@squadbase/vantage 0.4.0 → 0.5.1

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 (56) hide show
  1. package/README.md +1 -1
  2. package/dist/add-PPCBMWEN.js +6 -0
  3. package/dist/add-PPCBMWEN.js.map +1 -0
  4. package/dist/{build-77KHIRWR.js → build-756WIEVI.js} +4 -4
  5. package/dist/{build-77KHIRWR.js.map → build-756WIEVI.js.map} +1 -1
  6. package/dist/{check-26U4O5UW.js → check-KZ5PHCA6.js} +3 -3
  7. package/dist/{check-26U4O5UW.js.map → check-KZ5PHCA6.js.map} +1 -1
  8. package/dist/{chunk-N6HAGEUA.js → chunk-HQDEYCDP.js} +9 -3
  9. package/dist/chunk-HQDEYCDP.js.map +1 -0
  10. package/dist/{chunk-R2YYVCGS.js → chunk-L3TW4FNA.js} +12 -62
  11. package/dist/chunk-L3TW4FNA.js.map +1 -0
  12. package/dist/{chunk-ZIM745WE.js → chunk-X44ZTKID.js} +3 -3
  13. package/dist/{chunk-ZIM745WE.js.map → chunk-X44ZTKID.js.map} +1 -1
  14. package/dist/cli.js +12 -11
  15. package/dist/cli.js.map +1 -1
  16. package/dist/{dev-5K2PNSXT.js → dev-EILX2VTF.js} +8 -5
  17. package/dist/dev-EILX2VTF.js.map +1 -0
  18. package/dist/{docs-XEPM66VI.js → docs-GP2ZHIQF.js} +3 -3
  19. package/dist/{docs-XEPM66VI.js.map → docs-GP2ZHIQF.js.map} +1 -1
  20. package/dist/{doctor-6UMWKG6L.js → doctor-FXZLMGC3.js} +3 -3
  21. package/dist/{doctor-6UMWKG6L.js.map → doctor-FXZLMGC3.js.map} +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/{preview-VXERMTHP.js → preview-WBQPCTTT.js} +3 -3
  26. package/dist/{preview-VXERMTHP.js.map → preview-WBQPCTTT.js.map} +1 -1
  27. package/dist/{routes-3JUXAYQJ.js → routes-WCN4KSZY.js} +3 -3
  28. package/dist/{routes-3JUXAYQJ.js.map → routes-WCN4KSZY.js.map} +1 -1
  29. package/dist/{search-NJJW4PXG.js → search-GLKCJXSI.js} +3 -3
  30. package/dist/{search-NJJW4PXG.js.map → search-GLKCJXSI.js.map} +1 -1
  31. package/dist/{upgrade-4XAY447F.js → upgrade-S64IXL42.js} +4 -4
  32. package/dist/{upgrade-4XAY447F.js.map → upgrade-S64IXL42.js.map} +1 -1
  33. package/dist/vite/index.d.ts +1 -1
  34. package/dist/vite/index.js +1 -1
  35. package/docs/en/changelog.md +70 -0
  36. package/docs/en/cli-reference.md +32 -0
  37. package/docs/en/getting-started.md +3 -2
  38. package/docs/en/roadmap.md +199 -0
  39. package/docs/en/ui-and-theming.md +19 -0
  40. package/docs/index.json +22 -0
  41. package/docs/ja/changelog.md +66 -0
  42. package/docs/ja/cli-reference.md +31 -0
  43. package/docs/ja/getting-started.md +4 -2
  44. package/docs/ja/roadmap.md +196 -0
  45. package/docs/ja/ui-and-theming.md +20 -0
  46. package/package.json +1 -1
  47. package/skills/vantage-add-feature/SKILL.md +1 -1
  48. package/skills/vantage-app/SKILL.md +4 -3
  49. package/skills/vantage-pitfalls/SKILL.md +22 -0
  50. package/templates/AGENTS.md +18 -2
  51. package/theme.css +19 -0
  52. package/dist/add-GQEXRQSI.js +0 -6
  53. package/dist/add-GQEXRQSI.js.map +0 -1
  54. package/dist/chunk-N6HAGEUA.js.map +0 -1
  55. package/dist/chunk-R2YYVCGS.js.map +0 -1
  56. package/dist/dev-5K2PNSXT.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squadbase/vantage",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Data dashboard framework for Squadbase Editor. Vite-powered, config-free, one-file first.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -139,7 +139,7 @@ vantage add block sales-overview # → components/blocks/sales-overview.tsx
139
139
  ```bash
140
140
  vantage routes # 追加したページ/API が意図した URL に出ているか
141
141
  vantage check # 規約違反が無いか(exit 1 ならエラーあり)
142
- vantage dev # 実際に動くか(console は開発ターミナルに [browser:…] で転送)
142
+ vantage dev # 実際に動くか(warn/error と未捕捉エラーは開発ターミナルへ転送される)
143
143
  ```
144
144
 
145
145
  `vantage routes` は `--pages` / `--apis` で片側だけに絞れる。`--detail` を足すと各ルートの静的な
@@ -44,7 +44,7 @@ exit 1 になる。
44
44
  "routes": "vantage routes"
45
45
  },
46
46
  "dependencies": {
47
- "@squadbase/vantage": "^0.4.0",
47
+ "@squadbase/vantage": "^0.5.0",
48
48
  "react": "^19.2.7",
49
49
  "react-dom": "^19.2.7"
50
50
  }
@@ -116,8 +116,9 @@ pnpm preview # 本番ビルドをローカルで動かす
116
116
 
117
117
  ## 詰まったら
118
118
 
119
- - ブラウザの `console.*` とランタイムエラーは、**開発ターミナルに `[browser:…]` として転送
120
- される**。ブラウザの devtools を開かなくても読める。
119
+ - ブラウザの `console.warn` / `console.error` とランタイムエラーは、**開発ターミナルへ転送
120
+ される**(`[console.warn] …` / `[Unhandled error] …` + コードフレーム)。devtools を開かずに
121
+ 読める。`console.log` は転送されないので、**ターミナルで見たいログは `console.warn`** で出す。
121
122
  - `vantage check --json` / `vantage routes --json` は機械可読出力。
122
123
  - props や規約を確かめたいときは `vantage docs <name>`、名前が思い出せないときは
123
124
  `vantage search <やりたいこと>`。**推測で props を書かない。**
@@ -35,6 +35,28 @@ Base UI の `SelectValue` は選択中の **value をそのまま描き**、`Sel
35
35
 
36
36
  トリガーに `kanto` や `/sales` と生の値が出たら、まずこれを疑う。
37
37
 
38
+ ## 配色:素のパレット + `dark:` ではなく、セマンティックトークンで書く
39
+
40
+ 色は `text-foreground` / `text-muted-foreground` / `bg-card` / `border-border` などの
41
+ トークンで書く。トークンはライト / ダークの両方を持っているので、`dark:` を並べる必要が無い。
42
+
43
+ `text-slate-900 dark:text-slate-100` のような素の Tailwind パレット + `dark:` の組は、
44
+ **トークンで塗られた周囲と食い違う**。ダークトークンが効くのは祖先に `.dark` /
45
+ `[data-theme="dark"]` が付いているときだけで、`dark:` ユーティリティも同じスイッチに
46
+ 繋がっている(`theme.css` の `@custom-variant dark`)。つまり自分でクラスを付けない限り
47
+ アプリは常にライトで動くのに、素のパレットを使うとその 1 か所だけ手動で両モードを
48
+ 管理することになる。
49
+
50
+ ```tsx
51
+ // ✗ 手動で 2 モードを管理することになる
52
+ <div className="font-medium text-slate-900 dark:text-slate-100">{name}</div>
53
+ // ✓ トークンなら 1 つで済む
54
+ <div className="font-medium text-foreground">{name}</div>
55
+ ```
56
+
57
+ `--muted` / `--accent` / `--secondary` / `--border` は**背景・境界用**で、ライトではほぼ白。
58
+ 文字色に使うと読めなくなる ― 弱い文字色は `text-muted-foreground`。
59
+
38
60
  ## チャート:`EChart` の配色はトークン追従。上書きは `option.color`
39
61
 
40
62
  系列色は `--chart-1..5`、軸・凡例・ツールチップは文字色/境界色のトークンから組まれる
@@ -36,6 +36,11 @@ UI キット・開発サーバー・API サーバー・ビルドはすべて Van
36
36
  - **クライアントに届く env は `PUBLIC_` 接頭辞のものだけ。** `import.meta.env.PUBLIC_FOO`。
37
37
  それ以外を `import.meta.env` で読むと `PUBLIC_ENV_MISUSE` 警告。シークレットは
38
38
  `ApiContext.env`(server/ 内)にだけ届く。
39
+ - **色はセマンティックトークンで書く。** `text-foreground`・`text-muted-foreground`・`bg-card`・
40
+ `border-border`。トークンがライト / ダークの両方を持つので `dark:` を並べる必要が無い。
41
+ 素のパレット + `dark:`(`text-slate-900 dark:text-slate-100`)を混ぜると、その 1 か所だけ
42
+ 手動で 2 モードを管理することになる(→「ダークモードは opt-in」)。`--muted`・`--accent`・
43
+ `--secondary`・`--border` は背景・境界用で、文字色に使うと読めない。
39
44
  - **`.vantage/` と `dist/` は生成物。** 編集しない・読みにいかない(gitignore 済み)。任意の CLI
40
45
  コマンド、または `vantage upgrade` で再生成される。
41
46
  - **`definePage` の値はリテラルで書く。** title/description/navLabel はビルド時に静的抽出される
@@ -122,7 +127,7 @@ root/
122
127
  "routes": "vantage routes"
123
128
  },
124
129
  "dependencies": {
125
- "@squadbase/vantage": "^0.4.0",
130
+ "@squadbase/vantage": "^0.5.0",
126
131
  "react": "^19.2.7",
127
132
  "react-dom": "^19.2.7"
128
133
  }
@@ -318,6 +323,16 @@ const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST
318
323
  `ui: data-table` と `block: sales-overview` の 2 つだけ。それ以外の名前は import 専用で
319
324
  `add` の対象ではない(未知名で実行すると候補が一覧表示される)。
320
325
 
326
+ ### ダークモードは opt-in
327
+
328
+ ダークのトークンが効くのは、祖先に `.dark` か `[data-theme="dark"]` が付いているときだけ。
329
+ **OS / ブラウザの設定(`prefers-color-scheme`)は見ない。** `dark:` ユーティリティも同じ
330
+ スイッチに繋いであるので(`theme.css` の `@custom-variant dark`)、自分でクラスを付けない限り
331
+ アプリは常にライトで描かれる ― `dark:` を書いてもそこだけダークになることはない。
332
+
333
+ 明暗を切り替えたいときは、レイアウトのルート要素などに `.dark` / `data-theme="dark"` を
334
+ 自分で付ける。
335
+
321
336
  ## ドキュメントを引く(`vantage docs` / `vantage search`)
322
337
 
323
338
  ```bash
@@ -356,7 +371,8 @@ pnpm preview # 本番ビルドをローカル実行
356
371
  (手で書かない)。`vantage routes` は `--pages` / `--apis` で片側だけに絞れ、`--detail` を足すと
357
372
  各ルートの静的な仕様(ページ: パスパラメータ + `definePage` のメタ / API: メソッド・query・
358
373
  body・レスポンスの status と形)まで出る。`vantage check --json` / `vantage routes --json` は
359
- エージェント向けの機械可読出力。`console.*` とランタイムエラーは開発ターミナルに `[browser:…]` として転送される。
374
+ エージェント向けの機械可読出力。dev では `console.warn` / `console.error` とランタイムエラーが開発ターミナルへ
375
+ 転送される(`console.log` は転送されない)。エラーの全画面オーバーレイは `vantage dev --no-overlay` で消せる。
360
376
 
361
377
  ## さらに詳しく(同梱 Skill)
362
378
 
package/theme.css CHANGED
@@ -12,6 +12,12 @@
12
12
  on top — charts need distinguishable colours, not a greyscale ramp. */
13
13
 
14
14
  :root {
15
+ /* Native UI (scrollbars, form control popups, autofill) follows the OS unless
16
+ told otherwise. The tokens below don't, so pin it to the same switch —
17
+ otherwise a light app in an OS-dark browser gets dark scrollbars and a dark
18
+ `<select>` popup. */
19
+ color-scheme: light;
20
+
15
21
  --background: oklch(1 0 0);
16
22
  --foreground: oklch(0.145 0 0);
17
23
  --card: oklch(1 0 0);
@@ -51,6 +57,8 @@
51
57
 
52
58
  .dark,
53
59
  [data-theme="dark"] {
60
+ color-scheme: dark;
61
+
54
62
  --background: oklch(0.145 0 0);
55
63
  --foreground: oklch(0.985 0 0);
56
64
  --card: oklch(0.205 0 0);
@@ -145,6 +153,17 @@
145
153
  }
146
154
 
147
155
  /* ------------------------------------------------------- custom variants */
156
+
157
+ /* `dark:` must follow the same switch as the tokens above — the class, not the
158
+ OS setting. Tailwind v4's stock `dark` variant is `@media (prefers-color-scheme:
159
+ dark)`, so leaving it alone splits the theme in two: a browser in OS dark mode
160
+ activates every `dark:` utility while `--background`/`--foreground` stay light,
161
+ because no `.dark` class is present. The result is light-on-light — `dark:text-
162
+ slate-100` over a white card is invisible — and it hits Vantage's own kit too
163
+ (`dark:data-active:bg-input/30` and friends). `:is()` keeps the specificity
164
+ above the unprefixed utility, so `dark:` still wins when the class is set. */
165
+ @custom-variant dark (&:is(.dark, .dark *, [data-theme="dark"], [data-theme="dark"] *));
166
+
148
167
  /* Base UI reports state through `data-open`, `data-checked`, … rather than
149
168
  Radix's `data-state="open"`. These variants accept both spellings so the
150
169
  component classes read the same either way. */
@@ -1,6 +0,0 @@
1
- export { add, syncAgentsFile } from './chunk-ZIM745WE.js';
2
- import './chunk-D4Y5RWJA.js';
3
- import './chunk-N6HAGEUA.js';
4
- import './chunk-C4MQRWXS.js';
5
- //# sourceMappingURL=add-GQEXRQSI.js.map
6
- //# sourceMappingURL=add-GQEXRQSI.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"add-GQEXRQSI.js"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/util.ts"],"names":[],"mappings":"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","file":"chunk-N6HAGEUA.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 \"h\",\n \"v\",\n])\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 (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/**\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"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/dev.ts","../src/vite/index.ts"],"names":["path"],"mappings":"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","file":"chunk-R2YYVCGS.js","sourcesContent":["import { Hono } from \"hono\"\nimport { getRequestListener } from \"@hono/node-server\"\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport type { ViteDevServer } from \"vite\"\nimport type { RouteModel } from \"../core/types\"\nimport { corsMiddleware } from \"./cors\"\nimport {\n dispatchApi,\n matchApiRoute,\n sortApiRoutes,\n type ApiRouteEntry,\n} from \"./dispatch\"\nimport type { ApiModule } from \"./index\"\n\ntype Middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void\n\n/**\n * Build a connect-style middleware that serves `server/api/**` in dev. Modules\n * are loaded through Vite's SSR pipeline so edits hot-reload, and the route list\n * is read fresh on every request so added/removed API files take effect without\n * a restart.\n */\nexport function createApiDevMiddleware(opts: {\n server: ViteDevServer\n getModel: () => RouteModel\n getEnv: () => Record<string, string | undefined>\n}): Middleware {\n const { server, getModel, getEnv } = opts\n\n const buildRoutes = (): ApiRouteEntry[] =>\n sortApiRoutes(\n getModel().apis.map((a) => ({\n routePath: a.routePath,\n segments: a.segments,\n hasCatchall: a.segments.some((s) => s.kind === \"catchall\"),\n staticCount: a.segments.filter((s) => s.kind === \"static\").length,\n load: () => server.ssrLoadModule(a.absFile) as Promise<ApiModule>,\n })),\n )\n\n const app = new Hono()\n\n // CORS for split deployments, matching prod. Off unless CORS_ORIGIN is set;\n // read once here from the current env (dev's CORS config is deploy-level).\n const cors = corsMiddleware(getEnv())\n if (cors) {\n app.use(\"/api\", cors)\n app.use(\"/api/*\", cors)\n }\n\n const handle = async (c: { req: { url: string; raw: Request } }) => {\n const url = new URL(c.req.url)\n const match = matchApiRoute(buildRoutes(), url.pathname)\n if (!match) {\n return Response.json({ error: \"Not Found\", path: url.pathname }, { status: 404 })\n }\n let mod: ApiModule\n try {\n mod = await match.route.load()\n } catch (err) {\n if (err instanceof Error) server.ssrFixStacktrace(err)\n throw err\n }\n return dispatchApi(mod, c.req.raw, match.params, getEnv())\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n app.all(\"/api\", handle as any)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n app.all(\"/api/*\", handle as any)\n\n const listener = getRequestListener(app.fetch)\n\n return (req, res, next) => {\n const url = req.url ?? \"/\"\n const path = url.split(\"?\")[0]!\n if (path === \"/api\" || path.startsWith(\"/api/\")) {\n Promise.resolve(listener(req, res)).catch((err) => {\n console.error(\"[vantage] API middleware failure:\", err)\n if (!res.headersSent) {\n res.statusCode = 500\n res.setHeader(\"content-type\", \"application/json\")\n res.end(JSON.stringify({ error: \"Internal Server Error\" }))\n }\n })\n } else {\n next()\n }\n }\n}\n","import fs from \"node:fs\"\nimport path from \"node:path\"\nimport react from \"@vitejs/plugin-react\"\nimport tailwindcss from \"@tailwindcss/vite\"\nimport type { HtmlTagDescriptor, Plugin, PluginOption, ViteDevServer } from \"vite\"\nimport pc from \"picocolors\"\nimport { NON_ROUTE_DIRS, PAGE_EXTENSIONS, VANTAGE_DIR } from \"../core/constants\"\nimport { generateArtifacts } from \"../core/generate\"\nimport { resolvePageRoot, scanProject } from \"../core/scan\"\nimport type { RouteModel } from \"../core/types\"\nimport { createApiDevMiddleware } from \"../server/dev\"\n\nexport interface VantagePluginOptions {\n root: string\n /** Server-side env (process.env + loaded .env), passed to API handlers. */\n env?: Record<string, string | undefined>\n /**\n * A route model the caller already scanned. `dev`/`build` run diagnostics\n * before starting Vite, so without this the project would be walked a second\n * time for an answer that is milliseconds old.\n */\n model?: RouteModel\n /**\n * Set when the caller has already written `.vantage/` for `model`. `build`\n * does, so that the server bundle — which reads `server-routes.gen.ts` — can\n * be produced at the same time as the client instead of after it.\n */\n artifactsWritten?: boolean\n}\n\nconst DEDUPE = [\"react\", \"react-dom\", \"@tanstack/react-router\", \"@tanstack/react-query\"]\n\n/** Always prebundled: the generated client entry imports these on every start. */\nconst RUNTIME_DEPS = [\n \"react\",\n \"react-dom\",\n \"react-dom/client\",\n \"react/jsx-runtime\",\n \"@tanstack/react-router\",\n \"@tanstack/react-query\",\n]\n\n/**\n * The rest of the managed stack — everything `@squadbase/vantage/ui` and\n * `/components` pull in. Apps import framework subpaths, never these directly,\n * so Vantage knows the full set up front and Vite does not have to rediscover\n * it. Declaring them removes the second optimize wave (and the full page reload\n * it forces) the first time a page reaches for a new kit component.\n */\nconst KIT_DEPS = [\n \"@tanstack/react-table\",\n \"class-variance-authority\",\n \"clsx\",\n \"cmdk\",\n \"date-fns\",\n \"date-fns/locale\",\n \"echarts\",\n \"lucide-react\",\n \"react-day-picker\",\n \"tailwind-merge\",\n \"@base-ui/react/accordion\",\n \"@base-ui/react/button\",\n \"@base-ui/react/checkbox\",\n \"@base-ui/react/collapsible\",\n \"@base-ui/react/dialog\",\n \"@base-ui/react/input\",\n \"@base-ui/react/menu\",\n \"@base-ui/react/merge-props\",\n \"@base-ui/react/popover\",\n \"@base-ui/react/progress\",\n \"@base-ui/react/scroll-area\",\n \"@base-ui/react/select\",\n \"@base-ui/react/separator\",\n \"@base-ui/react/slider\",\n \"@base-ui/react/switch\",\n \"@base-ui/react/tabs\",\n \"@base-ui/react/toggle\",\n \"@base-ui/react/toggle-group\",\n \"@base-ui/react/tooltip\",\n \"@base-ui/react/use-render\",\n]\n\n/** The package part of a specifier: `@base-ui/react/select` → `@base-ui/react`. */\nfunction packageName(spec: string): string {\n const parts = spec.split(\"/\")\n return spec.startsWith(\"@\") ? parts.slice(0, 2).join(\"/\") : parts[0]!\n}\n\n/** Walk up `node_modules` chains looking for a package directory. */\nfunction hasPackage(fromDir: string, pkg: string): boolean {\n let dir = fromDir\n for (;;) {\n if (fs.existsSync(path.join(dir, \"node_modules\", pkg))) return true\n const parent = path.dirname(dir)\n if (parent === dir) return false\n dir = parent\n }\n}\n\n/**\n * Build `optimizeDeps.include`, keeping only specifiers that actually resolve\n * from the project root.\n *\n * Two constraints pin this down. Vite hard-errors on an include entry it cannot\n * resolve, so guessing is not an option. And Vite's own dependency discovery\n * names these packages *plainly* — so the `parent > child` form, which would\n * reach the copy inside the framework's own node_modules, does not merge with\n * what discovery finds: it prebundles a second, never-requested copy of every\n * entry (measured: 156 files instead of 78).\n *\n * The practical effect is that a hoisted install (npm/yarn, and pnpm with\n * hoisting) declares the whole managed stack up front and skips the second\n * optimize wave — the one that forces a full page reload the first time a page\n * reaches for a new kit component. Under a strict pnpm layout the kit resolves\n * only from the framework package, nothing extra is declared, and behaviour is\n * exactly what it was before.\n */\nfunction optimizeInclude(root: string): string[] {\n return [...RUNTIME_DEPS, ...KIT_DEPS].filter((spec) => hasPackage(root, packageName(spec)))\n}\n\n/** Page modules are scanned from the page root: `<root>/src` when it exists. */\nfunction isPageFile(pageRoot: string, file: string): boolean {\n const rel = path.relative(pageRoot, file)\n if (rel.startsWith(\"..\")) return false\n const segments = rel.split(path.sep)\n if (segments.some((s) => NON_ROUTE_DIRS.has(s) || (s.startsWith(\".\") && s !== \"..\"))) return false\n return PAGE_EXTENSIONS.some((ext) => file.endsWith(ext))\n}\n\nfunction isApiFile(root: string, file: string): boolean {\n const rel = path.relative(root, file)\n return rel.startsWith(`server${path.sep}api${path.sep}`) && /\\.(ts|tsx|js)$/.test(file) && !file.endsWith(\".d.ts\")\n}\n\nfunction isServerFile(root: string, file: string): boolean {\n const rel = path.relative(root, file)\n return rel === \"server\" || rel.startsWith(`server${path.sep}`)\n}\n\n/**\n * The single plugin that turns a plain Vite instance into Vantage: file-based\n * routing, generated entry/HTML, Tailwind, the server-import boundary, route\n * HMR and dev console forwarding.\n */\nexport function vantagePlugin(options: VantagePluginOptions): PluginOption {\n const root = path.resolve(options.root)\n const vantageDir = path.join(root, VANTAGE_DIR)\n let model: RouteModel = options.model ?? scanProject(root)\n /** Written once per start: `configResolved` and `buildStart` both need it. */\n let generated = Boolean(options.artifactsWritten)\n /** Cached dev shell, invalidated whenever the artifacts are rewritten. */\n let shellHtml: string | null = null\n\n /** Absolute page-scan root, kept in step with the last scan. */\n const pageRoot = (): string => (model.pageDir === \"\" ? root : path.join(root, model.pageDir))\n\n const emit = (): void => {\n generateArtifacts({ root, model })\n generated = true\n shellHtml = null\n }\n\n /** Write the artifacts for the model we already have, at most once per start. */\n const ensureGenerated = (): void => {\n if (!generated) emit()\n }\n\n const regenerate = (): void => {\n model = scanProject(root)\n emit()\n }\n\n const core: Plugin = {\n name: \"vantage:core\",\n enforce: \"pre\",\n\n config() {\n return {\n root,\n appType: \"custom\",\n envPrefix: [\"PUBLIC_\"],\n resolve: { dedupe: DEDUPE },\n optimizeDeps: { include: optimizeInclude(root) },\n build: {\n outDir: path.join(root, \"dist\", \"client\"),\n emptyOutDir: true,\n rollupOptions: {\n input: path.join(vantageDir, \"index.html\"),\n },\n },\n }\n },\n\n configResolved() {\n // Ensure .vantage exists before dev HTML serving or the build reads input.\n ensureGenerated()\n },\n\n buildStart() {\n // configResolved already ran in the normal path; this is the safety net\n // for embedders that construct the plugin without a full config pass.\n ensureGenerated()\n },\n\n // --- Server-import boundary: client code may never import server/. ---\n resolveId(source, importer, opts) {\n if (opts?.ssr) return null\n if (!importer) return null\n const imp = importer.split(\"?\")[0]!\n if (!imp.startsWith(root)) return null\n const relImp = path.relative(root, imp)\n if (\n relImp.startsWith(`server${path.sep}`) ||\n relImp.startsWith(VANTAGE_DIR) ||\n relImp.includes(\"node_modules\")\n ) {\n return null\n }\n let target: string | null = null\n if (source.startsWith(\".\")) target = path.resolve(path.dirname(imp), source)\n else if (source.startsWith(\"/\")) target = path.join(root, source.slice(1))\n else if (source === \"server\" || source.startsWith(\"server/\")) target = path.join(root, source)\n if (!target) return null\n const relTarget = path.relative(root, target)\n if (relTarget === \"server\" || relTarget.startsWith(`server${path.sep}`)) {\n this.error(\n `Client module \"${relImp}\" imports from server/ (\"${source}\"). ` +\n `server/ code must never reach the client bundle — move shared code to lib/.`,\n )\n }\n return null\n },\n\n // --- Keep React Fast Refresh working on page modules. ---\n // `export const page = definePage(...)` is a non-component export, which\n // makes @vitejs/plugin-react bail out of Fast Refresh (full reload). The\n // runtime never reads this export (title/description are extracted at\n // generate time), so we drop the `export` keyword — turning it into a local\n // const — before the React plugin analyzes the module. Offsets are\n // preserved (6 spaces for \"export\") so sourcemaps stay accurate.\n transform(code, id) {\n const clean = id.split(\"?\")[0]!\n if (!isPageFile(pageRoot(), clean)) return null\n if (!/export\\s+const\\s+page\\b/.test(code)) return null\n // Anchor to line start so `export const page` inside a string/comment is\n // not rewritten. \"export\" (6 chars) becomes 6 spaces to keep offsets.\n const out = code.replace(\n /^([ \\t]*)export(\\s+const\\s+page\\b)/gm,\n (_m, indent: string, rest: string) => indent + \" \" + rest,\n )\n if (out === code) return null\n return { code: out, map: null }\n },\n\n // --- Dev console + runtime errors forwarded to the terminal. ---\n transformIndexHtml: {\n order: \"pre\",\n handler(_html, ctx): HtmlTagDescriptor[] {\n if (!ctx.server) return []\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\" },\n injectTo: \"head-prepend\",\n children: CONSOLE_BRIDGE,\n },\n ]\n },\n },\n\n configureServer(server: ViteDevServer) {\n const getEnv = () => options.env ?? (process.env as Record<string, string | undefined>)\n\n // API requests handled before Vite's own middlewares.\n const apiMw = createApiDevMiddleware({ server, getModel: () => model, getEnv })\n server.middlewares.use((req, res, next) => {\n const url = (req.url ?? \"/\").split(\"?\")[0]\n if (url === \"/__vantage_console\" && req.method === \"POST\") {\n return handleConsoleBeacon(req, res)\n }\n // Without server/, /api/* is a normal client route: fall through to the\n // SPA shell instead of returning API 404s (matches production).\n if (model.hasServer) return apiMw(req, res, next)\n return next()\n })\n\n // Structural route changes -> regenerate manifest + reload. Adding or\n // removing styles.css also changes the generated runtime.css.\n const isStylesFile = (file: string) => path.relative(pageRoot(), file) === \"styles.css\"\n // Creating or deleting src/ moves the page root itself, which changes\n // every generated import even though no page file was touched.\n const rootMoved = () => resolvePageRoot(root).dir !== model.pageDir\n const onStructural = (file: string) => {\n if (rootMoved() || isPageFile(pageRoot(), file) || isApiFile(root, file) || isStylesFile(file)) {\n regenerate()\n server.ws.send({ type: \"full-reload\" })\n }\n }\n /**\n * A new directory can introduce route segments, so it has to be scanned —\n * but only when it could actually hold pages or API modules. Rescanning on\n * every mkdir (node_modules churn, build output, dot-dirs) walks the whole\n * project for nothing.\n */\n const isRouteDir = (dir: string) => {\n if (isServerFile(root, dir)) return true\n const rel = path.relative(pageRoot(), dir)\n if (rel === \"\" || rel.startsWith(\"..\")) return false\n return !rel.split(path.sep).some((s) => NON_ROUTE_DIRS.has(s) || s.startsWith(\".\"))\n }\n server.watcher.on(\"add\", onStructural)\n server.watcher.on(\"unlink\", onStructural)\n server.watcher.on(\"addDir\", (dir) => {\n if (rootMoved() || isRouteDir(dir)) regenerate()\n })\n server.watcher.on(\"unlinkDir\", (dir) => {\n if (!rootMoved() && !isRouteDir(dir)) return\n regenerate()\n server.ws.send({ type: \"full-reload\" })\n })\n server.watcher.on(\"change\", (file) => {\n if (isServerFile(root, file)) {\n const mods = server.moduleGraph.getModulesByFile(file)\n if (mods) for (const m of mods) server.moduleGraph.invalidateModule(m)\n }\n })\n\n // SPA fallback: serve the generated index.html for navigations.\n return () => {\n server.middlewares.use(async (req, res, next) => {\n if (req.method !== \"GET\" && req.method !== \"HEAD\") return next()\n // Standard SPA fallback: anything Vite's own middlewares didn't handle\n // (real modules, assets, /@vite, /@id) resolves to the app shell.\n try {\n // The shell is generated, not authored, and the plugin set that\n // transforms it is fixed — so the result only changes when the\n // artifacts are rewritten. Caching it keeps every navigation from\n // re-running the whole HTML transform chain.\n if (shellHtml === null) {\n const raw = fs.readFileSync(path.join(vantageDir, \"index.html\"), \"utf8\")\n // The first argument is the URL of the shell *document*, not of the\n // navigation being answered: Vite derives the ids of the scripts it\n // injects (the React Refresh preamble) from it, emitting\n // `<src>?html-proxy&index=0.js`. Passing `req.url` would make a page\n // load of /sales request \"/sales?html-proxy&index=0.js\", which\n // resolves to sales/index.tsx and errors. `originalUrl` still carries\n // the real navigation for plugins that want it.\n const shellUrl = `/${VANTAGE_DIR}/index.html`\n shellHtml = await server.transformIndexHtml(shellUrl, raw, req.originalUrl)\n }\n res.statusCode = 200\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(shellHtml)\n } catch (err) {\n next(err as Error)\n }\n })\n }\n },\n }\n\n // React Fast Refresh + Tailwind are owned by Vantage, never by the user.\n return [core, react(), tailwindcss() as PluginOption]\n}\n\nconst CONSOLE_BRIDGE = `\n(() => {\n const send = (level, message) => {\n try {\n const body = JSON.stringify({ level, message });\n if (navigator.sendBeacon) navigator.sendBeacon(\"/__vantage_console\", body);\n else fetch(\"/__vantage_console\", { method: \"POST\", body, keepalive: true });\n } catch (_) {}\n };\n const fmt = (args) => args.map((a) => {\n if (a instanceof Error) return a.stack || a.message;\n if (typeof a === \"object\") { try { return JSON.stringify(a); } catch { return String(a); } }\n return String(a);\n }).join(\" \");\n for (const lvl of [\"log\", \"info\", \"warn\", \"error\"]) {\n const orig = console[lvl].bind(console);\n console[lvl] = (...args) => { send(lvl, fmt(args)); orig(...args); };\n }\n window.addEventListener(\"error\", (e) => send(\"error\", (e.message || \"Error\") + \" @ \" + (e.filename || \"\") + \":\" + e.lineno));\n window.addEventListener(\"unhandledrejection\", (e) => send(\"error\", \"UnhandledRejection: \" + ((e.reason && e.reason.stack) || e.reason)));\n})();\n`\n\nfunction handleConsoleBeacon(req: import(\"node:http\").IncomingMessage, res: import(\"node:http\").ServerResponse): void {\n let body = \"\"\n req.on(\"data\", (chunk) => {\n body += chunk\n if (body.length > 1_000_000) req.destroy()\n })\n req.on(\"end\", () => {\n try {\n const { level, message } = JSON.parse(body) as { level: string; message: string }\n const tag = pc.dim(`[browser:${level}]`)\n const color =\n level === \"error\" ? pc.red : level === \"warn\" ? pc.yellow : (s: string) => s\n // eslint-disable-next-line no-console\n console.log(`${tag} ${color(String(message))}`)\n } catch {\n /* ignore malformed beacons */\n }\n res.statusCode = 204\n res.end()\n })\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/dev.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAeA,eAAsB,GAAA,CAAI,MAAc,IAAA,EAAmC;AACzE,EAAA,MAAM,KAAA,GAAQ,YAAY,IAAI,CAAA;AAC9B,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,IAAA,EAAM,KAAK,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,KAAa,OAAO,CAAA;AAC/E,EAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,IAAA,gBAAA,CAAiB,MAAM,CAAA;AACvB,IAAA,GAAA,CAAI,MAAM,sDAAsD,CAAA;AAChE,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,aAAA;AACb,EAAA,mBAAA,CAAoB,IAAI,CAAA;AACxB,EAAA,MAAM,GAAA,GAAM,EAAE,GAAG,OAAA,CAAQ,GAAA,EAAK,GAAG,OAAA,CAAQ,IAAA,EAAM,IAAA,EAAM,EAAE,CAAA,EAAE;AACzD,EAAA,MAAM,KAAA,GAAQ,kBAAA,CAAmB,IAAA,CAAK,KAAA,EAAO,IAAI,CAAA;AACjD,EAAA,IAAI,CAAC,MAAM,EAAA,EAAI;AACb,IAAA,GAAA,CAAI,KAAA,CAAM,MAAM,KAAK,CAAA;AACrB,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,MAAM,EAAE,IAAA,EAAM,UAAA,EAAW,GAAI,KAAA;AAE7B,EAAA,MAAM,SAAS,MAAM,UAAA;AAAA,IAAW,mBAAA;AAAA,IAAqB,MACnD,YAAA,CAAa;AAAA,MACX,UAAA,EAAY,KAAA;AAAA,MACZ,IAAA;AAAA,MACA,IAAA;AAAA;AAAA;AAAA,MAGA,OAAA,EAAS,CAAC,aAAA,CAAc,EAAE,MAAM,GAAA,EAAK,KAAA,EAAO,CAAC,CAAA;AAAA,MAC7C,MAAA,EAAQ,EAAE,IAAA,EAAM,UAAA,EAAW;AAAA,MAC3B,WAAA,EAAa;AAAA,KACd;AAAA,GACH;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,UAAA,CAAW,aAAA,EAAe,MAAM,MAAA,CAAO,QAAQ,CAAA;AAAA,EACvD,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AACnC,IAAA,IAAI,eAAA,CAAgB,GAAA,EAAK,IAAA,EAAM,UAAU,GAAG,OAAO,CAAA;AACnD,IAAA,MAAM,GAAA;AAAA,EACR;AACA,EAAA,GAAA,CAAI,MAAM,kBAAkB,CAAA;AAC5B,EAAA,MAAA,CAAO,SAAA,EAAU;AACjB,EAAA,IAAI,KAAA,CAAM,SAAA,EAAW,GAAA,CAAI,IAAA,CAAK,sBAA2B,CAAA;AAEzD,EAAA,MAAM,WAAW,YAAY;AAC3B,IAAA,MAAM,OAAO,KAAA,EAAM;AACnB,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB,CAAA;AACA,EAAA,OAAA,CAAQ,EAAA,CAAG,UAAU,QAAQ,CAAA;AAC7B,EAAA,OAAA,CAAQ,EAAA,CAAG,WAAW,QAAQ,CAAA;AAG9B,EAAA,OAAO,IAAI,QAAgB,MAAM;AAAA,EAAC,CAAC,CAAA;AACrC","file":"dev-5K2PNSXT.js","sourcesContent":["import { createServer, loadEnv } from \"vite\"\nimport { runDiagnostics } from \"../core/diagnostics\"\nimport { timedAsync } from \"../core/profile\"\nimport { scanProject } from \"../core/scan\"\nimport { vantagePlugin } from \"../vite/index\"\nimport {\n applyApiBaseUrlFlag,\n log,\n printDiagnostics,\n reportPortInUse,\n resolvePortOptions,\n type ParsedArgs,\n} from \"./util\"\n\n/** `vantage dev` — start the dev server with HMR and the optional API server. */\nexport async function dev(root: string, args: ParsedArgs): Promise<number> {\n const model = scanProject(root)\n const errors = runDiagnostics(root, model).filter((d) => d.severity === \"error\")\n if (errors.length) {\n printDiagnostics(errors)\n log.error(\"Fix the errors above before starting the dev server.\")\n return 1\n }\n\n const mode = \"development\"\n applyApiBaseUrlFlag(args)\n const env = { ...process.env, ...loadEnv(mode, root, \"\") }\n const ports = resolvePortOptions(args.flags, 5173)\n if (!ports.ok) {\n log.error(ports.error)\n return 1\n }\n const { port, strictPort } = ports\n\n const server = await timedAsync(\"vite:createServer\", () =>\n createServer({\n configFile: false,\n root,\n mode,\n // The model was just scanned for diagnostics; hand it over so the plugin\n // does not walk the project again.\n plugins: [vantagePlugin({ root, env, model })],\n server: { port, strictPort },\n clearScreen: false,\n }),\n )\n\n try {\n await timedAsync(\"vite:listen\", () => server.listen())\n } catch (err) {\n await server.close().catch(() => {})\n if (reportPortInUse(err, port, strictPort)) return 1\n throw err\n }\n log.brand(\"dev server ready\")\n server.printUrls()\n if (model.hasServer) log.info(\" \" + \"server/api enabled\")\n\n const shutdown = async () => {\n await server.close()\n process.exit(0)\n }\n process.on(\"SIGINT\", shutdown)\n process.on(\"SIGTERM\", shutdown)\n\n // Keep the process alive; the listening server owns the lifecycle.\n return new Promise<number>(() => {})\n}\n"]}