@adep/cli 0.0.2 → 0.0.4

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/README.md CHANGED
@@ -391,15 +391,14 @@ export ADEP_HOME=~/.adep
391
391
 
392
392
  ### `adep.config.ts`
393
393
 
394
- `adep init` 生成的项目标识文件,CLI 的 `dev` / `deploy` 按此识别项目:
394
+ `adep init` 生成的项目标识文件,CLI 的 `dev` / `deploy` 按此识别项目(CLI 直接 import 后读 `default` 的字段,无需任何辅助包):
395
395
 
396
396
  ```ts
397
- import { defineConfig } from 'adep/config'
398
-
399
- export default defineConfig({
397
+ // adep 项目配置:CLI(dev / deploy)按 default export 读取(name / functionsDir)。
398
+ export default {
400
399
  name: 'my-app', // 项目名(deploy 的默认 slug)
401
400
  template: 'function', // 模板:empty | function
402
- })
401
+ }
403
402
  ```
404
403
 
405
404
  ---
package/dist/index.js CHANGED
@@ -5568,13 +5568,11 @@ var InitError = class extends Error {
5568
5568
  this.name = "InitError";
5569
5569
  }
5570
5570
  };
5571
- var ADEP_CONFIG = (name, template) => `import { defineConfig } from 'adep/config'
5572
-
5573
- // adep \u9879\u76EE\u914D\u7F6E\uFF1ACLI\uFF08dev / deploy\uFF09\u4E0E\u5E73\u53F0\u6309\u6B64\u8BC6\u522B\u9879\u76EE\u3002
5574
- export default defineConfig({
5571
+ var ADEP_CONFIG = (name, template) => `// adep \u9879\u76EE\u914D\u7F6E\uFF1ACLI\uFF08dev / deploy\uFF09\u6309 default export \u8BFB\u53D6\uFF08name / functionsDir\uFF09\u3002
5572
+ export default {
5575
5573
  name: '${name}',
5576
5574
  template: '${template}',
5577
- })
5575
+ }
5578
5576
  `;
5579
5577
  var README = (name, template) => `# ${name}
5580
5578
 
@@ -5583,13 +5581,13 @@ AgentDeploy \u9879\u76EE\uFF08\u6A21\u677F\uFF1A${template}\uFF09\u3002
5583
5581
  - \`adep dev\`\uFF1A\u672C\u5730\u8C03\u8BD5\uFF08CLI-002 \u4EA4\u4ED8\uFF09
5584
5582
  - \`adep deploy\`\uFF1A\u53D1\u5E03\uFF08CLI-003 \u4EA4\u4ED8\uFF09
5585
5583
  `;
5586
- var HELLO_FUNCTION = `import { defineFunction } from 'adep/function'
5587
-
5588
- // \u793A\u4F8B\u51FD\u6570\uFF1Aadep deploy \u540E\u7ECF https://<project-slug>.<platform-domain>/hello \u89E6\u53D1\u3002
5589
- export default defineFunction(async (ctx) => {
5584
+ var HELLO_FUNCTION = `// \u793A\u4F8B\u51FD\u6570\uFF1Aadep deploy \u540E\u7ECF https://<project-slug>.<platform-domain>/hello \u89E6\u53D1\u3002
5585
+ // \u7528\u6237\u51FD\u6570\u5373 functions/ \u4E0B\u7684\u72EC\u7ACB\u6587\u4EF6\uFF0C\u9ED8\u8BA4\u5BFC\u51FA (ctx) => Response \u5F62\u72B6\u7684\u5904\u7406\u5668
5586
+ //\uFF08ctx \u5951\u7EA6\u89C1\u5E73\u53F0\u7684 FunctionContext\uFF1Amethod / path / query / headers / body / cloud.*\uFF09\u3002
5587
+ export default async (ctx) => {
5590
5588
  const name = (ctx.query['name'] as string | undefined) ?? 'world'
5591
5589
  return { message: \`hello \${name}\` }
5592
- })
5590
+ }
5593
5591
  `;
5594
5592
  var FUNCTION_INDEX = `// \u51FD\u6570\u6A21\u5757\u5165\u53E3\uFF1A\u9879\u76EE\u91CC\u7684\u6BCF\u4E2A\u51FD\u6570\u662F functions/ \u4E0B\u7684\u72EC\u7ACB\u6587\u4EF6\uFF0C
5595
5593
  // \u9ED8\u8BA4\u5BFC\u51FA (ctx) => Response \u5F62\u72B6\u7684\u5904\u7406\u5668\uFF08\u5951\u7EA6\u89C1 @adep/types \u7684 FunctionContext\uFF09\u3002
@@ -0,0 +1,692 @@
1
+ // packages/runtime/src/functions/runtime/worker-entry.ts
2
+ import { parentPort, workerData } from "node:worker_threads";
3
+ import { createRequire } from "node:module";
4
+ import { join } from "node:path";
5
+
6
+ // packages/runtime/src/functions/runtime/cloud-container.ts
7
+ var KNOWN_CAPABILITY_HINTS = {
8
+ db: {
9
+ code: "DB_NOT_PROVISIONED",
10
+ 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"
11
+ },
12
+ storage: {
13
+ code: "STORAGE_NOT_AVAILABLE",
14
+ 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"
15
+ },
16
+ fetch: {
17
+ code: "FN_FETCH_DISABLED",
18
+ 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"
19
+ },
20
+ realtime: {
21
+ code: "REALTIME_NOT_AVAILABLE",
22
+ 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"
23
+ }
24
+ };
25
+ var CapabilityNotRegisteredError = class extends Error {
26
+ code;
27
+ constructor(code, message) {
28
+ super(message);
29
+ this.code = code;
30
+ this.name = "CapabilityNotRegisteredError";
31
+ }
32
+ };
33
+ function createCloud(registrations) {
34
+ const store = registrations;
35
+ return new Proxy(
36
+ {},
37
+ {
38
+ get(_target, prop) {
39
+ if (typeof prop !== "string") return void 0;
40
+ if (!store.has(prop)) {
41
+ const hint = KNOWN_CAPABILITY_HINTS[prop];
42
+ throw new CapabilityNotRegisteredError(
43
+ hint?.code ?? "CAPABILITY_NOT_REGISTERED",
44
+ hint?.message ?? `\u80FD\u529B "${prop}" \u672A\u6CE8\u518C\uFF1A\u8BF7\u5728\u51FD\u6570\u6240\u5728\u9879\u76EE\u5B89\u88C5\u5BF9\u5E94\u80FD\u529B`
45
+ );
46
+ }
47
+ return store.get(prop);
48
+ },
49
+ has: () => true
50
+ // 支持 'db' in ctx.cloud 形态
51
+ }
52
+ );
53
+ }
54
+ function createCloudContainer() {
55
+ const registry = /* @__PURE__ */ new Map();
56
+ const names = /* @__PURE__ */ new Set();
57
+ let cloud = null;
58
+ const rebuild = () => {
59
+ cloud = createCloud(registry);
60
+ };
61
+ rebuild();
62
+ return {
63
+ register(name, impl) {
64
+ registry.set(name, impl);
65
+ names.add(name);
66
+ rebuild();
67
+ },
68
+ unregister(name) {
69
+ registry.delete(name);
70
+ names.delete(name);
71
+ rebuild();
72
+ },
73
+ get names() {
74
+ return [...names];
75
+ },
76
+ get cloud() {
77
+ return cloud;
78
+ }
79
+ };
80
+ }
81
+
82
+ // packages/runtime/src/functions/runtime/sandbox.ts
83
+ import vm from "node:vm";
84
+ import * as nodeModule from "node:module";
85
+
86
+ // packages/runtime/src/functions/runtime/exports.ts
87
+ function transformModule(code) {
88
+ let out = code;
89
+ const named = [];
90
+ out = out.replace(/(^|\n)(\s*)export\s+default\s+/g, "$1$2module.default = ");
91
+ out = out.replace(
92
+ /import\s*\{([^}]*)\}\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
93
+ (_match, names, source) => `const {${names}} = require(${source})`
94
+ );
95
+ out = out.replace(
96
+ /import\s*\*\s*as\s*([A-Za-z_$][\w$]*)\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
97
+ (_match, name, source) => `const ${name} = require(${source})`
98
+ );
99
+ out = out.replace(
100
+ /import\s+([A-Za-z_$][\w$]*)\s+from\s*(['"][^'"]*['"])[ \t]*;?/g,
101
+ (_match, name, source) => `const ${name} = require(${source})`
102
+ );
103
+ out = out.replace(
104
+ /export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
105
+ (_match, kw, name) => {
106
+ named.push(name);
107
+ return `${kw} ${name}`;
108
+ }
109
+ );
110
+ out = out.replace(
111
+ /export\s+(async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/g,
112
+ (_match, asyncKw, name) => {
113
+ named.push(name);
114
+ return `${asyncKw ?? ""}function ${name}`;
115
+ }
116
+ );
117
+ out = out.replace(/export\s+class\s+([A-Za-z_$][\w$]*)/g, (_match, name) => {
118
+ named.push(name);
119
+ return `class ${name}`;
120
+ });
121
+ if (named.length > 0) {
122
+ out += `
123
+ ;Object.assign(exports, { ${named.join(", ")} })`;
124
+ }
125
+ return out;
126
+ }
127
+
128
+ // packages/runtime/src/functions/runtime/sandbox.ts
129
+ var bunTranspiler;
130
+ function transpile(code) {
131
+ const bun = globalThis["Bun"];
132
+ if (bun?.Transpiler !== void 0) {
133
+ bunTranspiler ??= new bun.Transpiler({ loader: "ts" });
134
+ return bunTranspiler.transformSync(code);
135
+ }
136
+ const stripTypeScriptTypes2 = nodeModule.stripTypeScriptTypes;
137
+ if (typeof stripTypeScriptTypes2 === "function") {
138
+ return stripTypeScriptTypes2(code, { mode: "strip" });
139
+ }
140
+ return code;
141
+ }
142
+ function transformExports(code) {
143
+ return transformModule(code);
144
+ }
145
+ var SANDBOX_BUILTIN_REJECTED = "FN_SANDBOX_BUILTIN_BLOCKED";
146
+ function resolveModulePath(fromDir, request, files) {
147
+ if (!request.startsWith("./") && !request.startsWith("../")) return null;
148
+ const base = joinPosix(fromDir, request);
149
+ const candidates = [base, `${base}.ts`, `${base}.js`, `${base}/index.ts`, `${base}/index.js`];
150
+ for (const candidate of candidates) {
151
+ const normalized = normalizePosix(candidate);
152
+ if (files[normalized] !== void 0) return normalized;
153
+ }
154
+ return null;
155
+ }
156
+ function joinPosix(dir, request) {
157
+ const parts = [...dir.split("/"), ...request.split("/")];
158
+ const stack = [];
159
+ for (const part of parts) {
160
+ if (part === "" || part === ".") continue;
161
+ if (part === "..") stack.pop();
162
+ else stack.push(part);
163
+ }
164
+ return stack.join("/");
165
+ }
166
+ function normalizePosix(p) {
167
+ return joinPosix("", p);
168
+ }
169
+ function loadModule(path, files, sandboxGlobals, cache, resolveBare, bareCache) {
170
+ const cached = cache.get(path);
171
+ if (cached !== void 0) return cached;
172
+ const source = files[path];
173
+ if (source === void 0) {
174
+ throw new Error(`\u6A21\u5757\u4E0D\u5B58\u5728\uFF1A${path}`);
175
+ }
176
+ const exports = {};
177
+ cache.set(path, exports);
178
+ const dir = path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
179
+ const module = { exports, default: void 0 };
180
+ const require2 = (request) => {
181
+ const resolved = resolveModulePath(dir, request, files);
182
+ if (resolved !== null) {
183
+ return loadModule(resolved, files, sandboxGlobals, cache, resolveBare, bareCache);
184
+ }
185
+ if (resolveBare !== void 0 && !request.startsWith("./") && !request.startsWith("../")) {
186
+ const cachedModule = bareCache?.get(request);
187
+ if (cachedModule !== void 0) return cachedModule;
188
+ const loaded = resolveBare(request);
189
+ bareCache?.set(request, loaded);
190
+ return loaded;
191
+ }
192
+ const error = new Error(
193
+ `\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`
194
+ );
195
+ error.code = SANDBOX_BUILTIN_REJECTED;
196
+ throw error;
197
+ };
198
+ let transformed;
199
+ try {
200
+ transformed = transformExports(transpile(source));
201
+ } catch (error) {
202
+ const rawMessage = error instanceof Error ? error.message : String(error);
203
+ const stack = error.stack;
204
+ const line = typeof stack === "string" ? /(?:^|\n):(\d+)(?:\n|$)/.exec(stack)?.[1] : void 0;
205
+ const location = line === void 0 ? path : `${path}:${line}`;
206
+ const wrapped = new Error(`\u6E90\u7801\u8BED\u6CD5\u9519\u8BEF\uFF08${location}\uFF09\uFF1A${rawMessage}`, { cause: error });
207
+ const code = error.code;
208
+ if (typeof code === "string") wrapped.code = code;
209
+ throw wrapped;
210
+ }
211
+ const wrapper = vm.runInNewContext(
212
+ `(function (module, exports, require) { ${transformed}
213
+ })`,
214
+ vm.createContext({ ...sandboxGlobals }),
215
+ { filename: path }
216
+ );
217
+ wrapper(module, exports, require2);
218
+ if (module.default !== void 0 && exports["default"] === void 0) {
219
+ exports["default"] = module.default;
220
+ }
221
+ return exports;
222
+ }
223
+ function loadFunctionModule(files, entry, sandboxGlobals, resolveBare) {
224
+ const cache = /* @__PURE__ */ new Map();
225
+ const bareCache = /* @__PURE__ */ new Map();
226
+ const entryExports = loadModule(entry, files, sandboxGlobals, cache, resolveBare, bareCache);
227
+ const handler = entryExports["default"];
228
+ if (typeof handler !== "function") {
229
+ throw new Error(`\u5165\u53E3\u6587\u4EF6 ${entry} \u7F3A\u5C11 default \u5BFC\u51FA\u7684\u51FD\u6570`);
230
+ }
231
+ return { handler };
232
+ }
233
+
234
+ // packages/runtime/src/functions/runtime/sandbox-fetch.ts
235
+ var SandboxFetchError = class extends Error {
236
+ code;
237
+ constructor(code, message) {
238
+ super(message);
239
+ this.name = "SandboxFetchError";
240
+ this.code = code;
241
+ }
242
+ };
243
+ var DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
244
+ var defaultFetch = (url, init) => (
245
+ // 真实 Response 与内部 ResponseLike 结构性一致;getReader 的多态签名差异属纯类型问题,运行语义等价。
246
+ globalThis.fetch(url, init)
247
+ );
248
+ function isHostAllowed(host, rules) {
249
+ const h = host.toLocaleLowerCase();
250
+ return rules.some((raw) => {
251
+ const rule = raw.trim().toLocaleLowerCase();
252
+ if (rule.startsWith("*.")) {
253
+ const base = rule.slice(2);
254
+ return h === base || h.endsWith(`.${base}`);
255
+ }
256
+ return h === rule;
257
+ });
258
+ }
259
+ var FORBIDDEN = (url) => new SandboxFetchError(
260
+ "FN_FETCH_FORBIDDEN",
261
+ `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`
262
+ );
263
+ var TOO_LARGE = new SandboxFetchError(
264
+ "FN_FETCH_TOO_LARGE",
265
+ "cloud.fetch \u54CD\u5E94\u4F53\u8D85\u8FC7\u4E0A\u9650\uFF08FN_FETCH_TOO_LARGE\uFF09"
266
+ );
267
+ function headersToRecord(headers) {
268
+ const out = {};
269
+ if (headers === void 0 || headers === null) return out;
270
+ if (typeof headers.forEach === "function") {
271
+ ;
272
+ headers.forEach((value, key) => {
273
+ out[String(key).toLocaleLowerCase()] = String(value);
274
+ });
275
+ return out;
276
+ }
277
+ for (const [key, value] of Object.entries(headers)) {
278
+ out[key.toLocaleLowerCase()] = String(value);
279
+ }
280
+ return out;
281
+ }
282
+ function contentLength(res) {
283
+ const headers = res.headers;
284
+ if (headers === void 0 || headers === null) return null;
285
+ if (typeof headers.get === "function") {
286
+ const raw2 = headers.get?.("content-length");
287
+ if (raw2 === void 0 || raw2 === null || raw2.trim() === "") return null;
288
+ const n2 = Number(raw2);
289
+ return Number.isFinite(n2) && n2 >= 0 ? n2 : null;
290
+ }
291
+ const record = headers;
292
+ const raw = record["content-length"] ?? record["Content-Length"];
293
+ if (raw === void 0 || raw === null) return null;
294
+ const n = Number(raw);
295
+ return Number.isFinite(n) && n >= 0 ? n : null;
296
+ }
297
+ function concatChunks(chunks, total) {
298
+ const merged = new Uint8Array(total);
299
+ let offset = 0;
300
+ for (const chunk of chunks) {
301
+ merged.set(chunk, offset);
302
+ offset += chunk.byteLength;
303
+ }
304
+ return merged;
305
+ }
306
+ async function readBodyBytes(res, maxBytes) {
307
+ if (maxBytes > 0) {
308
+ const cl = contentLength(res);
309
+ if (cl !== null && cl > maxBytes) throw TOO_LARGE;
310
+ }
311
+ const body = res.body;
312
+ if (body !== void 0 && body !== null) {
313
+ const reader = body.getReader();
314
+ const chunks = [];
315
+ let total = 0;
316
+ for (; ; ) {
317
+ const { done, value } = await reader.read();
318
+ if (done) break;
319
+ if (value !== void 0) {
320
+ total += value.byteLength;
321
+ if (maxBytes > 0 && total > maxBytes) throw TOO_LARGE;
322
+ chunks.push(value);
323
+ }
324
+ }
325
+ return concatChunks(chunks, total);
326
+ }
327
+ if (typeof res.arrayBuffer === "function") {
328
+ const buffer = await res.arrayBuffer();
329
+ const bytes2 = new Uint8Array(buffer);
330
+ if (maxBytes > 0 && bytes2.byteLength > maxBytes) throw TOO_LARGE;
331
+ return bytes2;
332
+ }
333
+ const text = await res.text();
334
+ const bytes = encoder.encode(text);
335
+ if (maxBytes > 0 && bytes.byteLength > maxBytes) throw TOO_LARGE;
336
+ return bytes;
337
+ }
338
+ var encoder = new TextEncoder();
339
+ function errorMessageOf(error) {
340
+ if (error instanceof Error) return error.message;
341
+ return String(error);
342
+ }
343
+ function normalizeResponse(res, maxBytes) {
344
+ let cached = null;
345
+ let cachedPromise = null;
346
+ const readCached = () => {
347
+ if (cached !== null) return Promise.resolve(cached);
348
+ cachedPromise ??= readBodyBytes(res, maxBytes).then((bytes) => {
349
+ cached = bytes;
350
+ return bytes;
351
+ });
352
+ return cachedPromise;
353
+ };
354
+ const read = () => readCached();
355
+ return {
356
+ ok: res.ok,
357
+ status: res.status,
358
+ statusText: res.statusText,
359
+ headers: headersToRecord(res.headers),
360
+ text: async () => decoder.decode(await read()),
361
+ arrayBuffer: async () => bufferViewToArrayBuffer(await read()),
362
+ json: async () => JSON.parse(decoder.decode(await read()))
363
+ };
364
+ }
365
+ var decoder = new TextDecoder();
366
+ function bufferViewToArrayBuffer(bytes) {
367
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
368
+ }
369
+ function createSandboxFetch(options) {
370
+ const fetchImpl = options.fetchImpl ?? defaultFetch;
371
+ const { allowlist, timeoutMs } = options;
372
+ const maxBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
373
+ return async (url, init) => {
374
+ let parsed;
375
+ try {
376
+ parsed = new URL(url);
377
+ } catch {
378
+ throw new SandboxFetchError("FN_FETCH_INVALID_URL", `cloud.fetch \u6536\u5230\u975E\u6CD5 URL"${url}"`);
379
+ }
380
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw FORBIDDEN(url);
381
+ if (!isHostAllowed(parsed.hostname, allowlist)) throw FORBIDDEN(url);
382
+ const controller = new AbortController();
383
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
384
+ const signals = [controller.signal];
385
+ if (init?.signal !== void 0) signals.push(init.signal);
386
+ const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
387
+ try {
388
+ let res;
389
+ try {
390
+ res = await fetchImpl(url, { ...init, signal });
391
+ } catch (error) {
392
+ if (controller.signal.aborted) {
393
+ throw new SandboxFetchError(
394
+ "FN_FETCH_TIMEOUT",
395
+ `cloud.fetch \u8BF7\u6C42\u8D85\u65F6\uFF08\u8D85\u8FC7 ${timeoutMs}ms\uFF09`
396
+ );
397
+ }
398
+ if (init?.signal?.aborted === true) {
399
+ throw new SandboxFetchError("FN_FETCH_ABORTED", "cloud.fetch \u8BF7\u6C42\u88AB\u8C03\u7528\u65B9\u4E2D\u6B62");
400
+ }
401
+ throw new SandboxFetchError(
402
+ "FN_FETCH_FAILED",
403
+ `cloud.fetch \u8BF7\u6C42\u5931\u8D25\uFF1A${errorMessageOf(error)}`
404
+ );
405
+ }
406
+ return normalizeResponse(res, maxBytes);
407
+ } finally {
408
+ clearTimeout(timer);
409
+ }
410
+ };
411
+ }
412
+
413
+ // packages/runtime/src/shared/capability-keys.ts
414
+ var RPC_CAPABILITY_KEY = "__adepRpc";
415
+ var CHAIN_CAPABILITY_KEY = "__adepChain";
416
+ var DB_RPC = {
417
+ /** 直通方法(如 query):`(method=query, args=[sql, params])`。 */
418
+ query: "query",
419
+ /** 读取 owned 表变更流(DB-006):`(method=changes, args=[table, query])`。 */
420
+ changes: "changes",
421
+ /** 开启事务:`begin → txId`。 */
422
+ begin: "begin",
423
+ /** 提交事务:`commit, args=[txId]`。 */
424
+ commit: "commit",
425
+ /** 回滚事务:`rollback, args=[txId]`。 */
426
+ rollback: "rollback",
427
+ /** 执行一条链:`chain, args=[ChainRequest]`。 */
428
+ chain: "chain"
429
+ };
430
+
431
+ // packages/runtime/src/functions/runtime/chain.ts
432
+ function isChainCapability(value) {
433
+ if (typeof value !== "object" || value === null) return false;
434
+ const spec = value[CHAIN_CAPABILITY_KEY];
435
+ return typeof spec === "object" && spec !== null && Array.isArray(spec.stepMethods) && Array.isArray(spec.terminalMethods);
436
+ }
437
+ function createChainClient(capability, port, pending, nextId, spec) {
438
+ const call = (method, args) => new Promise((resolve, reject) => {
439
+ const id = nextId();
440
+ pending.set(id, { resolve, reject });
441
+ port.postMessage({ type: "rpc", id, capability, method, args });
442
+ });
443
+ const makeChainable = (rootArgs, steps, txId) => new Proxy(
444
+ {},
445
+ {
446
+ get(_target, prop) {
447
+ if (typeof prop !== "string") return void 0;
448
+ if (spec.stepMethods.includes(prop)) {
449
+ return (...args) => makeChainable(rootArgs, [...steps, { method: prop, args }], txId);
450
+ }
451
+ if (spec.terminalMethods.includes(prop)) {
452
+ return (...args) => call(DB_RPC.chain, [
453
+ {
454
+ rootArgs,
455
+ steps,
456
+ terminal: prop,
457
+ terminalArgs: args,
458
+ ...txId === void 0 ? {} : { txId }
459
+ }
460
+ ]);
461
+ }
462
+ return void 0;
463
+ }
464
+ }
465
+ );
466
+ const makeRoot = (txId) => new Proxy(
467
+ {},
468
+ {
469
+ get(_target, prop) {
470
+ if (typeof prop !== "string") return void 0;
471
+ if (prop === spec.rootMethod) {
472
+ return (...rootArgs) => makeChainable(rootArgs, [], txId);
473
+ }
474
+ if (spec.directMethods.includes(prop)) {
475
+ return (...args) => call(prop, args);
476
+ }
477
+ if (prop === spec.transactionMethod) {
478
+ return (fn) => orchestrateTransaction(fn, txId);
479
+ }
480
+ return void 0;
481
+ }
482
+ }
483
+ );
484
+ const orchestrateTransaction = async (fn, _outerTxId) => {
485
+ const txId = await call(DB_RPC.begin, []);
486
+ const tx = makeRoot(txId);
487
+ const settle = async (commit) => {
488
+ await call(commit ? DB_RPC.commit : DB_RPC.rollback, [txId]).catch(() => void 0);
489
+ };
490
+ try {
491
+ const result = await fn(tx);
492
+ await settle(true);
493
+ return result;
494
+ } catch (error) {
495
+ await settle(false);
496
+ throw error;
497
+ }
498
+ };
499
+ return makeRoot(void 0);
500
+ }
501
+
502
+ // packages/runtime/src/functions/deps/manifest.ts
503
+ function splitBareSpecifier(request) {
504
+ if (request.startsWith("@")) {
505
+ const segments = request.split("/");
506
+ return segments.slice(0, 2).join("/");
507
+ }
508
+ return request.split("/")[0];
509
+ }
510
+
511
+ // packages/runtime/src/functions/runtime/worker-entry.ts
512
+ function isRpcCapability(value) {
513
+ return typeof value === "object" && value !== null && value[RPC_CAPABILITY_KEY] === true;
514
+ }
515
+ function createRpcClient(capability, port, pending, nextId) {
516
+ return new Proxy(
517
+ {},
518
+ {
519
+ get(_target, method) {
520
+ if (typeof method !== "string") return void 0;
521
+ return (...args) => {
522
+ const id = nextId();
523
+ return new Promise((resolve, reject) => {
524
+ pending.set(id, { resolve, reject });
525
+ port.postMessage({ type: "rpc", id, capability, method, args });
526
+ });
527
+ };
528
+ }
529
+ }
530
+ );
531
+ }
532
+ function errorMessageOf2(error) {
533
+ if (error instanceof Error) return error.message;
534
+ if (typeof error === "object" && error !== null && "message" in error) {
535
+ const message = error.message;
536
+ if (typeof message === "string") return message;
537
+ }
538
+ return String(error);
539
+ }
540
+ function escapeRegExp(text) {
541
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
542
+ }
543
+ function firstUserFrame(stack, files) {
544
+ for (const key of Object.keys(files)) {
545
+ const match = new RegExp(
546
+ `(?<![\\w$/.])${escapeRegExp(key)}:(\\d+)(?::(\\d+))?(?::(\\d+))?`
547
+ ).exec(stack);
548
+ if (match !== null) {
549
+ return match[2] === void 0 ? `${key}:${match[1]}` : `${key}:${match[1]}:${match[2]}`;
550
+ }
551
+ }
552
+ return void 0;
553
+ }
554
+ function errorMessageWithLocation(error, files) {
555
+ const message = errorMessageOf2(error);
556
+ const stack = error.stack;
557
+ if (typeof stack !== "string") return message;
558
+ const frame = firstUserFrame(stack, files);
559
+ return frame === void 0 ? message : `${message}\uFF08${frame}\uFF09`;
560
+ }
561
+ function createBareResolver(deps) {
562
+ const platformRequire = createRequire(import.meta.url);
563
+ const depsRequire = deps.dir === null ? null : createRequire(join(deps.dir, "__deps__.js"));
564
+ return (request) => {
565
+ const root = splitBareSpecifier(request);
566
+ if (deps.builtin.includes(root)) return platformRequire(request);
567
+ if (deps.custom.includes(root)) {
568
+ if (depsRequire === null) {
569
+ 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`);
570
+ }
571
+ try {
572
+ return depsRequire(request);
573
+ } catch (error2) {
574
+ const message = errorMessageOf2(error2);
575
+ throw new Error(
576
+ `\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}`,
577
+ { cause: error2 }
578
+ );
579
+ }
580
+ }
581
+ const error = new Error(
582
+ `\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`
583
+ );
584
+ error.code = SANDBOX_BUILTIN_REJECTED;
585
+ throw error;
586
+ };
587
+ }
588
+ function runWorker(input, port) {
589
+ const emit = (level, args) => {
590
+ port.postMessage({ type: "log", level, message: args.map(String).join(" ") });
591
+ };
592
+ const forwardedConsole = {
593
+ log: (...args) => emit("log", args),
594
+ error: (...args) => emit("error", args),
595
+ warn: (...args) => emit("warn", args)
596
+ };
597
+ const container = createCloudContainer();
598
+ const pending = /* @__PURE__ */ new Map();
599
+ let rpcId = 0;
600
+ port.on?.((message) => {
601
+ const reply = message;
602
+ if (reply?.type !== "rpc-response" || typeof reply.id !== "number") return;
603
+ const entry = pending.get(reply.id);
604
+ if (entry === void 0) return;
605
+ pending.delete(reply.id);
606
+ if (reply.ok === true) entry.resolve(reply.result);
607
+ else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
608
+ });
609
+ for (const capability of input.capabilities ?? []) {
610
+ container.register(
611
+ capability.name,
612
+ isChainCapability(capability.value) ? createChainClient(
613
+ capability.name,
614
+ port,
615
+ pending,
616
+ () => ++rpcId,
617
+ capability.value[CHAIN_CAPABILITY_KEY]
618
+ ) : isRpcCapability(capability.value) ? createRpcClient(capability.name, port, pending, () => ++rpcId) : capability.value
619
+ );
620
+ }
621
+ const sandboxGlobals = {
622
+ console: forwardedConsole
623
+ };
624
+ if (input.env !== void 0) {
625
+ sandboxGlobals["process"] = { env: input.env };
626
+ }
627
+ if (input.fetch !== void 0) {
628
+ const sandboxFetch = createSandboxFetch({
629
+ allowlist: input.fetch.allowlist,
630
+ timeoutMs: input.fetch.timeoutMs,
631
+ ...input.fetch.maxResponseBytes === void 0 ? {} : { maxResponseBytes: input.fetch.maxResponseBytes }
632
+ });
633
+ sandboxGlobals["fetch"] = sandboxFetch;
634
+ container.register("fetch", sandboxFetch);
635
+ }
636
+ const ctx = {
637
+ method: input.request.method,
638
+ path: input.request.path,
639
+ query: input.request.query,
640
+ headers: input.request.headers,
641
+ ...input.request.body === void 0 ? {} : { body: input.request.body },
642
+ files: input.request.files ?? [],
643
+ cloud: container.cloud,
644
+ user: input.request.user ?? null
645
+ };
646
+ try {
647
+ const { handler } = loadFunctionModule(
648
+ input.files,
649
+ input.entry,
650
+ sandboxGlobals,
651
+ input.deps === void 0 ? void 0 : createBareResolver(input.deps)
652
+ );
653
+ const result = Promise.resolve(handler(ctx));
654
+ void result.then(
655
+ (value) => {
656
+ port.postMessage({ type: "result", body: value === void 0 ? null : value });
657
+ return void 0;
658
+ },
659
+ (error) => {
660
+ port.postMessage({
661
+ type: "error",
662
+ message: errorMessageWithLocation(error, input.files),
663
+ code: error.code,
664
+ // FN-011:函数抛错可携带 status(4xx/5xx),透传给执行器落 ExecutorError.status。
665
+ status: error.status
666
+ });
667
+ return void 0;
668
+ }
669
+ );
670
+ } catch (error) {
671
+ port.postMessage({
672
+ type: "error",
673
+ message: errorMessageWithLocation(error, input.files),
674
+ code: error.code,
675
+ status: error.status
676
+ });
677
+ }
678
+ }
679
+ var workerPort = parentPort;
680
+ if (workerPort !== null && workerData !== void 0) {
681
+ const port = {
682
+ // eslint-disable-next-line unicorn/require-post-message-target-origin -- node worker_threads 无 targetOrigin 语义
683
+ postMessage: (message) => workerPort.postMessage(message),
684
+ on: (listener) => {
685
+ workerPort.on("message", (value) => listener(value));
686
+ }
687
+ };
688
+ runWorker(workerData, port);
689
+ }
690
+ export {
691
+ runWorker
692
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adep/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "description": "`adep` 命令行工具包位:登录 / 初始化 / 本地调试 / 部署 / 数据库维护 / 云存储 / 静态托管 / 微前端组件(widget),实现见任务单 CLI-001 ~ CLI-003 与 FE-002",
6
6
  "bin": {
@@ -14,8 +14,8 @@
14
14
  "esbuild": "0.25.12"
15
15
  },
16
16
  "devDependencies": {
17
- "@adep/runtime": "0.1.1",
18
- "@adep/types": "0.1.1"
17
+ "@adep/runtime": "0.1.2",
18
+ "@adep/types": "0.1.3"
19
19
  },
20
20
  "scripts": {
21
21
  "test": "vitest run",