@ubean/cli 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -31,6 +31,45 @@ declare function createFsOps(cwd: string): {
31
31
  relative: (to: string) => string;
32
32
  };
33
33
  //#endregion
34
+ //#region src/analyze-lib.d.ts
35
+ interface ManifestChunk {
36
+ file: string;
37
+ isEntry?: boolean;
38
+ isDynamicEntry?: boolean;
39
+ name?: string;
40
+ src?: string;
41
+ }
42
+ interface BundleBudgetEntry {
43
+ file: string;
44
+ bytes: number;
45
+ gzip: number;
46
+ isEntry?: boolean;
47
+ }
48
+ interface BundleBaseline {
49
+ generatedAt: string;
50
+ outDir: string;
51
+ entries: BundleBudgetEntry[];
52
+ totalBytes: number;
53
+ totalGzip: number;
54
+ entryGzip: number;
55
+ }
56
+ declare function readViteManifest(manifestPath: string): Record<string, ManifestChunk>;
57
+ declare function summarizeBundle(outDir: string, manifest: Record<string, ManifestChunk>): BundleBaseline;
58
+ declare function compareBundleBaseline(current: Pick<BundleBaseline, 'totalGzip' | 'entryGzip'>, committed: Pick<BundleBaseline, 'totalGzip' | 'entryGzip'>, options?: {
59
+ maxIncrease?: number;
60
+ }): {
61
+ ok: boolean;
62
+ maxIncrease: number;
63
+ totalRatio: number;
64
+ entryRatio: number;
65
+ messages: string[];
66
+ };
67
+ declare function writeBundleBaseline(filePath: string, baseline: BundleBaseline): void;
68
+ declare function findClientManifest(cwd: string): {
69
+ outDir: string;
70
+ manifestPath: string;
71
+ } | undefined;
72
+ //#endregion
34
73
  //#region src/shared/templates.d.ts
35
74
  interface TemplateVariables {
36
75
  [key: string]: unknown;
@@ -127,7 +166,31 @@ declare function recoverScaffold(options: {
127
166
  }): Promise<ScaffoldResult>;
128
167
  declare function listScaffoldableFiles(cwd: string, type: ScaffoldType, baseDir?: string): Promise<string[]>;
129
168
  //#endregion
169
+ //#region src/scaffold-manifest.d.ts
170
+ declare const SCAFFOLD_CONTRACT_VERSION: 1;
171
+ interface ScaffoldArgManifest {
172
+ name: string;
173
+ required: boolean;
174
+ description: string;
175
+ default?: string;
176
+ }
177
+ interface ScaffoldTypeManifest {
178
+ type: ScaffoldType;
179
+ /** Dedicated CLI command (`ubean api add`, …) or `ubean page add --type`. */
180
+ cli: boolean;
181
+ /** Directory relative to `src/`. */
182
+ baseDir: string;
183
+ extensions: string[];
184
+ args: ScaffoldArgManifest[];
185
+ }
186
+ interface ScaffoldManifest {
187
+ contractVersion: typeof SCAFFOLD_CONTRACT_VERSION;
188
+ types: ScaffoldTypeManifest[];
189
+ }
190
+ /** Machine-readable scaffold catalog for studio / IDE plugins (RM-S01). */
191
+ declare function getScaffoldManifest(): ScaffoldManifest;
192
+ //#endregion
130
193
  //#region src/index.d.ts
131
194
  type FsOps = ReturnType<typeof createFsOps>;
132
195
  //#endregion
133
- export { API_TEMPLATE, type ApiTemplateData, type BackupOptions, CRON_TEMPLATE, type CronTemplateData, FsOps, type FsOpOptions as FsOpsOptions, LAYOUT_TEMPLATE, type LayoutTemplateData, MIDDLEWARE_TEMPLATE, type MiddlewareTemplateData, PAGE_TEMPLATE, PLUGIN_TEMPLATE, type PageTemplateData, type PluginTemplateData, type ScaffoldOptions, type ScaffoldResult, type ScaffoldType, type TemplateOptions, type TemplateVariables, createFsOps, deleteScaffold, listScaffoldableFiles, recoverScaffold, renderApiTemplate, renderCronTemplate, renderLayoutTemplate, renderMiddlewareTemplate, renderPageTemplate, renderPluginTemplate, renderTemplate, scaffold, toCamelCase, toKebabCase, toPascalCase };
196
+ export { API_TEMPLATE, type ApiTemplateData, type BackupOptions, type BundleBaseline, type BundleBudgetEntry, CRON_TEMPLATE, type CronTemplateData, FsOps, type FsOpOptions as FsOpsOptions, LAYOUT_TEMPLATE, type LayoutTemplateData, MIDDLEWARE_TEMPLATE, type ManifestChunk, type MiddlewareTemplateData, PAGE_TEMPLATE, PLUGIN_TEMPLATE, type PageTemplateData, type PluginTemplateData, SCAFFOLD_CONTRACT_VERSION, type ScaffoldArgManifest, type ScaffoldManifest, type ScaffoldOptions, type ScaffoldResult, type ScaffoldType, type ScaffoldTypeManifest, type TemplateOptions, type TemplateVariables, compareBundleBaseline, createFsOps, deleteScaffold, findClientManifest, getScaffoldManifest, listScaffoldableFiles, readViteManifest, recoverScaffold, renderApiTemplate, renderCronTemplate, renderLayoutTemplate, renderMiddlewareTemplate, renderPageTemplate, renderPluginTemplate, renderTemplate, scaffold, summarizeBundle, toCamelCase, toKebabCase, toPascalCase, writeBundleBaseline };
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- import { C as toCamelCase, E as createFsOps, S as renderTemplate, T as toPascalCase, _ as renderCronTemplate, a as scaffold, b as renderPageTemplate, d as CRON_TEMPLATE, f as LAYOUT_TEMPLATE, g as renderApiTemplate, h as PLUGIN_TEMPLATE, i as recoverScaffold, m as PAGE_TEMPLATE, n as listScaffoldableFiles, p as MIDDLEWARE_TEMPLATE, t as deleteScaffold, u as API_TEMPLATE, v as renderLayoutTemplate, w as toKebabCase, x as renderPluginTemplate, y as renderMiddlewareTemplate } from "./page-D-LZUcPP.js";
2
- export { API_TEMPLATE, CRON_TEMPLATE, LAYOUT_TEMPLATE, MIDDLEWARE_TEMPLATE, PAGE_TEMPLATE, PLUGIN_TEMPLATE, createFsOps, deleteScaffold, listScaffoldableFiles, recoverScaffold, renderApiTemplate, renderCronTemplate, renderLayoutTemplate, renderMiddlewareTemplate, renderPageTemplate, renderPluginTemplate, renderTemplate, scaffold, toCamelCase, toKebabCase, toPascalCase };
1
+ import { n as getScaffoldManifest, t as SCAFFOLD_CONTRACT_VERSION } from "./scaffold-manifest-TrH6OCX8.js";
2
+ import { A as summarizeBundle, C as toCamelCase, D as compareBundleBaseline, E as createFsOps, O as findClientManifest, S as renderTemplate, T as toPascalCase, _ as renderCronTemplate, a as scaffold, b as renderPageTemplate, d as CRON_TEMPLATE, f as LAYOUT_TEMPLATE, g as renderApiTemplate, h as PLUGIN_TEMPLATE, i as recoverScaffold, j as writeBundleBaseline, k as readViteManifest, m as PAGE_TEMPLATE, n as listScaffoldableFiles, p as MIDDLEWARE_TEMPLATE, t as deleteScaffold, u as API_TEMPLATE, v as renderLayoutTemplate, w as toKebabCase, x as renderPluginTemplate, y as renderMiddlewareTemplate } from "./page-BRUWKaig.js";
3
+ export { API_TEMPLATE, CRON_TEMPLATE, LAYOUT_TEMPLATE, MIDDLEWARE_TEMPLATE, PAGE_TEMPLATE, PLUGIN_TEMPLATE, SCAFFOLD_CONTRACT_VERSION, compareBundleBaseline, createFsOps, deleteScaffold, findClientManifest, getScaffoldManifest, listScaffoldableFiles, readViteManifest, recoverScaffold, renderApiTemplate, renderCronTemplate, renderLayoutTemplate, renderMiddlewareTemplate, renderPageTemplate, renderPluginTemplate, renderTemplate, scaffold, summarizeBundle, toCamelCase, toKebabCase, toPascalCase, writeBundleBaseline };
@@ -1,9 +1,75 @@
1
- import { existsSync, promises } from "node:fs";
2
- import { dirname, extname, join, relative, resolve } from "node:path";
3
- import { getLogger } from "@ubean/logger";
1
+ import { existsSync, mkdirSync, promises, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import { gzipSync } from "node:zlib";
3
+ import { dirname, join, resolve } from "pathe";
4
+ import { dirname as dirname$1, extname, join as join$1, relative as relative$1, resolve as resolve$1 } from "node:path";
5
+ import { getLogger } from "@ubean/shared/logger";
6
+ //#region src/analyze-lib.ts
7
+ function readViteManifest(manifestPath) {
8
+ return JSON.parse(readFileSync(manifestPath, "utf8"));
9
+ }
10
+ function summarizeBundle(outDir, manifest) {
11
+ const entries = [];
12
+ for (const chunk of Object.values(manifest)) {
13
+ if (!chunk.file || chunk.file.endsWith(".css")) continue;
14
+ const abs = join(outDir, chunk.file);
15
+ if (!existsSync(abs)) continue;
16
+ const bytes = statSync(abs).size;
17
+ const gzip = gzipSync(readFileSync(abs)).length;
18
+ entries.push({
19
+ file: chunk.file,
20
+ bytes,
21
+ gzip,
22
+ isEntry: chunk.isEntry
23
+ });
24
+ }
25
+ entries.sort((a, b) => b.gzip - a.gzip);
26
+ const totalBytes = entries.reduce((sum, e) => sum + e.bytes, 0);
27
+ const totalGzip = entries.reduce((sum, e) => sum + e.gzip, 0);
28
+ const entryGzip = entries.filter((e) => e.isEntry).reduce((sum, e) => sum + e.gzip, 0);
29
+ return {
30
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
31
+ outDir,
32
+ entries,
33
+ totalBytes,
34
+ totalGzip,
35
+ entryGzip
36
+ };
37
+ }
38
+ function compareBundleBaseline(current, committed, options = {}) {
39
+ const maxIncrease = options.maxIncrease ?? .05;
40
+ const totalRatio = committed.totalGzip === 0 ? current.totalGzip === 0 ? 0 : Infinity : current.totalGzip / committed.totalGzip - 1;
41
+ const entryRatio = committed.entryGzip === 0 ? current.entryGzip === 0 ? 0 : Infinity : current.entryGzip / committed.entryGzip - 1;
42
+ const messages = [];
43
+ if (totalRatio > maxIncrease) messages.push(`total gzip ${(current.totalGzip / 1024).toFixed(1)} kB exceeds baseline ${(committed.totalGzip / 1024).toFixed(1)} kB by ${(totalRatio * 100).toFixed(1)}% (max ${(maxIncrease * 100).toFixed(0)}%)`);
44
+ if (entryRatio > maxIncrease) messages.push(`entry gzip ${(current.entryGzip / 1024).toFixed(1)} kB exceeds baseline ${(committed.entryGzip / 1024).toFixed(1)} kB by ${(entryRatio * 100).toFixed(1)}% (max ${(maxIncrease * 100).toFixed(0)}%)`);
45
+ return {
46
+ ok: messages.length === 0,
47
+ maxIncrease,
48
+ totalRatio,
49
+ entryRatio,
50
+ messages
51
+ };
52
+ }
53
+ function writeBundleBaseline(filePath, baseline) {
54
+ mkdirSync(dirname(filePath), { recursive: true });
55
+ writeFileSync(filePath, `${JSON.stringify(baseline, null, 2)}\n`, "utf8");
56
+ }
57
+ function findClientManifest(cwd) {
58
+ const candidates = [
59
+ join(cwd, "dist/client/.vite/manifest.json"),
60
+ join(cwd, "dist/public/.vite/manifest.json"),
61
+ join(cwd, "dist/.vite/manifest.json"),
62
+ join(cwd, ".output/public/.vite/manifest.json")
63
+ ];
64
+ for (const manifestPath of candidates) if (existsSync(manifestPath)) return {
65
+ outDir: resolve(dirname(manifestPath), ".."),
66
+ manifestPath
67
+ };
68
+ }
69
+ //#endregion
4
70
  //#region src/shared/fs-ops.ts
5
71
  function resolvePath(cwd, ...paths) {
6
- return resolve(cwd, ...paths);
72
+ return resolve$1(cwd, ...paths);
7
73
  }
8
74
  async function ensureDir(dir) {
9
75
  await promises.mkdir(dir, { recursive: true });
@@ -23,7 +89,7 @@ async function readFile(path, encoding = "utf-8") {
23
89
  return promises.readFile(path, encoding);
24
90
  }
25
91
  async function writeFile(path, content, encoding = "utf-8") {
26
- await ensureDir(dirname(path));
92
+ await ensureDir(dirname$1(path));
27
93
  await promises.writeFile(path, content, encoding);
28
94
  }
29
95
  async function appendFile(path, content, encoding = "utf-8") {
@@ -36,15 +102,15 @@ async function remove(path) {
36
102
  });
37
103
  }
38
104
  async function copyFile(src, dest) {
39
- await ensureDir(dirname(dest));
105
+ await ensureDir(dirname$1(dest));
40
106
  await promises.copyFile(src, dest);
41
107
  }
42
108
  async function copyDir(src, dest, options) {
43
109
  await ensureDir(dest);
44
110
  const entries = await promises.readdir(src, { withFileTypes: true });
45
111
  for (const entry of entries) {
46
- const srcPath = join(src, entry.name);
47
- const destPath = join(dest, entry.name);
112
+ const srcPath = join$1(src, entry.name);
113
+ const destPath = join$1(dest, entry.name);
48
114
  if (options?.filter && !options.filter(srcPath)) continue;
49
115
  if (entry.isDirectory()) await copyDir(srcPath, destPath, options);
50
116
  else await copyFile(srcPath, destPath);
@@ -81,7 +147,7 @@ async function listFiles(dir, pattern) {
81
147
  async function walk(current) {
82
148
  const entries = await promises.readdir(current, { withFileTypes: true });
83
149
  for (const entry of entries) {
84
- const fullPath = join(current, entry.name);
150
+ const fullPath = join$1(current, entry.name);
85
151
  if (entry.isDirectory()) {
86
152
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".ubean") continue;
87
153
  await walk(fullPath);
@@ -111,7 +177,7 @@ function createFsOps(cwd) {
111
177
  restoreBackup: (path, opts) => restoreBackup(resolvePath(cwd, path), opts),
112
178
  removeBackup: (path, opts) => removeBackup(resolvePath(cwd, path), opts),
113
179
  listFiles: (dir, pattern) => listFiles(resolvePath(cwd, dir || "."), pattern),
114
- relative: (to) => relative(cwd, resolve(cwd, to))
180
+ relative: (to) => relative$1(cwd, resolve$1(cwd, to))
115
181
  };
116
182
  }
117
183
  //#endregion
@@ -583,32 +649,6 @@ const GLOBAL_MIDDLEWARE = [
583
649
  "});",
584
650
  ""
585
651
  ].join("\n");
586
- const I18N_MIDDLEWARE = [
587
- "import { defineMiddleware, createI18nMiddleware, setI18nConfig } from 'ubean';",
588
- "",
589
- "// Set global i18n config (used by localizePath, switchLocalePath, etc.)",
590
- "// Locale messages are auto-loaded by ubean:locales virtual module.",
591
- "setI18nConfig({",
592
- " defaultLocale: 'en',",
593
- " strategy: 'prefix_except_default',",
594
- " locales: ['en', 'zh']",
595
- "});",
596
- "",
597
- "// Create i18n middleware instance once.",
598
- "const i18nHandler = createI18nMiddleware({",
599
- " strategy: 'prefix_except_default',",
600
- " defaultLocale: 'en',",
601
- " locales: ['en', 'zh'],",
602
- " detectFromHeader: true,",
603
- " detectFromCookie: true,",
604
- " redirectOnLocaleMismatch: false",
605
- "});",
606
- "",
607
- "export default defineMiddleware(async (c, next) => {",
608
- " return i18nHandler(c, next);",
609
- "});",
610
- ""
611
- ].join("\n");
612
652
  const HELLO_API = `import { pipe, description, object, string, number } from 'valibot';
613
653
  import { defineHandler, describeRoute, resolver } from 'ubean';
614
654
 
@@ -990,71 +1030,50 @@ const ZH_LOCALE = `{
990
1030
  }
991
1031
  `;
992
1032
  /** ubean logo SVG — 所有模板共用 */
993
- const FAVICON_SVG = `<svg width="100%" height="100%" version="1.1" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg"
994
- xmlns:xlink="http://www.w3.org/1999/xlink">
1033
+ const FAVICON_SVG = `<svg width="100%" height="100%" version="1.1" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
995
1034
  <g>
996
- <path
997
- d="M 200,866 C 100,866 50,779.4 100,692.8 L 200,519.6 C 220,485 240,490 265,499.6 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
998
- fill="url(#LinearGradient)" fill-rule="nonzero" opacity="1" stroke="none" />
999
- <path
1000
- d="M 420,866 C 455,861 478,846 500,827 C 614,696 615,597 500,517 C 394,444 333,374 380,207.82 L 260,415.67 C 240.22,450 254.37,465.1 275.28,481.79 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
1001
- fill="url(#LinearGradient_2)" fill-rule="nonzero" opacity="1" stroke="none" />
1002
- <path d="M 500,517 C 394,444 333,374 380,207.82 L 400,173.2 C 367,295 421,350 603,428 C 572,440 524,474 500,517"
1003
- fill="url(#LinearGradient_3)" fill-rule="nonzero" opacity="1" stroke="none" />
1004
- <path d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 572,440 524,474 500,517 C 615,597 614,696 500,827"
1005
- fill="url(#LinearGradient_4)" fill-rule="nonzero" opacity="1" stroke="none" />
1006
- <path d="M 400,173.2 C 367,295 421,350 603,428 C 690,389, 750,445 788,500 L 600,173.2 C 550,86.6 450,86.6 400,173.2"
1007
- fill="url(#LinearGradient_5)" fill-rule="nonzero" opacity="1" stroke="none" />
1008
- <path
1009
- d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 690,389, 750,445 788,500 C 816,554 797,606 750,640 L 500,827"
1010
- fill="url(#LinearGradient_6)" fill-rule="nonzero" opacity="1" stroke="none" />
1011
- <path
1012
- d="M 788,500 C 816,554 797,606 750,640 L 500,827 C 497,851 513,862 540,866 L 800,866 C 900,866 950,779.4 900,692.8 L 788,500"
1013
- fill="url(#LinearGradient_7)" fill-rule="nonzero" opacity="1" stroke="none" />
1014
-
1015
- <!--左下角图案-->
1035
+ <path d="M 200,866 C 100,866 50,779.4 100,692.8 L 200,519.6 C 220,485 240,490 265,499.6 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866" fill="url(#LinearGradient)" fill-rule="nonzero" opacity="1" stroke="none"/>
1036
+ <path d="M 420,866 C 455,861 478,846 500,827 C 614,696 615,597 500,517 C 394,444 333,374 380,207.82 L 260,415.67 C 240.22,450 254.37,465.1 275.28,481.79 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866" fill="url(#LinearGradient_2)" fill-rule="nonzero" opacity="1" stroke="none"/>
1037
+ <path d="M 500,517 C 394,444 333,374 380,207.82 L 400,173.2 C 367,295 421,350 603,428 C 572,440 524,474 500,517" fill="url(#LinearGradient_3)" fill-rule="nonzero" opacity="1" stroke="none"/>
1038
+ <path d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 572,440 524,474 500,517 C 615,597 614,696 500,827" fill="url(#LinearGradient_4)" fill-rule="nonzero" opacity="1" stroke="none"/>
1039
+ <path d="M 400,173.2 C 367,295 421,350 603,428 C 690,389, 750,445 788,500 L 600,173.2 C 550,86.6 450,86.6 400,173.2" fill="url(#LinearGradient_5)" fill-rule="nonzero" opacity="1" stroke="none"/>
1040
+ <path d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 690,389, 750,445 788,500 C 816,554 797,606 750,640 L 500,827" fill="url(#LinearGradient_6)" fill-rule="nonzero" opacity="1" stroke="none"/>
1041
+ <path d="M 788,500 C 816,554 797,606 750,640 L 500,827 C 497,851 513,862 540,866 L 800,866 C 900,866 950,779.4 900,692.8 L 788,500" fill="url(#LinearGradient_7)" fill-rule="nonzero" opacity="1" stroke="none"/>
1042
+ </g>
1043
+ <!--左下角图案-->
1016
1044
  <g transform="translate(130, 675) scale(7)">
1017
1045
  <g viewBox="0 0 24 24">
1018
- <path fill="#ffffff" d="M4.528 5.118a1 1 0 0 1 1.027.05l5.554 3.703A2 2 0 0 1 12 10.535V21a1 1 0 0 1-1.555.832l-5.554-3.703A2 2 0 0 1 4 16.465V6a1 1 0 0 1 .528-.882m4-2a1 1 0 0 1 1.027.05l5.554 3.703A2 2 0 0 1 16 8.535V19a1 1 0 0 1-1.555.832l-.945-.63v-8.667a3.5 3.5 0 0 0-1.559-2.912L8 4.995V4a1 1 0 0 1 .528-.882m4-2a1 1 0 0 1 1.027.05l5.554 3.703A2 2 0 0 1 20 6.535V17a1 1 0 0 1-1.555.832l-.945-.63V8.534a3.5 3.5 0 0 0-1.559-2.912L12 2.995V2a1 1 0 0 1 .528-.882" />
1019
-
1046
+ <path fill="#ffffff" d="M4.528 5.118a1 1 0 0 1 1.027.05l5.554 3.703A2 2 0 0 1 12 10.535V21a1 1 0 0 1-1.555.832l-5.554-3.703A2 2 0 0 1 4 16.465V6a1 1 0 0 1 .528-.882m4-2a1 1 0 0 1 1.027.05l5.554 3.703A2 2 0 0 1 16 8.535V19a1 1 0 0 1-1.555.832l-.945-.63v-8.667a3.5 3.5 0 0 0-1.559-2.912L8 4.995V4a1 1 0 0 1 .528-.882m4-2a1 1 0 0 1 1.027.05l5.554 3.703A2 2 0 0 1 20 6.535V17a1 1 0 0 1-1.555.832l-.945-.63V8.534a3.5 3.5 0 0 0-1.559-2.912L12 2.995V2a1 1 0 0 1 .528-.882"/>
1020
1047
  </g>
1021
1048
  </g>
1022
- </g>
1023
1049
  <defs>
1024
- <linearGradient gradientTransform="matrix(104.391 -73.3432 73.3432 104.391 277.441 710.122)"
1025
- gradientUnits="userSpaceOnUse" id="LinearGradient" x1="0" x2="1" y1="0" y2="0">
1026
- <stop offset="0" stop-color="#30a772" />
1027
- <stop offset="1" stop-color="#30e191" />
1050
+ <linearGradient gradientTransform="matrix(104.391 -73.3432 73.3432 104.391 277.441 710.122)" gradientUnits="userSpaceOnUse" id="LinearGradient" x1="0" x2="1" y1="0" y2="0">
1051
+ <stop offset="0" stop-color="#373ebf"/>
1052
+ <stop offset="1" stop-color="#5058e6"/>
1028
1053
  </linearGradient>
1029
- <linearGradient gradientTransform="matrix(-173.747 557.324 -557.324 -173.747 508.829 258.172)"
1030
- gradientUnits="userSpaceOnUse" id="LinearGradient_2" x1="0" x2="1" y1="0" y2="0">
1031
- <stop offset="0" stop-color="#98f6cc" />
1032
- <stop offset="1" stop-color="#4aefa5" />
1054
+ <linearGradient gradientTransform="matrix(-173.747 557.324 -557.324 -173.747 508.829 258.172)" gradientUnits="userSpaceOnUse" id="LinearGradient_2" x1="0" x2="1" y1="0" y2="0">
1055
+ <stop offset="0" stop-color="#c2d6ff"/>
1056
+ <stop offset="1" stop-color="#646cff"/>
1033
1057
  </linearGradient>
1034
- <linearGradient gradientTransform="matrix(157.951 295.666 -295.666 157.951 382.944 193.642)"
1035
- gradientUnits="userSpaceOnUse" id="LinearGradient_3" x1="0" x2="1" y1="0" y2="0">
1036
- <stop offset="0" stop-color="#30e191" />
1037
- <stop offset="1" stop-color="#30a772" />
1058
+ <linearGradient gradientTransform="matrix(157.951 295.666 -295.666 157.951 382.944 193.642)" gradientUnits="userSpaceOnUse" id="LinearGradient_3" x1="0" x2="1" y1="0" y2="0">
1059
+ <stop offset="0" stop-color="#5058e6"/>
1060
+ <stop offset="1" stop-color="#373ebf"/>
1038
1061
  </linearGradient>
1039
- <linearGradient gradientTransform="matrix(-44.3023 219.578 -219.578 -44.3023 619.69 469.652)"
1040
- gradientUnits="userSpaceOnUse" id="LinearGradient_4" x1="0" x2="1" y1="0" y2="0">
1041
- <stop offset="0" stop-color="#6ff3b7" />
1042
- <stop offset="1" stop-color="#30e191" />
1062
+ <linearGradient gradientTransform="matrix(-44.3023 219.578 -219.578 -44.3023 619.69 469.652)" gradientUnits="userSpaceOnUse" id="LinearGradient_4" x1="0" x2="1" y1="0" y2="0">
1063
+ <stop offset="0" stop-color="#91a7ff"/>
1064
+ <stop offset="1" stop-color="#5058e6"/>
1043
1065
  </linearGradient>
1044
- <linearGradient gradientTransform="matrix(125.52 334.256 -334.256 125.52 539.723 235.139)"
1045
- gradientUnits="userSpaceOnUse" id="LinearGradient_5" x1="0" x2="1" y1="0" y2="0">
1046
- <stop offset="0" stop-color="#4aefa5" />
1047
- <stop offset="1" stop-color="#98f6cc" />
1066
+ <linearGradient gradientTransform="matrix(125.52 334.256 -334.256 125.52 539.723 235.139)" gradientUnits="userSpaceOnUse" id="LinearGradient_5" x1="0" x2="1" y1="0" y2="0">
1067
+ <stop offset="0" stop-color="#646cff"/>
1068
+ <stop offset="1" stop-color="#c2d6ff"/>
1048
1069
  </linearGradient>
1049
- <linearGradient gradientTransform="matrix(-241.23 357.206 -357.206 -241.23 754.054 449.312)"
1050
- gradientUnits="userSpaceOnUse" id="LinearGradient_6" x1="0" x2="1" y1="0" y2="0">
1051
- <stop offset="0" stop-color="#98f6cc" />
1052
- <stop offset="1" stop-color="#4aefa5" />
1070
+ <linearGradient gradientTransform="matrix(-241.23 357.206 -357.206 -241.23 754.054 449.312)" gradientUnits="userSpaceOnUse" id="LinearGradient_6" x1="0" x2="1" y1="0" y2="0">
1071
+ <stop offset="0" stop-color="#c2d6ff"/>
1072
+ <stop offset="1" stop-color="#646cff"/>
1053
1073
  </linearGradient>
1054
- <linearGradient gradientTransform="matrix(125.978 210.065 -210.065 125.978 596.433 613.665)"
1055
- gradientUnits="userSpaceOnUse" id="LinearGradient_7" x1="0" x2="1" y1="0" y2="0">
1056
- <stop offset="0" stop-color="#30a772" />
1057
- <stop offset="1" stop-color="#30e191" />
1074
+ <linearGradient gradientTransform="matrix(125.978 210.065 -210.065 125.978 596.433 613.665)" gradientUnits="userSpaceOnUse" id="LinearGradient_7" x1="0" x2="1" y1="0" y2="0">
1075
+ <stop offset="0" stop-color="#373ebf"/>
1076
+ <stop offset="1" stop-color="#5058e6"/>
1058
1077
  </linearGradient>
1059
1078
  </defs>
1060
1079
  </svg>
@@ -1242,7 +1261,6 @@ async function scaffoldUnifyTemplate(fs, options) {
1242
1261
  await fs.writeFile("src/pages/about2.reuse.ts", ABOUT_REUSE);
1243
1262
  await fs.writeFile("src/pages/(admin)/dashboard.vue", DASHBOARD_PAGE);
1244
1263
  await fs.writeFile("src/middleware/01.global.ts", GLOBAL_MIDDLEWARE);
1245
- await fs.writeFile("src/middleware/02.i18n.ts", I18N_MIDDLEWARE);
1246
1264
  await fs.writeFile("src/routes/api/hello-world.ts", HELLO_API);
1247
1265
  await fs.writeFile("src/components/IslandCounter.vue", ISLAND_COUNTER);
1248
1266
  await fs.writeFile("src/components/IslandClock.vue", ISLAND_CLOCK);
@@ -1301,46 +1319,46 @@ async function scaffoldBlogTemplate(fs, options) {
1301
1319
  //#region src/page.ts
1302
1320
  const logger = getLogger("cli");
1303
1321
  function getSrcDir(cwd) {
1304
- return join(cwd, "src");
1322
+ return join$1(cwd, "src");
1305
1323
  }
1306
1324
  function getDirForType(cwd, type) {
1307
1325
  const srcDir = getSrcDir(cwd);
1308
1326
  switch (type) {
1309
1327
  case "page":
1310
- case "reuse": return join(srcDir, "pages");
1311
- case "api": return join(srcDir, "routes");
1312
- case "layout": return join(srcDir, "layouts");
1313
- case "middleware": return join(srcDir, "middleware");
1314
- case "cron": return join(srcDir, "server", "crons");
1315
- case "plugin": return join(srcDir, "plugins");
1328
+ case "reuse": return join$1(srcDir, "pages");
1329
+ case "api": return join$1(srcDir, "routes");
1330
+ case "layout": return join$1(srcDir, "layouts");
1331
+ case "middleware": return join$1(srcDir, "middleware");
1332
+ case "cron": return join$1(srcDir, "server", "crons");
1333
+ case "plugin": return join$1(srcDir, "plugins");
1316
1334
  default: return srcDir;
1317
1335
  }
1318
1336
  }
1319
1337
  /** Resolve a baseDir that may be relative or absolute into an absolute path. */
1320
1338
  function resolveBaseDir(cwd, baseDir) {
1321
- return baseDir.startsWith("/") ? baseDir : join(cwd, baseDir);
1339
+ return baseDir.startsWith("/") ? baseDir : join$1(cwd, baseDir);
1322
1340
  }
1323
1341
  function resolveTargetPath(baseDir, path, type) {
1324
1342
  let normalizedPath = path.startsWith("/") ? path.slice(1) : path;
1325
1343
  if (normalizedPath === "" || normalizedPath === "/") normalizedPath = type === "page" || type === "reuse" ? "index" : "index";
1326
1344
  if (type === "page" || type === "layout" || type === "reuse") {
1327
1345
  if (type === "page" || type === "layout") {
1328
- if (normalizedPath.endsWith(".vue")) return join(baseDir, normalizedPath);
1346
+ if (normalizedPath.endsWith(".vue")) return join$1(baseDir, normalizedPath);
1329
1347
  const ext = ".vue";
1330
- if (normalizedPath.endsWith("/") || normalizedPath === "") return join(baseDir, normalizedPath, `index${ext}`);
1331
- return join(baseDir, `${normalizedPath}${ext}`);
1348
+ if (normalizedPath.endsWith("/") || normalizedPath === "") return join$1(baseDir, normalizedPath, `index${ext}`);
1349
+ return join$1(baseDir, `${normalizedPath}${ext}`);
1332
1350
  }
1333
- if (normalizedPath.endsWith(".reuse.ts")) return join(baseDir, normalizedPath);
1334
- if (normalizedPath.endsWith(".ts")) return join(baseDir, normalizedPath.replace(/\.ts$/, ".reuse.ts"));
1351
+ if (normalizedPath.endsWith(".reuse.ts")) return join$1(baseDir, normalizedPath);
1352
+ if (normalizedPath.endsWith(".ts")) return join$1(baseDir, normalizedPath.replace(/\.ts$/, ".reuse.ts"));
1335
1353
  const ext = ".reuse.ts";
1336
- if (normalizedPath.endsWith("/") || normalizedPath === "") return join(baseDir, normalizedPath, `index${ext}`);
1337
- return join(baseDir, `${normalizedPath}${ext}`);
1354
+ if (normalizedPath.endsWith("/") || normalizedPath === "") return join$1(baseDir, normalizedPath, `index${ext}`);
1355
+ return join$1(baseDir, `${normalizedPath}${ext}`);
1338
1356
  }
1339
- if (normalizedPath.endsWith(".ts") || normalizedPath.endsWith(".js")) return join(baseDir, normalizedPath);
1357
+ if (normalizedPath.endsWith(".ts") || normalizedPath.endsWith(".js")) return join$1(baseDir, normalizedPath);
1340
1358
  const ext = ".ts";
1341
- if (normalizedPath.endsWith("/") || normalizedPath === "") return join(baseDir, normalizedPath, `index${ext}`);
1342
- if ((type === "api" || type === "middleware" || type === "cron" || type === "plugin") && !normalizedPath.includes(".")) return join(baseDir, `${normalizedPath}${ext}`);
1343
- return join(baseDir, normalizedPath);
1359
+ if (normalizedPath.endsWith("/") || normalizedPath === "") return join$1(baseDir, normalizedPath, `index${ext}`);
1360
+ if ((type === "api" || type === "middleware" || type === "cron" || type === "plugin") && !normalizedPath.includes(".")) return join$1(baseDir, `${normalizedPath}${ext}`);
1361
+ return join$1(baseDir, normalizedPath);
1344
1362
  }
1345
1363
  function sanitizeNameSegment(seg) {
1346
1364
  return seg.replace(/^\[\.\.\.(.+)\]$/, "All$1").replace(/^\[\[(.+)\]\]$/, "$1Optional").replace(/^\[(.+)\]$/, "$1").replace(/[^a-zA-Z0-9$_]/g, "");
@@ -1721,4 +1739,4 @@ const pageCommand = {
1721
1739
  }
1722
1740
  };
1723
1741
  //#endregion
1724
- export { toCamelCase as C, createFsOps as E, renderTemplate as S, toPascalCase as T, renderCronTemplate as _, scaffold as a, renderPageTemplate as b, scaffoldStarterTemplate as c, CRON_TEMPLATE as d, LAYOUT_TEMPLATE as f, renderApiTemplate as g, PLUGIN_TEMPLATE as h, recoverScaffold as i, scaffoldUnifyTemplate as l, PAGE_TEMPLATE as m, listScaffoldableFiles as n, scaffoldBlogTemplate as o, MIDDLEWARE_TEMPLATE as p, pageCommand as r, scaffoldMinimalTemplate as s, deleteScaffold as t, API_TEMPLATE as u, renderLayoutTemplate as v, toKebabCase as w, renderPluginTemplate as x, renderMiddlewareTemplate as y };
1742
+ export { summarizeBundle as A, toCamelCase as C, compareBundleBaseline as D, createFsOps as E, findClientManifest as O, renderTemplate as S, toPascalCase as T, renderCronTemplate as _, scaffold as a, renderPageTemplate as b, scaffoldStarterTemplate as c, CRON_TEMPLATE as d, LAYOUT_TEMPLATE as f, renderApiTemplate as g, PLUGIN_TEMPLATE as h, recoverScaffold as i, writeBundleBaseline as j, readViteManifest as k, scaffoldUnifyTemplate as l, PAGE_TEMPLATE as m, listScaffoldableFiles as n, scaffoldBlogTemplate as o, MIDDLEWARE_TEMPLATE as p, pageCommand as r, scaffoldMinimalTemplate as s, deleteScaffold as t, API_TEMPLATE as u, renderLayoutTemplate as v, toKebabCase as w, renderPluginTemplate as x, renderMiddlewareTemplate as y };
@@ -0,0 +1,116 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ //#region src/scaffold-manifest.ts
14
+ var scaffold_manifest_exports = /* @__PURE__ */ __exportAll({
15
+ SCAFFOLD_CONTRACT_VERSION: () => 1,
16
+ getScaffoldManifest: () => getScaffoldManifest
17
+ });
18
+ const SCAFFOLD_CONTRACT_VERSION = 1;
19
+ const TYPES = [
20
+ {
21
+ type: "page",
22
+ cli: true,
23
+ baseDir: "pages",
24
+ extensions: [".vue"],
25
+ args: [{
26
+ name: "path",
27
+ required: true,
28
+ description: "Route path (e.g. users/[id])"
29
+ }]
30
+ },
31
+ {
32
+ type: "api",
33
+ cli: true,
34
+ baseDir: "routes",
35
+ extensions: [".ts"],
36
+ args: [{
37
+ name: "path",
38
+ required: true,
39
+ description: "API route path (e.g. users/[id])"
40
+ }, {
41
+ name: "method",
42
+ required: false,
43
+ description: "HTTP method",
44
+ default: "GET"
45
+ }]
46
+ },
47
+ {
48
+ type: "layout",
49
+ cli: true,
50
+ baseDir: "layouts",
51
+ extensions: [".vue"],
52
+ args: [{
53
+ name: "path",
54
+ required: true,
55
+ description: "Layout name (e.g. admin)"
56
+ }]
57
+ },
58
+ {
59
+ type: "middleware",
60
+ cli: true,
61
+ baseDir: "middleware",
62
+ extensions: [".ts"],
63
+ args: [{
64
+ name: "path",
65
+ required: true,
66
+ description: "Middleware path (e.g. auth)"
67
+ }]
68
+ },
69
+ {
70
+ type: "cron",
71
+ cli: true,
72
+ baseDir: "server/crons",
73
+ extensions: [".ts"],
74
+ args: [{
75
+ name: "path",
76
+ required: true,
77
+ description: "Cron task path (e.g. daily-cleanup)"
78
+ }, {
79
+ name: "schedule",
80
+ required: false,
81
+ description: "Cron expression",
82
+ default: "* * * * *"
83
+ }]
84
+ },
85
+ {
86
+ type: "plugin",
87
+ cli: true,
88
+ baseDir: "plugins",
89
+ extensions: [".ts"],
90
+ args: [{
91
+ name: "path",
92
+ required: true,
93
+ description: "Plugin path (e.g. analytics)"
94
+ }]
95
+ },
96
+ {
97
+ type: "reuse",
98
+ cli: false,
99
+ baseDir: "pages",
100
+ extensions: [".reuse.ts", ".reuse.vue"],
101
+ args: [{
102
+ name: "path",
103
+ required: true,
104
+ description: "Reuse route path; library API only (`scaffold({ type: \"reuse\" })`)"
105
+ }]
106
+ }
107
+ ];
108
+ /** Machine-readable scaffold catalog for studio / IDE plugins (RM-S01). */
109
+ function getScaffoldManifest() {
110
+ return {
111
+ contractVersion: 1,
112
+ types: TYPES
113
+ };
114
+ }
115
+ //#endregion
116
+ export { getScaffoldManifest as n, scaffold_manifest_exports as r, SCAFFOLD_CONTRACT_VERSION as t };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ubean/cli",
3
- "version": "0.2.1",
4
- "description": "CLI for ubean (ubean-next binary: dev, build, prepare, init, preview, page, env, config, devtools, api/layout/middleware/cron/plugin scaffolds)",
3
+ "version": "0.3.0",
4
+ "description": "CLI for ubean (ubean-next binary: dev, build, prepare, init, preview, page, env, config, devtools, api/layout/middleware/cron/plugin scaffolds) plus the Vite dev server runner",
5
5
  "bin": {
6
6
  "ubean-next": "./bin/ubean-next.mjs"
7
7
  },
@@ -27,29 +27,40 @@
27
27
  "citty": "^0.2.2",
28
28
  "kolorist": "^1.8.0",
29
29
  "pathe": "^2.0.3",
30
- "@ubean/app": "0.2.1",
31
- "@ubean/build": "0.2.1",
32
- "@ubean/codegen": "0.2.1",
33
- "@ubean/config": "0.2.1",
34
- "@ubean/dev-server": "0.2.1",
35
- "@ubean/logger": "0.2.1",
36
- "@ubean/preset": "0.2.1",
37
- "@ubean/prerender": "0.2.1",
38
- "@ubean/scan": "0.2.1",
39
- "@ubean/shared": "0.2.1",
40
- "@ubean/modules": "0.2.1"
30
+ "@ubean/app": "0.3.0",
31
+ "@ubean/build": "0.3.0",
32
+ "@ubean/client": "0.3.0",
33
+ "@ubean/preset": "0.3.0",
34
+ "@ubean/islands": "0.3.0",
35
+ "@ubean/scan": "0.3.0",
36
+ "@ubean/shared": "0.3.0",
37
+ "@ubean/config": "0.3.0"
41
38
  },
42
39
  "devDependencies": {
43
40
  "@types/node": "^26.2.0",
41
+ "@vitejs/plugin-vue": "^6.0.8",
44
42
  "typescript": "7.0.2",
43
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.9",
45
44
  "vite-plus": "0.2.9"
46
45
  },
47
46
  "peerDependencies": {
48
- "@ubean/devtools": "0.2.1"
47
+ "@vitejs/plugin-vue": "^6.0.8",
48
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.9",
49
+ "@ubean/content": "0.3.0",
50
+ "@ubean/devtools": "0.3.0"
49
51
  },
50
52
  "peerDependenciesMeta": {
53
+ "@ubean/content": {
54
+ "optional": true
55
+ },
51
56
  "@ubean/devtools": {
52
57
  "optional": true
58
+ },
59
+ "@vitejs/plugin-vue": {
60
+ "optional": true
61
+ },
62
+ "vite": {
63
+ "optional": true
53
64
  }
54
65
  },
55
66
  "scripts": {