@plebeiantech/lat.md 0.12.3-fork.15 → 0.12.3-fork.16

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.
Files changed (146) hide show
  1. package/dist/src/cli/checklist-menu.d.ts +2 -1
  2. package/dist/src/cli/checklist-menu.js +3 -2
  3. package/dist/src/cli/index.js +47 -10
  4. package/dist/src/cli/init-preferences.d.ts +4 -0
  5. package/dist/src/cli/init-preferences.js +35 -0
  6. package/dist/src/cli/init.js +7 -1
  7. package/dist/src/cli/search.js +2 -7
  8. package/dist/src/cli/ui-build-server.d.ts +12 -0
  9. package/dist/src/cli/ui-build-server.js +26 -0
  10. package/dist/src/cli/ui-build.js +1 -1
  11. package/dist/src/cli/ui.js +1 -1
  12. package/dist/src/search/query.d.ts +5 -2
  13. package/dist/src/search/query.js +25 -21
  14. package/dist/src/source-formats.d.ts +1 -1
  15. package/dist/src/source-formats.js +2 -0
  16. package/dist/src/source-parser.js +200 -0
  17. package/dist/src/view/client/assets/GraphView-BuZg_wrj.js +456 -0
  18. package/dist/src/view/client/assets/{MarkdownEditor-B7quqPb8.js → MarkdownEditor-BKqJtZYv.js} +8 -8
  19. package/dist/src/view/client/assets/_commonjsHelpers-CqkleIqs.js +1 -0
  20. package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-CAu3KwfO.js +1 -0
  21. package/dist/src/view/client/assets/{arc-BnwR8Bu7.js → arc-CFnPZhKM.js} +1 -1
  22. package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-Cf9Kd0OA.js +36 -0
  23. package/dist/src/view/client/assets/{blockDiagram-I7D4REHJ-DETl8e_H.js → blockDiagram-I7D4REHJ-dPn7g_vm.js} +2 -2
  24. package/dist/src/view/client/assets/{c4Diagram-7LVT6UL2-DJRAT1Ve.js → c4Diagram-7LVT6UL2-DdZrwaPd.js} +2 -2
  25. package/dist/src/view/client/assets/channel-C-byJRR7.js +1 -0
  26. package/dist/src/view/client/assets/{chunk-2Q5K7J3B-C0TmOC1Q.js → chunk-2Q5K7J3B-C42JuteH.js} +1 -1
  27. package/dist/src/view/client/assets/{chunk-5VM5RSS4-dfBOrYE6.js → chunk-5VM5RSS4-BKK3z8Zy.js} +1 -1
  28. package/dist/src/view/client/assets/{chunk-F27PBJKO-DAnks99K.js → chunk-F27PBJKO-qZl_uKcW.js} +1 -1
  29. package/dist/src/view/client/assets/{chunk-IMKFNOWR-CPjB07if.js → chunk-IMKFNOWR-Bs4Rnoj_.js} +1 -1
  30. package/dist/src/view/client/assets/{chunk-JWPE2WC7-VvU_gZI6.js → chunk-JWPE2WC7-BpxgV2rA.js} +1 -1
  31. package/dist/src/view/client/assets/{chunk-POPQ4Y6H-DDUbVF55.js → chunk-POPQ4Y6H-hIynofdE.js} +1 -1
  32. package/dist/src/view/client/assets/{chunk-SVP7TREG-BHROkr6D.js → chunk-SVP7TREG-t3gKMqeu.js} +1 -1
  33. package/dist/src/view/client/assets/{chunk-TICWLB2K-95PzGIOg.js → chunk-TICWLB2K-B2x394mh.js} +1 -1
  34. package/dist/src/view/client/assets/{chunk-XXDRQBXY-MdmuLhIs.js → chunk-XXDRQBXY-CHaVKDsH.js} +1 -1
  35. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-FlqGrEwv.js +1 -0
  36. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-FlqGrEwv.js +1 -0
  37. package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-DE2-Jgqu.js +1 -0
  38. package/dist/src/view/client/assets/{cynefin-OW5HDTMX-CeA8IKWo.js → cynefin-OW5HDTMX-BsEtOvRy.js} +1 -1
  39. package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-BKYG1Xs8.js +62 -0
  40. package/dist/src/view/client/assets/{dagre-GXQ25YYZ-DLQwTa3H.js → dagre-GXQ25YYZ-hgrdNjl7.js} +2 -2
  41. package/dist/src/view/client/assets/{diagram-S7CK7UJ4-kbKdIyXG.js → diagram-S7CK7UJ4-VIx8zAxf.js} +2 -2
  42. package/dist/src/view/client/assets/diagram-UQ7AKVKN-yfloehRm.js +41 -0
  43. package/dist/src/view/client/assets/{diagram-VSXAHHWV-EXJTU8qq.js → diagram-VSXAHHWV-BT_dA4Q9.js} +2 -2
  44. package/dist/src/view/client/assets/diagram-VX7I27RA-Gfmwxx6u.js +24 -0
  45. package/dist/src/view/client/assets/diagram-Z3DM3KII-C2yM7EOo.js +24 -0
  46. package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-Bkb_Lj59.js +1 -0
  47. package/dist/src/view/client/assets/{erDiagram-RLTQ6QDP-C925J5A3.js → erDiagram-RLTQ6QDP-C7wQHPye.js} +2 -2
  48. package/dist/src/view/client/assets/{flowDiagram-HODETNUW-DzoCa-Nq.js → flowDiagram-HODETNUW-CXoKr3oI.js} +1 -1
  49. package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-DqqXKgLa.js +292 -0
  50. package/dist/src/view/client/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  51. package/dist/src/view/client/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  52. package/dist/src/view/client/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  53. package/dist/src/view/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  54. package/dist/src/view/client/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  55. package/dist/src/view/client/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  56. package/dist/src/view/client/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  57. package/dist/src/view/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  58. package/dist/src/view/client/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  59. package/dist/src/view/client/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  60. package/dist/src/view/client/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  61. package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-D_DAhSgZ.js +106 -0
  62. package/dist/src/view/client/assets/index-DAxFk0q-.css +1 -0
  63. package/dist/src/view/client/assets/index-DPuOWFj2.js +10 -0
  64. package/dist/src/view/client/assets/infoDiagram-27XIBGKW-B50EOats.js +2 -0
  65. package/dist/src/view/client/assets/{ishikawaDiagram-5VMMS53U-CW4mto2d.js → ishikawaDiagram-5VMMS53U-D1rny9gj.js} +2 -2
  66. package/dist/src/view/client/assets/{journeyDiagram-3NMN7TZE-8R4eacFW.js → journeyDiagram-3NMN7TZE-B5UD2Xo4.js} +2 -2
  67. package/dist/src/view/client/assets/{kanban-definition-UXKFOSKX-Cy9ioXEJ.js → kanban-definition-UXKFOSKX-CTgey9zw.js} +6 -6
  68. package/dist/src/view/client/assets/{layout-C0MFuhth.js → layout-4X2n4os-.js} +1 -1
  69. package/dist/src/view/client/assets/{linear-Dv3N4dQR.js → linear-D0RIBXsp.js} +1 -1
  70. package/dist/src/view/client/assets/{maplibre-gl-DnqZgfUS.js → maplibre-gl-CDX6Zuow.js} +1 -1
  71. package/dist/src/view/client/assets/{mermaid.core-bds9A7e2.js → mermaid.core-BAnH8y-D.js} +11 -11
  72. package/dist/src/view/client/assets/{mindmap-definition-YA3MSWOX-DjmGW355.js → mindmap-definition-YA3MSWOX-WiFsh3Jg.js} +2 -2
  73. package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-DCJOrckP.js +1 -0
  74. package/dist/src/view/client/assets/{pieDiagram-E7YTZNPT-CCH2gGR-.js → pieDiagram-E7YTZNPT-C78IkUE2.js} +2 -2
  75. package/dist/src/view/client/assets/{quadrantDiagram-AXDQQJYC-CjocPJFz.js → quadrantDiagram-AXDQQJYC-xZ6guleB.js} +4 -4
  76. package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-D3PwmgX0.js +1 -0
  77. package/dist/src/view/client/assets/{requirementDiagram-BXWQKSXE-Ct6AoXRr.js → requirementDiagram-BXWQKSXE-v-I8wLGH.js} +2 -2
  78. package/dist/src/view/client/assets/{sankeyDiagram-P5KCCOFB-CIpgGN_w.js → sankeyDiagram-P5KCCOFB-DBY-sdO7.js} +2 -2
  79. package/dist/src/view/client/assets/{sequenceDiagram-WJ2MYXX4-DrmLFj6w.js → sequenceDiagram-WJ2MYXX4-D9HApBFi.js} +2 -2
  80. package/dist/src/view/client/assets/sizeCapture-INFHLROL-ERAytLnQ.js +1 -0
  81. package/dist/src/view/client/assets/stateDiagram-D77RDMKH-BKef_Qwv.js +1 -0
  82. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-BePfayWI.js +1 -0
  83. package/dist/src/view/client/assets/swimlanes-42K2YHIH-D7dS_tnF.js +1 -0
  84. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-DaqCEguT.js +8 -0
  85. package/dist/src/view/client/assets/{timeline-definition-24CTP7MA-BExPu6X5.js → timeline-definition-24CTP7MA-Di1UCseG.js} +2 -2
  86. package/dist/src/view/client/assets/{vennDiagram-4TSXK5OY-PC1MU3si.js → vennDiagram-4TSXK5OY-g7Je3H2H.js} +2 -2
  87. package/dist/src/view/client/assets/{wardleyDiagram-VM6X3IG4-DNWqU3fa.js → wardleyDiagram-VM6X3IG4-C_diPEka.js} +2 -2
  88. package/dist/src/view/client/assets/{xychartDiagram-S5SC5T6Z-E1uA28_D.js → xychartDiagram-S5SC5T6Z-C8uIQy_I.js} +2 -2
  89. package/dist/src/view/client/index.html +2 -2
  90. package/dist/src/view/document-route.d.ts +2 -0
  91. package/dist/src/view/document-route.js +40 -7
  92. package/dist/src/view/graph.d.ts +2 -2
  93. package/dist/src/view/graph.js +7 -3
  94. package/dist/src/view/highlight.js +205 -203
  95. package/dist/src/view/markdown.js +4 -0
  96. package/dist/src/view/preindexed-search.d.ts +15 -0
  97. package/dist/src/view/preindexed-search.js +25 -0
  98. package/dist/src/view/protocol.d.ts +3 -0
  99. package/dist/src/view/references.js +3 -4
  100. package/dist/src/view/search-result.d.ts +4 -0
  101. package/dist/src/view/search-result.js +20 -0
  102. package/dist/src/view/search.d.ts +7 -2
  103. package/dist/src/view/search.js +23 -30
  104. package/dist/src/view/server-build.d.ts +21 -0
  105. package/dist/src/view/server-build.js +145 -0
  106. package/dist/src/view/server-deployment.d.ts +32 -0
  107. package/dist/src/view/server-deployment.js +133 -0
  108. package/dist/src/view/server-index-worker.d.ts +6 -0
  109. package/dist/src/view/server-index-worker.js +14 -0
  110. package/dist/src/view/server.js +25 -7
  111. package/dist/src/view/static-build.d.ts +16 -1
  112. package/dist/src/view/static-build.js +187 -89
  113. package/dist/src/view/static-protocol.d.ts +7 -0
  114. package/dist/src/view/static-protocol.js +5 -0
  115. package/dist/src/view/store.js +14 -4
  116. package/dist/src/view/vercel-build.d.ts +24 -0
  117. package/dist/src/view/vercel-build.js +133 -0
  118. package/dist/src/view/vercel-server-build.d.ts +10 -0
  119. package/dist/src/view/vercel-server-build.js +61 -0
  120. package/dist/vendor/lat.md-server/index.d.ts +1 -1
  121. package/dist/vendor/lat.md-server/index.js +1 -1
  122. package/package.json +16 -4
  123. package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-V7-T6qsl.js +0 -1
  124. package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-u97vDna9.js +0 -36
  125. package/dist/src/view/client/assets/channel-BwQbnWCN.js +0 -1
  126. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-HvQKkIS-.js +0 -1
  127. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-HvQKkIS-.js +0 -1
  128. package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-CauUf_rN.js +0 -1
  129. package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-L1rtcT8l.js +0 -62
  130. package/dist/src/view/client/assets/diagram-UQ7AKVKN-kmzp92RC.js +0 -41
  131. package/dist/src/view/client/assets/diagram-VX7I27RA-DAiIyMCG.js +0 -24
  132. package/dist/src/view/client/assets/diagram-Z3DM3KII-G9wz50ZV.js +0 -24
  133. package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-D2tVRCNA.js +0 -1
  134. package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-D2ebbg4p.js +0 -292
  135. package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-B4QratYy.js +0 -106
  136. package/dist/src/view/client/assets/index-D0ajr_Ja.css +0 -1
  137. package/dist/src/view/client/assets/index-KZcnpXJH.js +0 -321
  138. package/dist/src/view/client/assets/infoDiagram-27XIBGKW-DL4mtHkt.js +0 -2
  139. package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-BWsZp0ab.js +0 -1
  140. package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-BjLeb2KF.js +0 -1
  141. package/dist/src/view/client/assets/sizeCapture-INFHLROL-BdFMe2Lr.js +0 -1
  142. package/dist/src/view/client/assets/stateDiagram-D77RDMKH-Zd9F1goW.js +0 -1
  143. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-ByIKCftl.js +0 -1
  144. package/dist/src/view/client/assets/swimlanes-42K2YHIH-a7VFwi00.js +0 -1
  145. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-CzxaUHB-.js +0 -8
  146. /package/dist/src/view/client/assets/{logo-small-RR_KBOAT.svg → logo-RR_KBOAT.svg} +0 -0
@@ -1,9 +1,13 @@
1
+ import { rename } from 'node:fs/promises';
1
2
  import type { CmdContext } from '../context.js';
2
3
  export type StaticViewBuildOptions = {
3
4
  basePath?: string;
4
5
  clientDir?: string;
6
+ codeExcludePaths?: string[];
7
+ force?: boolean;
5
8
  logoText?: string;
6
9
  externalCa?: string | Buffer;
10
+ searchApi?: string;
7
11
  };
8
12
  export type StaticViewBuildResult = {
9
13
  documents: number;
@@ -12,6 +16,17 @@ export type StaticViewBuildResult = {
12
16
  };
13
17
  export declare function normalizeStaticViewBasePath(value: string): string;
14
18
  /** Convert a live view route to its physical static-directory URL. */
15
- 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>;
16
30
  /** Build a serverless snapshot of the current read-only Lat UI. */
17
31
  export declare function buildStaticView(ctx: CmdContext, requestedOutput: string, options?: StaticViewBuildOptions): Promise<StaticViewBuildResult>;
32
+ export {};
@@ -5,21 +5,24 @@ import { fileURLToPath } from 'node:url';
5
5
  import { isDocumentPath } from '../document-formats.js';
6
6
  import { DEFAULT_VIEW_LOGO_TEXT } from './protocol.js';
7
7
  import { documentTreeUrls, rewriteDocumentTreeUrls } from './document-tree.js';
8
- import { viewStaticSourceKey, } from './static-protocol.js';
8
+ import { VIEW_STATIC_BOOTSTRAP_ID, viewStaticDocumentRequest, viewStaticSourceKey, } from './static-protocol.js';
9
9
  import { createViewStore } from './store.js';
10
10
  import { rewriteClientAssetUrls } from './client-shell.js';
11
- import { documentResourcePath, documentPath, documentUrl, rawDocumentPath, } from './document-route.js';
11
+ import { documentResourcePath, documentPath, documentUrl, rawDocumentPath, validateDocumentRoutes, } from './document-route.js';
12
12
  const defaultClientDir = fileURLToPath(new URL('./client/', import.meta.url));
13
+ const VIEW_BUILD_MOVE_MAX_RETRIES = 10;
14
+ const VIEW_BUILD_MOVE_RETRY_DELAY_MS = 150;
13
15
  function isInside(parent, child) {
14
16
  const rel = relative(parent, child);
15
17
  return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`));
16
18
  }
17
19
  export function normalizeStaticViewBasePath(value) {
18
- const parsed = new URL(value || '/', 'http://lat.local');
20
+ const path = value.startsWith('/') ? value : `/${value}`;
21
+ const parsed = new URL(path, 'http://lat.local');
19
22
  if (parsed.origin !== 'http://lat.local' ||
20
23
  parsed.search ||
21
24
  parsed.hash ||
22
- !value.startsWith('/')) {
25
+ value.includes('://')) {
23
26
  throw new Error('Static UI base path must be an absolute URL path');
24
27
  }
25
28
  return parsed.pathname.endsWith('/')
@@ -47,8 +50,8 @@ function decodeHtmlUrlAttribute(value) {
47
50
  return value.replace(/&(amp|#38|#x26);/gi, '&');
48
51
  }
49
52
  /** Convert a live view route to its physical static-directory URL. */
50
- export function staticViewUrl(value, basePath) {
51
- if (!value || value.startsWith('#'))
53
+ export function staticViewUrl(value, basePath, entryPath) {
54
+ if (!value || !value.startsWith('/') || value.startsWith('//'))
52
55
  return value;
53
56
  let url;
54
57
  try {
@@ -59,9 +62,13 @@ export function staticViewUrl(value, basePath) {
59
62
  }
60
63
  if (url.origin !== 'http://lat.local')
61
64
  return value;
62
- if (url.pathname.startsWith('/docs/')) {
65
+ const markdownPath = documentPath(url.pathname.replace(/\/$/, ''));
66
+ if (markdownPath || rawDocumentPath(url.pathname)) {
63
67
  const route = url.pathname.slice(1).replace(/\/+$/, '');
64
68
  const suffix = `${url.search}${url.hash}`;
69
+ if (entryPath && markdownPath === entryPath) {
70
+ return `${basePath}${suffix}`;
71
+ }
65
72
  return `${basePath}${route}${suffix}`;
66
73
  }
67
74
  if (url.pathname.startsWith('/resources/')) {
@@ -77,13 +84,16 @@ export function staticViewUrl(value, basePath) {
77
84
  if (url.pathname === '/graph') {
78
85
  return `${basePath}graph/${url.search}${url.hash}`;
79
86
  }
87
+ if (url.pathname === '/' || url.pathname === '/search') {
88
+ return `${basePath}${url.pathname.slice(1)}${url.search}${url.hash}`;
89
+ }
80
90
  return value;
81
91
  }
82
92
  function documentPathFromUrl(value) {
83
93
  return documentPath(value.pathname) ?? rawDocumentPath(value.pathname);
84
94
  }
85
- function rewriteHtmlLink(value, basePath, sourcePath, documentPaths) {
86
- const direct = staticViewUrl(value, basePath);
95
+ function rewriteHtmlLink(value, basePath, entryPath, sourcePath, documentPaths) {
96
+ const direct = staticViewUrl(value, basePath, entryPath);
87
97
  if (direct !== value || !sourcePath || value.startsWith('#'))
88
98
  return direct;
89
99
  let resolved;
@@ -103,64 +113,67 @@ function rewriteHtmlLink(value, basePath, sourcePath, documentPaths) {
103
113
  }
104
114
  const documentPath = documentPathFromUrl(resolved);
105
115
  if (resolved.pathname.startsWith('/external/')) {
106
- return staticViewUrl(`${resolved.pathname}${resolved.search}${resolved.hash}`, basePath);
116
+ return staticViewUrl(`${resolved.pathname}${resolved.search}${resolved.hash}`, basePath, entryPath);
107
117
  }
108
118
  if (resolved.origin !== 'http://lat.local' ||
109
119
  !documentPath ||
110
120
  !documentPaths.has(documentPath)) {
111
121
  return value;
112
122
  }
113
- return staticViewUrl(`${documentUrl(documentPath)}${resolved.search}${resolved.hash}`, basePath);
123
+ return staticViewUrl(`${documentUrl(documentPath)}${resolved.search}${resolved.hash}`, basePath, entryPath);
114
124
  }
115
- function rewriteDocumentLinks(tree, basePath, sourcePath, documentPaths) {
116
- return rewriteDocumentTreeUrls(tree, (value) => rewriteHtmlLink(value, basePath, sourcePath, documentPaths));
125
+ function rewriteDocumentLinks(tree, basePath, entryPath, sourcePath, documentPaths) {
126
+ return rewriteDocumentTreeUrls(tree, (value) => rewriteHtmlLink(value, basePath, entryPath, sourcePath, documentPaths));
117
127
  }
118
- function rewriteMarkdownReference(reference, basePath, sourcePath, documentPaths) {
128
+ function rewriteMarkdownReference(reference, basePath, entryPath, sourcePath, documentPaths) {
119
129
  return {
120
130
  ...reference,
121
- paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, sourcePath, documentPaths),
122
- url: staticViewUrl(reference.url, basePath),
131
+ paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, entryPath, sourcePath, documentPaths),
132
+ url: staticViewUrl(reference.url, basePath, entryPath),
123
133
  };
124
134
  }
125
- function rewriteBackReference(reference, basePath, sectionPaths, documentPaths) {
135
+ function rewriteBackReference(reference, basePath, entryPath, sectionPaths, documentPaths) {
126
136
  return reference.kind === 'markdown'
127
- ? rewriteMarkdownReference(reference, basePath, sectionPaths.get(reference.sectionId.split('#', 1)[0]) ?? null, documentPaths)
128
- : { ...reference, url: staticViewUrl(reference.url, basePath) };
137
+ ? rewriteMarkdownReference(reference, basePath, entryPath, sectionPaths.get(reference.sectionId.split('#', 1)[0]) ?? null, documentPaths)
138
+ : {
139
+ ...reference,
140
+ url: staticViewUrl(reference.url, basePath, entryPath),
141
+ };
129
142
  }
130
- function rewriteDocument(document, basePath, sectionPaths, documentPaths) {
143
+ function rewriteDocument(document, basePath, entryPath, sectionPaths, documentPaths) {
131
144
  return {
132
145
  ...document,
133
- tree: rewriteDocumentLinks(document.tree, basePath, document.path, documentPaths),
146
+ tree: rewriteDocumentLinks(document.tree, basePath, entryPath, document.path, documentPaths),
134
147
  gitTree: null,
135
148
  backReferences: document.backReferences.map((section) => ({
136
149
  ...section,
137
- references: section.references.map((reference) => rewriteBackReference(reference, basePath, sectionPaths, documentPaths)),
150
+ references: section.references.map((reference) => rewriteBackReference(reference, basePath, entryPath, sectionPaths, documentPaths)),
138
151
  })),
139
152
  };
140
153
  }
141
- function rewriteSourceReference(reference, basePath, sectionPaths, documentPaths) {
154
+ function rewriteSourceReference(reference, basePath, entryPath, sectionPaths, documentPaths) {
142
155
  const sectionPath = reference.sectionId.split('#', 1)[0];
143
156
  return {
144
157
  ...reference,
145
- paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, sectionPaths.get(sectionPath) ?? null, documentPaths),
146
- url: staticViewUrl(reference.url, basePath),
158
+ paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, entryPath, sectionPaths.get(sectionPath) ?? null, documentPaths),
159
+ url: staticViewUrl(reference.url, basePath, entryPath),
147
160
  };
148
161
  }
149
- function rewriteSource(source, basePath, sectionPaths, documentPaths) {
162
+ function rewriteSource(source, basePath, entryPath, sectionPaths, documentPaths) {
150
163
  return {
151
164
  ...source,
152
165
  context: source.context
153
- ? rewriteSourceReference(source.context, basePath, sectionPaths, documentPaths)
166
+ ? rewriteSourceReference(source.context, basePath, entryPath, sectionPaths, documentPaths)
154
167
  : null,
155
- otherReferences: source.otherReferences.map((reference) => rewriteSourceReference(reference, basePath, sectionPaths, documentPaths)),
168
+ otherReferences: source.otherReferences.map((reference) => rewriteSourceReference(reference, basePath, entryPath, sectionPaths, documentPaths)),
156
169
  };
157
170
  }
158
- function rewriteGraph(graph, basePath) {
171
+ function rewriteGraph(graph, basePath, entryPath) {
159
172
  return {
160
173
  ...graph,
161
174
  nodes: graph.nodes.map(({ gitStatus: _gitStatus, ...node }) => ({
162
175
  ...node,
163
- url: staticViewUrl(node.url, basePath),
176
+ url: staticViewUrl(node.url, basePath, entryPath),
164
177
  })),
165
178
  };
166
179
  }
@@ -307,13 +320,26 @@ function sourceRequestsFromSource(source, requests) {
307
320
  }
308
321
  }
309
322
  }
310
- function dataFile(kind, key) {
311
- const digest = createHash('sha256').update(key).digest('hex').slice(0, 20);
323
+ function serializeJson(value) {
324
+ return `${JSON.stringify(value)}\n`;
325
+ }
326
+ function dataFile(kind, content) {
327
+ const digest = createHash('sha256')
328
+ .update(content)
329
+ .digest('hex')
330
+ .slice(0, 20);
312
331
  return `data/${kind}/${digest}.json`;
313
332
  }
314
333
  async function writeJson(path, value) {
315
334
  await mkdir(dirname(path), { recursive: true });
316
- await writeFile(path, `${JSON.stringify(value)}\n`);
335
+ await writeFile(path, serializeJson(value));
336
+ }
337
+ async function writeDataJson(outputDir, kind, value) {
338
+ const content = serializeJson(value);
339
+ const path = dataFile(kind, content);
340
+ await mkdir(dirname(join(outputDir, path)), { recursive: true });
341
+ await writeFile(join(outputDir, path), content);
342
+ return path;
317
343
  }
318
344
  async function outputExists(path) {
319
345
  try {
@@ -326,16 +352,47 @@ async function outputExists(path) {
326
352
  throw error;
327
353
  }
328
354
  }
329
- async function validateOutput(outputDir, projectRoot) {
355
+ /** Refuse build targets that exist or could replace the project itself. */
356
+ export async function validateViewBuildOutput(outputDir, projectRoot, kind = 'Static', force = false) {
330
357
  if (outputDir === parse(outputDir).root ||
331
358
  outputDir === projectRoot ||
332
359
  isInside(outputDir, projectRoot)) {
333
- throw new Error('Static UI output must not contain the project root');
360
+ throw new Error(`${kind} UI output must not contain the project root`);
334
361
  }
335
- if (await outputExists(outputDir)) {
336
- throw new Error(`Static UI output already exists: ${outputDir}`);
362
+ if (!force && (await outputExists(outputDir))) {
363
+ throw new Error(`${kind} UI output already exists: ${outputDir}. Use --force to replace it.`);
337
364
  }
338
365
  }
366
+ const defaultViewBuildMoveDependencies = {
367
+ move: rename,
368
+ wait: (milliseconds) => new Promise((resolveWait) => setTimeout(resolveWait, milliseconds)),
369
+ };
370
+ /** Commit a staged build after transient filesystem locks have cleared. */
371
+ export async function moveViewBuildOutput(stagingDir, outputDir, dependencies = defaultViewBuildMoveDependencies) {
372
+ for (let retries = 0;; retries += 1) {
373
+ try {
374
+ await dependencies.move(stagingDir, outputDir);
375
+ return;
376
+ }
377
+ catch (error) {
378
+ const code = error.code;
379
+ if (retries >= VIEW_BUILD_MOVE_MAX_RETRIES ||
380
+ (code !== 'EBUSY' && code !== 'EPERM' && code !== 'ENOTEMPTY')) {
381
+ throw error;
382
+ }
383
+ await dependencies.wait(VIEW_BUILD_MOVE_RETRY_DELAY_MS);
384
+ }
385
+ }
386
+ }
387
+ /** Remove abandoned staging after transient filesystem locks have cleared. */
388
+ export async function removeViewBuildStaging(stagingDir) {
389
+ await rm(stagingDir, {
390
+ recursive: true,
391
+ force: true,
392
+ maxRetries: VIEW_BUILD_MOVE_MAX_RETRIES,
393
+ retryDelay: VIEW_BUILD_MOVE_RETRY_DELAY_MS,
394
+ });
395
+ }
339
396
  function sectionDocumentPaths(documents) {
340
397
  const result = new Map();
341
398
  for (const path of documents.keys()) {
@@ -343,25 +400,44 @@ function sectionDocumentPaths(documents) {
343
400
  }
344
401
  return result;
345
402
  }
346
- function clientShell(html, basePath) {
403
+ function clientShell(html, basePath, entry, searchApi) {
347
404
  const assets = rewriteClientAssetUrls(html, basePath);
348
- const configValue = JSON.stringify({ basePath }).replaceAll('<', '\\u003c');
349
- const config = `<script>globalThis.__LAT_STATIC_VIEW__=${configValue}</script>`;
405
+ const configValue = encodeURIComponent(JSON.stringify({ basePath, entry, searchApi }));
406
+ const config = `<meta name="lat-static-view" content="${configValue}">`;
350
407
  return assets.includes('</head>')
351
408
  ? assets.replace('</head>', ` ${config}\n </head>`)
352
409
  : `${config}\n${assets}`;
353
410
  }
354
- function redirectShell(target) {
411
+ function bootstrapShell(shell, manifest, responses = {}) {
412
+ const bootstrap = { manifest, responses };
413
+ const value = JSON.stringify(bootstrap).replaceAll('<', '\\u003c');
414
+ const data = `<script id="${VIEW_STATIC_BOOTSTRAP_ID}" type="application/json">${value}</script>`;
415
+ return shell.includes('</head>')
416
+ ? shell.replace('</head>', ` ${data}\n </head>`)
417
+ : `${data}\n${shell}`;
418
+ }
419
+ const REDIRECT_SCRIPT_PATH = 'data/redirect.js';
420
+ const REDIRECT_SCRIPT = `const meta = document.querySelector('meta[name="lat-redirect"]');
421
+ if (meta) {
422
+ try {
423
+ window.location.replace(decodeURIComponent(meta.content) + window.location.search + window.location.hash);
424
+ } catch {}
425
+ }
426
+ `;
427
+ function redirectShell(target, basePath) {
355
428
  const escaped = target.replaceAll('&', '&amp;').replaceAll('"', '&quot;');
356
- const scriptTarget = JSON.stringify(target).replaceAll('<', '\\u003c');
429
+ const scriptUrl = `${basePath}${REDIRECT_SCRIPT_PATH}`
430
+ .replaceAll('&', '&amp;')
431
+ .replaceAll('"', '&quot;');
357
432
  return `<!doctype html>
358
433
  <html lang="en">
359
434
  <head>
360
435
  <meta charset="UTF-8" />
361
- <meta http-equiv="refresh" content="0;url=${escaped}" />
436
+ <meta name="lat-redirect" content="${encodeURIComponent(target)}" />
362
437
  <title>lat.md</title>
438
+ <script src="${scriptUrl}" defer></script>
363
439
  </head>
364
- <body><script>window.location.replace(${scriptTarget} + window.location.hash)</script></body>
440
+ <body><a href="${escaped}">Open lat.md</a></body>
365
441
  </html>
366
442
  `;
367
443
  }
@@ -376,11 +452,11 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
376
452
  const basePath = normalizeStaticViewBasePath(options.basePath ?? '/');
377
453
  const clientDir = options.clientDir ?? defaultClientDir;
378
454
  const logoText = options.logoText ?? DEFAULT_VIEW_LOGO_TEXT;
379
- await validateOutput(outputDir, ctx.projectRoot);
455
+ await validateViewBuildOutput(outputDir, ctx.projectRoot, 'Static', options.force);
380
456
  await mkdir(dirname(outputDir), { recursive: true });
381
- const stagingDir = await mkdtemp(join(dirname(outputDir), '.lat-ui-build-'));
457
+ const stagingDir = await mkdtemp(join(dirname(outputDir), '.lat-static-staging-'));
382
458
  const store = await createViewStore(ctx.latDir, ctx.projectRoot, {
383
- codeExcludePaths: [outputDir],
459
+ codeExcludePaths: [outputDir, ...(options.codeExcludePaths ?? [])],
384
460
  git: false,
385
461
  watch: false,
386
462
  externalIgnoreLocal: true,
@@ -391,8 +467,9 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
391
467
  const payloadDir = staticViewPayloadDir(stagingDir, basePath);
392
468
  await mkdir(payloadDir, { recursive: true });
393
469
  await cp(clientDir, payloadDir, { recursive: true });
394
- const shell = clientShell(clientHtml, basePath);
395
470
  const index = { ...store.getIndex(), git: null, logoText };
471
+ validateDocumentRoutes(index.files);
472
+ const shell = clientShell(clientHtml, basePath, index.entry, options.searchApi);
396
473
  const documents = new Map();
397
474
  const documentResources = new Set();
398
475
  const sourceRequests = new Map();
@@ -489,25 +566,28 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
489
566
  }
490
567
  }
491
568
  }
569
+ const rewrittenGraph = rewriteGraph(graph, basePath, index.entry);
492
570
  const manifest = {
493
571
  version: 1,
494
572
  index,
495
- graph: 'data/graph.json',
573
+ graph: await writeDataJson(payloadDir, 'graphs', rewrittenGraph),
496
574
  documents: {},
497
575
  sources: {},
498
576
  externals: {},
499
577
  };
500
- await writeJson(join(payloadDir, manifest.graph), rewriteGraph(graph, basePath));
578
+ const documentBootstraps = new Map();
501
579
  for (const [path, document] of documents) {
502
- const dataPath = dataFile('documents', path);
503
- manifest.documents[path] = dataPath;
504
- await writeJson(join(payloadDir, dataPath), rewriteDocument(document, basePath, sectionPaths, documentPaths));
580
+ const rewritten = rewriteDocument(document, basePath, index.entry, sectionPaths, documentPaths);
581
+ manifest.documents[path] = await writeDataJson(payloadDir, 'documents', rewritten);
505
582
  const source = await store.getDocumentSource(path);
506
- const rawPath = join(payloadDir, 'docs', ...path.split('/'));
583
+ const rawPath = join(payloadDir, ...path.split('/'));
507
584
  await mkdir(dirname(rawPath), { recursive: true });
508
585
  await writeFile(rawPath, source.content);
509
- const route = `docs/${path.slice(0, -'.md'.length)}`;
510
- await writeRouteShell(payloadDir, route, shell);
586
+ const route = path.slice(0, -'.md'.length);
587
+ documentBootstraps.set(route, {
588
+ request: viewStaticDocumentRequest(path),
589
+ document: rewritten,
590
+ });
511
591
  }
512
592
  for (const path of [...documentResources].sort()) {
513
593
  let content;
@@ -523,78 +603,96 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
523
603
  }
524
604
  const sourceFiles = new Map();
525
605
  for (const [key, source] of sources) {
526
- const rewritten = rewriteSource(source, basePath, sectionPaths, documentPaths);
606
+ const rewritten = rewriteSource(source, basePath, index.entry, sectionPaths, documentPaths);
527
607
  const { path, content, highlightedLines, ...view } = rewritten;
528
608
  let fileDataPath = sourceFiles.get(path);
529
609
  if (!fileDataPath) {
530
- fileDataPath = dataFile('source-files', path);
531
- sourceFiles.set(path, fileDataPath);
532
- await writeJson(join(payloadDir, fileDataPath), {
610
+ fileDataPath = await writeDataJson(payloadDir, 'source-files', {
533
611
  path,
534
612
  content,
535
613
  highlightedLines,
536
614
  });
615
+ sourceFiles.set(path, fileDataPath);
537
616
  }
538
- const viewDataPath = dataFile('source-views', key);
617
+ const viewDataPath = await writeDataJson(payloadDir, 'source-views', view);
539
618
  manifest.sources[key] = { file: fileDataPath, view: viewDataPath };
540
- await writeJson(join(payloadDir, viewDataPath), view);
541
- }
542
- for (const path of sourceFiles.keys()) {
543
- const route = `code/${path}`;
544
- await writeRouteShell(payloadDir, route, shell);
545
619
  }
546
620
  const externalSourceFiles = new Map();
547
621
  const externalRoutes = new Set();
548
622
  for (const [target, external] of externals) {
549
623
  if (external.kind === 'markdown') {
550
- const dataPath = dataFile('external-documents', target);
551
- manifest.externals[target] = { kind: 'markdown', document: dataPath };
552
- await writeJson(join(payloadDir, dataPath), {
624
+ const dataPath = await writeDataJson(payloadDir, 'external-documents', {
553
625
  ...external,
554
- document: rewriteDocument(external.document, basePath, sectionPaths, documentPaths),
626
+ document: rewriteDocument(external.document, basePath, index.entry, sectionPaths, documentPaths),
555
627
  });
628
+ manifest.externals[target] = { kind: 'markdown', document: dataPath };
556
629
  const colon = external.document.path.indexOf(':');
557
630
  externalRoutes.add(`external/${external.document.path.slice(0, colon)}/${external.document.path.slice(colon + 1)}`);
558
631
  continue;
559
632
  }
560
- const rewritten = rewriteSource(external.source, basePath, sectionPaths, documentPaths);
633
+ const rewritten = rewriteSource(external.source, basePath, index.entry, sectionPaths, documentPaths);
561
634
  const { path, content, highlightedLines, ...sourceView } = rewritten;
562
635
  let fileDataPath = externalSourceFiles.get(path);
563
636
  if (!fileDataPath) {
564
- fileDataPath = dataFile('external-source-files', path);
565
- externalSourceFiles.set(path, fileDataPath);
566
- await writeJson(join(payloadDir, fileDataPath), {
637
+ fileDataPath = await writeDataJson(payloadDir, 'external-source-files', {
567
638
  path,
568
639
  content,
569
640
  highlightedLines,
570
641
  });
642
+ externalSourceFiles.set(path, fileDataPath);
571
643
  }
572
- const viewDataPath = dataFile('external-source-views', target);
573
- manifest.externals[target] = {
574
- kind: 'source',
575
- file: fileDataPath,
576
- view: viewDataPath,
577
- };
578
644
  const view = {
579
645
  kind: 'source',
580
646
  target: external.target,
581
647
  source: sourceView,
582
648
  };
583
- await writeJson(join(payloadDir, viewDataPath), view);
649
+ const viewDataPath = await writeDataJson(payloadDir, 'external-source-views', view);
650
+ manifest.externals[target] = {
651
+ kind: 'source',
652
+ file: fileDataPath,
653
+ view: viewDataPath,
654
+ };
584
655
  const colon = path.indexOf(':');
585
656
  externalRoutes.add(`external/${path.slice(0, colon)}/${path.slice(colon + 1)}`);
586
657
  }
658
+ await writeJson(join(payloadDir, 'data/manifest.json'), manifest);
659
+ const entryRoute = index.entry.slice(0, -'.md'.length);
660
+ const entryBootstrap = documentBootstraps.get(entryRoute);
661
+ if (!entryBootstrap) {
662
+ throw new Error(`Static UI entry document is missing: ${index.entry}`);
663
+ }
664
+ for (const [route, initial] of documentBootstraps) {
665
+ if (route === entryRoute)
666
+ continue;
667
+ await writeRouteShell(payloadDir, route, bootstrapShell(shell, manifest, {
668
+ [initial.request]: initial.document,
669
+ }));
670
+ }
671
+ const genericShell = bootstrapShell(shell, manifest);
672
+ for (const path of sourceFiles.keys()) {
673
+ await writeRouteShell(payloadDir, `code/${path}`, genericShell);
674
+ }
587
675
  for (const route of externalRoutes) {
588
- await writeRouteShell(payloadDir, route, shell);
676
+ await writeRouteShell(payloadDir, route, genericShell);
589
677
  }
590
- await writeRouteShell(payloadDir, 'graph', shell);
591
- await writeJson(join(payloadDir, 'data/manifest.json'), manifest);
592
- const entryRedirect = redirectShell(staticViewUrl(documentUrl(index.entry), basePath));
593
- await writeFile(join(payloadDir, 'index.html'), entryRedirect);
678
+ await writeRouteShell(payloadDir, 'graph', bootstrapShell(shell, manifest, { '/api/graph': rewrittenGraph }));
679
+ if (options.searchApi) {
680
+ await writeRouteShell(payloadDir, 'search', genericShell);
681
+ }
682
+ const redirectScriptPath = join(payloadDir, REDIRECT_SCRIPT_PATH);
683
+ await mkdir(dirname(redirectScriptPath), { recursive: true });
684
+ await writeFile(redirectScriptPath, REDIRECT_SCRIPT);
685
+ await writeFile(join(payloadDir, 'index.html'), bootstrapShell(shell, manifest, {
686
+ [entryBootstrap.request]: entryBootstrap.document,
687
+ }));
688
+ await writeRouteShell(payloadDir, entryRoute, redirectShell(basePath, basePath));
594
689
  if (payloadDir !== stagingDir) {
595
- await writeFile(join(stagingDir, 'index.html'), entryRedirect);
690
+ await writeFile(join(stagingDir, 'index.html'), redirectShell(basePath, basePath));
691
+ }
692
+ if (options.force) {
693
+ await rm(outputDir, { recursive: true, force: true });
596
694
  }
597
- await rename(stagingDir, outputDir);
695
+ await moveViewBuildOutput(stagingDir, outputDir);
598
696
  return {
599
697
  documents: documents.size,
600
698
  outputDir,
@@ -602,7 +700,7 @@ export async function buildStaticView(ctx, requestedOutput, options = {}) {
602
700
  };
603
701
  }
604
702
  catch (error) {
605
- await rm(stagingDir, { recursive: true, force: true });
703
+ await removeViewBuildStaging(stagingDir);
606
704
  throw error;
607
705
  }
608
706
  finally {
@@ -36,5 +36,12 @@ export type ViewStaticManifest = {
36
36
  sources: Record<string, ViewStaticSourceEntry>;
37
37
  externals: Record<string, ViewStaticExternalEntry>;
38
38
  };
39
+ export type ViewStaticBootstrap = {
40
+ manifest: ViewStaticManifest;
41
+ responses: Record<string, object>;
42
+ };
43
+ export declare const VIEW_STATIC_BOOTSTRAP_ID = "lat-static-bootstrap";
44
+ /** Match the live document endpoint key used by the static browser adapter. */
45
+ export declare function viewStaticDocumentRequest(path: string): string;
39
46
  /** Stable lookup key shared by the static exporter and browser adapter. */
40
47
  export declare function viewStaticSourceKey(request: ViewStaticSourceRequest): string;
@@ -1,3 +1,8 @@
1
+ export const VIEW_STATIC_BOOTSTRAP_ID = 'lat-static-bootstrap';
2
+ /** Match the live document endpoint key used by the static browser adapter. */
3
+ export function viewStaticDocumentRequest(path) {
4
+ return `/api/document?path=${encodeURIComponent(path)}`;
5
+ }
1
6
  /** Stable lookup key shared by the static exporter and browser adapter. */
2
7
  export function viewStaticSourceKey(request) {
3
8
  return JSON.stringify([
@@ -99,8 +99,8 @@ async function scanCodeState(projectRoot, excludedPaths = []) {
99
99
  scope,
100
100
  };
101
101
  }
102
- function viewIndex(latDir, paths, diagnostics, git, references, external) {
103
- const files = [...paths].sort();
102
+ function viewIndex(latDir, markdownFiles, diagnostics, git, references, external) {
103
+ const files = [...markdownFiles.keys()].sort();
104
104
  const externalFiles = new Map();
105
105
  for (const target of references.externalByTarget.keys()) {
106
106
  try {
@@ -123,8 +123,18 @@ function viewIndex(latDir, paths, diagnostics, git, references, external) {
123
123
  const indexName = directoryName.endsWith('.md')
124
124
  ? directoryName
125
125
  : `${directoryName}.md`;
126
+ const directoryOrder = Object.fromEntries([...markdownFiles].flatMap(([path, file]) => {
127
+ const separator = path.lastIndexOf('/');
128
+ const directory = separator === -1 ? '' : path.slice(0, separator);
129
+ const name = directory ? basename(directory) : directoryName;
130
+ const filename = name.endsWith('.md') ? name : `${name}.md`;
131
+ if (path.slice(separator + 1) !== filename)
132
+ return [];
133
+ return [[directory, file.indexEntries]];
134
+ }));
126
135
  return {
127
136
  files,
137
+ directoryOrder,
128
138
  externalFiles: [...externalFiles.values()].sort((left, right) => left.handle.localeCompare(right.handle) ||
129
139
  left.path.localeCompare(right.path)),
130
140
  entry: files.includes(indexName) ? indexName : (files[0] ?? ''),
@@ -162,10 +172,10 @@ async function buildSnapshot(latDir, projectRoot, markdownFiles, codeFiles, git,
162
172
  files,
163
173
  allSections,
164
174
  references,
165
- graph: buildViewGraph(files.values(), codeFiles.values(), allSections, diagnostics, git, generation, external),
175
+ graph: buildViewGraph(files.values(), codeFiles.values(), allSections, diagnostics, git, generation, references, external),
166
176
  diagnostics,
167
177
  git,
168
- index: viewIndex(latDir, [...files.keys()], diagnostics, git, references, external),
178
+ index: viewIndex(latDir, files, diagnostics, git, references, external),
169
179
  external,
170
180
  };
171
181
  }
@@ -0,0 +1,24 @@
1
+ type FileTraceResult = {
2
+ fileList: Set<string>;
3
+ warnings: Set<Error>;
4
+ };
5
+ export type VercelBuildDependencies = {
6
+ traceFiles: (files: string[], options: {
7
+ base: string;
8
+ conditions: string[];
9
+ exportsOnly: boolean;
10
+ processCwd: string;
11
+ }) => Promise<FileTraceResult>;
12
+ };
13
+ export type VercelBuildOptions = {
14
+ force?: boolean;
15
+ warn?: (message: string) => void;
16
+ };
17
+ export type VercelBuildResult = {
18
+ files: number;
19
+ functionPath: string;
20
+ outputDir: string;
21
+ };
22
+ /** Convert an installed portable Lat UI server into Vercel Build Output API v3. */
23
+ export declare function buildVercelOutput(requestedArtifact: string, requestedOutput?: string, options?: VercelBuildOptions, dependencies?: VercelBuildDependencies): Promise<VercelBuildResult>;
24
+ export {};