@adep/cli 0.4.11 → 0.5.1

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
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __esm = (fn, res) => function __init() {
5
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ var __esm = (fn, res, err) => function __init() {
5
+ if (err) throw err[0];
6
+ try {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ } catch (e) {
9
+ throw err = [e], e;
10
+ }
6
11
  };
7
12
  var __export = (target, all) => {
8
13
  for (var name in all)
@@ -50,16 +55,16 @@ function openBrowser(url2, options = {}) {
50
55
  const spawnImpl = options.spawnImpl ?? spawn;
51
56
  if (!shouldOpenBrowser(options)) return Promise.resolve(false);
52
57
  const { command, args } = browserOpenCommand(url2, platform);
53
- return new Promise((resolve20) => {
58
+ return new Promise((resolve21) => {
54
59
  try {
55
60
  const child = spawnImpl(command, args, { stdio: "ignore", detached: true });
56
- child.once("error", () => resolve20(false));
61
+ child.once("error", () => resolve21(false));
57
62
  child.once("spawn", () => {
58
63
  child.unref();
59
- resolve20(true);
64
+ resolve21(true);
60
65
  });
61
66
  } catch {
62
- resolve20(false);
67
+ resolve21(false);
63
68
  }
64
69
  });
65
70
  }
@@ -455,7 +460,7 @@ async function loginWithDevice(paths, input2) {
455
460
  expiresInSeconds: code.expires_in,
456
461
  browserOpened
457
462
  });
458
- const sleep = input2.sleep ?? ((ms) => new Promise((resolve20) => setTimeout(resolve20, ms)));
463
+ const sleep = input2.sleep ?? ((ms) => new Promise((resolve21) => setTimeout(resolve21, ms)));
459
464
  const token = await pollDeviceToken({
460
465
  server,
461
466
  deviceCode: code.device_code,
@@ -549,6 +554,8 @@ var init_auth = __esm({
549
554
  this.exitCode = exitCode;
550
555
  this.name = "CliError";
551
556
  }
557
+ code;
558
+ exitCode;
552
559
  };
553
560
  CLI_DEVICE_CLIENT_ID = "adep-cli";
554
561
  }
@@ -883,6 +890,8 @@ var init_executor_runtime = __esm({
883
890
  this.code = code;
884
891
  this.name = "ExecutorError";
885
892
  }
893
+ status;
894
+ code;
886
895
  };
887
896
  TIMEOUT_CODE = "FN_EXEC_TIMEOUT";
888
897
  OOM_CODE = "FN_EXEC_OOM";
@@ -1172,7 +1181,7 @@ var init_worker_executor = __esm({
1172
1181
  const entry = input2.entry ?? resolveDraftEntry(input2.fn.name, input2.files) ?? "index.ts";
1173
1182
  const deps = this.depsConfig === void 0 ? void 0 : resolveExecutionDeps(this.depsConfig, input2.project.id, input2.files["package.json"]);
1174
1183
  const logs = [];
1175
- return new Promise((resolve20, reject) => {
1184
+ return new Promise((resolve21, reject) => {
1176
1185
  let worker;
1177
1186
  try {
1178
1187
  worker = new Worker(resolveWorkerEntry(), {
@@ -1234,7 +1243,7 @@ var init_worker_executor = __esm({
1234
1243
  if (message.type === "result") {
1235
1244
  clearTimeout(timer);
1236
1245
  void worker.terminate();
1237
- resolve20({ body: message.body, logs });
1246
+ resolve21({ body: message.body, logs });
1238
1247
  return;
1239
1248
  }
1240
1249
  if (message.type === "error") {
@@ -1319,6 +1328,8 @@ var init_identifier = __esm({
1319
1328
  this.code = code;
1320
1329
  this.name = "DbError";
1321
1330
  }
1331
+ status;
1332
+ code;
1322
1333
  };
1323
1334
  IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]{0,62}$/;
1324
1335
  }
@@ -2548,11 +2559,13 @@ var init_sql_engine = __esm({
2548
2559
  this.code = code;
2549
2560
  this.name = "SimDbError";
2550
2561
  }
2562
+ code;
2551
2563
  };
2552
2564
  ParamCursor = class {
2553
2565
  constructor(params) {
2554
2566
  this.params = params;
2555
2567
  }
2568
+ params;
2556
2569
  index = 0;
2557
2570
  take() {
2558
2571
  const v = this.params[this.index];
@@ -2564,16 +2577,19 @@ var init_sql_engine = __esm({
2564
2577
  constructor(column) {
2565
2578
  this.column = column;
2566
2579
  }
2580
+ column;
2567
2581
  };
2568
2582
  ColumnRef = class {
2569
2583
  constructor(column) {
2570
2584
  this.column = column;
2571
2585
  }
2586
+ column;
2572
2587
  };
2573
2588
  ExprRef = class {
2574
2589
  constructor(source) {
2575
2590
  this.source = source;
2576
2591
  }
2592
+ source;
2577
2593
  };
2578
2594
  SimSqlEngine = class {
2579
2595
  tables = {};
@@ -3055,9 +3071,12 @@ var init_driver = __esm({
3055
3071
  this.code = code;
3056
3072
  this.name = "StorageError";
3057
3073
  }
3074
+ status;
3075
+ code;
3058
3076
  };
3059
3077
  STORAGE_CODES = {
3060
3078
  invalidPath: "STORAGE_INVALID_PATH",
3079
+ invalidData: "STORAGE_INVALID_DATA",
3061
3080
  notFound: "STORAGE_NOT_FOUND",
3062
3081
  quotaExceeded: "STORAGE_QUOTA_EXCEEDED"
3063
3082
  };
@@ -3281,11 +3300,33 @@ var init_signature = __esm({
3281
3300
  // packages/runtime/src/storage/cloud.ts
3282
3301
  function asBytes(data) {
3283
3302
  if (typeof data === "string") return new TextEncoder().encode(data);
3284
- if (data instanceof ArrayBuffer) return new Uint8Array(data);
3285
- if (data instanceof Uint8Array) return data;
3286
- const candidate = data;
3287
- if (candidate.data instanceof Uint8Array) return candidate.data;
3288
- throw new StorageError(400, STORAGE_CODES.invalidPath, "\u4E0D\u652F\u6301\u7684\u5B58\u50A8\u6570\u636E\u7C7B\u578B");
3303
+ if (isArrayBufferLike(data)) return new Uint8Array(data);
3304
+ if (isBytes(data)) return toByteView(data);
3305
+ if (isFunctionFile(data)) {
3306
+ if (isBytes(data.data)) return toByteView(data.data);
3307
+ if (isArrayBufferLike(data.data)) return new Uint8Array(data.data);
3308
+ if (typeof data.data === "string") return new TextEncoder().encode(data.data);
3309
+ }
3310
+ throw new StorageError(400, STORAGE_CODES.invalidData, describeUnsupportedUploadData(data));
3311
+ }
3312
+ function isArrayBufferLike(value) {
3313
+ return Object.prototype.toString.call(value) === "[object ArrayBuffer]";
3314
+ }
3315
+ function isBytes(value) {
3316
+ return ArrayBuffer.isView(value) && !(Object.prototype.toString.call(value) === "[object DataView]");
3317
+ }
3318
+ function toByteView(view) {
3319
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
3320
+ }
3321
+ function isFunctionFile(value) {
3322
+ if (typeof value !== "object" || value === null) return false;
3323
+ const candidate = value;
3324
+ return typeof candidate.name === "string" && "data" in candidate;
3325
+ }
3326
+ function describeUnsupportedUploadData(data) {
3327
+ const tag = Object.prototype.toString.call(data);
3328
+ const constructorName = typeof data === "object" && data !== null ? data.constructor?.name ?? "unknown" : "none";
3329
+ return `\u4E0D\u652F\u6301\u7684\u5B58\u50A8\u6570\u636E\u7C7B\u578B\uFF08\u80FD\u529B cloud.storage\uFF0C\u65B9\u6CD5 upload\uFF09\uFF1Atypeof=${typeof data}\uFF0CtoString=${tag}\uFF0Cconstructor=${constructorName}\u3002\u652F\u6301\uFF1Astring / Uint8Array / ArrayBuffer / ctx.files\uFF08FunctionFile\uFF09\u3002\u82E5\u6570\u636E\u6765\u81EA\u5BB9\u5668\u6267\u884C\u5668\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u5347\u7EA7\u5230\u5305\u542B RPC typed-array \u7F16\u89E3\u7801\u7684\u8FD0\u884C\u65F6\u955C\u50CF\u3002`;
3289
3330
  }
3290
3331
  function toStoredFile(meta3) {
3291
3332
  return {
@@ -3965,8 +4006,11 @@ var init_sql_split = __esm({
3965
4006
  var db_exports = {};
3966
4007
  __export(db_exports, {
3967
4008
  dbExec: () => dbExec,
4009
+ dbExecBatch: () => dbExecBatch,
3968
4010
  dbMigrate: () => dbMigrate,
3969
4011
  dbRollback: () => dbRollback,
4012
+ dbSchemaDiff: () => dbSchemaDiff,
4013
+ dbSchemaMigrate: () => dbSchemaMigrate,
3970
4014
  dbSnapshotCreate: () => dbSnapshotCreate,
3971
4015
  dbSnapshotList: () => dbSnapshotList,
3972
4016
  dbSnapshotRestore: () => dbSnapshotRestore,
@@ -4062,6 +4106,36 @@ async function dbRollback(paths, options) {
4062
4106
  { method: "POST", body: { to: options.to } }
4063
4107
  );
4064
4108
  }
4109
+ async function dbSchemaDiff(paths, options) {
4110
+ const { client, project: project2 } = await open2(paths, options);
4111
+ return client.request(
4112
+ `/api/v1/projects/${project2}/database/schema/diff${envQuery(options)}`,
4113
+ { method: "POST", body: { sql: options.sql } },
4114
+ "SCHEMA_DIFF_FAILED"
4115
+ );
4116
+ }
4117
+ async function dbSchemaMigrate(paths, options) {
4118
+ const { client, project: project2 } = await open2(paths, options);
4119
+ return client.request(
4120
+ `/api/v1/projects/${project2}/database/schema/migrate${envQuery(options)}`,
4121
+ { method: "POST", body: { sql: options.sql } },
4122
+ "SCHEMA_MIGRATE_FAILED"
4123
+ );
4124
+ }
4125
+ async function dbExecBatch(paths, options) {
4126
+ const { client, project: project2 } = await open2(paths, options);
4127
+ return client.request(
4128
+ `/api/v1/projects/${project2}/database/console/sql-batch${envQuery(options)}`,
4129
+ {
4130
+ method: "POST",
4131
+ body: {
4132
+ statements: options.statements,
4133
+ ...options.confirmTables === void 0 ? {} : { confirmTables: options.confirmTables }
4134
+ }
4135
+ },
4136
+ "SQL_EXEC_FAILED"
4137
+ );
4138
+ }
4065
4139
  async function dbMigrate(paths, options) {
4066
4140
  const queue = [];
4067
4141
  for (const file2 of options.files) {
@@ -4070,35 +4144,101 @@ async function dbMigrate(paths, options) {
4070
4144
  if (statements.length === 0) {
4071
4145
  throw new Error(`\u8FC1\u79FB\u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${file2}`);
4072
4146
  }
4073
- for (const statement of statements) queue.push({ file: file2, statement });
4147
+ queue.push({ file: file2, sql: source });
4074
4148
  }
4075
4149
  const { project: project2 } = await open2(paths, options);
4076
4150
  const applied = [];
4077
4151
  const changes = [];
4078
- for (const { file: file2, statement } of queue) {
4152
+ let createdTables = 0;
4153
+ let addedColumns = 0;
4154
+ let skippedTables = 0;
4155
+ let drift;
4156
+ const mergeDrift = (next) => {
4157
+ if (next === void 0) return;
4158
+ if (drift === void 0) {
4159
+ drift = { ...next };
4160
+ return;
4161
+ }
4162
+ drift = {
4163
+ ...drift,
4164
+ missingTables: [...drift.missingTables, ...next.missingTables],
4165
+ missingColumns: [...drift.missingColumns, ...next.missingColumns],
4166
+ typeMismatches: [...drift.typeMismatches, ...next.typeMismatches],
4167
+ extraTables: [.../* @__PURE__ */ new Set([...drift.extraTables, ...next.extraTables])],
4168
+ extraColumns: [...drift.extraColumns, ...next.extraColumns],
4169
+ destructiveStatements: [...drift.destructiveStatements, ...next.destructiveStatements],
4170
+ applicable: drift.applicable && next.applicable
4171
+ };
4172
+ };
4173
+ if (options.plan === true) {
4174
+ for (const { file: file2, sql } of queue) {
4175
+ try {
4176
+ const next = await dbSchemaDiff(paths, {
4177
+ cwd: options.cwd,
4178
+ sql,
4179
+ ...options.slug === void 0 ? {} : { slug: options.slug },
4180
+ ...options.environment === void 0 ? {} : { environment: options.environment }
4181
+ });
4182
+ mergeDrift(next);
4183
+ } catch (error62) {
4184
+ return {
4185
+ projectId: project2,
4186
+ applied,
4187
+ changes,
4188
+ createdTables,
4189
+ addedColumns,
4190
+ skippedTables,
4191
+ failed: toFailed(file2, error62)
4192
+ };
4193
+ }
4194
+ }
4195
+ return { projectId: project2, applied, changes, createdTables, addedColumns, skippedTables, drift };
4196
+ }
4197
+ for (const { file: file2, sql } of queue) {
4079
4198
  try {
4080
- const result = await dbExec(paths, {
4199
+ const result = await dbSchemaMigrate(paths, {
4081
4200
  cwd: options.cwd,
4201
+ sql,
4082
4202
  ...options.slug === void 0 ? {} : { slug: options.slug },
4083
- // 环境必须一路透传:漏掉这一步,`--env dev` 的迁移会**逐条落到生产库**
4084
- // (每条语句自己按 prod 打),而且前几条已经提交、失败即停也救不回来。
4085
- ...options.environment === void 0 ? {} : { environment: options.environment },
4086
- sql: statement
4203
+ // 环境必须一路透传:漏掉这一步,`--env dev` 的迁移会落到生产库。
4204
+ ...options.environment === void 0 ? {} : { environment: options.environment }
4087
4205
  });
4088
- applied.push(statement);
4089
- changes.push(result.changes);
4206
+ applied.push(...result.applied);
4207
+ changes.push(...result.applied.map(() => 0));
4208
+ createdTables += result.createdTables;
4209
+ addedColumns += result.addedColumns;
4210
+ skippedTables += result.skippedTables;
4211
+ mergeDrift(result.diff);
4090
4212
  } catch (error62) {
4091
- const code = error62 instanceof CliError ? error62.code : "MIGRATE_FAILED";
4092
- const message = error62 instanceof Error ? error62.message : String(error62);
4093
4213
  return {
4094
4214
  projectId: project2,
4095
4215
  applied,
4096
4216
  changes,
4097
- failed: { file: file2, statement, code, message }
4217
+ createdTables,
4218
+ addedColumns,
4219
+ skippedTables,
4220
+ drift,
4221
+ failed: toFailed(file2, error62)
4098
4222
  };
4099
4223
  }
4100
4224
  }
4101
- return { projectId: project2, applied, changes };
4225
+ return {
4226
+ projectId: project2,
4227
+ applied,
4228
+ changes,
4229
+ createdTables,
4230
+ addedColumns,
4231
+ skippedTables,
4232
+ drift
4233
+ };
4234
+ }
4235
+ function toFailed(file2, error62) {
4236
+ return {
4237
+ file: file2,
4238
+ statement: "",
4239
+ code: error62 instanceof CliError ? error62.code : "MIGRATE_FAILED",
4240
+ message: error62 instanceof Error ? error62.message : String(error62)
4241
+ };
4102
4242
  }
4103
4243
  var init_db2 = __esm({
4104
4244
  "packages/cli/src/db.ts"() {
@@ -4320,6 +4460,202 @@ var init_db_mode = __esm({
4320
4460
  }
4321
4461
  });
4322
4462
 
4463
+ // packages/runtime/src/shared/fetch-blocked-ports.ts
4464
+ function isFetchBlockedPort(port) {
4465
+ if (!Number.isInteger(port)) {
4466
+ throw new TypeError(`[fetch-blocked-ports] \u7AEF\u53E3\u5FC5\u987B\u662F\u6574\u6570\uFF1A\u6536\u5230 ${String(port)}`);
4467
+ }
4468
+ return FETCH_BLOCKED_PORTS.has(port);
4469
+ }
4470
+ var FETCH_BLOCKED_PORTS;
4471
+ var init_fetch_blocked_ports = __esm({
4472
+ "packages/runtime/src/shared/fetch-blocked-ports.ts"() {
4473
+ "use strict";
4474
+ FETCH_BLOCKED_PORTS = /* @__PURE__ */ new Set([
4475
+ 1,
4476
+ 7,
4477
+ 9,
4478
+ 11,
4479
+ 13,
4480
+ 15,
4481
+ 17,
4482
+ 19,
4483
+ 20,
4484
+ 21,
4485
+ 22,
4486
+ 23,
4487
+ 25,
4488
+ 37,
4489
+ 42,
4490
+ 43,
4491
+ 53,
4492
+ 69,
4493
+ 77,
4494
+ 79,
4495
+ 87,
4496
+ 95,
4497
+ 101,
4498
+ 102,
4499
+ 103,
4500
+ 104,
4501
+ 109,
4502
+ 110,
4503
+ 111,
4504
+ 113,
4505
+ 115,
4506
+ 117,
4507
+ 119,
4508
+ 123,
4509
+ 135,
4510
+ 137,
4511
+ 139,
4512
+ 143,
4513
+ 161,
4514
+ 179,
4515
+ 389,
4516
+ 427,
4517
+ 465,
4518
+ 512,
4519
+ 513,
4520
+ 514,
4521
+ 515,
4522
+ 526,
4523
+ 530,
4524
+ 531,
4525
+ 532,
4526
+ 540,
4527
+ 548,
4528
+ 554,
4529
+ 556,
4530
+ 563,
4531
+ 587,
4532
+ 601,
4533
+ 636,
4534
+ 989,
4535
+ 990,
4536
+ 993,
4537
+ 995,
4538
+ 1719,
4539
+ 1720,
4540
+ 1723,
4541
+ 2049,
4542
+ 3659,
4543
+ 4045,
4544
+ 4190,
4545
+ 5060,
4546
+ 5061,
4547
+ 6e3,
4548
+ 6566,
4549
+ 6665,
4550
+ 6666,
4551
+ 6667,
4552
+ 6668,
4553
+ 6669,
4554
+ 6679,
4555
+ 6697,
4556
+ 10080
4557
+ ]);
4558
+ }
4559
+ });
4560
+
4561
+ // packages/cli/src/serve/fetch-safe-port.ts
4562
+ function listenOnce(server, port, host) {
4563
+ return new Promise((resolve21, reject) => {
4564
+ const onError = (error62) => {
4565
+ server.off("error", onError);
4566
+ reject(error62);
4567
+ };
4568
+ server.once("error", onError);
4569
+ server.listen(port, host, () => {
4570
+ server.off("error", onError);
4571
+ resolve21();
4572
+ });
4573
+ });
4574
+ }
4575
+ function closeServer(server) {
4576
+ return new Promise((resolve21, reject) => {
4577
+ server.close((error62) => error62 === void 0 ? resolve21() : reject(error62));
4578
+ });
4579
+ }
4580
+ async function closeQuietly(server) {
4581
+ try {
4582
+ await closeServer(server);
4583
+ } catch (error62) {
4584
+ if (error62.code !== "ERR_SERVER_NOT_RUNNING") throw error62;
4585
+ }
4586
+ }
4587
+ function readTcpPort(server, host) {
4588
+ const address = server.address();
4589
+ if (address === null || typeof address === "string") {
4590
+ throw new Error(
4591
+ `[adep] ${host} listen \u6210\u529F\u540E address() \u8FD4\u56DE ${JSON.stringify(address)}\uFF0C\u65E0\u6CD5\u5224\u5B9A\u7AEF\u53E3\uFF1B\u672C\u5730 dev / serve \u5FC5\u987B\u662F Internet \u57DF socket\u3002`
4592
+ );
4593
+ }
4594
+ return address.port;
4595
+ }
4596
+ function buildExhaustedMessage(input2) {
4597
+ return [
4598
+ `[adep] ${input2.host} \u4E0A\u8FDE\u7EED ${input2.maxAttempts} \u6B21 listen(0) \u90FD\u843D\u5728 undici \u62D2\u7EDD\u8BBF\u95EE\u7684\u7AEF\u53E3\u5185\uFF08\u547D\u4E2D\uFF1A${input2.hits.join(", ")}\uFF09\uFF0C\u6700\u540E\u4E00\u6B21\u5DF2 close\u3002`,
4599
+ "\u8FD9\u4E9B\u7AEF\u53E3\u7684\u8BF7\u6C42\u5728\u5EFA\u7ACB\u8FDE\u63A5\u4E4B\u524D\u5C31\u4F1A\u88AB fetch \u62D2\u7EDD\uFF08TypeError: fetch failed / cause: bad port\uFF09\uFF0C\u6D4F\u89C8\u5668\u5BFC\u822A\u5219\u662F ERR_UNSAFE_PORT\u2014\u2014\u670D\u52A1\u8D77\u6765\u4E86\u4F46\u9875\u9762\u6253\u4E0D\u5F00\u3002",
4600
+ "\u53EF\u80FD\u539F\u56E0\uFF1A\u7CFB\u7EDF\u4E34\u65F6\u7AEF\u53E3\u8D77\u59CB\u503C\u88AB\u8C03\u4F4E\uFF08Windows \u7528 netsh int ipv4 show dynamicport tcp \u6838\u5BF9\uFF0CHyper-V / \u5BB9\u5668\u7F51\u7EDC\u4F1A\u6539\u5B83\uFF09\u3002\u53EF\u7528 --port \u6307\u5B9A\u4E00\u4E2A\u672A\u5360\u7528\u7684\u7AEF\u53E3\u7ED5\u8FC7\u3002"
4601
+ ].join("\n");
4602
+ }
4603
+ async function listenOnFetchSafePort(server, options) {
4604
+ const isBlocked = options.isBlocked ?? isFetchBlockedPort;
4605
+ const warn = options.warn ?? (() => {
4606
+ });
4607
+ const notifyListenError = async (error62) => {
4608
+ try {
4609
+ await options.onListenError?.(error62);
4610
+ } catch {
4611
+ }
4612
+ };
4613
+ if (options.port !== 0) {
4614
+ try {
4615
+ await listenOnce(server, options.port, options.host);
4616
+ } catch (error62) {
4617
+ await notifyListenError(error62);
4618
+ throw error62;
4619
+ }
4620
+ const actual = readTcpPort(server, options.host);
4621
+ if (isBlocked(actual)) {
4622
+ warn(
4623
+ `[adep] \u7AEF\u53E3 ${actual} \u5728 undici / \u6D4F\u89C8\u5668\u7684\u300C\u4E0D\u5B89\u5168\u7AEF\u53E3\u300D\u540D\u5355\u5185\uFF1A\u670D\u52A1\u53EF\u4EE5\u8D77\u6765\uFF0C\u4F46 fetch \u4F1A\u5728\u5EFA\u7ACB\u8FDE\u63A5\u524D\u62A5 bad port\u3001\u6D4F\u89C8\u5668\u5BFC\u822A\u62A5 ERR_UNSAFE_PORT\u3002\u5EFA\u8BAE\u6362\u4E2A\u7AEF\u53E3\u3002`
4624
+ );
4625
+ }
4626
+ return actual;
4627
+ }
4628
+ const maxAttempts = options.maxAttempts ?? MAX_FETCH_SAFE_LISTEN_ATTEMPTS;
4629
+ const hits = [];
4630
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
4631
+ try {
4632
+ await listenOnce(server, 0, options.host);
4633
+ } catch (error62) {
4634
+ await notifyListenError(error62);
4635
+ throw error62;
4636
+ }
4637
+ let actual;
4638
+ try {
4639
+ actual = readTcpPort(server, options.host);
4640
+ } catch (error62) {
4641
+ await closeQuietly(server);
4642
+ throw error62;
4643
+ }
4644
+ if (!isBlocked(actual)) return actual;
4645
+ hits.push(actual);
4646
+ await closeQuietly(server);
4647
+ }
4648
+ throw new Error(buildExhaustedMessage({ host: options.host, hits, maxAttempts }));
4649
+ }
4650
+ var MAX_FETCH_SAFE_LISTEN_ATTEMPTS;
4651
+ var init_fetch_safe_port = __esm({
4652
+ "packages/cli/src/serve/fetch-safe-port.ts"() {
4653
+ "use strict";
4654
+ init_fetch_blocked_ports();
4655
+ MAX_FETCH_SAFE_LISTEN_ATTEMPTS = 8;
4656
+ }
4657
+ });
4658
+
4323
4659
  // packages/cli/src/sim/env.ts
4324
4660
  import { readFile as readFile6 } from "node:fs/promises";
4325
4661
  import { join as join9 } from "node:path";
@@ -5775,8 +6111,8 @@ function isRpcCapability(value) {
5775
6111
  function createRpcClient(capability, port, pending, nextId) {
5776
6112
  return createFlatRpcProxy((method, args) => {
5777
6113
  const id = nextId();
5778
- return new Promise((resolve20, reject) => {
5779
- pending.set(id, { resolve: resolve20, reject });
6114
+ return new Promise((resolve21, reject) => {
6115
+ pending.set(id, { resolve: resolve21, reject });
5780
6116
  port.postMessage({ type: "rpc", id, capability, method, args });
5781
6117
  });
5782
6118
  });
@@ -5789,6 +6125,96 @@ var init_rpc_client = __esm({
5789
6125
  }
5790
6126
  });
5791
6127
 
6128
+ // packages/runtime/src/functions/runtime/rpc-codec.ts
6129
+ function base64ToBytes(base643) {
6130
+ const binary = atob(base643);
6131
+ const bytes = new Uint8Array(binary.length);
6132
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
6133
+ return bytes;
6134
+ }
6135
+ function decodeRpcValue(value) {
6136
+ if (Array.isArray(value)) return value.map((entry) => decodeRpcValue(entry));
6137
+ if (typeof value !== "object" || value === null) return value;
6138
+ const nativeTag = Object.prototype.toString.call(value);
6139
+ if (ArrayBuffer.isView(value) || nativeTag === "[object ArrayBuffer]" || nativeTag === "[object Date]" || nativeTag === "[object Map]" || nativeTag === "[object Set]") {
6140
+ return value;
6141
+ }
6142
+ const candidate = value;
6143
+ const tag = candidate[RPC_VALUE_TAG_KEY];
6144
+ if (typeof tag !== "string") {
6145
+ const output2 = {};
6146
+ for (const [key, entry] of Object.entries(candidate)) output2[key] = decodeRpcValue(entry);
6147
+ return output2;
6148
+ }
6149
+ switch (tag) {
6150
+ case RPC_VALUE_TAGS.typedArray:
6151
+ return base64ToBytes(String(candidate["data"] ?? ""));
6152
+ case RPC_VALUE_TAGS.arrayBuffer: {
6153
+ const bytes = base64ToBytes(String(candidate["data"] ?? ""));
6154
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
6155
+ }
6156
+ case RPC_VALUE_TAGS.date:
6157
+ return new Date(String(candidate["data"] ?? ""));
6158
+ case RPC_VALUE_TAGS.map: {
6159
+ const entries = Array.isArray(candidate["data"]) ? candidate["data"] : [];
6160
+ const map2 = /* @__PURE__ */ new Map();
6161
+ for (const entry of entries) {
6162
+ if (!Array.isArray(entry) || entry.length < 2) continue;
6163
+ map2.set(decodeRpcValue(entry[0]), decodeRpcValue(entry[1]));
6164
+ }
6165
+ return map2;
6166
+ }
6167
+ case RPC_VALUE_TAGS.set: {
6168
+ const values = Array.isArray(candidate["data"]) ? candidate["data"] : [];
6169
+ return new Set(values.map((entry) => decodeRpcValue(entry)));
6170
+ }
6171
+ case RPC_VALUE_TAGS.undefined:
6172
+ return void 0;
6173
+ case RPC_VALUE_TAGS.number: {
6174
+ const raw = String(candidate["data"] ?? "");
6175
+ if (raw === "NaN") return Number.NaN;
6176
+ if (raw === "Infinity") return Number.POSITIVE_INFINITY;
6177
+ if (raw === "-Infinity") return Number.NEGATIVE_INFINITY;
6178
+ return Number(raw);
6179
+ }
6180
+ case RPC_VALUE_TAGS.bigint:
6181
+ return BigInt(String(candidate["data"] ?? "0"));
6182
+ case RPC_VALUE_TAGS.object: {
6183
+ const escaped = candidate["data"];
6184
+ if (typeof escaped !== "object" || escaped === null) return {};
6185
+ const output2 = {};
6186
+ for (const [key, entry] of Object.entries(escaped)) {
6187
+ output2[key] = decodeRpcValue(entry);
6188
+ }
6189
+ return output2;
6190
+ }
6191
+ default:
6192
+ return Object.fromEntries(
6193
+ Object.entries(candidate).filter(([key]) => key !== RPC_VALUE_TAG_KEY).map(([key, entry]) => [key, decodeRpcValue(entry)])
6194
+ );
6195
+ }
6196
+ }
6197
+ var RPC_VALUE_TAG_KEY, RPC_VALUE_TAGS, RPC_VALUE_MAX_BYTES;
6198
+ var init_rpc_codec = __esm({
6199
+ "packages/runtime/src/functions/runtime/rpc-codec.ts"() {
6200
+ "use strict";
6201
+ RPC_VALUE_TAG_KEY = "__adepRpcType";
6202
+ RPC_VALUE_TAGS = {
6203
+ typedArray: "Uint8Array",
6204
+ arrayBuffer: "ArrayBuffer",
6205
+ date: "Date",
6206
+ map: "Map",
6207
+ set: "Set",
6208
+ undefined: "undefined",
6209
+ number: "Number",
6210
+ bigint: "BigInt",
6211
+ /** 转义:用户对象自身带 `RPC_VALUE_TAG_KEY` 键时的包装形态。 */
6212
+ object: "Object"
6213
+ };
6214
+ RPC_VALUE_MAX_BYTES = 8 * 1024 * 1024;
6215
+ }
6216
+ });
6217
+
5792
6218
  // packages/runtime/src/functions/runtime/rpc-wire.ts
5793
6219
  function wireRpcResponses(port, pending) {
5794
6220
  port.on?.((message) => {
@@ -5797,13 +6223,14 @@ function wireRpcResponses(port, pending) {
5797
6223
  const entry = pending.get(reply.id);
5798
6224
  if (entry === void 0) return;
5799
6225
  pending.delete(reply.id);
5800
- if (reply.ok === true) entry.resolve(reply.result);
6226
+ if (reply.ok === true) entry.resolve(decodeRpcValue(reply.result));
5801
6227
  else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
5802
6228
  });
5803
6229
  }
5804
6230
  var init_rpc_wire = __esm({
5805
6231
  "packages/runtime/src/functions/runtime/rpc-wire.ts"() {
5806
6232
  "use strict";
6233
+ init_rpc_codec();
5807
6234
  }
5808
6235
  });
5809
6236
 
@@ -5814,9 +6241,9 @@ function isChainCapability(value) {
5814
6241
  return typeof spec === "object" && spec !== null && Array.isArray(spec.stepMethods) && Array.isArray(spec.terminalMethods);
5815
6242
  }
5816
6243
  function createChainClient(capability, port, pending, nextId, spec) {
5817
- const call = (method, args) => new Promise((resolve20, reject) => {
6244
+ const call = (method, args) => new Promise((resolve21, reject) => {
5818
6245
  const id = nextId();
5819
- pending.set(id, { resolve: resolve20, reject });
6246
+ pending.set(id, { resolve: resolve21, reject });
5820
6247
  port.postMessage({ type: "rpc", id, capability, method, args });
5821
6248
  });
5822
6249
  const makeChainable = (rootArgs, steps, txId) => new Proxy(
@@ -6731,18 +7158,12 @@ async function startDevServer(options) {
6731
7158
  } catch {
6732
7159
  }
6733
7160
  };
6734
- await new Promise((resolveListen, rejectListen) => {
6735
- const onListenError = (error62) => {
6736
- void disposeAfterListenError().finally(() => rejectListen(error62));
6737
- };
6738
- server.once("error", onListenError);
6739
- server.listen(port, "127.0.0.1", () => {
6740
- server.off("error", onListenError);
6741
- resolveListen();
6742
- });
7161
+ const actualPort = await listenOnFetchSafePort(server, {
7162
+ port,
7163
+ host: "127.0.0.1",
7164
+ warn: log,
7165
+ onListenError: disposeAfterListenError
6743
7166
  });
6744
- const address = server.address();
6745
- const actualPort = typeof address === "object" && address !== null ? address.port : port;
6746
7167
  const baseUrl = `http://127.0.0.1:${actualPort}`;
6747
7168
  const coldStartMs = Date.now() - coldStartAt;
6748
7169
  const curlPath = config2.functionsPrefix.length === 0 ? "/hello" : `/${config2.functionsPrefix}/hello`;
@@ -6782,6 +7203,7 @@ var init_dev = __esm({
6782
7203
  init_worker_executor();
6783
7204
  init_runtime();
6784
7205
  init_db_mode();
7206
+ init_fetch_safe_port();
6785
7207
  init_env();
6786
7208
  init_fetch_config();
6787
7209
  init_invoke();
@@ -7229,6 +7651,7 @@ var init_zip = __esm({
7229
7651
  this.buf = buf;
7230
7652
  this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
7231
7653
  }
7654
+ buf;
7232
7655
  view;
7233
7656
  u16(offset) {
7234
7657
  return this.view.getUint16(offset, true);
@@ -7946,18 +8369,7 @@ async function startServeServer(options) {
7946
8369
  }
7947
8370
  });
7948
8371
  });
7949
- const actualPort = await new Promise((resolveListen, rejectListen) => {
7950
- server.once("error", rejectListen);
7951
- server.listen(port, host, () => {
7952
- server.off("error", rejectListen);
7953
- const addr = server.address();
7954
- if (addr === null || typeof addr === "string") {
7955
- resolveListen(port);
7956
- } else {
7957
- resolveListen(addr.port);
7958
- }
7959
- });
7960
- });
8372
+ const actualPort = await listenOnFetchSafePort(server, { port, host, warn: log });
7961
8373
  const banner = renderBanner({
7962
8374
  host,
7963
8375
  port: actualPort,
@@ -8015,6 +8427,7 @@ var init_server = __esm({
8015
8427
  init_invoke();
8016
8428
  init_dev();
8017
8429
  init_banner();
8430
+ init_fetch_safe_port();
8018
8431
  init_staleness();
8019
8432
  init_template_params2();
8020
8433
  init_adep_env_inject();
@@ -8059,6 +8472,163 @@ var init_hash = __esm({
8059
8472
  }
8060
8473
  });
8061
8474
 
8475
+ // packages/cli/src/publish-checks.ts
8476
+ import { posix as posix3 } from "node:path";
8477
+ function formatFindings(findings) {
8478
+ const lines = findings.map(
8479
+ (finding) => `${finding.file}:${finding.line} [${finding.rule}] ${finding.severity === "error" ? "\u5371\u9669" : "\u8B66\u544A"}\uFF1A${finding.message}`
8480
+ );
8481
+ return [`\u53D1\u5E03\u524D\u9759\u6001\u6821\u9A8C\u53D1\u73B0 ${findings.length} \u4E2A\u95EE\u9898\uFF1A`, ...lines, "\u4FEE\u590D\u540E\u91CD\u8BD5\uFF1Bwarn \u7EA7\u53EF\u7528 --force \u653E\u884C\uFF0Cerror \u7EA7\u4E0D\u53EF\u653E\u884C\u3002"].join(
8482
+ "\n"
8483
+ );
8484
+ }
8485
+ function locate(content, index) {
8486
+ const before = content.slice(0, index);
8487
+ const line = before.split("\n").length;
8488
+ const start = before.lastIndexOf("\n") + 1;
8489
+ const end = content.indexOf("\n", index);
8490
+ return { line, text: content.slice(start, end === -1 ? content.length : end) };
8491
+ }
8492
+ function checkFilePath(functionName, file2) {
8493
+ const normalized = file2.split("\\").join("/");
8494
+ const segments = normalized.split("/");
8495
+ const escapes = normalized.startsWith("/") || segments.some((s) => ESCAPE_KEY_SEGMENTS.has(s));
8496
+ if (!escapes) return [];
8497
+ return [
8498
+ {
8499
+ rule: "PATH_ESCAPE",
8500
+ severity: "error",
8501
+ functionName,
8502
+ file: file2,
8503
+ line: 1,
8504
+ message: `bundle \u952E\u4E0D\u80FD\u662F\u7EDD\u5BF9\u8DEF\u5F84\u6216\u5305\u542B ".."\uFF08\u6536\u5230 "${file2}"\uFF09`
8505
+ }
8506
+ ];
8507
+ }
8508
+ function checkImportSpecifiers(functionName, file2, content) {
8509
+ const findings = [];
8510
+ for (const matched of content.matchAll(IMPORT_SPECIFIER)) {
8511
+ const specifier = matched[1] ?? "";
8512
+ if (!specifier.startsWith(".")) continue;
8513
+ const resolved = posix3.normalize(posix3.join(posix3.dirname(file2.split("\\").join("/")), specifier));
8514
+ if (!resolved.startsWith("..") && !posix3.isAbsolute(resolved)) continue;
8515
+ const { line } = locate(content, matched.index ?? 0);
8516
+ findings.push({
8517
+ rule: "PATH_ESCAPE",
8518
+ severity: "error",
8519
+ functionName,
8520
+ file: file2,
8521
+ line,
8522
+ message: `import "${specifier}" \u89E3\u6790\u5230 "${resolved}"\uFF0C\u9003\u51FA\u51FD\u6570 bundle \u6839`
8523
+ });
8524
+ }
8525
+ return findings;
8526
+ }
8527
+ function checkSqlConcat(functionName, file2, content) {
8528
+ const findings = [];
8529
+ for (const matched of content.matchAll(SQL_CALL)) {
8530
+ const arg = matched.groups?.["arg"] ?? "";
8531
+ if (!SQL_KEYWORD.test(arg) || !CONCAT_OR_TEMPLATE.test(arg)) continue;
8532
+ const { line } = locate(content, matched.index ?? 0);
8533
+ findings.push({
8534
+ rule: "SQL_CONCAT",
8535
+ severity: "error",
8536
+ functionName,
8537
+ file: file2,
8538
+ line,
8539
+ message: "SQL \u8BED\u53E5\u542B\u5B57\u7B26\u4E32\u62FC\u63A5 / \u6A21\u677F\u63D2\u503C\uFF1B\u6539\u7528\u53C2\u6570\u5316\u5360\u4F4D\u7B26\uFF08? / $1\uFF09"
8540
+ });
8541
+ }
8542
+ return findings;
8543
+ }
8544
+ function checkSecrets(functionName, file2, content) {
8545
+ const findings = [];
8546
+ const lines = content.split("\n");
8547
+ lines.forEach((text, index) => {
8548
+ for (const rule of SECRET_RULES) {
8549
+ if (!rule.pattern.test(text)) continue;
8550
+ findings.push({
8551
+ rule: "SECRET_LITERAL",
8552
+ severity: rule.severity,
8553
+ functionName,
8554
+ file: file2,
8555
+ line: index + 1,
8556
+ message: rule.message
8557
+ });
8558
+ }
8559
+ });
8560
+ return findings;
8561
+ }
8562
+ function collectPrecheckFindings(functions) {
8563
+ const findings = [];
8564
+ for (const [functionName, files] of Object.entries(functions).toSorted(
8565
+ ([a], [b]) => a.localeCompare(b)
8566
+ )) {
8567
+ const sortedFiles = Object.entries(files).toSorted(([a], [b]) => a.localeCompare(b));
8568
+ for (const [file2, content] of sortedFiles) {
8569
+ findings.push(...checkFilePath(functionName, file2));
8570
+ findings.push(...checkImportSpecifiers(functionName, file2, content));
8571
+ findings.push(...checkSqlConcat(functionName, file2, content));
8572
+ findings.push(...checkSecrets(functionName, file2, content));
8573
+ }
8574
+ }
8575
+ const seen = /* @__PURE__ */ new Set();
8576
+ return findings.filter((finding) => {
8577
+ const key = `${finding.rule}|${finding.functionName}|${finding.file}|${finding.line}|${finding.message}`;
8578
+ if (seen.has(key)) return false;
8579
+ seen.add(key);
8580
+ return true;
8581
+ }).toSorted(
8582
+ (a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.rule.localeCompare(b.rule)
8583
+ );
8584
+ }
8585
+ function assertPrechecks(functions, options = {}) {
8586
+ const findings = collectPrecheckFindings(functions);
8587
+ const errors = findings.filter((finding) => finding.severity === "error");
8588
+ const warnings = findings.filter((finding) => finding.severity === "warn");
8589
+ if (errors.length > 0) throw new PrecheckError(findings);
8590
+ if (warnings.length > 0 && options.force !== true) throw new PrecheckError(warnings);
8591
+ return warnings;
8592
+ }
8593
+ var PrecheckError, ESCAPE_KEY_SEGMENTS, IMPORT_SPECIFIER, SQL_CALL, SQL_KEYWORD, CONCAT_OR_TEMPLATE, SECRET_RULES;
8594
+ var init_publish_checks = __esm({
8595
+ "packages/cli/src/publish-checks.ts"() {
8596
+ "use strict";
8597
+ init_auth();
8598
+ PrecheckError = class extends CliError {
8599
+ findings;
8600
+ constructor(findings) {
8601
+ super("PRECHECK_FAILED", formatFindings(findings));
8602
+ this.name = "PrecheckError";
8603
+ this.findings = findings;
8604
+ }
8605
+ };
8606
+ ESCAPE_KEY_SEGMENTS = /* @__PURE__ */ new Set([".."]);
8607
+ IMPORT_SPECIFIER = /(?:from\s*|import\s*|require\s*\(\s*)['"]([^'"]+)['"]/g;
8608
+ SQL_CALL = /\.(?:query|execute|run|all|get|prepare)\s*\(\s*(?<arg>[^\n]*)/g;
8609
+ SQL_KEYWORD = /\b(?:SELECT|INSERT|UPDATE|DELETE|REPLACE|WITH|WHERE|FROM)\b/i;
8610
+ CONCAT_OR_TEMPLATE = /(?:\$\{|`\s*\+|\+\s*['"`]|['"`]\s*\+)/;
8611
+ SECRET_RULES = [
8612
+ {
8613
+ pattern: /-----BEGIN (?:RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----/,
8614
+ message: "\u6E90\u7801\u542B PEM \u79C1\u94A5\u660E\u6587",
8615
+ severity: "error"
8616
+ },
8617
+ { pattern: /AKIA[0-9A-Z]{16}/, message: "\u6E90\u7801\u542B AWS Access Key \u660E\u6587", severity: "error" },
8618
+ {
8619
+ pattern: /(?:sk|pk)_(?:live|test)_[0-9A-Za-z]{16,}/,
8620
+ message: "\u6E90\u7801\u542B\u652F\u4ED8\u6E20\u9053\u5BC6\u94A5\u660E\u6587",
8621
+ severity: "error"
8622
+ },
8623
+ {
8624
+ pattern: /(?:password|passwd|secret|api[_-]?key|access[_-]?token)\s*[:=]\s*['"][^'"]{8,}['"]/i,
8625
+ message: "\u7591\u4F3C\u5BC6\u94A5 / \u53E3\u4EE4\u786C\u7F16\u7801\uFF1B\u6539\u4ECE ctx.env / \u5E73\u53F0\u73AF\u5883\u53D8\u91CF\u8BFB\u53D6",
8626
+ severity: "warn"
8627
+ }
8628
+ ];
8629
+ }
8630
+ });
8631
+
8062
8632
  // packages/cli/src/deploy.ts
8063
8633
  var deploy_exports = {};
8064
8634
  __export(deploy_exports, {
@@ -8164,6 +8734,10 @@ async function deploy(paths, options) {
8164
8734
  }
8165
8735
  const shared = await collectShared(functionsDir);
8166
8736
  const filesFor = (name) => local[name] ?? {};
8737
+ const precheckWarnings = assertPrechecks(local, { force: options.force === true });
8738
+ for (const finding of precheckWarnings) {
8739
+ log(`[adep] \u6821\u9A8C\u8B66\u544A ${finding.file}:${finding.line} [${finding.rule}] ${finding.message}`);
8740
+ }
8167
8741
  const sharedRows = Object.entries(shared).map(([path, content]) => ({ path, content }));
8168
8742
  const hashFiles = (name) => {
8169
8743
  const filesAsRuntimeSees = mergeSharedSource(filesFor(name), sharedRows);
@@ -8264,6 +8838,7 @@ var init_deploy = __esm({
8264
8838
  init_hash();
8265
8839
  init_dev();
8266
8840
  init_net();
8841
+ init_publish_checks();
8267
8842
  init_shared_source();
8268
8843
  init_shared_source();
8269
8844
  AmbiguousFunctionError = class extends CliError {
@@ -8275,6 +8850,7 @@ var init_deploy = __esm({
8275
8850
  this.names = names;
8276
8851
  this.name = "AmbiguousFunctionError";
8277
8852
  }
8853
+ names;
8278
8854
  };
8279
8855
  IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git"]);
8280
8856
  }
@@ -8743,11 +9319,11 @@ var fs_exports = {};
8743
9319
  __export(fs_exports, {
8744
9320
  createExportFileSystem: () => createExportFileSystem
8745
9321
  });
8746
- import { mkdir as mkdir16, readFile as readFile27, rm as rm5, stat as stat17, writeFile as writeFile16 } from "node:fs/promises";
9322
+ import { mkdir as mkdir16, readFile as readFile28, rm as rm5, stat as stat17, writeFile as writeFile16 } from "node:fs/promises";
8747
9323
  import { dirname as dirname14, join as join36 } from "node:path";
8748
9324
  function createExportFileSystem() {
8749
9325
  return {
8750
- readFile: (path) => readFile27(path),
9326
+ readFile: (path) => readFile28(path),
8751
9327
  writeFile: (path, content) => writeFile16(path, content),
8752
9328
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
8753
9329
  deleteFile: async (path) => {
@@ -8765,7 +9341,7 @@ function createExportFileSystem() {
8765
9341
  await mkdir16(path, { recursive: true });
8766
9342
  },
8767
9343
  unzip: async (zipPath, targetDir) => {
8768
- const entries = zipRead(await readFile27(zipPath));
9344
+ const entries = zipRead(await readFile28(zipPath));
8769
9345
  for (const [name, data] of entries) {
8770
9346
  const dest = join36(targetDir, name);
8771
9347
  await mkdir16(dirname14(dest), { recursive: true });
@@ -8799,6 +9375,10 @@ var init_command = __esm({
8799
9375
  this.pollInterval = pollInterval;
8800
9376
  this.maxPollAttempts = maxPollAttempts;
8801
9377
  }
9378
+ apiClient;
9379
+ fs;
9380
+ pollInterval;
9381
+ maxPollAttempts;
8802
9382
  /**
8803
9383
  * 执行导出命令。
8804
9384
  *
@@ -9006,14 +9586,14 @@ ${detail}`);
9006
9586
  * @param ms 毫秒数
9007
9587
  */
9008
9588
  sleep(ms) {
9009
- return new Promise((resolve20) => setTimeout(resolve20, ms));
9589
+ return new Promise((resolve21) => setTimeout(resolve21, ms));
9010
9590
  }
9011
9591
  };
9012
9592
  }
9013
9593
  });
9014
9594
 
9015
9595
  // packages/cli/src/sandbox-scan.ts
9016
- import { readdir as readdir13, readFile as readFile28 } from "node:fs/promises";
9596
+ import { readdir as readdir13, readFile as readFile30 } from "node:fs/promises";
9017
9597
  import { join as join37, relative as relative9, sep as sep5 } from "node:path";
9018
9598
  function extractSpecifiers(line) {
9019
9599
  const out = [];
@@ -9079,7 +9659,7 @@ async function scanFunctionSources(rootDir, functionsDir) {
9079
9659
  if (entry.name.endsWith(".d.ts")) continue;
9080
9660
  let content;
9081
9661
  try {
9082
- content = await readFile28(abs, "utf8");
9662
+ content = await readFile30(abs, "utf8");
9083
9663
  } catch {
9084
9664
  continue;
9085
9665
  }
@@ -9353,7 +9933,7 @@ __export(mcp_exports, {
9353
9933
  mcpPublish: () => mcpPublish,
9354
9934
  mcpUnpublish: () => mcpUnpublish
9355
9935
  });
9356
- import { resolve as resolve18 } from "node:path";
9936
+ import { resolve as resolve19 } from "node:path";
9357
9937
  async function mcpPublish(paths, options) {
9358
9938
  const fn = requireFunctionName(options.fn);
9359
9939
  const client = await createClient(paths);
@@ -9434,7 +10014,7 @@ function requireFunctionName(fn) {
9434
10014
  return fn.trim();
9435
10015
  }
9436
10016
  async function resolveProject(client, options) {
9437
- const slug = await resolveSlug(resolve18(options.cwd), options.slug);
10017
+ const slug = await resolveSlug(resolve19(options.cwd), options.slug);
9438
10018
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
9439
10019
  const match = listed.projects.find((project2) => project2.slug === slug);
9440
10020
  if (match === void 0) {
@@ -9619,9 +10199,11 @@ var init_git = __esm({
9619
10199
  var functions_exports = {};
9620
10200
  __export(functions_exports, {
9621
10201
  functionsList: () => functionsList,
9622
- functionsLogs: () => functionsLogs
10202
+ functionsLogs: () => functionsLogs,
10203
+ logsByTrace: () => logsByTrace,
10204
+ resolveProject: () => resolveProject2
9623
10205
  });
9624
- import { resolve as resolve19 } from "node:path";
10206
+ import { resolve as resolve20 } from "node:path";
9625
10207
  async function functionsList(paths, options) {
9626
10208
  const client = await createClient(paths);
9627
10209
  const project2 = await resolveProject2(client, options);
@@ -9662,8 +10244,24 @@ async function functionsLogs(paths, options) {
9662
10244
  );
9663
10245
  return { functionId: target.id, name: target.name, logs: result.logs };
9664
10246
  }
10247
+ async function logsByTrace(paths, options) {
10248
+ const trace = options.trace.trim();
10249
+ if (trace.length === 0) {
10250
+ throw new CliError("INVALID_ARGUMENT", "\u7F3A\u5C11 traceId\uFF1Aadep logs --trace <traceId>");
10251
+ }
10252
+ const client = await createClient(paths);
10253
+ const project2 = await resolveProject2(client, options);
10254
+ const params = new URLSearchParams({ trace });
10255
+ if (options.tail !== void 0) params.set("tail", String(options.tail));
10256
+ const result = await client.request(
10257
+ `/api/v1/projects/${project2.id}/logs?${params.toString()}`,
10258
+ {},
10259
+ "FUNCTION_LOGS_FAILED"
10260
+ );
10261
+ return { projectId: project2.id, slug: project2.slug, traceId: result.traceId, logs: result.logs };
10262
+ }
9665
10263
  async function resolveProject2(client, options) {
9666
- const slug = await resolveSlug(resolve19(options.cwd), options.slug);
10264
+ const slug = await resolveSlug(resolve20(options.cwd), options.slug);
9667
10265
  const projects = await projectsListFrom(client);
9668
10266
  const match = projects.find((project2) => project2.slug === slug);
9669
10267
  if (match === void 0) {
@@ -9686,6 +10284,65 @@ var init_functions = __esm({
9686
10284
  }
9687
10285
  });
9688
10286
 
10287
+ // packages/cli/src/rollback.ts
10288
+ var rollback_exports = {};
10289
+ __export(rollback_exports, {
10290
+ parseVersionFlag: () => parseVersionFlag,
10291
+ rollbackFunctionTo: () => rollbackFunctionTo
10292
+ });
10293
+ function parseVersionFlag(raw) {
10294
+ const text = (raw ?? "").trim();
10295
+ const matched = /^v?(\d+)$/.exec(text);
10296
+ const version2 = matched === null ? Number.NaN : Number(matched[1]);
10297
+ if (!Number.isInteger(version2) || version2 <= 0) {
10298
+ throw new CliError("INVALID_ARGUMENT", `--to \u987B\u4E3A\u7248\u672C\u53F7\uFF08\u5982 v2 \u6216 2\uFF09\uFF0C\u6536\u5230 "${raw ?? ""}"`);
10299
+ }
10300
+ return version2;
10301
+ }
10302
+ async function rollbackFunctionTo(paths, options) {
10303
+ if (!Number.isInteger(options.to) || options.to <= 0) {
10304
+ throw new CliError("INVALID_ARGUMENT", `--to \u987B\u4E3A\u6B63\u6574\u6570\uFF0C\u6536\u5230 ${options.to}`);
10305
+ }
10306
+ const client = await createClient(paths);
10307
+ const project2 = await resolveProject2(client, options);
10308
+ const listed = await client.request(
10309
+ `/api/v1/projects/${project2.id}/functions`,
10310
+ {},
10311
+ "FUNCTION_LIST_FAILED"
10312
+ );
10313
+ const target = listed.functions.find((fn) => fn.name === options.name);
10314
+ if (target === void 0) {
10315
+ throw new CliError("FN_NOT_FOUND", `\u51FD\u6570 "${options.name}" \u4E0D\u5B58\u5728\u4E8E\u9879\u76EE "${project2.slug}"`);
10316
+ }
10317
+ const versions = await client.request(`/api/v1/functions/${target.id}/versions`, {}, "FUNCTION_VERSIONS_FAILED");
10318
+ if (!versions.versions.some((version2) => version2.version === options.to)) {
10319
+ const available = versions.versions.map((version2) => `v${version2.version}`).join(", ");
10320
+ throw new CliError(
10321
+ "VERSION_NOT_FOUND",
10322
+ `\u7248\u672C v${options.to} \u4E0D\u5728\u4FDD\u7559\u7A97\u53E3\u5185\uFF08\u5F53\u524D v${versions.current ?? "\u2014"}\uFF1B\u53EF\u7528\uFF1A${available === "" ? "\u65E0" : available}\uFF09`
10323
+ );
10324
+ }
10325
+ const result = await client.request(
10326
+ `/api/v1/functions/${target.id}/rollback`,
10327
+ { method: "POST", body: { version: options.to } },
10328
+ "ROLLBACK_FAILED"
10329
+ );
10330
+ return {
10331
+ functionId: target.id,
10332
+ name: target.name,
10333
+ from: versions.current,
10334
+ to: result.version
10335
+ };
10336
+ }
10337
+ var init_rollback = __esm({
10338
+ "packages/cli/src/rollback.ts"() {
10339
+ "use strict";
10340
+ init_auth();
10341
+ init_client();
10342
+ init_functions();
10343
+ }
10344
+ });
10345
+
9689
10346
  // packages/cli/src/cli.ts
9690
10347
  init_config();
9691
10348
  import { Command } from "commander";
@@ -13019,6 +13676,7 @@ var TemplateRenderError = class extends Error {
13019
13676
  this.code = code;
13020
13677
  this.name = "TemplateRenderError";
13021
13678
  }
13679
+ code;
13022
13680
  };
13023
13681
  var PLACEHOLDER_PATTERN = /\{\{\s*([A-Za-z0-9_-]+)\s*\}\}/g;
13024
13682
  function declaredVariables(manifest) {
@@ -13141,6 +13799,7 @@ var InitError = class extends Error {
13141
13799
  this.code = code;
13142
13800
  this.name = "InitError";
13143
13801
  }
13802
+ code;
13144
13803
  };
13145
13804
  async function initProject(cwd, name, template, filesOverride) {
13146
13805
  if (!/^[a-z][a-z0-9-]{0,62}$/.test(name)) {
@@ -18920,7 +19579,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
18920
19579
  var NONE = 0;
18921
19580
  var ASSUMED = 1;
18922
19581
  var PROVEN = 2;
18923
- function isRecursive(inst, stack, resolve20) {
19582
+ function isRecursive(inst, stack, resolve21) {
18924
19583
  const cached2 = recursive.get(inst);
18925
19584
  if (cached2 !== void 0)
18926
19585
  return cached2 ? PROVEN : NONE;
@@ -18930,7 +19589,7 @@ function isRecursive(inst, stack, resolve20) {
18930
19589
  let result = NONE;
18931
19590
  const check2 = (child) => {
18932
19591
  if (result !== PROVEN && child?._zod) {
18933
- const answer = isRecursive(child, stack, resolve20);
19592
+ const answer = isRecursive(child, stack, resolve21);
18934
19593
  if (answer > result)
18935
19594
  result = answer;
18936
19595
  }
@@ -18941,7 +19600,7 @@ function isRecursive(inst, stack, resolve20) {
18941
19600
  const desc = Object.getOwnPropertyDescriptor(sh, key);
18942
19601
  if (spread && !desc.enumerable)
18943
19602
  continue;
18944
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve20) : NONE;
19603
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve21) : NONE;
18945
19604
  if (child > answer)
18946
19605
  answer = child;
18947
19606
  }
@@ -19005,7 +19664,7 @@ function isRecursive(inst, stack, resolve20) {
19005
19664
  break;
19006
19665
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
19007
19666
  case "lazy": {
19008
- const inner = def._cachedInner ?? (resolve20 ? inst._zod.innerType : void 0);
19667
+ const inner = def._cachedInner ?? (resolve21 ? inst._zod.innerType : void 0);
19009
19668
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
19010
19669
  break;
19011
19670
  }
@@ -26796,8 +27455,8 @@ function registry() {
26796
27455
  var globalRegistry = globalThis.__zod_globalRegistry;
26797
27456
 
26798
27457
  // node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/compile.js
26799
- var INVALID = Symbol.for("zod.compile.invalid");
26800
- var FALLBACK_FLAG = Symbol.for("zod.compile.fallback");
27458
+ var INVALID = /* @__PURE__ */ Symbol.for("zod.compile.invalid");
27459
+ var FALLBACK_FLAG = /* @__PURE__ */ Symbol.for("zod.compile.fallback");
26801
27460
  var ZodCompileAsyncError = class extends Error {
26802
27461
  constructor(message = "z.compile does not support async refinements, transforms, or checks") {
26803
27462
  super(message);
@@ -30585,7 +31244,7 @@ var nonoptionalProcessor = (schema, ctx, _json, params) => {
30585
31244
  const seen = ctx.seen.get(schema);
30586
31245
  seen.ref = def.innerType;
30587
31246
  };
30588
- var UNREPRESENTABLE_DEFAULT = Symbol();
31247
+ var UNREPRESENTABLE_DEFAULT = /* @__PURE__ */ Symbol();
30589
31248
  function serializeDefaultValue(value, schema, ctx, json2, params) {
30590
31249
  let unrepresentable = false;
30591
31250
  const serialized = JSON.stringify(value, (_, val) => {
@@ -33349,7 +34008,7 @@ function fromJSONSchema(schema, params) {
33349
34008
  }
33350
34009
 
33351
34010
  // node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/visit.js
33352
- var RESOLVING = Symbol("z.visit/resolving");
34011
+ var RESOLVING = /* @__PURE__ */ Symbol("z.visit/resolving");
33353
34012
  function visit(schema, fnOrHandlers) {
33354
34013
  const fn = typeof fnOrHandlers === "function" ? fnOrHandlers : (node2, rewritten) => {
33355
34014
  const h = fnOrHandlers[node2._zod.def.type];
@@ -35574,6 +36233,9 @@ var SyncTransportError = class extends Error {
35574
36233
  this.failedSeq = failedSeq;
35575
36234
  this.name = "SyncTransportError";
35576
36235
  }
36236
+ code;
36237
+ status;
36238
+ failedSeq;
35577
36239
  };
35578
36240
  function isBindable(value) {
35579
36241
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
@@ -37071,7 +37733,7 @@ function registerDevServers(program2, ctx) {
37071
37733
  init_auth();
37072
37734
  init_client();
37073
37735
  init_deploy();
37074
- import { stat as stat16 } from "node:fs/promises";
37736
+ import { readFile as readFile26, stat as stat16 } from "node:fs/promises";
37075
37737
  import { join as join34, resolve as resolve16 } from "node:path";
37076
37738
  async function resolveProjectId2(client, cwd, slug) {
37077
37739
  const resolvedSlug = await resolveSlug(resolve16(cwd), slug);
@@ -37154,6 +37816,58 @@ async function publishFunctions(paths, options) {
37154
37816
  const deployedCount = result.functions.filter((fn) => fn.action !== "none").length;
37155
37817
  return { ...result, elapsedSeconds, deployedCount };
37156
37818
  }
37819
+ async function checkSchemaDrift(paths, options) {
37820
+ const schemaFile = join34(options.cwd, "database", "schema.sql");
37821
+ const schemaStat = await stat16(schemaFile).catch(() => null);
37822
+ if (schemaStat === null || !schemaStat.isFile()) {
37823
+ options.log("[adep] \u672A\u627E\u5230 database/schema.sql\uFF0C\u8DF3\u8FC7 schema \u6F02\u79FB\u68C0\u67E5");
37824
+ return null;
37825
+ }
37826
+ const sql = await readFile26(schemaFile, "utf8");
37827
+ const { dbSchemaDiff: dbSchemaDiff2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
37828
+ let drift;
37829
+ try {
37830
+ drift = await dbSchemaDiff2(paths, {
37831
+ cwd: options.cwd,
37832
+ sql,
37833
+ ...options.slug === void 0 ? {} : { slug: options.slug },
37834
+ log: options.log
37835
+ });
37836
+ } catch (error62) {
37837
+ if (error62 instanceof CliError && (error62.code === "DB_NOT_PROVISIONED" || error62.code === "DB_NOT_FOUND")) {
37838
+ options.log("[adep] \u6570\u636E\u5E93\u5C1A\u672A\u542F\u52A8\uFF0C\u8DF3\u8FC7 schema \u6F02\u79FB\u68C0\u67E5\uFF08\u5148 adep db start \u540E\u53D1\u5E03\u53EF\u542F\u7528\uFF09");
37839
+ return null;
37840
+ }
37841
+ throw error62;
37842
+ }
37843
+ const blocking = drift.missingTables.length > 0 || drift.missingColumns.length > 0 || drift.typeMismatches.length > 0;
37844
+ if (drift.destructiveStatements.length > 0) {
37845
+ options.log(
37846
+ `[adep] \u26A0 schema.sql \u542B\u7834\u574F\u6027\u8BED\u53E5\uFF08\u4E0D\u4F1A\u88AB\u81EA\u52A8\u6267\u884C\uFF09\uFF1A${drift.destructiveStatements.join(" \xB7 ")}`
37847
+ );
37848
+ }
37849
+ if (!blocking) {
37850
+ options.log("[adep] \u2713 schema \u65E0\u6F02\u79FB");
37851
+ return drift;
37852
+ }
37853
+ if (options.allowDrift === true) {
37854
+ options.log("[adep] \u26A0 schema \u6F02\u79FB\u88AB --allow-drift \u653E\u884C\uFF1A\u7EBF\u4E0A\u51FD\u6570\u53EF\u80FD no such column");
37855
+ return drift;
37856
+ }
37857
+ const lines = ["\u68C0\u6D4B\u5230 schema \u6F02\u79FB\uFF0C\u53D1\u5E03\u5DF2\u963B\u65AD\uFF08\u4E91\u51FD\u6570\u4F1A\u76F4\u63A5 no such column\uFF09\uFF1A"];
37858
+ for (const item of drift.missingTables) lines.push(` +table ${item.table}`);
37859
+ for (const item of drift.missingColumns) {
37860
+ lines.push(` +column ${item.table}.${item.column.name}`);
37861
+ }
37862
+ for (const item of drift.typeMismatches) {
37863
+ lines.push(` !type ${item.table}.${item.column}\uFF08\u671F\u671B ${item.expected}\uFF0C\u7EBF\u4E0A ${item.actual}\uFF09`);
37864
+ }
37865
+ lines.push("\u4E0B\u4E00\u6B65\uFF1Aadep db migrate database/schema.sql");
37866
+ lines.push(" \u67E5\u770B\u8BA1\u5212\uFF1Aadep db migrate database/schema.sql --plan");
37867
+ lines.push(" \u5168\u5E93\u6F02\u79FB\u62A5\u544A\uFF1Aadep db doctor");
37868
+ lines.push("\u786E\u8BA4\u53EF\u5BB9\u5FCD\u6F02\u79FB\u65F6\u7528 adep publish --allow-drift \u653E\u884C\uFF08\u4E0D\u63A8\u8350\uFF1A\u4E0A\u7EBF\u5373 500\uFF09");
37869
+ throw new CliError("SCHEMA_DRIFT_DETECTED", lines.join("\n"));
37870
+ }
37157
37871
  async function runPublish(paths, io, cwd, flags) {
37158
37872
  const scope = flags.only === void 0 ? "fullstack" : flags.only;
37159
37873
  if (flags.only !== void 0 && flags.only !== "functions" && flags.only !== "frontend") {
@@ -37164,6 +37878,12 @@ async function runPublish(paths, io, cwd, flags) {
37164
37878
  const environment = flags.environment;
37165
37879
  const result = { scope };
37166
37880
  if (wantFunctions) {
37881
+ await checkSchemaDrift(paths, {
37882
+ cwd,
37883
+ ...flags.project === void 0 ? {} : { slug: flags.project },
37884
+ log: io.json ? () => void 0 : (line) => io.line(line),
37885
+ ...flags.allowDrift === void 0 ? {} : { allowDrift: flags.allowDrift }
37886
+ });
37167
37887
  result.functions = await publishFunctions(paths, {
37168
37888
  cwd,
37169
37889
  ...flags.project === void 0 ? {} : { slug: flags.project },
@@ -37257,6 +37977,9 @@ function registerPublish(program2, ctx) {
37257
37977
  ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option(
37258
37978
  "--force",
37259
37979
  "\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"
37980
+ ).option(
37981
+ "--allow-drift",
37982
+ "\u653E\u884C schema \u6F02\u79FB\uFF08\u7F3A\u8868/\u7F3A\u5217/\u7C7B\u578B\u4E0D\u4E00\u81F4\u65F6\u53D1\u5E03\u9ED8\u8BA4\u88AB\u963B\u65AD\uFF0C\u786E\u8BA4\u53EF\u5BB9\u5FCD\u540E\u4F7F\u7528\uFF1B\u4E0D\u63A8\u8350\uFF0C\u7EBF\u4E0A\u51FD\u6570\u4F1A no such column\uFF09"
37260
37983
  ).action(async (flags) => {
37261
37984
  const command = ctx.io("publish");
37262
37985
  await command.run(async () => {
@@ -37281,7 +38004,7 @@ init_auth();
37281
38004
  // packages/cli/src/deploy-worker.ts
37282
38005
  init_auth();
37283
38006
  init_client();
37284
- import { readdir as readdir12, readFile as readFile26 } from "node:fs/promises";
38007
+ import { readdir as readdir12, readFile as readFile27 } from "node:fs/promises";
37285
38008
  import { join as join35, relative as relative8, resolve as resolve17, sep as sep4 } from "node:path";
37286
38009
  async function collectWranglerFiles(dir) {
37287
38010
  const root = resolve17(dir);
@@ -37303,7 +38026,7 @@ async function collectWranglerFiles(dir) {
37303
38026
  if (entry.isDirectory()) {
37304
38027
  await walk(full);
37305
38028
  } else if (entry.isFile()) {
37306
- const buf = await readFile26(full).catch(() => null);
38029
+ const buf = await readFile27(full).catch(() => null);
37307
38030
  if (buf === null) continue;
37308
38031
  if (buf.includes(0)) continue;
37309
38032
  out[relative8(root, full).split(sep4).join("/")] = buf.toString("utf8");
@@ -37502,6 +38225,35 @@ function registerExport(program2, ctx) {
37502
38225
  }
37503
38226
 
37504
38227
  // packages/cli/src/commands/db.ts
38228
+ import { readFile as readFile29 } from "node:fs/promises";
38229
+ import { resolve as resolve18 } from "node:path";
38230
+ init_db2();
38231
+ function renderDrift(diff) {
38232
+ const lines = [];
38233
+ for (const table of diff.missingTables) lines.push(`+table ${table.table}`);
38234
+ for (const column of diff.missingColumns) {
38235
+ lines.push(
38236
+ `+column ${column.table}.${column.column.name} ${column.column.type}` + (column.blocked === null ? ` \u2192 ${column.sql}` : ` [\u62D2\u7EDD\u81EA\u52A8\u6267\u884C] ${column.blocked}`)
38237
+ );
38238
+ }
38239
+ for (const mismatch of diff.typeMismatches) {
38240
+ lines.push(
38241
+ `!type ${mismatch.table}.${mismatch.column} \u7EBF\u4E0A ${mismatch.actual || "(\u65E0\u7C7B\u578B)"} \u2192 schema ${mismatch.expected}`
38242
+ );
38243
+ }
38244
+ for (const table of diff.extraTables) lines.push(`-table ${table}\uFF08\u7EBF\u4E0A\u6709\u3001schema \u672A\u58F0\u660E\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u5220\u9664\uFF09`);
38245
+ for (const column of diff.extraColumns) {
38246
+ lines.push(`-column ${column.table}.${column.column}\uFF08\u7EBF\u4E0A\u6709\u3001schema \u672A\u58F0\u660E\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u5220\u9664\uFF09`);
38247
+ }
38248
+ for (const statement of diff.destructiveStatements) {
38249
+ lines.push(`!ddl ${statement.replace(/\s+/g, " ").slice(0, 120)}`);
38250
+ }
38251
+ if (lines.length === 0) return ["\u2713 schema \u4E0E\u7EBF\u4E0A\u4E00\u81F4\uFF0C\u65E0\u6F02\u79FB"];
38252
+ if (!diff.applicable) {
38253
+ lines.push("", "\u5B58\u5728\u7834\u574F\u6027 / \u4E0D\u53EF\u81EA\u52A8\u6267\u884C\u7684\u53D8\u66F4\uFF1A\u5DF2\u62D2\u7EDD\u81EA\u52A8\u5E94\u7528\uFF0C\u8BF7\u5907\u4EFD\u540E\u624B\u5DE5\u5904\u7406\u3002");
38254
+ }
38255
+ return lines;
38256
+ }
37505
38257
  function registerDb(program2, ctx) {
37506
38258
  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");
37507
38259
  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) => {
@@ -37544,33 +38296,66 @@ function registerDb(program2, ctx) {
37544
38296
  });
37545
38297
  });
37546
38298
  db.command("exec").description(
37547
- "\u6267\u884C\u5355\u6761 SQL\uFF08\u5199 / \u7834\u574F\u6027\u8BED\u53E5\u9700 --confirm-table \u4E8C\u6B21\u786E\u8BA4\uFF09\u3002\u53D7\u5168\u5C40 --env \u5F71\u54CD\uFF1Adev \u6253\u5F00\u53D1\u5E93\u3001prod \u6253\u751F\u4EA7\u5E93"
37548
- ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").requiredOption("--sql <sql>", "\u5F85\u6267\u884C SQL").option("--confirm-table <table>", "\u7834\u574F\u6027\u64CD\u4F5C\u7684\u76EE\u6807\u8868\u540D\uFF08\u4E8C\u6B21\u786E\u8BA4\uFF09").action(async (flags) => {
38299
+ "\u6267\u884C\u5355\u6761 SQL \u6216\u6279\u91CF SQL \u6587\u4EF6\uFF08\u5355\u4E8B\u52A1\uFF1B\u5199 / \u7834\u574F\u6027\u8BED\u53E5\u9700 --confirm-table \u4E8C\u6B21\u786E\u8BA4\uFF09\u3002\u53D7\u5168\u5C40 --env \u5F71\u54CD\uFF1Adev \u6253\u5F00\u53D1\u5E93\u3001prod \u6253\u751F\u4EA7\u5E93"
38300
+ ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option("--sql <sql>", "\u5F85\u6267\u884C SQL\uFF08\u5355\u6761\uFF09").option("--file <path>", "\u6279\u91CF SQL \u6587\u4EF6\uFF08\u5355\u4E8B\u52A1\uFF0C\u4EFB\u4E00\u6761\u5931\u8D25\u6574\u4F53\u56DE\u6EDA\uFF09").option("--confirm-table <table>", "\u7834\u574F\u6027\u64CD\u4F5C\u7684\u76EE\u6807\u8868\u540D\uFF08\u4E8C\u6B21\u786E\u8BA4\uFF09").action(async (flags) => {
37549
38301
  const command = ctx.io("db exec");
37550
38302
  await command.run(async () => {
38303
+ if (flags.sql !== void 0 && flags.file !== void 0) {
38304
+ command.fail("INVALID_ARGS", "--sql \u4E0E --file \u53EA\u80FD\u4E8C\u9009\u4E00");
38305
+ return;
38306
+ }
38307
+ if (flags.sql === void 0 && flags.file === void 0) {
38308
+ command.fail("INVALID_ARGS", "\u9700\u8981 --sql <sql> \u6216 --file <path>");
38309
+ return;
38310
+ }
37551
38311
  const { environment, source } = await ctx.env();
37552
- const { dbExec: dbExec2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
37553
- const result = await dbExec2(ctx.paths, {
37554
- cwd: ctx.cwd,
37555
- sql: flags.sql,
37556
- environment,
37557
- ...flags.project === void 0 ? {} : { slug: flags.project },
37558
- ...flags.confirmTable === void 0 ? {} : { confirmTable: flags.confirmTable }
37559
- });
37560
- command.ok(result, (data) => {
37561
- const r = data;
37562
- const lines = [];
37563
- if (r.columns.length > 0) {
37564
- lines.push(formatTable(r.columns, r.rows));
37565
- if (r.truncated) lines.push(`\uFF08\u7ED3\u679C\u5DF2\u622A\u65AD\u5230 ${r.rows.length} \u884C\uFF09`);
37566
- } else if (r.changes > 0) {
37567
- lines.push(`${r.changes} \u884C\u53D7\u5F71\u54CD`);
37568
- } else {
37569
- lines.push("\u8BED\u53E5\u6267\u884C\u6210\u529F\uFF08\u65E0\u8FD4\u56DE\u884C\uFF09");
38312
+ if (flags.file !== void 0) {
38313
+ const { dbExecBatch: dbExecBatch2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
38314
+ const sql = await readFile29(resolve18(flags.file), "utf8");
38315
+ const statements = splitSqlStatements(sql);
38316
+ if (statements.length === 0) {
38317
+ command.fail("EMPTY_FILE", `SQL \u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${flags.file}`);
38318
+ return;
37570
38319
  }
37571
- lines.push(`\u8017\u65F6 ${r.elapsedMs}ms`);
37572
- return lines;
37573
- });
38320
+ const result = await dbExecBatch2(ctx.paths, {
38321
+ cwd: ctx.cwd,
38322
+ statements,
38323
+ environment,
38324
+ ...flags.project === void 0 ? {} : { slug: flags.project },
38325
+ ...flags.confirmTable === void 0 ? {} : { confirmTables: statements.map(() => flags.confirmTable) }
38326
+ });
38327
+ command.ok(result, (data) => {
38328
+ const results = data.results;
38329
+ const total = results.reduce((sum, entry) => sum + entry.changes, 0);
38330
+ return [
38331
+ `\u2713 ${results.length} \u6761\u8BED\u53E5\u5DF2\u5728\u4E00\u4E2A\u4E8B\u52A1\u5185\u63D0\u4EA4`,
38332
+ `${total} \u884C\u53D7\u5F71\u54CD`
38333
+ ];
38334
+ });
38335
+ } else {
38336
+ const { dbExec: dbExec2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
38337
+ const result = await dbExec2(ctx.paths, {
38338
+ cwd: ctx.cwd,
38339
+ sql: flags.sql,
38340
+ environment,
38341
+ ...flags.project === void 0 ? {} : { slug: flags.project },
38342
+ ...flags.confirmTable === void 0 ? {} : { confirmTable: flags.confirmTable }
38343
+ });
38344
+ command.ok(result, (data) => {
38345
+ const r = data;
38346
+ const lines = [];
38347
+ if (r.columns.length > 0) {
38348
+ lines.push(formatTable(r.columns, r.rows));
38349
+ if (r.truncated) lines.push(`\uFF08\u7ED3\u679C\u5DF2\u622A\u65AD\u5230 ${r.rows.length} \u884C\uFF09`);
38350
+ } else if (r.changes > 0) {
38351
+ lines.push(`${r.changes} \u884C\u53D7\u5F71\u54CD`);
38352
+ } else {
38353
+ lines.push("\u8BED\u53E5\u6267\u884C\u6210\u529F\uFF08\u65E0\u8FD4\u56DE\u884C\uFF09");
38354
+ }
38355
+ lines.push(`\u8017\u65F6 ${r.elapsedMs}ms`);
38356
+ return lines;
38357
+ });
38358
+ }
37574
38359
  command.line(
37575
38360
  `\u73AF\u5883\uFF1A${environment}\uFF08${describeEnvironmentSource(source)}\uFF09\u2014\u2014 \u6253\u7684\u662F${environment === "dev" ? "\u5F00\u53D1\u5E93" : "\u751F\u4EA7\u5E93"}`
37576
38361
  );
@@ -37615,8 +38400,8 @@ function registerDb(program2, ctx) {
37615
38400
  });
37616
38401
  });
37617
38402
  db.command("migrate").description(
37618
- "\u6267\u884C SQL \u8FC1\u79FB\u6587\u4EF6\uFF08\u53EF\u591A\u4E2A\uFF0C\u6309\u58F0\u660E\u987A\u5E8F\u6267\u884C\u2014\u2014a.sql \u5EFA\u8868\u3001b.sql \u63D2\u6570\u636E\u7684\u4F9D\u8D56\u987A\u5E8F\u5C31\u662F\u58F0\u660E\u987A\u5E8F\uFF1B\u5931\u8D25\u5373\u505C\u5E76\u6307\u5411\u5931\u8D25\u6587\u4EF6\uFF09"
37619
- ).argument("<files...>", "\u8FC1\u79FB SQL \u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5F53\u524D\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u6309\u58F0\u660E\u987A\u5E8F\u6267\u884C\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (files, flags) => {
38403
+ "\u6267\u884C SQL \u8FC1\u79FB\u6587\u4EF6\uFF08\u589E\u91CF\u8BED\u4E49\uFF09\uFF1A\u7F3A\u8868\u5EFA\u8868\u3001\u65E2\u6709\u8868\u7F3A\u5217\u81EA\u52A8 ADD COLUMN\uFF1B\u5220\u5217/\u6539\u7C7B\u578B/\u91CD\u547D\u540D\u62D2\u7EDD\u81EA\u52A8\u6267\u884C\u3002\u53EF\u591A\u4E2A\u6587\u4EF6\uFF0C\u6309\u58F0\u660E\u987A\u5E8F\u6267\u884C\uFF0C\u5931\u8D25\u5373\u505C"
38404
+ ).argument("<files...>", "\u8FC1\u79FB SQL \u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5F53\u524D\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u6309\u58F0\u660E\u987A\u5E8F\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("--plan", "\u53EA\u8F93\u51FA\u6F02\u79FB\u8BA1\u5212\uFF08+table / +column / !type\uFF09\uFF0C\u4E0D\u6267\u884C\u4EFB\u4F55\u8BED\u53E5").action(async (files, flags) => {
37620
38405
  const command = ctx.io("db migrate");
37621
38406
  await command.run(async () => {
37622
38407
  const { environment, source } = await ctx.env();
@@ -37625,21 +38410,64 @@ function registerDb(program2, ctx) {
37625
38410
  cwd: ctx.cwd,
37626
38411
  files,
37627
38412
  environment,
37628
- ...flags.project === void 0 ? {} : { slug: flags.project }
38413
+ ...flags.project === void 0 ? {} : { slug: flags.project },
38414
+ ...flags.plan === true ? { plan: true } : {}
37629
38415
  });
38416
+ command.line(
38417
+ `\u73AF\u5883\uFF1A${environment}\uFF08${describeEnvironmentSource(source)}\uFF09\u2014\u2014 \u8FC1\u79FB\u5C06\u4F5C\u7528\u5230${environment === "dev" ? "\u5F00\u53D1\u5E93" : "\u751F\u4EA7\u5E93"}`
38418
+ );
37630
38419
  if (result.failed !== void 0) {
37631
38420
  const f = result.failed;
37632
- command.fail(f.code, `\u6587\u4EF6 ${f.file} \u4E2D\u7684\u8BED\u53E5\u6267\u884C\u5931\u8D25\uFF1A${f.message}`);
38421
+ command.fail(f.code, `\u6587\u4EF6 ${f.file} \u8FC1\u79FB\u5931\u8D25\uFF1A${f.message}`);
37633
38422
  return;
37634
38423
  }
37635
- command.line(
37636
- `\u73AF\u5883\uFF1A${environment}\uFF08${describeEnvironmentSource(source)}\uFF09\u2014\u2014 \u8FC1\u79FB\u5C06\u4F5C\u7528\u5230${environment === "dev" ? "\u5F00\u53D1\u5E93" : "\u751F\u4EA7\u5E93"}`
37637
- );
37638
38424
  command.ok(result, (data) => {
37639
38425
  const r = data;
37640
- const kinds = r.applied.map((s) => s.split(/\s+/)[0] ?? s).join(", ");
37641
- return `\u2713 ${r.applied.length} \u6761\u8BED\u53E5\u5DF2\u6267\u884C\uFF08${kinds}\uFF09`;
38426
+ const lines = renderDrift(
38427
+ r.drift ?? {
38428
+ missingTables: [],
38429
+ missingColumns: [],
38430
+ typeMismatches: [],
38431
+ extraTables: [],
38432
+ extraColumns: [],
38433
+ destructiveStatements: [],
38434
+ applicable: true
38435
+ }
38436
+ );
38437
+ if (flags.plan === true) return lines;
38438
+ lines.push(
38439
+ `\u2713 \u8FC1\u79FB\u5B8C\u6210\uFF1A\u65B0\u5EFA\u8868 ${r.createdTables}\uFF0C\u65B0\u589E\u5217 ${r.addedColumns}\uFF0C\u5DF2\u5B58\u5728\u8DF3\u8FC7 ${r.skippedTables}\uFF08\u5171\u6267\u884C ${r.applied.length} \u6761\u8BED\u53E5\uFF09`
38440
+ );
38441
+ return lines;
38442
+ });
38443
+ });
38444
+ });
38445
+ db.command("doctor").description(
38446
+ "\u5168\u5E93 schema \u6F02\u79FB\u62A5\u544A\uFF1A\u5BF9\u6BD4 schema.sql \u4E0E\u7EBF\u4E0A\u76EE\u5F55\uFF08\u7F3A\u8868 / \u7F3A\u5217 / \u7C7B\u578B\u4E0D\u4E00\u81F4\uFF09\u3002\u53D7\u5168\u5C40 --env \u5F71\u54CD\uFF1B\u5B58\u5728\u7834\u574F\u6027\u53D8\u66F4\u65F6\u9000\u51FA\u7801\u975E 0"
38447
+ ).argument("[schema]", "schema.sql \u8DEF\u5F84", "database/schema.sql").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (schema, flags) => {
38448
+ const command = ctx.io("db doctor");
38449
+ await command.run(async () => {
38450
+ const { environment, source } = await ctx.env();
38451
+ const { dbSchemaDiff: dbSchemaDiff2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
38452
+ const sql = await readFile29(resolve18(schema), "utf8");
38453
+ const diff = await dbSchemaDiff2(ctx.paths, {
38454
+ cwd: ctx.cwd,
38455
+ sql,
38456
+ environment,
38457
+ ...flags.project === void 0 ? {} : { slug: flags.project }
37642
38458
  });
38459
+ command.line(
38460
+ `\u73AF\u5883\uFF1A${environment}\uFF08${describeEnvironmentSource(source)}\uFF09\u2014\u2014 \u68C0\u67E5\u7684\u662F${environment === "dev" ? "\u5F00\u53D1\u5E93" : "\u751F\u4EA7\u5E93"}`
38461
+ );
38462
+ if (!diff.applicable) {
38463
+ command.fail(
38464
+ "SCHEMA_DRIFT",
38465
+ `\u68C0\u6D4B\u5230\u65E0\u6CD5\u81EA\u52A8\u6267\u884C\u7684\u6F02\u79FB\uFF08${schema}\uFF09\uFF1A
38466
+ ${renderDrift(diff).join("\n")}`
38467
+ );
38468
+ return;
38469
+ }
38470
+ command.ok(diff, () => renderDrift(diff));
37643
38471
  });
37644
38472
  });
37645
38473
  const snapshot = db.command("snapshot").description("\u6570\u636E\u5E93\u5FEB\u7167\uFF08\u4ED8\u8D39\u6863\u4F4D\uFF09\uFF1A\u5217\u51FA\uFF08\u7F3A\u7701\uFF09/ \u521B\u5EFA / \u8FD8\u539F");
@@ -38176,6 +39004,59 @@ function registerHosting(program2, ctx) {
38176
39004
  });
38177
39005
  }
38178
39006
 
39007
+ // packages/cli/src/commands/logs.ts
39008
+ init_auth();
39009
+ function registerLogs(program2, ctx) {
39010
+ program2.command("logs").description("\u6309 traceId \u67E5\u8BE2\u4E00\u6B21\u8C03\u7528\u94FE\u7684\u65E5\u5FD7\uFF08traceId \u89C1\u9519\u8BEF\u4FE1\u5C01\u6216\u54CD\u5E94\u5934\uFF09").option("--trace <traceId>", "W3C traceId\uFF0832 \u4F4D hex\uFF09").option("--tail <count>", "\u53D6\u6700\u8FD1\u591A\u5C11\u6761\uFF08\u7F3A\u7701 100\uFF0C\u670D\u52A1\u7AEF\u6709\u4E0A\u9650\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) => {
39011
+ const command = ctx.io("logs");
39012
+ await command.run(async () => {
39013
+ const trace = flags.trace?.trim() ?? "";
39014
+ if (trace.length === 0) {
39015
+ throw new CliError("INVALID_ARGUMENT", "\u7F3A\u5C11 --trace\uFF1Aadep logs --trace <traceId>");
39016
+ }
39017
+ const tail = flags.tail === void 0 ? void 0 : Number(flags.tail);
39018
+ if (tail !== void 0 && (!Number.isFinite(tail) || tail <= 0)) {
39019
+ throw new CliError("INVALID_TAIL", `--tail \u987B\u4E3A\u6B63\u6574\u6570\uFF0C\u6536\u5230 "${flags.tail}"`);
39020
+ }
39021
+ const { logsByTrace: logsByTrace2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
39022
+ const result = await logsByTrace2(ctx.paths, {
39023
+ cwd: ctx.cwd,
39024
+ trace,
39025
+ ...tail === void 0 ? {} : { tail },
39026
+ ...flags.project === void 0 ? {} : { slug: flags.project }
39027
+ });
39028
+ command.ok(result, (data) => {
39029
+ const r = data;
39030
+ if (r.logs.length === 0) {
39031
+ return `\uFF08trace ${r.traceId} \u6682\u65E0\u65E5\u5FD7\uFF1A\u786E\u8BA4 traceId \u6B63\u786E\uFF0C\u4E14\u8BE5\u8C03\u7528\u53D1\u751F\u5728\u65E5\u5FD7\u7F13\u51B2\u4FDD\u7559\u7A97\u53E3\u5185\uFF09`;
39032
+ }
39033
+ return r.logs.map((log) => `${log.at} [${log.level}] ${log.message}`);
39034
+ });
39035
+ });
39036
+ });
39037
+ }
39038
+
39039
+ // packages/cli/src/commands/rollback.ts
39040
+ function registerRollback(program2, ctx) {
39041
+ program2.command("rollback <fn>").description("\u628A\u5DF2\u53D1\u5E03\u51FD\u6570\u5207\u56DE\u5386\u53F2\u7248\u672C\uFF08\u7248\u672C\u6765\u81EA adep publish \u751F\u6210\u7684\u81EA\u589E\u53F7\uFF09").option("--to <version>", "\u76EE\u6807\u7248\u672C\u53F7\uFF0C\u5982 v2 \u6216 2").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (name, flags) => {
39042
+ const command = ctx.io("rollback");
39043
+ await command.run(async () => {
39044
+ const { parseVersionFlag: parseVersionFlag2, rollbackFunctionTo: rollbackFunctionTo2 } = await Promise.resolve().then(() => (init_rollback(), rollback_exports));
39045
+ const to = parseVersionFlag2(flags.to);
39046
+ const result = await rollbackFunctionTo2(ctx.paths, {
39047
+ cwd: ctx.cwd,
39048
+ name,
39049
+ to,
39050
+ ...flags.project === void 0 ? {} : { slug: flags.project }
39051
+ });
39052
+ command.ok(result, (data) => {
39053
+ const r = data;
39054
+ return `\u5DF2\u56DE\u6EDA ${r.name}\uFF1Av${r.from ?? "\u2014"} \u2192 v${r.to}`;
39055
+ });
39056
+ });
39057
+ });
39058
+ }
39059
+
38179
39060
  // packages/cli/src/cli.ts
38180
39061
  var requireJson = createRequire2(import.meta.url);
38181
39062
  var APP_VERSION = requireJson("../package.json").version;
@@ -38211,6 +39092,8 @@ function buildProgram(options = {}) {
38211
39092
  registerAuth(program2, ctx);
38212
39093
  registerMcp(program2, ctx);
38213
39094
  registerGit(program2, ctx);
39095
+ registerLogs(program2, ctx);
39096
+ registerRollback(program2, ctx);
38214
39097
  registerDeploy(program2, ctx);
38215
39098
  registerProjects(program2, ctx);
38216
39099
  registerFunctions(program2, ctx);