@lark-apaas/fullstack-cli 1.1.63-alpha.20260826072408 → 1.1.63-alpha.20260826101330

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.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/index.ts
2
- import fs34 from "fs";
3
- import path30 from "path";
2
+ import fs29 from "fs";
3
+ import path25 from "path";
4
4
  import { fileURLToPath as fileURLToPath5 } from "url";
5
+ import { config as dotenvConfig } from "dotenv";
5
6
 
6
7
  // src/cli.ts
7
8
  import { Command } from "commander";
@@ -2513,6 +2514,17 @@ function buildDefaultRules(opts) {
2513
2514
  command: "node scripts/hooks/run-precommit.js",
2514
2515
  overwrite: false
2515
2516
  },
2517
+ // 1d. Nest 开发态由平台 launcher 选择 SWC;已有声明保持用户版本/依赖分区。
2518
+ {
2519
+ type: "ensure-dev-dependency",
2520
+ name: "@swc/cli",
2521
+ version: "^0.5.2"
2522
+ },
2523
+ {
2524
+ type: "ensure-dev-dependency",
2525
+ name: "@swc/core",
2526
+ version: "^1.16.1"
2527
+ },
2516
2528
  // 2. 智能合并 nest-cli.json 配置(保留用户自定义的 assets、plugins 等)
2517
2529
  {
2518
2530
  from: "templates/nest-cli.json",
@@ -2587,6 +2599,19 @@ function buildDefaultRules(opts) {
2587
2599
  name: "lint",
2588
2600
  to: "node ./scripts/lint.js",
2589
2601
  ifStartsWith: "concurrently "
2602
+ },
2603
+ // 9a. 只迁移模板生成的精确默认值;用户追加参数或自定义命令保持不动。
2604
+ {
2605
+ type: "patch-script",
2606
+ name: "dev:server",
2607
+ to: "NODE_ENV=development node ./scripts/dev-server.js",
2608
+ ifEquals: "NODE_ENV=development nest start --watch"
2609
+ },
2610
+ {
2611
+ type: "patch-script",
2612
+ name: "dev:server",
2613
+ to: "NODE_ENV=development node ./scripts/dev-server.js",
2614
+ ifEquals: "nest start --watch"
2590
2615
  }
2591
2616
  ];
2592
2617
  if (!opts.disableGenOpenapi) {
@@ -2603,11 +2628,7 @@ function defaultProfile(opts) {
2603
2628
  return {
2604
2629
  sync: buildDefaultRules(opts),
2605
2630
  // 文件权限设置(所有 .sh 文件设置为可执行:'**/*.sh': 0o755)
2606
- // Workspace / TOS restore may materialize scripts with 0644 even when the
2607
- // platform template tracks the executable bit. `npm run dev` executes
2608
- // scripts/dev.sh directly, so repairing the mode is part of sync's
2609
- // platform contract rather than an image-entrypoint side effect.
2610
- permissions: { "**/*.sh": 493 },
2631
+ permissions: {},
2611
2632
  activateGitHooks: true
2612
2633
  };
2613
2634
  }
@@ -2620,7 +2641,15 @@ function emptyProfile() {
2620
2641
  }
2621
2642
  function viteReactProfile() {
2622
2643
  return {
2623
- sync: [],
2644
+ sync: [
2645
+ // 覆盖 scripts/build.sh(回溯 public/* → dist/output/ 的修复)
2646
+ {
2647
+ from: "templates/vite-react/build.sh",
2648
+ to: "scripts/build.sh",
2649
+ type: "file",
2650
+ overwrite: true
2651
+ }
2652
+ ],
2624
2653
  permissions: {},
2625
2654
  activateGitHooks: true
2626
2655
  };
@@ -2762,7 +2791,9 @@ async function run2(options) {
2762
2791
  }
2763
2792
  const stack = resolveStack(userProjectRoot);
2764
2793
  try {
2765
- console.log(`[fullstack-cli] Starting sync${stack ? ` (stack: ${stack})` : ""}...`);
2794
+ console.log(
2795
+ `[fullstack-cli] Starting sync${stack ? ` (stack: ${stack})` : ""}...`
2796
+ );
2766
2797
  const config = genSyncConfig(stack, {
2767
2798
  disableGenOpenapi: options.disableGenOpenapi ?? false
2768
2799
  });
@@ -2781,7 +2812,9 @@ async function run2(options) {
2781
2812
  activateGitHooks(userProjectRoot);
2782
2813
  } catch (error) {
2783
2814
  const message = error instanceof Error ? error.message : String(error);
2784
- console.warn(`[fullstack-cli] \u26A0 Failed to activate git hooks: ${message}`);
2815
+ console.warn(
2816
+ `[fullstack-cli] \u26A0 Failed to activate git hooks: ${message}`
2817
+ );
2785
2818
  }
2786
2819
  }
2787
2820
  console.log("[fullstack-cli] Sync completed successfully \u2705");
@@ -2801,7 +2834,9 @@ function resolveStack(userProjectRoot) {
2801
2834
  return typeof meta.stack === "string" ? meta.stack : void 0;
2802
2835
  } catch (error) {
2803
2836
  const message = error instanceof Error ? error.message : String(error);
2804
- console.warn(`[fullstack-cli] \u26A0 Failed to read .spark/meta.json, fallback to default sync: ${message}`);
2837
+ console.warn(
2838
+ `[fullstack-cli] \u26A0 Failed to read .spark/meta.json, fallback to default sync: ${message}`
2839
+ );
2805
2840
  return void 0;
2806
2841
  }
2807
2842
  }
@@ -2822,12 +2857,22 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
2822
2857
  }
2823
2858
  if (rule.type === "add-script") {
2824
2859
  const packageJsonPath = path5.join(userProjectRoot, "package.json");
2825
- addScript(packageJsonPath, rule.name, rule.command, rule.overwrite ?? false);
2860
+ addScript(
2861
+ packageJsonPath,
2862
+ rule.name,
2863
+ rule.command,
2864
+ rule.overwrite ?? false
2865
+ );
2866
+ return;
2867
+ }
2868
+ if (rule.type === "ensure-dev-dependency") {
2869
+ const packageJsonPath = path5.join(userProjectRoot, "package.json");
2870
+ ensureDevDependency(packageJsonPath, rule.name, rule.version);
2826
2871
  return;
2827
2872
  }
2828
2873
  if (rule.type === "patch-script") {
2829
2874
  const packageJsonPath = path5.join(userProjectRoot, "package.json");
2830
- patchScript(packageJsonPath, rule.name, rule.to, rule.ifStartsWith);
2875
+ patchScript(packageJsonPath, rule);
2831
2876
  return;
2832
2877
  }
2833
2878
  if (rule.type === "add-line") {
@@ -2855,7 +2900,12 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
2855
2900
  syncDirectory(srcPath, destPath, rule.overwrite ?? true);
2856
2901
  break;
2857
2902
  case "file":
2858
- syncFile(srcPath, destPath, rule.overwrite ?? true, rule.onlyIfExists ?? false);
2903
+ syncFile(
2904
+ srcPath,
2905
+ destPath,
2906
+ rule.overwrite ?? true,
2907
+ rule.onlyIfExists ?? false
2908
+ );
2859
2909
  break;
2860
2910
  case "append":
2861
2911
  appendToFile(srcPath, destPath);
@@ -2864,7 +2914,9 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
2864
2914
  }
2865
2915
  function syncFile(src, dest, overwrite = true, onlyIfExists = false) {
2866
2916
  if (onlyIfExists && !fs7.existsSync(dest)) {
2867
- console.log(`[fullstack-cli] \u25CB ${path5.basename(dest)} (skipped, target not exists)`);
2917
+ console.log(
2918
+ `[fullstack-cli] \u25CB ${path5.basename(dest)} (skipped, target not exists)`
2919
+ );
2868
2920
  return;
2869
2921
  }
2870
2922
  const destDir = path5.dirname(dest);
@@ -2872,7 +2924,9 @@ function syncFile(src, dest, overwrite = true, onlyIfExists = false) {
2872
2924
  fs7.mkdirSync(destDir, { recursive: true });
2873
2925
  }
2874
2926
  if (fs7.existsSync(dest) && !overwrite) {
2875
- console.log(`[fullstack-cli] \u25CB ${path5.basename(dest)} (skipped, already exists)`);
2927
+ console.log(
2928
+ `[fullstack-cli] \u25CB ${path5.basename(dest)} (skipped, already exists)`
2929
+ );
2876
2930
  return;
2877
2931
  }
2878
2932
  fs7.copyFileSync(src, dest);
@@ -2899,7 +2953,9 @@ function syncDirectory(src, dest, overwrite = true) {
2899
2953
  }
2900
2954
  });
2901
2955
  if (count > 0) {
2902
- console.log(`[fullstack-cli] Synced ${count} files to ${path5.basename(dest)}/`);
2956
+ console.log(
2957
+ `[fullstack-cli] Synced ${count} files to ${path5.basename(dest)}/`
2958
+ );
2903
2959
  }
2904
2960
  }
2905
2961
  function appendToFile(src, dest) {
@@ -2909,7 +2965,9 @@ function appendToFile(src, dest) {
2909
2965
  existingContent = fs7.readFileSync(dest, "utf-8");
2910
2966
  }
2911
2967
  if (existingContent.includes(content.trim())) {
2912
- console.log(`[fullstack-cli] \u25CB ${path5.basename(dest)} (already contains content)`);
2968
+ console.log(
2969
+ `[fullstack-cli] \u25CB ${path5.basename(dest)} (already contains content)`
2970
+ );
2913
2971
  return;
2914
2972
  }
2915
2973
  fs7.appendFileSync(dest, content);
@@ -2967,7 +3025,34 @@ function addScript(packageJsonPath, name, command, overwrite) {
2967
3025
  fs7.writeFileSync(packageJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
2968
3026
  console.log(`[fullstack-cli] \u2713 scripts.${name}`);
2969
3027
  }
2970
- function patchScript(packageJsonPath, name, to, ifStartsWith) {
3028
+ function ensureDevDependency(packageJsonPath, name, version) {
3029
+ if (!fs7.existsSync(packageJsonPath)) {
3030
+ console.log("[fullstack-cli] \u25CB package.json (not found)");
3031
+ return;
3032
+ }
3033
+ try {
3034
+ const content = fs7.readFileSync(packageJsonPath, "utf-8");
3035
+ const pkg2 = JSON.parse(content);
3036
+ const existingVersion = pkg2.dependencies?.[name] ?? pkg2.devDependencies?.[name];
3037
+ if (existingVersion !== void 0) {
3038
+ console.log(
3039
+ `[fullstack-cli] \u25CB ${name} (already declared as ${existingVersion})`
3040
+ );
3041
+ return;
3042
+ }
3043
+ pkg2.devDependencies ?? (pkg2.devDependencies = {});
3044
+ pkg2.devDependencies[name] = version;
3045
+ fs7.writeFileSync(packageJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
3046
+ console.log(`[fullstack-cli] \u2713 devDependencies.${name} = ${version}`);
3047
+ } catch (error) {
3048
+ const message = error instanceof Error ? error.message : String(error);
3049
+ console.warn(
3050
+ `[fullstack-cli] \u26A0 Could not ensure dependency ${name}: ${message}`
3051
+ );
3052
+ }
3053
+ }
3054
+ function patchScript(packageJsonPath, rule) {
3055
+ const { name, to } = rule;
2971
3056
  if (!fs7.existsSync(packageJsonPath)) {
2972
3057
  console.log(`[fullstack-cli] \u25CB package.json (not found)`);
2973
3058
  return;
@@ -2984,7 +3069,8 @@ function patchScript(packageJsonPath, name, to, ifStartsWith) {
2984
3069
  console.log(`[fullstack-cli] \u25CB scripts.${name} (already patched)`);
2985
3070
  return;
2986
3071
  }
2987
- if (!current.startsWith(ifStartsWith)) {
3072
+ const matches = rule.ifEquals !== void 0 ? current === rule.ifEquals : current.startsWith(rule.ifStartsWith);
3073
+ if (!matches) {
2988
3074
  console.warn(
2989
3075
  `[fullstack-cli] \u26A0 Skipped patching scripts.${name} because it has been customized`
2990
3076
  );
@@ -2995,7 +3081,9 @@ function patchScript(packageJsonPath, name, to, ifStartsWith) {
2995
3081
  console.log(`[fullstack-cli] \u2713 Patched scripts.${name}`);
2996
3082
  } catch (error) {
2997
3083
  const message = error instanceof Error ? error.message : String(error);
2998
- console.warn(`[fullstack-cli] \u26A0 Could not patch scripts.${name}: ${message}`);
3084
+ console.warn(
3085
+ `[fullstack-cli] \u26A0 Could not patch scripts.${name}: ${message}`
3086
+ );
2999
3087
  }
3000
3088
  }
3001
3089
  function addLineToFile(filePath, line) {
@@ -8224,2725 +8312,62 @@ async function preUploadStatic(options) {
8224
8312
  }
8225
8313
  }
8226
8314
 
8227
- // src/commands/build/server-cache-bundle.handler.ts
8228
- import fs29 from "fs";
8229
- import http from "http";
8230
- import net from "net";
8231
- import os3 from "os";
8232
- import path25 from "path";
8233
- import { builtinModules, createRequire as createRequire3 } from "module";
8234
- import { spawn as spawn2 } from "child_process";
8235
- import { createHash } from "crypto";
8236
- import { build } from "esbuild";
8237
- import { parse } from "acorn";
8238
- import { simple as walkSimple } from "acorn-walk";
8239
- var OPTIONAL_NEST_DEPENDENCIES = [
8240
- "@nestjs/microservices",
8241
- "@nestjs/microservices/microservices-module",
8242
- "@nestjs/websockets/socket-module",
8243
- "@node-rs/xxhash",
8244
- "fsevents"
8245
- ];
8246
- var BUILTINS = /* @__PURE__ */ new Set([
8247
- ...builtinModules,
8248
- ...builtinModules.map((name) => `node:${name}`)
8249
- ]);
8250
- var DEFAULT_COMPILED_ENTRIES = [
8251
- "dist/server/main.js",
8252
- "dist/main.js"
8253
- ];
8254
- var BUILD_ONLY_SERVER_CACHE_PACKAGES = [
8255
- "@lark-apaas/nestjs-openapi-devtools",
8256
- "@hey-api/openapi-ts",
8257
- "typescript",
8258
- "jiti",
8259
- "nypm"
8260
- ];
8261
- function workspaceSourceSha256(projectRoot) {
8262
- const files = [];
8263
- const visit = (directory) => {
8264
- if (!fs29.existsSync(directory)) return;
8265
- for (const entry of fs29.readdirSync(directory, { withFileTypes: true })) {
8266
- const candidate = path25.join(directory, entry.name);
8267
- if (entry.isSymbolicLink()) continue;
8268
- if (entry.isDirectory()) visit(candidate);
8269
- else if (entry.isFile()) files.push(candidate);
8270
- }
8271
- };
8272
- for (const root of ["server", "shared", "src"]) {
8273
- visit(path25.join(projectRoot, root));
8274
- }
8275
- const hash = createHash("sha256");
8276
- for (const file of files.sort()) {
8277
- hash.update(path25.relative(projectRoot, file).split(path25.sep).join("/"));
8278
- hash.update("\0");
8279
- hash.update(fs29.readFileSync(file));
8280
- hash.update("\0");
8281
- }
8282
- return hash.digest("hex");
8283
- }
8284
- function absolute(root, candidate) {
8285
- return path25.isAbsolute(candidate) ? candidate : path25.resolve(root, candidate);
8286
- }
8287
- function isPathInside(root, candidate) {
8288
- const relative = path25.relative(root, candidate);
8289
- return relative === "" || !relative.startsWith("..") && !path25.isAbsolute(relative);
8290
- }
8291
- function validateOwnedServerOutput(projectRoot, outfile, metadataFile) {
8292
- const cacheRoot = path25.join(projectRoot, ".miaoda-cache");
8293
- if (!isPathInside(cacheRoot, outfile) || path25.basename(path25.dirname(outfile)) !== "server" || path25.basename(outfile) !== "server.bundle.cjs" || metadataFile !== `${outfile}.meta.json`) {
8294
- return "server cache output must be <projectRoot>/.miaoda-cache/**/server/server.bundle.cjs with adjacent metadata";
8295
- }
8296
- let current = path25.dirname(outfile);
8297
- while (current !== projectRoot) {
8298
- if (fs29.existsSync(current) && fs29.lstatSync(current).isSymbolicLink()) {
8299
- return `server cache output directory symlink is unsupported: ${current}`;
8300
- }
8301
- const parent = path25.dirname(current);
8302
- if (parent === current || !isPathInside(projectRoot, parent)) {
8303
- return "server cache output escaped project root";
8304
- }
8305
- current = parent;
8306
- }
8307
- return void 0;
8308
- }
8309
- function resolveCompiledEntry(projectRoot, requestedEntry) {
8310
- if (requestedEntry) {
8311
- const entry = absolute(projectRoot, requestedEntry);
8312
- return fs29.existsSync(entry) ? { entry, reasons: [] } : { reasons: [`compiled entry missing: ${entry}`] };
8313
- }
8314
- const candidates = DEFAULT_COMPILED_ENTRIES.map(
8315
- (candidate) => absolute(projectRoot, candidate)
8316
- ).filter((candidate) => fs29.existsSync(candidate));
8317
- if (candidates.length === 1) return { entry: candidates[0], reasons: [] };
8318
- if (candidates.length > 1) {
8319
- return {
8320
- reasons: [
8321
- `compiled entry is ambiguous; pass --entry explicitly: ${candidates.join(", ")}`
8322
- ]
8323
- };
8324
- }
8325
- return {
8326
- reasons: [
8327
- `compiled entry missing; checked: ${DEFAULT_COMPILED_ENTRIES.map(
8328
- (candidate) => absolute(projectRoot, candidate)
8329
- ).join(", ")}`
8330
- ]
8331
- };
8332
- }
8333
- function optionalDependencyStubPlugin() {
8334
- const escaped = OPTIONAL_NEST_DEPENDENCIES.map(
8335
- (name) => name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
8336
- );
8337
- const filter = new RegExp(`^(?:${escaped.join("|")})$`);
8338
- return {
8339
- name: "miaoda-optional-nest-dependency-stubs",
8340
- setup(esbuild) {
8341
- esbuild.onResolve({ filter }, (args) => ({
8342
- path: args.path,
8343
- namespace: "miaoda-optional-nest-dependency"
8344
- }));
8345
- esbuild.onLoad(
8346
- { filter: /.*/, namespace: "miaoda-optional-nest-dependency" },
8347
- (args) => ({
8348
- contents: `const error = new Error(${JSON.stringify(
8349
- `Optional dependency is unavailable in cache runtime: ${args.path}`
8350
- )}); error.code = 'MODULE_NOT_FOUND'; throw error;`,
8351
- loader: "js"
8352
- })
8353
- );
8354
- }
8355
- };
8356
- }
8357
- function classTransformerStorageResolver(projectRoot) {
8358
- const projectRequire = createRequire3(path25.join(projectRoot, "package.json"));
8359
- return {
8360
- name: "miaoda-class-transformer-storage-resolver",
8361
- setup(esbuild) {
8362
- esbuild.onResolve({ filter: /^class-transformer\/storage$/ }, () => {
8363
- try {
8364
- return {
8365
- path: projectRequire.resolve("class-transformer/cjs/storage.js")
8366
- };
8367
- } catch {
8368
- return void 0;
8369
- }
8370
- });
8371
- }
8372
- };
8373
- }
8374
- function resolveProjectPackage(projectRoot, specifier) {
8375
- return createRequire3(path25.join(projectRoot, "package.json")).resolve(
8376
- specifier
8377
- );
8378
- }
8379
- function fullstackNestRuntimeResolver(projectRoot) {
8380
- return {
8381
- name: "miaoda-fullstack-nest-runtime-resolver",
8382
- setup(esbuild) {
8383
- esbuild.onResolve(
8384
- { filter: /^@lark-apaas\/fullstack-nestjs-core$/ },
8385
- () => {
8386
- try {
8387
- return {
8388
- path: resolveProjectPackage(
8389
- projectRoot,
8390
- "@lark-apaas/fullstack-nestjs-core/runtime"
8391
- )
8392
- };
8393
- } catch (runtimeError) {
8394
- try {
8395
- return {
8396
- path: resolveProjectPackage(
8397
- projectRoot,
8398
- "@lark-apaas/fullstack-nestjs-core"
8399
- )
8400
- };
8401
- } catch (rootError) {
8402
- return {
8403
- errors: [
8404
- {
8405
- text: `@lark-apaas/fullstack-nestjs-core cannot be resolved from the project: runtime=${runtimeError instanceof Error ? runtimeError.message : String(runtimeError)}; root=${rootError instanceof Error ? rootError.message : String(rootError)}`
8406
- }
8407
- ]
8408
- };
8409
- }
8410
- }
8411
- }
8412
- );
8413
- }
8414
- };
8415
- }
8416
- function legacyFullstackNestOpenApiStub(projectRoot) {
8417
- let runtimeOnlyEntryAvailable = false;
8418
- try {
8419
- resolveProjectPackage(
8420
- projectRoot,
8421
- "@lark-apaas/fullstack-nestjs-core/runtime"
8422
- );
8423
- runtimeOnlyEntryAvailable = true;
8424
- } catch {
8425
- }
8426
- return {
8427
- name: "miaoda-legacy-nest-openapi-stub",
8428
- setup(esbuild) {
8429
- if (runtimeOnlyEntryAvailable) return;
8430
- esbuild.onResolve(
8431
- { filter: /^@lark-apaas\/nestjs-openapi-devtools$/ },
8432
- () => ({
8433
- path: "@lark-apaas/nestjs-openapi-devtools",
8434
- namespace: "miaoda-legacy-nest-openapi-stub"
8435
- })
8436
- );
8437
- esbuild.onLoad(
8438
- { filter: /.*/, namespace: "miaoda-legacy-nest-openapi-stub" },
8439
- () => ({
8440
- contents: "class DisabledOpenApiModule { static async mount() {} }\nmodule.exports = { DevToolsModule: DisabledOpenApiModule, DevToolsV2Module: DisabledOpenApiModule };",
8441
- loader: "js"
8442
- })
8443
- );
8444
- }
8445
- };
8446
- }
8447
- function rejectNativeAddonsPlugin() {
8448
- return {
8449
- name: "miaoda-reject-native-addons",
8450
- setup(esbuild) {
8451
- esbuild.onResolve({ filter: /\.node$/ }, (args) => {
8452
- if (args.path.startsWith(".") && fs29.existsSync(path25.resolve(args.resolveDir, `${args.path}.js`))) {
8453
- return void 0;
8454
- }
8455
- return {
8456
- errors: [
8457
- {
8458
- text: `native addons are unsupported in the server cache bundle: ${args.path}`
8459
- }
8460
- ]
8461
- };
8462
- });
8463
- }
8464
- };
8465
- }
8466
- function findPackageRoot(entryPath) {
8467
- let current = path25.dirname(entryPath);
8468
- while (current !== path25.dirname(current)) {
8469
- if (fs29.existsSync(path25.join(current, "package.json"))) return current;
8470
- current = path25.dirname(current);
8471
- }
8472
- return void 0;
8473
- }
8474
- function canonicalSourcePath(projectRoot, sourcePath) {
8475
- const relativeOrigin = path25.relative(projectRoot, sourcePath).split(path25.sep).join("/");
8476
- const nestedPackageMarker = "/node_modules/";
8477
- const nestedPackageIndex = relativeOrigin.lastIndexOf(nestedPackageMarker);
8478
- const firstPackageIndex = relativeOrigin.indexOf("node_modules/");
8479
- if (nestedPackageIndex >= 0) {
8480
- return `node_modules/${relativeOrigin.slice(
8481
- nestedPackageIndex + nestedPackageMarker.length
8482
- )}`;
8483
- }
8484
- return firstPackageIndex > 0 ? relativeOrigin.slice(firstPackageIndex) : relativeOrigin;
8485
- }
8486
- function parseJavaScriptSource(source) {
8487
- try {
8488
- return parse(source, {
8489
- ecmaVersion: "latest",
8490
- sourceType: "module",
8491
- allowHashBang: true,
8492
- locations: true
8493
- });
8494
- } catch {
8495
- return parse(source, {
8496
- ecmaVersion: "latest",
8497
- sourceType: "script",
8498
- allowHashBang: true,
8499
- allowReturnOutsideFunction: true,
8500
- locations: true
8315
+ // src/commands/build/index.ts
8316
+ var getTokenCommand = {
8317
+ name: "get-token",
8318
+ description: "Get artifact upload credential (STI token)",
8319
+ register(program) {
8320
+ program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").requiredOption("--scene <scene>", "Build scene (pipeline, static)").option("--commit-id <id>", "Git commit ID (required for pipeline scene)").action(async (options) => {
8321
+ await getToken(options);
8501
8322
  });
8502
8323
  }
8503
- }
8504
- function staticStringValue(node) {
8505
- if (!node) return void 0;
8506
- if (node.type === "Literal" && typeof node.value === "string") {
8507
- return node.value;
8508
- }
8509
- if (node.type === "TemplateLiteral" && node.expressions.length === 0) {
8510
- return node.quasis[0]?.value?.cooked ?? "";
8511
- }
8512
- return void 0;
8513
- }
8514
- function isImportMetaUrl(node) {
8515
- return Boolean(
8516
- node?.type === "MemberExpression" && staticPropertyName(node) === "url" && node.object?.type === "MetaProperty" && node.object.meta?.name === "import" && node.object.property?.name === "meta"
8517
- );
8518
- }
8519
- function isBundleDirectoryExpression(node) {
8520
- if (!node) return false;
8521
- if (node.type === "Identifier" && node.name === "__dirname") return true;
8522
- if (node.type !== "CallExpression") return false;
8523
- const property = staticPropertyName(node.callee);
8524
- if (property === "dirname" && (node.arguments[0]?.type === "Identifier" && node.arguments[0].name === "__filename" ? true : node.arguments[0]?.type === "CallExpression" && staticPropertyName(node.arguments[0].callee) === "fileURLToPath" && isImportMetaUrl(node.arguments[0].arguments[0]))) {
8525
- return true;
8526
- }
8527
- return false;
8528
- }
8529
- function canonicalRuntimeAssetPath(candidate) {
8530
- const normalized = candidate.split(path25.sep).join("/");
8531
- if (!normalized || normalized === "." || normalized !== path25.posix.normalize(normalized) || normalized.startsWith("../") || path25.posix.isAbsolute(normalized) || normalized.includes("\\")) {
8532
- return void 0;
8533
- }
8534
- return normalized;
8535
- }
8536
- function resolveRuntimeAssetExpression(projectRoot, sourcePath, node) {
8537
- const direct = staticStringValue(node);
8538
- if (direct !== void 0 && !path25.isAbsolute(direct)) {
8539
- const destination2 = canonicalRuntimeAssetPath(direct);
8540
- return destination2 ? { source: path25.resolve(projectRoot, direct), destination: destination2 } : void 0;
8541
- }
8542
- if (node?.type === "NewExpression" && node.callee?.type === "Identifier" && node.callee.name === "URL") {
8543
- const relative2 = staticStringValue(node.arguments[0]);
8544
- if (relative2 && isImportMetaUrl(node.arguments[1])) {
8545
- const destination2 = canonicalRuntimeAssetPath(
8546
- relative2.replace(/^\.\//, "")
8547
- );
8548
- return destination2 ? {
8549
- source: path25.resolve(path25.dirname(sourcePath), relative2),
8550
- destination: destination2
8551
- } : void 0;
8552
- }
8553
- }
8554
- if (node?.type !== "CallExpression") return void 0;
8555
- const property = staticPropertyName(node.callee);
8556
- if (!["join", "resolve"].includes(property ?? "")) return void 0;
8557
- if (!isBundleDirectoryExpression(node.arguments[0])) return void 0;
8558
- const segments = node.arguments.slice(1).map(staticStringValue);
8559
- if (segments.some((segment) => segment === void 0)) return void 0;
8560
- const relative = path25.join(...segments);
8561
- const destination = canonicalRuntimeAssetPath(relative);
8562
- return destination ? {
8563
- source: path25.resolve(path25.dirname(sourcePath), relative),
8564
- destination
8565
- } : void 0;
8566
- }
8567
- function isFsModuleSpecifier(node) {
8568
- return ["fs", "node:fs"].includes(staticStringValue(node) ?? "");
8569
- }
8570
- function containsFsModuleLoad(node) {
8571
- if (!node) return false;
8572
- if (node.type === "CallExpression" && node.callee?.type === "Identifier" && node.callee.name === "require" && isFsModuleSpecifier(node.arguments[0])) {
8573
- return true;
8574
- }
8575
- if (node.type === "CallExpression") {
8576
- return node.arguments.some(
8577
- (argument) => containsFsModuleLoad(argument)
8578
- );
8579
- }
8580
- if (node.type === "MemberExpression") {
8581
- return containsFsModuleLoad(node.object);
8582
- }
8583
- if (node.type === "ChainExpression") {
8584
- return containsFsModuleLoad(node.expression);
8585
- }
8586
- return false;
8587
- }
8588
- function rootIdentifier(node) {
8589
- let current = node;
8590
- while (current?.type === "MemberExpression") current = current.object;
8591
- return current?.type === "Identifier" ? current.name : void 0;
8592
- }
8593
- function collectFsBindings(ast, runtimeFsMethods) {
8594
- const namespaces = /* @__PURE__ */ new Set();
8595
- const methods = /* @__PURE__ */ new Set();
8596
- walkSimple(ast, {
8597
- ImportDeclaration(node) {
8598
- if (!isFsModuleSpecifier(node.source)) return;
8599
- for (const specifier of node.specifiers ?? []) {
8600
- if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
8601
- namespaces.add(specifier.local.name);
8602
- continue;
8603
- }
8604
- if (specifier.type !== "ImportSpecifier") continue;
8605
- const imported = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
8606
- if (typeof imported === "string" && runtimeFsMethods.has(imported)) {
8607
- methods.add(specifier.local.name);
8608
- }
8609
- }
8610
- },
8611
- VariableDeclarator(node) {
8612
- if (!containsFsModuleLoad(node.init)) return;
8613
- if (node.id?.type === "Identifier") {
8614
- const importedMethod = staticPropertyName(node.init);
8615
- if (importedMethod && runtimeFsMethods.has(importedMethod)) {
8616
- methods.add(node.id.name);
8617
- } else {
8618
- namespaces.add(node.id.name);
8619
- }
8620
- return;
8621
- }
8622
- if (node.id?.type === "ObjectPattern") {
8623
- for (const property of node.id.properties ?? []) {
8624
- if (property.type === "RestElement") continue;
8625
- const imported = property.key.type === "Identifier" ? property.key.name : staticStringValue(property.key);
8626
- const local = property.value.type === "Identifier" ? property.value.name : void 0;
8627
- if (typeof imported === "string" && runtimeFsMethods.has(imported) && typeof local === "string") {
8628
- methods.add(local);
8629
- }
8630
- }
8631
- }
8632
- }
8633
- });
8634
- return { namespaces, methods };
8635
- }
8636
- function resolveFsMethod(callee, bindings, runtimeFsMethods) {
8637
- if (callee.type === "Identifier" && bindings.methods.has(callee.name)) {
8638
- return callee.name;
8639
- }
8640
- const method = staticPropertyName(callee);
8641
- if (!method || !runtimeFsMethods.has(method)) return void 0;
8642
- if (callee.type !== "MemberExpression") return void 0;
8643
- if (containsFsModuleLoad(callee.object)) return method;
8644
- const root = rootIdentifier(callee.object);
8645
- return root && bindings.namespaces.has(root) ? method : void 0;
8646
- }
8647
- function isChildProcessModuleSpecifier(node) {
8648
- return ["child_process", "node:child_process"].includes(
8649
- staticStringValue(node) ?? ""
8650
- );
8651
- }
8652
- function containsChildProcessLoad(node) {
8653
- if (!node) return false;
8654
- if (node.type === "CallExpression" && node.callee?.type === "Identifier" && node.callee.name === "require" && isChildProcessModuleSpecifier(node.arguments[0])) {
8655
- return true;
8656
- }
8657
- if (node.type === "MemberExpression") {
8658
- return containsChildProcessLoad(node.object);
8659
- }
8660
- return false;
8661
- }
8662
- function collectChildProcessForkBindings(ast) {
8663
- const namespaces = /* @__PURE__ */ new Set();
8664
- const methods = /* @__PURE__ */ new Set();
8665
- walkSimple(ast, {
8666
- ImportDeclaration(node) {
8667
- if (!isChildProcessModuleSpecifier(node.source)) return;
8668
- for (const specifier of node.specifiers ?? []) {
8669
- if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
8670
- namespaces.add(specifier.local.name);
8671
- } else if (specifier.type === "ImportSpecifier" && (specifier.imported?.name === "fork" || specifier.imported?.value === "fork")) {
8672
- methods.add(specifier.local.name);
8673
- }
8674
- }
8675
- },
8676
- VariableDeclarator(node) {
8677
- if (!containsChildProcessLoad(node.init)) return;
8678
- if (node.id?.type === "Identifier") {
8679
- if (staticPropertyName(node.init) === "fork") {
8680
- methods.add(node.id.name);
8681
- } else {
8682
- namespaces.add(node.id.name);
8683
- }
8684
- } else if (node.id?.type === "ObjectPattern") {
8685
- for (const property of node.id.properties ?? []) {
8686
- const imported = property.type !== "RestElement" && property.key?.type === "Identifier" ? property.key.name : property.type !== "RestElement" ? staticStringValue(property.key) : void 0;
8687
- if (property.type !== "RestElement" && imported === "fork" && property.value?.type === "Identifier") {
8688
- methods.add(property.value.name);
8689
- }
8690
- }
8691
- }
8692
- }
8693
- });
8694
- return { namespaces, methods };
8695
- }
8696
- function isChildProcessFork(callee, bindings) {
8697
- if (callee.type === "Identifier") return bindings.methods.has(callee.name);
8698
- if (callee.type !== "MemberExpression" || staticPropertyName(callee) !== "fork") {
8699
- return false;
8324
+ };
8325
+ var uploadStaticCommand = {
8326
+ name: "upload-static",
8327
+ description: "Upload shared/static files to TOS",
8328
+ register(program) {
8329
+ program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").option("--static-dir <dir>", "Static files directory", UPLOAD_STATIC_DEFAULTS.staticDir).option("--tosutil-path <path>", "Path to tosutil binary", UPLOAD_STATIC_DEFAULTS.tosutilPath).option("--endpoint <endpoint>", "TOS endpoint", UPLOAD_STATIC_DEFAULTS.endpoint).option("--region <region>", "TOS region", UPLOAD_STATIC_DEFAULTS.region).action(async (options) => {
8330
+ await uploadStatic(options);
8331
+ });
8700
8332
  }
8701
- if (containsChildProcessLoad(callee.object)) return true;
8702
- const root = rootIdentifier(callee.object);
8703
- return Boolean(root && bindings.namespaces.has(root));
8704
- }
8705
- function materializeServerRuntimeAssets(projectRoot, metafile, bundleDirectory, configuredAssets = []) {
8706
- const candidates = [];
8707
- const warnings = [];
8708
- const runtimeFsMethods = /* @__PURE__ */ new Set([
8709
- "readFile",
8710
- "readFileSync",
8711
- "createReadStream",
8712
- "open",
8713
- "openSync"
8714
- ]);
8715
- for (const input of Object.keys(metafile.inputs).sort()) {
8716
- if (!/\.(?:cjs|mjs|js)$/.test(input)) continue;
8717
- const sourcePath = path25.resolve(projectRoot, input);
8718
- if (!fs29.existsSync(sourcePath) || !fs29.statSync(sourcePath).isFile()) {
8719
- continue;
8720
- }
8721
- const source = fs29.readFileSync(sourcePath, "utf8");
8722
- const origin = canonicalSourcePath(projectRoot, sourcePath);
8723
- const ast = parseJavaScriptSource(source);
8724
- const fsBindings = collectFsBindings(ast, runtimeFsMethods);
8725
- const childProcessBindings = collectChildProcessForkBindings(ast);
8726
- const recordRuntimeAsset = (expressionNode) => {
8727
- const resolved = resolveRuntimeAssetExpression(
8728
- projectRoot,
8729
- sourcePath,
8730
- expressionNode
8731
- );
8732
- if (resolved && fs29.existsSync(resolved.source)) {
8733
- candidates.push({ ...resolved, origin });
8734
- return;
8735
- }
8736
- const expression = source.slice(
8737
- expressionNode?.start ?? 0,
8738
- expressionNode?.end ?? source.length
8739
- );
8740
- warnings.push({
8741
- kind: resolved ? "missing-runtime-asset" : "dynamic-runtime-asset",
8742
- source: origin,
8743
- expressionHash: createHash("sha256").update(expression).digest("hex").slice(0, 16),
8744
- message: resolved ? `Static runtime asset is unavailable at build time: ${resolved.destination}` : "Runtime asset path cannot be determined statically"
8745
- });
8746
- };
8747
- walkSimple(ast, {
8748
- CallExpression(node) {
8749
- const method = resolveFsMethod(
8750
- node.callee,
8751
- fsBindings,
8752
- runtimeFsMethods
8753
- );
8754
- if (method || isChildProcessFork(node.callee, childProcessBindings)) {
8755
- recordRuntimeAsset(node.arguments[0]);
8756
- }
8757
- },
8758
- NewExpression(node) {
8759
- if (node.callee?.type === "Identifier" && node.callee.name === "URL" && isImportMetaUrl(node.arguments[1])) {
8760
- recordRuntimeAsset(node);
8761
- return;
8762
- }
8763
- if (node.callee?.type === "Identifier" && ["Worker", "SharedWorker"].includes(node.callee.name)) {
8764
- recordRuntimeAsset(node.arguments[0]);
8765
- }
8766
- }
8333
+ };
8334
+ var preUploadStaticCommand = {
8335
+ name: "pre-upload-static",
8336
+ description: "Get TOS upload info and output as env vars for build.sh eval",
8337
+ register(program) {
8338
+ program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").action(async (options) => {
8339
+ await preUploadStatic(options);
8767
8340
  });
8768
8341
  }
8769
- for (const configured of configuredAssets) {
8770
- if (typeof configured?.source !== "string" || !configured.source || typeof configured?.path !== "string") {
8771
- throw new Error("configured runtime asset must include source and path");
8772
- }
8773
- const destination = canonicalRuntimeAssetPath(configured.path);
8774
- if (!destination) {
8775
- throw new Error(
8776
- `configured runtime asset path is invalid: ${configured.path}`
8777
- );
8778
- }
8779
- const source = path25.resolve(projectRoot, configured.source);
8780
- if (!isPathInside(projectRoot, source) || !fs29.existsSync(source)) {
8781
- throw new Error(
8782
- `configured runtime asset source is invalid: ${configured.source}`
8783
- );
8784
- }
8785
- candidates.push({ source, destination, origin: "package.json" });
8786
- }
8787
- const published = /* @__PURE__ */ new Map();
8788
- const assertNoSymlinkPath = (source) => {
8789
- const relative = path25.relative(projectRoot, source);
8790
- if (!relative || relative.startsWith("..") || path25.isAbsolute(relative)) {
8791
- throw new Error(`server runtime asset source escaped project: ${source}`);
8792
- }
8793
- let current = projectRoot;
8794
- for (const segment of relative.split(path25.sep)) {
8795
- current = path25.join(current, segment);
8796
- if (fs29.lstatSync(current).isSymbolicLink()) {
8797
- throw new Error(
8798
- `server runtime asset symlink is unsupported: ${current}`
8799
- );
8800
- }
8801
- }
8802
- };
8803
- const publishFile = (source, destination) => {
8804
- const assetPath = canonicalRuntimeAssetPath(destination);
8805
- if (!assetPath) {
8806
- throw new Error(`server runtime asset path is invalid: ${destination}`);
8807
- }
8808
- assertNoSymlinkPath(source);
8809
- const target = path25.join(bundleDirectory, ...assetPath.split("/"));
8810
- const content = fs29.readFileSync(source);
8811
- const sha2562 = createHash("sha256").update(content).digest("hex");
8812
- const existing = published.get(assetPath);
8813
- if (existing && existing.sha256 !== sha2562) {
8814
- throw new Error(`server runtime asset collision: ${assetPath}`);
8815
- }
8816
- if (!existing) {
8817
- fs29.mkdirSync(path25.dirname(target), { recursive: true });
8818
- fs29.writeFileSync(target, content);
8819
- published.set(assetPath, {
8820
- path: assetPath,
8821
- sha256: sha2562,
8822
- size: content.length
8823
- });
8824
- }
8825
- };
8826
- const publishCandidate = (source, destination) => {
8827
- assertNoSymlinkPath(source);
8828
- const stat = fs29.lstatSync(source);
8829
- if (stat.isSymbolicLink()) {
8830
- throw new Error(`server runtime asset symlink is unsupported: ${source}`);
8831
- }
8832
- if (stat.isFile()) {
8833
- publishFile(source, destination);
8834
- return;
8835
- }
8836
- if (!stat.isDirectory()) {
8837
- throw new Error(`server runtime asset type is unsupported: ${source}`);
8838
- }
8839
- for (const entry of fs29.readdirSync(source, { withFileTypes: true })) {
8840
- publishCandidate(
8841
- path25.join(source, entry.name),
8842
- path25.posix.join(destination, entry.name)
8843
- );
8844
- }
8845
- };
8846
- for (const candidate of candidates.sort(
8847
- (left, right) => left.destination.localeCompare(right.destination)
8848
- )) {
8849
- publishCandidate(candidate.source, candidate.destination);
8850
- }
8851
- return {
8852
- assets: Array.from(published.values()).sort(
8853
- (left, right) => left.path.localeCompare(right.path)
8854
- ),
8855
- warnings: warnings.filter(
8856
- (warning, index, all) => all.findIndex(
8857
- (item) => item.kind === warning.kind && item.source === warning.source && item.expressionHash === warning.expressionHash
8858
- ) === index
8859
- ).sort(
8860
- (left, right) => `${left.source}:${left.expressionHash}`.localeCompare(
8861
- `${right.source}:${right.expressionHash}`
8862
- )
8863
- )
8864
- };
8865
- }
8866
- function resolveStaticActionPlugins(projectRoot, configuredPlugins) {
8867
- const projectRequire = createRequire3(path25.join(projectRoot, "package.json"));
8868
- const plugins = [];
8869
- const reasons = [];
8870
- for (const [name, configuredVersion] of Object.entries(
8871
- configuredPlugins
8872
- ).sort(([left], [right]) => left.localeCompare(right))) {
8873
- if (typeof configuredVersion !== "string" || configuredVersion === "") {
8874
- reasons.push(`Action Plugin ${name} has an invalid configured version`);
8875
- continue;
8876
- }
8877
- try {
8878
- const entry = projectRequire.resolve(name);
8879
- const packageRoot = findPackageRoot(entry);
8880
- if (!packageRoot) {
8881
- reasons.push(`Action Plugin package root not found: ${name}`);
8882
- continue;
8883
- }
8884
- const packageJson = JSON.parse(
8885
- fs29.readFileSync(path25.join(packageRoot, "package.json"), "utf8")
8886
- );
8887
- if (packageJson.name !== name) {
8888
- reasons.push(
8889
- `Action Plugin package name mismatch: configured=${name} installed=${packageJson.name ?? "<missing>"}`
8890
- );
8891
- continue;
8892
- }
8893
- if (packageJson.version !== configuredVersion) {
8894
- reasons.push(
8895
- `Action Plugin version mismatch: ${name} configured=${configuredVersion} installed=${packageJson.version ?? "<missing>"}`
8896
- );
8897
- continue;
8898
- }
8899
- const manifestPath = path25.join(packageRoot, "manifest.json");
8900
- if (!fs29.existsSync(manifestPath)) {
8901
- reasons.push(`Action Plugin manifest is missing: ${name}`);
8902
- continue;
8903
- }
8904
- const manifest = JSON.parse(fs29.readFileSync(manifestPath, "utf8"));
8905
- if (manifest.name !== void 0 && manifest.name !== name) {
8906
- reasons.push(
8907
- `Action Plugin manifest name mismatch: configured=${name} manifest=${String(manifest.name)}`
8908
- );
8909
- continue;
8910
- }
8911
- if (manifest.version !== void 0 && manifest.version !== configuredVersion) {
8912
- reasons.push(
8913
- `Action Plugin manifest version mismatch: ${name} configured=${configuredVersion} manifest=${String(manifest.version)}`
8914
- );
8915
- continue;
8916
- }
8917
- plugins.push({ name, version: configuredVersion, entry, manifest });
8918
- } catch (error) {
8919
- reasons.push(
8920
- `Action Plugin cannot be statically resolved: ${name}: ${error instanceof Error ? error.message : String(error)}`
8921
- );
8922
- }
8923
- }
8924
- return { plugins, reasons };
8925
- }
8926
- function staticActionPluginRegistry(projectRoot, plugins, actionPluginProbe) {
8927
- if (plugins.length === 0) {
8928
- return { name: "miaoda-static-action-plugin-registry", setup() {
8929
- } };
8930
- }
8931
- const capabilityEntry = resolveProjectPackage(
8932
- projectRoot,
8933
- "@lark-apaas/nestjs-capability"
8934
- );
8935
- const registryEntries = plugins.map(
8936
- (plugin, index) => `[${JSON.stringify(plugin.name)}, { version: ${JSON.stringify(plugin.version)}, manifest: ${JSON.stringify(plugin.manifest)}, pluginPackage: __miaodaActionPlugin${index} }]`
8937
- ).join(",\n");
8938
- const staticImports = plugins.map(
8939
- (plugin, index) => `const __miaodaActionPlugin${index} = require(${JSON.stringify(plugin.entry)});`
8940
- ).join("\n");
8941
- const contents = `
8942
- const __miaodaCapability = require(${JSON.stringify(capabilityEntry)});
8943
- ${staticImports}
8944
- const __miaodaActionPluginRegistry = new Map([${registryEntries}]);
8945
- const __miaodaActionPluginProbe = ${JSON.stringify(actionPluginProbe ?? null)};
8946
- if (process.env.MIAODA_SERVER_CACHE_PROBE === 'true') {
8947
- for (const [__miaodaPluginKey, __miaodaRegistration] of __miaodaActionPluginRegistry) {
8948
- const __miaodaPluginPackage = __miaodaRegistration.pluginPackage.default ?? __miaodaRegistration.pluginPackage;
8949
- if (typeof __miaodaPluginPackage.create !== 'function') {
8950
- throw new Error('MIAODA_ACTION_PLUGIN_PROBE_CREATE_MISSING:' + __miaodaPluginKey);
8951
- }
8952
- }
8953
- console.error('MIAODA_ACTION_PLUGIN_REGISTRY_OK:' + __miaodaActionPluginRegistry.size);
8954
- }
8955
- if (process.env.MIAODA_SERVER_CACHE_PROBE === 'true' && __miaodaActionPluginProbe) {
8956
- const __miaodaProbeRegistration = __miaodaActionPluginRegistry.get(__miaodaActionPluginProbe.key);
8957
- if (!__miaodaProbeRegistration) {
8958
- throw new Error('MIAODA_ACTION_PLUGIN_PROBE_NOT_REGISTERED:' + __miaodaActionPluginProbe.key);
8959
- }
8960
- const __miaodaProbePackage = __miaodaProbeRegistration.pluginPackage.default ?? __miaodaProbeRegistration.pluginPackage;
8961
- if (typeof __miaodaProbePackage.create !== 'function') {
8962
- throw new Error('MIAODA_ACTION_PLUGIN_PROBE_CREATE_MISSING:' + __miaodaActionPluginProbe.key);
8963
- }
8964
- Promise.resolve(__miaodaProbePackage.create(__miaodaActionPluginProbe.config))
8965
- .then(() => console.error('MIAODA_ACTION_PLUGIN_PROBE_OK:' + __miaodaActionPluginProbe.key))
8966
- .catch(error => {
8967
- console.error('MIAODA_ACTION_PLUGIN_PROBE_FAILED:' + __miaodaActionPluginProbe.key + ':' + (error?.message ?? String(error)));
8968
- process.exitCode = 1;
8969
- });
8970
- }
8971
- const __miaodaPluginLoader = __miaodaCapability.PluginLoaderService;
8972
- if (typeof __miaodaPluginLoader !== 'function') {
8973
- throw new Error('MIAODA_STATIC_ACTION_PLUGIN_REGISTRY_UNSUPPORTED');
8974
- }
8975
- const __miaodaPluginLoaderPrototype = __miaodaPluginLoader.prototype;
8976
- __miaodaPluginLoaderPrototype.getManifest = function getStaticManifest(pluginKey) {
8977
- return __miaodaActionPluginRegistry.get(pluginKey)?.manifest ?? null;
8978
- };
8979
- __miaodaPluginLoaderPrototype.createPluginInstance = async function createStaticPluginInstance(pluginKey, config) {
8980
- const registered = __miaodaActionPluginRegistry.get(pluginKey);
8981
- if (!registered) throw new __miaodaCapability.PluginNotFoundError(pluginKey);
8982
- const pluginPackage = registered.pluginPackage.default ?? registered.pluginPackage;
8983
- if (typeof pluginPackage.create !== 'function') {
8984
- throw new __miaodaCapability.PluginLoadError(pluginKey, 'Plugin does not export create() function');
8985
- }
8986
- return pluginPackage.create(config);
8987
- };
8988
- __miaodaPluginLoaderPrototype.isPluginInstalled = function isStaticPluginInstalled(pluginKey) {
8989
- return __miaodaActionPluginRegistry.has(pluginKey);
8990
- };
8991
- __miaodaPluginLoaderPrototype.clearCache = function clearStaticPluginCache(pluginKey) {
8992
- if (pluginKey) {
8993
- this.pluginInstances?.delete(pluginKey);
8994
- this.manifestCache?.delete(pluginKey);
8995
- return;
8996
- }
8997
- this.pluginInstances?.clear();
8998
- this.manifestCache?.clear();
8999
- };
9000
- module.exports = __miaodaCapability;
9001
- `;
9002
- return {
9003
- name: "miaoda-static-action-plugin-registry",
9004
- setup(esbuild) {
9005
- esbuild.onResolve({ filter: /^@lark-apaas\/nestjs-capability$/ }, () => ({
9006
- path: "@lark-apaas/nestjs-capability",
9007
- namespace: "miaoda-static-action-plugin-registry"
9008
- }));
9009
- esbuild.onLoad(
9010
- {
9011
- filter: /.*/,
9012
- namespace: "miaoda-static-action-plugin-registry"
9013
- },
9014
- () => ({ contents, loader: "js", resolveDir: projectRoot })
9015
- );
9016
- }
9017
- };
9018
- }
9019
- function collectExternalImports(metafile, outfile, projectRoot) {
9020
- const realOutfile = fs29.existsSync(outfile) ? fs29.realpathSync(outfile) : path25.resolve(outfile);
9021
- const output = Object.entries(metafile.outputs).find(([candidate]) => {
9022
- const resolvedCandidate = path25.resolve(projectRoot, candidate);
9023
- return resolvedCandidate === path25.resolve(outfile) || fs29.existsSync(resolvedCandidate) && fs29.realpathSync(resolvedCandidate) === realOutfile;
9024
- })?.[1];
9025
- if (!output) return [];
9026
- const externalImports = new Set(
9027
- output.imports.filter((item) => item.external).map((item) => item.path).filter((item) => !BUILTINS.has(item) && !item.startsWith("node:"))
9028
- );
9029
- if (fs29.existsSync(outfile)) {
9030
- const ast = parseJavaScriptSource(fs29.readFileSync(outfile, "utf8"));
9031
- walkSimple(ast, {
9032
- CallExpression(node) {
9033
- if (staticPropertyName(node.callee) !== "resolve" || node.callee?.type !== "MemberExpression" || node.callee.object?.type !== "Identifier" || !["require", "__require"].includes(node.callee.object.name)) {
9034
- return;
9035
- }
9036
- const specifier = staticStringValue(node.arguments?.[0]);
9037
- if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("#") || BUILTINS.has(specifier) || specifier.startsWith("node:")) {
9038
- return;
9039
- }
9040
- externalImports.add(specifier);
9041
- }
9042
- });
9043
- }
9044
- return Array.from(externalImports).sort();
9045
- }
9046
- function collectBuildOnlyInputs(projectRoot, metafile) {
9047
- return Array.from(
9048
- new Set(
9049
- Object.keys(metafile.inputs).flatMap((input) => {
9050
- const source = canonicalSourcePath(
9051
- projectRoot,
9052
- path25.resolve(projectRoot, input)
9053
- );
9054
- const normalized = `/${source.replace(/^\.\//, "")}/`;
9055
- return BUILD_ONLY_SERVER_CACHE_PACKAGES.filter(
9056
- (packageName) => normalized.includes(`/node_modules/${packageName}/`)
9057
- );
9058
- })
9059
- )
9060
- ).sort();
9061
- }
9062
- function isStaticString(node) {
9063
- if (!node) return false;
9064
- if (node.type === "Literal") return typeof node.value === "string";
9065
- return node.type === "TemplateLiteral" && node.expressions.length === 0;
9066
- }
9067
- function staticPropertyName(node) {
9068
- if (node?.type !== "MemberExpression") return void 0;
9069
- if (!node.computed && node.property.type === "Identifier") {
9070
- return node.property.name;
9071
- }
9072
- if (node.computed && node.property.type === "Literal" && typeof node.property.value === "string") {
9073
- return node.property.value;
9074
- }
9075
- return void 0;
9076
- }
9077
- function collectDynamicImportWarnings(projectRoot, metafile) {
9078
- const warnings = [];
9079
- const sourceInputs = Object.keys(metafile.inputs).filter((input) => /\.(?:cjs|mjs|js)$/.test(input)).sort();
9080
- for (const input of sourceInputs) {
9081
- const sourcePath = path25.resolve(projectRoot, input);
9082
- if (!fs29.existsSync(sourcePath) || !fs29.statSync(sourcePath).isFile()) {
9083
- continue;
9084
- }
9085
- const source = fs29.readFileSync(sourcePath, "utf8");
9086
- const ast = parseJavaScriptSource(source);
9087
- const origin = canonicalSourcePath(projectRoot, sourcePath);
9088
- const fingerprint = (kind, node, message) => {
9089
- const expression = source.slice(node.start, node.end);
9090
- const hash = createHash("sha256").update(expression).digest("hex").slice(0, 16);
9091
- warnings.push({ kind, source: origin, expressionHash: hash, message });
9092
- };
9093
- walkSimple(ast, {
9094
- CallExpression(node) {
9095
- if (node.callee.type === "Identifier" && node.callee.name === "require" && !isStaticString(node.arguments[0])) {
9096
- fingerprint(
9097
- "dynamic-require",
9098
- node,
9099
- "Variable module loading remains in bundle"
9100
- );
9101
- }
9102
- const property = staticPropertyName(node.callee);
9103
- const resolverObject = node.callee.type === "MemberExpression" ? node.callee.object : void 0;
9104
- if (node.callee.type === "Identifier" && node.callee.name === "createRequire") {
9105
- fingerprint(
9106
- "create-require",
9107
- node,
9108
- "Runtime module resolver is created in bundle"
9109
- );
9110
- } else if (property === "resolve" && resolverObject?.type === "Identifier" && resolverObject.name === "require" && !isStaticString(node.arguments[0])) {
9111
- fingerprint(
9112
- "dynamic-require-resolve",
9113
- node,
9114
- "Variable require.resolve target remains in bundle"
9115
- );
9116
- } else if (property === "resolve" && resolverObject?.type === "Identifier" && ["import", "module"].includes(resolverObject.name) && !isStaticString(node.arguments[0])) {
9117
- fingerprint(
9118
- "runtime-module-resolution",
9119
- node,
9120
- "Variable runtime module resolution remains in bundle"
9121
- );
9122
- }
9123
- },
9124
- ImportExpression(node) {
9125
- if (!isStaticString(node.source)) {
9126
- fingerprint(
9127
- "dynamic-import",
9128
- node,
9129
- "Variable dynamic import remains in bundle"
9130
- );
9131
- }
9132
- }
9133
- });
9134
- }
9135
- return warnings.filter(
9136
- (warning, index, all) => all.findIndex(
9137
- (item) => item.kind === warning.kind && item.source === warning.source && item.expressionHash === warning.expressionHash
9138
- ) === index
9139
- ).sort(
9140
- (left, right) => `${left.kind}:${left.source}:${left.expressionHash}`.localeCompare(
9141
- `${right.kind}:${right.source}:${right.expressionHash}`
9142
- )
9143
- );
9144
- }
9145
- async function reservePort() {
9146
- return new Promise((resolve2, reject) => {
9147
- const server = net.createServer();
9148
- server.once("error", reject);
9149
- server.listen(0, "127.0.0.1", () => {
9150
- const address = server.address();
9151
- if (!address || typeof address === "string") {
9152
- server.close(() => reject(new Error("unable to reserve probe port")));
9153
- return;
9154
- }
9155
- server.close((error) => error ? reject(error) : resolve2(address.port));
9156
- });
9157
- });
9158
- }
9159
- function resolveLegacyCapabilityProbe(projectRoot) {
9160
- const capabilitiesRoot = path25.join(projectRoot, "server", "capabilities");
9161
- if (!fs29.existsSync(capabilitiesRoot)) {
9162
- return { files: [], expectedIds: [] };
9163
- }
9164
- const rootStat = fs29.lstatSync(capabilitiesRoot);
9165
- if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
9166
- throw new Error(
9167
- "legacy capability probe directory must be a regular directory"
9168
- );
9169
- }
9170
- const realProjectRoot = fs29.realpathSync(projectRoot);
9171
- const realCapabilitiesRoot = fs29.realpathSync(capabilitiesRoot);
9172
- if (!isPathInside(realProjectRoot, realCapabilitiesRoot)) {
9173
- throw new Error("legacy capability probe directory escaped project root");
9174
- }
9175
- const files = [];
9176
- const expectedIds = [];
9177
- for (const name of fs29.readdirSync(realCapabilitiesRoot).sort()) {
9178
- if (!name.endsWith(".json")) continue;
9179
- const source = path25.join(realCapabilitiesRoot, name);
9180
- const stat = fs29.lstatSync(source);
9181
- if (!stat.isFile() || stat.isSymbolicLink()) {
9182
- throw new Error(`legacy capability probe file is unsafe: ${name}`);
9183
- }
9184
- const parsed = JSON.parse(fs29.readFileSync(source, "utf8"));
9185
- if (typeof parsed.id !== "string" || parsed.id.length === 0) {
9186
- throw new Error(`legacy capability probe file has no id: ${name}`);
9187
- }
9188
- files.push({ source, name });
9189
- expectedIds.push(parsed.id);
9190
- }
9191
- return { files, expectedIds };
9192
- }
9193
- function resolveAvailabilityProbeConfig(projectRoot, configured) {
9194
- if (configured === void 0) {
9195
- const configuredBasePath = process.env.CLIENT_BASE_PATH;
9196
- const basePath = typeof configuredBasePath === "string" && configuredBasePath.startsWith("/") && !configuredBasePath.startsWith("//") ? configuredBasePath : "/";
9197
- const normalizedBasePath = basePath === "/" ? "" : basePath.replace(/\/+$/, "");
9198
- const capabilityPath = `${normalizedBasePath}/__innerapi__/capability/list`;
9199
- return {
9200
- readiness: { path: capabilityPath, expectedStatus: 200 },
9201
- business: {
9202
- path: capabilityPath,
9203
- expectedStatus: 200,
9204
- bodyIncludes: '"status_code":"0"'
9205
- },
9206
- legacyCapabilityProbe: resolveLegacyCapabilityProbe(projectRoot)
9207
- };
9208
- }
9209
- if (!configured?.readiness || !configured.business) {
9210
- throw new Error(
9211
- "miaodaCache.availabilityProbe.readiness and business are required"
9212
- );
9213
- }
9214
- const normalize = (name, value) => {
9215
- const requestPath = value?.path;
9216
- const expectedStatus = value?.expectedStatus;
9217
- if (typeof requestPath !== "string" || !requestPath.startsWith("/") || requestPath.startsWith("//") || !Number.isSafeInteger(expectedStatus) || expectedStatus < 100 || expectedStatus > 599 || value?.bodyIncludes !== void 0 && typeof value.bodyIncludes !== "string") {
9218
- throw new Error(`invalid ${name} availability probe configuration`);
9219
- }
9220
- return {
9221
- path: requestPath,
9222
- expectedStatus,
9223
- ...value?.bodyIncludes ? { bodyIncludes: value.bodyIncludes } : {}
9224
- };
9225
- };
9226
- return {
9227
- readiness: normalize("readiness", configured.readiness),
9228
- business: normalize("business", configured.business)
9229
- };
9230
- }
9231
- function requestHttp(port, request) {
9232
- return new Promise((resolve2, reject) => {
9233
- const clientRequest = http.request(
9234
- {
9235
- host: "127.0.0.1",
9236
- port,
9237
- path: request.path,
9238
- method: "GET",
9239
- timeout: 1e3,
9240
- headers: { connection: "close" }
9241
- },
9242
- (response) => {
9243
- let body = "";
9244
- response.setEncoding("utf8");
9245
- response.on("data", (chunk) => {
9246
- body = `${body}${String(chunk)}`.slice(0, 64 * 1024);
9247
- });
9248
- response.once(
9249
- "end",
9250
- () => resolve2({ status: response.statusCode ?? 0, body })
9251
- );
9252
- }
9253
- );
9254
- clientRequest.once("timeout", () => {
9255
- clientRequest.destroy(new Error("HTTP probe timed out"));
9256
- });
9257
- clientRequest.once("error", reject);
9258
- clientRequest.end();
9259
- });
9260
- }
9261
- function requestMatches(response, request) {
9262
- return response.status === request.expectedStatus && (request.bodyIncludes === void 0 || response.body.includes(request.bodyIncludes));
9263
- }
9264
- async function terminateProcessGroup(child) {
9265
- if (child.exitCode !== null || child.signalCode !== null) return;
9266
- const exited = new Promise(
9267
- (resolve2) => child.once("exit", () => resolve2())
9268
- );
9269
- try {
9270
- child.kill("SIGTERM");
9271
- } catch {
9272
- }
9273
- await Promise.race([
9274
- exited,
9275
- new Promise((resolve2) => setTimeout(resolve2, 500))
9276
- ]);
9277
- if (child.exitCode === null && child.signalCode === null) {
9278
- try {
9279
- process.kill(-child.pid, "SIGKILL");
9280
- } catch {
9281
- child.kill("SIGKILL");
9282
- }
9283
- await exited;
8342
+ };
8343
+ var buildCommandGroup = {
8344
+ name: "build",
8345
+ description: "Build related commands",
8346
+ commands: [getTokenCommand, uploadStaticCommand, preUploadStaticCommand]
8347
+ };
8348
+
8349
+ // src/commands/index.ts
8350
+ var commands = [
8351
+ genDbSchemaCommand,
8352
+ syncCommand,
8353
+ upgradeCommand,
8354
+ actionPluginCommandGroup,
8355
+ capabilityCommandGroup,
8356
+ componentCommandGroup,
8357
+ migrationCommand,
8358
+ readLogsCommand,
8359
+ buildCommandGroup
8360
+ ];
8361
+
8362
+ // src/index.ts
8363
+ for (const filename of [".env.local", ".env"]) {
8364
+ const envPath = path25.join(process.cwd(), filename);
8365
+ if (fs29.existsSync(envPath)) {
8366
+ dotenvConfig({ path: envPath });
9284
8367
  }
9285
8368
  }
9286
- async function runAvailabilityProbe(bundleFile, runtimeAssets, timeoutMs, config, actionPluginCount, actionPluginProbeKey) {
9287
- const probeRoot = fs29.mkdtempSync(
9288
- path25.join(os3.tmpdir(), "server-cache-probe-")
9289
- );
9290
- const isolatedBundle = path25.join(probeRoot, "server.bundle.cjs");
9291
- fs29.copyFileSync(bundleFile, isolatedBundle);
9292
- for (const asset of runtimeAssets) {
9293
- const source = path25.join(
9294
- path25.dirname(bundleFile),
9295
- ...asset.path.split("/")
9296
- );
9297
- const destination = path25.join(probeRoot, ...asset.path.split("/"));
9298
- fs29.mkdirSync(path25.dirname(destination), { recursive: true });
9299
- fs29.copyFileSync(source, destination);
9300
- }
9301
- if (config.legacyCapabilityProbe) {
9302
- const capabilityRoot = path25.join(probeRoot, "server", "capabilities");
9303
- fs29.mkdirSync(capabilityRoot, { recursive: true });
9304
- for (const file of config.legacyCapabilityProbe.files) {
9305
- fs29.copyFileSync(file.source, path25.join(capabilityRoot, file.name));
9306
- }
9307
- }
9308
- const port = await reservePort();
9309
- let stdout = "";
9310
- let stderr = "";
9311
- let responseText = "";
9312
- const checks = [];
9313
- const startedAt = Date.now();
9314
- const child = spawn2(process.execPath, [isolatedBundle], {
9315
- cwd: probeRoot,
9316
- detached: true,
9317
- stdio: ["ignore", "pipe", "pipe"],
9318
- env: {
9319
- ...process.env,
9320
- NODE_PATH: "",
9321
- // The cache bundle serves the development preview. Probe the same module
9322
- // graph instead of forcing production mode, which disables Miaoda's
9323
- // internal capability route and produces a false HTTP 500.
9324
- NODE_ENV: "development",
9325
- SERVER_HOST: "127.0.0.1",
9326
- SERVER_PORT: String(port),
9327
- MIAODA_SERVER_CACHE_PROBE: "true",
9328
- DEPRECATED_SKIP_INIT_DB_CONNECTION: process.env.DEPRECATED_SKIP_INIT_DB_CONNECTION ?? "true",
9329
- FORCE_AUTHN_INNERAPI_DOMAIN: process.env.FORCE_AUTHN_INNERAPI_DOMAIN ?? "http://127.0.0.1",
9330
- FORCE_AUTHN_ACCESS_KEY: process.env.FORCE_AUTHN_ACCESS_KEY ?? "server-cache-probe",
9331
- FORCE_AUTHN_ACCESS_SECRET: process.env.FORCE_AUTHN_ACCESS_SECRET ?? "server-cache-probe"
9332
- }
9333
- });
9334
- child.stdout?.setEncoding("utf8");
9335
- child.stdout?.on("data", (chunk) => {
9336
- stdout = `${stdout}${String(chunk)}`.slice(-8 * 1024);
9337
- });
9338
- child.stderr?.setEncoding("utf8");
9339
- child.stderr?.on("data", (chunk) => {
9340
- stderr = `${stderr}${String(chunk)}`.slice(-8 * 1024);
9341
- });
9342
- try {
9343
- const nodeModulesPresent = fs29.existsSync(
9344
- path25.join(probeRoot, "node_modules")
9345
- );
9346
- checks.push({
9347
- name: "isolated-node-modules",
9348
- success: !nodeModulesPresent,
9349
- message: nodeModulesPresent ? "node_modules unexpectedly exists in isolated probe directory" : "node_modules is absent"
9350
- });
9351
- const runtimeAssetsReadable = runtimeAssets.every((asset) => {
9352
- const file = path25.join(probeRoot, ...asset.path.split("/"));
9353
- return fs29.existsSync(file) && fs29.statSync(file).isFile() && fs29.statSync(file).size === asset.size && createHash("sha256").update(fs29.readFileSync(file)).digest("hex") === asset.sha256;
9354
- });
9355
- checks.push({
9356
- name: "runtime-assets",
9357
- success: runtimeAssetsReadable,
9358
- message: runtimeAssetsReadable ? `${runtimeAssets.length} runtime assets are readable` : "runtime asset integrity check failed in isolated directory"
9359
- });
9360
- let readinessResponse;
9361
- let lastReadinessError = "";
9362
- while (Date.now() - startedAt < timeoutMs && child.exitCode === null && child.signalCode === null) {
9363
- try {
9364
- const response = await requestHttp(port, config.readiness);
9365
- responseText = `${responseText}
9366
- ${response.body}`.slice(-64 * 1024);
9367
- readinessResponse = response;
9368
- if (requestMatches(response, config.readiness)) break;
9369
- lastReadinessError = `unexpected HTTP ${response.status}`;
9370
- } catch (error) {
9371
- lastReadinessError = error instanceof Error ? error.message : String(error);
9372
- }
9373
- await new Promise((resolve2) => setTimeout(resolve2, 25));
9374
- }
9375
- if (child.exitCode !== null || child.signalCode !== null) {
9376
- await new Promise((resolve2) => setTimeout(resolve2, 50));
9377
- }
9378
- const readinessSuccess = Boolean(
9379
- readinessResponse && requestMatches(readinessResponse, config.readiness)
9380
- );
9381
- const startupMs = Date.now() - startedAt;
9382
- checks.push({
9383
- name: "http-readiness",
9384
- success: readinessSuccess,
9385
- path: config.readiness.path,
9386
- status: readinessResponse?.status,
9387
- elapsedMs: startupMs,
9388
- ...!readinessSuccess ? {
9389
- message: child.exitCode !== null ? `process exited before readiness: ${child.exitCode}` : lastReadinessError || "HTTP readiness timed out"
9390
- } : {}
9391
- });
9392
- let businessResponse;
9393
- let businessError = "";
9394
- if (readinessSuccess) {
9395
- try {
9396
- businessResponse = await requestHttp(port, config.business);
9397
- responseText = `${responseText}
9398
- ${businessResponse.body}`.slice(
9399
- -64 * 1024
9400
- );
9401
- } catch (error) {
9402
- businessError = error instanceof Error ? error.message : String(error);
9403
- }
9404
- }
9405
- const businessSuccess = Boolean(
9406
- businessResponse && requestMatches(businessResponse, config.business)
9407
- );
9408
- checks.push({
9409
- name: "business-api",
9410
- success: businessSuccess,
9411
- path: config.business.path,
9412
- status: businessResponse?.status,
9413
- ...!businessSuccess ? {
9414
- message: businessError || (businessResponse ? `expected HTTP ${config.business.expectedStatus}${config.business.bodyIncludes ? ` containing ${JSON.stringify(config.business.bodyIncludes)}` : ""}, received HTTP ${businessResponse.status}` : "business API was not requested because readiness failed")
9415
- } : {}
9416
- });
9417
- if (config.legacyCapabilityProbe) {
9418
- let actualIds = [];
9419
- let capabilityError = "";
9420
- try {
9421
- const payload = JSON.parse(businessResponse?.body ?? "");
9422
- actualIds = (payload.data?.capabilities ?? []).map((capability) => capability.id).filter((id) => typeof id === "string").sort();
9423
- } catch (error) {
9424
- capabilityError = error instanceof Error ? error.message : String(error);
9425
- }
9426
- const expectedIds = [...config.legacyCapabilityProbe.expectedIds].sort();
9427
- const missingIds = expectedIds.filter((id) => !actualIds.includes(id));
9428
- checks.push({
9429
- name: "capability-configs",
9430
- success: businessSuccess && capabilityError.length === 0 && missingIds.length === 0,
9431
- message: capabilityError.length > 0 ? `capability response is invalid JSON: ${capabilityError}` : missingIds.length > 0 ? `capability response missed: ${missingIds.join(", ")}` : `${expectedIds.length} workspace capability configs loaded`
9432
- });
9433
- }
9434
- if (actionPluginCount > 0) {
9435
- const marker = `MIAODA_ACTION_PLUGIN_REGISTRY_OK:${actionPluginCount}`;
9436
- const markerDeadline = Date.now() + Math.min(1e3, timeoutMs);
9437
- while (!stderr.includes(marker) && Date.now() < markerDeadline) {
9438
- await new Promise((resolve2) => setTimeout(resolve2, 10));
9439
- }
9440
- checks.push({
9441
- name: "action-plugin-registry",
9442
- success: stderr.includes(marker),
9443
- message: stderr.includes(marker) ? `${actionPluginCount} static Action Plugin packages registered` : `static Action Plugin registry marker missing: expected ${actionPluginCount}`
9444
- });
9445
- }
9446
- if (actionPluginProbeKey) {
9447
- const marker = `MIAODA_ACTION_PLUGIN_PROBE_OK:${actionPluginProbeKey}`;
9448
- const markerDeadline = Date.now() + Math.min(1e3, timeoutMs);
9449
- while (!stderr.includes(marker) && Date.now() < markerDeadline) {
9450
- await new Promise((resolve2) => setTimeout(resolve2, 10));
9451
- }
9452
- checks.push({
9453
- name: "action-plugin-instantiation",
9454
- success: stderr.includes(marker),
9455
- message: stderr.includes(marker) ? `static Action Plugin instantiated: ${actionPluginProbeKey}` : `static Action Plugin probe marker missing: ${actionPluginProbeKey}`
9456
- });
9457
- }
9458
- await new Promise((resolve2) => setTimeout(resolve2, 25));
9459
- checks.push({
9460
- name: "process-alive",
9461
- success: child.exitCode === null && child.signalCode === null,
9462
- ...child.exitCode !== null ? { message: `process exited with code ${child.exitCode}` } : {}
9463
- });
9464
- const moduleNotFound = /MODULE_NOT_FOUND/.test(
9465
- `${stdout}
9466
- ${stderr}
9467
- ${responseText}`
9468
- );
9469
- checks.push({
9470
- name: "module-resolution",
9471
- success: !moduleNotFound,
9472
- ...moduleNotFound ? { message: "MODULE_NOT_FOUND appeared in stderr or HTTP response" } : {}
9473
- });
9474
- const success = checks.every((check2) => check2.success);
9475
- return {
9476
- success,
9477
- nodeModulesPresent,
9478
- port,
9479
- startupMs,
9480
- checks,
9481
- ...stdout.trim() ? { stdout: stdout.trim() } : {},
9482
- ...stderr.trim() ? { stderr: stderr.trim() } : {}
9483
- };
9484
- } finally {
9485
- await terminateProcessGroup(child);
9486
- fs29.rmSync(probeRoot, { recursive: true, force: true });
9487
- }
9488
- }
9489
- async function buildServerCacheBundle(options) {
9490
- const startedAt = Date.now();
9491
- const projectRoot = path25.resolve(options.projectRoot);
9492
- const outfile = absolute(
9493
- projectRoot,
9494
- options.outfile ?? ".miaoda-cache/server/server.bundle.cjs"
9495
- );
9496
- const metadataFile = absolute(
9497
- projectRoot,
9498
- options.metadataFile ?? `${outfile}.meta.json`
9499
- );
9500
- const fail = (reasons) => ({
9501
- built: false,
9502
- reasons,
9503
- elapsedMs: Date.now() - startedAt
9504
- });
9505
- const outputValidationError = validateOwnedServerOutput(
9506
- projectRoot,
9507
- outfile,
9508
- metadataFile
9509
- );
9510
- if (outputValidationError) return fail([outputValidationError]);
9511
- const serverOutputRoot = path25.dirname(outfile);
9512
- fs29.rmSync(serverOutputRoot, { recursive: true, force: true });
9513
- const resolvedEntry = resolveCompiledEntry(projectRoot, options.entry);
9514
- if (!resolvedEntry.entry) return fail(resolvedEntry.reasons);
9515
- const entry = resolvedEntry.entry;
9516
- if (outfile === entry || metadataFile === entry || outfile === metadataFile) {
9517
- return fail(["bundle output conflicts with an input or metadata file"]);
9518
- }
9519
- const packageJsonPath = path25.join(projectRoot, "package.json");
9520
- if (!fs29.existsSync(packageJsonPath)) {
9521
- return fail([`package.json missing: ${packageJsonPath}`]);
9522
- }
9523
- const packageJson = JSON.parse(fs29.readFileSync(packageJsonPath, "utf8"));
9524
- let availabilityProbeConfig;
9525
- try {
9526
- availabilityProbeConfig = resolveAvailabilityProbeConfig(
9527
- projectRoot,
9528
- packageJson.miaodaCache?.availabilityProbe
9529
- );
9530
- } catch (error) {
9531
- return fail([error instanceof Error ? error.message : String(error)]);
9532
- }
9533
- const actionPluginResolution = resolveStaticActionPlugins(
9534
- projectRoot,
9535
- packageJson.actionPlugins ?? {}
9536
- );
9537
- if (actionPluginResolution.reasons.length > 0) {
9538
- return fail(actionPluginResolution.reasons);
9539
- }
9540
- const actionPlugins = actionPluginResolution.plugins;
9541
- const configuredActionPluginProbe = packageJson.miaodaCache?.actionPluginProbe;
9542
- const actionPluginProbe = configuredActionPluginProbe === void 0 ? void 0 : typeof configuredActionPluginProbe.key === "string" && configuredActionPluginProbe.key ? {
9543
- key: configuredActionPluginProbe.key,
9544
- config: configuredActionPluginProbe.config
9545
- } : null;
9546
- if (actionPluginProbe === null) {
9547
- return fail(["Action Plugin probe key is invalid"]);
9548
- }
9549
- if (actionPluginProbe && !actionPlugins.some((plugin) => plugin.name === actionPluginProbe.key)) {
9550
- return fail([
9551
- `Action Plugin probe is not configured in actionPlugins: ${actionPluginProbe.key}`
9552
- ]);
9553
- }
9554
- fs29.mkdirSync(path25.dirname(serverOutputRoot), { recursive: true });
9555
- const tempRoot = fs29.mkdtempSync(
9556
- path25.join(path25.dirname(serverOutputRoot), ".server-build-")
9557
- );
9558
- const tempOutfile = path25.join(tempRoot, "server.bundle.cjs");
9559
- try {
9560
- const result = await build({
9561
- absWorkingDir: projectRoot,
9562
- entryPoints: [entry],
9563
- outfile: tempOutfile,
9564
- bundle: true,
9565
- platform: "node",
9566
- format: "cjs",
9567
- target: "node22",
9568
- treeShaking: true,
9569
- keepNames: true,
9570
- legalComments: "none",
9571
- sourcemap: false,
9572
- metafile: true,
9573
- logLevel: "silent",
9574
- define: {
9575
- "import.meta.url": "__miaoda_server_cache_import_meta_url__"
9576
- },
9577
- banner: {
9578
- js: 'const __miaoda_server_cache_import_meta_url__ = require("node:url").pathToFileURL(__filename).href;'
9579
- },
9580
- plugins: [
9581
- rejectNativeAddonsPlugin(),
9582
- fullstackNestRuntimeResolver(projectRoot),
9583
- legacyFullstackNestOpenApiStub(projectRoot),
9584
- staticActionPluginRegistry(
9585
- projectRoot,
9586
- actionPlugins,
9587
- actionPluginProbe ?? void 0
9588
- ),
9589
- classTransformerStorageResolver(projectRoot),
9590
- optionalDependencyStubPlugin()
9591
- ]
9592
- });
9593
- if (!result.metafile) return fail(["esbuild metafile missing"]);
9594
- for (const warning of result.warnings) {
9595
- console.warn(
9596
- `[server-cache-bundle] WARN ${JSON.stringify({
9597
- kind: "esbuild-warning",
9598
- message: warning.text,
9599
- location: warning.location
9600
- })}`
9601
- );
9602
- }
9603
- const nativeInputs = Object.keys(result.metafile.inputs).filter(
9604
- (input) => input.endsWith(".node")
9605
- );
9606
- if (nativeInputs.length > 0) {
9607
- return fail([
9608
- `native addons are unsupported: ${nativeInputs.join(", ")}`
9609
- ]);
9610
- }
9611
- const externalImports = collectExternalImports(
9612
- result.metafile,
9613
- tempOutfile,
9614
- projectRoot
9615
- );
9616
- if (externalImports.length > 0) {
9617
- return fail([`external imports remain: ${externalImports.join(", ")}`]);
9618
- }
9619
- const buildOnlyInputs = collectBuildOnlyInputs(
9620
- projectRoot,
9621
- result.metafile
9622
- );
9623
- if (buildOnlyInputs.length > 0) {
9624
- return fail([
9625
- `build-only packages entered server cache bundle: ${buildOnlyInputs.join(", ")}`
9626
- ]);
9627
- }
9628
- const configuredRuntimeAssets = [
9629
- ...packageJson.miaodaCache?.runtimeAssets ?? [],
9630
- ...availabilityProbeConfig.legacyCapabilityProbe?.files.length ? [
9631
- {
9632
- source: "server/capabilities",
9633
- path: "server/capabilities"
9634
- }
9635
- ] : []
9636
- ];
9637
- const materializedRuntimeAssets = materializeServerRuntimeAssets(
9638
- projectRoot,
9639
- result.metafile,
9640
- tempRoot,
9641
- configuredRuntimeAssets
9642
- );
9643
- const runtimeAssets = materializedRuntimeAssets.assets;
9644
- const runtimeAssetWarnings = materializedRuntimeAssets.warnings;
9645
- const dynamicImportWarnings = collectDynamicImportWarnings(
9646
- projectRoot,
9647
- result.metafile
9648
- );
9649
- for (const warning of [...dynamicImportWarnings, ...runtimeAssetWarnings]) {
9650
- console.warn(`[server-cache-bundle] WARN ${JSON.stringify(warning)}`);
9651
- }
9652
- const availabilityProbe = await runAvailabilityProbe(
9653
- tempOutfile,
9654
- runtimeAssets,
9655
- options.probeTimeoutMs ?? 3e4,
9656
- availabilityProbeConfig,
9657
- actionPlugins.length,
9658
- actionPluginProbe?.key
9659
- );
9660
- if (!availabilityProbe.success || availabilityProbe.nodeModulesPresent) {
9661
- return fail([
9662
- "isolated node_modules-free availability probe failed",
9663
- ...availabilityProbe.checks.filter((check2) => !check2.success).map(
9664
- (check2) => `${check2.name}: ${check2.message ?? `HTTP ${check2.status ?? "unavailable"}`}`
9665
- ),
9666
- ...availabilityProbe.stderr ? [availabilityProbe.stderr] : [],
9667
- ...availabilityProbe.stdout ? [availabilityProbe.stdout] : []
9668
- ]);
9669
- }
9670
- const bundleSha256 = createHash("sha256").update(fs29.readFileSync(tempOutfile)).digest("hex");
9671
- const sealedAvailabilityProbe = {
9672
- success: availabilityProbe.success,
9673
- nodeModulesPresent: availabilityProbe.nodeModulesPresent,
9674
- startupMs: availabilityProbe.startupMs,
9675
- checks: availabilityProbe.checks,
9676
- ...availabilityProbe.stderr ? { stderr: availabilityProbe.stderr } : {}
9677
- };
9678
- const metadata = {
9679
- schemaVersion: 2,
9680
- entry: path25.relative(projectRoot, entry).split(path25.sep).join("/"),
9681
- outfile: "server/server.bundle.cjs",
9682
- nodeVersion: process.version,
9683
- nodeModuleAbi: process.versions.modules,
9684
- platform: process.platform,
9685
- arch: process.arch,
9686
- bundleBytes: fs29.statSync(tempOutfile).size,
9687
- bundleSha256,
9688
- inputFiles: Object.keys(result.metafile.inputs).length,
9689
- workspaceSourceSha256: workspaceSourceSha256(projectRoot),
9690
- externalImports,
9691
- dynamicImportWarnings,
9692
- runtimeAssetWarnings,
9693
- actionPlugins: actionPlugins.map(({ name, version }) => ({
9694
- name,
9695
- version
9696
- })),
9697
- runtimeAssets,
9698
- availabilityProbe: sealedAvailabilityProbe,
9699
- consumable: true
9700
- };
9701
- fs29.writeFileSync(
9702
- path25.join(tempRoot, path25.basename(metadataFile)),
9703
- `${JSON.stringify(metadata, null, 2)}
9704
- `
9705
- );
9706
- fs29.mkdirSync(path25.dirname(serverOutputRoot), { recursive: true });
9707
- fs29.renameSync(tempRoot, serverOutputRoot);
9708
- return {
9709
- built: true,
9710
- outfile,
9711
- metadataFile,
9712
- bundleBytes: metadata.bundleBytes,
9713
- inputFiles: metadata.inputFiles,
9714
- externalImports,
9715
- dynamicImportWarnings,
9716
- runtimeAssetWarnings,
9717
- runtimeAssets,
9718
- actionPlugins: actionPlugins.map(({ name, version }) => ({
9719
- name,
9720
- version
9721
- })),
9722
- availabilityProbe,
9723
- reasons: [],
9724
- elapsedMs: Date.now() - startedAt
9725
- };
9726
- } catch (error) {
9727
- fs29.rmSync(serverOutputRoot, { recursive: true, force: true });
9728
- return fail([error instanceof Error ? error.message : String(error)]);
9729
- } finally {
9730
- fs29.rmSync(tempRoot, { recursive: true, force: true });
9731
- }
9732
- }
9733
-
9734
- // src/commands/build/app-runtime-manifest.handler.ts
9735
- import fs31 from "fs";
9736
- import path27 from "path";
9737
-
9738
- // src/client-dependency-graph.ts
9739
- import crypto from "crypto";
9740
- import fs30 from "fs";
9741
- import path26 from "path";
9742
- import { builtinModules as builtinModules2 } from "module";
9743
- import { Node as Node11, Project as Project4, SyntaxKind as SyntaxKind7 } from "ts-morph";
9744
- var BUILTIN_MODULES = /* @__PURE__ */ new Set([
9745
- ...builtinModules2,
9746
- ...builtinModules2.map((name) => `node:${name}`)
9747
- ]);
9748
- var SOURCE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
9749
- var STYLE_EXTENSIONS = [
9750
- ".css",
9751
- ".less",
9752
- ".sass",
9753
- ".scss",
9754
- ".styl",
9755
- ".stylus"
9756
- ];
9757
- function packageNameFromSpecifier(specifier) {
9758
- if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\0") || specifier.includes("://") || BUILTIN_MODULES.has(specifier)) {
9759
- return void 0;
9760
- }
9761
- const parts = specifier.split("/");
9762
- return specifier.startsWith("@") ? parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0 : parts[0];
9763
- }
9764
- function isStyleSpecifier(specifier) {
9765
- return STYLE_EXTENSIONS.some(
9766
- (extension) => new RegExp(`\\${extension}(?:$|\\?)`, "i").test(specifier)
9767
- );
9768
- }
9769
- function resolveLocalFile(specifier, importer, projectRoot, clientRoot) {
9770
- let candidate;
9771
- if (specifier.startsWith("@/")) {
9772
- candidate = path26.join(clientRoot, "src", specifier.slice(2));
9773
- } else if (specifier.startsWith("@client/")) {
9774
- candidate = path26.join(clientRoot, specifier.slice("@client/".length));
9775
- } else if (specifier.startsWith("@shared/")) {
9776
- candidate = path26.join(
9777
- projectRoot,
9778
- "shared",
9779
- specifier.slice("@shared/".length)
9780
- );
9781
- } else if (specifier.startsWith(".") || path26.isAbsolute(specifier)) {
9782
- candidate = path26.resolve(path26.dirname(importer), specifier);
9783
- }
9784
- if (!candidate) return void 0;
9785
- const projectRelative = path26.relative(projectRoot, path26.resolve(candidate));
9786
- if (projectRelative === ".." || projectRelative.startsWith(`..${path26.sep}`) || path26.isAbsolute(projectRelative)) {
9787
- throw new Error(
9788
- `MIAODA_CLIENT_SOURCE_PATH_ESCAPE: ${specifier} from ${path26.relative(
9789
- projectRoot,
9790
- importer
9791
- )}`
9792
- );
9793
- }
9794
- const extensions = [...SOURCE_EXTENSIONS, ...STYLE_EXTENSIONS];
9795
- const candidates = [
9796
- candidate,
9797
- ...extensions.map((extension) => `${candidate}${extension}`),
9798
- ...extensions.map((extension) => path26.join(candidate, `index${extension}`))
9799
- ];
9800
- const resolvedFile = candidates.find((file) => {
9801
- try {
9802
- return fs30.statSync(file).isFile();
9803
- } catch {
9804
- return false;
9805
- }
9806
- });
9807
- if (!resolvedFile) return void 0;
9808
- const realProjectRoot = fs30.realpathSync(projectRoot);
9809
- const realFile = fs30.realpathSync(resolvedFile);
9810
- const relative = path26.relative(realProjectRoot, realFile);
9811
- if (relative === ".." || relative.startsWith(`..${path26.sep}`) || path26.isAbsolute(relative)) {
9812
- throw new Error(`MIAODA_CLIENT_SOURCE_SYMLINK_ESCAPE: ${resolvedFile}`);
9813
- }
9814
- return resolvedFile;
9815
- }
9816
- function discoverClientSpecifiers(projectRoot, scanAllSourceFiles = false) {
9817
- const clientRoot = fs30.existsSync(path26.join(projectRoot, "client")) ? path26.join(projectRoot, "client") : projectRoot;
9818
- if (!fs30.existsSync(path26.join(clientRoot, "src"))) {
9819
- return { specifiers: [], optimizeDependencies: [] };
9820
- }
9821
- const project = new Project4({
9822
- skipAddingFilesFromTsConfig: true,
9823
- compilerOptions: { allowJs: true, jsx: 2 }
9824
- });
9825
- const specifiers = /* @__PURE__ */ new Set();
9826
- const optimizeDependencies = /* @__PURE__ */ new Set();
9827
- const pending = SOURCE_EXTENSIONS.map(
9828
- (extension) => path26.join(clientRoot, "src", `index${extension}`)
9829
- ).filter((file) => fs30.existsSync(file));
9830
- if (scanAllSourceFiles) {
9831
- const visit = (directory) => {
9832
- for (const entry of fs30.readdirSync(directory, { withFileTypes: true })) {
9833
- const file = path26.join(directory, entry.name);
9834
- if (entry.isSymbolicLink()) {
9835
- throw new Error(`MIAODA_CLIENT_SOURCE_SYMLINK_REJECTED: ${file}`);
9836
- }
9837
- if (entry.isDirectory()) visit(file);
9838
- else if (entry.isFile() && [...SOURCE_EXTENSIONS, ...STYLE_EXTENSIONS].includes(
9839
- path26.extname(file)
9840
- )) {
9841
- pending.push(file);
9842
- }
9843
- }
9844
- };
9845
- visit(path26.join(clientRoot, "src"));
9846
- }
9847
- const visited = /* @__PURE__ */ new Set();
9848
- const addBare = (specifier, optimize) => {
9849
- if (!packageNameFromSpecifier(specifier)) return;
9850
- specifiers.add(specifier);
9851
- if (optimize) optimizeDependencies.add(specifier);
9852
- };
9853
- const traverse = (specifier, importer, optimize = true) => {
9854
- const dependency = resolveLocalFile(
9855
- specifier,
9856
- importer,
9857
- projectRoot,
9858
- clientRoot
9859
- );
9860
- if (dependency) pending.push(dependency);
9861
- else addBare(specifier, optimize && !isStyleSpecifier(specifier));
9862
- };
9863
- while (pending.length > 0) {
9864
- const sourcePath = path26.resolve(pending.pop());
9865
- if (visited.has(sourcePath)) continue;
9866
- visited.add(sourcePath);
9867
- if (STYLE_EXTENSIONS.includes(path26.extname(sourcePath))) {
9868
- const css = fs30.readFileSync(sourcePath, "utf8");
9869
- for (const match of css.matchAll(
9870
- /@(import|plugin)\s+(?:url\(\s*)?["']([^"']+)["']/g
9871
- )) {
9872
- traverse(match[2], sourcePath, false);
9873
- }
9874
- for (const match of css.matchAll(/@source\s+["']([^"']+)["']/g)) {
9875
- const marker = /(?:^|[\\/])node_modules[\\/]((?:@[^\\/]+[\\/])?[^\\/*?{}]+)/.exec(
9876
- match[1]
9877
- );
9878
- if (marker) addBare(marker[1].replace(/\\/g, "/"), false);
9879
- }
9880
- continue;
9881
- }
9882
- const sourceFile = project.addSourceFileAtPath(sourcePath);
9883
- for (const declaration of sourceFile.getImportDeclarations()) {
9884
- if (declaration.isTypeOnly()) continue;
9885
- const namedImports = declaration.getNamedImports();
9886
- const hasRuntimeBinding = Boolean(declaration.getDefaultImport()) || Boolean(declaration.getNamespaceImport()) || namedImports.length === 0 || namedImports.some((specifier) => !specifier.isTypeOnly());
9887
- if (hasRuntimeBinding) {
9888
- traverse(declaration.getModuleSpecifierValue(), sourcePath);
9889
- }
9890
- }
9891
- for (const declaration of sourceFile.getExportDeclarations()) {
9892
- if (declaration.isTypeOnly()) continue;
9893
- const namedExports = declaration.getNamedExports();
9894
- const specifier = declaration.getModuleSpecifierValue();
9895
- if (specifier && (namedExports.length === 0 || namedExports.some((namedExport) => !namedExport.isTypeOnly()))) {
9896
- traverse(specifier, sourcePath);
9897
- }
9898
- }
9899
- for (const call of sourceFile.getDescendantsOfKind(
9900
- SyntaxKind7.CallExpression
9901
- )) {
9902
- const expression = call.getExpression();
9903
- const isDynamicImport = expression.getKind() === SyntaxKind7.ImportKeyword;
9904
- const isRequire = Node11.isIdentifier(expression) && expression.getText() === "require";
9905
- if (!isDynamicImport && !isRequire) continue;
9906
- const argument = call.getArguments()[0];
9907
- if (!argument || !Node11.isStringLiteral(argument)) {
9908
- throw new Error(
9909
- `MIAODA_CLIENT_DYNAMIC_DEPENDENCY_UNSUPPORTED: ${path26.relative(
9910
- projectRoot,
9911
- sourcePath
9912
- )}:${call.getStartLineNumber()}`
9913
- );
9914
- }
9915
- traverse(argument.getLiteralValue(), sourcePath);
9916
- }
9917
- }
9918
- return {
9919
- specifiers: [...specifiers].sort(),
9920
- optimizeDependencies: [...optimizeDependencies].sort()
9921
- };
9922
- }
9923
- function parentPackagePath(packagePath) {
9924
- const nestedMarker = packagePath.lastIndexOf("/node_modules/");
9925
- if (nestedMarker >= 0) return packagePath.slice(0, nestedMarker);
9926
- return packagePath.startsWith("node_modules/") ? "" : void 0;
9927
- }
9928
- function resolveLockedPackagePath(packages, fromPackagePath, packageName) {
9929
- let current = fromPackagePath;
9930
- while (current !== void 0) {
9931
- const candidate = current ? `${current}/node_modules/${packageName}` : `node_modules/${packageName}`;
9932
- if (packages[candidate]?.version) return candidate;
9933
- current = current ? parentPackagePath(current) : void 0;
9934
- }
9935
- return void 0;
9936
- }
9937
- function canonicalize(value) {
9938
- return JSON.stringify(value);
9939
- }
9940
- function clientConfigFiles(projectRoot) {
9941
- const fixedNames = [
9942
- "vite.config.ts",
9943
- "vite.config.mts",
9944
- "vite.config.js",
9945
- "vite.config.mjs",
9946
- "vite.config.cjs",
9947
- "postcss.config.js",
9948
- "postcss.config.cjs",
9949
- "postcss.config.mjs",
9950
- "tailwind.config.ts",
9951
- "tailwind.config.js",
9952
- "tailwind.config.cjs",
9953
- "tailwind.config.mjs",
9954
- "tsconfig.json",
9955
- "tsconfig.app.json",
9956
- "tsconfig.node.json",
9957
- ".env",
9958
- ".env.development",
9959
- ".env.development.local"
9960
- ];
9961
- const pending = fixedNames.map((name) => path26.join(projectRoot, name));
9962
- for (const patchRootName of ["patches", ".yarn/patches"]) {
9963
- const patchRoot = path26.join(projectRoot, patchRootName);
9964
- if (!fs30.existsSync(patchRoot)) continue;
9965
- const visit = (directory) => {
9966
- for (const entry of fs30.readdirSync(directory, { withFileTypes: true })) {
9967
- const file = path26.join(directory, entry.name);
9968
- if (entry.isSymbolicLink()) {
9969
- throw new Error(`MIAODA_CLIENT_CONFIG_SYMLINK_REJECTED: ${file}`);
9970
- }
9971
- if (entry.isDirectory()) visit(file);
9972
- else if (entry.isFile()) pending.push(file);
9973
- }
9974
- };
9975
- visit(patchRoot);
9976
- }
9977
- const visited = /* @__PURE__ */ new Set();
9978
- const result = [];
9979
- const resolveRelativeConfig = (specifier, importer) => {
9980
- if (!specifier.startsWith(".")) return void 0;
9981
- const candidate = path26.resolve(path26.dirname(importer), specifier);
9982
- const candidates = [
9983
- candidate,
9984
- ...[...SOURCE_EXTENSIONS, ".json"].map(
9985
- (extension) => `${candidate}${extension}`
9986
- ),
9987
- ...[...SOURCE_EXTENSIONS, ".json"].map(
9988
- (extension) => path26.join(candidate, `index${extension}`)
9989
- )
9990
- ];
9991
- return candidates.find((file) => {
9992
- const relative = path26.relative(projectRoot, file);
9993
- return relative !== ".." && !relative.startsWith(`..${path26.sep}`) && !path26.isAbsolute(relative) && fs30.existsSync(file) && fs30.statSync(file).isFile();
9994
- });
9995
- };
9996
- while (pending.length > 0) {
9997
- const file = path26.resolve(pending.pop());
9998
- if (visited.has(file) || !fs30.existsSync(file) || !fs30.statSync(file).isFile()) {
9999
- continue;
10000
- }
10001
- visited.add(file);
10002
- const content = fs30.readFileSync(file);
10003
- result.push({
10004
- path: path26.relative(projectRoot, file),
10005
- sha256: crypto.createHash("sha256").update(content).digest("hex")
10006
- });
10007
- if (SOURCE_EXTENSIONS.includes(path26.extname(file))) {
10008
- const source = content.toString("utf8");
10009
- for (const match of source.matchAll(
10010
- /(?:from\s*|import\s*\(|require\s*\()\s*["']([^"']+)["']/g
10011
- )) {
10012
- const dependency = resolveRelativeConfig(match[1], file);
10013
- if (dependency) pending.push(dependency);
10014
- }
10015
- } else if (path26.extname(file) === ".json") {
10016
- try {
10017
- const json = JSON.parse(content.toString("utf8"));
10018
- for (const specifier of [
10019
- json.extends,
10020
- ...(json.references ?? []).map((reference) => reference.path)
10021
- ]) {
10022
- if (!specifier) continue;
10023
- const dependency = resolveRelativeConfig(specifier, file);
10024
- if (dependency) pending.push(dependency);
10025
- }
10026
- } catch {
10027
- }
10028
- }
10029
- }
10030
- return result.sort((left, right) => left.path.localeCompare(right.path));
10031
- }
10032
- function clientConfigEnvironment() {
10033
- const names = [
10034
- "APP_FLAGS",
10035
- "ASSETS_CDN_PATH",
10036
- "BUILD_TOOL",
10037
- "CLIENT_BASE_PATH",
10038
- "DISABLE_INSPECTOR",
10039
- "FORCE_FRAMEWORK_BUILD_LOOSE_MODE",
10040
- "FORCE_FRAMEWORK_DOMAIN_MAIN",
10041
- "FORCE_FRAMEWORK_ENVIRONMENT",
10042
- "MIAODA_APP_ARCH_TYPE",
10043
- "MIAODA_APP_SOURCE",
10044
- "MIAODA_APP_TYPE",
10045
- "MIAODA_FONTS_MIRROR_OFF",
10046
- "NEED_ROUTES",
10047
- "STATIC_ASSETS_BASE_URL",
10048
- "__API_ROUTE_DEFINITIONS__",
10049
- "__PAGE_ROUTE_DEFINITIONS__"
10050
- ];
10051
- return Object.fromEntries(
10052
- names.map((name) => [
10053
- name,
10054
- crypto.createHash("sha256").update(process.env[name] ?? "").digest("hex")
10055
- ])
10056
- );
10057
- }
10058
- function installedDependencyLockFile(projectRoot) {
10059
- const hiddenLock = path26.join(
10060
- projectRoot,
10061
- "node_modules",
10062
- ".package-lock.json"
10063
- );
10064
- if (fs30.existsSync(hiddenLock)) {
10065
- if (fs30.lstatSync(hiddenLock).isSymbolicLink() || !fs30.statSync(hiddenLock).isFile()) {
10066
- throw new Error("MIAODA_NPM_HIDDEN_PACKAGE_LOCK_INVALID");
10067
- }
10068
- return hiddenLock;
10069
- }
10070
- return path26.join(projectRoot, "package-lock.json");
10071
- }
10072
- function buildClientDependencyGraph(options) {
10073
- const projectRoot = path26.resolve(options.projectRoot);
10074
- const packageLockFile = installedDependencyLockFile(projectRoot);
10075
- const lock = JSON.parse(
10076
- fs30.readFileSync(packageLockFile, "utf8")
10077
- );
10078
- if (!lock.packages || (lock.lockfileVersion ?? 0) < 2) {
10079
- throw new Error("MIAODA_NPM_PACKAGE_LOCK_V2_REQUIRED");
10080
- }
10081
- const discovery = discoverClientSpecifiers(
10082
- projectRoot,
10083
- options.includeAllProductionDependencies === true
10084
- );
10085
- if (options.includeAllProductionDependencies) {
10086
- const packageJson = JSON.parse(
10087
- fs30.readFileSync(path26.join(projectRoot, "package.json"), "utf8")
10088
- );
10089
- for (const specifier of Object.keys(packageJson.dependencies ?? {})) {
10090
- if (!lock.packages[`node_modules/${specifier}`]?.version) continue;
10091
- if (!discovery.specifiers.includes(specifier)) {
10092
- discovery.specifiers.push(specifier);
10093
- }
10094
- }
10095
- }
10096
- const implicitSpecifiers = [
10097
- "react",
10098
- "react-dom",
10099
- "react/jsx-runtime",
10100
- "react/jsx-dev-runtime",
10101
- "clsx",
10102
- "echarts",
10103
- "echarts-for-react",
10104
- "@lark-apaas/client-toolkit/runtime",
10105
- ...process.env.DISABLE_INSPECTOR === "true" ? [] : ["@lark-apaas/miaoda-inspector"]
10106
- ];
10107
- for (const specifier of implicitSpecifiers) {
10108
- const packageName = packageNameFromSpecifier(specifier);
10109
- if (lock.packages[`node_modules/${packageName}`]?.version && !discovery.specifiers.includes(specifier)) {
10110
- discovery.specifiers.push(specifier);
10111
- discovery.optimizeDependencies.push(specifier);
10112
- }
10113
- }
10114
- discovery.specifiers.sort();
10115
- discovery.optimizeDependencies.sort();
10116
- const entries = discovery.specifiers.map((specifier) => {
10117
- const packageName = packageNameFromSpecifier(specifier);
10118
- const packagePath = resolveLockedPackagePath(
10119
- lock.packages,
10120
- "",
10121
- packageName
10122
- );
10123
- if (!packagePath) {
10124
- throw new Error(`MIAODA_CLIENT_DEPENDENCY_LOCK_MISSING: ${specifier}`);
10125
- }
10126
- return { specifier, packagePath };
10127
- });
10128
- const pending = [...new Set(entries.map((entry) => entry.packagePath))];
10129
- const graphPackages = /* @__PURE__ */ new Map();
10130
- while (pending.length > 0) {
10131
- const packagePath = pending.pop();
10132
- if (graphPackages.has(packagePath)) continue;
10133
- const lockedPackage = lock.packages[packagePath];
10134
- if (!lockedPackage?.version) {
10135
- throw new Error(`MIAODA_CLIENT_DEPENDENCY_LOCK_MISSING: ${packagePath}`);
10136
- }
10137
- const edges = {};
10138
- const addEdge = (name, required) => {
10139
- const resolvedPath = resolveLockedPackagePath(
10140
- lock.packages,
10141
- packagePath,
10142
- name
10143
- );
10144
- if (!resolvedPath) {
10145
- if (required) {
10146
- throw new Error(
10147
- `MIAODA_CLIENT_DEPENDENCY_EDGE_MISSING: ${packagePath} -> ${name}`
10148
- );
10149
- }
10150
- return;
10151
- }
10152
- edges[name] = resolvedPath;
10153
- pending.push(resolvedPath);
10154
- };
10155
- for (const name of Object.keys(lockedPackage.dependencies ?? {}).sort()) {
10156
- addEdge(name, true);
10157
- }
10158
- for (const name of Object.keys(
10159
- lockedPackage.optionalDependencies ?? {}
10160
- ).sort()) {
10161
- addEdge(name, false);
10162
- }
10163
- for (const name of Object.keys(
10164
- lockedPackage.peerDependencies ?? {}
10165
- ).sort()) {
10166
- addEdge(
10167
- name,
10168
- lockedPackage.peerDependenciesMeta?.[name]?.optional !== true
10169
- );
10170
- }
10171
- graphPackages.set(packagePath, {
10172
- path: packagePath,
10173
- version: lockedPackage.version,
10174
- integrity: lockedPackage.integrity ?? null,
10175
- edges: Object.fromEntries(
10176
- Object.entries(edges).sort(
10177
- ([left], [right]) => left.localeCompare(right)
10178
- )
10179
- )
10180
- });
10181
- }
10182
- const graph = {
10183
- schemaVersion: 1,
10184
- algorithm: "npm-installed-client-closure-v2",
10185
- runtimeAbiHash: options.runtimeAbiHash,
10186
- resolveConditions: ["browser", "development", "module", "import"],
10187
- configFiles: clientConfigFiles(projectRoot),
10188
- configEnvironment: clientConfigEnvironment(),
10189
- entries,
10190
- packages: [...graphPackages.values()].sort(
10191
- (left, right) => left.path.localeCompare(right.path)
10192
- )
10193
- };
10194
- return {
10195
- graph,
10196
- hash: crypto.createHash("sha256").update(canonicalize(graph)).digest("hex"),
10197
- optimizeDependencies: discovery.optimizeDependencies
10198
- };
10199
- }
10200
-
10201
- // src/commands/build/app-runtime-manifest.handler.ts
10202
- var VITE_PRESETS = [
10203
- "@lark-apaas/coding-preset-vite-react",
10204
- "@lark-apaas/coding-vite-preset",
10205
- "@lark-apaas/fullstack-vite-preset"
10206
- ];
10207
- function detectApplicationRuntime(projectRoot, packageJson) {
10208
- const features = packageJson?.mclaw?.features;
10209
- const declaredPackages = {
10210
- ...packageJson?.dependencies ?? {},
10211
- ...packageJson?.devDependencies ?? {}
10212
- };
10213
- const usesCodingVitePreset = VITE_PRESETS.slice(0, 2).some(
10214
- (name) => declaredPackages[name] !== void 0
10215
- );
10216
- const hasServerRuntime = packageJson?.scripts?.["dev:server"] !== void 0 || declaredPackages["@nestjs/core"] !== void 0 || fs31.existsSync(path27.join(projectRoot, "server", "main.ts")) || fs31.existsSync(path27.join(projectRoot, "server", "src", "main.ts"));
10217
- const hasClientOnlyMetadata = Array.isArray(features) && features.includes("client") && !features.includes("server");
10218
- const applicationKind = !hasServerRuntime && (hasClientOnlyMetadata || usesCodingVitePreset) ? "frontend-only" : "fullstack";
10219
- const vitePreset = VITE_PRESETS.find((name) => declaredPackages[name] !== void 0) ?? "@lark-apaas/fullstack-vite-preset";
10220
- const entryCandidates = [
10221
- "client/src/index.tsx",
10222
- "client/src/main.tsx",
10223
- "src/index.tsx",
10224
- "src/main.tsx"
10225
- ];
10226
- const clientEntry = entryCandidates.find(
10227
- (relativePath) => fs31.existsSync(path27.join(projectRoot, relativePath))
10228
- );
10229
- if (!clientEntry) {
10230
- throw new Error("client entry missing");
10231
- }
10232
- return {
10233
- applicationKind,
10234
- vitePreset,
10235
- clientRoot: clientEntry.startsWith("client/") ? "client" : ".",
10236
- clientEntry
10237
- };
10238
- }
10239
- function buildAppRuntimeManifest(options) {
10240
- const projectRoot = path27.resolve(options.projectRoot);
10241
- const outfile = path27.resolve(
10242
- projectRoot,
10243
- options.outfile ?? ".miaoda-cache/app-runtime.json"
10244
- );
10245
- const runtimeManifestFile = path27.isAbsolute(options.runtimeManifestFile) ? options.runtimeManifestFile : path27.resolve(projectRoot, options.runtimeManifestFile);
10246
- const requiredFiles = [
10247
- path27.join(projectRoot, "package.json"),
10248
- path27.join(projectRoot, "package-lock.json"),
10249
- runtimeManifestFile
10250
- ];
10251
- fs31.rmSync(outfile, { force: true });
10252
- const missing = requiredFiles.filter((file) => !fs31.existsSync(file));
10253
- if (missing.length > 0) {
10254
- return {
10255
- built: false,
10256
- reasons: missing.map((file) => `input missing: ${file}`)
10257
- };
10258
- }
10259
- try {
10260
- const packageJson = JSON.parse(
10261
- fs31.readFileSync(path27.join(projectRoot, "package.json"), "utf8")
10262
- );
10263
- const runtime = JSON.parse(
10264
- fs31.readFileSync(runtimeManifestFile, "utf8")
10265
- );
10266
- if (runtime.schemaVersion !== 1 || !runtime.runtimeAbiHash) {
10267
- return {
10268
- built: false,
10269
- reasons: ["unsupported platform runtime manifest"]
10270
- };
10271
- }
10272
- const applicationRuntime = detectApplicationRuntime(
10273
- projectRoot,
10274
- packageJson
10275
- );
10276
- const client = buildClientDependencyGraph({
10277
- projectRoot,
10278
- runtimeAbiHash: runtime.runtimeAbiHash,
10279
- includeAllProductionDependencies: applicationRuntime.applicationKind === "frontend-only"
10280
- });
10281
- const manifest = {
10282
- schemaVersion: 1,
10283
- runtimeAbiHash: runtime.runtimeAbiHash,
10284
- ...applicationRuntime,
10285
- clientDependencyGraphHash: client.hash,
10286
- clientDependencyGraph: client.graph,
10287
- optimizeDependencies: client.optimizeDependencies
10288
- };
10289
- fs31.mkdirSync(path27.dirname(outfile), { recursive: true });
10290
- const temporaryFile = `${outfile}.${process.pid}.${Date.now()}.tmp`;
10291
- fs31.writeFileSync(temporaryFile, `${JSON.stringify(manifest, null, 2)}
10292
- `);
10293
- fs31.renameSync(temporaryFile, outfile);
10294
- return {
10295
- built: true,
10296
- outfile,
10297
- runtimeAbiHash: runtime.runtimeAbiHash,
10298
- ...applicationRuntime,
10299
- clientDependencyGraphHash: client.hash,
10300
- clientDependencyGraph: client.graph,
10301
- optimizeDependencies: client.optimizeDependencies,
10302
- reasons: []
10303
- };
10304
- } catch (error) {
10305
- fs31.rmSync(outfile, { force: true });
10306
- return {
10307
- built: false,
10308
- reasons: [error instanceof Error ? error.message : String(error)]
10309
- };
10310
- }
10311
- }
10312
-
10313
- // src/commands/build/cache-generation.handler.ts
10314
- import crypto2 from "crypto";
10315
- import fs32 from "fs";
10316
- import path28 from "path";
10317
- function sha256(file) {
10318
- return crypto2.createHash("sha256").update(fs32.readFileSync(file)).digest("hex");
10319
- }
10320
- function listRegularFiles(root) {
10321
- const files = [];
10322
- const visit = (directory) => {
10323
- for (const entry of fs32.readdirSync(directory, { withFileTypes: true })) {
10324
- const file = path28.join(directory, entry.name);
10325
- if (entry.isSymbolicLink()) {
10326
- throw new Error(`vite cache symlink is not supported: ${file}`);
10327
- }
10328
- if (entry.isDirectory()) {
10329
- visit(file);
10330
- } else if (entry.isFile()) {
10331
- files.push(file);
10332
- }
10333
- }
10334
- };
10335
- visit(root);
10336
- return files.sort();
10337
- }
10338
- var WORKSPACE_SOURCE_ROOTS = ["client", "server", "shared", "src"];
10339
- var WORKSPACE_SOURCE_FILES = [
10340
- ".env",
10341
- ".env.development",
10342
- ".env.development.local",
10343
- "drizzle.config.ts",
10344
- "nest-cli.json",
10345
- "postcss.config.js",
10346
- "postcss.config.cjs",
10347
- "postcss.config.mjs",
10348
- "tailwind.config.ts",
10349
- "tailwind.config.js",
10350
- "tailwind.config.cjs",
10351
- "tailwind.config.mjs",
10352
- "tsconfig.json",
10353
- "tsconfig.app.json",
10354
- "tsconfig.node.json",
10355
- "vite.config.ts",
10356
- "vite.config.mts",
10357
- "vite.config.js",
10358
- "vite.config.mjs",
10359
- "vite.config.cjs"
10360
- ];
10361
- function listWorkspaceSourceFiles(projectRoot) {
10362
- const files = WORKSPACE_SOURCE_ROOTS.flatMap((relativeRoot) => {
10363
- const root = path28.join(projectRoot, relativeRoot);
10364
- return fs32.existsSync(root) ? listRegularFiles(root) : [];
10365
- });
10366
- for (const relativeFile of WORKSPACE_SOURCE_FILES) {
10367
- const file = path28.join(projectRoot, relativeFile);
10368
- if (!fs32.existsSync(file)) continue;
10369
- if (fs32.lstatSync(file).isSymbolicLink() || !fs32.statSync(file).isFile()) {
10370
- throw new Error(`workspace source file is invalid: ${file}`);
10371
- }
10372
- files.push(file);
10373
- }
10374
- return [...new Set(files)].sort().map((file) => ({
10375
- path: path28.relative(projectRoot, file).split(path28.sep).join("/"),
10376
- sha256: sha256(file),
10377
- size: fs32.statSync(file).size
10378
- }));
10379
- }
10380
- function canonicalJson(value) {
10381
- if (Array.isArray(value)) return value.map(canonicalJson);
10382
- if (value && typeof value === "object") {
10383
- return Object.fromEntries(
10384
- Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, canonicalJson(child)])
10385
- );
10386
- }
10387
- return value;
10388
- }
10389
- function workspaceBuildInputs(projectRoot) {
10390
- const packageJsonFile = path28.join(projectRoot, "package.json");
10391
- const packageJson = fs32.existsSync(packageJsonFile) ? JSON.parse(fs32.readFileSync(packageJsonFile, "utf8")) : {};
10392
- return {
10393
- // Dependency versions deliberately remain governed by the recursive
10394
- // client graph and bundled server artifact. Only package.json fields that
10395
- // directly change bundle construction belong in this source binding.
10396
- actionPlugins: canonicalJson(packageJson.actionPlugins ?? {})
10397
- };
10398
- }
10399
- function packageNameFromOptimizerId(id) {
10400
- const specifier = id.split(" > ").at(-1) ?? id;
10401
- if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\0") || specifier.includes("://")) {
10402
- return void 0;
10403
- }
10404
- const parts = specifier.split("/");
10405
- return specifier.startsWith("@") ? parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0 : parts[0];
10406
- }
10407
- function isPathInside2(root, candidate) {
10408
- const relative = path28.relative(root, candidate);
10409
- return relative === "" || !relative.startsWith("..") && !path28.isAbsolute(relative);
10410
- }
10411
- function isCanonicalRelativeAssetPath(candidate) {
10412
- return typeof candidate === "string" && candidate.length > 0 && candidate === path28.posix.normalize(candidate) && candidate !== "." && !candidate.startsWith("../") && !path28.posix.isAbsolute(candidate) && !candidate.includes("\\");
10413
- }
10414
- function optimizerEntryUsesRuntimePackage(options) {
10415
- const variants = options.runtime.packages?.[options.packageName];
10416
- if (!Array.isArray(variants) || variants.length === 0) return false;
10417
- if (typeof options.entry?.src !== "string" || !options.entry.src)
10418
- return false;
10419
- const source = path28.isAbsolute(options.entry.src) ? options.entry.src : path28.resolve(options.projectRoot, options.entry.src);
10420
- if (!fs32.existsSync(source)) return false;
10421
- const realSource = fs32.realpathSync(source);
10422
- const runtimeRoot = path28.dirname(path28.resolve(options.runtimeManifestFile));
10423
- return variants.some((variant) => {
10424
- if (typeof variant.relativePath !== "string" || !variant.relativePath) {
10425
- return false;
10426
- }
10427
- const packageRoot = path28.resolve(runtimeRoot, variant.relativePath);
10428
- if (!isPathInside2(runtimeRoot, packageRoot) || !fs32.existsSync(packageRoot)) {
10429
- return false;
10430
- }
10431
- return isPathInside2(fs32.realpathSync(packageRoot), realSource);
10432
- });
10433
- }
10434
- var REQUIRED_SERVER_PROBE_CHECKS = [
10435
- "isolated-node-modules",
10436
- "runtime-assets",
10437
- "http-readiness",
10438
- "business-api",
10439
- "process-alive",
10440
- "module-resolution"
10441
- ];
10442
- function serverMetadataIsConsumable(serverMetadata) {
10443
- const warningsAreValid = Array.isArray(serverMetadata?.dynamicImportWarnings) && serverMetadata.dynamicImportWarnings.every(
10444
- (warning) => typeof warning?.kind === "string" && typeof warning?.source === "string" && /^[a-f0-9]{16}$/.test(warning?.expressionHash ?? "") && typeof warning?.message === "string"
10445
- );
10446
- const runtimeAssetWarningsAreValid = Array.isArray(serverMetadata?.runtimeAssetWarnings) && serverMetadata.runtimeAssetWarnings.every(
10447
- (warning) => typeof warning?.kind === "string" && typeof warning?.source === "string" && /^[a-f0-9]{16}$/.test(warning?.expressionHash ?? "") && typeof warning?.message === "string"
10448
- );
10449
- const actionPluginsAreValid = Array.isArray(serverMetadata?.actionPlugins) && serverMetadata.actionPlugins.every(
10450
- (plugin) => typeof plugin?.name === "string" && plugin.name.length > 0 && typeof plugin?.version === "string" && plugin.version.length > 0
10451
- );
10452
- const checks = serverMetadata?.availabilityProbe?.checks;
10453
- const checkNames = Array.isArray(checks) ? checks.map((check2) => check2?.name) : [];
10454
- const checksAreValid = Array.isArray(checks) && checks.every(
10455
- (check2) => typeof check2?.name === "string" && check2?.success === true
10456
- ) && new Set(checkNames).size === checkNames.length && REQUIRED_SERVER_PROBE_CHECKS.every((name) => checkNames.includes(name)) && (serverMetadata.actionPlugins?.length === 0 || checkNames.includes("action-plugin-registry"));
10457
- return serverMetadata?.schemaVersion === 2 && serverMetadata?.consumable === true && serverMetadata?.availabilityProbe?.success === true && serverMetadata?.availabilityProbe?.nodeModulesPresent === false && checksAreValid && warningsAreValid && runtimeAssetWarningsAreValid && actionPluginsAreValid && Array.isArray(serverMetadata?.runtimeAssets) && Array.isArray(serverMetadata?.externalImports) && serverMetadata.externalImports.length === 0;
10458
- }
10459
- function stableServerMetadataIdentity(serverMetadata) {
10460
- const availabilityProbe = serverMetadata?.availabilityProbe ?? {};
10461
- const checks = Array.isArray(availabilityProbe.checks) ? availabilityProbe.checks.map((check2) => {
10462
- const { elapsedMs: _elapsedMs, ...stableCheck } = check2;
10463
- return stableCheck;
10464
- }) : availabilityProbe.checks;
10465
- const {
10466
- startupMs: _startupMs,
10467
- stdout: _stdout,
10468
- stderr: _stderr,
10469
- ...stableProbe
10470
- } = availabilityProbe;
10471
- return canonicalJson({
10472
- ...serverMetadata,
10473
- availabilityProbe: { ...stableProbe, checks }
10474
- });
10475
- }
10476
- function serverDependenciesAreConsumable(serverDependencies) {
10477
- if (serverDependencies?.schemaVersion !== 1 || typeof serverDependencies?.sourceEntry !== "string" || serverDependencies.sourceEntry.length === 0 || typeof serverDependencies?.compiledEntry !== "string" || serverDependencies.compiledEntry.length === 0 || !Array.isArray(serverDependencies?.bootstrapModules) || serverDependencies.bootstrapModules.length === 0 || !Array.isArray(serverDependencies?.packages) || serverDependencies.packages.length === 0 || !Array.isArray(serverDependencies?.actionPlugins) || !Array.isArray(serverDependencies?.files) || serverDependencies.files.length === 0 || !/^[a-f0-9]{64}$/.test(serverDependencies?.treeSha256 ?? "") || serverDependencies.fileCount !== serverDependencies.files.length || !Number.isSafeInteger(serverDependencies.totalBytes) || serverDependencies.totalBytes <= 0) {
10478
- return false;
10479
- }
10480
- const packageRecordsAreValid = (packages) => packages.every(
10481
- (pkg2) => typeof pkg2?.name === "string" && pkg2.name.length > 0 && typeof pkg2?.version === "string" && pkg2.version.length > 0
10482
- );
10483
- const paths = /* @__PURE__ */ new Set();
10484
- const filesAreValid = serverDependencies.files.every((file) => {
10485
- if (!isCanonicalRelativeAssetPath(file?.path) || !/^[a-f0-9]{64}$/.test(file?.sha256 ?? "") || !Number.isSafeInteger(file?.size) || file.size < 0 || paths.has(file.path)) {
10486
- return false;
10487
- }
10488
- paths.add(file.path);
10489
- return true;
10490
- });
10491
- const expectedTreeSha256 = crypto2.createHash("sha256").update(JSON.stringify(serverDependencies.files)).digest("hex");
10492
- return packageRecordsAreValid(serverDependencies.packages) && packageRecordsAreValid(serverDependencies.actionPlugins) && filesAreValid && expectedTreeSha256 === serverDependencies.treeSha256 && serverDependencies.files.reduce(
10493
- (total, file) => total + file.size,
10494
- 0
10495
- ) === serverDependencies.totalBytes;
10496
- }
10497
- function sealCacheGeneration(options) {
10498
- const artifactScope = options.artifactScope ?? "all";
10499
- if (artifactScope !== "all" && artifactScope !== "server") {
10500
- return {
10501
- sealed: false,
10502
- reasons: [`unsupported artifact scope: ${options.artifactScope}`]
10503
- };
10504
- }
10505
- const includeViteArtifacts = artifactScope === "all";
10506
- const projectRoot = path28.resolve(options.projectRoot);
10507
- const cacheRoot = path28.resolve(
10508
- projectRoot,
10509
- options.cacheRoot ?? ".miaoda-cache"
10510
- );
10511
- const outfile = path28.resolve(
10512
- projectRoot,
10513
- options.outfile ?? path28.join(cacheRoot, "generation.json")
10514
- );
10515
- const runtimeManifestFile = path28.isAbsolute(options.runtimeManifestFile) ? options.runtimeManifestFile : path28.resolve(projectRoot, options.runtimeManifestFile);
10516
- const files = {
10517
- serverBundle: path28.join(cacheRoot, "server", "server.bundle.cjs"),
10518
- serverMetadata: path28.join(
10519
- cacheRoot,
10520
- "server",
10521
- "server.bundle.cjs.meta.json"
10522
- ),
10523
- serverDependencies: path28.join(
10524
- cacheRoot,
10525
- "server",
10526
- "dependencies.json"
10527
- ),
10528
- appRuntime: path28.join(cacheRoot, "app-runtime.json"),
10529
- viteMetadata: path28.join(cacheRoot, "vite", "deps", "_metadata.json")
10530
- };
10531
- const viteRoot = path28.join(cacheRoot, "vite");
10532
- fs32.rmSync(outfile, { force: true });
10533
- const baseInputs = [
10534
- runtimeManifestFile,
10535
- files.appRuntime,
10536
- ...includeViteArtifacts ? [files.viteMetadata] : []
10537
- ];
10538
- const missingBaseInputs = baseInputs.filter((file) => !fs32.existsSync(file));
10539
- if (missingBaseInputs.length > 0) {
10540
- return {
10541
- sealed: false,
10542
- reasons: missingBaseInputs.map(
10543
- (file) => `cache generation input missing: ${file}`
10544
- )
10545
- };
10546
- }
10547
- let applicationKind;
10548
- try {
10549
- const appRuntime = JSON.parse(fs32.readFileSync(files.appRuntime, "utf8"));
10550
- applicationKind = appRuntime.applicationKind === "frontend-only" ? "frontend-only" : "fullstack";
10551
- } catch (error) {
10552
- return {
10553
- sealed: false,
10554
- reasons: [error instanceof Error ? error.message : String(error)]
10555
- };
10556
- }
10557
- if (artifactScope === "server" && applicationKind === "frontend-only") {
10558
- return {
10559
- sealed: false,
10560
- reasons: ["server-scoped cache generation requires a fullstack application"]
10561
- };
10562
- }
10563
- const hasServerDependencies = fs32.existsSync(files.serverDependencies);
10564
- const serverFiles = hasServerDependencies ? [files.serverDependencies, path28.join(cacheRoot, "server", "node_modules")] : [files.serverBundle, files.serverMetadata];
10565
- const missing = (applicationKind === "fullstack" ? serverFiles : []).filter(
10566
- (file) => !fs32.existsSync(file)
10567
- );
10568
- if (missing.length > 0) {
10569
- return {
10570
- sealed: false,
10571
- reasons: missing.map((file) => `cache generation input missing: ${file}`)
10572
- };
10573
- }
10574
- try {
10575
- const runtime = JSON.parse(fs32.readFileSync(runtimeManifestFile, "utf8"));
10576
- const appRuntime = JSON.parse(fs32.readFileSync(files.appRuntime, "utf8"));
10577
- const viteMetadata = includeViteArtifacts ? JSON.parse(fs32.readFileSync(files.viteMetadata, "utf8")) : void 0;
10578
- const serverMetadata = applicationKind === "fullstack" && !hasServerDependencies ? JSON.parse(fs32.readFileSync(files.serverMetadata, "utf8")) : void 0;
10579
- const serverDependencies = applicationKind === "fullstack" && hasServerDependencies ? JSON.parse(fs32.readFileSync(files.serverDependencies, "utf8")) : void 0;
10580
- const reasons = [];
10581
- const serverRuntimeAssetFiles = [];
10582
- if (runtime.schemaVersion !== 1 || !runtime.runtimeAbiHash) {
10583
- reasons.push("unsupported platform runtime manifest");
10584
- }
10585
- if (appRuntime.schemaVersion !== 1 || appRuntime.runtimeAbiHash !== runtime.runtimeAbiHash) {
10586
- reasons.push("application/runtime ABI mismatch");
10587
- }
10588
- if (!/^[a-f0-9]{64}$/.test(appRuntime.clientDependencyGraphHash ?? "") || appRuntime.clientDependencyGraph?.schemaVersion !== 1 || appRuntime.clientDependencyGraph?.runtimeAbiHash !== runtime.runtimeAbiHash) {
10589
- reasons.push("application client dependency graph is invalid");
10590
- }
10591
- if (applicationKind === "fullstack" && hasServerDependencies && !serverDependenciesAreConsumable(serverDependencies)) {
10592
- reasons.push("server runtime dependency metadata is not consumable");
10593
- }
10594
- if (applicationKind === "fullstack" && !hasServerDependencies && !serverMetadataIsConsumable(serverMetadata)) {
10595
- reasons.push("server cache metadata is not consumable");
10596
- }
10597
- if (applicationKind === "fullstack" && !hasServerDependencies && sha256(files.serverBundle) !== serverMetadata.bundleSha256) {
10598
- reasons.push("server bundle SHA-256 mismatch");
10599
- }
10600
- if (applicationKind === "fullstack" && !hasServerDependencies && !Array.isArray(serverMetadata.runtimeAssets)) {
10601
- reasons.push("server runtime asset manifest is missing");
10602
- } else if (applicationKind === "fullstack" && !hasServerDependencies) {
10603
- const runtimeAssetPaths = /* @__PURE__ */ new Set();
10604
- for (const asset of serverMetadata.runtimeAssets) {
10605
- if (!isCanonicalRelativeAssetPath(asset?.path)) {
10606
- reasons.push(`server runtime asset path is invalid: ${asset?.path}`);
10607
- continue;
10608
- }
10609
- if (runtimeAssetPaths.has(asset.path)) {
10610
- reasons.push(
10611
- `server runtime asset path is duplicated: ${asset.path}`
10612
- );
10613
- continue;
10614
- }
10615
- runtimeAssetPaths.add(asset.path);
10616
- const file = path28.join(cacheRoot, "server", ...asset.path.split("/"));
10617
- if (!fs32.existsSync(file) || !fs32.statSync(file).isFile()) {
10618
- reasons.push(`server runtime asset is missing: ${asset.path}`);
10619
- continue;
10620
- }
10621
- const actualSha256 = sha256(file);
10622
- const actualSize = fs32.statSync(file).size;
10623
- if (asset.sha256 !== actualSha256 || asset.size !== actualSize) {
10624
- reasons.push(
10625
- `server runtime asset integrity mismatch: ${asset.path}`
10626
- );
10627
- continue;
10628
- }
10629
- serverRuntimeAssetFiles.push({
10630
- key: `serverRuntimeAsset:${asset.path}`,
10631
- file,
10632
- path: asset.path
10633
- });
10634
- }
10635
- }
10636
- if (applicationKind === "fullstack" && hasServerDependencies) {
10637
- const nodeModulesRoot = path28.join(cacheRoot, "server", "node_modules");
10638
- const actualFiles = listRegularFiles(nodeModulesRoot).map((file) => ({
10639
- path: path28.relative(nodeModulesRoot, file).split(path28.sep).join("/"),
10640
- sha256: sha256(file),
10641
- size: fs32.statSync(file).size
10642
- })).sort((left, right) => left.path.localeCompare(right.path));
10643
- if (JSON.stringify(actualFiles) !== JSON.stringify(serverDependencies.files)) {
10644
- reasons.push("server runtime dependency file set or integrity mismatch");
10645
- }
10646
- const currentActionPlugins = workspaceBuildInputs(projectRoot).actionPlugins;
10647
- const cachedActionPlugins = Object.fromEntries(
10648
- serverDependencies.actionPlugins.map(
10649
- (plugin) => [
10650
- plugin.name,
10651
- plugin.version
10652
- ]
10653
- )
10654
- );
10655
- if (JSON.stringify(currentActionPlugins) !== JSON.stringify(canonicalJson(cachedActionPlugins))) {
10656
- reasons.push("server runtime ActionPlugin dependency mismatch");
10657
- }
10658
- }
10659
- if (includeViteArtifacts && viteMetadata) {
10660
- const optimizedDependencies = new Set(
10661
- Object.keys(viteMetadata.optimized ?? {})
10662
- );
10663
- const missingViteDependencies = Array.from(
10664
- new Set(appRuntime.optimizeDependencies ?? [])
10665
- ).filter((specifier) => !optimizedDependencies.has(specifier));
10666
- if (missingViteDependencies.length > 0) {
10667
- reasons.push(
10668
- `vite cache dependency coverage missing: ${missingViteDependencies.join(", ")}`
10669
- );
10670
- }
10671
- }
10672
- if (includeViteArtifacts && viteMetadata) {
10673
- const graphPackageNames = new Set(
10674
- (appRuntime.clientDependencyGraph?.entries ?? []).map(
10675
- (entry) => packageNameFromOptimizerId(entry.specifier ?? "")
10676
- ).filter(Boolean)
10677
- );
10678
- const optimizerEntries = [
10679
- ...Object.entries(viteMetadata.optimized ?? {}),
10680
- ...Object.entries(viteMetadata.discovered ?? {})
10681
- ];
10682
- const uncoveredOptimizerPackages = Array.from(
10683
- new Set(
10684
- optimizerEntries.flatMap(([id, entry]) => {
10685
- const name = packageNameFromOptimizerId(id);
10686
- if (!name || graphPackageNames.has(name)) return [];
10687
- return optimizerEntryUsesRuntimePackage({
10688
- projectRoot,
10689
- runtimeManifestFile,
10690
- runtime,
10691
- packageName: name,
10692
- entry
10693
- }) ? [] : [name];
10694
- })
10695
- )
10696
- ).sort();
10697
- if (uncoveredOptimizerPackages.length > 0) {
10698
- reasons.push(
10699
- `vite optimizer graph/toolchain coverage missing: ${uncoveredOptimizerPackages.join(", ")}`
10700
- );
10701
- }
10702
- }
10703
- if (reasons.length > 0) return { sealed: false, reasons };
10704
- const artifactFiles = {
10705
- appRuntime: files.appRuntime,
10706
- ...includeViteArtifacts ? { viteMetadata: files.viteMetadata } : {},
10707
- ...applicationKind === "fullstack" ? hasServerDependencies ? { serverDependencies: files.serverDependencies } : {
10708
- serverBundle: files.serverBundle,
10709
- serverMetadata: files.serverMetadata
10710
- } : {}
10711
- };
10712
- const artifacts = Object.fromEntries([
10713
- ...Object.entries(artifactFiles).map(([name, file]) => [
10714
- name,
10715
- {
10716
- path: path28.relative(cacheRoot, file),
10717
- sha256: sha256(file),
10718
- size: fs32.statSync(file).size
10719
- }
10720
- ]),
10721
- ...serverRuntimeAssetFiles.map((asset) => [
10722
- asset.key,
10723
- {
10724
- path: path28.posix.join("server", asset.path),
10725
- sha256: sha256(asset.file),
10726
- size: fs32.statSync(asset.file).size
10727
- }
10728
- ])
10729
- ]);
10730
- const viteFiles = includeViteArtifacts ? listRegularFiles(viteRoot).map((file) => ({
10731
- path: path28.relative(cacheRoot, file),
10732
- sha256: sha256(file),
10733
- size: fs32.statSync(file).size
10734
- })) : void 0;
10735
- if (includeViteArtifacts && viteFiles && viteFiles.length === 0) {
10736
- return { sealed: false, reasons: ["vite cache is empty"] };
10737
- }
10738
- const stableMetadata = applicationKind === "fullstack" && !hasServerDependencies ? JSON.stringify(stableServerMetadataIdentity(serverMetadata)) : void 0;
10739
- const serverMetadataIdentity = stableMetadata ? {
10740
- sha256: crypto2.createHash("sha256").update(stableMetadata).digest("hex"),
10741
- size: Buffer.byteLength(stableMetadata)
10742
- } : void 0;
10743
- const serverDependencyFiles = applicationKind === "fullstack" && hasServerDependencies ? listRegularFiles(path28.join(cacheRoot, "server")).map((file) => ({
10744
- path: path28.relative(cacheRoot, file).split(path28.sep).join("/"),
10745
- sha256: sha256(file),
10746
- size: fs32.statSync(file).size
10747
- })) : void 0;
10748
- const identity = {
10749
- schemaVersion: hasServerDependencies ? 4 : 3,
10750
- runtimeAbiHash: runtime.runtimeAbiHash,
10751
- applicationKind,
10752
- ...applicationKind === "fullstack" ? {
10753
- serverRuntime: {
10754
- nodeVersion: (serverDependencies ?? serverMetadata).nodeVersion,
10755
- nodeModuleAbi: (serverDependencies ?? serverMetadata).nodeModuleAbi,
10756
- platform: (serverDependencies ?? serverMetadata).platform,
10757
- arch: (serverDependencies ?? serverMetadata).arch
10758
- },
10759
- ...hasServerDependencies ? {
10760
- serverRuntimeMode: "workspace-source-dependencies",
10761
- serverFiles: serverDependencyFiles
10762
- } : {}
10763
- } : {},
10764
- artifacts,
10765
- ...serverMetadataIdentity ? { serverMetadataIdentity } : {},
10766
- ...viteFiles ? { viteFiles } : {},
10767
- ...hasServerDependencies ? {} : { sourceFiles: listWorkspaceSourceFiles(projectRoot) },
10768
- workspaceBuildInputs: workspaceBuildInputs(projectRoot)
10769
- };
10770
- const generationIdentity = serverMetadataIdentity ? {
10771
- ...identity,
10772
- artifacts: {
10773
- ...identity.artifacts,
10774
- serverMetadata: {
10775
- ...identity.artifacts.serverMetadata,
10776
- ...serverMetadataIdentity
10777
- }
10778
- }
10779
- } : identity;
10780
- const generationId = crypto2.createHash("sha256").update(JSON.stringify(generationIdentity)).digest("hex");
10781
- fs32.mkdirSync(path28.dirname(outfile), { recursive: true });
10782
- const tempFile = `${outfile}.${process.pid}.${Date.now()}.tmp`;
10783
- fs32.writeFileSync(
10784
- tempFile,
10785
- `${JSON.stringify({ ...identity, generationId }, null, 2)}
10786
- `
10787
- );
10788
- fs32.renameSync(tempFile, outfile);
10789
- return { sealed: true, outfile, generationId, reasons: [] };
10790
- } catch (error) {
10791
- fs32.rmSync(outfile, { force: true });
10792
- return {
10793
- sealed: false,
10794
- reasons: [error instanceof Error ? error.message : String(error)]
10795
- };
10796
- }
10797
- }
10798
-
10799
- // src/commands/build/index.ts
10800
- var getTokenCommand = {
10801
- name: "get-token",
10802
- description: "Get artifact upload credential (STI token)",
10803
- register(program) {
10804
- program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").requiredOption("--scene <scene>", "Build scene (pipeline, static)").option("--commit-id <id>", "Git commit ID (required for pipeline scene)").action(
10805
- async (options) => {
10806
- await getToken(options);
10807
- }
10808
- );
10809
- }
10810
- };
10811
- var uploadStaticCommand = {
10812
- name: "upload-static",
10813
- description: "Upload shared/static files to TOS",
10814
- register(program) {
10815
- program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").option(
10816
- "--static-dir <dir>",
10817
- "Static files directory",
10818
- UPLOAD_STATIC_DEFAULTS.staticDir
10819
- ).option(
10820
- "--tosutil-path <path>",
10821
- "Path to tosutil binary",
10822
- UPLOAD_STATIC_DEFAULTS.tosutilPath
10823
- ).option(
10824
- "--endpoint <endpoint>",
10825
- "TOS endpoint",
10826
- UPLOAD_STATIC_DEFAULTS.endpoint
10827
- ).option("--region <region>", "TOS region", UPLOAD_STATIC_DEFAULTS.region).action(async (options) => {
10828
- await uploadStatic(options);
10829
- });
10830
- }
10831
- };
10832
- var preUploadStaticCommand = {
10833
- name: "pre-upload-static",
10834
- description: "Get TOS upload info and output as env vars for build.sh eval",
10835
- register(program) {
10836
- program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").action(async (options) => {
10837
- await preUploadStatic(options);
10838
- });
10839
- }
10840
- };
10841
- var serverCacheBundleCommand = {
10842
- name: "server-cache-bundle",
10843
- description: "Build and probe a node_modules-free single-file NestJS cache bundle",
10844
- register(program) {
10845
- program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).option(
10846
- "--entry <file>",
10847
- "Compiled Nest entry (auto-detects dist/server/main.js or dist/main.js)"
10848
- ).option(
10849
- "--outfile <file>",
10850
- "Output bundle",
10851
- ".miaoda-cache/server/server.bundle.cjs"
10852
- ).option("--metadata-file <file>", "Output metadata file").action(
10853
- async (options) => {
10854
- const result = await buildServerCacheBundle(options);
10855
- console.log(JSON.stringify(result));
10856
- if (!result.built) process.exitCode = 2;
10857
- }
10858
- );
10859
- }
10860
- };
10861
- var appRuntimeManifestCommand = {
10862
- name: "app-runtime-manifest",
10863
- description: "Freeze the browser dependency closure used by cache-only Vite",
10864
- register(program) {
10865
- program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).requiredOption(
10866
- "--runtime-manifest-file <file>",
10867
- "Image platform runtime manifest"
10868
- ).option("--outfile <file>", "Application runtime manifest output").action(
10869
- (options) => {
10870
- const result = buildAppRuntimeManifest(options);
10871
- console.log(JSON.stringify(result));
10872
- if (!result.built) process.exitCode = 2;
10873
- }
10874
- );
10875
- }
10876
- };
10877
- var cacheGenerationCommand = {
10878
- name: "cache-generation",
10879
- description: "Seal Vite, Nest and runtime manifests into one immutable cache generation",
10880
- register(program) {
10881
- program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).requiredOption(
10882
- "--runtime-manifest-file <file>",
10883
- "Image platform runtime manifest"
10884
- ).option("--cache-root <dir>", "Cache root", ".miaoda-cache").option("--outfile <file>", "Generation manifest output").option(
10885
- "--artifact-scope <scope>",
10886
- "Sealed artifact scope: all (Vite + Nest) or server (Nest only)",
10887
- "all"
10888
- ).action(
10889
- (options) => {
10890
- const result = sealCacheGeneration({
10891
- ...options,
10892
- artifactScope: options.artifactScope
10893
- });
10894
- console.log(JSON.stringify(result));
10895
- if (!result.sealed) process.exitCode = 2;
10896
- }
10897
- );
10898
- }
10899
- };
10900
- var buildCommandGroup = {
10901
- name: "build",
10902
- description: "Build related commands",
10903
- commands: [
10904
- getTokenCommand,
10905
- uploadStaticCommand,
10906
- preUploadStaticCommand,
10907
- serverCacheBundleCommand,
10908
- appRuntimeManifestCommand,
10909
- cacheGenerationCommand
10910
- ]
10911
- };
10912
-
10913
- // src/commands/index.ts
10914
- var commands = [
10915
- genDbSchemaCommand,
10916
- syncCommand,
10917
- upgradeCommand,
10918
- actionPluginCommandGroup,
10919
- capabilityCommandGroup,
10920
- componentCommandGroup,
10921
- migrationCommand,
10922
- readLogsCommand,
10923
- buildCommandGroup
10924
- ];
10925
-
10926
- // src/utils/workspace-env.ts
10927
- import fs33 from "fs";
10928
- import path29 from "path";
10929
- import { config as dotenvConfig } from "dotenv";
10930
- function loadWorkspaceEnv(cwd = process.cwd(), targetEnv = process.env) {
10931
- if (targetEnv.FULLSTACK_CLI_SKIP_DOTENV === "1") {
10932
- return;
10933
- }
10934
- for (const filename of [".env.local", ".env"]) {
10935
- const envPath = path29.join(cwd, filename);
10936
- if (fs33.existsSync(envPath)) {
10937
- dotenvConfig({ path: envPath, processEnv: targetEnv });
10938
- }
10939
- }
10940
- }
10941
-
10942
- // src/index.ts
10943
- loadWorkspaceEnv();
10944
- var __dirname = path30.dirname(fileURLToPath5(import.meta.url));
10945
- var pkg = JSON.parse(fs34.readFileSync(path30.join(__dirname, "../package.json"), "utf-8"));
8369
+ var __dirname = path25.dirname(fileURLToPath5(import.meta.url));
8370
+ var pkg = JSON.parse(fs29.readFileSync(path25.join(__dirname, "../package.json"), "utf-8"));
10946
8371
  var cli = new FullstackCLI(pkg.version);
10947
8372
  cli.useAll(commands);
10948
8373
  cli.run();