@adep/cli 0.4.1 → 0.4.5

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.
Files changed (46) hide show
  1. package/README.md +140 -11
  2. package/dist/index.js +34568 -27795
  3. package/dist/vite.js +279 -19
  4. package/dist/worker-entry.js +201 -2
  5. package/package.json +6 -5
  6. package/templates/app-desktop/README.md +67 -2
  7. package/templates/app-desktop/identity-store.mjs +309 -0
  8. package/templates/app-desktop/identity.mjs +517 -0
  9. package/templates/app-desktop/main.cjs +17 -0
  10. package/templates/app-desktop/main.mjs +218 -2
  11. package/templates/app-desktop/offline-runtime.mjs +72 -3
  12. package/templates/app-desktop/package.json +10 -6
  13. package/templates/app-desktop/recovery-ui.mjs +300 -0
  14. package/templates/app-desktop/sync-loop.mjs +137 -0
  15. package/templates/app-mobile/README.md +47 -9
  16. package/templates/app-mobile/package.json +2 -1
  17. package/templates/app-mobile/plugins/adep-bridge/Package.swift +52 -0
  18. package/templates/app-mobile/plugins/adep-bridge/android/build.gradle +34 -3
  19. package/templates/app-mobile/plugins/adep-bridge/android/src/main/AndroidManifest.xml +12 -5
  20. package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepBridge.kt +198 -12
  21. package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepIdentity.kt +342 -0
  22. package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepKeystore.kt +56 -2
  23. package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepSqlite.kt +506 -0
  24. package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepSqliteLogic.kt +235 -0
  25. package/templates/app-mobile/plugins/adep-bridge/dist/plugin.js +30 -0
  26. package/templates/app-mobile/plugins/adep-bridge/ios/AdepBridge.podspec +7 -1
  27. package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepBridge.swift +221 -9
  28. package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepIdentity.swift +500 -0
  29. package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepKeychain.swift +69 -17
  30. package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepPermissionGate.swift +25 -4
  31. package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepShellConfig.swift +54 -0
  32. package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepSqlite.swift +614 -0
  33. package/templates/app-mobile/plugins/adep-bridge/package.json +10 -0
  34. package/templates/app-mobile/template.json +12 -3
  35. package/templates/app-mobile/web/adep-bridge.js +103 -9
  36. package/templates/app-mobile/web/offline-runtime.js +230 -0
  37. package/templates/app-mobile-xtool/AdepShell-Info.plist +24 -0
  38. package/templates/app-mobile-xtool/Package.swift +59 -0
  39. package/templates/app-mobile-xtool/README.md +81 -0
  40. package/templates/app-mobile-xtool/Sources/AdepShell/App.swift +36 -0
  41. package/templates/app-mobile-xtool/Sources/AdepShell/ShellViewController.swift +223 -0
  42. package/templates/app-mobile-xtool/adep.permissions.json +4 -0
  43. package/templates/app-mobile-xtool/app/site/.gitkeep +0 -0
  44. package/templates/app-mobile-xtool/template.json +15 -0
  45. package/templates/app-mobile-xtool/xtool.yml +35 -0
  46. package/templates/app-mobile/plugins/adep-bridge/capacitor.plugin.json +0 -10
package/dist/vite.js CHANGED
@@ -15,6 +15,8 @@ var DB_RPC = {
15
15
  query: "query",
16
16
  /** 写路径(CF-013):`(method=writeQuery, args=[sql, params])` → `{ changes }`。 */
17
17
  writeQuery: "writeQuery",
18
+ /** 通用执行(BUG-4,2026-10-14):`(method=execute, args=[sql, params?])` → `{ changes }`。 */
19
+ execute: "execute",
18
20
  /** 读取 owned 表变更流(DB-006):`(method=changes, args=[table, query])`。 */
19
21
  changes: "changes",
20
22
  /** 开启事务:`begin → txId`。 */
@@ -62,6 +64,30 @@ function normalizeHttpStatus(status) {
62
64
  }
63
65
 
64
66
  // packages/runtime/src/shared/http-envelope.ts
67
+ function coerceAdepHttpEnvelope(value) {
68
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
69
+ if (isAdepHttpEnvelope(value)) return value;
70
+ const keys = Object.keys(value);
71
+ if (keys.length === 0) return null;
72
+ if (!keys.every((key) => key === "status" || key === "body" || key === "headers")) return null;
73
+ const candidate = value;
74
+ const status = candidate.status;
75
+ if (typeof status !== "number" || !Number.isInteger(status) || status < 100 || status > 599) {
76
+ return null;
77
+ }
78
+ if ("headers" in candidate && candidate.headers !== void 0) {
79
+ const headers = candidate.headers;
80
+ if (typeof headers !== "object" || headers === null || Array.isArray(headers)) return null;
81
+ if (!Object.values(headers).every((headerValue2) => typeof headerValue2 === "string")) return null;
82
+ }
83
+ return {
84
+ __adepHttp: {
85
+ status,
86
+ ...candidate.headers === void 0 ? {} : { headers: candidate.headers },
87
+ body: candidate.body
88
+ }
89
+ };
90
+ }
65
91
  function isAdepHttpEnvelope(value) {
66
92
  if (typeof value !== "object" || value === null) return false;
67
93
  const envelope = value.__adepHttp;
@@ -454,6 +480,14 @@ function assertWriteQuery(sql) {
454
480
  );
455
481
  }
456
482
  }
483
+ function classifyStatement(sql) {
484
+ const head = sqlHead(stripLiterals(sql));
485
+ if (head.startsWith("SELECT") || head.startsWith("WITH")) return "read";
486
+ if (head.startsWith("INSERT") || head.startsWith("UPDATE") || head.startsWith("DELETE")) {
487
+ return "write";
488
+ }
489
+ return "ddl";
490
+ }
457
491
 
458
492
  // packages/runtime/src/database/builder/owned.ts
459
493
  var OWNED_PK = "id";
@@ -708,10 +742,21 @@ function compileSelect(state, dialect) {
708
742
  if (state.orderBys.length > 0) {
709
743
  sql += ` ORDER BY ${state.orderBys.map((order) => `${dialect.quote(order.column)} ${order.direction.toUpperCase()}`).join(", ")}`;
710
744
  }
711
- if (state.limit !== void 0) sql += ` LIMIT ${pushParam(params, dialect, state.limit)}`;
712
- if (state.offset !== void 0) sql += ` OFFSET ${pushParam(params, dialect, state.offset)}`;
745
+ if (state.limit !== void 0) {
746
+ assertInlineableInt(state.limit, "limit");
747
+ sql += ` LIMIT ${state.limit}`;
748
+ }
749
+ if (state.offset !== void 0) {
750
+ assertInlineableInt(state.offset, "offset");
751
+ sql += ` OFFSET ${state.offset}`;
752
+ }
713
753
  return { sql, params };
714
754
  }
755
+ function assertInlineableInt(value, name) {
756
+ if (!Number.isInteger(value) || value < 0) {
757
+ throw unsafeOperation(`${name} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);
758
+ }
759
+ }
715
760
  function compileCount(state, dialect) {
716
761
  const params = [];
717
762
  let sql = `SELECT count(*) AS n FROM ${dialect.quote(state.table)}`;
@@ -1006,6 +1051,21 @@ function createCloudDb(driver, options = {}) {
1006
1051
  assertWriteQuery(sql);
1007
1052
  return driver.run(sql, params);
1008
1053
  },
1054
+ async execute(sql, params = []) {
1055
+ if (sql.trim() === "") {
1056
+ throw unsafeOperation("execute \u7684 sql \u4E0D\u80FD\u4E3A\u7A7A");
1057
+ }
1058
+ if (!Array.isArray(params)) {
1059
+ throw unsafeOperation("execute \u7684 params \u5FC5\u987B\u662F\u6570\u7EC4\uFF08\u65E0\u53C2\u53EF\u4E0D\u4F20\uFF09");
1060
+ }
1061
+ guardWrite();
1062
+ const kind = classifyStatement(sql);
1063
+ if (kind === "read") {
1064
+ await driver.all(sql, params);
1065
+ return { changes: 0 };
1066
+ }
1067
+ return driver.run(sql, params);
1068
+ },
1009
1069
  async changes(table, query = {}) {
1010
1070
  return readChanges(driver, table, query);
1011
1071
  }
@@ -1081,6 +1141,10 @@ function createDbCapability(driver, options = {}) {
1081
1141
  const [sql, params] = args;
1082
1142
  return await db.writeQuery(sql, params);
1083
1143
  }
1144
+ case DB_RPC.execute: {
1145
+ const [sql, params] = args;
1146
+ return await db.execute(sql, params ?? []);
1147
+ }
1084
1148
  case DB_RPC.changes: {
1085
1149
  const [table, query] = args;
1086
1150
  return await db.changes(table, query);
@@ -1246,11 +1310,21 @@ function parseWhereClauses(whereRaw, cursor) {
1246
1310
  const t = part.trim();
1247
1311
  if (t.length === 0) continue;
1248
1312
  if (/\bIS\s+NULL\b/i.test(t)) {
1249
- clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "")), operator: "IS NULL", value: null, list: false });
1313
+ clauses.push({
1314
+ column: unqualifyColumn(ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "")),
1315
+ operator: "IS NULL",
1316
+ value: null,
1317
+ list: false
1318
+ });
1250
1319
  continue;
1251
1320
  }
1252
1321
  if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1253
- clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "")), operator: "IS NOT NULL", value: null, list: false });
1322
+ clauses.push({
1323
+ column: unqualifyColumn(ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "")),
1324
+ operator: "IS NOT NULL",
1325
+ value: null,
1326
+ list: false
1327
+ });
1254
1328
  continue;
1255
1329
  }
1256
1330
  const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
@@ -1427,7 +1501,10 @@ function parseConflictClause(clause, cursor, fallbackCols) {
1427
1501
  clause.trim()
1428
1502
  );
1429
1503
  if (m === null) {
1430
- throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 ON CONFLICT \u5B50\u53E5\uFF1A${clause.trim().slice(0, 60)}\u2026`);
1504
+ throw new SimDbError(
1505
+ "DB_UNSAFE_OP",
1506
+ `\u65E0\u6CD5\u89E3\u6790 ON CONFLICT \u5B50\u53E5\uFF1A${clause.trim().slice(0, 60)}\u2026`
1507
+ );
1431
1508
  }
1432
1509
  const colsRaw = m[1];
1433
1510
  const cols = colsRaw === void 0 ? fallbackCols : colsRaw.split(",").map(ident);
@@ -1631,16 +1708,16 @@ var SimSqlEngine = class {
1631
1708
  row[col] = values[i] ?? null;
1632
1709
  });
1633
1710
  if (conflictSpec !== null) {
1634
- const existing = table.rows.find(
1635
- (r) => conflictSpec.cols.every((c) => r[c] === row[c])
1636
- );
1711
+ const existing = table.rows.find((r) => conflictSpec.cols.every((c) => r[c] === row[c]));
1637
1712
  if (existing !== void 0) {
1638
1713
  const oldRow = { ...existing };
1639
1714
  for (const set of conflictSpec.sets) {
1640
1715
  existing[set.col] = resolveSetValue(set.value, oldRow, row);
1641
1716
  }
1642
1717
  inserted += 1;
1643
- void this.persist();
1718
+ this.persist().catch((error) => {
1719
+ console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
1720
+ });
1644
1721
  continue;
1645
1722
  }
1646
1723
  }
@@ -1648,7 +1725,9 @@ var SimSqlEngine = class {
1648
1725
  table.rows.push(row);
1649
1726
  inserted += 1;
1650
1727
  }
1651
- void this.persist();
1728
+ this.persist().catch((error) => {
1729
+ console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
1730
+ });
1652
1731
  return { changes: inserted };
1653
1732
  }
1654
1733
  execUpdate(sql, params) {
@@ -1678,7 +1757,9 @@ var SimSqlEngine = class {
1678
1757
  }
1679
1758
  changes += 1;
1680
1759
  }
1681
- void this.persist();
1760
+ this.persist().catch((error) => {
1761
+ console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
1762
+ });
1682
1763
  return { changes };
1683
1764
  }
1684
1765
  execDelete(sql, params) {
@@ -1696,7 +1777,9 @@ var SimSqlEngine = class {
1696
1777
  else changes += 1;
1697
1778
  }
1698
1779
  table.rows = keep;
1699
- void this.persist();
1780
+ this.persist().catch((error) => {
1781
+ console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
1782
+ });
1700
1783
  return { changes };
1701
1784
  }
1702
1785
  select(sql, params) {
@@ -1718,7 +1801,9 @@ var SimSqlEngine = class {
1718
1801
  rows = table.rows.map((row) => {
1719
1802
  const merged = { ...row };
1720
1803
  for (const j of joins) {
1721
- const joined = this.tables[j.table]?.rows.find((jr) => jr[j.leftCol] === merged[j.rightCol]);
1804
+ const joined = this.tables[j.table]?.rows.find(
1805
+ (jr) => jr[j.leftCol] === merged[j.rightCol]
1806
+ );
1722
1807
  if (joined !== void 0) {
1723
1808
  for (const [k, v] of Object.entries(joined)) merged[`${j.alias}.${k}`] = v;
1724
1809
  }
@@ -2819,7 +2904,7 @@ function envDbFile() {
2819
2904
  function displayPath(cwd, target) {
2820
2905
  if (target === ":memory:") return target;
2821
2906
  const rel = relative(cwd, target);
2822
- return rel.startsWith("..") ? target : rel;
2907
+ return rel.startsWith("..") ? target : rel.split(/[\\/]/u).join("/");
2823
2908
  }
2824
2909
  function simDbTarget(cwd) {
2825
2910
  return displayPath(cwd, join5(simDir(cwd), "db.json"));
@@ -3211,6 +3296,15 @@ function parseAdepConfig(raw) {
3211
3296
  data.environment = rec;
3212
3297
  }
3213
3298
  }
3299
+ if (input.db_environment !== void 0) {
3300
+ if (input.db_environment !== "dev" && input.db_environment !== "prod") {
3301
+ errors.push(
3302
+ `db_environment \u53EA\u63A5\u53D7 'dev' \u6216 'prod'\uFF0C\u6536\u5230 ${typeNameOf(input.db_environment)}\uFF08\u6CE8\u610F\u522B\u4E0E environment \u6DF7\u7528\uFF1A\u540E\u8005\u662F\u6CE8\u5165\u51FD\u6570\u8FD0\u884C\u65F6\u7684\u53D8\u91CF\u8868\uFF09`
3303
+ );
3304
+ } else {
3305
+ data.db_environment = input.db_environment;
3306
+ }
3307
+ }
3214
3308
  if (input.runtime !== void 0) {
3215
3309
  const rec = asRecord(input.runtime);
3216
3310
  if (rec === null) {
@@ -3598,6 +3692,158 @@ function parseExportClause(clause) {
3598
3692
  }
3599
3693
  return entries;
3600
3694
  }
3695
+ var CONTINUES_AFTER = "=+-*/%&|^<>?:,.[(";
3696
+ var CONTINUES_BEFORE = "`([.?:,+-*/%&|^<>=";
3697
+ var REGEX_PRECEDERS = "(,=:[!&|?{};+-*%~^<>";
3698
+ var MATCHING_OPEN = { ")": "(", "]": "[", "}": "{" };
3699
+ function lineNumberAt(code, index) {
3700
+ let line = 1;
3701
+ for (let i = 0; i < index; i += 1) if (code.charCodeAt(i) === 10) line += 1;
3702
+ return line;
3703
+ }
3704
+ function skipQuoted(code, start) {
3705
+ const quote = code.charAt(start);
3706
+ let i = start + 1;
3707
+ while (i < code.length) {
3708
+ const ch = code.charAt(i);
3709
+ if (ch === "\\") {
3710
+ i += 2;
3711
+ continue;
3712
+ }
3713
+ if (ch === quote) return i + 1;
3714
+ if (ch === "\n") return i;
3715
+ i += 1;
3716
+ }
3717
+ return code.length;
3718
+ }
3719
+ function skipRegex(code, start) {
3720
+ let i = start + 1;
3721
+ let inClass = false;
3722
+ while (i < code.length) {
3723
+ const ch = code.charAt(i);
3724
+ if (ch === "\\") {
3725
+ i += 2;
3726
+ continue;
3727
+ }
3728
+ if (ch === "\n") return start + 1;
3729
+ if (ch === "[") inClass = true;
3730
+ else if (ch === "]") inClass = false;
3731
+ else if (ch === "/" && !inClass) return i + 1;
3732
+ i += 1;
3733
+ }
3734
+ return code.length;
3735
+ }
3736
+ function regexCanStart(prev) {
3737
+ return prev === "" || REGEX_PRECEDERS.includes(prev);
3738
+ }
3739
+ function continuesOnto(code, newline, prev) {
3740
+ if (prev !== "" && CONTINUES_AFTER.includes(prev)) return true;
3741
+ let i = newline + 1;
3742
+ while (i < code.length && /\s/.test(code.charAt(i))) i += 1;
3743
+ const next = code.charAt(i);
3744
+ return next !== "" && CONTINUES_BEFORE.includes(next);
3745
+ }
3746
+ function scanDeclaration(code, from) {
3747
+ const commas = [];
3748
+ const stack = [];
3749
+ let prev = "";
3750
+ let i = from;
3751
+ while (i < code.length) {
3752
+ const ch = code.charAt(i);
3753
+ if (stack[stack.length - 1] === "`") {
3754
+ if (ch === "\\") {
3755
+ i += 2;
3756
+ continue;
3757
+ }
3758
+ if (ch === "`") {
3759
+ stack.pop();
3760
+ prev = "`";
3761
+ i += 1;
3762
+ continue;
3763
+ }
3764
+ if (ch === "$" && code.charAt(i + 1) === "{") {
3765
+ stack.push("{");
3766
+ prev = "{";
3767
+ i += 2;
3768
+ continue;
3769
+ }
3770
+ i += 1;
3771
+ continue;
3772
+ }
3773
+ if (ch === "/" && code.charAt(i + 1) === "/") {
3774
+ const newline = code.indexOf("\n", i);
3775
+ i = newline === -1 ? code.length : newline;
3776
+ continue;
3777
+ }
3778
+ if (ch === "/" && code.charAt(i + 1) === "*") {
3779
+ const close = code.indexOf("*/", i + 2);
3780
+ i = close === -1 ? code.length : close + 2;
3781
+ continue;
3782
+ }
3783
+ if (ch === '"' || ch === "'") {
3784
+ i = skipQuoted(code, i);
3785
+ prev = ch;
3786
+ continue;
3787
+ }
3788
+ if (ch === "`") {
3789
+ stack.push("`");
3790
+ i += 1;
3791
+ continue;
3792
+ }
3793
+ if (ch === "/" && regexCanStart(prev)) {
3794
+ i = skipRegex(code, i);
3795
+ prev = "/";
3796
+ continue;
3797
+ }
3798
+ if (ch === "(" || ch === "[" || ch === "{") {
3799
+ stack.push(ch);
3800
+ prev = ch;
3801
+ i += 1;
3802
+ continue;
3803
+ }
3804
+ if (ch === ")" || ch === "]" || ch === "}") {
3805
+ if (stack[stack.length - 1] !== MATCHING_OPEN[ch]) return { commas, end: i };
3806
+ stack.pop();
3807
+ prev = ch;
3808
+ i += 1;
3809
+ continue;
3810
+ }
3811
+ if (stack.length === 0) {
3812
+ if (ch === ";") return { commas, end: i };
3813
+ if (ch === ",") commas.push(i);
3814
+ if (ch === "\n" && !continuesOnto(code, i, prev)) return { commas, end: i };
3815
+ }
3816
+ if (!/\s/.test(ch)) prev = ch;
3817
+ i += 1;
3818
+ }
3819
+ return { commas, end: code.length };
3820
+ }
3821
+ function declaratorName(segment) {
3822
+ const match = /^\s*([A-Za-z_$][\w$]*)\s*(?:=(?![=>])|$)/.exec(segment);
3823
+ return match === null ? null : match[1] ?? null;
3824
+ }
3825
+ function restDeclarators(code, from) {
3826
+ const { commas, end } = scanDeclaration(code, from);
3827
+ if (commas.length === 0) return [];
3828
+ const segments = [];
3829
+ let cursor = from;
3830
+ for (const comma of commas) {
3831
+ segments.push(code.slice(cursor, comma));
3832
+ cursor = comma + 1;
3833
+ }
3834
+ segments.push(code.slice(cursor, end));
3835
+ const names = [];
3836
+ for (const segment of segments.slice(1)) {
3837
+ const name = declaratorName(segment);
3838
+ if (name === null) {
3839
+ throw new Error(
3840
+ `\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF1A"${segment.trim()}"\uFF08\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u9017\u53F7\u5206\u9694\u7684\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF0C\u5982 \`export const a = 1, b = 2\`\uFF1B\u542B\u89E3\u6784\u6216\u590D\u6742\u521D\u503C\u65F6\u8BF7\u62C6\u6210\u591A\u6761 export\uFF09`
3841
+ );
3842
+ }
3843
+ names.push(name);
3844
+ }
3845
+ return names;
3846
+ }
3601
3847
  function transformModule(code) {
3602
3848
  let out = code;
3603
3849
  const named = [];
@@ -3660,10 +3906,20 @@ function transformModule(code) {
3660
3906
  return `${lead}${indent}const ${temp} = require(${source})${pad}`;
3661
3907
  }
3662
3908
  );
3909
+ const destructured = /(^|\n)[ \t]*export\s+(const|let|var)\s*[{[]/.exec(out);
3910
+ if (destructured !== null) {
3911
+ const offset = destructured.index + (destructured[1] === "\n" ? 1 : 0);
3912
+ throw new Error(
3913
+ `\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF08\u7B2C ${lineNumberAt(out, offset)} \u884C\uFF09\uFF1A\u89E3\u6784\u5BFC\u51FA \`export ${destructured[2] ?? ""} { \u2026 } = \u2026\`\u3002\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF1A\u8BF7\u5148\u58F0\u660E\u518D \`export { a, b }\`\uFF0C\u6216\u62C6\u6210\u591A\u6761 \`export const\``
3914
+ );
3915
+ }
3663
3916
  out = out.replace(
3664
3917
  /export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
3665
- (_match, kw, name) => {
3918
+ (match, kw, name, offset, source) => {
3666
3919
  named.push({ local: name, exported: name });
3920
+ for (const extra of restDeclarators(source, offset + match.length)) {
3921
+ named.push({ local: extra, exported: extra });
3922
+ }
3667
3923
  return `${kw} ${name}`;
3668
3924
  }
3669
3925
  );
@@ -4340,7 +4596,9 @@ function errorMessageOf2(error) {
4340
4596
  return String(error);
4341
4597
  }
4342
4598
  async function normalizeResultBody(value) {
4343
- if (!(value instanceof Response)) return value;
4599
+ if (!(value instanceof Response)) {
4600
+ return coerceAdepHttpEnvelope(value) ?? value;
4601
+ }
4344
4602
  const contentType = value.headers.get("content-type") ?? "";
4345
4603
  const text = await value.text();
4346
4604
  let payload = text;
@@ -4588,7 +4846,7 @@ function createBearerUserResolver(issuer) {
4588
4846
  function isRuntimeSource(name) {
4589
4847
  return (name.endsWith(".ts") || name.endsWith(".js")) && !name.endsWith(".d.ts") && !name.endsWith(".test.ts");
4590
4848
  }
4591
- async function collectFunctions(dir) {
4849
+ async function collectFunctions(dir, readImpl = (path) => readFile6(path, "utf8")) {
4592
4850
  const files = {};
4593
4851
  const walk = async (sub, prefix) => {
4594
4852
  let entries;
@@ -4603,7 +4861,8 @@ async function collectFunctions(dir) {
4603
4861
  if (entry.isDirectory()) {
4604
4862
  await walk(full, rel);
4605
4863
  } else if (entry.isFile() && isRuntimeSource(entry.name)) {
4606
- files[rel] = await readFile6(full, "utf8");
4864
+ const content = await readImpl(full).catch(() => null);
4865
+ if (content !== null) files[rel] = content;
4607
4866
  }
4608
4867
  }
4609
4868
  };
@@ -4679,7 +4938,8 @@ async function loadConfig(cwd) {
4679
4938
  name: config?.name ?? name,
4680
4939
  functionsDir: config?.functionsDir ?? "functions",
4681
4940
  functionsPrefix: config?.functions_prefix ?? "",
4682
- ...config?.environment === void 0 ? {} : { environment: config.environment }
4941
+ ...config?.environment === void 0 ? {} : { environment: config.environment },
4942
+ ...config?.db_environment === void 0 ? {} : { dbEnvironment: config.db_environment }
4683
4943
  };
4684
4944
  }
4685
4945
  var parseEnvFile = parseEnv;
@@ -127,6 +127,158 @@ function parseExportClause(clause) {
127
127
  }
128
128
  return entries;
129
129
  }
130
+ var CONTINUES_AFTER = "=+-*/%&|^<>?:,.[(";
131
+ var CONTINUES_BEFORE = "`([.?:,+-*/%&|^<>=";
132
+ var REGEX_PRECEDERS = "(,=:[!&|?{};+-*%~^<>";
133
+ var MATCHING_OPEN = { ")": "(", "]": "[", "}": "{" };
134
+ function lineNumberAt(code, index) {
135
+ let line = 1;
136
+ for (let i = 0; i < index; i += 1) if (code.charCodeAt(i) === 10) line += 1;
137
+ return line;
138
+ }
139
+ function skipQuoted(code, start) {
140
+ const quote = code.charAt(start);
141
+ let i = start + 1;
142
+ while (i < code.length) {
143
+ const ch = code.charAt(i);
144
+ if (ch === "\\") {
145
+ i += 2;
146
+ continue;
147
+ }
148
+ if (ch === quote) return i + 1;
149
+ if (ch === "\n") return i;
150
+ i += 1;
151
+ }
152
+ return code.length;
153
+ }
154
+ function skipRegex(code, start) {
155
+ let i = start + 1;
156
+ let inClass = false;
157
+ while (i < code.length) {
158
+ const ch = code.charAt(i);
159
+ if (ch === "\\") {
160
+ i += 2;
161
+ continue;
162
+ }
163
+ if (ch === "\n") return start + 1;
164
+ if (ch === "[") inClass = true;
165
+ else if (ch === "]") inClass = false;
166
+ else if (ch === "/" && !inClass) return i + 1;
167
+ i += 1;
168
+ }
169
+ return code.length;
170
+ }
171
+ function regexCanStart(prev) {
172
+ return prev === "" || REGEX_PRECEDERS.includes(prev);
173
+ }
174
+ function continuesOnto(code, newline, prev) {
175
+ if (prev !== "" && CONTINUES_AFTER.includes(prev)) return true;
176
+ let i = newline + 1;
177
+ while (i < code.length && /\s/.test(code.charAt(i))) i += 1;
178
+ const next = code.charAt(i);
179
+ return next !== "" && CONTINUES_BEFORE.includes(next);
180
+ }
181
+ function scanDeclaration(code, from) {
182
+ const commas = [];
183
+ const stack = [];
184
+ let prev = "";
185
+ let i = from;
186
+ while (i < code.length) {
187
+ const ch = code.charAt(i);
188
+ if (stack[stack.length - 1] === "`") {
189
+ if (ch === "\\") {
190
+ i += 2;
191
+ continue;
192
+ }
193
+ if (ch === "`") {
194
+ stack.pop();
195
+ prev = "`";
196
+ i += 1;
197
+ continue;
198
+ }
199
+ if (ch === "$" && code.charAt(i + 1) === "{") {
200
+ stack.push("{");
201
+ prev = "{";
202
+ i += 2;
203
+ continue;
204
+ }
205
+ i += 1;
206
+ continue;
207
+ }
208
+ if (ch === "/" && code.charAt(i + 1) === "/") {
209
+ const newline = code.indexOf("\n", i);
210
+ i = newline === -1 ? code.length : newline;
211
+ continue;
212
+ }
213
+ if (ch === "/" && code.charAt(i + 1) === "*") {
214
+ const close = code.indexOf("*/", i + 2);
215
+ i = close === -1 ? code.length : close + 2;
216
+ continue;
217
+ }
218
+ if (ch === '"' || ch === "'") {
219
+ i = skipQuoted(code, i);
220
+ prev = ch;
221
+ continue;
222
+ }
223
+ if (ch === "`") {
224
+ stack.push("`");
225
+ i += 1;
226
+ continue;
227
+ }
228
+ if (ch === "/" && regexCanStart(prev)) {
229
+ i = skipRegex(code, i);
230
+ prev = "/";
231
+ continue;
232
+ }
233
+ if (ch === "(" || ch === "[" || ch === "{") {
234
+ stack.push(ch);
235
+ prev = ch;
236
+ i += 1;
237
+ continue;
238
+ }
239
+ if (ch === ")" || ch === "]" || ch === "}") {
240
+ if (stack[stack.length - 1] !== MATCHING_OPEN[ch]) return { commas, end: i };
241
+ stack.pop();
242
+ prev = ch;
243
+ i += 1;
244
+ continue;
245
+ }
246
+ if (stack.length === 0) {
247
+ if (ch === ";") return { commas, end: i };
248
+ if (ch === ",") commas.push(i);
249
+ if (ch === "\n" && !continuesOnto(code, i, prev)) return { commas, end: i };
250
+ }
251
+ if (!/\s/.test(ch)) prev = ch;
252
+ i += 1;
253
+ }
254
+ return { commas, end: code.length };
255
+ }
256
+ function declaratorName(segment) {
257
+ const match = /^\s*([A-Za-z_$][\w$]*)\s*(?:=(?![=>])|$)/.exec(segment);
258
+ return match === null ? null : match[1] ?? null;
259
+ }
260
+ function restDeclarators(code, from) {
261
+ const { commas, end } = scanDeclaration(code, from);
262
+ if (commas.length === 0) return [];
263
+ const segments = [];
264
+ let cursor = from;
265
+ for (const comma of commas) {
266
+ segments.push(code.slice(cursor, comma));
267
+ cursor = comma + 1;
268
+ }
269
+ segments.push(code.slice(cursor, end));
270
+ const names = [];
271
+ for (const segment of segments.slice(1)) {
272
+ const name = declaratorName(segment);
273
+ if (name === null) {
274
+ throw new Error(
275
+ `\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF1A"${segment.trim()}"\uFF08\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u9017\u53F7\u5206\u9694\u7684\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF0C\u5982 \`export const a = 1, b = 2\`\uFF1B\u542B\u89E3\u6784\u6216\u590D\u6742\u521D\u503C\u65F6\u8BF7\u62C6\u6210\u591A\u6761 export\uFF09`
276
+ );
277
+ }
278
+ names.push(name);
279
+ }
280
+ return names;
281
+ }
130
282
  function transformModule(code) {
131
283
  let out = code;
132
284
  const named = [];
@@ -189,10 +341,20 @@ function transformModule(code) {
189
341
  return `${lead}${indent}const ${temp} = require(${source})${pad}`;
190
342
  }
191
343
  );
344
+ const destructured = /(^|\n)[ \t]*export\s+(const|let|var)\s*[{[]/.exec(out);
345
+ if (destructured !== null) {
346
+ const offset = destructured.index + (destructured[1] === "\n" ? 1 : 0);
347
+ throw new Error(
348
+ `\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF08\u7B2C ${lineNumberAt(out, offset)} \u884C\uFF09\uFF1A\u89E3\u6784\u5BFC\u51FA \`export ${destructured[2] ?? ""} { \u2026 } = \u2026\`\u3002\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF1A\u8BF7\u5148\u58F0\u660E\u518D \`export { a, b }\`\uFF0C\u6216\u62C6\u6210\u591A\u6761 \`export const\``
349
+ );
350
+ }
192
351
  out = out.replace(
193
352
  /export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
194
- (_match, kw, name) => {
353
+ (match, kw, name, offset, source) => {
195
354
  named.push({ local: name, exported: name });
355
+ for (const extra of restDeclarators(source, offset + match.length)) {
356
+ named.push({ local: extra, exported: extra });
357
+ }
196
358
  return `${kw} ${name}`;
197
359
  }
198
360
  );
@@ -594,6 +756,8 @@ var DB_RPC = {
594
756
  query: "query",
595
757
  /** 写路径(CF-013):`(method=writeQuery, args=[sql, params])` → `{ changes }`。 */
596
758
  writeQuery: "writeQuery",
759
+ /** 通用执行(BUG-4,2026-10-14):`(method=execute, args=[sql, params?])` → `{ changes }`。 */
760
+ execute: "execute",
597
761
  /** 读取 owned 表变更流(DB-006):`(method=changes, args=[table, query])`。 */
598
762
  changes: "changes",
599
763
  /** 开启事务:`begin → txId`。 */
@@ -732,6 +896,39 @@ function createChainClient(capability, port, pending, nextId, spec) {
732
896
  return makeRoot(void 0);
733
897
  }
734
898
 
899
+ // packages/runtime/src/shared/http-envelope.ts
900
+ function coerceAdepHttpEnvelope(value) {
901
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
902
+ if (isAdepHttpEnvelope(value)) return value;
903
+ const keys = Object.keys(value);
904
+ if (keys.length === 0) return null;
905
+ if (!keys.every((key) => key === "status" || key === "body" || key === "headers")) return null;
906
+ const candidate = value;
907
+ const status = candidate.status;
908
+ if (typeof status !== "number" || !Number.isInteger(status) || status < 100 || status > 599) {
909
+ return null;
910
+ }
911
+ if ("headers" in candidate && candidate.headers !== void 0) {
912
+ const headers = candidate.headers;
913
+ if (typeof headers !== "object" || headers === null || Array.isArray(headers)) return null;
914
+ if (!Object.values(headers).every((headerValue2) => typeof headerValue2 === "string")) return null;
915
+ }
916
+ return {
917
+ __adepHttp: {
918
+ status,
919
+ ...candidate.headers === void 0 ? {} : { headers: candidate.headers },
920
+ body: candidate.body
921
+ }
922
+ };
923
+ }
924
+ function isAdepHttpEnvelope(value) {
925
+ if (typeof value !== "object" || value === null) return false;
926
+ const envelope = value.__adepHttp;
927
+ if (typeof envelope !== "object" || envelope === null) return false;
928
+ const status = envelope.status;
929
+ return typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599;
930
+ }
931
+
735
932
  // packages/runtime/src/functions/deps/manifest.ts
736
933
  function splitBareSpecifier(request) {
737
934
  if (request.startsWith("@")) {
@@ -751,7 +948,9 @@ function errorMessageOf2(error) {
751
948
  return String(error);
752
949
  }
753
950
  async function normalizeResultBody(value) {
754
- if (!(value instanceof Response)) return value;
951
+ if (!(value instanceof Response)) {
952
+ return coerceAdepHttpEnvelope(value) ?? value;
953
+ }
755
954
  const contentType = value.headers.get("content-type") ?? "";
756
955
  const text = await value.text();
757
956
  let payload = text;