teamplay 0.5.0-alpha.33 → 0.5.0-alpha.35

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/orm/$.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import getSignal from "./getSignal.js";
5
5
  import Signal from "./Signal.js";
6
6
  import { LOCAL, valueSubscriptions } from './Value.js';
7
- import { reactionSubscriptions } from './Reaction.js';
7
+ import { reactionSubscriptions } from './reactionSubscriptions.js';
8
8
  export { LOCAL } from './Value.js';
9
9
  let counter = 0;
10
10
  function newIncrementalId() {
@@ -1,7 +1,7 @@
1
- import { raw, observe, unobserve } from '@nx-js/observer-util';
1
+ import { raw } from '@nx-js/observer-util';
2
2
  import arrayDiff from 'arraydiff';
3
3
  import { Signal, GETTERS, DEFAULT_GETTERS, SEGMENTS, isPublicCollection, isPublicCollectionSignal, isPublicDocumentSignal } from "../SignalBase.js";
4
- import { getRoot, ROOT, ROOT_ID, getRootSignal, GLOBAL_ROOT_ID } from "../Root.js";
4
+ import { getRoot, ROOT, ROOT_ID } from "../Root.js";
5
5
  import { docSubscriptions } from '../Doc.js';
6
6
  import { IS_QUERY, querySubscriptions } from '../Query.js';
7
7
  import { AGGREGATIONS, IS_AGGREGATION, aggregationSubscriptions } from '../Aggregation.js';
@@ -9,13 +9,7 @@ import { getIdFieldsForSegments, isIdFieldPath, isPublicDocPath, normalizeIdFiel
9
9
  import { incrementPublic as _incrementPublic, arrayPushPublic as _arrayPushPublic, arrayUnshiftPublic as _arrayUnshiftPublic, arrayInsertPublic as _arrayInsertPublic, arrayPopPublic as _arrayPopPublic, arrayShiftPublic as _arrayShiftPublic, arrayRemovePublic as _arrayRemovePublic, arrayMovePublic as _arrayMovePublic, setPublicDocReplace as _setPublicDocReplace, stringInsertPublic as _stringInsertPublic, stringRemovePublic as _stringRemovePublic } from '../dataTree.js';
10
10
  import { on as onCustomEvent, removeListener as removeCustomEventListener } from '../events.js';
11
11
  import { waitForImperativeQueryReady } from '../queryReadiness.js';
12
- import { isModelEventsEnabled } from './modelEvents.js';
13
- import { setRefLink, removeRefLink, getAllRefLinks } from './refRegistry.js';
14
- import { REF_TARGET, resolveRefSignalSafe, resolveRefSegmentsSafe } from './refFallback.js';
15
12
  import { runInBatch } from '../batchScheduler.js';
16
- import { runInModelEventsSilentContext, isSilentContextActive } from './silentContext.js';
17
- import universal$ from "../../react/universal$.js";
18
- import { getRootContext } from "../rootContext.js";
19
13
  import { arrayInsertPrivateData, arrayMovePrivateData, arrayPopPrivateData, arrayPushPrivateData, arrayRemovePrivateData, arrayShiftPrivateData, arrayUnshiftPrivateData, delPrivateData, setReplacePrivateData, stringInsertPrivateData, stringRemovePrivateData } from '../privateData.js';
20
14
  class SignalCompat extends Signal {
21
15
  static [GETTERS] = DEFAULT_GETTERS;
@@ -27,15 +21,9 @@ class SignalCompat extends Signal {
27
21
  getId() {
28
22
  if (isAggregationValuePath(this[SEGMENTS]))
29
23
  return super.getId();
30
- const $target = resolveRefSignal(this);
31
- if ($target !== this)
32
- return $target.getId();
33
24
  return super.getId();
34
25
  }
35
26
  getCollection() {
36
- const $target = resolveRefSignal(this);
37
- if ($target !== this)
38
- return $target.getCollection();
39
27
  return super.getCollection();
40
28
  }
41
29
  getCopy() {
@@ -75,15 +63,9 @@ class SignalCompat extends Signal {
75
63
  peek() {
76
64
  if (arguments.length > 0)
77
65
  throw Error('Signal.peek() does not accept any arguments');
78
- const $target = resolveRefSignal(this);
79
- if ($target !== this)
80
- return Signal.prototype.peek.apply($target, arguments);
81
66
  return Signal.prototype.peek.apply(this, arguments);
82
67
  }
83
68
  async set(value) {
84
- const forwarded = forwardRef(this, 'set', arguments);
85
- if (forwarded)
86
- return forwarded;
87
69
  if (arguments.length > 1)
88
70
  throw Error('Signal.set() expects a single argument');
89
71
  if (value === undefined)
@@ -91,9 +73,6 @@ class SignalCompat extends Signal {
91
73
  return setReplaceOnSignal(this, value);
92
74
  }
93
75
  async setReplace(value) {
94
- const forwarded = forwardRef(this, 'setReplace', arguments);
95
- if (forwarded)
96
- return forwarded;
97
76
  if (arguments.length > 1)
98
77
  throw Error('Signal.setReplace() expects a single argument');
99
78
  if (value === undefined)
@@ -101,9 +80,6 @@ class SignalCompat extends Signal {
101
80
  return setReplaceOnSignal(this, value);
102
81
  }
103
82
  async setNull(value) {
104
- const forwarded = forwardRef(this, 'setNull', arguments);
105
- if (forwarded)
106
- return forwarded;
107
83
  if (arguments.length > 1)
108
84
  throw Error('Signal.setNull() expects a single argument');
109
85
  if (this.get() != null)
@@ -111,17 +87,11 @@ class SignalCompat extends Signal {
111
87
  return setReplaceOnSignal(this, value);
112
88
  }
113
89
  async setDiffDeep(value) {
114
- const forwarded = forwardRef(this, 'setDiffDeep', arguments);
115
- if (forwarded)
116
- return forwarded;
117
90
  if (arguments.length > 1)
118
91
  throw Error('Signal.setDiffDeep() expects a single argument');
119
92
  return runInBatch(() => setDiffDeepOnSignal(this, value));
120
93
  }
121
94
  async setDiff(value) {
122
- const forwarded = forwardRef(this, 'setDiff', arguments);
123
- if (forwarded)
124
- return forwarded;
125
95
  if (arguments.length > 1)
126
96
  throw Error('Signal.setDiff() expects a single argument');
127
97
  const before = this.peek();
@@ -130,9 +100,6 @@ class SignalCompat extends Signal {
130
100
  return setReplaceOnSignal(this, value);
131
101
  }
132
102
  async setEach(object) {
133
- const forwarded = forwardRef(this, 'setEach', arguments);
134
- if (forwarded)
135
- return forwarded;
136
103
  if (arguments.length > 1)
137
104
  throw Error('Signal.setEach() expects a single argument');
138
105
  if (!object)
@@ -149,9 +116,6 @@ class SignalCompat extends Signal {
149
116
  });
150
117
  }
151
118
  async del() {
152
- const forwarded = forwardRef(this, 'del', arguments);
153
- if (forwarded)
154
- return forwarded;
155
119
  if (arguments.length > 0)
156
120
  throw Error('Signal.del() does not accept any arguments');
157
121
  try {
@@ -164,9 +128,6 @@ class SignalCompat extends Signal {
164
128
  }
165
129
  }
166
130
  async increment(byNumber) {
167
- const forwarded = forwardRef(this, 'increment', arguments);
168
- if (forwarded)
169
- return forwarded;
170
131
  if (arguments.length > 1)
171
132
  throw Error('Signal.increment() expects zero or one argument');
172
133
  if (byNumber != null && (typeof byNumber !== 'number' || !Number.isFinite(byNumber))) {
@@ -175,25 +136,16 @@ class SignalCompat extends Signal {
175
136
  return incrementOnSignal(this, byNumber);
176
137
  }
177
138
  async push(value) {
178
- const forwarded = forwardRef(this, 'push', arguments);
179
- if (forwarded)
180
- return forwarded;
181
139
  if (arguments.length > 1)
182
140
  throw Error('Signal.push() expects a single argument');
183
141
  return arrayPushOnSignal(this, value);
184
142
  }
185
143
  async unshift(value) {
186
- const forwarded = forwardRef(this, 'unshift', arguments);
187
- if (forwarded)
188
- return forwarded;
189
144
  if (arguments.length > 1)
190
145
  throw Error('Signal.unshift() expects a single argument');
191
146
  return arrayUnshiftOnSignal(this, value);
192
147
  }
193
148
  async insert(index, values) {
194
- const forwarded = forwardRef(this, 'insert', arguments);
195
- if (forwarded)
196
- return forwarded;
197
149
  if (arguments.length < 2)
198
150
  throw Error('Not enough arguments for insert');
199
151
  if (arguments.length > 2)
@@ -204,25 +156,16 @@ class SignalCompat extends Signal {
204
156
  return arrayInsertOnSignal(this, index, values);
205
157
  }
206
158
  async pop() {
207
- const forwarded = forwardRef(this, 'pop', arguments);
208
- if (forwarded)
209
- return forwarded;
210
159
  if (arguments.length > 0)
211
160
  throw Error('Signal.pop() does not accept any arguments');
212
161
  return arrayPopOnSignal(this);
213
162
  }
214
163
  async shift() {
215
- const forwarded = forwardRef(this, 'shift', arguments);
216
- if (forwarded)
217
- return forwarded;
218
164
  if (arguments.length > 0)
219
165
  throw Error('Signal.shift() does not accept any arguments');
220
166
  return arrayShiftOnSignal(this);
221
167
  }
222
168
  async remove(index, howMany) {
223
- const forwarded = forwardRef(this, 'remove', arguments);
224
- if (forwarded)
225
- return forwarded;
226
169
  if (arguments.length === 0) {
227
170
  const segments = this[SEGMENTS].slice();
228
171
  if (!segments.length || typeof segments[segments.length - 1] !== 'number') {
@@ -241,9 +184,6 @@ class SignalCompat extends Signal {
241
184
  return arrayRemoveOnSignal(this, index, howMany);
242
185
  }
243
186
  async move(from, to, howMany) {
244
- const forwarded = forwardRef(this, 'move', arguments);
245
- if (forwarded)
246
- return forwarded;
247
187
  if (arguments.length < 2)
248
188
  throw Error('Not enough arguments for move');
249
189
  if (arguments.length > 3)
@@ -254,9 +194,6 @@ class SignalCompat extends Signal {
254
194
  return arrayMoveOnSignal(this, from, to, howMany);
255
195
  }
256
196
  async stringInsert(index, text) {
257
- const forwarded = forwardRef(this, 'stringInsert', arguments);
258
- if (forwarded)
259
- return forwarded;
260
197
  if (arguments.length < 2)
261
198
  throw Error('Not enough arguments for stringInsert');
262
199
  if (arguments.length > 2)
@@ -267,9 +204,6 @@ class SignalCompat extends Signal {
267
204
  return stringInsertOnSignal(this, index, text);
268
205
  }
269
206
  async stringRemove(index, howMany) {
270
- const forwarded = forwardRef(this, 'stringRemove', arguments);
271
- if (forwarded)
272
- return forwarded;
273
207
  if (arguments.length < 2)
274
208
  throw Error('Not enough arguments for stringRemove');
275
209
  if (arguments.length > 2)
@@ -282,9 +216,6 @@ class SignalCompat extends Signal {
282
216
  return stringRemoveOnSignal(this, index, howMany);
283
217
  }
284
218
  async assign(value) {
285
- const forwarded = forwardRef(this, 'assign', arguments);
286
- if (forwarded)
287
- return forwarded;
288
219
  if (arguments.length > 1)
289
220
  throw Error('Signal.assign() expects a single argument');
290
221
  return Signal.prototype.assign.call(this, value);
@@ -319,245 +250,15 @@ class SignalCompat extends Signal {
319
250
  throw Error('Signal.removeListener() expects two arguments');
320
251
  return removeCustomEventListener(eventName, handler);
321
252
  }
322
- ref(path, target, options) {
323
- if (arguments.length < 1 || arguments.length > 2)
324
- throw Error('Signal.ref() expects one or two arguments');
325
- let $to;
326
- if (arguments.length === 1) {
327
- $to = resolveRefTarget(this, path, 'Signal.ref()');
328
- }
329
- else {
330
- $to = resolveRefTarget(this, path, 'Signal.ref()');
331
- options = target;
332
- }
333
- if (!$to)
334
- throw Error('Signal.ref() expects a target path or signal');
335
- if (this === $to)
336
- return this;
337
- ensurePrivateRefSource(this, 'Signal.ref()');
338
- const store = getRefStore(this);
339
- const fromPath = this.path();
340
- const existing = store.get(fromPath);
341
- if (existing)
342
- existing.stop();
343
- const mirrorOnly = !!($to?.[IS_QUERY] || $to?.[IS_AGGREGATION]);
344
- const { stop, onChange } = createRefLink(this, $to, { mirrorOnly, options });
345
- store.set(fromPath, { stop });
346
- const fromRootId = (getRoot(this) || this)?.[ROOT_ID];
347
- const toRootId = (getRoot($to) || $to)?.[ROOT_ID];
348
- if (!mirrorOnly) {
349
- this[REF_TARGET] = $to;
350
- setRefLink(fromRootId, fromPath, $to.path(), this[SEGMENTS], $to[SEGMENTS], {
351
- mirrorOnly: false,
352
- fromRootId,
353
- toRootId
354
- });
355
- }
356
- else {
357
- setRefLink(fromRootId, fromPath, $to.path(), this[SEGMENTS], $to[SEGMENTS], {
358
- mirrorOnly: true,
359
- onChange,
360
- fromRootId,
361
- toRootId
362
- });
363
- if (this[REF_TARGET])
364
- delete this[REF_TARGET];
365
- }
366
- return this;
367
- }
368
- refExtra(path) {
369
- if (arguments.length !== 1)
370
- throw Error('Signal.refExtra() expects a single argument');
371
- const segments = parseAtSubpath(path, 1, 'Signal.refExtra()');
372
- const $root = getRoot(this) || this;
373
- const $target = resolveSignal($root, segments);
374
- let $source = this;
375
- if (this[IS_QUERY]) {
376
- $source = this.extra;
377
- }
378
- return SignalCompat.prototype.ref.call($target, $source);
379
- }
380
- refIds(path) {
381
- if (arguments.length !== 1)
382
- throw Error('Signal.refIds() expects a single argument');
383
- if (!this[IS_QUERY]) {
384
- throw Error('Signal.refIds() can only be used on query signals');
385
- }
386
- const segments = parseAtSubpath(path, 1, 'Signal.refIds()');
387
- const $root = getRoot(this) || this;
388
- const $target = resolveSignal($root, segments);
389
- return SignalCompat.prototype.ref.call($target, this.ids);
390
- }
391
- removeRef() {
392
- if (arguments.length > 0)
393
- throw Error('Signal.removeRef() does not accept any arguments');
394
- const store = getRefStore(this);
395
- const fromPath = this.path();
396
- const existing = store.get(fromPath);
397
- if (existing) {
398
- existing.stop();
399
- store.delete(fromPath);
400
- }
401
- const fromRootId = (getRoot(this) || this)?.[ROOT_ID];
402
- removeRefLink(fromRootId, fromPath);
403
- const $target = resolveRefSignal(this);
404
- if ($target !== this) {
405
- setDiffDeepBypassRef(this, deepCopy($target.get()));
406
- }
407
- if (this[REF_TARGET])
408
- delete this[REF_TARGET];
409
- }
410
- }
411
- function getRefStore($signal) {
412
- const $root = getRoot($signal) || $signal;
413
- const rootId = $root?.[ROOT_ID];
414
- return getRootContext(rootId, true).activeRefs;
415
- }
416
- function createRefLink($from, $to, { mirrorOnly = false } = {}) {
417
- let disposed = false;
418
- let pendingRead = null;
419
- let mirrorObserver;
420
- const syncFromTarget = () => {
421
- const value = readRefValue($to);
422
- if (isThenable(value)) {
423
- pendingRead = value;
424
- value.then(() => {
425
- if (disposed || pendingRead !== value)
426
- return;
427
- pendingRead = null;
428
- syncFromTarget();
429
- }, () => {
430
- if (pendingRead === value)
431
- pendingRead = null;
432
- });
433
- return;
434
- }
435
- if (value === undefined)
436
- return;
437
- setDiffDeepBypassRef($from, deepCopy(value));
438
- };
439
- syncFromTarget();
440
- if (mirrorOnly) {
441
- mirrorObserver = observe(() => {
442
- syncFromTarget();
443
- return readRefValue($to);
444
- }, {
445
- scheduler: job => job()
446
- });
447
- // initialize dependency graph
448
- mirrorObserver();
449
- }
450
- return {
451
- onChange: syncFromTarget,
452
- stop: () => {
453
- disposed = true;
454
- if (mirrorObserver)
455
- unobserve(mirrorObserver);
456
- // Subsequent sync happens directly at mutation time via mirrorRefMutationFromTarget().
457
- }
458
- };
459
- }
460
- function readRefValue($signal) {
461
- try {
462
- return $signal.get();
463
- }
464
- catch (err) {
465
- if (isThenable(err))
466
- return err;
467
- throw err;
468
- }
469
253
  }
470
254
  function isAggregationValuePath(segments) {
471
255
  return Array.isArray(segments) &&
472
256
  segments.length >= 3 &&
473
257
  segments[0] === AGGREGATIONS;
474
258
  }
475
- function resolveRefSignal($signal) {
476
- const directTarget = resolveRefSignalSafe($signal);
477
- if (directTarget && directTarget !== $signal)
478
- return directTarget;
479
- const resolvedSegments = resolveRefSegmentsSafe($signal[SEGMENTS], (getRoot($signal) || $signal)?.[ROOT_ID]);
480
- if (!resolvedSegments)
481
- return $signal;
482
- const $root = getRoot($signal) || $signal;
483
- return resolveSignal($root, resolvedSegments);
484
- }
485
- function forwardRef($signal, methodName, args) {
486
- const $target = resolveRefSignal($signal);
487
- if ($target === $signal)
488
- return null;
489
- return SignalCompat.prototype[methodName].apply($target, args);
490
- }
491
- function setDiffDeepBypassRef($signal, value) {
492
- const segments = $signal[SEGMENTS];
493
- if (isPublicCollection(segments[0]))
494
- return Signal.prototype.set.call($signal, value);
495
- return setReplacePrivateData(getOwningRootId($signal), segments, value);
496
- }
497
- function mirrorRefMutationFromTarget(targetSegments, value) {
498
- if (!Array.isArray(targetSegments) || targetSegments.length === 0)
499
- return;
500
- const updates = [];
501
- for (const link of getAllRefLinks()) {
502
- if (!isPathPrefix(link.toSegments, targetSegments))
503
- continue;
504
- const suffix = targetSegments.slice(link.toSegments.length);
505
- updates.push({
506
- fromRootId: link.fromRootId,
507
- segments: link.fromSegments.concat(suffix),
508
- value: deepCopy(value)
509
- });
510
- }
511
- if (!updates.length)
512
- return;
513
- runInModelEventsSilentContext(() => {
514
- for (const update of updates) {
515
- const $root = getRootSignal({
516
- rootId: update.fromRootId || GLOBAL_ROOT_ID,
517
- rootFunction: universal$
518
- });
519
- const $target = resolveSignal($root, update.segments);
520
- setDiffDeepBypassRef($target, update.value);
521
- }
522
- });
523
- }
524
- function isPathPrefix(prefixSegments, fullSegments) {
525
- if (prefixSegments.length > fullSegments.length)
526
- return false;
527
- for (let i = 0; i < prefixSegments.length; i++) {
528
- if (String(prefixSegments[i]) !== String(fullSegments[i]))
529
- return false;
530
- }
531
- return true;
532
- }
533
- function isSignalLike(value) {
534
- return value && typeof value.path === 'function' && typeof value.get === 'function';
535
- }
536
259
  function isReactLike(value) {
537
260
  return !!(value && typeof value === 'object' && typeof value.$$typeof === 'symbol');
538
261
  }
539
- function isThenable(value) {
540
- return !!value && typeof value.then === 'function';
541
- }
542
- function resolveRefTarget($signal, target, methodName) {
543
- if (isSignalLike(target))
544
- return target;
545
- if (typeof target === 'string') {
546
- const segments = parseAtSubpath(target, 1, methodName);
547
- const $root = getRoot($signal) || $signal;
548
- return resolveSignal($root, segments);
549
- }
550
- return undefined;
551
- }
552
- function parseAtSubpath(subpath, argsLength, methodName) {
553
- if (argsLength === 0)
554
- return [];
555
- if (typeof subpath === 'string')
556
- return subpath.split('.').filter(Boolean);
557
- if (typeof subpath === 'number' && Number.isFinite(subpath) && Number.isInteger(subpath))
558
- return [subpath];
559
- throw Error(`${methodName} expects a string or integer argument`);
560
- }
561
262
  function resolveSignal($signal, segments) {
562
263
  let $cursor = $signal;
563
264
  for (const segment of segments) {
@@ -716,9 +417,6 @@ function setReplacePrivateCompatSync($signal, value) {
716
417
  value = normalizeIdFields(value, idFields, segments[1]);
717
418
  }
718
419
  setReplacePrivateData(getOwningRootId($signal), segments, value);
719
- if (shouldMirrorPrivateRefMutationLocally()) {
720
- mirrorRefMutationFromTarget(segments, value);
721
- }
722
420
  }
723
421
  function delPrivateCompatSync($signal, options) {
724
422
  const segments = $signal[SEGMENTS];
@@ -775,17 +473,9 @@ async function setReplaceOnSignal($signal, value) {
775
473
  value = normalizeIdFields(value, idFields, segments[1]);
776
474
  }
777
475
  if (isPublicCollection(segments[0])) {
778
- const result = await _setPublicDocReplace(segments, value);
779
- if (shouldMirrorPublicRefMutationLocally(segments)) {
780
- mirrorRefMutationFromTarget(segments, value);
781
- }
782
- return result;
476
+ return _setPublicDocReplace(segments, value);
783
477
  }
784
- const result = setReplacePrivateData(getOwningRootId($signal), segments, value);
785
- if (shouldMirrorPrivateRefMutationLocally()) {
786
- mirrorRefMutationFromTarget(segments, value);
787
- }
788
- return result;
478
+ return setReplacePrivateData(getOwningRootId($signal), segments, value);
789
479
  }
790
480
  async function incrementOnSignal($signal, byNumber) {
791
481
  const segments = $signal[SEGMENTS];
@@ -911,28 +601,6 @@ function getOwningRootId($signal) {
911
601
  const $root = getRoot($signal) || $signal;
912
602
  return $root?.[ROOT_ID];
913
603
  }
914
- function ensurePrivateRefSource($signal, methodName) {
915
- const segments = $signal?.[SEGMENTS];
916
- const collection = segments?.[0];
917
- if (typeof collection === 'string' && /^[_$]/.test(collection))
918
- return;
919
- throw Error(`${methodName} source path must be in a private collection`);
920
- }
921
- function shouldMirrorPublicRefMutationLocally(segments) {
922
- if (isSilentContextActive())
923
- return true;
924
- if (!Array.isArray(segments) || segments.length < 2)
925
- return true;
926
- // Public doc ops emit compat model events only when there is an initialized
927
- // Doc runtime (subscribed/fetched). Without runtime we must mirror immediately.
928
- const transportHash = JSON.stringify([segments[0], segments[1]]);
929
- return !docSubscriptions.hasRuntime(transportHash);
930
- }
931
- function shouldMirrorPrivateRefMutationLocally() {
932
- if (isSilentContextActive())
933
- return true;
934
- return !isModelEventsEnabled();
935
- }
936
604
  function shallowCopy(value) {
937
605
  const rawValue = raw(value);
938
606
  if (Array.isArray(rawValue))
@@ -1,10 +1,7 @@
1
- import { getRefLinks, getRefRootIds } from './refRegistry.js';
2
1
  import { isCompatEnv } from '../compatEnv.js';
3
- import { isSilentContextActive, isModelEventsSilentContextActive, runInModelEventsSilentContext } from './silentContext.js';
2
+ import { isSilentContextActive, isModelEventsSilentContextActive } from './silentContext.js';
4
3
  import { normalizeRootId } from "../rootScope.js";
5
4
  import { getRootContext, getRootContexts } from "../rootContext.js";
6
- import { setReplace as setReplaceInDataTree, del as delFromDataTree } from '../dataTree.js';
7
- import { setReplacePrivateData, delPrivateData } from '../privateData.js';
8
5
  const MODEL_EVENT_NAMES = ['change', 'all'];
9
6
  export function isModelEventsEnabled() {
10
7
  return isCompatEnv();
@@ -57,32 +54,8 @@ export function emitModelChange(path, value, prevValue, meta) {
57
54
  const eventName = meta?.eventName || 'change';
58
55
  const rootIds = getTargetRootIds(meta?.rootId);
59
56
  for (const rootId of rootIds) {
60
- const visited = new Set();
61
- const queue = [initialSegments];
62
- while (queue.length) {
63
- const segments = queue.shift();
64
- const key = segments.join('.');
65
- if (visited.has(key))
66
- continue;
67
- visited.add(key);
68
- emitForEvent(rootId, 'change', segments, value, prevValue, meta);
69
- emitForEvent(rootId, 'all', segments, value, prevValue, meta, eventName);
70
- for (const link of getRefLinks(rootId).values()) {
71
- if (!isPathPrefix(link.toSegments, segments))
72
- continue;
73
- if (link.mirrorOnly && typeof link.onChange === 'function') {
74
- link.onChange();
75
- }
76
- else if (!link.mirrorOnly) {
77
- mirrorRefAliasFromTargetSegments(rootId, link, segments, value, meta);
78
- }
79
- const suffix = segments.slice(link.toSegments.length);
80
- const nextSegments = link.fromSegments.concat(suffix);
81
- const nextKey = nextSegments.join('.');
82
- if (!visited.has(nextKey))
83
- queue.push(nextSegments);
84
- }
85
- }
57
+ emitForEvent(rootId, 'change', initialSegments, value, prevValue, meta);
58
+ emitForEvent(rootId, 'all', initialSegments, value, prevValue, meta, eventName);
86
59
  }
87
60
  }
88
61
  export function __resetModelEventsForTests() {
@@ -113,51 +86,6 @@ function splitPattern(pattern) {
113
86
  return [];
114
87
  return pattern.split('.').filter(Boolean);
115
88
  }
116
- function mirrorRefAliasFromTargetSegments(rootId, link, targetSegments, value, meta) {
117
- const suffix = targetSegments.slice(link.toSegments.length);
118
- const fromSegments = link.fromSegments.concat(suffix);
119
- const fromRootId = normalizeRootId(link.fromRootId ?? rootId);
120
- const shouldDelete = shouldDeleteMirroredPath(value, meta);
121
- runInModelEventsSilentContext(() => {
122
- if (isPrivateSegments(fromSegments)) {
123
- if (shouldDelete) {
124
- delPrivateData(fromRootId, fromSegments);
125
- }
126
- else {
127
- setReplacePrivateData(fromRootId, fromSegments, cloneValue(value));
128
- }
129
- return;
130
- }
131
- if (shouldDelete) {
132
- delFromDataTree(fromSegments);
133
- return;
134
- }
135
- setReplaceInDataTree(fromSegments, cloneValue(value));
136
- });
137
- }
138
- function isPrivateSegments(segments) {
139
- if (!Array.isArray(segments) || !segments.length)
140
- return false;
141
- return /^[_$]/.test(String(segments[0]));
142
- }
143
- function shouldDeleteMirroredPath(value, meta) {
144
- if (meta?.op === 'setReplace')
145
- return false;
146
- if (meta?.op === 'del')
147
- return true;
148
- return value === undefined;
149
- }
150
- function cloneValue(value) {
151
- if (Array.isArray(value))
152
- return value.map(cloneValue);
153
- if (value && typeof value === 'object') {
154
- const cloned = {};
155
- for (const key of Object.keys(value))
156
- cloned[key] = cloneValue(value[key]);
157
- return cloned;
158
- }
159
- return value;
160
- }
161
89
  function getModelEventRootStore(eventName, rootId, create = false) {
162
90
  return getRootContext(normalizeRootId(rootId), create)?.getModelEventStore(eventName, create);
163
91
  }
@@ -174,11 +102,7 @@ function getModelEventRootIds() {
174
102
  function getTargetRootIds(rootId) {
175
103
  if (rootId != null)
176
104
  return [normalizeRootId(rootId)];
177
- const rootIds = new Set([
178
- ...getModelEventRootIds(),
179
- ...getRefRootIds()
180
- ]);
181
- return rootIds;
105
+ return getModelEventRootIds();
182
106
  }
183
107
  function splitPath(path) {
184
108
  if (Array.isArray(path))
@@ -187,15 +111,6 @@ function splitPath(path) {
187
111
  return [];
188
112
  return String(path).split('.').filter(Boolean);
189
113
  }
190
- function isPathPrefix(prefixSegments, fullSegments) {
191
- if (prefixSegments.length > fullSegments.length)
192
- return false;
193
- for (let i = 0; i < prefixSegments.length; i++) {
194
- if (prefixSegments[i] !== fullSegments[i])
195
- return false;
196
- }
197
- return true;
198
- }
199
114
  function matchPattern(patternSegments, pathSegments) {
200
115
  function walk(patternIndex, pathIndex) {
201
116
  if (patternIndex === patternSegments.length) {
@@ -22,8 +22,6 @@ import { IS_QUERY, HASH, QUERIES } from './Query.js';
22
22
  import { AGGREGATIONS, IS_AGGREGATION, getAggregationCollectionName, getAggregationDocId } from './Aggregation.js';
23
23
  import { ROOT_FUNCTION, ROOT_ID, closeRootSignal, getRoot } from "./Root.js";
24
24
  import { getDefaultIdFields, getIdFieldsForSegments, isIdFieldPath, isPlainObject, isPublicDocPath, normalizeIdFields, prepareAddPayload, resolveAddDocId } from "./idFields.js";
25
- import { isCompatEnv } from './compatEnv.js';
26
- import { resolveRefSegmentsSafe, resolveRefSignalSafe } from './Compat/refFallback.js';
27
25
  import { runInBatch } from './batchScheduler.js';
28
26
  import { isPublicCollection } from "./signalPathKind.js";
29
27
  import { ARRAY_METHOD, DEFAULT_GETTERS, GET, GETTERS, SEGMENTS } from "./signalSymbols.js";
@@ -781,7 +779,7 @@ export const regularBindings = {
781
779
  }
782
780
  };
783
781
  const QUERY_METHODS = ['map', 'reduce', 'find', 'get', 'getIds', 'getExtra', 'fetch', 'unfetch'];
784
- const AGGREGATION_ALLOWED_METHODS = ['fetch', 'unfetch', 'ref', 'removeRef', 'refExtra', 'refIds'];
782
+ const AGGREGATION_ALLOWED_METHODS = ['fetch', 'unfetch'];
785
783
  // dot syntax always returns a child signal even if such method or property exists.
786
784
  // The method is only called when the signal is explicitly called as a function,
787
785
  // in which case we get the original method from the raw (non-proxied) parent signal
@@ -834,25 +832,6 @@ export const extremelyLateBindings = {
834
832
  const rawParent = rawSignal($parent);
835
833
  if (key in rawParent)
836
834
  return Reflect.apply(rawParent[key], $parent, argumentsList);
837
- if (isCompatEnv()) {
838
- const $resolvedParent = resolveRefSignalSafe($parent);
839
- if ($resolvedParent && $resolvedParent !== $parent) {
840
- const rawResolvedParent = rawSignal($resolvedParent);
841
- if (rawResolvedParent && key in rawResolvedParent) {
842
- return Reflect.apply(rawResolvedParent[key], $resolvedParent, argumentsList);
843
- }
844
- }
845
- else {
846
- const resolvedSegments = resolveRefSegmentsSafe(segments, (getRoot(signal) || signal)?.[ROOT_ID]);
847
- if (resolvedSegments) {
848
- const $resolvedByPath = getSignal(getRoot(signal), resolvedSegments);
849
- const rawResolvedByPath = rawSignal($resolvedByPath);
850
- if (rawResolvedByPath && key in rawResolvedByPath) {
851
- return Reflect.apply(rawResolvedByPath[key], $resolvedByPath, argumentsList);
852
- }
853
- }
854
- }
855
- }
856
835
  throw Error(ERRORS.noSignalKey($parent, key));
857
836
  },
858
837
  get(signal, key, receiver) {
@@ -27,8 +27,6 @@ async function runDispose(rootId) {
27
27
  const context = getRootContext(rootId, false);
28
28
  if (!context)
29
29
  return;
30
- stopActiveRefs(context);
31
- context.resetRefs();
32
30
  context.resetModelListeners();
33
31
  for (const transportHash of Array.from(context.queryRuntimeHashes)) {
34
32
  await querySubscriptions.destroyByRuntimeHash(transportHash, { rootId, force: true });
@@ -43,17 +41,6 @@ async function runDispose(rootId) {
43
41
  context.resetDirectDocSubscriptions();
44
42
  deleteRootContext(rootId);
45
43
  }
46
- function stopActiveRefs(context) {
47
- for (const entry of context.activeRefs.values()) {
48
- try {
49
- entry?.stop?.();
50
- }
51
- catch (err) {
52
- console.error(err);
53
- }
54
- }
55
- context.resetActiveRefs();
56
- }
57
44
  export function __resetPendingRootDisposesForTests() {
58
45
  PENDING_DISPOSES.clear();
59
46
  }
@@ -10,7 +10,7 @@ export interface GetSignalOptions {
10
10
  }
11
11
  declare const PROXIES_CACHE: Cache<RootSignalRuntime>;
12
12
  export default function getSignal($root?: RootSignalRuntime, segments?: PathSegment[], { useExtremelyLateBindings, rootId, signalHash, proxyHandlers }?: GetSignalOptions): RootSignalRuntime;
13
- export declare function getSignalClass(segments: PathSegment[], rootId?: string): SignalModelConstructor;
13
+ export declare function getSignalClass(segments: PathSegment[], _rootId?: string): SignalModelConstructor;
14
14
  export declare function rawSignal(proxy: unknown): RootSignalRuntime | undefined;
15
15
  export { PROXIES_CACHE as __DEBUG_SIGNALS_CACHE__ };
16
16
  export declare function purgeSignalHashes(hashes: Iterable<string>): void;
@@ -5,8 +5,6 @@ import { LOCAL } from './$.js';
5
5
  import { ROOT, ROOT_ID, GLOBAL_ROOT_ID } from "./Root.js";
6
6
  import { QUERIES } from './Query.js';
7
7
  import { AGGREGATIONS } from './Aggregation.js';
8
- import { isCompatEnv } from './compatEnv.js';
9
- import { resolveRefSegmentsSafe } from './Compat/refFallback.js';
10
8
  import { getSignalIdentityHash } from "./rootScope.js";
11
9
  import { isRootContextClosed, registerRootOwnedSignalHash } from "./rootContext.js";
12
10
  const PROXIES_CACHE = new Cache();
@@ -81,18 +79,10 @@ export default function getSignal($root, segments = [], { useExtremelyLateBindin
81
79
  function getDefaultProxyHandlers({ useExtremelyLateBindings } = {}) {
82
80
  return (useExtremelyLateBindings ? extremelyLateBindings : regularBindings);
83
81
  }
84
- export function getSignalClass(segments, rootId = GLOBAL_ROOT_ID) {
85
- let Model = findModel(segments);
82
+ export function getSignalClass(segments, _rootId = GLOBAL_ROOT_ID) {
83
+ const Model = findModel(segments);
86
84
  if (Model)
87
85
  return Model;
88
- if (!isCompatEnv())
89
- return Signal;
90
- const dereferencedSegments = resolveRefSegmentsSafe(segments, rootId);
91
- if (dereferencedSegments) {
92
- Model = findModel(dereferencedSegments);
93
- if (Model)
94
- return Model;
95
- }
96
86
  return Signal;
97
87
  }
98
88
  export function rawSignal(proxy) {
@@ -3,9 +3,6 @@ type RootId = string | null | undefined;
3
3
  type DataTree = Record<string | number, unknown>;
4
4
  type RuntimeKind = 'query' | 'aggregation';
5
5
  type ModelEventStore = Map<string, unknown>;
6
- type ActiveRefEntry = {
7
- stop?: () => void;
8
- };
9
6
  interface RootContextOptions {
10
7
  fetchOnly?: boolean;
11
8
  }
@@ -24,8 +21,6 @@ export default class RootContext {
24
21
  fetchOnly: boolean;
25
22
  privateDataRaw: DataTree;
26
23
  privateData: DataTree;
27
- readonly refLinks: Map<string, unknown>;
28
- readonly activeRefs: Map<string, ActiveRefEntry>;
29
24
  readonly modelListeners: ModelListeners;
30
25
  readonly queryRuntimeHashes: Set<string>;
31
26
  readonly aggregationRuntimeHashes: Set<string>;
@@ -48,8 +43,6 @@ export default class RootContext {
48
43
  unregisterSignalHash(signalHash: string | null | undefined): void;
49
44
  registerDirectDocSubscription(hash: string | null | undefined, segments: readonly PathSegment[], token?: unknown): void;
50
45
  unregisterDirectDocSubscription(hash: string | null | undefined, token?: unknown): void;
51
- resetRefs(): void;
52
- resetActiveRefs(): void;
53
46
  resetModelListeners(): void;
54
47
  resetRuntimeHashes(): void;
55
48
  resetPrivateData(): void;
@@ -12,8 +12,6 @@ export default class RootContext {
12
12
  fetchOnly;
13
13
  privateDataRaw;
14
14
  privateData;
15
- refLinks = new Map();
16
- activeRefs = new Map();
17
15
  modelListeners = {
18
16
  change: new Map(),
19
17
  all: new Map()
@@ -124,12 +122,6 @@ export default class RootContext {
124
122
  if (entry.count === 0)
125
123
  this.directDocSubscriptions.delete(hash);
126
124
  }
127
- resetRefs() {
128
- this.refLinks.clear();
129
- }
130
- resetActiveRefs() {
131
- this.activeRefs.clear();
132
- }
133
125
  resetModelListeners() {
134
126
  for (const store of Object.values(this.modelListeners)) {
135
127
  store.clear();
@@ -151,8 +143,6 @@ export default class RootContext {
151
143
  }
152
144
  isRuntimeEmpty() {
153
145
  return (isPlainObjectEmpty(this.privateData) &&
154
- this.refLinks.size === 0 &&
155
- this.activeRefs.size === 0 &&
156
146
  Object.values(this.modelListeners).every(store => store.size === 0) &&
157
147
  this.queryRuntimeHashes.size === 0 &&
158
148
  this.aggregationRuntimeHashes.size === 0 &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamplay",
3
- "version": "0.5.0-alpha.33",
3
+ "version": "0.5.0-alpha.35",
4
4
  "description": "Full-stack signals ORM with multiplayer",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -138,6 +138,5 @@
138
138
  "<rootDir>/test_client/helpers"
139
139
  ]
140
140
  },
141
- "license": "MIT",
142
- "gitHead": "5355598efe68ec4d94d0a08b0450a1bd35358caa"
141
+ "license": "MIT"
143
142
  }
@@ -1,13 +0,0 @@
1
- import type { PathSegment } from '../types/path.js'
2
- import type { SignalBaseInstance } from '../Signal.js'
3
-
4
- export const REF_TARGET: unique symbol
5
- export function resolveRefSignalSafe<TSignal extends SignalBaseInstance> (
6
- $signal: TSignal | undefined,
7
- maxDepth?: number
8
- ): TSignal | undefined
9
- export function resolveRefSegmentsSafe (
10
- segments: readonly PathSegment[],
11
- rootId?: string,
12
- maxDepth?: number
13
- ): PathSegment[] | undefined
@@ -1,65 +0,0 @@
1
- import { getRefLinks } from './refRegistry.js';
2
- import { GLOBAL_ROOT_ID } from "../Root.js";
3
- export const REF_TARGET = Symbol.for('teamplay.compat.refTarget');
4
- export function resolveRefSignalSafe($signal, maxDepth = 32) {
5
- let current = $signal;
6
- const seen = new Set();
7
- for (let i = 0; i < maxDepth; i++) {
8
- if (!current)
9
- return undefined;
10
- const next = current[REF_TARGET];
11
- if (!next)
12
- return current;
13
- if (seen.has(current))
14
- return undefined;
15
- seen.add(current);
16
- current = next;
17
- }
18
- return undefined;
19
- }
20
- export function resolveRefSegmentsSafe(segments, rootId = GLOBAL_ROOT_ID, maxDepth = 32) {
21
- if (!Array.isArray(segments) || segments.length === 0)
22
- return undefined;
23
- let current = [...segments];
24
- const visited = new Set([toPathKey(current)]);
25
- let changed = false;
26
- for (let i = 0; i < maxDepth; i++) {
27
- const link = findBestMatchingLink(current, rootId);
28
- if (!link)
29
- return changed ? current : undefined;
30
- const suffix = current.slice(link.fromSegments.length);
31
- const next = link.toSegments.concat(suffix);
32
- const key = toPathKey(next);
33
- if (visited.has(key))
34
- return undefined;
35
- visited.add(key);
36
- current = next;
37
- changed = true;
38
- }
39
- return undefined;
40
- }
41
- function findBestMatchingLink(segments, rootId) {
42
- let best;
43
- for (const link of getRefLinks(rootId).values()) {
44
- if (link.mirrorOnly)
45
- continue;
46
- if (!isPathPrefix(link.fromSegments, segments))
47
- continue;
48
- if (!best || link.fromSegments.length > best.fromSegments.length) {
49
- best = link;
50
- }
51
- }
52
- return best;
53
- }
54
- function isPathPrefix(prefixSegments, fullSegments) {
55
- if (prefixSegments.length > fullSegments.length)
56
- return false;
57
- for (let i = 0; i < prefixSegments.length; i++) {
58
- if (prefixSegments[i] !== String(fullSegments[i]))
59
- return false;
60
- }
61
- return true;
62
- }
63
- function toPathKey(segments) {
64
- return segments.map(segment => String(segment)).join('.');
65
- }
@@ -1,6 +0,0 @@
1
- export function setRefLink(rootId: any, fromPath: any, toPath: any, fromSegments: any, toSegments: any, options?: {}): void;
2
- export function removeRefLink(rootId: any, fromPath: any): void;
3
- export function getRefLinks(rootId?: string): Map<string, unknown>;
4
- export function getAllRefLinks(): Generator<unknown, void, unknown>;
5
- export function getRefRootIds(): string[];
6
- export function __resetRefLinksForTests(): void;
@@ -1,54 +0,0 @@
1
- import { GLOBAL_ROOT_ID } from "../Root.js";
2
- import { normalizeRootId } from "../rootScope.js";
3
- import { getRootContext, getRootContexts } from "../rootContext.js";
4
- const EMPTY_MAP = new Map();
5
- export function setRefLink(rootId, fromPath, toPath, fromSegments, toSegments, options = {}) {
6
- if (typeof fromPath !== 'string' || typeof toPath !== 'string')
7
- return;
8
- const normalizedFromSegments = Array.isArray(fromSegments)
9
- ? fromSegments.map(segment => String(segment))
10
- : splitPath(fromPath);
11
- const normalizedToSegments = Array.isArray(toSegments)
12
- ? toSegments.map(segment => String(segment))
13
- : splitPath(toPath);
14
- getRefStore(rootId, true).set(fromPath, {
15
- fromPath,
16
- toPath,
17
- fromSegments: normalizedFromSegments,
18
- toSegments: normalizedToSegments,
19
- fromRootId: normalizeRootId(rootId),
20
- toRootId: options.toRootId,
21
- mirrorOnly: !!options.mirrorOnly,
22
- onChange: typeof options.onChange === 'function' ? options.onChange : undefined
23
- });
24
- }
25
- export function removeRefLink(rootId, fromPath) {
26
- const store = getRefStore(rootId);
27
- if (!store)
28
- return;
29
- store.delete(fromPath);
30
- }
31
- export function getRefLinks(rootId = GLOBAL_ROOT_ID) {
32
- return getRefStore(rootId) || EMPTY_MAP;
33
- }
34
- export function* getAllRefLinks() {
35
- for (const context of getRootContexts()) {
36
- yield* context.refLinks.values();
37
- }
38
- }
39
- export function getRefRootIds() {
40
- return Array.from(getRootContexts())
41
- .filter(context => context.refLinks.size > 0)
42
- .map(context => context.rootId);
43
- }
44
- export function __resetRefLinksForTests() {
45
- for (const context of getRootContexts()) {
46
- context.resetRefs();
47
- }
48
- }
49
- function splitPath(path) {
50
- return path.split('.').filter(Boolean);
51
- }
52
- function getRefStore(rootId, create = false) {
53
- return getRootContext(normalizeRootId(rootId), create)?.refLinks;
54
- }