collabmd 0.1.44 → 0.1.46
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 +39 -19
- package/bin/collabmd.js +27 -1
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-CYM5nxUi.js +1 -0
- package/dist/client/assets/browser-utils--H_DkyEF.js +1 -0
- package/dist/client/assets/chunk-ERSWUTIN-hHdvnhaY.js +41 -0
- package/dist/client/assets/{chunk-CZQZEIFA-DT3N9fo7.js → chunk-YGJVY4SA-CjSe7Bx7.js} +2 -2
- package/dist/client/assets/comment-thread-store-CdcwrObc.js +1 -0
- package/dist/client/assets/comment-threads-9J6Em-_y.js +4 -0
- package/dist/client/assets/comment-ui-shared-BC4pt4w8.js +7 -0
- package/dist/client/assets/dist-B5HTH2BO.js +1 -0
- package/dist/client/assets/{dist-DhLvC8DS.js → dist-B5Jf1SLZ.js} +2 -2
- package/dist/client/assets/{dist-CnL7Y2sM.js → dist-BDt3rz7l.js} +1 -1
- package/dist/client/assets/dist-BEwK4csK.js +1 -0
- package/dist/client/assets/dist-BKW4PALF.js +1 -0
- package/dist/client/assets/dist-BWcHHOx-.js +1 -0
- package/dist/client/assets/{dist-CYZmbokb.js → dist-BalScOwZ.js} +9 -9
- package/dist/client/assets/dist-Bf8f4HmM.js +6 -0
- package/dist/client/assets/dist-BjHJDtyU.js +1 -0
- package/dist/client/assets/dist-Bm6pf9Bl.js +1 -0
- package/dist/client/assets/dist-BoVBdSjk.js +1 -0
- package/dist/client/assets/dist-CC5IrQMG.js +1 -0
- package/dist/client/assets/{dist-C11hHqv_.js → dist-CCP_AKPG.js} +12 -12
- package/dist/client/assets/dist-CZgOmxK6.js +1 -0
- package/dist/client/assets/{dist-D2AQ-76g.js → dist-Cqhv5LAk.js} +1 -1
- package/dist/client/assets/{dist-MvcV4190.js → dist-D-Z6FLem.js} +1 -1
- package/dist/client/assets/dist-DLMiIsNC.js +11 -0
- package/dist/client/assets/{dist-3bgCp7iY.js → dist-DZKu9Cs8.js} +1 -1
- package/dist/client/assets/dist-DaYdhcVs.js +1 -0
- package/dist/client/assets/dist-FWJsgGYI.js +1 -0
- package/dist/client/assets/dist-Kh2COra_.js +1 -0
- package/dist/client/assets/{dist-JYEDRrPT.js → dist-PDZ3bSqm.js} +1 -1
- package/dist/client/assets/{dist-Drp8uu5J.js → dist-TjMh8n1u.js} +1 -1
- package/dist/client/assets/{dist-DGb27Dl6.js → dist-dtAdgL39.js} +1 -1
- package/dist/client/assets/dist-jv4WdPnK.js +9 -0
- package/dist/client/assets/{dist-DK5Gs2wa.js → dist-rGBmqxC7.js} +1 -1
- package/dist/client/assets/{dist-DCzuX1AF.js → dist-shrl6K_0.js} +1 -1
- package/dist/client/assets/dist-tOaegDYS2.js +1 -0
- package/dist/client/assets/dist-ule2n6ak.js +1 -0
- package/dist/client/assets/dist-xElaxbia.js +1 -0
- package/dist/client/assets/drawio-editor-FzY1cVw8.js +9 -0
- package/dist/client/assets/drawioEditor-BjiKJqlc.js +2 -0
- package/dist/client/assets/editor-session-Cm9ekeNo.js +54 -0
- package/dist/client/assets/embedded-editor-base-CwTkk911.css +1 -0
- package/dist/client/assets/{en-GADW4C6J-DQ6zyCEM.js → en-7NFCYGKX-BrgYZAEe.js} +1 -1
- package/dist/client/assets/{preview-render-profile-BZzGSg6K.js → es-DXGV3RHd.js} +13 -13
- package/dist/client/assets/excalidraw-editor-B46zsTFI.js +9 -0
- package/dist/client/assets/excalidraw-editor-Bt7gMSoh.css +1 -0
- package/dist/client/assets/excalidraw-scene-BOben2gr.js +1 -0
- package/dist/client/assets/excalidrawEditor-CT2pHq7e.js +2 -0
- package/dist/client/assets/export-page-A7NHawJY.js +39 -0
- package/dist/client/assets/exportDocument-B2L8fe34.css +1 -0
- package/dist/client/assets/exportDocument-BaqcOAAW.js +2 -0
- package/dist/client/assets/file-icon-svg-CQAjlWjK.js +1 -0
- package/dist/client/assets/file-kind-BbqgGzpc.js +1 -0
- package/dist/client/assets/image-QXRYHUNP-SWEV8H0J.js +1 -0
- package/dist/client/assets/index-ClbjMBVt.js +2 -0
- package/dist/client/assets/index-Pum8ET-5.css +1 -0
- package/dist/client/assets/main-B3uPyqic.js +893 -0
- package/dist/client/assets/modulepreload-polyfill-P2Xu9kJm.js +1 -0
- package/dist/client/assets/pdf-BL9Pr2D5.js +54 -0
- package/dist/client/assets/pdf.worker-CLesOks4.mjs +64857 -0
- package/dist/client/assets/pdf_viewer-FVkkThnz.js +551 -0
- package/dist/client/assets/preview-diagram-utils-txBCoW8d.js +1 -0
- package/dist/client/assets/{preview-render-compiler-BSaQO_p3.js → preview-render-compiler-BD-XhkS2.js} +2 -2
- package/dist/client/assets/preview-render-compiler-BKedaMxx.js +1 -0
- package/dist/client/assets/preview-render-profile-CE-5rVTC.js +1 -0
- package/dist/client/assets/{preview-render-worker-B42LWvrD.js → preview-render-worker-CiPqc9n6.js} +20 -20
- package/dist/client/assets/prod-Dy20X7eT.js +1 -0
- package/dist/client/assets/prod-hnwh7wRM.js +177 -0
- package/dist/client/assets/quick-switcher-controller-fqOYR7qR.js +12 -0
- package/dist/client/assets/runtime-config-BLrEKVO1.js +1 -0
- package/dist/client/assets/vault-api-client-_LpV1aIn.js +6 -0
- package/dist/client/assets/{yjs-provider-reset-guard-Cox4nxwu.js → yjs-provider-reset-guard-DE0vINDP.js} +1 -1
- package/dist/client/drawio-editor.html +3 -2
- package/dist/client/excalidraw-editor.html +3 -2
- package/dist/client/export-document.html +4 -3
- package/dist/client/index.html +109 -27
- package/docker-compose.yml +42 -0
- package/package.json +26 -15
- package/scripts/local-structurizr-compose.mjs +101 -0
- package/src/client/app/drawio-editor-entry.js +0 -3
- package/src/client/app/drawio-editor.html +1 -0
- package/src/client/app/excalidraw-editor-entry.js +0 -3
- package/src/client/app/excalidraw-editor.html +1 -0
- package/src/client/app/export-document-entry.js +0 -3
- package/src/client/app/export-document.html +1 -0
- package/src/client/app/index.html +106 -24
- package/src/client/app/main-entry.js +0 -5
- package/src/client/application/app-shell/chat-feature.js +180 -124
- package/src/client/application/app-shell/comments-feature.js +20 -11
- package/src/client/application/app-shell/git-feature.js +16 -9
- package/src/client/application/app-shell/presence-feature.js +18 -11
- package/src/client/application/app-shell/ui-feature-shell.js +78 -17
- package/src/client/application/app-shell/ui-feature-sidebar.js +74 -1
- package/src/client/application/app-shell/ui-feature-tab-activity.js +2 -2
- package/src/client/application/app-shell/ui-feature-toolbar.js +2 -52
- package/src/client/application/app-shell/workspace-feature.js +27 -84
- package/src/client/application/app-shell-elements.js +9 -1
- package/src/client/application/diagram-chrome.js +161 -166
- package/src/client/application/diagram-preview-export.js +7 -34
- package/src/client/application/diagram-preview-hydrator.js +1 -19
- package/src/client/application/markdown-frontmatter.js +0 -2
- package/src/client/application/mermaid-preview-hydrator.js +1 -14
- package/src/client/application/pdf-preview-controller.js +992 -0
- package/src/client/application/plantuml-preview-hydrator.js +0 -10
- package/src/client/application/preview-diagram-utils.js +31 -2
- package/src/client/application/preview-render-compiler.js +2 -1
- package/src/client/application/preview-renderer.js +2 -2
- package/src/client/application/quick-switcher-loader.js +3 -1
- package/src/client/application/structurizr-preview-controller.js +395 -0
- package/src/client/application/workspace-coordinator.js +25 -3
- package/src/client/application/workspace-preview-controller.js +91 -5
- package/src/client/bootstrap/collabmd-app-shell.js +155 -43
- package/src/client/browser-utils.js +44 -0
- package/src/client/domain/excalidraw-collaboration.js +0 -2
- package/src/client/domain/room.js +38 -0
- package/src/client/domain/runtime-paths.js +26 -5
- package/src/client/domain/structurizr-language.js +99 -0
- package/src/client/domain/vault-paths.js +48 -0
- package/src/client/excalidraw-editor.js +833 -51
- package/src/client/export/export-pipeline.js +6 -34
- package/src/client/infrastructure/auth-client.js +4 -10
- package/src/client/infrastructure/browser-notification-port.js +33 -20
- package/src/client/infrastructure/browser-preferences-port.js +46 -9
- package/src/client/infrastructure/comment-thread-store.js +34 -13
- package/src/client/infrastructure/editor-session.js +10 -0
- package/src/client/infrastructure/editor-view-adapter.js +133 -5
- package/src/client/infrastructure/excalidraw-room-client.js +103 -14
- package/src/client/infrastructure/git-api-client.js +5 -0
- package/src/client/infrastructure/lobby-presence.js +1 -0
- package/src/client/infrastructure/vault-api-client.js +51 -0
- package/src/client/infrastructure/workspace-sync-client.js +13 -1
- package/src/client/presentation/comment-overview-controller.js +18 -53
- package/src/client/presentation/comment-ui/comment-ui-card.js +1 -12
- package/src/client/presentation/comment-ui/comment-ui-layout.js +242 -219
- package/src/client/presentation/comment-ui/comment-ui-render.js +32 -45
- package/src/client/presentation/comment-ui/comment-ui-shared.js +68 -13
- package/src/client/presentation/comment-ui-controller.js +5 -1
- package/src/client/presentation/drawio-embed-controller.js +9 -102
- package/src/client/presentation/drawio-viewer.js +118 -0
- package/src/client/presentation/excalidraw-embed-controller.js +74 -8
- package/src/client/presentation/file-action-controller.js +134 -0
- package/src/client/presentation/file-explorer-controller.js +33 -3
- package/src/client/presentation/file-explorer-view.js +59 -34
- package/src/client/presentation/file-icon-svg.js +40 -0
- package/src/client/presentation/file-tree-state.js +12 -4
- package/src/client/presentation/git-diff-view-controller.js +731 -3
- package/src/client/presentation/outline-controller.js +86 -0
- package/src/client/presentation/quick-switcher-controller.js +257 -74
- package/src/client/presentation/quick-switcher-text-search.js +3 -3
- package/src/client/presentation/toast-controller.js +3 -0
- package/src/client/styles/components/feedback.css +6 -0
- package/src/client/styles/components/navigation.css +11 -1
- package/src/client/styles/features/collaboration-chat.css +49 -53
- package/src/client/styles/features/collaboration-presence.css +9 -7
- package/src/client/styles/features/comment-card.css +25 -11
- package/src/client/styles/features/comment-overlays.css +0 -4
- package/src/client/styles/features/comment-overview.css +44 -21
- package/src/client/styles/features/comments-drawer.css +2 -100
- package/src/client/styles/features/diagram-preview.css +81 -18
- package/src/client/styles/features/diff-special.css +309 -0
- package/src/client/styles/features/embedded-preview.css +8 -33
- package/src/client/styles/features/quick-switcher.css +8 -0
- package/src/client/styles/foundation/themes.css +6 -0
- package/src/client/styles/foundation/tokens.css +1 -0
- package/src/client/styles/layout/editor-page.css +40 -0
- package/src/client/styles/layout/responsive.css +31 -1
- package/src/client/styles/layout/shell.css +383 -7
- package/src/client/styles/layout/sidebar.css +47 -15
- package/src/client/styles/layout/view-modes.css +1 -0
- package/src/client/styles/overrides/codemirror.css +217 -15
- package/src/client/styles/style.css +1 -0
- package/src/client/styles/surfaces/excalidraw-editor.css +294 -0
- package/src/domain/comment-threads.js +63 -5
- package/src/domain/excalidraw-room-codec.js +6 -4
- package/src/domain/file-kind.js +35 -3
- package/src/server/application/workspace-reconciliation.js +1 -1
- package/src/server/config/env.js +79 -0
- package/src/server/create-app-server.js +14 -3
- package/src/server/domain/bases/base-definition.js +1 -1
- package/src/server/domain/bases/base-expression-runtime.js +1 -4
- package/src/server/domain/bases/base-index-snapshot-store.js +1 -4
- package/src/server/domain/bases/base-query-service.js +1 -77
- package/src/server/domain/bases/base-transform.js +1 -4
- package/src/server/domain/collaboration/collaboration-room.js +55 -21
- package/src/server/domain/comment-overview.js +25 -8
- package/src/server/domain/docx-exporter.js +24 -33
- package/src/server/domain/ripgrep-search-service.js +7 -1
- package/src/server/domain/workspace-state.js +32 -11
- package/src/server/infrastructure/git/diff-service.js +29 -13
- package/src/server/infrastructure/git/git-service.js +61 -10
- package/src/server/infrastructure/git/history-service.js +96 -29
- package/src/server/infrastructure/git/image-mime.js +14 -0
- package/src/server/infrastructure/git/path-utils.js +1 -1
- package/src/server/infrastructure/git/responses.js +0 -95
- package/src/server/infrastructure/git/untracked-files.js +28 -1
- package/src/server/infrastructure/github/github-app-client.js +22 -15
- package/src/server/infrastructure/http/create-git-api-query-handler.js +31 -1
- package/src/server/infrastructure/http/create-request-handler.js +18 -31
- package/src/server/infrastructure/http/create-static-handler.js +5 -2
- package/src/server/infrastructure/http/create-structurizr-api-handler.js +145 -0
- package/src/server/infrastructure/http/create-vault-api-command-handler.js +70 -8
- package/src/server/infrastructure/http/create-vault-api-query-handler.js +51 -3
- package/src/server/infrastructure/http/http-errors.js +7 -1
- package/src/server/infrastructure/http/http-request-helpers.js +22 -0
- package/src/server/infrastructure/persistence/path-utils.js +1 -1
- package/src/server/infrastructure/persistence/vault-file-store.js +3 -0
- package/src/server/infrastructure/structurizr/structurizr-embed.css +43 -0
- package/src/server/infrastructure/structurizr/structurizr-workspace-service.js +374 -0
- package/src/server/infrastructure/websocket/attach-collaboration-gateway.js +4 -22
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-CbSISC1w.js +0 -1
- package/dist/client/assets/bases-preview-controller-2pLHk0uk.js +0 -143
- package/dist/client/assets/browser-utils-CKtI_rZl.js +0 -1
- package/dist/client/assets/button-BCEiw4Rw.js +0 -1
- package/dist/client/assets/chunk-AXR3VHVW-0GTk_evH.js +0 -41
- package/dist/client/assets/comment-threads-D-iKphIp.js +0 -4
- package/dist/client/assets/diagram-action-icons-aa_KOv9h.js +0 -36
- package/dist/client/assets/dist-BH87JoHx.js +0 -11
- package/dist/client/assets/dist-BIkPRZO7.js +0 -6
- package/dist/client/assets/dist-BqCsFpx4.js +0 -1
- package/dist/client/assets/dist-C2JHCt8U.js +0 -1
- package/dist/client/assets/dist-CZjTtmTu.js +0 -1
- package/dist/client/assets/dist-Cig4Ov_X.js +0 -1
- package/dist/client/assets/dist-CqQEC8gR.js +0 -1
- package/dist/client/assets/dist-D4Rzqod1.js +0 -1
- package/dist/client/assets/dist-D5sn-mwk.js +0 -9
- package/dist/client/assets/dist-D7G-n87v.js +0 -1
- package/dist/client/assets/dist-DRqOrNgN.js +0 -1
- package/dist/client/assets/dist-DetkMS_4.js +0 -1
- package/dist/client/assets/dist-Dp6FVkQ1.js +0 -1
- package/dist/client/assets/dist-DtbjNB28.js +0 -1
- package/dist/client/assets/dist-DyrYcvpo2.js +0 -1
- package/dist/client/assets/dist-GrygD2zE.js +0 -1
- package/dist/client/assets/dist-HmEpWUow.js +0 -1
- package/dist/client/assets/dist-RTa81Km7.js +0 -1
- package/dist/client/assets/drawio-editor-DDvFoarP.js +0 -9
- package/dist/client/assets/drawio-embed-controller-BD1GTRwn.js +0 -1
- package/dist/client/assets/drawioEditor-Bu5grlH5.js +0 -2
- package/dist/client/assets/editor-session-DGlpiAsK.js +0 -16
- package/dist/client/assets/embedded-editor-base-C9roKYpW.css +0 -1
- package/dist/client/assets/excalidraw-editor-BHu6k8d4.js +0 -9
- package/dist/client/assets/excalidraw-editor-Cr_184EF.css +0 -1
- package/dist/client/assets/excalidraw-embed-controller-y2fenN_g.js +0 -1
- package/dist/client/assets/excalidraw-embed-reconciler-DGiagExg.js +0 -1
- package/dist/client/assets/excalidraw-scene-BvsQ6mLP.js +0 -176
- package/dist/client/assets/excalidrawEditor-4vFE--Uw.js +0 -2
- package/dist/client/assets/export-page-Cby8JzPO.js +0 -39
- package/dist/client/assets/exportDocument-C9v-bc7I.css +0 -1
- package/dist/client/assets/exportDocument-CRHCfsdo.js +0 -2
- package/dist/client/assets/file-history-view-controller-BDjEV9xJ.js +0 -112
- package/dist/client/assets/file-kind-BKPOIRPE.js +0 -1
- package/dist/client/assets/git-diff-view-controller-DgdM1aqb.js +0 -150
- package/dist/client/assets/git-panel-controller-BDTR2HVp.js +0 -207
- package/dist/client/assets/image-XGD7JQR6-XDUWHRpO.js +0 -1
- package/dist/client/assets/index-7xOyXDhP.css +0 -1
- package/dist/client/assets/index-Bz1KuQ6y.js +0 -2
- package/dist/client/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/client/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/client/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/client/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/client/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/client/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/client/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/client/assets/main-Ci07m9oP.js +0 -152
- package/dist/client/assets/preview-diagram-utils-n_bbJA9V.js +0 -1
- package/dist/client/assets/preview-render-compiler-csGM5ZFz.js +0 -1
- package/dist/client/assets/quick-switcher-controller-CoiYvllm.js +0 -12
- package/dist/client/assets/room-CDrmIdDt.js +0 -1
- package/dist/client/assets/runtime-config-CDgeuPWN.js +0 -1
- package/dist/client/assets/runtime-config-loader-BHGniHP5.js +0 -1
- package/dist/client/assets/runtime-paths-DvpihCEq.js +0 -1
- package/dist/client/assets/segmented-control-DJrHSz8M.js +0 -1
- package/dist/client/assets/vault-api-client-sLB2bo56.js +0 -1
- package/dist/client/assets/vault-paths-CVkuh0j-.js +0 -5
- package/src/client/bootstrap/lazy-controller-feature.js +0 -433
- package/src/client/infrastructure/backlinks-api-client.js +0 -16
- package/src/client/infrastructure/plantuml-api-client.js +0 -19
- package/src/client/infrastructure/runtime-config-loader.js +0 -56
- package/src/server/domain/collaboration/room-persistence-controller.js +0 -80
- package/src/server/infrastructure/git/command-runner.js +0 -49
- package/src/server/infrastructure/git/errors.js +0 -8
- package/src/server/infrastructure/http/create-esm-proxy-handler.js +0 -130
package/src/domain/file-kind.js
CHANGED
|
@@ -4,20 +4,25 @@ const EXCALIDRAW_FILE_EXTENSION = '.excalidraw';
|
|
|
4
4
|
const DRAWIO_FILE_EXTENSION = '.drawio';
|
|
5
5
|
const MERMAID_FILE_EXTENSIONS = Object.freeze(['.mmd', '.mermaid']);
|
|
6
6
|
const PLANTUML_FILE_EXTENSIONS = Object.freeze(['.puml', '.plantuml']);
|
|
7
|
+
const STRUCTURIZR_FILE_EXTENSION = '.dsl';
|
|
8
|
+
const STRUCTURIZR_FILE_EXTENSIONS = Object.freeze([STRUCTURIZR_FILE_EXTENSION]);
|
|
9
|
+
const PDF_FILE_EXTENSION = '.pdf';
|
|
7
10
|
const IMAGE_ATTACHMENT_EXTENSIONS = Object.freeze(['.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg']);
|
|
8
11
|
const DIAGRAM_FILE_EXTENSIONS = Object.freeze([
|
|
9
12
|
EXCALIDRAW_FILE_EXTENSION,
|
|
10
13
|
DRAWIO_FILE_EXTENSION,
|
|
11
14
|
...MERMAID_FILE_EXTENSIONS,
|
|
12
15
|
...PLANTUML_FILE_EXTENSIONS,
|
|
16
|
+
...STRUCTURIZR_FILE_EXTENSIONS,
|
|
13
17
|
]);
|
|
14
18
|
const VAULT_FILE_EXTENSIONS = Object.freeze([
|
|
15
19
|
...MARKDOWN_FILE_EXTENSIONS,
|
|
16
20
|
BASE_FILE_EXTENSION,
|
|
17
21
|
...DIAGRAM_FILE_EXTENSIONS,
|
|
22
|
+
PDF_FILE_EXTENSION,
|
|
18
23
|
...IMAGE_ATTACHMENT_EXTENSIONS,
|
|
19
24
|
]);
|
|
20
|
-
const STRIP_VAULT_EXTENSION_PATTERN = /\.(?:md|markdown|mdx|base|excalidraw|drawio|mmd|mermaid|puml|plantuml|png|jpe?g|webp|gif|svg)$/i;
|
|
25
|
+
const STRIP_VAULT_EXTENSION_PATTERN = /\.(?:md|markdown|mdx|base|excalidraw|drawio|mmd|mermaid|puml|plantuml|dsl|pdf|png|jpe?g|webp|gif|svg)$/i;
|
|
21
26
|
|
|
22
27
|
function normalizeFilePath(filePath) {
|
|
23
28
|
return String(filePath ?? '').trim().toLowerCase();
|
|
@@ -36,7 +41,10 @@ export {
|
|
|
36
41
|
IMAGE_ATTACHMENT_EXTENSIONS,
|
|
37
42
|
MARKDOWN_FILE_EXTENSIONS,
|
|
38
43
|
MERMAID_FILE_EXTENSIONS,
|
|
44
|
+
PDF_FILE_EXTENSION,
|
|
39
45
|
PLANTUML_FILE_EXTENSIONS,
|
|
46
|
+
STRUCTURIZR_FILE_EXTENSION,
|
|
47
|
+
STRUCTURIZR_FILE_EXTENSIONS,
|
|
40
48
|
VAULT_FILE_EXTENSIONS,
|
|
41
49
|
};
|
|
42
50
|
|
|
@@ -65,6 +73,14 @@ export function getVaultFileKind(filePath) {
|
|
|
65
73
|
return 'plantuml';
|
|
66
74
|
}
|
|
67
75
|
|
|
76
|
+
if (hasFileExtension(filePath, STRUCTURIZR_FILE_EXTENSIONS)) {
|
|
77
|
+
return 'structurizr';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (hasFileExtension(filePath, [PDF_FILE_EXTENSION])) {
|
|
81
|
+
return 'pdf';
|
|
82
|
+
}
|
|
83
|
+
|
|
68
84
|
if (hasFileExtension(filePath, IMAGE_ATTACHMENT_EXTENSIONS)) {
|
|
69
85
|
return 'image';
|
|
70
86
|
}
|
|
@@ -118,13 +134,25 @@ export function isPlantUmlFilePath(filePath) {
|
|
|
118
134
|
return getVaultFileKind(filePath) === 'plantuml';
|
|
119
135
|
}
|
|
120
136
|
|
|
137
|
+
export function isStructurizrFilePath(filePath) {
|
|
138
|
+
return getVaultFileKind(filePath) === 'structurizr';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function isPdfFilePath(filePath) {
|
|
142
|
+
return getVaultFileKind(filePath) === 'pdf';
|
|
143
|
+
}
|
|
144
|
+
|
|
121
145
|
export function isImageAttachmentFilePath(filePath) {
|
|
122
146
|
return getVaultFileKind(filePath) === 'image';
|
|
123
147
|
}
|
|
124
148
|
|
|
125
149
|
export function isDiagramFilePath(filePath) {
|
|
126
150
|
const kind = getVaultFileKind(filePath);
|
|
127
|
-
return kind === 'excalidraw'
|
|
151
|
+
return kind === 'excalidraw'
|
|
152
|
+
|| kind === 'drawio'
|
|
153
|
+
|| kind === 'mermaid'
|
|
154
|
+
|| kind === 'plantuml'
|
|
155
|
+
|| kind === 'structurizr';
|
|
128
156
|
}
|
|
129
157
|
|
|
130
158
|
export function isVaultFilePath(filePath) {
|
|
@@ -133,7 +161,11 @@ export function isVaultFilePath(filePath) {
|
|
|
133
161
|
|
|
134
162
|
export function supportsCommentsForFilePath(filePath) {
|
|
135
163
|
const kind = getVaultFileKind(filePath);
|
|
136
|
-
return kind === 'markdown'
|
|
164
|
+
return kind === 'markdown'
|
|
165
|
+
|| kind === 'mermaid'
|
|
166
|
+
|| kind === 'plantuml'
|
|
167
|
+
|| kind === 'structurizr'
|
|
168
|
+
|| kind === 'excalidraw';
|
|
137
169
|
}
|
|
138
170
|
|
|
139
171
|
export function supportsBacklinksForFilePath(filePath) {
|
|
@@ -135,7 +135,7 @@ export class WorkspaceReconciliation {
|
|
|
135
135
|
async initialize({ snapshot = null } = {}) {
|
|
136
136
|
const effectiveSnapshot = snapshot ?? await this.vaultFileStore.scanWorkspaceState();
|
|
137
137
|
this.replaceWorkspaceState(effectiveSnapshot);
|
|
138
|
-
await this.baseQueryService?.initializeFromWorkspaceState?.(effectiveSnapshot);
|
|
138
|
+
await this.baseQueryService?.snapshotStore?.initializeFromWorkspaceState?.(effectiveSnapshot);
|
|
139
139
|
this.getWorkspaceRoom()?.replaceWorkspaceEntries(effectiveSnapshot.entries, {
|
|
140
140
|
generatedAt: effectiveSnapshot.scannedAt,
|
|
141
141
|
});
|
package/src/server/config/env.js
CHANGED
|
@@ -13,11 +13,28 @@ import {
|
|
|
13
13
|
import { loadBuildInfo } from './build-info.js';
|
|
14
14
|
import { isPerfLoggingEnabled } from './perf-logging.js';
|
|
15
15
|
|
|
16
|
+
const DEFAULT_SEARCH_MAX_BUFFER_BYTES = 2 * 1024 * 1024;
|
|
17
|
+
const DEFAULT_SEARCH_MAX_FILE_SIZE = '1M';
|
|
18
|
+
const DEFAULT_PDF_UPLOAD_BYTES = 50 * 1024 * 1024;
|
|
19
|
+
|
|
16
20
|
function parsePositiveInt(rawValue, fallbackValue) {
|
|
17
21
|
const parsed = Number.parseInt(rawValue ?? '', 10);
|
|
18
22
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallbackValue;
|
|
19
23
|
}
|
|
20
24
|
|
|
25
|
+
function normalizeSearchMaxFileSize(rawValue, fallbackValue = DEFAULT_SEARCH_MAX_FILE_SIZE) {
|
|
26
|
+
const normalized = String(rawValue ?? '').trim();
|
|
27
|
+
if (!normalized) {
|
|
28
|
+
return fallbackValue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!/^[1-9]\d*(?:[KMG])?$/iu.test(normalized)) {
|
|
32
|
+
throw new Error('COLLABMD_SEARCH_MAX_FILE_SIZE must be a positive byte count with an optional K, M, or G suffix.');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return normalized.toUpperCase();
|
|
36
|
+
}
|
|
37
|
+
|
|
21
38
|
function parseOptionalPositiveInt(rawValue, {
|
|
22
39
|
fallbackValue = null,
|
|
23
40
|
variableName = 'value',
|
|
@@ -56,6 +73,30 @@ function resolveDrawioBaseUrl(value) {
|
|
|
56
73
|
return normalizeOptionalString(value) || 'https://embed.diagrams.net';
|
|
57
74
|
}
|
|
58
75
|
|
|
76
|
+
function resolveStructurizrServerUrl(value) {
|
|
77
|
+
const normalized = normalizeOptionalString(value);
|
|
78
|
+
if (!normalized) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let parsedUrl;
|
|
83
|
+
try {
|
|
84
|
+
parsedUrl = new URL(normalized);
|
|
85
|
+
} catch {
|
|
86
|
+
throw new Error('STRUCTURIZR_SERVER_URL must be an absolute HTTP or HTTPS URL.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
|
90
|
+
throw new Error('STRUCTURIZR_SERVER_URL must use HTTP or HTTPS.');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (parsedUrl.search || parsedUrl.hash) {
|
|
94
|
+
throw new Error('STRUCTURIZR_SERVER_URL must not include a query string or hash.');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return normalized.replace(/\/+$/u, '');
|
|
98
|
+
}
|
|
99
|
+
|
|
59
100
|
function normalizeAppBasePath(basePath) {
|
|
60
101
|
const normalized = normalizeOptionalString(basePath);
|
|
61
102
|
if (!normalized || normalized === '/') {
|
|
@@ -278,6 +319,31 @@ function loadOidcConfig(overrides = {}, { basePath = '' } = {}) {
|
|
|
278
319
|
};
|
|
279
320
|
}
|
|
280
321
|
|
|
322
|
+
function loadStructurizrConfig(overrides = {}, { vaultDir } = {}) {
|
|
323
|
+
const serverUrl = resolveStructurizrServerUrl(
|
|
324
|
+
overrides.serverUrl
|
|
325
|
+
?? process.env.COLLABMD_STRUCTURIZR_SERVER_URL
|
|
326
|
+
?? process.env.STRUCTURIZR_SERVER_URL,
|
|
327
|
+
);
|
|
328
|
+
const mirrorDir = resolveOptionalPath(
|
|
329
|
+
overrides.mirrorDir
|
|
330
|
+
?? process.env.COLLABMD_STRUCTURIZR_MIRROR_DIR
|
|
331
|
+
?? process.env.STRUCTURIZR_MIRROR_DIR,
|
|
332
|
+
) || resolve(vaultDir, '.collabmd/structurizr');
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
enabled: Boolean(serverUrl),
|
|
336
|
+
mirrorDir,
|
|
337
|
+
serverUrl,
|
|
338
|
+
trustedExecutableDsl: overrides.trustedExecutableDsl
|
|
339
|
+
?? parseBooleanFlag(
|
|
340
|
+
process.env.COLLABMD_STRUCTURIZR_TRUSTED_EXECUTABLE_DSL
|
|
341
|
+
?? process.env.STRUCTURIZR_TRUSTED_EXECUTABLE_DSL,
|
|
342
|
+
false,
|
|
343
|
+
),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
281
347
|
function loadHostedConfig(overrides = {}, { authStrategy, vaultDir } = {}) {
|
|
282
348
|
const enabled = overrides.enabled ?? parseBooleanFlag(process.env.COLLABMD_HOSTED_ENABLED, false);
|
|
283
349
|
const metadataDbPath = resolveOptionalPath(
|
|
@@ -361,6 +427,7 @@ export function loadConfig(overrides = {}) {
|
|
|
361
427
|
: null;
|
|
362
428
|
const git = loadGitConfig(overrides.git);
|
|
363
429
|
const hosted = loadHostedConfig(overrides.hosted, { authStrategy, vaultDir });
|
|
430
|
+
const structurizr = loadStructurizrConfig(overrides.structurizr, { vaultDir });
|
|
364
431
|
const build = loadBuildInfo({
|
|
365
432
|
explicitBuildId: process.env.COLLABMD_BUILD_ID,
|
|
366
433
|
projectRoot,
|
|
@@ -396,6 +463,18 @@ export function loadConfig(overrides = {}) {
|
|
|
396
463
|
maxBaseQueryRows: parsePositiveInt(process.env.COLLABMD_MAX_BASE_QUERY_ROWS, 5_000),
|
|
397
464
|
maxDownloadFileBytes: parsePositiveInt(process.env.COLLABMD_MAX_DOWNLOAD_FILE_BYTES, 268_435_456),
|
|
398
465
|
maxInitialSyncBytes: parsePositiveInt(process.env.COLLABMD_MAX_INITIAL_SYNC_BYTES, 16_777_216),
|
|
466
|
+
maxPdfUploadBytes: parsePositiveInt(
|
|
467
|
+
overrides.maxPdfUploadBytes ?? process.env.COLLABMD_MAX_PDF_UPLOAD_BYTES,
|
|
468
|
+
DEFAULT_PDF_UPLOAD_BYTES,
|
|
469
|
+
),
|
|
470
|
+
searchMaxBufferBytes: parsePositiveInt(
|
|
471
|
+
overrides.searchMaxBufferBytes ?? process.env.COLLABMD_SEARCH_MAX_BUFFER_BYTES,
|
|
472
|
+
DEFAULT_SEARCH_MAX_BUFFER_BYTES,
|
|
473
|
+
),
|
|
474
|
+
searchMaxFileSize: normalizeSearchMaxFileSize(
|
|
475
|
+
overrides.searchMaxFileSize ?? process.env.COLLABMD_SEARCH_MAX_FILE_SIZE,
|
|
476
|
+
),
|
|
477
|
+
structurizr,
|
|
399
478
|
perfLoggingEnabled: overrides.perfLoggingEnabled ?? isPerfLoggingEnabled(process.env.COLLABMD_PERF_LOGGING),
|
|
400
479
|
port: parsePositiveInt(process.env.PORT, 1234),
|
|
401
480
|
nodeEnv,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'http';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
2
3
|
|
|
3
4
|
import { loadConfig } from './config/env.js';
|
|
4
5
|
import { createAuthService } from './auth/create-auth-service.js';
|
|
@@ -7,12 +8,13 @@ import { BacklinkIndex } from './domain/backlink-index.js';
|
|
|
7
8
|
import { BaseQueryService } from './domain/bases/base-query-service.js';
|
|
8
9
|
import { CollaborationDocumentStore } from './domain/collaboration/collaboration-document-store.js';
|
|
9
10
|
import { CollaborationRoom } from './domain/collaboration/collaboration-room.js';
|
|
10
|
-
import {
|
|
11
|
+
import { renderDocx } from './domain/docx-exporter.js';
|
|
11
12
|
import { GitService } from './infrastructure/git/git-service.js';
|
|
12
13
|
import { GitHubAppClient } from './infrastructure/github/github-app-client.js';
|
|
13
14
|
import { GitHubSetupFlow } from './infrastructure/github/github-setup-flow.js';
|
|
14
15
|
import { HostedWorkspaceService } from './domain/hosted-workspace.js';
|
|
15
16
|
import { PlantUmlRenderer } from './infrastructure/plantuml/plantuml-renderer.js';
|
|
17
|
+
import { StructurizrWorkspaceService } from './infrastructure/structurizr/structurizr-workspace-service.js';
|
|
16
18
|
import { RoomRegistry } from './domain/collaboration/room-registry.js';
|
|
17
19
|
import { RipgrepSearchService } from './domain/ripgrep-search-service.js';
|
|
18
20
|
import { createRequestHandler } from './infrastructure/http/create-request-handler.js';
|
|
@@ -80,16 +82,23 @@ export function createAppServer(config = loadConfig()) {
|
|
|
80
82
|
workspaceStateProvider: () => workspaceMutationCoordinator?.workspaceState ?? null,
|
|
81
83
|
workspaceStateSynchronizer: () => fileSystemSyncService?.flushPendingChanges?.(),
|
|
82
84
|
});
|
|
83
|
-
const docxExporter = new DocxExporter();
|
|
84
85
|
const plantUmlRenderer = new PlantUmlRenderer({
|
|
85
86
|
serverUrl: config.plantumlServerUrl,
|
|
86
87
|
});
|
|
88
|
+
const structurizrWorkspaceService = new StructurizrWorkspaceService({
|
|
89
|
+
mirrorDir: config.structurizr?.mirrorDir || resolve(config.vaultDir, '.collabmd/structurizr'),
|
|
90
|
+
serverUrl: config.structurizr?.serverUrl || '',
|
|
91
|
+
trustedExecutableDsl: config.structurizr?.trustedExecutableDsl,
|
|
92
|
+
vaultDir: config.vaultDir,
|
|
93
|
+
});
|
|
87
94
|
const gitService = new GitService({
|
|
88
95
|
commandEnv: config.git?.commandEnv,
|
|
89
96
|
enabled: config.gitEnabled,
|
|
90
97
|
vaultDir: config.vaultDir,
|
|
91
98
|
});
|
|
92
99
|
const searchService = new RipgrepSearchService({
|
|
100
|
+
maxBufferBytes: config.searchMaxBufferBytes,
|
|
101
|
+
maxFileSize: config.searchMaxFileSize,
|
|
93
102
|
perfLoggingEnabled: config.perfLoggingEnabled,
|
|
94
103
|
vaultDir: config.vaultDir,
|
|
95
104
|
});
|
|
@@ -144,7 +153,7 @@ export function createAppServer(config = loadConfig()) {
|
|
|
144
153
|
vaultFileStore,
|
|
145
154
|
backlinkIndex,
|
|
146
155
|
baseQueryService,
|
|
147
|
-
|
|
156
|
+
renderDocx,
|
|
148
157
|
roomRegistry,
|
|
149
158
|
plantUmlRenderer,
|
|
150
159
|
gitService,
|
|
@@ -154,6 +163,7 @@ export function createAppServer(config = loadConfig()) {
|
|
|
154
163
|
fileSystemSyncService,
|
|
155
164
|
hostedWorkspaceService,
|
|
156
165
|
githubSetupFlow,
|
|
166
|
+
structurizrWorkspaceService,
|
|
157
167
|
);
|
|
158
168
|
const httpServer = createServer((req, res) => {
|
|
159
169
|
requestHandler(req, res).catch((error) => {
|
|
@@ -316,6 +326,7 @@ export function createAppServer(config = loadConfig()) {
|
|
|
316
326
|
gitService,
|
|
317
327
|
hostedWorkspaceService,
|
|
318
328
|
searchService,
|
|
329
|
+
structurizrWorkspaceService,
|
|
319
330
|
setTestHydrateDelayMs(delayMs = 0) {
|
|
320
331
|
testControls.wsRoomHydrateDelayMs = Math.max(0, Number(delayMs) || 0);
|
|
321
332
|
},
|
|
@@ -2,7 +2,7 @@ import { dump as dumpYaml, loadAll as loadAllYaml } from 'js-yaml';
|
|
|
2
2
|
|
|
3
3
|
const SUPPORTED_VIEW_TYPES = new Set(['cards', 'list', 'table']);
|
|
4
4
|
|
|
5
|
-
function isPlainObject(value) {
|
|
5
|
+
export function isPlainObject(value) {
|
|
6
6
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { isImageAttachmentFilePath } from '../../../domain/file-kind.js';
|
|
2
2
|
import { resolveVaultRelativePath } from '../../../domain/vault-paths.js';
|
|
3
|
-
|
|
4
|
-
function isPlainObject(value) {
|
|
5
|
-
return Object.prototype.toString.call(value) === '[object Object]';
|
|
6
|
-
}
|
|
3
|
+
import { isPlainObject } from './base-definition.js';
|
|
7
4
|
|
|
8
5
|
export function createLinkValue(target, {
|
|
9
6
|
display = '',
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
createReferenceTargetAliasMap,
|
|
13
13
|
} from '../markdown-reference-extractor.js';
|
|
14
14
|
import { mapWithConcurrency } from '../../shared/async-utils.js';
|
|
15
|
+
import { isPlainObject } from './base-definition.js';
|
|
15
16
|
import { createLinkValue, dedupeLinkValues } from './base-expression-runtime.js';
|
|
16
17
|
|
|
17
18
|
const INLINE_TAG_RE = /(^|[\s(])#([A-Za-z0-9/_-]+)/g;
|
|
@@ -39,10 +40,6 @@ function createRowCacheKey(filePath, workspaceState, fileSetSignature) {
|
|
|
39
40
|
].join('\0');
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
function isPlainObject(value) {
|
|
43
|
-
return Object.prototype.toString.call(value) === '[object Object]';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
43
|
function normalizeTags(value) {
|
|
47
44
|
if (Array.isArray(value)) {
|
|
48
45
|
return value
|
|
@@ -152,82 +152,6 @@ export class BaseQueryService {
|
|
|
152
152
|
this.propertyCatalogCache = new Map();
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
get workspaceStateProvider() {
|
|
156
|
-
return this.snapshotStore.workspaceStateProvider;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
set workspaceStateProvider(value) {
|
|
160
|
-
this.snapshotStore.workspaceStateProvider = value;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
get workspaceStateSynchronizer() {
|
|
164
|
-
return this.snapshotStore.workspaceStateSynchronizer;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
set workspaceStateSynchronizer(value) {
|
|
168
|
-
this.snapshotStore.workspaceStateSynchronizer = value;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
get indexSnapshot() {
|
|
172
|
-
return this.snapshotStore.indexSnapshot;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
set indexSnapshot(value) {
|
|
176
|
-
this.snapshotStore.indexSnapshot = value;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
get lastWorkspaceState() {
|
|
180
|
-
return this.snapshotStore.lastWorkspaceState;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
set lastWorkspaceState(value) {
|
|
184
|
-
this.snapshotStore.lastWorkspaceState = value;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async getWorkspaceState() {
|
|
188
|
-
return this.snapshotStore.getWorkspaceState();
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
createSnapshotRow(...args) {
|
|
192
|
-
return this.snapshotStore.createSnapshotRow(...args);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
rebuildBacklinks(...args) {
|
|
196
|
-
return this.snapshotStore.rebuildBacklinks(...args);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async buildIndexSnapshot(...args) {
|
|
200
|
-
return this.snapshotStore.buildIndexSnapshot(...args);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
async synchronizeWorkspaceState() {
|
|
204
|
-
return this.snapshotStore.synchronizeWorkspaceState();
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
removeSnapshotPath(...args) {
|
|
208
|
-
return this.snapshotStore.removeSnapshotPath(...args);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
upsertSnapshotPath(...args) {
|
|
212
|
-
return this.snapshotStore.upsertSnapshotPath(...args);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
collectImpactedSourcesForMembershipChanges(...args) {
|
|
216
|
-
return this.snapshotStore.collectImpactedSourcesForMembershipChanges(...args);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
async refreshSnapshotRows(...args) {
|
|
220
|
-
return this.snapshotStore.refreshSnapshotRows(...args);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
async ensureIndexSnapshot(...args) {
|
|
224
|
-
return this.snapshotStore.ensureIndexSnapshot(...args);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async initializeFromWorkspaceState(...args) {
|
|
228
|
-
return this.snapshotStore.initializeFromWorkspaceState(...args);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
155
|
async applyWorkspaceChange(...args) {
|
|
232
156
|
const result = await this.snapshotStore.applyWorkspaceChange(...args);
|
|
233
157
|
const scannedAt = this.snapshotStore.indexSnapshot?.scannedAt;
|
|
@@ -279,7 +203,7 @@ export class BaseQueryService {
|
|
|
279
203
|
}
|
|
280
204
|
|
|
281
205
|
const definition = this.getCachedDefinition(source === null ? `file:${basePath}` : `source:${sourcePath}:${basePath}`, baseSource);
|
|
282
|
-
const snapshot = await this.ensureIndexSnapshot({
|
|
206
|
+
const snapshot = await this.snapshotStore.ensureIndexSnapshot({
|
|
283
207
|
basePath,
|
|
284
208
|
sourcePath,
|
|
285
209
|
});
|
|
@@ -2,15 +2,12 @@ import { dump as dumpYaml } from 'js-yaml';
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
findView,
|
|
5
|
+
isPlainObject,
|
|
5
6
|
normalizeBaseDefinition,
|
|
6
7
|
normalizeRawDefinitionForWrite,
|
|
7
8
|
parseBaseSource,
|
|
8
9
|
} from './base-definition.js';
|
|
9
10
|
|
|
10
|
-
function isPlainObject(value) {
|
|
11
|
-
return Object.prototype.toString.call(value) === '[object Object]';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
11
|
function cloneRawSource(source = '') {
|
|
15
12
|
const parsed = parseBaseSource(source);
|
|
16
13
|
return isPlainObject(parsed) ? parsed : {};
|
|
@@ -6,9 +6,9 @@ import * as decoding from 'lib0/decoding';
|
|
|
6
6
|
|
|
7
7
|
import { MSG_AWARENESS, MSG_SYNC } from './protocol.js';
|
|
8
8
|
import { CollaborationDocumentStore } from './collaboration-document-store.js';
|
|
9
|
-
import { RoomPersistenceController } from './room-persistence-controller.js';
|
|
10
9
|
import { logPerfEvent } from '../../config/perf-logging.js';
|
|
11
10
|
import { populateCommentThreads, serializeCommentThreads } from '../../../domain/comment-threads.js';
|
|
11
|
+
import { getVaultFileKind } from '../../../domain/file-kind.js';
|
|
12
12
|
import {
|
|
13
13
|
EXCALIDRAW_APP_STATE_KEY,
|
|
14
14
|
EXCALIDRAW_ELEMENTS_KEY,
|
|
@@ -123,7 +123,7 @@ function readAwarenessEntries(update) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function isExcalidrawRoom(name) {
|
|
126
|
-
return
|
|
126
|
+
return getVaultFileKind(name) === 'excalidraw';
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function isWorkspaceRoom(name) {
|
|
@@ -214,15 +214,10 @@ export class CollaborationRoom {
|
|
|
214
214
|
lastHydrate: null,
|
|
215
215
|
lastInitialSyncAt: 0,
|
|
216
216
|
};
|
|
217
|
-
this.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this.doc.destroy();
|
|
222
|
-
this.onEmpty?.(this.name);
|
|
223
|
-
},
|
|
224
|
-
onPersist: () => this.persist(),
|
|
225
|
-
});
|
|
217
|
+
this.persistTimer = null;
|
|
218
|
+
this.destroyTimer = null;
|
|
219
|
+
this.finalizePromise = null;
|
|
220
|
+
this.shutdownGeneration = 0;
|
|
226
221
|
|
|
227
222
|
this.awareness.setLocalState(null);
|
|
228
223
|
this.registerDocListeners();
|
|
@@ -475,11 +470,12 @@ export class CollaborationRoom {
|
|
|
475
470
|
return;
|
|
476
471
|
}
|
|
477
472
|
|
|
478
|
-
this.
|
|
473
|
+
clearTimeout(this.persistTimer);
|
|
474
|
+
this.persistTimer = setTimeout(() => {
|
|
479
475
|
this.persist().catch((error) => {
|
|
480
476
|
console.error(`[room:${this.name}] Failed to persist document:`, error.message);
|
|
481
477
|
});
|
|
482
|
-
});
|
|
478
|
+
}, 500);
|
|
483
479
|
}
|
|
484
480
|
|
|
485
481
|
async persist() {
|
|
@@ -620,9 +616,17 @@ export class CollaborationRoom {
|
|
|
620
616
|
this.documentStore?.rename(nextName);
|
|
621
617
|
}
|
|
622
618
|
|
|
619
|
+
cancelPersistenceTimers() {
|
|
620
|
+
this.shutdownGeneration += 1;
|
|
621
|
+
clearTimeout(this.persistTimer);
|
|
622
|
+
clearTimeout(this.destroyTimer);
|
|
623
|
+
this.persistTimer = null;
|
|
624
|
+
this.destroyTimer = null;
|
|
625
|
+
}
|
|
626
|
+
|
|
623
627
|
markDeleted() {
|
|
624
628
|
this.deleted = true;
|
|
625
|
-
this.
|
|
629
|
+
this.cancelPersistenceTimers();
|
|
626
630
|
if (this.clients.size === 0) {
|
|
627
631
|
this.finalizeIfIdle();
|
|
628
632
|
}
|
|
@@ -669,7 +673,9 @@ export class CollaborationRoom {
|
|
|
669
673
|
}
|
|
670
674
|
|
|
671
675
|
async addClient(ws, { sendInitialSync: shouldSendInitialSync = true } = {}) {
|
|
672
|
-
this.
|
|
676
|
+
this.shutdownGeneration += 1;
|
|
677
|
+
clearTimeout(this.destroyTimer);
|
|
678
|
+
this.destroyTimer = null;
|
|
673
679
|
await this.hydrate();
|
|
674
680
|
|
|
675
681
|
this.ensureClientState(ws);
|
|
@@ -721,9 +727,9 @@ export class CollaborationRoom {
|
|
|
721
727
|
}
|
|
722
728
|
|
|
723
729
|
this.destroyed = true;
|
|
724
|
-
this.
|
|
730
|
+
this.cancelPersistenceTimers();
|
|
725
731
|
await Promise.allSettled([
|
|
726
|
-
this.
|
|
732
|
+
this.finalizePromise,
|
|
727
733
|
this.activePersistPromise,
|
|
728
734
|
]);
|
|
729
735
|
|
|
@@ -745,12 +751,40 @@ export class CollaborationRoom {
|
|
|
745
751
|
}
|
|
746
752
|
|
|
747
753
|
finalizeIfIdle() {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
754
|
+
if (this.clients.size > 0 || this.finalizePromise) {
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const generation = ++this.shutdownGeneration;
|
|
759
|
+
this.finalizePromise = (async () => {
|
|
760
|
+
clearTimeout(this.persistTimer);
|
|
761
|
+
this.persistTimer = null;
|
|
762
|
+
|
|
763
|
+
try {
|
|
764
|
+
await this.persist();
|
|
765
|
+
} catch (error) {
|
|
751
766
|
console.error(`[room:${this.name}] Failed to persist final room state:`, error.message);
|
|
752
|
-
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (this.clients.size > 0 || generation !== this.shutdownGeneration) {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
this.destroyTimer = setTimeout(() => {
|
|
774
|
+
if (this.clients.size > 0 || generation !== this.shutdownGeneration) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
this.awareness.destroy();
|
|
779
|
+
this.doc.destroy();
|
|
780
|
+
this.onEmpty?.(this.name);
|
|
781
|
+
}, this.idleGraceMs);
|
|
782
|
+
this.destroyTimer.unref?.();
|
|
783
|
+
})().finally(() => {
|
|
784
|
+
this.finalizePromise = null;
|
|
753
785
|
});
|
|
786
|
+
|
|
787
|
+
return this.finalizePromise;
|
|
754
788
|
}
|
|
755
789
|
|
|
756
790
|
clearEphemeralExcalidrawHistory() {
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { summarizeCommentExcerpt } from '../../domain/comment-threads.js';
|
|
2
|
-
|
|
3
1
|
const COMMENT_OVERVIEW_PREVIEW_MAX_LENGTH = 140;
|
|
4
2
|
|
|
3
|
+
function summarizeCommentMarkdown(value, maxLength = COMMENT_OVERVIEW_PREVIEW_MAX_LENGTH) {
|
|
4
|
+
const normalized = String(value ?? '').replace(/\r\n?/gu, '\n').trim();
|
|
5
|
+
if (normalized.length <= maxLength) {
|
|
6
|
+
return normalized;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return `${normalized.slice(0, Math.max(maxLength - 1, 1)).trimEnd()}…`;
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
function asFiniteNumber(value) {
|
|
6
13
|
return Number.isFinite(value) ? value : null;
|
|
7
14
|
}
|
|
@@ -32,10 +39,16 @@ function createThreadSummary(thread) {
|
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
const id = asString(thread.id);
|
|
42
|
+
const anchorKind = asString(thread.anchorKind) || 'line';
|
|
43
|
+
const isDiagramElementAnchor = anchorKind === 'diagram-element';
|
|
35
44
|
const anchorStartLine = asFiniteNumber(thread.anchorStartLine);
|
|
36
45
|
const anchorEndLine = asFiniteNumber(thread.anchorEndLine);
|
|
37
46
|
const messages = asArray(thread.messages);
|
|
38
|
-
if (
|
|
47
|
+
if (
|
|
48
|
+
!id
|
|
49
|
+
|| messages.length === 0
|
|
50
|
+
|| (!isDiagramElementAnchor && (anchorStartLine === null || anchorEndLine === null))
|
|
51
|
+
) {
|
|
39
52
|
return null;
|
|
40
53
|
}
|
|
41
54
|
|
|
@@ -46,10 +59,14 @@ function createThreadSummary(thread) {
|
|
|
46
59
|
|
|
47
60
|
return {
|
|
48
61
|
anchor: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
...(isDiagramElementAnchor
|
|
63
|
+
? {}
|
|
64
|
+
: {
|
|
65
|
+
endLine: Math.max(anchorEndLine, anchorStartLine),
|
|
66
|
+
startLine: Math.max(anchorStartLine, 1),
|
|
67
|
+
}),
|
|
68
|
+
kind: anchorKind,
|
|
69
|
+
quote: asString(thread.anchorQuote) || (isDiagramElementAnchor ? 'Diagram element' : ''),
|
|
53
70
|
},
|
|
54
71
|
createdAt: asFiniteNumber(thread.createdAt) ?? latestActivityAt,
|
|
55
72
|
createdByColor: asString(thread.createdByColor),
|
|
@@ -58,7 +75,7 @@ function createThreadSummary(thread) {
|
|
|
58
75
|
latestActivityAt,
|
|
59
76
|
latestMessage: latestMessage
|
|
60
77
|
? {
|
|
61
|
-
bodyPreview:
|
|
78
|
+
bodyPreview: summarizeCommentMarkdown(latestMessage.body),
|
|
62
79
|
createdAt: asFiniteNumber(latestMessage.createdAt) ?? latestActivityAt,
|
|
63
80
|
userColor: asString(latestMessage.userColor),
|
|
64
81
|
userName: asString(latestMessage.userName) || 'Anonymous',
|