@spfn/core 0.3.0-beta.24 → 0.3.0-beta.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/state/state-binding.ts","../../src/state/state-event.ts","../../src/state/state-builder.ts","../../src/state/state-routes.ts","../../src/state/state-router.ts"],"names":["Type","Value"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * State Binding\n *\n * What a state router fixes for each state it groups, keyed by the builder's\n * definition — one per builder instance, so an intermediate builder is never\n * bound: the router's path (a state belongs to one router) and the schema\n * every `read()` result is checked against, built once here rather than per\n * request.\n */\n\nimport { Type, type TObject } from '@sinclair/typebox';\nimport type { StateDefinition } from './types';\n\nexport interface StateBinding\n{\n path: string;\n resultSchema: TObject;\n}\n\nconst bindings = new WeakMap<Readonly<StateDefinition>, StateBinding>();\n\n/** `{ value, data }` exactly as declared: `data` when `.data()` is, and nothing else. */\nfunction resultSchema(def: StateDefinition): TObject\n{\n return Type.Object(\n {\n value: def.value!,\n ...(def.data ? { data: def.data } : {}),\n },\n { additionalProperties: false },\n );\n}\n\n/** Bind a state to the router at `path`. */\nexport function bindState(def: Readonly<StateDefinition>, path: string): void\n{\n bindings.set(def, { path, resultSchema: resultSchema(def) });\n}\n\n/** The binding of a state, `undefined` until a router groups that builder. */\nexport function stateBinding(def: Readonly<StateDefinition>): StateBinding | undefined\n{\n return bindings.get(def);\n}\n","/**\n * State Event\n *\n * The two events a state derives: the change signal the app emits\n * (`state.changed`, in-process) and the SSE event the browser receives\n * (`state.<id>.changed`). Between them sits the one rule of the module — a\n * value is only ever what `read()` returned, re-read here, never computed from\n * the signal.\n */\n\nimport { Type, type TObject, type TSchema } from '@sinclair/typebox';\nimport { Value } from '@sinclair/typebox/value';\nimport { defineEvent } from '@spfn/core/event';\nimport type { EventDef, FramePredicate, SubscribePredicate } from '@spfn/core/event';\nimport { logger } from '@spfn/core/logger';\nimport { stateBinding, type StateBinding } from './state-binding';\nimport type { RoutableState, StateCallContext, StateDefinition } from './types';\n\nconst stateLogger = logger.child('@spfn/core:state');\n\n/** `{ at, value, data? }` as a response and a frame carry it. */\nexport interface Snapshot\n{\n at: string;\n value: unknown;\n data?: unknown;\n}\n\ntype Key = Record<string, string>;\n\ntype FramePayload = Snapshot & { key?: Key; subject?: string };\n\n/** The wire name of a state's SSE event. */\nexport function stateEventName(id: string): string\n{\n return `state.${id}.changed`;\n}\n\n/**\n * The key fields of `keySchema` taken from `source`, or `undefined` when any\n * is absent. Key fields are strings by construction (`.key()` refuses others),\n * so a query value and a payload field compare as they are.\n */\nexport function pickKey(keySchema: TObject, source: Record<string, unknown>): Key | undefined\n{\n const key: Key = {};\n\n for (const field of Object.keys(keySchema.properties))\n {\n const value = source[field];\n if (typeof value !== 'string')\n {\n return undefined;\n }\n key[field] = value;\n }\n\n return key;\n}\n\n/** What `read()` receives: a shared state's value does not depend on the subject, so it gets none. */\nexport function readContext(def: StateDefinition, subject: string | undefined, principal: unknown, key?: Key): StateCallContext\n{\n if (!def.key)\n {\n return { subject, principal };\n }\n\n return def.shared ? { principal, key } : { subject, principal, key };\n}\n\n/** What `.canRead()` / `.canWrite()` receive. */\nexport function permissionContext(def: StateDefinition, subject: string, principal: unknown, key?: Key): StateCallContext\n{\n return def.key ? { subject, principal, key } : { subject, principal };\n}\n\n/**\n * The router binding of a state, or a refusal: an unrouted builder has no\n * subscriber for its signal and no schema to check a read against.\n */\nexport function requireBinding(def: StateDefinition, what: string): StateBinding\n{\n const binding = stateBinding(def);\n\n if (!binding)\n {\n throw new Error(\n `State \"${def.id}\" is in no defineStateRouter, so ${what} reaches nothing. `\n + 'The router subscribes the change signal and checks every read, and every builder call returns a new '\n + 'builder — an earlier one is never routed. Group the state with defineStateRouter and export the builder '\n + 'instance you grouped.',\n );\n }\n\n return binding;\n}\n\n/** Refuse a `read()` result that is not what the state declares, naming the state, never the value. */\nfunction assertResult(def: StateDefinition, binding: StateBinding, result: unknown): asserts result is Omit<Snapshot, 'at'>\n{\n const error = Value.Errors(binding.resultSchema, result).First();\n\n if (error)\n {\n throw new Error(\n `State \"${def.id}\" read() returned a result its declaration does not allow: ${error.path || '(root)'} ${error.message}. `\n + 'Every response and frame is checked against .value() and .data(), so a client never receives a value the '\n + 'contract does not describe. Return { value'\n + `${def.data ? ', data' : ''} } as declared.`,\n );\n }\n}\n\n/**\n * Read the current value and check it against the declaration. `at` is taken\n * before `read()` starts, so a frame is never stamped later than the data it\n * carries.\n */\nexport async function readSnapshot(def: StateDefinition, ctx: StateCallContext, at = new Date().toISOString()): Promise<Snapshot>\n{\n const binding = requireBinding(def, 'a read');\n const result = await def.read!(ctx);\n assertResult(def, binding, result);\n\n return { at, ...result };\n}\n\n/**\n * The frame for a snapshot. A copy: the response keeps the snapshot itself, so\n * neither a handler mutating what it returned nor a subscriber mutating the\n * payload changes the other.\n */\nfunction toFrame(def: StateDefinition, snapshot: Snapshot, subject: string | undefined, key: Key | undefined): FramePayload\n{\n const frame: FramePayload = structuredClone(snapshot);\n\n if (def.key)\n {\n frame.key = { ...key };\n }\n\n if (!(def.key && def.shared))\n {\n frame.subject = subject;\n }\n\n return frame;\n}\n\n/** Read the value for one subject and key, send it as one frame, and return the snapshot. */\nexport async function readAndPublish(\n def: StateDefinition,\n event: EventDef<any>,\n subject: string | undefined,\n key: Key | undefined,\n principal: unknown,\n): Promise<Snapshot>\n{\n const snapshot = await readSnapshot(def, readContext(def, subject, principal, key));\n await event.emit(toFrame(def, snapshot, subject, key));\n\n return snapshot;\n}\n\n// ============================================================================\n// The derived SSE event\n// ============================================================================\n\nfunction framePayloadSchema(def: StateDefinition): TObject\n{\n return Type.Object({\n at: Type.String(),\n value: def.value ?? Type.Unknown(),\n ...(def.data ? { data: def.data } : {}),\n ...(def.key ? { key: def.key } : {}),\n ...(def.key && def.shared ? {} : { subject: Type.String() }),\n });\n}\n\n/**\n * `canRead` translated to the connect: the connection declares its key in the\n * connect query. A key field absent from it denies, without asking `canRead` —\n * there is no key to ask about.\n */\nfunction subscribePredicate(def: StateDefinition): SubscribePredicate\n{\n return async ({ subject, principal, request }) =>\n {\n if (!def.key)\n {\n return def.canRead ? def.canRead({ subject, principal }) : true;\n }\n\n const key = pickKey(def.key, request.query);\n\n return key !== undefined && def.canRead !== undefined && def.canRead({ subject, principal, key });\n };\n}\n\n/**\n * A frame reaches a connection on the key it declared, and only its own\n * subject's value unless shared. Never a connection without a subject: on a\n * stream without auth `canSubscribe` is never asked, so `canRead` would be\n * skipped.\n */\nfunction framePredicate(def: StateDefinition): FramePredicate<FramePayload>\n{\n const fields = def.key ? Object.keys(def.key.properties) : [];\n\n return (payload, { subject, request }) =>\n subject !== undefined\n && fields.every(field => payload.key?.[field] === request.query[field])\n && (payload.subject === undefined || payload.subject === subject);\n}\n\n/** The SSE event `state.<id>.changed`, its permissions and contract set once, here. */\nexport function createStateEvent(def: StateDefinition): EventDef<any>\n{\n const event = defineEvent(stateEventName(def.id), framePayloadSchema(def))\n .canSubscribe(subscribePredicate(def))\n .filter(framePredicate(def) as FramePredicate<unknown>);\n\n if (def.contract)\n {\n const { since, deprecatedIn, removedIn } = def.contract;\n event.contract({\n since,\n ...(deprecatedIn ? { deprecatedIn } : {}),\n ...(removedIn ? { removedIn } : {}),\n });\n }\n\n return event;\n}\n\n// ============================================================================\n// The change signal\n// ============================================================================\n\n/**\n * What a change signal must name: keyless `subject`; keyed the key fields, and\n * `subject` unless shared. Always a fresh object, never `def.key` itself: a key\n * declared `additionalProperties: false` would otherwise refuse every\n * `.changedBy()` payload carrying one more field. Extra fields are ignored.\n */\nexport function changedPayloadSchema(def: StateDefinition): TObject\n{\n return Type.Object({\n ...def.key?.properties,\n ...(def.key && def.shared ? {} : { subject: Type.String() }),\n });\n}\n\nfunction assertChangedPayload(def: StateDefinition, schema: TSchema, payload: unknown): void\n{\n const error = Value.Errors(schema, payload).First();\n\n if (error)\n {\n throw new Error(\n `${def.id}.changed.emit() refused its payload: ${error.path || '(root)'} ${error.message}. `\n + 'The module re-reads exactly the subject and key the payload names, so a missing field cannot be guessed. '\n + `Pass ${def.key ? 'every key field' : 'the subject'}${def.key && !def.shared ? ' and the subject' : ''}.`,\n );\n }\n}\n\n/**\n * The change signal `state.changed`: a plain in-process event whose `emit`\n * refuses a builder no router grouped, and validates its payload, since the\n * module reads the state the payload names.\n */\nexport function createChangedSignal(def: StateDefinition): EventDef<any>\n{\n const schema = changedPayloadSchema(def);\n const event = defineEvent(`state.${def.id}.signal`, schema);\n const emit = event.emit;\n\n event.emit = (async (payload: unknown) =>\n {\n requireBinding(def, `${def.id}.changed.emit()`);\n assertChangedPayload(def, schema, payload);\n await emit(payload as Record<string, unknown>);\n }) as EventDef<any>['emit'];\n\n return event;\n}\n\n/** Subject and key a signal payload names; a shared state's names no subject. */\nfunction signalTarget(def: StateDefinition, payload: Record<string, unknown>): { subject?: string; key?: Key }\n{\n const subject = def.key && def.shared ? undefined : payload.subject as string;\n\n return { subject, key: def.key ? pickKey(def.key, payload) : undefined };\n}\n\n/**\n * Re-read and publish for one signal. A `read()` that throws or returns an\n * undeclared result sends nothing and is logged — the signal came after a\n * commit the app already made, so there is nobody to throw to.\n */\nasync function onSignal(state: RoutableState, payload: Record<string, unknown>): Promise<void>\n{\n const { subject, key } = signalTarget(state._definition, payload);\n\n try\n {\n await readAndPublish(state._definition, state._event, subject, key, undefined);\n }\n catch (error)\n {\n stateLogger.warn(`State \"${state.id}\" could not be re-read on its change signal; no frame was sent`, {\n state: state.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\n/**\n * A `.changedBy()` event's payload, checked as the state's own `emit` checks\n * its signal. The app emitted it, so a payload missing a field is logged and\n * skipped rather than thrown.\n */\nasync function onChangedBy(state: RoutableState, event: EventDef<any>, schema: TObject, payload: unknown): Promise<void>\n{\n const error = Value.Errors(schema, payload).First();\n\n if (error)\n {\n stateLogger.warn(`State \"${state.id}\" skipped an \"${event.name}\" payload that names no value to re-read`, {\n state: state.id,\n event: event.name,\n error: `${error.path || '(root)'} ${error.message}`,\n });\n\n return;\n }\n\n await onSignal(state, payload as Record<string, unknown>);\n}\n\n/**\n * Re-read and publish on every signal of `state` and every event it lists in\n * `.changedBy()`, on the pod that emitted it only. A `.changedBy()` event in an\n * event router is cached, so a plain subscriber would re-read on every pod and\n * each would send its own frame; the derived state event is cached too, so the\n * emitting pod's one frame already reaches every pod. The `changed` signal\n * needs no such option: it is in no event router and never cached.\n */\nexport function subscribeChangeSignals(state: RoutableState): void\n{\n const schema = changedPayloadSchema(state._definition);\n\n state.changed.subscribe(payload => onSignal(state, payload));\n state._definition.changedBy?.forEach(event =>\n event.subscribe(payload => onChangedBy(state, event, schema, payload), { localOnly: true }));\n}\n","/**\n * State Builder\n *\n * `defineState(id)` starts an immutable builder: every call returns a new one,\n * order is free and there is no terminal method. `defineStateRouter` reads\n * what a builder declared and derives its routes and SSE event from it.\n */\n\nimport { Kind, Type, type TObject, type TSchema } from '@sinclair/typebox';\nimport { Value } from '@sinclair/typebox/value';\nimport type { MiddlewareHandler } from 'hono';\nimport type { EventDef } from '@spfn/core/event';\nimport type { NamedMiddleware } from '@spfn/core/route';\nimport { createChangedSignal, createStateEvent, pickKey, readAndPublish, requireBinding } from './state-event';\nimport type {\n ChangedPayload,\n EmptyStateShape,\n GrantTarget,\n PermissionContext,\n ReadContext,\n RevokeTarget,\n StateContract,\n StateDefinition,\n StateFrame,\n StatePredicate,\n StateReader,\n StateResult,\n StateShape,\n StateWriteOptions,\n StateWriter,\n WithShape,\n WriteContext,\n} from './types';\n\n/** A state id becomes part of a route name (`get<Id>State`) and of an event name (`state.<id>.changed`). */\nconst STATE_ID = /^[a-z][a-zA-Z0-9]*$/;\n\n/**\n * Query names the SSE stream reads itself. Key fields share the connect query\n * with them, so a key field under one of these names would be read as both.\n */\nconst RESERVED_KEY_FIELDS = ['events', 'token'];\n\n/**\n * A server-owned value declared once. See the module README.\n */\nexport class StateBuilder<TId extends string, T extends StateShape>\n{\n /** Type inference helper: what this builder declared. Never set at runtime. */\n declare readonly _types: T;\n\n private changedSignal?: EventDef<any>;\n private stateEvent?: EventDef<any>;\n\n constructor(\n readonly id: TId,\n readonly _definition: Readonly<StateDefinition>,\n )\n {\n }\n\n /**\n * Declare the key: one value per key (and per subject, unless `shared`).\n * Fields are required strings: they travel as query parameters.\n */\n key<K extends TObject, S extends boolean = false>(\n schema: K,\n options: { shared?: S } = {},\n ): StateBuilder<TId, WithShape<T, { key: K; shared: S }>>\n {\n this.assertOnce('key', !!this._definition.key);\n assertKeySchema(this.id, schema);\n\n return this.with({ key: schema, shared: options.shared === true });\n }\n\n /** Declare the value schema. Required. */\n value<V extends TSchema>(schema: V): StateBuilder<TId, WithShape<T, { value: V }>>\n {\n this.assertOnce('value', !!this._definition.value);\n\n return this.with({ value: schema });\n }\n\n /** Declare data attached to the value. Optional. */\n data<D extends TSchema>(schema: D): StateBuilder<TId, WithShape<T, { data: D }>>\n {\n this.assertOnce('data', !!this._definition.data);\n\n return this.with({ data: schema });\n }\n\n /**\n * Middleware for the two per-state routes, `get<Id>State` / `put<Id>State`.\n * Not authorization: the snapshot and the SSE stream cannot run it, so a\n * state with `.use()` must declare `.canRead()`. Calls add up.\n */\n use(middlewares: (MiddlewareHandler | NamedMiddleware<string>)[]): StateBuilder<TId, T>\n {\n return this.with({ middlewares: [...this._definition.middlewares, ...middlewares] });\n }\n\n /** Server-level named middlewares the two per-state routes skip. Calls add up; `'*'` wins. Needs `.canRead()`, as `.use()`. */\n skip(middlewareNames: string[] | '*'): StateBuilder<TId, T>\n {\n const current = this._definition.skipMiddlewares ?? [];\n const skipMiddlewares = current === '*' || middlewareNames === '*'\n ? '*'\n : [...current, ...middlewareNames];\n\n return this.with({ skipMiddlewares });\n }\n\n /** Publish the read route, the write route and the event in the contract. */\n contract(contract: StateContract): StateBuilder<TId, T>\n {\n this.assertOnce('contract', !!this._definition.contract);\n\n return this.with({ contract });\n }\n\n /** Who may read. Required on a keyed state; checked on HTTP and at SSE connect. */\n canRead(predicate: (ctx: PermissionContext<T>) => boolean | Promise<boolean>): StateBuilder<TId, T>\n {\n this.assertOnce('canRead', !!this._definition.canRead);\n\n return this.with({ canRead: predicate as StatePredicate });\n }\n\n /** Who may write. Absent → `canRead` decides. */\n canWrite(predicate: (ctx: PermissionContext<T>) => boolean | Promise<boolean>): StateBuilder<TId, T>\n {\n this.assertOnce('canWrite', !!this._definition.canWrite);\n\n return this.with({ canWrite: predicate as StatePredicate });\n }\n\n /** The only source of a value. Required. */\n read(\n fn: (ctx: ReadContext<T>) => StateResult<T> | Promise<StateResult<T>>,\n ): StateBuilder<TId, WithShape<T, { read: true }>>\n {\n this.assertOnce('read', !!this._definition.read);\n\n return this.with({ read: fn as StateReader });\n }\n\n /**\n * Derive `PUT <path>/<id>`. `fn` runs the command; the value the route\n * answers and broadcasts is re-read afterwards, never taken from `input`.\n */\n write<I extends TSchema>(\n input: I,\n fn: (ctx: WriteContext<T, I>) => void | Promise<void>,\n options: StateWriteOptions = {},\n ): StateBuilder<TId, WithShape<T, { input: I }>>\n {\n this.assertOnce('write', !!this._definition.write);\n\n return this.with({ write: { input, fn: fn as StateWriter, options } });\n }\n\n /**\n * Domain events whose payload names a changed value of this state, treated\n * like `changed.emit` with that payload: keyless `subject`, keyed the key\n * fields and `subject`, shared the key fields. The router subscribes them\n * and refuses one whose payload schema lacks a field.\n */\n changedBy(events: EventDef<any>[]): StateBuilder<TId, T>\n {\n this.assertOnce('changedBy', !!this._definition.changedBy);\n\n return this.with({ changedBy: [...events] });\n }\n\n /**\n * The change signal. Emit it after the change is committed; the module\n * re-reads the value and sends the frame. Refused on a builder no router\n * grouped — export the instance you passed to `defineStateRouter`.\n */\n get changed(): EventDef<ChangedPayload<T>>\n {\n this.changedSignal ??= createChangedSignal(this._definition);\n\n return this.changedSignal;\n }\n\n /** Internal: the SSE event `state.<id>.changed` (`defineStateRouter(...).events`). */\n get _event(): EventDef<StateFrame<T>>\n {\n this.stateEvent ??= createStateEvent(this._definition);\n\n return this.stateEvent;\n }\n\n /**\n * Activate the state's event on `subject`'s open connections and send it\n * the current value at once. On a keyed state only the connections that\n * declared `key` are opened. Does not consult `canRead`.\n */\n async grant(target: GrantTarget<T>): Promise<void>\n {\n const { subject, key } = target as { subject: string; key?: Record<string, string> };\n requireBinding(this._definition, `${this.id}.grant()`);\n this.assertGrantKey(key);\n const declared = this.declaredKey('grant', key);\n await this._event.grant(subject, declared && { query: declared });\n await readAndPublish(this._definition, this._event, subject, declared, undefined);\n }\n\n /**\n * Deactivate the state's event on `subject`'s open connections: on a keyed\n * state those that declared `key`, or every one when no key is given.\n */\n async revoke(target: RevokeTarget<T>): Promise<void>\n {\n const { subject, key } = target as { subject: string; key?: Record<string, string> };\n const declared = this.declaredKey('revoke', key);\n await this._event.revoke(subject, declared && { query: declared });\n }\n\n /** A keyed grant opens one key: without it there is no key to open and no value to send. */\n private assertGrantKey(key: Record<string, string> | undefined): void\n {\n if (this._definition.key && !key)\n {\n throw new Error(\n `State \"${this.id}\" .grant() was called without a key. `\n + 'A keyed grant opens exactly one key — every connection of the subject on any key would otherwise be '\n + 'opened, including keys canRead refused. Pass { subject, key }.',\n );\n }\n }\n\n /**\n * The declared key fields of `key`, checked against `.key()`: an empty or\n * partial key would match every connection of the subject. A field the\n * declaration does not name is dropped, never matched on — so the check\n * runs on a fresh object of the declared fields, never `.key()` itself: a\n * key declared `additionalProperties: false` would otherwise refuse it.\n * The fresh object keeps `.key()`'s `required`, and a key that still picks\n * to nothing is refused: `undefined` here would mean every connection.\n */\n private declaredKey(method: 'grant' | 'revoke', key: Record<string, string> | undefined): Record<string, string> | undefined\n {\n const schema = this._definition.key;\n if (!schema || key === undefined)\n {\n return undefined;\n }\n\n const error = Value.Errors({ ...Type.Object(schema.properties), required: schema.required }, key).First();\n if (error)\n {\n this.refuseKey(method, `${error.path || '(root)'} ${error.message}`);\n }\n\n return pickKey(schema, key) ?? this.refuseKey(method, '(root) a declared key field is missing or not a string');\n }\n\n private refuseKey(method: 'grant' | 'revoke', reason: string): never\n {\n throw new Error(\n `State \"${this.id}\" .${method}() refused its key: ${reason}. `\n + `A keyed ${method} reaches exactly the connections on one key, so every key field must be named.`,\n );\n }\n\n private with(changes: Partial<StateDefinition>): StateBuilder<TId, any>\n {\n return new StateBuilder(this.id, { ...this._definition, ...changes });\n }\n\n private assertOnce(method: string, declared: boolean): void\n {\n if (declared)\n {\n throw new Error(\n `State \"${this.id}\" already declares .${method}(). `\n + 'A state is declared once, so a second declaration would silently replace the first. '\n + `Declare .${method}() once.`,\n );\n }\n }\n}\n\n/**\n * Refuse a key the module could not carry: it must be an object of required\n * string fields, none named like a query parameter the SSE stream reads.\n */\nfunction assertKeySchema(id: string, schema: TSchema): void\n{\n if (schema[Kind] !== 'Object')\n {\n throw new Error(\n `State \"${id}\" .key() takes an object schema, got ${String(schema[Kind])}. `\n + 'Each key field becomes a named query parameter and a field of the frame\\'s key. '\n + 'Wrap the field: .key(Type.Object({ workspaceId: Type.String() })).',\n );\n }\n\n const fields = Object.entries((schema as TObject).properties);\n\n if (fields.length === 0)\n {\n throw new Error(\n `State \"${id}\" .key() declares no field. A key with no field names nothing to read by. `\n + 'Drop .key() for one value per subject.',\n );\n }\n\n fields.forEach(([field, fieldSchema]) => assertKeyField(id, schema as TObject, field, fieldSchema));\n}\n\nfunction assertKeyField(id: string, schema: TObject, field: string, fieldSchema: TSchema): void\n{\n if (RESERVED_KEY_FIELDS.includes(field))\n {\n throw new Error(\n `State \"${id}\" key field \"${field}\" is reserved. `\n + `The SSE stream reads ${RESERVED_KEY_FIELDS.map(name => `\"${name}\"`).join(' and ')} from the connect query `\n + 'that also carries the key, so the field would be read as both. Rename the field.',\n );\n }\n\n if (fieldSchema.type !== 'string' || !(schema.required ?? []).includes(field))\n {\n throw new Error(\n `State \"${id}\" key field \"${field}\" is not a required string. `\n + 'A key travels as a query parameter, which is always a string, and the SSE filter compares it with the '\n + 'connect query as one — a number would never match, and a missing field names no value. '\n + `Declare it ${field}: Type.String().`,\n );\n }\n}\n\n/**\n * Declare a server-owned state.\n *\n * @example\n * ```typescript\n * export const consent = defineState('consent')\n * .value(Type.Union([Type.Literal('pending'), Type.Literal('agreed')]))\n * .read(({ subject }) => consents.current(subject));\n * ```\n */\nexport function defineState<TId extends string>(id: TId): StateBuilder<TId, EmptyStateShape>\n{\n if (!STATE_ID.test(id))\n {\n throw new Error(\n `defineState(\"${id}\"): a state id must match ${STATE_ID}. `\n + 'It becomes part of the route names get<Id>State / put<Id>State and of the event name state.<id>.changed. '\n + 'Use a lowerCamel identifier, e.g. \"myState\".',\n );\n }\n\n return new StateBuilder(id, { id, shared: false, middlewares: [] });\n}\n","/**\n * State Routes\n *\n * The read, write and snapshot routes a state router derives. They are\n * ordinary `RouteDef`s registered through `registerRoutes`, so a state's\n * `.use()` middleware runs inside the route's own chain after the app's\n * global middleware.\n */\n\nimport { Type, type TObject, type TSchema } from '@sinclair/typebox';\nimport type { Context } from 'hono';\nimport { ForbiddenError, UnauthorizedError } from '@spfn/core/errors';\nimport { route } from '@spfn/core/route';\nimport type { RouteContract, RouteDef, RouteInput } from '@spfn/core/route';\nimport {\n permissionContext,\n pickKey,\n readAndPublish,\n readContext,\n readSnapshot,\n} from './state-event';\nimport type { RoutableState, StateCallContext, StateDefinition } from './types';\n\n/** Who a request is for. `null` answers 401. */\nexport type SubjectResolver = (c: Context) => string | null;\n\n/** The SSE `getSubject` default: the `userId` the app's auth middleware set. */\nexport const defaultSubject: SubjectResolver = c =>\n (c.get('auth') as Record<string, string> | undefined)?.userId ?? null;\n\ntype Key = Record<string, string>;\n\n/** `get<Id>State` / `put<Id>State`. */\nexport function stateRouteName(method: 'get' | 'put', id: string): string\n{\n return `${method}${id[0].toUpperCase()}${id.slice(1)}State`;\n}\n\nfunction requireSubject(c: Context, resolveSubject: SubjectResolver): string\n{\n const subject = resolveSubject(c);\n\n if (!subject)\n {\n throw new UnauthorizedError({ message: 'A state is read for a subject, and this request carries none' });\n }\n\n return subject;\n}\n\nasync function assertPermitted(def: StateDefinition, can: 'canRead' | 'canWrite', ctx: StateCallContext): Promise<void>\n{\n const predicate = can === 'canWrite' ? def.canWrite ?? def.canRead : def.canRead;\n\n if (predicate && !await predicate(ctx))\n {\n throw new ForbiddenError({ message: `${can === 'canWrite' ? 'Writing' : 'Reading'} state \"${def.id}\" is not permitted` });\n }\n}\n\nfunction responseSchema(def: StateDefinition): TObject\n{\n return Type.Object({\n at: Type.String(),\n value: def.value!,\n ...(def.data ? { data: def.data } : {}),\n });\n}\n\n/**\n * The route contract, or none when the state declares no `.contract()`. A\n * write's own version markers win over the state's, field by field.\n */\nfunction routeContract(def: StateDefinition, write: boolean): RouteContract | undefined\n{\n if (!def.contract)\n {\n return undefined;\n }\n\n const own = write ? stripUndefined(def.write!.options) : {};\n\n return stripUndefined({ ...def.contract, ...own, response: responseSchema(def) }) as RouteContract;\n}\n\nfunction stripUndefined<T extends object>(value: T): Partial<T>\n{\n return Object.fromEntries(Object.entries(value).filter(([, field]) => field !== undefined)) as Partial<T>;\n}\n\n/** `route.<method>(path)` with the state's input, middleware, skips and contract. */\nfunction stateRoute(def: StateDefinition, method: 'get' | 'put', path: string, input: RouteInput)\n{\n const contract = routeContract(def, method === 'put');\n const builder = route[method](path).input(input).use(def.middlewares);\n const skipped = def.skipMiddlewares ? builder.skip(def.skipMiddlewares) : builder;\n\n return contract ? skipped.contract(contract) : skipped;\n}\n\nfunction keyInput(def: StateDefinition): { query?: TObject }\n{\n return def.key ? { query: def.key } : {};\n}\n\n/** `GET <path>/<id>`: subject → key → `canRead` → `at` → `read()`. */\nexport function readRoute(state: RoutableState, path: string, resolveSubject: SubjectResolver): RouteDef<any, any, any>\n{\n const def = state._definition;\n\n return stateRoute(def, 'get', `${path}/${def.id}`, keyInput(def)).handler(async (c) =>\n {\n const subject = requireSubject(c.raw, resolveSubject);\n const principal = c.raw.get('auth');\n const key = def.key ? pickKey(def.key, (await c.data()).query) : undefined;\n await assertPermitted(def, 'canRead', permissionContext(def, subject, principal, key));\n\n return readSnapshot(def, readContext(def, subject, principal, key));\n });\n}\n\n/** `PUT <path>/<id>`: subject → key → `canWrite ?? canRead` → `write()` → `at` → `read()` → one frame. */\nexport function writeRoute(state: RoutableState, path: string, resolveSubject: SubjectResolver): RouteDef<any, any, any>\n{\n const def = state._definition;\n const write = def.write!;\n\n return stateRoute(def, 'put', `${path}/${def.id}`, { body: write.input, ...keyInput(def) }).handler(async (c) =>\n {\n const subject = requireSubject(c.raw, resolveSubject);\n const principal = c.raw.get('auth');\n const { body, query } = await c.data();\n const key = def.key ? pickKey(def.key, query) : undefined;\n await assertPermitted(def, 'canWrite', permissionContext(def, subject, principal, key));\n await write.fn({ ...readContext(def, subject, principal, key), input: body });\n\n return readAndPublish(def, state._event, subject, key, principal);\n });\n}\n\n/**\n * The snapshot's query: every key field of every keyed state, each optional —\n * a state whose key is incomplete is left out, not refused.\n */\nfunction snapshotQuery(states: RoutableState[]): TObject\n{\n const fields: Record<string, TSchema> = {};\n\n for (const state of states)\n {\n for (const [field, schema] of Object.entries(state._definition.key?.properties ?? {}))\n {\n fields[field] = Type.Optional(schema);\n }\n }\n\n return Type.Object(fields);\n}\n\n/** One state's entry in the snapshot, or `undefined` when its key is incomplete or `canRead` refuses. */\nasync function snapshotEntry(def: StateDefinition, subject: string, principal: unknown, query: Record<string, unknown>, at: string)\n{\n const key: Key | undefined = def.key ? pickKey(def.key, query) : undefined;\n\n if (def.key && !key)\n {\n return undefined;\n }\n\n if (def.canRead && !await def.canRead(permissionContext(def, subject, principal, key)))\n {\n return undefined;\n }\n\n const { value, data } = await readSnapshot(def, readContext(def, subject, principal, key), at);\n\n return def.data ? { value, data } : { value };\n}\n\n/** `GET <path>`: one `at`, then every readable state in declaration order. A `read()` that throws fails it all. */\nexport function snapshotRoute(states: RoutableState[], path: string, resolveSubject: SubjectResolver): RouteDef<any, any, any>\n{\n return route.get(path).input({ query: snapshotQuery(states) }).handler(async (c) =>\n {\n const subject = requireSubject(c.raw, resolveSubject);\n const principal = c.raw.get('auth');\n const { query } = await c.data();\n const at = new Date().toISOString();\n const entries = await Promise.all(states.map(state => snapshotEntry(state._definition, subject, principal, query, at)));\n\n return {\n at,\n states: Object.fromEntries(states\n .map((state, index) => [state.id, entries[index]])\n .filter(([, entry]) => entry !== undefined)),\n };\n });\n}\n","/**\n * State Router\n *\n * Groups states, derives their routes into one `Router` the app mounts with\n * `.packages()`, collects their SSE events for the app's event router, and\n * subscribes each state's change signal — once, here.\n */\n\nimport type { Static, TObject, TSchema } from '@sinclair/typebox';\nimport type { EventDef } from '@spfn/core/event';\nimport { defineRouter } from '@spfn/core/route';\nimport type { RouteDef, Router } from '@spfn/core/route';\nimport { bindState, stateBinding } from './state-binding';\nimport { changedPayloadSchema, stateEventName, subscribeChangeSignals } from './state-event';\nimport { defaultSubject, readRoute, snapshotRoute, stateRouteName, writeRoute } from './state-routes';\nimport type { SubjectResolver } from './state-routes';\nimport type { RoutableState, StateFrame, StateKey, StateResult, StateSnapshot, StateValue } from './types';\n\nexport interface StateRouterOptions\n{\n /**\n * Where the routes are mounted: `GET <path>`, `GET|PUT <path>/<id>`.\n * @default '/state'\n */\n path?: string;\n\n /**\n * Who an HTTP request is for. `null` answers 401.\n * @default (c) => c.get('auth')?.userId ?? null\n */\n subject?: SubjectResolver;\n}\n\ntype Shape<S extends RoutableState> = S['_types'];\n\ntype KeyQuery<S extends RoutableState> = Shape<S>['key'] extends TObject ? { query: Shape<S>['key'] } : {};\n\ntype ReadRoutes<S extends Record<string, RoutableState>> = {\n [K in keyof S as `get${Capitalize<S[K]['id']>}State`]: RouteDef<KeyQuery<S[K]>, {}, StateSnapshot<Shape<S[K]>>>;\n};\n\ntype WriteInput<S extends RoutableState> = KeyQuery<S> & { body: Shape<S>['input'] };\n\ntype WriteRoutes<S extends Record<string, RoutableState>> = {\n [K in keyof S as Shape<S[K]>['input'] extends TSchema ? `put${Capitalize<S[K]['id']>}State` : never]: RouteDef<WriteInput<S[K]>, {}, StateSnapshot<Shape<S[K]>>>;\n};\n\n/** What `GET <path>` answers: every state the subject may read and whose key the query carries. */\nexport type StatesSnapshot<S extends Record<string, RoutableState>> = {\n at: string;\n states: { [K in keyof S as S[K]['id']]?: StateResult<Shape<S[K]>> };\n};\n\n/** The routes one state router derives, typed for `createApi` and the route map. */\nexport type StateRoutes<S extends Record<string, RoutableState>> = ReadRoutes<S> & WriteRoutes<S> & {\n getStates: RouteDef<{ query: TObject }, {}, StatesSnapshot<S>>;\n};\n\n/** The SSE events, keyed by their wire names, for the app's `defineEventRouter`. */\nexport type StateEvents<S extends Record<string, RoutableState>> = {\n [K in keyof S as `state.${S[K]['id']}.changed`]: EventDef<StateFrame<Shape<S[K]>>>;\n};\n\nexport interface StateRouter<S extends Record<string, RoutableState>>\n{\n /** The derived routes. Mount with `appRouter.packages([states.router])`. */\n router: Router<StateRoutes<S>>;\n\n /** The derived SSE events. Spread into `defineEventRouter({ ...appEvents, ...states.events })`. */\n events: StateEvents<S>;\n\n /** The declarations, as given. */\n states: S;\n}\n\ntype StateById<R extends StateRouter<any>, TId extends string> = Extract<R['states'][keyof R['states']], { id: TId }>;\n\n/** The value type of state `TId` of a state router. */\nexport type InferStateValue<R extends StateRouter<any>, TId extends string> = StateValue<Shape<StateById<R, TId>>>;\n\n/** The key type of state `TId`, `undefined` when it is keyless. */\nexport type InferStateKey<R extends StateRouter<any>, TId extends string> = StateKey<Shape<StateById<R, TId>>>;\n\n/** The write input of state `TId`, `never` when it declares no `.write()`. */\nexport type InferStateInput<R extends StateRouter<any>, TId extends string> =\n Shape<StateById<R, TId>>['input'] extends TSchema ? Static<Shape<StateById<R, TId>>['input']> : never;\n\n/**\n * Group states, derive their routes and SSE events, and subscribe their change\n * signals.\n *\n * @example\n * ```typescript\n * export const states = defineStateRouter({ consent, runtime, member });\n *\n * // server.config.ts\n * // .routes(appRouter.packages([states.router]))\n * // .events(defineEventRouter({ ...appEvents, ...states.events }), { auth: { enabled: true } })\n * ```\n */\nexport function defineStateRouter<S extends Record<string, RoutableState>>(\n states: S,\n options: StateRouterOptions = {},\n): StateRouter<S>\n{\n const path = options.path ?? '/state';\n const list = Object.values(states);\n\n assertPath(path);\n list.forEach(assertRoutable);\n assertDistinctIds(list);\n list.forEach(state => assertNotRouted(state, path));\n\n list.forEach(state => bindState(state._definition, path));\n list.forEach(subscribeChangeSignals);\n\n return {\n router: defineRouter(deriveRoutes(list, path, options.subject ?? defaultSubject)) as Router<StateRoutes<S>>,\n events: Object.fromEntries(list.map(state => [stateEventName(state.id), state._event])) as StateEvents<S>,\n states,\n };\n}\n\nfunction deriveRoutes(states: RoutableState[], path: string, resolveSubject: SubjectResolver): Record<string, RouteDef<any, any, any>>\n{\n const routes: Record<string, RouteDef<any, any, any>> = {};\n\n for (const state of states)\n {\n routes[stateRouteName('get', state.id)] = readRoute(state, path, resolveSubject);\n\n if (state._definition.write)\n {\n routes[stateRouteName('put', state.id)] = writeRoute(state, path, resolveSubject);\n }\n }\n\n routes.getStates = snapshotRoute(states, path, resolveSubject);\n\n return routes;\n}\n\nfunction assertPath(path: string): void\n{\n if (!path.startsWith('/') || (path.length > 1 && path.endsWith('/')))\n {\n throw new Error(\n `defineStateRouter(..., { path: \"${path}\" }) is not an absolute path without a trailing slash. `\n + 'The routes are mounted at <path> and <path>/<id>. Write it as \"/state\".',\n );\n }\n}\n\n/** Refuse a state the router could not serve, naming it. */\nfunction assertRoutable(state: RoutableState): void\n{\n const def = state._definition;\n const missing = !def.value ? '.value()' : !def.read ? '.read()' : undefined;\n\n if (missing)\n {\n throw new Error(\n `defineStateRouter: state \"${state.id}\" declares no ${missing}. `\n + 'A state answers with the value its read returns, so both are required. '\n + `Add ${missing} to defineState('${state.id}').`,\n );\n }\n\n if (def.key && !def.canRead)\n {\n throw new Error(\n `defineStateRouter: keyed state \"${state.id}\" declares no .canRead(). `\n + 'The key comes from the request, so without it any subject could read any key. '\n + 'Add .canRead(({ subject, key }) => ...).',\n );\n }\n\n assertMiddlewareIsNotAuthorization(state);\n def.changedBy?.forEach(event => assertChangedBy(state, event));\n\n if (def.write && !def.contract && def.write.options.since)\n {\n throw new Error(\n `defineStateRouter: state \"${state.id}\" gives .write(..., { since: '${def.write.options.since}' }) `\n + 'but declares no .contract(), so there is nothing to fall back from: the write route would have a version '\n + 'but no auth profile, and the read route and the event would not be contracted at all. '\n + 'Add .contract({ since, ... }) to the state, or drop since from the write.',\n );\n }\n}\n\n/**\n * `.use()` / `.skip()` reach the two per-state routes only: the snapshot and\n * the SSE stream cannot run HTTP middleware. A guard there would hold on one\n * route and leak through the others, so authorization must be `canRead`.\n */\nfunction assertMiddlewareIsNotAuthorization(state: RoutableState): void\n{\n const def = state._definition;\n\n if ((def.middlewares.length > 0 || def.skipMiddlewares) && !def.canRead)\n {\n throw new Error(\n `defineStateRouter: state \"${state.id}\" declares .use() or .skip() but no .canRead(). `\n + `Middleware reaches only ${stateRouteName('get', state.id)} / ${stateRouteName('put', state.id)} — never the `\n + 'snapshot route or the SSE stream — so it cannot authorize. Authorization belongs in .canRead(), which is '\n + 'enforced on the read route, the snapshot and the stream. A state that needs middleware only for, say, rate '\n + 'limiting declares .canRead(() => true) to say so.',\n );\n }\n}\n\n/** A `.changedBy()` event must carry every field the state's change signal names, as a required property. */\nfunction assertChangedBy(state: RoutableState, event: EventDef<any>): void\n{\n const payload = event.schema as TObject | undefined;\n const signal = changedPayloadSchema(state._definition);\n const missing = Object.keys(signal.properties).find(field =>\n !payload?.properties?.[field] || !(payload.required ?? []).includes(field));\n\n if (missing)\n {\n throw new Error(\n `defineStateRouter: state \"${state.id}\" lists event \"${event.name}\" in .changedBy(), but its payload schema `\n + `has no required field \"${missing}\". Its payload is read like ${state.id}.changed.emit(), which names `\n + `${Object.keys(signal.properties).join(', ')}. Add the field to the event, or emit ${state.id}.changed instead.`,\n );\n }\n}\n\nfunction assertDistinctIds(states: RoutableState[]): void\n{\n const seen = new Set<string>();\n\n for (const state of states)\n {\n if (seen.has(state.id))\n {\n throw new Error(\n `defineStateRouter: two states have the id \"${state.id}\". `\n + `Both would derive the routes ${stateRouteName('get', state.id)} and the event `\n + `${stateEventName(state.id)}, and one would shadow the other. Rename one.`,\n );\n }\n seen.add(state.id);\n }\n}\n\nfunction assertNotRouted(state: RoutableState, path: string): void\n{\n const other = stateBinding(state._definition)?.path;\n\n if (other !== undefined)\n {\n throw new Error(\n `defineStateRouter: state \"${state.id}\" is already in another state router (path ${other}, this one ${path}). `\n + 'Each router subscribes the state\\'s change signal, so every change would be read and sent twice. '\n + 'Group each state in one router.',\n );\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { Context } from 'hono';
2
- import { a as EventDef, l as EventRouterBase, I as InferEventNames, h as InferEventPayload } from './router-ZDV1ISTo.js';
2
+ import { a as EventDef, n as EventRouterBase, I as InferEventNames, i as InferEventPayload } from './router-D5B0cpVN.js';
3
3
  import { c as SSETokenStore, S as SSETokenManager } from './token-manager-Ckjt2-qq.js';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { Context } from 'hono';
2
- import { E as EventRouterDef, I as InferEventNames, h as InferEventPayload, j as SubscribeRequest } from './router-ZDV1ISTo.js';
2
+ import { E as EventRouterDef, I as InferEventNames, i as InferEventPayload, k as SubscribeRequest } from './router-D5B0cpVN.js';
3
3
  import { c as SSETokenStore, S as SSETokenManager } from './token-manager-Ckjt2-qq.js';
4
4
 
5
5
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfn/core",
3
- "version": "0.3.0-beta.24",
3
+ "version": "0.3.0-beta.25",
4
4
  "description": "Full-stack TypeScript backend for Next.js: file-based typed routes, Drizzle entities and repositories, PostgreSQL transactions and a generated end-to-end client, in one fixed vertical slice per feature",
5
5
  "type": "module",
6
6
  "exports": {
@@ -119,6 +119,11 @@
119
119
  "import": "./dist/event/index.js",
120
120
  "require": "./dist/event/index.js"
121
121
  },
122
+ "./state": {
123
+ "types": "./dist/state/index.d.ts",
124
+ "import": "./dist/state/index.js",
125
+ "require": "./dist/state/index.js"
126
+ },
122
127
  "./event/sse": {
123
128
  "types": "./dist/event/sse/index.d.ts",
124
129
  "import": "./dist/event/sse/index.js",
@@ -48,7 +48,7 @@ From `@spfn/core/event`:
48
48
  - `.canSubscribe(predicate)`, `.filter(predicate)`, `.grant(subject)`, `.revoke(subject)` on an
49
49
  event — who may subscribe over SSE, which frames a connection receives, and changing an open
50
50
  connection (see [Per-event permission](#per-event-permission-cansubscribe-filter-grant--revoke))
51
- - Types: `EventDef`, `EventHandler`, `InferEventPayload`, `PubSubCache`, `JobQueueSender`,
51
+ - Types: `EventDef`, `EventHandler`, `EventSubscribeOptions`, `InferEventPayload`, `PubSubCache`, `JobQueueSender`,
52
52
  `EventContract`, `EventRouterContract`, `SubscribePredicate`, `SubscribeContext`,
53
53
  `SubscribeRequest`, `FramePredicate`, `FrameContext`,
54
54
  `EventRouterDef`, `InferEventNames`, `InferEventPayloads`,
@@ -132,15 +132,15 @@ Promise<void>` otherwise. Handlers run via `Promise.allSettled` — see
132
132
  |--------|-----------|-------|
133
133
  | `name` | `readonly string` | event name (e.g. `'user.created'`) |
134
134
  | `schema` | `readonly TSchema?` | the TypeBox schema, if provided |
135
- | `subscribe(handler)` | `(payload) => void \| Promise<void>` ⇒ returns `() => void` | in-memory; returns unsubscribe |
136
- | `unsubscribeAll()` | `() => void` | drop all in-memory handlers |
135
+ | `subscribe(handler, options?)` | `(payload) => void \| Promise<void>`, `{ localOnly?: boolean }` ⇒ returns `() => void` | in-memory; returns unsubscribe. `localOnly`: runs for this process's `emit` only, never for a cache delivery from another pod |
136
+ | `unsubscribeAll()` | `() => void` | drop all in-memory handlers, `localOnly` ones included |
137
137
  | `emit(payload?)` | `Promise<void>` | fan-out to handlers (or cache) + job queues |
138
138
  | `useCache(cache)` | `(PubSubCache) => Promise<EventDef>` | enable cross-instance broadcast (must `await`) |
139
139
  | `contract(contract)` | `(EventContract) => EventDef` | publish in the contract; returns the same event; a second call throws |
140
140
  | `canSubscribe(predicate)` | `<P>(SubscribePredicate<P>) => EventDef` | who may subscribe over SSE (once per connection); a second call throws |
141
141
  | `filter(predicate)` | `(FramePredicate<TPayload>) => EventDef` | which frames a connection receives (sync, per frame); a second call throws |
142
- | `grant(subject)` | `Promise<void>` | activate the event on the subject's open SSE connections where it is denied |
143
- | `revoke(subject)` | `Promise<void>` | deactivate the event on the subject's open SSE connections where it is allowed |
142
+ | `grant(subject, match?)` | `Promise<void>` | activate the event on the subject's open SSE connections (those matching `match`, when given) where it is denied |
143
+ | `revoke(subject, match?)` | `Promise<void>` | deactivate the event on the subject's open SSE connections (those matching `match`, when given) where it is allowed |
144
144
 
145
145
  > `_registerJobQueue`, `_registerSubscriptionControl` and `_payload` exist on the interface but
146
146
  > are **internal** — `_registerJobQueue` is called by `@spfn/core/job` when a job does
@@ -458,9 +458,22 @@ await workspaceRuntime.grant(userId); // membership restored
458
458
  — where it is denied: subscribe (the same code path as at connect, with the stored request
459
459
  snapshot) and send `subscription.granted`. Anything else is a no-op, and no connection resolves
460
460
  without error.
461
+ - `match: { query: Record<string, string> }` narrows either call to the connections whose connect
462
+ query carries every named field with exactly that value — string to string, over the request
463
+ snapshot. A connection that declared no such field never matches, not even against `''`.
464
+ Without `match`, every connection of the subject is reached.
465
+
466
+ ```typescript
467
+ // the tab on w1 only; a tab of the same user on w2 stays denied
468
+ await workspaceRuntime.grant(userId, { query: { workspaceId: 'w1' } });
469
+ ```
470
+
461
471
  - With the cache transport attached (`CACHE_URL`), the call applies on this pod and is published
462
472
  once on the control channel `<channelPrefix>$control`; every other pod applies it to its own
463
- connections. Without a cache it is local only.
473
+ connections, with the same `match` rule. `grant` / `revoke` reject a `match` whose `query` is
474
+ empty or holds a non-string value (an `undefined` field would vanish in JSON and widen the call
475
+ on every other pod) before applying or publishing it. A control message whose `match` is not an
476
+ object with a non-empty string-to-string `query` is malformed and ignored. Without a cache it is local only.
464
477
  - Three rules:
465
478
  1. **Open connections only.** Neither re-runs `canSubscribe` or `authorize` — they are an
466
479
  operator's statement about connections that exist now.
@@ -627,7 +640,10 @@ export default defineServerConfig()
627
640
  Mechanics (from `event.ts`): once a cache is wired, `emit` calls `cache.publish(name,
628
641
  payload)` **instead of** triggering local handlers directly — local handlers (including the
629
642
  SSE stream on the same pod) fire when the message comes back through the pub/sub `subscribe`
630
- callback. Auth `filter` still runs per-subscriber on the **receiving** pod's SSE handler —
643
+ callback. A handler subscribed with `{ localOnly: true }` is the exception: `emit` runs it directly
644
+ on the emitting pod, and a delivery through the cache never does — use it for work that must
645
+ happen once per emit, not once per pod. Without a cache it runs on every `emit` like any handler.
646
+ Auth `filter` still runs per-subscriber on the **receiving** pod's SSE handler —
631
647
  the transport only fans out by event name. Job queues receive the payload on every emit
632
648
  regardless of cache.
633
649
 
@@ -844,7 +860,7 @@ are reaped instead of lingering with their subscriptions and buffers.
844
860
  interface EventDef<TPayload = void> {
845
861
  readonly name: string;
846
862
  readonly schema?: TSchema;
847
- subscribe: (handler: EventHandler<TPayload>) => () => void;
863
+ subscribe: (handler: EventHandler<TPayload>, options?: { localOnly?: boolean }) => () => void;
848
864
  unsubscribeAll: () => void;
849
865
  emit: TPayload extends void ? () => Promise<void> : (payload: TPayload) => Promise<void>;
850
866
  useCache: (cache: PubSubCache) => Promise<EventDef<TPayload>>;
@@ -854,10 +870,11 @@ interface EventDef<TPayload = void> {
854
870
  canSubscribe: <P = unknown>(predicate: SubscribePredicate<P>) => EventDef<TPayload>;
855
871
  readonly _filter?: FramePredicate<TPayload>;
856
872
  filter: (predicate: FramePredicate<TPayload>) => EventDef<TPayload>;
857
- grant: (subject: string) => Promise<void>;
858
- revoke: (subject: string) => Promise<void>;
873
+ grant: (subject: string, match?: SubscriptionMatch) => Promise<void>;
874
+ revoke: (subject: string, match?: SubscriptionMatch) => Promise<void>;
859
875
  }
860
876
 
877
+ interface SubscriptionMatch { query: Record<string, string>; }
861
878
  interface SubscribeRequest { query: Record<string, string>; headers: Record<string, string>; }
862
879
  interface SubscribeContext<P = unknown> { subject: string; principal: P | undefined; request: SubscribeRequest; }
863
880
  type SubscribePredicate<P = unknown> = (ctx: SubscribeContext<P>) => boolean | Promise<boolean>;