teamplay 0.5.0-alpha.35 → 0.5.0-alpha.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/orm/Compat/SignalCompat.js +4 -87
- package/dist/orm/Doc.js +0 -100
- package/dist/orm/Query.js +0 -51
- package/dist/orm/SignalBase.js +2 -3
- package/dist/orm/connection.d.ts +0 -11
- package/dist/orm/connection.js +0 -17
- package/dist/orm/dataTree.d.ts +12 -12
- package/dist/orm/dataTree.js +17 -69
- package/dist/orm/disposeRootContext.js +0 -1
- package/dist/orm/rootContext.d.ts +0 -9
- package/dist/orm/rootContext.js +0 -18
- package/dist/server.d.ts +1 -2
- package/dist/server.js +2 -3
- package/package.json +3 -2
- package/dist/orm/Compat/modelEvents.d.ts +0 -6
- package/dist/orm/Compat/modelEvents.js +0 -143
- package/dist/orm/Compat/silentContext.d.ts +0 -4
- package/dist/orm/Compat/silentContext.js +0 -19
package/dist/index.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export { emit, useOn, useEmit } from './orm/events.js';
|
|
|
62
62
|
export { default as reaction } from './orm/reaction.js';
|
|
63
63
|
export type { ReactionHandle, ReactionOptions } from './orm/reaction.js';
|
|
64
64
|
export { useDidUpdate, useOnce, useSyncEffect } from './react/helpers.js';
|
|
65
|
-
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly
|
|
65
|
+
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly } from './orm/connection.js';
|
|
66
66
|
export type { TeamplayConnection, TeamplayShareDoc } from './orm/connection.js';
|
|
67
67
|
export { TEAMPLAY_RUNTIME_CONFIG_SYMBOL, configureTeamplay, getTeamplayConfig, getDefaultIdFields, setDefaultIdFields } from './config.js';
|
|
68
68
|
export type { IdField, IdFields, TeamplayRuntimeConfig } from './config.js';
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ export const observer = runtimeObserver;
|
|
|
21
21
|
export { emit, useOn, useEmit } from './orm/events.js';
|
|
22
22
|
export { default as reaction } from "./orm/reaction.js";
|
|
23
23
|
export { useDidUpdate, useOnce, useSyncEffect } from "./react/helpers.js";
|
|
24
|
-
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly
|
|
24
|
+
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly } from "./orm/connection.js";
|
|
25
25
|
export { TEAMPLAY_RUNTIME_CONFIG_SYMBOL, configureTeamplay, getTeamplayConfig, getDefaultIdFields, setDefaultIdFields } from "./config.js";
|
|
26
26
|
export { getSubscriptionGcDelay, setSubscriptionGcDelay } from "./orm/subscriptionGcDelay.js";
|
|
27
27
|
export { useId, useNow, useScheduleUpdate, useTriggerUpdate } from "./react/helpers.js";
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { raw } from '@nx-js/observer-util';
|
|
2
2
|
import arrayDiff from 'arraydiff';
|
|
3
|
-
import { Signal, GETTERS, DEFAULT_GETTERS, SEGMENTS, isPublicCollection
|
|
3
|
+
import { Signal, GETTERS, DEFAULT_GETTERS, SEGMENTS, isPublicCollection } from "../SignalBase.js";
|
|
4
4
|
import { getRoot, ROOT, ROOT_ID } from "../Root.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { AGGREGATIONS, IS_AGGREGATION, aggregationSubscriptions } from '../Aggregation.js';
|
|
5
|
+
import { IS_QUERY } from '../Query.js';
|
|
6
|
+
import { AGGREGATIONS, IS_AGGREGATION } from '../Aggregation.js';
|
|
8
7
|
import { getIdFieldsForSegments, isIdFieldPath, isPublicDocPath, normalizeIdFields, isPlainObject } from "../idFields.js";
|
|
9
8
|
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
9
|
import { on as onCustomEvent, removeListener as removeCustomEventListener } from '../events.js';
|
|
11
|
-
import { waitForImperativeQueryReady } from '../queryReadiness.js';
|
|
12
10
|
import { runInBatch } from '../batchScheduler.js';
|
|
13
11
|
import { arrayInsertPrivateData, arrayMovePrivateData, arrayPopPrivateData, arrayPushPrivateData, arrayRemovePrivateData, arrayShiftPrivateData, arrayUnshiftPrivateData, delPrivateData, setReplacePrivateData, stringInsertPrivateData, stringRemovePrivateData } from '../privateData.js';
|
|
14
12
|
class SignalCompat extends Signal {
|
|
@@ -36,16 +34,6 @@ class SignalCompat extends Signal {
|
|
|
36
34
|
throw Error('Signal.getDeepCopy() does not accept any arguments');
|
|
37
35
|
return deepCopy(this.get());
|
|
38
36
|
}
|
|
39
|
-
fetch(...items) {
|
|
40
|
-
if (items.length > 0)
|
|
41
|
-
return subscribeMany(items, 'subscribe', 'fetch', 'fetch');
|
|
42
|
-
return subscribeSelf(this, 'fetch', 'fetch');
|
|
43
|
-
}
|
|
44
|
-
unfetch(...items) {
|
|
45
|
-
if (items.length > 0)
|
|
46
|
-
return subscribeMany(items, 'unsubscribe', 'fetch', 'unfetch');
|
|
47
|
-
return unsubscribeSelf(this, 'fetch', 'unfetch');
|
|
48
|
-
}
|
|
49
37
|
getExtra() {
|
|
50
38
|
if (arguments.length > 0)
|
|
51
39
|
throw Error('Signal.getExtra() does not accept any arguments');
|
|
@@ -68,9 +56,7 @@ class SignalCompat extends Signal {
|
|
|
68
56
|
async set(value) {
|
|
69
57
|
if (arguments.length > 1)
|
|
70
58
|
throw Error('Signal.set() expects a single argument');
|
|
71
|
-
|
|
72
|
-
return Signal.prototype.set.call(this, value);
|
|
73
|
-
return setReplaceOnSignal(this, value);
|
|
59
|
+
return Signal.prototype.set.call(this, value);
|
|
74
60
|
}
|
|
75
61
|
async setReplace(value) {
|
|
76
62
|
if (arguments.length > 1)
|
|
@@ -621,75 +607,6 @@ function deepCopy(value) {
|
|
|
621
607
|
}
|
|
622
608
|
return racerDeepCopy(rawValue);
|
|
623
609
|
}
|
|
624
|
-
function subscribeMany(items, action, intent = 'subscribe', methodName = action) {
|
|
625
|
-
const targets = flattenItems(items);
|
|
626
|
-
const promises = [];
|
|
627
|
-
for (const target of targets) {
|
|
628
|
-
if (!target)
|
|
629
|
-
continue;
|
|
630
|
-
if (!(target instanceof Signal)) {
|
|
631
|
-
throw Error(`Signal.${methodName}() accepts only Signal instances. Got: ${target}`);
|
|
632
|
-
}
|
|
633
|
-
const result = action === 'subscribe'
|
|
634
|
-
? subscribeSelf(target, intent, methodName)
|
|
635
|
-
: unsubscribeSelf(target, intent, methodName);
|
|
636
|
-
if (result?.then)
|
|
637
|
-
promises.push(result);
|
|
638
|
-
}
|
|
639
|
-
if (promises.length)
|
|
640
|
-
return Promise.all(promises);
|
|
641
|
-
}
|
|
642
|
-
function flattenItems(items, result = []) {
|
|
643
|
-
for (const item of items) {
|
|
644
|
-
if (!item)
|
|
645
|
-
continue;
|
|
646
|
-
if (Array.isArray(item)) {
|
|
647
|
-
flattenItems(item, result);
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
result.push(item);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
return result;
|
|
654
|
-
}
|
|
655
|
-
function subscribeSelf($signal, intent = 'subscribe', methodName = 'subscribe') {
|
|
656
|
-
if ($signal[IS_QUERY]) {
|
|
657
|
-
return (async () => {
|
|
658
|
-
await querySubscriptions.subscribe($signal, { intent });
|
|
659
|
-
await waitForImperativeQueryReady($signal);
|
|
660
|
-
})();
|
|
661
|
-
}
|
|
662
|
-
if ($signal[IS_AGGREGATION]) {
|
|
663
|
-
return (async () => {
|
|
664
|
-
await aggregationSubscriptions.subscribe($signal, { intent });
|
|
665
|
-
await waitForImperativeQueryReady($signal);
|
|
666
|
-
})();
|
|
667
|
-
}
|
|
668
|
-
if (isPublicDocumentSignal($signal))
|
|
669
|
-
return docSubscriptions.subscribe($signal, { intent });
|
|
670
|
-
if (isPublicCollectionSignal($signal)) {
|
|
671
|
-
throw Error(`Signal.${methodName}() expects a document or query signal. Use sub($collection, params, { mode: 'fetch' }) for collection fetches.`);
|
|
672
|
-
}
|
|
673
|
-
if ($signal[SEGMENTS].length === 0) {
|
|
674
|
-
throw Error(`Signal.${methodName}() cannot be called on the root signal`);
|
|
675
|
-
}
|
|
676
|
-
throw Error(`Signal.${methodName}() expects a document or query signal`);
|
|
677
|
-
}
|
|
678
|
-
function unsubscribeSelf($signal, intent = 'subscribe', methodName = 'unsubscribe') {
|
|
679
|
-
if ($signal[IS_QUERY])
|
|
680
|
-
return querySubscriptions.unsubscribe($signal, { intent });
|
|
681
|
-
if ($signal[IS_AGGREGATION])
|
|
682
|
-
return aggregationSubscriptions.unsubscribe($signal, { intent });
|
|
683
|
-
if (isPublicDocumentSignal($signal))
|
|
684
|
-
return docSubscriptions.unsubscribe($signal, { intent });
|
|
685
|
-
if (isPublicCollectionSignal($signal)) {
|
|
686
|
-
throw Error(`Signal.${methodName}() expects a document or query signal`);
|
|
687
|
-
}
|
|
688
|
-
if ($signal[SEGMENTS].length === 0) {
|
|
689
|
-
throw Error(`Signal.${methodName}() cannot be called on the root signal`);
|
|
690
|
-
}
|
|
691
|
-
throw Error(`Signal.${methodName}() expects a document or query signal`);
|
|
692
|
-
}
|
|
693
610
|
// Racer-style deep copy:
|
|
694
611
|
// - Preserves prototypes by instantiating via `new value.constructor()`
|
|
695
612
|
// - Copies own enumerable props recursively
|
package/dist/orm/Doc.js
CHANGED
|
@@ -5,50 +5,12 @@ import { getConnection } from "./connection.js";
|
|
|
5
5
|
import FinalizationRegistry from "../utils/MockFinalizationRegistry.js";
|
|
6
6
|
import SubscriptionState from './SubscriptionState.js';
|
|
7
7
|
import { getIdFieldsForSegments, injectIdFields, isPlainObject } from "./idFields.js";
|
|
8
|
-
import { emitModelChange, isModelEventsEnabled } from './Compat/modelEvents.js';
|
|
9
8
|
import { getSubscriptionGcDelay } from "./subscriptionGcDelay.js";
|
|
10
9
|
import { isMissingShareDoc } from './missingDoc.js';
|
|
11
10
|
import { getRoot, ROOT_ID, GLOBAL_ROOT_ID, getRootTransportMode } from "./Root.js";
|
|
12
11
|
import { registerRootOwnedDirectDocSubscription, unregisterRootOwnedDirectDocSubscription, getRootOwnedDirectDocSubscriptions, clearRootOwnedDirectDocSubscriptions } from "./rootContext.js";
|
|
13
12
|
const ERROR_ON_EXCESSIVE_UNSUBSCRIBES = false;
|
|
14
13
|
const DOC_FINALIZATION_TOKENS = new WeakMap();
|
|
15
|
-
const RECENT_DOC_OP_CONTEXT_TTL = 100;
|
|
16
|
-
const ACTIVE_DOC_OP_CONTEXTS = [];
|
|
17
|
-
let recentDocOpContext;
|
|
18
|
-
export function getActiveDocOpContext() {
|
|
19
|
-
return ACTIVE_DOC_OP_CONTEXTS[ACTIVE_DOC_OP_CONTEXTS.length - 1] || recentDocOpContext;
|
|
20
|
-
}
|
|
21
|
-
function pushActiveDocOpContext(collection, docId, source) {
|
|
22
|
-
const context = { collection, docId, source };
|
|
23
|
-
ACTIVE_DOC_OP_CONTEXTS.push(context);
|
|
24
|
-
recentDocOpContext = context;
|
|
25
|
-
}
|
|
26
|
-
function popActiveDocOpContext(collection, docId, source) {
|
|
27
|
-
const current = ACTIVE_DOC_OP_CONTEXTS[ACTIVE_DOC_OP_CONTEXTS.length - 1];
|
|
28
|
-
if (current?.collection === collection && current?.docId === docId && current?.source === source) {
|
|
29
|
-
ACTIVE_DOC_OP_CONTEXTS.pop();
|
|
30
|
-
clearRecentDocOpContext(current);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
let index = -1;
|
|
34
|
-
for (let i = ACTIVE_DOC_OP_CONTEXTS.length - 1; i >= 0; i--) {
|
|
35
|
-
const context = ACTIVE_DOC_OP_CONTEXTS[i];
|
|
36
|
-
if (context.collection === collection && context.docId === docId && context.source === source) {
|
|
37
|
-
index = i;
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (index === -1)
|
|
42
|
-
return;
|
|
43
|
-
const [context] = ACTIVE_DOC_OP_CONTEXTS.splice(index, 1);
|
|
44
|
-
clearRecentDocOpContext(context);
|
|
45
|
-
}
|
|
46
|
-
function clearRecentDocOpContext(context) {
|
|
47
|
-
setTimeout(() => {
|
|
48
|
-
if (recentDocOpContext === context)
|
|
49
|
-
recentDocOpContext = undefined;
|
|
50
|
-
}, RECENT_DOC_OP_CONTEXT_TTL);
|
|
51
|
-
}
|
|
52
14
|
function getDocFinalizationToken($doc) {
|
|
53
15
|
let token = DOC_FINALIZATION_TOKENS.get($doc);
|
|
54
16
|
if (!token) {
|
|
@@ -185,17 +147,6 @@ class Doc {
|
|
|
185
147
|
doc.on('load', () => this._refData());
|
|
186
148
|
doc.on('create', () => this._refData());
|
|
187
149
|
doc.on('del', () => this._refMissingData());
|
|
188
|
-
if (isModelEventsEnabled()) {
|
|
189
|
-
doc.on('before op', (_op, source) => pushActiveDocOpContext(this.collection, this.docId, source));
|
|
190
|
-
doc.on('op', (op, source) => {
|
|
191
|
-
try {
|
|
192
|
-
emitDocOp(this.collection, this.docId, op, source);
|
|
193
|
-
}
|
|
194
|
-
finally {
|
|
195
|
-
popActiveDocOpContext(this.collection, this.docId, source);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
150
|
}
|
|
200
151
|
_refMissingData() {
|
|
201
152
|
_del([this.collection, this.docId]);
|
|
@@ -915,57 +866,6 @@ function createPendingDestroyEntry() {
|
|
|
915
866
|
reject: rejectPending
|
|
916
867
|
};
|
|
917
868
|
}
|
|
918
|
-
function emitDocOp(collection, docId, op, source) {
|
|
919
|
-
if (!isModelEventsEnabled())
|
|
920
|
-
return;
|
|
921
|
-
const ops = Array.isArray(op) ? op : [op];
|
|
922
|
-
for (const component of ops) {
|
|
923
|
-
if (!component || !component.p)
|
|
924
|
-
continue;
|
|
925
|
-
const baseSegments = [collection, docId];
|
|
926
|
-
let pathSegments = baseSegments.concat(component.p);
|
|
927
|
-
const meta = { source };
|
|
928
|
-
let value;
|
|
929
|
-
let prevValue;
|
|
930
|
-
if (has(component, 'si') || has(component, 'sd')) {
|
|
931
|
-
const index = component.p[component.p.length - 1];
|
|
932
|
-
meta.op = has(component, 'si') ? 'stringInsert' : 'stringRemove';
|
|
933
|
-
meta.index = index;
|
|
934
|
-
pathSegments = baseSegments.concat(component.p.slice(0, -1));
|
|
935
|
-
value = _getRaw(pathSegments);
|
|
936
|
-
prevValue = component.sd;
|
|
937
|
-
}
|
|
938
|
-
else if (has(component, 'lm')) {
|
|
939
|
-
meta.op = 'arrayMove';
|
|
940
|
-
meta.from = component.p[component.p.length - 1];
|
|
941
|
-
meta.to = component.lm;
|
|
942
|
-
pathSegments = baseSegments.concat(component.p.slice(0, -1));
|
|
943
|
-
value = _getRaw(pathSegments);
|
|
944
|
-
}
|
|
945
|
-
else if (has(component, 'li') || has(component, 'ld')) {
|
|
946
|
-
meta.op = has(component, 'li') ? 'arrayInsert' : 'arrayRemove';
|
|
947
|
-
meta.index = component.p[component.p.length - 1];
|
|
948
|
-
value = _getRaw(pathSegments);
|
|
949
|
-
prevValue = component.ld;
|
|
950
|
-
}
|
|
951
|
-
else if (has(component, 'na')) {
|
|
952
|
-
meta.op = 'increment';
|
|
953
|
-
meta.by = component.na;
|
|
954
|
-
value = _getRaw(pathSegments);
|
|
955
|
-
if (typeof value === 'number')
|
|
956
|
-
prevValue = value - component.na;
|
|
957
|
-
}
|
|
958
|
-
else {
|
|
959
|
-
meta.op = 'set';
|
|
960
|
-
value = has(component, 'oi') ? component.oi : _getRaw(pathSegments);
|
|
961
|
-
prevValue = component.od;
|
|
962
|
-
}
|
|
963
|
-
emitModelChange(pathSegments, value, prevValue, meta);
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
function has(obj, key) {
|
|
967
|
-
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
968
|
-
}
|
|
969
869
|
const ERRORS = {
|
|
970
870
|
notSubscribed: $doc => Error('trying to unsubscribe when not subscribed. Doc: ' + $doc.path())
|
|
971
871
|
};
|
package/dist/orm/Query.js
CHANGED
|
@@ -2,7 +2,6 @@ import { raw } from '@nx-js/observer-util';
|
|
|
2
2
|
import { set as _set, getRaw } from './dataTree.js';
|
|
3
3
|
import getSignal from "./getSignal.js";
|
|
4
4
|
import { getConnection } from "./connection.js";
|
|
5
|
-
import { emitModelChange, isModelEventsEnabled } from './Compat/modelEvents.js';
|
|
6
5
|
import { isCompatEnv } from './compatEnv.js';
|
|
7
6
|
import { docSubscriptions } from './Doc.js';
|
|
8
7
|
import FinalizationRegistry from "../utils/MockFinalizationRegistry.js";
|
|
@@ -127,22 +126,6 @@ export class Query {
|
|
|
127
126
|
return;
|
|
128
127
|
docs.splice(index, 0, ...newDocs);
|
|
129
128
|
idsState.splice(index, 0, ...ids);
|
|
130
|
-
if (!isModelEventsEnabled())
|
|
131
|
-
return;
|
|
132
|
-
const docsPath = [QUERIES, this.hash, 'docs'];
|
|
133
|
-
const idsPath = [QUERIES, this.hash, 'ids'];
|
|
134
|
-
for (let i = 0; i < newDocs.length; i++) {
|
|
135
|
-
emitModelChange(rootId, docsPath.concat(index + i), newDocs[i], undefined, {
|
|
136
|
-
op: 'queryInsert',
|
|
137
|
-
index: index + i
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
for (let i = 0; i < ids.length; i++) {
|
|
141
|
-
emitModelChange(rootId, idsPath.concat(index + i), ids[i], undefined, {
|
|
142
|
-
op: 'queryInsert',
|
|
143
|
-
index: index + i
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
129
|
});
|
|
147
130
|
});
|
|
148
131
|
this.shareQuery.on('move', (shareDocs, from, to) => {
|
|
@@ -153,26 +136,10 @@ export class Query {
|
|
|
153
136
|
const ids = getPrivateData(rootId, [QUERIES, this.hash, 'ids']);
|
|
154
137
|
if (!Array.isArray(docs) || !Array.isArray(ids))
|
|
155
138
|
return;
|
|
156
|
-
const prevDocs = isModelEventsEnabled() ? docs.slice() : undefined;
|
|
157
139
|
docs.splice(from, shareDocs.length);
|
|
158
140
|
docs.splice(to, 0, ...movedDocs);
|
|
159
|
-
const prevIds = isModelEventsEnabled() ? ids.slice() : undefined;
|
|
160
141
|
ids.splice(from, shareDocs.length);
|
|
161
142
|
ids.splice(to, 0, ...movedIds);
|
|
162
|
-
if (!isModelEventsEnabled())
|
|
163
|
-
return;
|
|
164
|
-
emitModelChange(rootId, [QUERIES, this.hash, 'docs'], docs, prevDocs, {
|
|
165
|
-
op: 'queryMove',
|
|
166
|
-
from,
|
|
167
|
-
to,
|
|
168
|
-
howMany: shareDocs.length
|
|
169
|
-
});
|
|
170
|
-
emitModelChange(rootId, [QUERIES, this.hash, 'ids'], ids, prevIds, {
|
|
171
|
-
op: 'queryMove',
|
|
172
|
-
from,
|
|
173
|
-
to,
|
|
174
|
-
howMany: shareDocs.length
|
|
175
|
-
});
|
|
176
143
|
});
|
|
177
144
|
});
|
|
178
145
|
this.shareQuery.on('remove', (shareDocs, index) => {
|
|
@@ -187,26 +154,8 @@ export class Query {
|
|
|
187
154
|
const ids = getPrivateData(rootId, [QUERIES, this.hash, 'ids']);
|
|
188
155
|
if (!Array.isArray(docs) || !Array.isArray(ids))
|
|
189
156
|
return;
|
|
190
|
-
const removedDocs = isModelEventsEnabled() ? docs.slice(index, index + shareDocs.length) : undefined;
|
|
191
157
|
docs.splice(index, shareDocs.length);
|
|
192
|
-
const removedIds = isModelEventsEnabled() ? ids.slice(index, index + docIds.length) : undefined;
|
|
193
158
|
ids.splice(index, docIds.length);
|
|
194
|
-
if (!isModelEventsEnabled())
|
|
195
|
-
return;
|
|
196
|
-
const docsPath = [QUERIES, this.hash, 'docs'];
|
|
197
|
-
const idsPath = [QUERIES, this.hash, 'ids'];
|
|
198
|
-
for (let i = 0; i < removedDocs.length; i++) {
|
|
199
|
-
emitModelChange(rootId, docsPath.concat(index + i), undefined, removedDocs[i], {
|
|
200
|
-
op: 'queryRemove',
|
|
201
|
-
index: index + i
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
for (let i = 0; i < removedIds.length; i++) {
|
|
205
|
-
emitModelChange(rootId, idsPath.concat(index + i), undefined, removedIds[i], {
|
|
206
|
-
op: 'queryRemove',
|
|
207
|
-
index: index + i
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
159
|
});
|
|
211
160
|
});
|
|
212
161
|
this.shareQuery.on('extra', extra => {
|
package/dist/orm/SignalBase.js
CHANGED
|
@@ -778,8 +778,7 @@ export const regularBindings = {
|
|
|
778
778
|
return Reflect.apply(extremelyLateBindings.get, this, arguments);
|
|
779
779
|
}
|
|
780
780
|
};
|
|
781
|
-
const QUERY_METHODS = ['map', 'reduce', 'find', 'get', 'getIds', 'getExtra'
|
|
782
|
-
const AGGREGATION_ALLOWED_METHODS = ['fetch', 'unfetch'];
|
|
781
|
+
const QUERY_METHODS = ['map', 'reduce', 'find', 'get', 'getIds', 'getExtra'];
|
|
783
782
|
// dot syntax always returns a child signal even if such method or property exists.
|
|
784
783
|
// The method is only called when the signal is explicitly called as a function,
|
|
785
784
|
// in which case we get the original method from the raw (non-proxied) parent signal
|
|
@@ -824,7 +823,7 @@ export const extremelyLateBindings = {
|
|
|
824
823
|
});
|
|
825
824
|
}
|
|
826
825
|
}
|
|
827
|
-
else if (!DEFAULT_GETTERS.includes(key)
|
|
826
|
+
else if (!DEFAULT_GETTERS.includes(key)) {
|
|
828
827
|
throw Error(ERRORS.aggregationSetter(segments, key));
|
|
829
828
|
}
|
|
830
829
|
}
|
package/dist/orm/connection.d.ts
CHANGED
|
@@ -16,18 +16,7 @@ export interface TeamplayConnection {
|
|
|
16
16
|
[key: string]: unknown;
|
|
17
17
|
}
|
|
18
18
|
export declare let connection: TeamplayConnection | undefined;
|
|
19
|
-
/** @deprecated Root-scoped private data made the publicOnly write guard obsolete. */
|
|
20
|
-
export declare const publicOnly = false;
|
|
21
19
|
export declare function setConnection(_connection: TeamplayConnection | undefined): void;
|
|
22
20
|
export declare function getConnection(): TeamplayConnection;
|
|
23
21
|
export declare function setDefaultFetchOnly(_fetchOnly: boolean): void;
|
|
24
22
|
export declare function getDefaultFetchOnly(): boolean;
|
|
25
|
-
export declare function setFetchOnly(_fetchOnly: boolean): void;
|
|
26
|
-
/**
|
|
27
|
-
* @deprecated No-op kept for compatibility with older server bootstrap code.
|
|
28
|
-
* Private collections are root-scoped; server safety now relies on avoiding
|
|
29
|
-
* writes to private collections through the global root.
|
|
30
|
-
*/
|
|
31
|
-
export declare function setPublicOnly(_publicOnly: boolean): void;
|
|
32
|
-
/** @deprecated publicOnly no longer blocks private writes. */
|
|
33
|
-
export declare function isPrivateMutationForbidden(): boolean;
|
package/dist/orm/connection.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export let connection;
|
|
2
2
|
let defaultFetchOnly;
|
|
3
|
-
/** @deprecated Root-scoped private data made the publicOnly write guard obsolete. */
|
|
4
|
-
export const publicOnly = false;
|
|
5
3
|
export function setConnection(_connection) {
|
|
6
4
|
connection = _connection;
|
|
7
5
|
}
|
|
@@ -16,21 +14,6 @@ export function setDefaultFetchOnly(_fetchOnly) {
|
|
|
16
14
|
export function getDefaultFetchOnly() {
|
|
17
15
|
return !!defaultFetchOnly;
|
|
18
16
|
}
|
|
19
|
-
// Deprecated alias kept for internal transition.
|
|
20
|
-
export function setFetchOnly(_fetchOnly) {
|
|
21
|
-
setDefaultFetchOnly(_fetchOnly);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* @deprecated No-op kept for compatibility with older server bootstrap code.
|
|
25
|
-
* Private collections are root-scoped; server safety now relies on avoiding
|
|
26
|
-
* writes to private collections through the global root.
|
|
27
|
-
*/
|
|
28
|
-
export function setPublicOnly(_publicOnly) {
|
|
29
|
-
}
|
|
30
|
-
/** @deprecated publicOnly no longer blocks private writes. */
|
|
31
|
-
export function isPrivateMutationForbidden() {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
17
|
const ERRORS = {
|
|
35
18
|
notSet: `
|
|
36
19
|
Connection is not set.
|
package/dist/orm/dataTree.d.ts
CHANGED
|
@@ -4,18 +4,18 @@ export function getLogicalRootSnapshot(rootId: any, tree?: {}): {
|
|
|
4
4
|
};
|
|
5
5
|
export function get(segments: any, tree?: {}): {};
|
|
6
6
|
export function getRaw(segments: any): {};
|
|
7
|
-
export function set(segments: any, value: any, tree
|
|
8
|
-
export function setReplace(segments: any, value: any, tree
|
|
9
|
-
export function del(segments: any, tree
|
|
7
|
+
export function set(segments: any, value: any, tree?: {}): void;
|
|
8
|
+
export function setReplace(segments: any, value: any, tree?: {}): void;
|
|
9
|
+
export function del(segments: any, tree?: {}): void;
|
|
10
10
|
export function setPublicDoc(segments: any, value: any, deleteValue?: boolean): Promise<any>;
|
|
11
11
|
export function setPublicDocReplace(segments: any, value: any): Promise<any>;
|
|
12
|
-
export function arrayPush(segments: any, value: any, tree
|
|
13
|
-
export function arrayUnshift(segments: any, value: any, tree
|
|
14
|
-
export function arrayInsert(segments: any, index: any, values: any, tree
|
|
15
|
-
export function arrayPop(segments: any, tree
|
|
16
|
-
export function arrayShift(segments: any, tree
|
|
17
|
-
export function arrayRemove(segments: any, index: any, howMany
|
|
18
|
-
export function arrayMove(segments: any, from: any, to: any, howMany
|
|
12
|
+
export function arrayPush(segments: any, value: any, tree?: {}): number;
|
|
13
|
+
export function arrayUnshift(segments: any, value: any, tree?: {}): number;
|
|
14
|
+
export function arrayInsert(segments: any, index: any, values: any, tree?: {}): number;
|
|
15
|
+
export function arrayPop(segments: any, tree?: {}): any;
|
|
16
|
+
export function arrayShift(segments: any, tree?: {}): any;
|
|
17
|
+
export function arrayRemove(segments: any, index: any, howMany?: number, tree?: {}): any[];
|
|
18
|
+
export function arrayMove(segments: any, from: any, to: any, howMany?: number, tree?: {}): any[];
|
|
19
19
|
export function incrementPublic(segments: any, byNumber: any): Promise<any>;
|
|
20
20
|
export function arrayPushPublic(segments: any, value: any): Promise<any>;
|
|
21
21
|
export function arrayUnshiftPublic(segments: any, value: any): Promise<any>;
|
|
@@ -24,8 +24,8 @@ export function arrayPopPublic(segments: any): Promise<any>;
|
|
|
24
24
|
export function arrayShiftPublic(segments: any): Promise<any>;
|
|
25
25
|
export function arrayRemovePublic(segments: any, index: any, howMany?: number): Promise<any>;
|
|
26
26
|
export function arrayMovePublic(segments: any, from: any, to: any, howMany?: number): Promise<any>;
|
|
27
|
-
export function stringInsertLocal(segments: any, index: any, text: any, tree
|
|
28
|
-
export function stringRemoveLocal(segments: any, index: any, howMany: any, tree
|
|
27
|
+
export function stringInsertLocal(segments: any, index: any, text: any, tree?: {}): any;
|
|
28
|
+
export function stringRemoveLocal(segments: any, index: any, howMany: any, tree?: {}): any;
|
|
29
29
|
export function stringInsertPublic(segments: any, index: any, text: any): Promise<any>;
|
|
30
30
|
export function stringRemovePublic(segments: any, index: any, howMany: any): Promise<any>;
|
|
31
31
|
export { isPrivateCollectionSegments } from "./rootScope.js";
|
package/dist/orm/dataTree.js
CHANGED
|
@@ -4,8 +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
7
|
import { isCompatEnv } from './compatEnv.js';
|
|
10
8
|
import { isMissingShareDoc } from './missingDoc.js';
|
|
11
9
|
import { getLogicalRootSnapshot as getLogicalRootSnapshotFromTree } from "./rootScope.js";
|
|
@@ -15,8 +13,6 @@ const ALLOW_PARTIAL_DOC_CREATION = false;
|
|
|
15
13
|
export const dataTreeRaw = {};
|
|
16
14
|
const dataTree = observable(dataTreeRaw);
|
|
17
15
|
function getWritableTree(tree) {
|
|
18
|
-
if (isSilentContextActive())
|
|
19
|
-
return getTreeRaw(tree);
|
|
20
16
|
return tree;
|
|
21
17
|
}
|
|
22
18
|
function getTreeRaw(tree) {
|
|
@@ -24,22 +20,6 @@ function getTreeRaw(tree) {
|
|
|
24
20
|
return dataTreeRaw;
|
|
25
21
|
return raw(tree) || tree;
|
|
26
22
|
}
|
|
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
23
|
export function resolveStorageSegments(rootId, logicalSegments) {
|
|
44
24
|
return logicalSegments;
|
|
45
25
|
}
|
|
@@ -59,10 +39,8 @@ export function get(segments, tree = dataTree) {
|
|
|
59
39
|
export function getRaw(segments) {
|
|
60
40
|
return get(segments, dataTreeRaw);
|
|
61
41
|
}
|
|
62
|
-
export function set(segments, value, tree = dataTree
|
|
42
|
+
export function set(segments, value, tree = dataTree) {
|
|
63
43
|
const writableTree = getWritableTree(tree);
|
|
64
|
-
const shouldEmit = shouldEmitModelEvents(tree, eventContext);
|
|
65
|
-
const prevValue = shouldEmit ? get(segments, getTreeRaw(tree)) : undefined;
|
|
66
44
|
let dataNode = writableTree;
|
|
67
45
|
let dataNodeRaw = getTreeRaw(writableTree);
|
|
68
46
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
@@ -87,7 +65,6 @@ export function set(segments, value, tree = dataTree, eventContext) {
|
|
|
87
65
|
return;
|
|
88
66
|
if (value == null || typeof value !== 'object') {
|
|
89
67
|
dataNode[key] = value;
|
|
90
|
-
emitModelEvent(segments, prevValue, { op: 'set' }, tree, eventContext);
|
|
91
68
|
return;
|
|
92
69
|
}
|
|
93
70
|
// instead of just setting the new value `dataNode[key] = value` we want
|
|
@@ -97,7 +74,6 @@ export function set(segments, value, tree = dataTree, eventContext) {
|
|
|
97
74
|
// (we just set it to this value)
|
|
98
75
|
if (dataNode[key] !== newValue)
|
|
99
76
|
dataNode[key] = newValue;
|
|
100
|
-
emitModelEvent(segments, prevValue, { op: 'set' }, tree, eventContext);
|
|
101
77
|
}
|
|
102
78
|
function hasOwnDataKey(node, key) {
|
|
103
79
|
if (node == null)
|
|
@@ -107,10 +83,8 @@ function hasOwnDataKey(node, key) {
|
|
|
107
83
|
return Object.prototype.hasOwnProperty.call(node, key);
|
|
108
84
|
}
|
|
109
85
|
// Like set(), but always assigns the value without equality checks or delete-on-null behavior
|
|
110
|
-
export function setReplace(segments, value, tree = dataTree
|
|
86
|
+
export function setReplace(segments, value, tree = dataTree) {
|
|
111
87
|
const writableTree = getWritableTree(tree);
|
|
112
|
-
const shouldEmit = shouldEmitModelEvents(tree, eventContext);
|
|
113
|
-
const prevValue = shouldEmit ? get(segments, getTreeRaw(tree)) : undefined;
|
|
114
88
|
let dataNode = writableTree;
|
|
115
89
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
116
90
|
const segment = segments[i];
|
|
@@ -127,12 +101,9 @@ export function setReplace(segments, value, tree = dataTree, eventContext) {
|
|
|
127
101
|
}
|
|
128
102
|
const key = segments[segments.length - 1];
|
|
129
103
|
dataNode[key] = value;
|
|
130
|
-
emitModelEvent(segments, prevValue, { op: 'setReplace' }, tree, eventContext);
|
|
131
104
|
}
|
|
132
|
-
export function del(segments, tree = dataTree
|
|
105
|
+
export function del(segments, tree = dataTree) {
|
|
133
106
|
const writableTree = getWritableTree(tree);
|
|
134
|
-
const shouldEmit = shouldEmitModelEvents(tree, eventContext);
|
|
135
|
-
const prevValue = shouldEmit ? get(segments, getTreeRaw(tree)) : undefined;
|
|
136
107
|
let dataNode = writableTree;
|
|
137
108
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
138
109
|
const segment = segments[i];
|
|
@@ -154,7 +125,6 @@ export function del(segments, tree = dataTree, eventContext) {
|
|
|
154
125
|
return;
|
|
155
126
|
delete dataNode[key];
|
|
156
127
|
}
|
|
157
|
-
emitModelEvent(segments, prevValue, { op: 'del' }, tree, eventContext);
|
|
158
128
|
}
|
|
159
129
|
export async function setPublicDoc(segments, value, deleteValue = false) {
|
|
160
130
|
if (segments.length === 0)
|
|
@@ -506,56 +476,38 @@ function getArrayNode(segments, tree = dataTree, create = true) {
|
|
|
506
476
|
}
|
|
507
477
|
return dataNode;
|
|
508
478
|
}
|
|
509
|
-
export function arrayPush(segments, value, tree = dataTree
|
|
479
|
+
export function arrayPush(segments, value, tree = dataTree) {
|
|
510
480
|
const arr = getArrayNode(segments, tree, true);
|
|
511
|
-
|
|
512
|
-
const result = arr.push(value);
|
|
513
|
-
emitModelEvent(segments.concat(index), undefined, { op: 'arrayPush', index }, tree, eventContext);
|
|
514
|
-
return result;
|
|
481
|
+
return arr.push(value);
|
|
515
482
|
}
|
|
516
|
-
export function arrayUnshift(segments, value, tree = dataTree
|
|
483
|
+
export function arrayUnshift(segments, value, tree = dataTree) {
|
|
517
484
|
const arr = getArrayNode(segments, tree, true);
|
|
518
|
-
|
|
519
|
-
emitModelEvent(segments.concat(0), undefined, { op: 'arrayUnshift', index: 0 }, tree, eventContext);
|
|
520
|
-
return result;
|
|
485
|
+
return arr.unshift(value);
|
|
521
486
|
}
|
|
522
|
-
export function arrayInsert(segments, index, values, tree = dataTree
|
|
487
|
+
export function arrayInsert(segments, index, values, tree = dataTree) {
|
|
523
488
|
const arr = getArrayNode(segments, tree, true);
|
|
524
489
|
const inserted = Array.isArray(values) ? values : [values];
|
|
525
490
|
arr.splice(index, 0, ...inserted);
|
|
526
|
-
for (let i = 0; i < inserted.length; i++) {
|
|
527
|
-
emitModelEvent(segments.concat(index + i), undefined, { op: 'arrayInsert', index: index + i }, tree, eventContext);
|
|
528
|
-
}
|
|
529
491
|
return arr.length;
|
|
530
492
|
}
|
|
531
|
-
export function arrayPop(segments, tree = dataTree
|
|
493
|
+
export function arrayPop(segments, tree = dataTree) {
|
|
532
494
|
const arr = getArrayNode(segments, tree, true);
|
|
533
495
|
if (!arr.length)
|
|
534
496
|
return;
|
|
535
|
-
|
|
536
|
-
const previous = arr.pop();
|
|
537
|
-
emitModelEvent(segments.concat(index), previous, { op: 'arrayPop', index }, tree, eventContext);
|
|
538
|
-
return previous;
|
|
497
|
+
return arr.pop();
|
|
539
498
|
}
|
|
540
|
-
export function arrayShift(segments, tree = dataTree
|
|
499
|
+
export function arrayShift(segments, tree = dataTree) {
|
|
541
500
|
const arr = getArrayNode(segments, tree, true);
|
|
542
501
|
if (!arr.length)
|
|
543
502
|
return;
|
|
544
|
-
|
|
545
|
-
emitModelEvent(segments.concat(0), previous, { op: 'arrayShift', index: 0 }, tree, eventContext);
|
|
546
|
-
return previous;
|
|
503
|
+
return arr.shift();
|
|
547
504
|
}
|
|
548
|
-
export function arrayRemove(segments, index, howMany = 1, tree = dataTree
|
|
505
|
+
export function arrayRemove(segments, index, howMany = 1, tree = dataTree) {
|
|
549
506
|
const arr = getArrayNode(segments, tree, true);
|
|
550
|
-
|
|
551
|
-
for (let i = 0; i < removed.length; i++) {
|
|
552
|
-
emitModelEvent(segments.concat(index + i), removed[i], { op: 'arrayRemove', index: index + i, howMany }, tree, eventContext);
|
|
553
|
-
}
|
|
554
|
-
return removed;
|
|
507
|
+
return arr.splice(index, howMany);
|
|
555
508
|
}
|
|
556
|
-
export function arrayMove(segments, from, to, howMany = 1, tree = dataTree
|
|
509
|
+
export function arrayMove(segments, from, to, howMany = 1, tree = dataTree) {
|
|
557
510
|
const arr = getArrayNode(segments, tree, true);
|
|
558
|
-
const prevValue = shouldEmitModelEvents(tree, eventContext) ? arr.slice() : undefined;
|
|
559
511
|
const len = arr.length;
|
|
560
512
|
if (from < 0)
|
|
561
513
|
from += len;
|
|
@@ -563,7 +515,6 @@ export function arrayMove(segments, from, to, howMany = 1, tree = dataTree, even
|
|
|
563
515
|
to += len;
|
|
564
516
|
const moved = arr.splice(from, howMany);
|
|
565
517
|
arr.splice(to, 0, ...moved);
|
|
566
|
-
emitModelEvent(segments, prevValue, { op: 'arrayMove', from, to, howMany }, tree, eventContext);
|
|
567
518
|
return moved;
|
|
568
519
|
}
|
|
569
520
|
export async function incrementPublic(segments, byNumber) {
|
|
@@ -732,7 +683,7 @@ export async function arrayMovePublic(segments, from, to, howMany = 1) {
|
|
|
732
683
|
doc.submitOp(op, err => err ? reject(err) : resolve(moved));
|
|
733
684
|
});
|
|
734
685
|
}
|
|
735
|
-
export function stringInsertLocal(segments, index, text, tree = dataTree
|
|
686
|
+
export function stringInsertLocal(segments, index, text, tree = dataTree) {
|
|
736
687
|
let dataNode = getWritableTree(tree);
|
|
737
688
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
738
689
|
const segment = segments[i];
|
|
@@ -745,17 +696,15 @@ export function stringInsertLocal(segments, index, text, tree = dataTree, eventC
|
|
|
745
696
|
const previous = dataNode[key];
|
|
746
697
|
if (previous == null) {
|
|
747
698
|
dataNode[key] = text;
|
|
748
|
-
emitModelEvent(segments, previous, { op: 'stringInsert', index }, tree, eventContext);
|
|
749
699
|
return previous;
|
|
750
700
|
}
|
|
751
701
|
if (typeof previous !== 'string') {
|
|
752
702
|
throw Error(`Expected string at ${segments.join('.')}`);
|
|
753
703
|
}
|
|
754
704
|
dataNode[key] = previous.slice(0, index) + text + previous.slice(index);
|
|
755
|
-
emitModelEvent(segments, previous, { op: 'stringInsert', index }, tree, eventContext);
|
|
756
705
|
return previous;
|
|
757
706
|
}
|
|
758
|
-
export function stringRemoveLocal(segments, index, howMany, tree = dataTree
|
|
707
|
+
export function stringRemoveLocal(segments, index, howMany, tree = dataTree) {
|
|
759
708
|
let dataNode = getWritableTree(tree);
|
|
760
709
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
761
710
|
const segment = segments[i];
|
|
@@ -771,7 +720,6 @@ export function stringRemoveLocal(segments, index, howMany, tree = dataTree, eve
|
|
|
771
720
|
throw Error(`Expected string at ${segments.join('.')}`);
|
|
772
721
|
}
|
|
773
722
|
dataNode[key] = previous.slice(0, index) + previous.slice(index + howMany);
|
|
774
|
-
emitModelEvent(segments, previous, { op: 'stringRemove', index, howMany }, tree, eventContext);
|
|
775
723
|
return previous;
|
|
776
724
|
}
|
|
777
725
|
export async function stringInsertPublic(segments, index, text) {
|
|
@@ -27,7 +27,6 @@ async function runDispose(rootId) {
|
|
|
27
27
|
const context = getRootContext(rootId, false);
|
|
28
28
|
if (!context)
|
|
29
29
|
return;
|
|
30
|
-
context.resetModelListeners();
|
|
31
30
|
for (const transportHash of Array.from(context.queryRuntimeHashes)) {
|
|
32
31
|
await querySubscriptions.destroyByRuntimeHash(transportHash, { rootId, force: true });
|
|
33
32
|
}
|
|
@@ -2,15 +2,9 @@ import type { PathSegment } from './types/path.js';
|
|
|
2
2
|
type RootId = string | null | undefined;
|
|
3
3
|
type DataTree = Record<string | number, unknown>;
|
|
4
4
|
type RuntimeKind = 'query' | 'aggregation';
|
|
5
|
-
type ModelEventStore = Map<string, unknown>;
|
|
6
5
|
interface RootContextOptions {
|
|
7
6
|
fetchOnly?: boolean;
|
|
8
7
|
}
|
|
9
|
-
interface ModelListeners {
|
|
10
|
-
change: ModelEventStore;
|
|
11
|
-
all: ModelEventStore;
|
|
12
|
-
[eventName: string]: ModelEventStore;
|
|
13
|
-
}
|
|
14
8
|
export interface DirectDocSubscriptionEntry {
|
|
15
9
|
segments: PathSegment[];
|
|
16
10
|
count: number;
|
|
@@ -21,13 +15,11 @@ export default class RootContext {
|
|
|
21
15
|
fetchOnly: boolean;
|
|
22
16
|
privateDataRaw: DataTree;
|
|
23
17
|
privateData: DataTree;
|
|
24
|
-
readonly modelListeners: ModelListeners;
|
|
25
18
|
readonly queryRuntimeHashes: Set<string>;
|
|
26
19
|
readonly aggregationRuntimeHashes: Set<string>;
|
|
27
20
|
readonly signalHashes: Set<string>;
|
|
28
21
|
readonly directDocSubscriptions: Map<string, DirectDocSubscriptionEntry>;
|
|
29
22
|
constructor(rootId: RootId, { fetchOnly }?: RootContextOptions);
|
|
30
|
-
getModelEventStore(eventName: string, create?: boolean): ModelEventStore;
|
|
31
23
|
getFetchOnly(): boolean;
|
|
32
24
|
setFetchOnly(value: boolean): void;
|
|
33
25
|
getPrivateDataRoot(): DataTree;
|
|
@@ -43,7 +35,6 @@ export default class RootContext {
|
|
|
43
35
|
unregisterSignalHash(signalHash: string | null | undefined): void;
|
|
44
36
|
registerDirectDocSubscription(hash: string | null | undefined, segments: readonly PathSegment[], token?: unknown): void;
|
|
45
37
|
unregisterDirectDocSubscription(hash: string | null | undefined, token?: unknown): void;
|
|
46
|
-
resetModelListeners(): void;
|
|
47
38
|
resetRuntimeHashes(): void;
|
|
48
39
|
resetPrivateData(): void;
|
|
49
40
|
resetSignalHashes(): void;
|
package/dist/orm/rootContext.js
CHANGED
|
@@ -12,10 +12,6 @@ export default class RootContext {
|
|
|
12
12
|
fetchOnly;
|
|
13
13
|
privateDataRaw;
|
|
14
14
|
privateData;
|
|
15
|
-
modelListeners = {
|
|
16
|
-
change: new Map(),
|
|
17
|
-
all: new Map()
|
|
18
|
-
};
|
|
19
15
|
queryRuntimeHashes = new Set();
|
|
20
16
|
aggregationRuntimeHashes = new Set();
|
|
21
17
|
signalHashes = new Set();
|
|
@@ -26,14 +22,6 @@ export default class RootContext {
|
|
|
26
22
|
this.privateDataRaw = {};
|
|
27
23
|
this.privateData = observable(this.privateDataRaw);
|
|
28
24
|
}
|
|
29
|
-
getModelEventStore(eventName, create = false) {
|
|
30
|
-
let store = this.modelListeners[eventName];
|
|
31
|
-
if (!store && create) {
|
|
32
|
-
store = new Map();
|
|
33
|
-
this.modelListeners[eventName] = store;
|
|
34
|
-
}
|
|
35
|
-
return store;
|
|
36
|
-
}
|
|
37
25
|
getFetchOnly() {
|
|
38
26
|
return !!this.fetchOnly;
|
|
39
27
|
}
|
|
@@ -122,11 +110,6 @@ export default class RootContext {
|
|
|
122
110
|
if (entry.count === 0)
|
|
123
111
|
this.directDocSubscriptions.delete(hash);
|
|
124
112
|
}
|
|
125
|
-
resetModelListeners() {
|
|
126
|
-
for (const store of Object.values(this.modelListeners)) {
|
|
127
|
-
store.clear();
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
113
|
resetRuntimeHashes() {
|
|
131
114
|
this.queryRuntimeHashes.clear();
|
|
132
115
|
this.aggregationRuntimeHashes.clear();
|
|
@@ -143,7 +126,6 @@ export default class RootContext {
|
|
|
143
126
|
}
|
|
144
127
|
isRuntimeEmpty() {
|
|
145
128
|
return (isPlainObjectEmpty(this.privateData) &&
|
|
146
|
-
Object.values(this.modelListeners).every(store => store.size === 0) &&
|
|
147
129
|
this.queryRuntimeHashes.size === 0 &&
|
|
148
130
|
this.aggregationRuntimeHashes.size === 0 &&
|
|
149
131
|
this.signalHashes.size === 0 &&
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export function createBackend(options?: {}): any;
|
|
2
|
-
export function initConnection(backend: any, { fetchOnly,
|
|
2
|
+
export function initConnection(backend: any, { fetchOnly, idFields, ...options }?: {
|
|
3
3
|
fetchOnly?: boolean | undefined;
|
|
4
|
-
publicOnly?: boolean | undefined;
|
|
5
4
|
}): {
|
|
6
5
|
middleware: (req: any, res: any, next: any) => Promise<any>;
|
|
7
6
|
upgrade: (req: any, socket: any, upgradeHead: any) => Promise<void>;
|
package/dist/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import createChannel from '@teamplay/channel/server';
|
|
2
2
|
import backendCreateBackend from '@teamplay/backend';
|
|
3
3
|
import { getModels } from "./orm/initModels.js";
|
|
4
|
-
import { connection, setConnection, setDefaultFetchOnly
|
|
4
|
+
import { connection, setConnection, setDefaultFetchOnly } from "./orm/connection.js";
|
|
5
5
|
import { configureTeamplay } from "./config.js";
|
|
6
6
|
export { default as ShareDB } from 'sharedb';
|
|
7
7
|
export { mongo, mongoClient, createMongoIndex, redis, redlock, sqlite, getRedis, Redis, getRedisOptions, redisPrefix, generateRedisPrefix } from '@teamplay/backend';
|
|
@@ -17,7 +17,7 @@ export function createBackend(options = {}) {
|
|
|
17
17
|
return backendCreateBackend(nextOptions);
|
|
18
18
|
}
|
|
19
19
|
export default createBackend;
|
|
20
|
-
export function initConnection(backend, { fetchOnly = true,
|
|
20
|
+
export function initConnection(backend, { fetchOnly = true, idFields, ...options } = {}) {
|
|
21
21
|
if (!backend)
|
|
22
22
|
throw Error('backend is required');
|
|
23
23
|
if (connection)
|
|
@@ -26,6 +26,5 @@ export function initConnection(backend, { fetchOnly = true, publicOnly = true, i
|
|
|
26
26
|
configureTeamplay({ idFields });
|
|
27
27
|
setConnection(backend.connect());
|
|
28
28
|
setDefaultFetchOnly(fetchOnly);
|
|
29
|
-
setPublicOnly(publicOnly);
|
|
30
29
|
return createChannel(backend, options);
|
|
31
30
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamplay",
|
|
3
|
-
"version": "0.5.0-alpha.
|
|
3
|
+
"version": "0.5.0-alpha.36",
|
|
4
4
|
"description": "Full-stack signals ORM with multiplayer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -138,5 +138,6 @@
|
|
|
138
138
|
"<rootDir>/test_client/helpers"
|
|
139
139
|
]
|
|
140
140
|
},
|
|
141
|
-
"license": "MIT"
|
|
141
|
+
"license": "MIT",
|
|
142
|
+
"gitHead": "c83e516afe64e94e7703529d04aed73ac3b27bfa"
|
|
142
143
|
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export function isModelEventsEnabled(): boolean;
|
|
2
|
-
export function normalizePattern(pattern: any, methodName: any): string | null;
|
|
3
|
-
export function onModelEvent(rootId: any, eventName: any, pattern: any, handler: any): any;
|
|
4
|
-
export function removeModelListener(rootId: any, eventName: any, handler: any): void;
|
|
5
|
-
export function emitModelChange(path: any, value: any, prevValue: any, meta: any): void;
|
|
6
|
-
export function __resetModelEventsForTests(): void;
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { isCompatEnv } from '../compatEnv.js';
|
|
2
|
-
import { isSilentContextActive, isModelEventsSilentContextActive } from './silentContext.js';
|
|
3
|
-
import { normalizeRootId } from "../rootScope.js";
|
|
4
|
-
import { getRootContext, getRootContexts } from "../rootContext.js";
|
|
5
|
-
const MODEL_EVENT_NAMES = ['change', 'all'];
|
|
6
|
-
export function isModelEventsEnabled() {
|
|
7
|
-
return isCompatEnv();
|
|
8
|
-
}
|
|
9
|
-
export function normalizePattern(pattern, methodName) {
|
|
10
|
-
if (pattern && typeof pattern.path === 'function')
|
|
11
|
-
pattern = pattern.path();
|
|
12
|
-
if (pattern == null || typeof pattern !== 'string') {
|
|
13
|
-
if (methodName)
|
|
14
|
-
throw Error(`${methodName} expects a string path or a signal`);
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
return pattern.split('.').filter(Boolean).join('.');
|
|
18
|
-
}
|
|
19
|
-
export function onModelEvent(rootId, eventName, pattern, handler) {
|
|
20
|
-
if (typeof handler !== 'function')
|
|
21
|
-
throw Error('Model event handler must be a function');
|
|
22
|
-
if (!MODEL_EVENT_NAMES.includes(eventName))
|
|
23
|
-
throw Error(`Unsupported model event: ${eventName}`);
|
|
24
|
-
const store = getModelEventRootStore(eventName, rootId, true);
|
|
25
|
-
const normalized = normalizePattern(pattern);
|
|
26
|
-
let entry = store.get(normalized);
|
|
27
|
-
if (!entry) {
|
|
28
|
-
entry = {
|
|
29
|
-
pattern: normalized,
|
|
30
|
-
segments: splitPattern(normalized),
|
|
31
|
-
handlers: new Set()
|
|
32
|
-
};
|
|
33
|
-
store.set(normalized, entry);
|
|
34
|
-
}
|
|
35
|
-
entry.handlers.add(handler);
|
|
36
|
-
return handler;
|
|
37
|
-
}
|
|
38
|
-
export function removeModelListener(rootId, eventName, handler) {
|
|
39
|
-
const store = getModelEventRootStore(eventName, rootId);
|
|
40
|
-
if (!store)
|
|
41
|
-
return;
|
|
42
|
-
for (const [pattern, entry] of store) {
|
|
43
|
-
entry.handlers.delete(handler);
|
|
44
|
-
if (!entry.handlers.size)
|
|
45
|
-
store.delete(pattern);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
export function emitModelChange(path, value, prevValue, meta) {
|
|
49
|
-
if (!isModelEventsEnabled())
|
|
50
|
-
return;
|
|
51
|
-
if (isSilentContextActive() || isModelEventsSilentContextActive())
|
|
52
|
-
return;
|
|
53
|
-
const initialSegments = splitPath(path);
|
|
54
|
-
const eventName = meta?.eventName || 'change';
|
|
55
|
-
const rootIds = getTargetRootIds(meta?.rootId);
|
|
56
|
-
for (const rootId of rootIds) {
|
|
57
|
-
emitForEvent(rootId, 'change', initialSegments, value, prevValue, meta);
|
|
58
|
-
emitForEvent(rootId, 'all', initialSegments, value, prevValue, meta, eventName);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
export function __resetModelEventsForTests() {
|
|
62
|
-
for (const context of getRootContexts()) {
|
|
63
|
-
context.resetModelListeners();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function emitForEvent(rootId, eventName, pathSegments, value, prevValue, meta, resolvedEventName = eventName) {
|
|
67
|
-
const store = getModelEventRootStore(eventName, rootId);
|
|
68
|
-
if (!store || store.size === 0)
|
|
69
|
-
return;
|
|
70
|
-
for (const entry of store.values()) {
|
|
71
|
-
const captures = matchPattern(entry.segments, pathSegments);
|
|
72
|
-
if (!captures)
|
|
73
|
-
continue;
|
|
74
|
-
for (const handler of entry.handlers) {
|
|
75
|
-
if (eventName === 'all') {
|
|
76
|
-
handler(...captures, resolvedEventName, value, prevValue, meta);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
handler(...captures, value, prevValue, meta);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function splitPattern(pattern) {
|
|
85
|
-
if (!pattern)
|
|
86
|
-
return [];
|
|
87
|
-
return pattern.split('.').filter(Boolean);
|
|
88
|
-
}
|
|
89
|
-
function getModelEventRootStore(eventName, rootId, create = false) {
|
|
90
|
-
return getRootContext(normalizeRootId(rootId), create)?.getModelEventStore(eventName, create);
|
|
91
|
-
}
|
|
92
|
-
function getModelEventRootIds() {
|
|
93
|
-
const rootIds = new Set();
|
|
94
|
-
for (const context of getRootContexts()) {
|
|
95
|
-
for (const store of Object.values(context.modelListeners)) {
|
|
96
|
-
if (store.size)
|
|
97
|
-
rootIds.add(context.rootId);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return rootIds;
|
|
101
|
-
}
|
|
102
|
-
function getTargetRootIds(rootId) {
|
|
103
|
-
if (rootId != null)
|
|
104
|
-
return [normalizeRootId(rootId)];
|
|
105
|
-
return getModelEventRootIds();
|
|
106
|
-
}
|
|
107
|
-
function splitPath(path) {
|
|
108
|
-
if (Array.isArray(path))
|
|
109
|
-
return path.map(segment => String(segment));
|
|
110
|
-
if (!path)
|
|
111
|
-
return [];
|
|
112
|
-
return String(path).split('.').filter(Boolean);
|
|
113
|
-
}
|
|
114
|
-
function matchPattern(patternSegments, pathSegments) {
|
|
115
|
-
function walk(patternIndex, pathIndex) {
|
|
116
|
-
if (patternIndex === patternSegments.length) {
|
|
117
|
-
return pathIndex === pathSegments.length ? [] : null;
|
|
118
|
-
}
|
|
119
|
-
const segment = patternSegments[patternIndex];
|
|
120
|
-
if (segment === '**') {
|
|
121
|
-
for (let i = pathIndex; i <= pathSegments.length; i++) {
|
|
122
|
-
const rest = walk(patternIndex + 1, i);
|
|
123
|
-
if (rest !== null) {
|
|
124
|
-
const capture = pathSegments.slice(pathIndex, i).join('.');
|
|
125
|
-
return [capture, ...rest];
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
if (pathIndex >= pathSegments.length)
|
|
131
|
-
return null;
|
|
132
|
-
if (segment === '*') {
|
|
133
|
-
const rest = walk(patternIndex + 1, pathIndex + 1);
|
|
134
|
-
if (rest === null)
|
|
135
|
-
return null;
|
|
136
|
-
return [pathSegments[pathIndex], ...rest];
|
|
137
|
-
}
|
|
138
|
-
if (segment !== pathSegments[pathIndex])
|
|
139
|
-
return null;
|
|
140
|
-
return walk(patternIndex + 1, pathIndex + 1);
|
|
141
|
-
}
|
|
142
|
-
return walk(0, 0);
|
|
143
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
let modelEventsSilentDepth = 0;
|
|
2
|
-
export function isSilentContextActive() {
|
|
3
|
-
return false;
|
|
4
|
-
}
|
|
5
|
-
export function isModelEventsSilentContextActive() {
|
|
6
|
-
return modelEventsSilentDepth > 0;
|
|
7
|
-
}
|
|
8
|
-
export function runInModelEventsSilentContext(fn) {
|
|
9
|
-
modelEventsSilentDepth += 1;
|
|
10
|
-
try {
|
|
11
|
-
return fn();
|
|
12
|
-
}
|
|
13
|
-
finally {
|
|
14
|
-
modelEventsSilentDepth -= 1;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export function __resetSilentContextForTests() {
|
|
18
|
-
modelEventsSilentDepth = 0;
|
|
19
|
-
}
|