@plebeiantech/lat.md 0.12.3-fork.9 → 0.13.4-fork.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 +27 -3
- package/dist/src/cli/agent-invocation.d.ts +6 -0
- package/dist/src/cli/agent-invocation.js +23 -0
- package/dist/src/cli/checklist-menu.d.ts +2 -1
- package/dist/src/cli/checklist-menu.js +3 -2
- package/dist/src/cli/fork-instructions.d.ts +1 -0
- package/dist/src/cli/fork-instructions.js +8 -32
- package/dist/src/cli/fork-scaffold.js +2 -2
- package/dist/src/cli/graph.d.ts +1 -1
- package/dist/src/cli/hook.d.ts +26 -0
- package/dist/src/cli/hook.js +115 -64
- package/dist/src/cli/index.js +178 -70
- package/dist/src/cli/init-preferences.d.ts +4 -0
- package/dist/src/cli/init-preferences.js +36 -0
- package/dist/src/cli/init.d.ts +2 -1
- package/dist/src/cli/init.js +100 -60
- package/dist/src/cli/reindex.d.ts +1 -1
- package/dist/src/cli/reindex.js +7 -10
- package/dist/src/cli/search.d.ts +14 -4
- package/dist/src/cli/search.js +115 -101
- package/dist/src/cli/ui-build-server.d.ts +12 -0
- package/dist/src/cli/ui-build-server.js +26 -0
- package/dist/src/cli/ui-build.d.ts +1 -1
- package/dist/src/cli/ui-build.js +1 -1
- package/dist/src/cli/ui.d.ts +1 -1
- package/dist/src/cli/ui.js +1 -1
- package/dist/src/cli/wiki.d.ts +12 -0
- package/dist/src/cli/wiki.js +85 -0
- package/dist/src/fork/antigravity-hook.d.ts +47 -0
- package/dist/src/fork/antigravity-hook.js +424 -0
- package/dist/src/fork/antigravity-init.d.ts +17 -0
- package/dist/src/fork/antigravity-init.js +124 -0
- package/dist/src/fork/upstream-drift.js +1 -1
- package/dist/src/fork/upstream-guard.d.ts +1 -1
- package/dist/src/fork/upstream-guard.js +8 -7
- package/dist/src/graph-export.js +7 -7
- package/dist/src/knowledge/index.js +2 -2
- package/dist/src/mcp/server.js +34 -18
- package/dist/src/search/cache.d.ts +3 -0
- package/dist/src/search/cache.js +104 -0
- package/dist/src/search/chunks.d.ts +23 -0
- package/dist/src/search/chunks.js +200 -0
- package/dist/src/search/db.d.ts +28 -16
- package/dist/src/search/db.js +100 -40
- package/dist/src/search/embedder.d.ts +2 -1
- package/dist/src/search/embedder.js +7 -6
- package/dist/src/search/index.d.ts +6 -2
- package/dist/src/search/index.js +176 -70
- package/dist/src/search/lexical.d.ts +6 -0
- package/dist/src/search/lexical.js +36 -0
- package/dist/src/search/lock.d.ts +5 -0
- package/dist/src/search/lock.js +45 -0
- package/dist/src/search/query.d.ts +26 -0
- package/dist/src/search/query.js +103 -0
- package/dist/src/search/search.d.ts +16 -7
- package/dist/src/search/search.js +165 -21
- package/dist/src/search/types.d.ts +15 -0
- package/dist/src/view/client/assets/GraphView-D_xnk0bP.js +456 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/src/view/client/assets/MarkdownEditor-bjqt_FoF.js +28 -0
- package/dist/src/view/client/assets/OrbitControls-DwcpQNja.js +1 -0
- package/dist/src/view/client/assets/STLLoader-CLWTKt5i.js +1 -0
- package/dist/src/view/client/assets/_commonjsHelpers-CqkleIqs.js +1 -0
- package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-kWGvtRnL.js +1 -0
- package/dist/src/view/client/assets/arc-BPAFd7cP.js +1 -0
- package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-CsY39oIR.js +36 -0
- package/dist/src/view/client/assets/blockDiagram-I7D4REHJ-DHGBG7BJ.js +129 -0
- package/dist/src/view/client/assets/c4Diagram-7LVT6UL2-vywK4eb7.js +38 -0
- package/dist/src/view/client/assets/channel-CX71L_qV.js +1 -0
- package/dist/src/view/client/assets/chunk-2Q5K7J3B-Do3Hz_ci.js +1 -0
- package/dist/src/view/client/assets/chunk-5VM5RSS4-B5R1lSeY.js +15 -0
- package/dist/src/view/client/assets/chunk-F27PBJKO-Dm55FM_W.js +1 -0
- package/dist/src/view/client/assets/chunk-IMKFNOWR-ChptrvvM.js +231 -0
- package/dist/src/view/client/assets/chunk-JWPE2WC7-BRQBjrKS.js +1 -0
- package/dist/src/view/client/assets/chunk-POPQ4Y6H-CainVZIL.js +1 -0
- package/dist/src/view/client/assets/chunk-SVP7TREG-DsKsNGmM.js +88 -0
- package/dist/src/view/client/assets/chunk-TICWLB2K-BctkMcJc.js +206 -0
- package/dist/src/view/client/assets/chunk-XXDRQBXY-BN7SgOUT.js +1 -0
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-B1VyU6zO.js +1 -0
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-B1VyU6zO.js +1 -0
- package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-BszzwrMe.js +1 -0
- package/dist/src/view/client/assets/cynefin-OW5HDTMX-CdRyAkPs.js +166 -0
- package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-BLvKPZ1u.js +62 -0
- package/dist/src/view/client/assets/cytoscape.esm-DzSz-X2X.js +321 -0
- package/dist/src/view/client/assets/dagre-GXQ25YYZ-V68w_l65.js +4 -0
- package/dist/src/view/client/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/src/view/client/assets/diagram-S7CK7UJ4-C2i4eEMg.js +30 -0
- package/dist/src/view/client/assets/diagram-UQ7AKVKN-BiwWh5jC.js +41 -0
- package/dist/src/view/client/assets/diagram-VSXAHHWV-hkKR_vyS.js +3 -0
- package/dist/src/view/client/assets/diagram-VX7I27RA-DzRCSMAc.js +24 -0
- package/dist/src/view/client/assets/diagram-Z3DM3KII-fhSFPxyK.js +24 -0
- package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-CCEUDKSA.js +1 -0
- package/dist/src/view/client/assets/erDiagram-RLTQ6QDP-FJ2IMyTi.js +99 -0
- package/dist/src/view/client/assets/flowDiagram-HODETNUW-BvasdLeK.js +168 -0
- package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-CiwkBZvY.js +292 -0
- package/dist/src/view/client/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/src/view/client/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/src/view/client/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/src/view/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/dist/src/view/client/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-DYlP2_js.js +106 -0
- package/dist/src/view/client/assets/index-BnENo9bV.js +1 -0
- package/dist/src/view/client/assets/index-CQ7EOox7.css +1 -0
- package/dist/src/view/client/assets/index-CynNDkxt.js +13 -0
- package/dist/src/view/client/assets/infoDiagram-27XIBGKW-DRPB2c48.js +2 -0
- package/dist/src/view/client/assets/init-Gi6I4Gst.js +1 -0
- package/dist/src/view/client/assets/ishikawaDiagram-5VMMS53U-8VV429Cv.js +70 -0
- package/dist/src/view/client/assets/journeyDiagram-3NMN7TZE-Dzmwnf83.js +139 -0
- package/dist/src/view/client/assets/kanban-definition-UXKFOSKX-pYyZZ1i-.js +89 -0
- package/dist/src/view/client/assets/katex-HP8lGamR.js +257 -0
- package/dist/src/view/client/assets/layout-GF9k6yGo.js +1 -0
- package/dist/src/view/client/assets/linear-Yt2sSOYV.js +1 -0
- package/dist/src/view/client/assets/logo-RR_KBOAT.svg +149 -0
- package/dist/src/view/client/assets/maplibre-gl-CDX6Zuow.js +800 -0
- package/dist/src/view/client/assets/mermaid.core-ChWYCHN0.js +310 -0
- package/dist/src/view/client/assets/mindmap-definition-YA3MSWOX-Cc4fQvf1.js +96 -0
- package/dist/src/view/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-C0SsB8bZ.js +1 -0
- package/dist/src/view/client/assets/pieDiagram-E7YTZNPT-DIJpqERZ.js +39 -0
- package/dist/src/view/client/assets/quadrantDiagram-AXDQQJYC--d-gl6j-.js +7 -0
- package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-BQxwTt7z.js +1 -0
- package/dist/src/view/client/assets/requirementDiagram-BXWQKSXE-B_oTeD2A.js +84 -0
- package/dist/src/view/client/assets/sankeyDiagram-P5KCCOFB-DLukmE8X.js +40 -0
- package/dist/src/view/client/assets/sequenceDiagram-WJ2MYXX4-BNjVB2sc.js +162 -0
- package/dist/src/view/client/assets/sizeCapture-INFHLROL-BZecQTOw.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-D77RDMKH-Bu1urvXC.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-5pc_697G.js +1 -0
- package/dist/src/view/client/assets/swimlanes-42K2YHIH-bLAlcepB.js +1 -0
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-BbOpZjpp.js +8 -0
- package/dist/src/view/client/assets/three.module-PDSP0dbZ.js +4108 -0
- package/dist/src/view/client/assets/timeline-definition-24CTP7MA-tbwCNvcA.js +120 -0
- package/dist/src/view/client/assets/vennDiagram-4TSXK5OY-D8U8Fk0N.js +34 -0
- package/dist/src/view/client/assets/wardleyDiagram-VM6X3IG4-LHBVIeNb.js +78 -0
- package/dist/src/view/client/assets/xychartDiagram-S5SC5T6Z-CN4tfaFV.js +7 -0
- package/dist/src/view/client/index.html +2 -2
- package/dist/src/view/client-shell.d.ts +2 -0
- package/dist/src/view/client-shell.js +5 -0
- package/dist/src/view/diagnostics.d.ts +3 -2
- package/dist/src/view/diagnostics.js +49 -58
- package/dist/src/view/document-edit.d.ts +8 -0
- package/dist/src/view/document-edit.js +25 -0
- package/dist/src/view/document-route.d.ts +14 -0
- package/dist/src/view/document-route.js +137 -0
- package/dist/src/view/document-tree.d.ts +18 -0
- package/dist/src/view/document-tree.js +139 -0
- package/dist/src/view/external-document-tree.d.ts +3 -0
- package/dist/src/view/external-document-tree.js +674 -0
- package/dist/src/view/git-diff.js +202 -2
- package/dist/src/view/git.js +1 -1
- package/dist/src/view/graph.d.ts +4 -3
- package/dist/src/view/graph.js +100 -9
- package/dist/src/view/highlight.d.ts +10 -2
- package/dist/src/view/highlight.js +50648 -3166
- package/dist/src/view/markdown.d.ts +3 -2
- package/dist/src/view/markdown.js +256 -54
- package/dist/src/view/preindexed-search.d.ts +15 -0
- package/dist/src/view/preindexed-search.js +25 -0
- package/dist/src/view/protocol.d.ts +53 -7
- package/dist/src/view/publication.d.ts +2 -0
- package/dist/src/view/publication.js +78 -0
- package/dist/src/view/references.d.ts +11 -26
- package/dist/src/view/references.js +121 -112
- package/dist/src/view/repository.d.ts +14 -4
- package/dist/src/view/repository.js +260 -19
- package/dist/src/view/request-security.d.ts +5 -0
- package/dist/src/view/request-security.js +46 -0
- package/dist/src/view/search-result.d.ts +4 -0
- package/dist/src/view/search-result.js +25 -0
- package/dist/src/view/search.d.ts +7 -2
- package/dist/src/view/search.js +23 -34
- package/dist/src/view/server-build.d.ts +21 -0
- package/dist/src/view/server-build.js +145 -0
- package/dist/src/view/server-deployment.d.ts +31 -0
- package/dist/src/view/server-deployment.js +123 -0
- package/dist/src/view/server-index-worker.d.ts +6 -0
- package/dist/src/view/server-index-worker.js +14 -0
- package/dist/src/view/server.d.ts +11 -2
- package/dist/src/view/server.js +245 -73
- package/dist/src/view/source-target.d.ts +2 -0
- package/dist/src/view/source-target.js +49 -8
- package/dist/src/view/static-build.d.ts +18 -2
- package/dist/src/view/static-build.js +449 -110
- package/dist/src/view/static-protocol.d.ts +26 -2
- package/dist/src/view/static-protocol.js +5 -0
- package/dist/src/view/store.d.ts +20 -3
- package/dist/src/view/store.js +304 -48
- package/dist/src/view/table-of-contents.d.ts +2 -2
- package/dist/src/view/table-of-contents.js +2 -22
- package/dist/src/view/vercel-build.d.ts +24 -0
- package/dist/src/view/vercel-build.js +152 -0
- package/dist/src/view/vercel-server-build.d.ts +10 -0
- package/dist/src/view/vercel-server-build.js +61 -0
- package/dist/src/wiki/catalog.d.ts +21 -0
- package/dist/src/wiki/catalog.js +256 -0
- package/dist/src/wiki/publish.d.ts +27 -0
- package/dist/src/wiki/publish.js +265 -0
- package/dist/src/wiki/render.d.ts +20 -0
- package/dist/src/wiki/render.js +163 -0
- package/dist/src/wiki/transform.d.ts +7 -0
- package/dist/src/wiki/transform.js +264 -0
- package/dist/vendor/lat.md-server/cli.d.ts +2 -0
- package/dist/vendor/lat.md-server/cli.js +12 -0
- package/dist/vendor/lat.md-server/index.d.ts +38 -0
- package/dist/vendor/lat.md-server/index.js +128 -0
- package/package.json +68 -22
- package/plugins/lat-md/README.md +61 -0
- package/plugins/lat-md/hooks.json +38 -0
- package/plugins/lat-md/plugin.json +9 -0
- package/plugins/lat-md/rules/AGENTS.md +344 -0
- package/plugins/lat-md/skills/lat-md/SKILL.md +210 -0
- package/plugins/lat-md/skills/lat-md-conventions/SKILL.md +226 -0
- package/templates/AGENTS.md +26 -7
- package/templates/cursor-rules.md +23 -7
- package/templates/fork/conventions.md +133 -11
- package/templates/opencode-plugin.ts +9 -9
- package/templates/pi-extension.ts +11 -11
- package/templates/skill/SKILL.md +35 -3
- package/dist/src/cli/check-coverage.d.ts +0 -2
- package/dist/src/cli/check-coverage.js +0 -71
- package/dist/src/cli/check-frontmatter.d.ts +0 -12
- package/dist/src/cli/check-frontmatter.js +0 -44
- package/dist/src/cli/check-mode.d.ts +0 -21
- package/dist/src/cli/check-mode.js +0 -364
- package/dist/src/cli/check-status.d.ts +0 -74
- package/dist/src/cli/check-status.js +0 -217
- package/dist/src/cli/check.d.ts +0 -45
- package/dist/src/cli/check.js +0 -781
- package/dist/src/cli/context.d.ts +0 -11
- package/dist/src/cli/context.js +0 -58
- package/dist/src/cli/expand.d.ts +0 -8
- package/dist/src/cli/expand.js +0 -94
- package/dist/src/cli/gen-index.d.ts +0 -45
- package/dist/src/cli/gen-index.js +0 -235
- package/dist/src/cli/link-scheme.d.ts +0 -54
- package/dist/src/cli/link-scheme.js +0 -101
- package/dist/src/cli/locate.d.ts +0 -2
- package/dist/src/cli/locate.js +0 -17
- package/dist/src/cli/refs.d.ts +0 -22
- package/dist/src/cli/refs.js +0 -229
- package/dist/src/cli/section.d.ts +0 -43
- package/dist/src/cli/section.js +0 -252
- package/dist/src/cli/select-menu.d.ts +0 -13
- package/dist/src/cli/select-menu.js +0 -100
- package/dist/src/code-refs.d.ts +0 -17
- package/dist/src/code-refs.js +0 -298
- package/dist/src/config.d.ts +0 -29
- package/dist/src/config.js +0 -83
- package/dist/src/context.d.ts +0 -23
- package/dist/src/context.js +0 -11
- package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
- package/dist/src/extensions/wiki-link/index.d.ts +0 -4
- package/dist/src/extensions/wiki-link/index.js +0 -3
- package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
- package/dist/src/extensions/wiki-link/syntax.js +0 -121
- package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
- package/dist/src/extensions/wiki-link/types.d.ts +0 -34
- package/dist/src/format.d.ts +0 -8
- package/dist/src/format.js +0 -43
- package/dist/src/init-version.d.ts +0 -10
- package/dist/src/init-version.js +0 -49
- package/dist/src/lattice.d.ts +0 -109
- package/dist/src/lattice.js +0 -817
- package/dist/src/parser.d.ts +0 -3
- package/dist/src/parser.js +0 -18
- package/dist/src/source-parser.d.ts +0 -27
- package/dist/src/source-parser.js +0 -916
- package/dist/src/untrusted.d.ts +0 -18
- package/dist/src/untrusted.js +0 -93
- package/dist/src/view/client/assets/index-C3iaZyYT.css +0 -1
- package/dist/src/view/client/assets/index-KWi67IMz.js +0 -334
- package/dist/src/view/client/assets/logo-CNF8zs47.svg +0 -182
- package/dist/src/walk.d.ts +0 -18
- package/dist/src/walk.js +0 -27
- /package/dist/src/{extensions/wiki-link → search}/types.js +0 -0
package/dist/src/view/server.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
|
+
import { trustedLiveRequest, RESOURCE_CONTENT_SECURITY_POLICY, } from './request-security.js';
|
|
1
2
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
3
4
|
import { extname, join, relative, resolve, sep } from 'node:path';
|
|
4
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { createLatServerApp, listenLatServer, } from '../../vendor/lat.md-server/index.js';
|
|
7
|
+
import { plainStyler, } from '@plebeiantech/lat.md-core/context';
|
|
8
|
+
import { sectionCommand } from '@plebeiantech/lat.md-core/cli/section';
|
|
5
9
|
import { DEFAULT_VIEW_LOGO_TEXT, } from './protocol.js';
|
|
6
|
-
import {
|
|
10
|
+
import { ViewDocumentConflictError } from './document-edit.js';
|
|
11
|
+
import { ViewExternalNotFoundError, ViewDocumentNotFoundError, ViewSourceNotFoundError, } from './repository.js';
|
|
7
12
|
import { createViewSearch } from './search.js';
|
|
8
13
|
import { createViewStore } from './store.js';
|
|
14
|
+
import { rewriteClientAssetUrls } from './client-shell.js';
|
|
15
|
+
import { documentResourcePath, documentPath, rawDocumentPath, validateDocumentRoutes, } from './document-route.js';
|
|
9
16
|
const DEFAULT_HOST = '127.0.0.1';
|
|
10
17
|
export const DEFAULT_VIEW_PORT = 4242;
|
|
18
|
+
const MAX_DOCUMENT_EDIT_BODY_BYTES = 16 * 1024 * 1024;
|
|
19
|
+
const MAX_DOCUMENT_CONTENT_LENGTH = 8 * 1024 * 1024;
|
|
11
20
|
const defaultClientDir = fileURLToPath(new URL('./client/', import.meta.url));
|
|
12
|
-
function documentUrl(path) {
|
|
13
|
-
return `/docs/${path.split('/').map(encodeURIComponent).join('/')}`;
|
|
14
|
-
}
|
|
15
|
-
function setSecurityHeaders(res) {
|
|
16
|
-
res.setHeader('Content-Security-Policy', "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; worker-src 'self' blob:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'");
|
|
17
|
-
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
18
|
-
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
19
|
-
}
|
|
20
21
|
function send(res, status, contentType, body, headOnly = false) {
|
|
21
22
|
res.statusCode = status;
|
|
22
23
|
res.setHeader('Content-Type', contentType);
|
|
@@ -27,6 +28,24 @@ function sendJson(res, status, value, headOnly) {
|
|
|
27
28
|
res.setHeader('Cache-Control', 'no-store');
|
|
28
29
|
send(res, status, 'application/json; charset=utf-8', JSON.stringify(value), headOnly);
|
|
29
30
|
}
|
|
31
|
+
async function readJsonBody(req) {
|
|
32
|
+
const chunks = [];
|
|
33
|
+
let size = 0;
|
|
34
|
+
for await (const value of req) {
|
|
35
|
+
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
36
|
+
size += chunk.byteLength;
|
|
37
|
+
if (size > MAX_DOCUMENT_EDIT_BODY_BYTES) {
|
|
38
|
+
throw new RangeError('Document edit is too large');
|
|
39
|
+
}
|
|
40
|
+
chunks.push(chunk);
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new SyntaxError('Document edit must be valid JSON');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
30
49
|
function contentType(path) {
|
|
31
50
|
switch (extname(path)) {
|
|
32
51
|
case '.css':
|
|
@@ -37,8 +56,17 @@ function contentType(path) {
|
|
|
37
56
|
return 'text/javascript; charset=utf-8';
|
|
38
57
|
case '.json':
|
|
39
58
|
return 'application/json; charset=utf-8';
|
|
59
|
+
case '.gif':
|
|
60
|
+
return 'image/gif';
|
|
61
|
+
case '.jpeg':
|
|
62
|
+
case '.jpg':
|
|
63
|
+
return 'image/jpeg';
|
|
64
|
+
case '.png':
|
|
65
|
+
return 'image/png';
|
|
40
66
|
case '.svg':
|
|
41
67
|
return 'image/svg+xml';
|
|
68
|
+
case '.webp':
|
|
69
|
+
return 'image/webp';
|
|
42
70
|
case '.woff2':
|
|
43
71
|
return 'font/woff2';
|
|
44
72
|
default:
|
|
@@ -71,23 +99,24 @@ async function sendClientFile(res, path, headOnly, immutable = false) {
|
|
|
71
99
|
send(res, 404, 'text/plain; charset=utf-8', 'Not found', headOnly);
|
|
72
100
|
}
|
|
73
101
|
}
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
102
|
+
async function sendClientShell(res, path, headOnly, entry) {
|
|
103
|
+
try {
|
|
104
|
+
const html = rewriteClientAssetUrls(await readFile(path, 'utf8'), '/');
|
|
105
|
+
const config = `<meta name="lat-live-entry" content="${encodeURIComponent(entry)}">`;
|
|
106
|
+
const body = html.includes('</head>')
|
|
107
|
+
? html.replace('</head>', `${config}</head>`)
|
|
108
|
+
: `${config}${html}`;
|
|
109
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
110
|
+
send(res, 200, 'text/html; charset=utf-8', body, headOnly);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (error.code !== 'ENOENT')
|
|
114
|
+
throw error;
|
|
115
|
+
send(res, 404, 'text/plain; charset=utf-8', 'Not found', headOnly);
|
|
116
|
+
}
|
|
88
117
|
}
|
|
89
|
-
/**
|
|
90
|
-
export async function
|
|
118
|
+
/** Create the portable Express application used by live Lat UI servers. */
|
|
119
|
+
export async function createViewApp(ctx, options = {}) {
|
|
91
120
|
const host = options.host ?? DEFAULT_HOST;
|
|
92
121
|
const clientDir = options.clientDir ?? defaultClientDir;
|
|
93
122
|
const logoText = options.logoText ?? DEFAULT_VIEW_LOGO_TEXT;
|
|
@@ -95,35 +124,60 @@ export async function startViewServer(ctx, options = {}) {
|
|
|
95
124
|
git: options.git,
|
|
96
125
|
gitPollMs: options.gitPollMs,
|
|
97
126
|
watch: options.watch,
|
|
127
|
+
externalCa: options.externalCa,
|
|
98
128
|
});
|
|
129
|
+
try {
|
|
130
|
+
validateDocumentRoutes(store.getIndex().files);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
await store.close();
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
99
136
|
const search = options.search ??
|
|
100
137
|
createViewSearch(ctx.latDir, undefined, () => store.markdownGeneration);
|
|
101
138
|
const eventClients = new Set();
|
|
139
|
+
const instanceId = randomUUID();
|
|
102
140
|
const broadcastChange = (change) => {
|
|
103
|
-
const message = `event: change\ndata: ${JSON.stringify(change)}\n\n`;
|
|
141
|
+
const message = `event: change\ndata: ${JSON.stringify({ ...change, instanceId })}\n\n`;
|
|
104
142
|
for (const client of eventClients)
|
|
105
143
|
client.write(message);
|
|
106
144
|
};
|
|
107
145
|
const unsubscribeStore = store.subscribe(broadcastChange);
|
|
108
|
-
const
|
|
146
|
+
const heartbeat = setInterval(() => {
|
|
147
|
+
for (const client of eventClients)
|
|
148
|
+
client.write(': heartbeat\n\n');
|
|
149
|
+
}, 15_000);
|
|
150
|
+
heartbeat.unref();
|
|
151
|
+
const handleRequest = (req, res) => {
|
|
109
152
|
void (async () => {
|
|
110
|
-
|
|
153
|
+
if (!trustedLiveRequest(req, host)) {
|
|
154
|
+
send(res, 403, 'text/plain; charset=utf-8', 'Untrusted request origin or host');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
111
157
|
const method = req.method ?? 'GET';
|
|
112
158
|
const headOnly = method === 'HEAD';
|
|
113
|
-
|
|
159
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
|
160
|
+
const documentEdit = method === 'PATCH' && url.pathname === '/api/document';
|
|
161
|
+
if (method !== 'GET' && !headOnly && !documentEdit) {
|
|
114
162
|
res.setHeader('Allow', 'GET, HEAD');
|
|
115
163
|
send(res, 405, 'text/plain; charset=utf-8', 'Method not allowed');
|
|
116
164
|
return;
|
|
117
165
|
}
|
|
118
|
-
const url = new URL(req.url ?? '/', `http://${host}`);
|
|
119
166
|
if (url.pathname === '/') {
|
|
120
167
|
const entry = store.getIndex().entry;
|
|
121
168
|
if (!entry) {
|
|
122
169
|
send(res, 404, 'text/plain; charset=utf-8', 'No Markdown files found');
|
|
123
170
|
return;
|
|
124
171
|
}
|
|
125
|
-
res.
|
|
126
|
-
|
|
172
|
+
await sendClientShell(res, join(clientDir, 'index.html'), headOnly, entry);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const index = store.getIndex();
|
|
176
|
+
const routePath = url.pathname.replace(/\/$/, '');
|
|
177
|
+
const markdownPath = documentPath(routePath);
|
|
178
|
+
if (markdownPath === index.entry) {
|
|
179
|
+
res.statusCode = 308;
|
|
180
|
+
res.setHeader('Location', `/${url.search}`);
|
|
127
181
|
res.end();
|
|
128
182
|
return;
|
|
129
183
|
}
|
|
@@ -146,12 +200,52 @@ export async function startViewServer(ctx, options = {}) {
|
|
|
146
200
|
return;
|
|
147
201
|
}
|
|
148
202
|
eventClients.add(res);
|
|
149
|
-
res.write(`
|
|
203
|
+
res.write(`retry: 1000\nevent: ready\ndata: ${JSON.stringify({ instanceId, generation: store.snapshot.generation, markdownGeneration: store.markdownGeneration })}\n\n`);
|
|
150
204
|
req.once('close', () => eventClients.delete(res));
|
|
151
205
|
return;
|
|
152
206
|
}
|
|
153
207
|
if (url.pathname === '/api/document') {
|
|
154
208
|
const path = url.searchParams.get('path') ?? '';
|
|
209
|
+
if (documentEdit) {
|
|
210
|
+
let body;
|
|
211
|
+
try {
|
|
212
|
+
body = await readJsonBody(req);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
sendJson(res, error instanceof RangeError ? 413 : 400, { error: error.message }, false);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (!body ||
|
|
219
|
+
typeof body !== 'object' ||
|
|
220
|
+
typeof body.baseContent !==
|
|
221
|
+
'string' ||
|
|
222
|
+
typeof body.content !==
|
|
223
|
+
'string') {
|
|
224
|
+
sendJson(res, 400, {
|
|
225
|
+
error: 'Document edit content is required',
|
|
226
|
+
}, false);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const edit = body;
|
|
230
|
+
if (edit.baseContent.length > MAX_DOCUMENT_CONTENT_LENGTH ||
|
|
231
|
+
edit.content.length > MAX_DOCUMENT_CONTENT_LENGTH) {
|
|
232
|
+
sendJson(res, 413, { error: 'Document edit is too large' }, false);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
sendJson(res, 200, await store.editDocument(path, edit.baseContent, edit.content), false);
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
if (error instanceof ViewDocumentConflictError) {
|
|
240
|
+
sendJson(res, 409, { error: error.message }, false);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (!(error instanceof ViewDocumentNotFoundError))
|
|
244
|
+
throw error;
|
|
245
|
+
sendJson(res, 404, { error: error.message }, false);
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
155
249
|
try {
|
|
156
250
|
sendJson(res, 200, await store.getDocument(path), headOnly);
|
|
157
251
|
}
|
|
@@ -162,6 +256,18 @@ export async function startViewServer(ctx, options = {}) {
|
|
|
162
256
|
}
|
|
163
257
|
return;
|
|
164
258
|
}
|
|
259
|
+
if (url.pathname === '/api/document-source') {
|
|
260
|
+
const path = url.searchParams.get('path') ?? '';
|
|
261
|
+
try {
|
|
262
|
+
sendJson(res, 200, await store.getDocumentSource(path), headOnly);
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
if (!(error instanceof ViewDocumentNotFoundError))
|
|
266
|
+
throw error;
|
|
267
|
+
sendJson(res, 404, { error: error.message }, headOnly);
|
|
268
|
+
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
165
271
|
if (url.pathname === '/api/search') {
|
|
166
272
|
const query = (url.searchParams.get('query') ?? '').trim();
|
|
167
273
|
if (query.length > 500) {
|
|
@@ -171,6 +277,30 @@ export async function startViewServer(ctx, options = {}) {
|
|
|
171
277
|
sendJson(res, 200, await search(query), headOnly);
|
|
172
278
|
return;
|
|
173
279
|
}
|
|
280
|
+
if (url.pathname === '/api/section') {
|
|
281
|
+
const query = (url.searchParams.get('query') ?? '').trim();
|
|
282
|
+
if (!query) {
|
|
283
|
+
sendJson(res, 400, { error: 'Section ID is required' }, headOnly);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (query.length > 1_000) {
|
|
287
|
+
sendJson(res, 400, { error: 'Section ID is too long' }, headOnly);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const result = await sectionCommand({
|
|
291
|
+
latDir: ctx.latDir,
|
|
292
|
+
projectRoot: ctx.projectRoot,
|
|
293
|
+
styler: plainStyler,
|
|
294
|
+
mode: 'cli',
|
|
295
|
+
}, query);
|
|
296
|
+
const tree = await store.renderSectionOutput(result.output, query);
|
|
297
|
+
sendJson(res, 200, {
|
|
298
|
+
output: result.output,
|
|
299
|
+
tree,
|
|
300
|
+
isError: result.isError === true,
|
|
301
|
+
}, headOnly);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
174
304
|
if (url.pathname === '/api/source') {
|
|
175
305
|
const path = url.searchParams.get('path') ?? '';
|
|
176
306
|
const symbol = url.searchParams.get('symbol') ?? '';
|
|
@@ -193,6 +323,18 @@ export async function startViewServer(ctx, options = {}) {
|
|
|
193
323
|
}
|
|
194
324
|
return;
|
|
195
325
|
}
|
|
326
|
+
if (url.pathname === '/api/external') {
|
|
327
|
+
const target = url.searchParams.get('target') ?? '';
|
|
328
|
+
try {
|
|
329
|
+
sendJson(res, 200, await store.getExternal(target), headOnly);
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
if (!(error instanceof ViewExternalNotFoundError))
|
|
333
|
+
throw error;
|
|
334
|
+
sendJson(res, 404, { error: error.message }, headOnly);
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
196
338
|
if (url.pathname.startsWith('/assets/')) {
|
|
197
339
|
const path = clientPath(clientDir, url.pathname);
|
|
198
340
|
if (!path) {
|
|
@@ -202,11 +344,47 @@ export async function startViewServer(ctx, options = {}) {
|
|
|
202
344
|
await sendClientFile(res, path, headOnly, true);
|
|
203
345
|
return;
|
|
204
346
|
}
|
|
347
|
+
const rawMarkdownPath = rawDocumentPath(url.pathname);
|
|
348
|
+
if (rawMarkdownPath) {
|
|
349
|
+
try {
|
|
350
|
+
const source = await store.getDocumentSource(rawMarkdownPath);
|
|
351
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
352
|
+
send(res, 200, 'text/markdown; charset=utf-8', source.content, headOnly);
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
if (!(error instanceof ViewDocumentNotFoundError))
|
|
356
|
+
throw error;
|
|
357
|
+
send(res, 404, 'text/plain; charset=utf-8', error.message, headOnly);
|
|
358
|
+
}
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const resourcePath = documentResourcePath(url.pathname);
|
|
362
|
+
if (resourcePath) {
|
|
363
|
+
try {
|
|
364
|
+
const body = await store.getDocumentResource(resourcePath);
|
|
365
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
366
|
+
res.setHeader('Content-Security-Policy', RESOURCE_CONTENT_SECURITY_POLICY);
|
|
367
|
+
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
|
|
368
|
+
if (/\.(?:html?|xhtml|xml|[cm]?js)$/i.test(resourcePath)) {
|
|
369
|
+
res.setHeader('Content-Disposition', 'attachment');
|
|
370
|
+
}
|
|
371
|
+
send(res, 200, contentType(resourcePath), body, headOnly);
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
if (!(error instanceof ViewDocumentNotFoundError))
|
|
375
|
+
throw error;
|
|
376
|
+
send(res, 404, 'text/plain; charset=utf-8', error.message, headOnly);
|
|
377
|
+
}
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
205
380
|
if (url.pathname === '/search' ||
|
|
206
381
|
url.pathname === '/graph' ||
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
382
|
+
(markdownPath !== null &&
|
|
383
|
+
(markdownPath.startsWith('@/') ||
|
|
384
|
+
index.files.includes(markdownPath))) ||
|
|
385
|
+
url.pathname.startsWith('/code/') ||
|
|
386
|
+
url.pathname.startsWith('/external/')) {
|
|
387
|
+
await sendClientShell(res, join(clientDir, 'index.html'), headOnly, index.entry);
|
|
210
388
|
return;
|
|
211
389
|
}
|
|
212
390
|
send(res, 404, 'text/plain; charset=utf-8', 'Not found', headOnly);
|
|
@@ -217,50 +395,44 @@ export async function startViewServer(ctx, options = {}) {
|
|
|
217
395
|
}
|
|
218
396
|
sendJson(res, 500, { error: error.message }, false);
|
|
219
397
|
});
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const requestedPort = options.port;
|
|
223
|
-
let port = requestedPort ?? DEFAULT_VIEW_PORT;
|
|
224
|
-
while (true) {
|
|
225
|
-
try {
|
|
226
|
-
await listen(server, host, port);
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
if (requestedPort !== undefined ||
|
|
231
|
-
error.code !== 'EADDRINUSE' ||
|
|
232
|
-
port === 65_535) {
|
|
233
|
-
throw error;
|
|
234
|
-
}
|
|
235
|
-
port++;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
catch (error) {
|
|
240
|
-
unsubscribeStore();
|
|
241
|
-
await store.close();
|
|
242
|
-
throw error;
|
|
243
|
-
}
|
|
244
|
-
const address = server.address();
|
|
245
|
-
if (!address || typeof address === 'string') {
|
|
246
|
-
await new Promise((resolveClose) => server.close(() => resolveClose()));
|
|
247
|
-
unsubscribeStore();
|
|
248
|
-
await store.close();
|
|
249
|
-
throw new Error('Could not determine lat ui server address');
|
|
250
|
-
}
|
|
398
|
+
};
|
|
399
|
+
const app = createLatServerApp({ handle: handleRequest });
|
|
251
400
|
return {
|
|
252
|
-
|
|
401
|
+
app,
|
|
253
402
|
store,
|
|
254
|
-
url: `http://${host}:${address.port}/`,
|
|
255
403
|
close: async () => {
|
|
404
|
+
clearInterval(heartbeat);
|
|
256
405
|
unsubscribeStore();
|
|
257
406
|
for (const client of eventClients)
|
|
258
407
|
client.end();
|
|
259
408
|
eventClients.clear();
|
|
260
409
|
await store.close();
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/** Start the loopback server used by `lat ui`. */
|
|
414
|
+
export async function startViewServer(ctx, options = {}) {
|
|
415
|
+
const host = options.host ?? DEFAULT_HOST;
|
|
416
|
+
const view = await createViewApp(ctx, options);
|
|
417
|
+
let running;
|
|
418
|
+
try {
|
|
419
|
+
const requestedPort = options.port;
|
|
420
|
+
running = await listenLatServer(view.app, {
|
|
421
|
+
host,
|
|
422
|
+
port: requestedPort ?? DEFAULT_VIEW_PORT,
|
|
423
|
+
findAvailablePort: requestedPort === undefined,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
catch (error) {
|
|
427
|
+
await view.close();
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
server: running.server,
|
|
432
|
+
store: view.store,
|
|
433
|
+
url: running.url,
|
|
434
|
+
close: async () => {
|
|
435
|
+
await Promise.all([running.close(), view.close()]);
|
|
264
436
|
},
|
|
265
437
|
};
|
|
266
438
|
}
|
|
@@ -1,16 +1,57 @@
|
|
|
1
|
-
import { extname
|
|
2
|
-
import {
|
|
1
|
+
import { extname } from 'node:path';
|
|
2
|
+
import { normalizeRepositoryPath } from '@plebeiantech/lat.md-core/repository-path';
|
|
3
|
+
import { isSourceFileExtension } from '@plebeiantech/lat.md-core/source-formats';
|
|
4
|
+
import { documentUrl, documentResourceUrl, rewriteDocumentLink, } from './document-route.js';
|
|
5
|
+
/** Resolve ordinary code links relative to their Markdown file, not the vault root. */
|
|
6
|
+
export function rewriteLocalFileLink(value, sourcePath) {
|
|
7
|
+
if (value && !/^(?:[#/]|[a-z][a-z\d+.-]*:)/i.test(value)) {
|
|
8
|
+
try {
|
|
9
|
+
// Keep a project prefix so URL normalization cannot silently clamp an
|
|
10
|
+
// escaping relative path back into the project.
|
|
11
|
+
const preview = sourcePath.startsWith('@/');
|
|
12
|
+
const authoredPath = preview
|
|
13
|
+
? sourcePath.slice(2)
|
|
14
|
+
: 'lat.md/' + sourcePath;
|
|
15
|
+
const base = authoredPath.split('/').map(encodeURIComponent).join('/');
|
|
16
|
+
const url = new URL(value, `http://lat.local/project/${base}`);
|
|
17
|
+
if (url.origin === 'http://lat.local' &&
|
|
18
|
+
url.pathname.startsWith('/project/')) {
|
|
19
|
+
const path = decodeURIComponent(url.pathname.slice('/project/'.length));
|
|
20
|
+
if (path.includes('@'))
|
|
21
|
+
return '#';
|
|
22
|
+
const suffix = url.search + url.hash;
|
|
23
|
+
if (normalizeRepositoryPath(path) &&
|
|
24
|
+
extname(path).toLowerCase() === '.md') {
|
|
25
|
+
return (documentUrl(path.startsWith('lat.md/') ? path.slice(7) : '@/' + path) + suffix);
|
|
26
|
+
}
|
|
27
|
+
if (preview &&
|
|
28
|
+
normalizeRepositoryPath(path) &&
|
|
29
|
+
!isSourceFileExtension(extname(path))) {
|
|
30
|
+
return (documentResourceUrl(path.startsWith('lat.md/') ? path.slice(7) : '@/' + path) + suffix);
|
|
31
|
+
}
|
|
32
|
+
if (normalizeRepositoryPath(path) &&
|
|
33
|
+
(!path.startsWith('lat.md/') || isSourceFileExtension(extname(path)))) {
|
|
34
|
+
return `/code/${path.split('/').map(encodeURIComponent).join('/')}${url.search}${url.hash}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Malformed URLs retain the ordinary document/resource fallback.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (sourcePath.startsWith('@/') &&
|
|
43
|
+
value &&
|
|
44
|
+
!/^(?:[#/]|[a-z][a-z\d+.-]*:)/i.test(value))
|
|
45
|
+
return '#';
|
|
46
|
+
return rewriteDocumentLink(value, sourcePath);
|
|
47
|
+
}
|
|
3
48
|
/** Normalize a supported source wiki-link target for view indexes and routes. */
|
|
4
49
|
export function viewSourceTarget(target) {
|
|
5
50
|
const hash = target.indexOf('#');
|
|
6
51
|
const authoredPath = hash === -1 ? target : target.slice(0, hash);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
posix.isAbsolute(authoredPath) ||
|
|
10
|
-
!SOURCE_EXTENSIONS.has(extname(authoredPath))) {
|
|
52
|
+
const path = normalizeRepositoryPath(authoredPath);
|
|
53
|
+
if (!path || !isSourceFileExtension(extname(path)))
|
|
11
54
|
return null;
|
|
12
|
-
}
|
|
13
|
-
const path = posix.normalize(authoredPath).replace(/^\.\//, '');
|
|
14
55
|
const symbol = hash === -1 ? '' : target.slice(hash + 1);
|
|
15
56
|
const fileKey = path.toLowerCase();
|
|
16
57
|
return {
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { rename } from 'node:fs/promises';
|
|
2
|
+
import type { CmdContext } from '@plebeiantech/lat.md-core/context';
|
|
2
3
|
export type StaticViewBuildOptions = {
|
|
3
4
|
basePath?: string;
|
|
4
5
|
clientDir?: string;
|
|
6
|
+
codeExcludePaths?: string[];
|
|
7
|
+
force?: boolean;
|
|
5
8
|
logoText?: string;
|
|
9
|
+
externalCa?: string | Buffer;
|
|
10
|
+
searchApi?: string;
|
|
6
11
|
};
|
|
7
12
|
export type StaticViewBuildResult = {
|
|
8
13
|
documents: number;
|
|
@@ -11,6 +16,17 @@ export type StaticViewBuildResult = {
|
|
|
11
16
|
};
|
|
12
17
|
export declare function normalizeStaticViewBasePath(value: string): string;
|
|
13
18
|
/** Convert a live view route to its physical static-directory URL. */
|
|
14
|
-
export declare function staticViewUrl(value: string, basePath: string): string;
|
|
19
|
+
export declare function staticViewUrl(value: string, basePath: string, entryPath?: string): string;
|
|
20
|
+
/** Refuse build targets that exist or could replace the project itself. */
|
|
21
|
+
export declare function validateViewBuildOutput(outputDir: string, projectRoot: string, kind?: string, force?: boolean): Promise<void>;
|
|
22
|
+
type ViewBuildMoveDependencies = {
|
|
23
|
+
move: typeof rename;
|
|
24
|
+
wait: (milliseconds: number) => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
/** Commit a staged build after transient filesystem locks have cleared. */
|
|
27
|
+
export declare function moveViewBuildOutput(stagingDir: string, outputDir: string, dependencies?: ViewBuildMoveDependencies): Promise<void>;
|
|
28
|
+
/** Remove abandoned staging after transient filesystem locks have cleared. */
|
|
29
|
+
export declare function removeViewBuildStaging(stagingDir: string): Promise<void>;
|
|
15
30
|
/** Build a serverless snapshot of the current read-only Lat UI. */
|
|
16
31
|
export declare function buildStaticView(ctx: CmdContext, requestedOutput: string, options?: StaticViewBuildOptions): Promise<StaticViewBuildResult>;
|
|
32
|
+
export {};
|