@squadbase/vantage 0.6.2-dev1.b332e5a → 0.6.2-dev1.d7c0911

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 (212) hide show
  1. package/dist/add-4GHF2TX2.js +6 -0
  2. package/dist/add-4GHF2TX2.js.map +1 -0
  3. package/dist/{build-TVKFIVFQ.js → build-X5NVCQKT.js} +7 -7
  4. package/dist/{build-TVKFIVFQ.js.map → build-X5NVCQKT.js.map} +1 -1
  5. package/dist/{check-3KHZXZMQ.js → check-ZBIH422T.js} +5 -5
  6. package/dist/{check-3KHZXZMQ.js.map → check-ZBIH422T.js.map} +1 -1
  7. package/dist/chunk-2ICNHUG6.js +1820 -0
  8. package/dist/chunk-2ICNHUG6.js.map +1 -0
  9. package/dist/{chunk-5ZOP4SQR.js → chunk-2N72FKLB.js} +12 -7
  10. package/dist/chunk-2N72FKLB.js.map +1 -0
  11. package/dist/{chunk-P7W4LR3Z.js → chunk-7DZGJQ3P.js} +3 -3
  12. package/dist/{chunk-P7W4LR3Z.js.map → chunk-7DZGJQ3P.js.map} +1 -1
  13. package/dist/{chunk-U2M6HGKQ.js → chunk-AABMKHEU.js} +4 -4
  14. package/dist/{chunk-U2M6HGKQ.js.map → chunk-AABMKHEU.js.map} +1 -1
  15. package/dist/{chunk-QI3XQKHS.js → chunk-GNXCX4WE.js} +10 -3
  16. package/dist/chunk-GNXCX4WE.js.map +1 -0
  17. package/dist/{chunk-PXRX5PEC.js → chunk-PDOBHMUQ.js} +3 -3
  18. package/dist/chunk-PDOBHMUQ.js.map +1 -0
  19. package/dist/{chunk-ZVANIULZ.js → chunk-RNTDBX6S.js} +4 -4
  20. package/dist/{chunk-ZVANIULZ.js.map → chunk-RNTDBX6S.js.map} +1 -1
  21. package/dist/{chunk-A2UUGASH.js → chunk-U736PVHY.js} +2 -2
  22. package/dist/chunk-U736PVHY.js.map +1 -0
  23. package/dist/{chunk-PVTHHV7X.js → chunk-V3LF7BE7.js} +27 -5
  24. package/dist/chunk-V3LF7BE7.js.map +1 -0
  25. package/dist/{chunk-LMUACBMA.js → chunk-WAMZWZJB.js} +53 -8
  26. package/dist/chunk-WAMZWZJB.js.map +1 -0
  27. package/dist/chunk-WRSX2MDK.js +7866 -0
  28. package/dist/chunk-WRSX2MDK.js.map +1 -0
  29. package/dist/{chunk-RPZAALCX.js → chunk-XPQSTZUU.js} +254 -164
  30. package/dist/chunk-XPQSTZUU.js.map +1 -0
  31. package/dist/{chunk-DTDVSFRY.js → chunk-XQUSGIDG.js} +17 -3
  32. package/dist/chunk-XQUSGIDG.js.map +1 -0
  33. package/dist/cli.js +12 -11
  34. package/dist/cli.js.map +1 -1
  35. package/dist/client/index.d.ts +32 -3
  36. package/dist/client/index.js +205 -12
  37. package/dist/client/index.js.map +1 -1
  38. package/dist/components/index.d.ts +1975 -28
  39. package/dist/components/index.js +4 -4
  40. package/dist/{dev-GDKATCC7.js → dev-4XEDTELV.js} +8 -8
  41. package/dist/dev-4XEDTELV.js.map +1 -0
  42. package/dist/doc/index.js +2 -2
  43. package/dist/doc/index.js.map +1 -1
  44. package/dist/{docs-EJJ3BECT.js → docs-JVP4RPKT.js} +3 -3
  45. package/dist/{docs-EJJ3BECT.js.map → docs-JVP4RPKT.js.map} +1 -1
  46. package/dist/{doctor-WQXPXP6K.js → doctor-5E2VEZPK.js} +5 -5
  47. package/dist/{doctor-WQXPXP6K.js.map → doctor-5E2VEZPK.js.map} +1 -1
  48. package/dist/markdown/index.js +1 -1
  49. package/dist/markdown/index.js.map +1 -1
  50. package/dist/{preview-OGMCNQUO.js → preview-T6CLSQVX.js} +3 -3
  51. package/dist/{preview-OGMCNQUO.js.map → preview-T6CLSQVX.js.map} +1 -1
  52. package/dist/query/index.d.ts +0 -11
  53. package/dist/query/index.js +2 -2
  54. package/dist/{routes-MWBWWOJ2.js → routes-3SGAFDMC.js} +4 -4
  55. package/dist/{routes-MWBWWOJ2.js.map → routes-3SGAFDMC.js.map} +1 -1
  56. package/dist/{search-6Y422SV6.js → search-5LC4XPB5.js} +3 -3
  57. package/dist/{search-6Y422SV6.js.map → search-5LC4XPB5.js.map} +1 -1
  58. package/dist/table/index.js +10 -9
  59. package/dist/table/index.js.map +1 -1
  60. package/dist/ui/index.d.ts +144 -11
  61. package/dist/ui/index.js +1339 -87
  62. package/dist/ui/index.js.map +1 -1
  63. package/dist/{upgrade-HCANX4GQ.js → upgrade-JHXZBGQS.js} +6 -6
  64. package/dist/{upgrade-HCANX4GQ.js.map → upgrade-JHXZBGQS.js.map} +1 -1
  65. package/dist/vite/index.d.ts +10 -0
  66. package/dist/vite/index.js +3 -3
  67. package/docs/en/components.md +29 -15
  68. package/docs/en/parts/data-table.md +22 -0
  69. package/docs/en/parts/delta.md +50 -0
  70. package/docs/en/parts/format.md +43 -0
  71. package/docs/en/parts/kpi-card.md +57 -0
  72. package/docs/en/parts/metric-value.md +3 -2
  73. package/docs/en/parts/sparkline.md +1 -1
  74. package/docs/en/parts/trend-indicator.md +17 -1
  75. package/docs/en/ui-and-theming.md +1 -1
  76. package/docs/index.json +366 -76
  77. package/docs/ja/changelog.md +31 -0
  78. package/docs/ja/components.md +57 -101
  79. package/docs/ja/page-types/csv.md +83 -0
  80. package/docs/ja/page-types/doc.md +83 -0
  81. package/docs/ja/page-types/excel.md +82 -0
  82. package/docs/ja/page-types/slide.md +132 -0
  83. package/docs/ja/page-types.md +47 -0
  84. package/docs/ja/parts/area-chart.md +61 -0
  85. package/docs/ja/parts/bar-chart.md +69 -0
  86. package/docs/ja/parts/bar-list.md +35 -0
  87. package/docs/ja/parts/category-bar.md +36 -0
  88. package/docs/ja/parts/data-table.md +22 -0
  89. package/docs/ja/parts/delta.md +50 -0
  90. package/docs/ja/parts/donut-chart.md +47 -0
  91. package/docs/ja/parts/echart.md +3 -0
  92. package/docs/ja/parts/format.md +44 -0
  93. package/docs/ja/parts/kpi-card.md +55 -0
  94. package/docs/ja/parts/line-chart.md +58 -0
  95. package/docs/ja/parts/metric-value.md +3 -2
  96. package/docs/ja/parts/progress-circle.md +34 -0
  97. package/docs/ja/parts/sparkline.md +2 -2
  98. package/docs/ja/parts/tracker.md +32 -0
  99. package/docs/ja/parts/trend-indicator.md +17 -1
  100. package/docs/ja/routing.md +8 -86
  101. package/docs/ja/ui/alert-dialog.md +41 -0
  102. package/docs/ja/ui/avatar.md +31 -0
  103. package/docs/ja/ui/combobox.md +74 -0
  104. package/docs/ja/ui/drawer.md +41 -0
  105. package/docs/ja/ui/field.md +42 -0
  106. package/docs/ja/ui/hover-card.md +21 -0
  107. package/docs/ja/ui/kbd.md +16 -0
  108. package/docs/ja/ui/pagination.md +36 -0
  109. package/docs/ja/ui/radio-group.md +21 -0
  110. package/docs/ja/ui/toast.md +46 -0
  111. package/docs/ja/ui-and-theming.md +14 -7
  112. package/package.json +13 -4
  113. package/registry/ui/accordion.tsx +76 -0
  114. package/registry/ui/alert-dialog.tsx +189 -0
  115. package/registry/ui/alert.tsx +80 -0
  116. package/registry/ui/app-shell.tsx +287 -0
  117. package/registry/ui/area-chart.tsx +3639 -0
  118. package/registry/ui/avatar.tsx +110 -0
  119. package/registry/ui/badge.tsx +56 -0
  120. package/registry/ui/bar-chart.tsx +3636 -0
  121. package/registry/ui/bar-list.tsx +3680 -0
  122. package/registry/ui/breadcrumb.tsx +128 -0
  123. package/registry/ui/button.tsx +62 -0
  124. package/registry/ui/calendar.tsx +223 -0
  125. package/registry/ui/card.tsx +107 -0
  126. package/registry/ui/category-bar.tsx +1255 -0
  127. package/registry/ui/chart-frame.tsx +1358 -0
  128. package/registry/ui/checkbox.tsx +30 -0
  129. package/registry/ui/collapsible.tsx +23 -0
  130. package/registry/ui/combobox.tsx +310 -0
  131. package/registry/ui/command.tsx +198 -0
  132. package/registry/ui/dashboard-card.tsx +217 -0
  133. package/registry/ui/data-table.tsx +693 -146
  134. package/registry/ui/date-range-picker.tsx +390 -0
  135. package/registry/ui/delta.tsx +188 -0
  136. package/registry/ui/dialog.tsx +161 -0
  137. package/registry/ui/donut-chart.tsx +3688 -0
  138. package/registry/ui/drawer.tsx +229 -0
  139. package/registry/ui/dropdown-menu.tsx +274 -0
  140. package/registry/ui/echart.tsx +890 -0
  141. package/registry/ui/field.tsx +240 -0
  142. package/registry/ui/filter-bar.tsx +392 -0
  143. package/registry/ui/funnel-steps.tsx +3541 -0
  144. package/registry/ui/heatmap.tsx +1752 -0
  145. package/registry/ui/hover-card.tsx +52 -0
  146. package/registry/ui/input-group.tsx +160 -0
  147. package/registry/ui/input.tsx +24 -0
  148. package/registry/ui/kbd.tsx +30 -0
  149. package/registry/ui/kpi-card.tsx +677 -0
  150. package/registry/ui/label.tsx +22 -0
  151. package/registry/ui/legend.tsx +3500 -0
  152. package/registry/ui/line-chart.tsx +3637 -0
  153. package/registry/ui/metric-value.tsx +62 -0
  154. package/registry/ui/multi-select.tsx +232 -0
  155. package/registry/ui/page-shell.tsx +282 -0
  156. package/registry/ui/pagination.tsx +140 -0
  157. package/registry/ui/placeholder.tsx +36 -0
  158. package/registry/ui/popover.tsx +92 -0
  159. package/registry/ui/progress-circle.tsx +867 -0
  160. package/registry/ui/progress.tsx +85 -0
  161. package/registry/ui/radio-group.tsx +39 -0
  162. package/registry/ui/sample-data.tsx +86 -0
  163. package/registry/ui/scatter-chart.tsx +4150 -0
  164. package/registry/ui/scroll-area.tsx +56 -0
  165. package/registry/ui/searchable-select.tsx +214 -0
  166. package/registry/ui/section-header.tsx +43 -0
  167. package/registry/ui/segmented-control.tsx +76 -0
  168. package/registry/ui/select.tsx +255 -0
  169. package/registry/ui/separator.tsx +27 -0
  170. package/registry/ui/sheet.tsx +139 -0
  171. package/registry/ui/sidebar.tsx +725 -0
  172. package/registry/ui/skeleton.tsx +17 -0
  173. package/registry/ui/slider.tsx +56 -0
  174. package/registry/ui/sparkline.tsx +230 -0
  175. package/registry/ui/spinner.tsx +14 -0
  176. package/registry/ui/states.tsx +90 -0
  177. package/registry/ui/status-badge.tsx +121 -0
  178. package/registry/ui/switch.tsx +34 -0
  179. package/registry/ui/table.tsx +118 -0
  180. package/registry/ui/tabs.tsx +84 -0
  181. package/registry/ui/textarea.tsx +22 -0
  182. package/registry/ui/toast.tsx +250 -0
  183. package/registry/ui/toggle-group.tsx +91 -0
  184. package/registry/ui/toggle.tsx +47 -0
  185. package/registry/ui/tooltip.tsx +68 -0
  186. package/registry/ui/tracker.tsx +843 -0
  187. package/registry/ui/trend-indicator.tsx +74 -0
  188. package/registry/ui/updated-at.tsx +122 -0
  189. package/registry/ui/waterfall-chart.tsx +4186 -0
  190. package/skills/vantage-add-feature/SKILL.md +9 -7
  191. package/skills/vantage-pitfalls/SKILL.md +5 -1
  192. package/templates/AGENTS.md +22 -1
  193. package/templates/agents/csv.md +2 -1
  194. package/templates/agents/doc.md +4 -3
  195. package/templates/agents/page.md +20 -6
  196. package/templates/agents/xlsx.md +2 -1
  197. package/theme.css +237 -136
  198. package/dist/add-DY4AXANK.js +0 -6
  199. package/dist/add-DY4AXANK.js.map +0 -1
  200. package/dist/chunk-5ZOP4SQR.js.map +0 -1
  201. package/dist/chunk-A2UUGASH.js.map +0 -1
  202. package/dist/chunk-DTDVSFRY.js.map +0 -1
  203. package/dist/chunk-LMUACBMA.js.map +0 -1
  204. package/dist/chunk-NKFBFDRZ.js +0 -2241
  205. package/dist/chunk-NKFBFDRZ.js.map +0 -1
  206. package/dist/chunk-PVTHHV7X.js.map +0 -1
  207. package/dist/chunk-PXRX5PEC.js.map +0 -1
  208. package/dist/chunk-QI3XQKHS.js.map +0 -1
  209. package/dist/chunk-RPZAALCX.js.map +0 -1
  210. package/dist/chunk-VA776YE5.js +0 -316
  211. package/dist/chunk-VA776YE5.js.map +0 -1
  212. package/dist/dev-GDKATCC7.js.map +0 -1
@@ -0,0 +1,1820 @@
1
+ import { generateArtifacts, setDraftArtifacts, restoreClientEntry } from './chunk-WAMZWZJB.js';
2
+ import { scanProject, resolvePageRoot, stripExt, splitPageVariant, fileToSegments, displayPath } from './chunk-RNTDBX6S.js';
3
+ import { corsMiddleware, matchApiRoute, dispatchApi, sortApiRoutes } from './chunk-46QI6GFC.js';
4
+ import { VANTAGE_DIR, NON_ROUTE_DIRS, FILE_PAGE_EXTENSIONS, PAGE_EXTENSIONS, RESERVED_PAGE_NAMES } from './chunk-C2CX6GLX.js';
5
+ import fs3 from 'fs';
6
+ import path6 from 'path';
7
+ import react from '@vitejs/plugin-react';
8
+ import tailwindcss from '@tailwindcss/vite';
9
+ import { Hono } from 'hono';
10
+ import { getRequestListener } from '@hono/node-server';
11
+ import { createHash, timingSafeEqual } from 'crypto';
12
+ import { createRequire } from 'module';
13
+ import { pathToFileURL, fileURLToPath } from 'url';
14
+
15
+ // @squadbase/vantage — generated build. Do not edit.
16
+ function createApiDevMiddleware(opts) {
17
+ const { server, getModel, getEnv } = opts;
18
+ const buildRoutes = () => sortApiRoutes(
19
+ getModel().apis.map((a) => ({
20
+ routePath: a.routePath,
21
+ segments: a.segments,
22
+ hasCatchall: a.segments.some((s) => s.kind === "catchall"),
23
+ staticCount: a.segments.filter((s) => s.kind === "static").length,
24
+ load: () => server.ssrLoadModule(a.absFile)
25
+ }))
26
+ );
27
+ const app = new Hono();
28
+ const cors = corsMiddleware(getEnv());
29
+ if (cors) {
30
+ app.use("/api", cors);
31
+ app.use("/api/*", cors);
32
+ }
33
+ const handle = async (c) => {
34
+ const url = new URL(c.req.url);
35
+ const match = matchApiRoute(buildRoutes(), url.pathname);
36
+ if (!match) {
37
+ return Response.json({ error: "Not Found", path: url.pathname }, { status: 404 });
38
+ }
39
+ let mod;
40
+ try {
41
+ mod = await match.route.load();
42
+ } catch (err) {
43
+ if (err instanceof Error) server.ssrFixStacktrace(err);
44
+ throw err;
45
+ }
46
+ return dispatchApi(mod, c.req.raw, match.params, getEnv());
47
+ };
48
+ app.all("/api", handle);
49
+ app.all("/api/*", handle);
50
+ const listener = getRequestListener(app.fetch);
51
+ return (req, res, next) => {
52
+ const url = req.url ?? "/";
53
+ const path7 = url.split("?")[0];
54
+ if (path7 === "/api" || path7.startsWith("/api/")) {
55
+ Promise.resolve(listener(req, res)).catch((err) => {
56
+ console.error("[vantage] API middleware failure:", err);
57
+ if (!res.headersSent) {
58
+ res.statusCode = 500;
59
+ res.setHeader("content-type", "application/json");
60
+ res.end(JSON.stringify({ error: "Internal Server Error" }));
61
+ }
62
+ });
63
+ } else {
64
+ next();
65
+ }
66
+ };
67
+ }
68
+
69
+ // src/client/draft-skeleton-source.ts
70
+ var IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
71
+ function draftSkeletonModuleSource(names = []) {
72
+ const lines = [
73
+ 'import { createElement } from "react"',
74
+ 'import { DraftSkeleton } from "@squadbase/vantage/client"',
75
+ "const Skeleton = () => createElement(DraftSkeleton)",
76
+ "const noop = () => undefined",
77
+ "export default Skeleton"
78
+ ];
79
+ for (const name of new Set(names)) {
80
+ if (name === "default" || !IDENTIFIER.test(name)) continue;
81
+ lines.push(`export const ${name} = ${/^[A-Z]/.test(name) ? "Skeleton" : "noop"}`);
82
+ }
83
+ return lines.join("\n") + "\n";
84
+ }
85
+ var KEEP_PER_FILE = 2;
86
+ var BorrowedVersions = class {
87
+ constructor(query) {
88
+ this.query = query;
89
+ }
90
+ query;
91
+ /** Hash → content. Immutable per hash. */
92
+ versions = /* @__PURE__ */ new Map();
93
+ /** Absolute file path → the content the shown draft borrows from. */
94
+ sources = /* @__PURE__ */ new Map();
95
+ /**
96
+ * The content a new draft of `file` should borrow from. While the shown draft
97
+ * itself borrows, that is the same source again (not the shown draft, whose
98
+ * text changes every time and would chain wrappers); otherwise the version
99
+ * shown before (`shown`).
100
+ */
101
+ sourceFor(file, shown) {
102
+ return this.sources.get(file) ?? shown;
103
+ }
104
+ /** Register `content` as borrowed by `file`'s next draft and return its URL. */
105
+ urlFor(file, url, content) {
106
+ const hash = createHash("sha1").update(content).digest("hex").slice(0, 12);
107
+ this.versions.delete(hash);
108
+ this.versions.set(hash, { file, content });
109
+ const ofFile = [...this.versions].filter(([, v]) => v.file === file);
110
+ for (const [h] of ofFile.slice(0, Math.max(0, ofFile.length - KEEP_PER_FILE))) this.versions.delete(h);
111
+ return `${url}?${this.query}=${hash}`;
112
+ }
113
+ /** Record what the draft now shown borrows from; `undefined` when it borrows nothing. */
114
+ shown(file, source) {
115
+ if (source === void 0) this.sources.delete(file);
116
+ else this.sources.set(file, source);
117
+ }
118
+ get(hash) {
119
+ return this.versions.get(hash)?.content;
120
+ }
121
+ drop(file) {
122
+ this.sources.delete(file);
123
+ for (const [h, v] of this.versions) if (v.file === file) this.versions.delete(h);
124
+ }
125
+ };
126
+ var loaded;
127
+ async function loadTypeScript(root) {
128
+ try {
129
+ const entry = createRequire(path6.join(path6.resolve(root), "package.json")).resolve("typescript");
130
+ const mod = await import(pathToFileURL(entry).href);
131
+ const compiler = mod.default ?? mod;
132
+ if (typeof compiler.createSourceFile !== "function") return null;
133
+ loaded = compiler;
134
+ return loaded;
135
+ } catch {
136
+ return null;
137
+ }
138
+ }
139
+ function api() {
140
+ loaded ??= createRequire(import.meta.url)("typescript");
141
+ return loaded;
142
+ }
143
+ var ts = new Proxy({}, {
144
+ get: (_target, key) => Reflect.get(api(), key)
145
+ });
146
+
147
+ // src/vite/draft/names.ts
148
+ function parseSource(source, fileName) {
149
+ const kind = /\.[jt]sx$/i.test(fileName) ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
150
+ return ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, kind);
151
+ }
152
+ function bodilessFunctions(source, fileName) {
153
+ const found = [];
154
+ const hasBody = (n) => (ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n) || ts.isConstructorDeclaration(n)) && n.body !== void 0;
155
+ const nameOf = (n) => {
156
+ if (ts.isConstructorDeclaration(n)) return "constructor";
157
+ const name = n.name;
158
+ return name === void 0 ? "default" : ts.isIdentifier(name) || ts.isStringLiteral(name) ? name.text : name.getText();
159
+ };
160
+ const check = (siblings) => {
161
+ siblings.forEach((node, i) => {
162
+ if (!(ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node))) return;
163
+ if (node.body !== void 0) return;
164
+ if (hasModifier(node, ts.SyntaxKind.AbstractKeyword) || inAmbientContext(node)) return;
165
+ const name = nameOf(node);
166
+ if (siblings.slice(i + 1).some((next) => hasBody(next) && nameOf(next) === name)) return;
167
+ found.push(name);
168
+ });
169
+ };
170
+ const visit = (node) => {
171
+ if (ts.isSourceFile(node) || ts.isBlock(node) || ts.isModuleBlock(node)) check(node.statements);
172
+ else if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) check(node.members);
173
+ ts.forEachChild(node, visit);
174
+ };
175
+ visit(parseSource(source, fileName));
176
+ return found;
177
+ }
178
+ function exportNames(source, fileName) {
179
+ const names = /* @__PURE__ */ new Set();
180
+ for (const stmt of parseSource(source, fileName).statements) {
181
+ if (ts.isExportAssignment(stmt)) {
182
+ if (!stmt.isExportEquals) names.add("default");
183
+ } else if (ts.isExportDeclaration(stmt)) {
184
+ if (stmt.isTypeOnly) continue;
185
+ const clause = stmt.exportClause;
186
+ if (clause && ts.isNamedExports(clause)) {
187
+ for (const spec of clause.elements) if (!spec.isTypeOnly) names.add(spec.name.text);
188
+ } else if (clause && ts.isNamespaceExport(clause)) {
189
+ names.add(clause.name.text);
190
+ }
191
+ } else if (hasModifier(stmt, ts.SyntaxKind.ExportKeyword) && !hasModifier(stmt, ts.SyntaxKind.DeclareKeyword)) {
192
+ if (isSignature(stmt)) continue;
193
+ if (hasModifier(stmt, ts.SyntaxKind.DefaultKeyword)) names.add("default");
194
+ else if (ts.isVariableStatement(stmt)) {
195
+ for (const decl of stmt.declarationList.declarations) bindingNames(decl.name, names);
196
+ } else if ((ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt) || ts.isEnumDeclaration(stmt)) && stmt.name) {
197
+ names.add(stmt.name.text);
198
+ }
199
+ }
200
+ }
201
+ return names;
202
+ }
203
+ function topLevelNames(source, fileName) {
204
+ const names = /* @__PURE__ */ new Set();
205
+ for (const stmt of parseSource(source, fileName).statements) {
206
+ if (isSignature(stmt)) continue;
207
+ if (ts.isVariableStatement(stmt)) {
208
+ for (const decl of stmt.declarationList.declarations) bindingNames(decl.name, names);
209
+ } else if ((ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt) || ts.isEnumDeclaration(stmt)) && stmt.name) {
210
+ names.add(stmt.name.text);
211
+ }
212
+ }
213
+ return names;
214
+ }
215
+ function boundNames(sf) {
216
+ const names = /* @__PURE__ */ new Set();
217
+ const visit = (node) => {
218
+ if (ts.isImportClause(node) && node.name) names.add(node.name.text);
219
+ else if (ts.isNamespaceImport(node) || ts.isImportSpecifier(node)) names.add(node.name.text);
220
+ else if (ts.isImportEqualsDeclaration(node)) names.add(node.name.text);
221
+ else if (ts.isVariableDeclaration(node) || ts.isParameter(node) || ts.isBindingElement(node))
222
+ bindingNames(node.name, names);
223
+ else if ((ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isClassDeclaration(node) || ts.isClassExpression(node) || ts.isEnumDeclaration(node)) && node.name)
224
+ names.add(node.name.text);
225
+ ts.forEachChild(node, visit);
226
+ };
227
+ visit(sf);
228
+ return names;
229
+ }
230
+ var BROWSER_GLOBALS = /* @__PURE__ */ new Set([
231
+ "window",
232
+ "document",
233
+ "navigator",
234
+ "location",
235
+ "history",
236
+ "localStorage",
237
+ "sessionStorage",
238
+ "screen",
239
+ "alert",
240
+ "confirm",
241
+ "prompt",
242
+ "matchMedia",
243
+ "getComputedStyle",
244
+ "requestAnimationFrame",
245
+ "cancelAnimationFrame",
246
+ "requestIdleCallback",
247
+ "cancelIdleCallback",
248
+ "ResizeObserver",
249
+ "IntersectionObserver",
250
+ "MutationObserver",
251
+ "Image",
252
+ "Audio",
253
+ "Node",
254
+ "Element",
255
+ "DOMParser",
256
+ "FileReader",
257
+ "File",
258
+ "WebSocket",
259
+ "Worker",
260
+ "Notification",
261
+ "indexedDB",
262
+ "caches",
263
+ "innerWidth",
264
+ "innerHeight",
265
+ "scrollTo",
266
+ "open",
267
+ "print",
268
+ "self",
269
+ "top",
270
+ "parent",
271
+ "frames",
272
+ "CSS",
273
+ "Option",
274
+ "customElements",
275
+ "DOMRect",
276
+ "DOMException",
277
+ "ClipboardItem",
278
+ "SpeechSynthesisUtterance",
279
+ "speechSynthesis",
280
+ "JSX",
281
+ "React",
282
+ // Window members the dev server's own `globalThis` (Node) does not have.
283
+ "devicePixelRatio",
284
+ "scrollX",
285
+ "scrollY",
286
+ "pageXOffset",
287
+ "pageYOffset",
288
+ "addEventListener",
289
+ "removeEventListener",
290
+ "dispatchEvent",
291
+ "postMessage",
292
+ "visualViewport",
293
+ "getSelection",
294
+ "XMLHttpRequest",
295
+ "AudioContext",
296
+ "Range",
297
+ "Text",
298
+ "Document",
299
+ "Storage",
300
+ "outerWidth",
301
+ "outerHeight",
302
+ "screenX",
303
+ "screenY",
304
+ "status",
305
+ "name",
306
+ "length",
307
+ "closed",
308
+ "opener",
309
+ "event"
310
+ ]);
311
+ var BROWSER_GLOBAL_PATTERN = /^(HTML|SVG|CSS|DOM)\w*|Event$|Observer$/;
312
+ var isGlobal = (name) => name === "undefined" || name === "arguments" || BROWSER_GLOBALS.has(name) || BROWSER_GLOBAL_PATTERN.test(name) || name in globalThis;
313
+ function undeclaredNames(source, fileName) {
314
+ const sf = parseSource(source, fileName);
315
+ const bound = boundNames(sf);
316
+ const missing = /* @__PURE__ */ new Set();
317
+ const visit = (node) => {
318
+ if (ts.isTypeNode(node) && !ts.isExpressionWithTypeArguments(node)) return;
319
+ if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) return;
320
+ if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) return;
321
+ if (ts.isIdentifier(node)) {
322
+ const parent = node.parent;
323
+ const name = node.text;
324
+ if (!bound.has(name) && !isGlobal(name) && isValueReference(node, parent)) missing.add(name);
325
+ return;
326
+ }
327
+ ts.forEachChild(node, visit);
328
+ };
329
+ visit(sf);
330
+ return [...missing];
331
+ }
332
+ function isValueReference(node, parent) {
333
+ if (ts.isPropertyAccessExpression(parent)) return parent.expression === node;
334
+ if (ts.isQualifiedName(parent) || ts.isMetaProperty(parent)) return false;
335
+ if (ts.isTypeOfExpression(parent)) return false;
336
+ if (ts.isJsxAttribute(parent)) return false;
337
+ if (ts.isJsxOpeningElement(parent) || ts.isJsxSelfClosingElement(parent) || ts.isJsxClosingElement(parent))
338
+ return parent.tagName === node && /^[A-Z]/.test(node.text);
339
+ if (ts.isLabeledStatement(parent) || ts.isBreakStatement(parent) || ts.isContinueStatement(parent)) return false;
340
+ if (ts.isBindingElement(parent)) return parent.propertyName !== node && parent.name !== node;
341
+ if (ts.isPropertyAssignment(parent)) return parent.name !== node;
342
+ if (ts.isMethodDeclaration(parent) || ts.isPropertyDeclaration(parent) || ts.isGetAccessorDeclaration(parent) || ts.isSetAccessorDeclaration(parent) || ts.isPropertySignature(parent) || ts.isEnumMember(parent))
343
+ return parent.name !== node;
344
+ return true;
345
+ }
346
+ function bindingNames(name, into) {
347
+ if (ts.isIdentifier(name)) {
348
+ into.add(name.text);
349
+ return;
350
+ }
351
+ for (const el of name.elements) if (ts.isBindingElement(el)) bindingNames(el.name, into);
352
+ }
353
+ function inAmbientContext(node) {
354
+ for (let n = node; n; n = n.parent) if (hasModifier(n, ts.SyntaxKind.DeclareKeyword)) return true;
355
+ return false;
356
+ }
357
+ function isSignature(node) {
358
+ return ts.isFunctionDeclaration(node) && node.body === void 0;
359
+ }
360
+ function hasModifier(node, kind) {
361
+ return ts.canHaveModifiers(node) && (ts.getModifiers(node)?.some((m) => m.kind === kind) ?? false);
362
+ }
363
+
364
+ // src/vite/draft/complete.ts
365
+ function completeDraft(source, opts) {
366
+ const isTsx = /\.tsx$/i.test(opts.path);
367
+ if (!isTsx && !/\.ts$/i.test(opts.path)) return null;
368
+ if (/\.d\.ts$/i.test(opts.path)) return null;
369
+ const page = isPageModule(opts.path, opts.pageDir);
370
+ const needExport = page || opts.requireExport !== false;
371
+ if (needExport && !(page ? /\bexport\s+default\b/ : /\bexport\b/).test(source)) return null;
372
+ const kind = isTsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
373
+ const snapshots = lex(source, isTsx);
374
+ const MAX_TRIES = 200;
375
+ const MAX_PARSED_CHARS = 4e6;
376
+ let tries = 0;
377
+ let parsedChars = 0;
378
+ for (let i = snapshots.length - 1; i >= 0 && tries < MAX_TRIES && parsedChars < MAX_PARSED_CHARS; i--) {
379
+ if (endsMidWord(source, snapshots[i])) continue;
380
+ const candidate = close(source, snapshots[i]);
381
+ if (candidate === null) continue;
382
+ tries++;
383
+ parsedChars += candidate.length;
384
+ if (parsesWithExport(candidate, opts.path, kind, page, needExport)) return candidate;
385
+ }
386
+ return null;
387
+ }
388
+ var CLOSERS = { paren: ")", bracket: "]", brace: "}", tplExpr: "}", jsxExpr: "}" };
389
+ function close(source, snap) {
390
+ let cut = snap.pos;
391
+ let stack = snap.stack;
392
+ if (snap.openTokenStart !== null) cut = Math.min(cut, snap.openTokenStart);
393
+ const dropAt = stack.findIndex((f) => f.kind === "jsxTag" || f.kind === "jsxClose" || f.kind === "template");
394
+ if (dropAt !== -1) {
395
+ cut = Math.min(cut, stack[dropAt].start);
396
+ stack = stack.slice(0, dropAt);
397
+ }
398
+ let suffix = "";
399
+ for (let i = stack.length - 1; i >= 0; i--) {
400
+ const f = stack[i];
401
+ suffix += f.kind === "jsxElem" ? `</${f.name ?? ""}>` : CLOSERS[f.kind];
402
+ }
403
+ const head = source.slice(0, cut);
404
+ if (!head.trim()) return null;
405
+ return suffix ? `${head}${needsBreak(head) ? "\n" : ""}${suffix}
406
+ ` : head;
407
+ }
408
+ function endsMidWord(source, snap) {
409
+ if (snap.pos !== source.length || snap.openTokenStart !== null) return false;
410
+ if (!ID_PART.test(source.charAt(source.length - 1))) return false;
411
+ const kind = snap.stack[snap.stack.length - 1]?.kind;
412
+ return kind !== "jsxElem" && kind !== "jsxTag" && kind !== "jsxClose" && kind !== "template";
413
+ }
414
+ function needsBreak(head) {
415
+ const lastLine = head.slice(head.lastIndexOf("\n") + 1);
416
+ return lastLine.includes("//");
417
+ }
418
+ function isPageModule(path7, pageDir = "") {
419
+ return /\.tsx$/i.test(path7) && isPagePath(path7, pageDir);
420
+ }
421
+ function isPagePath(path7, pageDir) {
422
+ let rel = path7.replace(/\\/g, "/");
423
+ if (pageDir !== "") {
424
+ if (!rel.startsWith(`${pageDir}/`)) return false;
425
+ rel = rel.slice(pageDir.length + 1);
426
+ }
427
+ const dirs = rel.split("/").slice(0, -1);
428
+ return dirs.every((d) => d !== "" && !d.startsWith(".") && !NON_ROUTE_DIRS.has(d));
429
+ }
430
+ function parsesWithExport(code, path7, kind, needDefault, needExport) {
431
+ const sf = ts.createSourceFile(path7, code, ts.ScriptTarget.Latest, false, kind);
432
+ const diagnostics = sf.parseDiagnostics;
433
+ if (diagnostics && diagnostics.length > 0) return false;
434
+ const exports = !needExport || sf.statements.some((s) => {
435
+ if (ts.isExportAssignment(s)) return true;
436
+ if (!needDefault && ts.isExportDeclaration(s)) return true;
437
+ if (!ts.canHaveModifiers(s)) return false;
438
+ const flags = ts.getCombinedModifierFlags(s);
439
+ return needDefault ? (flags & ts.ModifierFlags.ExportDefault) === ts.ModifierFlags.ExportDefault : (flags & ts.ModifierFlags.Export) !== 0;
440
+ });
441
+ return exports && bodilessFunctions(code, path7).length === 0;
442
+ }
443
+ var ID_START = /[A-Za-z_$]/;
444
+ var ID_PART = /[A-Za-z0-9_$]/;
445
+ var JSX_NAME_PART = /[A-Za-z0-9_$.:-]/;
446
+ var EXPR_START_CHARS = /* @__PURE__ */ new Set(["", "(", ",", "=", ":", "?", "[", "{", "}", "!", "&", "|", ";", ">", "+", "-", "*", "%", "~", "^"]);
447
+ var EXPR_START_WORDS = /* @__PURE__ */ new Set(["return", "typeof", "case", "do", "else", "in", "of", "new", "delete", "void", "throw", "yield", "await", "default"]);
448
+ function lex(src, jsx) {
449
+ const stack = [];
450
+ const snaps = [];
451
+ let prev = "";
452
+ const top = () => stack[stack.length - 1];
453
+ const snap = (pos, openTokenStart = null) => snaps.push({ pos, stack: stack.slice(), openTokenStart });
454
+ const exprCanStart = () => EXPR_START_CHARS.has(prev) || EXPR_START_WORDS.has(prev);
455
+ const skipString = (i2, quote, multiline) => {
456
+ for (let j = i2 + 1; j < src.length; j++) {
457
+ const c = src[j];
458
+ if (c === "\\") j++;
459
+ else if (c === quote) return j + 1;
460
+ else if (c === "\n") {
461
+ if (!multiline) return -1;
462
+ snap(j, i2);
463
+ }
464
+ }
465
+ return -1;
466
+ };
467
+ let i = 0;
468
+ while (i < src.length) {
469
+ const c = src.charAt(i);
470
+ const t = top();
471
+ const kind = t?.kind;
472
+ if (c === "\n" && kind !== "template") snap(i);
473
+ if (kind === "template") {
474
+ if (c === "\n") snap(i);
475
+ if (c === "\\") i += 2;
476
+ else if (c === "`") {
477
+ stack.pop();
478
+ prev = "x";
479
+ i++;
480
+ } else if (c === "$" && src[i + 1] === "{") {
481
+ stack.push({ kind: "tplExpr", start: i });
482
+ prev = "{";
483
+ i += 2;
484
+ } else i++;
485
+ continue;
486
+ }
487
+ if (kind === "jsxClose") {
488
+ if (c === ">") {
489
+ stack.pop();
490
+ if (top()?.kind === "jsxElem") stack.pop();
491
+ afterJsxElement();
492
+ }
493
+ i++;
494
+ continue;
495
+ }
496
+ if (kind === "jsxTag") {
497
+ if (c === '"' || c === "'") {
498
+ const end = skipString(i, c, true);
499
+ if (end === -1) break;
500
+ i = end;
501
+ } else if (c === "{") {
502
+ stack.push({ kind: "jsxExpr", start: i });
503
+ prev = "{";
504
+ i++;
505
+ } else if (c === "/" && src[i + 1] === ">") {
506
+ stack.pop();
507
+ afterJsxElement();
508
+ i += 2;
509
+ } else if (c === ">") {
510
+ const tag = stack.pop();
511
+ stack.push({ kind: "jsxElem", start: tag.start, name: tag.name });
512
+ i++;
513
+ } else i++;
514
+ continue;
515
+ }
516
+ if (kind === "jsxElem") {
517
+ if (c === "{") {
518
+ stack.push({ kind: "jsxExpr", start: i });
519
+ prev = "{";
520
+ i++;
521
+ } else if (c === "<") {
522
+ i = openJsx(i);
523
+ } else i++;
524
+ continue;
525
+ }
526
+ if (c === "/" && src[i + 1] === "/") {
527
+ const nl = src.indexOf("\n", i);
528
+ if (nl === -1) {
529
+ snap(src.length, i);
530
+ return snaps;
531
+ }
532
+ i = nl;
533
+ continue;
534
+ }
535
+ if (c === "/" && src[i + 1] === "*") {
536
+ const endC = src.indexOf("*/", i + 2);
537
+ const stop = endC === -1 ? src.length : endC;
538
+ for (let j = src.indexOf("\n", i); j !== -1 && j < stop; j = src.indexOf("\n", j + 1)) snap(j, i);
539
+ if (endC === -1) {
540
+ snap(src.length, i);
541
+ return snaps;
542
+ }
543
+ i = endC + 2;
544
+ continue;
545
+ }
546
+ if (c === '"' || c === "'") {
547
+ const end = skipString(i, c, false);
548
+ if (end === -1) {
549
+ const nl = src.indexOf("\n", i);
550
+ snap(nl === -1 ? src.length : nl, i);
551
+ if (nl === -1) return snaps;
552
+ i = nl + 1;
553
+ prev = "x";
554
+ continue;
555
+ }
556
+ i = end;
557
+ prev = "x";
558
+ continue;
559
+ }
560
+ if (c === "`") {
561
+ stack.push({ kind: "template", start: i });
562
+ i++;
563
+ continue;
564
+ }
565
+ if (c === "/" && exprCanStart()) {
566
+ let j = i + 1;
567
+ let inClass = false;
568
+ for (; j < src.length && src[j] !== "\n"; j++) {
569
+ if (src[j] === "\\") j++;
570
+ else if (src[j] === "[") inClass = true;
571
+ else if (src[j] === "]") inClass = false;
572
+ else if (src[j] === "/" && !inClass) break;
573
+ }
574
+ if (src[j] !== "/") {
575
+ snap(j, i);
576
+ if (j >= src.length) return snaps;
577
+ i = j;
578
+ continue;
579
+ }
580
+ i = j + 1;
581
+ while (i < src.length && ID_PART.test(src.charAt(i))) i++;
582
+ prev = "x";
583
+ continue;
584
+ }
585
+ if (c === "<" && jsx && exprCanStart() && (ID_START.test(src[i + 1] ?? "") || src[i + 1] === ">")) {
586
+ i = openJsx(i);
587
+ continue;
588
+ }
589
+ if (c === "(" || c === "[" || c === "{") {
590
+ stack.push({ kind: c === "(" ? "paren" : c === "[" ? "bracket" : "brace", start: i });
591
+ prev = c;
592
+ i++;
593
+ continue;
594
+ }
595
+ if (c === ")" || c === "]" || c === "}") {
596
+ if (t && (kind === "paren" || kind === "bracket" || kind === "brace" || kind === "tplExpr" || kind === "jsxExpr")) {
597
+ stack.pop();
598
+ }
599
+ prev = c === "}" && kind === "brace" ? "}" : "x";
600
+ i++;
601
+ continue;
602
+ }
603
+ if (ID_START.test(c)) {
604
+ let j = i + 1;
605
+ while (j < src.length && ID_PART.test(src.charAt(j))) j++;
606
+ prev = src.slice(i, j);
607
+ i = j;
608
+ continue;
609
+ }
610
+ if (/\s/.test(c)) {
611
+ i++;
612
+ continue;
613
+ }
614
+ if (/[0-9]/.test(c)) {
615
+ while (i < src.length && /[0-9A-Za-z_.]/.test(src.charAt(i))) i++;
616
+ prev = "x";
617
+ continue;
618
+ }
619
+ prev = c;
620
+ i++;
621
+ }
622
+ snap(src.length);
623
+ return snaps;
624
+ function openJsx(at) {
625
+ if (src[at + 1] === "/") {
626
+ stack.push({ kind: "jsxClose", start: at });
627
+ return at + 2;
628
+ }
629
+ let j = at + 1;
630
+ while (j < src.length && JSX_NAME_PART.test(src.charAt(j))) j++;
631
+ stack.push({ kind: "jsxTag", start: at, name: src.slice(at + 1, j) });
632
+ return j;
633
+ }
634
+ function afterJsxElement() {
635
+ prev = "x";
636
+ }
637
+ }
638
+ var COMMIT_WINDOW_MS = 1e4;
639
+ var instances = /* @__PURE__ */ new WeakMap();
640
+ function getDraftRoutes(server) {
641
+ return instances.get(server);
642
+ }
643
+ function createDraftRoutes(server, _model) {
644
+ const root = path6.resolve(server.config.root);
645
+ const vantageDir = path6.join(root, VANTAGE_DIR);
646
+ const pages = /* @__PURE__ */ new Map();
647
+ const committed = /* @__PURE__ */ new Map();
648
+ setDraftArtifacts(root, { hmr: true, pages: [] });
649
+ generateArtifacts({ root, model: scanProject(root) });
650
+ const toRel = (file) => {
651
+ const abs = path6.isAbsolute(file) ? file : path6.resolve(root, file);
652
+ return path6.relative(root, abs).split(path6.sep).join("/");
653
+ };
654
+ const describe = (rel) => {
655
+ if (rel === "" || rel.startsWith("../") || path6.isAbsolute(rel)) return null;
656
+ const pageRoot = resolvePageRoot(root);
657
+ const fromPageRoot = pageRoot.dir === "" ? rel : path6.posix.relative(pageRoot.dir, rel);
658
+ if (fromPageRoot.startsWith("../") || fromPageRoot === "") return null;
659
+ const parts = fromPageRoot.split("/");
660
+ if (parts.some((s) => NON_ROUTE_DIRS.has(s) || s.startsWith("."))) return null;
661
+ const base = parts[parts.length - 1];
662
+ const ext = PAGE_EXTENSIONS.find((e) => base.endsWith(e));
663
+ if (!ext) return null;
664
+ const nameNoExt = stripExt(base, PAGE_EXTENSIONS);
665
+ if (Object.values(RESERVED_PAGE_NAMES).includes(nameNoExt)) return null;
666
+ const { base: pageName, variant } = splitPageVariant(nameNoExt);
667
+ if (pageName.startsWith("_")) return null;
668
+ const relNoExt = stripExt(fromPageRoot, PAGE_EXTENSIONS);
669
+ const forSegments = variant ? relNoExt.slice(0, -(variant.length + 1)) : relNoExt;
670
+ const segments = fileToSegments(forSegments);
671
+ const dir = path6.posix.dirname(fromPageRoot);
672
+ return {
673
+ file: rel,
674
+ absFile: path6.join(root, ...rel.split("/")),
675
+ routePath: displayPath(segments),
676
+ segments,
677
+ dir: dir === "." ? "" : dir,
678
+ dynamic: segments.some((s) => s.kind !== "static"),
679
+ kind: "module",
680
+ ...variant ? { variant } : {}
681
+ };
682
+ };
683
+ const isNewPage = (file) => {
684
+ const page = describe(toRel(file));
685
+ return page !== null && !fs3.existsSync(page.absFile);
686
+ };
687
+ const rewrite = () => {
688
+ setDraftArtifacts(root, { hmr: true, pages: [...pages.values()] });
689
+ generateArtifacts({ root, model: scanProject(root) });
690
+ };
691
+ server.httpServer?.once("close", () => {
692
+ if (pages.size === 0) return;
693
+ pages.clear();
694
+ try {
695
+ rewrite();
696
+ } catch {
697
+ }
698
+ });
699
+ const resolvable = async (rel) => {
700
+ const container = server.environments?.client?.pluginContainer;
701
+ if (!container) return true;
702
+ try {
703
+ const importer = path6.join(vantageDir, "route-tree.gen.ts");
704
+ return await container.resolveId(`../${rel}`, importer) != null;
705
+ } catch {
706
+ return false;
707
+ }
708
+ };
709
+ const routes = {
710
+ isNewPage,
711
+ async ensure(file) {
712
+ const rel = toRel(file);
713
+ const page = describe(rel);
714
+ if (!page || fs3.existsSync(page.absFile)) return null;
715
+ if (pages.has(rel)) return { route: pages.get(rel).routePath };
716
+ const taken = [...scanProject(root).pages, ...pages.values()].some(
717
+ (p) => p.routePath === page.routePath && p.file !== rel
718
+ );
719
+ if (taken) return null;
720
+ if (!await resolvable(rel)) return null;
721
+ pages.set(rel, page);
722
+ rewrite();
723
+ return { route: page.routePath };
724
+ },
725
+ async release(file, { committed: wasCommitted }) {
726
+ const rel = toRel(file);
727
+ if (wasCommitted) committed.set(rel, Date.now() + COMMIT_WINDOW_MS);
728
+ if (!pages.delete(rel) && !wasCommitted) return;
729
+ rewrite();
730
+ },
731
+ isSuppressed(file) {
732
+ const rel = toRel(file);
733
+ if (pages.has(rel)) return true;
734
+ const until = committed.get(rel);
735
+ if (until === void 0) return false;
736
+ if (Date.now() <= until) return true;
737
+ committed.delete(rel);
738
+ return false;
739
+ }
740
+ };
741
+ instances.set(server, routes);
742
+ return routes;
743
+ }
744
+
745
+ // src/vite/draft/skeleton.ts
746
+ var SKELETON = '<div data-vantage-skeleton className="animate-pulse rounded-md bg-muted" style={{ minHeight: "4rem", width: "100%" }} />';
747
+ function declareMissingComponents(source, fileName) {
748
+ if (!/\.[jt]sx$/i.test(fileName)) return source;
749
+ const sf = parseSource(source, fileName);
750
+ const used = usedComponents(sf);
751
+ if (used.size === 0) return source;
752
+ const bound = boundNames(sf);
753
+ const typed = /\.tsx$/i.test(fileName);
754
+ const lines = [];
755
+ for (const [name, member] of used) {
756
+ if (bound.has(name)) continue;
757
+ lines.push(
758
+ member ? (
759
+ // `<Card.Header>`: every property of the placeholder is the placeholder.
760
+ `const ${name}${typed ? ": any" : ""} = new Proxy(function ${name}() { return ${SKELETON} }, { get: (target, key) => (typeof key === "string" ? target : undefined) })`
761
+ ) : `function ${name}(_props${typed ? ": any" : ""}) { return ${SKELETON} }`
762
+ );
763
+ }
764
+ if (lines.length === 0) return source;
765
+ return `${source}${source.endsWith("\n") ? "" : "\n"}${lines.join("\n")}
766
+ `;
767
+ }
768
+ function relativeImports(source, fileName) {
769
+ const found = /* @__PURE__ */ new Map();
770
+ for (const stmt of parseSource(source, fileName).statements) {
771
+ if (!ts.isImportDeclaration(stmt) || !ts.isStringLiteral(stmt.moduleSpecifier)) continue;
772
+ const specifier = stmt.moduleSpecifier.text;
773
+ if (!specifier.startsWith(".")) continue;
774
+ const names = found.get(specifier) ?? /* @__PURE__ */ new Set();
775
+ found.set(specifier, names);
776
+ const clause = stmt.importClause;
777
+ if (!clause || clause.isTypeOnly) continue;
778
+ if (clause.name) names.add("default");
779
+ if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
780
+ for (const el of clause.namedBindings.elements) {
781
+ if (!el.isTypeOnly) names.add((el.propertyName ?? el.name).text);
782
+ }
783
+ }
784
+ }
785
+ return found;
786
+ }
787
+ function usedComponents(sf) {
788
+ const used = /* @__PURE__ */ new Map();
789
+ const visit = (node) => {
790
+ if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
791
+ let tag = node.tagName;
792
+ let member = false;
793
+ while (ts.isPropertyAccessExpression(tag)) {
794
+ tag = tag.expression;
795
+ member = true;
796
+ }
797
+ if (ts.isIdentifier(tag) && /^[A-Z]/.test(tag.text)) used.set(tag.text, member || (used.get(tag.text) ?? false));
798
+ }
799
+ ts.forEachChild(node, visit);
800
+ };
801
+ visit(sf);
802
+ return used;
803
+ }
804
+ function draftTailwind(root) {
805
+ const dir = path6.join(root, VANTAGE_DIR, "draft-tailwind");
806
+ const runtimeCss = path6.join(root, VANTAGE_DIR, "runtime.css");
807
+ const mirrorOf = (file) => path6.join(dir, path6.relative(root, file).split(path6.sep).join("__"));
808
+ return {
809
+ stylesheet: runtimeCss,
810
+ owns: (file) => file.startsWith(dir + path6.sep),
811
+ reset() {
812
+ fs3.rmSync(dir, { recursive: true, force: true });
813
+ fs3.mkdirSync(dir, { recursive: true });
814
+ },
815
+ transformCss(code, id) {
816
+ if (id.split("?")[0] !== runtimeCss) return null;
817
+ return `${code}${code.endsWith("\n") ? "" : "\n"}@source ${JSON.stringify(dir)};
818
+ `;
819
+ },
820
+ write(file, content) {
821
+ const mirror = mirrorOf(file);
822
+ if (fs3.existsSync(mirror) && fs3.readFileSync(mirror, "utf8") === content) return false;
823
+ fs3.writeFileSync(mirror, content);
824
+ return true;
825
+ },
826
+ remove(file) {
827
+ fs3.rmSync(mirrorOf(file), { force: true });
828
+ }
829
+ };
830
+ }
831
+
832
+ // src/vite/draft/visible.ts
833
+ function renderedContent(source, fileName = "draft.tsx") {
834
+ const sf = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
835
+ const component = defaultComponent(sf);
836
+ if (!component?.body) return null;
837
+ const roots = [];
838
+ if (ts.isBlock(component.body)) {
839
+ const visit = (node) => {
840
+ if (ts.isFunctionLike(node)) return;
841
+ if (ts.isReturnStatement(node) && node.expression) roots.push(node.expression);
842
+ ts.forEachChild(node, visit);
843
+ };
844
+ ts.forEachChild(component.body, visit);
845
+ } else {
846
+ roots.push(component.body);
847
+ }
848
+ if (roots.length === 0) return 0;
849
+ const jsxRoots = roots.map(unwrap).filter(isJsx);
850
+ if (jsxRoots.length < roots.length) return null;
851
+ let leaves = 0;
852
+ const count = (node) => {
853
+ if (ts.isJsxText(node)) {
854
+ if (node.text.trim() !== "") leaves++;
855
+ return;
856
+ }
857
+ if (ts.isJsxExpression(node)) {
858
+ if (node.expression && !ts.isJsxAttribute(node.parent)) leaves++;
859
+ return;
860
+ }
861
+ if (ts.isJsxSelfClosingElement(node) || ts.isJsxOpeningElement(node)) {
862
+ if (isComponentTag(node.tagName) && node.attributes.properties.length > 0) leaves++;
863
+ return;
864
+ }
865
+ ts.forEachChild(node, count);
866
+ };
867
+ for (const root of jsxRoots) count(root);
868
+ return leaves;
869
+ }
870
+ function blanksScreen(next, shown) {
871
+ return renderedContent(next) === 0 && renderedContent(shown) !== 0;
872
+ }
873
+ function defaultComponent(sf) {
874
+ const functions = /* @__PURE__ */ new Map();
875
+ let exported;
876
+ for (const stmt of sf.statements) {
877
+ if (ts.isFunctionDeclaration(stmt)) {
878
+ const isDefault = stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword);
879
+ if (isDefault) exported = stmt;
880
+ else if (stmt.name) functions.set(stmt.name.text, stmt);
881
+ } else if (ts.isVariableStatement(stmt)) {
882
+ for (const decl of stmt.declarationList.declarations) {
883
+ const init = decl.initializer && unwrap(decl.initializer);
884
+ if (ts.isIdentifier(decl.name) && init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init)))
885
+ functions.set(decl.name.text, init);
886
+ }
887
+ } else if (ts.isExportAssignment(stmt) && !stmt.isExportEquals) {
888
+ const expr = unwrap(stmt.expression);
889
+ if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) exported = expr;
890
+ else if (ts.isIdentifier(expr)) exported = expr.text;
891
+ }
892
+ }
893
+ return typeof exported === "string" ? functions.get(exported) : exported;
894
+ }
895
+ function unwrap(node) {
896
+ while (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isSatisfiesExpression(node))
897
+ node = node.expression;
898
+ return node;
899
+ }
900
+ function isJsx(node) {
901
+ return ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node);
902
+ }
903
+ function isComponentTag(tag) {
904
+ return !ts.isIdentifier(tag) || /^[A-Z]/.test(tag.text);
905
+ }
906
+
907
+ // src/vite/draft/plugin.ts
908
+ var DRAFT_ENDPOINT = "/__vantage_draft";
909
+ var DRAFT_TOKEN_HEADER = "x-vantage-draft-token";
910
+ var DRAFT_STATE_EVENT = "vantage:draft-state";
911
+ var DRAFT_PAGE_EVENT = "vantage:draft-page";
912
+ var DRAFT_PAGE_CLOSED_EVENT = "vantage:draft-page-closed";
913
+ var DRAFT_RENDER_ERROR_EVENT = "vantage:draft-render-error";
914
+ var DRAFT_SYNC_EVENT = "vantage:draft-sync";
915
+ var DRAFT_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs"];
916
+ var DRAFTABLE_EXTENSIONS = [".ts", ".tsx"];
917
+ var MAX_BODY_BYTES = 1024 * 1024;
918
+ var DRAFT_IDLE_DISCARD_MS = 6e4;
919
+ var ROLLBACK_DEBOUNCE_MS = 150;
920
+ var PREV_QUERY = "vantage-draft-prev";
921
+ var SKELETON_PREFIX = "\0vantage-draft-skeleton:";
922
+ function draftPreviewPlugin(options) {
923
+ const root = path6.resolve(options.root);
924
+ const token = options.token ?? process.env.VANTAGE_DRAFT_TOKEN;
925
+ const createRoutes = options.createRoutes ?? createDraftRoutes;
926
+ const idleDiscardMs = options.idleDiscardMs ?? DRAFT_IDLE_DISCARD_MS;
927
+ let enabled = false;
928
+ let tailwind;
929
+ let routes;
930
+ let server;
931
+ const drafts = /* @__PURE__ */ new Map();
932
+ const newFiles = /* @__PURE__ */ new Set();
933
+ const drafted = /* @__PURE__ */ new Set();
934
+ const ensuredPages = /* @__PURE__ */ new Map();
935
+ const lastSeq = /* @__PURE__ */ new Map();
936
+ const idleTimers = /* @__PURE__ */ new Map();
937
+ const rolledBackAt = /* @__PURE__ */ new Map();
938
+ const skeletons = /* @__PURE__ */ new Map();
939
+ const borrowed = new BorrowedVersions(PREV_QUERY);
940
+ let lastApplied;
941
+ let lastStateKey = "";
942
+ let queue = Promise.resolve();
943
+ const enqueue = (task) => {
944
+ const run = queue.then(task);
945
+ queue = run.catch(() => {
946
+ });
947
+ return run;
948
+ };
949
+ const waiting = [];
950
+ const isDraftRequest = (req) => !req.final && !req.discard;
951
+ const SUPERSEDED = { applied: false, reason: "superseded" };
952
+ const submit = (req) => new Promise((resolve, reject) => {
953
+ const key = typeof req.path === "string" && req.path !== "" ? path6.resolve(root, req.path) : void 0;
954
+ if (key !== void 0) {
955
+ if (!isDraftRequest(req)) {
956
+ for (let i = waiting.length - 1; i >= 0; i--) {
957
+ const job2 = waiting[i];
958
+ if (job2.key !== key || !isDraftRequest(job2.req)) continue;
959
+ waiting.splice(i, 1);
960
+ job2.settle(SUPERSEDED);
961
+ }
962
+ } else {
963
+ const last = waiting.findLast((job2) => job2.key === key);
964
+ if (last !== void 0 && isDraftRequest(last.req)) {
965
+ if (isOlder(req, last.req)) return resolve({ applied: false, reason: "stale" });
966
+ last.settle(SUPERSEDED);
967
+ last.req = req;
968
+ last.settle = resolve;
969
+ last.fail = reject;
970
+ return;
971
+ }
972
+ }
973
+ }
974
+ const job = { key, req, settle: resolve, fail: reject };
975
+ waiting.push(job);
976
+ void enqueue(async () => {
977
+ const at = waiting.indexOf(job);
978
+ if (at === -1) return;
979
+ waiting.splice(at, 1);
980
+ try {
981
+ job.settle(await apply(job.req));
982
+ } catch (err) {
983
+ job.fail(err);
984
+ }
985
+ });
986
+ });
987
+ const relOf = (file) => path6.relative(root, file).split(path6.sep).join("/");
988
+ const shown = (file) => drafts.get(file)?.at(-1);
989
+ const diskText = (file) => {
990
+ try {
991
+ return fs3.readFileSync(file, "utf8");
992
+ } catch {
993
+ return void 0;
994
+ }
995
+ };
996
+ const candidatesOf = (base) => [
997
+ base,
998
+ ...DRAFT_EXTENSIONS.map((ext) => base + ext),
999
+ ...DRAFT_EXTENSIONS.map((ext) => path6.join(base, "index" + ext))
1000
+ ];
1001
+ const skeletonId = (base) => {
1002
+ const ext = path6.extname(base);
1003
+ return SKELETON_PREFIX + (DRAFT_EXTENSIONS.includes(ext) ? base.slice(0, -ext.length) : base);
1004
+ };
1005
+ const isWritten = (base) => candidatesOf(base).some((c) => newFiles.has(c) || fs3.existsSync(c));
1006
+ const registerSkeletons = (file, source, rel) => {
1007
+ const grown = [];
1008
+ const before = /* @__PURE__ */ new Map();
1009
+ for (const [specifier, names] of relativeImports(source, rel)) {
1010
+ const ext = path6.extname(specifier);
1011
+ if (ext !== "" && !DRAFT_EXTENSIONS.includes(ext)) continue;
1012
+ const base = path6.resolve(path6.dirname(file), specifier);
1013
+ if (isWritten(base)) continue;
1014
+ const id = skeletonId(base);
1015
+ const known = skeletons.get(id);
1016
+ if (!known) {
1017
+ before.set(id, void 0);
1018
+ skeletons.set(id, new Set(names));
1019
+ grown.push(id);
1020
+ } else if ([...names].some((n) => !known.has(n))) {
1021
+ if (!before.has(id)) before.set(id, new Set(known));
1022
+ for (const n of names) known.add(n);
1023
+ grown.push(id);
1024
+ }
1025
+ }
1026
+ const undo = () => {
1027
+ for (const [id, names] of before) {
1028
+ if (names === void 0) skeletons.delete(id);
1029
+ else skeletons.set(id, names);
1030
+ }
1031
+ };
1032
+ return { grown, undo };
1033
+ };
1034
+ const resolveTarget = (rel) => {
1035
+ if (typeof rel !== "string" || rel === "") return "path is required";
1036
+ const file = path6.resolve(root, rel);
1037
+ const relPath = path6.relative(root, file);
1038
+ if (relPath === "" || relPath.startsWith("..") || path6.isAbsolute(relPath)) return "path is outside the project";
1039
+ const segments = relPath.split(path6.sep);
1040
+ if (segments[0] === "server") return "server/ is not previewed";
1041
+ if (segments.some((s) => s === "node_modules" || s.startsWith("."))) return "path is not a project source";
1042
+ if (!DRAFTABLE_EXTENSIONS.includes(path6.extname(file))) return "only .ts and .tsx script modules are previewed";
1043
+ const exists = fs3.existsSync(file);
1044
+ if (exists && fs3.statSync(file).isDirectory()) return "path is a directory";
1045
+ if (exists && !isInside(fs3.realpathSync(root), fs3.realpathSync(file))) return "path is outside the project";
1046
+ return { file, rel: segments.join("/"), url: "/" + segments.join("/"), exists };
1047
+ };
1048
+ const modulesOf = (file) => [
1049
+ ...server.environments.client.moduleGraph.getModulesByFile(file) ?? []
1050
+ ].filter((mod) => mod.id !== null && !mod.url.includes(`${PREV_QUERY}=`));
1051
+ const invalidate = (file) => {
1052
+ const graph = server.environments.client.moduleGraph;
1053
+ for (const mod of modulesOf(file)) graph.invalidateModule(mod);
1054
+ };
1055
+ const restyle = async () => {
1056
+ const client = server.environments.client;
1057
+ for (const mod of client.moduleGraph.getModulesByFile(tailwind.stylesheet) ?? []) await client.reloadModule(mod);
1058
+ };
1059
+ const reachable = (mod) => mod.importers.size > 0 || mod.isSelfAccepting === true;
1060
+ const pushUpdate = async (file) => {
1061
+ for (const mod of modulesOf(file)) if (reachable(mod)) await server.environments.client.reloadModule(mod);
1062
+ };
1063
+ const draftState = () => {
1064
+ const files = [...drafts.keys()].map(relOf).sort();
1065
+ return { active: files.length > 0, files };
1066
+ };
1067
+ const notifyState = () => {
1068
+ const state = draftState();
1069
+ const key = state.files.join("\n");
1070
+ if (key === lastStateKey) return;
1071
+ lastStateKey = key;
1072
+ server.environments.client.hot.send(DRAFT_STATE_EVENT, state);
1073
+ };
1074
+ const sendState = (client) => {
1075
+ (client ?? server.environments.client.hot).send(DRAFT_STATE_EVENT, draftState());
1076
+ };
1077
+ const forget = async (file, opts) => {
1078
+ drafts.delete(file);
1079
+ rolledBackAt.delete(file);
1080
+ borrowed.drop(file);
1081
+ tailwind.remove(file);
1082
+ newFiles.delete(file);
1083
+ clearTimeout(idleTimers.get(file));
1084
+ idleTimers.delete(file);
1085
+ const route = ensuredPages.get(file);
1086
+ if (route === void 0) return;
1087
+ ensuredPages.delete(file);
1088
+ await routes.release(file, opts);
1089
+ if (!opts.committed && !isDynamicRoute(route)) server.environments.client.hot.send(DRAFT_PAGE_CLOSED_EVENT, { route });
1090
+ };
1091
+ const touchIdle = (target) => {
1092
+ clearTimeout(idleTimers.get(target.file));
1093
+ const timer = setTimeout(() => {
1094
+ idleTimers.delete(target.file);
1095
+ void enqueue(() => discard(target)).catch(() => {
1096
+ });
1097
+ }, idleDiscardMs);
1098
+ timer.unref();
1099
+ idleTimers.set(target.file, timer);
1100
+ };
1101
+ const apply = async (req) => {
1102
+ const target = resolveTarget(req.path);
1103
+ if (typeof target === "string") return { applied: false, reason: target };
1104
+ if (typeof req.seq === "number" && Number.isFinite(req.seq)) {
1105
+ if (req.seq < (lastSeq.get(target.file) ?? -Infinity)) return { applied: false, reason: "stale" };
1106
+ lastSeq.set(target.file, req.seq);
1107
+ }
1108
+ if (req.discard) return discard(target);
1109
+ if (req.final) return finalize(target);
1110
+ const result = await draft(target, req);
1111
+ if (drafts.has(target.file)) touchIdle(target);
1112
+ return result;
1113
+ };
1114
+ const finalize = async ({ file }) => {
1115
+ if (!fs3.existsSync(file)) {
1116
+ const had = drafts.has(file);
1117
+ await forget(file, { committed: false });
1118
+ invalidate(file);
1119
+ notifyState();
1120
+ return { applied: false, reason: had ? "file was not written" : "file does not exist" };
1121
+ }
1122
+ await forget(file, { committed: true });
1123
+ notifyState();
1124
+ invalidate(file);
1125
+ await pushUpdate(file);
1126
+ await refreshSkeletons([], file);
1127
+ return { applied: true };
1128
+ };
1129
+ const discard = async ({ file }) => {
1130
+ if (!drafts.has(file)) return { applied: false, reason: "no draft" };
1131
+ await forget(file, { committed: false });
1132
+ notifyState();
1133
+ invalidate(file);
1134
+ if (fs3.existsSync(file)) await pushUpdate(file);
1135
+ return { applied: true };
1136
+ };
1137
+ const draft = async (target, req) => {
1138
+ const { file, rel, url, exists } = target;
1139
+ if (typeof req.content !== "string") return { applied: false, reason: "content is required" };
1140
+ const pageDir = options.getModel().pageDir;
1141
+ const previous = shown(file);
1142
+ const base = previous?.served ?? diskText(file);
1143
+ const page = isPageModule(rel, pageDir);
1144
+ const newPage = !exists && page && routes.isNewPage(file);
1145
+ const diskText0 = diskText(file);
1146
+ const diskExports = page || diskText0 === void 0 ? /* @__PURE__ */ new Set() : exportNames(diskText0, rel);
1147
+ const completedDraft = completeDraft(req.content, {
1148
+ path: rel,
1149
+ pageDir,
1150
+ requireExport: page || diskExports.size === 0
1151
+ });
1152
+ if (completedDraft === null) return { applied: false, reason: "draft cannot be completed yet" };
1153
+ const withSkeletons = declareMissingComponents(completedDraft, rel);
1154
+ if (withSkeletons === previous?.completed) return { applied: true, reason: "unchanged" };
1155
+ const undeclared = undeclaredNames(withSkeletons, rel);
1156
+ if (undeclared.length > 0) return { applied: false, reason: `undeclared: ${undeclared.slice(0, 3).join(", ")}` };
1157
+ if (page && base !== void 0 && blanksScreen(withSkeletons, base))
1158
+ return { applied: false, reason: "renders nothing yet" };
1159
+ let completed = withSkeletons;
1160
+ let borrowSource;
1161
+ if (!page) {
1162
+ const have = exportNames(withSkeletons, rel);
1163
+ const missing = [...diskExports].filter((name) => !have.has(name));
1164
+ if (missing.length > 0) {
1165
+ const source = borrowed.sourceFor(file, base);
1166
+ const prevUrl = borrowed.urlFor(file, url, source);
1167
+ completed = stubExports(withSkeletons, diskExports, prevUrl, rel);
1168
+ if (completed.includes(prevUrl)) borrowSource = source;
1169
+ }
1170
+ }
1171
+ if (completed === previous?.served) return { applied: true, reason: "unchanged" };
1172
+ if (previous === void 0 && completed === diskText0) return { applied: true, reason: "unchanged" };
1173
+ if (base !== void 0) {
1174
+ const next = exportNames(completed, rel);
1175
+ if ([...exportNames(base, rel)].some((name) => !next.has(name))) return { applied: false, reason: "missing-exports" };
1176
+ }
1177
+ const version = { served: completed, completed: withSkeletons, borrowSource };
1178
+ drafted.add(file);
1179
+ const history = drafts.get(file) ?? [];
1180
+ drafts.set(file, [...history, version].slice(-8));
1181
+ if (!exists) newFiles.add(file);
1182
+ const { grown: grownSkeletons, undo: undoSkeletons } = registerSkeletons(file, completed, rel);
1183
+ invalidate(file);
1184
+ const revert = () => {
1185
+ if (history.length === 0) {
1186
+ drafts.delete(file);
1187
+ newFiles.delete(file);
1188
+ } else drafts.set(file, history);
1189
+ undoSkeletons();
1190
+ invalidate(file);
1191
+ };
1192
+ try {
1193
+ await server.environments.client.transformRequest(url);
1194
+ } catch (err) {
1195
+ revert();
1196
+ return { applied: false, reason: firstLine(err) };
1197
+ }
1198
+ await refreshSkeletons(grownSkeletons, exists ? void 0 : file);
1199
+ let route;
1200
+ if (newPage && !ensuredPages.has(file)) {
1201
+ const ensured = await routes.ensure(file);
1202
+ if (!ensured) {
1203
+ revert();
1204
+ return { applied: false, reason: "route could not be created" };
1205
+ }
1206
+ ensuredPages.set(file, ensured.route);
1207
+ route = ensured.route;
1208
+ }
1209
+ borrowed.shown(file, borrowSource);
1210
+ const styled = tailwind.write(file, completed);
1211
+ lastApplied = file;
1212
+ notifyState();
1213
+ if (route !== void 0) {
1214
+ if (!isDynamicRoute(route)) server.environments.client.hot.send(DRAFT_PAGE_EVENT, { route });
1215
+ return { applied: true, route, created: true };
1216
+ }
1217
+ if (styled) await restyle();
1218
+ await pushUpdate(file);
1219
+ return { applied: true };
1220
+ };
1221
+ const refreshSkeletons = async (grown, written) => {
1222
+ const graph = server.environments.client.moduleGraph;
1223
+ for (const id of grown) {
1224
+ const mod2 = graph.getModuleById(id);
1225
+ if (!mod2) continue;
1226
+ graph.invalidateModule(mod2);
1227
+ await server.environments.client.reloadModule(mod2);
1228
+ }
1229
+ if (written === void 0) return;
1230
+ const stand = skeletonId(written);
1231
+ skeletons.delete(stand);
1232
+ const mod = graph.getModuleById(stand);
1233
+ if (!mod) return;
1234
+ const importers = [...mod.importers];
1235
+ graph.invalidateModule(mod);
1236
+ for (const importer of importers) {
1237
+ graph.invalidateModule(importer);
1238
+ await server.environments.client.reloadModule(importer);
1239
+ }
1240
+ };
1241
+ const renderError = async (data) => {
1242
+ if (!enabled) return;
1243
+ const file = (data.file ? locate(data.file) : void 0) ?? lastApplied;
1244
+ const history = file === void 0 ? void 0 : drafts.get(file);
1245
+ if (file === void 0 || history === void 0) return;
1246
+ const now = Date.now();
1247
+ if (now - (rolledBackAt.get(file) ?? 0) < ROLLBACK_DEBOUNCE_MS) return;
1248
+ rolledBackAt.set(file, now);
1249
+ history.pop();
1250
+ const before = history.at(-1);
1251
+ if (before === void 0) {
1252
+ await forget(file, { committed: false });
1253
+ } else {
1254
+ borrowed.shown(file, before.borrowSource);
1255
+ if (tailwind.write(file, before.served)) await restyle();
1256
+ }
1257
+ notifyState();
1258
+ invalidate(file);
1259
+ if (before !== void 0 || fs3.existsSync(file)) await pushUpdate(file);
1260
+ };
1261
+ const locate = (name) => {
1262
+ const clean = name.split("?")[0];
1263
+ const candidates = [path6.resolve(root, clean.replace(/^\//, "")), clean];
1264
+ return candidates.find((c) => drafts.has(c));
1265
+ };
1266
+ const authorized = (req) => {
1267
+ if (token === void 0 || token === "") return isLoopback(req) && !isForwarded(req);
1268
+ const sent = req.headers[DRAFT_TOKEN_HEADER];
1269
+ return typeof sent === "string" && sameSecret(sent, token);
1270
+ };
1271
+ const handle = async (req, res) => {
1272
+ const send = (status, result) => {
1273
+ res.statusCode = status;
1274
+ res.setHeader("Content-Type", "application/json");
1275
+ res.end(JSON.stringify(result));
1276
+ };
1277
+ if (!authorized(req)) {
1278
+ const withToken = token !== void 0 && token !== "";
1279
+ return send(withToken ? 401 : 403, { applied: false, reason: withToken ? "invalid token" : "loopback only" });
1280
+ }
1281
+ if ((token === void 0 || token === "") && !String(req.headers["content-type"]).startsWith("application/json"))
1282
+ return send(415, { applied: false, reason: "content-type must be application/json" });
1283
+ let body;
1284
+ try {
1285
+ body = JSON.parse(await readBody(req));
1286
+ } catch (err) {
1287
+ if (err instanceof BodyTooLarge) return send(413, { applied: false, reason: err.message });
1288
+ return send(400, { applied: false, reason: firstLine(err) });
1289
+ }
1290
+ if (typeof body !== "object" || body === null || Array.isArray(body))
1291
+ return send(400, { applied: false, reason: "body must be a JSON object" });
1292
+ const request = body;
1293
+ if (typeof request.path !== "string" || request.path === "")
1294
+ return send(400, { applied: false, reason: "path is required" });
1295
+ try {
1296
+ const result = await submit(request);
1297
+ send(result.applied === false && REFUSED_PATH.test(result.reason ?? "") ? 400 : 200, result);
1298
+ } catch (err) {
1299
+ send(500, { applied: false, reason: firstLine(err) });
1300
+ }
1301
+ };
1302
+ return {
1303
+ name: "vantage:draft-preview",
1304
+ apply: "serve",
1305
+ enforce: "pre",
1306
+ api: { renderError },
1307
+ async configureServer(s) {
1308
+ if (!await loadTypeScript(root)) {
1309
+ console.warn(
1310
+ "[vantage] draft preview is off: `typescript` was not found in this project. Install it as a devDependency to preview unfinished files."
1311
+ );
1312
+ return;
1313
+ }
1314
+ enabled = true;
1315
+ server = s;
1316
+ routes = createRoutes(s, options.getModel());
1317
+ tailwind = draftTailwind(root);
1318
+ tailwind.reset();
1319
+ s.middlewares.use(DRAFT_ENDPOINT, (req, res, next) => {
1320
+ if (req.method !== "POST") return next();
1321
+ if ((req.url ?? "/").split("?")[0] !== "/") {
1322
+ res.statusCode = 404;
1323
+ res.setHeader("Content-Type", "application/json");
1324
+ return void res.end(JSON.stringify({ applied: false, reason: "not found" }));
1325
+ }
1326
+ void handle(req, res);
1327
+ });
1328
+ const hot = s.environments.client.hot;
1329
+ hot.on(DRAFT_RENDER_ERROR_EVENT, (data) => {
1330
+ void enqueue(() => renderError(data ?? {})).catch(() => {
1331
+ });
1332
+ });
1333
+ hot.on(
1334
+ "vite:client:connect",
1335
+ (_data, client) => sendState(client)
1336
+ );
1337
+ hot.on(
1338
+ DRAFT_SYNC_EVENT,
1339
+ (_data, client) => sendState(client)
1340
+ );
1341
+ },
1342
+ // A draft file that is not on disk yet still has to resolve for the modules importing it.
1343
+ resolveId(source, importer) {
1344
+ if (newFiles.size === 0 && skeletons.size === 0) return null;
1345
+ const clean = source.split("?")[0];
1346
+ let base;
1347
+ if (clean.startsWith("/")) base = clean.startsWith(root + "/") ? clean : path6.join(root, clean);
1348
+ else if (clean.startsWith(".") && importer) base = path6.resolve(path6.dirname(importer.split("?")[0]), clean);
1349
+ else return null;
1350
+ const written = candidatesOf(base);
1351
+ const draftFile = written.find((c) => newFiles.has(c));
1352
+ if (draftFile) return draftFile;
1353
+ if (clean.startsWith(".") && importer && skeletons.size > 0) {
1354
+ const id = skeletonId(base);
1355
+ if (skeletons.has(id) && !written.some((c) => fs3.existsSync(c))) return id;
1356
+ }
1357
+ return null;
1358
+ },
1359
+ // Before @tailwindcss/vite reads the root stylesheet.
1360
+ transform: {
1361
+ order: "pre",
1362
+ handler(code, id) {
1363
+ return tailwind?.transformCss(code, id) ?? null;
1364
+ }
1365
+ },
1366
+ load(id) {
1367
+ if (id.startsWith(SKELETON_PREFIX)) return draftSkeletonModuleSource([...skeletons.get(id) ?? []]);
1368
+ if (drafts.size === 0) return null;
1369
+ const prev = new URLSearchParams(id.split("?")[1] ?? "").get(PREV_QUERY);
1370
+ if (prev !== null) return borrowed.get(prev) ?? null;
1371
+ return shown(id.split("?")[0])?.served ?? null;
1372
+ },
1373
+ // The borrowed versions share the drafted file but are not what changed.
1374
+ hotUpdate({ modules, file }) {
1375
+ if (tailwind?.owns(file)) return [];
1376
+ if (enabled && file === path6.join(root, VANTAGE_DIR, "client-entry.tsx")) {
1377
+ restoreClientEntry(root);
1378
+ return [];
1379
+ }
1380
+ const kept = modules.filter(
1381
+ (mod) => mod.id !== null && !mod.url.includes(`${PREV_QUERY}=`) && (!drafted.has(file) || reachable(mod))
1382
+ );
1383
+ if (kept.length !== modules.length) return kept;
1384
+ }
1385
+ };
1386
+ }
1387
+ function stubExports(source, expected, prevUrl, fileName) {
1388
+ const have = exportNames(source, fileName);
1389
+ const declared = topLevelNames(source, fileName);
1390
+ const jsx = /\.tsx$/i.test(fileName);
1391
+ const local = [];
1392
+ const borrowed = [];
1393
+ for (const name of expected) {
1394
+ if (have.has(name)) continue;
1395
+ if (name !== "default" && declared.has(name)) local.push(name);
1396
+ else borrowed.push(name);
1397
+ }
1398
+ const isComponent = (name) => jsx && /^[A-Z]/.test(name);
1399
+ const wrapped = borrowed.filter(isComponent);
1400
+ const reexported = borrowed.filter((name) => !isComponent(name));
1401
+ const stubs = [];
1402
+ if (local.length) stubs.push(`export { ${local.join(", ")} }`);
1403
+ if (reexported.length) stubs.push(`export { ${reexported.join(", ")} } from ${JSON.stringify(prevUrl)}`);
1404
+ for (const name of wrapped) {
1405
+ const alias = `__vantageDraftPrev_${name}`;
1406
+ stubs.push(
1407
+ `import { ${name} as ${alias} } from ${JSON.stringify(prevUrl)}`,
1408
+ `export function ${name}(props: any) { return <${alias} {...props} /> }`
1409
+ );
1410
+ }
1411
+ return stubs.length ? `${source}${source.endsWith("\n") ? "" : "\n"}${stubs.join("\n")}
1412
+ ` : source;
1413
+ }
1414
+ function isInside(dir, file) {
1415
+ const rel = path6.relative(dir, file);
1416
+ return rel !== ".." && !rel.startsWith(".." + path6.sep) && !path6.isAbsolute(rel);
1417
+ }
1418
+ var REFUSED_PATH = /^path is a directory$/;
1419
+ function isDynamicRoute(route) {
1420
+ return /[:*$]/.test(route);
1421
+ }
1422
+ function isOlder(a, b) {
1423
+ return typeof a.seq === "number" && typeof b.seq === "number" && a.seq < b.seq;
1424
+ }
1425
+ function isForwarded(req) {
1426
+ return Object.keys(req.headers).some((name) => name === "forwarded" || name.startsWith("x-forwarded-"));
1427
+ }
1428
+ function isLoopback(req) {
1429
+ const addr = req.socket.remoteAddress;
1430
+ return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
1431
+ }
1432
+ function sameSecret(a, b) {
1433
+ const digest = (v) => createHash("sha256").update(v).digest();
1434
+ return timingSafeEqual(digest(a), digest(b));
1435
+ }
1436
+ var BodyTooLarge = class extends Error {
1437
+ constructor() {
1438
+ super("draft is too large");
1439
+ }
1440
+ };
1441
+ function readBody(req) {
1442
+ return new Promise((resolve, reject) => {
1443
+ const chunks = [];
1444
+ let size = 0;
1445
+ req.on("data", (chunk) => {
1446
+ size += chunk.length;
1447
+ if (size > MAX_BODY_BYTES) {
1448
+ chunks.length = 0;
1449
+ reject(new BodyTooLarge());
1450
+ return;
1451
+ }
1452
+ chunks.push(chunk);
1453
+ });
1454
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
1455
+ req.on("error", reject);
1456
+ });
1457
+ }
1458
+ function firstLine(err) {
1459
+ const message = err instanceof Error ? err.message : String(err);
1460
+ return message.split("\n").find((l) => l.trim() !== "")?.trim() ?? "transform failed";
1461
+ }
1462
+ var PACKAGE_NAME = "@squadbase/vantage";
1463
+ var NOT_PREBUNDLED = /* @__PURE__ */ new Set([
1464
+ "./server",
1465
+ "./server/node",
1466
+ "./vite",
1467
+ "./theme.css",
1468
+ "./package.json",
1469
+ "./markdown",
1470
+ "./table",
1471
+ "./slide",
1472
+ "./doc"
1473
+ ]);
1474
+ function ownPackageDir() {
1475
+ let dir = path6.dirname(fileURLToPath(import.meta.url));
1476
+ for (; ; ) {
1477
+ const manifest = path6.join(dir, "package.json");
1478
+ if (fs3.existsSync(manifest)) {
1479
+ try {
1480
+ if (JSON.parse(fs3.readFileSync(manifest, "utf8")).name === PACKAGE_NAME) return dir;
1481
+ } catch {
1482
+ }
1483
+ }
1484
+ const parent = path6.dirname(dir);
1485
+ if (parent === dir) return null;
1486
+ dir = parent;
1487
+ }
1488
+ }
1489
+ function packageName(spec) {
1490
+ const parts = spec.split("/");
1491
+ return spec.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
1492
+ }
1493
+ function findPackageDir(fromDir, pkg) {
1494
+ let dir = fromDir;
1495
+ for (; ; ) {
1496
+ const candidate = path6.join(dir, "node_modules", pkg);
1497
+ if (fs3.existsSync(candidate)) return candidate;
1498
+ const parent = path6.dirname(dir);
1499
+ if (parent === dir) return null;
1500
+ dir = parent;
1501
+ }
1502
+ }
1503
+ function resolvesFrom(root, spec) {
1504
+ const pkg = packageName(spec);
1505
+ const dir = findPackageDir(root, pkg);
1506
+ if (!dir) return false;
1507
+ const sub = spec.slice(pkg.length);
1508
+ if (sub === "") return true;
1509
+ let exportsField;
1510
+ try {
1511
+ exportsField = JSON.parse(fs3.readFileSync(path6.join(dir, "package.json"), "utf8")).exports;
1512
+ } catch {
1513
+ return false;
1514
+ }
1515
+ if (exportsField && typeof exportsField === "object" && !Array.isArray(exportsField)) {
1516
+ const keys = Object.keys(exportsField);
1517
+ if (!keys.some((k) => k.startsWith("."))) return false;
1518
+ const wanted = `.${sub}`;
1519
+ return keys.some((key) => {
1520
+ if (key === wanted) return true;
1521
+ const star = key.indexOf("*");
1522
+ if (star < 0) return false;
1523
+ return wanted.startsWith(key.slice(0, star)) && wanted.endsWith(key.slice(star + 1));
1524
+ });
1525
+ }
1526
+ const file = path6.join(dir, sub);
1527
+ return [file, `${file}.js`, `${file}.mjs`, path6.join(file, "index.js")].some((f) => fs3.existsSync(f));
1528
+ }
1529
+ function isInstalled(root) {
1530
+ const dir = findPackageDir(root, PACKAGE_NAME);
1531
+ if (!dir) return false;
1532
+ try {
1533
+ return fs3.realpathSync(dir).split(path6.sep).includes("node_modules");
1534
+ } catch {
1535
+ return false;
1536
+ }
1537
+ }
1538
+ function frameworkSubpaths(exportsField) {
1539
+ return Object.keys(exportsField).filter((key) => key.startsWith(".") && !key.includes("*") && !NOT_PREBUNDLED.has(key)).map((key) => key === "." ? PACKAGE_NAME : `${PACKAGE_NAME}${key.slice(1)}`);
1540
+ }
1541
+ function bareImports(source) {
1542
+ const out = /* @__PURE__ */ new Set();
1543
+ const re = /(?:^|[\n;])\s*(?:import|export)\s+(type\s)?(?:[^'";]*?\sfrom\s*)?['"]([^'"\n]+)['"]/g;
1544
+ for (const m of source.matchAll(re)) {
1545
+ const [, typeOnly, spec] = m;
1546
+ if (typeOnly || !spec || /^(\.|\/|node:|@\/|~|#)/.test(spec)) continue;
1547
+ out.add(spec);
1548
+ }
1549
+ return [...out];
1550
+ }
1551
+ function registryDeps(registryDir) {
1552
+ if (!fs3.existsSync(registryDir)) return [];
1553
+ const out = /* @__PURE__ */ new Set();
1554
+ for (const name of fs3.readdirSync(registryDir)) {
1555
+ if (!/\.(tsx?|jsx?)$/.test(name)) continue;
1556
+ for (const spec of bareImports(fs3.readFileSync(path6.join(registryDir, name), "utf8"))) {
1557
+ if (packageName(spec) !== PACKAGE_NAME) out.add(spec);
1558
+ }
1559
+ }
1560
+ return [...out].sort();
1561
+ }
1562
+ function derivedDeps(root) {
1563
+ const pkgDir = ownPackageDir();
1564
+ if (!pkgDir) return [];
1565
+ const out = registryDeps(path6.join(pkgDir, "registry", "ui"));
1566
+ if (isInstalled(root)) {
1567
+ try {
1568
+ const manifest = JSON.parse(fs3.readFileSync(path6.join(pkgDir, "package.json"), "utf8"));
1569
+ if (manifest.exports && typeof manifest.exports === "object") out.push(...frameworkSubpaths(manifest.exports));
1570
+ } catch {
1571
+ }
1572
+ }
1573
+ return out;
1574
+ }
1575
+
1576
+ // src/vite/index.ts
1577
+ var DEDUPE = ["react", "react-dom", "@tanstack/react-router", "@tanstack/react-query"];
1578
+ var RUNTIME_DEPS = [
1579
+ "react",
1580
+ "react-dom",
1581
+ "react-dom/client",
1582
+ "react/jsx-runtime",
1583
+ "@tanstack/react-router",
1584
+ "@tanstack/react-query"
1585
+ ];
1586
+ var KIT_DEPS = [
1587
+ "@tanstack/react-table",
1588
+ "class-variance-authority",
1589
+ "clsx",
1590
+ "cmdk",
1591
+ "date-fns",
1592
+ "date-fns/locale",
1593
+ "echarts",
1594
+ "lucide-react",
1595
+ "react-day-picker",
1596
+ "tailwind-merge",
1597
+ "@base-ui/react/accordion",
1598
+ "@base-ui/react/button",
1599
+ "@base-ui/react/checkbox",
1600
+ "@base-ui/react/collapsible",
1601
+ "@base-ui/react/dialog",
1602
+ "@base-ui/react/input",
1603
+ "@base-ui/react/menu",
1604
+ "@base-ui/react/merge-props",
1605
+ "@base-ui/react/popover",
1606
+ "@base-ui/react/progress",
1607
+ "@base-ui/react/scroll-area",
1608
+ "@base-ui/react/select",
1609
+ "@base-ui/react/separator",
1610
+ "@base-ui/react/slider",
1611
+ "@base-ui/react/switch",
1612
+ "@base-ui/react/tabs",
1613
+ "@base-ui/react/toggle",
1614
+ "@base-ui/react/toggle-group",
1615
+ "@base-ui/react/tooltip",
1616
+ "@base-ui/react/use-render"
1617
+ ];
1618
+ function optimizeInclude(root, extra) {
1619
+ return [.../* @__PURE__ */ new Set([...RUNTIME_DEPS, ...KIT_DEPS, ...derivedDeps(root), ...extra])].filter(
1620
+ (spec) => resolvesFrom(root, spec)
1621
+ );
1622
+ }
1623
+ var FILE_PAGE_DEPS = ["papaparse", "read-excel-file/browser"];
1624
+ var SLIDE_EXPORT_DEPS = ["html-to-image", "fflate"];
1625
+ function conditionalDeps(model) {
1626
+ return [
1627
+ ...model.pages.some((p) => p.kind === "file") ? FILE_PAGE_DEPS : [],
1628
+ ...model.pages.some((p) => p.variant === "slide") ? SLIDE_EXPORT_DEPS : []
1629
+ ];
1630
+ }
1631
+ function underPageRoot(pageRoot, file) {
1632
+ const rel = path6.relative(pageRoot, file);
1633
+ if (rel.startsWith("..")) return false;
1634
+ const segments = rel.split(path6.sep);
1635
+ return !segments.some((s) => NON_ROUTE_DIRS.has(s) || s.startsWith(".") && s !== "..");
1636
+ }
1637
+ function isPageModuleFile(pageRoot, file) {
1638
+ return underPageRoot(pageRoot, file) && PAGE_EXTENSIONS.some((ext) => file.endsWith(ext));
1639
+ }
1640
+ function isRoutedFile(pageRoot, file) {
1641
+ return isPageModuleFile(pageRoot, file) || isFilePageFile(pageRoot, file);
1642
+ }
1643
+ function isFilePageFile(pageRoot, file) {
1644
+ const lower = file.toLowerCase();
1645
+ return underPageRoot(pageRoot, file) && FILE_PAGE_EXTENSIONS.some((ext) => lower.endsWith(ext));
1646
+ }
1647
+ function isApiFile(root, file) {
1648
+ const rel = path6.relative(root, file);
1649
+ return rel.startsWith(`server${path6.sep}api${path6.sep}`) && /\.(ts|tsx|js)$/.test(file) && !file.endsWith(".d.ts");
1650
+ }
1651
+ function isServerFile(root, file) {
1652
+ const rel = path6.relative(root, file);
1653
+ return rel === "server" || rel.startsWith(`server${path6.sep}`);
1654
+ }
1655
+ function vantagePlugin(options) {
1656
+ const root = path6.resolve(options.root);
1657
+ const vantageDir = path6.join(root, VANTAGE_DIR);
1658
+ let model = options.model ?? scanProject(root);
1659
+ let generated = Boolean(options.artifactsWritten);
1660
+ let shellHtml = null;
1661
+ const pageRoot = () => model.pageDir === "" ? root : path6.join(root, model.pageDir);
1662
+ const emit = () => {
1663
+ generateArtifacts({ root, model });
1664
+ generated = true;
1665
+ shellHtml = null;
1666
+ };
1667
+ const ensureGenerated = () => {
1668
+ if (!generated) emit();
1669
+ };
1670
+ const regenerate = () => {
1671
+ model = scanProject(root);
1672
+ emit();
1673
+ };
1674
+ const core = {
1675
+ name: "vantage:core",
1676
+ enforce: "pre",
1677
+ config() {
1678
+ return {
1679
+ root,
1680
+ appType: "custom",
1681
+ envPrefix: ["PUBLIC_"],
1682
+ resolve: { dedupe: DEDUPE },
1683
+ optimizeDeps: { include: optimizeInclude(root, conditionalDeps(model)) },
1684
+ server: {
1685
+ // Browser console + runtime errors belong in the dev terminal: it is
1686
+ // the feedback surface both humans and agents already watch. Vite 8
1687
+ // forwards them natively — with source-mapped stacks and code frames,
1688
+ // which the hand-rolled beacon bridge this replaces could not do — but
1689
+ // only turns itself on when it detects an agent. Vantage wants it
1690
+ // always. warn/error only: forwarding `log`/`info` too lets one chatty
1691
+ // render loop bury the server's own output.
1692
+ forwardConsole: { unhandledErrors: true, logLevels: ["warn", "error"] }
1693
+ },
1694
+ build: {
1695
+ outDir: path6.join(root, "dist", "client"),
1696
+ emptyOutDir: true,
1697
+ rollupOptions: {
1698
+ input: path6.join(vantageDir, "index.html")
1699
+ }
1700
+ }
1701
+ };
1702
+ },
1703
+ configResolved() {
1704
+ ensureGenerated();
1705
+ },
1706
+ buildStart() {
1707
+ ensureGenerated();
1708
+ },
1709
+ // --- Server-import boundary: client code may never import server/. ---
1710
+ resolveId(source, importer, opts) {
1711
+ if (opts?.ssr) return null;
1712
+ if (!importer) return null;
1713
+ const imp = importer.split("?")[0];
1714
+ if (!imp.startsWith(root)) return null;
1715
+ const relImp = path6.relative(root, imp);
1716
+ if (relImp.startsWith(`server${path6.sep}`) || relImp.startsWith(VANTAGE_DIR) || relImp.includes("node_modules")) {
1717
+ return null;
1718
+ }
1719
+ let target = null;
1720
+ if (source.startsWith(".")) target = path6.resolve(path6.dirname(imp), source);
1721
+ else if (source.startsWith("/")) target = path6.join(root, source.slice(1));
1722
+ else if (source === "server" || source.startsWith("server/")) target = path6.join(root, source);
1723
+ if (!target) return null;
1724
+ const relTarget = path6.relative(root, target);
1725
+ if (relTarget === "server" || relTarget.startsWith(`server${path6.sep}`)) {
1726
+ this.error(
1727
+ `Client module "${relImp}" imports from server/ ("${source}"). server/ code must never reach the client bundle \u2014 move shared code to lib/.`
1728
+ );
1729
+ }
1730
+ return null;
1731
+ },
1732
+ // --- Keep React Fast Refresh working on page modules. ---
1733
+ // `export const page = definePage(...)` is a non-component export, which
1734
+ // makes @vitejs/plugin-react bail out of Fast Refresh (full reload). The
1735
+ // runtime never reads this export (title/description are extracted at
1736
+ // generate time), so we drop the `export` keyword — turning it into a local
1737
+ // const — before the React plugin analyzes the module. Offsets are
1738
+ // preserved (6 spaces for "export") so sourcemaps stay accurate.
1739
+ transform(code, id) {
1740
+ const clean = id.split("?")[0];
1741
+ if (!isPageModuleFile(pageRoot(), clean)) return null;
1742
+ if (!/export\s+const\s+page\b/.test(code)) return null;
1743
+ const out = code.replace(
1744
+ /^([ \t]*)export(\s+const\s+page\b)/gm,
1745
+ (_m, indent, rest) => indent + " " + rest
1746
+ );
1747
+ if (out === code) return null;
1748
+ return { code: out, map: null };
1749
+ },
1750
+ configureServer(server) {
1751
+ const getEnv = () => options.env ?? process.env;
1752
+ const apiMw = createApiDevMiddleware({ server, getModel: () => model, getEnv });
1753
+ server.middlewares.use((req, res, next) => {
1754
+ if (model.hasServer) return apiMw(req, res, next);
1755
+ return next();
1756
+ });
1757
+ const isStylesFile = (file) => path6.relative(pageRoot(), file) === "styles.css";
1758
+ const rootMoved = () => resolvePageRoot(root).dir !== model.pageDir;
1759
+ const onStructural = (file) => {
1760
+ const moved = rootMoved();
1761
+ if (moved || isRoutedFile(pageRoot(), file) || isApiFile(root, file) || isStylesFile(file)) {
1762
+ regenerate();
1763
+ if (!moved && getDraftRoutes(server)?.isSuppressed(file)) return;
1764
+ server.ws.send({ type: "full-reload" });
1765
+ }
1766
+ };
1767
+ const isRouteDir = (dir) => {
1768
+ if (isServerFile(root, dir)) return true;
1769
+ const rel = path6.relative(pageRoot(), dir);
1770
+ if (rel === "" || rel.startsWith("..")) return false;
1771
+ return !rel.split(path6.sep).some((s) => NON_ROUTE_DIRS.has(s) || s.startsWith("."));
1772
+ };
1773
+ server.watcher.on("add", onStructural);
1774
+ server.watcher.on("unlink", onStructural);
1775
+ server.watcher.on("addDir", (dir) => {
1776
+ if (rootMoved() || isRouteDir(dir)) regenerate();
1777
+ });
1778
+ server.watcher.on("unlinkDir", (dir) => {
1779
+ if (!rootMoved() && !isRouteDir(dir)) return;
1780
+ regenerate();
1781
+ server.ws.send({ type: "full-reload" });
1782
+ });
1783
+ server.watcher.on("change", (file) => {
1784
+ if (isServerFile(root, file)) {
1785
+ const mods = server.moduleGraph.getModulesByFile(file);
1786
+ if (mods) for (const m of mods) server.moduleGraph.invalidateModule(m);
1787
+ return;
1788
+ }
1789
+ if (isFilePageFile(pageRoot(), file)) server.ws.send({ type: "full-reload" });
1790
+ });
1791
+ return () => {
1792
+ server.middlewares.use(async (req, res, next) => {
1793
+ if (req.method !== "GET" && req.method !== "HEAD") return next();
1794
+ try {
1795
+ if (shellHtml === null) {
1796
+ const raw = fs3.readFileSync(path6.join(vantageDir, "index.html"), "utf8");
1797
+ const shellUrl = `/${VANTAGE_DIR}/index.html`;
1798
+ shellHtml = await server.transformIndexHtml(shellUrl, raw, req.originalUrl);
1799
+ }
1800
+ res.statusCode = 200;
1801
+ res.setHeader("Content-Type", "text/html");
1802
+ res.end(shellHtml);
1803
+ } catch (err) {
1804
+ next(err);
1805
+ }
1806
+ });
1807
+ };
1808
+ }
1809
+ };
1810
+ const draft = options.draftPreview ? draftPreviewPlugin({
1811
+ root,
1812
+ getModel: () => model,
1813
+ token: typeof options.draftPreview === "object" ? options.draftPreview.token : void 0
1814
+ }) : void 0;
1815
+ return [core, ...draft ? [draft] : [], react(), tailwindcss()];
1816
+ }
1817
+
1818
+ export { vantagePlugin };
1819
+ //# sourceMappingURL=chunk-2ICNHUG6.js.map
1820
+ //# sourceMappingURL=chunk-2ICNHUG6.js.map