@bytecodealliance/preview2-shim 0.22.0 → 0.24.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.
@@ -1,3 +1,4 @@
1
+ import { checkedU64AsNumber } from "./common.js";
1
2
  const MAX_BYTES = 65536;
2
3
  let insecureRandomValue1, insecureRandomValue2;
3
4
  export const insecure = {
@@ -20,11 +21,12 @@ export const insecureSeed = {
20
21
  };
21
22
  export const random = {
22
23
  getRandomBytes(len) {
23
- const bytes = new Uint8Array(Number(len));
24
- if (len > MAX_BYTES) {
24
+ const byteLength = checkedU64AsNumber(len, "random byte length");
25
+ const bytes = new Uint8Array(byteLength);
26
+ if (byteLength > MAX_BYTES) {
25
27
  // this is the max bytes crypto.getRandomValues
26
28
  // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues
27
- for (var generated = 0; generated < len; generated += MAX_BYTES) {
29
+ for (let generated = 0; generated < byteLength; generated += MAX_BYTES) {
28
30
  // buffer.slice automatically checks if the end is past the end of
29
31
  // the buffer so we don't have to here
30
32
  crypto.getRandomValues(bytes.subarray(generated, generated + MAX_BYTES));
@@ -1,7 +1,8 @@
1
1
  import type { instanceNetwork as InstanceNetworkNamespace, ipNameLookup as IpNameLookupNamespace, network as NetworkNamespace, tcpCreateSocket as TcpCreateSocketNamespace, tcp as TcpNamespace, udpCreateSocket as UdpCreateSocketNamespace, udp as UdpNamespace } from "../../types/sockets.js";
2
+ export { InMemoryTcpClient, InMemoryTcpSockets, InMemoryUdpClient, InMemoryUdpSockets, } from "./in-memory-sockets.js";
2
3
  export declare const instanceNetwork: typeof InstanceNetworkNamespace;
3
- export declare const ipNameLookup: typeof IpNameLookupNamespace;
4
4
  export declare const network: typeof NetworkNamespace;
5
+ export declare const ipNameLookup: typeof IpNameLookupNamespace;
5
6
  export declare const tcpCreateSocket: typeof TcpCreateSocketNamespace;
6
7
  export declare const tcp: typeof TcpNamespace;
7
8
  export declare const udpCreateSocket: typeof UdpCreateSocketNamespace;
@@ -1,66 +1,85 @@
1
+ export { InMemoryTcpClient, InMemoryTcpSockets, InMemoryUdpClient, InMemoryUdpSockets, } from "./in-memory-sockets.js";
2
+ const unsupported = () => {
3
+ throw "not-supported";
4
+ };
5
+ class Network {
6
+ }
7
+ const defaultNetwork = new Network();
1
8
  export const instanceNetwork = {
2
- instanceNetwork() {
3
- console.log(`[sockets] instance network`);
4
- },
9
+ instanceNetwork: () => defaultNetwork,
5
10
  };
11
+ export const network = { Network };
12
+ class ResolveAddressStream {
13
+ resolveNextAddress = unsupported;
14
+ subscribe = unsupported;
15
+ }
6
16
  export const ipNameLookup = {
7
- dropResolveAddressStream() { },
8
- subscribe() { },
9
- resolveAddresses() { },
10
- resolveNextAddress() { },
11
- nonBlocking() { },
12
- setNonBlocking() { },
13
- };
14
- export const network = {
15
- dropNetwork() { },
17
+ ResolveAddressStream,
18
+ resolveAddresses: unsupported,
16
19
  };
20
+ class TcpSocket {
21
+ startBind = unsupported;
22
+ finishBind = unsupported;
23
+ startConnect = unsupported;
24
+ finishConnect = unsupported;
25
+ startListen = unsupported;
26
+ finishListen = unsupported;
27
+ accept = unsupported;
28
+ localAddress = unsupported;
29
+ remoteAddress = unsupported;
30
+ isListening = unsupported;
31
+ addressFamily = unsupported;
32
+ setListenBacklogSize = unsupported;
33
+ keepAliveEnabled = unsupported;
34
+ setKeepAliveEnabled = unsupported;
35
+ keepAliveIdleTime = unsupported;
36
+ setKeepAliveIdleTime = unsupported;
37
+ keepAliveInterval = unsupported;
38
+ setKeepAliveInterval = unsupported;
39
+ keepAliveCount = unsupported;
40
+ setKeepAliveCount = unsupported;
41
+ hopLimit = unsupported;
42
+ setHopLimit = unsupported;
43
+ receiveBufferSize = unsupported;
44
+ setReceiveBufferSize = unsupported;
45
+ sendBufferSize = unsupported;
46
+ setSendBufferSize = unsupported;
47
+ subscribe = unsupported;
48
+ shutdown = unsupported;
49
+ }
17
50
  export const tcpCreateSocket = {
18
- createTcpSocket() { },
19
- };
20
- export const tcp = {
21
- subscribe() { },
22
- dropTcpSocket() { },
23
- bind() { },
24
- connect() { },
25
- listen() { },
26
- accept() { },
27
- localAddress() { },
28
- remoteAddress() { },
29
- addressFamily() { },
30
- setListenBacklogSize() { },
31
- keepAlive() { },
32
- setKeepAlive() { },
33
- noDelay() { },
34
- setNoDelay() { },
35
- unicastHopLimit() { },
36
- setUnicastHopLimit() { },
37
- receiveBufferSize() { },
38
- setReceiveBufferSize() { },
39
- sendBufferSize() { },
40
- setSendBufferSize() { },
41
- nonBlocking() { },
42
- setNonBlocking() { },
43
- shutdown() { },
51
+ createTcpSocket: unsupported,
44
52
  };
53
+ export const tcp = { TcpSocket };
54
+ class IncomingDatagramStream {
55
+ receive = unsupported;
56
+ subscribe = unsupported;
57
+ }
58
+ class OutgoingDatagramStream {
59
+ checkSend = unsupported;
60
+ send = unsupported;
61
+ subscribe = unsupported;
62
+ }
63
+ class UdpSocket {
64
+ startBind = unsupported;
65
+ finishBind = unsupported;
66
+ stream = unsupported;
67
+ localAddress = unsupported;
68
+ remoteAddress = unsupported;
69
+ addressFamily = unsupported;
70
+ unicastHopLimit = unsupported;
71
+ setUnicastHopLimit = unsupported;
72
+ receiveBufferSize = unsupported;
73
+ setReceiveBufferSize = unsupported;
74
+ sendBufferSize = unsupported;
75
+ setSendBufferSize = unsupported;
76
+ subscribe = unsupported;
77
+ }
45
78
  export const udpCreateSocket = {
46
- createUdpSocket() { },
79
+ createUdpSocket: unsupported,
47
80
  };
48
81
  export const udp = {
49
- subscribe() { },
50
- dropUdpSocket() { },
51
- bind() { },
52
- connect() { },
53
- receive() { },
54
- send() { },
55
- localAddress() { },
56
- remoteAddress() { },
57
- addressFamily() { },
58
- unicastHopLimit() { },
59
- setUnicastHopLimit() { },
60
- receiveBufferSize() { },
61
- setReceiveBufferSize() { },
62
- sendBufferSize() { },
63
- setSendBufferSize() { },
64
- nonBlocking() { },
65
- setNonBlocking() { },
82
+ IncomingDatagramStream,
83
+ OutgoingDatagramStream,
84
+ UdpSocket,
66
85
  };
@@ -59,7 +59,7 @@ import type { WASIShimConfig, GetImportObjectArgs, WASIImportObject } from "../.
59
59
  * }
60
60
  * });
61
61
  *
62
- * // Limited filesystem access
62
+ * // Node.js only: limited host filesystem access
63
63
  * const limitedShim = new WASIShim({
64
64
  * sandbox: {
65
65
  * preopens: {
@@ -70,6 +70,9 @@ import type { WASIShimConfig, GetImportObjectArgs, WASIImportObject } from "../.
70
70
  * });
71
71
  * ```
72
72
  *
73
+ * Browser applications should inject `filesystem` namespaces or explicitly
74
+ * configure `browserFilesystem`; browser preopens never interpret host paths.
75
+ *
73
76
  * Note that this object is similar but not identical to the Node `WASI` object --
74
77
  * it is solely concerned with shimming of preview2 when dealing with a WebAssembly
75
78
  * component transpiled by Jco. While this object *does* work with Node (and the browser)
@@ -1,5 +1,4 @@
1
1
  import * as wasi from "@bytecodealliance/preview2-shim";
2
- import { types, _createPreopenDescriptor } from "@bytecodealliance/preview2-shim/filesystem";
3
2
  /**
4
3
  * (EXPERIMENTAL) A class that holds WASI shims and can be used to configure
5
4
  * an instantiation of a WebAssembly component transpiled with jco
@@ -60,7 +59,7 @@ import { types, _createPreopenDescriptor } from "@bytecodealliance/preview2-shim
60
59
  * }
61
60
  * });
62
61
  *
63
- * // Limited filesystem access
62
+ * // Node.js only: limited host filesystem access
64
63
  * const limitedShim = new WASIShim({
65
64
  * sandbox: {
66
65
  * preopens: {
@@ -71,6 +70,9 @@ import { types, _createPreopenDescriptor } from "@bytecodealliance/preview2-shim
71
70
  * });
72
71
  * ```
73
72
  *
73
+ * Browser applications should inject `filesystem` namespaces or explicitly
74
+ * configure `browserFilesystem`; browser preopens never interpret host paths.
75
+ *
74
76
  * Note that this object is similar but not identical to the Node `WASI` object --
75
77
  * it is solely concerned with shimming of preview2 when dealing with a WebAssembly
76
78
  * component transpiled by Jco. While this object *does* work with Node (and the browser)
@@ -93,8 +95,6 @@ export class WASIShim {
93
95
  #sockets;
94
96
  /** Object that confirms to the shim interface for `wasi:http` */
95
97
  #http;
96
- /** Isolated preopens for this instance */
97
- #preopens;
98
98
  /** Isolated environment for this instance */
99
99
  #environment;
100
100
  /**
@@ -105,36 +105,94 @@ export class WASIShim {
105
105
  constructor(config) {
106
106
  // Support both old 'shims' parameter name and new 'config' style
107
107
  const shims = config;
108
- this.#cli = shims?.cli ?? wasi.cli;
109
- this.#filesystem = shims?.filesystem ?? wasi.filesystem;
108
+ const sandbox = shims?.sandbox;
109
+ const defaultCli = wasi.cli;
110
+ this.#cli =
111
+ shims?.cli ??
112
+ (defaultCli.createCli &&
113
+ (shims?.environment !== undefined ||
114
+ shims?.arguments !== undefined ||
115
+ shims?.initialCwd !== undefined ||
116
+ shims?.stdin !== undefined ||
117
+ shims?.stdout !== undefined ||
118
+ shims?.stderr !== undefined)
119
+ ? defaultCli.createCli({
120
+ environment: shims?.environment,
121
+ arguments: shims?.arguments,
122
+ initialCwd: shims?.initialCwd,
123
+ stdin: shims?.stdin,
124
+ stdout: shims?.stdout,
125
+ stderr: shims?.stderr,
126
+ })
127
+ : defaultCli);
128
+ const defaultFilesystem = wasi.filesystem;
129
+ if (shims?.browserFilesystem && !defaultFilesystem.createFilesystem) {
130
+ throw new TypeError("the selected filesystem does not support browser adapters");
131
+ }
132
+ this.#filesystem = shims?.filesystem ?? defaultFilesystem;
133
+ if (shims?.filesystem && sandbox?.preopens !== undefined) {
134
+ if (!shims.filesystem.createPreopens) {
135
+ throw new TypeError("an application-provided filesystem must implement createPreopens to use sandbox.preopens");
136
+ }
137
+ this.#filesystem = {
138
+ types: shims.filesystem.types,
139
+ preopens: shims.filesystem.createPreopens(sandbox.preopens),
140
+ dispose: shims.filesystem.dispose?.bind(shims.filesystem),
141
+ };
142
+ }
143
+ else if (shims?.browserFilesystem) {
144
+ this.#filesystem = defaultFilesystem.createFilesystem({
145
+ adapter: shims.browserFilesystem.adapter,
146
+ preopens: sandbox?.preopens ?? shims.browserFilesystem.preopens,
147
+ });
148
+ }
149
+ else if (sandbox?.preopens !== undefined) {
150
+ if (!defaultFilesystem.createFilesystem) {
151
+ throw new TypeError("the selected filesystem cannot create isolated preopens");
152
+ }
153
+ this.#filesystem = defaultFilesystem.createFilesystem({
154
+ preopens: sandbox.preopens,
155
+ });
156
+ }
110
157
  this.#io = shims?.io ?? wasi.io;
111
158
  this.#random = shims?.random ?? wasi.random;
112
159
  this.#clocks = shims?.clocks ?? wasi.clocks;
113
- this.#sockets = shims?.sockets ?? wasi.sockets;
160
+ const defaultSockets = wasi.sockets;
161
+ this.#sockets =
162
+ shims?.sockets ??
163
+ (defaultSockets.createSockets
164
+ ? defaultSockets.createSockets({
165
+ enableNetwork: shims?.sandbox?.enableNetwork,
166
+ })
167
+ : defaultSockets);
168
+ if (shims?.tcpSockets) {
169
+ this.#sockets = {
170
+ ...this.#sockets,
171
+ tcp: shims.tcpSockets.tcp,
172
+ tcpCreateSocket: shims.tcpSockets.tcpCreateSocket,
173
+ };
174
+ }
175
+ if (shims?.udpSockets) {
176
+ this.#sockets = {
177
+ ...this.#sockets,
178
+ udp: shims.udpSockets.udp,
179
+ udpCreateSocket: shims.udpSockets.udpCreateSocket,
180
+ };
181
+ }
114
182
  this.#http = shims?.http ?? wasi.http;
115
- // Extract sandbox options
116
- const sandbox = shims?.sandbox;
117
- // Create isolated preopens if configured
118
- if (sandbox?.preopens !== undefined) {
119
- this.#preopens = createIsolatedPreopens(sandbox.preopens);
183
+ if (shims?.incomingHandler) {
184
+ if (!this.#http.createIncomingHandler) {
185
+ throw new TypeError("the selected HTTP shim does not support Web incoming handlers");
186
+ }
187
+ this.#http = {
188
+ ...this.#http,
189
+ incomingHandler: this.#http.createIncomingHandler(shims.incomingHandler),
190
+ };
120
191
  }
121
192
  // Create isolated environment if env or args are configured
122
193
  if (sandbox?.env !== undefined || sandbox?.args !== undefined) {
123
194
  this.#environment = createIsolatedEnvironment(sandbox?.env, sandbox?.args, this.#cli);
124
195
  }
125
- // Apply network restrictions if disabled
126
- if (sandbox?.enableNetwork === false) {
127
- // Use the sockets module's built-in deny functions
128
- if (this.#sockets._denyTcp) {
129
- this.#sockets._denyTcp();
130
- }
131
- if (this.#sockets._denyUdp) {
132
- this.#sockets._denyUdp();
133
- }
134
- if (this.#sockets._denyDnsLookup) {
135
- this.#sockets._denyDnsLookup();
136
- }
137
- }
138
196
  }
139
197
  /**
140
198
  * Generate an import object for the shim that can be used with
@@ -164,8 +222,7 @@ export class WASIShim {
164
222
  obj[`wasi:sockets/tcp-create-socket${versionSuffix}`] = this.#sockets.tcpCreateSocket;
165
223
  obj[`wasi:sockets/udp${versionSuffix}`] = this.#sockets.udp;
166
224
  obj[`wasi:sockets/udp-create-socket${versionSuffix}`] = this.#sockets.udpCreateSocket;
167
- obj[`wasi:filesystem/preopens${versionSuffix}`] =
168
- this.#preopens ?? this.#filesystem.preopens;
225
+ obj[`wasi:filesystem/preopens${versionSuffix}`] = this.#filesystem.preopens;
169
226
  obj[`wasi:filesystem/types${versionSuffix}`] = this.#filesystem.types;
170
227
  obj[`wasi:io/error${versionSuffix}`] = this.#io.error;
171
228
  obj[`wasi:io/poll${versionSuffix}`] = this.#io.poll;
@@ -176,32 +233,11 @@ export class WASIShim {
176
233
  obj[`wasi:clocks/monotonic-clock${versionSuffix}`] = this.#clocks.monotonicClock;
177
234
  obj[`wasi:clocks/wall-clock${versionSuffix}`] = this.#clocks.wallClock;
178
235
  obj[`wasi:http/types${versionSuffix}`] = this.#http.types;
236
+ obj[`wasi:http/incoming-handler${versionSuffix}`] = this.#http.incomingHandler;
179
237
  obj[`wasi:http/outgoing-handler${versionSuffix}`] = this.#http.outgoingHandler;
180
238
  return obj;
181
239
  }
182
240
  }
183
- /**
184
- * Create an isolated preopens object with its own preopen entries.
185
- *
186
- * @param preopensConfig - Map of virtual paths to host paths
187
- * @returns A preopens object with Descriptor and getDirectories()
188
- */
189
- function createIsolatedPreopens(preopensConfig) {
190
- const entries = [];
191
- // Populate entries using the filesystem's descriptor creation
192
- if (_createPreopenDescriptor) {
193
- for (const [virtualPath, hostPath] of Object.entries(preopensConfig)) {
194
- const descriptor = _createPreopenDescriptor(hostPath);
195
- entries.push([descriptor, virtualPath]);
196
- }
197
- }
198
- return {
199
- Descriptor: types.Descriptor,
200
- getDirectories() {
201
- return entries;
202
- },
203
- };
204
- }
205
241
  /**
206
242
  * Create an isolated CLI environment with its own env and args.
207
243
  *
@@ -1,8 +1,6 @@
1
1
  import { createFuture, createReadableStream, createReadableStreamPollState, createWritableStream, futureDispose, futureTakeValue, pollStateReady, verifyPollsDroppedForDrop, } from "./worker-thread.js";
2
- import process from "node:process";
3
2
  import { convertSocketError, ipSocketAddress, isIPv4MappedAddress, isMulticastIpAddress, isUnicastIpAddress, isWildcardAddress, noLookup, serializeIpAddress, SOCKET_STATE_BIND, SOCKET_STATE_BOUND, SOCKET_STATE_CLOSED, SOCKET_STATE_CONNECT, SOCKET_STATE_CONNECTION, SOCKET_STATE_INIT, SOCKET_STATE_LISTEN, SOCKET_STATE_LISTENER, } from "./worker-sockets.js";
4
3
  import { Server, Socket as TcpSocket } from "node:net";
5
- const win = process.platform === "win32";
6
4
  export const tcpSockets = new Map();
7
5
  let tcpSocketCnt = 0;
8
6
  export function createTcpSocket() {
@@ -37,7 +35,16 @@ export function socketTcpFinish(id, fromState, toState) {
37
35
  futureDispose(socket.future, false);
38
36
  socket.future = null;
39
37
  if (tag === "err") {
40
- socket.state = SOCKET_STATE_CLOSED;
38
+ // A failed bind does not consume the socket. In particular, callers may
39
+ // retry after `address-in-use` with another address or port.
40
+ if (fromState === SOCKET_STATE_BIND) {
41
+ socket.server = null;
42
+ socket.localAddress = null;
43
+ socket.state = SOCKET_STATE_INIT;
44
+ }
45
+ else {
46
+ socket.state = SOCKET_STATE_CLOSED;
47
+ }
41
48
  throw val;
42
49
  }
43
50
  else {
@@ -77,7 +84,7 @@ export function socketTcpBindStart(id, localAddress, family) {
77
84
  reject("invalid-state");
78
85
  return;
79
86
  }
80
- socket.localAddress = ipSocketAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
87
+ socket.localAddress = ipSocketAddress(boundAddress.family, boundAddress.address, boundAddress.port);
81
88
  resolve();
82
89
  }
83
90
  server.once("listening", handleListen);
@@ -236,7 +243,7 @@ export function socketTcpGetLocalAddress(id) {
236
243
  const socket = tcpSockets.get(id);
237
244
  const address = socket.tcpSocket?.address();
238
245
  if (address && typeof address !== "string" && "family" in address) {
239
- return ipSocketAddress(address.family.toLowerCase(), address.address, address.port);
246
+ return ipSocketAddress(address.family, address.address, address.port);
240
247
  }
241
248
  if (socket.localAddress) {
242
249
  return socket.localAddress;
@@ -248,19 +255,14 @@ export function socketTcpGetRemoteAddress(id) {
248
255
  if (!tcpSocket?.remoteFamily || !tcpSocket.remoteAddress || !tcpSocket.remotePort) {
249
256
  throw "invalid-state";
250
257
  }
251
- return ipSocketAddress(tcpSocket.remoteFamily.toLowerCase(), tcpSocket.remoteAddress, tcpSocket.remotePort);
258
+ return ipSocketAddress(tcpSocket.remoteFamily, tcpSocket.remoteAddress, tcpSocket.remotePort);
252
259
  }
253
260
  export function socketTcpShutdown(id, _shutdownType) {
254
261
  const socket = tcpSockets.get(id);
255
262
  if (socket.state !== SOCKET_STATE_CONNECTION) {
256
263
  throw "invalid-state";
257
264
  }
258
- if (win && socket.tcpSocket?.destroySoon) {
259
- socket.tcpSocket.destroySoon();
260
- }
261
- else {
262
- socket.tcpSocket?.destroy();
263
- }
265
+ socket.tcpSocket?.destroy();
264
266
  }
265
267
  export function socketTcpSetKeepAlive(id, { keepAlive, keepAliveIdleTime }) {
266
268
  const socket = tcpSockets.get(id);
@@ -61,10 +61,9 @@ function createIncomingDatagramStream(socket) {
61
61
  udpSocket.off("error", onError);
62
62
  }
63
63
  function onMessage(data, rinfo) {
64
- const family = rinfo.family.toLowerCase();
65
64
  datagramStream.queue?.push({
66
65
  data,
67
- remoteAddress: ipSocketAddress(family, rinfo.address, rinfo.port),
66
+ remoteAddress: ipSocketAddress(rinfo.family, rinfo.address, rinfo.port),
68
67
  });
69
68
  if (!pollState.ready) {
70
69
  pollStateReady(pollState);
@@ -168,7 +167,7 @@ export function socketUdpGetLocalAddress(id) {
168
167
  catch (err) {
169
168
  throw convertSocketError(err);
170
169
  }
171
- return ipSocketAddress(family.toLowerCase(), address, port);
170
+ return ipSocketAddress(family, address, port);
172
171
  }
173
172
  /**
174
173
  * @param {number} id
@@ -183,7 +182,7 @@ export function socketUdpGetRemoteAddress(id) {
183
182
  catch (err) {
184
183
  throw convertSocketError(err);
185
184
  }
186
- return ipSocketAddress(family.toLowerCase(), address, port);
185
+ return ipSocketAddress(family, address, port);
187
186
  }
188
187
  export function socketUdpStream(id, remoteAddress) {
189
188
  const socket = udpSockets.get(id);
@@ -1,4 +1,4 @@
1
- import { IpAddressFamily, IpSocketAddress, Ipv4Address, Ipv6Address } from "../../types/interfaces/wasi-sockets-network.js";
1
+ import { IpSocketAddress, Ipv4Address, Ipv6Address } from "../../types/interfaces/wasi-sockets-network.js";
2
2
  export declare const SOCKET_STATE_INIT: number;
3
3
  export declare const SOCKET_STATE_BIND: number;
4
4
  export declare const SOCKET_STATE_BOUND: number;
@@ -15,8 +15,8 @@ export declare function socketResolveAddress(name: string): Promise<{
15
15
  tag: string;
16
16
  val: Ipv4Address | Ipv6Address;
17
17
  }[]>;
18
- export declare function convertSocketError(err: any): "access-denied" | "address-in-use" | "address-not-bindable" | "concurrency-conflict" | "connection-aborted" | "connection-refused" | "connection-reset" | "invalid-argument" | "invalid-state" | "not-supported" | "out-of-memory" | "unknown" | "would-block";
19
- export declare function convertSocketErrorCode(code: any): "access-denied" | "address-in-use" | "address-not-bindable" | "concurrency-conflict" | "connection-aborted" | "connection-refused" | "connection-reset" | "invalid-argument" | "invalid-state" | "not-supported" | "out-of-memory" | "unknown" | "would-block";
18
+ export declare function convertSocketError(err: any): "access-denied" | "address-in-use" | "address-not-bindable" | "concurrency-conflict" | "connection-aborted" | "connection-refused" | "connection-reset" | "datagram-too-large" | "invalid-argument" | "invalid-state" | "new-socket-limit" | "not-supported" | "out-of-memory" | "remote-unreachable" | "unknown" | "would-block";
19
+ export declare function convertSocketErrorCode(code: any): "access-denied" | "address-in-use" | "address-not-bindable" | "concurrency-conflict" | "connection-aborted" | "connection-refused" | "connection-reset" | "datagram-too-large" | "invalid-argument" | "invalid-state" | "new-socket-limit" | "not-supported" | "out-of-memory" | "remote-unreachable" | "unknown" | "would-block";
20
20
  export declare function tupleToIPv6(arr: Ipv6Address): string | null;
21
21
  export declare function tupleToIpv4(arr: Ipv4Address): string | null;
22
22
  export declare function isMulticastIpAddress(ipSocketAddress: IpSocketAddress): boolean;
@@ -27,6 +27,6 @@ export declare function isBroadcastIpAddress(ipSocketAddress: IpSocketAddress):
27
27
  export declare function serializeIpAddress(addr: IpSocketAddress): string | null;
28
28
  export declare function ipv6ToTuple(ipv6: string): Ipv6Address;
29
29
  export declare function ipv4ToTuple(ipv4: string): Ipv4Address;
30
- export declare function ipSocketAddress(family: IpAddressFamily, addr: string, port: number): IpSocketAddress;
30
+ export declare function ipSocketAddress(family: string | number, addr: string, port: number): IpSocketAddress;
31
31
  export declare function getDefaultSendBufferSize(): Promise<bigint>;
32
32
  export declare function getDefaultReceiveBufferSize(): Promise<bigint>;
@@ -2,7 +2,7 @@ import { isIP } from "node:net";
2
2
  import { lookup } from "node:dns/promises";
3
3
  import { createSocket } from "node:dgram";
4
4
  import { ALL, BADFAMILY, CANCELLED, CONNREFUSED, NODATA, NOMEM, NONAME, NOTFOUND, REFUSED, SERVFAIL, TIMEOUT, V4MAPPED, } from "node:dns";
5
- import { EACCES, EADDRINUSE, EADDRNOTAVAIL, EALREADY, EBADF, ECONNABORTED, ECONNREFUSED, ECONNRESET, EINVAL, ENOBUFS, ENOMEM, ENOTCONN, ENOTSUP, EPERM, EWOULDBLOCK, } from "node:constants";
5
+ import { EACCES, EADDRINUSE, EADDRNOTAVAIL, EALREADY, EBADF, ECONNABORTED, ECONNREFUSED, ECONNRESET, EHOSTUNREACH, EINVAL, EMFILE, EMSGSIZE, ENETDOWN, ENETUNREACH, ENFILE, ENOBUFS, ENOMEM, ENOTCONN, ENOTSUP, EPERM, EWOULDBLOCK, } from "node:constants";
6
6
  let stateCnt = 0;
7
7
  export const SOCKET_STATE_INIT = ++stateCnt;
8
8
  export const SOCKET_STATE_BIND = ++stateCnt;
@@ -98,18 +98,26 @@ export function convertSocketError(err) {
98
98
  return "concurrency-conflict";
99
99
  case "EWOULDBLOCK":
100
100
  return "would-block";
101
- // TODO: return "new-socket-limit";
101
+ case "EMFILE":
102
+ case "ENFILE":
103
+ return "new-socket-limit";
102
104
  case "EADDRNOTAVAIL":
103
105
  return "address-not-bindable";
104
106
  case "EADDRINUSE":
105
107
  return "address-in-use";
106
- // TODO: return "remote-unreachable";
108
+ case "EHOSTUNREACH":
109
+ case "EHOSTDOWN":
110
+ case "ENETUNREACH":
111
+ case "ENETDOWN":
112
+ return "remote-unreachable";
107
113
  case "ECONNREFUSED":
108
114
  return "connection-refused";
109
115
  case "ECONNRESET":
110
116
  return "connection-reset";
111
117
  case "ECONNABORTED":
112
118
  return "connection-aborted";
119
+ case "EMSGSIZE":
120
+ return "datagram-too-large";
113
121
  default:
114
122
  return "unknown";
115
123
  }
@@ -135,23 +143,30 @@ export function convertSocketErrorCode(code) {
135
143
  return "concurrency-conflict";
136
144
  case EWOULDBLOCK:
137
145
  return "would-block";
138
- // TODO: return "new-socket-limit";
146
+ case EMFILE:
147
+ case ENFILE:
148
+ return "new-socket-limit";
139
149
  case 4090: // windows
140
150
  case EADDRNOTAVAIL:
141
151
  return "address-not-bindable";
142
152
  case 4091: // windows
143
153
  case EADDRINUSE:
144
154
  return "address-in-use";
145
- // TODO: return "remote-unreachable";
155
+ case EHOSTUNREACH:
156
+ case ENETUNREACH:
157
+ case ENETDOWN:
158
+ return "remote-unreachable";
146
159
  case ECONNREFUSED:
147
160
  return "connection-refused";
148
161
  case ECONNRESET:
149
162
  return "connection-reset";
150
163
  case ECONNABORTED:
151
164
  return "connection-aborted";
152
- // TODO: return "datagram-too-large";
153
- // TODO: return "name-unresolvable";
154
- // TODO: return "temporary-resolver-failure";
165
+ case EMSGSIZE:
166
+ return "datagram-too-large";
167
+ // name-unresolvable/temporary-resolver-failure are DNS lookup errors,
168
+ // which only surface here as string error codes (see
169
+ // socketResolveAddress above), never as a raw platform errno.
155
170
  default:
156
171
  // process._rawDebug('unknown error code', code);
157
172
  return "unknown";
@@ -219,7 +234,9 @@ export function ipv4ToTuple(ipv4) {
219
234
  return ipv4.split(".").map((segment) => parseInt(segment, 10));
220
235
  }
221
236
  export function ipSocketAddress(family, addr, port) {
222
- if (family === "ipv4") {
237
+ // Node uses "IPv4"/"IPv6", while Deno's Node compatibility layer can
238
+ // return 4/6. Accept both, as well as the WASI address-family tags.
239
+ if (family === "ipv4" || family === "IPv4" || family === 4) {
223
240
  return {
224
241
  tag: "ipv4",
225
242
  val: {
@@ -228,6 +245,9 @@ export function ipSocketAddress(family, addr, port) {
228
245
  },
229
246
  };
230
247
  }
248
+ if (family !== "ipv6" && family !== "IPv6" && family !== 6) {
249
+ throw "invalid-argument";
250
+ }
231
251
  return {
232
252
  tag: "ipv6",
233
253
  val: {