teamplay 0.4.0-alpha.97 → 0.4.0-alpha.98
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/orm/Compat/SignalCompat.js +12 -3
- package/orm/dataTree.js +17 -0
- package/package.json +2 -2
- package/react/useSub.js +6 -1
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from '../dataTree.js'
|
|
30
30
|
import { on as onCustomEvent, removeListener as removeCustomEventListener } from './eventsCompat.js'
|
|
31
31
|
import { waitForImperativeQueryReady } from './queryReadiness.js'
|
|
32
|
-
import { normalizePattern, onModelEvent, removeModelListener } from './modelEvents.js'
|
|
32
|
+
import { isModelEventsEnabled, normalizePattern, onModelEvent, removeModelListener } from './modelEvents.js'
|
|
33
33
|
import { setRefLink, removeRefLink, getAllRefLinks } from './refRegistry.js'
|
|
34
34
|
import { REF_TARGET, resolveRefSignalSafe, resolveRefSegmentsSafe } from './refFallback.js'
|
|
35
35
|
import { runInBatch } from '../batchScheduler.js'
|
|
@@ -1061,7 +1061,9 @@ function setReplacePrivateCompatSync ($signal, value) {
|
|
|
1061
1061
|
value = normalizeIdFields(value, idFields, segments[1])
|
|
1062
1062
|
}
|
|
1063
1063
|
setReplacePrivateData(getOwningRootId($signal), segments, value)
|
|
1064
|
-
if (
|
|
1064
|
+
if (shouldMirrorPrivateRefMutationLocally()) {
|
|
1065
|
+
mirrorRefMutationFromTarget(segments, value)
|
|
1066
|
+
}
|
|
1065
1067
|
}
|
|
1066
1068
|
|
|
1067
1069
|
function delPrivateCompatSync ($signal, options) {
|
|
@@ -1123,7 +1125,9 @@ async function setReplaceOnSignal ($signal, value) {
|
|
|
1123
1125
|
}
|
|
1124
1126
|
if (isPrivateMutationForbidden()) throw Error(ERRORS.publicOnly)
|
|
1125
1127
|
const result = setReplacePrivateData(getOwningRootId($signal), segments, value)
|
|
1126
|
-
if (
|
|
1128
|
+
if (shouldMirrorPrivateRefMutationLocally()) {
|
|
1129
|
+
mirrorRefMutationFromTarget(segments, value)
|
|
1130
|
+
}
|
|
1127
1131
|
return result
|
|
1128
1132
|
}
|
|
1129
1133
|
|
|
@@ -1271,6 +1275,11 @@ function shouldMirrorPublicRefMutationLocally (segments) {
|
|
|
1271
1275
|
return !docSubscriptions.hasRuntime(transportHash)
|
|
1272
1276
|
}
|
|
1273
1277
|
|
|
1278
|
+
function shouldMirrorPrivateRefMutationLocally () {
|
|
1279
|
+
if (isSilentContextActive()) return true
|
|
1280
|
+
return !isModelEventsEnabled()
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1274
1283
|
function shallowCopy (value) {
|
|
1275
1284
|
const rawValue = raw(value)
|
|
1276
1285
|
if (Array.isArray(rawValue)) return rawValue.slice()
|
package/orm/dataTree.js
CHANGED
|
@@ -326,6 +326,13 @@ export async function setPublicDocReplace (segments, value) {
|
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
const relativePath = segments.slice(2)
|
|
329
|
+
// json0 direct replace ops require every ancestor container to already exist.
|
|
330
|
+
// Racer-like compat set, however, materializes missing/primitive parents while
|
|
331
|
+
// descending into the path. Fall back to the older diff-based path when the
|
|
332
|
+
// direct op would target a non-existent/non-object ancestor.
|
|
333
|
+
if (!canApplyDirectReplaceOp(docState.snapshot || {}, relativePath)) {
|
|
334
|
+
return setPublicDoc(segments, value)
|
|
335
|
+
}
|
|
329
336
|
const previous = getRaw(segments)
|
|
330
337
|
const normalizedPrevious = normalizeUndefined(
|
|
331
338
|
relativePath.length === 0 ? stripIdFields(previous, idFields) : previous
|
|
@@ -444,6 +451,16 @@ function normalizeUndefined (value) {
|
|
|
444
451
|
return value === undefined ? null : value
|
|
445
452
|
}
|
|
446
453
|
|
|
454
|
+
function canApplyDirectReplaceOp (docSnapshot, relativePath) {
|
|
455
|
+
if (relativePath.length === 0) return true
|
|
456
|
+
let node = docSnapshot
|
|
457
|
+
for (let i = 0; i < relativePath.length - 1; i++) {
|
|
458
|
+
if (node == null || typeof node !== 'object') return false
|
|
459
|
+
node = node[relativePath[i]]
|
|
460
|
+
}
|
|
461
|
+
return node != null && typeof node === 'object'
|
|
462
|
+
}
|
|
463
|
+
|
|
447
464
|
function normalizeValueForOp (value) {
|
|
448
465
|
let result = raw(value)
|
|
449
466
|
if (result != null && typeof result === 'object') result = JSON.parse(JSON.stringify(result))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamplay",
|
|
3
|
-
"version": "0.4.0-alpha.
|
|
3
|
+
"version": "0.4.0-alpha.98",
|
|
4
4
|
"description": "Full-stack signals ORM with multiplayer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
]
|
|
84
84
|
},
|
|
85
85
|
"license": "MIT",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "ae4e0e6ee39e395fa9eb48a2099cc1d5b2a4630d"
|
|
87
87
|
}
|
package/react/useSub.js
CHANGED
|
@@ -44,8 +44,8 @@ export function useSubDeferred (signal, params, { async = false, defer, batch =
|
|
|
44
44
|
// 1. if it's a promise, throw it so that Suspense can catch it and wait for subscription to finish
|
|
45
45
|
if (promiseOrSignal.then) {
|
|
46
46
|
const promise = maybeThrottle(promiseOrSignal)
|
|
47
|
+
const hasPreviousSignal = !!$signalRef.current
|
|
47
48
|
if (batch) {
|
|
48
|
-
const hasPreviousSignal = !!$signalRef.current
|
|
49
49
|
// Batch suspense must block only on initial load.
|
|
50
50
|
// On resubscribe we keep rendering previous signal and refresh in background.
|
|
51
51
|
if (!hasPreviousSignal) {
|
|
@@ -61,6 +61,11 @@ export function useSubDeferred (signal, params, { async = false, defer, batch =
|
|
|
61
61
|
scheduleUpdate(promise)
|
|
62
62
|
return
|
|
63
63
|
}
|
|
64
|
+
// Keep previous snapshot during update re-subscribe and refresh in background.
|
|
65
|
+
if (hasPreviousSignal) {
|
|
66
|
+
scheduleUpdate(promise)
|
|
67
|
+
return $signalRef.current
|
|
68
|
+
}
|
|
64
69
|
if (compatAttemptCleanup) registerCompatAttemptCleanup(signal, params)
|
|
65
70
|
throw promise
|
|
66
71
|
// 2. if it's a signal, we save it into ref to make sure it's not garbage collected while component exists
|