@adep/cli 0.1.0 → 0.1.2
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 +2623 -420
- package/dist/vite.js +1435 -177
- package/dist/worker-entry.js +43 -12
- package/package.json +15 -29
- package/src/index.ts +0 -8
package/dist/vite.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
// src/vite.ts
|
|
2
|
-
import {
|
|
3
|
-
import { resolve as resolve3 } from "node:path";
|
|
1
|
+
// packages/cli/src/vite.ts
|
|
2
|
+
import { adepPlugin } from "@adep/vite-plugin";
|
|
4
3
|
|
|
5
|
-
// src/dev.ts
|
|
4
|
+
// packages/cli/src/dev.ts
|
|
6
5
|
import { createServer } from "node:http";
|
|
7
6
|
import { watch } from "node:fs";
|
|
8
7
|
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
|
|
9
|
-
import { basename, join as
|
|
8
|
+
import { basename, join as join8, resolve as resolve2 } from "node:path";
|
|
10
9
|
|
|
11
|
-
//
|
|
10
|
+
// packages/runtime/src/shared/capability-keys.ts
|
|
12
11
|
var RPC_CAPABILITY_KEY = "__adepRpc";
|
|
13
12
|
var CHAIN_CAPABILITY_KEY = "__adepChain";
|
|
14
13
|
var DB_RPC = {
|
|
15
14
|
/** 直通方法(如 query):`(method=query, args=[sql, params])`。 */
|
|
16
15
|
query: "query",
|
|
16
|
+
/** 写路径(CF-013):`(method=writeQuery, args=[sql, params])` → `{ changes }`。 */
|
|
17
|
+
writeQuery: "writeQuery",
|
|
17
18
|
/** 读取 owned 表变更流(DB-006):`(method=changes, args=[table, query])`。 */
|
|
18
19
|
changes: "changes",
|
|
19
20
|
/** 开启事务:`begin → txId`。 */
|
|
@@ -40,7 +41,7 @@ var REALTIME_CAPABILITY_METHODS = [
|
|
|
40
41
|
"unsubscribe"
|
|
41
42
|
];
|
|
42
43
|
|
|
43
|
-
//
|
|
44
|
+
// packages/runtime/src/shared/executor-runtime.ts
|
|
44
45
|
var ExecutorError = class extends Error {
|
|
45
46
|
constructor(status, code, message) {
|
|
46
47
|
super(message);
|
|
@@ -60,19 +61,38 @@ function normalizeHttpStatus(status) {
|
|
|
60
61
|
return isHttpStatus(status) ? status : 500;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
//
|
|
64
|
+
// packages/runtime/src/shared/http-envelope.ts
|
|
65
|
+
function isAdepHttpEnvelope(value) {
|
|
66
|
+
if (typeof value !== "object" || value === null) return false;
|
|
67
|
+
const envelope = value.__adepHttp;
|
|
68
|
+
if (typeof envelope !== "object" || envelope === null) return false;
|
|
69
|
+
const status = envelope.status;
|
|
70
|
+
return typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599;
|
|
71
|
+
}
|
|
72
|
+
function writeEnvelopeResponse(res, envelope) {
|
|
73
|
+
const { status, headers, body } = envelope.__adepHttp;
|
|
74
|
+
const noBody = status >= 100 && status < 200 || status === 204 || status === 205;
|
|
75
|
+
res.writeHead(status, { "content-type": "application/json", ...headers });
|
|
76
|
+
if (noBody) {
|
|
77
|
+
res.end();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
res.end(JSON.stringify(body === void 0 ? null : body));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// packages/runtime/src/functions/runtime/worker-executor.ts
|
|
64
84
|
import { readFileSync } from "node:fs";
|
|
65
85
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
66
86
|
import { dirname, join } from "node:path";
|
|
67
87
|
import { Worker } from "node:worker_threads";
|
|
68
88
|
|
|
69
|
-
//
|
|
89
|
+
// packages/runtime/src/functions/deps/resolve.ts
|
|
70
90
|
import { resolve } from "node:path";
|
|
71
91
|
|
|
72
|
-
//
|
|
92
|
+
// packages/runtime/src/functions/deps/manifest.ts
|
|
73
93
|
import { createHash } from "node:crypto";
|
|
74
94
|
|
|
75
|
-
//
|
|
95
|
+
// packages/runtime/src/functions/domain.ts
|
|
76
96
|
var MAX_TOTAL_SOURCE_BYTES = 256 * 1024;
|
|
77
97
|
var FnError = class extends Error {
|
|
78
98
|
status;
|
|
@@ -85,7 +105,7 @@ var FnError = class extends Error {
|
|
|
85
105
|
}
|
|
86
106
|
};
|
|
87
107
|
|
|
88
|
-
//
|
|
108
|
+
// packages/runtime/src/functions/deps/manifest.ts
|
|
89
109
|
var PACKAGE_NAME_PATTERN = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-._~]+$/;
|
|
90
110
|
var COMPARATOR_PATTERN = /^(?:\^|~|>=|<=|>|<|=)?\d+(?:\.(?:\d+|x|X|\*)){0,2}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
|
|
91
111
|
var MANIFEST_MAX_DEPS = 100;
|
|
@@ -162,12 +182,19 @@ function classifyDependencies(dependencies, builtin) {
|
|
|
162
182
|
}
|
|
163
183
|
return { builtinDeps, customDeps };
|
|
164
184
|
}
|
|
185
|
+
function splitBareSpecifier(request) {
|
|
186
|
+
if (request.startsWith("@")) {
|
|
187
|
+
const segments = request.split("/");
|
|
188
|
+
return segments.slice(0, 2).join("/");
|
|
189
|
+
}
|
|
190
|
+
return request.split("/")[0];
|
|
191
|
+
}
|
|
165
192
|
function depsKeyOf(dependencies) {
|
|
166
193
|
const canonical = Object.entries(dependencies).map(([name, version]) => `${name}@${version}`).toSorted().join("\n");
|
|
167
194
|
return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
|
|
168
195
|
}
|
|
169
196
|
|
|
170
|
-
//
|
|
197
|
+
// packages/runtime/src/functions/deps/resolve.ts
|
|
171
198
|
function resolveExecutionDeps(config, projectId, manifestContent) {
|
|
172
199
|
const manifest = tryParseManifestDependencies(manifestContent);
|
|
173
200
|
const { customDeps } = classifyDependencies(manifest, config.builtin);
|
|
@@ -180,7 +207,7 @@ function resolveExecutionDeps(config, projectId, manifestContent) {
|
|
|
180
207
|
};
|
|
181
208
|
}
|
|
182
209
|
|
|
183
|
-
//
|
|
210
|
+
// packages/runtime/src/functions/runtime/worker-executor.ts
|
|
184
211
|
function resolveWorkerEntry(baseDir = fileURLToPath(new URL(".", import.meta.url))) {
|
|
185
212
|
const candidates = [
|
|
186
213
|
join(baseDir, "worker-entry.js"),
|
|
@@ -230,7 +257,7 @@ var WorkerFunctionExecutor = class {
|
|
|
230
257
|
const entry = input.entry ?? "index.ts";
|
|
231
258
|
const deps = this.depsConfig === void 0 ? void 0 : resolveExecutionDeps(this.depsConfig, input.project.id, input.files["package.json"]);
|
|
232
259
|
const logs = [];
|
|
233
|
-
return new Promise((
|
|
260
|
+
return new Promise((resolve3, reject) => {
|
|
234
261
|
let worker;
|
|
235
262
|
try {
|
|
236
263
|
worker = new Worker(resolveWorkerEntry(), {
|
|
@@ -292,7 +319,7 @@ var WorkerFunctionExecutor = class {
|
|
|
292
319
|
if (message.type === "result") {
|
|
293
320
|
clearTimeout(timer);
|
|
294
321
|
void worker.terminate();
|
|
295
|
-
|
|
322
|
+
resolve3({ body: message.body, logs });
|
|
296
323
|
return;
|
|
297
324
|
}
|
|
298
325
|
if (message.type === "error") {
|
|
@@ -325,11 +352,11 @@ var WorkerFunctionExecutor = class {
|
|
|
325
352
|
}
|
|
326
353
|
};
|
|
327
354
|
|
|
328
|
-
// src/sim/runtime.ts
|
|
355
|
+
// packages/cli/src/sim/runtime.ts
|
|
329
356
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
330
357
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
331
358
|
|
|
332
|
-
//
|
|
359
|
+
// packages/runtime/src/database/builder/dialect.ts
|
|
333
360
|
var sqliteDialect = {
|
|
334
361
|
name: "sqlite",
|
|
335
362
|
placeholder: () => "?",
|
|
@@ -348,7 +375,7 @@ function dialectFor(driver) {
|
|
|
348
375
|
return driver.engine === "pg" ? postgresDialect : sqliteDialect;
|
|
349
376
|
}
|
|
350
377
|
|
|
351
|
-
//
|
|
378
|
+
// packages/runtime/src/database/provision/identifier.ts
|
|
352
379
|
var DbError = class extends Error {
|
|
353
380
|
constructor(status, code, message) {
|
|
354
381
|
super(message);
|
|
@@ -372,31 +399,45 @@ function quoteIdentifier(name) {
|
|
|
372
399
|
return `"${name.replace(/"/g, '""')}"`;
|
|
373
400
|
}
|
|
374
401
|
|
|
375
|
-
//
|
|
402
|
+
// packages/runtime/src/database/builder/guards.ts
|
|
376
403
|
function unsafeOperation(message) {
|
|
377
404
|
return new DbError(400, "DB_UNSAFE_OP", message);
|
|
378
405
|
}
|
|
379
406
|
function stripLiterals(sql) {
|
|
380
407
|
return sql.replace(/'[^']*(?:''[^']*)*'/g, "").replace(/"[^"]*(?:""[^"]*)*"/g, "").replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
381
408
|
}
|
|
382
|
-
function
|
|
409
|
+
function sqlHead(sql) {
|
|
410
|
+
return sql.trim().replace(/^\(+/, "").trim().toUpperCase();
|
|
411
|
+
}
|
|
412
|
+
function assertSafeStatement(sql) {
|
|
383
413
|
const stripped = stripLiterals(sql);
|
|
384
414
|
if (stripped.includes(";")) {
|
|
385
415
|
throw unsafeOperation("\u4EC5\u5141\u8BB8\u5355\u6761\u8BED\u53E5\uFF0C\u7981\u6B62\u591A\u8BED\u53E5\u5806\u53E0");
|
|
386
416
|
}
|
|
387
|
-
const head = stripped.trim().replace(/^\(+/, "").trim().toUpperCase();
|
|
388
|
-
if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
|
|
389
|
-
throw unsafeOperation("cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
|
|
390
|
-
}
|
|
391
417
|
if (/ATTACH|DETACH/.test(stripped.toUpperCase())) {
|
|
392
418
|
throw unsafeOperation("\u7981\u6B62\u8DE8\u5E93\u64CD\u4F5C\uFF08ATTACH / DETACH\uFF09");
|
|
393
419
|
}
|
|
394
420
|
if (/SQLITE_\w+/i.test(stripped)) {
|
|
395
421
|
throw unsafeOperation("\u7981\u6B62\u8BBF\u95EE\u7CFB\u7EDF\u8868\uFF08sqlite_*\uFF09");
|
|
396
422
|
}
|
|
423
|
+
return sqlHead(stripped);
|
|
424
|
+
}
|
|
425
|
+
function assertReadOnlyQuery(sql) {
|
|
426
|
+
const head = assertSafeStatement(sql);
|
|
427
|
+
if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
|
|
428
|
+
throw unsafeOperation("cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
function assertWriteQuery(sql) {
|
|
432
|
+
const head = assertSafeStatement(sql);
|
|
433
|
+
if (!head.startsWith("INSERT") && !head.startsWith("UPDATE") && !head.startsWith("DELETE")) {
|
|
434
|
+
throw unsafeOperation(
|
|
435
|
+
"cloud.db.writeQuery \u4EC5\u5141\u8BB8 DML\uFF08INSERT / UPDATE / DELETE\uFF09\uFF0CDDL \u8BF7\u8D70\u63A7\u5236\u53F0"
|
|
436
|
+
);
|
|
437
|
+
}
|
|
397
438
|
}
|
|
398
439
|
|
|
399
|
-
//
|
|
440
|
+
// packages/runtime/src/database/builder/owned.ts
|
|
400
441
|
var OWNED_PK = "id";
|
|
401
442
|
var OWNED_OWNER_KEY = "__owner_key";
|
|
402
443
|
var CHANGE_LOG_PREFIX = "_adep_changes_";
|
|
@@ -509,7 +550,7 @@ async function readChanges(driver, table, query = {}) {
|
|
|
509
550
|
return rows.map(parseChange);
|
|
510
551
|
}
|
|
511
552
|
|
|
512
|
-
//
|
|
553
|
+
// packages/runtime/src/database/builder/ulid.ts
|
|
513
554
|
var ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
514
555
|
var TIME_LEN = 10;
|
|
515
556
|
var RANDOM_LEN = 16;
|
|
@@ -575,7 +616,7 @@ function ulid(now = Date.now()) {
|
|
|
575
616
|
return time + random;
|
|
576
617
|
}
|
|
577
618
|
|
|
578
|
-
//
|
|
619
|
+
// packages/runtime/src/database/builder/table.ts
|
|
579
620
|
var OPERATORS = /* @__PURE__ */ new Set([
|
|
580
621
|
"=",
|
|
581
622
|
"!=",
|
|
@@ -894,7 +935,7 @@ function createTableBuilder(table, driver, dialect, options = {}) {
|
|
|
894
935
|
return build(initialState);
|
|
895
936
|
}
|
|
896
937
|
|
|
897
|
-
//
|
|
938
|
+
// packages/runtime/src/database/builder/index.ts
|
|
898
939
|
var TX_STATES = /* @__PURE__ */ new WeakMap();
|
|
899
940
|
function createCloudDb(driver, options = {}) {
|
|
900
941
|
const dialect = options.dialect ?? dialectFor(driver);
|
|
@@ -939,6 +980,14 @@ function createCloudDb(driver, options = {}) {
|
|
|
939
980
|
assertReadOnlyQuery(sql);
|
|
940
981
|
return driver.all(sql, params);
|
|
941
982
|
},
|
|
983
|
+
async writeQuery(sql, params) {
|
|
984
|
+
if (!Array.isArray(params)) {
|
|
985
|
+
throw unsafeOperation("writeQuery \u7684 params \u5FC5\u987B\u63D0\u4F9B\uFF08\u65E0\u53C2\u4F20 []\uFF09");
|
|
986
|
+
}
|
|
987
|
+
guardWrite();
|
|
988
|
+
assertWriteQuery(sql);
|
|
989
|
+
return driver.run(sql, params);
|
|
990
|
+
},
|
|
942
991
|
async changes(table, query = {}) {
|
|
943
992
|
return readChanges(driver, table, query);
|
|
944
993
|
}
|
|
@@ -948,13 +997,14 @@ function createCloudDb(driver, options = {}) {
|
|
|
948
997
|
return makeHandle({ allowWriteDuringTx: false });
|
|
949
998
|
}
|
|
950
999
|
|
|
951
|
-
//
|
|
1000
|
+
// packages/runtime/src/database/sdk/cloud.ts
|
|
952
1001
|
var CLOUD_DB_SPEC = {
|
|
953
1002
|
kind: "cloud-db",
|
|
954
1003
|
rootMethod: "table",
|
|
955
1004
|
stepMethods: ["select", "where", "orderBy", "limit", "offset"],
|
|
956
1005
|
terminalMethods: ["get", "first", "count", "insert", "insertMany", "update", "delete"],
|
|
957
|
-
|
|
1006
|
+
// CF-013:writeQuery 是 D1 shim 的写路径(INSERT/UPDATE/DELETE),与 query 并列直通方法。
|
|
1007
|
+
directMethods: ["query", "writeQuery", "changes"],
|
|
958
1008
|
transactionMethod: "transaction"
|
|
959
1009
|
};
|
|
960
1010
|
var WRITE_TERMINALS = /* @__PURE__ */ new Set(["insert", "insertMany", "update", "delete"]);
|
|
@@ -1009,6 +1059,10 @@ function createDbCapability(driver, options = {}) {
|
|
|
1009
1059
|
const [sql, params] = args;
|
|
1010
1060
|
return await db.query(sql, params);
|
|
1011
1061
|
}
|
|
1062
|
+
case DB_RPC.writeQuery: {
|
|
1063
|
+
const [sql, params] = args;
|
|
1064
|
+
return await db.writeQuery(sql, params);
|
|
1065
|
+
}
|
|
1012
1066
|
case DB_RPC.changes: {
|
|
1013
1067
|
const [table, query] = args;
|
|
1014
1068
|
return await db.changes(table, query);
|
|
@@ -1052,7 +1106,7 @@ function createDbCapability(driver, options = {}) {
|
|
|
1052
1106
|
};
|
|
1053
1107
|
}
|
|
1054
1108
|
|
|
1055
|
-
// src/sim/sql-engine.ts
|
|
1109
|
+
// packages/cli/src/sim/sql-engine.ts
|
|
1056
1110
|
var SimDbError = class extends Error {
|
|
1057
1111
|
constructor(code, message) {
|
|
1058
1112
|
super(message);
|
|
@@ -1470,7 +1524,7 @@ function project(rows, selectRaw) {
|
|
|
1470
1524
|
});
|
|
1471
1525
|
}
|
|
1472
1526
|
|
|
1473
|
-
// src/sim/db.ts
|
|
1527
|
+
// packages/cli/src/sim/db.ts
|
|
1474
1528
|
function toProjectDriver(engine) {
|
|
1475
1529
|
return {
|
|
1476
1530
|
engine: "sqlite",
|
|
@@ -1490,10 +1544,110 @@ function createSimDbCapability(options = {}) {
|
|
|
1490
1544
|
return { bundle, engine, driver };
|
|
1491
1545
|
}
|
|
1492
1546
|
|
|
1493
|
-
// src/
|
|
1547
|
+
// packages/runtime/src/database/sdk/kv.ts
|
|
1548
|
+
var KV_TABLE = "_adep_kv";
|
|
1549
|
+
var KV_RPC = {
|
|
1550
|
+
get: "get",
|
|
1551
|
+
put: "put",
|
|
1552
|
+
delete: "delete",
|
|
1553
|
+
list: "list"
|
|
1554
|
+
};
|
|
1555
|
+
var KV_CAPABILITY_CODES = {
|
|
1556
|
+
invalidMethod: "KV_INVALID_METHOD"
|
|
1557
|
+
};
|
|
1558
|
+
var KV_LIST_DEFAULT_LIMIT = 100;
|
|
1559
|
+
function nowSeconds() {
|
|
1560
|
+
return Math.floor(Date.now() / 1e3);
|
|
1561
|
+
}
|
|
1562
|
+
function errorWithCode2(error) {
|
|
1563
|
+
const code = typeof error === "object" && error !== null && typeof error.code === "string" ? error.code : void 0;
|
|
1564
|
+
if (code !== void 0 && error instanceof Error) {
|
|
1565
|
+
return new Error(`[${code}] ${error.message}`);
|
|
1566
|
+
}
|
|
1567
|
+
return error;
|
|
1568
|
+
}
|
|
1569
|
+
function createKvCapability(driver) {
|
|
1570
|
+
let ensurePromise = null;
|
|
1571
|
+
const ensureTable = () => {
|
|
1572
|
+
if (ensurePromise === null) {
|
|
1573
|
+
ensurePromise = driver.run(
|
|
1574
|
+
`CREATE TABLE IF NOT EXISTS ${KV_TABLE} (key TEXT PRIMARY KEY, value TEXT, expires_at INTEGER)`
|
|
1575
|
+
).then(() => void 0);
|
|
1576
|
+
}
|
|
1577
|
+
return ensurePromise;
|
|
1578
|
+
};
|
|
1579
|
+
const handler = async (method, args) => {
|
|
1580
|
+
try {
|
|
1581
|
+
await ensureTable();
|
|
1582
|
+
switch (method) {
|
|
1583
|
+
case KV_RPC.get: {
|
|
1584
|
+
const [key] = args;
|
|
1585
|
+
const row = await driver.get(`SELECT value, expires_at FROM ${KV_TABLE} WHERE key = ?`, [
|
|
1586
|
+
key
|
|
1587
|
+
]);
|
|
1588
|
+
if (row === null || row === void 0) return null;
|
|
1589
|
+
const expiresAt = row.expires_at;
|
|
1590
|
+
if (expiresAt !== null && expiresAt !== void 0 && Number(expiresAt) <= nowSeconds()) {
|
|
1591
|
+
return null;
|
|
1592
|
+
}
|
|
1593
|
+
return row.value;
|
|
1594
|
+
}
|
|
1595
|
+
case KV_RPC.put: {
|
|
1596
|
+
const [key, value, options] = args;
|
|
1597
|
+
const ttl = options?.expirationTtlSeconds;
|
|
1598
|
+
const expiresAt = typeof ttl === "number" && ttl > 0 ? nowSeconds() + Math.floor(ttl) : null;
|
|
1599
|
+
await driver.run(`DELETE FROM ${KV_TABLE} WHERE key = ?`, [key]);
|
|
1600
|
+
await driver.run(`INSERT INTO ${KV_TABLE} (key, value, expires_at) VALUES (?, ?, ?)`, [
|
|
1601
|
+
key,
|
|
1602
|
+
value,
|
|
1603
|
+
expiresAt
|
|
1604
|
+
]);
|
|
1605
|
+
return void 0;
|
|
1606
|
+
}
|
|
1607
|
+
case KV_RPC.delete: {
|
|
1608
|
+
const [key] = args;
|
|
1609
|
+
await driver.run(`DELETE FROM ${KV_TABLE} WHERE key = ?`, [key]);
|
|
1610
|
+
return void 0;
|
|
1611
|
+
}
|
|
1612
|
+
case KV_RPC.list: {
|
|
1613
|
+
const [options] = args;
|
|
1614
|
+
const prefix = options?.prefix ?? "";
|
|
1615
|
+
const limit = options?.limit ?? KV_LIST_DEFAULT_LIMIT;
|
|
1616
|
+
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 ?`, [
|
|
1617
|
+
`${prefix}%`
|
|
1618
|
+
]);
|
|
1619
|
+
const now = nowSeconds();
|
|
1620
|
+
const entries = [];
|
|
1621
|
+
for (const row of rows) {
|
|
1622
|
+
const expiresAt = row.expires_at;
|
|
1623
|
+
if (expiresAt !== null && expiresAt !== void 0 && Number(expiresAt) <= now) continue;
|
|
1624
|
+
entries.push({
|
|
1625
|
+
name: String(row.key),
|
|
1626
|
+
expiration: expiresAt === null || expiresAt === void 0 ? null : Number(expiresAt)
|
|
1627
|
+
});
|
|
1628
|
+
if (entries.length >= limit) break;
|
|
1629
|
+
}
|
|
1630
|
+
return entries;
|
|
1631
|
+
}
|
|
1632
|
+
default:
|
|
1633
|
+
throw new Error(
|
|
1634
|
+
`\u672A\u77E5\u7684 cloud.kv \u65B9\u6CD5 "${String(method)}"\uFF08${KV_CAPABILITY_CODES.invalidMethod}\uFF09`
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
} catch (error) {
|
|
1638
|
+
throw errorWithCode2(error);
|
|
1639
|
+
}
|
|
1640
|
+
};
|
|
1641
|
+
return {
|
|
1642
|
+
capabilities: [{ name: "kv", value: { [RPC_CAPABILITY_KEY]: true } }],
|
|
1643
|
+
rpcHandlers: { kv: handler }
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
// packages/cli/src/sim/storage.ts
|
|
1494
1648
|
import { join as join3 } from "node:path";
|
|
1495
1649
|
|
|
1496
|
-
//
|
|
1650
|
+
// packages/runtime/src/storage/driver.ts
|
|
1497
1651
|
var PROJECT_QUOTA_BYTES = 1024 * 1024 * 1024;
|
|
1498
1652
|
var StorageError = class extends Error {
|
|
1499
1653
|
constructor(status, code, message) {
|
|
@@ -1534,7 +1688,7 @@ function assertSafeStoragePath(path) {
|
|
|
1534
1688
|
return path;
|
|
1535
1689
|
}
|
|
1536
1690
|
|
|
1537
|
-
//
|
|
1691
|
+
// packages/runtime/src/storage/hmac-sha256.ts
|
|
1538
1692
|
var K = new Uint32Array([
|
|
1539
1693
|
1116352408,
|
|
1540
1694
|
1899447441,
|
|
@@ -1695,7 +1849,7 @@ function hmacSha256Hex(key, message) {
|
|
|
1695
1849
|
return [...hmacSha256(key, message)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1696
1850
|
}
|
|
1697
1851
|
|
|
1698
|
-
//
|
|
1852
|
+
// packages/runtime/src/storage/signature.ts
|
|
1699
1853
|
var DEFAULT_SIGN_TTL_SECONDS = 15 * 60;
|
|
1700
1854
|
var SIGN_EXPIRES_KEY = "x-expires";
|
|
1701
1855
|
var SIGN_SIGNATURE_KEY = "x-signature";
|
|
@@ -1710,7 +1864,7 @@ function signDownloadUrl(config, projectId, path, ttlSeconds = DEFAULT_SIGN_TTL_
|
|
|
1710
1864
|
return `${base}?${SIGN_EXPIRES_KEY}=${expires}&${SIGN_SIGNATURE_KEY}=${signature}`;
|
|
1711
1865
|
}
|
|
1712
1866
|
|
|
1713
|
-
//
|
|
1867
|
+
// packages/runtime/src/storage/cloud.ts
|
|
1714
1868
|
var DEFAULT_VISIBILITY = "private";
|
|
1715
1869
|
function asBytes(data) {
|
|
1716
1870
|
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
@@ -1733,9 +1887,12 @@ function createStorageCapability(driver, signer, projectId) {
|
|
|
1733
1887
|
const handler = async (method, args) => {
|
|
1734
1888
|
switch (method) {
|
|
1735
1889
|
case "upload": {
|
|
1736
|
-
const [path, data] = args;
|
|
1890
|
+
const [path, data, options] = args;
|
|
1737
1891
|
return toStoredFile(
|
|
1738
|
-
await driver.put(projectId, path, asBytes(data), {
|
|
1892
|
+
await driver.put(projectId, path, asBytes(data), {
|
|
1893
|
+
visibility: DEFAULT_VISIBILITY,
|
|
1894
|
+
...options?.contentType === void 0 ? {} : { contentType: options.contentType }
|
|
1895
|
+
})
|
|
1739
1896
|
);
|
|
1740
1897
|
}
|
|
1741
1898
|
case "get": {
|
|
@@ -1769,7 +1926,7 @@ function createStorageCapability(driver, signer, projectId) {
|
|
|
1769
1926
|
};
|
|
1770
1927
|
}
|
|
1771
1928
|
|
|
1772
|
-
//
|
|
1929
|
+
// packages/runtime/src/storage/driver/local.ts
|
|
1773
1930
|
import { mkdir, readFile, readdir, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
1774
1931
|
import { dirname as dirname2, join as join2 } from "node:path";
|
|
1775
1932
|
var META_SUFFIX = ".adep-meta.json";
|
|
@@ -1976,7 +2133,7 @@ function createLocalStorageDriver(options) {
|
|
|
1976
2133
|
};
|
|
1977
2134
|
}
|
|
1978
2135
|
|
|
1979
|
-
// src/sim/storage.ts
|
|
2136
|
+
// packages/cli/src/sim/storage.ts
|
|
1980
2137
|
function createSimStorageCapability(options) {
|
|
1981
2138
|
const dir = join3(options.cwd, ".adep", "sim", "storage");
|
|
1982
2139
|
const driver = createLocalStorageDriver({ dir });
|
|
@@ -1988,7 +2145,7 @@ function createSimStorageCapability(options) {
|
|
|
1988
2145
|
return { bundle, driver };
|
|
1989
2146
|
}
|
|
1990
2147
|
|
|
1991
|
-
// src/sim/realtime.ts
|
|
2148
|
+
// packages/cli/src/sim/realtime.ts
|
|
1992
2149
|
var SimRealtime = class {
|
|
1993
2150
|
seq = 0;
|
|
1994
2151
|
subscribers = /* @__PURE__ */ new Map();
|
|
@@ -2110,7 +2267,7 @@ function createSimRealtimeCapability() {
|
|
|
2110
2267
|
};
|
|
2111
2268
|
}
|
|
2112
2269
|
|
|
2113
|
-
// src/sim/runtime.ts
|
|
2270
|
+
// packages/cli/src/sim/runtime.ts
|
|
2114
2271
|
function simDir(cwd) {
|
|
2115
2272
|
return join4(cwd, ".adep", "sim");
|
|
2116
2273
|
}
|
|
@@ -2161,7 +2318,8 @@ async function createSimRuntime(options) {
|
|
|
2161
2318
|
projectId: options.projectId ?? "local"
|
|
2162
2319
|
});
|
|
2163
2320
|
const simRealtime = createSimRealtimeCapability();
|
|
2164
|
-
const
|
|
2321
|
+
const kvBundle = createKvCapability(db.driver);
|
|
2322
|
+
const bundle = mergeBundles([db.bundle, storage.bundle, kvBundle, simRealtime.bundle]);
|
|
2165
2323
|
await db.engine.load();
|
|
2166
2324
|
return {
|
|
2167
2325
|
bundle,
|
|
@@ -2173,7 +2331,7 @@ async function createSimRuntime(options) {
|
|
|
2173
2331
|
};
|
|
2174
2332
|
}
|
|
2175
2333
|
|
|
2176
|
-
// src/sim/env.ts
|
|
2334
|
+
// packages/cli/src/sim/env.ts
|
|
2177
2335
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
2178
2336
|
import { join as join5 } from "node:path";
|
|
2179
2337
|
function parseEnv(content) {
|
|
@@ -2206,7 +2364,7 @@ async function loadSimEnv(cwd, config = {}) {
|
|
|
2206
2364
|
return merged;
|
|
2207
2365
|
}
|
|
2208
2366
|
|
|
2209
|
-
// src/sim/invoke.ts
|
|
2367
|
+
// packages/cli/src/sim/invoke.ts
|
|
2210
2368
|
function resolveFunctionEntry(files, fnName) {
|
|
2211
2369
|
const flat = `${fnName}.ts`;
|
|
2212
2370
|
if (files[flat] !== void 0) return flat;
|
|
@@ -2247,7 +2405,14 @@ function createSimInvokeHandler(options) {
|
|
|
2247
2405
|
};
|
|
2248
2406
|
}
|
|
2249
2407
|
|
|
2250
|
-
// src/
|
|
2408
|
+
// packages/cli/src/builtin-deps.ts
|
|
2409
|
+
var LOCAL_STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
|
|
2410
|
+
var LOCAL_BUILTIN_DEPS = [
|
|
2411
|
+
"@adep/cf-compat",
|
|
2412
|
+
LOCAL_STATE_OBJECTS_SPECIFIER
|
|
2413
|
+
];
|
|
2414
|
+
|
|
2415
|
+
// packages/cli/src/sim/boundary.ts
|
|
2251
2416
|
var SIM_BOUNDARIES = [
|
|
2252
2417
|
{
|
|
2253
2418
|
kind: "capability",
|
|
@@ -2276,11 +2441,11 @@ var SIM_BOUNDARIES = [
|
|
|
2276
2441
|
}
|
|
2277
2442
|
];
|
|
2278
2443
|
|
|
2279
|
-
// src/ts-config.ts
|
|
2444
|
+
// packages/cli/src/ts-config.ts
|
|
2280
2445
|
import { stat as stat2, readFile as readFile4 } from "node:fs/promises";
|
|
2281
2446
|
import { join as join6 } from "node:path";
|
|
2282
2447
|
|
|
2283
|
-
//
|
|
2448
|
+
// shared/sdk/adep-config.ts
|
|
2284
2449
|
var DEFAULT_ADEP_CONFIG = {
|
|
2285
2450
|
functionsDir: "functions",
|
|
2286
2451
|
functions_prefix: "/api"
|
|
@@ -2302,6 +2467,51 @@ function asStringRecord(value) {
|
|
|
2302
2467
|
}
|
|
2303
2468
|
return rec;
|
|
2304
2469
|
}
|
|
2470
|
+
function asBindingArray(value, label, errors, optionalKey) {
|
|
2471
|
+
if (!Array.isArray(value)) {
|
|
2472
|
+
errors.push(`${label} \u5FC5\u987B\u662F\u6570\u7EC4\uFF0C\u6536\u5230 ${typeNameOf(value)}`);
|
|
2473
|
+
return null;
|
|
2474
|
+
}
|
|
2475
|
+
const out = [];
|
|
2476
|
+
value.forEach((item, i) => {
|
|
2477
|
+
const idx = `${label}[${i}]`;
|
|
2478
|
+
if (item === null || typeof item !== "object" || Array.isArray(item)) {
|
|
2479
|
+
errors.push(`${idx} \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u6536\u5230 ${typeNameOf(item)}`);
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
const rec = item;
|
|
2483
|
+
if (typeof rec.name !== "string" || rec.name.length === 0) {
|
|
2484
|
+
errors.push(`${idx}.name \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\uFF0C\u6536\u5230 ${typeNameOf(rec.name)}`);
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
const entry = { name: rec.name };
|
|
2488
|
+
const optional = rec[optionalKey];
|
|
2489
|
+
if (optional !== void 0) {
|
|
2490
|
+
if (typeof optional !== "string") {
|
|
2491
|
+
errors.push(`${idx}.${optionalKey} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\uFF0C\u6536\u5230 ${typeNameOf(optional)}`);
|
|
2492
|
+
} else {
|
|
2493
|
+
entry[optionalKey] = optional;
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
out.push(entry);
|
|
2497
|
+
});
|
|
2498
|
+
return out;
|
|
2499
|
+
}
|
|
2500
|
+
function asCfBindingsConfig(value, errors) {
|
|
2501
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2502
|
+
errors.push(`cfBindings \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u6536\u5230 ${typeNameOf(value)}`);
|
|
2503
|
+
return null;
|
|
2504
|
+
}
|
|
2505
|
+
const rec = value;
|
|
2506
|
+
const bindings = {};
|
|
2507
|
+
const kv = rec.kv === void 0 ? void 0 : asBindingArray(rec.kv, "cfBindings.kv", errors, "namespace");
|
|
2508
|
+
if (kv !== null && kv !== void 0) bindings.kv = kv;
|
|
2509
|
+
const d1 = rec.d1 === void 0 ? void 0 : asBindingArray(rec.d1, "cfBindings.d1", errors, "database");
|
|
2510
|
+
if (d1 !== null && d1 !== void 0) bindings.d1 = d1;
|
|
2511
|
+
const r2 = rec.r2 === void 0 ? void 0 : asBindingArray(rec.r2, "cfBindings.r2", errors, "bucket");
|
|
2512
|
+
if (r2 !== null && r2 !== void 0) bindings.r2 = r2;
|
|
2513
|
+
return bindings;
|
|
2514
|
+
}
|
|
2305
2515
|
function parseAdepConfig(raw) {
|
|
2306
2516
|
if (raw === null || raw === void 0) {
|
|
2307
2517
|
return { ok: true, data: { ...DEFAULT_ADEP_CONFIG } };
|
|
@@ -2362,11 +2572,15 @@ function parseAdepConfig(raw) {
|
|
|
2362
2572
|
data.runtime = rec;
|
|
2363
2573
|
}
|
|
2364
2574
|
}
|
|
2575
|
+
if (input.cfBindings !== void 0) {
|
|
2576
|
+
const bindings = asCfBindingsConfig(input.cfBindings, errors);
|
|
2577
|
+
if (bindings !== null) data.cfBindings = bindings;
|
|
2578
|
+
}
|
|
2365
2579
|
if (errors.length > 0) return { ok: false, errors };
|
|
2366
2580
|
return { ok: true, data };
|
|
2367
2581
|
}
|
|
2368
2582
|
|
|
2369
|
-
// src/ts-config.ts
|
|
2583
|
+
// packages/cli/src/ts-config.ts
|
|
2370
2584
|
async function loadAdepConfigModule(cwd) {
|
|
2371
2585
|
const configPath = join6(cwd, "adep.config.ts");
|
|
2372
2586
|
try {
|
|
@@ -2410,14 +2624,1036 @@ ${result.errors.map((e) => ` - ${e}`).join("\n")}`;
|
|
|
2410
2624
|
return result.data;
|
|
2411
2625
|
}
|
|
2412
2626
|
|
|
2413
|
-
// src/
|
|
2627
|
+
// packages/runtime/src/state-objects/runtime.ts
|
|
2628
|
+
var StateObject = class {
|
|
2629
|
+
id;
|
|
2630
|
+
/** 对象内存状态(单例驻留);load 时从后端恢复。 */
|
|
2631
|
+
state;
|
|
2632
|
+
alarmAt = null;
|
|
2633
|
+
/** 运行时注入的持久化句柄(内部;protected,子类 flush() 使用)。 */
|
|
2634
|
+
runtime;
|
|
2635
|
+
constructor(id) {
|
|
2636
|
+
this.id = id;
|
|
2637
|
+
this.state = this.initialState();
|
|
2638
|
+
}
|
|
2639
|
+
/** 供运行时读取/序列化。 */
|
|
2640
|
+
getState() {
|
|
2641
|
+
return { ...this.state };
|
|
2642
|
+
}
|
|
2643
|
+
/** 通用快照方法(任何对象可经 invoke(type, id, 'snapshot') 读取)。 */
|
|
2644
|
+
async snapshot() {
|
|
2645
|
+
return this.getState();
|
|
2646
|
+
}
|
|
2647
|
+
/** 设置未来唤醒(alarm):到期时运行时调 onAlarm(调度 CF-037 落地)。 */
|
|
2648
|
+
setAlarm(at) {
|
|
2649
|
+
this.alarmAt = at;
|
|
2650
|
+
}
|
|
2651
|
+
clearAlarm() {
|
|
2652
|
+
this.alarmAt = null;
|
|
2653
|
+
}
|
|
2654
|
+
/** alarm 到期回调(子类覆写)。 */
|
|
2655
|
+
async onAlarm() {
|
|
2656
|
+
}
|
|
2657
|
+
/** 显式持久化当前状态(方法内任何位置可调)。 */
|
|
2658
|
+
async flush() {
|
|
2659
|
+
await this.runtime.flush(this);
|
|
2660
|
+
}
|
|
2661
|
+
};
|
|
2662
|
+
var StateObjectError = class extends Error {
|
|
2663
|
+
code;
|
|
2664
|
+
constructor(code, message) {
|
|
2665
|
+
super(message);
|
|
2666
|
+
this.name = "StateObjectError";
|
|
2667
|
+
this.code = code;
|
|
2668
|
+
}
|
|
2669
|
+
};
|
|
2670
|
+
var StateObjectRuntime = class {
|
|
2671
|
+
registry = /* @__PURE__ */ new Map();
|
|
2672
|
+
instances = /* @__PURE__ */ new Map();
|
|
2673
|
+
backend;
|
|
2674
|
+
constructor(backend) {
|
|
2675
|
+
this.backend = backend;
|
|
2676
|
+
}
|
|
2677
|
+
define(cls) {
|
|
2678
|
+
this.registry.set(cls.typeName, cls);
|
|
2679
|
+
}
|
|
2680
|
+
/** 已注册类型清单(控制台/审计用)。 */
|
|
2681
|
+
types() {
|
|
2682
|
+
return [...this.registry.keys()];
|
|
2683
|
+
}
|
|
2684
|
+
/** 内存驻留实例数(诊断用)。 */
|
|
2685
|
+
residentCount() {
|
|
2686
|
+
return this.instances.size;
|
|
2687
|
+
}
|
|
2688
|
+
key(type, id) {
|
|
2689
|
+
return `${type}:${id}`;
|
|
2690
|
+
}
|
|
2691
|
+
/** 取对象实例(单例驻留):内存有 → 复用;无 → 后端恢复或 new 初始态。 */
|
|
2692
|
+
async get(type, id) {
|
|
2693
|
+
const cls = this.registry.get(type);
|
|
2694
|
+
if (cls === void 0) {
|
|
2695
|
+
throw new StateObjectError(
|
|
2696
|
+
"STATE_TYPE_NOT_REGISTERED",
|
|
2697
|
+
`\u72B6\u6001\u5BF9\u8C61\u7C7B\u578B "${type}" \u672A\u6CE8\u518C\uFF08\u5DF2\u6CE8\u518C\uFF1A${this.types().join(", ") || "\u65E0"}\uFF09`
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
const k = this.key(type, id);
|
|
2701
|
+
const hit = this.instances.get(k);
|
|
2702
|
+
if (hit !== void 0) return hit;
|
|
2703
|
+
const snapshot = await this.backend.load(type, id);
|
|
2704
|
+
const raw = new cls(id);
|
|
2705
|
+
const created = raw;
|
|
2706
|
+
created.state = snapshot !== null ? snapshot.state : created.state;
|
|
2707
|
+
created.alarmAt = snapshot !== null ? snapshot.alarmAt : null;
|
|
2708
|
+
created.runtime = this;
|
|
2709
|
+
this.instances.set(k, created);
|
|
2710
|
+
return created;
|
|
2711
|
+
}
|
|
2712
|
+
/** 方法路由:单例对象上串行执行方法。 */
|
|
2713
|
+
async invoke(type, id, method, args = []) {
|
|
2714
|
+
const inst = await this.get(type, id);
|
|
2715
|
+
const fn = inst[method];
|
|
2716
|
+
if (typeof fn !== "function") {
|
|
2717
|
+
throw new StateObjectError(
|
|
2718
|
+
"STATE_METHOD_NOT_FOUND",
|
|
2719
|
+
`\u72B6\u6001\u5BF9\u8C61 "${type}:${id}" \u65E0\u65B9\u6CD5 "${method}"`
|
|
2720
|
+
);
|
|
2721
|
+
}
|
|
2722
|
+
try {
|
|
2723
|
+
return await fn.call(inst, ...args);
|
|
2724
|
+
} catch (error) {
|
|
2725
|
+
if (error instanceof StateObjectError) throw error;
|
|
2726
|
+
throw new StateObjectError(
|
|
2727
|
+
"STATE_INVOKE_ERROR",
|
|
2728
|
+
`\u72B6\u6001\u5BF9\u8C61 "${type}:${id}" \u65B9\u6CD5 "${method}" \u6267\u884C\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`
|
|
2729
|
+
);
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
/** 持久化快照(对象方法内 flush() 触发,或运行时统一写)。 */
|
|
2733
|
+
async flush(inst) {
|
|
2734
|
+
const raw = inst;
|
|
2735
|
+
const type = inst.constructor.typeName;
|
|
2736
|
+
if (type === void 0) {
|
|
2737
|
+
throw new StateObjectError("STATE_TYPE_NOT_REGISTERED", "\u72B6\u6001\u5BF9\u8C61\u7C7B\u5FC5\u987B\u58F0\u660E static typeName");
|
|
2738
|
+
}
|
|
2739
|
+
await this.backend.save(type, inst.id, inst.getState(), raw.alarmAt);
|
|
2740
|
+
}
|
|
2741
|
+
/**
|
|
2742
|
+
* alarm 轮询:把到期对象唤醒并调 onAlarm(CF-037)。
|
|
2743
|
+
* - onAlarm 后统一持久化(flush):onAlarm 内改的 state 与 setAlarm 重调度 / clearAlarm
|
|
2744
|
+
* 的新 alarmAt 都落库;
|
|
2745
|
+
* - 单对象 onAlarm 抛错**不阻塞**同 tick 其余对象:失败对象不落库、alarmAt 保留
|
|
2746
|
+
* → 下轮 dueAlarms 仍命中重试;错误折叠进 failed(不泄漏内部栈)。
|
|
2747
|
+
*/
|
|
2748
|
+
async pump(now) {
|
|
2749
|
+
const due = await this.backend.dueAlarms(now);
|
|
2750
|
+
const fired = [];
|
|
2751
|
+
const failed = [];
|
|
2752
|
+
for (const d of due) {
|
|
2753
|
+
try {
|
|
2754
|
+
const inst = await this.get(d.type, d.id);
|
|
2755
|
+
await inst.onAlarm();
|
|
2756
|
+
await this.flush(inst);
|
|
2757
|
+
fired.push({ type: d.type, id: d.id });
|
|
2758
|
+
} catch (error) {
|
|
2759
|
+
failed.push({
|
|
2760
|
+
type: d.type,
|
|
2761
|
+
id: d.id,
|
|
2762
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2763
|
+
});
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
return { fired, failed };
|
|
2767
|
+
}
|
|
2768
|
+
/** 释放内存驻留(进程重启 / 测试隔离用);不删后端数据。 */
|
|
2769
|
+
evictAll() {
|
|
2770
|
+
this.instances.clear();
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
|
|
2774
|
+
// packages/runtime/src/state-objects/backend.ts
|
|
2775
|
+
var STATE_OBJECTS_TABLE = "_adep_state_objects";
|
|
2776
|
+
function createProjectDriverStateBackend(driver) {
|
|
2777
|
+
let ensured = false;
|
|
2778
|
+
const ensureTable = async () => {
|
|
2779
|
+
if (ensured) return;
|
|
2780
|
+
await driver.run(
|
|
2781
|
+
`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"))`
|
|
2782
|
+
);
|
|
2783
|
+
ensured = true;
|
|
2784
|
+
};
|
|
2785
|
+
return {
|
|
2786
|
+
async load(type, id) {
|
|
2787
|
+
await ensureTable();
|
|
2788
|
+
const rows = await driver.all(
|
|
2789
|
+
`SELECT "state", "alarm_at" FROM ${STATE_OBJECTS_TABLE} WHERE "type" = ? AND "id" = ?`,
|
|
2790
|
+
[type, id]
|
|
2791
|
+
);
|
|
2792
|
+
if (rows.length === 0) return null;
|
|
2793
|
+
return {
|
|
2794
|
+
state: JSON.parse(String(rows[0].state)),
|
|
2795
|
+
alarmAt: rows[0].alarm_at
|
|
2796
|
+
};
|
|
2797
|
+
},
|
|
2798
|
+
async save(type, id, state, alarmAt) {
|
|
2799
|
+
await ensureTable();
|
|
2800
|
+
const existing = await driver.all(
|
|
2801
|
+
`SELECT 1 FROM ${STATE_OBJECTS_TABLE} WHERE "type" = ? AND "id" = ?`,
|
|
2802
|
+
[type, id]
|
|
2803
|
+
);
|
|
2804
|
+
const stateJson = JSON.stringify(state);
|
|
2805
|
+
if (existing.length === 0) {
|
|
2806
|
+
await driver.run(
|
|
2807
|
+
`INSERT INTO ${STATE_OBJECTS_TABLE} ("type", "id", "state", "alarm_at", "updated_at") VALUES (?, ?, ?, ?, ?)`,
|
|
2808
|
+
[type, id, stateJson, alarmAt, Date.now()]
|
|
2809
|
+
);
|
|
2810
|
+
} else {
|
|
2811
|
+
await driver.run(
|
|
2812
|
+
`UPDATE ${STATE_OBJECTS_TABLE} SET "state" = ?, "alarm_at" = ?, "updated_at" = ? WHERE "type" = ? AND "id" = ?`,
|
|
2813
|
+
[stateJson, alarmAt, Date.now(), type, id]
|
|
2814
|
+
);
|
|
2815
|
+
}
|
|
2816
|
+
},
|
|
2817
|
+
async dueAlarms(now) {
|
|
2818
|
+
await ensureTable();
|
|
2819
|
+
const rows = await driver.all(
|
|
2820
|
+
`SELECT "type", "id", "alarm_at" FROM ${STATE_OBJECTS_TABLE} WHERE "alarm_at" IS NOT NULL AND "alarm_at" <= ?`,
|
|
2821
|
+
[now]
|
|
2822
|
+
);
|
|
2823
|
+
return rows.map((r) => ({
|
|
2824
|
+
type: r.type,
|
|
2825
|
+
id: r.id,
|
|
2826
|
+
alarmAt: r.alarm_at
|
|
2827
|
+
}));
|
|
2828
|
+
},
|
|
2829
|
+
async remove(type, id) {
|
|
2830
|
+
await ensureTable();
|
|
2831
|
+
await driver.run(`DELETE FROM ${STATE_OBJECTS_TABLE} WHERE "type" = ? AND "id" = ?`, [
|
|
2832
|
+
type,
|
|
2833
|
+
id
|
|
2834
|
+
]);
|
|
2835
|
+
}
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// packages/runtime/src/state-objects/http.ts
|
|
2840
|
+
var STATE_PATH = "state";
|
|
2841
|
+
function parseStatePath(rest) {
|
|
2842
|
+
const segments = rest.split("/").filter((s) => s.length > 0);
|
|
2843
|
+
if (segments[0] !== STATE_PATH || segments.length < 4) return null;
|
|
2844
|
+
return {
|
|
2845
|
+
type: decodeURIComponent(segments[1]),
|
|
2846
|
+
id: decodeURIComponent(segments[2]),
|
|
2847
|
+
method: decodeURIComponent(segments.slice(3).join("/"))
|
|
2848
|
+
};
|
|
2849
|
+
}
|
|
2850
|
+
function parseStateBody(body) {
|
|
2851
|
+
if (body === null || body.length === 0) return { args: [] };
|
|
2852
|
+
try {
|
|
2853
|
+
const parsed = JSON.parse(body);
|
|
2854
|
+
if (!Array.isArray(parsed)) return { error: "body \u5FC5\u987B\u662F\u53C2\u6570\u6570\u7EC4\uFF08JSON\uFF09" };
|
|
2855
|
+
return { args: parsed };
|
|
2856
|
+
} catch {
|
|
2857
|
+
return { error: "body \u5FC5\u987B\u662F\u5408\u6CD5 JSON" };
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
// packages/runtime/src/state-objects/demo.ts
|
|
2862
|
+
var DemoCounter = class extends StateObject {
|
|
2863
|
+
static typeName = "DemoCounter";
|
|
2864
|
+
initialState() {
|
|
2865
|
+
return { count: 0 };
|
|
2866
|
+
}
|
|
2867
|
+
async increment(by = 1) {
|
|
2868
|
+
this.state.count += by;
|
|
2869
|
+
await this.flush();
|
|
2870
|
+
return { count: this.state.count };
|
|
2871
|
+
}
|
|
2872
|
+
async get() {
|
|
2873
|
+
return { count: this.state.count };
|
|
2874
|
+
}
|
|
2875
|
+
};
|
|
2876
|
+
var DemoChatRoom = class extends StateObject {
|
|
2877
|
+
static typeName = "DemoChatRoom";
|
|
2878
|
+
initialState() {
|
|
2879
|
+
return { members: [], messages: [], cursor: 0 };
|
|
2880
|
+
}
|
|
2881
|
+
async join(user) {
|
|
2882
|
+
if (!this.state.members.includes(user)) this.state.members.push(user);
|
|
2883
|
+
this.state.cursor += 1;
|
|
2884
|
+
await this.flush();
|
|
2885
|
+
return { members: this.state.members, cursor: this.state.cursor };
|
|
2886
|
+
}
|
|
2887
|
+
async send(user, text) {
|
|
2888
|
+
const seq = this.state.messages.length + 1;
|
|
2889
|
+
this.state.messages.push({ user, text, at: Date.now() });
|
|
2890
|
+
await this.flush();
|
|
2891
|
+
return { seq };
|
|
2892
|
+
}
|
|
2893
|
+
};
|
|
2894
|
+
|
|
2895
|
+
// packages/runtime/src/functions/runtime/sandbox.ts
|
|
2896
|
+
import vm from "node:vm";
|
|
2897
|
+
import * as nodeModule from "node:module";
|
|
2898
|
+
|
|
2899
|
+
// packages/runtime/src/functions/runtime/exports.ts
|
|
2900
|
+
function transformModule(code) {
|
|
2901
|
+
let out = code;
|
|
2902
|
+
const named = [];
|
|
2903
|
+
out = out.replace(/(^|\n)(\s*)export\s+default\s+/g, "$1$2module.default = ");
|
|
2904
|
+
out = out.replace(
|
|
2905
|
+
/import\s*\{([^}]*)\}\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
|
|
2906
|
+
(_match, names, source) => `const {${names}} = require(${source})`
|
|
2907
|
+
);
|
|
2908
|
+
out = out.replace(
|
|
2909
|
+
/import\s*\*\s*as\s*([A-Za-z_$][\w$]*)\s*from\s*(['"][^'"]*['"])[ \t]*;?/g,
|
|
2910
|
+
(_match, name, source) => `const ${name} = require(${source})`
|
|
2911
|
+
);
|
|
2912
|
+
out = out.replace(
|
|
2913
|
+
/import\s+([A-Za-z_$][\w$]*)\s+from\s*(['"][^'"]*['"])[ \t]*;?/g,
|
|
2914
|
+
(_match, name, source) => `const ${name} = require(${source})`
|
|
2915
|
+
);
|
|
2916
|
+
out = out.replace(
|
|
2917
|
+
/export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
|
|
2918
|
+
(_match, kw, name) => {
|
|
2919
|
+
named.push(name);
|
|
2920
|
+
return `${kw} ${name}`;
|
|
2921
|
+
}
|
|
2922
|
+
);
|
|
2923
|
+
out = out.replace(
|
|
2924
|
+
/export\s+(async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/g,
|
|
2925
|
+
(_match, asyncKw, name) => {
|
|
2926
|
+
named.push(name);
|
|
2927
|
+
return `${asyncKw ?? ""}function ${name}`;
|
|
2928
|
+
}
|
|
2929
|
+
);
|
|
2930
|
+
out = out.replace(/export\s+class\s+([A-Za-z_$][\w$]*)/g, (_match, name) => {
|
|
2931
|
+
named.push(name);
|
|
2932
|
+
return `class ${name}`;
|
|
2933
|
+
});
|
|
2934
|
+
if (named.length > 0) {
|
|
2935
|
+
out += `
|
|
2936
|
+
;Object.assign(exports, { ${named.join(", ")} })`;
|
|
2937
|
+
}
|
|
2938
|
+
return out;
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
// packages/runtime/src/functions/runtime/sandbox.ts
|
|
2942
|
+
var bunTranspiler;
|
|
2943
|
+
function transpile(code) {
|
|
2944
|
+
const bun = globalThis["Bun"];
|
|
2945
|
+
if (bun?.Transpiler !== void 0) {
|
|
2946
|
+
bunTranspiler ??= new bun.Transpiler({ loader: "ts" });
|
|
2947
|
+
return bunTranspiler.transformSync(code);
|
|
2948
|
+
}
|
|
2949
|
+
const stripTypeScriptTypes2 = nodeModule.stripTypeScriptTypes;
|
|
2950
|
+
if (typeof stripTypeScriptTypes2 === "function") {
|
|
2951
|
+
return stripTypeScriptTypes2(code, { mode: "strip" });
|
|
2952
|
+
}
|
|
2953
|
+
return code;
|
|
2954
|
+
}
|
|
2955
|
+
function transformExports(code) {
|
|
2956
|
+
return transformModule(code);
|
|
2957
|
+
}
|
|
2958
|
+
var SANDBOX_BUILTIN_REJECTED = "FN_SANDBOX_BUILTIN_BLOCKED";
|
|
2959
|
+
function resolveModulePath(fromDir, request, files) {
|
|
2960
|
+
if (!request.startsWith("./") && !request.startsWith("../")) return null;
|
|
2961
|
+
const base = joinPosix(fromDir, request);
|
|
2962
|
+
const candidates = [base, `${base}.ts`, `${base}.js`, `${base}/index.ts`, `${base}/index.js`];
|
|
2963
|
+
for (const candidate of candidates) {
|
|
2964
|
+
const normalized = normalizePosix(candidate);
|
|
2965
|
+
if (files[normalized] !== void 0) return normalized;
|
|
2966
|
+
}
|
|
2967
|
+
return null;
|
|
2968
|
+
}
|
|
2969
|
+
function joinPosix(dir, request) {
|
|
2970
|
+
const parts = [...dir.split("/"), ...request.split("/")];
|
|
2971
|
+
const stack = [];
|
|
2972
|
+
for (const part of parts) {
|
|
2973
|
+
if (part === "" || part === ".") continue;
|
|
2974
|
+
if (part === "..") stack.pop();
|
|
2975
|
+
else stack.push(part);
|
|
2976
|
+
}
|
|
2977
|
+
return stack.join("/");
|
|
2978
|
+
}
|
|
2979
|
+
function normalizePosix(p) {
|
|
2980
|
+
return joinPosix("", p);
|
|
2981
|
+
}
|
|
2982
|
+
function loadModule(path, files, sandboxGlobals, cache, resolveBare, bareCache) {
|
|
2983
|
+
const cached = cache.get(path);
|
|
2984
|
+
if (cached !== void 0) return cached;
|
|
2985
|
+
const source = files[path];
|
|
2986
|
+
if (source === void 0) {
|
|
2987
|
+
throw new Error(`\u6A21\u5757\u4E0D\u5B58\u5728\uFF1A${path}`);
|
|
2988
|
+
}
|
|
2989
|
+
const exports = {};
|
|
2990
|
+
cache.set(path, exports);
|
|
2991
|
+
const dir = path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
|
|
2992
|
+
const module = { exports, default: void 0 };
|
|
2993
|
+
const require2 = (request) => {
|
|
2994
|
+
const resolved = resolveModulePath(dir, request, files);
|
|
2995
|
+
if (resolved !== null) {
|
|
2996
|
+
return loadModule(resolved, files, sandboxGlobals, cache, resolveBare, bareCache);
|
|
2997
|
+
}
|
|
2998
|
+
if (resolveBare !== void 0 && !request.startsWith("./") && !request.startsWith("../")) {
|
|
2999
|
+
const cachedModule = bareCache?.get(request);
|
|
3000
|
+
if (cachedModule !== void 0) return cachedModule;
|
|
3001
|
+
const loaded = resolveBare(request);
|
|
3002
|
+
bareCache?.set(request, loaded);
|
|
3003
|
+
return loaded;
|
|
3004
|
+
}
|
|
3005
|
+
const error = new Error(
|
|
3006
|
+
`\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`
|
|
3007
|
+
);
|
|
3008
|
+
error.code = SANDBOX_BUILTIN_REJECTED;
|
|
3009
|
+
throw error;
|
|
3010
|
+
};
|
|
3011
|
+
let transformed;
|
|
3012
|
+
try {
|
|
3013
|
+
transformed = transformExports(transpile(source));
|
|
3014
|
+
} catch (error) {
|
|
3015
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
3016
|
+
const stack = error.stack;
|
|
3017
|
+
const line = typeof stack === "string" ? /(?:^|\n):(\d+)(?:\n|$)/.exec(stack)?.[1] : void 0;
|
|
3018
|
+
const location = line === void 0 ? path : `${path}:${line}`;
|
|
3019
|
+
const wrapped = new Error(`\u6E90\u7801\u8BED\u6CD5\u9519\u8BEF\uFF08${location}\uFF09\uFF1A${rawMessage}`, { cause: error });
|
|
3020
|
+
const code = error.code;
|
|
3021
|
+
if (typeof code === "string") wrapped.code = code;
|
|
3022
|
+
throw wrapped;
|
|
3023
|
+
}
|
|
3024
|
+
const wrapper = vm.runInNewContext(
|
|
3025
|
+
`(function (module, exports, require) { ${transformed}
|
|
3026
|
+
})`,
|
|
3027
|
+
vm.createContext({ ...sandboxGlobals }),
|
|
3028
|
+
{ filename: path }
|
|
3029
|
+
);
|
|
3030
|
+
wrapper(module, exports, require2);
|
|
3031
|
+
if (module.default !== void 0 && exports["default"] === void 0) {
|
|
3032
|
+
exports["default"] = module.default;
|
|
3033
|
+
}
|
|
3034
|
+
return exports;
|
|
3035
|
+
}
|
|
3036
|
+
function loadFunctionModule(files, entry, sandboxGlobals, resolveBare) {
|
|
3037
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3038
|
+
const bareCache = /* @__PURE__ */ new Map();
|
|
3039
|
+
const entryExports = loadModule(entry, files, sandboxGlobals, cache, resolveBare, bareCache);
|
|
3040
|
+
const handler = entryExports["default"];
|
|
3041
|
+
if (typeof handler !== "function") {
|
|
3042
|
+
throw new Error(`\u5165\u53E3\u6587\u4EF6 ${entry} \u7F3A\u5C11 default \u5BFC\u51FA\u7684\u51FD\u6570`);
|
|
3043
|
+
}
|
|
3044
|
+
return { handler };
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3047
|
+
// packages/runtime/src/state-objects/loader.ts
|
|
3048
|
+
var STATE_OBJECTS_ENTRY = "state-objects.ts";
|
|
3049
|
+
var STATE_OBJECTS_SPECIFIER = "@adep/runtime/state-objects";
|
|
3050
|
+
function resolveStateObjectSpecifier(request) {
|
|
3051
|
+
if (request === STATE_OBJECTS_SPECIFIER) return { StateObject };
|
|
3052
|
+
return void 0;
|
|
3053
|
+
}
|
|
3054
|
+
function defaultStateSandboxGlobals() {
|
|
3055
|
+
return {
|
|
3056
|
+
console,
|
|
3057
|
+
URL,
|
|
3058
|
+
URLSearchParams,
|
|
3059
|
+
Request,
|
|
3060
|
+
Response,
|
|
3061
|
+
Headers,
|
|
3062
|
+
TextEncoder,
|
|
3063
|
+
TextDecoder,
|
|
3064
|
+
AbortController,
|
|
3065
|
+
AbortSignal,
|
|
3066
|
+
ReadableStream,
|
|
3067
|
+
WritableStream,
|
|
3068
|
+
TransformStream,
|
|
3069
|
+
Blob,
|
|
3070
|
+
FormData,
|
|
3071
|
+
crypto,
|
|
3072
|
+
performance,
|
|
3073
|
+
atob,
|
|
3074
|
+
btoa,
|
|
3075
|
+
structuredClone
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
3078
|
+
function collectStateObjectClasses(exports_) {
|
|
3079
|
+
const classes = [];
|
|
3080
|
+
for (const value of Object.values(exports_)) {
|
|
3081
|
+
if (typeof value !== "function") continue;
|
|
3082
|
+
const proto = value.prototype;
|
|
3083
|
+
if (typeof proto !== "object" || proto === null) continue;
|
|
3084
|
+
if (!(proto instanceof StateObject)) continue;
|
|
3085
|
+
if (!Object.hasOwn(value, "typeName")) {
|
|
3086
|
+
throw new Error(
|
|
3087
|
+
`\u72B6\u6001\u5BF9\u8C61\u7C7B\u5FC5\u987B\u58F0\u660E static typeName\uFF08${value.name ?? "anonymous"}\uFF09`
|
|
3088
|
+
);
|
|
3089
|
+
}
|
|
3090
|
+
const typeName = value.typeName;
|
|
3091
|
+
if (typeof typeName !== "string" || typeName.length === 0) {
|
|
3092
|
+
throw new Error(
|
|
3093
|
+
`\u72B6\u6001\u5BF9\u8C61\u7C7B\u5FC5\u987B\u58F0\u660E static typeName\uFF08${value.name ?? "anonymous"}\uFF09`
|
|
3094
|
+
);
|
|
3095
|
+
}
|
|
3096
|
+
classes.push(value);
|
|
3097
|
+
}
|
|
3098
|
+
return classes;
|
|
3099
|
+
}
|
|
3100
|
+
function loadStateObjectClasses(files, entry = STATE_OBJECTS_ENTRY, options = {}) {
|
|
3101
|
+
if (files[entry] === void 0) {
|
|
3102
|
+
throw new Error(`\u72B6\u6001\u5BF9\u8C61\u58F0\u660E\u6587\u4EF6\u7F3A\u5931\uFF1A${entry}\uFF08\u7EA6\u5B9A ${STATE_OBJECTS_ENTRY}\uFF09`);
|
|
3103
|
+
}
|
|
3104
|
+
const globals = options.sandboxGlobals ?? defaultStateSandboxGlobals();
|
|
3105
|
+
const exportsObject = loadModule(entry, files, globals, /* @__PURE__ */ new Map(), options.resolveBare, /* @__PURE__ */ new Map());
|
|
3106
|
+
return collectStateObjectClasses(exportsObject);
|
|
3107
|
+
}
|
|
3108
|
+
|
|
3109
|
+
// packages/runtime/src/functions/runtime/worker-entry.ts
|
|
3110
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
3111
|
+
import { createRequire } from "node:module";
|
|
3112
|
+
import { join as join7 } from "node:path";
|
|
3113
|
+
|
|
3114
|
+
// packages/runtime/src/functions/runtime/cloud-container.ts
|
|
3115
|
+
var KNOWN_CAPABILITY_HINTS = {
|
|
3116
|
+
db: {
|
|
3117
|
+
code: "DB_NOT_PROVISIONED",
|
|
3118
|
+
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"
|
|
3119
|
+
},
|
|
3120
|
+
storage: {
|
|
3121
|
+
code: "STORAGE_NOT_AVAILABLE",
|
|
3122
|
+
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"
|
|
3123
|
+
},
|
|
3124
|
+
fetch: {
|
|
3125
|
+
code: "FN_FETCH_DISABLED",
|
|
3126
|
+
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"
|
|
3127
|
+
},
|
|
3128
|
+
realtime: {
|
|
3129
|
+
code: "REALTIME_NOT_AVAILABLE",
|
|
3130
|
+
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"
|
|
3131
|
+
},
|
|
3132
|
+
kv: {
|
|
3133
|
+
code: "KV_NOT_PROVISIONED",
|
|
3134
|
+
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"
|
|
3135
|
+
}
|
|
3136
|
+
};
|
|
3137
|
+
var CapabilityNotRegisteredError = class extends Error {
|
|
3138
|
+
code;
|
|
3139
|
+
constructor(code, message) {
|
|
3140
|
+
super(message);
|
|
3141
|
+
this.code = code;
|
|
3142
|
+
this.name = "CapabilityNotRegisteredError";
|
|
3143
|
+
}
|
|
3144
|
+
};
|
|
3145
|
+
function createCloud(registrations) {
|
|
3146
|
+
const store = registrations;
|
|
3147
|
+
return new Proxy(
|
|
3148
|
+
{},
|
|
3149
|
+
{
|
|
3150
|
+
get(_target, prop) {
|
|
3151
|
+
if (typeof prop !== "string") return void 0;
|
|
3152
|
+
if (!store.has(prop)) {
|
|
3153
|
+
const hint = KNOWN_CAPABILITY_HINTS[prop];
|
|
3154
|
+
throw new CapabilityNotRegisteredError(
|
|
3155
|
+
hint?.code ?? "CAPABILITY_NOT_REGISTERED",
|
|
3156
|
+
hint?.message ?? `\u80FD\u529B "${prop}" \u672A\u6CE8\u518C\uFF1A\u8BF7\u5728\u51FD\u6570\u6240\u5728\u9879\u76EE\u5B89\u88C5\u5BF9\u5E94\u80FD\u529B`
|
|
3157
|
+
);
|
|
3158
|
+
}
|
|
3159
|
+
return store.get(prop);
|
|
3160
|
+
},
|
|
3161
|
+
has: () => true
|
|
3162
|
+
// 支持 'db' in ctx.cloud 形态
|
|
3163
|
+
}
|
|
3164
|
+
);
|
|
3165
|
+
}
|
|
3166
|
+
function createCloudContainer() {
|
|
3167
|
+
const registry = /* @__PURE__ */ new Map();
|
|
3168
|
+
const names = /* @__PURE__ */ new Set();
|
|
3169
|
+
let cloud = null;
|
|
3170
|
+
const rebuild = () => {
|
|
3171
|
+
cloud = createCloud(registry);
|
|
3172
|
+
};
|
|
3173
|
+
rebuild();
|
|
3174
|
+
return {
|
|
3175
|
+
register(name, impl) {
|
|
3176
|
+
registry.set(name, impl);
|
|
3177
|
+
names.add(name);
|
|
3178
|
+
rebuild();
|
|
3179
|
+
},
|
|
3180
|
+
unregister(name) {
|
|
3181
|
+
registry.delete(name);
|
|
3182
|
+
names.delete(name);
|
|
3183
|
+
rebuild();
|
|
3184
|
+
},
|
|
3185
|
+
get names() {
|
|
3186
|
+
return [...names];
|
|
3187
|
+
},
|
|
3188
|
+
get cloud() {
|
|
3189
|
+
return cloud;
|
|
3190
|
+
}
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
// packages/runtime/src/functions/runtime/sandbox-fetch.ts
|
|
3195
|
+
var SandboxFetchError = class extends Error {
|
|
3196
|
+
code;
|
|
3197
|
+
constructor(code, message) {
|
|
3198
|
+
super(message);
|
|
3199
|
+
this.name = "SandboxFetchError";
|
|
3200
|
+
this.code = code;
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3203
|
+
var DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
|
|
3204
|
+
var defaultFetch = (url, init) => (
|
|
3205
|
+
// 真实 Response 与内部 ResponseLike 结构性一致;getReader 的多态签名差异属纯类型问题,运行语义等价。
|
|
3206
|
+
globalThis.fetch(url, init)
|
|
3207
|
+
);
|
|
3208
|
+
function isHostAllowed(host, rules) {
|
|
3209
|
+
const h = host.toLocaleLowerCase();
|
|
3210
|
+
return rules.some((raw) => {
|
|
3211
|
+
const rule = raw.trim().toLocaleLowerCase();
|
|
3212
|
+
if (rule.startsWith("*.")) {
|
|
3213
|
+
const base = rule.slice(2);
|
|
3214
|
+
return h === base || h.endsWith(`.${base}`);
|
|
3215
|
+
}
|
|
3216
|
+
return h === rule;
|
|
3217
|
+
});
|
|
3218
|
+
}
|
|
3219
|
+
var FORBIDDEN = (url) => new SandboxFetchError(
|
|
3220
|
+
"FN_FETCH_FORBIDDEN",
|
|
3221
|
+
`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`
|
|
3222
|
+
);
|
|
3223
|
+
var TOO_LARGE = new SandboxFetchError(
|
|
3224
|
+
"FN_FETCH_TOO_LARGE",
|
|
3225
|
+
"cloud.fetch \u54CD\u5E94\u4F53\u8D85\u8FC7\u4E0A\u9650\uFF08FN_FETCH_TOO_LARGE\uFF09"
|
|
3226
|
+
);
|
|
3227
|
+
function headersToRecord(headers) {
|
|
3228
|
+
const out = {};
|
|
3229
|
+
if (headers === void 0 || headers === null) return out;
|
|
3230
|
+
if (typeof headers.forEach === "function") {
|
|
3231
|
+
;
|
|
3232
|
+
headers.forEach((value, key) => {
|
|
3233
|
+
out[String(key).toLocaleLowerCase()] = String(value);
|
|
3234
|
+
});
|
|
3235
|
+
return out;
|
|
3236
|
+
}
|
|
3237
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
3238
|
+
out[key.toLocaleLowerCase()] = String(value);
|
|
3239
|
+
}
|
|
3240
|
+
return out;
|
|
3241
|
+
}
|
|
3242
|
+
function contentLength(res) {
|
|
3243
|
+
const headers = res.headers;
|
|
3244
|
+
if (headers === void 0 || headers === null) return null;
|
|
3245
|
+
if (typeof headers.get === "function") {
|
|
3246
|
+
const raw2 = headers.get?.("content-length");
|
|
3247
|
+
if (raw2 === void 0 || raw2 === null || raw2.trim() === "") return null;
|
|
3248
|
+
const n2 = Number(raw2);
|
|
3249
|
+
return Number.isFinite(n2) && n2 >= 0 ? n2 : null;
|
|
3250
|
+
}
|
|
3251
|
+
const record = headers;
|
|
3252
|
+
const raw = record["content-length"] ?? record["Content-Length"];
|
|
3253
|
+
if (raw === void 0 || raw === null) return null;
|
|
3254
|
+
const n = Number(raw);
|
|
3255
|
+
return Number.isFinite(n) && n >= 0 ? n : null;
|
|
3256
|
+
}
|
|
3257
|
+
function concatChunks(chunks, total) {
|
|
3258
|
+
const merged = new Uint8Array(total);
|
|
3259
|
+
let offset = 0;
|
|
3260
|
+
for (const chunk of chunks) {
|
|
3261
|
+
merged.set(chunk, offset);
|
|
3262
|
+
offset += chunk.byteLength;
|
|
3263
|
+
}
|
|
3264
|
+
return merged;
|
|
3265
|
+
}
|
|
3266
|
+
async function readBodyBytes(res, maxBytes) {
|
|
3267
|
+
if (maxBytes > 0) {
|
|
3268
|
+
const cl = contentLength(res);
|
|
3269
|
+
if (cl !== null && cl > maxBytes) throw TOO_LARGE;
|
|
3270
|
+
}
|
|
3271
|
+
const body = res.body;
|
|
3272
|
+
if (body !== void 0 && body !== null) {
|
|
3273
|
+
const reader = body.getReader();
|
|
3274
|
+
const chunks = [];
|
|
3275
|
+
let total = 0;
|
|
3276
|
+
for (; ; ) {
|
|
3277
|
+
const { done, value } = await reader.read();
|
|
3278
|
+
if (done) break;
|
|
3279
|
+
if (value !== void 0) {
|
|
3280
|
+
total += value.byteLength;
|
|
3281
|
+
if (maxBytes > 0 && total > maxBytes) throw TOO_LARGE;
|
|
3282
|
+
chunks.push(value);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
return concatChunks(chunks, total);
|
|
3286
|
+
}
|
|
3287
|
+
if (typeof res.arrayBuffer === "function") {
|
|
3288
|
+
const buffer = await res.arrayBuffer();
|
|
3289
|
+
const bytes2 = new Uint8Array(buffer);
|
|
3290
|
+
if (maxBytes > 0 && bytes2.byteLength > maxBytes) throw TOO_LARGE;
|
|
3291
|
+
return bytes2;
|
|
3292
|
+
}
|
|
3293
|
+
const text = await res.text();
|
|
3294
|
+
const bytes = encoder.encode(text);
|
|
3295
|
+
if (maxBytes > 0 && bytes.byteLength > maxBytes) throw TOO_LARGE;
|
|
3296
|
+
return bytes;
|
|
3297
|
+
}
|
|
3298
|
+
var encoder = new TextEncoder();
|
|
3299
|
+
function errorMessageOf(error) {
|
|
3300
|
+
if (error instanceof Error) return error.message;
|
|
3301
|
+
return String(error);
|
|
3302
|
+
}
|
|
3303
|
+
function normalizeResponse(res, maxBytes) {
|
|
3304
|
+
let cached = null;
|
|
3305
|
+
let cachedPromise = null;
|
|
3306
|
+
const readCached = () => {
|
|
3307
|
+
if (cached !== null) return Promise.resolve(cached);
|
|
3308
|
+
cachedPromise ??= readBodyBytes(res, maxBytes).then((bytes) => {
|
|
3309
|
+
cached = bytes;
|
|
3310
|
+
return bytes;
|
|
3311
|
+
});
|
|
3312
|
+
return cachedPromise;
|
|
3313
|
+
};
|
|
3314
|
+
const read = () => readCached();
|
|
3315
|
+
return {
|
|
3316
|
+
ok: res.ok,
|
|
3317
|
+
status: res.status,
|
|
3318
|
+
statusText: res.statusText,
|
|
3319
|
+
headers: headersToRecord(res.headers),
|
|
3320
|
+
text: async () => decoder.decode(await read()),
|
|
3321
|
+
arrayBuffer: async () => bufferViewToArrayBuffer(await read()),
|
|
3322
|
+
json: async () => JSON.parse(decoder.decode(await read()))
|
|
3323
|
+
};
|
|
3324
|
+
}
|
|
3325
|
+
var decoder = new TextDecoder();
|
|
3326
|
+
function bufferViewToArrayBuffer(bytes) {
|
|
3327
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
3328
|
+
}
|
|
3329
|
+
function createSandboxFetch(options) {
|
|
3330
|
+
const fetchImpl = options.fetchImpl ?? defaultFetch;
|
|
3331
|
+
const { allowlist, timeoutMs } = options;
|
|
3332
|
+
const maxBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
3333
|
+
return async (url, init) => {
|
|
3334
|
+
let parsed;
|
|
3335
|
+
try {
|
|
3336
|
+
parsed = new URL(url);
|
|
3337
|
+
} catch {
|
|
3338
|
+
throw new SandboxFetchError("FN_FETCH_INVALID_URL", `cloud.fetch \u6536\u5230\u975E\u6CD5 URL"${url}"`);
|
|
3339
|
+
}
|
|
3340
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw FORBIDDEN(url);
|
|
3341
|
+
if (!isHostAllowed(parsed.hostname, allowlist)) throw FORBIDDEN(url);
|
|
3342
|
+
const controller = new AbortController();
|
|
3343
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3344
|
+
const signals = [controller.signal];
|
|
3345
|
+
if (init?.signal !== void 0) signals.push(init.signal);
|
|
3346
|
+
const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
3347
|
+
try {
|
|
3348
|
+
let res;
|
|
3349
|
+
try {
|
|
3350
|
+
res = await fetchImpl(url, { ...init, signal });
|
|
3351
|
+
} catch (error) {
|
|
3352
|
+
if (controller.signal.aborted) {
|
|
3353
|
+
throw new SandboxFetchError(
|
|
3354
|
+
"FN_FETCH_TIMEOUT",
|
|
3355
|
+
`cloud.fetch \u8BF7\u6C42\u8D85\u65F6\uFF08\u8D85\u8FC7 ${timeoutMs}ms\uFF09`
|
|
3356
|
+
);
|
|
3357
|
+
}
|
|
3358
|
+
if (init?.signal?.aborted === true) {
|
|
3359
|
+
throw new SandboxFetchError("FN_FETCH_ABORTED", "cloud.fetch \u8BF7\u6C42\u88AB\u8C03\u7528\u65B9\u4E2D\u6B62");
|
|
3360
|
+
}
|
|
3361
|
+
throw new SandboxFetchError(
|
|
3362
|
+
"FN_FETCH_FAILED",
|
|
3363
|
+
`cloud.fetch \u8BF7\u6C42\u5931\u8D25\uFF1A${errorMessageOf(error)}`
|
|
3364
|
+
);
|
|
3365
|
+
}
|
|
3366
|
+
return normalizeResponse(res, maxBytes);
|
|
3367
|
+
} finally {
|
|
3368
|
+
clearTimeout(timer);
|
|
3369
|
+
}
|
|
3370
|
+
};
|
|
3371
|
+
}
|
|
3372
|
+
|
|
3373
|
+
// packages/runtime/src/functions/runtime/chain.ts
|
|
3374
|
+
function isChainCapability(value) {
|
|
3375
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3376
|
+
const spec = value[CHAIN_CAPABILITY_KEY];
|
|
3377
|
+
return typeof spec === "object" && spec !== null && Array.isArray(spec.stepMethods) && Array.isArray(spec.terminalMethods);
|
|
3378
|
+
}
|
|
3379
|
+
function createChainClient(capability, port, pending, nextId, spec) {
|
|
3380
|
+
const call = (method, args) => new Promise((resolve3, reject) => {
|
|
3381
|
+
const id = nextId();
|
|
3382
|
+
pending.set(id, { resolve: resolve3, reject });
|
|
3383
|
+
port.postMessage({ type: "rpc", id, capability, method, args });
|
|
3384
|
+
});
|
|
3385
|
+
const makeChainable = (rootArgs, steps, txId) => new Proxy(
|
|
3386
|
+
{},
|
|
3387
|
+
{
|
|
3388
|
+
get(_target, prop) {
|
|
3389
|
+
if (typeof prop !== "string") return void 0;
|
|
3390
|
+
if (spec.stepMethods.includes(prop)) {
|
|
3391
|
+
return (...args) => makeChainable(rootArgs, [...steps, { method: prop, args }], txId);
|
|
3392
|
+
}
|
|
3393
|
+
if (spec.terminalMethods.includes(prop)) {
|
|
3394
|
+
return (...args) => call(DB_RPC.chain, [
|
|
3395
|
+
{
|
|
3396
|
+
rootArgs,
|
|
3397
|
+
steps,
|
|
3398
|
+
terminal: prop,
|
|
3399
|
+
terminalArgs: args,
|
|
3400
|
+
...txId === void 0 ? {} : { txId }
|
|
3401
|
+
}
|
|
3402
|
+
]);
|
|
3403
|
+
}
|
|
3404
|
+
return void 0;
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
);
|
|
3408
|
+
const makeRoot = (txId) => new Proxy(
|
|
3409
|
+
{},
|
|
3410
|
+
{
|
|
3411
|
+
get(_target, prop) {
|
|
3412
|
+
if (typeof prop !== "string") return void 0;
|
|
3413
|
+
if (prop === spec.rootMethod) {
|
|
3414
|
+
return (...rootArgs) => makeChainable(rootArgs, [], txId);
|
|
3415
|
+
}
|
|
3416
|
+
if (spec.directMethods.includes(prop)) {
|
|
3417
|
+
return (...args) => call(prop, args);
|
|
3418
|
+
}
|
|
3419
|
+
if (prop === spec.transactionMethod) {
|
|
3420
|
+
return (fn) => orchestrateTransaction(fn, txId);
|
|
3421
|
+
}
|
|
3422
|
+
return void 0;
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
);
|
|
3426
|
+
const orchestrateTransaction = async (fn, _outerTxId) => {
|
|
3427
|
+
const txId = await call(DB_RPC.begin, []);
|
|
3428
|
+
const tx = makeRoot(txId);
|
|
3429
|
+
const settle = async (commit) => {
|
|
3430
|
+
await call(commit ? DB_RPC.commit : DB_RPC.rollback, [txId]).catch(() => void 0);
|
|
3431
|
+
};
|
|
3432
|
+
try {
|
|
3433
|
+
const result = await fn(tx);
|
|
3434
|
+
await settle(true);
|
|
3435
|
+
return result;
|
|
3436
|
+
} catch (error) {
|
|
3437
|
+
await settle(false);
|
|
3438
|
+
throw error;
|
|
3439
|
+
}
|
|
3440
|
+
};
|
|
3441
|
+
return makeRoot(void 0);
|
|
3442
|
+
}
|
|
3443
|
+
|
|
3444
|
+
// packages/runtime/src/functions/runtime/worker-entry.ts
|
|
3445
|
+
function isRpcCapability(value) {
|
|
3446
|
+
return typeof value === "object" && value !== null && value[RPC_CAPABILITY_KEY] === true;
|
|
3447
|
+
}
|
|
3448
|
+
function createRpcClient(capability, port, pending, nextId) {
|
|
3449
|
+
return new Proxy(
|
|
3450
|
+
{},
|
|
3451
|
+
{
|
|
3452
|
+
get(_target, method) {
|
|
3453
|
+
if (typeof method !== "string") return void 0;
|
|
3454
|
+
return (...args) => {
|
|
3455
|
+
const id = nextId();
|
|
3456
|
+
return new Promise((resolve3, reject) => {
|
|
3457
|
+
pending.set(id, { resolve: resolve3, reject });
|
|
3458
|
+
port.postMessage({ type: "rpc", id, capability, method, args });
|
|
3459
|
+
});
|
|
3460
|
+
};
|
|
3461
|
+
}
|
|
3462
|
+
}
|
|
3463
|
+
);
|
|
3464
|
+
}
|
|
3465
|
+
function errorMessageOf2(error) {
|
|
3466
|
+
if (error instanceof Error) return error.message;
|
|
3467
|
+
if (typeof error === "object" && error !== null && "message" in error) {
|
|
3468
|
+
const message = error.message;
|
|
3469
|
+
if (typeof message === "string") return message;
|
|
3470
|
+
}
|
|
3471
|
+
return String(error);
|
|
3472
|
+
}
|
|
3473
|
+
function escapeRegExp(text) {
|
|
3474
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3475
|
+
}
|
|
3476
|
+
function firstUserFrame(stack, files) {
|
|
3477
|
+
for (const key of Object.keys(files)) {
|
|
3478
|
+
const match = new RegExp(
|
|
3479
|
+
`(?<![\\w$/.])${escapeRegExp(key)}:(\\d+)(?::(\\d+))?(?::(\\d+))?`
|
|
3480
|
+
).exec(stack);
|
|
3481
|
+
if (match !== null) {
|
|
3482
|
+
return match[2] === void 0 ? `${key}:${match[1]}` : `${key}:${match[1]}:${match[2]}`;
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
return void 0;
|
|
3486
|
+
}
|
|
3487
|
+
function errorMessageWithLocation(error, files) {
|
|
3488
|
+
const message = errorMessageOf2(error);
|
|
3489
|
+
const stack = error.stack;
|
|
3490
|
+
if (typeof stack !== "string") return message;
|
|
3491
|
+
const frame = firstUserFrame(stack, files);
|
|
3492
|
+
return frame === void 0 ? message : `${message}\uFF08${frame}\uFF09`;
|
|
3493
|
+
}
|
|
3494
|
+
function createBareResolver(deps) {
|
|
3495
|
+
const platformRequire = createRequire(import.meta.url);
|
|
3496
|
+
const depsRequire = deps.dir === null ? null : createRequire(join7(deps.dir, "__deps__.js"));
|
|
3497
|
+
return (request) => {
|
|
3498
|
+
if (deps.builtin.includes(request)) return platformRequire(request);
|
|
3499
|
+
const root = splitBareSpecifier(request);
|
|
3500
|
+
if (deps.builtin.includes(root)) return platformRequire(request);
|
|
3501
|
+
if (deps.custom.includes(root)) {
|
|
3502
|
+
if (depsRequire === null) {
|
|
3503
|
+
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`);
|
|
3504
|
+
}
|
|
3505
|
+
try {
|
|
3506
|
+
return depsRequire(request);
|
|
3507
|
+
} catch (error2) {
|
|
3508
|
+
const message = errorMessageOf2(error2);
|
|
3509
|
+
throw new Error(
|
|
3510
|
+
`\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}`,
|
|
3511
|
+
{ cause: error2 }
|
|
3512
|
+
);
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
const error = new Error(
|
|
3516
|
+
`\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`
|
|
3517
|
+
);
|
|
3518
|
+
error.code = SANDBOX_BUILTIN_REJECTED;
|
|
3519
|
+
throw error;
|
|
3520
|
+
};
|
|
3521
|
+
}
|
|
3522
|
+
function runWorker(input, port) {
|
|
3523
|
+
const emit = (level, args) => {
|
|
3524
|
+
port.postMessage({ type: "log", level, message: args.map(String).join(" ") });
|
|
3525
|
+
};
|
|
3526
|
+
const forwardedConsole = {
|
|
3527
|
+
log: (...args) => emit("log", args),
|
|
3528
|
+
error: (...args) => emit("error", args),
|
|
3529
|
+
warn: (...args) => emit("warn", args)
|
|
3530
|
+
};
|
|
3531
|
+
const container = createCloudContainer();
|
|
3532
|
+
const pending = /* @__PURE__ */ new Map();
|
|
3533
|
+
let rpcId = 0;
|
|
3534
|
+
port.on?.((message) => {
|
|
3535
|
+
const reply = message;
|
|
3536
|
+
if (reply?.type !== "rpc-response" || typeof reply.id !== "number") return;
|
|
3537
|
+
const entry = pending.get(reply.id);
|
|
3538
|
+
if (entry === void 0) return;
|
|
3539
|
+
pending.delete(reply.id);
|
|
3540
|
+
if (reply.ok === true) entry.resolve(reply.result);
|
|
3541
|
+
else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
|
|
3542
|
+
});
|
|
3543
|
+
for (const capability of input.capabilities ?? []) {
|
|
3544
|
+
container.register(
|
|
3545
|
+
capability.name,
|
|
3546
|
+
isChainCapability(capability.value) ? createChainClient(
|
|
3547
|
+
capability.name,
|
|
3548
|
+
port,
|
|
3549
|
+
pending,
|
|
3550
|
+
() => ++rpcId,
|
|
3551
|
+
capability.value[CHAIN_CAPABILITY_KEY]
|
|
3552
|
+
) : isRpcCapability(capability.value) ? createRpcClient(capability.name, port, pending, () => ++rpcId) : capability.value
|
|
3553
|
+
);
|
|
3554
|
+
}
|
|
3555
|
+
const sandboxGlobals = {
|
|
3556
|
+
console: forwardedConsole,
|
|
3557
|
+
// CF-015:Cloudflare Workers 代码重度依赖 Web 标准 API(URL / Request / Response /
|
|
3558
|
+
// Headers / 流 / 编码 / crypto 等)。Node 18+ 全局内置,直接注入 vm 上下文;
|
|
3559
|
+
// 与 @adep/cf-compat 的 Workers 适配(ctxToRequest / responseToEnvelopeBody)配套。
|
|
3560
|
+
URL,
|
|
3561
|
+
URLSearchParams,
|
|
3562
|
+
Request,
|
|
3563
|
+
Response,
|
|
3564
|
+
Headers,
|
|
3565
|
+
TextEncoder,
|
|
3566
|
+
TextDecoder,
|
|
3567
|
+
AbortController,
|
|
3568
|
+
AbortSignal,
|
|
3569
|
+
ReadableStream,
|
|
3570
|
+
WritableStream,
|
|
3571
|
+
TransformStream,
|
|
3572
|
+
Blob,
|
|
3573
|
+
FormData,
|
|
3574
|
+
crypto,
|
|
3575
|
+
performance,
|
|
3576
|
+
atob,
|
|
3577
|
+
btoa,
|
|
3578
|
+
structuredClone
|
|
3579
|
+
};
|
|
3580
|
+
if (input.env !== void 0) {
|
|
3581
|
+
sandboxGlobals["process"] = { env: input.env };
|
|
3582
|
+
}
|
|
3583
|
+
if (input.fetch !== void 0) {
|
|
3584
|
+
const sandboxFetch = createSandboxFetch({
|
|
3585
|
+
allowlist: input.fetch.allowlist,
|
|
3586
|
+
timeoutMs: input.fetch.timeoutMs,
|
|
3587
|
+
...input.fetch.maxResponseBytes === void 0 ? {} : { maxResponseBytes: input.fetch.maxResponseBytes }
|
|
3588
|
+
});
|
|
3589
|
+
sandboxGlobals["fetch"] = sandboxFetch;
|
|
3590
|
+
container.register("fetch", sandboxFetch);
|
|
3591
|
+
}
|
|
3592
|
+
const ctx = {
|
|
3593
|
+
method: input.request.method,
|
|
3594
|
+
path: input.request.path,
|
|
3595
|
+
query: input.request.query,
|
|
3596
|
+
headers: input.request.headers,
|
|
3597
|
+
...input.request.body === void 0 ? {} : { body: input.request.body },
|
|
3598
|
+
files: input.request.files ?? [],
|
|
3599
|
+
cloud: container.cloud,
|
|
3600
|
+
user: input.request.user ?? null,
|
|
3601
|
+
...input.env === void 0 ? {} : { env: input.env }
|
|
3602
|
+
};
|
|
3603
|
+
try {
|
|
3604
|
+
const { handler } = loadFunctionModule(
|
|
3605
|
+
input.files,
|
|
3606
|
+
input.entry,
|
|
3607
|
+
sandboxGlobals,
|
|
3608
|
+
input.deps === void 0 ? void 0 : createBareResolver(input.deps)
|
|
3609
|
+
);
|
|
3610
|
+
const result = Promise.resolve(handler(ctx));
|
|
3611
|
+
void result.then(
|
|
3612
|
+
(value) => {
|
|
3613
|
+
port.postMessage({ type: "result", body: value === void 0 ? null : value });
|
|
3614
|
+
return void 0;
|
|
3615
|
+
},
|
|
3616
|
+
(error) => {
|
|
3617
|
+
port.postMessage({
|
|
3618
|
+
type: "error",
|
|
3619
|
+
message: errorMessageWithLocation(error, input.files),
|
|
3620
|
+
code: error.code,
|
|
3621
|
+
// FN-011:函数抛错可携带 status(4xx/5xx),透传给执行器落 ExecutorError.status。
|
|
3622
|
+
status: error.status
|
|
3623
|
+
});
|
|
3624
|
+
return void 0;
|
|
3625
|
+
}
|
|
3626
|
+
);
|
|
3627
|
+
} catch (error) {
|
|
3628
|
+
port.postMessage({
|
|
3629
|
+
type: "error",
|
|
3630
|
+
message: errorMessageWithLocation(error, input.files),
|
|
3631
|
+
code: error.code,
|
|
3632
|
+
status: error.status
|
|
3633
|
+
});
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
var workerPort = parentPort;
|
|
3637
|
+
if (workerPort !== null && workerData !== void 0) {
|
|
3638
|
+
const port = {
|
|
3639
|
+
// eslint-disable-next-line unicorn/require-post-message-target-origin -- node worker_threads 无 targetOrigin 语义
|
|
3640
|
+
postMessage: (message) => workerPort.postMessage(message),
|
|
3641
|
+
on: (listener) => {
|
|
3642
|
+
workerPort.on("message", (value) => listener(value));
|
|
3643
|
+
}
|
|
3644
|
+
};
|
|
3645
|
+
runWorker(workerData, port);
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
// packages/cli/src/dev.ts
|
|
2414
3649
|
async function loadConfig(cwd) {
|
|
2415
3650
|
const name = basename(resolve2(cwd));
|
|
2416
3651
|
const config = await loadAdepConfigModule(cwd);
|
|
2417
3652
|
return {
|
|
2418
3653
|
name: config?.name ?? name,
|
|
2419
3654
|
functionsDir: config?.functionsDir ?? "functions",
|
|
2420
|
-
functionsPrefix: config?.functions_prefix ?? ""
|
|
3655
|
+
functionsPrefix: config?.functions_prefix ?? "",
|
|
3656
|
+
...config?.environment === void 0 ? {} : { environment: config.environment }
|
|
2421
3657
|
};
|
|
2422
3658
|
}
|
|
2423
3659
|
function parseEnvFile(content) {
|
|
@@ -2444,7 +3680,7 @@ async function collectFunctions(dir) {
|
|
|
2444
3680
|
}
|
|
2445
3681
|
for (const entry of entries) {
|
|
2446
3682
|
const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
|
|
2447
|
-
const full =
|
|
3683
|
+
const full = join8(sub, entry.name);
|
|
2448
3684
|
if (entry.isDirectory()) {
|
|
2449
3685
|
await walk(full, rel);
|
|
2450
3686
|
} else if (entry.isFile() && entry.name.endsWith(".ts")) {
|
|
@@ -2511,7 +3747,7 @@ function printBoundaries(log) {
|
|
|
2511
3747
|
}
|
|
2512
3748
|
}
|
|
2513
3749
|
async function ensureGitignore(cwd) {
|
|
2514
|
-
const gitignorePath =
|
|
3750
|
+
const gitignorePath = join8(cwd, ".gitignore");
|
|
2515
3751
|
const existing = await readFile5(gitignorePath, "utf8").catch(() => "");
|
|
2516
3752
|
if (existing.split(/\r?\n/).includes(".adep/")) return;
|
|
2517
3753
|
await writeFile3(gitignorePath, `${existing.replace(/\n+$/, "")}
|
|
@@ -2526,9 +3762,11 @@ async function startDevServer(options) {
|
|
|
2526
3762
|
if (options.prefix !== void 0) {
|
|
2527
3763
|
config.functionsPrefix = options.prefix.replace(/^\/+|\/+$/g, "");
|
|
2528
3764
|
}
|
|
2529
|
-
const functionsDir =
|
|
3765
|
+
const functionsDir = join8(cwd, config.functionsDir);
|
|
2530
3766
|
const coldStartAt = Date.now();
|
|
2531
|
-
const executor = new WorkerFunctionExecutor(
|
|
3767
|
+
const executor = new WorkerFunctionExecutor({
|
|
3768
|
+
deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
|
|
3769
|
+
});
|
|
2532
3770
|
await mkdir3(functionsDir, { recursive: true });
|
|
2533
3771
|
const runtime = await createSimRuntime({
|
|
2534
3772
|
cwd,
|
|
@@ -2538,19 +3776,91 @@ async function startDevServer(options) {
|
|
|
2538
3776
|
});
|
|
2539
3777
|
await ensureGitignore(cwd);
|
|
2540
3778
|
let files = await collectFunctions(functionsDir);
|
|
2541
|
-
let env =
|
|
3779
|
+
let env = {
|
|
3780
|
+
...config.environment,
|
|
3781
|
+
...await loadSimEnv(cwd).catch(() => ({}))
|
|
3782
|
+
};
|
|
2542
3783
|
const dbBundle = runtime.bundle;
|
|
2543
3784
|
const invokeHandler = createSimInvokeHandler({ executor, files });
|
|
3785
|
+
let stateRuntime = null;
|
|
3786
|
+
let stateFingerprint = "";
|
|
3787
|
+
const bareResolver = createBareResolver({
|
|
3788
|
+
dir: null,
|
|
3789
|
+
builtin: [...LOCAL_BUILTIN_DEPS],
|
|
3790
|
+
custom: []
|
|
3791
|
+
});
|
|
3792
|
+
const collectStateDeclarations = () => {
|
|
3793
|
+
const declared = [];
|
|
3794
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
3795
|
+
for (const path of Object.keys(files)) {
|
|
3796
|
+
if (path === STATE_OBJECTS_ENTRY || path.endsWith(`/${STATE_OBJECTS_ENTRY}`)) {
|
|
3797
|
+
dirs.add(path === STATE_OBJECTS_ENTRY ? "" : path.slice(0, -STATE_OBJECTS_ENTRY.length - 1));
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
for (const dir of dirs) {
|
|
3801
|
+
const prefix = dir.length === 0 ? "" : `${dir}/`;
|
|
3802
|
+
const fileMap = {};
|
|
3803
|
+
for (const [path, content] of Object.entries(files)) {
|
|
3804
|
+
if (path.startsWith(prefix)) fileMap[path] = content;
|
|
3805
|
+
}
|
|
3806
|
+
declared.push({ dir, files: fileMap });
|
|
3807
|
+
}
|
|
3808
|
+
return declared;
|
|
3809
|
+
};
|
|
3810
|
+
const stateObjectBareResolver = (request) => {
|
|
3811
|
+
const state = resolveStateObjectSpecifier(request);
|
|
3812
|
+
if (state !== void 0) return state;
|
|
3813
|
+
return bareResolver(request);
|
|
3814
|
+
};
|
|
3815
|
+
const refreshStateRuntime = () => {
|
|
3816
|
+
const declarations = collectStateDeclarations();
|
|
3817
|
+
const fingerprint = declarations.map(
|
|
3818
|
+
(d) => `${d.dir}\0${d.files[`${d.dir === "" ? "" : `${d.dir}/`}${STATE_OBJECTS_ENTRY}`] ?? ""}`
|
|
3819
|
+
).join("");
|
|
3820
|
+
if (stateRuntime !== null && stateFingerprint === fingerprint) return stateRuntime;
|
|
3821
|
+
stateRuntime = new StateObjectRuntime(createProjectDriverStateBackend(runtime.db.driver));
|
|
3822
|
+
stateRuntime.define(DemoCounter);
|
|
3823
|
+
stateRuntime.define(DemoChatRoom);
|
|
3824
|
+
for (const d of declarations) {
|
|
3825
|
+
const loaded = loadStateObjectClasses(
|
|
3826
|
+
d.files,
|
|
3827
|
+
`${d.dir === "" ? "" : `${d.dir}/`}${STATE_OBJECTS_ENTRY}`,
|
|
3828
|
+
{
|
|
3829
|
+
resolveBare: stateObjectBareResolver
|
|
3830
|
+
}
|
|
3831
|
+
);
|
|
3832
|
+
for (const cls of loaded) stateRuntime.define(cls);
|
|
3833
|
+
}
|
|
3834
|
+
stateFingerprint = fingerprint;
|
|
3835
|
+
return stateRuntime;
|
|
3836
|
+
};
|
|
3837
|
+
let stateAlarmTimer;
|
|
3838
|
+
const startStateAlarmScheduler = () => {
|
|
3839
|
+
if (stateAlarmTimer !== void 0) return;
|
|
3840
|
+
stateAlarmTimer = setInterval(() => {
|
|
3841
|
+
void refreshStateRuntime().pump(Date.now()).catch((error) => {
|
|
3842
|
+
log(
|
|
3843
|
+
`[adep] \u72B6\u6001\u5BF9\u8C61 alarm tick \u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`
|
|
3844
|
+
);
|
|
3845
|
+
});
|
|
3846
|
+
}, options.stateAlarmTickMs ?? 1e3);
|
|
3847
|
+
stateAlarmTimer.unref?.();
|
|
3848
|
+
};
|
|
3849
|
+
const stopStateAlarmScheduler = () => {
|
|
3850
|
+
if (stateAlarmTimer === void 0) return;
|
|
3851
|
+
clearInterval(stateAlarmTimer);
|
|
3852
|
+
stateAlarmTimer = void 0;
|
|
3853
|
+
};
|
|
2544
3854
|
const reload = async () => {
|
|
2545
3855
|
const [nextFiles, envText2] = await Promise.all([
|
|
2546
3856
|
collectFunctions(functionsDir),
|
|
2547
|
-
readFile5(
|
|
3857
|
+
readFile5(join8(cwd, ".env.local"), "utf8").catch(() => "")
|
|
2548
3858
|
]);
|
|
2549
3859
|
files = nextFiles;
|
|
2550
|
-
env = parseEnvFile(envText2);
|
|
3860
|
+
env = { ...config.environment, ...parseEnvFile(envText2) };
|
|
2551
3861
|
};
|
|
2552
|
-
const envText = await readFile5(
|
|
2553
|
-
env = parseEnvFile(envText);
|
|
3862
|
+
const envText = await readFile5(join8(cwd, ".env.local"), "utf8").catch(() => "");
|
|
3863
|
+
env = { ...config.environment, ...parseEnvFile(envText) };
|
|
2554
3864
|
let debounceTimer;
|
|
2555
3865
|
let watcher;
|
|
2556
3866
|
try {
|
|
@@ -2610,6 +3920,43 @@ async function startDevServer(options) {
|
|
|
2610
3920
|
});
|
|
2611
3921
|
return;
|
|
2612
3922
|
}
|
|
3923
|
+
if (fnName === "state") {
|
|
3924
|
+
const normalizedPrefix = config.functionsPrefix.replace(/^\/+|\/+$/g, "");
|
|
3925
|
+
const rest = normalizedPrefix.length === 0 ? url.pathname : url.pathname.replace(new RegExp(`^/${normalizedPrefix}`), "");
|
|
3926
|
+
const parsed = parseStatePath(rest);
|
|
3927
|
+
if (parsed === null) {
|
|
3928
|
+
writeJson(res, 400, {
|
|
3929
|
+
error: { code: "STATE_BAD_PATH", message: "\u72B6\u6001\u5BF9\u8C61\u8DEF\u5F84\uFF1A/api/state/:type/:id/:method" }
|
|
3930
|
+
});
|
|
3931
|
+
return;
|
|
3932
|
+
}
|
|
3933
|
+
const rawBody = await bodyOf(req);
|
|
3934
|
+
const parsedBody = parseStateBody(
|
|
3935
|
+
req.method === "GET" || req.method === "HEAD" ? null : rawBody === void 0 ? null : typeof rawBody === "string" ? rawBody : JSON.stringify(rawBody)
|
|
3936
|
+
);
|
|
3937
|
+
if ("error" in parsedBody) {
|
|
3938
|
+
writeJson(res, 400, { error: { code: "STATE_BAD_ARGS", message: parsedBody.error } });
|
|
3939
|
+
return;
|
|
3940
|
+
}
|
|
3941
|
+
try {
|
|
3942
|
+
const result = await refreshStateRuntime().invoke(
|
|
3943
|
+
parsed.type,
|
|
3944
|
+
parsed.id,
|
|
3945
|
+
parsed.method,
|
|
3946
|
+
parsedBody.args
|
|
3947
|
+
);
|
|
3948
|
+
writeJson(res, 200, { ok: true, data: result });
|
|
3949
|
+
} catch (error) {
|
|
3950
|
+
if (error instanceof StateObjectError) {
|
|
3951
|
+
writeJson(res, error.code === "STATE_TYPE_NOT_REGISTERED" ? 404 : 400, {
|
|
3952
|
+
error: { code: error.code, message: error.message }
|
|
3953
|
+
});
|
|
3954
|
+
return;
|
|
3955
|
+
}
|
|
3956
|
+
writeJson(res, 500, { error: { code: "STATE_INVOKE_ERROR", message: String(error) } });
|
|
3957
|
+
}
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
2613
3960
|
const entry = resolveFunctionEntry(files, fnName);
|
|
2614
3961
|
if (entry === void 0) {
|
|
2615
3962
|
log(`[adep] ${req.method ?? "GET"} /${fnName} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
|
|
@@ -2621,8 +3968,15 @@ async function startDevServer(options) {
|
|
|
2621
3968
|
try {
|
|
2622
3969
|
const result = await executor.execute(input);
|
|
2623
3970
|
const durationMs = Math.round(performance.now() - startedAt);
|
|
2624
|
-
log(`[adep] ${req.method ?? "GET"} /${fnName} -> 200 ${durationMs}ms`);
|
|
2625
3971
|
for (const line of result.logs) log(`[adep] ${line}`);
|
|
3972
|
+
if (isAdepHttpEnvelope(result.body)) {
|
|
3973
|
+
log(
|
|
3974
|
+
`[adep] ${req.method ?? "GET"} /${fnName} -> ${result.body.__adepHttp.status} ${durationMs}ms`
|
|
3975
|
+
);
|
|
3976
|
+
writeEnvelopeResponse(res, result.body);
|
|
3977
|
+
return;
|
|
3978
|
+
}
|
|
3979
|
+
log(`[adep] ${req.method ?? "GET"} /${fnName} -> 200 ${durationMs}ms`);
|
|
2626
3980
|
writeJson(res, 200, result.body === void 0 ? null : result.body);
|
|
2627
3981
|
} catch (error) {
|
|
2628
3982
|
const durationMs = Math.round(performance.now() - startedAt);
|
|
@@ -2680,10 +4034,12 @@ async function startDevServer(options) {
|
|
|
2680
4034
|
log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
|
|
2681
4035
|
printBoundaries(log);
|
|
2682
4036
|
log(`[adep] \u6A21\u62DF\u6570\u636E\u76EE\u5F55\uFF1A${simDir(cwd)}`);
|
|
4037
|
+
startStateAlarmScheduler();
|
|
2683
4038
|
return {
|
|
2684
4039
|
port: actualPort,
|
|
2685
4040
|
baseUrl,
|
|
2686
4041
|
close: async () => {
|
|
4042
|
+
stopStateAlarmScheduler();
|
|
2687
4043
|
if (debounceTimer !== void 0) clearTimeout(debounceTimer);
|
|
2688
4044
|
watcher?.close();
|
|
2689
4045
|
await new Promise((resolveClose) => server.close(() => resolveClose()));
|
|
@@ -2693,126 +4049,28 @@ async function startDevServer(options) {
|
|
|
2693
4049
|
};
|
|
2694
4050
|
}
|
|
2695
4051
|
|
|
2696
|
-
// src/vite.ts
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
const prefixPath = normalized === "" ? "" : `/${normalized}`;
|
|
2708
|
-
return (req, res, next) => {
|
|
2709
|
-
if (prefixPath === "") return next();
|
|
2710
|
-
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
2711
|
-
if (url.pathname !== prefixPath && !url.pathname.startsWith(`${prefixPath}/`)) {
|
|
2712
|
-
return next();
|
|
2713
|
-
}
|
|
2714
|
-
const target = new URL(url.pathname + url.search, targetBase);
|
|
2715
|
-
const proxyReq = httpRequest(
|
|
2716
|
-
target,
|
|
2717
|
-
{ method: req.method, headers: { ...req.headers, host: target.host } },
|
|
2718
|
-
(proxyRes) => {
|
|
2719
|
-
res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
|
|
2720
|
-
proxyRes.pipe(res);
|
|
2721
|
-
}
|
|
2722
|
-
);
|
|
2723
|
-
proxyReq.on("error", (error) => {
|
|
2724
|
-
if (!res.headersSent) {
|
|
2725
|
-
res.writeHead(502, { "content-type": "application/json" });
|
|
2726
|
-
}
|
|
2727
|
-
res.end(
|
|
2728
|
-
JSON.stringify({
|
|
2729
|
-
error: {
|
|
2730
|
-
code: "ADEP_DEV_UNAVAILABLE",
|
|
2731
|
-
message: `\u4E91\u51FD\u6570\u4EE3\u7406\u5931\u8D25\uFF08adep dev server \u4E0D\u53EF\u8FBE\uFF09\uFF1A${error.message}`
|
|
2732
|
-
}
|
|
2733
|
-
})
|
|
2734
|
-
);
|
|
2735
|
-
});
|
|
2736
|
-
req.pipe(proxyReq);
|
|
2737
|
-
};
|
|
2738
|
-
}
|
|
4052
|
+
// packages/cli/src/vite.ts
|
|
4053
|
+
import {
|
|
4054
|
+
createAdepFnProxyScriptMiddleware,
|
|
4055
|
+
createAdepProxyMiddleware,
|
|
4056
|
+
FN_FETCH_INTERCEPTOR_SCRIPT,
|
|
4057
|
+
injectFnProxyScriptTag,
|
|
4058
|
+
isAddrInUse,
|
|
4059
|
+
normalizeFunctionPrefix
|
|
4060
|
+
} from "@adep/vite-plugin";
|
|
4061
|
+
var createDevServer = (opts) => startDevServer({ cwd: opts.cwd, port: opts.port, prefix: opts.prefix, log: opts.log });
|
|
4062
|
+
var loadConfig2 = (cwd) => loadAdepConfigModule(cwd);
|
|
2739
4063
|
function adepVitePlugin(options = {}) {
|
|
2740
|
-
|
|
2741
|
-
let dev;
|
|
2742
|
-
let prefix = normalizeFunctionPrefix(options.prefix);
|
|
2743
|
-
let prefixPath = "";
|
|
2744
|
-
let startPromise;
|
|
2745
|
-
const startAdepDev = async (log) => {
|
|
2746
|
-
if (startPromise !== void 0) return startPromise;
|
|
2747
|
-
startPromise = (async () => {
|
|
2748
|
-
if (prefix === "") {
|
|
2749
|
-
const config = await loadAdepConfigModule(cwd);
|
|
2750
|
-
prefix = normalizeFunctionPrefix(config?.functions_prefix);
|
|
2751
|
-
if (prefix === "") {
|
|
2752
|
-
log("[adep] adep.config.ts \u672A\u914D\u7F6E functions_prefix\uFF0C\u4E91\u51FD\u6570\u4EE3\u7406\u524D\u7F00\u9ED8\u8BA4 /api");
|
|
2753
|
-
prefix = "api";
|
|
2754
|
-
}
|
|
2755
|
-
}
|
|
2756
|
-
prefixPath = `/${prefix}`;
|
|
2757
|
-
const targetPort = options.port ?? 8787;
|
|
2758
|
-
try {
|
|
2759
|
-
dev = await startDevServer({ cwd, port: targetPort, prefix, log });
|
|
2760
|
-
} catch (error) {
|
|
2761
|
-
if (isAddrInUse(error)) {
|
|
2762
|
-
log(`[adep] \u7AEF\u53E3 ${targetPort} \u88AB\u5360\u7528\uFF0C\u6539\u7528\u968F\u673A\u7AEF\u53E3`);
|
|
2763
|
-
dev = await startDevServer({ cwd, port: 0, prefix, log });
|
|
2764
|
-
} else {
|
|
2765
|
-
log(
|
|
2766
|
-
`[adep] \u4E91\u51FD\u6570 dev server \u542F\u52A8\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}\uFF08vite \u524D\u7AEF\u7167\u5E38\uFF0C\u51FD\u6570\u4EE3\u7406\u4E0D\u53EF\u7528\uFF09`
|
|
2767
|
-
);
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
if (dev !== void 0) {
|
|
2771
|
-
log(
|
|
2772
|
-
`[adep] \u4E91\u51FD\u6570\u5DF2\u5C31\u7EEA\uFF1A${dev.baseUrl}${prefixPath}/<fn>\uFF08vite \u4EE3\u7406 ${prefixPath}/* \u2192 \u4E91\u51FD\u6570\uFF09`
|
|
2773
|
-
);
|
|
2774
|
-
}
|
|
2775
|
-
})();
|
|
2776
|
-
try {
|
|
2777
|
-
await startPromise;
|
|
2778
|
-
} finally {
|
|
2779
|
-
startPromise = void 0;
|
|
2780
|
-
}
|
|
2781
|
-
};
|
|
2782
|
-
const disposeAdepDev = async () => {
|
|
2783
|
-
if (dev === void 0) return;
|
|
2784
|
-
const target = dev;
|
|
2785
|
-
dev = void 0;
|
|
2786
|
-
await target.close();
|
|
2787
|
-
};
|
|
2788
|
-
const attachProxy = (server) => {
|
|
2789
|
-
if (dev === void 0 || prefixPath === "") return;
|
|
2790
|
-
server.middlewares.use(createAdepProxyMiddleware(prefixPath, dev.baseUrl));
|
|
2791
|
-
};
|
|
2792
|
-
return {
|
|
2793
|
-
name: "adep-cloud-functions",
|
|
2794
|
-
async configureServer(server) {
|
|
2795
|
-
const log = (line) => server.config.logger.info(line);
|
|
2796
|
-
await startAdepDev(log);
|
|
2797
|
-
attachProxy(server);
|
|
2798
|
-
server.httpServer?.on("close", () => {
|
|
2799
|
-
void disposeAdepDev();
|
|
2800
|
-
});
|
|
2801
|
-
},
|
|
2802
|
-
async configurePreviewServer(server) {
|
|
2803
|
-
const log = (line) => server.config.logger.info(line);
|
|
2804
|
-
await startAdepDev(log);
|
|
2805
|
-
attachProxy(server);
|
|
2806
|
-
},
|
|
2807
|
-
async closeBundle() {
|
|
2808
|
-
await disposeAdepDev();
|
|
2809
|
-
}
|
|
2810
|
-
};
|
|
4064
|
+
return adepPlugin({ ...options, createDevServer, loadConfig: loadConfig2 });
|
|
2811
4065
|
}
|
|
2812
4066
|
var vite_default = adepVitePlugin;
|
|
2813
4067
|
export {
|
|
4068
|
+
FN_FETCH_INTERCEPTOR_SCRIPT,
|
|
2814
4069
|
adepVitePlugin,
|
|
4070
|
+
createAdepFnProxyScriptMiddleware,
|
|
2815
4071
|
createAdepProxyMiddleware,
|
|
2816
4072
|
vite_default as default,
|
|
4073
|
+
injectFnProxyScriptTag,
|
|
4074
|
+
isAddrInUse,
|
|
2817
4075
|
normalizeFunctionPrefix
|
|
2818
4076
|
};
|