@bytecodealliance/preview2-shim 0.27.0 → 0.27.1

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.
@@ -1708,7 +1708,6 @@ function handle(call, id, payload) {
1708
1708
  case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH: {
1709
1709
  const stream = getStreamOrThrow(id);
1710
1710
  if (stream.flushPromise) return stream.flushPromise.then(() => handle(call, id, payload));
1711
- if (payload.byteLength > stream.stream.writableHighWaterMark - stream.stream.writableLength) throw new Error("wasi-io trap: Cannot write more than permitted writable length");
1712
1711
  stream.pollState.ready = false;
1713
1712
  return stream.flushPromise = new Promise((resolve, reject) => {
1714
1713
  if (stream.stream === stdout || stream.stream === stderr) {
@@ -504,10 +504,9 @@ function handle(call, id, payload) {
504
504
  if (stream.flushPromise) {
505
505
  return stream.flushPromise.then(() => handle(call, id, payload));
506
506
  }
507
- if (payload.byteLength >
508
- stream.stream.writableHighWaterMark - stream.stream.writableLength) {
509
- throw new Error("wasi-io trap: Cannot write more than permitted writable length");
510
- }
507
+ // Unlike write(), blocking-write-and-flush does not need a check-write
508
+ // permit. Node may buffer the write above its high-water mark while
509
+ // we wait for its completion callback below.
511
510
  stream.pollState.ready = false;
512
511
  return (stream.flushPromise = new Promise((resolve, reject) => {
513
512
  if (stream.stream === stdout || stream.stream === stderr) {
@@ -10,6 +10,7 @@ declare class Descriptor implements IDescriptor {
10
10
  private _id;
11
11
  static _createPreopen(hostPreopen: any): Descriptor;
12
12
  static _create(fileResourceId: any, mode: any, fullPath: any): Descriptor;
13
+ static _createVirtualDirectory(mode: any, fullPath: any): Descriptor;
13
14
  readViaStream(offset: any): any;
14
15
  writeViaStream(offset: any): any;
15
16
  appendViaStream(): any;
@@ -56,6 +56,7 @@ class Descriptor {
56
56
  #finalizer;
57
57
  #mode;
58
58
  #fullPath;
59
+ #virtualDirectory = false;
59
60
  _id = 0;
60
61
  static _createPreopen(hostPreopen) {
61
62
  const descriptor = new Descriptor();
@@ -79,6 +80,13 @@ class Descriptor {
79
80
  descriptor.#fullPath = fullPath;
80
81
  return descriptor;
81
82
  }
83
+ static _createVirtualDirectory(mode, fullPath) {
84
+ const descriptor = new Descriptor();
85
+ descriptor.#mode = mode;
86
+ descriptor.#fullPath = fullPath;
87
+ descriptor.#virtualDirectory = true;
88
+ return descriptor;
89
+ }
82
90
  [symbolDispose]() {
83
91
  if (this.#finalizer) {
84
92
  earlyDispose(this.#finalizer);
@@ -86,7 +94,7 @@ class Descriptor {
86
94
  }
87
95
  }
88
96
  readViaStream(offset) {
89
- if (this.#hostPreopen) {
97
+ if (this.#hostPreopen || this.#virtualDirectory) {
90
98
  throw "is-directory";
91
99
  }
92
100
  return inputStreamCreate(FILE, ioCall(INPUT_STREAM_CREATE | FILE, null, {
@@ -95,7 +103,7 @@ class Descriptor {
95
103
  }));
96
104
  }
97
105
  writeViaStream(offset) {
98
- if (this.#hostPreopen) {
106
+ if (this.#hostPreopen || this.#virtualDirectory) {
99
107
  throw "is-directory";
100
108
  }
101
109
  return outputStreamCreate(FILE, ioCall(OUTPUT_STREAM_CREATE | FILE, null, {
@@ -139,13 +147,13 @@ class Descriptor {
139
147
  return this.#mode;
140
148
  }
141
149
  getType() {
142
- if (this.#hostPreopen) {
150
+ if (this.#hostPreopen || this.#virtualDirectory) {
143
151
  return "directory";
144
152
  }
145
153
  return ioCall(FILESYSTEM_DESCRIPTOR_GET_TYPE, this.#fileResourceId);
146
154
  }
147
155
  setSize(size) {
148
- if (this.#hostPreopen) {
156
+ if (this.#hostPreopen || this.#virtualDirectory) {
149
157
  throw "is-directory";
150
158
  }
151
159
  try {
@@ -187,6 +195,9 @@ class Descriptor {
187
195
  }
188
196
  }
189
197
  read(length, offset) {
198
+ if (this.#virtualDirectory) {
199
+ throw "is-directory";
200
+ }
190
201
  if (!this.#fullPath) {
191
202
  throw "bad-descriptor";
192
203
  }
@@ -197,6 +208,9 @@ class Descriptor {
197
208
  return [bytes, eof];
198
209
  }
199
210
  write(buffer, offset) {
211
+ if (this.#virtualDirectory) {
212
+ throw "is-directory";
213
+ }
200
214
  if (!this.#fullPath) {
201
215
  throw "bad-descriptor";
202
216
  }
@@ -218,7 +232,7 @@ class Descriptor {
218
232
  }
219
233
  }
220
234
  sync() {
221
- if (this.#hostPreopen) {
235
+ if (this.#hostPreopen || this.#virtualDirectory) {
222
236
  throw "invalid";
223
237
  }
224
238
  try {
@@ -246,12 +260,14 @@ class Descriptor {
246
260
  }
247
261
  let stats;
248
262
  try {
249
- stats = ioCall(FILESYSTEM_DESCRIPTOR_STAT, this.#fileResourceId);
263
+ stats = this.#virtualDirectory
264
+ ? statSync(this.#fullPath, { bigint: true })
265
+ : ioCall(FILESYSTEM_DESCRIPTOR_STAT, this.#fileResourceId);
250
266
  }
251
267
  catch (e) {
252
268
  throw convertFsError(e);
253
269
  }
254
- const type = stats.type;
270
+ const type = this.#virtualDirectory ? lookupType(stats) : stats.type;
255
271
  return {
256
272
  type,
257
273
  linkCount: stats.nlink,
@@ -381,6 +397,24 @@ class Descriptor {
381
397
  throw "not-directory";
382
398
  }
383
399
  }
400
+ // Node cannot open a directory with fs.open on Windows (EISDIR).
401
+ // Directory operations use the path, so keep a descriptor without an fd.
402
+ try {
403
+ if (statSync(fullPath).isDirectory()) {
404
+ if (descriptorFlags.write || openFlags.create || openFlags.truncate) {
405
+ throw "is-directory";
406
+ }
407
+ return Descriptor._createVirtualDirectory(descriptorFlags, fullPath);
408
+ }
409
+ }
410
+ catch (e) {
411
+ if (e === "is-directory") {
412
+ throw e;
413
+ }
414
+ if (e.code !== "ENOENT") {
415
+ throw convertFsError(e);
416
+ }
417
+ }
384
418
  }
385
419
  try {
386
420
  const { id, type } = ioCall(FILESYSTEM_DESCRIPTOR_OPEN, null, {
@@ -509,6 +543,10 @@ class Descriptor {
509
543
  if (this.#hostPreopen) {
510
544
  return { upper: 0n, lower: BigInt(this._id) };
511
545
  }
546
+ if (this.#virtualDirectory) {
547
+ const stats = statSync(this.#fullPath, { bigint: true });
548
+ return { upper: stats.mtimeNs, lower: stats.ino };
549
+ }
512
550
  try {
513
551
  return ioCall(FILESYSTEM_DESCRIPTOR_METADATA_HASH, this.#fileResourceId);
514
552
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/preview2-shim",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "WASI Preview2 shim for JS environments",
5
5
  "homepage": "https://github.com/bytecodealliance/jco#readme",
6
6
  "bugs": {
@@ -64,7 +64,7 @@
64
64
  "@bytecodealliance/jco-node-fs": "0.3.2"
65
65
  },
66
66
  "devDependencies": {
67
- "@bytecodealliance/componentize-js": "0.22.0",
67
+ "@bytecodealliance/componentize-js": "0.23.0",
68
68
  "@bytecodealliance/jco": "1.25.2",
69
69
  "@types/node": "^24.12.4",
70
70
  "mime": "^4.0.7",