@adep/cli 0.1.1 → 0.1.3

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
@@ -250,6 +250,51 @@ function asStringRecord(value) {
250
250
  }
251
251
  return rec;
252
252
  }
253
+ function asBindingArray(value, label, errors, optionalKey) {
254
+ if (!Array.isArray(value)) {
255
+ errors.push(`${label} \u5FC5\u987B\u662F\u6570\u7EC4\uFF0C\u6536\u5230 ${typeNameOf(value)}`);
256
+ return null;
257
+ }
258
+ const out = [];
259
+ value.forEach((item, i) => {
260
+ const idx = `${label}[${i}]`;
261
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
262
+ errors.push(`${idx} \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u6536\u5230 ${typeNameOf(item)}`);
263
+ return;
264
+ }
265
+ const rec = item;
266
+ if (typeof rec.name !== "string" || rec.name.length === 0) {
267
+ errors.push(`${idx}.name \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\uFF0C\u6536\u5230 ${typeNameOf(rec.name)}`);
268
+ return;
269
+ }
270
+ const entry = { name: rec.name };
271
+ const optional = rec[optionalKey];
272
+ if (optional !== void 0) {
273
+ if (typeof optional !== "string") {
274
+ errors.push(`${idx}.${optionalKey} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\uFF0C\u6536\u5230 ${typeNameOf(optional)}`);
275
+ } else {
276
+ entry[optionalKey] = optional;
277
+ }
278
+ }
279
+ out.push(entry);
280
+ });
281
+ return out;
282
+ }
283
+ function asCfBindingsConfig(value, errors) {
284
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
285
+ errors.push(`cfBindings \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u6536\u5230 ${typeNameOf(value)}`);
286
+ return null;
287
+ }
288
+ const rec = value;
289
+ const bindings = {};
290
+ const kv = rec.kv === void 0 ? void 0 : asBindingArray(rec.kv, "cfBindings.kv", errors, "namespace");
291
+ if (kv !== null && kv !== void 0) bindings.kv = kv;
292
+ const d1 = rec.d1 === void 0 ? void 0 : asBindingArray(rec.d1, "cfBindings.d1", errors, "database");
293
+ if (d1 !== null && d1 !== void 0) bindings.d1 = d1;
294
+ const r2 = rec.r2 === void 0 ? void 0 : asBindingArray(rec.r2, "cfBindings.r2", errors, "bucket");
295
+ if (r2 !== null && r2 !== void 0) bindings.r2 = r2;
296
+ return bindings;
297
+ }
253
298
  function parseAdepConfig(raw) {
254
299
  if (raw === null || raw === void 0) {
255
300
  return { ok: true, data: { ...DEFAULT_ADEP_CONFIG } };
@@ -310,6 +355,10 @@ function parseAdepConfig(raw) {
310
355
  data.runtime = rec;
311
356
  }
312
357
  }
358
+ if (input.cfBindings !== void 0) {
359
+ const bindings = asCfBindingsConfig(input.cfBindings, errors);
360
+ if (bindings !== null) data.cfBindings = bindings;
361
+ }
313
362
  if (errors.length > 0) return { ok: false, errors };
314
363
  return { ok: true, data };
315
364
  }
@@ -345,6 +394,9 @@ function renderAdepConfig(config, options = {}) {
345
394
  if (config.runtime !== void 0) {
346
395
  lines.push(` runtime: ${renderTsValue(config.runtime)},`);
347
396
  }
397
+ if (config.cfBindings !== void 0) {
398
+ lines.push(` cfBindings: ${renderTsValue(config.cfBindings)},`);
399
+ }
348
400
  if (options.extraFields !== void 0) {
349
401
  for (const [key, value] of Object.entries(options.extraFields)) {
350
402
  lines.push(` ${key}: ${renderTsValue(value)},`);
@@ -417,6 +469,8 @@ var init_capability_keys = __esm({
417
469
  DB_RPC = {
418
470
  /** 直通方法(如 query):`(method=query, args=[sql, params])`。 */
419
471
  query: "query",
472
+ /** 写路径(CF-013):`(method=writeQuery, args=[sql, params])` → `{ changes }`。 */
473
+ writeQuery: "writeQuery",
420
474
  /** 读取 owned 表变更流(DB-006):`(method=changes, args=[table, query])`。 */
421
475
  changes: "changes",
422
476
  /** 开启事务:`begin → txId`。 */
@@ -479,6 +533,30 @@ var init_executor = __esm({
479
533
  }
480
534
  });
481
535
 
536
+ // packages/runtime/src/shared/http-envelope.ts
537
+ function isAdepHttpEnvelope(value) {
538
+ if (typeof value !== "object" || value === null) return false;
539
+ const envelope = value.__adepHttp;
540
+ if (typeof envelope !== "object" || envelope === null) return false;
541
+ const status = envelope.status;
542
+ return typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599;
543
+ }
544
+ function writeEnvelopeResponse(res, envelope) {
545
+ const { status, headers, body } = envelope.__adepHttp;
546
+ const noBody = status >= 100 && status < 200 || status === 204 || status === 205;
547
+ res.writeHead(status, { "content-type": "application/json", ...headers });
548
+ if (noBody) {
549
+ res.end();
550
+ return;
551
+ }
552
+ res.end(JSON.stringify(body === void 0 ? null : body));
553
+ }
554
+ var init_http_envelope = __esm({
555
+ "packages/runtime/src/shared/http-envelope.ts"() {
556
+ "use strict";
557
+ }
558
+ });
559
+
482
560
  // packages/runtime/src/functions/domain.ts
483
561
  var MAX_TOTAL_SOURCE_BYTES, FnError;
484
562
  var init_domain = __esm({
@@ -573,6 +651,13 @@ function classifyDependencies(dependencies, builtin) {
573
651
  }
574
652
  return { builtinDeps, customDeps };
575
653
  }
654
+ function splitBareSpecifier(request) {
655
+ if (request.startsWith("@")) {
656
+ const segments = request.split("/");
657
+ return segments.slice(0, 2).join("/");
658
+ }
659
+ return request.split("/")[0];
660
+ }
576
661
  function depsKeyOf(dependencies) {
577
662
  const canonical = Object.entries(dependencies).map(([name, version]) => `${name}@${version}`).toSorted().join("\n");
578
663
  return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
@@ -589,14 +674,14 @@ var init_manifest = __esm({
589
674
  });
590
675
 
591
676
  // packages/runtime/src/functions/deps/resolve.ts
592
- import { resolve as resolve2 } from "node:path";
677
+ import { resolve as resolve3 } from "node:path";
593
678
  function resolveExecutionDeps(config, projectId, manifestContent) {
594
679
  const manifest = tryParseManifestDependencies(manifestContent);
595
680
  const { customDeps } = classifyDependencies(manifest, config.builtin);
596
681
  const custom = Object.keys(customDeps);
597
682
  return {
598
683
  // 绝对化(相对进程 cwd,与 installer 侧 resolve(rootDir) 同基准):worker 的 createRequire 需要确定路径
599
- dir: custom.length === 0 ? null : resolve2(config.rootDir, projectId, depsKeyOf(customDeps)),
684
+ dir: custom.length === 0 ? null : resolve3(config.rootDir, projectId, depsKeyOf(customDeps)),
600
685
  builtin: [...config.builtin],
601
686
  custom
602
687
  };
@@ -611,22 +696,22 @@ var init_resolve = __esm({
611
696
  // packages/runtime/src/functions/runtime/worker-executor.ts
612
697
  import { readFileSync } from "node:fs";
613
698
  import { fileURLToPath, pathToFileURL } from "node:url";
614
- import { dirname as dirname3, join as join2 } from "node:path";
699
+ import { dirname as dirname4, join as join3 } from "node:path";
615
700
  import { Worker } from "node:worker_threads";
616
701
  function resolveWorkerEntry(baseDir = fileURLToPath(new URL(".", import.meta.url))) {
617
702
  const candidates = [
618
- join2(baseDir, "worker-entry.js"),
619
- join2(baseDir, "worker-entry.ts"),
620
- join2(baseDir, "domains/functions/runtime/worker-entry.js"),
621
- join2(baseDir, "domains/functions/runtime/worker-entry.ts")
703
+ join3(baseDir, "worker-entry.js"),
704
+ join3(baseDir, "worker-entry.ts"),
705
+ join3(baseDir, "domains/functions/runtime/worker-entry.js"),
706
+ join3(baseDir, "domains/functions/runtime/worker-entry.ts")
622
707
  ];
623
708
  let current = baseDir;
624
709
  for (let depth = 0; depth < 8; depth += 1) {
625
710
  candidates.push(
626
- join2(current, "packages/runtime/src/functions/runtime/worker-entry.js"),
627
- join2(current, "packages/runtime/src/functions/runtime/worker-entry.ts")
711
+ join3(current, "packages/runtime/src/functions/runtime/worker-entry.js"),
712
+ join3(current, "packages/runtime/src/functions/runtime/worker-entry.ts")
628
713
  );
629
- const parent = dirname3(current);
714
+ const parent = dirname4(current);
630
715
  if (parent === current) break;
631
716
  current = parent;
632
717
  }
@@ -668,7 +753,7 @@ var init_worker_executor = __esm({
668
753
  const entry = input.entry ?? "index.ts";
669
754
  const deps = this.depsConfig === void 0 ? void 0 : resolveExecutionDeps(this.depsConfig, input.project.id, input.files["package.json"]);
670
755
  const logs = [];
671
- return new Promise((resolve12, reject) => {
756
+ return new Promise((resolve13, reject) => {
672
757
  let worker;
673
758
  try {
674
759
  worker = new Worker(resolveWorkerEntry(), {
@@ -730,7 +815,7 @@ var init_worker_executor = __esm({
730
815
  if (message.type === "result") {
731
816
  clearTimeout(timer);
732
817
  void worker.terminate();
733
- resolve12({ body: message.body, logs });
818
+ resolve13({ body: message.body, logs });
734
819
  return;
735
820
  }
736
821
  if (message.type === "error") {
@@ -827,21 +912,35 @@ function unsafeOperation(message) {
827
912
  function stripLiterals(sql) {
828
913
  return sql.replace(/'[^']*(?:''[^']*)*'/g, "").replace(/"[^"]*(?:""[^"]*)*"/g, "").replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
829
914
  }
830
- function assertReadOnlyQuery(sql) {
915
+ function sqlHead(sql) {
916
+ return sql.trim().replace(/^\(+/, "").trim().toUpperCase();
917
+ }
918
+ function assertSafeStatement(sql) {
831
919
  const stripped = stripLiterals(sql);
832
920
  if (stripped.includes(";")) {
833
921
  throw unsafeOperation("\u4EC5\u5141\u8BB8\u5355\u6761\u8BED\u53E5\uFF0C\u7981\u6B62\u591A\u8BED\u53E5\u5806\u53E0");
834
922
  }
835
- const head = stripped.trim().replace(/^\(+/, "").trim().toUpperCase();
836
- if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
837
- throw unsafeOperation("cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
838
- }
839
923
  if (/ATTACH|DETACH/.test(stripped.toUpperCase())) {
840
924
  throw unsafeOperation("\u7981\u6B62\u8DE8\u5E93\u64CD\u4F5C\uFF08ATTACH / DETACH\uFF09");
841
925
  }
842
926
  if (/SQLITE_\w+/i.test(stripped)) {
843
927
  throw unsafeOperation("\u7981\u6B62\u8BBF\u95EE\u7CFB\u7EDF\u8868\uFF08sqlite_*\uFF09");
844
928
  }
929
+ return sqlHead(stripped);
930
+ }
931
+ function assertReadOnlyQuery(sql) {
932
+ const head = assertSafeStatement(sql);
933
+ if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
934
+ throw unsafeOperation("cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
935
+ }
936
+ }
937
+ function assertWriteQuery(sql) {
938
+ const head = assertSafeStatement(sql);
939
+ if (!head.startsWith("INSERT") && !head.startsWith("UPDATE") && !head.startsWith("DELETE")) {
940
+ throw unsafeOperation(
941
+ "cloud.db.writeQuery \u4EC5\u5141\u8BB8 DML\uFF08INSERT / UPDATE / DELETE\uFF09\uFF0CDDL \u8BF7\u8D70\u63A7\u5236\u53F0"
942
+ );
943
+ }
845
944
  }
846
945
  var init_guards = __esm({
847
946
  "packages/runtime/src/database/builder/guards.ts"() {
@@ -1417,6 +1516,14 @@ function createCloudDb(driver, options = {}) {
1417
1516
  assertReadOnlyQuery(sql);
1418
1517
  return driver.all(sql, params);
1419
1518
  },
1519
+ async writeQuery(sql, params) {
1520
+ if (!Array.isArray(params)) {
1521
+ throw unsafeOperation("writeQuery \u7684 params \u5FC5\u987B\u63D0\u4F9B\uFF08\u65E0\u53C2\u4F20 []\uFF09");
1522
+ }
1523
+ guardWrite();
1524
+ assertWriteQuery(sql);
1525
+ return driver.run(sql, params);
1526
+ },
1420
1527
  async changes(table, query = {}) {
1421
1528
  return readChanges(driver, table, query);
1422
1529
  }
@@ -1489,6 +1596,10 @@ function createDbCapability(driver, options = {}) {
1489
1596
  const [sql, params] = args;
1490
1597
  return await db.query(sql, params);
1491
1598
  }
1599
+ case DB_RPC.writeQuery: {
1600
+ const [sql, params] = args;
1601
+ return await db.writeQuery(sql, params);
1602
+ }
1492
1603
  case DB_RPC.changes: {
1493
1604
  const [table, query] = args;
1494
1605
  return await db.changes(table, query);
@@ -1543,7 +1654,8 @@ var init_cloud = __esm({
1543
1654
  rootMethod: "table",
1544
1655
  stepMethods: ["select", "where", "orderBy", "limit", "offset"],
1545
1656
  terminalMethods: ["get", "first", "count", "insert", "insertMany", "update", "delete"],
1546
- directMethods: ["query", "changes"],
1657
+ // CF-013:writeQuery 是 D1 shim 的写路径(INSERT/UPDATE/DELETE),与 query 并列直通方法。
1658
+ directMethods: ["query", "writeQuery", "changes"],
1547
1659
  transactionMethod: "transaction"
1548
1660
  };
1549
1661
  WRITE_TERMINALS = /* @__PURE__ */ new Set(["insert", "insertMany", "update", "delete"]);
@@ -2001,6 +2113,113 @@ var init_db = __esm({
2001
2113
  }
2002
2114
  });
2003
2115
 
2116
+ // packages/runtime/src/database/sdk/kv.ts
2117
+ function nowSeconds() {
2118
+ return Math.floor(Date.now() / 1e3);
2119
+ }
2120
+ function errorWithCode2(error) {
2121
+ const code = typeof error === "object" && error !== null && typeof error.code === "string" ? error.code : void 0;
2122
+ if (code !== void 0 && error instanceof Error) {
2123
+ return new Error(`[${code}] ${error.message}`);
2124
+ }
2125
+ return error;
2126
+ }
2127
+ function createKvCapability(driver) {
2128
+ let ensurePromise = null;
2129
+ const ensureTable = () => {
2130
+ if (ensurePromise === null) {
2131
+ ensurePromise = driver.run(
2132
+ `CREATE TABLE IF NOT EXISTS ${KV_TABLE} (key TEXT PRIMARY KEY, value TEXT, expires_at INTEGER)`
2133
+ ).then(() => void 0);
2134
+ }
2135
+ return ensurePromise;
2136
+ };
2137
+ const handler = async (method, args) => {
2138
+ try {
2139
+ await ensureTable();
2140
+ switch (method) {
2141
+ case KV_RPC.get: {
2142
+ const [key] = args;
2143
+ const row = await driver.get(`SELECT value, expires_at FROM ${KV_TABLE} WHERE key = ?`, [
2144
+ key
2145
+ ]);
2146
+ if (row === null || row === void 0) return null;
2147
+ const expiresAt = row.expires_at;
2148
+ if (expiresAt !== null && expiresAt !== void 0 && Number(expiresAt) <= nowSeconds()) {
2149
+ return null;
2150
+ }
2151
+ return row.value;
2152
+ }
2153
+ case KV_RPC.put: {
2154
+ const [key, value, options] = args;
2155
+ const ttl = options?.expirationTtlSeconds;
2156
+ const expiresAt = typeof ttl === "number" && ttl > 0 ? nowSeconds() + Math.floor(ttl) : null;
2157
+ await driver.run(`DELETE FROM ${KV_TABLE} WHERE key = ?`, [key]);
2158
+ await driver.run(`INSERT INTO ${KV_TABLE} (key, value, expires_at) VALUES (?, ?, ?)`, [
2159
+ key,
2160
+ value,
2161
+ expiresAt
2162
+ ]);
2163
+ return void 0;
2164
+ }
2165
+ case KV_RPC.delete: {
2166
+ const [key] = args;
2167
+ await driver.run(`DELETE FROM ${KV_TABLE} WHERE key = ?`, [key]);
2168
+ return void 0;
2169
+ }
2170
+ case KV_RPC.list: {
2171
+ const [options] = args;
2172
+ const prefix = options?.prefix ?? "";
2173
+ const limit = options?.limit ?? KV_LIST_DEFAULT_LIMIT;
2174
+ const rows = prefix === "" ? await driver.all(`SELECT key, expires_at FROM ${KV_TABLE}`) : await driver.all(`SELECT key, expires_at FROM ${KV_TABLE} WHERE key LIKE ?`, [
2175
+ `${prefix}%`
2176
+ ]);
2177
+ const now = nowSeconds();
2178
+ const entries = [];
2179
+ for (const row of rows) {
2180
+ const expiresAt = row.expires_at;
2181
+ if (expiresAt !== null && expiresAt !== void 0 && Number(expiresAt) <= now) continue;
2182
+ entries.push({
2183
+ name: String(row.key),
2184
+ expiration: expiresAt === null || expiresAt === void 0 ? null : Number(expiresAt)
2185
+ });
2186
+ if (entries.length >= limit) break;
2187
+ }
2188
+ return entries;
2189
+ }
2190
+ default:
2191
+ throw new Error(
2192
+ `\u672A\u77E5\u7684 cloud.kv \u65B9\u6CD5 "${String(method)}"\uFF08${KV_CAPABILITY_CODES.invalidMethod}\uFF09`
2193
+ );
2194
+ }
2195
+ } catch (error) {
2196
+ throw errorWithCode2(error);
2197
+ }
2198
+ };
2199
+ return {
2200
+ capabilities: [{ name: "kv", value: { [RPC_CAPABILITY_KEY]: true } }],
2201
+ rpcHandlers: { kv: handler }
2202
+ };
2203
+ }
2204
+ var KV_TABLE, KV_RPC, KV_CAPABILITY_CODES, KV_LIST_DEFAULT_LIMIT;
2205
+ var init_kv = __esm({
2206
+ "packages/runtime/src/database/sdk/kv.ts"() {
2207
+ "use strict";
2208
+ init_capability_keys();
2209
+ KV_TABLE = "_adep_kv";
2210
+ KV_RPC = {
2211
+ get: "get",
2212
+ put: "put",
2213
+ delete: "delete",
2214
+ list: "list"
2215
+ };
2216
+ KV_CAPABILITY_CODES = {
2217
+ invalidMethod: "KV_INVALID_METHOD"
2218
+ };
2219
+ KV_LIST_DEFAULT_LIMIT = 100;
2220
+ }
2221
+ });
2222
+
2004
2223
  // packages/runtime/src/storage/driver.ts
2005
2224
  function assertSafeStoragePath(path) {
2006
2225
  if (typeof path !== "string" || path.length === 0) {
@@ -2259,9 +2478,12 @@ function createStorageCapability(driver, signer, projectId) {
2259
2478
  const handler = async (method, args) => {
2260
2479
  switch (method) {
2261
2480
  case "upload": {
2262
- const [path, data] = args;
2481
+ const [path, data, options] = args;
2263
2482
  return toStoredFile(
2264
- await driver.put(projectId, path, asBytes(data), { visibility: DEFAULT_VISIBILITY })
2483
+ await driver.put(projectId, path, asBytes(data), {
2484
+ visibility: DEFAULT_VISIBILITY,
2485
+ ...options?.contentType === void 0 ? {} : { contentType: options.contentType }
2486
+ })
2265
2487
  );
2266
2488
  }
2267
2489
  case "get": {
@@ -2306,15 +2528,15 @@ var init_cloud2 = __esm({
2306
2528
  });
2307
2529
 
2308
2530
  // packages/runtime/src/storage/driver/local.ts
2309
- import { mkdir as mkdir3, readFile as readFile2, readdir, rm as rm2, stat as stat3, unlink, writeFile as writeFile2 } from "node:fs/promises";
2310
- import { dirname as dirname4, join as join3 } from "node:path";
2531
+ import { mkdir as mkdir4, readFile as readFile3, readdir as readdir2, rm as rm2, stat as stat4, unlink, writeFile as writeFile3 } from "node:fs/promises";
2532
+ import { dirname as dirname5, join as join4 } from "node:path";
2311
2533
  function createLocalStorageDriver(options) {
2312
2534
  const quotaBytes = options.quotaBytes ?? PROJECT_QUOTA_BYTES;
2313
- const bucketDir = (projectId) => join3(options.dir, projectId);
2314
- const objectPath = (projectId, path) => join3(bucketDir(projectId), path);
2315
- const metaPath = (projectId, path) => join3(dirname4(objectPath(projectId, path)), `${path.split("/").pop() ?? ""}${META_SUFFIX}`);
2535
+ const bucketDir = (projectId) => join4(options.dir, projectId);
2536
+ const objectPath = (projectId, path) => join4(bucketDir(projectId), path);
2537
+ const metaPath = (projectId, path) => join4(dirname5(objectPath(projectId, path)), `${path.split("/").pop() ?? ""}${META_SUFFIX}`);
2316
2538
  const readStoredMeta = async (projectId, path) => {
2317
- const raw = await readFile2(metaPath(projectId, path), "utf8");
2539
+ const raw = await readFile3(metaPath(projectId, path), "utf8");
2318
2540
  return JSON.parse(raw);
2319
2541
  };
2320
2542
  const writeStoredMeta = async (projectId, path, meta) => {
@@ -2324,7 +2546,7 @@ function createLocalStorageDriver(options) {
2324
2546
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2325
2547
  ...meta.contentType === void 0 ? {} : { contentType: meta.contentType }
2326
2548
  };
2327
- await writeFile2(metaPath(projectId, path), JSON.stringify(payload), "utf8");
2549
+ await writeFile3(metaPath(projectId, path), JSON.stringify(payload), "utf8");
2328
2550
  };
2329
2551
  const totalSize = async (projectId) => {
2330
2552
  const root = bucketDir(projectId);
@@ -2332,20 +2554,20 @@ function createLocalStorageDriver(options) {
2332
2554
  const walk = async (dir) => {
2333
2555
  let entries;
2334
2556
  try {
2335
- entries = await readdir(dir, { withFileTypes: true });
2557
+ entries = await readdir2(dir, { withFileTypes: true });
2336
2558
  } catch {
2337
2559
  return;
2338
2560
  }
2339
2561
  const tasks = [];
2340
2562
  for (const entry of entries) {
2341
- const full = join3(dir, entry.name);
2563
+ const full = join4(dir, entry.name);
2342
2564
  if (entry.isDirectory()) {
2343
2565
  tasks.push(walk(full));
2344
2566
  } else if (entry.isFile() && !entry.name.endsWith(META_SUFFIX)) {
2345
2567
  tasks.push(
2346
2568
  (async () => {
2347
2569
  try {
2348
- const info = await stat3(full);
2570
+ const info = await stat4(full);
2349
2571
  total += info.size;
2350
2572
  } catch {
2351
2573
  }
@@ -2367,7 +2589,7 @@ function createLocalStorageDriver(options) {
2367
2589
  const used = await totalSize(projectId);
2368
2590
  let existingSize = 0;
2369
2591
  try {
2370
- existingSize = (await stat3(objectPath(projectId, path))).size;
2592
+ existingSize = (await stat4(objectPath(projectId, path))).size;
2371
2593
  } catch {
2372
2594
  existingSize = 0;
2373
2595
  }
@@ -2382,8 +2604,8 @@ function createLocalStorageDriver(options) {
2382
2604
  );
2383
2605
  }
2384
2606
  const dest = objectPath(projectId, path);
2385
- await mkdir3(dirname4(dest), { recursive: true });
2386
- await writeFile2(dest, data);
2607
+ await mkdir4(dirname5(dest), { recursive: true });
2608
+ await writeFile3(dest, data);
2387
2609
  await writeStoredMeta(projectId, path, {
2388
2610
  visibility: putOptions.visibility,
2389
2611
  size: data.byteLength,
@@ -2406,7 +2628,7 @@ function createLocalStorageDriver(options) {
2406
2628
  } catch {
2407
2629
  throw new StorageError(404, STORAGE_CODES.notFound, `\u6587\u4EF6 "${path}" \u4E0D\u5B58\u5728`);
2408
2630
  }
2409
- const data = await readFile2(objectPath(projectId, path));
2631
+ const data = await readFile3(objectPath(projectId, path));
2410
2632
  const result = {
2411
2633
  path,
2412
2634
  size: meta.size,
@@ -2437,7 +2659,7 @@ function createLocalStorageDriver(options) {
2437
2659
  assertSafeStoragePath(path);
2438
2660
  let exists = true;
2439
2661
  try {
2440
- await stat3(objectPath(projectId, path));
2662
+ await stat4(objectPath(projectId, path));
2441
2663
  } catch {
2442
2664
  exists = false;
2443
2665
  }
@@ -2460,25 +2682,25 @@ function createLocalStorageDriver(options) {
2460
2682
  }
2461
2683
  const root = bucketDir(projectId);
2462
2684
  const metas = [];
2463
- const walk = async (dir, relative3) => {
2685
+ const walk = async (dir, relative4) => {
2464
2686
  let entries;
2465
2687
  try {
2466
- entries = await readdir(dir, { withFileTypes: true });
2688
+ entries = await readdir2(dir, { withFileTypes: true });
2467
2689
  } catch {
2468
2690
  return;
2469
2691
  }
2470
2692
  const tasks = [];
2471
2693
  for (const entry of entries) {
2472
2694
  if (entry.name.endsWith(META_SUFFIX)) continue;
2473
- const full = join3(dir, entry.name);
2474
- const rel = relative3 === "" ? entry.name : `${relative3}/${entry.name}`;
2695
+ const full = join4(dir, entry.name);
2696
+ const rel = relative4 === "" ? entry.name : `${relative4}/${entry.name}`;
2475
2697
  if (entry.isFile()) {
2476
2698
  if (prefix !== void 0 && !rel.startsWith(prefix)) continue;
2477
2699
  tasks.push(
2478
2700
  (async () => {
2479
2701
  try {
2480
2702
  const payload = JSON.parse(
2481
- await readFile2(full + META_SUFFIX, "utf8")
2703
+ await readFile3(full + META_SUFFIX, "utf8")
2482
2704
  );
2483
2705
  metas.push({
2484
2706
  path: rel,
@@ -2520,9 +2742,9 @@ var init_local = __esm({
2520
2742
  });
2521
2743
 
2522
2744
  // packages/cli/src/sim/storage.ts
2523
- import { join as join4 } from "node:path";
2745
+ import { join as join5 } from "node:path";
2524
2746
  function createSimStorageCapability(options) {
2525
- const dir = join4(options.cwd, ".adep", "sim", "storage");
2747
+ const dir = join5(options.cwd, ".adep", "sim", "storage");
2526
2748
  const driver = createLocalStorageDriver({ dir });
2527
2749
  const signer = {
2528
2750
  secret: options.secret ?? "adep-sim-secret",
@@ -2669,10 +2891,10 @@ var init_realtime = __esm({
2669
2891
  });
2670
2892
 
2671
2893
  // packages/cli/src/sim/runtime.ts
2672
- import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
2673
- import { dirname as dirname5, join as join5 } from "node:path";
2894
+ import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
2895
+ import { dirname as dirname6, join as join6 } from "node:path";
2674
2896
  function simDir(cwd) {
2675
- return join5(cwd, ".adep", "sim");
2897
+ return join6(cwd, ".adep", "sim");
2676
2898
  }
2677
2899
  function mergeBundles(bundles) {
2678
2900
  const capabilities = [];
@@ -2694,19 +2916,19 @@ function mergeBundles(bundles) {
2694
2916
  return { capabilities, rpcHandlers };
2695
2917
  }
2696
2918
  function jsonStorage(cwd) {
2697
- const file = join5(simDir(cwd), "db.json");
2919
+ const file = join6(simDir(cwd), "db.json");
2698
2920
  return {
2699
2921
  async load() {
2700
2922
  try {
2701
- const raw = await readFile3(file, "utf8");
2923
+ const raw = await readFile4(file, "utf8");
2702
2924
  return JSON.parse(raw);
2703
2925
  } catch {
2704
2926
  return null;
2705
2927
  }
2706
2928
  },
2707
2929
  async save(tables) {
2708
- await mkdir4(dirname5(file), { recursive: true });
2709
- await writeFile3(file, JSON.stringify(tables), "utf8");
2930
+ await mkdir5(dirname6(file), { recursive: true });
2931
+ await writeFile4(file, JSON.stringify(tables), "utf8");
2710
2932
  }
2711
2933
  };
2712
2934
  }
@@ -2721,7 +2943,8 @@ async function createSimRuntime(options) {
2721
2943
  projectId: options.projectId ?? "local"
2722
2944
  });
2723
2945
  const simRealtime = createSimRealtimeCapability();
2724
- const bundle = mergeBundles([db.bundle, storage.bundle, simRealtime.bundle]);
2946
+ const kvBundle = createKvCapability(db.driver);
2947
+ const bundle = mergeBundles([db.bundle, storage.bundle, kvBundle, simRealtime.bundle]);
2725
2948
  await db.engine.load();
2726
2949
  return {
2727
2950
  bundle,
@@ -2736,14 +2959,15 @@ var init_runtime = __esm({
2736
2959
  "packages/cli/src/sim/runtime.ts"() {
2737
2960
  "use strict";
2738
2961
  init_db();
2962
+ init_kv();
2739
2963
  init_storage();
2740
2964
  init_realtime();
2741
2965
  }
2742
2966
  });
2743
2967
 
2744
2968
  // packages/cli/src/sim/env.ts
2745
- import { readFile as readFile4 } from "node:fs/promises";
2746
- import { join as join6 } from "node:path";
2969
+ import { readFile as readFile5 } from "node:fs/promises";
2970
+ import { join as join7 } from "node:path";
2747
2971
  function parseEnv(content) {
2748
2972
  const env = {};
2749
2973
  for (const raw of content.split(/\r?\n/)) {
@@ -2758,8 +2982,8 @@ function parseEnv(content) {
2758
2982
  return env;
2759
2983
  }
2760
2984
  async function loadSimEnv(cwd, config = {}) {
2761
- const envRoot = await readFile4(join6(cwd, ".env"), "utf8").catch(() => "");
2762
- const envLocal = await readFile4(join6(cwd, ".env.local"), "utf8").catch(() => "");
2985
+ const envRoot = await readFile5(join7(cwd, ".env"), "utf8").catch(() => "");
2986
+ const envLocal = await readFile5(join7(cwd, ".env.local"), "utf8").catch(() => "");
2763
2987
  const merged = { ...parseEnv(envRoot), ...parseEnv(envLocal) };
2764
2988
  for (const secret of config.secrets ?? []) {
2765
2989
  if (merged[secret] !== void 0) continue;
@@ -2837,6 +3061,19 @@ var init_invoke = __esm({
2837
3061
  }
2838
3062
  });
2839
3063
 
3064
+ // packages/cli/src/builtin-deps.ts
3065
+ var LOCAL_STATE_OBJECTS_SPECIFIER, LOCAL_BUILTIN_DEPS;
3066
+ var init_builtin_deps = __esm({
3067
+ "packages/cli/src/builtin-deps.ts"() {
3068
+ "use strict";
3069
+ LOCAL_STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
3070
+ LOCAL_BUILTIN_DEPS = [
3071
+ "@adep/cf-compat",
3072
+ LOCAL_STATE_OBJECTS_SPECIFIER
3073
+ ];
3074
+ }
3075
+ });
3076
+
2840
3077
  // packages/cli/src/sim/boundary.ts
2841
3078
  var SIM_BOUNDARIES;
2842
3079
  var init_boundary = __esm({
@@ -2873,12 +3110,12 @@ var init_boundary = __esm({
2873
3110
  });
2874
3111
 
2875
3112
  // packages/cli/src/ts-config.ts
2876
- import { stat as stat4, readFile as readFile5 } from "node:fs/promises";
2877
- import { join as join7 } from "node:path";
3113
+ import { stat as stat5, readFile as readFile6 } from "node:fs/promises";
3114
+ import { join as join8 } from "node:path";
2878
3115
  async function loadAdepConfigModule(cwd) {
2879
- const configPath = join7(cwd, "adep.config.ts");
3116
+ const configPath = join8(cwd, "adep.config.ts");
2880
3117
  try {
2881
- await stat4(configPath);
3118
+ await stat5(configPath);
2882
3119
  } catch {
2883
3120
  return null;
2884
3121
  }
@@ -2890,7 +3127,7 @@ async function loadAdepConfigModule(cwd) {
2890
3127
  rawDefault = mod.default;
2891
3128
  } else {
2892
3129
  const { transform } = await import("esbuild");
2893
- const source = await readFile5(configPath, "utf8");
3130
+ const source = await readFile6(configPath, "utf8");
2894
3131
  const { code } = await transform(source, {
2895
3132
  loader: "ts",
2896
3133
  format: "esm",
@@ -2920,7 +3157,1120 @@ ${result.errors.map((e) => ` - ${e}`).join("\n")}`;
2920
3157
  var init_ts_config = __esm({
2921
3158
  "packages/cli/src/ts-config.ts"() {
2922
3159
  "use strict";
2923
- init_adep_config();
3160
+ init_adep_config();
3161
+ }
3162
+ });
3163
+
3164
+ // packages/runtime/src/state-objects/runtime.ts
3165
+ var StateObject, StateObjectError, StateObjectRuntime;
3166
+ var init_runtime2 = __esm({
3167
+ "packages/runtime/src/state-objects/runtime.ts"() {
3168
+ "use strict";
3169
+ StateObject = class {
3170
+ id;
3171
+ /** 对象内存状态(单例驻留);load 时从后端恢复。 */
3172
+ state;
3173
+ alarmAt = null;
3174
+ /** 运行时注入的持久化句柄(内部;protected,子类 flush() 使用)。 */
3175
+ runtime;
3176
+ constructor(id) {
3177
+ this.id = id;
3178
+ this.state = this.initialState();
3179
+ }
3180
+ /** 供运行时读取/序列化。 */
3181
+ getState() {
3182
+ return { ...this.state };
3183
+ }
3184
+ /** 通用快照方法(任何对象可经 invoke(type, id, 'snapshot') 读取)。 */
3185
+ async snapshot() {
3186
+ return this.getState();
3187
+ }
3188
+ /** 设置未来唤醒(alarm):到期时运行时调 onAlarm(调度 CF-037 落地)。 */
3189
+ setAlarm(at) {
3190
+ this.alarmAt = at;
3191
+ }
3192
+ clearAlarm() {
3193
+ this.alarmAt = null;
3194
+ }
3195
+ /** alarm 到期回调(子类覆写)。 */
3196
+ async onAlarm() {
3197
+ }
3198
+ /** 显式持久化当前状态(方法内任何位置可调)。 */
3199
+ async flush() {
3200
+ await this.runtime.flush(this);
3201
+ }
3202
+ };
3203
+ StateObjectError = class extends Error {
3204
+ code;
3205
+ constructor(code, message) {
3206
+ super(message);
3207
+ this.name = "StateObjectError";
3208
+ this.code = code;
3209
+ }
3210
+ };
3211
+ StateObjectRuntime = class {
3212
+ registry = /* @__PURE__ */ new Map();
3213
+ instances = /* @__PURE__ */ new Map();
3214
+ backend;
3215
+ constructor(backend) {
3216
+ this.backend = backend;
3217
+ }
3218
+ define(cls) {
3219
+ this.registry.set(cls.typeName, cls);
3220
+ }
3221
+ /** 已注册类型清单(控制台/审计用)。 */
3222
+ types() {
3223
+ return [...this.registry.keys()];
3224
+ }
3225
+ /** 内存驻留实例数(诊断用)。 */
3226
+ residentCount() {
3227
+ return this.instances.size;
3228
+ }
3229
+ key(type, id) {
3230
+ return `${type}:${id}`;
3231
+ }
3232
+ /** 取对象实例(单例驻留):内存有 → 复用;无 → 后端恢复或 new 初始态。 */
3233
+ async get(type, id) {
3234
+ const cls = this.registry.get(type);
3235
+ if (cls === void 0) {
3236
+ throw new StateObjectError(
3237
+ "STATE_TYPE_NOT_REGISTERED",
3238
+ `\u72B6\u6001\u5BF9\u8C61\u7C7B\u578B "${type}" \u672A\u6CE8\u518C\uFF08\u5DF2\u6CE8\u518C\uFF1A${this.types().join(", ") || "\u65E0"}\uFF09`
3239
+ );
3240
+ }
3241
+ const k = this.key(type, id);
3242
+ const hit = this.instances.get(k);
3243
+ if (hit !== void 0) return hit;
3244
+ const snapshot = await this.backend.load(type, id);
3245
+ const raw = new cls(id);
3246
+ const created = raw;
3247
+ created.state = snapshot !== null ? snapshot.state : created.state;
3248
+ created.alarmAt = snapshot !== null ? snapshot.alarmAt : null;
3249
+ created.runtime = this;
3250
+ this.instances.set(k, created);
3251
+ return created;
3252
+ }
3253
+ /** 方法路由:单例对象上串行执行方法。 */
3254
+ async invoke(type, id, method, args = []) {
3255
+ const inst = await this.get(type, id);
3256
+ const fn = inst[method];
3257
+ if (typeof fn !== "function") {
3258
+ throw new StateObjectError(
3259
+ "STATE_METHOD_NOT_FOUND",
3260
+ `\u72B6\u6001\u5BF9\u8C61 "${type}:${id}" \u65E0\u65B9\u6CD5 "${method}"`
3261
+ );
3262
+ }
3263
+ try {
3264
+ return await fn.call(inst, ...args);
3265
+ } catch (error) {
3266
+ if (error instanceof StateObjectError) throw error;
3267
+ throw new StateObjectError(
3268
+ "STATE_INVOKE_ERROR",
3269
+ `\u72B6\u6001\u5BF9\u8C61 "${type}:${id}" \u65B9\u6CD5 "${method}" \u6267\u884C\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`
3270
+ );
3271
+ }
3272
+ }
3273
+ /** 持久化快照(对象方法内 flush() 触发,或运行时统一写)。 */
3274
+ async flush(inst) {
3275
+ const raw = inst;
3276
+ const type = inst.constructor.typeName;
3277
+ if (type === void 0) {
3278
+ throw new StateObjectError("STATE_TYPE_NOT_REGISTERED", "\u72B6\u6001\u5BF9\u8C61\u7C7B\u5FC5\u987B\u58F0\u660E static typeName");
3279
+ }
3280
+ await this.backend.save(type, inst.id, inst.getState(), raw.alarmAt);
3281
+ }
3282
+ /**
3283
+ * alarm 轮询:把到期对象唤醒并调 onAlarm(CF-037)。
3284
+ * - onAlarm 后统一持久化(flush):onAlarm 内改的 state 与 setAlarm 重调度 / clearAlarm
3285
+ * 的新 alarmAt 都落库;
3286
+ * - 单对象 onAlarm 抛错**不阻塞**同 tick 其余对象:失败对象不落库、alarmAt 保留
3287
+ * → 下轮 dueAlarms 仍命中重试;错误折叠进 failed(不泄漏内部栈)。
3288
+ */
3289
+ async pump(now) {
3290
+ const due = await this.backend.dueAlarms(now);
3291
+ const fired = [];
3292
+ const failed = [];
3293
+ for (const d of due) {
3294
+ try {
3295
+ const inst = await this.get(d.type, d.id);
3296
+ await inst.onAlarm();
3297
+ await this.flush(inst);
3298
+ fired.push({ type: d.type, id: d.id });
3299
+ } catch (error) {
3300
+ failed.push({
3301
+ type: d.type,
3302
+ id: d.id,
3303
+ error: error instanceof Error ? error.message : String(error)
3304
+ });
3305
+ }
3306
+ }
3307
+ return { fired, failed };
3308
+ }
3309
+ /** 释放内存驻留(进程重启 / 测试隔离用);不删后端数据。 */
3310
+ evictAll() {
3311
+ this.instances.clear();
3312
+ }
3313
+ };
3314
+ }
3315
+ });
3316
+
3317
+ // packages/runtime/src/state-objects/backend.ts
3318
+ function createProjectDriverStateBackend(driver) {
3319
+ let ensured = false;
3320
+ const ensureTable = async () => {
3321
+ if (ensured) return;
3322
+ await driver.run(
3323
+ `CREATE TABLE IF NOT EXISTS ${STATE_OBJECTS_TABLE} ("type" TEXT NOT NULL, "id" TEXT NOT NULL, "state" TEXT NOT NULL, "alarm_at" INTEGER, "updated_at" INTEGER NOT NULL, PRIMARY KEY ("type", "id"))`
3324
+ );
3325
+ ensured = true;
3326
+ };
3327
+ return {
3328
+ async load(type, id) {
3329
+ await ensureTable();
3330
+ const rows = await driver.all(
3331
+ `SELECT "state", "alarm_at" FROM ${STATE_OBJECTS_TABLE} WHERE "type" = ? AND "id" = ?`,
3332
+ [type, id]
3333
+ );
3334
+ if (rows.length === 0) return null;
3335
+ return {
3336
+ state: JSON.parse(String(rows[0].state)),
3337
+ alarmAt: rows[0].alarm_at
3338
+ };
3339
+ },
3340
+ async save(type, id, state, alarmAt) {
3341
+ await ensureTable();
3342
+ const existing = await driver.all(
3343
+ `SELECT 1 FROM ${STATE_OBJECTS_TABLE} WHERE "type" = ? AND "id" = ?`,
3344
+ [type, id]
3345
+ );
3346
+ const stateJson = JSON.stringify(state);
3347
+ if (existing.length === 0) {
3348
+ await driver.run(
3349
+ `INSERT INTO ${STATE_OBJECTS_TABLE} ("type", "id", "state", "alarm_at", "updated_at") VALUES (?, ?, ?, ?, ?)`,
3350
+ [type, id, stateJson, alarmAt, Date.now()]
3351
+ );
3352
+ } else {
3353
+ await driver.run(
3354
+ `UPDATE ${STATE_OBJECTS_TABLE} SET "state" = ?, "alarm_at" = ?, "updated_at" = ? WHERE "type" = ? AND "id" = ?`,
3355
+ [stateJson, alarmAt, Date.now(), type, id]
3356
+ );
3357
+ }
3358
+ },
3359
+ async dueAlarms(now) {
3360
+ await ensureTable();
3361
+ const rows = await driver.all(
3362
+ `SELECT "type", "id", "alarm_at" FROM ${STATE_OBJECTS_TABLE} WHERE "alarm_at" IS NOT NULL AND "alarm_at" <= ?`,
3363
+ [now]
3364
+ );
3365
+ return rows.map((r) => ({
3366
+ type: r.type,
3367
+ id: r.id,
3368
+ alarmAt: r.alarm_at
3369
+ }));
3370
+ },
3371
+ async remove(type, id) {
3372
+ await ensureTable();
3373
+ await driver.run(`DELETE FROM ${STATE_OBJECTS_TABLE} WHERE "type" = ? AND "id" = ?`, [
3374
+ type,
3375
+ id
3376
+ ]);
3377
+ }
3378
+ };
3379
+ }
3380
+ var STATE_OBJECTS_TABLE;
3381
+ var init_backend = __esm({
3382
+ "packages/runtime/src/state-objects/backend.ts"() {
3383
+ "use strict";
3384
+ STATE_OBJECTS_TABLE = "_adep_state_objects";
3385
+ }
3386
+ });
3387
+
3388
+ // packages/runtime/src/state-objects/http.ts
3389
+ function parseStatePath(rest) {
3390
+ const segments = rest.split("/").filter((s) => s.length > 0);
3391
+ if (segments[0] !== STATE_PATH || segments.length < 4) return null;
3392
+ return {
3393
+ type: decodeURIComponent(segments[1]),
3394
+ id: decodeURIComponent(segments[2]),
3395
+ method: decodeURIComponent(segments.slice(3).join("/"))
3396
+ };
3397
+ }
3398
+ function parseStateBody(body) {
3399
+ if (body === null || body.length === 0) return { args: [] };
3400
+ try {
3401
+ const parsed = JSON.parse(body);
3402
+ if (!Array.isArray(parsed)) return { error: "body \u5FC5\u987B\u662F\u53C2\u6570\u6570\u7EC4\uFF08JSON\uFF09" };
3403
+ return { args: parsed };
3404
+ } catch {
3405
+ return { error: "body \u5FC5\u987B\u662F\u5408\u6CD5 JSON" };
3406
+ }
3407
+ }
3408
+ var STATE_PATH;
3409
+ var init_http = __esm({
3410
+ "packages/runtime/src/state-objects/http.ts"() {
3411
+ "use strict";
3412
+ STATE_PATH = "state";
3413
+ }
3414
+ });
3415
+
3416
+ // packages/runtime/src/state-objects/demo.ts
3417
+ var DemoCounter, DemoChatRoom;
3418
+ var init_demo = __esm({
3419
+ "packages/runtime/src/state-objects/demo.ts"() {
3420
+ "use strict";
3421
+ init_runtime2();
3422
+ DemoCounter = class extends StateObject {
3423
+ static typeName = "DemoCounter";
3424
+ initialState() {
3425
+ return { count: 0 };
3426
+ }
3427
+ async increment(by = 1) {
3428
+ this.state.count += by;
3429
+ await this.flush();
3430
+ return { count: this.state.count };
3431
+ }
3432
+ async get() {
3433
+ return { count: this.state.count };
3434
+ }
3435
+ };
3436
+ DemoChatRoom = class extends StateObject {
3437
+ static typeName = "DemoChatRoom";
3438
+ initialState() {
3439
+ return { members: [], messages: [], cursor: 0 };
3440
+ }
3441
+ async join(user) {
3442
+ if (!this.state.members.includes(user)) this.state.members.push(user);
3443
+ this.state.cursor += 1;
3444
+ await this.flush();
3445
+ return { members: this.state.members, cursor: this.state.cursor };
3446
+ }
3447
+ async send(user, text) {
3448
+ const seq = this.state.messages.length + 1;
3449
+ this.state.messages.push({ user, text, at: Date.now() });
3450
+ await this.flush();
3451
+ return { seq };
3452
+ }
3453
+ };
3454
+ }
3455
+ });
3456
+
3457
+ // packages/runtime/src/functions/runtime/exports.ts
3458
+ function transformModule(code) {
3459
+ let out = code;
3460
+ const named = [];
3461
+ out = out.replace(/(^|\n)(\s*)export\s+default\s+/g, "$1$2module.default = ");
3462
+ out = out.replace(
3463
+ /import\s*\{([^}]*)\}\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
3464
+ (_match, names, source) => `const {${names}} = require(${source})`
3465
+ );
3466
+ out = out.replace(
3467
+ /import\s*\*\s*as\s*([A-Za-z_$][\w$]*)\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
3468
+ (_match, name, source) => `const ${name} = require(${source})`
3469
+ );
3470
+ out = out.replace(
3471
+ /import\s+([A-Za-z_$][\w$]*)\s+from\s*(['"][^'"]*['"])[ \t]*;?/g,
3472
+ (_match, name, source) => `const ${name} = require(${source})`
3473
+ );
3474
+ out = out.replace(
3475
+ /export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
3476
+ (_match, kw, name) => {
3477
+ named.push(name);
3478
+ return `${kw} ${name}`;
3479
+ }
3480
+ );
3481
+ out = out.replace(
3482
+ /export\s+(async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/g,
3483
+ (_match, asyncKw, name) => {
3484
+ named.push(name);
3485
+ return `${asyncKw ?? ""}function ${name}`;
3486
+ }
3487
+ );
3488
+ out = out.replace(/export\s+class\s+([A-Za-z_$][\w$]*)/g, (_match, name) => {
3489
+ named.push(name);
3490
+ return `class ${name}`;
3491
+ });
3492
+ if (named.length > 0) {
3493
+ out += `
3494
+ ;Object.assign(exports, { ${named.join(", ")} })`;
3495
+ }
3496
+ return out;
3497
+ }
3498
+ var init_exports = __esm({
3499
+ "packages/runtime/src/functions/runtime/exports.ts"() {
3500
+ "use strict";
3501
+ }
3502
+ });
3503
+
3504
+ // packages/runtime/src/functions/runtime/sandbox.ts
3505
+ import vm from "node:vm";
3506
+ import * as nodeModule from "node:module";
3507
+ function transpile(code) {
3508
+ const bun = globalThis["Bun"];
3509
+ if (bun?.Transpiler !== void 0) {
3510
+ bunTranspiler ??= new bun.Transpiler({ loader: "ts" });
3511
+ return bunTranspiler.transformSync(code);
3512
+ }
3513
+ const stripTypeScriptTypes2 = nodeModule.stripTypeScriptTypes;
3514
+ if (typeof stripTypeScriptTypes2 === "function") {
3515
+ return stripTypeScriptTypes2(code, { mode: "strip" });
3516
+ }
3517
+ return code;
3518
+ }
3519
+ function transformExports(code) {
3520
+ return transformModule(code);
3521
+ }
3522
+ function resolveModulePath(fromDir, request, files) {
3523
+ if (!request.startsWith("./") && !request.startsWith("../")) return null;
3524
+ const base = joinPosix(fromDir, request);
3525
+ const candidates = [base, `${base}.ts`, `${base}.js`, `${base}/index.ts`, `${base}/index.js`];
3526
+ for (const candidate of candidates) {
3527
+ const normalized = normalizePosix(candidate);
3528
+ if (files[normalized] !== void 0) return normalized;
3529
+ }
3530
+ return null;
3531
+ }
3532
+ function joinPosix(dir, request) {
3533
+ const parts = [...dir.split("/"), ...request.split("/")];
3534
+ const stack = [];
3535
+ for (const part of parts) {
3536
+ if (part === "" || part === ".") continue;
3537
+ if (part === "..") stack.pop();
3538
+ else stack.push(part);
3539
+ }
3540
+ return stack.join("/");
3541
+ }
3542
+ function normalizePosix(p) {
3543
+ return joinPosix("", p);
3544
+ }
3545
+ function loadModule(path, files, sandboxGlobals, cache, resolveBare, bareCache) {
3546
+ const cached = cache.get(path);
3547
+ if (cached !== void 0) return cached;
3548
+ const source = files[path];
3549
+ if (source === void 0) {
3550
+ throw new Error(`\u6A21\u5757\u4E0D\u5B58\u5728\uFF1A${path}`);
3551
+ }
3552
+ const exports = {};
3553
+ cache.set(path, exports);
3554
+ const dir = path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
3555
+ const module = { exports, default: void 0 };
3556
+ const require2 = (request) => {
3557
+ const resolved = resolveModulePath(dir, request, files);
3558
+ if (resolved !== null) {
3559
+ return loadModule(resolved, files, sandboxGlobals, cache, resolveBare, bareCache);
3560
+ }
3561
+ if (resolveBare !== void 0 && !request.startsWith("./") && !request.startsWith("../")) {
3562
+ const cachedModule = bareCache?.get(request);
3563
+ if (cachedModule !== void 0) return cachedModule;
3564
+ const loaded = resolveBare(request);
3565
+ bareCache?.set(request, loaded);
3566
+ return loaded;
3567
+ }
3568
+ const error = new Error(
3569
+ `\u6C99\u7BB1\u62D2\u7EDD\u8BE5\u5F15\u7528\uFF1A"${request}"\u3002\u51FD\u6570\u5185\u53EA\u80FD require \u9879\u76EE\u5185\u7684\u76F8\u5BF9\u8DEF\u5F84\u6587\u4EF6\uFF08FN_SANDBOX_BUILTIN_BLOCKED\uFF09`
3570
+ );
3571
+ error.code = SANDBOX_BUILTIN_REJECTED;
3572
+ throw error;
3573
+ };
3574
+ let transformed;
3575
+ try {
3576
+ transformed = transformExports(transpile(source));
3577
+ } catch (error) {
3578
+ const rawMessage = error instanceof Error ? error.message : String(error);
3579
+ const stack = error.stack;
3580
+ const line = typeof stack === "string" ? /(?:^|\n):(\d+)(?:\n|$)/.exec(stack)?.[1] : void 0;
3581
+ const location = line === void 0 ? path : `${path}:${line}`;
3582
+ const wrapped = new Error(`\u6E90\u7801\u8BED\u6CD5\u9519\u8BEF\uFF08${location}\uFF09\uFF1A${rawMessage}`, { cause: error });
3583
+ const code = error.code;
3584
+ if (typeof code === "string") wrapped.code = code;
3585
+ throw wrapped;
3586
+ }
3587
+ const wrapper = vm.runInNewContext(
3588
+ `(function (module, exports, require) { ${transformed}
3589
+ })`,
3590
+ vm.createContext({ ...sandboxGlobals }),
3591
+ { filename: path }
3592
+ );
3593
+ wrapper(module, exports, require2);
3594
+ if (module.default !== void 0 && exports["default"] === void 0) {
3595
+ exports["default"] = module.default;
3596
+ }
3597
+ return exports;
3598
+ }
3599
+ function loadFunctionModule(files, entry, sandboxGlobals, resolveBare) {
3600
+ const cache = /* @__PURE__ */ new Map();
3601
+ const bareCache = /* @__PURE__ */ new Map();
3602
+ const entryExports = loadModule(entry, files, sandboxGlobals, cache, resolveBare, bareCache);
3603
+ const handler = entryExports["default"];
3604
+ if (typeof handler !== "function") {
3605
+ throw new Error(`\u5165\u53E3\u6587\u4EF6 ${entry} \u7F3A\u5C11 default \u5BFC\u51FA\u7684\u51FD\u6570`);
3606
+ }
3607
+ return { handler };
3608
+ }
3609
+ var bunTranspiler, SANDBOX_BUILTIN_REJECTED;
3610
+ var init_sandbox = __esm({
3611
+ "packages/runtime/src/functions/runtime/sandbox.ts"() {
3612
+ "use strict";
3613
+ init_exports();
3614
+ SANDBOX_BUILTIN_REJECTED = "FN_SANDBOX_BUILTIN_BLOCKED";
3615
+ }
3616
+ });
3617
+
3618
+ // packages/runtime/src/state-objects/loader.ts
3619
+ function resolveStateObjectSpecifier(request) {
3620
+ if (request === STATE_OBJECTS_SPECIFIER) return { StateObject };
3621
+ return void 0;
3622
+ }
3623
+ function defaultStateSandboxGlobals() {
3624
+ return {
3625
+ console,
3626
+ URL,
3627
+ URLSearchParams,
3628
+ Request,
3629
+ Response,
3630
+ Headers,
3631
+ TextEncoder,
3632
+ TextDecoder,
3633
+ AbortController,
3634
+ AbortSignal,
3635
+ ReadableStream,
3636
+ WritableStream,
3637
+ TransformStream,
3638
+ Blob,
3639
+ FormData,
3640
+ crypto,
3641
+ performance,
3642
+ atob,
3643
+ btoa,
3644
+ structuredClone
3645
+ };
3646
+ }
3647
+ function collectStateObjectClasses(exports_) {
3648
+ const classes = [];
3649
+ for (const value of Object.values(exports_)) {
3650
+ if (typeof value !== "function") continue;
3651
+ const proto = value.prototype;
3652
+ if (typeof proto !== "object" || proto === null) continue;
3653
+ if (!(proto instanceof StateObject)) continue;
3654
+ if (!Object.hasOwn(value, "typeName")) {
3655
+ throw new Error(
3656
+ `\u72B6\u6001\u5BF9\u8C61\u7C7B\u5FC5\u987B\u58F0\u660E static typeName\uFF08${value.name ?? "anonymous"}\uFF09`
3657
+ );
3658
+ }
3659
+ const typeName = value.typeName;
3660
+ if (typeof typeName !== "string" || typeName.length === 0) {
3661
+ throw new Error(
3662
+ `\u72B6\u6001\u5BF9\u8C61\u7C7B\u5FC5\u987B\u58F0\u660E static typeName\uFF08${value.name ?? "anonymous"}\uFF09`
3663
+ );
3664
+ }
3665
+ classes.push(value);
3666
+ }
3667
+ return classes;
3668
+ }
3669
+ function loadStateObjectClasses(files, entry = STATE_OBJECTS_ENTRY, options = {}) {
3670
+ if (files[entry] === void 0) {
3671
+ throw new Error(`\u72B6\u6001\u5BF9\u8C61\u58F0\u660E\u6587\u4EF6\u7F3A\u5931\uFF1A${entry}\uFF08\u7EA6\u5B9A ${STATE_OBJECTS_ENTRY}\uFF09`);
3672
+ }
3673
+ const globals = options.sandboxGlobals ?? defaultStateSandboxGlobals();
3674
+ const exportsObject = loadModule(entry, files, globals, /* @__PURE__ */ new Map(), options.resolveBare, /* @__PURE__ */ new Map());
3675
+ return collectStateObjectClasses(exportsObject);
3676
+ }
3677
+ var STATE_OBJECTS_ENTRY, STATE_OBJECTS_SPECIFIER;
3678
+ var init_loader = __esm({
3679
+ "packages/runtime/src/state-objects/loader.ts"() {
3680
+ "use strict";
3681
+ init_runtime2();
3682
+ init_sandbox();
3683
+ STATE_OBJECTS_ENTRY = "state-objects.ts";
3684
+ STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
3685
+ }
3686
+ });
3687
+
3688
+ // packages/runtime/src/state-objects/index.ts
3689
+ var init_state_objects = __esm({
3690
+ "packages/runtime/src/state-objects/index.ts"() {
3691
+ "use strict";
3692
+ init_runtime2();
3693
+ init_backend();
3694
+ init_http();
3695
+ init_demo();
3696
+ init_loader();
3697
+ }
3698
+ });
3699
+
3700
+ // packages/runtime/src/functions/runtime/cloud-container.ts
3701
+ function createCloud(registrations) {
3702
+ const store = registrations;
3703
+ return new Proxy(
3704
+ {},
3705
+ {
3706
+ get(_target, prop) {
3707
+ if (typeof prop !== "string") return void 0;
3708
+ if (!store.has(prop)) {
3709
+ const hint = KNOWN_CAPABILITY_HINTS[prop];
3710
+ throw new CapabilityNotRegisteredError(
3711
+ hint?.code ?? "CAPABILITY_NOT_REGISTERED",
3712
+ hint?.message ?? `\u80FD\u529B "${prop}" \u672A\u6CE8\u518C\uFF1A\u8BF7\u5728\u51FD\u6570\u6240\u5728\u9879\u76EE\u5B89\u88C5\u5BF9\u5E94\u80FD\u529B`
3713
+ );
3714
+ }
3715
+ return store.get(prop);
3716
+ },
3717
+ has: () => true
3718
+ // 支持 'db' in ctx.cloud 形态
3719
+ }
3720
+ );
3721
+ }
3722
+ function createCloudContainer() {
3723
+ const registry = /* @__PURE__ */ new Map();
3724
+ const names = /* @__PURE__ */ new Set();
3725
+ let cloud = null;
3726
+ const rebuild = () => {
3727
+ cloud = createCloud(registry);
3728
+ };
3729
+ rebuild();
3730
+ return {
3731
+ register(name, impl) {
3732
+ registry.set(name, impl);
3733
+ names.add(name);
3734
+ rebuild();
3735
+ },
3736
+ unregister(name) {
3737
+ registry.delete(name);
3738
+ names.delete(name);
3739
+ rebuild();
3740
+ },
3741
+ get names() {
3742
+ return [...names];
3743
+ },
3744
+ get cloud() {
3745
+ return cloud;
3746
+ }
3747
+ };
3748
+ }
3749
+ var KNOWN_CAPABILITY_HINTS, CapabilityNotRegisteredError;
3750
+ var init_cloud_container = __esm({
3751
+ "packages/runtime/src/functions/runtime/cloud-container.ts"() {
3752
+ "use strict";
3753
+ KNOWN_CAPABILITY_HINTS = {
3754
+ db: {
3755
+ code: "DB_NOT_PROVISIONED",
3756
+ message: "\u9879\u76EE\u6570\u636E\u5E93\u5C1A\u672A\u5F00\u542F\uFF1A\u8BF7\u5230\u9879\u76EE\u8BBE\u7F6E\u542F\u52A8\u6570\u636E\u5E93\uFF08DB_NOT_PROVISIONED\uFF09"
3757
+ },
3758
+ storage: {
3759
+ code: "STORAGE_NOT_AVAILABLE",
3760
+ message: "\u6587\u4EF6\u5B58\u50A8\u5C1A\u672A\u5F00\u542F\uFF1A\u8BF7\u5230\u9879\u76EE\u8BBE\u7F6E\u5F00\u542F\u6587\u4EF6\u5B58\u50A8\uFF08STORAGE_NOT_AVAILABLE\uFF09"
3761
+ },
3762
+ fetch: {
3763
+ code: "FN_FETCH_DISABLED",
3764
+ message: "\u6C99\u7BB1\u7F51\u7EDC\u672A\u5F00\u542F\uFF1A\u8BF7\u914D\u7F6E FUNCTIONS_FETCH_ALLOWLIST \u767D\u540D\u5355\u540E\u91CD\u542F\uFF08FN_FETCH_DISABLED\uFF09"
3765
+ },
3766
+ realtime: {
3767
+ code: "REALTIME_NOT_AVAILABLE",
3768
+ message: "\u5B9E\u65F6\u901A\u9053\u672A\u88C5\u914D\uFF1Arealtime \u57DF\u672A\u88C5\u8F7D\uFF08\u68C0\u67E5\u90E8\u7F72\u5F62\u6001\u4E0E Redis \u914D\u7F6E\uFF09\uFF08REALTIME_NOT_AVAILABLE\uFF09"
3769
+ },
3770
+ kv: {
3771
+ code: "KV_NOT_PROVISIONED",
3772
+ message: "\u9879\u76EE KV \u5B58\u50A8\u672A\u53EF\u7528\uFF1Akv \u968F\u9879\u76EE\u6570\u636E\u5E93\u63D0\u4F9B\uFF0C\u8BF7\u5148\u542F\u52A8\u6570\u636E\u5E93\uFF08KV_NOT_PROVISIONED\uFF09"
3773
+ }
3774
+ };
3775
+ CapabilityNotRegisteredError = class extends Error {
3776
+ code;
3777
+ constructor(code, message) {
3778
+ super(message);
3779
+ this.code = code;
3780
+ this.name = "CapabilityNotRegisteredError";
3781
+ }
3782
+ };
3783
+ }
3784
+ });
3785
+
3786
+ // packages/runtime/src/functions/runtime/sandbox-fetch.ts
3787
+ function isHostAllowed(host, rules) {
3788
+ const h = host.toLocaleLowerCase();
3789
+ return rules.some((raw) => {
3790
+ const rule = raw.trim().toLocaleLowerCase();
3791
+ if (rule.startsWith("*.")) {
3792
+ const base = rule.slice(2);
3793
+ return h === base || h.endsWith(`.${base}`);
3794
+ }
3795
+ return h === rule;
3796
+ });
3797
+ }
3798
+ function headersToRecord(headers) {
3799
+ const out = {};
3800
+ if (headers === void 0 || headers === null) return out;
3801
+ if (typeof headers.forEach === "function") {
3802
+ ;
3803
+ headers.forEach((value, key) => {
3804
+ out[String(key).toLocaleLowerCase()] = String(value);
3805
+ });
3806
+ return out;
3807
+ }
3808
+ for (const [key, value] of Object.entries(headers)) {
3809
+ out[key.toLocaleLowerCase()] = String(value);
3810
+ }
3811
+ return out;
3812
+ }
3813
+ function contentLength(res) {
3814
+ const headers = res.headers;
3815
+ if (headers === void 0 || headers === null) return null;
3816
+ if (typeof headers.get === "function") {
3817
+ const raw2 = headers.get?.("content-length");
3818
+ if (raw2 === void 0 || raw2 === null || raw2.trim() === "") return null;
3819
+ const n2 = Number(raw2);
3820
+ return Number.isFinite(n2) && n2 >= 0 ? n2 : null;
3821
+ }
3822
+ const record = headers;
3823
+ const raw = record["content-length"] ?? record["Content-Length"];
3824
+ if (raw === void 0 || raw === null) return null;
3825
+ const n = Number(raw);
3826
+ return Number.isFinite(n) && n >= 0 ? n : null;
3827
+ }
3828
+ function concatChunks(chunks, total) {
3829
+ const merged = new Uint8Array(total);
3830
+ let offset = 0;
3831
+ for (const chunk of chunks) {
3832
+ merged.set(chunk, offset);
3833
+ offset += chunk.byteLength;
3834
+ }
3835
+ return merged;
3836
+ }
3837
+ async function readBodyBytes(res, maxBytes) {
3838
+ if (maxBytes > 0) {
3839
+ const cl = contentLength(res);
3840
+ if (cl !== null && cl > maxBytes) throw TOO_LARGE;
3841
+ }
3842
+ const body = res.body;
3843
+ if (body !== void 0 && body !== null) {
3844
+ const reader = body.getReader();
3845
+ const chunks = [];
3846
+ let total = 0;
3847
+ for (; ; ) {
3848
+ const { done, value } = await reader.read();
3849
+ if (done) break;
3850
+ if (value !== void 0) {
3851
+ total += value.byteLength;
3852
+ if (maxBytes > 0 && total > maxBytes) throw TOO_LARGE;
3853
+ chunks.push(value);
3854
+ }
3855
+ }
3856
+ return concatChunks(chunks, total);
3857
+ }
3858
+ if (typeof res.arrayBuffer === "function") {
3859
+ const buffer = await res.arrayBuffer();
3860
+ const bytes2 = new Uint8Array(buffer);
3861
+ if (maxBytes > 0 && bytes2.byteLength > maxBytes) throw TOO_LARGE;
3862
+ return bytes2;
3863
+ }
3864
+ const text = await res.text();
3865
+ const bytes = encoder.encode(text);
3866
+ if (maxBytes > 0 && bytes.byteLength > maxBytes) throw TOO_LARGE;
3867
+ return bytes;
3868
+ }
3869
+ function errorMessageOf(error) {
3870
+ if (error instanceof Error) return error.message;
3871
+ return String(error);
3872
+ }
3873
+ function normalizeResponse(res, maxBytes) {
3874
+ let cached = null;
3875
+ let cachedPromise = null;
3876
+ const readCached = () => {
3877
+ if (cached !== null) return Promise.resolve(cached);
3878
+ cachedPromise ??= readBodyBytes(res, maxBytes).then((bytes) => {
3879
+ cached = bytes;
3880
+ return bytes;
3881
+ });
3882
+ return cachedPromise;
3883
+ };
3884
+ const read = () => readCached();
3885
+ return {
3886
+ ok: res.ok,
3887
+ status: res.status,
3888
+ statusText: res.statusText,
3889
+ headers: headersToRecord(res.headers),
3890
+ text: async () => decoder.decode(await read()),
3891
+ arrayBuffer: async () => bufferViewToArrayBuffer(await read()),
3892
+ json: async () => JSON.parse(decoder.decode(await read()))
3893
+ };
3894
+ }
3895
+ function bufferViewToArrayBuffer(bytes) {
3896
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
3897
+ }
3898
+ function createSandboxFetch(options) {
3899
+ const fetchImpl = options.fetchImpl ?? defaultFetch;
3900
+ const { allowlist, timeoutMs } = options;
3901
+ const maxBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
3902
+ return async (url, init) => {
3903
+ let parsed;
3904
+ try {
3905
+ parsed = new URL(url);
3906
+ } catch {
3907
+ throw new SandboxFetchError("FN_FETCH_INVALID_URL", `cloud.fetch \u6536\u5230\u975E\u6CD5 URL"${url}"`);
3908
+ }
3909
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw FORBIDDEN(url);
3910
+ if (!isHostAllowed(parsed.hostname, allowlist)) throw FORBIDDEN(url);
3911
+ const controller = new AbortController();
3912
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
3913
+ const signals = [controller.signal];
3914
+ if (init?.signal !== void 0) signals.push(init.signal);
3915
+ const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
3916
+ try {
3917
+ let res;
3918
+ try {
3919
+ res = await fetchImpl(url, { ...init, signal });
3920
+ } catch (error) {
3921
+ if (controller.signal.aborted) {
3922
+ throw new SandboxFetchError(
3923
+ "FN_FETCH_TIMEOUT",
3924
+ `cloud.fetch \u8BF7\u6C42\u8D85\u65F6\uFF08\u8D85\u8FC7 ${timeoutMs}ms\uFF09`
3925
+ );
3926
+ }
3927
+ if (init?.signal?.aborted === true) {
3928
+ throw new SandboxFetchError("FN_FETCH_ABORTED", "cloud.fetch \u8BF7\u6C42\u88AB\u8C03\u7528\u65B9\u4E2D\u6B62");
3929
+ }
3930
+ throw new SandboxFetchError(
3931
+ "FN_FETCH_FAILED",
3932
+ `cloud.fetch \u8BF7\u6C42\u5931\u8D25\uFF1A${errorMessageOf(error)}`
3933
+ );
3934
+ }
3935
+ return normalizeResponse(res, maxBytes);
3936
+ } finally {
3937
+ clearTimeout(timer);
3938
+ }
3939
+ };
3940
+ }
3941
+ var SandboxFetchError, DEFAULT_MAX_RESPONSE_BYTES, defaultFetch, FORBIDDEN, TOO_LARGE, encoder, decoder;
3942
+ var init_sandbox_fetch = __esm({
3943
+ "packages/runtime/src/functions/runtime/sandbox-fetch.ts"() {
3944
+ "use strict";
3945
+ SandboxFetchError = class extends Error {
3946
+ code;
3947
+ constructor(code, message) {
3948
+ super(message);
3949
+ this.name = "SandboxFetchError";
3950
+ this.code = code;
3951
+ }
3952
+ };
3953
+ DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
3954
+ defaultFetch = (url, init) => (
3955
+ // 真实 Response 与内部 ResponseLike 结构性一致;getReader 的多态签名差异属纯类型问题,运行语义等价。
3956
+ globalThis.fetch(url, init)
3957
+ );
3958
+ FORBIDDEN = (url) => new SandboxFetchError(
3959
+ "FN_FETCH_FORBIDDEN",
3960
+ `cloud.fetch \u62D2\u7EDD\u8BBF\u95EE "${url}"\uFF1A\u8BE5\u4E3B\u673A\u4E0D\u5728\u6C99\u7BB1\u7F51\u7EDC\u767D\u540D\u5355\u5185\uFF08FN_FETCH_FORBIDDEN\uFF09`
3961
+ );
3962
+ TOO_LARGE = new SandboxFetchError(
3963
+ "FN_FETCH_TOO_LARGE",
3964
+ "cloud.fetch \u54CD\u5E94\u4F53\u8D85\u8FC7\u4E0A\u9650\uFF08FN_FETCH_TOO_LARGE\uFF09"
3965
+ );
3966
+ encoder = new TextEncoder();
3967
+ decoder = new TextDecoder();
3968
+ }
3969
+ });
3970
+
3971
+ // packages/runtime/src/functions/runtime/rpc-key.ts
3972
+ var init_rpc_key = __esm({
3973
+ "packages/runtime/src/functions/runtime/rpc-key.ts"() {
3974
+ "use strict";
3975
+ init_capability_keys();
3976
+ }
3977
+ });
3978
+
3979
+ // packages/runtime/src/functions/runtime/chain.ts
3980
+ function isChainCapability(value) {
3981
+ if (typeof value !== "object" || value === null) return false;
3982
+ const spec = value[CHAIN_CAPABILITY_KEY];
3983
+ return typeof spec === "object" && spec !== null && Array.isArray(spec.stepMethods) && Array.isArray(spec.terminalMethods);
3984
+ }
3985
+ function createChainClient(capability, port, pending, nextId, spec) {
3986
+ const call = (method, args) => new Promise((resolve13, reject) => {
3987
+ const id = nextId();
3988
+ pending.set(id, { resolve: resolve13, reject });
3989
+ port.postMessage({ type: "rpc", id, capability, method, args });
3990
+ });
3991
+ const makeChainable = (rootArgs, steps, txId) => new Proxy(
3992
+ {},
3993
+ {
3994
+ get(_target, prop) {
3995
+ if (typeof prop !== "string") return void 0;
3996
+ if (spec.stepMethods.includes(prop)) {
3997
+ return (...args) => makeChainable(rootArgs, [...steps, { method: prop, args }], txId);
3998
+ }
3999
+ if (spec.terminalMethods.includes(prop)) {
4000
+ return (...args) => call(DB_RPC.chain, [
4001
+ {
4002
+ rootArgs,
4003
+ steps,
4004
+ terminal: prop,
4005
+ terminalArgs: args,
4006
+ ...txId === void 0 ? {} : { txId }
4007
+ }
4008
+ ]);
4009
+ }
4010
+ return void 0;
4011
+ }
4012
+ }
4013
+ );
4014
+ const makeRoot = (txId) => new Proxy(
4015
+ {},
4016
+ {
4017
+ get(_target, prop) {
4018
+ if (typeof prop !== "string") return void 0;
4019
+ if (prop === spec.rootMethod) {
4020
+ return (...rootArgs) => makeChainable(rootArgs, [], txId);
4021
+ }
4022
+ if (spec.directMethods.includes(prop)) {
4023
+ return (...args) => call(prop, args);
4024
+ }
4025
+ if (prop === spec.transactionMethod) {
4026
+ return (fn) => orchestrateTransaction(fn, txId);
4027
+ }
4028
+ return void 0;
4029
+ }
4030
+ }
4031
+ );
4032
+ const orchestrateTransaction = async (fn, _outerTxId) => {
4033
+ const txId = await call(DB_RPC.begin, []);
4034
+ const tx = makeRoot(txId);
4035
+ const settle = async (commit) => {
4036
+ await call(commit ? DB_RPC.commit : DB_RPC.rollback, [txId]).catch(() => void 0);
4037
+ };
4038
+ try {
4039
+ const result = await fn(tx);
4040
+ await settle(true);
4041
+ return result;
4042
+ } catch (error) {
4043
+ await settle(false);
4044
+ throw error;
4045
+ }
4046
+ };
4047
+ return makeRoot(void 0);
4048
+ }
4049
+ var init_chain = __esm({
4050
+ "packages/runtime/src/functions/runtime/chain.ts"() {
4051
+ "use strict";
4052
+ init_capability_keys();
4053
+ init_capability_keys();
4054
+ }
4055
+ });
4056
+
4057
+ // packages/runtime/src/functions/runtime/worker-entry.ts
4058
+ import { parentPort, workerData } from "node:worker_threads";
4059
+ import { createRequire as createRequire2 } from "node:module";
4060
+ import { join as join9 } from "node:path";
4061
+ function isRpcCapability(value) {
4062
+ return typeof value === "object" && value !== null && value[RPC_CAPABILITY_KEY] === true;
4063
+ }
4064
+ function createRpcClient(capability, port, pending, nextId) {
4065
+ return new Proxy(
4066
+ {},
4067
+ {
4068
+ get(_target, method) {
4069
+ if (typeof method !== "string") return void 0;
4070
+ return (...args) => {
4071
+ const id = nextId();
4072
+ return new Promise((resolve13, reject) => {
4073
+ pending.set(id, { resolve: resolve13, reject });
4074
+ port.postMessage({ type: "rpc", id, capability, method, args });
4075
+ });
4076
+ };
4077
+ }
4078
+ }
4079
+ );
4080
+ }
4081
+ function errorMessageOf2(error) {
4082
+ if (error instanceof Error) return error.message;
4083
+ if (typeof error === "object" && error !== null && "message" in error) {
4084
+ const message = error.message;
4085
+ if (typeof message === "string") return message;
4086
+ }
4087
+ return String(error);
4088
+ }
4089
+ function escapeRegExp2(text) {
4090
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4091
+ }
4092
+ function firstUserFrame(stack, files) {
4093
+ for (const key of Object.keys(files)) {
4094
+ const match = new RegExp(
4095
+ `(?<![\\w$/.])${escapeRegExp2(key)}:(\\d+)(?::(\\d+))?(?::(\\d+))?`
4096
+ ).exec(stack);
4097
+ if (match !== null) {
4098
+ return match[2] === void 0 ? `${key}:${match[1]}` : `${key}:${match[1]}:${match[2]}`;
4099
+ }
4100
+ }
4101
+ return void 0;
4102
+ }
4103
+ function errorMessageWithLocation(error, files) {
4104
+ const message = errorMessageOf2(error);
4105
+ const stack = error.stack;
4106
+ if (typeof stack !== "string") return message;
4107
+ const frame = firstUserFrame(stack, files);
4108
+ return frame === void 0 ? message : `${message}\uFF08${frame}\uFF09`;
4109
+ }
4110
+ function createBareResolver(deps) {
4111
+ const platformRequire = createRequire2(import.meta.url);
4112
+ const depsRequire = deps.dir === null ? null : createRequire2(join9(deps.dir, "__deps__.js"));
4113
+ return (request) => {
4114
+ if (deps.builtin.includes(request)) return platformRequire(request);
4115
+ const root = splitBareSpecifier(request);
4116
+ if (deps.builtin.includes(root)) return platformRequire(request);
4117
+ if (deps.custom.includes(root)) {
4118
+ if (depsRequire === null) {
4119
+ throw new Error(`\u4F9D\u8D56 "${root}" \u672A\u88C5\u8F7D\uFF1A\u9879\u76EE\u4F9D\u8D56\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u53D1\u5E03\u51FD\u6570\u89E6\u53D1\u4F9D\u8D56\u88C5\u8F7D`);
4120
+ }
4121
+ try {
4122
+ return depsRequire(request);
4123
+ } catch (error2) {
4124
+ const message = errorMessageOf2(error2);
4125
+ throw new Error(
4126
+ `\u4F9D\u8D56 "${request}" \u88C5\u8F7D\u5931\u8D25\uFF08\u76EE\u5F55 ${deps.dir}\uFF09\uFF1A\u8BF7\u91CD\u65B0\u53D1\u5E03\u51FD\u6570\u4EE5\u89E6\u53D1\u4F9D\u8D56\u5B89\u88C5\u3002\u539F\u56E0\uFF1A${message}`,
4127
+ { cause: error2 }
4128
+ );
4129
+ }
4130
+ }
4131
+ const error = new Error(
4132
+ `\u6C99\u7BB1\u62D2\u7EDD\u8BE5\u5F15\u7528\uFF1A"${request}"\u3002\u4EC5\u5141\u8BB8\u76F8\u5BF9\u8DEF\u5F84\u6587\u4EF6\u4E0E\u5DF2\u58F0\u660E\u7684\u4F9D\u8D56\uFF08\u5185\u7F6E\u767D\u540D\u5355\u6216 package.json\uFF09\uFF0C\u88F8\u6A21\u5757 "${root}" \u672A\u58F0\u660E\uFF08FN_SANDBOX_BUILTIN_BLOCKED\uFF09`
4133
+ );
4134
+ error.code = SANDBOX_BUILTIN_REJECTED;
4135
+ throw error;
4136
+ };
4137
+ }
4138
+ function runWorker(input, port) {
4139
+ const emit = (level, args) => {
4140
+ port.postMessage({ type: "log", level, message: args.map(String).join(" ") });
4141
+ };
4142
+ const forwardedConsole = {
4143
+ log: (...args) => emit("log", args),
4144
+ error: (...args) => emit("error", args),
4145
+ warn: (...args) => emit("warn", args)
4146
+ };
4147
+ const container = createCloudContainer();
4148
+ const pending = /* @__PURE__ */ new Map();
4149
+ let rpcId = 0;
4150
+ port.on?.((message) => {
4151
+ const reply = message;
4152
+ if (reply?.type !== "rpc-response" || typeof reply.id !== "number") return;
4153
+ const entry = pending.get(reply.id);
4154
+ if (entry === void 0) return;
4155
+ pending.delete(reply.id);
4156
+ if (reply.ok === true) entry.resolve(reply.result);
4157
+ else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
4158
+ });
4159
+ for (const capability of input.capabilities ?? []) {
4160
+ container.register(
4161
+ capability.name,
4162
+ isChainCapability(capability.value) ? createChainClient(
4163
+ capability.name,
4164
+ port,
4165
+ pending,
4166
+ () => ++rpcId,
4167
+ capability.value[CHAIN_CAPABILITY_KEY]
4168
+ ) : isRpcCapability(capability.value) ? createRpcClient(capability.name, port, pending, () => ++rpcId) : capability.value
4169
+ );
4170
+ }
4171
+ const sandboxGlobals = {
4172
+ console: forwardedConsole,
4173
+ // CF-015:Cloudflare Workers 代码重度依赖 Web 标准 API(URL / Request / Response /
4174
+ // Headers / 流 / 编码 / crypto 等)。Node 18+ 全局内置,直接注入 vm 上下文;
4175
+ // 与 @adep/cf-compat 的 Workers 适配(ctxToRequest / responseToEnvelopeBody)配套。
4176
+ URL,
4177
+ URLSearchParams,
4178
+ Request,
4179
+ Response,
4180
+ Headers,
4181
+ TextEncoder,
4182
+ TextDecoder,
4183
+ AbortController,
4184
+ AbortSignal,
4185
+ ReadableStream,
4186
+ WritableStream,
4187
+ TransformStream,
4188
+ Blob,
4189
+ FormData,
4190
+ crypto,
4191
+ performance,
4192
+ atob,
4193
+ btoa,
4194
+ structuredClone
4195
+ };
4196
+ if (input.env !== void 0) {
4197
+ sandboxGlobals["process"] = { env: input.env };
4198
+ }
4199
+ if (input.fetch !== void 0) {
4200
+ const sandboxFetch = createSandboxFetch({
4201
+ allowlist: input.fetch.allowlist,
4202
+ timeoutMs: input.fetch.timeoutMs,
4203
+ ...input.fetch.maxResponseBytes === void 0 ? {} : { maxResponseBytes: input.fetch.maxResponseBytes }
4204
+ });
4205
+ sandboxGlobals["fetch"] = sandboxFetch;
4206
+ container.register("fetch", sandboxFetch);
4207
+ }
4208
+ const ctx = {
4209
+ method: input.request.method,
4210
+ path: input.request.path,
4211
+ query: input.request.query,
4212
+ headers: input.request.headers,
4213
+ ...input.request.body === void 0 ? {} : { body: input.request.body },
4214
+ files: input.request.files ?? [],
4215
+ cloud: container.cloud,
4216
+ user: input.request.user ?? null,
4217
+ ...input.env === void 0 ? {} : { env: input.env }
4218
+ };
4219
+ try {
4220
+ const { handler } = loadFunctionModule(
4221
+ input.files,
4222
+ input.entry,
4223
+ sandboxGlobals,
4224
+ input.deps === void 0 ? void 0 : createBareResolver(input.deps)
4225
+ );
4226
+ const result = Promise.resolve(handler(ctx));
4227
+ void result.then(
4228
+ (value) => {
4229
+ port.postMessage({ type: "result", body: value === void 0 ? null : value });
4230
+ return void 0;
4231
+ },
4232
+ (error) => {
4233
+ port.postMessage({
4234
+ type: "error",
4235
+ message: errorMessageWithLocation(error, input.files),
4236
+ code: error.code,
4237
+ // FN-011:函数抛错可携带 status(4xx/5xx),透传给执行器落 ExecutorError.status。
4238
+ status: error.status
4239
+ });
4240
+ return void 0;
4241
+ }
4242
+ );
4243
+ } catch (error) {
4244
+ port.postMessage({
4245
+ type: "error",
4246
+ message: errorMessageWithLocation(error, input.files),
4247
+ code: error.code,
4248
+ status: error.status
4249
+ });
4250
+ }
4251
+ }
4252
+ var workerPort;
4253
+ var init_worker_entry = __esm({
4254
+ "packages/runtime/src/functions/runtime/worker-entry.ts"() {
4255
+ "use strict";
4256
+ init_cloud_container();
4257
+ init_sandbox();
4258
+ init_sandbox_fetch();
4259
+ init_rpc_key();
4260
+ init_chain();
4261
+ init_sandbox();
4262
+ init_manifest();
4263
+ workerPort = parentPort;
4264
+ if (workerPort !== null && workerData !== void 0) {
4265
+ const port = {
4266
+ // eslint-disable-next-line unicorn/require-post-message-target-origin -- node worker_threads 无 targetOrigin 语义
4267
+ postMessage: (message) => workerPort.postMessage(message),
4268
+ on: (listener) => {
4269
+ workerPort.on("message", (value) => listener(value));
4270
+ }
4271
+ };
4272
+ runWorker(workerData, port);
4273
+ }
2924
4274
  }
2925
4275
  });
2926
4276
 
@@ -2934,15 +4284,16 @@ __export(dev_exports, {
2934
4284
  });
2935
4285
  import { createServer } from "node:http";
2936
4286
  import { watch } from "node:fs";
2937
- import { mkdir as mkdir5, readdir as readdir2, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
2938
- import { basename, join as join8, resolve as resolve3 } from "node:path";
4287
+ import { mkdir as mkdir6, readdir as readdir3, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
4288
+ import { basename as basename2, join as join10, resolve as resolve4 } from "node:path";
2939
4289
  async function loadConfig(cwd) {
2940
- const name = basename(resolve3(cwd));
4290
+ const name = basename2(resolve4(cwd));
2941
4291
  const config = await loadAdepConfigModule(cwd);
2942
4292
  return {
2943
4293
  name: config?.name ?? name,
2944
4294
  functionsDir: config?.functionsDir ?? "functions",
2945
- functionsPrefix: config?.functions_prefix ?? ""
4295
+ functionsPrefix: config?.functions_prefix ?? "",
4296
+ ...config?.environment === void 0 ? {} : { environment: config.environment }
2946
4297
  };
2947
4298
  }
2948
4299
  function parseEnvFile(content) {
@@ -2963,17 +4314,17 @@ async function collectFunctions(dir) {
2963
4314
  const walk = async (sub, prefix) => {
2964
4315
  let entries;
2965
4316
  try {
2966
- entries = await readdir2(sub, { withFileTypes: true });
4317
+ entries = await readdir3(sub, { withFileTypes: true });
2967
4318
  } catch {
2968
4319
  return;
2969
4320
  }
2970
4321
  for (const entry of entries) {
2971
4322
  const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
2972
- const full = join8(sub, entry.name);
4323
+ const full = join10(sub, entry.name);
2973
4324
  if (entry.isDirectory()) {
2974
4325
  await walk(full, rel);
2975
4326
  } else if (entry.isFile() && entry.name.endsWith(".ts")) {
2976
- files[rel] = await readFile6(full, "utf8");
4327
+ files[rel] = await readFile7(full, "utf8");
2977
4328
  }
2978
4329
  }
2979
4330
  };
@@ -3036,25 +4387,27 @@ function printBoundaries(log) {
3036
4387
  }
3037
4388
  }
3038
4389
  async function ensureGitignore(cwd) {
3039
- const gitignorePath = join8(cwd, ".gitignore");
3040
- const existing = await readFile6(gitignorePath, "utf8").catch(() => "");
4390
+ const gitignorePath = join10(cwd, ".gitignore");
4391
+ const existing = await readFile7(gitignorePath, "utf8").catch(() => "");
3041
4392
  if (existing.split(/\r?\n/).includes(".adep/")) return;
3042
- await writeFile4(gitignorePath, `${existing.replace(/\n+$/, "")}
4393
+ await writeFile5(gitignorePath, `${existing.replace(/\n+$/, "")}
3043
4394
  .adep/
3044
4395
  `, "utf8");
3045
4396
  }
3046
4397
  async function startDevServer(options) {
3047
- const cwd = resolve3(options.cwd);
4398
+ const cwd = resolve4(options.cwd);
3048
4399
  const log = options.log ?? ((line) => process.stdout.write(`${line}
3049
4400
  `));
3050
4401
  const config = await loadConfig(cwd);
3051
4402
  if (options.prefix !== void 0) {
3052
4403
  config.functionsPrefix = options.prefix.replace(/^\/+|\/+$/g, "");
3053
4404
  }
3054
- const functionsDir = join8(cwd, config.functionsDir);
4405
+ const functionsDir = join10(cwd, config.functionsDir);
3055
4406
  const coldStartAt = Date.now();
3056
- const executor = new WorkerFunctionExecutor();
3057
- await mkdir5(functionsDir, { recursive: true });
4407
+ const executor = new WorkerFunctionExecutor({
4408
+ deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
4409
+ });
4410
+ await mkdir6(functionsDir, { recursive: true });
3058
4411
  const runtime = await createSimRuntime({
3059
4412
  cwd,
3060
4413
  projectId: "local",
@@ -3063,19 +4416,91 @@ async function startDevServer(options) {
3063
4416
  });
3064
4417
  await ensureGitignore(cwd);
3065
4418
  let files = await collectFunctions(functionsDir);
3066
- let env = await loadSimEnv(cwd).catch(() => ({}));
4419
+ let env = {
4420
+ ...config.environment,
4421
+ ...await loadSimEnv(cwd).catch(() => ({}))
4422
+ };
3067
4423
  const dbBundle = runtime.bundle;
3068
4424
  const invokeHandler = createSimInvokeHandler({ executor, files });
4425
+ let stateRuntime = null;
4426
+ let stateFingerprint = "";
4427
+ const bareResolver = createBareResolver({
4428
+ dir: null,
4429
+ builtin: [...LOCAL_BUILTIN_DEPS],
4430
+ custom: []
4431
+ });
4432
+ const collectStateDeclarations = () => {
4433
+ const declared = [];
4434
+ const dirs = /* @__PURE__ */ new Set();
4435
+ for (const path of Object.keys(files)) {
4436
+ if (path === STATE_OBJECTS_ENTRY || path.endsWith(`/${STATE_OBJECTS_ENTRY}`)) {
4437
+ dirs.add(path === STATE_OBJECTS_ENTRY ? "" : path.slice(0, -STATE_OBJECTS_ENTRY.length - 1));
4438
+ }
4439
+ }
4440
+ for (const dir of dirs) {
4441
+ const prefix = dir.length === 0 ? "" : `${dir}/`;
4442
+ const fileMap = {};
4443
+ for (const [path, content] of Object.entries(files)) {
4444
+ if (path.startsWith(prefix)) fileMap[path] = content;
4445
+ }
4446
+ declared.push({ dir, files: fileMap });
4447
+ }
4448
+ return declared;
4449
+ };
4450
+ const stateObjectBareResolver = (request) => {
4451
+ const state = resolveStateObjectSpecifier(request);
4452
+ if (state !== void 0) return state;
4453
+ return bareResolver(request);
4454
+ };
4455
+ const refreshStateRuntime = () => {
4456
+ const declarations = collectStateDeclarations();
4457
+ const fingerprint = declarations.map(
4458
+ (d) => `${d.dir}\0${d.files[`${d.dir === "" ? "" : `${d.dir}/`}${STATE_OBJECTS_ENTRY}`] ?? ""}`
4459
+ ).join("");
4460
+ if (stateRuntime !== null && stateFingerprint === fingerprint) return stateRuntime;
4461
+ stateRuntime = new StateObjectRuntime(createProjectDriverStateBackend(runtime.db.driver));
4462
+ stateRuntime.define(DemoCounter);
4463
+ stateRuntime.define(DemoChatRoom);
4464
+ for (const d of declarations) {
4465
+ const loaded = loadStateObjectClasses(
4466
+ d.files,
4467
+ `${d.dir === "" ? "" : `${d.dir}/`}${STATE_OBJECTS_ENTRY}`,
4468
+ {
4469
+ resolveBare: stateObjectBareResolver
4470
+ }
4471
+ );
4472
+ for (const cls of loaded) stateRuntime.define(cls);
4473
+ }
4474
+ stateFingerprint = fingerprint;
4475
+ return stateRuntime;
4476
+ };
4477
+ let stateAlarmTimer;
4478
+ const startStateAlarmScheduler = () => {
4479
+ if (stateAlarmTimer !== void 0) return;
4480
+ stateAlarmTimer = setInterval(() => {
4481
+ void refreshStateRuntime().pump(Date.now()).catch((error) => {
4482
+ log(
4483
+ `[adep] \u72B6\u6001\u5BF9\u8C61 alarm tick \u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`
4484
+ );
4485
+ });
4486
+ }, options.stateAlarmTickMs ?? 1e3);
4487
+ stateAlarmTimer.unref?.();
4488
+ };
4489
+ const stopStateAlarmScheduler = () => {
4490
+ if (stateAlarmTimer === void 0) return;
4491
+ clearInterval(stateAlarmTimer);
4492
+ stateAlarmTimer = void 0;
4493
+ };
3069
4494
  const reload = async () => {
3070
4495
  const [nextFiles, envText2] = await Promise.all([
3071
4496
  collectFunctions(functionsDir),
3072
- readFile6(join8(cwd, ".env.local"), "utf8").catch(() => "")
4497
+ readFile7(join10(cwd, ".env.local"), "utf8").catch(() => "")
3073
4498
  ]);
3074
4499
  files = nextFiles;
3075
- env = parseEnvFile(envText2);
4500
+ env = { ...config.environment, ...parseEnvFile(envText2) };
3076
4501
  };
3077
- const envText = await readFile6(join8(cwd, ".env.local"), "utf8").catch(() => "");
3078
- env = parseEnvFile(envText);
4502
+ const envText = await readFile7(join10(cwd, ".env.local"), "utf8").catch(() => "");
4503
+ env = { ...config.environment, ...parseEnvFile(envText) };
3079
4504
  let debounceTimer;
3080
4505
  let watcher;
3081
4506
  try {
@@ -3135,6 +4560,43 @@ async function startDevServer(options) {
3135
4560
  });
3136
4561
  return;
3137
4562
  }
4563
+ if (fnName === "state") {
4564
+ const normalizedPrefix = config.functionsPrefix.replace(/^\/+|\/+$/g, "");
4565
+ const rest = normalizedPrefix.length === 0 ? url.pathname : url.pathname.replace(new RegExp(`^/${normalizedPrefix}`), "");
4566
+ const parsed = parseStatePath(rest);
4567
+ if (parsed === null) {
4568
+ writeJson(res, 400, {
4569
+ error: { code: "STATE_BAD_PATH", message: "\u72B6\u6001\u5BF9\u8C61\u8DEF\u5F84\uFF1A/api/state/:type/:id/:method" }
4570
+ });
4571
+ return;
4572
+ }
4573
+ const rawBody = await bodyOf(req);
4574
+ const parsedBody = parseStateBody(
4575
+ req.method === "GET" || req.method === "HEAD" ? null : rawBody === void 0 ? null : typeof rawBody === "string" ? rawBody : JSON.stringify(rawBody)
4576
+ );
4577
+ if ("error" in parsedBody) {
4578
+ writeJson(res, 400, { error: { code: "STATE_BAD_ARGS", message: parsedBody.error } });
4579
+ return;
4580
+ }
4581
+ try {
4582
+ const result = await refreshStateRuntime().invoke(
4583
+ parsed.type,
4584
+ parsed.id,
4585
+ parsed.method,
4586
+ parsedBody.args
4587
+ );
4588
+ writeJson(res, 200, { ok: true, data: result });
4589
+ } catch (error) {
4590
+ if (error instanceof StateObjectError) {
4591
+ writeJson(res, error.code === "STATE_TYPE_NOT_REGISTERED" ? 404 : 400, {
4592
+ error: { code: error.code, message: error.message }
4593
+ });
4594
+ return;
4595
+ }
4596
+ writeJson(res, 500, { error: { code: "STATE_INVOKE_ERROR", message: String(error) } });
4597
+ }
4598
+ return;
4599
+ }
3138
4600
  const entry = resolveFunctionEntry(files, fnName);
3139
4601
  if (entry === void 0) {
3140
4602
  log(`[adep] ${req.method ?? "GET"} /${fnName} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
@@ -3146,8 +4608,15 @@ async function startDevServer(options) {
3146
4608
  try {
3147
4609
  const result = await executor.execute(input);
3148
4610
  const durationMs = Math.round(performance.now() - startedAt);
3149
- log(`[adep] ${req.method ?? "GET"} /${fnName} -> 200 ${durationMs}ms`);
3150
4611
  for (const line of result.logs) log(`[adep] ${line}`);
4612
+ if (isAdepHttpEnvelope(result.body)) {
4613
+ log(
4614
+ `[adep] ${req.method ?? "GET"} /${fnName} -> ${result.body.__adepHttp.status} ${durationMs}ms`
4615
+ );
4616
+ writeEnvelopeResponse(res, result.body);
4617
+ return;
4618
+ }
4619
+ log(`[adep] ${req.method ?? "GET"} /${fnName} -> 200 ${durationMs}ms`);
3151
4620
  writeJson(res, 200, result.body === void 0 ? null : result.body);
3152
4621
  } catch (error) {
3153
4622
  const durationMs = Math.round(performance.now() - startedAt);
@@ -3205,10 +4674,12 @@ async function startDevServer(options) {
3205
4674
  log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
3206
4675
  printBoundaries(log);
3207
4676
  log(`[adep] \u6A21\u62DF\u6570\u636E\u76EE\u5F55\uFF1A${simDir(cwd)}`);
4677
+ startStateAlarmScheduler();
3208
4678
  return {
3209
4679
  port: actualPort,
3210
4680
  baseUrl,
3211
4681
  close: async () => {
4682
+ stopStateAlarmScheduler();
3212
4683
  if (debounceTimer !== void 0) clearTimeout(debounceTimer);
3213
4684
  watcher?.close();
3214
4685
  await new Promise((resolveClose) => server.close(() => resolveClose()));
@@ -3221,12 +4692,16 @@ var init_dev = __esm({
3221
4692
  "packages/cli/src/dev.ts"() {
3222
4693
  "use strict";
3223
4694
  init_executor();
4695
+ init_http_envelope();
3224
4696
  init_worker_executor();
3225
4697
  init_runtime();
3226
4698
  init_env();
3227
4699
  init_invoke();
4700
+ init_builtin_deps();
3228
4701
  init_boundary();
3229
4702
  init_ts_config();
4703
+ init_state_objects();
4704
+ init_worker_entry();
3230
4705
  }
3231
4706
  });
3232
4707
 
@@ -3302,8 +4777,8 @@ __export(server_exports, {
3302
4777
  });
3303
4778
  import { createServer as createServer2 } from "node:http";
3304
4779
  import { watch as watch2 } from "node:fs";
3305
- import { mkdir as mkdir6, readdir as readdir3, readFile as readFile7, stat as stat5 } from "node:fs/promises";
3306
- import { join as join9, relative, resolve as resolve4 } from "node:path";
4780
+ import { mkdir as mkdir7, readdir as readdir4, readFile as readFile8, stat as stat6 } from "node:fs/promises";
4781
+ import { join as join11, relative as relative2, resolve as resolve5 } from "node:path";
3307
4782
  function envNumber(name) {
3308
4783
  const raw = process.env[name];
3309
4784
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -3319,17 +4794,17 @@ async function collectFunctions2(dir) {
3319
4794
  const walk = async (sub, prefix) => {
3320
4795
  let entries;
3321
4796
  try {
3322
- entries = await readdir3(sub, { withFileTypes: true });
4797
+ entries = await readdir4(sub, { withFileTypes: true });
3323
4798
  } catch {
3324
4799
  return;
3325
4800
  }
3326
4801
  for (const entry of entries) {
3327
4802
  const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
3328
- const full = join9(sub, entry.name);
4803
+ const full = join11(sub, entry.name);
3329
4804
  if (entry.isDirectory()) {
3330
4805
  await walk(full, rel);
3331
4806
  } else if (entry.isFile() && entry.name.endsWith(".ts")) {
3332
- files[rel] = await readFile7(full, "utf8");
4807
+ files[rel] = await readFile8(full, "utf8");
3333
4808
  }
3334
4809
  }
3335
4810
  };
@@ -3364,27 +4839,27 @@ function contentTypeFor(path) {
3364
4839
  return MIME_TYPES[ext] ?? "application/octet-stream";
3365
4840
  }
3366
4841
  async function startServeServer(options) {
3367
- const cwd = resolve4(options.cwd);
4842
+ const cwd = resolve5(options.cwd);
3368
4843
  const log = options.log ?? ((line) => process.stdout.write(`${line}
3369
4844
  `));
3370
4845
  const host = options.host ?? envString("HOST") ?? "127.0.0.1";
3371
4846
  const port = options.port ?? envNumber("PORT") ?? 8787;
3372
- const staticDir = resolve4(
4847
+ const staticDir = resolve5(
3373
4848
  cwd,
3374
4849
  options.staticDir ?? envString("ADEP_SERVE_STATIC_DIR") ?? "public"
3375
4850
  );
3376
4851
  const config = await loadConfig(cwd);
3377
- const functionsDir = join9(cwd, config.functionsDir);
4852
+ const functionsDir = join11(cwd, config.functionsDir);
3378
4853
  let hasStatic = false;
3379
4854
  try {
3380
- const publicStat = await stat5(staticDir);
4855
+ const publicStat = await stat6(staticDir);
3381
4856
  hasStatic = publicStat.isDirectory();
3382
4857
  } catch {
3383
4858
  hasStatic = false;
3384
4859
  }
3385
4860
  let files = await collectFunctions2(functionsDir);
3386
4861
  let functionNames = listFunctionNames(files);
3387
- const envText = await readFile7(join9(cwd, ".env.local"), "utf8").catch(() => "");
4862
+ const envText = await readFile8(join11(cwd, ".env.local"), "utf8").catch(() => "");
3388
4863
  let env = parseEnvFile(envText);
3389
4864
  let simEnv = await loadSimEnv(cwd).catch(() => ({}));
3390
4865
  const runtime = await createSimRuntime({
@@ -3393,7 +4868,9 @@ async function startServeServer(options) {
3393
4868
  baseUrl: `http://${host}:${port}`,
3394
4869
  log
3395
4870
  });
3396
- const executor = new WorkerFunctionExecutor();
4871
+ const executor = new WorkerFunctionExecutor({
4872
+ deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
4873
+ });
3397
4874
  const dbBundle = runtime.bundle;
3398
4875
  let invokeHandler = createSimInvokeHandler({ executor, files });
3399
4876
  let stopWatch;
@@ -3401,7 +4878,7 @@ async function startServeServer(options) {
3401
4878
  const reload = async () => {
3402
4879
  const [nextFiles, envLocalText] = await Promise.all([
3403
4880
  collectFunctions2(functionsDir),
3404
- readFile7(join9(cwd, ".env.local"), "utf8").catch(() => "")
4881
+ readFile8(join11(cwd, ".env.local"), "utf8").catch(() => "")
3405
4882
  ]);
3406
4883
  files = nextFiles;
3407
4884
  env = parseEnvFile(envLocalText);
@@ -3418,7 +4895,7 @@ async function startServeServer(options) {
3418
4895
  void reload();
3419
4896
  }, 120);
3420
4897
  };
3421
- await mkdir6(functionsDir, { recursive: true }).catch(() => void 0);
4898
+ await mkdir7(functionsDir, { recursive: true }).catch(() => void 0);
3422
4899
  try {
3423
4900
  watchers.push(watch2(functionsDir, { recursive: true }, scheduleReload));
3424
4901
  } catch {
@@ -3444,8 +4921,8 @@ async function startServeServer(options) {
3444
4921
  if (typeof value === "string") headers[key] = value;
3445
4922
  }
3446
4923
  const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await bodyOf2(req);
3447
- const hasEnv = Object.keys(env).length > 0 || Object.keys(simEnv).length > 0;
3448
- const mergedEnv = { ...simEnv, ...env };
4924
+ const hasEnv = Object.keys(env).length > 0 || Object.keys(simEnv).length > 0 || Object.keys(config.environment ?? {}).length > 0;
4925
+ const mergedEnv = { ...config.environment, ...simEnv, ...env };
3449
4926
  return {
3450
4927
  project: { id: "local", slug: config.name },
3451
4928
  fn: { id: fnName, name: fnName },
@@ -3470,16 +4947,16 @@ async function startServeServer(options) {
3470
4947
  const serveStatic = async (pathname, res) => {
3471
4948
  if (!hasStatic) return false;
3472
4949
  const safePath = pathname.replace(/\.\.\//g, "").replace(/^\//, "");
3473
- const filePath = join9(staticDir, safePath);
3474
- const resolvedPath = safePath === "" || safePath === "/" ? join9(filePath, "index.html") : filePath;
4950
+ const filePath = join11(staticDir, safePath);
4951
+ const resolvedPath = safePath === "" || safePath === "/" ? join11(filePath, "index.html") : filePath;
3475
4952
  try {
3476
- const fileStat = await stat5(resolvedPath);
4953
+ const fileStat = await stat6(resolvedPath);
3477
4954
  if (fileStat.isDirectory()) {
3478
- const indexPath = join9(resolvedPath, "index.html");
4955
+ const indexPath = join11(resolvedPath, "index.html");
3479
4956
  try {
3480
- const indexStat = await stat5(indexPath);
4957
+ const indexStat = await stat6(indexPath);
3481
4958
  if (indexStat.isFile()) {
3482
- const content2 = await readFile7(indexPath);
4959
+ const content2 = await readFile8(indexPath);
3483
4960
  res.writeHead(200, { "content-type": contentTypeFor(indexPath) });
3484
4961
  res.end(content2);
3485
4962
  return true;
@@ -3488,7 +4965,7 @@ async function startServeServer(options) {
3488
4965
  }
3489
4966
  return false;
3490
4967
  }
3491
- const content = await readFile7(resolvedPath);
4968
+ const content = await readFile8(resolvedPath);
3492
4969
  res.writeHead(200, { "content-type": contentTypeFor(resolvedPath) });
3493
4970
  res.end(content);
3494
4971
  return true;
@@ -3523,10 +5000,17 @@ async function startServeServer(options) {
3523
5000
  try {
3524
5001
  const result = await executor.execute(input);
3525
5002
  const durationMs = Math.round(performance.now() - startedAt);
3526
- log(`[serve] ${req.method ?? "GET"} ${pathname} -> 200 ${durationMs}ms`);
3527
5003
  if (options.watch === true) {
3528
5004
  for (const line of result.logs) log(`[serve] ${line}`);
3529
5005
  }
5006
+ if (isAdepHttpEnvelope(result.body)) {
5007
+ log(
5008
+ `[serve] ${req.method ?? "GET"} ${pathname} -> ${result.body.__adepHttp.status} ${durationMs}ms`
5009
+ );
5010
+ writeEnvelopeResponse(res, result.body);
5011
+ return;
5012
+ }
5013
+ log(`[serve] ${req.method ?? "GET"} ${pathname} -> 200 ${durationMs}ms`);
3530
5014
  writeJson2(res, 200, result.body === void 0 ? null : result.body);
3531
5015
  } catch (error) {
3532
5016
  const durationMs = Math.round(performance.now() - startedAt);
@@ -3602,7 +5086,7 @@ async function startServeServer(options) {
3602
5086
  functions: functionNames,
3603
5087
  functionsPrefix: config.functionsPrefix,
3604
5088
  hasStatic,
3605
- staticDir: relative(cwd, staticDir).length > 0 ? relative(cwd, staticDir) : staticDir
5089
+ staticDir: relative2(cwd, staticDir).length > 0 ? relative2(cwd, staticDir) : staticDir
3606
5090
  });
3607
5091
  log(banner);
3608
5092
  if (options.watch === true) {
@@ -3625,7 +5109,9 @@ var init_server = __esm({
3625
5109
  "packages/cli/src/serve/server.ts"() {
3626
5110
  "use strict";
3627
5111
  init_executor();
5112
+ init_http_envelope();
3628
5113
  init_worker_executor();
5114
+ init_builtin_deps();
3629
5115
  init_runtime();
3630
5116
  init_env();
3631
5117
  init_invoke();
@@ -3763,8 +5249,8 @@ __export(deploy_exports, {
3763
5249
  deploy: () => deploy
3764
5250
  });
3765
5251
  import { createHash as createHash2 } from "node:crypto";
3766
- import { readdir as readdir4, readFile as readFile8 } from "node:fs/promises";
3767
- import { join as join10, resolve as resolve5, basename as basename2 } from "node:path";
5252
+ import { readdir as readdir5, readFile as readFile9 } from "node:fs/promises";
5253
+ import { join as join12, resolve as resolve6, basename as basename3 } from "node:path";
3768
5254
  function functionUrlBase(prefix) {
3769
5255
  const raw = (prefix ?? "/api").trim();
3770
5256
  const normalized = raw === "/" ? "/" : raw.replace(/\/+$/, "");
@@ -3774,13 +5260,13 @@ async function collectEntries(functionsDir) {
3774
5260
  const entries = {};
3775
5261
  let names;
3776
5262
  try {
3777
- const dirents = await readdir4(functionsDir, { withFileTypes: true });
3778
- names = dirents.filter((entry) => entry.isFile() && entry.name.endsWith(".ts")).map((entry) => basename2(entry.name, ".ts")).toSorted();
5263
+ const dirents = await readdir5(functionsDir, { withFileTypes: true });
5264
+ names = dirents.filter((entry) => entry.isFile() && entry.name.endsWith(".ts")).map((entry) => basename3(entry.name, ".ts")).toSorted();
3779
5265
  } catch {
3780
5266
  return entries;
3781
5267
  }
3782
5268
  for (const name of names) {
3783
- entries[name] = await readFile8(join10(functionsDir, `${name}.ts`), "utf8");
5269
+ entries[name] = await readFile9(join12(functionsDir, `${name}.ts`), "utf8");
3784
5270
  }
3785
5271
  return entries;
3786
5272
  }
@@ -3792,10 +5278,10 @@ async function deploy(paths, options) {
3792
5278
  const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
3793
5279
  `));
3794
5280
  const client = await createClient(paths);
3795
- const cwd = resolve5(options.cwd);
5281
+ const cwd = resolve6(options.cwd);
3796
5282
  const config = await loadConfig(cwd);
3797
5283
  const slug = options.slug ?? config.name;
3798
- const functionsDir = options.functionsDir === void 0 ? join10(cwd, config.functionsDir) : resolve5(cwd, options.functionsDir);
5284
+ const functionsDir = options.functionsDir === void 0 ? join12(cwd, config.functionsDir) : resolve6(cwd, options.functionsDir);
3799
5285
  const local = await collectEntries(functionsDir);
3800
5286
  if (Object.keys(local).length === 0) {
3801
5287
  throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
@@ -3878,7 +5364,7 @@ var client_exports2 = {};
3878
5364
  __export(client_exports2, {
3879
5365
  createExportApiClient: () => createExportApiClient
3880
5366
  });
3881
- import { writeFile as writeFile5 } from "node:fs/promises";
5367
+ import { writeFile as writeFile6 } from "node:fs/promises";
3882
5368
  function toExportJob(view) {
3883
5369
  return {
3884
5370
  id: view.id,
@@ -3929,7 +5415,7 @@ async function createExportApiClient(paths) {
3929
5415
  }
3930
5416
  const response = await client.download(download.downloadUrl, "EXPORT_DOWNLOAD_FAILED");
3931
5417
  const bytes = Buffer.from(await response.arrayBuffer());
3932
- await writeFile5(outputPath, bytes);
5418
+ await writeFile6(outputPath, bytes);
3933
5419
  return { path: outputPath, size: bytes.length };
3934
5420
  }
3935
5421
  };
@@ -3949,7 +5435,7 @@ function zipRead(buf) {
3949
5435
  if (eocd < 0) throw new ZipFormatError("\u627E\u4E0D\u5230 EOCD \u7B7E\u540D");
3950
5436
  const total = r.u16(eocd + 10);
3951
5437
  const centralOffset = r.u32(eocd + 16);
3952
- const decoder = new TextDecoder();
5438
+ const decoder2 = new TextDecoder();
3953
5439
  const out = /* @__PURE__ */ new Map();
3954
5440
  let cursor = centralOffset;
3955
5441
  for (let i = 0; i < total; i++) {
@@ -3963,7 +5449,7 @@ function zipRead(buf) {
3963
5449
  const commentLen = r.u16(cursor + 32);
3964
5450
  const localHeaderOffset = r.u32(cursor + 42);
3965
5451
  if (localHeaderOffset + 30 > buf.length) throw new ZipFormatError("\u672C\u5730\u5934\u504F\u79FB\u8D8A\u754C");
3966
- const name = decoder.decode(r.slice(cursor + 46, nameLen));
5452
+ const name = decoder2.decode(r.slice(cursor + 46, nameLen));
3967
5453
  const localNameLen = r.u16(localHeaderOffset + 26);
3968
5454
  const localExtraLen = r.u16(localHeaderOffset + 28);
3969
5455
  const dataStart = localHeaderOffset + 30 + localNameLen + localExtraLen;
@@ -4026,33 +5512,33 @@ var fs_exports = {};
4026
5512
  __export(fs_exports, {
4027
5513
  createExportFileSystem: () => createExportFileSystem
4028
5514
  });
4029
- import { mkdir as mkdir7, readFile as readFile9, rm as rm3, stat as stat6, writeFile as writeFile6 } from "node:fs/promises";
4030
- import { dirname as dirname6, join as join11 } from "node:path";
5515
+ import { mkdir as mkdir8, readFile as readFile10, rm as rm3, stat as stat7, writeFile as writeFile7 } from "node:fs/promises";
5516
+ import { dirname as dirname7, join as join13 } from "node:path";
4031
5517
  function createExportFileSystem() {
4032
5518
  return {
4033
- readFile: (path) => readFile9(path),
4034
- writeFile: (path, content) => writeFile6(path, content),
5519
+ readFile: (path) => readFile10(path),
5520
+ writeFile: (path, content) => writeFile7(path, content),
4035
5521
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
4036
5522
  deleteFile: async (path) => {
4037
5523
  await rm3(path, { recursive: true, force: true });
4038
5524
  },
4039
5525
  fileExists: async (path) => {
4040
5526
  try {
4041
- await stat6(path);
5527
+ await stat7(path);
4042
5528
  return true;
4043
5529
  } catch {
4044
5530
  return false;
4045
5531
  }
4046
5532
  },
4047
5533
  mkdir: async (path) => {
4048
- await mkdir7(path, { recursive: true });
5534
+ await mkdir8(path, { recursive: true });
4049
5535
  },
4050
5536
  unzip: async (zipPath, targetDir) => {
4051
- const entries = zipRead(await readFile9(zipPath));
5537
+ const entries = zipRead(await readFile10(zipPath));
4052
5538
  for (const [name, data] of entries) {
4053
- const dest = join11(targetDir, name);
4054
- await mkdir7(dirname6(dest), { recursive: true });
4055
- await writeFile6(dest, data);
5539
+ const dest = join13(targetDir, name);
5540
+ await mkdir8(dirname7(dest), { recursive: true });
5541
+ await writeFile7(dest, data);
4056
5542
  }
4057
5543
  }
4058
5544
  };
@@ -4553,7 +6039,7 @@ ${detail}`);
4553
6039
  * @param ms 毫秒数
4554
6040
  */
4555
6041
  sleep(ms) {
4556
- return new Promise((resolve12) => setTimeout(resolve12, ms));
6042
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
4557
6043
  }
4558
6044
  };
4559
6045
  }
@@ -4571,10 +6057,10 @@ __export(db_exports, {
4571
6057
  dbStatus: () => dbStatus,
4572
6058
  dbStop: () => dbStop
4573
6059
  });
4574
- import { resolve as resolve7 } from "node:path";
6060
+ import { resolve as resolve8 } from "node:path";
4575
6061
  async function open2(paths, options) {
4576
6062
  const client = await createClient(paths);
4577
- const project2 = await resolveSlug(resolve7(options.cwd), options.slug);
6063
+ const project2 = await resolveSlug(resolve8(options.cwd), options.slug);
4578
6064
  return { client, project: project2 };
4579
6065
  }
4580
6066
  async function dbStart(paths, options) {
@@ -4648,11 +6134,11 @@ __export(storage_exports, {
4648
6134
  storageRemove: () => storageRemove,
4649
6135
  storageUpload: () => storageUpload
4650
6136
  });
4651
- import { mkdir as mkdir8, readFile as readFile10, stat as stat7, writeFile as writeFile7 } from "node:fs/promises";
4652
- import { basename as basename3, dirname as dirname7, extname, join as join12, resolve as resolve8 } from "node:path";
6137
+ import { mkdir as mkdir9, readFile as readFile11, stat as stat8, writeFile as writeFile8 } from "node:fs/promises";
6138
+ import { basename as basename4, dirname as dirname8, extname, join as join14, resolve as resolve9 } from "node:path";
4653
6139
  async function open3(paths, options) {
4654
6140
  const client = await createClient(paths);
4655
- const project2 = await resolveSlug(resolve8(options.cwd), options.slug);
6141
+ const project2 = await resolveSlug(resolve9(options.cwd), options.slug);
4656
6142
  return { client, project: project2 };
4657
6143
  }
4658
6144
  function contentTypeOf(path) {
@@ -4685,20 +6171,20 @@ function contentTypeOf(path) {
4685
6171
  }
4686
6172
  async function storageUpload(paths, options) {
4687
6173
  const { client, project: project2 } = await open3(paths, options);
4688
- const local = resolve8(options.file);
4689
- const info = await stat7(local).catch(() => null);
6174
+ const local = resolve9(options.file);
6175
+ const info = await stat8(local).catch(() => null);
4690
6176
  if (info === null || !info.isFile()) {
4691
6177
  throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
4692
6178
  }
4693
6179
  const visibility = options.visibility ?? "private";
4694
- const bytes = await readFile10(local);
6180
+ const bytes = await readFile11(local);
4695
6181
  const form = new FormData();
4696
6182
  form.set("path", options.path);
4697
6183
  form.set("visibility", visibility);
4698
6184
  form.set(
4699
6185
  "file",
4700
6186
  new Blob([bytes], { type: contentTypeOf(options.path) }),
4701
- basename3(local)
6187
+ basename4(local)
4702
6188
  );
4703
6189
  const response = await client.upload(
4704
6190
  `/api/v1/projects/${project2}/files`,
@@ -4732,9 +6218,9 @@ async function storageDownload(paths, options) {
4732
6218
  const url = await resolveDownloadUrl(client, project2, options.path);
4733
6219
  const response = await client.download(url, "STORAGE_DOWNLOAD_FAILED");
4734
6220
  const bytes = Buffer.from(await response.arrayBuffer());
4735
- const output = resolve8(options.output ?? join12(resolve8(options.cwd), basename3(options.path)));
4736
- await mkdir8(dirname7(output), { recursive: true });
4737
- await writeFile7(output, bytes);
6221
+ const output = resolve9(options.output ?? join14(resolve9(options.cwd), basename4(options.path)));
6222
+ await mkdir9(dirname8(output), { recursive: true });
6223
+ await writeFile8(output, bytes);
4738
6224
  return { path: options.path, output, size: bytes.length };
4739
6225
  }
4740
6226
  async function storageRemove(paths, options) {
@@ -4758,7 +6244,7 @@ __export(doctor_exports, {
4758
6244
  formatDoctorReport: () => formatDoctorReport,
4759
6245
  runDoctor: () => runDoctor
4760
6246
  });
4761
- import { stat as stat8 } from "node:fs/promises";
6247
+ import { stat as stat9 } from "node:fs/promises";
4762
6248
  async function probeServer(server) {
4763
6249
  const controller = new AbortController();
4764
6250
  const timer = setTimeout(() => controller.abort(), SERVER_PROBE_TIMEOUT_MS);
@@ -4776,7 +6262,7 @@ async function probeServer(server) {
4776
6262
  }
4777
6263
  async function credentialMode(file) {
4778
6264
  try {
4779
- const info = await stat8(file);
6265
+ const info = await stat9(file);
4780
6266
  return (info.mode & 511).toString(8).padStart(3, "0");
4781
6267
  } catch {
4782
6268
  return void 0;
@@ -4865,7 +6351,7 @@ __export(mcp_exports, {
4865
6351
  mcpPublish: () => mcpPublish,
4866
6352
  mcpUnpublish: () => mcpUnpublish
4867
6353
  });
4868
- import { resolve as resolve9 } from "node:path";
6354
+ import { resolve as resolve10 } from "node:path";
4869
6355
  async function mcpPublish(paths, options) {
4870
6356
  const fn = requireFunctionName(options.fn);
4871
6357
  const client = await createClient(paths);
@@ -4946,7 +6432,7 @@ function requireFunctionName(fn) {
4946
6432
  return fn.trim();
4947
6433
  }
4948
6434
  async function resolveProject(client, options) {
4949
- const slug = await resolveSlug(resolve9(options.cwd), options.slug);
6435
+ const slug = await resolveSlug(resolve10(options.cwd), options.slug);
4950
6436
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
4951
6437
  const match = listed.projects.find((project2) => project2.slug === slug);
4952
6438
  if (match === void 0) {
@@ -5047,13 +6533,13 @@ __export(functions_exports, {
5047
6533
  functionsList: () => functionsList,
5048
6534
  functionsLogs: () => functionsLogs
5049
6535
  });
5050
- import { resolve as resolve10 } from "node:path";
6536
+ import { resolve as resolve11 } from "node:path";
5051
6537
  async function functionsDeploy(paths, options) {
5052
6538
  const startedAt = Date.now();
5053
6539
  const result = await deploy(paths, {
5054
6540
  cwd: options.cwd,
5055
6541
  ...options.slug === void 0 ? {} : { slug: options.slug },
5056
- ...options.dir === void 0 ? {} : { functionsDir: resolve10(options.cwd, options.dir) },
6542
+ ...options.dir === void 0 ? {} : { functionsDir: resolve11(options.cwd, options.dir) },
5057
6543
  silent: true
5058
6544
  });
5059
6545
  return { ...result, elapsedSeconds: (Date.now() - startedAt) / 1e3 };
@@ -5099,7 +6585,7 @@ async function functionsLogs(paths, options) {
5099
6585
  return { functionId: target.id, name: target.name, logs: result.logs };
5100
6586
  }
5101
6587
  async function resolveProject2(client, options) {
5102
- const slug = await resolveSlug(resolve10(options.cwd), options.slug);
6588
+ const slug = await resolveSlug(resolve11(options.cwd), options.slug);
5103
6589
  const projects = await projectsListFrom(client);
5104
6590
  const match = projects.find((project2) => project2.slug === slug);
5105
6591
  if (match === void 0) {
@@ -5131,11 +6617,11 @@ __export(hosting_exports, {
5131
6617
  hostingInfo: () => hostingInfo,
5132
6618
  hostingPull: () => hostingPull
5133
6619
  });
5134
- import { readdir as readdir5, readFile as readFile11, stat as stat9 } from "node:fs/promises";
5135
- import { dirname as dirname8, join as join13, relative as relative2, resolve as resolve11, sep } from "node:path";
6620
+ import { readdir as readdir6, readFile as readFile12, stat as stat10 } from "node:fs/promises";
6621
+ import { dirname as dirname9, join as join15, relative as relative3, resolve as resolve12, sep } from "node:path";
5136
6622
  async function open4(paths, options) {
5137
6623
  const client = await createClient(paths);
5138
- const project2 = await resolveSlug(resolve11(options.cwd), options.slug);
6624
+ const project2 = await resolveSlug(resolve12(options.cwd), options.slug);
5139
6625
  return { client, project: project2 };
5140
6626
  }
5141
6627
  async function hostingInfo(paths, options) {
@@ -5148,21 +6634,21 @@ async function hostingInfo(paths, options) {
5148
6634
  };
5149
6635
  }
5150
6636
  async function collectSiteFiles(dir) {
5151
- const root = resolve11(dir);
6637
+ const root = resolve12(dir);
5152
6638
  const files = /* @__PURE__ */ new Map();
5153
6639
  const walk = async (sub) => {
5154
6640
  let entries;
5155
6641
  try {
5156
- entries = await readdir5(sub, { withFileTypes: true });
6642
+ entries = await readdir6(sub, { withFileTypes: true });
5157
6643
  } catch {
5158
6644
  return;
5159
6645
  }
5160
6646
  for (const entry of entries) {
5161
- const full = join13(sub, entry.name);
6647
+ const full = join15(sub, entry.name);
5162
6648
  if (entry.isDirectory()) {
5163
6649
  await walk(full);
5164
6650
  } else if (entry.isFile()) {
5165
- const rel = relative2(root, full).split(sep).join("/");
6651
+ const rel = relative3(root, full).split(sep).join("/");
5166
6652
  files.set(rel, full);
5167
6653
  }
5168
6654
  }
@@ -5176,13 +6662,13 @@ async function hostingDeploy(paths, options) {
5176
6662
  `));
5177
6663
  const files = await collectSiteFiles(options.dir);
5178
6664
  if (files.size === 0) {
5179
- throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve11(options.dir)}`);
6665
+ throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve12(options.dir)}`);
5180
6666
  }
5181
6667
  const uploaded = [];
5182
6668
  for (const [rel, full] of files) {
5183
6669
  log(`[adep] \u4E0A\u4F20 site/${rel}`);
5184
- const info2 = await stat9(full);
5185
- const bytes = await readFile11(full);
6670
+ const info2 = await stat10(full);
6671
+ const bytes = await readFile12(full);
5186
6672
  const form = new FormData();
5187
6673
  form.set("path", `site/${rel}`);
5188
6674
  form.set("visibility", "public");
@@ -5209,8 +6695,8 @@ async function hostingPull(paths, options) {
5209
6695
  const log = options.log ?? ((line) => process.stdout.write(`${line}
5210
6696
  `));
5211
6697
  const info = await hostingInfo(paths, options);
5212
- const outputDir = resolve11(options.output ?? resolve11(options.cwd));
5213
- const { mkdir: mkdir9, writeFile: writeFile8 } = await import("node:fs/promises");
6698
+ const outputDir = resolve12(options.output ?? resolve12(options.cwd));
6699
+ const { mkdir: mkdir10, writeFile: writeFile9 } = await import("node:fs/promises");
5214
6700
  const files = [];
5215
6701
  for (const entry of info.files) {
5216
6702
  if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
@@ -5220,9 +6706,9 @@ async function hostingPull(paths, options) {
5220
6706
  const response = await client.download(url, "HOSTING_DOWNLOAD_FAILED");
5221
6707
  const bytes = Buffer.from(await response.arrayBuffer());
5222
6708
  const rel = entry.path.replace(/^site\//, "");
5223
- const target = join13(outputDir, ...rel.split("/"));
5224
- await mkdir9(dirname8(target), { recursive: true });
5225
- await writeFile8(target, bytes);
6709
+ const target = join15(outputDir, ...rel.split("/"));
6710
+ await mkdir10(dirname9(target), { recursive: true });
6711
+ await writeFile9(target, bytes);
5226
6712
  files.push({ path: entry.path, size: bytes.length });
5227
6713
  }
5228
6714
  return { siteUrl: info.siteUrl, outputDir, files };
@@ -5252,7 +6738,7 @@ var init_hosting = __esm({
5252
6738
  // packages/cli/src/cli.ts
5253
6739
  init_config();
5254
6740
  import { Command } from "commander";
5255
- import { createRequire as createRequire2 } from "node:module";
6741
+ import { createRequire as createRequire3 } from "node:module";
5256
6742
 
5257
6743
  // packages/cli/src/output.ts
5258
6744
  init_auth();
@@ -6163,6 +7649,760 @@ function registerInit(program2, ctx) {
6163
7649
  );
6164
7650
  }
6165
7651
 
7652
+ // packages/cli/src/import-cf.ts
7653
+ init_adep_config();
7654
+ import { copyFile, mkdir as mkdir3, readFile as readFile2, readdir, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
7655
+ import { basename, dirname as dirname3, join as join2, relative, resolve as resolve2 } from "node:path";
7656
+ var TomlSyntaxError = class extends Error {
7657
+ constructor(message) {
7658
+ super(message);
7659
+ this.name = "TomlSyntaxError";
7660
+ }
7661
+ };
7662
+ function parseTomlValue(raw) {
7663
+ const text = raw.trim();
7664
+ if (text === "") throw new TomlSyntaxError("\u7A7A\u503C");
7665
+ if (text.startsWith("[") && text.endsWith("]")) {
7666
+ const inner = text.slice(1, -1).trim();
7667
+ if (inner === "") return [];
7668
+ return splitTopLevel(inner).map((part) => parseTomlValue(part));
7669
+ }
7670
+ if (text.startsWith("{") && text.endsWith("}")) {
7671
+ const inner = text.slice(1, -1).trim();
7672
+ const table = {};
7673
+ if (inner !== "") {
7674
+ for (const pair of splitTopLevel(inner)) {
7675
+ const eq = pair.indexOf("=");
7676
+ if (eq <= 0) throw new TomlSyntaxError(`\u5185\u8054\u8868\u6761\u76EE\u975E\u6CD5\uFF1A${pair}`);
7677
+ const key = pair.slice(0, eq).trim().replace(/^"|"$/g, "");
7678
+ table[key] = parseTomlValue(pair.slice(eq + 1));
7679
+ }
7680
+ }
7681
+ return table;
7682
+ }
7683
+ if (text.startsWith('"') || text.startsWith("'")) {
7684
+ return unquoteToml(text);
7685
+ }
7686
+ if (text === "true") return true;
7687
+ if (text === "false") return false;
7688
+ const number = Number(text);
7689
+ if (text !== "" && !Number.isNaN(number) && /^-?\d+(\.\d+)?$/.test(text)) return number;
7690
+ return text;
7691
+ }
7692
+ function splitTopLevel(text) {
7693
+ const parts = [];
7694
+ let depth = 0;
7695
+ let quote = null;
7696
+ let current = "";
7697
+ for (let i = 0; i < text.length; i += 1) {
7698
+ const ch = text[i];
7699
+ if (quote !== null) {
7700
+ current += ch;
7701
+ if (ch === quote && text[i - 1] !== "\\") quote = null;
7702
+ continue;
7703
+ }
7704
+ if (ch === '"' || ch === "'") {
7705
+ quote = ch;
7706
+ current += ch;
7707
+ continue;
7708
+ }
7709
+ if (ch === "{" || ch === "[") depth += 1;
7710
+ if (ch === "}" || ch === "]") depth -= 1;
7711
+ if (ch === "," && depth === 0) {
7712
+ parts.push(current);
7713
+ current = "";
7714
+ continue;
7715
+ }
7716
+ current += ch;
7717
+ }
7718
+ if (quote !== null) throw new TomlSyntaxError("\u5B57\u7B26\u4E32\u672A\u95ED\u5408");
7719
+ parts.push(current);
7720
+ return parts;
7721
+ }
7722
+ function unquoteToml(text) {
7723
+ const quote = text[0];
7724
+ const body = text.slice(1, -1);
7725
+ if (quote === "'") return body;
7726
+ return body.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
7727
+ }
7728
+ function parseWranglerToml(text) {
7729
+ const root = {};
7730
+ let current = { table: root };
7731
+ const tableAt = (path) => {
7732
+ let node = root;
7733
+ for (const seg of path) {
7734
+ const next = node[seg];
7735
+ if (next === void 0) {
7736
+ const created = {};
7737
+ node[seg] = created;
7738
+ node = created;
7739
+ } else if (typeof next === "object" && next !== null && !Array.isArray(next)) {
7740
+ node = next;
7741
+ } else {
7742
+ throw new TomlSyntaxError(`\u8DEF\u5F84\u51B2\u7A81\uFF1A${path.join(".")}\uFF08${seg} \u4E0D\u662F\u8868\uFF09`);
7743
+ }
7744
+ }
7745
+ return node;
7746
+ };
7747
+ const lines = text.split(/\r?\n/);
7748
+ for (let i = 0; i < lines.length; i += 1) {
7749
+ const rawLine = lines[i] ?? "";
7750
+ const line = stripTomlComment(rawLine).trim();
7751
+ if (line === "") continue;
7752
+ const arrayHeader = /^\[\[([^\]]+)\]\]\s*$/.exec(line);
7753
+ if (arrayHeader !== null) {
7754
+ const path = (arrayHeader[1] ?? "").trim().split(".").filter(Boolean);
7755
+ if (path.length === 0) throw new TomlSyntaxError(`\u7A7A\u6570\u7EC4\u8868\uFF1A${line}`);
7756
+ const parent = path.length === 1 ? root : tableAt(path.slice(0, -1));
7757
+ const key2 = path[path.length - 1] ?? "";
7758
+ let arr = parent[key2];
7759
+ if (arr === void 0) {
7760
+ arr = [];
7761
+ parent[key2] = arr;
7762
+ }
7763
+ if (!Array.isArray(arr)) throw new TomlSyntaxError(`\u8DEF\u5F84\u51B2\u7A81\uFF1A${key2} \u4E0D\u662F\u6570\u7EC4`);
7764
+ const table = {};
7765
+ arr.push(table);
7766
+ current = { table };
7767
+ continue;
7768
+ }
7769
+ const header = /^\[([^\]]+)\]\s*$/.exec(line);
7770
+ if (header !== null) {
7771
+ const path = (header[1] ?? "").trim().split(".").filter(Boolean);
7772
+ if (path.length !== 1) throw new TomlSyntaxError(`\u4EC5\u652F\u6301\u5355\u6BB5\u8868\uFF1A${line}`);
7773
+ current = { table: tableAt(path) };
7774
+ continue;
7775
+ }
7776
+ const eq = line.indexOf("=");
7777
+ if (eq <= 0) throw new TomlSyntaxError(`\u7B2C ${i + 1} \u884C\u65E0\u6CD5\u89E3\u6790\uFF1A${rawLine}`);
7778
+ const key = line.slice(0, eq).trim().replace(/^"|"$/g, "");
7779
+ let valueRaw = line.slice(eq + 1);
7780
+ let depth = bracketDepth(valueRaw);
7781
+ while (depth > 0) {
7782
+ if (i + 1 >= lines.length) {
7783
+ throw new TomlSyntaxError(`\u7B2C ${i + 1} \u884C\u503C\u672A\u95ED\u5408\uFF1A${key}`);
7784
+ }
7785
+ i += 1;
7786
+ const next = stripTomlComment(lines[i] ?? "").trim();
7787
+ valueRaw += ` ${next}`;
7788
+ depth = bracketDepth(valueRaw);
7789
+ }
7790
+ const value = parseTomlValue(valueRaw);
7791
+ current.table[key] = value;
7792
+ }
7793
+ return normalizeWranglerToml(root);
7794
+ }
7795
+ function stripTomlComment(line) {
7796
+ const hash = line.indexOf("#");
7797
+ if (hash === -1) return line;
7798
+ return line.slice(0, hash);
7799
+ }
7800
+ function bracketDepth(text) {
7801
+ let depth = 0;
7802
+ let quote = null;
7803
+ for (let i = 0; i < text.length; i += 1) {
7804
+ const ch = text[i];
7805
+ if (quote !== null) {
7806
+ if (ch === quote && text[i - 1] !== "\\") quote = null;
7807
+ continue;
7808
+ }
7809
+ if (ch === '"' || ch === "'") {
7810
+ quote = ch;
7811
+ continue;
7812
+ }
7813
+ if (ch === "[" || ch === "{") depth += 1;
7814
+ if (ch === "]" || ch === "}") depth -= 1;
7815
+ }
7816
+ return depth;
7817
+ }
7818
+ function tomlString(v) {
7819
+ return typeof v === "string" ? v : void 0;
7820
+ }
7821
+ function tomlStringRecord(v) {
7822
+ if (typeof v !== "object" || v === null || Array.isArray(v)) return void 0;
7823
+ const out = {};
7824
+ for (const [k, value] of Object.entries(v)) {
7825
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
7826
+ out[k] = String(value);
7827
+ }
7828
+ }
7829
+ return out;
7830
+ }
7831
+ function tomlBindingArray(v) {
7832
+ if (!Array.isArray(v)) return void 0;
7833
+ const out = [];
7834
+ for (const item of v) {
7835
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
7836
+ const rec = {};
7837
+ for (const [k, value] of Object.entries(item)) {
7838
+ if (typeof value === "string" || typeof value === "number") rec[k] = String(value);
7839
+ }
7840
+ out.push(rec);
7841
+ }
7842
+ }
7843
+ return out;
7844
+ }
7845
+ function normalizeWranglerToml(root) {
7846
+ const name = tomlString(root.name);
7847
+ const main = tomlString(root.main);
7848
+ const vars = tomlStringRecord(root.vars);
7849
+ const kv = tomlBindingArray(root.kv_namespaces);
7850
+ const d1 = tomlBindingArray(root.d1_databases);
7851
+ const r2 = tomlBindingArray(root.r2_buckets);
7852
+ const triggersRaw = typeof root.triggers === "object" && root.triggers !== null ? root.triggers : void 0;
7853
+ const crons = triggersRaw !== void 0 && Array.isArray(triggersRaw.crons) ? triggersRaw.crons.map(String) : void 0;
7854
+ const assetsRaw = typeof root.assets === "object" && root.assets !== null ? root.assets : void 0;
7855
+ const assetsDir = assetsRaw === void 0 ? void 0 : tomlString(assetsRaw.directory);
7856
+ const siteRaw = typeof root.site === "object" && root.site !== null ? root.site : void 0;
7857
+ const siteBucket = siteRaw === void 0 ? void 0 : tomlString(siteRaw.bucket);
7858
+ const out = { raw: root };
7859
+ if (name !== void 0) out.name = name;
7860
+ if (main !== void 0) out.main = main;
7861
+ if (vars !== void 0) out.vars = vars;
7862
+ if (kv !== void 0) out.kv_namespaces = kv;
7863
+ if (d1 !== void 0) out.d1_databases = d1;
7864
+ if (r2 !== void 0) out.r2_buckets = r2;
7865
+ if (crons !== void 0) out.triggers = { crons };
7866
+ if (assetsDir !== void 0) out.assets = { directory: assetsDir };
7867
+ if (siteBucket !== void 0) out.site = { bucket: siteBucket };
7868
+ const doRaw = typeof root.durable_objects === "object" && root.durable_objects !== null ? root.durable_objects : void 0;
7869
+ const doBindings = doRaw === void 0 ? void 0 : tomlBindingArray(doRaw.bindings);
7870
+ if (doBindings !== void 0 && doBindings.length > 0) {
7871
+ out.durable_objects = {
7872
+ bindings: doBindings
7873
+ };
7874
+ }
7875
+ return out;
7876
+ }
7877
+ var ImportCfError = class extends Error {
7878
+ code;
7879
+ constructor(code, message) {
7880
+ super(message);
7881
+ this.code = code;
7882
+ this.name = "ImportCfError";
7883
+ }
7884
+ };
7885
+ function slugify(name, fallback) {
7886
+ const slug = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-");
7887
+ return slug.length > 0 ? slug : fallback;
7888
+ }
7889
+ var SKIP_COPY_NAMES = /* @__PURE__ */ new Set([
7890
+ "wrangler.toml",
7891
+ "wrangler.json",
7892
+ "wrangler.jsonc",
7893
+ ".dev.vars",
7894
+ "package.json",
7895
+ "package-lock.json",
7896
+ "pnpm-lock.yaml",
7897
+ "yarn.lock",
7898
+ "bun.lockb",
7899
+ "node_modules",
7900
+ ".git",
7901
+ "dist",
7902
+ ".wrangler",
7903
+ "test",
7904
+ "tests"
7905
+ ]);
7906
+ async function copyWorkerDir(sourceDir, targetDir, mainFile) {
7907
+ const copied = [];
7908
+ const renamedIndex = [];
7909
+ const entries = await readdir(sourceDir, { withFileTypes: true });
7910
+ for (const entry of entries) {
7911
+ const from = join2(sourceDir, entry.name);
7912
+ const to = join2(targetDir, entry.name);
7913
+ if (SKIP_COPY_NAMES.has(entry.name)) continue;
7914
+ if (entry.isDirectory()) {
7915
+ await mkdir3(to, { recursive: true });
7916
+ const sub = await copyWorkerDir(from, to, "");
7917
+ copied.push(...sub.copied);
7918
+ renamedIndex.push(...sub.renamedIndex);
7919
+ continue;
7920
+ }
7921
+ if (from === mainFile) continue;
7922
+ if (entry.name === "index.ts") {
7923
+ await copyFile(from, join2(targetDir, "_index.ts"));
7924
+ renamedIndex.push("_index.ts");
7925
+ continue;
7926
+ }
7927
+ await copyFile(from, to);
7928
+ copied.push(relative(targetDir, to));
7929
+ }
7930
+ return { copied, renamedIndex };
7931
+ }
7932
+ async function readDevVars(sourceDir) {
7933
+ try {
7934
+ const text = await readFile2(join2(sourceDir, ".dev.vars"), "utf8");
7935
+ const vars = {};
7936
+ for (const line of text.split(/\r?\n/)) {
7937
+ const trimmed = line.trim();
7938
+ if (trimmed === "" || trimmed.startsWith("#")) continue;
7939
+ const eq = trimmed.indexOf("=");
7940
+ if (eq <= 0) continue;
7941
+ const key = trimmed.slice(0, eq).trim();
7942
+ vars[key] = trimmed.slice(eq + 1).trim().replace(/^"|"$/g, "");
7943
+ }
7944
+ return vars;
7945
+ } catch {
7946
+ return {};
7947
+ }
7948
+ }
7949
+ async function copyAssetsToWeb(sourceDir, assetsDir, outDir) {
7950
+ const files = [];
7951
+ const from = resolve2(sourceDir, assetsDir);
7952
+ const target = join2(outDir, "web");
7953
+ await mkdir3(target, { recursive: true });
7954
+ const entries = await readdir(from, { withFileTypes: true });
7955
+ for (const entry of entries) {
7956
+ const src = join2(from, entry.name);
7957
+ const dst = join2(target, entry.name);
7958
+ if (entry.isDirectory()) {
7959
+ await mkdir3(dst, { recursive: true });
7960
+ const sub = await copyAssetsToWeb(src, ".", outDir);
7961
+ files.push(...sub);
7962
+ continue;
7963
+ }
7964
+ await copyFile(src, dst);
7965
+ files.push(relative(outDir, dst));
7966
+ }
7967
+ return files;
7968
+ }
7969
+ function bindingsFromWrangler(config) {
7970
+ const cfBindings = {};
7971
+ const kv = config.kv_namespaces?.map((b) => ({
7972
+ name: b.binding ?? "",
7973
+ ...b.id === void 0 ? {} : { namespace: b.id }
7974
+ }));
7975
+ if (kv !== void 0 && kv.length > 0) cfBindings.kv = kv;
7976
+ const d1 = config.d1_databases?.map((b) => ({
7977
+ name: b.binding ?? "",
7978
+ ...b.database_name === void 0 ? b.database_id === void 0 ? {} : { database: b.database_id } : { database: b.database_name }
7979
+ }));
7980
+ if (d1 !== void 0 && d1.length > 0) cfBindings.d1 = d1;
7981
+ const r2 = config.r2_buckets?.map((b) => ({
7982
+ name: b.binding ?? "",
7983
+ ...b.bucket_name === void 0 ? {} : { bucket: b.bucket_name }
7984
+ }));
7985
+ if (r2 !== void 0 && r2.length > 0) cfBindings.r2 = r2;
7986
+ const isEmpty = cfBindings.kv === void 0 && cfBindings.d1 === void 0 && cfBindings.r2 === void 0;
7987
+ return {
7988
+ cfBindings: isEmpty ? void 0 : cfBindings,
7989
+ environment: config.vars
7990
+ };
7991
+ }
7992
+ function collectDurableObjectBindings(config) {
7993
+ return (config.durable_objects?.bindings ?? []).filter((b) => b.class_name !== void 0).map((b) => ({ name: b.name, className: b.class_name }));
7994
+ }
7995
+ function escapeRegExp(text) {
7996
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7997
+ }
7998
+ function findClosingBrace(text, openIdx) {
7999
+ let depth = 0;
8000
+ let i = openIdx;
8001
+ let quote = null;
8002
+ while (i < text.length) {
8003
+ const ch = text[i];
8004
+ if (quote !== null) {
8005
+ if (ch === "\\") {
8006
+ i += 2;
8007
+ continue;
8008
+ }
8009
+ if (ch === quote) quote = null;
8010
+ i += 1;
8011
+ continue;
8012
+ }
8013
+ if (ch === '"' || ch === "'" || ch === "`") {
8014
+ quote = ch;
8015
+ i += 1;
8016
+ continue;
8017
+ }
8018
+ if (ch === "/" && text[i + 1] === "/") {
8019
+ const nl = text.indexOf("\n", i);
8020
+ i = nl === -1 ? text.length : nl + 1;
8021
+ continue;
8022
+ }
8023
+ if (ch === "/" && text[i + 1] === "*") {
8024
+ const end = text.indexOf("*/", i + 2);
8025
+ i = end === -1 ? text.length : end + 2;
8026
+ continue;
8027
+ }
8028
+ if (ch === "{") depth += 1;
8029
+ else if (ch === "}") {
8030
+ depth -= 1;
8031
+ if (depth === 0) return i;
8032
+ }
8033
+ i += 1;
8034
+ }
8035
+ return -1;
8036
+ }
8037
+ function stripDurableObjectClasses(workerText, classNames) {
8038
+ let text = workerText;
8039
+ const removed = [];
8040
+ for (const className of classNames) {
8041
+ const pattern = new RegExp(
8042
+ `export\\s+class\\s+${escapeRegExp(className)}\\s+extends\\s+DurableObject`
8043
+ );
8044
+ const match = pattern.exec(text);
8045
+ if (match === null) continue;
8046
+ const startLine = text.lastIndexOf("\n", match.index) + 1;
8047
+ const braceIdx = text.indexOf("{", match.index);
8048
+ if (braceIdx === -1) continue;
8049
+ const endIdx = findClosingBrace(text, braceIdx);
8050
+ if (endIdx === -1) continue;
8051
+ let removeEnd = endIdx + 1;
8052
+ if (text[removeEnd] === "\n") removeEnd += 1;
8053
+ removed.push({ className, source: text.slice(startLine, endIdx + 1).trim() });
8054
+ text = text.slice(0, startLine) + text.slice(removeEnd);
8055
+ }
8056
+ text = text.replace(/^[ \t]*import[ \t][^\n]*from[ \t]['"]cloudflare:workers['"][^\n]*\n/gm, "");
8057
+ return { text, removed };
8058
+ }
8059
+ function extractMethodNames(source) {
8060
+ const names = [];
8061
+ const re = /(?:^|\n)[ \t]*(?:async[ \t]+)?([A-Za-z_$][\w$]*)[ \t]*\(/g;
8062
+ const CONTROL = /* @__PURE__ */ new Set(["if", "for", "while", "switch", "catch", "function", "with"]);
8063
+ let m;
8064
+ while ((m = re.exec(source)) !== null) {
8065
+ const name = m[1];
8066
+ if (CONTROL.has(name) || name === "constructor" || name === "super" || names.includes(name)) {
8067
+ continue;
8068
+ }
8069
+ names.push(name);
8070
+ }
8071
+ return names;
8072
+ }
8073
+ function renderStateObjectDeclaration(bindings, removed) {
8074
+ const lines = [
8075
+ "/**",
8076
+ " * \u7531 `adep import cf` \u751F\u6210\uFF08CF-039\uFF09\uFF1Awrangler [[durable_objects.bindings]] \u2192 \u72B6\u6001\u5BF9\u8C61\u58F0\u660E\u3002",
8077
+ " * \u539F DurableObject \u7C7B\u6E90\u7801\u4FDD\u7559\u5728 durable-objects/<ClassName>.ts\uFF08AI \u8FC1\u79FB\u53C2\u8003\uFF09\u3002",
8078
+ " * \u8C03\u7528\u9762\uFF1AHTTP POST /api/state/<Type>/<id>/<method> \xB7 MCP state.invoke \xB7 WS state:<Type>:<id>",
8079
+ " */",
8080
+ "import { StateObject } from '@adep/runtime/state-objects'",
8081
+ ""
8082
+ ];
8083
+ for (const { className } of bindings) {
8084
+ const removedSrc = removed.find((r) => r.className === className);
8085
+ const methods = extractMethodNames(removedSrc?.source ?? "");
8086
+ lines.push("/**", ` * \u8FC1\u79FB\u81EA DurableObject \u7C7B \`${className}\`\u3002`);
8087
+ if (methods.length > 0) {
8088
+ lines.push(
8089
+ ` * \u539F\u65B9\u6CD5\uFF08AI \u8FC1\u79FB\uFF1A\u628A fetch \u5165\u53E3\u8DEF\u7531\u62C6\u6210 StateObject \u65B9\u6CD5\uFF09\uFF1A${methods.join(", ")}`
8090
+ );
8091
+ } else {
8092
+ lines.push(` * \u539F\u7C7B\u6E90\u7801\u89C1 durable-objects/${className}.ts\u3002`);
8093
+ }
8094
+ lines.push(" */");
8095
+ lines.push(`export class ${className} extends StateObject<Record<string, unknown>> {`);
8096
+ lines.push(` static typeName = '${className}'`);
8097
+ lines.push("");
8098
+ lines.push(" protected initialState(): Record<string, unknown> {");
8099
+ lines.push(
8100
+ " // TODO\uFF1A\u4ECE\u539F DurableObject \u7684 this.state \u8FC1\u79FB\u521D\u59CB\u72B6\u6001\uFF08\u89C1 durable-objects/\uFF09\u3002"
8101
+ );
8102
+ lines.push(" return {}");
8103
+ lines.push(" }");
8104
+ lines.push("}");
8105
+ lines.push("");
8106
+ }
8107
+ return lines.join("\n");
8108
+ }
8109
+ function unsupportedFromWrangler(config) {
8110
+ const out = [];
8111
+ const raw = config.raw;
8112
+ if (raw.queues !== void 0) {
8113
+ out.push("queues\uFF08\u961F\u5217\uFF09\u2192 \u66FF\u4EE3\uFF1Acron \u89E6\u53D1\u5668 + \u6570\u636E\u5E93\u4EFB\u52A1\u8868\u8F6E\u8BE2");
8114
+ }
8115
+ if (raw.email_bindings !== void 0) {
8116
+ out.push("email_bindings \u2192 \u66FF\u4EE3\uFF1A\u7B2C\u4E09\u65B9\u90AE\u4EF6 API\uFF08\u5982 Resend/Mailgun\uFF09");
8117
+ }
8118
+ if (raw.services !== void 0) {
8119
+ out.push("services\uFF08service bindings\uFF09\u2192 \u66FF\u4EE3\uFF1A\u51FD\u6570\u95F4\u7ECF HTTP \u6216\u4E91\u6570\u636E\u5E93\u5171\u4EAB\u8C03\u7528");
8120
+ }
8121
+ if (raw.assets === void 0 && raw.site === void 0 && raw["_ssr"] !== void 0) {
8122
+ out.push("SSR\uFF08\u524D\u7AEF\u6E32\u67D3\uFF09\u2192 adep web/ \u4E3A\u9759\u6001\u6258\u7BA1\uFF0CSSR \u9700\u81EA\u884C\u5728\u51FD\u6570\u5185\u5B9E\u73B0");
8123
+ }
8124
+ return out;
8125
+ }
8126
+ function renderFunctionEntry(workerImport, bindings) {
8127
+ const bindingsLine = bindings === void 0 ? "" : `, { bindings: ${JSON.stringify(bindings, null, 2).replace(/\n/g, "\n ")} }`;
8128
+ return `/**
8129
+ * \u7531 \`adep import cf\` \u751F\u6210\uFF08CF-015\uFF09\uFF1A\u628A Cloudflare Workers \u6A21\u5757\u683C\u5F0F\u5305\u88C5\u4E3A adep \u4E91\u51FD\u6570\u3002
8130
+ * \u7ED1\u5B9A\u58F0\u660E\u6765\u81EA wrangler.toml\uFF1B\u672A\u652F\u6301\u9879\u4E0E\u66FF\u4EE3\u6A21\u5F0F\u89C1 MIGRATION.md\u3002
8131
+ *
8132
+ * \u6CE8\u610F\uFF1Aadep \u6C99\u7BB1\u628A \`import x from './x'\` \u8F6C\u8BD1\u4E3A \`require('./x')\`\uFF08\u8FD4\u56DE\u6A21\u5757\u5BF9\u8C61\uFF09\uFF0C
8133
+ * \u56E0\u6B64\u8FD9\u91CC\u5BF9 default \u4E0E\u5177\u540D\u4E24\u79CD worker \u5BFC\u51FA\u5F62\u6001\u90FD\u505A\u517C\u5BB9\u3002
8134
+ */
8135
+ import { createAdepFunction } from '@adep/cf-compat'
8136
+ import workerModule from './${workerImport}'
8137
+
8138
+ const worker = (workerModule as { default?: unknown }).default ?? workerModule
8139
+
8140
+ export default createAdepFunction(worker as never${bindingsLine})
8141
+ `;
8142
+ }
8143
+ function renderMigrationReport(config, result) {
8144
+ const lines = [
8145
+ `# \u8FC1\u79FB\u62A5\u544A\uFF1A${config.name ?? "worker"}\uFF08\u7531 adep import cf \u751F\u6210\uFF09`,
8146
+ "",
8147
+ "## \u6620\u5C04\u6E05\u5355",
8148
+ "",
8149
+ `- worker\uFF1A\`${config.main ?? "(\u65E0 main)"}\` \u2192 \`functions/${result.workerName}/\``,
8150
+ `- vars\uFF1A${result.mapping.vars} \u4E2A \u2192 adep.config.ts environment`,
8151
+ result.mapping.secretsFromDevVars ? "- secrets\uFF08.dev.vars\uFF09\u2192 environment\uFF08\u5EFA\u8BAE\u4E0A\u7EBF\u524D\u8FC1\u5230\u5E73\u53F0 env \u7BA1\u7406\uFF09" : "",
8152
+ `- KV \u7ED1\u5B9A\uFF1A${result.mapping.kv} \u4E2A`,
8153
+ `- D1 \u7ED1\u5B9A\uFF1A${result.mapping.d1} \u4E2A`,
8154
+ `- R2 \u7ED1\u5B9A\uFF1A${result.mapping.r2} \u4E2A`,
8155
+ result.mapping.crons.length > 0 ? `- cron \u89E6\u53D1\u5668\uFF1A${result.mapping.crons.join(", ")}\uFF08adep \u4FA7\u5728\u63A7\u5236\u53F0/MCP \u914D\u7F6E\u89E6\u53D1\u5668\uFF1BcreateAdepFunction \u5DF2\u652F\u6301 scheduled \u6D3E\u53D1\uFF09` : "",
8156
+ result.mapping.assets ? "- \u9759\u6001\u8D44\u6E90 assets \u2192 web/\uFF08adep \u524D\u7AEF\u6258\u7BA1\uFF09" : "",
8157
+ result.mapping.dos > 0 ? `- Durable Objects \u7ED1\u5B9A\uFF1A${result.mapping.dos} \u4E2A\uFF08class_name \u2192 functions/${result.workerName}/state-objects.ts \u58F0\u660E\u9AA8\u67B6\uFF1B\u539F\u7C7B\u4FDD\u7559 durable-objects/\uFF09` : "",
8158
+ "",
8159
+ "## \u672A\u652F\u6301\u9879\u4E0E\u66FF\u4EE3\u6A21\u5F0F",
8160
+ "",
8161
+ ...result.unsupported.length > 0 ? result.unsupported.map((item) => `- ${item}`) : ["- \uFF08\u65E0\uFF09"],
8162
+ "",
8163
+ "## AI \u8FC1\u79FB\u63D0\u793A",
8164
+ "",
8165
+ "- `ctx`\uFF08adep\uFF09\u2194 Workers `Request`\uFF1A`ctx.req` \u5373 Request \u5F62\u72B6\uFF0C`ctx.body`/`ctx.query`/`ctx.headers` \u5DF2\u63D0\u4F9B",
8166
+ "- `env.XXX` \u7ED1\u5B9A\u5728\u51FD\u6570\u5185\u7ECF cfEnv \u7EC4\u88C5\uFF08vars=process.env\u3001KV/D1/R2 \u4E3A shim \u5B9E\u4F8B\uFF09",
8167
+ "- Response \u8FD4\u56DE\u7ECF `__adepHttp` \u4FE1\u5C01\uFF0Cstatus/headers/body \u5168\u4FDD\u7559",
8168
+ "- \u591A\u6587\u4EF6 worker\uFF1A\u4F9D\u8D56\u6A21\u5757\u5DF2\u968F\u76EE\u5F55\u590D\u5236\u8FDB\u51FD\u6570\u76EE\u5F55\uFF0C\u4FDD\u6301\u76F8\u5BF9 import \u5373\u53EF",
8169
+ "- \u4E91\u51FD\u6570\u9ED8\u8BA4\u540C\u6B65\u6267\u884C\u6A21\u578B\uFF1A`ctx.waitUntil` \u4E3A\u7A7A\u5B9E\u73B0\uFF08v1\uFF09",
8170
+ "",
8171
+ "## Durable Objects \u8FC1\u79FB\u8981\u70B9\uFF08CF-039\uFF09",
8172
+ "",
8173
+ "- `this.state`\uFF08DO storage\uFF09\u2192 StateObject \u76F4\u63A5\u8BFB\u5199 `this.state` \u5B57\u6BB5 + `await this.flush()` \u6301\u4E45\u5316",
8174
+ "- `this.ctx.storage.setAlarm(t)` \u2192 `this.setAlarm(t)`\uFF1B`this.ctx.storage.getAlarm()` \u2192 alarm \u67E5\u8BE2\u9762\uFF08CF-037\uFF09",
8175
+ "- `this.ctx.waitUntil(p)` \u2192 adep \u540C\u6B65\u6267\u884C\u6A21\u578B\uFF0C\u7A7A\u5B9E\u73B0\uFF08v1\uFF09",
8176
+ "- `stub.fetch(req)` \u8C03\u7528\u65B9 \u2192 `fetch('/api/state/<ClassName>/<id>/<path>')` \u6216 WS `state:<ClassName>:<id>` \u6216 MCP `state.invoke`",
8177
+ "- `env.<BINDING>.idFromName(name)` \u2192 \u5BF9\u8C61 id \u5373\u8C03\u7528\u8DEF\u5F84\u7684 `<id>` \u6BB5",
8178
+ "- `[[migrations]]` \u4E3A CF \u7AEF DO \u7248\u672C\u7BA1\u7406\uFF0Cadep \u65E0\u5BF9\u5E94\u6982\u5FF5\uFF08\u5FFD\u7565\uFF09"
8179
+ ];
8180
+ return `${lines.filter((line) => line !== "").join("\n")}
8181
+ `;
8182
+ }
8183
+ function renderImportPackageJson(name) {
8184
+ return `${JSON.stringify(
8185
+ {
8186
+ name,
8187
+ private: true,
8188
+ scripts: {
8189
+ dev: "adep dev",
8190
+ serve: "adep serve",
8191
+ deploy: "adep deploy",
8192
+ doctor: "adep doctor"
8193
+ },
8194
+ dependencies: {
8195
+ "@adep/cli": "latest",
8196
+ "@adep/cf-compat": "latest"
8197
+ }
8198
+ },
8199
+ null,
8200
+ 2
8201
+ )}
8202
+ `;
8203
+ }
8204
+ async function importCfProject(cwd, sourceDir, options = {}) {
8205
+ let tomlText;
8206
+ try {
8207
+ tomlText = await readFile2(join2(sourceDir, "wrangler.toml"), "utf8");
8208
+ } catch {
8209
+ throw new ImportCfError(
8210
+ "NO_WRANGLER",
8211
+ `\u627E\u4E0D\u5230 ${join2(sourceDir, "wrangler.toml")}\uFF1A\u9700\u5728 Cloudflare \u9879\u76EE\u6839\u6267\u884C\u5BFC\u5165`
8212
+ );
8213
+ }
8214
+ let config;
8215
+ try {
8216
+ config = parseWranglerToml(tomlText);
8217
+ } catch (error) {
8218
+ throw new ImportCfError(
8219
+ "TOML_PARSE",
8220
+ `wrangler.toml \u89E3\u6790\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`
8221
+ );
8222
+ }
8223
+ const workerName = slugify(config.name ?? basename(sourceDir), "worker");
8224
+ const outDir = resolve2(cwd, options.out ?? `imported-${workerName}`);
8225
+ try {
8226
+ await stat3(outDir);
8227
+ throw new ImportCfError("DIR_EXISTS", `\u8F93\u51FA\u76EE\u5F55 ${outDir} \u5DF2\u5B58\u5728\uFF1A\u8BF7\u6362 --out \u6216\u5148\u5220\u9664`);
8228
+ } catch (error) {
8229
+ if (error instanceof ImportCfError) throw error;
8230
+ }
8231
+ const { cfBindings, environment } = bindingsFromWrangler(config);
8232
+ const devVars = await readDevVars(sourceDir);
8233
+ const mergedEnv = environment === void 0 && Object.keys(devVars).length === 0 ? void 0 : { ...environment, ...devVars };
8234
+ const files = [];
8235
+ const warnings = [];
8236
+ const adepConfig = {
8237
+ name: workerName,
8238
+ functionsDir: "functions",
8239
+ functions_prefix: "/api",
8240
+ ...mergedEnv === void 0 ? {} : { environment: mergedEnv },
8241
+ ...cfBindings === void 0 ? {} : { cfBindings }
8242
+ };
8243
+ const configText = renderAdepConfig(adepConfig, {
8244
+ header: "// \u7531 adep import cf \u751F\u6210\uFF08CF-015\uFF09\uFF1A\u7ED1\u5B9A\u58F0\u660E\u4E0E wrangler.toml \u5BF9\u5E94"
8245
+ });
8246
+ await mkdir3(outDir, { recursive: true });
8247
+ await writeFile2(join2(outDir, "adep.config.ts"), configText, "utf8");
8248
+ files.push("adep.config.ts");
8249
+ await writeFile2(join2(outDir, "package.json"), renderImportPackageJson(workerName), "utf8");
8250
+ files.push("package.json");
8251
+ let mainCopied = false;
8252
+ if (config.main !== void 0) {
8253
+ const mainAbs = resolve2(sourceDir, config.main);
8254
+ let mainStat;
8255
+ try {
8256
+ mainStat = await stat3(mainAbs);
8257
+ } catch {
8258
+ throw new ImportCfError("MAIN_MISSING", `main \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${config.main}`);
8259
+ }
8260
+ if (!mainStat.isFile()) {
8261
+ throw new ImportCfError("MAIN_NOT_FILE", `main \u4E0D\u662F\u6587\u4EF6\uFF1A${config.main}`);
8262
+ }
8263
+ const fnDir = join2(outDir, "functions", workerName);
8264
+ await mkdir3(fnDir, { recursive: true });
8265
+ await copyFile(mainAbs, join2(fnDir, "worker.ts"));
8266
+ files.push(`functions/${workerName}/worker.ts`);
8267
+ mainCopied = true;
8268
+ const mainDir = dirname3(mainAbs);
8269
+ const { copied, renamedIndex } = await copyWorkerDir(mainDir, fnDir, mainAbs);
8270
+ if (renamedIndex.length > 0) {
8271
+ warnings.push(
8272
+ `\u51FD\u6570\u76EE\u5F55\u539F\u6709 index.ts \u5DF2\u6539\u540D\u4E3A _index.ts\uFF08\u5165\u53E3\u88AB\u5305\u88C5\u5360\u7528\uFF09\uFF1A${renamedIndex.join(", ")}`
8273
+ );
8274
+ }
8275
+ files.push(...copied.map((f) => `functions/${workerName}/${f}`));
8276
+ if (copied.length > 0) {
8277
+ warnings.push(`\u5DF2\u590D\u5236\u540C\u76EE\u5F55\u4F9D\u8D56\u6A21\u5757 ${copied.length} \u4E2A\uFF08\u4FDD\u6301\u76F8\u5BF9 import\uFF09`);
8278
+ }
8279
+ await writeFile2(join2(fnDir, "index.ts"), renderFunctionEntry("worker", cfBindings), "utf8");
8280
+ files.push(`functions/${workerName}/index.ts`);
8281
+ }
8282
+ let dosMigrated = 0;
8283
+ if (mainCopied) {
8284
+ const doBindings = collectDurableObjectBindings(config);
8285
+ const noClassName = (config.durable_objects?.bindings ?? []).filter(
8286
+ (b) => b.class_name === void 0
8287
+ );
8288
+ if (noClassName.length > 0) {
8289
+ warnings.push(
8290
+ `durable_objects \u7ED1\u5B9A\u7F3A\u5C11 class_name\uFF08\u65E0\u6CD5\u751F\u6210\u58F0\u660E\uFF09\uFF1A${noClassName.map((b) => b.name).join(", ")}`
8291
+ );
8292
+ }
8293
+ if (doBindings.length > 0) {
8294
+ const fnDir = join2(outDir, "functions", workerName);
8295
+ const workerPath = join2(fnDir, "worker.ts");
8296
+ const workerText = await readFile2(workerPath, "utf8");
8297
+ const { text: stripped, removed } = stripDurableObjectClasses(
8298
+ workerText,
8299
+ doBindings.map((b) => b.className)
8300
+ );
8301
+ await writeFile2(workerPath, stripped, "utf8");
8302
+ if (removed.length > 0) {
8303
+ await mkdir3(join2(fnDir, "durable-objects"), { recursive: true });
8304
+ await Promise.all(
8305
+ removed.map(async (r) => {
8306
+ await writeFile2(
8307
+ join2(fnDir, "durable-objects", `${r.className}.ts`),
8308
+ `${r.source}
8309
+ `,
8310
+ "utf8"
8311
+ );
8312
+ files.push(`functions/${workerName}/durable-objects/${r.className}.ts`);
8313
+ })
8314
+ );
8315
+ }
8316
+ if (removed.length > 0) {
8317
+ await writeFile2(
8318
+ join2(fnDir, "state-objects.ts"),
8319
+ renderStateObjectDeclaration(doBindings, removed),
8320
+ "utf8"
8321
+ );
8322
+ files.push(`functions/${workerName}/state-objects.ts`);
8323
+ dosMigrated = removed.length;
8324
+ }
8325
+ if (removed.length < doBindings.length) {
8326
+ warnings.push(
8327
+ `\u4EE5\u4E0B DO \u7C7B\u672A\u5728 main \u6587\u4EF6\u4E2D\u627E\u5230\uFF08\u53EF\u80FD\u5728\u5176\u4ED6\u6A21\u5757\uFF0C\u9700\u624B\u52A8\u8FC1\u79FB\uFF09\uFF1A${doBindings.filter((b) => !removed.some((r) => r.className === b.className)).map((b) => b.className).join(", ")}`
8328
+ );
8329
+ }
8330
+ }
8331
+ }
8332
+ let assetsCopied = false;
8333
+ const assetsDir = config.assets?.directory ?? config.site?.bucket;
8334
+ if (assetsDir !== void 0) {
8335
+ try {
8336
+ const copied = await copyAssetsToWeb(sourceDir, assetsDir, outDir);
8337
+ assetsCopied = true;
8338
+ files.push(...copied);
8339
+ } catch (error) {
8340
+ warnings.push(
8341
+ `\u9759\u6001\u8D44\u6E90\u76EE\u5F55 ${assetsDir} \u590D\u5236\u5931\u8D25\uFF08${error instanceof Error ? error.message : String(error)}\uFF09\uFF0C\u8DF3\u8FC7`
8342
+ );
8343
+ }
8344
+ }
8345
+ const mapping = {
8346
+ vars: Object.keys(mergedEnv ?? {}).length,
8347
+ kv: config.kv_namespaces?.length ?? 0,
8348
+ d1: config.d1_databases?.length ?? 0,
8349
+ r2: config.r2_buckets?.length ?? 0,
8350
+ dos: dosMigrated,
8351
+ crons: config.triggers?.crons ?? [],
8352
+ assets: assetsCopied,
8353
+ secretsFromDevVars: Object.keys(devVars).length > 0
8354
+ };
8355
+ const unsupported = unsupportedFromWrangler(config);
8356
+ const migration = renderMigrationReport(config, {
8357
+ outDir,
8358
+ workerName,
8359
+ mapping,
8360
+ unsupported,
8361
+ warnings
8362
+ });
8363
+ await writeFile2(join2(outDir, "MIGRATION.md"), migration, "utf8");
8364
+ files.push("MIGRATION.md");
8365
+ if (!mainCopied) {
8366
+ warnings.push("wrangler.toml \u672A\u58F0\u660E main\uFF1A\u672A\u751F\u6210\u51FD\u6570\uFF0C\u4EC5\u751F\u6210\u914D\u7F6E\u4E0E\u62A5\u544A");
8367
+ }
8368
+ return { outDir, workerName, mapping, unsupported, files, warnings };
8369
+ }
8370
+
8371
+ // packages/cli/src/commands/import.ts
8372
+ function registerImport(program2, ctx) {
8373
+ const importCmd = program2.command("import").description("\u8FC1\u79FB\u5DE5\u5177\uFF1A\u4ECE Cloudflare / \u5176\u4ED6\u5E73\u53F0\u5BFC\u5165\u9879\u76EE\uFF08\u5F53\u524D\u652F\u6301 cf\uFF09");
8374
+ const cfCmd = importCmd.command("cf").description("\u4ECE Cloudflare Workers \u9879\u76EE\u751F\u6210 adep \u9AA8\u67B6\uFF08wrangler.toml \u2192 \u51FD\u6570 + \u7ED1\u5B9A\u58F0\u660E\uFF09");
8375
+ cfCmd.argument("<sourceDir>", "Cloudflare \u9879\u76EE\u6839\uFF08\u542B wrangler.toml\uFF09").option("-o, --out <dir>", "\u8F93\u51FA\u76EE\u5F55\uFF08\u7F3A\u7701 cwd/imported-<workerName>\uFF09").action(async (sourceDir, flags) => {
8376
+ const command = ctx.io("import cf");
8377
+ await command.run(async () => {
8378
+ const options = {};
8379
+ if (flags.out !== void 0) options.out = flags.out;
8380
+ const result = await importCfProject(ctx.cwd, sourceDir, options);
8381
+ command.ok(
8382
+ {
8383
+ outDir: result.outDir,
8384
+ workerName: result.workerName,
8385
+ mapping: result.mapping,
8386
+ unsupported: result.unsupported,
8387
+ warnings: result.warnings,
8388
+ files: result.files
8389
+ },
8390
+ (data) => {
8391
+ const d = data;
8392
+ const lines = [
8393
+ `\u5DF2\u5BFC\u5165 ${d.workerName} \u2192 ${d.outDir}`,
8394
+ `\u6620\u5C04\uFF1Avars ${d.mapping.vars} \xB7 KV ${d.mapping.kv} \xB7 D1 ${d.mapping.d1} \xB7 R2 ${d.mapping.r2}` + (d.mapping.crons.length > 0 ? ` \xB7 cron ${d.mapping.crons.join(",")}` : "") + (d.mapping.assets ? " \xB7 assets\u2192web/" : ""),
8395
+ ...d.unsupported.length > 0 ? [`\u672A\u652F\u6301\uFF1A${d.unsupported.length} \u9879\uFF08\u8BE6\u89C1 MIGRATION.md\uFF09`, ...d.unsupported] : [],
8396
+ ...d.warnings.map((w) => `\u63D0\u793A\uFF1A${w}`),
8397
+ `\u8FC1\u79FB\u62A5\u544A\uFF1A${d.outDir}/MIGRATION.md`
8398
+ ];
8399
+ return lines.join("\n");
8400
+ }
8401
+ );
8402
+ });
8403
+ });
8404
+ }
8405
+
6166
8406
  // packages/cli/src/commands/dev.ts
6167
8407
  function registerDevServers(program2, ctx) {
6168
8408
  program2.command("dev").description("\u672C\u5730\u8C03\u8BD5\uFF1A\u76D1\u542C functions/ \u70ED\u91CD\u8F7D\uFF0Chttp://localhost:<port>/<fnName>").option("-p, --port <port>", "\u76D1\u542C\u7AEF\u53E3\uFF08\u7F3A\u7701 8787\uFF09", "8787").action(async (flags) => {
@@ -6205,9 +8445,9 @@ function registerDevServers(program2, ctx) {
6205
8445
  init_auth();
6206
8446
  init_client();
6207
8447
  init_deploy();
6208
- import { resolve as resolve6 } from "node:path";
8448
+ import { resolve as resolve7 } from "node:path";
6209
8449
  async function resolveProjectId(client, cwd, slug) {
6210
- const resolvedSlug = await resolveSlug(resolve6(cwd), slug);
8450
+ const resolvedSlug = await resolveSlug(resolve7(cwd), slug);
6211
8451
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
6212
8452
  const match = listed.projects.find((project2) => project2.slug === resolvedSlug);
6213
8453
  if (match === void 0) {
@@ -6858,7 +9098,7 @@ function registerHosting(program2, ctx) {
6858
9098
  }
6859
9099
 
6860
9100
  // packages/cli/src/cli.ts
6861
- var requireJson2 = createRequire2(import.meta.url);
9101
+ var requireJson2 = createRequire3(import.meta.url);
6862
9102
  var APP_VERSION = requireJson2("../package.json").version;
6863
9103
  function buildProgram(options = {}) {
6864
9104
  const output = options.output ?? ((line) => process.stdout.write(`${line}
@@ -6871,6 +9111,7 @@ function buildProgram(options = {}) {
6871
9111
  const jsonMode = () => program2.opts()["json"] === true;
6872
9112
  const ctx = createCliContext({ output, paths, cwd, json: jsonMode });
6873
9113
  registerInit(program2, ctx);
9114
+ registerImport(program2, ctx);
6874
9115
  registerDevServers(program2, ctx);
6875
9116
  registerPublish(program2, ctx);
6876
9117
  registerExport(program2, ctx);