teamplay 0.4.0 → 0.5.0-alpha.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/babel-loader.cjs +1 -0
- package/babel.cjs +1 -0
- package/dist/connect/index.d.ts +1 -0
- package/dist/connect/index.js +9 -0
- package/dist/connect/lib/sharedb-crosstab-pubsub.d.cts +10 -0
- package/dist/connect/offline/index.d.ts +1 -0
- package/dist/connect/offline/index.js +126 -0
- package/dist/connect/offline/react-native.d.ts +10 -0
- package/dist/connect/offline/react-native.js +25 -0
- package/dist/connect/offline/web.d.ts +9 -0
- package/dist/connect/offline/web.js +12 -0
- package/dist/connect/sharedbConnection.d.cts +2 -0
- package/dist/connect/test.d.ts +1 -0
- package/dist/connect/test.js +12 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +74 -0
- package/dist/orm/$.d.ts +9 -0
- package/dist/orm/$.js +34 -0
- package/dist/orm/Aggregation.d.ts +17 -0
- package/dist/orm/Aggregation.js +115 -0
- package/dist/orm/Cache.d.ts +9 -0
- package/dist/orm/Cache.js +32 -0
- package/dist/orm/Compat/SignalCompat.d.ts +3 -0
- package/dist/orm/Compat/SignalCompat.js +1542 -0
- package/dist/orm/Compat/eventsCompat.d.ts +3 -0
- package/dist/orm/Compat/eventsCompat.js +73 -0
- package/dist/orm/Compat/hooksCompat.d.ts +33 -0
- package/dist/orm/Compat/hooksCompat.js +360 -0
- package/dist/orm/Compat/modelEvents.d.ts +6 -0
- package/dist/orm/Compat/modelEvents.js +228 -0
- package/dist/orm/Compat/queryReadiness.d.ts +5 -0
- package/dist/orm/Compat/queryReadiness.js +185 -0
- package/dist/orm/Compat/refFallback.d.ts +13 -0
- package/dist/orm/Compat/refFallback.js +65 -0
- package/dist/orm/Compat/refRegistry.d.ts +6 -0
- package/dist/orm/Compat/refRegistry.js +54 -0
- package/dist/orm/Compat/silentContext.d.ts +5 -0
- package/dist/orm/Compat/silentContext.js +48 -0
- package/dist/orm/Compat/startStopCompat.d.ts +3 -0
- package/dist/orm/Compat/startStopCompat.js +217 -0
- package/dist/orm/Doc.d.ts +96 -0
- package/dist/orm/Doc.js +966 -0
- package/dist/orm/Query.d.ts +117 -0
- package/dist/orm/Query.js +1111 -0
- package/dist/orm/Reaction.d.ts +10 -0
- package/dist/orm/Reaction.js +41 -0
- package/dist/orm/Root.d.ts +22 -0
- package/dist/orm/Root.js +85 -0
- package/dist/orm/Signal.d.ts +12 -0
- package/dist/orm/Signal.js +7 -0
- package/dist/orm/SignalBase.d.ts +168 -0
- package/dist/orm/SignalBase.js +625 -0
- package/dist/orm/SubscriptionState.d.ts +17 -0
- package/dist/orm/SubscriptionState.js +123 -0
- package/dist/orm/Value.d.ts +9 -0
- package/dist/orm/Value.js +25 -0
- package/dist/orm/addModel.d.ts +6 -0
- package/dist/orm/addModel.js +39 -0
- package/dist/orm/associations.d.ts +18 -0
- package/dist/orm/associations.js +70 -0
- package/dist/orm/batchScheduler.d.ts +7 -0
- package/dist/orm/batchScheduler.js +62 -0
- package/dist/orm/compatEnv.d.ts +1 -0
- package/dist/orm/compatEnv.js +4 -0
- package/dist/orm/connection.d.ts +26 -0
- package/dist/orm/connection.js +38 -0
- package/dist/orm/dataTree.d.ts +34 -0
- package/dist/orm/dataTree.js +880 -0
- package/dist/orm/disposeRootContext.d.ts +4 -0
- package/dist/orm/disposeRootContext.js +59 -0
- package/dist/orm/getSignal.d.ts +16 -0
- package/dist/orm/getSignal.js +133 -0
- package/dist/orm/idFields.d.ts +14 -0
- package/dist/orm/idFields.js +95 -0
- package/dist/orm/index.d.ts +7 -0
- package/dist/orm/index.js +6 -0
- package/dist/orm/initModels.d.ts +5 -0
- package/dist/orm/initModels.js +74 -0
- package/dist/orm/missingDoc.d.ts +1 -0
- package/dist/orm/missingDoc.js +3 -0
- package/dist/orm/pluralize.d.ts +12 -0
- package/dist/orm/privateData.d.ts +22 -0
- package/dist/orm/privateData.js +170 -0
- package/dist/orm/rootContext.d.ts +78 -0
- package/dist/orm/rootContext.js +297 -0
- package/dist/orm/rootScope.d.ts +12 -0
- package/dist/orm/rootScope.js +46 -0
- package/dist/orm/signalArrayReaders.d.ts +22 -0
- package/dist/orm/signalArrayReaders.js +42 -0
- package/dist/orm/signalMetadata.d.ts +17 -0
- package/dist/orm/signalMetadata.js +56 -0
- package/dist/orm/signalMutationGuards.d.ts +4 -0
- package/dist/orm/signalMutationGuards.js +14 -0
- package/dist/orm/signalPathKind.d.ts +2 -0
- package/dist/orm/signalPathKind.js +10 -0
- package/dist/orm/signalPathRules.d.ts +6 -0
- package/dist/orm/signalPathRules.js +28 -0
- package/dist/orm/signalReads.d.ts +26 -0
- package/dist/orm/signalReads.js +64 -0
- package/dist/orm/signalRuntimeAccess.d.ts +16 -0
- package/dist/orm/signalRuntimeAccess.js +24 -0
- package/dist/orm/signalRuntimeDescriptor.d.ts +19 -0
- package/dist/orm/signalRuntimeDescriptor.js +97 -0
- package/dist/orm/signalStorageMutations.d.ts +18 -0
- package/dist/orm/signalStorageMutations.js +26 -0
- package/dist/orm/signalSymbols.d.ts +5 -0
- package/dist/orm/signalSymbols.js +5 -0
- package/dist/orm/signalValueMutations.d.ts +14 -0
- package/dist/orm/signalValueMutations.js +36 -0
- package/dist/orm/sub.d.ts +37 -0
- package/dist/orm/sub.js +187 -0
- package/dist/orm/subscriptionGcDelay.d.ts +4 -0
- package/dist/orm/subscriptionGcDelay.js +26 -0
- package/dist/orm/types/baseMethods.d.ts +43 -0
- package/dist/orm/types/baseMethods.js +1 -0
- package/dist/orm/types/jsonSchema.d.ts +75 -0
- package/dist/orm/types/jsonSchema.js +1 -0
- package/dist/orm/types/modelManifest.d.ts +37 -0
- package/dist/orm/types/modelManifest.js +1 -0
- package/dist/orm/types/path.d.ts +8 -0
- package/dist/orm/types/path.js +1 -0
- package/dist/orm/types/query.d.ts +29 -0
- package/dist/orm/types/query.js +1 -0
- package/dist/orm/types/signal.d.ts +132 -0
- package/dist/orm/types/signal.js +1 -0
- package/dist/react/compatComponentRegistry.d.ts +4 -0
- package/dist/react/compatComponentRegistry.js +19 -0
- package/dist/react/convertToObserver.d.ts +26 -0
- package/dist/react/convertToObserver.js +114 -0
- package/dist/react/executionContextTracker.d.ts +11 -0
- package/dist/react/executionContextTracker.js +28 -0
- package/dist/react/helpers.d.ts +34 -0
- package/dist/react/helpers.js +134 -0
- package/dist/react/observer.d.ts +22 -0
- package/dist/react/observer.js +8 -0
- package/dist/react/promiseBatcher.d.ts +13 -0
- package/dist/react/promiseBatcher.js +118 -0
- package/dist/react/renderAttemptDestroyer.d.ts +19 -0
- package/dist/react/renderAttemptDestroyer.js +46 -0
- package/dist/react/trapRender.d.ts +6 -0
- package/dist/react/trapRender.js +48 -0
- package/dist/react/universal$.d.ts +1 -0
- package/dist/react/universal$.js +18 -0
- package/dist/react/universalSub.d.ts +1 -0
- package/dist/react/universalSub.js +22 -0
- package/dist/react/useApi.d.ts +13 -0
- package/dist/react/useApi.js +67 -0
- package/dist/react/useSub.d.ts +102 -0
- package/dist/react/useSub.js +189 -0
- package/dist/react/useSuspendMemo.d.ts +3 -0
- package/dist/react/useSuspendMemo.js +102 -0
- package/dist/react/wrapIntoSuspense.d.ts +9 -0
- package/dist/react/wrapIntoSuspense.js +102 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +28 -0
- package/dist/utils/MockFinalizationRegistry.d.ts +37 -0
- package/dist/utils/MockFinalizationRegistry.js +85 -0
- package/dist/utils/MockWeakRef.d.ts +12 -0
- package/dist/utils/MockWeakRef.js +23 -0
- package/dist/utils/isServer.d.ts +3 -0
- package/dist/utils/isServer.js +18 -0
- package/dist/utils/setDiffDeep.d.ts +1 -0
- package/dist/utils/setDiffDeep.js +61 -0
- package/dist/utils/useIsomorphicLayoutEffect.d.ts +3 -0
- package/dist/utils/useIsomorphicLayoutEffect.js +3 -0
- package/file-based-models.js +3 -0
- package/file-based-models.node.js +6 -0
- package/package.json +77 -32
- package/teamplay.models.auto-init.virtual.js +1 -0
- package/teamplay.models.virtual.js +1 -0
- package/connect/index.js +0 -9
- package/connect/offline/index.js +0 -124
- package/connect/offline/react-native.js +0 -28
- package/connect/offline/web.js +0 -15
- package/connect/test.js +0 -12
- package/index.d.ts +0 -106
- package/index.js +0 -125
- package/orm/$.js +0 -38
- package/orm/Aggregation.js +0 -117
- package/orm/Cache.js +0 -46
- package/orm/Compat/README.md +0 -1064
- package/orm/Compat/SignalCompat.js +0 -1479
- package/orm/Compat/eventsCompat.js +0 -79
- package/orm/Compat/hooksCompat.js +0 -374
- package/orm/Compat/modelEvents.js +0 -225
- package/orm/Compat/queryReadiness.js +0 -191
- package/orm/Compat/refFallback.js +0 -62
- package/orm/Compat/refRegistry.js +0 -61
- package/orm/Compat/silentContext.js +0 -51
- package/orm/Compat/startStopCompat.js +0 -207
- package/orm/Doc.js +0 -969
- package/orm/Query.js +0 -1127
- package/orm/Reaction.js +0 -48
- package/orm/Root.js +0 -88
- package/orm/Signal.js +0 -22
- package/orm/SignalBase.js +0 -696
- package/orm/SubscriptionState.js +0 -138
- package/orm/Value.js +0 -30
- package/orm/addModel.js +0 -31
- package/orm/associations.js +0 -97
- package/orm/batchScheduler.js +0 -62
- package/orm/compatEnv.js +0 -4
- package/orm/connection.js +0 -46
- package/orm/dataTree.js +0 -869
- package/orm/disposeRootContext.js +0 -68
- package/orm/getSignal.js +0 -130
- package/orm/idFields.js +0 -88
- package/orm/index.d.ts +0 -6
- package/orm/index.js +0 -5
- package/orm/missingDoc.js +0 -3
- package/orm/privateData.js +0 -181
- package/orm/rootContext.js +0 -313
- package/orm/rootScope.js +0 -51
- package/orm/sub.js +0 -151
- package/orm/subscriptionGcDelay.js +0 -32
- package/react/compatComponentRegistry.js +0 -20
- package/react/convertToObserver.js +0 -117
- package/react/executionContextTracker.js +0 -32
- package/react/helpers.js +0 -141
- package/react/observer.js +0 -9
- package/react/promiseBatcher.js +0 -115
- package/react/renderAttemptDestroyer.js +0 -47
- package/react/trapRender.js +0 -50
- package/react/universal$.js +0 -18
- package/react/universalSub.js +0 -21
- package/react/useApi.js +0 -63
- package/react/useSub.js +0 -169
- package/react/useSuspendMemo.js +0 -96
- package/react/wrapIntoSuspense.js +0 -119
- package/server.js +0 -31
- package/utils/MockFinalizationRegistry.js +0 -94
- package/utils/MockWeakRef.js +0 -25
- package/utils/isServer.js +0 -17
- package/utils/setDiffDeep.js +0 -58
- package/utils/useIsomorphicLayoutEffect.js +0 -4
- /package/{connect → dist/connect}/lib/sharedb-crosstab-pubsub.cjs +0 -0
- /package/{connect → dist/connect}/sharedbConnection.cjs +0 -0
|
@@ -0,0 +1,1542 @@
|
|
|
1
|
+
import { raw, observe, unobserve } from '@nx-js/observer-util';
|
|
2
|
+
import arrayDiff from 'arraydiff';
|
|
3
|
+
import { Signal, GETTERS, DEFAULT_GETTERS, SEGMENTS, isPublicCollection, isPublicCollectionSignal, isPublicDocumentSignal } from "../SignalBase.js";
|
|
4
|
+
import { getRoot, ROOT, ROOT_ID, getRootSignal, GLOBAL_ROOT_ID, unregisterRootFinalizer } from "../Root.js";
|
|
5
|
+
import { isPrivateMutationForbidden } from "../connection.js";
|
|
6
|
+
import { docSubscriptions } from '../Doc.js';
|
|
7
|
+
import { IS_QUERY, getQuerySignal, querySubscriptions } from '../Query.js';
|
|
8
|
+
import { IS_AGGREGATION, aggregationSubscriptions, getAggregationSignal } from '../Aggregation.js';
|
|
9
|
+
import { getIdFieldsForSegments, isIdFieldPath, isPublicDocPath, normalizeIdFields, isPlainObject } from "../idFields.js";
|
|
10
|
+
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';
|
|
11
|
+
import { on as onCustomEvent, removeListener as removeCustomEventListener } from './eventsCompat.js';
|
|
12
|
+
import { waitForImperativeQueryReady } from './queryReadiness.js';
|
|
13
|
+
import { isModelEventsEnabled, normalizePattern, onModelEvent, removeModelListener } from './modelEvents.js';
|
|
14
|
+
import { setRefLink, removeRefLink, getAllRefLinks } from './refRegistry.js';
|
|
15
|
+
import { REF_TARGET, resolveRefSignalSafe, resolveRefSegmentsSafe } from './refFallback.js';
|
|
16
|
+
import { runInBatch } from '../batchScheduler.js';
|
|
17
|
+
import { runInSilentContext, runInModelEventsSilentContext, isSilentContextActive } from './silentContext.js';
|
|
18
|
+
import universal$ from "../../react/universal$.js";
|
|
19
|
+
import { getRootContext } from "../rootContext.js";
|
|
20
|
+
import disposeRootContext from "../disposeRootContext.js";
|
|
21
|
+
import { arrayInsertPrivateData, arrayMovePrivateData, arrayPopPrivateData, arrayPushPrivateData, arrayRemovePrivateData, arrayShiftPrivateData, arrayUnshiftPrivateData, delPrivateData, setReplacePrivateData, stringInsertPrivateData, stringRemovePrivateData } from '../privateData.js';
|
|
22
|
+
class SignalCompat extends Signal {
|
|
23
|
+
static ID_FIELDS = ['_id', 'id'];
|
|
24
|
+
static [GETTERS] = [...DEFAULT_GETTERS, 'at', 'scope', 'getCopy', 'getDeepCopy'];
|
|
25
|
+
get root() {
|
|
26
|
+
return this.scope();
|
|
27
|
+
}
|
|
28
|
+
path(subpath) {
|
|
29
|
+
if (arguments.length > 1)
|
|
30
|
+
throw Error('Signal.path() expects a single argument');
|
|
31
|
+
if (arguments.length === 0)
|
|
32
|
+
return super.path();
|
|
33
|
+
const segments = parseAtSubpath(subpath, arguments.length, 'Signal.path()');
|
|
34
|
+
if (segments.length === 0)
|
|
35
|
+
return super.path();
|
|
36
|
+
return [...this[SEGMENTS], ...segments].join('.');
|
|
37
|
+
}
|
|
38
|
+
at(subpath) {
|
|
39
|
+
const segments = arguments.length > 1
|
|
40
|
+
? parseAtSegments(arguments, 'Signal.at()')
|
|
41
|
+
: parseAtSubpath(subpath, arguments.length, 'Signal.at()');
|
|
42
|
+
if (segments.length === 0)
|
|
43
|
+
return this;
|
|
44
|
+
return resolveRelativePathTarget(this, segments);
|
|
45
|
+
}
|
|
46
|
+
getId() {
|
|
47
|
+
const $target = resolveRefSignal(this);
|
|
48
|
+
if ($target !== this)
|
|
49
|
+
return $target.getId();
|
|
50
|
+
return super.getId();
|
|
51
|
+
}
|
|
52
|
+
getCollection() {
|
|
53
|
+
const $target = resolveRefSignal(this);
|
|
54
|
+
if ($target !== this)
|
|
55
|
+
return $target.getCollection();
|
|
56
|
+
return super.getCollection();
|
|
57
|
+
}
|
|
58
|
+
getCopy(subpath) {
|
|
59
|
+
if (arguments.length > 1)
|
|
60
|
+
throw Error('Signal.getCopy() expects a single argument');
|
|
61
|
+
const segments = parseAtSubpath(subpath, arguments.length, 'Signal.getCopy()');
|
|
62
|
+
const value = getSignalValueAt(this, segments);
|
|
63
|
+
return shallowCopy(value);
|
|
64
|
+
}
|
|
65
|
+
getDeepCopy(subpath) {
|
|
66
|
+
if (arguments.length > 1)
|
|
67
|
+
throw Error('Signal.getDeepCopy() expects a single argument');
|
|
68
|
+
const segments = parseAtSubpath(subpath, arguments.length, 'Signal.getDeepCopy()');
|
|
69
|
+
const value = getSignalValueAt(this, segments);
|
|
70
|
+
return deepCopy(value);
|
|
71
|
+
}
|
|
72
|
+
query(collection, params, options) {
|
|
73
|
+
if (arguments.length < 1 || arguments.length > 3)
|
|
74
|
+
throw Error('Signal.query() expects one to three arguments');
|
|
75
|
+
if (typeof collection !== 'string')
|
|
76
|
+
throw Error('Signal.query() expects collection to be a string');
|
|
77
|
+
const normalized = normalizeQueryParams(collection, params);
|
|
78
|
+
const root = getRoot(this) || (this[ROOT_ID] ? this : undefined);
|
|
79
|
+
const scopedOptions = withQueryScopeOptions(options, root);
|
|
80
|
+
if (isAggregationParams(normalized)) {
|
|
81
|
+
return getAggregationSignal(collection, normalized, scopedOptions);
|
|
82
|
+
}
|
|
83
|
+
return getQuerySignal(collection, normalized, scopedOptions);
|
|
84
|
+
}
|
|
85
|
+
subscribe(...items) {
|
|
86
|
+
if (items.length > 0)
|
|
87
|
+
return subscribeMany(items, 'subscribe');
|
|
88
|
+
return subscribeSelf(this);
|
|
89
|
+
}
|
|
90
|
+
unsubscribe(...items) {
|
|
91
|
+
if (items.length > 0)
|
|
92
|
+
return subscribeMany(items, 'unsubscribe');
|
|
93
|
+
return unsubscribeSelf(this);
|
|
94
|
+
}
|
|
95
|
+
fetch(...items) {
|
|
96
|
+
if (items.length > 0)
|
|
97
|
+
return subscribeMany(items, 'subscribe', 'fetch');
|
|
98
|
+
return subscribeSelf(this, 'fetch');
|
|
99
|
+
}
|
|
100
|
+
unfetch(...items) {
|
|
101
|
+
if (items.length > 0)
|
|
102
|
+
return subscribeMany(items, 'unsubscribe', 'fetch');
|
|
103
|
+
return unsubscribeSelf(this, 'fetch');
|
|
104
|
+
}
|
|
105
|
+
getExtra() {
|
|
106
|
+
if (arguments.length > 0)
|
|
107
|
+
throw Error('Signal.getExtra() does not accept any arguments');
|
|
108
|
+
if (this[IS_AGGREGATION])
|
|
109
|
+
return this.get();
|
|
110
|
+
if (this[IS_QUERY])
|
|
111
|
+
return this.extra.get();
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
close(callback) {
|
|
115
|
+
if (arguments.length > 1)
|
|
116
|
+
throw Error('Signal.close() expects zero or one argument');
|
|
117
|
+
if (callback != null && typeof callback !== 'function') {
|
|
118
|
+
throw Error('Signal.close() expects callback to be a function');
|
|
119
|
+
}
|
|
120
|
+
const $root = getRoot(this) || this;
|
|
121
|
+
const rootId = $root?.[ROOT_ID];
|
|
122
|
+
unregisterRootFinalizer($root);
|
|
123
|
+
disposeRootContext(rootId)
|
|
124
|
+
.then(() => callback?.())
|
|
125
|
+
.catch(err => {
|
|
126
|
+
if (callback)
|
|
127
|
+
callback(err);
|
|
128
|
+
else
|
|
129
|
+
console.error(err);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
silent(value) {
|
|
133
|
+
if (arguments.length > 1)
|
|
134
|
+
throw Error('Signal.silent() expects zero or one argument');
|
|
135
|
+
const enabled = value == null ? true : !!value;
|
|
136
|
+
return createSilentSignalWrapper(this, enabled);
|
|
137
|
+
}
|
|
138
|
+
get() {
|
|
139
|
+
if (arguments.length > 1) {
|
|
140
|
+
const segments = parseAtSegments(arguments, 'Signal.get()');
|
|
141
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
142
|
+
return Signal.prototype.get.call($target);
|
|
143
|
+
}
|
|
144
|
+
if (arguments.length === 1) {
|
|
145
|
+
if (arguments[0] == null) {
|
|
146
|
+
return Signal.prototype.get.apply(this, []);
|
|
147
|
+
}
|
|
148
|
+
const segments = parseAtSubpath(arguments[0], 1, 'Signal.get()');
|
|
149
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
150
|
+
return Signal.prototype.get.call($target);
|
|
151
|
+
}
|
|
152
|
+
return Signal.prototype.get.apply(this, arguments);
|
|
153
|
+
}
|
|
154
|
+
peek() {
|
|
155
|
+
if (arguments.length > 1) {
|
|
156
|
+
const segments = parseAtSegments(arguments, 'Signal.peek()');
|
|
157
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
158
|
+
return Signal.prototype.peek.call($target);
|
|
159
|
+
}
|
|
160
|
+
if (arguments.length === 1) {
|
|
161
|
+
if (arguments[0] == null) {
|
|
162
|
+
const $target = resolveRefSignal(this);
|
|
163
|
+
if ($target !== this)
|
|
164
|
+
return Signal.prototype.peek.apply($target, []);
|
|
165
|
+
return Signal.prototype.peek.apply(this, []);
|
|
166
|
+
}
|
|
167
|
+
const segments = parseAtSubpath(arguments[0], 1, 'Signal.peek()');
|
|
168
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
169
|
+
return Signal.prototype.peek.call($target);
|
|
170
|
+
}
|
|
171
|
+
const $target = resolveRefSignal(this);
|
|
172
|
+
if ($target !== this)
|
|
173
|
+
return Signal.prototype.peek.apply($target, arguments);
|
|
174
|
+
return Signal.prototype.peek.apply(this, arguments);
|
|
175
|
+
}
|
|
176
|
+
async set(path, value) {
|
|
177
|
+
const forwarded = forwardRef(this, 'set', arguments);
|
|
178
|
+
if (forwarded)
|
|
179
|
+
return forwarded;
|
|
180
|
+
if (arguments.length > 2)
|
|
181
|
+
throw Error('Signal.set() expects one or two arguments');
|
|
182
|
+
let segments = [];
|
|
183
|
+
if (arguments.length === 2) {
|
|
184
|
+
segments = parseAtSubpath(path, 1, 'Signal.set()');
|
|
185
|
+
}
|
|
186
|
+
else if (arguments.length === 1) {
|
|
187
|
+
value = path;
|
|
188
|
+
}
|
|
189
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
190
|
+
if (value === undefined)
|
|
191
|
+
return Signal.prototype.set.call($target, value);
|
|
192
|
+
return setReplaceOnSignal($target, value);
|
|
193
|
+
}
|
|
194
|
+
async add(collectionOrValue, value) {
|
|
195
|
+
const isRoot = this[SEGMENTS].length === 0;
|
|
196
|
+
const isRootCollectionCall = isRoot && typeof collectionOrValue === 'string';
|
|
197
|
+
if (isRootCollectionCall) {
|
|
198
|
+
if (arguments.length !== 2)
|
|
199
|
+
throw Error('Signal.add() expects (collection, object)');
|
|
200
|
+
if (!value || typeof value !== 'object')
|
|
201
|
+
throw Error('Signal.add() expects an object argument');
|
|
202
|
+
const $root = getRoot(this) || this;
|
|
203
|
+
const $collection = resolveSignal($root, [collectionOrValue]);
|
|
204
|
+
return $collection.add(value);
|
|
205
|
+
}
|
|
206
|
+
if (arguments.length > 1)
|
|
207
|
+
throw Error('Signal.add() expects a single argument');
|
|
208
|
+
return Signal.prototype.add.call(this, collectionOrValue);
|
|
209
|
+
}
|
|
210
|
+
async setNull(path, value) {
|
|
211
|
+
const forwarded = forwardRef(this, 'setNull', arguments);
|
|
212
|
+
if (forwarded)
|
|
213
|
+
return forwarded;
|
|
214
|
+
if (arguments.length > 2)
|
|
215
|
+
throw Error('Signal.setNull() expects one or two arguments');
|
|
216
|
+
let segments = [];
|
|
217
|
+
if (arguments.length === 2) {
|
|
218
|
+
segments = parseAtSubpath(path, 1, 'Signal.setNull()');
|
|
219
|
+
}
|
|
220
|
+
else if (arguments.length === 1) {
|
|
221
|
+
value = path;
|
|
222
|
+
}
|
|
223
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
224
|
+
if ($target.get() != null)
|
|
225
|
+
return;
|
|
226
|
+
return setReplaceOnSignal($target, value);
|
|
227
|
+
}
|
|
228
|
+
async create(path, value) {
|
|
229
|
+
const forwarded = forwardRef(this, 'create', arguments);
|
|
230
|
+
if (forwarded)
|
|
231
|
+
return forwarded;
|
|
232
|
+
if (arguments.length > 2)
|
|
233
|
+
throw Error('Signal.create() expects zero to two arguments');
|
|
234
|
+
let segments = [];
|
|
235
|
+
if (arguments.length === 2) {
|
|
236
|
+
segments = parseAtSubpath(path, 1, 'Signal.create()');
|
|
237
|
+
}
|
|
238
|
+
else if (arguments.length === 1) {
|
|
239
|
+
if (typeof path === 'string' || typeof path === 'number') {
|
|
240
|
+
segments = parseAtSubpath(path, 1, 'Signal.create()');
|
|
241
|
+
value = {};
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
value = path;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
value = {};
|
|
249
|
+
}
|
|
250
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
251
|
+
ensureCreateTarget($target, 'Signal.create()');
|
|
252
|
+
if ($target.get() != null) {
|
|
253
|
+
throw Error(`Signal.create() may only be used on a non-existing document path. Path: ${$target.path()}`);
|
|
254
|
+
}
|
|
255
|
+
return setReplaceOnSignal($target, value);
|
|
256
|
+
}
|
|
257
|
+
async setDiffDeep(path, value) {
|
|
258
|
+
const forwarded = forwardRef(this, 'setDiffDeep', arguments);
|
|
259
|
+
if (forwarded)
|
|
260
|
+
return forwarded;
|
|
261
|
+
if (arguments.length > 2)
|
|
262
|
+
throw Error('Signal.setDiffDeep() expects one or two arguments');
|
|
263
|
+
let segments = [];
|
|
264
|
+
if (arguments.length === 2) {
|
|
265
|
+
segments = parseAtSubpath(path, 1, 'Signal.setDiffDeep()');
|
|
266
|
+
}
|
|
267
|
+
else if (arguments.length === 1) {
|
|
268
|
+
value = path;
|
|
269
|
+
}
|
|
270
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
271
|
+
return runInBatch(() => setDiffDeepOnSignal($target, value));
|
|
272
|
+
}
|
|
273
|
+
async setDiff(path, value) {
|
|
274
|
+
const forwarded = forwardRef(this, 'setDiff', arguments);
|
|
275
|
+
if (forwarded)
|
|
276
|
+
return forwarded;
|
|
277
|
+
if (arguments.length > 2)
|
|
278
|
+
throw Error('Signal.setDiff() expects one or two arguments');
|
|
279
|
+
let segments = [];
|
|
280
|
+
if (arguments.length === 2) {
|
|
281
|
+
segments = parseAtSubpath(path, 1, 'Signal.setDiff()');
|
|
282
|
+
}
|
|
283
|
+
else if (arguments.length === 1) {
|
|
284
|
+
value = path;
|
|
285
|
+
}
|
|
286
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
287
|
+
const before = $target.peek();
|
|
288
|
+
if (racerEqualCompat(before, value))
|
|
289
|
+
return;
|
|
290
|
+
return setReplaceOnSignal($target, value);
|
|
291
|
+
}
|
|
292
|
+
async setEach(path, object) {
|
|
293
|
+
const forwarded = forwardRef(this, 'setEach', arguments);
|
|
294
|
+
if (forwarded)
|
|
295
|
+
return forwarded;
|
|
296
|
+
if (arguments.length > 2)
|
|
297
|
+
throw Error('Signal.setEach() expects one or two arguments');
|
|
298
|
+
let segments = [];
|
|
299
|
+
if (arguments.length === 2) {
|
|
300
|
+
segments = parseAtSubpath(path, 1, 'Signal.setEach()');
|
|
301
|
+
}
|
|
302
|
+
else if (arguments.length === 1) {
|
|
303
|
+
object = path;
|
|
304
|
+
}
|
|
305
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
306
|
+
if (!object)
|
|
307
|
+
return;
|
|
308
|
+
if (typeof object !== 'object') {
|
|
309
|
+
throw Error('Signal.setEach() expects an object argument, got: ' + typeof object);
|
|
310
|
+
}
|
|
311
|
+
return runInBatch(async () => {
|
|
312
|
+
const promises = [];
|
|
313
|
+
for (const key of Object.keys(object)) {
|
|
314
|
+
promises.push(SignalCompat.prototype.set.call($target[key], object[key]));
|
|
315
|
+
}
|
|
316
|
+
await Promise.all(promises);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
async del(path) {
|
|
320
|
+
const forwarded = forwardRef(this, 'del', arguments);
|
|
321
|
+
if (forwarded)
|
|
322
|
+
return forwarded;
|
|
323
|
+
if (arguments.length > 1)
|
|
324
|
+
throw Error('Signal.del() expects a single argument');
|
|
325
|
+
const segments = parseAtSubpath(path, arguments.length, 'Signal.del()');
|
|
326
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
327
|
+
try {
|
|
328
|
+
return await Signal.prototype.del.call($target);
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
if (isMissingPublicDocDeleteError($target, error))
|
|
332
|
+
return;
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
async increment(path, byNumber) {
|
|
337
|
+
const forwarded = forwardRef(this, 'increment', arguments);
|
|
338
|
+
if (forwarded)
|
|
339
|
+
return forwarded;
|
|
340
|
+
if (arguments.length > 2)
|
|
341
|
+
throw Error('Signal.increment() expects one or two arguments');
|
|
342
|
+
let segments = [];
|
|
343
|
+
if (arguments.length === 2) {
|
|
344
|
+
segments = parseAtSubpath(path, 1, 'Signal.increment()');
|
|
345
|
+
}
|
|
346
|
+
else if (arguments.length === 1) {
|
|
347
|
+
if (typeof path === 'number') {
|
|
348
|
+
byNumber = path;
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
segments = parseAtSubpath(path, 1, 'Signal.increment()');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
355
|
+
return incrementOnSignal($target, byNumber);
|
|
356
|
+
}
|
|
357
|
+
async push(path, value) {
|
|
358
|
+
const forwarded = forwardRef(this, 'push', arguments);
|
|
359
|
+
if (forwarded)
|
|
360
|
+
return forwarded;
|
|
361
|
+
if (arguments.length > 2)
|
|
362
|
+
throw Error('Signal.push() expects one or two arguments');
|
|
363
|
+
let segments = [];
|
|
364
|
+
if (arguments.length === 2) {
|
|
365
|
+
segments = parseAtSubpath(path, 1, 'Signal.push()');
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
value = path;
|
|
369
|
+
}
|
|
370
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
371
|
+
return arrayPushOnSignal($target, value);
|
|
372
|
+
}
|
|
373
|
+
async unshift(path, value) {
|
|
374
|
+
const forwarded = forwardRef(this, 'unshift', arguments);
|
|
375
|
+
if (forwarded)
|
|
376
|
+
return forwarded;
|
|
377
|
+
if (arguments.length > 2)
|
|
378
|
+
throw Error('Signal.unshift() expects one or two arguments');
|
|
379
|
+
let segments = [];
|
|
380
|
+
if (arguments.length === 2) {
|
|
381
|
+
segments = parseAtSubpath(path, 1, 'Signal.unshift()');
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
value = path;
|
|
385
|
+
}
|
|
386
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
387
|
+
return arrayUnshiftOnSignal($target, value);
|
|
388
|
+
}
|
|
389
|
+
async insert(path, index, values) {
|
|
390
|
+
const forwarded = forwardRef(this, 'insert', arguments);
|
|
391
|
+
if (forwarded)
|
|
392
|
+
return forwarded;
|
|
393
|
+
if (arguments.length < 2)
|
|
394
|
+
throw Error('Not enough arguments for insert');
|
|
395
|
+
if (arguments.length > 3)
|
|
396
|
+
throw Error('Signal.insert() expects two or three arguments');
|
|
397
|
+
let segments = [];
|
|
398
|
+
if (arguments.length === 2) {
|
|
399
|
+
index = arguments[0];
|
|
400
|
+
values = arguments[1];
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
segments = parseAtSubpath(path, 1, 'Signal.insert()');
|
|
404
|
+
index = arguments[1];
|
|
405
|
+
values = arguments[2];
|
|
406
|
+
}
|
|
407
|
+
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
408
|
+
throw Error('Signal.insert() expects a numeric index');
|
|
409
|
+
}
|
|
410
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
411
|
+
return arrayInsertOnSignal($target, index, values);
|
|
412
|
+
}
|
|
413
|
+
async pop(path) {
|
|
414
|
+
const forwarded = forwardRef(this, 'pop', arguments);
|
|
415
|
+
if (forwarded)
|
|
416
|
+
return forwarded;
|
|
417
|
+
if (arguments.length > 1)
|
|
418
|
+
throw Error('Signal.pop() expects a single argument');
|
|
419
|
+
const segments = parseAtSubpath(path, arguments.length, 'Signal.pop()');
|
|
420
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
421
|
+
return arrayPopOnSignal($target);
|
|
422
|
+
}
|
|
423
|
+
async shift(path) {
|
|
424
|
+
const forwarded = forwardRef(this, 'shift', arguments);
|
|
425
|
+
if (forwarded)
|
|
426
|
+
return forwarded;
|
|
427
|
+
if (arguments.length > 1)
|
|
428
|
+
throw Error('Signal.shift() expects a single argument');
|
|
429
|
+
const segments = parseAtSubpath(path, arguments.length, 'Signal.shift()');
|
|
430
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
431
|
+
return arrayShiftOnSignal($target);
|
|
432
|
+
}
|
|
433
|
+
async remove(path, index, howMany) {
|
|
434
|
+
const forwarded = forwardRef(this, 'remove', arguments);
|
|
435
|
+
if (forwarded)
|
|
436
|
+
return forwarded;
|
|
437
|
+
if (arguments.length === 0) {
|
|
438
|
+
const segments = this[SEGMENTS].slice();
|
|
439
|
+
if (!segments.length || typeof segments[segments.length - 1] !== 'number') {
|
|
440
|
+
throw Error('Signal.remove() expects an index');
|
|
441
|
+
}
|
|
442
|
+
index = segments.pop();
|
|
443
|
+
const $root = getRoot(this) || this;
|
|
444
|
+
const $target = resolveSignal($root, segments);
|
|
445
|
+
return arrayRemoveOnSignal($target, +index, howMany);
|
|
446
|
+
}
|
|
447
|
+
if (arguments.length < 1)
|
|
448
|
+
throw Error('Not enough arguments for remove');
|
|
449
|
+
if (arguments.length > 3)
|
|
450
|
+
throw Error('Signal.remove() expects one to three arguments');
|
|
451
|
+
let segments = [];
|
|
452
|
+
if (arguments.length === 1) {
|
|
453
|
+
if (typeof path === 'number') {
|
|
454
|
+
index = path;
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
segments = parseAtSubpath(path, 1, 'Signal.remove()');
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
else if (arguments.length === 2) {
|
|
461
|
+
if (typeof path === 'number') {
|
|
462
|
+
index = path;
|
|
463
|
+
howMany = arguments[1];
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
segments = parseAtSubpath(path, 1, 'Signal.remove()');
|
|
467
|
+
index = arguments[1];
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
segments = parseAtSubpath(path, 1, 'Signal.remove()');
|
|
472
|
+
index = arguments[1];
|
|
473
|
+
howMany = arguments[2];
|
|
474
|
+
}
|
|
475
|
+
if (index == null && segments.length && typeof segments[segments.length - 1] === 'number') {
|
|
476
|
+
index = segments.pop();
|
|
477
|
+
}
|
|
478
|
+
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
479
|
+
throw Error('Signal.remove() expects a numeric index');
|
|
480
|
+
}
|
|
481
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
482
|
+
return arrayRemoveOnSignal($target, index, howMany);
|
|
483
|
+
}
|
|
484
|
+
async move(path, from, to, howMany) {
|
|
485
|
+
const forwarded = forwardRef(this, 'move', arguments);
|
|
486
|
+
if (forwarded)
|
|
487
|
+
return forwarded;
|
|
488
|
+
if (arguments.length < 2)
|
|
489
|
+
throw Error('Not enough arguments for move');
|
|
490
|
+
if (arguments.length > 4)
|
|
491
|
+
throw Error('Signal.move() expects two to four arguments');
|
|
492
|
+
let segments = [];
|
|
493
|
+
if (arguments.length === 2) {
|
|
494
|
+
from = arguments[0];
|
|
495
|
+
to = arguments[1];
|
|
496
|
+
}
|
|
497
|
+
else if (arguments.length === 3) {
|
|
498
|
+
if (typeof path === 'number') {
|
|
499
|
+
from = arguments[0];
|
|
500
|
+
to = arguments[1];
|
|
501
|
+
howMany = arguments[2];
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
segments = parseAtSubpath(path, 1, 'Signal.move()');
|
|
505
|
+
from = arguments[1];
|
|
506
|
+
to = arguments[2];
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
segments = parseAtSubpath(path, 1, 'Signal.move()');
|
|
511
|
+
from = arguments[1];
|
|
512
|
+
to = arguments[2];
|
|
513
|
+
howMany = arguments[3];
|
|
514
|
+
}
|
|
515
|
+
if (typeof from !== 'number' || !Number.isFinite(from) || typeof to !== 'number' || !Number.isFinite(to)) {
|
|
516
|
+
throw Error('Signal.move() expects numeric from/to');
|
|
517
|
+
}
|
|
518
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
519
|
+
return arrayMoveOnSignal($target, from, to, howMany);
|
|
520
|
+
}
|
|
521
|
+
async stringInsert(path, index, text) {
|
|
522
|
+
const forwarded = forwardRef(this, 'stringInsert', arguments);
|
|
523
|
+
if (forwarded)
|
|
524
|
+
return forwarded;
|
|
525
|
+
if (arguments.length < 2)
|
|
526
|
+
throw Error('Not enough arguments for stringInsert');
|
|
527
|
+
if (arguments.length > 3)
|
|
528
|
+
throw Error('Signal.stringInsert() expects two or three arguments');
|
|
529
|
+
let segments = [];
|
|
530
|
+
if (arguments.length === 2) {
|
|
531
|
+
index = arguments[0];
|
|
532
|
+
text = arguments[1];
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
segments = parseAtSubpath(path, 1, 'Signal.stringInsert()');
|
|
536
|
+
index = arguments[1];
|
|
537
|
+
text = arguments[2];
|
|
538
|
+
}
|
|
539
|
+
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
540
|
+
throw Error('Signal.stringInsert() expects a numeric index');
|
|
541
|
+
}
|
|
542
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
543
|
+
return stringInsertOnSignal($target, index, text);
|
|
544
|
+
}
|
|
545
|
+
async stringRemove(path, index, howMany) {
|
|
546
|
+
const forwarded = forwardRef(this, 'stringRemove', arguments);
|
|
547
|
+
if (forwarded)
|
|
548
|
+
return forwarded;
|
|
549
|
+
if (arguments.length < 2)
|
|
550
|
+
throw Error('Not enough arguments for stringRemove');
|
|
551
|
+
if (arguments.length > 3)
|
|
552
|
+
throw Error('Signal.stringRemove() expects two or three arguments');
|
|
553
|
+
let segments = [];
|
|
554
|
+
if (arguments.length === 2) {
|
|
555
|
+
index = arguments[0];
|
|
556
|
+
howMany = arguments[1];
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
segments = parseAtSubpath(path, 1, 'Signal.stringRemove()');
|
|
560
|
+
index = arguments[1];
|
|
561
|
+
howMany = arguments[2];
|
|
562
|
+
}
|
|
563
|
+
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
564
|
+
throw Error('Signal.stringRemove() expects a numeric index');
|
|
565
|
+
}
|
|
566
|
+
if (howMany == null)
|
|
567
|
+
howMany = 1;
|
|
568
|
+
const $target = resolveRelativePathTarget(this, segments);
|
|
569
|
+
return stringRemoveOnSignal($target, index, howMany);
|
|
570
|
+
}
|
|
571
|
+
async assign(value) {
|
|
572
|
+
const forwarded = forwardRef(this, 'assign', arguments);
|
|
573
|
+
if (forwarded)
|
|
574
|
+
return forwarded;
|
|
575
|
+
if (arguments.length > 1)
|
|
576
|
+
throw Error('Signal.assign() expects a single argument');
|
|
577
|
+
return Signal.prototype.assign.call(this, value);
|
|
578
|
+
}
|
|
579
|
+
on(eventName, pattern, handler) {
|
|
580
|
+
if (arguments.length < 2)
|
|
581
|
+
throw Error('Signal.on() expects at least two arguments');
|
|
582
|
+
if (eventName === 'change' || eventName === 'all') {
|
|
583
|
+
if (typeof pattern === 'function') {
|
|
584
|
+
return onCustomEvent(eventName, pattern);
|
|
585
|
+
}
|
|
586
|
+
if (typeof handler !== 'function')
|
|
587
|
+
throw Error('Signal.on() expects a handler function');
|
|
588
|
+
const normalized = normalizePattern(pattern, 'Signal.on()');
|
|
589
|
+
const rootId = (getRoot(this) || this)?.[ROOT_ID];
|
|
590
|
+
return onModelEvent(rootId, eventName, normalized, handler);
|
|
591
|
+
}
|
|
592
|
+
if (typeof pattern !== 'function')
|
|
593
|
+
throw Error('Signal.on() expects a handler function');
|
|
594
|
+
return onCustomEvent(eventName, pattern);
|
|
595
|
+
}
|
|
596
|
+
once(eventName, pattern, handler) {
|
|
597
|
+
if (arguments.length < 2)
|
|
598
|
+
throw Error('Signal.once() expects at least two arguments');
|
|
599
|
+
const isModelEvent = eventName === 'change' || eventName === 'all';
|
|
600
|
+
if (isModelEvent && typeof pattern !== 'function') {
|
|
601
|
+
if (typeof handler !== 'function')
|
|
602
|
+
throw Error('Signal.once() expects a handler function');
|
|
603
|
+
const onceHandler = (...args) => {
|
|
604
|
+
this.removeListener(eventName, onceHandler);
|
|
605
|
+
handler(...args);
|
|
606
|
+
};
|
|
607
|
+
this.on(eventName, pattern, onceHandler);
|
|
608
|
+
return onceHandler;
|
|
609
|
+
}
|
|
610
|
+
if (typeof pattern !== 'function')
|
|
611
|
+
throw Error('Signal.once() expects a handler function');
|
|
612
|
+
const onceHandler = (...args) => {
|
|
613
|
+
this.removeListener(eventName, onceHandler);
|
|
614
|
+
pattern(...args);
|
|
615
|
+
};
|
|
616
|
+
this.on(eventName, onceHandler);
|
|
617
|
+
return onceHandler;
|
|
618
|
+
}
|
|
619
|
+
removeListener(eventName, handler) {
|
|
620
|
+
if (arguments.length !== 2)
|
|
621
|
+
throw Error('Signal.removeListener() expects two arguments');
|
|
622
|
+
if (eventName === 'change' || eventName === 'all') {
|
|
623
|
+
const rootId = (getRoot(this) || this)?.[ROOT_ID];
|
|
624
|
+
return removeModelListener(rootId, eventName, handler);
|
|
625
|
+
}
|
|
626
|
+
return removeCustomEventListener(eventName, handler);
|
|
627
|
+
}
|
|
628
|
+
ref(path, target, options) {
|
|
629
|
+
if (arguments.length > 3)
|
|
630
|
+
throw Error('Signal.ref() expects one to three arguments');
|
|
631
|
+
let $from = this;
|
|
632
|
+
let $to;
|
|
633
|
+
if (arguments.length === 1) {
|
|
634
|
+
$to = resolveRefTarget(this, path, 'Signal.ref()');
|
|
635
|
+
}
|
|
636
|
+
else if (arguments.length === 2) {
|
|
637
|
+
if (isSignalLike(target) || typeof target === 'string') {
|
|
638
|
+
const segments = parseAtSubpath(path, 1, 'Signal.ref()');
|
|
639
|
+
$from = resolveSignal(this, segments);
|
|
640
|
+
$to = resolveRefTarget(this, target, 'Signal.ref()');
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
$to = resolveRefTarget(this, path, 'Signal.ref()');
|
|
644
|
+
options = target;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
const segments = parseAtSubpath(path, 1, 'Signal.ref()');
|
|
649
|
+
$from = resolveSignal(this, segments);
|
|
650
|
+
$to = resolveRefTarget(this, target, 'Signal.ref()');
|
|
651
|
+
}
|
|
652
|
+
if (!$to)
|
|
653
|
+
throw Error('Signal.ref() expects a target path or signal');
|
|
654
|
+
if ($from === $to)
|
|
655
|
+
return $from;
|
|
656
|
+
ensurePrivateRefSource($from, 'Signal.ref()');
|
|
657
|
+
const store = getRefStore($from);
|
|
658
|
+
const fromPath = $from.path();
|
|
659
|
+
const existing = store.get(fromPath);
|
|
660
|
+
if (existing)
|
|
661
|
+
existing.stop();
|
|
662
|
+
const mirrorOnly = !!($to?.[IS_QUERY] || $to?.[IS_AGGREGATION]);
|
|
663
|
+
const { stop, onChange } = createRefLink($from, $to, { mirrorOnly, options });
|
|
664
|
+
store.set(fromPath, { stop });
|
|
665
|
+
const fromRootId = (getRoot($from) || $from)?.[ROOT_ID];
|
|
666
|
+
const toRootId = (getRoot($to) || $to)?.[ROOT_ID];
|
|
667
|
+
if (!mirrorOnly) {
|
|
668
|
+
$from[REF_TARGET] = $to;
|
|
669
|
+
setRefLink(fromRootId, fromPath, $to.path(), $from[SEGMENTS], $to[SEGMENTS], {
|
|
670
|
+
mirrorOnly: false,
|
|
671
|
+
fromRootId,
|
|
672
|
+
toRootId
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
setRefLink(fromRootId, fromPath, $to.path(), $from[SEGMENTS], $to[SEGMENTS], {
|
|
677
|
+
mirrorOnly: true,
|
|
678
|
+
onChange,
|
|
679
|
+
fromRootId,
|
|
680
|
+
toRootId
|
|
681
|
+
});
|
|
682
|
+
if ($from[REF_TARGET])
|
|
683
|
+
delete $from[REF_TARGET];
|
|
684
|
+
}
|
|
685
|
+
return $from;
|
|
686
|
+
}
|
|
687
|
+
refExtra(path) {
|
|
688
|
+
if (arguments.length !== 1)
|
|
689
|
+
throw Error('Signal.refExtra() expects a single argument');
|
|
690
|
+
const segments = parseAtSubpath(path, 1, 'Signal.refExtra()');
|
|
691
|
+
const $root = getRoot(this) || this;
|
|
692
|
+
const $target = resolveSignal($root, segments);
|
|
693
|
+
let $source = this;
|
|
694
|
+
if (this[IS_QUERY]) {
|
|
695
|
+
$source = this.extra;
|
|
696
|
+
}
|
|
697
|
+
return SignalCompat.prototype.ref.call($target, $source);
|
|
698
|
+
}
|
|
699
|
+
refIds(path) {
|
|
700
|
+
if (arguments.length !== 1)
|
|
701
|
+
throw Error('Signal.refIds() expects a single argument');
|
|
702
|
+
if (!this[IS_QUERY]) {
|
|
703
|
+
throw Error('Signal.refIds() can only be used on query signals');
|
|
704
|
+
}
|
|
705
|
+
const segments = parseAtSubpath(path, 1, 'Signal.refIds()');
|
|
706
|
+
const $root = getRoot(this) || this;
|
|
707
|
+
const $target = resolveSignal($root, segments);
|
|
708
|
+
return SignalCompat.prototype.ref.call($target, this.ids);
|
|
709
|
+
}
|
|
710
|
+
removeRef(path) {
|
|
711
|
+
if (arguments.length > 1)
|
|
712
|
+
throw Error('Signal.removeRef() expects a single argument');
|
|
713
|
+
let $from = this;
|
|
714
|
+
if (arguments.length === 1) {
|
|
715
|
+
const segments = parseAtSubpath(path, 1, 'Signal.removeRef()');
|
|
716
|
+
$from = resolveSignal(this, segments);
|
|
717
|
+
}
|
|
718
|
+
const store = getRefStore($from);
|
|
719
|
+
const fromPath = $from.path();
|
|
720
|
+
const existing = store.get(fromPath);
|
|
721
|
+
if (existing) {
|
|
722
|
+
existing.stop();
|
|
723
|
+
store.delete(fromPath);
|
|
724
|
+
}
|
|
725
|
+
const fromRootId = (getRoot($from) || $from)?.[ROOT_ID];
|
|
726
|
+
removeRefLink(fromRootId, fromPath);
|
|
727
|
+
const $target = resolveRefSignal($from);
|
|
728
|
+
if ($target !== $from) {
|
|
729
|
+
setDiffDeepBypassRef($from, deepCopy($target.get()));
|
|
730
|
+
}
|
|
731
|
+
if ($from[REF_TARGET])
|
|
732
|
+
delete $from[REF_TARGET];
|
|
733
|
+
}
|
|
734
|
+
scope(path) {
|
|
735
|
+
const $root = getRoot(this) || this;
|
|
736
|
+
if (arguments.length === 0)
|
|
737
|
+
return $root;
|
|
738
|
+
const segments = arguments.length > 1
|
|
739
|
+
? parseAtSegments(arguments, 'Signal.scope()')
|
|
740
|
+
: parseAtSubpath(path, arguments.length, 'Signal.scope()');
|
|
741
|
+
if (segments.length === 0)
|
|
742
|
+
return $root;
|
|
743
|
+
return resolveRelativePathTarget($root, segments);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
const SILENT_WRAPPER = Symbol('compat silent wrapper');
|
|
747
|
+
const SILENT_WRAPPER_TARGET = Symbol('compat silent wrapper target');
|
|
748
|
+
const SILENT_WRAPPER_ENABLED = Symbol('compat silent wrapper enabled');
|
|
749
|
+
function createSilentSignalWrapper($signal, enabled = true) {
|
|
750
|
+
if (!$signal || typeof $signal !== 'function')
|
|
751
|
+
return $signal;
|
|
752
|
+
if ($signal[SILENT_WRAPPER]) {
|
|
753
|
+
const target = $signal[SILENT_WRAPPER_TARGET] || $signal;
|
|
754
|
+
return createSilentSignalWrapper(target, enabled);
|
|
755
|
+
}
|
|
756
|
+
const handler = {
|
|
757
|
+
get(target, key, receiver) {
|
|
758
|
+
if (key === SILENT_WRAPPER)
|
|
759
|
+
return true;
|
|
760
|
+
if (key === SILENT_WRAPPER_TARGET)
|
|
761
|
+
return target;
|
|
762
|
+
if (key === SILENT_WRAPPER_ENABLED)
|
|
763
|
+
return enabled;
|
|
764
|
+
if (key === 'silent') {
|
|
765
|
+
return function silentWrapper(value) {
|
|
766
|
+
if (arguments.length > 1)
|
|
767
|
+
throw Error('Signal.silent() expects zero or one argument');
|
|
768
|
+
const nextEnabled = value == null ? true : !!value;
|
|
769
|
+
return createSilentSignalWrapper(target, nextEnabled);
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
const value = Reflect.get(target, key, receiver);
|
|
773
|
+
if (isSignalLike(value)) {
|
|
774
|
+
return createSilentSignalWrapper(value, enabled);
|
|
775
|
+
}
|
|
776
|
+
if (typeof value === 'function') {
|
|
777
|
+
return function wrappedMethod(...args) {
|
|
778
|
+
if (!enabled)
|
|
779
|
+
return Reflect.apply(value, target, args);
|
|
780
|
+
return runInSilentContext(() => Reflect.apply(value, target, args));
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
return value;
|
|
784
|
+
},
|
|
785
|
+
apply(target, thisArg, args) {
|
|
786
|
+
if (!enabled)
|
|
787
|
+
return Reflect.apply(target, thisArg, args);
|
|
788
|
+
return runInSilentContext(() => Reflect.apply(target, thisArg, args));
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
return new Proxy($signal, handler);
|
|
792
|
+
}
|
|
793
|
+
function getRefStore($signal) {
|
|
794
|
+
const $root = getRoot($signal) || $signal;
|
|
795
|
+
const rootId = $root?.[ROOT_ID];
|
|
796
|
+
return getRootContext(rootId, true).activeRefs;
|
|
797
|
+
}
|
|
798
|
+
function createRefLink($from, $to, { mirrorOnly = false } = {}) {
|
|
799
|
+
let disposed = false;
|
|
800
|
+
let pendingRead = null;
|
|
801
|
+
let mirrorObserver;
|
|
802
|
+
const syncFromTarget = () => {
|
|
803
|
+
const value = readRefValue($to);
|
|
804
|
+
if (isThenable(value)) {
|
|
805
|
+
pendingRead = value;
|
|
806
|
+
value.then(() => {
|
|
807
|
+
if (disposed || pendingRead !== value)
|
|
808
|
+
return;
|
|
809
|
+
pendingRead = null;
|
|
810
|
+
syncFromTarget();
|
|
811
|
+
}, () => {
|
|
812
|
+
if (pendingRead === value)
|
|
813
|
+
pendingRead = null;
|
|
814
|
+
});
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
if (value === undefined)
|
|
818
|
+
return;
|
|
819
|
+
setDiffDeepBypassRef($from, deepCopy(value));
|
|
820
|
+
};
|
|
821
|
+
syncFromTarget();
|
|
822
|
+
if (mirrorOnly) {
|
|
823
|
+
mirrorObserver = observe(() => {
|
|
824
|
+
syncFromTarget();
|
|
825
|
+
return readRefValue($to);
|
|
826
|
+
}, {
|
|
827
|
+
scheduler: job => job()
|
|
828
|
+
});
|
|
829
|
+
// initialize dependency graph
|
|
830
|
+
mirrorObserver();
|
|
831
|
+
}
|
|
832
|
+
return {
|
|
833
|
+
onChange: syncFromTarget,
|
|
834
|
+
stop: () => {
|
|
835
|
+
disposed = true;
|
|
836
|
+
if (mirrorObserver)
|
|
837
|
+
unobserve(mirrorObserver);
|
|
838
|
+
// Subsequent sync happens directly at mutation time via mirrorRefMutationFromTarget().
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
function readRefValue($signal) {
|
|
843
|
+
try {
|
|
844
|
+
return $signal.get();
|
|
845
|
+
}
|
|
846
|
+
catch (err) {
|
|
847
|
+
if (isThenable(err))
|
|
848
|
+
return err;
|
|
849
|
+
throw err;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
function resolveRefSignal($signal) {
|
|
853
|
+
const directTarget = resolveRefSignalSafe($signal);
|
|
854
|
+
if (directTarget && directTarget !== $signal)
|
|
855
|
+
return directTarget;
|
|
856
|
+
const resolvedSegments = resolveRefSegmentsSafe($signal[SEGMENTS], (getRoot($signal) || $signal)?.[ROOT_ID]);
|
|
857
|
+
if (!resolvedSegments)
|
|
858
|
+
return $signal;
|
|
859
|
+
const $root = getRoot($signal) || $signal;
|
|
860
|
+
return resolveSignal($root, resolvedSegments);
|
|
861
|
+
}
|
|
862
|
+
function forwardRef($signal, methodName, args) {
|
|
863
|
+
const $target = resolveRefSignal($signal);
|
|
864
|
+
if ($target === $signal)
|
|
865
|
+
return null;
|
|
866
|
+
return SignalCompat.prototype[methodName].apply($target, args);
|
|
867
|
+
}
|
|
868
|
+
function setDiffDeepBypassRef($signal, value) {
|
|
869
|
+
const segments = $signal[SEGMENTS];
|
|
870
|
+
if (isPublicCollection(segments[0]))
|
|
871
|
+
return Signal.prototype.set.call($signal, value);
|
|
872
|
+
return setReplacePrivateData(getOwningRootId($signal), segments, value);
|
|
873
|
+
}
|
|
874
|
+
function mirrorRefMutationFromTarget(targetSegments, value) {
|
|
875
|
+
if (!Array.isArray(targetSegments) || targetSegments.length === 0)
|
|
876
|
+
return;
|
|
877
|
+
const updates = [];
|
|
878
|
+
for (const link of getAllRefLinks()) {
|
|
879
|
+
if (!isPathPrefix(link.toSegments, targetSegments))
|
|
880
|
+
continue;
|
|
881
|
+
const suffix = targetSegments.slice(link.toSegments.length);
|
|
882
|
+
updates.push({
|
|
883
|
+
fromRootId: link.fromRootId,
|
|
884
|
+
segments: link.fromSegments.concat(suffix),
|
|
885
|
+
value: deepCopy(value)
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
if (!updates.length)
|
|
889
|
+
return;
|
|
890
|
+
runInModelEventsSilentContext(() => {
|
|
891
|
+
for (const update of updates) {
|
|
892
|
+
const $root = getRootSignal({
|
|
893
|
+
rootId: update.fromRootId || GLOBAL_ROOT_ID,
|
|
894
|
+
rootFunction: universal$
|
|
895
|
+
});
|
|
896
|
+
const $target = resolveSignal($root, update.segments);
|
|
897
|
+
setDiffDeepBypassRef($target, update.value);
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
function isPathPrefix(prefixSegments, fullSegments) {
|
|
902
|
+
if (prefixSegments.length > fullSegments.length)
|
|
903
|
+
return false;
|
|
904
|
+
for (let i = 0; i < prefixSegments.length; i++) {
|
|
905
|
+
if (String(prefixSegments[i]) !== String(fullSegments[i]))
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
return true;
|
|
909
|
+
}
|
|
910
|
+
function isSignalLike(value) {
|
|
911
|
+
return value && typeof value.path === 'function' && typeof value.get === 'function';
|
|
912
|
+
}
|
|
913
|
+
function isReactLike(value) {
|
|
914
|
+
return !!(value && typeof value === 'object' && typeof value.$$typeof === 'symbol');
|
|
915
|
+
}
|
|
916
|
+
function isThenable(value) {
|
|
917
|
+
return !!value && typeof value.then === 'function';
|
|
918
|
+
}
|
|
919
|
+
function resolveRefTarget($signal, target, methodName) {
|
|
920
|
+
if (isSignalLike(target))
|
|
921
|
+
return target;
|
|
922
|
+
if (typeof target === 'string') {
|
|
923
|
+
const segments = parseAtSubpath(target, 1, methodName);
|
|
924
|
+
const $root = getRoot($signal) || $signal;
|
|
925
|
+
return resolveSignal($root, segments);
|
|
926
|
+
}
|
|
927
|
+
return undefined;
|
|
928
|
+
}
|
|
929
|
+
function parseAtSubpath(subpath, argsLength, methodName) {
|
|
930
|
+
if (argsLength === 0)
|
|
931
|
+
return [];
|
|
932
|
+
if (typeof subpath === 'string')
|
|
933
|
+
return subpath.split('.').filter(Boolean);
|
|
934
|
+
if (typeof subpath === 'number' && Number.isFinite(subpath) && Number.isInteger(subpath))
|
|
935
|
+
return [subpath];
|
|
936
|
+
throw Error(`${methodName} expects a string or integer argument`);
|
|
937
|
+
}
|
|
938
|
+
function parseAtSegments(args, methodName) {
|
|
939
|
+
const segments = [];
|
|
940
|
+
for (const arg of Array.from(args)) {
|
|
941
|
+
if (typeof arg === 'string') {
|
|
942
|
+
const parts = arg.split('.').filter(Boolean);
|
|
943
|
+
segments.push(...parts);
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
if (typeof arg === 'number' && Number.isFinite(arg) && Number.isInteger(arg)) {
|
|
947
|
+
segments.push(arg);
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
throw Error(`${methodName} expects string or integer path segments`);
|
|
951
|
+
}
|
|
952
|
+
return segments;
|
|
953
|
+
}
|
|
954
|
+
function resolveSignal($signal, segments) {
|
|
955
|
+
let $cursor = $signal;
|
|
956
|
+
for (const segment of segments) {
|
|
957
|
+
$cursor = $cursor[segment];
|
|
958
|
+
}
|
|
959
|
+
return $cursor;
|
|
960
|
+
}
|
|
961
|
+
function resolveSignalWithRefs($signal, relativeSegments) {
|
|
962
|
+
const baseSegments = Array.isArray($signal?.[SEGMENTS]) ? $signal[SEGMENTS] : [];
|
|
963
|
+
const absoluteSegments = baseSegments.concat(relativeSegments);
|
|
964
|
+
const resolvedSegments = resolveRefSegmentsSafe(absoluteSegments, (getRoot($signal) || $signal)?.[ROOT_ID]);
|
|
965
|
+
if (!resolvedSegments)
|
|
966
|
+
return resolveSignal($signal, relativeSegments);
|
|
967
|
+
// Signals created through root functions can carry a raw root in [ROOT].
|
|
968
|
+
// For path-based ref writes we need proxy traversal semantics.
|
|
969
|
+
const $root = getRoot($signal) || $signal;
|
|
970
|
+
const $traversalRoot = getRoot($root) || $root;
|
|
971
|
+
return resolveSignal($traversalRoot, resolvedSegments);
|
|
972
|
+
}
|
|
973
|
+
function resolveRelativePathTarget($signal, relativeSegments) {
|
|
974
|
+
if (!Array.isArray(relativeSegments) || relativeSegments.length === 0) {
|
|
975
|
+
return resolveSignal($signal, []);
|
|
976
|
+
}
|
|
977
|
+
return resolveSignalWithRefs($signal, relativeSegments);
|
|
978
|
+
}
|
|
979
|
+
function isMissingPublicDocDeleteError($signal, error) {
|
|
980
|
+
const segments = $signal?.[SEGMENTS];
|
|
981
|
+
if (!Array.isArray(segments) || segments.length < 2)
|
|
982
|
+
return false;
|
|
983
|
+
if (!isPublicCollection(segments[0]))
|
|
984
|
+
return false;
|
|
985
|
+
if (!(error instanceof Error))
|
|
986
|
+
return false;
|
|
987
|
+
return error.message.includes('Trying to delete data from a non-existing doc');
|
|
988
|
+
}
|
|
989
|
+
async function setDiffDeepOnSignal($target, value) {
|
|
990
|
+
if ($target[SEGMENTS].length === 0)
|
|
991
|
+
throw Error('Can\'t set the root signal data');
|
|
992
|
+
// Use peek() here. compat start() writes via setDiffDeep inside an observer and must not
|
|
993
|
+
// subscribe to its own target, otherwise later local edits on child signals cause start()
|
|
994
|
+
// to rerun and overwrite them from source.
|
|
995
|
+
const before = $target.peek();
|
|
996
|
+
if (isPublicCollection($target[SEGMENTS][0])) {
|
|
997
|
+
await diffDeepCompat($target, before, value);
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
diffDeepCompatSync($target, before, value);
|
|
1001
|
+
}
|
|
1002
|
+
async function diffDeepCompat($signal, before, after) {
|
|
1003
|
+
if (before === after)
|
|
1004
|
+
return;
|
|
1005
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
1006
|
+
const diff = arrayDiff(before, after, deepEqualCompat);
|
|
1007
|
+
if (!diff.length)
|
|
1008
|
+
return;
|
|
1009
|
+
const index = getSingleArrayReplacementIndex(diff);
|
|
1010
|
+
if (index != null) {
|
|
1011
|
+
await diffDeepCompat(getChildSignal($signal, index), before[index], after[index]);
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
await applyArrayDiffCompat($signal, diff);
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
if (isDiffableObject(before, after)) {
|
|
1018
|
+
for (const key of Object.keys(before)) {
|
|
1019
|
+
if (Object.prototype.hasOwnProperty.call(after, key))
|
|
1020
|
+
continue;
|
|
1021
|
+
await SignalCompat.prototype.del.call(getChildSignal($signal, key));
|
|
1022
|
+
}
|
|
1023
|
+
for (const key of Object.keys(after)) {
|
|
1024
|
+
await diffDeepCompat(getChildSignal($signal, key), before[key], after[key]);
|
|
1025
|
+
}
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
await SignalCompat.prototype.set.call($signal, after);
|
|
1029
|
+
}
|
|
1030
|
+
function diffDeepCompatSync($signal, before, after) {
|
|
1031
|
+
if (before === after)
|
|
1032
|
+
return;
|
|
1033
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
1034
|
+
const diff = arrayDiff(before, after, deepEqualCompat);
|
|
1035
|
+
if (!diff.length)
|
|
1036
|
+
return;
|
|
1037
|
+
const index = getSingleArrayReplacementIndex(diff);
|
|
1038
|
+
if (index != null) {
|
|
1039
|
+
diffDeepCompatSync(getChildSignal($signal, index), before[index], after[index]);
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
applyArrayDiffCompatSync($signal, diff);
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
if (isDiffableObject(before, after)) {
|
|
1046
|
+
const preservePath = $signal[SEGMENTS];
|
|
1047
|
+
for (const key of Object.keys(before)) {
|
|
1048
|
+
if (Object.prototype.hasOwnProperty.call(after, key))
|
|
1049
|
+
continue;
|
|
1050
|
+
delPrivateCompatSync(getChildSignal($signal, key), { preservePath });
|
|
1051
|
+
}
|
|
1052
|
+
for (const key of Object.keys(after)) {
|
|
1053
|
+
diffDeepCompatSync(getChildSignal($signal, key), before[key], after[key]);
|
|
1054
|
+
}
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
setReplacePrivateCompatSync($signal, after);
|
|
1058
|
+
}
|
|
1059
|
+
function isDiffableObject(before, after) {
|
|
1060
|
+
if (!isPlainObject(before) || !isPlainObject(after))
|
|
1061
|
+
return false;
|
|
1062
|
+
if (isReactLike(before) || isReactLike(after))
|
|
1063
|
+
return false;
|
|
1064
|
+
return true;
|
|
1065
|
+
}
|
|
1066
|
+
function getSingleArrayReplacementIndex(diff) {
|
|
1067
|
+
if (!Array.isArray(diff) || diff.length !== 2)
|
|
1068
|
+
return null;
|
|
1069
|
+
const first = diff[0];
|
|
1070
|
+
const second = diff[1];
|
|
1071
|
+
if (first instanceof arrayDiff.RemoveDiff &&
|
|
1072
|
+
second instanceof arrayDiff.InsertDiff &&
|
|
1073
|
+
first.index === second.index &&
|
|
1074
|
+
first.howMany === 1 &&
|
|
1075
|
+
second.values.length === 1) {
|
|
1076
|
+
return first.index;
|
|
1077
|
+
}
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
async function applyArrayDiffCompat($signal, diff) {
|
|
1081
|
+
for (const item of diff) {
|
|
1082
|
+
if (item instanceof arrayDiff.InsertDiff) {
|
|
1083
|
+
await arrayInsertOnSignal($signal, item.index, item.values);
|
|
1084
|
+
continue;
|
|
1085
|
+
}
|
|
1086
|
+
if (item instanceof arrayDiff.RemoveDiff) {
|
|
1087
|
+
await arrayRemoveOnSignal($signal, item.index, item.howMany);
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
if (item instanceof arrayDiff.MoveDiff) {
|
|
1091
|
+
await arrayMoveOnSignal($signal, item.from, item.to, item.howMany);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function applyArrayDiffCompatSync($signal, diff) {
|
|
1096
|
+
const segments = ensureArrayTarget($signal);
|
|
1097
|
+
const rootId = getOwningRootId($signal);
|
|
1098
|
+
for (const item of diff) {
|
|
1099
|
+
if (item instanceof arrayDiff.InsertDiff) {
|
|
1100
|
+
arrayInsertPrivateData(rootId, segments, item.index, item.values);
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
1103
|
+
if (item instanceof arrayDiff.RemoveDiff) {
|
|
1104
|
+
arrayRemovePrivateData(rootId, segments, item.index, item.howMany);
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
if (item instanceof arrayDiff.MoveDiff) {
|
|
1108
|
+
arrayMovePrivateData(rootId, segments, item.from, item.to, item.howMany);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
function getChildSignal($parent, key) {
|
|
1113
|
+
const $child = new SignalCompat([...$parent[SEGMENTS], key]);
|
|
1114
|
+
const $root = getRoot($parent);
|
|
1115
|
+
if ($root)
|
|
1116
|
+
$child[ROOT] = $root;
|
|
1117
|
+
return $child;
|
|
1118
|
+
}
|
|
1119
|
+
function setReplacePrivateCompatSync($signal, value) {
|
|
1120
|
+
const segments = $signal[SEGMENTS];
|
|
1121
|
+
if (segments.length === 0)
|
|
1122
|
+
throw Error('Can\'t set the root signal data');
|
|
1123
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1124
|
+
if (isIdFieldPath(segments, idFields))
|
|
1125
|
+
return;
|
|
1126
|
+
if (isPublicDocPath(segments)) {
|
|
1127
|
+
value = normalizeIdFields(value, idFields, segments[1]);
|
|
1128
|
+
}
|
|
1129
|
+
setReplacePrivateData(getOwningRootId($signal), segments, value);
|
|
1130
|
+
if (shouldMirrorPrivateRefMutationLocally()) {
|
|
1131
|
+
mirrorRefMutationFromTarget(segments, value);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
function delPrivateCompatSync($signal, options) {
|
|
1135
|
+
const segments = $signal[SEGMENTS];
|
|
1136
|
+
if (segments.length === 0)
|
|
1137
|
+
throw Error('Can\'t delete the root signal data');
|
|
1138
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1139
|
+
if (isIdFieldPath(segments, idFields))
|
|
1140
|
+
return;
|
|
1141
|
+
delPrivateData(getOwningRootId($signal), segments, options);
|
|
1142
|
+
}
|
|
1143
|
+
function deepEqualCompat(left, right) {
|
|
1144
|
+
if (left === right)
|
|
1145
|
+
return true;
|
|
1146
|
+
if (left == null || right == null)
|
|
1147
|
+
return false;
|
|
1148
|
+
if (typeof left !== 'object' || typeof right !== 'object')
|
|
1149
|
+
return false;
|
|
1150
|
+
if (Array.isArray(left) !== Array.isArray(right))
|
|
1151
|
+
return false;
|
|
1152
|
+
if (Array.isArray(left)) {
|
|
1153
|
+
if (left.length !== right.length)
|
|
1154
|
+
return false;
|
|
1155
|
+
for (let i = 0; i < left.length; i++) {
|
|
1156
|
+
if (!deepEqualCompat(left[i], right[i]))
|
|
1157
|
+
return false;
|
|
1158
|
+
}
|
|
1159
|
+
return true;
|
|
1160
|
+
}
|
|
1161
|
+
if (!isPlainObject(left) || !isPlainObject(right))
|
|
1162
|
+
return false;
|
|
1163
|
+
const leftKeys = Object.keys(left);
|
|
1164
|
+
const rightKeys = Object.keys(right);
|
|
1165
|
+
if (leftKeys.length !== rightKeys.length)
|
|
1166
|
+
return false;
|
|
1167
|
+
for (const key of leftKeys) {
|
|
1168
|
+
if (!Object.prototype.hasOwnProperty.call(right, key))
|
|
1169
|
+
return false;
|
|
1170
|
+
if (!deepEqualCompat(left[key], right[key]))
|
|
1171
|
+
return false;
|
|
1172
|
+
}
|
|
1173
|
+
return true;
|
|
1174
|
+
}
|
|
1175
|
+
function racerEqualCompat(left, right) {
|
|
1176
|
+
return left === right || (Number.isNaN(left) && Number.isNaN(right));
|
|
1177
|
+
}
|
|
1178
|
+
function getSignalValueAt($signal, segments) {
|
|
1179
|
+
const $target = resolveRelativePathTarget($signal, segments);
|
|
1180
|
+
return $target.get();
|
|
1181
|
+
}
|
|
1182
|
+
async function setReplaceOnSignal($signal, value) {
|
|
1183
|
+
const segments = $signal[SEGMENTS];
|
|
1184
|
+
if (segments.length === 0)
|
|
1185
|
+
throw Error('Can\'t set the root signal data');
|
|
1186
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1187
|
+
if (isIdFieldPath(segments, idFields))
|
|
1188
|
+
return;
|
|
1189
|
+
if (isPublicDocPath(segments)) {
|
|
1190
|
+
value = normalizeIdFields(value, idFields, segments[1]);
|
|
1191
|
+
}
|
|
1192
|
+
if (isPublicCollection(segments[0])) {
|
|
1193
|
+
const result = await _setPublicDocReplace(segments, value);
|
|
1194
|
+
if (shouldMirrorPublicRefMutationLocally(segments)) {
|
|
1195
|
+
mirrorRefMutationFromTarget(segments, value);
|
|
1196
|
+
}
|
|
1197
|
+
return result;
|
|
1198
|
+
}
|
|
1199
|
+
if (isPrivateMutationForbidden())
|
|
1200
|
+
throw Error(ERRORS.publicOnly);
|
|
1201
|
+
const result = setReplacePrivateData(getOwningRootId($signal), segments, value);
|
|
1202
|
+
if (shouldMirrorPrivateRefMutationLocally()) {
|
|
1203
|
+
mirrorRefMutationFromTarget(segments, value);
|
|
1204
|
+
}
|
|
1205
|
+
return result;
|
|
1206
|
+
}
|
|
1207
|
+
async function incrementOnSignal($signal, byNumber) {
|
|
1208
|
+
const segments = $signal[SEGMENTS];
|
|
1209
|
+
if (segments.length === 0)
|
|
1210
|
+
throw Error('Can\'t increment the root signal data');
|
|
1211
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1212
|
+
if (isIdFieldPath(segments, idFields))
|
|
1213
|
+
return $signal.get();
|
|
1214
|
+
if (byNumber == null)
|
|
1215
|
+
byNumber = 1;
|
|
1216
|
+
if (typeof byNumber !== 'number')
|
|
1217
|
+
throw Error('Signal.increment() expects a number argument');
|
|
1218
|
+
let currentValue = $signal.get();
|
|
1219
|
+
if (currentValue == null)
|
|
1220
|
+
currentValue = 0;
|
|
1221
|
+
if (typeof currentValue !== 'number')
|
|
1222
|
+
throw Error('Signal.increment() tried to increment a non-number value');
|
|
1223
|
+
if (isPublicCollection(segments[0])) {
|
|
1224
|
+
await _incrementPublic(segments, byNumber);
|
|
1225
|
+
return currentValue + byNumber;
|
|
1226
|
+
}
|
|
1227
|
+
if (isPrivateMutationForbidden())
|
|
1228
|
+
throw Error(ERRORS.publicOnly);
|
|
1229
|
+
setReplacePrivateData(getOwningRootId($signal), segments, currentValue + byNumber);
|
|
1230
|
+
return currentValue + byNumber;
|
|
1231
|
+
}
|
|
1232
|
+
function ensureArrayTarget($signal) {
|
|
1233
|
+
const segments = $signal[SEGMENTS];
|
|
1234
|
+
if (segments.length < 2)
|
|
1235
|
+
throw Error('Can\'t mutate array on a collection or root signal');
|
|
1236
|
+
if ($signal[IS_QUERY])
|
|
1237
|
+
throw Error('Array mutators can\'t be used on a query signal');
|
|
1238
|
+
return segments;
|
|
1239
|
+
}
|
|
1240
|
+
function ensureValueTarget($signal) {
|
|
1241
|
+
const segments = $signal[SEGMENTS];
|
|
1242
|
+
if (segments.length < 2)
|
|
1243
|
+
throw Error('Can\'t mutate on a collection or root signal');
|
|
1244
|
+
if ($signal[IS_QUERY])
|
|
1245
|
+
throw Error('Mutators can\'t be used on a query signal');
|
|
1246
|
+
return segments;
|
|
1247
|
+
}
|
|
1248
|
+
function ensureCreateTarget($signal, methodName) {
|
|
1249
|
+
const segments = $signal[SEGMENTS];
|
|
1250
|
+
if ($signal[IS_QUERY])
|
|
1251
|
+
throw Error(`${methodName} can't be used on a query signal`);
|
|
1252
|
+
if (segments.length !== 2) {
|
|
1253
|
+
throw Error(`${methodName} may only be used on a document path`);
|
|
1254
|
+
}
|
|
1255
|
+
return segments;
|
|
1256
|
+
}
|
|
1257
|
+
async function arrayPushOnSignal($signal, value) {
|
|
1258
|
+
const segments = ensureArrayTarget($signal);
|
|
1259
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1260
|
+
if (isIdFieldPath(segments, idFields))
|
|
1261
|
+
return;
|
|
1262
|
+
if (isPublicCollection(segments[0]))
|
|
1263
|
+
return _arrayPushPublic(segments, value);
|
|
1264
|
+
if (isPrivateMutationForbidden())
|
|
1265
|
+
throw Error(ERRORS.publicOnly);
|
|
1266
|
+
return arrayPushPrivateData(getOwningRootId($signal), segments, value);
|
|
1267
|
+
}
|
|
1268
|
+
async function arrayUnshiftOnSignal($signal, value) {
|
|
1269
|
+
const segments = ensureArrayTarget($signal);
|
|
1270
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1271
|
+
if (isIdFieldPath(segments, idFields))
|
|
1272
|
+
return;
|
|
1273
|
+
if (isPublicCollection(segments[0]))
|
|
1274
|
+
return _arrayUnshiftPublic(segments, value);
|
|
1275
|
+
if (isPrivateMutationForbidden())
|
|
1276
|
+
throw Error(ERRORS.publicOnly);
|
|
1277
|
+
return arrayUnshiftPrivateData(getOwningRootId($signal), segments, value);
|
|
1278
|
+
}
|
|
1279
|
+
async function arrayInsertOnSignal($signal, index, values) {
|
|
1280
|
+
const segments = ensureArrayTarget($signal);
|
|
1281
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1282
|
+
if (isIdFieldPath(segments, idFields))
|
|
1283
|
+
return;
|
|
1284
|
+
if (isPublicCollection(segments[0]))
|
|
1285
|
+
return _arrayInsertPublic(segments, index, values);
|
|
1286
|
+
if (isPrivateMutationForbidden())
|
|
1287
|
+
throw Error(ERRORS.publicOnly);
|
|
1288
|
+
return arrayInsertPrivateData(getOwningRootId($signal), segments, index, values);
|
|
1289
|
+
}
|
|
1290
|
+
async function arrayPopOnSignal($signal) {
|
|
1291
|
+
const segments = ensureArrayTarget($signal);
|
|
1292
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1293
|
+
if (isIdFieldPath(segments, idFields))
|
|
1294
|
+
return;
|
|
1295
|
+
if (isPublicCollection(segments[0]))
|
|
1296
|
+
return _arrayPopPublic(segments);
|
|
1297
|
+
if (isPrivateMutationForbidden())
|
|
1298
|
+
throw Error(ERRORS.publicOnly);
|
|
1299
|
+
return arrayPopPrivateData(getOwningRootId($signal), segments);
|
|
1300
|
+
}
|
|
1301
|
+
async function arrayShiftOnSignal($signal) {
|
|
1302
|
+
const segments = ensureArrayTarget($signal);
|
|
1303
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1304
|
+
if (isIdFieldPath(segments, idFields))
|
|
1305
|
+
return;
|
|
1306
|
+
if (isPublicCollection(segments[0]))
|
|
1307
|
+
return _arrayShiftPublic(segments);
|
|
1308
|
+
if (isPrivateMutationForbidden())
|
|
1309
|
+
throw Error(ERRORS.publicOnly);
|
|
1310
|
+
return arrayShiftPrivateData(getOwningRootId($signal), segments);
|
|
1311
|
+
}
|
|
1312
|
+
async function arrayRemoveOnSignal($signal, index, howMany) {
|
|
1313
|
+
const segments = ensureArrayTarget($signal);
|
|
1314
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1315
|
+
if (isIdFieldPath(segments, idFields))
|
|
1316
|
+
return;
|
|
1317
|
+
if (isPublicCollection(segments[0]))
|
|
1318
|
+
return _arrayRemovePublic(segments, index, howMany);
|
|
1319
|
+
if (isPrivateMutationForbidden())
|
|
1320
|
+
throw Error(ERRORS.publicOnly);
|
|
1321
|
+
return arrayRemovePrivateData(getOwningRootId($signal), segments, index, howMany);
|
|
1322
|
+
}
|
|
1323
|
+
async function arrayMoveOnSignal($signal, from, to, howMany) {
|
|
1324
|
+
const segments = ensureArrayTarget($signal);
|
|
1325
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1326
|
+
if (isIdFieldPath(segments, idFields))
|
|
1327
|
+
return;
|
|
1328
|
+
if (isPublicCollection(segments[0]))
|
|
1329
|
+
return _arrayMovePublic(segments, from, to, howMany);
|
|
1330
|
+
if (isPrivateMutationForbidden())
|
|
1331
|
+
throw Error(ERRORS.publicOnly);
|
|
1332
|
+
return arrayMovePrivateData(getOwningRootId($signal), segments, from, to, howMany);
|
|
1333
|
+
}
|
|
1334
|
+
async function stringInsertOnSignal($signal, index, text) {
|
|
1335
|
+
const segments = ensureValueTarget($signal);
|
|
1336
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1337
|
+
if (isIdFieldPath(segments, idFields))
|
|
1338
|
+
return;
|
|
1339
|
+
if (isPublicCollection(segments[0]))
|
|
1340
|
+
return _stringInsertPublic(segments, index, text);
|
|
1341
|
+
if (isPrivateMutationForbidden())
|
|
1342
|
+
throw Error(ERRORS.publicOnly);
|
|
1343
|
+
return stringInsertPrivateData(getOwningRootId($signal), segments, index, text);
|
|
1344
|
+
}
|
|
1345
|
+
async function stringRemoveOnSignal($signal, index, howMany) {
|
|
1346
|
+
const segments = ensureValueTarget($signal);
|
|
1347
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
1348
|
+
if (isIdFieldPath(segments, idFields))
|
|
1349
|
+
return;
|
|
1350
|
+
if (isPublicCollection(segments[0]))
|
|
1351
|
+
return _stringRemovePublic(segments, index, howMany);
|
|
1352
|
+
if (isPrivateMutationForbidden())
|
|
1353
|
+
throw Error(ERRORS.publicOnly);
|
|
1354
|
+
return stringRemovePrivateData(getOwningRootId($signal), segments, index, howMany);
|
|
1355
|
+
}
|
|
1356
|
+
function getOwningRootId($signal) {
|
|
1357
|
+
const $root = getRoot($signal) || $signal;
|
|
1358
|
+
return $root?.[ROOT_ID];
|
|
1359
|
+
}
|
|
1360
|
+
function ensurePrivateRefSource($signal, methodName) {
|
|
1361
|
+
const segments = $signal?.[SEGMENTS];
|
|
1362
|
+
const collection = segments?.[0];
|
|
1363
|
+
if (typeof collection === 'string' && /^[_$]/.test(collection))
|
|
1364
|
+
return;
|
|
1365
|
+
throw Error(`${methodName} source path must be in a private collection`);
|
|
1366
|
+
}
|
|
1367
|
+
function shouldMirrorPublicRefMutationLocally(segments) {
|
|
1368
|
+
if (isSilentContextActive())
|
|
1369
|
+
return true;
|
|
1370
|
+
if (!Array.isArray(segments) || segments.length < 2)
|
|
1371
|
+
return true;
|
|
1372
|
+
// Public doc ops emit compat model events only when there is an initialized
|
|
1373
|
+
// Doc runtime (subscribed/fetched). Without runtime we must mirror immediately.
|
|
1374
|
+
const transportHash = JSON.stringify([segments[0], segments[1]]);
|
|
1375
|
+
return !docSubscriptions.hasRuntime(transportHash);
|
|
1376
|
+
}
|
|
1377
|
+
function shouldMirrorPrivateRefMutationLocally() {
|
|
1378
|
+
if (isSilentContextActive())
|
|
1379
|
+
return true;
|
|
1380
|
+
return !isModelEventsEnabled();
|
|
1381
|
+
}
|
|
1382
|
+
function shallowCopy(value) {
|
|
1383
|
+
const rawValue = raw(value);
|
|
1384
|
+
if (Array.isArray(rawValue))
|
|
1385
|
+
return rawValue.slice();
|
|
1386
|
+
if (rawValue && typeof rawValue === 'object')
|
|
1387
|
+
return { ...rawValue };
|
|
1388
|
+
return rawValue;
|
|
1389
|
+
}
|
|
1390
|
+
function deepCopy(value) {
|
|
1391
|
+
const rawValue = raw(value);
|
|
1392
|
+
if (!rawValue || typeof rawValue !== 'object')
|
|
1393
|
+
return rawValue;
|
|
1394
|
+
if (typeof globalThis.structuredClone === 'function') {
|
|
1395
|
+
try {
|
|
1396
|
+
return globalThis.structuredClone(rawValue);
|
|
1397
|
+
}
|
|
1398
|
+
catch { }
|
|
1399
|
+
}
|
|
1400
|
+
return racerDeepCopy(rawValue);
|
|
1401
|
+
}
|
|
1402
|
+
function normalizeQueryParams(collection, params) {
|
|
1403
|
+
if (params == null) {
|
|
1404
|
+
console.warn(`
|
|
1405
|
+
[Signal.query] Query is undefined. Got:
|
|
1406
|
+
${collection}, ${params}
|
|
1407
|
+
Falling back to {_id: '__NON_EXISTENT__'} query to prevent critical crash.
|
|
1408
|
+
You should prevent situations when the \`query\` is undefined.
|
|
1409
|
+
`);
|
|
1410
|
+
return { _id: '__NON_EXISTENT__' };
|
|
1411
|
+
}
|
|
1412
|
+
if (Array.isArray(params)) {
|
|
1413
|
+
return { _id: { $in: params.slice() } };
|
|
1414
|
+
}
|
|
1415
|
+
if (typeof params === 'string' || typeof params === 'number') {
|
|
1416
|
+
return { _id: params };
|
|
1417
|
+
}
|
|
1418
|
+
if (typeof params !== 'object') {
|
|
1419
|
+
throw Error(`Signal.query() expects params to be an object, array, or id. Got: ${params}`);
|
|
1420
|
+
}
|
|
1421
|
+
return params;
|
|
1422
|
+
}
|
|
1423
|
+
function isAggregationParams(params) {
|
|
1424
|
+
return Boolean(params?.$aggregate || params?.$aggregationName);
|
|
1425
|
+
}
|
|
1426
|
+
function withQueryScopeOptions(options, $root) {
|
|
1427
|
+
if (!options || typeof options !== 'object') {
|
|
1428
|
+
if (!$root)
|
|
1429
|
+
return options;
|
|
1430
|
+
return { root: $root };
|
|
1431
|
+
}
|
|
1432
|
+
const nextOptions = { ...options };
|
|
1433
|
+
if (nextOptions.root == null && $root)
|
|
1434
|
+
nextOptions.root = $root;
|
|
1435
|
+
return nextOptions;
|
|
1436
|
+
}
|
|
1437
|
+
function subscribeMany(items, action, intent = 'subscribe') {
|
|
1438
|
+
const targets = flattenItems(items);
|
|
1439
|
+
const promises = [];
|
|
1440
|
+
for (const target of targets) {
|
|
1441
|
+
if (!target)
|
|
1442
|
+
continue;
|
|
1443
|
+
if (!(target instanceof Signal)) {
|
|
1444
|
+
throw Error(`Signal.${action}() accepts only Signal instances. Got: ${target}`);
|
|
1445
|
+
}
|
|
1446
|
+
const result = action === 'subscribe'
|
|
1447
|
+
? subscribeSelf(target, intent)
|
|
1448
|
+
: unsubscribeSelf(target, intent);
|
|
1449
|
+
if (result?.then)
|
|
1450
|
+
promises.push(result);
|
|
1451
|
+
}
|
|
1452
|
+
if (promises.length)
|
|
1453
|
+
return Promise.all(promises);
|
|
1454
|
+
}
|
|
1455
|
+
function flattenItems(items, result = []) {
|
|
1456
|
+
for (const item of items) {
|
|
1457
|
+
if (!item)
|
|
1458
|
+
continue;
|
|
1459
|
+
if (Array.isArray(item)) {
|
|
1460
|
+
flattenItems(item, result);
|
|
1461
|
+
}
|
|
1462
|
+
else {
|
|
1463
|
+
result.push(item);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
return result;
|
|
1467
|
+
}
|
|
1468
|
+
function subscribeSelf($signal, intent = 'subscribe') {
|
|
1469
|
+
if ($signal[IS_QUERY]) {
|
|
1470
|
+
return (async () => {
|
|
1471
|
+
await querySubscriptions.subscribe($signal, { intent });
|
|
1472
|
+
await waitForImperativeQueryReady($signal);
|
|
1473
|
+
})();
|
|
1474
|
+
}
|
|
1475
|
+
if ($signal[IS_AGGREGATION]) {
|
|
1476
|
+
return (async () => {
|
|
1477
|
+
await aggregationSubscriptions.subscribe($signal, { intent });
|
|
1478
|
+
await waitForImperativeQueryReady($signal);
|
|
1479
|
+
})();
|
|
1480
|
+
}
|
|
1481
|
+
if (isPublicDocumentSignal($signal))
|
|
1482
|
+
return docSubscriptions.subscribe($signal, { intent });
|
|
1483
|
+
if (isPublicCollectionSignal($signal)) {
|
|
1484
|
+
throw Error('Signal.subscribe() expects a query signal. Use .query() for collections.');
|
|
1485
|
+
}
|
|
1486
|
+
if ($signal[SEGMENTS].length === 0) {
|
|
1487
|
+
throw Error('Signal.subscribe() cannot be called on the root signal');
|
|
1488
|
+
}
|
|
1489
|
+
throw Error('Signal.subscribe() expects a document or query signal');
|
|
1490
|
+
}
|
|
1491
|
+
function unsubscribeSelf($signal, intent = 'subscribe') {
|
|
1492
|
+
if ($signal[IS_QUERY])
|
|
1493
|
+
return querySubscriptions.unsubscribe($signal, { intent });
|
|
1494
|
+
if ($signal[IS_AGGREGATION])
|
|
1495
|
+
return aggregationSubscriptions.unsubscribe($signal, { intent });
|
|
1496
|
+
if (isPublicDocumentSignal($signal))
|
|
1497
|
+
return docSubscriptions.unsubscribe($signal, { intent });
|
|
1498
|
+
if (isPublicCollectionSignal($signal)) {
|
|
1499
|
+
throw Error('Signal.unsubscribe() expects a query signal. Use .query() for collections.');
|
|
1500
|
+
}
|
|
1501
|
+
if ($signal[SEGMENTS].length === 0) {
|
|
1502
|
+
throw Error('Signal.unsubscribe() cannot be called on the root signal');
|
|
1503
|
+
}
|
|
1504
|
+
throw Error('Signal.unsubscribe() expects a document or query signal');
|
|
1505
|
+
}
|
|
1506
|
+
// Racer-style deep copy:
|
|
1507
|
+
// - Preserves prototypes by instantiating via `new value.constructor()`
|
|
1508
|
+
// - Copies own enumerable props recursively
|
|
1509
|
+
// - Keeps functions as-is (no cloning)
|
|
1510
|
+
// - Handles Date by creating a new Date
|
|
1511
|
+
// Limitations: does not handle cyclic refs, Map/Set/RegExp/TypedArray, non-enumerables.
|
|
1512
|
+
function racerDeepCopy(value) {
|
|
1513
|
+
if (value instanceof Date)
|
|
1514
|
+
return new Date(value);
|
|
1515
|
+
if (typeof value === 'object') {
|
|
1516
|
+
if (value === null)
|
|
1517
|
+
return null;
|
|
1518
|
+
if (Array.isArray(value)) {
|
|
1519
|
+
const array = [];
|
|
1520
|
+
for (let i = value.length; i--;) {
|
|
1521
|
+
array[i] = racerDeepCopy(value[i]);
|
|
1522
|
+
}
|
|
1523
|
+
return array;
|
|
1524
|
+
}
|
|
1525
|
+
const object = new value.constructor();
|
|
1526
|
+
for (const key in value) {
|
|
1527
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
1528
|
+
object[key] = racerDeepCopy(value[key]);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
return object;
|
|
1532
|
+
}
|
|
1533
|
+
return value;
|
|
1534
|
+
}
|
|
1535
|
+
const ERRORS = {
|
|
1536
|
+
publicOnly: `
|
|
1537
|
+
Can't modify private collections data when 'publicOnly' is enabled.
|
|
1538
|
+
On the server you can only work with public collections.
|
|
1539
|
+
`
|
|
1540
|
+
};
|
|
1541
|
+
export { SignalCompat };
|
|
1542
|
+
export default SignalCompat;
|