@cloudflare/vitest-pool-workers 0.12.20 → 0.13.0
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/codemods/vitest-v3-to-v4.mjs +45 -0
- package/dist/codemods/vitest-v3-to-v4.mjs.map +1 -0
- package/dist/pool/index.d.mts +133 -0
- package/dist/pool/index.mjs +2784 -7847
- package/dist/pool/index.mjs.map +1 -6
- package/dist/worker/index.mjs +753 -792
- package/dist/worker/index.mjs.map +1 -6
- package/dist/worker/lib/cloudflare/snapshot.mjs +39 -0
- package/dist/worker/lib/cloudflare/snapshot.mjs.map +1 -0
- package/dist/worker/lib/cloudflare/test-internal.mjs +788 -1276
- package/dist/worker/lib/cloudflare/test-internal.mjs.map +1 -6
- package/dist/worker/lib/cloudflare/test.mjs +3 -36
- package/dist/worker/node/console.mjs +95 -116
- package/dist/worker/node/console.mjs.map +1 -6
- package/dist/worker/node/vm.mjs +10 -11
- package/dist/worker/node/vm.mjs.map +1 -6
- package/package.json +25 -21
- package/types/cloudflare-test.d.ts +5 -30
- package/dist/config/d1.d.ts +0 -7
- package/dist/config/index.cjs +0 -230
- package/dist/config/index.cjs.map +0 -6
- package/dist/config/index.d.ts +0 -27
- package/dist/config/pages.d.ts +0 -2
- package/dist/pool/config.d.ts +0 -112
- package/dist/pool/helpers.d.ts +0 -5
- package/dist/shared/builtin-modules.d.ts +0 -1
- package/dist/shared/d1.d.ts +0 -4
- package/dist/worker/lib/cloudflare/empty-internal.cjs +0 -27
- package/dist/worker/lib/cloudflare/empty-internal.cjs.map +0 -6
- package/dist/worker/lib/cloudflare/mock-agent.cjs +0 -3433
- package/dist/worker/lib/cloudflare/mock-agent.cjs.map +0 -6
- package/dist/worker/lib/cloudflare/test-runner.mjs +0 -246
- package/dist/worker/lib/cloudflare/test-runner.mjs.map +0 -6
- package/dist/worker/lib/cloudflare/test.mjs.map +0 -6
- package/dist/worker/lib/debug.mjs +0 -9
- package/dist/worker/lib/debug.mjs.map +0 -6
- package/dist/worker/lib/mlly.mjs +0 -48
- package/dist/worker/lib/mlly.mjs.map +0 -6
- package/dist/worker/lib/tinypool.mjs +0 -6
- package/dist/worker/lib/tinypool.mjs.map +0 -6
|
@@ -1,1373 +1,885 @@
|
|
|
1
|
-
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { DurableObject, WorkerEntrypoint, WorkflowEntrypoint, env, env as env$1, exports } from "cloudflare:workers";
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
+
|
|
5
|
+
//#region src/worker/fetch-mock.ts
|
|
6
|
+
const originalFetch = fetch;
|
|
7
|
+
globalThis.fetch = async (input, init) => {
|
|
8
|
+
return originalFetch.call(globalThis, input, init);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/worker/d1.ts
|
|
2
13
|
function isD1Database(v) {
|
|
3
|
-
|
|
14
|
+
return typeof v === "object" && v !== null && v.constructor.name === "D1Database" && "prepare" in v && typeof v.prepare === "function" && "batch" in v && typeof v.batch === "function" && "exec" in v && typeof v.exec === "function";
|
|
4
15
|
}
|
|
5
16
|
function isD1Migration(v) {
|
|
6
|
-
|
|
17
|
+
return typeof v === "object" && v !== null && "name" in v && typeof v.name === "string" && "queries" in v && Array.isArray(v.queries) && v.queries.every((query) => typeof query === "string");
|
|
7
18
|
}
|
|
8
19
|
function isD1Migrations(v) {
|
|
9
|
-
|
|
20
|
+
return Array.isArray(v) && v.every(isD1Migration);
|
|
10
21
|
}
|
|
11
22
|
async function applyD1Migrations(db, migrations, migrationsTableName = "d1_migrations") {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
if (!isD1Migrations(migrations)) {
|
|
18
|
-
throw new TypeError(
|
|
19
|
-
"Failed to execute 'applyD1Migrations': parameter 2 is not of type 'D1Migration[]'."
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
if (typeof migrationsTableName !== "string") {
|
|
23
|
-
throw new TypeError(
|
|
24
|
-
"Failed to execute 'applyD1Migrations': parameter 3 is not of type 'string'."
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
const schema = `CREATE TABLE IF NOT EXISTS ${migrationsTableName} (
|
|
23
|
+
if (!isD1Database(db)) throw new TypeError("Failed to execute 'applyD1Migrations': parameter 1 is not of type 'D1Database'.");
|
|
24
|
+
if (!isD1Migrations(migrations)) throw new TypeError("Failed to execute 'applyD1Migrations': parameter 2 is not of type 'D1Migration[]'.");
|
|
25
|
+
if (typeof migrationsTableName !== "string") throw new TypeError("Failed to execute 'applyD1Migrations': parameter 3 is not of type 'string'.");
|
|
26
|
+
const schema = `CREATE TABLE IF NOT EXISTS ${migrationsTableName} (
|
|
28
27
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
29
28
|
name TEXT UNIQUE,
|
|
30
29
|
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
|
31
30
|
);`;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (appliedMigrationNames.includes(migration.name)) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const queries = migration.queries.map((query) => db.prepare(query));
|
|
45
|
-
queries.push(insertMigrationStmt.bind(migration.name));
|
|
46
|
-
await db.batch(queries);
|
|
47
|
-
}
|
|
31
|
+
await db.prepare(schema).run();
|
|
32
|
+
const appliedMigrationNames = (await db.prepare(`SELECT name FROM ${migrationsTableName};`).all()).results.map(({ name }) => name);
|
|
33
|
+
const insertMigrationStmt = db.prepare(`INSERT INTO ${migrationsTableName} (name) VALUES (?);`);
|
|
34
|
+
for (const migration of migrations) {
|
|
35
|
+
if (appliedMigrationNames.includes(migration.name)) continue;
|
|
36
|
+
const queries = migration.queries.map((query) => db.prepare(query));
|
|
37
|
+
queries.push(insertMigrationStmt.bind(migration.name));
|
|
38
|
+
await db.batch(queries);
|
|
39
|
+
}
|
|
48
40
|
}
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
delete result.__VITEST_POOL_WORKERS_SELF_SERVICE;
|
|
62
|
-
delete result.__VITEST_POOL_WORKERS_LOOPBACK_SERVICE;
|
|
63
|
-
delete result.__VITEST_POOL_WORKERS_RUNNER_OBJECT;
|
|
64
|
-
delete result.__VITEST_POOL_WORKERS_UNSAFE_EVAL;
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
var internalEnv;
|
|
68
|
-
function setEnv(newEnv) {
|
|
69
|
-
internalEnv = newEnv;
|
|
70
|
-
SELF = newEnv.__VITEST_POOL_WORKERS_SELF_SERVICE;
|
|
71
|
-
env = stripInternalEnv(newEnv);
|
|
72
|
-
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/worker/env.ts
|
|
44
|
+
/**
|
|
45
|
+
* For reasons that aren't clear to me, just `SELF = exports.default` ends up with SELF being
|
|
46
|
+
* undefined in a test. This Proxy solution works.
|
|
47
|
+
*/
|
|
48
|
+
const SELF = new Proxy({}, { get(_, p) {
|
|
49
|
+
const target = exports.default;
|
|
50
|
+
const value = target[p];
|
|
51
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
52
|
+
} });
|
|
73
53
|
function getSerializedOptions() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
54
|
+
assert(typeof __vitest_worker__ === "object", "Expected global Vitest state");
|
|
55
|
+
const options = __vitest_worker__.providedContext.cloudflarePoolOptions;
|
|
56
|
+
assert(options !== void 0, "Expected serialised options, got keys: " + Object.keys(__vitest_worker__.providedContext).join(", "));
|
|
57
|
+
const parsedOptions = JSON.parse(options);
|
|
58
|
+
return {
|
|
59
|
+
...parsedOptions,
|
|
60
|
+
durableObjectBindingDesignators: new Map(parsedOptions.durableObjectBindingDesignators)
|
|
61
|
+
};
|
|
78
62
|
}
|
|
79
63
|
function getResolvedMainPath(forBindingType) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`Using ${forBindingType} bindings to the current worker requires \`poolOptions.workers.main\` to be set to your worker's entrypoint`
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
return options.main;
|
|
64
|
+
const options = getSerializedOptions();
|
|
65
|
+
if (options.main === void 0) throw new Error(`Using ${forBindingType} bindings to the current worker requires \`poolOptions.workers.main\` to be set to your worker's entrypoint: ${JSON.stringify(options)}`);
|
|
66
|
+
return options.main;
|
|
87
67
|
}
|
|
88
68
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/worker/durable-objects.ts
|
|
71
|
+
const CF_KEY_ACTION = "vitestPoolWorkersDurableObjectAction";
|
|
72
|
+
let nextActionId = 0;
|
|
73
|
+
const kUseResponse = Symbol("kUseResponse");
|
|
74
|
+
const actionResults = /* @__PURE__ */ new Map();
|
|
94
75
|
function isDurableObjectNamespace(v) {
|
|
95
|
-
|
|
76
|
+
return v instanceof Object && /^(?:Loopback)?DurableObjectNamespace$/.test(v.constructor.name) && "newUniqueId" in v && typeof v.newUniqueId === "function" && "idFromName" in v && typeof v.idFromName === "function" && "idFromString" in v && typeof v.idFromString === "function" && "get" in v && typeof v.get === "function";
|
|
96
77
|
}
|
|
97
78
|
function isDurableObjectStub(v) {
|
|
98
|
-
|
|
79
|
+
return typeof v === "object" && v !== null && (v.constructor.name === "DurableObject" || v.constructor.name === "WorkerRpc") && "fetch" in v && typeof v.fetch === "function" && "id" in v && typeof v.id === "object";
|
|
99
80
|
}
|
|
100
|
-
|
|
81
|
+
let sameIsolatedNamespaces;
|
|
101
82
|
function getSameIsolateNamespaces() {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
const namespace = internalEnv[key] ?? exports?.[key];
|
|
115
|
-
assert2(
|
|
116
|
-
isDurableObjectNamespace(namespace),
|
|
117
|
-
`Expected ${key} to be a DurableObjectNamespace binding`
|
|
118
|
-
);
|
|
119
|
-
sameIsolatedNamespaces.push(namespace);
|
|
120
|
-
}
|
|
121
|
-
return sameIsolatedNamespaces;
|
|
83
|
+
if (sameIsolatedNamespaces !== void 0) return sameIsolatedNamespaces;
|
|
84
|
+
sameIsolatedNamespaces = [];
|
|
85
|
+
const options = getSerializedOptions();
|
|
86
|
+
if (options.durableObjectBindingDesignators === void 0) return sameIsolatedNamespaces;
|
|
87
|
+
for (const [key, designator] of options.durableObjectBindingDesignators) {
|
|
88
|
+
if (designator.scriptName !== void 0) continue;
|
|
89
|
+
const namespace = env$1[key] ?? exports?.[key];
|
|
90
|
+
assert(isDurableObjectNamespace(namespace), `Expected ${key} to be a DurableObjectNamespace binding`);
|
|
91
|
+
sameIsolatedNamespaces.push(namespace);
|
|
92
|
+
}
|
|
93
|
+
return sameIsolatedNamespaces;
|
|
122
94
|
}
|
|
123
95
|
function assertSameIsolate(stub) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
throw new Error(
|
|
134
|
-
"Durable Object test helpers can only be used with stubs pointing to objects defined within the same worker."
|
|
135
|
-
);
|
|
96
|
+
const idString = stub.id.toString();
|
|
97
|
+
const namespaces = getSameIsolateNamespaces();
|
|
98
|
+
for (const namespace of namespaces) try {
|
|
99
|
+
namespace.idFromString(idString);
|
|
100
|
+
return;
|
|
101
|
+
} catch {}
|
|
102
|
+
throw new Error("Durable Object test helpers can only be used with stubs pointing to objects defined within the same worker.");
|
|
136
103
|
}
|
|
137
104
|
async function runInStub(stub, callback) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return response;
|
|
148
|
-
} else if (response.ok) {
|
|
149
|
-
return result;
|
|
150
|
-
} else {
|
|
151
|
-
throw result;
|
|
152
|
-
}
|
|
105
|
+
const id = nextActionId++;
|
|
106
|
+
actionResults.set(id, callback);
|
|
107
|
+
const response = await stub.fetch("http://x", { cf: { [CF_KEY_ACTION]: id } });
|
|
108
|
+
assert(actionResults.has(id), `Expected action result for ${id}`);
|
|
109
|
+
const result = actionResults.get(id);
|
|
110
|
+
actionResults.delete(id);
|
|
111
|
+
if (result === kUseResponse) return response;
|
|
112
|
+
else if (response.ok) return result;
|
|
113
|
+
else throw result;
|
|
153
114
|
}
|
|
154
115
|
async function runInDurableObject(stub, callback) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
if (typeof callback !== "function") {
|
|
161
|
-
throw new TypeError(
|
|
162
|
-
"Failed to execute 'runInDurableObject': parameter 2 is not of type 'function'."
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
assertSameIsolate(stub);
|
|
166
|
-
return runInStub(stub, callback);
|
|
116
|
+
if (!isDurableObjectStub(stub)) throw new TypeError("Failed to execute 'runInDurableObject': parameter 1 is not of type 'DurableObjectStub'.");
|
|
117
|
+
if (typeof callback !== "function") throw new TypeError("Failed to execute 'runInDurableObject': parameter 2 is not of type 'function'.");
|
|
118
|
+
assertSameIsolate(stub);
|
|
119
|
+
return runInStub(stub, callback);
|
|
167
120
|
}
|
|
168
121
|
async function runAlarm(instance, state) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
await state.storage.deleteAlarm();
|
|
174
|
-
await instance.alarm?.();
|
|
175
|
-
return true;
|
|
122
|
+
if (await state.storage.getAlarm() === null) return false;
|
|
123
|
+
await state.storage.deleteAlarm();
|
|
124
|
+
await instance.alarm?.();
|
|
125
|
+
return true;
|
|
176
126
|
}
|
|
177
127
|
async function runDurableObjectAlarm(stub) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
128
|
+
if (!isDurableObjectStub(stub)) throw new TypeError("Failed to execute 'runDurableObjectAlarm': parameter 1 is not of type 'DurableObjectStub'.");
|
|
129
|
+
return await runInDurableObject(stub, runAlarm);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Internal method for running `callback` inside the I/O context of the
|
|
133
|
+
* Runner Durable Object.
|
|
134
|
+
*
|
|
135
|
+
* Tests run in this context by default. This is required for performing
|
|
136
|
+
* operations that use Vitest's RPC mechanism as the Durable Object
|
|
137
|
+
* owns the RPC WebSocket. For example, importing modules or sending logs.
|
|
138
|
+
* Trying to perform those operations from a different context (e.g. within
|
|
139
|
+
* a `export default { fetch() {} }` handler or user Durable Object's `fetch()`
|
|
140
|
+
* handler) without using this function will result in a `Cannot perform I/O on
|
|
141
|
+
* behalf of a different request` error.
|
|
142
|
+
*/
|
|
143
|
+
function runInRunnerObject(callback) {
|
|
144
|
+
return runInStub(env$1["__VITEST_POOL_WORKERS_RUNNER_OBJECT"].get("singleton"), callback);
|
|
188
145
|
}
|
|
189
146
|
async function maybeHandleRunRequest(request, instance, state) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
} catch (e) {
|
|
207
|
-
actionResults.set(actionId, e);
|
|
208
|
-
return new Response(null, { status: 500 });
|
|
209
|
-
}
|
|
147
|
+
const actionId = request.cf?.[CF_KEY_ACTION];
|
|
148
|
+
if (actionId === void 0) return;
|
|
149
|
+
assert(typeof actionId === "number", `Expected numeric ${CF_KEY_ACTION}`);
|
|
150
|
+
try {
|
|
151
|
+
const callback = actionResults.get(actionId);
|
|
152
|
+
assert(typeof callback === "function", `Expected callback for ${actionId}`);
|
|
153
|
+
const result = await callback(instance, state);
|
|
154
|
+
if (result instanceof Response) {
|
|
155
|
+
actionResults.set(actionId, kUseResponse);
|
|
156
|
+
return result;
|
|
157
|
+
} else actionResults.set(actionId, result);
|
|
158
|
+
return new Response(null, { status: 204 });
|
|
159
|
+
} catch (e) {
|
|
160
|
+
actionResults.set(actionId, e);
|
|
161
|
+
return new Response(null, { status: 500 });
|
|
162
|
+
}
|
|
210
163
|
}
|
|
211
164
|
async function listDurableObjectIds(namespace) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
const url = `http://placeholder/durable-objects?unique_key=${encodeURIComponent(
|
|
231
|
-
uniqueKey
|
|
232
|
-
)}`;
|
|
233
|
-
const res = await internalEnv.__VITEST_POOL_WORKERS_LOOPBACK_SERVICE.fetch(url);
|
|
234
|
-
assert2.strictEqual(res.status, 200);
|
|
235
|
-
const ids = await res.json();
|
|
236
|
-
assert2(Array.isArray(ids));
|
|
237
|
-
return ids.map((id) => {
|
|
238
|
-
assert2(typeof id === "string");
|
|
239
|
-
return namespace.idFromString(id);
|
|
240
|
-
});
|
|
165
|
+
if (!isDurableObjectNamespace(namespace)) throw new TypeError("Failed to execute 'listDurableObjectIds': parameter 1 is not of type 'DurableObjectNamespace'.");
|
|
166
|
+
const boundName = Object.entries(env$1).find((entry) => namespace === entry[1])?.[0];
|
|
167
|
+
assert(boundName !== void 0, "Expected to find bound name for namespace");
|
|
168
|
+
const options = getSerializedOptions();
|
|
169
|
+
const designator = options.durableObjectBindingDesignators?.get(boundName);
|
|
170
|
+
assert(designator !== void 0, "Expected to find designator for namespace");
|
|
171
|
+
let uniqueKey = designator.unsafeUniqueKey;
|
|
172
|
+
if (uniqueKey === void 0) uniqueKey = `${designator.scriptName ?? options.selfName}-${designator.className}`;
|
|
173
|
+
const url = `http://placeholder/durable-objects?unique_key=${encodeURIComponent(uniqueKey)}`;
|
|
174
|
+
const res = await env$1.__VITEST_POOL_WORKERS_LOOPBACK_SERVICE.fetch(url);
|
|
175
|
+
assert.strictEqual(res.status, 200);
|
|
176
|
+
const ids = await res.json();
|
|
177
|
+
assert(Array.isArray(ids));
|
|
178
|
+
return ids.map((id) => {
|
|
179
|
+
assert(typeof id === "string");
|
|
180
|
+
return namespace.idFromString(id);
|
|
181
|
+
});
|
|
241
182
|
}
|
|
242
183
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
// src/worker/wait-until.ts
|
|
252
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/worker/wait-until.ts
|
|
186
|
+
/**
|
|
187
|
+
* Empty array and wait for all promises to resolve until no more added.
|
|
188
|
+
* If a single promise rejects, the rejection will be passed-through.
|
|
189
|
+
* If multiple promises reject, the rejections will be aggregated.
|
|
190
|
+
*/
|
|
253
191
|
async function waitForWaitUntil(waitUntil) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (errors.length === 1) {
|
|
264
|
-
throw errors[0];
|
|
265
|
-
} else if (errors.length > 1) {
|
|
266
|
-
throw new AggregateError(errors);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
var globalWaitUntil = [];
|
|
192
|
+
const errors = [];
|
|
193
|
+
while (waitUntil.length > 0) {
|
|
194
|
+
const results = await Promise.allSettled(waitUntil.splice(0));
|
|
195
|
+
for (const result of results) if (result.status === "rejected") errors.push(result.reason);
|
|
196
|
+
}
|
|
197
|
+
if (errors.length === 1) throw errors[0];
|
|
198
|
+
else if (errors.length > 1) throw new AggregateError(errors);
|
|
199
|
+
}
|
|
200
|
+
const globalWaitUntil = [];
|
|
270
201
|
function registerGlobalWaitUntil(promise) {
|
|
271
|
-
|
|
202
|
+
globalWaitUntil.push(promise);
|
|
272
203
|
}
|
|
273
204
|
function waitForGlobalWaitUntil() {
|
|
274
|
-
|
|
205
|
+
return waitForWaitUntil(globalWaitUntil);
|
|
275
206
|
}
|
|
276
|
-
|
|
207
|
+
const handlerContextStore = new AsyncLocalStorage();
|
|
277
208
|
function registerHandlerAndGlobalWaitUntil(promise) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
} else {
|
|
282
|
-
handlerContext.waitUntil(promise);
|
|
283
|
-
}
|
|
209
|
+
const handlerContext = handlerContextStore.getStore();
|
|
210
|
+
if (handlerContext === void 0) registerGlobalWaitUntil(promise);
|
|
211
|
+
else handlerContext.waitUntil(promise);
|
|
284
212
|
}
|
|
285
213
|
|
|
286
|
-
|
|
287
|
-
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/worker/patch-ctx.ts
|
|
216
|
+
const patchedHandlerContexts = /* @__PURE__ */ new WeakSet();
|
|
217
|
+
/**
|
|
218
|
+
* Executes the given callback within the provided ExecutionContext,
|
|
219
|
+
* patching the context to ensure that:
|
|
220
|
+
*
|
|
221
|
+
* - waitUntil calls are registered globally
|
|
222
|
+
* - ctx.exports shows a warning if accessing missing exports
|
|
223
|
+
*/
|
|
288
224
|
function patchAndRunWithHandlerContext(ctx, callback) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return void 0;
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
function isCtxExportsEnabled(exports3) {
|
|
321
|
-
return (
|
|
322
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
323
|
-
globalThis.Cloudflare?.compatibilityFlags.enable_ctx_exports && exports3 !== void 0
|
|
324
|
-
);
|
|
225
|
+
if (!patchedHandlerContexts.has(ctx)) {
|
|
226
|
+
patchedHandlerContexts.add(ctx);
|
|
227
|
+
const originalWaitUntil = ctx.waitUntil;
|
|
228
|
+
ctx.waitUntil = (promise) => {
|
|
229
|
+
registerGlobalWaitUntil(promise);
|
|
230
|
+
return originalWaitUntil.call(ctx, promise);
|
|
231
|
+
};
|
|
232
|
+
if (isCtxExportsEnabled(ctx.exports)) Object.defineProperty(ctx, "exports", { value: getCtxExportsProxy(ctx.exports) });
|
|
233
|
+
}
|
|
234
|
+
return handlerContextStore.run(ctx, callback);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Creates a proxy to the `ctx.exports` object that will warn the user if they attempt
|
|
238
|
+
* to access an undefined property. This could be a valid mistake by the user or
|
|
239
|
+
* it could mean that our static analysis of the main Worker's exports missed something.
|
|
240
|
+
*/
|
|
241
|
+
function getCtxExportsProxy(exports$1) {
|
|
242
|
+
return new Proxy(exports$1, { get(target, p) {
|
|
243
|
+
if (p in target) return target[p];
|
|
244
|
+
console.warn(`Attempted to access 'ctx.exports.${p}', which was not defined for the main 'SELF' Worker.\nCheck that '${p}' is exported as an entry-point from the Worker.\nThe '@cloudflare/vitest-pool-workers' integration tries to infer these exports by analyzing the source code of the main Worker.\n`);
|
|
245
|
+
} });
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Returns true if `ctx.exports` is enabled via compatibility flags.
|
|
249
|
+
*/
|
|
250
|
+
function isCtxExportsEnabled(exports$1) {
|
|
251
|
+
return globalThis.Cloudflare?.compatibilityFlags.enable_ctx_exports && exports$1 !== void 0;
|
|
325
252
|
}
|
|
326
253
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/worker/entrypoints.ts
|
|
256
|
+
/**
|
|
257
|
+
* Internal method for importing a module using Vite's transformation and
|
|
258
|
+
* execution pipeline. Can be called from any I/O context, and will ensure the
|
|
259
|
+
* request is run from within the `__VITEST_POOL_WORKERS_RUNNER_DURABLE_OBJECT__`.
|
|
260
|
+
*/
|
|
261
|
+
async function importModule(specifier) {
|
|
262
|
+
/**
|
|
263
|
+
* We need to run this import inside the Runner Object, or we get errors like:
|
|
264
|
+
* - The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response. Refer to: https://developers.cloudflare.com/workers/observability/errors/
|
|
265
|
+
* - Cannot perform I/O on behalf of a different Durable Object. I/O objects (such as streams, request/response bodies, and others) created in the context of one Durable Object cannot be accessed from a different Durable Object in the same isolate. This is a limitation of Cloudflare Workers which allows us to improve overall performance.
|
|
266
|
+
*/
|
|
267
|
+
return runInRunnerObject(() => {
|
|
268
|
+
return __vitest_mocker__.moduleRunner.import(specifier);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
const IGNORED_KEYS = ["self"];
|
|
272
|
+
/**
|
|
273
|
+
* Create a class extending `superClass` with a `Proxy` as a `prototype`.
|
|
274
|
+
* Unknown accesses on the `prototype` will defer to `getUnknownPrototypeKey()`.
|
|
275
|
+
* `workerd` will only look for RPC methods/properties on the prototype, not the
|
|
276
|
+
* instance. This helps avoid accidentally exposing things over RPC, but makes
|
|
277
|
+
* things a little trickier for us...
|
|
278
|
+
*/
|
|
338
279
|
function createProxyPrototypeClass(superClass, getUnknownPrototypeKey) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
280
|
+
function Class(...args) {
|
|
281
|
+
Class.prototype = new Proxy(Class.prototype, { get(target, key, receiver) {
|
|
282
|
+
const value = Reflect.get(target, key, receiver);
|
|
283
|
+
if (value !== void 0) return value;
|
|
284
|
+
if (typeof key === "symbol" || IGNORED_KEYS.includes(key)) return;
|
|
285
|
+
return getUnknownPrototypeKey.call(receiver, key);
|
|
286
|
+
} });
|
|
287
|
+
return Reflect.construct(superClass, args, Class);
|
|
288
|
+
}
|
|
289
|
+
Reflect.setPrototypeOf(Class.prototype, superClass.prototype);
|
|
290
|
+
Reflect.setPrototypeOf(Class, superClass);
|
|
291
|
+
return Class;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Only properties and methods declared on the prototype can be accessed over
|
|
295
|
+
* RPC. This function gets a property from the prototype if it's defined, and
|
|
296
|
+
* throws a helpful error message if not. Note we need to distinguish between a
|
|
297
|
+
* property that returns `undefined` and something not being defined at all.
|
|
298
|
+
*/
|
|
358
299
|
function getRPCProperty(ctor, instance, key) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
300
|
+
if (!Reflect.has(ctor.prototype, key)) {
|
|
301
|
+
const quotedKey = JSON.stringify(key);
|
|
302
|
+
const instanceHasKey = Reflect.has(instance, key);
|
|
303
|
+
let message = "";
|
|
304
|
+
if (instanceHasKey) message = [
|
|
305
|
+
`The RPC receiver's prototype does not implement ${quotedKey}, but the receiver instance does.`,
|
|
306
|
+
"Only properties and methods defined on the prototype can be accessed over RPC.",
|
|
307
|
+
`Ensure properties are declared like \`get ${key}() { ... }\` instead of \`${key} = ...\`,`,
|
|
308
|
+
`and methods are declared like \`${key}() { ... }\` instead of \`${key} = () => { ... }\`.`
|
|
309
|
+
].join("\n");
|
|
310
|
+
else message = `The RPC receiver does not implement ${quotedKey}.`;
|
|
311
|
+
throw new TypeError(message);
|
|
312
|
+
}
|
|
313
|
+
return Reflect.get(ctor.prototype, key, instance);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* When calling RPC methods dynamically, we don't know whether the `property`
|
|
317
|
+
* returned from `getSELFRPCProperty()` or `getDurableObjectRPCProperty()` below
|
|
318
|
+
* is just a property or a method. If we just returned `property`, but the
|
|
319
|
+
* client tried to call it as a method, `workerd` would throw an "x is not a
|
|
320
|
+
* function" error.
|
|
321
|
+
*
|
|
322
|
+
* Instead, we return a *callable, custom thenable*. This behaves like a
|
|
323
|
+
* function and a `Promise`! If `workerd` calls it, we'll wait for the promise
|
|
324
|
+
* to resolve then forward the call. Otherwise, this just appears like a regular
|
|
325
|
+
* async property. Note all client calls are async, so converting sync
|
|
326
|
+
* properties and methods to async is fine here.
|
|
327
|
+
*
|
|
328
|
+
* Unfortunately, wrapping `property` with a `Proxy` and an `apply()` trap gives
|
|
329
|
+
* `TypeError: Method Promise.prototype.then called on incompatible receiver #<Promise>`. :(
|
|
330
|
+
*/
|
|
384
331
|
function getRPCPropertyCallableThenable(key, property) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
fn.catch = (onRejected) => property.catch(onRejected);
|
|
395
|
-
fn.finally = (onFinally) => property.finally(onFinally);
|
|
396
|
-
return fn;
|
|
332
|
+
const fn = async function(...args) {
|
|
333
|
+
const maybeFn = await property;
|
|
334
|
+
if (typeof maybeFn === "function") return maybeFn(...args);
|
|
335
|
+
else throw new TypeError(`${JSON.stringify(key)} is not a function.`);
|
|
336
|
+
};
|
|
337
|
+
fn.then = (onFulfilled, onRejected) => property.then(onFulfilled, onRejected);
|
|
338
|
+
fn.catch = (onRejected) => property.catch(onRejected);
|
|
339
|
+
fn.finally = (onFinally) => property.finally(onFinally);
|
|
340
|
+
return fn;
|
|
397
341
|
}
|
|
398
342
|
function getEntrypointState(instance) {
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
"email"
|
|
343
|
+
return instance;
|
|
344
|
+
}
|
|
345
|
+
const WORKER_ENTRYPOINT_KEYS = [
|
|
346
|
+
"tailStream",
|
|
347
|
+
"fetch",
|
|
348
|
+
"tail",
|
|
349
|
+
"trace",
|
|
350
|
+
"scheduled",
|
|
351
|
+
"queue",
|
|
352
|
+
"test",
|
|
353
|
+
"email"
|
|
411
354
|
];
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
355
|
+
const DURABLE_OBJECT_KEYS = [
|
|
356
|
+
"fetch",
|
|
357
|
+
"alarm",
|
|
358
|
+
"webSocketMessage",
|
|
359
|
+
"webSocketClose",
|
|
360
|
+
"webSocketError"
|
|
418
361
|
];
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
362
|
+
/**
|
|
363
|
+
* Get the export to use for `entrypoint`. This is used for the `SELF` service
|
|
364
|
+
* binding in `cloudflare:test`, which sets `entrypoint` to "default".
|
|
365
|
+
* This requires importing the `main` module with Vite.
|
|
366
|
+
*/
|
|
367
|
+
async function getWorkerEntrypointExport(env$2, entrypoint) {
|
|
368
|
+
const mainPath = getResolvedMainPath("service");
|
|
369
|
+
const mainModule = await importModule(mainPath);
|
|
370
|
+
const entrypointValue = typeof mainModule === "object" && mainModule !== null && entrypoint in mainModule && mainModule[entrypoint];
|
|
371
|
+
if (!entrypointValue) {
|
|
372
|
+
const message = `${mainPath} does not export a ${entrypoint} entrypoint. \`@cloudflare/vitest-pool-workers\` does not support service workers or named entrypoints for \`SELF\`.\nIf you're using service workers, please migrate to the modules format: https://developers.cloudflare.com/workers/reference/migrate-to-module-workers.`;
|
|
373
|
+
throw new TypeError(message);
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
mainPath,
|
|
377
|
+
entrypointValue
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Get a property named `key` from the user's `WorkerEntrypoint`. `wrapper` here
|
|
382
|
+
* is an instance of a `WorkerEntrypoint` wrapper (i.e. the return value of
|
|
383
|
+
* `createWorkerEntrypointWrapper()`). This requires importing the `main` module
|
|
384
|
+
* with Vite, so will always return a `Promise.`
|
|
385
|
+
*/
|
|
430
386
|
async function getWorkerEntrypointRPCProperty(wrapper, entrypoint, key) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (!(instance instanceof WorkerEntrypoint)) {
|
|
445
|
-
throw new TypeError(expectedWorkerEntrypointMessage);
|
|
446
|
-
}
|
|
447
|
-
const value = getRPCProperty(ctor, instance, key);
|
|
448
|
-
if (typeof value === "function") {
|
|
449
|
-
return (...args) => patchAndRunWithHandlerContext(ctx, () => value.apply(instance, args));
|
|
450
|
-
} else {
|
|
451
|
-
return value;
|
|
452
|
-
}
|
|
453
|
-
});
|
|
387
|
+
const { ctx } = getEntrypointState(wrapper);
|
|
388
|
+
const { mainPath, entrypointValue } = await getWorkerEntrypointExport(env$1, entrypoint);
|
|
389
|
+
return patchAndRunWithHandlerContext(ctx, () => {
|
|
390
|
+
const env$2 = env$1;
|
|
391
|
+
const expectedWorkerEntrypointMessage = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \`WorkerEntrypoint\` for RPC`;
|
|
392
|
+
if (typeof entrypointValue !== "function") throw new TypeError(expectedWorkerEntrypointMessage);
|
|
393
|
+
const ctor = entrypointValue;
|
|
394
|
+
const instance = new ctor(ctx, env$2);
|
|
395
|
+
if (!(instance instanceof WorkerEntrypoint)) throw new TypeError(expectedWorkerEntrypointMessage);
|
|
396
|
+
const value = getRPCProperty(ctor, instance, key);
|
|
397
|
+
if (typeof value === "function") return (...args) => patchAndRunWithHandlerContext(ctx, () => value.apply(instance, args));
|
|
398
|
+
else return value;
|
|
399
|
+
});
|
|
454
400
|
}
|
|
455
401
|
function createWorkerEntrypointWrapper(entrypoint) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const message = `Expected ${entrypoint} export of ${mainPath} to define a \`${key}()\` method`;
|
|
494
|
-
throw new TypeError(message);
|
|
495
|
-
}
|
|
496
|
-
} else {
|
|
497
|
-
const message = `Expected ${entrypoint} export of ${mainPath}to be an object or a class, got ${entrypointValue}`;
|
|
498
|
-
throw new TypeError(message);
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
return Wrapper;
|
|
504
|
-
}
|
|
505
|
-
var kInstanceConstructor = /* @__PURE__ */ Symbol("kInstanceConstructor");
|
|
506
|
-
var kInstance = /* @__PURE__ */ Symbol("kInstance");
|
|
507
|
-
var kEnsureInstance = /* @__PURE__ */ Symbol("kEnsureInstance");
|
|
402
|
+
const Wrapper = createProxyPrototypeClass(WorkerEntrypoint, function(key) {
|
|
403
|
+
if (DURABLE_OBJECT_KEYS.includes(key)) return;
|
|
404
|
+
return getRPCPropertyCallableThenable(key, getWorkerEntrypointRPCProperty(this, entrypoint, key));
|
|
405
|
+
});
|
|
406
|
+
for (const key of WORKER_ENTRYPOINT_KEYS) Wrapper.prototype[key] = async function(thing) {
|
|
407
|
+
const { mainPath, entrypointValue } = await getWorkerEntrypointExport(this.env, entrypoint);
|
|
408
|
+
return patchAndRunWithHandlerContext(this.ctx, () => {
|
|
409
|
+
if (typeof entrypointValue === "object" && entrypointValue !== null) {
|
|
410
|
+
const maybeFn = entrypointValue[key];
|
|
411
|
+
if (typeof maybeFn === "function") return maybeFn.call(entrypointValue, thing, env$1, this.ctx);
|
|
412
|
+
else {
|
|
413
|
+
const message = `Expected ${entrypoint} export of ${mainPath} to define a \`${key}()\` function`;
|
|
414
|
+
throw new TypeError(message);
|
|
415
|
+
}
|
|
416
|
+
} else if (typeof entrypointValue === "function") {
|
|
417
|
+
const instance = new entrypointValue(this.ctx, env$1);
|
|
418
|
+
if (!(instance instanceof WorkerEntrypoint)) {
|
|
419
|
+
const message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \`WorkerEntrypoint\``;
|
|
420
|
+
throw new TypeError(message);
|
|
421
|
+
}
|
|
422
|
+
const maybeFn = instance[key];
|
|
423
|
+
if (typeof maybeFn === "function") return maybeFn.call(instance, thing);
|
|
424
|
+
else {
|
|
425
|
+
const message = `Expected ${entrypoint} export of ${mainPath} to define a \`${key}()\` method`;
|
|
426
|
+
throw new TypeError(message);
|
|
427
|
+
}
|
|
428
|
+
} else {
|
|
429
|
+
const message = `Expected ${entrypoint} export of ${mainPath} to be an object or a class, got ${entrypointValue}`;
|
|
430
|
+
throw new TypeError(message);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
};
|
|
434
|
+
return Wrapper;
|
|
435
|
+
}
|
|
436
|
+
const kInstanceConstructor = Symbol("kInstanceConstructor");
|
|
437
|
+
const kInstance = Symbol("kInstance");
|
|
438
|
+
const kEnsureInstance = Symbol("kEnsureInstance");
|
|
508
439
|
async function getDurableObjectRPCProperty(wrapper, className, key) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
} else {
|
|
518
|
-
return value;
|
|
519
|
-
}
|
|
440
|
+
const { mainPath, instanceCtor, instance } = await wrapper[kEnsureInstance]();
|
|
441
|
+
if (!(instance instanceof DurableObject)) {
|
|
442
|
+
const message = `Expected ${className} exported by ${mainPath} be a subclass of \`DurableObject\` for RPC`;
|
|
443
|
+
throw new TypeError(message);
|
|
444
|
+
}
|
|
445
|
+
const value = getRPCProperty(instanceCtor, instance, key);
|
|
446
|
+
if (typeof value === "function") return value.bind(instance);
|
|
447
|
+
else return value;
|
|
520
448
|
}
|
|
521
449
|
function createDurableObjectWrapper(className) {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
};
|
|
573
|
-
for (const key of DURABLE_OBJECT_KEYS) {
|
|
574
|
-
if (key === "fetch") {
|
|
575
|
-
continue;
|
|
576
|
-
}
|
|
577
|
-
Wrapper.prototype[key] = async function(...args) {
|
|
578
|
-
const { mainPath, instance } = await this[kEnsureInstance]();
|
|
579
|
-
const maybeFn = instance[key];
|
|
580
|
-
if (typeof maybeFn === "function") {
|
|
581
|
-
return maybeFn.apply(instance, args);
|
|
582
|
-
} else {
|
|
583
|
-
const message = `${className} exported by ${mainPath} does not define a \`${key}()\` method`;
|
|
584
|
-
throw new TypeError(message);
|
|
585
|
-
}
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
return Wrapper;
|
|
450
|
+
const Wrapper = createProxyPrototypeClass(DurableObject, function(key) {
|
|
451
|
+
if (WORKER_ENTRYPOINT_KEYS.includes(key)) return;
|
|
452
|
+
return getRPCPropertyCallableThenable(key, getDurableObjectRPCProperty(this, className, key));
|
|
453
|
+
});
|
|
454
|
+
Wrapper.prototype[kEnsureInstance] = async function() {
|
|
455
|
+
const { ctx, env: env$2 } = getEntrypointState(this);
|
|
456
|
+
const mainPath = getResolvedMainPath("Durable Object");
|
|
457
|
+
const constructor = (await importModule(mainPath))[className];
|
|
458
|
+
if (typeof constructor !== "function") throw new TypeError(`${mainPath} does not export a ${className} Durable Object`);
|
|
459
|
+
this[kInstanceConstructor] ??= constructor;
|
|
460
|
+
if (this[kInstanceConstructor] !== constructor) {
|
|
461
|
+
await ctx.blockConcurrencyWhile(() => {
|
|
462
|
+
throw new Error(`${mainPath} changed, invalidating this Durable Object. Please retry the \`DurableObjectStub#fetch()\` call.`);
|
|
463
|
+
});
|
|
464
|
+
assert.fail("Unreachable");
|
|
465
|
+
}
|
|
466
|
+
if (this[kInstance] === void 0) {
|
|
467
|
+
this[kInstance] = new this[kInstanceConstructor](ctx, env$2);
|
|
468
|
+
await ctx.blockConcurrencyWhile(async () => {});
|
|
469
|
+
}
|
|
470
|
+
return {
|
|
471
|
+
mainPath,
|
|
472
|
+
instanceCtor: this[kInstanceConstructor],
|
|
473
|
+
instance: this[kInstance]
|
|
474
|
+
};
|
|
475
|
+
};
|
|
476
|
+
Wrapper.prototype.fetch = async function(request) {
|
|
477
|
+
const { ctx } = getEntrypointState(this);
|
|
478
|
+
const { mainPath, instance } = await this[kEnsureInstance]();
|
|
479
|
+
const response = await maybeHandleRunRequest(request, instance, ctx);
|
|
480
|
+
if (response !== void 0) return response;
|
|
481
|
+
if (instance.fetch === void 0) {
|
|
482
|
+
const message = `${className} exported by ${mainPath} does not define a \`fetch()\` method`;
|
|
483
|
+
throw new TypeError(message);
|
|
484
|
+
}
|
|
485
|
+
return instance.fetch(request);
|
|
486
|
+
};
|
|
487
|
+
for (const key of DURABLE_OBJECT_KEYS) {
|
|
488
|
+
if (key === "fetch") continue;
|
|
489
|
+
Wrapper.prototype[key] = async function(...args) {
|
|
490
|
+
const { mainPath, instance } = await this[kEnsureInstance]();
|
|
491
|
+
const maybeFn = instance[key];
|
|
492
|
+
if (typeof maybeFn === "function") return maybeFn.apply(instance, args);
|
|
493
|
+
else {
|
|
494
|
+
const message = `${className} exported by ${mainPath} does not define a \`${key}()\` method`;
|
|
495
|
+
throw new TypeError(message);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
return Wrapper;
|
|
589
500
|
}
|
|
590
501
|
function createWorkflowEntrypointWrapper(entrypoint) {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \`WorkflowEntrypoint\``;
|
|
616
|
-
throw new TypeError(message);
|
|
617
|
-
}
|
|
618
|
-
const maybeFn = instance["run"];
|
|
619
|
-
if (typeof maybeFn === "function") {
|
|
620
|
-
return patchAndRunWithHandlerContext(
|
|
621
|
-
this.ctx,
|
|
622
|
-
() => maybeFn.call(instance, ...args)
|
|
623
|
-
);
|
|
624
|
-
} else {
|
|
625
|
-
const message = `Expected ${entrypoint} export of ${mainPath} to define a \`run()\` method, but got ${typeof maybeFn}`;
|
|
626
|
-
throw new TypeError(message);
|
|
627
|
-
}
|
|
628
|
-
} else {
|
|
629
|
-
const message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \`WorkflowEntrypoint\`, but got ${entrypointValue}`;
|
|
630
|
-
throw new TypeError(message);
|
|
631
|
-
}
|
|
632
|
-
};
|
|
633
|
-
return Wrapper;
|
|
502
|
+
const Wrapper = createProxyPrototypeClass(WorkflowEntrypoint, function(key) {
|
|
503
|
+
if (!["run"].includes(key)) return;
|
|
504
|
+
return getRPCPropertyCallableThenable(key, getWorkerEntrypointRPCProperty(this, entrypoint, key));
|
|
505
|
+
});
|
|
506
|
+
Wrapper.prototype.run = async function(...args) {
|
|
507
|
+
const { mainPath, entrypointValue } = await getWorkerEntrypointExport(env$1, entrypoint);
|
|
508
|
+
if (typeof entrypointValue === "function") {
|
|
509
|
+
const instance = new entrypointValue(this.ctx, env$1);
|
|
510
|
+
if (!(instance instanceof WorkflowEntrypoint)) {
|
|
511
|
+
const message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \`WorkflowEntrypoint\``;
|
|
512
|
+
throw new TypeError(message);
|
|
513
|
+
}
|
|
514
|
+
const maybeFn = instance["run"];
|
|
515
|
+
if (typeof maybeFn === "function") return patchAndRunWithHandlerContext(this.ctx, () => maybeFn.call(instance, ...args));
|
|
516
|
+
else {
|
|
517
|
+
const message = `Expected ${entrypoint} export of ${mainPath} to define a \`run()\` method, but got ${typeof maybeFn}`;
|
|
518
|
+
throw new TypeError(message);
|
|
519
|
+
}
|
|
520
|
+
} else {
|
|
521
|
+
const message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \`WorkflowEntrypoint\`, but got ${entrypointValue}`;
|
|
522
|
+
throw new TypeError(message);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
return Wrapper;
|
|
634
526
|
}
|
|
635
527
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
var ExecutionContext = class
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
throw new TypeError("Illegal invocation");
|
|
653
|
-
}
|
|
654
|
-
this[kWaitUntil].push(promise);
|
|
655
|
-
registerGlobalWaitUntil(promise);
|
|
656
|
-
}
|
|
657
|
-
passThroughOnException() {
|
|
658
|
-
}
|
|
528
|
+
//#endregion
|
|
529
|
+
//#region src/worker/events.ts
|
|
530
|
+
const kConstructFlag = Symbol("kConstructFlag");
|
|
531
|
+
const kWaitUntil = Symbol("kWaitUntil");
|
|
532
|
+
var ExecutionContext = class ExecutionContext {
|
|
533
|
+
[kWaitUntil] = [];
|
|
534
|
+
constructor(flag) {
|
|
535
|
+
if (flag !== kConstructFlag) throw new TypeError("Illegal constructor");
|
|
536
|
+
}
|
|
537
|
+
exports = isCtxExportsEnabled(exports) ? getCtxExportsProxy(exports) : void 0;
|
|
538
|
+
waitUntil(promise) {
|
|
539
|
+
if (!(this instanceof ExecutionContext)) throw new TypeError("Illegal invocation");
|
|
540
|
+
this[kWaitUntil].push(promise);
|
|
541
|
+
registerGlobalWaitUntil(promise);
|
|
542
|
+
}
|
|
543
|
+
passThroughOnException() {}
|
|
659
544
|
};
|
|
660
545
|
function createExecutionContext() {
|
|
661
|
-
|
|
546
|
+
return new ExecutionContext(kConstructFlag);
|
|
662
547
|
}
|
|
663
548
|
function isExecutionContextLike(v) {
|
|
664
|
-
|
|
549
|
+
return typeof v === "object" && v !== null && kWaitUntil in v && Array.isArray(v[kWaitUntil]);
|
|
665
550
|
}
|
|
666
551
|
async function waitOnExecutionContext(ctx) {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
},
|
|
690
|
-
cron: {
|
|
691
|
-
get() {
|
|
692
|
-
return cron;
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
noRetry() {
|
|
698
|
-
if (!(this instanceof _ScheduledController)) {
|
|
699
|
-
throw new TypeError("Illegal invocation");
|
|
700
|
-
}
|
|
701
|
-
}
|
|
552
|
+
if (!isExecutionContextLike(ctx)) throw new TypeError("Failed to execute 'getWaitUntil': parameter 1 is not of type 'ExecutionContext'.\nYou must call 'createExecutionContext()' or 'createPagesEventContext()' to get an 'ExecutionContext' instance.");
|
|
553
|
+
return waitForWaitUntil(ctx[kWaitUntil]);
|
|
554
|
+
}
|
|
555
|
+
var ScheduledController = class ScheduledController {
|
|
556
|
+
scheduledTime;
|
|
557
|
+
cron;
|
|
558
|
+
constructor(flag, options) {
|
|
559
|
+
if (flag !== kConstructFlag) throw new TypeError("Illegal constructor");
|
|
560
|
+
const scheduledTime = Number(options?.scheduledTime ?? Date.now());
|
|
561
|
+
const cron = String(options?.cron ?? "");
|
|
562
|
+
Object.defineProperties(this, {
|
|
563
|
+
scheduledTime: { get() {
|
|
564
|
+
return scheduledTime;
|
|
565
|
+
} },
|
|
566
|
+
cron: { get() {
|
|
567
|
+
return cron;
|
|
568
|
+
} }
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
noRetry() {
|
|
572
|
+
if (!(this instanceof ScheduledController)) throw new TypeError("Illegal invocation");
|
|
573
|
+
}
|
|
702
574
|
};
|
|
703
575
|
function createScheduledController(options) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
var
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
retry() {
|
|
778
|
-
if (!(this instanceof _QueueMessage)) {
|
|
779
|
-
throw new TypeError("Illegal invocation");
|
|
780
|
-
}
|
|
781
|
-
if (this.#controller[kRetryAll]) {
|
|
782
|
-
return;
|
|
783
|
-
}
|
|
784
|
-
if (this.#controller[kAckAll]) {
|
|
785
|
-
console.warn(
|
|
786
|
-
`Received a call to retry() on message ${this.id} after ackAll() was already called. Calling retry() on a message after calling ackAll() has no effect.`
|
|
787
|
-
);
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
if (this[kAck]) {
|
|
791
|
-
console.warn(
|
|
792
|
-
`Received a call to retry() on message ${this.id} after ack() was already called. Calling retry() on a message after calling ack() has no effect.`
|
|
793
|
-
);
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
this[kRetry] = true;
|
|
797
|
-
}
|
|
798
|
-
ack() {
|
|
799
|
-
if (!(this instanceof _QueueMessage)) {
|
|
800
|
-
throw new TypeError("Illegal invocation");
|
|
801
|
-
}
|
|
802
|
-
if (this.#controller[kAckAll]) {
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
if (this.#controller[kRetryAll]) {
|
|
806
|
-
console.warn(
|
|
807
|
-
`Received a call to ack() on message ${this.id} after retryAll() was already called. Calling ack() on a message after calling retryAll() has no effect.`
|
|
808
|
-
);
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
if (this[kRetry]) {
|
|
812
|
-
console.warn(
|
|
813
|
-
`Received a call to ack() on message ${this.id} after retry() was already called. Calling ack() on a message after calling retry() has no effect.`
|
|
814
|
-
);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
this[kAck] = true;
|
|
818
|
-
}
|
|
576
|
+
if (options !== void 0 && typeof options !== "object") throw new TypeError("Failed to execute 'createScheduledController': parameter 1 is not of type 'ScheduledOptions'.");
|
|
577
|
+
return new ScheduledController(kConstructFlag, options);
|
|
578
|
+
}
|
|
579
|
+
const kRetry = Symbol("kRetry");
|
|
580
|
+
const kAck = Symbol("kAck");
|
|
581
|
+
const kRetryAll = Symbol("kRetryAll");
|
|
582
|
+
const kAckAll = Symbol("kAckAll");
|
|
583
|
+
var QueueMessage = class QueueMessage {
|
|
584
|
+
#controller;
|
|
585
|
+
id;
|
|
586
|
+
timestamp;
|
|
587
|
+
body;
|
|
588
|
+
attempts;
|
|
589
|
+
[kRetry] = false;
|
|
590
|
+
[kAck] = false;
|
|
591
|
+
constructor(flag, controller, message) {
|
|
592
|
+
if (flag !== kConstructFlag) throw new TypeError("Illegal constructor");
|
|
593
|
+
this.#controller = controller;
|
|
594
|
+
const id = String(message.id);
|
|
595
|
+
let timestamp;
|
|
596
|
+
if (typeof message.timestamp === "number") timestamp = new Date(message.timestamp);
|
|
597
|
+
else if (message.timestamp instanceof Date) timestamp = new Date(message.timestamp.getTime());
|
|
598
|
+
else throw new TypeError("Incorrect type for the 'timestamp' field on 'ServiceBindingQueueMessage': the provided value is not of type 'date'.");
|
|
599
|
+
let attempts;
|
|
600
|
+
if (typeof message.attempts === "number") attempts = message.attempts;
|
|
601
|
+
else throw new TypeError("Incorrect type for the 'attempts' field on 'ServiceBindingQueueMessage': the provided value is not of type 'number'.");
|
|
602
|
+
if ("serializedBody" in message) throw new TypeError("Cannot use `serializedBody` with `createMessageBatch()`");
|
|
603
|
+
const body = structuredClone(message.body);
|
|
604
|
+
Object.defineProperties(this, {
|
|
605
|
+
id: { get() {
|
|
606
|
+
return id;
|
|
607
|
+
} },
|
|
608
|
+
timestamp: { get() {
|
|
609
|
+
return timestamp;
|
|
610
|
+
} },
|
|
611
|
+
body: { get() {
|
|
612
|
+
return body;
|
|
613
|
+
} },
|
|
614
|
+
attempts: { get() {
|
|
615
|
+
return attempts;
|
|
616
|
+
} }
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
retry() {
|
|
620
|
+
if (!(this instanceof QueueMessage)) throw new TypeError("Illegal invocation");
|
|
621
|
+
if (this.#controller[kRetryAll]) return;
|
|
622
|
+
if (this.#controller[kAckAll]) {
|
|
623
|
+
console.warn(`Received a call to retry() on message ${this.id} after ackAll() was already called. Calling retry() on a message after calling ackAll() has no effect.`);
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
if (this[kAck]) {
|
|
627
|
+
console.warn(`Received a call to retry() on message ${this.id} after ack() was already called. Calling retry() on a message after calling ack() has no effect.`);
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
this[kRetry] = true;
|
|
631
|
+
}
|
|
632
|
+
ack() {
|
|
633
|
+
if (!(this instanceof QueueMessage)) throw new TypeError("Illegal invocation");
|
|
634
|
+
if (this.#controller[kAckAll]) return;
|
|
635
|
+
if (this.#controller[kRetryAll]) {
|
|
636
|
+
console.warn(`Received a call to ack() on message ${this.id} after retryAll() was already called. Calling ack() on a message after calling retryAll() has no effect.`);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (this[kRetry]) {
|
|
640
|
+
console.warn(`Received a call to ack() on message ${this.id} after retry() was already called. Calling ack() on a message after calling retry() has no effect.`);
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
this[kAck] = true;
|
|
644
|
+
}
|
|
819
645
|
};
|
|
820
|
-
var QueueController = class
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
);
|
|
855
|
-
return;
|
|
856
|
-
}
|
|
857
|
-
this[kRetryAll] = true;
|
|
858
|
-
}
|
|
859
|
-
ackAll() {
|
|
860
|
-
if (!(this instanceof _QueueController)) {
|
|
861
|
-
throw new TypeError("Illegal invocation");
|
|
862
|
-
}
|
|
863
|
-
if (this[kRetryAll]) {
|
|
864
|
-
console.warn(
|
|
865
|
-
"Received a call to ackAll() after retryAll() was already called. Calling ackAll() after calling retryAll() has no effect."
|
|
866
|
-
);
|
|
867
|
-
return;
|
|
868
|
-
}
|
|
869
|
-
this[kAckAll] = true;
|
|
870
|
-
}
|
|
646
|
+
var QueueController = class QueueController {
|
|
647
|
+
queue;
|
|
648
|
+
messages;
|
|
649
|
+
[kRetryAll] = false;
|
|
650
|
+
[kAckAll] = false;
|
|
651
|
+
constructor(flag, queueOption, messagesOption) {
|
|
652
|
+
if (flag !== kConstructFlag) throw new TypeError("Illegal constructor");
|
|
653
|
+
const queue = String(queueOption);
|
|
654
|
+
const messages = messagesOption.map((message) => new QueueMessage(kConstructFlag, this, message));
|
|
655
|
+
Object.defineProperties(this, {
|
|
656
|
+
queue: { get() {
|
|
657
|
+
return queue;
|
|
658
|
+
} },
|
|
659
|
+
messages: { get() {
|
|
660
|
+
return messages;
|
|
661
|
+
} }
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
retryAll() {
|
|
665
|
+
if (!(this instanceof QueueController)) throw new TypeError("Illegal invocation");
|
|
666
|
+
if (this[kAckAll]) {
|
|
667
|
+
console.warn("Received a call to retryAll() after ackAll() was already called. Calling retryAll() after calling ackAll() has no effect.");
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
this[kRetryAll] = true;
|
|
671
|
+
}
|
|
672
|
+
ackAll() {
|
|
673
|
+
if (!(this instanceof QueueController)) throw new TypeError("Illegal invocation");
|
|
674
|
+
if (this[kRetryAll]) {
|
|
675
|
+
console.warn("Received a call to ackAll() after retryAll() was already called. Calling ackAll() after calling retryAll() has no effect.");
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
this[kAckAll] = true;
|
|
679
|
+
}
|
|
871
680
|
};
|
|
872
681
|
function createMessageBatch(queueName, messages) {
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
);
|
|
877
|
-
}
|
|
878
|
-
if (!Array.isArray(messages)) {
|
|
879
|
-
throw new TypeError(
|
|
880
|
-
"Failed to execute 'createMessageBatch': parameter 2 is not of type 'Array'."
|
|
881
|
-
);
|
|
882
|
-
}
|
|
883
|
-
return new QueueController(kConstructFlag, queueName, messages);
|
|
682
|
+
if (arguments.length === 0) throw new TypeError("Failed to execute 'createMessageBatch': parameter 1 is not of type 'string'.");
|
|
683
|
+
if (!Array.isArray(messages)) throw new TypeError("Failed to execute 'createMessageBatch': parameter 2 is not of type 'Array'.");
|
|
684
|
+
return new QueueController(kConstructFlag, queueName, messages);
|
|
884
685
|
}
|
|
885
686
|
async function getQueueResult(batch, ctx) {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
}
|
|
903
|
-
if (message[kAck]) {
|
|
904
|
-
explicitAcks.push(message.id);
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
return {
|
|
908
|
-
outcome: "ok",
|
|
909
|
-
retryBatch: {
|
|
910
|
-
retry: batch[kRetryAll]
|
|
911
|
-
},
|
|
912
|
-
ackAll: batch[kAckAll],
|
|
913
|
-
retryMessages,
|
|
914
|
-
explicitAcks
|
|
915
|
-
};
|
|
687
|
+
if (!(batch instanceof QueueController)) throw new TypeError("Failed to execute 'getQueueResult': parameter 1 is not of type 'MessageBatch'.\nYou must call 'createMessageBatch()' to get a 'MessageBatch' instance.");
|
|
688
|
+
if (!(ctx instanceof ExecutionContext)) throw new TypeError("Failed to execute 'getQueueResult': parameter 2 is not of type 'ExecutionContext'.\nYou must call 'createExecutionContext()' to get an 'ExecutionContext' instance.");
|
|
689
|
+
await waitOnExecutionContext(ctx);
|
|
690
|
+
const retryMessages = [];
|
|
691
|
+
const explicitAcks = [];
|
|
692
|
+
for (const message of batch.messages) {
|
|
693
|
+
if (message[kRetry]) retryMessages.push({ msgId: message.id });
|
|
694
|
+
if (message[kAck]) explicitAcks.push(message.id);
|
|
695
|
+
}
|
|
696
|
+
return {
|
|
697
|
+
outcome: "ok",
|
|
698
|
+
retryBatch: { retry: batch[kRetryAll] },
|
|
699
|
+
ackAll: batch[kAckAll],
|
|
700
|
+
retryMessages,
|
|
701
|
+
explicitAcks
|
|
702
|
+
};
|
|
916
703
|
}
|
|
917
704
|
function hasASSETSServiceBinding(value) {
|
|
918
|
-
|
|
705
|
+
return "ASSETS" in value && typeof value.ASSETS === "object" && value.ASSETS !== null && "fetch" in value.ASSETS && typeof value.ASSETS.fetch === "function";
|
|
919
706
|
}
|
|
920
707
|
function createPagesEventContext(opts) {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
"Incorrect type for the 'data' field on 'EventContextInit': the provided value is not of type 'object'."
|
|
949
|
-
);
|
|
950
|
-
}
|
|
951
|
-
if (!hasASSETSServiceBinding(env)) {
|
|
952
|
-
throw new TypeError(
|
|
953
|
-
"Cannot call `createPagesEventContext()` without defining `ASSETS` service binding"
|
|
954
|
-
);
|
|
955
|
-
}
|
|
956
|
-
const ctx = createExecutionContext();
|
|
957
|
-
return {
|
|
958
|
-
// If we might need to re-use this request, clone it
|
|
959
|
-
request: opts.next ? opts.request.clone() : opts.request,
|
|
960
|
-
functionPath: opts.functionPath ?? "",
|
|
961
|
-
[kWaitUntil]: ctx[kWaitUntil],
|
|
962
|
-
waitUntil: ctx.waitUntil.bind(ctx),
|
|
963
|
-
passThroughOnException: ctx.passThroughOnException.bind(ctx),
|
|
964
|
-
async next(nextInput, nextInit) {
|
|
965
|
-
if (opts.next === void 0) {
|
|
966
|
-
throw new TypeError(
|
|
967
|
-
"Cannot call `EventContext#next()` without including `next` property in 2nd argument to `createPagesEventContext()`"
|
|
968
|
-
);
|
|
969
|
-
}
|
|
970
|
-
if (nextInput === void 0) {
|
|
971
|
-
return opts.next(opts.request);
|
|
972
|
-
} else {
|
|
973
|
-
if (typeof nextInput === "string") {
|
|
974
|
-
nextInput = new URL(nextInput, opts.request.url).toString();
|
|
975
|
-
}
|
|
976
|
-
const nextRequest = new Request(nextInput, nextInit);
|
|
977
|
-
return opts.next(nextRequest);
|
|
978
|
-
}
|
|
979
|
-
},
|
|
980
|
-
env,
|
|
981
|
-
params: opts.params ?? {},
|
|
982
|
-
data: opts.data ?? {}
|
|
983
|
-
};
|
|
708
|
+
if (typeof opts !== "object" || opts === null) throw new TypeError("Failed to execute 'createPagesEventContext': parameter 1 is not of type 'EventContextInit'.");
|
|
709
|
+
if (!(opts.request instanceof Request)) throw new TypeError("Incorrect type for the 'request' field on 'EventContextInit': the provided value is not of type 'Request'.");
|
|
710
|
+
if (opts.functionPath !== void 0 && typeof opts.functionPath !== "string") throw new TypeError("Incorrect type for the 'functionPath' field on 'EventContextInit': the provided value is not of type 'string'.");
|
|
711
|
+
if (opts.next !== void 0 && typeof opts.next !== "function") throw new TypeError("Incorrect type for the 'next' field on 'EventContextInit': the provided value is not of type 'function'.");
|
|
712
|
+
if (opts.params !== void 0 && !(typeof opts.params === "object" && opts.params !== null)) throw new TypeError("Incorrect type for the 'params' field on 'EventContextInit': the provided value is not of type 'object'.");
|
|
713
|
+
if (opts.data !== void 0 && !(typeof opts.data === "object" && opts.data !== null)) throw new TypeError("Incorrect type for the 'data' field on 'EventContextInit': the provided value is not of type 'object'.");
|
|
714
|
+
if (!hasASSETSServiceBinding(env)) throw new TypeError("Cannot call `createPagesEventContext()` without defining `ASSETS` service binding");
|
|
715
|
+
const ctx = createExecutionContext();
|
|
716
|
+
return {
|
|
717
|
+
request: opts.next ? opts.request.clone() : opts.request,
|
|
718
|
+
functionPath: opts.functionPath ?? "",
|
|
719
|
+
[kWaitUntil]: ctx[kWaitUntil],
|
|
720
|
+
waitUntil: ctx.waitUntil.bind(ctx),
|
|
721
|
+
passThroughOnException: ctx.passThroughOnException.bind(ctx),
|
|
722
|
+
async next(nextInput, nextInit) {
|
|
723
|
+
if (opts.next === void 0) throw new TypeError("Cannot call `EventContext#next()` without including `next` property in 2nd argument to `createPagesEventContext()`");
|
|
724
|
+
if (nextInput === void 0) return opts.next(opts.request);
|
|
725
|
+
else {
|
|
726
|
+
if (typeof nextInput === "string") nextInput = new URL(nextInput, opts.request.url).toString();
|
|
727
|
+
const nextRequest = new Request(nextInput, nextInit);
|
|
728
|
+
return opts.next(nextRequest);
|
|
729
|
+
}
|
|
730
|
+
},
|
|
731
|
+
env,
|
|
732
|
+
params: opts.params ?? {},
|
|
733
|
+
data: opts.data ?? {}
|
|
734
|
+
};
|
|
984
735
|
}
|
|
985
736
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
var SingleAccessMap = class extends Map {
|
|
998
|
-
get(key) {
|
|
999
|
-
const value = super.get(key);
|
|
1000
|
-
super.delete(key);
|
|
1001
|
-
return value;
|
|
1002
|
-
}
|
|
1003
|
-
};
|
|
1004
|
-
var requests = new SingleAccessMap();
|
|
1005
|
-
var responses = new SingleAccessMap();
|
|
1006
|
-
var originalFetch = fetch;
|
|
1007
|
-
setDispatcher((opts, handler) => {
|
|
1008
|
-
const serialisedOptions = JSON.stringify(opts);
|
|
1009
|
-
const request = requests.get(serialisedOptions);
|
|
1010
|
-
assert4(request !== void 0, "Expected dispatch to come from fetch()");
|
|
1011
|
-
originalFetch.call(globalThis, request.request, { body: request.body }).then((response) => {
|
|
1012
|
-
responses.set(serialisedOptions, response);
|
|
1013
|
-
assert4(handler.onComplete !== void 0, "Expected onComplete() handler");
|
|
1014
|
-
handler.onComplete?.([]);
|
|
1015
|
-
}).catch((error) => {
|
|
1016
|
-
assert4(handler.onError !== void 0, "Expected onError() handler");
|
|
1017
|
-
handler.onError(error);
|
|
1018
|
-
});
|
|
1019
|
-
});
|
|
1020
|
-
globalThis.fetch = async (input, init) => {
|
|
1021
|
-
const isActive = isMockActive(fetchMock);
|
|
1022
|
-
if (!isActive) {
|
|
1023
|
-
return originalFetch.call(globalThis, input, init);
|
|
1024
|
-
}
|
|
1025
|
-
const request = new Request(input, init);
|
|
1026
|
-
const url = new URL(request.url);
|
|
1027
|
-
const abortSignal = init?.signal;
|
|
1028
|
-
let abortSignalAborted = abortSignal?.aborted ?? false;
|
|
1029
|
-
abortSignal?.addEventListener("abort", () => {
|
|
1030
|
-
abortSignalAborted = true;
|
|
1031
|
-
});
|
|
1032
|
-
if (request.headers.get("Upgrade") !== null) {
|
|
1033
|
-
return originalFetch.call(globalThis, request);
|
|
1034
|
-
}
|
|
1035
|
-
const requestHeaders = {};
|
|
1036
|
-
for (const entry of request.headers) {
|
|
1037
|
-
const key = entry[0].toLowerCase();
|
|
1038
|
-
const value = entry[1];
|
|
1039
|
-
if (key === "set-cookie") {
|
|
1040
|
-
(requestHeaders[key] ??= []).push(value);
|
|
1041
|
-
} else {
|
|
1042
|
-
requestHeaders[key] = value;
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
const bodyArray = request.body === null ? null : new Uint8Array(await request.arrayBuffer());
|
|
1046
|
-
const bodyText = bodyArray === null ? "" : DECODER.decode(bodyArray);
|
|
1047
|
-
const dispatchOptions = {
|
|
1048
|
-
origin: url.origin,
|
|
1049
|
-
path: url.pathname + url.search,
|
|
1050
|
-
method: request.method,
|
|
1051
|
-
body: bodyText,
|
|
1052
|
-
headers: requestHeaders
|
|
1053
|
-
};
|
|
1054
|
-
const serialisedOptions = JSON.stringify(dispatchOptions);
|
|
1055
|
-
requests.set(serialisedOptions, { request, body: bodyArray });
|
|
1056
|
-
let responseStatusCode;
|
|
1057
|
-
let responseStatusText;
|
|
1058
|
-
let responseHeaders;
|
|
1059
|
-
const responseChunks = [];
|
|
1060
|
-
let responseResolve;
|
|
1061
|
-
let responseReject;
|
|
1062
|
-
const responsePromise = new Promise((resolve, reject) => {
|
|
1063
|
-
responseResolve = resolve;
|
|
1064
|
-
responseReject = reject;
|
|
1065
|
-
});
|
|
1066
|
-
const dispatchHandlers = {
|
|
1067
|
-
onError(error) {
|
|
1068
|
-
responseReject(error);
|
|
1069
|
-
},
|
|
1070
|
-
onUpgrade(_statusCode, _headers, _socket) {
|
|
1071
|
-
assert4.fail("Unreachable: upgrade requests not supported");
|
|
1072
|
-
},
|
|
1073
|
-
// `onHeaders` and `onData` will only be called if the response was mocked
|
|
1074
|
-
onHeaders(statusCode, headers, _resume, statusText) {
|
|
1075
|
-
if (abortSignalAborted) {
|
|
1076
|
-
return false;
|
|
1077
|
-
}
|
|
1078
|
-
responseStatusCode = statusCode;
|
|
1079
|
-
responseStatusText = statusText;
|
|
1080
|
-
if (headers === null) {
|
|
1081
|
-
return true;
|
|
1082
|
-
}
|
|
1083
|
-
assert4.strictEqual(headers.length % 2, 0, "Expected key/value array");
|
|
1084
|
-
responseHeaders = Array.from({ length: headers.length / 2 }).map(
|
|
1085
|
-
(_, i) => [headers[i * 2].toString(), headers[i * 2 + 1].toString()]
|
|
1086
|
-
);
|
|
1087
|
-
return true;
|
|
1088
|
-
},
|
|
1089
|
-
onData(chunk) {
|
|
1090
|
-
if (abortSignalAborted) {
|
|
1091
|
-
return false;
|
|
1092
|
-
}
|
|
1093
|
-
responseChunks.push(chunk);
|
|
1094
|
-
return true;
|
|
1095
|
-
},
|
|
1096
|
-
onComplete() {
|
|
1097
|
-
if (abortSignalAborted) {
|
|
1098
|
-
responseReject(
|
|
1099
|
-
castAsAbortError(new Error("The operation was aborted"))
|
|
1100
|
-
);
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
const maybeResponse = responses.get(serialisedOptions);
|
|
1104
|
-
if (maybeResponse === void 0) {
|
|
1105
|
-
const responseBody = Buffer.concat(responseChunks);
|
|
1106
|
-
const response = new Response(responseBody, {
|
|
1107
|
-
status: responseStatusCode,
|
|
1108
|
-
statusText: responseStatusText,
|
|
1109
|
-
headers: responseHeaders
|
|
1110
|
-
});
|
|
1111
|
-
const throwImmutableHeadersError = () => {
|
|
1112
|
-
throw new TypeError("Can't modify immutable headers");
|
|
1113
|
-
};
|
|
1114
|
-
Object.defineProperty(response, "url", { value: url.href });
|
|
1115
|
-
Object.defineProperties(response.headers, {
|
|
1116
|
-
set: { value: throwImmutableHeadersError },
|
|
1117
|
-
append: { value: throwImmutableHeadersError },
|
|
1118
|
-
delete: { value: throwImmutableHeadersError }
|
|
1119
|
-
});
|
|
1120
|
-
responseResolve(response);
|
|
1121
|
-
} else {
|
|
1122
|
-
responseResolve(maybeResponse);
|
|
1123
|
-
}
|
|
1124
|
-
},
|
|
1125
|
-
onBodySent() {
|
|
1126
|
-
}
|
|
1127
|
-
// (ignored)
|
|
1128
|
-
};
|
|
1129
|
-
fetchMock.dispatch(dispatchOptions, dispatchHandlers);
|
|
1130
|
-
return responsePromise;
|
|
1131
|
-
};
|
|
1132
|
-
|
|
1133
|
-
// ../workflows-shared/src/instance.ts
|
|
737
|
+
//#endregion
|
|
738
|
+
//#region ../workflows-shared/src/instance.ts
|
|
739
|
+
let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
|
|
740
|
+
InstanceStatus$1[InstanceStatus$1["Queued"] = 0] = "Queued";
|
|
741
|
+
InstanceStatus$1[InstanceStatus$1["Running"] = 1] = "Running";
|
|
742
|
+
InstanceStatus$1[InstanceStatus$1["Paused"] = 2] = "Paused";
|
|
743
|
+
InstanceStatus$1[InstanceStatus$1["Errored"] = 3] = "Errored";
|
|
744
|
+
InstanceStatus$1[InstanceStatus$1["Terminated"] = 4] = "Terminated";
|
|
745
|
+
InstanceStatus$1[InstanceStatus$1["Complete"] = 5] = "Complete";
|
|
746
|
+
return InstanceStatus$1;
|
|
747
|
+
}({});
|
|
1134
748
|
function instanceStatusName(status) {
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
case 4 /* Terminated */:
|
|
1145
|
-
return "terminated";
|
|
1146
|
-
case 5 /* Complete */:
|
|
1147
|
-
return "complete";
|
|
1148
|
-
default:
|
|
1149
|
-
return "unknown";
|
|
1150
|
-
}
|
|
749
|
+
switch (status) {
|
|
750
|
+
case InstanceStatus.Queued: return "queued";
|
|
751
|
+
case InstanceStatus.Running: return "running";
|
|
752
|
+
case InstanceStatus.Paused: return "paused";
|
|
753
|
+
case InstanceStatus.Errored: return "errored";
|
|
754
|
+
case InstanceStatus.Terminated: return "terminated";
|
|
755
|
+
case InstanceStatus.Complete: return "complete";
|
|
756
|
+
default: return "unknown";
|
|
757
|
+
}
|
|
1151
758
|
}
|
|
1152
759
|
|
|
1153
|
-
|
|
760
|
+
//#endregion
|
|
761
|
+
//#region src/worker/workflows.ts
|
|
1154
762
|
async function introspectWorkflowInstance(workflow, instanceId) {
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
"[WorkflowIntrospector] Workflow binding and instance id are required."
|
|
1158
|
-
);
|
|
1159
|
-
}
|
|
1160
|
-
return new WorkflowInstanceIntrospectorHandle(workflow, instanceId);
|
|
763
|
+
if (!workflow || !instanceId) throw new Error("[WorkflowIntrospector] Workflow binding and instance id are required.");
|
|
764
|
+
return new WorkflowInstanceIntrospectorHandle(workflow, instanceId);
|
|
1161
765
|
}
|
|
1162
766
|
var WorkflowInstanceIntrospectorHandle = class {
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
if (status === instanceStatusName(0 /* Queued */)) {
|
|
1203
|
-
return;
|
|
1204
|
-
}
|
|
1205
|
-
await this.#workflow.unsafeWaitForStatus(this.#instanceId, status);
|
|
1206
|
-
}
|
|
1207
|
-
async getOutput() {
|
|
1208
|
-
return await this.#workflow.unsafeGetOutputOrError(this.#instanceId, true);
|
|
1209
|
-
}
|
|
1210
|
-
async getError() {
|
|
1211
|
-
return await this.#workflow.unsafeGetOutputOrError(
|
|
1212
|
-
this.#instanceId,
|
|
1213
|
-
false
|
|
1214
|
-
);
|
|
1215
|
-
}
|
|
1216
|
-
async dispose() {
|
|
1217
|
-
await this.#workflow.unsafeAbort(this.#instanceId, "Instance dispose");
|
|
1218
|
-
}
|
|
1219
|
-
async [Symbol.asyncDispose]() {
|
|
1220
|
-
await this.dispose();
|
|
1221
|
-
}
|
|
767
|
+
#workflow;
|
|
768
|
+
#instanceId;
|
|
769
|
+
#instanceModifier;
|
|
770
|
+
#instanceModifierPromise;
|
|
771
|
+
constructor(workflow, instanceId) {
|
|
772
|
+
this.#workflow = workflow;
|
|
773
|
+
this.#instanceId = instanceId;
|
|
774
|
+
this.#instanceModifierPromise = workflow.unsafeGetInstanceModifier(instanceId).then((res) => {
|
|
775
|
+
this.#instanceModifier = res;
|
|
776
|
+
this.#instanceModifierPromise = void 0;
|
|
777
|
+
return this.#instanceModifier;
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
async modify(fn) {
|
|
781
|
+
if (this.#instanceModifierPromise !== void 0) this.#instanceModifier = await this.#instanceModifierPromise;
|
|
782
|
+
if (this.#instanceModifier === void 0) throw new Error("could not apply modifications due to internal error. Retrying the test may resolve the issue.");
|
|
783
|
+
await fn(this.#instanceModifier);
|
|
784
|
+
return this;
|
|
785
|
+
}
|
|
786
|
+
async waitForStepResult(step) {
|
|
787
|
+
return await this.#workflow.unsafeWaitForStepResult(this.#instanceId, step.name, step.index);
|
|
788
|
+
}
|
|
789
|
+
async waitForStatus(status) {
|
|
790
|
+
if (status === instanceStatusName(InstanceStatus.Terminated) || status === instanceStatusName(InstanceStatus.Paused)) throw new Error(`[WorkflowIntrospector] InstanceStatus '${status}' is not implemented yet and cannot be waited.`);
|
|
791
|
+
if (status === instanceStatusName(InstanceStatus.Queued)) return;
|
|
792
|
+
await this.#workflow.unsafeWaitForStatus(this.#instanceId, status);
|
|
793
|
+
}
|
|
794
|
+
async getOutput() {
|
|
795
|
+
return await this.#workflow.unsafeGetOutputOrError(this.#instanceId, true);
|
|
796
|
+
}
|
|
797
|
+
async getError() {
|
|
798
|
+
return await this.#workflow.unsafeGetOutputOrError(this.#instanceId, false);
|
|
799
|
+
}
|
|
800
|
+
async dispose() {
|
|
801
|
+
await this.#workflow.unsafeAbort(this.#instanceId, "Instance dispose");
|
|
802
|
+
}
|
|
803
|
+
async [Symbol.asyncDispose]() {
|
|
804
|
+
await this.dispose();
|
|
805
|
+
}
|
|
1222
806
|
};
|
|
1223
807
|
async function introspectWorkflow(workflow) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
return new Proxy(target[property], {
|
|
1271
|
-
async apply(func, thisArg, argArray) {
|
|
1272
|
-
for (const [index, arg] of argArray[0]?.entries() ?? []) {
|
|
1273
|
-
const hasId = Object.hasOwn(arg, "id");
|
|
1274
|
-
if (!hasId) {
|
|
1275
|
-
argArray[0][index] = { id: crypto.randomUUID(), ...arg };
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
await Promise.all(
|
|
1279
|
-
argArray[0].map(
|
|
1280
|
-
(options) => introspectAndModifyInstance(options.id)
|
|
1281
|
-
)
|
|
1282
|
-
);
|
|
1283
|
-
const createPromises = (argArray[0] ?? []).map(
|
|
1284
|
-
(arg) => target["create"](arg)
|
|
1285
|
-
);
|
|
1286
|
-
return Promise.all(createPromises);
|
|
1287
|
-
}
|
|
1288
|
-
});
|
|
1289
|
-
}
|
|
1290
|
-
return target[property];
|
|
1291
|
-
};
|
|
1292
|
-
};
|
|
1293
|
-
const dispose = () => {
|
|
1294
|
-
internalEnv[bindingName] = internalOriginalWorkflow;
|
|
1295
|
-
env[bindingName] = externalOriginalWorkflow;
|
|
1296
|
-
};
|
|
1297
|
-
const proxyGetHandler = createWorkflowProxyGetHandler();
|
|
1298
|
-
internalEnv[bindingName] = new Proxy(internalOriginalWorkflow, {
|
|
1299
|
-
get: proxyGetHandler
|
|
1300
|
-
});
|
|
1301
|
-
env[bindingName] = new Proxy(externalOriginalWorkflow, {
|
|
1302
|
-
get: proxyGetHandler
|
|
1303
|
-
});
|
|
1304
|
-
return new WorkflowIntrospectorHandle(
|
|
1305
|
-
workflow,
|
|
1306
|
-
modifierCallbacks,
|
|
1307
|
-
instanceIntrospectors,
|
|
1308
|
-
dispose
|
|
1309
|
-
);
|
|
808
|
+
if (!workflow) throw new Error("[WorkflowIntrospector] Workflow binding is required.");
|
|
809
|
+
const modifierCallbacks = [];
|
|
810
|
+
const instanceIntrospectors = [];
|
|
811
|
+
const bindingName = await workflow.unsafeGetBindingName();
|
|
812
|
+
const originalWorkflow = env$1[bindingName];
|
|
813
|
+
const introspectAndModifyInstance = async (instanceId) => {
|
|
814
|
+
try {
|
|
815
|
+
await runInRunnerObject(async () => {
|
|
816
|
+
const introspector = await introspectWorkflowInstance(workflow, instanceId);
|
|
817
|
+
instanceIntrospectors.push(introspector);
|
|
818
|
+
for (const callback of modifierCallbacks) await introspector.modify(callback);
|
|
819
|
+
});
|
|
820
|
+
} catch (error) {
|
|
821
|
+
console.error(`[WorkflowIntrospector] Error during introspection for instance ${instanceId}:`, error);
|
|
822
|
+
throw new Error(`[WorkflowIntrospector] Failed to introspect Workflow instance ${instanceId}.`);
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
const createWorkflowProxyGetHandler = () => {
|
|
826
|
+
return (target, property) => {
|
|
827
|
+
if (property === "create") return new Proxy(target[property], { async apply(func, thisArg, argArray) {
|
|
828
|
+
if (!Object.hasOwn(argArray[0] ?? {}, "id")) argArray = [{
|
|
829
|
+
id: crypto.randomUUID(),
|
|
830
|
+
...argArray[0] ?? {}
|
|
831
|
+
}];
|
|
832
|
+
const instanceId = argArray[0].id;
|
|
833
|
+
await introspectAndModifyInstance(instanceId);
|
|
834
|
+
return target[property](...argArray);
|
|
835
|
+
} });
|
|
836
|
+
if (property === "createBatch") return new Proxy(target[property], { async apply(func, thisArg, argArray) {
|
|
837
|
+
for (const [index, arg] of argArray[0]?.entries() ?? []) if (!Object.hasOwn(arg, "id")) argArray[0][index] = {
|
|
838
|
+
id: crypto.randomUUID(),
|
|
839
|
+
...arg
|
|
840
|
+
};
|
|
841
|
+
await Promise.all(argArray[0].map((options) => introspectAndModifyInstance(options.id)));
|
|
842
|
+
const createPromises = (argArray[0] ?? []).map((arg) => target["create"](arg));
|
|
843
|
+
return Promise.all(createPromises);
|
|
844
|
+
} });
|
|
845
|
+
return target[property];
|
|
846
|
+
};
|
|
847
|
+
};
|
|
848
|
+
const dispose = () => {
|
|
849
|
+
env$1[bindingName] = originalWorkflow;
|
|
850
|
+
};
|
|
851
|
+
const proxyGetHandler = createWorkflowProxyGetHandler();
|
|
852
|
+
env$1[bindingName] = new Proxy(originalWorkflow, { get: proxyGetHandler });
|
|
853
|
+
return new WorkflowIntrospectorHandle(workflow, modifierCallbacks, instanceIntrospectors, dispose);
|
|
1310
854
|
}
|
|
1311
855
|
var WorkflowIntrospectorHandle = class {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
await this.dispose();
|
|
1338
|
-
}
|
|
1339
|
-
};
|
|
1340
|
-
export {
|
|
1341
|
-
SELF,
|
|
1342
|
-
applyD1Migrations,
|
|
1343
|
-
castAsAbortError,
|
|
1344
|
-
createDurableObjectWrapper,
|
|
1345
|
-
createExecutionContext,
|
|
1346
|
-
createMessageBatch,
|
|
1347
|
-
createPagesEventContext,
|
|
1348
|
-
createScheduledController,
|
|
1349
|
-
createWorkerEntrypointWrapper,
|
|
1350
|
-
createWorkflowEntrypointWrapper,
|
|
1351
|
-
env,
|
|
1352
|
-
fetchMock,
|
|
1353
|
-
getQueueResult,
|
|
1354
|
-
getResolvedMainPath,
|
|
1355
|
-
getSerializedOptions,
|
|
1356
|
-
handlerContextStore,
|
|
1357
|
-
internalEnv,
|
|
1358
|
-
introspectWorkflow,
|
|
1359
|
-
introspectWorkflowInstance,
|
|
1360
|
-
listDurableObjectIds,
|
|
1361
|
-
maybeHandleRunRequest,
|
|
1362
|
-
registerGlobalWaitUntil,
|
|
1363
|
-
registerHandlerAndGlobalWaitUntil,
|
|
1364
|
-
runDurableObjectAlarm,
|
|
1365
|
-
runInDurableObject,
|
|
1366
|
-
runInRunnerObject,
|
|
1367
|
-
setEnv,
|
|
1368
|
-
stripInternalEnv,
|
|
1369
|
-
waitForGlobalWaitUntil,
|
|
1370
|
-
waitForWaitUntil,
|
|
1371
|
-
waitOnExecutionContext
|
|
856
|
+
workflow;
|
|
857
|
+
#modifierCallbacks;
|
|
858
|
+
#instanceIntrospectors;
|
|
859
|
+
#disposeCallback;
|
|
860
|
+
constructor(workflow, modifierCallbacks, instanceIntrospectors, disposeCallback) {
|
|
861
|
+
this.workflow = workflow;
|
|
862
|
+
this.#modifierCallbacks = modifierCallbacks;
|
|
863
|
+
this.#instanceIntrospectors = instanceIntrospectors;
|
|
864
|
+
this.#disposeCallback = disposeCallback;
|
|
865
|
+
}
|
|
866
|
+
async modifyAll(fn) {
|
|
867
|
+
this.#modifierCallbacks.push(fn);
|
|
868
|
+
}
|
|
869
|
+
get() {
|
|
870
|
+
return this.#instanceIntrospectors;
|
|
871
|
+
}
|
|
872
|
+
async dispose() {
|
|
873
|
+
await Promise.all(this.#instanceIntrospectors.map((introspector) => introspector.dispose()));
|
|
874
|
+
this.#modifierCallbacks = [];
|
|
875
|
+
this.#instanceIntrospectors = [];
|
|
876
|
+
this.#disposeCallback();
|
|
877
|
+
}
|
|
878
|
+
async [Symbol.asyncDispose]() {
|
|
879
|
+
await this.dispose();
|
|
880
|
+
}
|
|
1372
881
|
};
|
|
1373
|
-
|
|
882
|
+
|
|
883
|
+
//#endregion
|
|
884
|
+
export { SELF, applyD1Migrations, createDurableObjectWrapper, createExecutionContext, createMessageBatch, createPagesEventContext, createScheduledController, createWorkerEntrypointWrapper, createWorkflowEntrypointWrapper, env, getQueueResult, getResolvedMainPath, getSerializedOptions, handlerContextStore, introspectWorkflow, introspectWorkflowInstance, listDurableObjectIds, maybeHandleRunRequest, registerGlobalWaitUntil, registerHandlerAndGlobalWaitUntil, runDurableObjectAlarm, runInDurableObject, runInRunnerObject, waitForGlobalWaitUntil, waitForWaitUntil, waitOnExecutionContext };
|
|
885
|
+
//# sourceMappingURL=test-internal.mjs.map
|