@bytecodealliance/preview3-shim 0.2.1 → 0.3.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 (78) hide show
  1. package/dist/browser/cli/environment.d.ts +10 -0
  2. package/dist/browser/cli/environment.js +15 -0
  3. package/dist/browser/cli/exit.d.ts +9 -0
  4. package/dist/browser/cli/exit.js +11 -0
  5. package/dist/browser/cli/run.d.ts +6 -0
  6. package/dist/browser/cli/run.js +7 -0
  7. package/dist/browser/cli/stderr.d.ts +7 -0
  8. package/dist/browser/cli/stderr.js +7 -0
  9. package/dist/browser/cli/stdin.d.ts +7 -0
  10. package/dist/browser/cli/stdin.js +7 -0
  11. package/dist/browser/cli/stdout.d.ts +7 -0
  12. package/dist/browser/cli/stdout.js +7 -0
  13. package/dist/browser/cli/terminal-input.d.ts +8 -0
  14. package/dist/browser/cli/terminal-input.js +5 -0
  15. package/dist/browser/cli/terminal-output.d.ts +8 -0
  16. package/dist/browser/cli/terminal-output.js +5 -0
  17. package/dist/browser/cli/terminal-stderr.d.ts +7 -0
  18. package/dist/browser/cli/terminal-stderr.js +7 -0
  19. package/dist/browser/cli/terminal-stdin.d.ts +7 -0
  20. package/dist/browser/cli/terminal-stdin.js +7 -0
  21. package/dist/browser/cli/terminal-stdout.d.ts +7 -0
  22. package/dist/browser/cli/terminal-stdout.js +7 -0
  23. package/dist/browser/cli.d.ts +11 -0
  24. package/dist/browser/cli.js +11 -0
  25. package/dist/browser/clocks/monotonic-clock.d.ts +13 -0
  26. package/dist/browser/clocks/monotonic-clock.js +19 -0
  27. package/dist/browser/clocks/system-clock.d.ts +9 -0
  28. package/dist/browser/clocks/system-clock.js +11 -0
  29. package/dist/browser/clocks/types.d.ts +3 -0
  30. package/dist/browser/clocks/types.js +1 -0
  31. package/dist/browser/clocks.d.ts +3 -0
  32. package/dist/browser/clocks.js +3 -0
  33. package/dist/browser/filesystem/preopens.d.ts +7 -0
  34. package/dist/browser/filesystem/preopens.js +7 -0
  35. package/dist/browser/filesystem/types.d.ts +33 -0
  36. package/dist/browser/filesystem/types.js +81 -0
  37. package/dist/browser/filesystem.d.ts +2 -0
  38. package/dist/browser/filesystem.js +2 -0
  39. package/dist/browser/http/client.d.ts +7 -0
  40. package/dist/browser/http/client.js +7 -0
  41. package/dist/browser/http/handler.d.ts +7 -0
  42. package/dist/browser/http/handler.js +7 -0
  43. package/dist/browser/http/types.d.ts +50 -0
  44. package/dist/browser/http/types.js +114 -0
  45. package/dist/browser/http.d.ts +3 -0
  46. package/dist/browser/http.js +3 -0
  47. package/dist/browser/index.d.ts +6 -0
  48. package/dist/browser/index.js +6 -0
  49. package/dist/browser/random/insecure-seed.d.ts +6 -0
  50. package/dist/browser/random/insecure-seed.js +7 -0
  51. package/dist/browser/random/insecure.d.ts +8 -0
  52. package/dist/browser/random/insecure.js +11 -0
  53. package/dist/browser/random/random.d.ts +8 -0
  54. package/dist/browser/random/random.js +11 -0
  55. package/dist/browser/random.d.ts +3 -0
  56. package/dist/browser/random.js +3 -0
  57. package/dist/browser/sockets/ip-name-lookup.d.ts +7 -0
  58. package/dist/browser/sockets/ip-name-lookup.js +7 -0
  59. package/dist/browser/sockets/types.d.ts +51 -0
  60. package/dist/browser/sockets/types.js +129 -0
  61. package/dist/browser/sockets.d.ts +2 -0
  62. package/dist/browser/sockets.js +2 -0
  63. package/dist/common/errors.d.ts +3 -0
  64. package/dist/common/errors.js +5 -0
  65. package/dist/nodejs/cli.js +2 -1
  66. package/dist/nodejs/filesystem/descriptor.js +2 -1
  67. package/dist/nodejs/http/client.js +2 -1
  68. package/dist/nodejs/http/server.js +2 -1
  69. package/dist/nodejs/sockets/tcp.js +2 -1
  70. package/dist/nodejs/sockets/udp.js +2 -1
  71. package/dist/nodejs/workers/cli-worker.bundle.js +88 -0
  72. package/dist/nodejs/workers/filesystem-worker.bundle.js +236 -0
  73. package/dist/nodejs/workers/http-worker.bundle.js +403 -0
  74. package/dist/nodejs/workers/resource-worker.d.ts +1 -1
  75. package/dist/nodejs/workers/resource-worker.js +5 -5
  76. package/dist/nodejs/workers/tcp-worker.bundle.js +496 -0
  77. package/dist/nodejs/workers/udp-worker.bundle.js +270 -0
  78. package/package.json +15 -6
@@ -0,0 +1,270 @@
1
+ import { once } from "node:events";
2
+ import { isMainThread, parentPort } from "worker_threads";
3
+ import dgram from "node:dgram";
4
+ //#region dist/nodejs/workers/resource-worker.js
5
+ function Router() {
6
+ const _hooks = {
7
+ beforeAll: null,
8
+ ops: /* @__PURE__ */ new Map()
9
+ };
10
+ if (isMainThread || !parentPort) throw new Error("Router can only be used in worker threads");
11
+ parentPort.on("message", async (msg) => {
12
+ const { _reply, _condvar, ...rest } = msg;
13
+ let result, error, transfer = [];
14
+ try {
15
+ if (_hooks.beforeAll) _hooks.beforeAll(rest);
16
+ const handler = _hooks.ops.get(rest.op);
17
+ if (!handler) throw new Error(`Unknown op ${rest.op}`);
18
+ const outcome = await handler(rest);
19
+ if (outcome && Array.isArray(outcome.transferable)) {
20
+ result = outcome.result;
21
+ transfer = outcome.transferable;
22
+ } else result = outcome;
23
+ } catch (err) {
24
+ error = serializeError(err);
25
+ }
26
+ _reply.postMessage({
27
+ result,
28
+ error
29
+ }, transfer);
30
+ _reply.close();
31
+ if (_condvar) notify(_condvar);
32
+ });
33
+ return {
34
+ beforeAll(fn) {
35
+ _hooks.beforeAll = fn;
36
+ return this;
37
+ },
38
+ op(name, fn) {
39
+ _hooks.ops.set(name, fn);
40
+ return this;
41
+ }
42
+ };
43
+ }
44
+ function serializeError(err) {
45
+ if (!(err instanceof Error)) return err;
46
+ const serialized = {
47
+ __resourceWorkerError: true,
48
+ name: err.name,
49
+ message: err.message,
50
+ stack: err.stack
51
+ };
52
+ for (const key of Reflect.ownKeys(err)) serialized[key] = err[key];
53
+ if (err.cause !== void 0) serialized.cause = serializeError(err.cause);
54
+ return serialized;
55
+ }
56
+ function notify(condvar) {
57
+ const lock = new Int32Array(condvar);
58
+ Atomics.store(lock, 0, 1);
59
+ Atomics.notify(lock, 0, 1);
60
+ }
61
+ //#endregion
62
+ //#region dist/nodejs/sockets/address.js
63
+ const tupleToIpv6 = (segments) => {
64
+ if (segments.length !== 8) return null;
65
+ return segments.map((segment) => segment.toString(16)).join(":");
66
+ };
67
+ const tupleToIpv4 = (segments) => {
68
+ if (segments.length !== 4) return null;
69
+ return segments.map((segment) => segment.toString(10)).join(".");
70
+ };
71
+ const ipv6ToTuple = (ipv6) => {
72
+ const [lhs, rhs = ""] = ipv6.includes("::") ? ipv6.split("::") : [ipv6];
73
+ const lhsParts = lhs === "" ? [] : lhs.split(":");
74
+ const rhsParts = rhs === "" ? [] : rhs.split(":");
75
+ return [
76
+ ...lhsParts,
77
+ ...Array(8 - lhsParts.length - rhsParts.length).fill(0),
78
+ ...rhsParts
79
+ ].map((segment) => {
80
+ const val = parseInt(segment, 16);
81
+ if (val < 0 || val > 65535 || Number.isNaN(val)) throw new Error(`Invalid IPv6 segment: ${segment}`);
82
+ return val;
83
+ });
84
+ };
85
+ const ipv4ToTuple = (ipv4) => {
86
+ return ipv4.split(".").map((segment) => {
87
+ const val = parseInt(segment, 10);
88
+ if (val < 0 || val > 255 || Number.isNaN(val)) throw new Error(`Invalid IPv4 segment: ${segment}`);
89
+ return val;
90
+ });
91
+ };
92
+ const isWildcardIpAddress = ({ val: { address } }) => address.every((b) => b === 0);
93
+ const isLoopbackIpAddress = ({ tag, val: { address } }) => tag === "ipv4" && address[0] === 127 || tag === "ipv6" && address.slice(0, 7).every((segment) => segment === 0) && address[7] === 1;
94
+ const ipAddressConflict = (a, b) => a.tag === b.tag && Number(a.val.port) === Number(b.val.port) && Number(a.val.port) !== 0 && (isWildcardIpAddress(a) || isWildcardIpAddress(b) || a.val.address.every((segment, idx) => segment === b.val.address[idx]));
95
+ /**
96
+ * Serialize a socket‐address to text.
97
+ * @param {{tag:string,val:{address:number[]}}} ipAddr
98
+ * @returns {string|null}
99
+ */
100
+ const serializeIpAddress = ({ tag, val: { address } }) => {
101
+ switch (tag) {
102
+ case "ipv4": return tupleToIpv4(address);
103
+ case "ipv6": return tupleToIpv6(address);
104
+ default: throw new Error(`Unknown IP tag: ${tag}`);
105
+ }
106
+ };
107
+ /**
108
+ * Create a socket‐address object.
109
+ * @param {'ipv4'|'ipv6'} family
110
+ * @param {string} host IP text
111
+ * @param {number|bigint} port
112
+ * @returns {{tag:string,val:Object}}
113
+ */
114
+ const makeIpAddress = (family, host, port) => {
115
+ let address;
116
+ switch (family) {
117
+ case "ipv4":
118
+ address = ipv4ToTuple(host);
119
+ break;
120
+ case "ipv6":
121
+ address = ipv6ToTuple(host);
122
+ break;
123
+ default: throw new Error(`Unknown IP family: ${family}`);
124
+ }
125
+ const base = {
126
+ address,
127
+ port
128
+ };
129
+ return family === "ipv4" ? {
130
+ tag: "ipv4",
131
+ val: base
132
+ } : {
133
+ tag: "ipv6",
134
+ val: {
135
+ ...base,
136
+ flowInfo: 0,
137
+ scopeId: 0
138
+ }
139
+ };
140
+ };
141
+ //#endregion
142
+ //#region dist/nodejs/workers/udp-worker.js
143
+ const sockets = /* @__PURE__ */ new Map();
144
+ let NEXT_SOCKET_ID = 0n;
145
+ function noLookup(ip, _opts, cb) {
146
+ cb(null, ip);
147
+ }
148
+ Router().beforeAll((msg) => {
149
+ if (msg.op !== "udp-create" && !sockets.has(msg.socketId)) throw new Error("Invalid socket ID");
150
+ }).op("udp-create", handleCreate).op("udp-bind", handleBind).op("udp-connect", handleConnect).op("udp-disconnect", handleDisconnect).op("udp-send", handleSend).op("udp-receive", handleReceive).op("udp-get-local-address", handleGetLocal).op("udp-set-unicast-hop-limit", handleSetHop).op("udp-recv-buffer-size", handleRecvBuffer).op("udp-send-buffer-size", handleSendBuffer).op("udp-dispose", handleDispose);
151
+ function handleCreate({ family }) {
152
+ const socketId = NEXT_SOCKET_ID++;
153
+ const socket = {
154
+ family,
155
+ connected: null,
156
+ localAddress: null,
157
+ receiveQueue: []
158
+ };
159
+ socket.udp = createSocket(socket);
160
+ sockets.set(socketId, socket);
161
+ return { socketId };
162
+ }
163
+ function createSocket(socket) {
164
+ const type = socket.family === "ipv6" ? "udp6" : "udp4";
165
+ const ipv6Only = socket.family === "ipv6";
166
+ const udp = dgram.createSocket({
167
+ type,
168
+ ipv6Only,
169
+ reuseAddr: false,
170
+ lookup: noLookup
171
+ });
172
+ udp.on("message", (msg, rinfo) => socket.receiveQueue.push({
173
+ msg,
174
+ rinfo
175
+ }));
176
+ udp.on("error", () => {});
177
+ return udp;
178
+ }
179
+ async function handleBind({ socketId, localAddress }) {
180
+ const socket = sockets.get(socketId);
181
+ if ([...sockets].some(([id, { localAddress: boundAddress }]) => id !== socketId && boundAddress && ipAddressConflict(boundAddress, localAddress))) {
182
+ const err = /* @__PURE__ */ new Error("EADDRINUSE");
183
+ err.code = "EADDRINUSE";
184
+ throw err;
185
+ }
186
+ const addr = serializeIpAddress(localAddress);
187
+ const port = localAddress.val.port;
188
+ const onListening = once(socket.udp, "listening");
189
+ const onError = once(socket.udp, "error").then(([err]) => {
190
+ throw err;
191
+ });
192
+ socket.udp.bind(port, addr);
193
+ await Promise.race([onListening, onError]);
194
+ const boundAddr = socket.udp.address();
195
+ socket.localAddress = makeIpAddress(socket.family, boundAddr.address, boundAddr.port);
196
+ }
197
+ async function handleConnect({ socketId, remoteAddress }) {
198
+ const socket = sockets.get(socketId);
199
+ const preserveLocalAddress = socket.connected && socket.localAddress && isLoopbackIpAddress(socket.connected) && isLoopbackIpAddress(remoteAddress);
200
+ if (socket.connected) {
201
+ const localAddress = preserveLocalAddress ? socket.localAddress : null;
202
+ await new Promise((resolve) => socket.udp.close(resolve));
203
+ socket.udp = createSocket(socket);
204
+ if (localAddress) await handleBind({
205
+ socketId,
206
+ localAddress
207
+ });
208
+ else socket.localAddress = null;
209
+ }
210
+ const addr = serializeIpAddress(remoteAddress);
211
+ const port = remoteAddress.val.port;
212
+ await new Promise((resolve, reject) => {
213
+ socket.udp.connect(port, addr, (err) => err ? reject(err) : resolve());
214
+ });
215
+ const boundAddr = socket.udp.address();
216
+ socket.localAddress = makeIpAddress(socket.family, boundAddr.address, boundAddr.port);
217
+ socket.connected = remoteAddress;
218
+ }
219
+ function handleDisconnect({ socketId }) {
220
+ const socket = sockets.get(socketId);
221
+ socket.udp.disconnect();
222
+ socket.connected = null;
223
+ }
224
+ async function handleSend({ socketId, data, remoteAddress }) {
225
+ const socket = sockets.get(socketId);
226
+ const isConnected = socket.connected != null;
227
+ await new Promise((resolve, reject) => {
228
+ if (isConnected) socket.udp.send(data, (err) => err ? reject(err) : resolve());
229
+ else {
230
+ const addr = serializeIpAddress(remoteAddress);
231
+ const port = remoteAddress.val.port;
232
+ socket.udp.send(data, port, addr, (err) => err ? reject(err) : resolve());
233
+ }
234
+ });
235
+ const boundAddr = socket.udp.address();
236
+ socket.localAddress = makeIpAddress(socket.family, boundAddr.address, boundAddr.port);
237
+ }
238
+ async function handleReceive({ socketId }) {
239
+ const socket = sockets.get(socketId);
240
+ if (socket.receiveQueue.length === 0) await Promise.race([once(socket.udp, "message"), once(socket.udp, "error").then(([err]) => {
241
+ throw err;
242
+ })]);
243
+ const { msg, rinfo } = socket.receiveQueue.shift();
244
+ return {
245
+ data: msg,
246
+ remoteAddress: makeIpAddress(socket.family, rinfo.address, rinfo.port)
247
+ };
248
+ }
249
+ function handleGetLocal({ socketId }) {
250
+ const socket = sockets.get(socketId);
251
+ const addr = socket.udp.address();
252
+ return makeIpAddress(socket.family, addr.address, addr.port);
253
+ }
254
+ function handleSetHop({ socketId, value }) {
255
+ sockets.get(socketId).udp.setTTL(value);
256
+ }
257
+ function handleRecvBuffer({ socketId }) {
258
+ const socket = sockets.get(socketId);
259
+ return BigInt(socket.udp.getRecvBufferSize());
260
+ }
261
+ function handleSendBuffer({ socketId }) {
262
+ const socket = sockets.get(socketId);
263
+ return BigInt(socket.udp.getSendBufferSize());
264
+ }
265
+ function handleDispose({ socketId }) {
266
+ sockets.get(socketId).udp.close();
267
+ sockets.delete(socketId);
268
+ }
269
+ //#endregion
270
+ export { noLookup };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/preview3-shim",
3
- "version": "0.2.1",
3
+ "version": "0.3.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": {
@@ -28,12 +28,20 @@
28
28
  "type": "module",
29
29
  "exports": {
30
30
  ".": {
31
- "types": "./dist/nodejs/index.d.ts",
32
- "node": "./dist/nodejs/index.js"
31
+ "types": "./dist/browser/index.d.ts",
32
+ "node": {
33
+ "types": "./dist/nodejs/index.d.ts",
34
+ "default": "./dist/nodejs/index.js"
35
+ },
36
+ "default": "./dist/browser/index.js"
33
37
  },
34
38
  "./*": {
35
- "types": "./dist/nodejs/*.d.ts",
36
- "node": "./dist/nodejs/*.js"
39
+ "types": "./dist/browser/*.d.ts",
40
+ "node": {
41
+ "types": "./dist/nodejs/*.d.ts",
42
+ "default": "./dist/nodejs/*.js"
43
+ },
44
+ "default": "./dist/browser/*.js"
37
45
  },
38
46
  "./interfaces/*": {
39
47
  "types": "./types/interfaces/*.d.ts"
@@ -45,12 +53,13 @@
45
53
  "devDependencies": {
46
54
  "@types/node": "^24.12.4",
47
55
  "globals": "^17.6.0",
56
+ "rolldown": "^1.2.0",
48
57
  "typescript": "^6.0.3",
49
58
  "vite": "^8.0.16",
50
59
  "vitest": "^4.0.8"
51
60
  },
52
61
  "scripts": {
53
- "build": "tsc --project tsconfig.build.json",
62
+ "build": "tsc --project tsconfig.build.json && node scripts/build-workers.mjs",
54
63
  "build:watch": "tsc --watch",
55
64
  "types:check": "tsc --noEmit",
56
65
  "fmt": "oxfmt",