@bytecodealliance/preview3-shim 0.1.2 → 0.2.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 (112) hide show
  1. package/dist/nodejs/cli.d.ts +51 -0
  2. package/dist/nodejs/cli.js +106 -0
  3. package/dist/nodejs/clocks.d.ts +55 -0
  4. package/dist/nodejs/clocks.js +83 -0
  5. package/dist/nodejs/filesystem/descriptor.d.ts +443 -0
  6. package/dist/nodejs/filesystem/descriptor.js +1010 -0
  7. package/dist/nodejs/filesystem/error.d.ts +61 -0
  8. package/dist/nodejs/filesystem/error.js +86 -0
  9. package/dist/nodejs/filesystem/utils.d.ts +8 -0
  10. package/dist/nodejs/filesystem/utils.js +25 -0
  11. package/dist/nodejs/filesystem.js +2 -0
  12. package/dist/nodejs/finalization.d.ts +2 -0
  13. package/{lib → dist}/nodejs/finalization.js +15 -21
  14. package/dist/nodejs/future.d.ts +98 -0
  15. package/dist/nodejs/future.js +176 -0
  16. package/dist/nodejs/http/client.d.ts +22 -0
  17. package/dist/nodejs/http/client.js +138 -0
  18. package/dist/nodejs/http/error.d.ts +18 -0
  19. package/dist/nodejs/http/error.js +62 -0
  20. package/dist/nodejs/http/fields.d.ts +144 -0
  21. package/dist/nodejs/http/fields.js +327 -0
  22. package/dist/nodejs/http/request.d.ts +256 -0
  23. package/dist/nodejs/http/request.js +606 -0
  24. package/dist/nodejs/http/response.d.ts +82 -0
  25. package/dist/nodejs/http/response.js +202 -0
  26. package/dist/nodejs/http/server.d.ts +13 -0
  27. package/dist/nodejs/http/server.js +127 -0
  28. package/dist/nodejs/http.d.ts +19 -0
  29. package/{lib → dist}/nodejs/http.js +13 -18
  30. package/dist/nodejs/index.js +8 -0
  31. package/dist/nodejs/random.d.ts +5 -0
  32. package/{lib → dist}/nodejs/random.js +2 -8
  33. package/dist/nodejs/sockets/address.d.ts +78 -0
  34. package/dist/nodejs/sockets/address.js +120 -0
  35. package/dist/nodejs/sockets/error.d.ts +83 -0
  36. package/dist/nodejs/sockets/error.js +120 -0
  37. package/dist/nodejs/sockets/ip-name-lookup.d.ts +18 -0
  38. package/dist/nodejs/sockets/ip-name-lookup.js +84 -0
  39. package/dist/nodejs/sockets/tcp.d.ts +333 -0
  40. package/dist/nodejs/sockets/tcp.js +723 -0
  41. package/dist/nodejs/sockets/udp.d.ts +224 -0
  42. package/dist/nodejs/sockets/udp.js +475 -0
  43. package/dist/nodejs/sockets.d.ts +11 -0
  44. package/{lib → dist}/nodejs/sockets.js +2 -5
  45. package/dist/nodejs/stream.d.ts +161 -0
  46. package/dist/nodejs/stream.js +388 -0
  47. package/dist/nodejs/workers/cli-worker.d.ts +1 -0
  48. package/dist/nodejs/workers/cli-worker.js +41 -0
  49. package/dist/nodejs/workers/filesystem-worker.d.ts +1 -0
  50. package/dist/nodejs/workers/filesystem-worker.js +102 -0
  51. package/dist/nodejs/workers/http-worker.d.ts +1 -0
  52. package/dist/nodejs/workers/http-worker.js +355 -0
  53. package/dist/nodejs/workers/resource-worker.d.ts +13 -0
  54. package/dist/nodejs/workers/resource-worker.js +152 -0
  55. package/dist/nodejs/workers/tcp-worker.d.ts +2 -0
  56. package/dist/nodejs/workers/tcp-worker.js +318 -0
  57. package/dist/nodejs/workers/udp-worker.d.ts +1 -0
  58. package/dist/nodejs/workers/udp-worker.js +156 -0
  59. package/package.json +20 -12
  60. package/types/interfaces/wasi-cli-environment.d.ts +3 -3
  61. package/types/interfaces/wasi-cli-exit.d.ts +12 -1
  62. package/types/interfaces/wasi-cli-run.d.ts +1 -1
  63. package/types/interfaces/wasi-cli-stderr.d.ts +3 -3
  64. package/types/interfaces/wasi-cli-stdin.d.ts +5 -5
  65. package/types/interfaces/wasi-cli-stdout.d.ts +3 -3
  66. package/types/interfaces/wasi-cli-terminal-input.d.ts +1 -1
  67. package/types/interfaces/wasi-cli-terminal-output.d.ts +1 -1
  68. package/types/interfaces/wasi-cli-terminal-stderr.d.ts +1 -1
  69. package/types/interfaces/wasi-cli-terminal-stdin.d.ts +1 -1
  70. package/types/interfaces/wasi-cli-terminal-stdout.d.ts +1 -1
  71. package/types/interfaces/wasi-cli-types.d.ts +5 -5
  72. package/types/interfaces/wasi-clocks-monotonic-clock.d.ts +3 -3
  73. package/types/interfaces/wasi-clocks-system-clock.d.ts +6 -6
  74. package/types/interfaces/wasi-clocks-types.d.ts +1 -1
  75. package/types/interfaces/wasi-filesystem-preopens.d.ts +1 -1
  76. package/types/interfaces/wasi-filesystem-types.d.ts +74 -74
  77. package/types/interfaces/wasi-http-client.d.ts +1 -1
  78. package/types/interfaces/wasi-http-handler.d.ts +1 -1
  79. package/types/interfaces/wasi-http-types.d.ts +34 -34
  80. package/types/interfaces/wasi-random-insecure-seed.d.ts +5 -5
  81. package/types/interfaces/wasi-random-insecure.d.ts +5 -5
  82. package/types/interfaces/wasi-random-random.d.ts +5 -5
  83. package/types/interfaces/wasi-sockets-ip-name-lookup.d.ts +11 -11
  84. package/types/interfaces/wasi-sockets-types.d.ts +121 -121
  85. package/types/wasi-cli-command.d.ts +23 -23
  86. package/types/wasi-http-service.d.ts +14 -14
  87. package/lib/nodejs/cli.js +0 -127
  88. package/lib/nodejs/clocks.js +0 -98
  89. package/lib/nodejs/filesystem/descriptor.js +0 -1093
  90. package/lib/nodejs/filesystem/error.js +0 -92
  91. package/lib/nodejs/filesystem/utils.js +0 -19
  92. package/lib/nodejs/future.js +0 -190
  93. package/lib/nodejs/http/client.js +0 -161
  94. package/lib/nodejs/http/error.js +0 -71
  95. package/lib/nodejs/http/fields.js +0 -373
  96. package/lib/nodejs/http/request.js +0 -691
  97. package/lib/nodejs/http/response.js +0 -227
  98. package/lib/nodejs/http/server.js +0 -157
  99. package/lib/nodejs/sockets/address.js +0 -146
  100. package/lib/nodejs/sockets/error.js +0 -123
  101. package/lib/nodejs/sockets/ip-name-lookup.js +0 -93
  102. package/lib/nodejs/sockets/tcp.js +0 -801
  103. package/lib/nodejs/sockets/udp.js +0 -516
  104. package/lib/nodejs/stream.js +0 -437
  105. package/lib/nodejs/workers/cli-worker.js +0 -49
  106. package/lib/nodejs/workers/filesystem-worker.js +0 -119
  107. package/lib/nodejs/workers/http-worker.js +0 -417
  108. package/lib/nodejs/workers/resource-worker.js +0 -195
  109. package/lib/nodejs/workers/tcp-worker.js +0 -370
  110. package/lib/nodejs/workers/udp-worker.js +0 -194
  111. /package/{lib/nodejs/filesystem.js → dist/nodejs/filesystem.d.ts} +0 -0
  112. /package/{lib/nodejs/index.js → dist/nodejs/index.d.ts} +0 -0
@@ -1,801 +0,0 @@
1
- import { StreamReader, readableByteStreamFromReader } from "../stream.js";
2
- import { FutureReader } from "../future.js";
3
- import { ResourceWorker } from "../workers/resource-worker.js";
4
- import { SocketError } from "./error.js";
5
-
6
- import {
7
- isWildcardIpAddress,
8
- isUnicastIpAddress,
9
- isMulticastIpAddress,
10
- isIpv4MappedAddress,
11
- isBindableIpAddress,
12
- IP_ADDRESS_FAMILY,
13
- } from "./address.js";
14
-
15
- let WORKER = null;
16
- const symbolDispose = Symbol.dispose || Symbol.for("dispose");
17
- function worker() {
18
- return (WORKER ??= new ResourceWorker(new URL("../workers/tcp-worker.js", import.meta.url)));
19
- }
20
-
21
- let TCP_CREATE_TOKEN = null;
22
- function token() {
23
- return (TCP_CREATE_TOKEN ??= Symbol("TcpCreateToken"));
24
- }
25
-
26
- function invalidRecv() {
27
- const stream = new ReadableStream({
28
- start(controller) {
29
- controller.close();
30
- },
31
- });
32
- const promise = Promise.reject(new SocketError("invalid-state"));
33
- return [new StreamReader(stream, { preventCancel: false }), new FutureReader(promise)];
34
- }
35
-
36
- const STATE = {
37
- UNBOUND: "unbound",
38
- BOUND: "bound",
39
- LISTENING: "listening",
40
- CONNECTING: "connecting",
41
- CONNECTED: "connected",
42
- CLOSED: "closed",
43
- };
44
-
45
- /**
46
- * Creates a new TCP socket
47
- * WIT: createTcpSocket: func(address-family: ip-address-family) -> result<tcp-socket, error-code>
48
- *
49
- * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
50
- * @returns {TcpSocket>} A new TCP socket instance
51
- * @throws {SocketError} with payload.tag 'invalid-argument' if `addressFamily` is not IPV4 or IPV6
52
- * @throws {SocketError} for other errors, payload.tag maps the low-level system error_
53
- */
54
- export function createTcpSocket(addressFamily) {
55
- if (addressFamily !== IP_ADDRESS_FAMILY.IPV4 && addressFamily !== IP_ADDRESS_FAMILY.IPV6) {
56
- throw new SocketError("invalid-argument");
57
- }
58
-
59
- try {
60
- const result = worker().runSync({
61
- op: "tcp-create",
62
- family: addressFamily,
63
- });
64
-
65
- return TcpSocket._create(token(), addressFamily, result.socketId);
66
- } catch (error) {
67
- throw SocketError.from(error);
68
- }
69
- }
70
-
71
- export class TcpSocket {
72
- #socketId = null;
73
- #family = null;
74
- #state = "unbound";
75
- #sendStarted = false;
76
- #receiveStarted = false;
77
- #options = {
78
- // defaults per https://nodejs.org/docs/latest/api/net.html#socketsetkeepaliveenable-initialdelay
79
- keepAliveEnabled: false,
80
-
81
- // Node.js doesn't give us the ability to detect the OS default,
82
- // therefore we hardcode the default value instead of using the OS default,
83
- // since we would never be able to report it as a return value otherwise.
84
- // We could make this configurable as a global JCO implementation configuration
85
- // instead.
86
- keepAliveIdleTime: 7200_000_000_000n,
87
-
88
- // The following options are NOT configurable in Node.js!
89
- // Any configurations set will respond correctly, but underneath retain
90
- // system / Node.js defaults.
91
- keepAliveInterval: 1_000_000_000n,
92
- keepAliveCount: 10,
93
- hopLimit: 1,
94
- receiveBufferSize: 65_536n,
95
- sendBufferSize: 65_536n,
96
- };
97
-
98
- /**
99
- * WIT static constructor for `wasi:sockets/types.tcp-socket`.
100
- *
101
- * WIT:
102
- * ```
103
- * create: static func(address-family: ip-address-family) -> result<tcp-socket, error-code>
104
- * ```
105
- *
106
- * @static
107
- * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
108
- * @returns {TcpSocket} A new TcpSocket instance
109
- * @throws {SocketError} with payload.tag 'invalid-argument' if `addressFamily` is not IPV4 or IPV6
110
- * @throws {SocketError} for other socket creation errors
111
- */
112
- static create(addressFamily) {
113
- return createTcpSocket(addressFamily);
114
- }
115
-
116
- /**
117
- * Creates a new TCP socket
118
- * WIT:
119
- * ```
120
- * constructor(address-family: ip-address-family)
121
- * ```
122
- *
123
- * @static
124
- * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
125
- * @param {number} socketId - The internal socket identifier
126
- * @returns {TcpSocket} A new TcpSocket instance
127
- * @private
128
- */
129
- static _create(t, addressFamily, socketId) {
130
- if (t !== token()) {
131
- throw new Error("Use createTcpSocket to create a Socket");
132
- }
133
-
134
- if (addressFamily !== IP_ADDRESS_FAMILY.IPV4 && addressFamily !== IP_ADDRESS_FAMILY.IPV6) {
135
- throw new SocketError("invalid-argument");
136
- }
137
-
138
- const socket = new TcpSocket();
139
- socket.#family = addressFamily;
140
- socket.#socketId = socketId;
141
- return socket;
142
- }
143
-
144
- /**
145
- * Binds the socket to a local address
146
- * WIT:
147
- * ```
148
- * bind: func(local-address: ip-socket-address) -> result<_, error-code>
149
- * ```
150
- *
151
- * @param {Object} localAddress - The local address to bind to
152
- * @returns {void}
153
- * @throws {SocketError} with payload.tag 'invalid-state' if the socket is not in ~STATE.UNBOUND~
154
- * @throws {SocketError} with payload.tag 'invalid-argument' if ~localAddress~ is invalid
155
- * @throws {SocketError} for other errors, payload.tag maps the system error
156
- */
157
- bind(localAddress) {
158
- if (this.#state !== STATE.UNBOUND) {
159
- throw new SocketError("invalid-state");
160
- }
161
-
162
- if (!this.#isValidLocalAddress(localAddress)) {
163
- throw new SocketError("invalid-argument");
164
- }
165
- if (!isBindableIpAddress(localAddress)) {
166
- throw new SocketError("address-not-bindable");
167
- }
168
- try {
169
- worker().runSync({
170
- op: "tcp-bind",
171
- localAddress,
172
- socketId: this.#socketId,
173
- });
174
-
175
- this.#state = STATE.BOUND;
176
- } catch (error) {
177
- throw SocketError.from(error);
178
- }
179
- }
180
-
181
- /**
182
- * Connects to a remote endpoint
183
- * WIT:
184
- * ```
185
- * connect: async func(remote-address: ip-socket-address) -> result<_, error-code>
186
- * ```
187
- *
188
- * @async
189
- * @param {Object} remoteAddress - The remote address to connect to
190
- * @returns {Promise<void>}
191
- * @throws {SocketError} with payload.tag 'invalid-state' if socket is CONNECTING, CONNECTED, or LISTENING
192
- * @throws {SocketError} with payload.tag 'invalid-argument' if ~remoteAddress~ is invalid or port == 0
193
- * @throws {SocketError} for other errors, payload.tag maps the system error
194
- */
195
- async connect(remoteAddress) {
196
- if (
197
- this.#state === STATE.CONNECTING ||
198
- this.#state === STATE.CONNECTED ||
199
- this.#state === STATE.LISTENING
200
- ) {
201
- throw new SocketError("invalid-state");
202
- }
203
-
204
- if (!this.#isValidRemoteAddress(remoteAddress)) {
205
- throw new SocketError("invalid-argument");
206
- }
207
-
208
- this.#state = STATE.CONNECTING;
209
-
210
- try {
211
- await worker().run({
212
- op: "tcp-connect",
213
- remoteAddress,
214
- socketId: this.#socketId,
215
- });
216
-
217
- this.#state = STATE.CONNECTED;
218
- } catch (error) {
219
- this.#state = STATE.CLOSED;
220
- throw SocketError.from(error);
221
- }
222
- }
223
-
224
- /**
225
- * Starts listening for connections
226
- * WIT:
227
- * ```
228
- * listen: func() -> result<stream<tcp-socket>, error-code>
229
- * ```
230
- *
231
- * @returns {StreamReader} A stream of incoming TCP socket connections
232
- * @throws {SocketError} with payload.tag 'invalid-state' if socket is LISTENING or CONNECTED
233
- * @throws {SocketError} for other errors, payload.tag maps the system error
234
- */
235
- listen() {
236
- if (this.#state === STATE.LISTENING || this.#state === STATE.CONNECTED) {
237
- throw new SocketError("invalid-state");
238
- }
239
- try {
240
- // Convert incoming connections from worker to TcpSocket instances
241
- const listener = this;
242
- const transform = new TransformStream({
243
- transform({ family, socketId }, controller) {
244
- const socket = TcpSocket._create(token(), family, socketId);
245
- socket.#state = STATE.CONNECTED;
246
- socket.#options = { ...listener.#options };
247
- controller.enqueue(socket);
248
- },
249
- });
250
-
251
- worker().runSync(
252
- {
253
- op: "tcp-listen",
254
- socketId: this.#socketId,
255
- stream: transform.writable,
256
- },
257
- [transform.writable],
258
- );
259
-
260
- this.#state = STATE.LISTENING;
261
- return new StreamReader(transform.readable);
262
- } catch (error) {
263
- this.#state = STATE.CLOSED;
264
- throw SocketError.from(error);
265
- }
266
- }
267
-
268
- /**
269
- * Sends data to the connected peer
270
- * WIT:
271
- * ```
272
- * send: async func(data: stream<u8>) -> result<_, error-code>
273
- * ```
274
- *
275
- * @async
276
- * @param {object} data - The byte stream to send.
277
- * @returns {Promise<void>}
278
- * @throws {SocketError} With payload.tag 'invalid-state' if socket is not CONNECTED
279
- * @throws {SocketError} With payload.tag 'invalid-argument' if `data` is not a readable byte stream
280
- * @throws {SocketError} for other errors, payload.tag maps the system error
281
- */
282
- async send(data) {
283
- if (this.#state !== STATE.CONNECTED) {
284
- throw new SocketError("invalid-state");
285
- }
286
- if (this.#sendStarted) {
287
- data?.[symbolDispose]?.();
288
- throw new SocketError("invalid-state");
289
- }
290
- let stream;
291
- try {
292
- stream = readableByteStreamFromReader(data, { name: "tcp send data" });
293
- } catch (error) {
294
- if (error instanceof TypeError) {
295
- throw new SocketError("invalid-argument", error.message, undefined, { cause: error });
296
- }
297
- throw error;
298
- }
299
- this.#sendStarted = true;
300
-
301
- try {
302
- // Transfer the stream to the worker
303
- await worker().run(
304
- {
305
- op: "tcp-send",
306
- socketId: this.#socketId,
307
- stream,
308
- },
309
- [stream],
310
- );
311
- } catch (error) {
312
- throw SocketError.from(error);
313
- }
314
- }
315
-
316
- /**
317
- * Receives data from the connected peer
318
- * WIT:
319
- * ```
320
- * receive: func() -> tuple<stream<u8>, future<result<_, error-code>>>
321
- * ```
322
- *
323
- * @throws {SocketError} with payload.tag 'invalid-state' if socket is not CONNECTED
324
- * @throws {SocketError} for other errors, payload.tag maps the system error
325
- * @returns {{ stream: StreamReader, future: FutureReader }}
326
- */
327
- receive() {
328
- if (this.#state !== STATE.CONNECTED) {
329
- return invalidRecv();
330
- }
331
- if (this.#receiveStarted) {
332
- return invalidRecv();
333
- }
334
- this.#receiveStarted = true;
335
-
336
- const transform = new TransformStream();
337
- const promise = worker()
338
- .run(
339
- {
340
- op: "tcp-receive",
341
- socketId: this.#socketId,
342
- stream: transform.writable,
343
- },
344
- [transform.writable],
345
- )
346
- .catch((err) => {
347
- throw SocketError.from(err);
348
- });
349
-
350
- return [
351
- new StreamReader(transform.readable, { preventCancel: false }),
352
- new FutureReader(promise),
353
- ];
354
- }
355
-
356
- /**
357
- * Gets the bound local address
358
- * WIT:
359
- * ```
360
- * local-address: func() -> result<ip-socket-address, error-code>
361
- * ```
362
- *
363
- * @returns {Object} The local socket address
364
- * @throws {SocketError} with payload.tag 'invalid-state' if socket is not BOUND
365
- * @throws {SocketError} for other errors, payload.tag maps the system error
366
- */
367
- getLocalAddress() {
368
- if (this.#state === STATE.UNBOUND) {
369
- throw new SocketError("invalid-state");
370
- }
371
-
372
- try {
373
- return worker().runSync({
374
- op: "tcp-get-local-address",
375
- socketId: this.#socketId,
376
- });
377
- } catch (err) {
378
- throw SocketError.from(err);
379
- }
380
- }
381
-
382
- /**
383
- * Gets the remote address
384
- * WIT:
385
- * ```
386
- * remote-address: func() -> result<ip-socket-address, error-code>
387
- * ```
388
- *
389
- * @returns {Object} The remote socket address
390
- * @throws {SocketError} with payload.tag 'invalid-state' if socket is not CONNECTED
391
- * @throws {SocketError} for other errors, payload.tag maps the system error
392
- */
393
- getRemoteAddress() {
394
- if (this.#state !== STATE.CONNECTED) {
395
- throw new SocketError("invalid-state");
396
- }
397
-
398
- try {
399
- return worker().runSync({
400
- op: "tcp-get-remote-address",
401
- socketId: this.#socketId,
402
- });
403
- } catch (err) {
404
- throw SocketError.from(err);
405
- }
406
- }
407
-
408
- /**
409
- * Checks if the socket is in listening state
410
- * WIT:
411
- * ```
412
- * is-listening: func() -> bool
413
- * ```
414
- *
415
- * @returns {boolean} True if socket is listening, false otherwise
416
- */
417
- getIsListening() {
418
- return this.#state === STATE.LISTENING;
419
- }
420
-
421
- /**
422
- * Gets the address family
423
- * WIT:
424
- * ```
425
- * address-family: func() -> ip-address-family
426
- * ```
427
- *
428
- * @returns {IP_ADDRESS_FAMILY} The IP address family (IPv4 or IPv6)
429
- */
430
- getAddressFamily() {
431
- return this.#family;
432
- }
433
-
434
- /**
435
- * Sets the listen backlog size
436
- * WIT:
437
- * ```
438
- * set-listen-backlog-size: func(value: u64) -> result<_, error-code>
439
- * ```
440
- *
441
- * @param {bigint} value - The backlog size
442
- * @returns {void}
443
- * @throws {SocketError} with payload.tag 'invalid-argument' if `value` is 0
444
- * @throws {SocketError} with payload.tag 'not-supported' if socket is CONNECTING or CONNECTED
445
- * @throws {SocketError} with payload.tag 'invalid-state' if socket is not UNBOUND or BOUND
446
- * @throws {SocketError} for other errors, payload.tag maps the system error
447
- */
448
- setListenBacklogSize(value) {
449
- if (value <= 0n) {
450
- throw new SocketError("invalid-argument");
451
- }
452
-
453
- if (
454
- this.#state === STATE.CONNECTING ||
455
- this.#state === STATE.CONNECTED ||
456
- this.#state === STATE.LISTENING
457
- ) {
458
- throw new SocketError("not-supported");
459
- }
460
-
461
- if (this.#state !== STATE.UNBOUND && this.#state !== STATE.BOUND) {
462
- throw new SocketError("invalid-state");
463
- }
464
-
465
- this.#options.listenBacklogSize = value;
466
- try {
467
- worker().runSync({
468
- op: "tcp-set-listen-backlog-size",
469
- socketId: this.#socketId,
470
- value,
471
- });
472
- } catch (err) {
473
- throw SocketError.from(err);
474
- }
475
- }
476
-
477
- /**
478
- * Gets whether keep-alive is enabled
479
- * WIT:
480
- * ```
481
- * keep-alive-enabled: func() -> result<bool, error-code>
482
- * ```
483
- *
484
- * @returns {boolean} True if keep-alive is enabled, false otherwise
485
- */
486
- getKeepAliveEnabled() {
487
- return this.#options.keepAliveEnabled;
488
- }
489
-
490
- /**
491
- * Sets keep-alive enabled state
492
- * WIT:
493
- * ```
494
- * set-keep-alive-enabled: func(value: bool) -> result<_, error-code>
495
- * ```
496
- *
497
- * @async
498
- * @param {boolean} value - Whether to enable keep-alive
499
- * @returns {void}
500
- * @throws {SocketError} for other errors, payload.tag maps the system error
501
- */
502
- setKeepAliveEnabled(value) {
503
- try {
504
- this.#options.keepAliveEnabled = value;
505
-
506
- worker().runSync({
507
- op: "tcp-set-keep-alive",
508
- socketId: this.#socketId,
509
- keepAliveEnabled: this.#options.keepAliveEnabled,
510
- keepAliveIdleTime: this.#options.keepAliveIdleTime,
511
- });
512
- } catch (err) {
513
- throw SocketError.from(err);
514
- }
515
- }
516
-
517
- /**
518
- * Gets the keep-alive idle time
519
- * WIT:
520
- * ```
521
- * keep-alive-idle-time: func() -> result<duration, error-code>
522
- * ```
523
- *
524
- * @returns {bigint} The keep-alive idle time in nanoseconds
525
- */
526
- getKeepAliveIdleTime() {
527
- return this.#options.keepAliveIdleTime;
528
- }
529
-
530
- /**
531
- * Sets the keep-alive idle time
532
- * WIT:
533
- * ```
534
- * set-keep-alive-idle-time: func(value: duration) -> result<_, error-code>
535
- * ```
536
- *
537
- * @param {bigint} value - The idle time in nanoseconds
538
- * @returns {void}
539
- * @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
540
- * @throws {SocketError} for other errors, payload.tag maps the system error
541
- */
542
- setKeepAliveIdleTime(value) {
543
- if (value < 1n) {
544
- throw new SocketError("invalid-argument");
545
- }
546
-
547
- // Ensure that the value passed to the worker never gets rounded down to 0.
548
- if (value < 1_000_000_000n) {
549
- value = 1_000_000_000n;
550
- }
551
-
552
- if (value === this.#options.keepAliveIdleTime || !this.#options.keepAliveEnabled) {
553
- this.#options.keepAliveIdleTime = value;
554
- return;
555
- }
556
-
557
- this.#options.keepAliveIdleTime = value;
558
-
559
- try {
560
- worker().runSync({
561
- op: "tcp-set-keep-alive",
562
- socketId: this.#socketId,
563
- keepAliveEnabled: this.#options.keepAliveEnabled,
564
- keepAliveIdleTime: this.#options.keepAliveIdleTime,
565
- });
566
- } catch (err) {
567
- throw SocketError.from(err);
568
- }
569
- }
570
-
571
- /**
572
- * Gets the keep-alive interval
573
- * WIT:
574
- * ```
575
- * keep-alive-interval: func() -> result<duration, error-code>
576
- * ```
577
- *
578
- * @returns {bigint} The keep-alive interval in nanoseconds
579
- */
580
- getKeepAliveInterval() {
581
- return this.#options.keepAliveInterval;
582
- }
583
-
584
- /**
585
- * Sets the keep-alive interval
586
- * WIT:
587
- * ```
588
- * set-keep-alive-interval: func(value: duration) -> result<_, error-code>
589
- * ```
590
- *
591
- * @param {bigint} value - The interval in nanoseconds
592
- * @returns {void}
593
- * @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
594
- */
595
- setKeepAliveInterval(value) {
596
- if (value < 1n) {
597
- throw new SocketError("invalid-argument");
598
- }
599
- this.#options.keepAliveInterval = value;
600
- }
601
-
602
- /**
603
- * Gets the keep-alive count
604
- * WIT:
605
- * ```
606
- * keep-alive-count: func() -> result<u32, error-code>
607
- * ```
608
- *
609
- * @returns {number} The keep-alive count
610
- */
611
- getKeepAliveCount() {
612
- return this.#options.keepAliveCount;
613
- }
614
-
615
- /**
616
- * Sets the keep-alive count
617
- * WIT:
618
- * ```
619
- * set-keep-alive-count: func(value: u32) -> result<_, error-code>
620
- * ```
621
- *
622
- * @param {number} value - The keep-alive count
623
- * @returns {void}
624
- * @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
625
- */
626
- setKeepAliveCount(value) {
627
- if (value < 1) {
628
- throw new SocketError("invalid-argument");
629
- }
630
- this.#options.keepAliveCount = value;
631
- }
632
-
633
- /**
634
- * Gets the hop limit
635
- * WIT:
636
- * ```
637
- * hop-limit: func() -> result<u8, error-code>
638
- * ```
639
- *
640
- * @returns {number} The hop limit
641
- */
642
- getHopLimit() {
643
- return this.#options.hopLimit;
644
- }
645
-
646
- /**
647
- * Sets the hop limit
648
- * WIT:
649
- * ```
650
- * set-hop-limit: func(value: u8) -> result<_, error-code>
651
- * ```
652
- *
653
- * @param {number} value - The hop limit
654
- * @returns {void}
655
- * @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
656
- */
657
- setHopLimit(value) {
658
- if (value < 1) {
659
- throw new SocketError("invalid-argument");
660
- }
661
- this.#options.hopLimit = value;
662
- }
663
-
664
- /**
665
- * Gets the receive buffer size
666
- * WIT:
667
- * ```
668
- * receive-buffer-size: func() -> result<u64, error-code>
669
- * ```
670
- *
671
- * @returns {bigint} The receive buffer size in bytes
672
- * @throws {SocketError} for other errors, payload.tag maps the system error
673
- */
674
- getReceiveBufferSize() {
675
- if (this.#options.receiveBufferSize) {
676
- return this.#options.receiveBufferSize;
677
- }
678
-
679
- try {
680
- const result = worker().runSync({
681
- op: "tcp-recv-buffer-size",
682
- socketId: this.#socketId,
683
- });
684
-
685
- this.#options.receiveBufferSize = result;
686
- return result;
687
- } catch (err) {
688
- throw SocketError.from(err);
689
- }
690
- }
691
-
692
- /**
693
- * Sets the receive buffer size
694
- * WIT:
695
- * ```
696
- * set-receive-buffer-size: func(value: u64) -> result<_, error-code>
697
- * ```
698
- *
699
- * @param {bigint} value - The receive buffer size in bytes
700
- * @returns {void}
701
- * @throws {SocketError} with payload.tag 'invalid-argument' if `value` is 0
702
- */
703
- setReceiveBufferSize(value) {
704
- if (value <= 0n) {
705
- throw new SocketError("invalid-argument");
706
- }
707
- this.#options.receiveBufferSize = value;
708
- }
709
-
710
- /**
711
- * Gets the send buffer size
712
- * WIT:
713
- * ```
714
- * send-buffer-size: func() -> result<u64, error-code>
715
- * ```
716
- *
717
- * @returns {bigint} The send buffer size in bytes
718
- * @throws {SocketError} for other errors, payload.tag maps the system error
719
- */
720
- getSendBufferSize() {
721
- if (this.#options.sendBufferSize) {
722
- return this.#options.sendBufferSize;
723
- }
724
-
725
- try {
726
- const result = worker().runSync({
727
- op: "tcp-send-buffer-size",
728
- socketId: this.#socketId,
729
- });
730
-
731
- this.#options.sendBufferSize = result;
732
- return result;
733
- } catch (err) {
734
- throw SocketError.from(err);
735
- }
736
- }
737
-
738
- /**
739
- * Sets the send buffer size
740
- * WIT:
741
- * ```
742
- * set-send-buffer-size: func(value: u64) -> result<_, error-code>
743
- * ```
744
- *
745
- * @param {bigint} value - The send buffer size in bytes
746
- * @returns {void}
747
- * @throws {SocketError} with payload.tag 'invalid-argument' if `value` is 0
748
- */
749
- setSendBufferSize(value) {
750
- if (value <= 0n) {
751
- throw new SocketError("invalid-argument");
752
- }
753
- this.#options.sendBufferSize = value;
754
- }
755
-
756
- /**
757
- * Disposes the socket
758
- */
759
- [Symbol.dispose]() {
760
- if (this.#socketId) {
761
- worker().runSync({
762
- op: "tcp-dispose",
763
- socketId: this.#socketId,
764
- });
765
- }
766
-
767
- this.#socketId = null;
768
- this.#state = STATE.CLOSED;
769
- }
770
-
771
- /**
772
- * Validates if a local address is valid for this socket
773
- * @param {Object} localAddress - The local address to validate
774
- * @returns {boolean} True if the address is valid, false otherwise
775
- * @private
776
- */
777
- #isValidLocalAddress(localAddress) {
778
- return (
779
- this.#family === localAddress.tag &&
780
- (isUnicastIpAddress(localAddress) || isWildcardIpAddress(localAddress)) &&
781
- !isIpv4MappedAddress(localAddress)
782
- );
783
- }
784
-
785
- /**
786
- * Validates if a remote address is valid for this socket
787
- * @param {Object} remoteAddress - The remote address to validate
788
- * @returns {boolean} True if the address is valid, false otherwise
789
- * @private
790
- */
791
- #isValidRemoteAddress(remoteAddress) {
792
- return (
793
- this.#family === remoteAddress.tag &&
794
- remoteAddress.val.port !== 0 &&
795
- isUnicastIpAddress(remoteAddress) &&
796
- !isWildcardIpAddress(remoteAddress) &&
797
- !isMulticastIpAddress(remoteAddress) &&
798
- !isIpv4MappedAddress(remoteAddress)
799
- );
800
- }
801
- }