2.6 KiB
analytics-event-schema.ts
(no submodules)
Purpose
Defines the canonical Zod schema for AnalyticsEvent and a validateAnalyticsEvent parse helper. The schema lets consumers validate untrusted payloads (iframe postMessage bridges, browser extension messages, recovered IndexedDB rows) before handing them to the tracker. The helper wraps safeParse so the boundary failure mode is a typed AnalyticsBrowserError(INVALID_EVENT) carrying the full Zod issue list on error.context.issues — no raw ZodError leaks past the boundary.
Features
- Single source of truth for the on-wire and in-memory shape of an analytics event.
- Required:
id,name,timestamp,sessionId,anonymousId,properties(record). Optional:userId. - Boundary-failure translation: every Zod issue is collected into
error.context.issuesso observability tooling can render the full failure tree. - Schema is exported directly so downstream packages can
.merge/.extendto add domain-specific shape (e.g. an e-commerce analytics extension).
Usage: Basic
import { validateAnalyticsEvent } from "@suaveplan/analytics-browser/schema";
const safe = validateAnalyticsEvent(unknownPayload);
tracker.track(safe.name, safe.properties);
Usage: Advanced
import z from "zod";
import { AnalyticsEventSchema } from "@suaveplan/analytics-browser/schema";
// Domain-specific extension — every commerce event additionally carries
// a non-empty `cartId`. Composition stays within the Zod model so the
// .issues path stays intact when validation fails.
const CommerceEventSchema = AnalyticsEventSchema.extend({
properties: z
.record(z.string(), z.unknown())
.refine((p) => typeof p.cartId === "string" && p.cartId.length > 0, {
message: "missing cartId",
}),
});
API Reference
AnalyticsEventSchema: z.ZodType<AnalyticsEvent>— the raw Zod schema.validateAnalyticsEvent(input: unknown): AnalyticsEvent— parses and returns; throwsAnalyticsBrowserError(INVALID_EVENT)on failure witherror.context.issuesexposing the Zod issue array.
Implementation Notes
The schema deliberately uses z.string().min(1) rather than z.string() for every identifier so a producer cannot bypass validation by sending an empty string. properties uses z.record(z.string(), z.unknown()) rather than a stricter shape because tracker callers attach arbitrary metadata; if a downstream consumer needs a stricter contract they SHOULD .extend the schema as shown above. The helper does not log on failure — that is the caller's decision — and never swallows errors silently.