@ricsam/isolate-daemon 0.1.17 → 0.1.18
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/cjs/callback-fs-handler.cjs +19 -9
- package/dist/cjs/callback-fs-handler.cjs.map +2 -2
- package/dist/cjs/connection.cjs +100 -41
- package/dist/cjs/connection.cjs.map +3 -3
- package/dist/cjs/index.cjs +19 -9
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/types.cjs +14 -8
- package/dist/cjs/types.cjs.map +1 -1
- package/dist/mjs/connection.mjs +82 -33
- package/dist/mjs/connection.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -2,27 +2,37 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
6
8
|
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
8
10
|
if (entry)
|
|
9
11
|
return entry;
|
|
10
12
|
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
16
21
|
__moduleCache.set(from, entry);
|
|
17
22
|
return entry;
|
|
18
23
|
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
19
29
|
var __export = (target, all) => {
|
|
20
30
|
for (var name in all)
|
|
21
31
|
__defProp(target, name, {
|
|
22
32
|
get: all[name],
|
|
23
33
|
enumerable: true,
|
|
24
34
|
configurable: true,
|
|
25
|
-
set: (
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
26
36
|
});
|
|
27
37
|
};
|
|
28
38
|
|
|
@@ -130,4 +140,4 @@ function updateStats(state) {
|
|
|
130
140
|
state.stats.activeConnections = state.connections.size;
|
|
131
141
|
}
|
|
132
142
|
|
|
133
|
-
//# debugId=
|
|
143
|
+
//# debugId=08DBEA612F7F726864756E2164756E21
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * @ricsam/isolate-daemon\n *\n * Node.js daemon for running isolated-vm runtimes accessible via IPC.\n */\n\nimport { createServer, type Server } from \"node:net\";\nimport { unlink } from \"node:fs/promises\";\nimport { handleConnection } from \"./connection.cjs\";\nimport type {\n DaemonOptions,\n DaemonHandle,\n DaemonState,\n DaemonStats,\n} from \"./types.cjs\";\n\nexport type { DaemonOptions, DaemonHandle, DaemonStats };\n\nconst DEFAULT_OPTIONS: Required<DaemonOptions> = {\n socketPath: \"/tmp/isolate-daemon.sock\",\n host: \"127.0.0.1\",\n port: 47891,\n maxIsolates: 100,\n defaultMemoryLimitMB: 128,\n};\n\n/**\n * Start the isolate daemon.\n *\n * @param options - Daemon configuration options\n * @returns Handle to control the daemon\n */\nexport async function startDaemon(\n options: DaemonOptions = {}\n): Promise<DaemonHandle> {\n const resolvedOptions: Required<DaemonOptions> = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n const state: DaemonState = {\n isolates: new Map(),\n connections: new Map(),\n stats: {\n activeIsolates: 0,\n activeConnections: 0,\n totalIsolatesCreated: 0,\n totalRequestsProcessed: 0,\n },\n options: resolvedOptions,\n namespacedRuntimes: new Map(),\n namespacedCreatesInFlight: new Set(),\n };\n\n const server = createServer((socket) => {\n handleConnection(socket, state);\n updateStats(state);\n });\n\n // Try to remove existing socket file\n if (resolvedOptions.socketPath) {\n try {\n await unlink(resolvedOptions.socketPath);\n } catch {\n // Ignore if doesn't exist\n }\n }\n\n // Start listening\n await new Promise<void>((resolve, reject) => {\n server.on(\"error\", reject);\n\n if (resolvedOptions.socketPath) {\n server.listen(resolvedOptions.socketPath, () => {\n server.removeListener(\"error\", reject);\n resolve();\n });\n } else {\n server.listen(resolvedOptions.port, resolvedOptions.host, () => {\n server.removeListener(\"error\", reject);\n resolve();\n });\n }\n });\n\n const address = resolvedOptions.socketPath\n ? resolvedOptions.socketPath\n : `${resolvedOptions.host}:${resolvedOptions.port}`;\n\n console.log(`Isolate daemon listening on ${address}`);\n\n return {\n address,\n getStats: () => ({\n ...state.stats,\n activeIsolates: state.isolates.size,\n activeConnections: state.connections.size,\n }),\n close: async () => {\n // Close all connections\n for (const [socket] of state.connections) {\n socket.destroy();\n }\n\n // Dispose all isolates\n for (const [, instance] of state.isolates) {\n try {\n instance.runtime.dispose();\n } catch {\n // Ignore\n }\n }\n\n state.isolates.clear();\n state.connections.clear();\n state.namespacedRuntimes.clear();\n\n // Close server\n await closeServer(server);\n\n // Remove socket file\n if (resolvedOptions.socketPath) {\n try {\n await unlink(resolvedOptions.socketPath);\n } catch {\n // Ignore\n }\n }\n\n console.log(\"Isolate daemon stopped\");\n },\n };\n}\n\nfunction closeServer(server: Server): Promise<void> {\n return new Promise((resolve, reject) => {\n server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n}\n\nfunction updateStats(state: DaemonState): void {\n state.stats.activeIsolates = state.isolates.size;\n state.stats.activeConnections = state.connections.size;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAM0C,IAA1C;AACuB,IAAvB;AACiC,IAAjC;AAUA,IAAM,kBAA2C;AAAA,EAC/C,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,aAAa;AAAA,EACb,sBAAsB;AACxB;AAQA,eAAsB,WAAW,CAC/B,UAAyB,CAAC,GACH;AAAA,EACvB,MAAM,kBAA2C;AAAA,OAC5C;AAAA,OACA;AAAA,EACL;AAAA,EAEA,MAAM,QAAqB;AAAA,IACzB,UAAU,IAAI;AAAA,IACd,aAAa,IAAI;AAAA,IACjB,OAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,mBAAmB;AAAA,MACnB,sBAAsB;AAAA,MACtB,wBAAwB;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,IACT,oBAAoB,IAAI;AAAA,IACxB,2BAA2B,IAAI;AAAA,EACjC;AAAA,EAEA,MAAM,SAAS,6BAAa,CAAC,WAAW;AAAA,IACtC,mCAAiB,QAAQ,KAAK;AAAA,IAC9B,YAAY,KAAK;AAAA,GAClB;AAAA,EAGD,IAAI,gBAAgB,YAAY;AAAA,IAC9B,IAAI;AAAA,MACF,MAAM,uBAAO,gBAAgB,UAAU;AAAA,MACvC,MAAM;AAAA,EAGV;AAAA,EAGA,MAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAAA,IAC3C,OAAO,GAAG,SAAS,MAAM;AAAA,IAEzB,IAAI,gBAAgB,YAAY;AAAA,MAC9B,OAAO,OAAO,gBAAgB,YAAY,MAAM;AAAA,QAC9C,OAAO,eAAe,SAAS,MAAM;AAAA,QACrC,QAAQ;AAAA,OACT;AAAA,IACH,EAAO;AAAA,MACL,OAAO,OAAO,gBAAgB,MAAM,gBAAgB,MAAM,MAAM;AAAA,QAC9D,OAAO,eAAe,SAAS,MAAM;AAAA,QACrC,QAAQ;AAAA,OACT;AAAA;AAAA,GAEJ;AAAA,EAED,MAAM,UAAU,gBAAgB,aAC5B,gBAAgB,aAChB,GAAG,gBAAgB,QAAQ,gBAAgB;AAAA,EAE/C,QAAQ,IAAI,+BAA+B,SAAS;AAAA,EAEpD,OAAO;AAAA,IACL;AAAA,IACA,UAAU,OAAO;AAAA,SACZ,MAAM;AAAA,MACT,gBAAgB,MAAM,SAAS;AAAA,MAC/B,mBAAmB,MAAM,YAAY;AAAA,IACvC;AAAA,IACA,OAAO,YAAY;AAAA,MAEjB,YAAY,WAAW,MAAM,aAAa;AAAA,QACxC,OAAO,QAAQ;AAAA,MACjB;AAAA,MAGA,cAAc,aAAa,MAAM,UAAU;AAAA,QACzC,IAAI;AAAA,UACF,SAAS,QAAQ,QAAQ;AAAA,UACzB,MAAM;AAAA,MAGV;AAAA,MAEA,MAAM,SAAS,MAAM;AAAA,MACrB,MAAM,YAAY,MAAM;AAAA,MACxB,MAAM,mBAAmB,MAAM;AAAA,MAG/B,MAAM,YAAY,MAAM;AAAA,MAGxB,IAAI,gBAAgB,YAAY;AAAA,QAC9B,IAAI;AAAA,UACF,MAAM,uBAAO,gBAAgB,UAAU;AAAA,UACvC,MAAM;AAAA,MAGV;AAAA,MAEA,QAAQ,IAAI,wBAAwB;AAAA;AAAA,EAExC;AAAA;AAGF,SAAS,WAAW,CAAC,QAA+B;AAAA,EAClD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,IACtC,OAAO,MAAM,CAAC,QAAQ;AAAA,MACpB,IAAI,KAAK;AAAA,QACP,OAAO,GAAG;AAAA,MACZ,EAAO;AAAA,QACL,QAAQ;AAAA;AAAA,KAEX;AAAA,GACF;AAAA;AAGH,SAAS,WAAW,CAAC,OAA0B;AAAA,EAC7C,MAAM,MAAM,iBAAiB,MAAM,SAAS;AAAA,EAC5C,MAAM,MAAM,oBAAoB,MAAM,YAAY;AAAA;",
|
|
8
|
+
"debugId": "08DBEA612F7F726864756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/cjs/package.json
CHANGED
package/dist/cjs/types.cjs
CHANGED
|
@@ -2,23 +2,29 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
6
8
|
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
8
10
|
if (entry)
|
|
9
11
|
return entry;
|
|
10
12
|
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
16
21
|
__moduleCache.set(from, entry);
|
|
17
22
|
return entry;
|
|
18
23
|
};
|
|
24
|
+
var __moduleCache;
|
|
19
25
|
|
|
20
26
|
// packages/isolate-daemon/src/types.ts
|
|
21
27
|
var exports_types = {};
|
|
22
28
|
module.exports = __toCommonJS(exports_types);
|
|
23
29
|
|
|
24
|
-
//# debugId=
|
|
30
|
+
//# debugId=5C509FE4BE77B71164756E2164756E21
|
package/dist/cjs/types.cjs.map
CHANGED
package/dist/mjs/connection.mjs
CHANGED
|
@@ -70,6 +70,9 @@ function handleConnection(socket, state) {
|
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
socket.on("close", () => {
|
|
73
|
+
for (const streamId of Array.from(connection.activeStreams.keys())) {
|
|
74
|
+
closeActiveDownloadSession(connection, streamId);
|
|
75
|
+
}
|
|
73
76
|
for (const [, controller] of connection.dispatchAbortControllers) {
|
|
74
77
|
controller.abort();
|
|
75
78
|
}
|
|
@@ -103,6 +106,22 @@ function sendMessage(socket, message) {
|
|
|
103
106
|
const frame = buildFrame(message);
|
|
104
107
|
socket.write(frame);
|
|
105
108
|
}
|
|
109
|
+
function closeActiveDownloadSession(connection, streamId) {
|
|
110
|
+
const session = connection.activeStreams.get(streamId);
|
|
111
|
+
if (!session) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
session.state = "closed";
|
|
115
|
+
if (session.creditResolver) {
|
|
116
|
+
session.creditResolver();
|
|
117
|
+
session.creditResolver = undefined;
|
|
118
|
+
}
|
|
119
|
+
if (session.cancelReader) {
|
|
120
|
+
session.cancelReader();
|
|
121
|
+
session.cancelReader = undefined;
|
|
122
|
+
}
|
|
123
|
+
connection.activeStreams.delete(streamId);
|
|
124
|
+
}
|
|
106
125
|
function sendError(socket, requestId, code, message, details) {
|
|
107
126
|
const response = {
|
|
108
127
|
type: MessageType.RESPONSE_ERROR,
|
|
@@ -1362,8 +1381,7 @@ function handleStreamError(message, connection) {
|
|
|
1362
1381
|
}
|
|
1363
1382
|
const session = connection.activeStreams.get(message.streamId);
|
|
1364
1383
|
if (session) {
|
|
1365
|
-
|
|
1366
|
-
connection.activeStreams.delete(message.streamId);
|
|
1384
|
+
closeActiveDownloadSession(connection, message.streamId);
|
|
1367
1385
|
}
|
|
1368
1386
|
const callbackReceiver = connection.callbackStreamReceivers.get(message.streamId);
|
|
1369
1387
|
if (callbackReceiver && callbackReceiver.state === "active") {
|
|
@@ -1482,6 +1500,7 @@ function waitForCredit(session) {
|
|
|
1482
1500
|
});
|
|
1483
1501
|
}
|
|
1484
1502
|
async function sendStreamedResponse(connection, requestId, response) {
|
|
1503
|
+
const SEND_LOOP_YIELD_BYTES = 64 * 1024;
|
|
1485
1504
|
const streamId = connection.nextStreamId++;
|
|
1486
1505
|
const headers = [];
|
|
1487
1506
|
response.headers.forEach((value, key) => {
|
|
@@ -1517,38 +1536,61 @@ async function sendStreamedResponse(connection, requestId, response) {
|
|
|
1517
1536
|
};
|
|
1518
1537
|
connection.activeStreams.set(streamId, session);
|
|
1519
1538
|
const reader = response.body.getReader();
|
|
1539
|
+
session.cancelReader = () => {
|
|
1540
|
+
reader.cancel("Stream cancelled by client").catch(() => {});
|
|
1541
|
+
};
|
|
1542
|
+
let cancelledByClient = false;
|
|
1543
|
+
let bytesSinceYield = 0;
|
|
1544
|
+
let chunksSinceYield = 0;
|
|
1520
1545
|
try {
|
|
1521
|
-
|
|
1522
|
-
while (
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
const
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1546
|
+
streamLoop:
|
|
1547
|
+
while (true) {
|
|
1548
|
+
while (session.credit < STREAM_CHUNK_SIZE && session.state === "active") {
|
|
1549
|
+
await waitForCredit(session);
|
|
1550
|
+
}
|
|
1551
|
+
if (session.state !== "active") {
|
|
1552
|
+
cancelledByClient = true;
|
|
1553
|
+
break;
|
|
1554
|
+
}
|
|
1555
|
+
const { done, value } = await reader.read();
|
|
1556
|
+
if (done) {
|
|
1557
|
+
const endMsg = {
|
|
1558
|
+
type: MessageType.RESPONSE_STREAM_END,
|
|
1559
|
+
requestId,
|
|
1560
|
+
streamId
|
|
1561
|
+
};
|
|
1562
|
+
sendMessage(connection.socket, endMsg);
|
|
1563
|
+
break;
|
|
1564
|
+
}
|
|
1565
|
+
for (let offset = 0;offset < value.length; offset += STREAM_CHUNK_SIZE) {
|
|
1566
|
+
const chunk = value.slice(offset, offset + STREAM_CHUNK_SIZE);
|
|
1567
|
+
const chunkMsg = {
|
|
1568
|
+
type: MessageType.RESPONSE_STREAM_CHUNK,
|
|
1569
|
+
requestId,
|
|
1570
|
+
streamId,
|
|
1571
|
+
chunk
|
|
1572
|
+
};
|
|
1573
|
+
sendMessage(connection.socket, chunkMsg);
|
|
1574
|
+
const creditCost = Math.max(chunk.length, STREAM_CHUNK_SIZE);
|
|
1575
|
+
session.credit -= creditCost;
|
|
1576
|
+
session.bytesTransferred += chunk.length;
|
|
1577
|
+
bytesSinceYield += chunk.length;
|
|
1578
|
+
chunksSinceYield += 1;
|
|
1579
|
+
if (chunk.length < 1024 || bytesSinceYield >= SEND_LOOP_YIELD_BYTES || chunksSinceYield >= 256) {
|
|
1580
|
+
bytesSinceYield = 0;
|
|
1581
|
+
chunksSinceYield = 0;
|
|
1582
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
1583
|
+
if (session.state !== "active") {
|
|
1584
|
+
cancelledByClient = true;
|
|
1585
|
+
break streamLoop;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1549
1589
|
}
|
|
1550
|
-
}
|
|
1551
1590
|
} catch (err) {
|
|
1591
|
+
if (cancelledByClient || session.state !== "active") {
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1552
1594
|
const errorMsg = {
|
|
1553
1595
|
type: MessageType.STREAM_ERROR,
|
|
1554
1596
|
streamId,
|
|
@@ -1556,8 +1598,15 @@ async function sendStreamedResponse(connection, requestId, response) {
|
|
|
1556
1598
|
};
|
|
1557
1599
|
sendMessage(connection.socket, errorMsg);
|
|
1558
1600
|
} finally {
|
|
1601
|
+
if (cancelledByClient) {
|
|
1602
|
+
await Promise.race([
|
|
1603
|
+
reader.cancel("Stream cancelled by client").catch(() => {}),
|
|
1604
|
+
new Promise((resolve) => setTimeout(resolve, 50))
|
|
1605
|
+
]);
|
|
1606
|
+
}
|
|
1607
|
+
session.cancelReader = undefined;
|
|
1559
1608
|
reader.releaseLock();
|
|
1560
|
-
connection
|
|
1609
|
+
closeActiveDownloadSession(connection, streamId);
|
|
1561
1610
|
}
|
|
1562
1611
|
}
|
|
1563
1612
|
async function handleRunTests(message, connection, state) {
|
|
@@ -1677,4 +1726,4 @@ export {
|
|
|
1677
1726
|
handleConnection
|
|
1678
1727
|
};
|
|
1679
1728
|
|
|
1680
|
-
//# debugId=
|
|
1729
|
+
//# debugId=1FC256F121C44C4364756E2164756E21
|