@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
@@ -1,437 +0,0 @@
1
- export const DEFAULT_BYTE_STREAM_CHUNK_SIZE = 64 * 1024;
2
- const symbolDispose = Symbol.dispose || Symbol.for("dispose");
3
-
4
- let BYTE_STREAM_ENCODER = null;
5
- function encoder() {
6
- return (BYTE_STREAM_ENCODER ??= new TextEncoder());
7
- }
8
-
9
- /**
10
- * Creates a transferable ReadableStream from an async iterator.
11
- *
12
- * Use this when a StreamReader's contents need to be sent to a worker thread,
13
- * since async iterators are not transferable.
14
- *
15
- * @param {AsyncIterator} iterator - The async iterator to wrap.
16
- * @param {string} [name="iterator"] - Optional name for error messages.
17
- * @returns {ReadableStream} A transferable ReadableStream that pulls from the iterator.
18
- */
19
- export function readableStreamFromIterator(iterator, name = "iterator") {
20
- if (
21
- iterator == null ||
22
- iterator == undefined ||
23
- typeof iterator[Symbol.asyncIterator] !== "function"
24
- ) {
25
- throw new TypeError(`${name} must implement [Symbol.asyncIterator]()`);
26
- }
27
-
28
- return new ReadableStream({
29
- async pull(controller) {
30
- const { done, value } = await iterator.next();
31
- if (done) {
32
- controller.close();
33
- } else {
34
- controller.enqueue(value);
35
- }
36
- },
37
- cancel() {
38
- return iterator.return?.();
39
- },
40
- });
41
- }
42
-
43
- /**
44
- * Creates a transferable ReadableStream from a byte-stream reader.
45
- *
46
- * Generated p3 stream readers expose `read({ count })`, which performs one
47
- * bounded Canonical ABI stream read for up to `count` bytes. Prefer that path so
48
- * host byte sinks consume practical chunks instead of one byte at a time.
49
- *
50
- * @param {object} reader - Reader that provides `read()`, or `[Symbol.asyncIterator]()`.
51
- * @param {object} [opts={}] - Optional adapter settings.
52
- * @param {number} [opts.chunkSize=DEFAULT_BYTE_STREAM_CHUNK_SIZE] - Maximum bytes to request per generated `read()` call.
53
- * @param {string} [opts.name="stream reader"] - Reader name used in error messages.
54
- * @returns {ReadableStream<Uint8Array>} A transferable stream of byte chunks.
55
- */
56
- export function readableByteStreamFromReader(reader, opts = {}) {
57
- const source = byteStreamSource(reader, opts);
58
- return new ReadableStream({
59
- async pull(controller) {
60
- const { done, value } = await source.read();
61
- if (done) {
62
- controller.close();
63
- return;
64
- }
65
- controller.enqueue(_byteChunk(value));
66
- },
67
- cancel(reason) {
68
- return source.cancel?.(reason);
69
- },
70
- });
71
- }
72
-
73
- function byteStreamSource(reader, opts) {
74
- const name = opts.name ?? "stream reader";
75
- const chunkSize = opts.chunkSize ?? DEFAULT_BYTE_STREAM_CHUNK_SIZE;
76
- if (!Number.isInteger(chunkSize) || chunkSize < 1) {
77
- throw new TypeError(`invalid byte stream chunk size [${chunkSize}]`);
78
- }
79
-
80
- if (typeof reader?.read === "function") {
81
- return {
82
- async read() {
83
- const result = await reader.read({ count: chunkSize });
84
- if (isIteratorResult(result)) {
85
- return result;
86
- }
87
- return { value: result, done: result === null };
88
- },
89
- cancel(reason) {
90
- if (typeof reader.cancel === "function") {
91
- return reader.cancel(reason);
92
- }
93
- if (typeof reader.close === "function") {
94
- return reader.close();
95
- }
96
- return reader[symbolDispose]?.();
97
- },
98
- };
99
- }
100
-
101
- if (typeof reader?.[Symbol.asyncIterator] === "function") {
102
- const iterator = reader[Symbol.asyncIterator]();
103
- return {
104
- read() {
105
- return iterator.next();
106
- },
107
- cancel(reason) {
108
- return iterator.return?.(reason);
109
- },
110
- };
111
- }
112
-
113
- throw new TypeError(`${name} must provide read() or [Symbol.asyncIterator]()`);
114
- }
115
-
116
- function isIteratorResult(value) {
117
- return value != null && typeof value === "object" && typeof value.done === "boolean";
118
- }
119
-
120
- export function _byteChunk(value) {
121
- if (value instanceof Uint8Array) {
122
- return value;
123
- }
124
- if (value instanceof ArrayBuffer) {
125
- return new Uint8Array(value);
126
- }
127
- if (Array.isArray(value)) {
128
- for (const byte of value) {
129
- assertByte(byte);
130
- }
131
- return Uint8Array.from(value);
132
- }
133
- if (typeof value === "number") {
134
- return Uint8Array.of(assertByte(value));
135
- }
136
- if (typeof value === "string") {
137
- return encoder().encode(value);
138
- }
139
-
140
- throw new TypeError(
141
- "byte stream chunk must be a byte, byte array, ArrayBuffer, Uint8Array, or string",
142
- );
143
- }
144
-
145
- function assertByte(value) {
146
- if (!Number.isInteger(value) || value < 0 || value > 255) {
147
- throw new RangeError(`Invalid byte stream value: ${value}`);
148
- }
149
- return value;
150
- }
151
-
152
- /**
153
- * Creates a bidirectional stream with separate reader and writer interfaces.
154
- *
155
- * Uses a TransformStream internally.
156
- *
157
- * @param {Object} [opts={}] - Configuration options for the stream.
158
- * @param {number} [opts.readableHWM=65536] - High water mark for the readable side (bytes).
159
- * @param {number} [opts.writableHWM=65536] - High water mark for the writable side (bytes).
160
- *
161
- * @returns {Object} An object containing:
162
- * - `tx` {StreamWriter}: The writer for sending data to the stream.
163
- * - `rx` {StreamReader}: The reader for receiving data from the stream.
164
- *
165
- * @example
166
- *
167
- * const { tx, rx } = stream();
168
- * const payload = Buffer.from('roundtrip');
169
- *
170
- * await tx.write(payload);
171
- * await tx.close();
172
- *
173
- * const chunk1 = await rx.read();
174
- * expect(chunk1).toEqual(payload);
175
- *
176
- * const done = await rx.read();
177
- * expect(done).toBeNull();
178
- *
179
- */
180
- export function stream(opts = {}) {
181
- const { readableHWM = 64 * 1024, writableHWM = 64 * 1024 } = opts;
182
-
183
- const transform = new TransformStream(
184
- {},
185
- { highWaterMark: writableHWM },
186
- { highWaterMark: readableHWM },
187
- );
188
-
189
- const tx = new StreamWriter(transform.writable);
190
- const rx = new StreamReader(transform.readable);
191
-
192
- return { tx, rx };
193
- }
194
-
195
- export class StreamReader {
196
- /** Original source ReadableStream or AsyncIterable */
197
- #source = null;
198
- /** Active async iterator obtained from the source */
199
- #iterator = null;
200
- /** Whether the iterator completed on next() call */
201
- #done = false;
202
-
203
- /**
204
- * Constructs a StreamReader.
205
- *
206
- * @param {AsyncIterable|Iterable} source - An async or sync iterable to consume e.g. ReadableStream, async generator, array.
207
- * @throws {Error} If the provided source does not implement `[Symbol.asyncIterator]` or `[Symbol.iterator]`.
208
- */
209
- constructor(source, opts = {}) {
210
- if (
211
- !source ||
212
- (typeof source[Symbol.asyncIterator] !== "function" &&
213
- typeof source[Symbol.iterator] !== "function")
214
- ) {
215
- throw new Error(
216
- "Failed to create StreamReader: provided source must implement [Symbol.asyncIterator]() or [Symbol.iterator]()",
217
- );
218
- }
219
- this.#source = source;
220
- // For ReadableStream, use values() with preventCancel so the underlying
221
- // stream is not cancelled when the iterator is released.
222
- if (source instanceof ReadableStream) {
223
- this.#iterator = source.values({ preventCancel: opts.preventCancel ?? true });
224
- } else if (typeof source[Symbol.asyncIterator] === "function") {
225
- this.#iterator = source[Symbol.asyncIterator]();
226
- } else {
227
- // Wrap a sync iterator as an async one
228
- const syncIterator = source[Symbol.iterator]();
229
- this.#iterator = {
230
- next() {
231
- return Promise.resolve(syncIterator.next());
232
- },
233
- return(val) {
234
- return Promise.resolve(
235
- syncIterator.return ? syncIterator.return(val) : { done: true, value: val },
236
- );
237
- },
238
- };
239
- }
240
- }
241
-
242
- /**
243
- * Reads the next chunk from the stream.
244
- *
245
- * @returns {Promise<any>} Resolves with the next chunk or null if the stream is done.
246
- */
247
- async read() {
248
- if (this.#done) {
249
- return null;
250
- }
251
- this.#ensureIterator();
252
-
253
- const { done, value } = await this.#iterator.next();
254
- if (done) {
255
- this.#done = true;
256
- this.#iterator = null;
257
- return value !== undefined ? value : null;
258
- }
259
- return value;
260
- }
261
-
262
- /**
263
- * Reads all chunks from the stream and concatenates them into a buffer.
264
- *
265
- * @returns {Promise<Buffer>} Resolves with the concatenated buffer.
266
- */
267
- async readAll() {
268
- this.#ensureIterator();
269
-
270
- const chunks = [];
271
- let c;
272
- try {
273
- while ((c = await this.read()) !== null) {
274
- chunks.push(c);
275
- }
276
-
277
- return Buffer.concat(chunks);
278
- } finally {
279
- this.close();
280
- }
281
- }
282
-
283
- /**
284
- * Cancels the stream, signalling a premature exit to the iterator.
285
- *
286
- * @returns {Promise<void>}
287
- */
288
- async cancel(_reason) {
289
- this.#ensureIterator();
290
- if (typeof this.#iterator.return === "function") {
291
- await this.#iterator.return();
292
- }
293
- this.#iterator = null;
294
- }
295
-
296
- /**
297
- * Closes the reader and releases the iterator.
298
- * Only calls return() if the iterator hasn't completed naturally,
299
- * since return() is meant for premature exits only.
300
- */
301
- close() {
302
- if (!this.#iterator) {
303
- return;
304
- }
305
- if (!this.#done && typeof this.#iterator.return === "function") {
306
- this.#iterator.return();
307
- }
308
- this.#iterator = null;
309
- }
310
-
311
- [symbolDispose]() {
312
- this.close();
313
- }
314
-
315
- /**
316
- * Consumes the reader and returns the underlying async iterator.
317
- *
318
- * After calling this method the StreamReader is closed and must not be used.
319
- *
320
- * @returns {AsyncIterator} The remaining async iterator.
321
- */
322
- intoAsyncIterator() {
323
- const iterator = this.#iterator;
324
- this.#iterator = null;
325
- this.#source = null;
326
-
327
- if (!iterator) {
328
- throw new Error("StreamReader is closed");
329
- }
330
-
331
- return iterator;
332
- }
333
-
334
- /**
335
- * Implements the async-iterable protocol so a StreamReader can be used
336
- * directly with `for await…of` and any helper that consumes an
337
- * async iterator (e.g. `readableStreamFromIterator`). Like
338
- * `intoAsyncIterator()` above, this consumes the reader.
339
- *
340
- * @returns {AsyncIterator}
341
- */
342
- [Symbol.asyncIterator]() {
343
- return this.intoAsyncIterator();
344
- }
345
-
346
- #ensureIterator() {
347
- if (this.#iterator === null) {
348
- throw new Error("StreamReader is closed");
349
- }
350
- }
351
- }
352
-
353
- export class StreamWriter {
354
- /** Reference to the original stream object that implements getWriter */
355
- #stream = null;
356
- /** Active reader obtained from the stream */
357
- #writer = null;
358
-
359
- /**
360
- * Constructs a StreamWriter.
361
- *
362
- * @param {WritableStream} writable - The writable stream to write to.
363
- * @throws {Error} If the provided stream does not implement `getWriter`.
364
- */
365
- constructor(writable) {
366
- if (!writable || typeof writable.getWriter !== "function") {
367
- throw new Error("Provided writable must implement getWriter()");
368
- }
369
- this.#stream = writable;
370
- this.#writer = writable.getWriter();
371
- }
372
-
373
- /**
374
- * Writes a chunk to the stream.
375
- *
376
- * @param {*} chunk - The chunk to write.
377
- * @returns {Promise<void>}
378
- */
379
- async write(chunk) {
380
- this.#ensureWriter();
381
- return this.#writer.write(chunk);
382
- }
383
-
384
- /**
385
- * Aborts the stream with the given reason.
386
- *
387
- * @param {*} reason - The reason for aborting the stream.
388
- * @returns {Promise<void>}
389
- */
390
- async abort(reason) {
391
- this.#ensureWriter();
392
- return this.#writer.abort(reason);
393
- }
394
-
395
- /**
396
- * Closes the writer and the stream.
397
- *
398
- * @returns {Promise<void>}
399
- */
400
- async close() {
401
- this.#ensureWriter();
402
- const writer = this.#writer;
403
- this.#writer = null;
404
- await writer.close();
405
- }
406
-
407
- /**
408
- * Closes the writer with an error.
409
- *
410
- * @param {Error} error - The error to close the writer with.
411
- * @returns {Promise<void>}
412
- */
413
- async closeWithError(error) {
414
- this.#ensureWriter();
415
- const writer = this.#writer;
416
- this.#writer = null;
417
- await writer.abort(error);
418
- }
419
-
420
- /**
421
- * Converts the writer back into a writable stream.
422
- *
423
- * @returns {WritableStream} The original writable stream that implements `getWriter()`.
424
- */
425
- async intoWritableStream() {
426
- const stream = this.#stream;
427
- this.#writer = null;
428
- this.#stream = null;
429
- return stream;
430
- }
431
-
432
- #ensureWriter() {
433
- if (this.#writer === null) {
434
- throw new Error("StreamWriter is closed");
435
- }
436
- }
437
- }
@@ -1,49 +0,0 @@
1
- import process from "node:process";
2
- import { Readable } from "node:stream";
3
- import { pipeline } from "stream/promises";
4
-
5
- import { Router } from "../workers/resource-worker.js";
6
-
7
- Router().op("stdout", handleOp).op("stderr", handleOp);
8
-
9
- async function handleOp(msg) {
10
- const { op, stream } = msg;
11
-
12
- const readable = Readable.from(byteChunks(stream), { objectMode: false });
13
- const writable = op === "stdout" ? process.stdout : process.stderr;
14
-
15
- await pipeline(readable, writable, { end: false });
16
- return { ok: true };
17
- }
18
-
19
- async function* byteChunks(stream) {
20
- for await (const value of stream) {
21
- yield nodeByteChunk(value);
22
- }
23
- }
24
-
25
- function assertByte(value) {
26
- if (!Number.isInteger(value) || value < 0 || value > 255) {
27
- throw new RangeError(`Invalid byte stream value: ${value}`);
28
- }
29
- return value;
30
- }
31
-
32
- function nodeByteChunk(value) {
33
- if (value instanceof Uint8Array) {
34
- return value; // also matches Buffer
35
- }
36
- if (value instanceof ArrayBuffer) {
37
- return new Uint8Array(value);
38
- }
39
- if (Array.isArray(value)) {
40
- for (const byte of value) {
41
- assertByte(byte);
42
- }
43
- return Uint8Array.from(value);
44
- }
45
- if (typeof value === "number") {
46
- return Uint8Array.of(assertByte(value));
47
- }
48
- return value;
49
- }
@@ -1,119 +0,0 @@
1
- import { promisify } from "util";
2
-
3
- import { Router } from "./resource-worker.js";
4
- import { FSError } from "../filesystem/error.js";
5
- import { wasiTypeFromDirent } from "../filesystem/utils.js";
6
-
7
- // Use fs callback API for BigInt offset support
8
- import fs from "fs";
9
- const readAsync = promisify(fs.read);
10
- const writeAsync = promisify(fs.write);
11
- const { opendir } = fs.promises;
12
-
13
- const CHUNK_BYTES = 64 * 1024;
14
- // Reuse a single buffer for all read/write ops
15
- const BUFFER = Buffer.alloc(CHUNK_BYTES);
16
- const MAX_SAFE_FILE_POSITION = BigInt(Number.MAX_SAFE_INTEGER);
17
-
18
- /** Auto‐dispatch all ops */
19
- Router().op("read", handleRead).op("write", handleWrite).op("readDir", handleReadDir);
20
-
21
- async function handleRead({ fd, offset, stream }) {
22
- if (typeof fd !== "number" || fd < 0) {
23
- throw new TypeError(`Invalid file descriptor: ${fd}`);
24
- }
25
-
26
- if (!stream || typeof stream.getWriter !== "function") {
27
- throw new TypeError("stream must have a getWriter() method");
28
- }
29
-
30
- const writer = stream.getWriter();
31
- try {
32
- let pos = BigInt(offset);
33
- const start = pos;
34
-
35
- while (true) {
36
- const { bytesRead } = await readAsync(fd, BUFFER, 0, CHUNK_BYTES, filePosition(pos));
37
- if (bytesRead === 0) {
38
- break;
39
- }
40
-
41
- await writer.write(BUFFER.subarray(0, bytesRead));
42
- pos += BigInt(bytesRead);
43
- }
44
-
45
- await writer.close();
46
-
47
- return { bytesRead: pos - start };
48
- } catch (err) {
49
- await writer.abort(err);
50
- throw err;
51
- }
52
- }
53
-
54
- async function handleWrite({ fd, offset, stream }) {
55
- if (typeof fd !== "number" || fd < 0) {
56
- throw new TypeError(`Invalid file descriptor: ${fd}`);
57
- }
58
-
59
- if (!stream || typeof stream.getReader !== "function") {
60
- throw new TypeError("stream must have a getReader() method");
61
- }
62
-
63
- const reader = stream.getReader();
64
- try {
65
- let pos = BigInt(offset);
66
- const start = pos;
67
-
68
- while (true) {
69
- const { done, value } = await reader.read();
70
- if (done) {
71
- break;
72
- }
73
- const buf = Buffer.from(value);
74
- const { bytesWritten } = await writeAsync(fd, buf, 0, buf.length, filePosition(pos));
75
- pos += BigInt(bytesWritten);
76
- }
77
- return { bytesWritten: pos - start };
78
- } catch (err) {
79
- await reader.cancel(err);
80
- throw err;
81
- }
82
- }
83
-
84
- function filePosition(position) {
85
- if (position < 0n || position > MAX_SAFE_FILE_POSITION) {
86
- throw new FSError("invalid");
87
- }
88
- return Number(position);
89
- }
90
-
91
- async function handleReadDir({ fullPath, stream, preopens }) {
92
- if (!stream || typeof stream.getWriter !== "function") {
93
- throw new TypeError("stream must have a getWriter() method");
94
- }
95
-
96
- const writer = stream.getWriter();
97
- const canAccess = preopens.some((p) => fullPath === p || fullPath.startsWith(p + "/"));
98
-
99
- if (!canAccess) {
100
- const err = new FSError("not-permitted");
101
- await writer.abort(err);
102
- throw err;
103
- }
104
-
105
- try {
106
- const walker = await opendir(fullPath);
107
- for await (const dirent of walker) {
108
- await writer.write({
109
- name: dirent.name,
110
- type: wasiTypeFromDirent(dirent),
111
- });
112
- }
113
- await writer.close();
114
- return { ok: true };
115
- } catch (err) {
116
- await writer.abort(err);
117
- throw err;
118
- }
119
- }