canvu-react 0.4.7 → 0.4.9
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/realtime.cjs +97 -10
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.js +97 -10
- package/dist/realtime.js.map +1 -1
- package/package.json +1 -1
package/dist/realtime.js
CHANGED
|
@@ -1996,6 +1996,7 @@ function createYjsBoardDoc() {
|
|
|
1996
1996
|
doc,
|
|
1997
1997
|
yItems,
|
|
1998
1998
|
lastServerConfirmedIds: /* @__PURE__ */ new Set(),
|
|
1999
|
+
lastServerConfirmedItemSerializations: /* @__PURE__ */ new Map(),
|
|
1999
2000
|
serverItemSeenAt: /* @__PURE__ */ new Map()
|
|
2000
2001
|
};
|
|
2001
2002
|
}
|
|
@@ -2052,6 +2053,10 @@ function valuesEqual(left, right) {
|
|
|
2052
2053
|
return false;
|
|
2053
2054
|
}
|
|
2054
2055
|
}
|
|
2056
|
+
function serializeItem(value) {
|
|
2057
|
+
const item = value instanceof Y.Map ? yMapToVectorItem(value) : value;
|
|
2058
|
+
return JSON.stringify(item);
|
|
2059
|
+
}
|
|
2055
2060
|
function updateYMapInPlace(yMap, next) {
|
|
2056
2061
|
const nextKeys = /* @__PURE__ */ new Set();
|
|
2057
2062
|
for (const [key, value] of Object.entries(next)) {
|
|
@@ -2121,6 +2126,14 @@ function applyServerSnapshotToYDoc(board, options) {
|
|
|
2121
2126
|
if (!id) continue;
|
|
2122
2127
|
const existing = indexYItemsById(board.yItems).get(id);
|
|
2123
2128
|
if (existing) {
|
|
2129
|
+
const currentSerialized = serializeItem(existing.yMap);
|
|
2130
|
+
const incomingSerialized = serializeItem(item);
|
|
2131
|
+
const confirmedSerialized = board.lastServerConfirmedItemSerializations.get(id);
|
|
2132
|
+
const hasPendingLocalChange = confirmedSerialized === void 0 ? currentSerialized !== incomingSerialized : currentSerialized !== confirmedSerialized && currentSerialized !== incomingSerialized;
|
|
2133
|
+
if (hasPendingLocalChange) {
|
|
2134
|
+
board.serverItemSeenAt.set(id, now);
|
|
2135
|
+
continue;
|
|
2136
|
+
}
|
|
2124
2137
|
updateYMapInPlace(existing.yMap, item);
|
|
2125
2138
|
board.serverItemSeenAt.set(id, now);
|
|
2126
2139
|
continue;
|
|
@@ -2131,9 +2144,13 @@ function applyServerSnapshotToYDoc(board, options) {
|
|
|
2131
2144
|
}
|
|
2132
2145
|
}, origin);
|
|
2133
2146
|
board.lastServerConfirmedIds = /* @__PURE__ */ new Set();
|
|
2147
|
+
board.lastServerConfirmedItemSerializations = /* @__PURE__ */ new Map();
|
|
2134
2148
|
for (const item of snapshotItems) {
|
|
2135
2149
|
const id = getItemId(item);
|
|
2136
|
-
if (id)
|
|
2150
|
+
if (id) {
|
|
2151
|
+
board.lastServerConfirmedIds.add(id);
|
|
2152
|
+
board.lastServerConfirmedItemSerializations.set(id, serializeItem(item));
|
|
2153
|
+
}
|
|
2137
2154
|
}
|
|
2138
2155
|
}
|
|
2139
2156
|
function replaceYDocWithSnapshot(board, options) {
|
|
@@ -2148,11 +2165,13 @@ function replaceYDocWithSnapshot(board, options) {
|
|
|
2148
2165
|
}
|
|
2149
2166
|
}, origin);
|
|
2150
2167
|
board.lastServerConfirmedIds = /* @__PURE__ */ new Set();
|
|
2168
|
+
board.lastServerConfirmedItemSerializations = /* @__PURE__ */ new Map();
|
|
2151
2169
|
board.serverItemSeenAt = /* @__PURE__ */ new Map();
|
|
2152
2170
|
for (const item of snapshotItems) {
|
|
2153
2171
|
const id = getItemId(item);
|
|
2154
2172
|
if (id) {
|
|
2155
2173
|
board.lastServerConfirmedIds.add(id);
|
|
2174
|
+
board.lastServerConfirmedItemSerializations.set(id, serializeItem(item));
|
|
2156
2175
|
board.serverItemSeenAt.set(id, now);
|
|
2157
2176
|
}
|
|
2158
2177
|
}
|
|
@@ -2164,7 +2183,8 @@ function getLocallyPendingItemIds(board) {
|
|
|
2164
2183
|
if (!yMap) continue;
|
|
2165
2184
|
const id = getItemId(yMap);
|
|
2166
2185
|
if (!id) continue;
|
|
2167
|
-
|
|
2186
|
+
const confirmedSerialized = board.lastServerConfirmedItemSerializations.get(id);
|
|
2187
|
+
if (!confirmedSerialized || serializeItem(yMap) !== confirmedSerialized) {
|
|
2168
2188
|
pending.add(id);
|
|
2169
2189
|
}
|
|
2170
2190
|
}
|
|
@@ -2353,6 +2373,30 @@ function prepareRealtimeItems(items) {
|
|
|
2353
2373
|
return null;
|
|
2354
2374
|
}
|
|
2355
2375
|
}
|
|
2376
|
+
function getRealtimeItemId(item) {
|
|
2377
|
+
const id = item.id;
|
|
2378
|
+
return typeof id === "string" ? id : null;
|
|
2379
|
+
}
|
|
2380
|
+
function serializeRealtimeItem(item) {
|
|
2381
|
+
try {
|
|
2382
|
+
return JSON.stringify(sanitizeRealtimeItem(item));
|
|
2383
|
+
} catch {
|
|
2384
|
+
return null;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
function resolvePendingDraftItemIds(board, items) {
|
|
2388
|
+
const pendingIds = /* @__PURE__ */ new Set();
|
|
2389
|
+
for (const item of items) {
|
|
2390
|
+
const id = getRealtimeItemId(item);
|
|
2391
|
+
if (!id) continue;
|
|
2392
|
+
const confirmedSerialized = board.lastServerConfirmedItemSerializations.get(id);
|
|
2393
|
+
const serialized = serializeRealtimeItem(item);
|
|
2394
|
+
if (!confirmedSerialized || !serialized || serialized !== confirmedSerialized) {
|
|
2395
|
+
pendingIds.add(id);
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
return pendingIds.size > 0 ? Array.from(pendingIds) : void 0;
|
|
2399
|
+
}
|
|
2356
2400
|
function useRealtimeSession(options) {
|
|
2357
2401
|
const {
|
|
2358
2402
|
url,
|
|
@@ -2543,7 +2587,8 @@ function useRealtimeSession(options) {
|
|
|
2543
2587
|
}
|
|
2544
2588
|
const board = boardRef.current;
|
|
2545
2589
|
const draft = localDraftRef.current;
|
|
2546
|
-
const
|
|
2590
|
+
const canEncodeYDocState = board && draft.yDocState == null && sameSerializedItems(readVectorItems(board.yItems), draft.items);
|
|
2591
|
+
const draftToWrite = canEncodeYDocState ? { ...draft, yDocState: encodeYDocState(board) } : draft;
|
|
2547
2592
|
writeRealtimeOfflineDraft(draftToWrite);
|
|
2548
2593
|
}, [clearDraftPersistSchedule, roomId]);
|
|
2549
2594
|
const scheduleDraftPersistence = useCallback(() => {
|
|
@@ -2683,13 +2728,26 @@ function useRealtimeSession(options) {
|
|
|
2683
2728
|
}, DOCUMENT_FLUSH_DEBOUNCE_MS);
|
|
2684
2729
|
}, DOCUMENT_FLUSH_DEBOUNCE_MS);
|
|
2685
2730
|
}, [clearDocumentFlushSchedule, flushQueuedDocument]);
|
|
2686
|
-
const queueDocumentSend = useCallback(
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2731
|
+
const queueDocumentSend = useCallback(
|
|
2732
|
+
(items) => {
|
|
2733
|
+
pendingLocalItemsRef.current = items;
|
|
2734
|
+
queuedDirtyRef.current = true;
|
|
2735
|
+
setHasPendingDocumentSync(true);
|
|
2736
|
+
setHasLocalOfflineDraft(true);
|
|
2737
|
+
const board = boardRef.current;
|
|
2738
|
+
const draftItems = sanitizeRealtimeItems(items);
|
|
2739
|
+
setLocalDraftRef.current({
|
|
2740
|
+
roomId,
|
|
2741
|
+
baseRevision: currentRevisionRef.current,
|
|
2742
|
+
items: draftItems,
|
|
2743
|
+
updatedAt: nowMs(),
|
|
2744
|
+
pendingIds: board ? resolvePendingDraftItemIds(board, draftItems) : void 0
|
|
2745
|
+
});
|
|
2746
|
+
scheduleDraftPersistenceRef.current?.();
|
|
2747
|
+
scheduleDocumentFlushRef.current();
|
|
2748
|
+
},
|
|
2749
|
+
[roomId]
|
|
2750
|
+
);
|
|
2693
2751
|
const applyDraftSnapshot = useCallback(
|
|
2694
2752
|
(draft, options2) => {
|
|
2695
2753
|
const board = boardRef.current;
|
|
@@ -2704,6 +2762,7 @@ function useRealtimeSession(options) {
|
|
|
2704
2762
|
restoredFromBinary = decodeYDocState(board, draft.yDocState);
|
|
2705
2763
|
if (restoredFromBinary) {
|
|
2706
2764
|
const allIds = /* @__PURE__ */ new Set();
|
|
2765
|
+
const allItems = readVectorItems(board.yItems);
|
|
2707
2766
|
for (let i = 0; i < board.yItems.length; i++) {
|
|
2708
2767
|
const yMap = board.yItems.get(i);
|
|
2709
2768
|
if (!yMap) continue;
|
|
@@ -2712,9 +2771,17 @@ function useRealtimeSession(options) {
|
|
|
2712
2771
|
}
|
|
2713
2772
|
const pendingIds = new Set(draft.pendingIds ?? []);
|
|
2714
2773
|
board.lastServerConfirmedIds = /* @__PURE__ */ new Set();
|
|
2774
|
+
board.lastServerConfirmedItemSerializations = /* @__PURE__ */ new Map();
|
|
2715
2775
|
for (const id of allIds) {
|
|
2716
2776
|
if (!pendingIds.has(id)) {
|
|
2717
2777
|
board.lastServerConfirmedIds.add(id);
|
|
2778
|
+
const item = allItems.find((candidate) => candidate.id === id);
|
|
2779
|
+
if (item) {
|
|
2780
|
+
board.lastServerConfirmedItemSerializations.set(
|
|
2781
|
+
id,
|
|
2782
|
+
JSON.stringify(item)
|
|
2783
|
+
);
|
|
2784
|
+
}
|
|
2718
2785
|
}
|
|
2719
2786
|
}
|
|
2720
2787
|
}
|
|
@@ -2725,6 +2792,7 @@ function useRealtimeSession(options) {
|
|
|
2725
2792
|
origin: ORIGIN_BOOTSTRAP
|
|
2726
2793
|
});
|
|
2727
2794
|
board.lastServerConfirmedIds = /* @__PURE__ */ new Set();
|
|
2795
|
+
board.lastServerConfirmedItemSerializations = /* @__PURE__ */ new Map();
|
|
2728
2796
|
}
|
|
2729
2797
|
}
|
|
2730
2798
|
const items = board ? readVectorItems(board.yItems) : draft.items;
|
|
@@ -2843,6 +2911,25 @@ function useRealtimeSession(options) {
|
|
|
2843
2911
|
setLocalDraftRef.current = setLocalDraft;
|
|
2844
2912
|
const scheduleDraftPersistenceRef = useRef(scheduleDraftPersistence);
|
|
2845
2913
|
scheduleDraftPersistenceRef.current = scheduleDraftPersistence;
|
|
2914
|
+
const persistLocalDraftRef = useRef(persistLocalDraft);
|
|
2915
|
+
persistLocalDraftRef.current = persistLocalDraft;
|
|
2916
|
+
useEffect(() => {
|
|
2917
|
+
const persistDraft = () => {
|
|
2918
|
+
persistLocalDraftRef.current();
|
|
2919
|
+
};
|
|
2920
|
+
const handleVisibilityChange = () => {
|
|
2921
|
+
if (window.document.visibilityState === "hidden") persistDraft();
|
|
2922
|
+
};
|
|
2923
|
+
window.addEventListener("pagehide", persistDraft);
|
|
2924
|
+
window.document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
2925
|
+
return () => {
|
|
2926
|
+
window.removeEventListener("pagehide", persistDraft);
|
|
2927
|
+
window.document.removeEventListener(
|
|
2928
|
+
"visibilitychange",
|
|
2929
|
+
handleVisibilityChange
|
|
2930
|
+
);
|
|
2931
|
+
};
|
|
2932
|
+
}, []);
|
|
2846
2933
|
useEffect(() => {
|
|
2847
2934
|
if (boardRef.current) {
|
|
2848
2935
|
boardRef.current.doc.destroy();
|