canvu-react 0.4.43 → 0.4.45
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 +51 -4
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +51 -4
- 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.cjs
CHANGED
|
@@ -2260,6 +2260,7 @@ var ORIGIN_BOOTSTRAP = /* @__PURE__ */ Symbol("canvu/realtime/bootstrap");
|
|
|
2260
2260
|
var DRAFT_STORAGE_PREFIX = "canvu-realtime-draft:";
|
|
2261
2261
|
var DOCUMENT_FLUSH_DEBOUNCE_MS = 120;
|
|
2262
2262
|
var DRAFT_PERSIST_DEBOUNCE_MS = 420;
|
|
2263
|
+
var CONNECTION_MESSAGE_STATE_UPDATE_INTERVAL_MS = 1e3;
|
|
2263
2264
|
function requestWindowIdleCallback(callback, timeout) {
|
|
2264
2265
|
if (typeof window.requestIdleCallback === "function") {
|
|
2265
2266
|
return window.requestIdleCallback(callback, { timeout });
|
|
@@ -2337,6 +2338,9 @@ function sameSerializedItems(left, right) {
|
|
|
2337
2338
|
function nowMs() {
|
|
2338
2339
|
return Date.now();
|
|
2339
2340
|
}
|
|
2341
|
+
function shouldUpdateRealtimeConnectionMessageState(input) {
|
|
2342
|
+
return input.lastStateUpdateAt == null || input.receivedAt - input.lastStateUpdateAt >= CONNECTION_MESSAGE_STATE_UPDATE_INTERVAL_MS;
|
|
2343
|
+
}
|
|
2340
2344
|
function hasDurableDocumentPersistence(snapshot) {
|
|
2341
2345
|
return snapshot.persistedRevision == null || snapshot.persistedRevision >= snapshot.revision;
|
|
2342
2346
|
}
|
|
@@ -2484,6 +2488,7 @@ function useRealtimeSession(options) {
|
|
|
2484
2488
|
const connectionStateRef = react.useRef(
|
|
2485
2489
|
enabled ? "connecting" : "offline"
|
|
2486
2490
|
);
|
|
2491
|
+
const lastConnectionMessageStateUpdateAtRef = react.useRef(null);
|
|
2487
2492
|
const localDraftRef = react.useRef(null);
|
|
2488
2493
|
const conflictRef = react.useRef(null);
|
|
2489
2494
|
const onErrorRef = react.useRef(onError);
|
|
@@ -3036,6 +3041,7 @@ function useRealtimeSession(options) {
|
|
|
3036
3041
|
react.useEffect(() => {
|
|
3037
3042
|
if (!enabled) {
|
|
3038
3043
|
manualDisconnectRef.current = true;
|
|
3044
|
+
lastConnectionMessageStateUpdateAtRef.current = null;
|
|
3039
3045
|
clearReconnectTimer();
|
|
3040
3046
|
clearHeartbeatTimer();
|
|
3041
3047
|
clearConnectTimeout();
|
|
@@ -3080,6 +3086,7 @@ function useRealtimeSession(options) {
|
|
|
3080
3086
|
return;
|
|
3081
3087
|
}
|
|
3082
3088
|
let disposed = false;
|
|
3089
|
+
lastConnectionMessageStateUpdateAtRef.current = null;
|
|
3083
3090
|
updateConnectionRef.current((prev) => ({
|
|
3084
3091
|
...prev,
|
|
3085
3092
|
state: retryCountRef.current > 0 ? "reconnecting" : "connecting",
|
|
@@ -3131,10 +3138,17 @@ function useRealtimeSession(options) {
|
|
|
3131
3138
|
}
|
|
3132
3139
|
const parsed = parseRealtimeServerMessage(payload);
|
|
3133
3140
|
if (!parsed) return;
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3141
|
+
const receivedAt = nowMs();
|
|
3142
|
+
if (shouldUpdateRealtimeConnectionMessageState({
|
|
3143
|
+
lastStateUpdateAt: lastConnectionMessageStateUpdateAtRef.current,
|
|
3144
|
+
receivedAt
|
|
3145
|
+
})) {
|
|
3146
|
+
lastConnectionMessageStateUpdateAtRef.current = receivedAt;
|
|
3147
|
+
updateConnectionRef.current((prev) => ({
|
|
3148
|
+
...prev,
|
|
3149
|
+
lastMessageAt: receivedAt
|
|
3150
|
+
}));
|
|
3151
|
+
}
|
|
3138
3152
|
if (parsed.type === "session:welcome") {
|
|
3139
3153
|
retryCountRef.current = 0;
|
|
3140
3154
|
updateConnectionRef.current((prev) => ({
|
|
@@ -3143,7 +3157,7 @@ function useRealtimeSession(options) {
|
|
|
3143
3157
|
connected: true,
|
|
3144
3158
|
clientId: parsed.clientId,
|
|
3145
3159
|
retryCount: 0,
|
|
3146
|
-
lastConnectedAt:
|
|
3160
|
+
lastConnectedAt: receivedAt,
|
|
3147
3161
|
lastError: null
|
|
3148
3162
|
}));
|
|
3149
3163
|
applyPeersRef.current(parsed.peers);
|
|
@@ -3631,6 +3645,12 @@ function realtimeSessionPlugin(options) {
|
|
|
3631
3645
|
render: () => /* @__PURE__ */ jsxRuntime.jsx(RealtimeSessionPanel, { ...options })
|
|
3632
3646
|
};
|
|
3633
3647
|
}
|
|
3648
|
+
var CLIENT_ONLY_IMAGE_KEYS2 = /* @__PURE__ */ new Set([
|
|
3649
|
+
"imageBlobId",
|
|
3650
|
+
"imageThumbnailBlobId",
|
|
3651
|
+
"imageRasterHref",
|
|
3652
|
+
"imageThumbnailHref"
|
|
3653
|
+
]);
|
|
3634
3654
|
function getSceneItemId(item) {
|
|
3635
3655
|
const id = item.id;
|
|
3636
3656
|
return typeof id === "string" ? id : null;
|
|
@@ -3647,6 +3667,43 @@ function hasMissingLocalItems(localItems, incomingItems) {
|
|
|
3647
3667
|
}
|
|
3648
3668
|
return false;
|
|
3649
3669
|
}
|
|
3670
|
+
function getComparableRealtimeItem(item) {
|
|
3671
|
+
const comparable = { ...item };
|
|
3672
|
+
if (item.toolKind === "image") {
|
|
3673
|
+
for (const key of CLIENT_ONLY_IMAGE_KEYS2) {
|
|
3674
|
+
delete comparable[key];
|
|
3675
|
+
}
|
|
3676
|
+
comparable.childrenSvg = "";
|
|
3677
|
+
}
|
|
3678
|
+
return comparable;
|
|
3679
|
+
}
|
|
3680
|
+
function serializeComparableRealtimeItem(item) {
|
|
3681
|
+
return JSON.stringify(getComparableRealtimeItem(item));
|
|
3682
|
+
}
|
|
3683
|
+
function hasChangedLocalItems(localItems, incomingItems) {
|
|
3684
|
+
const incomingItemsById = /* @__PURE__ */ new Map();
|
|
3685
|
+
for (const incomingItem of incomingItems) {
|
|
3686
|
+
const id = getSceneItemId(incomingItem);
|
|
3687
|
+
if (id) incomingItemsById.set(id, incomingItem);
|
|
3688
|
+
}
|
|
3689
|
+
for (const localItem of localItems) {
|
|
3690
|
+
const id = getSceneItemId(localItem);
|
|
3691
|
+
const incomingItem = id ? incomingItemsById.get(id) : null;
|
|
3692
|
+
if (!incomingItem) continue;
|
|
3693
|
+
if (serializeComparableRealtimeItem(localItem) !== serializeComparableRealtimeItem(incomingItem)) {
|
|
3694
|
+
return true;
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
return false;
|
|
3698
|
+
}
|
|
3699
|
+
function shouldPreserveLocalRealtimeItems({
|
|
3700
|
+
localItems,
|
|
3701
|
+
incomingItems,
|
|
3702
|
+
hasPendingLocalChanges
|
|
3703
|
+
}) {
|
|
3704
|
+
if (!hasPendingLocalChanges) return false;
|
|
3705
|
+
return hasMissingLocalItems(localItems, incomingItems) || hasChangedLocalItems(localItems, incomingItems);
|
|
3706
|
+
}
|
|
3650
3707
|
function useRealtimeCanvasDocument(options) {
|
|
3651
3708
|
const {
|
|
3652
3709
|
session,
|
|
@@ -3659,6 +3716,8 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3659
3716
|
const [loading, setLoading] = react.useState(false);
|
|
3660
3717
|
const lastAppliedRevisionRef = react.useRef(null);
|
|
3661
3718
|
const inFlightRevisionRef = react.useRef(null);
|
|
3719
|
+
const latestItemsRef = react.useRef(items);
|
|
3720
|
+
const hasLocalChangeInFlightRef = react.useRef(false);
|
|
3662
3721
|
const hasEverPropagatedItemsRef = react.useRef(false);
|
|
3663
3722
|
const realtimeEnabled = enabled && session != null;
|
|
3664
3723
|
const documentRevision = session?.document?.revision ?? null;
|
|
@@ -3681,6 +3740,7 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3681
3740
|
onItemsChange?.(normalizeItems ? normalizeItems(nextItems) : nextItems);
|
|
3682
3741
|
return;
|
|
3683
3742
|
}
|
|
3743
|
+
hasLocalChangeInFlightRef.current = true;
|
|
3684
3744
|
const normalizedItems = normalizeItems ? normalizeItems(nextItems) : nextItems;
|
|
3685
3745
|
onItemsChange?.(normalizedItems);
|
|
3686
3746
|
session?.remoteAdapter.send?.(normalizedItems);
|
|
@@ -3688,10 +3748,16 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3688
3748
|
[enabled, normalizeItems, onItemsChange, session]
|
|
3689
3749
|
);
|
|
3690
3750
|
react.useEffect(() => {
|
|
3751
|
+
latestItemsRef.current = items;
|
|
3691
3752
|
if (items.length > 0) {
|
|
3692
3753
|
hasEverPropagatedItemsRef.current = true;
|
|
3693
3754
|
}
|
|
3694
|
-
}, [items
|
|
3755
|
+
}, [items]);
|
|
3756
|
+
react.useEffect(() => {
|
|
3757
|
+
if (!hasLocalOfflineDraft && !hasPendingDocumentSync) {
|
|
3758
|
+
hasLocalChangeInFlightRef.current = false;
|
|
3759
|
+
}
|
|
3760
|
+
}, [hasLocalOfflineDraft, hasPendingDocumentSync]);
|
|
3695
3761
|
react.useEffect(() => {
|
|
3696
3762
|
if (!realtimeEnabled || !onItemsChange || !session?.document) return;
|
|
3697
3763
|
if (documentUpdatedByClientId === connectionClientId) return;
|
|
@@ -3705,17 +3771,22 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3705
3771
|
if (cancelled) return;
|
|
3706
3772
|
if (inFlightRevisionRef.current !== documentRevision) return;
|
|
3707
3773
|
lastAppliedRevisionRef.current = documentRevision;
|
|
3708
|
-
const
|
|
3709
|
-
const
|
|
3774
|
+
const localItems = latestItemsRef.current;
|
|
3775
|
+
const hasLocalItems = localItems.length > 0;
|
|
3776
|
+
const hasPendingLocalChanges = hasLocalOfflineDraft || hasPendingDocumentSync || hasLocalChangeInFlightRef.current;
|
|
3710
3777
|
if (resolvedItems.length === 0 && (hasEverPropagatedItemsRef.current || hasLocalItems || hasPendingLocalChanges)) {
|
|
3711
3778
|
if (hasLocalItems) {
|
|
3712
|
-
const normalizedLocalItems = normalizeItems ? normalizeItems(
|
|
3779
|
+
const normalizedLocalItems = normalizeItems ? normalizeItems(localItems) : [...localItems];
|
|
3713
3780
|
session.remoteAdapter.send?.(normalizedLocalItems);
|
|
3714
3781
|
}
|
|
3715
3782
|
return;
|
|
3716
3783
|
}
|
|
3717
|
-
if (
|
|
3718
|
-
|
|
3784
|
+
if (shouldPreserveLocalRealtimeItems({
|
|
3785
|
+
localItems,
|
|
3786
|
+
incomingItems: resolvedItems,
|
|
3787
|
+
hasPendingLocalChanges
|
|
3788
|
+
})) {
|
|
3789
|
+
const normalizedLocalItems = normalizeItems ? normalizeItems(localItems) : [...localItems];
|
|
3719
3790
|
session.remoteAdapter.send?.(normalizedLocalItems);
|
|
3720
3791
|
return;
|
|
3721
3792
|
}
|
|
@@ -3741,7 +3812,6 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3741
3812
|
documentUpdatedByClientId,
|
|
3742
3813
|
hasLocalOfflineDraft,
|
|
3743
3814
|
hasPendingDocumentSync,
|
|
3744
|
-
items,
|
|
3745
3815
|
normalizeItems,
|
|
3746
3816
|
onItemsChange,
|
|
3747
3817
|
realtimeEnabled,
|