teamplay 0.5.0-alpha.10 → 0.5.0-alpha.11
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.
|
@@ -8,39 +8,21 @@ export function isModelEventsSilentContextActive() {
|
|
|
8
8
|
}
|
|
9
9
|
export function runInSilentContext(fn) {
|
|
10
10
|
silentDepth += 1;
|
|
11
|
-
let result;
|
|
12
11
|
try {
|
|
13
|
-
|
|
12
|
+
return fn();
|
|
14
13
|
}
|
|
15
|
-
|
|
14
|
+
finally {
|
|
16
15
|
silentDepth -= 1;
|
|
17
|
-
throw error;
|
|
18
16
|
}
|
|
19
|
-
if (result?.then) {
|
|
20
|
-
return Promise.resolve(result).finally(() => {
|
|
21
|
-
silentDepth -= 1;
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
silentDepth -= 1;
|
|
25
|
-
return result;
|
|
26
17
|
}
|
|
27
18
|
export function runInModelEventsSilentContext(fn) {
|
|
28
19
|
modelEventsSilentDepth += 1;
|
|
29
|
-
let result;
|
|
30
20
|
try {
|
|
31
|
-
|
|
21
|
+
return fn();
|
|
32
22
|
}
|
|
33
|
-
|
|
23
|
+
finally {
|
|
34
24
|
modelEventsSilentDepth -= 1;
|
|
35
|
-
throw error;
|
|
36
|
-
}
|
|
37
|
-
if (result?.then) {
|
|
38
|
-
return Promise.resolve(result).finally(() => {
|
|
39
|
-
modelEventsSilentDepth -= 1;
|
|
40
|
-
});
|
|
41
25
|
}
|
|
42
|
-
modelEventsSilentDepth -= 1;
|
|
43
|
-
return result;
|
|
44
26
|
}
|
|
45
27
|
export function __resetSilentContextForTests() {
|
|
46
28
|
silentDepth = 0;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { observe, raw, unobserve } from '@nx-js/observer-util';
|
|
2
|
+
import { getActiveDocOpContext } from '../Doc.js';
|
|
2
3
|
import { getRoot } from "../Root.js";
|
|
3
4
|
import { scheduleReaction } from '../batchScheduler.js';
|
|
4
5
|
const START_REACTIONS = Symbol('compat start reactions');
|
|
@@ -19,11 +20,15 @@ export function compatStartOnRoot($root, targetPath, ...depsAndGetter) {
|
|
|
19
20
|
const targetSegments = parsePathSegments(targetPath);
|
|
20
21
|
const $target = resolveSignal($root, targetSegments);
|
|
21
22
|
const targetKey = $target.path();
|
|
23
|
+
const depPaths = deps
|
|
24
|
+
.map(dep => getStartDepPath(dep, $root))
|
|
25
|
+
.filter(Boolean);
|
|
22
26
|
const store = getStartStore($root);
|
|
23
27
|
const existing = store.get(targetKey);
|
|
24
28
|
if (existing)
|
|
25
29
|
existing.stop();
|
|
26
30
|
let lastSourceSnapshot = UNSET;
|
|
31
|
+
let lastTargetSnapshot = UNSET;
|
|
27
32
|
const reaction = observe(() => {
|
|
28
33
|
const resolvedDeps = [];
|
|
29
34
|
for (const dep of deps) {
|
|
@@ -45,8 +50,23 @@ export function compatStartOnRoot($root, targetPath, ...depsAndGetter) {
|
|
|
45
50
|
if (lastSourceSnapshot !== UNSET && deepEqualStartValue(lastSourceSnapshot, sourceSnapshot)) {
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
53
|
+
const currentTargetSnapshot = lastTargetSnapshot === UNSET
|
|
54
|
+
? UNSET
|
|
55
|
+
: detachStartValue($target.peek());
|
|
56
|
+
if (currentTargetSnapshot !== UNSET && deepEqualStartValue(currentTargetSnapshot, sourceSnapshot)) {
|
|
57
|
+
lastSourceSnapshot = sourceSnapshot;
|
|
58
|
+
lastTargetSnapshot = sourceSnapshot;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (currentTargetSnapshot !== UNSET &&
|
|
62
|
+
!deepEqualStartValue(lastTargetSnapshot, currentTargetSnapshot) &&
|
|
63
|
+
isActiveLocalDocOpForDeps(depPaths)) {
|
|
64
|
+
lastSourceSnapshot = sourceSnapshot;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
48
67
|
lastSourceSnapshot = sourceSnapshot;
|
|
49
68
|
const detachedValue = detachStartValue(sourceSnapshot);
|
|
69
|
+
lastTargetSnapshot = detachStartValue(detachedValue);
|
|
50
70
|
// Keep the detached snapshot to avoid aliasing source and target.
|
|
51
71
|
// Old racer start() writes through diffDeep by default. In compat mode we must preserve
|
|
52
72
|
// that behavior, but also avoid reading the target reactively inside start(), otherwise
|
|
@@ -104,9 +124,22 @@ function resolveStartDep(dep, $root) {
|
|
|
104
124
|
throw err;
|
|
105
125
|
}
|
|
106
126
|
}
|
|
127
|
+
function getStartDepPath(dep, $root) {
|
|
128
|
+
if (isSignalLike(dep))
|
|
129
|
+
return dep.path();
|
|
130
|
+
if (typeof dep === 'string')
|
|
131
|
+
return resolveSignal($root, parsePathSegments(dep)).path();
|
|
132
|
+
}
|
|
107
133
|
function getStartDepValue($signal) {
|
|
108
134
|
return readReactiveSnapshot($signal.get());
|
|
109
135
|
}
|
|
136
|
+
function isActiveLocalDocOpForDeps(depPaths) {
|
|
137
|
+
const context = getActiveDocOpContext();
|
|
138
|
+
if (!context?.source)
|
|
139
|
+
return false;
|
|
140
|
+
const docPath = `${context.collection}.${context.docId}`;
|
|
141
|
+
return depPaths.some(depPath => depPath === docPath || depPath.startsWith(docPath + '.'));
|
|
142
|
+
}
|
|
110
143
|
function readReactiveSnapshot(value) {
|
|
111
144
|
if (!value || typeof value !== 'object')
|
|
112
145
|
return value;
|
package/dist/orm/Doc.js
CHANGED
|
@@ -12,6 +12,43 @@ import { getRoot, ROOT_ID, GLOBAL_ROOT_ID, getRootTransportMode } from "./Root.j
|
|
|
12
12
|
import { registerRootOwnedDirectDocSubscription, unregisterRootOwnedDirectDocSubscription, getRootOwnedDirectDocSubscriptions, clearRootOwnedDirectDocSubscriptions } from "./rootContext.js";
|
|
13
13
|
const ERROR_ON_EXCESSIVE_UNSUBSCRIBES = false;
|
|
14
14
|
const DOC_FINALIZATION_TOKENS = new WeakMap();
|
|
15
|
+
const RECENT_DOC_OP_CONTEXT_TTL = 100;
|
|
16
|
+
const ACTIVE_DOC_OP_CONTEXTS = [];
|
|
17
|
+
let recentDocOpContext;
|
|
18
|
+
export function getActiveDocOpContext() {
|
|
19
|
+
return ACTIVE_DOC_OP_CONTEXTS[ACTIVE_DOC_OP_CONTEXTS.length - 1] || recentDocOpContext;
|
|
20
|
+
}
|
|
21
|
+
function pushActiveDocOpContext(collection, docId, source) {
|
|
22
|
+
const context = { collection, docId, source };
|
|
23
|
+
ACTIVE_DOC_OP_CONTEXTS.push(context);
|
|
24
|
+
recentDocOpContext = context;
|
|
25
|
+
}
|
|
26
|
+
function popActiveDocOpContext(collection, docId, source) {
|
|
27
|
+
const current = ACTIVE_DOC_OP_CONTEXTS[ACTIVE_DOC_OP_CONTEXTS.length - 1];
|
|
28
|
+
if (current?.collection === collection && current?.docId === docId && current?.source === source) {
|
|
29
|
+
ACTIVE_DOC_OP_CONTEXTS.pop();
|
|
30
|
+
clearRecentDocOpContext(current);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let index = -1;
|
|
34
|
+
for (let i = ACTIVE_DOC_OP_CONTEXTS.length - 1; i >= 0; i--) {
|
|
35
|
+
const context = ACTIVE_DOC_OP_CONTEXTS[i];
|
|
36
|
+
if (context.collection === collection && context.docId === docId && context.source === source) {
|
|
37
|
+
index = i;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (index === -1)
|
|
42
|
+
return;
|
|
43
|
+
const [context] = ACTIVE_DOC_OP_CONTEXTS.splice(index, 1);
|
|
44
|
+
clearRecentDocOpContext(context);
|
|
45
|
+
}
|
|
46
|
+
function clearRecentDocOpContext(context) {
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
if (recentDocOpContext === context)
|
|
49
|
+
recentDocOpContext = undefined;
|
|
50
|
+
}, RECENT_DOC_OP_CONTEXT_TTL);
|
|
51
|
+
}
|
|
15
52
|
function getDocFinalizationToken($doc) {
|
|
16
53
|
let token = DOC_FINALIZATION_TOKENS.get($doc);
|
|
17
54
|
if (!token) {
|
|
@@ -149,7 +186,15 @@ class Doc {
|
|
|
149
186
|
doc.on('create', () => this._refData());
|
|
150
187
|
doc.on('del', () => this._refMissingData());
|
|
151
188
|
if (isModelEventsEnabled()) {
|
|
152
|
-
doc.on('op',
|
|
189
|
+
doc.on('before op', (_op, source) => pushActiveDocOpContext(this.collection, this.docId, source));
|
|
190
|
+
doc.on('op', (op, source) => {
|
|
191
|
+
try {
|
|
192
|
+
emitDocOp(this.collection, this.docId, op, source);
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
popActiveDocOpContext(this.collection, this.docId, source);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
153
198
|
}
|
|
154
199
|
}
|
|
155
200
|
_refMissingData() {
|
|
@@ -870,7 +915,7 @@ function createPendingDestroyEntry() {
|
|
|
870
915
|
reject: rejectPending
|
|
871
916
|
};
|
|
872
917
|
}
|
|
873
|
-
function emitDocOp(collection, docId, op) {
|
|
918
|
+
function emitDocOp(collection, docId, op, source) {
|
|
874
919
|
if (!isModelEventsEnabled())
|
|
875
920
|
return;
|
|
876
921
|
const ops = Array.isArray(op) ? op : [op];
|
|
@@ -879,7 +924,7 @@ function emitDocOp(collection, docId, op) {
|
|
|
879
924
|
continue;
|
|
880
925
|
const baseSegments = [collection, docId];
|
|
881
926
|
let pathSegments = baseSegments.concat(component.p);
|
|
882
|
-
const meta = {};
|
|
927
|
+
const meta = { source };
|
|
883
928
|
let value;
|
|
884
929
|
let prevValue;
|
|
885
930
|
if (has(component, 'si') || has(component, 'sd')) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamplay",
|
|
3
|
-
"version": "0.5.0-alpha.
|
|
3
|
+
"version": "0.5.0-alpha.11",
|
|
4
4
|
"description": "Full-stack signals ORM with multiplayer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -134,5 +134,5 @@
|
|
|
134
134
|
]
|
|
135
135
|
},
|
|
136
136
|
"license": "MIT",
|
|
137
|
-
"gitHead": "
|
|
137
|
+
"gitHead": "2c23ad4108aad3dc7ac4947a987e395e933761cc"
|
|
138
138
|
}
|