y-mxgraph 0.8.5 → 0.8.6
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/iframe-bridge/provider.cjs +69 -22
- package/iframe-bridge/provider.cjs.map +1 -1
- package/iframe-bridge/provider.js +69 -22
- package/iframe-bridge/provider.js.map +1 -1
- package/iframe-bridge/server.cjs +3 -3
- package/iframe-bridge/server.cjs.map +1 -1
- package/iframe-bridge/server.js +3 -3
- package/iframe-bridge/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -158,6 +158,8 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
158
158
|
let seq = 0;
|
|
159
159
|
const unackedYdocUpdates = /* @__PURE__ */ new Map();
|
|
160
160
|
let initRetryTimer = null;
|
|
161
|
+
let serverSupportsAck = false;
|
|
162
|
+
let legacyMode = false;
|
|
161
163
|
const connectListeners = /* @__PURE__ */ new Set();
|
|
162
164
|
const disconnectListeners = /* @__PURE__ */ new Set();
|
|
163
165
|
let lastLocalAwarenessSnapshot = null;
|
|
@@ -260,19 +262,28 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
260
262
|
snapshotLocalAwarenessState();
|
|
261
263
|
while (pendingYdocUpdates.length > 0) {
|
|
262
264
|
const { update, isBaseline } = pendingYdocUpdates.shift();
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
if (legacyMode) {
|
|
266
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline };
|
|
267
|
+
window.parent.postMessage(message, "*");
|
|
268
|
+
} else {
|
|
269
|
+
const seqNum = ++seq;
|
|
270
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
271
|
+
window.parent.postMessage(message, "*");
|
|
272
|
+
unackedYdocUpdates.set(seqNum, { update, isBaseline });
|
|
273
|
+
}
|
|
267
274
|
}
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
|
|
275
|
+
if (!legacyMode) {
|
|
276
|
+
for (const [savedSeq, { update, isBaseline }] of unackedYdocUpdates) {
|
|
277
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: savedSeq };
|
|
278
|
+
window.parent.postMessage(message, "*");
|
|
279
|
+
}
|
|
271
280
|
}
|
|
272
281
|
connectListeners.forEach((fn) => fn());
|
|
273
282
|
} else {
|
|
274
283
|
lastLocalAwarenessSnapshot = null;
|
|
275
|
-
|
|
284
|
+
if (!legacyMode) {
|
|
285
|
+
unackedYdocUpdates.clear();
|
|
286
|
+
}
|
|
276
287
|
disconnectListeners.forEach((fn) => fn());
|
|
277
288
|
}
|
|
278
289
|
}
|
|
@@ -281,11 +292,18 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
281
292
|
clearInterval(initRetryTimer);
|
|
282
293
|
}
|
|
283
294
|
if (!forceFullSync && pendingYdocUpdates.length > 0) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
295
|
+
if (!legacyMode) {
|
|
296
|
+
const updates = pendingYdocUpdates.splice(0);
|
|
297
|
+
parentPostMessage({
|
|
298
|
+
type: "ydoc-pending-updates",
|
|
299
|
+
payload: updates.map((u) => ({ update: Array.from(u.update), isBaseline: u.isBaseline }))
|
|
300
|
+
});
|
|
301
|
+
} else {
|
|
302
|
+
for (const { update, isBaseline } of pendingYdocUpdates) {
|
|
303
|
+
parentPostMessage({ type: "ydoc-update", payload: Array.from(update), isBaseline });
|
|
304
|
+
}
|
|
305
|
+
pendingYdocUpdates.length = 0;
|
|
306
|
+
}
|
|
289
307
|
}
|
|
290
308
|
parentPostMessage({ type: "init" });
|
|
291
309
|
initRetryTimer = setInterval(() => {
|
|
@@ -306,11 +324,17 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
306
324
|
pendingYdocUpdates.push({ update, isBaseline });
|
|
307
325
|
return;
|
|
308
326
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
327
|
+
if (legacyMode) {
|
|
328
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline };
|
|
329
|
+
logMessage("send", "ydoc-update", message);
|
|
330
|
+
window.parent.postMessage(message, "*");
|
|
331
|
+
} else {
|
|
332
|
+
const seqNum = ++seq;
|
|
333
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
334
|
+
logMessage("send", "ydoc-update", message);
|
|
335
|
+
window.parent.postMessage(message, "*");
|
|
336
|
+
unackedYdocUpdates.set(seqNum, { update, isBaseline });
|
|
337
|
+
}
|
|
314
338
|
};
|
|
315
339
|
const onAwarenessUpdate = ({
|
|
316
340
|
added,
|
|
@@ -368,6 +392,23 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
368
392
|
if (!event.data || typeof event.data !== "object") return;
|
|
369
393
|
const { type, payload, serverClientId: receivedServerId } = event.data;
|
|
370
394
|
logMessage("recv", type, payload);
|
|
395
|
+
if (type === "pong" && receivedServerId != null) {
|
|
396
|
+
serverClientId = receivedServerId;
|
|
397
|
+
if (event.data.protocolVersion >= 2) {
|
|
398
|
+
serverSupportsAck = true;
|
|
399
|
+
if (legacyMode) {
|
|
400
|
+
legacyMode = false;
|
|
401
|
+
log("server supports ack (protocol v" + event.data.protocolVersion + ", corrected from legacy)");
|
|
402
|
+
} else {
|
|
403
|
+
log("server supports ack (protocol v" + event.data.protocolVersion + ")");
|
|
404
|
+
}
|
|
405
|
+
} else if (!serverSupportsAck) {
|
|
406
|
+
legacyMode = true;
|
|
407
|
+
unackedYdocUpdates.clear();
|
|
408
|
+
log("legacy mode detected: server has no protocolVersion");
|
|
409
|
+
}
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
371
412
|
if (type === "ydoc-update-ack") {
|
|
372
413
|
const ackSeq = event.data.seq;
|
|
373
414
|
if (ackSeq != null) {
|
|
@@ -375,14 +416,20 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
375
416
|
}
|
|
376
417
|
return;
|
|
377
418
|
}
|
|
378
|
-
if (type === "pong" && receivedServerId != null) {
|
|
379
|
-
serverClientId = receivedServerId;
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
419
|
if (type === "ydoc-sync" || type === "ydoc-update") {
|
|
383
420
|
applyingParentUpdate = true;
|
|
384
421
|
Y__namespace.applyUpdate(ydoc, new Uint8Array(payload));
|
|
385
422
|
applyingParentUpdate = false;
|
|
423
|
+
if (type === "ydoc-sync" && event.data.protocolVersion != null) {
|
|
424
|
+
if (event.data.protocolVersion >= 2 && !serverSupportsAck) {
|
|
425
|
+
serverSupportsAck = true;
|
|
426
|
+
log("server supports ack (protocol v" + event.data.protocolVersion + ", via ydoc-sync)");
|
|
427
|
+
}
|
|
428
|
+
} else if (type === "ydoc-sync" && !serverSupportsAck && !legacyMode) {
|
|
429
|
+
legacyMode = true;
|
|
430
|
+
unackedYdocUpdates.clear();
|
|
431
|
+
log("legacy mode tentative: ydoc-sync has no protocolVersion");
|
|
432
|
+
}
|
|
386
433
|
if (type === "ydoc-sync" && !connected) {
|
|
387
434
|
setConnected(true);
|
|
388
435
|
if (initRetryTimer) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.cjs","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 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 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 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 connectListeners.forEach((fn) => fn());\n } else {\n lastLocalAwarenessSnapshot = null;\n unackedYdocUpdates.clear();\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 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 }\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 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 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 === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedYdocUpdates.delete(ackSeq);\n }\n return;\n }\n if (type === \"pong\" && receivedServerId != null) {\n serverClientId = receivedServerId;\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 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":["awareness","localClientId","Y","applyAwarenessUpdate","mxLike","cleanup"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"provider.cjs","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":["awareness","localClientId","Y","applyAwarenessUpdate","mxLike","cleanup"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAM,2BAA2B,oBAAI,IAAI,CAAC,UAAU,WAAW,CAAC;AAEhE,SAAS,uBAAuB,KAAsB;AACpD,SAAO,yBAAyB,IAAI,GAAG;AACzC;AAEA,SAAS,8BACP,MACA,MACwC;AACxC,QAAM,2BAAW,IAAI;AAAA,IACnB,GAAG,OAAO,KAAK,QAAA,OAAA,OAAQ,CAAA,CAAE;AAAA,IACzB,GAAG,OAAO,KAAK,QAAA,OAAA,OAAQ,CAAA,CAAE;AAAA,EAAA,CAC1B;AACD,QAAM,UAAkD,CAAA;AACxD,aAAW,OAAO,MAAM;AACtB,UAAM,YAAY,QAAA,OAAA,SAAA,KAAO,GAAA;AACzB,UAAM,YAAY,QAAA,OAAA,SAAA,KAAO,GAAA;AACzB,QAAI,KAAK,UAAU,SAAS,MAAM,KAAK,UAAU,SAAS,GAAG;AAC3D,cAAQ,KAAK,EAAE,KAAK,OAAO,WAAW;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAmBA,SAAS,oBAAoB,MAAc,OAAiC;AAC1E,QAAM,SAAS,SAAS,CAAA;AACxB,SAAO;AAAA,IACL;AAAA,IACA,SAAS,MAAM;AAAA,IACf,aAAa,CAAC,MAAc,OAAO,CAAC;AAAA,EAAA;AAExC;AA4CA,SAAS,YAAY,MAAkB,KAA+B;AACpE,MAAI,SAAS;AACb,MAAI,QAAQ;AACZ,MAAI;AACJ,KAAG;AACD,WAAO,KAAK,KAAK;AACjB,eAAW,OAAO,QAAS;AAC3B,aAAS;AAAA,EACX,SAAS,QAAQ;AACjB,SAAO,CAAC,WAAW,GAAG,GAAG;AAC3B;AAEA,SAAS,aAAa,OAAyB;AAC7C,QAAM,QAAkB,CAAA;AACxB,SAAO,QAAQ,KAAM;AACnB,UAAM,KAAM,QAAQ,MAAQ,GAAI;AAChC,eAAW;AAAA,EACb;AACA,QAAM,KAAK,KAAK;AAChB,SAAO;AACT;AAEA,SAAS,cAAc,MAAkB,KAA+B;AACtE,QAAM,CAAC,KAAK,IAAI,IAAI,YAAY,MAAM,GAAG;AACzC,QAAM,MAAM,IAAI,YAAA,EAAc,OAAO,KAAK,SAAS,MAAM,OAAO,GAAG,CAAC;AACpE,SAAO,CAAC,KAAK,OAAO,GAAG;AACzB;AAEA,SAAS,eAAe,KAAuB;AAC7C,QAAM,UAAU,IAAI,cAAc,OAAO,GAAG;AAC5C,SAAO,CAAC,GAAG,aAAa,QAAQ,MAAM,GAAG,GAAG,OAAO;AACrD;AAEA,SAAS,sBACP,QACA,QACA,MACY;AACZ,QAAM,UAAqE,CAAA;AAC3E,QAAM,oCAAoB,IAAA;AAC1B,MAAI,MAAM;AAEV,QAAM,CAAC,OAAO,IAAI,IAAI,YAAY,QAAQ,GAAG;AAC7C,QAAM;AAEN,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAM,CAAC,UAAU,IAAI,IAAI,YAAY,QAAQ,GAAG;AAChD,UAAM;AACN,UAAM,CAAC,OAAO,IAAI,IAAI,YAAY,QAAQ,GAAG;AAC7C,UAAM;AACN,UAAM,CAAC,OAAO,IAAI,IAAI,cAAc,QAAQ,GAAG;AAC/C,UAAM;AAEN,UAAM,WAAW,aAAa,SAAS,OAAO;AAC9C,QAAI,cAAc,IAAI,QAAQ,GAAG;AAC/B;AAAA,IACF;AAEA,kBAAc,IAAI,QAAQ;AAC1B,YAAQ,KAAK,EAAE,UAAU,UAAU,OAAO,OAAO;AAAA,EACnD;AAEA,QAAM,SAAmB,CAAA;AACzB,SAAO,KAAK,GAAG,aAAa,QAAQ,MAAM,CAAC;AAC3C,aAAW,SAAS,SAAS;AAC3B,WAAO,KAAK,GAAG,aAAa,MAAM,QAAQ,CAAC;AAC3C,WAAO,KAAK,GAAG,aAAa,MAAM,KAAK,CAAC;AACxC,WAAO,KAAK,GAAG,eAAe,MAAM,KAAK,CAAC;AAAA,EAC5C;AAEA,SAAO,IAAI,WAAW,MAAM;AAC9B;AAEA,SAAS,sBAAsB,MAAwD;AACrF,QAAM,6BAAa,IAAA;AACnB,MAAI,MAAM;AACV,QAAM,CAAC,OAAO,IAAI,IAAI,YAAY,MAAM,GAAG;AAC3C,QAAM;AAEN,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAM,CAAC,UAAU,IAAI,IAAI,YAAY,MAAM,GAAG;AAC9C,UAAM;AACN,UAAM,CAAA,EAAG,IAAI,IAAI,YAAY,MAAM,GAAG;AACtC,UAAM;AACN,UAAM,CAAC,UAAU,IAAI,IAAI,cAAc,MAAM,GAAG;AAChD,UAAM;AAEN,QAAI,UAAU;AACZ,UAAI;AACF,eAAO,IAAI,UAAU,KAAK,MAAM,QAAQ,CAAC;AAAA,MAC3C,SAAQ,GAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,2BACd,MACA,SACsB;AACtB,QAAM,EAAE,WAAW,mBAAmB,QAAQ,MAAA,IAAU,4BAAW,CAAA;AACnE,MAAI,uBAAuB;AAC3B,MAAI,iBAAgC;AACpC,MAAI,iBAAsC;AAC1C,MAAI,gBAA+B;AACnC,MAAI,mBAGO;AACX,MAAI,YAAY;AAChB,MAAI,gBAAgB;AACpB,QAAM,iBAAiB;AACvB,QAAM,qBAAuE,CAAA;AAC7E,MAAI,MAAM;AACV,QAAM,yCAAyB,IAAA;AAC/B,MAAI,iBAAwD;AAG5D,MAAI,oBAAoB;AACxB,MAAI,aAAa;AACjB,QAAM,uCAAuB,IAAA;AAC7B,QAAM,0CAA0B,IAAA;AAChC,MAAI,6BAA6D;AAEjE,QAAM,MAAM,QACR,IAAI,SAAoB,QAAQ,IAAI,4BAA4B,GAAG,IAAI,IACvE,MAAM;AAEV,QAAM,uBAAuB,CAAC,CAAC;AAC/B,MAAIA;AACJ,QAAM,kCAAkB,IAAA;AACxB,QAAM,gBAAgB,KAAK,MAAM,KAAK,OAAA,IAAW,UAAU,IAAI;AAC/D,QAAM,qCAAqB,IAAA;AAE3B,WAAS,sBAAqC;AAC5C,aAAS,uBAAuB;AAC9B,aAAO,kBAAA,OAAA,iBAAkB;AAAA,IAC3B;AAEA,WAAO;AAAA,MACL,IAAI,WAAW;AACb,eAAO,qBAAA;AAAA,MACT;AAAA,MACA,IAAI,SAAS;AACX,eAAO;AAAA,MACT;AAAA,MACA,YAAY;AACV,eAAO,IAAI,IAAI,WAAW;AAAA,MAC5B;AAAA,MACA,gBAAgB;AAzPtB,YAAA;AA0PQ,gBAAO,KAAA,YAAY,IAAI,qBAAA,CAAsB,MAAtC,OAAA,KAA2C;AAAA,MACpD;AAAA,MACA,cAAc,OAAuC;AACnD,cAAM,KAAK,qBAAA;AACX,YAAI,UAAU,MAAM;AAClB,sBAAY,OAAO,EAAE;AACrB,gBAAM,SAAS,EAAE,OAAO,CAAA,GAAI,SAAS,IAAI,SAAS,CAAC,EAAE,EAAA;AACrD,yBAAe,QAAQ,CAAA,YAAW,QAAQ,MAAM,CAAC;AAAA,QACnD,OAAO;AACL,gBAAM,UAAU,YAAY,IAAI,EAAE;AAClC,sBAAY,IAAI,IAAI,KAAK;AACzB,gBAAM,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA,GAAI,SAAS,CAAC,EAAE,GAAG,SAAS,CAAA,EAAC;AACvE,yBAAe,QAAQ,CAAA,YAAW,QAAQ,MAAM,CAAC;AAAA,QACnD;AAAA,MACF;AAAA,MACA,mBAAmB,OAAe,OAAgB;AAChD,cAAM,KAAK,qBAAA;AACX,cAAM,UAAU,YAAY,IAAI,EAAE,KAAK,CAAA;AACvC,cAAM,WAAW,cAAA,eAAA,CAAA,GAAK,OAAA,GAAL,EAAc,CAAC,KAAK,GAAG,OAAM;AAC9C,oBAAY,IAAI,IAAI,QAAQ;AAC5B,kCAA0B,OAAO,KAAK;AACtC,cAAM,SAAS,EAAE,OAAO,CAAA,GAAI,SAAS,CAAC,EAAE,GAAG,SAAS,GAAC;AACrD,uBAAe,QAAQ,CAAA,YAAW,QAAQ,MAAM,CAAC;AAAA,MACnD;AAAA,MACA,GAAG,OAAiB,SAAsF;AACxG,YAAI,UAAU,UAAU;AACtB,yBAAe,IAAI,OAAO;AAAA,QAC5B;AAAA,MACF;AAAA,MACA,IAAI,OAAiB,SAAsF;AACzG,YAAI,UAAU,UAAU;AACtB,yBAAe,OAAO,OAAO;AAAA,QAC/B;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ;AAEA,MAAI,mBAAmB;AACrBA,kBAAY;AAAA,EACd,OAAO;AACLA,kBAAY,oBAAA;AAAA,EACd;AAEA,WAAS,cAAc,SAAkB;AACvC,QAAI,mBAAmB,YAAY;AACjC,aAAO,EAAE,OAAO,QAAQ,WAAA;AAAA,IAC1B;AACA,QAAI,MAAM,QAAQ,OAAO,KAAK,QAAQ,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,GAAG;AAC/E,aAAO,EAAE,OAAO,QAAQ,OAAA;AAAA,IAC1B;AACA,WAAO;AAAA,EACT;AAEA,WAAS,WAAW,WAA4B,MAAc,SAAmB;AAC/E,QAAI,CAAC,MAAO;AACZ,QAAI,WAAW,MAAM,cAAc,OAAO,CAAC;AAAA,EAC7C;AAEA,WAAS,8BAA8B;AACrC,UAAM,QAAQA,YAAU,cAAA;AACxB,iCAA6B,QAAQ,mBAAK,KAAA,IAAU;AAAA,EACtD;AAEA,WAAS,0BAA0B,KAAa,OAAgB;AAC9D,QAAI,CAAC,aAAa,CAAC,uBAAuB,GAAG,EAAG;AAChD,UAAM,UAAU,EAAE,MAAM,mBAAmB,KAAK,MAAA;AAChD,eAAW,QAAQ,mBAAmB,OAAO;AAC7C,WAAO,OAAO,YAAY,SAAS,GAAG;AAAA,EACxC;AAEA,WAAS,kBAAkB,SAAkB;AAhU/C,QAAA;AAiUI,eAAW,SAAS,KAAA,QAA8B,SAA9B,OAAA,KAAsC,eAAe,OAAO;AAChF,WAAO,OAAO,YAAY,SAAS,GAAG;AAAA,EACxC;AAEA,WAAS,aAAa,OAAgB;AACpC,QAAI,cAAc,MAAO;AACzB,gBAAY;AACZ,QAAI,OAAO;AACT,sBAAgB;AAChB,kCAAA;AACA,aAAO,mBAAmB,SAAS,GAAG;AACpC,cAAM,EAAE,QAAQ,eAAe,mBAAmB,MAAA;AAClD,YAAI,YAAY;AACd,gBAAM,UAAU,EAAE,MAAM,eAAe,SAAS,MAAM,KAAK,MAAM,GAAG,WAAA;AACpE,iBAAO,OAAO,YAAY,SAAS,GAAG;AAAA,QACxC,OAAO;AACL,gBAAM,SAAS,EAAE;AACjB,gBAAM,UAAU,EAAE,MAAM,eAAe,SAAS,MAAM,KAAK,MAAM,GAAG,YAAY,KAAK,OAAA;AACrF,iBAAO,OAAO,YAAY,SAAS,GAAG;AACtC,6BAAmB,IAAI,QAAQ,EAAE,QAAQ,YAAY;AAAA,QACvD;AAAA,MACF;AACA,UAAI,CAAC,YAAY;AACf,mBAAW,CAAC,UAAU,EAAE,QAAQ,WAAA,CAAY,KAAK,oBAAoB;AACnE,gBAAM,UAAU,EAAE,MAAM,eAAe,SAAS,MAAM,KAAK,MAAM,GAAG,YAAY,KAAK,SAAA;AACrF,iBAAO,OAAO,YAAY,SAAS,GAAG;AAAA,QACxC;AAAA,MACF;AACA,uBAAiB,QAAQ,CAAC,OAAO,GAAA,CAAI;AAAA,IACvC,OAAO;AACL,mCAA6B;AAC7B,UAAI,CAAC,YAAY;AACf,2BAAmB,MAAA;AAAA,MACrB;AACA,0BAAoB,QAAQ,CAAC,OAAO,GAAA,CAAI;AAAA,IAC1C;AAAA,EACF;AAEA,WAAS,iBAAiB;AACxB,QAAI,gBAAgB;AAClB,oBAAc,cAAc;AAAA,IAC9B;AACA,QAAI,CAAC,iBAAiB,mBAAmB,SAAS,GAAG;AACnD,UAAI,CAAC,YAAY;AACf,cAAM,UAAU,mBAAmB,OAAO,CAAC;AAC3C,0BAAkB;AAAA,UAChB,MAAM;AAAA,UACN,SAAS,QAAQ,IAAI,CAAA,OAAM,EAAE,QAAQ,MAAM,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,aAAa;AAAA,QAAA,CACvF;AAAA,MACH,OAAO;AACL,mBAAW,EAAE,QAAQ,WAAA,KAAgB,oBAAoB;AACvD,4BAAkB,EAAE,MAAM,eAAe,SAAS,MAAM,KAAK,MAAM,GAAG,YAAY;AAAA,QACpF;AACA,2BAAmB,SAAS;AAAA,MAC9B;AAAA,IACF;AACA,sBAAkB,EAAE,MAAM,QAAQ;AAClC,qBAAiB,YAAY,MAAM;AACjC,UAAI,CAAC,WAAW;AACd,0BAAkB,EAAE,MAAM,QAAQ;AAAA,MACpC;AAAA,IACF,GAAG,GAAI;AAAA,EACT;AAEA,QAAM,eAAe,CAAC,QAAoB,WAAoB;AAC5D,QAAI,qBAAsB;AAE1B,UAAM,aAAa,WAAW,QAAQ,WAAW;AACjD,QAAI,CAAC,WAAW;AACd,UAAI,mBAAmB,UAAU,gBAAgB;AAC/C,wBAAgB;AAChB,2BAAmB,SAAS;AAC5B,gBAAQ,KAAK,4DAA4D;AAAA,MAC3E;AACA,yBAAmB,KAAK,EAAE,QAAQ,WAAA,CAAY;AAC9C;AAAA,IACF;AACA,QAAI,YAAY;AACd,YAAM,UAAU,EAAE,MAAM,eAAe,SAAS,MAAM,KAAK,MAAM,GAAG,WAAA;AACpE,iBAAW,QAAQ,eAAe,OAAO;AACzC,aAAO,OAAO,YAAY,SAAS,GAAG;AAAA,IACxC,OAAO;AACL,YAAM,SAAS,EAAE;AACjB,YAAM,UAAU,EAAE,MAAM,eAAe,SAAS,MAAM,KAAK,MAAM,GAAG,YAAY,KAAK,OAAA;AACrF,iBAAW,QAAQ,eAAe,OAAO;AACzC,aAAO,OAAO,YAAY,SAAS,GAAG;AACtC,yBAAmB,IAAI,QAAQ,EAAE,QAAQ,YAAY;AAAA,IACvD;AAAA,EACF;AAEA,QAAM,oBAAoB,CAAC;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,EAAA,MAKI;AACJ,QAAI,sBAAsB;AACxB;AAAA,IACF;AACA,QAAI,CAAC,WAAW;AACd;AAAA,IACF;AACA,UAAM,UAAU,CAAC,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO;AACjD,QAAI,QAAQ,WAAW,EAAG;AAE1B,UAAMC,iBAAgBD,YAAU;AAChC,UAAM,eAAe,QAAQ,SAASC,cAAa;AACnD,QAAI,CAAC,aAAc;AAEnB,UAAM,YAAYD,YAAU,cAAA;AAC5B,UAAM,eAAe;AAAA,MACnB;AAAA,MACA;AAAA,IAAA;AAEF,iCAA6B,YAAY,mBAAK,SAAA,IAAc;AAC5D,eAAW,EAAE,KAAK,MAAA,KAAW,cAAc;AACzC,gCAA0B,KAAK,KAAK;AAAA,IACtC;AAAA,EACF;AAEA,QAAM,0BAA0B,CAC9B,QACA,SACG;AACH,UAAM,EAAE,eAAe,cAAA,IAAkB;AACzC,UAAM,WAAW,OAAO;AACxB,UAAM,WAAW,iBAAiB;AAClC,UAAM,YAAY,iBAAiB,MAAM,iBAAiB;AAC1D,2BAAuB;AACvB,WAAO,UAAU,IAAI,MAAM,QAAQ,EAAE,KAAK,EAAE;AAC5C,WAAO,iBAAiB;AACxB,QAAI,aAAa,GAAG;AAClB,aAAO,UAAU,oBAAoB,OAAO,CAAC;AAAA,IAC/C,WAAW,WAAW,UAAU;AAC9B,aAAO;AAAA,QACL,oBAAoB,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAA,EAAC,EAAE,CAAG;AAAA,MAAA;AAAA,IAEzD,WAAW,WAAW,UAAU;AAC9B,aAAO;AAAA,QACL,oBAAoB,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAA,EAAC,EAAE,CAAG;AAAA,MAAA;AAAA,IAEzD,OAAO;AACL,aAAO;AAAA,QACL,oBAAoB,OAAO,EAAE,MAAM,EAAE,SAAS,CAAA,EAAC,EAAE,CAAG;AAAA,MAAA;AAAA,IAExD;AACA,2BAAuB;AAAA,EACzB;AAEA,QAAM,YAAY,CAAC,UAAwB;AACzC,QAAI,MAAM,WAAW,OAAO,OAAQ;AACpC,QAAI,CAAC,MAAM,QAAQ,OAAO,MAAM,SAAS,SAAU;AACnD,UAAM,EAAE,MAAM,SAAS,gBAAgB,iBAAA,IAAqB,MAAM;AAElE,eAAW,QAAQ,MAAM,OAAO;AAChC,QAAI,SAAS,UAAU,oBAAoB,MAAM;AAC/C,uBAAiB;AAEjB,UAAI,MAAM,KAAK,mBAAmB,GAAG;AACnC,4BAAoB;AACpB,YAAI,YAAY;AAEd,uBAAa;AACb,cAAI,oCAAoC,MAAM,KAAK,kBAAkB,0BAA0B;AAAA,QACjG,OAAO;AACL,cAAI,oCAAoC,MAAM,KAAK,kBAAkB,GAAG;AAAA,QAC1E;AAAA,MACF,WAAW,CAAC,mBAAmB;AAC7B,qBAAa;AACb,2BAAmB,MAAA;AACnB,YAAI,qDAAqD;AAAA,MAC3D;AACA;AAAA,IACF;AACA,QAAI,SAAS,mBAAmB;AAC9B,YAAM,SAAS,MAAM,KAAK;AAC1B,UAAI,UAAU,MAAM;AAClB,2BAAmB,OAAO,MAAM;AAAA,MAClC;AACA;AAAA,IACF;AAEA,QAAI,SAAS,eAAe,SAAS,eAAe;AAClD,6BAAuB;AACvBE,mBAAE,YAAY,MAAM,IAAI,WAAW,OAAO,CAAC;AAC3C,6BAAuB;AAEvB,UAAI,SAAS,eAAe,MAAM,KAAK,mBAAmB,MAAM;AAC9D,YAAI,MAAM,KAAK,mBAAmB,KAAK,CAAC,mBAAmB;AACzD,8BAAoB;AACpB,cAAI,oCAAoC,MAAM,KAAK,kBAAkB,kBAAkB;AAAA,QACzF;AAAA,MACF,WAAW,SAAS,eAAe,CAAC,qBAAqB,CAAC,YAAY;AAGpE,qBAAa;AACb,2BAAmB,MAAA;AACnB,YAAI,yDAAyD;AAAA,MAC/D;AACA,UAAI,SAAS,eAAe,CAAC,WAAW;AACtC,qBAAa,IAAI;AACjB,YAAI,gBAAgB;AAClB,wBAAc,cAAc;AAC5B,2BAAiB;AAAA,QACnB;AAAA,MACF;AAAA,IACF,WAAW,SAAS,oBAAoB,SAAS,oBAAoB;AACnE,iBAAW,QAAQ,MAAM,OAAO;AAChC,YAAM,cAAc;AACpB,UAAI,oBAAoB,MAAM;AAC5B,yBAAiB;AACjB,YAAI,yBAAyB,SAAS,oBAAoB,QAAQ,gBAAgB,kBAAkB;AAClG,gBAAM,YAAY,YAAY,IAAI,WAAW;AAC7C,cAAI,WAAW;AACb,wBAAY,OAAO,WAAW;AAC9B,wBAAY,IAAI,kBAAkB,SAAS;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAEA,UAAI,sBAAsB;AACxB,cAAM,WAAW,oBAAA,OAAA,mBAAoB;AACrC,cAAM,UAAUF,YAAU;AAE1B,+BAAuB;AACvB,YAAI,YAAY,QAAQ,aAAa,SAAS;AAC5C,gBAAM,WAAW;AAAA,YACf,IAAI,WAAW,OAAO;AAAA,YACtB;AAAA,YACA;AAAA,UAAA;AAGF,cAAI,SAAS,kBAAkB;AAC5BA,wBAAwB,KAAK,OAAO,OAAO;AAC5CA,wBAAU,cAAc,IAAI;AAAA,UAC9B;AAEAG,yCAAqBH,aAAwB,UAAU,IAAI;AAAA,QAC7D,OAAO;AACLG,oBAAAA,qBAAqBH,aAAwB,IAAI,WAAW,OAAO,GAAG,IAAI;AAAA,QAC5E;AACA,+BAAuB;AAAA,MACzB,OAAO;AACL,cAAM,eAAe,sBAAsB,IAAI,WAAW,OAAO,CAAC;AAClE,+BAAuB;AACvB,cAAM,mBAA6B,CAAA;AACnC,cAAM,mBAA6B,CAAA;AACnC,mBAAW,CAAC,IAAI,KAAK,KAAK,cAAc;AACtC,gBAAM,UAAU,YAAY,IAAI,EAAE;AAClC,gBAAM,UAAU,CAAC,WAAW,KAAK,UAAU,YAAY,IAAI,EAAE,CAAC,MAAM,KAAK,UAAU,KAAK;AACxF,sBAAY,IAAI,IAAI,KAAK;AACzB,cAAI,SAAS;AACX,6BAAiB,KAAK,EAAE;AAAA,UAC1B;AAAA,QACF;AACA,mBAAW,CAAC,EAAE,KAAK,aAAa;AAC9B,cAAI,CAAC,aAAa,IAAI,EAAE,GAAG;AACzB,wBAAY,OAAO,EAAE;AACrB,6BAAiB,KAAK,EAAE;AAAA,UAC1B;AAAA,QACF;AACA,YAAI,iBAAiB,SAAS,KAAK,iBAAiB,SAAS,GAAG;AAC9D,gBAAM,SAAS,EAAE,OAAO,CAAA,GAAI,SAAS,kBAAkB,SAAS,iBAAA;AAChE,yBAAe,QAAQ,CAAA,YAAW,QAAQ,MAAM,CAAC;AAAA,QACnD;AACA,+BAAuB;AAAA,MACzB;AAAA,IACF,WAAW,SAAS,cAAc;AAChC,UAAI,CAAC,eAAe;AAClB,2BAAmB,MAAM;AAAA,MAC3B,OAAO;AACL,gCAAwB,eAAe,MAAM,IAAI;AAAA,MACnD;AAAA,IACF,WAAW,SAAS,cAAc;AAChC,mBAAa,KAAK;AAClB,qBAAA;AAAA,IACF;AAAA,EACF;AAEA,OAAK,GAAG,UAAU,YAAY;AAG9B,MAAI,sBAAsB;AACvBA,gBAAwB,GAAG,UAAU,iBAAiB;AAAA,EACzD;AACA,SAAO,iBAAiB,WAAW,SAAS;AAE5C,iBAAA;AAGA,aAAW,MAAM;AACf,WAAO,OAAO,YAAY,EAAE,MAAM,OAAA,GAAU,GAAG;AAAA,EACjD,GAAG,GAAG;AAEN,SAAO;AAAA,IACL,IAAI,iBAAiB;AACnB,aAAO;AAAA,IACT;AAAA,IACA,IAAI,YAAY;AACd,aAAO;AAAA,IACT;AAAA,IACA,IAAI,YAAY;AACd,aAAOA;AAAAA,IACT;AAAA,IACA,UAAU,IAAgB;AACxB,uBAAiB,IAAI,EAAE;AACvB,aAAO,MAAM,iBAAiB,OAAO,EAAE;AAAA,IACzC;AAAA,IACA,aAAa,IAAgB;AAC3B,0BAAoB,IAAI,EAAE;AAC1B,aAAO,MAAM,oBAAoB,OAAO,EAAE;AAAA,IAC5C;AAAA,IACA,GAAG,OAAiC,IAAgB;AAClD,UAAI,UAAU,WAAW;AACvB,yBAAiB,IAAI,EAAE;AACvB,eAAO,MAAM,iBAAiB,OAAO,EAAE;AAAA,MACzC,OAAO;AACL,4BAAoB,IAAI,EAAE;AAC1B,eAAO,MAAM,oBAAoB,OAAO,EAAE;AAAA,MAC5C;AAAA,IACF;AAAA,IACA,eAAe,QAAiC;AAC9C,YAAM,eAAeA,YAAU,cAAA,KAAmB,CAAA;AAClD,YAAM,cAAe,aAAoD,QAAQ,CAAA;AACjF,YAAM,UAAU,kCAAK,WAAA,GAAgB,MAAA;AACrCA,kBAAU,cAAc,iCACnB,YAAA,GADmB;AAAA,QAEtB,MAAM;AAAA,MAAA,CACR,CAAC;AAED,UAAI,WAAW;AACb,cAAM,UAAU,EAAE,MAAM,oBAAoB,OAAA;AAC5C,mBAAW,QAAQ,oBAAoB,MAAM;AAC7C,eAAO,OAAO,YAAY,SAAS,GAAG;AAAA,MACxC;AAAA,IACF;AAAA,IACA,oBAAoB,MAAkB;AACpC,UAAI,gBAAgB;AAClB,uBAAA;AAAA,MACF;AAEA,YAAM,SAAS,KAAK,MAAA,EAAQ;AAC5B,YAAM,oBAAoB,OAAO;AAGjC,UAAI,qBAAqB,QAAQ,mBAAmB;AAClD,cAAMI,UAAS;AACf,cAAM,WAAWA,QAAO,KAAK,KAAKA,OAAM;AACxC,cAAM,WAAWA,QAAO,KAAK,KAAKA,OAAM;AACxC,cAAM,cAAcA,QAAO,QAAQ,KAAKA,OAAM;AAC9C,cAAM,cAAcA,QAAO,QAAQ,KAAKA,OAAM;AAC9C,wBAAgBA;AAChBA,gBAAO,OAAO,MAAM;AAClB,cAAI,CAAC,sBAAsB;AACzB,mBAAO,OAAO,YAAY,EAAE,MAAM,OAAA,GAAU,GAAG;AAAA,UACjD,OAAO;AACL,qBAAA;AAAA,UACF;AAAA,QACF;AACAA,gBAAO,OAAO,MAAM;AAClB,cAAI,CAAC,sBAAsB;AACzB,mBAAO,OAAO,YAAY,EAAE,MAAM,OAAA,GAAU,GAAG;AAAA,UACjD,OAAO;AACL,qBAAA;AAAA,UACF;AAAA,QACF;AACAA,gBAAO,UAAU,MAAMA,QAAO,iBAAiB;AAC/CA,gBAAO,UAAU,MAAMA,QAAO,iBAAiBA,QAAO,QAAQ;AAC9D,YAAI,kBAAkB;AACpB,kCAAwBA,SAAQ,gBAAgB;AAChD,6BAAmB;AAAA,QACrB;AACA,eAAO,OAAO,YAAY,EAAE,MAAM,qBAAA,GAAwB,GAAG;AAC7D,cAAMC,WAAU,MAAM;AACpBD,kBAAO,OAAO;AACdA,kBAAO,OAAO;AACdA,kBAAO,UAAU;AACjBA,kBAAO,UAAU;AACjB,0BAAgB;AAChB,6BAAmB;AAAA,QACrB;AACA,yBAAiBC;AACjB,eAAOA;AAAAA,MACT;AAEA,YAAM,QAAqC,CAAA;AAC3C,YAAM,MAAM,MAAM,QAAQ,qBAAA,OAAA,SAAA,kBAAmB,cAAc,IACtD,kBAAkB,iBACnB,CAAA;AACJ,eAAS,IAAI,GAAG,IAAI,IAAI,IAAI,QAAQ,KAAK,GAAG;AAC1C,cAAM,MAAM,OAAO,IAAI,CAAC,CAAC;AACzB,cAAM,KAAK,IAAI,IAAI,CAAC;AACpB,cAAM,KAAK,CAAC,KAAK,EAAE,CAAC;AAAA,MACtB;AAEA,YAAM,SAAiB;AAAA,QACrB,gBAAgB,CAAA;AAAA,QAChB,SAAS,CAAA;AAAA,QACT,gBAAgB;AAAA,QAEhB,YAAY,MAAc,IAAgB;AACxC,eAAK,eAAe,KAAK,MAAM,EAAE;AAAA,QACnC;AAAA,QAEA,UAAU,KAAc;AAxtBhC,cAAA,IAAA;AAytBU,gBAAM,aACH,OAAA,OAAA,SAAA,IAAuC,WACtC,MAAA,KAAA,OAAA,OAAA,SAAA,IAAgD,YAAhD,OAAA,SAAA,GAAA,KAAA,GAAA,MAAA,OAAA,KACA;AACJ,mBAAS,IAAI,GAAG,IAAI,IAAI,KAAK,eAAe,QAAQ,KAAK,GAAG;AAC1D,kBAAM,MAAM,KAAK,eAAe,CAAC;AACjC,kBAAM,WAAW,KAAK,eAAe,IAAI,CAAC;AAC1C,gBAAI,QAAQ,WAAW;AACrB,kBAAI;AACF,yBAAS,MAAM,GAAG;AAAA,cACpB,SAAS,GAAG;AACV,wBAAQ;AAAA,kBACN;AAAA,kBACA;AAAA,gBAAA;AAAA,cAEJ;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QAEA,UAAmB;AACjB,iBAAO,KAAK,iBAAiB;AAAA,QAC/B;AAAA,QAEA,UAAmB;AACjB,iBAAO,KAAK,iBAAiB,KAAK,QAAQ;AAAA,QAC5C;AAAA,QAEA,OAAO;AACL,cAAI,CAAC,sBAAsB;AACzB,mBAAO,OAAO,YAAY,EAAE,MAAM,OAAA,GAAU,GAAG;AAAA,UACjD;AAAA,QACF;AAAA,QAEA,OAAO;AACL,cAAI,CAAC,sBAAsB;AACzB,mBAAO,OAAO,YAAY,EAAE,MAAM,OAAA,GAAU,GAAG;AAAA,UACjD;AAAA,QACF;AAAA,QAEA,uBAAuB;AAAA,QAEvB;AAAA,MAAA;AAGF,YAAM,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM;AAC3B,cAAM,IAAI,IAAI,YAAA;AACd,YAAI,MAAM,SAAS,MAAM,WAAW,MAAM,UAAU,MAAM,QAAQ;AAChE,iBAAO,YAAY,GAAG,EAAE;AAAA,QAC1B;AAAA,MACF,CAAC;AAED,sBAAgB;AAChB,aAAO,cAAc;AACrB,aAAO,eAAe,WAAY;AAAA,MAAC;AAEnC,UAAI,kBAAkB;AACpB,gCAAwB,QAAQ,gBAAgB;AAChD,2BAAmB;AAAA,MACrB;AACA,aAAO,OAAO,YAAY,EAAE,MAAM,qBAAA,GAAwB,GAAG;AAE7D,YAAM,UAAU,MAAM;AACpB,eAAO,cAAc;AACrB,eAAO,eAAe,qBAAA,OAAA,SAAA,kBAAmB;AAGzC,wBAAgB;AAChB,2BAAmB;AAAA,MACrB;AAEA,uBAAiB;AACjB,aAAO;AAAA,IACT;AAAA,IACA,SAAS,MAAM;AACb,aAAO,mBAAmB,SAAS,GAAG;AACpC,cAAM,EAAE,QAAQ,eAAe,mBAAmB,MAAA;AAClD,eAAO,OAAO,YAAY,EAAE,MAAM,eAAe,SAAS,MAAM,KAAK,MAAM,GAAG,WAAA,GAAc,GAAG;AAAA,MACjG;AACA,yBAAmB,MAAA;AACnB,WAAK,IAAI,UAAU,YAAY;AAC/B,UAAI,sBAAsB;AACvBL,oBAAwB,IAAI,UAAU,iBAAiB;AAAA,MAC1D;AACA,aAAO,oBAAoB,WAAW,SAAS;AAC/C,UAAI,gBAAgB;AAClB,sBAAc,cAAc;AAC5B,yBAAiB;AAAA,MACnB;AACA,uBAAiB,MAAA;AACjB,0BAAoB,MAAA;AACpB,UAAI,gBAAgB;AAClB,uBAAA;AAAA,MACF;AAAA,IACF;AAAA,EAAA;AAEJ;;"}
|
|
@@ -139,6 +139,8 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
139
139
|
let seq = 0;
|
|
140
140
|
const unackedYdocUpdates = /* @__PURE__ */ new Map();
|
|
141
141
|
let initRetryTimer = null;
|
|
142
|
+
let serverSupportsAck = false;
|
|
143
|
+
let legacyMode = false;
|
|
142
144
|
const connectListeners = /* @__PURE__ */ new Set();
|
|
143
145
|
const disconnectListeners = /* @__PURE__ */ new Set();
|
|
144
146
|
let lastLocalAwarenessSnapshot = null;
|
|
@@ -241,19 +243,28 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
241
243
|
snapshotLocalAwarenessState();
|
|
242
244
|
while (pendingYdocUpdates.length > 0) {
|
|
243
245
|
const { update, isBaseline } = pendingYdocUpdates.shift();
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
246
|
+
if (legacyMode) {
|
|
247
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline };
|
|
248
|
+
window.parent.postMessage(message, "*");
|
|
249
|
+
} else {
|
|
250
|
+
const seqNum = ++seq;
|
|
251
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
252
|
+
window.parent.postMessage(message, "*");
|
|
253
|
+
unackedYdocUpdates.set(seqNum, { update, isBaseline });
|
|
254
|
+
}
|
|
248
255
|
}
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
256
|
+
if (!legacyMode) {
|
|
257
|
+
for (const [savedSeq, { update, isBaseline }] of unackedYdocUpdates) {
|
|
258
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: savedSeq };
|
|
259
|
+
window.parent.postMessage(message, "*");
|
|
260
|
+
}
|
|
252
261
|
}
|
|
253
262
|
connectListeners.forEach((fn) => fn());
|
|
254
263
|
} else {
|
|
255
264
|
lastLocalAwarenessSnapshot = null;
|
|
256
|
-
|
|
265
|
+
if (!legacyMode) {
|
|
266
|
+
unackedYdocUpdates.clear();
|
|
267
|
+
}
|
|
257
268
|
disconnectListeners.forEach((fn) => fn());
|
|
258
269
|
}
|
|
259
270
|
}
|
|
@@ -262,11 +273,18 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
262
273
|
clearInterval(initRetryTimer);
|
|
263
274
|
}
|
|
264
275
|
if (!forceFullSync && pendingYdocUpdates.length > 0) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
276
|
+
if (!legacyMode) {
|
|
277
|
+
const updates = pendingYdocUpdates.splice(0);
|
|
278
|
+
parentPostMessage({
|
|
279
|
+
type: "ydoc-pending-updates",
|
|
280
|
+
payload: updates.map((u) => ({ update: Array.from(u.update), isBaseline: u.isBaseline }))
|
|
281
|
+
});
|
|
282
|
+
} else {
|
|
283
|
+
for (const { update, isBaseline } of pendingYdocUpdates) {
|
|
284
|
+
parentPostMessage({ type: "ydoc-update", payload: Array.from(update), isBaseline });
|
|
285
|
+
}
|
|
286
|
+
pendingYdocUpdates.length = 0;
|
|
287
|
+
}
|
|
270
288
|
}
|
|
271
289
|
parentPostMessage({ type: "init" });
|
|
272
290
|
initRetryTimer = setInterval(() => {
|
|
@@ -287,11 +305,17 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
287
305
|
pendingYdocUpdates.push({ update, isBaseline });
|
|
288
306
|
return;
|
|
289
307
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
308
|
+
if (legacyMode) {
|
|
309
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline };
|
|
310
|
+
logMessage("send", "ydoc-update", message);
|
|
311
|
+
window.parent.postMessage(message, "*");
|
|
312
|
+
} else {
|
|
313
|
+
const seqNum = ++seq;
|
|
314
|
+
const message = { type: "ydoc-update", payload: Array.from(update), isBaseline, seq: seqNum };
|
|
315
|
+
logMessage("send", "ydoc-update", message);
|
|
316
|
+
window.parent.postMessage(message, "*");
|
|
317
|
+
unackedYdocUpdates.set(seqNum, { update, isBaseline });
|
|
318
|
+
}
|
|
295
319
|
};
|
|
296
320
|
const onAwarenessUpdate = ({
|
|
297
321
|
added,
|
|
@@ -349,6 +373,23 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
349
373
|
if (!event.data || typeof event.data !== "object") return;
|
|
350
374
|
const { type, payload, serverClientId: receivedServerId } = event.data;
|
|
351
375
|
logMessage("recv", type, payload);
|
|
376
|
+
if (type === "pong" && receivedServerId != null) {
|
|
377
|
+
serverClientId = receivedServerId;
|
|
378
|
+
if (event.data.protocolVersion >= 2) {
|
|
379
|
+
serverSupportsAck = true;
|
|
380
|
+
if (legacyMode) {
|
|
381
|
+
legacyMode = false;
|
|
382
|
+
log("server supports ack (protocol v" + event.data.protocolVersion + ", corrected from legacy)");
|
|
383
|
+
} else {
|
|
384
|
+
log("server supports ack (protocol v" + event.data.protocolVersion + ")");
|
|
385
|
+
}
|
|
386
|
+
} else if (!serverSupportsAck) {
|
|
387
|
+
legacyMode = true;
|
|
388
|
+
unackedYdocUpdates.clear();
|
|
389
|
+
log("legacy mode detected: server has no protocolVersion");
|
|
390
|
+
}
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
352
393
|
if (type === "ydoc-update-ack") {
|
|
353
394
|
const ackSeq = event.data.seq;
|
|
354
395
|
if (ackSeq != null) {
|
|
@@ -356,14 +397,20 @@ function createIframeBridgeProvider(ydoc, options) {
|
|
|
356
397
|
}
|
|
357
398
|
return;
|
|
358
399
|
}
|
|
359
|
-
if (type === "pong" && receivedServerId != null) {
|
|
360
|
-
serverClientId = receivedServerId;
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
400
|
if (type === "ydoc-sync" || type === "ydoc-update") {
|
|
364
401
|
applyingParentUpdate = true;
|
|
365
402
|
Y.applyUpdate(ydoc, new Uint8Array(payload));
|
|
366
403
|
applyingParentUpdate = false;
|
|
404
|
+
if (type === "ydoc-sync" && event.data.protocolVersion != null) {
|
|
405
|
+
if (event.data.protocolVersion >= 2 && !serverSupportsAck) {
|
|
406
|
+
serverSupportsAck = true;
|
|
407
|
+
log("server supports ack (protocol v" + event.data.protocolVersion + ", via ydoc-sync)");
|
|
408
|
+
}
|
|
409
|
+
} else if (type === "ydoc-sync" && !serverSupportsAck && !legacyMode) {
|
|
410
|
+
legacyMode = true;
|
|
411
|
+
unackedYdocUpdates.clear();
|
|
412
|
+
log("legacy mode tentative: ydoc-sync has no protocolVersion");
|
|
413
|
+
}
|
|
367
414
|
if (type === "ydoc-sync" && !connected) {
|
|
368
415
|
setConnected(true);
|
|
369
416
|
if (initRetryTimer) {
|
|
@@ -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 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 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 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 connectListeners.forEach((fn) => fn());\n } else {\n lastLocalAwarenessSnapshot = null;\n unackedYdocUpdates.clear();\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 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 }\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 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 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 === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedYdocUpdates.delete(ackSeq);\n }\n return;\n }\n if (type === \"pong\" && receivedServerId != null) {\n serverClientId = receivedServerId;\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 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\";\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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"}
|
package/iframe-bridge/server.cjs
CHANGED
|
@@ -126,7 +126,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
126
126
|
}
|
|
127
127
|
function postToIframe(type, payload) {
|
|
128
128
|
const cw = iframe.contentWindow;
|
|
129
|
-
const message = { type, payload:
|
|
129
|
+
const message = { type, payload: [] };
|
|
130
130
|
logMessage("send", type, payload);
|
|
131
131
|
if (cw) {
|
|
132
132
|
cw.postMessage(message, "*");
|
|
@@ -217,7 +217,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
217
217
|
}
|
|
218
218
|
const docState = Y__namespace.encodeStateAsUpdate(ydoc);
|
|
219
219
|
logMessage("send", "ydoc-sync", { bytes: docState.length });
|
|
220
|
-
|
|
220
|
+
postObjectToIframe({ type: "ydoc-sync", payload: Array.from(docState), protocolVersion: 2 });
|
|
221
221
|
unackedServerUpdates.clear();
|
|
222
222
|
const cw = iframe.contentWindow;
|
|
223
223
|
if (cw) {
|
|
@@ -253,7 +253,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
|
253
253
|
logMessage("recv", "ping", payload);
|
|
254
254
|
const cw = iframe.contentWindow;
|
|
255
255
|
if (cw) {
|
|
256
|
-
const message = { type: "pong", serverClientId: awareness$1.clientID };
|
|
256
|
+
const message = { type: "pong", serverClientId: awareness$1.clientID, protocolVersion: 2 };
|
|
257
257
|
logMessage("send", "pong", message);
|
|
258
258
|
cw.postMessage(message, "*");
|
|
259
259
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.cjs","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n\n/**\n * 基线数据标记(用于首次初始化)。\n * 此 origin 的更新不应进入 UndoManager 的撤销栈。\n */\nexport const BASELINE_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN, BASELINE_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n debug?: boolean;\n}\n\nexport interface IframeBridgeServer {\n connected: boolean;\n onConnect: (fn: () => void) => () => void;\n onDisconnect: (fn: () => void) => () => void;\n on: (event: \"connect\" | \"disconnect\", fn: () => void) => () => void;\n destroy: () => void;\n}\n\nexport function createIframeBridgeServer(\n iframe: HTMLIFrameElement,\n ydoc: Y.Doc,\n awareness: Awareness,\n options?: IframeBridgeServerOptions,\n): IframeBridgeServer {\n const { undoManager, debug = false } = options ?? {};\n const log = debug\n ? (...args: unknown[]) => console.log(\"[iframe-bridge server]\", ...args)\n : () => undefined;\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 let connected = false;\n let forceFullSync = false;\n let applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\n const MAX_QUEUE_SIZE = 1000;\n const pendingUpdatesToIframe: Array<{ update: Uint8Array; isBaseline: boolean }> = [];\n let serverSeq = 0;\n const unackedServerUpdates = new Map<number, { update: Uint8Array; isBaseline: boolean }>();\n\n function tryAddIframeOriginTracking() {\n if (!undoManager) return;\n try {\n if (typeof (undoManager as any).addTrackedOrigin === \"function\") {\n (undoManager as any).addTrackedOrigin(IFRAME_ORIGIN);\n iframeOriginTracked = true;\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to add IFRAME_ORIGIN to UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n function tryRemoveIframeOriginTracking() {\n if (!undoManager || !iframeOriginTracked) return;\n try {\n if (typeof (undoManager as any).removeTrackedOrigin === \"function\") {\n (undoManager as any).removeTrackedOrigin(IFRAME_ORIGIN);\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to remove IFRAME_ORIGIN from UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n tryAddIframeOriginTracking();\n\n function setConnected(value: boolean) {\n if (connected === value) return;\n connected = value;\n if (value) {\n const wasForceFullSync = forceFullSync;\n forceFullSync = false;\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n }\n if (!wasForceFullSync) {\n for (const [savedSeq, { update, isBaseline }] of unackedServerUpdates) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: savedSeq }, \"*\");\n }\n }\n }\n connectListeners.forEach((fn) => fn());\n } else {\n unackedServerUpdates.clear();\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function postToIframe(type: string, payload?: Uint8Array) {\n const cw = iframe.contentWindow;\n const message = { type, payload: payload ? Array.from(payload) : [] };\n logMessage(\"send\", type, payload);\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n function postObjectToIframe(message: Record<string, unknown>) {\n const type = message.type as string;\n logMessage(\"send\", type, message);\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (origin === IFRAME_ORIGIN) return;\n // 检测基线数据:origin 为 null 时是 xml2ydoc 首次初始化\n const isBaseline = origin === null || origin === undefined;\n logMessage(\"send\", \"ydoc-update\", update);\n if (!connected) {\n if (pendingUpdatesToIframe.length >= MAX_QUEUE_SIZE) {\n forceFullSync = true;\n pendingUpdatesToIframe.length = 0;\n console.warn(\"[iframe-bridge server] queue full, forcing full sync on reconnect\");\n }\n pendingUpdatesToIframe.push({ update, isBaseline });\n return;\n }\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n };\n\n function postUndoStateToIframe() {\n if (!undoManager) return;\n const undoStack = (undoManager as any).undoStack;\n const redoStack = (undoManager as any).redoStack;\n const cw = iframe.contentWindow;\n if (cw) {\n const state = {\n type: \"undo-state\",\n canUndo: undoManager.canUndo(),\n canRedo: undoManager.canRedo(),\n undoStackSize: undoStack?.length ?? 0,\n redoStackSize: redoStack?.length ?? 0,\n };\n logMessage(\"send\", \"undo-state\", state);\n cw.postMessage(state, \"*\");\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 (applyingIframeUpdate) return;\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n // 把所有变化的 clientID 都发送给 iframe(包括其他 Webrtc peers 的光标更新)\n // 但要注意:server 自身的 clientID 需要被 iframe 识别为 serverClientId\n const update = encodeAwarenessUpdate(awareness, changes);\n logMessage(\"send\", \"awareness-update\", update);\n postObjectToIframe({\n type: \"awareness-update\",\n payload: Array.from(update),\n serverClientId: awareness.clientID,\n });\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n\n const { type: msgType, payload } = event.data;\n\n if (msgType === \"ydoc-pending-updates\") {\n logMessage(\"recv\", \"ydoc-pending-updates\", payload);\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const arr = item.update ?? item;\n const isBaseline = item.isBaseline ?? false;\n const update = new Uint8Array(arr);\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n }\n }\n } else if (msgType === \"init\") {\n logMessage(\"recv\", \"init\", payload);\n if (!connected) {\n setConnected(true);\n }\n const docState = Y.encodeStateAsUpdate(ydoc);\n logMessage(\"send\", \"ydoc-sync\", { bytes: docState.length });\n postToIframe(\"ydoc-sync\", new Uint8Array(Array.from(docState)));\n unackedServerUpdates.clear();\n // 在单独的 postMessage 中发送 serverClientId,方便 iframe 接收\n const cw = iframe.contentWindow;\n if (cw) {\n const states = awareness.getStates();\n const statesArray = Array.from(states.entries());\n log(\"[DEBUG] server sending awareness-sync - detailed\", {\n serverClientId: awareness.clientID,\n statesCount: states.size,\n statesArray: statesArray.map(([id, state]) => ({\n clientId: id,\n user: (state as Record<string, unknown>)?.user,\n hasUser: !!(state as Record<string, unknown>)?.user,\n })),\n });\n const message = {\n type: \"awareness-sync\",\n payload: Array.from(encodeAwarenessUpdate(\n awareness,\n Array.from(states.keys()),\n )),\n serverClientId: awareness.clientID,\n };\n log(\"[DEBUG] server sending awareness-sync\", {\n serverClientId: awareness.clientID,\n states: Object.fromEntries(states),\n payloadLength: message.payload.length,\n });\n logMessage(\"send\", \"awareness-sync\", message);\n cw.postMessage(message, \"*\");\n }\n // 同步初始 undo 状态\n postUndoStateToIframe();\n } else if (msgType === \"ping\") {\n logMessage(\"recv\", \"ping\", payload);\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"pong\", serverClientId: awareness.clientID };\n logMessage(\"send\", \"pong\", message);\n cw.postMessage(message, \"*\");\n }\n } else if (msgType === \"ydoc-update\") {\n logMessage(\"recv\", \"ydoc-update\", payload);\n const update = new Uint8Array(payload);\n const isBaseline = event.data.isBaseline;\n // 基线数据使用 BASELINE_ORIGIN(不进入 undo 栈),编辑数据使用 IFRAME_ORIGIN\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n // 源 iframe 已经持有此 update,无需回传\n const inSeq = event.data.seq;\n if (inSeq != null) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update-ack\", seq: inSeq }, \"*\");\n }\n }\n } else if (msgType === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedServerUpdates.delete(ackSeq);\n }\n } else if (msgType === \"awareness-local-state\") {\n // 保留消息类型兼容旧客户端,已不再采用\n logMessage(\"recv\", \"awareness-local-state (ignored)\", payload);\n } else if (msgType === \"set-local-state\") {\n const { key, value } = event.data as {\n key?: string;\n value?: unknown;\n };\n logMessage(\"recv\", \"set-local-state\", { key, value });\n if (typeof key === \"string\") {\n applyingIframeUpdate = true;\n awareness.setLocalStateField(key, value);\n applyingIframeUpdate = false;\n }\n } else if (msgType === \"awareness-update\") {\n logMessage(\"recv\", \"awareness-update\", payload);\n // 应用 iframe 的 awareness 更新时设置标志,防止触发 onAwarenessUpdate 回传\n applyingIframeUpdate = true;\n applyAwarenessUpdate(awareness, new Uint8Array(payload), IFRAME_ORIGIN);\n applyingIframeUpdate = false;\n } else if (msgType === \"set-local-fields\") {\n logMessage(\"recv\", \"set-local-fields\", payload);\n const { fields } = event.data;\n if (fields && typeof fields === \"object\") {\n applyingIframeUpdate = true;\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 applyingIframeUpdate = false;\n }\n } else if (msgType === \"request-undo-state\") {\n postUndoStateToIframe();\n } else if (msgType === \"undo\" && undoManager) {\n undoManager.undo();\n postUndoStateToIframe();\n } else if (msgType === \"redo\" && undoManager) {\n undoManager.redo();\n postUndoStateToIframe();\n }\n };\n\n const onUndoPopped = () => {\n postUndoStateToIframe();\n };\n\n const onStackCleared = () => {\n postUndoStateToIframe();\n };\n\n const onStackItemAdded = () => {\n postUndoStateToIframe();\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.on(\"stack-item-popped\", onUndoPopped);\n undoManager.on(\"stack-cleared\", onStackCleared);\n undoManager.on(\"stack-item-added\", onStackItemAdded);\n }\n\n return {\n get connected() {\n return connected;\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 destroy: () => {\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline }, \"*\");\n }\n }\n setConnected(false);\n postToIframe(\"disconnect\");\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.off(\"stack-item-popped\", onUndoPopped);\n undoManager.off(\"stack-cleared\", onStackCleared);\n undoManager.off(\"stack-item-added\", onStackItemAdded);\n tryRemoveIframeOriginTracking();\n }\n connectListeners.clear();\n disconnectListeners.clear();\n },\n };\n}\n"],"names":["awareness","encodeAwarenessUpdate","Y","applyAwarenessUpdate"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.cjs","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n\n/**\n * 基线数据标记(用于首次初始化)。\n * 此 origin 的更新不应进入 UndoManager 的撤销栈。\n */\nexport const BASELINE_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN, BASELINE_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n debug?: boolean;\n}\n\nexport interface IframeBridgeServer {\n connected: boolean;\n onConnect: (fn: () => void) => () => void;\n onDisconnect: (fn: () => void) => () => void;\n on: (event: \"connect\" | \"disconnect\", fn: () => void) => () => void;\n destroy: () => void;\n}\n\nexport function createIframeBridgeServer(\n iframe: HTMLIFrameElement,\n ydoc: Y.Doc,\n awareness: Awareness,\n options?: IframeBridgeServerOptions,\n): IframeBridgeServer {\n const { undoManager, debug = false } = options ?? {};\n const log = debug\n ? (...args: unknown[]) => console.log(\"[iframe-bridge server]\", ...args)\n : () => undefined;\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 let connected = false;\n let forceFullSync = false;\n let applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\n const MAX_QUEUE_SIZE = 1000;\n const pendingUpdatesToIframe: Array<{ update: Uint8Array; isBaseline: boolean }> = [];\n let serverSeq = 0;\n const unackedServerUpdates = new Map<number, { update: Uint8Array; isBaseline: boolean }>();\n\n function tryAddIframeOriginTracking() {\n if (!undoManager) return;\n try {\n if (typeof (undoManager as any).addTrackedOrigin === \"function\") {\n (undoManager as any).addTrackedOrigin(IFRAME_ORIGIN);\n iframeOriginTracked = true;\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to add IFRAME_ORIGIN to UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n function tryRemoveIframeOriginTracking() {\n if (!undoManager || !iframeOriginTracked) return;\n try {\n if (typeof (undoManager as any).removeTrackedOrigin === \"function\") {\n (undoManager as any).removeTrackedOrigin(IFRAME_ORIGIN);\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to remove IFRAME_ORIGIN from UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n tryAddIframeOriginTracking();\n\n function setConnected(value: boolean) {\n if (connected === value) return;\n connected = value;\n if (value) {\n const wasForceFullSync = forceFullSync;\n forceFullSync = false;\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n }\n if (!wasForceFullSync) {\n for (const [savedSeq, { update, isBaseline }] of unackedServerUpdates) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: savedSeq }, \"*\");\n }\n }\n }\n connectListeners.forEach((fn) => fn());\n } else {\n unackedServerUpdates.clear();\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function postToIframe(type: string, payload?: Uint8Array) {\n const cw = iframe.contentWindow;\n const message = { type, payload: payload ? Array.from(payload) : [] };\n logMessage(\"send\", type, payload);\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n function postObjectToIframe(message: Record<string, unknown>) {\n const type = message.type as string;\n logMessage(\"send\", type, message);\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (origin === IFRAME_ORIGIN) return;\n // 检测基线数据:origin 为 null 时是 xml2ydoc 首次初始化\n const isBaseline = origin === null || origin === undefined;\n logMessage(\"send\", \"ydoc-update\", update);\n if (!connected) {\n if (pendingUpdatesToIframe.length >= MAX_QUEUE_SIZE) {\n forceFullSync = true;\n pendingUpdatesToIframe.length = 0;\n console.warn(\"[iframe-bridge server] queue full, forcing full sync on reconnect\");\n }\n pendingUpdatesToIframe.push({ update, isBaseline });\n return;\n }\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n };\n\n function postUndoStateToIframe() {\n if (!undoManager) return;\n const undoStack = (undoManager as any).undoStack;\n const redoStack = (undoManager as any).redoStack;\n const cw = iframe.contentWindow;\n if (cw) {\n const state = {\n type: \"undo-state\",\n canUndo: undoManager.canUndo(),\n canRedo: undoManager.canRedo(),\n undoStackSize: undoStack?.length ?? 0,\n redoStackSize: redoStack?.length ?? 0,\n };\n logMessage(\"send\", \"undo-state\", state);\n cw.postMessage(state, \"*\");\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 (applyingIframeUpdate) return;\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n // 把所有变化的 clientID 都发送给 iframe(包括其他 Webrtc peers 的光标更新)\n // 但要注意:server 自身的 clientID 需要被 iframe 识别为 serverClientId\n const update = encodeAwarenessUpdate(awareness, changes);\n logMessage(\"send\", \"awareness-update\", update);\n postObjectToIframe({\n type: \"awareness-update\",\n payload: Array.from(update),\n serverClientId: awareness.clientID,\n });\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n\n const { type: msgType, payload } = event.data;\n\n if (msgType === \"ydoc-pending-updates\") {\n logMessage(\"recv\", \"ydoc-pending-updates\", payload);\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const arr = item.update ?? item;\n const isBaseline = item.isBaseline ?? false;\n const update = new Uint8Array(arr);\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n }\n }\n } else if (msgType === \"init\") {\n logMessage(\"recv\", \"init\", payload);\n if (!connected) {\n setConnected(true);\n }\n const docState = Y.encodeStateAsUpdate(ydoc);\n logMessage(\"send\", \"ydoc-sync\", { bytes: docState.length });\n postObjectToIframe({ type: \"ydoc-sync\", payload: Array.from(docState), protocolVersion: 2 });\n unackedServerUpdates.clear();\n // 在单独的 postMessage 中发送 serverClientId,方便 iframe 接收\n const cw = iframe.contentWindow;\n if (cw) {\n const states = awareness.getStates();\n const statesArray = Array.from(states.entries());\n log(\"[DEBUG] server sending awareness-sync - detailed\", {\n serverClientId: awareness.clientID,\n statesCount: states.size,\n statesArray: statesArray.map(([id, state]) => ({\n clientId: id,\n user: (state as Record<string, unknown>)?.user,\n hasUser: !!(state as Record<string, unknown>)?.user,\n })),\n });\n const message = {\n type: \"awareness-sync\",\n payload: Array.from(encodeAwarenessUpdate(\n awareness,\n Array.from(states.keys()),\n )),\n serverClientId: awareness.clientID,\n };\n log(\"[DEBUG] server sending awareness-sync\", {\n serverClientId: awareness.clientID,\n states: Object.fromEntries(states),\n payloadLength: message.payload.length,\n });\n logMessage(\"send\", \"awareness-sync\", message);\n cw.postMessage(message, \"*\");\n }\n // 同步初始 undo 状态\n postUndoStateToIframe();\n } else if (msgType === \"ping\") {\n logMessage(\"recv\", \"ping\", payload);\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"pong\", serverClientId: awareness.clientID, protocolVersion: 2 };\n logMessage(\"send\", \"pong\", message);\n cw.postMessage(message, \"*\");\n }\n } else if (msgType === \"ydoc-update\") {\n logMessage(\"recv\", \"ydoc-update\", payload);\n const update = new Uint8Array(payload);\n const isBaseline = event.data.isBaseline;\n // 基线数据使用 BASELINE_ORIGIN(不进入 undo 栈),编辑数据使用 IFRAME_ORIGIN\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n // 源 iframe 已经持有此 update,无需回传\n const inSeq = event.data.seq;\n if (inSeq != null) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update-ack\", seq: inSeq }, \"*\");\n }\n }\n } else if (msgType === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedServerUpdates.delete(ackSeq);\n }\n } else if (msgType === \"awareness-local-state\") {\n // 保留消息类型兼容旧客户端,已不再采用\n logMessage(\"recv\", \"awareness-local-state (ignored)\", payload);\n } else if (msgType === \"set-local-state\") {\n const { key, value } = event.data as {\n key?: string;\n value?: unknown;\n };\n logMessage(\"recv\", \"set-local-state\", { key, value });\n if (typeof key === \"string\") {\n applyingIframeUpdate = true;\n awareness.setLocalStateField(key, value);\n applyingIframeUpdate = false;\n }\n } else if (msgType === \"awareness-update\") {\n logMessage(\"recv\", \"awareness-update\", payload);\n // 应用 iframe 的 awareness 更新时设置标志,防止触发 onAwarenessUpdate 回传\n applyingIframeUpdate = true;\n applyAwarenessUpdate(awareness, new Uint8Array(payload), IFRAME_ORIGIN);\n applyingIframeUpdate = false;\n } else if (msgType === \"set-local-fields\") {\n logMessage(\"recv\", \"set-local-fields\", payload);\n const { fields } = event.data;\n if (fields && typeof fields === \"object\") {\n applyingIframeUpdate = true;\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 applyingIframeUpdate = false;\n }\n } else if (msgType === \"request-undo-state\") {\n postUndoStateToIframe();\n } else if (msgType === \"undo\" && undoManager) {\n undoManager.undo();\n postUndoStateToIframe();\n } else if (msgType === \"redo\" && undoManager) {\n undoManager.redo();\n postUndoStateToIframe();\n }\n };\n\n const onUndoPopped = () => {\n postUndoStateToIframe();\n };\n\n const onStackCleared = () => {\n postUndoStateToIframe();\n };\n\n const onStackItemAdded = () => {\n postUndoStateToIframe();\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.on(\"stack-item-popped\", onUndoPopped);\n undoManager.on(\"stack-cleared\", onStackCleared);\n undoManager.on(\"stack-item-added\", onStackItemAdded);\n }\n\n return {\n get connected() {\n return connected;\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 destroy: () => {\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline }, \"*\");\n }\n }\n setConnected(false);\n postToIframe(\"disconnect\");\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.off(\"stack-item-popped\", onUndoPopped);\n undoManager.off(\"stack-cleared\", onStackCleared);\n undoManager.off(\"stack-item-added\", onStackItemAdded);\n tryRemoveIframeOriginTracking();\n }\n connectListeners.clear();\n disconnectListeners.clear();\n },\n };\n}\n"],"names":["awareness","encodeAwarenessUpdate","Y","applyAwarenessUpdate"],"mappings":"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"}
|
package/iframe-bridge/server.js
CHANGED
|
@@ -107,7 +107,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness, options) {
|
|
|
107
107
|
}
|
|
108
108
|
function postToIframe(type, payload) {
|
|
109
109
|
const cw = iframe.contentWindow;
|
|
110
|
-
const message = { type, payload:
|
|
110
|
+
const message = { type, payload: [] };
|
|
111
111
|
logMessage("send", type, payload);
|
|
112
112
|
if (cw) {
|
|
113
113
|
cw.postMessage(message, "*");
|
|
@@ -198,7 +198,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness, options) {
|
|
|
198
198
|
}
|
|
199
199
|
const docState = Y.encodeStateAsUpdate(ydoc);
|
|
200
200
|
logMessage("send", "ydoc-sync", { bytes: docState.length });
|
|
201
|
-
|
|
201
|
+
postObjectToIframe({ type: "ydoc-sync", payload: Array.from(docState), protocolVersion: 2 });
|
|
202
202
|
unackedServerUpdates.clear();
|
|
203
203
|
const cw = iframe.contentWindow;
|
|
204
204
|
if (cw) {
|
|
@@ -234,7 +234,7 @@ function createIframeBridgeServer(iframe, ydoc, awareness, options) {
|
|
|
234
234
|
logMessage("recv", "ping", payload);
|
|
235
235
|
const cw = iframe.contentWindow;
|
|
236
236
|
if (cw) {
|
|
237
|
-
const message = { type: "pong", serverClientId: awareness.clientID };
|
|
237
|
+
const message = { type: "pong", serverClientId: awareness.clientID, protocolVersion: 2 };
|
|
238
238
|
logMessage("send", "pong", message);
|
|
239
239
|
cw.postMessage(message, "*");
|
|
240
240
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n\n/**\n * 基线数据标记(用于首次初始化)。\n * 此 origin 的更新不应进入 UndoManager 的撤销栈。\n */\nexport const BASELINE_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN, BASELINE_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n debug?: boolean;\n}\n\nexport interface IframeBridgeServer {\n connected: boolean;\n onConnect: (fn: () => void) => () => void;\n onDisconnect: (fn: () => void) => () => void;\n on: (event: \"connect\" | \"disconnect\", fn: () => void) => () => void;\n destroy: () => void;\n}\n\nexport function createIframeBridgeServer(\n iframe: HTMLIFrameElement,\n ydoc: Y.Doc,\n awareness: Awareness,\n options?: IframeBridgeServerOptions,\n): IframeBridgeServer {\n const { undoManager, debug = false } = options ?? {};\n const log = debug\n ? (...args: unknown[]) => console.log(\"[iframe-bridge server]\", ...args)\n : () => undefined;\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 let connected = false;\n let forceFullSync = false;\n let applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\n const MAX_QUEUE_SIZE = 1000;\n const pendingUpdatesToIframe: Array<{ update: Uint8Array; isBaseline: boolean }> = [];\n let serverSeq = 0;\n const unackedServerUpdates = new Map<number, { update: Uint8Array; isBaseline: boolean }>();\n\n function tryAddIframeOriginTracking() {\n if (!undoManager) return;\n try {\n if (typeof (undoManager as any).addTrackedOrigin === \"function\") {\n (undoManager as any).addTrackedOrigin(IFRAME_ORIGIN);\n iframeOriginTracked = true;\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to add IFRAME_ORIGIN to UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n function tryRemoveIframeOriginTracking() {\n if (!undoManager || !iframeOriginTracked) return;\n try {\n if (typeof (undoManager as any).removeTrackedOrigin === \"function\") {\n (undoManager as any).removeTrackedOrigin(IFRAME_ORIGIN);\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to remove IFRAME_ORIGIN from UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n tryAddIframeOriginTracking();\n\n function setConnected(value: boolean) {\n if (connected === value) return;\n connected = value;\n if (value) {\n const wasForceFullSync = forceFullSync;\n forceFullSync = false;\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n }\n if (!wasForceFullSync) {\n for (const [savedSeq, { update, isBaseline }] of unackedServerUpdates) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: savedSeq }, \"*\");\n }\n }\n }\n connectListeners.forEach((fn) => fn());\n } else {\n unackedServerUpdates.clear();\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function postToIframe(type: string, payload?: Uint8Array) {\n const cw = iframe.contentWindow;\n const message = { type, payload: payload ? Array.from(payload) : [] };\n logMessage(\"send\", type, payload);\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n function postObjectToIframe(message: Record<string, unknown>) {\n const type = message.type as string;\n logMessage(\"send\", type, message);\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (origin === IFRAME_ORIGIN) return;\n // 检测基线数据:origin 为 null 时是 xml2ydoc 首次初始化\n const isBaseline = origin === null || origin === undefined;\n logMessage(\"send\", \"ydoc-update\", update);\n if (!connected) {\n if (pendingUpdatesToIframe.length >= MAX_QUEUE_SIZE) {\n forceFullSync = true;\n pendingUpdatesToIframe.length = 0;\n console.warn(\"[iframe-bridge server] queue full, forcing full sync on reconnect\");\n }\n pendingUpdatesToIframe.push({ update, isBaseline });\n return;\n }\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n };\n\n function postUndoStateToIframe() {\n if (!undoManager) return;\n const undoStack = (undoManager as any).undoStack;\n const redoStack = (undoManager as any).redoStack;\n const cw = iframe.contentWindow;\n if (cw) {\n const state = {\n type: \"undo-state\",\n canUndo: undoManager.canUndo(),\n canRedo: undoManager.canRedo(),\n undoStackSize: undoStack?.length ?? 0,\n redoStackSize: redoStack?.length ?? 0,\n };\n logMessage(\"send\", \"undo-state\", state);\n cw.postMessage(state, \"*\");\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 (applyingIframeUpdate) return;\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n // 把所有变化的 clientID 都发送给 iframe(包括其他 Webrtc peers 的光标更新)\n // 但要注意:server 自身的 clientID 需要被 iframe 识别为 serverClientId\n const update = encodeAwarenessUpdate(awareness, changes);\n logMessage(\"send\", \"awareness-update\", update);\n postObjectToIframe({\n type: \"awareness-update\",\n payload: Array.from(update),\n serverClientId: awareness.clientID,\n });\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n\n const { type: msgType, payload } = event.data;\n\n if (msgType === \"ydoc-pending-updates\") {\n logMessage(\"recv\", \"ydoc-pending-updates\", payload);\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const arr = item.update ?? item;\n const isBaseline = item.isBaseline ?? false;\n const update = new Uint8Array(arr);\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n }\n }\n } else if (msgType === \"init\") {\n logMessage(\"recv\", \"init\", payload);\n if (!connected) {\n setConnected(true);\n }\n const docState = Y.encodeStateAsUpdate(ydoc);\n logMessage(\"send\", \"ydoc-sync\", { bytes: docState.length });\n postToIframe(\"ydoc-sync\", new Uint8Array(Array.from(docState)));\n unackedServerUpdates.clear();\n // 在单独的 postMessage 中发送 serverClientId,方便 iframe 接收\n const cw = iframe.contentWindow;\n if (cw) {\n const states = awareness.getStates();\n const statesArray = Array.from(states.entries());\n log(\"[DEBUG] server sending awareness-sync - detailed\", {\n serverClientId: awareness.clientID,\n statesCount: states.size,\n statesArray: statesArray.map(([id, state]) => ({\n clientId: id,\n user: (state as Record<string, unknown>)?.user,\n hasUser: !!(state as Record<string, unknown>)?.user,\n })),\n });\n const message = {\n type: \"awareness-sync\",\n payload: Array.from(encodeAwarenessUpdate(\n awareness,\n Array.from(states.keys()),\n )),\n serverClientId: awareness.clientID,\n };\n log(\"[DEBUG] server sending awareness-sync\", {\n serverClientId: awareness.clientID,\n states: Object.fromEntries(states),\n payloadLength: message.payload.length,\n });\n logMessage(\"send\", \"awareness-sync\", message);\n cw.postMessage(message, \"*\");\n }\n // 同步初始 undo 状态\n postUndoStateToIframe();\n } else if (msgType === \"ping\") {\n logMessage(\"recv\", \"ping\", payload);\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"pong\", serverClientId: awareness.clientID };\n logMessage(\"send\", \"pong\", message);\n cw.postMessage(message, \"*\");\n }\n } else if (msgType === \"ydoc-update\") {\n logMessage(\"recv\", \"ydoc-update\", payload);\n const update = new Uint8Array(payload);\n const isBaseline = event.data.isBaseline;\n // 基线数据使用 BASELINE_ORIGIN(不进入 undo 栈),编辑数据使用 IFRAME_ORIGIN\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n // 源 iframe 已经持有此 update,无需回传\n const inSeq = event.data.seq;\n if (inSeq != null) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update-ack\", seq: inSeq }, \"*\");\n }\n }\n } else if (msgType === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedServerUpdates.delete(ackSeq);\n }\n } else if (msgType === \"awareness-local-state\") {\n // 保留消息类型兼容旧客户端,已不再采用\n logMessage(\"recv\", \"awareness-local-state (ignored)\", payload);\n } else if (msgType === \"set-local-state\") {\n const { key, value } = event.data as {\n key?: string;\n value?: unknown;\n };\n logMessage(\"recv\", \"set-local-state\", { key, value });\n if (typeof key === \"string\") {\n applyingIframeUpdate = true;\n awareness.setLocalStateField(key, value);\n applyingIframeUpdate = false;\n }\n } else if (msgType === \"awareness-update\") {\n logMessage(\"recv\", \"awareness-update\", payload);\n // 应用 iframe 的 awareness 更新时设置标志,防止触发 onAwarenessUpdate 回传\n applyingIframeUpdate = true;\n applyAwarenessUpdate(awareness, new Uint8Array(payload), IFRAME_ORIGIN);\n applyingIframeUpdate = false;\n } else if (msgType === \"set-local-fields\") {\n logMessage(\"recv\", \"set-local-fields\", payload);\n const { fields } = event.data;\n if (fields && typeof fields === \"object\") {\n applyingIframeUpdate = true;\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 applyingIframeUpdate = false;\n }\n } else if (msgType === \"request-undo-state\") {\n postUndoStateToIframe();\n } else if (msgType === \"undo\" && undoManager) {\n undoManager.undo();\n postUndoStateToIframe();\n } else if (msgType === \"redo\" && undoManager) {\n undoManager.redo();\n postUndoStateToIframe();\n }\n };\n\n const onUndoPopped = () => {\n postUndoStateToIframe();\n };\n\n const onStackCleared = () => {\n postUndoStateToIframe();\n };\n\n const onStackItemAdded = () => {\n postUndoStateToIframe();\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.on(\"stack-item-popped\", onUndoPopped);\n undoManager.on(\"stack-cleared\", onStackCleared);\n undoManager.on(\"stack-item-added\", onStackItemAdded);\n }\n\n return {\n get connected() {\n return connected;\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 destroy: () => {\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline }, \"*\");\n }\n }\n setConnected(false);\n postToIframe(\"disconnect\");\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.off(\"stack-item-popped\", onUndoPopped);\n undoManager.off(\"stack-cleared\", onStackCleared);\n undoManager.off(\"stack-item-added\", onStackItemAdded);\n tryRemoveIframeOriginTracking();\n }\n connectListeners.clear();\n disconnectListeners.clear();\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n\n/**\n * 基线数据标记(用于首次初始化)。\n * 此 origin 的更新不应进入 UndoManager 的撤销栈。\n */\nexport const BASELINE_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN, BASELINE_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n debug?: boolean;\n}\n\nexport interface IframeBridgeServer {\n connected: boolean;\n onConnect: (fn: () => void) => () => void;\n onDisconnect: (fn: () => void) => () => void;\n on: (event: \"connect\" | \"disconnect\", fn: () => void) => () => void;\n destroy: () => void;\n}\n\nexport function createIframeBridgeServer(\n iframe: HTMLIFrameElement,\n ydoc: Y.Doc,\n awareness: Awareness,\n options?: IframeBridgeServerOptions,\n): IframeBridgeServer {\n const { undoManager, debug = false } = options ?? {};\n const log = debug\n ? (...args: unknown[]) => console.log(\"[iframe-bridge server]\", ...args)\n : () => undefined;\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 let connected = false;\n let forceFullSync = false;\n let applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\n const MAX_QUEUE_SIZE = 1000;\n const pendingUpdatesToIframe: Array<{ update: Uint8Array; isBaseline: boolean }> = [];\n let serverSeq = 0;\n const unackedServerUpdates = new Map<number, { update: Uint8Array; isBaseline: boolean }>();\n\n function tryAddIframeOriginTracking() {\n if (!undoManager) return;\n try {\n if (typeof (undoManager as any).addTrackedOrigin === \"function\") {\n (undoManager as any).addTrackedOrigin(IFRAME_ORIGIN);\n iframeOriginTracked = true;\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to add IFRAME_ORIGIN to UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n function tryRemoveIframeOriginTracking() {\n if (!undoManager || !iframeOriginTracked) return;\n try {\n if (typeof (undoManager as any).removeTrackedOrigin === \"function\") {\n (undoManager as any).removeTrackedOrigin(IFRAME_ORIGIN);\n }\n } catch (error) {\n console.warn(\n \"[iframe-bridge server] failed to remove IFRAME_ORIGIN from UndoManager tracked origins:\",\n error,\n );\n }\n }\n\n tryAddIframeOriginTracking();\n\n function setConnected(value: boolean) {\n if (connected === value) return;\n connected = value;\n if (value) {\n const wasForceFullSync = forceFullSync;\n forceFullSync = false;\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n }\n if (!wasForceFullSync) {\n for (const [savedSeq, { update, isBaseline }] of unackedServerUpdates) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: savedSeq }, \"*\");\n }\n }\n }\n connectListeners.forEach((fn) => fn());\n } else {\n unackedServerUpdates.clear();\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function postToIframe(type: string, payload?: Uint8Array) {\n const cw = iframe.contentWindow;\n const message = { type, payload: payload ? Array.from(payload) : [] };\n logMessage(\"send\", type, payload);\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n function postObjectToIframe(message: Record<string, unknown>) {\n const type = message.type as string;\n logMessage(\"send\", type, message);\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage(message, \"*\");\n }\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (origin === IFRAME_ORIGIN) return;\n // 检测基线数据:origin 为 null 时是 xml2ydoc 首次初始化\n const isBaseline = origin === null || origin === undefined;\n logMessage(\"send\", \"ydoc-update\", update);\n if (!connected) {\n if (pendingUpdatesToIframe.length >= MAX_QUEUE_SIZE) {\n forceFullSync = true;\n pendingUpdatesToIframe.length = 0;\n console.warn(\"[iframe-bridge server] queue full, forcing full sync on reconnect\");\n }\n pendingUpdatesToIframe.push({ update, isBaseline });\n return;\n }\n const seqNum = ++serverSeq;\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline, seq: seqNum };\n cw.postMessage(message, \"*\");\n }\n unackedServerUpdates.set(seqNum, { update, isBaseline });\n };\n\n function postUndoStateToIframe() {\n if (!undoManager) return;\n const undoStack = (undoManager as any).undoStack;\n const redoStack = (undoManager as any).redoStack;\n const cw = iframe.contentWindow;\n if (cw) {\n const state = {\n type: \"undo-state\",\n canUndo: undoManager.canUndo(),\n canRedo: undoManager.canRedo(),\n undoStackSize: undoStack?.length ?? 0,\n redoStackSize: redoStack?.length ?? 0,\n };\n logMessage(\"send\", \"undo-state\", state);\n cw.postMessage(state, \"*\");\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 (applyingIframeUpdate) return;\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n // 把所有变化的 clientID 都发送给 iframe(包括其他 Webrtc peers 的光标更新)\n // 但要注意:server 自身的 clientID 需要被 iframe 识别为 serverClientId\n const update = encodeAwarenessUpdate(awareness, changes);\n logMessage(\"send\", \"awareness-update\", update);\n postObjectToIframe({\n type: \"awareness-update\",\n payload: Array.from(update),\n serverClientId: awareness.clientID,\n });\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n\n const { type: msgType, payload } = event.data;\n\n if (msgType === \"ydoc-pending-updates\") {\n logMessage(\"recv\", \"ydoc-pending-updates\", payload);\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const arr = item.update ?? item;\n const isBaseline = item.isBaseline ?? false;\n const update = new Uint8Array(arr);\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n }\n }\n } else if (msgType === \"init\") {\n logMessage(\"recv\", \"init\", payload);\n if (!connected) {\n setConnected(true);\n }\n const docState = Y.encodeStateAsUpdate(ydoc);\n logMessage(\"send\", \"ydoc-sync\", { bytes: docState.length });\n postObjectToIframe({ type: \"ydoc-sync\", payload: Array.from(docState), protocolVersion: 2 });\n unackedServerUpdates.clear();\n // 在单独的 postMessage 中发送 serverClientId,方便 iframe 接收\n const cw = iframe.contentWindow;\n if (cw) {\n const states = awareness.getStates();\n const statesArray = Array.from(states.entries());\n log(\"[DEBUG] server sending awareness-sync - detailed\", {\n serverClientId: awareness.clientID,\n statesCount: states.size,\n statesArray: statesArray.map(([id, state]) => ({\n clientId: id,\n user: (state as Record<string, unknown>)?.user,\n hasUser: !!(state as Record<string, unknown>)?.user,\n })),\n });\n const message = {\n type: \"awareness-sync\",\n payload: Array.from(encodeAwarenessUpdate(\n awareness,\n Array.from(states.keys()),\n )),\n serverClientId: awareness.clientID,\n };\n log(\"[DEBUG] server sending awareness-sync\", {\n serverClientId: awareness.clientID,\n states: Object.fromEntries(states),\n payloadLength: message.payload.length,\n });\n logMessage(\"send\", \"awareness-sync\", message);\n cw.postMessage(message, \"*\");\n }\n // 同步初始 undo 状态\n postUndoStateToIframe();\n } else if (msgType === \"ping\") {\n logMessage(\"recv\", \"ping\", payload);\n const cw = iframe.contentWindow;\n if (cw) {\n const message = { type: \"pong\", serverClientId: awareness.clientID, protocolVersion: 2 };\n logMessage(\"send\", \"pong\", message);\n cw.postMessage(message, \"*\");\n }\n } else if (msgType === \"ydoc-update\") {\n logMessage(\"recv\", \"ydoc-update\", payload);\n const update = new Uint8Array(payload);\n const isBaseline = event.data.isBaseline;\n // 基线数据使用 BASELINE_ORIGIN(不进入 undo 栈),编辑数据使用 IFRAME_ORIGIN\n const applyOrigin = isBaseline ? BASELINE_ORIGIN : IFRAME_ORIGIN;\n Y.applyUpdate(ydoc, update, applyOrigin);\n // 源 iframe 已经持有此 update,无需回传\n const inSeq = event.data.seq;\n if (inSeq != null) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update-ack\", seq: inSeq }, \"*\");\n }\n }\n } else if (msgType === \"ydoc-update-ack\") {\n const ackSeq = event.data.seq;\n if (ackSeq != null) {\n unackedServerUpdates.delete(ackSeq);\n }\n } else if (msgType === \"awareness-local-state\") {\n // 保留消息类型兼容旧客户端,已不再采用\n logMessage(\"recv\", \"awareness-local-state (ignored)\", payload);\n } else if (msgType === \"set-local-state\") {\n const { key, value } = event.data as {\n key?: string;\n value?: unknown;\n };\n logMessage(\"recv\", \"set-local-state\", { key, value });\n if (typeof key === \"string\") {\n applyingIframeUpdate = true;\n awareness.setLocalStateField(key, value);\n applyingIframeUpdate = false;\n }\n } else if (msgType === \"awareness-update\") {\n logMessage(\"recv\", \"awareness-update\", payload);\n // 应用 iframe 的 awareness 更新时设置标志,防止触发 onAwarenessUpdate 回传\n applyingIframeUpdate = true;\n applyAwarenessUpdate(awareness, new Uint8Array(payload), IFRAME_ORIGIN);\n applyingIframeUpdate = false;\n } else if (msgType === \"set-local-fields\") {\n logMessage(\"recv\", \"set-local-fields\", payload);\n const { fields } = event.data;\n if (fields && typeof fields === \"object\") {\n applyingIframeUpdate = true;\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 applyingIframeUpdate = false;\n }\n } else if (msgType === \"request-undo-state\") {\n postUndoStateToIframe();\n } else if (msgType === \"undo\" && undoManager) {\n undoManager.undo();\n postUndoStateToIframe();\n } else if (msgType === \"redo\" && undoManager) {\n undoManager.redo();\n postUndoStateToIframe();\n }\n };\n\n const onUndoPopped = () => {\n postUndoStateToIframe();\n };\n\n const onStackCleared = () => {\n postUndoStateToIframe();\n };\n\n const onStackItemAdded = () => {\n postUndoStateToIframe();\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.on(\"stack-item-popped\", onUndoPopped);\n undoManager.on(\"stack-cleared\", onStackCleared);\n undoManager.on(\"stack-item-added\", onStackItemAdded);\n }\n\n return {\n get connected() {\n return connected;\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 destroy: () => {\n while (pendingUpdatesToIframe.length > 0) {\n const { update, isBaseline } = pendingUpdatesToIframe.shift()!;\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type: \"ydoc-update\", payload: Array.from(update), isBaseline }, \"*\");\n }\n }\n setConnected(false);\n postToIframe(\"disconnect\");\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.off(\"stack-item-popped\", onUndoPopped);\n undoManager.off(\"stack-cleared\", onStackCleared);\n undoManager.off(\"stack-item-added\", onStackItemAdded);\n tryRemoveIframeOriginTracking();\n }\n connectListeners.clear();\n disconnectListeners.clear();\n },\n };\n}\n"],"names":[],"mappings":"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"}
|