@bytecodealliance/preview3-shim 0.6.0 → 0.6.1
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Server, Socket } from "node:net";
|
|
1
|
+
import net, { Server, Socket } from "node:net";
|
|
2
2
|
import { once } from "node:events";
|
|
3
3
|
import { isMainThread, parentPort } from "worker_threads";
|
|
4
4
|
//#region dist/nodejs/workers/resource-worker.js
|
|
@@ -252,6 +252,7 @@ var SocketError = class SocketError extends Error {
|
|
|
252
252
|
};
|
|
253
253
|
//#endregion
|
|
254
254
|
//#region dist/nodejs/workers/tcp-worker.js
|
|
255
|
+
const BoundSocket = net.BoundSocket;
|
|
255
256
|
const sockets = /* @__PURE__ */ new Map();
|
|
256
257
|
let NEXT_SOCKET_ID = 0n;
|
|
257
258
|
Router().beforeAll((msg) => {
|
|
@@ -263,6 +264,7 @@ function handleTcpCreate({ family }) {
|
|
|
263
264
|
family,
|
|
264
265
|
tcp: null,
|
|
265
266
|
server: null,
|
|
267
|
+
bound: null,
|
|
266
268
|
acceptWriter: null,
|
|
267
269
|
backlog: 128,
|
|
268
270
|
localAddress: null,
|
|
@@ -283,6 +285,17 @@ async function handleTcpBind({ socketId, localAddress }) {
|
|
|
283
285
|
err.code = "EADDRINUSE";
|
|
284
286
|
throw err;
|
|
285
287
|
}
|
|
288
|
+
if (BoundSocket) {
|
|
289
|
+
const bound = new BoundSocket({
|
|
290
|
+
host: address,
|
|
291
|
+
port,
|
|
292
|
+
ipv6Only: family === "ipv6"
|
|
293
|
+
});
|
|
294
|
+
const boundAddress = bound.address();
|
|
295
|
+
socket.bound = bound;
|
|
296
|
+
socket.localAddress = makeIpAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
286
299
|
const server = socket.server = createTcpServer(socket);
|
|
287
300
|
const onListening = once(server, "listening");
|
|
288
301
|
server.listen({
|
|
@@ -300,16 +313,20 @@ async function handleTcpConnect({ socketId, remoteAddress }) {
|
|
|
300
313
|
const socket = sockets.get(socketId);
|
|
301
314
|
const host = serializeIpAddress(remoteAddress);
|
|
302
315
|
const port = remoteAddress.val.port;
|
|
303
|
-
const localAddress = socket
|
|
316
|
+
const { bound, localAddress } = socket;
|
|
317
|
+
socket.bound = null;
|
|
304
318
|
await closeTcpServer(socket);
|
|
305
|
-
const tcp = socket.tcp = new Socket({
|
|
319
|
+
const tcp = socket.tcp = new Socket({
|
|
320
|
+
handle: bound ?? void 0,
|
|
321
|
+
allowHalfOpen: true
|
|
322
|
+
});
|
|
306
323
|
tcp.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
307
324
|
const onConnect = once(tcp, "connect");
|
|
308
325
|
tcp.connect({
|
|
309
326
|
port,
|
|
310
327
|
host,
|
|
311
|
-
localAddress: localAddress ? serializeIpAddress(localAddress) : void 0,
|
|
312
|
-
localPort: localAddress?.val.port
|
|
328
|
+
localAddress: !bound && localAddress ? serializeIpAddress(localAddress) : void 0,
|
|
329
|
+
localPort: !bound ? localAddress?.val.port : void 0
|
|
313
330
|
});
|
|
314
331
|
await onConnect;
|
|
315
332
|
}
|
|
@@ -322,7 +339,13 @@ async function handleTcpListen({ socketId, stream }) {
|
|
|
322
339
|
if (!server) {
|
|
323
340
|
server = socket.server = createTcpServer(socket);
|
|
324
341
|
const onListening = once(server, "listening");
|
|
325
|
-
|
|
342
|
+
const bound = socket.bound;
|
|
343
|
+
socket.bound = null;
|
|
344
|
+
if (bound) server.listen({
|
|
345
|
+
handle: bound,
|
|
346
|
+
backlog
|
|
347
|
+
});
|
|
348
|
+
else server.listen({
|
|
326
349
|
host: family === "ipv6" ? "::" : "0.0.0.0",
|
|
327
350
|
port: 0,
|
|
328
351
|
backlog,
|
|
@@ -352,6 +375,7 @@ function createTcpServer(socket) {
|
|
|
352
375
|
backlog: socket.backlog,
|
|
353
376
|
tcp: conn,
|
|
354
377
|
server: null,
|
|
378
|
+
bound: null,
|
|
355
379
|
acceptWriter: null,
|
|
356
380
|
localAddress: makeIpAddress(socket.family, conn.localAddress, conn.localPort),
|
|
357
381
|
keepAliveEnabled: socket.keepAliveEnabled,
|
|
@@ -466,6 +490,10 @@ async function handleTcpReceive({ socketId, stream }) {
|
|
|
466
490
|
}
|
|
467
491
|
function cleanupDisposedSocket(socketId, socket) {
|
|
468
492
|
if (!socket.disposed || socket.activeStreams > 0) return;
|
|
493
|
+
if (socket.bound) {
|
|
494
|
+
socket.bound.close();
|
|
495
|
+
socket.bound = null;
|
|
496
|
+
}
|
|
469
497
|
if (socket.server) socket.server.close();
|
|
470
498
|
if (socket.tcp) socket.tcp.destroy();
|
|
471
499
|
sockets.delete(socketId);
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { Socket, Server } from "node:net";
|
|
1
|
+
import net, { Socket, Server } from "node:net";
|
|
2
2
|
import { once } from "node:events";
|
|
3
3
|
import { Router } from "../workers/resource-worker.js";
|
|
4
4
|
import { serializeIpAddress, makeIpAddress, ipAddressConflict } from "../sockets/address.js";
|
|
5
5
|
import { SocketError } from "../sockets/error.js";
|
|
6
|
+
// node:net gained a standalone bind API in v26.4 (also on v24.x). It holds the
|
|
7
|
+
// endpoint with a real bind(2) until a Socket or Server adopts it, so connect and
|
|
8
|
+
// listen never have to release the port and reacquire it. Older releases fall
|
|
9
|
+
// back to reserving the endpoint with a listening server.
|
|
10
|
+
const BoundSocket = net.BoundSocket;
|
|
6
11
|
// Socket instances stored by ID
|
|
7
12
|
const sockets = new Map();
|
|
8
13
|
// Unique IDs for sockets
|
|
@@ -34,6 +39,7 @@ function handleTcpCreate({ family }) {
|
|
|
34
39
|
family,
|
|
35
40
|
tcp: null,
|
|
36
41
|
server: null,
|
|
42
|
+
bound: null,
|
|
37
43
|
acceptWriter: null,
|
|
38
44
|
backlog: 128,
|
|
39
45
|
localAddress: null,
|
|
@@ -56,8 +62,15 @@ async function handleTcpBind({ socketId, localAddress }) {
|
|
|
56
62
|
err.code = "EADDRINUSE";
|
|
57
63
|
throw err;
|
|
58
64
|
}
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
if (BoundSocket) {
|
|
66
|
+
const bound = new BoundSocket({ host: address, port, ipv6Only: family === "ipv6" });
|
|
67
|
+
const boundAddress = bound.address();
|
|
68
|
+
socket.bound = bound;
|
|
69
|
+
socket.localAddress = makeIpAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Without a standalone bind API, keep a server open to reserve the endpoint,
|
|
73
|
+
// then reuse it for listen or close it for connect.
|
|
61
74
|
const server = (socket.server = createTcpServer(socket));
|
|
62
75
|
const onListening = once(server, "listening");
|
|
63
76
|
server.listen({
|
|
@@ -78,19 +91,24 @@ async function handleTcpConnect({ socketId, remoteAddress }) {
|
|
|
78
91
|
const socket = sockets.get(socketId);
|
|
79
92
|
const host = serializeIpAddress(remoteAddress);
|
|
80
93
|
const port = remoteAddress.val.port;
|
|
81
|
-
const localAddress = socket
|
|
94
|
+
const { bound, localAddress } = socket;
|
|
95
|
+
socket.bound = null;
|
|
82
96
|
await closeTcpServer(socket);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
// An adopted bound handle already owns the local endpoint, so the connect
|
|
98
|
+
// must not name it again. Without one, the reservation server released the
|
|
99
|
+
// endpoint just above and the client re-binds it here.
|
|
100
|
+
// @types/node does not yet declare the `handle` option, so it is passed via a
|
|
101
|
+
// variable to skip the object literal excess property check.
|
|
102
|
+
const socketOptions = { handle: bound ?? undefined, allowHalfOpen: true };
|
|
103
|
+
const tcp = (socket.tcp = new Socket(socketOptions));
|
|
86
104
|
tcp.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
87
105
|
// TODO(tandr): Add lookup
|
|
88
106
|
const onConnect = once(tcp, "connect");
|
|
89
107
|
tcp.connect({
|
|
90
108
|
port,
|
|
91
109
|
host,
|
|
92
|
-
localAddress: localAddress ? serializeIpAddress(localAddress) : undefined,
|
|
93
|
-
localPort: localAddress?.val.port,
|
|
110
|
+
localAddress: !bound && localAddress ? serializeIpAddress(localAddress) : undefined,
|
|
111
|
+
localPort: !bound ? localAddress?.val.port : undefined,
|
|
94
112
|
});
|
|
95
113
|
// events.once rejects when the emitter produces an error while waiting and
|
|
96
114
|
// removes its temporary listeners after settling. A separate error promise
|
|
@@ -107,12 +125,19 @@ async function handleTcpListen({ socketId, stream }) {
|
|
|
107
125
|
if (!server) {
|
|
108
126
|
server = socket.server = createTcpServer(socket);
|
|
109
127
|
const onListening = once(server, "listening");
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
backlog
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
const bound = socket.bound;
|
|
129
|
+
socket.bound = null;
|
|
130
|
+
if (bound) {
|
|
131
|
+
server.listen({ handle: bound, backlog });
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
server.listen({
|
|
135
|
+
host: family === "ipv6" ? "::" : "0.0.0.0",
|
|
136
|
+
port: 0,
|
|
137
|
+
backlog,
|
|
138
|
+
ipv6Only: family === "ipv6",
|
|
139
|
+
});
|
|
140
|
+
}
|
|
116
141
|
await onListening;
|
|
117
142
|
}
|
|
118
143
|
const addr = server.address();
|
|
@@ -141,6 +166,7 @@ function createTcpServer(socket) {
|
|
|
141
166
|
backlog: socket.backlog,
|
|
142
167
|
tcp: conn,
|
|
143
168
|
server: null,
|
|
169
|
+
bound: null,
|
|
144
170
|
acceptWriter: null,
|
|
145
171
|
localAddress: makeIpAddress(socket.family, conn.localAddress, conn.localPort),
|
|
146
172
|
keepAliveEnabled: socket.keepAliveEnabled,
|
|
@@ -286,6 +312,10 @@ function cleanupDisposedSocket(socketId, socket) {
|
|
|
286
312
|
if (!socket.disposed || socket.activeStreams > 0) {
|
|
287
313
|
return;
|
|
288
314
|
}
|
|
315
|
+
if (socket.bound) {
|
|
316
|
+
socket.bound.close();
|
|
317
|
+
socket.bound = null;
|
|
318
|
+
}
|
|
289
319
|
if (socket.server) {
|
|
290
320
|
socket.server.close();
|
|
291
321
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytecodealliance/preview3-shim",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "WASI Preview3 shim for JS environments",
|
|
5
5
|
"homepage": "https://github.com/bytecodealliance/jco/blob/main/packages/preview3-shim/#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@bytecodealliance/jco-node-fs": "0.3.2",
|
|
52
|
-
"@bytecodealliance/preview2-shim": "^0.
|
|
52
|
+
"@bytecodealliance/preview2-shim": "^0.25.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^24.12.4",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"rolldown": "^1.2.4",
|
|
58
58
|
"typescript": "7.0.2",
|
|
59
59
|
"vite": "^8.0.16",
|
|
60
|
-
"vitest": "^4.1.
|
|
60
|
+
"vitest": "^4.1.11"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsc --project tsconfig.build.json && node scripts/build-workers.mjs",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"lint": "oxlint",
|
|
69
69
|
"lint:fix": "oxlint --fix",
|
|
70
70
|
"pretest": "pnpm run build",
|
|
71
|
-
"test": "vitest --run",
|
|
71
|
+
"test": "vitest --run -c test/vitest.ts",
|
|
72
72
|
"prebench": "pnpm run build",
|
|
73
73
|
"bench": "vitest bench --run"
|
|
74
74
|
}
|