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.
Files changed (237) hide show
  1. package/babel-loader.cjs +1 -0
  2. package/babel.cjs +1 -0
  3. package/dist/connect/index.d.ts +1 -0
  4. package/dist/connect/index.js +9 -0
  5. package/dist/connect/lib/sharedb-crosstab-pubsub.d.cts +10 -0
  6. package/dist/connect/offline/index.d.ts +1 -0
  7. package/dist/connect/offline/index.js +126 -0
  8. package/dist/connect/offline/react-native.d.ts +10 -0
  9. package/dist/connect/offline/react-native.js +25 -0
  10. package/dist/connect/offline/web.d.ts +9 -0
  11. package/dist/connect/offline/web.js +12 -0
  12. package/dist/connect/sharedbConnection.d.cts +2 -0
  13. package/dist/connect/test.d.ts +1 -0
  14. package/dist/connect/test.js +12 -0
  15. package/dist/index.d.ts +66 -0
  16. package/dist/index.js +74 -0
  17. package/dist/orm/$.d.ts +9 -0
  18. package/dist/orm/$.js +34 -0
  19. package/dist/orm/Aggregation.d.ts +17 -0
  20. package/dist/orm/Aggregation.js +115 -0
  21. package/dist/orm/Cache.d.ts +9 -0
  22. package/dist/orm/Cache.js +32 -0
  23. package/dist/orm/Compat/SignalCompat.d.ts +3 -0
  24. package/dist/orm/Compat/SignalCompat.js +1542 -0
  25. package/dist/orm/Compat/eventsCompat.d.ts +3 -0
  26. package/dist/orm/Compat/eventsCompat.js +73 -0
  27. package/dist/orm/Compat/hooksCompat.d.ts +33 -0
  28. package/dist/orm/Compat/hooksCompat.js +360 -0
  29. package/dist/orm/Compat/modelEvents.d.ts +6 -0
  30. package/dist/orm/Compat/modelEvents.js +228 -0
  31. package/dist/orm/Compat/queryReadiness.d.ts +5 -0
  32. package/dist/orm/Compat/queryReadiness.js +185 -0
  33. package/dist/orm/Compat/refFallback.d.ts +13 -0
  34. package/dist/orm/Compat/refFallback.js +65 -0
  35. package/dist/orm/Compat/refRegistry.d.ts +6 -0
  36. package/dist/orm/Compat/refRegistry.js +54 -0
  37. package/dist/orm/Compat/silentContext.d.ts +5 -0
  38. package/dist/orm/Compat/silentContext.js +48 -0
  39. package/dist/orm/Compat/startStopCompat.d.ts +3 -0
  40. package/dist/orm/Compat/startStopCompat.js +217 -0
  41. package/dist/orm/Doc.d.ts +96 -0
  42. package/dist/orm/Doc.js +966 -0
  43. package/dist/orm/Query.d.ts +117 -0
  44. package/dist/orm/Query.js +1111 -0
  45. package/dist/orm/Reaction.d.ts +10 -0
  46. package/dist/orm/Reaction.js +41 -0
  47. package/dist/orm/Root.d.ts +22 -0
  48. package/dist/orm/Root.js +85 -0
  49. package/dist/orm/Signal.d.ts +12 -0
  50. package/dist/orm/Signal.js +7 -0
  51. package/dist/orm/SignalBase.d.ts +168 -0
  52. package/dist/orm/SignalBase.js +625 -0
  53. package/dist/orm/SubscriptionState.d.ts +17 -0
  54. package/dist/orm/SubscriptionState.js +123 -0
  55. package/dist/orm/Value.d.ts +9 -0
  56. package/dist/orm/Value.js +25 -0
  57. package/dist/orm/addModel.d.ts +6 -0
  58. package/dist/orm/addModel.js +39 -0
  59. package/dist/orm/associations.d.ts +18 -0
  60. package/dist/orm/associations.js +70 -0
  61. package/dist/orm/batchScheduler.d.ts +7 -0
  62. package/dist/orm/batchScheduler.js +62 -0
  63. package/dist/orm/compatEnv.d.ts +1 -0
  64. package/dist/orm/compatEnv.js +4 -0
  65. package/dist/orm/connection.d.ts +26 -0
  66. package/dist/orm/connection.js +38 -0
  67. package/dist/orm/dataTree.d.ts +34 -0
  68. package/dist/orm/dataTree.js +880 -0
  69. package/dist/orm/disposeRootContext.d.ts +4 -0
  70. package/dist/orm/disposeRootContext.js +59 -0
  71. package/dist/orm/getSignal.d.ts +16 -0
  72. package/dist/orm/getSignal.js +133 -0
  73. package/dist/orm/idFields.d.ts +14 -0
  74. package/dist/orm/idFields.js +95 -0
  75. package/dist/orm/index.d.ts +7 -0
  76. package/dist/orm/index.js +6 -0
  77. package/dist/orm/initModels.d.ts +5 -0
  78. package/dist/orm/initModels.js +74 -0
  79. package/dist/orm/missingDoc.d.ts +1 -0
  80. package/dist/orm/missingDoc.js +3 -0
  81. package/dist/orm/pluralize.d.ts +12 -0
  82. package/dist/orm/privateData.d.ts +22 -0
  83. package/dist/orm/privateData.js +170 -0
  84. package/dist/orm/rootContext.d.ts +78 -0
  85. package/dist/orm/rootContext.js +297 -0
  86. package/dist/orm/rootScope.d.ts +12 -0
  87. package/dist/orm/rootScope.js +46 -0
  88. package/dist/orm/signalArrayReaders.d.ts +22 -0
  89. package/dist/orm/signalArrayReaders.js +42 -0
  90. package/dist/orm/signalMetadata.d.ts +17 -0
  91. package/dist/orm/signalMetadata.js +56 -0
  92. package/dist/orm/signalMutationGuards.d.ts +4 -0
  93. package/dist/orm/signalMutationGuards.js +14 -0
  94. package/dist/orm/signalPathKind.d.ts +2 -0
  95. package/dist/orm/signalPathKind.js +10 -0
  96. package/dist/orm/signalPathRules.d.ts +6 -0
  97. package/dist/orm/signalPathRules.js +28 -0
  98. package/dist/orm/signalReads.d.ts +26 -0
  99. package/dist/orm/signalReads.js +64 -0
  100. package/dist/orm/signalRuntimeAccess.d.ts +16 -0
  101. package/dist/orm/signalRuntimeAccess.js +24 -0
  102. package/dist/orm/signalRuntimeDescriptor.d.ts +19 -0
  103. package/dist/orm/signalRuntimeDescriptor.js +97 -0
  104. package/dist/orm/signalStorageMutations.d.ts +18 -0
  105. package/dist/orm/signalStorageMutations.js +26 -0
  106. package/dist/orm/signalSymbols.d.ts +5 -0
  107. package/dist/orm/signalSymbols.js +5 -0
  108. package/dist/orm/signalValueMutations.d.ts +14 -0
  109. package/dist/orm/signalValueMutations.js +36 -0
  110. package/dist/orm/sub.d.ts +37 -0
  111. package/dist/orm/sub.js +187 -0
  112. package/dist/orm/subscriptionGcDelay.d.ts +4 -0
  113. package/dist/orm/subscriptionGcDelay.js +26 -0
  114. package/dist/orm/types/baseMethods.d.ts +43 -0
  115. package/dist/orm/types/baseMethods.js +1 -0
  116. package/dist/orm/types/jsonSchema.d.ts +75 -0
  117. package/dist/orm/types/jsonSchema.js +1 -0
  118. package/dist/orm/types/modelManifest.d.ts +37 -0
  119. package/dist/orm/types/modelManifest.js +1 -0
  120. package/dist/orm/types/path.d.ts +8 -0
  121. package/dist/orm/types/path.js +1 -0
  122. package/dist/orm/types/query.d.ts +29 -0
  123. package/dist/orm/types/query.js +1 -0
  124. package/dist/orm/types/signal.d.ts +132 -0
  125. package/dist/orm/types/signal.js +1 -0
  126. package/dist/react/compatComponentRegistry.d.ts +4 -0
  127. package/dist/react/compatComponentRegistry.js +19 -0
  128. package/dist/react/convertToObserver.d.ts +26 -0
  129. package/dist/react/convertToObserver.js +114 -0
  130. package/dist/react/executionContextTracker.d.ts +11 -0
  131. package/dist/react/executionContextTracker.js +28 -0
  132. package/dist/react/helpers.d.ts +34 -0
  133. package/dist/react/helpers.js +134 -0
  134. package/dist/react/observer.d.ts +22 -0
  135. package/dist/react/observer.js +8 -0
  136. package/dist/react/promiseBatcher.d.ts +13 -0
  137. package/dist/react/promiseBatcher.js +118 -0
  138. package/dist/react/renderAttemptDestroyer.d.ts +19 -0
  139. package/dist/react/renderAttemptDestroyer.js +46 -0
  140. package/dist/react/trapRender.d.ts +6 -0
  141. package/dist/react/trapRender.js +48 -0
  142. package/dist/react/universal$.d.ts +1 -0
  143. package/dist/react/universal$.js +18 -0
  144. package/dist/react/universalSub.d.ts +1 -0
  145. package/dist/react/universalSub.js +22 -0
  146. package/dist/react/useApi.d.ts +13 -0
  147. package/dist/react/useApi.js +67 -0
  148. package/dist/react/useSub.d.ts +102 -0
  149. package/dist/react/useSub.js +189 -0
  150. package/dist/react/useSuspendMemo.d.ts +3 -0
  151. package/dist/react/useSuspendMemo.js +102 -0
  152. package/dist/react/wrapIntoSuspense.d.ts +9 -0
  153. package/dist/react/wrapIntoSuspense.js +102 -0
  154. package/dist/server.d.ts +11 -0
  155. package/dist/server.js +28 -0
  156. package/dist/utils/MockFinalizationRegistry.d.ts +37 -0
  157. package/dist/utils/MockFinalizationRegistry.js +85 -0
  158. package/dist/utils/MockWeakRef.d.ts +12 -0
  159. package/dist/utils/MockWeakRef.js +23 -0
  160. package/dist/utils/isServer.d.ts +3 -0
  161. package/dist/utils/isServer.js +18 -0
  162. package/dist/utils/setDiffDeep.d.ts +1 -0
  163. package/dist/utils/setDiffDeep.js +61 -0
  164. package/dist/utils/useIsomorphicLayoutEffect.d.ts +3 -0
  165. package/dist/utils/useIsomorphicLayoutEffect.js +3 -0
  166. package/file-based-models.js +3 -0
  167. package/file-based-models.node.js +6 -0
  168. package/package.json +77 -32
  169. package/teamplay.models.auto-init.virtual.js +1 -0
  170. package/teamplay.models.virtual.js +1 -0
  171. package/connect/index.js +0 -9
  172. package/connect/offline/index.js +0 -124
  173. package/connect/offline/react-native.js +0 -28
  174. package/connect/offline/web.js +0 -15
  175. package/connect/test.js +0 -12
  176. package/index.d.ts +0 -106
  177. package/index.js +0 -125
  178. package/orm/$.js +0 -38
  179. package/orm/Aggregation.js +0 -117
  180. package/orm/Cache.js +0 -46
  181. package/orm/Compat/README.md +0 -1064
  182. package/orm/Compat/SignalCompat.js +0 -1479
  183. package/orm/Compat/eventsCompat.js +0 -79
  184. package/orm/Compat/hooksCompat.js +0 -374
  185. package/orm/Compat/modelEvents.js +0 -225
  186. package/orm/Compat/queryReadiness.js +0 -191
  187. package/orm/Compat/refFallback.js +0 -62
  188. package/orm/Compat/refRegistry.js +0 -61
  189. package/orm/Compat/silentContext.js +0 -51
  190. package/orm/Compat/startStopCompat.js +0 -207
  191. package/orm/Doc.js +0 -969
  192. package/orm/Query.js +0 -1127
  193. package/orm/Reaction.js +0 -48
  194. package/orm/Root.js +0 -88
  195. package/orm/Signal.js +0 -22
  196. package/orm/SignalBase.js +0 -696
  197. package/orm/SubscriptionState.js +0 -138
  198. package/orm/Value.js +0 -30
  199. package/orm/addModel.js +0 -31
  200. package/orm/associations.js +0 -97
  201. package/orm/batchScheduler.js +0 -62
  202. package/orm/compatEnv.js +0 -4
  203. package/orm/connection.js +0 -46
  204. package/orm/dataTree.js +0 -869
  205. package/orm/disposeRootContext.js +0 -68
  206. package/orm/getSignal.js +0 -130
  207. package/orm/idFields.js +0 -88
  208. package/orm/index.d.ts +0 -6
  209. package/orm/index.js +0 -5
  210. package/orm/missingDoc.js +0 -3
  211. package/orm/privateData.js +0 -181
  212. package/orm/rootContext.js +0 -313
  213. package/orm/rootScope.js +0 -51
  214. package/orm/sub.js +0 -151
  215. package/orm/subscriptionGcDelay.js +0 -32
  216. package/react/compatComponentRegistry.js +0 -20
  217. package/react/convertToObserver.js +0 -117
  218. package/react/executionContextTracker.js +0 -32
  219. package/react/helpers.js +0 -141
  220. package/react/observer.js +0 -9
  221. package/react/promiseBatcher.js +0 -115
  222. package/react/renderAttemptDestroyer.js +0 -47
  223. package/react/trapRender.js +0 -50
  224. package/react/universal$.js +0 -18
  225. package/react/universalSub.js +0 -21
  226. package/react/useApi.js +0 -63
  227. package/react/useSub.js +0 -169
  228. package/react/useSuspendMemo.js +0 -96
  229. package/react/wrapIntoSuspense.js +0 -119
  230. package/server.js +0 -31
  231. package/utils/MockFinalizationRegistry.js +0 -94
  232. package/utils/MockWeakRef.js +0 -25
  233. package/utils/isServer.js +0 -17
  234. package/utils/setDiffDeep.js +0 -58
  235. package/utils/useIsomorphicLayoutEffect.js +0 -4
  236. /package/{connect → dist/connect}/lib/sharedb-crosstab-pubsub.cjs +0 -0
  237. /package/{connect → dist/connect}/sharedbConnection.cjs +0 -0
@@ -0,0 +1,228 @@
1
+ import { getRefLinks, getRefRootIds } from './refRegistry.js';
2
+ import { isCompatEnv } from '../compatEnv.js';
3
+ import { isSilentContextActive, isModelEventsSilentContextActive, runInModelEventsSilentContext } from './silentContext.js';
4
+ import { normalizeRootId } from "../rootScope.js";
5
+ import { getRootContext, getRootContexts } from "../rootContext.js";
6
+ import { setReplace as setReplaceInDataTree, del as delFromDataTree } from '../dataTree.js';
7
+ import { setReplacePrivateData, delPrivateData } from '../privateData.js';
8
+ const MODEL_EVENT_NAMES = ['change', 'all'];
9
+ export function isModelEventsEnabled() {
10
+ return isCompatEnv();
11
+ }
12
+ export function normalizePattern(pattern, methodName) {
13
+ if (pattern && typeof pattern.path === 'function')
14
+ pattern = pattern.path();
15
+ if (pattern == null || typeof pattern !== 'string') {
16
+ if (methodName)
17
+ throw Error(`${methodName} expects a string path or a signal`);
18
+ return null;
19
+ }
20
+ return pattern.split('.').filter(Boolean).join('.');
21
+ }
22
+ export function onModelEvent(rootId, eventName, pattern, handler) {
23
+ if (typeof handler !== 'function')
24
+ throw Error('Model event handler must be a function');
25
+ if (!MODEL_EVENT_NAMES.includes(eventName))
26
+ throw Error(`Unsupported model event: ${eventName}`);
27
+ const store = getModelEventRootStore(eventName, rootId, true);
28
+ const normalized = normalizePattern(pattern);
29
+ let entry = store.get(normalized);
30
+ if (!entry) {
31
+ entry = {
32
+ pattern: normalized,
33
+ segments: splitPattern(normalized),
34
+ handlers: new Set()
35
+ };
36
+ store.set(normalized, entry);
37
+ }
38
+ entry.handlers.add(handler);
39
+ return handler;
40
+ }
41
+ export function removeModelListener(rootId, eventName, handler) {
42
+ const store = getModelEventRootStore(eventName, rootId);
43
+ if (!store)
44
+ return;
45
+ for (const [pattern, entry] of store) {
46
+ entry.handlers.delete(handler);
47
+ if (!entry.handlers.size)
48
+ store.delete(pattern);
49
+ }
50
+ }
51
+ export function emitModelChange(path, value, prevValue, meta) {
52
+ if (!isModelEventsEnabled())
53
+ return;
54
+ if (isSilentContextActive() || isModelEventsSilentContextActive())
55
+ return;
56
+ const initialSegments = splitPath(path);
57
+ const eventName = meta?.eventName || 'change';
58
+ const rootIds = getTargetRootIds(meta?.rootId);
59
+ for (const rootId of rootIds) {
60
+ const visited = new Set();
61
+ const queue = [initialSegments];
62
+ while (queue.length) {
63
+ const segments = queue.shift();
64
+ const key = segments.join('.');
65
+ if (visited.has(key))
66
+ continue;
67
+ visited.add(key);
68
+ emitForEvent(rootId, 'change', segments, value, prevValue, meta);
69
+ emitForEvent(rootId, 'all', segments, value, prevValue, meta, eventName);
70
+ for (const link of getRefLinks(rootId).values()) {
71
+ if (!isPathPrefix(link.toSegments, segments))
72
+ continue;
73
+ if (link.mirrorOnly && typeof link.onChange === 'function') {
74
+ link.onChange();
75
+ }
76
+ else if (!link.mirrorOnly) {
77
+ mirrorRefAliasFromTargetSegments(rootId, link, segments, value, meta);
78
+ }
79
+ const suffix = segments.slice(link.toSegments.length);
80
+ const nextSegments = link.fromSegments.concat(suffix);
81
+ const nextKey = nextSegments.join('.');
82
+ if (!visited.has(nextKey))
83
+ queue.push(nextSegments);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ export function __resetModelEventsForTests() {
89
+ for (const context of getRootContexts()) {
90
+ context.resetModelListeners();
91
+ }
92
+ }
93
+ function emitForEvent(rootId, eventName, pathSegments, value, prevValue, meta, resolvedEventName = eventName) {
94
+ const store = getModelEventRootStore(eventName, rootId);
95
+ if (!store || store.size === 0)
96
+ return;
97
+ for (const entry of store.values()) {
98
+ const captures = matchPattern(entry.segments, pathSegments);
99
+ if (!captures)
100
+ continue;
101
+ for (const handler of entry.handlers) {
102
+ if (eventName === 'all') {
103
+ handler(...captures, resolvedEventName, value, prevValue, meta);
104
+ }
105
+ else {
106
+ handler(...captures, value, prevValue, meta);
107
+ }
108
+ }
109
+ }
110
+ }
111
+ function splitPattern(pattern) {
112
+ if (!pattern)
113
+ return [];
114
+ return pattern.split('.').filter(Boolean);
115
+ }
116
+ function mirrorRefAliasFromTargetSegments(rootId, link, targetSegments, value, meta) {
117
+ const suffix = targetSegments.slice(link.toSegments.length);
118
+ const fromSegments = link.fromSegments.concat(suffix);
119
+ const fromRootId = normalizeRootId(link.fromRootId ?? rootId);
120
+ const shouldDelete = shouldDeleteMirroredPath(value, meta);
121
+ runInModelEventsSilentContext(() => {
122
+ if (isPrivateSegments(fromSegments)) {
123
+ if (shouldDelete) {
124
+ delPrivateData(fromRootId, fromSegments);
125
+ }
126
+ else {
127
+ setReplacePrivateData(fromRootId, fromSegments, cloneValue(value));
128
+ }
129
+ return;
130
+ }
131
+ if (shouldDelete) {
132
+ delFromDataTree(fromSegments);
133
+ return;
134
+ }
135
+ setReplaceInDataTree(fromSegments, cloneValue(value));
136
+ });
137
+ }
138
+ function isPrivateSegments(segments) {
139
+ if (!Array.isArray(segments) || !segments.length)
140
+ return false;
141
+ return /^[_$]/.test(String(segments[0]));
142
+ }
143
+ function shouldDeleteMirroredPath(value, meta) {
144
+ if (meta?.op === 'setReplace')
145
+ return false;
146
+ if (meta?.op === 'del')
147
+ return true;
148
+ return value === undefined;
149
+ }
150
+ function cloneValue(value) {
151
+ if (Array.isArray(value))
152
+ return value.map(cloneValue);
153
+ if (value && typeof value === 'object') {
154
+ const cloned = {};
155
+ for (const key of Object.keys(value))
156
+ cloned[key] = cloneValue(value[key]);
157
+ return cloned;
158
+ }
159
+ return value;
160
+ }
161
+ function getModelEventRootStore(eventName, rootId, create = false) {
162
+ return getRootContext(normalizeRootId(rootId), create)?.getModelEventStore(eventName, create);
163
+ }
164
+ function getModelEventRootIds() {
165
+ const rootIds = new Set();
166
+ for (const context of getRootContexts()) {
167
+ for (const store of Object.values(context.modelListeners)) {
168
+ if (store.size)
169
+ rootIds.add(context.rootId);
170
+ }
171
+ }
172
+ return rootIds;
173
+ }
174
+ function getTargetRootIds(rootId) {
175
+ if (rootId != null)
176
+ return [normalizeRootId(rootId)];
177
+ const rootIds = new Set([
178
+ ...getModelEventRootIds(),
179
+ ...getRefRootIds()
180
+ ]);
181
+ return rootIds;
182
+ }
183
+ function splitPath(path) {
184
+ if (Array.isArray(path))
185
+ return path.map(segment => String(segment));
186
+ if (!path)
187
+ return [];
188
+ return String(path).split('.').filter(Boolean);
189
+ }
190
+ function isPathPrefix(prefixSegments, fullSegments) {
191
+ if (prefixSegments.length > fullSegments.length)
192
+ return false;
193
+ for (let i = 0; i < prefixSegments.length; i++) {
194
+ if (prefixSegments[i] !== fullSegments[i])
195
+ return false;
196
+ }
197
+ return true;
198
+ }
199
+ function matchPattern(patternSegments, pathSegments) {
200
+ function walk(patternIndex, pathIndex) {
201
+ if (patternIndex === patternSegments.length) {
202
+ return pathIndex === pathSegments.length ? [] : null;
203
+ }
204
+ const segment = patternSegments[patternIndex];
205
+ if (segment === '**') {
206
+ for (let i = pathIndex; i <= pathSegments.length; i++) {
207
+ const rest = walk(patternIndex + 1, i);
208
+ if (rest !== null) {
209
+ const capture = pathSegments.slice(pathIndex, i).join('.');
210
+ return [capture, ...rest];
211
+ }
212
+ }
213
+ return null;
214
+ }
215
+ if (pathIndex >= pathSegments.length)
216
+ return null;
217
+ if (segment === '*') {
218
+ const rest = walk(patternIndex + 1, pathIndex + 1);
219
+ if (rest === null)
220
+ return null;
221
+ return [pathSegments[pathIndex], ...rest];
222
+ }
223
+ if (segment !== pathSegments[pathIndex])
224
+ return null;
225
+ return walk(patternIndex + 1, pathIndex + 1);
226
+ }
227
+ return walk(0, 0);
228
+ }
@@ -0,0 +1,5 @@
1
+ export function isQueryReady(collection: any, idsSegments: any, docsSegments: any, extraSegments: any, aggregationSegments: any, isAggregate: any, hasExtraResult: any): boolean;
2
+ export function isDocReady(segments: any): boolean;
3
+ export function waitForImperativeQueryReady($query: any): Promise<void>;
4
+ export function __setImperativeQueryReadyTimeoutForTests(timeoutMs: any): void;
5
+ export function __resetImperativeQueryReadyTimeoutForTests(): void;
@@ -0,0 +1,185 @@
1
+ import { getRaw } from '../dataTree.js';
2
+ import { getConnection } from "../connection.js";
3
+ import { isMissingShareDoc } from '../missingDoc.js';
4
+ import { QUERIES, HASH, PARAMS, COLLECTION_NAME, querySubscriptions } from '../Query.js';
5
+ import { AGGREGATIONS, IS_AGGREGATION, aggregationSubscriptions } from '../Aggregation.js';
6
+ import { getPrivateData, setPrivateData } from '../privateData.js';
7
+ import { getRoot, ROOT_ID } from "../Root.js";
8
+ import { isRootContextClosed } from "../rootContext.js";
9
+ import { getScopedSignalHash, normalizeRootId } from "../rootScope.js";
10
+ let imperativeQueryReadyTimeoutMs = 1000;
11
+ export function isQueryReady(collection, idsSegments, docsSegments, extraSegments, aggregationSegments, isAggregate, hasExtraResult) {
12
+ if (hasExtraResult) {
13
+ return getRaw(extraSegments) !== undefined;
14
+ }
15
+ if (isAggregate) {
16
+ const docs = getRaw(docsSegments);
17
+ if (Array.isArray(docs))
18
+ return true;
19
+ if (getRaw(extraSegments) !== undefined)
20
+ return true;
21
+ return getRaw(aggregationSegments) !== undefined;
22
+ }
23
+ const ids = getRaw(idsSegments);
24
+ if (!Array.isArray(ids))
25
+ return false;
26
+ for (const id of ids) {
27
+ if (id == null)
28
+ continue;
29
+ if (!isDocReady([collection, id]))
30
+ return false;
31
+ }
32
+ return true;
33
+ }
34
+ export function isDocReady(segments) {
35
+ const rawDoc = getRaw(segments);
36
+ if (rawDoc !== undefined)
37
+ return true;
38
+ const [collection, id] = segments;
39
+ const shareDoc = getShareDoc(collection, id);
40
+ // Missing docs should not block the batch barrier forever.
41
+ return isMissingShareDoc(shareDoc);
42
+ }
43
+ export async function waitForImperativeQueryReady($query) {
44
+ const timeoutMs = imperativeQueryReadyTimeoutMs;
45
+ const startedAt = Date.now();
46
+ const ownerState = createImperativeOwnerState($query);
47
+ while (true) {
48
+ if (isImperativeQueryCancelled($query, ownerState))
49
+ return;
50
+ if (isImperativeQueryReady($query)) {
51
+ syncQueryDocsFromCollection($query);
52
+ return;
53
+ }
54
+ if (Date.now() - startedAt >= timeoutMs) {
55
+ throw createImperativeQueryReadinessError($query, timeoutMs);
56
+ }
57
+ await new Promise(resolve => setTimeout(resolve, 0));
58
+ }
59
+ }
60
+ export function __setImperativeQueryReadyTimeoutForTests(timeoutMs) {
61
+ imperativeQueryReadyTimeoutMs = timeoutMs;
62
+ }
63
+ export function __resetImperativeQueryReadyTimeoutForTests() {
64
+ imperativeQueryReadyTimeoutMs = 1000;
65
+ }
66
+ function isImperativeQueryReady($query) {
67
+ const collection = $query[COLLECTION_NAME];
68
+ const hash = $query[HASH];
69
+ const rootId = getRoot($query)?.[ROOT_ID];
70
+ const params = $query[PARAMS];
71
+ const hasExtraResult = isExtraQuery(params);
72
+ if (hasExtraResult)
73
+ return getPrivateData(rootId, [QUERIES, hash, 'extra'], true) !== undefined;
74
+ const isAggregate = !!$query[IS_AGGREGATION] || isAggregationQuery(params);
75
+ if (isAggregate) {
76
+ const docs = getPrivateData(rootId, [QUERIES, hash, 'docs'], true);
77
+ if (Array.isArray(docs))
78
+ return true;
79
+ if (getPrivateData(rootId, [QUERIES, hash, 'extra'], true) !== undefined)
80
+ return true;
81
+ return getPrivateData(rootId, [AGGREGATIONS, hash], true) !== undefined;
82
+ }
83
+ const ids = getPrivateData(rootId, [QUERIES, hash, 'ids'], true);
84
+ if (!Array.isArray(ids))
85
+ return false;
86
+ for (const id of ids) {
87
+ if (id == null)
88
+ continue;
89
+ if (getRaw([collection, id]) === undefined)
90
+ return false;
91
+ }
92
+ return true;
93
+ }
94
+ function isImperativeQueryCancelled($query, ownerState) {
95
+ const rootId = getRoot($query)?.[ROOT_ID];
96
+ if (isRootContextClosed(rootId))
97
+ return true;
98
+ if (!ownerState?.wasTracked)
99
+ return false;
100
+ const trackedOwnerCount = ownerState.subscriptions.getTrackedOwnerCount(ownerState.ownerKey);
101
+ return trackedOwnerCount == null || trackedOwnerCount <= 0;
102
+ }
103
+ function createImperativeOwnerState($query) {
104
+ const hash = $query[HASH];
105
+ const rootId = normalizeRootId(getRoot($query)?.[ROOT_ID]);
106
+ const subscriptions = ($query[IS_AGGREGATION] || isAggregationQuery($query[PARAMS]))
107
+ ? aggregationSubscriptions
108
+ : querySubscriptions;
109
+ const ownerKey = getScopedSignalHash(rootId, hash, 'queryOwner');
110
+ return {
111
+ subscriptions,
112
+ ownerKey,
113
+ wasTracked: subscriptions.getTrackedOwnerCount(ownerKey) != null
114
+ };
115
+ }
116
+ function syncQueryDocsFromCollection($query) {
117
+ const params = $query[PARAMS];
118
+ if ($query[IS_AGGREGATION] || isAggregationQuery(params) || isExtraQuery(params))
119
+ return;
120
+ const collection = $query[COLLECTION_NAME];
121
+ const hash = $query[HASH];
122
+ const rootId = getRoot($query)?.[ROOT_ID];
123
+ const ids = getPrivateData(rootId, [QUERIES, hash, 'ids'], true);
124
+ if (!Array.isArray(ids))
125
+ return;
126
+ const docs = [];
127
+ for (const id of ids) {
128
+ if (id == null)
129
+ continue;
130
+ const doc = getRaw([collection, id]);
131
+ if (doc === undefined) {
132
+ throw createImperativeQueryReadinessError($query, imperativeQueryReadyTimeoutMs);
133
+ }
134
+ docs.push(doc);
135
+ }
136
+ setPrivateData(rootId, [QUERIES, hash, 'docs'], docs);
137
+ }
138
+ function createImperativeQueryReadinessError($query, timeoutMs) {
139
+ const collection = $query[COLLECTION_NAME];
140
+ const hash = $query[HASH];
141
+ const rootId = getRoot($query)?.[ROOT_ID];
142
+ const params = $query[PARAMS];
143
+ const ids = getPrivateData(rootId, [QUERIES, hash, 'ids'], true);
144
+ const missingDocs = [];
145
+ if (Array.isArray(ids)) {
146
+ for (const id of ids) {
147
+ if (id == null)
148
+ continue;
149
+ const doc = getRaw([collection, id]);
150
+ if (doc !== undefined)
151
+ continue;
152
+ const shareDoc = getShareDoc(collection, id);
153
+ missingDocs.push({
154
+ id,
155
+ missingShareDoc: isMissingShareDoc(shareDoc)
156
+ });
157
+ }
158
+ }
159
+ return Error(`
160
+ Compat query did not fully materialize within ${timeoutMs}ms.
161
+ Collection: ${collection}
162
+ Params: ${JSON.stringify(params)}
163
+ Hash: ${hash}
164
+ Ids: ${JSON.stringify(ids)}
165
+ Missing docs: ${JSON.stringify(missingDocs)}
166
+ `);
167
+ }
168
+ function getShareDoc(collection, id) {
169
+ try {
170
+ return getConnection().get(collection, id);
171
+ }
172
+ catch {
173
+ return undefined;
174
+ }
175
+ }
176
+ function isExtraQuery(query) {
177
+ if (!query || typeof query !== 'object')
178
+ return false;
179
+ return !!(query.$count || query.$queryName);
180
+ }
181
+ function isAggregationQuery(query) {
182
+ if (!query || typeof query !== 'object')
183
+ return false;
184
+ return !!(query.$aggregate || query.$aggregationName);
185
+ }
@@ -0,0 +1,13 @@
1
+ import type { PathSegment } from '../types/path.js'
2
+ import type { SignalBaseInstance } from '../Signal.js'
3
+
4
+ export const REF_TARGET: unique symbol
5
+ export function resolveRefSignalSafe<TSignal extends SignalBaseInstance> (
6
+ $signal: TSignal | undefined,
7
+ maxDepth?: number
8
+ ): TSignal | undefined
9
+ export function resolveRefSegmentsSafe (
10
+ segments: readonly PathSegment[],
11
+ rootId?: string,
12
+ maxDepth?: number
13
+ ): PathSegment[] | undefined
@@ -0,0 +1,65 @@
1
+ import { getRefLinks } from './refRegistry.js';
2
+ import { GLOBAL_ROOT_ID } from "../Root.js";
3
+ export const REF_TARGET = Symbol.for('teamplay.compat.refTarget');
4
+ export function resolveRefSignalSafe($signal, maxDepth = 32) {
5
+ let current = $signal;
6
+ const seen = new Set();
7
+ for (let i = 0; i < maxDepth; i++) {
8
+ if (!current)
9
+ return undefined;
10
+ const next = current[REF_TARGET];
11
+ if (!next)
12
+ return current;
13
+ if (seen.has(current))
14
+ return undefined;
15
+ seen.add(current);
16
+ current = next;
17
+ }
18
+ return undefined;
19
+ }
20
+ export function resolveRefSegmentsSafe(segments, rootId = GLOBAL_ROOT_ID, maxDepth = 32) {
21
+ if (!Array.isArray(segments) || segments.length === 0)
22
+ return undefined;
23
+ let current = [...segments];
24
+ const visited = new Set([toPathKey(current)]);
25
+ let changed = false;
26
+ for (let i = 0; i < maxDepth; i++) {
27
+ const link = findBestMatchingLink(current, rootId);
28
+ if (!link)
29
+ return changed ? current : undefined;
30
+ const suffix = current.slice(link.fromSegments.length);
31
+ const next = link.toSegments.concat(suffix);
32
+ const key = toPathKey(next);
33
+ if (visited.has(key))
34
+ return undefined;
35
+ visited.add(key);
36
+ current = next;
37
+ changed = true;
38
+ }
39
+ return undefined;
40
+ }
41
+ function findBestMatchingLink(segments, rootId) {
42
+ let best;
43
+ for (const link of getRefLinks(rootId).values()) {
44
+ if (link.mirrorOnly)
45
+ continue;
46
+ if (!isPathPrefix(link.fromSegments, segments))
47
+ continue;
48
+ if (!best || link.fromSegments.length > best.fromSegments.length) {
49
+ best = link;
50
+ }
51
+ }
52
+ return best;
53
+ }
54
+ function isPathPrefix(prefixSegments, fullSegments) {
55
+ if (prefixSegments.length > fullSegments.length)
56
+ return false;
57
+ for (let i = 0; i < prefixSegments.length; i++) {
58
+ if (prefixSegments[i] !== String(fullSegments[i]))
59
+ return false;
60
+ }
61
+ return true;
62
+ }
63
+ function toPathKey(segments) {
64
+ return segments.map(segment => String(segment)).join('.');
65
+ }
@@ -0,0 +1,6 @@
1
+ export function setRefLink(rootId: any, fromPath: any, toPath: any, fromSegments: any, toSegments: any, options?: {}): void;
2
+ export function removeRefLink(rootId: any, fromPath: any): void;
3
+ export function getRefLinks(rootId?: string): Map<string, unknown>;
4
+ export function getAllRefLinks(): Generator<unknown, void, unknown>;
5
+ export function getRefRootIds(): string[];
6
+ export function __resetRefLinksForTests(): void;
@@ -0,0 +1,54 @@
1
+ import { GLOBAL_ROOT_ID } from "../Root.js";
2
+ import { normalizeRootId } from "../rootScope.js";
3
+ import { getRootContext, getRootContexts } from "../rootContext.js";
4
+ const EMPTY_MAP = new Map();
5
+ export function setRefLink(rootId, fromPath, toPath, fromSegments, toSegments, options = {}) {
6
+ if (typeof fromPath !== 'string' || typeof toPath !== 'string')
7
+ return;
8
+ const normalizedFromSegments = Array.isArray(fromSegments)
9
+ ? fromSegments.map(segment => String(segment))
10
+ : splitPath(fromPath);
11
+ const normalizedToSegments = Array.isArray(toSegments)
12
+ ? toSegments.map(segment => String(segment))
13
+ : splitPath(toPath);
14
+ getRefStore(rootId, true).set(fromPath, {
15
+ fromPath,
16
+ toPath,
17
+ fromSegments: normalizedFromSegments,
18
+ toSegments: normalizedToSegments,
19
+ fromRootId: normalizeRootId(rootId),
20
+ toRootId: options.toRootId,
21
+ mirrorOnly: !!options.mirrorOnly,
22
+ onChange: typeof options.onChange === 'function' ? options.onChange : undefined
23
+ });
24
+ }
25
+ export function removeRefLink(rootId, fromPath) {
26
+ const store = getRefStore(rootId);
27
+ if (!store)
28
+ return;
29
+ store.delete(fromPath);
30
+ }
31
+ export function getRefLinks(rootId = GLOBAL_ROOT_ID) {
32
+ return getRefStore(rootId) || EMPTY_MAP;
33
+ }
34
+ export function* getAllRefLinks() {
35
+ for (const context of getRootContexts()) {
36
+ yield* context.refLinks.values();
37
+ }
38
+ }
39
+ export function getRefRootIds() {
40
+ return Array.from(getRootContexts())
41
+ .filter(context => context.refLinks.size > 0)
42
+ .map(context => context.rootId);
43
+ }
44
+ export function __resetRefLinksForTests() {
45
+ for (const context of getRootContexts()) {
46
+ context.resetRefs();
47
+ }
48
+ }
49
+ function splitPath(path) {
50
+ return path.split('.').filter(Boolean);
51
+ }
52
+ function getRefStore(rootId, create = false) {
53
+ return getRootContext(normalizeRootId(rootId), create)?.refLinks;
54
+ }
@@ -0,0 +1,5 @@
1
+ export function isSilentContextActive(): boolean;
2
+ export function isModelEventsSilentContextActive(): boolean;
3
+ export function runInSilentContext(fn: any): any;
4
+ export function runInModelEventsSilentContext(fn: any): any;
5
+ export function __resetSilentContextForTests(): void;
@@ -0,0 +1,48 @@
1
+ let silentDepth = 0;
2
+ let modelEventsSilentDepth = 0;
3
+ export function isSilentContextActive() {
4
+ return silentDepth > 0;
5
+ }
6
+ export function isModelEventsSilentContextActive() {
7
+ return modelEventsSilentDepth > 0;
8
+ }
9
+ export function runInSilentContext(fn) {
10
+ silentDepth += 1;
11
+ let result;
12
+ try {
13
+ result = fn();
14
+ }
15
+ catch (error) {
16
+ silentDepth -= 1;
17
+ throw error;
18
+ }
19
+ if (result?.then) {
20
+ return Promise.resolve(result).finally(() => {
21
+ silentDepth -= 1;
22
+ });
23
+ }
24
+ silentDepth -= 1;
25
+ return result;
26
+ }
27
+ export function runInModelEventsSilentContext(fn) {
28
+ modelEventsSilentDepth += 1;
29
+ let result;
30
+ try {
31
+ result = fn();
32
+ }
33
+ catch (error) {
34
+ modelEventsSilentDepth -= 1;
35
+ throw error;
36
+ }
37
+ if (result?.then) {
38
+ return Promise.resolve(result).finally(() => {
39
+ modelEventsSilentDepth -= 1;
40
+ });
41
+ }
42
+ modelEventsSilentDepth -= 1;
43
+ return result;
44
+ }
45
+ export function __resetSilentContextForTests() {
46
+ silentDepth = 0;
47
+ modelEventsSilentDepth = 0;
48
+ }
@@ -0,0 +1,3 @@
1
+ export function compatStartOnRoot($root: any, targetPath: any, ...depsAndGetter: any[]): any;
2
+ export function compatStopOnRoot($root: any, targetPath: any): void;
3
+ export function joinScopePath(scopePath: any, relativePath: any): string;