@squadbase/vantage 0.6.2-dev1.31accb1 → 0.6.2-dev1.42c4e48

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 (58) 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-MFWRPYKW.js} +7 -7
  4. package/dist/{build-TVKFIVFQ.js.map → build-MFWRPYKW.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-P7W4LR3Z.js → chunk-7DZGJQ3P.js} +3 -3
  8. package/dist/{chunk-P7W4LR3Z.js.map → chunk-7DZGJQ3P.js.map} +1 -1
  9. package/dist/{chunk-U2M6HGKQ.js → chunk-AABMKHEU.js} +4 -4
  10. package/dist/{chunk-U2M6HGKQ.js.map → chunk-AABMKHEU.js.map} +1 -1
  11. package/dist/{chunk-QI3XQKHS.js → chunk-GNXCX4WE.js} +10 -3
  12. package/dist/chunk-GNXCX4WE.js.map +1 -0
  13. package/dist/chunk-IBGOCWJB.js +1716 -0
  14. package/dist/chunk-IBGOCWJB.js.map +1 -0
  15. package/dist/{chunk-LMUACBMA.js → chunk-QEWCYW3I.js} +43 -8
  16. package/dist/chunk-QEWCYW3I.js.map +1 -0
  17. package/dist/{chunk-ZVANIULZ.js → chunk-RNTDBX6S.js} +4 -4
  18. package/dist/{chunk-ZVANIULZ.js.map → chunk-RNTDBX6S.js.map} +1 -1
  19. package/dist/{chunk-PVTHHV7X.js → chunk-V3LF7BE7.js} +27 -5
  20. package/dist/chunk-V3LF7BE7.js.map +1 -0
  21. package/dist/{chunk-DTDVSFRY.js → chunk-XQUSGIDG.js} +17 -3
  22. package/dist/chunk-XQUSGIDG.js.map +1 -0
  23. package/dist/cli.js +12 -11
  24. package/dist/cli.js.map +1 -1
  25. package/dist/client/index.d.ts +32 -3
  26. package/dist/client/index.js +205 -12
  27. package/dist/client/index.js.map +1 -1
  28. package/dist/{dev-GDKATCC7.js → dev-DCTOHQ6W.js} +8 -8
  29. package/dist/dev-DCTOHQ6W.js.map +1 -0
  30. package/dist/{docs-EJJ3BECT.js → docs-JVP4RPKT.js} +3 -3
  31. package/dist/{docs-EJJ3BECT.js.map → docs-JVP4RPKT.js.map} +1 -1
  32. package/dist/{doctor-WQXPXP6K.js → doctor-5E2VEZPK.js} +5 -5
  33. package/dist/{doctor-WQXPXP6K.js.map → doctor-5E2VEZPK.js.map} +1 -1
  34. package/dist/{preview-OGMCNQUO.js → preview-T6CLSQVX.js} +3 -3
  35. package/dist/{preview-OGMCNQUO.js.map → preview-T6CLSQVX.js.map} +1 -1
  36. package/dist/query/index.d.ts +0 -11
  37. package/dist/query/index.js +2 -2
  38. package/dist/{routes-MWBWWOJ2.js → routes-3SGAFDMC.js} +4 -4
  39. package/dist/{routes-MWBWWOJ2.js.map → routes-3SGAFDMC.js.map} +1 -1
  40. package/dist/{search-6Y422SV6.js → search-5LC4XPB5.js} +3 -3
  41. package/dist/{search-6Y422SV6.js.map → search-5LC4XPB5.js.map} +1 -1
  42. package/dist/table/index.js +2 -2
  43. package/dist/{upgrade-HCANX4GQ.js → upgrade-DBBE6GIR.js} +6 -6
  44. package/dist/{upgrade-HCANX4GQ.js.map → upgrade-DBBE6GIR.js.map} +1 -1
  45. package/dist/vite/index.d.ts +10 -0
  46. package/dist/vite/index.js +3 -3
  47. package/docs/ja/changelog.md +5 -0
  48. package/package.json +8 -2
  49. package/theme.css +11 -0
  50. package/dist/add-DY4AXANK.js +0 -6
  51. package/dist/add-DY4AXANK.js.map +0 -1
  52. package/dist/chunk-DTDVSFRY.js.map +0 -1
  53. package/dist/chunk-LMUACBMA.js.map +0 -1
  54. package/dist/chunk-PVTHHV7X.js.map +0 -1
  55. package/dist/chunk-QI3XQKHS.js.map +0 -1
  56. package/dist/chunk-VA776YE5.js +0 -316
  57. package/dist/chunk-VA776YE5.js.map +0 -1
  58. package/dist/dev-GDKATCC7.js.map +0 -1
@@ -8,17 +8,6 @@ export { QueryClient, QueryKey, UseInfiniteQueryOptions, UseMutationOptions, Use
8
8
  */
9
9
  declare function createQueryClient(): QueryClient;
10
10
 
11
- /**
12
- * The one seam for calling the API from client code. All `/api/*` requests go
13
- * through here so a split deployment (client on S3/CloudFront, server on Lambda)
14
- * can point the client at a different origin without touching page code.
15
- *
16
- * The base is read from `import.meta.env.PUBLIC_API_BASE_URL` — a `PUBLIC_`
17
- * prefixed var so it is inlined into the client bundle (see envPrefix in the
18
- * Vite plugin). It can be set in `.env` or injected at build time via
19
- * `vantage build --api-base-url <url>`. When unset it is empty, so requests stay
20
- * same-origin relative paths — identical to hand-written `fetch("/api/...")`.
21
- */
22
11
  /** The configured API base URL (no trailing slash), or "" for same-origin. */
23
12
  declare function apiBaseUrl(): string;
24
13
  /**
@@ -1,4 +1,4 @@
1
- export { ApiError, QueryClient, apiBaseUrl, apiFetch, apiJson, apiPath, apiUrl, keepPreviousData, useApiMutation, useApiQuery, useInfiniteQuery, useIsFetching, useIsMutating, useMutation, useQueries, useQuery, useQueryClient } from '../chunk-PVTHHV7X.js';
2
- export { createQueryClient } from '../chunk-DTDVSFRY.js';
1
+ export { ApiError, QueryClient, apiBaseUrl, apiFetch, apiJson, apiPath, apiUrl, keepPreviousData, useApiMutation, useApiQuery, useInfiniteQuery, useIsFetching, useIsMutating, useMutation, useQueries, useQuery, useQueryClient } from '../chunk-V3LF7BE7.js';
2
+ export { createQueryClient } from '../chunk-XQUSGIDG.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  import { extractPageSpec, extractApiSpec } from './chunk-JKLLFVEU.js';
2
2
  import './chunk-CEXAQQ5W.js';
3
- import { scanProject } from './chunk-ZVANIULZ.js';
4
- import { printJson } from './chunk-QI3XQKHS.js';
3
+ import { scanProject } from './chunk-RNTDBX6S.js';
4
+ import { printJson } from './chunk-GNXCX4WE.js';
5
5
  import './chunk-C2CX6GLX.js';
6
6
  import pc from 'picocolors';
7
7
 
@@ -124,5 +124,5 @@ async function routes(root, args) {
124
124
  }
125
125
 
126
126
  export { routes };
127
- //# sourceMappingURL=routes-MWBWWOJ2.js.map
128
- //# sourceMappingURL=routes-MWBWWOJ2.js.map
127
+ //# sourceMappingURL=routes-3SGAFDMC.js.map
128
+ //# sourceMappingURL=routes-3SGAFDMC.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/routes.ts"],"names":[],"mappings":"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","file":"routes-MWBWWOJ2.js","sourcesContent":["import pc from \"picocolors\"\nimport {\n extractApiSpec,\n extractPageSpec,\n type ApiMethodSpec,\n type PageSpec,\n type RouteParam,\n} from \"../core/route-spec\"\nimport { scanProject } from \"../core/scan\"\nimport type { ApiRoute, PageRoute, RouteModel } from \"../core/types\"\nimport { printJson, type ParsedArgs } from \"./util\"\n\nconst ROUTE_COLUMN = 28\nconst LABEL_COLUMN = 9\n\n/** Print an indented `label value` line under a route. */\nfunction detailLine(indent: string, label: string, value: string): void {\n console.log(`${indent}${pc.dim(label.padEnd(LABEL_COLUMN))}${value}`)\n}\n\n/** Render params as `:id`, `*rest`. */\nfunction formatParams(params: RouteParam[]): string {\n return params.map((p) => (p.kind === \"catchall\" ? `*${p.name}` : `:${p.name}`)).join(\", \")\n}\n\nfunction formatKeys(keys: string[] | undefined): string {\n return keys?.length ? ` { ${keys.join(\", \")} }` : \"\"\n}\n\nfunction printPageSpec(spec: PageSpec): void {\n const indent = \" \"\n if (spec.title) detailLine(indent, \"title\", spec.title)\n if (spec.navLabel) detailLine(indent, \"nav\", spec.navLabel)\n if (spec.description) detailLine(indent, \"desc\", spec.description)\n if (spec.params.length) detailLine(indent, \"params\", formatParams(spec.params))\n}\n\nfunction printApiMethodSpec(method: ApiMethodSpec, params: RouteParam[]): void {\n const indent = \" \"\n console.log(` ${pc.bold(method.method)}`)\n if (params.length) detailLine(indent, \"path\", formatParams(params))\n if (method.query.length) detailLine(indent, \"query\", method.query.join(\", \"))\n if (method.body) detailLine(indent, \"body\", method.body.format + formatKeys(method.body.keys))\n for (const res of method.responses) {\n const parts = [String(res.status), res.contentType].filter(Boolean).join(\" \")\n detailLine(indent, \"response\", parts + formatKeys(res.keys))\n }\n for (const err of method.errors) {\n detailLine(indent, \"error\", `${err.status}${err.message ? ` \"${err.message}\"` : \"\"}`)\n }\n}\n\n/**\n * How a page is rendered, when it is not the plain case. Without this a\n * `.slide.tsx` and a `.tsx` that resolve to the same URL look identical here,\n * and the whole point of `routes` is to show what the scan understood.\n */\nfunction pageBadge(page: PageRoute): string {\n if (page.kind === \"file\") return pc.magenta(` (${(page.fileExt ?? \"\").slice(1)})`)\n if (page.variant) return pc.magenta(` (${page.variant})`)\n return \"\"\n}\n\nfunction printPages(model: RouteModel, detail: boolean): void {\n console.log(pc.bold(\"\\nPages\"))\n if (model.pages.length === 0) console.log(pc.dim(\" (none)\"))\n for (const p of model.pages) {\n console.log(` ${pc.green(p.routePath.padEnd(ROUTE_COLUMN))} ${pc.dim(p.file)}${pageBadge(p)}`)\n if (detail) printPageSpec(extractPageSpec(p))\n }\n\n if (model.layouts.length || model.notFound || model.error) {\n console.log(pc.bold(\"\\nSpecial\"))\n for (const l of model.layouts) {\n const label = \"layout \" + (l.dir === \"\" ? \"/\" : \"/\" + l.dir)\n console.log(` ${pc.cyan(label.padEnd(ROUTE_COLUMN))} ${pc.dim(l.file)}`)\n }\n if (model.notFound) console.log(` ${pc.cyan(\"404\".padEnd(ROUTE_COLUMN))} ${pc.dim(model.notFound)}`)\n if (model.error) console.log(` ${pc.cyan(\"error\".padEnd(ROUTE_COLUMN))} ${pc.dim(model.error)}`)\n }\n}\n\nfunction printApis(model: RouteModel, detail: boolean): void {\n console.log(pc.bold(\"\\nAPI\"))\n if (!model.hasServer) {\n console.log(pc.dim(\" (none — this project has no server/ directory)\"))\n return\n }\n if (model.apis.length === 0) console.log(pc.dim(\" (none)\"))\n for (const a of model.apis) {\n console.log(` ${pc.yellow(a.routePath.padEnd(ROUTE_COLUMN))} ${pc.dim(a.file)}`)\n if (!detail) continue\n const spec = extractApiSpec(a)\n if (spec.methods.length === 0) console.log(` ${pc.dim(\"(no HTTP method handler exported)\")}`)\n for (const method of spec.methods) printApiMethodSpec(method, spec.params)\n }\n}\n\nfunction pageJson(p: PageRoute, detail: boolean) {\n return {\n route: p.routePath,\n file: p.file,\n dynamic: p.dynamic,\n kind: p.kind,\n ...(p.fileExt ? { fileExt: p.fileExt } : {}),\n ...(p.variant ? { variant: p.variant } : {}),\n ...(detail ? { spec: extractPageSpec(p) } : {}),\n }\n}\n\nfunction apiJson(a: ApiRoute, detail: boolean) {\n return {\n route: a.routePath,\n file: a.file,\n params: a.params,\n ...(detail ? { spec: extractApiSpec(a) } : {}),\n }\n}\n\n/**\n * `vantage routes` — show the page and API URL map.\n * `--pages` / `--apis` narrow the map to one side; `--detail` adds the static\n * spec of each route (page path params + definePage meta, API methods with\n * their request input and response shape).\n */\nexport async function routes(root: string, args: ParsedArgs): Promise<number> {\n const model = scanProject(root)\n const onlyPages = Boolean(args.flags.pages)\n const onlyApis = Boolean(args.flags.apis)\n // Neither flag (or both) means \"everything\", so the two are never exclusive.\n const showPages = onlyPages || !onlyApis\n const showApis = onlyApis || !onlyPages\n const detail = Boolean(args.flags.detail)\n\n if (args.flags.json) {\n const payload: Record<string, unknown> = {}\n if (showPages) {\n payload.pages = model.pages.map((p) => pageJson(p, detail))\n payload.layouts = model.layouts.map((l) => ({ dir: l.dir === \"\" ? \"/\" : l.dir, file: l.file }))\n payload.notFound = model.notFound\n payload.error = model.error\n // Files the scan skipped. `check` explains them; listing them here means\n // an agent reading `routes --json` sees them without a second command.\n payload.unrouted = model.unrouted\n }\n if (showApis) {\n payload.apis = model.apis.map((a) => apiJson(a, detail))\n payload.hasServer = model.hasServer\n }\n printJson(payload)\n return 0\n }\n\n if (showPages) printPages(model, detail)\n // Without --apis, an API-less project stays silent (nothing to say about it).\n if (showApis && (model.hasServer || onlyApis)) printApis(model, detail)\n console.log(\"\")\n return 0\n}\n"]}
1
+ {"version":3,"sources":["../src/cli/routes.ts"],"names":[],"mappings":"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","file":"routes-3SGAFDMC.js","sourcesContent":["import pc from \"picocolors\"\nimport {\n extractApiSpec,\n extractPageSpec,\n type ApiMethodSpec,\n type PageSpec,\n type RouteParam,\n} from \"../core/route-spec\"\nimport { scanProject } from \"../core/scan\"\nimport type { ApiRoute, PageRoute, RouteModel } from \"../core/types\"\nimport { printJson, type ParsedArgs } from \"./util\"\n\nconst ROUTE_COLUMN = 28\nconst LABEL_COLUMN = 9\n\n/** Print an indented `label value` line under a route. */\nfunction detailLine(indent: string, label: string, value: string): void {\n console.log(`${indent}${pc.dim(label.padEnd(LABEL_COLUMN))}${value}`)\n}\n\n/** Render params as `:id`, `*rest`. */\nfunction formatParams(params: RouteParam[]): string {\n return params.map((p) => (p.kind === \"catchall\" ? `*${p.name}` : `:${p.name}`)).join(\", \")\n}\n\nfunction formatKeys(keys: string[] | undefined): string {\n return keys?.length ? ` { ${keys.join(\", \")} }` : \"\"\n}\n\nfunction printPageSpec(spec: PageSpec): void {\n const indent = \" \"\n if (spec.title) detailLine(indent, \"title\", spec.title)\n if (spec.navLabel) detailLine(indent, \"nav\", spec.navLabel)\n if (spec.description) detailLine(indent, \"desc\", spec.description)\n if (spec.params.length) detailLine(indent, \"params\", formatParams(spec.params))\n}\n\nfunction printApiMethodSpec(method: ApiMethodSpec, params: RouteParam[]): void {\n const indent = \" \"\n console.log(` ${pc.bold(method.method)}`)\n if (params.length) detailLine(indent, \"path\", formatParams(params))\n if (method.query.length) detailLine(indent, \"query\", method.query.join(\", \"))\n if (method.body) detailLine(indent, \"body\", method.body.format + formatKeys(method.body.keys))\n for (const res of method.responses) {\n const parts = [String(res.status), res.contentType].filter(Boolean).join(\" \")\n detailLine(indent, \"response\", parts + formatKeys(res.keys))\n }\n for (const err of method.errors) {\n detailLine(indent, \"error\", `${err.status}${err.message ? ` \"${err.message}\"` : \"\"}`)\n }\n}\n\n/**\n * How a page is rendered, when it is not the plain case. Without this a\n * `.slide.tsx` and a `.tsx` that resolve to the same URL look identical here,\n * and the whole point of `routes` is to show what the scan understood.\n */\nfunction pageBadge(page: PageRoute): string {\n if (page.kind === \"file\") return pc.magenta(` (${(page.fileExt ?? \"\").slice(1)})`)\n if (page.variant) return pc.magenta(` (${page.variant})`)\n return \"\"\n}\n\nfunction printPages(model: RouteModel, detail: boolean): void {\n console.log(pc.bold(\"\\nPages\"))\n if (model.pages.length === 0) console.log(pc.dim(\" (none)\"))\n for (const p of model.pages) {\n console.log(` ${pc.green(p.routePath.padEnd(ROUTE_COLUMN))} ${pc.dim(p.file)}${pageBadge(p)}`)\n if (detail) printPageSpec(extractPageSpec(p))\n }\n\n if (model.layouts.length || model.notFound || model.error) {\n console.log(pc.bold(\"\\nSpecial\"))\n for (const l of model.layouts) {\n const label = \"layout \" + (l.dir === \"\" ? \"/\" : \"/\" + l.dir)\n console.log(` ${pc.cyan(label.padEnd(ROUTE_COLUMN))} ${pc.dim(l.file)}`)\n }\n if (model.notFound) console.log(` ${pc.cyan(\"404\".padEnd(ROUTE_COLUMN))} ${pc.dim(model.notFound)}`)\n if (model.error) console.log(` ${pc.cyan(\"error\".padEnd(ROUTE_COLUMN))} ${pc.dim(model.error)}`)\n }\n}\n\nfunction printApis(model: RouteModel, detail: boolean): void {\n console.log(pc.bold(\"\\nAPI\"))\n if (!model.hasServer) {\n console.log(pc.dim(\" (none — this project has no server/ directory)\"))\n return\n }\n if (model.apis.length === 0) console.log(pc.dim(\" (none)\"))\n for (const a of model.apis) {\n console.log(` ${pc.yellow(a.routePath.padEnd(ROUTE_COLUMN))} ${pc.dim(a.file)}`)\n if (!detail) continue\n const spec = extractApiSpec(a)\n if (spec.methods.length === 0) console.log(` ${pc.dim(\"(no HTTP method handler exported)\")}`)\n for (const method of spec.methods) printApiMethodSpec(method, spec.params)\n }\n}\n\nfunction pageJson(p: PageRoute, detail: boolean) {\n return {\n route: p.routePath,\n file: p.file,\n dynamic: p.dynamic,\n kind: p.kind,\n ...(p.fileExt ? { fileExt: p.fileExt } : {}),\n ...(p.variant ? { variant: p.variant } : {}),\n ...(detail ? { spec: extractPageSpec(p) } : {}),\n }\n}\n\nfunction apiJson(a: ApiRoute, detail: boolean) {\n return {\n route: a.routePath,\n file: a.file,\n params: a.params,\n ...(detail ? { spec: extractApiSpec(a) } : {}),\n }\n}\n\n/**\n * `vantage routes` — show the page and API URL map.\n * `--pages` / `--apis` narrow the map to one side; `--detail` adds the static\n * spec of each route (page path params + definePage meta, API methods with\n * their request input and response shape).\n */\nexport async function routes(root: string, args: ParsedArgs): Promise<number> {\n const model = scanProject(root)\n const onlyPages = Boolean(args.flags.pages)\n const onlyApis = Boolean(args.flags.apis)\n // Neither flag (or both) means \"everything\", so the two are never exclusive.\n const showPages = onlyPages || !onlyApis\n const showApis = onlyApis || !onlyPages\n const detail = Boolean(args.flags.detail)\n\n if (args.flags.json) {\n const payload: Record<string, unknown> = {}\n if (showPages) {\n payload.pages = model.pages.map((p) => pageJson(p, detail))\n payload.layouts = model.layouts.map((l) => ({ dir: l.dir === \"\" ? \"/\" : l.dir, file: l.file }))\n payload.notFound = model.notFound\n payload.error = model.error\n // Files the scan skipped. `check` explains them; listing them here means\n // an agent reading `routes --json` sees them without a second command.\n payload.unrouted = model.unrouted\n }\n if (showApis) {\n payload.apis = model.apis.map((a) => apiJson(a, detail))\n payload.hasServer = model.hasServer\n }\n printJson(payload)\n return 0\n }\n\n if (showPages) printPages(model, detail)\n // Without --apis, an API-less project stays silent (nothing to say about it).\n if (showApis && (model.hasServer || onlyApis)) printApis(model, detail)\n console.log(\"\")\n return 0\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { loadCatalog, isDocLang, DOC_LANGS, DEFAULT_DOC_LANG, docsForLang, readDoc } from './chunk-2KRCGXBY.js';
2
- import { log, printJson } from './chunk-QI3XQKHS.js';
2
+ import { log, printJson } from './chunk-GNXCX4WE.js';
3
3
  import './chunk-C2CX6GLX.js';
4
4
  import pc from 'picocolors';
5
5
 
@@ -321,5 +321,5 @@ async function search(_root, args) {
321
321
  }
322
322
 
323
323
  export { search };
324
- //# sourceMappingURL=search-6Y422SV6.js.map
325
- //# sourceMappingURL=search-6Y422SV6.js.map
324
+ //# sourceMappingURL=search-5LC4XPB5.js.map
325
+ //# sourceMappingURL=search-5LC4XPB5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/search-index.ts","../src/cli/search.ts"],"names":[],"mappings":"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","file":"search-6Y422SV6.js","sourcesContent":["import { readDoc, type DocEntry } from \"./docs-catalog\"\n\n/**\n * A tiny BM25F ranker over the bundled documentation. The corpus is the catalog\n * `docs-catalog.ts` exposes — the same one `vantage docs` prints, so search never\n * creates a second source of truth.\n *\n * The index is built at run time: 65 pages per language (~300 KB) tokenize in a\n * few milliseconds, which is cheaper than shipping and version-locking a\n * prebuilt index alongside the docs bundle.\n */\n\n/**\n * Field weights. A name or a title match says far more about relevance than one\n * more occurrence in a long body, and BM25F models that as a weighted term\n * frequency (and a matching weighted document length).\n */\nconst FIELD_WEIGHTS = { slug: 3, title: 3, description: 2, body: 1 } as const\n\n/** Standard BM25 constants: term-frequency saturation and length normalization. */\nconst K1 = 1.2\nconst B = 0.75\n\n/**\n * Latin/digit runs, or runs of Japanese script (kana + CJK ideographs). CJK\n * punctuation (U+3000–U+303F, 。and 、) is deliberately outside the ranges, so\n * runs break at sentence boundaries.\n */\nconst TOKEN_RE = /[a-z0-9]+|[぀-ヿ㐀-䶿一-鿿]+/g\nconst LATIN_RE = /^[a-z0-9]+$/\n/** `TOKEN_RE`, but before lowercasing — for text that is not being indexed. */\nconst TOKEN_RE_ANYCASE = /[a-zA-Z0-9]+|[぀-ヿ㐀-䶿一-鿿]+/g\nconst CJK_RE = /[぀-ヿ㐀-䶿一-鿿]/\n\n/**\n * One run of a single script: hiragana (U+3041–U+309F), katakana (U+30A0–U+30FF,\n * so ー stays inside テーブル), or kanji. Japanese writes content words in\n * katakana and kanji and the grammatical glue between them in hiragana, so\n * cutting at every script change segments 「テーブルにページングを付けたい」into\n * テーブル · に · ページング · を · 付 · けたい without a morphological analyser.\n */\nconst SCRIPT_RE = /[ぁ-ゟ]+|[゠-ヿ]+|[㐀-䶿一-鿿]+/g\nconst HIRAGANA_RE = /^[ぁ-ゟ]$/\n\n/** Plural forms, so `colors` finds `color` and `queries` finds `query`. */\nfunction singular(word: string): string {\n if (word.length >= 5 && word.endsWith(\"ies\")) return `${word.slice(0, -3)}y`\n if (word.length >= 4 && word.endsWith(\"s\") && !/(ss|us|is)$/.test(word)) return word.slice(0, -1)\n return word\n}\n\n/**\n * Split text into index terms. Latin runs become words (`DataTable` splits into\n * `data` + `table`, so a two-word query finds it). Japanese runs are segmented\n * by script change; each segment is indexed whole *and* as character bigrams,\n * so an exact word scores high while a near miss (ページング / ページネーション)\n * still shares enough terms to be found.\n */\nexport function tokenize(text: string): string[] {\n const normalized = text\n .normalize(\"NFKC\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n const tokens: string[] = []\n for (const match of normalized.matchAll(TOKEN_RE)) {\n const run = match[0]!\n if (LATIN_RE.test(run)) {\n tokens.push(singular(run))\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n // A lone hiragana is a particle (を, に, が …): it appears in every page\n // and would make every page a match.\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n // A 2-character segment is its own only bigram — pushing both would\n // double-count it.\n if (segment.length <= 2) {\n tokens.push(segment)\n continue\n }\n tokens.push(segment)\n for (let i = 0; i < segment.length - 1; i++) tokens.push(segment.slice(i, i + 2))\n }\n }\n return tokens\n}\n\n/**\n * The words a snippet should highlight: whole words and whole Japanese\n * segments as the user typed them, without the derived bigrams (highlighting\n * those would paint most of a Japanese line yellow) and without the singular\n * rewrite (which no longer appears verbatim in the text).\n */\nexport function queryPhrases(query: string): string[] {\n const phrases: string[] = []\n for (const match of query.normalize(\"NFKC\").matchAll(TOKEN_RE_ANYCASE)) {\n const run = match[0]!\n if (!CJK_RE.test(run)) {\n phrases.push(run)\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n phrases.push(segment)\n }\n }\n return [...new Set(phrases)]\n}\n\n/** One ranked document, with the body kept for snippet extraction. */\nexport interface SearchHit {\n entry: DocEntry\n score: number\n /** Query terms that were looked up — the input for `snippet()`. */\n terms: string[]\n body: string\n}\n\ninterface IndexedDoc {\n entry: DocEntry\n body: string\n /** Weighted term frequency across all fields. */\n tf: Map<string, number>\n /** Weighted document length. */\n length: number\n}\n\nexport interface SearchIndex {\n /** Every document with a non-zero score, best first. */\n search(query: string): SearchHit[]\n}\n\n/** Build the index for one language's catalog entries. */\nexport function buildIndex(entries: DocEntry[]): SearchIndex {\n const docs: IndexedDoc[] = entries.map((entry) => {\n const body = readDoc(entry)\n const tf = new Map<string, number>()\n let length = 0\n const add = (text: string, weight: number) => {\n for (const token of tokenize(text)) {\n tf.set(token, (tf.get(token) ?? 0) + weight)\n length += weight\n }\n }\n add(entry.slug, FIELD_WEIGHTS.slug)\n add(entry.title, FIELD_WEIGHTS.title)\n add(entry.description, FIELD_WEIGHTS.description)\n add(body, FIELD_WEIGHTS.body)\n return { entry, body, tf, length }\n })\n\n const df = new Map<string, number>()\n for (const doc of docs) {\n for (const term of doc.tf.keys()) df.set(term, (df.get(term) ?? 0) + 1)\n }\n const total = docs.length\n const avgLength = total ? docs.reduce((sum, doc) => sum + doc.length, 0) / total : 1\n\n return {\n search(query: string): SearchHit[] {\n const terms = [...new Set(tokenize(query))]\n if (terms.length === 0) return []\n\n const hits: SearchHit[] = []\n for (const doc of docs) {\n let score = 0\n for (const term of terms) {\n const tf = doc.tf.get(term)\n if (!tf) continue\n const n = df.get(term) ?? 0\n const idf = Math.log(1 + (total - n + 0.5) / (n + 0.5))\n const norm = 1 - B + (B * doc.length) / avgLength\n score += idf * ((tf * (K1 + 1)) / (tf + K1 * norm))\n }\n if (score > 0) hits.push({ entry: doc.entry, score, terms, body: doc.body })\n }\n hits.sort((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug))\n return hits\n },\n }\n}\n\n/** How much of a line to show around the first matched term. */\nconst SNIPPET_LENGTH = 150\n\n/**\n * Pick the passage that best covers the query terms. Lines are compared\n * lowercased only (no NFKC, no camelCase splitting) so offsets stay aligned\n * with the text that is printed.\n */\nexport function snippet(body: string, terms: string[], length = SNIPPET_LENGTH): string {\n let best = \"\"\n let bestHits = 0\n let bestIndex = 0\n let bestIsHeading = true\n\n // The first line is the page's own `# Title`, which the caller already shows.\n for (const raw of body.split(\"\\n\").slice(1)) {\n const line = raw.replace(/^\\s*[-*]\\s+/, \"\").replace(/\\s+/g, \" \").trim()\n if (!line || /^(```|~~~|\\|\\s*-{2,})/.test(line)) continue\n const haystack = line.toLowerCase()\n const heading = line.startsWith(\"#\")\n let hits = 0\n let first = -1\n for (const term of terms) {\n const at = haystack.indexOf(term)\n if (at === -1) continue\n hits++\n if (first === -1 || at < first) first = at\n }\n // Equal coverage: prose says more than a heading does.\n if (hits > bestHits || (hits === bestHits && hits > 0 && bestIsHeading && !heading)) {\n best = line\n bestHits = hits\n bestIndex = first\n bestIsHeading = heading\n }\n }\n\n if (!bestHits) return \"\"\n if (best.length <= length) return best\n\n const start = Math.max(0, bestIndex - Math.floor(length / 4))\n const text = best.slice(start, start + length).trim()\n return `${start > 0 ? \"…\" : \"\"}${text}${start + length < best.length ? \"…\" : \"\"}`\n}\n","import pc from \"picocolors\"\nimport {\n DEFAULT_DOC_LANG,\n DOC_LANGS,\n docsForLang,\n isDocLang,\n loadCatalog,\n readDoc,\n type DocEntry,\n type DocLang,\n} from \"./docs-catalog\"\nimport { buildIndex, queryPhrases, snippet, type SearchHit } from \"./search-index\"\nimport { log, printJson, type ParsedArgs } from \"./util\"\n\n/** Results shown when `--limit` is absent. */\nconst DEFAULT_LIMIT = 10\n\n/** Matching lines printed per page in regex mode (the count is always exact). */\nconst MAX_REGEX_LINES = 3\n\n/** Parse `--limit`, falling back silently — an off result list is not a failure. */\nfunction parseLimit(value: string | boolean | undefined, fallback: number): number {\n if (typeof value === \"string\") {\n const n = Number(value)\n if (Number.isInteger(n) && n > 0) return n\n }\n return fallback\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Dim a line, with every match of `re` picked out. Piped output stays plain. */\nfunction paintMatches(text: string, re: RegExp): string {\n if (!process.stdout.isTTY) return text\n let out = \"\"\n let last = 0\n for (const match of text.matchAll(re)) {\n const at = match.index ?? 0\n if (!match[0]) continue // zero-length match: nothing to highlight\n out += pc.dim(text.slice(last, at)) + pc.yellow(match[0])\n last = at + match[0].length\n }\n return out + pc.dim(text.slice(last))\n}\n\n/** Same, for the words of a natural-language query. */\nfunction paintTerms(text: string, words: string[]): string {\n if (!process.stdout.isTTY) return text\n if (words.length === 0) return pc.dim(text)\n return paintMatches(text, new RegExp(words.map(escapeRegExp).join(\"|\"), \"gi\"))\n}\n\nfunction header(count: number, query: string, lang: DocLang, mode: string): void {\n const label = `${count} result${count === 1 ? \"\" : \"s\"} for \"${query}\"`\n console.log(\"\")\n console.log(pc.bold(label) + pc.dim(` ${lang} · ${mode}`))\n console.log(\"\")\n}\n\nfunction footer(total: number, shown: number, lines: string[]): void {\n if (total > shown) {\n console.log(\"\")\n console.log(pc.dim(` ${total - shown} more — raise --limit to see them`))\n }\n console.log(\"\")\n for (const line of lines) console.log(pc.dim(line))\n}\n\nfunction noResults(query: string): void {\n log.warn(`Nothing matches \"${query}\".`)\n console.log(pc.dim(\" Try fewer or more general words, or run `vantage docs --list` to browse every page.\"))\n}\n\nfunction meta(entry: DocEntry) {\n return {\n slug: entry.slug,\n title: entry.title,\n description: entry.description,\n section: entry.section,\n sectionTitle: entry.sectionTitle,\n command: `vantage docs ${entry.slug}`,\n }\n}\n\n/** Default mode: rank the corpus with BM25 and show the best passage of each hit. */\nfunction runRanked(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n const hits = buildIndex(entries).search(query)\n const shown = hits.slice(0, limit)\n const passage = (hit: SearchHit) => snippet(hit.body, hit.terms)\n\n if (json) {\n printJson({\n query,\n mode: \"bm25\",\n lang,\n count: hits.length,\n results: shown.map((hit) => ({\n ...meta(hit.entry),\n score: Math.round(hit.score * 1000) / 1000,\n snippet: passage(hit),\n })),\n })\n return 0\n }\n\n if (hits.length === 0) {\n noResults(query)\n return 0\n }\n\n const words = queryPhrases(query)\n const width = Math.max(...shown.map((hit) => hit.entry.slug.length))\n header(hits.length, query, lang, \"bm25\")\n for (const hit of shown) {\n const title = `${hit.entry.title}${pc.dim(` · ${hit.entry.sectionTitle}`)}`\n console.log(` ${pc.cyan(hit.entry.slug.padEnd(width))} ${title}`)\n const text = passage(hit)\n if (text) console.log(` ${\" \".repeat(width)} ${paintTerms(text, words)}`)\n }\n footer(hits.length, shown.length, [\n \"vantage docs <name> open one result --regex treat the query as a regular expression\",\n \"vantage search --json machine-readable --limit max results (default 10)\",\n ])\n return 0\n}\n\n/** `--regex` mode: scan names, titles and bodies for a regular expression. */\nfunction runRegex(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n let scan: RegExp\n let probe: RegExp\n try {\n scan = new RegExp(query, \"gi\")\n probe = new RegExp(query, \"i\")\n } catch (err) {\n log.error(err instanceof Error ? err.message : `Invalid regular expression: ${String(err)}`)\n return 1\n }\n\n const results: { entry: DocEntry; matchCount: number; matches: { line: number; text: string }[] }[] = []\n for (const entry of entries) {\n const lines = readDoc(entry).split(\"\\n\")\n const matches: { line: number; text: string }[] = []\n let matchCount = 0\n for (let i = 0; i < lines.length; i++) {\n const found = [...lines[i]!.matchAll(scan)]\n if (found.length === 0) continue\n matchCount += found.length\n if (matches.length < MAX_REGEX_LINES) {\n matches.push({ line: i + 1, text: lines[i]!.replace(/\\s+/g, \" \").trim() })\n }\n }\n const inMeta = probe.test(entry.slug) || probe.test(entry.title) || probe.test(entry.description)\n if (matchCount === 0 && !inMeta) continue\n results.push({ entry, matchCount, matches })\n }\n // Stable sort: pages with more matches first, catalog order within ties.\n results.sort((a, b) => b.matchCount - a.matchCount)\n const shown = results.slice(0, limit)\n\n if (json) {\n printJson({\n query,\n mode: \"regex\",\n lang,\n count: results.length,\n results: shown.map((result) => ({\n ...meta(result.entry),\n matchCount: result.matchCount,\n matches: result.matches,\n })),\n })\n return 0\n }\n\n if (results.length === 0) {\n noResults(query)\n return 0\n }\n\n header(results.length, query, lang, \"regex\")\n for (const result of shown) {\n // A page can match on its name, title or description alone — with no body line to show.\n const count = pc.dim(\n result.matchCount ? ` ${result.matchCount} match${result.matchCount === 1 ? \"\" : \"es\"}` : \" name match\",\n )\n console.log(` ${pc.cyan(result.entry.slug)} ${result.entry.title}${count}`)\n for (const match of result.matches) {\n console.log(` ${pc.dim(String(match.line).padStart(4))} ${paintMatches(match.text, scan)}`)\n }\n }\n footer(results.length, shown.length, [\n \"vantage docs <name> open one result --limit max results (default 10)\",\n \"vantage search --json machine-readable --lang ja | en\",\n ])\n return 0\n}\n\n/** `vantage search <query> [--regex] [--limit n] [--json] [--lang ja|en]` */\nexport async function search(_root: string, args: ParsedArgs): Promise<number> {\n const query = args.positionals.slice(1).join(\" \").trim()\n if (!query) {\n log.error(\"Usage: vantage search <query> [--regex] [--limit <n>] [--lang ja|en] [--json]\")\n return 1\n }\n\n const catalog = loadCatalog()\n if (!catalog) {\n log.error(\"The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.\")\n return 1\n }\n\n const langFlag = args.flags.lang\n if (langFlag !== undefined && !isDocLang(langFlag)) {\n log.error(`Unknown --lang \"${String(langFlag)}\". Available: ${DOC_LANGS.join(\", \")}`)\n return 1\n }\n const lang: DocLang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG\n\n const entries = docsForLang(catalog, lang)\n if (entries.length === 0) {\n log.error(`No documentation bundled for \"${lang}\".`)\n return 1\n }\n\n // Pages that opted out with `search: false` (e.g. the changelog) are still\n // reachable via `vantage docs` but never surface here.\n const searchable = entries.filter((entry) => entry.searchable !== false)\n\n const limit = parseLimit(args.flags.limit, DEFAULT_LIMIT)\n const json = Boolean(args.flags.json)\n return args.flags.regex\n ? runRegex(searchable, query, lang, limit, json)\n : runRanked(searchable, query, lang, limit, json)\n}\n"]}
1
+ {"version":3,"sources":["../src/cli/search-index.ts","../src/cli/search.ts"],"names":[],"mappings":"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","file":"search-5LC4XPB5.js","sourcesContent":["import { readDoc, type DocEntry } from \"./docs-catalog\"\n\n/**\n * A tiny BM25F ranker over the bundled documentation. The corpus is the catalog\n * `docs-catalog.ts` exposes — the same one `vantage docs` prints, so search never\n * creates a second source of truth.\n *\n * The index is built at run time: 65 pages per language (~300 KB) tokenize in a\n * few milliseconds, which is cheaper than shipping and version-locking a\n * prebuilt index alongside the docs bundle.\n */\n\n/**\n * Field weights. A name or a title match says far more about relevance than one\n * more occurrence in a long body, and BM25F models that as a weighted term\n * frequency (and a matching weighted document length).\n */\nconst FIELD_WEIGHTS = { slug: 3, title: 3, description: 2, body: 1 } as const\n\n/** Standard BM25 constants: term-frequency saturation and length normalization. */\nconst K1 = 1.2\nconst B = 0.75\n\n/**\n * Latin/digit runs, or runs of Japanese script (kana + CJK ideographs). CJK\n * punctuation (U+3000–U+303F, 。and 、) is deliberately outside the ranges, so\n * runs break at sentence boundaries.\n */\nconst TOKEN_RE = /[a-z0-9]+|[぀-ヿ㐀-䶿一-鿿]+/g\nconst LATIN_RE = /^[a-z0-9]+$/\n/** `TOKEN_RE`, but before lowercasing — for text that is not being indexed. */\nconst TOKEN_RE_ANYCASE = /[a-zA-Z0-9]+|[぀-ヿ㐀-䶿一-鿿]+/g\nconst CJK_RE = /[぀-ヿ㐀-䶿一-鿿]/\n\n/**\n * One run of a single script: hiragana (U+3041–U+309F), katakana (U+30A0–U+30FF,\n * so ー stays inside テーブル), or kanji. Japanese writes content words in\n * katakana and kanji and the grammatical glue between them in hiragana, so\n * cutting at every script change segments 「テーブルにページングを付けたい」into\n * テーブル · に · ページング · を · 付 · けたい without a morphological analyser.\n */\nconst SCRIPT_RE = /[ぁ-ゟ]+|[゠-ヿ]+|[㐀-䶿一-鿿]+/g\nconst HIRAGANA_RE = /^[ぁ-ゟ]$/\n\n/** Plural forms, so `colors` finds `color` and `queries` finds `query`. */\nfunction singular(word: string): string {\n if (word.length >= 5 && word.endsWith(\"ies\")) return `${word.slice(0, -3)}y`\n if (word.length >= 4 && word.endsWith(\"s\") && !/(ss|us|is)$/.test(word)) return word.slice(0, -1)\n return word\n}\n\n/**\n * Split text into index terms. Latin runs become words (`DataTable` splits into\n * `data` + `table`, so a two-word query finds it). Japanese runs are segmented\n * by script change; each segment is indexed whole *and* as character bigrams,\n * so an exact word scores high while a near miss (ページング / ページネーション)\n * still shares enough terms to be found.\n */\nexport function tokenize(text: string): string[] {\n const normalized = text\n .normalize(\"NFKC\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n const tokens: string[] = []\n for (const match of normalized.matchAll(TOKEN_RE)) {\n const run = match[0]!\n if (LATIN_RE.test(run)) {\n tokens.push(singular(run))\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n // A lone hiragana is a particle (を, に, が …): it appears in every page\n // and would make every page a match.\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n // A 2-character segment is its own only bigram — pushing both would\n // double-count it.\n if (segment.length <= 2) {\n tokens.push(segment)\n continue\n }\n tokens.push(segment)\n for (let i = 0; i < segment.length - 1; i++) tokens.push(segment.slice(i, i + 2))\n }\n }\n return tokens\n}\n\n/**\n * The words a snippet should highlight: whole words and whole Japanese\n * segments as the user typed them, without the derived bigrams (highlighting\n * those would paint most of a Japanese line yellow) and without the singular\n * rewrite (which no longer appears verbatim in the text).\n */\nexport function queryPhrases(query: string): string[] {\n const phrases: string[] = []\n for (const match of query.normalize(\"NFKC\").matchAll(TOKEN_RE_ANYCASE)) {\n const run = match[0]!\n if (!CJK_RE.test(run)) {\n phrases.push(run)\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n phrases.push(segment)\n }\n }\n return [...new Set(phrases)]\n}\n\n/** One ranked document, with the body kept for snippet extraction. */\nexport interface SearchHit {\n entry: DocEntry\n score: number\n /** Query terms that were looked up — the input for `snippet()`. */\n terms: string[]\n body: string\n}\n\ninterface IndexedDoc {\n entry: DocEntry\n body: string\n /** Weighted term frequency across all fields. */\n tf: Map<string, number>\n /** Weighted document length. */\n length: number\n}\n\nexport interface SearchIndex {\n /** Every document with a non-zero score, best first. */\n search(query: string): SearchHit[]\n}\n\n/** Build the index for one language's catalog entries. */\nexport function buildIndex(entries: DocEntry[]): SearchIndex {\n const docs: IndexedDoc[] = entries.map((entry) => {\n const body = readDoc(entry)\n const tf = new Map<string, number>()\n let length = 0\n const add = (text: string, weight: number) => {\n for (const token of tokenize(text)) {\n tf.set(token, (tf.get(token) ?? 0) + weight)\n length += weight\n }\n }\n add(entry.slug, FIELD_WEIGHTS.slug)\n add(entry.title, FIELD_WEIGHTS.title)\n add(entry.description, FIELD_WEIGHTS.description)\n add(body, FIELD_WEIGHTS.body)\n return { entry, body, tf, length }\n })\n\n const df = new Map<string, number>()\n for (const doc of docs) {\n for (const term of doc.tf.keys()) df.set(term, (df.get(term) ?? 0) + 1)\n }\n const total = docs.length\n const avgLength = total ? docs.reduce((sum, doc) => sum + doc.length, 0) / total : 1\n\n return {\n search(query: string): SearchHit[] {\n const terms = [...new Set(tokenize(query))]\n if (terms.length === 0) return []\n\n const hits: SearchHit[] = []\n for (const doc of docs) {\n let score = 0\n for (const term of terms) {\n const tf = doc.tf.get(term)\n if (!tf) continue\n const n = df.get(term) ?? 0\n const idf = Math.log(1 + (total - n + 0.5) / (n + 0.5))\n const norm = 1 - B + (B * doc.length) / avgLength\n score += idf * ((tf * (K1 + 1)) / (tf + K1 * norm))\n }\n if (score > 0) hits.push({ entry: doc.entry, score, terms, body: doc.body })\n }\n hits.sort((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug))\n return hits\n },\n }\n}\n\n/** How much of a line to show around the first matched term. */\nconst SNIPPET_LENGTH = 150\n\n/**\n * Pick the passage that best covers the query terms. Lines are compared\n * lowercased only (no NFKC, no camelCase splitting) so offsets stay aligned\n * with the text that is printed.\n */\nexport function snippet(body: string, terms: string[], length = SNIPPET_LENGTH): string {\n let best = \"\"\n let bestHits = 0\n let bestIndex = 0\n let bestIsHeading = true\n\n // The first line is the page's own `# Title`, which the caller already shows.\n for (const raw of body.split(\"\\n\").slice(1)) {\n const line = raw.replace(/^\\s*[-*]\\s+/, \"\").replace(/\\s+/g, \" \").trim()\n if (!line || /^(```|~~~|\\|\\s*-{2,})/.test(line)) continue\n const haystack = line.toLowerCase()\n const heading = line.startsWith(\"#\")\n let hits = 0\n let first = -1\n for (const term of terms) {\n const at = haystack.indexOf(term)\n if (at === -1) continue\n hits++\n if (first === -1 || at < first) first = at\n }\n // Equal coverage: prose says more than a heading does.\n if (hits > bestHits || (hits === bestHits && hits > 0 && bestIsHeading && !heading)) {\n best = line\n bestHits = hits\n bestIndex = first\n bestIsHeading = heading\n }\n }\n\n if (!bestHits) return \"\"\n if (best.length <= length) return best\n\n const start = Math.max(0, bestIndex - Math.floor(length / 4))\n const text = best.slice(start, start + length).trim()\n return `${start > 0 ? \"…\" : \"\"}${text}${start + length < best.length ? \"…\" : \"\"}`\n}\n","import pc from \"picocolors\"\nimport {\n DEFAULT_DOC_LANG,\n DOC_LANGS,\n docsForLang,\n isDocLang,\n loadCatalog,\n readDoc,\n type DocEntry,\n type DocLang,\n} from \"./docs-catalog\"\nimport { buildIndex, queryPhrases, snippet, type SearchHit } from \"./search-index\"\nimport { log, printJson, type ParsedArgs } from \"./util\"\n\n/** Results shown when `--limit` is absent. */\nconst DEFAULT_LIMIT = 10\n\n/** Matching lines printed per page in regex mode (the count is always exact). */\nconst MAX_REGEX_LINES = 3\n\n/** Parse `--limit`, falling back silently — an off result list is not a failure. */\nfunction parseLimit(value: string | boolean | undefined, fallback: number): number {\n if (typeof value === \"string\") {\n const n = Number(value)\n if (Number.isInteger(n) && n > 0) return n\n }\n return fallback\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Dim a line, with every match of `re` picked out. Piped output stays plain. */\nfunction paintMatches(text: string, re: RegExp): string {\n if (!process.stdout.isTTY) return text\n let out = \"\"\n let last = 0\n for (const match of text.matchAll(re)) {\n const at = match.index ?? 0\n if (!match[0]) continue // zero-length match: nothing to highlight\n out += pc.dim(text.slice(last, at)) + pc.yellow(match[0])\n last = at + match[0].length\n }\n return out + pc.dim(text.slice(last))\n}\n\n/** Same, for the words of a natural-language query. */\nfunction paintTerms(text: string, words: string[]): string {\n if (!process.stdout.isTTY) return text\n if (words.length === 0) return pc.dim(text)\n return paintMatches(text, new RegExp(words.map(escapeRegExp).join(\"|\"), \"gi\"))\n}\n\nfunction header(count: number, query: string, lang: DocLang, mode: string): void {\n const label = `${count} result${count === 1 ? \"\" : \"s\"} for \"${query}\"`\n console.log(\"\")\n console.log(pc.bold(label) + pc.dim(` ${lang} · ${mode}`))\n console.log(\"\")\n}\n\nfunction footer(total: number, shown: number, lines: string[]): void {\n if (total > shown) {\n console.log(\"\")\n console.log(pc.dim(` ${total - shown} more — raise --limit to see them`))\n }\n console.log(\"\")\n for (const line of lines) console.log(pc.dim(line))\n}\n\nfunction noResults(query: string): void {\n log.warn(`Nothing matches \"${query}\".`)\n console.log(pc.dim(\" Try fewer or more general words, or run `vantage docs --list` to browse every page.\"))\n}\n\nfunction meta(entry: DocEntry) {\n return {\n slug: entry.slug,\n title: entry.title,\n description: entry.description,\n section: entry.section,\n sectionTitle: entry.sectionTitle,\n command: `vantage docs ${entry.slug}`,\n }\n}\n\n/** Default mode: rank the corpus with BM25 and show the best passage of each hit. */\nfunction runRanked(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n const hits = buildIndex(entries).search(query)\n const shown = hits.slice(0, limit)\n const passage = (hit: SearchHit) => snippet(hit.body, hit.terms)\n\n if (json) {\n printJson({\n query,\n mode: \"bm25\",\n lang,\n count: hits.length,\n results: shown.map((hit) => ({\n ...meta(hit.entry),\n score: Math.round(hit.score * 1000) / 1000,\n snippet: passage(hit),\n })),\n })\n return 0\n }\n\n if (hits.length === 0) {\n noResults(query)\n return 0\n }\n\n const words = queryPhrases(query)\n const width = Math.max(...shown.map((hit) => hit.entry.slug.length))\n header(hits.length, query, lang, \"bm25\")\n for (const hit of shown) {\n const title = `${hit.entry.title}${pc.dim(` · ${hit.entry.sectionTitle}`)}`\n console.log(` ${pc.cyan(hit.entry.slug.padEnd(width))} ${title}`)\n const text = passage(hit)\n if (text) console.log(` ${\" \".repeat(width)} ${paintTerms(text, words)}`)\n }\n footer(hits.length, shown.length, [\n \"vantage docs <name> open one result --regex treat the query as a regular expression\",\n \"vantage search --json machine-readable --limit max results (default 10)\",\n ])\n return 0\n}\n\n/** `--regex` mode: scan names, titles and bodies for a regular expression. */\nfunction runRegex(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n let scan: RegExp\n let probe: RegExp\n try {\n scan = new RegExp(query, \"gi\")\n probe = new RegExp(query, \"i\")\n } catch (err) {\n log.error(err instanceof Error ? err.message : `Invalid regular expression: ${String(err)}`)\n return 1\n }\n\n const results: { entry: DocEntry; matchCount: number; matches: { line: number; text: string }[] }[] = []\n for (const entry of entries) {\n const lines = readDoc(entry).split(\"\\n\")\n const matches: { line: number; text: string }[] = []\n let matchCount = 0\n for (let i = 0; i < lines.length; i++) {\n const found = [...lines[i]!.matchAll(scan)]\n if (found.length === 0) continue\n matchCount += found.length\n if (matches.length < MAX_REGEX_LINES) {\n matches.push({ line: i + 1, text: lines[i]!.replace(/\\s+/g, \" \").trim() })\n }\n }\n const inMeta = probe.test(entry.slug) || probe.test(entry.title) || probe.test(entry.description)\n if (matchCount === 0 && !inMeta) continue\n results.push({ entry, matchCount, matches })\n }\n // Stable sort: pages with more matches first, catalog order within ties.\n results.sort((a, b) => b.matchCount - a.matchCount)\n const shown = results.slice(0, limit)\n\n if (json) {\n printJson({\n query,\n mode: \"regex\",\n lang,\n count: results.length,\n results: shown.map((result) => ({\n ...meta(result.entry),\n matchCount: result.matchCount,\n matches: result.matches,\n })),\n })\n return 0\n }\n\n if (results.length === 0) {\n noResults(query)\n return 0\n }\n\n header(results.length, query, lang, \"regex\")\n for (const result of shown) {\n // A page can match on its name, title or description alone — with no body line to show.\n const count = pc.dim(\n result.matchCount ? ` ${result.matchCount} match${result.matchCount === 1 ? \"\" : \"es\"}` : \" name match\",\n )\n console.log(` ${pc.cyan(result.entry.slug)} ${result.entry.title}${count}`)\n for (const match of result.matches) {\n console.log(` ${pc.dim(String(match.line).padStart(4))} ${paintMatches(match.text, scan)}`)\n }\n }\n footer(results.length, shown.length, [\n \"vantage docs <name> open one result --limit max results (default 10)\",\n \"vantage search --json machine-readable --lang ja | en\",\n ])\n return 0\n}\n\n/** `vantage search <query> [--regex] [--limit n] [--json] [--lang ja|en]` */\nexport async function search(_root: string, args: ParsedArgs): Promise<number> {\n const query = args.positionals.slice(1).join(\" \").trim()\n if (!query) {\n log.error(\"Usage: vantage search <query> [--regex] [--limit <n>] [--lang ja|en] [--json]\")\n return 1\n }\n\n const catalog = loadCatalog()\n if (!catalog) {\n log.error(\"The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.\")\n return 1\n }\n\n const langFlag = args.flags.lang\n if (langFlag !== undefined && !isDocLang(langFlag)) {\n log.error(`Unknown --lang \"${String(langFlag)}\". Available: ${DOC_LANGS.join(\", \")}`)\n return 1\n }\n const lang: DocLang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG\n\n const entries = docsForLang(catalog, lang)\n if (entries.length === 0) {\n log.error(`No documentation bundled for \"${lang}\".`)\n return 1\n }\n\n // Pages that opted out with `search: false` (e.g. the changelog) are still\n // reachable via `vantage docs` but never surface here.\n const searchable = entries.filter((entry) => entry.searchable !== false)\n\n const limit = parseLimit(args.flags.limit, DEFAULT_LIMIT)\n const json = Boolean(args.flags.json)\n return args.flags.regex\n ? runRegex(searchable, query, lang, limit, json)\n : runRanked(searchable, query, lang, limit, json)\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { FILE_PAGE_MAX_ROWS, FILE_PAGE_MAX_BYTES } from '../chunk-C2CX6GLX.js';
2
- import { useQuery } from '../chunk-PVTHHV7X.js';
3
- import '../chunk-DTDVSFRY.js';
2
+ import { useQuery } from '../chunk-V3LF7BE7.js';
3
+ import '../chunk-XQUSGIDG.js';
4
4
  import { Loading, ErrorState } from '../chunk-5ZOP4SQR.js';
5
5
  import { PageShell, PageShellHeader, PageShellHeading, PageShellTitle, PageShellMeta, PageShellActions, PageShellContent } from '../chunk-AG6RZ2RR.js';
6
6
  import '../chunk-OB6UBJXF.js';
@@ -1,8 +1,8 @@
1
- import { syncAgentsFile } from './chunk-U2M6HGKQ.js';
2
- import { generateArtifacts } from './chunk-LMUACBMA.js';
1
+ import { syncAgentsFile } from './chunk-AABMKHEU.js';
2
+ import { generateArtifacts } from './chunk-QEWCYW3I.js';
3
3
  import './chunk-CEXAQQ5W.js';
4
- import { scanProject } from './chunk-ZVANIULZ.js';
5
- import { frameworkVersion, printJson, log } from './chunk-QI3XQKHS.js';
4
+ import { scanProject } from './chunk-RNTDBX6S.js';
5
+ import { frameworkVersion, printJson, log } from './chunk-GNXCX4WE.js';
6
6
  import './chunk-C2CX6GLX.js';
7
7
 
8
8
  // @squadbase/vantage — generated build. Do not edit.
@@ -25,5 +25,5 @@ async function upgrade(root, args) {
25
25
  }
26
26
 
27
27
  export { upgrade };
28
- //# sourceMappingURL=upgrade-HCANX4GQ.js.map
29
- //# sourceMappingURL=upgrade-HCANX4GQ.js.map
28
+ //# sourceMappingURL=upgrade-DBBE6GIR.js.map
29
+ //# sourceMappingURL=upgrade-DBBE6GIR.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/upgrade.ts"],"names":[],"mappings":";;;;;;;;;;AAWA,eAAsB,OAAA,CAAQ,MAAc,IAAA,EAAmC;AAC7E,EAAA,MAAM,UAAU,gBAAA,EAAiB;AACjC,EAAA,MAAM,KAAA,GAAQ,YAAY,IAAI,CAAA;AAC9B,EAAA,iBAAA,CAAkB,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAKjC,EAAA,MAAM,MAAA,GAAS,eAAe,IAAI,CAAA;AAElC,EAAA,IAAI,IAAA,CAAK,MAAM,IAAA,EAAM;AACnB,IAAA,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,OAAA,EAAS,UAAA,EAAY,EAAC,EAAG,WAAA,EAAa,IAAA,EAAM,YAAA,EAAc,MAAA,KAAW,SAAA,EAAW,CAAA;AACtG,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,GAAA,CAAI,KAAA,CAAM,CAAA,gBAAA,EAAc,OAAO,CAAA,CAAE,CAAA;AACjC,EAAA,GAAA,CAAI,GAAG,iCAAiC,CAAA;AACxC,EAAA,IAAI,MAAA,KAAW,SAAA,EAAW,GAAA,CAAI,EAAA,CAAG,kDAAkD,CAAA;AACnF,EAAA,GAAA,CAAI,KAAK,wDAAwD,CAAA;AACjE,EAAA,OAAO,CAAA;AACT","file":"upgrade-HCANX4GQ.js","sourcesContent":["import { generateArtifacts } from \"../core/generate\"\nimport { scanProject } from \"../core/scan\"\nimport { syncAgentsFile } from \"./add\"\nimport { frameworkVersion, log, printJson, type ParsedArgs } from \"./util\"\n\n/**\n * `vantage upgrade` — reconcile generated artifacts with the installed\n * framework version and apply any needed code transforms. v0.1 only\n * regenerates artifacts and re-syncs a managed AGENTS.md + agents/*.md; the\n * migration hook exists for future major versions.\n */\nexport async function upgrade(root: string, args: ParsedArgs): Promise<number> {\n const version = frameworkVersion()\n const model = scanProject(root)\n generateArtifacts({ root, model })\n\n // Keep an adopted AGENTS.md + agents/*.md (the app-author map and its\n // per-artifact-type knowledge files) in step with the framework's canonical\n // copies. No-op when the app never ran `vantage add agents`.\n const agents = syncAgentsFile(root)\n\n if (args.flags.json) {\n printJson({ ok: true, version, transforms: [], regenerated: true, agentsSynced: agents === \"updated\" })\n return 0\n }\n\n log.brand(`upgrade → v${version}`)\n log.ok(\"Regenerated .vantage artifacts.\")\n if (agents === \"updated\") log.ok(\"Synced AGENTS.md and agents/ from the framework.\")\n log.info(\"No breaking code transforms required for this version.\")\n return 0\n}\n"]}
1
+ {"version":3,"sources":["../src/cli/upgrade.ts"],"names":[],"mappings":";;;;;;;;;;AAWA,eAAsB,OAAA,CAAQ,MAAc,IAAA,EAAmC;AAC7E,EAAA,MAAM,UAAU,gBAAA,EAAiB;AACjC,EAAA,MAAM,KAAA,GAAQ,YAAY,IAAI,CAAA;AAC9B,EAAA,iBAAA,CAAkB,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAKjC,EAAA,MAAM,MAAA,GAAS,eAAe,IAAI,CAAA;AAElC,EAAA,IAAI,IAAA,CAAK,MAAM,IAAA,EAAM;AACnB,IAAA,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,OAAA,EAAS,UAAA,EAAY,EAAC,EAAG,WAAA,EAAa,IAAA,EAAM,YAAA,EAAc,MAAA,KAAW,SAAA,EAAW,CAAA;AACtG,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,GAAA,CAAI,KAAA,CAAM,CAAA,gBAAA,EAAc,OAAO,CAAA,CAAE,CAAA;AACjC,EAAA,GAAA,CAAI,GAAG,iCAAiC,CAAA;AACxC,EAAA,IAAI,MAAA,KAAW,SAAA,EAAW,GAAA,CAAI,EAAA,CAAG,kDAAkD,CAAA;AACnF,EAAA,GAAA,CAAI,KAAK,wDAAwD,CAAA;AACjE,EAAA,OAAO,CAAA;AACT","file":"upgrade-DBBE6GIR.js","sourcesContent":["import { generateArtifacts } from \"../core/generate\"\nimport { scanProject } from \"../core/scan\"\nimport { syncAgentsFile } from \"./add\"\nimport { frameworkVersion, log, printJson, type ParsedArgs } from \"./util\"\n\n/**\n * `vantage upgrade` — reconcile generated artifacts with the installed\n * framework version and apply any needed code transforms. v0.1 only\n * regenerates artifacts and re-syncs a managed AGENTS.md + agents/*.md; the\n * migration hook exists for future major versions.\n */\nexport async function upgrade(root: string, args: ParsedArgs): Promise<number> {\n const version = frameworkVersion()\n const model = scanProject(root)\n generateArtifacts({ root, model })\n\n // Keep an adopted AGENTS.md + agents/*.md (the app-author map and its\n // per-artifact-type knowledge files) in step with the framework's canonical\n // copies. No-op when the app never ran `vantage add agents`.\n const agents = syncAgentsFile(root)\n\n if (args.flags.json) {\n printJson({ ok: true, version, transforms: [], regenerated: true, agentsSynced: agents === \"updated\" })\n return 0\n }\n\n log.brand(`upgrade → v${version}`)\n log.ok(\"Regenerated .vantage artifacts.\")\n if (agents === \"updated\") log.ok(\"Synced AGENTS.md and agents/ from the framework.\")\n log.info(\"No breaking code transforms required for this version.\")\n return 0\n}\n"]}
@@ -17,6 +17,16 @@ interface VantagePluginOptions {
17
17
  * be produced at the same time as the client instead of after it.
18
18
  */
19
19
  artifactsWritten?: boolean;
20
+ /**
21
+ * Dev only: accept unfinished files at `POST /__vantage_draft` and show them
22
+ * in the running app before they are saved (`vantage dev --draft-preview`).
23
+ * Off, the plugin is not registered and nothing changes. `token` is the shared
24
+ * secret callers send as `x-vantage-draft-token` (default: env
25
+ * `VANTAGE_DRAFT_TOKEN`; without either, only loopback callers are served).
26
+ */
27
+ draftPreview?: boolean | {
28
+ token?: string;
29
+ };
20
30
  }
21
31
  /**
22
32
  * The single plugin that turns a plain Vite instance into Vantage: file-based
@@ -1,7 +1,7 @@
1
- export { vantagePlugin } from '../chunk-VA776YE5.js';
2
- import '../chunk-LMUACBMA.js';
1
+ export { vantagePlugin } from '../chunk-IBGOCWJB.js';
2
+ import '../chunk-QEWCYW3I.js';
3
3
  import '../chunk-CEXAQQ5W.js';
4
- import '../chunk-ZVANIULZ.js';
4
+ import '../chunk-RNTDBX6S.js';
5
5
  import '../chunk-46QI6GFC.js';
6
6
  import '../chunk-B7LLBNLV.js';
7
7
  import '../chunk-C2CX6GLX.js';
@@ -46,6 +46,11 @@ Vantage のリリースごとの変更点です。新しいものが上に来ま
46
46
  持たないのに、ブラウザのタイムゾーンで表示していたため、UTC より西(アメリカなど)では
47
47
  `2026-06-02` が `6/1` と前日に、時刻付きのセルは UTC より東(日本など)でも夜の時刻が翌日に
48
48
  ずれていました。いまはどのタイムゾーンでもファイルに書かれた日付・時刻のまま表示します。
49
+ - **ドキュメント(`.doc.tsx`)を画面で見るとき、本文が画面の端に付かなくなりました。** 画面表示用の
50
+ 余白が無かったため、表示幅が本文の幅(`--doc-max-width`、既定 48rem)より狭いと本文が左右の端に
51
+ 付き、見出しもヘッダーのすぐ下から始まっていました。いまは左右に 1.5rem、上に 3rem、下に 5rem の
52
+ 余白を取ります。下を広めにしているのは、右下の「PDF として保存」ボタンに最後の行が隠れないように
53
+ するためです。広い画面での本文の幅と、印刷の見た目は変わりません。
49
54
 
50
55
  ## v0.6.2
51
56
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squadbase/vantage",
3
- "version": "0.6.2-dev1.31accb1",
3
+ "version": "0.6.2-dev1.42c4e48",
4
4
  "description": "Data dashboard framework for Squadbase Editor. Vite-powered, config-free, one-file first.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -149,7 +149,13 @@
149
149
  },
150
150
  "peerDependencies": {
151
151
  "react": ">=18.2.0",
152
- "react-dom": ">=18.2.0"
152
+ "react-dom": ">=18.2.0",
153
+ "typescript": ">=5.0.0"
154
+ },
155
+ "peerDependenciesMeta": {
156
+ "typescript": {
157
+ "optional": true
158
+ }
153
159
  },
154
160
  "devDependencies": {
155
161
  "@types/node": "^22.10.0",
package/theme.css CHANGED
@@ -287,6 +287,17 @@
287
287
  line-height: var(--doc-line-height);
288
288
  overflow-wrap: break-word;
289
289
  }
290
+ /* On screen the document sits in the app frame's unpadded `<main>`, so it
291
+ brings its own gutter. `content-box` keeps `--doc-max-width` the width of
292
+ the text: the side gutter shows only once the frame is narrower than that.
293
+ The bottom leaves room for the fixed "Save as PDF" button. Paper takes its
294
+ margin from the print rules below instead. */
295
+ @media screen {
296
+ :where([data-slot="document"]) {
297
+ box-sizing: content-box;
298
+ padding: 3rem 1.5rem 5rem;
299
+ }
300
+ }
290
301
  :where([data-slot="document"]) :where(h1, h2, h3, h4) {
291
302
  font-family: var(--doc-font-heading);
292
303
  font-weight: 700;
@@ -1,6 +0,0 @@
1
- export { add, syncAgentsFile } from './chunk-U2M6HGKQ.js';
2
- import './chunk-ZVANIULZ.js';
3
- import './chunk-QI3XQKHS.js';
4
- import './chunk-C2CX6GLX.js';
5
- //# sourceMappingURL=add-DY4AXANK.js.map
6
- //# sourceMappingURL=add-DY4AXANK.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"add-DY4AXANK.js"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/query/client.ts"],"names":[],"mappings":";;;;AAOO,SAAS,iBAAA,GAAiC;AAC/C,EAAA,OAAO,IAAI,WAAA,CAAY;AAAA,IACrB,cAAA,EAAgB;AAAA,MACd,OAAA,EAAS;AAAA,QACP,SAAA,EAAW,GAAA;AAAA,QACX,KAAA,EAAO,CAAA;AAAA,QACP,oBAAA,EAAsB,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOtB,WAAA,EAAa;AAAA,OACf;AAAA,MACA,SAAA,EAAW;AAAA,QACT,WAAA,EAAa;AAAA;AACf;AACF,GACD,CAAA;AACH","file":"chunk-DTDVSFRY.js","sourcesContent":["import { QueryClient } from \"@tanstack/react-query\"\n\n/**\n * Create the QueryClient with Vantage defaults. Individual queries may override\n * these, but replacing the QueryClient wholesale is intentionally not exposed —\n * Squadbase relies on a single managed client for auth, logging and telemetry.\n */\nexport function createQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 30_000,\n retry: 1,\n refetchOnWindowFocus: false,\n // A dashboard talks to its own origin (or the configured API base), so\n // the browser's offline heuristic says nothing useful about whether a\n // request can succeed. Under the default \"online\" mode a failed request\n // is *paused* rather than retried whenever that heuristic reads\n // offline, and the page sits on its loading state forever instead of\n // showing the error.\n networkMode: \"always\",\n },\n mutations: {\n networkMode: \"always\",\n },\n },\n })\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/generate.ts"],"names":["require"],"mappings":"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","file":"chunk-LMUACBMA.js","sourcesContent":["import fs from \"node:fs\"\nimport path from \"node:path\"\nimport { createRequire } from \"node:module\"\nimport { MANIFEST_SCHEMA_VERSION, VANTAGE_DIR } from \"./constants\"\nimport { filePageKind, filePageModuleName } from \"./file-page\"\nimport { timed } from \"./profile\"\nimport { buildRouteTree } from \"./route-tree\"\nimport type { BuiltPage, BuiltTree } from \"./route-tree\"\nimport type { RouteModel, Segment } from \"./types\"\n\nconst PKG = \"@squadbase/vantage\"\n\n/** Subdirectory of `.vantage/` holding one wrapper module per data-file page. */\nconst FILE_PAGES_DIR = \"file-pages\"\n\n/**\n * Vite inlines an asset under 4 KB as a base64 data URL, which would bury a\n * small `.csv` inside a JS chunk and leave the download link pointing at it.\n * `?no-inline` is checked before the size limit, so it always wins.\n */\nconst ASSET_QUERY = \"?url&no-inline\"\n\n/**\n * Resolve the absolute directory of the installed @squadbase/vantage package.\n * Memoized per root: module resolution is comparatively expensive and the answer\n * cannot change while the process lives.\n */\nconst vantageDirCache = new Map<string, string | null>()\n\nfunction resolveVantageDir(root: string): string | null {\n const hit = vantageDirCache.get(root)\n if (hit !== undefined) return hit\n let dir: string | null\n try {\n const require = createRequire(path.join(root, \"noop.js\"))\n dir = path.dirname(require.resolve(`${PKG}/package.json`))\n } catch {\n dir = null\n }\n vantageDirCache.set(root, dir)\n return dir\n}\n\n/** POSIX import specifier from `.vantage/` to a project-relative file. */\nfunction importFromVantage(relFile: string): string {\n return `../${relFile}`\n}\n\n/**\n * POSIX import specifier from `.vantage/file-pages/` to a project-relative\n * file — one level deeper than `importFromVantage`. Do not mix the two up. The\n * \".vantage/ sits exactly one level below the project root\" invariant still\n * holds for the directory itself; this is a second, explicit depth used only\n * by the generated wrappers.\n */\nfunction importFromFilePages(relFile: string): string {\n return `../../${relFile}`\n}\n\nfunction ensureDir(dir: string): void {\n fs.mkdirSync(dir, { recursive: true })\n}\n\nfunction writeIfChanged(file: string, content: string): void {\n try {\n if (fs.existsSync(file) && fs.readFileSync(file, \"utf8\") === content) return\n } catch {\n /* fall through to write */\n }\n fs.writeFileSync(file, content)\n}\n\nfunction serializeSegments(segments: Segment[]): string {\n return (\n \"[\" +\n segments\n .map((s) => {\n if (s.kind === \"static\") return `{ kind: \"static\", value: ${JSON.stringify(s.value)} }`\n if (s.kind === \"param\") return `{ kind: \"param\", name: ${JSON.stringify(s.name)} }`\n return `{ kind: \"catchall\", name: ${JSON.stringify(s.name)} }`\n })\n .join(\", \") +\n \"]\"\n )\n}\n\nconst BANNER =\n \"// AUTO-GENERATED by @squadbase/vantage. Do not edit — regenerated on every run.\\n\"\n\nfunction renderRouteTree(tree: BuiltTree): string {\n const lines: string[] = []\n lines.push(BANNER)\n lines.push(`import type { ClientManifest } from \"${PKG}/client\"`)\n lines.push(\"\")\n lines.push(\"export const manifest: ClientManifest = {\")\n lines.push(\n ` rootLayout: ${tree.rootLayout ? `() => import(${JSON.stringify(importFromVantage(tree.rootLayout))})` : \"null\"},`,\n )\n lines.push(\n ` notFound: ${tree.notFound ? `() => import(${JSON.stringify(importFromVantage(tree.notFound))})` : \"null\"},`,\n )\n lines.push(\n ` error: ${tree.error ? `() => import(${JSON.stringify(importFromVantage(tree.error))})` : \"null\"},`,\n )\n lines.push(\" layouts: [\")\n for (const l of tree.layouts) {\n lines.push(\n ` { id: ${JSON.stringify(l.id)}, parentId: ${JSON.stringify(l.parentId)}, path: ${JSON.stringify(\n l.path,\n )}, load: () => import(${JSON.stringify(importFromVantage(l.file))}) },`,\n )\n }\n lines.push(\" ],\")\n lines.push(\" pages: [\")\n for (const p of tree.pages) {\n const extra: string[] = []\n if (p.title) extra.push(`title: ${JSON.stringify(p.title)}`)\n if (p.description) extra.push(`description: ${JSON.stringify(p.description)}`)\n if (p.navLabel) extra.push(`navLabel: ${JSON.stringify(p.navLabel)}`)\n if (p.kind !== \"module\") extra.push(`kind: ${JSON.stringify(p.kind)}`)\n if (p.variant) extra.push(`variant: ${JSON.stringify(p.variant)}`)\n // A data file is not a module, so the manifest loads the wrapper generated\n // for it instead. Everything else about the entry is unchanged, which is\n // why the client manifest shape stays the same.\n const specifier =\n p.kind === \"file\"\n ? `./${FILE_PAGES_DIR}/${filePageModuleName(p)}`\n : importFromVantage(p.file)\n lines.push(\n ` { parentLayoutId: ${JSON.stringify(p.parentLayoutId)}, path: ${JSON.stringify(\n p.path,\n )}, index: ${p.index}, routePath: ${JSON.stringify(p.routePath)}${\n extra.length ? \", \" + extra.join(\", \") : \"\"\n }, load: () => import(${JSON.stringify(specifier)}) },`,\n )\n }\n lines.push(\" ],\")\n lines.push(\"}\")\n lines.push(\"\")\n return lines.join(\"\\n\")\n}\n\nfunction renderServerRoutes(model: RouteModel): string {\n const lines: string[] = []\n lines.push(BANNER)\n lines.push(`import type { ProdApiRoute } from \"${PKG}/server/node\"`)\n model.apis.forEach((a, i) => {\n lines.push(`import * as m${i} from ${JSON.stringify(importFromVantage(a.file))}`)\n })\n lines.push(\"\")\n lines.push(\"export const apiRoutes: ProdApiRoute[] = [\")\n model.apis.forEach((a, i) => {\n lines.push(\n ` { routePath: ${JSON.stringify(a.routePath)}, segments: ${serializeSegments(\n a.segments,\n )}, module: m${i} },`,\n )\n })\n lines.push(\"]\")\n lines.push(\"\")\n return lines.join(\"\\n\")\n}\n\nfunction renderIndexHtml(): string {\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Vantage</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/.vantage/client-entry.tsx\"></script>\n </body>\n</html>\n`\n}\n\nfunction renderClientEntry(): string {\n return `${BANNER}import { bootstrap } from \"${PKG}/client\"\nimport { manifest } from \"./route-tree.gen\"\nimport \"./runtime.css\"\n\nbootstrap(manifest)\n`\n}\n\nfunction renderRuntimeCss(root: string, pageDir: string): string {\n const parts: string[] = []\n parts.push('@import \"tailwindcss\";')\n parts.push(`@import \"${PKG}/theme.css\";`)\n // The global stylesheet lives next to the pages: styles.css at the project\n // root, or src/styles.css once src/ exists (`SRC_DIR_SPLIT` catches a leftover\n // root-level one instead of importing both).\n const stylesRel = pageDir === \"\" ? \"styles.css\" : `${pageDir}/styles.css`\n if (fs.existsSync(path.join(root, stylesRel))) {\n parts.push(`@import \"../${stylesRel}\";`)\n }\n // Tailwind auto-detects the Vite project root; the packaged components live\n // in node_modules, which Tailwind skips by default, so register them here.\n // The whole of dist/ has to be scanned, not just dist/ui and dist/components:\n // tsup hoists code shared between entries into top-level dist/chunk-*.js, and\n // that is where most of the component class strings end up.\n const vantageDir = resolveVantageDir(root)\n if (vantageDir) {\n parts.push(`@source ${JSON.stringify(path.join(vantageDir, \"dist\"))};`)\n }\n return parts.join(\"\\n\") + \"\\n\"\n}\n\nfunction renderEnvTypes(): string {\n return `${BANNER}\ninterface ImportMetaEnv {\n readonly MODE: string\n readonly DEV: boolean\n readonly PROD: boolean\n readonly SSR: boolean\n readonly BASE_URL: string\n readonly [key: \\`PUBLIC_\\${string}\\`]: string | undefined\n}\n\ninterface ImportMeta {\n readonly env: ImportMetaEnv\n}\n\ndeclare module \"*.css\" {\n const content: string\n export default content\n}\n\n// Generated data-file pages import their source with Vite's asset query. The\n// app's tsconfig includes .vantage/**/*.tsx, so the wrappers are type-checked\n// alongside the app and need this declaration to resolve.\ndeclare module \"*?url&no-inline\" {\n const src: string\n export default src\n}\n`\n}\n\nfunction renderInternalManifest(model: RouteModel): string {\n return (\n JSON.stringify(\n {\n schemaVersion: MANIFEST_SCHEMA_VERSION,\n pageDir: model.pageDir,\n pages: model.pages.map((p) => ({ file: p.file, route: p.routePath })),\n apis: model.apis.map((a) => ({ file: a.file, route: a.routePath })),\n hasServer: model.hasServer,\n },\n null,\n 2,\n ) + \"\\n\"\n )\n}\n\n/**\n * The wrapper module standing in for one data-file page. Thin on purpose: the\n * asset import is what puts the file through Vite's pipeline (hashed in the\n * build, a stable URL in dev), and everything else lives in the viewer.\n */\nfunction renderFilePageWrapper(page: BuiltPage): string {\n const fileName = path.posix.basename(page.file)\n const props = [\n `kind=${JSON.stringify(filePageKind(page))}`,\n \"src={src}\",\n `fileName={${JSON.stringify(fileName)}}`,\n ...(page.title ? [`title={${JSON.stringify(page.title)}}`] : []),\n ]\n return `${BANNER}import { FilePageView } from \"${PKG}/table\"\nimport src from ${JSON.stringify(importFromFilePages(page.file) + ASSET_QUERY)}\n\n// ${page.file} -> ${page.routePath}\nexport default function FilePage() {\n return <FilePageView ${props.join(\" \")} />\n}\n`\n}\n\n/**\n * One wrapper module per data-file page. `writeIfChanged` never deletes, so\n * orphans are pruned explicitly: a renamed `.csv` would otherwise leave behind\n * a wrapper importing a file that no longer exists — invisible to the build\n * (rollup only follows the manifest) but a hard error in the app's own `tsc`.\n */\nfunction writeFilePages(vantageDir: string, tree: { pages: BuiltPage[] }): void {\n const dir = path.join(vantageDir, FILE_PAGES_DIR)\n const filePages = tree.pages.filter((p) => p.kind === \"file\")\n if (filePages.length === 0) {\n fs.rmSync(dir, { recursive: true, force: true })\n return\n }\n ensureDir(dir)\n const keep = new Set<string>()\n for (const page of filePages) {\n const name = filePageModuleName(page)\n keep.add(name)\n writeIfChanged(path.join(dir, name), renderFilePageWrapper(page))\n }\n for (const entry of fs.readdirSync(dir)) {\n if (!keep.has(entry)) fs.rmSync(path.join(dir, entry), { force: true })\n }\n}\n\n/** Options controlling artifact generation. */\nexport interface GenerateOptions {\n root: string\n model: RouteModel\n}\n\n/**\n * Regenerate the `.vantage/` directory from a route model. Idempotent and\n * content-stable so it does not thrash file watchers.\n */\nexport function generateArtifacts({ root, model }: GenerateOptions): string {\n return timed(\"generate\", () => {\n const vantageDir = path.join(root, VANTAGE_DIR)\n ensureDir(vantageDir)\n ensureDir(path.join(vantageDir, \"types\"))\n\n // Everything in .vantage is generated and git/agent/search invisible.\n writeIfChanged(path.join(vantageDir, \".gitignore\"), \"*\\n\")\n writeIfChanged(path.join(vantageDir, \"index.html\"), renderIndexHtml())\n writeIfChanged(path.join(vantageDir, \"client-entry.tsx\"), renderClientEntry())\n // Built once and shared: `renderRouteTree` and `writeFilePages` need the\n // same tree, and building it twice re-reads every page module for metadata.\n const tree = buildRouteTree(model)\n writeIfChanged(path.join(vantageDir, \"route-tree.gen.ts\"), renderRouteTree(tree))\n writeIfChanged(path.join(vantageDir, \"runtime.css\"), renderRuntimeCss(root, model.pageDir))\n writeIfChanged(path.join(vantageDir, \"types\", \"env.d.ts\"), renderEnvTypes())\n writeIfChanged(path.join(vantageDir, \"manifest.json\"), renderInternalManifest(model))\n\n writeFilePages(vantageDir, tree)\n\n if (model.hasServer) {\n writeIfChanged(path.join(vantageDir, \"server-routes.gen.ts\"), renderServerRoutes(model))\n }\n\n return vantageDir\n })\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/query/api.ts","../src/query/hooks.ts"],"names":[],"mappings":"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","file":"chunk-PVTHHV7X.js","sourcesContent":["/**\n * The one seam for calling the API from client code. All `/api/*` requests go\n * through here so a split deployment (client on S3/CloudFront, server on Lambda)\n * can point the client at a different origin without touching page code.\n *\n * The base is read from `import.meta.env.PUBLIC_API_BASE_URL` — a `PUBLIC_`\n * prefixed var so it is inlined into the client bundle (see envPrefix in the\n * Vite plugin). It can be set in `.env` or injected at build time via\n * `vantage build --api-base-url <url>`. When unset it is empty, so requests stay\n * same-origin relative paths — identical to hand-written `fetch(\"/api/...\")`.\n */\n\n/** The configured API base URL (no trailing slash), or \"\" for same-origin. */\nexport function apiBaseUrl(): string {\n // `import.meta.env` is typed in the generated .vantage/types, not here.\n const env = (import.meta as { env?: Record<string, string | undefined> }).env\n const raw = env?.PUBLIC_API_BASE_URL ?? \"\"\n return raw.replace(/\\/+$/, \"\")\n}\n\n/**\n * Build a full API URL. Pass the path exactly as it maps to `server/api/**`,\n * including the `/api` prefix — e.g. `apiUrl(\"/api/customers\")`. With no base\n * configured this returns the relative path unchanged.\n */\nexport function apiUrl(path: string): string {\n const rel = path.startsWith(\"/\") ? path : `/${path}`\n return apiBaseUrl() + rel\n}\n\n/**\n * Thin `fetch` wrapper that resolves the path against the API base. Returns the\n * raw `Response` — parsing and error handling stay with the caller, matching the\n * existing `queryFn` style.\n */\nexport function apiFetch(path: string, init?: RequestInit): Promise<Response> {\n return fetch(apiUrl(path), init)\n}\n\n/** Query-string values accepted by the API helpers. */\nexport type ApiSearch = Record<\n string,\n string | number | boolean | null | undefined | (string | number)[]\n>\n\n/**\n * Append a query string to an API path. `undefined`/`null` entries are dropped\n * so an unset filter leaves the URL — and the query key — unchanged. Array\n * values repeat the key, matching `URLSearchParams.getAll` on the server.\n */\nexport function apiPath(path: string, search?: ApiSearch): string {\n if (!search) return path\n const params = new URLSearchParams()\n // Sorted so two calls with the same filters produce the same query key.\n for (const key of Object.keys(search).sort()) {\n const value = search[key]\n if (value === undefined || value === null) continue\n if (Array.isArray(value)) {\n for (const item of value) params.append(key, String(item))\n } else {\n params.append(key, String(value))\n }\n }\n const qs = params.toString()\n if (!qs) return path\n return path + (path.includes(\"?\") ? \"&\" : \"?\") + qs\n}\n\n/**\n * A non-2xx response from `server/api`. `message` is the server's `HttpError`\n * message when there was one; anything else surfaces as a generic status text,\n * mirroring what the server chose to disclose.\n */\nexport class ApiError extends Error {\n /** HTTP status of the response. */\n readonly status: number\n /** Parsed response body, when there was one. */\n readonly body: unknown\n /** `x-vantage-request-id`, to correlate with the server's terminal log. */\n readonly requestId: string | undefined\n\n constructor(message: string, status: number, body: unknown, requestId?: string) {\n super(message)\n this.name = \"ApiError\"\n this.status = status\n this.body = body\n this.requestId = requestId\n }\n}\n\n/**\n * Fetch an API route and parse its JSON, throwing `ApiError` on a non-2xx.\n * This is what the API hooks call; use it directly in a loader or an event\n * handler where a hook doesn't fit.\n */\nexport async function apiJson<T = unknown>(path: string, init?: RequestInit): Promise<T> {\n const res = await apiFetch(path, init)\n const requestId = res.headers.get(\"x-vantage-request-id\") ?? undefined\n\n // Read as text first: an error response may be HTML from a proxy, and a 204\n // has no body at all — neither should throw a JSON parse error at the caller.\n const text = await res.text()\n let body: unknown\n if (text) {\n try {\n body = JSON.parse(text)\n } catch {\n body = text\n }\n }\n\n if (!res.ok) {\n const serverMessage =\n typeof body === \"object\" && body !== null && typeof (body as { error?: unknown }).error === \"string\"\n ? (body as { error: string }).error\n : undefined\n throw new ApiError(\n serverMessage ?? `${res.status} ${res.statusText || \"Request failed\"}`,\n res.status,\n body,\n requestId,\n )\n }\n\n return body as T\n}\n","/**\n * Hooks for the app's own `server/api` routes. They are `useQuery`/`useMutation`\n * with the parts every page was repeating — base URL, JSON parsing, non-2xx to\n * `ApiError`, a query key derived from the URL — moved into the framework.\n * Everything else about TanStack Query stays available through the options.\n */\nimport { useMutation, useQuery } from \"@tanstack/react-query\"\nimport type {\n QueryKey,\n UseMutationOptions,\n UseMutationResult,\n UseQueryOptions,\n UseQueryResult,\n} from \"@tanstack/react-query\"\nimport { apiJson, apiPath, type ApiError, type ApiSearch } from \"./api\"\n\n/** Query-key namespace, so `invalidateQueries({ queryKey: [\"api\"] })` works. */\nconst API_KEY = \"api\"\n\nexport interface ApiQueryOptions<TData>\n extends Omit<UseQueryOptions<TData, ApiError>, \"queryKey\" | \"queryFn\"> {\n /** Query-string values; `undefined` entries are omitted. */\n search?: ApiSearch\n /** Extra `fetch` init (headers, credentials, …). */\n init?: RequestInit\n /** Override the derived `[\"api\", url]` key. */\n queryKey?: QueryKey\n}\n\n/**\n * GET an API route.\n *\n * ```tsx\n * const { data, isPending, error } = useApiQuery<Monthly>(\"/api/monthly-analysis\")\n * const filtered = useApiQuery<Row[]>(\"/api/customers\", { search: { segment } })\n * ```\n *\n * The key defaults to `[\"api\", <url with query string>]`, so changing `search`\n * refetches and `invalidateQueries({ queryKey: [\"api\"] })` clears everything.\n */\nexport function useApiQuery<TData = unknown>(\n path: string,\n options: ApiQueryOptions<TData> = {},\n): UseQueryResult<TData, ApiError> {\n const { search, init, queryKey, ...rest } = options\n const url = apiPath(path, search)\n return useQuery<TData, ApiError>({\n queryKey: queryKey ?? [API_KEY, url],\n // The signal comes from TanStack so an unmounted/refetched query aborts;\n // a caller-supplied signal wins.\n queryFn: ({ signal }) => apiJson<TData>(url, { ...init, signal: init?.signal ?? signal }),\n ...rest,\n })\n}\n\nexport interface ApiMutationOptions<TData, TVariables>\n extends Omit<UseMutationOptions<TData, ApiError, TVariables>, \"mutationFn\"> {\n /** HTTP method (default `\"POST\"`). */\n method?: \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\"\n /** Extra `fetch` init (headers, credentials, …). */\n init?: RequestInit\n}\n\n/**\n * Write to an API route. The mutation variables are sent as the JSON body.\n *\n * ```tsx\n * const save = useApiMutation<Customer, { id: string; name: string }>(\n * (vars) => `/api/customers/${vars.id}`,\n * { method: \"PUT\" },\n * )\n * save.mutate({ id: \"1\", name: \"Northwind\" })\n * ```\n */\nexport function useApiMutation<TData = unknown, TVariables = void>(\n path: string | ((variables: TVariables) => string),\n options: ApiMutationOptions<TData, TVariables> = {},\n): UseMutationResult<TData, ApiError, TVariables> {\n const { method = \"POST\", init, ...rest } = options\n return useMutation<TData, ApiError, TVariables>({\n mutationFn: (variables: TVariables) => {\n const url = typeof path === \"function\" ? path(variables) : path\n const hasBody = variables !== undefined && variables !== null\n return apiJson<TData>(url, {\n method,\n ...init,\n headers: hasBody\n ? { \"content-type\": \"application/json\", ...(init?.headers as Record<string, string>) }\n : init?.headers,\n ...(hasBody ? { body: JSON.stringify(variables) } : {}),\n })\n },\n ...rest,\n })\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/util.ts"],"names":[],"mappings":"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","file":"chunk-QI3XQKHS.js","sourcesContent":["import fs from \"node:fs\"\nimport path from \"node:path\"\nimport pc from \"picocolors\"\nimport { PAGE_EXTENSIONS } from \"../core/constants\"\nimport type { Diagnostic } from \"../core/types\"\n\n/** Parsed CLI arguments. */\nexport interface ParsedArgs {\n positionals: string[]\n flags: Record<string, string | boolean>\n}\n\n/** Flags that never take a value, so they don't swallow the next token. */\nconst BOOLEAN_FLAGS = new Set([\n \"json\",\n \"help\",\n \"force\",\n \"verbose\",\n \"version\",\n \"all\",\n \"list\",\n \"regex\",\n \"pages\",\n \"apis\",\n \"detail\",\n \"strict-port\",\n \"no-strict-port\",\n \"overlay\",\n \"no-overlay\",\n \"h\",\n \"v\",\n])\n\n/**\n * Flags whose value is optional: bare `--host` means `true` (all interfaces),\n * `--host 0.0.0.0` / `--host=::` carry the address. The next token is taken as\n * the value only when it does not look like another flag, so `--host --port 3000`\n * still reads as two flags. Write `--host=<addr>` when the following token could\n * be mistaken for the value (e.g. a positional).\n */\nconst OPTIONAL_VALUE_FLAGS = new Set([\"host\"])\n\n/** Minimal argv parser: `--json`, `--port 3000`, `--port=3000`, `-v`, positionals. */\nexport function parseArgs(argv: string[]): ParsedArgs {\n const positionals: string[] = []\n const flags: Record<string, string | boolean> = {}\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]!\n if (arg.startsWith(\"--\")) {\n const eq = arg.indexOf(\"=\")\n if (eq !== -1) {\n flags[arg.slice(2, eq)] = arg.slice(eq + 1)\n continue\n }\n const key = arg.slice(2)\n if (BOOLEAN_FLAGS.has(key)) {\n flags[key] = true\n continue\n }\n const next = argv[i + 1]\n if (OPTIONAL_VALUE_FLAGS.has(key)) {\n if (next !== undefined && !next.startsWith(\"-\")) {\n flags[key] = next\n i++\n } else {\n flags[key] = true\n }\n continue\n }\n if (next !== undefined && !next.startsWith(\"-\")) {\n flags[key] = next\n i++\n } else {\n flags[key] = true\n }\n } else if (arg.length > 1 && arg.startsWith(\"-\") && !/^-\\d/.test(arg)) {\n // Single-dash short flags, e.g. `-v`, `-h` (each char is a boolean).\n for (const ch of arg.slice(1)) flags[ch] = true\n } else {\n positionals.push(arg)\n }\n }\n return { positionals, flags }\n}\n\n/**\n * Apply a `--api-base-url <url>` flag by setting `process.env.PUBLIC_API_BASE_URL`\n * so Vite inlines it into the client bundle (via envPrefix). Setting it on\n * process.env gives the flag precedence over any `.env` file value. No-op when\n * the flag is absent, leaving any `.env` value in effect.\n */\nexport function applyApiBaseUrlFlag(args: ParsedArgs): void {\n const value = args.flags[\"api-base-url\"]\n if (typeof value === \"string\" && value.length) {\n process.env.PUBLIC_API_BASE_URL = value\n }\n}\n\n/** A resolved `--port`, or the reason it could not be resolved. */\nexport type PortResolution =\n | { ok: true; port: number; strictPort: boolean }\n | { ok: false; error: string }\n\n/**\n * Resolve `--port` / `--strict-port` / `--no-strict-port` into Vite's server\n * options.\n *\n * An explicit `--port` is strict by default: writing `--port 3000` means the\n * port is a contract with something outside this process — a reverse proxy, a\n * container port mapping, an OAuth redirect URI — so binding 3001 instead is a\n * silent failure, not a recovery (a supervisor that only checks \"is anything\n * listening on 3000\" will happily report a server that nobody can reach).\n * Without the flag the default is merely \"some free port\", so Vite keeps\n * walking to the next one as it always has, and running two projects at once\n * needs no ceremony. `--strict-port` / `--no-strict-port` override either way.\n *\n * A bad value is an error rather than a silent fallback, for the same reason:\n * a typo'd `--port` that quietly became 5173 is exactly the failure strictness\n * exists to prevent.\n */\nexport function resolvePortOptions(\n flags: Record<string, string | boolean>,\n fallback: number,\n): PortResolution {\n const raw = flags.port\n let port = fallback\n if (raw !== undefined) {\n if (typeof raw !== \"string\") return { ok: false, error: \"--port needs a number, e.g. --port 3000\" }\n const n = Number(raw)\n if (!Number.isInteger(n) || n < 1 || n > 65535) {\n return { ok: false, error: `Invalid --port \"${raw}\" — use an integer between 1 and 65535.` }\n }\n port = n\n }\n const strictPort = flags[\"no-strict-port\"]\n ? false\n : Boolean(flags[\"strict-port\"]) || raw !== undefined\n return { ok: true, port, strictPort }\n}\n\n/** Environment variable read for `allowedHosts` when the flag is absent. */\nexport const ALLOWED_HOSTS_ENV = \"VANTAGE_ALLOWED_HOSTS\"\n\n/** Resolved `--host` / `--allowed-hosts`, or the reason they could not be resolved. */\nexport type HostResolution =\n | { ok: true; options: { host?: string | true; allowedHosts?: string[] | true } }\n | { ok: false; error: string }\n\n/**\n * Resolve `--host [addr]` and `--allowed-hosts <list|true>` (falling back to\n * `VANTAGE_ALLOWED_HOSTS`) into the subset of Vite's server options they map to.\n *\n * Only the keys that were actually set are returned, so spreading the result\n * into `server` / `preview` leaves Vite's defaults untouched when neither is\n * given — the default behaviour must not change for anyone who never asked.\n *\n * `allowedHosts` exists because Vite rejects (403) any request whose `Host`\n * is not localhost or the bound address. A reverse proxy in front of the dev\n * server — a sandbox preview proxy, a tunnel, a container network — presents\n * its own hostname, so that hostname must be listed (or the check disabled\n * with the literal `true`). The env form is for supervisors that start the\n * server and know the hostname; an explicit flag still wins over it.\n */\nexport function resolveHostOptions(\n flags: Record<string, string | boolean>,\n env: NodeJS.ProcessEnv = process.env,\n): HostResolution {\n const options: { host?: string | true; allowedHosts?: string[] | true } = {}\n\n const host = flags.host\n // bare `--host` and `--host=` both mean \"every interface\"\n if (host === true || host === \"\") options.host = true\n else if (typeof host === \"string\") options.host = host\n\n const flag = flags[\"allowed-hosts\"]\n if (flag === true) {\n return {\n ok: false,\n error: `--allowed-hosts needs a comma-separated list of hostnames, or \"true\" to allow any`,\n }\n }\n const raw = typeof flag === \"string\" ? flag : env[ALLOWED_HOSTS_ENV]\n const allowedHosts = parseAllowedHosts(raw)\n if (allowedHosts !== undefined) options.allowedHosts = allowedHosts\n\n return { ok: true, options }\n}\n\n/** `\"a,b\"` → `[\"a\",\"b\"]`, the literal `true` → `true`, unset/blank → undefined (Vite default). */\nfunction parseAllowedHosts(raw: string | undefined): string[] | true | undefined {\n if (raw === undefined) return undefined\n const trimmed = raw.trim()\n if (trimmed === \"\") return undefined\n if (trimmed === \"true\") return true\n const hosts = trimmed\n .split(\",\")\n .map((h) => h.trim())\n .filter((h) => h.length > 0)\n return hosts.length ? hosts : undefined\n}\n\n/**\n * Resolve `--overlay` / `--no-overlay` into Vite's `server.hmr.overlay`.\n *\n * The overlay stays on by default — it is the fastest way for a human to see a\n * runtime error. `--no-overlay` is for the cases where a full-screen error card\n * is in the way rather than helpful: screenshots and demos, and agent-driven\n * sessions where the error already arrives in the terminal through console\n * forwarding and the overlay only obscures the page being inspected.\n */\nexport function resolveHmrOverlay(flags: Record<string, string | boolean>): boolean {\n if (flags.overlay) return true\n return !flags[\"no-overlay\"]\n}\n\n/**\n * Report a strict bind that lost the port, in the one shape dev and preview\n * share. Returns false when `err` is anything else, so the caller rethrows.\n * Vite throws a plain Error (no `code`) for this, hence the message match — a\n * reworded Vite message degrades to the generic handler, not to a wrong one.\n */\nexport function reportPortInUse(err: unknown, port: number, strictPort: boolean): boolean {\n if (!strictPort || !(err instanceof Error) || !/already in use/.test(err.message)) return false\n log.error(`Port ${port} is already in use.`)\n log.info(\" free that port, pass a different --port, or --no-strict-port to take the next one\")\n return true\n}\n\n/** Resolve the project root, honoring `--root`, defaulting to cwd. */\nexport function resolveRoot(flags: Record<string, string | boolean>): string {\n const raw = typeof flags.root === \"string\" ? flags.root : process.cwd()\n return path.resolve(raw)\n}\n\n/** How far up from a page file to look for the package root. */\nconst QUICK_ROOT_MAX_DEPTH = 5\n\n/**\n * Resolve a positional path to a quick-run project root.\n * A directory → itself; a page file (.tsx/.jsx) → its project; else null.\n */\nexport function resolveQuickRoot(target: string): string | null {\n try {\n const abs = path.resolve(target)\n const stat = fs.statSync(abs)\n if (stat.isDirectory()) return abs\n if (stat.isFile() && PAGE_EXTENSIONS.some((ext) => abs.endsWith(ext))) {\n // Walk up to the nearest package.json so `vantage ./demo/src/index.tsx`\n // starts in ./demo — the directory holding the page is not the project\n // root once pages live under src/ (or in any nested route directory).\n let dir = path.dirname(abs)\n for (let i = 0; i <= QUICK_ROOT_MAX_DEPTH; i++) {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir\n const parent = path.dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n return path.dirname(abs)\n }\n } catch {\n // statSync throws when the path does not exist → null (not a quick target)\n }\n return null\n}\n\nexport const log = {\n info: (msg: string) => console.log(msg),\n step: (msg: string) => console.log(pc.cyan(\"→ \") + msg),\n ok: (msg: string) => console.log(pc.green(\"✓ \") + msg),\n warn: (msg: string) => console.log(pc.yellow(\"! \") + msg),\n error: (msg: string) => console.error(pc.red(\"✗ \") + msg),\n brand: (msg: string) => console.log(pc.bold(pc.magenta(\"vantage \")) + msg),\n}\n\n/** Print diagnostics as human-readable text. */\nexport function printDiagnostics(diags: Diagnostic[]): void {\n for (const d of diags) {\n const badge =\n d.severity === \"error\" ? pc.red(pc.bold(\" ERROR \")) : pc.yellow(pc.bold(\" WARN \"))\n console.log(`${badge} ${pc.dim(d.code)} ${d.message}`)\n if (d.files?.length) console.log(` ${pc.dim(\"files:\")} ${d.files.join(\", \")}`)\n if (d.fix) console.log(` ${pc.dim(\"fix:\")} ${d.fix}`)\n }\n}\n\n/** Emit a JSON payload to stdout (for agent consumption). */\nexport function printJson(payload: unknown): void {\n process.stdout.write(JSON.stringify(payload, null, 2) + \"\\n\")\n}\n\n/** Read the vantage package version. */\nexport function frameworkVersion(): string {\n try {\n // dist/cli.js (and shared chunks) live in dist/, so package.json is one up.\n const url = new URL(\"../package.json\", import.meta.url)\n const pkg = JSON.parse(fs.readFileSync(url, \"utf8\")) as { version: string }\n return pkg.version\n } catch {\n return \"0.0.0\"\n }\n}\n\nexport function fileExists(p: string): boolean {\n try {\n return fs.existsSync(p)\n } catch {\n return false\n }\n}\n"]}