106 lines
3.7 KiB
Markdown
106 lines
3.7 KiB
Markdown
# 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<typeof FooSchema>` 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<typeof FooSchema>`.
|
|
|
|
## 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.
|