teamplay 0.4.0 → 0.5.0-alpha.1
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
package/babel-loader.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('babel-plugin-teamplay/loader')
|
package/babel.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('babel-plugin-teamplay')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function connect(options: any): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Socket from '@teamplay/channel';
|
|
2
|
+
import Connection from './sharedbConnection.cjs';
|
|
3
|
+
import { connection, setConnection } from "../orm/connection.js";
|
|
4
|
+
export default function connect(options) {
|
|
5
|
+
if (connection)
|
|
6
|
+
return;
|
|
7
|
+
const socket = new Socket(options);
|
|
8
|
+
setConnection(new Connection(socket));
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export = CrossTabPubSub;
|
|
2
|
+
declare function CrossTabPubSub({ onMessage, ...options }?: {}): CrossTabPubSub;
|
|
3
|
+
declare class CrossTabPubSub {
|
|
4
|
+
constructor({ onMessage, ...options }?: {});
|
|
5
|
+
_onMessage: any;
|
|
6
|
+
close(callback: any): void;
|
|
7
|
+
_subscribe(channel: any, callback: any): any;
|
|
8
|
+
_unsubscribe(channel: any, callback: any): any;
|
|
9
|
+
_publish(channels: any, data: any, callback: any): any;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function createConnectWithPersistence({ storage, createPubsub }?: {}): () => Promise<void>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Offline 'connect' implementation with persistence to local storage.
|
|
2
|
+
// This creates a full sharedb server with mingo database in the browser or react-native app.
|
|
3
|
+
import ShareDbMingo from '@startupjs/sharedb-mingo-memory';
|
|
4
|
+
import ShareBackend from 'sharedb';
|
|
5
|
+
import { connection, setConnection } from "../../orm/connection.js";
|
|
6
|
+
const STORAGE_NAMESPACE = 'teamplay-offline';
|
|
7
|
+
const DOCS_PREFIX = `${STORAGE_NAMESPACE}:docs:`;
|
|
8
|
+
const LAST_OP_PREFIX = `${STORAGE_NAMESPACE}:last-op:`;
|
|
9
|
+
export default function createConnectWithPersistence({ storage, createPubsub } = {}) {
|
|
10
|
+
if (!storage)
|
|
11
|
+
throw new Error('[connect-offline] storage is required');
|
|
12
|
+
return async function connect() {
|
|
13
|
+
if (connection)
|
|
14
|
+
return;
|
|
15
|
+
const db = new ShareDbMingo();
|
|
16
|
+
const options = { db };
|
|
17
|
+
const { pubsub } = (await init(db, storage, createPubsub)) || {};
|
|
18
|
+
if (pubsub)
|
|
19
|
+
options.pubsub = pubsub;
|
|
20
|
+
const backend = new ShareBackend(options);
|
|
21
|
+
setConnection(backend.connect());
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async function init(db, storage, createPubsub) {
|
|
25
|
+
await loadData(db, storage);
|
|
26
|
+
addPersistence(db, storage);
|
|
27
|
+
globalThis.db = db;
|
|
28
|
+
const pubsub = createPubsub
|
|
29
|
+
? createPubsub((channel, data) => {
|
|
30
|
+
if (!(data?.c && data?.d))
|
|
31
|
+
return;
|
|
32
|
+
updateDocInDb(db, storage, data.c, data.d);
|
|
33
|
+
})
|
|
34
|
+
: null;
|
|
35
|
+
return { pubsub };
|
|
36
|
+
}
|
|
37
|
+
// do same thing as in loadData but for a single doc
|
|
38
|
+
async function updateDocInDb(db, storage, collection, docId) {
|
|
39
|
+
try {
|
|
40
|
+
const snapshot = await storage.getItem(getDocsKey(collection, docId));
|
|
41
|
+
if (!snapshot)
|
|
42
|
+
return;
|
|
43
|
+
if (!db.docs[collection]) {
|
|
44
|
+
db.docs[collection] = {};
|
|
45
|
+
db.ops[collection] = {};
|
|
46
|
+
}
|
|
47
|
+
if (snapshot && typeof snapshot === 'object' && snapshot.v == null)
|
|
48
|
+
snapshot.v = 0;
|
|
49
|
+
db.docs[collection][docId] = snapshot;
|
|
50
|
+
if (!db.ops[collection])
|
|
51
|
+
db.ops[collection] = {};
|
|
52
|
+
const lastOp = await storage.getItem(getLastOpKey(collection, docId));
|
|
53
|
+
db.ops[collection][docId] = buildOpsArray(lastOp);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error('Error updating doc from storage:', err);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function loadData(db, storage) {
|
|
60
|
+
const docsToLoad = [];
|
|
61
|
+
await storage.iterate((value, key) => {
|
|
62
|
+
const parsedKey = parseStorageKey(key);
|
|
63
|
+
if (!parsedKey || parsedKey.type !== 'docs')
|
|
64
|
+
return;
|
|
65
|
+
const { collection, docId } = parsedKey;
|
|
66
|
+
if (!db.docs[collection]) {
|
|
67
|
+
db.docs[collection] = {};
|
|
68
|
+
db.ops[collection] = {};
|
|
69
|
+
}
|
|
70
|
+
// We don't support multiplayer in offline-only mode.
|
|
71
|
+
// Note: if you have multiple tabs open in browser then the last operation wins.
|
|
72
|
+
if (value && typeof value === 'object' && value.v == null)
|
|
73
|
+
value.v = 0;
|
|
74
|
+
db.docs[collection][docId] = value;
|
|
75
|
+
if (!db.ops[collection][docId])
|
|
76
|
+
db.ops[collection][docId] = [];
|
|
77
|
+
docsToLoad.push({ collection, docId });
|
|
78
|
+
});
|
|
79
|
+
for (const { collection, docId } of docsToLoad) {
|
|
80
|
+
const lastOp = await storage.getItem(getLastOpKey(collection, docId));
|
|
81
|
+
if (!db.ops[collection])
|
|
82
|
+
db.ops[collection] = {};
|
|
83
|
+
db.ops[collection][docId] = buildOpsArray(lastOp);
|
|
84
|
+
}
|
|
85
|
+
console.log('DB data was loaded from storage to shareDbMingo');
|
|
86
|
+
}
|
|
87
|
+
function addPersistence(db, storage) {
|
|
88
|
+
const originalCommit = db.commit;
|
|
89
|
+
db.commit = function (collection, docId, op, snapshot, options, callback) {
|
|
90
|
+
originalCommit.call(this, collection, docId, op, snapshot, options, async (err) => {
|
|
91
|
+
if (err)
|
|
92
|
+
return callback(err);
|
|
93
|
+
try {
|
|
94
|
+
await storage.setItem(getDocsKey(collection, docId), snapshot);
|
|
95
|
+
await storage.setItem(getLastOpKey(collection, docId), op);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
throw Error('Error saving to storage:\n', err.message);
|
|
99
|
+
}
|
|
100
|
+
callback(null, true);
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function parseStorageKey(key) {
|
|
105
|
+
const [namespace, type, collection, ...docSegments] = key.split(':');
|
|
106
|
+
if (namespace !== STORAGE_NAMESPACE)
|
|
107
|
+
return null;
|
|
108
|
+
return { type, collection, docId: docSegments.join(':') };
|
|
109
|
+
}
|
|
110
|
+
function getDocsKey(collection, docId) {
|
|
111
|
+
return `${DOCS_PREFIX}${collection}:${docId}`;
|
|
112
|
+
}
|
|
113
|
+
function getLastOpKey(collection, docId) {
|
|
114
|
+
return `${LAST_OP_PREFIX}${collection}:${docId}`;
|
|
115
|
+
}
|
|
116
|
+
function buildOpsArray(lastOp) {
|
|
117
|
+
if (!lastOp)
|
|
118
|
+
return [];
|
|
119
|
+
const version = lastOp.v;
|
|
120
|
+
if (Number.isFinite(version) && version > 0) {
|
|
121
|
+
const ops = new Array(version + 1);
|
|
122
|
+
ops[version] = lastOp;
|
|
123
|
+
return ops;
|
|
124
|
+
}
|
|
125
|
+
return [lastOp];
|
|
126
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export namespace storage {
|
|
2
|
+
export { getItem };
|
|
3
|
+
export { setItem };
|
|
4
|
+
export { iterate };
|
|
5
|
+
}
|
|
6
|
+
declare const _default: () => Promise<void>;
|
|
7
|
+
export default _default;
|
|
8
|
+
declare function getItem(key: any): Promise<any>;
|
|
9
|
+
declare function setItem(key: any, value: any): Promise<any>;
|
|
10
|
+
declare function iterate(iterator: any): Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
|
+
import createConnectWithPersistence from './index.js';
|
|
3
|
+
async function getItem(key) {
|
|
4
|
+
const value = await AsyncStorage.getItem(key);
|
|
5
|
+
if (value == null)
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(value);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async function setItem(key, value) {
|
|
15
|
+
return AsyncStorage.setItem(key, JSON.stringify(value));
|
|
16
|
+
}
|
|
17
|
+
async function iterate(iterator) {
|
|
18
|
+
const keys = await AsyncStorage.getAllKeys();
|
|
19
|
+
for (const key of keys) {
|
|
20
|
+
const value = await getItem(key);
|
|
21
|
+
await iterator(value, key);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export const storage = { getItem, setItem, iterate };
|
|
25
|
+
export default createConnectWithPersistence({ storage });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function createPubsub(onMessage: any): SharedbCrosstabPubsub;
|
|
2
|
+
export namespace storage {
|
|
3
|
+
function getItem(key: any): Promise<any>;
|
|
4
|
+
function setItem(key: any, value: any): Promise<any>;
|
|
5
|
+
function iterate(iterator: any): Promise<any>;
|
|
6
|
+
}
|
|
7
|
+
declare const _default: () => Promise<void>;
|
|
8
|
+
export default _default;
|
|
9
|
+
import SharedbCrosstabPubsub from '../lib/sharedb-crosstab-pubsub.cjs';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import localforage from 'localforage';
|
|
2
|
+
import SharedbCrosstabPubsub from '../lib/sharedb-crosstab-pubsub.cjs';
|
|
3
|
+
import createConnectWithPersistence from './index.js';
|
|
4
|
+
export const storage = {
|
|
5
|
+
getItem: key => localforage.getItem(key),
|
|
6
|
+
setItem: (key, value) => localforage.setItem(key, value),
|
|
7
|
+
iterate: iterator => localforage.iterate(iterator)
|
|
8
|
+
};
|
|
9
|
+
export function createPubsub(onMessage) {
|
|
10
|
+
return new SharedbCrosstabPubsub({ onMessage });
|
|
11
|
+
}
|
|
12
|
+
export default createConnectWithPersistence({ storage, createPubsub });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function connect(): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// mock of client connection to sharedb to use inside tests.
|
|
2
|
+
// This just creates a sharedb server with in-memory database
|
|
3
|
+
// and creates a server connection to it.
|
|
4
|
+
import ShareDbMingo from '@startupjs/sharedb-mingo-memory';
|
|
5
|
+
import ShareBackend from 'sharedb';
|
|
6
|
+
import { connection, setConnection } from "../orm/connection.js";
|
|
7
|
+
export default function connect() {
|
|
8
|
+
if (connection)
|
|
9
|
+
return;
|
|
10
|
+
const backend = new ShareBackend({ db: new ShareDbMingo() });
|
|
11
|
+
setConnection(backend.connect());
|
|
12
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import { SEGMENTS } from './orm/Signal.js';
|
|
3
|
+
import useApi from './react/useApi.js';
|
|
4
|
+
import type { AnySignal, ArraySignal, CollectionDocument, CollectionDocumentModel, CollectionSignal, CollectionSignalFromSpec, CollectionAggregationSignal, CollectionQuerySignal, CollectionSpec, CollectionsFromManifest, DocumentSignal, FromJsonSchema, JsonSchema, JsonSchemaSpec, MaybePromise, MaybePromiseSubResult, ModelEntry, ModelManifest, PathModelsFromManifest, PublicSignal, LocalSignalFactory, RuntimeSignalConstructor, RuntimeSignalInstance, RootCollections, RootSignal, WildcardPathSegment, WildcardSignalPath, AppendPath, JoinPath, QueryParams, QuerySignal, RegisteredAggregationInput, SignalChild, SignalBaseInstance, SignalArrayMutatorMethods, SignalArrayReaderMethods, SignalClass, SignalCollectionMethods, SignalConstructor, SignalForKind, SignalKind, SignalMetadataMethods, SignalModelConstructor, SignalStringMutatorMethods, SignalValueMethods, SubResult, TypedAggregationInput, TypedAggregationSignal, TypedSignal, ZodLikeSchema, ZodSchemaSpec } from './orm/Signal.js';
|
|
5
|
+
export interface TeamplayCollections {
|
|
6
|
+
}
|
|
7
|
+
export interface TeamplayModels {
|
|
8
|
+
}
|
|
9
|
+
export interface TeamplaySignalFields {
|
|
10
|
+
}
|
|
11
|
+
export type Signal<TValue = unknown> = PublicSignal<TValue>;
|
|
12
|
+
export type { AnySignal, ArraySignal, CollectionDocument, CollectionDocumentModel, CollectionSignal, CollectionSpec, CollectionSignalFromSpec, CollectionAggregationSignal, CollectionQuerySignal, DocumentSignal, FromJsonSchema, JsonSchema, JsonSchemaSpec, MaybePromise, MaybePromiseSubResult, ModelEntry, ModelManifest, CollectionsFromManifest, LocalSignalFactory, PathModelsFromManifest, PublicSignal, RuntimeSignalConstructor, RuntimeSignalInstance, RootCollections, RootSignal, WildcardPathSegment, WildcardSignalPath, AppendPath, JoinPath, QueryParams, QuerySignal, RegisteredAggregationInput, SignalArrayMutatorMethods, SignalArrayReaderMethods, SignalBaseInstance, SignalClass, SignalChild, SignalConstructor, SignalCollectionMethods, SignalForKind, SignalKind, SignalMetadataMethods, SignalModelConstructor, SignalStringMutatorMethods, SignalValueMethods, SubResult, TypedAggregationInput, TypedAggregationSignal, TypedSignal, ZodLikeSchema, ZodSchemaSpec };
|
|
13
|
+
export interface ObserverOptions {
|
|
14
|
+
forwardRef?: boolean;
|
|
15
|
+
cache?: boolean;
|
|
16
|
+
throttle?: number | boolean;
|
|
17
|
+
defer?: boolean | number;
|
|
18
|
+
suspenseProps?: React.ComponentProps<typeof React.Suspense>;
|
|
19
|
+
}
|
|
20
|
+
export type ObserverComponent<TProps extends object> = (props: TProps) => React.ReactNode;
|
|
21
|
+
export type ObserverForwardRefComponent<TProps extends object, TRef> = (props: TProps, ref: React.ForwardedRef<TRef>) => React.ReactNode;
|
|
22
|
+
export type ObserverForwardRefOptions = Omit<ObserverOptions, 'forwardRef'> & {
|
|
23
|
+
forwardRef: true;
|
|
24
|
+
};
|
|
25
|
+
export interface ObserverFunction {
|
|
26
|
+
<TProps extends object, TRef = unknown>(Component: ObserverForwardRefComponent<TProps, TRef>, options: ObserverForwardRefOptions): React.NamedExoticComponent<React.PropsWithoutRef<TProps> & React.RefAttributes<TRef>>;
|
|
27
|
+
<TProps extends object>(Component: ObserverComponent<TProps>, options?: ObserverOptions): React.NamedExoticComponent<TProps>;
|
|
28
|
+
__wrapObserverMeta: unknown;
|
|
29
|
+
__makeObserver: unknown;
|
|
30
|
+
}
|
|
31
|
+
export declare const Signal: SignalConstructor;
|
|
32
|
+
export { SEGMENTS };
|
|
33
|
+
export { __DEBUG_SIGNALS_CACHE__, rawSignal, getSignalClass } from './orm/getSignal.js';
|
|
34
|
+
export { default as addModel } from './orm/addModel.js';
|
|
35
|
+
export { defineModels, default as initModels, getModels, resetModelsForTests } from './orm/initModels.js';
|
|
36
|
+
export { default as signal } from './orm/getSignal.js';
|
|
37
|
+
export { GLOBAL_ROOT_ID } from './orm/Root.js';
|
|
38
|
+
export declare const $: RootSignal;
|
|
39
|
+
export declare const $root: RootSignal;
|
|
40
|
+
export declare const model: RootSignal;
|
|
41
|
+
export default $;
|
|
42
|
+
export { default as sub } from './orm/sub.js';
|
|
43
|
+
export { default as useSub, useAsyncSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from './react/useSub.js';
|
|
44
|
+
export { default as useSuspendMemo, useSuspendMemoByKey } from './react/useSuspendMemo.js';
|
|
45
|
+
export declare const observer: ObserverFunction;
|
|
46
|
+
export { useValue, useValue$, useModel, useLocal, useLocal$, useLocalDoc, useLocalDoc$, useSession, useSession$, usePage, usePage$, useBatch, useDoc, useDoc$, useBatchDoc, useBatchDoc$, useAsyncDoc, useAsyncDoc$, useQuery, useQuery$, useAsyncQuery, useAsyncQuery$, useBatchQuery, useBatchQuery$, useQueryIds, useBatchQueryIds, useAsyncQueryIds, useQueryDoc, useQueryDoc$, useBatchQueryDoc, useBatchQueryDoc$, useAsyncQueryDoc, useAsyncQueryDoc$ } from './orm/Compat/hooksCompat.js';
|
|
47
|
+
export { emit, useOn, useEmit } from './orm/Compat/eventsCompat.js';
|
|
48
|
+
export { useDidUpdate, useOnce, useSyncEffect } from './react/helpers.js';
|
|
49
|
+
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly, publicOnly, setPublicOnly } from './orm/connection.js';
|
|
50
|
+
export type { TeamplayConnection, TeamplayShareDoc } from './orm/connection.js';
|
|
51
|
+
export { getSubscriptionGcDelay, setSubscriptionGcDelay } from './orm/subscriptionGcDelay.js';
|
|
52
|
+
export { useId, useNow, useScheduleUpdate, useTriggerUpdate } from './react/helpers.js';
|
|
53
|
+
export { GUID_PATTERN, defineSchema, hasMany, hasOne, hasManyFlags, belongsTo, pickFormFields } from '@teamplay/schema';
|
|
54
|
+
export { aggregation, aggregationHeader as __aggregationHeader } from '@teamplay/utils/aggregation';
|
|
55
|
+
export { accessControl } from '@teamplay/utils/accessControl';
|
|
56
|
+
export type { AggregationCallback, AggregationContext, AggregationFunction, AggregationMeta, AggregationParams, AggregationQuery, ClientAggregationFunction, DefaultAggregationSession } from '@teamplay/utils/aggregation';
|
|
57
|
+
export type { AccessControl, AccessControlRules, AccessCreateContext, AccessDecision, AccessDeleteContext, AccessOperation, AccessReadContext, AccessRule, AccessUpdateContext, AccessValidator, AccessValidatorObject, DefaultAccessSession } from '@teamplay/utils/accessControl';
|
|
58
|
+
export declare function batch(): undefined;
|
|
59
|
+
export declare function batch<TResult>(fn: () => TResult): TResult;
|
|
60
|
+
export declare function batchModel(): undefined;
|
|
61
|
+
export declare function batchModel<TResult>(fn: () => TResult): TResult;
|
|
62
|
+
export declare function serverOnly<TValue>(value: TValue): TValue;
|
|
63
|
+
export declare function clone<TValue>(value: TValue): TValue;
|
|
64
|
+
export declare function initLocalCollection(name: string): any;
|
|
65
|
+
export { useApi };
|
|
66
|
+
export declare function getRootSignal<TCollections extends Record<string, any> = TeamplayCollections>(options?: Record<string, any>): RootSignal<TCollections>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import RuntimeSignal, { SEGMENTS } from "./orm/Signal.js";
|
|
2
|
+
import { getRootSignal as _getRootSignal, GLOBAL_ROOT_ID } from "./orm/Root.js";
|
|
3
|
+
import universal$ from "./react/universal$.js";
|
|
4
|
+
import useApi from "./react/useApi.js";
|
|
5
|
+
import runtimeObserver from "./react/observer.js";
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
7
|
+
export const Signal = RuntimeSignal;
|
|
8
|
+
export { SEGMENTS };
|
|
9
|
+
export { __DEBUG_SIGNALS_CACHE__, rawSignal, getSignalClass } from "./orm/getSignal.js";
|
|
10
|
+
export { default as addModel } from "./orm/addModel.js";
|
|
11
|
+
export { defineModels, default as initModels, getModels, resetModelsForTests } from "./orm/initModels.js";
|
|
12
|
+
export { default as signal } from "./orm/getSignal.js";
|
|
13
|
+
export { GLOBAL_ROOT_ID } from "./orm/Root.js";
|
|
14
|
+
const getRuntimeRootSignal = _getRootSignal;
|
|
15
|
+
export const $ = getRuntimeRootSignal({ rootId: GLOBAL_ROOT_ID, rootFunction: universal$ });
|
|
16
|
+
export const $root = $;
|
|
17
|
+
export const model = $;
|
|
18
|
+
export default $;
|
|
19
|
+
export { default as sub } from "./orm/sub.js";
|
|
20
|
+
export { default as useSub, useAsyncSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from "./react/useSub.js";
|
|
21
|
+
export { default as useSuspendMemo, useSuspendMemoByKey } from "./react/useSuspendMemo.js";
|
|
22
|
+
export const observer = runtimeObserver;
|
|
23
|
+
export { useValue, useValue$, useModel, useLocal, useLocal$, useLocalDoc, useLocalDoc$, useSession, useSession$, usePage, usePage$, useBatch, useDoc, useDoc$, useBatchDoc, useBatchDoc$, useAsyncDoc, useAsyncDoc$, useQuery, useQuery$, useAsyncQuery, useAsyncQuery$, useBatchQuery, useBatchQuery$, useQueryIds, useBatchQueryIds, useAsyncQueryIds, useQueryDoc, useQueryDoc$, useBatchQueryDoc, useBatchQueryDoc$, useAsyncQueryDoc, useAsyncQueryDoc$ } from './orm/Compat/hooksCompat.js';
|
|
24
|
+
export { emit, useOn, useEmit } from './orm/Compat/eventsCompat.js';
|
|
25
|
+
export { useDidUpdate, useOnce, useSyncEffect } from "./react/helpers.js";
|
|
26
|
+
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly, publicOnly, setPublicOnly } from "./orm/connection.js";
|
|
27
|
+
export { getSubscriptionGcDelay, setSubscriptionGcDelay } from "./orm/subscriptionGcDelay.js";
|
|
28
|
+
export { useId, useNow, useScheduleUpdate, useTriggerUpdate } from "./react/helpers.js";
|
|
29
|
+
export { GUID_PATTERN, defineSchema, hasMany, hasOne, hasManyFlags, belongsTo, pickFormFields } from '@teamplay/schema';
|
|
30
|
+
export { aggregation, aggregationHeader as __aggregationHeader } from '@teamplay/utils/aggregation';
|
|
31
|
+
export { accessControl } from '@teamplay/utils/accessControl';
|
|
32
|
+
export function batch(fn) {
|
|
33
|
+
return fn == null ? $.batch() : $.batch(fn);
|
|
34
|
+
}
|
|
35
|
+
export function batchModel(fn) {
|
|
36
|
+
return fn == null ? $.batch() : $.batch(fn);
|
|
37
|
+
}
|
|
38
|
+
export function serverOnly(value) {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
export function clone(value) {
|
|
42
|
+
if (typeof globalThis.structuredClone === 'function') {
|
|
43
|
+
try {
|
|
44
|
+
return globalThis.structuredClone(value);
|
|
45
|
+
}
|
|
46
|
+
catch { }
|
|
47
|
+
}
|
|
48
|
+
if (value == null)
|
|
49
|
+
return value;
|
|
50
|
+
return JSON.parse(JSON.stringify(value));
|
|
51
|
+
}
|
|
52
|
+
export function initLocalCollection(name) {
|
|
53
|
+
if (typeof name !== 'string')
|
|
54
|
+
throw Error('initLocalCollection() expects a collection name');
|
|
55
|
+
if (!name)
|
|
56
|
+
return;
|
|
57
|
+
const segments = name.split('.').filter(Boolean);
|
|
58
|
+
if (!segments.length)
|
|
59
|
+
return;
|
|
60
|
+
let $cursor = $;
|
|
61
|
+
for (const segment of segments) {
|
|
62
|
+
$cursor = $cursor[segment];
|
|
63
|
+
}
|
|
64
|
+
if ($cursor.get() == null)
|
|
65
|
+
$cursor.set({});
|
|
66
|
+
return $cursor;
|
|
67
|
+
}
|
|
68
|
+
export { useApi };
|
|
69
|
+
export function getRootSignal(options) {
|
|
70
|
+
return getRuntimeRootSignal({
|
|
71
|
+
rootFunction: universal$,
|
|
72
|
+
...options
|
|
73
|
+
});
|
|
74
|
+
}
|
package/dist/orm/$.d.ts
ADDED
package/dist/orm/$.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// this is just the $() function implementation.
|
|
2
|
+
// The actual $ exported from this package is a Proxy targeting the dataTree root,
|
|
3
|
+
// and this function is an implementation of the `apply` handler for that Proxy.
|
|
4
|
+
import getSignal from "./getSignal.js";
|
|
5
|
+
import Signal from "./Signal.js";
|
|
6
|
+
import { LOCAL, valueSubscriptions } from './Value.js';
|
|
7
|
+
import { reactionSubscriptions } from './Reaction.js';
|
|
8
|
+
export { LOCAL } from './Value.js';
|
|
9
|
+
let counter = 0;
|
|
10
|
+
function newIncrementalId() {
|
|
11
|
+
const id = `_${counter}`;
|
|
12
|
+
counter += 1;
|
|
13
|
+
return id;
|
|
14
|
+
}
|
|
15
|
+
export default function $($root, value, id) {
|
|
16
|
+
if (!($root instanceof Signal))
|
|
17
|
+
throw Error('First argument of $() should be a Root Signal');
|
|
18
|
+
if (typeof value === 'function') {
|
|
19
|
+
return reaction$($root, value, id);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return value$($root, value, id);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function value$($root, value, id = newIncrementalId()) {
|
|
26
|
+
const $value = getSignal($root, [LOCAL, id]);
|
|
27
|
+
valueSubscriptions.init($value, value);
|
|
28
|
+
return $value;
|
|
29
|
+
}
|
|
30
|
+
function reaction$($root, fn, id = newIncrementalId()) {
|
|
31
|
+
const $value = getSignal($root, [LOCAL, id]);
|
|
32
|
+
reactionSubscriptions.init($value, fn);
|
|
33
|
+
return $value;
|
|
34
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type Signal from './Signal.js'
|
|
2
|
+
import type {
|
|
3
|
+
QuerySubscriptions,
|
|
4
|
+
QuerySignalOptions
|
|
5
|
+
} from './Query.js'
|
|
6
|
+
|
|
7
|
+
export const IS_AGGREGATION: unique symbol
|
|
8
|
+
export const AGGREGATIONS: '$aggregations'
|
|
9
|
+
export const aggregationSubscriptions: QuerySubscriptions
|
|
10
|
+
export function getAggregationSignal (collectionName: string, params: unknown, options?: QuerySignalOptions): Signal
|
|
11
|
+
export function isAggregationSignal ($signal: unknown): boolean | undefined
|
|
12
|
+
export function getAggregationDocId (
|
|
13
|
+
segments: readonly unknown[],
|
|
14
|
+
rootId?: string,
|
|
15
|
+
method?: (path: unknown[]) => unknown
|
|
16
|
+
): string | number | undefined
|
|
17
|
+
export function getAggregationCollectionName (segments: readonly unknown[]): string | undefined
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { raw } from '@nx-js/observer-util';
|
|
2
|
+
import { getRaw } from './dataTree.js';
|
|
3
|
+
import getSignal from "./getSignal.js";
|
|
4
|
+
import { QuerySubscriptions, hashQuery, Query, HASH, PARAMS, COLLECTION_NAME, parseQueryHash } from './Query.js';
|
|
5
|
+
import Signal, { SEGMENTS } from "./Signal.js";
|
|
6
|
+
import { getIdFieldsForSegments, isPlainObject } from "./idFields.js";
|
|
7
|
+
import { delPrivateData, getPrivateData, setPrivateData } from './privateData.js';
|
|
8
|
+
import { setSignalRuntimeDescriptor } from "./signalRuntimeDescriptor.js";
|
|
9
|
+
export const IS_AGGREGATION = Symbol('is aggregation signal');
|
|
10
|
+
export const AGGREGATIONS = '$aggregations';
|
|
11
|
+
class Aggregation extends Query {
|
|
12
|
+
_initData() {
|
|
13
|
+
this._syncAllRootsData();
|
|
14
|
+
this.shareQuery.on('extra', extra => {
|
|
15
|
+
extra = raw(extra);
|
|
16
|
+
injectAggregationIds(extra, this.collectionName);
|
|
17
|
+
this._forEachRoot(rootId => {
|
|
18
|
+
setPrivateData(rootId, [AGGREGATIONS, this.hash], extra);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
_syncRootData(rootId) {
|
|
23
|
+
if (!this.shareQuery)
|
|
24
|
+
return;
|
|
25
|
+
const extra = raw(this.shareQuery.extra);
|
|
26
|
+
injectAggregationIds(extra, this.collectionName);
|
|
27
|
+
setPrivateData(rootId, [AGGREGATIONS, this.hash], extra);
|
|
28
|
+
}
|
|
29
|
+
_removeRootData(rootId) {
|
|
30
|
+
delPrivateData(rootId, [AGGREGATIONS, this.hash]);
|
|
31
|
+
}
|
|
32
|
+
_removeData() {
|
|
33
|
+
this._forEachRoot(rootId => this._removeRootData(rootId));
|
|
34
|
+
this.rootIds.clear();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export const aggregationSubscriptions = new QuerySubscriptions(Aggregation);
|
|
38
|
+
aggregationSubscriptions.runtimeKind = 'aggregation';
|
|
39
|
+
function injectAggregationIds(extra, collectionName) {
|
|
40
|
+
if (!Array.isArray(extra))
|
|
41
|
+
return;
|
|
42
|
+
const idFields = getIdFieldsForSegments([collectionName, '']);
|
|
43
|
+
for (const doc of extra) {
|
|
44
|
+
if (!isPlainObject(doc))
|
|
45
|
+
continue;
|
|
46
|
+
const docId = doc._id ?? doc.id;
|
|
47
|
+
if (docId == null)
|
|
48
|
+
continue;
|
|
49
|
+
if (idFields.includes('_id') && doc._id !== docId)
|
|
50
|
+
doc._id = docId;
|
|
51
|
+
if (idFields.includes('id') && doc.id !== docId)
|
|
52
|
+
doc.id = docId;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function getAggregationSignal(collectionName, params, options) {
|
|
56
|
+
params = JSON.parse(JSON.stringify(params));
|
|
57
|
+
const transportHash = hashQuery(collectionName, params);
|
|
58
|
+
const { root, signalOptions } = parseAggregationSignalOptions(options);
|
|
59
|
+
const $aggregation = getSignal(root, [AGGREGATIONS, transportHash], signalOptions);
|
|
60
|
+
$aggregation[IS_AGGREGATION] ??= true;
|
|
61
|
+
$aggregation[COLLECTION_NAME] ??= collectionName;
|
|
62
|
+
$aggregation[PARAMS] ??= params;
|
|
63
|
+
$aggregation[HASH] ??= transportHash;
|
|
64
|
+
setSignalRuntimeDescriptor($aggregation, {
|
|
65
|
+
kind: 'aggregation',
|
|
66
|
+
collectionName,
|
|
67
|
+
itemPattern: [collectionName, '*']
|
|
68
|
+
});
|
|
69
|
+
return $aggregation;
|
|
70
|
+
}
|
|
71
|
+
// example: ['$aggregations', '{"active":true}']
|
|
72
|
+
export function isAggregationSignal($signal) {
|
|
73
|
+
if (!($signal instanceof Signal))
|
|
74
|
+
return;
|
|
75
|
+
const segments = $signal[SEGMENTS];
|
|
76
|
+
if (!(segments.length === 2))
|
|
77
|
+
return;
|
|
78
|
+
if (!(segments[0] === AGGREGATIONS))
|
|
79
|
+
return;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// example: ['$aggregations', '{"active":true}', 42]
|
|
83
|
+
// AND only if it also has either '_id' or 'id' field inside
|
|
84
|
+
export function getAggregationDocId(segments, rootId, method) {
|
|
85
|
+
if (!(segments.length >= 3))
|
|
86
|
+
return;
|
|
87
|
+
if (!(segments[0] === AGGREGATIONS))
|
|
88
|
+
return;
|
|
89
|
+
if (!(typeof segments[2] === 'number'))
|
|
90
|
+
return;
|
|
91
|
+
if (typeof method !== 'function') {
|
|
92
|
+
method = path => rootId == null ? getRaw(path) : getPrivateData(rootId, path);
|
|
93
|
+
}
|
|
94
|
+
const docId = method([...segments.slice(0, 3), '_id']) || method([...segments.slice(0, 3), 'id']);
|
|
95
|
+
return docId;
|
|
96
|
+
}
|
|
97
|
+
export function getAggregationCollectionName(segments) {
|
|
98
|
+
if (!(segments.length >= 2))
|
|
99
|
+
return;
|
|
100
|
+
if (!(segments[0] === AGGREGATIONS))
|
|
101
|
+
return;
|
|
102
|
+
const hash = segments[1];
|
|
103
|
+
const { collectionName } = parseQueryHash(hash);
|
|
104
|
+
return collectionName;
|
|
105
|
+
}
|
|
106
|
+
function parseAggregationSignalOptions(options) {
|
|
107
|
+
if (!options || typeof options !== 'object') {
|
|
108
|
+
return {
|
|
109
|
+
root: undefined,
|
|
110
|
+
signalOptions: {}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const { root, ...signalOptions } = options;
|
|
114
|
+
return { root, signalOptions };
|
|
115
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default class Cache<TValue extends object = object> {
|
|
2
|
+
private readonly cache;
|
|
3
|
+
private readonly fr;
|
|
4
|
+
_getKeys(): string[];
|
|
5
|
+
get(key: string): TValue | undefined;
|
|
6
|
+
set(key: string, value: TValue, inputs?: readonly object[]): void;
|
|
7
|
+
delete(key: string): void;
|
|
8
|
+
get size(): number;
|
|
9
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import FinalizationRegistry from "../utils/MockFinalizationRegistry.js";
|
|
2
|
+
import WeakRef, { destroyMockWeakRef } from "../utils/MockWeakRef.js";
|
|
3
|
+
export default class Cache {
|
|
4
|
+
cache = new Map();
|
|
5
|
+
fr = new FinalizationRegistry(([key]) => {
|
|
6
|
+
// FinalizationRegistry can trigger long after the WeakRef was already
|
|
7
|
+
// collected and a fresh value was stored for the same key.
|
|
8
|
+
if (this.get(key))
|
|
9
|
+
return;
|
|
10
|
+
this.delete(key);
|
|
11
|
+
});
|
|
12
|
+
// For testing purposes.
|
|
13
|
+
_getKeys() {
|
|
14
|
+
return Array.from(this.cache.keys()).sort();
|
|
15
|
+
}
|
|
16
|
+
get(key) {
|
|
17
|
+
return this.cache.get(key)?.deref();
|
|
18
|
+
}
|
|
19
|
+
set(key, value, inputs = []) {
|
|
20
|
+
if (typeof key !== 'string')
|
|
21
|
+
throw Error('Cache key should be a string');
|
|
22
|
+
this.cache.set(key, new WeakRef(value));
|
|
23
|
+
this.fr.register(value, [key, ...inputs]);
|
|
24
|
+
}
|
|
25
|
+
delete(key) {
|
|
26
|
+
destroyMockWeakRef(this.cache.get(key));
|
|
27
|
+
this.cache.delete(key);
|
|
28
|
+
}
|
|
29
|
+
get size() {
|
|
30
|
+
return this.cache.size;
|
|
31
|
+
}
|
|
32
|
+
}
|