@bytecodealliance/preview3-shim 0.3.1 → 0.4.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.
@@ -255,7 +255,13 @@ export class TcpSocket {
255
255
  }
256
256
  let stream;
257
257
  try {
258
- stream = readableByteStreamFromReader(data, { name: "tcp send data" });
258
+ // A remote error arrives from the TCP worker through a MessagePort. Yield
259
+ // after each chunk so a guest producer that completes writes immediately
260
+ // cannot starve that error (and its stream cancellation) indefinitely.
261
+ stream = readableByteStreamFromReader(data, {
262
+ name: "tcp send data",
263
+ yieldAfterChunk: true,
264
+ });
259
265
  }
260
266
  catch (error) {
261
267
  if (error instanceof TypeError) {
@@ -1,5 +1,10 @@
1
1
  export declare const DEFAULT_BYTE_STREAM_CHUNK_SIZE: number;
2
2
  declare const symbolDispose: symbol;
3
+ interface ReadableByteStreamOptions {
4
+ chunkSize?: number;
5
+ name?: string;
6
+ yieldAfterChunk?: boolean;
7
+ }
3
8
  /**
4
9
  * Creates a transferable ReadableStream from an async iterator.
5
10
  *
@@ -22,9 +27,10 @@ export declare function readableStreamFromIterator(iterator: any, name?: string)
22
27
  * @param {object} [opts={}] - Optional adapter settings.
23
28
  * @param {number} [opts.chunkSize=DEFAULT_BYTE_STREAM_CHUNK_SIZE] - Maximum bytes to request per generated `read()` call.
24
29
  * @param {string} [opts.name="stream reader"] - Reader name used in error messages.
30
+ * @param {boolean} [opts.yieldAfterChunk=false] - Yield one event-loop turn after each chunk.
25
31
  * @returns {ReadableStream<Uint8Array>} A transferable stream of byte chunks.
26
32
  */
27
- export declare function readableByteStreamFromReader(reader: any, opts?: {}): ReadableStream<any>;
33
+ export declare function readableByteStreamFromReader(reader: any, opts?: ReadableByteStreamOptions): ReadableStream<any>;
28
34
  export declare function _byteChunk(value: any): any;
29
35
  /**
30
36
  * Creates a bidirectional stream with separate reader and writer interfaces.
@@ -46,6 +46,7 @@ export function readableStreamFromIterator(iterator, name = "iterator") {
46
46
  * @param {object} [opts={}] - Optional adapter settings.
47
47
  * @param {number} [opts.chunkSize=DEFAULT_BYTE_STREAM_CHUNK_SIZE] - Maximum bytes to request per generated `read()` call.
48
48
  * @param {string} [opts.name="stream reader"] - Reader name used in error messages.
49
+ * @param {boolean} [opts.yieldAfterChunk=false] - Yield one event-loop turn after each chunk.
49
50
  * @returns {ReadableStream<Uint8Array>} A transferable stream of byte chunks.
50
51
  */
51
52
  export function readableByteStreamFromReader(reader, opts = {}) {
@@ -58,6 +59,9 @@ export function readableByteStreamFromReader(reader, opts = {}) {
58
59
  return;
59
60
  }
60
61
  controller.enqueue(_byteChunk(value));
62
+ if (opts.yieldAfterChunk) {
63
+ await new Promise((resolve) => setTimeout(resolve, 0));
64
+ }
61
65
  },
62
66
  cancel(reason) {
63
67
  return source.cancel?.(reason);
@@ -3,7 +3,6 @@ import { Readable } from "stream";
3
3
  import { pipeline } from "stream/promises";
4
4
  import { once } from "node:events";
5
5
  import { isMainThread, parentPort } from "worker_threads";
6
- import process from "node:process";
7
6
  //#region dist/nodejs/workers/resource-worker.js
8
7
  function Router() {
9
8
  const _hooks = {
@@ -255,7 +254,6 @@ var SocketError = class SocketError extends Error {
255
254
  };
256
255
  //#endregion
257
256
  //#region dist/nodejs/workers/tcp-worker.js
258
- const { TCP, constants: TCPConstants } = process.binding("tcp_wrap");
259
257
  const sockets = /* @__PURE__ */ new Map();
260
258
  let NEXT_SOCKET_ID = 0n;
261
259
  Router().beforeAll((msg) => {
@@ -263,14 +261,15 @@ Router().beforeAll((msg) => {
263
261
  }).op("tcp-create", handleTcpCreate).op("tcp-bind", handleTcpBind).op("tcp-connect", handleTcpConnect).op("tcp-listen", handleTcpListen).op("tcp-send", handleTcpSend).op("tcp-receive", handleTcpReceive).op("tcp-get-local-address", handleGetLocalAddress).op("tcp-get-remote-address", handleGetRemoteAddress).op("tcp-set-listen-backlog-size", handleTcpSetBacklogSize).op("tcp-set-keep-alive", handleTcpSetKeepAlive).op("tcp-recv-buffer-size", handleRecvBufferSize).op("tcp-send-buffer-size", handleSendBufferSize).op("tcp-dispose", handleTcpDispose);
264
262
  function handleTcpCreate({ family }) {
265
263
  const socketId = NEXT_SOCKET_ID++;
266
- const handle = new TCP(TCPConstants.SOCKET);
267
264
  sockets.set(socketId, {
268
- handle,
269
265
  family,
270
266
  tcp: null,
271
267
  server: null,
268
+ acceptWriter: null,
272
269
  backlog: 128,
273
270
  localAddress: null,
271
+ keepAliveEnabled: false,
272
+ keepAliveIdleTime: 0,
274
273
  disposed: false,
275
274
  activeStreams: 0
276
275
  });
@@ -280,80 +279,104 @@ async function handleTcpBind({ socketId, localAddress }) {
280
279
  const socket = sockets.get(socketId);
281
280
  const address = serializeIpAddress(localAddress);
282
281
  const port = localAddress.val.port;
283
- const { handle, family } = socket;
282
+ const { family } = socket;
284
283
  if ([...sockets].some(([id, { localAddress: boundAddress }]) => id !== socketId && boundAddress && ipAddressConflict(boundAddress, localAddress))) {
285
284
  const err = /* @__PURE__ */ new Error("EADDRINUSE");
286
285
  err.code = "EADDRINUSE";
287
286
  throw err;
288
287
  }
289
- await new Promise((resolve, reject) => {
290
- let code;
291
- if (family === "ipv6") code = handle.bind6(address, port, TCPConstants.UV_TCP_IPV6ONLY);
292
- else code = handle.bind(address, port);
293
- if (code !== 0) reject(SocketError.from(-code));
294
- else resolve();
288
+ const server = socket.server = createTcpServer(socket);
289
+ const onListening = once(server, "listening");
290
+ server.listen({
291
+ host: address,
292
+ port,
293
+ backlog: socket.backlog,
294
+ ipv6Only: family === "ipv6"
295
295
  });
296
- const out = {};
297
- const code = handle.getsockname(out);
298
- if (code !== 0) throw SocketError.from(-code);
299
- socket.localAddress = makeIpAddress(out.family.toLowerCase(), out.address, out.port);
296
+ await onListening;
297
+ const boundAddress = server.address();
298
+ if (!boundAddress || typeof boundAddress === "string") throw new SocketError("invalid-state");
299
+ socket.localAddress = makeIpAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
300
300
  }
301
301
  async function handleTcpConnect({ socketId, remoteAddress }) {
302
302
  const socket = sockets.get(socketId);
303
303
  const host = serializeIpAddress(remoteAddress);
304
304
  const port = remoteAddress.val.port;
305
- const tcp = socket.tcp = new Socket({
306
- handle: socket.handle,
307
- pauseOnCreate: true,
308
- allowHalfOpen: true
309
- });
305
+ const localAddress = socket.localAddress;
306
+ await closeTcpServer(socket);
307
+ const tcp = socket.tcp = new Socket({ allowHalfOpen: true });
308
+ tcp.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
310
309
  const onConnect = once(tcp, "connect");
311
- const onError = once(tcp, "error").then(([err]) => {
312
- throw err;
313
- });
314
310
  tcp.connect({
315
311
  port,
316
- host
312
+ host,
313
+ localAddress: localAddress ? serializeIpAddress(localAddress) : void 0,
314
+ localPort: localAddress?.val.port
317
315
  });
318
- await Promise.race([onConnect, onError]);
316
+ await onConnect;
319
317
  }
320
318
  async function handleTcpListen({ socketId, stream }) {
321
319
  const writer = stream.getWriter();
322
320
  const socket = sockets.get(socketId);
323
- const { handle, backlog, family } = socket;
321
+ const { backlog, family } = socket;
322
+ socket.acceptWriter = writer;
323
+ let server = socket.server;
324
+ if (!server) {
325
+ server = socket.server = createTcpServer(socket);
326
+ const onListening = once(server, "listening");
327
+ server.listen({
328
+ host: family === "ipv6" ? "::" : "0.0.0.0",
329
+ port: 0,
330
+ backlog,
331
+ ipv6Only: family === "ipv6"
332
+ });
333
+ await onListening;
334
+ }
335
+ const addr = server.address();
336
+ if (addr && typeof addr === "object") socket.localAddress = makeIpAddress(family, addr.address, addr.port);
337
+ }
338
+ function createTcpServer(socket) {
324
339
  const server = new Server({
325
340
  pauseOnConnect: true,
326
341
  allowHalfOpen: true
327
342
  });
328
- const onListening = once(server, "listening");
329
- const onError = once(server, "error").then(([err]) => {
330
- throw err;
331
- });
332
- server.listen(handle, backlog);
333
- await Promise.race([onListening, onError]);
334
- const addr = server.address();
335
- if (addr && typeof addr === "object") socket.localAddress = makeIpAddress(family, addr.address, addr.port);
336
343
  server.on("connection", (conn) => {
344
+ const writer = socket.acceptWriter;
345
+ if (!writer) {
346
+ conn.destroy();
347
+ return;
348
+ }
337
349
  conn.allowHalfOpen = true;
350
+ conn.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
338
351
  const id = NEXT_SOCKET_ID++;
339
352
  sockets.set(id, {
340
- handle: conn._handle,
341
- family,
342
- backlog,
353
+ family: socket.family,
354
+ backlog: socket.backlog,
343
355
  tcp: conn,
344
356
  server: null,
345
- localAddress: makeIpAddress(family, conn.localAddress, conn.localPort),
357
+ acceptWriter: null,
358
+ localAddress: makeIpAddress(socket.family, conn.localAddress, conn.localPort),
359
+ keepAliveEnabled: socket.keepAliveEnabled,
360
+ keepAliveIdleTime: socket.keepAliveIdleTime,
346
361
  disposed: false,
347
362
  activeStreams: 0
348
363
  });
349
364
  writer.write({
350
- family,
365
+ family: socket.family,
351
366
  socketId: id
352
367
  });
353
368
  });
354
- socket.server = server;
355
- server.on("error", (err) => stream.abort(err));
356
- server.on("close", () => writer.close());
369
+ server.on("error", (err) => socket.acceptWriter?.abort(err));
370
+ server.on("close", () => socket.acceptWriter?.close());
371
+ return server;
372
+ }
373
+ function closeTcpServer(socket) {
374
+ const server = socket.server;
375
+ socket.server = null;
376
+ if (!server) return Promise.resolve();
377
+ return new Promise((resolve, reject) => {
378
+ server.close((err) => err ? reject(err) : resolve());
379
+ });
357
380
  }
358
381
  async function handleTcpSend({ socketId, stream }) {
359
382
  const socket = sockets.get(socketId);
@@ -428,22 +451,19 @@ function cleanupDisposedSocket(socketId, socket) {
428
451
  if (!socket.disposed || socket.activeStreams > 0) return;
429
452
  if (socket.server) socket.server.close();
430
453
  if (socket.tcp) socket.tcp.destroy();
431
- if (socket.handle) socket.handle.close();
432
454
  sockets.delete(socketId);
433
455
  }
434
456
  async function handleGetLocalAddress({ socketId }) {
435
457
  const socket = sockets.get(socketId);
436
- const out = {};
437
- const code = socket.handle.getsockname(out);
438
- if (code !== 0) throw SocketError.from(-code);
439
- return makeIpAddress(out.family.toLowerCase(), out.address, out.port);
458
+ const address = socket.tcp?.address();
459
+ if (address && typeof address !== "string" && "family" in address) return makeIpAddress(address.family.toLowerCase(), address.address, address.port);
460
+ if (socket.localAddress) return socket.localAddress;
461
+ throw new SocketError("invalid-state");
440
462
  }
441
463
  async function handleGetRemoteAddress({ socketId }) {
442
464
  const socket = sockets.get(socketId);
443
- const out = {};
444
- const code = socket.handle.getpeername(out);
445
- if (code !== 0) throw SocketError.from(-code);
446
- return makeIpAddress(out.family.toLowerCase(), out.address, out.port);
465
+ if (!socket.tcp?.remoteFamily || !socket.tcp.remoteAddress || !socket.tcp.remotePort) throw new SocketError("invalid-state");
466
+ return makeIpAddress(socket.tcp.remoteFamily.toLowerCase(), socket.tcp.remoteAddress, socket.tcp.remotePort);
447
467
  }
448
468
  function handleTcpSetBacklogSize({ socketId, value }) {
449
469
  const socket = sockets.get(socketId);
@@ -451,9 +471,9 @@ function handleTcpSetBacklogSize({ socketId, value }) {
451
471
  }
452
472
  async function handleTcpSetKeepAlive({ socketId, keepAliveEnabled, keepAliveIdleTime }) {
453
473
  const socket = sockets.get(socketId);
454
- const time = Number(keepAliveIdleTime / 1000000000n);
455
- const code = socket.handle.setKeepAlive(keepAliveEnabled, time);
456
- if (code !== 0) throw SocketError.from(-code);
474
+ socket.keepAliveEnabled = keepAliveEnabled;
475
+ socket.keepAliveIdleTime = Number(keepAliveIdleTime / 1000000000n);
476
+ socket.tcp?.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
457
477
  }
458
478
  async function handleRecvBufferSize({ socketId }) {
459
479
  const socket = sockets.get(socketId);
@@ -5,8 +5,6 @@ import { once } from "node:events";
5
5
  import { Router } from "../workers/resource-worker.js";
6
6
  import { serializeIpAddress, makeIpAddress, ipAddressConflict } from "../sockets/address.js";
7
7
  import { SocketError } from "../sockets/error.js";
8
- import process from "node:process";
9
- const { TCP, constants: TCPConstants } = process.binding("tcp_wrap");
10
8
  // Socket instances stored by ID
11
9
  const sockets = new Map();
12
10
  // Unique IDs for sockets
@@ -34,14 +32,15 @@ Router()
34
32
  // Create a new TCP socket
35
33
  function handleTcpCreate({ family }) {
36
34
  const socketId = NEXT_SOCKET_ID++;
37
- const handle = new TCP(TCPConstants.SOCKET);
38
35
  sockets.set(socketId, {
39
- handle,
40
36
  family,
41
37
  tcp: null,
42
38
  server: null,
39
+ acceptWriter: null,
43
40
  backlog: 128,
44
41
  localAddress: null,
42
+ keepAliveEnabled: false,
43
+ keepAliveIdleTime: 0,
45
44
  disposed: false,
46
45
  activeStreams: 0,
47
46
  });
@@ -52,89 +51,120 @@ async function handleTcpBind({ socketId, localAddress }) {
52
51
  const socket = sockets.get(socketId);
53
52
  const address = serializeIpAddress(localAddress);
54
53
  const port = localAddress.val.port;
55
- const { handle, family } = socket;
54
+ const { family } = socket;
56
55
  const hasConflict = [...sockets].some(([id, { localAddress: boundAddress }]) => id !== socketId && boundAddress && ipAddressConflict(boundAddress, localAddress));
57
56
  if (hasConflict) {
58
57
  const err = new Error("EADDRINUSE");
59
58
  err.code = "EADDRINUSE";
60
59
  throw err;
61
60
  }
62
- await new Promise((resolve, reject) => {
63
- let code;
64
- if (family === "ipv6") {
65
- code = handle.bind6(address, port, TCPConstants.UV_TCP_IPV6ONLY);
66
- }
67
- else {
68
- code = handle.bind(address, port);
69
- }
70
- if (code !== 0) {
71
- reject(SocketError.from(-code));
72
- }
73
- else {
74
- resolve();
75
- }
61
+ // node:net has no public standalone TCP bind API. Keep a server open
62
+ // to reserve the endpoint, then reuse it for listen or close it for connect.
63
+ const server = (socket.server = createTcpServer(socket));
64
+ const onListening = once(server, "listening");
65
+ server.listen({
66
+ host: address,
67
+ port,
68
+ backlog: socket.backlog,
69
+ ipv6Only: family === "ipv6",
76
70
  });
77
- const out = {};
78
- const code = handle.getsockname(out);
79
- if (code !== 0) {
80
- throw SocketError.from(-code);
71
+ await onListening;
72
+ const boundAddress = server.address();
73
+ if (!boundAddress || typeof boundAddress === "string") {
74
+ throw new SocketError("invalid-state");
81
75
  }
82
- socket.localAddress = makeIpAddress(out.family.toLowerCase(), out.address, out.port);
76
+ socket.localAddress = makeIpAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
83
77
  }
84
78
  // Connect a socket to remote address
85
79
  async function handleTcpConnect({ socketId, remoteAddress }) {
86
80
  const socket = sockets.get(socketId);
87
81
  const host = serializeIpAddress(remoteAddress);
88
82
  const port = remoteAddress.val.port;
83
+ const localAddress = socket.localAddress;
84
+ await closeTcpServer(socket);
89
85
  const tcp = (socket.tcp = new Socket({
90
- handle: socket.handle,
91
- pauseOnCreate: true,
92
86
  allowHalfOpen: true,
93
87
  }));
88
+ tcp.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
89
+ // TODO(tandr): Add lookup
94
90
  const onConnect = once(tcp, "connect");
95
- const onError = once(tcp, "error").then(([err]) => {
96
- throw err;
91
+ tcp.connect({
92
+ port,
93
+ host,
94
+ localAddress: localAddress ? serializeIpAddress(localAddress) : undefined,
95
+ localPort: localAddress?.val.port,
97
96
  });
98
- // TODO(tandr): Add lookup
99
- tcp.connect({ port, host });
100
- await Promise.race([onConnect, onError]);
97
+ // events.once rejects when the emitter produces an error while waiting and
98
+ // removes its temporary listeners after settling. A separate error promise
99
+ // would remain attached after a successful connect and could later reject
100
+ // unobserved when an established connection is reset.
101
+ await onConnect;
101
102
  }
102
103
  async function handleTcpListen({ socketId, stream }) {
103
104
  const writer = stream.getWriter();
104
105
  const socket = sockets.get(socketId);
105
- const { handle, backlog, family } = socket;
106
- const server = new Server({
107
- pauseOnConnect: true,
108
- allowHalfOpen: true,
109
- });
110
- const onListening = once(server, "listening");
111
- const onError = once(server, "error").then(([err]) => {
112
- throw err;
113
- });
114
- server.listen(handle, backlog);
115
- await Promise.race([onListening, onError]);
106
+ const { backlog, family } = socket;
107
+ socket.acceptWriter = writer;
108
+ let server = socket.server;
109
+ if (!server) {
110
+ server = socket.server = createTcpServer(socket);
111
+ const onListening = once(server, "listening");
112
+ server.listen({
113
+ host: family === "ipv6" ? "::" : "0.0.0.0",
114
+ port: 0,
115
+ backlog,
116
+ ipv6Only: family === "ipv6",
117
+ });
118
+ await onListening;
119
+ }
116
120
  const addr = server.address();
117
121
  if (addr && typeof addr === "object") {
118
122
  socket.localAddress = makeIpAddress(family, addr.address, addr.port);
119
123
  }
124
+ }
125
+ function createTcpServer(socket) {
126
+ const server = new Server({
127
+ pauseOnConnect: true,
128
+ allowHalfOpen: true,
129
+ });
120
130
  server.on("connection", (conn) => {
131
+ const writer = socket.acceptWriter;
132
+ // The reservation is already listening at the OS level, so reject any
133
+ // connections that arrive before the WASI socket enters its listen state.
134
+ if (!writer) {
135
+ conn.destroy();
136
+ return;
137
+ }
121
138
  conn.allowHalfOpen = true;
139
+ conn.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
122
140
  const id = NEXT_SOCKET_ID++;
123
141
  sockets.set(id, {
124
- handle: conn._handle,
125
- family,
126
- backlog,
142
+ family: socket.family,
143
+ backlog: socket.backlog,
127
144
  tcp: conn,
128
145
  server: null,
129
- localAddress: makeIpAddress(family, conn.localAddress, conn.localPort),
146
+ acceptWriter: null,
147
+ localAddress: makeIpAddress(socket.family, conn.localAddress, conn.localPort),
148
+ keepAliveEnabled: socket.keepAliveEnabled,
149
+ keepAliveIdleTime: socket.keepAliveIdleTime,
130
150
  disposed: false,
131
151
  activeStreams: 0,
132
152
  });
133
- writer.write({ family, socketId: id });
153
+ writer.write({ family: socket.family, socketId: id });
154
+ });
155
+ server.on("error", (err) => socket.acceptWriter?.abort(err));
156
+ server.on("close", () => socket.acceptWriter?.close());
157
+ return server;
158
+ }
159
+ function closeTcpServer(socket) {
160
+ const server = socket.server;
161
+ socket.server = null;
162
+ if (!server) {
163
+ return Promise.resolve();
164
+ }
165
+ return new Promise((resolve, reject) => {
166
+ server.close((err) => (err ? reject(err) : resolve()));
134
167
  });
135
- socket.server = server;
136
- server.on("error", (err) => stream.abort(err));
137
- server.on("close", () => writer.close());
138
168
  }
139
169
  async function handleTcpSend({ socketId, stream }) {
140
170
  const socket = sockets.get(socketId);
@@ -231,28 +261,25 @@ function cleanupDisposedSocket(socketId, socket) {
231
261
  if (socket.tcp) {
232
262
  socket.tcp.destroy();
233
263
  }
234
- if (socket.handle) {
235
- socket.handle.close();
236
- }
237
264
  sockets.delete(socketId);
238
265
  }
239
266
  async function handleGetLocalAddress({ socketId }) {
240
267
  const socket = sockets.get(socketId);
241
- const out = {};
242
- const code = socket.handle.getsockname(out);
243
- if (code !== 0) {
244
- throw SocketError.from(-code);
268
+ const address = socket.tcp?.address();
269
+ if (address && typeof address !== "string" && "family" in address) {
270
+ return makeIpAddress(address.family.toLowerCase(), address.address, address.port);
245
271
  }
246
- return makeIpAddress(out.family.toLowerCase(), out.address, out.port);
272
+ if (socket.localAddress) {
273
+ return socket.localAddress;
274
+ }
275
+ throw new SocketError("invalid-state");
247
276
  }
248
277
  async function handleGetRemoteAddress({ socketId }) {
249
278
  const socket = sockets.get(socketId);
250
- const out = {};
251
- const code = socket.handle.getpeername(out);
252
- if (code !== 0) {
253
- throw SocketError.from(-code);
279
+ if (!socket.tcp?.remoteFamily || !socket.tcp.remoteAddress || !socket.tcp.remotePort) {
280
+ throw new SocketError("invalid-state");
254
281
  }
255
- return makeIpAddress(out.family.toLowerCase(), out.address, out.port);
282
+ return makeIpAddress(socket.tcp.remoteFamily.toLowerCase(), socket.tcp.remoteAddress, socket.tcp.remotePort);
256
283
  }
257
284
  function handleTcpSetBacklogSize({ socketId, value }) {
258
285
  const socket = sockets.get(socketId);
@@ -260,11 +287,9 @@ function handleTcpSetBacklogSize({ socketId, value }) {
260
287
  }
261
288
  async function handleTcpSetKeepAlive({ socketId, keepAliveEnabled, keepAliveIdleTime }) {
262
289
  const socket = sockets.get(socketId);
263
- const time = Number(keepAliveIdleTime / 1000000000n);
264
- const code = socket.handle.setKeepAlive(keepAliveEnabled, time);
265
- if (code !== 0) {
266
- throw SocketError.from(-code);
267
- }
290
+ socket.keepAliveEnabled = keepAliveEnabled;
291
+ socket.keepAliveIdleTime = Number(keepAliveIdleTime / 1000000000n);
292
+ socket.tcp?.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
268
293
  }
269
294
  async function handleRecvBufferSize({ socketId }) {
270
295
  const socket = sockets.get(socketId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/preview3-shim",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
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": {
@@ -48,7 +48,7 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@bytecodealliance/preview2-shim": "^0.19.0"
51
+ "@bytecodealliance/preview2-shim": "^0.21.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^24.12.4",