@earendil-works/chord 1.1.0 → 1.3.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 (190) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +79 -195
  3. package/dist/cell.d.ts +122 -0
  4. package/dist/cell.d.ts.map +1 -0
  5. package/dist/cell.js +356 -0
  6. package/dist/cell.js.map +1 -0
  7. package/dist/cluster.d.ts +27 -0
  8. package/dist/cluster.d.ts.map +1 -0
  9. package/dist/cluster.js +230 -0
  10. package/dist/cluster.js.map +1 -0
  11. package/dist/connection.d.ts +270 -0
  12. package/dist/connection.d.ts.map +1 -0
  13. package/dist/connection.js +1216 -0
  14. package/dist/connection.js.map +1 -0
  15. package/dist/context/index.d.ts +12 -1
  16. package/dist/context/index.d.ts.map +1 -1
  17. package/dist/context/index.js.map +1 -1
  18. package/dist/contract.d.ts +208 -0
  19. package/dist/contract.d.ts.map +1 -0
  20. package/dist/contract.js +246 -0
  21. package/dist/contract.js.map +1 -0
  22. package/dist/declare.d.ts +33 -0
  23. package/dist/declare.d.ts.map +1 -0
  24. package/dist/declare.js +2 -0
  25. package/dist/declare.js.map +1 -0
  26. package/dist/delta/apply-immutable-trusted.js.map +1 -1
  27. package/dist/delta/diff.d.ts +1 -1
  28. package/dist/delta/diff.d.ts.map +1 -1
  29. package/dist/delta/diff.js.map +1 -1
  30. package/dist/delta/index.d.ts +4 -3
  31. package/dist/delta/index.d.ts.map +1 -1
  32. package/dist/delta/index.js +45 -0
  33. package/dist/delta/index.js.map +1 -1
  34. package/dist/delta/revision-validator.d.ts +1 -1
  35. package/dist/delta/revision-validator.d.ts.map +1 -1
  36. package/dist/delta/revision-validator.js.map +1 -1
  37. package/dist/delta/tracker.d.ts +1 -1
  38. package/dist/delta/tracker.d.ts.map +1 -1
  39. package/dist/delta/tracker.js +40 -4
  40. package/dist/delta/tracker.js.map +1 -1
  41. package/dist/errors.d.ts +28 -0
  42. package/dist/errors.d.ts.map +1 -0
  43. package/dist/errors.js +59 -0
  44. package/dist/errors.js.map +1 -0
  45. package/dist/host.d.ts +348 -0
  46. package/dist/host.d.ts.map +1 -0
  47. package/dist/host.js +1000 -0
  48. package/dist/host.js.map +1 -0
  49. package/dist/index.d.ts +17 -10
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +8 -8
  52. package/dist/index.js.map +1 -1
  53. package/dist/json.d.ts +9 -1
  54. package/dist/json.d.ts.map +1 -1
  55. package/dist/json.js.map +1 -1
  56. package/dist/link.d.ts +107 -0
  57. package/dist/link.d.ts.map +1 -0
  58. package/dist/link.js +355 -0
  59. package/dist/link.js.map +1 -0
  60. package/dist/loader.d.ts +4 -0
  61. package/dist/loader.d.ts.map +1 -0
  62. package/dist/loader.js +73 -0
  63. package/dist/loader.js.map +1 -0
  64. package/dist/manager.d.ts +115 -0
  65. package/dist/manager.d.ts.map +1 -0
  66. package/dist/manager.js +345 -0
  67. package/dist/manager.js.map +1 -0
  68. package/dist/node.d.ts +3 -4
  69. package/dist/node.d.ts.map +1 -1
  70. package/dist/node.js +3 -2
  71. package/dist/node.js.map +1 -1
  72. package/dist/object.d.ts +438 -0
  73. package/dist/object.d.ts.map +1 -0
  74. package/dist/object.js +1571 -0
  75. package/dist/object.js.map +1 -0
  76. package/dist/output.d.ts +85 -0
  77. package/dist/output.d.ts.map +1 -0
  78. package/dist/output.js +350 -0
  79. package/dist/output.js.map +1 -0
  80. package/dist/publish.d.ts +5 -0
  81. package/dist/publish.d.ts.map +1 -0
  82. package/dist/publish.js +40 -0
  83. package/dist/publish.js.map +1 -0
  84. package/dist/registry.d.ts +25 -0
  85. package/dist/registry.d.ts.map +1 -0
  86. package/dist/registry.js +6 -0
  87. package/dist/registry.js.map +1 -0
  88. package/dist/reload.d.ts +126 -0
  89. package/dist/reload.d.ts.map +1 -0
  90. package/dist/reload.js +653 -0
  91. package/dist/reload.js.map +1 -0
  92. package/dist/remote.d.ts +165 -0
  93. package/dist/remote.d.ts.map +1 -0
  94. package/dist/remote.js +612 -0
  95. package/dist/remote.js.map +1 -0
  96. package/dist/schema.d.ts +21 -0
  97. package/dist/schema.d.ts.map +1 -0
  98. package/dist/schema.js +228 -0
  99. package/dist/schema.js.map +1 -0
  100. package/dist/state.d.ts +92 -0
  101. package/dist/state.d.ts.map +1 -0
  102. package/dist/{services/state.js → state.js} +28 -138
  103. package/dist/state.js.map +1 -0
  104. package/dist/types.d.ts +69 -258
  105. package/dist/types.d.ts.map +1 -1
  106. package/dist/types.js.map +1 -1
  107. package/dist/websocket.d.ts +15 -0
  108. package/dist/websocket.d.ts.map +1 -0
  109. package/dist/websocket.js +16 -0
  110. package/dist/websocket.js.map +1 -0
  111. package/dist/wire.d.ts +216 -0
  112. package/dist/wire.d.ts.map +1 -0
  113. package/dist/wire.js +165 -0
  114. package/dist/wire.js.map +1 -0
  115. package/docs/guide.md +814 -0
  116. package/docs/spec.md +288 -0
  117. package/docs/tutorial.md +931 -0
  118. package/package.json +14 -10
  119. package/src/delta/README.md +5 -3
  120. package/dist/api.d.ts +0 -20
  121. package/dist/api.d.ts.map +0 -1
  122. package/dist/api.js +0 -77
  123. package/dist/api.js.map +0 -1
  124. package/dist/bundler.d.ts +0 -6
  125. package/dist/bundler.d.ts.map +0 -1
  126. package/dist/bundler.js +0 -3
  127. package/dist/bundler.js.map +0 -1
  128. package/dist/facets/host.d.ts +0 -12
  129. package/dist/facets/host.d.ts.map +0 -1
  130. package/dist/facets/host.js +0 -763
  131. package/dist/facets/host.js.map +0 -1
  132. package/dist/facets/loader.d.ts +0 -3
  133. package/dist/facets/loader.d.ts.map +0 -1
  134. package/dist/facets/loader.js +0 -5
  135. package/dist/facets/loader.js.map +0 -1
  136. package/dist/node/bundle-loader.d.ts +0 -30
  137. package/dist/node/bundle-loader.d.ts.map +0 -1
  138. package/dist/node/bundle-loader.js +0 -377
  139. package/dist/node/bundle-loader.js.map +0 -1
  140. package/dist/node/bundle.d.ts +0 -26
  141. package/dist/node/bundle.d.ts.map +0 -1
  142. package/dist/node/bundle.js +0 -183
  143. package/dist/node/bundle.js.map +0 -1
  144. package/dist/node/manifest.d.ts +0 -36
  145. package/dist/node/manifest.d.ts.map +0 -1
  146. package/dist/node/manifest.js +0 -6
  147. package/dist/node/manifest.js.map +0 -1
  148. package/dist/node/package.d.ts +0 -15
  149. package/dist/node/package.d.ts.map +0 -1
  150. package/dist/node/package.js +0 -199
  151. package/dist/node/package.js.map +0 -1
  152. package/dist/services/consumer.d.ts +0 -11
  153. package/dist/services/consumer.d.ts.map +0 -1
  154. package/dist/services/consumer.js +0 -585
  155. package/dist/services/consumer.js.map +0 -1
  156. package/dist/services/errors.d.ts +0 -8
  157. package/dist/services/errors.d.ts.map +0 -1
  158. package/dist/services/errors.js +0 -22
  159. package/dist/services/errors.js.map +0 -1
  160. package/dist/services/handle.d.ts +0 -15
  161. package/dist/services/handle.d.ts.map +0 -1
  162. package/dist/services/handle.js +0 -101
  163. package/dist/services/handle.js.map +0 -1
  164. package/dist/services/instances.d.ts +0 -26
  165. package/dist/services/instances.d.ts.map +0 -1
  166. package/dist/services/instances.js +0 -140
  167. package/dist/services/instances.js.map +0 -1
  168. package/dist/services/loopback.d.ts +0 -5
  169. package/dist/services/loopback.d.ts.map +0 -1
  170. package/dist/services/loopback.js +0 -15
  171. package/dist/services/loopback.js.map +0 -1
  172. package/dist/services/provider.d.ts +0 -37
  173. package/dist/services/provider.d.ts.map +0 -1
  174. package/dist/services/provider.js +0 -521
  175. package/dist/services/provider.js.map +0 -1
  176. package/dist/services/state-codec.d.ts +0 -15
  177. package/dist/services/state-codec.d.ts.map +0 -1
  178. package/dist/services/state-codec.js +0 -133
  179. package/dist/services/state-codec.js.map +0 -1
  180. package/dist/services/state-internals.d.ts +0 -13
  181. package/dist/services/state-internals.d.ts.map +0 -1
  182. package/dist/services/state-internals.js +0 -10
  183. package/dist/services/state-internals.js.map +0 -1
  184. package/dist/services/state.d.ts +0 -28
  185. package/dist/services/state.d.ts.map +0 -1
  186. package/dist/services/state.js.map +0 -1
  187. package/dist/services/wire.d.ts +0 -63
  188. package/dist/services/wire.d.ts.map +0 -1
  189. package/dist/services/wire.js +0 -186
  190. package/dist/services/wire.js.map +0 -1
@@ -1,7 +1,10 @@
1
- import { BACKGROUND_CONTEXT } from "../context/index.js";
2
- import { applyImmutable, isBase, track } from "../delta/index.js";
3
- import { JsonRevisionValidator } from "../delta/revision-validator.js";
4
- import { registerReplicatedStateInternals } from "./state-internals.js";
1
+ /**
2
+ * Replicated state: an immutable JSON value with ordered, serialized change notifications. Either authoritative and
3
+ * mutable (`replicatedState(initial)`) or a publication-only view of an external revision source
4
+ * (`replicatedState(source)`).
5
+ */
6
+ import { BACKGROUND_CONTEXT } from "./context/index.js";
7
+ import { track } from "./delta/index.js";
5
8
  /** One public subscription, independent of producer and other subscriber progress. */
6
9
  class StateSubscriber {
7
10
  #listener;
@@ -72,7 +75,6 @@ class StateSubscriber {
72
75
  class ReplicatedStatePublisher {
73
76
  #listeners = new Map();
74
77
  #reportError;
75
- #sourceListeners = new Set();
76
78
  #publications = [];
77
79
  #value;
78
80
  #sequence = 0;
@@ -91,36 +93,24 @@ class ReplicatedStatePublisher {
91
93
  const { value, sequence } = this.snapshot();
92
94
  const subscriber = new StateSubscriber(listener, this.#reportError);
93
95
  this.#listeners.set(subscriber, sequence);
94
- subscriber.push({ value, context: serviceDeliveryContext(), delivery: { kind: "hydrate", sequence } });
96
+ // Hydration has no caller; it is delivered with the background context.
97
+ subscriber.push({ value, context: BACKGROUND_CONTEXT, delivery: { kind: "hydrate", sequence } });
95
98
  subscriber.drain();
96
99
  return () => {
97
100
  subscriber.close();
98
101
  this.#listeners.delete(subscriber);
99
102
  };
100
103
  }
101
- subscribeSource(listener) {
102
- this.#sourceListeners.add(listener);
103
- return () => this.#sourceListeners.delete(listener);
104
- }
105
- /** Publish an already-prepared immutable revision and return isolated listener failures. */
106
- publish(value, ops, context) {
104
+ /** Publish an already-prepared immutable revision. Subscriber failures are reported, never thrown. */
105
+ publish(value, context) {
107
106
  this.#value = value;
108
107
  this.#sequence += 1;
109
- this.#publications.push({ value, ops, sequence: this.#sequence, context });
108
+ this.#publications.push({ value, sequence: this.#sequence, context });
110
109
  if (this.#delivering)
111
- return [];
110
+ return;
112
111
  this.#delivering = true;
113
- const errors = [];
114
112
  try {
115
113
  for (let publication = this.#publications.shift(); publication !== undefined; publication = this.#publications.shift()) {
116
- for (const listener of [...this.#sourceListeners]) {
117
- try {
118
- listener(publication.ops, publication.sequence, publication.context);
119
- }
120
- catch (error) {
121
- errors.push(error);
122
- }
123
- }
124
114
  const delivery = { kind: "update", sequence: publication.sequence };
125
115
  for (const [subscriber, hydratedSequence] of [...this.#listeners]) {
126
116
  if (publication.sequence <= hydratedSequence)
@@ -133,20 +123,15 @@ class ReplicatedStatePublisher {
133
123
  finally {
134
124
  this.#delivering = false;
135
125
  }
136
- return errors;
137
126
  }
138
127
  }
139
- export class MutableReplicatedStateImpl {
128
+ class MutableReplicatedStateImpl {
140
129
  #tracker;
141
130
  #publisher;
142
131
  #changing = false;
143
132
  constructor(initial) {
144
133
  this.#tracker = track(initial);
145
134
  this.#publisher = new ReplicatedStatePublisher(this.#tracker.value);
146
- registerReplicatedStateInternals(this, {
147
- snapshot: () => this.#publisher.snapshot(),
148
- subscribe: (listener) => this.#publisher.subscribeSource(listener),
149
- });
150
135
  }
151
136
  get value() {
152
137
  return this.#tracker.value;
@@ -175,18 +160,16 @@ export class MutableReplicatedStateImpl {
175
160
  this.#changing = false;
176
161
  }
177
162
  this.#tracker.adopt(prepared);
178
- if (prepared.ops.length === 0)
179
- return;
180
- throwCollectedErrors(this.#publisher.publish(prepared.value, prepared.ops, context), "Replicated state listeners failed");
163
+ if (prepared.ops.length > 0)
164
+ this.#publisher.publish(prepared.value, context);
181
165
  }
182
166
  replace(context, value) {
183
167
  if (this.#changing)
184
168
  throw new Error("Replicated state cannot be replaced from a change callback");
185
169
  const prepared = this.#tracker.prepareReplace(value);
186
170
  this.#tracker.adopt(prepared);
187
- if (prepared.ops.length === 0)
188
- return;
189
- throwCollectedErrors(this.#publisher.publish(prepared.value, prepared.ops, context), "Replicated state listeners failed");
171
+ if (prepared.ops.length > 0)
172
+ this.#publisher.publish(prepared.value, context);
190
173
  }
191
174
  subscribe(listener) {
192
175
  return this.#publisher.subscribe(listener);
@@ -205,10 +188,6 @@ class AttachedReplicatedStateImpl {
205
188
  this.#cursor = snapshot.cursor;
206
189
  this.#reportError = options.onError ?? reportErrorAsync;
207
190
  this.#publisher = new ReplicatedStatePublisher(snapshot.value, (error) => this.#report(error));
208
- registerReplicatedStateInternals(this, {
209
- snapshot: () => this.#publisher.snapshot(),
210
- subscribe: (listener) => this.#publisher.subscribeSource(listener),
211
- });
212
191
  }
213
192
  get value() {
214
193
  return this.#publisher.value;
@@ -235,11 +214,7 @@ class AttachedReplicatedStateImpl {
235
214
  throw new Error(`Replicated state source cursor has a gap: expected ${expected}, received ${frame.cursor}`);
236
215
  }
237
216
  this.#cursor = frame.cursor;
238
- const errors = this.#publisher.publish(frame.value, frame.ops, frame.context);
239
- if (errors.length === 1)
240
- this.#report(errors[0]);
241
- else if (errors.length > 1)
242
- this.#report(new AggregateError(errors, "Replicated state listeners failed"));
217
+ this.#publisher.publish(frame.value, frame.context);
243
218
  }
244
219
  catch (error) {
245
220
  this.#fail(toError(error));
@@ -268,7 +243,7 @@ class AttachedReplicatedStateImpl {
268
243
  }
269
244
  }
270
245
  /** Attach a publication-only replicated state to one authoritative immutable source stream. */
271
- export function attachReplicatedStateSource(source, options = {}) {
246
+ function attachReplicatedStateSource(source, options = {}) {
272
247
  const attachment = source.attach();
273
248
  try {
274
249
  const state = new AttachedReplicatedStateImpl(attachment, options);
@@ -285,93 +260,6 @@ export function attachReplicatedStateSource(source, options = {}) {
285
260
  throw error;
286
261
  }
287
262
  }
288
- /** A cold read-only state used by service consumers until a complete snapshot arrives. */
289
- export class ReplicatedStateReplica {
290
- #listeners = new Set();
291
- #reportError;
292
- #validator = new JsonRevisionValidator();
293
- #value;
294
- #sequence;
295
- constructor(reportError) {
296
- this.#reportError = reportError;
297
- }
298
- get value() {
299
- return this.#value;
300
- }
301
- subscribe(listener) {
302
- const subscriber = new StateSubscriber(listener, this.#reportError);
303
- this.#listeners.add(subscriber);
304
- if (this.#value !== undefined) {
305
- subscriber.push({
306
- value: this.#value,
307
- context: serviceDeliveryContext(),
308
- delivery: { kind: "hydrate", sequence: this.#sequence },
309
- });
310
- subscriber.drain();
311
- }
312
- return () => {
313
- subscriber.close();
314
- this.#listeners.delete(subscriber);
315
- };
316
- }
317
- hydrate(sequence, ops, context) {
318
- let next;
319
- try {
320
- if (!isBase(ops))
321
- throw new Error("Replicated state snapshot is not a base operation batch");
322
- next = this.#validator.validate(applyImmutable(undefined, ops));
323
- }
324
- catch (error) {
325
- this.clear();
326
- throw error;
327
- }
328
- this.#sequence = sequence;
329
- this.#value = next;
330
- this.#deliverAll(context, { kind: "hydrate", sequence });
331
- }
332
- update(sequence, ops, context) {
333
- if (this.#sequence === undefined || this.#value === undefined) {
334
- throw new Error("Replicated state received an update before hydration");
335
- }
336
- if (sequence !== this.#sequence + 1) {
337
- this.clear();
338
- throw new Error("Replicated state update sequence has a gap");
339
- }
340
- let next;
341
- try {
342
- next = this.#validator.validate(applyImmutable(this.#value, ops));
343
- }
344
- catch (error) {
345
- this.clear();
346
- throw error;
347
- }
348
- this.#sequence = sequence;
349
- this.#value = next;
350
- this.#deliverAll(context, { kind: "update", sequence });
351
- }
352
- clear() {
353
- this.#value = undefined;
354
- this.#sequence = undefined;
355
- for (const subscriber of this.#listeners)
356
- subscriber.clear();
357
- }
358
- #deliverAll(context, delivery) {
359
- if (this.#value === undefined)
360
- return;
361
- const frame = { value: this.#value, context, delivery };
362
- const subscribers = [...this.#listeners];
363
- // Enqueue for everyone before user code can publish another revision reentrantly.
364
- for (const subscriber of subscribers)
365
- subscriber.push(frame);
366
- for (const subscriber of subscribers)
367
- subscriber.drain();
368
- }
369
- }
370
- /** @internal Context for synthetic service deliveries without a caller. */
371
- export function serviceDeliveryContext() {
372
- // TODO: Add delivery-scoped cancellation or metadata if deliveries gain an owned lifecycle.
373
- return BACKGROUND_CONTEXT;
374
- }
375
263
  function assertCursor(cursor, kind) {
376
264
  if (!Number.isSafeInteger(cursor))
377
265
  throw new TypeError(`Replicated state source ${kind} cursor must be a safe integer`);
@@ -380,12 +268,6 @@ function isPromiseLike(value) {
380
268
  return (((typeof value === "object" && value !== null) || typeof value === "function") &&
381
269
  typeof value.then === "function");
382
270
  }
383
- function throwCollectedErrors(errors, message) {
384
- if (errors.length === 1)
385
- throw errors[0];
386
- if (errors.length > 1)
387
- throw new AggregateError(errors, message);
388
- }
389
271
  function reportErrorAsync(error) {
390
272
  queueMicrotask(() => {
391
273
  throw error;
@@ -394,4 +276,12 @@ function reportErrorAsync(error) {
394
276
  function toError(error) {
395
277
  return error instanceof Error ? error : new Error(String(error));
396
278
  }
279
+ export function replicatedState(initialOrSource, options) {
280
+ if (isReplicatedStateSource(initialOrSource))
281
+ return attachReplicatedStateSource(initialOrSource, options);
282
+ return new MutableReplicatedStateImpl(initialOrSource);
283
+ }
284
+ function isReplicatedStateSource(value) {
285
+ return typeof value.attach === "function";
286
+ }
397
287
  //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Replicated state: an immutable JSON value with ordered, serialized change notifications. Either authoritative and\n * mutable (`replicatedState(initial)`) or a publication-only view of an external revision source\n * (`replicatedState(source)`).\n */\nimport { BACKGROUND_CONTEXT, type Context } from \"./context/index.ts\";\nimport { type Draft, type Op, type Prepared, type Tracker, track } from \"./delta/index.ts\";\n\nexport interface ReplicatedStateDelivery {\n\treadonly kind: \"hydrate\" | \"update\";\n\treadonly sequence: number;\n}\n\nexport interface ReplicatedState<T> {\n\t/**\n\t * Contract-immutable value, or undefined until hydration. It is not frozen and may share containers with an\n\t * in-process provider; consumers must not mutate it. Later updates do not mutate previously returned values.\n\t */\n\treadonly value: T | undefined;\n\t/**\n\t * Each subscription serializes callbacks, awaiting hydration before updates. Values are immutable and may\n\t * share unchanged revision data. At most 100 deliveries wait behind the running callback; overflow keeps\n\t * only the newest pending value/context/delivery, so update sequences may skip. Failures are reported in\n\t * isolation and delivery continues. Unsubscribe discards pending work without aborting or joining a callback.\n\t */\n\tsubscribe(listener: (value: T, context: Context, delivery: ReplicatedStateDelivery) => Promise<void>): () => void;\n\tsubscribe(listener: (value: T, context: Context, delivery: ReplicatedStateDelivery) => void): () => void;\n}\n\nexport interface MutableReplicatedState<T extends object> extends ReplicatedState<T> {\n\treadonly value: T;\n\t/**\n\t * Atomically publish one synchronous overlay mutation. Draft handles are unusable after the callback returns.\n\t * Values placed through the draft are cloned by value; assigning `undefined` to an object property deletes it.\n\t */\n\tchange(context: Context, mutate: (draft: Draft<T>) => void): void;\n\t/**\n\t * Atomically take immutable ownership of an alias-free strict-JSON replacement.\n\t * The caller must not mutate the transferred root after this call.\n\t */\n\treplace(context: Context, value: T): void;\n}\n\n/** One immutable authoritative revision committed after an attachment snapshot. */\nexport interface ReplicatedStateSourceFrame<T> {\n\t/** Monotonic source cursor. The first frame after a snapshot must be `snapshot.cursor + 1`. */\n\treadonly cursor: number;\n\t/** The exact immutable value produced by this commit. */\n\treadonly value: T;\n\t/** The exact immutable operation batch that produced `value` from the preceding source revision. */\n\treadonly ops: readonly Op[];\n\treadonly context: Context;\n}\n\nexport interface ReplicatedStateSourceAttachment<T> {\n\t/** Fixed immutable snapshot captured at the atomic attachment boundary. */\n\treadonly snapshot: { readonly value: T; readonly cursor: number };\n\t/**\n\t * Install the sole listener and synchronously drain every buffered frame in source commit order.\n\t * This method is single-use. After it begins, every new committed frame must also be delivered in order\n\t * until disposal, including commits made reentrantly while a prior frame is being delivered.\n\t */\n\tactivate(listener: (frame: ReplicatedStateSourceFrame<T>) => void): void;\n\t/** Stop delivery and release source resources. Disposal must be idempotent. */\n\tdispose(): void;\n}\n\n/**\n * An authoritative immutable revision source.\n *\n * `attach()` must synchronously and atomically capture one snapshot and register the returned attachment to buffer\n * every later committed frame. The snapshot must include every commit before that boundary; buffered frames must\n * include every commit after it, with no overlap or gap. Snapshot values, frame values, and operation batches are\n * immutable and remain valid after delivery. Chord only publishes these references; it never applies or re-diffs them.\n */\nexport interface ReplicatedStateSource<T> {\n\tattach(): ReplicatedStateSourceAttachment<T>;\n}\n\nexport interface ReplicatedStateSourceOptions {\n\t/** Receives source-contract and publication-listener failures without throwing them into the source. */\n\treadonly onError?: (error: Error) => void;\n}\n\n/** A synchronously hydrated publication-only state backed by one source attachment. */\nexport interface AttachedReplicatedState<T> extends ReplicatedState<T> {\n\treadonly value: T;\n\t/** Idempotently release the source attachment. The last published value remains readable. */\n\tdispose(): void;\n}\n\n/** The void signature also accepts synchronous callbacks that return an ignored value. */\ntype StateListener<T> = (value: T, context: Context, delivery: ReplicatedStateDelivery) => void;\n\ntype StateDelivery<T> = {\n\treadonly value: T;\n\treadonly context: Context;\n\treadonly delivery: ReplicatedStateDelivery;\n};\n\n/** One public subscription, independent of producer and other subscriber progress. */\nclass StateSubscriber<T> {\n\treadonly #listener: StateListener<T>;\n\treadonly #reportError: (error: Error) => void;\n\treadonly #pending: StateDelivery<T>[] = [];\n\t#running = false;\n\t#started = false;\n\t#closed = false;\n\n\tconstructor(listener: StateListener<T>, reportError: (error: Error) => void) {\n\t\tthis.#listener = listener;\n\t\tthis.#reportError = reportError;\n\t}\n\n\tpush(frame: StateDelivery<T>): void {\n\t\tif (this.#closed) return;\n\t\tif (this.#pending.length === 100) {\n\t\t\t// A cold replica can queue updates reentrantly before this subscriber's first hydration starts.\n\t\t\tconst hydration = this.#started ? undefined : this.#pending[0];\n\t\t\tthis.#pending.length = 0;\n\t\t\tif (hydration !== undefined) this.#pending.push(hydration);\n\t\t}\n\t\tthis.#pending.push(frame);\n\t}\n\n\tdrain(): void {\n\t\tif (this.#running || this.#closed) return;\n\t\tthis.#running = true;\n\t\tfor (let frame = this.#pending.shift(); frame !== undefined; frame = this.#pending.shift()) {\n\t\t\tthis.#started = true;\n\t\t\ttry {\n\t\t\t\tconst result: unknown = this.#listener(frame.value, frame.context, frame.delivery);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\tvoid Promise.resolve(result).then(\n\t\t\t\t\t\t() => this.#resume(),\n\t\t\t\t\t\t(error: unknown) => {\n\t\t\t\t\t\t\tthis.#report(error);\n\t\t\t\t\t\t\tthis.#resume();\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.#report(error);\n\t\t\t}\n\t\t}\n\t\tthis.#running = false;\n\t}\n\n\tclear(): void {\n\t\tthis.#pending.length = 0;\n\t}\n\n\tclose(): void {\n\t\tthis.#closed = true;\n\t\tthis.clear();\n\t}\n\n\t#resume(): void {\n\t\tthis.#running = false;\n\t\tthis.drain();\n\t}\n\n\t#report(error: unknown): void {\n\t\ttry {\n\t\t\tthis.#reportError(toError(error));\n\t\t} catch (reportError) {\n\t\t\treportErrorAsync(toError(reportError));\n\t\t}\n\t}\n}\n\ntype Publication<T> = {\n\treadonly value: T;\n\treadonly sequence: number;\n\treadonly context: Context;\n};\n\n/** Maintains local publication order independently of how revisions are produced. */\nclass ReplicatedStatePublisher<T> {\n\treadonly #listeners = new Map<StateSubscriber<T>, number>();\n\treadonly #reportError: (error: Error) => void;\n\treadonly #publications: Publication<T>[] = [];\n\t#value: T;\n\t#sequence = 0;\n\t#delivering = false;\n\n\tconstructor(initial: T, reportError: (error: Error) => void = reportErrorAsync) {\n\t\tthis.#value = initial;\n\t\tthis.#reportError = reportError;\n\t}\n\n\tget value(): T {\n\t\treturn this.#value;\n\t}\n\n\tsnapshot(): { readonly value: T; readonly sequence: number } {\n\t\treturn { value: this.#value, sequence: this.#sequence };\n\t}\n\n\tsubscribe(listener: StateListener<T>): () => void {\n\t\tconst { value, sequence } = this.snapshot();\n\t\tconst subscriber = new StateSubscriber(listener, this.#reportError);\n\t\tthis.#listeners.set(subscriber, sequence);\n\t\t// Hydration has no caller; it is delivered with the background context.\n\t\tsubscriber.push({ value, context: BACKGROUND_CONTEXT, delivery: { kind: \"hydrate\", sequence } });\n\t\tsubscriber.drain();\n\t\treturn () => {\n\t\t\tsubscriber.close();\n\t\t\tthis.#listeners.delete(subscriber);\n\t\t};\n\t}\n\n\t/** Publish an already-prepared immutable revision. Subscriber failures are reported, never thrown. */\n\tpublish(value: T, context: Context): void {\n\t\tthis.#value = value;\n\t\tthis.#sequence += 1;\n\t\tthis.#publications.push({ value, sequence: this.#sequence, context });\n\t\tif (this.#delivering) return;\n\n\t\tthis.#delivering = true;\n\t\ttry {\n\t\t\tfor (\n\t\t\t\tlet publication = this.#publications.shift();\n\t\t\t\tpublication !== undefined;\n\t\t\t\tpublication = this.#publications.shift()\n\t\t\t) {\n\t\t\t\tconst delivery = { kind: \"update\", sequence: publication.sequence } as const;\n\t\t\t\tfor (const [subscriber, hydratedSequence] of [...this.#listeners]) {\n\t\t\t\t\tif (publication.sequence <= hydratedSequence) continue;\n\t\t\t\t\tsubscriber.push({ value: publication.value, context: publication.context, delivery });\n\t\t\t\t\tsubscriber.drain();\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#delivering = false;\n\t\t}\n\t}\n}\n\nclass MutableReplicatedStateImpl<T extends object> implements MutableReplicatedState<T> {\n\treadonly #tracker: Tracker<T>;\n\treadonly #publisher: ReplicatedStatePublisher<T>;\n\t#changing = false;\n\n\tconstructor(initial: T) {\n\t\tthis.#tracker = track(initial);\n\t\tthis.#publisher = new ReplicatedStatePublisher(this.#tracker.value);\n\t}\n\n\tget value(): T {\n\t\treturn this.#tracker.value;\n\t}\n\n\tchange(context: Context, mutate: Parameters<MutableReplicatedState<T>[\"change\"]>[1]): void {\n\t\tif (this.#changing) throw new Error(\"Replicated state cannot be changed reentrantly from a change callback\");\n\t\tthis.#changing = true;\n\t\tlet prepared: Prepared<T>;\n\t\ttry {\n\t\t\tconst change = this.#tracker.beginChange();\n\t\t\ttry {\n\t\t\t\tconst outcome = (mutate as (draft: typeof change.state) => unknown)(change.state);\n\t\t\t\tif (isPromiseLike(outcome)) {\n\t\t\t\t\tvoid Promise.resolve(outcome).catch(() => undefined);\n\t\t\t\t\tthrow new TypeError(\"Replicated state change callbacks must be synchronous\");\n\t\t\t\t}\n\t\t\t\tprepared = change.prepare();\n\t\t\t} catch (error) {\n\t\t\t\tchange.abort();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#changing = false;\n\t\t}\n\n\t\tthis.#tracker.adopt(prepared);\n\t\tif (prepared.ops.length > 0) this.#publisher.publish(prepared.value, context);\n\t}\n\n\treplace(context: Context, value: T): void {\n\t\tif (this.#changing) throw new Error(\"Replicated state cannot be replaced from a change callback\");\n\t\tconst prepared = this.#tracker.prepareReplace(value);\n\t\tthis.#tracker.adopt(prepared);\n\t\tif (prepared.ops.length > 0) this.#publisher.publish(prepared.value, context);\n\t}\n\n\tsubscribe(listener: StateListener<T>): () => void {\n\t\treturn this.#publisher.subscribe(listener);\n\t}\n}\n\nclass AttachedReplicatedStateImpl<T> implements AttachedReplicatedState<T> {\n\treadonly #publisher: ReplicatedStatePublisher<T>;\n\treadonly #attachment: ReplicatedStateSourceAttachment<T>;\n\treadonly #reportError: (error: Error) => void;\n\t#cursor: number;\n\t#disposed = false;\n\n\tconstructor(attachment: ReplicatedStateSourceAttachment<T>, options: ReplicatedStateSourceOptions) {\n\t\tconst { snapshot } = attachment;\n\t\tassertCursor(snapshot.cursor, \"snapshot\");\n\t\tthis.#attachment = attachment;\n\t\tthis.#cursor = snapshot.cursor;\n\t\tthis.#reportError = options.onError ?? reportErrorAsync;\n\t\tthis.#publisher = new ReplicatedStatePublisher(snapshot.value, (error) => this.#report(error));\n\t}\n\n\tget value(): T {\n\t\treturn this.#publisher.value;\n\t}\n\n\tsubscribe(listener: StateListener<T>): () => void {\n\t\treturn this.#publisher.subscribe(listener);\n\t}\n\n\tactivate(): void {\n\t\tthis.#attachment.activate((frame) => this.#receive(frame));\n\t}\n\n\tdispose(): void {\n\t\tif (this.#disposed) return;\n\t\tthis.#disposed = true;\n\t\tthis.#attachment.dispose();\n\t}\n\n\t#receive(frame: ReplicatedStateSourceFrame<T>): void {\n\t\tif (this.#disposed) return;\n\t\ttry {\n\t\t\tassertCursor(frame.cursor, \"frame\");\n\t\t\tconst expected = this.#cursor + 1;\n\t\t\tif (frame.cursor !== expected) {\n\t\t\t\tthrow new Error(`Replicated state source cursor has a gap: expected ${expected}, received ${frame.cursor}`);\n\t\t\t}\n\t\t\tthis.#cursor = frame.cursor;\n\t\t\tthis.#publisher.publish(frame.value, frame.context);\n\t\t} catch (error) {\n\t\t\tthis.#fail(toError(error));\n\t\t}\n\t}\n\n\t#fail(error: Error): void {\n\t\tif (this.#disposed) return;\n\t\tthis.#disposed = true;\n\t\ttry {\n\t\t\tthis.#attachment.dispose();\n\t\t} catch (disposeError) {\n\t\t\tthis.#report(new AggregateError([error, disposeError], \"Replicated state source contract failed\"));\n\t\t\treturn;\n\t\t}\n\t\tthis.#report(error);\n\t}\n\n\t#report(error: unknown): void {\n\t\ttry {\n\t\t\tthis.#reportError(toError(error));\n\t\t} catch (reportError) {\n\t\t\treportErrorAsync(toError(reportError));\n\t\t}\n\t}\n}\n\n/** Attach a publication-only replicated state to one authoritative immutable source stream. */\nfunction attachReplicatedStateSource<T>(\n\tsource: ReplicatedStateSource<T>,\n\toptions: ReplicatedStateSourceOptions = {},\n): AttachedReplicatedState<T> {\n\tconst attachment = source.attach();\n\ttry {\n\t\tconst state = new AttachedReplicatedStateImpl(attachment, options);\n\t\tstate.activate();\n\t\treturn state;\n\t} catch (error) {\n\t\ttry {\n\t\t\tattachment.dispose();\n\t\t} catch (disposeError) {\n\t\t\tthrow new AggregateError([error, disposeError], \"Failed to attach replicated state source\");\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction assertCursor(cursor: number, kind: \"snapshot\" | \"frame\"): void {\n\tif (!Number.isSafeInteger(cursor))\n\t\tthrow new TypeError(`Replicated state source ${kind} cursor must be a safe integer`);\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n\treturn (\n\t\t((typeof value === \"object\" && value !== null) || typeof value === \"function\") &&\n\t\ttypeof (value as { then?: unknown }).then === \"function\"\n\t);\n}\n\nfunction reportErrorAsync(error: Error): void {\n\tqueueMicrotask(() => {\n\t\tthrow error;\n\t});\n}\n\nfunction toError(error: unknown): Error {\n\treturn error instanceof Error ? error : new Error(String(error));\n}\n\nexport function replicatedState<T>(\n\tsource: ReplicatedStateSource<T>,\n\toptions?: ReplicatedStateSourceOptions,\n): AttachedReplicatedState<T>;\n/**\n * Create authoritative state by taking immutable ownership of an alias-free strict-JSON root.\n * The caller must not mutate `initial` after this call.\n */\nexport function replicatedState<T extends object>(initial: T): MutableReplicatedState<T>;\nexport function replicatedState(\n\tinitialOrSource: object | ReplicatedStateSource<unknown>,\n\toptions?: ReplicatedStateSourceOptions,\n): MutableReplicatedState<object> | AttachedReplicatedState<unknown> {\n\tif (isReplicatedStateSource(initialOrSource)) return attachReplicatedStateSource(initialOrSource, options);\n\treturn new MutableReplicatedStateImpl(initialOrSource);\n}\n\nfunction isReplicatedStateSource(value: object): value is ReplicatedStateSource<unknown> {\n\treturn typeof (value as { readonly attach?: unknown }).attach === \"function\";\n}\n"]}