@adep/cli 0.1.15 → 0.1.17

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
@@ -2693,6 +2693,14 @@ function hmacSha256(key, message) {
2693
2693
  function hmacSha256Hex(key, message) {
2694
2694
  return [...hmacSha256(key, message)].map((b) => b.toString(16).padStart(2, "0")).join("");
2695
2695
  }
2696
+ function constantTimeEqual(a, b) {
2697
+ if (a.length !== b.length) return false;
2698
+ let diff = 0;
2699
+ for (let i = 0; i < a.length; i += 1) {
2700
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
2701
+ }
2702
+ return diff === 0;
2703
+ }
2696
2704
  var K, rotr;
2697
2705
  var init_hmac_sha256 = __esm({
2698
2706
  "packages/runtime/src/storage/hmac-sha256.ts"() {
@@ -2778,6 +2786,22 @@ function signDownloadUrl(config, projectId, path, ttlSeconds = DEFAULT_SIGN_TTL_
2778
2786
  const signature = sign(config.secret, projectId, path, expires);
2779
2787
  return `${base}?${SIGN_EXPIRES_KEY}=${expires}&${SIGN_SIGNATURE_KEY}=${signature}`;
2780
2788
  }
2789
+ function verifyDownloadSignature(config, projectId, path, query, nowSeconds2 = Math.floor(Date.now() / 1e3)) {
2790
+ const expiresRaw = query.expires;
2791
+ const signatureRaw = query.signature;
2792
+ if (typeof expiresRaw !== "string" || typeof signatureRaw !== "string") {
2793
+ return { ok: false, reason: "missing" };
2794
+ }
2795
+ if (!/^\d{1,15}$/.test(expiresRaw)) return { ok: false, reason: "malformed" };
2796
+ const expires = Number(expiresRaw);
2797
+ if (!Number.isFinite(expires)) return { ok: false, reason: "malformed" };
2798
+ if (nowSeconds2 > expires) return { ok: false, reason: "expired" };
2799
+ const expected = sign(config.secret, projectId, path, expires);
2800
+ if (!constantTimeEqual(signatureRaw, expected)) {
2801
+ return { ok: false, reason: "invalid" };
2802
+ }
2803
+ return { ok: true };
2804
+ }
2781
2805
  var DEFAULT_SIGN_TTL_SECONDS, SIGN_EXPIRES_KEY, SIGN_SIGNATURE_KEY;
2782
2806
  var init_signature = __esm({
2783
2807
  "packages/runtime/src/storage/signature.ts"() {
@@ -3006,7 +3030,7 @@ function createLocalStorageDriver(options) {
3006
3030
  assertStoragePrefix(prefix);
3007
3031
  const root = bucketDir(projectId);
3008
3032
  const metas = [];
3009
- const walk = async (dir, relative6) => {
3033
+ const walk = async (dir, relative8) => {
3010
3034
  let entries;
3011
3035
  try {
3012
3036
  entries = await readdir3(dir, { withFileTypes: true });
@@ -3017,7 +3041,7 @@ function createLocalStorageDriver(options) {
3017
3041
  for (const entry of entries) {
3018
3042
  if (entry.name.endsWith(META_SUFFIX)) continue;
3019
3043
  const full = join6(dir, entry.name);
3020
- const rel = relative6 === "" ? entry.name : `${relative6}/${entry.name}`;
3044
+ const rel = relative8 === "" ? entry.name : `${relative8}/${entry.name}`;
3021
3045
  if (entry.isFile()) {
3022
3046
  if (prefix !== void 0 && !rel.startsWith(prefix)) continue;
3023
3047
  tasks.push(
@@ -3071,17 +3095,19 @@ function createSimStorageCapability(options) {
3071
3095
  const dir = join7(options.cwd, ".adep", "sim", "storage");
3072
3096
  const driver = createLocalStorageDriver({ dir });
3073
3097
  const signer = {
3074
- secret: options.secret ?? "adep-sim-secret",
3098
+ secret: options.secret ?? SIM_SIGN_SECRET,
3075
3099
  baseUrl: options.baseUrl ?? "http://127.0.0.1:8787"
3076
3100
  };
3077
3101
  const bundle = createStorageCapability(driver, signer, options.projectId ?? "sim-project");
3078
3102
  return { bundle, driver };
3079
3103
  }
3104
+ var SIM_SIGN_SECRET;
3080
3105
  var init_storage = __esm({
3081
3106
  "packages/cli/src/sim/storage.ts"() {
3082
3107
  "use strict";
3083
3108
  init_cloud2();
3084
3109
  init_local();
3110
+ SIM_SIGN_SECRET = "adep-sim-secret";
3085
3111
  }
3086
3112
  });
3087
3113
 
@@ -3281,6 +3307,8 @@ async function createSimRuntime(options) {
3281
3307
  bundle,
3282
3308
  realtime: simRealtime.realtime,
3283
3309
  db,
3310
+ /** 存储句柄(serve 的签名文件下载路由用它读对象;bundle 里的 capability 是同一驱动的 RPC 面)。 */
3311
+ storage,
3284
3312
  dispose: async () => {
3285
3313
  await db.driver.close();
3286
3314
  }
@@ -3298,185 +3326,665 @@ var init_runtime = __esm({
3298
3326
  }
3299
3327
  });
3300
3328
 
3301
- // packages/cli/src/sim/env.ts
3302
- import { readFile as readFile6 } from "node:fs/promises";
3303
- import { join as join9 } from "node:path";
3304
- function parseEnv(content) {
3305
- const env = {};
3306
- for (const raw of content.split(/\r?\n/)) {
3307
- const line = raw.trim();
3308
- if (line.length === 0 || line.startsWith("#")) continue;
3309
- const eq = line.indexOf("=");
3310
- if (eq === -1) continue;
3311
- const key = line.slice(0, eq).trim();
3312
- if (key.length === 0) continue;
3313
- env[key] = line.slice(eq + 1).trim();
3314
- }
3315
- return env;
3329
+ // packages/cli/src/client.ts
3330
+ var client_exports = {};
3331
+ __export(client_exports, {
3332
+ createClient: () => createClient,
3333
+ resolveSlug: () => resolveSlug
3334
+ });
3335
+ async function envelopeError(response, fallbackCode, parsed) {
3336
+ const payload = parsed ?? null;
3337
+ return new CliError(
3338
+ payload?.error?.code ?? fallbackCode,
3339
+ payload?.error?.message ?? `\u5E73\u53F0\u8FD4\u56DE HTTP ${response.status}`
3340
+ );
3316
3341
  }
3317
- async function loadSimEnv(cwd, config = {}) {
3318
- const envRoot = await readFile6(join9(cwd, ".env"), "utf8").catch(() => "");
3319
- const envLocal = await readFile6(join9(cwd, ".env.local"), "utf8").catch(() => "");
3320
- const merged = { ...parseEnv(envRoot), ...parseEnv(envLocal) };
3321
- for (const secret of config.secrets ?? []) {
3322
- if (merged[secret] !== void 0) continue;
3323
- if (process.env[secret] !== void 0) {
3324
- merged[secret] = process.env[secret];
3325
- continue;
3326
- }
3327
- throw new Error(
3328
- `secret "${secret}" \u672A\u914D\u7F6E\uFF1A\u8BF7\u5728 .env.local \u6DFB\u52A0 ${secret}=<value>\uFF0C\u6216\u7528\u73AF\u5883\u53D8\u91CF\u5BFC\u51FA\u540E\u91CD\u8BD5 adep dev\uFF08\u6A21\u62DF\u73AF\u5883\u6C38\u4E0D\u843D\u76D8\u8BE5\u503C\uFF09`
3329
- );
3342
+ async function parseBody(response) {
3343
+ const text = await response.text();
3344
+ if (text.length === 0) return null;
3345
+ try {
3346
+ return JSON.parse(text);
3347
+ } catch {
3348
+ return null;
3330
3349
  }
3331
- return merged;
3332
3350
  }
3333
- var init_env = __esm({
3334
- "packages/cli/src/sim/env.ts"() {
3335
- "use strict";
3351
+ async function createClient(paths) {
3352
+ const credentials = await loadCredentials(paths);
3353
+ if (credentials === null) {
3354
+ throw new CliError("NOT_LOGGED_IN", "\u672A\u767B\u5F55\uFF1A\u8BF7\u5148\u6267\u884C adep login");
3336
3355
  }
3337
- });
3338
-
3339
- // packages/cli/src/sim/invoke.ts
3340
- function resolveFunctionEntry(files, fnName) {
3341
- const flat = `${fnName}.ts`;
3342
- if (files[flat] !== void 0) return flat;
3343
- const directory = `${fnName}/index.ts`;
3344
- if (files[directory] !== void 0) return directory;
3345
- return void 0;
3346
- }
3347
- function listFunctionNames(files) {
3348
- const names = /* @__PURE__ */ new Set();
3349
- for (const key of Object.keys(files)) {
3350
- const parts = key.split("/");
3351
- if (parts.length === 1 && parts[0] !== void 0 && parts[0].endsWith(".ts")) {
3352
- names.add(parts[0].slice(0, -3));
3353
- } else if (parts.length === 2 && parts[1] === "index.ts" && parts[0] !== void 0) {
3354
- names.add(parts[0]);
3356
+ const server = credentials.server;
3357
+ const cookie = sessionCookieHeader(credentials);
3358
+ const request = async (path, init = {}, fallbackCode = "API_REQUEST_FAILED") => {
3359
+ const method = init.method ?? (init.body === void 0 ? "GET" : "POST");
3360
+ let response;
3361
+ try {
3362
+ response = await fetch(`${server}${path}`, {
3363
+ method,
3364
+ headers: { "content-type": "application/json", cookie },
3365
+ ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) }
3366
+ });
3367
+ } catch (error) {
3368
+ throw new CliError(
3369
+ "SERVER_UNREACHABLE",
3370
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
3371
+ );
3355
3372
  }
3356
- }
3357
- return [...names];
3358
- }
3359
- function createSimInvokeHandler(options) {
3360
- return async (method, args) => {
3361
- if (method !== "invoke") {
3362
- throw new Error(`\u672A\u77E5\u7684 cloud.invoke \u65B9\u6CD5 "${method}"`);
3373
+ const parsed = await parseBody(response);
3374
+ if (response.status < 200 || response.status >= 300) {
3375
+ throw await envelopeError(response, fallbackCode, parsed);
3363
3376
  }
3364
- const input = args[0];
3365
- if (typeof input?.name !== "string" || input.name.length === 0) {
3366
- throw new Error("cloud.invoke \u9700\u8981\u76EE\u6807\u51FD\u6570\u540D\uFF08InvokeInput.name\uFF09");
3377
+ return parsed;
3378
+ };
3379
+ const upload = async (path, form, fallbackCode = "UPLOAD_FAILED") => {
3380
+ let response;
3381
+ try {
3382
+ response = await fetch(`${server}${path}`, {
3383
+ method: "POST",
3384
+ headers: { cookie },
3385
+ body: form
3386
+ });
3387
+ } catch (error) {
3388
+ throw new CliError(
3389
+ "SERVER_UNREACHABLE",
3390
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
3391
+ );
3367
3392
  }
3368
- const targetEntry = resolveFunctionEntry(options.files, input.name);
3369
- if (targetEntry === void 0) {
3370
- throw new Error(`\u76EE\u6807\u51FD\u6570 "${input.name}" \u4E0D\u5B58\u5728`);
3393
+ if (response.status < 200 || response.status >= 300) {
3394
+ throw await envelopeError(response, fallbackCode, await parseBody(response));
3371
3395
  }
3372
- const executeInput = {
3373
- project: { id: "local", slug: "local" },
3374
- fn: { id: input.name, name: input.name },
3375
- files: options.files,
3376
- entry: targetEntry,
3377
- request: {
3378
- method: "POST",
3379
- path: `/${input.name}`,
3380
- query: input.query ?? {},
3381
- headers: {},
3382
- ...input.body === void 0 ? {} : { body: input.body }
3383
- },
3384
- timeoutMs: 1e4,
3385
- ...options.env === void 0 ? {} : { env: options.env }
3386
- };
3387
- const result = await options.executor.execute(executeInput);
3388
- return result.body;
3396
+ return response;
3397
+ };
3398
+ const download = async (url, fallbackCode = "DOWNLOAD_FAILED") => {
3399
+ const target = url.startsWith("http") ? url : `${server}${url}`;
3400
+ let response;
3401
+ try {
3402
+ response = await fetch(target, { headers: { cookie } });
3403
+ } catch (error) {
3404
+ throw new CliError(
3405
+ "SERVER_UNREACHABLE",
3406
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
3407
+ );
3408
+ }
3409
+ if (response.status < 200 || response.status >= 300) {
3410
+ throw await envelopeError(response, fallbackCode, await parseBody(response));
3411
+ }
3412
+ return response;
3389
3413
  };
3414
+ return { server, cookie, request, upload, download };
3390
3415
  }
3391
- var init_invoke = __esm({
3392
- "packages/cli/src/sim/invoke.ts"() {
3393
- "use strict";
3394
- }
3395
- });
3396
-
3397
- // shared/builtin-deps.ts
3398
- var CF_COMPAT_SPECIFIER, STATE_OBJECTS_SPECIFIER, BUILTIN_DEPS, BUILTIN_DEPS_CSV;
3399
- var init_builtin_deps = __esm({
3400
- "shared/builtin-deps.ts"() {
3401
- "use strict";
3402
- CF_COMPAT_SPECIFIER = "@adep/cf-compat";
3403
- STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
3404
- BUILTIN_DEPS = [
3405
- CF_COMPAT_SPECIFIER,
3406
- STATE_OBJECTS_SPECIFIER,
3407
- "axios",
3408
- "lodash",
3409
- "dayjs",
3410
- "zod"
3411
- ];
3412
- BUILTIN_DEPS_CSV = BUILTIN_DEPS.join(",");
3413
- }
3414
- });
3415
-
3416
- // packages/cli/src/builtin-deps.ts
3417
- var LOCAL_BUILTIN_DEPS;
3418
- var init_builtin_deps2 = __esm({
3419
- "packages/cli/src/builtin-deps.ts"() {
3416
+ async function resolveSlug(cwd, slug) {
3417
+ if (slug !== void 0 && slug.length > 0) return slug;
3418
+ const config = await loadConfig(cwd);
3419
+ return config.name;
3420
+ }
3421
+ var init_client = __esm({
3422
+ "packages/cli/src/client.ts"() {
3420
3423
  "use strict";
3421
- init_builtin_deps();
3422
- LOCAL_BUILTIN_DEPS = [CF_COMPAT_SPECIFIER, STATE_OBJECTS_SPECIFIER];
3424
+ init_auth();
3425
+ init_credentials();
3426
+ init_dev();
3423
3427
  }
3424
3428
  });
3425
3429
 
3426
- // packages/cli/src/sim/boundary.ts
3427
- var SIM_BOUNDARIES;
3428
- var init_boundary = __esm({
3429
- "packages/cli/src/sim/boundary.ts"() {
3430
- "use strict";
3431
- SIM_BOUNDARIES = [
3432
- {
3433
- kind: "capability",
3434
- title: "\u89E6\u53D1\u5668\u4E0D\u81EA\u52A8\u6267\u884C",
3435
- detail: "\u5B9A\u65F6 / \u4E8B\u4EF6\u89E6\u53D1\u5668\u53EA\u767B\u8BB0\uFF0C\u4E0D\u7531\u6A21\u62DF\u5668\u81EA\u52A8\u89E6\u53D1\uFF08\u672C\u5730\u4EE5\u624B\u5DE5 HTTP \u8C03\u7528\u66FF\u4EE3\uFF09\u3002"
3436
- },
3437
- {
3438
- kind: "diff",
3439
- title: "\u65E0\u8DE8\u5B9E\u4F8B\u5E7F\u64AD",
3440
- detail: "cloud.realtime \u5DF2\u6CE8\u5165\uFF0C\u4F46\u4E3A\u5355\u8FDB\u7A0B\u5185\u5B58\u5E7F\u64AD\uFF1A\u4E0D\u652F\u6301\u8DE8\u8FDB\u7A0B / \u8DE8\u5B9E\u4F8B\uFF0C\u7EBF\u4E0A\u591A\u5B9E\u4F8B\u8BED\u4E49\u4E0D\u540C\u3002"
3441
- },
3442
- {
3443
- kind: "capability",
3444
- title: "publish \u4E0D\u652F\u6301 except",
3445
- detail: "\u672C\u5730\u4E0D\u5EFA WS \u63E1\u624B\u3001\u65E0\u8FDE\u63A5\u8EAB\u4EFD\uFF0C\u6545 cloud.realtime.publish \u7684 except\uFF08\u4E0D\u53D1\u56DE\u53D1\u9001\u8005\uFF09\u65E0\u4ECE\u5B9E\u73B0\uFF0C\u4F20\u5165\u5373\u62A5\u9519\u3002"
3446
- },
3447
- {
3448
- kind: "capability",
3449
- title: "\u65E0\u9650\u989D\u7B49\u4EF7",
3450
- detail: "\u672C\u5730\u4E0D\u6267\u884C\u8BA1\u91CF / \u914D\u989D\u95E8\u7981\uFF08\u4E0D\u6309\u51FD\u6570\u8C03\u7528\u3001\u6D41\u91CF\u3001\u63A8\u9001\u8BA1\u6570\uFF09\uFF0C\u9650\u989D\u8BED\u4E49\u4EC5\u7EBF\u4E0A\u751F\u6548\u3002"
3451
- },
3452
- {
3453
- kind: "diff",
3454
- title: "\u4E0D\u8BA1\u91CF",
3455
- detail: "\u672C\u6A21\u62DF\u8FD0\u884C\u65F6\u4E0D\u4EA7\u51FA\u8BA1\u91CF\u4E8B\u4EF6\uFF0C\u4E5F\u4E0D\u5199 billing\uFF1B\u79BB\u7EBF\u5F00\u53D1\u4E0D\u8BA1\u8D39\u3002"
3456
- }
3457
- ];
3458
- }
3430
+ // packages/cli/src/db.ts
3431
+ var db_exports = {};
3432
+ __export(db_exports, {
3433
+ dbExec: () => dbExec,
3434
+ dbMigrate: () => dbMigrate,
3435
+ dbRollback: () => dbRollback,
3436
+ dbSnapshotCreate: () => dbSnapshotCreate,
3437
+ dbSnapshotList: () => dbSnapshotList,
3438
+ dbSnapshotRestore: () => dbSnapshotRestore,
3439
+ dbStart: () => dbStart,
3440
+ dbStatus: () => dbStatus,
3441
+ dbStop: () => dbStop,
3442
+ splitSqlStatements: () => splitSqlStatements
3459
3443
  });
3460
-
3461
- // packages/cli/src/ts-config.ts
3462
- import { stat as stat6, readFile as readFile7 } from "node:fs/promises";
3463
- import { join as join10 } from "node:path";
3464
- async function loadAdepConfigModule(cwd) {
3465
- const configPath = join10(cwd, "adep.config.ts");
3466
- try {
3467
- await stat6(configPath);
3468
- } catch {
3469
- return null;
3470
- }
3471
- let rawDefault;
3472
- try {
3473
- const bun = globalThis.Bun;
3444
+ import { readFile as readFile6 } from "node:fs/promises";
3445
+ import { resolve as resolve4 } from "node:path";
3446
+ async function open2(paths, options) {
3447
+ const client = await createClient(paths);
3448
+ const project2 = await resolveSlug(resolve4(options.cwd), options.slug);
3449
+ return { client, project: project2 };
3450
+ }
3451
+ async function dbStart(paths, options) {
3452
+ const { client, project: project2 } = await open2(paths, options);
3453
+ return client.request(`/api/v1/projects/${project2}/database`, { method: "POST" });
3454
+ }
3455
+ async function dbStatus(paths, options) {
3456
+ const { client, project: project2 } = await open2(paths, options);
3457
+ return client.request(`/api/v1/projects/${project2}/database`);
3458
+ }
3459
+ async function dbStop(paths, options) {
3460
+ const { client, project: project2 } = await open2(paths, options);
3461
+ return client.request(`/api/v1/projects/${project2}/database`, {
3462
+ method: "DELETE"
3463
+ });
3464
+ }
3465
+ async function dbExec(paths, options) {
3466
+ const { client, project: project2 } = await open2(paths, options);
3467
+ return client.request(
3468
+ `/api/v1/projects/${project2}/database/console/sql`,
3469
+ {
3470
+ method: "POST",
3471
+ body: {
3472
+ sql: options.sql,
3473
+ ...options.params === void 0 ? {} : { params: options.params },
3474
+ ...options.confirmTable === void 0 ? {} : { confirmTable: options.confirmTable }
3475
+ }
3476
+ },
3477
+ "SQL_EXEC_FAILED"
3478
+ );
3479
+ }
3480
+ async function dbSnapshotList(paths, options) {
3481
+ const { client, project: project2 } = await open2(paths, options);
3482
+ return client.request(
3483
+ `/api/v1/projects/${project2}/database/snapshots`
3484
+ );
3485
+ }
3486
+ async function dbSnapshotCreate(paths, options) {
3487
+ const { client, project: project2 } = await open2(paths, options);
3488
+ return client.request(`/api/v1/projects/${project2}/database/snapshots`, {
3489
+ method: "POST"
3490
+ });
3491
+ }
3492
+ async function dbSnapshotRestore(paths, options) {
3493
+ const { client, project: project2 } = await open2(paths, options);
3494
+ return client.request(
3495
+ `/api/v1/projects/${project2}/database/snapshots/${options.snapshotId}/restore`,
3496
+ { method: "POST" }
3497
+ );
3498
+ }
3499
+ async function dbRollback(paths, options) {
3500
+ const { client, project: project2 } = await open2(paths, options);
3501
+ return client.request(
3502
+ `/api/v1/projects/${project2}/database/rollback`,
3503
+ { method: "POST", body: { to: options.to } }
3504
+ );
3505
+ }
3506
+ function splitSqlStatements(source) {
3507
+ const statements = [];
3508
+ let buffer = "";
3509
+ let inQuote = false;
3510
+ const lines = source.split("\n");
3511
+ for (const rawLine of lines) {
3512
+ const trimmed = rawLine.trim();
3513
+ if (!inQuote && (trimmed.length === 0 || trimmed.startsWith("--"))) continue;
3514
+ for (let i = 0; i < rawLine.length; i++) {
3515
+ const ch = rawLine[i];
3516
+ if (inQuote) {
3517
+ if (ch === "'") {
3518
+ if (rawLine[i + 1] === "'") {
3519
+ buffer += ch + rawLine[i + 1];
3520
+ i++;
3521
+ continue;
3522
+ }
3523
+ inQuote = false;
3524
+ }
3525
+ buffer += ch;
3526
+ continue;
3527
+ }
3528
+ if (ch === "'") {
3529
+ inQuote = true;
3530
+ buffer += ch;
3531
+ continue;
3532
+ }
3533
+ if (ch === "-" && rawLine[i + 1] === "-") break;
3534
+ if (ch === ";") {
3535
+ const statement = buffer.trim();
3536
+ if (statement.length > 0) statements.push(statement);
3537
+ buffer = "";
3538
+ continue;
3539
+ }
3540
+ buffer += ch;
3541
+ }
3542
+ buffer += inQuote ? "\n" : " ";
3543
+ }
3544
+ if (inQuote) {
3545
+ throw new Error(`SQL \u8FC1\u79FB\u6587\u4EF6\u5F15\u53F7\u672A\u95ED\u5408\uFF1A${buffer.trim().slice(0, 80)}\u2026`);
3546
+ }
3547
+ const tail = buffer.trim();
3548
+ if (tail.length > 0) statements.push(tail);
3549
+ return statements;
3550
+ }
3551
+ async function dbMigrate(paths, options) {
3552
+ const source = await readFile6(resolve4(options.file), "utf8");
3553
+ const statements = splitSqlStatements(source);
3554
+ if (statements.length === 0) {
3555
+ throw new Error(`\u8FC1\u79FB\u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${options.file}`);
3556
+ }
3557
+ const { project: project2 } = await open2(paths, options);
3558
+ const applied = [];
3559
+ const changes = [];
3560
+ for (const statement of statements) {
3561
+ try {
3562
+ const result = await dbExec(paths, {
3563
+ cwd: options.cwd,
3564
+ ...options.slug === void 0 ? {} : { slug: options.slug },
3565
+ sql: statement
3566
+ });
3567
+ applied.push(statement);
3568
+ changes.push(result.changes);
3569
+ } catch (error) {
3570
+ const code = error instanceof CliError ? error.code : "MIGRATE_FAILED";
3571
+ const message = error instanceof Error ? error.message : String(error);
3572
+ return {
3573
+ projectId: project2,
3574
+ applied,
3575
+ changes,
3576
+ failed: { statement, code, message }
3577
+ };
3578
+ }
3579
+ }
3580
+ return { projectId: project2, applied, changes };
3581
+ }
3582
+ var init_db2 = __esm({
3583
+ "packages/cli/src/db.ts"() {
3584
+ "use strict";
3585
+ init_auth();
3586
+ init_client();
3587
+ }
3588
+ });
3589
+
3590
+ // packages/cli/src/serve/sqlite-driver.ts
3591
+ import { mkdir as mkdir7 } from "node:fs/promises";
3592
+ import { dirname as dirname8, resolve as resolve5 } from "node:path";
3593
+ function isBun(versions) {
3594
+ return versions["bun"] !== void 0 && versions["bun"] !== "";
3595
+ }
3596
+ function detectSqliteRuntime(versions = process.versions) {
3597
+ if (isBun(versions)) return "bun";
3598
+ const raw = versions["node"];
3599
+ if (raw === void 0) return null;
3600
+ const [majorText, minorText] = raw.split(".");
3601
+ const major = Number(majorText);
3602
+ const minor = Number(minorText ?? "0");
3603
+ if (!Number.isInteger(major) || !Number.isInteger(minor)) return null;
3604
+ if (major > NODE_SQLITE_MIN.major) return "node";
3605
+ if (major === NODE_SQLITE_MIN.major && minor >= NODE_SQLITE_MIN.minor) return "node";
3606
+ return null;
3607
+ }
3608
+ function sqliteModuleName(runtime) {
3609
+ return runtime === "bun" ? "bun:sqlite" : "node:sqlite";
3610
+ }
3611
+ function sqliteUnavailableReason(versions = process.versions) {
3612
+ const current = isBun(versions) ? `Bun ${versions["bun"] ?? ""}`.trim() : `Node ${versions["node"] ?? "\u672A\u77E5"}`;
3613
+ return `\u5F53\u524D\u8FD0\u884C\u65F6 ${current} \u4E0D\u63D0\u4F9B SQLite \u5185\u5EFA\u6A21\u5757\uFF08\u9700\u8981 Bun \u6216 Node \u2265 ${NODE_SQLITE_MIN.major}.${NODE_SQLITE_MIN.minor}\uFF09`;
3614
+ }
3615
+ function sqliteRuntimeRequirementMessage(versions = process.versions) {
3616
+ return `--db sqlite \u9700\u8981 Bun\uFF08\u5185\u7F6E bun:sqlite\uFF09\u6216 Node \u2265 ${NODE_SQLITE_MIN.major}.${NODE_SQLITE_MIN.minor}\uFF08\u5185\u7F6E node:sqlite\uFF09\uFF1B${sqliteUnavailableReason(versions)}\u3002\u8BF7\u6539\u7528 \`--db sim\`\uFF08\u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\uFF0C\u65E0\u9700\u989D\u5916\u8FD0\u884C\u65F6\uFF09\uFF0C\u6216\u5347\u7EA7 Node / \u7528 Bun \u8FD0\u884C\u3002`;
3617
+ }
3618
+ async function openSqliteProjectDriver(file, options = {}) {
3619
+ const runtime = options.runtime ?? detectSqliteRuntime();
3620
+ if (runtime === null) throw new Error(sqliteRuntimeRequirementMessage());
3621
+ const moduleName = sqliteModuleName(runtime);
3622
+ const ctorName = runtime === "bun" ? "Database" : "DatabaseSync";
3623
+ let mod;
3624
+ try {
3625
+ const specifier = moduleName;
3626
+ mod = await import(
3627
+ /* @vite-ignore */
3628
+ specifier
3629
+ );
3630
+ } catch (error) {
3631
+ throw new Error(
3632
+ `${sqliteRuntimeRequirementMessage()}
3633
+ \uFF08\u8F7D\u5165 ${moduleName} \u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}\uFF09`,
3634
+ { cause: error }
3635
+ );
3636
+ }
3637
+ const Ctor = mod[ctorName];
3638
+ if (Ctor === void 0) {
3639
+ throw new Error(`${moduleName} \u672A\u5BFC\u51FA ${ctorName}\uFF1A\u5F53\u524D\u8FD0\u884C\u65F6\u7684 SQLite \u5185\u5EFA\u6A21\u5757\u4E0D\u53EF\u7528`);
3640
+ }
3641
+ const target = file === ":memory:" ? file : resolve5(file);
3642
+ if (target !== ":memory:") await mkdir7(dirname8(target), { recursive: true });
3643
+ const database = new Ctor(target);
3644
+ database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
3645
+ return {
3646
+ engine: "sqlite",
3647
+ async run(sql, params = []) {
3648
+ if (params.length === 0) {
3649
+ database.exec(sql);
3650
+ return { changes: 0 };
3651
+ }
3652
+ const result = database.prepare(sql).run(...params);
3653
+ return { changes: Number(result.changes) };
3654
+ },
3655
+ async all(sql, params = []) {
3656
+ const statement = database.prepare(sql);
3657
+ statement.setReturnArrays?.(false);
3658
+ return statement.all(...params);
3659
+ },
3660
+ async get(sql, params = []) {
3661
+ const statement = database.prepare(sql);
3662
+ statement.setReturnArrays?.(false);
3663
+ const row = statement.get(...params);
3664
+ return row ?? null;
3665
+ },
3666
+ async close() {
3667
+ database.close();
3668
+ }
3669
+ };
3670
+ }
3671
+ var NODE_SQLITE_MIN;
3672
+ var init_sqlite_driver = __esm({
3673
+ "packages/cli/src/serve/sqlite-driver.ts"() {
3674
+ "use strict";
3675
+ NODE_SQLITE_MIN = { major: 22, minor: 5 };
3676
+ }
3677
+ });
3678
+
3679
+ // packages/cli/src/serve/db-mode.ts
3680
+ import { readFile as readFile7 } from "node:fs/promises";
3681
+ import { join as join9, relative as relative2, resolve as resolve6 } from "node:path";
3682
+ function isServeDbMode(value) {
3683
+ return SERVE_DB_MODES.includes(value.trim().toLowerCase());
3684
+ }
3685
+ function parseServeDbMode(raw, source) {
3686
+ const value = raw.trim().toLowerCase();
3687
+ if (!isServeDbMode(value)) {
3688
+ throw new Error(
3689
+ `${source} \u7684\u6570\u636E\u5E93\u6A21\u5F0F "${raw}" \u65E0\u6548\uFF1A\u53EA\u652F\u6301 ${SERVE_DB_MODES.join(" | ")}\uFF08sim = \u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\u4E0E .adep/sim/db.json\uFF1Bsqlite = \u771F\u5B9E SQLite \u5E93\u6587\u4EF6\uFF09`
3690
+ );
3691
+ }
3692
+ return value;
3693
+ }
3694
+ function resolveServeDbMode(explicit) {
3695
+ if (explicit !== void 0) return parseServeDbMode(explicit, "--db");
3696
+ const fromEnv = process.env["ADEP_SERVE_DB"];
3697
+ if (fromEnv !== void 0 && fromEnv.trim() !== "") {
3698
+ return parseServeDbMode(fromEnv, "ADEP_SERVE_DB");
3699
+ }
3700
+ return DEFAULT_SERVE_DB_MODE;
3701
+ }
3702
+ function resolveServeDbFile(cwd, explicit) {
3703
+ const raw = explicit ?? envDbFile() ?? DEFAULT_SQLITE_DB_FILE;
3704
+ return raw === ":memory:" ? raw : resolve6(cwd, raw);
3705
+ }
3706
+ function envDbFile() {
3707
+ const raw = process.env["ADEP_SERVE_DB_FILE"];
3708
+ return raw === void 0 || raw.trim() === "" ? void 0 : raw.trim();
3709
+ }
3710
+ function displayPath(cwd, target) {
3711
+ if (target === ":memory:") return target;
3712
+ const rel = relative2(cwd, target);
3713
+ return rel.startsWith("..") ? target : rel;
3714
+ }
3715
+ function simDbTarget(cwd) {
3716
+ return displayPath(cwd, join9(simDir(cwd), "db.json"));
3717
+ }
3718
+ function resolveLocalDbTarget(cwd, options) {
3719
+ const mode = resolveServeDbMode(options.db);
3720
+ return {
3721
+ mode,
3722
+ file: mode === "sqlite" ? resolveServeDbFile(cwd, options.dbFile) : null
3723
+ };
3724
+ }
3725
+ async function openLocalDbDriver(target, options) {
3726
+ if (target.mode === "sim" || target.file === null) {
3727
+ return { mode: "sim", file: null, module: null, driver: null };
3728
+ }
3729
+ const simTarget = simDbTarget(options.cwd);
3730
+ const runtimeName = detectSqliteRuntime();
3731
+ if (runtimeName === null) {
3732
+ options.log(
3733
+ `[${options.tag}] \u8B66\u544A\uFF1A${sqliteUnavailableReason()}\uFF0C\u5DF2\u81EA\u52A8\u964D\u7EA7\u4E3A sim \u6A21\u5F0F\uFF08\u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\uFF0C\u5E93 ${simTarget}\uFF09\u3002\u5982\u9700\u771F\u5B9E SQLite\uFF0C\u8BF7\u7528 Bun \u6216\u5347\u7EA7 Node \u540E\u91CD\u8BD5\u3002`
3734
+ );
3735
+ return { mode: "sim", file: null, module: null, driver: null };
3736
+ }
3737
+ try {
3738
+ const driver = await openSqliteProjectDriver(target.file, { runtime: runtimeName });
3739
+ return {
3740
+ mode: "sqlite",
3741
+ file: target.file,
3742
+ module: sqliteModuleName(runtimeName),
3743
+ driver
3744
+ };
3745
+ } catch (error) {
3746
+ const detail = error instanceof Error ? error.message : String(error);
3747
+ options.log(
3748
+ `[${options.tag}] \u8B66\u544A\uFF1A\u6253\u5F00 SQLite \u5E93\u5931\u8D25\uFF08${detail}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u964D\u7EA7\u4E3A sim \u6A21\u5F0F\uFF08\u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\uFF0C\u5E93 ${simTarget}\uFF09\u3002`
3749
+ );
3750
+ return { mode: "sim", file: null, module: null, driver: null };
3751
+ }
3752
+ }
3753
+ async function applyLocalSchema(driver, options) {
3754
+ const { schemaFile, mode, tag, cwd, log } = options;
3755
+ const schemaPath = resolve6(cwd, schemaFile);
3756
+ const schemaSource = await readFile7(schemaPath, "utf8").catch((error) => {
3757
+ if (error.code === "ENOENT") {
3758
+ throw new Error(`schema \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${schemaPath}`);
3759
+ }
3760
+ throw error;
3761
+ });
3762
+ const statements = splitSqlStatements(schemaSource);
3763
+ let applied = 0;
3764
+ let skipped = 0;
3765
+ for (const [index, statement] of statements.entries()) {
3766
+ try {
3767
+ await driver.run(statement);
3768
+ applied += 1;
3769
+ } catch (error) {
3770
+ const isUnsupported = error instanceof Error && "code" in error && error.code === "DB_UNSAFE_OP";
3771
+ if (mode === "sim" && isUnsupported) {
3772
+ skipped += 1;
3773
+ log(`[${tag}] \u8DF3\u8FC7 schema \u8BED\u53E5\uFF08sim \u5F15\u64CE\u4E0D\u652F\u6301\uFF09\uFF1A${statement.slice(0, 60)}\u2026`);
3774
+ continue;
3775
+ }
3776
+ const detail = error instanceof Error ? error.message : String(error);
3777
+ throw new Error(
3778
+ `schema \u8BED\u53E5\u6267\u884C\u5931\u8D25\uFF08--schema ${schemaFile}\uFF0C\u7B2C ${index + 1} \u6761\uFF0Cdb \u6A21\u5F0F ${mode}\uFF09\uFF1A${detail}
3779
+ \u8BED\u53E5\uFF1A${statement.slice(0, 200)}` + (mode === "sqlite" ? "\n\uFF08sqlite \u6A21\u5F0F\u4E0D\u505A\u8BED\u53E5\u8DF3\u8FC7\uFF1B\u5982\u9700\u8DF3\u8FC7\u8BED\u4E49\u8BF7\u6539\u7528 --db sim\uFF09" : ""),
3780
+ { cause: error }
3781
+ );
3782
+ }
3783
+ }
3784
+ const skipNote = skipped > 0 ? `\uFF0C\u8DF3\u8FC7 ${skipped} \u6761` : "";
3785
+ log(`[${tag}] \u5DF2\u5E94\u7528\u6570\u636E\u5E93\u7ED3\u6784\uFF08--schema ${schemaFile}\uFF09\uFF1A${applied} \u6761\u8BED\u53E5${skipNote}`);
3786
+ }
3787
+ var SERVE_DB_MODES, DEFAULT_SERVE_DB_MODE, DEFAULT_SQLITE_DB_FILE;
3788
+ var init_db_mode = __esm({
3789
+ "packages/cli/src/serve/db-mode.ts"() {
3790
+ "use strict";
3791
+ init_db2();
3792
+ init_runtime();
3793
+ init_sqlite_driver();
3794
+ SERVE_DB_MODES = ["sim", "sqlite"];
3795
+ DEFAULT_SERVE_DB_MODE = "sqlite";
3796
+ DEFAULT_SQLITE_DB_FILE = ".adep/data/project.sqlite";
3797
+ }
3798
+ });
3799
+
3800
+ // packages/cli/src/sim/env.ts
3801
+ import { readFile as readFile8 } from "node:fs/promises";
3802
+ import { join as join10 } from "node:path";
3803
+ function parseEnv(content) {
3804
+ const env = {};
3805
+ for (const raw of content.split(/\r?\n/)) {
3806
+ const line = raw.trim();
3807
+ if (line.length === 0 || line.startsWith("#")) continue;
3808
+ const eq = line.indexOf("=");
3809
+ if (eq === -1) continue;
3810
+ const key = line.slice(0, eq).trim();
3811
+ if (key.length === 0) continue;
3812
+ env[key] = line.slice(eq + 1).trim();
3813
+ }
3814
+ return env;
3815
+ }
3816
+ async function loadSimEnv(cwd, config = {}) {
3817
+ const envRoot = await readFile8(join10(cwd, ".env"), "utf8").catch(() => "");
3818
+ const envLocal = await readFile8(join10(cwd, ".env.local"), "utf8").catch(() => "");
3819
+ const merged = { ...parseEnv(envRoot), ...parseEnv(envLocal) };
3820
+ for (const secret of config.secrets ?? []) {
3821
+ if (merged[secret] !== void 0) continue;
3822
+ if (process.env[secret] !== void 0) {
3823
+ merged[secret] = process.env[secret];
3824
+ continue;
3825
+ }
3826
+ throw new Error(
3827
+ `secret "${secret}" \u672A\u914D\u7F6E\uFF1A\u8BF7\u5728 .env.local \u6DFB\u52A0 ${secret}=<value>\uFF0C\u6216\u7528\u73AF\u5883\u53D8\u91CF\u5BFC\u51FA\u540E\u91CD\u8BD5 adep dev\uFF08\u6A21\u62DF\u73AF\u5883\u6C38\u4E0D\u843D\u76D8\u8BE5\u503C\uFF09`
3828
+ );
3829
+ }
3830
+ return merged;
3831
+ }
3832
+ var init_env = __esm({
3833
+ "packages/cli/src/sim/env.ts"() {
3834
+ "use strict";
3835
+ }
3836
+ });
3837
+
3838
+ // packages/cli/src/sim/invoke.ts
3839
+ function resolveFunctionEntry(files, fnName) {
3840
+ const flat = `${fnName}.ts`;
3841
+ if (files[flat] !== void 0) return flat;
3842
+ const directory = `${fnName}/index.ts`;
3843
+ if (files[directory] !== void 0) return directory;
3844
+ return void 0;
3845
+ }
3846
+ function listFunctionNames(files) {
3847
+ const names = /* @__PURE__ */ new Set();
3848
+ for (const key of Object.keys(files)) {
3849
+ const parts = key.split("/");
3850
+ if (parts.length === 1 && parts[0] !== void 0 && parts[0].endsWith(".ts")) {
3851
+ names.add(parts[0].slice(0, -3));
3852
+ } else if (parts.length === 2 && parts[1] === "index.ts" && parts[0] !== void 0) {
3853
+ names.add(parts[0]);
3854
+ }
3855
+ }
3856
+ return [...names];
3857
+ }
3858
+ function createSimInvokeHandler(options) {
3859
+ return async (method, args) => {
3860
+ if (method !== "invoke") {
3861
+ throw new Error(`\u672A\u77E5\u7684 cloud.invoke \u65B9\u6CD5 "${method}"`);
3862
+ }
3863
+ const input = args[0];
3864
+ if (typeof input?.name !== "string" || input.name.length === 0) {
3865
+ throw new Error("cloud.invoke \u9700\u8981\u76EE\u6807\u51FD\u6570\u540D\uFF08InvokeInput.name\uFF09");
3866
+ }
3867
+ const targetEntry = resolveFunctionEntry(options.files, input.name);
3868
+ if (targetEntry === void 0) {
3869
+ throw new Error(`\u76EE\u6807\u51FD\u6570 "${input.name}" \u4E0D\u5B58\u5728`);
3870
+ }
3871
+ const executeInput = {
3872
+ project: { id: "local", slug: "local" },
3873
+ fn: { id: input.name, name: input.name },
3874
+ files: options.files,
3875
+ entry: targetEntry,
3876
+ request: {
3877
+ method: "POST",
3878
+ path: `/${input.name}`,
3879
+ query: input.query ?? {},
3880
+ headers: {},
3881
+ ...input.body === void 0 ? {} : { body: input.body }
3882
+ },
3883
+ timeoutMs: 1e4,
3884
+ ...options.env === void 0 ? {} : { env: options.env }
3885
+ };
3886
+ const result = await options.executor.execute(executeInput);
3887
+ return result.body;
3888
+ };
3889
+ }
3890
+ var init_invoke = __esm({
3891
+ "packages/cli/src/sim/invoke.ts"() {
3892
+ "use strict";
3893
+ }
3894
+ });
3895
+
3896
+ // shared/builtin-deps.ts
3897
+ var CF_COMPAT_SPECIFIER, STATE_OBJECTS_SPECIFIER, CRYPTO_SPECIFIER, ROUTE_SPECIFIER, BUILTIN_DEPS, BUILTIN_DEPS_CSV;
3898
+ var init_builtin_deps = __esm({
3899
+ "shared/builtin-deps.ts"() {
3900
+ "use strict";
3901
+ CF_COMPAT_SPECIFIER = "@adep/cf-compat";
3902
+ STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
3903
+ CRYPTO_SPECIFIER = "@adep/crypto";
3904
+ ROUTE_SPECIFIER = "@adep/runtime/route";
3905
+ BUILTIN_DEPS = [
3906
+ CF_COMPAT_SPECIFIER,
3907
+ STATE_OBJECTS_SPECIFIER,
3908
+ CRYPTO_SPECIFIER,
3909
+ ROUTE_SPECIFIER,
3910
+ "axios",
3911
+ "lodash",
3912
+ "dayjs",
3913
+ "zod"
3914
+ ];
3915
+ BUILTIN_DEPS_CSV = BUILTIN_DEPS.join(",");
3916
+ }
3917
+ });
3918
+
3919
+ // packages/cli/src/builtin-deps.ts
3920
+ var LOCAL_BUILTIN_DEPS;
3921
+ var init_builtin_deps2 = __esm({
3922
+ "packages/cli/src/builtin-deps.ts"() {
3923
+ "use strict";
3924
+ init_builtin_deps();
3925
+ LOCAL_BUILTIN_DEPS = [
3926
+ CF_COMPAT_SPECIFIER,
3927
+ STATE_OBJECTS_SPECIFIER,
3928
+ CRYPTO_SPECIFIER,
3929
+ ROUTE_SPECIFIER
3930
+ ];
3931
+ }
3932
+ });
3933
+
3934
+ // packages/cli/src/sim/boundary.ts
3935
+ var SIM_BOUNDARIES;
3936
+ var init_boundary = __esm({
3937
+ "packages/cli/src/sim/boundary.ts"() {
3938
+ "use strict";
3939
+ SIM_BOUNDARIES = [
3940
+ {
3941
+ kind: "capability",
3942
+ title: "\u89E6\u53D1\u5668\u4E0D\u81EA\u52A8\u6267\u884C",
3943
+ detail: "\u5B9A\u65F6 / \u4E8B\u4EF6\u89E6\u53D1\u5668\u53EA\u767B\u8BB0\uFF0C\u4E0D\u7531\u6A21\u62DF\u5668\u81EA\u52A8\u89E6\u53D1\uFF08\u672C\u5730\u4EE5\u624B\u5DE5 HTTP \u8C03\u7528\u66FF\u4EE3\uFF09\u3002"
3944
+ },
3945
+ {
3946
+ kind: "diff",
3947
+ title: "\u65E0\u8DE8\u5B9E\u4F8B\u5E7F\u64AD",
3948
+ detail: "cloud.realtime \u5DF2\u6CE8\u5165\uFF0C\u4F46\u4E3A\u5355\u8FDB\u7A0B\u5185\u5B58\u5E7F\u64AD\uFF1A\u4E0D\u652F\u6301\u8DE8\u8FDB\u7A0B / \u8DE8\u5B9E\u4F8B\uFF0C\u7EBF\u4E0A\u591A\u5B9E\u4F8B\u8BED\u4E49\u4E0D\u540C\u3002"
3949
+ },
3950
+ {
3951
+ kind: "capability",
3952
+ title: "publish \u4E0D\u652F\u6301 except",
3953
+ detail: "\u672C\u5730\u4E0D\u5EFA WS \u63E1\u624B\u3001\u65E0\u8FDE\u63A5\u8EAB\u4EFD\uFF0C\u6545 cloud.realtime.publish \u7684 except\uFF08\u4E0D\u53D1\u56DE\u53D1\u9001\u8005\uFF09\u65E0\u4ECE\u5B9E\u73B0\uFF0C\u4F20\u5165\u5373\u62A5\u9519\u3002"
3954
+ },
3955
+ {
3956
+ kind: "capability",
3957
+ title: "\u65E0\u9650\u989D\u7B49\u4EF7",
3958
+ detail: "\u672C\u5730\u4E0D\u6267\u884C\u8BA1\u91CF / \u914D\u989D\u95E8\u7981\uFF08\u4E0D\u6309\u51FD\u6570\u8C03\u7528\u3001\u6D41\u91CF\u3001\u63A8\u9001\u8BA1\u6570\uFF09\uFF0C\u9650\u989D\u8BED\u4E49\u4EC5\u7EBF\u4E0A\u751F\u6548\u3002"
3959
+ },
3960
+ {
3961
+ kind: "diff",
3962
+ title: "\u4E0D\u8BA1\u91CF",
3963
+ detail: "\u672C\u6A21\u62DF\u8FD0\u884C\u65F6\u4E0D\u4EA7\u51FA\u8BA1\u91CF\u4E8B\u4EF6\uFF0C\u4E5F\u4E0D\u5199 billing\uFF1B\u79BB\u7EBF\u5F00\u53D1\u4E0D\u8BA1\u8D39\u3002"
3964
+ }
3965
+ ];
3966
+ }
3967
+ });
3968
+
3969
+ // packages/cli/src/ts-config.ts
3970
+ import { stat as stat6, readFile as readFile9 } from "node:fs/promises";
3971
+ import { join as join11 } from "node:path";
3972
+ async function loadAdepConfigModule(cwd) {
3973
+ const configPath = join11(cwd, "adep.config.ts");
3974
+ try {
3975
+ await stat6(configPath);
3976
+ } catch {
3977
+ return null;
3978
+ }
3979
+ let rawDefault;
3980
+ try {
3981
+ const bun = globalThis.Bun;
3474
3982
  if (bun !== void 0) {
3475
3983
  const mod = await import(configPath);
3476
3984
  rawDefault = mod.default;
3477
3985
  } else {
3478
3986
  const { transform } = await import("esbuild");
3479
- const source = await readFile7(configPath, "utf8");
3987
+ const source = await readFile9(configPath, "utf8");
3480
3988
  const { code } = await transform(source, {
3481
3989
  loader: "ts",
3482
3990
  format: "esm",
@@ -4424,7 +4932,7 @@ var init_chain = __esm({
4424
4932
  // packages/runtime/src/functions/runtime/worker-entry.ts
4425
4933
  import { parentPort, workerData } from "node:worker_threads";
4426
4934
  import { createRequire } from "node:module";
4427
- import { join as join11 } from "node:path";
4935
+ import { join as join12 } from "node:path";
4428
4936
  function isRpcCapability(value) {
4429
4937
  return typeof value === "object" && value !== null && value[RPC_CAPABILITY_KEY] === true;
4430
4938
  }
@@ -4473,7 +4981,7 @@ function errorMessageWithLocation(error, files) {
4473
4981
  }
4474
4982
  function createBareResolver(deps) {
4475
4983
  const platformRequire = createRequire(import.meta.url);
4476
- const depsRequire = deps.dir === null ? null : createRequire(join11(deps.dir, "__deps__.js"));
4984
+ const depsRequire = deps.dir === null ? null : createRequire(join12(deps.dir, "__deps__.js"));
4477
4985
  return (request) => {
4478
4986
  if (deps.builtin.includes(request)) return platformRequire(request);
4479
4987
  const root = splitBareSpecifier(request);
@@ -4664,8 +5172,8 @@ var init_shared_source = __esm({
4664
5172
  });
4665
5173
 
4666
5174
  // packages/cli/src/dev-shared.ts
4667
- import { readdir as readdir4, readFile as readFile8 } from "node:fs/promises";
4668
- import { join as join12 } from "node:path";
5175
+ import { readdir as readdir4, readFile as readFile10 } from "node:fs/promises";
5176
+ import { join as join13 } from "node:path";
4669
5177
  function bearerUserResolverFromEnv() {
4670
5178
  const raw = process.env.ADEP_AUTH_ISSUER;
4671
5179
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -4706,11 +5214,11 @@ async function collectFunctions(dir) {
4706
5214
  }
4707
5215
  for (const entry of entries) {
4708
5216
  const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
4709
- const full = join12(sub, entry.name);
5217
+ const full = join13(sub, entry.name);
4710
5218
  if (entry.isDirectory()) {
4711
5219
  await walk(full, rel);
4712
5220
  } else if (entry.isFile() && isRuntimeSource(entry.name)) {
4713
- files[rel] = await readFile8(full, "utf8");
5221
+ files[rel] = await readFile10(full, "utf8");
4714
5222
  }
4715
5223
  }
4716
5224
  };
@@ -4798,10 +5306,10 @@ __export(dev_exports, {
4798
5306
  });
4799
5307
  import { createServer } from "node:http";
4800
5308
  import { watch } from "node:fs";
4801
- import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile6 } from "node:fs/promises";
4802
- import { basename as basename2, join as join13, resolve as resolve4 } from "node:path";
5309
+ import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile6 } from "node:fs/promises";
5310
+ import { basename as basename2, join as join14, resolve as resolve7 } from "node:path";
4803
5311
  async function loadConfig(cwd) {
4804
- const name = basename2(resolve4(cwd));
5312
+ const name = basename2(resolve7(cwd));
4805
5313
  const config = await loadAdepConfigModule(cwd);
4806
5314
  return {
4807
5315
  name: config?.name ?? name,
@@ -4843,34 +5351,49 @@ function printBoundaries(log) {
4843
5351
  }
4844
5352
  }
4845
5353
  async function ensureGitignore(cwd) {
4846
- const gitignorePath = join13(cwd, ".gitignore");
4847
- const existing = await readFile9(gitignorePath, "utf8").catch(() => "");
5354
+ const gitignorePath = join14(cwd, ".gitignore");
5355
+ const existing = await readFile11(gitignorePath, "utf8").catch(() => "");
4848
5356
  if (existing.split(/\r?\n/).includes(".adep/")) return;
4849
5357
  await writeFile6(gitignorePath, `${existing.replace(/\n+$/, "")}
4850
5358
  .adep/
4851
5359
  `, "utf8");
4852
5360
  }
4853
5361
  async function startDevServer(options) {
4854
- const cwd = resolve4(options.cwd);
5362
+ const cwd = resolve7(options.cwd);
4855
5363
  const log = options.log ?? ((line) => process.stdout.write(`${line}
4856
5364
  `));
4857
5365
  const config = await loadConfig(cwd);
4858
5366
  if (options.prefix !== void 0) {
4859
5367
  config.functionsPrefix = options.prefix.replace(/^\/+|\/+$/g, "");
4860
5368
  }
4861
- const functionsDir = join13(cwd, config.functionsDir);
5369
+ const functionsDir = join14(cwd, config.functionsDir);
4862
5370
  const coldStartAt = Date.now();
5371
+ const dbTarget = resolveLocalDbTarget(cwd, {
5372
+ ...options.db === void 0 ? {} : { db: options.db },
5373
+ ...options.dbFile === void 0 ? {} : { dbFile: options.dbFile }
5374
+ });
4863
5375
  const bearerUser = bearerUserResolverFromEnv();
4864
5376
  const executor = new WorkerFunctionExecutor({
4865
5377
  deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
4866
5378
  });
4867
- await mkdir7(functionsDir, { recursive: true });
5379
+ await mkdir8(functionsDir, { recursive: true });
5380
+ const db = await openLocalDbDriver(dbTarget, { cwd, tag: "adep", log });
4868
5381
  const runtime = await createSimRuntime({
4869
5382
  cwd,
4870
5383
  projectId: "local",
4871
5384
  baseUrl: `http://127.0.0.1:${options.port ?? 8787}`,
4872
- log
5385
+ log,
5386
+ ...db.driver === null ? {} : { driver: db.driver }
4873
5387
  });
5388
+ if (options.schemaFile !== void 0) {
5389
+ await applyLocalSchema(runtime.db.driver, {
5390
+ cwd,
5391
+ schemaFile: options.schemaFile,
5392
+ mode: db.mode,
5393
+ tag: "adep",
5394
+ log
5395
+ });
5396
+ }
4874
5397
  await ensureGitignore(cwd);
4875
5398
  let files = mergeSharedIntoFunctions(await collectFunctions(functionsDir));
4876
5399
  let env = {
@@ -4951,12 +5474,12 @@ async function startDevServer(options) {
4951
5474
  const reload = async () => {
4952
5475
  const [nextFiles, envText2] = await Promise.all([
4953
5476
  collectFunctions(functionsDir).then(mergeSharedIntoFunctions),
4954
- readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "")
5477
+ readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "")
4955
5478
  ]);
4956
5479
  files = nextFiles;
4957
5480
  env = { ...config.environment, ...parseEnvFile(envText2) };
4958
5481
  };
4959
- const envText = await readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "");
5482
+ const envText = await readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "");
4960
5483
  env = { ...config.environment, ...parseEnvFile(envText) };
4961
5484
  let debounceTimer;
4962
5485
  let watcher;
@@ -5113,13 +5636,17 @@ async function startDevServer(options) {
5113
5636
  const baseUrl = `http://127.0.0.1:${actualPort}`;
5114
5637
  const coldStartMs = Date.now() - coldStartAt;
5115
5638
  const curlPath = config.functionsPrefix.length === 0 ? "/hello" : `/${config.functionsPrefix}/hello`;
5116
- log(`[adep] dev server listening on ${baseUrl}\uFF08\u6A21\u62DF\u8FD0\u884C\u65F6\uFF0C\u51B7\u542F\u52A8 ${coldStartMs}ms\uFF09`);
5639
+ const dbLabel = db.mode === "sqlite" ? `SQLite \u771F\u5B9E\u5E93${db.module === null ? "" : `\uFF08${db.module}\uFF09`}` : "sim \u5F15\u64CE\uFF08\u5185\u7F6E\u6A21\u62DF\uFF09";
5640
+ const dbTargetText = db.file === null ? simDbTarget(cwd) : displayPath(cwd, db.file);
5641
+ log(
5642
+ `[adep] dev server listening on ${baseUrl}\uFF08\u672C\u5730\u8FD0\u884C\u65F6 / ${dbLabel}\uFF0C\u51B7\u542F\u52A8 ${coldStartMs}ms\uFF09`
5643
+ );
5117
5644
  log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
5118
5645
  printBoundaries(log);
5119
5646
  if (bearerUser !== void 0) {
5120
5647
  log(`[adep] \u767B\u5F55\u5373\u670D\u52A1\uFF1AADEP_AUTH_ISSUER \u5DF2\u914D\u7F6E\uFF0CBearer token \u5C06\u89E3\u6790\u4E3A\u7528\u6237\u8EAB\u4EFD\uFF08userinfo \u7AEF\u70B9\uFF09`);
5121
5648
  }
5122
- log(`[adep] \u6A21\u62DF\u6570\u636E\u76EE\u5F55\uFF1A${simDir(cwd)}`);
5649
+ log(`[adep] \u6570\u636E\u5E93\uFF1A${dbLabel} \u2192 ${dbTargetText}`);
5123
5650
  startStateAlarmScheduler();
5124
5651
  return {
5125
5652
  port: actualPort,
@@ -5142,6 +5669,7 @@ var init_dev = __esm({
5142
5669
  init_http_envelope();
5143
5670
  init_worker_executor();
5144
5671
  init_runtime();
5672
+ init_db_mode();
5145
5673
  init_env();
5146
5674
  init_invoke();
5147
5675
  init_builtin_deps2();
@@ -5154,267 +5682,6 @@ var init_dev = __esm({
5154
5682
  }
5155
5683
  });
5156
5684
 
5157
- // packages/cli/src/client.ts
5158
- var client_exports = {};
5159
- __export(client_exports, {
5160
- createClient: () => createClient,
5161
- resolveSlug: () => resolveSlug
5162
- });
5163
- async function envelopeError(response, fallbackCode, parsed) {
5164
- const payload = parsed ?? null;
5165
- return new CliError(
5166
- payload?.error?.code ?? fallbackCode,
5167
- payload?.error?.message ?? `\u5E73\u53F0\u8FD4\u56DE HTTP ${response.status}`
5168
- );
5169
- }
5170
- async function parseBody(response) {
5171
- const text = await response.text();
5172
- if (text.length === 0) return null;
5173
- try {
5174
- return JSON.parse(text);
5175
- } catch {
5176
- return null;
5177
- }
5178
- }
5179
- async function createClient(paths) {
5180
- const credentials = await loadCredentials(paths);
5181
- if (credentials === null) {
5182
- throw new CliError("NOT_LOGGED_IN", "\u672A\u767B\u5F55\uFF1A\u8BF7\u5148\u6267\u884C adep login");
5183
- }
5184
- const server = credentials.server;
5185
- const cookie = sessionCookieHeader(credentials);
5186
- const request = async (path, init = {}, fallbackCode = "API_REQUEST_FAILED") => {
5187
- const method = init.method ?? (init.body === void 0 ? "GET" : "POST");
5188
- let response;
5189
- try {
5190
- response = await fetch(`${server}${path}`, {
5191
- method,
5192
- headers: { "content-type": "application/json", cookie },
5193
- ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) }
5194
- });
5195
- } catch (error) {
5196
- throw new CliError(
5197
- "SERVER_UNREACHABLE",
5198
- `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
5199
- );
5200
- }
5201
- const parsed = await parseBody(response);
5202
- if (response.status < 200 || response.status >= 300) {
5203
- throw await envelopeError(response, fallbackCode, parsed);
5204
- }
5205
- return parsed;
5206
- };
5207
- const upload = async (path, form, fallbackCode = "UPLOAD_FAILED") => {
5208
- let response;
5209
- try {
5210
- response = await fetch(`${server}${path}`, {
5211
- method: "POST",
5212
- headers: { cookie },
5213
- body: form
5214
- });
5215
- } catch (error) {
5216
- throw new CliError(
5217
- "SERVER_UNREACHABLE",
5218
- `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
5219
- );
5220
- }
5221
- if (response.status < 200 || response.status >= 300) {
5222
- throw await envelopeError(response, fallbackCode, await parseBody(response));
5223
- }
5224
- return response;
5225
- };
5226
- const download = async (url, fallbackCode = "DOWNLOAD_FAILED") => {
5227
- const target = url.startsWith("http") ? url : `${server}${url}`;
5228
- let response;
5229
- try {
5230
- response = await fetch(target, { headers: { cookie } });
5231
- } catch (error) {
5232
- throw new CliError(
5233
- "SERVER_UNREACHABLE",
5234
- `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
5235
- );
5236
- }
5237
- if (response.status < 200 || response.status >= 300) {
5238
- throw await envelopeError(response, fallbackCode, await parseBody(response));
5239
- }
5240
- return response;
5241
- };
5242
- return { server, cookie, request, upload, download };
5243
- }
5244
- async function resolveSlug(cwd, slug) {
5245
- if (slug !== void 0 && slug.length > 0) return slug;
5246
- const config = await loadConfig(cwd);
5247
- return config.name;
5248
- }
5249
- var init_client = __esm({
5250
- "packages/cli/src/client.ts"() {
5251
- "use strict";
5252
- init_auth();
5253
- init_credentials();
5254
- init_dev();
5255
- }
5256
- });
5257
-
5258
- // packages/cli/src/db.ts
5259
- var db_exports = {};
5260
- __export(db_exports, {
5261
- dbExec: () => dbExec,
5262
- dbMigrate: () => dbMigrate,
5263
- dbRollback: () => dbRollback,
5264
- dbSnapshotCreate: () => dbSnapshotCreate,
5265
- dbSnapshotList: () => dbSnapshotList,
5266
- dbSnapshotRestore: () => dbSnapshotRestore,
5267
- dbStart: () => dbStart,
5268
- dbStatus: () => dbStatus,
5269
- dbStop: () => dbStop,
5270
- splitSqlStatements: () => splitSqlStatements
5271
- });
5272
- import { readFile as readFile10 } from "node:fs/promises";
5273
- import { resolve as resolve5 } from "node:path";
5274
- async function open2(paths, options) {
5275
- const client = await createClient(paths);
5276
- const project2 = await resolveSlug(resolve5(options.cwd), options.slug);
5277
- return { client, project: project2 };
5278
- }
5279
- async function dbStart(paths, options) {
5280
- const { client, project: project2 } = await open2(paths, options);
5281
- return client.request(`/api/v1/projects/${project2}/database`, { method: "POST" });
5282
- }
5283
- async function dbStatus(paths, options) {
5284
- const { client, project: project2 } = await open2(paths, options);
5285
- return client.request(`/api/v1/projects/${project2}/database`);
5286
- }
5287
- async function dbStop(paths, options) {
5288
- const { client, project: project2 } = await open2(paths, options);
5289
- return client.request(`/api/v1/projects/${project2}/database`, {
5290
- method: "DELETE"
5291
- });
5292
- }
5293
- async function dbExec(paths, options) {
5294
- const { client, project: project2 } = await open2(paths, options);
5295
- return client.request(
5296
- `/api/v1/projects/${project2}/database/console/sql`,
5297
- {
5298
- method: "POST",
5299
- body: {
5300
- sql: options.sql,
5301
- ...options.params === void 0 ? {} : { params: options.params },
5302
- ...options.confirmTable === void 0 ? {} : { confirmTable: options.confirmTable }
5303
- }
5304
- },
5305
- "SQL_EXEC_FAILED"
5306
- );
5307
- }
5308
- async function dbSnapshotList(paths, options) {
5309
- const { client, project: project2 } = await open2(paths, options);
5310
- return client.request(
5311
- `/api/v1/projects/${project2}/database/snapshots`
5312
- );
5313
- }
5314
- async function dbSnapshotCreate(paths, options) {
5315
- const { client, project: project2 } = await open2(paths, options);
5316
- return client.request(`/api/v1/projects/${project2}/database/snapshots`, {
5317
- method: "POST"
5318
- });
5319
- }
5320
- async function dbSnapshotRestore(paths, options) {
5321
- const { client, project: project2 } = await open2(paths, options);
5322
- return client.request(
5323
- `/api/v1/projects/${project2}/database/snapshots/${options.snapshotId}/restore`,
5324
- { method: "POST" }
5325
- );
5326
- }
5327
- async function dbRollback(paths, options) {
5328
- const { client, project: project2 } = await open2(paths, options);
5329
- return client.request(
5330
- `/api/v1/projects/${project2}/database/rollback`,
5331
- { method: "POST", body: { to: options.to } }
5332
- );
5333
- }
5334
- function splitSqlStatements(source) {
5335
- const statements = [];
5336
- let buffer = "";
5337
- let inQuote = false;
5338
- const lines = source.split("\n");
5339
- for (const rawLine of lines) {
5340
- const trimmed = rawLine.trim();
5341
- if (trimmed.length === 0 || trimmed.startsWith("--")) continue;
5342
- for (let i = 0; i < rawLine.length; i++) {
5343
- const ch = rawLine[i];
5344
- if (inQuote) {
5345
- if (ch === "'") {
5346
- if (rawLine[i + 1] === "'") {
5347
- buffer += ch + rawLine[i + 1];
5348
- i++;
5349
- continue;
5350
- }
5351
- inQuote = false;
5352
- }
5353
- buffer += ch;
5354
- continue;
5355
- }
5356
- if (ch === "'") {
5357
- inQuote = true;
5358
- buffer += ch;
5359
- continue;
5360
- }
5361
- if (ch === "-" && rawLine[i + 1] === "-") break;
5362
- if (ch === ";") {
5363
- const statement = buffer.trim();
5364
- if (statement.length > 0) statements.push(statement);
5365
- buffer = "";
5366
- continue;
5367
- }
5368
- buffer += ch;
5369
- }
5370
- buffer += " ";
5371
- }
5372
- if (inQuote) {
5373
- throw new Error(`SQL \u8FC1\u79FB\u6587\u4EF6\u5F15\u53F7\u672A\u95ED\u5408\uFF1A${buffer.trim().slice(0, 80)}\u2026`);
5374
- }
5375
- const tail = buffer.trim();
5376
- if (tail.length > 0) statements.push(tail);
5377
- return statements;
5378
- }
5379
- async function dbMigrate(paths, options) {
5380
- const source = await readFile10(resolve5(options.file), "utf8");
5381
- const statements = splitSqlStatements(source);
5382
- if (statements.length === 0) {
5383
- throw new Error(`\u8FC1\u79FB\u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${options.file}`);
5384
- }
5385
- const { project: project2 } = await open2(paths, options);
5386
- const applied = [];
5387
- const changes = [];
5388
- for (const statement of statements) {
5389
- try {
5390
- const result = await dbExec(paths, {
5391
- cwd: options.cwd,
5392
- ...options.slug === void 0 ? {} : { slug: options.slug },
5393
- sql: statement
5394
- });
5395
- applied.push(statement);
5396
- changes.push(result.changes);
5397
- } catch (error) {
5398
- const code = error instanceof CliError ? error.code : "MIGRATE_FAILED";
5399
- const message = error instanceof Error ? error.message : String(error);
5400
- return {
5401
- projectId: project2,
5402
- applied,
5403
- changes,
5404
- failed: { statement, code, message }
5405
- };
5406
- }
5407
- }
5408
- return { projectId: project2, applied, changes };
5409
- }
5410
- var init_db2 = __esm({
5411
- "packages/cli/src/db.ts"() {
5412
- "use strict";
5413
- init_auth();
5414
- init_client();
5415
- }
5416
- });
5417
-
5418
5685
  // packages/cli/src/serve/banner.ts
5419
5686
  function isLoopback(host) {
5420
5687
  return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "[::1]";
@@ -5483,135 +5750,6 @@ var init_banner = __esm({
5483
5750
  }
5484
5751
  });
5485
5752
 
5486
- // packages/cli/src/serve/db-mode.ts
5487
- import { resolve as resolve6 } from "node:path";
5488
- function isServeDbMode(value) {
5489
- return SERVE_DB_MODES.includes(value.trim().toLowerCase());
5490
- }
5491
- function parseServeDbMode(raw, source) {
5492
- const value = raw.trim().toLowerCase();
5493
- if (!isServeDbMode(value)) {
5494
- throw new Error(
5495
- `${source} \u7684\u6570\u636E\u5E93\u6A21\u5F0F "${raw}" \u65E0\u6548\uFF1A\u53EA\u652F\u6301 ${SERVE_DB_MODES.join(" | ")}\uFF08sim = \u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\u4E0E .adep/sim/db.json\uFF1Bsqlite = \u771F\u5B9E SQLite \u5E93\u6587\u4EF6\uFF09`
5496
- );
5497
- }
5498
- return value;
5499
- }
5500
- function resolveServeDbMode(explicit) {
5501
- if (explicit !== void 0) return parseServeDbMode(explicit, "--db");
5502
- const fromEnv = process.env["ADEP_SERVE_DB"];
5503
- if (fromEnv !== void 0 && fromEnv.trim() !== "") {
5504
- return parseServeDbMode(fromEnv, "ADEP_SERVE_DB");
5505
- }
5506
- return DEFAULT_SERVE_DB_MODE;
5507
- }
5508
- function resolveServeDbFile(cwd, explicit) {
5509
- const raw = explicit ?? envDbFile() ?? DEFAULT_SQLITE_DB_FILE;
5510
- return raw === ":memory:" ? raw : resolve6(cwd, raw);
5511
- }
5512
- function envDbFile() {
5513
- const raw = process.env["ADEP_SERVE_DB_FILE"];
5514
- return raw === void 0 || raw.trim() === "" ? void 0 : raw.trim();
5515
- }
5516
- var SERVE_DB_MODES, DEFAULT_SERVE_DB_MODE, DEFAULT_SQLITE_DB_FILE;
5517
- var init_db_mode = __esm({
5518
- "packages/cli/src/serve/db-mode.ts"() {
5519
- "use strict";
5520
- SERVE_DB_MODES = ["sim", "sqlite"];
5521
- DEFAULT_SERVE_DB_MODE = "sqlite";
5522
- DEFAULT_SQLITE_DB_FILE = ".adep/data/project.sqlite";
5523
- }
5524
- });
5525
-
5526
- // packages/cli/src/serve/sqlite-driver.ts
5527
- import { mkdir as mkdir8 } from "node:fs/promises";
5528
- import { dirname as dirname8, resolve as resolve7 } from "node:path";
5529
- function isBun(versions) {
5530
- return versions["bun"] !== void 0 && versions["bun"] !== "";
5531
- }
5532
- function detectSqliteRuntime(versions = process.versions) {
5533
- if (isBun(versions)) return "bun";
5534
- const raw = versions["node"];
5535
- if (raw === void 0) return null;
5536
- const [majorText, minorText] = raw.split(".");
5537
- const major = Number(majorText);
5538
- const minor = Number(minorText ?? "0");
5539
- if (!Number.isInteger(major) || !Number.isInteger(minor)) return null;
5540
- if (major > NODE_SQLITE_MIN.major) return "node";
5541
- if (major === NODE_SQLITE_MIN.major && minor >= NODE_SQLITE_MIN.minor) return "node";
5542
- return null;
5543
- }
5544
- function sqliteModuleName(runtime) {
5545
- return runtime === "bun" ? "bun:sqlite" : "node:sqlite";
5546
- }
5547
- function sqliteUnavailableReason(versions = process.versions) {
5548
- const current = isBun(versions) ? `Bun ${versions["bun"] ?? ""}`.trim() : `Node ${versions["node"] ?? "\u672A\u77E5"}`;
5549
- return `\u5F53\u524D\u8FD0\u884C\u65F6 ${current} \u4E0D\u63D0\u4F9B SQLite \u5185\u5EFA\u6A21\u5757\uFF08\u9700\u8981 Bun \u6216 Node \u2265 ${NODE_SQLITE_MIN.major}.${NODE_SQLITE_MIN.minor}\uFF09`;
5550
- }
5551
- function sqliteRuntimeRequirementMessage(versions = process.versions) {
5552
- return `--db sqlite \u9700\u8981 Bun\uFF08\u5185\u7F6E bun:sqlite\uFF09\u6216 Node \u2265 ${NODE_SQLITE_MIN.major}.${NODE_SQLITE_MIN.minor}\uFF08\u5185\u7F6E node:sqlite\uFF09\uFF1B${sqliteUnavailableReason(versions)}\u3002\u8BF7\u6539\u7528 \`--db sim\`\uFF08\u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\uFF0C\u65E0\u9700\u989D\u5916\u8FD0\u884C\u65F6\uFF09\uFF0C\u6216\u5347\u7EA7 Node / \u7528 Bun \u8FD0\u884C\u3002`;
5553
- }
5554
- async function openSqliteProjectDriver(file, options = {}) {
5555
- const runtime = options.runtime ?? detectSqliteRuntime();
5556
- if (runtime === null) throw new Error(sqliteRuntimeRequirementMessage());
5557
- const moduleName = sqliteModuleName(runtime);
5558
- const ctorName = runtime === "bun" ? "Database" : "DatabaseSync";
5559
- let mod;
5560
- try {
5561
- const specifier = moduleName;
5562
- mod = await import(
5563
- /* @vite-ignore */
5564
- specifier
5565
- );
5566
- } catch (error) {
5567
- throw new Error(
5568
- `${sqliteRuntimeRequirementMessage()}
5569
- \uFF08\u8F7D\u5165 ${moduleName} \u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}\uFF09`,
5570
- { cause: error }
5571
- );
5572
- }
5573
- const Ctor = mod[ctorName];
5574
- if (Ctor === void 0) {
5575
- throw new Error(`${moduleName} \u672A\u5BFC\u51FA ${ctorName}\uFF1A\u5F53\u524D\u8FD0\u884C\u65F6\u7684 SQLite \u5185\u5EFA\u6A21\u5757\u4E0D\u53EF\u7528`);
5576
- }
5577
- const target = file === ":memory:" ? file : resolve7(file);
5578
- if (target !== ":memory:") await mkdir8(dirname8(target), { recursive: true });
5579
- const database = new Ctor(target);
5580
- database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
5581
- return {
5582
- engine: "sqlite",
5583
- async run(sql, params = []) {
5584
- if (params.length === 0) {
5585
- database.exec(sql);
5586
- return { changes: 0 };
5587
- }
5588
- const result = database.prepare(sql).run(...params);
5589
- return { changes: Number(result.changes) };
5590
- },
5591
- async all(sql, params = []) {
5592
- const statement = database.prepare(sql);
5593
- statement.setReturnArrays?.(false);
5594
- return statement.all(...params);
5595
- },
5596
- async get(sql, params = []) {
5597
- const statement = database.prepare(sql);
5598
- statement.setReturnArrays?.(false);
5599
- const row = statement.get(...params);
5600
- return row ?? null;
5601
- },
5602
- async close() {
5603
- database.close();
5604
- }
5605
- };
5606
- }
5607
- var NODE_SQLITE_MIN;
5608
- var init_sqlite_driver = __esm({
5609
- "packages/cli/src/serve/sqlite-driver.ts"() {
5610
- "use strict";
5611
- NODE_SQLITE_MIN = { major: 22, minor: 5 };
5612
- }
5613
- });
5614
-
5615
5753
  // packages/cli/src/serve/server.ts
5616
5754
  var server_exports = {};
5617
5755
  __export(server_exports, {
@@ -5621,8 +5759,8 @@ __export(server_exports, {
5621
5759
  });
5622
5760
  import { createServer as createServer2 } from "node:http";
5623
5761
  import { watch as watch2 } from "node:fs";
5624
- import { mkdir as mkdir9, readFile as readFile11, stat as stat7 } from "node:fs/promises";
5625
- import { extname, join as join14, relative as relative2, resolve as resolve8 } from "node:path";
5762
+ import { mkdir as mkdir9, readFile as readFile12, stat as stat7 } from "node:fs/promises";
5763
+ import { extname, join as join15, relative as relative3, resolve as resolve8 } from "node:path";
5626
5764
  function envNumber(name) {
5627
5765
  const raw = process.env[name];
5628
5766
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -5640,11 +5778,6 @@ function contentTypeFor(path) {
5640
5778
  const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
5641
5779
  return MIME_TYPES[ext] ?? "application/octet-stream";
5642
5780
  }
5643
- function displayPath(cwd, target) {
5644
- if (target === ":memory:") return target;
5645
- const rel = relative2(cwd, target);
5646
- return rel.startsWith("..") ? target : rel;
5647
- }
5648
5781
  async function startServeServer(options) {
5649
5782
  const cwd = resolve8(options.cwd);
5650
5783
  const log = options.log ?? ((line) => process.stdout.write(`${line}
@@ -5655,10 +5788,12 @@ async function startServeServer(options) {
5655
5788
  cwd,
5656
5789
  options.staticDir ?? envString("ADEP_SERVE_STATIC_DIR") ?? "public"
5657
5790
  );
5658
- let dbMode = resolveServeDbMode(options.db);
5659
- let sqliteFile = dbMode === "sqlite" ? resolveServeDbFile(cwd, options.dbFile) : null;
5791
+ const dbTarget = resolveLocalDbTarget(cwd, {
5792
+ ...options.db === void 0 ? {} : { db: options.db },
5793
+ ...options.dbFile === void 0 ? {} : { dbFile: options.dbFile }
5794
+ });
5660
5795
  const config = await loadConfig(cwd);
5661
- const functionsDir = join14(cwd, config.functionsDir);
5796
+ const functionsDir = join15(cwd, config.functionsDir);
5662
5797
  const bearerUser = bearerUserResolverFromEnv();
5663
5798
  let hasStatic = false;
5664
5799
  try {
@@ -5670,76 +5805,28 @@ async function startServeServer(options) {
5670
5805
  const loadFunctionFiles = async () => mergeSharedIntoFunctions(await collectFunctions(functionsDir));
5671
5806
  let files = await loadFunctionFiles();
5672
5807
  let functionNames = listFunctionNames(files);
5673
- const envText = await readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "");
5808
+ const envText = await readFile12(join15(cwd, ".env.local"), "utf8").catch(() => "");
5674
5809
  let env = parseEnvFile(envText);
5675
5810
  let simEnv = await loadSimEnv(cwd).catch(() => ({}));
5676
- let sqliteModule = null;
5677
- let sqliteDriver = null;
5678
- if (sqliteFile !== null) {
5679
- const runtimeName = detectSqliteRuntime();
5680
- if (runtimeName === null) {
5681
- log(
5682
- `[serve] \u8B66\u544A\uFF1A${sqliteUnavailableReason()}\uFF0C\u5DF2\u81EA\u52A8\u964D\u7EA7\u4E3A sim \u6A21\u5F0F\uFF08\u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\uFF0C\u5E93 ${displayPath(cwd, join14(simDir(cwd), "db.json"))}\uFF09\u3002\u5982\u9700\u771F\u5B9E SQLite\uFF0C\u8BF7\u7528 Bun \u6216\u5347\u7EA7 Node \u540E\u91CD\u8BD5\u3002`
5683
- );
5684
- dbMode = "sim";
5685
- sqliteFile = null;
5686
- } else {
5687
- sqliteModule = sqliteModuleName(runtimeName);
5688
- try {
5689
- sqliteDriver = await openSqliteProjectDriver(sqliteFile, { runtime: runtimeName });
5690
- } catch (error) {
5691
- const detail = error instanceof Error ? error.message : String(error);
5692
- log(
5693
- `[serve] \u8B66\u544A\uFF1A\u6253\u5F00 SQLite \u5E93\u5931\u8D25\uFF08${detail}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u964D\u7EA7\u4E3A sim \u6A21\u5F0F\uFF08\u5185\u7F6E\u6A21\u62DF\u5F15\u64CE\uFF0C\u5E93 ${displayPath(cwd, join14(simDir(cwd), "db.json"))}\uFF09\u3002`
5694
- );
5695
- sqliteModule = null;
5696
- sqliteDriver = null;
5697
- sqliteFile = null;
5698
- dbMode = "sim";
5699
- }
5700
- }
5701
- }
5811
+ const db = await openLocalDbDriver(dbTarget, { cwd, tag: "serve", log });
5812
+ const dbMode = db.mode;
5813
+ const sqliteFile = db.file;
5814
+ const sqliteModule = db.module;
5702
5815
  const runtime = await createSimRuntime({
5703
5816
  cwd,
5704
5817
  projectId: "local",
5705
5818
  baseUrl: `http://${host}:${port}`,
5706
5819
  log,
5707
- ...sqliteDriver === null ? {} : { driver: sqliteDriver }
5820
+ ...db.driver === null ? {} : { driver: db.driver }
5708
5821
  });
5709
5822
  if (options.schemaFile !== void 0) {
5710
- const schemaPath = resolve8(cwd, options.schemaFile);
5711
- const schemaSource = await readFile11(schemaPath, "utf8").catch(
5712
- (error) => {
5713
- if (error.code === "ENOENT") {
5714
- throw new Error(`schema \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${schemaPath}`);
5715
- }
5716
- throw error;
5717
- }
5718
- );
5719
- const statements = splitSqlStatements(schemaSource);
5720
- let applied = 0;
5721
- let skipped = 0;
5722
- for (const [index, statement] of statements.entries()) {
5723
- try {
5724
- await runtime.db.driver.run(statement);
5725
- applied += 1;
5726
- } catch (error) {
5727
- const isUnsupported = error instanceof Error && "code" in error && error.code === "DB_UNSAFE_OP";
5728
- if (dbMode === "sim" && isUnsupported) {
5729
- skipped += 1;
5730
- log(`[serve] \u8DF3\u8FC7 schema \u8BED\u53E5\uFF08sim \u5F15\u64CE\u4E0D\u652F\u6301\uFF09\uFF1A${statement.slice(0, 60)}\u2026`);
5731
- continue;
5732
- }
5733
- const detail = error instanceof Error ? error.message : String(error);
5734
- throw new Error(
5735
- `schema \u8BED\u53E5\u6267\u884C\u5931\u8D25\uFF08--schema ${options.schemaFile}\uFF0C\u7B2C ${index + 1} \u6761\uFF0Cdb \u6A21\u5F0F ${dbMode}\uFF09\uFF1A${detail}
5736
- \u8BED\u53E5\uFF1A${statement.slice(0, 200)}` + (dbMode === "sqlite" ? "\n\uFF08sqlite \u6A21\u5F0F\u4E0D\u505A\u8BED\u53E5\u8DF3\u8FC7\uFF1B\u5982\u9700\u8DF3\u8FC7\u8BED\u4E49\u8BF7\u6539\u7528 --db sim\uFF09" : ""),
5737
- { cause: error }
5738
- );
5739
- }
5740
- }
5741
- const skipNote = skipped > 0 ? `\uFF0C\u8DF3\u8FC7 ${skipped} \u6761` : "";
5742
- log(`[serve] \u5DF2\u5E94\u7528\u6570\u636E\u5E93\u7ED3\u6784\uFF08--schema ${options.schemaFile}\uFF09\uFF1A${applied} \u6761\u8BED\u53E5${skipNote}`);
5823
+ await applyLocalSchema(runtime.db.driver, {
5824
+ cwd,
5825
+ schemaFile: options.schemaFile,
5826
+ mode: dbMode,
5827
+ tag: "serve",
5828
+ log
5829
+ });
5743
5830
  }
5744
5831
  const executor = new WorkerFunctionExecutor({
5745
5832
  deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
@@ -5751,7 +5838,7 @@ async function startServeServer(options) {
5751
5838
  const reload = async () => {
5752
5839
  const [nextFiles, envLocalText] = await Promise.all([
5753
5840
  loadFunctionFiles(),
5754
- readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "")
5841
+ readFile12(join15(cwd, ".env.local"), "utf8").catch(() => "")
5755
5842
  ]);
5756
5843
  files = nextFiles;
5757
5844
  env = parseEnvFile(envLocalText);
@@ -5806,16 +5893,16 @@ async function startServeServer(options) {
5806
5893
  const serveStatic = async (pathname, res) => {
5807
5894
  if (!hasStatic) return false;
5808
5895
  const safePath = pathname.replace(/\.\.\//g, "").replace(/^\//, "");
5809
- const filePath = join14(staticDir, safePath);
5810
- const resolvedPath = safePath === "" || safePath === "/" ? join14(filePath, "index.html") : filePath;
5896
+ const filePath = join15(staticDir, safePath);
5897
+ const resolvedPath = safePath === "" || safePath === "/" ? join15(filePath, "index.html") : filePath;
5811
5898
  try {
5812
5899
  const fileStat = await stat7(resolvedPath);
5813
5900
  if (fileStat.isDirectory()) {
5814
- const indexPath = join14(resolvedPath, "index.html");
5901
+ const indexPath = join15(resolvedPath, "index.html");
5815
5902
  try {
5816
5903
  const indexStat = await stat7(indexPath);
5817
5904
  if (indexStat.isFile()) {
5818
- const content2 = await readFile11(indexPath);
5905
+ const content2 = await readFile12(indexPath);
5819
5906
  res.writeHead(200, { "content-type": contentTypeFor(indexPath) });
5820
5907
  res.end(content2);
5821
5908
  return true;
@@ -5824,7 +5911,7 @@ async function startServeServer(options) {
5824
5911
  }
5825
5912
  return false;
5826
5913
  }
5827
- const content = await readFile11(resolvedPath);
5914
+ const content = await readFile12(resolvedPath);
5828
5915
  res.writeHead(200, { "content-type": contentTypeFor(resolvedPath) });
5829
5916
  res.end(content);
5830
5917
  return true;
@@ -5833,7 +5920,7 @@ async function startServeServer(options) {
5833
5920
  const ext = extname(pathname);
5834
5921
  if (ext === "" || ext === ".html") {
5835
5922
  try {
5836
- const indexContent = await readFile11(join14(staticDir, "index.html"));
5923
+ const indexContent = await readFile12(join15(staticDir, "index.html"));
5837
5924
  res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
5838
5925
  res.end(indexContent);
5839
5926
  return true;
@@ -5844,9 +5931,66 @@ async function startServeServer(options) {
5844
5931
  return false;
5845
5932
  }
5846
5933
  };
5934
+ const serveSignedFile = async (req, res, url, projectId, path) => {
5935
+ const driver = runtime.storage.driver;
5936
+ try {
5937
+ const meta = await driver.getMeta(projectId, path);
5938
+ if (meta.visibility === "private") {
5939
+ const verification = verifyDownloadSignature(
5940
+ { secret: SIM_SIGN_SECRET, baseUrl: "" },
5941
+ projectId,
5942
+ path,
5943
+ {
5944
+ expires: url.searchParams.get(SIGN_EXPIRES_KEY) ?? void 0,
5945
+ signature: url.searchParams.get(SIGN_SIGNATURE_KEY) ?? void 0
5946
+ }
5947
+ );
5948
+ if (!verification.ok) {
5949
+ const message = verification.reason === "expired" ? "\u7B7E\u540D URL \u5DF2\u8FC7\u671F\uFF1A\u8BF7\u91CD\u65B0\u751F\u6210\uFF0815 \u5206\u949F\u6709\u6548\uFF09" : verification.reason === "missing" ? "\u79C1\u6709\u6587\u4EF6\u9700\u8981\u7B7E\u540D URL \u624D\u80FD\u8BBF\u95EE" : "\u7B7E\u540D\u65E0\u6548\uFF1AURL \u53EF\u80FD\u88AB\u7BE1\u6539";
5950
+ writeJson(res, 403, { error: { code: "STORAGE_SIGNATURE_INVALID", message } });
5951
+ log(`[serve] ${req.method ?? "GET"} ${url.pathname} -> 403 (${verification.reason})`);
5952
+ return true;
5953
+ }
5954
+ }
5955
+ const { data } = await driver.get(projectId, path);
5956
+ res.writeHead(200, {
5957
+ "content-type": meta.contentType ?? "application/octet-stream",
5958
+ "content-length": String(meta.size),
5959
+ "cache-control": meta.visibility === "public" ? "public, max-age=3600" : "private, no-store"
5960
+ });
5961
+ res.end(data);
5962
+ log(`[serve] ${req.method ?? "GET"} ${url.pathname} -> 200\uFF08\u6587\u4EF6\u4E0B\u8F7D ${meta.size}B\uFF09`);
5963
+ } catch (error) {
5964
+ if (error instanceof StorageError) {
5965
+ writeJson(res, error.status, { error: { code: error.code, message: error.message } });
5966
+ log(`[serve] ${req.method ?? "GET"} ${url.pathname} -> ${error.status} (${error.code})`);
5967
+ return true;
5968
+ }
5969
+ writeJson(res, 500, {
5970
+ error: {
5971
+ code: "FILE_DOWNLOAD_ERROR",
5972
+ message: error instanceof Error ? error.message : "\u6587\u4EF6\u4E0B\u8F7D\u5931\u8D25"
5973
+ }
5974
+ });
5975
+ log(`[serve] ${req.method ?? "GET"} ${url.pathname} -> 500\uFF08\u6587\u4EF6\u4E0B\u8F7D\u5F02\u5E38\uFF09`);
5976
+ }
5977
+ return true;
5978
+ };
5979
+ const SIGNED_FILES_ROUTE = /^\/api\/v1\/projects\/([^/]+)\/files\/([^/]+)$/;
5847
5980
  const handle = async (req, res) => {
5848
5981
  const url = new URL(req.url ?? "/", `http://${host}:${port}`);
5849
5982
  const pathname = url.pathname;
5983
+ const filesMatch = SIGNED_FILES_ROUTE.exec(pathname);
5984
+ if (filesMatch !== null && (req.method === "GET" || req.method === "HEAD")) {
5985
+ await serveSignedFile(
5986
+ req,
5987
+ res,
5988
+ url,
5989
+ decodeURIComponent(filesMatch[1]),
5990
+ decodeURIComponent(filesMatch[2])
5991
+ );
5992
+ return;
5993
+ }
5850
5994
  const normalizedPrefix = config.functionsPrefix.replace(/^\/+|\/+$/g, "");
5851
5995
  const fnRest = normalizedPrefix.length > 0 ? pathname === `/${normalizedPrefix}` || pathname.startsWith(`/${normalizedPrefix}/`) ? pathname.slice(normalizedPrefix.length + 1) : null : pathname === "/api" ? "" : pathname.startsWith("/api/") ? pathname.slice("/api/".length) : null;
5852
5996
  if (fnRest !== null) {
@@ -5921,7 +6065,7 @@ async function startServeServer(options) {
5921
6065
  functions: functionNames,
5922
6066
  static: hasStatic,
5923
6067
  // CLI-020:当前数据面(换模式即换库,这里让脚本/e2e 有可断言的读数)。
5924
- db: sqliteFile === null ? { mode: "sim", file: displayPath(cwd, join14(simDir(cwd), "db.json")) } : { mode: "sqlite", file: displayPath(cwd, sqliteFile), driver: sqliteModule },
6068
+ db: sqliteFile === null ? { mode: "sim", file: simDbTarget(cwd) } : { mode: "sqlite", file: displayPath(cwd, sqliteFile), driver: sqliteModule },
5925
6069
  endpoints: {
5926
6070
  functions: "/api/{fn}",
5927
6071
  static: `/ \u2192 ${staticDir}`,
@@ -5960,9 +6104,9 @@ async function startServeServer(options) {
5960
6104
  functions: functionNames,
5961
6105
  functionsPrefix: config.functionsPrefix,
5962
6106
  hasStatic,
5963
- staticDir: relative2(cwd, staticDir).length > 0 ? relative2(cwd, staticDir) : staticDir,
6107
+ staticDir: relative3(cwd, staticDir).length > 0 ? relative3(cwd, staticDir) : staticDir,
5964
6108
  dbMode,
5965
- dbTarget: sqliteFile === null ? displayPath(cwd, join14(simDir(cwd), "db.json")) : displayPath(cwd, sqliteFile),
6109
+ dbTarget: sqliteFile === null ? simDbTarget(cwd) : displayPath(cwd, sqliteFile),
5966
6110
  ...sqliteModule === null ? {} : { dbDriver: sqliteModule }
5967
6111
  });
5968
6112
  log(banner);
@@ -5994,15 +6138,16 @@ var init_server = __esm({
5994
6138
  init_executor();
5995
6139
  init_http_envelope();
5996
6140
  init_worker_executor();
6141
+ init_signature();
6142
+ init_driver();
5997
6143
  init_builtin_deps2();
5998
- init_db2();
5999
6144
  init_runtime();
6145
+ init_storage();
6000
6146
  init_env();
6001
6147
  init_invoke();
6002
6148
  init_dev();
6003
6149
  init_banner();
6004
6150
  init_db_mode();
6005
- init_sqlite_driver();
6006
6151
  init_dev_shared();
6007
6152
  MIME_TYPES = {
6008
6153
  ".html": "text/html; charset=utf-8",
@@ -6037,8 +6182,8 @@ __export(deploy_exports, {
6037
6182
  deploy: () => deploy
6038
6183
  });
6039
6184
  import { createHash as createHash2 } from "node:crypto";
6040
- import { readdir as readdir5, readFile as readFile12 } from "node:fs/promises";
6041
- import { join as join15, resolve as resolve9, basename as basename3, relative as relative3, sep } from "node:path";
6185
+ import { readdir as readdir5, readFile as readFile13 } from "node:fs/promises";
6186
+ import { join as join16, resolve as resolve9, basename as basename3, relative as relative4, sep } from "node:path";
6042
6187
  function functionUrlBase(prefix) {
6043
6188
  const raw = (prefix ?? "/api").trim();
6044
6189
  const normalized = raw === "/" ? "/" : raw.replace(/\/+$/, "");
@@ -6064,10 +6209,10 @@ async function collectFunctionFiles(functionsDir) {
6064
6209
  if (conflicting.length > 0) throw new AmbiguousFunctionError(functionsDir, conflicting);
6065
6210
  const out = {};
6066
6211
  for (const name of flatNames) {
6067
- out[name] = { [`${name}.ts`]: await readFile12(join15(functionsDir, `${name}.ts`), "utf8") };
6212
+ out[name] = { [`${name}.ts`]: await readFile13(join16(functionsDir, `${name}.ts`), "utf8") };
6068
6213
  }
6069
6214
  for (const name of dirNames) {
6070
- const files = await collectFunctionDir(join15(functionsDir, name));
6215
+ const files = await collectFunctionDir(join16(functionsDir, name));
6071
6216
  if (files["index.ts"] === void 0) continue;
6072
6217
  out[name] = files;
6073
6218
  }
@@ -6086,11 +6231,11 @@ async function collectFunctionDir(absDir) {
6086
6231
  const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
6087
6232
  if (entry.isDirectory()) {
6088
6233
  if (entry.name === "__tests__" || IGNORED_DIRS.has(entry.name)) continue;
6089
- await walk(join15(dir, entry.name), rel);
6234
+ await walk(join16(dir, entry.name), rel);
6090
6235
  continue;
6091
6236
  }
6092
6237
  if (!isRuntimeSource2(entry.name)) continue;
6093
- files[rel] = await readFile12(join15(dir, entry.name), "utf8");
6238
+ files[rel] = await readFile13(join16(dir, entry.name), "utf8");
6094
6239
  }
6095
6240
  };
6096
6241
  await walk(absDir, "");
@@ -6100,7 +6245,7 @@ function sha256Hex(content) {
6100
6245
  return createHash2("sha256").update(content).digest("hex");
6101
6246
  }
6102
6247
  async function collectShared(functionsDir) {
6103
- const sharedDir = join15(functionsDir, "_shared");
6248
+ const sharedDir = join16(functionsDir, "_shared");
6104
6249
  const files = {};
6105
6250
  const walk = async (dir) => {
6106
6251
  let entries;
@@ -6112,13 +6257,13 @@ async function collectShared(functionsDir) {
6112
6257
  for (const entry of entries) {
6113
6258
  if (entry.isDirectory()) {
6114
6259
  if (entry.name === "__tests__" || entry.name === "node_modules") continue;
6115
- await walk(join15(dir, entry.name));
6260
+ await walk(join16(dir, entry.name));
6116
6261
  continue;
6117
6262
  }
6118
6263
  if (!isRuntimeSource2(entry.name)) continue;
6119
- const full = join15(dir, entry.name);
6120
- const rel = relative3(sharedDir, full).split(sep).join("/");
6121
- files[`${SHARED_SOURCE_ROOT3}${rel}`] = await readFile12(full, "utf8");
6264
+ const full = join16(dir, entry.name);
6265
+ const rel = relative4(sharedDir, full).split(sep).join("/");
6266
+ files[`${SHARED_SOURCE_ROOT3}${rel}`] = await readFile13(full, "utf8");
6122
6267
  }
6123
6268
  };
6124
6269
  await walk(sharedDir);
@@ -6132,7 +6277,7 @@ async function deploy(paths, options) {
6132
6277
  const cwd = resolve9(options.cwd);
6133
6278
  const config = await loadConfig(cwd);
6134
6279
  const slug = options.slug ?? config.name;
6135
- const functionsDir = options.functionsDir === void 0 ? join15(cwd, config.functionsDir) : resolve9(cwd, options.functionsDir);
6280
+ const functionsDir = options.functionsDir === void 0 ? join16(cwd, config.functionsDir) : resolve9(cwd, options.functionsDir);
6136
6281
  const local = await collectFunctionFiles(functionsDir);
6137
6282
  if (Object.keys(local).length === 0) {
6138
6283
  throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
@@ -6204,7 +6349,12 @@ async function deploy(paths, options) {
6204
6349
  }
6205
6350
  const published = await client.request(
6206
6351
  `/api/v1/functions/${functionId}/publish`,
6207
- { method: "POST" }
6352
+ {
6353
+ method: "POST",
6354
+ // FN-013:显式 body 而非省略——`force: false` 与 `undefined` 在服务端语义相同,
6355
+ // 但显式传值让「这次发布是否放行过警告」在请求层面可审计。
6356
+ body: { force: options.force === true }
6357
+ }
6208
6358
  );
6209
6359
  deployed.push({
6210
6360
  name: item.name,
@@ -6263,8 +6413,8 @@ var frontend_exports = {};
6263
6413
  __export(frontend_exports, {
6264
6414
  frontendSync: () => frontendSync
6265
6415
  });
6266
- import { readdir as readdir6, readFile as readFile13, stat as stat8 } from "node:fs/promises";
6267
- import { join as join16, relative as relative4, sep as sep2 } from "node:path";
6416
+ import { readdir as readdir6, readFile as readFile14, stat as stat8 } from "node:fs/promises";
6417
+ import { join as join17, relative as relative5, sep as sep2 } from "node:path";
6268
6418
  async function resolveProjectId(client, cwd, slug) {
6269
6419
  const resolvedSlug = await resolveSlug(cwd, slug);
6270
6420
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -6284,20 +6434,21 @@ async function collectFiles(root, dir) {
6284
6434
  for (const entry of entries) {
6285
6435
  if (entry.isDirectory()) {
6286
6436
  if (IGNORED_DIRS2.has(entry.name)) continue;
6287
- const nested = await collectFiles(root, join16(dir, entry.name));
6437
+ const nested = await collectFiles(root, join17(dir, entry.name));
6288
6438
  for (const [path, content] of nested.files) files.set(path, content);
6289
6439
  skipped.push(...nested.skipped);
6290
6440
  continue;
6291
6441
  }
6292
- const full = join16(dir, entry.name);
6293
- const rel = relative4(root, full).split(sep2).join("/");
6442
+ if (IGNORED_FILES.has(entry.name)) continue;
6443
+ const full = join17(dir, entry.name);
6444
+ const rel = relative5(root, full).split(sep2).join("/");
6294
6445
  const info = await stat8(full);
6295
6446
  if (info.size > 1024 * 1024) {
6296
6447
  skipped.push(rel);
6297
6448
  continue;
6298
6449
  }
6299
6450
  try {
6300
- const content = await readFile13(full, "utf8");
6451
+ const content = await readFile14(full, "utf8");
6301
6452
  if (content.includes("\0")) {
6302
6453
  skipped.push(rel);
6303
6454
  continue;
@@ -6312,7 +6463,7 @@ async function collectFiles(root, dir) {
6312
6463
  async function frontendSync(paths, options) {
6313
6464
  const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
6314
6465
  `));
6315
- const webDir = options.dir ?? join16(options.cwd, "web");
6466
+ const webDir = options.dir ?? join17(options.cwd, "web");
6316
6467
  const rootStat = await stat8(webDir).catch(() => null);
6317
6468
  if (rootStat === null || !rootStat.isDirectory()) {
6318
6469
  throw new CliError(
@@ -6359,7 +6510,7 @@ async function frontendSync(paths, options) {
6359
6510
  }
6360
6511
  return { projectId: project2.id, uploaded: files.size, skipped, totalBytes };
6361
6512
  }
6362
- var MAX_FILES, MAX_TOTAL_SOURCE_BYTES2, FILE_PATH_PATTERN, IGNORED_DIRS2;
6513
+ var MAX_FILES, MAX_TOTAL_SOURCE_BYTES2, FILE_PATH_PATTERN, IGNORED_DIRS2, IGNORED_FILES;
6363
6514
  var init_frontend = __esm({
6364
6515
  "packages/cli/src/frontend.ts"() {
6365
6516
  "use strict";
@@ -6370,6 +6521,14 @@ var init_frontend = __esm({
6370
6521
  MAX_TOTAL_SOURCE_BYTES2 = FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES;
6371
6522
  FILE_PATH_PATTERN = FRONTEND_DRAFT_FILE_PATH_PATTERN;
6372
6523
  IGNORED_DIRS2 = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", ".adep", ".vite", "coverage"]);
6524
+ IGNORED_FILES = /* @__PURE__ */ new Set([
6525
+ "package-lock.json",
6526
+ "npm-shrinkwrap.json",
6527
+ "yarn.lock",
6528
+ "pnpm-lock.yaml",
6529
+ "bun.lockb",
6530
+ "bun.lock"
6531
+ ]);
6373
6532
  }
6374
6533
  });
6375
6534
 
@@ -6526,11 +6685,11 @@ var fs_exports = {};
6526
6685
  __export(fs_exports, {
6527
6686
  createExportFileSystem: () => createExportFileSystem
6528
6687
  });
6529
- import { mkdir as mkdir10, readFile as readFile14, rm as rm3, stat as stat10, writeFile as writeFile8 } from "node:fs/promises";
6530
- import { dirname as dirname9, join as join18 } from "node:path";
6688
+ import { mkdir as mkdir10, readFile as readFile15, rm as rm3, stat as stat10, writeFile as writeFile8 } from "node:fs/promises";
6689
+ import { dirname as dirname9, join as join19 } from "node:path";
6531
6690
  function createExportFileSystem() {
6532
6691
  return {
6533
- readFile: (path) => readFile14(path),
6692
+ readFile: (path) => readFile15(path),
6534
6693
  writeFile: (path, content) => writeFile8(path, content),
6535
6694
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
6536
6695
  deleteFile: async (path) => {
@@ -6548,9 +6707,9 @@ function createExportFileSystem() {
6548
6707
  await mkdir10(path, { recursive: true });
6549
6708
  },
6550
6709
  unzip: async (zipPath, targetDir) => {
6551
- const entries = zipRead(await readFile14(zipPath));
6710
+ const entries = zipRead(await readFile15(zipPath));
6552
6711
  for (const [name, data] of entries) {
6553
- const dest = join18(targetDir, name);
6712
+ const dest = join19(targetDir, name);
6554
6713
  await mkdir10(dirname9(dest), { recursive: true });
6555
6714
  await writeFile8(dest, data);
6556
6715
  }
@@ -7068,8 +7227,8 @@ __export(storage_exports, {
7068
7227
  storageRemove: () => storageRemove,
7069
7228
  storageUpload: () => storageUpload
7070
7229
  });
7071
- import { mkdir as mkdir11, readFile as readFile15, stat as stat11, writeFile as writeFile9 } from "node:fs/promises";
7072
- import { basename as basename4, dirname as dirname10, extname as extname2, join as join19, resolve as resolve11 } from "node:path";
7230
+ import { mkdir as mkdir11, readFile as readFile16, stat as stat11, writeFile as writeFile9 } from "node:fs/promises";
7231
+ import { basename as basename4, dirname as dirname10, extname as extname2, join as join20, resolve as resolve11 } from "node:path";
7073
7232
  async function open3(paths, options) {
7074
7233
  const client = await createClient(paths);
7075
7234
  const project2 = await resolveSlug(resolve11(options.cwd), options.slug);
@@ -7111,7 +7270,7 @@ async function storageUpload(paths, options) {
7111
7270
  throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
7112
7271
  }
7113
7272
  const visibility = options.visibility ?? "private";
7114
- const bytes = await readFile15(local);
7273
+ const bytes = await readFile16(local);
7115
7274
  const form = new FormData();
7116
7275
  form.set("path", options.path);
7117
7276
  form.set("visibility", visibility);
@@ -7152,7 +7311,7 @@ async function storageDownload(paths, options) {
7152
7311
  const url = await resolveDownloadUrl(client, project2, options.path);
7153
7312
  const response = await client.download(url, "STORAGE_DOWNLOAD_FAILED");
7154
7313
  const bytes = Buffer.from(await response.arrayBuffer());
7155
- const output = resolve11(options.output ?? join19(resolve11(options.cwd), basename4(options.path)));
7314
+ const output = resolve11(options.output ?? join20(resolve11(options.cwd), basename4(options.path)));
7156
7315
  await mkdir11(dirname10(output), { recursive: true });
7157
7316
  await writeFile9(output, bytes);
7158
7317
  return { path: options.path, output, size: bytes.length };
@@ -7172,6 +7331,189 @@ var init_storage2 = __esm({
7172
7331
  }
7173
7332
  });
7174
7333
 
7334
+ // packages/cli/src/sandbox-scan.ts
7335
+ import { readdir as readdir7, readFile as readFile17 } from "node:fs/promises";
7336
+ import { join as join21, relative as relative6, sep as sep3 } from "node:path";
7337
+ function extractSpecifiers(line) {
7338
+ const out = [];
7339
+ const patterns = [
7340
+ /\bfrom\s+['"]([^'"]+)['"]/g,
7341
+ // import x from '<spec>' / export … from '<spec>'
7342
+ /\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
7343
+ /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
7344
+ /^\s*import\s+['"]([^'"]+)['"]/g
7345
+ // 副作用导入 import '<spec>'
7346
+ ];
7347
+ for (const pattern of patterns) {
7348
+ for (const match of line.matchAll(pattern)) {
7349
+ const spec = match[1];
7350
+ if (spec !== void 0) out.push(spec);
7351
+ }
7352
+ }
7353
+ return out;
7354
+ }
7355
+ function classify(specifier) {
7356
+ if (specifier.startsWith("node:")) {
7357
+ const bare = specifier.slice("node:".length);
7358
+ const root = bare.split("/")[0];
7359
+ const suggestion = BUILTIN_SUGGESTIONS[specifier] ?? BUILTIN_SUGGESTIONS[`node:${root}`];
7360
+ return {
7361
+ code: "NODE_BUILTIN",
7362
+ message: `\u6C99\u7BB1\u6CA1\u6709 node \u5185\u7F6E\u6A21\u5757\uFF0C'${specifier}' \u5728\u53D1\u5E03\u540E\u8FD0\u884C\u65F6\u4F1A\u629B ERR_MODULE_NOT_FOUND\uFF08\u672C\u5730 adep dev \u80FD\u8DD1\uFF0C\u56E0\u4E3A\u5BBF\u4E3B\u5C31\u662F Node\uFF09\u3002${suggestion ?? `\u8BF7\u79FB\u9664\u5BF9 ${root} \u7684\u4F9D\u8D56\u3002`}`
7363
+ };
7364
+ }
7365
+ if (NODE_BUILTINS.has(specifier)) {
7366
+ return {
7367
+ code: "NODE_BUILTIN",
7368
+ message: `\u6C99\u7BB1\u6CA1\u6709 node \u5185\u7F6E\u6A21\u5757\uFF0C'${specifier}' \u5728\u53D1\u5E03\u540E\u8FD0\u884C\u65F6\u4F1A\u629B ERR_MODULE_NOT_FOUND\u3002${BUILTIN_SUGGESTIONS[specifier] ?? `\u8BF7\u79FB\u9664\u5BF9 ${specifier} \u7684\u4F9D\u8D56\u3002`}`
7369
+ };
7370
+ }
7371
+ if (NATIVE_ADDON_PACKAGES.has(specifier)) {
7372
+ return {
7373
+ code: "NATIVE_ADDON",
7374
+ message: `'${specifier}' \u9700\u8981\u539F\u751F C++ \u6269\u5C55\uFF0C\u4E91\u51FD\u6570\u6C99\u7BB1\u65E0\u6CD5\u52A0\u8F7D\uFF08\u4E5F\u4E0D\u662F registry \u767D\u540D\u5355\u80FD\u89E3\u51B3\u7684\u95EE\u9898\uFF09\u3002\u8BF7\u6362\u7EAF JS \u5B9E\u73B0\uFF08\u5982 bcrypt\u2192@adep/crypto \u7684 hashPassword\u3001sharp\u2192\u6784\u5EFA\u671F\u9884\u5904\u7406\u56FE\u7247\uFF09\u3002`
7375
+ };
7376
+ }
7377
+ return null;
7378
+ }
7379
+ async function scanFunctionSources(rootDir, functionsDir) {
7380
+ const base = join21(rootDir, functionsDir);
7381
+ const findings = [];
7382
+ async function walk(current) {
7383
+ let entries;
7384
+ try {
7385
+ entries = await readdir7(current, { withFileTypes: true });
7386
+ } catch {
7387
+ return;
7388
+ }
7389
+ for (const entry of entries) {
7390
+ const abs = join21(current, entry.name);
7391
+ if (entry.isDirectory()) {
7392
+ if (SKIP_DIRS.has(entry.name)) continue;
7393
+ await walk(abs);
7394
+ continue;
7395
+ }
7396
+ if (!entry.isFile()) continue;
7397
+ if (!SOURCE_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) continue;
7398
+ if (entry.name.endsWith(".d.ts")) continue;
7399
+ let content;
7400
+ try {
7401
+ content = await readFile17(abs, "utf8");
7402
+ } catch {
7403
+ continue;
7404
+ }
7405
+ if (content.length > MAX_SCAN_BYTES) continue;
7406
+ const relPath = relative6(rootDir, abs).split(sep3).join("/");
7407
+ const lines = content.split("\n");
7408
+ for (const [index, line] of lines.entries()) {
7409
+ const trimmed = line.trim();
7410
+ if (trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("/*")) continue;
7411
+ for (const specifier of extractSpecifiers(line)) {
7412
+ const hit = classify(specifier);
7413
+ if (hit !== null) {
7414
+ findings.push({
7415
+ file: relPath,
7416
+ line: index + 1,
7417
+ code: hit.code,
7418
+ specifier,
7419
+ message: hit.message
7420
+ });
7421
+ }
7422
+ }
7423
+ }
7424
+ }
7425
+ }
7426
+ await walk(base);
7427
+ return findings;
7428
+ }
7429
+ var NODE_BUILTINS, NATIVE_ADDON_PACKAGES, BUILTIN_SUGGESTIONS, SOURCE_EXTENSIONS, SKIP_DIRS, MAX_SCAN_BYTES;
7430
+ var init_sandbox_scan = __esm({
7431
+ "packages/cli/src/sandbox-scan.ts"() {
7432
+ "use strict";
7433
+ NODE_BUILTINS = /* @__PURE__ */ new Set([
7434
+ "assert",
7435
+ "async_hooks",
7436
+ "buffer",
7437
+ "child_process",
7438
+ "cluster",
7439
+ "console",
7440
+ "constants",
7441
+ "crypto",
7442
+ "dgram",
7443
+ "diagnostics_channel",
7444
+ "dns",
7445
+ "domain",
7446
+ "events",
7447
+ "fs",
7448
+ "http",
7449
+ "http2",
7450
+ "https",
7451
+ "inspector",
7452
+ "module",
7453
+ "net",
7454
+ "os",
7455
+ "path",
7456
+ "perf_hooks",
7457
+ "process",
7458
+ "punycode",
7459
+ "querystring",
7460
+ "readline",
7461
+ "repl",
7462
+ "stream",
7463
+ "string_decoder",
7464
+ "sys",
7465
+ "timers",
7466
+ "tls",
7467
+ "trace_events",
7468
+ "tty",
7469
+ "url",
7470
+ "util",
7471
+ "v8",
7472
+ "vm",
7473
+ "wasi",
7474
+ "worker_threads",
7475
+ "zlib"
7476
+ ]);
7477
+ NATIVE_ADDON_PACKAGES = /* @__PURE__ */ new Set([
7478
+ "bcrypt",
7479
+ "better-sqlite3",
7480
+ "sqlite3",
7481
+ "sharp",
7482
+ "canvas",
7483
+ "argon2",
7484
+ "node-gyp",
7485
+ "farmhash",
7486
+ "xxhash-addon",
7487
+ "zeromq",
7488
+ "grpc",
7489
+ "@grpc/grpc-js",
7490
+ "leveldown",
7491
+ "rocksdb",
7492
+ "node-canvas",
7493
+ "microtime",
7494
+ "sodium-native",
7495
+ "re2"
7496
+ ]);
7497
+ BUILTIN_SUGGESTIONS = {
7498
+ "node:crypto": "\u7528 WebCrypto\uFF08\u6C99\u7BB1\u5DF2\u6CE8\u5165 crypto\uFF09\u6216 @adep/crypto \u7684 signJwt / hashPassword / encryptSecret",
7499
+ crypto: "\u7528 WebCrypto\uFF08\u6C99\u7BB1\u5DF2\u6CE8\u5165 crypto\uFF09\u6216 @adep/crypto",
7500
+ "node:fs": "\u6C99\u7BB1\u65E0\u6587\u4EF6\u7CFB\u7EDF\uFF1B\u9879\u76EE\u6570\u636E\u8D70 ctx.cloud.db\uFF0C\u6587\u4EF6\u8D70 ctx.cloud.storage",
7501
+ fs: "\u6C99\u7BB1\u65E0\u6587\u4EF6\u7CFB\u7EDF\uFF1B\u9879\u76EE\u6570\u636E\u8D70 ctx.cloud.db\uFF0C\u6587\u4EF6\u8D70 ctx.cloud.storage",
7502
+ "node:path": "\u624B\u5199\u5B57\u7B26\u4E32\u62FC\u63A5\uFF08\u6C99\u7BB1\u91CC\u7684\u8DEF\u5F84\u90FD\u662F POSIX \u5F62\u5F0F\uFF09",
7503
+ path: "\u624B\u5199\u5B57\u7B26\u4E32\u62FC\u63A5\uFF08\u6C99\u7BB1\u91CC\u7684\u8DEF\u5F84\u90FD\u662F POSIX \u5F62\u5F0F\uFF09",
7504
+ "node:buffer": "\u7528 Uint8Array + TextEncoder/TextDecoder\uFF08\u6C99\u7BB1\u5DF2\u6CE8\u5165\uFF09",
7505
+ buffer: "\u7528 Uint8Array + TextEncoder/TextDecoder\uFF08\u6C99\u7BB1\u5DF2\u6CE8\u5165\uFF09",
7506
+ "node:process": "\u73AF\u5883\u53D8\u91CF\u8D70 ctx.env\uFF08adep.config.ts \u7684 environment\uFF09",
7507
+ process: "\u73AF\u5883\u53D8\u91CF\u8D70 ctx.env\uFF08adep.config.ts \u7684 environment\uFF09",
7508
+ "node:stream": "\u7528\u6C99\u7BB1\u6CE8\u5165\u7684 ReadableStream / WritableStream / TransformStream",
7509
+ stream: "\u7528\u6C99\u7BB1\u6CE8\u5165\u7684 ReadableStream / WritableStream / TransformStream"
7510
+ };
7511
+ SOURCE_EXTENSIONS = [".ts", ".js", ".mjs", ".cjs", ".tsx", ".jsx"];
7512
+ SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "__tests__", "dist", ".git", ".adep", "coverage"]);
7513
+ MAX_SCAN_BYTES = 512 * 1024;
7514
+ }
7515
+ });
7516
+
7175
7517
  // packages/cli/src/doctor.ts
7176
7518
  var doctor_exports = {};
7177
7519
  __export(doctor_exports, {
@@ -7202,12 +7544,13 @@ async function credentialMode(file) {
7202
7544
  return void 0;
7203
7545
  }
7204
7546
  }
7205
- async function runDoctor(paths) {
7547
+ async function runDoctor(paths, cwd = process.cwd()) {
7206
7548
  const credentials = await loadCredentials(paths);
7207
7549
  const server = credentials?.server ?? resolveServer();
7208
7550
  const mode = await credentialMode(paths.credentialsFile);
7209
7551
  const offline = await isOffline();
7210
7552
  const health = await probeServer(server);
7553
+ const sandbox = await scanSandbox(cwd);
7211
7554
  const report = {
7212
7555
  server,
7213
7556
  credentials: {
@@ -7218,7 +7561,8 @@ async function runDoctor(paths) {
7218
7561
  network: { offline },
7219
7562
  serverHealth: health,
7220
7563
  offlineCommands: [...OFFLINE_COMMANDS],
7221
- boundaries: SIM_BOUNDARIES.map((b) => ({ kind: b.kind, title: b.title, detail: b.detail }))
7564
+ boundaries: SIM_BOUNDARIES.map((b) => ({ kind: b.kind, title: b.title, detail: b.detail })),
7565
+ sandbox
7222
7566
  };
7223
7567
  if (credentials !== null) report.credentials.email = credentials.email;
7224
7568
  if (mode !== void 0 && mode !== "600") {
@@ -7226,6 +7570,22 @@ async function runDoctor(paths) {
7226
7570
  }
7227
7571
  return report;
7228
7572
  }
7573
+ async function scanSandbox(cwd) {
7574
+ let functionsDir = "functions";
7575
+ try {
7576
+ const config = await loadAdepConfigModule(cwd);
7577
+ if (config?.functionsDir !== void 0 && config.functionsDir.length > 0) {
7578
+ functionsDir = config.functionsDir;
7579
+ }
7580
+ } catch {
7581
+ }
7582
+ try {
7583
+ const findings = await scanFunctionSources(cwd, functionsDir);
7584
+ return { functionsDir, findings };
7585
+ } catch {
7586
+ return { functionsDir: null, findings: [] };
7587
+ }
7588
+ }
7229
7589
  function formatDoctorReport(report) {
7230
7590
  const lines = ["adep doctor \xB7 \u73AF\u5883\u81EA\u68C0", ""];
7231
7591
  lines.push("\u51ED\u636E\u4E0E\u8EAB\u4EFD");
@@ -7253,6 +7613,28 @@ function formatDoctorReport(report) {
7253
7613
  }
7254
7614
  lines.push("", "\u79BB\u7EBF\u53EF\u7528\u8303\u56F4\uFF08\u65AD\u7F51\u65F6\u4ECD\u53EF\u6267\u884C\uFF09");
7255
7615
  for (const command of report.offlineCommands) lines.push(` \xB7 ${command}`);
7616
+ lines.push("", "\u4E91\u51FD\u6570\u6C99\u7BB1\u517C\u5BB9\u6027\uFF08\u53D1\u5E03\u524D\u5C31\u80FD\u6539\uFF0C\u522B\u7B49\u8FD0\u884C\u65F6\u70B8\uFF09");
7617
+ if (report.sandbox.functionsDir === null) {
7618
+ lines.push(" \xB7 \u672A\u627E\u5230\u51FD\u6570\u76EE\u5F55\uFF0C\u8DF3\u8FC7\u626B\u63CF");
7619
+ } else if (report.sandbox.findings.length === 0) {
7620
+ lines.push(` \u2713 ${report.sandbox.functionsDir}/ \u5185\u672A\u53D1\u73B0 node \u5185\u7F6E\u6A21\u5757 / \u539F\u751F addon \u4F9D\u8D56`);
7621
+ } else {
7622
+ const byFile = /* @__PURE__ */ new Map();
7623
+ for (const finding of report.sandbox.findings) {
7624
+ const list = byFile.get(finding.file) ?? [];
7625
+ list.push(finding);
7626
+ byFile.set(finding.file, list);
7627
+ }
7628
+ lines.push(
7629
+ ` \u2717 \u53D1\u73B0 ${report.sandbox.findings.length} \u5904\u6C99\u7BB1\u4E0D\u517C\u5BB9\uFF08\u672C\u5730 adep dev \u80FD\u8DD1\uFF0C\u53D1\u5E03\u540E\u4F1A\u5931\u8D25\uFF09\uFF1A`
7630
+ );
7631
+ for (const [file, findingList] of byFile) {
7632
+ for (const finding of findingList) {
7633
+ lines.push(` ${file}:${finding.line} [${finding.code}] ${finding.specifier}`);
7634
+ lines.push(` ${finding.message}`);
7635
+ }
7636
+ }
7637
+ }
7256
7638
  lines.push("", "\u672C\u5730\u6A21\u62DF\u8FD0\u884C\u65F6\u7684\u80FD\u529B\u8FB9\u754C\uFF08\u4E0E adep dev \u542F\u52A8\u6A2A\u5E45\u540C\u6E90\uFF09");
7257
7639
  for (const boundary of report.boundaries) {
7258
7640
  lines.push(` \xB7 [${boundary.kind}] ${boundary.title}\uFF1A${boundary.detail}`);
@@ -7267,6 +7649,8 @@ var init_doctor = __esm({
7267
7649
  init_config();
7268
7650
  init_boundary();
7269
7651
  init_net();
7652
+ init_sandbox_scan();
7653
+ init_ts_config();
7270
7654
  SERVER_PROBE_TIMEOUT_MS = 5e3;
7271
7655
  OFFLINE_COMMANDS = [
7272
7656
  "adep init",
@@ -7639,8 +8023,8 @@ __export(hosting_exports, {
7639
8023
  hostingInfo: () => hostingInfo,
7640
8024
  hostingPull: () => hostingPull
7641
8025
  });
7642
- import { readdir as readdir7, readFile as readFile16, stat as stat13 } from "node:fs/promises";
7643
- import { dirname as dirname11, join as join20, relative as relative5, resolve as resolve14, sep as sep3 } from "node:path";
8026
+ import { readdir as readdir8, readFile as readFile18, stat as stat13 } from "node:fs/promises";
8027
+ import { dirname as dirname11, join as join22, relative as relative7, resolve as resolve14, sep as sep4 } from "node:path";
7644
8028
  async function open4(paths, options) {
7645
8029
  const client = await createClient(paths);
7646
8030
  const project2 = await resolveSlug(resolve14(options.cwd), options.slug);
@@ -7661,16 +8045,16 @@ async function collectSiteFiles(dir) {
7661
8045
  const walk = async (sub) => {
7662
8046
  let entries;
7663
8047
  try {
7664
- entries = await readdir7(sub, { withFileTypes: true });
8048
+ entries = await readdir8(sub, { withFileTypes: true });
7665
8049
  } catch {
7666
8050
  return;
7667
8051
  }
7668
8052
  for (const entry of entries) {
7669
- const full = join20(sub, entry.name);
8053
+ const full = join22(sub, entry.name);
7670
8054
  if (entry.isDirectory()) {
7671
8055
  await walk(full);
7672
8056
  } else if (entry.isFile()) {
7673
- const rel = relative5(root, full).split(sep3).join("/");
8057
+ const rel = relative7(root, full).split(sep4).join("/");
7674
8058
  files.set(rel, full);
7675
8059
  }
7676
8060
  }
@@ -7690,7 +8074,7 @@ async function hostingDeploy(paths, options) {
7690
8074
  for (const [rel, full] of files) {
7691
8075
  log(`[adep] \u4E0A\u4F20 site/${rel}`);
7692
8076
  const info2 = await stat13(full);
7693
- const bytes = await readFile16(full);
8077
+ const bytes = await readFile18(full);
7694
8078
  const form = new FormData();
7695
8079
  form.set("path", `site/${rel}`);
7696
8080
  form.set("visibility", "public");
@@ -7728,7 +8112,7 @@ async function hostingPull(paths, options) {
7728
8112
  const response = await client.download(url, "HOSTING_DOWNLOAD_FAILED");
7729
8113
  const bytes = Buffer.from(await response.arrayBuffer());
7730
8114
  const rel = entry.path.replace(/^site\//, "");
7731
- const target = join20(outputDir, ...rel.split("/"));
8115
+ const target = join22(outputDir, ...rel.split("/"));
7732
8116
  await mkdir12(dirname11(target), { recursive: true });
7733
8117
  await writeFile10(target, bytes);
7734
8118
  files.push({ path: entry.path, size: bytes.length });
@@ -12274,11 +12658,28 @@ function registerImport(program2, ctx) {
12274
12658
 
12275
12659
  // packages/cli/src/commands/dev.ts
12276
12660
  function registerDevServers(program2, ctx) {
12277
- program2.command("dev").description("\u672C\u5730\u8C03\u8BD5\uFF1A\u76D1\u542C functions/ \u70ED\u91CD\u8F7D\uFF0Chttp://localhost:<port>/<fnName>").option("-p, --port <port>", "\u76D1\u542C\u7AEF\u53E3\uFF08\u7F3A\u7701 8787\uFF09", "8787").action(async (flags) => {
12661
+ program2.command("dev").description("\u672C\u5730\u8C03\u8BD5\uFF1A\u76D1\u542C functions/ \u70ED\u91CD\u8F7D\uFF0Chttp://localhost:<port>/<fnName>").option("-p, --port <port>", "\u76D1\u542C\u7AEF\u53E3\uFF08\u7F3A\u7701 8787\uFF09", "8787").option(
12662
+ "--db <mode>",
12663
+ "\u6570\u636E\u5E93\u6A21\u5F0F\uFF1Asqlite\uFF08\u7F3A\u7701\uFF0C\u771F\u5B9E SQLite \u5E93\u6587\u4EF6\uFF0C\u9700 Bun \u6216 Node \u2265 22.5\uFF1B\u8FD0\u884C\u65F6\u4E0D\u652F\u6301\u6216\u6253\u5F00\u5931\u8D25\u65F6\u81EA\u52A8\u964D\u7EA7 sim\uFF09| sim\uFF08\u5185\u7F6E\u6A21\u62DF\u5F15\u64CE + .adep/sim/db.json\uFF09"
12664
+ ).option(
12665
+ "--db-file <path>",
12666
+ "sqlite \u6A21\u5F0F\u7684\u5E93\u6587\u4EF6\uFF08\u7F3A\u7701\u53D6 ADEP_SERVE_DB_FILE\uFF0C\u518D\u7F3A\u7701 .adep/data/project.sqlite\uFF09"
12667
+ ).option(
12668
+ "--schema <file>",
12669
+ "\u6570\u636E\u5E93\u7ED3\u6784\u6587\u4EF6\uFF1A\u542F\u52A8\u65F6\u5BF9\u672C\u5730\u5E93\u9010\u6761\u5E94\u7528\uFF08\u5EFA\u8868\u8BED\u53E5\u5EFA\u8BAE IF NOT EXISTS\uFF0C\u5E42\u7B49\u53EF\u91CD\u590D\u542F\u52A8\uFF09"
12670
+ ).action(async (flags) => {
12278
12671
  const command = ctx.io("dev");
12279
12672
  await command.run(async () => {
12280
12673
  const { startDevServer: startDevServer2 } = await Promise.resolve().then(() => (init_dev(), dev_exports));
12281
- const started = await startDevServer2({ cwd: ctx.cwd, port: Number(flags.port ?? "8787") });
12674
+ const started = await startDevServer2({
12675
+ cwd: ctx.cwd,
12676
+ port: Number(flags.port ?? "8787"),
12677
+ // 缺省值一律交给 startDevServer 定档(旗标 > ADEP_SERVE_DB > 内置缺省),
12678
+ // 与 `adep serve` 同一条纪律:commander 的缺省值不该盖掉环境变量。
12679
+ ...flags.db === void 0 ? {} : { db: flags.db },
12680
+ ...flags.dbFile === void 0 ? {} : { dbFile: flags.dbFile },
12681
+ ...flags.schema === void 0 ? {} : { schemaFile: flags.schema }
12682
+ });
12282
12683
  command.raw(`[adep] dev server listening on ${started.baseUrl}\uFF08Ctrl-C \u9000\u51FA\uFF09`);
12283
12684
  await new Promise(() => void 0);
12284
12685
  });
@@ -12333,7 +12734,7 @@ init_auth();
12333
12734
  init_client();
12334
12735
  init_deploy();
12335
12736
  import { stat as stat9 } from "node:fs/promises";
12336
- import { join as join17, resolve as resolve10 } from "node:path";
12737
+ import { join as join18, resolve as resolve10 } from "node:path";
12337
12738
  async function resolveProjectId2(client, cwd, slug) {
12338
12739
  const resolvedSlug = await resolveSlug(resolve10(cwd), slug);
12339
12740
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -12376,7 +12777,8 @@ async function publishFunctions(paths, options) {
12376
12777
  cwd: options.cwd,
12377
12778
  ...options.slug === void 0 ? {} : { slug: options.slug },
12378
12779
  silent: options.silent ?? false,
12379
- ...options.log === void 0 ? {} : { log: options.log }
12780
+ ...options.log === void 0 ? {} : { log: options.log },
12781
+ ...options.force === void 0 ? {} : { force: options.force }
12380
12782
  });
12381
12783
  const elapsedSeconds = (Date.now() - startedAt) / 1e3;
12382
12784
  const deployedCount = result.functions.filter((fn) => fn.action !== "none").length;
@@ -12395,11 +12797,12 @@ async function runPublish(paths, io, cwd, flags) {
12395
12797
  cwd,
12396
12798
  ...flags.project === void 0 ? {} : { slug: flags.project },
12397
12799
  silent: io.json,
12398
- log: (line) => io.line(line)
12800
+ log: (line) => io.line(line),
12801
+ ...flags.force === void 0 ? {} : { force: flags.force }
12399
12802
  });
12400
12803
  }
12401
12804
  if (wantFrontend) {
12402
- const webDir = join17(cwd, "web");
12805
+ const webDir = join18(cwd, "web");
12403
12806
  const webStat = await stat9(webDir).catch(() => null);
12404
12807
  if (webStat !== null && webStat.isDirectory()) {
12405
12808
  const { frontendSync: frontendSync2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
@@ -12447,7 +12850,10 @@ function registerPublish(program2, ctx) {
12447
12850
  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(
12448
12851
  "--only <scope>",
12449
12852
  "\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"
12450
- ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
12853
+ ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option(
12854
+ "--force",
12855
+ "\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"
12856
+ ).action(async (flags) => {
12451
12857
  const command = ctx.io("publish");
12452
12858
  await command.run(async () => {
12453
12859
  const result = await runPublish(ctx.paths, command, ctx.cwd, flags);
@@ -12457,13 +12863,14 @@ function registerPublish(program2, ctx) {
12457
12863
  }
12458
12864
 
12459
12865
  // packages/cli/src/commands/deploy.ts
12460
- async function runDeploy(paths, io, cwd, slug, dir) {
12866
+ async function runDeploy(paths, io, cwd, slug, dir, force) {
12461
12867
  const { deploy: deploy2 } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
12462
12868
  const startedAt = Date.now();
12463
12869
  const result = await deploy2(paths, {
12464
12870
  cwd,
12465
12871
  ...slug === void 0 ? {} : { slug },
12466
12872
  ...dir === void 0 ? {} : { functionsDir: dir },
12873
+ ...force === void 0 ? {} : { force },
12467
12874
  // --json 下逐函数进度会破坏「stdout 恰好一个 JSON 对象」的信封约定(PRD §2.5.3)。
12468
12875
  silent: io.json,
12469
12876
  // 人读模式的进度也走注入的 io:deploy 内部缺省会直写 process.stdout,
@@ -12488,14 +12895,14 @@ async function runDeploy(paths, io, cwd, slug, dir) {
12488
12895
  function registerDeploy(program2, ctx) {
12489
12896
  program2.command("deploy").description(
12490
12897
  "[deprecated] \u63A8\u8350\u4F7F\u7528 adep publish\u3002\u589E\u91CF\u90E8\u7F72\u51FD\u6570\uFF1A\u5BF9\u6BD4\u8FDC\u7AEF\u54C8\u5E0C \u2192 \u4EC5\u4E0A\u4F20\u53D8\u66F4 \u2192 \u53D1\u5E03 \u2192 \u8F93\u51FA\u8BBF\u95EE\u57DF\u540D"
12491
- ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
12898
+ ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option("--force", "\u653E\u884C warn \u7EA7\u5BC6\u94A5\u5F15\u7528\u547D\u4E2D\uFF08FN-013\uFF1B\u786E\u8BA4\u975E\u6CC4\u6F0F\u540E\u7528\uFF0C\u670D\u52A1\u7AEF\u843D\u5BA1\u8BA1\uFF09").action(async (flags) => {
12492
12899
  const command = ctx.io("deploy");
12493
12900
  if (!command.json) {
12494
12901
  process.stderr.write(
12495
12902
  "\u63D0\u793A\uFF1Aadep deploy \u5DF2\u5E9F\u5F03\uFF0C\u63A8\u8350\u4F7F\u7528 adep publish\uFF08\u5168\u6808\u53D1\u5E03\uFF09\u6216 adep publish --only functions\uFF08\u4EC5\u51FD\u6570\uFF09\n"
12496
12903
  );
12497
12904
  }
12498
- await command.run(() => runDeploy(ctx.paths, command, ctx.cwd, flags.project));
12905
+ await command.run(() => runDeploy(ctx.paths, command, ctx.cwd, flags.project, void 0, flags.force));
12499
12906
  });
12500
12907
  }
12501
12908
 
@@ -12539,7 +12946,7 @@ function registerExport(program2, ctx) {
12539
12946
 
12540
12947
  // packages/cli/src/commands/db.ts
12541
12948
  function registerDb(program2, ctx) {
12542
- const db = program2.command("db").description("\u9879\u76EE\u6570\u636E\u5E93\u7EF4\u62A4\uFF1A\u542F\u52A8 / \u72B6\u6001 / \u505C\u6B62 / SQL / \u5FEB\u7167 / \u56DE\u6EDA").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
12949
+ const db = program2.command("db").description("\u9879\u76EE\u6570\u636E\u5E93\u7EF4\u62A4\uFF1A\u542F\u52A8 / \u72B6\u6001 / \u505C\u6B62 / SQL / \u5FEB\u7167 / \u56DE\u6EDA");
12543
12950
  db.command("start").description("\u542F\u52A8\u9879\u76EE\u6570\u636E\u5E93\uFF08\u5DF2\u5B58\u5728\u5219\u91CD\u65B0\u6FC0\u6D3B\uFF0C\u4E0D\u91CD\u5EFA\u6570\u636E\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
12544
12951
  const command = ctx.io("db start");
12545
12952
  await command.run(async () => {
@@ -12690,7 +13097,7 @@ function registerDb(program2, ctx) {
12690
13097
 
12691
13098
  // packages/cli/src/commands/frontend.ts
12692
13099
  function registerFrontend(program2, ctx) {
12693
- const frontend = program2.command("frontend").description("\u524D\u7AEF\u8349\u7A3F\u7EF4\u62A4\uFF1Async\uFF08\u672C\u5730 web/ \u2192 \u5E73\u53F0\u8349\u7A3F\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
13100
+ const frontend = program2.command("frontend").description("\u524D\u7AEF\u8349\u7A3F\u7EF4\u62A4\uFF1Async\uFF08\u672C\u5730 web/ \u2192 \u5E73\u53F0\u8349\u7A3F\uFF09");
12694
13101
  frontend.command("sync").description("\u4E0A\u4F20\u672C\u5730 web/ \u6E90\u7801\u4E3A\u5E73\u53F0\u524D\u7AEF\u8349\u7A3F\uFF08\u6574\u7EC4\u66FF\u6362\uFF1Bpublish \u5168\u6808\u65F6\u81EA\u52A8\u6267\u884C\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option("-d, --dir <dir>", "\u672C\u5730\u524D\u7AEF\u6E90\u7801\u76EE\u5F55\uFF08\u7F3A\u7701 cwd/web\uFF09").action(async (flags) => {
12695
13102
  const command = ctx.io("frontend sync");
12696
13103
  await command.run(async () => {
@@ -12712,7 +13119,7 @@ function registerFrontend(program2, ctx) {
12712
13119
 
12713
13120
  // packages/cli/src/commands/storage.ts
12714
13121
  function registerStorage(program2, ctx) {
12715
- const storage = program2.command("storage").description("\u4E91\u5B58\u50A8 / \u6587\u4EF6\u5B58\u50A8\uFF1A\u4E0A\u4F20 / \u4E0B\u8F7D / \u5217\u8868 / \u5220\u9664").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
13122
+ const storage = program2.command("storage").description("\u4E91\u5B58\u50A8 / \u6587\u4EF6\u5B58\u50A8\uFF1A\u4E0A\u4F20 / \u4E0B\u8F7D / \u5217\u8868 / \u5220\u9664");
12716
13123
  storage.command("upload").description("\u4E0A\u4F20\u5355\u4E2A\u6587\u4EF6\uFF08multipart\uFF1B\u5355\u6587\u4EF6 \u2264 50MB\uFF09").argument("<file>", "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84").requiredOption("--path <remote-path>", "\u6876\u5185\u76EE\u6807\u8DEF\u5F84\uFF08\u5982 avatars/a.png\uFF09").option(
12717
13124
  "--visibility <public|private>",
12718
13125
  "public \u76F4\u8FDE / private \u7B7E\u540D\uFF08\u7F3A\u7701 private\uFF09",
@@ -12997,14 +13404,16 @@ function registerFunctions(program2, ctx) {
12997
13404
  const functions = program2.command("functions").description("\u4E91\u51FD\u6570\uFF1A\u90E8\u7F72\uFF08\u53EF\u6307\u5B9A\u76EE\u5F55\uFF09/ \u5217\u51FA / \u67E5\u65E5\u5FD7");
12998
13405
  functions.command("deploy").description(
12999
13406
  "[deprecated] \u63A8\u8350\u4F7F\u7528 adep publish --only functions\u3002\u90E8\u7F72\u51FD\u6570\u76EE\u5F55\uFF08dir \u8986\u76D6 adep.config.ts \u7684 functionsDir\uFF09"
13000
- ).argument("[dir]", "\u51FD\u6570\u76EE\u5F55\uFF08\u76F8\u5BF9\u9879\u76EE\u6839\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u7F3A\u7701\u53D6\u914D\u7F6E\u91CC\u7684 functionsDir\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (dir, flags) => {
13407
+ ).argument("[dir]", "\u51FD\u6570\u76EE\u5F55\uFF08\u76F8\u5BF9\u9879\u76EE\u6839\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u7F3A\u7701\u53D6\u914D\u7F6E\u91CC\u7684 functionsDir\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option("--force", "\u653E\u884C warn \u7EA7\u5BC6\u94A5\u5F15\u7528\u547D\u4E2D\uFF08FN-013\uFF1B\u786E\u8BA4\u975E\u6CC4\u6F0F\u540E\u7528\uFF0C\u670D\u52A1\u7AEF\u843D\u5BA1\u8BA1\uFF09").action(async (dir, flags) => {
13001
13408
  const command = ctx.io("functions deploy");
13002
13409
  if (!command.json) {
13003
13410
  process.stderr.write(
13004
13411
  "\u63D0\u793A\uFF1Aadep functions deploy \u5DF2\u5E9F\u5F03\uFF0C\u63A8\u8350\u4F7F\u7528 adep publish --only functions\n"
13005
13412
  );
13006
13413
  }
13007
- await command.run(() => runDeploy(ctx.paths, command, ctx.cwd, flags.project, dir));
13414
+ await command.run(
13415
+ () => runDeploy(ctx.paths, command, ctx.cwd, flags.project, dir, flags.force)
13416
+ );
13008
13417
  });
13009
13418
  functions.command("list").description("\u5217\u51FA\u9879\u76EE\u4E0B\u7684\u4E91\u51FD\u6570\uFF08\u542B\u516C\u7F51\u8BBF\u95EE\u524D\u7F00\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
13010
13419
  const command = ctx.io("functions list");
@@ -13055,7 +13464,7 @@ function parseBool(raw) {
13055
13464
  throw new CliError("INVALID_BOOLEAN", `\u5E03\u5C14\u53C2\u6570\u987B\u4E3A true \u6216 false\uFF0C\u6536\u5230 "${raw}"`);
13056
13465
  }
13057
13466
  function registerHosting(program2, ctx) {
13058
- const hosting = program2.command("hosting").description("\u9759\u6001\u6258\u7BA1\uFF1A\u67E5\u770B / \u90E8\u7F72 / \u62C9\u53D6 / \u914D\u7F6E").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
13467
+ const hosting = program2.command("hosting").description("\u9759\u6001\u6258\u7BA1\uFF1A\u67E5\u770B / \u90E8\u7F72 / \u62C9\u53D6 / \u914D\u7F6E");
13059
13468
  hosting.command("info").description("\u67E5\u770B\u9759\u6001\u6258\u7BA1\u914D\u7F6E\u3001\u7AD9\u70B9\u5730\u5740\u4E0E\u6587\u4EF6\u6811").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
13060
13469
  const command = ctx.io("hosting info");
13061
13470
  await command.run(async () => {