@lark-apaas/fullstack-cli 1.1.27 → 1.1.28-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import fs25 from "fs";
3
- import path21 from "path";
2
+ import fs26 from "fs";
3
+ import path22 from "path";
4
4
  import { fileURLToPath as fileURLToPath5 } from "url";
5
5
  import { config as dotenvConfig } from "dotenv";
6
6
 
@@ -4285,7 +4285,7 @@ var PROMPT_PATTERNS = [
4285
4285
  { pattern: /proceed\?/i, answer: "y\n" }
4286
4286
  ];
4287
4287
  async function executeShadcnAdd(registryItemPath) {
4288
- return new Promise((resolve) => {
4288
+ return new Promise((resolve2) => {
4289
4289
  let output = "";
4290
4290
  const args = ["--yes", "shadcn@3.8.2", "add", registryItemPath];
4291
4291
  const ptyProcess = pty.spawn("npx", args, {
@@ -4311,7 +4311,7 @@ async function executeShadcnAdd(registryItemPath) {
4311
4311
  });
4312
4312
  const timeoutId = setTimeout(() => {
4313
4313
  ptyProcess.kill();
4314
- resolve({
4314
+ resolve2({
4315
4315
  success: false,
4316
4316
  files: [],
4317
4317
  error: "\u6267\u884C\u8D85\u65F6"
@@ -4322,7 +4322,7 @@ async function executeShadcnAdd(registryItemPath) {
4322
4322
  const success = exitCode === 0;
4323
4323
  const filePaths = parseOutput(output);
4324
4324
  const files = filePaths.map(toFileInfo);
4325
- resolve({
4325
+ resolve2({
4326
4326
  success,
4327
4327
  files,
4328
4328
  error: success ? void 0 : output || `Process exited with code ${exitCode}`
@@ -4333,12 +4333,12 @@ async function executeShadcnAdd(registryItemPath) {
4333
4333
 
4334
4334
  // src/commands/component/add.handler.ts
4335
4335
  function runActionPluginInit() {
4336
- return new Promise((resolve) => {
4336
+ return new Promise((resolve2) => {
4337
4337
  execFile("fullstack-cli", ["action-plugin", "init"], { cwd: process.cwd(), stdio: "ignore" }, (error) => {
4338
4338
  if (error) {
4339
4339
  debug("action-plugin init \u5931\u8D25: %s", error.message);
4340
4340
  }
4341
- resolve();
4341
+ resolve2();
4342
4342
  });
4343
4343
  });
4344
4344
  }
@@ -7174,7 +7174,45 @@ async function genArtifactUploadCredential(appId, body) {
7174
7174
  const response = await client.post(url, body);
7175
7175
  if (!response.ok || response.status !== 200) {
7176
7176
  throw new Error(
7177
- `API request failed: ${response.status} ${response.statusText}`
7177
+ `gen_artifact_upload_credential \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
7178
+ );
7179
+ }
7180
+ return response.json();
7181
+ }
7182
+ async function getDefaultBucketId(appId) {
7183
+ const client = getHttpClient();
7184
+ const url = `/b/${appId}/get_published_v2`;
7185
+ const response = await client.get(url);
7186
+ if (!response.ok || response.status !== 200) {
7187
+ throw new Error(
7188
+ `get_published_v2 \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
7189
+ );
7190
+ }
7191
+ const data = await response.json();
7192
+ const bucketId = data?.data?.app_runtime_extra?.bucket?.default_bucket_id;
7193
+ if (!bucketId) {
7194
+ throw new Error(`\u672A\u627E\u5230\u5E94\u7528 ${appId} \u7684\u9ED8\u8BA4\u5B58\u50A8\u6876`);
7195
+ }
7196
+ return bucketId;
7197
+ }
7198
+ async function preUploadStaticAttachment(appId, bucketId) {
7199
+ const client = getHttpClient();
7200
+ const url = `/v1/app/${appId}/storage/bucket/${bucketId}/preUploadStatic`;
7201
+ const response = await client.post(url, {});
7202
+ if (!response.ok || response.status !== 200) {
7203
+ throw new Error(
7204
+ `preUploadStatic \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
7205
+ );
7206
+ }
7207
+ return response.json();
7208
+ }
7209
+ async function uploadStaticAttachmentCallback(appId, bucketId, body) {
7210
+ const client = getHttpClient();
7211
+ const url = `/v1/app/${appId}/storage/bucket/${bucketId}/object/callbackStatic`;
7212
+ const response = await client.post(url, body);
7213
+ if (!response.ok || response.status !== 200) {
7214
+ throw new Error(
7215
+ `callbackStatic \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
7178
7216
  );
7179
7217
  }
7180
7218
  return response.json();
@@ -7212,6 +7250,165 @@ function camelToKebab(str) {
7212
7250
  return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
7213
7251
  }
7214
7252
 
7253
+ // src/commands/build/upload-static.handler.ts
7254
+ import * as fs25 from "fs";
7255
+ import * as path21 from "path";
7256
+ import { execSync as execSync3 } from "child_process";
7257
+ function readCredentialsFromEnv() {
7258
+ const uploadPrefix = process.env.STATIC_UPLOAD_PREFIX;
7259
+ const uploadID = process.env.STATIC_UPLOAD_ID;
7260
+ const bucketId = process.env.STATIC_UPLOAD_BUCKET_ID;
7261
+ const accessKeyID = process.env.STATIC_UPLOAD_AK;
7262
+ const secretAccessKey = process.env.STATIC_UPLOAD_SK;
7263
+ const sessionToken = process.env.STATIC_UPLOAD_TOKEN;
7264
+ if (!uploadPrefix || !uploadID || !bucketId || !accessKeyID || !secretAccessKey || !sessionToken) {
7265
+ return null;
7266
+ }
7267
+ return { uploadPrefix, uploadID, bucketId, accessKeyID, secretAccessKey, sessionToken };
7268
+ }
7269
+ var LOG_PREFIX = "[upload-static]";
7270
+ async function uploadStatic(options) {
7271
+ try {
7272
+ const {
7273
+ appId,
7274
+ staticDir = "shared/static",
7275
+ tosutilPath = "/workspace/tosutil",
7276
+ endpoint = "tos-cn-beijing.volces.com",
7277
+ region = "cn-beijing"
7278
+ } = options;
7279
+ const resolvedStaticDir = path21.resolve(staticDir);
7280
+ if (!fs25.existsSync(resolvedStaticDir)) {
7281
+ console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E0D\u5B58\u5728: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
7282
+ return;
7283
+ }
7284
+ if (isDirEmpty(resolvedStaticDir)) {
7285
+ console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E3A\u7A7A: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
7286
+ return;
7287
+ }
7288
+ if (!fs25.existsSync(tosutilPath)) {
7289
+ throw new Error(
7290
+ `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`
7291
+ );
7292
+ }
7293
+ let uploadPrefix;
7294
+ let uploadID;
7295
+ let bucketId;
7296
+ let accessKeyID;
7297
+ let secretAccessKey;
7298
+ let sessionToken;
7299
+ const envCredentials = readCredentialsFromEnv();
7300
+ if (envCredentials) {
7301
+ console.error(`${LOG_PREFIX} \u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684\u4E0A\u4F20\u51ED\u8BC1`);
7302
+ ({ uploadPrefix, uploadID, bucketId, accessKeyID, secretAccessKey, sessionToken } = envCredentials);
7303
+ } else {
7304
+ console.error(`${LOG_PREFIX} \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E\uFF0C\u8C03\u7528 preUploadStatic...`);
7305
+ bucketId = await resolveBucketId(appId);
7306
+ const preUploadResp = await fetchPreUpload(appId, bucketId);
7307
+ const { uploadCredential } = preUploadResp.data;
7308
+ ({ uploadPrefix, uploadID } = preUploadResp.data);
7309
+ ({ AccessKeyID: accessKeyID, SecretAccessKey: secretAccessKey, SessionToken: sessionToken } = uploadCredential);
7310
+ }
7311
+ console.error(`${LOG_PREFIX} \u4E0A\u4F20\u76EE\u6807: ${uploadPrefix}`);
7312
+ console.error(`${LOG_PREFIX} \u914D\u7F6E tosutil...`);
7313
+ configureTosutil(tosutilPath, {
7314
+ endpoint,
7315
+ region,
7316
+ accessKeyID,
7317
+ secretAccessKey,
7318
+ sessionToken
7319
+ });
7320
+ console.error(`${LOG_PREFIX} \u4E0A\u4F20 ${resolvedStaticDir} -> ${uploadPrefix}`);
7321
+ uploadToTos(tosutilPath, resolvedStaticDir, uploadPrefix);
7322
+ console.error(`${LOG_PREFIX} tosutil \u4E0A\u4F20\u5B8C\u6210`);
7323
+ console.error(`${LOG_PREFIX} \u8C03\u7528 callbackStatic (uploadID: ${uploadID})...`);
7324
+ const callbackResp = await uploadStaticAttachmentCallback(appId, bucketId, { uploadID });
7325
+ if (callbackResp.status_code !== "0") {
7326
+ throw new Error(`callbackStatic \u8FD4\u56DE\u5F02\u5E38, status_code: ${callbackResp.status_code}`);
7327
+ }
7328
+ const attachments = callbackResp.data?.attachments || [];
7329
+ console.error(`${LOG_PREFIX} \u4E0A\u4F20\u5B8C\u6210\uFF0C\u5171 ${attachments.length} \u4E2A\u6587\u4EF6`);
7330
+ console.log(JSON.stringify(callbackResp));
7331
+ } catch (error) {
7332
+ const message = error instanceof Error ? error.message : String(error);
7333
+ console.error(`${LOG_PREFIX} Error: ${message}`);
7334
+ process.exit(1);
7335
+ }
7336
+ }
7337
+ async function fetchPreUpload(appId, bucketId) {
7338
+ const response = await preUploadStaticAttachment(appId, bucketId);
7339
+ if (response.status_code !== "0") {
7340
+ throw new Error(`preUploadStatic \u8FD4\u56DE\u5F02\u5E38, status_code: ${response.status_code}`);
7341
+ }
7342
+ const { uploadPrefix, uploadID, uploadCredential } = response.data || {};
7343
+ if (!uploadPrefix || !uploadID) {
7344
+ throw new Error("preUploadStatic \u8FD4\u56DE\u6570\u636E\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 uploadPrefix \u6216 uploadID");
7345
+ }
7346
+ if (!uploadCredential?.AccessKeyID || !uploadCredential?.SecretAccessKey || !uploadCredential?.SessionToken) {
7347
+ throw new Error("preUploadStatic \u8FD4\u56DE\u7684\u51ED\u8BC1\u5B57\u6BB5\u4E0D\u5B8C\u6574");
7348
+ }
7349
+ return response;
7350
+ }
7351
+ function configureTosutil(tosutilPath, config) {
7352
+ const { endpoint, region, accessKeyID, secretAccessKey, sessionToken } = config;
7353
+ execSync3(
7354
+ `${tosutilPath} config -e ${endpoint} -i ${accessKeyID} -k ${secretAccessKey} -t ${sessionToken} -re ${region}`,
7355
+ { stdio: "pipe" }
7356
+ );
7357
+ }
7358
+ function uploadToTos(tosutilPath, sourceDir, destUrl) {
7359
+ execSync3(
7360
+ `${tosutilPath} cp "${sourceDir}" "${destUrl}" -r -flat -j 5 -p 3 -ps 10485760 -f`,
7361
+ { stdio: "inherit" }
7362
+ );
7363
+ }
7364
+ async function resolveBucketId(appId) {
7365
+ console.error(`${LOG_PREFIX} \u83B7\u53D6\u9ED8\u8BA4\u5B58\u50A8\u6876...`);
7366
+ const bucketId = await getDefaultBucketId(appId);
7367
+ console.error(`${LOG_PREFIX} \u9ED8\u8BA4\u5B58\u50A8\u6876: ${bucketId}`);
7368
+ return bucketId;
7369
+ }
7370
+ function isDirEmpty(dirPath) {
7371
+ const entries = fs25.readdirSync(dirPath);
7372
+ return entries.length === 0;
7373
+ }
7374
+
7375
+ // src/commands/build/pre-upload-static.handler.ts
7376
+ var LOG_PREFIX2 = "[pre-upload-static]";
7377
+ async function preUploadStatic(options) {
7378
+ try {
7379
+ const { appId } = options;
7380
+ console.error(`${LOG_PREFIX2} \u83B7\u53D6\u9ED8\u8BA4\u5B58\u50A8\u6876...`);
7381
+ const bucketId = await getDefaultBucketId(appId);
7382
+ console.error(`${LOG_PREFIX2} \u9ED8\u8BA4\u5B58\u50A8\u6876: ${bucketId}`);
7383
+ console.error(`${LOG_PREFIX2} \u8C03\u7528 preUploadStatic...`);
7384
+ const response = await preUploadStaticAttachment(appId, bucketId);
7385
+ if (response.status_code !== "0") {
7386
+ console.error(`${LOG_PREFIX2} preUploadStatic \u8FD4\u56DE\u5F02\u5E38, status_code: ${response.status_code}`);
7387
+ return;
7388
+ }
7389
+ const { downloadUrlPrefix, uploadPrefix, uploadID, uploadCredential } = response.data || {};
7390
+ if (!downloadUrlPrefix || !uploadPrefix || !uploadID) {
7391
+ console.error(`${LOG_PREFIX2} preUploadStatic \u8FD4\u56DE\u6570\u636E\u4E0D\u5B8C\u6574`);
7392
+ return;
7393
+ }
7394
+ if (!uploadCredential?.AccessKeyID || !uploadCredential?.SecretAccessKey || !uploadCredential?.SessionToken) {
7395
+ console.error(`${LOG_PREFIX2} preUploadStatic \u8FD4\u56DE\u7684\u51ED\u8BC1\u5B57\u6BB5\u4E0D\u5B8C\u6574`);
7396
+ return;
7397
+ }
7398
+ console.log(`export STATIC_ASSETS_BASE_URL="${downloadUrlPrefix}"`);
7399
+ console.log(`export STATIC_UPLOAD_PREFIX="${uploadPrefix}"`);
7400
+ console.log(`export STATIC_UPLOAD_ID="${uploadID}"`);
7401
+ console.log(`export STATIC_UPLOAD_AK="${uploadCredential.AccessKeyID}"`);
7402
+ console.log(`export STATIC_UPLOAD_SK="${uploadCredential.SecretAccessKey}"`);
7403
+ console.log(`export STATIC_UPLOAD_TOKEN="${uploadCredential.SessionToken}"`);
7404
+ console.log(`export STATIC_UPLOAD_BUCKET_ID="${bucketId}"`);
7405
+ console.error(`${LOG_PREFIX2} \u73AF\u5883\u53D8\u91CF\u5DF2\u8F93\u51FA`);
7406
+ } catch (error) {
7407
+ const message = error instanceof Error ? error.message : String(error);
7408
+ console.error(`${LOG_PREFIX2} Warning: ${message}`);
7409
+ }
7410
+ }
7411
+
7215
7412
  // src/commands/build/index.ts
7216
7413
  var getTokenCommand = {
7217
7414
  name: "get-token",
@@ -7222,10 +7419,28 @@ var getTokenCommand = {
7222
7419
  });
7223
7420
  }
7224
7421
  };
7422
+ var uploadStaticCommand = {
7423
+ name: "upload-static",
7424
+ description: "Upload shared/static files to TOS",
7425
+ register(program) {
7426
+ program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").option("--static-dir <dir>", "Static files directory", "shared/static").option("--tosutil-path <path>", "Path to tosutil binary", "/workspace/tosutil").option("--endpoint <endpoint>", "TOS endpoint", "tos-cn-beijing.volces.com").option("--region <region>", "TOS region", "cn-beijing").action(async (options) => {
7427
+ await uploadStatic(options);
7428
+ });
7429
+ }
7430
+ };
7431
+ var preUploadStaticCommand = {
7432
+ name: "pre-upload-static",
7433
+ description: "Get TOS upload info and output as env vars for build.sh eval",
7434
+ register(program) {
7435
+ program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").action(async (options) => {
7436
+ await preUploadStatic(options);
7437
+ });
7438
+ }
7439
+ };
7225
7440
  var buildCommandGroup = {
7226
7441
  name: "build",
7227
7442
  description: "Build related commands",
7228
- commands: [getTokenCommand]
7443
+ commands: [getTokenCommand, uploadStaticCommand, preUploadStaticCommand]
7229
7444
  };
7230
7445
 
7231
7446
  // src/commands/index.ts
@@ -7242,12 +7457,12 @@ var commands = [
7242
7457
  ];
7243
7458
 
7244
7459
  // src/index.ts
7245
- var envPath = path21.join(process.cwd(), ".env");
7246
- if (fs25.existsSync(envPath)) {
7460
+ var envPath = path22.join(process.cwd(), ".env");
7461
+ if (fs26.existsSync(envPath)) {
7247
7462
  dotenvConfig({ path: envPath });
7248
7463
  }
7249
- var __dirname = path21.dirname(fileURLToPath5(import.meta.url));
7250
- var pkg = JSON.parse(fs25.readFileSync(path21.join(__dirname, "../package.json"), "utf-8"));
7464
+ var __dirname = path22.dirname(fileURLToPath5(import.meta.url));
7465
+ var pkg = JSON.parse(fs26.readFileSync(path22.join(__dirname, "../package.json"), "utf-8"));
7251
7466
  var cli = new FullstackCLI(pkg.version);
7252
7467
  cli.useAll(commands);
7253
7468
  cli.run();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.27",
3
+ "version": "1.1.28-alpha.1",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -19,28 +19,46 @@ print_time() {
19
19
  }
20
20
 
21
21
  # ==================== 步骤 0 ====================
22
- echo "🗑️ [0/5] 安装插件"
22
+ echo "🗑️ [0/6] 安装插件"
23
23
  STEP_START=$(node -e "console.log(Date.now())")
24
24
  npx fullstack-cli action-plugin init
25
25
  print_time $STEP_START
26
26
  echo ""
27
27
 
28
28
  # ==================== 步骤 1 ====================
29
- echo "📝 [1/5] 更新 openapi 代码"
29
+ echo "📝 [1/6] 更新 openapi 代码"
30
30
  STEP_START=$(node -e "console.log(Date.now())")
31
31
  npm run gen:openapi
32
32
  print_time $STEP_START
33
33
  echo ""
34
34
 
35
35
  # ==================== 步骤 2 ====================
36
- echo "🗑️ [2/5] 清理 dist 目录"
36
+ echo "🗑️ [2/6] 清理 dist 目录"
37
37
  STEP_START=$(node -e "console.log(Date.now())")
38
38
  rm -rf "$ROOT_DIR/dist"
39
39
  print_time $STEP_START
40
40
  echo ""
41
41
 
42
42
  # ==================== 步骤 3 ====================
43
- echo "🔨 [3/5] 并行构建 server 和 client"
43
+ echo "🔗 [3/6] 预上传:获取 TOS 信息并注入环境变量"
44
+ STEP_START=$(node -e "console.log(Date.now())")
45
+
46
+ if [ -d "$ROOT_DIR/shared/static" ] && [ "$(ls -A "$ROOT_DIR/shared/static" 2>/dev/null)" ]; then
47
+ eval "$(npx fullstack-cli build pre-upload-static --app-id "${app_id}")"
48
+ if [ -n "$STATIC_ASSETS_BASE_URL" ]; then
49
+ echo " STATIC_ASSETS_BASE_URL=$STATIC_ASSETS_BASE_URL"
50
+ else
51
+ echo " ⚠️ 未获取到 TOS URL 前缀,将使用默认路径"
52
+ fi
53
+ else
54
+ echo " 跳过:shared/static 目录不存在或为空"
55
+ fi
56
+
57
+ print_time $STEP_START
58
+ echo ""
59
+
60
+ # ==================== 步骤 4 ====================
61
+ echo "🔨 [4/6] 并行构建 server 和 client"
44
62
  STEP_START=$(node -e "console.log(Date.now())")
45
63
 
46
64
  # 并行构建
@@ -77,8 +95,8 @@ echo " ✅ Client 构建完成"
77
95
  print_time $STEP_START
78
96
  echo ""
79
97
 
80
- # ==================== 步骤 4 ====================
81
- echo "📦 [4/5] 准备 server 依赖产物"
98
+ # ==================== 步骤 5 ====================
99
+ echo "📦 [5/6] 准备 server 依赖产物"
82
100
  STEP_START=$(node -e "console.log(Date.now())")
83
101
 
84
102
  mkdir -p "$OUT_DIR/dist/client"
@@ -96,8 +114,8 @@ rm -rf "$ROOT_DIR/dist/tsconfig.node.tsbuildinfo"
96
114
  print_time $STEP_START
97
115
  echo ""
98
116
 
99
- # ==================== 步骤 5 ====================
100
- echo "✂️ [5/5] 智能依赖裁剪"
117
+ # ==================== 步骤 6 ====================
118
+ echo "✂️ [6/6] 智能依赖裁剪"
101
119
  STEP_START=$(node -e "console.log(Date.now())")
102
120
 
103
121
  # 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json