@adep/cli 0.1.16 → 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
@@ -3030,7 +3030,7 @@ function createLocalStorageDriver(options) {
3030
3030
  assertStoragePrefix(prefix);
3031
3031
  const root = bucketDir(projectId);
3032
3032
  const metas = [];
3033
- const walk = async (dir, relative7) => {
3033
+ const walk = async (dir, relative8) => {
3034
3034
  let entries;
3035
3035
  try {
3036
3036
  entries = await readdir3(dir, { withFileTypes: true });
@@ -3041,7 +3041,7 @@ function createLocalStorageDriver(options) {
3041
3041
  for (const entry of entries) {
3042
3042
  if (entry.name.endsWith(META_SUFFIX)) continue;
3043
3043
  const full = join6(dir, entry.name);
3044
- const rel = relative7 === "" ? entry.name : `${relative7}/${entry.name}`;
3044
+ const rel = relative8 === "" ? entry.name : `${relative8}/${entry.name}`;
3045
3045
  if (entry.isFile()) {
3046
3046
  if (prefix !== void 0 && !rel.startsWith(prefix)) continue;
3047
3047
  tasks.push(
@@ -3326,233 +3326,704 @@ var init_runtime = __esm({
3326
3326
  }
3327
3327
  });
3328
3328
 
3329
- // packages/cli/src/sim/env.ts
3330
- import { readFile as readFile6 } from "node:fs/promises";
3331
- import { join as join9 } from "node:path";
3332
- function parseEnv(content) {
3333
- const env = {};
3334
- for (const raw of content.split(/\r?\n/)) {
3335
- const line = raw.trim();
3336
- if (line.length === 0 || line.startsWith("#")) continue;
3337
- const eq = line.indexOf("=");
3338
- if (eq === -1) continue;
3339
- const key = line.slice(0, eq).trim();
3340
- if (key.length === 0) continue;
3341
- env[key] = line.slice(eq + 1).trim();
3342
- }
3343
- 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
+ );
3344
3341
  }
3345
- async function loadSimEnv(cwd, config = {}) {
3346
- const envRoot = await readFile6(join9(cwd, ".env"), "utf8").catch(() => "");
3347
- const envLocal = await readFile6(join9(cwd, ".env.local"), "utf8").catch(() => "");
3348
- const merged = { ...parseEnv(envRoot), ...parseEnv(envLocal) };
3349
- for (const secret of config.secrets ?? []) {
3350
- if (merged[secret] !== void 0) continue;
3351
- if (process.env[secret] !== void 0) {
3352
- merged[secret] = process.env[secret];
3353
- continue;
3354
- }
3355
- throw new Error(
3356
- `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`
3357
- );
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;
3358
3349
  }
3359
- return merged;
3360
3350
  }
3361
- var init_env = __esm({
3362
- "packages/cli/src/sim/env.ts"() {
3363
- "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");
3364
3355
  }
3365
- });
3366
-
3367
- // packages/cli/src/sim/invoke.ts
3368
- function resolveFunctionEntry(files, fnName) {
3369
- const flat = `${fnName}.ts`;
3370
- if (files[flat] !== void 0) return flat;
3371
- const directory = `${fnName}/index.ts`;
3372
- if (files[directory] !== void 0) return directory;
3373
- return void 0;
3374
- }
3375
- function listFunctionNames(files) {
3376
- const names = /* @__PURE__ */ new Set();
3377
- for (const key of Object.keys(files)) {
3378
- const parts = key.split("/");
3379
- if (parts.length === 1 && parts[0] !== void 0 && parts[0].endsWith(".ts")) {
3380
- names.add(parts[0].slice(0, -3));
3381
- } else if (parts.length === 2 && parts[1] === "index.ts" && parts[0] !== void 0) {
3382
- 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
+ );
3383
3372
  }
3384
- }
3385
- return [...names];
3386
- }
3387
- function createSimInvokeHandler(options) {
3388
- return async (method, args) => {
3389
- if (method !== "invoke") {
3390
- 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);
3391
3376
  }
3392
- const input = args[0];
3393
- if (typeof input?.name !== "string" || input.name.length === 0) {
3394
- 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
+ );
3395
3392
  }
3396
- const targetEntry = resolveFunctionEntry(options.files, input.name);
3397
- if (targetEntry === void 0) {
3398
- 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));
3399
3395
  }
3400
- const executeInput = {
3401
- project: { id: "local", slug: "local" },
3402
- fn: { id: input.name, name: input.name },
3403
- files: options.files,
3404
- entry: targetEntry,
3405
- request: {
3406
- method: "POST",
3407
- path: `/${input.name}`,
3408
- query: input.query ?? {},
3409
- headers: {},
3410
- ...input.body === void 0 ? {} : { body: input.body }
3411
- },
3412
- timeoutMs: 1e4,
3413
- ...options.env === void 0 ? {} : { env: options.env }
3414
- };
3415
- const result = await options.executor.execute(executeInput);
3416
- 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;
3417
3413
  };
3414
+ return { server, cookie, request, upload, download };
3418
3415
  }
3419
- var init_invoke = __esm({
3420
- "packages/cli/src/sim/invoke.ts"() {
3421
- "use strict";
3422
- }
3423
- });
3424
-
3425
- // shared/builtin-deps.ts
3426
- var CF_COMPAT_SPECIFIER, STATE_OBJECTS_SPECIFIER, CRYPTO_SPECIFIER, ROUTE_SPECIFIER, BUILTIN_DEPS, BUILTIN_DEPS_CSV;
3427
- var init_builtin_deps = __esm({
3428
- "shared/builtin-deps.ts"() {
3429
- "use strict";
3430
- CF_COMPAT_SPECIFIER = "@adep/cf-compat";
3431
- STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
3432
- CRYPTO_SPECIFIER = "@adep/crypto";
3433
- ROUTE_SPECIFIER = "@adep/runtime/route";
3434
- BUILTIN_DEPS = [
3435
- CF_COMPAT_SPECIFIER,
3436
- STATE_OBJECTS_SPECIFIER,
3437
- CRYPTO_SPECIFIER,
3438
- ROUTE_SPECIFIER,
3439
- "axios",
3440
- "lodash",
3441
- "dayjs",
3442
- "zod"
3443
- ];
3444
- BUILTIN_DEPS_CSV = BUILTIN_DEPS.join(",");
3445
- }
3446
- });
3447
-
3448
- // packages/cli/src/builtin-deps.ts
3449
- var LOCAL_BUILTIN_DEPS;
3450
- var init_builtin_deps2 = __esm({
3451
- "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"() {
3452
3423
  "use strict";
3453
- init_builtin_deps();
3454
- LOCAL_BUILTIN_DEPS = [
3455
- CF_COMPAT_SPECIFIER,
3456
- STATE_OBJECTS_SPECIFIER,
3457
- CRYPTO_SPECIFIER,
3458
- ROUTE_SPECIFIER
3459
- ];
3424
+ init_auth();
3425
+ init_credentials();
3426
+ init_dev();
3460
3427
  }
3461
3428
  });
3462
3429
 
3463
- // packages/cli/src/sim/boundary.ts
3464
- var SIM_BOUNDARIES;
3465
- var init_boundary = __esm({
3466
- "packages/cli/src/sim/boundary.ts"() {
3467
- "use strict";
3468
- SIM_BOUNDARIES = [
3469
- {
3470
- kind: "capability",
3471
- title: "\u89E6\u53D1\u5668\u4E0D\u81EA\u52A8\u6267\u884C",
3472
- 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"
3473
- },
3474
- {
3475
- kind: "diff",
3476
- title: "\u65E0\u8DE8\u5B9E\u4F8B\u5E7F\u64AD",
3477
- 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"
3478
- },
3479
- {
3480
- kind: "capability",
3481
- title: "publish \u4E0D\u652F\u6301 except",
3482
- 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"
3483
- },
3484
- {
3485
- kind: "capability",
3486
- title: "\u65E0\u9650\u989D\u7B49\u4EF7",
3487
- 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"
3488
- },
3489
- {
3490
- kind: "diff",
3491
- title: "\u4E0D\u8BA1\u91CF",
3492
- 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"
3493
- }
3494
- ];
3495
- }
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
3496
3443
  });
3497
-
3498
- // packages/cli/src/ts-config.ts
3499
- import { stat as stat6, readFile as readFile7 } from "node:fs/promises";
3500
- import { join as join10 } from "node:path";
3501
- async function loadAdepConfigModule(cwd) {
3502
- const configPath = join10(cwd, "adep.config.ts");
3503
- try {
3504
- await stat6(configPath);
3505
- } catch {
3506
- return null;
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" : " ";
3507
3543
  }
3508
- let rawDefault;
3509
- try {
3510
- const bun = globalThis.Bun;
3511
- if (bun !== void 0) {
3512
- const mod = await import(configPath);
3513
- rawDefault = mod.default;
3514
- } else {
3515
- const { transform } = await import("esbuild");
3516
- const source = await readFile7(configPath, "utf8");
3517
- const { code } = await transform(source, {
3518
- loader: "ts",
3519
- format: "esm",
3520
- target: "node22"
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
3521
3566
  });
3522
- const url = `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`;
3523
- const mod = await import(url);
3524
- rawDefault = mod.default;
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
+ };
3525
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
+ );
3526
3630
  } catch (error) {
3527
- const reason = error instanceof Error ? error.message : String(error);
3528
- const message = `adep.config.ts \u52A0\u8F7D\u5931\u8D25\uFF1A${reason}`;
3529
- process.stderr.write(`\u9519\u8BEF\uFF1A${message}
3530
- `);
3531
- throw new Error(message, { cause: 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
+ );
3532
3636
  }
3533
- const result = parseAdepConfig(rawDefault);
3534
- if (!result.ok) {
3535
- const message = `adep.config.ts \u6821\u9A8C\u5931\u8D25\uFF1A
3536
- ${result.errors.map((e) => ` - ${e}`).join("\n")}`;
3537
- process.stderr.write(`${message}
3538
- `);
3539
- throw new Error(message);
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`);
3540
3640
  }
3541
- return result.data;
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
+ };
3542
3670
  }
3543
- var init_ts_config = __esm({
3544
- "packages/cli/src/ts-config.ts"() {
3671
+ var NODE_SQLITE_MIN;
3672
+ var init_sqlite_driver = __esm({
3673
+ "packages/cli/src/serve/sqlite-driver.ts"() {
3545
3674
  "use strict";
3546
- init_adep_config();
3675
+ NODE_SQLITE_MIN = { major: 22, minor: 5 };
3547
3676
  }
3548
3677
  });
3549
3678
 
3550
- // packages/runtime/src/state-objects/runtime.ts
3551
- var StateObject, StateObjectError, StateObjectRuntime;
3552
- var init_runtime2 = __esm({
3553
- "packages/runtime/src/state-objects/runtime.ts"() {
3554
- "use strict";
3555
- StateObject = class {
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;
3982
+ if (bun !== void 0) {
3983
+ const mod = await import(configPath);
3984
+ rawDefault = mod.default;
3985
+ } else {
3986
+ const { transform } = await import("esbuild");
3987
+ const source = await readFile9(configPath, "utf8");
3988
+ const { code } = await transform(source, {
3989
+ loader: "ts",
3990
+ format: "esm",
3991
+ target: "node22"
3992
+ });
3993
+ const url = `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`;
3994
+ const mod = await import(url);
3995
+ rawDefault = mod.default;
3996
+ }
3997
+ } catch (error) {
3998
+ const reason = error instanceof Error ? error.message : String(error);
3999
+ const message = `adep.config.ts \u52A0\u8F7D\u5931\u8D25\uFF1A${reason}`;
4000
+ process.stderr.write(`\u9519\u8BEF\uFF1A${message}
4001
+ `);
4002
+ throw new Error(message, { cause: error });
4003
+ }
4004
+ const result = parseAdepConfig(rawDefault);
4005
+ if (!result.ok) {
4006
+ const message = `adep.config.ts \u6821\u9A8C\u5931\u8D25\uFF1A
4007
+ ${result.errors.map((e) => ` - ${e}`).join("\n")}`;
4008
+ process.stderr.write(`${message}
4009
+ `);
4010
+ throw new Error(message);
4011
+ }
4012
+ return result.data;
4013
+ }
4014
+ var init_ts_config = __esm({
4015
+ "packages/cli/src/ts-config.ts"() {
4016
+ "use strict";
4017
+ init_adep_config();
4018
+ }
4019
+ });
4020
+
4021
+ // packages/runtime/src/state-objects/runtime.ts
4022
+ var StateObject, StateObjectError, StateObjectRuntime;
4023
+ var init_runtime2 = __esm({
4024
+ "packages/runtime/src/state-objects/runtime.ts"() {
4025
+ "use strict";
4026
+ StateObject = class {
3556
4027
  id;
3557
4028
  /** 对象内存状态(单例驻留);load 时从后端恢复。 */
3558
4029
  state;
@@ -4461,7 +4932,7 @@ var init_chain = __esm({
4461
4932
  // packages/runtime/src/functions/runtime/worker-entry.ts
4462
4933
  import { parentPort, workerData } from "node:worker_threads";
4463
4934
  import { createRequire } from "node:module";
4464
- import { join as join11 } from "node:path";
4935
+ import { join as join12 } from "node:path";
4465
4936
  function isRpcCapability(value) {
4466
4937
  return typeof value === "object" && value !== null && value[RPC_CAPABILITY_KEY] === true;
4467
4938
  }
@@ -4510,7 +4981,7 @@ function errorMessageWithLocation(error, files) {
4510
4981
  }
4511
4982
  function createBareResolver(deps) {
4512
4983
  const platformRequire = createRequire(import.meta.url);
4513
- 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"));
4514
4985
  return (request) => {
4515
4986
  if (deps.builtin.includes(request)) return platformRequire(request);
4516
4987
  const root = splitBareSpecifier(request);
@@ -4701,8 +5172,8 @@ var init_shared_source = __esm({
4701
5172
  });
4702
5173
 
4703
5174
  // packages/cli/src/dev-shared.ts
4704
- import { readdir as readdir4, readFile as readFile8 } from "node:fs/promises";
4705
- 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";
4706
5177
  function bearerUserResolverFromEnv() {
4707
5178
  const raw = process.env.ADEP_AUTH_ISSUER;
4708
5179
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -4743,11 +5214,11 @@ async function collectFunctions(dir) {
4743
5214
  }
4744
5215
  for (const entry of entries) {
4745
5216
  const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
4746
- const full = join12(sub, entry.name);
5217
+ const full = join13(sub, entry.name);
4747
5218
  if (entry.isDirectory()) {
4748
5219
  await walk(full, rel);
4749
5220
  } else if (entry.isFile() && isRuntimeSource(entry.name)) {
4750
- files[rel] = await readFile8(full, "utf8");
5221
+ files[rel] = await readFile10(full, "utf8");
4751
5222
  }
4752
5223
  }
4753
5224
  };
@@ -4835,10 +5306,10 @@ __export(dev_exports, {
4835
5306
  });
4836
5307
  import { createServer } from "node:http";
4837
5308
  import { watch } from "node:fs";
4838
- import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile6 } from "node:fs/promises";
4839
- 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";
4840
5311
  async function loadConfig(cwd) {
4841
- const name = basename2(resolve4(cwd));
5312
+ const name = basename2(resolve7(cwd));
4842
5313
  const config = await loadAdepConfigModule(cwd);
4843
5314
  return {
4844
5315
  name: config?.name ?? name,
@@ -4880,34 +5351,49 @@ function printBoundaries(log) {
4880
5351
  }
4881
5352
  }
4882
5353
  async function ensureGitignore(cwd) {
4883
- const gitignorePath = join13(cwd, ".gitignore");
4884
- const existing = await readFile9(gitignorePath, "utf8").catch(() => "");
5354
+ const gitignorePath = join14(cwd, ".gitignore");
5355
+ const existing = await readFile11(gitignorePath, "utf8").catch(() => "");
4885
5356
  if (existing.split(/\r?\n/).includes(".adep/")) return;
4886
5357
  await writeFile6(gitignorePath, `${existing.replace(/\n+$/, "")}
4887
5358
  .adep/
4888
5359
  `, "utf8");
4889
5360
  }
4890
5361
  async function startDevServer(options) {
4891
- const cwd = resolve4(options.cwd);
5362
+ const cwd = resolve7(options.cwd);
4892
5363
  const log = options.log ?? ((line) => process.stdout.write(`${line}
4893
5364
  `));
4894
5365
  const config = await loadConfig(cwd);
4895
5366
  if (options.prefix !== void 0) {
4896
5367
  config.functionsPrefix = options.prefix.replace(/^\/+|\/+$/g, "");
4897
5368
  }
4898
- const functionsDir = join13(cwd, config.functionsDir);
5369
+ const functionsDir = join14(cwd, config.functionsDir);
4899
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
+ });
4900
5375
  const bearerUser = bearerUserResolverFromEnv();
4901
5376
  const executor = new WorkerFunctionExecutor({
4902
5377
  deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
4903
5378
  });
4904
- await mkdir7(functionsDir, { recursive: true });
5379
+ await mkdir8(functionsDir, { recursive: true });
5380
+ const db = await openLocalDbDriver(dbTarget, { cwd, tag: "adep", log });
4905
5381
  const runtime = await createSimRuntime({
4906
5382
  cwd,
4907
5383
  projectId: "local",
4908
5384
  baseUrl: `http://127.0.0.1:${options.port ?? 8787}`,
4909
- log
5385
+ log,
5386
+ ...db.driver === null ? {} : { driver: db.driver }
4910
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
+ }
4911
5397
  await ensureGitignore(cwd);
4912
5398
  let files = mergeSharedIntoFunctions(await collectFunctions(functionsDir));
4913
5399
  let env = {
@@ -4988,12 +5474,12 @@ async function startDevServer(options) {
4988
5474
  const reload = async () => {
4989
5475
  const [nextFiles, envText2] = await Promise.all([
4990
5476
  collectFunctions(functionsDir).then(mergeSharedIntoFunctions),
4991
- readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "")
5477
+ readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "")
4992
5478
  ]);
4993
5479
  files = nextFiles;
4994
5480
  env = { ...config.environment, ...parseEnvFile(envText2) };
4995
5481
  };
4996
- const envText = await readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "");
5482
+ const envText = await readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "");
4997
5483
  env = { ...config.environment, ...parseEnvFile(envText) };
4998
5484
  let debounceTimer;
4999
5485
  let watcher;
@@ -5024,431 +5510,175 @@ async function startDevServer(options) {
5024
5510
  invoke: invokeHandler
5025
5511
  },
5026
5512
  timeoutMs: 1e4,
5027
- ...hasEnv ? { env } : {}
5028
- };
5029
- };
5030
- const handle = async (req, res) => {
5031
- const url = new URL(req.url ?? "/", "http://127.0.0.1");
5032
- const { fnName, error: routeError } = resolveRouteFnName(url.pathname, config.functionsPrefix);
5033
- if (routeError !== void 0) {
5034
- writeJson(res, 400, { error: routeError });
5035
- return;
5036
- }
5037
- if (fnName === void 0) {
5038
- writeJson(res, 400, {
5039
- error: { code: "FN_NAME_REQUIRED", message: "\u4EE5 /{fnName} \u8C03\u7528\u672C\u5730\u51FD\u6570" }
5040
- });
5041
- return;
5042
- }
5043
- if (fnName === "state") {
5044
- const normalizedPrefix = config.functionsPrefix.replace(/^\/+|\/+$/g, "");
5045
- const rest = normalizedPrefix.length === 0 ? url.pathname : url.pathname.replace(new RegExp(`^/${normalizedPrefix}`), "");
5046
- const parsed = parseStatePath(rest);
5047
- if (parsed === null) {
5048
- writeJson(res, 400, {
5049
- error: { code: "STATE_BAD_PATH", message: "\u72B6\u6001\u5BF9\u8C61\u8DEF\u5F84\uFF1A/api/state/:type/:id/:method" }
5050
- });
5051
- return;
5052
- }
5053
- const rawBody = await bodyOf(req);
5054
- const parsedBody = parseStateBody(
5055
- req.method === "GET" || req.method === "HEAD" ? null : rawBody === void 0 ? null : typeof rawBody === "string" ? rawBody : JSON.stringify(rawBody)
5056
- );
5057
- if ("error" in parsedBody) {
5058
- writeJson(res, 400, { error: { code: "STATE_BAD_ARGS", message: parsedBody.error } });
5059
- return;
5060
- }
5061
- try {
5062
- const result = await refreshStateRuntime().invoke(
5063
- parsed.type,
5064
- parsed.id,
5065
- parsed.method,
5066
- parsedBody.args
5067
- );
5068
- writeJson(res, 200, { ok: true, data: result });
5069
- } catch (error) {
5070
- if (error instanceof StateObjectError) {
5071
- writeJson(res, error.code === "STATE_TYPE_NOT_REGISTERED" ? 404 : 400, {
5072
- error: { code: error.code, message: error.message }
5073
- });
5074
- return;
5075
- }
5076
- writeJson(res, 500, { error: { code: "STATE_INVOKE_ERROR", message: String(error) } });
5077
- }
5078
- return;
5079
- }
5080
- const entry = resolveFunctionEntry(files, fnName);
5081
- if (entry === void 0) {
5082
- log(`[adep] ${req.method ?? "GET"} /${fnName} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
5083
- writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
5084
- return;
5085
- }
5086
- const input = await buildInput(fnName, entry, url, req);
5087
- const startedAt = performance.now();
5088
- try {
5089
- const result = await executor.execute(input);
5090
- const durationMs = Math.round(performance.now() - startedAt);
5091
- for (const line of result.logs) log(`[adep] ${line}`);
5092
- if (isAdepHttpEnvelope(result.body)) {
5093
- log(
5094
- `[adep] ${req.method ?? "GET"} /${fnName} -> ${result.body.__adepHttp.status} ${durationMs}ms`
5095
- );
5096
- writeEnvelopeResponse(res, result.body);
5097
- return;
5098
- }
5099
- log(`[adep] ${req.method ?? "GET"} /${fnName} -> 200 ${durationMs}ms`);
5100
- writeJson(res, 200, result.body === void 0 ? null : result.body);
5101
- } catch (error) {
5102
- const durationMs = Math.round(performance.now() - startedAt);
5103
- if (error instanceof ExecutorError) {
5104
- log(
5105
- `[adep] ${req.method ?? "GET"} /${fnName} -> ${error.status} ${durationMs}ms (${error.code})`
5106
- );
5107
- writeJson(res, error.status, { error: { code: error.code, message: error.message } });
5108
- return;
5109
- }
5110
- log(`[adep] ${req.method ?? "GET"} /${fnName} -> 500 ${durationMs}ms`);
5111
- writeJson(res, 500, {
5112
- error: {
5113
- code: "FN_EXEC_ERROR",
5114
- message: error instanceof Error ? error.message : "\u51FD\u6570\u6267\u884C\u5931\u8D25"
5115
- }
5116
- });
5117
- }
5118
- };
5119
- const server = createServer((req, res) => {
5120
- void handle(req, res);
5121
- });
5122
- const port = options.port ?? 8787;
5123
- const disposeAfterListenError = async () => {
5124
- if (debounceTimer !== void 0) clearTimeout(debounceTimer);
5125
- try {
5126
- watcher?.close();
5127
- } catch {
5128
- }
5129
- try {
5130
- await executor.dispose();
5131
- } catch {
5132
- }
5133
- try {
5134
- await runtime.dispose();
5135
- } catch {
5136
- }
5137
- };
5138
- await new Promise((resolveListen, rejectListen) => {
5139
- const onListenError = (error) => {
5140
- void disposeAfterListenError().finally(() => rejectListen(error));
5141
- };
5142
- server.once("error", onListenError);
5143
- server.listen(port, "127.0.0.1", () => {
5144
- server.off("error", onListenError);
5145
- resolveListen();
5146
- });
5147
- });
5148
- const address = server.address();
5149
- const actualPort = typeof address === "object" && address !== null ? address.port : port;
5150
- const baseUrl = `http://127.0.0.1:${actualPort}`;
5151
- const coldStartMs = Date.now() - coldStartAt;
5152
- const curlPath = config.functionsPrefix.length === 0 ? "/hello" : `/${config.functionsPrefix}/hello`;
5153
- log(`[adep] dev server listening on ${baseUrl}\uFF08\u6A21\u62DF\u8FD0\u884C\u65F6\uFF0C\u51B7\u542F\u52A8 ${coldStartMs}ms\uFF09`);
5154
- log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
5155
- printBoundaries(log);
5156
- if (bearerUser !== void 0) {
5157
- 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`);
5158
- }
5159
- log(`[adep] \u6A21\u62DF\u6570\u636E\u76EE\u5F55\uFF1A${simDir(cwd)}`);
5160
- startStateAlarmScheduler();
5161
- return {
5162
- port: actualPort,
5163
- baseUrl,
5164
- close: async () => {
5165
- stopStateAlarmScheduler();
5166
- if (debounceTimer !== void 0) clearTimeout(debounceTimer);
5167
- watcher?.close();
5168
- await new Promise((resolveClose) => server.close(() => resolveClose()));
5169
- await executor.dispose();
5170
- await runtime.dispose();
5171
- }
5172
- };
5173
- }
5174
- var parseEnvFile;
5175
- var init_dev = __esm({
5176
- "packages/cli/src/dev.ts"() {
5177
- "use strict";
5178
- init_executor();
5179
- init_http_envelope();
5180
- init_worker_executor();
5181
- init_runtime();
5182
- init_env();
5183
- init_invoke();
5184
- init_builtin_deps2();
5185
- init_boundary();
5186
- init_ts_config();
5187
- init_state_objects();
5188
- init_worker_entry();
5189
- init_dev_shared();
5190
- parseEnvFile = parseEnv;
5191
- }
5192
- });
5193
-
5194
- // packages/cli/src/client.ts
5195
- var client_exports = {};
5196
- __export(client_exports, {
5197
- createClient: () => createClient,
5198
- resolveSlug: () => resolveSlug
5199
- });
5200
- async function envelopeError(response, fallbackCode, parsed) {
5201
- const payload = parsed ?? null;
5202
- return new CliError(
5203
- payload?.error?.code ?? fallbackCode,
5204
- payload?.error?.message ?? `\u5E73\u53F0\u8FD4\u56DE HTTP ${response.status}`
5205
- );
5206
- }
5207
- async function parseBody(response) {
5208
- const text = await response.text();
5209
- if (text.length === 0) return null;
5210
- try {
5211
- return JSON.parse(text);
5212
- } catch {
5213
- return null;
5214
- }
5215
- }
5216
- async function createClient(paths) {
5217
- const credentials = await loadCredentials(paths);
5218
- if (credentials === null) {
5219
- throw new CliError("NOT_LOGGED_IN", "\u672A\u767B\u5F55\uFF1A\u8BF7\u5148\u6267\u884C adep login");
5220
- }
5221
- const server = credentials.server;
5222
- const cookie = sessionCookieHeader(credentials);
5223
- const request = async (path, init = {}, fallbackCode = "API_REQUEST_FAILED") => {
5224
- const method = init.method ?? (init.body === void 0 ? "GET" : "POST");
5225
- let response;
5226
- try {
5227
- response = await fetch(`${server}${path}`, {
5228
- method,
5229
- headers: { "content-type": "application/json", cookie },
5230
- ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) }
5231
- });
5232
- } catch (error) {
5233
- throw new CliError(
5234
- "SERVER_UNREACHABLE",
5235
- `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
5236
- );
5237
- }
5238
- const parsed = await parseBody(response);
5239
- if (response.status < 200 || response.status >= 300) {
5240
- throw await envelopeError(response, fallbackCode, parsed);
5241
- }
5242
- return parsed;
5513
+ ...hasEnv ? { env } : {}
5514
+ };
5243
5515
  };
5244
- const upload = async (path, form, fallbackCode = "UPLOAD_FAILED") => {
5245
- let response;
5246
- try {
5247
- response = await fetch(`${server}${path}`, {
5248
- method: "POST",
5249
- headers: { cookie },
5250
- body: form
5251
- });
5252
- } catch (error) {
5253
- throw new CliError(
5254
- "SERVER_UNREACHABLE",
5255
- `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
5256
- );
5516
+ const handle = async (req, res) => {
5517
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
5518
+ const { fnName, error: routeError } = resolveRouteFnName(url.pathname, config.functionsPrefix);
5519
+ if (routeError !== void 0) {
5520
+ writeJson(res, 400, { error: routeError });
5521
+ return;
5257
5522
  }
5258
- if (response.status < 200 || response.status >= 300) {
5259
- throw await envelopeError(response, fallbackCode, await parseBody(response));
5523
+ if (fnName === void 0) {
5524
+ writeJson(res, 400, {
5525
+ error: { code: "FN_NAME_REQUIRED", message: "\u4EE5 /{fnName} \u8C03\u7528\u672C\u5730\u51FD\u6570" }
5526
+ });
5527
+ return;
5260
5528
  }
5261
- return response;
5262
- };
5263
- const download = async (url, fallbackCode = "DOWNLOAD_FAILED") => {
5264
- const target = url.startsWith("http") ? url : `${server}${url}`;
5265
- let response;
5266
- try {
5267
- response = await fetch(target, { headers: { cookie } });
5268
- } catch (error) {
5269
- throw new CliError(
5270
- "SERVER_UNREACHABLE",
5271
- `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
5529
+ if (fnName === "state") {
5530
+ const normalizedPrefix = config.functionsPrefix.replace(/^\/+|\/+$/g, "");
5531
+ const rest = normalizedPrefix.length === 0 ? url.pathname : url.pathname.replace(new RegExp(`^/${normalizedPrefix}`), "");
5532
+ const parsed = parseStatePath(rest);
5533
+ if (parsed === null) {
5534
+ writeJson(res, 400, {
5535
+ error: { code: "STATE_BAD_PATH", message: "\u72B6\u6001\u5BF9\u8C61\u8DEF\u5F84\uFF1A/api/state/:type/:id/:method" }
5536
+ });
5537
+ return;
5538
+ }
5539
+ const rawBody = await bodyOf(req);
5540
+ const parsedBody = parseStateBody(
5541
+ req.method === "GET" || req.method === "HEAD" ? null : rawBody === void 0 ? null : typeof rawBody === "string" ? rawBody : JSON.stringify(rawBody)
5272
5542
  );
5273
- }
5274
- if (response.status < 200 || response.status >= 300) {
5275
- throw await envelopeError(response, fallbackCode, await parseBody(response));
5276
- }
5277
- return response;
5278
- };
5279
- return { server, cookie, request, upload, download };
5280
- }
5281
- async function resolveSlug(cwd, slug) {
5282
- if (slug !== void 0 && slug.length > 0) return slug;
5283
- const config = await loadConfig(cwd);
5284
- return config.name;
5285
- }
5286
- var init_client = __esm({
5287
- "packages/cli/src/client.ts"() {
5288
- "use strict";
5289
- init_auth();
5290
- init_credentials();
5291
- init_dev();
5292
- }
5293
- });
5294
-
5295
- // packages/cli/src/db.ts
5296
- var db_exports = {};
5297
- __export(db_exports, {
5298
- dbExec: () => dbExec,
5299
- dbMigrate: () => dbMigrate,
5300
- dbRollback: () => dbRollback,
5301
- dbSnapshotCreate: () => dbSnapshotCreate,
5302
- dbSnapshotList: () => dbSnapshotList,
5303
- dbSnapshotRestore: () => dbSnapshotRestore,
5304
- dbStart: () => dbStart,
5305
- dbStatus: () => dbStatus,
5306
- dbStop: () => dbStop,
5307
- splitSqlStatements: () => splitSqlStatements
5308
- });
5309
- import { readFile as readFile10 } from "node:fs/promises";
5310
- import { resolve as resolve5 } from "node:path";
5311
- async function open2(paths, options) {
5312
- const client = await createClient(paths);
5313
- const project2 = await resolveSlug(resolve5(options.cwd), options.slug);
5314
- return { client, project: project2 };
5315
- }
5316
- async function dbStart(paths, options) {
5317
- const { client, project: project2 } = await open2(paths, options);
5318
- return client.request(`/api/v1/projects/${project2}/database`, { method: "POST" });
5319
- }
5320
- async function dbStatus(paths, options) {
5321
- const { client, project: project2 } = await open2(paths, options);
5322
- return client.request(`/api/v1/projects/${project2}/database`);
5323
- }
5324
- async function dbStop(paths, options) {
5325
- const { client, project: project2 } = await open2(paths, options);
5326
- return client.request(`/api/v1/projects/${project2}/database`, {
5327
- method: "DELETE"
5328
- });
5329
- }
5330
- async function dbExec(paths, options) {
5331
- const { client, project: project2 } = await open2(paths, options);
5332
- return client.request(
5333
- `/api/v1/projects/${project2}/database/console/sql`,
5334
- {
5335
- method: "POST",
5336
- body: {
5337
- sql: options.sql,
5338
- ...options.params === void 0 ? {} : { params: options.params },
5339
- ...options.confirmTable === void 0 ? {} : { confirmTable: options.confirmTable }
5543
+ if ("error" in parsedBody) {
5544
+ writeJson(res, 400, { error: { code: "STATE_BAD_ARGS", message: parsedBody.error } });
5545
+ return;
5340
5546
  }
5341
- },
5342
- "SQL_EXEC_FAILED"
5343
- );
5344
- }
5345
- async function dbSnapshotList(paths, options) {
5346
- const { client, project: project2 } = await open2(paths, options);
5347
- return client.request(
5348
- `/api/v1/projects/${project2}/database/snapshots`
5349
- );
5350
- }
5351
- async function dbSnapshotCreate(paths, options) {
5352
- const { client, project: project2 } = await open2(paths, options);
5353
- return client.request(`/api/v1/projects/${project2}/database/snapshots`, {
5354
- method: "POST"
5355
- });
5356
- }
5357
- async function dbSnapshotRestore(paths, options) {
5358
- const { client, project: project2 } = await open2(paths, options);
5359
- return client.request(
5360
- `/api/v1/projects/${project2}/database/snapshots/${options.snapshotId}/restore`,
5361
- { method: "POST" }
5362
- );
5363
- }
5364
- async function dbRollback(paths, options) {
5365
- const { client, project: project2 } = await open2(paths, options);
5366
- return client.request(
5367
- `/api/v1/projects/${project2}/database/rollback`,
5368
- { method: "POST", body: { to: options.to } }
5369
- );
5370
- }
5371
- function splitSqlStatements(source) {
5372
- const statements = [];
5373
- let buffer = "";
5374
- let inQuote = false;
5375
- const lines = source.split("\n");
5376
- for (const rawLine of lines) {
5377
- const trimmed = rawLine.trim();
5378
- if (!inQuote && (trimmed.length === 0 || trimmed.startsWith("--"))) continue;
5379
- for (let i = 0; i < rawLine.length; i++) {
5380
- const ch = rawLine[i];
5381
- if (inQuote) {
5382
- if (ch === "'") {
5383
- if (rawLine[i + 1] === "'") {
5384
- buffer += ch + rawLine[i + 1];
5385
- i++;
5386
- continue;
5387
- }
5388
- inQuote = false;
5547
+ try {
5548
+ const result = await refreshStateRuntime().invoke(
5549
+ parsed.type,
5550
+ parsed.id,
5551
+ parsed.method,
5552
+ parsedBody.args
5553
+ );
5554
+ writeJson(res, 200, { ok: true, data: result });
5555
+ } catch (error) {
5556
+ if (error instanceof StateObjectError) {
5557
+ writeJson(res, error.code === "STATE_TYPE_NOT_REGISTERED" ? 404 : 400, {
5558
+ error: { code: error.code, message: error.message }
5559
+ });
5560
+ return;
5389
5561
  }
5390
- buffer += ch;
5391
- continue;
5562
+ writeJson(res, 500, { error: { code: "STATE_INVOKE_ERROR", message: String(error) } });
5392
5563
  }
5393
- if (ch === "'") {
5394
- inQuote = true;
5395
- buffer += ch;
5396
- continue;
5564
+ return;
5565
+ }
5566
+ const entry = resolveFunctionEntry(files, fnName);
5567
+ if (entry === void 0) {
5568
+ log(`[adep] ${req.method ?? "GET"} /${fnName} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
5569
+ writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
5570
+ return;
5571
+ }
5572
+ const input = await buildInput(fnName, entry, url, req);
5573
+ const startedAt = performance.now();
5574
+ try {
5575
+ const result = await executor.execute(input);
5576
+ const durationMs = Math.round(performance.now() - startedAt);
5577
+ for (const line of result.logs) log(`[adep] ${line}`);
5578
+ if (isAdepHttpEnvelope(result.body)) {
5579
+ log(
5580
+ `[adep] ${req.method ?? "GET"} /${fnName} -> ${result.body.__adepHttp.status} ${durationMs}ms`
5581
+ );
5582
+ writeEnvelopeResponse(res, result.body);
5583
+ return;
5397
5584
  }
5398
- if (ch === "-" && rawLine[i + 1] === "-") break;
5399
- if (ch === ";") {
5400
- const statement = buffer.trim();
5401
- if (statement.length > 0) statements.push(statement);
5402
- buffer = "";
5403
- continue;
5585
+ log(`[adep] ${req.method ?? "GET"} /${fnName} -> 200 ${durationMs}ms`);
5586
+ writeJson(res, 200, result.body === void 0 ? null : result.body);
5587
+ } catch (error) {
5588
+ const durationMs = Math.round(performance.now() - startedAt);
5589
+ if (error instanceof ExecutorError) {
5590
+ log(
5591
+ `[adep] ${req.method ?? "GET"} /${fnName} -> ${error.status} ${durationMs}ms (${error.code})`
5592
+ );
5593
+ writeJson(res, error.status, { error: { code: error.code, message: error.message } });
5594
+ return;
5404
5595
  }
5405
- buffer += ch;
5596
+ log(`[adep] ${req.method ?? "GET"} /${fnName} -> 500 ${durationMs}ms`);
5597
+ writeJson(res, 500, {
5598
+ error: {
5599
+ code: "FN_EXEC_ERROR",
5600
+ message: error instanceof Error ? error.message : "\u51FD\u6570\u6267\u884C\u5931\u8D25"
5601
+ }
5602
+ });
5406
5603
  }
5407
- buffer += inQuote ? "\n" : " ";
5408
- }
5409
- if (inQuote) {
5410
- throw new Error(`SQL \u8FC1\u79FB\u6587\u4EF6\u5F15\u53F7\u672A\u95ED\u5408\uFF1A${buffer.trim().slice(0, 80)}\u2026`);
5411
- }
5412
- const tail = buffer.trim();
5413
- if (tail.length > 0) statements.push(tail);
5414
- return statements;
5415
- }
5416
- async function dbMigrate(paths, options) {
5417
- const source = await readFile10(resolve5(options.file), "utf8");
5418
- const statements = splitSqlStatements(source);
5419
- if (statements.length === 0) {
5420
- throw new Error(`\u8FC1\u79FB\u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${options.file}`);
5421
- }
5422
- const { project: project2 } = await open2(paths, options);
5423
- const applied = [];
5424
- const changes = [];
5425
- for (const statement of statements) {
5604
+ };
5605
+ const server = createServer((req, res) => {
5606
+ void handle(req, res);
5607
+ });
5608
+ const port = options.port ?? 8787;
5609
+ const disposeAfterListenError = async () => {
5610
+ if (debounceTimer !== void 0) clearTimeout(debounceTimer);
5426
5611
  try {
5427
- const result = await dbExec(paths, {
5428
- cwd: options.cwd,
5429
- ...options.slug === void 0 ? {} : { slug: options.slug },
5430
- sql: statement
5431
- });
5432
- applied.push(statement);
5433
- changes.push(result.changes);
5434
- } catch (error) {
5435
- const code = error instanceof CliError ? error.code : "MIGRATE_FAILED";
5436
- const message = error instanceof Error ? error.message : String(error);
5437
- return {
5438
- projectId: project2,
5439
- applied,
5440
- changes,
5441
- failed: { statement, code, message }
5442
- };
5612
+ watcher?.close();
5613
+ } catch {
5614
+ }
5615
+ try {
5616
+ await executor.dispose();
5617
+ } catch {
5618
+ }
5619
+ try {
5620
+ await runtime.dispose();
5621
+ } catch {
5443
5622
  }
5623
+ };
5624
+ await new Promise((resolveListen, rejectListen) => {
5625
+ const onListenError = (error) => {
5626
+ void disposeAfterListenError().finally(() => rejectListen(error));
5627
+ };
5628
+ server.once("error", onListenError);
5629
+ server.listen(port, "127.0.0.1", () => {
5630
+ server.off("error", onListenError);
5631
+ resolveListen();
5632
+ });
5633
+ });
5634
+ const address = server.address();
5635
+ const actualPort = typeof address === "object" && address !== null ? address.port : port;
5636
+ const baseUrl = `http://127.0.0.1:${actualPort}`;
5637
+ const coldStartMs = Date.now() - coldStartAt;
5638
+ const curlPath = config.functionsPrefix.length === 0 ? "/hello" : `/${config.functionsPrefix}/hello`;
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
+ );
5644
+ log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
5645
+ printBoundaries(log);
5646
+ if (bearerUser !== void 0) {
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`);
5444
5648
  }
5445
- return { projectId: project2, applied, changes };
5649
+ log(`[adep] \u6570\u636E\u5E93\uFF1A${dbLabel} \u2192 ${dbTargetText}`);
5650
+ startStateAlarmScheduler();
5651
+ return {
5652
+ port: actualPort,
5653
+ baseUrl,
5654
+ close: async () => {
5655
+ stopStateAlarmScheduler();
5656
+ if (debounceTimer !== void 0) clearTimeout(debounceTimer);
5657
+ watcher?.close();
5658
+ await new Promise((resolveClose) => server.close(() => resolveClose()));
5659
+ await executor.dispose();
5660
+ await runtime.dispose();
5661
+ }
5662
+ };
5446
5663
  }
5447
- var init_db2 = __esm({
5448
- "packages/cli/src/db.ts"() {
5664
+ var parseEnvFile;
5665
+ var init_dev = __esm({
5666
+ "packages/cli/src/dev.ts"() {
5449
5667
  "use strict";
5450
- init_auth();
5451
- init_client();
5668
+ init_executor();
5669
+ init_http_envelope();
5670
+ init_worker_executor();
5671
+ init_runtime();
5672
+ init_db_mode();
5673
+ init_env();
5674
+ init_invoke();
5675
+ init_builtin_deps2();
5676
+ init_boundary();
5677
+ init_ts_config();
5678
+ init_state_objects();
5679
+ init_worker_entry();
5680
+ init_dev_shared();
5681
+ parseEnvFile = parseEnv;
5452
5682
  }
5453
5683
  });
5454
5684
 
@@ -5520,135 +5750,6 @@ var init_banner = __esm({
5520
5750
  }
5521
5751
  });
5522
5752
 
5523
- // packages/cli/src/serve/db-mode.ts
5524
- import { resolve as resolve6 } from "node:path";
5525
- function isServeDbMode(value) {
5526
- return SERVE_DB_MODES.includes(value.trim().toLowerCase());
5527
- }
5528
- function parseServeDbMode(raw, source) {
5529
- const value = raw.trim().toLowerCase();
5530
- if (!isServeDbMode(value)) {
5531
- throw new Error(
5532
- `${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`
5533
- );
5534
- }
5535
- return value;
5536
- }
5537
- function resolveServeDbMode(explicit) {
5538
- if (explicit !== void 0) return parseServeDbMode(explicit, "--db");
5539
- const fromEnv = process.env["ADEP_SERVE_DB"];
5540
- if (fromEnv !== void 0 && fromEnv.trim() !== "") {
5541
- return parseServeDbMode(fromEnv, "ADEP_SERVE_DB");
5542
- }
5543
- return DEFAULT_SERVE_DB_MODE;
5544
- }
5545
- function resolveServeDbFile(cwd, explicit) {
5546
- const raw = explicit ?? envDbFile() ?? DEFAULT_SQLITE_DB_FILE;
5547
- return raw === ":memory:" ? raw : resolve6(cwd, raw);
5548
- }
5549
- function envDbFile() {
5550
- const raw = process.env["ADEP_SERVE_DB_FILE"];
5551
- return raw === void 0 || raw.trim() === "" ? void 0 : raw.trim();
5552
- }
5553
- var SERVE_DB_MODES, DEFAULT_SERVE_DB_MODE, DEFAULT_SQLITE_DB_FILE;
5554
- var init_db_mode = __esm({
5555
- "packages/cli/src/serve/db-mode.ts"() {
5556
- "use strict";
5557
- SERVE_DB_MODES = ["sim", "sqlite"];
5558
- DEFAULT_SERVE_DB_MODE = "sqlite";
5559
- DEFAULT_SQLITE_DB_FILE = ".adep/data/project.sqlite";
5560
- }
5561
- });
5562
-
5563
- // packages/cli/src/serve/sqlite-driver.ts
5564
- import { mkdir as mkdir8 } from "node:fs/promises";
5565
- import { dirname as dirname8, resolve as resolve7 } from "node:path";
5566
- function isBun(versions) {
5567
- return versions["bun"] !== void 0 && versions["bun"] !== "";
5568
- }
5569
- function detectSqliteRuntime(versions = process.versions) {
5570
- if (isBun(versions)) return "bun";
5571
- const raw = versions["node"];
5572
- if (raw === void 0) return null;
5573
- const [majorText, minorText] = raw.split(".");
5574
- const major = Number(majorText);
5575
- const minor = Number(minorText ?? "0");
5576
- if (!Number.isInteger(major) || !Number.isInteger(minor)) return null;
5577
- if (major > NODE_SQLITE_MIN.major) return "node";
5578
- if (major === NODE_SQLITE_MIN.major && minor >= NODE_SQLITE_MIN.minor) return "node";
5579
- return null;
5580
- }
5581
- function sqliteModuleName(runtime) {
5582
- return runtime === "bun" ? "bun:sqlite" : "node:sqlite";
5583
- }
5584
- function sqliteUnavailableReason(versions = process.versions) {
5585
- const current = isBun(versions) ? `Bun ${versions["bun"] ?? ""}`.trim() : `Node ${versions["node"] ?? "\u672A\u77E5"}`;
5586
- 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`;
5587
- }
5588
- function sqliteRuntimeRequirementMessage(versions = process.versions) {
5589
- 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`;
5590
- }
5591
- async function openSqliteProjectDriver(file, options = {}) {
5592
- const runtime = options.runtime ?? detectSqliteRuntime();
5593
- if (runtime === null) throw new Error(sqliteRuntimeRequirementMessage());
5594
- const moduleName = sqliteModuleName(runtime);
5595
- const ctorName = runtime === "bun" ? "Database" : "DatabaseSync";
5596
- let mod;
5597
- try {
5598
- const specifier = moduleName;
5599
- mod = await import(
5600
- /* @vite-ignore */
5601
- specifier
5602
- );
5603
- } catch (error) {
5604
- throw new Error(
5605
- `${sqliteRuntimeRequirementMessage()}
5606
- \uFF08\u8F7D\u5165 ${moduleName} \u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}\uFF09`,
5607
- { cause: error }
5608
- );
5609
- }
5610
- const Ctor = mod[ctorName];
5611
- if (Ctor === void 0) {
5612
- throw new Error(`${moduleName} \u672A\u5BFC\u51FA ${ctorName}\uFF1A\u5F53\u524D\u8FD0\u884C\u65F6\u7684 SQLite \u5185\u5EFA\u6A21\u5757\u4E0D\u53EF\u7528`);
5613
- }
5614
- const target = file === ":memory:" ? file : resolve7(file);
5615
- if (target !== ":memory:") await mkdir8(dirname8(target), { recursive: true });
5616
- const database = new Ctor(target);
5617
- database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
5618
- return {
5619
- engine: "sqlite",
5620
- async run(sql, params = []) {
5621
- if (params.length === 0) {
5622
- database.exec(sql);
5623
- return { changes: 0 };
5624
- }
5625
- const result = database.prepare(sql).run(...params);
5626
- return { changes: Number(result.changes) };
5627
- },
5628
- async all(sql, params = []) {
5629
- const statement = database.prepare(sql);
5630
- statement.setReturnArrays?.(false);
5631
- return statement.all(...params);
5632
- },
5633
- async get(sql, params = []) {
5634
- const statement = database.prepare(sql);
5635
- statement.setReturnArrays?.(false);
5636
- const row = statement.get(...params);
5637
- return row ?? null;
5638
- },
5639
- async close() {
5640
- database.close();
5641
- }
5642
- };
5643
- }
5644
- var NODE_SQLITE_MIN;
5645
- var init_sqlite_driver = __esm({
5646
- "packages/cli/src/serve/sqlite-driver.ts"() {
5647
- "use strict";
5648
- NODE_SQLITE_MIN = { major: 22, minor: 5 };
5649
- }
5650
- });
5651
-
5652
5753
  // packages/cli/src/serve/server.ts
5653
5754
  var server_exports = {};
5654
5755
  __export(server_exports, {
@@ -5658,8 +5759,8 @@ __export(server_exports, {
5658
5759
  });
5659
5760
  import { createServer as createServer2 } from "node:http";
5660
5761
  import { watch as watch2 } from "node:fs";
5661
- import { mkdir as mkdir9, readFile as readFile11, stat as stat7 } from "node:fs/promises";
5662
- 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";
5663
5764
  function envNumber(name) {
5664
5765
  const raw = process.env[name];
5665
5766
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -5677,11 +5778,6 @@ function contentTypeFor(path) {
5677
5778
  const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
5678
5779
  return MIME_TYPES[ext] ?? "application/octet-stream";
5679
5780
  }
5680
- function displayPath(cwd, target) {
5681
- if (target === ":memory:") return target;
5682
- const rel = relative2(cwd, target);
5683
- return rel.startsWith("..") ? target : rel;
5684
- }
5685
5781
  async function startServeServer(options) {
5686
5782
  const cwd = resolve8(options.cwd);
5687
5783
  const log = options.log ?? ((line) => process.stdout.write(`${line}
@@ -5692,10 +5788,12 @@ async function startServeServer(options) {
5692
5788
  cwd,
5693
5789
  options.staticDir ?? envString("ADEP_SERVE_STATIC_DIR") ?? "public"
5694
5790
  );
5695
- let dbMode = resolveServeDbMode(options.db);
5696
- 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
+ });
5697
5795
  const config = await loadConfig(cwd);
5698
- const functionsDir = join14(cwd, config.functionsDir);
5796
+ const functionsDir = join15(cwd, config.functionsDir);
5699
5797
  const bearerUser = bearerUserResolverFromEnv();
5700
5798
  let hasStatic = false;
5701
5799
  try {
@@ -5707,76 +5805,28 @@ async function startServeServer(options) {
5707
5805
  const loadFunctionFiles = async () => mergeSharedIntoFunctions(await collectFunctions(functionsDir));
5708
5806
  let files = await loadFunctionFiles();
5709
5807
  let functionNames = listFunctionNames(files);
5710
- const envText = await readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "");
5808
+ const envText = await readFile12(join15(cwd, ".env.local"), "utf8").catch(() => "");
5711
5809
  let env = parseEnvFile(envText);
5712
5810
  let simEnv = await loadSimEnv(cwd).catch(() => ({}));
5713
- let sqliteModule = null;
5714
- let sqliteDriver = null;
5715
- if (sqliteFile !== null) {
5716
- const runtimeName = detectSqliteRuntime();
5717
- if (runtimeName === null) {
5718
- log(
5719
- `[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`
5720
- );
5721
- dbMode = "sim";
5722
- sqliteFile = null;
5723
- } else {
5724
- sqliteModule = sqliteModuleName(runtimeName);
5725
- try {
5726
- sqliteDriver = await openSqliteProjectDriver(sqliteFile, { runtime: runtimeName });
5727
- } catch (error) {
5728
- const detail = error instanceof Error ? error.message : String(error);
5729
- log(
5730
- `[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`
5731
- );
5732
- sqliteModule = null;
5733
- sqliteDriver = null;
5734
- sqliteFile = null;
5735
- dbMode = "sim";
5736
- }
5737
- }
5738
- }
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;
5739
5815
  const runtime = await createSimRuntime({
5740
5816
  cwd,
5741
5817
  projectId: "local",
5742
5818
  baseUrl: `http://${host}:${port}`,
5743
5819
  log,
5744
- ...sqliteDriver === null ? {} : { driver: sqliteDriver }
5820
+ ...db.driver === null ? {} : { driver: db.driver }
5745
5821
  });
5746
5822
  if (options.schemaFile !== void 0) {
5747
- const schemaPath = resolve8(cwd, options.schemaFile);
5748
- const schemaSource = await readFile11(schemaPath, "utf8").catch(
5749
- (error) => {
5750
- if (error.code === "ENOENT") {
5751
- throw new Error(`schema \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${schemaPath}`);
5752
- }
5753
- throw error;
5754
- }
5755
- );
5756
- const statements = splitSqlStatements(schemaSource);
5757
- let applied = 0;
5758
- let skipped = 0;
5759
- for (const [index, statement] of statements.entries()) {
5760
- try {
5761
- await runtime.db.driver.run(statement);
5762
- applied += 1;
5763
- } catch (error) {
5764
- const isUnsupported = error instanceof Error && "code" in error && error.code === "DB_UNSAFE_OP";
5765
- if (dbMode === "sim" && isUnsupported) {
5766
- skipped += 1;
5767
- log(`[serve] \u8DF3\u8FC7 schema \u8BED\u53E5\uFF08sim \u5F15\u64CE\u4E0D\u652F\u6301\uFF09\uFF1A${statement.slice(0, 60)}\u2026`);
5768
- continue;
5769
- }
5770
- const detail = error instanceof Error ? error.message : String(error);
5771
- throw new Error(
5772
- `schema \u8BED\u53E5\u6267\u884C\u5931\u8D25\uFF08--schema ${options.schemaFile}\uFF0C\u7B2C ${index + 1} \u6761\uFF0Cdb \u6A21\u5F0F ${dbMode}\uFF09\uFF1A${detail}
5773
- \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" : ""),
5774
- { cause: error }
5775
- );
5776
- }
5777
- }
5778
- const skipNote = skipped > 0 ? `\uFF0C\u8DF3\u8FC7 ${skipped} \u6761` : "";
5779
- 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
+ });
5780
5830
  }
5781
5831
  const executor = new WorkerFunctionExecutor({
5782
5832
  deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
@@ -5788,7 +5838,7 @@ async function startServeServer(options) {
5788
5838
  const reload = async () => {
5789
5839
  const [nextFiles, envLocalText] = await Promise.all([
5790
5840
  loadFunctionFiles(),
5791
- readFile11(join14(cwd, ".env.local"), "utf8").catch(() => "")
5841
+ readFile12(join15(cwd, ".env.local"), "utf8").catch(() => "")
5792
5842
  ]);
5793
5843
  files = nextFiles;
5794
5844
  env = parseEnvFile(envLocalText);
@@ -5843,16 +5893,16 @@ async function startServeServer(options) {
5843
5893
  const serveStatic = async (pathname, res) => {
5844
5894
  if (!hasStatic) return false;
5845
5895
  const safePath = pathname.replace(/\.\.\//g, "").replace(/^\//, "");
5846
- const filePath = join14(staticDir, safePath);
5847
- 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;
5848
5898
  try {
5849
5899
  const fileStat = await stat7(resolvedPath);
5850
5900
  if (fileStat.isDirectory()) {
5851
- const indexPath = join14(resolvedPath, "index.html");
5901
+ const indexPath = join15(resolvedPath, "index.html");
5852
5902
  try {
5853
5903
  const indexStat = await stat7(indexPath);
5854
5904
  if (indexStat.isFile()) {
5855
- const content2 = await readFile11(indexPath);
5905
+ const content2 = await readFile12(indexPath);
5856
5906
  res.writeHead(200, { "content-type": contentTypeFor(indexPath) });
5857
5907
  res.end(content2);
5858
5908
  return true;
@@ -5861,7 +5911,7 @@ async function startServeServer(options) {
5861
5911
  }
5862
5912
  return false;
5863
5913
  }
5864
- const content = await readFile11(resolvedPath);
5914
+ const content = await readFile12(resolvedPath);
5865
5915
  res.writeHead(200, { "content-type": contentTypeFor(resolvedPath) });
5866
5916
  res.end(content);
5867
5917
  return true;
@@ -5870,7 +5920,7 @@ async function startServeServer(options) {
5870
5920
  const ext = extname(pathname);
5871
5921
  if (ext === "" || ext === ".html") {
5872
5922
  try {
5873
- const indexContent = await readFile11(join14(staticDir, "index.html"));
5923
+ const indexContent = await readFile12(join15(staticDir, "index.html"));
5874
5924
  res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
5875
5925
  res.end(indexContent);
5876
5926
  return true;
@@ -6015,7 +6065,7 @@ async function startServeServer(options) {
6015
6065
  functions: functionNames,
6016
6066
  static: hasStatic,
6017
6067
  // CLI-020:当前数据面(换模式即换库,这里让脚本/e2e 有可断言的读数)。
6018
- 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 },
6019
6069
  endpoints: {
6020
6070
  functions: "/api/{fn}",
6021
6071
  static: `/ \u2192 ${staticDir}`,
@@ -6054,9 +6104,9 @@ async function startServeServer(options) {
6054
6104
  functions: functionNames,
6055
6105
  functionsPrefix: config.functionsPrefix,
6056
6106
  hasStatic,
6057
- staticDir: relative2(cwd, staticDir).length > 0 ? relative2(cwd, staticDir) : staticDir,
6107
+ staticDir: relative3(cwd, staticDir).length > 0 ? relative3(cwd, staticDir) : staticDir,
6058
6108
  dbMode,
6059
- dbTarget: sqliteFile === null ? displayPath(cwd, join14(simDir(cwd), "db.json")) : displayPath(cwd, sqliteFile),
6109
+ dbTarget: sqliteFile === null ? simDbTarget(cwd) : displayPath(cwd, sqliteFile),
6060
6110
  ...sqliteModule === null ? {} : { dbDriver: sqliteModule }
6061
6111
  });
6062
6112
  log(banner);
@@ -6091,7 +6141,6 @@ var init_server = __esm({
6091
6141
  init_signature();
6092
6142
  init_driver();
6093
6143
  init_builtin_deps2();
6094
- init_db2();
6095
6144
  init_runtime();
6096
6145
  init_storage();
6097
6146
  init_env();
@@ -6099,7 +6148,6 @@ var init_server = __esm({
6099
6148
  init_dev();
6100
6149
  init_banner();
6101
6150
  init_db_mode();
6102
- init_sqlite_driver();
6103
6151
  init_dev_shared();
6104
6152
  MIME_TYPES = {
6105
6153
  ".html": "text/html; charset=utf-8",
@@ -6134,8 +6182,8 @@ __export(deploy_exports, {
6134
6182
  deploy: () => deploy
6135
6183
  });
6136
6184
  import { createHash as createHash2 } from "node:crypto";
6137
- import { readdir as readdir5, readFile as readFile12 } from "node:fs/promises";
6138
- 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";
6139
6187
  function functionUrlBase(prefix) {
6140
6188
  const raw = (prefix ?? "/api").trim();
6141
6189
  const normalized = raw === "/" ? "/" : raw.replace(/\/+$/, "");
@@ -6161,10 +6209,10 @@ async function collectFunctionFiles(functionsDir) {
6161
6209
  if (conflicting.length > 0) throw new AmbiguousFunctionError(functionsDir, conflicting);
6162
6210
  const out = {};
6163
6211
  for (const name of flatNames) {
6164
- out[name] = { [`${name}.ts`]: await readFile12(join15(functionsDir, `${name}.ts`), "utf8") };
6212
+ out[name] = { [`${name}.ts`]: await readFile13(join16(functionsDir, `${name}.ts`), "utf8") };
6165
6213
  }
6166
6214
  for (const name of dirNames) {
6167
- const files = await collectFunctionDir(join15(functionsDir, name));
6215
+ const files = await collectFunctionDir(join16(functionsDir, name));
6168
6216
  if (files["index.ts"] === void 0) continue;
6169
6217
  out[name] = files;
6170
6218
  }
@@ -6183,11 +6231,11 @@ async function collectFunctionDir(absDir) {
6183
6231
  const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
6184
6232
  if (entry.isDirectory()) {
6185
6233
  if (entry.name === "__tests__" || IGNORED_DIRS.has(entry.name)) continue;
6186
- await walk(join15(dir, entry.name), rel);
6234
+ await walk(join16(dir, entry.name), rel);
6187
6235
  continue;
6188
6236
  }
6189
6237
  if (!isRuntimeSource2(entry.name)) continue;
6190
- files[rel] = await readFile12(join15(dir, entry.name), "utf8");
6238
+ files[rel] = await readFile13(join16(dir, entry.name), "utf8");
6191
6239
  }
6192
6240
  };
6193
6241
  await walk(absDir, "");
@@ -6197,7 +6245,7 @@ function sha256Hex(content) {
6197
6245
  return createHash2("sha256").update(content).digest("hex");
6198
6246
  }
6199
6247
  async function collectShared(functionsDir) {
6200
- const sharedDir = join15(functionsDir, "_shared");
6248
+ const sharedDir = join16(functionsDir, "_shared");
6201
6249
  const files = {};
6202
6250
  const walk = async (dir) => {
6203
6251
  let entries;
@@ -6209,13 +6257,13 @@ async function collectShared(functionsDir) {
6209
6257
  for (const entry of entries) {
6210
6258
  if (entry.isDirectory()) {
6211
6259
  if (entry.name === "__tests__" || entry.name === "node_modules") continue;
6212
- await walk(join15(dir, entry.name));
6260
+ await walk(join16(dir, entry.name));
6213
6261
  continue;
6214
6262
  }
6215
6263
  if (!isRuntimeSource2(entry.name)) continue;
6216
- const full = join15(dir, entry.name);
6217
- const rel = relative3(sharedDir, full).split(sep).join("/");
6218
- 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");
6219
6267
  }
6220
6268
  };
6221
6269
  await walk(sharedDir);
@@ -6229,7 +6277,7 @@ async function deploy(paths, options) {
6229
6277
  const cwd = resolve9(options.cwd);
6230
6278
  const config = await loadConfig(cwd);
6231
6279
  const slug = options.slug ?? config.name;
6232
- 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);
6233
6281
  const local = await collectFunctionFiles(functionsDir);
6234
6282
  if (Object.keys(local).length === 0) {
6235
6283
  throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
@@ -6301,7 +6349,12 @@ async function deploy(paths, options) {
6301
6349
  }
6302
6350
  const published = await client.request(
6303
6351
  `/api/v1/functions/${functionId}/publish`,
6304
- { method: "POST" }
6352
+ {
6353
+ method: "POST",
6354
+ // FN-013:显式 body 而非省略——`force: false` 与 `undefined` 在服务端语义相同,
6355
+ // 但显式传值让「这次发布是否放行过警告」在请求层面可审计。
6356
+ body: { force: options.force === true }
6357
+ }
6305
6358
  );
6306
6359
  deployed.push({
6307
6360
  name: item.name,
@@ -6360,8 +6413,8 @@ var frontend_exports = {};
6360
6413
  __export(frontend_exports, {
6361
6414
  frontendSync: () => frontendSync
6362
6415
  });
6363
- import { readdir as readdir6, readFile as readFile13, stat as stat8 } from "node:fs/promises";
6364
- 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";
6365
6418
  async function resolveProjectId(client, cwd, slug) {
6366
6419
  const resolvedSlug = await resolveSlug(cwd, slug);
6367
6420
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -6381,20 +6434,21 @@ async function collectFiles(root, dir) {
6381
6434
  for (const entry of entries) {
6382
6435
  if (entry.isDirectory()) {
6383
6436
  if (IGNORED_DIRS2.has(entry.name)) continue;
6384
- const nested = await collectFiles(root, join16(dir, entry.name));
6437
+ const nested = await collectFiles(root, join17(dir, entry.name));
6385
6438
  for (const [path, content] of nested.files) files.set(path, content);
6386
6439
  skipped.push(...nested.skipped);
6387
6440
  continue;
6388
6441
  }
6389
- const full = join16(dir, entry.name);
6390
- 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("/");
6391
6445
  const info = await stat8(full);
6392
6446
  if (info.size > 1024 * 1024) {
6393
6447
  skipped.push(rel);
6394
6448
  continue;
6395
6449
  }
6396
6450
  try {
6397
- const content = await readFile13(full, "utf8");
6451
+ const content = await readFile14(full, "utf8");
6398
6452
  if (content.includes("\0")) {
6399
6453
  skipped.push(rel);
6400
6454
  continue;
@@ -6409,7 +6463,7 @@ async function collectFiles(root, dir) {
6409
6463
  async function frontendSync(paths, options) {
6410
6464
  const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
6411
6465
  `));
6412
- const webDir = options.dir ?? join16(options.cwd, "web");
6466
+ const webDir = options.dir ?? join17(options.cwd, "web");
6413
6467
  const rootStat = await stat8(webDir).catch(() => null);
6414
6468
  if (rootStat === null || !rootStat.isDirectory()) {
6415
6469
  throw new CliError(
@@ -6456,7 +6510,7 @@ async function frontendSync(paths, options) {
6456
6510
  }
6457
6511
  return { projectId: project2.id, uploaded: files.size, skipped, totalBytes };
6458
6512
  }
6459
- 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;
6460
6514
  var init_frontend = __esm({
6461
6515
  "packages/cli/src/frontend.ts"() {
6462
6516
  "use strict";
@@ -6467,6 +6521,14 @@ var init_frontend = __esm({
6467
6521
  MAX_TOTAL_SOURCE_BYTES2 = FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES;
6468
6522
  FILE_PATH_PATTERN = FRONTEND_DRAFT_FILE_PATH_PATTERN;
6469
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
+ ]);
6470
6532
  }
6471
6533
  });
6472
6534
 
@@ -6623,11 +6685,11 @@ var fs_exports = {};
6623
6685
  __export(fs_exports, {
6624
6686
  createExportFileSystem: () => createExportFileSystem
6625
6687
  });
6626
- import { mkdir as mkdir10, readFile as readFile14, rm as rm3, stat as stat10, writeFile as writeFile8 } from "node:fs/promises";
6627
- 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";
6628
6690
  function createExportFileSystem() {
6629
6691
  return {
6630
- readFile: (path) => readFile14(path),
6692
+ readFile: (path) => readFile15(path),
6631
6693
  writeFile: (path, content) => writeFile8(path, content),
6632
6694
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
6633
6695
  deleteFile: async (path) => {
@@ -6645,9 +6707,9 @@ function createExportFileSystem() {
6645
6707
  await mkdir10(path, { recursive: true });
6646
6708
  },
6647
6709
  unzip: async (zipPath, targetDir) => {
6648
- const entries = zipRead(await readFile14(zipPath));
6710
+ const entries = zipRead(await readFile15(zipPath));
6649
6711
  for (const [name, data] of entries) {
6650
- const dest = join18(targetDir, name);
6712
+ const dest = join19(targetDir, name);
6651
6713
  await mkdir10(dirname9(dest), { recursive: true });
6652
6714
  await writeFile8(dest, data);
6653
6715
  }
@@ -7165,8 +7227,8 @@ __export(storage_exports, {
7165
7227
  storageRemove: () => storageRemove,
7166
7228
  storageUpload: () => storageUpload
7167
7229
  });
7168
- import { mkdir as mkdir11, readFile as readFile15, stat as stat11, writeFile as writeFile9 } from "node:fs/promises";
7169
- 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";
7170
7232
  async function open3(paths, options) {
7171
7233
  const client = await createClient(paths);
7172
7234
  const project2 = await resolveSlug(resolve11(options.cwd), options.slug);
@@ -7208,7 +7270,7 @@ async function storageUpload(paths, options) {
7208
7270
  throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
7209
7271
  }
7210
7272
  const visibility = options.visibility ?? "private";
7211
- const bytes = await readFile15(local);
7273
+ const bytes = await readFile16(local);
7212
7274
  const form = new FormData();
7213
7275
  form.set("path", options.path);
7214
7276
  form.set("visibility", visibility);
@@ -7249,7 +7311,7 @@ async function storageDownload(paths, options) {
7249
7311
  const url = await resolveDownloadUrl(client, project2, options.path);
7250
7312
  const response = await client.download(url, "STORAGE_DOWNLOAD_FAILED");
7251
7313
  const bytes = Buffer.from(await response.arrayBuffer());
7252
- 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)));
7253
7315
  await mkdir11(dirname10(output), { recursive: true });
7254
7316
  await writeFile9(output, bytes);
7255
7317
  return { path: options.path, output, size: bytes.length };
@@ -7270,8 +7332,8 @@ var init_storage2 = __esm({
7270
7332
  });
7271
7333
 
7272
7334
  // packages/cli/src/sandbox-scan.ts
7273
- import { readdir as readdir7, readFile as readFile16 } from "node:fs/promises";
7274
- import { join as join20, relative as relative5, sep as sep3 } from "node:path";
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";
7275
7337
  function extractSpecifiers(line) {
7276
7338
  const out = [];
7277
7339
  const patterns = [
@@ -7315,7 +7377,7 @@ function classify(specifier) {
7315
7377
  return null;
7316
7378
  }
7317
7379
  async function scanFunctionSources(rootDir, functionsDir) {
7318
- const base = join20(rootDir, functionsDir);
7380
+ const base = join21(rootDir, functionsDir);
7319
7381
  const findings = [];
7320
7382
  async function walk(current) {
7321
7383
  let entries;
@@ -7325,7 +7387,7 @@ async function scanFunctionSources(rootDir, functionsDir) {
7325
7387
  return;
7326
7388
  }
7327
7389
  for (const entry of entries) {
7328
- const abs = join20(current, entry.name);
7390
+ const abs = join21(current, entry.name);
7329
7391
  if (entry.isDirectory()) {
7330
7392
  if (SKIP_DIRS.has(entry.name)) continue;
7331
7393
  await walk(abs);
@@ -7336,12 +7398,12 @@ async function scanFunctionSources(rootDir, functionsDir) {
7336
7398
  if (entry.name.endsWith(".d.ts")) continue;
7337
7399
  let content;
7338
7400
  try {
7339
- content = await readFile16(abs, "utf8");
7401
+ content = await readFile17(abs, "utf8");
7340
7402
  } catch {
7341
7403
  continue;
7342
7404
  }
7343
7405
  if (content.length > MAX_SCAN_BYTES) continue;
7344
- const relPath = relative5(rootDir, abs).split(sep3).join("/");
7406
+ const relPath = relative6(rootDir, abs).split(sep3).join("/");
7345
7407
  const lines = content.split("\n");
7346
7408
  for (const [index, line] of lines.entries()) {
7347
7409
  const trimmed = line.trim();
@@ -7961,8 +8023,8 @@ __export(hosting_exports, {
7961
8023
  hostingInfo: () => hostingInfo,
7962
8024
  hostingPull: () => hostingPull
7963
8025
  });
7964
- import { readdir as readdir8, readFile as readFile17, stat as stat13 } from "node:fs/promises";
7965
- import { dirname as dirname11, join as join21, relative as relative6, resolve as resolve14, sep as sep4 } 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";
7966
8028
  async function open4(paths, options) {
7967
8029
  const client = await createClient(paths);
7968
8030
  const project2 = await resolveSlug(resolve14(options.cwd), options.slug);
@@ -7988,11 +8050,11 @@ async function collectSiteFiles(dir) {
7988
8050
  return;
7989
8051
  }
7990
8052
  for (const entry of entries) {
7991
- const full = join21(sub, entry.name);
8053
+ const full = join22(sub, entry.name);
7992
8054
  if (entry.isDirectory()) {
7993
8055
  await walk(full);
7994
8056
  } else if (entry.isFile()) {
7995
- const rel = relative6(root, full).split(sep4).join("/");
8057
+ const rel = relative7(root, full).split(sep4).join("/");
7996
8058
  files.set(rel, full);
7997
8059
  }
7998
8060
  }
@@ -8012,7 +8074,7 @@ async function hostingDeploy(paths, options) {
8012
8074
  for (const [rel, full] of files) {
8013
8075
  log(`[adep] \u4E0A\u4F20 site/${rel}`);
8014
8076
  const info2 = await stat13(full);
8015
- const bytes = await readFile17(full);
8077
+ const bytes = await readFile18(full);
8016
8078
  const form = new FormData();
8017
8079
  form.set("path", `site/${rel}`);
8018
8080
  form.set("visibility", "public");
@@ -8050,7 +8112,7 @@ async function hostingPull(paths, options) {
8050
8112
  const response = await client.download(url, "HOSTING_DOWNLOAD_FAILED");
8051
8113
  const bytes = Buffer.from(await response.arrayBuffer());
8052
8114
  const rel = entry.path.replace(/^site\//, "");
8053
- const target = join21(outputDir, ...rel.split("/"));
8115
+ const target = join22(outputDir, ...rel.split("/"));
8054
8116
  await mkdir12(dirname11(target), { recursive: true });
8055
8117
  await writeFile10(target, bytes);
8056
8118
  files.push({ path: entry.path, size: bytes.length });
@@ -12596,11 +12658,28 @@ function registerImport(program2, ctx) {
12596
12658
 
12597
12659
  // packages/cli/src/commands/dev.ts
12598
12660
  function registerDevServers(program2, ctx) {
12599
- 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) => {
12600
12671
  const command = ctx.io("dev");
12601
12672
  await command.run(async () => {
12602
12673
  const { startDevServer: startDevServer2 } = await Promise.resolve().then(() => (init_dev(), dev_exports));
12603
- 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
+ });
12604
12683
  command.raw(`[adep] dev server listening on ${started.baseUrl}\uFF08Ctrl-C \u9000\u51FA\uFF09`);
12605
12684
  await new Promise(() => void 0);
12606
12685
  });
@@ -12655,7 +12734,7 @@ init_auth();
12655
12734
  init_client();
12656
12735
  init_deploy();
12657
12736
  import { stat as stat9 } from "node:fs/promises";
12658
- import { join as join17, resolve as resolve10 } from "node:path";
12737
+ import { join as join18, resolve as resolve10 } from "node:path";
12659
12738
  async function resolveProjectId2(client, cwd, slug) {
12660
12739
  const resolvedSlug = await resolveSlug(resolve10(cwd), slug);
12661
12740
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -12698,7 +12777,8 @@ async function publishFunctions(paths, options) {
12698
12777
  cwd: options.cwd,
12699
12778
  ...options.slug === void 0 ? {} : { slug: options.slug },
12700
12779
  silent: options.silent ?? false,
12701
- ...options.log === void 0 ? {} : { log: options.log }
12780
+ ...options.log === void 0 ? {} : { log: options.log },
12781
+ ...options.force === void 0 ? {} : { force: options.force }
12702
12782
  });
12703
12783
  const elapsedSeconds = (Date.now() - startedAt) / 1e3;
12704
12784
  const deployedCount = result.functions.filter((fn) => fn.action !== "none").length;
@@ -12717,11 +12797,12 @@ async function runPublish(paths, io, cwd, flags) {
12717
12797
  cwd,
12718
12798
  ...flags.project === void 0 ? {} : { slug: flags.project },
12719
12799
  silent: io.json,
12720
- log: (line) => io.line(line)
12800
+ log: (line) => io.line(line),
12801
+ ...flags.force === void 0 ? {} : { force: flags.force }
12721
12802
  });
12722
12803
  }
12723
12804
  if (wantFrontend) {
12724
- const webDir = join17(cwd, "web");
12805
+ const webDir = join18(cwd, "web");
12725
12806
  const webStat = await stat9(webDir).catch(() => null);
12726
12807
  if (webStat !== null && webStat.isDirectory()) {
12727
12808
  const { frontendSync: frontendSync2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
@@ -12769,7 +12850,10 @@ function registerPublish(program2, ctx) {
12769
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(
12770
12851
  "--only <scope>",
12771
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"
12772
- ).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) => {
12773
12857
  const command = ctx.io("publish");
12774
12858
  await command.run(async () => {
12775
12859
  const result = await runPublish(ctx.paths, command, ctx.cwd, flags);
@@ -12779,13 +12863,14 @@ function registerPublish(program2, ctx) {
12779
12863
  }
12780
12864
 
12781
12865
  // packages/cli/src/commands/deploy.ts
12782
- async function runDeploy(paths, io, cwd, slug, dir) {
12866
+ async function runDeploy(paths, io, cwd, slug, dir, force) {
12783
12867
  const { deploy: deploy2 } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
12784
12868
  const startedAt = Date.now();
12785
12869
  const result = await deploy2(paths, {
12786
12870
  cwd,
12787
12871
  ...slug === void 0 ? {} : { slug },
12788
12872
  ...dir === void 0 ? {} : { functionsDir: dir },
12873
+ ...force === void 0 ? {} : { force },
12789
12874
  // --json 下逐函数进度会破坏「stdout 恰好一个 JSON 对象」的信封约定(PRD §2.5.3)。
12790
12875
  silent: io.json,
12791
12876
  // 人读模式的进度也走注入的 io:deploy 内部缺省会直写 process.stdout,
@@ -12810,14 +12895,14 @@ async function runDeploy(paths, io, cwd, slug, dir) {
12810
12895
  function registerDeploy(program2, ctx) {
12811
12896
  program2.command("deploy").description(
12812
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"
12813
- ).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) => {
12814
12899
  const command = ctx.io("deploy");
12815
12900
  if (!command.json) {
12816
12901
  process.stderr.write(
12817
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"
12818
12903
  );
12819
12904
  }
12820
- 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));
12821
12906
  });
12822
12907
  }
12823
12908
 
@@ -12861,7 +12946,7 @@ function registerExport(program2, ctx) {
12861
12946
 
12862
12947
  // packages/cli/src/commands/db.ts
12863
12948
  function registerDb(program2, ctx) {
12864
- 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");
12865
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) => {
12866
12951
  const command = ctx.io("db start");
12867
12952
  await command.run(async () => {
@@ -13012,7 +13097,7 @@ function registerDb(program2, ctx) {
13012
13097
 
13013
13098
  // packages/cli/src/commands/frontend.ts
13014
13099
  function registerFrontend(program2, ctx) {
13015
- 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");
13016
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) => {
13017
13102
  const command = ctx.io("frontend sync");
13018
13103
  await command.run(async () => {
@@ -13034,7 +13119,7 @@ function registerFrontend(program2, ctx) {
13034
13119
 
13035
13120
  // packages/cli/src/commands/storage.ts
13036
13121
  function registerStorage(program2, ctx) {
13037
- 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");
13038
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(
13039
13124
  "--visibility <public|private>",
13040
13125
  "public \u76F4\u8FDE / private \u7B7E\u540D\uFF08\u7F3A\u7701 private\uFF09",
@@ -13319,14 +13404,16 @@ function registerFunctions(program2, ctx) {
13319
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");
13320
13405
  functions.command("deploy").description(
13321
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"
13322
- ).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) => {
13323
13408
  const command = ctx.io("functions deploy");
13324
13409
  if (!command.json) {
13325
13410
  process.stderr.write(
13326
13411
  "\u63D0\u793A\uFF1Aadep functions deploy \u5DF2\u5E9F\u5F03\uFF0C\u63A8\u8350\u4F7F\u7528 adep publish --only functions\n"
13327
13412
  );
13328
13413
  }
13329
- 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
+ );
13330
13417
  });
13331
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) => {
13332
13419
  const command = ctx.io("functions list");
@@ -13377,7 +13464,7 @@ function parseBool(raw) {
13377
13464
  throw new CliError("INVALID_BOOLEAN", `\u5E03\u5C14\u53C2\u6570\u987B\u4E3A true \u6216 false\uFF0C\u6536\u5230 "${raw}"`);
13378
13465
  }
13379
13466
  function registerHosting(program2, ctx) {
13380
- 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");
13381
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) => {
13382
13469
  const command = ctx.io("hosting info");
13383
13470
  await command.run(async () => {