@bytecodealliance/preview3-shim 0.1.1 → 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 -100
  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
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Create a new UDP socket.
3
+ * WIT:
4
+ * ```
5
+ * createUdpSocket: func(address-family: ip-address-family) -> result<udp-socket, error-code>
6
+ * ```
7
+ *
8
+ * @async
9
+ * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family
10
+ * @returns {Promise<UdpSocket>}
11
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~addressFamily~ is not IPv4 or IPv6
12
+ * @throws {SocketError} for other errors, payload.tag maps the system error
13
+ */
14
+ export declare function createUdpSocket(addressFamily: any): UdpSocket;
15
+ export declare class UdpSocket {
16
+ #private;
17
+ /**
18
+ * WIT static constructor for `wasi:sockets/types.udp-socket`.
19
+ *
20
+ * WIT:
21
+ * ```
22
+ * create: static func(address-family: ip-address-family) -> result<udp-socket, error-code>
23
+ * ```
24
+ *
25
+ * @static
26
+ * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
27
+ * @returns {UdpSocket} A new UdpSocket instance
28
+ * @throws {SocketError} with payload.tag 'invalid-argument' if `addressFamily` is not IPV4 or IPV6
29
+ * @throws {SocketError} for other socket creation errors
30
+ */
31
+ static create(addressFamily: any): UdpSocket;
32
+ /**
33
+ * Creates a new UDP socket
34
+ * WIT:
35
+ * ```
36
+ * constructor(address-family: ip-address-family)
37
+ * ```
38
+ *
39
+ * @static
40
+ * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
41
+ * @param {string} socketId - The internal socket identifier
42
+ * @returns {UdpSocket} A new UdpSocket instance
43
+ * @private
44
+ */
45
+ static _create(t: any, addressFamily: any, socketId: any): UdpSocket;
46
+ /**
47
+ * Bind the socket to the provided IP address and port.
48
+ * WIT:
49
+ * ```
50
+ * bind: func(local-address: ip-socket-address) -> result<_, error-code>
51
+ * ```
52
+ *
53
+ * @param {Object} localAddress - The local address to bind to
54
+ * @returns {void}
55
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is not in ~STATE.UNBOUND~
56
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~localAddress~ is invalid
57
+ * @throws {SocketError} for other errors, payload.tag maps the system error
58
+ *
59
+ */
60
+ bind(localAddress: any): void;
61
+ /**
62
+ * Associate this socket with a specific peer address.
63
+ * WIT:
64
+ * ```
65
+ * connect: func(remote-address: ip-socket-address) -> result<_, error-code>
66
+ * ```
67
+ *
68
+ * @param {Object} remoteAddress - The remote address to connect to
69
+ * @returns {void}
70
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is already connected
71
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~remoteAddress~ is invalid or wildcard
72
+ * @throws {SocketError} for other errors, payload.tag maps the system error
73
+ */
74
+ connect(remoteAddress: any): void;
75
+ /**
76
+ * Dissociate this socket from its peer address.
77
+ * WIT:
78
+ * ```
79
+ * disconnect: func() -> result<_, error-code>
80
+ * ```
81
+ *
82
+ * @returns {void}
83
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is not connected
84
+ * @throws {SocketError} for other errors, payload.tag maps the system error
85
+ */
86
+ disconnect(): void;
87
+ /**
88
+ * Send a message on the socket to a particular peer.
89
+ * WIT:
90
+ * ```
91
+ * send: func(data: list<u8>, remote-address: option<ip-socket-address>) -> result<_, error-code>
92
+ * ```
93
+ *
94
+ * @async
95
+ * @param {Uint8Array} data - The datagram payload
96
+ * @param {?Object} remoteAddress Optional peer address if not connected.
97
+ * @returns {Promise<void>}
98
+ * @throws {SocketError} with payload.tag 'invalid-state' if socket is not bound
99
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~data~ is not a Uint8Array or address invalid
100
+ * @throws {SocketError} for other errors, payload.tag maps the system error
101
+ */
102
+ send(data: any, remoteAddress?: any): Promise<void>;
103
+ /**
104
+ * Receive a message on the socket.
105
+ * WIT:
106
+ * ```
107
+ * receive: func() -> result<tuple<list<u8>, ip-socket-address>, error-code>
108
+ * ```
109
+ *
110
+ * @async
111
+ * @returns {Promise<[Uint8Array, Object]>} Received data and sender address
112
+ * @throws {SocketError} with payload.tag 'invalid-state' if socket has not been bound
113
+ * @throws {SocketError} for other errors, payload.tag maps the system error
114
+ */
115
+ receive(): Promise<any[]>;
116
+ /**
117
+ * Get the current bound address.
118
+ * WIT:
119
+ * ```
120
+ * local-address: func() -> result<ip-socket-address, error-code>
121
+ * ```
122
+ *
123
+ * @returns {Object} The local socket address
124
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket hasn't been bound yet
125
+ * @throws {SocketError} for other errors, payload.tag maps the system error
126
+ */
127
+ getLocalAddress(): any;
128
+ /**
129
+ * Get the address the socket is currently connected to.
130
+ * WIT:
131
+ * ```
132
+ * remote-address: func() -> result<ip-socket-address, error-code>
133
+ * ```
134
+ *
135
+ * @returns {Object} The connected peer address
136
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is not connected
137
+ */
138
+ getRemoteAddress(): any;
139
+ /**
140
+ * Whether this is an IPv4 or IPv6 socket.
141
+ * WIT:
142
+ * ```
143
+ * address-family: func() -> ip-address-family
144
+ * ```
145
+ *
146
+ * @returns {IP_ADDRESS_FAMILY}
147
+ */
148
+ getAddressFamily(): any;
149
+ /**
150
+ * Get the unicast hop limit (TTL).
151
+ * WIT:
152
+ * ```
153
+ * unicast-hop-limit: func() -> result<u8, error-code>
154
+ * ```
155
+ *
156
+ * @returns {number}
157
+ */
158
+ getUnicastHopLimit(): number;
159
+ /**
160
+ * Set the unicast hop limit (TTL).
161
+ * WIT:
162
+ * ```
163
+ * set-unicast-hop-limit: func(value: u8) -> result<_, error-code>
164
+ * ```
165
+ *
166
+ * @param {number} value - The hop limit (must be ≥1)
167
+ * @returns {void}
168
+ * @throws {SocketError} with payload.tag 'invalid-argument' if value < 1
169
+ * @throws {SocketError} for other errors, payload.tag maps the system error
170
+ */
171
+ setUnicastHopLimit(value: any): void;
172
+ /**
173
+ * Get the receive buffer size.
174
+ * WIT:
175
+ * ```
176
+ * receive-buffer-size: func() -> result<u64, error-code>
177
+ * ```
178
+ *
179
+ * @returns {bigint}
180
+ * @throws {SocketError} payload.tag maps the system error
181
+ */
182
+ getReceiveBufferSize(): any;
183
+ /**
184
+ * Set the receive buffer size.
185
+ * WIT:
186
+ * ```
187
+ * set-receive-buffer-size: func(value: u64) -> result<_, error-code>
188
+ * ```
189
+ *
190
+ * @param {bigint} value - The buffer size in bytes (must be >0)
191
+ * @throws {SocketError} payload.tag maps the system error
192
+ */
193
+ setReceiveBufferSize(value: any): void;
194
+ /**
195
+ * Get the send buffer size.
196
+ * WIT:
197
+ * ```
198
+ * send-buffer-size: func() -> result<u64, error-code>
199
+ * ```
200
+ *
201
+ * @async
202
+ * @returns {bigint}
203
+ * @throws {SocketError} payload.tag maps the system error
204
+ */
205
+ getSendBufferSize(): any;
206
+ /**
207
+ * Set the send buffer size.
208
+ * WIT:
209
+ * ```
210
+ * set-send-buffer-size: func(value: u64) -> result<_, error-code>
211
+ * ```
212
+ *
213
+ * @param {bigint} value - The buffer size in bytes (must be >0)
214
+ * @throws {SocketError} with payload.tag 'invalid-argument' if value == 0
215
+ */
216
+ setSendBufferSize(value: any): void;
217
+ /**
218
+ * Dispose the socket.
219
+ *
220
+ * Releases native resources and marks the socket as closed.
221
+ */
222
+ [Symbol.dispose](): void;
223
+ }
224
+ export declare const udpCreateSocket: {};
@@ -0,0 +1,475 @@
1
+ import { ResourceWorker } from "../workers/resource-worker.js";
2
+ import { SocketError } from "./error.js";
3
+ import { isWildcardIpAddress, isUnicastIpAddress, isIpv4MappedAddress, isBindableIpAddress, IP_ADDRESS_FAMILY, } from "./address.js";
4
+ let WORKER = null;
5
+ function worker() {
6
+ return (WORKER ??= new ResourceWorker(new URL("../workers/udp-worker.js", import.meta.url)));
7
+ }
8
+ let UDP_CREATE_TOKEN = null;
9
+ function token() {
10
+ return (UDP_CREATE_TOKEN ??= Symbol("UdpCreateToken"));
11
+ }
12
+ const STATE = {
13
+ UNBOUND: "unbound",
14
+ BOUND: "bound",
15
+ CONNECTED: "connected",
16
+ CLOSED: "closed",
17
+ };
18
+ /**
19
+ * Create a new UDP socket.
20
+ * WIT:
21
+ * ```
22
+ * createUdpSocket: func(address-family: ip-address-family) -> result<udp-socket, error-code>
23
+ * ```
24
+ *
25
+ * @async
26
+ * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family
27
+ * @returns {Promise<UdpSocket>}
28
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~addressFamily~ is not IPv4 or IPv6
29
+ * @throws {SocketError} for other errors, payload.tag maps the system error
30
+ */
31
+ export function createUdpSocket(addressFamily) {
32
+ if (addressFamily !== IP_ADDRESS_FAMILY.IPV4 && addressFamily !== IP_ADDRESS_FAMILY.IPV6) {
33
+ throw new SocketError("invalid-argument");
34
+ }
35
+ try {
36
+ const { socketId } = worker().runSync({
37
+ op: "udp-create",
38
+ family: addressFamily,
39
+ });
40
+ return UdpSocket._create(token(), addressFamily, socketId);
41
+ }
42
+ catch (e) {
43
+ throw SocketError.from(e);
44
+ }
45
+ }
46
+ export class UdpSocket {
47
+ #socketId = null;
48
+ #family = null;
49
+ #state = STATE.UNBOUND;
50
+ #remote = null;
51
+ #options = {
52
+ hopLimit: 1,
53
+ receiveBufferSize: 65536n,
54
+ sendBufferSize: 65536n,
55
+ };
56
+ /**
57
+ * WIT static constructor for `wasi:sockets/types.udp-socket`.
58
+ *
59
+ * WIT:
60
+ * ```
61
+ * create: static func(address-family: ip-address-family) -> result<udp-socket, error-code>
62
+ * ```
63
+ *
64
+ * @static
65
+ * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
66
+ * @returns {UdpSocket} A new UdpSocket instance
67
+ * @throws {SocketError} with payload.tag 'invalid-argument' if `addressFamily` is not IPV4 or IPV6
68
+ * @throws {SocketError} for other socket creation errors
69
+ */
70
+ static create(addressFamily) {
71
+ return createUdpSocket(addressFamily);
72
+ }
73
+ /**
74
+ * Creates a new UDP socket
75
+ * WIT:
76
+ * ```
77
+ * constructor(address-family: ip-address-family)
78
+ * ```
79
+ *
80
+ * @static
81
+ * @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
82
+ * @param {string} socketId - The internal socket identifier
83
+ * @returns {UdpSocket} A new UdpSocket instance
84
+ * @private
85
+ */
86
+ static _create(t, addressFamily, socketId) {
87
+ if (t !== token()) {
88
+ throw new Error("Use createUdpSocket to create a Socket");
89
+ }
90
+ if (addressFamily !== IP_ADDRESS_FAMILY.IPV4 && addressFamily !== IP_ADDRESS_FAMILY.IPV6) {
91
+ throw new SocketError("invalid-argument");
92
+ }
93
+ const sock = new UdpSocket();
94
+ sock.#family = addressFamily;
95
+ sock.#socketId = socketId;
96
+ return sock;
97
+ }
98
+ /**
99
+ * Bind the socket to the provided IP address and port.
100
+ * WIT:
101
+ * ```
102
+ * bind: func(local-address: ip-socket-address) -> result<_, error-code>
103
+ * ```
104
+ *
105
+ * @param {Object} localAddress - The local address to bind to
106
+ * @returns {void}
107
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is not in ~STATE.UNBOUND~
108
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~localAddress~ is invalid
109
+ * @throws {SocketError} for other errors, payload.tag maps the system error
110
+ *
111
+ */
112
+ bind(localAddress) {
113
+ if (this.#state !== STATE.UNBOUND) {
114
+ throw new SocketError("invalid-state");
115
+ }
116
+ if (localAddress.tag !== this.#family ||
117
+ (!isUnicastIpAddress(localAddress) && !isWildcardIpAddress(localAddress)) ||
118
+ isIpv4MappedAddress(localAddress)) {
119
+ throw new SocketError("invalid-argument");
120
+ }
121
+ if (!isBindableIpAddress(localAddress)) {
122
+ throw new SocketError("address-not-bindable");
123
+ }
124
+ try {
125
+ worker().runSync({
126
+ op: "udp-bind",
127
+ socketId: this.#socketId,
128
+ localAddress,
129
+ });
130
+ this.#state = STATE.BOUND;
131
+ }
132
+ catch (e) {
133
+ throw SocketError.from(e);
134
+ }
135
+ }
136
+ /**
137
+ * Associate this socket with a specific peer address.
138
+ * WIT:
139
+ * ```
140
+ * connect: func(remote-address: ip-socket-address) -> result<_, error-code>
141
+ * ```
142
+ *
143
+ * @param {Object} remoteAddress - The remote address to connect to
144
+ * @returns {void}
145
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is already connected
146
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~remoteAddress~ is invalid or wildcard
147
+ * @throws {SocketError} for other errors, payload.tag maps the system error
148
+ */
149
+ connect(remoteAddress) {
150
+ if (remoteAddress.tag !== this.#family ||
151
+ remoteAddress.val.port === 0 ||
152
+ isWildcardIpAddress(remoteAddress) ||
153
+ !isUnicastIpAddress(remoteAddress) ||
154
+ isIpv4MappedAddress(remoteAddress)) {
155
+ throw new SocketError("invalid-argument");
156
+ }
157
+ try {
158
+ worker().runSync({
159
+ op: "udp-connect",
160
+ socketId: this.#socketId,
161
+ remoteAddress,
162
+ });
163
+ this.#remote = remoteAddress;
164
+ this.#state = STATE.CONNECTED;
165
+ }
166
+ catch (e) {
167
+ throw SocketError.from(e);
168
+ }
169
+ }
170
+ /**
171
+ * Dissociate this socket from its peer address.
172
+ * WIT:
173
+ * ```
174
+ * disconnect: func() -> result<_, error-code>
175
+ * ```
176
+ *
177
+ * @returns {void}
178
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is not connected
179
+ * @throws {SocketError} for other errors, payload.tag maps the system error
180
+ */
181
+ disconnect() {
182
+ if (this.#state !== STATE.CONNECTED) {
183
+ throw new SocketError("invalid-state");
184
+ }
185
+ try {
186
+ worker().runSync({
187
+ op: "udp-disconnect",
188
+ socketId: this.#socketId,
189
+ });
190
+ this.#remote = null;
191
+ this.#state = STATE.BOUND;
192
+ }
193
+ catch (e) {
194
+ throw SocketError.from(e);
195
+ }
196
+ }
197
+ /**
198
+ * Send a message on the socket to a particular peer.
199
+ * WIT:
200
+ * ```
201
+ * send: func(data: list<u8>, remote-address: option<ip-socket-address>) -> result<_, error-code>
202
+ * ```
203
+ *
204
+ * @async
205
+ * @param {Uint8Array} data - The datagram payload
206
+ * @param {?Object} remoteAddress Optional peer address if not connected.
207
+ * @returns {Promise<void>}
208
+ * @throws {SocketError} with payload.tag 'invalid-state' if socket is not bound
209
+ * @throws {SocketError} with payload.tag 'invalid-argument' if ~data~ is not a Uint8Array or address invalid
210
+ * @throws {SocketError} for other errors, payload.tag maps the system error
211
+ */
212
+ async send(data, remoteAddress = null) {
213
+ if (this.#state === STATE.CLOSED) {
214
+ throw new SocketError("invalid-state");
215
+ }
216
+ if (!(data instanceof Uint8Array)) {
217
+ throw new SocketError("invalid-argument");
218
+ }
219
+ const addr = remoteAddress ?? this.#remote;
220
+ if (!addr ||
221
+ addr.val.port === 0 ||
222
+ addr.tag !== this.#family ||
223
+ isWildcardIpAddress(addr) ||
224
+ isIpv4MappedAddress(addr) ||
225
+ !isUnicastIpAddress(addr)) {
226
+ throw new SocketError("invalid-argument");
227
+ }
228
+ if (this.#state === STATE.CONNECTED &&
229
+ remoteAddress != null &&
230
+ (addr.tag !== this.#remote.tag ||
231
+ addr.val.port !== this.#remote.val.port ||
232
+ addr.val.address.some((v, i) => v !== this.#remote.val.address[i]))) {
233
+ throw new SocketError("invalid-argument");
234
+ }
235
+ const wasUnbound = this.#state === STATE.UNBOUND;
236
+ try {
237
+ await worker().run({
238
+ op: "udp-send",
239
+ socketId: this.#socketId,
240
+ data,
241
+ remoteAddress: addr,
242
+ }, [data.buffer]);
243
+ if (wasUnbound) {
244
+ this.#state = STATE.BOUND;
245
+ }
246
+ }
247
+ catch (e) {
248
+ throw SocketError.from(e);
249
+ }
250
+ }
251
+ /**
252
+ * Receive a message on the socket.
253
+ * WIT:
254
+ * ```
255
+ * receive: func() -> result<tuple<list<u8>, ip-socket-address>, error-code>
256
+ * ```
257
+ *
258
+ * @async
259
+ * @returns {Promise<[Uint8Array, Object]>} Received data and sender address
260
+ * @throws {SocketError} with payload.tag 'invalid-state' if socket has not been bound
261
+ * @throws {SocketError} for other errors, payload.tag maps the system error
262
+ */
263
+ async receive() {
264
+ if (this.#state === STATE.UNBOUND) {
265
+ throw new SocketError("invalid-state");
266
+ }
267
+ try {
268
+ const { data, remoteAddress } = await worker().run({
269
+ op: "udp-receive",
270
+ socketId: this.#socketId,
271
+ });
272
+ return [new Uint8Array(data), remoteAddress];
273
+ }
274
+ catch (e) {
275
+ throw SocketError.from(e);
276
+ }
277
+ }
278
+ /**
279
+ * Get the current bound address.
280
+ * WIT:
281
+ * ```
282
+ * local-address: func() -> result<ip-socket-address, error-code>
283
+ * ```
284
+ *
285
+ * @returns {Object} The local socket address
286
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket hasn't been bound yet
287
+ * @throws {SocketError} for other errors, payload.tag maps the system error
288
+ */
289
+ getLocalAddress() {
290
+ if (this.#state === STATE.UNBOUND) {
291
+ throw new SocketError("invalid-state");
292
+ }
293
+ try {
294
+ return worker().runSync({
295
+ op: "udp-get-local-address",
296
+ socketId: this.#socketId,
297
+ });
298
+ }
299
+ catch (e) {
300
+ throw SocketError.from(e);
301
+ }
302
+ }
303
+ /**
304
+ * Get the address the socket is currently connected to.
305
+ * WIT:
306
+ * ```
307
+ * remote-address: func() -> result<ip-socket-address, error-code>
308
+ * ```
309
+ *
310
+ * @returns {Object} The connected peer address
311
+ * @throws {SocketError} with payload.tag 'invalid-state' if the socket is not connected
312
+ */
313
+ getRemoteAddress() {
314
+ if (this.#state !== STATE.CONNECTED) {
315
+ throw new SocketError("invalid-state");
316
+ }
317
+ return this.#remote;
318
+ }
319
+ /**
320
+ * Whether this is an IPv4 or IPv6 socket.
321
+ * WIT:
322
+ * ```
323
+ * address-family: func() -> ip-address-family
324
+ * ```
325
+ *
326
+ * @returns {IP_ADDRESS_FAMILY}
327
+ */
328
+ getAddressFamily() {
329
+ return this.#family;
330
+ }
331
+ /**
332
+ * Get the unicast hop limit (TTL).
333
+ * WIT:
334
+ * ```
335
+ * unicast-hop-limit: func() -> result<u8, error-code>
336
+ * ```
337
+ *
338
+ * @returns {number}
339
+ */
340
+ getUnicastHopLimit() {
341
+ return this.#options.hopLimit;
342
+ }
343
+ /**
344
+ * Set the unicast hop limit (TTL).
345
+ * WIT:
346
+ * ```
347
+ * set-unicast-hop-limit: func(value: u8) -> result<_, error-code>
348
+ * ```
349
+ *
350
+ * @param {number} value - The hop limit (must be ≥1)
351
+ * @returns {void}
352
+ * @throws {SocketError} with payload.tag 'invalid-argument' if value < 1
353
+ * @throws {SocketError} for other errors, payload.tag maps the system error
354
+ */
355
+ setUnicastHopLimit(value) {
356
+ if (value < 1) {
357
+ throw new SocketError("invalid-argument");
358
+ }
359
+ this.#options.hopLimit = value;
360
+ if (this.#state === STATE.UNBOUND) {
361
+ return;
362
+ }
363
+ try {
364
+ worker().runSync({
365
+ op: "udp-set-unicast-hop-limit",
366
+ socketId: this.#socketId,
367
+ value,
368
+ });
369
+ }
370
+ catch (e) {
371
+ throw SocketError.from(e);
372
+ }
373
+ }
374
+ /**
375
+ * Get the receive buffer size.
376
+ * WIT:
377
+ * ```
378
+ * receive-buffer-size: func() -> result<u64, error-code>
379
+ * ```
380
+ *
381
+ * @returns {bigint}
382
+ * @throws {SocketError} payload.tag maps the system error
383
+ */
384
+ getReceiveBufferSize() {
385
+ if (this.#options.receiveBufferSize) {
386
+ return this.#options.receiveBufferSize;
387
+ }
388
+ try {
389
+ const size = worker().runSync({
390
+ op: "udp-recv-buffer-size",
391
+ socketId: this.#socketId,
392
+ });
393
+ this.#options.receiveBufferSize = size;
394
+ return size;
395
+ }
396
+ catch (e) {
397
+ throw SocketError.from(e);
398
+ }
399
+ }
400
+ /**
401
+ * Set the receive buffer size.
402
+ * WIT:
403
+ * ```
404
+ * set-receive-buffer-size: func(value: u64) -> result<_, error-code>
405
+ * ```
406
+ *
407
+ * @param {bigint} value - The buffer size in bytes (must be >0)
408
+ * @throws {SocketError} payload.tag maps the system error
409
+ */
410
+ setReceiveBufferSize(value) {
411
+ if (value === 0n) {
412
+ throw new SocketError("invalid-argument");
413
+ }
414
+ this.#options.receiveBufferSize = value;
415
+ }
416
+ /**
417
+ * Get the send buffer size.
418
+ * WIT:
419
+ * ```
420
+ * send-buffer-size: func() -> result<u64, error-code>
421
+ * ```
422
+ *
423
+ * @async
424
+ * @returns {bigint}
425
+ * @throws {SocketError} payload.tag maps the system error
426
+ */
427
+ getSendBufferSize() {
428
+ if (this.#options.sendBufferSize) {
429
+ return this.#options.sendBufferSize;
430
+ }
431
+ try {
432
+ const size = worker().runSync({
433
+ op: "udp-send-buffer-size",
434
+ socketId: this.#socketId,
435
+ });
436
+ this.#options.sendBufferSize = size;
437
+ return size;
438
+ }
439
+ catch (e) {
440
+ throw SocketError.from(e);
441
+ }
442
+ }
443
+ /**
444
+ * Set the send buffer size.
445
+ * WIT:
446
+ * ```
447
+ * set-send-buffer-size: func(value: u64) -> result<_, error-code>
448
+ * ```
449
+ *
450
+ * @param {bigint} value - The buffer size in bytes (must be >0)
451
+ * @throws {SocketError} with payload.tag 'invalid-argument' if value == 0
452
+ */
453
+ setSendBufferSize(value) {
454
+ if (value === 0n) {
455
+ throw new SocketError("invalid-argument");
456
+ }
457
+ this.#options.sendBufferSize = value;
458
+ }
459
+ /**
460
+ * Dispose the socket.
461
+ *
462
+ * Releases native resources and marks the socket as closed.
463
+ */
464
+ [Symbol.dispose]() {
465
+ if (this.#socketId) {
466
+ worker().runSync({
467
+ op: "udp-dispose",
468
+ socketId: this.#socketId,
469
+ });
470
+ }
471
+ this.#socketId = null;
472
+ this.#state = STATE.CLOSED;
473
+ }
474
+ }
475
+ export const udpCreateSocket = {};
@@ -0,0 +1,11 @@
1
+ import { TcpSocket } from "./sockets/tcp.js";
2
+ import { UdpSocket } from "./sockets/udp.js";
3
+ export { ipNameLookup } from "./sockets/ip-name-lookup.js";
4
+ export * from "./sockets/tcp.js";
5
+ export * from "./sockets/udp.js";
6
+ export { IP_ADDRESS_FAMILY } from "./sockets/address.js";
7
+ export { makeIpAddress, serializeIpAddress } from "./sockets/address.js";
8
+ export declare const types: {
9
+ TcpSocket: typeof TcpSocket;
10
+ UdpSocket: typeof UdpSocket;
11
+ };