@adep/cli 0.3.1 → 0.4.0

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
@@ -23736,13 +23736,67 @@ var init_demo = __esm({
23736
23736
  });
23737
23737
 
23738
23738
  // packages/runtime/src/functions/runtime/exports.ts
23739
+ function keepLineCount(matched, lead) {
23740
+ const consumed = matched.split("\n").length - 1;
23741
+ const kept = lead === "\n" ? 1 : 0;
23742
+ return "\n".repeat(Math.max(0, consumed - kept));
23743
+ }
23744
+ function parseSpecifier(part) {
23745
+ const asMatch = /^([A-Za-z_$][\w$]*)\s+as\s+([A-Za-z_$][\w$]*)$/.exec(part);
23746
+ if (asMatch !== null) {
23747
+ const [, local, exported] = asMatch;
23748
+ if (local !== void 0 && exported !== void 0) return [local, exported];
23749
+ }
23750
+ return /^[A-Za-z_$][\w$]*$/.test(part) ? [part, part] : null;
23751
+ }
23752
+ function namedImportsToDestructure(clause) {
23753
+ const parts = [];
23754
+ for (const raw of clause.split(",")) {
23755
+ const part = raw.trim();
23756
+ if (part === "") continue;
23757
+ const spec = parseSpecifier(part);
23758
+ if (spec === null) {
23759
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u5177\u540D\u5BFC\u5165\u5F62\u6001\uFF1A"${part}"\uFF08\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7 a \u6216 a as b\uFF09`);
23760
+ }
23761
+ parts.push(spec[0] === spec[1] ? spec[0] : `${spec[0]}: ${spec[1]}`);
23762
+ }
23763
+ return parts;
23764
+ }
23765
+ function parseExportClause(clause) {
23766
+ const entries = [];
23767
+ for (const raw of clause.split(",")) {
23768
+ const part = raw.trim();
23769
+ if (part === "") continue;
23770
+ const spec = parseSpecifier(part);
23771
+ if (spec === null) {
23772
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u518D\u5BFC\u51FA\u5B50\u53E5\uFF1A"${part}"\uFF08\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7 a \u6216 a as b\uFF09`);
23773
+ }
23774
+ entries.push({ local: spec[0], exported: spec[1] });
23775
+ }
23776
+ return entries;
23777
+ }
23739
23778
  function transformModule(code) {
23740
23779
  let out = code;
23741
23780
  const named = [];
23781
+ const starReexports = [];
23782
+ let tempSeq = 0;
23783
+ const nextTemp = () => `__adep_reexport_${tempSeq++}`;
23742
23784
  out = out.replace(/(^|\n)(\s*)export\s+default\s+/g, "$1$2module.default = ");
23743
23785
  out = out.replace(
23744
23786
  /import\s*\{([^}]*)\}\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
23745
- (_match, names, source) => `const {${names}} = require(${source})`
23787
+ (matched, clause, source) => {
23788
+ const parts = namedImportsToDestructure(clause);
23789
+ const pad = keepLineCount(matched, "");
23790
+ return parts.length === 0 ? `require(${source})${pad}` : `const { ${parts.join(", ")} } = require(${source})${pad}`;
23791
+ }
23792
+ );
23793
+ out = out.replace(
23794
+ /import\s+([A-Za-z_$][\w$]*)\s*,\s*\{([^}]*)\}\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
23795
+ (matched, name, clause, source) => {
23796
+ const parts = namedImportsToDestructure(clause);
23797
+ const pad = keepLineCount(matched, "");
23798
+ return parts.length === 0 ? `const ${name} = require(${source})${pad}` : `const ${name} = require(${source}), { ${parts.join(", ")} } = ${name}${pad}`;
23799
+ }
23746
23800
  );
23747
23801
  out = out.replace(
23748
23802
  /import\s*\*\s*as\s*([A-Za-z_$][\w$]*)\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
@@ -23752,27 +23806,67 @@ function transformModule(code) {
23752
23806
  /import\s+([A-Za-z_$][\w$]*)\s+from\s*(['"][^'"]*['"])[ \t]*;?/g,
23753
23807
  (_match, name, source) => `const ${name} = require(${source})`
23754
23808
  );
23809
+ out = out.replace(
23810
+ /(^|\n)([ \t]*)import\s*(['"][^'"]*['"])[ \t]*;?/g,
23811
+ (_match, lead, indent, source) => `${lead}${indent}require(${source})`
23812
+ );
23813
+ out = out.replace(
23814
+ /(^|\n)([ \t]*)export\s*\{([^}]*)\}[ \t]*(?:\n[ \t]*(?=from\b))?(?:from\s*(['"][^'"]*['"]))?[ \t]*;?/g,
23815
+ (matched, lead, indent, clause, source) => {
23816
+ const pad = keepLineCount(matched, lead);
23817
+ const entries = parseExportClause(clause);
23818
+ if (entries.length === 0) return `${lead}${indent}${pad}`;
23819
+ if (source === void 0) {
23820
+ named.push(...entries);
23821
+ return `${lead}${indent}${pad}`;
23822
+ }
23823
+ const temp = nextTemp();
23824
+ for (const entry of entries) {
23825
+ named.push({ local: `${temp}.${entry.local}`, exported: entry.exported });
23826
+ }
23827
+ return `${lead}${indent}const ${temp} = require(${source})${pad}`;
23828
+ }
23829
+ );
23830
+ out = out.replace(
23831
+ /(^|\n)([ \t]*)export\s*\*[ \t]*(?:as[ \t]+([A-Za-z_$][\w$]*)[ \t]*)?\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
23832
+ (matched, lead, indent, ns, source) => {
23833
+ const pad = keepLineCount(matched, lead);
23834
+ const temp = nextTemp();
23835
+ if (ns === void 0) starReexports.push(temp);
23836
+ else named.push({ local: temp, exported: ns });
23837
+ return `${lead}${indent}const ${temp} = require(${source})${pad}`;
23838
+ }
23839
+ );
23755
23840
  out = out.replace(
23756
23841
  /export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
23757
23842
  (_match, kw, name) => {
23758
- named.push(name);
23843
+ named.push({ local: name, exported: name });
23759
23844
  return `${kw} ${name}`;
23760
23845
  }
23761
23846
  );
23762
23847
  out = out.replace(
23763
23848
  /export\s+(async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/g,
23764
23849
  (_match, asyncKw, name) => {
23765
- named.push(name);
23850
+ named.push({ local: name, exported: name });
23766
23851
  return `${asyncKw ?? ""}function ${name}`;
23767
23852
  }
23768
23853
  );
23769
23854
  out = out.replace(/export\s+class\s+([A-Za-z_$][\w$]*)/g, (_match, name) => {
23770
- named.push(name);
23855
+ named.push({ local: name, exported: name });
23771
23856
  return `class ${name}`;
23772
23857
  });
23773
- if (named.length > 0) {
23858
+ for (const temp of starReexports) {
23859
+ out += `
23860
+ ;Object.keys(${temp}).forEach((k) => { if (k !== 'default') exports[k] = ${temp}[k] })`;
23861
+ }
23862
+ const byExported = /* @__PURE__ */ new Map();
23863
+ for (const entry of named) byExported.set(entry.exported, entry.local);
23864
+ if (byExported.size > 0) {
23865
+ const picks = [...byExported].map(
23866
+ ([exported, local]) => local === exported ? exported : `${exported}: ${local}`
23867
+ );
23774
23868
  out += `
23775
- ;Object.assign(exports, { ${named.join(", ")} })`;
23869
+ ;Object.assign(exports, { ${picks.join(", ")} })`;
23776
23870
  }
23777
23871
  return out;
23778
23872
  }
@@ -23782,6 +23876,16 @@ var init_exports = __esm({
23782
23876
  }
23783
23877
  });
23784
23878
 
23879
+ // packages/runtime/src/shared/regexp.ts
23880
+ function escapeRegExp(text) {
23881
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23882
+ }
23883
+ var init_regexp = __esm({
23884
+ "packages/runtime/src/shared/regexp.ts"() {
23885
+ "use strict";
23886
+ }
23887
+ });
23888
+
23785
23889
  // packages/runtime/src/functions/runtime/sandbox.ts
23786
23890
  import vm from "node:vm";
23787
23891
  import * as nodeModule from "node:module";
@@ -23823,6 +23927,21 @@ function joinPosix(dir, request) {
23823
23927
  function normalizePosix(p) {
23824
23928
  return joinPosix("", p);
23825
23929
  }
23930
+ function errorLineIn(stack, path) {
23931
+ const own = new RegExp(`${escapeRegExp(path)}:(\\d+)`).exec(stack);
23932
+ if (own !== null) return own[1];
23933
+ return /(?:^|\n):(\d+)(?:\n|$)/.exec(stack)?.[1];
23934
+ }
23935
+ function syntaxErrorWithLocation(error51, path) {
23936
+ const rawMessage = error51 instanceof Error ? error51.message : String(error51);
23937
+ const stack = error51.stack;
23938
+ const line = typeof stack === "string" ? errorLineIn(stack, path) : void 0;
23939
+ const location = line === void 0 ? path : `${path}:${line}`;
23940
+ const wrapped = new Error(`\u6E90\u7801\u8BED\u6CD5\u9519\u8BEF\uFF08${location}\uFF09\uFF1A${rawMessage}`, { cause: error51 });
23941
+ const code = error51.code;
23942
+ if (typeof code === "string") wrapped.code = code;
23943
+ return wrapped;
23944
+ }
23826
23945
  function loadModule(path, files, sandboxGlobals, cache, resolveBare, bareCache) {
23827
23946
  const cached2 = cache.get(path);
23828
23947
  if (cached2 !== void 0) return cached2;
@@ -23856,21 +23975,19 @@ function loadModule(path, files, sandboxGlobals, cache, resolveBare, bareCache)
23856
23975
  try {
23857
23976
  transformed = transformExports(transpile(source));
23858
23977
  } catch (error51) {
23859
- const rawMessage = error51 instanceof Error ? error51.message : String(error51);
23860
- const stack = error51.stack;
23861
- const line = typeof stack === "string" ? /(?:^|\n):(\d+)(?:\n|$)/.exec(stack)?.[1] : void 0;
23862
- const location = line === void 0 ? path : `${path}:${line}`;
23863
- const wrapped = new Error(`\u6E90\u7801\u8BED\u6CD5\u9519\u8BEF\uFF08${location}\uFF09\uFF1A${rawMessage}`, { cause: error51 });
23864
- const code = error51.code;
23865
- if (typeof code === "string") wrapped.code = code;
23866
- throw wrapped;
23867
- }
23868
- const wrapper = vm.runInNewContext(
23869
- `(function (module, exports, require) { ${transformed}
23978
+ throw syntaxErrorWithLocation(error51, path);
23979
+ }
23980
+ let wrapper;
23981
+ try {
23982
+ wrapper = vm.runInNewContext(
23983
+ `(function (module, exports, require) { ${transformed}
23870
23984
  })`,
23871
- vm.createContext({ ...sandboxGlobals }),
23872
- { filename: path }
23873
- );
23985
+ vm.createContext({ ...sandboxGlobals }),
23986
+ { filename: path }
23987
+ );
23988
+ } catch (error51) {
23989
+ throw syntaxErrorWithLocation(error51, path);
23990
+ }
23874
23991
  wrapper(module, exports, require2);
23875
23992
  if (module.default !== void 0 && exports["default"] === void 0) {
23876
23993
  exports["default"] = module.default;
@@ -23892,6 +24009,7 @@ var init_sandbox = __esm({
23892
24009
  "packages/runtime/src/functions/runtime/sandbox.ts"() {
23893
24010
  "use strict";
23894
24011
  init_exports();
24012
+ init_regexp();
23895
24013
  SANDBOX_BUILTIN_REJECTED = "FN_SANDBOX_BUILTIN_BLOCKED";
23896
24014
  }
23897
24015
  });
@@ -24400,16 +24518,6 @@ var init_chain = __esm({
24400
24518
  }
24401
24519
  });
24402
24520
 
24403
- // packages/runtime/src/shared/regexp.ts
24404
- function escapeRegExp(text) {
24405
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24406
- }
24407
- var init_regexp = __esm({
24408
- "packages/runtime/src/shared/regexp.ts"() {
24409
- "use strict";
24410
- }
24411
- });
24412
-
24413
24521
  // packages/runtime/src/functions/runtime/worker-entry.ts
24414
24522
  import { parentPort, workerData } from "node:worker_threads";
24415
24523
  import { createRequire } from "node:module";
@@ -24422,12 +24530,35 @@ function errorMessageOf2(error51) {
24422
24530
  }
24423
24531
  return String(error51);
24424
24532
  }
24533
+ async function normalizeResultBody(value) {
24534
+ if (!(value instanceof Response)) return value;
24535
+ const contentType = value.headers.get("content-type") ?? "";
24536
+ const text = await value.text();
24537
+ let payload = text;
24538
+ if (contentType.includes("application/json")) {
24539
+ try {
24540
+ payload = text === "" ? null : JSON.parse(text);
24541
+ } catch {
24542
+ payload = text;
24543
+ }
24544
+ }
24545
+ const headers = {};
24546
+ value.headers.forEach((headerValue, key) => {
24547
+ headers[key] = headerValue;
24548
+ });
24549
+ return { __adepHttp: { status: value.status, body: payload, headers } };
24550
+ }
24425
24551
  function firstUserFrame(stack, files) {
24426
- for (const key of Object.keys(files)) {
24427
- const match = new RegExp(
24428
- `(?<![\\w$/.])${escapeRegExp(key)}:(\\d+)(?::(\\d+))?(?::(\\d+))?`
24429
- ).exec(stack);
24430
- if (match !== null) {
24552
+ const patterns = Object.keys(files).map(
24553
+ (key) => [
24554
+ key,
24555
+ new RegExp(`(?<![\\w$/.])${escapeRegExp(key)}:(\\d+)(?::(\\d+))?(?::(\\d+))?`)
24556
+ ]
24557
+ );
24558
+ for (const line of stack.split("\n")) {
24559
+ for (const [key, pattern] of patterns) {
24560
+ const match = pattern.exec(line);
24561
+ if (match === null) continue;
24431
24562
  return match[2] === void 0 ? `${key}:${match[1]}` : `${key}:${match[1]}:${match[2]}`;
24432
24563
  }
24433
24564
  }
@@ -24438,7 +24569,8 @@ function errorMessageWithLocation(error51, files) {
24438
24569
  const stack = error51.stack;
24439
24570
  if (typeof stack !== "string") return message;
24440
24571
  const frame = firstUserFrame(stack, files);
24441
- return frame === void 0 ? message : `${message}\uFF08${frame}\uFF09`;
24572
+ if (frame === void 0 || message.includes(`\uFF08${frame}\uFF09`)) return message;
24573
+ return `${message}\uFF08${frame}\uFF09`;
24442
24574
  }
24443
24575
  function createBareResolver(deps) {
24444
24576
  const platformRequire = createRequire(import.meta.url);
@@ -24551,8 +24683,20 @@ function runWorker(input, port) {
24551
24683
  const result = Promise.resolve(handler(ctx));
24552
24684
  void result.then(
24553
24685
  (value) => {
24554
- port.postMessage({ type: "result", body: value === void 0 ? null : value });
24555
- return void 0;
24686
+ return normalizeResultBody(value).then(
24687
+ (body) => {
24688
+ port.postMessage({ type: "result", body: body === void 0 ? null : body });
24689
+ return void 0;
24690
+ },
24691
+ (error51) => {
24692
+ port.postMessage({
24693
+ type: "error",
24694
+ message: `\u51FD\u6570\u8FD4\u56DE\u7684 Response \u89E3\u5305\u5931\u8D25\uFF1A${errorMessageOf2(error51)}`,
24695
+ code: "FN_RESPONSE_UNWRAP_FAILED"
24696
+ });
24697
+ return void 0;
24698
+ }
24699
+ );
24556
24700
  },
24557
24701
  (error51) => {
24558
24702
  port.postMessage({
@@ -25322,6 +25466,7 @@ __export(app_build_exports, {
25322
25466
  bindVersion: () => bindVersion,
25323
25467
  buildDesktopApp: () => buildDesktopApp,
25324
25468
  collectFunctionNames: () => collectFunctionNames,
25469
+ compareByCodeUnit: () => compareByCodeUnit,
25325
25470
  computeBundleVersion: () => computeBundleVersion,
25326
25471
  createAppBuildApi: () => createAppBuildApi,
25327
25472
  findArtifacts: () => findArtifacts,
@@ -25343,6 +25488,9 @@ import { createHash as createHash2 } from "node:crypto";
25343
25488
  import { copyFile, mkdir as mkdir9, mkdtemp, readFile as readFile12, readdir as readdir5, rm as rm3, stat as stat8, writeFile as writeFile8 } from "node:fs/promises";
25344
25489
  import { tmpdir } from "node:os";
25345
25490
  import { basename as basename2, dirname as dirname10, join as join16, posix, relative as relative2, resolve as resolve8 } from "node:path";
25491
+ function compareByCodeUnit(left, right) {
25492
+ return left < right ? -1 : left > right ? 1 : 0;
25493
+ }
25346
25494
  function normalizePlatform(input) {
25347
25495
  if (input === void 0 || input.length === 0) {
25348
25496
  if (process.platform === "darwin" || process.platform === "win32" || process.platform === "linux") {
@@ -25402,7 +25550,7 @@ async function readShellConfig(shellDir) {
25402
25550
  return { raw, config: config2 };
25403
25551
  }
25404
25552
  function computeBundleVersion(manifest) {
25405
- const siteEntries = manifest.contents.filter((content) => content.path.startsWith(SITE_PREFIX)).toSorted((left, right) => left.path.localeCompare(right.path));
25553
+ const siteEntries = manifest.contents.filter((content) => content.path.startsWith(SITE_PREFIX)).toSorted((left, right) => compareByCodeUnit(left.path, right.path));
25406
25554
  const fingerprint = createHash2("sha256").update(siteEntries.map((content) => `${content.path}:${content.sha256}`).join("\n")).digest("hex").slice(0, 12);
25407
25555
  return `${manifest.project.version}.${fingerprint}`;
25408
25556
  }
@@ -25418,7 +25566,7 @@ function collectFunctionNames(manifest) {
25418
25566
  if (name.length === 0 || name === FUNCTION_SHARED_DIR) continue;
25419
25567
  names.add(name);
25420
25568
  }
25421
- return [...names].toSorted((left, right) => left.localeCompare(right));
25569
+ return [...names].toSorted(compareByCodeUnit);
25422
25570
  }
25423
25571
  function readManifest(entries, options) {
25424
25572
  const raw = entries.get("manifest.json");
@@ -25483,7 +25631,10 @@ function verifySiteContents(manifest, entries) {
25483
25631
  );
25484
25632
  if (!result.valid) {
25485
25633
  const detail = result.errors.map((item) => item.message).join("; ");
25486
- throw new InitError("APP_BUNDLE_INTEGRITY", `\u5BFC\u51FA\u5305 site/ \u5185\u5BB9\u7269\u6821\u9A8C\u548C\u4E0D\u5339\u914D\uFF08\u5305\u5DF2\u635F\u574F\uFF09\uFF1A${detail}`);
25634
+ throw new InitError(
25635
+ "APP_BUNDLE_INTEGRITY",
25636
+ `\u5BFC\u51FA\u5305 site/ \u5185\u5BB9\u7269\u6821\u9A8C\u548C\u4E0D\u5339\u914D\uFF08\u5305\u5DF2\u635F\u574F\uFF09\uFF1A${detail}`
25637
+ );
25487
25638
  }
25488
25639
  }
25489
25640
  async function writeSiteTree(shellDir, site) {
@@ -25549,7 +25700,8 @@ function missingMobileDepsError(shellDir, platform) {
25549
25700
  async function assertShellPackagerReady(shellDir, platform, prepareOnly) {
25550
25701
  if (prepareOnly) return;
25551
25702
  if (platform === "ios") {
25552
- if (!await pathExists(join16(shellDir, "ios", "App"))) throw missingMobileDepsError(shellDir, "ios");
25703
+ if (!await pathExists(join16(shellDir, "ios", "App")))
25704
+ throw missingMobileDepsError(shellDir, "ios");
25553
25705
  return;
25554
25706
  }
25555
25707
  if (platform === "android") {
@@ -25686,10 +25838,10 @@ async function findArtifacts(shellDir, outDir, platform) {
25686
25838
  }
25687
25839
  };
25688
25840
  await walk(outDir, 1);
25689
- return found.toSorted((left, right) => left.localeCompare(right));
25841
+ return found.toSorted(compareByCodeUnit);
25690
25842
  }
25691
25843
  function topAssets(written) {
25692
- return [...written].toSorted((left, right) => right.size - left.size || left.path.localeCompare(right.path)).slice(0, TOP_ASSETS_LIMIT);
25844
+ return [...written].toSorted((left, right) => right.size - left.size || compareByCodeUnit(left.path, right.path)).slice(0, TOP_ASSETS_LIMIT);
25693
25845
  }
25694
25846
  function mismatchWarning(config2, server) {
25695
25847
  if (server === void 0 || server.length === 0) return [];
@@ -26840,71 +26992,321 @@ var init_deploy = __esm({
26840
26992
  }
26841
26993
  });
26842
26994
 
26843
- // shared/frontend-draft.ts
26844
- var FRONTEND_DRAFT_FILE_PATH_PATTERN, FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES, FRONTEND_DRAFT_MAX_FILES;
26845
- var init_frontend_draft = __esm({
26846
- "shared/frontend-draft.ts"() {
26995
+ // packages/cli/src/storage.ts
26996
+ var storage_exports = {};
26997
+ __export(storage_exports, {
26998
+ contentTypeOf: () => contentTypeOf,
26999
+ storageDownload: () => storageDownload,
27000
+ storageList: () => storageList,
27001
+ storageRemove: () => storageRemove,
27002
+ storageUpload: () => storageUpload
27003
+ });
27004
+ import { mkdir as mkdir13, readFile as readFile18, stat as stat12, writeFile as writeFile11 } from "node:fs/promises";
27005
+ import { basename as basename5, dirname as dirname13, extname as extname2, join as join22, resolve as resolve13 } from "node:path";
27006
+ async function open3(paths, options) {
27007
+ const client = await createClient(paths);
27008
+ const project2 = await resolveSlug(resolve13(options.cwd), options.slug);
27009
+ return { client, project: project2 };
27010
+ }
27011
+ function contentTypeOf(path) {
27012
+ const map2 = {
27013
+ ".html": "text/html; charset=utf-8",
27014
+ ".htm": "text/html; charset=utf-8",
27015
+ ".css": "text/css; charset=utf-8",
27016
+ ".js": "text/javascript; charset=utf-8",
27017
+ ".mjs": "text/javascript; charset=utf-8",
27018
+ ".json": "application/json; charset=utf-8",
27019
+ ".png": "image/png",
27020
+ ".jpg": "image/jpeg",
27021
+ ".jpeg": "image/jpeg",
27022
+ ".gif": "image/gif",
27023
+ ".svg": "image/svg+xml",
27024
+ ".webp": "image/webp",
27025
+ ".ico": "image/x-icon",
27026
+ ".txt": "text/plain; charset=utf-8",
27027
+ ".md": "text/markdown; charset=utf-8",
27028
+ ".xml": "application/xml",
27029
+ ".wasm": "application/wasm",
27030
+ ".pdf": "application/pdf",
27031
+ ".zip": "application/zip",
27032
+ ".woff": "font/woff",
27033
+ ".woff2": "font/woff2",
27034
+ ".ttf": "font/ttf",
27035
+ ".otf": "font/otf"
27036
+ };
27037
+ return map2[extname2(path).toLowerCase()] ?? "application/octet-stream";
27038
+ }
27039
+ async function storageUpload(paths, options) {
27040
+ const { client, project: project2 } = await open3(paths, options);
27041
+ const local = resolve13(options.file);
27042
+ const info = await stat12(local).catch(() => null);
27043
+ if (info === null || !info.isFile()) {
27044
+ throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
27045
+ }
27046
+ const visibility = options.visibility ?? "private";
27047
+ const bytes = await readFile18(local);
27048
+ const form = new FormData();
27049
+ form.set("path", options.path);
27050
+ form.set("visibility", visibility);
27051
+ form.set(
27052
+ "file",
27053
+ new Blob([bytes], { type: contentTypeOf(options.path) }),
27054
+ basename5(local)
27055
+ );
27056
+ const response = await client.upload(
27057
+ `/api/v1/projects/${project2}/files`,
27058
+ form,
27059
+ "STORAGE_UPLOAD_FAILED"
27060
+ );
27061
+ const body = await response.json();
27062
+ return { ...body.file, ...body.signedUrl === void 0 ? {} : { signedUrl: body.signedUrl } };
27063
+ }
27064
+ async function storageList(paths, options) {
27065
+ const { client, project: project2 } = await open3(paths, options);
27066
+ const query = options.prefix === void 0 ? "" : `?prefix=${encodeURIComponent(options.prefix)}`;
27067
+ const body = await client.request(
27068
+ `/api/v1/projects/${project2}/files${query}`
27069
+ );
27070
+ return { project: project2, files: body.files };
27071
+ }
27072
+ async function resolveDownloadUrl(client, project2, path) {
27073
+ const body = await client.request(
27074
+ `/api/v1/projects/${project2}/files?prefix=${encodeURIComponent(path)}`
27075
+ );
27076
+ const entry = body.files.find((file2) => file2.path === path);
27077
+ const url2 = entry?.url ?? entry?.signedUrl;
27078
+ if (entry === void 0 || url2 === void 0 || url2.length === 0) {
27079
+ throw new CliError("STORAGE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${path}`);
27080
+ }
27081
+ return url2;
27082
+ }
27083
+ async function storageDownload(paths, options) {
27084
+ const { client, project: project2 } = await open3(paths, options);
27085
+ const url2 = await resolveDownloadUrl(client, project2, options.path);
27086
+ const response = await client.download(url2, "STORAGE_DOWNLOAD_FAILED");
27087
+ const bytes = Buffer.from(await response.arrayBuffer());
27088
+ const output = resolve13(options.output ?? join22(resolve13(options.cwd), basename5(options.path)));
27089
+ await mkdir13(dirname13(output), { recursive: true });
27090
+ await writeFile11(output, bytes);
27091
+ return { path: options.path, output, size: bytes.length };
27092
+ }
27093
+ async function storageRemove(paths, options) {
27094
+ const { client, project: project2 } = await open3(paths, options);
27095
+ return client.request(
27096
+ `/api/v1/projects/${project2}/files/${encodeURIComponent(options.path)}`,
27097
+ { method: "DELETE" }
27098
+ );
27099
+ }
27100
+ var init_storage2 = __esm({
27101
+ "packages/cli/src/storage.ts"() {
26847
27102
  "use strict";
26848
- FRONTEND_DRAFT_FILE_PATH_PATTERN = /^[a-zA-Z0-9._][a-zA-Z0-9._/-]*$/;
26849
- FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES = 512 * 1024;
26850
- FRONTEND_DRAFT_MAX_FILES = 100;
27103
+ init_client();
27104
+ init_auth();
26851
27105
  }
26852
27106
  });
26853
27107
 
26854
- // packages/cli/src/frontend.ts
26855
- var frontend_exports = {};
26856
- __export(frontend_exports, {
26857
- frontendSync: () => frontendSync
27108
+ // packages/cli/src/hosting.ts
27109
+ var hosting_exports = {};
27110
+ __export(hosting_exports, {
27111
+ hostingConfig: () => hostingConfig,
27112
+ hostingDeploy: () => hostingDeploy,
27113
+ hostingInfo: () => hostingInfo,
27114
+ hostingPull: () => hostingPull
26858
27115
  });
26859
- import { readdir as readdir8, readFile as readFile18, stat as stat12 } from "node:fs/promises";
26860
- import { join as join22, relative as relative6, sep as sep2 } from "node:path";
26861
- async function collectFiles(root, dir) {
27116
+ import { readdir as readdir8, readFile as readFile19, stat as stat13 } from "node:fs/promises";
27117
+ import { dirname as dirname14, join as join23, relative as relative6, resolve as resolve14, sep as sep2 } from "node:path";
27118
+ async function open4(paths, options) {
27119
+ const client = await createClient(paths);
27120
+ const project2 = await resolveSlug(resolve14(options.cwd), options.slug);
27121
+ return { client, project: project2 };
27122
+ }
27123
+ async function hostingInfo(paths, options) {
27124
+ const { client, project: project2 } = await open4(paths, options);
27125
+ const body = await client.request(`/api/v1/projects/${project2}/hosting`);
27126
+ return {
27127
+ config: body.config,
27128
+ siteUrl: body.siteUrl,
27129
+ files: body.files ?? []
27130
+ };
27131
+ }
27132
+ async function collectSiteFiles(dir) {
27133
+ const root = resolve14(dir);
26862
27134
  const files = /* @__PURE__ */ new Map();
26863
- const skipped = [];
26864
- const entries = await readdir8(dir, { withFileTypes: true });
26865
- for (const entry of entries) {
26866
- if (entry.isDirectory()) {
26867
- if (IGNORED_DIRS2.has(entry.name)) continue;
26868
- const nested = await collectFiles(root, join22(dir, entry.name));
26869
- for (const [path, content] of nested.files) files.set(path, content);
26870
- skipped.push(...nested.skipped);
26871
- continue;
26872
- }
26873
- if (IGNORED_FILES.has(entry.name)) continue;
26874
- const full = join22(dir, entry.name);
26875
- const rel = relative6(root, full).split(sep2).join("/");
26876
- const info = await stat12(full);
26877
- if (info.size > 1024 * 1024) {
26878
- skipped.push(rel);
26879
- continue;
26880
- }
27135
+ const walk = async (sub) => {
27136
+ let entries;
26881
27137
  try {
26882
- const content = await readFile18(full, "utf8");
26883
- if (content.includes("\0")) {
26884
- skipped.push(rel);
26885
- continue;
26886
- }
26887
- files.set(rel, content);
27138
+ entries = await readdir8(sub, { withFileTypes: true });
26888
27139
  } catch {
26889
- skipped.push(rel);
27140
+ return;
26890
27141
  }
26891
- }
26892
- return { files, skipped };
27142
+ for (const entry of entries) {
27143
+ const full = join23(sub, entry.name);
27144
+ if (entry.isDirectory()) {
27145
+ await walk(full);
27146
+ } else if (entry.isFile()) {
27147
+ const rel = relative6(root, full).split(sep2).join("/");
27148
+ files.set(rel, full);
27149
+ }
27150
+ }
27151
+ };
27152
+ await walk(root);
27153
+ return files;
26893
27154
  }
26894
- async function frontendSync(paths, options) {
26895
- const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
27155
+ async function hostingDeploy(paths, options) {
27156
+ const { client, project: project2 } = await open4(paths, options);
27157
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
26896
27158
  `));
26897
- const webDir = options.dir ?? join22(options.cwd, "web");
26898
- const rootStat = await stat12(webDir).catch(() => null);
26899
- if (rootStat === null || !rootStat.isDirectory()) {
26900
- throw new CliError(
26901
- "FRONTEND_DIR_MISSING",
26902
- `\u672C\u5730\u524D\u7AEF\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${webDir}\uFF08adep frontend sync \u671F\u671B ${webDir}/ \u4E0B\u662F Vite \u5DE5\u7A0B\uFF09`
26903
- );
26904
- }
26905
- const { files, skipped } = await collectFiles(webDir, webDir);
27159
+ const files = await collectSiteFiles(options.dir);
26906
27160
  if (files.size === 0) {
26907
- throw new CliError("FRONTEND_EMPTY", `\u672C\u5730\u524D\u7AEF\u76EE\u5F55\u4E3A\u7A7A\u6216\u65E0\u53EF\u4E0A\u4F20\u6587\u672C\u6587\u4EF6\uFF1A${webDir}`);
27161
+ throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve14(options.dir)}`);
27162
+ }
27163
+ const uploaded = [];
27164
+ for (const [rel, full] of files) {
27165
+ log(`[adep] \u4E0A\u4F20 site/${rel}`);
27166
+ const info2 = await stat13(full);
27167
+ const bytes = await readFile19(full);
27168
+ const form = new FormData();
27169
+ form.set("path", `site/${rel}`);
27170
+ form.set("visibility", "public");
27171
+ form.set(
27172
+ "file",
27173
+ new Blob([bytes], { type: contentTypeOf(rel) }),
27174
+ rel.split("/").pop()
27175
+ );
27176
+ await client.upload(`/api/v1/projects/${project2}/files`, form, "HOSTING_UPLOAD_FAILED");
27177
+ uploaded.push({ path: `site/${rel}`, size: info2.size });
27178
+ }
27179
+ const config2 = await client.request(
27180
+ `/api/v1/projects/${project2}/hosting`,
27181
+ {
27182
+ method: "PUT",
27183
+ body: options.spa === void 0 ? { enabled: true } : { enabled: true, spaMode: options.spa }
27184
+ }
27185
+ );
27186
+ const info = await hostingInfo(paths, options);
27187
+ return { config: config2.config, siteUrl: info.siteUrl, uploaded };
27188
+ }
27189
+ async function hostingPull(paths, options) {
27190
+ const { client } = await open4(paths, options);
27191
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
27192
+ `));
27193
+ const info = await hostingInfo(paths, options);
27194
+ const outputDir = resolve14(options.output ?? resolve14(options.cwd));
27195
+ const { mkdir: mkdir15, writeFile: writeFile13 } = await import("node:fs/promises");
27196
+ const files = [];
27197
+ for (const entry of info.files) {
27198
+ if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
27199
+ const url2 = entry.url;
27200
+ if (url2 === void 0 || url2.length === 0) continue;
27201
+ log(`[adep] \u4E0B\u8F7D ${entry.path}`);
27202
+ const response = await client.download(url2, "HOSTING_DOWNLOAD_FAILED");
27203
+ const bytes = Buffer.from(await response.arrayBuffer());
27204
+ const rel = entry.path.replace(/^site\//, "");
27205
+ const target = join23(outputDir, ...rel.split("/"));
27206
+ await mkdir15(dirname14(target), { recursive: true });
27207
+ await writeFile13(target, bytes);
27208
+ files.push({ path: entry.path, size: bytes.length });
27209
+ }
27210
+ return { siteUrl: info.siteUrl, outputDir, files };
27211
+ }
27212
+ async function hostingConfig(paths, options) {
27213
+ const { client, project: project2 } = await open4(paths, options);
27214
+ const body = {};
27215
+ if (options.enabled !== void 0) body["enabled"] = options.enabled;
27216
+ if (options.spa !== void 0) body["spaMode"] = options.spa;
27217
+ const result = await client.request(
27218
+ `/api/v1/projects/${project2}/hosting`,
27219
+ { method: "PUT", body }
27220
+ );
27221
+ return result.config;
27222
+ }
27223
+ var HOSTING_CONFIG_PATH;
27224
+ var init_hosting = __esm({
27225
+ "packages/cli/src/hosting.ts"() {
27226
+ "use strict";
27227
+ init_client();
27228
+ init_auth();
27229
+ init_storage2();
27230
+ HOSTING_CONFIG_PATH = "site/.hosting.json";
27231
+ }
27232
+ });
27233
+
27234
+ // shared/frontend-draft.ts
27235
+ var FRONTEND_DRAFT_FILE_PATH_PATTERN, FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES, FRONTEND_DRAFT_MAX_FILES, FRONTEND_TRANSFORM_EXTENSIONS;
27236
+ var init_frontend_draft = __esm({
27237
+ "shared/frontend-draft.ts"() {
27238
+ "use strict";
27239
+ FRONTEND_DRAFT_FILE_PATH_PATTERN = /^[a-zA-Z0-9._][a-zA-Z0-9._/-]*$/;
27240
+ FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES = 512 * 1024;
27241
+ FRONTEND_DRAFT_MAX_FILES = 100;
27242
+ FRONTEND_TRANSFORM_EXTENSIONS = [
27243
+ ".ts",
27244
+ ".tsx",
27245
+ ".jsx",
27246
+ ".vue",
27247
+ ".scss",
27248
+ ".sass",
27249
+ ".less",
27250
+ ".styl"
27251
+ ];
27252
+ }
27253
+ });
27254
+
27255
+ // packages/cli/src/frontend.ts
27256
+ var frontend_exports = {};
27257
+ __export(frontend_exports, {
27258
+ frontendSync: () => frontendSync,
27259
+ isStaticFrontendDir: () => isStaticFrontendDir
27260
+ });
27261
+ import { readdir as readdir9, readFile as readFile20, stat as stat14 } from "node:fs/promises";
27262
+ import { join as join24, relative as relative7, sep as sep3 } from "node:path";
27263
+ async function collectFiles(root, dir) {
27264
+ const files = /* @__PURE__ */ new Map();
27265
+ const skipped = [];
27266
+ const entries = await readdir9(dir, { withFileTypes: true });
27267
+ for (const entry of entries) {
27268
+ if (entry.isDirectory()) {
27269
+ if (IGNORED_DIRS2.has(entry.name)) continue;
27270
+ const nested = await collectFiles(root, join24(dir, entry.name));
27271
+ for (const [path, content] of nested.files) files.set(path, content);
27272
+ skipped.push(...nested.skipped);
27273
+ continue;
27274
+ }
27275
+ if (IGNORED_FILES.has(entry.name)) continue;
27276
+ const full = join24(dir, entry.name);
27277
+ const rel = relative7(root, full).split(sep3).join("/");
27278
+ const info = await stat14(full);
27279
+ if (info.size > 1024 * 1024) {
27280
+ skipped.push(rel);
27281
+ continue;
27282
+ }
27283
+ try {
27284
+ const content = await readFile20(full, "utf8");
27285
+ if (content.includes("\0")) {
27286
+ skipped.push(rel);
27287
+ continue;
27288
+ }
27289
+ files.set(rel, content);
27290
+ } catch {
27291
+ skipped.push(rel);
27292
+ }
27293
+ }
27294
+ return { files, skipped };
27295
+ }
27296
+ async function frontendSync(paths, options) {
27297
+ const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
27298
+ `));
27299
+ const webDir = options.dir ?? join24(options.cwd, "web");
27300
+ const rootStat = await stat14(webDir).catch(() => null);
27301
+ if (rootStat === null || !rootStat.isDirectory()) {
27302
+ throw new CliError(
27303
+ "FRONTEND_DIR_MISSING",
27304
+ `\u672C\u5730\u524D\u7AEF\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${webDir}\uFF08adep frontend sync \u671F\u671B ${webDir}/ \u4E0B\u662F Vite \u5DE5\u7A0B\uFF09`
27305
+ );
27306
+ }
27307
+ const { files, skipped } = await collectFiles(webDir, webDir);
27308
+ if (files.size === 0) {
27309
+ throw new CliError("FRONTEND_EMPTY", `\u672C\u5730\u524D\u7AEF\u76EE\u5F55\u4E3A\u7A7A\u6216\u65E0\u53EF\u4E0A\u4F20\u6587\u672C\u6587\u4EF6\uFF1A${webDir}`);
26908
27310
  }
26909
27311
  if (files.size > MAX_FILES) {
26910
27312
  throw new CliError("FRONTEND_TOO_MANY_FILES", `\u6587\u4EF6\u6570 ${files.size} \u8D85\u8FC7\u4E0A\u9650\uFF08${MAX_FILES}\uFF09`);
@@ -26941,6 +27343,35 @@ async function frontendSync(paths, options) {
26941
27343
  }
26942
27344
  return { projectId: project2.id, uploaded: files.size, skipped, totalBytes };
26943
27345
  }
27346
+ function declaresBuildScript(pkgJson) {
27347
+ if (pkgJson === void 0) return false;
27348
+ let scripts;
27349
+ try {
27350
+ scripts = JSON.parse(pkgJson)["scripts"];
27351
+ } catch {
27352
+ return false;
27353
+ }
27354
+ if (typeof scripts !== "object" || scripts === null || Array.isArray(scripts)) return false;
27355
+ const build = scripts["build"];
27356
+ return typeof build === "string" && build.trim().length > 0;
27357
+ }
27358
+ async function isStaticFrontendDir(dir) {
27359
+ const pkg = await readFile20(join24(dir, "package.json"), "utf8").catch(() => void 0);
27360
+ if (declaresBuildScript(pkg)) return false;
27361
+ const walk = async (sub) => {
27362
+ const entries = await readdir9(sub, { withFileTypes: true });
27363
+ for (const entry of entries) {
27364
+ if (entry.isDirectory()) {
27365
+ if (IGNORED_DIRS2.has(entry.name)) continue;
27366
+ if (!await walk(join24(sub, entry.name))) return false;
27367
+ continue;
27368
+ }
27369
+ if (FRONTEND_TRANSFORM_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) return false;
27370
+ }
27371
+ return true;
27372
+ };
27373
+ return walk(dir);
27374
+ }
26944
27375
  var MAX_FILES, MAX_TOTAL_SOURCE_BYTES2, FILE_PATH_PATTERN, IGNORED_DIRS2, IGNORED_FILES;
26945
27376
  var init_frontend = __esm({
26946
27377
  "packages/cli/src/frontend.ts"() {
@@ -26968,33 +27399,33 @@ var fs_exports = {};
26968
27399
  __export(fs_exports, {
26969
27400
  createExportFileSystem: () => createExportFileSystem
26970
27401
  });
26971
- import { mkdir as mkdir13, readFile as readFile19, rm as rm5, stat as stat14, writeFile as writeFile11 } from "node:fs/promises";
26972
- import { dirname as dirname13, join as join24 } from "node:path";
27402
+ import { mkdir as mkdir14, readFile as readFile21, rm as rm5, stat as stat16, writeFile as writeFile12 } from "node:fs/promises";
27403
+ import { dirname as dirname15, join as join26 } from "node:path";
26973
27404
  function createExportFileSystem() {
26974
27405
  return {
26975
- readFile: (path) => readFile19(path),
26976
- writeFile: (path, content) => writeFile11(path, content),
27406
+ readFile: (path) => readFile21(path),
27407
+ writeFile: (path, content) => writeFile12(path, content),
26977
27408
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
26978
27409
  deleteFile: async (path) => {
26979
27410
  await rm5(path, { recursive: true, force: true });
26980
27411
  },
26981
27412
  fileExists: async (path) => {
26982
27413
  try {
26983
- await stat14(path);
27414
+ await stat16(path);
26984
27415
  return true;
26985
27416
  } catch {
26986
27417
  return false;
26987
27418
  }
26988
27419
  },
26989
27420
  mkdir: async (path) => {
26990
- await mkdir13(path, { recursive: true });
27421
+ await mkdir14(path, { recursive: true });
26991
27422
  },
26992
27423
  unzip: async (zipPath, targetDir) => {
26993
- const entries = zipRead(await readFile19(zipPath));
27424
+ const entries = zipRead(await readFile21(zipPath));
26994
27425
  for (const [name, data] of entries) {
26995
- const dest = join24(targetDir, name);
26996
- await mkdir13(dirname13(dest), { recursive: true });
26997
- await writeFile11(dest, data);
27426
+ const dest = join26(targetDir, name);
27427
+ await mkdir14(dirname15(dest), { recursive: true });
27428
+ await writeFile12(dest, data);
26998
27429
  }
26999
27430
  }
27000
27431
  };
@@ -27237,122 +27668,9 @@ ${detail}`);
27237
27668
  }
27238
27669
  });
27239
27670
 
27240
- // packages/cli/src/storage.ts
27241
- var storage_exports = {};
27242
- __export(storage_exports, {
27243
- contentTypeOf: () => contentTypeOf,
27244
- storageDownload: () => storageDownload,
27245
- storageList: () => storageList,
27246
- storageRemove: () => storageRemove,
27247
- storageUpload: () => storageUpload
27248
- });
27249
- import { mkdir as mkdir14, readFile as readFile20, stat as stat15, writeFile as writeFile12 } from "node:fs/promises";
27250
- import { basename as basename5, dirname as dirname14, extname as extname2, join as join25, resolve as resolve14 } from "node:path";
27251
- async function open3(paths, options) {
27252
- const client = await createClient(paths);
27253
- const project2 = await resolveSlug(resolve14(options.cwd), options.slug);
27254
- return { client, project: project2 };
27255
- }
27256
- function contentTypeOf(path) {
27257
- const map2 = {
27258
- ".html": "text/html; charset=utf-8",
27259
- ".htm": "text/html; charset=utf-8",
27260
- ".css": "text/css; charset=utf-8",
27261
- ".js": "text/javascript; charset=utf-8",
27262
- ".mjs": "text/javascript; charset=utf-8",
27263
- ".json": "application/json; charset=utf-8",
27264
- ".png": "image/png",
27265
- ".jpg": "image/jpeg",
27266
- ".jpeg": "image/jpeg",
27267
- ".gif": "image/gif",
27268
- ".svg": "image/svg+xml",
27269
- ".webp": "image/webp",
27270
- ".ico": "image/x-icon",
27271
- ".txt": "text/plain; charset=utf-8",
27272
- ".md": "text/markdown; charset=utf-8",
27273
- ".xml": "application/xml",
27274
- ".wasm": "application/wasm",
27275
- ".pdf": "application/pdf",
27276
- ".zip": "application/zip",
27277
- ".woff": "font/woff",
27278
- ".woff2": "font/woff2",
27279
- ".ttf": "font/ttf",
27280
- ".otf": "font/otf"
27281
- };
27282
- return map2[extname2(path).toLowerCase()] ?? "application/octet-stream";
27283
- }
27284
- async function storageUpload(paths, options) {
27285
- const { client, project: project2 } = await open3(paths, options);
27286
- const local = resolve14(options.file);
27287
- const info = await stat15(local).catch(() => null);
27288
- if (info === null || !info.isFile()) {
27289
- throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
27290
- }
27291
- const visibility = options.visibility ?? "private";
27292
- const bytes = await readFile20(local);
27293
- const form = new FormData();
27294
- form.set("path", options.path);
27295
- form.set("visibility", visibility);
27296
- form.set(
27297
- "file",
27298
- new Blob([bytes], { type: contentTypeOf(options.path) }),
27299
- basename5(local)
27300
- );
27301
- const response = await client.upload(
27302
- `/api/v1/projects/${project2}/files`,
27303
- form,
27304
- "STORAGE_UPLOAD_FAILED"
27305
- );
27306
- const body = await response.json();
27307
- return { ...body.file, ...body.signedUrl === void 0 ? {} : { signedUrl: body.signedUrl } };
27308
- }
27309
- async function storageList(paths, options) {
27310
- const { client, project: project2 } = await open3(paths, options);
27311
- const query = options.prefix === void 0 ? "" : `?prefix=${encodeURIComponent(options.prefix)}`;
27312
- const body = await client.request(
27313
- `/api/v1/projects/${project2}/files${query}`
27314
- );
27315
- return { project: project2, files: body.files };
27316
- }
27317
- async function resolveDownloadUrl(client, project2, path) {
27318
- const body = await client.request(
27319
- `/api/v1/projects/${project2}/files?prefix=${encodeURIComponent(path)}`
27320
- );
27321
- const entry = body.files.find((file2) => file2.path === path);
27322
- const url2 = entry?.url ?? entry?.signedUrl;
27323
- if (entry === void 0 || url2 === void 0 || url2.length === 0) {
27324
- throw new CliError("STORAGE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${path}`);
27325
- }
27326
- return url2;
27327
- }
27328
- async function storageDownload(paths, options) {
27329
- const { client, project: project2 } = await open3(paths, options);
27330
- const url2 = await resolveDownloadUrl(client, project2, options.path);
27331
- const response = await client.download(url2, "STORAGE_DOWNLOAD_FAILED");
27332
- const bytes = Buffer.from(await response.arrayBuffer());
27333
- const output = resolve14(options.output ?? join25(resolve14(options.cwd), basename5(options.path)));
27334
- await mkdir14(dirname14(output), { recursive: true });
27335
- await writeFile12(output, bytes);
27336
- return { path: options.path, output, size: bytes.length };
27337
- }
27338
- async function storageRemove(paths, options) {
27339
- const { client, project: project2 } = await open3(paths, options);
27340
- return client.request(
27341
- `/api/v1/projects/${project2}/files/${encodeURIComponent(options.path)}`,
27342
- { method: "DELETE" }
27343
- );
27344
- }
27345
- var init_storage2 = __esm({
27346
- "packages/cli/src/storage.ts"() {
27347
- "use strict";
27348
- init_client();
27349
- init_auth();
27350
- }
27351
- });
27352
-
27353
27671
  // packages/cli/src/sandbox-scan.ts
27354
- import { readdir as readdir9, readFile as readFile21 } from "node:fs/promises";
27355
- import { join as join26, relative as relative7, sep as sep3 } from "node:path";
27672
+ import { readdir as readdir10, readFile as readFile22 } from "node:fs/promises";
27673
+ import { join as join27, relative as relative8, sep as sep4 } from "node:path";
27356
27674
  function extractSpecifiers(line) {
27357
27675
  const out = [];
27358
27676
  const patterns = [
@@ -27396,17 +27714,17 @@ function classify(specifier) {
27396
27714
  return null;
27397
27715
  }
27398
27716
  async function scanFunctionSources(rootDir, functionsDir) {
27399
- const base = join26(rootDir, functionsDir);
27717
+ const base = join27(rootDir, functionsDir);
27400
27718
  const findings = [];
27401
27719
  async function walk(current) {
27402
27720
  let entries;
27403
27721
  try {
27404
- entries = await readdir9(current, { withFileTypes: true });
27722
+ entries = await readdir10(current, { withFileTypes: true });
27405
27723
  } catch {
27406
27724
  return;
27407
27725
  }
27408
27726
  for (const entry of entries) {
27409
- const abs = join26(current, entry.name);
27727
+ const abs = join27(current, entry.name);
27410
27728
  if (entry.isDirectory()) {
27411
27729
  if (SKIP_DIRS.has(entry.name)) continue;
27412
27730
  await walk(abs);
@@ -27417,12 +27735,12 @@ async function scanFunctionSources(rootDir, functionsDir) {
27417
27735
  if (entry.name.endsWith(".d.ts")) continue;
27418
27736
  let content;
27419
27737
  try {
27420
- content = await readFile21(abs, "utf8");
27738
+ content = await readFile22(abs, "utf8");
27421
27739
  } catch {
27422
27740
  continue;
27423
27741
  }
27424
27742
  if (content.length > MAX_SCAN_BYTES) continue;
27425
- const relPath = relative7(rootDir, abs).split(sep3).join("/");
27743
+ const relPath = relative8(rootDir, abs).split(sep4).join("/");
27426
27744
  const lines = content.split("\n");
27427
27745
  for (const [index, line] of lines.entries()) {
27428
27746
  const trimmed = line.trim();
@@ -27539,7 +27857,7 @@ __export(doctor_exports, {
27539
27857
  formatDoctorReport: () => formatDoctorReport,
27540
27858
  runDoctor: () => runDoctor
27541
27859
  });
27542
- import { stat as stat16 } from "node:fs/promises";
27860
+ import { stat as stat17 } from "node:fs/promises";
27543
27861
  async function probeServer(server) {
27544
27862
  const controller = new AbortController();
27545
27863
  const timer = setTimeout(() => controller.abort(), SERVER_PROBE_TIMEOUT_MS);
@@ -27557,7 +27875,7 @@ async function probeServer(server) {
27557
27875
  }
27558
27876
  async function credentialMode(file2) {
27559
27877
  try {
27560
- const info = await stat16(file2);
27878
+ const info = await stat17(file2);
27561
27879
  return (info.mode & 511).toString(8).padStart(3, "0");
27562
27880
  } catch {
27563
27881
  return void 0;
@@ -27688,7 +28006,7 @@ __export(mcp_exports, {
27688
28006
  mcpPublish: () => mcpPublish,
27689
28007
  mcpUnpublish: () => mcpUnpublish
27690
28008
  });
27691
- import { resolve as resolve15 } from "node:path";
28009
+ import { resolve as resolve16 } from "node:path";
27692
28010
  async function mcpPublish(paths, options) {
27693
28011
  const fn = requireFunctionName(options.fn);
27694
28012
  const client = await createClient(paths);
@@ -27769,7 +28087,7 @@ function requireFunctionName(fn) {
27769
28087
  return fn.trim();
27770
28088
  }
27771
28089
  async function resolveProject(client, options) {
27772
- const slug = await resolveSlug(resolve15(options.cwd), options.slug);
28090
+ const slug = await resolveSlug(resolve16(options.cwd), options.slug);
27773
28091
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
27774
28092
  const match = listed.projects.find((project2) => project2.slug === slug);
27775
28093
  if (match === void 0) {
@@ -27954,7 +28272,7 @@ __export(functions_exports, {
27954
28272
  functionsList: () => functionsList,
27955
28273
  functionsLogs: () => functionsLogs
27956
28274
  });
27957
- import { resolve as resolve16 } from "node:path";
28275
+ import { resolve as resolve17 } from "node:path";
27958
28276
  async function functionsList(paths, options) {
27959
28277
  const client = await createClient(paths);
27960
28278
  const project2 = await resolveProject2(client, options);
@@ -27996,7 +28314,7 @@ async function functionsLogs(paths, options) {
27996
28314
  return { functionId: target.id, name: target.name, logs: result.logs };
27997
28315
  }
27998
28316
  async function resolveProject2(client, options) {
27999
- const slug = await resolveSlug(resolve16(options.cwd), options.slug);
28317
+ const slug = await resolveSlug(resolve17(options.cwd), options.slug);
28000
28318
  const projects = await projectsListFrom(client);
28001
28319
  const match = projects.find((project2) => project2.slug === slug);
28002
28320
  if (match === void 0) {
@@ -28019,132 +28337,6 @@ var init_functions = __esm({
28019
28337
  }
28020
28338
  });
28021
28339
 
28022
- // packages/cli/src/hosting.ts
28023
- var hosting_exports = {};
28024
- __export(hosting_exports, {
28025
- hostingConfig: () => hostingConfig,
28026
- hostingDeploy: () => hostingDeploy,
28027
- hostingInfo: () => hostingInfo,
28028
- hostingPull: () => hostingPull
28029
- });
28030
- import { readdir as readdir10, readFile as readFile22, stat as stat17 } from "node:fs/promises";
28031
- import { dirname as dirname15, join as join27, relative as relative8, resolve as resolve17, sep as sep4 } from "node:path";
28032
- async function open4(paths, options) {
28033
- const client = await createClient(paths);
28034
- const project2 = await resolveSlug(resolve17(options.cwd), options.slug);
28035
- return { client, project: project2 };
28036
- }
28037
- async function hostingInfo(paths, options) {
28038
- const { client, project: project2 } = await open4(paths, options);
28039
- const body = await client.request(`/api/v1/projects/${project2}/hosting`);
28040
- return {
28041
- config: body.config,
28042
- siteUrl: body.siteUrl,
28043
- files: body.files ?? []
28044
- };
28045
- }
28046
- async function collectSiteFiles(dir) {
28047
- const root = resolve17(dir);
28048
- const files = /* @__PURE__ */ new Map();
28049
- const walk = async (sub) => {
28050
- let entries;
28051
- try {
28052
- entries = await readdir10(sub, { withFileTypes: true });
28053
- } catch {
28054
- return;
28055
- }
28056
- for (const entry of entries) {
28057
- const full = join27(sub, entry.name);
28058
- if (entry.isDirectory()) {
28059
- await walk(full);
28060
- } else if (entry.isFile()) {
28061
- const rel = relative8(root, full).split(sep4).join("/");
28062
- files.set(rel, full);
28063
- }
28064
- }
28065
- };
28066
- await walk(root);
28067
- return files;
28068
- }
28069
- async function hostingDeploy(paths, options) {
28070
- const { client, project: project2 } = await open4(paths, options);
28071
- const log = options.log ?? ((line) => process.stdout.write(`${line}
28072
- `));
28073
- const files = await collectSiteFiles(options.dir);
28074
- if (files.size === 0) {
28075
- throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve17(options.dir)}`);
28076
- }
28077
- const uploaded = [];
28078
- for (const [rel, full] of files) {
28079
- log(`[adep] \u4E0A\u4F20 site/${rel}`);
28080
- const info2 = await stat17(full);
28081
- const bytes = await readFile22(full);
28082
- const form = new FormData();
28083
- form.set("path", `site/${rel}`);
28084
- form.set("visibility", "public");
28085
- form.set(
28086
- "file",
28087
- new Blob([bytes], { type: contentTypeOf(rel) }),
28088
- rel.split("/").pop()
28089
- );
28090
- await client.upload(`/api/v1/projects/${project2}/files`, form, "HOSTING_UPLOAD_FAILED");
28091
- uploaded.push({ path: `site/${rel}`, size: info2.size });
28092
- }
28093
- const config2 = await client.request(
28094
- `/api/v1/projects/${project2}/hosting`,
28095
- {
28096
- method: "PUT",
28097
- body: options.spa === void 0 ? { enabled: true } : { enabled: true, spaMode: options.spa }
28098
- }
28099
- );
28100
- const info = await hostingInfo(paths, options);
28101
- return { config: config2.config, siteUrl: info.siteUrl, uploaded };
28102
- }
28103
- async function hostingPull(paths, options) {
28104
- const { client } = await open4(paths, options);
28105
- const log = options.log ?? ((line) => process.stdout.write(`${line}
28106
- `));
28107
- const info = await hostingInfo(paths, options);
28108
- const outputDir = resolve17(options.output ?? resolve17(options.cwd));
28109
- const { mkdir: mkdir15, writeFile: writeFile13 } = await import("node:fs/promises");
28110
- const files = [];
28111
- for (const entry of info.files) {
28112
- if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
28113
- const url2 = entry.url;
28114
- if (url2 === void 0 || url2.length === 0) continue;
28115
- log(`[adep] \u4E0B\u8F7D ${entry.path}`);
28116
- const response = await client.download(url2, "HOSTING_DOWNLOAD_FAILED");
28117
- const bytes = Buffer.from(await response.arrayBuffer());
28118
- const rel = entry.path.replace(/^site\//, "");
28119
- const target = join27(outputDir, ...rel.split("/"));
28120
- await mkdir15(dirname15(target), { recursive: true });
28121
- await writeFile13(target, bytes);
28122
- files.push({ path: entry.path, size: bytes.length });
28123
- }
28124
- return { siteUrl: info.siteUrl, outputDir, files };
28125
- }
28126
- async function hostingConfig(paths, options) {
28127
- const { client, project: project2 } = await open4(paths, options);
28128
- const body = {};
28129
- if (options.enabled !== void 0) body["enabled"] = options.enabled;
28130
- if (options.spa !== void 0) body["spaMode"] = options.spa;
28131
- const result = await client.request(
28132
- `/api/v1/projects/${project2}/hosting`,
28133
- { method: "PUT", body }
28134
- );
28135
- return result.config;
28136
- }
28137
- var HOSTING_CONFIG_PATH;
28138
- var init_hosting = __esm({
28139
- "packages/cli/src/hosting.ts"() {
28140
- "use strict";
28141
- init_client();
28142
- init_auth();
28143
- init_storage2();
28144
- HOSTING_CONFIG_PATH = "site/.hosting.json";
28145
- }
28146
- });
28147
-
28148
28340
  // packages/cli/src/cli.ts
28149
28341
  init_config();
28150
28342
  import { Command } from "commander";
@@ -28680,7 +28872,10 @@ async function writeOfflineTree(shellDir, collected) {
28680
28872
  function readFunctionsIndex(entries) {
28681
28873
  const raw = entries.get(OFFLINE_BUNDLE_PATHS.functionsIndex);
28682
28874
  if (raw === void 0) {
28683
- throw new InitError("APP_OFFLINE_BUNDLE_INVALID", "\u79BB\u7EBF\u5305\u7F3A\u5C11 functions/index.json\uFF08\u4EA7\u7269\u5DF2\u635F\u574F\uFF09");
28875
+ throw new InitError(
28876
+ "APP_OFFLINE_BUNDLE_INVALID",
28877
+ "\u79BB\u7EBF\u5305\u7F3A\u5C11 functions/index.json\uFF08\u4EA7\u7269\u5DF2\u635F\u574F\uFF09"
28878
+ );
28684
28879
  }
28685
28880
  let parsed;
28686
28881
  try {
@@ -28693,7 +28888,10 @@ function readFunctionsIndex(entries) {
28693
28888
  }
28694
28889
  const body = parsed;
28695
28890
  if (!Array.isArray(body.functions)) {
28696
- throw new InitError("APP_OFFLINE_BUNDLE_INVALID", "\u79BB\u7EBF\u5305 functions/index.json \u7F3A\u5C11 functions \u6570\u7EC4");
28891
+ throw new InitError(
28892
+ "APP_OFFLINE_BUNDLE_INVALID",
28893
+ "\u79BB\u7EBF\u5305 functions/index.json \u7F3A\u5C11 functions \u6570\u7EC4"
28894
+ );
28697
28895
  }
28698
28896
  return body.functions.map((entry, index) => {
28699
28897
  if (typeof entry.name !== "string" || entry.name === "") {
@@ -28728,7 +28926,9 @@ async function waitForOfflineBuild(api, projectId, jobId, pollIntervalMs, maxPol
28728
28926
  }
28729
28927
  }
28730
28928
  function offlineBundleFingerprint(manifest) {
28731
- const entries = [...manifest.contents].toSorted((left, right) => left.path.localeCompare(right.path));
28929
+ const entries = [...manifest.contents].toSorted(
28930
+ (left, right) => compareByCodeUnit(left.path, right.path)
28931
+ );
28732
28932
  return createHash3("sha256").update(entries.map((content) => `${content.path}:${content.sha256}`).join("\n")).digest("hex").slice(0, 12);
28733
28933
  }
28734
28934
  async function buildOfflineApp(options, deps) {
@@ -28865,7 +29065,10 @@ async function createAppOfflineBuildApi(paths, cwd) {
28865
29065
  );
28866
29066
  const downloadUrl = envelope.downloadUrl;
28867
29067
  if (typeof downloadUrl !== "string" || downloadUrl.length === 0) {
28868
- throw new CliError("APP_OFFLINE_BUNDLE_UNAVAILABLE", "\u79BB\u7EBF\u5305\u4E0B\u8F7D URL \u4E3A\u7A7A\uFF0C\u4EA7\u7269\u53EF\u80FD\u5C1A\u4E0D\u53EF\u7528");
29068
+ throw new CliError(
29069
+ "APP_OFFLINE_BUNDLE_UNAVAILABLE",
29070
+ "\u79BB\u7EBF\u5305\u4E0B\u8F7D URL \u4E3A\u7A7A\uFF0C\u4EA7\u7269\u53EF\u80FD\u5C1A\u4E0D\u53EF\u7528"
29071
+ );
28869
29072
  }
28870
29073
  const response = await client.download(downloadUrl, "APP_OFFLINE_BUILD_DOWNLOAD_FAILED");
28871
29074
  const bytes = Buffer.from(await response.arrayBuffer());
@@ -29830,10 +30033,10 @@ function registerDevServers(program2, ctx) {
29830
30033
  init_auth();
29831
30034
  init_client();
29832
30035
  init_deploy();
29833
- import { stat as stat13 } from "node:fs/promises";
29834
- import { join as join23, resolve as resolve13 } from "node:path";
30036
+ import { stat as stat15 } from "node:fs/promises";
30037
+ import { join as join25, resolve as resolve15 } from "node:path";
29835
30038
  async function resolveProjectId2(client, cwd, slug) {
29836
- const resolvedSlug = await resolveSlug(resolve13(cwd), slug);
30039
+ const resolvedSlug = await resolveSlug(resolve15(cwd), slug);
29837
30040
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
29838
30041
  const match = listed.projects.find((project2) => project2.slug === resolvedSlug);
29839
30042
  if (match === void 0) {
@@ -29868,6 +30071,29 @@ async function publishFrontend(paths, options) {
29868
30071
  siteUrl: versions.siteUrl
29869
30072
  };
29870
30073
  }
30074
+ async function publishStaticFrontend(paths, options) {
30075
+ const webDir = join25(options.cwd, "web");
30076
+ const indexStat = await stat15(join25(webDir, "index.html")).catch(() => null);
30077
+ if (indexStat === null || !indexStat.isFile()) {
30078
+ throw new CliError(
30079
+ "FRONTEND_NO_PAGE",
30080
+ `\u7EAF\u9759\u6001\u53D1\u5E03\u7F3A\u5C11\u7AD9\u70B9\u5165\u53E3\uFF1A${webDir}/index.html \u4E0D\u5B58\u5728\uFF08\u6784\u5EFA\u578B\u5DE5\u7A0B\u8BF7\u5728 web/package.json \u58F0\u660E scripts.build\uFF09`
30081
+ );
30082
+ }
30083
+ const { hostingDeploy: hostingDeploy2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
30084
+ const result = await hostingDeploy2(paths, {
30085
+ cwd: options.cwd,
30086
+ dir: webDir,
30087
+ ...options.slug === void 0 ? {} : { slug: options.slug },
30088
+ ...options.log === void 0 ? {} : { log: options.log }
30089
+ });
30090
+ return {
30091
+ mode: "static",
30092
+ siteUrl: result.siteUrl,
30093
+ uploaded: result.uploaded.length,
30094
+ spaMode: result.config.spaMode
30095
+ };
30096
+ }
29871
30097
  async function publishFunctions(paths, options) {
29872
30098
  const startedAt = Date.now();
29873
30099
  const result = await deploy(paths, {
@@ -29899,23 +30125,40 @@ async function runPublish(paths, io, cwd, flags) {
29899
30125
  });
29900
30126
  }
29901
30127
  if (wantFrontend) {
29902
- const webDir = join23(cwd, "web");
29903
- const webStat = await stat13(webDir).catch(() => null);
30128
+ const webDir = join25(cwd, "web");
30129
+ const webStat = await stat15(webDir).catch(() => null);
29904
30130
  if (webStat !== null && webStat.isDirectory()) {
29905
- const { frontendSync: frontendSync2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
29906
- await frontendSync2(paths, {
30131
+ const { isStaticFrontendDir: isStaticFrontendDir2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
30132
+ if (await isStaticFrontendDir2(webDir)) {
30133
+ result.frontend = await publishStaticFrontend(paths, {
30134
+ cwd,
30135
+ ...flags.project === void 0 ? {} : { slug: flags.project },
30136
+ silent: io.json,
30137
+ log: (line) => io.line(line)
30138
+ });
30139
+ } else {
30140
+ const { frontendSync: frontendSync2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
30141
+ await frontendSync2(paths, {
30142
+ cwd,
30143
+ ...flags.project === void 0 ? {} : { slug: flags.project },
30144
+ silent: io.json,
30145
+ log: (line) => io.line(line)
30146
+ });
30147
+ result.frontend = await publishFrontend(paths, {
30148
+ cwd,
30149
+ ...flags.project === void 0 ? {} : { slug: flags.project },
30150
+ silent: io.json,
30151
+ log: (line) => io.line(line)
30152
+ });
30153
+ }
30154
+ } else {
30155
+ result.frontend = await publishFrontend(paths, {
29907
30156
  cwd,
29908
30157
  ...flags.project === void 0 ? {} : { slug: flags.project },
29909
30158
  silent: io.json,
29910
30159
  log: (line) => io.line(line)
29911
30160
  });
29912
30161
  }
29913
- result.frontend = await publishFrontend(paths, {
29914
- cwd,
29915
- ...flags.project === void 0 ? {} : { slug: flags.project },
29916
- silent: io.json,
29917
- log: (line) => io.line(line)
29918
- });
29919
30162
  }
29920
30163
  return result;
29921
30164
  }
@@ -29938,15 +30181,21 @@ function renderPublish(data) {
29938
30181
  }
29939
30182
  if (result.frontend !== void 0) {
29940
30183
  const fe = result.frontend;
29941
- const status = fe.reused ? `\uFF08\u590D\u7528 v${fe.version}\uFF0C\u65E0\u53D8\u66F4\uFF09` : `v${fe.version}`;
29942
- lines.push(`\u2713 frontend built ${status} \xB7 ${fe.siteUrl}`);
30184
+ if (fe.mode === "static") {
30185
+ lines.push(
30186
+ `\u2713 frontend published\uFF08\u9759\u6001\u76F4\u901A ${fe.uploaded} \u4E2A\u6587\u4EF6\uFF0CSPA \u56DE\u9000 ${fe.spaMode ? "\u5F00" : "\u5173"}\uFF09 \xB7 ${fe.siteUrl}`
30187
+ );
30188
+ } else {
30189
+ const status = fe.reused ? `\uFF08\u590D\u7528 v${fe.version}\uFF0C\u65E0\u53D8\u66F4\uFF09` : `v${fe.version}`;
30190
+ lines.push(`\u2713 frontend built ${status} \xB7 ${fe.siteUrl}`);
30191
+ }
29943
30192
  }
29944
30193
  return lines;
29945
30194
  }
29946
30195
  function registerPublish(program2, ctx) {
29947
30196
  program2.command("publish").description("\u5168\u6808\u53D1\u5E03\uFF1A\u51FD\u6570\u90E8\u7F72 + \u524D\u7AEF\u6784\u5EFA\u6258\u7BA1\uFF08--only functions|frontend \u53EF\u5355\u72EC\u53D1\u5E03\u4E00\u4FA7\uFF09").option(
29948
30197
  "--only <scope>",
29949
- "\u4EC5\u53D1\u5E03\u4E00\u4FA7\uFF1Afunctions\uFF08\u53EA\u90E8\u7F72\u4E91\u51FD\u6570\uFF09| frontend\uFF08\u53EA\u6784\u5EFA\u6258\u7BA1\u524D\u7AEF\uFF09\uFF1B\u7F3A\u7701\u5168\u6808\u53D1\u5E03"
30198
+ "\u4EC5\u53D1\u5E03\u4E00\u4FA7\uFF1Afunctions\uFF08\u53EA\u90E8\u7F72\u4E91\u51FD\u6570\uFF09| frontend\uFF08\u53EA\u6784\u5EFA\u6258\u7BA1\u524D\u7AEF\uFF1B\u7EAF\u9759\u6001\u7AD9\u81EA\u52A8\u76F4\u901A\u6258\u7BA1\u901A\u9053\uFF09\uFF1B\u7F3A\u7701\u5168\u6808\u53D1\u5E03"
29950
30199
  ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option(
29951
30200
  "--force",
29952
30201
  "\u653E\u884C warn \u7EA7\u5BC6\u94A5\u5F15\u7528\u547D\u4E2D\uFF08FN-013\uFF1B\u6E90\u7801\u5F15\u7528\u4E86\u5DF2\u914D\u7F6E\u7684 secret \u73AF\u5883\u53D8\u91CF\u540D\u65F6\u53D1\u5E03\u88AB\u963B\u65AD\uFF0C\u786E\u8BA4\u975E\u6CC4\u6F0F\u540E\u7528\u672C\u65D7\u6807\u653E\u884C\uFF0C\u670D\u52A1\u7AEF\u843D\u5BA1\u8BA1\uFF09"