import type { z } from 'zod'; export interface EventDefinition< TPayload extends z.ZodTypeAny = z.ZodTypeAny, TReply extends z.ZodTypeAny = z.ZodTypeAny, > { payload: TPayload; replies?: TReply; } export type AnyEventDef = EventDefinition; export type AnyEventRegistry = EventRegistry>; export type EventDefinitionsInput = Record; type Normalize = { [K in keyof T]: T[K] extends z.ZodTypeAny ? { payload: T[K] } : T[K] extends EventDefinition ? T[K] : never; }; export interface EventRegistry< TDefs extends Record = Record, > { readonly defs: TDefs; has(type: string): boolean; payloadSchema(type: string): z.ZodTypeAny | undefined; replySchema(type: string): z.ZodTypeAny | undefined; } /** * Declare the set of events the bus will carry. Each entry is either a * raw zod schema for the payload, or an object `{ payload, replies? }` * if the event participates in query/reply. * * The returned registry is the single source of truth for type names * and payload shapes. emit, subscribe, watch, and query all consult it. */ export function defineEvents( input: TInput, ): EventRegistry> { const defs = {} as Record; for (const [type, def] of Object.entries(input)) { if (isZodSchema(def)) { defs[type] = { payload: def }; } else { defs[type] = def; } } return { defs: defs as Normalize, has: (type) => Object.hasOwn(defs, type), payloadSchema: (type) => defs[type]?.payload, replySchema: (type) => defs[type]?.replies, }; } function isZodSchema(value: unknown): value is z.ZodTypeAny { return ( typeof value === 'object' && value !== null && '_def' in value && typeof (value as { parse?: unknown }).parse === 'function' ); } /** All declared event type names, as a literal union. */ export type EventTypeOf = R extends EventRegistry ? keyof D & string : never; /** Payload type for a specific event name. */ export type PayloadOf> = R extends EventRegistry ? D[T] extends EventDefinition ? z.infer

: never : never; /** Reply payload type for a query event (undefined if no replies declared). */ export type ReplyOf> = R extends EventRegistry ? D[T] extends EventDefinition ? Reply extends z.ZodTypeAny ? z.infer : never : never : never; /** * Glob pattern over registered event types. v1 typing keeps it simple: * the pattern is `EventTypeOf` (exact) or any string (glob). Runtime * matching enforces shape; compile-time check covers the common exact * case and catches misspelled prefixes. */ export type EventPattern = EventTypeOf | (string & {});