teamplay 0.5.0-alpha.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +3 -3
  2. package/dist/config.d.ts +2 -0
  3. package/dist/config.js +1 -0
  4. package/dist/connect/index.d.ts +1 -1
  5. package/dist/connect/index.js +6 -2
  6. package/dist/connect/offline/index.d.ts +1 -1
  7. package/dist/connect/offline/index.js +8 -4
  8. package/dist/connect/offline/react-native.d.ts +1 -1
  9. package/dist/connect/offline/web.d.ts +1 -1
  10. package/dist/connect/test.d.ts +1 -1
  11. package/dist/connect/test.js +5 -1
  12. package/dist/index.d.ts +9 -5
  13. package/dist/index.js +6 -5
  14. package/dist/orm/$.js +1 -1
  15. package/dist/orm/Aggregation.d.ts +5 -3
  16. package/dist/orm/Aggregation.js +39 -15
  17. package/dist/orm/Doc.js +0 -55
  18. package/dist/orm/Query.d.ts +1 -0
  19. package/dist/orm/Query.js +25 -82
  20. package/dist/orm/Root.d.ts +4 -0
  21. package/dist/orm/Root.js +16 -0
  22. package/dist/orm/Signal.d.ts +0 -2
  23. package/dist/orm/Signal.js +1 -4
  24. package/dist/orm/SignalBase.d.ts +21 -1
  25. package/dist/orm/SignalBase.js +259 -56
  26. package/dist/orm/batchScheduler.d.ts +7 -7
  27. package/dist/orm/connection.d.ts +0 -4
  28. package/dist/orm/connection.js +0 -12
  29. package/dist/orm/dataTree.d.ts +12 -12
  30. package/dist/orm/dataTree.js +55 -107
  31. package/dist/orm/disposeRootContext.js +0 -14
  32. package/dist/orm/events.d.ts +6 -0
  33. package/dist/orm/events.js +48 -0
  34. package/dist/orm/getSignal.d.ts +1 -1
  35. package/dist/orm/getSignal.js +4 -33
  36. package/dist/orm/idFields.d.ts +10 -1
  37. package/dist/orm/idFields.js +102 -14
  38. package/dist/orm/index.d.ts +2 -0
  39. package/dist/orm/index.js +1 -0
  40. package/dist/orm/initModels.js +1 -1
  41. package/dist/orm/privateData.d.ts +7 -22
  42. package/dist/orm/privateData.js +20 -1
  43. package/dist/orm/queryReadiness.d.ts +13 -0
  44. package/dist/orm/{Compat/queryReadiness.js → queryReadiness.js} +10 -10
  45. package/dist/orm/reaction.d.ts +11 -0
  46. package/dist/orm/reaction.js +47 -0
  47. package/dist/orm/rootContext.d.ts +0 -16
  48. package/dist/orm/rootContext.js +0 -28
  49. package/dist/orm/signalMetadata.js +3 -3
  50. package/dist/orm/signalReads.js +3 -9
  51. package/dist/orm/signalStorageMutations.d.ts +0 -2
  52. package/dist/orm/signalStorageMutations.js +0 -9
  53. package/dist/orm/signalSymbols.js +1 -1
  54. package/dist/orm/signalValueMutations.d.ts +1 -1
  55. package/dist/orm/signalValueMutations.js +0 -3
  56. package/dist/orm/sub.d.ts +12 -7
  57. package/dist/orm/sub.js +87 -30
  58. package/dist/orm/subscriptionGcDelay.js +2 -6
  59. package/dist/react/convertToObserver.js +1 -4
  60. package/dist/react/promiseBatcher.js +1 -1
  61. package/dist/react/renderAttemptDestroyer.d.ts +0 -8
  62. package/dist/react/renderAttemptDestroyer.js +2 -28
  63. package/dist/react/trapRender.js +3 -3
  64. package/dist/react/useSub.d.ts +86 -5
  65. package/dist/react/useSub.js +191 -32
  66. package/dist/react/useSuspendMemo.js +1 -5
  67. package/dist/server.d.ts +2 -3
  68. package/dist/server.js +5 -3
  69. package/package.json +16 -14
  70. package/dist/orm/Compat/SignalCompat.d.ts +0 -3
  71. package/dist/orm/Compat/SignalCompat.js +0 -1267
  72. package/dist/orm/Compat/eventsCompat.d.ts +0 -3
  73. package/dist/orm/Compat/eventsCompat.js +0 -73
  74. package/dist/orm/Compat/hooksCompat.d.ts +0 -33
  75. package/dist/orm/Compat/hooksCompat.js +0 -360
  76. package/dist/orm/Compat/modelEvents.d.ts +0 -6
  77. package/dist/orm/Compat/modelEvents.js +0 -228
  78. package/dist/orm/Compat/queryReadiness.d.ts +0 -5
  79. package/dist/orm/Compat/refFallback.d.ts +0 -13
  80. package/dist/orm/Compat/refFallback.js +0 -65
  81. package/dist/orm/Compat/refRegistry.d.ts +0 -6
  82. package/dist/orm/Compat/refRegistry.js +0 -54
  83. package/dist/orm/Compat/silentContext.d.ts +0 -5
  84. package/dist/orm/Compat/silentContext.js +0 -48
  85. package/dist/orm/Compat/startStopCompat.d.ts +0 -3
  86. package/dist/orm/Compat/startStopCompat.js +0 -217
  87. package/dist/orm/compatEnv.d.ts +0 -1
  88. package/dist/orm/compatEnv.js +0 -4
  89. package/dist/react/compatComponentRegistry.d.ts +0 -4
  90. package/dist/react/compatComponentRegistry.js +0 -19
  91. /package/dist/orm/{Reaction.d.ts → reactionSubscriptions.d.ts} +0 -0
  92. /package/dist/orm/{Reaction.js → reactionSubscriptions.js} +0 -0
@@ -4,9 +4,6 @@ import diffMatchPatch from 'diff-match-patch';
4
4
  import { getConnection } from "./connection.js";
5
5
  import setDiffDeep from '../utils/setDiffDeep.js';
6
6
  import { getIdFieldsForSegments, injectIdFields, stripIdFields, isPlainObject, isIdFieldPath } from "./idFields.js";
7
- import { emitModelChange, isModelEventsEnabled } from './Compat/modelEvents.js';
8
- import { isSilentContextActive } from './Compat/silentContext.js';
9
- import { isCompatEnv } from './compatEnv.js';
10
7
  import { isMissingShareDoc } from './missingDoc.js';
11
8
  import { getLogicalRootSnapshot as getLogicalRootSnapshotFromTree } from "./rootScope.js";
12
9
  import { getRootContext } from "./rootContext.js";
@@ -15,8 +12,6 @@ const ALLOW_PARTIAL_DOC_CREATION = false;
15
12
  export const dataTreeRaw = {};
16
13
  const dataTree = observable(dataTreeRaw);
17
14
  function getWritableTree(tree) {
18
- if (isSilentContextActive())
19
- return getTreeRaw(tree);
20
15
  return tree;
21
16
  }
22
17
  function getTreeRaw(tree) {
@@ -24,22 +19,6 @@ function getTreeRaw(tree) {
24
19
  return dataTreeRaw;
25
20
  return raw(tree) || tree;
26
21
  }
27
- function shouldEmitModelEvents(tree, eventContext) {
28
- return (tree === dataTree || eventContext?.rootId != null) &&
29
- isModelEventsEnabled() &&
30
- !isSilentContextActive();
31
- }
32
- function emitModelEvent(segments, prevValue, meta, tree = dataTree, eventContext) {
33
- if (!shouldEmitModelEvents(tree, eventContext))
34
- return;
35
- const treeRaw = getTreeRaw(tree);
36
- const value = get(segments, treeRaw);
37
- const logicalSegments = eventContext?.logicalSegments || segments;
38
- const modelEventMeta = eventContext?.rootId != null
39
- ? { ...meta, rootId: eventContext.rootId }
40
- : meta;
41
- emitModelChange(logicalSegments, value, prevValue, modelEventMeta);
42
- }
43
22
  export function resolveStorageSegments(rootId, logicalSegments) {
44
23
  return logicalSegments;
45
24
  }
@@ -59,10 +38,8 @@ export function get(segments, tree = dataTree) {
59
38
  export function getRaw(segments) {
60
39
  return get(segments, dataTreeRaw);
61
40
  }
62
- export function set(segments, value, tree = dataTree, eventContext) {
41
+ export function set(segments, value, tree = dataTree) {
63
42
  const writableTree = getWritableTree(tree);
64
- const shouldEmit = shouldEmitModelEvents(tree, eventContext);
65
- const prevValue = shouldEmit ? get(segments, getTreeRaw(tree)) : undefined;
66
43
  let dataNode = writableTree;
67
44
  let dataNodeRaw = getTreeRaw(writableTree);
68
45
  for (let i = 0; i < segments.length - 1; i++) {
@@ -87,7 +64,6 @@ export function set(segments, value, tree = dataTree, eventContext) {
87
64
  return;
88
65
  if (value == null || typeof value !== 'object') {
89
66
  dataNode[key] = value;
90
- emitModelEvent(segments, prevValue, { op: 'set' }, tree, eventContext);
91
67
  return;
92
68
  }
93
69
  // instead of just setting the new value `dataNode[key] = value` we want
@@ -97,7 +73,6 @@ export function set(segments, value, tree = dataTree, eventContext) {
97
73
  // (we just set it to this value)
98
74
  if (dataNode[key] !== newValue)
99
75
  dataNode[key] = newValue;
100
- emitModelEvent(segments, prevValue, { op: 'set' }, tree, eventContext);
101
76
  }
102
77
  function hasOwnDataKey(node, key) {
103
78
  if (node == null)
@@ -107,10 +82,8 @@ function hasOwnDataKey(node, key) {
107
82
  return Object.prototype.hasOwnProperty.call(node, key);
108
83
  }
109
84
  // Like set(), but always assigns the value without equality checks or delete-on-null behavior
110
- export function setReplace(segments, value, tree = dataTree, eventContext) {
85
+ export function setReplace(segments, value, tree = dataTree) {
111
86
  const writableTree = getWritableTree(tree);
112
- const shouldEmit = shouldEmitModelEvents(tree, eventContext);
113
- const prevValue = shouldEmit ? get(segments, getTreeRaw(tree)) : undefined;
114
87
  let dataNode = writableTree;
115
88
  for (let i = 0; i < segments.length - 1; i++) {
116
89
  const segment = segments[i];
@@ -127,12 +100,9 @@ export function setReplace(segments, value, tree = dataTree, eventContext) {
127
100
  }
128
101
  const key = segments[segments.length - 1];
129
102
  dataNode[key] = value;
130
- emitModelEvent(segments, prevValue, { op: 'setReplace' }, tree, eventContext);
131
103
  }
132
- export function del(segments, tree = dataTree, eventContext) {
104
+ export function del(segments, tree = dataTree) {
133
105
  const writableTree = getWritableTree(tree);
134
- const shouldEmit = shouldEmitModelEvents(tree, eventContext);
135
- const prevValue = shouldEmit ? get(segments, getTreeRaw(tree)) : undefined;
136
106
  let dataNode = writableTree;
137
107
  for (let i = 0; i < segments.length - 1; i++) {
138
108
  const segment = segments[i];
@@ -154,7 +124,6 @@ export function del(segments, tree = dataTree, eventContext) {
154
124
  return;
155
125
  delete dataNode[key];
156
126
  }
157
- emitModelEvent(segments, prevValue, { op: 'del' }, tree, eventContext);
158
127
  }
159
128
  export async function setPublicDoc(segments, value, deleteValue = false) {
160
129
  if (segments.length === 0)
@@ -178,18 +147,18 @@ export async function setPublicDoc(segments, value, deleteValue = false) {
178
147
  if (isIdFieldPath(segments, idFields))
179
148
  return;
180
149
  const doc = getConnection().get(collection, docId);
181
- let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompatDocData: true });
150
+ let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal: true });
182
151
  if (!docState.exists && segments.length > 2) {
183
- docState = await resolvePublicDocStateWithCompatFetchFallback({
152
+ docState = await resolvePublicDocStateWithLocalRecovery({
184
153
  collection,
185
154
  docId,
186
155
  doc,
187
156
  idFields,
188
- hydrateCompatDocData: true
157
+ hydrateDocDataFromLocal: true
189
158
  });
190
159
  }
191
160
  if (!docState.exists && deleteValue)
192
- throw Error(ERRORS.deleteNonExistentDoc(segments));
161
+ return;
193
162
  // make sure that the value is not observable to not trigger extra reads. And clone it
194
163
  value = raw(value);
195
164
  if (value == null) {
@@ -286,14 +255,14 @@ export async function setPublicDocReplace(segments, value) {
286
255
  if (isIdFieldPath(segments, idFields))
287
256
  return;
288
257
  const doc = getConnection().get(collection, docId);
289
- let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompatDocData: true });
258
+ let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal: true });
290
259
  if (!docState.exists && segments.length > 2) {
291
- docState = await resolvePublicDocStateWithCompatFetchFallback({
260
+ docState = await resolvePublicDocStateWithLocalRecovery({
292
261
  collection,
293
262
  docId,
294
263
  doc,
295
264
  idFields,
296
- hydrateCompatDocData: true
265
+ hydrateDocDataFromLocal: true
297
266
  });
298
267
  }
299
268
  // make sure that the value is not observable to not trigger extra reads. And clone it
@@ -336,7 +305,7 @@ export async function setPublicDocReplace(segments, value) {
336
305
  }
337
306
  const relativePath = segments.slice(2);
338
307
  // json0 direct replace ops require every ancestor container to already exist.
339
- // Racer-like compat set, however, materializes missing/primitive parents while
308
+ // setPublicDoc() materializes missing/primitive parents while
340
309
  // descending into the path. Fall back to the older diff-based path when the
341
310
  // direct op would target a non-existent/non-object ancestor.
342
311
  if (!canApplyDirectReplaceOp(docState.snapshot || {}, relativePath)) {
@@ -374,9 +343,10 @@ async function createPublicDocAndHydrateLocal({ doc, collection, docId, newDoc,
374
343
  await new Promise((resolve, reject) => {
375
344
  doc.create(newDoc, err => err ? reject(err) : resolve());
376
345
  });
377
- // In compatibility mode we must allow immediate subpath writes after create()
378
- // even when the ShareDB snapshot hasn't been loaded via subscribe/fetch yet.
379
- if (isCompatEnv() && doc?.data == null) {
346
+ // Keep public creates immediately writable even when the ShareDB snapshot has
347
+ // not been loaded via subscribe/fetch yet. UI flows rely on optimistic add()
348
+ // followed by child writes without waiting for DB confirmation.
349
+ if (doc?.data == null) {
380
350
  const localDoc = JSON.parse(JSON.stringify(newDoc || {}));
381
351
  if (isPlainObject(localDoc))
382
352
  injectIdFields(localDoc, idFields, docId);
@@ -387,7 +357,7 @@ async function createPublicDocAndHydrateLocal({ doc, collection, docId, newDoc,
387
357
  }
388
358
  ensureLocalDocSyncedWithShareDoc({ collection, docId, doc, idFields });
389
359
  }
390
- function resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompatDocData = false }) {
360
+ function resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal = false }) {
391
361
  ensureLocalDocSyncedWithShareDoc({ collection, docId, doc, idFields });
392
362
  if (isMissingShareDoc(doc)) {
393
363
  return { exists: false, snapshot: undefined, source: 'none' };
@@ -400,24 +370,29 @@ function resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompat
400
370
  };
401
371
  }
402
372
  const localSnapshot = getRaw([collection, docId]);
403
- if (!(isCompatEnv() && localSnapshot != null)) {
373
+ if (localSnapshot == null) {
404
374
  return { exists: false, snapshot: undefined, source: 'none' };
405
375
  }
406
- // In compat mode local raw data can be the source of truth between create/add
407
- // and later subpath mutations even if ShareDB doc.data is currently empty.
408
- if (hydrateCompatDocData) {
376
+ // Local raw data can be the source of truth between add() and later subpath
377
+ // mutations even if ShareDB doc.data is currently empty or was recreated.
378
+ if (hydrateDocDataFromLocal) {
409
379
  doc.data = localSnapshot;
410
380
  }
411
381
  return { exists: true, snapshot: localSnapshot, source: 'local' };
412
382
  }
413
- async function resolvePublicDocStateWithCompatFetchFallback({ collection, docId, doc, idFields, hydrateCompatDocData = false }) {
414
- let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompatDocData });
415
- if (docState.exists || !isCompatEnv())
383
+ async function resolvePublicDocStateWithLocalRecovery({ collection, docId, doc, idFields, hydrateDocDataFromLocal = false }) {
384
+ let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal });
385
+ if (docState.exists)
386
+ return docState;
387
+ const shouldFetch = getRaw([collection, docId]) != null &&
388
+ isMissingShareDoc(doc) &&
389
+ doc.version == null;
390
+ if (!shouldFetch)
416
391
  return docState;
417
392
  await new Promise((resolve, reject) => {
418
393
  doc.fetch(err => err ? reject(err) : resolve());
419
394
  });
420
- docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompatDocData });
395
+ docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal });
421
396
  return docState;
422
397
  }
423
398
  function ensureLocalDocSyncedWithShareDoc({ collection, docId, doc, idFields }) {
@@ -500,56 +475,38 @@ function getArrayNode(segments, tree = dataTree, create = true) {
500
475
  }
501
476
  return dataNode;
502
477
  }
503
- export function arrayPush(segments, value, tree = dataTree, eventContext) {
478
+ export function arrayPush(segments, value, tree = dataTree) {
504
479
  const arr = getArrayNode(segments, tree, true);
505
- const index = arr.length;
506
- const result = arr.push(value);
507
- emitModelEvent(segments.concat(index), undefined, { op: 'arrayPush', index }, tree, eventContext);
508
- return result;
480
+ return arr.push(value);
509
481
  }
510
- export function arrayUnshift(segments, value, tree = dataTree, eventContext) {
482
+ export function arrayUnshift(segments, value, tree = dataTree) {
511
483
  const arr = getArrayNode(segments, tree, true);
512
- const result = arr.unshift(value);
513
- emitModelEvent(segments.concat(0), undefined, { op: 'arrayUnshift', index: 0 }, tree, eventContext);
514
- return result;
484
+ return arr.unshift(value);
515
485
  }
516
- export function arrayInsert(segments, index, values, tree = dataTree, eventContext) {
486
+ export function arrayInsert(segments, index, values, tree = dataTree) {
517
487
  const arr = getArrayNode(segments, tree, true);
518
488
  const inserted = Array.isArray(values) ? values : [values];
519
489
  arr.splice(index, 0, ...inserted);
520
- for (let i = 0; i < inserted.length; i++) {
521
- emitModelEvent(segments.concat(index + i), undefined, { op: 'arrayInsert', index: index + i }, tree, eventContext);
522
- }
523
490
  return arr.length;
524
491
  }
525
- export function arrayPop(segments, tree = dataTree, eventContext) {
492
+ export function arrayPop(segments, tree = dataTree) {
526
493
  const arr = getArrayNode(segments, tree, true);
527
494
  if (!arr.length)
528
495
  return;
529
- const index = arr.length - 1;
530
- const previous = arr.pop();
531
- emitModelEvent(segments.concat(index), previous, { op: 'arrayPop', index }, tree, eventContext);
532
- return previous;
496
+ return arr.pop();
533
497
  }
534
- export function arrayShift(segments, tree = dataTree, eventContext) {
498
+ export function arrayShift(segments, tree = dataTree) {
535
499
  const arr = getArrayNode(segments, tree, true);
536
500
  if (!arr.length)
537
501
  return;
538
- const previous = arr.shift();
539
- emitModelEvent(segments.concat(0), previous, { op: 'arrayShift', index: 0 }, tree, eventContext);
540
- return previous;
502
+ return arr.shift();
541
503
  }
542
- export function arrayRemove(segments, index, howMany = 1, tree = dataTree, eventContext) {
504
+ export function arrayRemove(segments, index, howMany = 1, tree = dataTree) {
543
505
  const arr = getArrayNode(segments, tree, true);
544
- const removed = arr.splice(index, howMany);
545
- for (let i = 0; i < removed.length; i++) {
546
- emitModelEvent(segments.concat(index + i), removed[i], { op: 'arrayRemove', index: index + i, howMany }, tree, eventContext);
547
- }
548
- return removed;
506
+ return arr.splice(index, howMany);
549
507
  }
550
- export function arrayMove(segments, from, to, howMany = 1, tree = dataTree, eventContext) {
508
+ export function arrayMove(segments, from, to, howMany = 1, tree = dataTree) {
551
509
  const arr = getArrayNode(segments, tree, true);
552
- const prevValue = shouldEmitModelEvents(tree, eventContext) ? arr.slice() : undefined;
553
510
  const len = arr.length;
554
511
  if (from < 0)
555
512
  from += len;
@@ -557,7 +514,6 @@ export function arrayMove(segments, from, to, howMany = 1, tree = dataTree, even
557
514
  to += len;
558
515
  const moved = arr.splice(from, howMany);
559
516
  arr.splice(to, 0, ...moved);
560
- emitModelEvent(segments, prevValue, { op: 'arrayMove', from, to, howMany }, tree, eventContext);
561
517
  return moved;
562
518
  }
563
519
  export async function incrementPublic(segments, byNumber) {
@@ -572,12 +528,12 @@ export async function incrementPublic(segments, byNumber) {
572
528
  throw Error(ERRORS.publicDoc(segments));
573
529
  const doc = getConnection().get(collection, docId);
574
530
  const idFields = getIdFieldsForSegments([collection, docId]);
575
- const docState = await resolvePublicDocStateWithCompatFetchFallback({
531
+ const docState = await resolvePublicDocStateWithLocalRecovery({
576
532
  collection,
577
533
  docId,
578
534
  doc,
579
535
  idFields,
580
- hydrateCompatDocData: true
536
+ hydrateDocDataFromLocal: true
581
537
  });
582
538
  if (!docState.exists)
583
539
  throw Error(ERRORS.nonExistingDoc(segments));
@@ -615,12 +571,12 @@ export async function arrayInsertPublic(segments, index, values) {
615
571
  throw Error(ERRORS.publicDoc(segments));
616
572
  const doc = getConnection().get(collection, docId);
617
573
  const idFields = getIdFieldsForSegments([collection, docId]);
618
- const docState = await resolvePublicDocStateWithCompatFetchFallback({
574
+ const docState = await resolvePublicDocStateWithLocalRecovery({
619
575
  collection,
620
576
  docId,
621
577
  doc,
622
578
  idFields,
623
- hydrateCompatDocData: true
579
+ hydrateDocDataFromLocal: true
624
580
  });
625
581
  if (!docState.exists)
626
582
  throw Error(ERRORS.nonExistingDoc(segments));
@@ -674,12 +630,12 @@ export async function arrayRemovePublic(segments, index, howMany = 1) {
674
630
  throw Error(ERRORS.publicDoc(segments));
675
631
  const doc = getConnection().get(collection, docId);
676
632
  const idFields = getIdFieldsForSegments([collection, docId]);
677
- const docState = await resolvePublicDocStateWithCompatFetchFallback({
633
+ const docState = await resolvePublicDocStateWithLocalRecovery({
678
634
  collection,
679
635
  docId,
680
636
  doc,
681
637
  idFields,
682
- hydrateCompatDocData: true
638
+ hydrateDocDataFromLocal: true
683
639
  });
684
640
  if (!docState.exists)
685
641
  throw Error(ERRORS.nonExistingDoc(segments));
@@ -702,12 +658,12 @@ export async function arrayMovePublic(segments, from, to, howMany = 1) {
702
658
  throw Error(ERRORS.publicDoc(segments));
703
659
  const doc = getConnection().get(collection, docId);
704
660
  const idFields = getIdFieldsForSegments([collection, docId]);
705
- const docState = await resolvePublicDocStateWithCompatFetchFallback({
661
+ const docState = await resolvePublicDocStateWithLocalRecovery({
706
662
  collection,
707
663
  docId,
708
664
  doc,
709
665
  idFields,
710
- hydrateCompatDocData: true
666
+ hydrateDocDataFromLocal: true
711
667
  });
712
668
  if (!docState.exists)
713
669
  throw Error(ERRORS.nonExistingDoc(segments));
@@ -726,7 +682,7 @@ export async function arrayMovePublic(segments, from, to, howMany = 1) {
726
682
  doc.submitOp(op, err => err ? reject(err) : resolve(moved));
727
683
  });
728
684
  }
729
- export function stringInsertLocal(segments, index, text, tree = dataTree, eventContext) {
685
+ export function stringInsertLocal(segments, index, text, tree = dataTree) {
730
686
  let dataNode = getWritableTree(tree);
731
687
  for (let i = 0; i < segments.length - 1; i++) {
732
688
  const segment = segments[i];
@@ -739,17 +695,15 @@ export function stringInsertLocal(segments, index, text, tree = dataTree, eventC
739
695
  const previous = dataNode[key];
740
696
  if (previous == null) {
741
697
  dataNode[key] = text;
742
- emitModelEvent(segments, previous, { op: 'stringInsert', index }, tree, eventContext);
743
698
  return previous;
744
699
  }
745
700
  if (typeof previous !== 'string') {
746
701
  throw Error(`Expected string at ${segments.join('.')}`);
747
702
  }
748
703
  dataNode[key] = previous.slice(0, index) + text + previous.slice(index);
749
- emitModelEvent(segments, previous, { op: 'stringInsert', index }, tree, eventContext);
750
704
  return previous;
751
705
  }
752
- export function stringRemoveLocal(segments, index, howMany, tree = dataTree, eventContext) {
706
+ export function stringRemoveLocal(segments, index, howMany, tree = dataTree) {
753
707
  let dataNode = getWritableTree(tree);
754
708
  for (let i = 0; i < segments.length - 1; i++) {
755
709
  const segment = segments[i];
@@ -765,7 +719,6 @@ export function stringRemoveLocal(segments, index, howMany, tree = dataTree, eve
765
719
  throw Error(`Expected string at ${segments.join('.')}`);
766
720
  }
767
721
  dataNode[key] = previous.slice(0, index) + previous.slice(index + howMany);
768
- emitModelEvent(segments, previous, { op: 'stringRemove', index, howMany }, tree, eventContext);
769
722
  return previous;
770
723
  }
771
724
  export async function stringInsertPublic(segments, index, text) {
@@ -780,12 +733,12 @@ export async function stringInsertPublic(segments, index, text) {
780
733
  throw Error(ERRORS.publicDoc(segments));
781
734
  const doc = getConnection().get(collection, docId);
782
735
  const idFields = getIdFieldsForSegments([collection, docId]);
783
- const docState = await resolvePublicDocStateWithCompatFetchFallback({
736
+ const docState = await resolvePublicDocStateWithLocalRecovery({
784
737
  collection,
785
738
  docId,
786
739
  doc,
787
740
  idFields,
788
- hydrateCompatDocData: true
741
+ hydrateDocDataFromLocal: true
789
742
  });
790
743
  if (!docState.exists)
791
744
  throw Error(ERRORS.nonExistingDoc(segments));
@@ -814,12 +767,12 @@ export async function stringRemovePublic(segments, index, howMany) {
814
767
  throw Error(ERRORS.publicDoc(segments));
815
768
  const doc = getConnection().get(collection, docId);
816
769
  const idFields = getIdFieldsForSegments([collection, docId]);
817
- const docState = await resolvePublicDocStateWithCompatFetchFallback({
770
+ const docState = await resolvePublicDocStateWithLocalRecovery({
818
771
  collection,
819
772
  docId,
820
773
  doc,
821
774
  idFields,
822
- hydrateCompatDocData: true
775
+ hydrateDocDataFromLocal: true
823
776
  });
824
777
  if (!docState.exists)
825
778
  throw Error(ERRORS.nonExistingDoc(segments));
@@ -853,11 +806,6 @@ const ERRORS = {
853
806
  `,
854
807
  publicDocIdNumber: segments => `
855
808
  Public doc id must be a string. Got a number: ${segments}
856
- `,
857
- deleteNonExistentDoc: segments => `
858
- Trying to delete data from a non-existing doc ${segments}.
859
- Make sure that the document exists and you are subscribed to it
860
- before trying to delete anything from it or the doc itself.
861
809
  `,
862
810
  publicDocIdUndefined: segments => `
863
811
  Trying to modify a public document with the id 'undefined'.
@@ -27,9 +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
- context.resetModelListeners();
33
30
  for (const transportHash of Array.from(context.queryRuntimeHashes)) {
34
31
  await querySubscriptions.destroyByRuntimeHash(transportHash, { rootId, force: true });
35
32
  }
@@ -43,17 +40,6 @@ async function runDispose(rootId) {
43
40
  context.resetDirectDocSubscriptions();
44
41
  deleteRootContext(rootId);
45
42
  }
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
43
  export function __resetPendingRootDisposesForTests() {
58
44
  PENDING_DISPOSES.clear();
59
45
  }
@@ -0,0 +1,6 @@
1
+ export const emit: any
2
+ export const on: any
3
+ export const removeListener: any
4
+ export const useOn: any
5
+ export const useEmit: any
6
+ export const __resetEventsForTests: any
@@ -0,0 +1,48 @@
1
+ import { useLayoutEffect } from 'react';
2
+ const listeners = new Map();
3
+ export function emit(eventName, ...args) {
4
+ const subs = listeners.get(eventName);
5
+ if (!subs)
6
+ return;
7
+ const snapshot = Array.from(subs);
8
+ for (const handler of snapshot) {
9
+ handler(...args);
10
+ }
11
+ }
12
+ export function on(eventName, handler) {
13
+ if (!listeners.has(eventName))
14
+ listeners.set(eventName, new Set());
15
+ const subs = listeners.get(eventName);
16
+ subs.add(handler);
17
+ return handler;
18
+ }
19
+ export function removeListener(eventName, handler) {
20
+ const subs = listeners.get(eventName);
21
+ if (!subs)
22
+ return;
23
+ subs.delete(handler);
24
+ if (!subs.size)
25
+ listeners.delete(eventName);
26
+ }
27
+ export function useOn(eventName, patternOrHandler, handler, deps) {
28
+ const isModelEvent = eventName === 'change' || eventName === 'all';
29
+ if (!isModelEvent || typeof patternOrHandler === 'function') {
30
+ if (typeof patternOrHandler !== 'function')
31
+ throw Error('useOn() expects a handler function');
32
+ }
33
+ else {
34
+ throw Error('Signal model events are not supported. Use reaction() for signal changes.');
35
+ }
36
+ useLayoutEffect(() => {
37
+ const listener = on(eventName, patternOrHandler);
38
+ return () => {
39
+ removeListener(eventName, listener);
40
+ };
41
+ }, [eventName, patternOrHandler, deps]);
42
+ }
43
+ export function useEmit() {
44
+ return emit;
45
+ }
46
+ export function __resetEventsForTests() {
47
+ listeners.clear();
48
+ }
@@ -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;
@@ -1,13 +1,10 @@
1
1
  import Cache from "./Cache.js";
2
- import Signal, { SEGMENTS, regularBindings, extremelyLateBindings, isPublicCollection, isPrivateCollection } from "./Signal.js";
2
+ import Signal, { regularBindings, extremelyLateBindings, isPublicCollection, isPrivateCollection } from "./Signal.js";
3
3
  import { findModel } from "./addModel.js";
4
4
  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 { getConnection } from "./connection.js";
10
- import { resolveRefSegmentsSafe } from './Compat/refFallback.js';
11
8
  import { getSignalIdentityHash } from "./rootScope.js";
12
9
  import { isRootContextClosed, registerRootOwnedSignalHash } from "./rootContext.js";
13
10
  const PROXIES_CACHE = new Cache();
@@ -80,38 +77,12 @@ export default function getSignal($root, segments = [], { useExtremelyLateBindin
80
77
  return proxy;
81
78
  }
82
79
  function getDefaultProxyHandlers({ useExtremelyLateBindings } = {}) {
83
- const baseHandlers = (useExtremelyLateBindings ? extremelyLateBindings : regularBindings);
84
- if (!isCompatEnv() || baseHandlers !== extremelyLateBindings)
85
- return baseHandlers;
86
- return {
87
- ...baseHandlers,
88
- get(signal, key, receiver) {
89
- if (key === 'connection' && signal[SEGMENTS].length === 0) {
90
- try {
91
- return getConnection();
92
- }
93
- catch {
94
- return undefined;
95
- }
96
- }
97
- return baseHandlers.get
98
- ? baseHandlers.get(signal, key, receiver)
99
- : Reflect.get(signal, key, receiver);
100
- }
101
- };
80
+ return (useExtremelyLateBindings ? extremelyLateBindings : regularBindings);
102
81
  }
103
- export function getSignalClass(segments, rootId = GLOBAL_ROOT_ID) {
104
- let Model = findModel(segments);
82
+ export function getSignalClass(segments, _rootId = GLOBAL_ROOT_ID) {
83
+ const Model = findModel(segments);
105
84
  if (Model)
106
85
  return Model;
107
- if (!isCompatEnv())
108
- return Signal;
109
- const dereferencedSegments = resolveRefSegmentsSafe(segments, rootId);
110
- if (dereferencedSegments) {
111
- Model = findModel(dereferencedSegments);
112
- if (Model)
113
- return Model;
114
- }
115
86
  return Signal;
116
87
  }
117
88
  export function rawSignal(proxy) {
@@ -2,13 +2,22 @@ import type { PathSegment } from './types/path.js';
2
2
  export type IdField = string;
3
3
  export type IdFields = readonly IdField[];
4
4
  export type PlainObject = Record<string, unknown>;
5
+ export interface TeamplayRuntimeConfig {
6
+ idFields?: IdFields | null;
7
+ }
5
8
  export declare const DEFAULT_ID_FIELDS: readonly ["_id"];
9
+ export declare const TEAMPLAY_RUNTIME_CONFIG_SYMBOL: unique symbol;
6
10
  export declare function getIdFieldsForSegments(segments: PathSegment[]): IdFields;
11
+ export declare function configureTeamplay({ idFields }?: TeamplayRuntimeConfig): void;
12
+ export declare function getTeamplayConfig(): Required<TeamplayRuntimeConfig>;
13
+ export declare function getDefaultIdFields(): IdFields;
14
+ export declare function setDefaultIdFields(idFields?: IdFields): void;
15
+ export declare function __resetTeamplayConfigForTests(): void;
7
16
  export declare function isPlainObject(value: unknown): value is PlainObject;
8
17
  export declare function injectIdFields<TValue>(value: TValue, idFields: IdFields, docId: PathSegment): TValue;
9
18
  export declare function normalizeIdFields<TValue>(value: TValue, idFields: IdFields, docId: PathSegment): TValue;
10
19
  export declare function stripIdFields<TValue>(value: TValue, idFields: IdFields): TValue;
11
- export declare function resolveAddDocId(value: unknown, getDefaultId: () => string): PathSegment;
20
+ export declare function resolveAddDocId(value: unknown, idFields: IdFields, getDefaultId: () => string): PathSegment;
12
21
  export declare function prepareAddPayload<TValue extends object>(value: TValue, idFields: IdFields, docId: PathSegment): TValue;
13
22
  export declare function isPublicDocPath(segments: unknown): segments is [string, PathSegment];
14
23
  export declare function isIdFieldPath(segments: unknown, idFields: IdFields): segments is [string, PathSegment, string];