@lark-apaas/fullstack-cli 1.1.22-alpha.25 → 1.1.22-alpha.26

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.
@@ -120,43 +120,4 @@ export const customTimestamptz = customType<{
120
120
  if(value instanceof Date) return value;
121
121
  return new Date(value);
122
122
  },
123
- });
124
-
125
- /**
126
- * User type marker for user_profile_domain
127
- * Simple marker type, no conversion needed - passes through as string
128
- */
129
- export const userType = customType<{
130
- data: string;
131
- driverData: string;
132
- }>({
133
- dataType() {
134
- return 'user_profile_domain';
135
- },
136
- toDriver(value: string) {
137
- return value;
138
- },
139
- fromDriver(value: string) {
140
- return value;
141
- },
142
- });
143
-
144
- /**
145
- * File type marker for file_attachment_domain
146
- * Simple marker type, no conversion needed - passes through as string
147
- */
148
- export const fileType = customType<{
149
- data: string;
150
- driverData: string;
151
- }>({
152
- dataType() {
153
- return 'file_attachment_domain';
154
- },
155
- toDriver(value: string) {
156
- return value;
157
- },
158
- fromDriver(value: string) {
159
- return value;
160
- },
161
- });
162
-
123
+ });
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
 
@@ -469,10 +469,6 @@ var patchDefectsTransform = {
469
469
  // src/commands/db/gen-dbschema/transforms/ast/replace-unknown.ts
470
470
  import { Node as Node5 } from "ts-morph";
471
471
  var KNOWN_TYPE_FACTORIES = {
472
- // Domain types (new) - array handled natively via .array()
473
- user_profile_domain: "userType",
474
- file_attachment_domain: "fileType",
475
- // Legacy composite types (deprecated but kept for compatibility)
476
472
  user_profile: "userProfile",
477
473
  file_attachment: "fileAttachment"
478
474
  };
@@ -499,19 +495,18 @@ var replaceUnknownTransform = {
499
495
  const lines = textBefore.split("\n");
500
496
  let factoryName = "text";
501
497
  let foundKnownType = false;
502
- let shouldRemoveArray = false;
498
+ let isArrayType = false;
503
499
  for (let i = lines.length - 1; i >= Math.max(0, lines.length - 5); i--) {
504
500
  const line = lines[i];
505
501
  const todoMatch = line.match(/\/\/ TODO: failed to parse database type '(?:\w+\.)?([\w_]+)(\[\])?'/);
506
502
  if (todoMatch) {
507
- const baseTypeName = todoMatch[1];
508
- const isArrayType = todoMatch[2] === "[]";
509
- if (isArrayType && KNOWN_ARRAY_TYPE_FACTORIES[baseTypeName]) {
510
- factoryName = KNOWN_ARRAY_TYPE_FACTORIES[baseTypeName];
503
+ const typeName = todoMatch[1];
504
+ isArrayType = todoMatch[2] === "[]";
505
+ if (isArrayType && KNOWN_ARRAY_TYPE_FACTORIES[typeName]) {
506
+ factoryName = KNOWN_ARRAY_TYPE_FACTORIES[typeName];
511
507
  foundKnownType = true;
512
- shouldRemoveArray = true;
513
- } else if (KNOWN_TYPE_FACTORIES[baseTypeName]) {
514
- factoryName = KNOWN_TYPE_FACTORIES[baseTypeName];
508
+ } else if (KNOWN_TYPE_FACTORIES[typeName]) {
509
+ factoryName = KNOWN_TYPE_FACTORIES[typeName];
515
510
  foundKnownType = true;
516
511
  }
517
512
  break;
@@ -521,13 +516,13 @@ var replaceUnknownTransform = {
521
516
  expression,
522
517
  factoryName,
523
518
  foundKnownType,
524
- shouldRemoveArray,
519
+ isArrayType,
525
520
  node
526
521
  });
527
522
  });
528
- for (const { expression, factoryName, foundKnownType, shouldRemoveArray, node } of replacements) {
523
+ for (const { expression, factoryName, foundKnownType, isArrayType, node } of replacements) {
529
524
  expression.replaceWithText(factoryName);
530
- if (shouldRemoveArray) {
525
+ if (isArrayType && foundKnownType) {
531
526
  const parent = node.getParent();
532
527
  if (Node5.isPropertyAccessExpression(parent) && parent.getName() === "array") {
533
528
  const grandParent = parent.getParent();
@@ -4290,7 +4285,7 @@ var PROMPT_PATTERNS = [
4290
4285
  { pattern: /proceed\?/i, answer: "y\n" }
4291
4286
  ];
4292
4287
  async function executeShadcnAdd(registryItemPath) {
4293
- return new Promise((resolve) => {
4288
+ return new Promise((resolve2) => {
4294
4289
  let output = "";
4295
4290
  const args = ["--yes", "shadcn@3.8.2", "add", registryItemPath];
4296
4291
  const ptyProcess = pty.spawn("npx", args, {
@@ -4316,7 +4311,7 @@ async function executeShadcnAdd(registryItemPath) {
4316
4311
  });
4317
4312
  const timeoutId = setTimeout(() => {
4318
4313
  ptyProcess.kill();
4319
- resolve({
4314
+ resolve2({
4320
4315
  success: false,
4321
4316
  files: [],
4322
4317
  error: "\u6267\u884C\u8D85\u65F6"
@@ -4327,7 +4322,7 @@ async function executeShadcnAdd(registryItemPath) {
4327
4322
  const success = exitCode === 0;
4328
4323
  const filePaths = parseOutput(output);
4329
4324
  const files = filePaths.map(toFileInfo);
4330
- resolve({
4325
+ resolve2({
4331
4326
  success,
4332
4327
  files,
4333
4328
  error: success ? void 0 : output || `Process exited with code ${exitCode}`
@@ -4338,12 +4333,12 @@ async function executeShadcnAdd(registryItemPath) {
4338
4333
 
4339
4334
  // src/commands/component/add.handler.ts
4340
4335
  function runActionPluginInit() {
4341
- return new Promise((resolve) => {
4336
+ return new Promise((resolve2) => {
4342
4337
  execFile("fullstack-cli", ["action-plugin", "init"], { cwd: process.cwd(), stdio: "ignore" }, (error) => {
4343
4338
  if (error) {
4344
4339
  debug("action-plugin init \u5931\u8D25: %s", error.message);
4345
4340
  }
4346
- resolve();
4341
+ resolve2();
4347
4342
  });
4348
4343
  });
4349
4344
  }
@@ -7179,7 +7174,45 @@ async function genArtifactUploadCredential(appId, body) {
7179
7174
  const response = await client.post(url, body);
7180
7175
  if (!response.ok || response.status !== 200) {
7181
7176
  throw new Error(
7182
- `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}`
7183
7216
  );
7184
7217
  }
7185
7218
  return response.json();
@@ -7217,6 +7250,133 @@ function camelToKebab(str) {
7217
7250
  return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
7218
7251
  }
7219
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
+ var LOG_PREFIX = "[upload-static]";
7258
+ async function uploadStatic(options) {
7259
+ try {
7260
+ const {
7261
+ appId,
7262
+ staticDir = "shared/static",
7263
+ tosutilPath = "/workspace/tosutil",
7264
+ tosutilUrl,
7265
+ endpoint = "tos-cn-beijing.volces.com",
7266
+ region = "cn-beijing"
7267
+ } = options;
7268
+ const resolvedStaticDir = path21.resolve(staticDir);
7269
+ if (!fs25.existsSync(resolvedStaticDir)) {
7270
+ console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E0D\u5B58\u5728: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
7271
+ return;
7272
+ }
7273
+ if (isDirEmpty(resolvedStaticDir)) {
7274
+ console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E3A\u7A7A: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
7275
+ return;
7276
+ }
7277
+ const resolvedTosutilPath = ensureTosutil(tosutilPath, tosutilUrl);
7278
+ const bucketId = await resolveBucketId(appId);
7279
+ console.error(`${LOG_PREFIX} \u8C03\u7528 preUploadStatic...`);
7280
+ const preUploadResp = await fetchPreUpload(appId, bucketId);
7281
+ const { uploadPrefix, uploadID, uploadCredential } = preUploadResp.data;
7282
+ console.error(`${LOG_PREFIX} \u4E0A\u4F20\u76EE\u6807: ${uploadPrefix}`);
7283
+ console.error(`${LOG_PREFIX} \u914D\u7F6E tosutil...`);
7284
+ configureTosutil(resolvedTosutilPath, {
7285
+ endpoint,
7286
+ region,
7287
+ accessKeyID: uploadCredential.accessKeyID,
7288
+ secretAccessKey: uploadCredential.secretAccessKey,
7289
+ sessionToken: uploadCredential.sessionToken
7290
+ });
7291
+ console.error(`${LOG_PREFIX} \u4E0A\u4F20 ${resolvedStaticDir} -> ${uploadPrefix}`);
7292
+ uploadToTos(resolvedTosutilPath, resolvedStaticDir, uploadPrefix);
7293
+ console.error(`${LOG_PREFIX} tosutil \u4E0A\u4F20\u5B8C\u6210`);
7294
+ console.error(`${LOG_PREFIX} \u8C03\u7528 callbackStatic (uploadID: ${uploadID})...`);
7295
+ const callbackResp = await uploadStaticAttachmentCallback(appId, bucketId, { uploadID });
7296
+ if (callbackResp.status_code !== "0") {
7297
+ throw new Error(`callbackStatic \u8FD4\u56DE\u5F02\u5E38, status_code: ${callbackResp.status_code}`);
7298
+ }
7299
+ const attachments = callbackResp.data?.attachments || [];
7300
+ console.error(`${LOG_PREFIX} \u4E0A\u4F20\u5B8C\u6210\uFF0C\u5171 ${attachments.length} \u4E2A\u6587\u4EF6`);
7301
+ console.log(JSON.stringify(callbackResp));
7302
+ } catch (error) {
7303
+ const message = error instanceof Error ? error.message : String(error);
7304
+ console.error(`${LOG_PREFIX} Error: ${message}`);
7305
+ process.exit(1);
7306
+ }
7307
+ }
7308
+ async function fetchPreUpload(appId, bucketId) {
7309
+ const response = await preUploadStaticAttachment(appId, bucketId);
7310
+ if (response.status_code !== "0") {
7311
+ throw new Error(`preUploadStatic \u8FD4\u56DE\u5F02\u5E38, status_code: ${response.status_code}`);
7312
+ }
7313
+ const { uploadPrefix, uploadID, uploadCredential } = response.data || {};
7314
+ if (!uploadPrefix || !uploadID) {
7315
+ throw new Error("preUploadStatic \u8FD4\u56DE\u6570\u636E\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 uploadPrefix \u6216 uploadID");
7316
+ }
7317
+ if (!uploadCredential?.accessKeyID || !uploadCredential?.secretAccessKey || !uploadCredential?.sessionToken) {
7318
+ throw new Error("preUploadStatic \u8FD4\u56DE\u7684\u51ED\u8BC1\u5B57\u6BB5\u4E0D\u5B8C\u6574");
7319
+ }
7320
+ return response;
7321
+ }
7322
+ function ensureTosutil(tosutilPath, tosutilUrl) {
7323
+ if (isTosutilAvailable(tosutilPath)) {
7324
+ console.error(`${LOG_PREFIX} tosutil \u5DF2\u5C31\u7EEA: ${tosutilPath}`);
7325
+ return tosutilPath;
7326
+ }
7327
+ if (!tosutilUrl) {
7328
+ throw new Error(
7329
+ `tosutil \u4E0D\u53EF\u7528 (\u8DEF\u5F84: ${tosutilPath})\uFF0C\u4E14\u672A\u63D0\u4F9B --tosutil-url \u4E0B\u8F7D\u5730\u5740\u3002\u8BF7\u786E\u4FDD tosutil \u5DF2\u5B58\u5728\uFF0C\u6216\u901A\u8FC7 --tosutil-url \u6307\u5B9A\u4E0B\u8F7D\u5730\u5740\u3002`
7330
+ );
7331
+ }
7332
+ console.error(`${LOG_PREFIX} tosutil \u4E0D\u5B58\u5728\uFF0C\u4ECE ${tosutilUrl} \u4E0B\u8F7D...`);
7333
+ downloadTosutil(tosutilUrl, tosutilPath);
7334
+ if (!isTosutilAvailable(tosutilPath)) {
7335
+ throw new Error(`tosutil \u4E0B\u8F7D\u540E\u4ECD\u4E0D\u53EF\u7528 (\u8DEF\u5F84: ${tosutilPath})`);
7336
+ }
7337
+ console.error(`${LOG_PREFIX} tosutil \u4E0B\u8F7D\u5B8C\u6210: ${tosutilPath}`);
7338
+ return tosutilPath;
7339
+ }
7340
+ function isTosutilAvailable(tosutilPath) {
7341
+ try {
7342
+ execSync3(`${tosutilPath} --version`, { stdio: "pipe" });
7343
+ return true;
7344
+ } catch {
7345
+ return false;
7346
+ }
7347
+ }
7348
+ function downloadTosutil(url, destPath) {
7349
+ const destDir = path21.dirname(destPath);
7350
+ if (!fs25.existsSync(destDir)) {
7351
+ fs25.mkdirSync(destDir, { recursive: true });
7352
+ }
7353
+ execSync3(`curl -L --fail -o "${destPath}" "${url}"`, { stdio: "pipe" });
7354
+ execSync3(`chmod +x "${destPath}"`, { stdio: "pipe" });
7355
+ }
7356
+ function configureTosutil(tosutilPath, config) {
7357
+ const { endpoint, region, accessKeyID, secretAccessKey, sessionToken } = config;
7358
+ execSync3(
7359
+ `${tosutilPath} config -e ${endpoint} -i ${accessKeyID} -k ${secretAccessKey} -t ${sessionToken} -re ${region}`,
7360
+ { stdio: "pipe" }
7361
+ );
7362
+ }
7363
+ function uploadToTos(tosutilPath, sourceDir, destUrl) {
7364
+ execSync3(
7365
+ `${tosutilPath} cp "${sourceDir}" "${destUrl}" -r -flat -j 5 -p 3 -ps 10485760 -f`,
7366
+ { stdio: "inherit" }
7367
+ );
7368
+ }
7369
+ async function resolveBucketId(appId) {
7370
+ console.error(`${LOG_PREFIX} \u83B7\u53D6\u9ED8\u8BA4\u5B58\u50A8\u6876...`);
7371
+ const bucketId = await getDefaultBucketId(appId);
7372
+ console.error(`${LOG_PREFIX} \u9ED8\u8BA4\u5B58\u50A8\u6876: ${bucketId}`);
7373
+ return bucketId;
7374
+ }
7375
+ function isDirEmpty(dirPath) {
7376
+ const entries = fs25.readdirSync(dirPath);
7377
+ return entries.length === 0;
7378
+ }
7379
+
7220
7380
  // src/commands/build/index.ts
7221
7381
  var getTokenCommand = {
7222
7382
  name: "get-token",
@@ -7227,10 +7387,19 @@ var getTokenCommand = {
7227
7387
  });
7228
7388
  }
7229
7389
  };
7390
+ var uploadStaticCommand = {
7391
+ name: "upload-static",
7392
+ description: "Upload shared/static files to TOS",
7393
+ register(program) {
7394
+ 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("--tosutil-url <url>", "URL to download tosutil if not present").option("--endpoint <endpoint>", "TOS endpoint", "tos-cn-beijing.volces.com").option("--region <region>", "TOS region", "cn-beijing").action(async (options) => {
7395
+ await uploadStatic(options);
7396
+ });
7397
+ }
7398
+ };
7230
7399
  var buildCommandGroup = {
7231
7400
  name: "build",
7232
7401
  description: "Build related commands",
7233
- commands: [getTokenCommand]
7402
+ commands: [getTokenCommand, uploadStaticCommand]
7234
7403
  };
7235
7404
 
7236
7405
  // src/commands/index.ts
@@ -7247,12 +7416,12 @@ var commands = [
7247
7416
  ];
7248
7417
 
7249
7418
  // src/index.ts
7250
- var envPath = path21.join(process.cwd(), ".env");
7251
- if (fs25.existsSync(envPath)) {
7419
+ var envPath = path22.join(process.cwd(), ".env");
7420
+ if (fs26.existsSync(envPath)) {
7252
7421
  dotenvConfig({ path: envPath });
7253
7422
  }
7254
- var __dirname = path21.dirname(fileURLToPath5(import.meta.url));
7255
- var pkg = JSON.parse(fs25.readFileSync(path21.join(__dirname, "../package.json"), "utf-8"));
7423
+ var __dirname = path22.dirname(fileURLToPath5(import.meta.url));
7424
+ var pkg = JSON.parse(fs26.readFileSync(path22.join(__dirname, "../package.json"), "utf-8"));
7256
7425
  var cli = new FullstackCLI(pkg.version);
7257
7426
  cli.useAll(commands);
7258
7427
  cli.run();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.22-alpha.25",
3
+ "version": "1.1.22-alpha.26",
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
  "collection": "@nestjs/schematics",
4
4
  "sourceRoot": "server",
5
5
  "compilerOptions": {
6
- "deleteOutDir": true,
6
+ "deleteOutDir": false,
7
7
  "tsConfigPath": "tsconfig.node.json",
8
8
  "assets": [
9
9
  {
@@ -19,28 +19,28 @@ 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] 并行构建 server 和 client"
44
44
  STEP_START=$(node -e "console.log(Date.now())")
45
45
 
46
46
  # 并行构建
@@ -78,7 +78,7 @@ print_time $STEP_START
78
78
  echo ""
79
79
 
80
80
  # ==================== 步骤 4 ====================
81
- echo "📦 [4/5] 准备 server 依赖产物"
81
+ echo "📦 [4/6] 准备 server 依赖产物"
82
82
  STEP_START=$(node -e "console.log(Date.now())")
83
83
 
84
84
  mkdir -p "$OUT_DIR/dist/client"
@@ -97,7 +97,7 @@ print_time $STEP_START
97
97
  echo ""
98
98
 
99
99
  # ==================== 步骤 5 ====================
100
- echo "✂️ [5/5] 智能依赖裁剪"
100
+ echo "✂️ [5/6] 智能依赖裁剪"
101
101
  STEP_START=$(node -e "console.log(Date.now())")
102
102
 
103
103
  # 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
@@ -106,6 +106,25 @@ node "$ROOT_DIR/scripts/prune-smart.js"
106
106
  print_time $STEP_START
107
107
  echo ""
108
108
 
109
+ # ==================== 步骤 6 ====================
110
+ echo "☁️ [6/6] 上传静态资源到 TOS"
111
+ STEP_START=$(node -e "console.log(Date.now())")
112
+
113
+ # 环境变量(与产物上传脚本共享同一 CI 环境):
114
+ # app_id - 应用 ID
115
+ # tosutil_url - tosutil 下载地址
116
+ # bucket_id 由 CLI 自动通过 get_published_v2 获取,也可通过 --bucket-id 显式指定
117
+ if [ -d "$ROOT_DIR/shared/static" ] && [ "$(ls -A "$ROOT_DIR/shared/static" 2>/dev/null)" ]; then
118
+ npx fullstack-cli build upload-static \
119
+ --app-id "${app_id}" \
120
+ --tosutil-url "${tosutil_url}"
121
+ else
122
+ echo " ⏭️ shared/static 目录为空或不存在,跳过上传"
123
+ fi
124
+
125
+ print_time $STEP_START
126
+ echo ""
127
+
109
128
  # 总耗时
110
129
  echo "构建完成"
111
130
  print_time $TOTAL_START