@lark-apaas/fullstack-cli 1.1.28-alpha.17 → 1.1.28-alpha.19

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
@@ -1414,15 +1414,14 @@ async function fetchSyncedTables(appId, workspace) {
1414
1414
  DEFAULT_TIMEOUT_MS2
1415
1415
  );
1416
1416
  });
1417
- const dbBranch = process.env.FORCE_DB_BRANCH || "main";
1418
1417
  const start = Date.now();
1419
1418
  console.log(
1420
- `[fetchSyncedTables] \u2192 GET listTableView (dbBranch=${dbBranch}) appId=${appId ? "set" : "unset"} workspace=${workspace ? "set" : "unset"}`
1419
+ `[fetchSyncedTables] \u2192 GET listTableView (dbBranch=main) appId=${appId ? "set" : "unset"} workspace=${workspace ? "set" : "unset"}`
1421
1420
  );
1422
1421
  const response = await Promise.race([
1423
1422
  client.get(
1424
1423
  `/api/v1/dataloom/inner/app/${appId}/workspaces/${workspace}/listTableView`,
1425
- { params: { dbBranch }, headers: { "x-supaas-bizsource": "miaoda" } }
1424
+ { params: { dbBranch: "main" }, headers: { "x-supaas-bizsource": "miaoda" } }
1426
1425
  ),
1427
1426
  timeoutPromise
1428
1427
  ]);
@@ -2378,12 +2377,15 @@ var syncConfig = {
2378
2377
  type: "directory",
2379
2378
  overwrite: true
2380
2379
  },
2381
- // 2. 覆写 nest-cli.json 配置,禁止用户修改
2380
+ // 2. 智能合并 nest-cli.json 配置(保留用户自定义的 assets、plugins 等)
2382
2381
  {
2383
2382
  from: "templates/nest-cli.json",
2384
2383
  to: "nest-cli.json",
2385
- type: "file",
2386
- overwrite: true
2384
+ type: "merge-json",
2385
+ arrayMerge: {
2386
+ "compilerOptions.assets": { key: "include" },
2387
+ "compilerOptions.plugins": { key: "name" }
2388
+ }
2387
2389
  },
2388
2390
  // // 2. 追加内容到 .gitignore
2389
2391
  // {
@@ -2476,6 +2478,52 @@ function removeLineFromFile(filePath, pattern) {
2476
2478
  return true;
2477
2479
  }
2478
2480
 
2481
+ // src/utils/merge-json.ts
2482
+ function isPlainObject(value) {
2483
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2484
+ }
2485
+ function mergeArrayByKey(userArr, templateArr, key) {
2486
+ const result = [...userArr];
2487
+ for (const templateItem of templateArr) {
2488
+ if (!isPlainObject(templateItem)) continue;
2489
+ const templateKey = templateItem[key];
2490
+ const existingIndex = result.findIndex(
2491
+ (item) => isPlainObject(item) && item[key] === templateKey
2492
+ );
2493
+ if (existingIndex >= 0) {
2494
+ result[existingIndex] = templateItem;
2495
+ } else {
2496
+ result.push(templateItem);
2497
+ }
2498
+ }
2499
+ return result;
2500
+ }
2501
+ function deepMergeJson(user, template, arrayMerge = {}, currentPath = "") {
2502
+ const result = { ...user };
2503
+ for (const key of Object.keys(template)) {
2504
+ const fullPath = currentPath ? `${currentPath}.${key}` : key;
2505
+ const templateValue = template[key];
2506
+ const userValue = user[key];
2507
+ if (Array.isArray(templateValue)) {
2508
+ const mergeConfig = arrayMerge[fullPath];
2509
+ if (mergeConfig && Array.isArray(userValue)) {
2510
+ result[key] = mergeArrayByKey(userValue, templateValue, mergeConfig.key);
2511
+ } else {
2512
+ result[key] = templateValue;
2513
+ }
2514
+ } else if (isPlainObject(templateValue)) {
2515
+ if (isPlainObject(userValue)) {
2516
+ result[key] = deepMergeJson(userValue, templateValue, arrayMerge, fullPath);
2517
+ } else {
2518
+ result[key] = templateValue;
2519
+ }
2520
+ } else {
2521
+ result[key] = templateValue;
2522
+ }
2523
+ }
2524
+ return result;
2525
+ }
2526
+
2479
2527
  // src/commands/sync/run.handler.ts
2480
2528
  async function run2(options) {
2481
2529
  const userProjectRoot = process.env.INIT_CWD || process.cwd();
@@ -2538,6 +2586,12 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
2538
2586
  addLineToFile(destPath2, rule.line);
2539
2587
  return;
2540
2588
  }
2589
+ if (rule.type === "merge-json") {
2590
+ const srcPath2 = path4.join(pluginRoot, rule.from);
2591
+ const destPath2 = path4.join(userProjectRoot, rule.to);
2592
+ mergeJsonFile(srcPath2, destPath2, rule.arrayMerge);
2593
+ return;
2594
+ }
2541
2595
  if (!("from" in rule)) {
2542
2596
  return;
2543
2597
  }
@@ -2680,6 +2734,33 @@ function addLineToFile(filePath, line) {
2680
2734
  fs6.appendFileSync(filePath, appendContent);
2681
2735
  console.log(`[fullstack-cli] \u2713 ${fileName} (added: ${line})`);
2682
2736
  }
2737
+ function mergeJsonFile(src, dest, arrayMerge) {
2738
+ const fileName = path4.basename(dest);
2739
+ if (!fs6.existsSync(src)) {
2740
+ console.warn(`[fullstack-cli] Source not found: ${src}`);
2741
+ return;
2742
+ }
2743
+ const templateContent = JSON.parse(fs6.readFileSync(src, "utf-8"));
2744
+ if (!fs6.existsSync(dest)) {
2745
+ const destDir = path4.dirname(dest);
2746
+ if (!fs6.existsSync(destDir)) {
2747
+ fs6.mkdirSync(destDir, { recursive: true });
2748
+ }
2749
+ fs6.writeFileSync(dest, JSON.stringify(templateContent, null, 2) + "\n");
2750
+ console.log(`[fullstack-cli] \u2713 ${fileName} (created)`);
2751
+ return;
2752
+ }
2753
+ const userContent = JSON.parse(fs6.readFileSync(dest, "utf-8"));
2754
+ const merged = deepMergeJson(userContent, templateContent, arrayMerge ?? {});
2755
+ const userStr = JSON.stringify(userContent, null, 2);
2756
+ const mergedStr = JSON.stringify(merged, null, 2);
2757
+ if (userStr === mergedStr) {
2758
+ console.log(`[fullstack-cli] \u25CB ${fileName} (already up to date)`);
2759
+ return;
2760
+ }
2761
+ fs6.writeFileSync(dest, mergedStr + "\n");
2762
+ console.log(`[fullstack-cli] \u2713 ${fileName} (merged)`);
2763
+ }
2683
2764
 
2684
2765
  // src/commands/sync/index.ts
2685
2766
  var syncCommand = {
@@ -2936,7 +3017,7 @@ function getUpgradeFilesToStage(disableGenOpenapi = true) {
2936
3017
  const syncConfig2 = genSyncConfig({ disableGenOpenapi });
2937
3018
  const filesToStage = /* @__PURE__ */ new Set();
2938
3019
  syncConfig2.sync.forEach((rule) => {
2939
- if (rule.type === "file" || rule.type === "directory") {
3020
+ if (rule.type === "file" || rule.type === "directory" || rule.type === "merge-json") {
2940
3021
  filesToStage.add(rule.to);
2941
3022
  } else if (rule.type === "remove-line" || rule.type === "add-line") {
2942
3023
  filesToStage.add(rule.to);
@@ -7189,17 +7270,20 @@ async function genArtifactUploadCredential(appId, body) {
7189
7270
  }
7190
7271
  async function getDefaultBucketId(appId) {
7191
7272
  const client = getHttpClient();
7192
- const url = `/b/${appId}/get_published_v2`;
7193
- const response = await client.get(url);
7273
+ const url = `/v1/app/${appId}/storage/inner/staticBucket`;
7274
+ const response = await client.post(url, {});
7194
7275
  if (!response.ok || response.status !== 200) {
7195
7276
  throw new Error(
7196
- `get_published_v2 \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
7277
+ `getOrCreateStaticBucket \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
7197
7278
  );
7198
7279
  }
7199
7280
  const data = await response.json();
7200
- const bucketId = data?.data?.app_runtime_extra?.bucket?.default_bucket_id;
7281
+ if (data.status_code !== "0") {
7282
+ throw new Error(`getOrCreateStaticBucket \u8FD4\u56DE\u5F02\u5E38, status_code: ${data.status_code}`);
7283
+ }
7284
+ const bucketId = data?.data?.bucketID;
7201
7285
  if (!bucketId) {
7202
- throw new Error(`\u672A\u627E\u5230\u5E94\u7528 ${appId} \u7684\u9ED8\u8BA4\u5B58\u50A8\u6876`);
7286
+ throw new Error(`\u672A\u627E\u5230\u5E94\u7528 ${appId} \u7684\u9759\u6001\u8D44\u6E90\u5B58\u50A8\u6876`);
7203
7287
  }
7204
7288
  return bucketId;
7205
7289
  }
@@ -7280,7 +7364,7 @@ async function uploadStatic(options) {
7280
7364
  const {
7281
7365
  appId,
7282
7366
  staticDir = "shared/static",
7283
- tosutilPath = "/workspace/tosutil",
7367
+ tosutilPath = "tosutil",
7284
7368
  endpoint = "tos-cn-beijing.volces.com",
7285
7369
  region = "cn-beijing"
7286
7370
  } = options;
@@ -7293,9 +7377,10 @@ async function uploadStatic(options) {
7293
7377
  console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E3A\u7A7A: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
7294
7378
  return;
7295
7379
  }
7296
- if (!fs25.existsSync(tosutilPath)) {
7380
+ const resolvedTosutil = resolveTosutilPath(tosutilPath);
7381
+ if (!resolvedTosutil) {
7297
7382
  throw new Error(
7298
- `tosutil \u4E0D\u5B58\u5728: ${tosutilPath}\u3002\u8BF7\u786E\u4FDD\u6D41\u6C34\u7EBF\u5DF2\u5728"\u4EA7\u7269\u6253\u5305\u4E0A\u4F20"\u6B65\u9AA4\u4E2D\u4E0B\u8F7D tosutil\u3002`
7383
+ `tosutil \u4E0D\u5B58\u5728: ${tosutilPath}\u3002\u8BF7\u786E\u4FDD tosutil \u5DF2\u5B89\u88C5\u5728\u7CFB\u7EDF PATH \u4E2D\u6216\u901A\u8FC7 --tosutil-path \u6307\u5B9A\u8DEF\u5F84\u3002`
7299
7384
  );
7300
7385
  }
7301
7386
  let uploadPrefix;
@@ -7318,7 +7403,7 @@ async function uploadStatic(options) {
7318
7403
  }
7319
7404
  console.error(`${LOG_PREFIX} \u4E0A\u4F20\u76EE\u6807: ${uploadPrefix}`);
7320
7405
  console.error(`${LOG_PREFIX} \u914D\u7F6E tosutil...`);
7321
- configureTosutil(tosutilPath, {
7406
+ configureTosutil(resolvedTosutil, {
7322
7407
  endpoint,
7323
7408
  region,
7324
7409
  accessKeyID,
@@ -7326,7 +7411,7 @@ async function uploadStatic(options) {
7326
7411
  sessionToken
7327
7412
  });
7328
7413
  console.error(`${LOG_PREFIX} \u4E0A\u4F20 ${resolvedStaticDir} -> ${uploadPrefix}`);
7329
- uploadToTos(tosutilPath, resolvedStaticDir, uploadPrefix);
7414
+ uploadToTos(resolvedTosutil, resolvedStaticDir, uploadPrefix);
7330
7415
  console.error(`${LOG_PREFIX} tosutil \u4E0A\u4F20\u5B8C\u6210`);
7331
7416
  console.error(`${LOG_PREFIX} \u8C03\u7528 callbackStatic (uploadID: ${uploadID})...`);
7332
7417
  const callbackResp = await uploadStaticAttachmentCallback(appId, bucketId, { uploadID });
@@ -7342,6 +7427,17 @@ async function uploadStatic(options) {
7342
7427
  process.exit(1);
7343
7428
  }
7344
7429
  }
7430
+ function resolveTosutilPath(tosutilPath) {
7431
+ if (path21.isAbsolute(tosutilPath)) {
7432
+ return fs25.existsSync(tosutilPath) ? tosutilPath : null;
7433
+ }
7434
+ try {
7435
+ const resolved = execFileSync("which", [tosutilPath], { encoding: "utf-8" }).trim();
7436
+ return resolved || null;
7437
+ } catch {
7438
+ return null;
7439
+ }
7440
+ }
7345
7441
  async function fetchPreUpload(appId, bucketId) {
7346
7442
  const response = await preUploadStaticAttachment(appId, bucketId);
7347
7443
  if (response.status_code !== "0") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.28-alpha.17",
3
+ "version": "1.1.28-alpha.19",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3,7 +3,7 @@
3
3
  set -euo pipefail
4
4
 
5
5
  ROOT_DIR="$(pwd)"
6
- OUT_DIR="$ROOT_DIR/dist/server"
6
+ DIST_DIR="$ROOT_DIR/dist"
7
7
 
8
8
  # 记录总开始时间
9
9
  TOTAL_START=$(node -e "console.log(Date.now())")
@@ -78,25 +78,26 @@ print_time $STEP_START
78
78
  echo ""
79
79
 
80
80
  # ==================== 步骤 4 ====================
81
- echo "📦 [4/5] 准备 server 依赖产物"
81
+ echo "📦 [4/5] 准备产物"
82
82
  STEP_START=$(node -e "console.log(Date.now())")
83
83
 
84
- mkdir -p "$OUT_DIR/dist/client"
85
-
86
- # 移动 HTML(从 dist/client 移走,避免残留)
87
- mv "$ROOT_DIR/dist/client/"*.html "$OUT_DIR/dist/client/" || true
88
-
89
- # 拷贝 run.sh 文件
90
- cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
84
+ # 拷贝 run.sh 到 dist/(prod 从 dist/ 启动,确保 cwd 一致性)
85
+ cp "$ROOT_DIR/scripts/run.sh" "$DIST_DIR/"
91
86
 
92
87
  # 拷贝 .env 文件(如果存在)
93
88
  if [ -f "$ROOT_DIR/.env" ]; then
94
- cp "$ROOT_DIR/.env" "$OUT_DIR/"
89
+ cp "$ROOT_DIR/.env" "$DIST_DIR/"
90
+ fi
91
+
92
+ # 移动 client 下的 HTML 文件到 dist/dist/client,保证 views 路径在 dev/prod 下一致
93
+ if [ -d "$DIST_DIR/client" ]; then
94
+ mkdir -p "$DIST_DIR/dist/client"
95
+ find "$DIST_DIR/client" -maxdepth 1 -name "*.html" -exec mv {} "$DIST_DIR/dist/client/" \;
95
96
  fi
96
97
 
97
98
  # 清理无用文件
98
- rm -rf "$ROOT_DIR/dist/scripts"
99
- rm -rf "$ROOT_DIR/dist/tsconfig.node.tsbuildinfo"
99
+ rm -rf "$DIST_DIR/scripts"
100
+ rm -rf "$DIST_DIR/tsconfig.node.tsbuildinfo"
100
101
 
101
102
  print_time $STEP_START
102
103
  echo ""
@@ -116,8 +117,8 @@ echo "构建完成"
116
117
  print_time $TOTAL_START
117
118
 
118
119
  # 输出产物信息
119
- DIST_SIZE=$(du -sh "$OUT_DIR" | cut -f1)
120
- NODE_MODULES_SIZE=$(du -sh "$ROOT_DIR/dist/node_modules" | cut -f1)
120
+ DIST_SIZE=$(du -sh "$DIST_DIR" | cut -f1)
121
+ NODE_MODULES_SIZE=$(du -sh "$DIST_DIR/node_modules" | cut -f1)
121
122
  echo ""
122
123
  echo "📊 构建产物统计:"
123
124
  echo " 产物大小: $DIST_SIZE"
@@ -6,11 +6,12 @@ const fs = require('fs');
6
6
  const path = require('path');
7
7
 
8
8
  const ROOT_DIR = path.resolve(__dirname, '..');
9
- const DIST_SERVER_DIR = path.join(ROOT_DIR, 'dist/server');
9
+ const DIST_DIR = path.join(ROOT_DIR, 'dist');
10
+ const DIST_SERVER_DIR = path.join(DIST_DIR, 'server');
10
11
  const ROOT_PACKAGE_JSON = path.join(ROOT_DIR, 'package.json');
11
12
  const ROOT_NODE_MODULES = path.join(ROOT_DIR, 'node_modules');
12
- const OUT_NODE_MODULES = path.join(ROOT_DIR, 'dist/node_modules');
13
- const OUT_PACKAGE_JSON = path.join(DIST_SERVER_DIR, 'package.json');
13
+ const OUT_NODE_MODULES = path.join(DIST_DIR, 'node_modules');
14
+ const OUT_PACKAGE_JSON = path.join(DIST_DIR, 'package.json');
14
15
 
15
16
  // Server 入口文件
16
17
  const SERVER_ENTRY = path.join(DIST_SERVER_DIR, 'main.js');
@@ -294,9 +295,6 @@ async function smartPrune() {
294
295
  version: originalPackage.version,
295
296
  private: true,
296
297
  dependencies: prunedDependencies,
297
- scripts: {
298
- start: originalPackage.scripts?.start || 'node main.js'
299
- },
300
298
  engines: originalPackage.engines
301
299
  };
302
300
 
@@ -2,4 +2,7 @@
2
2
  # This file is auto-generated by @lark-apaas/fullstack-cli
3
3
 
4
4
  # 生产环境下,启动服务
5
- npm run start
5
+ # dist/ 根目录执行,确保 process.cwd() 与 dev 模式一致
6
+ # dev: cwd = 项目根, shared/ client/ 可达
7
+ # prod: cwd = dist/, shared/ client/ 可达
8
+ NODE_ENV=production node server/main.js