@bytecodealliance/preview3-shim 0.1.0 → 0.1.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.
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
|
+
import nodePath from "node:path";
|
|
2
3
|
import process from "node:process";
|
|
3
4
|
|
|
4
5
|
import { StreamReader, readableByteStreamFromReader } from "../stream.js";
|
|
@@ -29,8 +30,10 @@ class Descriptor {
|
|
|
29
30
|
#finalizer;
|
|
30
31
|
/** Host filesystem path for preopened directories */
|
|
31
32
|
#hostPreopen;
|
|
33
|
+
/** Whether this descriptor refers to a directory. */
|
|
34
|
+
#isDirectory = false;
|
|
32
35
|
|
|
33
|
-
static _create(handle, mode, fullPath) {
|
|
36
|
+
static _create(handle, mode, fullPath, isDirectory = false) {
|
|
34
37
|
const {
|
|
35
38
|
read = false,
|
|
36
39
|
write = false,
|
|
@@ -52,6 +55,7 @@ class Descriptor {
|
|
|
52
55
|
const desc = new Descriptor();
|
|
53
56
|
desc.#handle = handle;
|
|
54
57
|
desc.#fullPath = fullPath;
|
|
58
|
+
desc.#isDirectory = isDirectory;
|
|
55
59
|
desc.#mode = merged;
|
|
56
60
|
desc.#finalizer = registerDispose(desc, null, handle, (handle) => handle.close());
|
|
57
61
|
|
|
@@ -60,6 +64,15 @@ class Descriptor {
|
|
|
60
64
|
|
|
61
65
|
static _createPreopen(hostPreopen) {
|
|
62
66
|
const desc = new Descriptor();
|
|
67
|
+
desc.#isDirectory = true;
|
|
68
|
+
desc.#mode = {
|
|
69
|
+
read: true,
|
|
70
|
+
write: false,
|
|
71
|
+
fileIntegritySync: false,
|
|
72
|
+
dataIntegritySync: false,
|
|
73
|
+
requestedWriteSync: false,
|
|
74
|
+
mutateDirectory: true,
|
|
75
|
+
};
|
|
63
76
|
|
|
64
77
|
if (hostPreopen.endsWith("/")) {
|
|
65
78
|
desc.#hostPreopen = hostPreopen.slice(0, -1) || "/";
|
|
@@ -363,6 +376,7 @@ class Descriptor {
|
|
|
363
376
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
364
377
|
*/
|
|
365
378
|
async createDirectoryAt(path) {
|
|
379
|
+
await this.#ensureSandboxedPath(path);
|
|
366
380
|
const full = this.#getFullPath(path, false);
|
|
367
381
|
try {
|
|
368
382
|
await fs.mkdir(full);
|
|
@@ -426,6 +440,7 @@ class Descriptor {
|
|
|
426
440
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
427
441
|
*/
|
|
428
442
|
async statAt(flags, path) {
|
|
443
|
+
await this.#ensureSandboxedPath(path);
|
|
429
444
|
const full = this.#getFullPath(path, flags.symlinkFollow);
|
|
430
445
|
try {
|
|
431
446
|
const statFn = flags.symlinkFollow ? fs.stat : fs.lstat;
|
|
@@ -464,6 +479,7 @@ class Descriptor {
|
|
|
464
479
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
465
480
|
*/
|
|
466
481
|
async setTimesAt(flags, path, atimeDesc, mtimeDesc) {
|
|
482
|
+
await this.#ensureSandboxedPath(path);
|
|
467
483
|
const { atime, mtime } = await this.#computeTimestamps(atimeDesc, mtimeDesc, path);
|
|
468
484
|
|
|
469
485
|
if (!flags.symlinkFollow && !fs.lutimes) {
|
|
@@ -501,6 +517,8 @@ class Descriptor {
|
|
|
501
517
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
502
518
|
*/
|
|
503
519
|
async linkAt(oldFlags, oldPath, newDesc, newPath) {
|
|
520
|
+
await this.#ensureSandboxedPath(oldPath);
|
|
521
|
+
await newDesc.#ensureSandboxedPath(newPath);
|
|
504
522
|
const src = this.#getFullPath(oldPath, oldFlags.symlinkFollow);
|
|
505
523
|
const dst = newDesc.#getFullPath(newPath, false);
|
|
506
524
|
|
|
@@ -542,9 +560,16 @@ class Descriptor {
|
|
|
542
560
|
throw new FSError("access");
|
|
543
561
|
}
|
|
544
562
|
|
|
563
|
+
await this.#ensureSandboxedPath(path);
|
|
545
564
|
const fullPath = this.#getFullPath(path, pf.symlinkFollow);
|
|
546
565
|
const target = stripTrailingSlash(fullPath);
|
|
547
566
|
|
|
567
|
+
const mode = {
|
|
568
|
+
...df,
|
|
569
|
+
read: df.read || !df.write,
|
|
570
|
+
write: df.write || of.create || of.truncate,
|
|
571
|
+
};
|
|
572
|
+
|
|
548
573
|
const makeFsFlags = () => {
|
|
549
574
|
let fsFlags = 0;
|
|
550
575
|
if (of.create) {
|
|
@@ -559,11 +584,11 @@ class Descriptor {
|
|
|
559
584
|
if (of.truncate) {
|
|
560
585
|
fsFlags |= fs.constants.O_TRUNC;
|
|
561
586
|
}
|
|
562
|
-
if (
|
|
587
|
+
if (mode.read && mode.write) {
|
|
563
588
|
fsFlags |= fs.constants.O_RDWR;
|
|
564
|
-
} else if (
|
|
589
|
+
} else if (mode.write) {
|
|
565
590
|
fsFlags |= fs.constants.O_WRONLY;
|
|
566
|
-
} else if (
|
|
591
|
+
} else if (mode.read) {
|
|
567
592
|
fsFlags |= fs.constants.O_RDONLY;
|
|
568
593
|
}
|
|
569
594
|
if (df.fileIntegritySync) {
|
|
@@ -610,8 +635,9 @@ class Descriptor {
|
|
|
610
635
|
|
|
611
636
|
try {
|
|
612
637
|
const handle = await fs.open(target, fsFlags);
|
|
613
|
-
const
|
|
614
|
-
const isDir =
|
|
638
|
+
const stats = await handle.stat();
|
|
639
|
+
const isDir = stats.isDirectory();
|
|
640
|
+
const desc = descriptorCreate(handle, mode, fullPath, isDir);
|
|
615
641
|
|
|
616
642
|
if (fullPath.endsWith("/") && !isDir) {
|
|
617
643
|
desc[symbolDispose]();
|
|
@@ -639,6 +665,7 @@ class Descriptor {
|
|
|
639
665
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
640
666
|
*/
|
|
641
667
|
async readlinkAt(path) {
|
|
668
|
+
await this.#ensureSandboxedPath(path);
|
|
642
669
|
const full = this.#getFullPath(path, false);
|
|
643
670
|
try {
|
|
644
671
|
return await fs.readlink(full);
|
|
@@ -660,6 +687,10 @@ class Descriptor {
|
|
|
660
687
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
661
688
|
*/
|
|
662
689
|
async removeDirectoryAt(path) {
|
|
690
|
+
if (path === ".") {
|
|
691
|
+
throw new FSError("invalid");
|
|
692
|
+
}
|
|
693
|
+
await this.#ensureSandboxedPath(path);
|
|
663
694
|
const full = this.#getFullPath(path, false);
|
|
664
695
|
try {
|
|
665
696
|
await fs.rmdir(full);
|
|
@@ -686,6 +717,8 @@ class Descriptor {
|
|
|
686
717
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
687
718
|
*/
|
|
688
719
|
async renameAt(oldPath, newDesc, newPath) {
|
|
720
|
+
await this.#ensureSandboxedPath(oldPath);
|
|
721
|
+
await newDesc.#ensureSandboxedPath(newPath);
|
|
689
722
|
const src = this.#getFullPath(oldPath, false);
|
|
690
723
|
const dst = newDesc.#getFullPath(newPath, false);
|
|
691
724
|
try {
|
|
@@ -715,6 +748,7 @@ class Descriptor {
|
|
|
715
748
|
if (target.startsWith("/")) {
|
|
716
749
|
throw new FSError("not-permitted");
|
|
717
750
|
}
|
|
751
|
+
await this.#ensureSandboxedPath(path);
|
|
718
752
|
const full = this.#getFullPath(path, false);
|
|
719
753
|
|
|
720
754
|
try {
|
|
@@ -750,6 +784,7 @@ class Descriptor {
|
|
|
750
784
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
751
785
|
*/
|
|
752
786
|
async unlinkFileAt(path) {
|
|
787
|
+
await this.#ensureSandboxedPath(path);
|
|
753
788
|
const full = this.#getFullPath(path, false);
|
|
754
789
|
if (full.endsWith("/")) {
|
|
755
790
|
const isDir = (await fs.stat(full)).isDirectory();
|
|
@@ -787,7 +822,8 @@ class Descriptor {
|
|
|
787
822
|
* @returns {Promise<boolean>}
|
|
788
823
|
*/
|
|
789
824
|
async isSameObject(other) {
|
|
790
|
-
|
|
825
|
+
const [left, right] = await Promise.all([this.#statForIdentity(), other.#statForIdentity()]);
|
|
826
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
791
827
|
}
|
|
792
828
|
|
|
793
829
|
/**
|
|
@@ -802,11 +838,8 @@ class Descriptor {
|
|
|
802
838
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
803
839
|
*/
|
|
804
840
|
async metadataHash() {
|
|
805
|
-
if (this.#hostPreopen) {
|
|
806
|
-
return { upper: 0n, lower: BigInt(this._id) };
|
|
807
|
-
}
|
|
808
841
|
try {
|
|
809
|
-
const s = await this.#
|
|
842
|
+
const s = await this.#statForIdentity();
|
|
810
843
|
return { upper: s.mtimeNs, lower: s.ino };
|
|
811
844
|
} catch (e) {
|
|
812
845
|
throw FSError.from(e);
|
|
@@ -827,10 +860,11 @@ class Descriptor {
|
|
|
827
860
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
828
861
|
*/
|
|
829
862
|
async metadataHashAt(flags, path) {
|
|
863
|
+
await this.#ensureSandboxedPath(path);
|
|
830
864
|
const full = this.#getFullPath(path, false);
|
|
831
865
|
try {
|
|
832
866
|
const statFn = flags.symlinkFollow ? fs.stat : fs.lstat;
|
|
833
|
-
const s = await statFn(full);
|
|
867
|
+
const s = await statFn(full, { bigint: true });
|
|
834
868
|
return { upper: s.mtimeNs, lower: s.ino };
|
|
835
869
|
} catch (e) {
|
|
836
870
|
throw FSError.from(e);
|
|
@@ -896,6 +930,10 @@ class Descriptor {
|
|
|
896
930
|
#getFullPath(subpath, _followSymlinks) {
|
|
897
931
|
subpath = subpath.replaceAll("\\", "/").replace(/\/\/+/g, "/");
|
|
898
932
|
|
|
933
|
+
if (subpath === "") {
|
|
934
|
+
throw new FSError("no-entry");
|
|
935
|
+
}
|
|
936
|
+
|
|
899
937
|
if (subpath.startsWith("/")) {
|
|
900
938
|
throw new FSError("not-permitted");
|
|
901
939
|
}
|
|
@@ -924,6 +962,59 @@ class Descriptor {
|
|
|
924
962
|
return `${baseNormalized}/${segments.join("/")}`;
|
|
925
963
|
}
|
|
926
964
|
|
|
965
|
+
async #statForIdentity() {
|
|
966
|
+
if (this.#hostPreopen) {
|
|
967
|
+
return fs.stat(this.#hostPreopen, { bigint: true });
|
|
968
|
+
}
|
|
969
|
+
this.#ensureHandle();
|
|
970
|
+
return this.#handle.stat({ bigint: true });
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// WASI paths are always relative to a directory descriptor. During path
|
|
974
|
+
// resolution, both `..` and symlinks must not escape that descriptor's base.
|
|
975
|
+
async #ensureSandboxedPath(subpath) {
|
|
976
|
+
if (!this.#isDirectory) {
|
|
977
|
+
throw new FSError("not-directory");
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const base = this.#hostPreopen ?? this.#fullPath;
|
|
981
|
+
const baseResolved = nodePath.resolve(base);
|
|
982
|
+
const segments = subpath.replaceAll("\\", "/").replace(/\/\/+/g, "/").split("/");
|
|
983
|
+
let current = baseResolved;
|
|
984
|
+
|
|
985
|
+
for (const seg of segments) {
|
|
986
|
+
if (seg === "" || seg === ".") {
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
if (seg === "..") {
|
|
990
|
+
current = nodePath.dirname(current);
|
|
991
|
+
if (!isWithinPath(baseResolved, current)) {
|
|
992
|
+
throw new FSError("not-permitted");
|
|
993
|
+
}
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
current = nodePath.join(current, seg);
|
|
998
|
+
let stat;
|
|
999
|
+
try {
|
|
1000
|
+
stat = await fs.lstat(current);
|
|
1001
|
+
} catch (err) {
|
|
1002
|
+
if (err.code === "ENOENT") {
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
throw FSError.from(err);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
if (stat.isSymbolicLink()) {
|
|
1009
|
+
const target = await fs.readlink(current);
|
|
1010
|
+
current = nodePath.resolve(nodePath.dirname(current), target);
|
|
1011
|
+
if (!isWithinPath(baseResolved, current)) {
|
|
1012
|
+
throw new FSError("not-permitted");
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
927
1018
|
#ensureHandle() {
|
|
928
1019
|
if (!this.#handle) {
|
|
929
1020
|
throw new FSError("bad-descriptor");
|
|
@@ -964,6 +1055,11 @@ function stripTrailingSlash(path) {
|
|
|
964
1055
|
return path.replace(/\/+$/, "");
|
|
965
1056
|
}
|
|
966
1057
|
|
|
1058
|
+
function isWithinPath(base, candidate) {
|
|
1059
|
+
const relative = nodePath.relative(base, candidate);
|
|
1060
|
+
return relative === "" || (!relative.startsWith("..") && !nodePath.isAbsolute(relative));
|
|
1061
|
+
}
|
|
1062
|
+
|
|
967
1063
|
const preopenEntries = [];
|
|
968
1064
|
export const preopens = {
|
|
969
1065
|
Descriptor,
|
|
@@ -115,16 +115,19 @@ export class Fields {
|
|
|
115
115
|
let bucket = this.#table.get(lowercased);
|
|
116
116
|
if (bucket) {
|
|
117
117
|
this.#entries = this.#entries.filter((e) => !bucket.includes(e));
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
this.#table.delete(lowercased);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (values.length === 0) {
|
|
122
|
+
return;
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
bucket = [];
|
|
126
|
+
this.#table.set(lowercased, bucket);
|
|
124
127
|
for (const value of values) {
|
|
125
128
|
const entry = [name, value];
|
|
126
129
|
this.#entries.push(entry);
|
|
127
|
-
|
|
130
|
+
bucket.push(entry);
|
|
128
131
|
}
|
|
129
132
|
}
|
|
130
133
|
|
|
@@ -140,6 +143,7 @@ export class Fields {
|
|
|
140
143
|
*/
|
|
141
144
|
delete(name) {
|
|
142
145
|
this.#ensureMutable();
|
|
146
|
+
this.#validateName(name);
|
|
143
147
|
const lowercased = name.toLowerCase();
|
|
144
148
|
const tableEntries = this.#table.get(lowercased);
|
|
145
149
|
|
|
@@ -162,6 +166,7 @@ export class Fields {
|
|
|
162
166
|
*/
|
|
163
167
|
getAndDelete(name) {
|
|
164
168
|
this.#ensureMutable();
|
|
169
|
+
this.#validateName(name);
|
|
165
170
|
|
|
166
171
|
const values = this.get(name);
|
|
167
172
|
this.delete(name);
|
|
@@ -188,10 +193,11 @@ export class Fields {
|
|
|
188
193
|
this.#validateValue(name, value);
|
|
189
194
|
|
|
190
195
|
const lowercased = name.toLowerCase();
|
|
191
|
-
const entry = [name, value];
|
|
192
|
-
this.#entries.push(entry);
|
|
193
196
|
|
|
194
197
|
const tableEntries = this.#table.get(lowercased);
|
|
198
|
+
const entryName = tableEntries?.[0]?.[0] ?? name;
|
|
199
|
+
const entry = [entryName, value];
|
|
200
|
+
this.#entries.push(entry);
|
|
195
201
|
if (tableEntries) {
|
|
196
202
|
tableEntries.push(entry);
|
|
197
203
|
} else {
|
|
@@ -274,7 +280,7 @@ export class Fields {
|
|
|
274
280
|
|
|
275
281
|
#validateValue(name, value) {
|
|
276
282
|
try {
|
|
277
|
-
validateHeaderValue(name,
|
|
283
|
+
validateHeaderValue(name, bytesToHeaderValueString(value));
|
|
278
284
|
} catch {
|
|
279
285
|
throw new HttpError("invalid-syntax", `Invalid header value for ${name}`);
|
|
280
286
|
}
|
|
@@ -287,6 +293,14 @@ export class Fields {
|
|
|
287
293
|
}
|
|
288
294
|
}
|
|
289
295
|
|
|
296
|
+
function bytesToHeaderValueString(value) {
|
|
297
|
+
let result = "";
|
|
298
|
+
for (let i = 0; i < value.length; i += 0x8000) {
|
|
299
|
+
result += String.fromCharCode(...value.subarray(i, i + 0x8000));
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
|
|
290
304
|
export function _fieldsLock(fields) {
|
|
291
305
|
return Fields._lock(fields);
|
|
292
306
|
}
|
|
@@ -325,7 +325,7 @@ export class Request {
|
|
|
325
325
|
*/
|
|
326
326
|
setPathWithQuery(pathWithQuery) {
|
|
327
327
|
validateUrlPart(pathWithQuery, UrlPart.PATH_WITH_QUERY);
|
|
328
|
-
this.#pathWithQuery = pathWithQuery ?? undefined;
|
|
328
|
+
this.#pathWithQuery = pathWithQuery === "" ? "/" : (pathWithQuery ?? undefined);
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
/**
|
|
@@ -575,7 +575,7 @@ const UrlPart = {
|
|
|
575
575
|
};
|
|
576
576
|
|
|
577
577
|
function normalizeMethod(method) {
|
|
578
|
-
const VALUE_TOKEN_RE = /^[
|
|
578
|
+
const VALUE_TOKEN_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
579
579
|
|
|
580
580
|
if (typeof method === "string") {
|
|
581
581
|
if (!VALUE_TOKEN_RE.test(method)) {
|
|
@@ -597,7 +597,10 @@ function normalizeMethod(method) {
|
|
|
597
597
|
}
|
|
598
598
|
|
|
599
599
|
if (method.tag === "other" && typeof method.val === "string" && VALUE_TOKEN_RE.test(method.val)) {
|
|
600
|
-
|
|
600
|
+
const standard = method.val.toLowerCase();
|
|
601
|
+
return SUPPORTED_METHODS.includes(standard) && method.val === method.val.toUpperCase()
|
|
602
|
+
? { tag: standard }
|
|
603
|
+
: { tag: "other", val: method.val };
|
|
601
604
|
}
|
|
602
605
|
|
|
603
606
|
throw new HttpError("invalid-syntax");
|
|
@@ -614,7 +617,7 @@ function normalizeScheme(scheme) {
|
|
|
614
617
|
if (uppercase === "HTTP" || uppercase === "HTTPS") {
|
|
615
618
|
return { tag: uppercase };
|
|
616
619
|
}
|
|
617
|
-
return { tag: "other", val: scheme
|
|
620
|
+
return { tag: "other", val: scheme };
|
|
618
621
|
}
|
|
619
622
|
|
|
620
623
|
if (typeof scheme !== "object" || typeof scheme.tag !== "string") {
|
|
@@ -627,7 +630,11 @@ function normalizeScheme(scheme) {
|
|
|
627
630
|
|
|
628
631
|
if (scheme.tag === "other" && typeof scheme.val === "string") {
|
|
629
632
|
validateUrlPart(scheme.val, UrlPart.SCHEME);
|
|
630
|
-
|
|
633
|
+
const uppercase = scheme.val.toUpperCase();
|
|
634
|
+
if (uppercase === "HTTP" || uppercase === "HTTPS") {
|
|
635
|
+
return { tag: uppercase };
|
|
636
|
+
}
|
|
637
|
+
return { tag: "other", val: scheme.val };
|
|
631
638
|
}
|
|
632
639
|
|
|
633
640
|
throw new HttpError("invalid-syntax");
|
|
@@ -660,6 +667,10 @@ function validateUrlPart(value, part) {
|
|
|
660
667
|
throw new HttpError("invalid-syntax", `Invalid ${part}: ${value}`);
|
|
661
668
|
}
|
|
662
669
|
|
|
670
|
+
if (part === UrlPart.PATH_WITH_QUERY && /[ <>`]/.test(value)) {
|
|
671
|
+
throw new HttpError("invalid-syntax", `Invalid ${part}: ${value}`);
|
|
672
|
+
}
|
|
673
|
+
|
|
663
674
|
try {
|
|
664
675
|
switch (part) {
|
|
665
676
|
case UrlPart.PATH_WITH_QUERY:
|
|
@@ -23,6 +23,16 @@ function token() {
|
|
|
23
23
|
return (TCP_CREATE_TOKEN ??= Symbol("TcpCreateToken"));
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function invalidRecv() {
|
|
27
|
+
const stream = new ReadableStream({
|
|
28
|
+
start(controller) {
|
|
29
|
+
controller.close();
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const promise = Promise.reject(new SocketError("invalid-state"));
|
|
33
|
+
return [new StreamReader(stream, { preventCancel: false }), new FutureReader(promise)];
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
const STATE = {
|
|
27
37
|
UNBOUND: "unbound",
|
|
28
38
|
BOUND: "bound",
|
|
@@ -316,16 +326,10 @@ export class TcpSocket {
|
|
|
316
326
|
*/
|
|
317
327
|
receive() {
|
|
318
328
|
if (this.#state !== STATE.CONNECTED) {
|
|
319
|
-
|
|
329
|
+
return invalidRecv();
|
|
320
330
|
}
|
|
321
331
|
if (this.#receiveStarted) {
|
|
322
|
-
|
|
323
|
-
start(controller) {
|
|
324
|
-
controller.close();
|
|
325
|
-
},
|
|
326
|
-
});
|
|
327
|
-
const promise = Promise.reject(new SocketError("invalid-state"));
|
|
328
|
-
return [new StreamReader(stream, { preventCancel: false }), new FutureReader(promise)];
|
|
332
|
+
return invalidRecv();
|
|
329
333
|
}
|
|
330
334
|
this.#receiveStarted = true;
|
|
331
335
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytecodealliance/preview3-shim",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
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": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"globals": "^16.3.0",
|
|
45
45
|
"vite": "^7.1.5",
|
|
46
|
-
"vitest": "^
|
|
46
|
+
"vitest": "^4.1.0"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"compile:check": "tsc --noEmit types/index.d.ts",
|