experimental-a2 0.5.0 → 0.6.0

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/{ai-CFNeCrRl.d.ts → ai-D_PGS-JR.d.ts} +2 -2
  3. package/dist/{ai-CFNeCrRl.d.ts.map → ai-D_PGS-JR.d.ts.map} +1 -1
  4. package/dist/ai-server.d.ts +2 -2
  5. package/dist/ai-server.js +1 -1
  6. package/dist/ai.d.ts +1 -1
  7. package/dist/{client-D7mvIXrF.d.ts → client-CdMqi7mC.d.ts} +23 -12
  8. package/dist/client-CdMqi7mC.d.ts.map +1 -0
  9. package/dist/{client-BKlyLiOU.js → client-Dj5d3SP_.js} +37 -19
  10. package/dist/client-Dj5d3SP_.js.map +1 -0
  11. package/dist/client.d.ts +1 -1
  12. package/dist/client.js +1 -1
  13. package/dist/http.d.ts +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/otel.d.ts +1 -1
  16. package/dist/react.d.ts +41 -7
  17. package/dist/react.d.ts.map +1 -1
  18. package/dist/react.js +74 -35
  19. package/dist/react.js.map +1 -1
  20. package/dist/scheduler-qstash.d.ts +1 -1
  21. package/dist/scheduler-qstash.js +1 -1
  22. package/dist/scheduler-vercel.d.ts +1 -1
  23. package/dist/scheduler-vercel.js +1 -1
  24. package/dist/{server-DUF9pjsx.d.ts → server-DpvjhdoE.d.ts} +2 -2
  25. package/dist/{server-DUF9pjsx.d.ts.map → server-DpvjhdoE.d.ts.map} +1 -1
  26. package/dist/{server-C72KOw51.js → server-Duw6MVlB.js} +13 -7
  27. package/dist/server-Duw6MVlB.js.map +1 -0
  28. package/dist/server.d.ts +1 -1
  29. package/dist/server.js +1 -1
  30. package/dist/{telemetry-BjYHTfh2.d.ts → telemetry-CpeclqB2.d.ts} +3 -3
  31. package/dist/{telemetry-BjYHTfh2.d.ts.map → telemetry-CpeclqB2.d.ts.map} +1 -1
  32. package/docs/guides/03-react.mdx +98 -1
  33. package/docs/guides/09-presence.mdx +5 -2
  34. package/docs/reference/01-api.mdx +45 -4
  35. package/package.json +1 -1
  36. package/src/client.ts +69 -33
  37. package/src/react.ts +118 -44
  38. package/src/server.ts +2 -2
  39. package/src/telemetry.ts +17 -10
  40. package/dist/client-BKlyLiOU.js.map +0 -1
  41. package/dist/client-D7mvIXrF.d.ts.map +0 -1
  42. package/dist/server-C72KOw51.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-Duw6MVlB.js","names":[],"sources":["../src/deterministic-id.ts","../src/telemetry.ts","../src/server.ts"],"sourcesContent":["/**\n * Deterministic default ids for handler `session.append` calls. A handler\n * re-run after a crash calls `session.append` again; giving\n * each call a deterministic id — derived from the triggering event's id\n * and the caller's stable name — makes the re-run a no-op via the store's\n * unique index on event ids.\n *\n * The id is a UUIDv5-shaped SHA-1 over\n * `(namespace, triggerEventId, name, itemOrdinal)`, computed with\n * WebCrypto so it runs on any platform a2 core targets.\n */\n\nconst APPEND_NAMESPACE = 'a2:handler-append:v2'\nconst RETURN_NAMESPACE = 'a2:handler-return:v1'\nconst SCHEDULE_NAMESPACE = 'a2:schedule:v1'\nconst SCHEDULED_EVENT_NAMESPACE = 'a2:scheduled-event:v1'\n\nasync function deterministicIdFromInput(input: string): Promise<string> {\n const digest = await crypto.subtle.digest(\n 'SHA-1',\n new TextEncoder().encode(input),\n )\n const bytes = new Uint8Array(digest).slice(0, 16)\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x50\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`\n}\n\nasync function deterministicId(parts: Array<string | number>): Promise<string> {\n return deterministicIdFromInput(parts.join('\\u0000'))\n}\n\nexport async function deterministicEventId(\n triggerEventId: string,\n name: string,\n itemOrdinal: number,\n): Promise<string> {\n if (name.length === 0) throw new TypeError('append name must not be empty')\n return deterministicId([APPEND_NAMESPACE, triggerEventId, name, itemOrdinal])\n}\n\nexport async function deterministicReturnedEventId(\n triggerEventId: string,\n itemOrdinal: number,\n): Promise<string> {\n return deterministicId([RETURN_NAMESPACE, triggerEventId, itemOrdinal])\n}\n\nexport async function deterministicScheduleId(\n contract: string,\n sessionId: string,\n triggerEventId: string | null,\n name: string,\n): Promise<string> {\n return deterministicIdFromInput(\n JSON.stringify([\n SCHEDULE_NAMESPACE,\n contract,\n sessionId,\n triggerEventId,\n name,\n ]),\n )\n}\n\nexport async function deterministicScheduledEventId(\n scheduleId: string,\n itemOrdinal: number,\n): Promise<string> {\n return deterministicId([SCHEDULED_EVENT_NAMESPACE, scheduleId, itemOrdinal])\n}\n","/**\n * The A2Telemetry interface — the instrumentation seam. Same philosophy\n * as store backends: the interface lives in core, implementations ship as\n * entry points (`experimental-a2/otel` adapts it to OpenTelemetry). Without\n * one, spans are free and swallowed errors print to the console.\n */\n\n/** Attribute values a2 emits. */\nexport type A2AttributeValue = string | number | boolean\n\n/** The spans a2 emits today. The catalogue grows with the surface. */\nexport type A2SpanName = 'a2.append' | 'a2.drain' | 'a2.event' | 'a2.state'\n\nexport type A2SpanHandle = {\n /** Attach or update an attribute mid-span (e.g. the outcome). */\n setAttribute(key: string, value: A2AttributeValue): void\n /**\n * Mark the span failed without a2's control flow throwing — used for\n * handler failures, which a2 swallows by design (they go into the\n * retry machinery, not up the stack) but telemetry must still see.\n */\n recordError(error: unknown): void\n}\n\nexport type A2Telemetry = {\n /**\n * Wrap one unit of a2 work. Implementations should time it, record a\n * thrown error as a failure, propagate context so nested spans tree\n * up, and always return `fn`'s result (or rethrow its error) —\n * telemetry observes, it never alters behavior.\n */\n span<T>(\n name: A2SpanName,\n attributes: Record<string, A2AttributeValue>,\n fn: (span: A2SpanHandle) => Promise<T>,\n ): Promise<T>\n}\n\n/**\n * The default when no telemetry is configured. Spans cost nothing, but\n * `recordError` prints: it only ever receives errors a2 swallows by\n * design, so without a configured sink the console is the one place\n * they can surface. Passing `telemetry` replaces this sink wholesale.\n */\nexport const CONSOLE_TELEMETRY: A2Telemetry = {\n span: (name, attributes, fn) =>\n fn({\n setAttribute: () => {},\n recordError: (error) => {\n // oxlint-disable-next-line no-console -- the whole point: swallowed errors must surface without configuration\n console.error(`[a2] error in ${name}`, attributes, error)\n },\n }),\n}\n","// oxlint-disable no-await-in-loop -- scheduler advances after durable outcomes\n/**\n * experimental-a2/server — where a contract is implemented. `createServer({\n * contract, store, handlers, ... })` binds the vocabulary to storage and\n * reactions; sessions, drains, claims, and scheduler all live here.\n * Server-only by construction: this entry point is the only one that\n * can reach a store backend, and its exports map fails loudly in browser\n * bundles.\n */\n\nimport type {\n AppendInput,\n Contract,\n ContractEvent,\n EventDefs,\n PresenceDefs,\n PresenceMap,\n PresencePatch,\n PresenceSnapshot,\n WithPresence,\n} from './contract.ts'\nimport { A2Error, asStoreUnavailable } from './errors.ts'\nimport {\n DRAIN_TIMINGS,\n POLL_TIMINGS,\n MAX_DATE_MS,\n RESERVED_PARTICIPANT_IDS,\n markSchedulerSendFailure,\n nullProtoRecord,\n serverInternals,\n serverSchedulerBindings,\n type DrainOutcome,\n type DrainResult,\n} from './internal.ts'\nimport { InspectionUnsupportedError, serverInspection } from './inspection.ts'\nimport { defaultSleep } from './store-polling.ts'\nimport type {\n A2Store,\n AppendEvent,\n Event,\n EventCause,\n StoreClaimAvailableResult,\n StoreStateRead,\n PresenceRow,\n ReturnedEvent,\n StoredEvent,\n} from './store.ts'\nimport type { Reducer } from './reducer.ts'\nimport { validateSync } from './validate.ts'\nimport {\n deterministicEventId,\n deterministicReturnedEventId,\n deterministicScheduledEventId,\n deterministicScheduleId,\n} from './deterministic-id.ts'\nimport { invocationDeadlineMs, platformWaitUntil } from './platform.ts'\nimport { retryableLazy } from './retryable-lazy.ts'\nimport type {\n ScheduledEvent,\n SchedulerAppendTask,\n SchedulerTask,\n} from './scheduler-task.ts'\nimport {\n CONSOLE_TELEMETRY,\n type A2SpanHandle,\n type A2Telemetry,\n} from './telemetry.ts'\n\n/**\n * Events that arrived over the wire through `parsePushBody` — already\n * envelope-validated, headed for schema validation inside `append`.\n * The brand lets the documented push route hand them straight to\n * `session.append` without weakening typed appends for app code: a\n * hand-written `{ type: string }` literal still fails to compile.\n */\nexport type PushedEvent = {\n type: string\n payload: unknown\n id?: string\n readonly '~a2.pushed': true\n}\n\n/**\n * A presence patch that arrived over the wire through `parsePushBody`\n * — same provenance brand as `PushedEvent`, so the documented route\n * hands it whole to `session.setPresence` while a hand-written\n * untyped patch still fails to compile. Field validation happens\n * inside `setPresence`.\n */\nexport type PushedPresence = {\n participant: string\n values: Record<string, unknown>\n seen?: number\n /** The sender's LWW stamp in epoch ms; receipt time when absent. */\n at?: number\n readonly '~a2.pushed': true\n}\n\nexport type PushValidationContext = {\n sessionId: string\n events: readonly PushedEvent[]\n /** The whole pushed patch — present exactly on the presence-plane\n * invocation, so the callback authorizes the participant id and can\n * apply size or cardinality policy. */\n presence?: PushedPresence\n}\n\n/** What every handler receives. */\nexport type HandlerContext<\n D extends EventDefs,\n K extends keyof D & string = keyof D & string,\n P extends PresenceDefs = Record<never, never>,\n> = {\n /** The triggering event. */\n event: ContractEvent<D, K>\n /** Durable, 1-based dispatch ordinal for this event. */\n attempt: number\n /** This session, with handler-scoped idempotent append. */\n session: Session<D, HandlerAppend<D>, P>\n /** Fires on `abortOn` events (cancellation slice); dormant otherwise. */\n signal: AbortSignal\n}\n\nexport type Handler<\n D extends EventDefs,\n K extends keyof D & string = keyof D & string,\n P extends PresenceDefs = Record<never, never>,\n> = (\n ctx: HandlerContext<D, K, P>,\n) => Promise<void | AppendInput<D> | readonly AppendInput<D>[]>\n\nexport type LaneContext<\n D extends EventDefs,\n K extends keyof D & string = keyof D & string,\n> = {\n sessionId: string\n event: Pick<ContractEvent<D, K>, 'type' | 'payload'> & { id?: string }\n}\n\nexport type Lane<\n D extends EventDefs,\n K extends keyof D & string = keyof D & string,\n> = string | ((context: LaneContext<D, K>) => string)\n\nexport type SessionDispatch<D extends EventDefs> = {\n (...events: AppendInput<D>[]): Promise<ContractEvent<D>[]>\n /** The push-route path: events from `parsePushBody`. */\n (...events: PushedEvent[]): Promise<ContractEvent<D>[]>\n}\n\nexport type SessionAppend<D extends EventDefs> = SessionDispatch<D> & {\n /** Commit, then hand pending work directly to configured scheduler. */\n dispatch: SessionDispatch<D>\n}\n\nexport type HandlerAppend<D extends EventDefs> = (\n name: string,\n ...events: AppendInput<D>[]\n) => Promise<ContractEvent<D>[]>\n\nexport type ScheduleDelay = `${number}${'ms' | 's' | 'm' | 'h' | 'd'}`\n\nexport type ScheduleTiming =\n { delay: ScheduleDelay; at?: never } | { at: Date; delay?: never }\n\nexport type SessionSchedule<D extends EventDefs> = (\n name: string,\n timing: ScheduleTiming,\n ...events: AppendInput<D>[]\n) => Promise<void>\n\n/**\n * The presence members of a session — intersected in via\n * `WithPresence`, so they exist exactly when the contract declares\n * presence fields. Intersected before the base members so the widened\n * `stream` overload is tried first: the literal `presence: true`\n * selects it, everything else falls through to the events-only base.\n */\nexport type SessionPresence<D extends EventDefs, P extends PresenceDefs> = {\n /**\n * The two-plane feed: one snapshot of the current pruned map first\n * (per-field stamps exact), then presence patches interleaved with\n * events.\n */\n stream(opts: {\n startAfter?: number\n presence: true\n }): AsyncIterable<ContractEvent<D> | PresencePatch<P> | PresenceSnapshot<P>>\n /**\n * Validate against the contract's presence schemas, then broadcast.\n * Never an append: no log row, no dispatch, no scheduler arm. `at`\n * is the sender's LWW stamp in epoch ms; omitted, receipt time\n * stands in (single writer, so receipt order is sender order).\n */\n setPresence(\n patch:\n | {\n participant: string\n values: PresencePatch<P>['values']\n seen?: number\n at?: number\n }\n | PushedPresence,\n ): Promise<void>\n /** The current map, expired values pruned — a point-in-time read. */\n presence(): Promise<PresenceMap<P>>\n}\n\n/** A handle on one instance of the machine. Creating it does no I/O. */\nexport type Session<\n D extends EventDefs,\n Append = SessionAppend<D>,\n P extends PresenceDefs = Record<never, never>,\n> = WithPresence<P, SessionPresence<D, P>> & {\n readonly id: string\n append: Append\n schedule: SessionSchedule<D>\n history(options?: { gte?: number; lte?: number }): Promise<ContractEvent<D>[]>\n state<S>(reducer: Reducer<D, S>): Promise<{ state: S; index: number }>\n /**\n * A live feed of this session's events, starting after `startAfter`\n * (exclusive). Server-side only — `handle` from experimental-a2/http\n * exposes it over SSE as the route's stream lane.\n */\n stream(opts?: { startAfter?: number }): AsyncIterable<ContractEvent<D>>\n}\n\n/**\n * The public server shape scheduler handlers accept. It stays structural so\n * servers of any contract mix in one route; A2's private server internals add\n * delayed-append delivery without exposing an untyped append method here.\n */\nexport type DrainableServer = {\n readonly contract: { readonly name: string }\n drain(sessionId: string): Promise<{ settled: boolean }>\n}\n\n/**\n * The scheduler seam (a2-implementation.md §7, §9). `schedule` puts a\n * versioned drain or delayed append task on durable infrastructure;\n * `handler` returns the route the transport delivers to. Claim holders\n * move the watchdog alongside their renewable execution window.\n * Implementations ship as\n * entry points (`experimental-a2/scheduler-vercel`); core never imports a\n * transport.\n */\nexport type A2Scheduler = {\n schedule(task: SchedulerTask): Promise<void>\n handler(...servers: DrainableServer[]): (req: Request) => Promise<Response>\n}\n\nexport type A2Server<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n> = {\n /** The contract this server implements. */\n readonly contract: Contract<D, P>\n session(id: string): Session<D, SessionAppend<D>, P>\n /**\n * Process every currently eligible event. `settled` means nothing\n * actionable remains, including work blocked behind a dead letter.\n */\n drain(sessionId: string): Promise<{ settled: boolean }>\n}\n\n/**\n * Deliver one authenticated scheduler append through an A2 server's ordinary\n * top-level append path. Custom scheduler adapters call this after validating\n * their transport envelope; application code normally uses `session.schedule`.\n */\nexport async function deliverSchedulerAppend(\n server: DrainableServer,\n task: SchedulerAppendTask,\n): Promise<void> {\n if (server.contract.name !== task.contract) {\n throw new TypeError(\n `a2 scheduler: append task for contract '${task.contract}' cannot be delivered to '${server.contract.name}'`,\n )\n }\n const internals = serverInternals.get(server)\n if (!internals) {\n throw new TypeError(\n `a2 scheduler: server for contract '${task.contract}' cannot receive scheduled appends`,\n )\n }\n await internals.schedulerAppend(task.sessionId, task.events)\n}\n\n/**\n * Which events fire `ctx.signal` while a handler runs — the preemption\n * channel for user cancellation. The array form matches by type; the\n * object form takes per-type predicates for targeted cancellation\n * (`(event, trigger) => event.payload.of === trigger.id`). Handlers\n * without `abortOn` pay nothing. An aborted handler should catch and\n * return normally; throwing means \"retry me\".\n */\nexport type AbortSpec<D extends EventDefs, K extends keyof D & string> =\n | Array<keyof D & string>\n | {\n [T in keyof D & string]?:\n | true\n | ((\n event: ContractEvent<D, T>,\n trigger: ContractEvent<D, K>,\n context: { attempt: number },\n ) => boolean)\n }\n\nexport type HandlerEntry<\n D extends EventDefs,\n K extends keyof D & string = keyof D & string,\n P extends PresenceDefs = Record<never, never>,\n> =\n | Handler<D, K, P>\n | {\n abortOn?: AbortSpec<D, K>\n /** Session-scoped FIFO key, resolved and persisted when the event lands. */\n lane?: Lane<D, K>\n handler: Handler<D, K, P>\n }\n\nexport type ServerOptions<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n> = {\n /** The contract this server implements (see `a2.contract`). */\n contract: Contract<D, P>\n /** Where events live. Defaults: sqlite in dev, memory in tests, required in prod. */\n store?: A2Store\n /**\n * Queue-backed scheduler — e.g. `vercelQueues()` from\n * `experimental-a2/scheduler-vercel`. Absent means append-driven healing only: a\n * working configuration, but a clockless one. Recommended in\n * production.\n */\n scheduler?: A2Scheduler\n /** Optional instrumentation — e.g. `otel()` from `experimental-a2/otel`. */\n telemetry?: A2Telemetry\n /** Validate events that came through `parsePushBody` before writing them. */\n validatePush?: (context: PushValidationContext) => void | PromiseLike<void>\n /**\n * Presence-plane policy — valid only when the contract declares\n * presence fields (TypeError at construction otherwise). `ttlMs` is\n * how long a value survives without a refreshing set; default 60s.\n */\n presence?: { ttlMs?: number }\n /**\n * The reactions, keyed by event type — all present at construction,\n * so a handler can never be silently missing because its module\n * wasn't imported. Compose across files by spreading objects (note:\n * a duplicate key under spread silently last-wins).\n */\n handlers?: { [K in keyof D & string]?: HandlerEntry<D, K, P> }\n}\n\nconst MAX_FAILURES = 10\n\n/** Default: how long a presence value survives without a refreshing set. */\nconst PRESENCE_TTL_MS = 60_000\n\ntype ClaimWindow = {\n ttlMs: number\n expiresAtMs: number\n watchdogAtMs: number\n deadlineCapped: boolean\n}\n\ntype DrainSignal = {\n version: number\n closed: boolean\n notify(): void\n wait(version: number): { promise: Promise<void>; cancel(): void }\n}\n\ntype AbortSubscription = {\n controller: AbortController\n triggerIndex: number\n types: Set<string>\n matches(event: Event): boolean\n}\n\ntype AbortHub = {\n subscriptions: Set<AbortSubscription>\n seen: Map<number, Event>\n startAfter: number\n ready: Promise<void>\n watch: Promise<void> | null\n error: unknown\n iterator: AsyncIterator<Event> | null\n stopped: boolean\n}\n\nfunction createDrainSignal(): DrainSignal {\n const listeners = new Set<() => void>()\n return {\n version: 0,\n closed: false,\n notify() {\n this.version += 1\n for (const listener of listeners) listener()\n listeners.clear()\n },\n wait(version) {\n if (this.version !== version) {\n return { promise: Promise.resolve(), cancel: () => {} }\n }\n let resolve!: () => void\n const promise = new Promise<void>((done) => {\n resolve = done\n })\n listeners.add(resolve)\n return { promise, cancel: () => listeners.delete(resolve) }\n },\n }\n}\n\nfunction dispatchAbortEvent(hub: AbortHub, event: Event): void {\n let relevant = false\n for (const subscription of hub.subscriptions) {\n if (!subscription.types.has(event.type)) continue\n relevant = true\n if (subscription.matches(event)) subscription.controller.abort()\n }\n if (relevant) hub.seen.set(event.index, event)\n}\n\nfunction pruneAbortHub(hub: AbortHub): void {\n let minimum = Infinity\n const types = new Set<string>()\n for (const subscription of hub.subscriptions) {\n minimum = Math.min(minimum, subscription.triggerIndex)\n for (const type of subscription.types) types.add(type)\n }\n for (const [index, event] of hub.seen) {\n if (index <= minimum || !types.has(event.type)) hub.seen.delete(index)\n }\n}\n\n/**\n * Deadlines tighten the claim/watchdog window; they never decide whether a\n * handler starts. A platform timeout therefore follows the same path as any\n * other process death: the in-flight event remains pending and is retried.\n */\nfunction nextClaimWindow(): ClaimWindow {\n const nowMs = Date.now()\n const deadlineMs = invocationDeadlineMs()\n const deadlineTtlMs =\n deadlineMs === null ? DRAIN_TIMINGS.claimTtlMs : deadlineMs - nowMs\n const deadlineCapped =\n deadlineMs !== null && deadlineTtlMs <= DRAIN_TIMINGS.claimTtlMs\n const ttlMs = Math.max(1, Math.min(DRAIN_TIMINGS.claimTtlMs, deadlineTtlMs))\n const expiresAtMs = nowMs + ttlMs\n return {\n ttlMs,\n expiresAtMs,\n watchdogAtMs: expiresAtMs + DRAIN_TIMINGS.watchdogGraceMs,\n deadlineCapped,\n }\n}\n\nfunction schedulerSlot(dueAt: number): number {\n return Math.ceil(dueAt / 1_000) * 1_000\n}\n\nfunction currentSchedulerSlot(now: number): number {\n return Math.floor(now / 1_000) * 1_000\n}\n\n/**\n * The namespace separator between machine name and session id in\n * storage. Machines sharing one store backend (the dev-default sqlite\n * file, a shared Postgres) must not collide on session ids; the machine\n * name is what makes multi-machine apps unambiguous (a2-api.md §1), so\n * it prefixes every storage key.\n */\nconst NS = '\\u001f'\n\nconst devDefaultStore = retryableLazy(() =>\n import('./store-sqlite.ts').then((m) => m.sqlite()),\n)\n\nfunction environment(): 'development' | 'test' | 'production' {\n const env =\n typeof process === 'undefined' ? undefined : process.env?.['NODE_ENV']\n if (env === 'test') return 'test'\n if (env === 'production') return 'production'\n return 'development'\n}\n\nfunction describeError(err: unknown): string {\n if (err instanceof Error) return err.stack ?? `${err.name}: ${err.message}`\n return String(err)\n}\n\n/**\n * Comparison key for a presence value in the degraded-tier diff — an\n * LWW tie can replace a value without moving its `seen`/`at` stamp.\n */\nfunction fingerprint(value: unknown): string {\n return JSON.stringify(value) ?? ''\n}\n\nfunction foldPresenceRows(\n rows: PresenceRow[],\n): Record<string, Record<string, { value: unknown; seen: number; at: Date }>> {\n // Null-prototype at both levels: participants and fields are caller\n // strings, and a '__proto__' key on a normal object rewrites its\n // prototype instead of setting an own property.\n const map =\n nullProtoRecord<\n Record<string, Record<string, { value: unknown; seen: number; at: Date }>>\n >()\n for (const row of rows) {\n ;(map[row.participant] ??= nullProtoRecord())[row.field] = {\n value: row.value,\n seen: row.seen,\n at: row.at,\n }\n }\n return map\n}\n\n/** Implement a contract: bind its vocabulary to storage and reactions. */\nexport function createServer<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n>(options: ServerOptions<D, P>): A2Server<D, P> {\n const serverContract = options?.contract\n if (\n serverContract === null ||\n typeof serverContract !== 'object' ||\n typeof serverContract.name !== 'string' ||\n serverContract.events === null\n ) {\n throw new TypeError(\n 'createServer expects options with a contract (see a2.contract)',\n )\n }\n const name = serverContract.name\n const defs = serverContract.events\n const presenceDefs: Readonly<PresenceDefs> = serverContract.presence\n const declaresPresence = Object.keys(presenceDefs).length > 0\n const presenceNotSupported = (): A2Error =>\n new A2Error(\n 'PRESENCE_NOT_SUPPORTED',\n `the contract '${name}' declares presence but the store backend for its server has no presence capability (A2Store.presence)`,\n )\n\n if (options.presence !== undefined) {\n // An option for a plane the contract doesn't declare is a mistake\n // worth failing loud at construction.\n if (!declaresPresence) {\n throw new TypeError(\n `the presence option requires a contract that declares presence fields — '${name}' has none`,\n )\n }\n const { ttlMs } = options.presence\n if (ttlMs !== undefined && (!Number.isInteger(ttlMs) || ttlMs <= 0)) {\n throw new TypeError(\n 'presence.ttlMs must be a positive integer of milliseconds',\n )\n }\n }\n const presenceTtlMs = options.presence?.ttlMs ?? PRESENCE_TTL_MS\n\n // Resolve where events live. Explicit store wins; otherwise the\n // environment decides — and production refuses to guess\n // (a2-implementation.md §8): a failed boot beats events written to an\n // ephemeral filesystem.\n let makeStore: () => Promise<A2Store>\n if (options.store) {\n const explicit = options.store\n // Fail at boot, not first use (a2-api.md §12).\n if (declaresPresence && !explicit.presence) throw presenceNotSupported()\n makeStore = () => Promise.resolve(explicit)\n } else {\n const env = environment()\n if (env === 'production') {\n const error = (): A2Error =>\n new A2Error(\n 'STORE_NOT_CONFIGURED',\n `the server for '${name}' has no store configured and NODE_ENV is 'production' — pass an explicit store backend (e.g. postgres from 'experimental-a2/store-postgres')`,\n )\n // `next build` evaluates route modules with NODE_ENV=production\n // to collect page data — in a CI without the runtime env vars, a\n // construction-time throw fails the build for nothing (the store is\n // never used during collection). During that phase only, defer\n // the failure to first use; a real production boot still fails at\n // construction, before any event can land somewhere ephemeral.\n if (process.env['NEXT_PHASE'] !== 'phase-production-build') {\n throw error()\n }\n makeStore = () => Promise.reject(error())\n } else {\n makeStore =\n env === 'test'\n ? () => import('./store-memory.ts').then((m) => m.memory())\n : devDefaultStore.get\n }\n }\n\n // Environment-resolved stores arrive lazily; assert the capability the\n // moment one resolves — the closest available moment to construction.\n if (declaresPresence && !options.store) {\n const inner = makeStore\n makeStore = async () => {\n const store = await inner()\n if (!store.presence) throw presenceNotSupported()\n return store\n }\n }\n\n const resolveStore = retryableLazy(makeStore).get\n\n const telemetry = options.telemetry ?? CONSOLE_TELEMETRY\n const scheduler = options.scheduler\n\n type AbortMatcher = Map<\n string,\n | true\n | ((\n event: ContractEvent<D>,\n trigger: ContractEvent<D>,\n context: { attempt: number },\n ) => boolean)\n >\n const handlers = new Map<\n string,\n { handler: Handler<D>; abortOn: AbortMatcher | null; lane: Lane<D> | null }\n >()\n for (const [type, entry] of Object.entries(options.handlers ?? {})) {\n if (entry === undefined) continue\n if (!Object.hasOwn(defs, type)) {\n throw new TypeError(\n `contract '${name}' has no event type '${type}' — cannot register a handler for it`,\n )\n }\n const handler = typeof entry === 'function' ? entry : entry?.handler\n if (typeof handler !== 'function') {\n throw new TypeError(`handler for '${type}' must be a function`)\n }\n let abortOn: AbortMatcher | null = null\n const spec = typeof entry === 'function' ? undefined : entry.abortOn\n if (spec !== undefined) {\n abortOn = new Map()\n const pairs = Array.isArray(spec)\n ? spec.map((abortType) => [abortType, true as const] as const)\n : (Object.entries(spec) as Array<\n [\n string,\n (\n | true\n | ((\n e: never,\n t: never,\n context: { attempt: number },\n ) => boolean)\n ),\n ]\n >)\n for (const [abortType, matcher] of pairs) {\n if (matcher === undefined) continue\n if (!Object.hasOwn(defs, abortType)) {\n throw new TypeError(\n `contract '${name}' has no event type '${String(abortType)}' — cannot abort on it`,\n )\n }\n abortOn.set(String(abortType), matcher as never)\n }\n if (abortOn.size === 0) abortOn = null\n }\n const lane = typeof entry === 'function' ? null : (entry.lane ?? null)\n if (\n lane !== null &&\n typeof lane !== 'function' &&\n (typeof lane !== 'string' || lane.length === 0)\n ) {\n throw new TypeError(\n `lane for '${type}' must be a non-empty string or a function`,\n )\n }\n handlers.set(type, {\n handler: handler as Handler<D>,\n abortOn,\n lane: lane as Lane<D> | null,\n })\n }\n\n const prefix = `${name}${NS}`\n const nsId = (sessionId: string): string => `${prefix}${sessionId}`\n const stripNs = (stored: string): string => stored.slice(prefix.length)\n\n const toPublic = (row: Event): ContractEvent<D> =>\n ({\n id: row.id,\n type: row.type,\n payload: row.payload,\n index: row.index,\n sessionId: stripNs(row.sessionId),\n createdAt: row.createdAt,\n }) as ContractEvent<D>\n\n // ── background work tracking ─────────────────────────────────────\n // Every fire-and-forget operation is tracked so (a) platforms with\n // waitUntil keep the invocation alive and (b) tests can flush\n // deterministically via serverInternals.\n const inFlight = new Set<Promise<unknown>>()\n const track = (p: Promise<unknown>): void => {\n inFlight.add(p)\n const drop = (): void => {\n inFlight.delete(p)\n }\n p.then(drop, drop)\n }\n\n type SchedulerArmSlot = {\n promise: Promise<void>\n forget: ReturnType<typeof setTimeout>\n }\n const schedulerArmSlots = new Map<string, SchedulerArmSlot>()\n\n /**\n * Start an optional scheduler arm without putting it on the execution path.\n * The returned raw promise lets the initial append report failure; the\n * tracked copy is always rejection-safe for heartbeat callers.\n */\n const startSchedulerArm = (\n sessionId: string,\n dueAt: number,\n ): Promise<void> | null => {\n if (!scheduler) return null\n const slottedDueAt = schedulerSlot(dueAt)\n const slotKey = JSON.stringify([sessionId, slottedDueAt])\n const existing = schedulerArmSlots.get(slotKey)\n if (existing) return existing.promise\n // Normalize even a custom adapter's synchronous throw into a rejected\n // promise. Optional scheduler must never stop inline claiming.\n const raw = Promise.resolve().then(() =>\n scheduler.schedule({\n version: 1,\n kind: 'drain',\n contract: name,\n sessionId,\n dueAt: slottedDueAt,\n }),\n )\n const forget = setTimeout(\n () => {\n if (schedulerArmSlots.get(slotKey)?.promise === raw) {\n schedulerArmSlots.delete(slotKey)\n }\n },\n Math.max(0, slottedDueAt - Date.now()) + 1_000,\n )\n ;(forget as { unref?: () => void }).unref?.()\n schedulerArmSlots.set(slotKey, { promise: raw, forget })\n void raw.then(undefined, () => {\n const current = schedulerArmSlots.get(slotKey)\n if (current?.promise !== raw) return\n clearTimeout(current.forget)\n schedulerArmSlots.delete(slotKey)\n })\n const safe = raw.catch(() => {})\n track(safe)\n platformWaitUntil(safe)\n return raw\n }\n\n const scheduledDrains = new Map<\n string,\n { signal: DrainSignal; promise: Promise<void> }\n >()\n\n const scheduleDrain = (sessionId: string, watchdogDueAt?: number): void => {\n const existing = scheduledDrains.get(sessionId)\n if (existing && !existing.signal.closed) {\n existing.signal.notify()\n return\n }\n if (existing) scheduledDrains.delete(sessionId)\n const signal = createDrainSignal()\n const p = new Promise<void>((resolve) => {\n queueMicrotask(() => {\n void drainSession(sessionId, watchdogDueAt, signal)\n .then(() => resolve())\n .catch(() => resolve())\n })\n }).finally(() => {\n if (scheduledDrains.get(sessionId)?.promise === p) {\n scheduledDrains.delete(sessionId)\n }\n })\n scheduledDrains.set(sessionId, { signal, promise: p })\n track(p)\n platformWaitUntil(p)\n }\n\n // ── append ───────────────────────────────────────────────────────\n\n const validateEvents = (\n sessionId: string,\n events: AppendInput<D>[],\n resolveDispatchMetadata = true,\n ): AppendEvent[] => {\n if (events.length === 0) {\n throw new TypeError('append requires at least one event')\n }\n return events.map((e) => {\n const schema = Object.hasOwn(defs, e.type) ? defs[e.type] : undefined\n if (!schema) {\n throw new A2Error(\n 'UNKNOWN_EVENT_TYPE',\n `contract '${name}' has no event type '${String(e.type)}'`,\n )\n }\n const result = validateSync(schema, e.payload, `event '${e.type}'`)\n if (result.issues) {\n throw new A2Error(\n 'INVALID_PAYLOAD',\n `invalid payload for event '${e.type}' on machine '${name}'`,\n { details: result.issues },\n )\n }\n const validated: AppendEvent = { type: e.type, payload: result.value }\n if (e.id !== undefined) validated.id = e.id\n if (!resolveDispatchMetadata) return validated\n const registration = handlers.get(e.type)\n if (!registration) {\n validated.settled = true\n } else if (registration.lane !== null) {\n const lane =\n typeof registration.lane === 'function'\n ? registration.lane({\n sessionId,\n event: {\n type: e.type,\n payload: structuredClone(result.value),\n ...(e.id === undefined ? {} : { id: e.id }),\n } as never,\n })\n : registration.lane\n if (typeof lane !== 'string' || lane.length === 0) {\n throw new TypeError(\n `lane for '${e.type}' must resolve to a non-empty string`,\n )\n }\n validated.lane = lane\n }\n return validated\n })\n }\n\n /**\n * Validate + write. `onAppended` runs inside the telemetry span, so\n * the drain it schedules is created in the append's active context —\n * with a real tracer, causal work remains connected.\n */\n const appendCore = (\n sessionId: string,\n events: AppendInput<D>[],\n source: 'external' | 'handler',\n mode: 'inline' | 'dispatch',\n onAppended: (rows: ContractEvent<D>[], watchdogDueAt?: number) => void,\n cause?: EventCause,\n generatedIds?: readonly boolean[],\n requireDurableInitialArm = false,\n ): Promise<ContractEvent<D>[]> =>\n telemetry.span(\n 'a2.append',\n {\n 'a2.contract': name,\n 'a2.session_id': sessionId,\n 'a2.append.source': source,\n 'a2.append.mode': mode,\n 'a2.append.types': events.map((e) => String(e.type)).join(','),\n 'a2.append.count': events.length,\n },\n async (span) => {\n if (mode === 'dispatch' && !scheduler) {\n throw new TypeError(\n 'append.dispatch requires a configured scheduler adapter',\n )\n }\n assertSessionId(sessionId)\n const validated = validateEvents(sessionId, events)\n if (cause) {\n for (const [index, event] of validated.entries()) {\n event.cause = generatedIds?.[index]\n ? { ...cause, batchSize: events.length }\n : cause\n }\n }\n const store = await resolveStore()\n let rows: StoredEvent[]\n let shouldHealSession: boolean\n try {\n const result = await store.append(nsId(sessionId), validated)\n rows = result.events\n shouldHealSession = result.hasPending\n } catch (err) {\n throw asStoreUnavailable(err)\n }\n const appended = rows.map(toPublic)\n\n const initialWatchdogAt =\n shouldHealSession &&\n scheduler &&\n source === 'external' &&\n mode === 'inline'\n ? schedulerSlot(nextClaimWindow().watchdogAtMs)\n : undefined\n const initialArm =\n initialWatchdogAt !== undefined\n ? startSchedulerArm(sessionId, initialWatchdogAt)\n : null\n const dispatchArm =\n shouldHealSession && mode === 'dispatch'\n ? startSchedulerArm(sessionId, currentSchedulerSlot(Date.now()))\n : null\n if (shouldHealSession && mode === 'inline') {\n onAppended(appended, initialWatchdogAt)\n }\n if (dispatchArm) {\n await dispatchArm\n }\n if (initialArm) {\n let timeout: ReturnType<typeof setTimeout> | null = null\n try {\n await Promise.race([\n initialArm,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => {\n reject(\n new Error(\n `a2 scheduler arm timed out after ${DRAIN_TIMINGS.schedulerArmTimeoutMs}ms`,\n ),\n )\n }, DRAIN_TIMINGS.schedulerArmTimeoutMs)\n }),\n ])\n } catch (err) {\n span.setAttribute('a2.append.armed', false)\n span.recordError(err)\n if (requireDurableInitialArm) throw err\n } finally {\n if (timeout) clearTimeout(timeout)\n }\n }\n return appended\n },\n )\n\n const readHistory = async (\n sessionId: string,\n bounds?: { gte?: number; lte?: number },\n ): Promise<StoredEvent[]> => {\n const gte = bounds?.gte\n const lte = bounds?.lte\n assertHistoryIndex('gte', gte)\n assertHistoryIndex('lte', lte)\n if (gte !== undefined && lte !== undefined && gte > lte) {\n throw new RangeError(\n 'history.gte must be less than or equal to history.lte',\n )\n }\n if (lte === 0) return []\n\n const store = await resolveStore()\n try {\n const readOptions =\n gte === undefined && lte === undefined\n ? undefined\n : {\n ...(gte === undefined\n ? {}\n : { afterIndex: Math.max(0, gte - 1) }),\n ...(lte === undefined ? {} : { throughIndex: lte }),\n }\n const rows = await store.read(nsId(sessionId), readOptions)\n return rows.filter(\n (row) =>\n (gte === undefined || row.index >= gte) &&\n (lte === undefined || row.index <= lte),\n )\n } catch (err) {\n throw asStoreUnavailable(err)\n }\n }\n\n // Snapshot plus tail is one adapter operation. A cache-path failure is\n // not load-bearing: fall back to the raw store, which still reports a\n // real storage failure.\n const readCachedState = async (\n store: A2Store,\n sessionId: string,\n reducerName: string,\n ): Promise<StoreStateRead> => {\n try {\n return await store.readState(nsId(sessionId), reducerName)\n } catch {\n try {\n return { snapshot: null, events: await store.read(nsId(sessionId)) }\n } catch (err) {\n throw asStoreUnavailable(err)\n }\n }\n }\n\n // The cache is untrusted: schema rejection refolds from the raw store.\n const foldStateRead = async <S>(\n store: A2Store,\n sessionId: string,\n reducer: Reducer<D, S>,\n stateRead: StoreStateRead,\n span: A2SpanHandle,\n ): Promise<{ state: S; index: number; folded: number }> => {\n let state = cloneInitial(reducer.initialState)\n let index = 0\n let snapshotOutcome = 'miss'\n const snap = stateRead.snapshot\n let rows = stateRead.events\n if (snap) {\n if (reducer.stateSchema) {\n const result = validateSync(\n reducer.stateSchema,\n snap.state,\n 'the stateSchema',\n )\n if (result.issues) {\n snapshotOutcome = 'rejected'\n } else {\n state = result.value as S\n index = snap.index\n snapshotOutcome = 'hit'\n }\n } else {\n state = snap.state as S\n index = snap.index\n snapshotOutcome = 'hit'\n }\n }\n span.setAttribute('a2.state.snapshot', snapshotOutcome)\n\n if (snapshotOutcome === 'rejected') {\n try {\n rows = await store.read(nsId(sessionId))\n } catch (err) {\n throw asStoreUnavailable(err)\n }\n }\n for (const row of rows) {\n state = reducer.fold(state, toPublic(row) as never)\n index = row.index\n }\n span.setAttribute('a2.state.folded', rows.length)\n span.setAttribute('a2.state.index', index)\n return { state, index, folded: rows.length }\n }\n\n // ── same-tick state-read coalescing ──────────────────────────────\n // Concurrent state() calls for one reducer name coalesce into a\n // single store.readStates() round trip when the adapter has one.\n // Unlike DataLoader there is deliberately NO result cache: a batch\n // exists only between enqueue and flush, and nothing is shared after\n // distribution — every state() call still observes a fresh frontier.\n type PendingStateRead = {\n sessionId: string\n resolve: (read: StoreStateRead | Promise<StoreStateRead>) => void\n }\n const pendingStateReads = new Map<string, PendingStateRead[]>()\n\n // The flush microtask voids this promise, so the function must be\n // total: never reject, never leave an entry unresolved — even for a\n // synchronously throwing adapter or a read structuredClone rejects.\n const flushStateReads = async (\n store: A2Store,\n reducerName: string,\n batch: PendingStateRead[],\n ): Promise<void> => {\n let reads: StoreStateRead[] | null\n try {\n reads = store.readStates\n ? await store.readStates(\n batch.map((entry) => nsId(entry.sessionId)),\n reducerName,\n )\n : null\n } catch {\n reads = null\n }\n // A failed or misaligned batch is an ill-behaved cache path, never a\n // batch-shaped error: each caller falls back to its own per-call read\n // (promise adoption carries a real storage failure to that caller).\n if (!reads || reads.length !== batch.length) {\n for (const entry of batch) {\n entry.resolve(readCachedState(store, entry.sessionId, reducerName))\n }\n return\n }\n // Duplicate ids share one store read; their folds must not share\n // payload objects, exactly as two separate state() calls would not.\n const seen = new Set<string>()\n for (const [position, entry] of batch.entries()) {\n const shared = seen.has(entry.sessionId)\n seen.add(entry.sessionId)\n try {\n const read = reads[position]!\n entry.resolve(shared ? structuredClone(read) : read)\n } catch {\n entry.resolve(readCachedState(store, entry.sessionId, reducerName))\n }\n }\n }\n\n const enqueueStateRead = (\n store: A2Store,\n sessionId: string,\n reducerName: string,\n ): Promise<StoreStateRead> =>\n new Promise((resolve) => {\n let batch = pendingStateReads.get(reducerName)\n if (!batch) {\n const opened: PendingStateRead[] = []\n pendingStateReads.set(reducerName, opened)\n // One microtask is the whole batching window — deliberately NOT\n // DataLoader's post-promise-job nextTick, which would defer\n // handler-internal reads past the entire microtask cascade and\n // reorder drain interleaving (and has no edge-runtime primitive).\n // It still coalesces reliably: siblings of one Promise.all\n // traverse identical awaits (store resolution, span wrapper), so\n // their enqueues sit at consecutive queue positions — cold or\n // warm — and this flush, queued by the first of them, runs after\n // the last. A deeper-staggered caller just opens the next batch.\n queueMicrotask(() => {\n pendingStateReads.delete(reducerName)\n void flushStateReads(store, reducerName, opened)\n })\n batch = opened\n }\n batch.push({ sessionId, resolve })\n })\n\n const readState = async <S>(\n sessionId: string,\n reducer: Reducer<D, S>,\n ): Promise<{ state: S; index: number }> => {\n const store = await resolveStore()\n return telemetry.span(\n 'a2.state',\n {\n 'a2.contract': name,\n 'a2.session_id': sessionId,\n 'a2.state.reducer': reducer.name,\n },\n async (span) => {\n const stateRead = store.readStates\n ? await enqueueStateRead(store, sessionId, reducer.name)\n : await readCachedState(store, sessionId, reducer.name)\n const { state, index, folded } = await foldStateRead(\n store,\n sessionId,\n reducer,\n stateRead,\n span,\n )\n // Write-back is a disposable cache. Copy before returning so caller\n // mutations cannot race the background persistence.\n if (folded > 0) {\n const snapshotState = cloneInitial(state)\n const write = Promise.resolve()\n .then(() =>\n store.putSnapshot(\n nsId(sessionId),\n reducer.name,\n index,\n snapshotState,\n ),\n )\n .catch(() => {})\n track(write)\n platformWaitUntil(write)\n }\n return { state, index }\n },\n )\n }\n\n const makeSchedule = (\n sessionId: string,\n trigger: Pick<StoredEvent, 'id' | 'createdAt'> | null,\n ): SessionSchedule<D> => {\n const triggerEventId = trigger?.id ?? null\n const triggerCreatedAt = trigger?.createdAt.getTime()\n return async (scheduleName, timing, ...events) => {\n if (!scheduler) {\n throw new TypeError(\n 'session.schedule requires a configured scheduler adapter',\n )\n }\n assertScheduleName(scheduleName)\n if (events.length === 0) {\n throw new TypeError('schedule requires at least one event')\n }\n const dueAt = scheduleDueAt(timing, triggerCreatedAt ?? Date.now())\n const payloads = events.map((event) =>\n cloneScheduledPayload(event.payload),\n )\n const snapshottedEvents = events.map((event, index) => ({\n type: event.type,\n payload: payloads[index],\n ...(event.id === undefined ? {} : { id: event.id }),\n })) as AppendInput<D>[]\n const validated = validateEvents(\n sessionId,\n structuredClone(snapshottedEvents),\n false,\n )\n const scheduleId = await deterministicScheduleId(\n name,\n sessionId,\n triggerEventId,\n scheduleName,\n )\n const scheduledEvents: ScheduledEvent[] = await Promise.all(\n validated.map(async (event, item) => ({\n id:\n event.id ?? (await deterministicScheduledEventId(scheduleId, item)),\n type: event.type,\n payload: payloads[item],\n })),\n )\n if (\n new Set(scheduledEvents.map((event) => event.id)).size !==\n scheduledEvents.length\n ) {\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n 'scheduled batch contains the same event id more than once',\n )\n }\n try {\n await scheduler.schedule({\n version: 1,\n kind: 'append',\n id: scheduleId,\n contract: name,\n sessionId,\n dueAt,\n events: scheduledEvents,\n })\n } catch (error) {\n throw markSchedulerSendFailure(error)\n }\n }\n }\n\n const toSessionEvent = (id: string, event: Event): ContractEvent<D> =>\n ({\n id: event.id,\n type: event.type,\n payload: event.payload,\n index: event.index,\n sessionId: id,\n createdAt: event.createdAt,\n }) as ContractEvent<D>\n\n const streamEvents = (\n id: string,\n startAfter: number,\n ): AsyncIterable<ContractEvent<D>> => {\n const store = resolveStore()\n const outer = async function* (): AsyncGenerator<ContractEvent<D>> {\n const inner = (await store).stream(nsId(id), { startAfter })\n for await (const event of inner) yield toSessionEvent(id, event)\n }\n return outer()\n }\n\n // ── presence ──────────────────────────────────────────────\n\n const requirePresence = (\n store: A2Store,\n ): NonNullable<A2Store['presence']> => {\n if (!store.presence) throw presenceNotSupported()\n return store.presence\n }\n\n const setPresence = async (\n sessionId: string,\n patch: {\n participant: string\n values: Record<string, unknown>\n seen?: number\n at?: number\n },\n fallbackSeen: number,\n ): Promise<void> => {\n // The push-route provenance seam, mirroring appendExternal: a\n // branded patch came from the wire, so `validatePush` runs before\n // field validation and the broadcast — with `events: []`, the\n // documented presence-only shape.\n if (Reflect.get(patch, '~a2.pushed') === true) {\n // Frozen before the callback: this is the authorization seam,\n // and an authorization hook must not be able to rewrite\n // authorship or values on its way through (assignment throws\n // under strict mode, failing the push loudly).\n Object.freeze(patch.values)\n await options.validatePush?.({\n sessionId,\n events: [],\n presence: Object.freeze(patch as PushedPresence),\n })\n }\n if (\n typeof patch.participant !== 'string' ||\n patch.participant.length === 0\n ) {\n throw new TypeError('presence participant must be a non-empty string')\n }\n if (RESERVED_PARTICIPANT_IDS.has(patch.participant)) {\n throw new TypeError(\n `presence participant must not be '${patch.participant}'`,\n )\n }\n if (\n patch.at !== undefined &&\n (typeof patch.at !== 'number' ||\n !Number.isFinite(patch.at) ||\n patch.at < 0 ||\n patch.at > MAX_DATE_MS)\n ) {\n throw new TypeError(\n 'presence at must be non-negative epoch milliseconds within the Date range',\n )\n }\n // Validate the whole patch before the adapter sees any of it — a\n // bad field means nothing is broadcast.\n const validated: Record<string, unknown> = nullProtoRecord()\n for (const [field, value] of Object.entries(patch.values)) {\n if (value === undefined) continue\n const schema = Object.hasOwn(presenceDefs, field)\n ? presenceDefs[field]\n : undefined\n if (!schema) {\n throw new A2Error(\n 'UNKNOWN_PRESENCE_FIELD',\n `contract '${name}' has no presence field '${field}'`,\n )\n }\n if (value === null) {\n validated[field] = null\n continue\n }\n const result = validateSync(schema, value, `presence field '${field}'`)\n if (result.issues) {\n throw new A2Error(\n 'INVALID_PAYLOAD',\n `invalid value for presence field '${field}' on machine '${name}'`,\n { details: result.issues },\n )\n }\n validated[field] = result.value\n }\n const store = await resolveStore()\n try {\n await requirePresence(store).set(\n nsId(sessionId),\n patch.participant,\n validated,\n {\n seen: patch.seen ?? fallbackSeen,\n // The sender's stamp is the LWW order; receipt time is the\n // fallback for stampless callers (handlers, old wire\n // clients), where receipt order is sender order — single\n // writer. Storage anchors expiry on its own clock either way.\n at: new Date(patch.at ?? Date.now()),\n ttlMs: presenceTtlMs,\n },\n )\n } catch (err) {\n throw asStoreUnavailable(err)\n }\n }\n\n const readPresenceMap = async (\n sessionId: string,\n ): Promise<PresenceMap<P>> => {\n const store = await resolveStore()\n let rows: PresenceRow[]\n try {\n rows = await requirePresence(store).read(nsId(sessionId))\n } catch (err) {\n throw asStoreUnavailable(err)\n }\n return foldPresenceRows(rows) as PresenceMap<P>\n }\n\n /**\n * The two-plane feed. Patches ride `subscribe` when the adapter has\n * the push tier; without it the map is re-read and diffed whenever\n * the event feed wakes, and at the poll idle ceiling while it is\n * silent — degraded means later, not lost while watched.\n */\n const streamWithPresence = (\n id: string,\n startAfter: number,\n ): AsyncIterable<ContractEvent<D> | PresencePatch | PresenceSnapshot> => {\n const ns = nsId(id)\n const outer = async function* (): AsyncGenerator<\n ContractEvent<D> | PresencePatch | PresenceSnapshot\n > {\n const store = await resolveStore()\n const api = requirePresence(store)\n\n const readRows = async (): Promise<PresenceRow[]> => {\n try {\n return await api.read(ns)\n } catch (err) {\n throw asStoreUnavailable(err)\n }\n }\n\n // What this feed has already painted, per (participant, field) —\n // the comparison state for re-read diffs.\n const painted = new Map<\n string,\n Map<string, { seen: number; atMs: number; value: string }>\n >()\n\n // One patch per (participant, field), never merged — a merged\n // stamp would let a stale field inherit a fresher sibling's\n // `seen` and survive the documented frontier reconciliation.\n const diffRows = (rows: PresenceRow[]): PresencePatch[] => {\n const patches: PresencePatch[] = []\n const live = new Map<string, Set<string>>()\n for (const row of rows) {\n let liveFields = live.get(row.participant)\n if (!liveFields) {\n liveFields = new Set()\n live.set(row.participant, liveFields)\n }\n liveFields.add(row.field)\n const stamp = {\n seen: row.seen,\n atMs: row.at.getTime(),\n value: fingerprint(row.value),\n }\n const prior = painted.get(row.participant)?.get(row.field)\n if (\n prior &&\n prior.seen === stamp.seen &&\n prior.atMs === stamp.atMs &&\n prior.value === stamp.value\n ) {\n continue\n }\n let paintedFields = painted.get(row.participant)\n if (!paintedFields) {\n paintedFields = new Map()\n painted.set(row.participant, paintedFields)\n }\n paintedFields.set(row.field, stamp)\n patches.push({\n participant: row.participant,\n values: { [row.field]: row.value },\n seen: row.seen,\n at: row.at,\n })\n }\n for (const [participant, fields] of painted) {\n for (const [field, prior] of fields) {\n if (live.get(participant)?.has(field)) continue\n fields.delete(field)\n patches.push({\n participant,\n values: { [field]: null },\n // A cleared field has no surviving row; its last painted\n // `seen` and the observation time are the honest stamps.\n seen: prior.seen,\n at: new Date(),\n })\n }\n if (fields.size === 0) painted.delete(participant)\n }\n return patches\n }\n\n const paint = (patch: PresencePatch): void => {\n let fields = painted.get(patch.participant)\n for (const [field, value] of Object.entries(patch.values)) {\n if (value === null || value === undefined) {\n fields?.delete(field)\n continue\n }\n if (!fields) {\n fields = new Map()\n painted.set(patch.participant, fields)\n }\n fields.set(field, {\n seen: patch.seen,\n atMs: patch.at.getTime(),\n value: fingerprint(value),\n })\n }\n if (fields?.size === 0) painted.delete(patch.participant)\n }\n\n // Arrivals coalesce per (participant, field): latest value wins,\n // each field keeps its own seen/at stamps (never merged — a stale\n // field must not inherit a fresher sibling's `seen`), one patch\n // per (participant, field) on drain. A stalled consumer therefore\n // holds at most the live presence cardinality, never the arrival\n // history.\n const queue = new Map<\n string,\n Map<string, { value: unknown; seen: number; at: Date }>\n >()\n let wakeQueue: (() => void) | null = null\n const enqueue = (patch: PresencePatch): void => {\n for (const [field, value] of Object.entries(patch.values)) {\n if (value === undefined) continue\n let fields = queue.get(patch.participant)\n if (!fields) {\n fields = new Map()\n queue.set(patch.participant, fields)\n }\n // Per-field LWW in the queue itself: pub/sub delivery order\n // is not apply order (two instances' PUBLISHes race), and an\n // unconditional overwrite would let an older patch swallow a\n // newer queued value that then never reaches the subscriber.\n // Ties go to the incoming patch, like every other comparator.\n const queued = fields.get(field)\n if (queued && queued.at.getTime() > patch.at.getTime()) continue\n fields.set(field, { value, seen: patch.seen, at: patch.at })\n }\n wakeQueue?.()\n }\n const dequeue = (): PresencePatch | null => {\n for (const [participant, fields] of queue) {\n for (const [field, stamp] of fields) {\n fields.delete(field)\n if (fields.size === 0) queue.delete(participant)\n return {\n participant,\n values: { [field]: stamp.value },\n seen: stamp.seen,\n at: stamp.at,\n }\n }\n queue.delete(participant)\n }\n return null\n }\n // Subscribe before the snapshot read: a patch landing between\n // the two is painted twice, never lost — repaints are idempotent.\n const unsubscribe = api.subscribe?.(ns, enqueue)\n\n const events = store.stream(ns, { startAfter })[Symbol.asyncIterator]()\n let pendingEvent: Promise<IteratorResult<Event>> | null = null\n try {\n // Exactly one snapshot before any live item: the pruned map,\n // per-field stamps exact — a reconnecting client replaces its\n // foreign entries wholesale from it.\n const snapshotRows = await readRows()\n for (const row of snapshotRows) {\n let fields = painted.get(row.participant)\n if (!fields) {\n fields = new Map()\n painted.set(row.participant, fields)\n }\n fields.set(row.field, {\n seen: row.seen,\n atMs: row.at.getTime(),\n value: fingerprint(row.value),\n })\n }\n yield { snapshot: foldPresenceRows(snapshotRows) }\n\n for (;;) {\n for (;;) {\n const patch = dequeue()\n if (!patch) break\n paint(patch)\n yield patch\n }\n pendingEvent ??= events.next()\n let woke: 'event' | 'patch' | 'tick'\n if (unsubscribe) {\n const arrival = new Promise<void>((resolve) => {\n wakeQueue = resolve\n })\n woke = await Promise.race([\n pendingEvent.then(() => 'event' as const),\n arrival.then(() => 'patch' as const),\n ])\n wakeQueue = null\n if (woke === 'patch') continue\n } else {\n const sleeper = defaultSleep(POLL_TIMINGS.idleCeilingMs)\n woke = await Promise.race([\n pendingEvent.then(() => 'event' as const),\n sleeper.promise.then(() => 'tick' as const),\n ])\n sleeper.cancel()\n }\n if (woke === 'event') {\n const result = await pendingEvent\n pendingEvent = null\n if (result.done) return\n yield toSessionEvent(id, result.value)\n }\n if (!unsubscribe) {\n for (const patch of diffRows(await readRows())) yield patch\n }\n }\n } finally {\n wakeQueue = null\n unsubscribe?.()\n // The consumer may close while an event read is in flight; its\n // settlement is no longer anyone's business.\n pendingEvent?.catch(() => {})\n await events.return?.()\n }\n }\n return outer()\n }\n\n const makeSession = <Append>(\n id: string,\n append: Append,\n trigger: Pick<StoredEvent, 'id' | 'createdAt' | 'index'> | null,\n ): Session<D, Append, P> =>\n ({\n id,\n append,\n schedule: makeSchedule(id, trigger),\n history: async (bounds?: { gte?: number; lte?: number }) =>\n (await readHistory(id, bounds)).map(toPublic),\n state: <S>(reducer: Reducer<D, S>) => readState(id, reducer),\n stream: (opts?: { startAfter?: number; presence?: boolean }) => {\n const startAfter = opts?.startAfter ?? 0\n assertStreamIndex(startAfter)\n return opts?.presence === true\n ? streamWithPresence(id, startAfter)\n : streamEvents(id, startAfter)\n },\n // Only on presence-declaring contracts — the type surface promises\n // no runtime-inert members (a2-api.md §12).\n ...(declaresPresence\n ? {\n setPresence: (patch: {\n participant: string\n values: Record<string, unknown>\n seen?: number\n at?: number\n }) => setPresence(id, patch, trigger?.index ?? 0),\n presence: () => readPresenceMap(id),\n }\n : {}),\n }) as Session<D, Append, P>\n\n // ── drain ────────────────────────────────────────────────────────\n\n const makeCtx = (\n trigger: StoredEvent,\n attempt: number,\n signal: AbortSignal,\n ): HandlerContext<D> => {\n const publicSessionId = stripNs(trigger.sessionId)\n const append: HandlerAppend<D> = async (appendName, ...events) => {\n assertAppendName(appendName)\n const generatedIds = events.map((event) => event.id === undefined)\n const withIds = await Promise.all(\n // oxlint-disable-next-line no-map-spread\n events.map(async (event, item) => {\n if (event.id !== undefined) return event\n const id = await deterministicEventId(trigger.id, appendName, item)\n return { ...event, id }\n }),\n )\n return appendCore(\n publicSessionId,\n withIds,\n 'handler',\n 'inline',\n (_rows, watchdogDueAt) => scheduleDrain(publicSessionId, watchdogDueAt),\n { index: trigger.index, attempt },\n generatedIds,\n )\n }\n return {\n event: toPublic(trigger),\n attempt,\n // The handler-scoped `setPresence` stamps `seen` with the\n // triggering event's index by default — the frontier the handler\n // provably reflects.\n session: makeSession(publicSessionId, append, trigger),\n signal,\n }\n }\n\n const abortHubs = new Map<string, AbortHub>()\n\n const createAbortHub = (\n store: A2Store,\n ns: string,\n startAfter: number,\n ): AbortHub => {\n const hub: AbortHub = {\n subscriptions: new Set(),\n seen: new Map(),\n startAfter,\n ready: Promise.resolve(),\n watch: null,\n error: null,\n iterator: null,\n stopped: false,\n }\n hub.ready = (async () => {\n const existing = await store.read(ns, { afterIndex: startAfter })\n for (const event of existing) dispatchAbortEvent(hub, event)\n const tail = existing.at(-1)?.index ?? startAfter\n const feed = store.stream(ns, { startAfter: tail })\n const iterator = feed[Symbol.asyncIterator]()\n hub.iterator = iterator\n hub.watch = (async () => {\n for (;;) {\n const { value, done } = await iterator.next()\n if (done || value === undefined || hub.stopped) return\n dispatchAbortEvent(hub, value)\n }\n })().catch((error: unknown) => {\n hub.error = error\n })\n })().catch((error: unknown) => {\n hub.error = error\n if (abortHubs.get(ns) === hub) abortHubs.delete(ns)\n throw error\n })\n abortHubs.set(ns, hub)\n return hub\n }\n\n const subscribeAbort = async (\n store: A2Store,\n ns: string,\n trigger: StoredEvent,\n abortOn: AbortMatcher,\n attempt: number,\n ): Promise<{\n signal: AbortSignal\n monitor<T>(operation: Promise<T>): Promise<T>\n close(): Promise<void>\n }> => {\n let hub = abortHubs.get(ns)\n if (!hub) hub = createAbortHub(store, ns, trigger.index)\n const activeTypes = new Set<string>()\n for (const active of hub.subscriptions) {\n for (const type of active.types) activeTypes.add(type)\n }\n const publicTrigger = toPublic(trigger)\n const subscription: AbortSubscription = {\n controller: new AbortController(),\n triggerIndex: trigger.index,\n types: new Set(abortOn.keys()),\n matches: (event) => {\n if (event.index <= trigger.index) return false\n const matcher = abortOn.get(event.type)\n if (matcher === undefined) return false\n return matcher === true\n ? true\n : matcher(toPublic(event as StoredEvent), publicTrigger, { attempt })\n },\n }\n hub.subscriptions.add(subscription)\n const needsCatchup =\n trigger.index < hub.startAfter ||\n [...subscription.types].some((type) => !activeTypes.has(type))\n if (needsCatchup) {\n const earlier = await store.read(ns, { afterIndex: trigger.index })\n hub.startAfter = Math.min(hub.startAfter, trigger.index)\n for (const event of earlier) dispatchAbortEvent(hub, event)\n }\n for (const event of hub.seen.values()) {\n if (subscription.matches(event)) subscription.controller.abort()\n }\n await hub.ready\n if (hub.error !== null) throw hub.error\n return {\n signal: subscription.controller.signal,\n monitor: async <T>(operation: Promise<T>): Promise<T> => {\n const outcome = await Promise.race([\n operation.then(\n (value) => ({ type: 'completed' as const, value }),\n (error: unknown) => ({ type: 'handler-failed' as const, error }),\n ),\n hub.watch!.then(() =>\n hub.error === null\n ? { type: 'monitor-closed' as const }\n : { type: 'monitor-failed' as const, error: hub.error },\n ),\n ])\n if (outcome.type === 'completed') return outcome.value\n if (outcome.type === 'handler-failed') throw outcome.error\n if (outcome.type === 'monitor-failed') {\n for (const active of hub.subscriptions) {\n active.controller.abort(outcome.error)\n }\n await operation.catch(() => {})\n throw outcome.error\n }\n await operation.catch(() => {})\n throw new Error('abort monitor closed while handlers were active')\n },\n close: async () => {\n hub.subscriptions.delete(subscription)\n if (hub.subscriptions.size > 0) {\n pruneAbortHub(hub)\n return\n }\n hub.stopped = true\n abortHubs.delete(ns)\n await hub.ready\n await hub.iterator?.return?.()\n await hub.watch\n },\n }\n }\n\n const returnedEvents = async (\n sessionId: string,\n trigger: StoredEvent,\n result: void | AppendInput<D> | readonly AppendInput<D>[],\n ): Promise<ReturnedEvent[]> => {\n if (result === undefined) return []\n const events = Array.isArray(result) ? [...result] : [result]\n if (events.length === 0) return []\n const withIds = await Promise.all(\n // oxlint-disable-next-line oxc/no-map-spread -- handler results remain caller-owned\n events.map(async (event, item) => {\n const withId = { ...event }\n withId.id =\n event.id ?? (await deterministicReturnedEventId(trigger.id, item))\n return withId\n }),\n )\n return validateEvents(sessionId, withIds).map((event) =>\n Object.assign(event, {\n id: event.id!,\n cause: {\n index: trigger.index,\n attempt: trigger.attemptCount,\n },\n }),\n )\n }\n\n type EventStatus =\n 'processed' | 'failed' | 'dead_lettered' | 'superseded' | 'surrendered'\n\n type EventOutcome = {\n status: EventStatus\n opensLane: boolean\n appendsEvents: boolean\n }\n\n const drainSession = (\n sessionId: string,\n watchdogDueAt?: number,\n signal?: DrainSignal,\n ): Promise<DrainResult> =>\n telemetry.span(\n 'a2.drain',\n { 'a2.contract': name, 'a2.session_id': sessionId },\n async (span) => {\n const store = await resolveStore()\n const ns = nsId(sessionId)\n const holder = crypto.randomUUID()\n type ActiveEvent = {\n attempt: number\n execution: Promise<EventOutcome>\n supersede: AbortController\n /** Resolves the tracked execution early once supersession is durable. */\n fence: (outcome: EventOutcome) => void\n /** Local lease estimate: request time + ttl — at or before the store's. */\n expiresAtMs: number\n lapsed: boolean\n }\n const active = new Map<number, ActiveEvent>()\n const excluded = new Set<number>()\n let processed = 0\n let sawFailure = false\n let schedulerArm: Promise<void> | undefined\n let heartbeat: ReturnType<typeof setInterval> | null = null\n let lapseTimer: ReturnType<typeof setTimeout> | null = null\n let retryTimer: ReturnType<typeof setTimeout> | null = null\n let renewal: Promise<void> | null = null\n let stopRenewing = false\n\n // Self-fencing at local lease lapse: the drain wrote every expiry it\n // holds (request time + ttl, at or before the store's own stamp), so\n // it can conclude \"assume a successor\" with zero I/O — including\n // while the store is unreachable or in the first tick after a stall.\n const lapseDue = (): void => {\n lapseTimer = null\n const nowMs = Date.now()\n for (const [index, entry] of active) {\n if (entry.lapsed || entry.expiresAtMs > nowMs) continue\n entry.lapsed = true\n entry.supersede.abort(\n new A2Error(\n 'CLAIM_EXPIRED',\n `the claim on event ${index} in session '${sessionId}' lapsed without renewal`,\n ),\n )\n }\n scheduleLapse()\n }\n const scheduleLapse = (): void => {\n if (lapseTimer) {\n clearTimeout(lapseTimer)\n lapseTimer = null\n }\n let next = Number.POSITIVE_INFINITY\n for (const entry of active.values()) {\n if (!entry.lapsed) next = Math.min(next, entry.expiresAtMs)\n }\n if (next === Number.POSITIVE_INFINITY) return\n lapseTimer = setTimeout(lapseDue, Math.max(0, next - Date.now()))\n ;(lapseTimer as { unref?: () => void }).unref?.()\n }\n\n // A missed beat spends lease slack; the next scheduled beat may be\n // provably too late. Retry promptly (jittered against fleet-wide\n // synchronization on a struggling store) while a lease can still be\n // saved — the lapse ends the retries naturally.\n const scheduleRenewRetry = (): void => {\n if (stopRenewing || retryTimer) return\n const nowMs = Date.now()\n const saveable = [...active.values()].some(\n (entry) => !entry.lapsed && entry.expiresAtMs > nowMs,\n )\n if (!saveable) return\n const delay = DRAIN_TIMINGS.renewRetryMs * (0.5 + Math.random() * 0.5)\n retryTimer = setTimeout(() => {\n retryTimer = null\n void renew()\n }, delay)\n ;(retryTimer as { unref?: () => void }).unref?.()\n }\n\n const alignWatchdogAt = (minimumDueAt: number): number => {\n if (watchdogDueAt === undefined) return minimumDueAt\n const beats = Math.max(\n 0,\n Math.ceil(\n (minimumDueAt - watchdogDueAt) / DRAIN_TIMINGS.claimHeartbeatMs,\n ),\n )\n return watchdogDueAt + beats * DRAIN_TIMINGS.claimHeartbeatMs\n }\n\n const requestWatchdog = (dueAt: number): void => {\n const arm = startSchedulerArm(sessionId, alignWatchdogAt(dueAt))\n if (arm) schedulerArm = arm\n }\n\n const renew = (): Promise<void> => {\n if (stopRenewing || renewal || active.size === 0) {\n return renewal ?? Promise.resolve()\n }\n const window = nextClaimWindow()\n requestWatchdog(window.watchdogAtMs)\n const claims = [...active.entries()].map(([index, entry]) => ({\n index,\n attempt: entry.attempt,\n }))\n const operation = store\n .renewClaims({\n sessionId: ns,\n holder,\n claims,\n ttlMs: window.ttlMs,\n ...(window.deadlineCapped\n ? { expiresAtMs: window.expiresAtMs }\n : {}),\n })\n .then(\n (result) => {\n for (const index of result.renewed) {\n const entry = active.get(index)\n if (entry && !entry.lapsed) {\n entry.expiresAtMs = window.expiresAtMs\n }\n }\n for (const index of result.superseded) {\n const entry = active.get(index)\n if (!entry) continue\n // Idempotent: the local lapse normally aborted this signal\n // already — this is the proof, whose job is the release.\n entry.supersede.abort(\n new A2Error(\n 'SUPERSEDED_ATTEMPT',\n `a newer attempt owns event ${index} in session '${sessionId}'`,\n ),\n )\n entry.fence({\n status: 'superseded',\n opensLane: false,\n appendsEvents: false,\n })\n }\n if (window.deadlineCapped) stopRenewing = true\n scheduleLapse()\n return undefined\n },\n () => {\n scheduleRenewRetry()\n return undefined\n },\n )\n let tracked!: Promise<void>\n tracked = operation.finally(() => {\n if (renewal === tracked) renewal = null\n })\n renewal = tracked\n return tracked\n }\n\n const runEvent = async (\n event: StoredEvent,\n supersedeSignal: AbortSignal,\n ): Promise<EventOutcome> => {\n const registration = handlers.get(event.type)\n return telemetry.span(\n 'a2.event',\n {\n 'a2.contract': name,\n 'a2.session_id': sessionId,\n 'a2.event.type': event.type,\n 'a2.event.index': event.index,\n 'a2.event.id': event.id,\n 'a2.event.attempt': event.attemptCount,\n 'a2.event.handled': registration !== undefined,\n ...(event.lane === null ? {} : { 'a2.event.lane': event.lane }),\n },\n async (eventSpan) => {\n let subscription:\n | {\n signal: AbortSignal\n monitor<T>(operation: Promise<T>): Promise<T>\n close(): Promise<void>\n }\n | undefined\n let handlerSignal = supersedeSignal\n let returned: ReturnedEvent[]\n try {\n if (registration?.abortOn) {\n subscription = await subscribeAbort(\n store,\n ns,\n event,\n registration.abortOn,\n event.attemptCount,\n )\n handlerSignal = AbortSignal.any([\n supersedeSignal,\n subscription.signal,\n ])\n }\n const operation = registration?.handler(\n makeCtx(event, event.attemptCount, handlerSignal),\n )\n const result = operation\n ? await (subscription\n ? subscription.monitor(operation)\n : operation)\n : undefined\n if (subscription) {\n await subscription.close()\n subscription = undefined\n }\n returned = await returnedEvents(sessionId, event, result)\n } catch (err) {\n if (supersedeSignal.aborted && err === supersedeSignal.reason) {\n // The handler surrendered to its own abort — identity, not\n // code, so it cannot arrive from another context. A lapse\n // is not a handler failure: no completion, no failure\n // budget spent; the claim simply expires and recovery\n // retries.\n eventSpan.setAttribute('a2.event.outcome', 'surrendered')\n return {\n status: 'surrendered',\n opensLane: false,\n appendsEvents: false,\n }\n }\n // Everything else — including a store fence rejection — is\n // adjudicated by failAttempt, which is itself fenced: a\n // genuinely superseded attempt gets 'superseded' back with\n // no mutation. One adjudicator, not two.\n eventSpan.recordError(err)\n const failure = await store.failAttempt({\n sessionId: ns,\n index: event.index,\n attempt: event.attemptCount,\n error: describeError(err),\n maxFailures: MAX_FAILURES,\n })\n eventSpan.setAttribute('a2.event.outcome', failure.outcome)\n return {\n status: failure.outcome,\n opensLane: false,\n appendsEvents: false,\n }\n } finally {\n await subscription?.close()\n }\n await renewal\n const completion = await store.completeAttempt({\n sessionId: ns,\n index: event.index,\n attempt: event.attemptCount,\n events: returned,\n })\n eventSpan.setAttribute(\n 'a2.event.outcome',\n completion.outcome === 'completed'\n ? 'processed'\n : completion.outcome,\n )\n if (completion.outcome === 'superseded') {\n return {\n status: 'superseded',\n opensLane: false,\n appendsEvents: false,\n }\n }\n if (handlerSignal.aborted) {\n eventSpan.setAttribute('a2.event.aborted', true)\n }\n return {\n status: 'processed',\n opensLane: event.lane !== null,\n appendsEvents: returned.length > 0,\n }\n },\n )\n }\n\n let claimAgain = false\n\n const start = (event: StoredEvent, expiresAtMs: number): void => {\n // Re-claiming an index this drain still tracks is durable proof\n // that the old attempt lost: our own new claim advanced the\n // ordinal. Fence the old entry before it can be confused with\n // the new one.\n const previous = active.get(event.index)\n if (previous) {\n previous.supersede.abort(\n new A2Error(\n 'SUPERSEDED_ATTEMPT',\n `a newer attempt owns event ${event.index} in session '${sessionId}'`,\n ),\n )\n previous.fence({\n status: 'superseded',\n opensLane: false,\n appendsEvents: false,\n })\n }\n const supersede = new AbortController()\n let fence!: (outcome: EventOutcome) => void\n const fenced = new Promise<EventOutcome>((resolve) => {\n fence = resolve\n })\n // The race lets a durable supersession release this slot while the\n // zombie handler keeps running — its completion and failure are\n // fenced by the store, so nothing it does from here is counted.\n let entry!: ActiveEvent\n const execution = Promise.race([\n runEvent(event, supersede.signal),\n fenced,\n ]).then((eventOutcome) => {\n // Identity-guarded: a fenced predecessor's continuation must\n // not delete the entry of the attempt that replaced it.\n if (active.get(event.index) === entry) active.delete(event.index)\n if (eventOutcome.status === 'processed') processed += 1\n if (eventOutcome.status === 'failed') {\n excluded.add(event.index)\n sawFailure = true\n }\n claimAgain ||= eventOutcome.opensLane || eventOutcome.appendsEvents\n return eventOutcome\n })\n entry = {\n attempt: event.attemptCount,\n execution,\n supersede,\n fence,\n expiresAtMs,\n lapsed: false,\n }\n active.set(event.index, entry)\n scheduleLapse()\n if (!heartbeat && !stopRenewing) {\n heartbeat = setInterval(\n () => void renew(),\n DRAIN_TIMINGS.claimHeartbeatMs,\n )\n ;(heartbeat as { unref?: () => void }).unref?.()\n }\n }\n\n let outcome: DrainOutcome = 'settled'\n let shouldClaim = true\n try {\n for (;;) {\n const signalVersion = signal?.version ?? 0\n let claim: StoreClaimAvailableResult | undefined\n if (shouldClaim) {\n const window = nextClaimWindow()\n claim = await store.claimAvailable({\n sessionId: ns,\n holder,\n ttlMs: window.ttlMs,\n ...(window.deadlineCapped\n ? { expiresAtMs: window.expiresAtMs }\n : {}),\n ...(excluded.size === 0\n ? {}\n : { excludeIndexes: [...excluded] }),\n })\n if (claim.outcome === 'claimed') {\n requestWatchdog(window.watchdogAtMs)\n if (window.deadlineCapped) stopRenewing = true\n for (const event of claim.events) {\n start(event, window.expiresAtMs)\n }\n shouldClaim = false\n }\n }\n if (active.size > 0) {\n const wake = signal?.wait(signalVersion)\n await Promise.race([\n ...[...active.values()].map((entry) => entry.execution),\n ...(wake ? [wake.promise] : []),\n ])\n wake?.cancel()\n shouldClaim =\n claimAgain ||\n active.size === 0 ||\n (signal !== undefined && signal.version !== signalVersion)\n claimAgain = false\n continue\n }\n if (!shouldClaim) {\n shouldClaim = true\n continue\n }\n if (claim === undefined) continue\n if (signal && signal.version !== signalVersion) continue\n if (claim.outcome === 'busy') {\n requestWatchdog(\n claim.retryAt.getTime() + DRAIN_TIMINGS.watchdogGraceMs,\n )\n outcome = 'busy'\n } else if (sawFailure) {\n outcome = 'stalled'\n }\n if (signal) signal.closed = true\n break\n }\n } finally {\n if (signal) signal.closed = true\n stopRenewing = true\n if (heartbeat) clearInterval(heartbeat)\n if (retryTimer) clearTimeout(retryTimer)\n await renewal\n await Promise.allSettled(\n [...active.values()].map((entry) => entry.execution),\n )\n if (lapseTimer) clearTimeout(lapseTimer)\n }\n span.setAttribute('a2.drain.processed', processed)\n span.setAttribute('a2.drain.outcome', outcome)\n return {\n settled: outcome === 'settled',\n outcome,\n processed,\n ...(schedulerArm ? { schedulerArm } : {}),\n }\n },\n )\n\n // ── public surface ───────────────────────────────────────────────\n\n const appendExternal = async (\n sessionId: string,\n mode: 'inline' | 'dispatch',\n events: Array<AppendInput<D> | PushedEvent>,\n requireDurableInitialArm = false,\n ): Promise<ContractEvent<D>[]> => {\n const pushed = events.filter(\n (event): event is PushedEvent =>\n Reflect.get(event, '~a2.pushed') === true,\n )\n if (pushed.length > 0) {\n await options.validatePush?.({ sessionId, events: pushed })\n }\n return appendCore(\n sessionId,\n events as AppendInput<D>[],\n 'external',\n mode,\n (_rows, watchdogDueAt) => scheduleDrain(sessionId, watchdogDueAt),\n undefined,\n undefined,\n requireDurableInitialArm,\n )\n }\n\n const self: A2Server<D, P> = {\n contract: serverContract,\n session(id) {\n assertSessionId(id)\n const appendInline = async (\n ...events: Array<AppendInput<D> | PushedEvent>\n ) => appendExternal(id, 'inline', events)\n const appendDispatch = async (\n ...events: Array<AppendInput<D> | PushedEvent>\n ) => appendExternal(id, 'dispatch', events)\n const append = Object.assign(appendInline, {\n dispatch: appendDispatch,\n }) as SessionAppend<D>\n return makeSession(id, append, null)\n },\n\n async drain(sessionId) {\n assertSessionId(sessionId)\n const { settled } = await drainSession(sessionId)\n return { settled }\n },\n }\n\n serverInternals.set(self, {\n settle: async () => {\n while (inFlight.size > 0) {\n await Promise.allSettled(inFlight)\n }\n },\n schedulerDrain: (sessionId, opts) => {\n assertSessionId(sessionId)\n return drainSession(sessionId, opts?.watchdogDueAt)\n },\n schedulerAppend: async (sessionId, events) => {\n if (!scheduler) {\n throw new TypeError(\n 'scheduled append delivery requires a configured scheduler adapter',\n )\n }\n assertSessionId(sessionId)\n await appendExternal(sessionId, 'inline', [...events], true)\n },\n })\n serverSchedulerBindings.set(self, { scheduler })\n\n serverInspection.set(self, {\n async listSessions(inspectionOptions) {\n const store = await resolveStore()\n if (!store.inspect) {\n throw new InspectionUnsupportedError(\n 'this store backend does not support inspection',\n )\n }\n const page = await store.inspect.listSessions({\n prefix: `${name}${NS}`,\n limit: inspectionOptions.limit,\n ...(inspectionOptions.cursor !== undefined\n ? { cursor: inspectionOptions.cursor }\n : {}),\n })\n return {\n cursor: page.cursor,\n // oxlint-disable-next-line oxc/no-map-spread -- inspection results remain adapter-owned\n sessions: page.sessions.map((session) => {\n const publicSession = { ...session }\n publicSession.sessionId = stripNs(session.sessionId)\n return publicSession\n }),\n }\n },\n async readSessionPage(sessionId, inspectionOptions) {\n assertSessionId(sessionId)\n if (\n !Number.isSafeInteger(inspectionOptions.afterIndex) ||\n inspectionOptions.afterIndex < 0 ||\n !Number.isSafeInteger(inspectionOptions.limit) ||\n inspectionOptions.limit < 1 ||\n (inspectionOptions.throughIndex !== undefined &&\n (!Number.isSafeInteger(inspectionOptions.throughIndex) ||\n inspectionOptions.throughIndex < 0))\n ) {\n throw new TypeError('invalid inspection event page bounds')\n }\n const store = await resolveStore()\n if (!store.inspect) {\n throw new InspectionUnsupportedError(\n 'this store backend does not support inspection',\n )\n }\n const ns = nsId(sessionId)\n const snapshots =\n inspectionOptions.afterIndex === 0\n ? await store.inspect.listSnapshots(ns)\n : []\n const page = store.inspect.readEvents\n ? await store.inspect.readEvents(ns, inspectionOptions)\n : await (async () => {\n const all = await store.read(ns)\n const currentFrontier = all.at(-1)?.index ?? 0\n const throughIndex = Math.min(\n inspectionOptions.throughIndex ?? currentFrontier,\n currentFrontier,\n )\n return {\n events: all\n .filter(\n (event) =>\n event.index > inspectionOptions.afterIndex &&\n event.index <= throughIndex,\n )\n .slice(0, inspectionOptions.limit),\n throughIndex,\n }\n })()\n const { events, throughIndex } = page\n if (\n !Number.isSafeInteger(throughIndex) ||\n throughIndex < 0 ||\n events.length > inspectionOptions.limit ||\n (inspectionOptions.throughIndex !== undefined &&\n inspectionOptions.afterIndex > 0 &&\n throughIndex !== inspectionOptions.throughIndex)\n ) {\n throw new A2Error(\n 'STORE_UNAVAILABLE',\n `inspection event page for session '${sessionId}' has invalid bounds`,\n )\n }\n for (let position = 0; position < events.length; position += 1) {\n if (\n events[position]!.index !==\n inspectionOptions.afterIndex + position + 1 ||\n events[position]!.index > throughIndex\n ) {\n throw new A2Error(\n 'STORE_UNAVAILABLE',\n `inspection event page for session '${sessionId}' is not contiguous`,\n )\n }\n }\n if (inspectionOptions.afterIndex < throughIndex && events.length === 0) {\n throw new A2Error(\n 'STORE_UNAVAILABLE',\n `inspection event page for session '${sessionId}' ended before index ${throughIndex}`,\n )\n }\n const lastIndex = events.at(-1)?.index ?? inspectionOptions.afterIndex\n return {\n // oxlint-disable-next-line oxc/no-map-spread -- inspection results remain adapter-owned\n events: events.map((event) => {\n const publicEvent = { ...event }\n publicEvent.sessionId = sessionId\n return publicEvent\n }),\n snapshots: snapshots.filter(\n (snapshot) => snapshot.index <= throughIndex,\n ),\n throughIndex,\n nextIndex: lastIndex < throughIndex ? lastIndex : null,\n }\n },\n })\n\n return self\n}\n\nfunction assertSessionId(id: string): void {\n if (typeof id !== 'string' || id.length === 0) {\n throw new TypeError('session id must be a non-empty string')\n }\n if (id.includes(NS)) {\n throw new TypeError('session id contains a reserved control character')\n }\n}\n\nfunction assertHistoryIndex(name: 'gte' | 'lte', value?: number): void {\n if (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {\n throw new TypeError(`history.${name} must be a non-negative safe integer`)\n }\n}\n\nfunction assertStreamIndex(value: number): void {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new TypeError('stream.startAfter must be a non-negative safe integer')\n }\n}\n\nfunction assertAppendName(name: string): void {\n if (typeof name !== 'string' || name.length === 0) {\n throw new TypeError('handler append name must be a non-empty string')\n }\n}\n\nfunction assertScheduleName(name: string): void {\n if (typeof name !== 'string' || name.length === 0) {\n throw new TypeError('schedule name must be a non-empty string')\n }\n}\n\nconst SCHEDULE_DELAY = /^(?:0|[1-9]\\d*)(?:\\.\\d+)?(ms|s|m|h|d)$/\nconst SCHEDULE_DELAY_MULTIPLIER: Record<'ms' | 's' | 'm' | 'h' | 'd', number> =\n {\n ms: 1,\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n }\n\nfunction scheduleDueAt(timing: ScheduleTiming, baseTime: number): number {\n if (timing === null || typeof timing !== 'object' || Array.isArray(timing)) {\n throw new TypeError(\n \"schedule timing must contain exactly one of 'delay' or 'at'\",\n )\n }\n const record = timing as Record<string, unknown>\n const hasDelay = Object.hasOwn(record, 'delay')\n const hasAt = Object.hasOwn(record, 'at')\n if (hasDelay === hasAt) {\n throw new TypeError(\n \"schedule timing must contain exactly one of 'delay' or 'at'\",\n )\n }\n\n let dueAt: number\n if (hasAt) {\n const at = record['at']\n if (!(at instanceof Date) || !Number.isFinite(at.getTime())) {\n throw new TypeError('schedule at must be a valid Date')\n }\n dueAt = at.getTime()\n } else {\n const delay = record['delay']\n if (typeof delay !== 'string') {\n throw new TypeError(\n \"schedule delay must use ms, s, m, h, or d (for example '30s')\",\n )\n }\n const match = SCHEDULE_DELAY.exec(delay)\n const amount = match ? Number(delay.slice(0, -match[1]!.length)) : NaN\n if (!match || !Number.isFinite(amount) || amount <= 0) {\n throw new TypeError(\n \"schedule delay must be positive and use ms, s, m, h, or d (for example '30s')\",\n )\n }\n dueAt =\n baseTime +\n amount *\n SCHEDULE_DELAY_MULTIPLIER[\n match[1] as keyof typeof SCHEDULE_DELAY_MULTIPLIER\n ]\n }\n if (!Number.isFinite(dueAt)) {\n throw new TypeError('schedule due time must be a finite epoch time')\n }\n return dueAt\n}\n\nfunction assertScheduledPayload(payload: unknown): void {\n try {\n if (isJsonValue(payload, new WeakSet())) return\n } catch {\n // Proxies and hostile accessors are not stable transport values either.\n }\n throw new TypeError(\n 'session.schedule event payload must be JSON-serializable',\n )\n}\n\nfunction cloneScheduledPayload(payload: unknown): unknown {\n assertScheduledPayload(payload)\n try {\n const cloned = structuredClone(payload)\n const encoded = JSON.stringify(cloned)\n if (encoded === undefined) throw new TypeError()\n return JSON.parse(encoded) as unknown\n } catch {\n throw new TypeError(\n 'session.schedule event payload must be JSON-serializable',\n )\n }\n}\n\nfunction isJsonValue(value: unknown, ancestors: WeakSet<object>): boolean {\n if (value === null) return true\n if (typeof value === 'string' || typeof value === 'boolean') return true\n if (typeof value === 'number') {\n return Number.isFinite(value) && !Object.is(value, -0)\n }\n if (typeof value !== 'object') return false\n if (ancestors.has(value)) return false\n ancestors.add(value)\n try {\n if (Array.isArray(value)) {\n const keys = Reflect.ownKeys(value)\n if (keys.length !== value.length + 1 || !keys.includes('length')) {\n return false\n }\n for (let index = 0; index < value.length; index += 1) {\n const descriptor = Object.getOwnPropertyDescriptor(value, String(index))\n if (\n !descriptor ||\n !descriptor.enumerable ||\n !('value' in descriptor) ||\n !isJsonValue(descriptor.value, ancestors)\n ) {\n return false\n }\n }\n return true\n }\n const prototype = Object.getPrototypeOf(value)\n if (prototype !== Object.prototype) return false\n for (const key of Reflect.ownKeys(value)) {\n if (typeof key !== 'string') return false\n const descriptor = Object.getOwnPropertyDescriptor(value, key)\n if (\n !descriptor ||\n !descriptor.enumerable ||\n !('value' in descriptor) ||\n !isJsonValue(descriptor.value, ancestors)\n ) {\n return false\n }\n }\n return true\n } finally {\n ancestors.delete(value)\n }\n}\n\nfunction cloneInitial<S>(initial: S): S {\n // Defensive: a reducer that mutates state in place must not corrupt\n // the shared initialState across folds. Fall back to the original for\n // non-cloneable values (functions, class instances).\n try {\n return structuredClone(initial)\n } catch {\n return initial\n }\n}\n\n// Server-side types users need when passing custom stores or building\n// transports — re-exported so experimental-a2/server is self-sufficient.\nexport type {\n A2Store,\n A2StoreInspection,\n AppendEvent,\n Clock,\n Event,\n EventCause,\n FailAttemptResult,\n IdSource,\n StoreAppendResult,\n StoreClaimAvailableResult,\n StoreStateRead,\n PresenceRow,\n StoredEvent,\n StoredSessionPage,\n StoredSessionSummary,\n StoredSnapshot,\n} from './store.ts'\nexport type {\n ScheduledEvent,\n SchedulerAppendTask,\n SchedulerDrainTask,\n SchedulerTask,\n} from './scheduler-task.ts'\nexport type {\n AppendInput,\n Contract,\n ContractEvent,\n EventDefs,\n PresenceDefs,\n PresenceMap,\n PresencePatch,\n PresenceSnapshot,\n} from './contract.ts'\n"],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { a as EventDefs, c as PresencePatch, l as PresenceSnapshot, n as Contract, o as PresenceDefs, r as ContractEvent, s as PresenceMap, t as AppendInput } from "./contract-jIfaR085.js";
2
2
  import { a as Event, c as IdSource, d as StoreClaimAvailableResult, f as StoreStateRead, g as StoredSnapshot, h as StoredSessionSummary, i as Clock, l as PresenceRow, m as StoredSessionPage, n as A2StoreInspection, o as EventCause, p as StoredEvent, r as AppendEvent, s as FailAttemptResult, t as A2Store, u as StoreAppendResult } from "./store-DysUkTH3.js";
3
- import { C as deliverSchedulerAppend, D as SchedulerTask, E as SchedulerDrainTask, S as createServer, T as SchedulerAppendTask, _ as Session, a as Handler, b as SessionPresence, c as HandlerEntry, d as PushValidationContext, f as PushedEvent, g as ServerOptions, h as ScheduleTiming, i as DrainableServer, l as Lane, m as ScheduleDelay, n as A2Server, o as HandlerAppend, p as PushedPresence, r as AbortSpec, s as HandlerContext, t as A2Scheduler, u as LaneContext, v as SessionAppend, w as ScheduledEvent, x as SessionSchedule, y as SessionDispatch } from "./server-DUF9pjsx.js";
3
+ import { C as deliverSchedulerAppend, D as SchedulerTask, E as SchedulerDrainTask, S as createServer, T as SchedulerAppendTask, _ as Session, a as Handler, b as SessionPresence, c as HandlerEntry, d as PushValidationContext, f as PushedEvent, g as ServerOptions, h as ScheduleTiming, i as DrainableServer, l as Lane, m as ScheduleDelay, n as A2Server, o as HandlerAppend, p as PushedPresence, r as AbortSpec, s as HandlerContext, t as A2Scheduler, u as LaneContext, v as SessionAppend, w as ScheduledEvent, x as SessionSchedule, y as SessionDispatch } from "./server-DpvjhdoE.js";
4
4
  export { A2Scheduler, A2Server, type A2Store, type A2StoreInspection, AbortSpec, type AppendEvent, type AppendInput, type Clock, type Contract, type ContractEvent, DrainableServer, type Event, type EventCause, type EventDefs, type FailAttemptResult, Handler, HandlerAppend, HandlerContext, HandlerEntry, type IdSource, Lane, LaneContext, type PresenceDefs, type PresenceMap, type PresencePatch, type PresenceRow, type PresenceSnapshot, PushValidationContext, PushedEvent, PushedPresence, ScheduleDelay, ScheduleTiming, type ScheduledEvent, type SchedulerAppendTask, type SchedulerDrainTask, type SchedulerTask, ServerOptions, Session, SessionAppend, SessionDispatch, SessionPresence, SessionSchedule, type StoreAppendResult, type StoreClaimAvailableResult, type StoreStateRead, type StoredEvent, type StoredSessionPage, type StoredSessionSummary, type StoredSnapshot, createServer, deliverSchedulerAppend };
package/dist/server.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as deliverSchedulerAppend, t as createServer } from "./server-C72KOw51.js";
1
+ import { n as deliverSchedulerAppend, t as createServer } from "./server-Duw6MVlB.js";
2
2
  export { createServer, deliverSchedulerAppend };
@@ -2,8 +2,8 @@
2
2
  /**
3
3
  * The A2Telemetry interface — the instrumentation seam. Same philosophy
4
4
  * as store backends: the interface lives in core, implementations ship as
5
- * entry points (`experimental-a2/otel` adapts it to OpenTelemetry). Without one,
6
- * every operation runs through a no-op wrapper.
5
+ * entry points (`experimental-a2/otel` adapts it to OpenTelemetry). Without
6
+ * one, spans are free and swallowed errors print to the console.
7
7
  */
8
8
  /** Attribute values a2 emits. */
9
9
  type A2AttributeValue = string | number | boolean;
@@ -30,4 +30,4 @@ type A2Telemetry = {
30
30
  };
31
31
  //#endregion
32
32
  export { A2Telemetry as i, A2SpanHandle as n, A2SpanName as r, A2AttributeValue as t };
33
- //# sourceMappingURL=telemetry-BjYHTfh2.d.ts.map
33
+ //# sourceMappingURL=telemetry-CpeclqB2.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry-BjYHTfh2.d.ts","names":[],"sources":["../src/telemetry.ts"],"mappings":";;;;;;;;KAQY;;KAGA;KAEA;;EAEV,aAAa,aAAa,OAAO;;;;;;EAMjC,YAAY;;KAGF;;;;;;;EAOV,KAAK,GACH,MAAM,YACN,YAAY,eAAe,mBAC3B,KAAK,MAAM,iBAAiB,QAAQ,KACnC,QAAQ"}
1
+ {"version":3,"file":"telemetry-CpeclqB2.d.ts","names":[],"sources":["../src/telemetry.ts"],"mappings":";;;;;;;;KAQY;;KAGA;KAEA;;EAEV,aAAa,aAAa,OAAO;;;;;;EAMjC,YAAY;;KAGF;;;;;;;EAOV,KAAK,GACH,MAAM,YACN,YAAY,eAAe,mBAC3B,KAAK,MAAM,iBAAiB,QAAQ,KACnC,QAAQ"}
@@ -218,7 +218,11 @@ That identity is an in-memory L1, not another source of truth. Repeated
218
218
  `session(id)` calls reuse it while active and for five idle minutes by
219
219
  default. A newer server fold advances it, pending pushes stay overlaid,
220
220
  and a stale server render cannot rewind it. The optional IndexedDB cache
221
- is the L2: it survives reloads; the memory runtime does not.
221
+ is the L2: it survives reloads; the memory runtime does not. The
222
+ stream is shared the same way: `connect()` takes a lease and returns
223
+ its release, so however many hooks, providers, or plain calls hold one
224
+ session open, the first lease connects and the last release closes
225
+ (`close()` is the hard stop).
222
226
 
223
227
  One detail worth knowing: every push carries a client-generated event id.
224
228
  That id is how the ack finds its optimistic entry, and it makes retrying
@@ -234,6 +238,99 @@ revisits paint from the local copy, the stream resumes from the cached
234
238
  frontier, and offline pushes queue and replay. See
235
239
  [Local-first](/guides/local-first).
236
240
 
241
+ ## Client-first sessions
242
+
243
+ Everything above assumes a server component hands the first fold down.
244
+ A client-rendered app often has nothing to hand: a sidebar showing ten
245
+ channel sessions, a user session read from deep inside a menu, panes
246
+ that mount from client-side navigation. No server fold, and no natural
247
+ provider boundary for components that reach sessions ad hoc.
248
+
249
+ For that shape, `experimental-a2/react` exports a standalone hook. Any
250
+ component can mount any session, no provider needed:
251
+
252
+ ```tsx app/orders/[orderId]/order-badge.tsx
253
+ 'use client'
254
+ import { useSession } from 'experimental-a2/react'
255
+ import { ordersClient } from './session'
256
+
257
+ export function OrderBadge({ orderId }: { orderId: string }) {
258
+ // your fetch (SWR, a router loader, a parent's payload): anything
259
+ // that lands the { state, index } your route returns (below), e.g.
260
+ // const { data } = useSWR(`/api/orders/${orderId}/state`)
261
+ const data = undefined // still loading
262
+
263
+ const { state } = useSession(ordersClient, orderId, { hydrate: data })
264
+ if (!data) return <span>…</span> // your loading state IS the pending state
265
+ return <span>{state.status}</span>
266
+ }
267
+ ```
268
+
269
+ The fold comes from your own route, and the route is one line of A2:
270
+
271
+ ```ts app/api/orders/[orderId]/state/route.ts
272
+ import { ordersServer } from '@/server/orders'
273
+ import { ordersReducer } from '@/reducer'
274
+
275
+ export async function GET(
276
+ _req: Request,
277
+ { params }: { params: Promise<{ orderId: string }> },
278
+ ) {
279
+ const { orderId } = await params
280
+ // here's where you'd do auth, or any other checks
281
+ return Response.json(
282
+ await ordersServer.session(orderId).state(ordersReducer),
283
+ )
284
+ }
285
+ ```
286
+
287
+ Note what is not on the wire: a reducer name. The route calls
288
+ `session.state(reducer)` with the reducer by reference, the same
289
+ module your client bundle folds with. That matters because renaming a
290
+ reducer is the [snapshot invalidation knob](/concepts/state): if the
291
+ name traveled on the wire, every rename would open a version-skew
292
+ window between deployed clients and servers. By reference, the knob
293
+ stays free. And unlike a history slice, which is immutable once read
294
+ and earns a standard wire shape, a state read is a moving snapshot;
295
+ there is nothing for the library to standardize, so the read stays
296
+ behind your route, under your auth and caching policy.
297
+
298
+ `hydrate` is one atomic option: the `{ state, index }` pair
299
+ `session.state(reducer)` returns. State and its frontier travel
300
+ together or not at all; a half-present handoff cannot compile. While
301
+ it is `undefined` (your fetch has not landed), the hook holds the
302
+ stream and `state` is the reducer's `initialState`. There is no
303
+ pending flag on the result: whether the fold has been handed over is
304
+ your own input, so your data layer's loading state is the pending
305
+ state. When the value arrives, the session hydrates
306
+ and the stream connects at that frontier. The hold is deliberate:
307
+ connecting without a fold means replaying the whole log through the
308
+ browser, and the library never picks the expensive path silently. When
309
+ a full replay is what you want (a short log, a debug view), hand the
310
+ fold's true starting point:
311
+ `hydrate: { state: ordersReducer.initialState, index: 0 }`. State at
312
+ index 0 is the reducer's seed by definition, so the explicit replay
313
+ needs no special vocabulary; the stream then delivers every event
314
+ live.
315
+
316
+ The rest behaves like the provider. The handle is identity-mapped
317
+ (every hook and provider mounting the same session shares one runtime)
318
+ and each mount holds a lease on the shared stream (see
319
+ [the client identity note](#the-client-component)). A later, further
320
+ fold handed to the same session
321
+ advances it and a stale one is ignored, the same never-move-backward
322
+ rule as everywhere else. For presence, identity comes from the
323
+ client's `participant` (set once on `createClient`) or the hook's
324
+ `participant` option, which overrides it. The
325
+ result is exactly the shape the bound hook returns. There is no
326
+ loading or error member: the
327
+ library performs no fetch here, so your data layer's states are the
328
+ states, retried however your data layer retries.
329
+
330
+ `SessionProvider` keeps its required `initialState`/`initialIndex`.
331
+ The provider is the server-handoff tool; the hook is the client-first
332
+ tool.
333
+
237
334
  ## Keep the backend out of the bundle
238
335
 
239
336
  The split is structural, not disciplinary. Core `experimental-a2` (the contract,
@@ -94,8 +94,11 @@ presence-only push acks `[]`.
94
94
 
95
95
  ## The browser
96
96
 
97
- The provider takes a `participant` id (yours to mint: a user id, a tab
98
- nonce, the playground's guest name). The hook grows two members. The
97
+ Presence needs a `participant` id (yours to mint: a user id, a tab
98
+ nonce, the playground's guest name). State it once on
99
+ `createClient({ participant })` when the app knows it at module scope,
100
+ or pass it to the provider, whose `participant` prop overrides the
101
+ client's. The hook grows two members. The
99
102
  session module is the usual pair from
100
103
  [Live UI](/guides/react#the-session-module), bound to a reducer that
101
104
  carries the canvas contract:
@@ -650,7 +650,7 @@ transition and the destination should adopt the same optimistic session.
650
650
  | `initialState` | server-rendered state |
651
651
  | `initialIndex` | the fold's frontier, where the stream resumes |
652
652
  | `initialEvents` | optional earlier raw events for a history UI |
653
- | `participant` | this client's presence identity; required to call `setPresence` |
653
+ | `participant` | overrides the client's `participant`; one of the two is required to call `setPresence` |
654
654
 
655
655
  Opens the stream on mount, closes it on unmount, reconnects with
656
656
  backoff from the current frontier. `participant` binds at the session's
@@ -706,8 +706,9 @@ invert). No ack, no `confirmed`, no retry.
706
706
  Both members exist only when the contract declares `presence`; their
707
707
  value and field types come from its schemas, through the reducer, with
708
708
  no type arguments (the reducer is the client's typed handle on the
709
- contract; it still never folds presence). `setPresence` requires the
710
- provider's `participant`. If the map holds only your own echo with
709
+ contract; it still never folds presence). `setPresence` requires a
710
+ `participant`: the client's default, or the provider's override. If
711
+ the map holds only your own echo with
711
712
  participants active, the GET route forgot `presence: true`. See
712
713
  [Presence](/guides/presence).
713
714
 
@@ -754,6 +755,37 @@ connection as dead (aborts it and reconnects), so `live` means bytes
754
755
  are actually flowing, not "the socket hasn't errored yet". See
755
756
  [Live UI](/guides/react).
756
757
 
758
+ ### `useSession(client, sessionId, options?)`
759
+
760
+ ```ts
761
+ useSession(client: A2Client, sessionId: string, options?: {
762
+ participant?: string // overrides the client's participant
763
+ hydrate?: { state: S; index: number }
764
+ }): UseSessionResult
765
+ ```
766
+
767
+ The standalone, provider-less hook. It returns the same result shape
768
+ as the bound hook, for apps whose components reach sessions ad hoc (a
769
+ sidebar of channel sessions, a user session read from a menu). The
770
+ handle is identity-mapped: every hook and provider mounting the same
771
+ session shares one runtime. The stream is refcounted: the first mount
772
+ connects, the last unmount closes (StrictMode-safe).
773
+
774
+ `hydrate` is the hydration input, one atomic option: the
775
+ `{ state, index }` pair `session.state(reducer)` returns, fetched by
776
+ your app through its own route and handed over whenever it lands.
777
+ While it is `undefined`, the hook holds the stream (connecting without
778
+ a fold would replay the whole log). There is no pending flag on the
779
+ result: whether the fold has been handed over is your own input, so
780
+ your data layer's loading state is the pending state.
781
+ When it arrives, the session hydrates under the usual
782
+ never-move-backward rule and the stream connects at that frontier.
783
+ For a deliberate full replay, hand the fold's true starting point:
784
+ `{ state: reducer.initialState, index: 0 }`. State at index 0 is the
785
+ reducer's seed by definition, so the explicit replay needs no special
786
+ vocabulary. See
787
+ [Client-first sessions](/guides/react#client-first-sessions).
788
+
757
789
  ## `experimental-a2/ai`
758
790
 
759
791
  ### `agent(options)`
@@ -1035,6 +1067,7 @@ createClient(options: {
1035
1067
  reducer: Reducer
1036
1068
  api: ClientApi
1037
1069
  gcTime?: number // idle session lifetime; 5 minutes by default
1070
+ participant?: string // default presence identity for every session
1038
1071
  }): A2Client
1039
1072
 
1040
1073
  type ClientApi =
@@ -1049,11 +1082,19 @@ queue with ack/rollback, and the local fold. `client.session(id, {
1049
1082
  initialState?, initialIndex?, initialEvents?, participant? })` returns a
1050
1083
  handle with `getSnapshot()`/`subscribe()` (the `useSyncExternalStore`
1051
1084
  contract), `push()`, `loadHistory()`, `connect()`, and `close()`.
1085
+ `connect()` takes a lease on the live stream and returns its release:
1086
+ leases refcount per handle (the first connects, releasing the last
1087
+ closes, releasing twice is a no-op), so independent consumers of one
1088
+ identity-mapped handle never fight over the stream. `close()` is the
1089
+ hard stop: it drops every outstanding lease and closes now; a later
1090
+ `connect()` starts fresh.
1052
1091
  Snapshots carry `state`, `events`, `index`, `history`, and `connection`
1053
1092
  (the same fields `useSession` exposes), and `push` returns the same
1054
1093
  ack-then-`confirmed` result. On contracts that declare `presence` the handle also carries
1055
1094
  `setPresence()` and snapshots carry the `presence` map, exactly like
1056
- the hook; `participant` is the identity `setPresence` sends under. Use
1095
+ the hook; `participant` is the identity `setPresence` sends under:
1096
+ stated once on `createClient` as the default for every handle, or per
1097
+ session as the override. Use
1057
1098
  it directly from any other framework, or none.
1058
1099
 
1059
1100
  Within one `A2Client`, repeated `session(id)` calls return the same live
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "experimental-a2",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Durable sync and reactions for things with a lifecycle: one event log, derived state, and live client per session.",
5
5
  "license": "MIT",
6
6
  "type": "module",