@adep/cli 0.4.11 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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();
@@ -8275,6 +8688,7 @@ var init_deploy = __esm({
8275
8688
  this.names = names;
8276
8689
  this.name = "AmbiguousFunctionError";
8277
8690
  }
8691
+ names;
8278
8692
  };
8279
8693
  IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git"]);
8280
8694
  }
@@ -8743,11 +9157,11 @@ var fs_exports = {};
8743
9157
  __export(fs_exports, {
8744
9158
  createExportFileSystem: () => createExportFileSystem
8745
9159
  });
8746
- import { mkdir as mkdir16, readFile as readFile27, rm as rm5, stat as stat17, writeFile as writeFile16 } from "node:fs/promises";
9160
+ import { mkdir as mkdir16, readFile as readFile28, rm as rm5, stat as stat17, writeFile as writeFile16 } from "node:fs/promises";
8747
9161
  import { dirname as dirname14, join as join36 } from "node:path";
8748
9162
  function createExportFileSystem() {
8749
9163
  return {
8750
- readFile: (path) => readFile27(path),
9164
+ readFile: (path) => readFile28(path),
8751
9165
  writeFile: (path, content) => writeFile16(path, content),
8752
9166
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
8753
9167
  deleteFile: async (path) => {
@@ -8765,7 +9179,7 @@ function createExportFileSystem() {
8765
9179
  await mkdir16(path, { recursive: true });
8766
9180
  },
8767
9181
  unzip: async (zipPath, targetDir) => {
8768
- const entries = zipRead(await readFile27(zipPath));
9182
+ const entries = zipRead(await readFile28(zipPath));
8769
9183
  for (const [name, data] of entries) {
8770
9184
  const dest = join36(targetDir, name);
8771
9185
  await mkdir16(dirname14(dest), { recursive: true });
@@ -8799,6 +9213,10 @@ var init_command = __esm({
8799
9213
  this.pollInterval = pollInterval;
8800
9214
  this.maxPollAttempts = maxPollAttempts;
8801
9215
  }
9216
+ apiClient;
9217
+ fs;
9218
+ pollInterval;
9219
+ maxPollAttempts;
8802
9220
  /**
8803
9221
  * 执行导出命令。
8804
9222
  *
@@ -9006,14 +9424,14 @@ ${detail}`);
9006
9424
  * @param ms 毫秒数
9007
9425
  */
9008
9426
  sleep(ms) {
9009
- return new Promise((resolve20) => setTimeout(resolve20, ms));
9427
+ return new Promise((resolve21) => setTimeout(resolve21, ms));
9010
9428
  }
9011
9429
  };
9012
9430
  }
9013
9431
  });
9014
9432
 
9015
9433
  // packages/cli/src/sandbox-scan.ts
9016
- import { readdir as readdir13, readFile as readFile28 } from "node:fs/promises";
9434
+ import { readdir as readdir13, readFile as readFile30 } from "node:fs/promises";
9017
9435
  import { join as join37, relative as relative9, sep as sep5 } from "node:path";
9018
9436
  function extractSpecifiers(line) {
9019
9437
  const out = [];
@@ -9079,7 +9497,7 @@ async function scanFunctionSources(rootDir, functionsDir) {
9079
9497
  if (entry.name.endsWith(".d.ts")) continue;
9080
9498
  let content;
9081
9499
  try {
9082
- content = await readFile28(abs, "utf8");
9500
+ content = await readFile30(abs, "utf8");
9083
9501
  } catch {
9084
9502
  continue;
9085
9503
  }
@@ -9353,7 +9771,7 @@ __export(mcp_exports, {
9353
9771
  mcpPublish: () => mcpPublish,
9354
9772
  mcpUnpublish: () => mcpUnpublish
9355
9773
  });
9356
- import { resolve as resolve18 } from "node:path";
9774
+ import { resolve as resolve19 } from "node:path";
9357
9775
  async function mcpPublish(paths, options) {
9358
9776
  const fn = requireFunctionName(options.fn);
9359
9777
  const client = await createClient(paths);
@@ -9434,7 +9852,7 @@ function requireFunctionName(fn) {
9434
9852
  return fn.trim();
9435
9853
  }
9436
9854
  async function resolveProject(client, options) {
9437
- const slug = await resolveSlug(resolve18(options.cwd), options.slug);
9855
+ const slug = await resolveSlug(resolve19(options.cwd), options.slug);
9438
9856
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
9439
9857
  const match = listed.projects.find((project2) => project2.slug === slug);
9440
9858
  if (match === void 0) {
@@ -9621,7 +10039,7 @@ __export(functions_exports, {
9621
10039
  functionsList: () => functionsList,
9622
10040
  functionsLogs: () => functionsLogs
9623
10041
  });
9624
- import { resolve as resolve19 } from "node:path";
10042
+ import { resolve as resolve20 } from "node:path";
9625
10043
  async function functionsList(paths, options) {
9626
10044
  const client = await createClient(paths);
9627
10045
  const project2 = await resolveProject2(client, options);
@@ -9663,7 +10081,7 @@ async function functionsLogs(paths, options) {
9663
10081
  return { functionId: target.id, name: target.name, logs: result.logs };
9664
10082
  }
9665
10083
  async function resolveProject2(client, options) {
9666
- const slug = await resolveSlug(resolve19(options.cwd), options.slug);
10084
+ const slug = await resolveSlug(resolve20(options.cwd), options.slug);
9667
10085
  const projects = await projectsListFrom(client);
9668
10086
  const match = projects.find((project2) => project2.slug === slug);
9669
10087
  if (match === void 0) {
@@ -13019,6 +13437,7 @@ var TemplateRenderError = class extends Error {
13019
13437
  this.code = code;
13020
13438
  this.name = "TemplateRenderError";
13021
13439
  }
13440
+ code;
13022
13441
  };
13023
13442
  var PLACEHOLDER_PATTERN = /\{\{\s*([A-Za-z0-9_-]+)\s*\}\}/g;
13024
13443
  function declaredVariables(manifest) {
@@ -13141,6 +13560,7 @@ var InitError = class extends Error {
13141
13560
  this.code = code;
13142
13561
  this.name = "InitError";
13143
13562
  }
13563
+ code;
13144
13564
  };
13145
13565
  async function initProject(cwd, name, template, filesOverride) {
13146
13566
  if (!/^[a-z][a-z0-9-]{0,62}$/.test(name)) {
@@ -18920,7 +19340,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
18920
19340
  var NONE = 0;
18921
19341
  var ASSUMED = 1;
18922
19342
  var PROVEN = 2;
18923
- function isRecursive(inst, stack, resolve20) {
19343
+ function isRecursive(inst, stack, resolve21) {
18924
19344
  const cached2 = recursive.get(inst);
18925
19345
  if (cached2 !== void 0)
18926
19346
  return cached2 ? PROVEN : NONE;
@@ -18930,7 +19350,7 @@ function isRecursive(inst, stack, resolve20) {
18930
19350
  let result = NONE;
18931
19351
  const check2 = (child) => {
18932
19352
  if (result !== PROVEN && child?._zod) {
18933
- const answer = isRecursive(child, stack, resolve20);
19353
+ const answer = isRecursive(child, stack, resolve21);
18934
19354
  if (answer > result)
18935
19355
  result = answer;
18936
19356
  }
@@ -18941,7 +19361,7 @@ function isRecursive(inst, stack, resolve20) {
18941
19361
  const desc = Object.getOwnPropertyDescriptor(sh, key);
18942
19362
  if (spread && !desc.enumerable)
18943
19363
  continue;
18944
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve20) : NONE;
19364
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve21) : NONE;
18945
19365
  if (child > answer)
18946
19366
  answer = child;
18947
19367
  }
@@ -19005,7 +19425,7 @@ function isRecursive(inst, stack, resolve20) {
19005
19425
  break;
19006
19426
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
19007
19427
  case "lazy": {
19008
- const inner = def._cachedInner ?? (resolve20 ? inst._zod.innerType : void 0);
19428
+ const inner = def._cachedInner ?? (resolve21 ? inst._zod.innerType : void 0);
19009
19429
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
19010
19430
  break;
19011
19431
  }
@@ -26796,8 +27216,8 @@ function registry() {
26796
27216
  var globalRegistry = globalThis.__zod_globalRegistry;
26797
27217
 
26798
27218
  // 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");
27219
+ var INVALID = /* @__PURE__ */ Symbol.for("zod.compile.invalid");
27220
+ var FALLBACK_FLAG = /* @__PURE__ */ Symbol.for("zod.compile.fallback");
26801
27221
  var ZodCompileAsyncError = class extends Error {
26802
27222
  constructor(message = "z.compile does not support async refinements, transforms, or checks") {
26803
27223
  super(message);
@@ -30585,7 +31005,7 @@ var nonoptionalProcessor = (schema, ctx, _json, params) => {
30585
31005
  const seen = ctx.seen.get(schema);
30586
31006
  seen.ref = def.innerType;
30587
31007
  };
30588
- var UNREPRESENTABLE_DEFAULT = Symbol();
31008
+ var UNREPRESENTABLE_DEFAULT = /* @__PURE__ */ Symbol();
30589
31009
  function serializeDefaultValue(value, schema, ctx, json2, params) {
30590
31010
  let unrepresentable = false;
30591
31011
  const serialized = JSON.stringify(value, (_, val) => {
@@ -33349,7 +33769,7 @@ function fromJSONSchema(schema, params) {
33349
33769
  }
33350
33770
 
33351
33771
  // node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/visit.js
33352
- var RESOLVING = Symbol("z.visit/resolving");
33772
+ var RESOLVING = /* @__PURE__ */ Symbol("z.visit/resolving");
33353
33773
  function visit(schema, fnOrHandlers) {
33354
33774
  const fn = typeof fnOrHandlers === "function" ? fnOrHandlers : (node2, rewritten) => {
33355
33775
  const h = fnOrHandlers[node2._zod.def.type];
@@ -35574,6 +35994,9 @@ var SyncTransportError = class extends Error {
35574
35994
  this.failedSeq = failedSeq;
35575
35995
  this.name = "SyncTransportError";
35576
35996
  }
35997
+ code;
35998
+ status;
35999
+ failedSeq;
35577
36000
  };
35578
36001
  function isBindable(value) {
35579
36002
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
@@ -37071,7 +37494,7 @@ function registerDevServers(program2, ctx) {
37071
37494
  init_auth();
37072
37495
  init_client();
37073
37496
  init_deploy();
37074
- import { stat as stat16 } from "node:fs/promises";
37497
+ import { readFile as readFile26, stat as stat16 } from "node:fs/promises";
37075
37498
  import { join as join34, resolve as resolve16 } from "node:path";
37076
37499
  async function resolveProjectId2(client, cwd, slug) {
37077
37500
  const resolvedSlug = await resolveSlug(resolve16(cwd), slug);
@@ -37154,6 +37577,58 @@ async function publishFunctions(paths, options) {
37154
37577
  const deployedCount = result.functions.filter((fn) => fn.action !== "none").length;
37155
37578
  return { ...result, elapsedSeconds, deployedCount };
37156
37579
  }
37580
+ async function checkSchemaDrift(paths, options) {
37581
+ const schemaFile = join34(options.cwd, "database", "schema.sql");
37582
+ const schemaStat = await stat16(schemaFile).catch(() => null);
37583
+ if (schemaStat === null || !schemaStat.isFile()) {
37584
+ options.log("[adep] \u672A\u627E\u5230 database/schema.sql\uFF0C\u8DF3\u8FC7 schema \u6F02\u79FB\u68C0\u67E5");
37585
+ return null;
37586
+ }
37587
+ const sql = await readFile26(schemaFile, "utf8");
37588
+ const { dbSchemaDiff: dbSchemaDiff2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
37589
+ let drift;
37590
+ try {
37591
+ drift = await dbSchemaDiff2(paths, {
37592
+ cwd: options.cwd,
37593
+ sql,
37594
+ ...options.slug === void 0 ? {} : { slug: options.slug },
37595
+ log: options.log
37596
+ });
37597
+ } catch (error62) {
37598
+ if (error62 instanceof CliError && (error62.code === "DB_NOT_PROVISIONED" || error62.code === "DB_NOT_FOUND")) {
37599
+ 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");
37600
+ return null;
37601
+ }
37602
+ throw error62;
37603
+ }
37604
+ const blocking = drift.missingTables.length > 0 || drift.missingColumns.length > 0 || drift.typeMismatches.length > 0;
37605
+ if (drift.destructiveStatements.length > 0) {
37606
+ options.log(
37607
+ `[adep] \u26A0 schema.sql \u542B\u7834\u574F\u6027\u8BED\u53E5\uFF08\u4E0D\u4F1A\u88AB\u81EA\u52A8\u6267\u884C\uFF09\uFF1A${drift.destructiveStatements.join(" \xB7 ")}`
37608
+ );
37609
+ }
37610
+ if (!blocking) {
37611
+ options.log("[adep] \u2713 schema \u65E0\u6F02\u79FB");
37612
+ return drift;
37613
+ }
37614
+ if (options.allowDrift === true) {
37615
+ options.log("[adep] \u26A0 schema \u6F02\u79FB\u88AB --allow-drift \u653E\u884C\uFF1A\u7EBF\u4E0A\u51FD\u6570\u53EF\u80FD no such column");
37616
+ return drift;
37617
+ }
37618
+ 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"];
37619
+ for (const item of drift.missingTables) lines.push(` +table ${item.table}`);
37620
+ for (const item of drift.missingColumns) {
37621
+ lines.push(` +column ${item.table}.${item.column.name}`);
37622
+ }
37623
+ for (const item of drift.typeMismatches) {
37624
+ lines.push(` !type ${item.table}.${item.column}\uFF08\u671F\u671B ${item.expected}\uFF0C\u7EBF\u4E0A ${item.actual}\uFF09`);
37625
+ }
37626
+ lines.push("\u4E0B\u4E00\u6B65\uFF1Aadep db migrate database/schema.sql");
37627
+ lines.push(" \u67E5\u770B\u8BA1\u5212\uFF1Aadep db migrate database/schema.sql --plan");
37628
+ lines.push(" \u5168\u5E93\u6F02\u79FB\u62A5\u544A\uFF1Aadep db doctor");
37629
+ 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");
37630
+ throw new CliError("SCHEMA_DRIFT_DETECTED", lines.join("\n"));
37631
+ }
37157
37632
  async function runPublish(paths, io, cwd, flags) {
37158
37633
  const scope = flags.only === void 0 ? "fullstack" : flags.only;
37159
37634
  if (flags.only !== void 0 && flags.only !== "functions" && flags.only !== "frontend") {
@@ -37164,6 +37639,12 @@ async function runPublish(paths, io, cwd, flags) {
37164
37639
  const environment = flags.environment;
37165
37640
  const result = { scope };
37166
37641
  if (wantFunctions) {
37642
+ await checkSchemaDrift(paths, {
37643
+ cwd,
37644
+ ...flags.project === void 0 ? {} : { slug: flags.project },
37645
+ log: io.json ? () => void 0 : (line) => io.line(line),
37646
+ ...flags.allowDrift === void 0 ? {} : { allowDrift: flags.allowDrift }
37647
+ });
37167
37648
  result.functions = await publishFunctions(paths, {
37168
37649
  cwd,
37169
37650
  ...flags.project === void 0 ? {} : { slug: flags.project },
@@ -37257,6 +37738,9 @@ function registerPublish(program2, ctx) {
37257
37738
  ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option(
37258
37739
  "--force",
37259
37740
  "\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"
37741
+ ).option(
37742
+ "--allow-drift",
37743
+ "\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
37744
  ).action(async (flags) => {
37261
37745
  const command = ctx.io("publish");
37262
37746
  await command.run(async () => {
@@ -37281,7 +37765,7 @@ init_auth();
37281
37765
  // packages/cli/src/deploy-worker.ts
37282
37766
  init_auth();
37283
37767
  init_client();
37284
- import { readdir as readdir12, readFile as readFile26 } from "node:fs/promises";
37768
+ import { readdir as readdir12, readFile as readFile27 } from "node:fs/promises";
37285
37769
  import { join as join35, relative as relative8, resolve as resolve17, sep as sep4 } from "node:path";
37286
37770
  async function collectWranglerFiles(dir) {
37287
37771
  const root = resolve17(dir);
@@ -37303,7 +37787,7 @@ async function collectWranglerFiles(dir) {
37303
37787
  if (entry.isDirectory()) {
37304
37788
  await walk(full);
37305
37789
  } else if (entry.isFile()) {
37306
- const buf = await readFile26(full).catch(() => null);
37790
+ const buf = await readFile27(full).catch(() => null);
37307
37791
  if (buf === null) continue;
37308
37792
  if (buf.includes(0)) continue;
37309
37793
  out[relative8(root, full).split(sep4).join("/")] = buf.toString("utf8");
@@ -37502,6 +37986,35 @@ function registerExport(program2, ctx) {
37502
37986
  }
37503
37987
 
37504
37988
  // packages/cli/src/commands/db.ts
37989
+ import { readFile as readFile29 } from "node:fs/promises";
37990
+ import { resolve as resolve18 } from "node:path";
37991
+ init_db2();
37992
+ function renderDrift(diff) {
37993
+ const lines = [];
37994
+ for (const table of diff.missingTables) lines.push(`+table ${table.table}`);
37995
+ for (const column of diff.missingColumns) {
37996
+ lines.push(
37997
+ `+column ${column.table}.${column.column.name} ${column.column.type}` + (column.blocked === null ? ` \u2192 ${column.sql}` : ` [\u62D2\u7EDD\u81EA\u52A8\u6267\u884C] ${column.blocked}`)
37998
+ );
37999
+ }
38000
+ for (const mismatch of diff.typeMismatches) {
38001
+ lines.push(
38002
+ `!type ${mismatch.table}.${mismatch.column} \u7EBF\u4E0A ${mismatch.actual || "(\u65E0\u7C7B\u578B)"} \u2192 schema ${mismatch.expected}`
38003
+ );
38004
+ }
38005
+ 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`);
38006
+ for (const column of diff.extraColumns) {
38007
+ lines.push(`-column ${column.table}.${column.column}\uFF08\u7EBF\u4E0A\u6709\u3001schema \u672A\u58F0\u660E\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u5220\u9664\uFF09`);
38008
+ }
38009
+ for (const statement of diff.destructiveStatements) {
38010
+ lines.push(`!ddl ${statement.replace(/\s+/g, " ").slice(0, 120)}`);
38011
+ }
38012
+ if (lines.length === 0) return ["\u2713 schema \u4E0E\u7EBF\u4E0A\u4E00\u81F4\uFF0C\u65E0\u6F02\u79FB"];
38013
+ if (!diff.applicable) {
38014
+ 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");
38015
+ }
38016
+ return lines;
38017
+ }
37505
38018
  function registerDb(program2, ctx) {
37506
38019
  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
38020
  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 +38057,66 @@ function registerDb(program2, ctx) {
37544
38057
  });
37545
38058
  });
37546
38059
  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) => {
38060
+ "\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"
38061
+ ).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
38062
  const command = ctx.io("db exec");
37550
38063
  await command.run(async () => {
38064
+ if (flags.sql !== void 0 && flags.file !== void 0) {
38065
+ command.fail("INVALID_ARGS", "--sql \u4E0E --file \u53EA\u80FD\u4E8C\u9009\u4E00");
38066
+ return;
38067
+ }
38068
+ if (flags.sql === void 0 && flags.file === void 0) {
38069
+ command.fail("INVALID_ARGS", "\u9700\u8981 --sql <sql> \u6216 --file <path>");
38070
+ return;
38071
+ }
37551
38072
  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");
38073
+ if (flags.file !== void 0) {
38074
+ const { dbExecBatch: dbExecBatch2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
38075
+ const sql = await readFile29(resolve18(flags.file), "utf8");
38076
+ const statements = splitSqlStatements(sql);
38077
+ if (statements.length === 0) {
38078
+ command.fail("EMPTY_FILE", `SQL \u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${flags.file}`);
38079
+ return;
37570
38080
  }
37571
- lines.push(`\u8017\u65F6 ${r.elapsedMs}ms`);
37572
- return lines;
37573
- });
38081
+ const result = await dbExecBatch2(ctx.paths, {
38082
+ cwd: ctx.cwd,
38083
+ statements,
38084
+ environment,
38085
+ ...flags.project === void 0 ? {} : { slug: flags.project },
38086
+ ...flags.confirmTable === void 0 ? {} : { confirmTables: statements.map(() => flags.confirmTable) }
38087
+ });
38088
+ command.ok(result, (data) => {
38089
+ const results = data.results;
38090
+ const total = results.reduce((sum, entry) => sum + entry.changes, 0);
38091
+ return [
38092
+ `\u2713 ${results.length} \u6761\u8BED\u53E5\u5DF2\u5728\u4E00\u4E2A\u4E8B\u52A1\u5185\u63D0\u4EA4`,
38093
+ `${total} \u884C\u53D7\u5F71\u54CD`
38094
+ ];
38095
+ });
38096
+ } else {
38097
+ const { dbExec: dbExec2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
38098
+ const result = await dbExec2(ctx.paths, {
38099
+ cwd: ctx.cwd,
38100
+ sql: flags.sql,
38101
+ environment,
38102
+ ...flags.project === void 0 ? {} : { slug: flags.project },
38103
+ ...flags.confirmTable === void 0 ? {} : { confirmTable: flags.confirmTable }
38104
+ });
38105
+ command.ok(result, (data) => {
38106
+ const r = data;
38107
+ const lines = [];
38108
+ if (r.columns.length > 0) {
38109
+ lines.push(formatTable(r.columns, r.rows));
38110
+ if (r.truncated) lines.push(`\uFF08\u7ED3\u679C\u5DF2\u622A\u65AD\u5230 ${r.rows.length} \u884C\uFF09`);
38111
+ } else if (r.changes > 0) {
38112
+ lines.push(`${r.changes} \u884C\u53D7\u5F71\u54CD`);
38113
+ } else {
38114
+ lines.push("\u8BED\u53E5\u6267\u884C\u6210\u529F\uFF08\u65E0\u8FD4\u56DE\u884C\uFF09");
38115
+ }
38116
+ lines.push(`\u8017\u65F6 ${r.elapsedMs}ms`);
38117
+ return lines;
38118
+ });
38119
+ }
37574
38120
  command.line(
37575
38121
  `\u73AF\u5883\uFF1A${environment}\uFF08${describeEnvironmentSource(source)}\uFF09\u2014\u2014 \u6253\u7684\u662F${environment === "dev" ? "\u5F00\u53D1\u5E93" : "\u751F\u4EA7\u5E93"}`
37576
38122
  );
@@ -37615,8 +38161,8 @@ function registerDb(program2, ctx) {
37615
38161
  });
37616
38162
  });
37617
38163
  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) => {
38164
+ "\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"
38165
+ ).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
38166
  const command = ctx.io("db migrate");
37621
38167
  await command.run(async () => {
37622
38168
  const { environment, source } = await ctx.env();
@@ -37625,21 +38171,64 @@ function registerDb(program2, ctx) {
37625
38171
  cwd: ctx.cwd,
37626
38172
  files,
37627
38173
  environment,
37628
- ...flags.project === void 0 ? {} : { slug: flags.project }
38174
+ ...flags.project === void 0 ? {} : { slug: flags.project },
38175
+ ...flags.plan === true ? { plan: true } : {}
37629
38176
  });
38177
+ command.line(
38178
+ `\u73AF\u5883\uFF1A${environment}\uFF08${describeEnvironmentSource(source)}\uFF09\u2014\u2014 \u8FC1\u79FB\u5C06\u4F5C\u7528\u5230${environment === "dev" ? "\u5F00\u53D1\u5E93" : "\u751F\u4EA7\u5E93"}`
38179
+ );
37630
38180
  if (result.failed !== void 0) {
37631
38181
  const f = result.failed;
37632
- command.fail(f.code, `\u6587\u4EF6 ${f.file} \u4E2D\u7684\u8BED\u53E5\u6267\u884C\u5931\u8D25\uFF1A${f.message}`);
38182
+ command.fail(f.code, `\u6587\u4EF6 ${f.file} \u8FC1\u79FB\u5931\u8D25\uFF1A${f.message}`);
37633
38183
  return;
37634
38184
  }
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
38185
  command.ok(result, (data) => {
37639
38186
  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`;
38187
+ const lines = renderDrift(
38188
+ r.drift ?? {
38189
+ missingTables: [],
38190
+ missingColumns: [],
38191
+ typeMismatches: [],
38192
+ extraTables: [],
38193
+ extraColumns: [],
38194
+ destructiveStatements: [],
38195
+ applicable: true
38196
+ }
38197
+ );
38198
+ if (flags.plan === true) return lines;
38199
+ lines.push(
38200
+ `\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`
38201
+ );
38202
+ return lines;
38203
+ });
38204
+ });
38205
+ });
38206
+ db.command("doctor").description(
38207
+ "\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"
38208
+ ).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) => {
38209
+ const command = ctx.io("db doctor");
38210
+ await command.run(async () => {
38211
+ const { environment, source } = await ctx.env();
38212
+ const { dbSchemaDiff: dbSchemaDiff2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
38213
+ const sql = await readFile29(resolve18(schema), "utf8");
38214
+ const diff = await dbSchemaDiff2(ctx.paths, {
38215
+ cwd: ctx.cwd,
38216
+ sql,
38217
+ environment,
38218
+ ...flags.project === void 0 ? {} : { slug: flags.project }
37642
38219
  });
38220
+ command.line(
38221
+ `\u73AF\u5883\uFF1A${environment}\uFF08${describeEnvironmentSource(source)}\uFF09\u2014\u2014 \u68C0\u67E5\u7684\u662F${environment === "dev" ? "\u5F00\u53D1\u5E93" : "\u751F\u4EA7\u5E93"}`
38222
+ );
38223
+ if (!diff.applicable) {
38224
+ command.fail(
38225
+ "SCHEMA_DRIFT",
38226
+ `\u68C0\u6D4B\u5230\u65E0\u6CD5\u81EA\u52A8\u6267\u884C\u7684\u6F02\u79FB\uFF08${schema}\uFF09\uFF1A
38227
+ ${renderDrift(diff).join("\n")}`
38228
+ );
38229
+ return;
38230
+ }
38231
+ command.ok(diff, () => renderDrift(diff));
37643
38232
  });
37644
38233
  });
37645
38234
  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");