collabmd 0.1.48 → 0.1.49
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 +61 -5
- package/bin/collabmd.js +3 -0
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-C-nmgL5g.js +1 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-CdVZqicp.js +1 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-I39sYjHI.js → architectureDiagram-5GKGNRK7-wUo0bXif.js} +3 -3
- package/dist/client/assets/{blockDiagram-NRAW4CY4-C6DtJy5Y.js → blockDiagram-I7D4REHJ-BRSK3m49.js} +4 -4
- package/dist/client/assets/browser-utils-DbXSMI-6.js +1 -0
- package/dist/client/assets/{c4Diagram-UCG6FXSJ-CtWtxS9_.js → c4Diagram-7LVT6UL2-yD2poxqw.js} +1 -1
- package/dist/client/assets/channel-Fa4GS_-F.js +1 -0
- package/dist/client/assets/chunk-2E4U76K2-BPnTT-J3.js +2 -0
- package/dist/client/assets/{chunk-TEH6E4GO-DVayPj-q.js → chunk-4HAMMTFA-DStbIfJ1.js} +20 -20
- package/dist/client/assets/{chunk-75Z2AOVW-CdFSaPjz.js → chunk-75Z2AOVW-C5pGd3W9.js} +1 -1
- package/dist/client/assets/{chunk-CLGD4ZFX-DQLgbQrv.js → chunk-CLGD4ZFX-BMeArk03.js} +1 -1
- package/dist/client/assets/chunk-DU6HZSFF-Zkp69c6c.js +127 -0
- package/dist/client/assets/{chunk-F27PBJKO-CNHIFhjo.js → chunk-F27PBJKO-D4xNct1r.js} +1 -1
- package/dist/client/assets/{chunk-GMAD6QVW-CbcBqPM5.js → chunk-GMAD6QVW-NZ6WpDb8.js} +1 -1
- package/dist/client/assets/{chunk-OBVCFTLP-BJR7u1jh.js → chunk-GVQU2GXP-D8SDprfX.js} +1 -1
- package/dist/client/assets/{chunk-G27WJ6UU-D9-eg537.js → chunk-IMKFNOWR-D8jEuU3Q.js} +2 -2
- package/dist/client/assets/{chunk-JQ64N6SF-DSFNH4bh.js → chunk-L3NEJ4N5-aijKP-eh.js} +1 -1
- package/dist/client/assets/chunk-OSK3NFVY-CCbLQAMa.js +10 -0
- package/dist/client/assets/{chunk-P2QGCYS3-BRpqY32H.js → chunk-P2QGCYS3-Oag_FdCq.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-Cb4SlVZF.js → chunk-POPQ4Y6H-CYnpIgXT.js} +1 -1
- package/dist/client/assets/{chunk-PWAF6VOD-Cz8IwBB5.js → chunk-PWAF6VOD-JSNrcBmP.js} +1 -1
- package/dist/client/assets/{chunk-RM4UPSZO-CWRwxNWJ.js → chunk-RM4UPSZO-DOWllDY8.js} +4 -4
- package/dist/client/assets/{chunk-RHFEMEQ7-CWY8cf4H.js → chunk-SHT3W25Y-BiQGljao.js} +5 -5
- package/dist/client/assets/{chunk-SVP7TREG-CyHOmcac.js → chunk-SVP7TREG-DB485R5x.js} +1 -1
- package/dist/client/assets/{chunk-LCL6LL3I-DmDkVukh.js → chunk-TICWLB2K-8rAVvoS3.js} +4 -4
- package/dist/client/assets/{chunk-CKBBP62Z-DG26UiBv.js → chunk-TLUHSLCS-DTY5v0aj.js} +2 -2
- package/dist/client/assets/classDiagram-ZZMXUADV-BsQWoR3Q.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BsQWoR3Q.js +1 -0
- package/dist/client/assets/{comment-thread-store-CdcwrObc.js → comment-thread-store-CX98zR6q.js} +1 -1
- package/dist/client/assets/comment-threads-BnRwo5B9.js +4 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CdTPi2yO.js → cynefinDiagram-5FMLGOSQ-rTz9RhFH.js} +1 -1
- package/dist/client/assets/{dagre-3AP2YEHR-5gtJtd0O.js → dagre-GXQ25YYZ-Cr67wLpQ.js} +2 -2
- package/dist/client/assets/{diagram-S7CK7UJ4-BudWz9WU.js → diagram-S7CK7UJ4-DywERe__.js} +2 -2
- package/dist/client/assets/{diagram-UQ7AKVKN-3v4rbH-s.js → diagram-UQ7AKVKN-CNYlXtu4.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-0H1a61Bn.js +3 -0
- package/dist/client/assets/{diagram-VX7I27RA-C_-rj0sw.js → diagram-VX7I27RA-CsJbsx5F.js} +1 -1
- package/dist/client/assets/{diagram-Z3DM3KII-B4yxavgj.js → diagram-Z3DM3KII-D0mLxEgI.js} +1 -1
- package/dist/client/assets/dist--hk9I5HQ.js +1 -0
- package/dist/client/assets/{dist-DutPuFmC.js → dist-B1XEa-Zs.js} +1 -1
- package/dist/client/assets/dist-Bd1JucQF.js +1 -0
- package/dist/client/assets/{dist-DZAAWTG-.js → dist-C0G3AaXG.js} +1 -1
- package/dist/client/assets/dist-Dm4w5UId.js +1 -0
- package/dist/client/assets/{dist-B_yQaEv_.js → dist-DpYDHR9p.js} +1 -1
- package/dist/client/assets/{dist-CietwTVS.js → dist-DzNmC81X.js} +1 -1
- package/dist/client/assets/{dist-DDUn5zTz.js → dist-GvvCNBe4.js} +1 -1
- package/dist/client/assets/dist-JaU3aRlD.js +19 -0
- package/dist/client/assets/{dist-Bw3VIE_v.js → dist-TW8iFRyW.js} +1 -1
- package/dist/client/assets/{dist-Dir5dDKZ.js → dist-jVU5Be5P.js} +1 -1
- package/dist/client/assets/document-formatter-rDDjRfZ2.js +2 -0
- package/dist/client/assets/drawioEditor-JubEEha7.js +9 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-HeTxHpCU.js +1 -0
- package/dist/client/assets/editor-session-Bk6oIvSr.js +54 -0
- package/dist/client/assets/{embedded-editor-base-B3l6Xy65.css → embedded-editor-base-BlCgz6mw.css} +1 -1
- package/dist/client/assets/{erDiagram-SSCWMZ5O-C-iy6VkX.js → erDiagram-RLTQ6QDP-CbrDdd5P.js} +2 -2
- package/dist/client/assets/{vault-utils-DvoSftJT.js → es-Bfdp096f.js} +13 -13
- package/dist/client/assets/excalidraw-element-link-YLIaTnVF.js +7 -0
- package/dist/client/assets/{excalidraw-scene-BOben2gr.js → excalidraw-scene-6uROebca.js} +1 -1
- package/dist/client/assets/excalidrawEditor-dBMbRX_S.js +9 -0
- package/dist/client/assets/export-page-CRRQ2NEl.js +57 -0
- package/dist/client/assets/exportDocument-BlQRd9_m.js +2 -0
- package/dist/client/assets/exportDocument-CNSbjZwu.css +1 -0
- package/dist/client/assets/flowDiagram-HODETNUW-D5Gy0wmg.js +1 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-DtKHAbez.js → ganttDiagram-EL5Y4UJY-BHgOYiZz.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-oue8fQ5o.js → gitGraphDiagram-WWUBYQGX-Dl__X3Sk.js} +1 -1
- package/dist/client/assets/image-ZVKINSPA-DgzW5zAy.js +1 -0
- package/dist/client/assets/index-D3RER1SZ.js +1023 -0
- package/dist/client/assets/index-DREVKl_K.css +1 -0
- package/dist/client/assets/{infoDiagram-RXCK75RN-BMzo6KIn.js → infoDiagram-27XIBGKW-DBpoANC9.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BIM3h287.js → ishikawaDiagram-5VMMS53U-BMPC6hfp.js} +1 -1
- package/dist/client/assets/{journeyDiagram-EYS64GPL-mF6Lh8O-.js → journeyDiagram-3NMN7TZE-B1sApUmM.js} +2 -2
- package/dist/client/assets/{kanban-definition-3QL26DDD-DLN2NyoR.js → kanban-definition-UXKFOSKX-C9yP4td1.js} +4 -4
- package/dist/client/assets/{line-BfTWJmgf.js → line-BFl3ujec.js} +1 -1
- package/dist/client/assets/mermaid.core-BrY09czX.js +11 -0
- package/dist/client/assets/mermaid.core-DfcNfOTv.js +1 -0
- package/dist/client/assets/{mindmap-definition-FBJOCRG2-CRyHaHTk.js → mindmap-definition-YA3MSWOX-BUQHcYbK.js} +8 -8
- package/dist/client/assets/pegDiagram-XKGWAZYB-Bi2Iml7Z.js +1 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-B5OZPb88.js → pieDiagram-E7YTZNPT-_gYXnMoi.js} +1 -1
- package/dist/client/assets/preview-render-compiler-CfxJYldJ.js +41 -0
- package/dist/client/assets/preview-render-compiler-Cu8_i9iS.js +1 -0
- package/dist/client/assets/{preview-render-worker-_QTxqKvP.js → preview-render-worker-c4Yi93qW.js} +41 -35
- package/dist/client/assets/prod-BiJL30sl.js +1 -0
- package/dist/client/assets/prod-qAk7rHa4.js +177 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Drrw14YH.js → quadrantDiagram-AXDQQJYC-DwexhEhd.js} +1 -1
- package/dist/client/assets/quick-switcher-controller-BoIK_wuG.js +1 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-BVA5UbMu.js +1 -0
- package/dist/client/assets/{requirementDiagram-EFPCY7ZU-CRZG6mRB.js → requirementDiagram-BXWQKSXE-C4cKwiIw.js} +2 -2
- package/dist/client/assets/runtime-config-DcmnGcXU.js +1 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-DvarEJpo.js → sankeyDiagram-P5KCCOFB-B5HHkRT2.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-B4oWlb-w.js → sequenceDiagram-WJ2MYXX4-BX6jqJFD.js} +6 -6
- package/dist/client/assets/{stateDiagram-HBIQ2CUA-qbHIIqRZ.js → stateDiagram-D77RDMKH-CmqxyRGx.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-zoLLQVyh.js +1 -0
- package/dist/client/assets/{swimlanes-XN3QIQJK-xB6CtUGj.js → swimlanes-42K2YHIH-Bmgb9Zld.js} +1 -1
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DS-KQN37.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-Lj_yTNlY.js → timeline-definition-24CTP7MA-BA-lVH6P.js} +1 -1
- package/dist/client/assets/vault-api-client-iZLhMJKe.js +6 -0
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BekRp5Y0.js → vennDiagram-4TSXK5OY-DNdUC_Xj.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-kdnV_Hdm.js → wardleyDiagram-VM6X3IG4-C2oY-YbF.js} +1 -1
- package/dist/client/assets/wiki-link-resolver-DFIwErjc.js +1 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DufGwNSB.js → xychartDiagram-S5SC5T6Z-CoIR8CBX.js} +1 -1
- package/dist/client/assets/{yjs-provider-reset-guard-DE0vINDP.js → yjs-provider-reset-guard-9ul1qF6k.js} +1 -1
- package/dist/client/drawio-editor.html +11 -3
- package/dist/client/excalidraw-editor.html +45 -2
- package/dist/client/export-document.html +3 -3
- package/dist/client/index.html +67 -35
- package/integrations/pi/index.ts +94 -0
- package/package.json +41 -32
- package/src/client/app/drawio-editor.html +2 -2
- package/src/client/app/excalidraw-editor.html +2 -2
- package/src/client/app/export-document.html +1 -1
- package/src/client/app/index.html +49 -33
- package/src/client/app/main-entry.js +15 -1
- package/src/client/application/app-shell/chat-feature.js +7 -22
- package/src/client/application/app-shell/git-feature.js +23 -5
- package/src/client/application/app-shell/presence-feature.js +8 -25
- package/src/client/application/app-shell/ui-feature-shell.js +36 -91
- package/src/client/application/app-shell/ui-feature-sidebar.js +43 -7
- package/src/client/application/app-shell/ui-feature-tab-activity.js +19 -6
- package/src/client/application/app-shell/ui-feature-toolbar.js +16 -129
- package/src/client/application/app-shell-elements.js +4 -0
- package/src/client/application/preview-render-compiler.js +1 -87
- package/src/client/application/preview-render-scheduler.js +8 -24
- package/src/client/application/preview-renderer.js +2 -2
- package/src/client/application/webmcp-diagram-renderer.js +47 -0
- package/src/client/application/workspace-coordinator.js +3 -1
- package/src/client/application/workspace-route-controller.js +7 -0
- package/src/client/bootstrap/collabmd-app-shell.js +78 -1
- package/src/client/domain/excalidraw-element-link.js +73 -0
- package/src/client/domain/excalidraw-scene.js +21 -0
- package/src/client/domain/hash-routes.js +8 -0
- package/src/client/domain/room.js +1 -5
- package/src/client/domain/runtime-paths.js +5 -0
- package/src/client/excalidraw-editor.js +135 -10
- package/src/client/export/export-host.js +3 -1
- package/src/client/export/export-pipeline.js +4 -17
- package/src/client/infrastructure/agent-connection-api-client.js +23 -0
- package/src/client/infrastructure/auth-client.js +3 -13
- package/src/client/infrastructure/editor-session.js +11 -0
- package/src/client/infrastructure/editor-view-adapter.js +13 -0
- package/src/client/infrastructure/excalidraw-room-client.js +80 -1
- package/src/client/infrastructure/git-api-client.js +39 -33
- package/src/client/infrastructure/lobby-presence.js +2 -5
- package/src/client/infrastructure/runtime-config.js +11 -1
- package/src/client/infrastructure/tab-activity-lock.js +2 -5
- package/src/client/infrastructure/vault-api-client.js +33 -26
- package/src/client/infrastructure/webmcp-tool-registry.js +283 -0
- package/src/client/infrastructure/workspace-sync-client.js +6 -4
- package/src/client/presentation/agent-connection-controller.js +255 -0
- package/src/client/presentation/backlinks-panel.js +3 -0
- package/src/client/presentation/bases-preview-controller.js +27 -18
- package/src/client/presentation/comment-ui/comment-ui-card.js +4 -2
- package/src/client/presentation/create-menu-presenter.js +19 -16
- package/src/client/presentation/excalidraw-embed-controller.js +164 -4
- package/src/client/presentation/file-explorer-view.js +70 -12
- package/src/client/presentation/file-history-view-controller.js +13 -11
- package/src/client/presentation/git-diff-view-controller.js +35 -43
- package/src/client/presentation/git-panel-controller.js +77 -27
- package/src/client/presentation/image-lightbox-controller.js +20 -16
- package/src/client/presentation/layout-controller.js +3 -1
- package/src/client/presentation/quick-switcher-controller.js +20 -78
- package/src/client/presentation/quick-switcher-text-search.js +10 -14
- package/src/client/styles/components/navigation.css +1 -2
- package/src/client/styles/features/agent-connection.css +202 -0
- package/src/client/styles/features/collaboration-chat.css +8 -1
- package/src/client/styles/features/collaboration-dialogs.css +16 -1
- package/src/client/styles/features/collaboration-presence.css +17 -4
- package/src/client/styles/features/diff-toolbar.css +1 -1
- package/src/client/styles/features/media-lightbox.css +12 -3
- package/src/client/styles/features/quick-switcher.css +20 -11
- package/src/client/styles/foundation/themes.css +2 -0
- package/src/client/styles/layout/editor-page.css +25 -11
- package/src/client/styles/layout/responsive.css +2 -20
- package/src/client/styles/layout/shell.css +1 -0
- package/src/client/styles/layout/sidebar.css +7 -4
- package/src/client/styles/primitives/controls.css +21 -54
- package/src/client/styles/style.css +1 -0
- package/src/domain/agent-tool-definitions.js +796 -0
- package/src/domain/collabmd-content-capabilities.js +149 -0
- package/src/domain/collaboration-protocol.js +2 -0
- package/src/domain/comment-threads.js +3 -5
- package/src/domain/diagram-source.js +50 -0
- package/src/domain/editable-content-revision.js +10 -0
- package/src/domain/editable-text.js +3 -0
- package/src/domain/exact-text-edits.js +69 -0
- package/src/domain/excalidraw-agent-scene.js +522 -0
- package/src/domain/excalidraw-agent-verification.js +460 -0
- package/src/domain/excalidraw-room-codec.js +1 -5
- package/src/domain/video-embed.js +76 -0
- package/src/server/application/agent-connection-service.js +178 -0
- package/src/server/application/agent-content-service.js +773 -0
- package/src/server/application/workspace-reconciliation.js +5 -7
- package/src/server/config/env.js +51 -1
- package/src/server/create-app-server.js +36 -0
- package/src/server/domain/bases/base-query-service.js +1 -5
- package/src/server/domain/collaboration/collaboration-room.js +121 -25
- package/src/server/domain/collaboration/protocol.js +4 -0
- package/src/server/domain/hosted-workspace.js +21 -0
- package/src/server/domain/markdown-reference-extractor.js +15 -1
- package/src/server/infrastructure/git/git-service.js +19 -1
- package/src/server/infrastructure/git/history-service.js +1 -1
- package/src/server/infrastructure/git/local-exclude.js +25 -0
- package/src/server/infrastructure/git/parsers.js +19 -17
- package/src/server/infrastructure/git/path-utils.js +0 -16
- package/src/server/infrastructure/git/status-service.js +1 -1
- package/src/server/infrastructure/git/untracked-files.js +12 -21
- package/src/server/infrastructure/http/create-agent-api-handler.js +171 -0
- package/src/server/infrastructure/http/create-git-api-command-handler.js +32 -0
- package/src/server/infrastructure/http/create-request-handler.js +28 -0
- package/src/server/infrastructure/http/create-static-handler.js +6 -0
- package/src/server/infrastructure/mcp/create-agent-mcp-handler.js +199 -0
- package/src/server/infrastructure/persistence/agent-connection-store.js +120 -0
- package/src/server/infrastructure/persistence/pull-backup-store.js +2 -27
- package/src/server/infrastructure/persistence/vault-file-store.js +9 -2
- package/src/server/shared/agent-tool-image.js +22 -0
- package/src/server/shared/agent-tool-rate-limiter.js +20 -0
- package/src/server/startup/git-remote-bootstrap.js +5 -33
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-BPH4FJkv.js +0 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-BNDLzJ7L.js +0 -1
- package/dist/client/assets/browser-utils--H_DkyEF.js +0 -1
- package/dist/client/assets/channel-CaoKA_We.js +0 -1
- package/dist/client/assets/chunk-DSNCTWBM-8xkug7fQ.js +0 -2
- package/dist/client/assets/chunk-DU6HZSFF-COXDzJK1.js +0 -127
- package/dist/client/assets/chunk-R7TYR2AO-CTd0Yj98.js +0 -10
- package/dist/client/assets/classDiagram-DTDB5LWJ-7fEmn0zV.js +0 -1
- package/dist/client/assets/classDiagram-v2-JRS7N3AN-7fEmn0zV.js +0 -1
- package/dist/client/assets/comment-threads-9J6Em-_y.js +0 -4
- package/dist/client/assets/comment-ui-shared-DuoyznXW.js +0 -7
- package/dist/client/assets/diagram-VSXAHHWV-CQRVEZR7.js +0 -3
- package/dist/client/assets/dist-73RPdcyU.js +0 -1
- package/dist/client/assets/dist-CH-sQu3r.js +0 -1
- package/dist/client/assets/document-formatter-Dxl_a8XO.js +0 -2
- package/dist/client/assets/drawio-editor-BVaNNtYp.js +0 -9
- package/dist/client/assets/drawioEditor-BkIBlXx0.js +0 -2
- package/dist/client/assets/ebnfDiagram-PWID7BFC-OXa8VEp1.js +0 -1
- package/dist/client/assets/editor-session-DMyVdHLj.js +0 -54
- package/dist/client/assets/excalidraw-editor-BjYaNEMY.js +0 -9
- package/dist/client/assets/excalidraw-mermaid-stub-BNckbX2n.js +0 -1
- package/dist/client/assets/excalidraw-mermaid-stub-DE5FTiZB.js +0 -1
- package/dist/client/assets/excalidrawEditor-ChqF_d82.js +0 -2
- package/dist/client/assets/export-page-Dyu0XCbu.js +0 -57
- package/dist/client/assets/exportDocument-CJBx4Xjx.css +0 -1
- package/dist/client/assets/exportDocument-Dgvfa2Sd.js +0 -2
- package/dist/client/assets/flowDiagram-A5DVABFB-CiW1eN8C.js +0 -1
- package/dist/client/assets/image-ZVKINSPA-0zXSnE7M.js +0 -1
- package/dist/client/assets/index-CSNIMyOP.css +0 -1
- package/dist/client/assets/index-DG3N2Ps-.js +0 -2
- package/dist/client/assets/main-D0wCxpVn.js +0 -903
- package/dist/client/assets/mermaid.core-BJRLUQZE.js +0 -11
- package/dist/client/assets/pegDiagram-XKGWAZYB-B31fKPR2.js +0 -1
- package/dist/client/assets/preview-render-compiler-CrJIooVD.js +0 -35
- package/dist/client/assets/preview-render-compiler-O0JxBVNF.js +0 -1
- package/dist/client/assets/preview-render-profile-B4RWYWHt.js +0 -1
- package/dist/client/assets/prod-BiYPMR1i.js +0 -177
- package/dist/client/assets/prod-VxdGZ5Ly.js +0 -1
- package/dist/client/assets/quick-switcher-controller-CaEjEtq_.js +0 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-BPifP0MB.js +0 -1
- package/dist/client/assets/runtime-config-BLrEKVO1.js +0 -1
- package/dist/client/assets/stateDiagram-v2-4QOOHH4V-B--gjrit.js +0 -1
- package/dist/client/assets/swimlanesDiagram-VK2B7HYN-DO8XNXEg.js +0 -8
- package/dist/client/assets/vault-api-client-BkwdFjx0.js +0 -6
- package/src/client/app/drawio-editor-entry.js +0 -1
- package/src/client/app/excalidraw-editor-entry.js +0 -1
- package/src/client/excalidraw-mermaid-stub.js +0 -7
- package/src/client/main.js +0 -16
- /package/dist/client/assets/{drawio-editor-UQQ8XHou.css → drawioEditor-UQQ8XHou.css} +0 -0
- /package/dist/client/assets/{excalidraw-editor-BbSbI80a.css → excalidrawEditor-BbSbI80a.css} +0 -0
- /package/dist/client/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { getElementBounds } from '@excalidraw/element';
|
|
12
12
|
import '@excalidraw/excalidraw/index.css';
|
|
13
13
|
|
|
14
|
+
import { createEditableContentRevision } from '../domain/editable-content-revision.js';
|
|
14
15
|
import {
|
|
15
16
|
buildRenderableCollaboratorsMap,
|
|
16
17
|
findCollaboratorByPeerId,
|
|
@@ -45,6 +46,11 @@ import {
|
|
|
45
46
|
summarizeExcalidrawScene,
|
|
46
47
|
} from './domain/excalidraw-diagnostics.js';
|
|
47
48
|
import { isPlainQuickSwitcherShortcut } from './domain/keyboard-shortcuts.js';
|
|
49
|
+
import {
|
|
50
|
+
createExcalidrawElementLink,
|
|
51
|
+
parseExcalidrawElementLink,
|
|
52
|
+
} from './domain/excalidraw-element-link.js';
|
|
53
|
+
import { resolveAppPath, resolveAppUrl } from './domain/runtime-paths.js';
|
|
48
54
|
import { ensureClientAuthenticated } from './infrastructure/auth-client.js';
|
|
49
55
|
import {
|
|
50
56
|
EXCALIDRAW_ROOM_CONNECTION_STATE,
|
|
@@ -58,6 +64,8 @@ const diagnostics = createExcalidrawDiagnosticRing({
|
|
|
58
64
|
enabled: params.get('excalidrawDebug') === '1',
|
|
59
65
|
});
|
|
60
66
|
const parentOrigin = window.location.origin;
|
|
67
|
+
const appPath = resolveAppPath('/');
|
|
68
|
+
const appUrl = resolveAppUrl('/');
|
|
61
69
|
const syncTimeoutMs = Number.parseInt(params.get('syncTimeoutMs') || '', 10);
|
|
62
70
|
|
|
63
71
|
let currentDocument = {
|
|
@@ -71,6 +79,12 @@ let localAwarenessUser = resolveLocalAwarenessUser({
|
|
|
71
79
|
storedUserName: localStorage.getItem('collabmd-user-name'),
|
|
72
80
|
});
|
|
73
81
|
let appliedSceneJson = '';
|
|
82
|
+
let appliedSceneRevisionPromise = createEditableContentRevision(appliedSceneJson);
|
|
83
|
+
|
|
84
|
+
function setAppliedSceneJson(value) {
|
|
85
|
+
appliedSceneJson = value;
|
|
86
|
+
appliedSceneRevisionPromise = createEditableContentRevision(value);
|
|
87
|
+
}
|
|
74
88
|
|
|
75
89
|
let collabReady = false;
|
|
76
90
|
let pendingRemoteSceneJson = '';
|
|
@@ -327,17 +341,34 @@ function getDiagramCommentMarkerPosition(thread, api = getMountedExcalidrawAPI()
|
|
|
327
341
|
);
|
|
328
342
|
}
|
|
329
343
|
|
|
330
|
-
function
|
|
344
|
+
function getDiagramElementTargets(elementId, elementType = 'element', api = getMountedExcalidrawAPI()) {
|
|
345
|
+
const normalizedElementId = String(elementId ?? '').trim();
|
|
346
|
+
const elements = api?.getSceneElementsIncludingDeleted?.()
|
|
347
|
+
?.filter((element) => !element.isDeleted) || [];
|
|
348
|
+
if (!normalizedElementId) {
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (elementType === 'group') {
|
|
353
|
+
const groupElements = elements.filter((element) => element.groupIds?.includes(normalizedElementId));
|
|
354
|
+
if (groupElements.length > 0) {
|
|
355
|
+
return groupElements;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return elements.filter((element) => element.id === normalizedElementId);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function focusDiagramElement(elementId, elementType = 'element') {
|
|
331
363
|
const api = getMountedExcalidrawAPI();
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
if (!api || !element) {
|
|
364
|
+
const elements = getDiagramElementTargets(elementId, elementType, api);
|
|
365
|
+
if (!api || elements.length === 0) {
|
|
335
366
|
return;
|
|
336
367
|
}
|
|
337
368
|
|
|
338
369
|
api.updateScene({
|
|
339
370
|
appState: {
|
|
340
|
-
selectedElementIds:
|
|
371
|
+
selectedElementIds: Object.fromEntries(elements.map((element) => [element.id, true])),
|
|
341
372
|
},
|
|
342
373
|
captureUpdate: CaptureUpdateAction.NEVER,
|
|
343
374
|
});
|
|
@@ -352,11 +383,16 @@ function focusDiagramCommentThread(thread) {
|
|
|
352
383
|
animation: false,
|
|
353
384
|
fit: 'contain',
|
|
354
385
|
offsets: { ui: true },
|
|
355
|
-
target:
|
|
386
|
+
target: elements,
|
|
356
387
|
});
|
|
357
388
|
} finally {
|
|
358
389
|
releaseViewportBroadcastSuppressionAfterPaint();
|
|
359
390
|
}
|
|
391
|
+
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function focusDiagramCommentThread(thread) {
|
|
395
|
+
focusDiagramElement(thread?.elementId);
|
|
360
396
|
}
|
|
361
397
|
|
|
362
398
|
function applyDocumentMode(mode = currentDocument.mode) {
|
|
@@ -413,6 +449,23 @@ function createRoomClient(filePath) {
|
|
|
413
449
|
};
|
|
414
450
|
}
|
|
415
451
|
|
|
452
|
+
function handleExcalidrawLinkOpen(element, event) {
|
|
453
|
+
if (window.parent === window) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const target = parseExcalidrawElementLink(element?.link, {
|
|
458
|
+
appPath,
|
|
459
|
+
origin: parentOrigin,
|
|
460
|
+
});
|
|
461
|
+
if (!target) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
event?.preventDefault?.();
|
|
466
|
+
postToParent('open-element-link', { href: element.link });
|
|
467
|
+
}
|
|
468
|
+
|
|
416
469
|
function buildExcalidrawProps({ initialData, renderTopRightUI, viewModeEnabled } = {}) {
|
|
417
470
|
const props = {
|
|
418
471
|
onMount: handleEditorMount,
|
|
@@ -431,11 +484,17 @@ function buildExcalidrawProps({ initialData, renderTopRightUI, viewModeEnabled }
|
|
|
431
484
|
collabReady = false;
|
|
432
485
|
},
|
|
433
486
|
aiEnabled: false,
|
|
487
|
+
generateLinkForSelection: (elementId, elementType) => createExcalidrawElementLink(
|
|
488
|
+
currentDocument.filePath,
|
|
489
|
+
elementId,
|
|
490
|
+
{ appUrl, elementType },
|
|
491
|
+
),
|
|
434
492
|
isCollaborating: true,
|
|
435
493
|
onChange: (elements, appState, files) => {
|
|
436
494
|
scheduleSyncToRoom(elements, appState, files);
|
|
437
495
|
roomClient?.syncLocalSelectionAwareness(appState);
|
|
438
496
|
},
|
|
497
|
+
onLinkOpen: handleExcalidrawLinkOpen,
|
|
439
498
|
onPointerUpdate: (payload) => {
|
|
440
499
|
roomClient?.scheduleLocalPointerAwareness(payload);
|
|
441
500
|
},
|
|
@@ -1199,6 +1258,9 @@ if (isTestMode) {
|
|
|
1199
1258
|
.map((element) => element.id)
|
|
1200
1259
|
.sort() ?? []
|
|
1201
1260
|
),
|
|
1261
|
+
getSelectedElementIds: () => (
|
|
1262
|
+
Object.keys(getMountedExcalidrawAPI()?.getAppState?.()?.selectedElementIds || {}).sort()
|
|
1263
|
+
),
|
|
1202
1264
|
getElementStatus: (elementId) => (
|
|
1203
1265
|
getMountedExcalidrawAPI()?.getSceneElementsIncludingDeleted?.()
|
|
1204
1266
|
?.find((entry) => entry.id === elementId && !entry.isDeleted)?.status ?? null
|
|
@@ -1347,7 +1409,7 @@ function applySceneFromJson(rawJson, {
|
|
|
1347
1409
|
return;
|
|
1348
1410
|
}
|
|
1349
1411
|
|
|
1350
|
-
|
|
1412
|
+
setAppliedSceneJson(normalizedJson);
|
|
1351
1413
|
recordSceneDiagnostic('remote-scene-received', {}, normalizedJson);
|
|
1352
1414
|
|
|
1353
1415
|
if (!getMountedExcalidrawAPI() || !collabReady) {
|
|
@@ -1423,7 +1485,7 @@ function requestEditorRemount(scene) {
|
|
|
1423
1485
|
const normalizedScene = normalizeScene(scene);
|
|
1424
1486
|
const normalizedJson = JSON.stringify(normalizedScene);
|
|
1425
1487
|
pendingRemoteSceneJson = normalizedJson;
|
|
1426
|
-
|
|
1488
|
+
setAppliedSceneJson(normalizedJson);
|
|
1427
1489
|
pendingCollaborators = activeCollaborators;
|
|
1428
1490
|
initialViewportFitPending = true;
|
|
1429
1491
|
clearPreviewViewportFitTimers();
|
|
@@ -1499,7 +1561,7 @@ function applyLocalScene(scene, {
|
|
|
1499
1561
|
const normalizedScene = normalizeScene(scene);
|
|
1500
1562
|
const normalizedJson = JSON.stringify(normalizedScene);
|
|
1501
1563
|
|
|
1502
|
-
|
|
1564
|
+
setAppliedSceneJson(normalizedJson);
|
|
1503
1565
|
|
|
1504
1566
|
if (!getMountedExcalidrawAPI() || !collabReady) {
|
|
1505
1567
|
pendingRemoteSceneJson = normalizedJson;
|
|
@@ -1845,6 +1907,36 @@ async function waitForPendingRoomWrites({
|
|
|
1845
1907
|
}
|
|
1846
1908
|
}
|
|
1847
1909
|
|
|
1910
|
+
function waitForAnimationFrame() {
|
|
1911
|
+
return new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
async function waitForAppliedSceneRevision(revision, {
|
|
1915
|
+
afterRevision = '',
|
|
1916
|
+
maxWaitMs = 4500,
|
|
1917
|
+
} = {}) {
|
|
1918
|
+
const startedAt = performance.now();
|
|
1919
|
+
while ((performance.now() - startedAt) < maxWaitMs) {
|
|
1920
|
+
const appliedRevision = await appliedSceneRevisionPromise;
|
|
1921
|
+
if (
|
|
1922
|
+
!pendingRemoteSceneJson
|
|
1923
|
+
&& (appliedRevision === revision || (afterRevision && appliedRevision !== afterRevision))
|
|
1924
|
+
) {
|
|
1925
|
+
await waitForAnimationFrame();
|
|
1926
|
+
await waitForAnimationFrame();
|
|
1927
|
+
const paintedRevision = await appliedSceneRevisionPromise;
|
|
1928
|
+
if (
|
|
1929
|
+
!pendingRemoteSceneJson
|
|
1930
|
+
&& (paintedRevision === revision || (afterRevision && paintedRevision !== afterRevision))
|
|
1931
|
+
) {
|
|
1932
|
+
return paintedRevision;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
await new Promise((resolve) => window.setTimeout(resolve, 16));
|
|
1936
|
+
}
|
|
1937
|
+
return '';
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1848
1940
|
async function prepareRealtimeRoomDisconnect() {
|
|
1849
1941
|
if (!roomClient) {
|
|
1850
1942
|
return true;
|
|
@@ -1942,6 +2034,11 @@ window.addEventListener('message', (event) => {
|
|
|
1942
2034
|
return;
|
|
1943
2035
|
}
|
|
1944
2036
|
|
|
2037
|
+
if (message.type === 'focus-element') {
|
|
2038
|
+
focusDiagramElement(message.elementId, message.elementType);
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
1945
2042
|
if (message.type === 'follow-user') {
|
|
1946
2043
|
applyHostFollowRequest(message.peerId || null);
|
|
1947
2044
|
return;
|
|
@@ -1952,6 +2049,34 @@ window.addEventListener('message', (event) => {
|
|
|
1952
2049
|
return;
|
|
1953
2050
|
}
|
|
1954
2051
|
|
|
2052
|
+
if (message.type === 'flush-agent-writes') {
|
|
2053
|
+
void (async () => {
|
|
2054
|
+
roomClient?.flushSceneSync();
|
|
2055
|
+
await waitForPendingRoomWrites({ maxWaitMs: 1000 });
|
|
2056
|
+
const serverFlush = await roomClient?.waitForServerFlush?.({ timeoutMs: 1000 });
|
|
2057
|
+
postToParent('agent-writes-flushed', {
|
|
2058
|
+
requestId: message.requestId || '',
|
|
2059
|
+
revision: await appliedSceneRevisionPromise,
|
|
2060
|
+
status: serverFlush?.status || 'unavailable',
|
|
2061
|
+
});
|
|
2062
|
+
})();
|
|
2063
|
+
return;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
if (message.type === 'wait-for-agent-revision') {
|
|
2067
|
+
void (async () => {
|
|
2068
|
+
const revision = String(message.revision || '');
|
|
2069
|
+
const paintedRevision = revision && await waitForAppliedSceneRevision(revision, {
|
|
2070
|
+
afterRevision: String(message.afterRevision || ''),
|
|
2071
|
+
});
|
|
2072
|
+
postToParent(paintedRevision ? 'agent-revision-painted' : 'agent-revision-not-painted', {
|
|
2073
|
+
requestId: message.requestId || '',
|
|
2074
|
+
revision: paintedRevision || revision,
|
|
2075
|
+
});
|
|
2076
|
+
})();
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
1955
2080
|
if (message.type === 'prepare-disconnect') {
|
|
1956
2081
|
void (async () => {
|
|
1957
2082
|
const requestId = message.requestId || '';
|
|
@@ -2053,7 +2178,7 @@ function initializeEditor(api) {
|
|
|
2053
2178
|
const sceneJson = pendingRemoteSceneJson || roomClient?.getLastSceneJson?.() || '';
|
|
2054
2179
|
const initialScene = parseSceneJson(sceneJson);
|
|
2055
2180
|
pendingRemoteSceneJson = '';
|
|
2056
|
-
|
|
2181
|
+
setAppliedSceneJson(JSON.stringify(initialScene));
|
|
2057
2182
|
updateApiScene(initialScene);
|
|
2058
2183
|
|
|
2059
2184
|
if (pendingCollaborators) {
|
|
@@ -8,7 +8,9 @@ const pendingJobs = new Map();
|
|
|
8
8
|
let exportBridgeErrorHandler = null;
|
|
9
9
|
|
|
10
10
|
function createJobId() {
|
|
11
|
-
|
|
11
|
+
const id = globalThis.crypto?.randomUUID?.()
|
|
12
|
+
?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
13
|
+
return `export-${id}`;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
function normalizeFormat(format) {
|
|
@@ -17,10 +17,11 @@ import { compilePreviewDocument } from '../application/preview-render-compiler.j
|
|
|
17
17
|
import { isMarkdownFilePath, stripVaultFileExtension } from '../../domain/file-kind.js';
|
|
18
18
|
import { resolveVaultRelativePath } from '../../domain/vault-paths.js';
|
|
19
19
|
import { resolveWikiTargetPath } from '../../domain/wiki-link-resolver.js';
|
|
20
|
-
import {
|
|
20
|
+
import { createExcalidrawExportOptions, parseSceneJson } from '../domain/excalidraw-scene.js';
|
|
21
21
|
import { escapeHtml } from '../domain/vault-utils.js';
|
|
22
22
|
import { downloadBlob } from '../browser-utils.js';
|
|
23
23
|
import { resolveApiUrl, resolveAppUrl } from '../infrastructure/runtime-config.js';
|
|
24
|
+
import { parseApiResponse } from '../infrastructure/api-client-utils.js';
|
|
24
25
|
|
|
25
26
|
const EXPORT_PAGE_SOURCE = 'collabmd-export-page';
|
|
26
27
|
const EXPORT_HOST_SOURCE = 'collabmd-export-host';
|
|
@@ -355,11 +356,7 @@ async function fetchJson(url, init = {}) {
|
|
|
355
356
|
},
|
|
356
357
|
...init,
|
|
357
358
|
});
|
|
358
|
-
|
|
359
|
-
if (!response.ok) {
|
|
360
|
-
throw new Error(data?.error || `Request failed: ${response.status}`);
|
|
361
|
-
}
|
|
362
|
-
return data;
|
|
359
|
+
return parseApiResponse(response, `Request failed: ${response.status}`);
|
|
363
360
|
}
|
|
364
361
|
|
|
365
362
|
async function fetchTextFile(filePath) {
|
|
@@ -820,17 +817,7 @@ async function renderPlantUmlToSvgMarkup(source) {
|
|
|
820
817
|
async function renderExcalidrawToSvgMarkup(filePath) {
|
|
821
818
|
const rawScene = await fetchTextFile(filePath);
|
|
822
819
|
const scene = parseSceneJson(rawScene);
|
|
823
|
-
const
|
|
824
|
-
const svgElement = await exportExcalidrawToSvg({
|
|
825
|
-
appState: {
|
|
826
|
-
...initialData.appState,
|
|
827
|
-
exportBackground: true,
|
|
828
|
-
exportWithDarkMode: false,
|
|
829
|
-
},
|
|
830
|
-
elements: initialData.elements.filter((element) => !element.isDeleted),
|
|
831
|
-
exportPadding: 24,
|
|
832
|
-
files: initialData.files || null,
|
|
833
|
-
});
|
|
820
|
+
const svgElement = await exportExcalidrawToSvg(createExcalidrawExportOptions(scene));
|
|
834
821
|
return normalizeExportSvgMarkup(svgElement.outerHTML, { padding: 24 });
|
|
835
822
|
}
|
|
836
823
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { resolveApiUrl } from '../domain/runtime-paths.js';
|
|
2
|
+
import { parseApiResponse } from './api-client-utils.js';
|
|
3
|
+
|
|
4
|
+
export const agentConnectionApiClient = {
|
|
5
|
+
listConnections() {
|
|
6
|
+
return fetch(resolveApiUrl('/agent/connections'))
|
|
7
|
+
.then((response) => parseApiResponse(response, 'Failed to load Agent Connections'));
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
createConnection(payload) {
|
|
11
|
+
return fetch(resolveApiUrl('/agent/connections'), {
|
|
12
|
+
body: JSON.stringify(payload),
|
|
13
|
+
headers: { 'Content-Type': 'application/json' },
|
|
14
|
+
method: 'POST',
|
|
15
|
+
}).then((response) => parseApiResponse(response, 'Failed to create Agent Connection'));
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
revokeConnection(connectionId) {
|
|
19
|
+
return fetch(resolveApiUrl(`/agent/connections/${encodeURIComponent(connectionId)}`), {
|
|
20
|
+
method: 'DELETE',
|
|
21
|
+
}).then((response) => parseApiResponse(response, 'Failed to revoke Agent Connection'));
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../styles/features/auth-gate.css';
|
|
2
2
|
|
|
3
3
|
import { getHashParamsFromRaw } from '../domain/hash-routes.js';
|
|
4
|
+
import { parseApiResponse } from './api-client-utils.js';
|
|
4
5
|
import { getRuntimeConfig } from './runtime-config.js';
|
|
5
6
|
|
|
6
7
|
const DEFAULT_AUTH_CONFIG = {
|
|
@@ -66,12 +67,7 @@ async function fetchAuthStatus(config) {
|
|
|
66
67
|
},
|
|
67
68
|
});
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
if (!response.ok) {
|
|
71
|
-
throw new Error(payload.error || 'Failed to read auth status');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return payload;
|
|
70
|
+
return parseApiResponse(response, 'Failed to read auth status');
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
function syncOidcIdentityToLocalState(status) {
|
|
@@ -100,13 +96,7 @@ async function submitPassword(config, password) {
|
|
|
100
96
|
},
|
|
101
97
|
body: JSON.stringify({ password }),
|
|
102
98
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (!response.ok) {
|
|
106
|
-
throw new Error(payload.error || 'Authentication failed');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return payload;
|
|
99
|
+
return parseApiResponse(response, 'Authentication failed');
|
|
110
100
|
}
|
|
111
101
|
|
|
112
102
|
function createOverlayShell() {
|
|
@@ -290,6 +290,13 @@ export class EditorSession {
|
|
|
290
290
|
return this.viewAdapter.insertText(text);
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
applyTextReplacements(replacements) {
|
|
294
|
+
if (!this.collaborationClient.initialSyncComplete) {
|
|
295
|
+
throw new Error('The collaborative document is not synchronized');
|
|
296
|
+
}
|
|
297
|
+
return this.viewAdapter.applyTextReplacements(replacements);
|
|
298
|
+
}
|
|
299
|
+
|
|
293
300
|
replaceText(text) {
|
|
294
301
|
return this.viewAdapter.replaceText(text);
|
|
295
302
|
}
|
|
@@ -306,6 +313,10 @@ export class EditorSession {
|
|
|
306
313
|
return this.viewAdapter.flashRemoteRange(range);
|
|
307
314
|
}
|
|
308
315
|
|
|
316
|
+
isInitialSyncComplete() {
|
|
317
|
+
return this.collaborationClient.initialSyncComplete;
|
|
318
|
+
}
|
|
319
|
+
|
|
309
320
|
waitForInitialSync(timeoutMs = 1500) {
|
|
310
321
|
return this.collaborationClient.waitForInitialSync(timeoutMs);
|
|
311
322
|
}
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
isPlantUmlFilePath,
|
|
51
51
|
isStructurizrFilePath,
|
|
52
52
|
} from '../../domain/file-kind.js';
|
|
53
|
+
import { resolveExactTextChanges } from '../../domain/exact-text-edits.js';
|
|
53
54
|
import { normalizeCommentQuote } from '../../domain/comment-threads.js';
|
|
54
55
|
import { formatDocumentText } from '../domain/document-formatter.js';
|
|
55
56
|
import { createMarkdownToolbarEdit } from '../domain/markdown-formatting.js';
|
|
@@ -1143,6 +1144,18 @@ export class EditorViewAdapter {
|
|
|
1143
1144
|
return true;
|
|
1144
1145
|
}
|
|
1145
1146
|
|
|
1147
|
+
applyTextReplacements(replacements) {
|
|
1148
|
+
if (!this.editorView) {
|
|
1149
|
+
throw new Error('The editor is not available');
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
const { state } = this.editorView;
|
|
1153
|
+
const changes = resolveExactTextChanges(state.doc.toString(), replacements);
|
|
1154
|
+
|
|
1155
|
+
this.editorView.dispatch({ changes, userEvent: 'input' });
|
|
1156
|
+
return changes.length;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1146
1159
|
replaceText(text) {
|
|
1147
1160
|
if (!this.editorView) {
|
|
1148
1161
|
return false;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Doc } from 'yjs';
|
|
2
2
|
import { WebsocketProvider } from 'y-websocket';
|
|
3
|
+
import * as decoding from 'lib0/decoding';
|
|
4
|
+
import * as encoding from 'lib0/encoding';
|
|
3
5
|
import {
|
|
4
6
|
EXCALIDRAW_APP_STATE_KEY,
|
|
5
7
|
EXCALIDRAW_ELEMENTS_KEY,
|
|
@@ -12,6 +14,10 @@ import {
|
|
|
12
14
|
readLegacyExcalidrawRoomScene,
|
|
13
15
|
replaceExcalidrawRoomScene,
|
|
14
16
|
} from '../../domain/excalidraw-room-codec.js';
|
|
17
|
+
import {
|
|
18
|
+
MSG_AGENT_FLUSH,
|
|
19
|
+
MSG_AGENT_FLUSH_ACK,
|
|
20
|
+
} from '../../domain/collaboration-protocol.js';
|
|
15
21
|
|
|
16
22
|
import {
|
|
17
23
|
buildCollaboratorsMap,
|
|
@@ -33,6 +39,7 @@ import { stopReconnectOnControlledClose } from './yjs-provider-reset-guard.js';
|
|
|
33
39
|
const DEFAULT_EMPTY_SCENE_GUARD_MS = 250;
|
|
34
40
|
const DEFAULT_SAVE_THROTTLE_MS = 48;
|
|
35
41
|
const DEFAULT_SYNC_TIMEOUT_MS = 4000;
|
|
42
|
+
const DEFAULT_AGENT_FLUSH_TIMEOUT_MS = 1000;
|
|
36
43
|
|
|
37
44
|
export const EXCALIDRAW_ROOM_CONNECTION_STATE = Object.freeze({
|
|
38
45
|
AUTHORITATIVE: 'authoritative',
|
|
@@ -178,6 +185,8 @@ export class ExcalidrawRoomClient {
|
|
|
178
185
|
this.lastViewportSignature = '';
|
|
179
186
|
this.lastSelectedIdsSignature = '';
|
|
180
187
|
this.pendingEmptySceneCandidate = null;
|
|
188
|
+
this.agentFlushRequestCounter = 0;
|
|
189
|
+
this.pendingAgentFlushRequests = new Map();
|
|
181
190
|
this.structuredObserversAttached = false;
|
|
182
191
|
this.canWriteToRoom = false;
|
|
183
192
|
this.waitingForAuthoritativeSync = false;
|
|
@@ -250,6 +259,74 @@ export class ExcalidrawRoomClient {
|
|
|
250
259
|
return this.connectionState;
|
|
251
260
|
}
|
|
252
261
|
|
|
262
|
+
installAgentFlushHandler() {
|
|
263
|
+
const messageHandlers = this.provider?.messageHandlers;
|
|
264
|
+
if (!messageHandlers || typeof messageHandlers !== 'object') {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
messageHandlers[MSG_AGENT_FLUSH_ACK] = (_encoder, decoder) => {
|
|
269
|
+
let requestId;
|
|
270
|
+
try {
|
|
271
|
+
requestId = decoding.readVarString(decoder);
|
|
272
|
+
} catch {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const request = this.pendingAgentFlushRequests.get(requestId);
|
|
277
|
+
if (!request) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
request.resolve({ status: 'acknowledged' });
|
|
282
|
+
};
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
settleAgentFlushRequests(status) {
|
|
287
|
+
const requests = [...this.pendingAgentFlushRequests.values()];
|
|
288
|
+
requests.forEach((request) => request.resolve({ status }));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
waitForServerFlush({ timeoutMs = DEFAULT_AGENT_FLUSH_TIMEOUT_MS } = {}) {
|
|
292
|
+
const ws = this.provider?.ws;
|
|
293
|
+
const openState = ws?.OPEN ?? globalThis.WebSocket?.OPEN ?? 1;
|
|
294
|
+
if (
|
|
295
|
+
!this.canWriteToRoom
|
|
296
|
+
|| !ws
|
|
297
|
+
|| ws.readyState !== openState
|
|
298
|
+
|| !this.provider?.messageHandlers?.[MSG_AGENT_FLUSH_ACK]
|
|
299
|
+
) {
|
|
300
|
+
return Promise.resolve({ status: 'unavailable' });
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const requestId = `agent-flush-${this.ydoc?.clientID ?? 'client'}-${++this.agentFlushRequestCounter}`;
|
|
304
|
+
return new Promise((resolve) => {
|
|
305
|
+
const finish = (result) => {
|
|
306
|
+
const request = this.pendingAgentFlushRequests.get(requestId);
|
|
307
|
+
if (!request) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
this.clearTimeoutFn(request.timeoutId);
|
|
311
|
+
this.pendingAgentFlushRequests.delete(requestId);
|
|
312
|
+
resolve(result);
|
|
313
|
+
};
|
|
314
|
+
this.pendingAgentFlushRequests.set(requestId, {
|
|
315
|
+
resolve: finish,
|
|
316
|
+
timeoutId: this.setTimeoutFn(() => finish({ status: 'timeout' }), timeoutMs),
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const encoder = encoding.createEncoder();
|
|
321
|
+
encoding.writeVarUint(encoder, MSG_AGENT_FLUSH);
|
|
322
|
+
encoding.writeVarString(encoder, requestId);
|
|
323
|
+
ws.send(encoding.toUint8Array(encoder));
|
|
324
|
+
} catch {
|
|
325
|
+
finish({ status: 'unavailable' });
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
253
330
|
hasPendingWrites() {
|
|
254
331
|
return Boolean(this.pendingSceneSyncPayload);
|
|
255
332
|
}
|
|
@@ -368,6 +445,7 @@ export class ExcalidrawRoomClient {
|
|
|
368
445
|
disableBc: true,
|
|
369
446
|
maxBackoffTime: 5000,
|
|
370
447
|
});
|
|
448
|
+
this.installAgentFlushHandler();
|
|
371
449
|
stopReconnectOnControlledClose(this.provider);
|
|
372
450
|
|
|
373
451
|
this.awareness = this.provider.awareness;
|
|
@@ -636,7 +714,7 @@ export class ExcalidrawRoomClient {
|
|
|
636
714
|
}
|
|
637
715
|
|
|
638
716
|
scheduleSceneSync(elements, appState, files) {
|
|
639
|
-
if (!this.canWriteToRoom) {
|
|
717
|
+
if (!this.canWriteToRoom || this.isApplyingSharedSnapshot()) {
|
|
640
718
|
return false;
|
|
641
719
|
}
|
|
642
720
|
|
|
@@ -933,6 +1011,7 @@ export class ExcalidrawRoomClient {
|
|
|
933
1011
|
|
|
934
1012
|
disconnect() {
|
|
935
1013
|
this.flushSceneSync();
|
|
1014
|
+
this.settleAgentFlushRequests('disconnected');
|
|
936
1015
|
this.setConnectionState(EXCALIDRAW_ROOM_CONNECTION_STATE.DISCONNECTING);
|
|
937
1016
|
this.clearTimeoutFn(this.sceneSyncTimer);
|
|
938
1017
|
this.sceneSyncTimer = null;
|