# event-schemas ## Purpose The package-local Zod schemas for the `event` entity surface. Owns every input / output shape touching the events routes and repositories: the persisted `EventSchema`, the create / update request bodies, the list-query parameters, the path param shape, the `EventLocationSchema` value object, and the `EventStatusSchema` 0..2 integer encoding. The `@suaveplan/api-schemas` package ships only event-bus envelope schemas (`DomainEvent`, `EventEnvelope`, `EventMetadata`); the event-management entity schemas are owned here because no other package needs them. The schemas double as the type sources — every exported `*Schema` has a matching `type Foo = z.infer` so consumers get a single source of truth for both runtime validation and compile-time narrowing. The `CreateEventSchema` and `UpdateEventSchema` carry a `.refine()` constraint that asserts `end_time > start_time` at the parser boundary so the repository never sees a malformed time pair. ## Features - 11 schemas spanning persistence, request, response, and value objects. - `CreateEventSchema` / `UpdateEventSchema` enforce `end_time > start_time` via `.refine()`. - `EventStatusSchema` constrains status to `0..2` (draft / active / cancelled) matching the upstream encoding. - `EventQuerySchema` coerces query-string `limit` / `offset` / `upcoming` / `past` to typed numbers / booleans. - `EventLocationSchema` validates `(lat, lng)` coordinates against geographic bounds. ## Usage: Basic Example ```ts import { CreateEventSchema, EventSchema } from "@suaveplan/api-plugin-events"; const parsed = CreateEventSchema.parse({ title: "Meetup", start_time: "2026-06-01T18:00:00Z", end_time: "2026-06-01T22:00:00Z", }); console.log(parsed.timezone); // "UTC" ``` ## Usage: Advanced Example ```ts import { EventQuerySchema, EventListResponseSchema, UpdateEventSchema, } from "@suaveplan/api-plugin-events"; // Coerce from URL search params const url = new URL("https://api.example.com/events?limit=10&past=true"); const query = EventQuerySchema.parse(Object.fromEntries(url.searchParams)); // Build a typed response payload const body = EventListResponseSchema.parse({ data: [ /* events from repository */ ], total: 42, }); // Forbid time inversion at the boundary const result = UpdateEventSchema.safeParse({ start_time: "2026-06-01T22:00:00Z", end_time: "2026-06-01T18:00:00Z", }); if (!result.success) { // result.error.issues[0].path === ["end_time"] } ``` ## API Reference - `EventStatusSchema: z.ZodNumber` — integer 0..2. - `EventLocationSchema: z.ZodObject` — `{ name, address?, coordinates? }`. - `AttendeeCountSchema: z.ZodObject` — `{ going, maybe, invited }`. - `EventSchema: z.ZodObject` — the persisted event row. - `CreateEventSchema: z.ZodEffects<...>` — POST `/` body. - `UpdateEventSchema: z.ZodEffects<...>` — PUT `/{id}` body. - `EventQuerySchema: z.ZodObject` — GET `/` query params. - `EventIdParamSchema: z.ZodObject` — `{ id: string }`. - `EventListResponseSchema: z.ZodObject` — GET `/` response. Every schema exports a sibling `type Foo = z.infer`. ## Implementation Notes `status` is encoded as an integer (`0=draft`, `1=active`, `2=cancelled`) rather than a string enum to match the upstream SurrealDB schema and to keep label cardinality low when emitted as OTel attributes. The two cross-field `.refine()` rules (`end_time > start_time`) are duplicated on `CreateEventSchema` and `UpdateEventSchema` rather than factored to a shared helper because the `UpdateEventSchema` variant must tolerate a single-field update (`{ title }`) without raising the refinement, which means the rule fires only when both `start_time` and `end_time` appear in the same payload.