teamplay 0.5.0-alpha.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +3 -3
  2. package/dist/config.d.ts +2 -0
  3. package/dist/config.js +1 -0
  4. package/dist/connect/index.d.ts +1 -1
  5. package/dist/connect/index.js +6 -2
  6. package/dist/connect/offline/index.d.ts +1 -1
  7. package/dist/connect/offline/index.js +8 -4
  8. package/dist/connect/offline/react-native.d.ts +1 -1
  9. package/dist/connect/offline/web.d.ts +1 -1
  10. package/dist/connect/test.d.ts +1 -1
  11. package/dist/connect/test.js +5 -1
  12. package/dist/index.d.ts +9 -5
  13. package/dist/index.js +6 -5
  14. package/dist/orm/$.js +1 -1
  15. package/dist/orm/Aggregation.d.ts +5 -3
  16. package/dist/orm/Aggregation.js +39 -15
  17. package/dist/orm/Doc.js +0 -55
  18. package/dist/orm/Query.d.ts +1 -0
  19. package/dist/orm/Query.js +25 -82
  20. package/dist/orm/Root.d.ts +4 -0
  21. package/dist/orm/Root.js +16 -0
  22. package/dist/orm/Signal.d.ts +0 -2
  23. package/dist/orm/Signal.js +1 -4
  24. package/dist/orm/SignalBase.d.ts +21 -1
  25. package/dist/orm/SignalBase.js +259 -56
  26. package/dist/orm/batchScheduler.d.ts +7 -7
  27. package/dist/orm/connection.d.ts +0 -4
  28. package/dist/orm/connection.js +0 -12
  29. package/dist/orm/dataTree.d.ts +12 -12
  30. package/dist/orm/dataTree.js +55 -107
  31. package/dist/orm/disposeRootContext.js +0 -14
  32. package/dist/orm/events.d.ts +6 -0
  33. package/dist/orm/events.js +48 -0
  34. package/dist/orm/getSignal.d.ts +1 -1
  35. package/dist/orm/getSignal.js +4 -33
  36. package/dist/orm/idFields.d.ts +10 -1
  37. package/dist/orm/idFields.js +102 -14
  38. package/dist/orm/index.d.ts +2 -0
  39. package/dist/orm/index.js +1 -0
  40. package/dist/orm/initModels.js +1 -1
  41. package/dist/orm/privateData.d.ts +7 -22
  42. package/dist/orm/privateData.js +20 -1
  43. package/dist/orm/queryReadiness.d.ts +13 -0
  44. package/dist/orm/{Compat/queryReadiness.js → queryReadiness.js} +10 -10
  45. package/dist/orm/reaction.d.ts +11 -0
  46. package/dist/orm/reaction.js +47 -0
  47. package/dist/orm/rootContext.d.ts +0 -16
  48. package/dist/orm/rootContext.js +0 -28
  49. package/dist/orm/signalMetadata.js +3 -3
  50. package/dist/orm/signalReads.js +3 -9
  51. package/dist/orm/signalStorageMutations.d.ts +0 -2
  52. package/dist/orm/signalStorageMutations.js +0 -9
  53. package/dist/orm/signalSymbols.js +1 -1
  54. package/dist/orm/signalValueMutations.d.ts +1 -1
  55. package/dist/orm/signalValueMutations.js +0 -3
  56. package/dist/orm/sub.d.ts +12 -7
  57. package/dist/orm/sub.js +87 -30
  58. package/dist/orm/subscriptionGcDelay.js +2 -6
  59. package/dist/react/convertToObserver.js +1 -4
  60. package/dist/react/promiseBatcher.js +1 -1
  61. package/dist/react/renderAttemptDestroyer.d.ts +0 -8
  62. package/dist/react/renderAttemptDestroyer.js +2 -28
  63. package/dist/react/trapRender.js +3 -3
  64. package/dist/react/useSub.d.ts +86 -5
  65. package/dist/react/useSub.js +191 -32
  66. package/dist/react/useSuspendMemo.js +1 -5
  67. package/dist/server.d.ts +2 -3
  68. package/dist/server.js +5 -3
  69. package/package.json +16 -14
  70. package/dist/orm/Compat/SignalCompat.d.ts +0 -3
  71. package/dist/orm/Compat/SignalCompat.js +0 -1267
  72. package/dist/orm/Compat/eventsCompat.d.ts +0 -3
  73. package/dist/orm/Compat/eventsCompat.js +0 -73
  74. package/dist/orm/Compat/hooksCompat.d.ts +0 -33
  75. package/dist/orm/Compat/hooksCompat.js +0 -360
  76. package/dist/orm/Compat/modelEvents.d.ts +0 -6
  77. package/dist/orm/Compat/modelEvents.js +0 -228
  78. package/dist/orm/Compat/queryReadiness.d.ts +0 -5
  79. package/dist/orm/Compat/refFallback.d.ts +0 -13
  80. package/dist/orm/Compat/refFallback.js +0 -65
  81. package/dist/orm/Compat/refRegistry.d.ts +0 -6
  82. package/dist/orm/Compat/refRegistry.js +0 -54
  83. package/dist/orm/Compat/silentContext.d.ts +0 -5
  84. package/dist/orm/Compat/silentContext.js +0 -48
  85. package/dist/orm/Compat/startStopCompat.d.ts +0 -3
  86. package/dist/orm/Compat/startStopCompat.js +0 -217
  87. package/dist/orm/compatEnv.d.ts +0 -1
  88. package/dist/orm/compatEnv.js +0 -4
  89. package/dist/react/compatComponentRegistry.d.ts +0 -4
  90. package/dist/react/compatComponentRegistry.js +0 -19
  91. /package/dist/orm/{Reaction.d.ts → reactionSubscriptions.d.ts} +0 -0
  92. /package/dist/orm/{Reaction.js → reactionSubscriptions.js} +0 -0
@@ -1,228 +0,0 @@
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
- }
@@ -1,5 +0,0 @@
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;
@@ -1,13 +0,0 @@
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
@@ -1,65 +0,0 @@
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
- }
@@ -1,6 +0,0 @@
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;
@@ -1,54 +0,0 @@
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
- }
@@ -1,5 +0,0 @@
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;
@@ -1,48 +0,0 @@
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
- }
@@ -1,3 +0,0 @@
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;
@@ -1,217 +0,0 @@
1
- import { observe, raw, unobserve } from '@nx-js/observer-util';
2
- import { getRoot } from "../Root.js";
3
- import { scheduleReaction } from '../batchScheduler.js';
4
- const START_REACTIONS = Symbol('compat start reactions');
5
- const SKIP_TICK = Symbol('compat start skip tick');
6
- export function compatStartOnRoot($root, targetPath, ...depsAndGetter) {
7
- if (!isRootSignal($root))
8
- throw Error('Signal.start() is only available on root signal');
9
- if (typeof targetPath !== 'string')
10
- throw Error('Signal.start() expects targetPath to be a string');
11
- if (depsAndGetter.length < 1) {
12
- throw Error('Signal.start() expects targetPath, dependencies, and a getter function');
13
- }
14
- const getter = depsAndGetter[depsAndGetter.length - 1];
15
- if (typeof getter !== 'function') {
16
- throw Error('Signal.start() expects the last argument to be a getter function');
17
- }
18
- const deps = depsAndGetter.slice(0, -1);
19
- const targetSegments = parsePathSegments(targetPath);
20
- const $target = resolveSignal($root, targetSegments);
21
- const targetKey = $target.path();
22
- const store = getStartStore($root);
23
- const existing = store.get(targetKey);
24
- if (existing)
25
- existing.stop();
26
- let lastSourceSnapshot = UNSET;
27
- const reaction = observe(() => {
28
- const resolvedDeps = [];
29
- for (const dep of deps) {
30
- const resolved = resolveStartDep(dep, $root);
31
- if (resolved === SKIP_TICK)
32
- return;
33
- resolvedDeps.push(resolved);
34
- }
35
- let nextValue;
36
- try {
37
- nextValue = getter(...resolvedDeps);
38
- }
39
- catch (err) {
40
- if (isThenable(err))
41
- return;
42
- throw err;
43
- }
44
- const sourceSnapshot = detachStartValue(nextValue);
45
- if (lastSourceSnapshot !== UNSET && deepEqualStartValue(lastSourceSnapshot, sourceSnapshot)) {
46
- return;
47
- }
48
- lastSourceSnapshot = sourceSnapshot;
49
- const detachedValue = detachStartValue(sourceSnapshot);
50
- // Keep the detached snapshot to avoid aliasing source and target.
51
- // Old racer start() writes through diffDeep by default. In compat mode we must preserve
52
- // that behavior, but also avoid reading the target reactively inside start(), otherwise
53
- // start() subscribes to its own output and local child edits get immediately overwritten.
54
- const maybePromise = $target.setDiffDeep(detachedValue);
55
- if (maybePromise?.then) {
56
- maybePromise
57
- .then(() => { })
58
- .catch(ignorePromiseRejection);
59
- }
60
- }, { scheduler: scheduleReaction });
61
- store.set(targetKey, { stop: () => unobserve(reaction) });
62
- return $target;
63
- }
64
- export function compatStopOnRoot($root, targetPath) {
65
- if (!isRootSignal($root))
66
- throw Error('Signal.stop() is only available on root signal');
67
- if (typeof targetPath !== 'string')
68
- throw Error('Signal.stop() expects targetPath to be a string');
69
- const targetSegments = parsePathSegments(targetPath);
70
- const $target = resolveSignal($root, targetSegments);
71
- const targetKey = $target.path();
72
- const store = getStartStore($root);
73
- const existing = store.get(targetKey);
74
- if (!existing)
75
- return;
76
- existing.stop();
77
- store.delete(targetKey);
78
- }
79
- export function joinScopePath(scopePath, relativePath) {
80
- if (typeof scopePath !== 'string')
81
- scopePath = '';
82
- const segments = [];
83
- if (scopePath)
84
- segments.push(...parsePathSegments(scopePath));
85
- if (relativePath)
86
- segments.push(...parsePathSegments(relativePath));
87
- return segments.join('.');
88
- }
89
- function getStartStore($root) {
90
- $root[START_REACTIONS] ??= new Map();
91
- return $root[START_REACTIONS];
92
- }
93
- function resolveStartDep(dep, $root) {
94
- try {
95
- if (isSignalLike(dep))
96
- return getStartDepValue(dep);
97
- if (typeof dep === 'string')
98
- return getStartDepValue(resolveSignal($root, parsePathSegments(dep)));
99
- return dep;
100
- }
101
- catch (err) {
102
- if (isThenable(err))
103
- return SKIP_TICK;
104
- throw err;
105
- }
106
- }
107
- function getStartDepValue($signal) {
108
- return readReactiveSnapshot($signal.get());
109
- }
110
- function readReactiveSnapshot(value) {
111
- if (!value || typeof value !== 'object')
112
- return value;
113
- if (value instanceof Date)
114
- return new Date(value);
115
- if (Array.isArray(value)) {
116
- const array = [];
117
- for (let i = 0; i < value.length; i++) {
118
- array[i] = readReactiveSnapshot(value[i]);
119
- }
120
- return array;
121
- }
122
- const object = new value.constructor();
123
- for (const key in value) {
124
- if (Object.prototype.hasOwnProperty.call(value, key)) {
125
- object[key] = readReactiveSnapshot(value[key]);
126
- }
127
- }
128
- return object;
129
- }
130
- function isSignalLike(value) {
131
- return value && typeof value.path === 'function' && typeof value.get === 'function';
132
- }
133
- function parsePathSegments(path) {
134
- return path.split('.').filter(Boolean);
135
- }
136
- function resolveSignal($base, segments) {
137
- let $cursor = $base;
138
- for (const segment of segments)
139
- $cursor = $cursor[segment];
140
- return $cursor;
141
- }
142
- function isRootSignal($signal) {
143
- return getRoot($signal) === $signal;
144
- }
145
- function ignorePromiseRejection() { }
146
- function isThenable(value) {
147
- return !!value && typeof value.then === 'function';
148
- }
149
- const UNSET = Symbol('compat start unset');
150
- function detachStartValue(value) {
151
- const rawValue = raw(value);
152
- if (!rawValue || typeof rawValue !== 'object')
153
- return rawValue;
154
- if (typeof globalThis.structuredClone === 'function') {
155
- try {
156
- return globalThis.structuredClone(rawValue);
157
- }
158
- catch { }
159
- }
160
- return racerDeepCopy(rawValue);
161
- }
162
- function racerDeepCopy(value) {
163
- if (value instanceof Date)
164
- return new Date(value);
165
- if (typeof value === 'object') {
166
- if (value === null)
167
- return null;
168
- if (Array.isArray(value)) {
169
- const array = [];
170
- for (let i = value.length; i--;) {
171
- array[i] = racerDeepCopy(value[i]);
172
- }
173
- return array;
174
- }
175
- const object = new value.constructor();
176
- for (const key in value) {
177
- if (Object.prototype.hasOwnProperty.call(value, key)) {
178
- object[key] = racerDeepCopy(value[key]);
179
- }
180
- }
181
- return object;
182
- }
183
- return value;
184
- }
185
- function deepEqualStartValue(left, right) {
186
- if (left === right)
187
- return true;
188
- if (Number.isNaN(left) && Number.isNaN(right))
189
- return true;
190
- if (left instanceof Date || right instanceof Date) {
191
- return left instanceof Date && right instanceof Date && left.getTime() === right.getTime();
192
- }
193
- if (!left || !right || typeof left !== 'object' || typeof right !== 'object')
194
- return false;
195
- if (Array.isArray(left) || Array.isArray(right)) {
196
- if (!Array.isArray(left) || !Array.isArray(right))
197
- return false;
198
- if (left.length !== right.length)
199
- return false;
200
- for (let i = 0; i < left.length; i++) {
201
- if (!deepEqualStartValue(left[i], right[i]))
202
- return false;
203
- }
204
- return true;
205
- }
206
- const leftKeys = Object.keys(left);
207
- const rightKeys = Object.keys(right);
208
- if (leftKeys.length !== rightKeys.length)
209
- return false;
210
- for (const key of leftKeys) {
211
- if (!Object.prototype.hasOwnProperty.call(right, key))
212
- return false;
213
- if (!deepEqualStartValue(left[key], right[key]))
214
- return false;
215
- }
216
- return true;
217
- }
@@ -1 +0,0 @@
1
- export function isCompatEnv (): boolean
@@ -1,4 +0,0 @@
1
- export function isCompatEnv() {
2
- return globalThis?.teamplayCompatibilityMode ??
3
- (typeof process !== 'undefined' && process?.env?.TEAMPLAY_COMPAT === '1');
4
- }
@@ -1,4 +0,0 @@
1
- export declare function markCompatComponent(componentId: string | undefined): void;
2
- export declare function unmarkCompatComponent(componentId: string | undefined): void;
3
- export declare function isCompatComponent(componentId: string | undefined): boolean;
4
- export declare function __resetCompatComponentRegistryForTests(): void;
@@ -1,19 +0,0 @@
1
- const compatComponentIds = new Set();
2
- export function markCompatComponent(componentId) {
3
- if (!componentId)
4
- return;
5
- compatComponentIds.add(componentId);
6
- }
7
- export function unmarkCompatComponent(componentId) {
8
- if (!componentId)
9
- return;
10
- compatComponentIds.delete(componentId);
11
- }
12
- export function isCompatComponent(componentId) {
13
- if (!componentId)
14
- return false;
15
- return compatComponentIds.has(componentId);
16
- }
17
- export function __resetCompatComponentRegistryForTests() {
18
- compatComponentIds.clear();
19
- }