@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
|
@@ -1,22 +1,29 @@
|
|
|
1
|
+
import { createPublicationPolicy } from './publication.js';
|
|
1
2
|
import { createHash } from 'node:crypto';
|
|
2
3
|
import { cp, lstat, mkdir, mkdtemp, readFile, rename, rm, writeFile, } from 'node:fs/promises';
|
|
3
4
|
import { dirname, join, parse, relative, resolve, sep } from 'node:path';
|
|
4
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { isDocumentPath } from '@plebeiantech/lat.md-core/document-formats';
|
|
5
7
|
import { DEFAULT_VIEW_LOGO_TEXT } from './protocol.js';
|
|
6
|
-
import {
|
|
8
|
+
import { documentTreeUrls, rewriteDocumentTreeUrls } from './document-tree.js';
|
|
9
|
+
import { VIEW_STATIC_BOOTSTRAP_ID, viewStaticDocumentRequest, viewStaticSourceKey, } from './static-protocol.js';
|
|
7
10
|
import { createViewStore } from './store.js';
|
|
8
|
-
|
|
11
|
+
import { rewriteClientAssetUrls } from './client-shell.js';
|
|
12
|
+
import { documentResourcePath, documentPath, documentUrl, rawDocumentPath, validateDocumentRoutes, } from './document-route.js';
|
|
9
13
|
const defaultClientDir = fileURLToPath(new URL('./client/', import.meta.url));
|
|
14
|
+
const VIEW_BUILD_MOVE_MAX_RETRIES = 10;
|
|
15
|
+
const VIEW_BUILD_MOVE_RETRY_DELAY_MS = 150;
|
|
10
16
|
function isInside(parent, child) {
|
|
11
17
|
const rel = relative(parent, child);
|
|
12
18
|
return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`));
|
|
13
19
|
}
|
|
14
20
|
export function normalizeStaticViewBasePath(value) {
|
|
15
|
-
const
|
|
21
|
+
const path = value.startsWith('/') ? value : `/${value}`;
|
|
22
|
+
const parsed = new URL(path, 'http://lat.local');
|
|
16
23
|
if (parsed.origin !== 'http://lat.local' ||
|
|
17
24
|
parsed.search ||
|
|
18
25
|
parsed.hash ||
|
|
19
|
-
|
|
26
|
+
value.includes('://')) {
|
|
20
27
|
throw new Error('Static UI base path must be an absolute URL path');
|
|
21
28
|
}
|
|
22
29
|
return parsed.pathname.endsWith('/')
|
|
@@ -44,8 +51,8 @@ function decodeHtmlUrlAttribute(value) {
|
|
|
44
51
|
return value.replace(/&(amp|#38|#x26);/gi, '&');
|
|
45
52
|
}
|
|
46
53
|
/** Convert a live view route to its physical static-directory URL. */
|
|
47
|
-
export function staticViewUrl(value, basePath) {
|
|
48
|
-
if (!value || value.startsWith('
|
|
54
|
+
export function staticViewUrl(value, basePath, entryPath) {
|
|
55
|
+
if (!value || !value.startsWith('/') || value.startsWith('//'))
|
|
49
56
|
return value;
|
|
50
57
|
let url;
|
|
51
58
|
try {
|
|
@@ -56,7 +63,20 @@ export function staticViewUrl(value, basePath) {
|
|
|
56
63
|
}
|
|
57
64
|
if (url.origin !== 'http://lat.local')
|
|
58
65
|
return value;
|
|
59
|
-
|
|
66
|
+
const markdownPath = documentPath(url.pathname.replace(/\/$/, ''));
|
|
67
|
+
if (markdownPath || rawDocumentPath(url.pathname)) {
|
|
68
|
+
const route = url.pathname.slice(1).replace(/\/+$/, '');
|
|
69
|
+
const suffix = `${url.search}${url.hash}`;
|
|
70
|
+
if (entryPath && markdownPath === entryPath) {
|
|
71
|
+
return `${basePath}${suffix}`;
|
|
72
|
+
}
|
|
73
|
+
return `${basePath}${route}${suffix}`;
|
|
74
|
+
}
|
|
75
|
+
if (url.pathname.startsWith('/resources/')) {
|
|
76
|
+
const route = url.pathname.slice(1);
|
|
77
|
+
return `${basePath}${route}${url.search}${url.hash}`;
|
|
78
|
+
}
|
|
79
|
+
for (const prefix of ['/code/', '/external/']) {
|
|
60
80
|
if (!url.pathname.startsWith(prefix))
|
|
61
81
|
continue;
|
|
62
82
|
const route = url.pathname.slice(1).replace(/\/+$/, '');
|
|
@@ -65,96 +85,96 @@ export function staticViewUrl(value, basePath) {
|
|
|
65
85
|
if (url.pathname === '/graph') {
|
|
66
86
|
return `${basePath}graph/${url.search}${url.hash}`;
|
|
67
87
|
}
|
|
88
|
+
if (url.pathname === '/' || url.pathname === '/search') {
|
|
89
|
+
return `${basePath}${url.pathname.slice(1)}${url.search}${url.hash}`;
|
|
90
|
+
}
|
|
68
91
|
return value;
|
|
69
92
|
}
|
|
70
93
|
function documentPathFromUrl(value) {
|
|
71
|
-
|
|
72
|
-
return null;
|
|
73
|
-
try {
|
|
74
|
-
return value.pathname
|
|
75
|
-
.slice('/docs/'.length)
|
|
76
|
-
.split('/')
|
|
77
|
-
.map(decodeURIComponent)
|
|
78
|
-
.join('/');
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
94
|
+
return documentPath(value.pathname) ?? rawDocumentPath(value.pathname);
|
|
83
95
|
}
|
|
84
|
-
function rewriteHtmlLink(value, basePath, sourcePath, documentPaths) {
|
|
85
|
-
const direct = staticViewUrl(value, basePath);
|
|
96
|
+
function rewriteHtmlLink(value, basePath, entryPath, sourcePath, documentPaths) {
|
|
97
|
+
const direct = staticViewUrl(value, basePath, entryPath);
|
|
86
98
|
if (direct !== value || !sourcePath || value.startsWith('#'))
|
|
87
99
|
return direct;
|
|
88
100
|
let resolved;
|
|
89
101
|
try {
|
|
90
|
-
const
|
|
91
|
-
|
|
102
|
+
const externalAt = sourcePath.indexOf(':');
|
|
103
|
+
const currentRoute = externalAt > 0 && !documentPaths.has(sourcePath)
|
|
104
|
+
? `/external/${encodeURIComponent(sourcePath.slice(0, externalAt))}/${sourcePath
|
|
105
|
+
.slice(externalAt + 1)
|
|
106
|
+
.split('/')
|
|
107
|
+
.map(encodeURIComponent)
|
|
108
|
+
.join('/')}`
|
|
109
|
+
: documentUrl(sourcePath);
|
|
110
|
+
resolved = new URL(decodeHtmlUrlAttribute(value), `http://lat.local${currentRoute}`);
|
|
92
111
|
}
|
|
93
112
|
catch {
|
|
94
113
|
return value;
|
|
95
114
|
}
|
|
96
115
|
const documentPath = documentPathFromUrl(resolved);
|
|
116
|
+
if (resolved.pathname.startsWith('/external/')) {
|
|
117
|
+
return staticViewUrl(`${resolved.pathname}${resolved.search}${resolved.hash}`, basePath, entryPath);
|
|
118
|
+
}
|
|
97
119
|
if (resolved.origin !== 'http://lat.local' ||
|
|
98
120
|
!documentPath ||
|
|
99
121
|
!documentPaths.has(documentPath)) {
|
|
100
122
|
return value;
|
|
101
123
|
}
|
|
102
|
-
return staticViewUrl(`${
|
|
124
|
+
return staticViewUrl(`${documentUrl(documentPath)}${resolved.search}${resolved.hash}`, basePath, entryPath);
|
|
103
125
|
}
|
|
104
|
-
function
|
|
105
|
-
return
|
|
106
|
-
const rewritten = rewriteHtmlLink(value, basePath, sourcePath, documentPaths);
|
|
107
|
-
if (rewritten === value)
|
|
108
|
-
return attribute;
|
|
109
|
-
return `href="${rewritten.replaceAll('&', '&').replaceAll('"', '"')}"`;
|
|
110
|
-
});
|
|
126
|
+
function rewriteDocumentLinks(tree, basePath, entryPath, sourcePath, documentPaths) {
|
|
127
|
+
return rewriteDocumentTreeUrls(tree, (value) => rewriteHtmlLink(value, basePath, entryPath, sourcePath, documentPaths));
|
|
111
128
|
}
|
|
112
|
-
function rewriteMarkdownReference(reference, basePath, sourcePath, documentPaths) {
|
|
129
|
+
function rewriteMarkdownReference(reference, basePath, entryPath, sourcePath, documentPaths) {
|
|
113
130
|
return {
|
|
114
131
|
...reference,
|
|
115
|
-
|
|
116
|
-
url: staticViewUrl(reference.url, basePath),
|
|
132
|
+
paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, entryPath, sourcePath, documentPaths),
|
|
133
|
+
url: staticViewUrl(reference.url, basePath, entryPath),
|
|
117
134
|
};
|
|
118
135
|
}
|
|
119
|
-
function rewriteBackReference(reference, basePath, sectionPaths, documentPaths) {
|
|
136
|
+
function rewriteBackReference(reference, basePath, entryPath, sectionPaths, documentPaths) {
|
|
120
137
|
return reference.kind === 'markdown'
|
|
121
|
-
? rewriteMarkdownReference(reference, basePath, sectionPaths.get(reference.sectionId.split('#', 1)[0]) ?? null, documentPaths)
|
|
122
|
-
: {
|
|
138
|
+
? rewriteMarkdownReference(reference, basePath, entryPath, sectionPaths.get(reference.sectionId.split('#', 1)[0]) ?? null, documentPaths)
|
|
139
|
+
: {
|
|
140
|
+
...reference,
|
|
141
|
+
url: staticViewUrl(reference.url, basePath, entryPath),
|
|
142
|
+
};
|
|
123
143
|
}
|
|
124
|
-
function rewriteDocument(document, basePath, sectionPaths, documentPaths) {
|
|
144
|
+
function rewriteDocument(document, basePath, entryPath, sectionPaths, documentPaths) {
|
|
125
145
|
return {
|
|
126
146
|
...document,
|
|
127
|
-
|
|
128
|
-
|
|
147
|
+
tree: rewriteDocumentLinks(document.tree, basePath, entryPath, document.path, documentPaths),
|
|
148
|
+
gitTree: null,
|
|
129
149
|
backReferences: document.backReferences.map((section) => ({
|
|
130
150
|
...section,
|
|
131
|
-
references: section.references.map((reference) => rewriteBackReference(reference, basePath, sectionPaths, documentPaths)),
|
|
151
|
+
references: section.references.map((reference) => rewriteBackReference(reference, basePath, entryPath, sectionPaths, documentPaths)),
|
|
132
152
|
})),
|
|
133
153
|
};
|
|
134
154
|
}
|
|
135
|
-
function rewriteSourceReference(reference, basePath, sectionPaths, documentPaths) {
|
|
155
|
+
function rewriteSourceReference(reference, basePath, entryPath, sectionPaths, documentPaths) {
|
|
136
156
|
const sectionPath = reference.sectionId.split('#', 1)[0];
|
|
137
157
|
return {
|
|
138
158
|
...reference,
|
|
139
|
-
|
|
140
|
-
url: staticViewUrl(reference.url, basePath),
|
|
159
|
+
paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, entryPath, sectionPaths.get(sectionPath) ?? null, documentPaths),
|
|
160
|
+
url: staticViewUrl(reference.url, basePath, entryPath),
|
|
141
161
|
};
|
|
142
162
|
}
|
|
143
|
-
function rewriteSource(source, basePath, sectionPaths, documentPaths) {
|
|
163
|
+
function rewriteSource(source, basePath, entryPath, sectionPaths, documentPaths) {
|
|
144
164
|
return {
|
|
145
165
|
...source,
|
|
146
166
|
context: source.context
|
|
147
|
-
? rewriteSourceReference(source.context, basePath, sectionPaths, documentPaths)
|
|
167
|
+
? rewriteSourceReference(source.context, basePath, entryPath, sectionPaths, documentPaths)
|
|
148
168
|
: null,
|
|
149
|
-
otherReferences: source.otherReferences.map((reference) => rewriteSourceReference(reference, basePath, sectionPaths, documentPaths)),
|
|
169
|
+
otherReferences: source.otherReferences.map((reference) => rewriteSourceReference(reference, basePath, entryPath, sectionPaths, documentPaths)),
|
|
150
170
|
};
|
|
151
171
|
}
|
|
152
|
-
function rewriteGraph(graph, basePath) {
|
|
172
|
+
function rewriteGraph(graph, basePath, entryPath) {
|
|
153
173
|
return {
|
|
154
174
|
...graph,
|
|
155
175
|
nodes: graph.nodes.map(({ gitStatus: _gitStatus, ...node }) => ({
|
|
156
176
|
...node,
|
|
157
|
-
url: staticViewUrl(node.url, basePath),
|
|
177
|
+
url: staticViewUrl(node.url, basePath, entryPath),
|
|
158
178
|
})),
|
|
159
179
|
};
|
|
160
180
|
}
|
|
@@ -163,8 +183,14 @@ function positiveInteger(value) {
|
|
|
163
183
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
|
|
164
184
|
}
|
|
165
185
|
function sourceRequest(value) {
|
|
166
|
-
|
|
167
|
-
|
|
186
|
+
let url;
|
|
187
|
+
try {
|
|
188
|
+
url = new URL(decodeHtmlUrlAttribute(value), 'http://lat.local');
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
if (url.origin !== 'http://lat.local' || !url.pathname.startsWith('/code/'))
|
|
168
194
|
return null;
|
|
169
195
|
let path;
|
|
170
196
|
let symbol;
|
|
@@ -174,6 +200,14 @@ function sourceRequest(value) {
|
|
|
174
200
|
.split('/')
|
|
175
201
|
.map(decodeURIComponent)
|
|
176
202
|
.join('/');
|
|
203
|
+
if (path.split('/').some((part) => !part || part === '.' || part === '..') ||
|
|
204
|
+
path.includes('\\') ||
|
|
205
|
+
path.includes('\0') ||
|
|
206
|
+
/^[a-z]:/i.test(path))
|
|
207
|
+
return null;
|
|
208
|
+
// Encoded separators cannot create extra route components after decoding.
|
|
209
|
+
if (/%(?:2f|5c)/i.test(url.pathname))
|
|
210
|
+
return null;
|
|
177
211
|
symbol = decodeURIComponent(url.hash.slice(1));
|
|
178
212
|
}
|
|
179
213
|
catch {
|
|
@@ -187,21 +221,104 @@ function sourceRequest(value) {
|
|
|
187
221
|
at: positiveInteger(url.searchParams.get('at')),
|
|
188
222
|
};
|
|
189
223
|
}
|
|
224
|
+
function externalRequest(value, external) {
|
|
225
|
+
let url;
|
|
226
|
+
try {
|
|
227
|
+
url = new URL(decodeHtmlUrlAttribute(value), 'http://lat.local');
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
if (url.origin !== 'http://lat.local' ||
|
|
233
|
+
!url.pathname.startsWith('/external/'))
|
|
234
|
+
return null;
|
|
235
|
+
try {
|
|
236
|
+
const parts = url.pathname
|
|
237
|
+
.slice('/external/'.length)
|
|
238
|
+
.split('/')
|
|
239
|
+
.map(decodeURIComponent);
|
|
240
|
+
const handle = parts.shift() ?? '';
|
|
241
|
+
const path = parts.join('/');
|
|
242
|
+
if (!handle || !path)
|
|
243
|
+
return null;
|
|
244
|
+
const fragment = decodeURIComponent(url.hash.slice(1));
|
|
245
|
+
const target = `${handle}:${path}${fragment ? `#${fragment}` : ''}`;
|
|
246
|
+
const parsed = external?.parse(target);
|
|
247
|
+
if (parsed) {
|
|
248
|
+
if (!isDocumentPath(parsed.resolvedPath)) {
|
|
249
|
+
return parsed.identity;
|
|
250
|
+
}
|
|
251
|
+
const hash = parsed.identity.indexOf('#');
|
|
252
|
+
return hash === -1 ? parsed.identity : parsed.identity.slice(0, hash);
|
|
253
|
+
}
|
|
254
|
+
return `${handle}:${path}${isDocumentPath(path) || !fragment ? '' : `#${fragment}`}`;
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function externalRequestsFromDocument(document, requests, external, externalBase) {
|
|
261
|
+
const add = (value) => {
|
|
262
|
+
let candidate = value;
|
|
263
|
+
if (externalBase && !value.startsWith('#')) {
|
|
264
|
+
try {
|
|
265
|
+
const colon = externalBase.indexOf(':');
|
|
266
|
+
const base = `/external/${encodeURIComponent(externalBase.slice(0, colon))}/${externalBase
|
|
267
|
+
.slice(colon + 1)
|
|
268
|
+
.split('/')
|
|
269
|
+
.map(encodeURIComponent)
|
|
270
|
+
.join('/')}`;
|
|
271
|
+
const resolved = new URL(decodeHtmlUrlAttribute(value), `http://lat.local${base}`);
|
|
272
|
+
if (resolved.origin === 'http://lat.local') {
|
|
273
|
+
candidate = `${resolved.pathname}${resolved.hash}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// Leave malformed links to the renderer rather than exporting them.
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const request = externalRequest(candidate, external);
|
|
281
|
+
if (request)
|
|
282
|
+
requests.add(request);
|
|
283
|
+
};
|
|
284
|
+
for (const value of documentTreeUrls(document.tree))
|
|
285
|
+
add(value);
|
|
286
|
+
for (const section of document.backReferences) {
|
|
287
|
+
for (const reference of section.references) {
|
|
288
|
+
add(reference.url);
|
|
289
|
+
if (reference.kind === 'markdown') {
|
|
290
|
+
for (const value of documentTreeUrls(reference.paragraphTree))
|
|
291
|
+
add(value);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function externalRequestsFromSource(source, requests, external) {
|
|
297
|
+
for (const reference of [
|
|
298
|
+
...(source.context ? [source.context] : []),
|
|
299
|
+
...source.otherReferences,
|
|
300
|
+
]) {
|
|
301
|
+
for (const value of documentTreeUrls(reference.paragraphTree)) {
|
|
302
|
+
const request = externalRequest(value, external);
|
|
303
|
+
if (request)
|
|
304
|
+
requests.add(request);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
190
308
|
function sourceRequestsFromDocument(document, requests) {
|
|
191
309
|
const add = (value) => {
|
|
192
310
|
const request = sourceRequest(value);
|
|
193
311
|
if (request)
|
|
194
312
|
requests.set(viewStaticSourceKey(request), request);
|
|
195
313
|
};
|
|
196
|
-
for (const
|
|
197
|
-
add(
|
|
314
|
+
for (const value of documentTreeUrls(document.tree))
|
|
315
|
+
add(value);
|
|
198
316
|
for (const section of document.backReferences) {
|
|
199
317
|
for (const reference of section.references) {
|
|
200
318
|
add(reference.url);
|
|
201
319
|
if (reference.kind === 'markdown') {
|
|
202
|
-
for (const
|
|
203
|
-
add(
|
|
204
|
-
}
|
|
320
|
+
for (const value of documentTreeUrls(reference.paragraphTree))
|
|
321
|
+
add(value);
|
|
205
322
|
}
|
|
206
323
|
}
|
|
207
324
|
}
|
|
@@ -212,20 +329,33 @@ function sourceRequestsFromSource(source, requests) {
|
|
|
212
329
|
...source.otherReferences,
|
|
213
330
|
];
|
|
214
331
|
for (const reference of references) {
|
|
215
|
-
for (const
|
|
216
|
-
const request = sourceRequest(
|
|
332
|
+
for (const value of documentTreeUrls(reference.paragraphTree)) {
|
|
333
|
+
const request = sourceRequest(value);
|
|
217
334
|
if (request)
|
|
218
335
|
requests.set(viewStaticSourceKey(request), request);
|
|
219
336
|
}
|
|
220
337
|
}
|
|
221
338
|
}
|
|
222
|
-
function
|
|
223
|
-
|
|
339
|
+
function serializeJson(value) {
|
|
340
|
+
return `${JSON.stringify(value)}\n`;
|
|
341
|
+
}
|
|
342
|
+
function dataFile(kind, content) {
|
|
343
|
+
const digest = createHash('sha256')
|
|
344
|
+
.update(content)
|
|
345
|
+
.digest('hex')
|
|
346
|
+
.slice(0, 20);
|
|
224
347
|
return `data/${kind}/${digest}.json`;
|
|
225
348
|
}
|
|
226
349
|
async function writeJson(path, value) {
|
|
227
350
|
await mkdir(dirname(path), { recursive: true });
|
|
228
|
-
await writeFile(path,
|
|
351
|
+
await writeFile(path, serializeJson(value));
|
|
352
|
+
}
|
|
353
|
+
async function writeDataJson(outputDir, kind, value) {
|
|
354
|
+
const content = serializeJson(value);
|
|
355
|
+
const path = dataFile(kind, content);
|
|
356
|
+
await mkdir(dirname(join(outputDir, path)), { recursive: true });
|
|
357
|
+
await writeFile(join(outputDir, path), content);
|
|
358
|
+
return path;
|
|
229
359
|
}
|
|
230
360
|
async function outputExists(path) {
|
|
231
361
|
try {
|
|
@@ -238,16 +368,47 @@ async function outputExists(path) {
|
|
|
238
368
|
throw error;
|
|
239
369
|
}
|
|
240
370
|
}
|
|
241
|
-
|
|
371
|
+
/** Refuse build targets that exist or could replace the project itself. */
|
|
372
|
+
export async function validateViewBuildOutput(outputDir, projectRoot, kind = 'Static', force = false) {
|
|
242
373
|
if (outputDir === parse(outputDir).root ||
|
|
243
374
|
outputDir === projectRoot ||
|
|
244
375
|
isInside(outputDir, projectRoot)) {
|
|
245
|
-
throw new Error(
|
|
376
|
+
throw new Error(`${kind} UI output must not contain the project root`);
|
|
246
377
|
}
|
|
247
|
-
if (await outputExists(outputDir)) {
|
|
248
|
-
throw new Error(
|
|
378
|
+
if (!force && (await outputExists(outputDir))) {
|
|
379
|
+
throw new Error(`${kind} UI output already exists: ${outputDir}. Use --force to replace it.`);
|
|
249
380
|
}
|
|
250
381
|
}
|
|
382
|
+
const defaultViewBuildMoveDependencies = {
|
|
383
|
+
move: rename,
|
|
384
|
+
wait: (milliseconds) => new Promise((resolveWait) => setTimeout(resolveWait, milliseconds)),
|
|
385
|
+
};
|
|
386
|
+
/** Commit a staged build after transient filesystem locks have cleared. */
|
|
387
|
+
export async function moveViewBuildOutput(stagingDir, outputDir, dependencies = defaultViewBuildMoveDependencies) {
|
|
388
|
+
for (let retries = 0;; retries += 1) {
|
|
389
|
+
try {
|
|
390
|
+
await dependencies.move(stagingDir, outputDir);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
const code = error.code;
|
|
395
|
+
if (retries >= VIEW_BUILD_MOVE_MAX_RETRIES ||
|
|
396
|
+
(code !== 'EBUSY' && code !== 'EPERM' && code !== 'ENOTEMPTY')) {
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
await dependencies.wait(VIEW_BUILD_MOVE_RETRY_DELAY_MS);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/** Remove abandoned staging after transient filesystem locks have cleared. */
|
|
404
|
+
export async function removeViewBuildStaging(stagingDir) {
|
|
405
|
+
await rm(stagingDir, {
|
|
406
|
+
recursive: true,
|
|
407
|
+
force: true,
|
|
408
|
+
maxRetries: VIEW_BUILD_MOVE_MAX_RETRIES,
|
|
409
|
+
retryDelay: VIEW_BUILD_MOVE_RETRY_DELAY_MS,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
251
412
|
function sectionDocumentPaths(documents) {
|
|
252
413
|
const result = new Map();
|
|
253
414
|
for (const path of documents.keys()) {
|
|
@@ -255,30 +416,65 @@ function sectionDocumentPaths(documents) {
|
|
|
255
416
|
}
|
|
256
417
|
return result;
|
|
257
418
|
}
|
|
258
|
-
function clientShell(html, basePath) {
|
|
259
|
-
const assets = html
|
|
260
|
-
const configValue = JSON.stringify({ basePath
|
|
261
|
-
const config = `<
|
|
419
|
+
function clientShell(html, basePath, entry, searchApi) {
|
|
420
|
+
const assets = rewriteClientAssetUrls(html, basePath);
|
|
421
|
+
const configValue = encodeURIComponent(JSON.stringify({ basePath, entry, searchApi }));
|
|
422
|
+
const config = `<meta name="lat-static-view" content="${configValue}">`;
|
|
262
423
|
return assets.includes('</head>')
|
|
263
424
|
? assets.replace('</head>', ` ${config}\n </head>`)
|
|
264
425
|
: `${config}\n${assets}`;
|
|
265
426
|
}
|
|
266
|
-
function
|
|
427
|
+
function bootstrapShell(shell, manifest, responses = {}) {
|
|
428
|
+
const bootstrap = { manifest, responses };
|
|
429
|
+
const value = JSON.stringify(bootstrap).replaceAll('<', '\\u003c');
|
|
430
|
+
const data = `<script id="${VIEW_STATIC_BOOTSTRAP_ID}" type="application/json">${value}</script>`;
|
|
431
|
+
return shell.includes('</head>')
|
|
432
|
+
? shell.replace('</head>', ` ${data}\n </head>`)
|
|
433
|
+
: `${data}\n${shell}`;
|
|
434
|
+
}
|
|
435
|
+
const REDIRECT_SCRIPT_PATH = 'data/redirect.js';
|
|
436
|
+
const REDIRECT_SCRIPT = `const meta = document.querySelector('meta[name="lat-redirect"]');
|
|
437
|
+
if (meta) {
|
|
438
|
+
try {
|
|
439
|
+
window.location.replace(decodeURIComponent(meta.content) + window.location.search + window.location.hash);
|
|
440
|
+
} catch {}
|
|
441
|
+
}
|
|
442
|
+
`;
|
|
443
|
+
function redirectShell(target, basePath) {
|
|
267
444
|
const escaped = target.replaceAll('&', '&').replaceAll('"', '"');
|
|
268
|
-
const
|
|
445
|
+
const scriptUrl = `${basePath}${REDIRECT_SCRIPT_PATH}`
|
|
446
|
+
.replaceAll('&', '&')
|
|
447
|
+
.replaceAll('"', '"');
|
|
269
448
|
return `<!doctype html>
|
|
270
449
|
<html lang="en">
|
|
271
450
|
<head>
|
|
272
451
|
<meta charset="UTF-8" />
|
|
273
|
-
<meta
|
|
452
|
+
<meta name="lat-redirect" content="${encodeURIComponent(target)}" />
|
|
274
453
|
<title>lat.md</title>
|
|
454
|
+
<script src="${scriptUrl}" defer></script>
|
|
275
455
|
</head>
|
|
276
|
-
<body><
|
|
456
|
+
<body><a href="${escaped}">Open lat.md</a></body>
|
|
277
457
|
</html>
|
|
278
458
|
`;
|
|
279
459
|
}
|
|
460
|
+
/** All authored route writes must remain strictly below the payload root. */
|
|
461
|
+
function publicationOutputPath(root, ...parts) {
|
|
462
|
+
if (parts.some((part) => part.includes('\\') ||
|
|
463
|
+
part.includes('\0') ||
|
|
464
|
+
part.split('/').some((segment) => segment === '..' || segment === '.')))
|
|
465
|
+
throw new Error('Unsafe export route');
|
|
466
|
+
const path = resolve(root, ...parts);
|
|
467
|
+
const rel = relative(root, path);
|
|
468
|
+
if (!rel ||
|
|
469
|
+
rel.startsWith(`..${sep}`) ||
|
|
470
|
+
rel === '..' ||
|
|
471
|
+
/^[a-z]:/i.test(rel) ||
|
|
472
|
+
rel.startsWith(sep))
|
|
473
|
+
throw new Error('Export route is outside the output directory');
|
|
474
|
+
return path;
|
|
475
|
+
}
|
|
280
476
|
async function writeRouteShell(outputDir, route, shell) {
|
|
281
|
-
const path =
|
|
477
|
+
const path = publicationOutputPath(outputDir, route, 'index.html');
|
|
282
478
|
await mkdir(dirname(path), { recursive: true });
|
|
283
479
|
await writeFile(path, shell);
|
|
284
480
|
}
|
|
@@ -288,27 +484,56 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
|
|
|
288
484
|
const basePath = normalizeStaticViewBasePath(options.basePath ?? '/');
|
|
289
485
|
const clientDir = options.clientDir ?? defaultClientDir;
|
|
290
486
|
const logoText = options.logoText ?? DEFAULT_VIEW_LOGO_TEXT;
|
|
291
|
-
await
|
|
487
|
+
await validateViewBuildOutput(outputDir, ctx.projectRoot, 'Static', options.force);
|
|
292
488
|
await mkdir(dirname(outputDir), { recursive: true });
|
|
293
|
-
const stagingDir = await mkdtemp(join(dirname(outputDir), '.lat-
|
|
294
|
-
|
|
295
|
-
codeExcludePaths: [outputDir],
|
|
296
|
-
git: false,
|
|
297
|
-
watch: false,
|
|
298
|
-
});
|
|
489
|
+
const stagingDir = await mkdtemp(join(dirname(outputDir), '.lat-static-staging-'));
|
|
490
|
+
let store;
|
|
299
491
|
try {
|
|
492
|
+
store = await createViewStore(ctx.latDir, ctx.projectRoot, {
|
|
493
|
+
codeExcludePaths: [outputDir, ...(options.codeExcludePaths ?? [])],
|
|
494
|
+
git: false,
|
|
495
|
+
watch: false,
|
|
496
|
+
externalIgnoreLocal: true,
|
|
497
|
+
externalCa: options.externalCa,
|
|
498
|
+
publishable: await createPublicationPolicy(ctx.projectRoot),
|
|
499
|
+
});
|
|
300
500
|
const clientHtml = await readFile(join(clientDir, 'index.html'), 'utf8');
|
|
301
501
|
const payloadDir = staticViewPayloadDir(stagingDir, basePath);
|
|
302
502
|
await mkdir(payloadDir, { recursive: true });
|
|
303
503
|
await cp(clientDir, payloadDir, { recursive: true });
|
|
304
|
-
const shell = clientShell(clientHtml, basePath);
|
|
305
504
|
const index = { ...store.getIndex(), git: null, logoText };
|
|
505
|
+
validateDocumentRoutes(index.files);
|
|
506
|
+
const shell = clientShell(clientHtml, basePath, index.entry, options.searchApi);
|
|
306
507
|
const documents = new Map();
|
|
508
|
+
const documentResources = new Set();
|
|
307
509
|
const sourceRequests = new Map();
|
|
308
|
-
|
|
510
|
+
const externalRequests = new Set();
|
|
511
|
+
for (const file of index.externalFiles) {
|
|
512
|
+
externalRequests.add(file.target);
|
|
513
|
+
}
|
|
514
|
+
const pendingDocuments = new Set(index.files);
|
|
515
|
+
for (const path of pendingDocuments) {
|
|
309
516
|
const document = await store.getDocument(path);
|
|
310
517
|
documents.set(path, document);
|
|
518
|
+
for (const url of documentTreeUrls(document.tree)) {
|
|
519
|
+
let parsed;
|
|
520
|
+
try {
|
|
521
|
+
parsed = new URL(url, 'http://lat.local');
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
if (parsed.origin !== 'http://lat.local')
|
|
527
|
+
continue;
|
|
528
|
+
const previewPath = documentPath(parsed.pathname);
|
|
529
|
+
if (previewPath?.startsWith('@/'))
|
|
530
|
+
pendingDocuments.add(previewPath);
|
|
531
|
+
const resourcePath = documentResourcePath(parsed.pathname);
|
|
532
|
+
if (resourcePath)
|
|
533
|
+
documentResources.add(resourcePath);
|
|
534
|
+
}
|
|
311
535
|
sourceRequestsFromDocument(document, sourceRequests);
|
|
536
|
+
externalRequestsFromDocument(document, externalRequests, store.snapshot.external);
|
|
312
537
|
}
|
|
313
538
|
const documentPaths = new Set(documents.keys());
|
|
314
539
|
const sectionPaths = sectionDocumentPaths(documents);
|
|
@@ -317,6 +542,37 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
|
|
|
317
542
|
const request = sourceRequest(node.url);
|
|
318
543
|
if (request)
|
|
319
544
|
sourceRequests.set(viewStaticSourceKey(request), request);
|
|
545
|
+
if (node.externalTarget)
|
|
546
|
+
externalRequests.add(node.externalTarget);
|
|
547
|
+
}
|
|
548
|
+
const externals = new Map();
|
|
549
|
+
const pendingExternal = [...externalRequests];
|
|
550
|
+
for (let index = 0; index < pendingExternal.length; index++) {
|
|
551
|
+
const target = pendingExternal[index];
|
|
552
|
+
if (externals.has(target))
|
|
553
|
+
continue;
|
|
554
|
+
let external;
|
|
555
|
+
try {
|
|
556
|
+
external = await store.getExternal(target);
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
throw new Error(`Could not export external source ${target}: ${error.message}`);
|
|
560
|
+
}
|
|
561
|
+
externals.set(target, external);
|
|
562
|
+
const before = externalRequests.size;
|
|
563
|
+
if (external.kind === 'markdown') {
|
|
564
|
+
externalRequestsFromDocument(external.document, externalRequests, store.snapshot.external, external.document.path);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
externalRequestsFromSource(external.source, externalRequests, store.snapshot.external);
|
|
568
|
+
}
|
|
569
|
+
if (externalRequests.size > before) {
|
|
570
|
+
for (const next of externalRequests) {
|
|
571
|
+
if (!externals.has(next) && !pendingExternal.includes(next)) {
|
|
572
|
+
pendingExternal.push(next);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
320
576
|
}
|
|
321
577
|
const sources = new Map();
|
|
322
578
|
const pending = [...sourceRequests.keys()];
|
|
@@ -346,63 +602,146 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
|
|
|
346
602
|
}
|
|
347
603
|
}
|
|
348
604
|
}
|
|
605
|
+
const rewrittenGraph = rewriteGraph(graph, basePath, index.entry);
|
|
349
606
|
const manifest = {
|
|
350
607
|
version: 1,
|
|
351
608
|
index,
|
|
352
|
-
graph: '
|
|
609
|
+
graph: await writeDataJson(payloadDir, 'graphs', rewrittenGraph),
|
|
353
610
|
documents: {},
|
|
354
611
|
sources: {},
|
|
612
|
+
externals: {},
|
|
355
613
|
};
|
|
356
|
-
|
|
614
|
+
const documentBootstraps = new Map();
|
|
357
615
|
for (const [path, document] of documents) {
|
|
358
|
-
const
|
|
359
|
-
manifest.documents[path] =
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
616
|
+
const rewritten = rewriteDocument(document, basePath, index.entry, sectionPaths, documentPaths);
|
|
617
|
+
manifest.documents[path] = await writeDataJson(payloadDir, 'documents', rewritten);
|
|
618
|
+
if (!path.startsWith('@/')) {
|
|
619
|
+
const source = await store.getDocumentSource(path);
|
|
620
|
+
const rawPath = publicationOutputPath(payloadDir, path);
|
|
621
|
+
await mkdir(dirname(rawPath), { recursive: true });
|
|
622
|
+
await writeFile(rawPath, source.content);
|
|
623
|
+
}
|
|
624
|
+
const route = path.startsWith('@/') ? path : path.slice(0, -'.md'.length);
|
|
625
|
+
documentBootstraps.set(route, {
|
|
626
|
+
request: viewStaticDocumentRequest(path),
|
|
627
|
+
document: rewritten,
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
for (const path of [...documentResources].sort()) {
|
|
631
|
+
let content;
|
|
632
|
+
try {
|
|
633
|
+
content = await store.getDocumentResource(path);
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
throw new Error(`Could not export document resource ${path}: ${error.message}`);
|
|
637
|
+
}
|
|
638
|
+
const outputPath = publicationOutputPath(payloadDir, 'resources', path);
|
|
639
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
640
|
+
await writeFile(outputPath, content);
|
|
363
641
|
}
|
|
364
642
|
const sourceFiles = new Map();
|
|
365
643
|
for (const [key, source] of sources) {
|
|
366
|
-
const rewritten = rewriteSource(source, basePath, sectionPaths, documentPaths);
|
|
367
|
-
const { path, content,
|
|
644
|
+
const rewritten = rewriteSource(source, basePath, index.entry, sectionPaths, documentPaths);
|
|
645
|
+
const { path, content, highlightedLines, ...view } = rewritten;
|
|
368
646
|
let fileDataPath = sourceFiles.get(path);
|
|
369
647
|
if (!fileDataPath) {
|
|
370
|
-
fileDataPath =
|
|
371
|
-
sourceFiles.set(path, fileDataPath);
|
|
372
|
-
await writeJson(join(payloadDir, fileDataPath), {
|
|
648
|
+
fileDataPath = await writeDataJson(payloadDir, 'source-files', {
|
|
373
649
|
path,
|
|
374
650
|
content,
|
|
375
|
-
|
|
651
|
+
highlightedLines,
|
|
376
652
|
});
|
|
653
|
+
sourceFiles.set(path, fileDataPath);
|
|
377
654
|
}
|
|
378
|
-
const viewDataPath =
|
|
655
|
+
const viewDataPath = await writeDataJson(payloadDir, 'source-views', view);
|
|
379
656
|
manifest.sources[key] = { file: fileDataPath, view: viewDataPath };
|
|
380
|
-
await writeJson(join(payloadDir, viewDataPath), view);
|
|
381
657
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
658
|
+
const externalSourceFiles = new Map();
|
|
659
|
+
const externalRoutes = new Set();
|
|
660
|
+
for (const [target, external] of externals) {
|
|
661
|
+
if (external.kind === 'markdown') {
|
|
662
|
+
const dataPath = await writeDataJson(payloadDir, 'external-documents', {
|
|
663
|
+
...external,
|
|
664
|
+
document: rewriteDocument(external.document, basePath, index.entry, sectionPaths, documentPaths),
|
|
665
|
+
});
|
|
666
|
+
manifest.externals[target] = { kind: 'markdown', document: dataPath };
|
|
667
|
+
const colon = external.document.path.indexOf(':');
|
|
668
|
+
externalRoutes.add(`external/${external.document.path.slice(0, colon)}/${external.document.path.slice(colon + 1)}`);
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
const rewritten = rewriteSource(external.source, basePath, index.entry, sectionPaths, documentPaths);
|
|
672
|
+
const { path, content, highlightedLines, ...sourceView } = rewritten;
|
|
673
|
+
let fileDataPath = externalSourceFiles.get(path);
|
|
674
|
+
if (!fileDataPath) {
|
|
675
|
+
fileDataPath = await writeDataJson(payloadDir, 'external-source-files', {
|
|
676
|
+
path,
|
|
677
|
+
content,
|
|
678
|
+
highlightedLines,
|
|
679
|
+
});
|
|
680
|
+
externalSourceFiles.set(path, fileDataPath);
|
|
681
|
+
}
|
|
682
|
+
const view = {
|
|
683
|
+
kind: 'source',
|
|
684
|
+
target: external.target,
|
|
685
|
+
source: sourceView,
|
|
686
|
+
};
|
|
687
|
+
const viewDataPath = await writeDataJson(payloadDir, 'external-source-views', view);
|
|
688
|
+
manifest.externals[target] = {
|
|
689
|
+
kind: 'source',
|
|
690
|
+
file: fileDataPath,
|
|
691
|
+
view: viewDataPath,
|
|
692
|
+
};
|
|
693
|
+
const colon = path.indexOf(':');
|
|
694
|
+
externalRoutes.add(`external/${path.slice(0, colon)}/${path.slice(colon + 1)}`);
|
|
385
695
|
}
|
|
386
|
-
await writeRouteShell(payloadDir, 'graph', shell);
|
|
387
696
|
await writeJson(join(payloadDir, 'data/manifest.json'), manifest);
|
|
388
|
-
const
|
|
389
|
-
|
|
697
|
+
const entryRoute = index.entry.slice(0, -'.md'.length);
|
|
698
|
+
const entryBootstrap = documentBootstraps.get(entryRoute);
|
|
699
|
+
if (!entryBootstrap) {
|
|
700
|
+
throw new Error(`Static UI entry document is missing: ${index.entry}`);
|
|
701
|
+
}
|
|
702
|
+
for (const [route, initial] of documentBootstraps) {
|
|
703
|
+
if (route === entryRoute)
|
|
704
|
+
continue;
|
|
705
|
+
await writeRouteShell(payloadDir, route, bootstrapShell(shell, manifest, {
|
|
706
|
+
[initial.request]: initial.document,
|
|
707
|
+
}));
|
|
708
|
+
}
|
|
709
|
+
const genericShell = bootstrapShell(shell, manifest);
|
|
710
|
+
for (const path of sourceFiles.keys()) {
|
|
711
|
+
await writeRouteShell(payloadDir, `code/${path}`, genericShell);
|
|
712
|
+
}
|
|
713
|
+
for (const route of externalRoutes) {
|
|
714
|
+
await writeRouteShell(payloadDir, route, genericShell);
|
|
715
|
+
}
|
|
716
|
+
await writeRouteShell(payloadDir, 'graph', bootstrapShell(shell, manifest, { '/api/graph': rewrittenGraph }));
|
|
717
|
+
if (options.searchApi) {
|
|
718
|
+
await writeRouteShell(payloadDir, 'search', genericShell);
|
|
719
|
+
}
|
|
720
|
+
const redirectScriptPath = join(payloadDir, REDIRECT_SCRIPT_PATH);
|
|
721
|
+
await mkdir(dirname(redirectScriptPath), { recursive: true });
|
|
722
|
+
await writeFile(redirectScriptPath, REDIRECT_SCRIPT);
|
|
723
|
+
await writeFile(join(payloadDir, 'index.html'), bootstrapShell(shell, manifest, {
|
|
724
|
+
[entryBootstrap.request]: entryBootstrap.document,
|
|
725
|
+
}));
|
|
726
|
+
await writeRouteShell(payloadDir, entryRoute, redirectShell(basePath, basePath));
|
|
390
727
|
if (payloadDir !== stagingDir) {
|
|
391
|
-
await writeFile(join(stagingDir, 'index.html'),
|
|
728
|
+
await writeFile(join(stagingDir, 'index.html'), redirectShell(basePath, basePath));
|
|
729
|
+
}
|
|
730
|
+
if (options.force) {
|
|
731
|
+
await rm(outputDir, { recursive: true, force: true });
|
|
392
732
|
}
|
|
393
|
-
await
|
|
394
|
-
await rename(stagingDir, outputDir);
|
|
733
|
+
await moveViewBuildOutput(stagingDir, outputDir);
|
|
395
734
|
return {
|
|
396
735
|
documents: documents.size,
|
|
397
736
|
outputDir,
|
|
398
|
-
sources: sources.size,
|
|
737
|
+
sources: sources.size + externals.size,
|
|
399
738
|
};
|
|
400
739
|
}
|
|
401
740
|
catch (error) {
|
|
402
|
-
await
|
|
741
|
+
await removeViewBuildStaging(stagingDir);
|
|
403
742
|
throw error;
|
|
404
743
|
}
|
|
405
744
|
finally {
|
|
406
|
-
await store
|
|
745
|
+
await store?.close();
|
|
407
746
|
}
|
|
408
747
|
}
|