experimental-a2 0.23.0 → 0.24.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 (118) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{actor-CqibLgjQ.d.ts → actor-Bqyb7gwf.d.ts} +3 -3
  3. package/dist/{actor-CqibLgjQ.d.ts.map → actor-Bqyb7gwf.d.ts.map} +1 -1
  4. package/dist/actor-client.d.ts +1 -1
  5. package/dist/actor-client.js +2 -2
  6. package/dist/actor-react.d.ts +2 -2
  7. package/dist/actor-react.js +5 -5
  8. package/dist/{actor-shared-DFET5q16.js → actor-shared-B4OB6Qo7.js} +3 -3
  9. package/dist/{actor-shared-DFET5q16.js.map → actor-shared-B4OB6Qo7.js.map} +1 -1
  10. package/dist/actor.d.ts +1 -1
  11. package/dist/actor.js +4 -4
  12. package/dist/{ai-DAu77CDr.d.ts → ai-BZUu5-b7.d.ts} +2 -2
  13. package/dist/{ai-DAu77CDr.d.ts.map → ai-BZUu5-b7.d.ts.map} +1 -1
  14. package/dist/{ai-EEfKyc-z.js → ai-CCCNxd3L.js} +3 -3
  15. package/dist/{ai-EEfKyc-z.js.map → ai-CCCNxd3L.js.map} +1 -1
  16. package/dist/ai-client.d.ts +2 -2
  17. package/dist/ai-client.js +2 -2
  18. package/dist/ai-fx.d.ts +1 -1
  19. package/dist/{ai-harness-DTjkAr2T.d.ts → ai-harness-C8aV869s.d.ts} +2 -2
  20. package/dist/{ai-harness-DTjkAr2T.d.ts.map → ai-harness-C8aV869s.d.ts.map} +1 -1
  21. package/dist/ai-pi.d.ts +1 -1
  22. package/dist/ai-react.d.ts +4 -4
  23. package/dist/ai-react.js +2 -2
  24. package/dist/ai-server.d.ts +3 -3
  25. package/dist/ai-server.js +4 -4
  26. package/dist/ai.d.ts +1 -1
  27. package/dist/ai.js +1 -1
  28. package/dist/{client-CUMbS_38.d.ts → client-CCJASjUM.d.ts} +2 -2
  29. package/dist/{client-CUMbS_38.d.ts.map → client-CCJASjUM.d.ts.map} +1 -1
  30. package/dist/{client-BQS4i_V9.js → client-sq-djxhD.js} +4 -4
  31. package/dist/{client-BQS4i_V9.js.map → client-sq-djxhD.js.map} +1 -1
  32. package/dist/client.d.ts +2 -2
  33. package/dist/client.js +1 -1
  34. package/dist/{contract-CWukt01d.js → contract-DqfBSIqJ.js} +2 -2
  35. package/dist/{contract-CWukt01d.js.map → contract-DqfBSIqJ.js.map} +1 -1
  36. package/dist/index.d.ts +3 -3
  37. package/dist/index.js +3 -3
  38. package/dist/{initial-snapshot-D3Lve43o.d.ts → initial-snapshot-BA6xwv10.d.ts} +2 -2
  39. package/dist/initial-snapshot-BA6xwv10.d.ts.map +1 -0
  40. package/dist/{react-BoHvC3v9.d.ts → react-KC4eW7yG.d.ts} +3 -3
  41. package/dist/{react-BoHvC3v9.d.ts.map → react-KC4eW7yG.d.ts.map} +1 -1
  42. package/dist/react.d.ts +1 -1
  43. package/dist/react.js +1 -1
  44. package/dist/{reducer-CjmvZSAb.js → reducer-Bswr11ar.js} +2 -2
  45. package/dist/{reducer-CjmvZSAb.js.map → reducer-Bswr11ar.js.map} +1 -1
  46. package/dist/scheduler-qstash.d.ts +2 -2
  47. package/dist/scheduler-qstash.js +2 -2
  48. package/dist/scheduler-vercel.d.ts +2 -2
  49. package/dist/scheduler-vercel.js +1 -1
  50. package/dist/{server-qgez0Xny.d.ts → server-B9gu0qi1.d.ts} +9 -3
  51. package/dist/server-B9gu0qi1.d.ts.map +1 -0
  52. package/dist/{server-DtFrWxi3.js → server-DX7mM6nm.js} +22 -14
  53. package/dist/server-DX7mM6nm.js.map +1 -0
  54. package/dist/server.d.ts +2 -2
  55. package/dist/server.js +1 -1
  56. package/dist/{session-clear-wHd5GCpZ.js → session-clear-XJYpmUpg.js} +14 -2
  57. package/dist/session-clear-XJYpmUpg.js.map +1 -0
  58. package/dist/{session-clear-D1PFe7xl.d.ts → session-clear-vfonou9S.d.ts} +2 -2
  59. package/dist/session-clear-vfonou9S.d.ts.map +1 -0
  60. package/dist/{store-D0MhBvg6.d.ts → store-DEzcHZOA.d.ts} +11 -1
  61. package/dist/store-DEzcHZOA.d.ts.map +1 -0
  62. package/dist/store-N8PXxDAS.js.map +1 -1
  63. package/dist/{store-codec-DwrWlgQx.js → store-codec-pAG2oPgQ.js} +4 -4
  64. package/dist/store-codec-pAG2oPgQ.js.map +1 -0
  65. package/dist/store-memory.d.ts +1 -1
  66. package/dist/store-memory.d.ts.map +1 -1
  67. package/dist/store-memory.js +11 -4
  68. package/dist/store-memory.js.map +1 -1
  69. package/dist/store-postgres.d.ts +1 -1
  70. package/dist/store-postgres.d.ts.map +1 -1
  71. package/dist/store-postgres.js +26 -7
  72. package/dist/store-postgres.js.map +1 -1
  73. package/dist/store-redis-http.d.ts +1 -1
  74. package/dist/store-redis-http.js +2 -2
  75. package/dist/{store-redis-notify-CBDVJxA_.js → store-redis-notify-ys_-VrSP.js} +27 -16
  76. package/dist/store-redis-notify-ys_-VrSP.js.map +1 -0
  77. package/dist/store-redis.d.ts +1 -1
  78. package/dist/store-redis.js +2 -2
  79. package/dist/store-sqlite.d.ts +1 -1
  80. package/dist/store-sqlite.d.ts.map +1 -1
  81. package/dist/store-sqlite.js +11 -4
  82. package/dist/store-sqlite.js.map +1 -1
  83. package/dist/store-valkey.d.ts +1 -1
  84. package/dist/store-valkey.js +2 -2
  85. package/dist/{wire-CV-Z7wz-.js → wire-BFE9sIQf.js} +3 -2
  86. package/dist/wire-BFE9sIQf.js.map +1 -0
  87. package/docs/contract/03-sessions.mdx +51 -0
  88. package/docs/reference/02-server.mdx +44 -4
  89. package/docs/reference/06-errors.mdx +1 -0
  90. package/examples/playground/app/a2slack/consumers/search.ts +1 -1
  91. package/examples/playground/app/a2slack/db/migrations/0005_a2slack_feed_v2.sql +7 -0
  92. package/examples/playground/app/a2slack/db/migrations/meta/0005_snapshot.json +1165 -0
  93. package/examples/playground/app/a2slack/db/migrations/meta/_journal.json +8 -1
  94. package/examples/playground/app/a2slack/db/queries.ts +1 -1
  95. package/examples/playground/app/a2slack/drills/a2slack.drill.ts +17 -14
  96. package/examples/playground/app/a2slack/search-index.ts +1 -1
  97. package/examples/playground/app/a2slack/server.ts +2 -2
  98. package/examples/playground/lib/store.ts +2 -0
  99. package/examples/playground/package.json +1 -1
  100. package/package.json +1 -1
  101. package/src/errors.ts +39 -0
  102. package/src/idempotent-replay.ts +4 -3
  103. package/src/server.ts +32 -9
  104. package/src/store-memory.ts +26 -4
  105. package/src/store-postgres.ts +36 -6
  106. package/src/store-redis-core.ts +40 -15
  107. package/src/store-sqlite.ts +25 -4
  108. package/src/store.ts +10 -0
  109. package/src/wire.ts +1 -0
  110. package/dist/initial-snapshot-D3Lve43o.d.ts.map +0 -1
  111. package/dist/server-DtFrWxi3.js.map +0 -1
  112. package/dist/server-qgez0Xny.d.ts.map +0 -1
  113. package/dist/session-clear-D1PFe7xl.d.ts.map +0 -1
  114. package/dist/session-clear-wHd5GCpZ.js.map +0 -1
  115. package/dist/store-D0MhBvg6.d.ts.map +0 -1
  116. package/dist/store-codec-DwrWlgQx.js.map +0 -1
  117. package/dist/store-redis-notify-CBDVJxA_.js.map +0 -1
  118. package/dist/wire-CV-Z7wz-.js.map +0 -1
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { i as StateSnapshot } from "./reducer-CYPHsSmd.js";
2
- import { t as InitialSnapshot } from "./initial-snapshot-D3Lve43o.js";
3
- import { _ as createClient, a as Connection, c as HistoryState, d as ReconnectPolicy, f as SessionClient, g as SessionUrl, h as SessionSnapshot, i as ClientWebSocketConstructor, l as LoadHistoryOptions, m as SessionOptions, n as ClientApi, o as ConnectionStatus, p as SessionClientPresence, r as ClientWebSocket, s as CreateClientOptions, t as A2Client, u as PushResult, v as A2ClientError, y as A2ClientErrorOptions } from "./client-CUMbS_38.js";
2
+ import { t as InitialSnapshot } from "./initial-snapshot-BA6xwv10.js";
3
+ import { _ as createClient, a as Connection, c as HistoryState, d as ReconnectPolicy, f as SessionClient, g as SessionUrl, h as SessionSnapshot, i as ClientWebSocketConstructor, l as LoadHistoryOptions, m as SessionOptions, n as ClientApi, o as ConnectionStatus, p as SessionClientPresence, r as ClientWebSocket, s as CreateClientOptions, t as A2Client, u as PushResult, v as A2ClientError, y as A2ClientErrorOptions } from "./client-CCJASjUM.js";
4
4
  export { A2Client, A2ClientError, type A2ClientErrorOptions, ClientApi, ClientWebSocket, ClientWebSocketConstructor, Connection, ConnectionStatus, CreateClientOptions, HistoryState, type InitialSnapshot, LoadHistoryOptions, PushResult, ReconnectPolicy, SessionClient, SessionClientPresence, SessionOptions, SessionSnapshot, SessionUrl, type StateSnapshot, createClient };
package/dist/client.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as A2ClientError, t as createClient } from "./client-BQS4i_V9.js";
1
+ import { a as A2ClientError, t as createClient } from "./client-sq-djxhD.js";
2
2
  export { A2ClientError, createClient };
@@ -1,4 +1,4 @@
1
- import { i as makeReducerBuilder, o as assertSyncSchema } from "./reducer-CjmvZSAb.js";
1
+ import { i as makeReducerBuilder, o as assertSyncSchema } from "./reducer-Bswr11ar.js";
2
2
  //#region src/contract.ts
3
3
  function contract(options) {
4
4
  for (const type of Object.keys(options.events ?? {})) if (type.startsWith("a2.")) throw new TypeError(`contract '${String(options.name)}': event types starting with 'a2.' are reserved`);
@@ -36,4 +36,4 @@ function defineContract(options) {
36
36
  //#endregion
37
37
  export { internalContract as n, contract as t };
38
38
 
39
- //# sourceMappingURL=contract-CWukt01d.js.map
39
+ //# sourceMappingURL=contract-DqfBSIqJ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract-CWukt01d.js","names":[],"sources":["../src/contract.ts"],"sourcesContent":["import {\n makeReducerBuilder,\n type Reducer,\n type RegisteredReducer,\n} from './reducer.ts'\nimport { RESERVED_EVENT_PREFIX } from './session-clear.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport { assertSyncSchema } from './validate.ts'\n\n/** The event vocabulary shape: event name → payload schema. */\nexport type EventDefs = Record<string, StandardSchemaV1>\n\n/** The presence vocabulary shape: field name → value schema. */\nexport type PresenceDefs = Record<string, StandardSchemaV1>\n\n/** One event of a contract, narrowed to type `K`. */\nexport type ContractEvent<\n D extends EventDefs,\n K extends keyof D & string = keyof D & string,\n> = {\n [T in keyof D & string]: {\n id: string\n type: T\n payload: StandardSchemaV1.InferOutput<D[T]>\n index: number\n sessionId: string\n createdAt: Date\n }\n}[K]\n\n/** Input to `append`/`push`, typed against the contract's schemas. */\nexport type AppendInput<D extends EventDefs> = {\n [T in keyof D & string]: {\n type: T\n payload: StandardSchemaV1.InferInput<D[T]>\n id?: string\n }\n}[keyof D & string]\n\nexport type EventBatchFactory<D extends EventDefs> = <\n const E extends readonly AppendInput<D>[],\n>(\n ...events: E\n) => E\n\n/**\n * One presence update: a participant's changed fields (`null` marks a\n * cleared one), stamped with the sender's stream frontier (`seen`).\n * This is what `stream({ presence: true })` interleaves with events.\n */\nexport type PresencePatch<P extends PresenceDefs = PresenceDefs> = {\n participant: string\n values: {\n [F in keyof P & string]?: StandardSchemaV1.InferOutput<P[F]> | null\n }\n seen: number\n at: Date\n}\n\n/**\n * The replicated ephemeral map: participant → field → latest value,\n * last-writer-wins per field. Never stored in the log; how long a\n * value stays painted is view logic, decided at render time against\n * `at`.\n */\nexport type PresenceMap<P extends PresenceDefs = PresenceDefs> = {\n [participant: string]: {\n [F in keyof P & string]?: {\n value: StandardSchemaV1.InferOutput<P[F]>\n seen: number\n at: Date\n }\n }\n}\n\n/**\n * The one item a presence stream yields before live patches: the\n * current pruned map, per-field stamps exact. Discriminate\n * structurally (`'snapshot' in item`).\n */\nexport type PresenceSnapshot<P extends PresenceDefs = PresenceDefs> = {\n snapshot: PresenceMap<P>\n}\n\n/**\n * Intersect into a surface type to add `Members` only when the\n * contract declares presence fields — on presence-less contracts the\n * members do not exist, a type error rather than a runtime throw.\n */\nexport type WithPresence<\n P extends PresenceDefs,\n Members,\n> = keyof P extends never ? unknown : Members\n\nexport type ReducerOptions<Seed, S> = {\n /**\n * Identity and snapshot cache key. Rename it when the fold's logic\n * changes — snapshots under the old name are ignored and refolded.\n */\n name: string\n /**\n * The seed the fold starts from. With a `stateSchema`, it's typed as\n * the schema's *input*: validated at definition, and the validated\n * output (defaults applied) is what the fold actually starts from.\n */\n initialState: Seed\n /**\n * Optional: declares the state's shape (the fold's state type becomes\n * the schema's output) and guards cached folds — server snapshots and\n * the browser cache reject mismatching shapes and refold.\n */\n stateSchema?: StandardSchemaV1<Seed, S>\n}\n\nexport type Contract<\n D extends EventDefs = EventDefs,\n P extends PresenceDefs = Record<never, never>,\n R = RegisteredReducer<D, P> | undefined,\n> = {\n /** Identity — prefixes storage keys and queue messages. */\n readonly name: string\n /** The vocabulary. */\n readonly events: Readonly<D>\n /** The presence vocabulary — empty unless declared. */\n readonly presence: Readonly<P>\n /** Preserve literal types for a consumer-returned event batch. */\n readonly batch: EventBatchFactory<D>\n readonly reducer: R\n}\n\n/**\n * Define a contract: a name plus the events it understands. Validators\n * must be synchronous — async ones are rejected here, at definition\n * time. The result is a plain, importable, isomorphic value.\n */\ntype ContractOptions<D extends EventDefs, P extends PresenceDefs> = {\n name: string\n events: D\n presence?: P\n}\n\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n Schema extends StandardSchemaV1 = StandardSchemaV1,\n>(\n options: ContractOptions<D, P> & {\n reducer: {\n name: string\n initialState: StandardSchemaV1.InferInput<NoInfer<Schema>>\n stateSchema: Schema\n fold: (\n state: StandardSchemaV1.InferOutput<Schema>,\n event: ContractEvent<NoInfer<D>>,\n ) => StandardSchemaV1.InferOutput<Schema>\n }\n },\n): Contract<D, P, Reducer<D, StandardSchemaV1.InferOutput<Schema>, P>>\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n S = unknown,\n>(\n options: ContractOptions<D, P> & {\n reducer: {\n name: string\n initialState: S\n fold: (state: NoInfer<S>, event: ContractEvent<NoInfer<D>>) => NoInfer<S>\n }\n },\n): Contract<D, P, Reducer<D, S, P>>\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n R extends RegisteredReducer<D, P> = RegisteredReducer<D, P>,\n>(options: ContractOptions<D, P> & { reducer: R }): Contract<D, P, R>\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n>(\n options: ContractOptions<D, P> & { reducer?: undefined },\n): Contract<D, P, undefined>\nexport function contract(options: AnyContractOptions): unknown {\n for (const type of Object.keys(options.events ?? {})) {\n if (type.startsWith(RESERVED_EVENT_PREFIX)) {\n throw new TypeError(\n `contract '${String(options.name)}': event types starting with '${RESERVED_EVENT_PREFIX}' are reserved`,\n )\n }\n }\n return defineContract(options)\n}\n\n/** A2's own contracts, which may declare reserved `a2.` event types. */\nexport const internalContract: typeof contract =\n defineContract as typeof contract\n\ntype AnyContractOptions = ContractOptions<EventDefs, PresenceDefs> & {\n reducer?:\n | (ReducerOptions<unknown, unknown> & {\n fold: (state: never, event: never) => unknown\n })\n | undefined\n}\n\nfunction defineContract(options: AnyContractOptions): unknown {\n const { name } = options\n if (typeof name !== 'string' || name.length === 0) {\n throw new TypeError('contract name must be a non-empty string')\n }\n if (name.includes('\\u001f')) {\n throw new TypeError('contract name contains a reserved control character')\n }\n const defs = options.events\n for (const [type, schema] of Object.entries(defs)) {\n if (typeof schema?.['~standard']?.validate !== 'function') {\n throw new TypeError(\n `contract '${name}': the value for '${type}' is not a Standard Schema (expected an object with '~standard')`,\n )\n }\n assertSyncSchema(schema, `event '${type}'`)\n }\n const events = Object.freeze({ ...defs })\n\n const presenceDefs = options.presence ?? {}\n for (const [field, schema] of Object.entries(presenceDefs)) {\n if (typeof schema?.['~standard']?.validate !== 'function') {\n throw new TypeError(\n `contract '${name}': the value for presence field '${field}' is not a Standard Schema (expected an object with '~standard')`,\n )\n }\n assertSyncSchema(schema, `presence field '${field}'`)\n }\n const presence = Object.freeze({ ...presenceDefs })\n\n return {\n name,\n events,\n presence,\n batch: <const E extends readonly AppendInput<EventDefs>[]>(\n ...items: E\n ): E => items,\n reducer:\n options.reducer === undefined\n ? undefined\n : {\n ...options.reducer,\n ...makeReducerBuilder(events, presence, options.reducer).fold(\n options.reducer.fold as (\n state: unknown,\n event: ContractEvent<EventDefs>,\n ) => unknown,\n ),\n },\n }\n}\n"],"mappings":";;AAsLA,SAAgB,SAAS,SAAsC;CAC7D,KAAK,MAAM,QAAQ,OAAO,KAAK,QAAQ,UAAU,CAAC,CAAC,GACjD,IAAI,KAAK,WAAA,KAAgC,GACvC,MAAM,IAAI,UACR,aAAa,OAAO,QAAQ,IAAI,EAAE,gDACpC;CAGJ,OAAO,eAAe,OAAO;AAC/B;;AAGA,MAAa,mBACX;AAUF,SAAS,eAAe,SAAsC;CAC5D,MAAM,EAAE,SAAS;CACjB,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C,MAAM,IAAI,UAAU,0CAA0C;CAEhE,IAAI,KAAK,SAAS,GAAQ,GACxB,MAAM,IAAI,UAAU,qDAAqD;CAE3E,MAAM,OAAO,QAAQ;CACrB,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,IAAI,GAAG;EACjD,IAAI,OAAO,SAAS,YAAY,EAAE,aAAa,YAC7C,MAAM,IAAI,UACR,aAAa,KAAK,oBAAoB,KAAK,iEAC7C;EAEF,iBAAiB,QAAQ,UAAU,KAAK,EAAE;CAC5C;CACA,MAAM,SAAS,OAAO,OAAO,EAAE,GAAG,KAAK,CAAC;CAExC,MAAM,eAAe,QAAQ,YAAY,CAAC;CAC1C,KAAK,MAAM,CAAC,OAAO,WAAW,OAAO,QAAQ,YAAY,GAAG;EAC1D,IAAI,OAAO,SAAS,YAAY,EAAE,aAAa,YAC7C,MAAM,IAAI,UACR,aAAa,KAAK,mCAAmC,MAAM,iEAC7D;EAEF,iBAAiB,QAAQ,mBAAmB,MAAM,EAAE;CACtD;CACA,MAAM,WAAW,OAAO,OAAO,EAAE,GAAG,aAAa,CAAC;CAElD,OAAO;EACL;EACA;EACA;EACA,QACE,GAAG,UACG;EACR,SACE,QAAQ,YAAY,KAAA,IAChB,KAAA,IACA;GACE,GAAG,QAAQ;GACX,GAAG,mBAAmB,QAAQ,UAAU,QAAQ,OAAO,CAAC,CAAC,KACvD,QAAQ,QAAQ,IAIlB;EACF;CACR;AACF"}
1
+ {"version":3,"file":"contract-DqfBSIqJ.js","names":[],"sources":["../src/contract.ts"],"sourcesContent":["import {\n makeReducerBuilder,\n type Reducer,\n type RegisteredReducer,\n} from './reducer.ts'\nimport { RESERVED_EVENT_PREFIX } from './session-clear.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport { assertSyncSchema } from './validate.ts'\n\n/** The event vocabulary shape: event name → payload schema. */\nexport type EventDefs = Record<string, StandardSchemaV1>\n\n/** The presence vocabulary shape: field name → value schema. */\nexport type PresenceDefs = Record<string, StandardSchemaV1>\n\n/** One event of a contract, narrowed to type `K`. */\nexport type ContractEvent<\n D extends EventDefs,\n K extends keyof D & string = keyof D & string,\n> = {\n [T in keyof D & string]: {\n id: string\n type: T\n payload: StandardSchemaV1.InferOutput<D[T]>\n index: number\n sessionId: string\n createdAt: Date\n }\n}[K]\n\n/** Input to `append`/`push`, typed against the contract's schemas. */\nexport type AppendInput<D extends EventDefs> = {\n [T in keyof D & string]: {\n type: T\n payload: StandardSchemaV1.InferInput<D[T]>\n id?: string\n }\n}[keyof D & string]\n\nexport type EventBatchFactory<D extends EventDefs> = <\n const E extends readonly AppendInput<D>[],\n>(\n ...events: E\n) => E\n\n/**\n * One presence update: a participant's changed fields (`null` marks a\n * cleared one), stamped with the sender's stream frontier (`seen`).\n * This is what `stream({ presence: true })` interleaves with events.\n */\nexport type PresencePatch<P extends PresenceDefs = PresenceDefs> = {\n participant: string\n values: {\n [F in keyof P & string]?: StandardSchemaV1.InferOutput<P[F]> | null\n }\n seen: number\n at: Date\n}\n\n/**\n * The replicated ephemeral map: participant → field → latest value,\n * last-writer-wins per field. Never stored in the log; how long a\n * value stays painted is view logic, decided at render time against\n * `at`.\n */\nexport type PresenceMap<P extends PresenceDefs = PresenceDefs> = {\n [participant: string]: {\n [F in keyof P & string]?: {\n value: StandardSchemaV1.InferOutput<P[F]>\n seen: number\n at: Date\n }\n }\n}\n\n/**\n * The one item a presence stream yields before live patches: the\n * current pruned map, per-field stamps exact. Discriminate\n * structurally (`'snapshot' in item`).\n */\nexport type PresenceSnapshot<P extends PresenceDefs = PresenceDefs> = {\n snapshot: PresenceMap<P>\n}\n\n/**\n * Intersect into a surface type to add `Members` only when the\n * contract declares presence fields — on presence-less contracts the\n * members do not exist, a type error rather than a runtime throw.\n */\nexport type WithPresence<\n P extends PresenceDefs,\n Members,\n> = keyof P extends never ? unknown : Members\n\nexport type ReducerOptions<Seed, S> = {\n /**\n * Identity and snapshot cache key. Rename it when the fold's logic\n * changes — snapshots under the old name are ignored and refolded.\n */\n name: string\n /**\n * The seed the fold starts from. With a `stateSchema`, it's typed as\n * the schema's *input*: validated at definition, and the validated\n * output (defaults applied) is what the fold actually starts from.\n */\n initialState: Seed\n /**\n * Optional: declares the state's shape (the fold's state type becomes\n * the schema's output) and guards cached folds — server snapshots and\n * the browser cache reject mismatching shapes and refold.\n */\n stateSchema?: StandardSchemaV1<Seed, S>\n}\n\nexport type Contract<\n D extends EventDefs = EventDefs,\n P extends PresenceDefs = Record<never, never>,\n R = RegisteredReducer<D, P> | undefined,\n> = {\n /** Identity — prefixes storage keys and queue messages. */\n readonly name: string\n /** The vocabulary. */\n readonly events: Readonly<D>\n /** The presence vocabulary — empty unless declared. */\n readonly presence: Readonly<P>\n /** Preserve literal types for a consumer-returned event batch. */\n readonly batch: EventBatchFactory<D>\n readonly reducer: R\n}\n\n/**\n * Define a contract: a name plus the events it understands. Validators\n * must be synchronous — async ones are rejected here, at definition\n * time. The result is a plain, importable, isomorphic value.\n */\ntype ContractOptions<D extends EventDefs, P extends PresenceDefs> = {\n name: string\n events: D\n presence?: P\n}\n\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n Schema extends StandardSchemaV1 = StandardSchemaV1,\n>(\n options: ContractOptions<D, P> & {\n reducer: {\n name: string\n initialState: StandardSchemaV1.InferInput<NoInfer<Schema>>\n stateSchema: Schema\n fold: (\n state: StandardSchemaV1.InferOutput<Schema>,\n event: ContractEvent<NoInfer<D>>,\n ) => StandardSchemaV1.InferOutput<Schema>\n }\n },\n): Contract<D, P, Reducer<D, StandardSchemaV1.InferOutput<Schema>, P>>\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n S = unknown,\n>(\n options: ContractOptions<D, P> & {\n reducer: {\n name: string\n initialState: S\n fold: (state: NoInfer<S>, event: ContractEvent<NoInfer<D>>) => NoInfer<S>\n }\n },\n): Contract<D, P, Reducer<D, S, P>>\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n R extends RegisteredReducer<D, P> = RegisteredReducer<D, P>,\n>(options: ContractOptions<D, P> & { reducer: R }): Contract<D, P, R>\nexport function contract<\n D extends EventDefs,\n P extends PresenceDefs = Record<never, never>,\n>(\n options: ContractOptions<D, P> & { reducer?: undefined },\n): Contract<D, P, undefined>\nexport function contract(options: AnyContractOptions): unknown {\n for (const type of Object.keys(options.events ?? {})) {\n if (type.startsWith(RESERVED_EVENT_PREFIX)) {\n throw new TypeError(\n `contract '${String(options.name)}': event types starting with '${RESERVED_EVENT_PREFIX}' are reserved`,\n )\n }\n }\n return defineContract(options)\n}\n\n/** A2's own contracts, which may declare reserved `a2.` event types. */\nexport const internalContract: typeof contract =\n defineContract as typeof contract\n\ntype AnyContractOptions = ContractOptions<EventDefs, PresenceDefs> & {\n reducer?:\n | (ReducerOptions<unknown, unknown> & {\n fold: (state: never, event: never) => unknown\n })\n | undefined\n}\n\nfunction defineContract(options: AnyContractOptions): unknown {\n const { name } = options\n if (typeof name !== 'string' || name.length === 0) {\n throw new TypeError('contract name must be a non-empty string')\n }\n if (name.includes('\\u001f')) {\n throw new TypeError('contract name contains a reserved control character')\n }\n const defs = options.events\n for (const [type, schema] of Object.entries(defs)) {\n if (typeof schema?.['~standard']?.validate !== 'function') {\n throw new TypeError(\n `contract '${name}': the value for '${type}' is not a Standard Schema (expected an object with '~standard')`,\n )\n }\n assertSyncSchema(schema, `event '${type}'`)\n }\n const events = Object.freeze({ ...defs })\n\n const presenceDefs = options.presence ?? {}\n for (const [field, schema] of Object.entries(presenceDefs)) {\n if (typeof schema?.['~standard']?.validate !== 'function') {\n throw new TypeError(\n `contract '${name}': the value for presence field '${field}' is not a Standard Schema (expected an object with '~standard')`,\n )\n }\n assertSyncSchema(schema, `presence field '${field}'`)\n }\n const presence = Object.freeze({ ...presenceDefs })\n\n return {\n name,\n events,\n presence,\n batch: <const E extends readonly AppendInput<EventDefs>[]>(\n ...items: E\n ): E => items,\n reducer:\n options.reducer === undefined\n ? undefined\n : {\n ...options.reducer,\n ...makeReducerBuilder(events, presence, options.reducer).fold(\n options.reducer.fold as (\n state: unknown,\n event: ContractEvent<EventDefs>,\n ) => unknown,\n ),\n },\n }\n}\n"],"mappings":";;AAsLA,SAAgB,SAAS,SAAsC;CAC7D,KAAK,MAAM,QAAQ,OAAO,KAAK,QAAQ,UAAU,CAAC,CAAC,GACjD,IAAI,KAAK,WAAA,KAAgC,GACvC,MAAM,IAAI,UACR,aAAa,OAAO,QAAQ,IAAI,EAAE,gDACpC;CAGJ,OAAO,eAAe,OAAO;AAC/B;;AAGA,MAAa,mBACX;AAUF,SAAS,eAAe,SAAsC;CAC5D,MAAM,EAAE,SAAS;CACjB,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C,MAAM,IAAI,UAAU,0CAA0C;CAEhE,IAAI,KAAK,SAAS,GAAQ,GACxB,MAAM,IAAI,UAAU,qDAAqD;CAE3E,MAAM,OAAO,QAAQ;CACrB,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,IAAI,GAAG;EACjD,IAAI,OAAO,SAAS,YAAY,EAAE,aAAa,YAC7C,MAAM,IAAI,UACR,aAAa,KAAK,oBAAoB,KAAK,iEAC7C;EAEF,iBAAiB,QAAQ,UAAU,KAAK,EAAE;CAC5C;CACA,MAAM,SAAS,OAAO,OAAO,EAAE,GAAG,KAAK,CAAC;CAExC,MAAM,eAAe,QAAQ,YAAY,CAAC;CAC1C,KAAK,MAAM,CAAC,OAAO,WAAW,OAAO,QAAQ,YAAY,GAAG;EAC1D,IAAI,OAAO,SAAS,YAAY,EAAE,aAAa,YAC7C,MAAM,IAAI,UACR,aAAa,KAAK,mCAAmC,MAAM,iEAC7D;EAEF,iBAAiB,QAAQ,mBAAmB,MAAM,EAAE;CACtD;CACA,MAAM,WAAW,OAAO,OAAO,EAAE,GAAG,aAAa,CAAC;CAElD,OAAO;EACL;EACA;EACA;EACA,QACE,GAAG,UACG;EACR,SACE,QAAQ,YAAY,KAAA,IAChB,KAAA,IACA;GACE,GAAG,QAAQ;GACX,GAAG,mBAAmB,QAAQ,UAAU,QAAQ,OAAO,CAAC,CAAC,KACvD,QAAQ,QAAQ,IAIlB;EACF;CACR;AACF"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { _ as contract, a as reducer, c as ContractEvent, d as PresenceDefs, f as PresenceMap, h as ReducerOptions, i as StateSnapshot, l as EventBatchFactory, m as PresenceSnapshot, n as ReducerBuilder, o as AppendInput, p as PresencePatch, s as Contract, t as Reducer, u as EventDefs, v as StandardSchemaV1 } from "./reducer-CYPHsSmd.js";
2
- import { a as NonRetriableError, i as A2ServerErrorCode, n as A2Error, r as A2ErrorCode, t as InitialSnapshot } from "./initial-snapshot-D3Lve43o.js";
3
- import { i as Event } from "./store-D0MhBvg6.js";
4
- import { t as SessionCleared } from "./session-clear-D1PFe7xl.js";
2
+ import { a as NonRetriableError, i as A2ServerErrorCode, n as A2Error, r as A2ErrorCode, t as InitialSnapshot } from "./initial-snapshot-BA6xwv10.js";
3
+ import { i as Event } from "./store-DEzcHZOA.js";
4
+ import { t as SessionCleared } from "./session-clear-vfonou9S.js";
5
5
  import { i as A2Telemetry, n as A2SpanHandle, r as A2SpanName, t as A2AttributeValue } from "./telemetry-CWwsh-Gx.js";
6
6
  //#region src/idempotent-id.d.ts
7
7
  declare function idempotentId(...parts: string[]): Promise<string>;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as NonRetriableError, i as A2Error } from "./session-clear-wHd5GCpZ.js";
2
- import { a as reducer } from "./reducer-CjmvZSAb.js";
3
- import { t as contract } from "./contract-CWukt01d.js";
1
+ import { a as NonRetriableError, i as A2Error } from "./session-clear-XJYpmUpg.js";
2
+ import { a as reducer } from "./reducer-Bswr11ar.js";
3
+ import { t as contract } from "./contract-DqfBSIqJ.js";
4
4
  import { t as idempotentId } from "./idempotent-id-BRJVeylj.js";
5
5
  export { A2Error, NonRetriableError, contract, idempotentId, reducer };
@@ -1,6 +1,6 @@
1
1
  import { i as StateSnapshot } from "./reducer-CYPHsSmd.js";
2
2
  //#region src/errors.d.ts
3
- type A2ServerErrorCode = "INVALID_PAYLOAD" | "FORBIDDEN" | "UNKNOWN_EVENT_TYPE" | "PARTIAL_DUPLICATE_BATCH" | "SUPERSEDED_ATTEMPT" | "SESSION_CLEARED" | "CLAIM_EXPIRED" | "STORE_UNAVAILABLE" | "STORE_NOT_CONFIGURED" | "UNKNOWN_PRESENCE_FIELD" | "PRESENCE_NOT_SUPPORTED" | "CONSUMER_DEAD_LETTERED";
3
+ type A2ServerErrorCode = "INVALID_PAYLOAD" | "FORBIDDEN" | "UNKNOWN_EVENT_TYPE" | "PARTIAL_DUPLICATE_BATCH" | "SUPERSEDED_ATTEMPT" | "SESSION_CLEARED" | "LAST_INDEX_MISMATCH" | "CLAIM_EXPIRED" | "STORE_UNAVAILABLE" | "STORE_NOT_CONFIGURED" | "UNKNOWN_PRESENCE_FIELD" | "PRESENCE_NOT_SUPPORTED" | "CONSUMER_DEAD_LETTERED";
4
4
  type A2ErrorCode = A2ServerErrorCode | "TIMEOUT" | "HTTP_ERROR" | "CONNECTION_FAILED" | "UNKNOWN";
5
5
  declare class A2Error extends Error {
6
6
  readonly code: A2ErrorCode;
@@ -29,4 +29,4 @@ declare class NonRetriableError extends Error {
29
29
  type InitialSnapshot<S> = StateSnapshot<S> | null | undefined | Promise<StateSnapshot<S> | null | undefined>;
30
30
  //#endregion
31
31
  export { NonRetriableError as a, A2ServerErrorCode as i, A2Error as n, A2ErrorCode as r, InitialSnapshot as t };
32
- //# sourceMappingURL=initial-snapshot-D3Lve43o.d.ts.map
32
+ //# sourceMappingURL=initial-snapshot-BA6xwv10.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initial-snapshot-BA6xwv10.d.ts","names":[],"sources":["../src/errors.ts","../src/initial-snapshot.ts"],"mappings":";;KAAY;KAeA,cACV;cAEW,gBAAgB;WAClB,MAAM;;WAEN;EAET,YACE,MAAM,aACN,iBACA;IAAY;IAAmB;;;;;;;;;;;cAmFtB,0BAA0B;EACrC,YAAY,iBAAiB;IAAY;;;;;KC5G/B,gBAAgB,KACxB,cAAc,wBAGd,QAAQ,cAAc"}
@@ -1,6 +1,6 @@
1
1
  import { c as ContractEvent, d as PresenceDefs, f as PresenceMap, g as WithPresence, o as AppendInput, p as PresencePatch, s as Contract, t as Reducer, u as EventDefs } from "./reducer-CYPHsSmd.js";
2
- import { t as InitialSnapshot } from "./initial-snapshot-D3Lve43o.js";
3
- import { a as Connection, c as HistoryState, l as LoadHistoryOptions, t as A2Client, u as PushResult } from "./client-CUMbS_38.js";
2
+ import { t as InitialSnapshot } from "./initial-snapshot-BA6xwv10.js";
3
+ import { a as Connection, c as HistoryState, l as LoadHistoryOptions, t as A2Client, u as PushResult } from "./client-CCJASjUM.js";
4
4
  import { ReactElement, ReactNode } from "react";
5
5
  //#region src/react.d.ts
6
6
  type UseSessionOptions<S> = {
@@ -83,4 +83,4 @@ declare function createReact<D extends EventDefs, S, P extends PresenceDefs = Re
83
83
  declare function useSession<D extends EventDefs, S, P extends PresenceDefs = Record<never, never>>(client: A2Client<D, S, P>, sessionId: string, options?: UseSessionOptions<NoInfer<S>>): UseSessionResult<D, S, P>;
84
84
  //#endregion
85
85
  export { SessionProviderProps as a, UseSessionResult as c, BoundSessionProviderProps as i, createReact as l, BoundA2React as n, UseSessionOptions as o, BoundSessionOptions as r, UseSessionPresence as s, A2React as t, useSession as u };
86
- //# sourceMappingURL=react-BoHvC3v9.d.ts.map
86
+ //# sourceMappingURL=react-KC4eW7yG.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react-BoHvC3v9.d.ts","names":[],"sources":["../src/react.ts"],"mappings":";;;;;KAwCY,kBAAkB;EAC5B;EACA,UAAU,gBAAgB;EAC1B;EACA;;KAGU,qBAAqB,UAAU,WAAW;EACpD;EACA;EACA,UAAU,gBAAgB;EAC1B,gBAAgB,cAAc;EAC9B;EACA,WAAW;;KAGD,0BAA0B,UAAU,WAAW,KAAK,KAC9D,qBAAqB,GAAG;KAId,mBAAmB,UAAU;;EAEvC,UAAU,YAAY;;;;;;;;EAQtB,cAAc,QAAQ,cAAc;;KAG1B,iBACV,UAAU,WACV,GACA,UAAU,eAAe,wBACvB,aAAa,GAAG,mBAAmB;;EAErC,OAAO;;EAEP;;EAEA,QAAQ,cAAc;;EAEtB;;;;;;EAMA,YAAY;;;;;;EAMZ,UAAU,QAAQ,YAAY,SAAS,WAAW;;EAElD;;;;;;EAMA,cAAc,UAAU,uBAAuB,QAAQ,cAAc;;EAErE,SAAS;;KAGC,oBACV,UAAU,WACV,GACA,UAAU,gBACR,kBAAkB;EACpB;EACA,SAAS,SAAS,GAAG,GAAG;;KAGd,QACV,UAAU,WACV,GACA,UAAU,eAAe;EAEzB,kBAAkB,OAAO,qBAAqB,GAAG,OAAO;EACxD,aACE,UAAU,oBAAoB,GAAG,GAAG,OACjC,iBAAiB,GAAG,GAAG;;KAGlB,aACV,UAAU,WACV,GACA,UAAU,eAAe;EAEzB,kBAAkB,OAAO,0BAA0B,GAAG,OAAO;EAC7D,aACE,UAAU,oBAAoB,GAAG,GAAG,OACjC,iBAAiB,GAAG,GAAG;;iBAGd,YACd,UAAU,WACV,GACA,UAAU,eAAe,sBACzB;EAAW,QAAQ,SAAS,GAAG,GAAG;IAAO,aAAa,GAAG,GAAG;iBAC9C,YACd,UAAU,WACV,GACA,UAAU,eAAe,sBACzB;EAAW,UAAU,SAAS,GAAG,GAAG,QAAQ,GAAG,GAAG;IAAQ,QAAQ,GAAG,GAAG;iBA4J1D,WACd,UAAU,WACV,GACA,UAAU,eAAe,sBAEzB,QAAQ,SAAS,GAAG,GAAG,IACvB,mBACA,UAAS,kBAAkB,QAAQ,MAClC,iBAAiB,GAAG,GAAG"}
1
+ {"version":3,"file":"react-KC4eW7yG.d.ts","names":[],"sources":["../src/react.ts"],"mappings":";;;;;KAwCY,kBAAkB;EAC5B;EACA,UAAU,gBAAgB;EAC1B;EACA;;KAGU,qBAAqB,UAAU,WAAW;EACpD;EACA;EACA,UAAU,gBAAgB;EAC1B,gBAAgB,cAAc;EAC9B;EACA,WAAW;;KAGD,0BAA0B,UAAU,WAAW,KAAK,KAC9D,qBAAqB,GAAG;KAId,mBAAmB,UAAU;;EAEvC,UAAU,YAAY;;;;;;;;EAQtB,cAAc,QAAQ,cAAc;;KAG1B,iBACV,UAAU,WACV,GACA,UAAU,eAAe,wBACvB,aAAa,GAAG,mBAAmB;;EAErC,OAAO;;EAEP;;EAEA,QAAQ,cAAc;;EAEtB;;;;;;EAMA,YAAY;;;;;;EAMZ,UAAU,QAAQ,YAAY,SAAS,WAAW;;EAElD;;;;;;EAMA,cAAc,UAAU,uBAAuB,QAAQ,cAAc;;EAErE,SAAS;;KAGC,oBACV,UAAU,WACV,GACA,UAAU,gBACR,kBAAkB;EACpB;EACA,SAAS,SAAS,GAAG,GAAG;;KAGd,QACV,UAAU,WACV,GACA,UAAU,eAAe;EAEzB,kBAAkB,OAAO,qBAAqB,GAAG,OAAO;EACxD,aACE,UAAU,oBAAoB,GAAG,GAAG,OACjC,iBAAiB,GAAG,GAAG;;KAGlB,aACV,UAAU,WACV,GACA,UAAU,eAAe;EAEzB,kBAAkB,OAAO,0BAA0B,GAAG,OAAO;EAC7D,aACE,UAAU,oBAAoB,GAAG,GAAG,OACjC,iBAAiB,GAAG,GAAG;;iBAGd,YACd,UAAU,WACV,GACA,UAAU,eAAe,sBACzB;EAAW,QAAQ,SAAS,GAAG,GAAG;IAAO,aAAa,GAAG,GAAG;iBAC9C,YACd,UAAU,WACV,GACA,UAAU,eAAe,sBACzB;EAAW,UAAU,SAAS,GAAG,GAAG,QAAQ,GAAG,GAAG;IAAQ,QAAQ,GAAG,GAAG;iBA4J1D,WACd,UAAU,WACV,GACA,UAAU,eAAe,sBAEzB,QAAQ,SAAS,GAAG,GAAG,IACvB,mBACA,UAAS,kBAAkB,QAAQ,MAClC,iBAAiB,GAAG,GAAG"}
package/dist/react.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as SessionProviderProps, c as UseSessionResult, i as BoundSessionProviderProps, l as createReact, n as BoundA2React, o as UseSessionOptions, r as BoundSessionOptions, s as UseSessionPresence, t as A2React, u as useSession } from "./react-BoHvC3v9.js";
1
+ import { a as SessionProviderProps, c as UseSessionResult, i as BoundSessionProviderProps, l as createReact, n as BoundA2React, o as UseSessionOptions, r as BoundSessionOptions, s as UseSessionPresence, t as A2React, u as useSession } from "./react-KC4eW7yG.js";
2
2
  export { A2React, BoundA2React, BoundSessionOptions, BoundSessionProviderProps, SessionProviderProps, UseSessionOptions, UseSessionPresence, UseSessionResult, createReact, useSession };
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { i as isInitialPromise, n as createRenderSession, r as resolveInitialForReact, t as createClient } from "./client-BQS4i_V9.js";
2
+ import { i as isInitialPromise, n as createRenderSession, r as resolveInitialForReact, t as createClient } from "./client-sq-djxhD.js";
3
3
  import { createContext, createElement, use, useContext, useEffect, useMemo, useSyncExternalStore } from "react";
4
4
  //#region src/react.ts
5
5
  function createReact(options) {
@@ -1,4 +1,4 @@
1
- import { n as isSessionCleared } from "./session-clear-wHd5GCpZ.js";
1
+ import { n as isSessionCleared } from "./session-clear-XJYpmUpg.js";
2
2
  //#region src/validate.ts
3
3
  /**
4
4
  * Run a Standard Schema validator, requiring a synchronous result.
@@ -84,4 +84,4 @@ function reducer(options) {
84
84
  //#endregion
85
85
  export { reducer as a, makeReducerBuilder as i, foldEvent as n, assertSyncSchema as o, foldsClearMarkers as r, validateSync as s, cloneInitial as t };
86
86
 
87
- //# sourceMappingURL=reducer-CjmvZSAb.js.map
87
+ //# sourceMappingURL=reducer-Bswr11ar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reducer-CjmvZSAb.js","names":[],"sources":["../src/validate.ts","../src/reducer.ts"],"sourcesContent":["import type { StandardSchemaV1 } from './standard-schema.ts'\n\n/**\n * Run a Standard Schema validator, requiring a synchronous result.\n * Validators must be synchronous (specs/a2-api.md §1) — an async one is\n * a definition bug, rejected at definition time where possible and here\n * as a backstop. `what` names the schema in error messages, e.g.\n * \"event 'created'\" or \"the stateSchema\".\n */\nexport function validateSync<Input, Output>(\n schema: StandardSchemaV1<Input, Output>,\n value: unknown,\n what: string,\n): StandardSchemaV1.Result<Output> {\n const result = schema['~standard'].validate(value)\n if (result instanceof Promise) {\n throw new TypeError(\n `the schema for ${what} is asynchronous — a2 schemas must validate synchronously`,\n )\n }\n return result\n}\n\n/**\n * Probe a schema to reject always-async validators early. The probe\n * value is deliberately garbage — we only care whether the result is a\n * Promise, not whether it passes.\n */\nexport function assertSyncSchema(schema: StandardSchemaV1, what: string): void {\n const probe = Symbol('a2.schema-probe')\n const result = schema['~standard'].validate(probe)\n if (result instanceof Promise) {\n // Swallow the eventual rejection — the probe input was garbage.\n result.catch(() => {})\n throw new TypeError(\n `the schema for ${what} is asynchronous — a2 schemas must validate synchronously`,\n )\n }\n}\n","import type {\n ContractEvent,\n EventDefs,\n PresenceDefs,\n ReducerOptions,\n} from './contract.ts'\nimport { isSessionCleared, type SessionCleared } from './session-clear.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport { validateSync } from './validate.ts'\n\nexport type StateSnapshot<S> = {\n state: S\n index: number\n /** The session's latest clear marker, once it has been cleared. */\n clearIndex?: number | undefined\n}\n\n/**\n * A fresh copy of a reducer's seed, so a fold that mutates in place\n * cannot corrupt the shared `initialState`. Non-cloneable seeds\n * (functions, class instances, proxies) fall back to the original.\n */\nexport function cloneInitial<S>(initial: S): S {\n try {\n return structuredClone(initial)\n } catch {\n return initial\n }\n}\n\nconst markerFolds = new WeakSet<object>()\n\n/**\n * Mark a fold that receives clear markers itself instead of resetting to its\n * `initialState`. The actor follower has no seed of its own; its stream carries\n * the reset state in the marker.\n */\nexport function foldsClearMarkers<\n F extends (state: never, event: never) => unknown,\n>(fold: F): F {\n markerFolds.add(fold)\n return fold\n}\n\n/** One fold step; a clear marker resets to the seed on server and client alike. */\nexport function foldEvent<D extends EventDefs, S>(\n source: Pick<Reducer<D, S>, 'fold' | 'initialState'>,\n state: S,\n event: ContractEvent<D> | SessionCleared,\n): S {\n if (!isSessionCleared(event)) return source.fold(state, event)\n return markerFolds.has(source.fold)\n ? source.fold(state, event as unknown as ContractEvent<D>)\n : cloneInitial(source.initialState)\n}\n\n/**\n * A pure fold over a session's events — `(state, event) => state` —\n * published inline in a contract or built with `reducer(options).fold(fn)`.\n *\n * The name is the reducer's identity. Cached folds (server snapshots,\n * the browser cache) are keyed by it, which makes it the invalidation\n * knob too: changed the fold's logic? Change the name. Snapshots under\n * the old name are ignored and the next read refolds from raw events.\n * See docs/contract/02-state.mdx.\n */\nexport type Reducer<\n D extends EventDefs = EventDefs,\n S = unknown,\n P extends PresenceDefs = Record<never, never>,\n> = {\n /** Identity and cache key. Rename when the fold's logic changes. */\n readonly name: string\n /** The contract's vocabulary — types every event in the fold. */\n readonly events: Readonly<D>\n /**\n * The contract's presence vocabulary — carried because the reducer\n * is the client's typed handle on the contract. The fold never sees\n * presence.\n */\n readonly presence: Readonly<P>\n readonly fold: (state: S, event: ContractEvent<D>) => S\n readonly initialState: S\n /**\n * When present: `initialState` was validated against it at\n * definition, and any cached fold a2 rehydrates (server snapshots,\n * the browser cache) is checked against it — failing snapshots are\n * discarded and refolded, catching shape drift a stale name can't.\n */\n readonly stateSchema: StandardSchemaV1<unknown, S> | undefined\n}\n\n/** The second step of `reducer` — see the method's doc. */\nexport type ReducerBuilder<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = {\n fold(fold: (state: S, event: ContractEvent<D>) => S): Reducer<D, S, P>\n}\n\n/** Internal — shared validation for inline and standalone reducer definitions. */\nexport function makeReducerBuilder<\n D extends EventDefs,\n P extends PresenceDefs,\n Seed,\n S,\n>(\n events: Readonly<D>,\n presence: Readonly<P>,\n options: {\n name: string\n initialState: Seed\n stateSchema?: StandardSchemaV1<Seed, S>\n },\n): ReducerBuilder<D, S, P> {\n const { name } = options\n if (typeof name !== 'string' || name.length === 0) {\n throw new TypeError(\n 'reducer name must be a non-empty string — it identifies the reducer and keys cached snapshots',\n )\n }\n\n // Without a schema, S = Seed (the type parameter default), so the\n // seed is the state. With one, the seed is the schema's input and the\n // validated output (defaults applied) becomes the fold's actual seed.\n let initialState = options.initialState as unknown as S\n if (options.stateSchema) {\n const result = validateSync(\n options.stateSchema,\n options.initialState,\n 'the stateSchema',\n )\n if (result.issues) {\n throw new TypeError(\n `reducer initialState does not match its stateSchema: ${result.issues\n .map((issue) => issue.message)\n .join('; ')}`,\n )\n }\n initialState = result.value as S\n const restored = validateSync(\n options.stateSchema,\n initialState,\n 'the stateSchema',\n )\n if (\n restored.issues ||\n JSON.stringify(restored.value) !== JSON.stringify(initialState)\n ) {\n throw new TypeError(\n 'stateSchema must accept and preserve its own output so snapshots can be restored',\n )\n }\n }\n\n return {\n fold(fold) {\n if (typeof fold !== 'function') {\n throw new TypeError('reducer fold must be a function')\n }\n return {\n name,\n events,\n presence,\n fold,\n initialState,\n stateSchema: options.stateSchema as\n StandardSchemaV1<unknown, S> | undefined,\n }\n },\n }\n}\n\nexport type RegisteredReducer<\n D extends EventDefs,\n P extends PresenceDefs,\n> = Omit<Reducer<D, unknown, P>, 'fold'> & {\n readonly fold: (state: never, event: never) => unknown\n}\n\nexport function reducer<\n D extends EventDefs,\n P extends PresenceDefs,\n Seed,\n S = Seed,\n>(\n options: ReducerOptions<Seed, S> & {\n contract: { events: Readonly<D>; presence: Readonly<P> }\n },\n): ReducerBuilder<D, S, P> {\n return makeReducerBuilder(\n options.contract.events,\n options.contract.presence,\n options,\n )\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,aACd,QACA,OACA,MACiC;CACjC,MAAM,SAAS,OAAO,YAAY,CAAC,SAAS,KAAK;CACjD,IAAI,kBAAkB,SACpB,MAAM,IAAI,UACR,kBAAkB,KAAK,0DACzB;CAEF,OAAO;AACT;;;;;;AAOA,SAAgB,iBAAiB,QAA0B,MAAoB;CAC7E,MAAM,QAAQ,OAAO,iBAAiB;CACtC,MAAM,SAAS,OAAO,YAAY,CAAC,SAAS,KAAK;CACjD,IAAI,kBAAkB,SAAS;EAE7B,OAAO,YAAY,CAAC,CAAC;EACrB,MAAM,IAAI,UACR,kBAAkB,KAAK,0DACzB;CACF;AACF;;;;;;;;AChBA,SAAgB,aAAgB,SAAe;CAC7C,IAAI;EACF,OAAO,gBAAgB,OAAO;CAChC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAM,8BAAc,IAAI,QAAgB;;;;;;AAOxC,SAAgB,kBAEd,MAAY;CACZ,YAAY,IAAI,IAAI;CACpB,OAAO;AACT;;AAGA,SAAgB,UACd,QACA,OACA,OACG;CACH,IAAI,CAAC,iBAAiB,KAAK,GAAG,OAAO,OAAO,KAAK,OAAO,KAAK;CAC7D,OAAO,YAAY,IAAI,OAAO,IAAI,IAC9B,OAAO,KAAK,OAAO,KAAoC,IACvD,aAAa,OAAO,YAAY;AACtC;;AAgDA,SAAgB,mBAMd,QACA,UACA,SAKyB;CACzB,MAAM,EAAE,SAAS;CACjB,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C,MAAM,IAAI,UACR,+FACF;CAMF,IAAI,eAAe,QAAQ;CAC3B,IAAI,QAAQ,aAAa;EACvB,MAAM,SAAS,aACb,QAAQ,aACR,QAAQ,cACR,iBACF;EACA,IAAI,OAAO,QACT,MAAM,IAAI,UACR,wDAAwD,OAAO,OAC5D,KAAK,UAAU,MAAM,OAAO,CAAC,CAC7B,KAAK,IAAI,GACd;EAEF,eAAe,OAAO;EACtB,MAAM,WAAW,aACf,QAAQ,aACR,cACA,iBACF;EACA,IACE,SAAS,UACT,KAAK,UAAU,SAAS,KAAK,MAAM,KAAK,UAAU,YAAY,GAE9D,MAAM,IAAI,UACR,kFACF;CAEJ;CAEA,OAAO,EACL,KAAK,MAAM;EACT,IAAI,OAAO,SAAS,YAClB,MAAM,IAAI,UAAU,iCAAiC;EAEvD,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,aAAa,QAAQ;EAEvB;CACF,EACF;AACF;AASA,SAAgB,QAMd,SAGyB;CACzB,OAAO,mBACL,QAAQ,SAAS,QACjB,QAAQ,SAAS,UACjB,OACF;AACF"}
1
+ {"version":3,"file":"reducer-Bswr11ar.js","names":[],"sources":["../src/validate.ts","../src/reducer.ts"],"sourcesContent":["import type { StandardSchemaV1 } from './standard-schema.ts'\n\n/**\n * Run a Standard Schema validator, requiring a synchronous result.\n * Validators must be synchronous (specs/a2-api.md §1) — an async one is\n * a definition bug, rejected at definition time where possible and here\n * as a backstop. `what` names the schema in error messages, e.g.\n * \"event 'created'\" or \"the stateSchema\".\n */\nexport function validateSync<Input, Output>(\n schema: StandardSchemaV1<Input, Output>,\n value: unknown,\n what: string,\n): StandardSchemaV1.Result<Output> {\n const result = schema['~standard'].validate(value)\n if (result instanceof Promise) {\n throw new TypeError(\n `the schema for ${what} is asynchronous — a2 schemas must validate synchronously`,\n )\n }\n return result\n}\n\n/**\n * Probe a schema to reject always-async validators early. The probe\n * value is deliberately garbage — we only care whether the result is a\n * Promise, not whether it passes.\n */\nexport function assertSyncSchema(schema: StandardSchemaV1, what: string): void {\n const probe = Symbol('a2.schema-probe')\n const result = schema['~standard'].validate(probe)\n if (result instanceof Promise) {\n // Swallow the eventual rejection — the probe input was garbage.\n result.catch(() => {})\n throw new TypeError(\n `the schema for ${what} is asynchronous — a2 schemas must validate synchronously`,\n )\n }\n}\n","import type {\n ContractEvent,\n EventDefs,\n PresenceDefs,\n ReducerOptions,\n} from './contract.ts'\nimport { isSessionCleared, type SessionCleared } from './session-clear.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport { validateSync } from './validate.ts'\n\nexport type StateSnapshot<S> = {\n state: S\n index: number\n /** The session's latest clear marker, once it has been cleared. */\n clearIndex?: number | undefined\n}\n\n/**\n * A fresh copy of a reducer's seed, so a fold that mutates in place\n * cannot corrupt the shared `initialState`. Non-cloneable seeds\n * (functions, class instances, proxies) fall back to the original.\n */\nexport function cloneInitial<S>(initial: S): S {\n try {\n return structuredClone(initial)\n } catch {\n return initial\n }\n}\n\nconst markerFolds = new WeakSet<object>()\n\n/**\n * Mark a fold that receives clear markers itself instead of resetting to its\n * `initialState`. The actor follower has no seed of its own; its stream carries\n * the reset state in the marker.\n */\nexport function foldsClearMarkers<\n F extends (state: never, event: never) => unknown,\n>(fold: F): F {\n markerFolds.add(fold)\n return fold\n}\n\n/** One fold step; a clear marker resets to the seed on server and client alike. */\nexport function foldEvent<D extends EventDefs, S>(\n source: Pick<Reducer<D, S>, 'fold' | 'initialState'>,\n state: S,\n event: ContractEvent<D> | SessionCleared,\n): S {\n if (!isSessionCleared(event)) return source.fold(state, event)\n return markerFolds.has(source.fold)\n ? source.fold(state, event as unknown as ContractEvent<D>)\n : cloneInitial(source.initialState)\n}\n\n/**\n * A pure fold over a session's events — `(state, event) => state` —\n * published inline in a contract or built with `reducer(options).fold(fn)`.\n *\n * The name is the reducer's identity. Cached folds (server snapshots,\n * the browser cache) are keyed by it, which makes it the invalidation\n * knob too: changed the fold's logic? Change the name. Snapshots under\n * the old name are ignored and the next read refolds from raw events.\n * See docs/contract/02-state.mdx.\n */\nexport type Reducer<\n D extends EventDefs = EventDefs,\n S = unknown,\n P extends PresenceDefs = Record<never, never>,\n> = {\n /** Identity and cache key. Rename when the fold's logic changes. */\n readonly name: string\n /** The contract's vocabulary — types every event in the fold. */\n readonly events: Readonly<D>\n /**\n * The contract's presence vocabulary — carried because the reducer\n * is the client's typed handle on the contract. The fold never sees\n * presence.\n */\n readonly presence: Readonly<P>\n readonly fold: (state: S, event: ContractEvent<D>) => S\n readonly initialState: S\n /**\n * When present: `initialState` was validated against it at\n * definition, and any cached fold a2 rehydrates (server snapshots,\n * the browser cache) is checked against it — failing snapshots are\n * discarded and refolded, catching shape drift a stale name can't.\n */\n readonly stateSchema: StandardSchemaV1<unknown, S> | undefined\n}\n\n/** The second step of `reducer` — see the method's doc. */\nexport type ReducerBuilder<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = {\n fold(fold: (state: S, event: ContractEvent<D>) => S): Reducer<D, S, P>\n}\n\n/** Internal — shared validation for inline and standalone reducer definitions. */\nexport function makeReducerBuilder<\n D extends EventDefs,\n P extends PresenceDefs,\n Seed,\n S,\n>(\n events: Readonly<D>,\n presence: Readonly<P>,\n options: {\n name: string\n initialState: Seed\n stateSchema?: StandardSchemaV1<Seed, S>\n },\n): ReducerBuilder<D, S, P> {\n const { name } = options\n if (typeof name !== 'string' || name.length === 0) {\n throw new TypeError(\n 'reducer name must be a non-empty string — it identifies the reducer and keys cached snapshots',\n )\n }\n\n // Without a schema, S = Seed (the type parameter default), so the\n // seed is the state. With one, the seed is the schema's input and the\n // validated output (defaults applied) becomes the fold's actual seed.\n let initialState = options.initialState as unknown as S\n if (options.stateSchema) {\n const result = validateSync(\n options.stateSchema,\n options.initialState,\n 'the stateSchema',\n )\n if (result.issues) {\n throw new TypeError(\n `reducer initialState does not match its stateSchema: ${result.issues\n .map((issue) => issue.message)\n .join('; ')}`,\n )\n }\n initialState = result.value as S\n const restored = validateSync(\n options.stateSchema,\n initialState,\n 'the stateSchema',\n )\n if (\n restored.issues ||\n JSON.stringify(restored.value) !== JSON.stringify(initialState)\n ) {\n throw new TypeError(\n 'stateSchema must accept and preserve its own output so snapshots can be restored',\n )\n }\n }\n\n return {\n fold(fold) {\n if (typeof fold !== 'function') {\n throw new TypeError('reducer fold must be a function')\n }\n return {\n name,\n events,\n presence,\n fold,\n initialState,\n stateSchema: options.stateSchema as\n StandardSchemaV1<unknown, S> | undefined,\n }\n },\n }\n}\n\nexport type RegisteredReducer<\n D extends EventDefs,\n P extends PresenceDefs,\n> = Omit<Reducer<D, unknown, P>, 'fold'> & {\n readonly fold: (state: never, event: never) => unknown\n}\n\nexport function reducer<\n D extends EventDefs,\n P extends PresenceDefs,\n Seed,\n S = Seed,\n>(\n options: ReducerOptions<Seed, S> & {\n contract: { events: Readonly<D>; presence: Readonly<P> }\n },\n): ReducerBuilder<D, S, P> {\n return makeReducerBuilder(\n options.contract.events,\n options.contract.presence,\n options,\n )\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,aACd,QACA,OACA,MACiC;CACjC,MAAM,SAAS,OAAO,YAAY,CAAC,SAAS,KAAK;CACjD,IAAI,kBAAkB,SACpB,MAAM,IAAI,UACR,kBAAkB,KAAK,0DACzB;CAEF,OAAO;AACT;;;;;;AAOA,SAAgB,iBAAiB,QAA0B,MAAoB;CAC7E,MAAM,QAAQ,OAAO,iBAAiB;CACtC,MAAM,SAAS,OAAO,YAAY,CAAC,SAAS,KAAK;CACjD,IAAI,kBAAkB,SAAS;EAE7B,OAAO,YAAY,CAAC,CAAC;EACrB,MAAM,IAAI,UACR,kBAAkB,KAAK,0DACzB;CACF;AACF;;;;;;;;AChBA,SAAgB,aAAgB,SAAe;CAC7C,IAAI;EACF,OAAO,gBAAgB,OAAO;CAChC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAM,8BAAc,IAAI,QAAgB;;;;;;AAOxC,SAAgB,kBAEd,MAAY;CACZ,YAAY,IAAI,IAAI;CACpB,OAAO;AACT;;AAGA,SAAgB,UACd,QACA,OACA,OACG;CACH,IAAI,CAAC,iBAAiB,KAAK,GAAG,OAAO,OAAO,KAAK,OAAO,KAAK;CAC7D,OAAO,YAAY,IAAI,OAAO,IAAI,IAC9B,OAAO,KAAK,OAAO,KAAoC,IACvD,aAAa,OAAO,YAAY;AACtC;;AAgDA,SAAgB,mBAMd,QACA,UACA,SAKyB;CACzB,MAAM,EAAE,SAAS;CACjB,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C,MAAM,IAAI,UACR,+FACF;CAMF,IAAI,eAAe,QAAQ;CAC3B,IAAI,QAAQ,aAAa;EACvB,MAAM,SAAS,aACb,QAAQ,aACR,QAAQ,cACR,iBACF;EACA,IAAI,OAAO,QACT,MAAM,IAAI,UACR,wDAAwD,OAAO,OAC5D,KAAK,UAAU,MAAM,OAAO,CAAC,CAC7B,KAAK,IAAI,GACd;EAEF,eAAe,OAAO;EACtB,MAAM,WAAW,aACf,QAAQ,aACR,cACA,iBACF;EACA,IACE,SAAS,UACT,KAAK,UAAU,SAAS,KAAK,MAAM,KAAK,UAAU,YAAY,GAE9D,MAAM,IAAI,UACR,kFACF;CAEJ;CAEA,OAAO,EACL,KAAK,MAAM;EACT,IAAI,OAAO,SAAS,YAClB,MAAM,IAAI,UAAU,iCAAiC;EAEvD,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,aAAa,QAAQ;EAEvB;CACF,EACF;AACF;AASA,SAAgB,QAMd,SAGyB;CACzB,OAAO,mBACL,QAAQ,SAAS,QACjB,QAAQ,SAAS,UACjB,OACF;AACF"}
@@ -1,5 +1,5 @@
1
- import { r as Clock } from "./store-D0MhBvg6.js";
2
- import { B as SchedulerTask, t as A2Scheduler } from "./server-qgez0Xny.js";
1
+ import { r as Clock } from "./store-DEzcHZOA.js";
2
+ import { B as SchedulerTask, t as A2Scheduler } from "./server-B9gu0qi1.js";
3
3
  //#region src/scheduler-qstash.d.ts
4
4
  type QStashStoreOutage = {
5
5
  version: 1;
@@ -1,7 +1,7 @@
1
- import { i as A2Error } from "./session-clear-wHd5GCpZ.js";
1
+ import { i as A2Error } from "./session-clear-XJYpmUpg.js";
2
2
  import { S as serverInternals, f as assertSchedulerTargets, p as classifySchedulerSendFailure, t as DRAIN_TIMINGS } from "./internal-CvsrprnU.js";
3
3
  import { n as platformVercelOidcToken } from "./platform-B4TnJtWu.js";
4
- import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "./server-DtFrWxi3.js";
4
+ import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "./server-DX7mM6nm.js";
5
5
  import { t as retryableLazy } from "./retryable-lazy-DZWmHpii.js";
6
6
  import { n as SYSTEM_CLOCK } from "./store-N8PXxDAS.js";
7
7
  import { t as normalizeSchedulerTask } from "./scheduler-task-X1SToDjP.js";
@@ -1,5 +1,5 @@
1
- import { r as Clock } from "./store-D0MhBvg6.js";
2
- import { B as SchedulerTask, t as A2Scheduler } from "./server-qgez0Xny.js";
1
+ import { r as Clock } from "./store-DEzcHZOA.js";
2
+ import { B as SchedulerTask, t as A2Scheduler } from "./server-B9gu0qi1.js";
3
3
  //#region src/scheduler-vercel.d.ts
4
4
  /**
5
5
  * The "not settled yet" signal for a drain whose outcome is unknown — an
@@ -1,5 +1,5 @@
1
1
  import { S as serverInternals, f as assertSchedulerTargets, p as classifySchedulerSendFailure, t as DRAIN_TIMINGS } from "./internal-CvsrprnU.js";
2
- import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "./server-DtFrWxi3.js";
2
+ import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "./server-DX7mM6nm.js";
3
3
  import { t as retryableLazy } from "./retryable-lazy-DZWmHpii.js";
4
4
  import { n as SYSTEM_CLOCK } from "./store-N8PXxDAS.js";
5
5
  import { t as normalizeSchedulerTask } from "./scheduler-task-X1SToDjP.js";
@@ -1,6 +1,6 @@
1
1
  import { c as ContractEvent, d as PresenceDefs, f as PresenceMap, g as WithPresence, m as PresenceSnapshot, o as AppendInput, p as PresencePatch, r as RegisteredReducer, s as Contract, t as Reducer, u as EventDefs } from "./reducer-CYPHsSmd.js";
2
- import { t as A2Store } from "./store-D0MhBvg6.js";
3
- import { t as SessionCleared } from "./session-clear-D1PFe7xl.js";
2
+ import { t as A2Store } from "./store-DEzcHZOA.js";
3
+ import { t as SessionCleared } from "./session-clear-vfonou9S.js";
4
4
  import { i as A2Telemetry } from "./telemetry-CWwsh-Gx.js";
5
5
  //#region src/session-socket.d.ts
6
6
  /**
@@ -139,6 +139,12 @@ type SessionDispatch<D extends EventDefs> = (...events: AppendInput<D>[]) => Pro
139
139
  type SessionAppend<D extends EventDefs> = SessionDispatch<D> & {
140
140
  /** Commit, then hand pending work directly to configured scheduler. */
141
141
  dispatch: SessionDispatch<D>;
142
+ /**
143
+ * Append only while `index` is the session's head, checked in the same
144
+ * atomic step as the write. Otherwise nothing is written and it throws
145
+ * `LAST_INDEX_MISMATCH`, with the head as `details.index`.
146
+ */
147
+ ifLastIndex(index: number, ...events: AppendInput<D>[]): Promise<ContractEvent<D>[]>;
142
148
  };
143
149
  type ConsumerAppend<D extends EventDefs> = (name: string, ...events: AppendInput<D>[]) => Promise<ContractEvent<D>[]>;
144
150
  type ScheduleDelay = `${number}${"ms" | "s" | "m" | "h" | "d"}`;
@@ -450,4 +456,4 @@ type ServerOptions<D extends EventDefs, P extends PresenceDefs = Record<never, n
450
456
  declare function createServer<D extends EventDefs, P extends PresenceDefs = Record<never, never>, R extends RegisteredReducer<D, P> | undefined = RegisteredReducer<D, P> | undefined, const C extends readonly unknown[] = readonly Consumer<D>[]>(options: ServerOptions<D, P, R, C>): A2Server<D, P, R>;
451
457
  //#endregion
452
458
  export { SessionSchedule as A, SchedulerTask as B, SessionConsumeOptions as C, SessionPresence as D, SessionDispatch as E, deliverSchedulerClear as F, UpgradeWebSocket as G, A2PushEvent as H, ScheduledEvent as I, A2Socket as K, SchedulerAppendTask as L, consumer as M, createServer as N, SessionRedriveOptions as O, deliverSchedulerAppend as P, SchedulerClearTask as R, SessionClearResult as S, SessionDeadLetters as T, A2PushPresence as U, A2Operation as V, ServerFetchOptions as W, ServerConsumers as _, ConsumerAppend as a, SessionAppend as b, ConsumerOptions as c, DeadLetter as d, DrainableServer as f, ScheduleTiming as g, ScheduleDelay as h, Consumer as i, StateOptions as j, SessionRedriveResult as k, ConsumerResult as l, LaneContext as m, A2Server as n, ConsumerContext as o, InlineConsumer as p, AbortSpec as r, ConsumerLane as s, A2Scheduler as t, ConsumerSpec as u, ServerOptions as v, SessionConsumeResult as w, SessionClearOptions as x, Session as y, SchedulerDrainTask as z };
453
- //# sourceMappingURL=server-qgez0Xny.d.ts.map
459
+ //# sourceMappingURL=server-B9gu0qi1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-B9gu0qi1.d.ts","names":[],"sources":["../src/session-socket.ts","../src/server-fetch.ts","../src/scheduler-task.ts","../src/server.ts"],"mappings":";;;;;;;;;;;;KA2CY;EACV,KAAK;EACL,GAAG,kBAAkB,WAAW;EAChC,GAAG,gBAAgB;EACnB,GAAG,gBAAgB,WAAW;EAC9B,MAAM,eAAe;;;EAGrB;;;;KCjBG,mBAAmB,UAAU,oBACzB,wBAAwB;KAE5B,wBAAwB,UAAU,gBAAgB,YAClD,WAAW,2BAA0B;KAG9B,YAAY,UAAU,YAAY;WACnC,MAAM,mBAAmB;WACzB;WACA;;KAGC,eAAe,UAAU,eAAe;WACzC;WACA,QAAQ,wBAAwB;WAChC;WACA;;KAGC,YACV,UAAU,YAAY,WACtB,UAAU,eAAe;WAGZ;WACA;WACA;WACA;WACA;;WAGA;WACA;WACA;WACA;WACA;;WAGA;WACA;WACA,iBAAiB,YAAY;WAC7B,WAAW,eAAe;WAC1B;;KAGH,oBACV,SAAS,QAAQ,sBACd,WAAW,QAAQ;KAEZ,mBACV,UAAU,YAAY,WACtB,UAAU,eAAe;EAEzB,aAAa,WAAW,YAAY,GAAG,iBAAiB;EACxD,mBAAmB;;EAEnB;;;;;KC1FU;EACV;EACA;EACA;;;KAIU;EACV;EACA;EACA;EACA;;EAEA;;;KAIU;EACV;EACA;;EAEA;EACA;EACA;;EAEA;EACA,iBAAiB;;EAEjB;;;KAIU;EACV;EACA;;EAEA;EACA;EACA;;EAEA;;EAEA;;;KAIU,gBACV,qBAAqB,sBAAsB;;;KCgCxC,YAAY,uBAAuB,YAEpC;EAAY,oBAAoB;IAC9B;;KAiCM,gBACV,UAAU,WACV,gBAAgB,mBAAmB,YACnC,UAAU,eAAe,sBACzB;;EAGA,OAAO,cAAc,GAAG;;EAExB;;EAEA,SAAS,QAAQ,GAAG,eAAe,IAAI,GAAG;;EAE1C,QAAQ;;KAGE,YACV,UAAU,WACV,gBAAgB,mBAAmB;EAEnC;EACA,OAAO,KAAK,cAAc,GAAG;IAA4B;;;;;;;;KAQ/C,aACV,UAAU,WACV,gBAAgB,mBAAmB,yBACtB,SAAS,YAAY,GAAG;KAE3B,gBAAgB,UAAU,iBACjC,QAAQ,YAAY,SACpB,QAAQ,cAAc;KAEf,cAAc,UAAU,aAAa,gBAAgB;;EAE/D,UAAU,gBAAgB;;;;;;EAM1B,YACE,kBACG,QAAQ,YAAY,OACtB,QAAQ,cAAc;;KAGf,eAAe,UAAU,cACnC,iBACG,QAAQ,YAAY,SACpB,QAAQ,cAAc;KAEf;KAEA;EACR,OAAO;EAAe;;EAAiB,IAAI;EAAM;;KAEzC,gBAAgB,UAAU;GAElC,cACA,QAAQ,mBACL,QAAQ,YAAY,OACtB;;;;;;EAMH,MACE,cACA,SAAS;IAAmB;MAC3B;;KAGO;EACV;;KAGU;;EAEV;;KAGU;EAAuB;EAAkB;;KAEzC;;EAEV;;KAGU;;EAEV;;KAGU;;;;;;EAMV;;EAEA,SAAS;;KAGC;;EAEV;;;KAIU,WAAW,UAAU,aAAa,cAAc;;EAE1D;EACA;;EAEA;;;;;EAKA;;;;;EAKA;EACA,UAAU;;;KAIA,mBAAmB,UAAU;;EAEvC,eAAe,QAAQ,WAAW;;;;;EAKlC,QACE;IAAU;IAAkB;KAC5B,SAAS,wBACR,QAAQ;;;;;;;;;KAUD,gBAAgB,UAAU,WAAW,UAAU;;;;;;EAMzD,OAAO;IACL;IACA;MACE,cACF,cAAc,KAAK,iBAAiB,cAAc,KAAK,iBAAiB;;;;;;;EAQ1E,YAAY;IACV;IACA,QAAQ,cAAc;IACtB;IACA;MACE;;EAEJ,YAAY,QAAQ,YAAY;;;KAItB,QACV,UAAU,WACV,SAAS,cAAc,IACvB,UAAU,eAAe,sBACzB,aACE,aAAa,GAAG,gBAAgB,GAAG;WAC5B;EACT,QAAQ;EACR,UAAU,gBAAgB;;;;;EAK1B,MAAM,UAAU,sBAAsB,QAAQ;EAC9C,QAAQ;IAAY;IAAc;MAAiB,QAAQ,cAAc;;;;;;;;EAQzE,QACE,UAAU,SAAS,IACnB,UAAU,wBACT,QAAQ;EACX;KACG,GACC,SAAS,QAAQ,GAAG,GAAG,uBACvB,UAAU,eACT;MAAU,OAAO;MAAG;MAAe;;QAClC;QAEI;MAAU,OAAO;MAAG;MAAe;;;;;;;;EAM7C,OAAO;IACL;MACE,cAAc,cAAc,KAAK;;;;;;;KAQ3B;WACD;aAAqB;;EAC9B,MAAM,oBAAoB;IAAU;;;;;;;;;;;;KAY1B;EACV,SAAS,MAAM,gBAAgB;EAC/B,WAAW,SAAS,qBAAqB,KAAK,YAAY,QAAQ;;KAGxD,SACV,UAAU,WACV,UAAU,eAAe,sBACzB,UAAU,kBAAkB,GAAG,iBAC7B,kBAAkB,GAAG;;WAGd,UAAU,SAAS,GAAG,GAAG;WACzB;KACN,SAAS,UAAU,QAAQ;KAC3B,SAAS,SAAS,SAAS,mBAAmB,GAAG,KAAK,QAAQ;;EAEjE,QACE,aACC,QAAQ,GAAG,cAAc,IAAI,GAAG,YAAY,MAAM,mBAAmB;;;;;EAKxE,MAAM,oBAAoB;IAAU;;;;;;;;iBAiBhB,uBACpB,QAAQ,iBACR,MAAM,sBACL;;;;;;;;iBAgCmB,sBACpB,QAAQ,iBACR,MAAM,qBACL;;;;;;;;;KAiCS,UAAU,UAAU,WAAW,gBAAgB,cACvD,YAAY,iBAET,WAAW,uBAGN,OAAO,cAAc,GAAG,IACxB,SAAS,cAAc,GAAG,IAC1B;EAAW;;;KAKX,eAAe,UAAU,aAAa,eACzC,YAAY,cAAc,YAAY;;KAInC,aAAa,UAAU;WACxB,uBAAuB;WACvB,MAAM,aAAa;WACnB;WACA,SAAS,UAAU,SAAS;WAC5B,MAAM,KAAK,gBAAgB,OAAO,eAAe;;;KAIhD,SAAS,UAAU;WACpB;WACA;aAAqB;;WACrB,MAAM,aAAa;;KAGlB,gBACV,UAAU,WACV,UAAU,cACV,UAAU,kBAAkB,GAAG,gBAC/B,gBAAgB;;EAGhB,UAAU,SAAS,GAAG,GAAG;;EAEzB;;EAEA,iBAAiB;;EAEjB,OAAO,aAAa,GAAG;;EAEvB;EACA,UAAU,UAAU,GAAG;;;;;;KAOb,eACV,UAAU,WACV,UAAU,cACV,UAAU,kBAAkB,GAAG,gBAC/B,gBAAgB,cACd,KAAK,gBAAgB,GAAG,GAAG,GAAG;EAChC,MAAM,KAAK,gBAAgB,GAAG,GAAG,GAAG,YAAY,QAAQ,eAAe;;;KAIpE,YAAY,UAAU,WAAW,qBAAqB,UACjD,aACN,QAAQ,SAAS;;;;;KAMT,gBACV,UAAU,WACV,UAAU,cACV,UAAU,kBAAkB,GAAG,gBAC/B,4CAEU,WAAW,IACnB,eAAe,GAAG,GAAG,GAAG,YAAY,GAAG,EAAE,OAAO,QAAQ,EAAE,IAAI,SAAS;;iBAM3D,SACd,UAAU,WACV,UAAU,cACV,UAAU,kBAAkB,GAAG,sBACzB,gBAAgB,mBAAmB,YAEzC,SAAS,gBAAgB,GAAG,GAAG,GAAG;EAElC,IACE,KAAK,KAAK,gBAAgB,GAAG,GAAG,GAAG,YAAY,QAAQ,eAAe,KACrE,SAAS;;KAgHF,cACV,UAAU,WACV,UAAU,eAAe,sBACzB,UAAU,kBAAkB,GAAG,iBAC7B,kBAAkB,GAAG,gBACvB,wCAAwC,SAAS;;EAGjD,UAAU,SAAS,GAAG,GAAG;;EAEzB,QAAQ;;;;;;;EAOR,YAAY;;EAEZ,YAAY;;;;;;EAMZ;IAAa;;;;;;;EAMb,YAAY,gBAAgB,GAAG,GAAG,GAAG,cAAc,SAAS;;;iBA0R9C,aACd,UAAU,WACV,UAAU,eAAe,sBACzB,UAAU,kBAAkB,GAAG,iBAC7B,kBAAkB,GAAG,sBACjB,wCAAwC,SAAS,MACvD,SAAS,cAAc,GAAG,GAAG,GAAG,KAAK,SAAS,GAAG,GAAG"}
@@ -1,12 +1,12 @@
1
- import { a as NonRetriableError, i as A2Error, n as isSessionCleared, o as asStoreUnavailable, r as sessionClearedError } from "./session-clear-wHd5GCpZ.js";
2
- import { n as foldEvent, s as validateSync, t as cloneInitial } from "./reducer-CjmvZSAb.js";
1
+ import { a as NonRetriableError, i as A2Error, n as isSessionCleared, o as asStoreUnavailable, r as sessionClearedError } from "./session-clear-XJYpmUpg.js";
2
+ import { n as foldEvent, s as validateSync, t as cloneInitial } from "./reducer-Bswr11ar.js";
3
3
  import { n as encodeState, t as decodeState } from "./reducer-runtime-DQwz_J59.js";
4
4
  import { C as stateTailReaders, S as serverInternals, a as POLL_TIMINGS, b as runtimeConsumerFactory, c as SOCKET_TIMINGS, g as failedPreviousAttempt, h as drainSettledHooks, l as STATE_CACHE, s as RESERVED_PARTICIPANT_IDS, t as DRAIN_TIMINGS, u as STREAM_TIMINGS, v as markSchedulerSendFailure, x as runtimeConsumers, y as nullProtoRecord } from "./internal-CvsrprnU.js";
5
5
  import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
6
6
  import { a as presenceTombstones, i as takeBuffered, n as isSerializedEvent, r as parseSerializedEvent, t as bufferedEvents } from "./stream-buffer-DrTyiIuo.js";
7
7
  import { i as streamActivities, r as createStreamActivity, t as defaultSleep } from "./store-polling-BZt2Rf3D.js";
8
8
  import { r as platformWaitUntil, t as invocationDeadlineMs } from "./platform-B4TnJtWu.js";
9
- import { A as stateSnapshotToWire, C as serializedEventToWireJson, D as socketFrameFor, E as socketEventsFor, O as socketSubscribedFor, S as presenceSnapshotToWire, T as socketErrorAckFor, b as presencePatchToWire, d as heldEventBatch, i as compactEventJson, j as wireVersion, k as socketUnsubscribedFor, m as isStreamEvent, n as SOCKET_PING_FRAME, o as errorStatus, r as asA2Error, s as errorToWire, t as EVENT_WRITE_CHARS, u as eventToWire, w as socketAckFor } from "./wire-CV-Z7wz-.js";
9
+ import { A as stateSnapshotToWire, C as serializedEventToWireJson, D as socketFrameFor, E as socketEventsFor, O as socketSubscribedFor, S as presenceSnapshotToWire, T as socketErrorAckFor, b as presencePatchToWire, d as heldEventBatch, i as compactEventJson, j as wireVersion, k as socketUnsubscribedFor, m as isStreamEvent, n as SOCKET_PING_FRAME, o as errorStatus, r as asA2Error, s as errorToWire, t as EVENT_WRITE_CHARS, u as eventToWire, w as socketAckFor } from "./wire-BFE9sIQf.js";
10
10
  import { t as retryableLazy } from "./retryable-lazy-DZWmHpii.js";
11
11
  //#region src/push-envelope.ts
12
12
  /**
@@ -1573,7 +1573,7 @@ function createServer(options) {
1573
1573
  * the drain it schedules is created in the append's active context —
1574
1574
  * with a real tracer, causal work remains connected.
1575
1575
  */
1576
- const appendCore = (sessionId, events, source, mode, onAppended, cause, generatedIds, requireDurableInitialArm = false, originIndex) => telemetry.span("a2.append", {
1576
+ const appendCore = (sessionId, events, source, mode, onAppended, cause, generatedIds, requireDurableInitialArm = false, condition = {}) => telemetry.span("a2.append", {
1577
1577
  "a2.contract": name,
1578
1578
  "a2.session_id": sessionId,
1579
1579
  "a2.append.source": source,
@@ -1594,7 +1594,7 @@ function createServer(options) {
1594
1594
  try {
1595
1595
  const result = await store.append(nsId(sessionId), validated, {
1596
1596
  consumers: storeConsumers,
1597
- ...originIndex === void 0 ? {} : { originIndex }
1597
+ ...condition
1598
1598
  });
1599
1599
  rows = result.events;
1600
1600
  shouldHealSession = result.hasPending && !(source === "consumer" && !validated.some(startsWork));
@@ -2018,7 +2018,7 @@ function createServer(options) {
2018
2018
  assertScheduleName(scheduleName);
2019
2019
  if (clearOptions === null || typeof clearOptions !== "object") throw new TypeError("schedule.clear requires an ifLastIndex");
2020
2020
  const { ifLastIndex, ...timing } = clearOptions;
2021
- assertClearIndex(ifLastIndex);
2021
+ assertIfLastIndex(ifLastIndex);
2022
2022
  const dueAt = scheduleDueAt(timing, triggerCreatedAt ?? Date.now());
2023
2023
  const store = await resolveStore();
2024
2024
  if (!store.clear || !store.reclaim) throw new TypeError("session.schedule.clear requires a store that supports clearing");
@@ -2446,7 +2446,7 @@ function createServer(options) {
2446
2446
  };
2447
2447
  const clearSession = async (sessionId, clearOptions, attempt) => {
2448
2448
  const ifLastIndex = clearOptions?.ifLastIndex;
2449
- if (ifLastIndex !== void 0) assertClearIndex(ifLastIndex);
2449
+ if (ifLastIndex !== void 0) assertIfLastIndex(ifLastIndex);
2450
2450
  const store = await resolveStore();
2451
2451
  if (!store.clear || !store.reclaim) throw new TypeError("session.clear requires a store that supports clearing");
2452
2452
  const ns = nsId(sessionId);
@@ -3182,14 +3182,22 @@ function createServer(options) {
3182
3182
  ...schedulerArm ? { schedulerArm } : {}
3183
3183
  };
3184
3184
  });
3185
- const appendExternal = async (sessionId, mode, events, requireDurableInitialArm = false, originIndex) => {
3186
- return appendCore(sessionId, events, "external", mode, (_rows, watchdogDueAt) => scheduleDrain(sessionId, watchdogDueAt), void 0, void 0, requireDurableInitialArm, originIndex);
3185
+ const appendExternal = async (sessionId, mode, events, requireDurableInitialArm = false, condition = {}) => {
3186
+ return appendCore(sessionId, events, "external", mode, (_rows, watchdogDueAt) => scheduleDrain(sessionId, watchdogDueAt), void 0, void 0, requireDurableInitialArm, condition);
3187
3187
  };
3188
3188
  const session = (id) => {
3189
3189
  assertSessionId(id);
3190
3190
  const appendInline = async (...events) => appendExternal(id, "inline", events);
3191
3191
  const appendDispatch = async (...events) => appendExternal(id, "dispatch", events);
3192
- const append = Object.assign(appendInline, { dispatch: appendDispatch });
3192
+ const appendIfLastIndex = async (index, ...events) => {
3193
+ assertIfLastIndex(index);
3194
+ if (events.length === 0) throw new TypeError("append.ifLastIndex requires at least one event");
3195
+ return appendExternal(id, "inline", events, false, { ifLastIndex: index });
3196
+ };
3197
+ const append = Object.assign(appendInline, {
3198
+ dispatch: appendDispatch,
3199
+ ifLastIndex: appendIfLastIndex
3200
+ });
3193
3201
  return Object.assign(makeSession(id, append, null), {
3194
3202
  deadLetters: () => listDeadLetters(id),
3195
3203
  redrive: (target, redriveOptions) => redriveEvent(id, target, redriveOptions)
@@ -3233,7 +3241,7 @@ function createServer(options) {
3233
3241
  if (!scheduler) throw new TypeError("scheduled append delivery requires a configured scheduler adapter");
3234
3242
  assertSessionId(sessionId);
3235
3243
  try {
3236
- await appendExternal(sessionId, "inline", [...events], true, originIndex);
3244
+ await appendExternal(sessionId, "inline", [...events], true, originIndex === void 0 ? {} : { originIndex });
3237
3245
  } catch (error) {
3238
3246
  if (originIndex !== void 0 && error instanceof A2Error && error.code === "SESSION_CLEARED") return;
3239
3247
  throw error;
@@ -3242,7 +3250,7 @@ function createServer(options) {
3242
3250
  historyWithMarkers: async (sessionId, gte) => (await readHistory(sessionId, { gte })).map(toPublic),
3243
3251
  schedulerClear: async (sessionId, ifLastIndex) => {
3244
3252
  assertSessionId(sessionId);
3245
- assertClearIndex(ifLastIndex);
3253
+ assertIfLastIndex(ifLastIndex);
3246
3254
  await clearSession(sessionId, { ifLastIndex }, void 0);
3247
3255
  }
3248
3256
  });
@@ -3267,7 +3275,7 @@ function assertConsumeIndex(value) {
3267
3275
  function assertRedriveIndex(value) {
3268
3276
  if (!Number.isSafeInteger(value) || value < 1) throw new TypeError("redrive requires a positive safe-integer index");
3269
3277
  }
3270
- function assertClearIndex(value) {
3278
+ function assertIfLastIndex(value) {
3271
3279
  if (!Number.isSafeInteger(value) || value < 0) throw new TypeError("ifLastIndex must be a non-negative safe integer");
3272
3280
  }
3273
3281
  function assertAppendName(name) {
@@ -3359,4 +3367,4 @@ const stateCacheKey = (sessionId, reducerName) => `${sessionId}\u0000${reducerNa
3359
3367
  //#endregion
3360
3368
  export { CONSOLE_TELEMETRY as a, parsePresenceSibling as c, deliverSchedulerClear as i, createServer as n, setServerFetchHooks as o, deliverSchedulerAppend as r, sseResponse as s, consumer as t };
3361
3369
 
3362
- //# sourceMappingURL=server-DtFrWxi3.js.map
3370
+ //# sourceMappingURL=server-DX7mM6nm.js.map