@spfn/core 0.3.0-beta.26 → 0.3.0-beta.27

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.
@@ -21,6 +21,8 @@ interface StateShape {
21
21
  data: TSchema | undefined;
22
22
  input: TSchema | undefined;
23
23
  read: boolean;
24
+ /** Who the callbacks' `principal` is, from `.principal<P>()`; `unknown` until declared. */
25
+ principal: unknown;
24
26
  }
25
27
  /** The shape of `defineState(id)` before any call. */
26
28
  interface EmptyStateShape extends StateShape {
@@ -30,6 +32,7 @@ interface EmptyStateShape extends StateShape {
30
32
  data: undefined;
31
33
  input: undefined;
32
34
  read: false;
35
+ principal: unknown;
33
36
  }
34
37
  /** `T` with the fields of `U` replaced. */
35
38
  type WithShape<T extends StateShape, U extends Partial<StateShape>> = {
@@ -57,22 +60,38 @@ type StateResult<T extends StateShape> = T['data'] extends TSchema ? {
57
60
  type StateSnapshot<T extends StateShape> = Simplify<{
58
61
  at: string;
59
62
  } & StateResult<T>>;
60
- /** What `.canRead()` / `.canWrite()` decide on. */
63
+ /**
64
+ * What `.canRead()` decides on. `principal` may be `undefined`: at SSE connect
65
+ * it is what `resolvePrincipal` returned.
66
+ */
61
67
  type PermissionContext<T extends StateShape> = T['key'] extends TObject ? {
62
68
  subject: string;
63
- principal: unknown;
69
+ principal: T['principal'] | undefined;
64
70
  key: Static<T['key']>;
65
71
  } : {
66
72
  subject: string;
67
- principal: unknown;
73
+ principal: T['principal'] | undefined;
68
74
  };
69
- /** What `read()` receives. A shared state's value does not depend on the subject, so it gets none. */
75
+ /**
76
+ * What `.canWrite()` decides on. Only the write route asks it, and with
77
+ * `.principal()` declared that route refuses a request whose `auth` is
78
+ * `undefined` or `null` (401).
79
+ */
80
+ type WritePermissionContext<T extends StateShape> = Simplify<Omit<PermissionContext<T>, 'principal'> & {
81
+ principal: T['principal'];
82
+ }>;
83
+ /**
84
+ * What `read()` receives. A shared state's value does not depend on the
85
+ * subject, so it gets none. `principal` may be `undefined`: the change
86
+ * signal's re-read has no request.
87
+ */
70
88
  type ReadContext<T extends StateShape> = T['key'] extends TObject ? T['shared'] extends true ? {
71
- principal: unknown;
89
+ principal: T['principal'] | undefined;
72
90
  key: Static<T['key']>;
73
91
  } : PermissionContext<T> : PermissionContext<T>;
74
- /** What `write()` receives: the read context plus the validated input. */
75
- type WriteContext<T extends StateShape, I extends TSchema> = Simplify<ReadContext<T> & {
92
+ /** What `write()` receives: the read context, the write route's principal and the validated input. */
93
+ type WriteContext<T extends StateShape, I extends TSchema> = Simplify<Omit<ReadContext<T>, 'principal'> & {
94
+ principal: T['principal'];
76
95
  input: Static<I>;
77
96
  }>;
78
97
  /** The payload of `state.changed.emit()`: exactly what names the value to re-read. */
@@ -137,6 +156,8 @@ interface StateDefinition {
137
156
  id: string;
138
157
  key?: TObject;
139
158
  shared: boolean;
159
+ /** Whether `.principal()` was declared: the write route then refuses a request whose `auth` is `undefined` or `null`. */
160
+ principal: boolean;
140
161
  value?: TSchema;
141
162
  data?: TSchema;
142
163
  middlewares: (MiddlewareHandler | NamedMiddleware<string>)[];
@@ -204,6 +225,15 @@ declare class StateBuilder<TId extends string, T extends StateShape> {
204
225
  data<D extends TSchema>(schema: D): StateBuilder<TId, WithShape<T, {
205
226
  data: D;
206
227
  }>>;
228
+ /**
229
+ * Declare who the callbacks' `principal` is — what the app's auth
230
+ * middleware sets as `c.get('auth')`. Type-only, but for one rule: the write
231
+ * route refuses a request without a principal (401), so `.canWrite()` and
232
+ * `.write()` receive `P`; `.read()` and `.canRead()` receive `P | undefined`.
233
+ */
234
+ principal<P>(): StateBuilder<TId, WithShape<T, {
235
+ principal: P;
236
+ }>>;
207
237
  /**
208
238
  * Middleware for the two per-state routes, `get<Id>State` / `put<Id>State`.
209
239
  * Not authorization: the snapshot and the SSE stream cannot run it, so a
@@ -217,7 +247,7 @@ declare class StateBuilder<TId extends string, T extends StateShape> {
217
247
  /** Who may read. Required on a keyed state; checked on HTTP and at SSE connect. */
218
248
  canRead(predicate: (ctx: PermissionContext<T>) => boolean | Promise<boolean>): StateBuilder<TId, T>;
219
249
  /** Who may write. Absent → `canRead` decides. */
220
- canWrite(predicate: (ctx: PermissionContext<T>) => boolean | Promise<boolean>): StateBuilder<TId, T>;
250
+ canWrite(predicate: (ctx: WritePermissionContext<T>) => boolean | Promise<boolean>): StateBuilder<TId, T>;
221
251
  /** The only source of a value. Required. */
222
252
  read(fn: (ctx: ReadContext<T>) => StateResult<T> | Promise<StateResult<T>>): StateBuilder<TId, WithShape<T, {
223
253
  read: true;
@@ -294,6 +324,19 @@ declare function defineState<TId extends string>(id: TId): StateBuilder<TId, Emp
294
324
 
295
325
  /** Who a request is for. `null` answers 401. */
296
326
  type SubjectResolver = (c: Context) => string | null;
327
+ /**
328
+ * What the router gives the snapshot route `GET <path>` alone. A per-state
329
+ * route keeps its own state's `.use()` / `.skip()` / `.contract()`, and the
330
+ * SSE stream runs none of them.
331
+ */
332
+ interface SnapshotRouteOptions {
333
+ /** Middleware for the snapshot route only. Not authorization: the stream never runs it (see README). */
334
+ use?: (MiddlewareHandler | NamedMiddleware<string>)[];
335
+ /** Server-level named middlewares the snapshot route skips; `'*'` skips every one. */
336
+ skip?: string[] | '*';
337
+ /** Publishes the snapshot route in the contract; the response schema is derived. */
338
+ contract?: StateContract;
339
+ }
297
340
  /** What the browser cannot read from a type: every state, in declaration order, its key fields and whether it has a write. */
298
341
  type StatesManifest = Record<string, {
299
342
  key: string[];
@@ -308,7 +351,12 @@ type StatesManifest = Record<string, {
308
351
  * subscribes each state's change signal — once, here.
309
352
  */
310
353
 
311
- interface StateRouterOptions {
354
+ /**
355
+ * Where the router mounts, whom a request is for, and the snapshot route's own
356
+ * `use` / `skip` / `contract` (`SnapshotRouteOptions`) — those reach `GET <path>`
357
+ * only, never a per-state route or the SSE stream.
358
+ */
359
+ interface StateRouterOptions extends SnapshotRouteOptions {
312
360
  /**
313
361
  * Where the routes are mounted: `GET <path>`, `GET|PUT <path>/<id>`.
314
362
  * @default '/state'
@@ -392,4 +440,4 @@ type InferStateInput<R extends StateRouter<any>, TId extends string> = Shape<Sta
392
440
  */
393
441
  declare function defineStateRouter<S extends Record<string, RoutableState>>(states: S, options?: StateRouterOptions): StateRouter<S>;
394
442
 
395
- export { type ChangedPayload, type GrantTarget, type InferStateInput, type InferStateKey, type InferStateValue, type PermissionContext, type ReadContext, type RevokeTarget, type RoutableState, StateBuilder, type StateContract, type StateEvents, type StateFrame, type StateKey, type StateResult, type StateRouter, type StateRouterOptions, type StateRoutes, type StateShape, type StateSnapshot, type StateValue, type StateWriteOptions, type StatesManifest, type StatesSnapshot, type SubjectResolver, type WriteContext, defineState, defineStateRouter };
443
+ export { type ChangedPayload, type GrantTarget, type InferStateInput, type InferStateKey, type InferStateValue, type PermissionContext, type ReadContext, type RevokeTarget, type RoutableState, type SnapshotRouteOptions, StateBuilder, type StateContract, type StateEvents, type StateFrame, type StateKey, type StateResult, type StateRouter, type StateRouterOptions, type StateRoutes, type StateShape, type StateSnapshot, type StateValue, type StateWriteOptions, type StatesManifest, type StatesSnapshot, type SubjectResolver, type WriteContext, type WritePermissionContext, defineState, defineStateRouter };
@@ -1,5 +1,6 @@
1
1
  import { Type, Kind } from '@sinclair/typebox';
2
2
  import { Value } from '@sinclair/typebox/value';
3
+ import { getTransactionContext, onAfterCommit } from '@spfn/core/db';
3
4
  import { defineEvent } from '@spfn/core/event';
4
5
  import { logger } from '@spfn/core/logger';
5
6
  import { defineRouter, route } from '@spfn/core/route';
@@ -83,7 +84,12 @@ function toFrame(def, snapshot, subject, key) {
83
84
  }
84
85
  async function readAndPublish(def, event, subject, key, principal) {
85
86
  const snapshot = await readSnapshot(def, readContext(def, subject, principal, key));
86
- await event.emit(toFrame(def, snapshot, subject, key));
87
+ const frame = toFrame(def, snapshot, subject, key);
88
+ if (getTransactionContext()) {
89
+ onAfterCommit(() => event.emit(frame));
90
+ } else {
91
+ await event.emit(frame);
92
+ }
87
93
  return snapshot;
88
94
  }
89
95
  function framePayloadSchema(def) {
@@ -154,7 +160,7 @@ async function onSignal(state, payload) {
154
160
  try {
155
161
  await readAndPublish(state._definition, state._event, subject, key, void 0);
156
162
  } catch (error) {
157
- stateLogger.warn(`State "${state.id}" could not be re-read on its change signal; no frame was sent`, {
163
+ stateLogger.warn(`State "${state.id}" could not be re-read or published on its change signal; no frame was sent`, {
158
164
  state: state.id,
159
165
  error: error instanceof Error ? error.message : String(error)
160
166
  });
@@ -207,6 +213,16 @@ var StateBuilder = class _StateBuilder {
207
213
  this.assertOnce("data", !!this._definition.data);
208
214
  return this.with({ data: schema });
209
215
  }
216
+ /**
217
+ * Declare who the callbacks' `principal` is — what the app's auth
218
+ * middleware sets as `c.get('auth')`. Type-only, but for one rule: the write
219
+ * route refuses a request without a principal (401), so `.canWrite()` and
220
+ * `.write()` receive `P`; `.read()` and `.canRead()` receive `P | undefined`.
221
+ */
222
+ principal() {
223
+ this.assertOnce("principal", this._definition.principal);
224
+ return this.with({ principal: true });
225
+ }
210
226
  /**
211
227
  * Middleware for the two per-state routes, `get<Id>State` / `put<Id>State`.
212
228
  * Not authorization: the snapshot and the SSE stream cannot run it, so a
@@ -371,7 +387,7 @@ function defineState(id) {
371
387
  `defineState("${id}"): a state id must match ${STATE_ID}. It becomes part of the route names get<Id>State / put<Id>State and of the event name state.<id>.changed. Use a lowerCamel identifier, e.g. "myState".`
372
388
  );
373
389
  }
374
- return new StateBuilder(id, { id, shared: false, middlewares: [] });
390
+ return new StateBuilder(id, { id, shared: false, principal: false, middlewares: [] });
375
391
  }
376
392
  var defaultSubject = (c) => c.get("auth")?.userId ?? null;
377
393
  function stateRouteName(method, id) {
@@ -384,19 +400,30 @@ function requireSubject(c, resolveSubject) {
384
400
  }
385
401
  return subject;
386
402
  }
403
+ function writePrincipal(def, c) {
404
+ const principal = c.get("auth");
405
+ if (def.principal && principal == null) {
406
+ throw new UnauthorizedError({
407
+ message: `State "${def.id}" declares .principal(), and this request carries none`
408
+ });
409
+ }
410
+ return principal;
411
+ }
387
412
  async function assertPermitted(def, can, ctx) {
388
413
  const predicate = can === "canWrite" ? def.canWrite ?? def.canRead : def.canRead;
389
414
  if (predicate && !await predicate(ctx)) {
390
415
  throw new ForbiddenError({ message: `${can === "canWrite" ? "Writing" : "Reading"} state "${def.id}" is not permitted` });
391
416
  }
392
417
  }
393
- function responseSchema(def) {
418
+ function resultSchema2(def) {
394
419
  return Type.Object({
395
- at: Type.String(),
396
420
  value: def.value,
397
421
  ...def.data ? { data: def.data } : {}
398
422
  });
399
423
  }
424
+ function responseSchema(def) {
425
+ return Type.Object({ at: Type.String(), ...resultSchema2(def).properties });
426
+ }
400
427
  function routeContract(def, write) {
401
428
  if (!def.contract) {
402
429
  return void 0;
@@ -431,7 +458,7 @@ function writeRoute(state, path, resolveSubject) {
431
458
  const write = def.write;
432
459
  return stateRoute(def, "put", `${path}/${def.id}`, { body: write.input, ...keyInput(def) }).handler(async (c) => {
433
460
  const subject = requireSubject(c.raw, resolveSubject);
434
- const principal = c.raw.get("auth");
461
+ const principal = writePrincipal(def, c.raw);
435
462
  const { body, query } = await c.data();
436
463
  const key = def.key ? pickKey(def.key, query) : void 0;
437
464
  await assertPermitted(def, "canWrite", permissionContext(def, subject, principal, key));
@@ -465,8 +492,22 @@ function stateManifest(states) {
465
492
  write: state._definition.write !== void 0
466
493
  }]));
467
494
  }
468
- function snapshotRoute(states, manifest, path, resolveSubject) {
469
- return route.get(path).input({ query: snapshotQuery(states) }).handler(async (c) => {
495
+ function snapshotResponseSchema(states) {
496
+ const manifestEntry = Type.Object({ key: Type.Array(Type.String()), write: Type.Boolean() });
497
+ return Type.Object({
498
+ at: Type.String(),
499
+ states: Type.Object(Object.fromEntries(states.map((state) => [state.id, Type.Optional(resultSchema2(state._definition))]))),
500
+ manifest: Type.Object(Object.fromEntries(states.map((state) => [state.id, manifestEntry])))
501
+ });
502
+ }
503
+ function snapshotBuilder(states, path, options) {
504
+ const builder = route.get(path).input({ query: snapshotQuery(states) });
505
+ const used = options.use?.length ? builder.use(options.use) : builder;
506
+ const skipped = options.skip ? used.skip(options.skip) : used;
507
+ return options.contract ? skipped.contract(stripUndefined({ ...options.contract, response: snapshotResponseSchema(states) })) : skipped;
508
+ }
509
+ function snapshotRoute(states, manifest, path, resolveSubject, options = {}) {
510
+ return snapshotBuilder(states, path, options).handler(async (c) => {
470
511
  const subject = requireSubject(c.raw, resolveSubject);
471
512
  const principal = c.raw.get("auth");
472
513
  const { query } = await c.data();
@@ -486,17 +527,19 @@ function defineStateRouter(states, options = {}) {
486
527
  const list = Object.values(states);
487
528
  assertPath(path);
488
529
  list.forEach(assertRoutable);
530
+ assertSnapshotMiddlewareIsNotAuthorization(list, options);
489
531
  assertDistinctIds(list);
490
532
  list.forEach((state) => assertNotRouted(state, path));
491
533
  list.forEach((state) => bindState(state._definition, path));
492
534
  list.forEach(subscribeChangeSignals);
493
535
  return {
494
- router: defineRouter(deriveRoutes(list, path, options.subject ?? defaultSubject)),
536
+ router: defineRouter(deriveRoutes(list, path, options)),
495
537
  events: Object.fromEntries(list.map((state) => [stateEventName(state.id), state._event])),
496
538
  states
497
539
  };
498
540
  }
499
- function deriveRoutes(states, path, resolveSubject) {
541
+ function deriveRoutes(states, path, options) {
542
+ const resolveSubject = options.subject ?? defaultSubject;
500
543
  const routes = {};
501
544
  for (const state of states) {
502
545
  routes[stateRouteName("get", state.id)] = readRoute(state, path, resolveSubject);
@@ -504,7 +547,7 @@ function deriveRoutes(states, path, resolveSubject) {
504
547
  routes[stateRouteName("put", state.id)] = writeRoute(state, path, resolveSubject);
505
548
  }
506
549
  }
507
- routes.getStates = snapshotRoute(states, stateManifest(states), path, resolveSubject);
550
+ routes.getStates = snapshotRoute(states, stateManifest(states), path, resolveSubject, options);
508
551
  return routes;
509
552
  }
510
553
  function assertPath(path) {
@@ -543,6 +586,14 @@ function assertMiddlewareIsNotAuthorization(state) {
543
586
  );
544
587
  }
545
588
  }
589
+ function assertSnapshotMiddlewareIsNotAuthorization(states, options) {
590
+ const unguarded = states.find((state) => !state._definition.canRead);
591
+ if (((options.use?.length ?? 0) > 0 || options.skip) && unguarded) {
592
+ throw new Error(
593
+ `defineStateRouter: the router gives the snapshot route use or skip, but state "${unguarded.id}" declares no .canRead(). The snapshot's middleware never reaches the SSE stream, which serves the same state, so it cannot authorize. Authorization belongs in .canRead(); a state readable by every subject declares .canRead(() => true) to say so.`
594
+ );
595
+ }
596
+ }
546
597
  function assertChangedBy(state, event) {
547
598
  const payload = event.schema;
548
599
  const signal = changedPayloadSchema(state._definition);
@@ -1 +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/** What the browser cannot read from a type: every state, in declaration order, its key fields and whether it has a write. */\nexport type StatesManifest = Record<string, { key: string[]; write: boolean }>;\n\n/** The snapshot's `manifest`. It is static: the router builds it once and every snapshot answers the same object. */\nexport function stateManifest(states: RoutableState[]): StatesManifest\n{\n return Object.fromEntries(states.map(state => [state.id, {\n key: Object.keys(state._definition.key?.properties ?? {}),\n write: state._definition.write !== undefined,\n }]));\n}\n\n/**\n * `GET <path>`: one `at`, then every readable state in declaration order, and\n * the router's `manifest`. A `read()` that throws fails it all.\n */\nexport function snapshotRoute(states: RoutableState[], manifest: StatesManifest, 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 manifest,\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, stateManifest, 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/**\n * What `GET <path>` answers: every state the subject may read and whose key\n * the query carries, and the manifest of every state — its key fields and\n * whether it has a write — in declaration order.\n */\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 manifest: { [K in keyof S as S[K]['id']]: { key: string[]; write: boolean } };\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, stateManifest(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
+ {"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","resultSchema"],"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 { getTransactionContext, onAfterCommit } from '@spfn/core/db';\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/**\n * Read the value for one subject and key, send it as one frame, and return the\n * snapshot. Inside a transaction the frame is published after the root\n * transaction commits, and never when the root rolls back; it still carries the\n * value read inside it. A nested transaction (a savepoint) that rolls back\n * while the root commits still publishes the frame read inside it, because\n * after-commit callbacks belong to the root: emit the signal from the outer\n * transaction, or after it, when an inner one may roll back. Outside a\n * transaction the frame is sent here and awaited, so an emit that throws fails\n * the caller — `onAfterCommit` would only log it.\n */\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 const frame = toFrame(def, snapshot, subject, key);\n\n if (getTransactionContext())\n {\n onAfterCommit(() => event.emit(frame));\n }\n else\n {\n await event.emit(frame);\n }\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 or published 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 WritePermissionContext,\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 * Declare who the callbacks' `principal` is — what the app's auth\n * middleware sets as `c.get('auth')`. Type-only, but for one rule: the write\n * route refuses a request without a principal (401), so `.canWrite()` and\n * `.write()` receive `P`; `.read()` and `.canRead()` receive `P | undefined`.\n */\n principal<P>(): StateBuilder<TId, WithShape<T, { principal: P }>>\n {\n this.assertOnce('principal', this._definition.principal);\n\n return this.with({ principal: true });\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: WritePermissionContext<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, principal: 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, MiddlewareHandler } from 'hono';\nimport { ForbiddenError, UnauthorizedError } from '@spfn/core/errors';\nimport { route } from '@spfn/core/route';\nimport type { NamedMiddleware, 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, StateContract, 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\n/**\n * The write route's principal, `c.get('auth')`. A state that declared\n * `.principal()` types `canWrite` / `write` without `undefined`, so a request\n * whose `auth` is `undefined` or `null` is refused here, before either runs.\n */\nfunction writePrincipal(def: StateDefinition, c: Context): unknown\n{\n const principal = c.get('auth');\n\n if (def.principal && principal == null)\n {\n throw new UnauthorizedError({\n message: `State \"${def.id}\" declares .principal(), and this request carries none`,\n });\n }\n\n return principal;\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\n/** `{ value, data? }` as declared: one state's response without `at`, and its entry in the snapshot. */\nfunction resultSchema(def: StateDefinition): TObject\n{\n return Type.Object({\n value: def.value!,\n ...(def.data ? { data: def.data } : {}),\n });\n}\n\nfunction responseSchema(def: StateDefinition): TObject\n{\n return Type.Object({ at: Type.String(), ...resultSchema(def).properties });\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 → principal (with `.principal()`) → 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 = writePrincipal(def, c.raw);\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/**\n * What the router gives the snapshot route `GET <path>` alone. A per-state\n * route keeps its own state's `.use()` / `.skip()` / `.contract()`, and the\n * SSE stream runs none of them.\n */\nexport interface SnapshotRouteOptions\n{\n /** Middleware for the snapshot route only. Not authorization: the stream never runs it (see README). */\n use?: (MiddlewareHandler | NamedMiddleware<string>)[];\n\n /** Server-level named middlewares the snapshot route skips; `'*'` skips every one. */\n skip?: string[] | '*';\n\n /** Publishes the snapshot route in the contract; the response schema is derived. */\n contract?: StateContract;\n}\n\n/** What the browser cannot read from a type: every state, in declaration order, its key fields and whether it has a write. */\nexport type StatesManifest = Record<string, { key: string[]; write: boolean }>;\n\n/** The snapshot's `manifest`. It is static: the router builds it once and every snapshot answers the same object. */\nexport function stateManifest(states: RoutableState[]): StatesManifest\n{\n return Object.fromEntries(states.map(state => [state.id, {\n key: Object.keys(state._definition.key?.properties ?? {}),\n write: state._definition.write !== undefined,\n }]));\n}\n\n/**\n * The snapshot's response: `at`, one optional `{ value, data? }` per state and\n * one required manifest entry per state, in declaration order. Fresh objects,\n * so no per-state schema is touched.\n */\nfunction snapshotResponseSchema(states: RoutableState[]): TObject\n{\n const manifestEntry = Type.Object({ key: Type.Array(Type.String()), write: Type.Boolean() });\n\n return Type.Object({\n at: Type.String(),\n states: Type.Object(Object.fromEntries(states.map(state => [state.id, Type.Optional(resultSchema(state._definition))]))),\n manifest: Type.Object(Object.fromEntries(states.map(state => [state.id, manifestEntry]))),\n });\n}\n\n/**\n * `route.get(path)` with the router's snapshot options. Each is applied only\n * when given — an empty `use` counts as not given — so a router without them\n * derives the route it always did. The\n * contract is built here, once, when the router is built.\n */\nfunction snapshotBuilder(states: RoutableState[], path: string, options: SnapshotRouteOptions)\n{\n const builder = route.get(path).input({ query: snapshotQuery(states) });\n const used = options.use?.length ? builder.use(options.use) : builder;\n const skipped = options.skip ? used.skip(options.skip) : used;\n\n return options.contract\n ? skipped.contract(stripUndefined({ ...options.contract, response: snapshotResponseSchema(states) }) as RouteContract)\n : skipped;\n}\n\n/**\n * `GET <path>`: one `at`, then every readable state in declaration order, and\n * the router's `manifest`. A `read()` that throws fails it all.\n */\nexport function snapshotRoute(\n states: RoutableState[],\n manifest: StatesManifest,\n path: string,\n resolveSubject: SubjectResolver,\n options: SnapshotRouteOptions = {},\n): RouteDef<any, any, any>\n{\n return snapshotBuilder(states, path, options).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 manifest,\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, stateManifest, stateRouteName, writeRoute } from './state-routes';\nimport type { SnapshotRouteOptions, SubjectResolver } from './state-routes';\nimport type { RoutableState, StateFrame, StateKey, StateResult, StateSnapshot, StateValue } from './types';\n\n/**\n * Where the router mounts, whom a request is for, and the snapshot route's own\n * `use` / `skip` / `contract` (`SnapshotRouteOptions`) — those reach `GET <path>`\n * only, never a per-state route or the SSE stream.\n */\nexport interface StateRouterOptions extends SnapshotRouteOptions\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/**\n * What `GET <path>` answers: every state the subject may read and whose key\n * the query carries, and the manifest of every state — its key fields and\n * whether it has a write — in declaration order.\n */\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 manifest: { [K in keyof S as S[K]['id']]: { key: string[]; write: boolean } };\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 assertSnapshotMiddlewareIsNotAuthorization(list, options);\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)) 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, options: StateRouterOptions): Record<string, RouteDef<any, any, any>>\n{\n const resolveSubject = options.subject ?? defaultSubject;\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, stateManifest(states), path, resolveSubject, options);\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/**\n * The router's `use` / `skip` reach the snapshot route only — never the SSE\n * stream, which serves the same states — so, as for a state's own `.use()`,\n * every state must authorize with `canRead`. A `contract` alone runs nothing.\n */\nfunction assertSnapshotMiddlewareIsNotAuthorization(states: RoutableState[], options: StateRouterOptions): void\n{\n const unguarded = states.find(state => !state._definition.canRead);\n\n if (((options.use?.length ?? 0) > 0 || options.skip) && unguarded)\n {\n throw new Error(\n `defineStateRouter: the router gives the snapshot route use or skip, but state \"${unguarded.id}\" declares no `\n + '.canRead(). The snapshot\\'s middleware never reaches the SSE stream, which serves the same state, so it '\n + 'cannot authorize. Authorization belongs in .canRead(); a state readable by every subject declares '\n + '.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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfn/core",
3
- "version": "0.3.0-beta.26",
3
+ "version": "0.3.0-beta.27",
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": {
@@ -34,11 +34,11 @@ import type { states } from '@/server/states';
34
34
  From `@spfn/core/state`:
35
35
 
36
36
  - Builder: `defineState(id)` → `StateBuilder`
37
- - Router: `defineStateRouter(states, { path?, subject? })` → `StateRouter`
38
- - Types: `StateBuilder`, `StateRouter`, `StateRouterOptions`, `StateRoutes`, `StateEvents`,
37
+ - Router: `defineStateRouter(states, { path?, subject?, use?, skip?, contract? })` → `StateRouter`
38
+ - Types: `StateBuilder`, `StateRouter`, `StateRouterOptions`, `SnapshotRouteOptions`, `StateRoutes`, `StateEvents`,
39
39
  `StatesSnapshot`, `StatesManifest`, `SubjectResolver`, `InferStateValue`, `InferStateKey`, `InferStateInput`,
40
40
  `StateShape`, `StateValue`, `StateKey`, `StateResult`, `StateSnapshot`, `StateFrame`,
41
- `ReadContext`, `PermissionContext`, `WriteContext`, `ChangedPayload`, `GrantTarget`,
41
+ `ReadContext`, `PermissionContext`, `WritePermissionContext`, `WriteContext`, `ChangedPayload`, `GrantTarget`,
42
42
  `RevokeTarget`, `StateContract`, `StateWriteOptions`, `RoutableState`
43
43
 
44
44
  `StateBuilder` methods — immutable, every call returns a new builder, order free, no terminal
@@ -49,10 +49,11 @@ method:
49
49
  | `.key(schema, { shared? })` | Key fields: one value per key. `shared: true` — the value does not depend on the subject | a non-object schema; a field that is not a required `Type.String()`; a field named `events` or `token`; a second call |
50
50
  | `.value(schema)` | The value. Required | a second call |
51
51
  | `.data(schema)` | Data attached to the value. Optional | a second call |
52
+ | `.principal<P>()` | Type-only: who the callbacks' `principal` is — what the app's auth middleware sets as `c.get('auth')`. The write route then refuses a request whose `auth` is `undefined` or `null` (401) | a second call |
52
53
  | `.use(mws)` / `.skip(names)` | Middleware for the two per-state routes, `get<Id>State` / `put<Id>State`; calls add up. **Not authorization** — the snapshot and the SSE stream cannot run it; authorize with `.canRead()` (see [Permissions](#permissions)) | at `defineStateRouter`, when the state declares no `.canRead()` |
53
54
  | `.contract({ since, auth?, requiresSession?, deprecatedIn?, removedIn? })` | Publishes the read route, the write route and the event | a second call |
54
55
  | `.canRead(fn)` | `({ subject, principal, key? }) => boolean \| Promise<boolean>`. Required on a keyed state | a second call |
55
- | `.canWrite(fn)` | Same shape. Absent → `canRead` decides | a second call |
56
+ | `.canWrite(fn)` | Same shape; `principal` without `undefined` (below). Absent → `canRead` decides | a second call |
56
57
  | `.read(fn)` | The only source of a value. Required. Returns `{ value }`, or `{ value, data }` with `.data` — checked against the declaration on every path | a second call |
57
58
  | `.write(input, fn, { since?, deprecatedIn?, removedIn? })` | Derives the write route. `fn` gets the read context plus `input` and returns nothing | a second call |
58
59
  | `.changedBy(events)` | Domain events whose payload is read like the change signal's (see [The change signal](#the-change-signal)) | a second call; at `defineStateRouter`, an event whose payload schema lacks a required field |
@@ -63,9 +64,48 @@ keyed state only, and required there), `.revoke({ subject, key? })`, `.id`.
63
64
  `StateRouter`: `.router` (a `Router` from `defineRouter`), `.events` (`Record` of the SSE
64
65
  events keyed by wire name), `.states` (the declarations as given).
65
66
 
67
+ `defineStateRouter` options:
68
+
69
+ | Option | Effect |
70
+ | --- | --- |
71
+ | `path` | Where the routes are mounted, default `/state` |
72
+ | `subject` | Who an HTTP request is for, default `c => c.get('auth')?.userId ?? null` |
73
+ | `use` | Middleware for the snapshot route `GET <path>` only. **Not authorization**; refused when a state declares no `.canRead()`. An empty `use` is not a middleware and is not refused |
74
+ | `skip` | Server-level named middlewares the snapshot route skips; `'*'` skips every one. Refused like `use` |
75
+ | `contract` | `{ since, auth?, requiresSession?, deprecatedIn?, removedIn? }` — publishes the snapshot route; its response schema is derived |
76
+
77
+ `use`, `skip` and `contract` reach the snapshot route only. A per-state route keeps exactly its
78
+ own state's `.use()` / `.skip()` / `.contract()`; nothing is merged either way. A server that
79
+ gates every request behind a named middleware (say `'requirements'`: "finish your onboarding")
80
+ lets the onboarding states `.skip(['requirements'])` and the router `skip: ['requirements']`, so
81
+ the shell's first snapshot is served to exactly the people it routes. The router does not infer
82
+ the snapshot's skips from its states'.
83
+
66
84
  The types of `.read()`, `.write()`, `.canRead()` and `.canWrite()` contexts and of `R` are
67
85
  computed from the schemas declared *before* the call — runtime order is free, but declare
68
- `.key()`, `.value()` and `.data()` first to have the functions checked against them.
86
+ `.key()`, `.value()`, `.data()` and `.principal()` first to have the functions checked against them.
87
+
88
+ `principal` in each callback, with `.principal<P>()` declared:
89
+
90
+ | Context | `principal` | Why |
91
+ | --- | --- | --- |
92
+ | `ReadContext` (`.read`) | `P \| undefined` | the change signal's re-read has no request, so none |
93
+ | `PermissionContext` (`.canRead`) | `P \| undefined` | SSE connect passes what `resolvePrincipal` returned, possibly `undefined` |
94
+ | `WritePermissionContext` (`.canWrite`) | `P` | asked on `PUT <path>/<id>` only, which refuses a request whose `auth` is `undefined` or `null` |
95
+ | `WriteContext` (`.write`) | `P` | the same route |
96
+
97
+ Without `.principal()` every one is `unknown`. `defineState<AuthContext>('consent')` is not the
98
+ form: an explicit type argument would default the id to `string` and lose the route-name
99
+ literals. Nor is a router option: the router cannot retype callbacks declared before it.
100
+
101
+ ```typescript
102
+ export const consent = defineState('consent')
103
+ .principal<AuthContext>()
104
+ .value(Consent)
105
+ .canWrite(({ principal }) => principal.user.verified) // AuthContext
106
+ .read(({ subject }) => consentService.current(subject))
107
+ .write(Input, ({ principal, input }) => consentService.record(principal.user.email, input));
108
+ ```
69
109
 
70
110
  ---
71
111
 
@@ -160,7 +200,8 @@ Route names are `get<Id>State` / `put<Id>State` with the id's first letter upper
160
200
  id must match `^[a-z][a-zA-Z0-9]*$` — `defineState` refuses another.
161
201
 
162
202
  `defineStateRouter` refuses, naming the state: no `.value()` or `.read()`; a keyed state
163
- without `.canRead()`; a state with `.use()` or `.skip()` but no `.canRead()`; a
203
+ without `.canRead()`; a state with `.use()` or `.skip()` but no `.canRead()`; a router `use`
204
+ or `skip` while any state declares no `.canRead()` (the first such state is named); a
164
205
  `.changedBy()` event whose payload schema lacks a field the signal needs; two states with one
165
206
  id; a `.write(…, { since })` on a state without `.contract()`; a state already grouped by
166
207
  another router (each router subscribes the change signal, so every change would be read and
@@ -173,12 +214,17 @@ sent twice). A builder without `.value()` or
173
214
 
174
215
  The subject comes from `options.subject(c)`, default `c.get('auth')?.userId ?? null` — the
175
216
  SSE `getSubject` default. No subject → `UnauthorizedError` (401). The principal on HTTP is
176
- `c.get('auth')` as the app's middleware set it.
217
+ `c.get('auth')` as the app's middleware set it. A state that declared `.principal()` refuses a
218
+ write whose request's `auth` is `undefined` or `null` with `UnauthorizedError` (401), after the subject and before
219
+ `canWrite`; the read and snapshot routes never refuse on a missing principal.
177
220
 
178
221
  - **Read** `GET <path>/<id>`: subject → key (query, validated) → `canRead` (false → 403) →
179
222
  `at` → `read()` → `{ at, value, data }`.
180
- - **Write** `PUT <path>/<id>`: subject → key → `canWrite ?? canRead` (false → 403, `write` not
181
- called) → `write({ …, input })` → `at` → `read()` → one SSE frame → `{ at, value, data }`.
223
+ - **Write** `PUT <path>/<id>`: subject → principal (whose `auth` is `undefined` or `null` → 401) → key →
224
+ `canWrite ?? canRead` (false → 403, `write` not called) → `write({ …, input })` → `at` →
225
+ `read()` → one SSE frame → `{ at, value, data }`.
226
+ When the handler runs inside a transaction (`.use([Transactional()])`), the frame is
227
+ published after that transaction commits (see [Frames and transactions](#frames-and-transactions)).
182
228
  A `write` that throws propagates; nothing is read and no frame is sent. The input is a
183
229
  command, never the value: what the route answers is re-read.
184
230
  - **Snapshot** `GET <path>`: subject → one `at` → for each state, in declaration order: a keyed
@@ -196,15 +242,17 @@ A result that does not match fails the read, write and snapshot routes with an `
196
242
  naming the state and the first validation message, never the value; on the change signal it
197
243
  is logged at warn and sends nothing; `grant` rejects with the same error and sends nothing.
198
244
 
199
- A write that committed and then failed to read — `read()` threw or returned an undeclared
200
- result — answers 500 and sends no frame, although the write ran. There is no value to report;
201
- the next signal or read brings the client up to date.
245
+ A write whose `read()` then fails — it threw or returned an undeclared result — answers 500
246
+ and sends no frame. Without a transaction the write has already committed: there is no value
247
+ to report, and the next signal or read brings the client up to date. Under
248
+ `.use([Transactional()])` the failed read rolls the write back with it, so nothing changed.
202
249
 
203
250
  The derived routes are ordinary `RouteDef`s registered by `registerRoutes`, so `.use()`
204
251
  middleware runs inside the route's own chain, after the app's global middleware — it sees the
205
- `auth` the app set. It runs on the two per-state routes only: the snapshot route and the SSE
206
- stream carry no state's `.use()`. That is why `.use()` / `.skip()` require `.canRead()` — a
207
- guard in middleware would hold on `GET <path>/<id>` and leak through `GET <path>` and the
252
+ `auth` the app set. A state's `.use()` / `.skip()` / `.contract()` reach its two per-state
253
+ routes only; the router's `use` / `skip` / `contract` reach the snapshot route only. The SSE
254
+ stream runs neither. That is why `.use()` / `.skip()` — the state's and the router's — require
255
+ `.canRead()`: a guard in middleware would hold on one route and leak through the others and the
208
256
  stream. A state that needs middleware only for, say, rate limiting declares
209
257
  `.canRead(() => true)` to say so.
210
258
 
@@ -213,8 +261,10 @@ stream. A state that needs middleware only for, say, rate limiting declares
213
261
  ## The change signal
214
262
 
215
263
  The app emits `state.changed` **after the commit** that changed the value — from
216
- `onAfterCommit` (`@spfn/core/db`), not inside the transaction. The module never reads on its
217
- own: no polling, no database trigger. On each signal it reads and sends one frame:
264
+ `onAfterCommit` (`@spfn/core/db`), not inside the transaction. An emit made inside a
265
+ transaction anyway reads there and sends its frame at the commit (see
266
+ [Frames and transactions](#frames-and-transactions)). The module never reads on its own: no
267
+ polling, no database trigger. On each signal it reads and sends one frame:
218
268
 
219
269
  | State | Read | Frame |
220
270
  | --- | --- | --- |
@@ -257,6 +307,27 @@ module attaches nothing to the event — no `canSubscribe`, no `filter`; it only
257
307
  `read()`'s result is copied into the frame, so neither a handler mutating what it returned nor
258
308
  a subscriber mutating the payload changes the other.
259
309
 
310
+ ### Frames and transactions
311
+
312
+ Every frame — of the write route, of the change signal and of `grant` — is sent by one rule:
313
+
314
+ | Where the read ran | Frame |
315
+ | --- | --- |
316
+ | outside a transaction | emitted at once and awaited; an emit that throws fails the write or `grant`; on the change signal it is logged at warn and `changed.emit` resolves |
317
+ | inside a transaction | queued with `onAfterCommit` and published after the root transaction commits; never when the root rolls back |
318
+
319
+ - The frame carries the value read inside the transaction, with that read's `at`; nothing is
320
+ read again after the commit. The response is the same snapshot.
321
+ - So a `changed.emit` or a `grant` made inside a transaction is deferred to its commit, like a
322
+ write.
323
+ - The queue belongs to the root transaction: a `Transactional()` nested in an outer
324
+ `runInTransaction` publishes at the outer commit.
325
+ - A nested transaction (a savepoint) that rolls back while the root commits still publishes
326
+ the frame read inside it, because after-commit callbacks belong to the root; emit the signal
327
+ from the outer transaction, or after it, when an inner one may roll back.
328
+ - A deferred emit runs outside the transaction context; an error it throws is logged by the
329
+ transaction runner and reaches nobody.
330
+
260
331
  ---
261
332
 
262
333
  ## Permissions
@@ -266,7 +337,7 @@ a subscriber mutating the payload changes the other.
266
337
  | `canRead` | `GET <path>/<id>` | 403 |
267
338
  | `canRead` | `GET <path>` | that state omitted |
268
339
  | `canRead` | SSE connect (`canSubscribe`), with the key from the connect query | that event in `connected.deniedEvents` |
269
- | `canWrite ?? canRead` | `PUT <path>/<id>` | 403 |
340
+ | `canWrite ?? canRead` | `PUT <path>/<id>` | 403; with `.principal()` declared, a request whose `auth` is `undefined` or `null` is 401 before it is asked |
270
341
 
271
342
  On SSE the connection declares its key in the connect query —
272
343
  `/events/stream?events=state.runtime.changed&workspaceId=w1&token=…`. The module sets each
@@ -342,7 +413,10 @@ change" by the client (implemented in the client half). There is no version coun
342
413
  - the SSE event `state.<id>.changed` with `since` / `deprecatedIn` / `removedIn`.
343
414
 
344
415
  A state without `.contract()` appears nowhere, like a route without one. The snapshot route is
345
- not contracted, its `manifest` included. A `value` literal removed later is `response.type-changed` on the read
416
+ contracted by the router's own `contract` option, never by a state's: response
417
+ `{ at, states: { [id]?: { value, data? } }, manifest: { [id]: { key: string[], write: boolean } } }`,
418
+ each `states` entry optional and each `manifest` entry required, in declaration order — built
419
+ once when the router is built. Without that option it appears nowhere. A `value` literal removed later is `response.type-changed` on the read
346
420
  operation and `event.payload.type-changed` on the event, as any route and event.
347
421
 
348
422
  ---