Initial Commit
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user