y-mxgraph 0.8.0 → 0.8.2

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/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # y-mxgraph
2
2
 
3
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mizuka-wu/y-mxgraph)
4
+
5
+ <video width="320" height="240" controls>
6
+ <source src="https://github.com/mizuka-wu/y-mxgraph/blob/main/demo.mp4" type="video/mp4">
7
+ </video>
8
+
3
9
  [中文文档](./README.zh-CN.md)
4
10
 
5
11
  Yjs binding for draw.io (mxGraph) documents, enabling real-time collaborative editing.
@@ -77,6 +83,8 @@ pnpm --filter y-mxgraph test
77
83
 
78
84
  ## Demo
79
85
 
86
+ <video src="https://raw.githubusercontent.com/mizuka-wu/y-mxgraph/main/demo.mp4" controls width="100%"></video>
87
+
80
88
  ```bash
81
89
  # Single-page mode (draw.io loaded directly in the current page)
82
90
  pnpm --filter @y-mxgraph/demo dev
@@ -291,6 +299,7 @@ pnpm --filter @y-mxgraph/ws-demo dev # Start client on port 5174
291
299
  Creates a bridge server on the parent page.
292
300
 
293
301
  **Parameters:**
302
+
294
303
  - `iframe: HTMLIFrameElement` - Target iframe element
295
304
  - `ydoc: Y.Doc` - Shared Yjs document
296
305
  - `awareness: Awareness` - Awareness instance (usually from provider.awareness)
@@ -298,6 +307,7 @@ Creates a bridge server on the parent page.
298
307
  - `options.debug?: boolean` - Enable debug logging (default: false)
299
308
 
300
309
  **Returns:** `IframeBridgeServer` with:
310
+
301
311
  - `connected: boolean` - Current connection status
302
312
  - `onConnect(fn)` / `onDisconnect(fn)` - Connection lifecycle callbacks
303
313
  - `destroy()` - Cleanup all listeners
@@ -307,11 +317,13 @@ Creates a bridge server on the parent page.
307
317
  Creates a bridge provider inside the iframe.
308
318
 
309
319
  **Parameters:**
320
+
310
321
  - `ydoc: Y.Doc` - Local Yjs document
311
322
  - `options.awareness?: Awareness` - Optional external Awareness (creates internal AwarenessLike if omitted)
312
323
  - `options.debug?: boolean` - Enable debug logging (default: false)
313
324
 
314
325
  **Returns:** `IframeBridgeProvider` with:
326
+
315
327
  - `connected: boolean` - Connection status to parent
316
328
  - `awareness: Awareness` - Awareness instance (use for Binding)
317
329
  - `serverClientId: number | null` - Parent's client ID
package/README.zh-CN.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # y-mxgraph
2
2
 
3
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mizuka-wu/y-mxgraph)
4
+
3
5
  [English](./README.md)
4
6
 
5
7
  Yjs 与 draw.io (mxGraph) 文档的双向绑定库,让 draw.io 支持实时多人协同编辑。
@@ -131,6 +131,7 @@ function createIframeBridgeProvider(ydoc, options) {
131
131
  let serverClientId = null;
132
132
  let currentCleanup = null;
133
133
  let currentMxLike = null;
134
+ let pendingUndoState = null;
134
135
  let connected = false;
135
136
  let initRetryTimer = null;
136
137
  const connectListeners = /* @__PURE__ */ new Set();
@@ -277,6 +278,31 @@ function createIframeBridgeProvider(ydoc, options) {
277
278
  logMessage("send", "awareness-local-state", state);
278
279
  window.parent.postMessage(message, "*");
279
280
  };
281
+ const syncUndoStateFromServer = (mxLike, data) => {
282
+ const { undoStackSize, redoStackSize } = data;
283
+ const oldIndex = mxLike.indexOfNextAdd;
284
+ const newIndex = undoStackSize || 0;
285
+ const newTotal = (undoStackSize || 0) + (redoStackSize || 0);
286
+ applyingParentUpdate = true;
287
+ mxLike.history = new Array(newTotal).fill({});
288
+ mxLike.indexOfNextAdd = newIndex;
289
+ if (newTotal === 0) {
290
+ mxLike.fireEvent(createMxEventObject("clear"));
291
+ } else if (newIndex < oldIndex) {
292
+ mxLike.fireEvent(
293
+ createMxEventObject("undo", { edit: { changes: [] } })
294
+ );
295
+ } else if (newIndex > oldIndex) {
296
+ mxLike.fireEvent(
297
+ createMxEventObject("redo", { edit: { changes: [] } })
298
+ );
299
+ } else {
300
+ mxLike.fireEvent(
301
+ createMxEventObject("add", { edit: { changes: [] } })
302
+ );
303
+ }
304
+ applyingParentUpdate = false;
305
+ };
280
306
  const onMessage = (event) => {
281
307
  if (event.source !== window.parent) return;
282
308
  const { type, payload, serverClientId: receivedServerId } = event.data;
@@ -346,30 +372,12 @@ function createIframeBridgeProvider(ydoc, options) {
346
372
  }
347
373
  applyingParentUpdate = false;
348
374
  }
349
- } else if (type === "undo-state" && currentMxLike) {
350
- const { undoStackSize, redoStackSize } = event.data;
351
- const oldIndex = currentMxLike.indexOfNextAdd;
352
- const newIndex = undoStackSize || 0;
353
- const newTotal = (undoStackSize || 0) + (redoStackSize || 0);
354
- applyingParentUpdate = true;
355
- currentMxLike.history = new Array(newTotal).fill({});
356
- currentMxLike.indexOfNextAdd = newIndex;
357
- if (newTotal === 0) {
358
- currentMxLike.fireEvent(createMxEventObject("clear"));
359
- } else if (newIndex < oldIndex) {
360
- currentMxLike.fireEvent(
361
- createMxEventObject("undo", { edit: { changes: [] } })
362
- );
363
- } else if (newIndex > oldIndex) {
364
- currentMxLike.fireEvent(
365
- createMxEventObject("redo", { edit: { changes: [] } })
366
- );
375
+ } else if (type === "undo-state") {
376
+ if (!currentMxLike) {
377
+ pendingUndoState = event.data;
367
378
  } else {
368
- currentMxLike.fireEvent(
369
- createMxEventObject("add", { edit: { changes: [] } })
370
- );
379
+ syncUndoStateFromServer(currentMxLike, event.data);
371
380
  }
372
- applyingParentUpdate = false;
373
381
  } else if (type === "disconnect") {
374
382
  setConnected(false);
375
383
  startInitRetry();
@@ -430,6 +438,45 @@ function createIframeBridgeProvider(ydoc, options) {
430
438
  }
431
439
  const editor = file.getUi().editor;
432
440
  const originUndoManager = editor.undoManager;
441
+ if (originUndoManager && "_y" in originUndoManager) {
442
+ const mxLike2 = originUndoManager;
443
+ const origUndo = mxLike2.undo.bind(mxLike2);
444
+ const origRedo = mxLike2.redo.bind(mxLike2);
445
+ const origCanUndo = mxLike2.canUndo.bind(mxLike2);
446
+ const origCanRedo = mxLike2.canRedo.bind(mxLike2);
447
+ currentMxLike = mxLike2;
448
+ mxLike2.undo = () => {
449
+ if (!applyingParentUpdate) {
450
+ window.parent.postMessage({ type: "undo" }, "*");
451
+ } else {
452
+ origUndo();
453
+ }
454
+ };
455
+ mxLike2.redo = () => {
456
+ if (!applyingParentUpdate) {
457
+ window.parent.postMessage({ type: "redo" }, "*");
458
+ } else {
459
+ origRedo();
460
+ }
461
+ };
462
+ mxLike2.canUndo = () => mxLike2.indexOfNextAdd > 0;
463
+ mxLike2.canRedo = () => mxLike2.indexOfNextAdd < mxLike2.history.length;
464
+ if (pendingUndoState) {
465
+ syncUndoStateFromServer(mxLike2, pendingUndoState);
466
+ pendingUndoState = null;
467
+ }
468
+ window.parent.postMessage({ type: "request-undo-state" }, "*");
469
+ const cleanup2 = () => {
470
+ mxLike2.undo = origUndo;
471
+ mxLike2.redo = origRedo;
472
+ mxLike2.canUndo = origCanUndo;
473
+ mxLike2.canRedo = origCanRedo;
474
+ currentMxLike = null;
475
+ pendingUndoState = null;
476
+ };
477
+ currentCleanup = cleanup2;
478
+ return cleanup2;
479
+ }
433
480
  const pairs = [];
434
481
  const raw = Array.isArray(originUndoManager == null ? void 0 : originUndoManager.eventListeners) ? originUndoManager.eventListeners : [];
435
482
  for (let i = 0; i + 1 < raw.length; i += 2) {
@@ -491,10 +538,16 @@ function createIframeBridgeProvider(ydoc, options) {
491
538
  editor.undoManager = mxLike;
492
539
  editor.undoListener = function() {
493
540
  };
541
+ if (pendingUndoState) {
542
+ syncUndoStateFromServer(mxLike, pendingUndoState);
543
+ pendingUndoState = null;
544
+ }
545
+ window.parent.postMessage({ type: "request-undo-state" }, "*");
494
546
  const cleanup = () => {
495
547
  editor.undoManager = originUndoManager;
496
548
  editor.undoListener = originUndoManager == null ? void 0 : originUndoManager.undoListener;
497
549
  currentMxLike = null;
550
+ pendingUndoState = null;
498
551
  };
499
552
  currentCleanup = cleanup;
500
553
  return cleanup;
@@ -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\";\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 connected = false;\n let initRetryTimer: ReturnType<typeof setInterval> | null = null;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\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 let pendingState: Record<string, unknown> | null | undefined = undefined;\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const FLUSH_INTERVAL = 50;\n\n function getEffectiveClientId() {\n return serverClientId ?? localClientId;\n }\n\n function scheduleFlush() {\n if (flushTimer) return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n if (pendingState !== undefined && connected) {\n window.parent.postMessage({ type: \"awareness-local-state\", state: pendingState }, \"*\");\n pendingState = undefined;\n }\n }, FLUSH_INTERVAL);\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 } else {\n localStates.set(id, state);\n }\n pendingState = state;\n scheduleFlush();\n const update = { added: state && !localStates.has(id) ? [id] : [], updated: state ? [id] : [], removed: state === null ? [id] : [] };\n updateHandlers.forEach(handler => handler(update));\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 pendingState = newState;\n scheduleFlush();\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 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 connectListeners.forEach((fn) => fn());\n } else {\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function startInitRetry() {\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\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 const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\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 state = awareness.getLocalState();\n const message = { type: \"awareness-local-state\", state };\n logMessage(\"send\", \"awareness-local-state\", state);\n window.parent.postMessage(message, \"*\");\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== window.parent) 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 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 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 if (changedClientIds.length > 0) {\n const update = { added: [], updated: changedClientIds, removed: [] };\n updateHandlers.forEach(handler => handler(update));\n }\n applyingParentUpdate = false;\n }\n } else if (type === \"undo-state\" && currentMxLike) {\n // 从 Server 同步真实的 undo/redo 状态\n const { undoStackSize, redoStackSize } = event.data;\n\n const oldIndex = currentMxLike.indexOfNextAdd;\n const newIndex = undoStackSize || 0;\n const newTotal = (undoStackSize || 0) + (redoStackSize || 0);\n\n // 直接根据 server 状态重建本地状态\n applyingParentUpdate = true;\n\n // 重建 history 数组匹配 server 的总大小\n currentMxLike.history = new Array(newTotal).fill({});\n currentMxLike.indexOfNextAdd = newIndex;\n\n // 触发对应事件通知 UI 更新\n if (newTotal === 0) {\n currentMxLike.fireEvent(createMxEventObject(\"clear\"));\n } else if (newIndex < oldIndex) {\n currentMxLike.fireEvent(\n createMxEventObject(\"undo\", { edit: { changes: [] } }),\n );\n } else if (newIndex > oldIndex) {\n currentMxLike.fireEvent(\n createMxEventObject(\"redo\", { edit: { changes: [] } }),\n );\n } else {\n currentMxLike.fireEvent(\n createMxEventObject(\"add\", { edit: { changes: [] } }),\n );\n }\n\n applyingParentUpdate = false;\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 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 const cleanup = () => {\n editor.undoManager = originUndoManager;\n editor.undoListener = originUndoManager?.undoListener as\n | ((...args: unknown[]) => void)\n | undefined;\n currentMxLike = null;\n };\n\n currentCleanup = cleanup;\n return cleanup;\n },\n destroy: () => {\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"],"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\";\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 initRetryTimer: ReturnType<typeof setInterval> | null = null;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\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 let pendingState: Record<string, unknown> | null | undefined = undefined;\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const FLUSH_INTERVAL = 50;\n\n function getEffectiveClientId() {\n return serverClientId ?? localClientId;\n }\n\n function scheduleFlush() {\n if (flushTimer) return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n if (pendingState !== undefined && connected) {\n window.parent.postMessage({ type: \"awareness-local-state\", state: pendingState }, \"*\");\n pendingState = undefined;\n }\n }, FLUSH_INTERVAL);\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 } else {\n localStates.set(id, state);\n }\n pendingState = state;\n scheduleFlush();\n const update = { added: state && !localStates.has(id) ? [id] : [], updated: state ? [id] : [], removed: state === null ? [id] : [] };\n updateHandlers.forEach(handler => handler(update));\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 pendingState = newState;\n scheduleFlush();\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 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 connectListeners.forEach((fn) => fn());\n } else {\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function startInitRetry() {\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\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 const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\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 state = awareness.getLocalState();\n const message = { type: \"awareness-local-state\", state };\n logMessage(\"send\", \"awareness-local-state\", state);\n window.parent.postMessage(message, \"*\");\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 const { type, payload, serverClientId: receivedServerId } = event.data;\n\n logMessage(\"recv\", type, payload);\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 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 if (changedClientIds.length > 0) {\n const update = { added: [], updated: changedClientIds, removed: [] };\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 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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"}
@@ -112,6 +112,7 @@ function createIframeBridgeProvider(ydoc, options) {
112
112
  let serverClientId = null;
113
113
  let currentCleanup = null;
114
114
  let currentMxLike = null;
115
+ let pendingUndoState = null;
115
116
  let connected = false;
116
117
  let initRetryTimer = null;
117
118
  const connectListeners = /* @__PURE__ */ new Set();
@@ -258,6 +259,31 @@ function createIframeBridgeProvider(ydoc, options) {
258
259
  logMessage("send", "awareness-local-state", state);
259
260
  window.parent.postMessage(message, "*");
260
261
  };
262
+ const syncUndoStateFromServer = (mxLike, data) => {
263
+ const { undoStackSize, redoStackSize } = data;
264
+ const oldIndex = mxLike.indexOfNextAdd;
265
+ const newIndex = undoStackSize || 0;
266
+ const newTotal = (undoStackSize || 0) + (redoStackSize || 0);
267
+ applyingParentUpdate = true;
268
+ mxLike.history = new Array(newTotal).fill({});
269
+ mxLike.indexOfNextAdd = newIndex;
270
+ if (newTotal === 0) {
271
+ mxLike.fireEvent(createMxEventObject("clear"));
272
+ } else if (newIndex < oldIndex) {
273
+ mxLike.fireEvent(
274
+ createMxEventObject("undo", { edit: { changes: [] } })
275
+ );
276
+ } else if (newIndex > oldIndex) {
277
+ mxLike.fireEvent(
278
+ createMxEventObject("redo", { edit: { changes: [] } })
279
+ );
280
+ } else {
281
+ mxLike.fireEvent(
282
+ createMxEventObject("add", { edit: { changes: [] } })
283
+ );
284
+ }
285
+ applyingParentUpdate = false;
286
+ };
261
287
  const onMessage = (event) => {
262
288
  if (event.source !== window.parent) return;
263
289
  const { type, payload, serverClientId: receivedServerId } = event.data;
@@ -327,30 +353,12 @@ function createIframeBridgeProvider(ydoc, options) {
327
353
  }
328
354
  applyingParentUpdate = false;
329
355
  }
330
- } else if (type === "undo-state" && currentMxLike) {
331
- const { undoStackSize, redoStackSize } = event.data;
332
- const oldIndex = currentMxLike.indexOfNextAdd;
333
- const newIndex = undoStackSize || 0;
334
- const newTotal = (undoStackSize || 0) + (redoStackSize || 0);
335
- applyingParentUpdate = true;
336
- currentMxLike.history = new Array(newTotal).fill({});
337
- currentMxLike.indexOfNextAdd = newIndex;
338
- if (newTotal === 0) {
339
- currentMxLike.fireEvent(createMxEventObject("clear"));
340
- } else if (newIndex < oldIndex) {
341
- currentMxLike.fireEvent(
342
- createMxEventObject("undo", { edit: { changes: [] } })
343
- );
344
- } else if (newIndex > oldIndex) {
345
- currentMxLike.fireEvent(
346
- createMxEventObject("redo", { edit: { changes: [] } })
347
- );
356
+ } else if (type === "undo-state") {
357
+ if (!currentMxLike) {
358
+ pendingUndoState = event.data;
348
359
  } else {
349
- currentMxLike.fireEvent(
350
- createMxEventObject("add", { edit: { changes: [] } })
351
- );
360
+ syncUndoStateFromServer(currentMxLike, event.data);
352
361
  }
353
- applyingParentUpdate = false;
354
362
  } else if (type === "disconnect") {
355
363
  setConnected(false);
356
364
  startInitRetry();
@@ -411,6 +419,45 @@ function createIframeBridgeProvider(ydoc, options) {
411
419
  }
412
420
  const editor = file.getUi().editor;
413
421
  const originUndoManager = editor.undoManager;
422
+ if (originUndoManager && "_y" in originUndoManager) {
423
+ const mxLike2 = originUndoManager;
424
+ const origUndo = mxLike2.undo.bind(mxLike2);
425
+ const origRedo = mxLike2.redo.bind(mxLike2);
426
+ const origCanUndo = mxLike2.canUndo.bind(mxLike2);
427
+ const origCanRedo = mxLike2.canRedo.bind(mxLike2);
428
+ currentMxLike = mxLike2;
429
+ mxLike2.undo = () => {
430
+ if (!applyingParentUpdate) {
431
+ window.parent.postMessage({ type: "undo" }, "*");
432
+ } else {
433
+ origUndo();
434
+ }
435
+ };
436
+ mxLike2.redo = () => {
437
+ if (!applyingParentUpdate) {
438
+ window.parent.postMessage({ type: "redo" }, "*");
439
+ } else {
440
+ origRedo();
441
+ }
442
+ };
443
+ mxLike2.canUndo = () => mxLike2.indexOfNextAdd > 0;
444
+ mxLike2.canRedo = () => mxLike2.indexOfNextAdd < mxLike2.history.length;
445
+ if (pendingUndoState) {
446
+ syncUndoStateFromServer(mxLike2, pendingUndoState);
447
+ pendingUndoState = null;
448
+ }
449
+ window.parent.postMessage({ type: "request-undo-state" }, "*");
450
+ const cleanup2 = () => {
451
+ mxLike2.undo = origUndo;
452
+ mxLike2.redo = origRedo;
453
+ mxLike2.canUndo = origCanUndo;
454
+ mxLike2.canRedo = origCanRedo;
455
+ currentMxLike = null;
456
+ pendingUndoState = null;
457
+ };
458
+ currentCleanup = cleanup2;
459
+ return cleanup2;
460
+ }
414
461
  const pairs = [];
415
462
  const raw = Array.isArray(originUndoManager == null ? void 0 : originUndoManager.eventListeners) ? originUndoManager.eventListeners : [];
416
463
  for (let i = 0; i + 1 < raw.length; i += 2) {
@@ -472,10 +519,16 @@ function createIframeBridgeProvider(ydoc, options) {
472
519
  editor.undoManager = mxLike;
473
520
  editor.undoListener = function() {
474
521
  };
522
+ if (pendingUndoState) {
523
+ syncUndoStateFromServer(mxLike, pendingUndoState);
524
+ pendingUndoState = null;
525
+ }
526
+ window.parent.postMessage({ type: "request-undo-state" }, "*");
475
527
  const cleanup = () => {
476
528
  editor.undoManager = originUndoManager;
477
529
  editor.undoListener = originUndoManager == null ? void 0 : originUndoManager.undoListener;
478
530
  currentMxLike = null;
531
+ pendingUndoState = null;
479
532
  };
480
533
  currentCleanup = cleanup;
481
534
  return cleanup;
@@ -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\";\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 connected = false;\n let initRetryTimer: ReturnType<typeof setInterval> | null = null;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\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 let pendingState: Record<string, unknown> | null | undefined = undefined;\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const FLUSH_INTERVAL = 50;\n\n function getEffectiveClientId() {\n return serverClientId ?? localClientId;\n }\n\n function scheduleFlush() {\n if (flushTimer) return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n if (pendingState !== undefined && connected) {\n window.parent.postMessage({ type: \"awareness-local-state\", state: pendingState }, \"*\");\n pendingState = undefined;\n }\n }, FLUSH_INTERVAL);\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 } else {\n localStates.set(id, state);\n }\n pendingState = state;\n scheduleFlush();\n const update = { added: state && !localStates.has(id) ? [id] : [], updated: state ? [id] : [], removed: state === null ? [id] : [] };\n updateHandlers.forEach(handler => handler(update));\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 pendingState = newState;\n scheduleFlush();\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 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 connectListeners.forEach((fn) => fn());\n } else {\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function startInitRetry() {\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\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 const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\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 state = awareness.getLocalState();\n const message = { type: \"awareness-local-state\", state };\n logMessage(\"send\", \"awareness-local-state\", state);\n window.parent.postMessage(message, \"*\");\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== window.parent) 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 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 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 if (changedClientIds.length > 0) {\n const update = { added: [], updated: changedClientIds, removed: [] };\n updateHandlers.forEach(handler => handler(update));\n }\n applyingParentUpdate = false;\n }\n } else if (type === \"undo-state\" && currentMxLike) {\n // 从 Server 同步真实的 undo/redo 状态\n const { undoStackSize, redoStackSize } = event.data;\n\n const oldIndex = currentMxLike.indexOfNextAdd;\n const newIndex = undoStackSize || 0;\n const newTotal = (undoStackSize || 0) + (redoStackSize || 0);\n\n // 直接根据 server 状态重建本地状态\n applyingParentUpdate = true;\n\n // 重建 history 数组匹配 server 的总大小\n currentMxLike.history = new Array(newTotal).fill({});\n currentMxLike.indexOfNextAdd = newIndex;\n\n // 触发对应事件通知 UI 更新\n if (newTotal === 0) {\n currentMxLike.fireEvent(createMxEventObject(\"clear\"));\n } else if (newIndex < oldIndex) {\n currentMxLike.fireEvent(\n createMxEventObject(\"undo\", { edit: { changes: [] } }),\n );\n } else if (newIndex > oldIndex) {\n currentMxLike.fireEvent(\n createMxEventObject(\"redo\", { edit: { changes: [] } }),\n );\n } else {\n currentMxLike.fireEvent(\n createMxEventObject(\"add\", { edit: { changes: [] } }),\n );\n }\n\n applyingParentUpdate = false;\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 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 const cleanup = () => {\n editor.undoManager = originUndoManager;\n editor.undoListener = originUndoManager?.undoListener as\n | ((...args: unknown[]) => void)\n | undefined;\n currentMxLike = null;\n };\n\n currentCleanup = cleanup;\n return cleanup;\n },\n destroy: () => {\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"],"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\";\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 initRetryTimer: ReturnType<typeof setInterval> | null = null;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\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 let pendingState: Record<string, unknown> | null | undefined = undefined;\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const FLUSH_INTERVAL = 50;\n\n function getEffectiveClientId() {\n return serverClientId ?? localClientId;\n }\n\n function scheduleFlush() {\n if (flushTimer) return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n if (pendingState !== undefined && connected) {\n window.parent.postMessage({ type: \"awareness-local-state\", state: pendingState }, \"*\");\n pendingState = undefined;\n }\n }, FLUSH_INTERVAL);\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 } else {\n localStates.set(id, state);\n }\n pendingState = state;\n scheduleFlush();\n const update = { added: state && !localStates.has(id) ? [id] : [], updated: state ? [id] : [], removed: state === null ? [id] : [] };\n updateHandlers.forEach(handler => handler(update));\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 pendingState = newState;\n scheduleFlush();\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 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 connectListeners.forEach((fn) => fn());\n } else {\n disconnectListeners.forEach((fn) => fn());\n }\n }\n\n function startInitRetry() {\n if (initRetryTimer) {\n clearInterval(initRetryTimer);\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 const message = { type: \"ydoc-update\", payload: Array.from(update), isBaseline };\n logMessage(\"send\", \"ydoc-update\", message);\n window.parent.postMessage(message, \"*\");\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 state = awareness.getLocalState();\n const message = { type: \"awareness-local-state\", state };\n logMessage(\"send\", \"awareness-local-state\", state);\n window.parent.postMessage(message, \"*\");\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 const { type, payload, serverClientId: receivedServerId } = event.data;\n\n logMessage(\"recv\", type, payload);\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 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 if (changedClientIds.length > 0) {\n const update = { added: [], updated: changedClientIds, removed: [] };\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 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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"}
@@ -238,6 +238,8 @@ function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
238
238
  }));
239
239
  applyingIframeUpdate = false;
240
240
  }
241
+ } else if (msgType === "request-undo-state") {
242
+ postUndoStateToIframe();
241
243
  } else if (msgType === "undo" && undoManager) {
242
244
  undoManager.undo();
243
245
  postUndoStateToIframe();
@@ -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 applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\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 connectListeners.forEach((fn) => fn());\n } else {\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 logMessage(\"send\", \"ydoc-update\", update);\n postToIframe(\"ydoc-update\", update);\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 === \"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 // 在单独的 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 } else if (msgType === \"awareness-local-state\") {\n log(\"[DEBUG] server received awareness-local-state\", {\n currentState: awareness.getLocalState(),\n receivedState: event.data.state,\n });\n logMessage(\"recv\", \"awareness-local-state\", payload);\n applyingIframeUpdate = true;\n awareness.setLocalState(event.data.state);\n applyingIframeUpdate = false;\n log(\"[DEBUG] server after setLocalState\", {\n newState: awareness.getLocalState(),\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 === \"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 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 applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\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 connectListeners.forEach((fn) => fn());\n } else {\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 logMessage(\"send\", \"ydoc-update\", update);\n postToIframe(\"ydoc-update\", update);\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 === \"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 // 在单独的 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 } else if (msgType === \"awareness-local-state\") {\n log(\"[DEBUG] server received awareness-local-state\", {\n currentState: awareness.getLocalState(),\n receivedState: event.data.state,\n });\n logMessage(\"recv\", \"awareness-local-state\", payload);\n applyingIframeUpdate = true;\n awareness.setLocalState(event.data.state);\n applyingIframeUpdate = false;\n log(\"[DEBUG] server after setLocalState\", {\n newState: awareness.getLocalState(),\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 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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"}
@@ -219,6 +219,8 @@ function createIframeBridgeServer(iframe, ydoc, awareness, options) {
219
219
  }));
220
220
  applyingIframeUpdate = false;
221
221
  }
222
+ } else if (msgType === "request-undo-state") {
223
+ postUndoStateToIframe();
222
224
  } else if (msgType === "undo" && undoManager) {
223
225
  undoManager.undo();
224
226
  postUndoStateToIframe();
@@ -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 applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\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 connectListeners.forEach((fn) => fn());\n } else {\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 logMessage(\"send\", \"ydoc-update\", update);\n postToIframe(\"ydoc-update\", update);\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 === \"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 // 在单独的 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 } else if (msgType === \"awareness-local-state\") {\n log(\"[DEBUG] server received awareness-local-state\", {\n currentState: awareness.getLocalState(),\n receivedState: event.data.state,\n });\n logMessage(\"recv\", \"awareness-local-state\", payload);\n applyingIframeUpdate = true;\n awareness.setLocalState(event.data.state);\n applyingIframeUpdate = false;\n log(\"[DEBUG] server after setLocalState\", {\n newState: awareness.getLocalState(),\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 === \"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 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 applyingIframeUpdate = false;\n const connectListeners = new Set<() => void>();\n const disconnectListeners = new Set<() => void>();\n let iframeOriginTracked = false;\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 connectListeners.forEach((fn) => fn());\n } else {\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 logMessage(\"send\", \"ydoc-update\", update);\n postToIframe(\"ydoc-update\", update);\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 === \"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 // 在单独的 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 } else if (msgType === \"awareness-local-state\") {\n log(\"[DEBUG] server received awareness-local-state\", {\n currentState: awareness.getLocalState(),\n receivedState: event.data.state,\n });\n logMessage(\"recv\", \"awareness-local-state\", payload);\n applyingIframeUpdate = true;\n awareness.setLocalState(event.data.state);\n applyingIframeUpdate = false;\n log(\"[DEBUG] server after setLocalState\", {\n newState: awareness.getLocalState(),\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 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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"}
@@ -73,9 +73,12 @@ function parse$3(object) {
73
73
  }
74
74
  if (object[mxGeometryKey]) {
75
75
  const geometry = object[mxGeometryKey];
76
- const geometryString = js2xml(geometry, {
77
- compact: true
78
- });
76
+ const geometryString = js2xml(
77
+ { [mxGeometryKey]: geometry },
78
+ {
79
+ compact: true
80
+ }
81
+ );
79
82
  xmlElement.setAttribute(mxGeometryAttributeKey, geometryString);
80
83
  delete object[mxGeometryKey];
81
84
  }
@@ -257,4 +260,4 @@ export {
257
260
  xml2ydoc as x,
258
261
  ydoc2xml as y
259
262
  };
260
- //# sourceMappingURL=index-D8PKHH-R.js.map
263
+ //# sourceMappingURL=index-BtfQrQYT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BtfQrQYT.js","sources":["../src/helper/xml.ts","../src/helper/yjs.ts","../src/models/mxCell.ts","../src/models/mxGraphModel.ts","../src/models/diagram.ts","../src/models/mxfile.ts","../src/transform/index.ts"],"sourcesContent":["import { xml2js, js2xml, type ElementCompact } from \"xml-js\";\n\nfunction deepProcess(node: unknown): void {\n if (node == null) return;\n\n if (Array.isArray(node)) {\n for (const item of node) {\n deepProcess(item);\n }\n return;\n }\n\n if (typeof node !== \"object\") return;\n\n const obj = node as Record<string, unknown>;\n const keys = Object.keys(obj);\n for (const key of keys) {\n if (key === \"_attributes\") continue;\n\n let value = obj[key];\n const keyLower = key.toLowerCase();\n\n if (\n (keyLower === \"diagram\" || keyLower === \"mxcell\") &&\n value !== undefined &&\n !Array.isArray(value)\n ) {\n obj[key] = [value];\n value = obj[key];\n }\n\n if (Array.isArray(value)) {\n for (const v of value) deepProcess(v);\n } else if (value && typeof value === \"object\") {\n deepProcess(value);\n }\n }\n}\n\nexport function parse(xml: string) {\n const result = xml2js(xml, { compact: true }) as Record<string, unknown>;\n deepProcess(result);\n return result;\n}\n\nexport function serializer(obj: ElementCompact, spaces = 2) {\n return js2xml(obj, {\n compact: true,\n spaces,\n });\n}\n","import * as Y from \"yjs\";\n\n/**\n * 从 Y.Map 中安全获取子 Map(格式固定,转型安全)\n */\nexport function getMap<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Map<T> | undefined {\n return parent.get(key) as Y.Map<T> | undefined;\n}\n\n/**\n * 从 Y.Map 中安全获取子 Array(格式固定,转型安全)\n */\nexport function getArray<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Array<T> | undefined {\n return parent.get(key) as Y.Array<T> | undefined;\n}\n","import * as Y from \"yjs\";\nimport { xml2js, js2xml } from \"xml-js\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxCell\";\n\nconst mxGeometryKey = \"mxGeometry\";\nconst mxGeometryAttributeKey = \"geometry\";\n\nexport interface MxCellModel extends ElementCompact {\n [mxGeometryKey]?: ElementCompact;\n}\n\nexport function parse(object: MxCellModel): Y.XmlElement {\n const xmlElement = new Y.XmlElement(\"mxCell\");\n\n for (const attribute of Object.keys(object._attributes || {})) {\n xmlElement.setAttribute(\n attribute,\n `${object._attributes?.[attribute] || \"\"}`,\n );\n }\n\n if (object[mxGeometryKey]) {\n const geometry = object[mxGeometryKey];\n const geometryString = js2xml(\n { [mxGeometryKey]: geometry },\n {\n compact: true,\n },\n );\n xmlElement.setAttribute(mxGeometryAttributeKey, geometryString);\n delete object[mxGeometryKey];\n }\n\n return xmlElement;\n}\n\nexport function serialize(xmlElement: Y.XmlElement) {\n const rawAttributes = {\n ...xmlElement.getAttributes(),\n };\n\n // 提取 mxGeometry(不需要转义,它本身就是 XML 字符串)\n let mxGeometry: ElementCompact | null = null;\n let mxGeometryString: string | undefined;\n\n if (mxGeometryAttributeKey in rawAttributes) {\n mxGeometryString = rawAttributes[mxGeometryAttributeKey];\n delete rawAttributes[mxGeometryAttributeKey];\n }\n\n // 转义其他属性值中的特殊字符\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(rawAttributes)) {\n if (typeof value === \"string\") {\n attributes[key] = value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n } else if (value != null) {\n attributes[key] = String(value);\n }\n }\n\n // 解析 mxGeometry\n if (mxGeometryString) {\n try {\n const parsed = xml2js(mxGeometryString, { compact: true }) as Record<\n string,\n ElementCompact\n >;\n mxGeometry = parsed[mxGeometryKey] ?? null;\n if (mxGeometry && mxGeometry._attributes) {\n mxGeometry._attributes[\"as\"] = \"geometry\";\n }\n } catch (e) {\n console.warn(\"[y-mxgraph] Failed to parse mxGeometry:\", e);\n }\n }\n\n const obj: Record<string, unknown> = {\n _attributes: attributes,\n };\n\n if (mxGeometry) {\n obj[mxGeometryKey] = mxGeometry;\n }\n\n return obj;\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\n\nimport {\n key as mxCellKey,\n parse as parseMxCell,\n serialize as serializeMxCell,\n type MxCellModel,\n} from \"./mxCell\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxGraphModel\";\nexport const mxCellOrderKey = mxCellKey + \"Order\";\n\nexport interface MxGraphModel extends ElementCompact {\n root: {\n mxCell: MxCellModel[];\n };\n}\n\nexport type YMxGraphModel = Y.Map<unknown>;\n\nexport function parse(object: MxGraphModel, doc?: Y.Doc) {\n const mxCells = (object.root[mxCellKey] || []).map((cell: MxCellModel) => {\n return {\n value: parseMxCell(cell),\n id: (cell._attributes?.id || \"\") as string,\n };\n });\n\n const mxGraphElement = doc?.getMap(key) || new Y.Map();\n\n const cells = new Y.Map<Y.XmlElement>();\n const cellsOrder = new Y.Array<string>();\n\n mxCells.forEach((cell) => {\n cells.set(cell.id, cell.value);\n });\n\n cellsOrder.push(mxCells.map((cell) => cell.id));\n\n mxGraphElement.set(mxCellKey, cells);\n mxGraphElement.set(mxCellOrderKey, cellsOrder);\n\n return mxGraphElement as YMxGraphModel;\n}\n\nexport function serialize(map: YMxGraphModel) {\n const cells = getMap<Y.XmlElement>(map, mxCellKey)!;\n const cellsOrder = getArray<string>(map, mxCellOrderKey)!;\n return {\n _attributes: {},\n root: {\n [mxCellKey]: cellsOrder\n .toArray()\n .map((id) => serializeMxCell(cells!.get(id) as Y.XmlElement)),\n },\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap } from \"../helper/yjs\";\nimport {\n parse as parseMxGraphModel,\n serialize as serializeMxGraphModel,\n key as mxGraphModelKey,\n type MxGraphModel,\n type YMxGraphModel,\n} from \"./mxGraphModel\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"diagram\";\n\nexport interface Diagram extends ElementCompact {\n mxGraphModel: MxGraphModel;\n}\n\nexport type YDiagram = Y.Map<unknown>;\n\nexport function parse(object: Diagram): YDiagram {\n const yDiagramElement = new Y.Map();\n yDiagramElement.set(\"name\", `${object._attributes?.name || \"\"}`);\n yDiagramElement.set(\"id\", `${object._attributes?.id || \"\"}`);\n\n const mxGraphModel = parseMxGraphModel(object[mxGraphModelKey]);\n\n yDiagramElement.set(mxGraphModelKey, mxGraphModel);\n return yDiagramElement as YDiagram;\n}\n\nexport function serialize(yDiagram: YDiagram) {\n const mxGraphModel = getMap(yDiagram, mxGraphModelKey);\n\n return {\n _attributes: {\n name: yDiagram.get(\"name\") as string,\n id: yDiagram.get(\"id\") as string,\n },\n [mxGraphModelKey]: mxGraphModel\n ? serializeMxGraphModel(mxGraphModel)\n : undefined,\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\nimport {\n parse as parseDiagram,\n key as diagramKey,\n serialize as serializeDiagram,\n} from \"./diagram\";\nimport type { Diagram, YDiagram } from \"./diagram\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxfile\";\nexport const diagramOrderKey = diagramKey + \"Order\";\n\nexport type YMxFile = Y.Map<unknown>;\n\nexport interface MxFile extends ElementCompact {\n diagram: Diagram[];\n}\n\nexport function parse(object: MxFile, doc: Y.Doc) {\n const mxfile = doc.getMap(key);\n mxfile.set(\"pages\", (object._attributes?.pages || \"1\") + \"\");\n\n const diagramList = object.diagram.map((diagram) => ({\n value: parseDiagram(diagram),\n id: (diagram._attributes?.id || \"\") as string,\n }));\n const diagramMap = new Y.Map<YDiagram>();\n const diagramOrder = new Y.Array<string>();\n diagramList.forEach((diagram) => {\n diagramMap.set(diagram.id, diagram.value);\n });\n diagramOrder.push(diagramList.map((diagram) => diagram.id));\n\n mxfile.set(diagramKey, diagramMap);\n mxfile.set(diagramOrderKey, diagramOrder);\n return mxfile;\n}\n\nexport function serializer(yMxFile: YMxFile): ElementCompact {\n const diagrams = getMap<YDiagram>(yMxFile, diagramKey);\n const diagramOrder = getArray<string>(yMxFile, diagramOrderKey);\n\n const orderIds = diagramOrder ? diagramOrder.toArray() : [];\n // 如果 diagramOrder 为空但 diagram map 不为空,使用 diagram map 中的所有 ID\n const ids =\n orderIds.length > 0\n ? orderIds\n : diagrams\n ? Array.from(diagrams.keys())\n : [];\n\n const obj: Record<string, unknown> = {\n _attributes: {\n pages: (yMxFile.get(\"pages\") as string) || \"1\",\n },\n [diagramKey]: ids\n .map((id) => diagrams!.get(id) as YDiagram)\n .filter((d): d is YDiagram => !!d)\n .map((diagramElement) => serializeDiagram(diagramElement)),\n };\n\n return obj as ElementCompact;\n}\n","import * as Y from \"yjs\";\nimport { parse, serializer } from \"../helper/xml\";\nimport {\n parse as parseMxFile,\n key as mxfileKey,\n serializer as serializerMxFile,\n type YMxFile,\n} from \"../models/mxfile\";\nimport {\n parse as parseMxGraphModel,\n key as mxGraphModelKey,\n serialize as serializerMxGraphModel,\n type YMxGraphModel,\n} from \"../models/mxGraphModel\";\n\nexport function xml2ydoc(xml: string, doc: Y.Doc): Y.Doc {\n const object = parse(xml);\n\n const mxfile = (object as Record<string, unknown>).mxfile;\n const mxGraphModel = (object as Record<string, unknown>).mxGraphModel;\n if (mxfile) {\n doc.transact(() => {\n parseMxFile(mxfile as import(\"../models/mxfile\").MxFile, doc);\n });\n } else if (mxGraphModel) {\n doc.transact(() => {\n parseMxGraphModel(\n mxGraphModel as import(\"../models/mxGraphModel\").MxGraphModel,\n doc,\n );\n });\n } else {\n throw new Error(\"不支持的文件格式\");\n }\n\n return doc;\n}\n\nexport function ydoc2xml(doc: Y.Doc, spaces = 0): string {\n if (doc.share.has(mxfileKey)) {\n return serializer(\n {\n [mxfileKey]: serializerMxFile(doc.getMap(mxfileKey)),\n },\n spaces,\n );\n }\n if (doc.share.has(mxGraphModelKey)) {\n return serializer(\n {\n [mxGraphModelKey]: serializerMxGraphModel(doc.getMap(mxGraphModelKey)),\n },\n spaces,\n );\n }\n\n return \"\";\n}\n"],"names":["key","parse","serializer","serialize","mxCellKey","parseMxCell","serializeMxCell","parseMxGraphModel","mxGraphModelKey","serializeMxGraphModel","diagramKey","_a","parseDiagram","serializeDiagram","parseMxFile","mxfileKey","serializerMxFile","serializerMxGraphModel"],"mappings":"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"}
@@ -91,9 +91,12 @@ function parse$3(object) {
91
91
  }
92
92
  if (object[mxGeometryKey]) {
93
93
  const geometry = object[mxGeometryKey];
94
- const geometryString = xmlJs.js2xml(geometry, {
95
- compact: true
96
- });
94
+ const geometryString = xmlJs.js2xml(
95
+ { [mxGeometryKey]: geometry },
96
+ {
97
+ compact: true
98
+ }
99
+ );
97
100
  xmlElement.setAttribute(mxGeometryAttributeKey, geometryString);
98
101
  delete object[mxGeometryKey];
99
102
  }
@@ -273,4 +276,4 @@ exports.serialize = serialize;
273
276
  exports.serializer = serializer$1;
274
277
  exports.xml2ydoc = xml2ydoc;
275
278
  exports.ydoc2xml = ydoc2xml;
276
- //# sourceMappingURL=index-DkYwhpfJ.cjs.map
279
+ //# sourceMappingURL=index-CaG-EdEK.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CaG-EdEK.cjs","sources":["../src/helper/xml.ts","../src/helper/yjs.ts","../src/models/mxCell.ts","../src/models/mxGraphModel.ts","../src/models/diagram.ts","../src/models/mxfile.ts","../src/transform/index.ts"],"sourcesContent":["import { xml2js, js2xml, type ElementCompact } from \"xml-js\";\n\nfunction deepProcess(node: unknown): void {\n if (node == null) return;\n\n if (Array.isArray(node)) {\n for (const item of node) {\n deepProcess(item);\n }\n return;\n }\n\n if (typeof node !== \"object\") return;\n\n const obj = node as Record<string, unknown>;\n const keys = Object.keys(obj);\n for (const key of keys) {\n if (key === \"_attributes\") continue;\n\n let value = obj[key];\n const keyLower = key.toLowerCase();\n\n if (\n (keyLower === \"diagram\" || keyLower === \"mxcell\") &&\n value !== undefined &&\n !Array.isArray(value)\n ) {\n obj[key] = [value];\n value = obj[key];\n }\n\n if (Array.isArray(value)) {\n for (const v of value) deepProcess(v);\n } else if (value && typeof value === \"object\") {\n deepProcess(value);\n }\n }\n}\n\nexport function parse(xml: string) {\n const result = xml2js(xml, { compact: true }) as Record<string, unknown>;\n deepProcess(result);\n return result;\n}\n\nexport function serializer(obj: ElementCompact, spaces = 2) {\n return js2xml(obj, {\n compact: true,\n spaces,\n });\n}\n","import * as Y from \"yjs\";\n\n/**\n * 从 Y.Map 中安全获取子 Map(格式固定,转型安全)\n */\nexport function getMap<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Map<T> | undefined {\n return parent.get(key) as Y.Map<T> | undefined;\n}\n\n/**\n * 从 Y.Map 中安全获取子 Array(格式固定,转型安全)\n */\nexport function getArray<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Array<T> | undefined {\n return parent.get(key) as Y.Array<T> | undefined;\n}\n","import * as Y from \"yjs\";\nimport { xml2js, js2xml } from \"xml-js\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxCell\";\n\nconst mxGeometryKey = \"mxGeometry\";\nconst mxGeometryAttributeKey = \"geometry\";\n\nexport interface MxCellModel extends ElementCompact {\n [mxGeometryKey]?: ElementCompact;\n}\n\nexport function parse(object: MxCellModel): Y.XmlElement {\n const xmlElement = new Y.XmlElement(\"mxCell\");\n\n for (const attribute of Object.keys(object._attributes || {})) {\n xmlElement.setAttribute(\n attribute,\n `${object._attributes?.[attribute] || \"\"}`,\n );\n }\n\n if (object[mxGeometryKey]) {\n const geometry = object[mxGeometryKey];\n const geometryString = js2xml(\n { [mxGeometryKey]: geometry },\n {\n compact: true,\n },\n );\n xmlElement.setAttribute(mxGeometryAttributeKey, geometryString);\n delete object[mxGeometryKey];\n }\n\n return xmlElement;\n}\n\nexport function serialize(xmlElement: Y.XmlElement) {\n const rawAttributes = {\n ...xmlElement.getAttributes(),\n };\n\n // 提取 mxGeometry(不需要转义,它本身就是 XML 字符串)\n let mxGeometry: ElementCompact | null = null;\n let mxGeometryString: string | undefined;\n\n if (mxGeometryAttributeKey in rawAttributes) {\n mxGeometryString = rawAttributes[mxGeometryAttributeKey];\n delete rawAttributes[mxGeometryAttributeKey];\n }\n\n // 转义其他属性值中的特殊字符\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(rawAttributes)) {\n if (typeof value === \"string\") {\n attributes[key] = value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n } else if (value != null) {\n attributes[key] = String(value);\n }\n }\n\n // 解析 mxGeometry\n if (mxGeometryString) {\n try {\n const parsed = xml2js(mxGeometryString, { compact: true }) as Record<\n string,\n ElementCompact\n >;\n mxGeometry = parsed[mxGeometryKey] ?? null;\n if (mxGeometry && mxGeometry._attributes) {\n mxGeometry._attributes[\"as\"] = \"geometry\";\n }\n } catch (e) {\n console.warn(\"[y-mxgraph] Failed to parse mxGeometry:\", e);\n }\n }\n\n const obj: Record<string, unknown> = {\n _attributes: attributes,\n };\n\n if (mxGeometry) {\n obj[mxGeometryKey] = mxGeometry;\n }\n\n return obj;\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\n\nimport {\n key as mxCellKey,\n parse as parseMxCell,\n serialize as serializeMxCell,\n type MxCellModel,\n} from \"./mxCell\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxGraphModel\";\nexport const mxCellOrderKey = mxCellKey + \"Order\";\n\nexport interface MxGraphModel extends ElementCompact {\n root: {\n mxCell: MxCellModel[];\n };\n}\n\nexport type YMxGraphModel = Y.Map<unknown>;\n\nexport function parse(object: MxGraphModel, doc?: Y.Doc) {\n const mxCells = (object.root[mxCellKey] || []).map((cell: MxCellModel) => {\n return {\n value: parseMxCell(cell),\n id: (cell._attributes?.id || \"\") as string,\n };\n });\n\n const mxGraphElement = doc?.getMap(key) || new Y.Map();\n\n const cells = new Y.Map<Y.XmlElement>();\n const cellsOrder = new Y.Array<string>();\n\n mxCells.forEach((cell) => {\n cells.set(cell.id, cell.value);\n });\n\n cellsOrder.push(mxCells.map((cell) => cell.id));\n\n mxGraphElement.set(mxCellKey, cells);\n mxGraphElement.set(mxCellOrderKey, cellsOrder);\n\n return mxGraphElement as YMxGraphModel;\n}\n\nexport function serialize(map: YMxGraphModel) {\n const cells = getMap<Y.XmlElement>(map, mxCellKey)!;\n const cellsOrder = getArray<string>(map, mxCellOrderKey)!;\n return {\n _attributes: {},\n root: {\n [mxCellKey]: cellsOrder\n .toArray()\n .map((id) => serializeMxCell(cells!.get(id) as Y.XmlElement)),\n },\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap } from \"../helper/yjs\";\nimport {\n parse as parseMxGraphModel,\n serialize as serializeMxGraphModel,\n key as mxGraphModelKey,\n type MxGraphModel,\n type YMxGraphModel,\n} from \"./mxGraphModel\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"diagram\";\n\nexport interface Diagram extends ElementCompact {\n mxGraphModel: MxGraphModel;\n}\n\nexport type YDiagram = Y.Map<unknown>;\n\nexport function parse(object: Diagram): YDiagram {\n const yDiagramElement = new Y.Map();\n yDiagramElement.set(\"name\", `${object._attributes?.name || \"\"}`);\n yDiagramElement.set(\"id\", `${object._attributes?.id || \"\"}`);\n\n const mxGraphModel = parseMxGraphModel(object[mxGraphModelKey]);\n\n yDiagramElement.set(mxGraphModelKey, mxGraphModel);\n return yDiagramElement as YDiagram;\n}\n\nexport function serialize(yDiagram: YDiagram) {\n const mxGraphModel = getMap(yDiagram, mxGraphModelKey);\n\n return {\n _attributes: {\n name: yDiagram.get(\"name\") as string,\n id: yDiagram.get(\"id\") as string,\n },\n [mxGraphModelKey]: mxGraphModel\n ? serializeMxGraphModel(mxGraphModel)\n : undefined,\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\nimport {\n parse as parseDiagram,\n key as diagramKey,\n serialize as serializeDiagram,\n} from \"./diagram\";\nimport type { Diagram, YDiagram } from \"./diagram\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxfile\";\nexport const diagramOrderKey = diagramKey + \"Order\";\n\nexport type YMxFile = Y.Map<unknown>;\n\nexport interface MxFile extends ElementCompact {\n diagram: Diagram[];\n}\n\nexport function parse(object: MxFile, doc: Y.Doc) {\n const mxfile = doc.getMap(key);\n mxfile.set(\"pages\", (object._attributes?.pages || \"1\") + \"\");\n\n const diagramList = object.diagram.map((diagram) => ({\n value: parseDiagram(diagram),\n id: (diagram._attributes?.id || \"\") as string,\n }));\n const diagramMap = new Y.Map<YDiagram>();\n const diagramOrder = new Y.Array<string>();\n diagramList.forEach((diagram) => {\n diagramMap.set(diagram.id, diagram.value);\n });\n diagramOrder.push(diagramList.map((diagram) => diagram.id));\n\n mxfile.set(diagramKey, diagramMap);\n mxfile.set(diagramOrderKey, diagramOrder);\n return mxfile;\n}\n\nexport function serializer(yMxFile: YMxFile): ElementCompact {\n const diagrams = getMap<YDiagram>(yMxFile, diagramKey);\n const diagramOrder = getArray<string>(yMxFile, diagramOrderKey);\n\n const orderIds = diagramOrder ? diagramOrder.toArray() : [];\n // 如果 diagramOrder 为空但 diagram map 不为空,使用 diagram map 中的所有 ID\n const ids =\n orderIds.length > 0\n ? orderIds\n : diagrams\n ? Array.from(diagrams.keys())\n : [];\n\n const obj: Record<string, unknown> = {\n _attributes: {\n pages: (yMxFile.get(\"pages\") as string) || \"1\",\n },\n [diagramKey]: ids\n .map((id) => diagrams!.get(id) as YDiagram)\n .filter((d): d is YDiagram => !!d)\n .map((diagramElement) => serializeDiagram(diagramElement)),\n };\n\n return obj as ElementCompact;\n}\n","import * as Y from \"yjs\";\nimport { parse, serializer } from \"../helper/xml\";\nimport {\n parse as parseMxFile,\n key as mxfileKey,\n serializer as serializerMxFile,\n type YMxFile,\n} from \"../models/mxfile\";\nimport {\n parse as parseMxGraphModel,\n key as mxGraphModelKey,\n serialize as serializerMxGraphModel,\n type YMxGraphModel,\n} from \"../models/mxGraphModel\";\n\nexport function xml2ydoc(xml: string, doc: Y.Doc): Y.Doc {\n const object = parse(xml);\n\n const mxfile = (object as Record<string, unknown>).mxfile;\n const mxGraphModel = (object as Record<string, unknown>).mxGraphModel;\n if (mxfile) {\n doc.transact(() => {\n parseMxFile(mxfile as import(\"../models/mxfile\").MxFile, doc);\n });\n } else if (mxGraphModel) {\n doc.transact(() => {\n parseMxGraphModel(\n mxGraphModel as import(\"../models/mxGraphModel\").MxGraphModel,\n doc,\n );\n });\n } else {\n throw new Error(\"不支持的文件格式\");\n }\n\n return doc;\n}\n\nexport function ydoc2xml(doc: Y.Doc, spaces = 0): string {\n if (doc.share.has(mxfileKey)) {\n return serializer(\n {\n [mxfileKey]: serializerMxFile(doc.getMap(mxfileKey)),\n },\n spaces,\n );\n }\n if (doc.share.has(mxGraphModelKey)) {\n return serializer(\n {\n [mxGraphModelKey]: serializerMxGraphModel(doc.getMap(mxGraphModelKey)),\n },\n spaces,\n );\n }\n\n return \"\";\n}\n"],"names":["key","parse","xml2js","serializer","js2xml","Y","serialize","mxCellKey","parseMxCell","serializeMxCell","parseMxGraphModel","mxGraphModelKey","serializeMxGraphModel","diagramKey","_a","parseDiagram","serializeDiagram","parseMxFile","mxfileKey","serializerMxFile","serializerMxGraphModel"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mxCell.d.ts","sourceRoot":"","sources":["../../src/models/mxCell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE7C,eAAO,MAAM,GAAG,WAAW,CAAC;AAE5B,QAAA,MAAM,aAAa,eAAe,CAAC;AAGnC,MAAM,WAAW,WAAY,SAAQ,cAAc;IACjD,CAAC,aAAa,CAAC,CAAC,EAAE,cAAc,CAAC;CAClC;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,CAAC,CAAC,UAAU,CAoBvD;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,2BAmDjD"}
1
+ {"version":3,"file":"mxCell.d.ts","sourceRoot":"","sources":["../../src/models/mxCell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE7C,eAAO,MAAM,GAAG,WAAW,CAAC;AAE5B,QAAA,MAAM,aAAa,eAAe,CAAC;AAGnC,MAAM,WAAW,WAAY,SAAQ,cAAc;IACjD,CAAC,aAAa,CAAC,CAAC,EAAE,cAAc,CAAC;CAClC;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,CAAC,CAAC,UAAU,CAuBvD;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,2BAsDjD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "y-mxgraph",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Yjs binding for draw.io (mxGraph) documents",
5
5
  "keywords": [
6
6
  "yjs",
package/transform.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const transform = require("./index-DkYwhpfJ.cjs");
3
+ const transform = require("./index-CaG-EdEK.cjs");
4
4
  exports.xml2ydoc = transform.xml2ydoc;
5
5
  exports.ydoc2xml = transform.ydoc2xml;
6
6
  //# sourceMappingURL=transform.cjs.map
package/transform.js CHANGED
@@ -1,4 +1,4 @@
1
- import { x, y } from "./index-D8PKHH-R.js";
1
+ import { x, y } from "./index-BtfQrQYT.js";
2
2
  export {
3
3
  x as xml2ydoc,
4
4
  y as ydoc2xml
package/y-mxgraph.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const transform = require("./index-DkYwhpfJ.cjs");
3
+ const transform = require("./index-CaG-EdEK.cjs");
4
4
  const Y = require("yjs");
5
5
  const colord = require("colord");
6
6
  function _interopNamespaceDefault(e) {
package/y-mxgraph.js CHANGED
@@ -1,4 +1,4 @@
1
- import { k as key, a as key$1, d as diagramOrderKey, b as key$2, m as mxCellOrderKey, c as key$3, p as parse, e as parse$1, f as serializer, s as serialize, x as xml2ydoc, y as ydoc2xml } from "./index-D8PKHH-R.js";
1
+ import { k as key, a as key$1, d as diagramOrderKey, b as key$2, m as mxCellOrderKey, c as key$3, p as parse, e as parse$1, f as serializer, s as serialize, x as xml2ydoc, y as ydoc2xml } from "./index-BtfQrQYT.js";
2
2
  import * as Y from "yjs";
3
3
  import { colord } from "colord";
4
4
  var __defProp$1 = Object.defineProperty;
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-D8PKHH-R.js","sources":["../src/helper/xml.ts","../src/helper/yjs.ts","../src/models/mxCell.ts","../src/models/mxGraphModel.ts","../src/models/diagram.ts","../src/models/mxfile.ts","../src/transform/index.ts"],"sourcesContent":["import { xml2js, js2xml, type ElementCompact } from \"xml-js\";\n\nfunction deepProcess(node: unknown): void {\n if (node == null) return;\n\n if (Array.isArray(node)) {\n for (const item of node) {\n deepProcess(item);\n }\n return;\n }\n\n if (typeof node !== \"object\") return;\n\n const obj = node as Record<string, unknown>;\n const keys = Object.keys(obj);\n for (const key of keys) {\n if (key === \"_attributes\") continue;\n\n let value = obj[key];\n const keyLower = key.toLowerCase();\n\n if (\n (keyLower === \"diagram\" || keyLower === \"mxcell\") &&\n value !== undefined &&\n !Array.isArray(value)\n ) {\n obj[key] = [value];\n value = obj[key];\n }\n\n if (Array.isArray(value)) {\n for (const v of value) deepProcess(v);\n } else if (value && typeof value === \"object\") {\n deepProcess(value);\n }\n }\n}\n\nexport function parse(xml: string) {\n const result = xml2js(xml, { compact: true }) as Record<string, unknown>;\n deepProcess(result);\n return result;\n}\n\nexport function serializer(obj: ElementCompact, spaces = 2) {\n return js2xml(obj, {\n compact: true,\n spaces,\n });\n}\n","import * as Y from \"yjs\";\n\n/**\n * 从 Y.Map 中安全获取子 Map(格式固定,转型安全)\n */\nexport function getMap<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Map<T> | undefined {\n return parent.get(key) as Y.Map<T> | undefined;\n}\n\n/**\n * 从 Y.Map 中安全获取子 Array(格式固定,转型安全)\n */\nexport function getArray<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Array<T> | undefined {\n return parent.get(key) as Y.Array<T> | undefined;\n}\n","import * as Y from \"yjs\";\nimport { xml2js, js2xml } from \"xml-js\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxCell\";\n\nconst mxGeometryKey = \"mxGeometry\";\nconst mxGeometryAttributeKey = \"geometry\";\n\nexport interface MxCellModel extends ElementCompact {\n [mxGeometryKey]?: ElementCompact;\n}\n\nexport function parse(object: MxCellModel): Y.XmlElement {\n const xmlElement = new Y.XmlElement(\"mxCell\");\n\n for (const attribute of Object.keys(object._attributes || {})) {\n xmlElement.setAttribute(\n attribute,\n `${object._attributes?.[attribute] || \"\"}`\n );\n }\n\n if (object[mxGeometryKey]) {\n const geometry = object[mxGeometryKey];\n const geometryString = js2xml(geometry, {\n compact: true,\n });\n xmlElement.setAttribute(mxGeometryAttributeKey, geometryString);\n delete object[mxGeometryKey];\n }\n\n return xmlElement;\n}\n\nexport function serialize(xmlElement: Y.XmlElement) {\n const rawAttributes = {\n ...xmlElement.getAttributes(),\n };\n\n // 提取 mxGeometry(不需要转义,它本身就是 XML 字符串)\n let mxGeometry: ElementCompact | null = null;\n let mxGeometryString: string | undefined;\n\n if (mxGeometryAttributeKey in rawAttributes) {\n mxGeometryString = rawAttributes[mxGeometryAttributeKey];\n delete rawAttributes[mxGeometryAttributeKey];\n }\n\n // 转义其他属性值中的特殊字符\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(rawAttributes)) {\n if (typeof value === 'string') {\n attributes[key] = value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n } else if (value != null) {\n attributes[key] = String(value);\n }\n }\n\n // 解析 mxGeometry\n if (mxGeometryString) {\n try {\n const parsed = xml2js(mxGeometryString, { compact: true }) as Record<string, ElementCompact>;\n mxGeometry = parsed[mxGeometryKey] ?? null;\n if (mxGeometry && mxGeometry._attributes) {\n mxGeometry._attributes[\"as\"] = \"geometry\";\n }\n } catch (e) {\n console.warn(\"[y-mxgraph] Failed to parse mxGeometry:\", e);\n }\n }\n\n const obj: Record<string, unknown> = {\n _attributes: attributes,\n };\n\n if (mxGeometry) {\n obj[mxGeometryKey] = mxGeometry;\n }\n\n return obj;\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\n\nimport {\n key as mxCellKey,\n parse as parseMxCell,\n serialize as serializeMxCell,\n type MxCellModel,\n} from \"./mxCell\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxGraphModel\";\nexport const mxCellOrderKey = mxCellKey + \"Order\";\n\nexport interface MxGraphModel extends ElementCompact {\n root: {\n mxCell: MxCellModel[];\n };\n}\n\nexport type YMxGraphModel = Y.Map<unknown>;\n\nexport function parse(object: MxGraphModel, doc?: Y.Doc) {\n const mxCells = (object.root[mxCellKey] || []).map((cell: MxCellModel) => {\n return {\n value: parseMxCell(cell),\n id: (cell._attributes?.id || \"\") as string,\n };\n });\n\n const mxGraphElement = doc?.getMap(key) || new Y.Map();\n\n const cells = new Y.Map<Y.XmlElement>();\n const cellsOrder = new Y.Array<string>();\n\n mxCells.forEach((cell) => {\n cells.set(cell.id, cell.value);\n });\n\n cellsOrder.push(mxCells.map((cell) => cell.id));\n\n mxGraphElement.set(mxCellKey, cells);\n mxGraphElement.set(mxCellOrderKey, cellsOrder);\n\n return mxGraphElement as YMxGraphModel;\n}\n\nexport function serialize(map: YMxGraphModel) {\n const cells = getMap<Y.XmlElement>(map, mxCellKey)!;\n const cellsOrder = getArray<string>(map, mxCellOrderKey)!;\n return {\n _attributes: {},\n root: {\n [mxCellKey]: cellsOrder\n .toArray()\n .map((id) => serializeMxCell(cells!.get(id) as Y.XmlElement)),\n },\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap } from \"../helper/yjs\";\nimport {\n parse as parseMxGraphModel,\n serialize as serializeMxGraphModel,\n key as mxGraphModelKey,\n type MxGraphModel,\n type YMxGraphModel,\n} from \"./mxGraphModel\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"diagram\";\n\nexport interface Diagram extends ElementCompact {\n mxGraphModel: MxGraphModel;\n}\n\nexport type YDiagram = Y.Map<unknown>;\n\nexport function parse(object: Diagram): YDiagram {\n const yDiagramElement = new Y.Map();\n yDiagramElement.set(\"name\", `${object._attributes?.name || \"\"}`);\n yDiagramElement.set(\"id\", `${object._attributes?.id || \"\"}`);\n\n const mxGraphModel = parseMxGraphModel(object[mxGraphModelKey]);\n\n yDiagramElement.set(mxGraphModelKey, mxGraphModel);\n return yDiagramElement as YDiagram;\n}\n\nexport function serialize(yDiagram: YDiagram) {\n const mxGraphModel = getMap(yDiagram, mxGraphModelKey);\n\n return {\n _attributes: {\n name: yDiagram.get(\"name\") as string,\n id: yDiagram.get(\"id\") as string,\n },\n [mxGraphModelKey]: mxGraphModel\n ? serializeMxGraphModel(mxGraphModel)\n : undefined,\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\nimport {\n parse as parseDiagram,\n key as diagramKey,\n serialize as serializeDiagram,\n} from \"./diagram\";\nimport type { Diagram, YDiagram } from \"./diagram\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxfile\";\nexport const diagramOrderKey = diagramKey + \"Order\";\n\nexport type YMxFile = Y.Map<unknown>;\n\nexport interface MxFile extends ElementCompact {\n diagram: Diagram[];\n}\n\nexport function parse(object: MxFile, doc: Y.Doc) {\n const mxfile = doc.getMap(key);\n mxfile.set(\"pages\", (object._attributes?.pages || \"1\") + \"\");\n\n const diagramList = object.diagram.map((diagram) => ({\n value: parseDiagram(diagram),\n id: (diagram._attributes?.id || \"\") as string,\n }));\n const diagramMap = new Y.Map<YDiagram>();\n const diagramOrder = new Y.Array<string>();\n diagramList.forEach((diagram) => {\n diagramMap.set(diagram.id, diagram.value);\n });\n diagramOrder.push(diagramList.map((diagram) => diagram.id));\n\n mxfile.set(diagramKey, diagramMap);\n mxfile.set(diagramOrderKey, diagramOrder);\n return mxfile;\n}\n\nexport function serializer(yMxFile: YMxFile): ElementCompact {\n const diagrams = getMap<YDiagram>(yMxFile, diagramKey);\n const diagramOrder = getArray<string>(yMxFile, diagramOrderKey);\n\n const orderIds = diagramOrder ? diagramOrder.toArray() : [];\n // 如果 diagramOrder 为空但 diagram map 不为空,使用 diagram map 中的所有 ID\n const ids =\n orderIds.length > 0\n ? orderIds\n : diagrams\n ? Array.from(diagrams.keys())\n : [];\n\n const obj: Record<string, unknown> = {\n _attributes: {\n pages: (yMxFile.get(\"pages\") as string) || \"1\",\n },\n [diagramKey]: ids\n .map((id) => diagrams!.get(id) as YDiagram)\n .filter((d): d is YDiagram => !!d)\n .map((diagramElement) => serializeDiagram(diagramElement)),\n };\n\n return obj as ElementCompact;\n}\n","import * as Y from \"yjs\";\nimport { parse, serializer } from \"../helper/xml\";\nimport {\n parse as parseMxFile,\n key as mxfileKey,\n serializer as serializerMxFile,\n type YMxFile,\n} from \"../models/mxfile\";\nimport {\n parse as parseMxGraphModel,\n key as mxGraphModelKey,\n serialize as serializerMxGraphModel,\n type YMxGraphModel,\n} from \"../models/mxGraphModel\";\n\nexport function xml2ydoc(xml: string, doc: Y.Doc): Y.Doc {\n const object = parse(xml);\n\n const mxfile = (object as Record<string, unknown>).mxfile;\n const mxGraphModel = (object as Record<string, unknown>).mxGraphModel;\n if (mxfile) {\n doc.transact(() => {\n parseMxFile(mxfile as import(\"../models/mxfile\").MxFile, doc);\n });\n } else if (mxGraphModel) {\n doc.transact(() => {\n parseMxGraphModel(\n mxGraphModel as import(\"../models/mxGraphModel\").MxGraphModel,\n doc,\n );\n });\n } else {\n throw new Error(\"不支持的文件格式\");\n }\n\n return doc;\n}\n\nexport function ydoc2xml(doc: Y.Doc, spaces = 0): string {\n if (doc.share.has(mxfileKey)) {\n return serializer(\n {\n [mxfileKey]: serializerMxFile(doc.getMap(mxfileKey)),\n },\n spaces,\n );\n }\n if (doc.share.has(mxGraphModelKey)) {\n return serializer(\n {\n [mxGraphModelKey]: serializerMxGraphModel(doc.getMap(mxGraphModelKey)),\n },\n spaces,\n );\n }\n\n return \"\";\n}\n"],"names":["key","parse","serializer","serialize","mxCellKey","parseMxCell","serializeMxCell","parseMxGraphModel","mxGraphModelKey","serializeMxGraphModel","diagramKey","_a","parseDiagram","serializeDiagram","parseMxFile","mxfileKey","serializerMxFile","serializerMxGraphModel"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-DkYwhpfJ.cjs","sources":["../src/helper/xml.ts","../src/helper/yjs.ts","../src/models/mxCell.ts","../src/models/mxGraphModel.ts","../src/models/diagram.ts","../src/models/mxfile.ts","../src/transform/index.ts"],"sourcesContent":["import { xml2js, js2xml, type ElementCompact } from \"xml-js\";\n\nfunction deepProcess(node: unknown): void {\n if (node == null) return;\n\n if (Array.isArray(node)) {\n for (const item of node) {\n deepProcess(item);\n }\n return;\n }\n\n if (typeof node !== \"object\") return;\n\n const obj = node as Record<string, unknown>;\n const keys = Object.keys(obj);\n for (const key of keys) {\n if (key === \"_attributes\") continue;\n\n let value = obj[key];\n const keyLower = key.toLowerCase();\n\n if (\n (keyLower === \"diagram\" || keyLower === \"mxcell\") &&\n value !== undefined &&\n !Array.isArray(value)\n ) {\n obj[key] = [value];\n value = obj[key];\n }\n\n if (Array.isArray(value)) {\n for (const v of value) deepProcess(v);\n } else if (value && typeof value === \"object\") {\n deepProcess(value);\n }\n }\n}\n\nexport function parse(xml: string) {\n const result = xml2js(xml, { compact: true }) as Record<string, unknown>;\n deepProcess(result);\n return result;\n}\n\nexport function serializer(obj: ElementCompact, spaces = 2) {\n return js2xml(obj, {\n compact: true,\n spaces,\n });\n}\n","import * as Y from \"yjs\";\n\n/**\n * 从 Y.Map 中安全获取子 Map(格式固定,转型安全)\n */\nexport function getMap<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Map<T> | undefined {\n return parent.get(key) as Y.Map<T> | undefined;\n}\n\n/**\n * 从 Y.Map 中安全获取子 Array(格式固定,转型安全)\n */\nexport function getArray<T = unknown>(\n parent: Y.Map<unknown>,\n key: string,\n): Y.Array<T> | undefined {\n return parent.get(key) as Y.Array<T> | undefined;\n}\n","import * as Y from \"yjs\";\nimport { xml2js, js2xml } from \"xml-js\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxCell\";\n\nconst mxGeometryKey = \"mxGeometry\";\nconst mxGeometryAttributeKey = \"geometry\";\n\nexport interface MxCellModel extends ElementCompact {\n [mxGeometryKey]?: ElementCompact;\n}\n\nexport function parse(object: MxCellModel): Y.XmlElement {\n const xmlElement = new Y.XmlElement(\"mxCell\");\n\n for (const attribute of Object.keys(object._attributes || {})) {\n xmlElement.setAttribute(\n attribute,\n `${object._attributes?.[attribute] || \"\"}`\n );\n }\n\n if (object[mxGeometryKey]) {\n const geometry = object[mxGeometryKey];\n const geometryString = js2xml(geometry, {\n compact: true,\n });\n xmlElement.setAttribute(mxGeometryAttributeKey, geometryString);\n delete object[mxGeometryKey];\n }\n\n return xmlElement;\n}\n\nexport function serialize(xmlElement: Y.XmlElement) {\n const rawAttributes = {\n ...xmlElement.getAttributes(),\n };\n\n // 提取 mxGeometry(不需要转义,它本身就是 XML 字符串)\n let mxGeometry: ElementCompact | null = null;\n let mxGeometryString: string | undefined;\n\n if (mxGeometryAttributeKey in rawAttributes) {\n mxGeometryString = rawAttributes[mxGeometryAttributeKey];\n delete rawAttributes[mxGeometryAttributeKey];\n }\n\n // 转义其他属性值中的特殊字符\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(rawAttributes)) {\n if (typeof value === 'string') {\n attributes[key] = value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n } else if (value != null) {\n attributes[key] = String(value);\n }\n }\n\n // 解析 mxGeometry\n if (mxGeometryString) {\n try {\n const parsed = xml2js(mxGeometryString, { compact: true }) as Record<string, ElementCompact>;\n mxGeometry = parsed[mxGeometryKey] ?? null;\n if (mxGeometry && mxGeometry._attributes) {\n mxGeometry._attributes[\"as\"] = \"geometry\";\n }\n } catch (e) {\n console.warn(\"[y-mxgraph] Failed to parse mxGeometry:\", e);\n }\n }\n\n const obj: Record<string, unknown> = {\n _attributes: attributes,\n };\n\n if (mxGeometry) {\n obj[mxGeometryKey] = mxGeometry;\n }\n\n return obj;\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\n\nimport {\n key as mxCellKey,\n parse as parseMxCell,\n serialize as serializeMxCell,\n type MxCellModel,\n} from \"./mxCell\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxGraphModel\";\nexport const mxCellOrderKey = mxCellKey + \"Order\";\n\nexport interface MxGraphModel extends ElementCompact {\n root: {\n mxCell: MxCellModel[];\n };\n}\n\nexport type YMxGraphModel = Y.Map<unknown>;\n\nexport function parse(object: MxGraphModel, doc?: Y.Doc) {\n const mxCells = (object.root[mxCellKey] || []).map((cell: MxCellModel) => {\n return {\n value: parseMxCell(cell),\n id: (cell._attributes?.id || \"\") as string,\n };\n });\n\n const mxGraphElement = doc?.getMap(key) || new Y.Map();\n\n const cells = new Y.Map<Y.XmlElement>();\n const cellsOrder = new Y.Array<string>();\n\n mxCells.forEach((cell) => {\n cells.set(cell.id, cell.value);\n });\n\n cellsOrder.push(mxCells.map((cell) => cell.id));\n\n mxGraphElement.set(mxCellKey, cells);\n mxGraphElement.set(mxCellOrderKey, cellsOrder);\n\n return mxGraphElement as YMxGraphModel;\n}\n\nexport function serialize(map: YMxGraphModel) {\n const cells = getMap<Y.XmlElement>(map, mxCellKey)!;\n const cellsOrder = getArray<string>(map, mxCellOrderKey)!;\n return {\n _attributes: {},\n root: {\n [mxCellKey]: cellsOrder\n .toArray()\n .map((id) => serializeMxCell(cells!.get(id) as Y.XmlElement)),\n },\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap } from \"../helper/yjs\";\nimport {\n parse as parseMxGraphModel,\n serialize as serializeMxGraphModel,\n key as mxGraphModelKey,\n type MxGraphModel,\n type YMxGraphModel,\n} from \"./mxGraphModel\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"diagram\";\n\nexport interface Diagram extends ElementCompact {\n mxGraphModel: MxGraphModel;\n}\n\nexport type YDiagram = Y.Map<unknown>;\n\nexport function parse(object: Diagram): YDiagram {\n const yDiagramElement = new Y.Map();\n yDiagramElement.set(\"name\", `${object._attributes?.name || \"\"}`);\n yDiagramElement.set(\"id\", `${object._attributes?.id || \"\"}`);\n\n const mxGraphModel = parseMxGraphModel(object[mxGraphModelKey]);\n\n yDiagramElement.set(mxGraphModelKey, mxGraphModel);\n return yDiagramElement as YDiagram;\n}\n\nexport function serialize(yDiagram: YDiagram) {\n const mxGraphModel = getMap(yDiagram, mxGraphModelKey);\n\n return {\n _attributes: {\n name: yDiagram.get(\"name\") as string,\n id: yDiagram.get(\"id\") as string,\n },\n [mxGraphModelKey]: mxGraphModel\n ? serializeMxGraphModel(mxGraphModel)\n : undefined,\n };\n}\n","import * as Y from \"yjs\";\nimport { getMap, getArray } from \"../helper/yjs\";\nimport {\n parse as parseDiagram,\n key as diagramKey,\n serialize as serializeDiagram,\n} from \"./diagram\";\nimport type { Diagram, YDiagram } from \"./diagram\";\nimport type { ElementCompact } from \"xml-js\";\n\nexport const key = \"mxfile\";\nexport const diagramOrderKey = diagramKey + \"Order\";\n\nexport type YMxFile = Y.Map<unknown>;\n\nexport interface MxFile extends ElementCompact {\n diagram: Diagram[];\n}\n\nexport function parse(object: MxFile, doc: Y.Doc) {\n const mxfile = doc.getMap(key);\n mxfile.set(\"pages\", (object._attributes?.pages || \"1\") + \"\");\n\n const diagramList = object.diagram.map((diagram) => ({\n value: parseDiagram(diagram),\n id: (diagram._attributes?.id || \"\") as string,\n }));\n const diagramMap = new Y.Map<YDiagram>();\n const diagramOrder = new Y.Array<string>();\n diagramList.forEach((diagram) => {\n diagramMap.set(diagram.id, diagram.value);\n });\n diagramOrder.push(diagramList.map((diagram) => diagram.id));\n\n mxfile.set(diagramKey, diagramMap);\n mxfile.set(diagramOrderKey, diagramOrder);\n return mxfile;\n}\n\nexport function serializer(yMxFile: YMxFile): ElementCompact {\n const diagrams = getMap<YDiagram>(yMxFile, diagramKey);\n const diagramOrder = getArray<string>(yMxFile, diagramOrderKey);\n\n const orderIds = diagramOrder ? diagramOrder.toArray() : [];\n // 如果 diagramOrder 为空但 diagram map 不为空,使用 diagram map 中的所有 ID\n const ids =\n orderIds.length > 0\n ? orderIds\n : diagrams\n ? Array.from(diagrams.keys())\n : [];\n\n const obj: Record<string, unknown> = {\n _attributes: {\n pages: (yMxFile.get(\"pages\") as string) || \"1\",\n },\n [diagramKey]: ids\n .map((id) => diagrams!.get(id) as YDiagram)\n .filter((d): d is YDiagram => !!d)\n .map((diagramElement) => serializeDiagram(diagramElement)),\n };\n\n return obj as ElementCompact;\n}\n","import * as Y from \"yjs\";\nimport { parse, serializer } from \"../helper/xml\";\nimport {\n parse as parseMxFile,\n key as mxfileKey,\n serializer as serializerMxFile,\n type YMxFile,\n} from \"../models/mxfile\";\nimport {\n parse as parseMxGraphModel,\n key as mxGraphModelKey,\n serialize as serializerMxGraphModel,\n type YMxGraphModel,\n} from \"../models/mxGraphModel\";\n\nexport function xml2ydoc(xml: string, doc: Y.Doc): Y.Doc {\n const object = parse(xml);\n\n const mxfile = (object as Record<string, unknown>).mxfile;\n const mxGraphModel = (object as Record<string, unknown>).mxGraphModel;\n if (mxfile) {\n doc.transact(() => {\n parseMxFile(mxfile as import(\"../models/mxfile\").MxFile, doc);\n });\n } else if (mxGraphModel) {\n doc.transact(() => {\n parseMxGraphModel(\n mxGraphModel as import(\"../models/mxGraphModel\").MxGraphModel,\n doc,\n );\n });\n } else {\n throw new Error(\"不支持的文件格式\");\n }\n\n return doc;\n}\n\nexport function ydoc2xml(doc: Y.Doc, spaces = 0): string {\n if (doc.share.has(mxfileKey)) {\n return serializer(\n {\n [mxfileKey]: serializerMxFile(doc.getMap(mxfileKey)),\n },\n spaces,\n );\n }\n if (doc.share.has(mxGraphModelKey)) {\n return serializer(\n {\n [mxGraphModelKey]: serializerMxGraphModel(doc.getMap(mxGraphModelKey)),\n },\n spaces,\n );\n }\n\n return \"\";\n}\n"],"names":["key","parse","xml2js","serializer","js2xml","Y","serialize","mxCellKey","parseMxCell","serializeMxCell","parseMxGraphModel","mxGraphModelKey","serializeMxGraphModel","diagramKey","_a","parseDiagram","serializeDiagram","parseMxFile","mxfileKey","serializerMxFile","serializerMxGraphModel"],"mappings":"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"}