@adep/cli 0.1.8 → 0.1.10

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
@@ -460,6 +460,16 @@ var init_prompt = __esm({
460
460
  }
461
461
  });
462
462
 
463
+ // packages/runtime/src/shared/regexp.ts
464
+ function escapeRegExp(text) {
465
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
466
+ }
467
+ var init_regexp = __esm({
468
+ "packages/runtime/src/shared/regexp.ts"() {
469
+ "use strict";
470
+ }
471
+ });
472
+
463
473
  // packages/runtime/src/shared/capability-keys.ts
464
474
  var RPC_CAPABILITY_KEY, CHAIN_CAPABILITY_KEY, DB_RPC, REALTIME_CAPABILITY_CODES, REALTIME_CAPABILITY_METHODS;
465
475
  var init_capability_keys = __esm({
@@ -1663,7 +1673,7 @@ var init_cloud = __esm({
1663
1673
  }
1664
1674
  });
1665
1675
 
1666
- // packages/cli/src/sim/sql-engine.ts
1676
+ // packages/runtime/src/sim/sql-engine.ts
1667
1677
  function ident(raw) {
1668
1678
  return raw.trim().replace(/^"|"$/g, "").trim();
1669
1679
  }
@@ -1677,6 +1687,7 @@ function stripQuotes(raw) {
1677
1687
  const t = raw.trim();
1678
1688
  if (/^'.*'$/.test(t)) return t.slice(1, -1);
1679
1689
  if (/^".*"$/.test(t)) return t.slice(1, -1);
1690
+ if (/^NULL$/i.test(t)) return null;
1680
1691
  return t;
1681
1692
  }
1682
1693
  function parseCreateTable(ddl) {
@@ -1685,7 +1696,7 @@ function parseCreateTable(ddl) {
1685
1696
  );
1686
1697
  if (m === null) return null;
1687
1698
  const name = ident(m[1]);
1688
- const body = m[2];
1699
+ const body = m[3];
1689
1700
  const columns = [];
1690
1701
  for (const part of body.split(",")) {
1691
1702
  const tokens = part.trim().split(/\s+/);
@@ -1697,50 +1708,109 @@ function parseCreateTable(ddl) {
1697
1708
  }
1698
1709
  return { name, columns };
1699
1710
  }
1700
- function parseWhereClauses(whereRaw, cursor) {
1701
- const clauses = [];
1702
- for (const part of whereRaw.split(/\s+AND\s+/i)) {
1703
- const t = part.trim();
1704
- if (t.length === 0) continue;
1705
- if (/\bIS\s+NULL\b/i.test(t)) {
1706
- const col2 = ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "");
1707
- clauses.push({ column: col2, operator: "IS NULL", value: null, list: false });
1708
- continue;
1709
- }
1710
- if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1711
- const col2 = ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "");
1712
- clauses.push({ column: col2, operator: "IS NOT NULL", value: null, list: false });
1713
- continue;
1714
- }
1715
- const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
1716
- t
1717
- );
1718
- if (opMatch === null) continue;
1719
- const col = ident(opMatch[1] ?? "");
1720
- const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
1721
- const rhs = (opMatch[4] ?? "").trim();
1722
- if (op === "in" || op === "not in") {
1723
- const inner = rhs.replace(/^\(|\)$/g, "");
1724
- const items = splitListItems(inner);
1725
- const list = items.map((item) => {
1726
- if (item.trim() === "?") return cursor.take();
1727
- return stripQuotes(item);
1728
- });
1729
- clauses.push({ column: col, operator: op, value: list, list: true });
1711
+ function splitTopLevel2(raw, token) {
1712
+ const parts = [];
1713
+ let depth = 0;
1714
+ let inQuote = false;
1715
+ let buffer = "";
1716
+ const n = raw.length;
1717
+ const isTokenAt = (i) => {
1718
+ const word = raw.slice(i, i + token.length);
1719
+ if (word.toUpperCase() !== token) return false;
1720
+ const before = i === 0 ? "" : raw[i - 1] ?? "";
1721
+ const after = raw[i + token.length] ?? "";
1722
+ return !/[A-Za-z0-9_.]/.test(before) && !/[A-Za-z0-9_.]/.test(after);
1723
+ };
1724
+ for (let i = 0; i < n; i += 1) {
1725
+ const ch = raw[i] ?? "";
1726
+ if (ch === "'") {
1727
+ if (inQuote && raw[i + 1] === "'") {
1728
+ buffer += ch + (raw[i + 1] ?? "");
1729
+ i += 1;
1730
+ continue;
1731
+ }
1732
+ inQuote = !inQuote;
1733
+ buffer += ch;
1730
1734
  continue;
1731
1735
  }
1732
- let value;
1733
- if (rhs === "?") {
1734
- value = cursor.take();
1736
+ if (!inQuote && ch === "(") depth += 1;
1737
+ else if (!inQuote && ch === ")") depth -= 1;
1738
+ if (!inQuote && depth === 0 && isTokenAt(i)) {
1739
+ parts.push(buffer);
1740
+ buffer = "";
1741
+ i += token.length - 1;
1735
1742
  } else {
1736
- value = stripQuotes(rhs);
1743
+ buffer += ch;
1737
1744
  }
1738
- clauses.push({ column: col, operator: op, value, list: false });
1739
1745
  }
1740
- return clauses;
1746
+ parts.push(buffer);
1747
+ return parts;
1748
+ }
1749
+ function unqualifyColumn(raw) {
1750
+ const t = raw.trim();
1751
+ const dot = t.lastIndexOf(".");
1752
+ if (dot > 0 && /^[A-Za-z_][A-Za-z0-9_]*\./.test(t)) return t.slice(dot + 1);
1753
+ return t;
1754
+ }
1755
+ function parseLeftJoins(tail) {
1756
+ const joins = [];
1757
+ const re = /LEFT\s+JOIN\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+([A-Za-z_][A-Za-z0-9_]*)\s+ON\s+([A-Za-z_][A-Za-z0-9_.]*)\s*=\s*([A-Za-z_][A-Za-z0-9_.]*)/gi;
1758
+ let m;
1759
+ while ((m = re.exec(tail)) !== null) {
1760
+ joins.push({
1761
+ table: ident(m[1] ?? ""),
1762
+ alias: m[3] ?? "",
1763
+ leftCol: unqualifyColumn(m[4] ?? ""),
1764
+ rightCol: unqualifyColumn(m[5] ?? "")
1765
+ });
1766
+ }
1767
+ return joins;
1768
+ }
1769
+ function parseWhereClauses(whereRaw, cursor) {
1770
+ const parseAndGroup = (andRaw) => {
1771
+ const clauses = [];
1772
+ for (const part of splitTopLevel2(andRaw, "AND")) {
1773
+ const t = part.trim();
1774
+ if (t.length === 0) continue;
1775
+ if (/\bIS\s+NULL\b/i.test(t)) {
1776
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "")), operator: "IS NULL", value: null, list: false });
1777
+ continue;
1778
+ }
1779
+ if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1780
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "")), operator: "IS NOT NULL", value: null, list: false });
1781
+ continue;
1782
+ }
1783
+ const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
1784
+ t
1785
+ );
1786
+ if (opMatch === null) continue;
1787
+ const col = unqualifyColumn(ident(opMatch[1] ?? ""));
1788
+ const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
1789
+ const rhs = (opMatch[4] ?? "").trim();
1790
+ if (op === "in" || op === "not in") {
1791
+ const inner = rhs.replace(/^\(|\)$/g, "");
1792
+ const items = splitListItems(inner);
1793
+ const list = items.map((item) => {
1794
+ if (item.trim() === "?") return cursor.take();
1795
+ return stripQuotes(item);
1796
+ });
1797
+ clauses.push({ column: col, operator: op, value: list, list: true });
1798
+ continue;
1799
+ }
1800
+ let value;
1801
+ if (rhs === "?") {
1802
+ value = cursor.take();
1803
+ } else {
1804
+ value = stripQuotes(rhs);
1805
+ }
1806
+ clauses.push({ column: col, operator: op, value, list: false });
1807
+ }
1808
+ return clauses;
1809
+ };
1810
+ return splitTopLevel2(whereRaw, "OR").map((group) => group.trim()).filter((group) => group.length > 0).map(parseAndGroup);
1741
1811
  }
1742
- function matchWhere(clauses, row) {
1743
- return clauses.every((c) => matchValue(row[c.column], c));
1812
+ function matchWhere(groups, row) {
1813
+ return groups.some((clauses) => clauses.every((c) => matchValue(row[c.column], c)));
1744
1814
  }
1745
1815
  function splitListItems(inner) {
1746
1816
  const items = [];
@@ -1760,6 +1830,153 @@ function splitListItems(inner) {
1760
1830
  items.push(buffer);
1761
1831
  return items;
1762
1832
  }
1833
+ function resolveSetValue(value, existing, row) {
1834
+ if (value instanceof ExcludedRef) return row[value.column];
1835
+ if (value instanceof ColumnRef) return existing[value.column];
1836
+ if (value instanceof ExprRef) return evalArithmetic(value.source, existing, row);
1837
+ return value;
1838
+ }
1839
+ function evalArithmetic(src, existing, row) {
1840
+ const num = (v) => {
1841
+ const n2 = Number(v);
1842
+ return Number.isFinite(n2) ? n2 : 0;
1843
+ };
1844
+ let i = 0;
1845
+ const n = src.length;
1846
+ const skip = () => {
1847
+ while (i < n && /\s/.test(src[i] ?? "")) i += 1;
1848
+ };
1849
+ const peek = () => {
1850
+ skip();
1851
+ return i < n ? src[i] ?? "" : null;
1852
+ };
1853
+ const parseIdent = () => {
1854
+ skip();
1855
+ const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
1856
+ if (m === null) return null;
1857
+ i += (m[1] ?? "").length;
1858
+ skip();
1859
+ let col = ident(m[1] ?? "");
1860
+ let excluded = false;
1861
+ if (src[i] === ".") {
1862
+ const m2 = /^\.([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
1863
+ if (m2 !== null) {
1864
+ i += (m2[0] ?? "").length;
1865
+ if (col.toLowerCase() === "excluded") excluded = true;
1866
+ col = ident(m2[1] ?? "");
1867
+ }
1868
+ }
1869
+ return { col, excluded };
1870
+ };
1871
+ const parseFactor = () => {
1872
+ const ch = peek();
1873
+ if (ch === "(") {
1874
+ i += 1;
1875
+ const v = parseExpr();
1876
+ skip();
1877
+ if (src[i] === ")") i += 1;
1878
+ return v;
1879
+ }
1880
+ const numMatch = /^(\d+(?:\.\d+)?)/.exec(src.slice(i));
1881
+ if (numMatch !== null) {
1882
+ i += (numMatch[1] ?? "").length;
1883
+ return Number(numMatch[1]);
1884
+ }
1885
+ const id = parseIdent();
1886
+ if (id !== null) {
1887
+ const v = id.excluded ? row[id.col] : existing[id.col];
1888
+ return num(v);
1889
+ }
1890
+ return 0;
1891
+ };
1892
+ const parseTerm = () => {
1893
+ let v = parseFactor();
1894
+ for (; ; ) {
1895
+ const ch = peek();
1896
+ if (ch !== "*" && ch !== "/") return v;
1897
+ i += 1;
1898
+ const rhs = parseFactor();
1899
+ v = ch === "*" ? v * rhs : rhs === 0 ? v : v / rhs;
1900
+ }
1901
+ };
1902
+ const parseExpr = () => {
1903
+ let v = parseTerm();
1904
+ for (; ; ) {
1905
+ const ch = peek();
1906
+ if (ch !== "+" && ch !== "-") return v;
1907
+ i += 1;
1908
+ const rhs = parseTerm();
1909
+ v = ch === "+" ? v + rhs : v - rhs;
1910
+ }
1911
+ };
1912
+ return parseExpr();
1913
+ }
1914
+ function splitInsertTuples(body) {
1915
+ const tuples = [];
1916
+ let i = 0;
1917
+ const n = body.length;
1918
+ while (i < n) {
1919
+ while (i < n && (body[i] === " " || body[i] === " " || body[i] === "\n" || body[i] === "\r" || body[i] === ",")) {
1920
+ i += 1;
1921
+ }
1922
+ if (i >= n) break;
1923
+ if (body[i] !== "(") {
1924
+ return { tuples, conflict: body.slice(i).trim() };
1925
+ }
1926
+ let depth = 0;
1927
+ let j = i;
1928
+ for (; j < n; j += 1) {
1929
+ if (body[j] === "(") depth += 1;
1930
+ else if (body[j] === ")") {
1931
+ depth -= 1;
1932
+ if (depth === 0) break;
1933
+ }
1934
+ }
1935
+ if (j >= n) return { tuples, conflict: null };
1936
+ tuples.push(body.slice(i + 1, j));
1937
+ i = j + 1;
1938
+ }
1939
+ return { tuples, conflict: null };
1940
+ }
1941
+ function parseConflictClause(clause, cursor, fallbackCols) {
1942
+ const m = /^ON\s+CONFLICT(?:\s*\(([^)]*)\))?\s+DO\s+(UPDATE\s+SET\s+([\s\S]+)|NOTHING\s*)$/i.exec(
1943
+ clause.trim()
1944
+ );
1945
+ if (m === null) {
1946
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 ON CONFLICT \u5B50\u53E5\uFF1A${clause.trim().slice(0, 60)}\u2026`);
1947
+ }
1948
+ const colsRaw = m[1];
1949
+ const cols = colsRaw === void 0 ? fallbackCols : colsRaw.split(",").map(ident);
1950
+ if (cols.length === 0) throw new SimDbError("DB_UNSAFE_OP", "ON CONFLICT \u51B2\u7A81\u5217\u4E3A\u7A7A");
1951
+ const action = m[2] ?? "";
1952
+ if (/^NOTHING/i.test(action)) return { cols, sets: [] };
1953
+ const setRaw = m[3] ?? "";
1954
+ const sets = splitListItems(setRaw).map((part) => {
1955
+ const eq = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([\s\S]+)$/i.exec(part.trim());
1956
+ if (eq === null) {
1957
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 SET \u8D4B\u503C\uFF1A${part.trim().slice(0, 60)}\u2026`);
1958
+ }
1959
+ const col = ident(eq[1] ?? "");
1960
+ const rhs = (eq[2] ?? "").trim();
1961
+ let value;
1962
+ if (rhs === "?") {
1963
+ value = cursor.take();
1964
+ } else {
1965
+ const ex = /^excluded\.([A-Za-z_][A-Za-z0-9_]*)$/i.exec(rhs);
1966
+ if (ex !== null) {
1967
+ value = new ExcludedRef(ident(ex[1] ?? ""));
1968
+ } else if (/^([A-Za-z_][A-Za-z0-9_]*)$/.test(rhs) && !/^NULL$/i.test(rhs)) {
1969
+ value = new ColumnRef(ident(rhs));
1970
+ } else if (/^'.*'$/.test(rhs) || /^".*"$/.test(rhs) || /^NULL$/i.test(rhs)) {
1971
+ value = stripQuotes(rhs);
1972
+ } else {
1973
+ value = new ExprRef(rhs);
1974
+ }
1975
+ }
1976
+ return { col, value };
1977
+ });
1978
+ return { cols, sets };
1979
+ }
1763
1980
  function matchValue(value, clause) {
1764
1981
  const op = clause.operator;
1765
1982
  if (op === "IS NULL") return value === null || value === void 0;
@@ -1775,9 +1992,9 @@ function matchValue(value, clause) {
1775
1992
  const right = clause.value;
1776
1993
  switch (op) {
1777
1994
  case "=":
1778
- return left === right;
1995
+ return left !== null && right !== null && left === right;
1779
1996
  case "!=":
1780
- return left !== right;
1997
+ return left !== null && right !== null && left !== right;
1781
1998
  case ">":
1782
1999
  return left !== null && right !== null && left > right;
1783
2000
  case ">=":
@@ -1809,6 +2026,15 @@ function indexAfter(start, matches, tail) {
1809
2026
  const end = candidates.length === 0 ? -1 : Math.min(...candidates);
1810
2027
  return end === -1 ? tail.length : end;
1811
2028
  }
2029
+ function parseSelectItem(raw) {
2030
+ const t = raw.trim();
2031
+ const as = /\s+AS\s+([A-Za-z_][A-Za-z0-9_]*)$/i.exec(t);
2032
+ let name = as === null ? t : t.slice(0, as.index).trim();
2033
+ if (unqualifyColumn(name) === "*") return { name: "", qualified: "", alias: "", star: true };
2034
+ const qualified = /^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? ident(name) : "";
2035
+ const plain = unqualifyColumn(ident(name));
2036
+ return { name: plain, qualified, alias: as === null ? plain : ident(as[1] ?? ""), star: false };
2037
+ }
1812
2038
  function project(rows, selectRaw) {
1813
2039
  if (/^count\s*\(\s*\*/i.test(selectRaw) || /^count\s*\(\s*1\)/i.test(selectRaw)) {
1814
2040
  const alias = selectRaw.match(/\bAS\s+([A-Za-z_][A-Za-z0-9_]*)/i)?.[1] ?? "n";
@@ -1819,16 +2045,27 @@ function project(rows, selectRaw) {
1819
2045
  return [{ [constMatch[2]]: Number(constMatch[1]) }];
1820
2046
  }
1821
2047
  if (selectRaw.trim() === "*") return rows;
1822
- const cols = selectRaw.split(",").map((s) => ident(s.trim()));
2048
+ const items = selectRaw.split(",").map(parseSelectItem);
2049
+ const valueOf = (row, item) => item.qualified !== "" && row[item.qualified] !== void 0 ? row[item.qualified] : row[item.name];
2050
+ if (items.some((item) => item.star)) {
2051
+ return rows.map((row) => {
2052
+ const out = { ...row };
2053
+ for (const item of items) {
2054
+ if (item.star) continue;
2055
+ out[item.alias] = valueOf(row, item);
2056
+ }
2057
+ return out;
2058
+ });
2059
+ }
1823
2060
  return rows.map((row) => {
1824
2061
  const out = {};
1825
- for (const col of cols) out[col] = row[col];
2062
+ for (const item of items) out[item.alias] = valueOf(row, item);
1826
2063
  return out;
1827
2064
  });
1828
2065
  }
1829
- var SimDbError, ParamCursor, SimSqlEngine;
2066
+ var SimDbError, ParamCursor, ExcludedRef, ColumnRef, ExprRef, SimSqlEngine;
1830
2067
  var init_sql_engine = __esm({
1831
- "packages/cli/src/sim/sql-engine.ts"() {
2068
+ "packages/runtime/src/sim/sql-engine.ts"() {
1832
2069
  "use strict";
1833
2070
  SimDbError = class extends Error {
1834
2071
  constructor(code, message) {
@@ -1848,6 +2085,21 @@ var init_sql_engine = __esm({
1848
2085
  return v ?? null;
1849
2086
  }
1850
2087
  };
2088
+ ExcludedRef = class {
2089
+ constructor(column) {
2090
+ this.column = column;
2091
+ }
2092
+ };
2093
+ ColumnRef = class {
2094
+ constructor(column) {
2095
+ this.column = column;
2096
+ }
2097
+ };
2098
+ ExprRef = class {
2099
+ constructor(source) {
2100
+ this.source = source;
2101
+ }
2102
+ };
1851
2103
  SimSqlEngine = class {
1852
2104
  tables = {};
1853
2105
  storage;
@@ -1957,16 +2209,36 @@ var init_sql_engine = __esm({
1957
2209
  const valueBody = match[4].trim();
1958
2210
  const cursor = new ParamCursor(params);
1959
2211
  const table = this.ensureTable(tableName);
2212
+ const { tuples, conflict } = splitInsertTuples(valueBody);
2213
+ if (tuples.length === 0) throw new SimDbError("DB_UNSAFE_OP", "INSERT \u7F3A\u5C11 VALUES \u5143\u7EC4");
2214
+ const conflictSpec = conflict === null ? null : parseConflictClause(
2215
+ conflict,
2216
+ cursor,
2217
+ table.columns.filter((c) => c.primaryKey).map((c) => c.name)
2218
+ );
1960
2219
  let inserted = 0;
1961
- for (const group of splitListItems(valueBody)) {
1962
- const inner = group.trim().replace(/^\(|\)$/g, "");
1963
- const values = splitListItems(inner).map(
2220
+ for (const tuple of tuples) {
2221
+ const values = splitListItems(tuple).map(
1964
2222
  (item) => item.trim() === "?" ? cursor.take() : stripQuotes(item)
1965
2223
  );
1966
2224
  const row = {};
1967
2225
  cols.forEach((col, i) => {
1968
2226
  row[col] = values[i] ?? null;
1969
2227
  });
2228
+ if (conflictSpec !== null) {
2229
+ const existing = table.rows.find(
2230
+ (r) => conflictSpec.cols.every((c) => r[c] === row[c])
2231
+ );
2232
+ if (existing !== void 0) {
2233
+ const oldRow = { ...existing };
2234
+ for (const set of conflictSpec.sets) {
2235
+ existing[set.col] = resolveSetValue(set.value, oldRow, row);
2236
+ }
2237
+ inserted += 1;
2238
+ void this.persist();
2239
+ continue;
2240
+ }
2241
+ }
1970
2242
  this.applyAutoincrement(table, row);
1971
2243
  table.rows.push(row);
1972
2244
  inserted += 1;
@@ -2035,6 +2307,20 @@ var init_sql_engine = __esm({
2035
2307
  return project(this.catalog(), selectRaw);
2036
2308
  }
2037
2309
  const table = this.ensureTable(tableName);
2310
+ let rows = table.rows;
2311
+ const joins = parseLeftJoins(tail);
2312
+ if (joins.length > 0) {
2313
+ rows = table.rows.map((row) => {
2314
+ const merged = { ...row };
2315
+ for (const j of joins) {
2316
+ const joined = this.tables[j.table]?.rows.find((jr) => jr[j.leftCol] === merged[j.rightCol]);
2317
+ if (joined !== void 0) {
2318
+ for (const [k, v] of Object.entries(joined)) merged[`${j.alias}.${k}`] = v;
2319
+ }
2320
+ }
2321
+ return merged;
2322
+ });
2323
+ }
2038
2324
  const whereMatch = /\bWHERE\b/i.exec(tail);
2039
2325
  const orderMatch = /\bORDER\s+BY\b/i.exec(tail);
2040
2326
  const limitMatch = /\bLIMIT\b/i.exec(tail);
@@ -2043,7 +2329,6 @@ var init_sql_engine = __esm({
2043
2329
  whereMatch.index + whereMatch[0].length,
2044
2330
  indexAfter(whereMatch.index, [orderMatch, limitMatch, offsetMatch], tail)
2045
2331
  );
2046
- let rows = table.rows;
2047
2332
  if (whereRaw.trim().length > 0) {
2048
2333
  const clauses = parseWhereClauses(whereRaw, cursor);
2049
2334
  rows = rows.filter((row) => matchWhere(clauses, row));
@@ -2053,9 +2338,9 @@ var init_sql_engine = __esm({
2053
2338
  orderMatch.index + orderMatch[0].length,
2054
2339
  indexAfter(orderMatch.index, [limitMatch, offsetMatch], tail)
2055
2340
  );
2056
- const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+(asc|desc)/i.exec(orderRaw);
2341
+ const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s+(asc|desc)/i.exec(orderRaw);
2057
2342
  if (oc !== null) {
2058
- const col = ident(oc[1]);
2343
+ const col = unqualifyColumn(ident(oc[1]));
2059
2344
  const dir = oc[3].toLowerCase();
2060
2345
  rows = [...rows].toSorted((a, b) => {
2061
2346
  const av = a[col];
@@ -2258,6 +2543,19 @@ function assertSafeStoragePath(path) {
2258
2543
  }
2259
2544
  return path;
2260
2545
  }
2546
+ function assertStoragePrefix(prefix) {
2547
+ if (prefix !== void 0 && prefix !== "") {
2548
+ const segments = prefix.split("/");
2549
+ if (prefix.startsWith("/") || /[\\]/.test(prefix) || segments.some((segment) => segment === "..")) {
2550
+ throw new StorageError(
2551
+ 400,
2552
+ STORAGE_CODES.invalidPath,
2553
+ `\u975E\u6CD5\u524D\u7F00 "${prefix}"\uFF08\u7981\u6B62 / \u5F00\u5934\u3001\u53CD\u659C\u6760\u6216 .. \u7A7F\u8D8A\uFF09`
2554
+ );
2555
+ }
2556
+ }
2557
+ return prefix ?? "";
2558
+ }
2261
2559
  var PROJECT_QUOTA_BYTES, StorageError, STORAGE_CODES;
2262
2560
  var init_driver = __esm({
2263
2561
  "packages/runtime/src/storage/driver.ts"() {
@@ -2682,16 +2980,7 @@ function createLocalStorageDriver(options) {
2682
2980
  await unlink(metaPath(projectId, path)).catch(() => void 0);
2683
2981
  },
2684
2982
  async list(projectId, prefix) {
2685
- if (prefix !== void 0 && prefix !== "") {
2686
- const segments = prefix.split("/");
2687
- if (prefix.startsWith("/") || /[\\]/.test(prefix) || segments.some((segment) => segment === "..")) {
2688
- throw new StorageError(
2689
- 400,
2690
- STORAGE_CODES.invalidPath,
2691
- `\u975E\u6CD5\u524D\u7F00 "${prefix}"\uFF08\u7981\u6B62 / \u5F00\u5934\u3001\u53CD\u659C\u6760\u6216 .. \u7A7F\u8D8A\uFF09`
2692
- );
2693
- }
2694
- }
2983
+ assertStoragePrefix(prefix);
2695
2984
  const root = bucketDir(projectId);
2696
2985
  const metas = [];
2697
2986
  const walk = async (dir, relative6) => {
@@ -2773,7 +3062,7 @@ var init_storage = __esm({
2773
3062
  }
2774
3063
  });
2775
3064
 
2776
- // packages/cli/src/sim/realtime.ts
3065
+ // packages/runtime/src/sim/realtime.ts
2777
3066
  function realtimeError(code, message) {
2778
3067
  return new Error(`[${code}] ${message}`);
2779
3068
  }
@@ -2854,7 +3143,7 @@ function createSimRealtimeCapability() {
2854
3143
  }
2855
3144
  var SimRealtime, MAX_BUFFERED_MESSAGES, MAX_SUBSCRIPTIONS, REALTIME_CODES;
2856
3145
  var init_realtime = __esm({
2857
- "packages/cli/src/sim/realtime.ts"() {
3146
+ "packages/runtime/src/sim/realtime.ts"() {
2858
3147
  "use strict";
2859
3148
  init_capability_keys();
2860
3149
  SimRealtime = class {
@@ -2902,12 +3191,7 @@ var init_realtime = __esm({
2902
3191
  }
2903
3192
  });
2904
3193
 
2905
- // packages/cli/src/sim/runtime.ts
2906
- import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
2907
- import { dirname as dirname6, join as join6 } from "node:path";
2908
- function simDir(cwd) {
2909
- return join6(cwd, ".adep", "sim");
2910
- }
3194
+ // packages/runtime/src/sim/merge.ts
2911
3195
  function mergeBundles(bundles) {
2912
3196
  const capabilities = [];
2913
3197
  const byName = /* @__PURE__ */ new Map();
@@ -2927,6 +3211,18 @@ function mergeBundles(bundles) {
2927
3211
  }
2928
3212
  return { capabilities, rpcHandlers };
2929
3213
  }
3214
+ var init_merge = __esm({
3215
+ "packages/runtime/src/sim/merge.ts"() {
3216
+ "use strict";
3217
+ }
3218
+ });
3219
+
3220
+ // packages/cli/src/sim/runtime.ts
3221
+ import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
3222
+ import { dirname as dirname6, join as join6 } from "node:path";
3223
+ function simDir(cwd) {
3224
+ return join6(cwd, ".adep", "sim");
3225
+ }
2930
3226
  function jsonStorage(cwd) {
2931
3227
  const file = join6(simDir(cwd), "db.json");
2932
3228
  return {
@@ -2974,6 +3270,7 @@ var init_runtime = __esm({
2974
3270
  init_kv();
2975
3271
  init_storage();
2976
3272
  init_realtime();
3273
+ init_merge();
2977
3274
  }
2978
3275
  });
2979
3276
 
@@ -3073,16 +3370,32 @@ var init_invoke = __esm({
3073
3370
  }
3074
3371
  });
3075
3372
 
3076
- // packages/cli/src/builtin-deps.ts
3077
- var LOCAL_STATE_OBJECTS_SPECIFIER, LOCAL_BUILTIN_DEPS;
3373
+ // shared/builtin-deps.ts
3374
+ var CF_COMPAT_SPECIFIER, STATE_OBJECTS_SPECIFIER, BUILTIN_DEPS, BUILTIN_DEPS_CSV;
3078
3375
  var init_builtin_deps = __esm({
3079
- "packages/cli/src/builtin-deps.ts"() {
3376
+ "shared/builtin-deps.ts"() {
3080
3377
  "use strict";
3081
- LOCAL_STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
3082
- LOCAL_BUILTIN_DEPS = [
3083
- "@adep/cf-compat",
3084
- LOCAL_STATE_OBJECTS_SPECIFIER
3378
+ CF_COMPAT_SPECIFIER = "@adep/cf-compat";
3379
+ STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
3380
+ BUILTIN_DEPS = [
3381
+ CF_COMPAT_SPECIFIER,
3382
+ STATE_OBJECTS_SPECIFIER,
3383
+ "axios",
3384
+ "lodash",
3385
+ "dayjs",
3386
+ "zod"
3085
3387
  ];
3388
+ BUILTIN_DEPS_CSV = BUILTIN_DEPS.join(",");
3389
+ }
3390
+ });
3391
+
3392
+ // packages/cli/src/builtin-deps.ts
3393
+ var LOCAL_BUILTIN_DEPS;
3394
+ var init_builtin_deps2 = __esm({
3395
+ "packages/cli/src/builtin-deps.ts"() {
3396
+ "use strict";
3397
+ init_builtin_deps();
3398
+ LOCAL_BUILTIN_DEPS = [CF_COMPAT_SPECIFIER, STATE_OBJECTS_SPECIFIER];
3086
3399
  }
3087
3400
  });
3088
3401
 
@@ -3629,7 +3942,7 @@ var init_sandbox = __esm({
3629
3942
 
3630
3943
  // packages/runtime/src/state-objects/loader.ts
3631
3944
  function resolveStateObjectSpecifier(request) {
3632
- if (request === STATE_OBJECTS_SPECIFIER) return { StateObject };
3945
+ if (request === STATE_OBJECTS_SPECIFIER2) return { StateObject };
3633
3946
  return void 0;
3634
3947
  }
3635
3948
  function defaultStateSandboxGlobals() {
@@ -3686,14 +3999,14 @@ function loadStateObjectClasses(files, entry = STATE_OBJECTS_ENTRY, options = {}
3686
3999
  const exportsObject = loadModule(entry, files, globals, /* @__PURE__ */ new Map(), options.resolveBare, /* @__PURE__ */ new Map());
3687
4000
  return collectStateObjectClasses(exportsObject);
3688
4001
  }
3689
- var STATE_OBJECTS_ENTRY, STATE_OBJECTS_SPECIFIER;
4002
+ var STATE_OBJECTS_ENTRY, STATE_OBJECTS_SPECIFIER2;
3690
4003
  var init_loader = __esm({
3691
4004
  "packages/runtime/src/state-objects/loader.ts"() {
3692
4005
  "use strict";
3693
4006
  init_runtime2();
3694
4007
  init_sandbox();
3695
4008
  STATE_OBJECTS_ENTRY = "state-objects.ts";
3696
- STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
4009
+ STATE_OBJECTS_SPECIFIER2 = "@adep/runtime/state-objects";
3697
4010
  }
3698
4011
  });
3699
4012
 
@@ -3988,6 +4301,24 @@ var init_rpc_key = __esm({
3988
4301
  }
3989
4302
  });
3990
4303
 
4304
+ // packages/runtime/src/functions/runtime/rpc-wire.ts
4305
+ function wireRpcResponses(port, pending) {
4306
+ port.on?.((message) => {
4307
+ const reply = message;
4308
+ if (reply?.type !== "rpc-response" || typeof reply.id !== "number") return;
4309
+ const entry = pending.get(reply.id);
4310
+ if (entry === void 0) return;
4311
+ pending.delete(reply.id);
4312
+ if (reply.ok === true) entry.resolve(reply.result);
4313
+ else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
4314
+ });
4315
+ }
4316
+ var init_rpc_wire = __esm({
4317
+ "packages/runtime/src/functions/runtime/rpc-wire.ts"() {
4318
+ "use strict";
4319
+ }
4320
+ });
4321
+
3991
4322
  // packages/runtime/src/functions/runtime/chain.ts
3992
4323
  function isChainCapability(value) {
3993
4324
  if (typeof value !== "object" || value === null) return false;
@@ -4098,13 +4429,10 @@ function errorMessageOf2(error) {
4098
4429
  }
4099
4430
  return String(error);
4100
4431
  }
4101
- function escapeRegExp2(text) {
4102
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4103
- }
4104
4432
  function firstUserFrame(stack, files) {
4105
4433
  for (const key of Object.keys(files)) {
4106
4434
  const match = new RegExp(
4107
- `(?<![\\w$/.])${escapeRegExp2(key)}:(\\d+)(?::(\\d+))?(?::(\\d+))?`
4435
+ `(?<![\\w$/.])${escapeRegExp(key)}:(\\d+)(?::(\\d+))?(?::(\\d+))?`
4108
4436
  ).exec(stack);
4109
4437
  if (match !== null) {
4110
4438
  return match[2] === void 0 ? `${key}:${match[1]}` : `${key}:${match[1]}:${match[2]}`;
@@ -4159,15 +4487,7 @@ function runWorker(input, port) {
4159
4487
  const container = createCloudContainer();
4160
4488
  const pending = /* @__PURE__ */ new Map();
4161
4489
  let rpcId = 0;
4162
- port.on?.((message) => {
4163
- const reply = message;
4164
- if (reply?.type !== "rpc-response" || typeof reply.id !== "number") return;
4165
- const entry = pending.get(reply.id);
4166
- if (entry === void 0) return;
4167
- pending.delete(reply.id);
4168
- if (reply.ok === true) entry.resolve(reply.result);
4169
- else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
4170
- });
4490
+ wireRpcResponses(port, pending);
4171
4491
  for (const capability of input.capabilities ?? []) {
4172
4492
  container.register(
4173
4493
  capability.name,
@@ -4269,9 +4589,11 @@ var init_worker_entry = __esm({
4269
4589
  init_sandbox();
4270
4590
  init_sandbox_fetch();
4271
4591
  init_rpc_key();
4592
+ init_rpc_wire();
4272
4593
  init_chain();
4273
4594
  init_sandbox();
4274
4595
  init_manifest();
4596
+ init_regexp();
4275
4597
  workerPort = parentPort;
4276
4598
  if (workerPort !== null && workerData !== void 0) {
4277
4599
  const port = {
@@ -4286,43 +4608,38 @@ var init_worker_entry = __esm({
4286
4608
  }
4287
4609
  });
4288
4610
 
4289
- // packages/cli/src/dev.ts
4290
- var dev_exports = {};
4291
- __export(dev_exports, {
4292
- loadConfig: () => loadConfig,
4293
- parseEnvFile: () => parseEnvFile,
4294
- resolveRouteFnName: () => resolveRouteFnName,
4295
- startDevServer: () => startDevServer
4296
- });
4297
- import { createServer } from "node:http";
4298
- import { watch } from "node:fs";
4299
- import { mkdir as mkdir6, readdir as readdir3, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
4300
- import { basename as basename2, join as join10, resolve as resolve4 } from "node:path";
4301
- async function loadConfig(cwd) {
4302
- const name = basename2(resolve4(cwd));
4303
- const config = await loadAdepConfigModule(cwd);
4304
- return {
4305
- name: config?.name ?? name,
4306
- functionsDir: config?.functionsDir ?? "functions",
4307
- functionsPrefix: config?.functions_prefix ?? "",
4308
- ...config?.environment === void 0 ? {} : { environment: config.environment }
4611
+ // packages/cli/src/dev-shared.ts
4612
+ import { readdir as readdir3, readFile as readFile7 } from "node:fs/promises";
4613
+ import { join as join10 } from "node:path";
4614
+ function bearerUserResolverFromEnv() {
4615
+ const raw = process.env.ADEP_AUTH_ISSUER;
4616
+ if (raw === void 0 || raw.trim() === "") return void 0;
4617
+ return createBearerUserResolver(raw.trim());
4618
+ }
4619
+ function createBearerUserResolver(issuer) {
4620
+ const userinfoUrl = `${issuer.replace(/\/+$/, "")}/oauth/userinfo`;
4621
+ return async (headers) => {
4622
+ const match = BEARER_TOKEN_RE.exec((headers["authorization"] ?? "").trim());
4623
+ const token = match?.[1]?.trim();
4624
+ if (token === void 0 || token === "") return null;
4625
+ try {
4626
+ const res = await fetch(userinfoUrl, { headers: { authorization: `Bearer ${token}` } });
4627
+ if (!res.ok) return null;
4628
+ const claims = await res.json();
4629
+ if (typeof claims.sub !== "string" || claims.sub.length === 0) return null;
4630
+ return {
4631
+ id: claims.sub,
4632
+ ...typeof claims.name === "string" ? { name: claims.name } : {},
4633
+ ...typeof claims.email === "string" ? { email: claims.email } : {}
4634
+ };
4635
+ } catch {
4636
+ return null;
4637
+ }
4309
4638
  };
4310
4639
  }
4311
- function parseEnvFile(content) {
4312
- const env = {};
4313
- for (const raw of content.split(/\r?\n/)) {
4314
- const line = raw.trim();
4315
- if (line.length === 0 || line.startsWith("#")) continue;
4316
- const eq = line.indexOf("=");
4317
- if (eq === -1) continue;
4318
- const key = line.slice(0, eq).trim();
4319
- if (key.length === 0) continue;
4320
- env[key] = line.slice(eq + 1).trim();
4321
- }
4322
- return env;
4323
- }
4324
4640
  async function collectFunctions(dir) {
4325
4641
  const files = {};
4642
+ const isRuntimeSource = (name) => (name.endsWith(".ts") || name.endsWith(".js")) && !name.endsWith(".d.ts") && !name.endsWith(".test.ts");
4326
4643
  const walk = async (sub, prefix) => {
4327
4644
  let entries;
4328
4645
  try {
@@ -4335,7 +4652,7 @@ async function collectFunctions(dir) {
4335
4652
  const full = join10(sub, entry.name);
4336
4653
  if (entry.isDirectory()) {
4337
4654
  await walk(full, rel);
4338
- } else if (entry.isFile() && entry.name.endsWith(".ts")) {
4655
+ } else if (entry.isFile() && isRuntimeSource(entry.name)) {
4339
4656
  files[rel] = await readFile7(full, "utf8");
4340
4657
  }
4341
4658
  }
@@ -4362,6 +4679,59 @@ function bodyOf(req) {
4362
4679
  req.on("error", rejectBody);
4363
4680
  });
4364
4681
  }
4682
+ function writeJson(res, status, payload) {
4683
+ res.writeHead(status, { "content-type": "application/json" });
4684
+ res.end(JSON.stringify(payload));
4685
+ }
4686
+ async function requestInput(url, req, readBody) {
4687
+ const query = {};
4688
+ for (const key of new Set(url.searchParams.keys())) {
4689
+ const values = url.searchParams.getAll(key);
4690
+ query[key] = values.length > 1 ? values.join(",") : values[0] ?? "";
4691
+ }
4692
+ const headers = {};
4693
+ for (const [key, value] of Object.entries(req.headers)) {
4694
+ if (typeof value === "string") headers[key] = value;
4695
+ }
4696
+ const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await readBody(req);
4697
+ return {
4698
+ method: req.method ?? "GET",
4699
+ path: url.pathname,
4700
+ query,
4701
+ headers,
4702
+ ...body === void 0 ? {} : { body }
4703
+ };
4704
+ }
4705
+ var BEARER_TOKEN_RE;
4706
+ var init_dev_shared = __esm({
4707
+ "packages/cli/src/dev-shared.ts"() {
4708
+ "use strict";
4709
+ BEARER_TOKEN_RE = /^Bearer\s+(.+)$/i;
4710
+ }
4711
+ });
4712
+
4713
+ // packages/cli/src/dev.ts
4714
+ var dev_exports = {};
4715
+ __export(dev_exports, {
4716
+ loadConfig: () => loadConfig,
4717
+ parseEnvFile: () => parseEnvFile,
4718
+ resolveRouteFnName: () => resolveRouteFnName,
4719
+ startDevServer: () => startDevServer
4720
+ });
4721
+ import { createServer } from "node:http";
4722
+ import { watch } from "node:fs";
4723
+ import { mkdir as mkdir6, readFile as readFile8, writeFile as writeFile5 } from "node:fs/promises";
4724
+ import { basename as basename2, join as join11, resolve as resolve4 } from "node:path";
4725
+ async function loadConfig(cwd) {
4726
+ const name = basename2(resolve4(cwd));
4727
+ const config = await loadAdepConfigModule(cwd);
4728
+ return {
4729
+ name: config?.name ?? name,
4730
+ functionsDir: config?.functionsDir ?? "functions",
4731
+ functionsPrefix: config?.functions_prefix ?? "",
4732
+ ...config?.environment === void 0 ? {} : { environment: config.environment }
4733
+ };
4734
+ }
4365
4735
  function resolveRouteFnName(pathname, prefix) {
4366
4736
  const segments = pathname.split("/").filter((segment) => segment.length > 0);
4367
4737
  const normalizedPrefix = prefix.replace(/^\/+|\/+$/g, "");
@@ -4388,10 +4758,6 @@ function resolveRouteFnName(pathname, prefix) {
4388
4758
  }
4389
4759
  return { fnName: second };
4390
4760
  }
4391
- function writeJson(res, status, payload) {
4392
- res.writeHead(status, { "content-type": "application/json" });
4393
- res.end(JSON.stringify(payload));
4394
- }
4395
4761
  function printBoundaries(log) {
4396
4762
  log("[adep] \u80FD\u529B\u8FB9\u754C\uFF08\u6A21\u62DF\u8FD0\u884C\u65F6\u53EA\u66FF\u6362\u4F20\u8F93/\u6301\u4E45\u5316\uFF0C\u4E0D\u6539\u5199\u8BED\u4E49\uFF09\uFF1A");
4397
4763
  for (const b of SIM_BOUNDARIES) {
@@ -4399,8 +4765,8 @@ function printBoundaries(log) {
4399
4765
  }
4400
4766
  }
4401
4767
  async function ensureGitignore(cwd) {
4402
- const gitignorePath = join10(cwd, ".gitignore");
4403
- const existing = await readFile7(gitignorePath, "utf8").catch(() => "");
4768
+ const gitignorePath = join11(cwd, ".gitignore");
4769
+ const existing = await readFile8(gitignorePath, "utf8").catch(() => "");
4404
4770
  if (existing.split(/\r?\n/).includes(".adep/")) return;
4405
4771
  await writeFile5(gitignorePath, `${existing.replace(/\n+$/, "")}
4406
4772
  .adep/
@@ -4414,8 +4780,9 @@ async function startDevServer(options) {
4414
4780
  if (options.prefix !== void 0) {
4415
4781
  config.functionsPrefix = options.prefix.replace(/^\/+|\/+$/g, "");
4416
4782
  }
4417
- const functionsDir = join10(cwd, config.functionsDir);
4783
+ const functionsDir = join11(cwd, config.functionsDir);
4418
4784
  const coldStartAt = Date.now();
4785
+ const bearerUser = bearerUserResolverFromEnv();
4419
4786
  const executor = new WorkerFunctionExecutor({
4420
4787
  deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
4421
4788
  });
@@ -4506,12 +4873,12 @@ async function startDevServer(options) {
4506
4873
  const reload = async () => {
4507
4874
  const [nextFiles, envText2] = await Promise.all([
4508
4875
  collectFunctions(functionsDir),
4509
- readFile7(join10(cwd, ".env.local"), "utf8").catch(() => "")
4876
+ readFile8(join11(cwd, ".env.local"), "utf8").catch(() => "")
4510
4877
  ]);
4511
4878
  files = nextFiles;
4512
4879
  env = { ...config.environment, ...parseEnvFile(envText2) };
4513
4880
  };
4514
- const envText = await readFile7(join10(cwd, ".env.local"), "utf8").catch(() => "");
4881
+ const envText = await readFile8(join11(cwd, ".env.local"), "utf8").catch(() => "");
4515
4882
  env = { ...config.environment, ...parseEnvFile(envText) };
4516
4883
  let debounceTimer;
4517
4884
  let watcher;
@@ -4526,29 +4893,15 @@ async function startDevServer(options) {
4526
4893
  watcher = void 0;
4527
4894
  }
4528
4895
  const buildInput = async (fnName, entry, url, req) => {
4529
- const query = {};
4530
- for (const key of new Set(url.searchParams.keys())) {
4531
- const values = url.searchParams.getAll(key);
4532
- query[key] = values.length > 1 ? values.join(",") : values[0] ?? "";
4533
- }
4534
- const headers = {};
4535
- for (const [key, value] of Object.entries(req.headers)) {
4536
- if (typeof value === "string") headers[key] = value;
4537
- }
4538
- const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await bodyOf(req);
4539
4896
  const hasEnv = Object.keys(env).length > 0;
4897
+ const request = await requestInput(url, req, bodyOf);
4898
+ if (bearerUser !== void 0) request.user = await bearerUser(request.headers);
4540
4899
  return {
4541
4900
  project: { id: "local", slug: config.name },
4542
4901
  fn: { id: fnName, name: fnName },
4543
4902
  files,
4544
4903
  entry,
4545
- request: {
4546
- method: req.method ?? "GET",
4547
- path: url.pathname,
4548
- query,
4549
- headers,
4550
- ...body === void 0 ? {} : { body }
4551
- },
4904
+ request,
4552
4905
  // 模拟运行时能力:db / storage / realtime 各自只读复用线上装配,语义一致。
4553
4906
  capabilities: dbBundle.capabilities,
4554
4907
  rpcHandlers: {
@@ -4685,6 +5038,9 @@ async function startDevServer(options) {
4685
5038
  log(`[adep] dev server listening on ${baseUrl}\uFF08\u6A21\u62DF\u8FD0\u884C\u65F6\uFF0C\u51B7\u542F\u52A8 ${coldStartMs}ms\uFF09`);
4686
5039
  log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
4687
5040
  printBoundaries(log);
5041
+ if (bearerUser !== void 0) {
5042
+ log(`[adep] \u767B\u5F55\u5373\u670D\u52A1\uFF1AADEP_AUTH_ISSUER \u5DF2\u914D\u7F6E\uFF0CBearer token \u5C06\u89E3\u6790\u4E3A\u7528\u6237\u8EAB\u4EFD\uFF08userinfo \u7AEF\u70B9\uFF09`);
5043
+ }
4688
5044
  log(`[adep] \u6A21\u62DF\u6570\u636E\u76EE\u5F55\uFF1A${simDir(cwd)}`);
4689
5045
  startStateAlarmScheduler();
4690
5046
  return {
@@ -4700,6 +5056,7 @@ async function startDevServer(options) {
4700
5056
  }
4701
5057
  };
4702
5058
  }
5059
+ var parseEnvFile;
4703
5060
  var init_dev = __esm({
4704
5061
  "packages/cli/src/dev.ts"() {
4705
5062
  "use strict";
@@ -4709,11 +5066,13 @@ var init_dev = __esm({
4709
5066
  init_runtime();
4710
5067
  init_env();
4711
5068
  init_invoke();
4712
- init_builtin_deps();
5069
+ init_builtin_deps2();
4713
5070
  init_boundary();
4714
5071
  init_ts_config();
4715
5072
  init_state_objects();
4716
5073
  init_worker_entry();
5074
+ init_dev_shared();
5075
+ parseEnvFile = parseEnv;
4717
5076
  }
4718
5077
  });
4719
5078
 
@@ -4832,7 +5191,7 @@ __export(db_exports, {
4832
5191
  dbStop: () => dbStop,
4833
5192
  splitSqlStatements: () => splitSqlStatements
4834
5193
  });
4835
- import { readFile as readFile8 } from "node:fs/promises";
5194
+ import { readFile as readFile9 } from "node:fs/promises";
4836
5195
  import { resolve as resolve5 } from "node:path";
4837
5196
  async function open2(paths, options) {
4838
5197
  const client = await createClient(paths);
@@ -4900,22 +5259,29 @@ function splitSqlStatements(source) {
4900
5259
  let inQuote = false;
4901
5260
  const lines = source.split("\n");
4902
5261
  for (const rawLine of lines) {
4903
- const line = rawLine.trim();
4904
- if (line.length === 0) continue;
4905
- if (line.startsWith("--")) continue;
4906
- for (let i = 0; i < line.length; i++) {
4907
- const ch = line[i];
4908
- if (ch === "'") {
4909
- if (inQuote && line[i + 1] === "'") {
4910
- buffer += ch + line[i + 1];
4911
- i++;
4912
- continue;
5262
+ const trimmed = rawLine.trim();
5263
+ if (trimmed.length === 0 || trimmed.startsWith("--")) continue;
5264
+ for (let i = 0; i < rawLine.length; i++) {
5265
+ const ch = rawLine[i];
5266
+ if (inQuote) {
5267
+ if (ch === "'") {
5268
+ if (rawLine[i + 1] === "'") {
5269
+ buffer += ch + rawLine[i + 1];
5270
+ i++;
5271
+ continue;
5272
+ }
5273
+ inQuote = false;
4913
5274
  }
4914
- inQuote = !inQuote;
4915
5275
  buffer += ch;
4916
5276
  continue;
4917
5277
  }
4918
- if (ch === ";" && !inQuote) {
5278
+ if (ch === "'") {
5279
+ inQuote = true;
5280
+ buffer += ch;
5281
+ continue;
5282
+ }
5283
+ if (ch === "-" && rawLine[i + 1] === "-") break;
5284
+ if (ch === ";") {
4919
5285
  const statement = buffer.trim();
4920
5286
  if (statement.length > 0) statements.push(statement);
4921
5287
  buffer = "";
@@ -4933,7 +5299,7 @@ function splitSqlStatements(source) {
4933
5299
  return statements;
4934
5300
  }
4935
5301
  async function dbMigrate(paths, options) {
4936
- const source = await readFile8(resolve5(options.file), "utf8");
5302
+ const source = await readFile9(resolve5(options.file), "utf8");
4937
5303
  const statements = splitSqlStatements(source);
4938
5304
  if (statements.length === 0) {
4939
5305
  throw new Error(`\u8FC1\u79FB\u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${options.file}`);
@@ -5039,12 +5405,13 @@ var init_banner = __esm({
5039
5405
  var server_exports = {};
5040
5406
  __export(server_exports, {
5041
5407
  isLoopback: () => isLoopback,
5408
+ resolveServePort: () => resolveServePort,
5042
5409
  startServeServer: () => startServeServer
5043
5410
  });
5044
5411
  import { createServer as createServer2 } from "node:http";
5045
5412
  import { watch as watch2 } from "node:fs";
5046
- import { mkdir as mkdir7, readdir as readdir4, readFile as readFile9, stat as stat6 } from "node:fs/promises";
5047
- import { extname, join as join11, relative as relative2, resolve as resolve6 } from "node:path";
5413
+ import { mkdir as mkdir7, readFile as readFile10, stat as stat6 } from "node:fs/promises";
5414
+ import { extname, join as join12, relative as relative2, resolve as resolve6 } from "node:path";
5048
5415
  function envNumber(name) {
5049
5416
  const raw = process.env[name];
5050
5417
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -5055,50 +5422,8 @@ function envString(name) {
5055
5422
  const raw = process.env[name];
5056
5423
  return raw === void 0 || raw.trim() === "" ? void 0 : raw.trim();
5057
5424
  }
5058
- async function collectFunctions2(dir) {
5059
- const files = {};
5060
- const walk = async (sub, prefix) => {
5061
- let entries;
5062
- try {
5063
- entries = await readdir4(sub, { withFileTypes: true });
5064
- } catch {
5065
- return;
5066
- }
5067
- for (const entry of entries) {
5068
- const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
5069
- const full = join11(sub, entry.name);
5070
- if (entry.isDirectory()) {
5071
- await walk(full, rel);
5072
- } else if (entry.isFile() && entry.name.endsWith(".ts")) {
5073
- files[rel] = await readFile9(full, "utf8");
5074
- }
5075
- }
5076
- };
5077
- await walk(dir, "");
5078
- return files;
5079
- }
5080
- function bodyOf2(req) {
5081
- return new Promise((resolveBody, rejectBody) => {
5082
- const chunks = [];
5083
- req.on("data", (chunk) => chunks.push(chunk));
5084
- req.on("end", () => {
5085
- const raw = Buffer.concat(chunks).toString("utf8");
5086
- if (raw.length === 0) {
5087
- resolveBody(void 0);
5088
- return;
5089
- }
5090
- try {
5091
- resolveBody(JSON.parse(raw));
5092
- } catch {
5093
- resolveBody(raw);
5094
- }
5095
- });
5096
- req.on("error", rejectBody);
5097
- });
5098
- }
5099
- function writeJson2(res, status, payload) {
5100
- res.writeHead(status, { "content-type": "application/json" });
5101
- res.end(JSON.stringify(payload));
5425
+ function resolveServePort(explicitPort) {
5426
+ return explicitPort ?? envNumber("PORT") ?? 8787;
5102
5427
  }
5103
5428
  function contentTypeFor(path) {
5104
5429
  const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
@@ -5109,13 +5434,14 @@ async function startServeServer(options) {
5109
5434
  const log = options.log ?? ((line) => process.stdout.write(`${line}
5110
5435
  `));
5111
5436
  const host = options.host ?? envString("HOST") ?? "127.0.0.1";
5112
- const port = options.port ?? envNumber("PORT") ?? 8787;
5437
+ const port = resolveServePort(options.port);
5113
5438
  const staticDir = resolve6(
5114
5439
  cwd,
5115
5440
  options.staticDir ?? envString("ADEP_SERVE_STATIC_DIR") ?? "public"
5116
5441
  );
5117
5442
  const config = await loadConfig(cwd);
5118
- const functionsDir = join11(cwd, config.functionsDir);
5443
+ const functionsDir = join12(cwd, config.functionsDir);
5444
+ const bearerUser = bearerUserResolverFromEnv();
5119
5445
  let hasStatic = false;
5120
5446
  try {
5121
5447
  const publicStat = await stat6(staticDir);
@@ -5123,9 +5449,9 @@ async function startServeServer(options) {
5123
5449
  } catch {
5124
5450
  hasStatic = false;
5125
5451
  }
5126
- let files = await collectFunctions2(functionsDir);
5452
+ let files = await collectFunctions(functionsDir);
5127
5453
  let functionNames = listFunctionNames(files);
5128
- const envText = await readFile9(join11(cwd, ".env.local"), "utf8").catch(() => "");
5454
+ const envText = await readFile10(join12(cwd, ".env.local"), "utf8").catch(() => "");
5129
5455
  let env = parseEnvFile(envText);
5130
5456
  let simEnv = await loadSimEnv(cwd).catch(() => ({}));
5131
5457
  const runtime = await createSimRuntime({
@@ -5136,12 +5462,14 @@ async function startServeServer(options) {
5136
5462
  });
5137
5463
  if (options.schemaFile !== void 0) {
5138
5464
  const schemaPath = resolve6(cwd, options.schemaFile);
5139
- const schemaSource = await readFile9(schemaPath, "utf8").catch((error) => {
5140
- if (error.code === "ENOENT") {
5141
- throw new Error(`schema \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${schemaPath}`);
5465
+ const schemaSource = await readFile10(schemaPath, "utf8").catch(
5466
+ (error) => {
5467
+ if (error.code === "ENOENT") {
5468
+ throw new Error(`schema \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${schemaPath}`);
5469
+ }
5470
+ throw error;
5142
5471
  }
5143
- throw error;
5144
- });
5472
+ );
5145
5473
  const statements = splitSqlStatements(schemaSource);
5146
5474
  let applied = 0;
5147
5475
  let skipped = 0;
@@ -5171,8 +5499,8 @@ async function startServeServer(options) {
5171
5499
  if (options.watch === true) {
5172
5500
  const reload = async () => {
5173
5501
  const [nextFiles, envLocalText] = await Promise.all([
5174
- collectFunctions2(functionsDir),
5175
- readFile9(join11(cwd, ".env.local"), "utf8").catch(() => "")
5502
+ collectFunctions(functionsDir),
5503
+ readFile10(join12(cwd, ".env.local"), "utf8").catch(() => "")
5176
5504
  ]);
5177
5505
  files = nextFiles;
5178
5506
  env = parseEnvFile(envLocalText);
@@ -5205,30 +5533,16 @@ async function startServeServer(options) {
5205
5533
  };
5206
5534
  }
5207
5535
  const buildInput = async (fnName, entry, url, req) => {
5208
- const query = {};
5209
- for (const key of new Set(url.searchParams.keys())) {
5210
- const values = url.searchParams.getAll(key);
5211
- query[key] = values.length > 1 ? values.join(",") : values[0] ?? "";
5212
- }
5213
- const headers = {};
5214
- for (const [key, value] of Object.entries(req.headers)) {
5215
- if (typeof value === "string") headers[key] = value;
5216
- }
5217
- const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await bodyOf2(req);
5218
5536
  const hasEnv = Object.keys(env).length > 0 || Object.keys(simEnv).length > 0 || Object.keys(config.environment ?? {}).length > 0;
5219
5537
  const mergedEnv = { ...config.environment, ...simEnv, ...env };
5538
+ const request = await requestInput(url, req, bodyOf);
5539
+ if (bearerUser !== void 0) request.user = await bearerUser(request.headers);
5220
5540
  return {
5221
5541
  project: { id: "local", slug: config.name },
5222
5542
  fn: { id: fnName, name: fnName },
5223
5543
  files,
5224
5544
  entry,
5225
- request: {
5226
- method: req.method ?? "GET",
5227
- path: url.pathname,
5228
- query,
5229
- headers,
5230
- ...body === void 0 ? {} : { body }
5231
- },
5545
+ request,
5232
5546
  capabilities: dbBundle.capabilities,
5233
5547
  rpcHandlers: {
5234
5548
  ...dbBundle.rpcHandlers,
@@ -5241,16 +5555,16 @@ async function startServeServer(options) {
5241
5555
  const serveStatic = async (pathname, res) => {
5242
5556
  if (!hasStatic) return false;
5243
5557
  const safePath = pathname.replace(/\.\.\//g, "").replace(/^\//, "");
5244
- const filePath = join11(staticDir, safePath);
5245
- const resolvedPath = safePath === "" || safePath === "/" ? join11(filePath, "index.html") : filePath;
5558
+ const filePath = join12(staticDir, safePath);
5559
+ const resolvedPath = safePath === "" || safePath === "/" ? join12(filePath, "index.html") : filePath;
5246
5560
  try {
5247
5561
  const fileStat = await stat6(resolvedPath);
5248
5562
  if (fileStat.isDirectory()) {
5249
- const indexPath = join11(resolvedPath, "index.html");
5563
+ const indexPath = join12(resolvedPath, "index.html");
5250
5564
  try {
5251
5565
  const indexStat = await stat6(indexPath);
5252
5566
  if (indexStat.isFile()) {
5253
- const content2 = await readFile9(indexPath);
5567
+ const content2 = await readFile10(indexPath);
5254
5568
  res.writeHead(200, { "content-type": contentTypeFor(indexPath) });
5255
5569
  res.end(content2);
5256
5570
  return true;
@@ -5259,7 +5573,7 @@ async function startServeServer(options) {
5259
5573
  }
5260
5574
  return false;
5261
5575
  }
5262
- const content = await readFile9(resolvedPath);
5576
+ const content = await readFile10(resolvedPath);
5263
5577
  res.writeHead(200, { "content-type": contentTypeFor(resolvedPath) });
5264
5578
  res.end(content);
5265
5579
  return true;
@@ -5268,7 +5582,7 @@ async function startServeServer(options) {
5268
5582
  const ext = extname(pathname);
5269
5583
  if (ext === "" || ext === ".html") {
5270
5584
  try {
5271
- const indexContent = await readFile9(join11(staticDir, "index.html"));
5585
+ const indexContent = await readFile10(join12(staticDir, "index.html"));
5272
5586
  res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
5273
5587
  res.end(indexContent);
5274
5588
  return true;
@@ -5287,11 +5601,11 @@ async function startServeServer(options) {
5287
5601
  if (fnRest !== null) {
5288
5602
  const { fnName, error: routeError } = resolveRouteFnName(fnRest, "");
5289
5603
  if (routeError !== void 0) {
5290
- writeJson2(res, 400, { error: routeError });
5604
+ writeJson(res, 400, { error: routeError });
5291
5605
  return;
5292
5606
  }
5293
5607
  if (fnName === void 0 || fnName.length === 0) {
5294
- writeJson2(res, 400, {
5608
+ writeJson(res, 400, {
5295
5609
  error: { code: "FN_NAME_REQUIRED", message: "\u4EE5 /api/{fnName} \u8C03\u7528\u51FD\u6570" }
5296
5610
  });
5297
5611
  return;
@@ -5299,7 +5613,7 @@ async function startServeServer(options) {
5299
5613
  const entry = resolveFunctionEntry(files, fnName);
5300
5614
  if (entry === void 0) {
5301
5615
  log(`[serve] ${req.method ?? "GET"} ${pathname} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
5302
- writeJson2(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
5616
+ writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
5303
5617
  return;
5304
5618
  }
5305
5619
  const input = await buildInput(fnName, entry, url, req);
@@ -5318,18 +5632,18 @@ async function startServeServer(options) {
5318
5632
  return;
5319
5633
  }
5320
5634
  log(`[serve] ${req.method ?? "GET"} ${pathname} -> 200 ${durationMs}ms`);
5321
- writeJson2(res, 200, result.body === void 0 ? null : result.body);
5635
+ writeJson(res, 200, result.body === void 0 ? null : result.body);
5322
5636
  } catch (error) {
5323
5637
  const durationMs = Math.round(performance.now() - startedAt);
5324
5638
  if (error instanceof ExecutorError) {
5325
5639
  log(
5326
5640
  `[serve] ${req.method ?? "GET"} ${pathname} -> ${error.status} ${durationMs}ms (${error.code})`
5327
5641
  );
5328
- writeJson2(res, error.status, { error: { code: error.code, message: error.message } });
5642
+ writeJson(res, error.status, { error: { code: error.code, message: error.message } });
5329
5643
  return;
5330
5644
  }
5331
5645
  log(`[serve] ${req.method ?? "GET"} ${pathname} -> 500 ${durationMs}ms`);
5332
- writeJson2(res, 500, {
5646
+ writeJson(res, 500, {
5333
5647
  error: {
5334
5648
  code: "FN_EXEC_ERROR",
5335
5649
  message: error instanceof Error ? error.message : "\u51FD\u6570\u6267\u884C\u5931\u8D25"
@@ -5339,7 +5653,7 @@ async function startServeServer(options) {
5339
5653
  return;
5340
5654
  }
5341
5655
  if (pathname === "/healthz") {
5342
- writeJson2(res, 200, {
5656
+ writeJson(res, 200, {
5343
5657
  status: "ok",
5344
5658
  service: "adep-serve",
5345
5659
  project: config.name
@@ -5349,7 +5663,7 @@ async function startServeServer(options) {
5349
5663
  const served = await serveStatic(pathname, res);
5350
5664
  if (served) return;
5351
5665
  if (pathname === "/" || pathname === "") {
5352
- writeJson2(res, 200, {
5666
+ writeJson(res, 200, {
5353
5667
  service: "adep-serve",
5354
5668
  mode: "development",
5355
5669
  project: config.name,
@@ -5364,13 +5678,13 @@ async function startServeServer(options) {
5364
5678
  });
5365
5679
  return;
5366
5680
  }
5367
- writeJson2(res, 404, { error: { code: "NOT_FOUND", message: `\u8DEF\u5F84 "${pathname}" \u4E0D\u5B58\u5728` } });
5681
+ writeJson(res, 404, { error: { code: "NOT_FOUND", message: `\u8DEF\u5F84 "${pathname}" \u4E0D\u5B58\u5728` } });
5368
5682
  };
5369
5683
  const server = createServer2((req, res) => {
5370
5684
  void handle(req, res).catch((error) => {
5371
5685
  log(`[serve] \u672A\u5904\u7406\u9519\u8BEF: ${error instanceof Error ? error.message : String(error)}`);
5372
5686
  if (!res.headersSent) {
5373
- writeJson2(res, 500, { error: { code: "INTERNAL_ERROR", message: "\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF" } });
5687
+ writeJson(res, 500, { error: { code: "INTERNAL_ERROR", message: "\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF" } });
5374
5688
  }
5375
5689
  });
5376
5690
  });
@@ -5399,6 +5713,9 @@ async function startServeServer(options) {
5399
5713
  if (options.watch === true) {
5400
5714
  log(`[serve] \u70ED\u91CD\u8F7D\u5DF2\u5F00\u542F\uFF1A\u6539 functions/ \u4E0E .env* \u5373\u751F\u6548\uFF0C\u51FD\u6570 console \u8F93\u51FA\u76F4\u8FBE\u7EC8\u7AEF\uFF08--watch\uFF09`);
5401
5715
  }
5716
+ if (bearerUser !== void 0) {
5717
+ log(`[serve] \u767B\u5F55\u5373\u670D\u52A1\uFF1AADEP_AUTH_ISSUER \u5DF2\u914D\u7F6E\uFF0CBearer token \u5C06\u89E3\u6790\u4E3A\u7528\u6237\u8EAB\u4EFD\uFF08userinfo \u7AEF\u70B9\uFF09`);
5718
+ }
5402
5719
  return {
5403
5720
  port: actualPort,
5404
5721
  host,
@@ -5418,13 +5735,14 @@ var init_server = __esm({
5418
5735
  init_executor();
5419
5736
  init_http_envelope();
5420
5737
  init_worker_executor();
5421
- init_builtin_deps();
5738
+ init_builtin_deps2();
5422
5739
  init_db2();
5423
5740
  init_runtime();
5424
5741
  init_env();
5425
5742
  init_invoke();
5426
5743
  init_dev();
5427
5744
  init_banner();
5745
+ init_dev_shared();
5428
5746
  MIME_TYPES = {
5429
5747
  ".html": "text/html; charset=utf-8",
5430
5748
  ".htm": "text/html; charset=utf-8",
@@ -5457,8 +5775,8 @@ __export(deploy_exports, {
5457
5775
  deploy: () => deploy
5458
5776
  });
5459
5777
  import { createHash as createHash2 } from "node:crypto";
5460
- import { readdir as readdir5, readFile as readFile10 } from "node:fs/promises";
5461
- import { join as join12, resolve as resolve7, basename as basename3, relative as relative3, sep } from "node:path";
5778
+ import { readdir as readdir4, readFile as readFile11 } from "node:fs/promises";
5779
+ import { join as join13, resolve as resolve7, basename as basename3, relative as relative3, sep } from "node:path";
5462
5780
  function functionUrlBase(prefix) {
5463
5781
  const raw = (prefix ?? "/api").trim();
5464
5782
  const normalized = raw === "/" ? "/" : raw.replace(/\/+$/, "");
@@ -5468,13 +5786,13 @@ async function collectEntries(functionsDir) {
5468
5786
  const entries = {};
5469
5787
  let names;
5470
5788
  try {
5471
- const dirents = await readdir5(functionsDir, { withFileTypes: true });
5789
+ const dirents = await readdir4(functionsDir, { withFileTypes: true });
5472
5790
  names = dirents.filter((entry) => entry.isFile() && entry.name.endsWith(".ts")).map((entry) => basename3(entry.name, ".ts")).toSorted();
5473
5791
  } catch {
5474
5792
  return entries;
5475
5793
  }
5476
5794
  for (const name of names) {
5477
- entries[name] = await readFile10(join12(functionsDir, `${name}.ts`), "utf8");
5795
+ entries[name] = await readFile11(join13(functionsDir, `${name}.ts`), "utf8");
5478
5796
  }
5479
5797
  return entries;
5480
5798
  }
@@ -5482,25 +5800,26 @@ function sha256Hex(content) {
5482
5800
  return createHash2("sha256").update(content).digest("hex");
5483
5801
  }
5484
5802
  async function collectShared(functionsDir) {
5485
- const sharedDir = join12(functionsDir, "_shared");
5803
+ const sharedDir = join13(functionsDir, "_shared");
5486
5804
  const files = {};
5487
5805
  const walk = async (dir) => {
5488
5806
  let entries;
5489
5807
  try {
5490
- entries = await readdir5(dir, { withFileTypes: true });
5808
+ entries = await readdir4(dir, { withFileTypes: true });
5491
5809
  } catch {
5492
5810
  return;
5493
5811
  }
5494
5812
  for (const entry of entries) {
5495
5813
  if (entry.isDirectory()) {
5496
5814
  if (entry.name === "__tests__" || entry.name === "node_modules") continue;
5497
- await walk(join12(dir, entry.name));
5815
+ await walk(join13(dir, entry.name));
5498
5816
  continue;
5499
5817
  }
5500
- if (!entry.name.endsWith(".ts") || entry.name.endsWith(".test.ts")) continue;
5501
- const full = join12(dir, entry.name);
5818
+ const isRuntimeSource = (entry.name.endsWith(".ts") || entry.name.endsWith(".js")) && !entry.name.endsWith(".d.ts") && !entry.name.endsWith(".test.ts");
5819
+ if (!isRuntimeSource) continue;
5820
+ const full = join13(dir, entry.name);
5502
5821
  const rel = relative3(sharedDir, full).split(sep).join("/");
5503
- files[`_shared/${rel}`] = await readFile10(full, "utf8");
5822
+ files[`_shared/${rel}`] = await readFile11(full, "utf8");
5504
5823
  }
5505
5824
  };
5506
5825
  await walk(sharedDir);
@@ -5514,7 +5833,7 @@ async function deploy(paths, options) {
5514
5833
  const cwd = resolve7(options.cwd);
5515
5834
  const config = await loadConfig(cwd);
5516
5835
  const slug = options.slug ?? config.name;
5517
- const functionsDir = options.functionsDir === void 0 ? join12(cwd, config.functionsDir) : resolve7(cwd, options.functionsDir);
5836
+ const functionsDir = options.functionsDir === void 0 ? join13(cwd, config.functionsDir) : resolve7(cwd, options.functionsDir);
5518
5837
  const local = await collectEntries(functionsDir);
5519
5838
  if (Object.keys(local).length === 0) {
5520
5839
  throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
@@ -5602,13 +5921,24 @@ var init_deploy = __esm({
5602
5921
  }
5603
5922
  });
5604
5923
 
5924
+ // shared/frontend-draft.ts
5925
+ var FRONTEND_DRAFT_FILE_PATH_PATTERN, FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES, FRONTEND_DRAFT_MAX_FILES;
5926
+ var init_frontend_draft = __esm({
5927
+ "shared/frontend-draft.ts"() {
5928
+ "use strict";
5929
+ FRONTEND_DRAFT_FILE_PATH_PATTERN = /^[a-zA-Z0-9._][a-zA-Z0-9._/-]*$/;
5930
+ FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES = 512 * 1024;
5931
+ FRONTEND_DRAFT_MAX_FILES = 100;
5932
+ }
5933
+ });
5934
+
5605
5935
  // packages/cli/src/frontend.ts
5606
5936
  var frontend_exports = {};
5607
5937
  __export(frontend_exports, {
5608
5938
  frontendSync: () => frontendSync
5609
5939
  });
5610
- import { readdir as readdir6, readFile as readFile11, stat as stat7 } from "node:fs/promises";
5611
- import { join as join13, relative as relative4, sep as sep2 } from "node:path";
5940
+ import { readdir as readdir5, readFile as readFile12, stat as stat7 } from "node:fs/promises";
5941
+ import { join as join14, relative as relative4, sep as sep2 } from "node:path";
5612
5942
  async function resolveProjectId(client, cwd, slug) {
5613
5943
  const resolvedSlug = await resolveSlug(cwd, slug);
5614
5944
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -5624,16 +5954,16 @@ async function resolveProjectId(client, cwd, slug) {
5624
5954
  async function collectFiles(root, dir) {
5625
5955
  const files = /* @__PURE__ */ new Map();
5626
5956
  const skipped = [];
5627
- const entries = await readdir6(dir, { withFileTypes: true });
5957
+ const entries = await readdir5(dir, { withFileTypes: true });
5628
5958
  for (const entry of entries) {
5629
5959
  if (entry.isDirectory()) {
5630
5960
  if (IGNORED_DIRS.has(entry.name)) continue;
5631
- const nested = await collectFiles(root, join13(dir, entry.name));
5961
+ const nested = await collectFiles(root, join14(dir, entry.name));
5632
5962
  for (const [path, content] of nested.files) files.set(path, content);
5633
5963
  skipped.push(...nested.skipped);
5634
5964
  continue;
5635
5965
  }
5636
- const full = join13(dir, entry.name);
5966
+ const full = join14(dir, entry.name);
5637
5967
  const rel = relative4(root, full).split(sep2).join("/");
5638
5968
  const info = await stat7(full);
5639
5969
  if (info.size > 1024 * 1024) {
@@ -5641,7 +5971,7 @@ async function collectFiles(root, dir) {
5641
5971
  continue;
5642
5972
  }
5643
5973
  try {
5644
- const content = await readFile11(full, "utf8");
5974
+ const content = await readFile12(full, "utf8");
5645
5975
  if (content.includes("\0")) {
5646
5976
  skipped.push(rel);
5647
5977
  continue;
@@ -5656,7 +5986,7 @@ async function collectFiles(root, dir) {
5656
5986
  async function frontendSync(paths, options) {
5657
5987
  const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
5658
5988
  `));
5659
- const webDir = options.dir ?? join13(options.cwd, "web");
5989
+ const webDir = options.dir ?? join14(options.cwd, "web");
5660
5990
  const rootStat = await stat7(webDir).catch(() => null);
5661
5991
  if (rootStat === null || !rootStat.isDirectory()) {
5662
5992
  throw new CliError(
@@ -5709,9 +6039,10 @@ var init_frontend = __esm({
5709
6039
  "use strict";
5710
6040
  init_auth();
5711
6041
  init_client();
5712
- MAX_FILES = 100;
5713
- MAX_TOTAL_SOURCE_BYTES2 = 256 * 1024;
5714
- FILE_PATH_PATTERN = /^[a-zA-Z0-9._][a-zA-Z0-9._/-]*$/;
6042
+ init_frontend_draft();
6043
+ MAX_FILES = FRONTEND_DRAFT_MAX_FILES;
6044
+ MAX_TOTAL_SOURCE_BYTES2 = FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES;
6045
+ FILE_PATH_PATTERN = FRONTEND_DRAFT_FILE_PATH_PATTERN;
5715
6046
  IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", ".adep", ".vite", "coverage"]);
5716
6047
  }
5717
6048
  });
@@ -5869,11 +6200,11 @@ var fs_exports = {};
5869
6200
  __export(fs_exports, {
5870
6201
  createExportFileSystem: () => createExportFileSystem
5871
6202
  });
5872
- import { mkdir as mkdir8, readFile as readFile12, rm as rm3, stat as stat9, writeFile as writeFile7 } from "node:fs/promises";
5873
- import { dirname as dirname7, join as join15 } from "node:path";
6203
+ import { mkdir as mkdir8, readFile as readFile13, rm as rm3, stat as stat9, writeFile as writeFile7 } from "node:fs/promises";
6204
+ import { dirname as dirname7, join as join16 } from "node:path";
5874
6205
  function createExportFileSystem() {
5875
6206
  return {
5876
- readFile: (path) => readFile12(path),
6207
+ readFile: (path) => readFile13(path),
5877
6208
  writeFile: (path, content) => writeFile7(path, content),
5878
6209
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
5879
6210
  deleteFile: async (path) => {
@@ -5891,9 +6222,9 @@ function createExportFileSystem() {
5891
6222
  await mkdir8(path, { recursive: true });
5892
6223
  },
5893
6224
  unzip: async (zipPath, targetDir) => {
5894
- const entries = zipRead(await readFile12(zipPath));
6225
+ const entries = zipRead(await readFile13(zipPath));
5895
6226
  for (const [name, data] of entries) {
5896
- const dest = join15(targetDir, name);
6227
+ const dest = join16(targetDir, name);
5897
6228
  await mkdir8(dirname7(dest), { recursive: true });
5898
6229
  await writeFile7(dest, data);
5899
6230
  }
@@ -6411,8 +6742,8 @@ __export(storage_exports, {
6411
6742
  storageRemove: () => storageRemove,
6412
6743
  storageUpload: () => storageUpload
6413
6744
  });
6414
- import { mkdir as mkdir9, readFile as readFile13, stat as stat10, writeFile as writeFile8 } from "node:fs/promises";
6415
- import { basename as basename4, dirname as dirname8, extname as extname2, join as join16, resolve as resolve9 } from "node:path";
6745
+ import { mkdir as mkdir9, readFile as readFile14, stat as stat10, writeFile as writeFile8 } from "node:fs/promises";
6746
+ import { basename as basename4, dirname as dirname8, extname as extname2, join as join17, resolve as resolve9 } from "node:path";
6416
6747
  async function open3(paths, options) {
6417
6748
  const client = await createClient(paths);
6418
6749
  const project2 = await resolveSlug(resolve9(options.cwd), options.slug);
@@ -6454,7 +6785,7 @@ async function storageUpload(paths, options) {
6454
6785
  throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
6455
6786
  }
6456
6787
  const visibility = options.visibility ?? "private";
6457
- const bytes = await readFile13(local);
6788
+ const bytes = await readFile14(local);
6458
6789
  const form = new FormData();
6459
6790
  form.set("path", options.path);
6460
6791
  form.set("visibility", visibility);
@@ -6495,7 +6826,7 @@ async function storageDownload(paths, options) {
6495
6826
  const url = await resolveDownloadUrl(client, project2, options.path);
6496
6827
  const response = await client.download(url, "STORAGE_DOWNLOAD_FAILED");
6497
6828
  const bytes = Buffer.from(await response.arrayBuffer());
6498
- const output = resolve9(options.output ?? join16(resolve9(options.cwd), basename4(options.path)));
6829
+ const output = resolve9(options.output ?? join17(resolve9(options.cwd), basename4(options.path)));
6499
6830
  await mkdir9(dirname8(output), { recursive: true });
6500
6831
  await writeFile8(output, bytes);
6501
6832
  return { path: options.path, output, size: bytes.length };
@@ -6745,6 +7076,7 @@ var init_mcp = __esm({
6745
7076
  var projects_exports = {};
6746
7077
  __export(projects_exports, {
6747
7078
  projectsCreate: () => projectsCreate,
7079
+ projectsDelete: () => projectsDelete,
6748
7080
  projectsInfo: () => projectsInfo,
6749
7081
  projectsList: () => projectsList
6750
7082
  });
@@ -6800,6 +7132,32 @@ async function projectsInfo(paths, options) {
6800
7132
  }
6801
7133
  return match;
6802
7134
  }
7135
+ async function projectsDelete(paths, options) {
7136
+ await requireNetworkGuard();
7137
+ const slug = requireSlug(options.slug, "adep projects delete <slug>");
7138
+ if (options.confirmed !== true) {
7139
+ throw new CliError(
7140
+ "CONFIRM_REQUIRED",
7141
+ `\u5220\u9664\u9879\u76EE\u4E0D\u53EF\u64A4\u9500\uFF0C\u786E\u8BA4\u540E\u52A0 --yes \u91CD\u8DD1\uFF1Aadep projects delete ${slug} --yes`
7142
+ );
7143
+ }
7144
+ const client = await createClient(paths);
7145
+ const list = await client.request(
7146
+ "/api/v1/projects",
7147
+ {},
7148
+ "PROJECT_LIST_FAILED"
7149
+ );
7150
+ const match = list.projects.find((project2) => project2.slug === slug);
7151
+ if (match === void 0) {
7152
+ throw new CliError("PROJECT_NOT_FOUND", `\u9879\u76EE "${slug}" \u4E0D\u5B58\u5728\u6216\u4F60\u6CA1\u6709\u8BBF\u95EE\u6743\u9650`);
7153
+ }
7154
+ await client.request(
7155
+ `/api/v1/projects/${match.id}`,
7156
+ { method: "DELETE" },
7157
+ "PROJECT_DELETE_FAILED"
7158
+ );
7159
+ return { id: match.id, slug: match.slug };
7160
+ }
6803
7161
  async function requireNetworkGuard() {
6804
7162
  const { requireNetwork: requireNetwork2 } = await Promise.resolve().then(() => (init_net(), net_exports));
6805
7163
  await requireNetwork2("adep projects");
@@ -6879,21 +7237,10 @@ var init_git = __esm({
6879
7237
  // packages/cli/src/functions.ts
6880
7238
  var functions_exports = {};
6881
7239
  __export(functions_exports, {
6882
- functionsDeploy: () => functionsDeploy,
6883
7240
  functionsList: () => functionsList,
6884
7241
  functionsLogs: () => functionsLogs
6885
7242
  });
6886
7243
  import { resolve as resolve11 } from "node:path";
6887
- async function functionsDeploy(paths, options) {
6888
- const startedAt = Date.now();
6889
- const result = await deploy(paths, {
6890
- cwd: options.cwd,
6891
- ...options.slug === void 0 ? {} : { slug: options.slug },
6892
- ...options.dir === void 0 ? {} : { functionsDir: resolve11(options.cwd, options.dir) },
6893
- silent: true
6894
- });
6895
- return { ...result, elapsedSeconds: (Date.now() - startedAt) / 1e3 };
6896
- }
6897
7244
  async function functionsList(paths, options) {
6898
7245
  const client = await createClient(paths);
6899
7246
  const project2 = await resolveProject2(client, options);
@@ -6955,7 +7302,6 @@ var init_functions = __esm({
6955
7302
  "use strict";
6956
7303
  init_auth();
6957
7304
  init_client();
6958
- init_deploy();
6959
7305
  }
6960
7306
  });
6961
7307
 
@@ -6967,8 +7313,8 @@ __export(hosting_exports, {
6967
7313
  hostingInfo: () => hostingInfo,
6968
7314
  hostingPull: () => hostingPull
6969
7315
  });
6970
- import { readdir as readdir7, readFile as readFile14, stat as stat12 } from "node:fs/promises";
6971
- import { dirname as dirname9, join as join17, relative as relative5, resolve as resolve12, sep as sep3 } from "node:path";
7316
+ import { readdir as readdir6, readFile as readFile15, stat as stat12 } from "node:fs/promises";
7317
+ import { dirname as dirname9, join as join18, relative as relative5, resolve as resolve12, sep as sep3 } from "node:path";
6972
7318
  async function open4(paths, options) {
6973
7319
  const client = await createClient(paths);
6974
7320
  const project2 = await resolveSlug(resolve12(options.cwd), options.slug);
@@ -6989,12 +7335,12 @@ async function collectSiteFiles(dir) {
6989
7335
  const walk = async (sub) => {
6990
7336
  let entries;
6991
7337
  try {
6992
- entries = await readdir7(sub, { withFileTypes: true });
7338
+ entries = await readdir6(sub, { withFileTypes: true });
6993
7339
  } catch {
6994
7340
  return;
6995
7341
  }
6996
7342
  for (const entry of entries) {
6997
- const full = join17(sub, entry.name);
7343
+ const full = join18(sub, entry.name);
6998
7344
  if (entry.isDirectory()) {
6999
7345
  await walk(full);
7000
7346
  } else if (entry.isFile()) {
@@ -7018,7 +7364,7 @@ async function hostingDeploy(paths, options) {
7018
7364
  for (const [rel, full] of files) {
7019
7365
  log(`[adep] \u4E0A\u4F20 site/${rel}`);
7020
7366
  const info2 = await stat12(full);
7021
- const bytes = await readFile14(full);
7367
+ const bytes = await readFile15(full);
7022
7368
  const form = new FormData();
7023
7369
  form.set("path", `site/${rel}`);
7024
7370
  form.set("visibility", "public");
@@ -7056,7 +7402,7 @@ async function hostingPull(paths, options) {
7056
7402
  const response = await client.download(url, "HOSTING_DOWNLOAD_FAILED");
7057
7403
  const bytes = Buffer.from(await response.arrayBuffer());
7058
7404
  const rel = entry.path.replace(/^site\//, "");
7059
- const target = join17(outputDir, ...rel.split("/"));
7405
+ const target = join18(outputDir, ...rel.split("/"));
7060
7406
  await mkdir10(dirname9(target), { recursive: true });
7061
7407
  await writeFile9(target, bytes);
7062
7408
  files.push({ path: entry.path, size: bytes.length });
@@ -7377,6 +7723,16 @@ var ADEP_TSCONFIG_JSON = `{
7377
7723
  // packages/cli/src/init.ts
7378
7724
  init_adep_config();
7379
7725
 
7726
+ // shared/sdk/function-template.ts
7727
+ var HELLO_FUNCTION_SOURCE = `// \u793A\u4F8B\u4E91\u51FD\u6570\uFF1A\u90E8\u7F72\u540E\u7ECF /api/hello \u89E6\u53D1\uFF08\u672C\u5730\u5F00\u53D1\u7531 vite \u63D2\u4EF6\u4EE3\u7406\u540C\u4E00\u8DEF\u5F84\uFF09\u3002
7728
+ // \u7528\u6237\u51FD\u6570\u9ED8\u8BA4\u5BFC\u51FA (ctx: AdepContext) \u5F62\u72B6\u7684\u5904\u7406\u5668\uFF0Cctx \u5951\u7EA6\u89C1 adep.d.ts
7729
+ //\uFF08method / path / query / headers / body / files / user / cloud.*\uFF09\u3002
7730
+ export default async (ctx: AdepContext) => {
7731
+ const name = (ctx.query['name'] as string | undefined) ?? 'world'
7732
+ return { message: \`hello \${name}\` }
7733
+ }
7734
+ `;
7735
+
7380
7736
  // shared/sdk/web-project-template.ts
7381
7737
  var ADEP_CLIENT_VERSION = "^0.2.0";
7382
7738
  var ADEP_VITE_PLUGIN_VERSION = "^0.1.0";
@@ -9684,7 +10040,12 @@ onMounted(() => {
9684
10040
  ];
9685
10041
 
9686
10042
  // packages/cli/src/init.ts
9687
- var TEMPLATE_NAMES = ["empty", "function", "fullstack", "countdown"];
10043
+ var TEMPLATE_NAMES = [
10044
+ "empty",
10045
+ "function",
10046
+ "fullstack",
10047
+ "countdown"
10048
+ ];
9688
10049
  var InitError = class extends Error {
9689
10050
  constructor(code, message) {
9690
10051
  super(message);
@@ -9920,14 +10281,6 @@ console.log(result.message)
9920
10281
  \`web/src/\` \u5B58\u653E\u524D\u7AEF\u6E90\u7801\uFF08\`main.ts\` / \`App.vue\`\uFF09\uFF0C\u4E0E Web IDE \u5185 \`web/\` \u5DE5\u7A0B\u7684 \`src/\`
9921
10282
  \u5B8C\u5168\u540C\u6784\uFF1Bvite \u5DE5\u7A0B\u6839\u5728\u9879\u76EE\u6839\u76EE\u5F55\uFF08\`vite.config.ts\` / \`index.html\` / \`package.json\`\uFF09\u3002
9922
10283
  `;
9923
- var HELLO_FUNCTION = `// \u793A\u4F8B\u51FD\u6570\uFF1Aadep deploy \u540E\u7ECF https://<project-slug>.<platform-domain>/api/hello \u89E6\u53D1\u3002
9924
- // \u7528\u6237\u51FD\u6570\u5373 functions/ \u4E0B\u7684\u72EC\u7ACB\u6587\u4EF6\uFF0C\u9ED8\u8BA4\u5BFC\u51FA (ctx: AdepContext) => Response \u5F62\u72B6\u7684\u5904\u7406\u5668
9925
- //\uFF08ctx \u5951\u7EA6\u89C1 adep.d.ts\uFF1Amethod / path / query / headers / body / files / user / cloud.*\uFF09\u3002
9926
- export default async (ctx: AdepContext) => {
9927
- const name = (ctx.query['name'] as string | undefined) ?? 'world'
9928
- return { message: \`hello \${name}\` }
9929
- }
9930
- `;
9931
10284
  var FUNCTION_INDEX = `// \u51FD\u6570\u6A21\u5757\u5165\u53E3\uFF1A\u9879\u76EE\u91CC\u7684\u6BCF\u4E2A\u51FD\u6570\u662F functions/ \u4E0B\u7684\u72EC\u7ACB\u6587\u4EF6\uFF0C
9932
10285
  // \u9ED8\u8BA4\u5BFC\u51FA (ctx: AdepContext) => Response \u5F62\u72B6\u7684\u5904\u7406\u5668\uFF08\u5951\u7EA6\u89C1 adep.d.ts\uFF09\u3002
9933
10286
  `;
@@ -10010,10 +10363,10 @@ async function initProject(cwd, name, template) {
10010
10363
  { path: ".gitignore", content: "node_modules/\ndata/\n.adep/\nsite/\n" }
10011
10364
  ];
10012
10365
  if (template === "function") {
10013
- files.push({ path: "functions/hello.ts", content: HELLO_FUNCTION });
10366
+ files.push({ path: "functions/hello.ts", content: HELLO_FUNCTION_SOURCE });
10014
10367
  files.push({ path: "functions/README.md", content: FUNCTION_INDEX });
10015
10368
  } else if (template === "fullstack") {
10016
- files.push({ path: "functions/hello.ts", content: HELLO_FUNCTION });
10369
+ files.push({ path: "functions/hello.ts", content: HELLO_FUNCTION_SOURCE });
10017
10370
  files.push({ path: "functions/README.md", content: FUNCTION_INDEX });
10018
10371
  files.push({ path: "database/schema.sql", content: SCHEMA_SQL });
10019
10372
  files.push({ path: "index.html", content: INDEX_HTML });
@@ -10247,6 +10600,7 @@ function registerInit(program2, ctx) {
10247
10600
 
10248
10601
  // packages/cli/src/import-cf.ts
10249
10602
  init_adep_config();
10603
+ init_regexp();
10250
10604
  import { copyFile, mkdir as mkdir3, readFile as readFile2, readdir, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
10251
10605
  import { basename, dirname as dirname3, join as join2, relative, resolve as resolve2 } from "node:path";
10252
10606
  var TomlSyntaxError = class extends Error {
@@ -10588,9 +10942,6 @@ function bindingsFromWrangler(config) {
10588
10942
  function collectDurableObjectBindings(config) {
10589
10943
  return (config.durable_objects?.bindings ?? []).filter((b) => b.class_name !== void 0).map((b) => ({ name: b.name, className: b.class_name }));
10590
10944
  }
10591
- function escapeRegExp(text) {
10592
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10593
- }
10594
10945
  function findClosingBrace(text, openIdx) {
10595
10946
  let depth = 0;
10596
10947
  let i = openIdx;
@@ -11052,7 +11403,7 @@ init_auth();
11052
11403
  init_client();
11053
11404
  init_deploy();
11054
11405
  import { stat as stat8 } from "node:fs/promises";
11055
- import { join as join14, resolve as resolve8 } from "node:path";
11406
+ import { join as join15, resolve as resolve8 } from "node:path";
11056
11407
  async function resolveProjectId2(client, cwd, slug) {
11057
11408
  const resolvedSlug = await resolveSlug(resolve8(cwd), slug);
11058
11409
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -11118,7 +11469,7 @@ async function runPublish(paths, io, cwd, flags) {
11118
11469
  });
11119
11470
  }
11120
11471
  if (wantFrontend) {
11121
- const webDir = join14(cwd, "web");
11472
+ const webDir = join15(cwd, "web");
11122
11473
  const webStat = await stat8(webDir).catch(() => null);
11123
11474
  if (webStat !== null && webStat.isDirectory()) {
11124
11475
  const { frontendSync: frontendSync2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
@@ -11623,6 +11974,17 @@ function registerProjects(program2, ctx) {
11623
11974
  });
11624
11975
  });
11625
11976
  });
11977
+ projects.command("delete").description("\u5220\u9664\u9879\u76EE\uFF08\u7EA7\u8054\u6E05\u7406\u5168\u90E8\u8D44\u6E90\uFF0C\u4E0D\u53EF\u64A4\u9500\uFF1B\u9700 --yes \u786E\u8BA4\uFF09").argument("<slug>", "\u9879\u76EE slug").option("-y, --yes", "\u786E\u8BA4\u5220\u9664\uFF08\u7F3A\u7701\u62D2\u7EDD\u6267\u884C\uFF09").action(async (slug, flags) => {
11978
+ const command = ctx.io("projects delete");
11979
+ await command.run(async () => {
11980
+ const { projectsDelete: projectsDelete2 } = await Promise.resolve().then(() => (init_projects(), projects_exports));
11981
+ const deleted = await projectsDelete2(ctx.paths, { slug, confirmed: flags.yes === true });
11982
+ command.ok(deleted, (data) => {
11983
+ const d = data;
11984
+ return `\u2713 Project deleted \xB7 ${d.slug}`;
11985
+ });
11986
+ });
11987
+ });
11626
11988
  }
11627
11989
 
11628
11990
  // packages/cli/src/commands/git.ts