@lightfish/cli 0.0.4 → 0.0.5

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.
Files changed (2) hide show
  1. package/dist/lightfish.js +407 -9
  2. package/package.json +4 -1
package/dist/lightfish.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/lightfish.ts
4
4
  import cac from "cac";
5
- import { execa as execa3 } from "execa";
5
+ import { execa as execa4 } from "execa";
6
6
 
7
7
  // src/commands/create.ts
8
8
  import path4 from "path";
@@ -364,30 +364,409 @@ async function createProject(options = {}) {
364
364
  return resolvedOptions;
365
365
  }
366
366
 
367
- // src/utils/package-info.ts
367
+ // src/commands/publish.ts
368
+ import fs8 from "fs";
369
+ import path8 from "path";
370
+
371
+ // src/utils/env.ts
368
372
  import fs5 from "fs";
369
373
  import path5 from "path";
374
+ import { parse } from "dotenv";
375
+ var DEFAULT_BASE_ROOT = "https://lf-frontend.oss-cn-beijing.aliyuncs.com";
376
+ function loadDotenv({ cwd, envPath }) {
377
+ let merged;
378
+ if (envPath) {
379
+ merged = readEnvFile(path5.resolve(cwd, envPath));
380
+ } else {
381
+ const base = readEnvFile(path5.resolve(cwd, ".env"));
382
+ const local = readEnvFile(path5.resolve(cwd, ".env.local"));
383
+ merged = { ...base, ...local };
384
+ }
385
+ for (const [key, value] of Object.entries(merged)) {
386
+ if (process.env[key] === void 0) {
387
+ process.env[key] = value;
388
+ }
389
+ }
390
+ }
391
+ function readEnvFile(file) {
392
+ if (!fs5.existsSync(file)) return {};
393
+ return parse(fs5.readFileSync(file, "utf8"));
394
+ }
395
+ function getRequiredEnvNames({ notify, serverDetected }) {
396
+ const required = ["OSS_REGION", "OSS_BUCKET", "OSS_ACCESS_KEYID", "OSS_ACCESS_KEYSECRECT"];
397
+ if (notify) required.push("DEPLOY_API_URL");
398
+ if (serverDetected) required.push("DATABASE_URL");
399
+ return required;
400
+ }
401
+ function resolvePublishEnv(options, env = process.env) {
402
+ const required = getRequiredEnvNames(options);
403
+ const missing = required.filter((name) => !env[name]);
404
+ if (missing.length > 0) {
405
+ throw new Error(
406
+ `\u7F3A\u5C11\u5FC5\u9700\u73AF\u5883\u53D8\u91CF:${missing.join(", ")}(\u8BF7\u5728 .env / .env.local \u6216\u73AF\u5883\u53D8\u91CF\u4E2D\u914D\u7F6E)`
407
+ );
408
+ }
409
+ return {
410
+ ossRegion: env.OSS_REGION,
411
+ ossBucket: env.OSS_BUCKET,
412
+ ossAccessKeyId: env.OSS_ACCESS_KEYID,
413
+ // 注意:变量名沿用 CI secrets 的拼写(SECRECT),保持 .env 兼容
414
+ ossAccessKeySecret: env.OSS_ACCESS_KEYSECRECT,
415
+ deployApiUrl: options.notify ? env.DEPLOY_API_URL : void 0,
416
+ databaseUrl: env.DATABASE_URL,
417
+ baseRoot: env.BASE_ROOT || DEFAULT_BASE_ROOT
418
+ };
419
+ }
420
+
421
+ // src/utils/build.ts
422
+ import fs6 from "fs";
423
+ import path6 from "path";
424
+ import { execa as execa3 } from "execa";
425
+ var SERVER_CONFIG_FILES = [
426
+ "lightfish-server.config.js",
427
+ "lightfish-server.config.ts",
428
+ "lightfish-server.config.mjs",
429
+ "lightfish-server.config.cjs"
430
+ ];
431
+ var VITE_CONFIG_FILES = [
432
+ "vite.config.ts",
433
+ "vite.config.js",
434
+ "vite.config.mts",
435
+ "vite.config.mjs",
436
+ "vite.config.cjs"
437
+ ];
438
+ function readPackageJson(cwd) {
439
+ const file = path6.join(cwd, "package.json");
440
+ if (!fs6.existsSync(file)) return void 0;
441
+ return JSON.parse(fs6.readFileSync(file, "utf8"));
442
+ }
443
+ function hasVite(cwd) {
444
+ if (VITE_CONFIG_FILES.some((f) => fs6.existsSync(path6.join(cwd, f)))) return true;
445
+ const pkg = readPackageJson(cwd);
446
+ if (pkg) {
447
+ const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
448
+ if ("vite" in deps) return true;
449
+ }
450
+ return false;
451
+ }
452
+ function detectBuild(cwd) {
453
+ return {
454
+ vite: hasVite(cwd),
455
+ server: SERVER_CONFIG_FILES.some((f) => fs6.existsSync(path6.join(cwd, f)))
456
+ };
457
+ }
458
+ async function runBuildSteps(options) {
459
+ const detection = detectBuild(options.cwd);
460
+ if (!detection.vite && !detection.server) {
461
+ throw new Error("\u672A\u68C0\u6D4B\u5230 Vite \u6216 lightfish-server,\u65E0\u6CD5\u6784\u5EFA");
462
+ }
463
+ const execOptions = {
464
+ cwd: options.cwd,
465
+ preferLocal: true,
466
+ stdio: "inherit",
467
+ env: { ...process.env, ...options.env }
468
+ };
469
+ if (detection.vite) {
470
+ await execa3("vite", ["build"], execOptions);
471
+ }
472
+ if (detection.server) {
473
+ await execa3("lightfish-server", ["build"], execOptions);
474
+ await execa3("lightfish-server", ["db", "push"], execOptions);
475
+ }
476
+ }
477
+
478
+ // src/utils/oss.ts
479
+ import OSS from "ali-oss";
480
+ import fs7 from "fs";
481
+ import path7 from "path";
482
+ function withPrefix(prefix, key) {
483
+ const normalized = prefix.replace(/^\/+/, "").replace(/\/+$/, "");
484
+ if (!normalized) return key;
485
+ return `${normalized}/${key}`;
486
+ }
487
+ function walkDir(dir, base = "") {
488
+ if (!fs7.existsSync(dir)) return [];
489
+ const entries = fs7.readdirSync(dir, { withFileTypes: true });
490
+ const files = [];
491
+ for (const entry of entries) {
492
+ const fullPath = path7.join(dir, entry.name);
493
+ const key = base ? `${base}/${entry.name}` : entry.name;
494
+ if (entry.isDirectory()) {
495
+ files.push(...walkDir(fullPath, key));
496
+ } else {
497
+ files.push({ localPath: fullPath, key });
498
+ }
499
+ }
500
+ return files;
501
+ }
502
+ async function uploadDist(options, client) {
503
+ const oss = client ?? createClient(options);
504
+ const files = walkDir(options.distDir);
505
+ console.log(`[publish] Found ${files.length} files to upload`);
506
+ const results = await Promise.all(
507
+ files.map(({ localPath, key }) => {
508
+ const objectKey = withPrefix(options.objectPrefix, key);
509
+ return oss.put(objectKey, localPath).then((res) => ({ key: objectKey, ok: res.res.status === 200 })).catch((err) => {
510
+ const message = err instanceof Error ? err.message : String(err);
511
+ console.error(`[publish] ERROR ${objectKey}: ${message}`);
512
+ return { key: objectKey, ok: false };
513
+ });
514
+ })
515
+ );
516
+ for (const r of results.filter((r2) => r2.ok)) {
517
+ console.log(`[publish] ok ${r.key}`);
518
+ }
519
+ const ok = results.filter((r) => r.ok).length;
520
+ const fail = results.filter((r) => !r.ok).length;
521
+ console.log(`[publish] Done: ${ok} succeeded, ${fail} failed`);
522
+ return { ok, fail };
523
+ }
524
+ function createClient(options) {
525
+ return new OSS({
526
+ region: options.region,
527
+ accessKeyId: options.accessKeyId,
528
+ accessKeySecret: options.accessKeySecret,
529
+ bucket: options.bucket
530
+ });
531
+ }
532
+
533
+ // src/utils/notify.ts
534
+ async function notifyDeploy(options) {
535
+ const fetchFn = options.fetchImpl ?? fetch;
536
+ const body = JSON.stringify(options.payload);
537
+ console.log(`[publish] POST ${options.apiUrl}`);
538
+ console.log(`[publish] body: ${body}`);
539
+ let res;
540
+ try {
541
+ res = await fetchFn(options.apiUrl, {
542
+ method: "POST",
543
+ headers: { "Content-Type": "application/json" },
544
+ body
545
+ });
546
+ } catch (err) {
547
+ const message = err instanceof Error ? err.message : String(err);
548
+ throw new Error(`\u90E8\u7F72 API \u8BF7\u6C42\u5931\u8D25:${message}`);
549
+ }
550
+ if (!res.ok) {
551
+ throw new Error(`\u90E8\u7F72 API \u8FD4\u56DE HTTP ${res.status}`);
552
+ }
553
+ let data;
554
+ try {
555
+ data = await res.json();
556
+ } catch {
557
+ throw new Error("\u90E8\u7F72 API \u54CD\u5E94\u975E JSON");
558
+ }
559
+ console.log(`[publish] response: ${JSON.stringify(data)}`);
560
+ if (typeof data?.success !== "boolean" || data.success !== true) {
561
+ throw new Error("\u90E8\u7F72 API \u672A\u8FD4\u56DE success=true");
562
+ }
563
+ }
564
+
565
+ // src/commands/publish.ts
566
+ function generateVersion(date = /* @__PURE__ */ new Date()) {
567
+ return date.toISOString().replace(/[-T:.Z]/g, "").slice(0, 14);
568
+ }
569
+ function readPackageJsonName(cwd) {
570
+ const file = path8.join(cwd, "package.json");
571
+ if (!fs8.existsSync(file)) return void 0;
572
+ const pkg = JSON.parse(fs8.readFileSync(file, "utf8"));
573
+ return pkg.name;
574
+ }
575
+ function resolveAppName(options) {
576
+ if (options.app) return options.app;
577
+ const pkgName = readPackageJsonName(options.cwd);
578
+ if (pkgName) {
579
+ return pkgName.startsWith("@") ? pkgName.replace(/^@[^/]+\//, "") : pkgName;
580
+ }
581
+ throw new Error("\u65E0\u6CD5\u786E\u5B9A APP_NAME:\u8BF7\u901A\u8FC7 --app \u6307\u5B9A,\u6216\u786E\u4FDD package.json \u542B name \u5B57\u6BB5");
582
+ }
583
+ function assertNumericVersion(version) {
584
+ if (!/^\d+$/.test(version)) {
585
+ throw new Error(`version \u5FC5\u987B\u4E3A\u7EAF\u6570\u5B57(\u4E0E\u90E8\u7F72 API \u7684 number \u5951\u7EA6\u4E00\u81F4),\u6536\u5230:${version}`);
586
+ }
587
+ }
588
+ function resolveOptions(options) {
589
+ const cwd = options.cwd ?? process.cwd();
590
+ const appName = resolveAppName({ cwd, app: options.app });
591
+ const version = options.version ?? generateVersion();
592
+ assertNumericVersion(version);
593
+ const distDir = path8.resolve(cwd, options.dist ?? "dist");
594
+ const notify = !options.noNotify;
595
+ const baseRoot = process.env.BASE_ROOT || DEFAULT_BASE_ROOT;
596
+ const root = baseRoot.replace(/\/+$/, "");
597
+ const viteBaseUrl = root ? `${root}/${appName}/${version}/` : `/${appName}/${version}/`;
598
+ const objectPrefix = `${appName}/${version}`;
599
+ const ossIndexUrl = `${root}/${appName}/${version}/index.html`;
600
+ return {
601
+ cwd,
602
+ appName,
603
+ version,
604
+ distDir,
605
+ baseRoot,
606
+ root,
607
+ viteBaseUrl,
608
+ objectPrefix,
609
+ ossIndexUrl,
610
+ notify,
611
+ skipBuild: options.skipBuild ?? false,
612
+ note: options.note
613
+ };
614
+ }
615
+ function printBuildPlanDryRun(detection) {
616
+ if (!detection.vite && !detection.server) {
617
+ console.log("[publish] (dry-run) \u672A\u68C0\u6D4B\u5230 Vite \u6216 lightfish-server,\u6784\u5EFA\u5C06\u5931\u8D25");
618
+ return;
619
+ }
620
+ console.log("[publish] (dry-run) \u5C06\u6267\u884C\u6784\u5EFA:");
621
+ if (detection.vite) console.log("[publish] (dry-run) vite build");
622
+ if (detection.server) {
623
+ console.log("[publish] (dry-run) lightfish-server build");
624
+ console.log("[publish] (dry-run) lightfish-server db push");
625
+ }
626
+ }
627
+ function printEnvDryRun(serverDetected, notify) {
628
+ const required = getRequiredEnvNames({ notify, serverDetected });
629
+ console.log("[publish] (dry-run) \u73AF\u5883\u53D8\u91CF\u9884\u68C0:");
630
+ for (const name of required) {
631
+ const present = process.env[name] !== void 0 && process.env[name] !== "";
632
+ console.log(`[publish] (dry-run) ${present ? "\u2713" : "\u2717"} ${name}`);
633
+ }
634
+ }
635
+ function printUploadPlanDryRun(options) {
636
+ const files = walkDir(options.distDir);
637
+ if (files.length === 0) {
638
+ console.log(`[publish] (dry-run) \u4EA7\u7269\u76EE\u5F55 ${options.distDir} \u4E3A\u7A7A\u6216\u4E0D\u5B58\u5728(\u6784\u5EFA\u540E\u5C06\u751F\u6210)`);
639
+ return;
640
+ }
641
+ console.log(`[publish] (dry-run) \u5C06\u4E0A\u4F20 ${files.length} \u4E2A\u6587\u4EF6\u5230 OSS \u524D\u7F00:${options.objectPrefix}/`);
642
+ for (const { key } of files) {
643
+ console.log(`[publish] (dry-run) ${withPrefix(options.objectPrefix, key)}`);
644
+ }
645
+ }
646
+ function buildNotifyPayload(params) {
647
+ const payload = {
648
+ id: params.appName,
649
+ version: Number(params.version),
650
+ ossIndexUrl: params.ossIndexUrl,
651
+ domain: `https://${params.appName}.lightfish.top`
652
+ };
653
+ if (params.note) payload.note = params.note;
654
+ return payload;
655
+ }
656
+ function printNotifyPlanDryRun(options, pubEnv) {
657
+ if (!options.notify) {
658
+ console.log("[publish] (dry-run) \u901A\u77E5\u5DF2\u8DF3\u8FC7(--no-notify)");
659
+ return;
660
+ }
661
+ const payload = buildNotifyPayload({
662
+ appName: options.appName,
663
+ version: options.version,
664
+ ossIndexUrl: options.ossIndexUrl,
665
+ note: options.note
666
+ });
667
+ console.log("[publish] (dry-run) \u5C06 POST \u901A\u77E5:");
668
+ console.log(`[publish] (dry-run) url: ${pubEnv.deployApiUrl ?? "(\u672A\u914D\u7F6E DEPLOY_API_URL)"}`);
669
+ console.log(`[publish] (dry-run) body: ${JSON.stringify(payload)}`);
670
+ }
671
+ async function runPublish(options = {}) {
672
+ const cwd = options.cwd ?? process.cwd();
673
+ loadDotenv({ cwd, envPath: options.envPath });
674
+ const resolved = resolveOptions(options);
675
+ console.log(`[publish] app=${resolved.appName} version=${resolved.version} dist=${resolved.distDir}`);
676
+ let serverDetected = false;
677
+ if (!resolved.skipBuild) {
678
+ const detection = detectBuild(resolved.cwd);
679
+ serverDetected = detection.server;
680
+ if (options.dryRun) {
681
+ printBuildPlanDryRun(detection);
682
+ } else {
683
+ console.log("[publish] \u5F00\u59CB\u6784\u5EFA...");
684
+ const buildEnv = {
685
+ VITE_BASE_URL: resolved.viteBaseUrl,
686
+ BASE_ROOT: resolved.baseRoot,
687
+ APP_NAME: resolved.appName,
688
+ BUILD_VERSION: resolved.version
689
+ };
690
+ if (process.env.DATABASE_URL) buildEnv.DATABASE_URL = process.env.DATABASE_URL;
691
+ await runBuildSteps({
692
+ cwd: resolved.cwd,
693
+ env: buildEnv
694
+ });
695
+ console.log("[publish] \u6784\u5EFA\u5B8C\u6210");
696
+ }
697
+ }
698
+ const pubEnv = options.dryRun ? softResolveEnv(resolved.notify, serverDetected) : resolvePublishEnv({ notify: resolved.notify, serverDetected });
699
+ if (options.dryRun) {
700
+ printEnvDryRun(serverDetected, resolved.notify);
701
+ printUploadPlanDryRun(resolved);
702
+ printNotifyPlanDryRun(resolved, pubEnv);
703
+ console.log("[publish] (dry-run) \u5B8C\u6210,\u672A\u6267\u884C\u4EFB\u4F55\u526F\u4F5C\u7528");
704
+ return;
705
+ }
706
+ if (!fs8.existsSync(resolved.distDir)) {
707
+ throw new Error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728:${resolved.distDir}`);
708
+ }
709
+ console.log("[publish] \u5F00\u59CB\u4E0A\u4F20 OSS...");
710
+ const { fail } = await uploadDist({
711
+ region: pubEnv.ossRegion,
712
+ bucket: pubEnv.ossBucket,
713
+ accessKeyId: pubEnv.ossAccessKeyId,
714
+ accessKeySecret: pubEnv.ossAccessKeySecret,
715
+ objectPrefix: resolved.objectPrefix,
716
+ distDir: resolved.distDir
717
+ });
718
+ if (fail > 0) {
719
+ throw new Error(`OSS \u4E0A\u4F20\u6709 ${fail} \u4E2A\u6587\u4EF6\u5931\u8D25`);
720
+ }
721
+ console.log("[publish] OSS \u4E0A\u4F20\u5B8C\u6210");
722
+ if (resolved.notify) {
723
+ console.log("[publish] \u5F00\u59CB\u901A\u77E5\u90E8\u7F72 API...");
724
+ const payload = buildNotifyPayload({
725
+ appName: resolved.appName,
726
+ version: resolved.version,
727
+ ossIndexUrl: resolved.ossIndexUrl,
728
+ note: resolved.note
729
+ });
730
+ await notifyDeploy({ apiUrl: pubEnv.deployApiUrl, payload });
731
+ console.log("[publish] \u901A\u77E5\u5B8C\u6210");
732
+ }
733
+ }
734
+ function softResolveEnv(notify, serverDetected) {
735
+ return {
736
+ ossRegion: process.env.OSS_REGION ?? "",
737
+ ossBucket: process.env.OSS_BUCKET ?? "",
738
+ ossAccessKeyId: process.env.OSS_ACCESS_KEYID ?? "",
739
+ ossAccessKeySecret: process.env.OSS_ACCESS_KEYSECRECT ?? "",
740
+ deployApiUrl: notify ? process.env.DEPLOY_API_URL : void 0,
741
+ databaseUrl: process.env.DATABASE_URL,
742
+ baseRoot: process.env.BASE_ROOT || DEFAULT_BASE_ROOT
743
+ };
744
+ }
745
+
746
+ // src/utils/package-info.ts
747
+ import fs9 from "fs";
748
+ import path9 from "path";
370
749
  import { fileURLToPath } from "url";
371
- var dirname = path5.dirname(fileURLToPath(import.meta.url));
750
+ var dirname = path9.dirname(fileURLToPath(import.meta.url));
372
751
  function readPackageVersion() {
373
752
  const packageJsonPathCandidates = [
374
753
  // 源码模式:src/utils/package-info.ts -> packages/cli/package.json
375
- path5.resolve(dirname, "../../package.json"),
754
+ path9.resolve(dirname, "../../package.json"),
376
755
  // 构建产物模式:dist/lightfish.js -> packages/cli/package.json
377
- path5.resolve(dirname, "../package.json")
756
+ path9.resolve(dirname, "../package.json")
378
757
  ];
379
- const packageJsonPath = packageJsonPathCandidates.find((candidate) => fs5.existsSync(candidate));
758
+ const packageJsonPath = packageJsonPathCandidates.find((candidate) => fs9.existsSync(candidate));
380
759
  if (!packageJsonPath) {
381
760
  return "0.0.0";
382
761
  }
383
- const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf8"));
762
+ const packageJson = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
384
763
  return packageJson.version ?? "0.0.0";
385
764
  }
386
765
 
387
766
  // src/lightfish.ts
388
767
  var cli = cac("lightfish");
389
768
  async function runBuild() {
390
- await execa3("vite", ["build"], {
769
+ await execa4("vite", ["build"], {
391
770
  cwd: process.cwd(),
392
771
  preferLocal: true,
393
772
  stdio: "inherit"
@@ -424,9 +803,28 @@ cli.command("build", "\u6267\u884C Vite \u6784\u5EFA\uFF0C\u540E\u7EED\u4F1A\u53
424
803
  process.exitCode = 1;
425
804
  }
426
805
  });
806
+ cli.command("publish", "\u6784\u5EFA\u5E76\u90E8\u7F72\u5230 OSS\uFF0C\u901A\u77E5\u90E8\u7F72 API").option("--app <name>", "\u8986\u76D6 APP_NAME\uFF08\u9ED8\u8BA4 package.json#name \u53BB scope\uFF09").option("--version <v>", "\u8986\u76D6 BUILD_VERSION\uFF08\u9ED8\u8BA4 UTC \u65F6\u95F4\u6233 YYYYMMDDHHmmss\uFF09").option("--dist <dir>", "\u4EA7\u7269\u76EE\u5F55", { default: "dist" }).option("--note <text>", "\u901A\u77E5 body \u7684 note \u5B57\u6BB5\uFF0C\u4E0D\u4F20\u5219\u7701\u7565").option("--env <path>", "\u6307\u5B9A .env \u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 cwd/.env + .env.local\uFF09").option("--no-build", "\u8DF3\u8FC7\u6784\u5EFA\uFF0C\u4F7F\u7528\u5DF2\u6709 dist").option("--no-notify", "\u8DF3\u8FC7\u901A\u77E5\u90E8\u7F72 API").option("--dry-run", "\u53EA\u6253\u5370\u5C06\u505A\u4EC0\u4E48\uFF0C\u4E0D\u6267\u884C").action(async (options) => {
807
+ try {
808
+ await runPublish({
809
+ app: options.app,
810
+ version: options.version,
811
+ dist: options.dist,
812
+ note: options.note,
813
+ envPath: options.env,
814
+ skipBuild: options.build === false,
815
+ noNotify: options.notify === false,
816
+ dryRun: options.dryRun
817
+ });
818
+ process.exit(0);
819
+ } catch (error) {
820
+ const message = error instanceof Error ? error.message : String(error);
821
+ console.error(`\u53D1\u5E03\u5931\u8D25\uFF1A${message}`);
822
+ process.exit(1);
823
+ }
824
+ });
427
825
  cli.command("", "\u663E\u793A\u5E2E\u52A9").action(() => {
428
826
  cli.outputHelp();
429
827
  });
430
828
  cli.help();
431
- cli.version(readPackageVersion());
829
+ cli.version(readPackageVersion(), "-v, --cli-version");
432
830
  cli.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightfish/cli",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -18,12 +18,15 @@
18
18
  "lint": "tsc --noEmit"
19
19
  },
20
20
  "dependencies": {
21
+ "ali-oss": "^6.23.0",
21
22
  "cac": "^7.0.0",
23
+ "dotenv": "^16.6.1",
22
24
  "execa": "^9.6.1",
23
25
  "fs-extra": "^11.3.5",
24
26
  "prompts": "^2.4.2"
25
27
  },
26
28
  "devDependencies": {
29
+ "@types/ali-oss": "^6.23.3",
27
30
  "@types/fs-extra": "^11.0.4",
28
31
  "@types/prompts": "^2.4.9"
29
32
  }