@montra-interactive/deepstate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,750 @@
1
+ // src/helpers.ts
2
+ import { combineLatest } from "rxjs";
3
+ import { distinctUntilChanged, map } from "rxjs/operators";
4
+ function deepEqual(a, b) {
5
+ if (a === b)
6
+ return true;
7
+ if (a === null || b === null)
8
+ return false;
9
+ if (typeof a !== "object" || typeof b !== "object")
10
+ return false;
11
+ if (Array.isArray(a) && Array.isArray(b)) {
12
+ if (a.length !== b.length)
13
+ return false;
14
+ return a.every((item, i) => deepEqual(item, b[i]));
15
+ }
16
+ if (Array.isArray(a) !== Array.isArray(b))
17
+ return false;
18
+ const keysA = Object.keys(a);
19
+ const keysB = Object.keys(b);
20
+ if (keysA.length !== keysB.length)
21
+ return false;
22
+ return keysA.every((key) => deepEqual(a[key], b[key]));
23
+ }
24
+ function isObservable(obj) {
25
+ return obj !== null && typeof obj === "object" && "subscribe" in obj && typeof obj.subscribe === "function";
26
+ }
27
+ function select(...args) {
28
+ if (args.length === 1 && !isObservable(args[0])) {
29
+ const obj = args[0];
30
+ const keys = Object.keys(obj);
31
+ const observables = keys.map((k) => obj[k]);
32
+ return combineLatest(observables).pipe(map((values) => {
33
+ const result = {};
34
+ keys.forEach((key, i) => {
35
+ result[key] = values[i];
36
+ });
37
+ return result;
38
+ }));
39
+ }
40
+ return combineLatest(args);
41
+ }
42
+ function selectFromEach(arrayNode, selector) {
43
+ return arrayNode.pipe(map((items) => items.map(selector)), distinctUntilChanged((a, b) => a.length === b.length && a.every((v, i) => deepEqual(v, b[i]))));
44
+ }
45
+
46
+ // src/deepstate.ts
47
+ import { BehaviorSubject, combineLatest as combineLatest2, of } from "rxjs";
48
+ import {
49
+ map as map2,
50
+ distinctUntilChanged as distinctUntilChanged2,
51
+ shareReplay,
52
+ take,
53
+ filter
54
+ } from "rxjs/operators";
55
+ var distinctCallCount = 0;
56
+ function countedDistinctUntilChanged(compareFn) {
57
+ return distinctUntilChanged2((a, b) => {
58
+ distinctCallCount++;
59
+ if (compareFn)
60
+ return compareFn(a, b);
61
+ return a === b;
62
+ });
63
+ }
64
+ function deepFreeze(obj) {
65
+ if (obj === null || typeof obj !== "object")
66
+ return obj;
67
+ if (Object.isFrozen(obj))
68
+ return obj;
69
+ Object.freeze(obj);
70
+ if (Array.isArray(obj)) {
71
+ obj.forEach((item) => deepFreeze(item));
72
+ } else {
73
+ Object.keys(obj).forEach((key) => {
74
+ deepFreeze(obj[key]);
75
+ });
76
+ }
77
+ return obj;
78
+ }
79
+ var NODE = Symbol("node");
80
+ function createLeafNode(value) {
81
+ const subject$ = new BehaviorSubject(value);
82
+ const distinct$ = subject$.pipe(distinctUntilChanged2(), shareReplay(1));
83
+ distinct$.subscribe();
84
+ return {
85
+ $: distinct$,
86
+ get: () => subject$.getValue(),
87
+ set: (v) => subject$.next(v),
88
+ subscribeOnce: (callback) => {
89
+ return distinct$.pipe(take(1)).subscribe(callback);
90
+ }
91
+ };
92
+ }
93
+ function createObjectNode(value) {
94
+ const keys = Object.keys(value);
95
+ const children = new Map;
96
+ for (const key of keys) {
97
+ children.set(key, createNodeForValue(value[key], true));
98
+ }
99
+ const getCurrentValue = () => {
100
+ const result = {};
101
+ for (const [key, child] of children) {
102
+ result[key] = child.get();
103
+ }
104
+ return result;
105
+ };
106
+ if (keys.length === 0) {
107
+ const empty$ = of(value).pipe(shareReplay(1));
108
+ return {
109
+ $: empty$,
110
+ children,
111
+ get: () => ({}),
112
+ set: () => {},
113
+ lock: () => {},
114
+ unlock: () => {}
115
+ };
116
+ }
117
+ const lock$ = new BehaviorSubject(true);
118
+ const childObservables = keys.map((key) => children.get(key).$);
119
+ const $ = combineLatest2([...childObservables, lock$]).pipe(filter((values) => values[values.length - 1] === true), map2((values) => {
120
+ const result = {};
121
+ keys.forEach((key, i) => {
122
+ result[key] = values[i];
123
+ });
124
+ return result;
125
+ }), shareReplay(1));
126
+ $.subscribe();
127
+ const frozen$ = $.pipe(map2(deepFreeze));
128
+ return {
129
+ $: frozen$,
130
+ children,
131
+ get: () => deepFreeze(getCurrentValue()),
132
+ set: (v) => {
133
+ for (const [key, child] of children) {
134
+ child.set(v[key]);
135
+ }
136
+ },
137
+ lock: () => lock$.next(false),
138
+ unlock: () => lock$.next(true),
139
+ subscribeOnce: (callback) => {
140
+ return frozen$.pipe(take(1)).subscribe(callback);
141
+ }
142
+ };
143
+ }
144
+ function createArrayNode(value) {
145
+ const subject$ = new BehaviorSubject([...value]);
146
+ const childCache = new Map;
147
+ const createChildProjection = (index) => {
148
+ const currentValue = subject$.getValue()[index];
149
+ if (currentValue !== null && typeof currentValue === "object") {
150
+ return createArrayElementObjectNode(subject$, index, currentValue);
151
+ }
152
+ const element$ = subject$.pipe(map2((arr) => arr[index]), countedDistinctUntilChanged(), shareReplay(1));
153
+ element$.subscribe();
154
+ return {
155
+ $: element$,
156
+ get: () => subject$.getValue()[index],
157
+ set: (v) => {
158
+ const arr = [...subject$.getValue()];
159
+ arr[index] = v;
160
+ subject$.next(arr);
161
+ },
162
+ subscribeOnce: (callback) => {
163
+ return element$.pipe(take(1)).subscribe(callback);
164
+ }
165
+ };
166
+ };
167
+ const lock$ = new BehaviorSubject(true);
168
+ const locked$ = combineLatest2([subject$, lock$]).pipe(filter(([_, unlocked]) => unlocked), map2(([arr, _]) => arr), map2(deepFreeze), shareReplay(1));
169
+ locked$.subscribe();
170
+ const length$ = locked$.pipe(map2((arr) => arr.length), distinctUntilChanged2(), shareReplay(1));
171
+ length$.subscribe();
172
+ const lengthWithGet = Object.assign(length$, {
173
+ get: () => subject$.getValue().length
174
+ });
175
+ return {
176
+ $: locked$,
177
+ childCache,
178
+ get: () => deepFreeze([...subject$.getValue()]),
179
+ set: (v) => {
180
+ childCache.clear();
181
+ subject$.next([...v]);
182
+ },
183
+ subscribeOnce: (callback) => {
184
+ return locked$.pipe(take(1)).subscribe(callback);
185
+ },
186
+ at: (index) => {
187
+ const arr = subject$.getValue();
188
+ if (index < 0 || index >= arr.length)
189
+ return;
190
+ if (!childCache.has(index)) {
191
+ childCache.set(index, createChildProjection(index));
192
+ }
193
+ return childCache.get(index);
194
+ },
195
+ length$: lengthWithGet,
196
+ push: (...items) => {
197
+ const current = subject$.getValue();
198
+ const newArr = [...current, ...items];
199
+ subject$.next(newArr);
200
+ return newArr.length;
201
+ },
202
+ pop: () => {
203
+ const current = subject$.getValue();
204
+ if (current.length === 0)
205
+ return;
206
+ const last = current[current.length - 1];
207
+ childCache.delete(current.length - 1);
208
+ subject$.next(current.slice(0, -1));
209
+ return deepFreeze(last);
210
+ },
211
+ mapItems: (fn) => {
212
+ return subject$.getValue().map((item, i) => fn(deepFreeze(item), i));
213
+ },
214
+ filterItems: (fn) => {
215
+ return deepFreeze(subject$.getValue().filter((item, i) => fn(deepFreeze(item), i)));
216
+ },
217
+ lock: () => lock$.next(false),
218
+ unlock: () => lock$.next(true)
219
+ };
220
+ }
221
+ var NULLABLE_NODE = Symbol("nullableNode");
222
+ function createNullableObjectNode(initialValue) {
223
+ const subject$ = new BehaviorSubject(initialValue);
224
+ let children = null;
225
+ const pendingChildren = new Map;
226
+ const lock$ = new BehaviorSubject(true);
227
+ const buildChildren = (obj) => {
228
+ const keys = Object.keys(obj);
229
+ children = new Map;
230
+ for (const key of keys) {
231
+ children.set(key, createNodeForValue(obj[key]));
232
+ }
233
+ };
234
+ if (initialValue !== null && initialValue !== undefined && typeof initialValue === "object") {
235
+ buildChildren(initialValue);
236
+ }
237
+ const getCurrentValue = () => {
238
+ const raw = subject$.getValue();
239
+ if (raw === null || raw === undefined || !children) {
240
+ return raw;
241
+ }
242
+ const result = {};
243
+ for (const [key, child] of children) {
244
+ result[key] = child.get();
245
+ }
246
+ return result;
247
+ };
248
+ const $ = combineLatest2([subject$, lock$]).pipe(filter(([_, unlocked]) => unlocked), map2(([value, _]) => {
249
+ if (value === null || value === undefined || !children) {
250
+ return value;
251
+ }
252
+ const result = {};
253
+ for (const [key, child] of children) {
254
+ result[key] = child.get();
255
+ }
256
+ return result;
257
+ }), distinctUntilChanged2((a, b) => {
258
+ if (a === null || a === undefined)
259
+ return a === b;
260
+ if (b === null || b === undefined)
261
+ return false;
262
+ return JSON.stringify(a) === JSON.stringify(b);
263
+ }), map2(deepFreeze), shareReplay(1));
264
+ $.subscribe();
265
+ const nodeState = { children };
266
+ const updateChildrenRef = () => {
267
+ nodeState.children = children;
268
+ };
269
+ const buildChildrenAndUpdate = (obj) => {
270
+ const keys = Object.keys(obj);
271
+ children = new Map;
272
+ for (const key of keys) {
273
+ children.set(key, createNodeForValue(obj[key], true));
274
+ }
275
+ updateChildrenRef();
276
+ for (const [key, pendingNode] of pendingChildren) {
277
+ if (children.has(key) && "_subscribeToRealChild" in pendingNode) {
278
+ pendingNode._subscribeToRealChild();
279
+ }
280
+ }
281
+ };
282
+ if (initialValue !== null && initialValue !== undefined && typeof initialValue === "object") {
283
+ children = null;
284
+ buildChildrenAndUpdate(initialValue);
285
+ }
286
+ return {
287
+ [NULLABLE_NODE]: true,
288
+ $,
289
+ get children() {
290
+ return nodeState.children;
291
+ },
292
+ get: () => deepFreeze(getCurrentValue()),
293
+ set: (value) => {
294
+ if (value === null || value === undefined) {
295
+ subject$.next(value);
296
+ } else if (typeof value === "object") {
297
+ if (!children) {
298
+ buildChildrenAndUpdate(value);
299
+ } else {
300
+ const newKeys = new Set(Object.keys(value));
301
+ const existingKeys = new Set(children.keys());
302
+ for (const [key, child] of children) {
303
+ if (newKeys.has(key)) {
304
+ child.set(value[key]);
305
+ }
306
+ }
307
+ for (const key of newKeys) {
308
+ if (!existingKeys.has(key)) {
309
+ children.set(key, createNodeForValue(value[key], true));
310
+ }
311
+ }
312
+ }
313
+ subject$.next(value);
314
+ }
315
+ },
316
+ getChild: (key) => {
317
+ const value = subject$.getValue();
318
+ if (value === null || value === undefined || !children) {
319
+ return;
320
+ }
321
+ return children.get(key);
322
+ },
323
+ getOrCreateChild: (key) => {
324
+ if (children && children.has(key)) {
325
+ return children.get(key);
326
+ }
327
+ if (pendingChildren.has(key)) {
328
+ if (children && children.has(key)) {
329
+ return children.get(key);
330
+ }
331
+ return pendingChildren.get(key);
332
+ }
333
+ const pendingSubject$ = new BehaviorSubject(undefined);
334
+ const parentSubscription = subject$.subscribe((parentValue) => {
335
+ if (parentValue === null || parentValue === undefined) {
336
+ pendingSubject$.next(undefined);
337
+ } else if (children && children.has(key)) {
338
+ pendingSubject$.next(children.get(key).get());
339
+ } else {
340
+ pendingSubject$.next(parentValue[key]);
341
+ }
342
+ });
343
+ let realChildSubscription = null;
344
+ const child$ = pendingSubject$.pipe(distinctUntilChanged2(), shareReplay(1));
345
+ child$.subscribe();
346
+ const pendingNode = {
347
+ $: child$,
348
+ get: () => {
349
+ const parentValue = subject$.getValue();
350
+ if (parentValue === null || parentValue === undefined) {
351
+ return;
352
+ }
353
+ if (children && children.has(key)) {
354
+ return children.get(key).get();
355
+ }
356
+ return parentValue[key];
357
+ },
358
+ set: (value) => {
359
+ const parentValue = subject$.getValue();
360
+ if (parentValue === null || parentValue === undefined) {
361
+ return;
362
+ }
363
+ if (children && children.has(key)) {
364
+ children.get(key).set(value);
365
+ return;
366
+ }
367
+ const newParent = { ...parentValue, [key]: value };
368
+ subject$.next(newParent);
369
+ },
370
+ _subscribeToRealChild: () => {
371
+ if (children && children.has(key) && !realChildSubscription) {
372
+ realChildSubscription = children.get(key).$.subscribe((value) => {
373
+ pendingSubject$.next(value);
374
+ });
375
+ }
376
+ }
377
+ };
378
+ pendingChildren.set(key, pendingNode);
379
+ return pendingNode;
380
+ },
381
+ isNull: () => {
382
+ const value = subject$.getValue();
383
+ return value === null || value === undefined;
384
+ },
385
+ lock: () => lock$.next(false),
386
+ unlock: () => lock$.next(true),
387
+ subscribeOnce: (callback) => {
388
+ return $.pipe(take(1)).subscribe(callback);
389
+ }
390
+ };
391
+ }
392
+ function isNullableNode(node) {
393
+ return NULLABLE_NODE in node;
394
+ }
395
+ function createArrayElementObjectNode(parentArray$, index, initialValue) {
396
+ const keys = Object.keys(initialValue);
397
+ const children = new Map;
398
+ for (const key of keys) {
399
+ children.set(key, createArrayElementPropertyNode(parentArray$, index, key, initialValue[key]));
400
+ }
401
+ if (keys.length === 0) {
402
+ const element$ = parentArray$.pipe(map2((arr) => arr[index]), countedDistinctUntilChanged(), shareReplay(1));
403
+ element$.subscribe();
404
+ return {
405
+ $: element$,
406
+ children,
407
+ get: () => parentArray$.getValue()[index],
408
+ set: (v) => {
409
+ const arr = [...parentArray$.getValue()];
410
+ arr[index] = v;
411
+ parentArray$.next(arr);
412
+ }
413
+ };
414
+ }
415
+ const childObservables = keys.map((key) => children.get(key).$);
416
+ const $ = combineLatest2(childObservables).pipe(map2((values) => {
417
+ const result = {};
418
+ keys.forEach((key, i) => {
419
+ result[key] = values[i];
420
+ });
421
+ return result;
422
+ }), countedDistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), shareReplay(1));
423
+ $.subscribe();
424
+ return {
425
+ $,
426
+ children,
427
+ get: () => {
428
+ const result = {};
429
+ for (const [key, child] of children) {
430
+ result[key] = child.get();
431
+ }
432
+ return result;
433
+ },
434
+ set: (v) => {
435
+ const arr = [...parentArray$.getValue()];
436
+ arr[index] = v;
437
+ parentArray$.next(arr);
438
+ for (const [key, child] of children) {
439
+ child.set(v[key]);
440
+ }
441
+ }
442
+ };
443
+ }
444
+ function createArrayElementPropertyNode(parentArray$, index, key, initialValue) {
445
+ if (initialValue !== null && typeof initialValue === "object") {
446
+ if (Array.isArray(initialValue)) {
447
+ return createNestedArrayProjection(parentArray$, index, key, initialValue);
448
+ }
449
+ return createNestedObjectProjection(parentArray$, index, key, initialValue);
450
+ }
451
+ const prop$ = parentArray$.pipe(map2((arr) => arr[index]?.[key]), countedDistinctUntilChanged(), shareReplay(1));
452
+ prop$.subscribe();
453
+ return {
454
+ $: prop$,
455
+ get: () => {
456
+ const arr = parentArray$.getValue();
457
+ return arr[index]?.[key];
458
+ },
459
+ set: (v) => {
460
+ const arr = [...parentArray$.getValue()];
461
+ arr[index] = { ...arr[index], [key]: v };
462
+ parentArray$.next(arr);
463
+ }
464
+ };
465
+ }
466
+ function createNestedObjectProjection(parentArray$, index, key, initialValue) {
467
+ const keys = Object.keys(initialValue);
468
+ const children = new Map;
469
+ for (const nestedKey of keys) {
470
+ const nested$ = parentArray$.pipe(map2((arr) => {
471
+ const element = arr[index];
472
+ const obj = element?.[key];
473
+ return obj?.[nestedKey];
474
+ }), countedDistinctUntilChanged(), shareReplay(1));
475
+ nested$.subscribe();
476
+ children.set(nestedKey, {
477
+ $: nested$,
478
+ get: () => {
479
+ const arr = parentArray$.getValue();
480
+ const element = arr[index];
481
+ const obj = element?.[key];
482
+ return obj?.[nestedKey];
483
+ },
484
+ set: (v) => {
485
+ const arr = [...parentArray$.getValue()];
486
+ const element = { ...arr[index] };
487
+ element[key] = { ...element[key], [nestedKey]: v };
488
+ arr[index] = element;
489
+ parentArray$.next(arr);
490
+ }
491
+ });
492
+ }
493
+ const obj$ = parentArray$.pipe(map2((arr) => arr[index]?.[key]), countedDistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), shareReplay(1));
494
+ obj$.subscribe();
495
+ return {
496
+ $: obj$,
497
+ children,
498
+ get: () => {
499
+ const arr = parentArray$.getValue();
500
+ return arr[index]?.[key];
501
+ },
502
+ set: (v) => {
503
+ const arr = [...parentArray$.getValue()];
504
+ arr[index] = { ...arr[index], [key]: v };
505
+ parentArray$.next(arr);
506
+ }
507
+ };
508
+ }
509
+ function createNestedArrayProjection(parentArray$, index, key, initialValue) {
510
+ const arr$ = parentArray$.pipe(map2((arr) => arr[index]?.[key]), countedDistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), shareReplay(1));
511
+ arr$.subscribe();
512
+ return {
513
+ $: arr$,
514
+ get: () => {
515
+ const arr = parentArray$.getValue();
516
+ return arr[index]?.[key];
517
+ },
518
+ set: (v) => {
519
+ const arr = [...parentArray$.getValue()];
520
+ arr[index] = { ...arr[index], [key]: v };
521
+ parentArray$.next(arr);
522
+ }
523
+ };
524
+ }
525
+ function createNodeForValue(value, maybeNullable = false) {
526
+ if (isNullableMarked(value)) {
527
+ delete value[NULLABLE_MARKER];
528
+ return createNullableObjectNode(value);
529
+ }
530
+ if (value === null || value === undefined) {
531
+ if (maybeNullable) {
532
+ return createNullableObjectNode(value);
533
+ }
534
+ return createLeafNode(value);
535
+ }
536
+ if (typeof value !== "object") {
537
+ return createLeafNode(value);
538
+ }
539
+ if (Array.isArray(value)) {
540
+ return createArrayNode(value);
541
+ }
542
+ return createObjectNode(value);
543
+ }
544
+ function wrapNullableWithProxy(node) {
545
+ const update = (callback) => {
546
+ node.lock();
547
+ try {
548
+ const childrenProxy = new Proxy({}, {
549
+ get(_, prop) {
550
+ if (typeof prop === "string") {
551
+ const child = node.getChild(prop);
552
+ if (child) {
553
+ return wrapWithProxy(child);
554
+ }
555
+ }
556
+ return;
557
+ }
558
+ });
559
+ callback(childrenProxy);
560
+ } finally {
561
+ node.unlock();
562
+ }
563
+ return node.get();
564
+ };
565
+ const proxy = new Proxy(node.$, {
566
+ get(target, prop) {
567
+ if (prop === "subscribe")
568
+ return node.$.subscribe.bind(node.$);
569
+ if (prop === "pipe")
570
+ return node.$.pipe.bind(node.$);
571
+ if (prop === "forEach")
572
+ return node.$.forEach?.bind(node.$);
573
+ if (prop === "get")
574
+ return node.get;
575
+ if (prop === "set")
576
+ return node.set;
577
+ if (prop === "update")
578
+ return update;
579
+ if (prop === "subscribeOnce")
580
+ return node.subscribeOnce;
581
+ if (prop === NODE)
582
+ return node;
583
+ if (prop === Symbol.observable || prop === "@@observable") {
584
+ return () => node.$;
585
+ }
586
+ if (typeof prop === "string") {
587
+ const child = node.getOrCreateChild(prop);
588
+ return wrapWithProxy(child);
589
+ }
590
+ if (prop in target) {
591
+ const val = target[prop];
592
+ return typeof val === "function" ? val.bind(target) : val;
593
+ }
594
+ return;
595
+ },
596
+ has(_, prop) {
597
+ if (!node.isNull() && node.children && typeof prop === "string") {
598
+ return node.children.has(prop);
599
+ }
600
+ return false;
601
+ },
602
+ ownKeys() {
603
+ if (!node.isNull() && node.children) {
604
+ return Array.from(node.children.keys());
605
+ }
606
+ return [];
607
+ },
608
+ getOwnPropertyDescriptor(_, prop) {
609
+ if (!node.isNull() && node.children && typeof prop === "string" && node.children.has(prop)) {
610
+ return { enumerable: true, configurable: true };
611
+ }
612
+ return;
613
+ }
614
+ });
615
+ return proxy;
616
+ }
617
+ function wrapWithProxy(node) {
618
+ if (isNullableNode(node)) {
619
+ return wrapNullableWithProxy(node);
620
+ }
621
+ const value = node.get();
622
+ if (value === null || typeof value !== "object") {
623
+ return Object.assign(node.$, {
624
+ get: node.get,
625
+ set: node.set,
626
+ subscribe: node.$.subscribe.bind(node.$),
627
+ pipe: node.$.pipe.bind(node.$),
628
+ subscribeOnce: node.subscribeOnce,
629
+ [NODE]: node
630
+ });
631
+ }
632
+ if (Array.isArray(value)) {
633
+ const arrayNode = node;
634
+ const wrapped = Object.assign(node.$, {
635
+ get: node.get,
636
+ set: node.set,
637
+ subscribe: node.$.subscribe.bind(node.$),
638
+ pipe: node.$.pipe.bind(node.$),
639
+ subscribeOnce: node.subscribeOnce,
640
+ at: (index) => {
641
+ const child = arrayNode.at(index);
642
+ if (!child)
643
+ return;
644
+ return wrapWithProxy(child);
645
+ },
646
+ length: arrayNode.length$,
647
+ push: arrayNode.push,
648
+ pop: arrayNode.pop,
649
+ map: arrayNode.mapItems,
650
+ filter: arrayNode.filterItems,
651
+ update: (callback) => {
652
+ arrayNode.lock();
653
+ try {
654
+ callback(wrapped);
655
+ } finally {
656
+ arrayNode.unlock();
657
+ }
658
+ return node.get();
659
+ },
660
+ [NODE]: node
661
+ });
662
+ return wrapped;
663
+ }
664
+ const objectNode = node;
665
+ let updateFn;
666
+ const proxy = new Proxy(node.$, {
667
+ get(target, prop) {
668
+ if (prop === "subscribe")
669
+ return node.$.subscribe.bind(node.$);
670
+ if (prop === "pipe")
671
+ return node.$.pipe.bind(node.$);
672
+ if (prop === "forEach")
673
+ return node.$.forEach?.bind(node.$);
674
+ if (prop === "get")
675
+ return node.get;
676
+ if (prop === "set")
677
+ return node.set;
678
+ if (prop === "update")
679
+ return updateFn;
680
+ if (prop === "subscribeOnce")
681
+ return node.subscribeOnce;
682
+ if (prop === NODE)
683
+ return node;
684
+ if (prop === Symbol.observable || prop === "@@observable") {
685
+ return () => node.$;
686
+ }
687
+ if (objectNode.children && typeof prop === "string") {
688
+ const child = objectNode.children.get(prop);
689
+ if (child) {
690
+ return wrapWithProxy(child);
691
+ }
692
+ }
693
+ if (prop in target) {
694
+ const val = target[prop];
695
+ return typeof val === "function" ? val.bind(target) : val;
696
+ }
697
+ return;
698
+ },
699
+ has(target, prop) {
700
+ if (objectNode.children && typeof prop === "string") {
701
+ return objectNode.children.has(prop);
702
+ }
703
+ return prop in target;
704
+ },
705
+ ownKeys() {
706
+ if (objectNode.children) {
707
+ return Array.from(objectNode.children.keys());
708
+ }
709
+ return [];
710
+ },
711
+ getOwnPropertyDescriptor(target, prop) {
712
+ if (objectNode.children && typeof prop === "string" && objectNode.children.has(prop)) {
713
+ return { enumerable: true, configurable: true };
714
+ }
715
+ return;
716
+ }
717
+ });
718
+ if (objectNode.lock && objectNode.unlock) {
719
+ updateFn = (callback) => {
720
+ objectNode.lock();
721
+ try {
722
+ callback(proxy);
723
+ } finally {
724
+ objectNode.unlock();
725
+ }
726
+ return node.get();
727
+ };
728
+ }
729
+ return proxy;
730
+ }
731
+ function state(initialState) {
732
+ const node = createObjectNode(initialState);
733
+ return wrapWithProxy(node);
734
+ }
735
+ var NULLABLE_MARKER = Symbol("nullable");
736
+ function nullable(value) {
737
+ if (value === null) {
738
+ return null;
739
+ }
740
+ return Object.assign(value, { [NULLABLE_MARKER]: true });
741
+ }
742
+ function isNullableMarked(value) {
743
+ return value !== null && typeof value === "object" && NULLABLE_MARKER in value;
744
+ }
745
+ export {
746
+ state,
747
+ selectFromEach,
748
+ select,
749
+ nullable
750
+ };