zocket 0.0.1 → 0.0.2

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.
package/dist/index.js CHANGED
@@ -1,3056 +1,5 @@
1
- // ../orbz/src/utils/runtime.js
2
- var _baseAnchor;
3
- var hasSetDefault = false;
4
- var MEM = {
5
- get BASE_ANCHOR() {
6
- return _baseAnchor;
7
- },
8
- set BASE_ANCHOR(anchor) {
9
- if (hasSetDefault) {
10
- throw new Error("cannot update base anchor");
11
- }
12
- _baseAnchor = anchor;
13
- hasSetDefault = true;
14
- },
15
- LAST_ANCHOR_ID: 1,
16
- ORB_META: new WeakMap,
17
- ORB_STATE: new WeakMap,
18
- ORB_PLAN: new WeakMap,
19
- ORB_GETTER_CACHE: new WeakMap,
20
- FACTORY_PLAN: new WeakMap,
21
- MOUNTS: new WeakMap,
22
- MOUNT_FACTORIES: new WeakMap,
23
- SHAPE_NAMES: new Set,
24
- LINKS_BY_SOURCE: new Map,
25
- INSPECTORS: new Set
26
- };
27
- var VOCAB = {
28
- SHAPE: {
29
- NAME: Symbol.for("orbz.Shape.name"),
30
- INIT: Symbol.for("orbz.Shape.init"),
31
- KEYS: Symbol.for("orbz.Shape.keys"),
32
- EDGE: Symbol.for("orbz.Shape.edge"),
33
- SAVE: Symbol.for("orbz.Shape.save"),
34
- LOAD: Symbol.for("orbz.Shape.load"),
35
- MOUNTS: Symbol.for("orbz.Shape.mounts")
36
- }
37
- };
38
- VOCAB.SHAPE_SYMBOLS = new Set(Object.values(VOCAB.SHAPE));
39
- var ROUTE_SEGMENT = /^[A-Za-z0-9._~-]+$/;
40
- function assertRouteSegment(segment) {
41
- if (typeof segment !== "string" || segment.length === 0 || !ROUTE_SEGMENT.test(segment)) {
42
- throw new Error("Route segments must be non-empty URL-safe strings");
43
- }
44
- }
45
-
46
- // ../orbz/src/utils/shapePlan.js
47
- var hasOwn = Object.prototype.hasOwnProperty;
48
- function createShapePlan(definition, options = {}) {
49
- if (!definition || typeof definition !== "object") {
50
- throw new TypeError("Shape definition must be an object");
51
- }
52
- const descriptors = Object.getOwnPropertyDescriptors(definition);
53
- const identity = readShapeIdentity(descriptors);
54
- const parents = options.parents ?? [];
55
- const directParents = parents.map((plan2) => ({ id: plan2.id, name: plan2.name }));
56
- const ancestry = uniqueShapeRefs([
57
- ...parents.flatMap((parent) => parent.ancestry),
58
- ...directParents
59
- ]);
60
- const plan = {
61
- id: identity.id,
62
- name: identity.name,
63
- parents: directParents,
64
- ancestry,
65
- ancestryIds: new Set(ancestry.map((parent) => parent.id)),
66
- descriptors,
67
- entries: [],
68
- byKey: new Map,
69
- state: [],
70
- publicState: [],
71
- internalState: [],
72
- slots: [],
73
- serializable: [],
74
- enumerable: [],
75
- getters: [],
76
- pairedAccessors: [],
77
- shortcutSetters: [],
78
- methods: [],
79
- generatorMethods: [],
80
- protocol: {
81
- init: undefined,
82
- keys: undefined,
83
- edge: undefined,
84
- save: undefined,
85
- load: undefined
86
- },
87
- mounts: {}
88
- };
89
- let mountDescriptors;
90
- for (const key of Reflect.ownKeys(descriptors)) {
91
- if (typeof key === "symbol") {
92
- if (!VOCAB.SHAPE_SYMBOLS.has(key)) {
93
- throw new Error("Shape definitions may not use arbitrary symbol keys");
94
- }
95
- if (key === VOCAB.SHAPE.MOUNTS) {
96
- mountDescriptors = readMountDescriptors(descriptors[key]);
97
- continue;
98
- }
99
- indexProtocolMember(plan, key, descriptors[key]);
100
- continue;
101
- }
102
- if (key === "$") {
103
- throw new Error("Shape cannot define reserved key '$'");
104
- }
105
- const descriptor = descriptors[key];
106
- const entry = classifyShapeMember(key, descriptor);
107
- if (entry.meta.serializable) {
108
- assertRouteSegment(key);
109
- }
110
- plan.entries.push(entry);
111
- plan.byKey.set(key, entry);
112
- indexShapeEntry(plan, entry);
113
- }
114
- plan.mounts = normalizeMountDescriptors(mountDescriptors, plan);
115
- registerShapeName(identity.name);
116
- return plan;
117
- }
118
- function createExtendedShapeDefinition(parentPlans, definition) {
119
- if (!definition || typeof definition !== "object") {
120
- throw new TypeError("Shape definition must be an object");
121
- }
122
- const merged = {};
123
- for (const parent of parentPlans) {
124
- for (const [key, descriptor] of Object.entries(parent.descriptors)) {
125
- Object.defineProperty(merged, key, descriptor);
126
- }
127
- }
128
- for (const key of Reflect.ownKeys(definition)) {
129
- Object.defineProperty(merged, key, Object.getOwnPropertyDescriptor(definition, key));
130
- }
131
- return merged;
132
- }
133
- function indexProtocolMember(plan, key, descriptor) {
134
- if (key === VOCAB.SHAPE.NAME) {
135
- return;
136
- }
137
- if (!Object.prototype.hasOwnProperty.call(descriptor, "value") || typeof descriptor.value !== "function") {
138
- throw new Error("Shape protocol members must be methods");
139
- }
140
- if (key === VOCAB.SHAPE.INIT) {
141
- plan.protocol.init = descriptor.value;
142
- } else if (key === VOCAB.SHAPE.KEYS) {
143
- plan.protocol.keys = descriptor.value;
144
- } else if (key === VOCAB.SHAPE.EDGE) {
145
- plan.protocol.edge = descriptor.value;
146
- } else if (key === VOCAB.SHAPE.SAVE) {
147
- plan.protocol.save = descriptor.value;
148
- } else if (key === VOCAB.SHAPE.LOAD) {
149
- plan.protocol.load = descriptor.value;
150
- } else if (key === VOCAB.SHAPE.MOUNTS) {
151
- return;
152
- } else {
153
- throw new Error("Unknown Shape protocol member");
154
- }
155
- }
156
- function readShapeIdentity(descriptors) {
157
- const nameDescriptor = descriptors[VOCAB.SHAPE.NAME];
158
- if (!nameDescriptor || !Object.prototype.hasOwnProperty.call(nameDescriptor, "value")) {
159
- throw new Error("Shape.name is required");
160
- }
161
- const name = nameDescriptor.value;
162
- if (typeof name !== "string" || name.length === 0) {
163
- throw new TypeError("Shape.name must be a non-empty string");
164
- }
165
- return { id: name, name };
166
- }
167
- function uniqueShapeRefs(refs) {
168
- const seen = new Set;
169
- const out = [];
170
- for (const ref of refs) {
171
- if (seen.has(ref.id))
172
- continue;
173
- seen.add(ref.id);
174
- out.push(ref);
175
- }
176
- return out;
177
- }
178
- function registerShapeName(name) {
179
- if (MEM.SHAPE_NAMES.has(name)) {
180
- throw new Error(`Shape '${name}' is already defined`);
181
- }
182
- MEM.SHAPE_NAMES.add(name);
183
- }
184
- function classifyShapeMember(key, descriptor) {
185
- const hasValue = hasOwn.call(descriptor, "value");
186
- const hasGetter = typeof descriptor.get === "function";
187
- const hasSetter = typeof descriptor.set === "function";
188
- const internal = key.startsWith("_");
189
- if (hasValue) {
190
- if (typeof descriptor.value === "function") {
191
- if (isOrbFactory(descriptor.value)) {
192
- return {
193
- key,
194
- kind: "slot",
195
- value: descriptor.value,
196
- shapeId: descriptor.value.shapeId,
197
- descriptor,
198
- meta: {
199
- visibility: internal ? "internal" : "public",
200
- internal,
201
- enumerable: !internal,
202
- serializable: true,
203
- writableFromPublic: !internal,
204
- writableFromBehavior: true,
205
- acceptedInConstructor: true
206
- }
207
- };
208
- }
209
- const generator = isGeneratorFunction(descriptor.value);
210
- return {
211
- key,
212
- kind: generator ? "generatorMethod" : "method",
213
- value: descriptor.value,
214
- descriptor,
215
- meta: {
216
- internal: false,
217
- enumerable: false,
218
- serializable: false
219
- }
220
- };
221
- }
222
- assertJsonCompatibleStateDefault(key, descriptor.value);
223
- return {
224
- key,
225
- kind: "state",
226
- value: descriptor.value,
227
- descriptor,
228
- meta: {
229
- visibility: internal ? "internal" : "public",
230
- internal,
231
- enumerable: !internal,
232
- serializable: true,
233
- writableFromPublic: !internal,
234
- writableFromBehavior: true,
235
- acceptedInConstructor: true
236
- }
237
- };
238
- }
239
- if (hasGetter && hasSetter) {
240
- return {
241
- key,
242
- kind: "pairedAccessor",
243
- get: descriptor.get,
244
- set: descriptor.set,
245
- descriptor,
246
- meta: {
247
- internal,
248
- enumerable: false,
249
- serializable: false,
250
- acceptedInConstructor: true
251
- }
252
- };
253
- }
254
- if (hasGetter) {
255
- return {
256
- key,
257
- kind: "getter",
258
- get: descriptor.get,
259
- descriptor,
260
- meta: {
261
- internal,
262
- enumerable: false,
263
- serializable: false
264
- }
265
- };
266
- }
267
- if (hasSetter) {
268
- return {
269
- key,
270
- kind: "shortcutSetter",
271
- set: descriptor.set,
272
- descriptor,
273
- meta: {
274
- internal,
275
- enumerable: false,
276
- serializable: false,
277
- acceptedInConstructor: true
278
- }
279
- };
280
- }
281
- throw new Error(`Unsupported Shape member '${key}'`);
282
- }
283
- function indexShapeEntry(plan, entry) {
284
- if (entry.kind === "state") {
285
- plan.state.push(entry);
286
- plan.serializable.push(entry);
287
- if (entry.meta.internal) {
288
- plan.internalState.push(entry);
289
- } else {
290
- plan.publicState.push(entry);
291
- plan.enumerable.push(entry);
292
- }
293
- } else if (entry.kind === "slot") {
294
- plan.state.push(entry);
295
- plan.slots.push(entry);
296
- plan.serializable.push(entry);
297
- if (entry.meta.internal) {
298
- plan.internalState.push(entry);
299
- } else {
300
- plan.publicState.push(entry);
301
- plan.enumerable.push(entry);
302
- }
303
- } else if (entry.kind === "getter") {
304
- plan.getters.push(entry);
305
- } else if (entry.kind === "pairedAccessor") {
306
- plan.pairedAccessors.push(entry);
307
- } else if (entry.kind === "shortcutSetter") {
308
- plan.shortcutSetters.push(entry);
309
- } else if (entry.kind === "method") {
310
- plan.methods.push(entry);
311
- } else if (entry.kind === "generatorMethod") {
312
- plan.generatorMethods.push(entry);
313
- } else {
314
- throw new Error(`Unknown Shape entry kind '${entry.kind}'`);
315
- }
316
- }
317
- function readMountDescriptors(descriptor) {
318
- if (!Object.prototype.hasOwnProperty.call(descriptor, "value")) {
319
- throw new Error("Shape.mounts must be a plain object");
320
- }
321
- return descriptor.value;
322
- }
323
- function normalizeMountDescriptors(value, plan) {
324
- if (value === undefined)
325
- return {};
326
- if (!value || typeof value !== "object" || Array.isArray(value)) {
327
- throw new TypeError("Shape.mounts must be a plain object");
328
- }
329
- const out = {};
330
- const getters = new Set(plan.getters.map((entry) => entry.key));
331
- const commands = new Set([
332
- ...plan.methods.map((entry) => entry.key),
333
- ...plan.generatorMethods.map((entry) => entry.key)
334
- ]);
335
- for (const [target, rawConfig] of Object.entries(value)) {
336
- assertRouteSegment(target);
337
- if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
338
- throw new TypeError(`Shape.mounts.${target} must be a plain object`);
339
- }
340
- for (const key of Object.keys(rawConfig)) {
341
- if (key !== "outsource") {
342
- throw new Error(`Unsupported Shape.mounts.${target} option '${key}'`);
343
- }
344
- }
345
- const outsource = normalizeOutsourceList(rawConfig.outsource, target);
346
- const projections = [];
347
- const methods = [];
348
- for (const key of outsource) {
349
- if (getters.has(key)) {
350
- projections.push(key);
351
- } else if (commands.has(key)) {
352
- methods.push(key);
353
- } else {
354
- throw new Error(`Shape.mounts.${target} cannot outsource '${key}'`);
355
- }
356
- }
357
- out[target] = {
358
- target,
359
- outsource,
360
- projections,
361
- commands: methods
362
- };
363
- }
364
- return out;
365
- }
366
- function normalizeOutsourceList(value, target) {
367
- if (value === undefined)
368
- return [];
369
- if (!Array.isArray(value)) {
370
- throw new TypeError(`Shape.mounts.${target}.outsource must be an array`);
371
- }
372
- const seen = new Set;
373
- const out = [];
374
- for (const key of value) {
375
- if (typeof key !== "string" || key.length === 0) {
376
- throw new TypeError(`Shape.mounts.${target}.outsource entries must be non-empty strings`);
377
- }
378
- if (seen.has(key))
379
- continue;
380
- seen.add(key);
381
- out.push(key);
382
- }
383
- return out;
384
- }
385
- function isGeneratorFunction(value) {
386
- return typeof value === "function" && value.constructor && value.constructor.name === "GeneratorFunction";
387
- }
388
- function isOrbFactory(value) {
389
- return typeof value === "function" && typeof value.shapeId === "string";
390
- }
391
- function assertJsonCompatibleStateDefault(key, value) {
392
- if (isJsonCompatibleValue(value))
393
- return;
394
- throw new Error(`State default '${key}' must be JSON-compatible in v1`);
395
- }
396
- function isJsonCompatibleValue(value) {
397
- if (value === null)
398
- return true;
399
- switch (typeof value) {
400
- case "string":
401
- case "boolean":
402
- return true;
403
- case "number":
404
- return Number.isFinite(value);
405
- case "object":
406
- return isJsonCompatibleObject(value);
407
- default:
408
- return false;
409
- }
410
- }
411
- function isJsonCompatibleObject(value) {
412
- if (Array.isArray(value)) {
413
- return value.every(isJsonCompatibleValue);
414
- }
415
- const prototype = Object.getPrototypeOf(value);
416
- if (prototype !== Object.prototype && prototype !== null) {
417
- return false;
418
- }
419
- return Object.values(value).every(isJsonCompatibleValue);
420
- }
421
-
422
- // ../orbz/src/utils/inspection.js
423
- function emitInspectionEvent(event) {
424
- if (MEM.INSPECTORS.size === 0)
425
- return;
426
- const frozenEvent = Object.freeze({ ...event });
427
- for (const listener of [...MEM.INSPECTORS]) {
428
- listener(frozenEvent);
429
- }
430
- }
431
-
432
- // ../orbz/src/utils/reactivity.js
433
- var activeComputation = null;
434
- var batchDepth = 0;
435
- var isFlushing = false;
436
- var nextRuntimeOrbId = 1;
437
- var DEPENDENTS = new Map;
438
- var pendingEffects = new Set;
439
- var DEPENDENCY_KEYS = new WeakMap;
440
- var ORB_RUNTIME_ID = new WeakMap;
441
- function trackDependency(orb, key) {
442
- if (!activeComputation)
443
- return;
444
- activeComputation.nextDeps.add(createDependencyKey(orb, key));
445
- }
446
- function runTracked(computation, fn) {
447
- const parentComputation = activeComputation;
448
- computation.nextDeps = new Set;
449
- activeComputation = computation;
450
- try {
451
- return fn();
452
- } finally {
453
- activeComputation = parentComputation;
454
- }
455
- }
456
- function notifyDependencyChanged(orb, key) {
457
- const dependents = DEPENDENTS.get(createDependencyKey(orb, key));
458
- if (!dependents)
459
- return;
460
- for (const computation of [...dependents]) {
461
- if (computation.type === "effect" && computation.active) {
462
- pendingEffects.add(computation);
463
- } else if (computation.type === "getter") {
464
- computation.onDependencyChanged?.();
465
- }
466
- }
467
- flushEffects();
468
- }
469
- function replaceSubscriptions(computation) {
470
- removeSubscriptions(computation);
471
- computation.deps = computation.nextDeps;
472
- computation.nextDeps = new Set;
473
- for (const dependency of computation.deps) {
474
- let dependents = DEPENDENTS.get(dependency);
475
- if (!dependents) {
476
- dependents = new Set;
477
- DEPENDENTS.set(dependency, dependents);
478
- }
479
- dependents.add(computation);
480
- }
481
- }
482
- function removeSubscriptions(computation) {
483
- if (!computation.deps)
484
- return;
485
- for (const dependency of computation.deps) {
486
- const dependents = DEPENDENTS.get(dependency);
487
- if (!dependents)
488
- continue;
489
- dependents.delete(computation);
490
- if (dependents.size === 0) {
491
- DEPENDENTS.delete(dependency);
492
- }
493
- }
494
- computation.deps = new Set;
495
- }
496
- function batch(callback) {
497
- emitInspectionEvent({ type: "batch:start", depth: batchDepth + 1 });
498
- batchDepth++;
499
- try {
500
- return callback();
501
- } finally {
502
- batchDepth--;
503
- emitInspectionEvent({ type: "batch:end", depth: batchDepth + 1 });
504
- if (batchDepth === 0) {
505
- flushEffects();
506
- }
507
- }
508
- }
509
- function fx(callback) {
510
- if (typeof callback !== "function") {
511
- throw new TypeError("fx() expects a callback");
512
- }
513
- const effect = {
514
- type: "effect",
515
- active: true,
516
- deps: new Set,
517
- nextDeps: new Set,
518
- run() {
519
- if (!effect.active)
520
- return;
521
- emitInspectionEvent({ type: "effect:run" });
522
- runTracked(effect, callback);
523
- replaceSubscriptions(effect);
524
- }
525
- };
526
- effect.run();
527
- return () => {
528
- effect.active = false;
529
- pendingEffects.delete(effect);
530
- removeSubscriptions(effect);
531
- };
532
- }
533
- function createDependencyKey(orb, key) {
534
- let keys = DEPENDENCY_KEYS.get(orb);
535
- if (!keys) {
536
- keys = new Map;
537
- DEPENDENCY_KEYS.set(orb, keys);
538
- }
539
- if (!keys.has(key)) {
540
- keys.set(key, {
541
- target: getOrbRuntimeId(orb),
542
- key
543
- });
544
- }
545
- return keys.get(key);
546
- }
547
- function flushEffects() {
548
- if (batchDepth > 0 || isFlushing)
549
- return;
550
- isFlushing = true;
551
- try {
552
- while (pendingEffects.size > 0) {
553
- const effects = [...pendingEffects];
554
- pendingEffects.clear();
555
- for (const effect of effects) {
556
- effect.run();
557
- }
558
- }
559
- } finally {
560
- isFlushing = false;
561
- }
562
- }
563
- function getOrbRuntimeId(orb) {
564
- if (!ORB_RUNTIME_ID.has(orb)) {
565
- ORB_RUNTIME_ID.set(orb, nextRuntimeOrbId++);
566
- }
567
- return ORB_RUNTIME_ID.get(orb);
568
- }
569
- function createEachEffect({ node, callback, options, keys, peek, read }) {
570
- if (typeof callback !== "function") {
571
- throw new TypeError("eachEffect() expects a callback");
572
- }
573
- const itemStops = new Map;
574
- const itemValues = new Map;
575
- const scope = options.scope;
576
- let disposed = false;
577
- const stopMembership = fx(() => {
578
- const activeKeys = new Set;
579
- for (const key of keys()) {
580
- const value = peek(key);
581
- activeKeys.add(key);
582
- if (itemValues.get(key) === value && itemStops.has(key))
583
- continue;
584
- stopItem(key);
585
- itemValues.set(key, value);
586
- itemStops.set(key, fx(() => {
587
- const current = read(key);
588
- itemValues.set(key, current);
589
- callback(current, key, node);
590
- }));
591
- }
592
- for (const key of itemStops.keys()) {
593
- if (!activeKeys.has(key))
594
- stopItem(key);
595
- }
596
- });
597
- const stop = () => {
598
- if (disposed)
599
- return;
600
- disposed = true;
601
- stopMembership();
602
- for (const key of itemStops.keys())
603
- stopItem(key);
604
- };
605
- if (scope)
606
- scope.onDispose(stop);
607
- return stop;
608
- function stopItem(key) {
609
- itemStops.get(key)?.();
610
- itemStops.delete(key);
611
- itemValues.delete(key);
612
- }
613
- }
614
-
615
- // ../orbz/src/utils/createOrbFactory.js
616
- var { ORB_STATE, ORB_PLAN, ORB_GETTER_CACHE, FACTORY_PLAN } = MEM;
617
- var behaviorDepth = 0;
618
- var CONSTRUCT = Symbol("construct");
619
- var HYDRATE = Symbol("hydrate");
620
- function createOrbFactory(plan) {
621
-
622
- class Orb {
623
- constructor(input, mode = CONSTRUCT) {
624
- ORB_PLAN.set(this, plan);
625
- const state = createInitialState(plan);
626
- ORB_STATE.set(this, state);
627
- ORB_GETTER_CACHE.set(this, new Map);
628
- defineInstanceStateAccessors(this, plan);
629
- runWithBehaviorAuthority(() => {
630
- const normalized = mode === HYDRATE ? normalizeHydrationInput(this, plan, input) : normalizeConstructorInput(this, plan, input);
631
- applyConstructorInput(this, plan, normalized, {
632
- hydration: mode === HYDRATE
633
- });
634
- });
635
- MEM.BASE_ANCHOR.adoptRuntimeOrb(this);
636
- }
637
- toJSON() {
638
- return this[VOCAB.SHAPE.SAVE]();
639
- }
640
- }
641
- function OrbFactory(input) {
642
- return new Orb(input);
643
- }
644
- Object.defineProperty(Orb, "name", {
645
- value: sanitizeConstructorName(plan.id),
646
- configurable: true
647
- });
648
- Object.defineProperty(Orb, "shapeId", {
649
- value: plan.id,
650
- enumerable: true
651
- });
652
- Object.defineProperty(Orb, "hydrate", {
653
- enumerable: true,
654
- configurable: false,
655
- value(record) {
656
- return hydrateOrb(Orb, plan, record);
657
- }
658
- });
659
- Object.defineProperty(Orb, "accepts", {
660
- enumerable: true,
661
- configurable: false,
662
- value(value) {
663
- return acceptsShape(plan, value);
664
- }
665
- });
666
- Object.defineProperty(OrbFactory, "name", {
667
- value: sanitizeConstructorName(plan.id),
668
- configurable: true
669
- });
670
- Object.defineProperty(OrbFactory, "prototype", {
671
- value: Orb.prototype,
672
- configurable: false
673
- });
674
- Object.defineProperty(OrbFactory, "shapeId", {
675
- value: plan.id,
676
- enumerable: true
677
- });
678
- Object.defineProperty(OrbFactory, "hydrate", {
679
- enumerable: true,
680
- configurable: false,
681
- value(record) {
682
- return hydrateOrb(Orb, plan, record);
683
- }
684
- });
685
- Object.defineProperty(OrbFactory, "accepts", {
686
- enumerable: true,
687
- configurable: false,
688
- value(value) {
689
- return acceptsShape(plan, value);
690
- }
691
- });
692
- FACTORY_PLAN.set(OrbFactory, plan);
693
- Object.defineProperty(plan, "factory", {
694
- value: OrbFactory,
695
- enumerable: false,
696
- configurable: true
697
- });
698
- for (const entry of plan.entries) {
699
- switch (entry.kind) {
700
- case "state":
701
- case "slot":
702
- defineStateAccessor(Orb.prototype, entry);
703
- break;
704
- case "getter":
705
- defineGetter(Orb.prototype, entry);
706
- break;
707
- case "pairedAccessor":
708
- definePairedAccessor(Orb.prototype, entry);
709
- break;
710
- case "shortcutSetter":
711
- defineShortcutSetter(Orb.prototype, entry);
712
- break;
713
- case "method":
714
- defineMethod(Orb.prototype, entry);
715
- break;
716
- case "generatorMethod":
717
- defineGeneratorMethod(Orb.prototype, entry);
718
- break;
719
- default:
720
- throw new Error(`Unknown Shape entry kind '${entry.kind}'`);
721
- }
722
- }
723
- defineDollar(Orb.prototype);
724
- defineProtocol(Orb.prototype, plan);
725
- return OrbFactory;
726
- }
727
- function hydrateOrb(Orb, plan, record) {
728
- const input = parseHydrationRecord(record, plan);
729
- return new Orb(input, HYDRATE);
730
- }
731
- function parseHydrationRecord(record, plan) {
732
- if (typeof record === "string") {
733
- const parsed = JSON.parse(record);
734
- if (plan.protocol.load) {
735
- return parsed;
736
- } else {
737
- record = parsed;
738
- }
739
- }
740
- if (plan.protocol.load) {
741
- return record;
742
- } else if (!record || typeof record !== "object" || Array.isArray(record)) {
743
- throw new TypeError("Orb hydration record must be an object or JSON string");
744
- } else {
745
- return record;
746
- }
747
- }
748
- function defineInstanceStateAccessors(orb, plan) {
749
- for (const entry of plan.state) {
750
- defineStateAccessor(orb, entry);
751
- }
752
- }
753
- function createInitialState(plan) {
754
- const state = {};
755
- for (const entry of plan.state) {
756
- state[entry.key] = entry.kind === "slot" ? undefined : cloneDefault(entry.value);
757
- }
758
- return state;
759
- }
760
- function applyConstructorInput(orb, plan, input, options = {}) {
761
- if (input == null) {
762
- assertRequiredSlots(orb, plan);
763
- return;
764
- }
765
- if (typeof input !== "object") {
766
- throw new TypeError("Orb constructor input must be an object");
767
- }
768
- for (const [key, value] of Object.entries(input)) {
769
- const entry = plan.byKey.get(key);
770
- if (!entry) {
771
- throw new Error(`Unknown constructor key '${key}' for Shape '${plan.id}'`);
772
- }
773
- switch (entry.kind) {
774
- case "state":
775
- case "slot":
776
- if (value instanceof OrbLink) {
777
- const state = getState(orb);
778
- state[key] = value;
779
- value.bindOrb(orb, key);
780
- markStateChanged(orb, key);
781
- } else {
782
- orb[key] = value;
783
- }
784
- break;
785
- case "pairedAccessor":
786
- case "shortcutSetter":
787
- orb[key] = value;
788
- break;
789
- case "getter":
790
- throw new Error(`Cannot assign derived getter '${key}' during construction`);
791
- case "method":
792
- case "generatorMethod":
793
- throw new Error(`Cannot assign method '${key}' during construction`);
794
- default:
795
- throw new Error(`Unsupported constructor key '${key}'`);
796
- }
797
- }
798
- assertRequiredSlots(orb, plan);
799
- if (options.hydration) {
800
- for (const key of Object.keys(input)) {
801
- const entry = plan.byKey.get(key);
802
- if (entry?.meta?.serializable)
803
- continue;
804
- throw new Error(`Hydration key '${key}' is not persisted state`);
805
- }
806
- }
807
- }
808
- function normalizeConstructorInput(orb, plan, input) {
809
- const normalized = (plan.protocol.init ?? defaultInit).call(orb, input);
810
- if (!normalized || typeof normalized !== "object" || Array.isArray(normalized)) {
811
- throw new TypeError("Shape.init must return constructor state");
812
- }
813
- return normalized;
814
- }
815
- function normalizeHydrationInput(orb, plan, input) {
816
- const normalized = (plan.protocol.load ?? defaultLoad).call(orb, input);
817
- if (!normalized || typeof normalized !== "object" || Array.isArray(normalized)) {
818
- throw new TypeError("Shape.load must return constructor state");
819
- }
820
- return normalized;
821
- }
822
- function serializeDefaultOrb(orb, plan) {
823
- const state = getState(orb);
824
- const out = {};
825
- for (const entry of plan.serializable) {
826
- out[entry.key] = serializeSlot(state[entry.key]);
827
- }
828
- return out;
829
- }
830
- function defaultInit(input = {}) {
831
- if (!input || typeof input !== "object" || Array.isArray(input)) {
832
- throw new TypeError("Orb constructor input must be an object");
833
- }
834
- return input;
835
- }
836
- function defaultLoad(input = {}) {
837
- if (!input || typeof input !== "object" || Array.isArray(input)) {
838
- throw new TypeError("Orb hydration record must be an object or JSON string");
839
- }
840
- return input;
841
- }
842
- function defineStateAccessor(proto, entry) {
843
- Object.defineProperty(proto, entry.key, {
844
- enumerable: entry.meta.enumerable,
845
- configurable: false,
846
- get() {
847
- const state = getState(this);
848
- if (entry.meta.internal && !hasBehaviorAuthority()) {
849
- throw new Error(`Cannot read internal state '${entry.key}' from outside Shape behavior`);
850
- }
851
- trackDependency(this, entry.key);
852
- return readSlot(state[entry.key]);
853
- },
854
- set(value) {
855
- if (entry.meta.internal && !hasBehaviorAuthority()) {
856
- throw new Error(`Cannot write internal state '${entry.key}' from outside Shape behavior`);
857
- }
858
- const state = getState(this);
859
- const previous = state[entry.key];
860
- if (previous instanceof OrbLink) {
861
- throw new Error(`Cannot write linked state slot '${entry.key}'`);
862
- }
863
- state[entry.key] = prepareStateValue(this, entry, value);
864
- if (!Object.is(previous, value)) {
865
- batch(() => {
866
- emitOrbEvent(this, "state:write", entry.key);
867
- markStateChanged(this, entry.key);
868
- const meta = MEM.ORB_META.get(this);
869
- meta?.anchor?.handleOrbSlotChanged?.(this, entry.key);
870
- });
871
- }
872
- }
873
- });
874
- }
875
- function prepareStateValue(orb, entry, value) {
876
- if (entry.kind === "slot") {
877
- assertSlotValue(entry, value);
878
- }
879
- return value;
880
- }
881
- function assertRequiredSlots(orb, plan) {
882
- const state = getState(orb);
883
- for (const entry of plan.slots) {
884
- if (state[entry.key] === undefined) {
885
- throw new Error(`Missing required slot '${entry.key}'`);
886
- }
887
- }
888
- }
889
- function assertSlotValue(entry, value) {
890
- if (value instanceof OrbLink)
891
- return;
892
- if (value instanceof LazyRef)
893
- return;
894
- if (!entry.value.accepts(value)) {
895
- throw new Error(`Slot '${entry.key}' expects Shape '${entry.shapeId}'`);
896
- }
897
- }
898
- function defineGetter(proto, entry) {
899
- Object.defineProperty(proto, entry.key, {
900
- enumerable: false,
901
- configurable: false,
902
- get() {
903
- return readCachedGetter(this, entry);
904
- }
905
- });
906
- }
907
- function definePairedAccessor(proto, entry) {
908
- Object.defineProperty(proto, entry.key, {
909
- enumerable: false,
910
- configurable: false,
911
- get() {
912
- return readCachedGetter(this, entry);
913
- },
914
- set(value) {
915
- return batch(() => runWithBehaviorAuthority(() => entry.set.call(this, value)));
916
- }
917
- });
918
- }
919
- function defineShortcutSetter(proto, entry) {
920
- Object.defineProperty(proto, entry.key, {
921
- enumerable: false,
922
- configurable: false,
923
- get() {
924
- return;
925
- },
926
- set(value) {
927
- return batch(() => runWithBehaviorAuthority(() => entry.set.call(this, value)));
928
- }
929
- });
930
- }
931
- function defineMethod(proto, entry) {
932
- Object.defineProperty(proto, entry.key, {
933
- enumerable: false,
934
- configurable: false,
935
- value(...args) {
936
- return batch(() => runWithBehaviorAuthority(() => entry.value.apply(this, args)));
937
- }
938
- });
939
- }
940
- function defineGeneratorMethod(proto, entry) {
941
- Object.defineProperty(proto, entry.key, {
942
- enumerable: false,
943
- configurable: false,
944
- value(...args) {
945
- const iterator = runWithBehaviorAuthority(() => entry.value.apply(this, args));
946
- return runGeneratorFlow(iterator);
947
- }
948
- });
949
- }
950
- function defineDollar(proto) {
951
- Object.defineProperty(proto, "$", {
952
- enumerable: false,
953
- configurable: false,
954
- get() {
955
- const orb = this;
956
- function createLink(key) {
957
- if (typeof key !== "string") {
958
- throw new TypeError("orb.$() expects a property key string in v1");
959
- }
960
- const plan = ORB_PLAN.get(orb);
961
- if (!plan.byKey.has(key)) {
962
- throw new Error(`Cannot create link to unknown key '${key}'`);
963
- }
964
- const entry = plan.byKey.get(key);
965
- if (!isPublicReadableEntry(entry)) {
966
- throw new Error(`Cannot create link to unreadable key '${key}'`);
967
- }
968
- return new OrbLink(orb, key, { $: `${getOrbId(orb)}/${key}` });
969
- }
970
- Object.defineProperty(createLink, "uuid", {
971
- enumerable: true,
972
- configurable: true,
973
- get() {
974
- return MEM.ORB_META.get(orb)?.uuid ?? getOrbRuntimeId2(orb);
975
- }
976
- });
977
- Object.defineProperty(createLink, "anchor", {
978
- enumerable: true,
979
- configurable: true,
980
- get() {
981
- return MEM.ORB_META.get(orb)?.anchor;
982
- }
983
- });
984
- Object.defineProperty(createLink, "routes", {
985
- enumerable: true,
986
- configurable: true,
987
- get() {
988
- return [...MEM.ORB_META.get(orb)?.routes ?? []];
989
- }
990
- });
991
- Object.defineProperty(createLink, "mount", {
992
- enumerable: true,
993
- configurable: true,
994
- get() {
995
- return createMountApi(orb);
996
- }
997
- });
998
- Object.defineProperty(createLink, "track", {
999
- enumerable: true,
1000
- configurable: true,
1001
- value(token) {
1002
- assertBehaviorAuthority("track");
1003
- trackDependency(orb, token);
1004
- }
1005
- });
1006
- Object.defineProperty(createLink, "changed", {
1007
- enumerable: true,
1008
- configurable: true,
1009
- value(token) {
1010
- assertBehaviorAuthority("changed");
1011
- markStateChanged(orb, token);
1012
- const meta = MEM.ORB_META.get(orb);
1013
- meta?.anchor?.handleOrbProtocolChanged?.(orb, token);
1014
- }
1015
- });
1016
- return createLink;
1017
- }
1018
- });
1019
- }
1020
- function createMountApi(orb) {
1021
- return {
1022
- get info() {
1023
- return cloneMountInfo(MEM.MOUNTS.get(orb));
1024
- },
1025
- status(key) {
1026
- return readMountBackingState(orb, "_mount_statuses", key);
1027
- },
1028
- error(key) {
1029
- return readMountBackingState(orb, "_mount_errors", key);
1030
- },
1031
- apply(patch = {}) {
1032
- return applyMountPatch(orb, patch);
1033
- }
1034
- };
1035
- }
1036
- function applyMountPatch(orb, patch = {}) {
1037
- const runtime = MEM.MOUNTS.get(orb);
1038
- if (!runtime)
1039
- return;
1040
- const apply = orb?._mountApply;
1041
- if (typeof apply !== "function") {
1042
- throw new Error("Mounted orb is missing generated _mountApply()");
1043
- }
1044
- return apply.call(orb, patch);
1045
- }
1046
- function readMountBackingState(orb, stateKey, key) {
1047
- if (!MEM.MOUNTS.has(orb))
1048
- return;
1049
- const values = runWithBehaviorAuthority(() => orb[stateKey]);
1050
- if (key === undefined)
1051
- return values;
1052
- return values?.[key];
1053
- }
1054
- function cloneMountInfo(runtime) {
1055
- if (!runtime)
1056
- return;
1057
- return {
1058
- source: { ...runtime.source },
1059
- target: runtime.target,
1060
- shape: { ...runtime.shape },
1061
- outsource: [...runtime.outsource],
1062
- projections: [...runtime.projections],
1063
- commands: [...runtime.commands]
1064
- };
1065
- }
1066
- function defineProtocol(proto, plan) {
1067
- const protocol = {
1068
- [VOCAB.SHAPE.KEYS]: plan.protocol.keys ?? defaultKeys,
1069
- [VOCAB.SHAPE.EDGE]: plan.protocol.edge ?? defaultEdge,
1070
- [VOCAB.SHAPE.SAVE]: plan.protocol.save ?? defaultSave,
1071
- [VOCAB.SHAPE.LOAD]: plan.protocol.load ?? defaultLoad,
1072
- [VOCAB.SHAPE.INIT]: plan.protocol.init ?? defaultInit
1073
- };
1074
- defineProtocolMethod(proto, VOCAB.SHAPE.INIT, protocol[VOCAB.SHAPE.INIT]);
1075
- defineProtocolMethod(proto, VOCAB.SHAPE.KEYS, protocol[VOCAB.SHAPE.KEYS]);
1076
- defineProtocolMethod(proto, VOCAB.SHAPE.EDGE, protocol[VOCAB.SHAPE.EDGE]);
1077
- defineProtocolMethod(proto, VOCAB.SHAPE.SAVE, protocol[VOCAB.SHAPE.SAVE]);
1078
- defineProtocolMethod(proto, VOCAB.SHAPE.LOAD, protocol[VOCAB.SHAPE.LOAD]);
1079
- function defaultKeys() {
1080
- return plan.serializable.map((entry) => entry.key);
1081
- }
1082
- function defaultEdge(key) {
1083
- const entry = plan.byKey.get(key);
1084
- if (!entry || !entry.meta.serializable) {
1085
- throw new Error(`Unknown edge '${String(key)}'`);
1086
- }
1087
- const orb = this;
1088
- const state = getState(orb);
1089
- return {
1090
- key,
1091
- segment: String(key),
1092
- read() {
1093
- trackDependency(orb, key);
1094
- return readSlot(state[key]);
1095
- },
1096
- peek() {
1097
- return state[key];
1098
- },
1099
- write(value) {
1100
- return runWithBehaviorAuthority(() => {
1101
- orb[key] = value;
1102
- return value;
1103
- });
1104
- }
1105
- };
1106
- }
1107
- function defaultSave() {
1108
- return serializeDefaultOrb(this, plan);
1109
- }
1110
- }
1111
- function defineProtocolMethod(proto, symbol, method) {
1112
- Object.defineProperty(proto, symbol, {
1113
- enumerable: false,
1114
- configurable: false,
1115
- value(...args) {
1116
- return runWithBehaviorAuthority(() => {
1117
- const result = method.apply(this, args);
1118
- return symbol === VOCAB.SHAPE.EDGE ? wrapEdgeBehavior(result) : result;
1119
- });
1120
- }
1121
- });
1122
- }
1123
- function wrapEdgeBehavior(edge) {
1124
- if (!edge || typeof edge !== "object") {
1125
- return edge;
1126
- }
1127
- const wrapped = { ...edge };
1128
- for (const key of Reflect.ownKeys(wrapped)) {
1129
- if (typeof wrapped[key] !== "function")
1130
- continue;
1131
- const method = wrapped[key];
1132
- wrapped[key] = function edgeBehaviorMethod(...args) {
1133
- const run = () => runWithBehaviorAuthority(() => method.apply(edge, args));
1134
- return key === "write" || key === "delete" ? batch(run) : run();
1135
- };
1136
- }
1137
- return wrapped;
1138
- }
1139
- function isPublicReadableEntry(entry) {
1140
- if (entry.meta.internal)
1141
- return false;
1142
- return entry.kind === "state" || entry.kind === "getter" || entry.kind === "pairedAccessor";
1143
- }
1144
- function readCachedGetter(orb, entry) {
1145
- trackDependency(orb, entry.key);
1146
- const cache = getGetterCache(orb, entry.key);
1147
- if (cache.hasValue && !cache.dirty) {
1148
- emitOrbEvent(orb, "getter:cache-hit", entry.key);
1149
- return cache.value;
1150
- }
1151
- const computation = getGetterComputation(orb, entry.key);
1152
- try {
1153
- emitOrbEvent(orb, "getter:compute", entry.key);
1154
- const value = runTracked(computation, () => runWithBehaviorAuthority(() => entry.get.call(orb)));
1155
- cache.value = wrapBehaviorFunction(value, orb);
1156
- replaceSubscriptions(computation);
1157
- cache.deps = computation.deps;
1158
- cache.dirty = false;
1159
- cache.hasValue = true;
1160
- return cache.value;
1161
- } catch (error) {
1162
- replaceSubscriptions(computation);
1163
- cache.deps = computation.deps;
1164
- cache.dirty = true;
1165
- cache.hasValue = false;
1166
- throw error;
1167
- }
1168
- }
1169
- function wrapBehaviorFunction(value, orb) {
1170
- if (typeof value !== "function")
1171
- return value;
1172
- return function behaviorFunction(...args) {
1173
- return runWithBehaviorAuthority(() => value.apply(orb, args));
1174
- };
1175
- }
1176
- function getGetterCache(orb, key) {
1177
- const getterCache = ORB_GETTER_CACHE.get(orb);
1178
- if (!getterCache) {
1179
- throw new Error("Invalid Orb receiver");
1180
- }
1181
- if (!getterCache.has(key)) {
1182
- getterCache.set(key, {
1183
- value: undefined,
1184
- deps: new Set,
1185
- dirty: true,
1186
- hasValue: false,
1187
- computation: {
1188
- type: "getter",
1189
- orb,
1190
- key,
1191
- deps: new Set,
1192
- nextDeps: new Set,
1193
- onDependencyChanged() {
1194
- markGetterDirty(orb, key);
1195
- }
1196
- }
1197
- });
1198
- }
1199
- return getterCache.get(key);
1200
- }
1201
- function getGetterComputation(orb, key) {
1202
- return getGetterCache(orb, key).computation;
1203
- }
1204
- function markGetterDependentsDirty(orb, changedKey) {
1205
- const getterCache = ORB_GETTER_CACHE.get(orb);
1206
- if (!getterCache)
1207
- return;
1208
- const changedDependency = createDependencyKey(orb, changedKey);
1209
- for (const [getterKey, cache] of getterCache) {
1210
- if (cache.deps.has(changedDependency)) {
1211
- markGetterDirty(orb, getterKey);
1212
- }
1213
- }
1214
- }
1215
- function markGetterDirty(orb, getterKey) {
1216
- const cache = getGetterCache(orb, getterKey);
1217
- if (cache.dirty) {
1218
- emitOrbEvent(orb, "getter:dirty", getterKey);
1219
- notifyDependencyChanged(orb, getterKey);
1220
- propagateLinkedState(orb, getterKey);
1221
- return;
1222
- }
1223
- cache.dirty = true;
1224
- emitOrbEvent(orb, "getter:dirty", getterKey);
1225
- notifyDependencyChanged(orb, getterKey);
1226
- propagateLinkedState(orb, getterKey);
1227
- markGetterDependentsDirty(orb, getterKey);
1228
- }
1229
- function markStateChanged(orb, key) {
1230
- markGetterDependentsDirty(orb, key);
1231
- notifyDependencyChanged(orb, key);
1232
- propagateLinkedState(orb, key);
1233
- }
1234
- function propagateLinkedState(source, sourceKey) {
1235
- for (const { target, key } of OrbLink.linkedTargets(source, sourceKey)) {
1236
- markStateChanged(target, key);
1237
- }
1238
- }
1239
- function runGeneratorFlow(iterator) {
1240
- return new Promise((resolve, reject) => {
1241
- function step(method, value) {
1242
- let result;
1243
- try {
1244
- result = batch(() => runWithBehaviorAuthority(() => iterator[method](value)));
1245
- } catch (error) {
1246
- reject(error);
1247
- return;
1248
- }
1249
- if (result.done) {
1250
- resolve(result.value);
1251
- return;
1252
- }
1253
- Promise.resolve(result.value).then((value2) => step("next", value2), (error) => step("throw", error));
1254
- }
1255
- step("next");
1256
- });
1257
- }
1258
- function runWithBehaviorAuthority(fn) {
1259
- behaviorDepth++;
1260
- try {
1261
- return fn();
1262
- } finally {
1263
- behaviorDepth--;
1264
- }
1265
- }
1266
- function hasBehaviorAuthority() {
1267
- return behaviorDepth > 0;
1268
- }
1269
- function assertBehaviorAuthority(method) {
1270
- if (!hasBehaviorAuthority()) {
1271
- throw new Error(`node.$.${method}() may only be called from Shape behavior`);
1272
- }
1273
- }
1274
- function getState(orb) {
1275
- const state = ORB_STATE.get(orb);
1276
- if (!state) {
1277
- throw new Error("Invalid Orb receiver");
1278
- }
1279
- return state;
1280
- }
1281
- function emitOrbEvent(orb, type, key) {
1282
- emitInspectionEvent({ type, key, shapeId: ORB_PLAN.get(orb)?.id });
1283
- }
1284
- function cloneDefault(value) {
1285
- if (value === undefined)
1286
- return;
1287
- return JSON.parse(JSON.stringify(value));
1288
- }
1289
- function sanitizeConstructorName(shapeId) {
1290
- const name = shapeId.replace(/[^a-zA-Z0-9_$]/g, "_");
1291
- if (/^[a-zA-Z_$]/.test(name)) {
1292
- return name;
1293
- }
1294
- return `Shape_${name}`;
1295
- }
1296
- function getOrbId(orb) {
1297
- return `$uuid:${getOrbRuntimeId2(orb)}`;
1298
- }
1299
- var nextRuntimeOrbId2 = 1;
1300
- var ORB_RUNTIME_ID2 = new WeakMap;
1301
- function getOrbRuntimeId2(orb) {
1302
- if (!ORB_RUNTIME_ID2.has(orb)) {
1303
- ORB_RUNTIME_ID2.set(orb, nextRuntimeOrbId2++);
1304
- }
1305
- return ORB_RUNTIME_ID2.get(orb);
1306
- }
1307
- function acceptsShape(expectedPlan, value) {
1308
- const valuePlan = FACTORY_PLAN.get(value) ?? ORB_PLAN.get(value);
1309
- if (!valuePlan)
1310
- return false;
1311
- return valuePlan.id === expectedPlan.id || valuePlan.ancestryIds.has(expectedPlan.id);
1312
- }
1313
- function resolveLazyRef(orb, key, value) {
1314
- const plan = ORB_PLAN.get(orb);
1315
- const entry = plan?.byKey.get(key);
1316
- if (!entry || !entry.meta?.serializable) {
1317
- return resolveProtocolLazyRef(orb, key, value);
1318
- }
1319
- const state = ORB_STATE.get(orb);
1320
- if (!state) {
1321
- throw new Error("Invalid Orb receiver");
1322
- }
1323
- if (!(state[key] instanceof LazyRef)) {
1324
- throw new Error(`Slot '${key}' is not a lazy ref`);
1325
- }
1326
- state[key] = prepareStateValue(orb, entry, value);
1327
- batch(() => {
1328
- emitOrbEvent(orb, "state:write", key);
1329
- markStateChanged(orb, key);
1330
- const meta = MEM.ORB_META.get(orb);
1331
- meta?.anchor?.handleOrbSlotChanged?.(orb, key);
1332
- });
1333
- return value;
1334
- }
1335
- function resolveProtocolLazyRef(orb, key, value) {
1336
- const edge = orb[VOCAB.SHAPE.EDGE](key);
1337
- const current = edge.peek();
1338
- if (current !== undefined && !(current instanceof LazyRef)) {
1339
- throw new Error(`Protocol edge '${key}' is not a lazy ref`);
1340
- }
1341
- edge.write(value);
1342
- return value;
1343
- }
1344
-
1345
- class OrbLink {
1346
- constructor(source, key, descriptor) {
1347
- this.source = source;
1348
- this.key = key;
1349
- this.descriptor = descriptor;
1350
- }
1351
- read() {
1352
- return this.source[this.key];
1353
- }
1354
- serialize() {
1355
- return this.descriptor;
1356
- }
1357
- target() {
1358
- return { source: this.source, key: this.key };
1359
- }
1360
- bindOrb(target, key) {
1361
- const dependency = createDependencyKey(this.source, this.key);
1362
- let targets = MEM.LINKS_BY_SOURCE.get(dependency);
1363
- if (!targets) {
1364
- targets = new Set;
1365
- MEM.LINKS_BY_SOURCE.set(dependency, targets);
1366
- }
1367
- targets.add({ target, key });
1368
- }
1369
- static linkedTargets(source, key) {
1370
- const targets = MEM.LINKS_BY_SOURCE.get(createDependencyKey(source, key));
1371
- return targets ? [...targets] : [];
1372
- }
1373
- }
1374
-
1375
- class LazyRef {
1376
- constructor(ref) {
1377
- if (typeof ref !== "string" || ref.length === 0) {
1378
- throw new TypeError("LazyRef expects a non-empty ref string");
1379
- }
1380
- this.ref = ref;
1381
- this.status = "idle";
1382
- }
1383
- }
1384
- function readSlot(value) {
1385
- if (value instanceof OrbLink)
1386
- return value.read();
1387
- if (value instanceof LazyRef)
1388
- return;
1389
- return value;
1390
- }
1391
- function serializeSlot(value) {
1392
- if (value instanceof OrbLink)
1393
- return value.serialize();
1394
- if (value instanceof LazyRef)
1395
- return { $: value.ref };
1396
- return value;
1397
- }
1398
-
1399
- // ../orbz/src/Shape.js
1400
- function Shape(...defs) {
1401
- if (defs.length < 1) {
1402
- throw new TypeError("Shape() expects a definition object");
1403
- }
1404
- const finalDefinition = defs.at(-1);
1405
- const parents = defs.slice(0, -1);
1406
- if (parents.length === 0) {
1407
- const plan2 = createShapePlan(finalDefinition);
1408
- return createOrbFactory(plan2);
1409
- }
1410
- const parentPlans = parents.map((parent) => {
1411
- const plan2 = MEM.FACTORY_PLAN.get(parent);
1412
- if (!plan2) {
1413
- throw new TypeError("Shape extension parents must be Shape factories");
1414
- }
1415
- return plan2;
1416
- });
1417
- const extendedDefinition = createExtendedShapeDefinition(parentPlans, finalDefinition);
1418
- const plan = createShapePlan(extendedDefinition, { parents: parentPlans });
1419
- return createOrbFactory(plan);
1420
- }
1421
- Object.defineProperties(Shape, {
1422
- name: { value: VOCAB.SHAPE.NAME, enumerable: true, configurable: true },
1423
- init: { value: VOCAB.SHAPE.INIT, enumerable: true },
1424
- keys: { value: VOCAB.SHAPE.KEYS, enumerable: true },
1425
- edge: { value: VOCAB.SHAPE.EDGE, enumerable: true },
1426
- save: { value: VOCAB.SHAPE.SAVE, enumerable: true },
1427
- load: { value: VOCAB.SHAPE.LOAD, enumerable: true },
1428
- mounts: { value: VOCAB.SHAPE.MOUNTS, enumerable: true }
1429
- });
1430
- // ../orbz/src/libShapes/Mount.js
1431
- var MOUNT_RESERVED_KEYS = new Set([
1432
- "_mount_values",
1433
- "_mount_statuses",
1434
- "_mount_errors",
1435
- "_mount_logs",
1436
- "_mountApply",
1437
- "_mountDispose"
1438
- ]);
1439
- var FACTORY_CACHE = new WeakMap;
1440
- function createMountedFactory(SourceShape, target) {
1441
- const sourcePlan = MEM.FACTORY_PLAN.get(SourceShape);
1442
- if (!sourcePlan)
1443
- throw new TypeError("createMountedFactory() expects a Shape factory");
1444
- const mount = sourcePlan.mounts?.[target];
1445
- if (!mount)
1446
- return null;
1447
- let byTarget = FACTORY_CACHE.get(SourceShape);
1448
- if (!byTarget) {
1449
- byTarget = new Map;
1450
- FACTORY_CACHE.set(SourceShape, byTarget);
1451
- }
1452
- if (byTarget.has(target))
1453
- return byTarget.get(target);
1454
- assertOrdinarySourceShape(sourcePlan);
1455
- assertReservedKeysAvailable(sourcePlan);
1456
- const mountedName = `${sourcePlan.name}$mount$${target}`;
1457
- const definition = createMountDefinition(sourcePlan, {
1458
- target,
1459
- name: mountedName,
1460
- source: {
1461
- id: sourcePlan.id,
1462
- name: sourcePlan.name
1463
- },
1464
- outsource: mount.outsource,
1465
- projections: mount.projections,
1466
- commands: mount.commands
1467
- });
1468
- const MountedShape = Shape(SourceShape, definition);
1469
- MEM.MOUNT_FACTORIES.set(MountedShape, {
1470
- sourceFactory: SourceShape,
1471
- source: {
1472
- id: sourcePlan.id,
1473
- name: sourcePlan.name
1474
- },
1475
- sourcePlan,
1476
- target,
1477
- shape: {
1478
- id: mountedName,
1479
- name: mountedName
1480
- },
1481
- outsource: [...mount.outsource],
1482
- projections: [...mount.projections],
1483
- commands: [...mount.commands]
1484
- });
1485
- byTarget.set(target, MountedShape);
1486
- return MountedShape;
1487
- }
1488
- function isMountedOrb(value) {
1489
- return MEM.MOUNTS.has(value);
1490
- }
1491
- function getMountSourcePlan(orb) {
1492
- return MEM.MOUNTS.get(orb)?.sourcePlan;
1493
- }
1494
- function bindMountedOrb(anchor, orb) {
1495
- const runtime = MEM.MOUNTS.get(orb);
1496
- if (!runtime)
1497
- return;
1498
- const routes = [...MEM.ORB_META.get(orb)?.routes ?? []];
1499
- const contextKey = `${anchor.id}:${routes.join("|")}`;
1500
- if (runtime.anchor === anchor && runtime.contextKey === contextKey)
1501
- return;
1502
- runtime.unsubscribe?.();
1503
- runtime.anchor = anchor;
1504
- runtime.contextKey = contextKey;
1505
- runtime.routes = routes;
1506
- runtime.unsubscribe = undefined;
1507
- if (routes.length === 0)
1508
- return;
1509
- const subscribe = anchor.adapter.mount?.subscribe;
1510
- if (typeof subscribe !== "function") {
1511
- applyMountPatch2(orb, {
1512
- statuses: Object.fromEntries(runtime.projections.map((key) => [key, "pending"]))
1513
- });
1514
- return;
1515
- }
1516
- const unsubscribe = subscribe.call(anchor.adapter.mount, createMountContext(anchor, orb, runtime), (patch) => applyMountPatch2(orb, patch));
1517
- runtime.unsubscribe = typeof unsubscribe === "function" ? unsubscribe : undefined;
1518
- }
1519
- function disposeMountedOrb(orb) {
1520
- const runtime = MEM.MOUNTS.get(orb);
1521
- if (!runtime)
1522
- return;
1523
- runtime.unsubscribe?.();
1524
- runtime.unsubscribe = undefined;
1525
- runtime.anchor = null;
1526
- MEM.MOUNTS.delete(orb);
1527
- return;
1528
- }
1529
- function commandMountedOrb(orb, method, args) {
1530
- const runtime = MEM.MOUNTS.get(orb);
1531
- if (!runtime) {
1532
- throw new Error(`Cannot call mounted method '${method}' on a non-mounted Orb`);
1533
- }
1534
- const anchor = runtime.anchor ?? MEM.ORB_META.get(orb)?.anchor;
1535
- const command = anchor?.adapter.mount?.command;
1536
- if (typeof command !== "function") {
1537
- throw new Error(`Mounted method '${method}' requires an Anchor mount adapter`);
1538
- }
1539
- return command.call(anchor.adapter.mount, createMountContext(anchor, orb, runtime), method, args);
1540
- }
1541
- function applyMountPatch2(orb, patch = {}) {
1542
- const runtime = MEM.MOUNTS.get(orb);
1543
- if (!runtime)
1544
- return;
1545
- const normalized = normalizePatch(patch);
1546
- const apply = orb?._mountApply;
1547
- if (typeof apply !== "function") {
1548
- throw new Error("Mounted orb is missing generated _mountApply()");
1549
- }
1550
- return apply.call(orb, normalized);
1551
- }
1552
- function createMountDefinition(sourcePlan, config) {
1553
- const projections = new Set(config.projections);
1554
- const commands = new Set(config.commands);
1555
- const definition = {};
1556
- Object.defineProperty(definition, VOCAB.SHAPE.NAME, {
1557
- value: config.name,
1558
- enumerable: true,
1559
- configurable: true
1560
- });
1561
- for (const key of projections) {
1562
- const descriptor = sourcePlan.descriptors[key];
1563
- Object.defineProperty(definition, key, {
1564
- get() {
1565
- return this._mount_values[key];
1566
- },
1567
- enumerable: descriptor.enumerable,
1568
- configurable: descriptor.configurable
1569
- });
1570
- }
1571
- for (const key of commands) {
1572
- const descriptor = sourcePlan.descriptors[key];
1573
- Object.defineProperty(definition, key, {
1574
- value(...args) {
1575
- return commandMountedOrb(this, key, args);
1576
- },
1577
- enumerable: descriptor.enumerable,
1578
- configurable: descriptor.configurable,
1579
- writable: descriptor.writable
1580
- });
1581
- }
1582
- defineMountState(definition);
1583
- defineGeneratedMethod(definition, "_mountApply", mountApplyBehavior);
1584
- defineGeneratedMethod(definition, "_mountDispose", mountDisposeBehavior);
1585
- defineMountProtocol(definition, sourcePlan);
1586
- Object.defineProperty(definition, VOCAB.SHAPE.INIT, {
1587
- value(input = {}) {
1588
- initializeMountRuntime(this, config);
1589
- return normalizeConstructorState(input, "Orb constructor input");
1590
- },
1591
- enumerable: true,
1592
- configurable: true,
1593
- writable: true
1594
- });
1595
- Object.defineProperty(definition, VOCAB.SHAPE.LOAD, {
1596
- value(input = {}) {
1597
- initializeMountRuntime(this, config);
1598
- return normalizeConstructorState(input, "Orb hydration record");
1599
- },
1600
- enumerable: true,
1601
- configurable: true,
1602
- writable: true
1603
- });
1604
- return definition;
1605
- }
1606
- function defineMountProtocol(definition, sourcePlan) {
1607
- const sourceKeys = sourcePlan.serializable.map((entry) => entry.key);
1608
- const sourceKeySet = new Set(sourceKeys);
1609
- Object.defineProperty(definition, VOCAB.SHAPE.KEYS, {
1610
- value() {
1611
- return [...sourceKeys];
1612
- },
1613
- enumerable: true,
1614
- configurable: true,
1615
- writable: true
1616
- });
1617
- Object.defineProperty(definition, VOCAB.SHAPE.EDGE, {
1618
- value(key) {
1619
- if (!sourceKeySet.has(key)) {
1620
- throw new Error(`Unknown mount edge '${String(key)}'`);
1621
- }
1622
- return {
1623
- key,
1624
- segment: String(key),
1625
- read: () => this[key],
1626
- peek: () => this[key],
1627
- write: (value) => {
1628
- this[key] = value;
1629
- return value;
1630
- }
1631
- };
1632
- },
1633
- enumerable: true,
1634
- configurable: true,
1635
- writable: true
1636
- });
1637
- Object.defineProperty(definition, VOCAB.SHAPE.SAVE, {
1638
- value() {
1639
- const out = {};
1640
- for (const key of sourceKeys) {
1641
- out[key] = this[key];
1642
- }
1643
- return out;
1644
- },
1645
- enumerable: true,
1646
- configurable: true,
1647
- writable: true
1648
- });
1649
- }
1650
- function defineMountState(definition) {
1651
- Object.defineProperties(definition, {
1652
- _mount_values: {
1653
- value: {},
1654
- enumerable: true,
1655
- configurable: true,
1656
- writable: true
1657
- },
1658
- _mount_statuses: {
1659
- value: {},
1660
- enumerable: true,
1661
- configurable: true,
1662
- writable: true
1663
- },
1664
- _mount_errors: {
1665
- value: {},
1666
- enumerable: true,
1667
- configurable: true,
1668
- writable: true
1669
- },
1670
- _mount_logs: {
1671
- value: [],
1672
- enumerable: true,
1673
- configurable: true,
1674
- writable: true
1675
- }
1676
- });
1677
- }
1678
- function defineGeneratedMethod(definition, key, value) {
1679
- Object.defineProperty(definition, key, {
1680
- value,
1681
- enumerable: false,
1682
- configurable: true,
1683
- writable: true
1684
- });
1685
- }
1686
- function initializeMountRuntime(orb, config) {
1687
- MEM.MOUNTS.set(orb, {
1688
- source: config.source,
1689
- sourcePlan: null,
1690
- target: config.target,
1691
- shape: {
1692
- id: config.name,
1693
- name: config.name
1694
- },
1695
- outsource: [...config.outsource],
1696
- projections: [...config.projections],
1697
- commands: [...config.commands],
1698
- anchor: null,
1699
- routes: [],
1700
- contextKey: "",
1701
- unsubscribe: undefined
1702
- });
1703
- const factoryInfo = MEM.MOUNT_FACTORIES.get(MEM.ORB_PLAN.get(orb)?.factory);
1704
- const runtime = MEM.MOUNTS.get(orb);
1705
- if (factoryInfo) {
1706
- runtime.sourcePlan = factoryInfo.sourcePlan;
1707
- }
1708
- }
1709
- function mountApplyBehavior(patch = {}) {
1710
- const normalized = normalizePatch(patch);
1711
- if (normalized.values) {
1712
- this._mount_values = {
1713
- ...readObjectState(this._mount_values),
1714
- ...normalized.values
1715
- };
1716
- }
1717
- if (normalized.statuses) {
1718
- this._mount_statuses = {
1719
- ...readObjectState(this._mount_statuses),
1720
- ...normalized.statuses
1721
- };
1722
- }
1723
- if (normalized.errors) {
1724
- this._mount_errors = {
1725
- ...readObjectState(this._mount_errors),
1726
- ...normalized.errors
1727
- };
1728
- }
1729
- if (normalized.logs) {
1730
- this._mount_logs = [
1731
- ...readArrayState(this._mount_logs),
1732
- ...normalized.logs
1733
- ];
1734
- }
1735
- return this;
1736
- }
1737
- function mountDisposeBehavior() {
1738
- return disposeMountedOrb(this);
1739
- }
1740
- function createMountContext(anchor, orb, runtime) {
1741
- const meta = MEM.ORB_META.get(orb);
1742
- return {
1743
- anchor,
1744
- anchorId: anchor.id,
1745
- orb,
1746
- uuid: meta?.uuid,
1747
- routes: [...meta?.routes ?? []],
1748
- sourceShape: { ...runtime.source },
1749
- mountShape: { ...runtime.shape },
1750
- target: runtime.target,
1751
- outsource: [...runtime.outsource],
1752
- projections: [...runtime.projections],
1753
- commands: [...runtime.commands]
1754
- };
1755
- }
1756
- function normalizePatch(patch) {
1757
- if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
1758
- throw new TypeError("Mount patch must be an object");
1759
- }
1760
- const normalized = {};
1761
- if (patch.values !== undefined) {
1762
- assertPlainObject(patch.values, "Mount patch values");
1763
- normalized.values = patch.values;
1764
- }
1765
- if (patch.statuses !== undefined) {
1766
- assertPlainObject(patch.statuses, "Mount patch statuses");
1767
- for (const [key, value] of Object.entries(patch.statuses)) {
1768
- if (typeof value !== "string") {
1769
- throw new TypeError(`Mount patch status '${key}' must be a string`);
1770
- }
1771
- }
1772
- normalized.statuses = patch.statuses;
1773
- }
1774
- if (patch.errors !== undefined) {
1775
- assertPlainObject(patch.errors, "Mount patch errors");
1776
- normalized.errors = patch.errors;
1777
- }
1778
- if (patch.logs !== undefined) {
1779
- if (!Array.isArray(patch.logs)) {
1780
- throw new TypeError("Mount patch logs must be an array");
1781
- }
1782
- normalized.logs = patch.logs;
1783
- }
1784
- return normalized;
1785
- }
1786
- function normalizeConstructorState(input, label) {
1787
- if (!input || typeof input !== "object" || Array.isArray(input)) {
1788
- throw new TypeError(`${label} must be an object`);
1789
- }
1790
- return input;
1791
- }
1792
- function readObjectState(value) {
1793
- if (value && typeof value === "object" && !Array.isArray(value))
1794
- return value;
1795
- return {};
1796
- }
1797
- function readArrayState(value) {
1798
- if (Array.isArray(value))
1799
- return value;
1800
- return [];
1801
- }
1802
- function assertOrdinarySourceShape(sourcePlan) {
1803
- for (const symbol of VOCAB.SHAPE_SYMBOLS) {
1804
- if (symbol !== VOCAB.SHAPE.NAME && symbol !== VOCAB.SHAPE.MOUNTS && sourcePlan.protocol[protocolKey(symbol)]) {
1805
- throw new Error(`Mount only supports ordinary Shapes (Shape '${sourcePlan.id}')`);
1806
- }
1807
- }
1808
- }
1809
- function protocolKey(symbol) {
1810
- if (symbol === VOCAB.SHAPE.INIT)
1811
- return "init";
1812
- if (symbol === VOCAB.SHAPE.KEYS)
1813
- return "keys";
1814
- if (symbol === VOCAB.SHAPE.EDGE)
1815
- return "edge";
1816
- if (symbol === VOCAB.SHAPE.SAVE)
1817
- return "save";
1818
- if (symbol === VOCAB.SHAPE.LOAD)
1819
- return "load";
1820
- throw new Error("Unknown Shape protocol symbol");
1821
- }
1822
- function assertReservedKeysAvailable(sourcePlan) {
1823
- for (const key of MOUNT_RESERVED_KEYS) {
1824
- if (sourcePlan.byKey.has(key)) {
1825
- throw new Error(`Cannot mount Shape '${sourcePlan.id}' because '${key}' is reserved for Mount`);
1826
- }
1827
- }
1828
- }
1829
- function assertPlainObject(value, label) {
1830
- if (!value || typeof value !== "object" || Array.isArray(value)) {
1831
- throw new TypeError(`${label} must be an object`);
1832
- }
1833
- }
1834
-
1835
- // ../orbz/src/Anchor.js
1836
- class Anchor {
1837
- constructor(options = {}) {
1838
- const normalized = typeof options === "string" ? { id: options } : options;
1839
- this.id = normalized.id ?? `anchor${MEM.LAST_ANCHOR_ID++}`;
1840
- this._connections = new Map;
1841
- this._uuidToOrb = new Map;
1842
- this._routeToUuid = new Map;
1843
- this._observers = new Set;
1844
- this._nextUuid = 1;
1845
- this.adapter = normalized.adapter ?? createMemoryAdapter();
1846
- this.loading = normalized.loading ?? "eager";
1847
- this.mountTargets = normalizeMountTargets(normalized.mountTargets ?? normalized.mountTarget);
1848
- this._resolveAnchor = normalized.resolveAnchor ?? null;
1849
- this._dirty = new Set;
1850
- this._deletedRoutes = new Set;
1851
- this._pendingLazyByUuid = new Map;
1852
- this._disposed = false;
1853
- this._autosaveRunning = false;
1854
- this._autosaveTimer = null;
1855
- if (normalized.autosave) {
1856
- this._startAutosave(normalized.autosave);
1857
- }
1858
- }
1859
- connect(anchor) {
1860
- if (!anchor || typeof anchor.id !== "string") {
1861
- throw new TypeError("connect() expects an Anchor");
1862
- }
1863
- if (hasSharedAnchorId(this, anchor)) {
1864
- throw new Error(`Anchor '${anchor.id}' is already connected`);
1865
- }
1866
- this._connections.set(anchor.id, anchor);
1867
- }
1868
- observe(listener) {
1869
- if (typeof listener !== "function") {
1870
- throw new TypeError("Anchor.observe() expects a listener function");
1871
- }
1872
- this._observers.add(listener);
1873
- let active = true;
1874
- return () => {
1875
- if (!active)
1876
- return;
1877
- active = false;
1878
- this._observers.delete(listener);
1879
- };
1880
- }
1881
- adoptRuntimeOrb(orb) {
1882
- return this._ensureOrb(orb);
1883
- }
1884
- resolveMount(shapeFactory) {
1885
- if (typeof shapeFactory !== "function") {
1886
- throw new TypeError("Anchor.resolveMount() expects a Shape factory");
1887
- }
1888
- for (const target of this.mountTargets) {
1889
- const mounted = createMountedFactory(shapeFactory, target);
1890
- if (mounted)
1891
- return mounted;
1892
- }
1893
- return;
1894
- }
1895
- set(route, orb) {
1896
- assertRoute(route);
1897
- return this._adoptValueAtRoute(route, orb) || orb;
1898
- }
1899
- handleOrbSlotChanged(orb, key) {
1900
- const meta = MEM.ORB_META.get(orb);
1901
- if (meta?.anchor === this) {
1902
- this._dirty.add(meta.uuid);
1903
- const shape = MEM.ORB_PLAN.get(orb)?.id;
1904
- const edge = getEdge(orb, key);
1905
- if (!edge) {
1906
- for (const route of meta.routes) {
1907
- this._deriveOrbRoutes(orb, route);
1908
- }
1909
- return;
1910
- }
1911
- this._emitObserve({
1912
- type: "state:write",
1913
- uuid: meta.uuid,
1914
- shape,
1915
- key,
1916
- value: this._serializeValue(edge.peek()),
1917
- routes: [...meta.routes]
1918
- });
1919
- for (const route of meta.routes) {
1920
- const edgeRoute = joinRoute(route, edge.segment);
1921
- if (!this._adoptValueAtRoute(edgeRoute, edge.peek())) {
1922
- this._deleteRoute(edgeRoute);
1923
- }
1924
- }
1925
- return;
1926
- }
1927
- }
1928
- handleOrbProtocolChanged(orb) {
1929
- const meta = MEM.ORB_META.get(orb);
1930
- if (!meta || meta.anchor !== this)
1931
- return;
1932
- this._dirty.add(meta.uuid);
1933
- this._emitObserve({
1934
- type: "protocol:change",
1935
- uuid: meta.uuid,
1936
- shape: MEM.ORB_PLAN.get(orb)?.id,
1937
- routes: [...meta.routes]
1938
- });
1939
- for (const route of meta.routes) {
1940
- this._deriveOrbRoutes(orb, route);
1941
- }
1942
- }
1943
- at(route) {
1944
- const { anchor, local } = this._resolveRouteOwner(route);
1945
- trackDependency(anchor, routeDependency(local));
1946
- return anchor.get(local);
1947
- }
1948
- get(routeOrUuid) {
1949
- if (typeof routeOrUuid !== "string") {
1950
- throw new TypeError("Anchor.get() expects a route or UUID ref");
1951
- }
1952
- if (routeOrUuid.startsWith("$uuid:")) {
1953
- return this._uuidToOrb.get(parseUuidRef(routeOrUuid).uuid);
1954
- }
1955
- const { anchor, local } = this._resolveRouteOwner(routeOrUuid);
1956
- const uuid = anchor._routeToUuid.get(local);
1957
- return uuid ? anchor._uuidToOrb.get(uuid) : undefined;
1958
- }
1959
- async load(routeOrUuid) {
1960
- if (routeOrUuid.startsWith("$uuid:")) {
1961
- return this._loadUuid(parseUuidRef(routeOrUuid).uuid);
1962
- }
1963
- const { anchor, local } = await this._resolveRouteOwnerAsync(routeOrUuid);
1964
- if (anchor !== this) {
1965
- return anchor.load(local);
1966
- }
1967
- let uuid = this._routeToUuid.get(local);
1968
- if (!uuid) {
1969
- uuid = await this.adapter.routes?.get?.(local);
1970
- }
1971
- if (!uuid)
1972
- return;
1973
- assertUuid(uuid, `Malformed route '${local}'`);
1974
- const orb = await this._loadUuid(uuid);
1975
- this._setRoute(local, uuid);
1976
- this._deriveOrbRoutes(orb, local);
1977
- return orb;
1978
- }
1979
- async save(routeOrUuid) {
1980
- if (routeOrUuid) {
1981
- if (!routeOrUuid.startsWith("$uuid:")) {
1982
- const { anchor, local } = this._resolveRouteOwner(routeOrUuid);
1983
- if (anchor !== this) {
1984
- return anchor.save(local);
1985
- }
1986
- const uuid = this._routeToUuid.get(local);
1987
- if (uuid) {
1988
- this._deletedRoutes.delete(local);
1989
- await this.adapter.routes?.set?.(local, uuid);
1990
- }
1991
- }
1992
- const orb = this.get(routeOrUuid);
1993
- if (!orb)
1994
- return;
1995
- await this._saveOrb(orb);
1996
- return;
1997
- }
1998
- await this.saveAllDirty();
1999
- }
2000
- async saveAllDirty() {
2001
- for (const [route, uuid] of this._routeToUuid) {
2002
- this._deletedRoutes.delete(route);
2003
- await this.adapter.routes?.set?.(route, uuid);
2004
- }
2005
- for (const route of this._deletedRoutes) {
2006
- await this.adapter.routes?.delete?.(route);
2007
- }
2008
- this._deletedRoutes.clear();
2009
- const reachable = this._collectLiveReachableUuids();
2010
- const dirty = [...this._dirty].filter((uuid) => reachable.has(uuid));
2011
- this._dirty.clear();
2012
- for (const uuid of dirty) {
2013
- const orb = this._uuidToOrb.get(uuid);
2014
- if (orb) {
2015
- await this._saveOrb(orb);
2016
- }
2017
- }
2018
- }
2019
- async collectGarbage() {
2020
- const listRoutes = this.adapter.routes?.list;
2021
- const deleteRoute = this.adapter.routes?.delete;
2022
- const listOrbs = this.adapter.state?.listOrbs;
2023
- const deleteOrb = this.adapter.state?.deleteOrb;
2024
- if (typeof listRoutes !== "function") {
2025
- throw new Error("Anchor GC requires adapter.routes.list()");
2026
- }
2027
- if (typeof deleteRoute !== "function") {
2028
- throw new Error("Anchor GC requires adapter.routes.delete()");
2029
- }
2030
- if (typeof listOrbs !== "function") {
2031
- throw new Error("Anchor GC requires adapter.state.listOrbs()");
2032
- }
2033
- if (typeof deleteOrb !== "function") {
2034
- throw new Error("Anchor GC requires adapter.state.deleteOrb()");
2035
- }
2036
- await this.saveAllDirty();
2037
- const routeRecords = await listRoutes.call(this.adapter.routes);
2038
- const orbRecords = await listOrbs.call(this.adapter.state);
2039
- const recordsByUuid = new Map;
2040
- const routeToUuid = new Map;
2041
- for (const record of orbRecords ?? []) {
2042
- if (record?.uuid) {
2043
- recordsByUuid.set(record.uuid, record);
2044
- }
2045
- }
2046
- for (const record of routeRecords ?? []) {
2047
- if (!record)
2048
- continue;
2049
- const route = record.route;
2050
- const uuid = record.uuid;
2051
- assertRoute(route);
2052
- assertUuid(uuid, `Malformed route '${route}'`);
2053
- routeToUuid.set(route, uuid);
2054
- }
2055
- const retained = new Set;
2056
- const pending = [...routeToUuid.values()];
2057
- while (pending.length > 0) {
2058
- const uuid = pending.pop();
2059
- if (retained.has(uuid))
2060
- continue;
2061
- retained.add(uuid);
2062
- const record = recordsByUuid.get(uuid);
2063
- if (!record)
2064
- continue;
2065
- assertOrbRecord(record, uuid);
2066
- for (const ref of collectSerializedRefs(record.state)) {
2067
- const targetUuid = resolveLocalSerializedRef(ref, routeToUuid, this.id);
2068
- if (targetUuid && !retained.has(targetUuid)) {
2069
- pending.push(targetUuid);
2070
- }
2071
- }
2072
- }
2073
- const deleted = [];
2074
- for (const uuid of recordsByUuid.keys()) {
2075
- if (retained.has(uuid))
2076
- continue;
2077
- await deleteOrb.call(this.adapter.state, uuid);
2078
- this._dirty.delete(uuid);
2079
- deleted.push(uuid);
2080
- }
2081
- return { retained: retained.size, deleted };
2082
- }
2083
- dispose() {
2084
- if (this._disposed)
2085
- return;
2086
- this._disposed = true;
2087
- if (this._autosaveTimer) {
2088
- clearInterval(this._autosaveTimer);
2089
- this._autosaveTimer = null;
2090
- }
2091
- for (const orb of this._uuidToOrb.values()) {
2092
- disposeMountedOrb(orb);
2093
- }
2094
- }
2095
- fullRef(ref) {
2096
- if (ref.startsWith("$uuid:") || ref.includes(":"))
2097
- return ref;
2098
- return `${this.id}:${ref}`;
2099
- }
2100
- _ensureOrb(orb) {
2101
- if (!MEM.ORB_PLAN.get(orb)) {
2102
- throw new TypeError("Anchor can only adopt Orb nodes");
2103
- }
2104
- const existing = MEM.ORB_META.get(orb);
2105
- if (existing?.anchor === this) {
2106
- return existing.uuid;
2107
- }
2108
- const uuid = this._createUuid();
2109
- MEM.ORB_META.set(orb, {
2110
- anchor: this,
2111
- uuid,
2112
- routes: existing?.routes ?? new Set
2113
- });
2114
- this._uuidToOrb.set(uuid, orb);
2115
- this._dirty.add(uuid);
2116
- bindMountedOrb(this, orb);
2117
- return uuid;
2118
- }
2119
- _adoptValueAtRoute(route, value) {
2120
- if (value instanceof LazyRef) {
2121
- const ref = parseLazyUuidRef(value);
2122
- if (ref && !ref.path) {
2123
- this._setRoute(route, ref.uuid, { dirty: false });
2124
- return true;
2125
- }
2126
- return false;
2127
- }
2128
- if (MEM.ORB_PLAN.get(value)) {
2129
- const adopted = this._mountValueForAnchor(value);
2130
- const uuid = this._ensureOrb(adopted);
2131
- this._setRoute(route, uuid);
2132
- this._deriveOrbRoutes(adopted, route);
2133
- return adopted;
2134
- }
2135
- return false;
2136
- }
2137
- _deriveOrbRoutes(orb, route) {
2138
- if (!MEM.ORB_PLAN.get(orb))
2139
- return;
2140
- const seenRoutes = new Set;
2141
- for (const edge of getEdges(orb)) {
2142
- const edgeRoute = joinRoute(route, edge.segment);
2143
- if (this._adoptValueAtRoute(edgeRoute, edge.peek())) {
2144
- seenRoutes.add(edgeRoute);
2145
- }
2146
- }
2147
- for (const existingRoute of [...this._routeToUuid.keys()]) {
2148
- if (isDirectEdgeRoute(route, existingRoute) && !seenRoutes.has(existingRoute)) {
2149
- this._deleteRoute(existingRoute);
2150
- }
2151
- }
2152
- }
2153
- _createUuid() {
2154
- const adapterUuid = this.adapter.state?.createUuid?.();
2155
- if (adapterUuid) {
2156
- return adapterUuid;
2157
- }
2158
- return `${this.id.replace(/[^a-zA-Z0-9_-]/g, "_")}_${this._nextUuid++}`;
2159
- }
2160
- _setRoute(route, uuid, options = {}) {
2161
- const previousUuid = this._routeToUuid.get(route);
2162
- const dirty = options.dirty ?? true;
2163
- this._deletedRoutes.delete(route);
2164
- this._routeToUuid.set(route, uuid);
2165
- const orb = this._uuidToOrb.get(uuid);
2166
- if (orb) {
2167
- const meta = MEM.ORB_META.get(orb);
2168
- meta.routes.add(route);
2169
- bindMountedOrb(this, orb);
2170
- }
2171
- if (dirty) {
2172
- this._dirty.add(uuid);
2173
- }
2174
- notifyDependencyChanged(this, routeDependency(route));
2175
- const event = {
2176
- type: "route:set",
2177
- route,
2178
- uuid
2179
- };
2180
- if (previousUuid && previousUuid !== uuid) {
2181
- event.previousUuid = previousUuid;
2182
- }
2183
- if (orb) {
2184
- event.shape = MEM.ORB_PLAN.get(orb)?.id;
2185
- }
2186
- this._emitObserve(event);
2187
- }
2188
- _deleteRoute(route) {
2189
- const uuid = this._routeToUuid.get(route);
2190
- if (!uuid)
2191
- return;
2192
- this._routeToUuid.delete(route);
2193
- this._deletedRoutes.add(route);
2194
- const orb = this._uuidToOrb.get(uuid);
2195
- const meta = orb ? MEM.ORB_META.get(orb) : null;
2196
- meta?.routes?.delete(route);
2197
- if (orb)
2198
- bindMountedOrb(this, orb);
2199
- notifyDependencyChanged(this, routeDependency(route));
2200
- this._emitObserve({
2201
- type: "route:delete",
2202
- route,
2203
- uuid
2204
- });
2205
- }
2206
- _emitObserve(event) {
2207
- if (this._observers.size === 0)
2208
- return;
2209
- const frozen = Object.freeze({
2210
- anchorId: this.id,
2211
- ...event
2212
- });
2213
- for (const observer of [...this._observers]) {
2214
- observer(frozen);
2215
- }
2216
- }
2217
- async _saveOrb(orb) {
2218
- const meta = MEM.ORB_META.get(orb);
2219
- const plan = MEM.ORB_PLAN.get(orb);
2220
- if (!meta || !plan)
2221
- return;
2222
- const sourcePlan = getMountSourcePlan(orb);
2223
- const record = {
2224
- uuid: meta.uuid,
2225
- shape: sourcePlan?.id ?? plan.id,
2226
- state: sourcePlan ? this._serializeOrbStateForPlan(orb, sourcePlan) : this._serializeOrbState(orb)
2227
- };
2228
- await this.adapter.state?.saveOrb?.(record);
2229
- }
2230
- _serializeOrbState(orb) {
2231
- const saved = orb[VOCAB.SHAPE.SAVE]();
2232
- if (Array.isArray(saved)) {
2233
- const out2 = [];
2234
- for (const edge of getEdges(orb)) {
2235
- out2[Number(edge.key)] = this._serializeValue(edge.peek());
2236
- }
2237
- return out2;
2238
- }
2239
- if (!saved || typeof saved !== "object") {
2240
- return saved;
2241
- }
2242
- const out = JSON.parse(JSON.stringify(saved));
2243
- for (const edge of getEdges(orb)) {
2244
- out[edge.key] = this._serializeValue(edge.peek());
2245
- }
2246
- return out;
2247
- }
2248
- _serializeValue(value) {
2249
- if (value instanceof OrbLink) {
2250
- const { source, key } = value.target();
2251
- return { $: `$uuid:${this._ensureOrb(source)}/${key}` };
2252
- }
2253
- if (value instanceof LazyRef) {
2254
- return { $: value.ref };
2255
- }
2256
- if (MEM.ORB_PLAN.get(value)) {
2257
- return { $: `$uuid:${this._ensureOrb(value)}` };
2258
- }
2259
- if (value === undefined)
2260
- return;
2261
- return JSON.parse(JSON.stringify(value));
2262
- }
2263
- _serializeOrbStateForPlan(orb, plan) {
2264
- const out = {};
2265
- for (const entry of plan.serializable) {
2266
- const edge = orb[VOCAB.SHAPE.EDGE](entry.key);
2267
- out[entry.key] = this._serializeValue(edge.peek());
2268
- }
2269
- return out;
2270
- }
2271
- _collectLiveReachableUuids() {
2272
- const reachable = new Set;
2273
- for (const uuid of this._routeToUuid.values()) {
2274
- this._collectLiveReachableUuid(uuid, reachable);
2275
- }
2276
- return reachable;
2277
- }
2278
- _collectLiveReachableUuid(uuid, reachable) {
2279
- if (!uuid || reachable.has(uuid))
2280
- return;
2281
- reachable.add(uuid);
2282
- const orb = this._uuidToOrb.get(uuid);
2283
- if (!orb)
2284
- return;
2285
- for (const edge of getEdges(orb)) {
2286
- this._collectLiveReachableValue(edge.peek(), reachable);
2287
- }
2288
- }
2289
- _collectLiveReachableValue(value, reachable) {
2290
- if (value instanceof OrbLink) {
2291
- const { source } = value.target();
2292
- this._collectLiveReachableUuid(this._ensureOrb(source), reachable);
2293
- return;
2294
- }
2295
- if (value instanceof LazyRef) {
2296
- const ref = parseLazyUuidRef(value);
2297
- if (ref) {
2298
- this._collectLiveReachableUuid(ref.uuid, reachable);
2299
- }
2300
- return;
2301
- }
2302
- if (MEM.ORB_PLAN.get(value)) {
2303
- this._collectLiveReachableUuid(this._ensureOrb(value), reachable);
2304
- }
2305
- }
2306
- async _loadUuid(uuid) {
2307
- assertUuid(uuid, "Malformed UUID");
2308
- if (this._uuidToOrb.has(uuid)) {
2309
- return this._uuidToOrb.get(uuid);
2310
- }
2311
- const record = await this.adapter.state?.loadOrb?.(uuid);
2312
- if (!record)
2313
- return;
2314
- assertOrbRecord(record, uuid);
2315
- let shape = await this.adapter.shapes?.load?.(record.shape);
2316
- if (!shape) {
2317
- throw new Error(`Missing Shape '${record.shape}'`);
2318
- }
2319
- shape = this.resolveMount(shape) ?? shape;
2320
- const input = await this._reviveValue(record.state);
2321
- const orb = shape.hydrate(input);
2322
- MEM.ORB_META.set(orb, {
2323
- anchor: this,
2324
- uuid,
2325
- routes: new Set
2326
- });
2327
- this._uuidToOrb.set(uuid, orb);
2328
- this._registerLazyInputTargets(orb, input);
2329
- this._registerLazyEdges(orb);
2330
- this._resolvePendingLazy(uuid, orb);
2331
- this._deriveOrbRoutesFromKnownRoutes(orb);
2332
- return orb;
2333
- }
2334
- _mountValueForAnchor(value) {
2335
- if (isMountedOrb(value))
2336
- return value;
2337
- const plan = MEM.ORB_PLAN.get(value);
2338
- const factory = plan?.factory;
2339
- if (!factory)
2340
- return value;
2341
- const mountedFactory = this.resolveMount(factory);
2342
- if (!mountedFactory)
2343
- return value;
2344
- return mountedFactory.hydrate(this._serializeOrbStateForPlan(value, plan));
2345
- }
2346
- async _reviveValue(value) {
2347
- if (isSerializedRef(value)) {
2348
- const ref = value.$;
2349
- if (ref.startsWith("$uuid:")) {
2350
- const { uuid, path } = parseUuidRef(ref);
2351
- if (this.loading === "lazy" && !path) {
2352
- return new LazyRef(ref);
2353
- }
2354
- const target = await this._loadUuid(uuid);
2355
- return path ? target.$(path) : target;
2356
- }
2357
- return this.load(ref);
2358
- }
2359
- if (Array.isArray(value)) {
2360
- const out = [];
2361
- for (const item of value) {
2362
- out.push(await this._reviveValue(item));
2363
- }
2364
- return out;
2365
- }
2366
- if (value && typeof value === "object") {
2367
- const out = {};
2368
- for (const [key, nested] of Object.entries(value)) {
2369
- out[key] = await this._reviveValue(nested);
2370
- }
2371
- return out;
2372
- }
2373
- return value;
2374
- }
2375
- _deriveOrbRoutesFromKnownRoutes(orb) {
2376
- const meta = MEM.ORB_META.get(orb);
2377
- if (!meta)
2378
- return;
2379
- for (const [route, uuid] of this._routeToUuid) {
2380
- if (uuid === meta.uuid) {
2381
- meta.routes.add(route);
2382
- this._deriveOrbRoutes(orb, route);
2383
- }
2384
- }
2385
- }
2386
- _registerLazyEdges(orb) {
2387
- for (const edge of getEdges(orb)) {
2388
- this._registerLazyTarget(orb, edge.key, edge.peek());
2389
- }
2390
- }
2391
- _registerLazyInputTargets(orb, input) {
2392
- if (!input || typeof input !== "object")
2393
- return;
2394
- if (Array.isArray(input)) {
2395
- input.forEach((value, index) => {
2396
- this._registerLazyTarget(orb, String(index), value);
2397
- });
2398
- return;
2399
- }
2400
- for (const [key, value] of Object.entries(input)) {
2401
- this._registerLazyTarget(orb, key, value);
2402
- }
2403
- }
2404
- _registerLazyTarget(target, key, value) {
2405
- const ref = parseLazyUuidRef(value);
2406
- if (!ref || ref.path)
2407
- return;
2408
- let pending = this._pendingLazyByUuid.get(ref.uuid);
2409
- if (!pending) {
2410
- pending = new Set;
2411
- this._pendingLazyByUuid.set(ref.uuid, pending);
2412
- }
2413
- for (const entry of pending) {
2414
- if (entry.target === target && entry.key === key) {
2415
- return;
2416
- }
2417
- }
2418
- pending.add({ target, key });
2419
- }
2420
- _resolvePendingLazy(uuid, value) {
2421
- const pending = this._pendingLazyByUuid.get(uuid);
2422
- if (!pending)
2423
- return;
2424
- this._pendingLazyByUuid.delete(uuid);
2425
- for (const { target, key } of pending) {
2426
- resolveLazyRef(target, key, value);
2427
- }
2428
- }
2429
- _resolveRouteOwner(ref) {
2430
- const parsed = parseRouteRef(ref);
2431
- if (!parsed.anchorId || parsed.anchorId === this.id) {
2432
- return { anchor: this, local: parsed.route };
2433
- }
2434
- const connected = this._findConnectedAnchor(parsed.anchorId);
2435
- if (!connected) {
2436
- const resolved = this._resolveConfiguredAnchor(parsed.anchorId);
2437
- if (isPromiseLike(resolved)) {
2438
- throw new Error(`Async Anchor resolver for '${parsed.anchorId}' requires load()`);
2439
- }
2440
- if (resolved) {
2441
- return { anchor: resolved, local: parsed.route };
2442
- }
2443
- throw new Error(`Unresolved Anchor '${parsed.anchorId}'`);
2444
- }
2445
- return { anchor: connected, local: parsed.route };
2446
- }
2447
- async _resolveRouteOwnerAsync(ref) {
2448
- const parsed = parseRouteRef(ref);
2449
- if (!parsed.anchorId || parsed.anchorId === this.id) {
2450
- return { anchor: this, local: parsed.route };
2451
- }
2452
- const connected = this._findConnectedAnchor(parsed.anchorId);
2453
- if (connected) {
2454
- return { anchor: connected, local: parsed.route };
2455
- }
2456
- const resolved = await this._resolveConfiguredAnchor(parsed.anchorId);
2457
- if (!resolved) {
2458
- throw new Error(`Unresolved Anchor '${parsed.anchorId}'`);
2459
- }
2460
- assertResolvedAnchor(parsed.anchorId, resolved);
2461
- return { anchor: resolved, local: parsed.route };
2462
- }
2463
- _resolveConfiguredAnchor(anchorId) {
2464
- if (!this._resolveAnchor)
2465
- return null;
2466
- const anchor = this._resolveAnchor(anchorId);
2467
- if (!anchor || isPromiseLike(anchor))
2468
- return anchor;
2469
- assertResolvedAnchor(anchorId, anchor);
2470
- return anchor;
2471
- }
2472
- _findConnectedAnchor(anchorId, seen = new Set) {
2473
- if (this.id === anchorId)
2474
- return this;
2475
- if (seen.has(this))
2476
- return null;
2477
- seen.add(this);
2478
- for (const anchor of this._connections.values()) {
2479
- const found = anchor._findConnectedAnchor(anchorId, seen);
2480
- if (found)
2481
- return found;
2482
- }
2483
- return null;
2484
- }
2485
- _collectAnchorIds(seen = new Set, ids = new Set) {
2486
- if (seen.has(this))
2487
- return ids;
2488
- seen.add(this);
2489
- ids.add(this.id);
2490
- for (const anchor of this._connections.values()) {
2491
- anchor._collectAnchorIds(seen, ids);
2492
- }
2493
- return ids;
2494
- }
2495
- _startAutosave(options) {
2496
- const intervalMs = options?.intervalMs;
2497
- if (!Number.isFinite(intervalMs) || intervalMs <= 0) {
2498
- throw new Error("Anchor autosave intervalMs must be a positive number");
2499
- }
2500
- this._autosaveTimer = setInterval(() => {
2501
- this._runAutosave();
2502
- }, intervalMs);
2503
- this._autosaveTimer.unref?.();
2504
- }
2505
- async _runAutosave() {
2506
- if (this._disposed || this._autosaveRunning)
2507
- return;
2508
- this._autosaveRunning = true;
2509
- try {
2510
- await this.saveAllDirty();
2511
- } finally {
2512
- this._autosaveRunning = false;
2513
- }
2514
- }
2515
- }
2516
- MEM.BASE_ANCHOR = new Anchor({ id: "default" });
2517
- var baseAnchor = MEM.BASE_ANCHOR;
2518
- function parseUuidRef(ref) {
2519
- const body = ref.slice("$uuid:".length);
2520
- if (!body) {
2521
- throw new Error(`Malformed ref '${ref}'`);
2522
- }
2523
- const slash = body.indexOf("/");
2524
- if (slash === -1) {
2525
- return { uuid: body, path: "" };
2526
- }
2527
- const uuid = body.slice(0, slash);
2528
- const path = body.slice(slash + 1);
2529
- if (!uuid || !path) {
2530
- throw new Error(`Malformed ref '${ref}'`);
2531
- }
2532
- return {
2533
- uuid,
2534
- path
2535
- };
2536
- }
2537
- function parseLazyUuidRef(value) {
2538
- if (!(value instanceof LazyRef))
2539
- return null;
2540
- if (!value.ref.startsWith("$uuid:"))
2541
- return null;
2542
- return parseUuidRef(value.ref);
2543
- }
2544
- function parseRouteRef(ref) {
2545
- if (typeof ref !== "string") {
2546
- throw new TypeError("Anchor route ref must be a string");
2547
- }
2548
- const colon = ref.indexOf(":");
2549
- if (colon === -1) {
2550
- assertRoute(ref);
2551
- return { anchorId: undefined, route: ref };
2552
- }
2553
- const anchorId = ref.slice(0, colon);
2554
- const route = ref.slice(colon + 1);
2555
- if (!anchorId) {
2556
- throw new Error(`Malformed route ref '${ref}'`);
2557
- }
2558
- assertRoute(route);
2559
- return { anchorId, route };
2560
- }
2561
- function routeDependency(route) {
2562
- return `route:${route}`;
2563
- }
2564
- function joinRoute(parent, segment) {
2565
- assertRouteSegment(segment);
2566
- return `${parent}/${segment}`;
2567
- }
2568
- function getEdges(value) {
2569
- return value[VOCAB.SHAPE.KEYS]().map((key) => value[VOCAB.SHAPE.EDGE](key));
2570
- }
2571
- function getEdge(value, key) {
2572
- try {
2573
- return value[VOCAB.SHAPE.EDGE](key);
2574
- } catch {
2575
- return;
2576
- }
2577
- }
2578
- function isDirectEdgeRoute(parent, route) {
2579
- if (!route.startsWith(`${parent}/`))
2580
- return false;
2581
- return !route.slice(parent.length + 1).includes("/");
2582
- }
2583
- function assertRoute(route) {
2584
- if (typeof route !== "string" || route.length === 0 || route.startsWith("$uuid:")) {
2585
- throw new Error("Anchor route must be a non-empty route string");
2586
- }
2587
- for (const segment of route.split("/")) {
2588
- assertRouteSegment(segment);
2589
- }
2590
- }
2591
- function assertUuid(uuid, message) {
2592
- if (typeof uuid !== "string" || uuid.length === 0) {
2593
- throw new Error(message);
2594
- }
2595
- }
2596
- function assertOrbRecord(record, expectedUuid) {
2597
- const valid = record && typeof record === "object" && !Array.isArray(record) && typeof record.uuid === "string" && record.uuid === expectedUuid && typeof record.shape === "string" && record.shape.length > 0 && Object.prototype.hasOwnProperty.call(record, "state");
2598
- if (!valid) {
2599
- throw new Error(`Malformed Orb record '${expectedUuid}'`);
2600
- }
2601
- }
2602
- function assertAnchor(anchor) {
2603
- if (!anchor || typeof anchor.id !== "string" || typeof anchor.get !== "function") {
2604
- throw new TypeError("Expected an Anchor");
2605
- }
2606
- }
2607
- function assertResolvedAnchor(anchorId, anchor) {
2608
- assertAnchor(anchor);
2609
- if (anchor.id !== anchorId) {
2610
- throw new Error(`Anchor resolver returned '${anchor.id}' for '${anchorId}'`);
2611
- }
2612
- }
2613
- function hasSharedAnchorId(left, right) {
2614
- const leftIds = left._collectAnchorIds();
2615
- const rightIds = right._collectAnchorIds();
2616
- for (const id of rightIds) {
2617
- if (leftIds.has(id))
2618
- return true;
2619
- }
2620
- return false;
2621
- }
2622
- function isPromiseLike(value) {
2623
- return Boolean(value && typeof value.then === "function");
2624
- }
2625
- function normalizeMountTargets(value) {
2626
- if (value === undefined)
2627
- return [];
2628
- const list = Array.isArray(value) ? value : [value];
2629
- const seen = new Set;
2630
- const out = [];
2631
- for (const target of list) {
2632
- if (typeof target !== "string" || target.length === 0) {
2633
- throw new TypeError("Anchor mount targets must be non-empty strings");
2634
- }
2635
- assertRouteSegment(target);
2636
- if (seen.has(target))
2637
- continue;
2638
- seen.add(target);
2639
- out.push(target);
2640
- }
2641
- return out;
2642
- }
2643
- function isSerializedRef(value) {
2644
- return Boolean(value && typeof value === "object" && !Array.isArray(value) && typeof value.$ === "string" && Object.keys(value).length === 1);
2645
- }
2646
- function collectSerializedRefs(value, refs = []) {
2647
- if (isSerializedRef(value)) {
2648
- refs.push(value.$);
2649
- return refs;
2650
- }
2651
- if (Array.isArray(value)) {
2652
- for (const item of value) {
2653
- collectSerializedRefs(item, refs);
2654
- }
2655
- return refs;
2656
- }
2657
- if (value && typeof value === "object") {
2658
- for (const nested of Object.values(value)) {
2659
- collectSerializedRefs(nested, refs);
2660
- }
2661
- }
2662
- return refs;
2663
- }
2664
- function resolveLocalSerializedRef(ref, routeToUuid, anchorId) {
2665
- if (ref.startsWith("$uuid:")) {
2666
- return parseUuidRef(ref).uuid;
2667
- }
2668
- const parsed = parseRouteRef(ref);
2669
- if (parsed.anchorId && parsed.anchorId !== anchorId) {
2670
- return;
2671
- }
2672
- return routeToUuid.get(parsed.route);
2673
- }
2674
- function createMemoryAdapter() {
2675
- const records = new Map;
2676
- const routes = new Map;
2677
- let nextUuid = 1;
2678
- return {
2679
- state: {
2680
- createUuid() {
2681
- return `u${nextUuid++}`;
2682
- },
2683
- async loadOrb(uuid) {
2684
- return records.get(uuid) ?? null;
2685
- },
2686
- async saveOrb(record) {
2687
- records.set(record.uuid, JSON.parse(JSON.stringify(record)));
2688
- },
2689
- async deleteOrb(uuid) {
2690
- records.delete(uuid);
2691
- },
2692
- async listOrbs() {
2693
- return [...records.values()].map((record) => JSON.parse(JSON.stringify(record)));
2694
- }
2695
- },
2696
- routes: {
2697
- async get(route) {
2698
- return routes.get(route) ?? null;
2699
- },
2700
- async set(route, uuid) {
2701
- routes.set(route, uuid);
2702
- },
2703
- async delete(route) {
2704
- routes.delete(route);
2705
- },
2706
- async list() {
2707
- return [...routes].map(([route, uuid]) => ({ route, uuid }));
2708
- }
2709
- },
2710
- shapes: {
2711
- async load() {
2712
- return null;
2713
- },
2714
- async register() {}
2715
- }
2716
- };
2717
- }
2718
- // ../orbz/src/libShapes/Dict.js
2719
- var DICT_KEYS = "dict:keys";
2720
- var dictValueToken = (key) => `dict:value:${key}`;
2721
- var dictPresenceToken = (key) => `dict:presence:${key}`;
2722
- var Dict = Shape({
2723
- [Shape.name]: "Dict",
2724
- _values: {},
2725
- get get() {
2726
- return (key) => this[Shape.edge](key).peek();
2727
- },
2728
- get at() {
2729
- return (key) => this[Shape.edge](key).read();
2730
- },
2731
- set(key, value) {
2732
- return this[Shape.edge](key).write(value);
2733
- },
2734
- delete(key) {
2735
- return this[Shape.edge](key).delete();
2736
- },
2737
- get has() {
2738
- return (key) => {
2739
- const normalized = normalizeKey(key);
2740
- this.$.track(dictPresenceToken(normalized));
2741
- return Object.prototype.hasOwnProperty.call(this._values, normalized);
2742
- };
2743
- },
2744
- get keys() {
2745
- return () => this[Shape.keys]();
2746
- },
2747
- get all() {
2748
- return () => {
2749
- const out = {};
2750
- for (const key of this[Shape.keys]())
2751
- out[key] = this[Shape.edge](key).read();
2752
- return out;
2753
- };
2754
- },
2755
- get each() {
2756
- return (callback) => {
2757
- if (typeof callback !== "function") {
2758
- throw new TypeError("Dict.each() expects a callback");
2759
- }
2760
- for (const key of this[Shape.keys]())
2761
- callback(this[Shape.edge](key).read(), key, this);
2762
- };
2763
- },
2764
- eachEffect(callback, options = {}) {
2765
- return createEachEffect({
2766
- node: this,
2767
- callback,
2768
- options,
2769
- keys: () => this[Shape.keys](),
2770
- peek: (key) => this[Shape.edge](key).peek(),
2771
- read: (key) => this[Shape.edge](key).read()
2772
- });
2773
- },
2774
- [Shape.init](initial = {}) {
2775
- if (!initial || typeof initial !== "object" || Array.isArray(initial)) {
2776
- throw new TypeError("Dict() expects an object");
2777
- }
2778
- const values = {};
2779
- for (const [key, value] of Object.entries(initial))
2780
- values[normalizeKey(key)] = value;
2781
- return { _values: values };
2782
- },
2783
- [Shape.load](initial = {}) {
2784
- return this[Shape.init](initial);
2785
- },
2786
- [Shape.save]() {
2787
- const out = {};
2788
- for (const key of Object.keys(this._values))
2789
- out[key] = serializeSlot(this._values[key]);
2790
- return out;
2791
- },
2792
- [Shape.keys]() {
2793
- this.$.track(DICT_KEYS);
2794
- return Object.keys(this._values);
2795
- },
2796
- [Shape.edge](key) {
2797
- const normalized = normalizeKey(key);
2798
- const node = this;
2799
- const values = this._values;
2800
- return {
2801
- key: normalized,
2802
- segment: normalized,
2803
- read() {
2804
- node.$.track(dictValueToken(normalized));
2805
- return readSlot(values[normalized]);
2806
- },
2807
- peek() {
2808
- return values[normalized];
2809
- },
2810
- write(value) {
2811
- setDictValue(node, values, normalized, value);
2812
- return value;
2813
- },
2814
- delete() {
2815
- return deleteDictValue(node, values, normalized);
2816
- },
2817
- save() {
2818
- return serializeSlot(values[normalized]);
2819
- }
2820
- };
2821
- }
2822
- });
2823
- function setDictValue(node, values, key, value) {
2824
- const hadKey = Object.prototype.hasOwnProperty.call(values, key);
2825
- const previous = values[key];
2826
- if (Object.is(previous, value) && hadKey)
2827
- return;
2828
- batch(() => {
2829
- values[key] = value;
2830
- node.$.changed(dictValueToken(key));
2831
- if (!hadKey) {
2832
- node.$.changed(DICT_KEYS);
2833
- node.$.changed(dictPresenceToken(key));
2834
- }
2835
- });
2836
- }
2837
- function deleteDictValue(node, values, key) {
2838
- if (!Object.prototype.hasOwnProperty.call(values, key))
2839
- return false;
2840
- batch(() => {
2841
- delete values[key];
2842
- node.$.changed(DICT_KEYS);
2843
- node.$.changed(dictPresenceToken(key));
2844
- node.$.changed(dictValueToken(key));
2845
- });
2846
- return true;
2847
- }
2848
- function normalizeKey(key) {
2849
- if (typeof key !== "string") {
2850
- throw new TypeError("Dict keys must be strings");
2851
- }
2852
- assertRouteSegment(key);
2853
- return key;
2854
- }
2855
- // ../orbz/src/libShapes/List.js
2856
- var LIST_ITEMS = "list:items";
2857
- var LIST_LENGTH = "list:length";
2858
- var listItemToken = (index) => `list:item:${index}`;
2859
- var List = Shape({
2860
- [Shape.name]: "List",
2861
- _values: [],
2862
- get length() {
2863
- this.$.track(LIST_LENGTH);
2864
- return this._values.length;
2865
- },
2866
- get keys() {
2867
- return () => this[Shape.keys]();
2868
- },
2869
- get get() {
2870
- return (index) => this[Shape.edge](index).peek();
2871
- },
2872
- get at() {
2873
- return (index) => this[Shape.edge](index).read();
2874
- },
2875
- set(index, value) {
2876
- return this[Shape.edge](index).write(value);
2877
- },
2878
- push(value) {
2879
- return pushListValue(this, this._values, value);
2880
- },
2881
- removeAt(index) {
2882
- return this[Shape.edge](index).delete();
2883
- },
2884
- get toArray() {
2885
- return () => {
2886
- this.$.track(LIST_ITEMS);
2887
- return [...this._values];
2888
- };
2889
- },
2890
- get all() {
2891
- return () => this.toArray();
2892
- },
2893
- get each() {
2894
- return (callback) => {
2895
- if (typeof callback !== "function") {
2896
- throw new TypeError("List.each() expects a callback");
2897
- }
2898
- for (const index of this[Shape.keys]())
2899
- callback(this[Shape.edge](index).read(), index, this);
2900
- };
2901
- },
2902
- eachEffect(callback, options = {}) {
2903
- return createEachEffect({
2904
- node: this,
2905
- callback,
2906
- options,
2907
- keys: () => this[Shape.keys](),
2908
- peek: (index) => this[Shape.edge](index).peek(),
2909
- read: (index) => this[Shape.edge](index).read()
2910
- });
2911
- },
2912
- get map() {
2913
- return (callback) => new DerivedListView(this, callback);
2914
- },
2915
- [Shape.init](initial = []) {
2916
- if (!Array.isArray(initial)) {
2917
- throw new TypeError("List() expects an array");
2918
- }
2919
- return { _values: [...initial] };
2920
- },
2921
- [Shape.load](initial = []) {
2922
- return this[Shape.init](initial);
2923
- },
2924
- [Shape.save]() {
2925
- return this._values.map(serializeSlot);
2926
- },
2927
- [Shape.keys]() {
2928
- this.$.track(LIST_LENGTH);
2929
- return this._values.map((_, index) => index);
2930
- },
2931
- [Shape.edge](index) {
2932
- const normalized = normalizeIndex(index);
2933
- const node = this;
2934
- const values = this._values;
2935
- return {
2936
- key: normalized,
2937
- segment: String(normalized),
2938
- read() {
2939
- node.$.track(listItemToken(normalized));
2940
- return readSlot(values[normalized]);
2941
- },
2942
- peek() {
2943
- return values[normalized];
2944
- },
2945
- write(value) {
2946
- setListValue(node, values, normalized, value);
2947
- return value;
2948
- },
2949
- delete() {
2950
- return removeListValue(node, values, normalized);
2951
- },
2952
- save() {
2953
- return serializeSlot(values[normalized]);
2954
- }
2955
- };
2956
- }
2957
- });
2958
-
2959
- class DerivedListView {
2960
- constructor(source, mapper) {
2961
- if (typeof mapper !== "function") {
2962
- throw new TypeError("List.map() expects a callback");
2963
- }
2964
- this._source = source;
2965
- this._mapper = mapper;
2966
- }
2967
- get length() {
2968
- return this._source.length;
2969
- }
2970
- keys() {
2971
- return this._source.keys();
2972
- }
2973
- get(index) {
2974
- const normalized = normalizeIndex(index);
2975
- return this._mapper(this._source.get(normalized), normalized, this._source);
2976
- }
2977
- at(index) {
2978
- const normalized = normalizeIndex(index);
2979
- return this._mapper(this._source.at(normalized), normalized, this._source);
2980
- }
2981
- toArray() {
2982
- return this.keys().map((index) => this.at(index));
2983
- }
2984
- all() {
2985
- return this.toArray();
2986
- }
2987
- each(callback) {
2988
- if (typeof callback !== "function") {
2989
- throw new TypeError("List.each() expects a callback");
2990
- }
2991
- for (const index of this.keys())
2992
- callback(this.at(index), index, this);
2993
- }
2994
- eachEffect(callback, options = {}) {
2995
- return createEachEffect({
2996
- node: this,
2997
- callback,
2998
- options,
2999
- keys: () => this.keys(),
3000
- peek: (index) => this.get(index),
3001
- read: (index) => this.at(index)
3002
- });
3003
- }
3004
- map(callback) {
3005
- return new DerivedListView(this, callback);
3006
- }
3007
- toJSON() {
3008
- return this.toArray();
3009
- }
3010
- }
3011
- function setListValue(node, values, index, value) {
3012
- const previousLength = values.length;
3013
- const previous = values[index];
3014
- if (Object.is(previous, value) && index in values)
3015
- return;
3016
- batch(() => {
3017
- values[index] = value;
3018
- if (values.length !== previousLength)
3019
- node.$.changed(LIST_LENGTH);
3020
- node.$.changed(listItemToken(index));
3021
- node.$.changed(LIST_ITEMS);
3022
- });
3023
- }
3024
- function pushListValue(node, values, value) {
3025
- batch(() => {
3026
- const index = values.length;
3027
- values.push(value);
3028
- node.$.changed(LIST_LENGTH);
3029
- node.$.changed(listItemToken(index));
3030
- node.$.changed(LIST_ITEMS);
3031
- });
3032
- return values.length;
3033
- }
3034
- function removeListValue(node, values, index) {
3035
- if (index < 0 || index >= values.length)
3036
- return;
3037
- let removed;
3038
- batch(() => {
3039
- removed = values.splice(index, 1)[0];
3040
- node.$.changed(LIST_LENGTH);
3041
- for (let i = index;i <= values.length; i += 1)
3042
- node.$.changed(listItemToken(i));
3043
- node.$.changed(LIST_ITEMS);
3044
- });
3045
- return removed;
3046
- }
3047
- function normalizeIndex(index) {
3048
- if (!Number.isInteger(index) || index < 0) {
3049
- throw new TypeError("List indexes must be non-negative integers");
3050
- }
3051
- return index;
3052
- }
3053
1
  // src/core.js
2
+ import { Anchor, batch, describe } from "orbz";
3054
3
  function createProtocolCodec() {
3055
4
  return {
3056
5
  encode(message) {