teamplay 0.5.0-alpha.9 → 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.
- package/README.md +3 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.js +1 -0
- package/dist/connect/index.d.ts +1 -1
- package/dist/connect/index.js +6 -2
- package/dist/connect/offline/index.d.ts +1 -1
- package/dist/connect/offline/index.js +8 -4
- package/dist/connect/offline/react-native.d.ts +1 -1
- package/dist/connect/offline/web.d.ts +1 -1
- package/dist/connect/test.d.ts +1 -1
- package/dist/connect/test.js +5 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.js +6 -5
- package/dist/orm/$.js +1 -1
- package/dist/orm/Aggregation.d.ts +5 -3
- package/dist/orm/Aggregation.js +39 -15
- package/dist/orm/Doc.js +0 -55
- package/dist/orm/Query.d.ts +1 -0
- package/dist/orm/Query.js +25 -82
- package/dist/orm/Root.d.ts +4 -0
- package/dist/orm/Root.js +16 -0
- package/dist/orm/Signal.d.ts +0 -2
- package/dist/orm/Signal.js +1 -4
- package/dist/orm/SignalBase.d.ts +21 -1
- package/dist/orm/SignalBase.js +259 -56
- package/dist/orm/batchScheduler.d.ts +7 -7
- package/dist/orm/connection.d.ts +0 -4
- package/dist/orm/connection.js +0 -12
- package/dist/orm/dataTree.d.ts +12 -12
- package/dist/orm/dataTree.js +55 -107
- package/dist/orm/disposeRootContext.js +0 -14
- package/dist/orm/events.d.ts +6 -0
- package/dist/orm/events.js +48 -0
- package/dist/orm/getSignal.d.ts +1 -1
- package/dist/orm/getSignal.js +4 -33
- package/dist/orm/idFields.d.ts +10 -1
- package/dist/orm/idFields.js +102 -14
- package/dist/orm/index.d.ts +2 -0
- package/dist/orm/index.js +1 -0
- package/dist/orm/initModels.js +1 -1
- package/dist/orm/privateData.d.ts +7 -22
- package/dist/orm/privateData.js +20 -1
- package/dist/orm/queryReadiness.d.ts +13 -0
- package/dist/orm/{Compat/queryReadiness.js → queryReadiness.js} +10 -10
- package/dist/orm/reaction.d.ts +11 -0
- package/dist/orm/reaction.js +47 -0
- package/dist/orm/rootContext.d.ts +0 -16
- package/dist/orm/rootContext.js +0 -28
- package/dist/orm/signalMetadata.js +3 -3
- package/dist/orm/signalReads.js +3 -9
- package/dist/orm/signalStorageMutations.d.ts +0 -2
- package/dist/orm/signalStorageMutations.js +0 -9
- package/dist/orm/signalSymbols.js +1 -1
- package/dist/orm/signalValueMutations.d.ts +1 -1
- package/dist/orm/signalValueMutations.js +0 -3
- package/dist/orm/sub.d.ts +12 -7
- package/dist/orm/sub.js +87 -30
- package/dist/orm/subscriptionGcDelay.js +2 -6
- package/dist/react/convertToObserver.js +1 -4
- package/dist/react/promiseBatcher.js +1 -1
- package/dist/react/renderAttemptDestroyer.d.ts +0 -8
- package/dist/react/renderAttemptDestroyer.js +2 -28
- package/dist/react/trapRender.js +3 -3
- package/dist/react/useSub.d.ts +86 -5
- package/dist/react/useSub.js +191 -32
- package/dist/react/useSuspendMemo.js +1 -5
- package/dist/server.d.ts +1 -2
- package/dist/server.js +5 -3
- package/package.json +15 -13
- package/dist/orm/Compat/SignalCompat.d.ts +0 -3
- package/dist/orm/Compat/SignalCompat.js +0 -1267
- package/dist/orm/Compat/eventsCompat.d.ts +0 -3
- package/dist/orm/Compat/eventsCompat.js +0 -73
- package/dist/orm/Compat/hooksCompat.d.ts +0 -33
- package/dist/orm/Compat/hooksCompat.js +0 -360
- package/dist/orm/Compat/modelEvents.d.ts +0 -6
- package/dist/orm/Compat/modelEvents.js +0 -228
- package/dist/orm/Compat/queryReadiness.d.ts +0 -5
- package/dist/orm/Compat/refFallback.d.ts +0 -13
- package/dist/orm/Compat/refFallback.js +0 -65
- package/dist/orm/Compat/refRegistry.d.ts +0 -6
- package/dist/orm/Compat/refRegistry.js +0 -54
- package/dist/orm/Compat/silentContext.d.ts +0 -5
- package/dist/orm/Compat/silentContext.js +0 -48
- package/dist/orm/Compat/startStopCompat.d.ts +0 -3
- package/dist/orm/Compat/startStopCompat.js +0 -217
- package/dist/orm/compatEnv.d.ts +0 -1
- package/dist/orm/compatEnv.js +0 -4
- package/dist/react/compatComponentRegistry.d.ts +0 -4
- package/dist/react/compatComponentRegistry.js +0 -19
- /package/dist/orm/{Reaction.d.ts → reactionSubscriptions.d.ts} +0 -0
- /package/dist/orm/{Reaction.js → reactionSubscriptions.js} +0 -0
package/dist/orm/dataTree.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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,
|
|
150
|
+
let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal: true });
|
|
182
151
|
if (!docState.exists && segments.length > 2) {
|
|
183
|
-
docState = await
|
|
152
|
+
docState = await resolvePublicDocStateWithLocalRecovery({
|
|
184
153
|
collection,
|
|
185
154
|
docId,
|
|
186
155
|
doc,
|
|
187
156
|
idFields,
|
|
188
|
-
|
|
157
|
+
hydrateDocDataFromLocal: true
|
|
189
158
|
});
|
|
190
159
|
}
|
|
191
160
|
if (!docState.exists && deleteValue)
|
|
192
|
-
|
|
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,
|
|
258
|
+
let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal: true });
|
|
290
259
|
if (!docState.exists && segments.length > 2) {
|
|
291
|
-
docState = await
|
|
260
|
+
docState = await resolvePublicDocStateWithLocalRecovery({
|
|
292
261
|
collection,
|
|
293
262
|
docId,
|
|
294
263
|
doc,
|
|
295
264
|
idFields,
|
|
296
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
378
|
-
//
|
|
379
|
-
|
|
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,
|
|
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 (
|
|
373
|
+
if (localSnapshot == null) {
|
|
404
374
|
return { exists: false, snapshot: undefined, source: 'none' };
|
|
405
375
|
}
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
if (
|
|
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
|
|
414
|
-
let docState = resolvePublicDocState({ collection, docId, doc, idFields,
|
|
415
|
-
if (docState.exists
|
|
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,
|
|
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
|
|
478
|
+
export function arrayPush(segments, value, tree = dataTree) {
|
|
504
479
|
const arr = getArrayNode(segments, tree, true);
|
|
505
|
-
|
|
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
|
|
482
|
+
export function arrayUnshift(segments, value, tree = dataTree) {
|
|
511
483
|
const arr = getArrayNode(segments, tree, true);
|
|
512
|
-
|
|
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
|
|
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
|
|
492
|
+
export function arrayPop(segments, tree = dataTree) {
|
|
526
493
|
const arr = getArrayNode(segments, tree, true);
|
|
527
494
|
if (!arr.length)
|
|
528
495
|
return;
|
|
529
|
-
|
|
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
|
|
498
|
+
export function arrayShift(segments, tree = dataTree) {
|
|
535
499
|
const arr = getArrayNode(segments, tree, true);
|
|
536
500
|
if (!arr.length)
|
|
537
501
|
return;
|
|
538
|
-
|
|
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
|
|
504
|
+
export function arrayRemove(segments, index, howMany = 1, tree = dataTree) {
|
|
543
505
|
const arr = getArrayNode(segments, tree, true);
|
|
544
|
-
|
|
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
|
|
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
|
|
531
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
576
532
|
collection,
|
|
577
533
|
docId,
|
|
578
534
|
doc,
|
|
579
535
|
idFields,
|
|
580
|
-
|
|
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
|
|
574
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
619
575
|
collection,
|
|
620
576
|
docId,
|
|
621
577
|
doc,
|
|
622
578
|
idFields,
|
|
623
|
-
|
|
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
|
|
633
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
678
634
|
collection,
|
|
679
635
|
docId,
|
|
680
636
|
doc,
|
|
681
637
|
idFields,
|
|
682
|
-
|
|
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
|
|
661
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
706
662
|
collection,
|
|
707
663
|
docId,
|
|
708
664
|
doc,
|
|
709
665
|
idFields,
|
|
710
|
-
|
|
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
|
|
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
|
|
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
|
|
736
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
784
737
|
collection,
|
|
785
738
|
docId,
|
|
786
739
|
doc,
|
|
787
740
|
idFields,
|
|
788
|
-
|
|
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
|
|
770
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
818
771
|
collection,
|
|
819
772
|
docId,
|
|
820
773
|
doc,
|
|
821
774
|
idFields,
|
|
822
|
-
|
|
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,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
|
+
}
|
package/dist/orm/getSignal.d.ts
CHANGED
|
@@ -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[],
|
|
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;
|
package/dist/orm/getSignal.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import Cache from "./Cache.js";
|
|
2
|
-
import Signal, {
|
|
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
|
-
|
|
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,
|
|
104
|
-
|
|
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) {
|
package/dist/orm/idFields.d.ts
CHANGED
|
@@ -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];
|