@braidlabs/skew 0.1.1

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.
@@ -0,0 +1,337 @@
1
+ // --- path helpers -----------------------------------------------------------
2
+ function segmentsOf(path) {
3
+ if (typeof path !== 'string' || path.length === 0) {
4
+ throw new TypeError(`lens: op path must be a non-empty string, got ${JSON.stringify(path)}`);
5
+ }
6
+ return path.split('.');
7
+ }
8
+ function getAt(scope, segments) {
9
+ let current = scope;
10
+ for (const segment of segments) {
11
+ if (typeof current !== 'object' || current === null)
12
+ return undefined;
13
+ current = current[segment];
14
+ }
15
+ return current;
16
+ }
17
+ function setAt(scope, segments, value) {
18
+ let current = scope;
19
+ for (let i = 0; i < segments.length - 1; i++) {
20
+ const segment = segments[i];
21
+ const next = current[segment];
22
+ if (typeof next !== 'object' || next === null) {
23
+ const created = {};
24
+ current[segment] = created;
25
+ current = created;
26
+ }
27
+ else {
28
+ current = next;
29
+ }
30
+ }
31
+ current[segments[segments.length - 1]] = value;
32
+ }
33
+ function deleteAt(scope, segments) {
34
+ // Walk down, remembering the chain so empties can be pruned on the way up.
35
+ const parents = [];
36
+ let current = scope;
37
+ for (let i = 0; i < segments.length - 1; i++) {
38
+ if (typeof current !== 'object' || current === null)
39
+ return;
40
+ parents.push(current);
41
+ current = current[segments[i]];
42
+ }
43
+ if (typeof current !== 'object' || current === null)
44
+ return;
45
+ delete current[segments[segments.length - 1]];
46
+ // An intermediate object this deletion emptied was (in the shapes lenses
47
+ // describe) created *for* the deleted field — an up-migration's `move` or
48
+ // `default` built it on the way in. Leaving `liquidity: {}` behind on the
49
+ // way down would put a field in the projection that the older shape never
50
+ // had. Prune upward until a non-empty ancestor stops us; the root scope is
51
+ // never pruned.
52
+ let child = current;
53
+ for (let i = parents.length - 1; i >= 0; i--) {
54
+ if (Array.isArray(child) || Object.keys(child).length > 0)
55
+ break;
56
+ const parent = parents[i];
57
+ delete parent[segments[i]];
58
+ child = parent;
59
+ }
60
+ }
61
+ function compileValueSpec(spec) {
62
+ if (typeof spec === 'object' && spec !== null && !Array.isArray(spec)) {
63
+ const record = spec;
64
+ if (record['$now'] === true) {
65
+ return { resolve: (_scope, _root, ctx) => ctx.now().toISOString(), derived: true };
66
+ }
67
+ if (typeof record['$from'] === 'string') {
68
+ const path = record['$from'];
69
+ const fromRoot = path.startsWith('/');
70
+ const segments = segmentsOf(fromRoot ? path.slice(1) : path);
71
+ return {
72
+ resolve: (scope, root) => getAt(fromRoot ? root : scope, segments),
73
+ derived: false,
74
+ };
75
+ }
76
+ if ('$value' in record) {
77
+ const literal = record['$value'];
78
+ return { resolve: () => literal, derived: true };
79
+ }
80
+ }
81
+ return { resolve: () => spec, derived: true };
82
+ }
83
+ function fail(message) {
84
+ throw new TypeError(`lens: ${message}`);
85
+ }
86
+ function compileOp(op) {
87
+ var _a;
88
+ if (typeof op !== 'object' || op === null)
89
+ fail(`op must be an object, got ${JSON.stringify(op)}`);
90
+ const keys = Object.keys(op);
91
+ if (keys.length !== 1)
92
+ fail(`op must have exactly one key, got ${JSON.stringify(keys)}`);
93
+ const kind = keys[0];
94
+ switch (kind) {
95
+ case 'rename':
96
+ case 'move': {
97
+ const { from, to } = (_a = op.rename) !== null && _a !== void 0 ? _a : op.move;
98
+ const fromSegments = segmentsOf(from);
99
+ const toSegments = segmentsOf(to);
100
+ const moveValue = (source, target) => {
101
+ return (scope) => {
102
+ const value = getAt(scope, source);
103
+ deleteAt(scope, source);
104
+ if (value !== undefined)
105
+ setAt(scope, target, value);
106
+ };
107
+ };
108
+ return {
109
+ up: moveValue(fromSegments, toSegments),
110
+ down: moveValue(toSegments, fromSegments),
111
+ derivedUp: [],
112
+ derivedDown: [],
113
+ lossyDown: [],
114
+ };
115
+ }
116
+ case 'wrap': {
117
+ const { path, key, also } = op
118
+ .wrap;
119
+ const segments = segmentsOf(path);
120
+ if (typeof key !== 'string' || key.length === 0)
121
+ fail(`wrap at "${path}" needs a non-empty key`);
122
+ const alsoEntries = Object.entries(also !== null && also !== void 0 ? also : {}).map(([alsoKey, spec]) => [alsoKey, compileValueSpec(spec)]);
123
+ return {
124
+ up: (scope, root, ctx) => {
125
+ const scalar = getAt(scope, segments);
126
+ const wrapped = { [key]: scalar };
127
+ for (const [alsoKey, spec] of alsoEntries) {
128
+ wrapped[alsoKey] = spec.resolve(scope, root, ctx);
129
+ }
130
+ setAt(scope, segments, wrapped);
131
+ },
132
+ down: (scope) => {
133
+ const wrapped = getAt(scope, segments);
134
+ if (typeof wrapped !== 'object' || wrapped === null) {
135
+ throw new Error(`lens: expected an object at "${path}" to unwrap "${key}" from`);
136
+ }
137
+ setAt(scope, segments, wrapped[key]);
138
+ },
139
+ derivedUp: alsoEntries.filter(([, spec]) => spec.derived).map(([alsoKey]) => `${path}.${alsoKey}`),
140
+ derivedDown: [],
141
+ // Everything wrap added beside the original scalar is discarded on the
142
+ // way down — that is the information the older shape cannot carry.
143
+ lossyDown: alsoEntries.map(([alsoKey]) => `${path}.${alsoKey}`),
144
+ };
145
+ }
146
+ case 'hoist': {
147
+ const { path, key } = op.hoist;
148
+ const segments = segmentsOf(path);
149
+ if (typeof key !== 'string' || key.length === 0)
150
+ fail(`hoist at "${path}" needs a non-empty key`);
151
+ return {
152
+ up: (scope) => {
153
+ const source = getAt(scope, segments);
154
+ if (typeof source !== 'object' || source === null) {
155
+ throw new Error(`lens: expected an object at "${path}" to hoist "${key}" from`);
156
+ }
157
+ setAt(scope, segments, source[key]);
158
+ },
159
+ down: (scope) => {
160
+ setAt(scope, segments, { [key]: getAt(scope, segments) });
161
+ },
162
+ derivedUp: [],
163
+ derivedDown: [],
164
+ lossyDown: [],
165
+ };
166
+ }
167
+ case 'map': {
168
+ const { path, ops } = op.map;
169
+ const segments = segmentsOf(path);
170
+ const inner = compileOps(ops);
171
+ const overArray = (apply) => {
172
+ return (scope, root, ctx) => {
173
+ const list = getAt(scope, segments);
174
+ if (list === undefined)
175
+ return;
176
+ if (!Array.isArray(list))
177
+ throw new Error(`lens: expected an array at "${path}" to map over`);
178
+ for (const element of list) {
179
+ for (const step of apply)
180
+ step(element, root, ctx);
181
+ }
182
+ };
183
+ };
184
+ const prefix = (paths) => paths.map((p) => `${path}[].${p}`);
185
+ return {
186
+ up: overArray(inner.ops.map((o) => o.up)),
187
+ down: inner.invertible
188
+ ? overArray([...inner.ops].reverse().map((o) => o.down))
189
+ : null,
190
+ derivedUp: prefix(inner.derivedUp),
191
+ derivedDown: prefix(inner.derivedDown),
192
+ lossyDown: prefix(inner.lossyDown),
193
+ };
194
+ }
195
+ case 'default': {
196
+ const { path, value, derived = true } = op.default;
197
+ const segments = segmentsOf(path);
198
+ return {
199
+ up: (scope) => {
200
+ if (getAt(scope, segments) === undefined)
201
+ setAt(scope, segments, structuredClone(value));
202
+ },
203
+ down: (scope) => deleteAt(scope, segments),
204
+ derivedUp: derived ? [path] : [],
205
+ derivedDown: [],
206
+ lossyDown: [path],
207
+ };
208
+ }
209
+ case 'drop': {
210
+ const dropOp = op.drop;
211
+ const segments = segmentsOf(dropOp.path);
212
+ const restorable = 'restore' in dropOp;
213
+ return {
214
+ up: (scope) => deleteAt(scope, segments),
215
+ down: restorable ? (scope) => setAt(scope, segments, structuredClone(dropOp.restore)) : null,
216
+ derivedUp: [],
217
+ derivedDown: restorable ? [dropOp.path] : [],
218
+ lossyDown: [],
219
+ };
220
+ }
221
+ case 'convert': {
222
+ const { path, to, via } = op.convert;
223
+ const segments = segmentsOf(path);
224
+ if (to !== 'string' && to !== 'number')
225
+ fail(`convert at "${path}" must target 'string' or 'number'`);
226
+ const coerce = (target, table) => {
227
+ return (scope) => {
228
+ const current = getAt(scope, segments);
229
+ if (current === undefined)
230
+ return;
231
+ if (table) {
232
+ const mapped = table[String(current)];
233
+ if (mapped === undefined) {
234
+ throw new Error(`lens: convert at "${path}" has no mapping for ${JSON.stringify(current)}`);
235
+ }
236
+ setAt(scope, segments, mapped);
237
+ return;
238
+ }
239
+ const converted = target === 'string' ? String(current) : Number(current);
240
+ if (target === 'number' && Number.isNaN(converted)) {
241
+ throw new Error(`lens: convert at "${path}" could not read ${JSON.stringify(current)} as a number`);
242
+ }
243
+ setAt(scope, segments, converted);
244
+ };
245
+ };
246
+ let inverseTable = null;
247
+ let invertible = true;
248
+ if (via) {
249
+ inverseTable = {};
250
+ for (const [key, mapped] of Object.entries(via)) {
251
+ const inverseKey = String(mapped);
252
+ if (inverseKey in inverseTable) {
253
+ // Two old values map to the same new one — the down direction
254
+ // cannot know which to restore.
255
+ invertible = false;
256
+ break;
257
+ }
258
+ inverseTable[inverseKey] = coerceKeyBack(key, to === 'string' ? 'number' : 'string');
259
+ }
260
+ }
261
+ return {
262
+ up: coerce(to, via !== null && via !== void 0 ? via : null),
263
+ down: invertible ? coerce(to === 'string' ? 'number' : 'string', inverseTable) : null,
264
+ derivedUp: [],
265
+ derivedDown: [],
266
+ lossyDown: [],
267
+ };
268
+ }
269
+ case 'const': {
270
+ const { path, value, derived = false } = op.const;
271
+ const segments = segmentsOf(path);
272
+ return {
273
+ up: (scope) => setAt(scope, segments, structuredClone(value)),
274
+ down: (scope) => deleteAt(scope, segments),
275
+ derivedUp: derived ? [path] : [],
276
+ derivedDown: [],
277
+ lossyDown: [path],
278
+ };
279
+ }
280
+ default:
281
+ return fail(`unknown op "${kind}"`);
282
+ }
283
+ }
284
+ /**
285
+ * `via` keys arrive as strings (JSON object keys always are). When the down
286
+ * direction restores an *old* value that was numeric, give it back as the
287
+ * number it was.
288
+ */
289
+ function coerceKeyBack(key, oldKind) {
290
+ if (oldKind !== 'number')
291
+ return key;
292
+ const numeric = Number(key);
293
+ return Number.isNaN(numeric) ? key : numeric;
294
+ }
295
+ function compileOps(ops) {
296
+ if (!Array.isArray(ops))
297
+ fail('ops must be an array');
298
+ const compiled = ops.map(compileOp);
299
+ return {
300
+ ops: compiled,
301
+ invertible: compiled.every((o) => o.down !== null),
302
+ derivedUp: compiled.flatMap((o) => o.derivedUp),
303
+ derivedDown: compiled.flatMap((o) => o.derivedDown),
304
+ lossyDown: compiled.flatMap((o) => o.lossyDown),
305
+ };
306
+ }
307
+ /**
308
+ * Compiles an ops list into executable up and (when possible) down
309
+ * migrations. Throws `TypeError` on a malformed ops list — a bad contract is
310
+ * a programming error and should fail at declaration, not at read time.
311
+ */
312
+ export function compileLens(ops) {
313
+ const compiled = compileOps(ops);
314
+ const up = (data, ctx) => {
315
+ const draft = structuredClone(data);
316
+ for (const op of compiled.ops)
317
+ op.up(draft, draft, ctx);
318
+ return draft;
319
+ };
320
+ const down = compiled.invertible
321
+ ? (data, ctx) => {
322
+ const draft = structuredClone(data);
323
+ for (const op of [...compiled.ops].reverse())
324
+ op.down(draft, draft, ctx);
325
+ return draft;
326
+ }
327
+ : null;
328
+ return {
329
+ up,
330
+ down,
331
+ invertible: compiled.invertible,
332
+ derivedUp: compiled.derivedUp,
333
+ derivedDown: compiled.derivedDown,
334
+ lossyDown: compiled.lossyDown,
335
+ };
336
+ }
337
+ //# sourceMappingURL=lens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lens.js","sourceRoot":"","sources":["../../../../../libs/skew/src/lib/lens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { VersionedOptions, VersionedSchema } from './versioned.js';
2
+ /**
3
+ * A list schema derived from an item schema, so the two cannot drift apart.
4
+ *
5
+ * The failure this prevents is quiet: a `Fund` schema and a `Fund[]` schema
6
+ * maintained side by side share their migration logic by discipline only, and
7
+ * the day someone edits one chain without the other, records migrate
8
+ * differently depending on whether they arrived alone or in a collection.
9
+ * Deriving the list from the item makes that impossible — every step here
10
+ * *is* the item's step, mapped.
11
+ *
12
+ * Provenance paths are re-rooted with an `[]` prefix (`liquidity.hqlaPct`
13
+ * becomes `[].liquidity.hqlaPct`), so a consumer of the list result can still
14
+ * tell exactly which fields of which shape were guessed or discarded.
15
+ */
16
+ export declare function versionedList<TItem>(itemSchema: VersionedSchema<TItem>, nameOrOptions?: string | (VersionedOptions<TItem[]> & {
17
+ readonly name?: string;
18
+ })): VersionedSchema<TItem[]>;
@@ -0,0 +1,49 @@
1
+ import { versioned } from './versioned.js';
2
+ /**
3
+ * A list schema derived from an item schema, so the two cannot drift apart.
4
+ *
5
+ * The failure this prevents is quiet: a `Fund` schema and a `Fund[]` schema
6
+ * maintained side by side share their migration logic by discipline only, and
7
+ * the day someone edits one chain without the other, records migrate
8
+ * differently depending on whether they arrived alone or in a collection.
9
+ * Deriving the list from the item makes that impossible — every step here
10
+ * *is* the item's step, mapped.
11
+ *
12
+ * Provenance paths are re-rooted with an `[]` prefix (`liquidity.hqlaPct`
13
+ * becomes `[].liquidity.hqlaPct`), so a consumer of the list result can still
14
+ * tell exactly which fields of which shape were guessed or discarded.
15
+ */
16
+ export function versionedList(itemSchema, nameOrOptions) {
17
+ var _a;
18
+ const opts = typeof nameOrOptions === 'string' ? { name: nameOrOptions } : (nameOrOptions !== null && nameOrOptions !== void 0 ? nameOrOptions : {});
19
+ const name = (_a = opts.name) !== null && _a !== void 0 ? _a : `${itemSchema.name}[]`;
20
+ let schema = versioned(name, {
21
+ assumeLegacyVersion: opts.assumeLegacyVersion,
22
+ validate: opts.validate
23
+ ? opts.validate
24
+ : undefined,
25
+ });
26
+ for (const step of itemSchema.steps) {
27
+ schema = schema.next(step.description, liftStep(step));
28
+ }
29
+ return schema;
30
+ }
31
+ function liftStep(step) {
32
+ const requireArray = (list) => {
33
+ if (!Array.isArray(list)) {
34
+ throw new Error(`expected an array, got ${list === null ? 'null' : typeof list}`);
35
+ }
36
+ return list;
37
+ };
38
+ const prefix = (paths) => paths === null || paths === void 0 ? void 0 : paths.map((p) => `[].${p}`);
39
+ return {
40
+ up: (list, ctx) => requireArray(list).map((item) => step.up(item, ctx)),
41
+ down: step.down
42
+ ? (list, ctx) => requireArray(list).map((item) => step.down(item, ctx))
43
+ : undefined,
44
+ derives: prefix(step.derives),
45
+ downDerives: prefix(step.downDerives),
46
+ lossy: prefix(step.lossy),
47
+ };
48
+ }
49
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../../libs/skew/src/lib/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoD,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE7F;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAC3B,UAAkC,EAClC,aAAiF;;IAEjF,MAAM,IAAI,GAAG,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,EAAE,CAAC,CAAC;IACjG,MAAM,IAAI,GAAG,MAAA,IAAI,CAAC,IAAI,mCAAI,GAAG,UAAU,CAAC,IAAI,IAAI,CAAC;IAEjD,IAAI,MAAM,GAAG,SAAS,CAAU,IAAI,EAAE;QACpC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACrB,CAAC,CAAE,IAAI,CAAC,QAAiD;YACzD,CAAC,CAAC,SAAS;KACd,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAU,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,MAAkC,CAAC;AAC5C,CAAC;AAED,SAAS,QAAQ,CAAC,IAAmB;IAOnC,MAAM,YAAY,GAAG,CAAC,IAAa,EAAsB,EAAE;QACzD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,KAAoC,EAAE,EAAE,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEtF,OAAO;QACL,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACvE,IAAI,EAAE,IAAI,CAAC,IAAI;YACb,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAE,IAAI,CAAC,IAA2C,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/G,CAAC,CAAC,SAAS;QACb,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;QAC7B,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;QACrC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;KAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,77 @@
1
+ import type { MigrationStep, VersionedSchema } from './versioned.js';
2
+ /**
3
+ * The shared schema registry — the federation-specific move.
4
+ *
5
+ * In a federated page, the parties on either side of a version boundary are
6
+ * loaded into the *same JavaScript runtime*. A host built against v1 sits
7
+ * beside a remote built against v2, and the remote's bundle contains exactly
8
+ * the migration knowledge the host lacks. This registry is where that
9
+ * knowledge is pooled: each bundle contributes the steps it knows, keyed by
10
+ * `(contract name, target version)`, and `read()` consults it for any step
11
+ * missing from the local chain — in **both** directions.
12
+ *
13
+ * The effect worth naming: an older host handed newer data no longer dead-ends
14
+ * at `ahead`. If any loaded bundle registered a down-migration for the
15
+ * intervening steps, the host reads an honest, lossy projection instead —
16
+ * with `downgradedFrom` and `lossyPaths` saying exactly what happened.
17
+ *
18
+ * Registration is **explicit** (`registerSchema`), not automatic. Module-level
19
+ * state shared across bundles is a capability, not a default: tests declare
20
+ * throwaway schemas by the dozen, and a page may legitimately host unrelated
21
+ * contracts that happen to collide on a short name. Register the contracts you
22
+ * mean to share.
23
+ *
24
+ * This registry is module-level, deliberately outside any DI system. The
25
+ * demo's rule — a remote must not depend on the host having configured
26
+ * providers — holds here: both sides reach the same registry through the one
27
+ * shared `@braidlabs/skew` instance (`sharedMappings`), with no cooperation beyond
28
+ * that.
29
+ *
30
+ * ## Conflicts
31
+ *
32
+ * Two bundles registering the same `(name, to)` with *matching* fingerprints
33
+ * is the healthy case — independent builds that agree. Divergent fingerprints
34
+ * mean two builds disagree about what a version transition means: the
35
+ * first-registered step is kept (whichever bundle loaded first — determinism
36
+ * within a page lifetime matters more than either candidate), and a
37
+ * diagnostic fires. That diagnostic is the only place this class of bug —
38
+ * same name, same version, different meaning — becomes visible at all; wire
39
+ * it to telemetry.
40
+ */
41
+ export interface RegistryConflict {
42
+ readonly name: string;
43
+ readonly to: number;
44
+ /** Fingerprint of the step that was kept (registered first). */
45
+ readonly kept: string;
46
+ /** Fingerprint of the step that was rejected. */
47
+ readonly rejected: string;
48
+ readonly keptDescription: string;
49
+ readonly rejectedDescription: string;
50
+ }
51
+ /**
52
+ * Replaces the conflict diagnostic (default: `console.warn`). Pass `null` to
53
+ * restore the default. Wire this to telemetry in production.
54
+ */
55
+ export declare function setRegistryConflictHandler(handler: ((conflict: RegistryConflict) => void) | null): void;
56
+ /** Contributes steps under a contract name. Idempotent for identical steps. */
57
+ export declare function registerSteps(name: string, steps: readonly (MigrationStep | undefined)[]): void;
58
+ /**
59
+ * Contributes every step a schema knows to the shared registry, making them
60
+ * available to any other bundle in the page reading the same contract.
61
+ *
62
+ * Call this once per contract, from each bundle that wants to share — the
63
+ * newer party's registration is what lets an older party downgrade.
64
+ */
65
+ export declare function registerSchema<T>(schema: VersionedSchema<T>): void;
66
+ /** The registered step migrating `(to - 1)` → `to`, if any bundle shared one. */
67
+ export declare function registryStep(name: string, to: number): MigrationStep | undefined;
68
+ /**
69
+ * The highest target version any registered step for `name` reaches, or
70
+ * `null` when nothing is registered. Diagnostic use.
71
+ */
72
+ export declare function registryCeiling(name: string): number | null;
73
+ /**
74
+ * Clears every registration. Test isolation — a shared module-level registry
75
+ * would otherwise leak declarations between test files.
76
+ */
77
+ export declare function resetSchemaRegistry(): void;
@@ -0,0 +1,80 @@
1
+ import { stepFingerprint } from './fingerprint.js';
2
+ const registry = new Map();
3
+ let onConflict = (conflict) => {
4
+ console.warn(`[skew] schema registry conflict: two builds disagree about "${conflict.name}" v${conflict.to - 1} → v${conflict.to}. ` +
5
+ `Kept "${conflict.keptDescription}" (${conflict.kept}), rejected "${conflict.rejectedDescription}" (${conflict.rejected}). ` +
6
+ `Same name + same version + different meaning is silent corruption everywhere except here — investigate.`);
7
+ };
8
+ /**
9
+ * Replaces the conflict diagnostic (default: `console.warn`). Pass `null` to
10
+ * restore the default. Wire this to telemetry in production.
11
+ */
12
+ export function setRegistryConflictHandler(handler) {
13
+ onConflict = handler !== null && handler !== void 0 ? handler : ((conflict) => {
14
+ console.warn(`[skew] schema registry conflict: two builds disagree about "${conflict.name}" v${conflict.to - 1} → v${conflict.to}.`);
15
+ });
16
+ }
17
+ /** Contributes steps under a contract name. Idempotent for identical steps. */
18
+ export function registerSteps(name, steps) {
19
+ let byTarget = registry.get(name);
20
+ if (!byTarget) {
21
+ byTarget = new Map();
22
+ registry.set(name, byTarget);
23
+ }
24
+ for (const step of steps) {
25
+ // Step lists built from a contract may carry holes (a named code step this
26
+ // bundle cannot run) — a hole is nothing to share.
27
+ if (!step)
28
+ continue;
29
+ const fingerprint = stepFingerprint(step);
30
+ const existing = byTarget.get(step.to);
31
+ if (!existing) {
32
+ byTarget.set(step.to, { step, fingerprint });
33
+ continue;
34
+ }
35
+ if (existing.fingerprint !== fingerprint) {
36
+ onConflict({
37
+ name,
38
+ to: step.to,
39
+ kept: existing.fingerprint,
40
+ rejected: fingerprint,
41
+ keptDescription: existing.step.description,
42
+ rejectedDescription: step.description,
43
+ });
44
+ }
45
+ // Matching fingerprint (or conflict): the first registration stands.
46
+ }
47
+ }
48
+ /**
49
+ * Contributes every step a schema knows to the shared registry, making them
50
+ * available to any other bundle in the page reading the same contract.
51
+ *
52
+ * Call this once per contract, from each bundle that wants to share — the
53
+ * newer party's registration is what lets an older party downgrade.
54
+ */
55
+ export function registerSchema(schema) {
56
+ registerSteps(schema.name, schema.steps);
57
+ }
58
+ /** The registered step migrating `(to - 1)` → `to`, if any bundle shared one. */
59
+ export function registryStep(name, to) {
60
+ var _a, _b;
61
+ return (_b = (_a = registry.get(name)) === null || _a === void 0 ? void 0 : _a.get(to)) === null || _b === void 0 ? void 0 : _b.step;
62
+ }
63
+ /**
64
+ * The highest target version any registered step for `name` reaches, or
65
+ * `null` when nothing is registered. Diagnostic use.
66
+ */
67
+ export function registryCeiling(name) {
68
+ const byTarget = registry.get(name);
69
+ if (!byTarget || byTarget.size === 0)
70
+ return null;
71
+ return Math.max(...byTarget.keys());
72
+ }
73
+ /**
74
+ * Clears every registration. Test isolation — a shared module-level registry
75
+ * would otherwise leak declarations between test files.
76
+ */
77
+ export function resetSchemaRegistry() {
78
+ registry.clear();
79
+ }
80
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../../libs/skew/src/lib/registry.ts"],"names":[],"mappings":"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"}