@ricsam/isolate-daemon 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cjs/callback-fs-handler.cjs +34 -43
- package/dist/cjs/callback-fs-handler.cjs.map +3 -3
- package/dist/cjs/connection.cjs +264 -162
- package/dist/cjs/connection.cjs.map +3 -3
- package/dist/cjs/index.cjs +3 -2
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/callback-fs-handler.mjs +34 -43
- package/dist/mjs/callback-fs-handler.mjs.map +3 -3
- package/dist/mjs/connection.mjs +267 -160
- package/dist/mjs/connection.mjs.map +3 -3
- package/dist/mjs/index.mjs +3 -2
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/types.d.ts +15 -1
- package/package.json +1 -1
package/dist/mjs/connection.mjs
CHANGED
|
@@ -7,12 +7,39 @@ import {
|
|
|
7
7
|
ErrorCode,
|
|
8
8
|
STREAM_CHUNK_SIZE,
|
|
9
9
|
STREAM_DEFAULT_CREDIT,
|
|
10
|
-
marshalValue
|
|
10
|
+
marshalValue,
|
|
11
|
+
isPromiseRef,
|
|
12
|
+
isAsyncIteratorRef,
|
|
13
|
+
deserializeResponse,
|
|
14
|
+
IsolateEvents,
|
|
15
|
+
ClientEvents
|
|
11
16
|
} from "@ricsam/isolate-protocol";
|
|
12
17
|
import { createCallbackFileSystemHandler } from "./callback-fs-handler.mjs";
|
|
13
18
|
import {
|
|
14
19
|
createRuntime
|
|
15
20
|
} from "@ricsam/isolate-runtime";
|
|
21
|
+
var LINKER_CONFLICT_ERROR = "Module is currently being linked by another linker";
|
|
22
|
+
function getErrorText(error) {
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
const cause = error.cause;
|
|
25
|
+
const causeText = cause instanceof Error ? `${cause.name}: ${cause.message}
|
|
26
|
+
${cause.stack ?? ""}` : cause != null ? String(cause) : "";
|
|
27
|
+
return [error.name, error.message, error.stack, causeText].filter((part) => part != null && part !== "").join(`
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
if (typeof error === "string") {
|
|
31
|
+
return error;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return JSON.stringify(error);
|
|
35
|
+
} catch {
|
|
36
|
+
return String(error ?? "");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function isLinkerConflictError(error) {
|
|
40
|
+
const text = getErrorText(error).toLowerCase();
|
|
41
|
+
return text.includes(LINKER_CONFLICT_ERROR.toLowerCase());
|
|
42
|
+
}
|
|
16
43
|
function handleConnection(socket, state) {
|
|
17
44
|
const connection = {
|
|
18
45
|
socket,
|
|
@@ -45,17 +72,17 @@ function handleConnection(socket, state) {
|
|
|
45
72
|
const instance = state.isolates.get(isolateId);
|
|
46
73
|
if (instance) {
|
|
47
74
|
if (instance.namespaceId != null && !instance.isDisposed) {
|
|
48
|
-
|
|
75
|
+
if (instance.isPoisoned) {
|
|
76
|
+
hardDeleteRuntime(instance, state).catch(() => {});
|
|
77
|
+
} else {
|
|
78
|
+
softDeleteRuntime(instance, state);
|
|
79
|
+
}
|
|
49
80
|
} else if (!instance.isDisposed) {
|
|
50
|
-
instance
|
|
51
|
-
state.isolates.delete(isolateId);
|
|
81
|
+
hardDeleteRuntime(instance, state).catch(() => {});
|
|
52
82
|
}
|
|
53
83
|
}
|
|
54
84
|
}
|
|
55
85
|
for (const [, pending] of connection.pendingCallbacks) {
|
|
56
|
-
if (pending.timeoutId) {
|
|
57
|
-
clearTimeout(pending.timeoutId);
|
|
58
|
-
}
|
|
59
86
|
pending.reject(new Error("Connection closed"));
|
|
60
87
|
}
|
|
61
88
|
connection.pendingCallbacks.clear();
|
|
@@ -183,28 +210,64 @@ async function handleMessage(message, connection, state) {
|
|
|
183
210
|
case MessageType.CALLBACK_STREAM_END:
|
|
184
211
|
handleCallbackStreamEnd(message, connection);
|
|
185
212
|
break;
|
|
186
|
-
case MessageType.
|
|
187
|
-
|
|
188
|
-
break;
|
|
189
|
-
case MessageType.CLIENT_WS_MESSAGE:
|
|
190
|
-
handleClientWsMessage(message, connection, state);
|
|
191
|
-
break;
|
|
192
|
-
case MessageType.CLIENT_WS_CLOSED:
|
|
193
|
-
handleClientWsClosed(message, connection, state);
|
|
194
|
-
break;
|
|
195
|
-
case MessageType.CLIENT_WS_ERROR:
|
|
196
|
-
handleClientWsError(message, connection, state);
|
|
213
|
+
case MessageType.CLIENT_EVENT:
|
|
214
|
+
handleClientEvent(message, connection, state);
|
|
197
215
|
break;
|
|
198
216
|
default:
|
|
199
217
|
sendError(connection.socket, message.requestId ?? 0, ErrorCode.UNKNOWN_MESSAGE_TYPE, `Unknown message type: ${message.type}`);
|
|
200
218
|
}
|
|
201
219
|
}
|
|
220
|
+
async function hardDeleteRuntime(instance, state) {
|
|
221
|
+
try {
|
|
222
|
+
await instance.runtime.dispose();
|
|
223
|
+
} finally {
|
|
224
|
+
state.isolates.delete(instance.isolateId);
|
|
225
|
+
if (instance.namespaceId != null) {
|
|
226
|
+
const indexed = state.namespacedRuntimes.get(instance.namespaceId);
|
|
227
|
+
if (indexed?.isolateId === instance.isolateId) {
|
|
228
|
+
state.namespacedRuntimes.delete(instance.namespaceId);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
instance.isDisposed = true;
|
|
232
|
+
instance.disposedAt = undefined;
|
|
233
|
+
instance.ownerConnection = null;
|
|
234
|
+
if (instance.callbackContext) {
|
|
235
|
+
if (instance.callbackContext.reconnectionPromise) {
|
|
236
|
+
clearTimeout(instance.callbackContext.reconnectionPromise.timeoutId);
|
|
237
|
+
instance.callbackContext.reconnectionPromise.promise.catch(() => {});
|
|
238
|
+
instance.callbackContext.reconnectionPromise.reject(new Error("Runtime was permanently disposed"));
|
|
239
|
+
instance.callbackContext.reconnectionPromise = undefined;
|
|
240
|
+
}
|
|
241
|
+
instance.callbackContext.connection = null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
var RECONNECTION_TIMEOUT_MS = 30000;
|
|
202
246
|
function softDeleteRuntime(instance, state) {
|
|
203
247
|
instance.isDisposed = true;
|
|
204
248
|
instance.disposedAt = Date.now();
|
|
205
249
|
instance.ownerConnection = null;
|
|
206
250
|
if (instance.callbackContext) {
|
|
207
251
|
instance.callbackContext.connection = null;
|
|
252
|
+
let resolve;
|
|
253
|
+
let reject;
|
|
254
|
+
const promise = new Promise((res, rej) => {
|
|
255
|
+
resolve = res;
|
|
256
|
+
reject = rej;
|
|
257
|
+
});
|
|
258
|
+
promise.catch(() => {});
|
|
259
|
+
const timeoutId = setTimeout(() => {
|
|
260
|
+
if (instance.callbackContext?.reconnectionPromise) {
|
|
261
|
+
instance.callbackContext.reconnectionPromise = undefined;
|
|
262
|
+
reject(new Error("Reconnection timeout: no client reconnected within timeout"));
|
|
263
|
+
}
|
|
264
|
+
}, RECONNECTION_TIMEOUT_MS);
|
|
265
|
+
instance.callbackContext.reconnectionPromise = {
|
|
266
|
+
promise,
|
|
267
|
+
resolve,
|
|
268
|
+
reject,
|
|
269
|
+
timeoutId
|
|
270
|
+
};
|
|
208
271
|
}
|
|
209
272
|
instance.callbacks.clear();
|
|
210
273
|
instance.runtime.timers.clearAll();
|
|
@@ -218,6 +281,7 @@ function softDeleteRuntime(instance, state) {
|
|
|
218
281
|
function reuseNamespacedRuntime(instance, connection, message, state) {
|
|
219
282
|
instance.ownerConnection = connection.socket;
|
|
220
283
|
instance.isDisposed = false;
|
|
284
|
+
instance.isPoisoned = false;
|
|
221
285
|
instance.disposedAt = undefined;
|
|
222
286
|
instance.lastActivity = Date.now();
|
|
223
287
|
connection.isolates.add(instance.isolateId);
|
|
@@ -225,6 +289,11 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
|
|
|
225
289
|
const testEnvOptions = message.options.testEnvironment != null && typeof message.options.testEnvironment === "object" ? message.options.testEnvironment : undefined;
|
|
226
290
|
if (instance.callbackContext) {
|
|
227
291
|
instance.callbackContext.connection = connection;
|
|
292
|
+
if (instance.callbackContext.reconnectionPromise) {
|
|
293
|
+
clearTimeout(instance.callbackContext.reconnectionPromise.timeoutId);
|
|
294
|
+
instance.callbackContext.reconnectionPromise.resolve(connection);
|
|
295
|
+
instance.callbackContext.reconnectionPromise = undefined;
|
|
296
|
+
}
|
|
228
297
|
instance.callbackContext.consoleOnEntry = callbacks?.console?.onEntry?.callbackId;
|
|
229
298
|
instance.callbackContext.fetch = callbacks?.fetch?.callbackId;
|
|
230
299
|
instance.callbackContext.moduleLoader = callbacks?.moduleLoader?.callbackId;
|
|
@@ -319,6 +388,35 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
|
|
|
319
388
|
instance.returnedIterators = new Map;
|
|
320
389
|
instance.nextLocalCallbackId = 1e6;
|
|
321
390
|
}
|
|
391
|
+
async function waitForConnection(callbackContext) {
|
|
392
|
+
if (callbackContext.connection) {
|
|
393
|
+
return callbackContext.connection;
|
|
394
|
+
}
|
|
395
|
+
if (callbackContext.reconnectionPromise) {
|
|
396
|
+
return callbackContext.reconnectionPromise.promise;
|
|
397
|
+
}
|
|
398
|
+
throw new Error("No connection available and no reconnection pending");
|
|
399
|
+
}
|
|
400
|
+
async function invokeCallbackWithReconnect(callbackContext, getCallbackId, args, label, invokeClientCallback) {
|
|
401
|
+
const conn = await waitForConnection(callbackContext);
|
|
402
|
+
const cbId = getCallbackId();
|
|
403
|
+
if (cbId === undefined) {
|
|
404
|
+
throw new Error(`${label} callback not available`);
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
return await invokeClientCallback(conn, cbId, args);
|
|
408
|
+
} catch (err) {
|
|
409
|
+
if (callbackContext.reconnectionPromise && !callbackContext.connection) {
|
|
410
|
+
const newConn = await callbackContext.reconnectionPromise.promise;
|
|
411
|
+
const newCbId = getCallbackId();
|
|
412
|
+
if (newCbId === undefined) {
|
|
413
|
+
throw new Error(`${label} callback not available after reconnection`);
|
|
414
|
+
}
|
|
415
|
+
return invokeClientCallback(newConn, newCbId, args);
|
|
416
|
+
}
|
|
417
|
+
throw err;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
322
420
|
async function evictOldestDisposedRuntime(state) {
|
|
323
421
|
let oldest = null;
|
|
324
422
|
let oldestTime = Infinity;
|
|
@@ -332,18 +430,15 @@ async function evictOldestDisposedRuntime(state) {
|
|
|
332
430
|
}
|
|
333
431
|
if (oldest) {
|
|
334
432
|
try {
|
|
335
|
-
await oldest
|
|
433
|
+
await hardDeleteRuntime(oldest, state);
|
|
336
434
|
} catch {}
|
|
337
|
-
state.isolates.delete(oldest.isolateId);
|
|
338
|
-
if (oldest.namespaceId != null) {
|
|
339
|
-
state.namespacedRuntimes.delete(oldest.namespaceId);
|
|
340
|
-
}
|
|
341
435
|
return true;
|
|
342
436
|
}
|
|
343
437
|
return false;
|
|
344
438
|
}
|
|
345
439
|
async function handleCreateRuntime(message, connection, state) {
|
|
346
440
|
const namespaceId = message.options.namespaceId;
|
|
441
|
+
let namespaceCreationLocked = false;
|
|
347
442
|
if (namespaceId != null) {
|
|
348
443
|
const existing = state.namespacedRuntimes.get(namespaceId);
|
|
349
444
|
if (existing) {
|
|
@@ -365,14 +460,20 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
365
460
|
});
|
|
366
461
|
return;
|
|
367
462
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
if (!await evictOldestDisposedRuntime(state)) {
|
|
371
|
-
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_MEMORY_LIMIT, `Maximum isolates (${state.options.maxIsolates}) reached`);
|
|
463
|
+
if (state.namespacedCreatesInFlight.has(namespaceId)) {
|
|
464
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, `Namespace "${namespaceId}" creation already in progress`);
|
|
372
465
|
return;
|
|
373
466
|
}
|
|
467
|
+
state.namespacedCreatesInFlight.add(namespaceId);
|
|
468
|
+
namespaceCreationLocked = true;
|
|
374
469
|
}
|
|
375
470
|
try {
|
|
471
|
+
if (state.isolates.size >= state.options.maxIsolates) {
|
|
472
|
+
if (!await evictOldestDisposedRuntime(state)) {
|
|
473
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_MEMORY_LIMIT, `Maximum isolates (${state.options.maxIsolates}) reached`);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
376
477
|
const isolateId = randomUUID();
|
|
377
478
|
const consoleCallbacks = message.options.callbacks?.console;
|
|
378
479
|
const fetchCallback = message.options.callbacks?.fetch;
|
|
@@ -415,6 +516,7 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
415
516
|
nextLocalCallbackId: 1e6,
|
|
416
517
|
namespaceId,
|
|
417
518
|
isDisposed: false,
|
|
519
|
+
isPoisoned: false,
|
|
418
520
|
callbackContext
|
|
419
521
|
};
|
|
420
522
|
let bridgedCustomFunctions;
|
|
@@ -437,8 +539,6 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
437
539
|
return iteratorId;
|
|
438
540
|
}
|
|
439
541
|
});
|
|
440
|
-
const isPromiseRef = (value) => typeof value === "object" && value !== null && value.__type === "PromiseRef";
|
|
441
|
-
const isAsyncIteratorRef = (value) => typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
|
|
442
542
|
const addCallbackIdsToRefs = (value) => {
|
|
443
543
|
if (value === null || typeof value !== "object")
|
|
444
544
|
return value;
|
|
@@ -503,11 +603,16 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
503
603
|
}
|
|
504
604
|
return await callback(...args);
|
|
505
605
|
} else {
|
|
506
|
-
const conn = callbackContext
|
|
507
|
-
|
|
508
|
-
|
|
606
|
+
const conn = await waitForConnection(callbackContext);
|
|
607
|
+
try {
|
|
608
|
+
return await invokeClientCallback(conn, callbackId, args);
|
|
609
|
+
} catch (err) {
|
|
610
|
+
if (callbackContext.reconnectionPromise && !callbackContext.connection) {
|
|
611
|
+
const newConn = await callbackContext.reconnectionPromise.promise;
|
|
612
|
+
return invokeClientCallback(newConn, callbackId, args);
|
|
613
|
+
}
|
|
614
|
+
throw err;
|
|
509
615
|
}
|
|
510
|
-
return invokeClientCallback(conn, callbackId, args);
|
|
511
616
|
}
|
|
512
617
|
};
|
|
513
618
|
customFnMarshalOptions = { createMarshalContext, addCallbackIdsToRefs, invokeCallback };
|
|
@@ -524,27 +629,20 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
524
629
|
const nextCallbackId = callbackContext_.custom.get(`${name}:next`);
|
|
525
630
|
const returnCallbackId = callbackContext_.custom.get(`${name}:return`);
|
|
526
631
|
async function* bridgedIterator() {
|
|
527
|
-
const
|
|
528
|
-
if (!conn || startCallbackId === undefined) {
|
|
529
|
-
throw new Error(`AsyncIterator callback '${name}' not available`);
|
|
530
|
-
}
|
|
531
|
-
const startResult = await invokeClientCallback(conn, startCallbackId, args);
|
|
632
|
+
const startResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:start`), args, `AsyncIterator '${name}' start`, invokeClientCallback);
|
|
532
633
|
const iteratorId = startResult.iteratorId;
|
|
533
634
|
try {
|
|
534
635
|
while (true) {
|
|
535
|
-
const
|
|
536
|
-
if (!nextConn || nextCallbackId === undefined) {
|
|
537
|
-
throw new Error(`AsyncIterator callback '${name}' not available`);
|
|
538
|
-
}
|
|
539
|
-
const nextResult = await invokeClientCallback(nextConn, nextCallbackId, [iteratorId]);
|
|
636
|
+
const nextResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:next`), [iteratorId], `AsyncIterator '${name}' next`, invokeClientCallback);
|
|
540
637
|
if (nextResult.done)
|
|
541
638
|
return nextResult.value;
|
|
542
639
|
yield nextResult.value;
|
|
543
640
|
}
|
|
544
641
|
} finally {
|
|
545
642
|
const retConn = callbackContext_.connection;
|
|
546
|
-
|
|
547
|
-
|
|
643
|
+
const retCbId = callbackContext_.custom.get(`${name}:return`);
|
|
644
|
+
if (retConn && retCbId !== undefined) {
|
|
645
|
+
await invokeClientCallback(retConn, retCbId, [iteratorId]).catch(() => {});
|
|
548
646
|
}
|
|
549
647
|
}
|
|
550
648
|
}
|
|
@@ -555,12 +653,7 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
555
653
|
bridgedCustomFunctions[name] = {
|
|
556
654
|
type: registration.type,
|
|
557
655
|
fn: async (...args) => {
|
|
558
|
-
|
|
559
|
-
const cbId = callbackContext_.custom.get(name);
|
|
560
|
-
if (!conn || cbId === undefined) {
|
|
561
|
-
throw new Error(`Custom function callback '${name}' not available`);
|
|
562
|
-
}
|
|
563
|
-
return invokeClientCallback(conn, cbId, args);
|
|
656
|
+
return invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(name), args, `Custom function '${name}'`, invokeClientCallback);
|
|
564
657
|
}
|
|
565
658
|
};
|
|
566
659
|
}
|
|
@@ -569,12 +662,7 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
569
662
|
let moduleLoader;
|
|
570
663
|
if (moduleLoaderCallback) {
|
|
571
664
|
moduleLoader = async (specifier, importer) => {
|
|
572
|
-
|
|
573
|
-
const cbId = callbackContext.moduleLoader;
|
|
574
|
-
if (!conn || cbId === undefined) {
|
|
575
|
-
throw new Error("Module loader callback not available");
|
|
576
|
-
}
|
|
577
|
-
return invokeClientCallback(conn, cbId, [specifier, importer]);
|
|
665
|
+
return invokeCallbackWithReconnect(callbackContext, () => callbackContext.moduleLoader, [specifier, importer], "Module loader", invokeClientCallback);
|
|
578
666
|
};
|
|
579
667
|
}
|
|
580
668
|
let testEnvironment;
|
|
@@ -605,19 +693,8 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
605
693
|
if (playwrightCallbacks) {
|
|
606
694
|
playwrightOptions = {
|
|
607
695
|
handler: async (op) => {
|
|
608
|
-
const conn = callbackContext.connection;
|
|
609
|
-
const callbackId = callbackContext.playwright.handlerCallbackId;
|
|
610
|
-
if (!conn || callbackId === undefined) {
|
|
611
|
-
return {
|
|
612
|
-
ok: false,
|
|
613
|
-
error: {
|
|
614
|
-
name: "Error",
|
|
615
|
-
message: "Playwright handler callback not available"
|
|
616
|
-
}
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
696
|
try {
|
|
620
|
-
const resultJson = await
|
|
697
|
+
const resultJson = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.playwright.handlerCallbackId, [JSON.stringify(op)], "Playwright handler", invokeClientCallback);
|
|
621
698
|
return JSON.parse(resultJson);
|
|
622
699
|
} catch (err) {
|
|
623
700
|
const error = err;
|
|
@@ -657,18 +734,13 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
657
734
|
}
|
|
658
735
|
},
|
|
659
736
|
fetch: async (url, init) => {
|
|
660
|
-
const conn = callbackContext.connection;
|
|
661
|
-
const callbackId = callbackContext.fetch;
|
|
662
|
-
if (!conn || callbackId === undefined) {
|
|
663
|
-
throw new Error("Fetch callback not available");
|
|
664
|
-
}
|
|
665
737
|
const serialized = {
|
|
666
738
|
url,
|
|
667
739
|
method: init.method,
|
|
668
740
|
headers: init.headers,
|
|
669
741
|
body: init.rawBody
|
|
670
742
|
};
|
|
671
|
-
const result = await
|
|
743
|
+
const result = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.fetch, [serialized], "Fetch", invokeClientCallback);
|
|
672
744
|
if (result && typeof result === "object" && result.__streamingResponse) {
|
|
673
745
|
const response = result.response;
|
|
674
746
|
response.__isCallbackStream = true;
|
|
@@ -678,10 +750,7 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
678
750
|
},
|
|
679
751
|
fs: {
|
|
680
752
|
getDirectory: async (dirPath) => {
|
|
681
|
-
const conn = callbackContext
|
|
682
|
-
if (!conn) {
|
|
683
|
-
throw new Error("FS callbacks not available");
|
|
684
|
-
}
|
|
753
|
+
const conn = await waitForConnection(callbackContext);
|
|
685
754
|
return createCallbackFileSystemHandler({
|
|
686
755
|
connection: conn,
|
|
687
756
|
callbackContext,
|
|
@@ -768,18 +837,19 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
768
837
|
} else {
|
|
769
838
|
data = cmd.data;
|
|
770
839
|
}
|
|
771
|
-
const
|
|
772
|
-
type:
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
data,
|
|
778
|
-
code: cmd.code,
|
|
779
|
-
reason: cmd.reason
|
|
780
|
-
}
|
|
840
|
+
const payload = {
|
|
841
|
+
type: cmd.type,
|
|
842
|
+
connectionId: cmd.connectionId,
|
|
843
|
+
data,
|
|
844
|
+
code: cmd.code,
|
|
845
|
+
reason: cmd.reason
|
|
781
846
|
};
|
|
782
|
-
sendMessage(targetConnection.socket,
|
|
847
|
+
sendMessage(targetConnection.socket, {
|
|
848
|
+
type: MessageType.ISOLATE_EVENT,
|
|
849
|
+
isolateId,
|
|
850
|
+
event: IsolateEvents.WS_COMMAND,
|
|
851
|
+
payload
|
|
852
|
+
});
|
|
783
853
|
});
|
|
784
854
|
runtime.fetch.onClientWebSocketCommand((cmd) => {
|
|
785
855
|
const targetConnection = callbackContext.connection;
|
|
@@ -793,40 +863,62 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
793
863
|
data = cmd.data;
|
|
794
864
|
}
|
|
795
865
|
if (cmd.type === "connect") {
|
|
796
|
-
const
|
|
797
|
-
type: MessageType.CLIENT_WS_CONNECT,
|
|
798
|
-
requestId: 0,
|
|
799
|
-
isolateId,
|
|
866
|
+
const payload = {
|
|
800
867
|
socketId: cmd.socketId,
|
|
801
868
|
url: cmd.url,
|
|
802
869
|
protocols: cmd.protocols
|
|
803
870
|
};
|
|
804
|
-
sendMessage(targetConnection.socket,
|
|
805
|
-
|
|
806
|
-
const msg = {
|
|
807
|
-
type: MessageType.CLIENT_WS_SEND,
|
|
808
|
-
requestId: 0,
|
|
871
|
+
sendMessage(targetConnection.socket, {
|
|
872
|
+
type: MessageType.ISOLATE_EVENT,
|
|
809
873
|
isolateId,
|
|
874
|
+
event: IsolateEvents.WS_CLIENT_CONNECT,
|
|
875
|
+
payload
|
|
876
|
+
});
|
|
877
|
+
} else if (cmd.type === "send") {
|
|
878
|
+
const payload = {
|
|
810
879
|
socketId: cmd.socketId,
|
|
811
880
|
data
|
|
812
881
|
};
|
|
813
|
-
sendMessage(targetConnection.socket,
|
|
814
|
-
|
|
815
|
-
const msg = {
|
|
816
|
-
type: MessageType.CLIENT_WS_CLOSE,
|
|
817
|
-
requestId: 0,
|
|
882
|
+
sendMessage(targetConnection.socket, {
|
|
883
|
+
type: MessageType.ISOLATE_EVENT,
|
|
818
884
|
isolateId,
|
|
885
|
+
event: IsolateEvents.WS_CLIENT_SEND,
|
|
886
|
+
payload
|
|
887
|
+
});
|
|
888
|
+
} else if (cmd.type === "close") {
|
|
889
|
+
const payload = {
|
|
819
890
|
socketId: cmd.socketId,
|
|
820
891
|
code: cmd.code,
|
|
821
892
|
reason: cmd.reason
|
|
822
893
|
};
|
|
823
|
-
sendMessage(targetConnection.socket,
|
|
894
|
+
sendMessage(targetConnection.socket, {
|
|
895
|
+
type: MessageType.ISOLATE_EVENT,
|
|
896
|
+
isolateId,
|
|
897
|
+
event: IsolateEvents.WS_CLIENT_CLOSE,
|
|
898
|
+
payload
|
|
899
|
+
});
|
|
824
900
|
}
|
|
825
901
|
});
|
|
902
|
+
runtime.fetch.onEvent((eventName, payload) => {
|
|
903
|
+
const targetConnection = callbackContext.connection;
|
|
904
|
+
if (!targetConnection) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
sendMessage(targetConnection.socket, {
|
|
908
|
+
type: MessageType.ISOLATE_EVENT,
|
|
909
|
+
isolateId,
|
|
910
|
+
event: eventName,
|
|
911
|
+
payload
|
|
912
|
+
});
|
|
913
|
+
});
|
|
826
914
|
sendOk(connection.socket, message.requestId, { isolateId, reused: false });
|
|
827
915
|
} catch (err) {
|
|
828
916
|
const error = err;
|
|
829
917
|
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
918
|
+
} finally {
|
|
919
|
+
if (namespaceCreationLocked && namespaceId != null) {
|
|
920
|
+
state.namespacedCreatesInFlight.delete(namespaceId);
|
|
921
|
+
}
|
|
830
922
|
}
|
|
831
923
|
}
|
|
832
924
|
async function handleDisposeRuntime(message, connection, state) {
|
|
@@ -842,14 +934,20 @@ async function handleDisposeRuntime(message, connection, state) {
|
|
|
842
934
|
try {
|
|
843
935
|
connection.isolates.delete(message.isolateId);
|
|
844
936
|
if (instance.namespaceId != null) {
|
|
845
|
-
|
|
937
|
+
if (instance.isPoisoned) {
|
|
938
|
+
await hardDeleteRuntime(instance, state);
|
|
939
|
+
} else {
|
|
940
|
+
softDeleteRuntime(instance, state);
|
|
941
|
+
}
|
|
846
942
|
} else {
|
|
847
|
-
await instance
|
|
848
|
-
state.isolates.delete(message.isolateId);
|
|
943
|
+
await hardDeleteRuntime(instance, state);
|
|
849
944
|
}
|
|
850
945
|
sendOk(connection.socket, message.requestId);
|
|
851
946
|
} catch (err) {
|
|
852
947
|
const error = err;
|
|
948
|
+
if (instance.namespaceId != null && isLinkerConflictError(error)) {
|
|
949
|
+
instance.isPoisoned = true;
|
|
950
|
+
}
|
|
853
951
|
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
854
952
|
}
|
|
855
953
|
}
|
|
@@ -862,14 +960,15 @@ async function handleEval(message, connection, state) {
|
|
|
862
960
|
instance.lastActivity = Date.now();
|
|
863
961
|
try {
|
|
864
962
|
await instance.runtime.eval(message.code, {
|
|
865
|
-
filename: message.filename
|
|
866
|
-
maxExecutionMs: message.maxExecutionMs
|
|
963
|
+
filename: message.filename
|
|
867
964
|
});
|
|
868
965
|
sendOk(connection.socket, message.requestId, { value: undefined });
|
|
869
966
|
} catch (err) {
|
|
870
967
|
const error = err;
|
|
871
|
-
|
|
872
|
-
|
|
968
|
+
if (instance.namespaceId != null && isLinkerConflictError(error)) {
|
|
969
|
+
instance.isPoisoned = true;
|
|
970
|
+
}
|
|
971
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
873
972
|
}
|
|
874
973
|
}
|
|
875
974
|
async function handleDispatchRequest(message, connection, state) {
|
|
@@ -977,34 +1076,38 @@ async function handleWsClose(message, connection, state) {
|
|
|
977
1076
|
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
978
1077
|
}
|
|
979
1078
|
}
|
|
980
|
-
function
|
|
981
|
-
const instance = state.isolates.get(message.isolateId);
|
|
982
|
-
if (!instance)
|
|
983
|
-
return;
|
|
984
|
-
instance.lastActivity = Date.now();
|
|
985
|
-
instance.runtime.fetch.dispatchClientWebSocketOpen(message.socketId, message.protocol, message.extensions);
|
|
986
|
-
}
|
|
987
|
-
function handleClientWsMessage(message, connection, state) {
|
|
988
|
-
const instance = state.isolates.get(message.isolateId);
|
|
989
|
-
if (!instance)
|
|
990
|
-
return;
|
|
991
|
-
instance.lastActivity = Date.now();
|
|
992
|
-
const data = message.data instanceof Uint8Array ? message.data.buffer.slice(message.data.byteOffset, message.data.byteOffset + message.data.byteLength) : message.data;
|
|
993
|
-
instance.runtime.fetch.dispatchClientWebSocketMessage(message.socketId, data);
|
|
994
|
-
}
|
|
995
|
-
function handleClientWsClosed(message, connection, state) {
|
|
1079
|
+
function handleClientEvent(message, connection, state) {
|
|
996
1080
|
const instance = state.isolates.get(message.isolateId);
|
|
997
1081
|
if (!instance)
|
|
998
1082
|
return;
|
|
999
1083
|
instance.lastActivity = Date.now();
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1084
|
+
switch (message.event) {
|
|
1085
|
+
case ClientEvents.WS_CLIENT_OPENED: {
|
|
1086
|
+
const payload = message.payload;
|
|
1087
|
+
instance.runtime.fetch.dispatchClientWebSocketOpen(payload.socketId, payload.protocol, payload.extensions);
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
case ClientEvents.WS_CLIENT_MESSAGE: {
|
|
1091
|
+
const payload = message.payload;
|
|
1092
|
+
const data = payload.data instanceof Uint8Array ? payload.data.buffer.slice(payload.data.byteOffset, payload.data.byteOffset + payload.data.byteLength) : payload.data;
|
|
1093
|
+
instance.runtime.fetch.dispatchClientWebSocketMessage(payload.socketId, data);
|
|
1094
|
+
break;
|
|
1095
|
+
}
|
|
1096
|
+
case ClientEvents.WS_CLIENT_CLOSED: {
|
|
1097
|
+
const payload = message.payload;
|
|
1098
|
+
instance.runtime.fetch.dispatchClientWebSocketClose(payload.socketId, payload.code, payload.reason, payload.wasClean);
|
|
1099
|
+
break;
|
|
1100
|
+
}
|
|
1101
|
+
case ClientEvents.WS_CLIENT_ERROR: {
|
|
1102
|
+
const payload = message.payload;
|
|
1103
|
+
instance.runtime.fetch.dispatchClientWebSocketError(payload.socketId);
|
|
1104
|
+
break;
|
|
1105
|
+
}
|
|
1106
|
+
default: {
|
|
1107
|
+
instance.runtime.fetch.dispatchEvent(message.event, message.payload);
|
|
1108
|
+
break;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1008
1111
|
}
|
|
1009
1112
|
async function handleFetchGetUpgradeRequest(message, connection, state) {
|
|
1010
1113
|
const instance = state.isolates.get(message.isolateId);
|
|
@@ -1148,9 +1251,6 @@ function handleCallbackResponse(message, connection) {
|
|
|
1148
1251
|
return;
|
|
1149
1252
|
}
|
|
1150
1253
|
connection.pendingCallbacks.delete(message.requestId);
|
|
1151
|
-
if (pending.timeoutId) {
|
|
1152
|
-
clearTimeout(pending.timeoutId);
|
|
1153
|
-
}
|
|
1154
1254
|
if (message.error) {
|
|
1155
1255
|
const error = new Error(message.error.message);
|
|
1156
1256
|
error.name = message.error.name;
|
|
@@ -1162,17 +1262,12 @@ function handleCallbackResponse(message, connection) {
|
|
|
1162
1262
|
pending.resolve(message.result);
|
|
1163
1263
|
}
|
|
1164
1264
|
}
|
|
1165
|
-
async function invokeClientCallback(connection, callbackId, args
|
|
1265
|
+
async function invokeClientCallback(connection, callbackId, args) {
|
|
1166
1266
|
const requestId = connection.nextCallbackId++;
|
|
1167
1267
|
return new Promise((resolve, reject) => {
|
|
1168
|
-
const timeoutId = setTimeout(() => {
|
|
1169
|
-
connection.pendingCallbacks.delete(requestId);
|
|
1170
|
-
reject(new Error("Callback timeout"));
|
|
1171
|
-
}, timeout);
|
|
1172
1268
|
const pending = {
|
|
1173
1269
|
resolve,
|
|
1174
|
-
reject
|
|
1175
|
-
timeoutId
|
|
1270
|
+
reject
|
|
1176
1271
|
};
|
|
1177
1272
|
connection.pendingCallbacks.set(requestId, pending);
|
|
1178
1273
|
const invoke = {
|
|
@@ -1184,13 +1279,6 @@ async function invokeClientCallback(connection, callbackId, args, timeout = 1e4)
|
|
|
1184
1279
|
sendMessage(connection.socket, invoke);
|
|
1185
1280
|
});
|
|
1186
1281
|
}
|
|
1187
|
-
function deserializeResponse(data) {
|
|
1188
|
-
return new Response(data.body, {
|
|
1189
|
-
status: data.status,
|
|
1190
|
-
statusText: data.statusText,
|
|
1191
|
-
headers: data.headers
|
|
1192
|
-
});
|
|
1193
|
-
}
|
|
1194
1282
|
function handleStreamPush(message, connection) {
|
|
1195
1283
|
const receiver = connection.streamReceivers.get(message.streamId);
|
|
1196
1284
|
if (!receiver) {
|
|
@@ -1318,9 +1406,6 @@ function handleCallbackStreamStart(message, connection) {
|
|
|
1318
1406
|
const pending = connection.pendingCallbacks.get(message.requestId);
|
|
1319
1407
|
if (pending) {
|
|
1320
1408
|
connection.pendingCallbacks.delete(message.requestId);
|
|
1321
|
-
if (pending.timeoutId) {
|
|
1322
|
-
clearTimeout(pending.timeoutId);
|
|
1323
|
-
}
|
|
1324
1409
|
const response = new Response(readableStream, {
|
|
1325
1410
|
status: message.metadata.status,
|
|
1326
1411
|
statusText: message.metadata.statusText,
|
|
@@ -1451,13 +1536,35 @@ async function handleRunTests(message, connection, state) {
|
|
|
1451
1536
|
return;
|
|
1452
1537
|
}
|
|
1453
1538
|
instance.lastActivity = Date.now();
|
|
1539
|
+
if (instance.pendingTestRun) {
|
|
1540
|
+
try {
|
|
1541
|
+
const results = await instance.pendingTestRun.promise;
|
|
1542
|
+
const currentConn = instance.callbackContext?.connection;
|
|
1543
|
+
if (currentConn) {
|
|
1544
|
+
sendOk(currentConn.socket, message.requestId, results);
|
|
1545
|
+
}
|
|
1546
|
+
} catch (err) {
|
|
1547
|
+
const error = err;
|
|
1548
|
+
const currentConn = instance.callbackContext?.connection;
|
|
1549
|
+
if (currentConn) {
|
|
1550
|
+
sendError(currentConn.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1454
1555
|
try {
|
|
1455
1556
|
const timeout = message.timeout ?? 30000;
|
|
1456
|
-
const
|
|
1457
|
-
|
|
1557
|
+
const runPromise = instance.runtime.testEnvironment.runTests(timeout);
|
|
1558
|
+
instance.pendingTestRun = { promise: runPromise };
|
|
1559
|
+
const results = await runPromise;
|
|
1560
|
+
instance.pendingTestRun = undefined;
|
|
1561
|
+
const currentConn = instance.callbackContext?.connection ?? connection;
|
|
1562
|
+
sendOk(currentConn.socket, message.requestId, results);
|
|
1458
1563
|
} catch (err) {
|
|
1564
|
+
instance.pendingTestRun = undefined;
|
|
1459
1565
|
const error = err;
|
|
1460
|
-
|
|
1566
|
+
const currentConn = instance.callbackContext?.connection ?? connection;
|
|
1567
|
+
sendError(currentConn.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
1461
1568
|
}
|
|
1462
1569
|
}
|
|
1463
1570
|
async function handleResetTestEnv(message, connection, state) {
|
|
@@ -1539,4 +1646,4 @@ export {
|
|
|
1539
1646
|
handleConnection
|
|
1540
1647
|
};
|
|
1541
1648
|
|
|
1542
|
-
//# debugId=
|
|
1649
|
+
//# debugId=DCB2345D02FBF03C64756E2164756E21
|