@bytecodealliance/preview2-shim 0.20.1 → 0.20.2

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.
@@ -38,7 +38,7 @@ declare class Descriptor implements TypesNamespace.Descriptor {
38
38
  advise(offset: Filesize, length: Filesize, advice: TypesNamespace.Advice): void;
39
39
  syncData(): void;
40
40
  getFlags(): TypesNamespace.DescriptorFlags;
41
- getType(): "directory" | "regular-file" | "unknown" | "fifo";
41
+ getType(): "directory" | "fifo" | "regular-file" | "unknown";
42
42
  setSize(size: bigint): void;
43
43
  setTimes(dataAccessTimestamp: any, dataModificationTimestamp: any): void;
44
44
  read(length: bigint, offset: bigint): [Uint8Array<ArrayBufferLike>, boolean];
@@ -29,6 +29,17 @@ export declare const OUTPUT_STREAM_BLOCKING_SPLICE: number;
29
29
  export declare const OUTPUT_STREAM_SUBSCRIBE: number;
30
30
  export declare const OUTPUT_STREAM_DISPOSE: number;
31
31
  export declare const OUTPUT_STREAM_GET_TOTAL_BYTES: number;
32
+ export declare const FILESYSTEM_DESCRIPTOR_OPEN: number;
33
+ export declare const FILESYSTEM_DESCRIPTOR_CLOSE: number;
34
+ export declare const FILESYSTEM_DESCRIPTOR_SYNC_DATA: number;
35
+ export declare const FILESYSTEM_DESCRIPTOR_GET_TYPE: number;
36
+ export declare const FILESYSTEM_DESCRIPTOR_SET_SIZE: number;
37
+ export declare const FILESYSTEM_DESCRIPTOR_SET_TIMES: number;
38
+ export declare const FILESYSTEM_DESCRIPTOR_READ: number;
39
+ export declare const FILESYSTEM_DESCRIPTOR_WRITE: number;
40
+ export declare const FILESYSTEM_DESCRIPTOR_SYNC: number;
41
+ export declare const FILESYSTEM_DESCRIPTOR_STAT: number;
42
+ export declare const FILESYSTEM_DESCRIPTOR_METADATA_HASH: number;
32
43
  export declare const POLL_POLLABLE_READY: number;
33
44
  export declare const POLL_POLLABLE_BLOCK: number;
34
45
  export declare const POLL_POLLABLE_DISPOSE: number;
package/dist/io/calls.js CHANGED
@@ -35,6 +35,18 @@ export const OUTPUT_STREAM_BLOCKING_SPLICE = ++call_id << CALL_SHIFT;
35
35
  export const OUTPUT_STREAM_SUBSCRIBE = ++call_id << CALL_SHIFT;
36
36
  export const OUTPUT_STREAM_DISPOSE = ++call_id << CALL_SHIFT;
37
37
  export const OUTPUT_STREAM_GET_TOTAL_BYTES = ++call_id << CALL_SHIFT;
38
+ // Filesystem descriptors
39
+ export const FILESYSTEM_DESCRIPTOR_OPEN = ++call_id << CALL_SHIFT;
40
+ export const FILESYSTEM_DESCRIPTOR_CLOSE = ++call_id << CALL_SHIFT;
41
+ export const FILESYSTEM_DESCRIPTOR_SYNC_DATA = ++call_id << CALL_SHIFT;
42
+ export const FILESYSTEM_DESCRIPTOR_GET_TYPE = ++call_id << CALL_SHIFT;
43
+ export const FILESYSTEM_DESCRIPTOR_SET_SIZE = ++call_id << CALL_SHIFT;
44
+ export const FILESYSTEM_DESCRIPTOR_SET_TIMES = ++call_id << CALL_SHIFT;
45
+ export const FILESYSTEM_DESCRIPTOR_READ = ++call_id << CALL_SHIFT;
46
+ export const FILESYSTEM_DESCRIPTOR_WRITE = ++call_id << CALL_SHIFT;
47
+ export const FILESYSTEM_DESCRIPTOR_SYNC = ++call_id << CALL_SHIFT;
48
+ export const FILESYSTEM_DESCRIPTOR_STAT = ++call_id << CALL_SHIFT;
49
+ export const FILESYSTEM_DESCRIPTOR_METADATA_HASH = ++call_id << CALL_SHIFT;
38
50
  // Io Poll
39
51
  export const POLL_POLLABLE_READY = ++call_id << CALL_SHIFT;
40
52
  export const POLL_POLLABLE_BLOCK = ++call_id << CALL_SHIFT;
@@ -0,0 +1,29 @@
1
+ export declare function openFileResource(path: string, flags: number): Promise<{
2
+ id: number;
3
+ type: any;
4
+ }>;
5
+ export declare function retainFileResource(id: number): number;
6
+ export declare function releaseFileResource(id: number): Promise<void>;
7
+ export declare function fileResourceFd(id: number): number;
8
+ export declare function syncFileResourceData(id: number): Promise<void>;
9
+ export declare function getFileResourceType(id: number): Promise<"block-device" | "character-device" | "directory" | "fifo" | "regular-file" | "socket" | "symbolic-link" | "unknown">;
10
+ export declare function setFileResourceSize(id: number, size: number): Promise<void>;
11
+ export declare function setFileResourceTimes(id: number, atime: number, mtime: number): Promise<void>;
12
+ export declare function readFileResource(id: number, length: number, offset: number): Promise<{
13
+ bytes: Uint8Array<ArrayBuffer>;
14
+ eof: boolean;
15
+ }>;
16
+ export declare function writeFileResource(id: number, buffer: Uint8Array, offset: number): Promise<number>;
17
+ export declare function syncFileResource(id: number): Promise<void>;
18
+ export declare function statFileResource(id: number): Promise<{
19
+ type: string;
20
+ nlink: bigint;
21
+ size: bigint;
22
+ atimeNs: bigint;
23
+ mtimeNs: bigint;
24
+ ctimeNs: bigint;
25
+ }>;
26
+ export declare function metadataHashFileResource(id: number): Promise<{
27
+ upper: bigint;
28
+ lower: bigint;
29
+ }>;
@@ -0,0 +1,116 @@
1
+ import fs from "node:fs";
2
+ import { promisify } from "node:util";
3
+ const closeAsync = promisify(fs.close);
4
+ const fdatasyncAsync = promisify(fs.fdatasync);
5
+ const fstatAsync = promisify(fs.fstat);
6
+ const fsyncAsync = promisify(fs.fsync);
7
+ const ftruncateAsync = promisify(fs.ftruncate);
8
+ const futimesAsync = promisify(fs.futimes);
9
+ const openAsync = promisify(fs.open);
10
+ const readAsync = promisify(fs.read);
11
+ const writeAsync = promisify(fs.write);
12
+ let nextFileResourceId = 0;
13
+ const fileResources = new Map();
14
+ function lookupType(obj) {
15
+ if (obj.isFile()) {
16
+ return "regular-file";
17
+ }
18
+ if (obj.isSocket()) {
19
+ return "socket";
20
+ }
21
+ if (obj.isSymbolicLink()) {
22
+ return "symbolic-link";
23
+ }
24
+ if (obj.isFIFO()) {
25
+ return "fifo";
26
+ }
27
+ if (obj.isDirectory()) {
28
+ return "directory";
29
+ }
30
+ if (obj.isCharacterDevice()) {
31
+ return "character-device";
32
+ }
33
+ if (obj.isBlockDevice()) {
34
+ return "block-device";
35
+ }
36
+ return "unknown";
37
+ }
38
+ function getFileResource(id) {
39
+ const resource = fileResources.get(id);
40
+ if (!resource) {
41
+ const error = new Error(`Invalid filesystem descriptor resource: ${id}`);
42
+ error.code = "EBADF";
43
+ throw error;
44
+ }
45
+ return resource;
46
+ }
47
+ export async function openFileResource(path, flags) {
48
+ const fd = await openAsync(path, flags);
49
+ let type;
50
+ try {
51
+ type = lookupType(await fstatAsync(fd, { bigint: true }));
52
+ }
53
+ catch (error) {
54
+ await closeAsync(fd);
55
+ throw error;
56
+ }
57
+ const id = ++nextFileResourceId;
58
+ fileResources.set(id, { fd, refs: 1 });
59
+ return { id, type };
60
+ }
61
+ export function retainFileResource(id) {
62
+ getFileResource(id).refs++;
63
+ return id;
64
+ }
65
+ export async function releaseFileResource(id) {
66
+ const resource = getFileResource(id);
67
+ if (--resource.refs === 0) {
68
+ fileResources.delete(id);
69
+ await closeAsync(resource.fd);
70
+ }
71
+ }
72
+ export function fileResourceFd(id) {
73
+ return getFileResource(id).fd;
74
+ }
75
+ export async function syncFileResourceData(id) {
76
+ await fdatasyncAsync(fileResourceFd(id));
77
+ }
78
+ export async function getFileResourceType(id) {
79
+ return lookupType(await fstatAsync(fileResourceFd(id), { bigint: true }));
80
+ }
81
+ export async function setFileResourceSize(id, size) {
82
+ await ftruncateAsync(fileResourceFd(id), size);
83
+ }
84
+ export async function setFileResourceTimes(id, atime, mtime) {
85
+ await futimesAsync(fileResourceFd(id), atime, mtime);
86
+ }
87
+ export async function readFileResource(id, length, offset) {
88
+ const buffer = new Uint8Array(length);
89
+ const result = await readAsync(fileResourceFd(id), buffer, 0, length, offset);
90
+ // Deno v1 returns the byte count directly, while Node returns an object
91
+ // containing the byte count and buffer through util.promisify's custom args.
92
+ const bytesRead = typeof result === "number" ? result : result.bytesRead;
93
+ return { bytes: buffer.subarray(0, bytesRead), eof: bytesRead === 0 };
94
+ }
95
+ export async function writeFileResource(id, buffer, offset) {
96
+ const result = await writeAsync(fileResourceFd(id), buffer, 0, buffer.byteLength, offset);
97
+ return typeof result === "number" ? result : result.bytesWritten;
98
+ }
99
+ export async function syncFileResource(id) {
100
+ await fsyncAsync(fileResourceFd(id));
101
+ }
102
+ export async function statFileResource(id) {
103
+ const stats = await fstatAsync(fileResourceFd(id), { bigint: true });
104
+ return {
105
+ type: lookupType(stats),
106
+ nlink: stats.nlink,
107
+ size: stats.size,
108
+ atimeNs: stats.atimeNs,
109
+ mtimeNs: stats.mtimeNs,
110
+ ctimeNs: stats.ctimeNs,
111
+ };
112
+ }
113
+ export async function metadataHashFileResource(id) {
114
+ const stats = await fstatAsync(fileResourceFd(id), { bigint: true });
115
+ return { upper: stats.mtimeNs, lower: stats.ino };
116
+ }
@@ -2,13 +2,13 @@ export declare function stopHttpServer(id: any): Promise<void>;
2
2
  export declare function clearOutgoingResponse(id: any): void;
3
3
  export declare function getHttpServerAddress(id: any): Promise<any>;
4
4
  export declare function setOutgoingResponse(id: any, { statusCode, headers, streamId }: {
5
- statusCode: any;
6
5
  headers: any;
6
+ statusCode: any;
7
7
  streamId: any;
8
8
  }): Promise<void>;
9
9
  export declare function startHttpServer(id: number, { port, host }: {
10
- port: any;
11
10
  host: any;
11
+ port: any;
12
12
  }): Promise<void>;
13
13
  export declare function createHttpRequest(method: any, scheme: any, authority: any, pathWithQuery: any, headers: any, bodyId: any, connectTimeout: any, betweenBytesTimeout: any, firstByteTimeout: any): Promise<{
14
14
  status: number | undefined;
@@ -11,12 +11,12 @@ export declare function noLookup(ip: any, _opts: any, cb: any): void;
11
11
  export declare function socketResolveAddress(name: string): Promise<{
12
12
  tag: string;
13
13
  val: Ipv4Address | Ipv6Address;
14
- }[]> | Promise<{
14
+ }[][]> | Promise<{
15
15
  tag: string;
16
16
  val: Ipv4Address | Ipv6Address;
17
- }[][]>;
18
- export declare function convertSocketError(err: any): "unknown" | "would-block" | "connection-refused" | "invalid-argument" | "invalid-state" | "access-denied" | "not-supported" | "out-of-memory" | "concurrency-conflict" | "address-not-bindable" | "address-in-use" | "connection-reset" | "connection-aborted";
19
- export declare function convertSocketErrorCode(code: any): "unknown" | "would-block" | "connection-refused" | "invalid-argument" | "invalid-state" | "access-denied" | "not-supported" | "out-of-memory" | "concurrency-conflict" | "address-not-bindable" | "address-in-use" | "connection-reset" | "connection-aborted";
17
+ }[]>;
18
+ export declare function convertSocketError(err: any): "access-denied" | "address-in-use" | "address-not-bindable" | "concurrency-conflict" | "connection-aborted" | "connection-refused" | "connection-reset" | "invalid-argument" | "invalid-state" | "not-supported" | "out-of-memory" | "unknown" | "would-block";
19
+ export declare function convertSocketErrorCode(code: any): "access-denied" | "address-in-use" | "address-not-bindable" | "concurrency-conflict" | "connection-aborted" | "connection-refused" | "connection-reset" | "invalid-argument" | "invalid-state" | "not-supported" | "out-of-memory" | "unknown" | "would-block";
20
20
  export declare function tupleToIPv6(arr: Ipv6Address): string | null;
21
21
  export declare function tupleToIpv4(arr: Ipv4Address): string | null;
22
22
  export declare function isMulticastIpAddress(ipSocketAddress: IpSocketAddress): boolean;
@@ -1,9 +1,10 @@
1
- import { createReadStream, createWriteStream, read } from "node:fs";
1
+ import fs, { createReadStream, createWriteStream, read } from "node:fs";
2
2
  import process, { hrtime, nextTick, stderr, stdout } from "node:process";
3
3
  import { PassThrough, Readable } from "node:stream";
4
4
  import { parentPort, workerData } from "node:worker_threads";
5
5
  import { Agent, createServer, request } from "node:http";
6
6
  import { Agent as Agent$1, request as request$1 } from "node:https";
7
+ import { promisify } from "node:util";
7
8
  import { Server, Socket, isIP } from "node:net";
8
9
  import { lookup } from "node:dns/promises";
9
10
  import { createSocket } from "node:dgram";
@@ -78,6 +79,17 @@ var calls_exports = /* @__PURE__ */ __exportAll({
78
79
  CLOCKS_DURATION_SUBSCRIBE: () => CLOCKS_DURATION_SUBSCRIBE,
79
80
  CLOCKS_INSTANT_SUBSCRIBE: () => CLOCKS_INSTANT_SUBSCRIBE,
80
81
  FILE: () => FILE,
82
+ FILESYSTEM_DESCRIPTOR_CLOSE: () => FILESYSTEM_DESCRIPTOR_CLOSE,
83
+ FILESYSTEM_DESCRIPTOR_GET_TYPE: () => FILESYSTEM_DESCRIPTOR_GET_TYPE,
84
+ FILESYSTEM_DESCRIPTOR_METADATA_HASH: () => FILESYSTEM_DESCRIPTOR_METADATA_HASH,
85
+ FILESYSTEM_DESCRIPTOR_OPEN: () => FILESYSTEM_DESCRIPTOR_OPEN,
86
+ FILESYSTEM_DESCRIPTOR_READ: () => FILESYSTEM_DESCRIPTOR_READ,
87
+ FILESYSTEM_DESCRIPTOR_SET_SIZE: () => FILESYSTEM_DESCRIPTOR_SET_SIZE,
88
+ FILESYSTEM_DESCRIPTOR_SET_TIMES: () => FILESYSTEM_DESCRIPTOR_SET_TIMES,
89
+ FILESYSTEM_DESCRIPTOR_STAT: () => FILESYSTEM_DESCRIPTOR_STAT,
90
+ FILESYSTEM_DESCRIPTOR_SYNC: () => FILESYSTEM_DESCRIPTOR_SYNC,
91
+ FILESYSTEM_DESCRIPTOR_SYNC_DATA: () => FILESYSTEM_DESCRIPTOR_SYNC_DATA,
92
+ FILESYSTEM_DESCRIPTOR_WRITE: () => FILESYSTEM_DESCRIPTOR_WRITE,
81
93
  FUTURE_DISPOSE: () => FUTURE_DISPOSE,
82
94
  FUTURE_SUBSCRIBE: () => FUTURE_SUBSCRIBE,
83
95
  FUTURE_TAKE_VALUE: () => FUTURE_TAKE_VALUE,
@@ -195,6 +207,17 @@ const OUTPUT_STREAM_BLOCKING_SPLICE = ++call_id << 24;
195
207
  const OUTPUT_STREAM_SUBSCRIBE = ++call_id << 24;
196
208
  const OUTPUT_STREAM_DISPOSE = ++call_id << 24;
197
209
  const OUTPUT_STREAM_GET_TOTAL_BYTES = ++call_id << 24;
210
+ const FILESYSTEM_DESCRIPTOR_OPEN = ++call_id << 24;
211
+ const FILESYSTEM_DESCRIPTOR_CLOSE = ++call_id << 24;
212
+ const FILESYSTEM_DESCRIPTOR_SYNC_DATA = ++call_id << 24;
213
+ const FILESYSTEM_DESCRIPTOR_GET_TYPE = ++call_id << 24;
214
+ const FILESYSTEM_DESCRIPTOR_SET_SIZE = ++call_id << 24;
215
+ const FILESYSTEM_DESCRIPTOR_SET_TIMES = ++call_id << 24;
216
+ const FILESYSTEM_DESCRIPTOR_READ = ++call_id << 24;
217
+ const FILESYSTEM_DESCRIPTOR_WRITE = ++call_id << 24;
218
+ const FILESYSTEM_DESCRIPTOR_SYNC = ++call_id << 24;
219
+ const FILESYSTEM_DESCRIPTOR_STAT = ++call_id << 24;
220
+ const FILESYSTEM_DESCRIPTOR_METADATA_HASH = ++call_id << 24;
198
221
  const POLL_POLLABLE_READY = ++call_id << 24;
199
222
  const POLL_POLLABLE_BLOCK = ++call_id << 24;
200
223
  const POLL_POLLABLE_DISPOSE = ++call_id << 24;
@@ -403,6 +426,117 @@ function getFirstError(e) {
403
426
  return e;
404
427
  }
405
428
  //#endregion
429
+ //#region dist/io/worker-filesystem.js
430
+ const closeAsync = promisify(fs.close);
431
+ const fdatasyncAsync = promisify(fs.fdatasync);
432
+ const fstatAsync = promisify(fs.fstat);
433
+ const fsyncAsync = promisify(fs.fsync);
434
+ const ftruncateAsync = promisify(fs.ftruncate);
435
+ const futimesAsync = promisify(fs.futimes);
436
+ const openAsync = promisify(fs.open);
437
+ const readAsync = promisify(fs.read);
438
+ const writeAsync = promisify(fs.write);
439
+ let nextFileResourceId = 0;
440
+ const fileResources = /* @__PURE__ */ new Map();
441
+ function lookupType(obj) {
442
+ if (obj.isFile()) return "regular-file";
443
+ if (obj.isSocket()) return "socket";
444
+ if (obj.isSymbolicLink()) return "symbolic-link";
445
+ if (obj.isFIFO()) return "fifo";
446
+ if (obj.isDirectory()) return "directory";
447
+ if (obj.isCharacterDevice()) return "character-device";
448
+ if (obj.isBlockDevice()) return "block-device";
449
+ return "unknown";
450
+ }
451
+ function getFileResource(id) {
452
+ const resource = fileResources.get(id);
453
+ if (!resource) {
454
+ const error = /* @__PURE__ */ new Error(`Invalid filesystem descriptor resource: ${id}`);
455
+ error.code = "EBADF";
456
+ throw error;
457
+ }
458
+ return resource;
459
+ }
460
+ async function openFileResource(path, flags) {
461
+ const fd = await openAsync(path, flags);
462
+ let type;
463
+ try {
464
+ type = lookupType(await fstatAsync(fd, { bigint: true }));
465
+ } catch (error) {
466
+ await closeAsync(fd);
467
+ throw error;
468
+ }
469
+ const id = ++nextFileResourceId;
470
+ fileResources.set(id, {
471
+ fd,
472
+ refs: 1
473
+ });
474
+ return {
475
+ id,
476
+ type
477
+ };
478
+ }
479
+ function retainFileResource(id) {
480
+ getFileResource(id).refs++;
481
+ return id;
482
+ }
483
+ async function releaseFileResource(id) {
484
+ const resource = getFileResource(id);
485
+ if (--resource.refs === 0) {
486
+ fileResources.delete(id);
487
+ await closeAsync(resource.fd);
488
+ }
489
+ }
490
+ function fileResourceFd(id) {
491
+ return getFileResource(id).fd;
492
+ }
493
+ async function syncFileResourceData(id) {
494
+ await fdatasyncAsync(fileResourceFd(id));
495
+ }
496
+ async function getFileResourceType(id) {
497
+ return lookupType(await fstatAsync(fileResourceFd(id), { bigint: true }));
498
+ }
499
+ async function setFileResourceSize(id, size) {
500
+ await ftruncateAsync(fileResourceFd(id), size);
501
+ }
502
+ async function setFileResourceTimes(id, atime, mtime) {
503
+ await futimesAsync(fileResourceFd(id), atime, mtime);
504
+ }
505
+ async function readFileResource(id, length, offset) {
506
+ const buffer = new Uint8Array(length);
507
+ const result = await readAsync(fileResourceFd(id), buffer, 0, length, offset);
508
+ const bytesRead = typeof result === "number" ? result : result.bytesRead;
509
+ return {
510
+ bytes: buffer.subarray(0, bytesRead),
511
+ eof: bytesRead === 0
512
+ };
513
+ }
514
+ async function writeFileResource(id, buffer, offset) {
515
+ const result = await writeAsync(fileResourceFd(id), buffer, 0, buffer.byteLength, offset);
516
+ return typeof result === "number" ? result : result.bytesWritten;
517
+ }
518
+ async function syncFileResource(id) {
519
+ await fsyncAsync(fileResourceFd(id));
520
+ }
521
+ async function statFileResource(id) {
522
+ const stats = await fstatAsync(fileResourceFd(id), { bigint: true });
523
+ return {
524
+ type: lookupType(stats),
525
+ nlink: stats.nlink,
526
+ size: stats.size,
527
+ atimeNs: stats.atimeNs,
528
+ mtimeNs: stats.mtimeNs,
529
+ ctimeNs: stats.ctimeNs
530
+ };
531
+ }
532
+ async function metadataHashFileResource(id) {
533
+ const stats = await fstatAsync(fileResourceFd(id), { bigint: true });
534
+ return {
535
+ upper: stats.mtimeNs,
536
+ lower: stats.ino
537
+ };
538
+ }
539
+ //#endregion
406
540
  //#region dist/io/worker-sockets.js
407
541
  let stateCnt = 0;
408
542
  const SOCKET_STATE_INIT = ++stateCnt;
@@ -1067,9 +1201,10 @@ async function socketOutgoingDatagramStreamSend(id, datagrams) {
1067
1201
  const address = remoteAddress ? serializeIpAddress(remoteAddress) : socket.remoteAddress;
1068
1202
  const port = remoteAddress?.val.port ?? socket.remotePort;
1069
1203
  let sendLastBatch = true;
1070
- if (sendQueue.length > 0) if (sendQueueAddress === address && sendQueuePort === port) sendQueue.push(data);
1071
- else sendLastBatch = true;
1072
- else {
1204
+ if (sendQueue.length > 0) {
1205
+ if (sendQueueAddress === address && sendQueuePort === port) sendQueue.push(data);
1206
+ else sendLastBatch = true;
1207
+ } else {
1073
1208
  sendQueueAddress = address;
1074
1209
  sendQueuePort = port;
1075
1210
  sendQueue.push(data);
@@ -1419,24 +1554,41 @@ function handle(call, id, payload) {
1419
1554
  subscribeInstant(pollState, payload);
1420
1555
  return createPoll(pollState);
1421
1556
  }
1557
+ case FILESYSTEM_DESCRIPTOR_OPEN: return openFileResource(payload.path, payload.flags);
1558
+ case FILESYSTEM_DESCRIPTOR_CLOSE: return releaseFileResource(id);
1559
+ case FILESYSTEM_DESCRIPTOR_SYNC_DATA: return syncFileResourceData(id);
1560
+ case FILESYSTEM_DESCRIPTOR_GET_TYPE: return getFileResourceType(id);
1561
+ case FILESYSTEM_DESCRIPTOR_SET_SIZE: return setFileResourceSize(id, payload);
1562
+ case FILESYSTEM_DESCRIPTOR_SET_TIMES: return setFileResourceTimes(id, payload.atime, payload.mtime);
1563
+ case FILESYSTEM_DESCRIPTOR_READ: return readFileResource(id, payload.length, payload.offset);
1564
+ case FILESYSTEM_DESCRIPTOR_WRITE: return writeFileResource(id, payload.buffer, payload.offset);
1565
+ case FILESYSTEM_DESCRIPTOR_SYNC: return syncFileResource(id);
1566
+ case FILESYSTEM_DESCRIPTOR_STAT: return statFileResource(id);
1567
+ case FILESYSTEM_DESCRIPTOR_METADATA_HASH: return metadataHashFileResource(id);
1422
1568
  case INPUT_STREAM_CREATE | FILE: {
1423
- const { fd, offset } = payload;
1424
- return createReadableStream(createReadStream(null, {
1569
+ const { descriptorId, offset } = payload;
1570
+ const fd = fileResourceFd(descriptorId);
1571
+ const streamId = createReadableStream(createReadStream(null, {
1425
1572
  fd,
1426
1573
  autoClose: false,
1427
- highWaterMark: 64 * 1024,
1574
+ highWaterMark: 65536,
1428
1575
  start: Number(offset)
1429
1576
  }));
1577
+ streams.get(streamId).fileResourceId = retainFileResource(descriptorId);
1578
+ return streamId;
1430
1579
  }
1431
1580
  case OUTPUT_STREAM_CREATE | FILE: {
1432
- const { fd, offset } = payload;
1433
- return createWritableStream(createWriteStream(null, {
1581
+ const { descriptorId, offset } = payload;
1582
+ const fd = fileResourceFd(descriptorId);
1583
+ const streamId = createWritableStream(createWriteStream(null, {
1434
1584
  fd,
1435
1585
  autoClose: false,
1436
1586
  emitClose: false,
1437
- highWaterMark: 64 * 1024,
1587
+ highWaterMark: 65536,
1438
1588
  start: Number(offset)
1439
1589
  }));
1590
+ streams.get(streamId).fileResourceId = retainFileResource(descriptorId);
1591
+ return streamId;
1440
1592
  }
1441
1593
  }
1442
1594
  switch (call & CALL_MASK) {
@@ -1457,10 +1609,13 @@ function handle(call, id, payload) {
1457
1609
  case INPUT_STREAM_SKIP: return handle(INPUT_STREAM_READ | call & CALL_TYPE_MASK, id, new Uint8Array(Number(payload)));
1458
1610
  case INPUT_STREAM_BLOCKING_SKIP: return handle(INPUT_STREAM_BLOCKING_READ | call & CALL_TYPE_MASK, id, new Uint8Array(Number(payload)));
1459
1611
  case INPUT_STREAM_SUBSCRIBE: return createPoll(streams.get(id).pollState);
1460
- case INPUT_STREAM_DISPOSE:
1461
- verifyPollsDroppedForDrop(streams.get(id).pollState, "input stream");
1612
+ case INPUT_STREAM_DISPOSE: {
1613
+ const stream = streams.get(id);
1614
+ verifyPollsDroppedForDrop(stream.pollState, "input stream");
1462
1615
  streams.delete(id);
1616
+ if (stream.fileResourceId) return releaseFileResource(stream.fileResourceId);
1463
1617
  return;
1618
+ }
1464
1619
  case OUTPUT_STREAM_CHECK_WRITE: {
1465
1620
  const { stream, pollState } = getStreamOrThrow(id);
1466
1621
  const bytes = stream.writableHighWaterMark - stream.writableLength;
@@ -1566,9 +1721,12 @@ function handle(call, id, payload) {
1566
1721
  case OUTPUT_STREAM_DISPOSE: {
1567
1722
  const stream = streams.get(id);
1568
1723
  verifyPollsDroppedForDrop(stream.pollState, "output stream");
1569
- stream.stream.end();
1570
1724
  streams.delete(id);
1571
- return;
1725
+ if (stream.fileResourceId) return new Promise((resolve) => stream.stream.end(resolve)).then(() => releaseFileResource(stream.fileResourceId));
1726
+ else {
1727
+ stream.stream.end();
1728
+ return;
1729
+ }
1572
1730
  }
1573
1731
  case POLL_POLLABLE_READY: return polls.get(id).ready;
1574
1732
  case POLL_POLLABLE_BLOCK: payload = [id];
@@ -9,6 +9,7 @@ export interface Stream {
9
9
  stream: NodeJS.ReadableStream | NodeJS.WritableStream;
10
10
  flushPromise: Promise<void> | null;
11
11
  pollState: any;
12
+ fileResourceId?: number;
12
13
  }
13
14
  export interface Future {
14
15
  future: {
@@ -6,7 +6,8 @@ import { clearOutgoingResponse, createHttpRequest, setOutgoingResponse, startHtt
6
6
  import { Readable } from "node:stream";
7
7
  import { read } from "node:fs";
8
8
  import { nextTick } from "node:process";
9
- import { CALL_MASK, CALL_TYPE_MASK, CLOCKS_DURATION_SUBSCRIBE, CLOCKS_INSTANT_SUBSCRIBE, FILE, FUTURE_DISPOSE, FUTURE_SUBSCRIBE, FUTURE_TAKE_VALUE, HTTP, HTTP_CREATE_REQUEST, HTTP_OUTGOING_BODY_DISPOSE, HTTP_OUTPUT_STREAM_FINISH, HTTP_SERVER_CLEAR_OUTGOING_RESPONSE, HTTP_SERVER_SET_OUTGOING_RESPONSE, HTTP_SERVER_START, HTTP_SERVER_STOP, HTTP_SERVER_GET_ADDRESS, INPUT_STREAM_BLOCKING_READ, INPUT_STREAM_BLOCKING_SKIP, INPUT_STREAM_CREATE, INPUT_STREAM_DISPOSE, INPUT_STREAM_READ, INPUT_STREAM_SKIP, INPUT_STREAM_SUBSCRIBE, OUTPUT_STREAM_BLOCKING_FLUSH, OUTPUT_STREAM_BLOCKING_SPLICE, OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH, OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH, OUTPUT_STREAM_CHECK_WRITE, OUTPUT_STREAM_CREATE, OUTPUT_STREAM_DISPOSE, OUTPUT_STREAM_FLUSH, OUTPUT_STREAM_SPLICE, OUTPUT_STREAM_SUBSCRIBE, OUTPUT_STREAM_WRITE, OUTPUT_STREAM_WRITE_ZEROES, POLL_POLLABLE_BLOCK, POLL_POLLABLE_DISPOSE, POLL_POLLABLE_READY, POLL_POLL_LIST, SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST, SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST, SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST, SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST, SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE, SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE, SOCKET_TCP_ACCEPT, SOCKET_TCP_BIND_FINISH, SOCKET_TCP_BIND_START, SOCKET_TCP_CONNECT_FINISH, SOCKET_TCP_CONNECT_START, SOCKET_TCP_CREATE_HANDLE, SOCKET_TCP_DISPOSE, SOCKET_TCP_GET_LOCAL_ADDRESS, SOCKET_TCP_GET_REMOTE_ADDRESS, SOCKET_TCP_IS_LISTENING, SOCKET_TCP_LISTEN_FINISH, SOCKET_TCP_LISTEN_START, SOCKET_TCP_SET_KEEP_ALIVE, SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE, SOCKET_TCP_SHUTDOWN, SOCKET_TCP_SUBSCRIBE, SOCKET_UDP_BIND_FINISH, SOCKET_UDP_BIND_START, SOCKET_UDP_CREATE_HANDLE, SOCKET_UDP_DISPOSE, SOCKET_UDP_GET_LOCAL_ADDRESS, SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE, SOCKET_UDP_GET_REMOTE_ADDRESS, SOCKET_UDP_GET_SEND_BUFFER_SIZE, SOCKET_UDP_GET_UNICAST_HOP_LIMIT, SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE, SOCKET_UDP_SET_SEND_BUFFER_SIZE, SOCKET_UDP_SET_UNICAST_HOP_LIMIT, SOCKET_UDP_STREAM, SOCKET_UDP_SUBSCRIBE, SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE, SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND, SOCKET_OUTGOING_DATAGRAM_STREAM_SEND, SOCKET_DATAGRAM_STREAM_SUBSCRIBE, SOCKET_DATAGRAM_STREAM_DISPOSE, STDERR, STDIN, STDOUT, reverseMap, } from "./calls.js";
9
+ import { CALL_MASK, CALL_TYPE_MASK, CLOCKS_DURATION_SUBSCRIBE, CLOCKS_INSTANT_SUBSCRIBE, FILE, FILESYSTEM_DESCRIPTOR_CLOSE, FILESYSTEM_DESCRIPTOR_GET_TYPE, FILESYSTEM_DESCRIPTOR_METADATA_HASH, FILESYSTEM_DESCRIPTOR_OPEN, FILESYSTEM_DESCRIPTOR_READ, FILESYSTEM_DESCRIPTOR_SET_SIZE, FILESYSTEM_DESCRIPTOR_SET_TIMES, FILESYSTEM_DESCRIPTOR_STAT, FILESYSTEM_DESCRIPTOR_SYNC, FILESYSTEM_DESCRIPTOR_SYNC_DATA, FILESYSTEM_DESCRIPTOR_WRITE, FUTURE_DISPOSE, FUTURE_SUBSCRIBE, FUTURE_TAKE_VALUE, HTTP, HTTP_CREATE_REQUEST, HTTP_OUTGOING_BODY_DISPOSE, HTTP_OUTPUT_STREAM_FINISH, HTTP_SERVER_CLEAR_OUTGOING_RESPONSE, HTTP_SERVER_SET_OUTGOING_RESPONSE, HTTP_SERVER_START, HTTP_SERVER_STOP, HTTP_SERVER_GET_ADDRESS, INPUT_STREAM_BLOCKING_READ, INPUT_STREAM_BLOCKING_SKIP, INPUT_STREAM_CREATE, INPUT_STREAM_DISPOSE, INPUT_STREAM_READ, INPUT_STREAM_SKIP, INPUT_STREAM_SUBSCRIBE, OUTPUT_STREAM_BLOCKING_FLUSH, OUTPUT_STREAM_BLOCKING_SPLICE, OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH, OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH, OUTPUT_STREAM_CHECK_WRITE, OUTPUT_STREAM_CREATE, OUTPUT_STREAM_DISPOSE, OUTPUT_STREAM_FLUSH, OUTPUT_STREAM_SPLICE, OUTPUT_STREAM_SUBSCRIBE, OUTPUT_STREAM_WRITE, OUTPUT_STREAM_WRITE_ZEROES, POLL_POLLABLE_BLOCK, POLL_POLLABLE_DISPOSE, POLL_POLLABLE_READY, POLL_POLL_LIST, SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST, SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST, SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST, SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST, SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE, SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE, SOCKET_TCP_ACCEPT, SOCKET_TCP_BIND_FINISH, SOCKET_TCP_BIND_START, SOCKET_TCP_CONNECT_FINISH, SOCKET_TCP_CONNECT_START, SOCKET_TCP_CREATE_HANDLE, SOCKET_TCP_DISPOSE, SOCKET_TCP_GET_LOCAL_ADDRESS, SOCKET_TCP_GET_REMOTE_ADDRESS, SOCKET_TCP_IS_LISTENING, SOCKET_TCP_LISTEN_FINISH, SOCKET_TCP_LISTEN_START, SOCKET_TCP_SET_KEEP_ALIVE, SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE, SOCKET_TCP_SHUTDOWN, SOCKET_TCP_SUBSCRIBE, SOCKET_UDP_BIND_FINISH, SOCKET_UDP_BIND_START, SOCKET_UDP_CREATE_HANDLE, SOCKET_UDP_DISPOSE, SOCKET_UDP_GET_LOCAL_ADDRESS, SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE, SOCKET_UDP_GET_REMOTE_ADDRESS, SOCKET_UDP_GET_SEND_BUFFER_SIZE, SOCKET_UDP_GET_UNICAST_HOP_LIMIT, SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE, SOCKET_UDP_SET_SEND_BUFFER_SIZE, SOCKET_UDP_SET_UNICAST_HOP_LIMIT, SOCKET_UDP_STREAM, SOCKET_UDP_SUBSCRIBE, SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE, SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND, SOCKET_OUTGOING_DATAGRAM_STREAM_SEND, SOCKET_DATAGRAM_STREAM_SUBSCRIBE, SOCKET_DATAGRAM_STREAM_DISPOSE, STDERR, STDIN, STDOUT, reverseMap, } from "./calls.js";
10
+ import { fileResourceFd, getFileResourceType, metadataHashFileResource, openFileResource, readFileResource, releaseFileResource, retainFileResource, setFileResourceSize, setFileResourceTimes, statFileResource, syncFileResource, syncFileResourceData, writeFileResource, } from "./worker-filesystem.js";
10
11
  import { SOCKET_STATE_BIND, SOCKET_STATE_BOUND, SOCKET_STATE_CONNECT, SOCKET_STATE_CONNECTION, SOCKET_STATE_LISTEN, SOCKET_STATE_LISTENER, socketResolveAddress, getDefaultSendBufferSize, getDefaultReceiveBufferSize, } from "./worker-sockets.js";
11
12
  import { createTcpSocket, socketTcpAccept, socketTcpBindStart, socketTcpConnectStart, socketTcpDispose, socketTcpFinish, socketTcpGetLocalAddress, socketTcpGetRemoteAddress, socketTcpListenStart, socketTcpSetKeepAlive, socketTcpSetListenBacklogSize, socketTcpShutdown, tcpSockets, } from "./worker-socket-tcp.js";
12
13
  import { createUdpSocket, datagramStreams, socketDatagramStreamDispose, socketIncomingDatagramStreamReceive, socketOutgoingDatagramStreamCheckSend, socketOutgoingDatagramStreamSend, socketUdpBindFinish, socketUdpBindStart, socketUdpDispose, socketUdpGetLocalAddress, socketUdpGetReceiveBufferSize, socketUdpGetRemoteAddress, socketUdpGetSendBufferSize, socketUdpGetUnicastHopLimit, socketUdpSetReceiveBufferSize, socketUdpSetSendBufferSize, socketUdpSetUnicastHopLimit, socketUdpStream, udpSockets, } from "./worker-socket-udp.js";
@@ -365,18 +366,44 @@ function handle(call, id, payload) {
365
366
  return createPoll(pollState);
366
367
  }
367
368
  // Filesystem
369
+ case FILESYSTEM_DESCRIPTOR_OPEN:
370
+ return openFileResource(payload.path, payload.flags);
371
+ case FILESYSTEM_DESCRIPTOR_CLOSE:
372
+ return releaseFileResource(id);
373
+ case FILESYSTEM_DESCRIPTOR_SYNC_DATA:
374
+ return syncFileResourceData(id);
375
+ case FILESYSTEM_DESCRIPTOR_GET_TYPE:
376
+ return getFileResourceType(id);
377
+ case FILESYSTEM_DESCRIPTOR_SET_SIZE:
378
+ return setFileResourceSize(id, payload);
379
+ case FILESYSTEM_DESCRIPTOR_SET_TIMES:
380
+ return setFileResourceTimes(id, payload.atime, payload.mtime);
381
+ case FILESYSTEM_DESCRIPTOR_READ:
382
+ return readFileResource(id, payload.length, payload.offset);
383
+ case FILESYSTEM_DESCRIPTOR_WRITE:
384
+ return writeFileResource(id, payload.buffer, payload.offset);
385
+ case FILESYSTEM_DESCRIPTOR_SYNC:
386
+ return syncFileResource(id);
387
+ case FILESYSTEM_DESCRIPTOR_STAT:
388
+ return statFileResource(id);
389
+ case FILESYSTEM_DESCRIPTOR_METADATA_HASH:
390
+ return metadataHashFileResource(id);
368
391
  case INPUT_STREAM_CREATE | FILE: {
369
- const { fd, offset } = payload;
392
+ const { descriptorId, offset } = payload;
393
+ const fd = fileResourceFd(descriptorId);
370
394
  const stream = createReadStream(null, {
371
395
  fd,
372
396
  autoClose: false,
373
397
  highWaterMark: 64 * 1024,
374
398
  start: Number(offset),
375
399
  });
376
- return createReadableStream(stream);
400
+ const streamId = createReadableStream(stream);
401
+ streams.get(streamId).fileResourceId = retainFileResource(descriptorId);
402
+ return streamId;
377
403
  }
378
404
  case OUTPUT_STREAM_CREATE | FILE: {
379
- const { fd, offset } = payload;
405
+ const { descriptorId, offset } = payload;
406
+ const fd = fileResourceFd(descriptorId);
380
407
  const stream = createWriteStream(null, {
381
408
  fd,
382
409
  autoClose: false,
@@ -384,7 +411,9 @@ function handle(call, id, payload) {
384
411
  highWaterMark: 64 * 1024,
385
412
  start: Number(offset),
386
413
  });
387
- return createWritableStream(stream);
414
+ const streamId = createWritableStream(stream);
415
+ streams.get(streamId).fileResourceId = retainFileResource(descriptorId);
416
+ return streamId;
388
417
  }
389
418
  }
390
419
  // Generic call implementations (streams + polls)
@@ -421,6 +450,9 @@ function handle(call, id, payload) {
421
450
  const stream = streams.get(id);
422
451
  verifyPollsDroppedForDrop(stream.pollState, "input stream");
423
452
  streams.delete(id);
453
+ if (stream.fileResourceId) {
454
+ return releaseFileResource(stream.fileResourceId);
455
+ }
424
456
  return;
425
457
  }
426
458
  case OUTPUT_STREAM_CHECK_WRITE: {
@@ -599,9 +631,14 @@ function handle(call, id, payload) {
599
631
  case OUTPUT_STREAM_DISPOSE: {
600
632
  const stream = streams.get(id);
601
633
  verifyPollsDroppedForDrop(stream.pollState, "output stream");
602
- stream.stream.end();
603
634
  streams.delete(id);
604
- return;
635
+ if (stream.fileResourceId) {
636
+ return new Promise((resolve) => stream.stream.end(resolve)).then(() => releaseFileResource(stream.fileResourceId));
637
+ }
638
+ else {
639
+ stream.stream.end();
640
+ return;
641
+ }
605
642
  }
606
643
  case POLL_POLLABLE_READY:
607
644
  return polls.get(id).ready;
@@ -1,5 +1,5 @@
1
1
  import { types as TypesNamespace, preopens as PreopensNamespace } from "../../types/filesystem.js";
2
- import type { Descriptor as IDescriptor, DirectoryEntryStream as IDirectoryEntryStream } from "../../types/interfaces/wasi-filesystem-types.js";
2
+ import type { Descriptor as IDescriptor, DescriptorType, DirectoryEntryStream as IDirectoryEntryStream } from "../../types/interfaces/wasi-filesystem-types.js";
3
3
  declare const symbolDispose: symbol;
4
4
  /**
5
5
  * @implements {DescriptorProps}
@@ -9,14 +9,14 @@ declare class Descriptor implements IDescriptor {
9
9
  [symbolDispose]: () => void;
10
10
  private _id;
11
11
  static _createPreopen(hostPreopen: any): Descriptor;
12
- static _create(fd: any, mode: any, fullPath: any): Descriptor;
12
+ static _create(fileResourceId: any, mode: any, fullPath: any): Descriptor;
13
13
  readViaStream(offset: any): any;
14
14
  writeViaStream(offset: any): any;
15
15
  appendViaStream(): any;
16
16
  advise(_offset: any, _length: any, _advice: any): void;
17
17
  syncData(): void;
18
18
  getFlags(): any;
19
- getType(): TypesNamespace.DescriptorType;
19
+ getType(): any;
20
20
  setSize(size: any): void;
21
21
  setTimes(dataAccessTimestamp: any, dataModificationTimestamp: any): void;
22
22
  read(length: any, offset: any): [Uint8Array, boolean];
@@ -25,7 +25,7 @@ declare class Descriptor implements IDescriptor {
25
25
  sync(): void;
26
26
  createDirectoryAt(path: any): void;
27
27
  stat(): {
28
- type: TypesNamespace.DescriptorType;
28
+ type: any;
29
29
  linkCount: any;
30
30
  size: any;
31
31
  dataAccessTimestamp: {
@@ -42,7 +42,7 @@ declare class Descriptor implements IDescriptor {
42
42
  };
43
43
  };
44
44
  statAt(pathFlags: any, path: any): {
45
- type: TypesNamespace.DescriptorType;
45
+ type: DescriptorType;
46
46
  linkCount: any;
47
47
  size: any;
48
48
  dataAccessTimestamp: {
@@ -67,10 +67,7 @@ declare class Descriptor implements IDescriptor {
67
67
  symlinkAt(target: any, path: any): void;
68
68
  unlinkFileAt(path: any): void;
69
69
  isSameObject(other: any): boolean;
70
- metadataHash(): {
71
- upper: bigint;
72
- lower: bigint;
73
- };
70
+ metadataHash(): any;
74
71
  metadataHashAt(pathFlags: any, path: any): {
75
72
  upper: bigint;
76
73
  lower: bigint;
@@ -1,6 +1,6 @@
1
1
  import { earlyDispose, inputStreamCreate, ioCall, outputStreamCreate, registerDispose, } from "../io/worker-io.js";
2
- import { FILE, INPUT_STREAM_CREATE, OUTPUT_STREAM_CREATE } from "../io/calls.js";
3
- import { closeSync, constants, fdatasyncSync, fstatSync, fsyncSync, ftruncateSync, futimesSync, linkSync, lstatSync, lutimesSync, mkdirSync, opendirSync, openSync, readlinkSync, readSync, renameSync, rmdirSync, statSync, symlinkSync, unlinkSync, utimesSync, writeSync, } from "node:fs";
2
+ import { FILE, FILESYSTEM_DESCRIPTOR_CLOSE, FILESYSTEM_DESCRIPTOR_GET_TYPE, FILESYSTEM_DESCRIPTOR_METADATA_HASH, FILESYSTEM_DESCRIPTOR_OPEN, FILESYSTEM_DESCRIPTOR_READ, FILESYSTEM_DESCRIPTOR_SET_SIZE, FILESYSTEM_DESCRIPTOR_SET_TIMES, FILESYSTEM_DESCRIPTOR_STAT, FILESYSTEM_DESCRIPTOR_SYNC, FILESYSTEM_DESCRIPTOR_SYNC_DATA, FILESYSTEM_DESCRIPTOR_WRITE, INPUT_STREAM_CREATE, OUTPUT_STREAM_CREATE, } from "../io/calls.js";
3
+ import { constants, linkSync, lstatSync, lutimesSync, mkdirSync, opendirSync, readlinkSync, renameSync, rmdirSync, statSync, symlinkSync, unlinkSync, utimesSync, } from "node:fs";
4
4
  import { platform } from "node:process";
5
5
  const symbolDispose = Symbol.dispose || Symbol.for("dispose");
6
6
  const isWindows = platform === "win32";
@@ -35,6 +35,9 @@ function lookupType(obj) {
35
35
  }
36
36
  return "unknown";
37
37
  }
38
+ function closeFileResource(id) {
39
+ ioCall(FILESYSTEM_DESCRIPTOR_CLOSE, id);
40
+ }
38
41
  // Note: This should implement per-segment semantics of openAt, but we cannot
39
42
  // currently due to the lack of support for openat() in Node.js.
40
43
  // Tracking issue: https://github.com/libuv/libuv/issues/4167
@@ -43,7 +46,7 @@ function lookupType(obj) {
43
46
  */
44
47
  class Descriptor {
45
48
  #hostPreopen;
46
- #fd;
49
+ #fileResourceId;
47
50
  #finalizer;
48
51
  #mode;
49
52
  #fullPath;
@@ -62,10 +65,10 @@ class Descriptor {
62
65
  }
63
66
  return descriptor;
64
67
  }
65
- static _create(fd, mode, fullPath) {
68
+ static _create(fileResourceId, mode, fullPath) {
66
69
  const descriptor = new Descriptor();
67
- descriptor.#fd = fd;
68
- descriptor.#finalizer = registerDispose(descriptor, null, fd, closeSync);
70
+ descriptor.#fileResourceId = fileResourceId;
71
+ descriptor.#finalizer = registerDispose(descriptor, null, fileResourceId, closeFileResource);
69
72
  descriptor.#mode = mode;
70
73
  descriptor.#fullPath = fullPath;
71
74
  return descriptor;
@@ -81,7 +84,7 @@ class Descriptor {
81
84
  throw "is-directory";
82
85
  }
83
86
  return inputStreamCreate(FILE, ioCall(INPUT_STREAM_CREATE | FILE, null, {
84
- fd: this.#fd,
87
+ descriptorId: this.#fileResourceId,
85
88
  offset,
86
89
  }));
87
90
  }
@@ -89,7 +92,10 @@ class Descriptor {
89
92
  if (this.#hostPreopen) {
90
93
  throw "is-directory";
91
94
  }
92
- return outputStreamCreate(FILE, ioCall(OUTPUT_STREAM_CREATE | FILE, null, { fd: this.#fd, offset }));
95
+ return outputStreamCreate(FILE, ioCall(OUTPUT_STREAM_CREATE | FILE, null, {
96
+ descriptorId: this.#fileResourceId,
97
+ offset,
98
+ }));
93
99
  }
94
100
  appendViaStream() {
95
101
  return this.writeViaStream(this.stat().size);
@@ -104,7 +110,7 @@ class Descriptor {
104
110
  throw "invalid";
105
111
  }
106
112
  try {
107
- fdatasyncSync(this.#fd);
113
+ ioCall(FILESYSTEM_DESCRIPTOR_SYNC_DATA, this.#fileResourceId);
108
114
  }
109
115
  catch (e) {
110
116
  if (e.code === "EPERM") {
@@ -120,15 +126,14 @@ class Descriptor {
120
126
  if (this.#hostPreopen) {
121
127
  return "directory";
122
128
  }
123
- const stats = fstatSync(this.#fd);
124
- return lookupType(stats);
129
+ return ioCall(FILESYSTEM_DESCRIPTOR_GET_TYPE, this.#fileResourceId);
125
130
  }
126
131
  setSize(size) {
127
132
  if (this.#hostPreopen) {
128
133
  throw "is-directory";
129
134
  }
130
135
  try {
131
- ftruncateSync(this.#fd, Number(size));
136
+ ioCall(FILESYSTEM_DESCRIPTOR_SET_SIZE, this.#fileResourceId, Number(size));
132
137
  }
133
138
  catch (e) {
134
139
  if (isWindows && e.code === "EPERM") {
@@ -149,7 +154,7 @@ class Descriptor {
149
154
  const atime = this.#getNewTimestamp(dataAccessTimestamp, dataAccessTimestamp.tag === "no-change" && stats.dataAccessTimestamp);
150
155
  const mtime = this.#getNewTimestamp(dataModificationTimestamp, dataModificationTimestamp.tag === "no-change" && stats.dataModificationTimestamp);
151
156
  try {
152
- futimesSync(this.#fd, atime, mtime);
157
+ ioCall(FILESYSTEM_DESCRIPTOR_SET_TIMES, this.#fileResourceId, { atime, mtime });
153
158
  }
154
159
  catch (e) {
155
160
  throw convertFsError(e);
@@ -169,16 +174,20 @@ class Descriptor {
169
174
  if (!this.#fullPath) {
170
175
  throw "bad-descriptor";
171
176
  }
172
- const buf = new Uint8Array(Number(length));
173
- const bytesRead = readSync(this.#fd, buf, 0, Number(length), Number(offset));
174
- const out = new Uint8Array(buf.buffer, 0, bytesRead);
175
- return [out, bytesRead === 0];
177
+ const { bytes, eof } = ioCall(FILESYSTEM_DESCRIPTOR_READ, this.#fileResourceId, {
178
+ length: Number(length),
179
+ offset: Number(offset),
180
+ });
181
+ return [bytes, eof];
176
182
  }
177
183
  write(buffer, offset) {
178
184
  if (!this.#fullPath) {
179
185
  throw "bad-descriptor";
180
186
  }
181
- return BigInt(writeSync(this.#fd, buffer, 0, buffer.byteLength, Number(offset)));
187
+ return BigInt(ioCall(FILESYSTEM_DESCRIPTOR_WRITE, this.#fileResourceId, {
188
+ buffer,
189
+ offset: Number(offset),
190
+ }));
182
191
  }
183
192
  readDirectory() {
184
193
  if (!this.#fullPath) {
@@ -197,7 +206,7 @@ class Descriptor {
197
206
  throw "invalid";
198
207
  }
199
208
  try {
200
- fsyncSync(this.#fd);
209
+ ioCall(FILESYSTEM_DESCRIPTOR_SYNC, this.#fileResourceId);
201
210
  }
202
211
  catch (e) {
203
212
  if (e.code === "EPERM") {
@@ -221,12 +230,12 @@ class Descriptor {
221
230
  }
222
231
  let stats;
223
232
  try {
224
- stats = fstatSync(this.#fd, { bigint: true });
233
+ stats = ioCall(FILESYSTEM_DESCRIPTOR_STAT, this.#fileResourceId);
225
234
  }
226
235
  catch (e) {
227
236
  throw convertFsError(e);
228
237
  }
229
- const type = lookupType(stats);
238
+ const type = stats.type;
230
239
  return {
231
240
  type,
232
241
  linkCount: stats.nlink,
@@ -361,9 +370,12 @@ class Descriptor {
361
370
  }
362
371
  }
363
372
  try {
364
- const fd = openSync(fullPath.endsWith("/") ? fullPath.slice(0, -1) : fullPath, fsOpenFlags);
365
- const descriptor = descriptorCreate(fd, descriptorFlags, fullPath);
366
- if (fullPath.endsWith("/") && descriptor.getType() !== "directory") {
373
+ const { id, type } = ioCall(FILESYSTEM_DESCRIPTOR_OPEN, null, {
374
+ path: fullPath.endsWith("/") ? fullPath.slice(0, -1) : fullPath,
375
+ flags: fsOpenFlags,
376
+ });
377
+ const descriptor = descriptorCreate(id, descriptorFlags, fullPath);
378
+ if (fullPath.endsWith("/") && type !== "directory") {
367
379
  descriptor[symbolDispose]();
368
380
  throw "not-directory";
369
381
  }
@@ -475,8 +487,7 @@ class Descriptor {
475
487
  return { upper: 0n, lower: BigInt(this._id) };
476
488
  }
477
489
  try {
478
- const stats = fstatSync(this.#fd, { bigint: true });
479
- return { upper: stats.mtimeNs, lower: stats.ino };
490
+ return ioCall(FILESYSTEM_DESCRIPTOR_METADATA_HASH, this.#fileResourceId);
480
491
  }
481
492
  catch (e) {
482
493
  throw convertFsError(e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/preview2-shim",
3
- "version": "0.20.1",
3
+ "version": "0.20.2",
4
4
  "description": "WASI Preview2 shim for JS environments",
5
5
  "homepage": "https://github.com/bytecodealliance/jco#readme",
6
6
  "bugs": {
@@ -62,9 +62,9 @@
62
62
  "@types/node": "^24.12.4",
63
63
  "mime": "^4.0.7",
64
64
  "puppeteer": "^25.1.0",
65
- "rolldown": "^1.2.0",
66
- "typescript": "^6.0.3",
67
- "vitest": "^4.0.8"
65
+ "rolldown": "^1.2.4",
66
+ "typescript": "7.0.2",
67
+ "vitest": "^4.1.10"
68
68
  },
69
69
  "scripts": {
70
70
  "build": "tsc --project tsconfig.build.json && node scripts/build-worker.mjs",
@@ -74,6 +74,7 @@
74
74
  "fmt:check": "oxfmt --check",
75
75
  "lint": "oxlint",
76
76
  "lint:fix": "oxlint --fix",
77
- "test": "vitest run -c test/vitest.ts"
77
+ "test": "vitest run -c test/vitest.ts",
78
+ "test:deno": "deno test --no-check -A test/deno/*.mjs"
78
79
  }
79
80
  }