canvu-react 0.4.42 → 0.4.44
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/dist/native.cjs +480 -63
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +46 -3
- package/dist/native.d.ts +46 -3
- package/dist/native.js +480 -64
- package/dist/native.js.map +1 -1
- package/dist/realtime.cjs +82 -12
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.js +82 -12
- package/dist/realtime.js.map +1 -1
- package/dist/realtimeNative.cjs +85 -15
- package/dist/realtimeNative.cjs.map +1 -1
- package/dist/realtimeNative.js +85 -15
- package/dist/realtimeNative.js.map +1 -1
- package/package.json +1 -1
package/dist/realtime.js
CHANGED
|
@@ -2235,6 +2235,7 @@ var ORIGIN_BOOTSTRAP = /* @__PURE__ */ Symbol("canvu/realtime/bootstrap");
|
|
|
2235
2235
|
var DRAFT_STORAGE_PREFIX = "canvu-realtime-draft:";
|
|
2236
2236
|
var DOCUMENT_FLUSH_DEBOUNCE_MS = 120;
|
|
2237
2237
|
var DRAFT_PERSIST_DEBOUNCE_MS = 420;
|
|
2238
|
+
var CONNECTION_MESSAGE_STATE_UPDATE_INTERVAL_MS = 1e3;
|
|
2238
2239
|
function requestWindowIdleCallback(callback, timeout) {
|
|
2239
2240
|
if (typeof window.requestIdleCallback === "function") {
|
|
2240
2241
|
return window.requestIdleCallback(callback, { timeout });
|
|
@@ -2312,6 +2313,9 @@ function sameSerializedItems(left, right) {
|
|
|
2312
2313
|
function nowMs() {
|
|
2313
2314
|
return Date.now();
|
|
2314
2315
|
}
|
|
2316
|
+
function shouldUpdateRealtimeConnectionMessageState(input) {
|
|
2317
|
+
return input.lastStateUpdateAt == null || input.receivedAt - input.lastStateUpdateAt >= CONNECTION_MESSAGE_STATE_UPDATE_INTERVAL_MS;
|
|
2318
|
+
}
|
|
2315
2319
|
function hasDurableDocumentPersistence(snapshot) {
|
|
2316
2320
|
return snapshot.persistedRevision == null || snapshot.persistedRevision >= snapshot.revision;
|
|
2317
2321
|
}
|
|
@@ -2459,6 +2463,7 @@ function useRealtimeSession(options) {
|
|
|
2459
2463
|
const connectionStateRef = useRef(
|
|
2460
2464
|
enabled ? "connecting" : "offline"
|
|
2461
2465
|
);
|
|
2466
|
+
const lastConnectionMessageStateUpdateAtRef = useRef(null);
|
|
2462
2467
|
const localDraftRef = useRef(null);
|
|
2463
2468
|
const conflictRef = useRef(null);
|
|
2464
2469
|
const onErrorRef = useRef(onError);
|
|
@@ -3011,6 +3016,7 @@ function useRealtimeSession(options) {
|
|
|
3011
3016
|
useEffect(() => {
|
|
3012
3017
|
if (!enabled) {
|
|
3013
3018
|
manualDisconnectRef.current = true;
|
|
3019
|
+
lastConnectionMessageStateUpdateAtRef.current = null;
|
|
3014
3020
|
clearReconnectTimer();
|
|
3015
3021
|
clearHeartbeatTimer();
|
|
3016
3022
|
clearConnectTimeout();
|
|
@@ -3055,6 +3061,7 @@ function useRealtimeSession(options) {
|
|
|
3055
3061
|
return;
|
|
3056
3062
|
}
|
|
3057
3063
|
let disposed = false;
|
|
3064
|
+
lastConnectionMessageStateUpdateAtRef.current = null;
|
|
3058
3065
|
updateConnectionRef.current((prev) => ({
|
|
3059
3066
|
...prev,
|
|
3060
3067
|
state: retryCountRef.current > 0 ? "reconnecting" : "connecting",
|
|
@@ -3106,10 +3113,17 @@ function useRealtimeSession(options) {
|
|
|
3106
3113
|
}
|
|
3107
3114
|
const parsed = parseRealtimeServerMessage(payload);
|
|
3108
3115
|
if (!parsed) return;
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3116
|
+
const receivedAt = nowMs();
|
|
3117
|
+
if (shouldUpdateRealtimeConnectionMessageState({
|
|
3118
|
+
lastStateUpdateAt: lastConnectionMessageStateUpdateAtRef.current,
|
|
3119
|
+
receivedAt
|
|
3120
|
+
})) {
|
|
3121
|
+
lastConnectionMessageStateUpdateAtRef.current = receivedAt;
|
|
3122
|
+
updateConnectionRef.current((prev) => ({
|
|
3123
|
+
...prev,
|
|
3124
|
+
lastMessageAt: receivedAt
|
|
3125
|
+
}));
|
|
3126
|
+
}
|
|
3113
3127
|
if (parsed.type === "session:welcome") {
|
|
3114
3128
|
retryCountRef.current = 0;
|
|
3115
3129
|
updateConnectionRef.current((prev) => ({
|
|
@@ -3118,7 +3132,7 @@ function useRealtimeSession(options) {
|
|
|
3118
3132
|
connected: true,
|
|
3119
3133
|
clientId: parsed.clientId,
|
|
3120
3134
|
retryCount: 0,
|
|
3121
|
-
lastConnectedAt:
|
|
3135
|
+
lastConnectedAt: receivedAt,
|
|
3122
3136
|
lastError: null
|
|
3123
3137
|
}));
|
|
3124
3138
|
applyPeersRef.current(parsed.peers);
|
|
@@ -3606,6 +3620,12 @@ function realtimeSessionPlugin(options) {
|
|
|
3606
3620
|
render: () => /* @__PURE__ */ jsx(RealtimeSessionPanel, { ...options })
|
|
3607
3621
|
};
|
|
3608
3622
|
}
|
|
3623
|
+
var CLIENT_ONLY_IMAGE_KEYS2 = /* @__PURE__ */ new Set([
|
|
3624
|
+
"imageBlobId",
|
|
3625
|
+
"imageThumbnailBlobId",
|
|
3626
|
+
"imageRasterHref",
|
|
3627
|
+
"imageThumbnailHref"
|
|
3628
|
+
]);
|
|
3609
3629
|
function getSceneItemId(item) {
|
|
3610
3630
|
const id = item.id;
|
|
3611
3631
|
return typeof id === "string" ? id : null;
|
|
@@ -3622,6 +3642,43 @@ function hasMissingLocalItems(localItems, incomingItems) {
|
|
|
3622
3642
|
}
|
|
3623
3643
|
return false;
|
|
3624
3644
|
}
|
|
3645
|
+
function getComparableRealtimeItem(item) {
|
|
3646
|
+
const comparable = { ...item };
|
|
3647
|
+
if (item.toolKind === "image") {
|
|
3648
|
+
for (const key of CLIENT_ONLY_IMAGE_KEYS2) {
|
|
3649
|
+
delete comparable[key];
|
|
3650
|
+
}
|
|
3651
|
+
comparable.childrenSvg = "";
|
|
3652
|
+
}
|
|
3653
|
+
return comparable;
|
|
3654
|
+
}
|
|
3655
|
+
function serializeComparableRealtimeItem(item) {
|
|
3656
|
+
return JSON.stringify(getComparableRealtimeItem(item));
|
|
3657
|
+
}
|
|
3658
|
+
function hasChangedLocalItems(localItems, incomingItems) {
|
|
3659
|
+
const incomingItemsById = /* @__PURE__ */ new Map();
|
|
3660
|
+
for (const incomingItem of incomingItems) {
|
|
3661
|
+
const id = getSceneItemId(incomingItem);
|
|
3662
|
+
if (id) incomingItemsById.set(id, incomingItem);
|
|
3663
|
+
}
|
|
3664
|
+
for (const localItem of localItems) {
|
|
3665
|
+
const id = getSceneItemId(localItem);
|
|
3666
|
+
const incomingItem = id ? incomingItemsById.get(id) : null;
|
|
3667
|
+
if (!incomingItem) continue;
|
|
3668
|
+
if (serializeComparableRealtimeItem(localItem) !== serializeComparableRealtimeItem(incomingItem)) {
|
|
3669
|
+
return true;
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
return false;
|
|
3673
|
+
}
|
|
3674
|
+
function shouldPreserveLocalRealtimeItems({
|
|
3675
|
+
localItems,
|
|
3676
|
+
incomingItems,
|
|
3677
|
+
hasPendingLocalChanges
|
|
3678
|
+
}) {
|
|
3679
|
+
if (!hasPendingLocalChanges) return false;
|
|
3680
|
+
return hasMissingLocalItems(localItems, incomingItems) || hasChangedLocalItems(localItems, incomingItems);
|
|
3681
|
+
}
|
|
3625
3682
|
function useRealtimeCanvasDocument(options) {
|
|
3626
3683
|
const {
|
|
3627
3684
|
session,
|
|
@@ -3634,6 +3691,8 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3634
3691
|
const [loading, setLoading] = useState(false);
|
|
3635
3692
|
const lastAppliedRevisionRef = useRef(null);
|
|
3636
3693
|
const inFlightRevisionRef = useRef(null);
|
|
3694
|
+
const latestItemsRef = useRef(items);
|
|
3695
|
+
const hasLocalChangeInFlightRef = useRef(false);
|
|
3637
3696
|
const hasEverPropagatedItemsRef = useRef(false);
|
|
3638
3697
|
const realtimeEnabled = enabled && session != null;
|
|
3639
3698
|
const documentRevision = session?.document?.revision ?? null;
|
|
@@ -3656,6 +3715,7 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3656
3715
|
onItemsChange?.(normalizeItems ? normalizeItems(nextItems) : nextItems);
|
|
3657
3716
|
return;
|
|
3658
3717
|
}
|
|
3718
|
+
hasLocalChangeInFlightRef.current = true;
|
|
3659
3719
|
const normalizedItems = normalizeItems ? normalizeItems(nextItems) : nextItems;
|
|
3660
3720
|
onItemsChange?.(normalizedItems);
|
|
3661
3721
|
session?.remoteAdapter.send?.(normalizedItems);
|
|
@@ -3663,10 +3723,16 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3663
3723
|
[enabled, normalizeItems, onItemsChange, session]
|
|
3664
3724
|
);
|
|
3665
3725
|
useEffect(() => {
|
|
3726
|
+
latestItemsRef.current = items;
|
|
3666
3727
|
if (items.length > 0) {
|
|
3667
3728
|
hasEverPropagatedItemsRef.current = true;
|
|
3668
3729
|
}
|
|
3669
|
-
}, [items
|
|
3730
|
+
}, [items]);
|
|
3731
|
+
useEffect(() => {
|
|
3732
|
+
if (!hasLocalOfflineDraft && !hasPendingDocumentSync) {
|
|
3733
|
+
hasLocalChangeInFlightRef.current = false;
|
|
3734
|
+
}
|
|
3735
|
+
}, [hasLocalOfflineDraft, hasPendingDocumentSync]);
|
|
3670
3736
|
useEffect(() => {
|
|
3671
3737
|
if (!realtimeEnabled || !onItemsChange || !session?.document) return;
|
|
3672
3738
|
if (documentUpdatedByClientId === connectionClientId) return;
|
|
@@ -3680,17 +3746,22 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3680
3746
|
if (cancelled) return;
|
|
3681
3747
|
if (inFlightRevisionRef.current !== documentRevision) return;
|
|
3682
3748
|
lastAppliedRevisionRef.current = documentRevision;
|
|
3683
|
-
const
|
|
3684
|
-
const
|
|
3749
|
+
const localItems = latestItemsRef.current;
|
|
3750
|
+
const hasLocalItems = localItems.length > 0;
|
|
3751
|
+
const hasPendingLocalChanges = hasLocalOfflineDraft || hasPendingDocumentSync || hasLocalChangeInFlightRef.current;
|
|
3685
3752
|
if (resolvedItems.length === 0 && (hasEverPropagatedItemsRef.current || hasLocalItems || hasPendingLocalChanges)) {
|
|
3686
3753
|
if (hasLocalItems) {
|
|
3687
|
-
const normalizedLocalItems = normalizeItems ? normalizeItems(
|
|
3754
|
+
const normalizedLocalItems = normalizeItems ? normalizeItems(localItems) : [...localItems];
|
|
3688
3755
|
session.remoteAdapter.send?.(normalizedLocalItems);
|
|
3689
3756
|
}
|
|
3690
3757
|
return;
|
|
3691
3758
|
}
|
|
3692
|
-
if (
|
|
3693
|
-
|
|
3759
|
+
if (shouldPreserveLocalRealtimeItems({
|
|
3760
|
+
localItems,
|
|
3761
|
+
incomingItems: resolvedItems,
|
|
3762
|
+
hasPendingLocalChanges
|
|
3763
|
+
})) {
|
|
3764
|
+
const normalizedLocalItems = normalizeItems ? normalizeItems(localItems) : [...localItems];
|
|
3694
3765
|
session.remoteAdapter.send?.(normalizedLocalItems);
|
|
3695
3766
|
return;
|
|
3696
3767
|
}
|
|
@@ -3716,7 +3787,6 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3716
3787
|
documentUpdatedByClientId,
|
|
3717
3788
|
hasLocalOfflineDraft,
|
|
3718
3789
|
hasPendingDocumentSync,
|
|
3719
|
-
items,
|
|
3720
3790
|
normalizeItems,
|
|
3721
3791
|
onItemsChange,
|
|
3722
3792
|
realtimeEnabled,
|