y-mxgraph 0.8.6 → 0.9.1
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/binding/consistency.d.ts +56 -0
- package/binding/consistency.d.ts.map +1 -0
- package/binding/index.d.ts +38 -0
- package/binding/index.d.ts.map +1 -1
- package/binding/patch.d.ts +4 -2
- package/binding/patch.d.ts.map +1 -1
- package/iframe-bridge/provider.cjs +63 -6
- package/iframe-bridge/provider.cjs.map +1 -1
- package/iframe-bridge/provider.js +61 -4
- package/iframe-bridge/provider.js.map +1 -1
- package/iframe-bridge/server.cjs +86 -16
- package/iframe-bridge/server.cjs.map +1 -1
- package/iframe-bridge/server.js +78 -8
- package/iframe-bridge/server.js.map +1 -1
- package/{index-BhW4J2Zt.js → index-CN7tFgEG.js} +26 -4
- package/index-CN7tFgEG.js.map +1 -0
- package/{index-D3Hk2QcW.cjs → index-CqD1uLD3.cjs} +24 -2
- package/index-CqD1uLD3.cjs.map +1 -0
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/models/mxGraphModel.d.ts.map +1 -1
- package/origin-C_FHB48F.cjs +6 -0
- package/origin-C_FHB48F.cjs.map +1 -0
- package/origin-Doo2uLkM.js +7 -0
- package/origin-Doo2uLkM.js.map +1 -0
- package/package.json +1 -1
- package/transform.cjs +1 -1
- package/transform.js +1 -1
- package/y-mxgraph.cjs +366 -143
- package/y-mxgraph.cjs.map +1 -1
- package/y-mxgraph.js +366 -143
- package/y-mxgraph.js.map +1 -1
- package/index-BhW4J2Zt.js.map +0 -1
- package/index-D3Hk2QcW.cjs.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Y from "yjs";
|
|
2
2
|
import { applyAwarenessUpdate } from "y-protocols/awareness";
|
|
3
|
+
import { B as BASELINE_ORIGIN, I as IFRAME_ORIGIN } from "../origin-Doo2uLkM.js";
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __defProps = Object.defineProperties;
|
|
5
6
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
@@ -126,7 +127,7 @@ function parseAwarenessPayload(data) {
|
|
|
126
127
|
return result;
|
|
127
128
|
}
|
|
128
129
|
function createIframeBridgeProvider(ydoc, options) {
|
|
129
|
-
const { awareness: externalAwareness, debug = false } = options != null ? options : {};
|
|
130
|
+
const { awareness: externalAwareness, debug = false, consistencyCheckInterval = 0 } = options != null ? options : {};
|
|
130
131
|
let applyingParentUpdate = false;
|
|
131
132
|
let serverClientId = null;
|
|
132
133
|
let currentCleanup = null;
|
|
@@ -139,6 +140,25 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
139
140
|
let seq = 0;
|
|
140
141
|
const unackedYdocUpdates = /* @__PURE__ */ new Map();
|
|
141
142
|
let initRetryTimer = null;
|
|
143
|
+
let consistencyTimer = null;
|
|
144
|
+
let pendingCheckTimer = null;
|
|
145
|
+
const { pendingTimeoutMs, onPendingTimeout } = options != null ? options : {};
|
|
146
|
+
function schedulePendingCheck() {
|
|
147
|
+
if (pendingCheckTimer || !pendingTimeoutMs || !onPendingTimeout) return;
|
|
148
|
+
pendingCheckTimer = setTimeout(() => {
|
|
149
|
+
pendingCheckTimer = null;
|
|
150
|
+
const now = Date.now();
|
|
151
|
+
const unackedCount = unackedYdocUpdates.size;
|
|
152
|
+
const pendingCount = pendingYdocUpdates.length;
|
|
153
|
+
if (unackedCount > 0 || pendingCount > 0) {
|
|
154
|
+
const oldest = unackedCount > 0 ? Math.min(...Array.from(unackedYdocUpdates.values()).map((v) => v.sentAt)) : now;
|
|
155
|
+
onPendingTimeout({
|
|
156
|
+
pendingCount: unackedCount + pendingCount,
|
|
157
|
+
oldestMs: now - oldest
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}, pendingTimeoutMs);
|
|
161
|
+
}
|
|
142
162
|
let serverSupportsAck = false;
|
|
143
163
|
let legacyMode = false;
|
|
144
164
|
const connectListeners = /* @__PURE__ */ new Set();
|
|
@@ -250,7 +270,7 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
250
270
|
const seqNum = ++seq;
|
|
251
271
|
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
252
272
|
window.parent.postMessage(message, "*");
|
|
253
|
-
unackedYdocUpdates.set(seqNum, { update, isBaseline });
|
|
273
|
+
unackedYdocUpdates.set(seqNum, { update, isBaseline, sentAt: Date.now() });
|
|
254
274
|
}
|
|
255
275
|
}
|
|
256
276
|
if (!legacyMode) {
|
|
@@ -260,6 +280,7 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
260
280
|
}
|
|
261
281
|
}
|
|
262
282
|
connectListeners.forEach((fn) => fn());
|
|
283
|
+
startConsistencyCheck();
|
|
263
284
|
} else {
|
|
264
285
|
lastLocalAwarenessSnapshot = null;
|
|
265
286
|
if (!legacyMode) {
|
|
@@ -293,6 +314,16 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
293
314
|
}
|
|
294
315
|
}, 1e3);
|
|
295
316
|
}
|
|
317
|
+
function startConsistencyCheck() {
|
|
318
|
+
if (consistencyTimer) clearInterval(consistencyTimer);
|
|
319
|
+
if (consistencyCheckInterval <= 0) return;
|
|
320
|
+
consistencyTimer = setInterval(() => {
|
|
321
|
+
if (!connected) return;
|
|
322
|
+
const sv = Y.encodeStateVector(ydoc);
|
|
323
|
+
parentPostMessage({ type: "consistency-check", stateVector: Array.from(sv) });
|
|
324
|
+
log("consistency-check sent");
|
|
325
|
+
}, consistencyCheckInterval);
|
|
326
|
+
}
|
|
296
327
|
const onYdocUpdate = (update, origin) => {
|
|
297
328
|
if (applyingParentUpdate) return;
|
|
298
329
|
const isBaseline = origin === null || origin === void 0;
|
|
@@ -303,6 +334,7 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
303
334
|
console.warn("[iframe-bridge] queue full, forcing full sync on reconnect");
|
|
304
335
|
}
|
|
305
336
|
pendingYdocUpdates.push({ update, isBaseline });
|
|
337
|
+
schedulePendingCheck();
|
|
306
338
|
return;
|
|
307
339
|
}
|
|
308
340
|
if (legacyMode) {
|
|
@@ -314,7 +346,8 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
314
346
|
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
315
347
|
logMessage("send", "ydoc-update", message);
|
|
316
348
|
window.parent.postMessage(message, "*");
|
|
317
|
-
unackedYdocUpdates.set(seqNum, { update, isBaseline });
|
|
349
|
+
unackedYdocUpdates.set(seqNum, { update, isBaseline, sentAt: Date.now() });
|
|
350
|
+
schedulePendingCheck();
|
|
318
351
|
}
|
|
319
352
|
};
|
|
320
353
|
const onAwarenessUpdate = ({
|
|
@@ -399,7 +432,9 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
399
432
|
}
|
|
400
433
|
if (type === "ydoc-sync" || type === "ydoc-update") {
|
|
401
434
|
applyingParentUpdate = true;
|
|
402
|
-
|
|
435
|
+
const isBaseline = event.data && typeof event.data === "object" && event.data.isBaseline ? true : false;
|
|
436
|
+
const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;
|
|
437
|
+
Y.applyUpdate(ydoc, new Uint8Array(payload), applyOrigin);
|
|
403
438
|
applyingParentUpdate = false;
|
|
404
439
|
if (type === "ydoc-sync" && event.data.protocolVersion != null) {
|
|
405
440
|
if (event.data.protocolVersion >= 2 && !serverSupportsAck) {
|
|
@@ -484,6 +519,10 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
484
519
|
} else if (type === "disconnect") {
|
|
485
520
|
setConnected(false);
|
|
486
521
|
startInitRetry();
|
|
522
|
+
} else if (type === "force-sync") {
|
|
523
|
+
log("received force-sync from server");
|
|
524
|
+
const fullState = Y.encodeStateAsUpdate(ydoc);
|
|
525
|
+
parentPostMessage({ type: "ydoc-pending-updates", payload: [{ update: Array.from(fullState), isBaseline: false }] });
|
|
487
526
|
}
|
|
488
527
|
};
|
|
489
528
|
ydoc.on("update", onYdocUpdate);
|
|
@@ -655,7 +694,21 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
655
694
|
currentCleanup = cleanup;
|
|
656
695
|
return cleanup;
|
|
657
696
|
},
|
|
697
|
+
forceSyncToServer() {
|
|
698
|
+
if (!connected) return;
|
|
699
|
+
const fullState = Y.encodeStateAsUpdate(ydoc);
|
|
700
|
+
window.parent.postMessage({ type: "ydoc-pending-updates", payload: [{ update: Array.from(fullState), isBaseline: false }] }, "*");
|
|
701
|
+
unackedYdocUpdates.clear();
|
|
702
|
+
if (pendingCheckTimer) {
|
|
703
|
+
clearTimeout(pendingCheckTimer);
|
|
704
|
+
pendingCheckTimer = null;
|
|
705
|
+
}
|
|
706
|
+
},
|
|
658
707
|
destroy: () => {
|
|
708
|
+
if (pendingCheckTimer) {
|
|
709
|
+
clearTimeout(pendingCheckTimer);
|
|
710
|
+
pendingCheckTimer = null;
|
|
711
|
+
}
|
|
659
712
|
while (pendingYdocUpdates.length > 0) {
|
|
660
713
|
const { update, isBaseline } = pendingYdocUpdates.shift();
|
|
661
714
|
window.parent.postMessage({ type: "ydoc-update", payload: Array.from(update), isBaseline }, "*");
|
|
@@ -670,6 +723,10 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
670
723
|
clearInterval(initRetryTimer);
|
|
671
724
|
initRetryTimer = null;
|
|
672
725
|
}
|
|
726
|
+
if (consistencyTimer) {
|
|
727
|
+
clearInterval(consistencyTimer);
|
|
728
|
+
consistencyTimer = null;
|
|
729
|
+
}
|
|
673
730
|
connectListeners.clear();
|
|
674
731
|
disconnectListeners.clear();
|
|
675
732
|
if (currentCleanup) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sources":["../../../iframe-bridge/src/provider.ts"],"sourcesContent":["import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n} from \"y-protocols/awareness\";\nconst IFRAME_BRIDGE_STATE_KEYS = new Set([\"cursor\", \"selection\"]);\n\nfunction isIframeBridgeStateKey(key: string): boolean {\n return IFRAME_BRIDGE_STATE_KEYS.has(key);\n}\n\nfunction getAwarenessStateFieldChanges(\n prev: Record<string, unknown> | null,\n next: Record<string, unknown> | null,\n): Array<{ key: string; value: unknown }> {\n const keys = new Set([\n ...Object.keys(prev ?? {}),\n ...Object.keys(next ?? {}),\n ]);\n const changes: Array<{ key: string; value: unknown }> = [];\n for (const key of keys) {\n const prevValue = prev?.[key];\n const nextValue = next?.[key];\n if (JSON.stringify(prevValue) !== JSON.stringify(nextValue)) {\n changes.push({ key, value: nextValue });\n }\n }\n return changes;\n}\n\n/**\n * Awareness-like 接口,只需要支持本地状态管理。\n * 用于 iframe-bridge provider 不需要与父页面同步 awareness 的场景。\n */\nexport interface AwarenessLike {\n readonly clientID: number;\n readonly states: Map<number, Record<string, unknown>>;\n getStates(): Map<number, Record<string, unknown>>;\n getLocalState(): Record<string, unknown> | null;\n setLocalState(state: Record<string, unknown> | null): void;\n setLocalStateField(field: string, value: unknown): void;\n on(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void): void;\n off(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void): void;\n}\n\ntype ListenerFn = (sender: unknown, evt?: unknown) => void;\n\nfunction createMxEventObject(name: string, props?: Record<string, unknown>) {\n const _props = props || {};\n return {\n name,\n getName: () => name,\n getProperty: (k: string) => _props[k],\n };\n}\n\ntype MxLike = Record<string, unknown> & {\n eventListeners: Array<string | ListenerFn>;\n history: unknown[];\n indexOfNextAdd: number;\n addListener(name: string, fn: ListenerFn): void;\n fireEvent(evt: unknown): void;\n canUndo(): boolean;\n canRedo(): boolean;\n undo(): void;\n redo(): void;\n undoableEditHappened(_edit: unknown): void;\n};\n\nexport interface DrawioEditor {\n undoManager?: {\n eventListeners?: unknown[];\n [key: string]: unknown;\n };\n undoListener?: (...args: unknown[]) => void;\n}\n\nexport interface DrawioFile {\n getUi(): { editor: DrawioEditor };\n}\n\nexport interface IframeBridgeProviderOptions {\n awareness?: Awareness;\n debug?: boolean;\n}\n\nexport interface IframeBridgeProvider {\n serverClientId: number | null;\n connected: boolean;\n awareness: Awareness;\n onConnect: (fn: () => void) => () => void;\n onDisconnect: (fn: () => void) => () => void;\n on: (event: \"connect\" | \"disconnect\", fn: () => void) => () => void;\n setLocalFields: (fields: Record<string, unknown>) => void;\n takeoverUndoManager: (file: DrawioFile) => () => void;\n destroy: () => void;\n}\n\nfunction readVarUint(data: Uint8Array, pos: number): [number, number] {\n let result = 0;\n let shift = 0;\n let byte: number;\n do {\n byte = data[pos++];\n result |= (byte & 0x7f) << shift;\n shift += 7;\n } while (byte >= 0x80);\n return [result >>> 0, pos];\n}\n\nfunction writeVarUint(value: number): number[] {\n const bytes: number[] = [];\n while (value > 0x7f) {\n bytes.push((value & 0x7f) | 0x80);\n value >>>= 7;\n }\n bytes.push(value);\n return bytes;\n}\n\nfunction readVarString(data: Uint8Array, pos: number): [string, number] {\n const [len, pos2] = readVarUint(data, pos);\n const str = new TextDecoder().decode(data.subarray(pos2, pos2 + len));\n return [str, pos2 + len];\n}\n\nfunction writeVarString(str: string): number[] {\n const encoded = new TextEncoder().encode(str);\n return [...writeVarUint(encoded.length), ...encoded];\n}\n\nfunction remapClientIdInUpdate(\n update: Uint8Array,\n fromId: number,\n toId: number,\n): Uint8Array {\n const entries: Array<{ clientID: number; clock: number; state: string }> = [];\n const seenClientIds = new Set<number>();\n let pos = 0;\n\n const [count, pos2] = readVarUint(update, pos);\n pos = pos2;\n\n for (let i = 0; i < count; i++) {\n const [clientID, pos3] = readVarUint(update, pos);\n pos = pos3;\n const [clock, pos4] = readVarUint(update, pos);\n pos = pos4;\n const [state, pos5] = readVarString(update, pos);\n pos = pos5;\n\n const mappedId = clientID === fromId ? toId : clientID;\n if (seenClientIds.has(mappedId)) {\n continue;\n }\n\n seenClientIds.add(mappedId);\n entries.push({ clientID: mappedId, clock, state });\n }\n\n const result: number[] = [];\n result.push(...writeVarUint(entries.length));\n for (const entry of entries) {\n result.push(...writeVarUint(entry.clientID));\n result.push(...writeVarUint(entry.clock));\n result.push(...writeVarString(entry.state));\n }\n\n return new Uint8Array(result);\n}\n\nfunction parseAwarenessPayload(data: Uint8Array): Map<number, Record<string, unknown>> {\n const result = new Map<number, Record<string, unknown>>();\n let pos = 0;\n const [count, pos2] = readVarUint(data, pos);\n pos = pos2;\n\n for (let i = 0; i < count; i++) {\n const [clientID, pos3] = readVarUint(data, pos);\n pos = pos3;\n const [, pos4] = readVarUint(data, pos);\n pos = pos4;\n const [stateStr, pos5] = readVarString(data, pos);\n pos = pos5;\n\n if (stateStr) {\n try {\n result.set(clientID, JSON.parse(stateStr));\n } catch {\n // no-op\n }\n }\n }\n return result;\n}\n\nexport function createIframeBridgeProvider(\n ydoc: Y.Doc,\n options?: IframeBridgeProviderOptions,\n): IframeBridgeProvider {\n const { awareness: externalAwareness, debug = false } = options ?? {};\n let applyingParentUpdate = false;\n let serverClientId: number | null = null;\n let currentCleanup: (() => void) | null = null;\n let currentMxLike: MxLike | null = null;\n let pendingUndoState: {\n undoStackSize?: number;\n redoStackSize?: number;\n } | null = null;\n let connected = false;\n let forceFullSync = false;\n const MAX_QUEUE_SIZE = 1000;\n const pendingYdocUpdates: Array<{update: Uint8Array, isBaseline: boolean}> = [];\n let seq = 0;\n const unackedYdocUpdates = new Map<number, { update: Uint8Array; isBaseline: boolean }>();\n let initRetryTimer: ReturnType<typeof setInterval> | null = null;\n \n // Legacy mode detection: old servers don't send protocolVersion in pong\n let serverSupportsAck = false;\n let legacyMode = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let lastLocalAwarenessSnapshot: Record<string, unknown> | null = null;\n\n const log = debug\n ? (...args: unknown[]) => console.log(\"[iframe-bridge provider]\", ...args)\n : () => undefined;\n\n const useExternalAwareness = !!externalAwareness;\n let awareness: Awareness | AwarenessLike;\n const localStates = new Map<number, Record<string, unknown>>();\n const localClientId = Math.floor(Math.random() * 2147483647) + 1;\n const updateHandlers = new Set<(update: { added: number[]; updated: number[]; removed: number[] }) => void>();\n\n function createAwarenessLike(): AwarenessLike {\n function getEffectiveClientId() {\n return serverClientId ?? localClientId;\n }\n\n return {\n get clientID() {\n return getEffectiveClientId();\n },\n get states() {\n return localStates;\n },\n getStates() {\n return new Map(localStates);\n },\n getLocalState() {\n return localStates.get(getEffectiveClientId()) ?? null;\n },\n setLocalState(state: Record<string, unknown> | null) {\n const id = getEffectiveClientId();\n if (state === null) {\n localStates.delete(id);\n const update = { added: [], updated: [], removed: [id] };\n updateHandlers.forEach(handler => handler(update));\n } else {\n const existed = localStates.has(id);\n localStates.set(id, state);\n const update = { added: !existed ? [id] : [], updated: [id], removed: [] };\n updateHandlers.forEach(handler => handler(update));\n }\n },\n setLocalStateField(field: string, value: unknown) {\n const id = getEffectiveClientId();\n const current = localStates.get(id) || {};\n const newState = { ...current, [field]: value };\n localStates.set(id, newState);\n postSetLocalStateToParent(field, value);\n const update = { added: [], updated: [id], removed: [] };\n updateHandlers.forEach(handler => handler(update));\n },\n on(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void) {\n if (event === \"update\") {\n updateHandlers.add(handler);\n }\n },\n off(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void) {\n if (event === \"update\") {\n updateHandlers.delete(handler);\n }\n },\n };\n }\n\n if (externalAwareness) {\n awareness = externalAwareness;\n } else {\n awareness = createAwarenessLike();\n }\n\n function formatPayload(payload: unknown) {\n if (payload instanceof Uint8Array) {\n return { bytes: payload.byteLength };\n }\n if (Array.isArray(payload) && payload.every((item) => typeof item === \"number\")) {\n return { bytes: payload.length };\n }\n return payload;\n }\n\n function logMessage(direction: \"send\" | \"recv\", type: string, payload?: unknown) {\n if (!debug) return;\n log(direction, type, formatPayload(payload));\n }\n\n function snapshotLocalAwarenessState() {\n const state = awareness.getLocalState();\n lastLocalAwarenessSnapshot = state ? { ...state } : null;\n }\n\n function postSetLocalStateToParent(key: string, value: unknown) {\n if (!connected || !isIframeBridgeStateKey(key)) return;\n const message = { type: \"set-local-state\", key, value };\n logMessage(\"send\", \"set-local-state\", message);\n window.parent.postMessage(message, \"*\");\n }\n\n function parentPostMessage(message: unknown) {\n logMessage(\"send\", (message as { type?: string }).type ?? \"postMessage\", message);\n window.parent.postMessage(message, \"*\");\n }\n\n function setConnected(value: boolean) {\n if (connected === value) return;\n connected = value;\n if (value) {\n forceFullSync = false;\n snapshotLocalAwarenessState();\n while (pendingYdocUpdates.length > 0) {\n const { update, isBaseline } = pendingYdocUpdates.shift()!;\n if (legacyMode) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n window.parent.postMessage(message, \"*\");\n } else {\n const seqNum = ++seq;\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n window.parent.postMessage(message, \"*\");\n unackedYdocUpdates.set(seqNum, { update, isBaseline });\n }\n }\n if (!legacyMode) {\n for (const [savedSeq, { update, isBaseline }] of unackedYdocUpdates) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: savedSeq };\n window.parent.postMessage(message, \"*\");\n }\n }\n connectListeners.forEach((fn) => fn());\n } else {\n lastLocalAwarenessSnapshot = null;\n if (!legacyMode) {\n unackedYdocUpdates.clear();\n }\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function startInitRetry() {\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\n }\n if (!forceFullSync && pendingYdocUpdates.length > 0) {\n if (!legacyMode) {\n const updates = pendingYdocUpdates.splice(0);\n parentPostMessage({\n type: \"ydoc-pending-updates\",\n payload: updates.map(u => ({ update: Array.from(u.update), isBaseline: u.isBaseline })),\n });\n } else {\n for (const { update, isBaseline } of pendingYdocUpdates) {\n parentPostMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline });\n }\n pendingYdocUpdates.length = 0;\n }\n }\n parentPostMessage({ type: \"init\" });\n initRetryTimer = setInterval(() => {\n if (!connected) {\n parentPostMessage({ type: \"init\" });\n }\n }, 1000);\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (applyingParentUpdate) return;\n // 检测基线数据:origin 为 null 时是 xml2ydoc 首次初始化\n const isBaseline = origin === null || origin === undefined;\n if (!connected) {\n if (pendingYdocUpdates.length >= MAX_QUEUE_SIZE) {\n forceFullSync = true;\n pendingYdocUpdates.length = 0;\n console.warn(\"[iframe-bridge] queue full, forcing full sync on reconnect\");\n }\n pendingYdocUpdates.push({ update, isBaseline });\n return;\n }\n if (legacyMode) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\n } else {\n const seqNum = ++seq;\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\n unackedYdocUpdates.set(seqNum, { update, isBaseline });\n }\n };\n\n const onAwarenessUpdate = ({\n added,\n updated,\n removed,\n }: {\n added: number[];\n updated: number[];\n removed: number[];\n }) => {\n if (applyingParentUpdate) {\n return;\n }\n if (!connected) {\n return;\n }\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n const localClientId = awareness.clientID;\n const localChanged = changes.includes(localClientId);\n if (!localChanged) return;\n\n const nextState = awareness.getLocalState();\n const fieldChanges = getAwarenessStateFieldChanges(\n lastLocalAwarenessSnapshot,\n nextState,\n );\n lastLocalAwarenessSnapshot = nextState ? { ...nextState } : null;\n for (const { key, value } of fieldChanges) {\n postSetLocalStateToParent(key, value);\n }\n };\n\n const syncUndoStateFromServer = (\n mxLike: MxLike,\n data: { undoStackSize?: number; redoStackSize?: number },\n ) => {\n const { undoStackSize, redoStackSize } = data;\n const oldIndex = mxLike.indexOfNextAdd;\n const newIndex = undoStackSize || 0;\n const newTotal = (undoStackSize || 0) + (redoStackSize || 0);\n applyingParentUpdate = true;\n mxLike.history = new Array(newTotal).fill({});\n mxLike.indexOfNextAdd = newIndex;\n if (newTotal === 0) {\n mxLike.fireEvent(createMxEventObject(\"clear\"));\n } else if (newIndex < oldIndex) {\n mxLike.fireEvent(\n createMxEventObject(\"undo\", { edit: { changes: [] } }),\n );\n } else if (newIndex > oldIndex) {\n mxLike.fireEvent(\n createMxEventObject(\"redo\", { edit: { changes: [] } }),\n );\n } else {\n mxLike.fireEvent(\n createMxEventObject(\"add\", { edit: { changes: [] } }),\n );\n }\n applyingParentUpdate = false;\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== window.parent) return;\n if (!event.data || typeof event.data !== 'object') return;\n const { type, payload, serverClientId: receivedServerId } = event.data;\n\n logMessage(\"recv\", type, payload);\n if (type === \"pong\" && receivedServerId != null) {\n serverClientId = receivedServerId;\n // 版本号检测:新版 server 在 pong 里带 protocolVersion\n if (event.data.protocolVersion >= 2) {\n serverSupportsAck = true;\n if (legacyMode) {\n // ydoc-sync 先到且无 protocolVersion 时误判了 legacy,纠正回来\n legacyMode = false;\n log(\"server supports ack (protocol v\" + event.data.protocolVersion + \", corrected from legacy)\");\n } else {\n log(\"server supports ack (protocol v\" + event.data.protocolVersion + \")\");\n }\n } else if (!serverSupportsAck) {\n legacyMode = true;\n unackedYdocUpdates.clear();\n log(\"legacy mode detected: server has no protocolVersion\");\n }\n return;\n }\n if (type === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedYdocUpdates.delete(ackSeq);\n }\n return;\n }\n\n if (type === \"ydoc-sync\" || type === \"ydoc-update\") {\n applyingParentUpdate = true;\n Y.applyUpdate(ydoc, new Uint8Array(payload));\n applyingParentUpdate = false;\n // ydoc-sync 也可能带 protocolVersion(兜底检测,正常情况 pong 已检测)\n if (type === \"ydoc-sync\" && event.data.protocolVersion != null) {\n if (event.data.protocolVersion >= 2 && !serverSupportsAck) {\n serverSupportsAck = true;\n log(\"server supports ack (protocol v\" + event.data.protocolVersion + \", via ydoc-sync)\");\n }\n } else if (type === \"ydoc-sync\" && !serverSupportsAck && !legacyMode) {\n // ydoc-sync 无 protocolVersion 且 pong 还没来 → 先切 legacy\n // 如果 pong 后来带 protocolVersion 会纠正回来\n legacyMode = true;\n unackedYdocUpdates.clear();\n log(\"legacy mode tentative: ydoc-sync has no protocolVersion\");\n }\n if (type === \"ydoc-sync\" && !connected) {\n setConnected(true);\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\n initRetryTimer = null;\n }\n }\n } else if (type === \"awareness-sync\" || type === \"awareness-update\") {\n logMessage(\"recv\", type, payload);\n const prevLocalId = localClientId;\n if (receivedServerId != null) {\n serverClientId = receivedServerId;\n if (useExternalAwareness === false && receivedServerId != null && prevLocalId !== receivedServerId) {\n const tempState = localStates.get(prevLocalId);\n if (tempState) {\n localStates.delete(prevLocalId);\n localStates.set(receivedServerId, tempState);\n }\n }\n }\n\n if (useExternalAwareness) {\n const serverId = receivedServerId ?? serverClientId;\n const localId = awareness.clientID;\n \n applyingParentUpdate = true;\n if (serverId != null && serverId !== localId) {\n const remapped = remapClientIdInUpdate(\n new Uint8Array(payload),\n serverId,\n localId,\n );\n \n if (type === \"awareness-sync\") {\n (awareness as Awareness).meta.delete(localId);\n awareness.setLocalState(null);\n }\n \n applyAwarenessUpdate(awareness as Awareness, remapped, null);\n } else {\n applyAwarenessUpdate(awareness as Awareness, new Uint8Array(payload), null);\n }\n applyingParentUpdate = false;\n } else {\n const parsedStates = parseAwarenessPayload(new Uint8Array(payload));\n applyingParentUpdate = true;\n const changedClientIds: number[] = [];\n const removedClientIds: number[] = [];\n for (const [id, state] of parsedStates) {\n const existed = localStates.has(id);\n const changed = !existed || JSON.stringify(localStates.get(id)) !== JSON.stringify(state);\n localStates.set(id, state);\n if (changed) {\n changedClientIds.push(id);\n }\n }\n for (const [id] of localStates) {\n if (!parsedStates.has(id)) {\n localStates.delete(id);\n removedClientIds.push(id);\n }\n }\n if (changedClientIds.length > 0 || removedClientIds.length > 0) {\n const update = { added: [], updated: changedClientIds, removed: removedClientIds };\n updateHandlers.forEach(handler => handler(update));\n }\n applyingParentUpdate = false;\n }\n } else if (type === \"undo-state\") {\n if (!currentMxLike) {\n pendingUndoState = event.data;\n } else {\n syncUndoStateFromServer(currentMxLike, event.data);\n }\n } else if (type === \"disconnect\") {\n setConnected(false);\n startInitRetry();\n }\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n // 只有真正的 y-protocols Awareness 实例才有 .on() 方法\n // AwarenessLike(内部创建的)通过 updateHandlers 管理回调\n if (useExternalAwareness) {\n (awareness as Awareness).on(\"update\", onAwarenessUpdate);\n }\n window.addEventListener(\"message\", onMessage);\n\n startInitRetry();\n\n // 发送 ping 获取 serverClientId\n setTimeout(() => {\n window.parent.postMessage({ type: \"ping\" }, \"*\");\n }, 100);\n\n return {\n get serverClientId() {\n return serverClientId;\n },\n get connected() {\n return connected;\n },\n get awareness() {\n return awareness as Awareness;\n },\n onConnect(fn: () => void) {\n connectListeners.add(fn);\n return () => connectListeners.delete(fn);\n },\n onDisconnect(fn: () => void) {\n disconnectListeners.add(fn);\n return () => disconnectListeners.delete(fn);\n },\n on(event: \"connect\" | \"disconnect\", fn: () => void) {\n if (event === \"connect\") {\n connectListeners.add(fn);\n return () => connectListeners.delete(fn);\n } else {\n disconnectListeners.add(fn);\n return () => disconnectListeners.delete(fn);\n }\n },\n setLocalFields(fields: Record<string, unknown>) {\n const currentLocal = awareness.getLocalState() || {};\n const currentUser = (currentLocal as { user?: Record<string, unknown> }).user || {};\n const newUser = { ...currentUser, ...fields };\n awareness.setLocalState({\n ...currentLocal,\n user: newUser,\n });\n // 通知父页面更新本地字段,父页面可选择是否处理\n if (connected) {\n const message = { type: \"set-local-fields\", fields };\n logMessage(\"send\", \"set-local-fields\", fields);\n window.parent.postMessage(message, \"*\");\n }\n },\n takeoverUndoManager(file: DrawioFile) {\n if (currentCleanup) {\n currentCleanup();\n }\n\n const editor = file.getUi().editor;\n const originUndoManager = editor.undoManager;\n\n // bindUndoManager 已安装:不替换 editor.undoManager,只委托 undo/redo\n if (originUndoManager && \"_y\" in originUndoManager) {\n const mxLike = originUndoManager as MxLike;\n const origUndo = mxLike.undo.bind(mxLike);\n const origRedo = mxLike.redo.bind(mxLike);\n const origCanUndo = mxLike.canUndo.bind(mxLike);\n const origCanRedo = mxLike.canRedo.bind(mxLike);\n currentMxLike = mxLike;\n mxLike.undo = () => {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"undo\" }, \"*\");\n } else {\n origUndo();\n }\n };\n mxLike.redo = () => {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"redo\" }, \"*\");\n } else {\n origRedo();\n }\n };\n mxLike.canUndo = () => mxLike.indexOfNextAdd > 0;\n mxLike.canRedo = () => mxLike.indexOfNextAdd < mxLike.history.length;\n if (pendingUndoState) {\n syncUndoStateFromServer(mxLike, pendingUndoState);\n pendingUndoState = null;\n }\n window.parent.postMessage({ type: \"request-undo-state\" }, \"*\");\n const cleanup = () => {\n mxLike.undo = origUndo;\n mxLike.redo = origRedo;\n mxLike.canUndo = origCanUndo;\n mxLike.canRedo = origCanRedo;\n currentMxLike = null;\n pendingUndoState = null;\n };\n currentCleanup = cleanup;\n return cleanup;\n }\n\n const pairs: Array<[string, ListenerFn]> = [];\n const raw = Array.isArray(originUndoManager?.eventListeners)\n ? (originUndoManager.eventListeners as unknown[])\n : [];\n for (let i = 0; i + 1 < raw.length; i += 2) {\n const key = String(raw[i]);\n const fn = raw[i + 1] as ListenerFn;\n pairs.push([key, fn]);\n }\n\n const mxLike: MxLike = {\n eventListeners: [] as Array<string | ListenerFn>,\n history: [] as unknown[],\n indexOfNextAdd: 0,\n\n addListener(name: string, fn: ListenerFn) {\n this.eventListeners.push(name, fn);\n },\n\n fireEvent(evt: unknown) {\n const eventName: string =\n (evt as { name?: string } | undefined)?.name ||\n ((evt as { getName?: () => string } | undefined)?.getName?.() ??\n \"\");\n for (let i = 0; i + 1 < this.eventListeners.length; i += 2) {\n const key = this.eventListeners[i];\n const listener = this.eventListeners[i + 1] as ListenerFn;\n if (key === eventName) {\n try {\n listener(this, evt);\n } catch (e) {\n console.warn(\n \"[iframe-bridge] undoManager event listener error:\",\n e,\n );\n }\n }\n }\n },\n\n canUndo(): boolean {\n return this.indexOfNextAdd > 0;\n },\n\n canRedo(): boolean {\n return this.indexOfNextAdd < this.history.length;\n },\n\n undo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"undo\" }, \"*\");\n }\n },\n\n redo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"redo\" }, \"*\");\n }\n },\n\n undoableEditHappened() {\n // no-op\n },\n };\n\n pairs.forEach(([key, fn]) => {\n const k = key.toLowerCase();\n if (k === \"add\" || k === \"clear\" || k === \"undo\" || k === \"redo\") {\n mxLike.addListener(k, fn);\n }\n });\n\n currentMxLike = mxLike;\n editor.undoManager = mxLike as unknown as DrawioEditor[\"undoManager\"];\n editor.undoListener = function () {};\n\n if (pendingUndoState) {\n syncUndoStateFromServer(mxLike, pendingUndoState);\n pendingUndoState = null;\n }\n window.parent.postMessage({ type: \"request-undo-state\" }, \"*\");\n\n const cleanup = () => {\n editor.undoManager = originUndoManager;\n editor.undoListener = originUndoManager?.undoListener as\n | ((...args: unknown[]) => void)\n | undefined;\n currentMxLike = null;\n pendingUndoState = null;\n };\n\n currentCleanup = cleanup;\n return cleanup;\n },\n destroy: () => {\n while (pendingYdocUpdates.length > 0) {\n const { update, isBaseline } = pendingYdocUpdates.shift()!;\n window.parent.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline }, \"*\");\n }\n unackedYdocUpdates.clear();\n ydoc.off(\"update\", onYdocUpdate);\n if (useExternalAwareness) {\n (awareness as Awareness).off(\"update\", onAwarenessUpdate);\n }\n window.removeEventListener(\"message\", onMessage);\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\n initRetryTimer = null;\n }\n connectListeners.clear();\n disconnectListeners.clear();\n if (currentCleanup) {\n currentCleanup();\n }\n },\n };\n}\n"],"names":["localClientId","mxLike","cleanup"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"provider.js","sources":["../../../iframe-bridge/src/provider.ts"],"sourcesContent":["import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN, BASELINE_ORIGIN } from \"./origin.js\";\nconst IFRAME_BRIDGE_STATE_KEYS = new Set([\"cursor\", \"selection\"]);\n\nfunction isIframeBridgeStateKey(key: string): boolean {\n return IFRAME_BRIDGE_STATE_KEYS.has(key);\n}\n\nfunction getAwarenessStateFieldChanges(\n prev: Record<string, unknown> | null,\n next: Record<string, unknown> | null,\n): Array<{ key: string; value: unknown }> {\n const keys = new Set([\n ...Object.keys(prev ?? {}),\n ...Object.keys(next ?? {}),\n ]);\n const changes: Array<{ key: string; value: unknown }> = [];\n for (const key of keys) {\n const prevValue = prev?.[key];\n const nextValue = next?.[key];\n if (JSON.stringify(prevValue) !== JSON.stringify(nextValue)) {\n changes.push({ key, value: nextValue });\n }\n }\n return changes;\n}\n\n/**\n * Awareness-like 接口,只需要支持本地状态管理。\n * 用于 iframe-bridge provider 不需要与父页面同步 awareness 的场景。\n */\nexport interface AwarenessLike {\n readonly clientID: number;\n readonly states: Map<number, Record<string, unknown>>;\n getStates(): Map<number, Record<string, unknown>>;\n getLocalState(): Record<string, unknown> | null;\n setLocalState(state: Record<string, unknown> | null): void;\n setLocalStateField(field: string, value: unknown): void;\n on(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void): void;\n off(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void): void;\n}\n\ntype ListenerFn = (sender: unknown, evt?: unknown) => void;\n\nfunction createMxEventObject(name: string, props?: Record<string, unknown>) {\n const _props = props || {};\n return {\n name,\n getName: () => name,\n getProperty: (k: string) => _props[k],\n };\n}\n\ntype MxLike = Record<string, unknown> & {\n eventListeners: Array<string | ListenerFn>;\n history: unknown[];\n indexOfNextAdd: number;\n addListener(name: string, fn: ListenerFn): void;\n fireEvent(evt: unknown): void;\n canUndo(): boolean;\n canRedo(): boolean;\n undo(): void;\n redo(): void;\n undoableEditHappened(_edit: unknown): void;\n};\n\nexport interface DrawioEditor {\n undoManager?: {\n eventListeners?: unknown[];\n [key: string]: unknown;\n };\n undoListener?: (...args: unknown[]) => void;\n}\n\nexport interface DrawioFile {\n getUi(): { editor: DrawioEditor };\n}\n\nexport interface IframeBridgeProviderOptions {\n awareness?: Awareness;\n debug?: boolean;\n /** 一致性检查间隔(毫秒),0 或不传则禁用。定期比较 state vector,不一致时请求 full sync。 */\n consistencyCheckInterval?: number;\n /** pending update 超时回调(ms),不传则不检测 */\n pendingTimeoutMs?: number;\n /** pending update 超时触发的回调 */\n onPendingTimeout?: (info: { pendingCount: number; oldestMs: number }) => void;\n}\n\nexport interface IframeBridgeProvider {\n serverClientId: number | null;\n connected: boolean;\n awareness: Awareness;\n onConnect: (fn: () => void) => () => void;\n onDisconnect: (fn: () => void) => () => void;\n on: (event: \"connect\" | \"disconnect\", fn: () => void) => () => void;\n setLocalFields: (fields: Record<string, unknown>) => void;\n takeoverUndoManager: (file: DrawioFile) => () => void;\n forceSyncToServer: () => void;\n destroy: () => void;\n}\n\nfunction readVarUint(data: Uint8Array, pos: number): [number, number] {\n let result = 0;\n let shift = 0;\n let byte: number;\n do {\n byte = data[pos++];\n result |= (byte & 0x7f) << shift;\n shift += 7;\n } while (byte >= 0x80);\n return [result >>> 0, pos];\n}\n\nfunction writeVarUint(value: number): number[] {\n const bytes: number[] = [];\n while (value > 0x7f) {\n bytes.push((value & 0x7f) | 0x80);\n value >>>= 7;\n }\n bytes.push(value);\n return bytes;\n}\n\nfunction readVarString(data: Uint8Array, pos: number): [string, number] {\n const [len, pos2] = readVarUint(data, pos);\n const str = new TextDecoder().decode(data.subarray(pos2, pos2 + len));\n return [str, pos2 + len];\n}\n\nfunction writeVarString(str: string): number[] {\n const encoded = new TextEncoder().encode(str);\n return [...writeVarUint(encoded.length), ...encoded];\n}\n\nfunction remapClientIdInUpdate(\n update: Uint8Array,\n fromId: number,\n toId: number,\n): Uint8Array {\n const entries: Array<{ clientID: number; clock: number; state: string }> = [];\n const seenClientIds = new Set<number>();\n let pos = 0;\n\n const [count, pos2] = readVarUint(update, pos);\n pos = pos2;\n\n for (let i = 0; i < count; i++) {\n const [clientID, pos3] = readVarUint(update, pos);\n pos = pos3;\n const [clock, pos4] = readVarUint(update, pos);\n pos = pos4;\n const [state, pos5] = readVarString(update, pos);\n pos = pos5;\n\n const mappedId = clientID === fromId ? toId : clientID;\n if (seenClientIds.has(mappedId)) {\n continue;\n }\n\n seenClientIds.add(mappedId);\n entries.push({ clientID: mappedId, clock, state });\n }\n\n const result: number[] = [];\n result.push(...writeVarUint(entries.length));\n for (const entry of entries) {\n result.push(...writeVarUint(entry.clientID));\n result.push(...writeVarUint(entry.clock));\n result.push(...writeVarString(entry.state));\n }\n\n return new Uint8Array(result);\n}\n\nfunction parseAwarenessPayload(data: Uint8Array): Map<number, Record<string, unknown>> {\n const result = new Map<number, Record<string, unknown>>();\n let pos = 0;\n const [count, pos2] = readVarUint(data, pos);\n pos = pos2;\n\n for (let i = 0; i < count; i++) {\n const [clientID, pos3] = readVarUint(data, pos);\n pos = pos3;\n const [, pos4] = readVarUint(data, pos);\n pos = pos4;\n const [stateStr, pos5] = readVarString(data, pos);\n pos = pos5;\n\n if (stateStr) {\n try {\n result.set(clientID, JSON.parse(stateStr));\n } catch {\n // no-op\n }\n }\n }\n return result;\n}\n\nexport function createIframeBridgeProvider(\n ydoc: Y.Doc,\n options?: IframeBridgeProviderOptions,\n): IframeBridgeProvider {\n const { awareness: externalAwareness, debug = false, consistencyCheckInterval = 0 } = options ?? {};\n let applyingParentUpdate = false;\n let serverClientId: number | null = null;\n let currentCleanup: (() => void) | null = null;\n let currentMxLike: MxLike | null = null;\n let pendingUndoState: {\n undoStackSize?: number;\n redoStackSize?: number;\n } | null = null;\n let connected = false;\n let forceFullSync = false;\n const MAX_QUEUE_SIZE = 1000;\n const pendingYdocUpdates: Array<{update: Uint8Array, isBaseline: boolean}> = [];\n let seq = 0;\n const unackedYdocUpdates = new Map<number, { update: Uint8Array; isBaseline: boolean; sentAt: number }>();\n let initRetryTimer: ReturnType<typeof setInterval> | null = null;\n let consistencyTimer: ReturnType<typeof setInterval> | null = null;\n let pendingCheckTimer: ReturnType<typeof setTimeout> | null = null;\n\n const { pendingTimeoutMs, onPendingTimeout } = options ?? {};\n\n function schedulePendingCheck() {\n if (pendingCheckTimer || !pendingTimeoutMs || !onPendingTimeout) return;\n pendingCheckTimer = setTimeout(() => {\n pendingCheckTimer = null;\n const now = Date.now();\n const unackedCount = unackedYdocUpdates.size;\n const pendingCount = pendingYdocUpdates.length;\n if (unackedCount > 0 || pendingCount > 0) {\n const oldest = unackedCount > 0\n ? Math.min(...Array.from(unackedYdocUpdates.values()).map((v) => v.sentAt))\n : now;\n onPendingTimeout({\n pendingCount: unackedCount + pendingCount,\n oldestMs: now - oldest,\n });\n }\n }, pendingTimeoutMs);\n }\n \n // Legacy mode detection: old servers don't send protocolVersion in pong\n let serverSupportsAck = false;\n let legacyMode = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let lastLocalAwarenessSnapshot: Record<string, unknown> | null = null;\n\n const log = debug\n ? (...args: unknown[]) => console.log(\"[iframe-bridge provider]\", ...args)\n : () => undefined;\n\n const useExternalAwareness = !!externalAwareness;\n let awareness: Awareness | AwarenessLike;\n const localStates = new Map<number, Record<string, unknown>>();\n const localClientId = Math.floor(Math.random() * 2147483647) + 1;\n const updateHandlers = new Set<(update: { added: number[]; updated: number[]; removed: number[] }) => void>();\n\n function createAwarenessLike(): AwarenessLike {\n function getEffectiveClientId() {\n return serverClientId ?? localClientId;\n }\n\n return {\n get clientID() {\n return getEffectiveClientId();\n },\n get states() {\n return localStates;\n },\n getStates() {\n return new Map(localStates);\n },\n getLocalState() {\n return localStates.get(getEffectiveClientId()) ?? null;\n },\n setLocalState(state: Record<string, unknown> | null) {\n const id = getEffectiveClientId();\n if (state === null) {\n localStates.delete(id);\n const update = { added: [], updated: [], removed: [id] };\n updateHandlers.forEach(handler => handler(update));\n } else {\n const existed = localStates.has(id);\n localStates.set(id, state);\n const update = { added: !existed ? [id] : [], updated: [id], removed: [] };\n updateHandlers.forEach(handler => handler(update));\n }\n },\n setLocalStateField(field: string, value: unknown) {\n const id = getEffectiveClientId();\n const current = localStates.get(id) || {};\n const newState = { ...current, [field]: value };\n localStates.set(id, newState);\n postSetLocalStateToParent(field, value);\n const update = { added: [], updated: [id], removed: [] };\n updateHandlers.forEach(handler => handler(update));\n },\n on(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void) {\n if (event === \"update\") {\n updateHandlers.add(handler);\n }\n },\n off(event: \"update\", handler: (update: { added: number[]; updated: number[]; removed: number[] }) => void) {\n if (event === \"update\") {\n updateHandlers.delete(handler);\n }\n },\n };\n }\n\n if (externalAwareness) {\n awareness = externalAwareness;\n } else {\n awareness = createAwarenessLike();\n }\n\n function formatPayload(payload: unknown) {\n if (payload instanceof Uint8Array) {\n return { bytes: payload.byteLength };\n }\n if (Array.isArray(payload) && payload.every((item) => typeof item === \"number\")) {\n return { bytes: payload.length };\n }\n return payload;\n }\n\n function logMessage(direction: \"send\" | \"recv\", type: string, payload?: unknown) {\n if (!debug) return;\n log(direction, type, formatPayload(payload));\n }\n\n function snapshotLocalAwarenessState() {\n const state = awareness.getLocalState();\n lastLocalAwarenessSnapshot = state ? { ...state } : null;\n }\n\n function postSetLocalStateToParent(key: string, value: unknown) {\n if (!connected || !isIframeBridgeStateKey(key)) return;\n const message = { type: \"set-local-state\", key, value };\n logMessage(\"send\", \"set-local-state\", message);\n window.parent.postMessage(message, \"*\");\n }\n\n function parentPostMessage(message: unknown) {\n logMessage(\"send\", (message as { type?: string }).type ?? \"postMessage\", message);\n window.parent.postMessage(message, \"*\");\n }\n\n function setConnected(value: boolean) {\n if (connected === value) return;\n connected = value;\n if (value) {\n forceFullSync = false;\n snapshotLocalAwarenessState();\n while (pendingYdocUpdates.length > 0) {\n const { update, isBaseline } = pendingYdocUpdates.shift()!;\n if (legacyMode) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n window.parent.postMessage(message, \"*\");\n } else {\n const seqNum = ++seq;\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n window.parent.postMessage(message, \"*\");\n unackedYdocUpdates.set(seqNum, { update, isBaseline, sentAt: Date.now() });\n }\n }\n if (!legacyMode) {\n for (const [savedSeq, { update, isBaseline }] of unackedYdocUpdates) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: savedSeq };\n window.parent.postMessage(message, \"*\");\n }\n }\n connectListeners.forEach((fn) => fn());\n // 连接后启动一致性检查\n startConsistencyCheck();\n } else {\n lastLocalAwarenessSnapshot = null;\n if (!legacyMode) {\n unackedYdocUpdates.clear();\n }\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function startInitRetry() {\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\n }\n if (!forceFullSync && pendingYdocUpdates.length > 0) {\n if (!legacyMode) {\n const updates = pendingYdocUpdates.splice(0);\n parentPostMessage({\n type: \"ydoc-pending-updates\",\n payload: updates.map(u => ({ update: Array.from(u.update), isBaseline: u.isBaseline })),\n });\n } else {\n for (const { update, isBaseline } of pendingYdocUpdates) {\n parentPostMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline });\n }\n pendingYdocUpdates.length = 0;\n }\n }\n parentPostMessage({ type: \"init\" });\n initRetryTimer = setInterval(() => {\n if (!connected) {\n parentPostMessage({ type: \"init\" });\n }\n }, 1000);\n }\n\n function startConsistencyCheck() {\n if (consistencyTimer) clearInterval(consistencyTimer);\n if (consistencyCheckInterval <= 0) return;\n consistencyTimer = setInterval(() => {\n if (!connected) return;\n // 发送本地 state vector 给 server 比较\n const sv = Y.encodeStateVector(ydoc);\n parentPostMessage({ type: \"consistency-check\", stateVector: Array.from(sv) });\n log(\"consistency-check sent\");\n }, consistencyCheckInterval);\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (applyingParentUpdate) return;\n // 检测基线数据:origin 为 null 时是 xml2ydoc 首次初始化\n const isBaseline = origin === null || origin === undefined;\n if (!connected) {\n if (pendingYdocUpdates.length >= MAX_QUEUE_SIZE) {\n forceFullSync = true;\n pendingYdocUpdates.length = 0;\n console.warn(\"[iframe-bridge] queue full, forcing full sync on reconnect\");\n }\n pendingYdocUpdates.push({ update, isBaseline });\n schedulePendingCheck();\n return;\n }\n if (legacyMode) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\n } else {\n const seqNum = ++seq;\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\n unackedYdocUpdates.set(seqNum, { update, isBaseline, sentAt: Date.now() });\n schedulePendingCheck();\n }\n };\n\n const onAwarenessUpdate = ({\n added,\n updated,\n removed,\n }: {\n added: number[];\n updated: number[];\n removed: number[];\n }) => {\n if (applyingParentUpdate) {\n return;\n }\n if (!connected) {\n return;\n }\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n const localClientId = awareness.clientID;\n const localChanged = changes.includes(localClientId);\n if (!localChanged) return;\n\n const nextState = awareness.getLocalState();\n const fieldChanges = getAwarenessStateFieldChanges(\n lastLocalAwarenessSnapshot,\n nextState,\n );\n lastLocalAwarenessSnapshot = nextState ? { ...nextState } : null;\n for (const { key, value } of fieldChanges) {\n postSetLocalStateToParent(key, value);\n }\n };\n\n const syncUndoStateFromServer = (\n mxLike: MxLike,\n data: { undoStackSize?: number; redoStackSize?: number },\n ) => {\n const { undoStackSize, redoStackSize } = data;\n const oldIndex = mxLike.indexOfNextAdd;\n const newIndex = undoStackSize || 0;\n const newTotal = (undoStackSize || 0) + (redoStackSize || 0);\n applyingParentUpdate = true;\n mxLike.history = new Array(newTotal).fill({});\n mxLike.indexOfNextAdd = newIndex;\n if (newTotal === 0) {\n mxLike.fireEvent(createMxEventObject(\"clear\"));\n } else if (newIndex < oldIndex) {\n mxLike.fireEvent(\n createMxEventObject(\"undo\", { edit: { changes: [] } }),\n );\n } else if (newIndex > oldIndex) {\n mxLike.fireEvent(\n createMxEventObject(\"redo\", { edit: { changes: [] } }),\n );\n } else {\n mxLike.fireEvent(\n createMxEventObject(\"add\", { edit: { changes: [] } }),\n );\n }\n applyingParentUpdate = false;\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== window.parent) return;\n if (!event.data || typeof event.data !== 'object') return;\n const { type, payload, serverClientId: receivedServerId } = event.data;\n\n logMessage(\"recv\", type, payload);\n if (type === \"pong\" && receivedServerId != null) {\n serverClientId = receivedServerId;\n // 版本号检测:新版 server 在 pong 里带 protocolVersion\n if (event.data.protocolVersion >= 2) {\n serverSupportsAck = true;\n if (legacyMode) {\n // ydoc-sync 先到且无 protocolVersion 时误判了 legacy,纠正回来\n legacyMode = false;\n log(\"server supports ack (protocol v\" + event.data.protocolVersion + \", corrected from legacy)\");\n } else {\n log(\"server supports ack (protocol v\" + event.data.protocolVersion + \")\");\n }\n } else if (!serverSupportsAck) {\n legacyMode = true;\n unackedYdocUpdates.clear();\n log(\"legacy mode detected: server has no protocolVersion\");\n }\n return;\n }\n if (type === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedYdocUpdates.delete(ackSeq);\n }\n return;\n }\n\n if (type === \"ydoc-sync\" || type === \"ydoc-update\") {\n applyingParentUpdate = true;\n // 使用 origin 区分 baseline vs 编辑数据,server 端 UndoManager 可据此追踪\n const isBaseline = (event.data && typeof event.data === \"object\" && event.data.isBaseline) ? true : false;\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, new Uint8Array(payload), applyOrigin);\n applyingParentUpdate = false;\n // ydoc-sync 也可能带 protocolVersion(兜底检测,正常情况 pong 已检测)\n if (type === \"ydoc-sync\" && event.data.protocolVersion != null) {\n if (event.data.protocolVersion >= 2 && !serverSupportsAck) {\n serverSupportsAck = true;\n log(\"server supports ack (protocol v\" + event.data.protocolVersion + \", via ydoc-sync)\");\n }\n } else if (type === \"ydoc-sync\" && !serverSupportsAck && !legacyMode) {\n // ydoc-sync 无 protocolVersion 且 pong 还没来 → 先切 legacy\n // 如果 pong 后来带 protocolVersion 会纠正回来\n legacyMode = true;\n unackedYdocUpdates.clear();\n log(\"legacy mode tentative: ydoc-sync has no protocolVersion\");\n }\n if (type === \"ydoc-sync\" && !connected) {\n setConnected(true);\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\n initRetryTimer = null;\n }\n }\n } else if (type === \"awareness-sync\" || type === \"awareness-update\") {\n logMessage(\"recv\", type, payload);\n const prevLocalId = localClientId;\n if (receivedServerId != null) {\n serverClientId = receivedServerId;\n if (useExternalAwareness === false && receivedServerId != null && prevLocalId !== receivedServerId) {\n const tempState = localStates.get(prevLocalId);\n if (tempState) {\n localStates.delete(prevLocalId);\n localStates.set(receivedServerId, tempState);\n }\n }\n }\n\n if (useExternalAwareness) {\n const serverId = receivedServerId ?? serverClientId;\n const localId = awareness.clientID;\n \n applyingParentUpdate = true;\n if (serverId != null && serverId !== localId) {\n const remapped = remapClientIdInUpdate(\n new Uint8Array(payload),\n serverId,\n localId,\n );\n \n if (type === \"awareness-sync\") {\n (awareness as Awareness).meta.delete(localId);\n awareness.setLocalState(null);\n }\n \n applyAwarenessUpdate(awareness as Awareness, remapped, null);\n } else {\n applyAwarenessUpdate(awareness as Awareness, new Uint8Array(payload), null);\n }\n applyingParentUpdate = false;\n } else {\n const parsedStates = parseAwarenessPayload(new Uint8Array(payload));\n applyingParentUpdate = true;\n const changedClientIds: number[] = [];\n const removedClientIds: number[] = [];\n for (const [id, state] of parsedStates) {\n const existed = localStates.has(id);\n const changed = !existed || JSON.stringify(localStates.get(id)) !== JSON.stringify(state);\n localStates.set(id, state);\n if (changed) {\n changedClientIds.push(id);\n }\n }\n for (const [id] of localStates) {\n if (!parsedStates.has(id)) {\n localStates.delete(id);\n removedClientIds.push(id);\n }\n }\n if (changedClientIds.length > 0 || removedClientIds.length > 0) {\n const update = { added: [], updated: changedClientIds, removed: removedClientIds };\n updateHandlers.forEach(handler => handler(update));\n }\n applyingParentUpdate = false;\n }\n } else if (type === \"undo-state\") {\n if (!currentMxLike) {\n pendingUndoState = event.data;\n } else {\n syncUndoStateFromServer(currentMxLike, event.data);\n }\n } else if (type === \"disconnect\") {\n setConnected(false);\n startInitRetry();\n } else if (type === \"force-sync\") {\n // server 检测到不一致,强制发送完整 state\n log(\"received force-sync from server\");\n const fullState = Y.encodeStateAsUpdate(ydoc);\n parentPostMessage({ type: \"ydoc-pending-updates\", payload: [{ update: Array.from(fullState), isBaseline: false }] });\n }\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n // 只有真正的 y-protocols Awareness 实例才有 .on() 方法\n // AwarenessLike(内部创建的)通过 updateHandlers 管理回调\n if (useExternalAwareness) {\n (awareness as Awareness).on(\"update\", onAwarenessUpdate);\n }\n window.addEventListener(\"message\", onMessage);\n\n startInitRetry();\n\n // 发送 ping 获取 serverClientId\n setTimeout(() => {\n window.parent.postMessage({ type: \"ping\" }, \"*\");\n }, 100);\n\n return {\n get serverClientId() {\n return serverClientId;\n },\n get connected() {\n return connected;\n },\n get awareness() {\n return awareness as Awareness;\n },\n onConnect(fn: () => void) {\n connectListeners.add(fn);\n return () => connectListeners.delete(fn);\n },\n onDisconnect(fn: () => void) {\n disconnectListeners.add(fn);\n return () => disconnectListeners.delete(fn);\n },\n on(event: \"connect\" | \"disconnect\", fn: () => void) {\n if (event === \"connect\") {\n connectListeners.add(fn);\n return () => connectListeners.delete(fn);\n } else {\n disconnectListeners.add(fn);\n return () => disconnectListeners.delete(fn);\n }\n },\n setLocalFields(fields: Record<string, unknown>) {\n const currentLocal = awareness.getLocalState() || {};\n const currentUser = (currentLocal as { user?: Record<string, unknown> }).user || {};\n const newUser = { ...currentUser, ...fields };\n awareness.setLocalState({\n ...currentLocal,\n user: newUser,\n });\n // 通知父页面更新本地字段,父页面可选择是否处理\n if (connected) {\n const message = { type: \"set-local-fields\", fields };\n logMessage(\"send\", \"set-local-fields\", fields);\n window.parent.postMessage(message, \"*\");\n }\n },\n takeoverUndoManager(file: DrawioFile) {\n if (currentCleanup) {\n currentCleanup();\n }\n\n const editor = file.getUi().editor;\n const originUndoManager = editor.undoManager;\n\n // bindUndoManager 已安装:不替换 editor.undoManager,只委托 undo/redo\n if (originUndoManager && \"_y\" in originUndoManager) {\n const mxLike = originUndoManager as MxLike;\n const origUndo = mxLike.undo.bind(mxLike);\n const origRedo = mxLike.redo.bind(mxLike);\n const origCanUndo = mxLike.canUndo.bind(mxLike);\n const origCanRedo = mxLike.canRedo.bind(mxLike);\n currentMxLike = mxLike;\n mxLike.undo = () => {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"undo\" }, \"*\");\n } else {\n origUndo();\n }\n };\n mxLike.redo = () => {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"redo\" }, \"*\");\n } else {\n origRedo();\n }\n };\n mxLike.canUndo = () => mxLike.indexOfNextAdd > 0;\n mxLike.canRedo = () => mxLike.indexOfNextAdd < mxLike.history.length;\n if (pendingUndoState) {\n syncUndoStateFromServer(mxLike, pendingUndoState);\n pendingUndoState = null;\n }\n window.parent.postMessage({ type: \"request-undo-state\" }, \"*\");\n const cleanup = () => {\n mxLike.undo = origUndo;\n mxLike.redo = origRedo;\n mxLike.canUndo = origCanUndo;\n mxLike.canRedo = origCanRedo;\n currentMxLike = null;\n pendingUndoState = null;\n };\n currentCleanup = cleanup;\n return cleanup;\n }\n\n const pairs: Array<[string, ListenerFn]> = [];\n const raw = Array.isArray(originUndoManager?.eventListeners)\n ? (originUndoManager.eventListeners as unknown[])\n : [];\n for (let i = 0; i + 1 < raw.length; i += 2) {\n const key = String(raw[i]);\n const fn = raw[i + 1] as ListenerFn;\n pairs.push([key, fn]);\n }\n\n const mxLike: MxLike = {\n eventListeners: [] as Array<string | ListenerFn>,\n history: [] as unknown[],\n indexOfNextAdd: 0,\n\n addListener(name: string, fn: ListenerFn) {\n this.eventListeners.push(name, fn);\n },\n\n fireEvent(evt: unknown) {\n const eventName: string =\n (evt as { name?: string } | undefined)?.name ||\n ((evt as { getName?: () => string } | undefined)?.getName?.() ??\n \"\");\n for (let i = 0; i + 1 < this.eventListeners.length; i += 2) {\n const key = this.eventListeners[i];\n const listener = this.eventListeners[i + 1] as ListenerFn;\n if (key === eventName) {\n try {\n listener(this, evt);\n } catch (e) {\n console.warn(\n \"[iframe-bridge] undoManager event listener error:\",\n e,\n );\n }\n }\n }\n },\n\n canUndo(): boolean {\n return this.indexOfNextAdd > 0;\n },\n\n canRedo(): boolean {\n return this.indexOfNextAdd < this.history.length;\n },\n\n undo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"undo\" }, \"*\");\n }\n },\n\n redo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"redo\" }, \"*\");\n }\n },\n\n undoableEditHappened() {\n // no-op\n },\n };\n\n pairs.forEach(([key, fn]) => {\n const k = key.toLowerCase();\n if (k === \"add\" || k === \"clear\" || k === \"undo\" || k === \"redo\") {\n mxLike.addListener(k, fn);\n }\n });\n\n currentMxLike = mxLike;\n editor.undoManager = mxLike as unknown as DrawioEditor[\"undoManager\"];\n editor.undoListener = function () {};\n\n if (pendingUndoState) {\n syncUndoStateFromServer(mxLike, pendingUndoState);\n pendingUndoState = null;\n }\n window.parent.postMessage({ type: \"request-undo-state\" }, \"*\");\n\n const cleanup = () => {\n editor.undoManager = originUndoManager;\n editor.undoListener = originUndoManager?.undoListener as\n | ((...args: unknown[]) => void)\n | undefined;\n currentMxLike = null;\n pendingUndoState = null;\n };\n\n currentCleanup = cleanup;\n return cleanup;\n },\n forceSyncToServer() {\n if (!connected) return;\n const fullState = Y.encodeStateAsUpdate(ydoc);\n window.parent.postMessage({ type: \"ydoc-pending-updates\", payload: [{ update: Array.from(fullState), isBaseline: false }] }, \"*\");\n unackedYdocUpdates.clear();\n if (pendingCheckTimer) {\n clearTimeout(pendingCheckTimer);\n pendingCheckTimer = null;\n }\n },\n destroy: () => {\n if (pendingCheckTimer) {\n clearTimeout(pendingCheckTimer);\n pendingCheckTimer = null;\n }\n while (pendingYdocUpdates.length > 0) {\n const { update, isBaseline } = pendingYdocUpdates.shift()!;\n window.parent.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline }, \"*\");\n }\n unackedYdocUpdates.clear();\n ydoc.off(\"update\", onYdocUpdate);\n if (useExternalAwareness) {\n (awareness as Awareness).off(\"update\", onAwarenessUpdate);\n }\n window.removeEventListener(\"message\", onMessage);\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\n initRetryTimer = null;\n }\n if (consistencyTimer) {\n clearInterval(consistencyTimer);\n consistencyTimer = null;\n }\n connectListeners.clear();\n disconnectListeners.clear();\n if (currentCleanup) {\n currentCleanup();\n }\n },\n };\n}\n"],"names":["localClientId","mxLike","cleanup"],"mappings":"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"}
|
package/iframe-bridge/server.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const Y = require("yjs");
|
|
4
4
|
const awareness = require("y-protocols/awareness");
|
|
5
|
+
const origin = require("../origin-C_FHB48F.cjs");
|
|
5
6
|
function _interopNamespaceDefault(e) {
|
|
6
7
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
7
8
|
if (e) {
|
|
@@ -19,8 +20,6 @@ function _interopNamespaceDefault(e) {
|
|
|
19
20
|
return Object.freeze(n);
|
|
20
21
|
}
|
|
21
22
|
const Y__namespace = /* @__PURE__ */ _interopNamespaceDefault(Y);
|
|
22
|
-
const IFRAME_ORIGIN = {};
|
|
23
|
-
const BASELINE_ORIGIN = {};
|
|
24
23
|
var __defProp = Object.defineProperty;
|
|
25
24
|
var __defProps = Object.defineProperties;
|
|
26
25
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
@@ -41,7 +40,7 @@ var __spreadValues = (a, b) => {
|
|
|
41
40
|
};
|
|
42
41
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
43
42
|
function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
44
|
-
const { undoManager, debug = false } = options != null ? options : {};
|
|
43
|
+
const { undoManager, debug = false, pendingTimeoutMs, onPendingTimeout } = options != null ? options : {};
|
|
45
44
|
const log = debug ? (...args) => console.log("[iframe-bridge server]", ...args) : () => void 0;
|
|
46
45
|
function formatPayload(payload) {
|
|
47
46
|
if (payload instanceof Uint8Array) {
|
|
@@ -66,11 +65,29 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
66
65
|
const pendingUpdatesToIframe = [];
|
|
67
66
|
let serverSeq = 0;
|
|
68
67
|
const unackedServerUpdates = /* @__PURE__ */ new Map();
|
|
68
|
+
let pendingCheckTimer = null;
|
|
69
|
+
function schedulePendingCheck() {
|
|
70
|
+
if (pendingCheckTimer || !pendingTimeoutMs || !onPendingTimeout) return;
|
|
71
|
+
pendingCheckTimer = setTimeout(() => {
|
|
72
|
+
pendingCheckTimer = null;
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
const unackedCount = unackedServerUpdates.size;
|
|
75
|
+
const pendingCount = pendingUpdatesToIframe.length;
|
|
76
|
+
if (unackedCount > 0 || pendingCount > 0) {
|
|
77
|
+
const oldest = unackedCount > 0 ? Math.min(...Array.from(unackedServerUpdates.values()).map((v) => v.sentAt)) : now;
|
|
78
|
+
onPendingTimeout({
|
|
79
|
+
pendingCount: unackedCount + pendingCount,
|
|
80
|
+
oldestMs: now - oldest
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}, pendingTimeoutMs);
|
|
84
|
+
}
|
|
85
|
+
let iframeCapabilities = null;
|
|
69
86
|
function tryAddIframeOriginTracking() {
|
|
70
87
|
if (!undoManager) return;
|
|
71
88
|
try {
|
|
72
89
|
if (typeof undoManager.addTrackedOrigin === "function") {
|
|
73
|
-
undoManager.addTrackedOrigin(IFRAME_ORIGIN);
|
|
90
|
+
undoManager.addTrackedOrigin(origin.IFRAME_ORIGIN);
|
|
74
91
|
iframeOriginTracked = true;
|
|
75
92
|
}
|
|
76
93
|
} catch (error) {
|
|
@@ -84,7 +101,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
84
101
|
if (!undoManager || !iframeOriginTracked) return;
|
|
85
102
|
try {
|
|
86
103
|
if (typeof undoManager.removeTrackedOrigin === "function") {
|
|
87
|
-
undoManager.removeTrackedOrigin(IFRAME_ORIGIN);
|
|
104
|
+
undoManager.removeTrackedOrigin(origin.IFRAME_ORIGIN);
|
|
88
105
|
}
|
|
89
106
|
} catch (error) {
|
|
90
107
|
console.warn(
|
|
@@ -108,7 +125,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
108
125
|
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
109
126
|
cw.postMessage(message, "*");
|
|
110
127
|
}
|
|
111
|
-
unackedServerUpdates.set(seqNum, { update, isBaseline });
|
|
128
|
+
unackedServerUpdates.set(seqNum, { update, isBaseline, sentAt: Date.now() });
|
|
112
129
|
}
|
|
113
130
|
if (!wasForceFullSync) {
|
|
114
131
|
for (const [savedSeq, { update, isBaseline }] of unackedServerUpdates) {
|
|
@@ -118,6 +135,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
118
135
|
}
|
|
119
136
|
}
|
|
120
137
|
}
|
|
138
|
+
postObjectToIframe({ type: "capabilities-request" });
|
|
121
139
|
connectListeners.forEach((fn) => fn());
|
|
122
140
|
} else {
|
|
123
141
|
unackedServerUpdates.clear();
|
|
@@ -140,9 +158,9 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
140
158
|
cw.postMessage(message, "*");
|
|
141
159
|
}
|
|
142
160
|
}
|
|
143
|
-
const onYdocUpdate = (update, origin) => {
|
|
144
|
-
if (origin === IFRAME_ORIGIN) return;
|
|
145
|
-
const isBaseline = origin === null || origin === void 0;
|
|
161
|
+
const onYdocUpdate = (update, origin$1) => {
|
|
162
|
+
if (origin$1 === origin.IFRAME_ORIGIN) return;
|
|
163
|
+
const isBaseline = origin$1 === null || origin$1 === void 0;
|
|
146
164
|
logMessage("send", "ydoc-update", update);
|
|
147
165
|
if (!connected) {
|
|
148
166
|
if (pendingUpdatesToIframe.length >= MAX_QUEUE_SIZE) {
|
|
@@ -151,6 +169,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
151
169
|
console.warn("[iframe-bridge server] queue full, forcing full sync on reconnect");
|
|
152
170
|
}
|
|
153
171
|
pendingUpdatesToIframe.push({ update, isBaseline });
|
|
172
|
+
schedulePendingCheck();
|
|
154
173
|
return;
|
|
155
174
|
}
|
|
156
175
|
const seqNum = ++serverSeq;
|
|
@@ -159,7 +178,8 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
159
178
|
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
160
179
|
cw.postMessage(message, "*");
|
|
161
180
|
}
|
|
162
|
-
unackedServerUpdates.set(seqNum, { update, isBaseline });
|
|
181
|
+
unackedServerUpdates.set(seqNum, { update, isBaseline, sentAt: Date.now() });
|
|
182
|
+
schedulePendingCheck();
|
|
163
183
|
};
|
|
164
184
|
function postUndoStateToIframe() {
|
|
165
185
|
var _a, _b;
|
|
@@ -196,7 +216,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
196
216
|
});
|
|
197
217
|
};
|
|
198
218
|
const onMessage = (event) => {
|
|
199
|
-
var _a, _b;
|
|
219
|
+
var _a, _b, _c;
|
|
200
220
|
if (event.source !== iframe.contentWindow) return;
|
|
201
221
|
const { type: msgType, payload } = event.data;
|
|
202
222
|
if (msgType === "ydoc-pending-updates") {
|
|
@@ -206,7 +226,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
206
226
|
const arr = (_a = item.update) != null ? _a : item;
|
|
207
227
|
const isBaseline = (_b = item.isBaseline) != null ? _b : false;
|
|
208
228
|
const update = new Uint8Array(arr);
|
|
209
|
-
const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;
|
|
229
|
+
const applyOrigin = isBaseline ? origin.BASELINE_ORIGIN : origin.IFRAME_ORIGIN;
|
|
210
230
|
Y__namespace.applyUpdate(ydoc, update, applyOrigin);
|
|
211
231
|
}
|
|
212
232
|
}
|
|
@@ -261,7 +281,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
261
281
|
logMessage("recv", "ydoc-update", payload);
|
|
262
282
|
const update = new Uint8Array(payload);
|
|
263
283
|
const isBaseline = event.data.isBaseline;
|
|
264
|
-
const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;
|
|
284
|
+
const applyOrigin = isBaseline ? origin.BASELINE_ORIGIN : origin.IFRAME_ORIGIN;
|
|
265
285
|
Y__namespace.applyUpdate(ydoc, update, applyOrigin);
|
|
266
286
|
const inSeq = event.data.seq;
|
|
267
287
|
if (inSeq != null) {
|
|
@@ -288,7 +308,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
288
308
|
} else if (msgType === "awareness-update") {
|
|
289
309
|
logMessage("recv", "awareness-update", payload);
|
|
290
310
|
applyingIframeUpdate = true;
|
|
291
|
-
awareness.applyAwarenessUpdate(awareness$1, new Uint8Array(payload), IFRAME_ORIGIN);
|
|
311
|
+
awareness.applyAwarenessUpdate(awareness$1, new Uint8Array(payload), origin.IFRAME_ORIGIN);
|
|
292
312
|
applyingIframeUpdate = false;
|
|
293
313
|
} else if (msgType === "set-local-fields") {
|
|
294
314
|
logMessage("recv", "set-local-fields", payload);
|
|
@@ -305,12 +325,35 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
305
325
|
}
|
|
306
326
|
} else if (msgType === "request-undo-state") {
|
|
307
327
|
postUndoStateToIframe();
|
|
328
|
+
} else if (msgType === "consistency-check") {
|
|
329
|
+
logMessage("recv", "consistency-check", payload);
|
|
330
|
+
const providerSV = new Uint8Array(event.data.stateVector || []);
|
|
331
|
+
const serverSV = Y__namespace.encodeStateVector(ydoc);
|
|
332
|
+
const svMatch = providerSV.length === serverSV.length && providerSV.every((v, i) => v === serverSV[i]);
|
|
333
|
+
if (!svMatch) {
|
|
334
|
+
log("consistency mismatch detected, sending force-sync");
|
|
335
|
+
const cw = iframe.contentWindow;
|
|
336
|
+
if (cw) {
|
|
337
|
+
cw.postMessage({ type: "force-sync" }, "*");
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
} else if (msgType === "request-full-sync") {
|
|
341
|
+
logMessage("recv", "request-full-sync", payload);
|
|
342
|
+
const docState = Y__namespace.encodeStateAsUpdate(ydoc);
|
|
343
|
+
postObjectToIframe({ type: "ydoc-sync", payload: Array.from(docState), protocolVersion: 2 });
|
|
308
344
|
} else if (msgType === "undo" && undoManager) {
|
|
309
345
|
undoManager.undo();
|
|
310
346
|
postUndoStateToIframe();
|
|
311
347
|
} else if (msgType === "redo" && undoManager) {
|
|
312
348
|
undoManager.redo();
|
|
313
349
|
postUndoStateToIframe();
|
|
350
|
+
} else if (msgType === "capabilities-request") {
|
|
351
|
+
logMessage("recv", "capabilities-request", payload);
|
|
352
|
+
postObjectToIframe({ type: "capabilities-reply", capabilities: { consistency: true } });
|
|
353
|
+
} else if (msgType === "capabilities-reply") {
|
|
354
|
+
logMessage("recv", "capabilities-reply", payload);
|
|
355
|
+
iframeCapabilities = (_c = event.data.capabilities) != null ? _c : null;
|
|
356
|
+
log("[DEBUG] received iframe capabilities", iframeCapabilities);
|
|
314
357
|
}
|
|
315
358
|
};
|
|
316
359
|
const onUndoPopped = () => {
|
|
@@ -322,9 +365,14 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
322
365
|
const onStackItemAdded = () => {
|
|
323
366
|
postUndoStateToIframe();
|
|
324
367
|
};
|
|
368
|
+
let paused = false;
|
|
369
|
+
const wrappedOnMessage = (event) => {
|
|
370
|
+
if (paused) return;
|
|
371
|
+
onMessage(event);
|
|
372
|
+
};
|
|
325
373
|
ydoc.on("update", onYdocUpdate);
|
|
326
374
|
awareness$1.on("update", onAwarenessUpdate);
|
|
327
|
-
window.addEventListener("message",
|
|
375
|
+
window.addEventListener("message", wrappedOnMessage);
|
|
328
376
|
if (undoManager) {
|
|
329
377
|
undoManager.on("stack-item-popped", onUndoPopped);
|
|
330
378
|
undoManager.on("stack-cleared", onStackCleared);
|
|
@@ -351,7 +399,29 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
351
399
|
return () => disconnectListeners.delete(fn);
|
|
352
400
|
}
|
|
353
401
|
},
|
|
402
|
+
forceSyncToClient() {
|
|
403
|
+
if (!connected) return;
|
|
404
|
+
const cw = iframe.contentWindow;
|
|
405
|
+
if (!cw) return;
|
|
406
|
+
const docState = Y__namespace.encodeStateAsUpdate(ydoc);
|
|
407
|
+
cw.postMessage({ type: "ydoc-sync", payload: Array.from(docState) }, "*");
|
|
408
|
+
unackedServerUpdates.clear();
|
|
409
|
+
if (pendingCheckTimer) {
|
|
410
|
+
clearTimeout(pendingCheckTimer);
|
|
411
|
+
pendingCheckTimer = null;
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
pause() {
|
|
415
|
+
paused = true;
|
|
416
|
+
},
|
|
417
|
+
resume() {
|
|
418
|
+
paused = false;
|
|
419
|
+
},
|
|
354
420
|
destroy: () => {
|
|
421
|
+
if (pendingCheckTimer) {
|
|
422
|
+
clearTimeout(pendingCheckTimer);
|
|
423
|
+
pendingCheckTimer = null;
|
|
424
|
+
}
|
|
355
425
|
while (pendingUpdatesToIframe.length > 0) {
|
|
356
426
|
const { update, isBaseline } = pendingUpdatesToIframe.shift();
|
|
357
427
|
const cw = iframe.contentWindow;
|
|
@@ -363,7 +433,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
363
433
|
postToIframe("disconnect");
|
|
364
434
|
ydoc.off("update", onYdocUpdate);
|
|
365
435
|
awareness$1.off("update", onAwarenessUpdate);
|
|
366
|
-
window.removeEventListener("message",
|
|
436
|
+
window.removeEventListener("message", wrappedOnMessage);
|
|
367
437
|
if (undoManager) {
|
|
368
438
|
undoManager.off("stack-item-popped", onUndoPopped);
|
|
369
439
|
undoManager.off("stack-cleared", onStackCleared);
|