@earendil-works/chord 1.0.4 → 1.2.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 (186) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +77 -194
  3. package/dist/cell.d.ts +101 -0
  4. package/dist/cell.d.ts.map +1 -0
  5. package/dist/cell.js +316 -0
  6. package/dist/cell.js.map +1 -0
  7. package/dist/cluster.d.ts +26 -0
  8. package/dist/cluster.d.ts.map +1 -0
  9. package/dist/cluster.js +214 -0
  10. package/dist/cluster.js.map +1 -0
  11. package/dist/connection.d.ts +157 -0
  12. package/dist/connection.d.ts.map +1 -0
  13. package/dist/connection.js +757 -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 +133 -0
  19. package/dist/contract.d.ts.map +1 -0
  20. package/dist/contract.js +157 -0
  21. package/dist/contract.js.map +1 -0
  22. package/dist/declare.d.ts +70 -0
  23. package/dist/declare.d.ts.map +1 -0
  24. package/dist/declare.js +22 -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 +2 -2
  31. package/dist/delta/index.d.ts.map +1 -1
  32. package/dist/delta/index.js +41 -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 +27 -0
  42. package/dist/errors.d.ts.map +1 -0
  43. package/dist/errors.js +44 -0
  44. package/dist/errors.js.map +1 -0
  45. package/dist/host.d.ts +254 -0
  46. package/dist/host.d.ts.map +1 -0
  47. package/dist/host.js +795 -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 +72 -0
  57. package/dist/link.d.ts.map +1 -0
  58. package/dist/link.js +169 -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 +68 -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 +319 -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/publish.d.ts +5 -0
  73. package/dist/publish.d.ts.map +1 -0
  74. package/dist/publish.js +40 -0
  75. package/dist/publish.js.map +1 -0
  76. package/dist/record.d.ts +320 -0
  77. package/dist/record.d.ts.map +1 -0
  78. package/dist/record.js +1292 -0
  79. package/dist/record.js.map +1 -0
  80. package/dist/registry.d.ts +25 -0
  81. package/dist/registry.d.ts.map +1 -0
  82. package/dist/registry.js +6 -0
  83. package/dist/registry.js.map +1 -0
  84. package/dist/reload.d.ts +118 -0
  85. package/dist/reload.d.ts.map +1 -0
  86. package/dist/reload.js +589 -0
  87. package/dist/reload.js.map +1 -0
  88. package/dist/remote.d.ts +70 -0
  89. package/dist/remote.d.ts.map +1 -0
  90. package/dist/remote.js +308 -0
  91. package/dist/remote.js.map +1 -0
  92. package/dist/schema.d.ts +21 -0
  93. package/dist/schema.d.ts.map +1 -0
  94. package/dist/schema.js +228 -0
  95. package/dist/schema.js.map +1 -0
  96. package/dist/state.d.ts +92 -0
  97. package/dist/state.d.ts.map +1 -0
  98. package/dist/{services/state.js → state.js} +28 -138
  99. package/dist/state.js.map +1 -0
  100. package/dist/types.d.ts +62 -262
  101. package/dist/types.d.ts.map +1 -1
  102. package/dist/types.js.map +1 -1
  103. package/dist/websocket.d.ts +16 -0
  104. package/dist/websocket.d.ts.map +1 -0
  105. package/dist/websocket.js +15 -0
  106. package/dist/websocket.js.map +1 -0
  107. package/dist/wire.d.ts +135 -0
  108. package/dist/wire.d.ts.map +1 -0
  109. package/dist/wire.js +112 -0
  110. package/dist/wire.js.map +1 -0
  111. package/docs/guide.md +750 -0
  112. package/docs/spec.md +261 -0
  113. package/docs/tutorial.md +909 -0
  114. package/package.json +10 -11
  115. package/src/delta/README.md +5 -3
  116. package/dist/api.d.ts +0 -20
  117. package/dist/api.d.ts.map +0 -1
  118. package/dist/api.js +0 -77
  119. package/dist/api.js.map +0 -1
  120. package/dist/bundler.d.ts +0 -6
  121. package/dist/bundler.d.ts.map +0 -1
  122. package/dist/bundler.js +0 -3
  123. package/dist/bundler.js.map +0 -1
  124. package/dist/facets/host.d.ts +0 -12
  125. package/dist/facets/host.d.ts.map +0 -1
  126. package/dist/facets/host.js +0 -763
  127. package/dist/facets/host.js.map +0 -1
  128. package/dist/facets/loader.d.ts +0 -3
  129. package/dist/facets/loader.d.ts.map +0 -1
  130. package/dist/facets/loader.js +0 -5
  131. package/dist/facets/loader.js.map +0 -1
  132. package/dist/node/bundle-loader.d.ts +0 -30
  133. package/dist/node/bundle-loader.d.ts.map +0 -1
  134. package/dist/node/bundle-loader.js +0 -377
  135. package/dist/node/bundle-loader.js.map +0 -1
  136. package/dist/node/bundle.d.ts +0 -26
  137. package/dist/node/bundle.d.ts.map +0 -1
  138. package/dist/node/bundle.js +0 -183
  139. package/dist/node/bundle.js.map +0 -1
  140. package/dist/node/manifest.d.ts +0 -36
  141. package/dist/node/manifest.d.ts.map +0 -1
  142. package/dist/node/manifest.js +0 -6
  143. package/dist/node/manifest.js.map +0 -1
  144. package/dist/node/package.d.ts +0 -15
  145. package/dist/node/package.d.ts.map +0 -1
  146. package/dist/node/package.js +0 -199
  147. package/dist/node/package.js.map +0 -1
  148. package/dist/services/consumer.d.ts +0 -11
  149. package/dist/services/consumer.d.ts.map +0 -1
  150. package/dist/services/consumer.js +0 -585
  151. package/dist/services/consumer.js.map +0 -1
  152. package/dist/services/errors.d.ts +0 -8
  153. package/dist/services/errors.d.ts.map +0 -1
  154. package/dist/services/errors.js +0 -22
  155. package/dist/services/errors.js.map +0 -1
  156. package/dist/services/handle.d.ts +0 -15
  157. package/dist/services/handle.d.ts.map +0 -1
  158. package/dist/services/handle.js +0 -101
  159. package/dist/services/handle.js.map +0 -1
  160. package/dist/services/instances.d.ts +0 -26
  161. package/dist/services/instances.d.ts.map +0 -1
  162. package/dist/services/instances.js +0 -140
  163. package/dist/services/instances.js.map +0 -1
  164. package/dist/services/loopback.d.ts +0 -5
  165. package/dist/services/loopback.d.ts.map +0 -1
  166. package/dist/services/loopback.js +0 -15
  167. package/dist/services/loopback.js.map +0 -1
  168. package/dist/services/provider.d.ts +0 -37
  169. package/dist/services/provider.d.ts.map +0 -1
  170. package/dist/services/provider.js +0 -521
  171. package/dist/services/provider.js.map +0 -1
  172. package/dist/services/state-codec.d.ts +0 -15
  173. package/dist/services/state-codec.d.ts.map +0 -1
  174. package/dist/services/state-codec.js +0 -133
  175. package/dist/services/state-codec.js.map +0 -1
  176. package/dist/services/state-internals.d.ts +0 -13
  177. package/dist/services/state-internals.d.ts.map +0 -1
  178. package/dist/services/state-internals.js +0 -10
  179. package/dist/services/state-internals.js.map +0 -1
  180. package/dist/services/state.d.ts +0 -28
  181. package/dist/services/state.d.ts.map +0 -1
  182. package/dist/services/state.js.map +0 -1
  183. package/dist/services/wire.d.ts +0 -63
  184. package/dist/services/wire.d.ts.map +0 -1
  185. package/dist/services/wire.js +0 -186
  186. package/dist/services/wire.js.map +0 -1
package/dist/schema.js ADDED
@@ -0,0 +1,228 @@
1
+ import { Value } from "typebox/value";
2
+ import { invalid } from "./errors.js";
3
+ const asSchema = (schema) => schema !== null && typeof schema === "object" ? schema : schema === false ? { not: {} } : {};
4
+ /** Canonical JSON: sorted object keys, `undefined` members dropped. */
5
+ export function canonicalJson(value) {
6
+ if (value === null || typeof value !== "object")
7
+ return JSON.stringify(value) ?? "null";
8
+ if (Array.isArray(value))
9
+ return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
10
+ const keys = Object.keys(value)
11
+ .filter((key) => value[key] !== undefined)
12
+ .sort();
13
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
14
+ }
15
+ /** Non-cryptographic 64-bit hash (two FNV-1a lanes). Contracts are trusted, so collisions are not an attack surface. */
16
+ export function hash64(text) {
17
+ let a = 0x811c9dc5;
18
+ let b = 0x01000193 ^ 0x5bd1e995;
19
+ for (let index = 0; index < text.length; index++) {
20
+ const code = text.charCodeAt(index);
21
+ a = Math.imul(a ^ code, 0x01000193);
22
+ b = Math.imul(b ^ code, 0x5bd1e995) ^ (b >>> 13);
23
+ }
24
+ return (a >>> 0).toString(16).padStart(8, "0") + (b >>> 0).toString(16).padStart(8, "0");
25
+ }
26
+ export function deepEqual(a, b) {
27
+ return a === b || canonicalJson(a) === canonicalJson(b);
28
+ }
29
+ /** Throws `invalid` (with `reason`) and the first schema errors when `value` does not match. */
30
+ export function assertValid(reason, what, schema, value) {
31
+ if (Value.Check(schema, value))
32
+ return;
33
+ const errors = [...Value.Errors(schema, value)].slice(0, 3);
34
+ const summary = errors.map((error) => `${error.instancePath || "/"} ${error.message}`).join("; ");
35
+ throw invalid(reason, `${what}: ${summary}`, errors);
36
+ }
37
+ /** Applies defaults, strips unknown fields, validates. Returns a fresh value. */
38
+ export function normalize(schema, value, what) {
39
+ const normalized = Value.Clean(schema, Value.Default(schema, Value.Clone(value ?? {})));
40
+ assertValid("input", what, schema, normalized);
41
+ return normalized;
42
+ }
43
+ /** Canonical identity of a normalized value: fields equal to their schema default are omitted. */
44
+ export function canonicalIdentity(schema, value) {
45
+ return canonicalJson(stripDefaults(asSchema(schema), value));
46
+ }
47
+ function stripDefaults(schema, value) {
48
+ if (Array.isArray(value)) {
49
+ const items = schema.items;
50
+ if (Array.isArray(items))
51
+ return value.map((item, index) => stripDefaults(asSchema(items[index]), item));
52
+ return value.map((item) => stripDefaults(asSchema(items), item));
53
+ }
54
+ if (value === null || typeof value !== "object")
55
+ return value;
56
+ const properties = asSchema(schema.properties);
57
+ const result = {};
58
+ for (const [key, item] of Object.entries(value)) {
59
+ const property = asSchema(properties[key]);
60
+ if ("default" in property && deepEqual(property.default, item))
61
+ continue;
62
+ result[key] = stripDefaults(property, item);
63
+ }
64
+ return result;
65
+ }
66
+ const CONSTRAINTS = [
67
+ "minLength",
68
+ "maxLength",
69
+ "pattern",
70
+ "format",
71
+ "minimum",
72
+ "maximum",
73
+ "exclusiveMinimum",
74
+ "exclusiveMaximum",
75
+ "multipleOf",
76
+ "minItems",
77
+ "maxItems",
78
+ "uniqueItems",
79
+ "minProperties",
80
+ "maxProperties",
81
+ ];
82
+ const typesOf = (schema) => typeof schema.type === "string" ? [schema.type] : Array.isArray(schema.type) ? schema.type : undefined;
83
+ /** Keywords `fits` reasons about. Any other validation keyword in the provider's schema forces exact equality. */
84
+ const KNOWN = new Set([
85
+ ...CONSTRAINTS,
86
+ "type",
87
+ "properties",
88
+ "required",
89
+ "additionalProperties",
90
+ "patternProperties",
91
+ "items",
92
+ "additionalItems",
93
+ "const",
94
+ "enum",
95
+ "anyOf",
96
+ "parameters",
97
+ "returnType",
98
+ ]);
99
+ /** Annotations: no effect on validity. */
100
+ const ANNOTATIONS = new Set([
101
+ "title",
102
+ "description",
103
+ "default",
104
+ "examples",
105
+ "$id",
106
+ "$schema",
107
+ "$comment",
108
+ "readOnly",
109
+ "writeOnly",
110
+ "deprecated",
111
+ ]);
112
+ const withoutAnnotations = (schema) => Object.fromEntries(Object.entries(schema).filter(([key]) => !ANNOTATIONS.has(key)));
113
+ /**
114
+ * Conservative structural subtyping: true only if every value valid under `sub` is valid under `sup`, where object
115
+ * fields missing from `sub` but optional in `sup` count as fine (unknown fields are stripped at the provider, see
116
+ * `RecordImpl.call`). A provider schema using a keyword this function does not model (`not`, `allOf`, `contains`,
117
+ * `$ref`, ...) or an `additionalProperties` schema only fits an identical consumer schema.
118
+ */
119
+ export function fits(subSchema, supSchema) {
120
+ const sub = withoutAnnotations(asSchema(subSchema));
121
+ const sup = withoutAnnotations(asSchema(supSchema));
122
+ if (Object.keys(sup).length === 0)
123
+ return true;
124
+ if (deepEqual(sub, sup))
125
+ return true;
126
+ if (Object.keys(sup).some((key) => !KNOWN.has(key)))
127
+ return false;
128
+ if (sup.additionalProperties !== undefined && typeof sup.additionalProperties !== "boolean")
129
+ return false;
130
+ if (Array.isArray(sub.anyOf))
131
+ return sub.anyOf.every((branch) => fits(branch, sup));
132
+ if (Array.isArray(sup.anyOf))
133
+ return sup.anyOf.some((branch) => fits(sub, branch));
134
+ if ("const" in sup)
135
+ return "const" in sub && deepEqual(sub.const, sup.const);
136
+ if (Array.isArray(sup.enum)) {
137
+ const values = "const" in sub ? [sub.const] : Array.isArray(sub.enum) ? sub.enum : undefined;
138
+ return values?.every((item) => sup.enum.some((allowed) => deepEqual(allowed, item))) ?? false;
139
+ }
140
+ for (const key of CONSTRAINTS)
141
+ if (key in sup && !deepEqual(sub[key], sup[key]))
142
+ return false;
143
+ const supTypes = typesOf(sup);
144
+ const subTypes = typesOf(sub);
145
+ if (supTypes === undefined || subTypes === undefined)
146
+ return false;
147
+ if (!subTypes.every((type) => supTypes.includes(type) || (type === "integer" && supTypes.includes("number")))) {
148
+ return false;
149
+ }
150
+ if ("const" in sub || Array.isArray(sub.enum))
151
+ return true;
152
+ if (subTypes.includes("object") && !objectFits(sub, sup))
153
+ return false;
154
+ if (subTypes.includes("array") && !arrayFits(sub, sup))
155
+ return false;
156
+ if (subTypes.includes("function"))
157
+ return functionFits(sub, sup);
158
+ return true;
159
+ }
160
+ function objectFits(sub, sup) {
161
+ const subProperties = asSchema(sub.properties);
162
+ const supProperties = asSchema(sup.properties);
163
+ const subRequired = new Set(sub.required ?? []);
164
+ for (const key of sup.required ?? [])
165
+ if (!subRequired.has(key))
166
+ return false;
167
+ for (const [key, property] of Object.entries(supProperties)) {
168
+ if (key in subProperties) {
169
+ if (!fits(subProperties[key], property))
170
+ return false;
171
+ }
172
+ else if (typeof sub.additionalProperties === "object" && !fits(sub.additionalProperties, property)) {
173
+ // The consumer may send this name with any value its `additionalProperties` allows. Open consumer objects
174
+ // are fine: unknown names are stripped with the consumer's own schema before the call (`RecordImpl.call`).
175
+ return false;
176
+ }
177
+ }
178
+ if (sup.additionalProperties === false) {
179
+ if (sub.additionalProperties !== false)
180
+ return false;
181
+ if (Object.keys(subProperties).some((key) => !(key in supProperties)))
182
+ return false;
183
+ }
184
+ const supPatterns = asSchema(sup.patternProperties);
185
+ if (Object.keys(supPatterns).length > 0) {
186
+ // Every value the consumer may put under a matching name must fit, and the consumer must not allow arbitrary
187
+ // extra names (it would then allow any value under a matching one).
188
+ const subPatterns = asSchema(sub.patternProperties);
189
+ if (sub.additionalProperties !== false && Object.keys(subPatterns).length === 0)
190
+ return false;
191
+ for (const [pattern, property] of Object.entries(supPatterns)) {
192
+ const matcher = new RegExp(pattern, "u");
193
+ for (const [key, subProperty] of Object.entries(subProperties)) {
194
+ if (!(key in supProperties) && matcher.test(key) && !fits(subProperty, property))
195
+ return false;
196
+ }
197
+ if (Object.keys(subPatterns).length > 0 &&
198
+ (!(pattern in subPatterns) || !fits(subPatterns[pattern], property))) {
199
+ return false;
200
+ }
201
+ }
202
+ for (const pattern of Object.keys(subPatterns))
203
+ if (!(pattern in supPatterns))
204
+ return false;
205
+ }
206
+ return true;
207
+ }
208
+ function arrayFits(sub, sup) {
209
+ if (Array.isArray(sup.items)) {
210
+ if (!Array.isArray(sub.items) || sub.items.length !== sup.items.length)
211
+ return false;
212
+ return sub.items.every((item, index) => fits(item, sup.items[index]));
213
+ }
214
+ if (Array.isArray(sub.items))
215
+ return sub.items.every((item) => fits(item, sup.items));
216
+ return fits(sub.items, sup.items);
217
+ }
218
+ function functionFits(sub, sup) {
219
+ const subParameters = sub.parameters ?? [];
220
+ const supParameters = sup.parameters ?? [];
221
+ // A function accepting fewer parameters is fine; each shared parameter is contravariant.
222
+ if (subParameters.length > supParameters.length)
223
+ return false;
224
+ if (!subParameters.every((parameter, index) => fits(supParameters[index], parameter)))
225
+ return false;
226
+ return fits(sub.returnType, sup.returnType);
227
+ }
228
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TSchema } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { type ChordErrorReason, invalid } from \"./errors.ts\";\n\n/** JSON Schema as data. TypeBox schemas are plain JSON Schema objects. */\ntype Schema = { readonly [key: string]: unknown };\n\nconst asSchema = (schema: unknown): Schema =>\n\tschema !== null && typeof schema === \"object\" ? (schema as Schema) : schema === false ? { not: {} } : {};\n\n/** Canonical JSON: sorted object keys, `undefined` members dropped. */\nexport function canonicalJson(value: unknown): string {\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value) ?? \"null\";\n\tif (Array.isArray(value)) return `[${value.map((item) => canonicalJson(item)).join(\",\")}]`;\n\tconst keys = Object.keys(value)\n\t\t.filter((key) => (value as Record<string, unknown>)[key] !== undefined)\n\t\t.sort();\n\treturn `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson((value as Record<string, unknown>)[key])}`).join(\",\")}}`;\n}\n\n/** Non-cryptographic 64-bit hash (two FNV-1a lanes). Contracts are trusted, so collisions are not an attack surface. */\nexport function hash64(text: string): string {\n\tlet a = 0x811c9dc5;\n\tlet b = 0x01000193 ^ 0x5bd1e995;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tconst code = text.charCodeAt(index);\n\t\ta = Math.imul(a ^ code, 0x01000193);\n\t\tb = Math.imul(b ^ code, 0x5bd1e995) ^ (b >>> 13);\n\t}\n\treturn (a >>> 0).toString(16).padStart(8, \"0\") + (b >>> 0).toString(16).padStart(8, \"0\");\n}\n\nexport function deepEqual(a: unknown, b: unknown): boolean {\n\treturn a === b || canonicalJson(a) === canonicalJson(b);\n}\n\n/** Throws `invalid` (with `reason`) and the first schema errors when `value` does not match. */\nexport function assertValid(reason: ChordErrorReason, what: string, schema: TSchema, value: unknown): void {\n\tif (Value.Check(schema, value)) return;\n\tconst errors = [...Value.Errors(schema, value)].slice(0, 3);\n\tconst summary = errors.map((error) => `${error.instancePath || \"/\"} ${error.message}`).join(\"; \");\n\tthrow invalid(reason, `${what}: ${summary}`, errors);\n}\n\n/** Applies defaults, strips unknown fields, validates. Returns a fresh value. */\nexport function normalize(schema: TSchema, value: unknown, what: string): unknown {\n\tconst normalized = Value.Clean(schema, Value.Default(schema, Value.Clone(value ?? {})));\n\tassertValid(\"input\", what, schema, normalized);\n\treturn normalized;\n}\n\n/** Canonical identity of a normalized value: fields equal to their schema default are omitted. */\nexport function canonicalIdentity(schema: TSchema, value: unknown): string {\n\treturn canonicalJson(stripDefaults(asSchema(schema), value));\n}\n\nfunction stripDefaults(schema: Schema, value: unknown): unknown {\n\tif (Array.isArray(value)) {\n\t\tconst items = schema.items;\n\t\tif (Array.isArray(items)) return value.map((item, index) => stripDefaults(asSchema(items[index]), item));\n\t\treturn value.map((item) => stripDefaults(asSchema(items), item));\n\t}\n\tif (value === null || typeof value !== \"object\") return value;\n\tconst properties = asSchema(schema.properties);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, item] of Object.entries(value)) {\n\t\tconst property = asSchema(properties[key]);\n\t\tif (\"default\" in property && deepEqual(property.default, item)) continue;\n\t\tresult[key] = stripDefaults(property, item);\n\t}\n\treturn result;\n}\n\nconst CONSTRAINTS = [\n\t\"minLength\",\n\t\"maxLength\",\n\t\"pattern\",\n\t\"format\",\n\t\"minimum\",\n\t\"maximum\",\n\t\"exclusiveMinimum\",\n\t\"exclusiveMaximum\",\n\t\"multipleOf\",\n\t\"minItems\",\n\t\"maxItems\",\n\t\"uniqueItems\",\n\t\"minProperties\",\n\t\"maxProperties\",\n] as const;\n\nconst typesOf = (schema: Schema): string[] | undefined =>\n\ttypeof schema.type === \"string\" ? [schema.type] : Array.isArray(schema.type) ? (schema.type as string[]) : undefined;\n\n/** Keywords `fits` reasons about. Any other validation keyword in the provider's schema forces exact equality. */\nconst KNOWN: ReadonlySet<string> = new Set([\n\t...CONSTRAINTS,\n\t\"type\",\n\t\"properties\",\n\t\"required\",\n\t\"additionalProperties\",\n\t\"patternProperties\",\n\t\"items\",\n\t\"additionalItems\",\n\t\"const\",\n\t\"enum\",\n\t\"anyOf\",\n\t\"parameters\",\n\t\"returnType\",\n]);\n\n/** Annotations: no effect on validity. */\nconst ANNOTATIONS: ReadonlySet<string> = new Set([\n\t\"title\",\n\t\"description\",\n\t\"default\",\n\t\"examples\",\n\t\"$id\",\n\t\"$schema\",\n\t\"$comment\",\n\t\"readOnly\",\n\t\"writeOnly\",\n\t\"deprecated\",\n]);\n\nconst withoutAnnotations = (schema: Schema): Schema =>\n\tObject.fromEntries(Object.entries(schema).filter(([key]) => !ANNOTATIONS.has(key)));\n\n/**\n * Conservative structural subtyping: true only if every value valid under `sub` is valid under `sup`, where object\n * fields missing from `sub` but optional in `sup` count as fine (unknown fields are stripped at the provider, see\n * `RecordImpl.call`). A provider schema using a keyword this function does not model (`not`, `allOf`, `contains`,\n * `$ref`, ...) or an `additionalProperties` schema only fits an identical consumer schema.\n */\nexport function fits(subSchema: unknown, supSchema: unknown): boolean {\n\tconst sub = withoutAnnotations(asSchema(subSchema));\n\tconst sup = withoutAnnotations(asSchema(supSchema));\n\tif (Object.keys(sup).length === 0) return true;\n\tif (deepEqual(sub, sup)) return true;\n\tif (Object.keys(sup).some((key) => !KNOWN.has(key))) return false;\n\tif (sup.additionalProperties !== undefined && typeof sup.additionalProperties !== \"boolean\") return false;\n\tif (Array.isArray(sub.anyOf)) return sub.anyOf.every((branch) => fits(branch, sup));\n\tif (Array.isArray(sup.anyOf)) return sup.anyOf.some((branch) => fits(sub, branch));\n\tif (\"const\" in sup) return \"const\" in sub && deepEqual(sub.const, sup.const);\n\tif (Array.isArray(sup.enum)) {\n\t\tconst values = \"const\" in sub ? [sub.const] : Array.isArray(sub.enum) ? sub.enum : undefined;\n\t\treturn values?.every((item) => (sup.enum as unknown[]).some((allowed) => deepEqual(allowed, item))) ?? false;\n\t}\n\tfor (const key of CONSTRAINTS) if (key in sup && !deepEqual(sub[key], sup[key])) return false;\n\tconst supTypes = typesOf(sup);\n\tconst subTypes = typesOf(sub);\n\tif (supTypes === undefined || subTypes === undefined) return false;\n\tif (!subTypes.every((type) => supTypes.includes(type) || (type === \"integer\" && supTypes.includes(\"number\")))) {\n\t\treturn false;\n\t}\n\tif (\"const\" in sub || Array.isArray(sub.enum)) return true;\n\tif (subTypes.includes(\"object\") && !objectFits(sub, sup)) return false;\n\tif (subTypes.includes(\"array\") && !arrayFits(sub, sup)) return false;\n\tif (subTypes.includes(\"function\")) return functionFits(sub, sup);\n\treturn true;\n}\n\nfunction objectFits(sub: Schema, sup: Schema): boolean {\n\tconst subProperties = asSchema(sub.properties);\n\tconst supProperties = asSchema(sup.properties);\n\tconst subRequired = new Set((sub.required as string[] | undefined) ?? []);\n\tfor (const key of (sup.required as string[] | undefined) ?? []) if (!subRequired.has(key)) return false;\n\tfor (const [key, property] of Object.entries(supProperties)) {\n\t\tif (key in subProperties) {\n\t\t\tif (!fits(subProperties[key], property)) return false;\n\t\t} else if (typeof sub.additionalProperties === \"object\" && !fits(sub.additionalProperties, property)) {\n\t\t\t// The consumer may send this name with any value its `additionalProperties` allows. Open consumer objects\n\t\t\t// are fine: unknown names are stripped with the consumer's own schema before the call (`RecordImpl.call`).\n\t\t\treturn false;\n\t\t}\n\t}\n\tif (sup.additionalProperties === false) {\n\t\tif (sub.additionalProperties !== false) return false;\n\t\tif (Object.keys(subProperties).some((key) => !(key in supProperties))) return false;\n\t}\n\tconst supPatterns = asSchema(sup.patternProperties);\n\tif (Object.keys(supPatterns).length > 0) {\n\t\t// Every value the consumer may put under a matching name must fit, and the consumer must not allow arbitrary\n\t\t// extra names (it would then allow any value under a matching one).\n\t\tconst subPatterns = asSchema(sub.patternProperties);\n\t\tif (sub.additionalProperties !== false && Object.keys(subPatterns).length === 0) return false;\n\t\tfor (const [pattern, property] of Object.entries(supPatterns)) {\n\t\t\tconst matcher = new RegExp(pattern, \"u\");\n\t\t\tfor (const [key, subProperty] of Object.entries(subProperties)) {\n\t\t\t\tif (!(key in supProperties) && matcher.test(key) && !fits(subProperty, property)) return false;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tObject.keys(subPatterns).length > 0 &&\n\t\t\t\t(!(pattern in subPatterns) || !fits(subPatterns[pattern], property))\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tfor (const pattern of Object.keys(subPatterns)) if (!(pattern in supPatterns)) return false;\n\t}\n\treturn true;\n}\n\nfunction arrayFits(sub: Schema, sup: Schema): boolean {\n\tif (Array.isArray(sup.items)) {\n\t\tif (!Array.isArray(sub.items) || sub.items.length !== sup.items.length) return false;\n\t\treturn sub.items.every((item, index) => fits(item, (sup.items as unknown[])[index]));\n\t}\n\tif (Array.isArray(sub.items)) return sub.items.every((item) => fits(item, sup.items));\n\treturn fits(sub.items, sup.items);\n}\n\nfunction functionFits(sub: Schema, sup: Schema): boolean {\n\tconst subParameters = (sub.parameters as unknown[] | undefined) ?? [];\n\tconst supParameters = (sup.parameters as unknown[] | undefined) ?? [];\n\t// A function accepting fewer parameters is fine; each shared parameter is contravariant.\n\tif (subParameters.length > supParameters.length) return false;\n\tif (!subParameters.every((parameter, index) => fits(supParameters[index], parameter))) return false;\n\treturn fits(sub.returnType, sup.returnType);\n}\n"]}
@@ -0,0 +1,92 @@
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 { type Context } from "./context/index.ts";
7
+ import { type Draft, type Op } from "./delta/index.ts";
8
+ export interface ReplicatedStateDelivery {
9
+ readonly kind: "hydrate" | "update";
10
+ readonly sequence: number;
11
+ }
12
+ export interface ReplicatedState<T> {
13
+ /**
14
+ * Contract-immutable value, or undefined until hydration. It is not frozen and may share containers with an
15
+ * in-process provider; consumers must not mutate it. Later updates do not mutate previously returned values.
16
+ */
17
+ readonly value: T | undefined;
18
+ /**
19
+ * Each subscription serializes callbacks, awaiting hydration before updates. Values are immutable and may
20
+ * share unchanged revision data. At most 100 deliveries wait behind the running callback; overflow keeps
21
+ * only the newest pending value/context/delivery, so update sequences may skip. Failures are reported in
22
+ * isolation and delivery continues. Unsubscribe discards pending work without aborting or joining a callback.
23
+ */
24
+ subscribe(listener: (value: T, context: Context, delivery: ReplicatedStateDelivery) => Promise<void>): () => void;
25
+ subscribe(listener: (value: T, context: Context, delivery: ReplicatedStateDelivery) => void): () => void;
26
+ }
27
+ export interface MutableReplicatedState<T extends object> extends ReplicatedState<T> {
28
+ readonly value: T;
29
+ /**
30
+ * Atomically publish one synchronous overlay mutation. Draft handles are unusable after the callback returns.
31
+ * Values placed through the draft are cloned by value; assigning `undefined` to an object property deletes it.
32
+ */
33
+ change(context: Context, mutate: (draft: Draft<T>) => void): void;
34
+ /**
35
+ * Atomically take immutable ownership of an alias-free strict-JSON replacement.
36
+ * The caller must not mutate the transferred root after this call.
37
+ */
38
+ replace(context: Context, value: T): void;
39
+ }
40
+ /** One immutable authoritative revision committed after an attachment snapshot. */
41
+ export interface ReplicatedStateSourceFrame<T> {
42
+ /** Monotonic source cursor. The first frame after a snapshot must be `snapshot.cursor + 1`. */
43
+ readonly cursor: number;
44
+ /** The exact immutable value produced by this commit. */
45
+ readonly value: T;
46
+ /** The exact immutable operation batch that produced `value` from the preceding source revision. */
47
+ readonly ops: readonly Op[];
48
+ readonly context: Context;
49
+ }
50
+ export interface ReplicatedStateSourceAttachment<T> {
51
+ /** Fixed immutable snapshot captured at the atomic attachment boundary. */
52
+ readonly snapshot: {
53
+ readonly value: T;
54
+ readonly cursor: number;
55
+ };
56
+ /**
57
+ * Install the sole listener and synchronously drain every buffered frame in source commit order.
58
+ * This method is single-use. After it begins, every new committed frame must also be delivered in order
59
+ * until disposal, including commits made reentrantly while a prior frame is being delivered.
60
+ */
61
+ activate(listener: (frame: ReplicatedStateSourceFrame<T>) => void): void;
62
+ /** Stop delivery and release source resources. Disposal must be idempotent. */
63
+ dispose(): void;
64
+ }
65
+ /**
66
+ * An authoritative immutable revision source.
67
+ *
68
+ * `attach()` must synchronously and atomically capture one snapshot and register the returned attachment to buffer
69
+ * every later committed frame. The snapshot must include every commit before that boundary; buffered frames must
70
+ * include every commit after it, with no overlap or gap. Snapshot values, frame values, and operation batches are
71
+ * immutable and remain valid after delivery. Chord only publishes these references; it never applies or re-diffs them.
72
+ */
73
+ export interface ReplicatedStateSource<T> {
74
+ attach(): ReplicatedStateSourceAttachment<T>;
75
+ }
76
+ export interface ReplicatedStateSourceOptions {
77
+ /** Receives source-contract and publication-listener failures without throwing them into the source. */
78
+ readonly onError?: (error: Error) => void;
79
+ }
80
+ /** A synchronously hydrated publication-only state backed by one source attachment. */
81
+ export interface AttachedReplicatedState<T> extends ReplicatedState<T> {
82
+ readonly value: T;
83
+ /** Idempotently release the source attachment. The last published value remains readable. */
84
+ dispose(): void;
85
+ }
86
+ export declare function replicatedState<T>(source: ReplicatedStateSource<T>, options?: ReplicatedStateSourceOptions): AttachedReplicatedState<T>;
87
+ /**
88
+ * Create authoritative state by taking immutable ownership of an alias-free strict-JSON root.
89
+ * The caller must not mutate `initial` after this call.
90
+ */
91
+ export declare function replicatedState<T extends object>(initial: T): MutableReplicatedState<T>;
92
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
@@ -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