@adep/cli 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +34 -14
- package/dist/worker-entry.js +692 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2915,6 +2915,25 @@ var init_env = __esm({
|
|
|
2915
2915
|
});
|
|
2916
2916
|
|
|
2917
2917
|
// packages/cli/src/sim/invoke.ts
|
|
2918
|
+
function resolveFunctionEntry(files, fnName) {
|
|
2919
|
+
const flat = `${fnName}.ts`;
|
|
2920
|
+
if (files[flat] !== void 0) return flat;
|
|
2921
|
+
const directory = `${fnName}/index.ts`;
|
|
2922
|
+
if (files[directory] !== void 0) return directory;
|
|
2923
|
+
return void 0;
|
|
2924
|
+
}
|
|
2925
|
+
function listFunctionNames(files) {
|
|
2926
|
+
const names = /* @__PURE__ */ new Set();
|
|
2927
|
+
for (const key of Object.keys(files)) {
|
|
2928
|
+
const parts = key.split("/");
|
|
2929
|
+
if (parts.length === 1 && parts[0]?.endsWith(".ts")) {
|
|
2930
|
+
names.add(parts[0].slice(0, -3));
|
|
2931
|
+
} else if (parts.length === 2 && parts[1] === "index.ts") {
|
|
2932
|
+
names.add(parts[0]);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
return [...names];
|
|
2936
|
+
}
|
|
2918
2937
|
function createSimInvokeHandler(options) {
|
|
2919
2938
|
return async (method, args) => {
|
|
2920
2939
|
if (method !== "invoke") {
|
|
@@ -2924,7 +2943,10 @@ function createSimInvokeHandler(options) {
|
|
|
2924
2943
|
if (typeof input?.name !== "string" || input.name.length === 0) {
|
|
2925
2944
|
throw new Error("cloud.invoke \u9700\u8981\u76EE\u6807\u51FD\u6570\u540D\uFF08InvokeInput.name\uFF09");
|
|
2926
2945
|
}
|
|
2927
|
-
const targetEntry =
|
|
2946
|
+
const targetEntry = resolveFunctionEntry(options.files, input.name);
|
|
2947
|
+
if (targetEntry === void 0) {
|
|
2948
|
+
throw new Error(`\u76EE\u6807\u51FD\u6570 "${input.name}" \u4E0D\u5B58\u5728`);
|
|
2949
|
+
}
|
|
2928
2950
|
const executeInput = {
|
|
2929
2951
|
project: { id: "local", slug: "local" },
|
|
2930
2952
|
fn: { id: input.name, name: input.name },
|
|
@@ -3130,7 +3152,7 @@ async function startDevServer(options) {
|
|
|
3130
3152
|
} catch {
|
|
3131
3153
|
watcher = void 0;
|
|
3132
3154
|
}
|
|
3133
|
-
const buildInput = async (fnName, url, req) => {
|
|
3155
|
+
const buildInput = async (fnName, entry, url, req) => {
|
|
3134
3156
|
const query = {};
|
|
3135
3157
|
for (const key of new Set(url.searchParams.keys())) {
|
|
3136
3158
|
const values = url.searchParams.getAll(key);
|
|
@@ -3146,7 +3168,7 @@ async function startDevServer(options) {
|
|
|
3146
3168
|
project: { id: "local", slug: config.name },
|
|
3147
3169
|
fn: { id: fnName, name: fnName },
|
|
3148
3170
|
files,
|
|
3149
|
-
entry
|
|
3171
|
+
entry,
|
|
3150
3172
|
request: {
|
|
3151
3173
|
method: req.method ?? "GET",
|
|
3152
3174
|
path: url.pathname,
|
|
@@ -3173,14 +3195,13 @@ async function startDevServer(options) {
|
|
|
3173
3195
|
});
|
|
3174
3196
|
return;
|
|
3175
3197
|
}
|
|
3176
|
-
const entry =
|
|
3177
|
-
|
|
3178
|
-
if (source === void 0) {
|
|
3198
|
+
const entry = resolveFunctionEntry(files, fnName);
|
|
3199
|
+
if (entry === void 0) {
|
|
3179
3200
|
log(`[adep] ${req.method ?? "GET"} /${fnName} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
|
|
3180
3201
|
writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
|
|
3181
3202
|
return;
|
|
3182
3203
|
}
|
|
3183
|
-
const input = await buildInput(fnName, url, req);
|
|
3204
|
+
const input = await buildInput(fnName, entry, url, req);
|
|
3184
3205
|
const startedAt = performance.now();
|
|
3185
3206
|
try {
|
|
3186
3207
|
const result = await executor.execute(input);
|
|
@@ -3655,7 +3676,7 @@ async function startServeServer(options) {
|
|
|
3655
3676
|
hasStatic = false;
|
|
3656
3677
|
}
|
|
3657
3678
|
const files = await collectFunctions2(functionsDir);
|
|
3658
|
-
const functionNames =
|
|
3679
|
+
const functionNames = listFunctionNames(files);
|
|
3659
3680
|
const envText = await readFile7(join11(cwd, ".env.local"), "utf8").catch(() => "");
|
|
3660
3681
|
const env = parseEnvFile(envText);
|
|
3661
3682
|
const simEnv = await loadSimEnv(cwd).catch(() => ({}));
|
|
@@ -3668,7 +3689,7 @@ async function startServeServer(options) {
|
|
|
3668
3689
|
const executor = new WorkerFunctionExecutor();
|
|
3669
3690
|
const dbBundle = runtime.bundle;
|
|
3670
3691
|
const invokeHandler = createSimInvokeHandler({ executor, files });
|
|
3671
|
-
const buildInput = async (fnName, url, req) => {
|
|
3692
|
+
const buildInput = async (fnName, entry, url, req) => {
|
|
3672
3693
|
const query = {};
|
|
3673
3694
|
for (const key of new Set(url.searchParams.keys())) {
|
|
3674
3695
|
const values = url.searchParams.getAll(key);
|
|
@@ -3685,7 +3706,7 @@ async function startServeServer(options) {
|
|
|
3685
3706
|
project: { id: "local", slug: config.name },
|
|
3686
3707
|
fn: { id: fnName, name: fnName },
|
|
3687
3708
|
files,
|
|
3688
|
-
entry
|
|
3709
|
+
entry,
|
|
3689
3710
|
request: {
|
|
3690
3711
|
method: req.method ?? "GET",
|
|
3691
3712
|
path: url.pathname,
|
|
@@ -3742,14 +3763,13 @@ async function startServeServer(options) {
|
|
|
3742
3763
|
});
|
|
3743
3764
|
return;
|
|
3744
3765
|
}
|
|
3745
|
-
const entry =
|
|
3746
|
-
|
|
3747
|
-
if (source === void 0) {
|
|
3766
|
+
const entry = resolveFunctionEntry(files, fnName);
|
|
3767
|
+
if (entry === void 0) {
|
|
3748
3768
|
log(`[serve] ${req.method ?? "GET"} ${pathname} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
|
|
3749
3769
|
writeJson2(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
|
|
3750
3770
|
return;
|
|
3751
3771
|
}
|
|
3752
|
-
const input = await buildInput(fnName, url, req);
|
|
3772
|
+
const input = await buildInput(fnName, entry, url, req);
|
|
3753
3773
|
const startedAt = performance.now();
|
|
3754
3774
|
try {
|
|
3755
3775
|
const result = await executor.execute(input);
|
|
@@ -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
|
+
};
|