@bytecodealliance/preview3-shim 0.6.0 → 0.7.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.
Files changed (41) hide show
  1. package/README.md +9 -2
  2. package/dist/browser/cli/environment.d.ts +1 -0
  3. package/dist/browser/cli/environment.js +9 -4
  4. package/dist/browser/cli/exit.js +4 -3
  5. package/dist/browser/cli/run.d.ts +2 -0
  6. package/dist/browser/cli/run.js +11 -3
  7. package/dist/browser/cli/stderr.js +10 -3
  8. package/dist/browser/cli/stdin.js +3 -2
  9. package/dist/browser/cli/stdout.js +10 -3
  10. package/dist/browser/cli/terminal-stderr.js +2 -2
  11. package/dist/browser/cli/terminal-stdin.js +2 -2
  12. package/dist/browser/cli/terminal-stdout.js +2 -2
  13. package/dist/browser/cli.d.ts +3 -0
  14. package/dist/browser/cli.js +3 -0
  15. package/dist/browser/clocks/monotonic-clock.js +7 -7
  16. package/dist/browser/clocks/system-clock.js +4 -3
  17. package/dist/browser/filesystem/preopens.js +3 -2
  18. package/dist/browser/filesystem/types.d.ts +44 -1
  19. package/dist/browser/filesystem/types.js +139 -50
  20. package/dist/browser/filesystem.d.ts +13 -0
  21. package/dist/browser/filesystem.js +20 -0
  22. package/dist/browser/http/client.d.ts +2 -2
  23. package/dist/browser/http/client.js +138 -3
  24. package/dist/browser/http/handler.d.ts +4 -0
  25. package/dist/browser/http/handler.js +11 -3
  26. package/dist/browser/http/types.d.ts +44 -22
  27. package/dist/browser/http/types.js +192 -50
  28. package/dist/browser/http.d.ts +3 -0
  29. package/dist/browser/http.js +3 -0
  30. package/dist/browser/sockets/ip-name-lookup.js +34 -3
  31. package/dist/browser/sockets/types.d.ts +15 -0
  32. package/dist/browser/sockets/types.js +241 -49
  33. package/dist/browser/sockets.d.ts +2 -0
  34. package/dist/browser/sockets.js +2 -0
  35. package/dist/browser/streams.d.ts +20 -0
  36. package/dist/browser/streams.js +106 -0
  37. package/dist/nodejs/workers/tcp-worker.bundle.js +34 -6
  38. package/dist/nodejs/workers/tcp-worker.js +45 -15
  39. package/package.json +5 -5
  40. package/dist/common/errors.d.ts +0 -3
  41. package/dist/common/errors.js +0 -5
@@ -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
- // node:net has no public standalone TCP bind API. Keep a server open
60
- // to reserve the endpoint, then reuse it for listen or close it for connect.
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.localAddress;
94
+ const { bound, localAddress } = socket;
95
+ socket.bound = null;
82
96
  await closeTcpServer(socket);
83
- const tcp = (socket.tcp = new Socket({
84
- allowHalfOpen: true,
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
- server.listen({
111
- host: family === "ipv6" ? "::" : "0.0.0.0",
112
- port: 0,
113
- backlog,
114
- ipv6Only: family === "ipv6",
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.0",
3
+ "version": "0.7.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": {
@@ -49,15 +49,16 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@bytecodealliance/jco-node-fs": "0.3.2",
52
- "@bytecodealliance/preview2-shim": "^0.24.1"
52
+ "@bytecodealliance/preview2-shim": "^0.26.0"
53
53
  },
54
54
  "devDependencies": {
55
+ "@bytecodealliance/jco": "1.25.2",
55
56
  "@types/node": "^24.12.4",
56
57
  "globals": "^17.6.0",
57
58
  "rolldown": "^1.2.4",
58
59
  "typescript": "7.0.2",
59
60
  "vite": "^8.0.16",
60
- "vitest": "^4.1.10"
61
+ "vitest": "^4.1.11"
61
62
  },
62
63
  "scripts": {
63
64
  "build": "tsc --project tsconfig.build.json && node scripts/build-workers.mjs",
@@ -67,8 +68,7 @@
67
68
  "fmt:check": "oxfmt --check",
68
69
  "lint": "oxlint",
69
70
  "lint:fix": "oxlint --fix",
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
  }
@@ -1,3 +0,0 @@
1
- export declare class Todo extends Error {
2
- constructor();
3
- }
@@ -1,5 +0,0 @@
1
- export class Todo extends Error {
2
- constructor() {
3
- super("TODO: not yet implemented");
4
- }
5
- }