@bytecodealliance/preview2-shim 0.14.1 → 0.15.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.
- package/README.md +2 -2
- package/lib/browser/filesystem.js +6 -5
- package/lib/browser/random.js +1 -1
- package/lib/browser/sockets.js +0 -14
- package/lib/io/calls.js +80 -16
- package/lib/io/worker-http.js +164 -67
- package/lib/io/worker-io.js +207 -68
- package/lib/io/worker-socket-tcp.js +285 -0
- package/lib/io/worker-socket-udp.js +576 -0
- package/lib/io/worker-sockets.js +371 -0
- package/lib/io/worker-thread.js +793 -399
- package/lib/nodejs/cli.js +29 -13
- package/lib/nodejs/clocks.js +9 -6
- package/lib/nodejs/filesystem.js +170 -57
- package/lib/nodejs/http.js +662 -531
- package/lib/nodejs/index.js +0 -3
- package/lib/nodejs/sockets.js +571 -11
- package/lib/synckit/index.js +25 -41
- package/package.json +2 -2
- package/types/interfaces/wasi-http-types.d.ts +53 -41
- package/types/interfaces/wasi-sockets-tcp.d.ts +5 -0
- package/lib/common/assert.js +0 -7
- package/lib/nodejs/sockets/socket-common.js +0 -116
- package/lib/nodejs/sockets/socketopts-bindings.js +0 -94
- package/lib/nodejs/sockets/tcp-socket-impl.js +0 -794
- package/lib/nodejs/sockets/udp-socket-impl.js +0 -628
- package/lib/nodejs/sockets/wasi-sockets.js +0 -320
- package/lib/synckit/index.d.ts +0 -71
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytecodealliance/preview2-shim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "WASI Preview2 shim for JS environments",
|
|
5
5
|
"author": "Guy Bedford, Eduardo Rodrigues<16357187+eduardomourar@users.noreply.github.com>",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"test": "mocha -u tdd test/test.js --timeout
|
|
21
|
+
"test": "node --expose-gc ../../node_modules/mocha/bin/mocha.js -u tdd test/test.js --timeout 30000"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"types",
|
|
@@ -37,7 +37,14 @@ export namespace WasiHttpTypes {
|
|
|
37
37
|
* syntactically invalid, or if a header was forbidden.
|
|
38
38
|
*/
|
|
39
39
|
/**
|
|
40
|
-
* Get all of the values corresponding to a key.
|
|
40
|
+
* Get all of the values corresponding to a key. If the key is not present
|
|
41
|
+
* in this `fields`, an empty list is returned. However, if the key is
|
|
42
|
+
* present but empty, this is represented by a list with one or more
|
|
43
|
+
* empty field-values present.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Returns `true` when the key is present in this `fields`. If the key is
|
|
47
|
+
* syntactically invalid, `false` is returned.
|
|
41
48
|
*/
|
|
42
49
|
/**
|
|
43
50
|
* Set all of the values for a key. Clears any existing values for that
|
|
@@ -255,10 +262,14 @@ export namespace WasiHttpTypes {
|
|
|
255
262
|
* The outer `option` represents future readiness. Users can wait on this
|
|
256
263
|
* `option` to become `some` using the `subscribe` method.
|
|
257
264
|
*
|
|
258
|
-
* The `result`
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
265
|
+
* The outer `result` is used to retrieve the trailers or error at most
|
|
266
|
+
* once. It will be success on the first call in which the outer option
|
|
267
|
+
* is `some`, and error on subsequent calls.
|
|
268
|
+
*
|
|
269
|
+
* The inner `result` represents that either the HTTP Request or Response
|
|
270
|
+
* body, as well as any trailers, were received successfully, or that an
|
|
271
|
+
* error occured receiving them. The optional `trailers` indicates whether
|
|
272
|
+
* or not trailers were present in the body.
|
|
262
273
|
*
|
|
263
274
|
* When some `trailers` are returned by this method, the `trailers`
|
|
264
275
|
* resource is immutable, and a child. Use of the `set`, `append`, or
|
|
@@ -349,7 +360,7 @@ import type { InputStream } from '../interfaces/wasi-io-streams.js';
|
|
|
349
360
|
export { InputStream };
|
|
350
361
|
import type { OutputStream } from '../interfaces/wasi-io-streams.js';
|
|
351
362
|
export { OutputStream };
|
|
352
|
-
import type { IoError } from '../interfaces/wasi-io-error.js';
|
|
363
|
+
import type { Error as IoError } from '../interfaces/wasi-io-error.js';
|
|
353
364
|
export { IoError };
|
|
354
365
|
import type { Pollable } from '../interfaces/wasi-io-poll.js';
|
|
355
366
|
export { Pollable };
|
|
@@ -618,15 +629,16 @@ export type Trailers = Fields;
|
|
|
618
629
|
export type StatusCode = number;
|
|
619
630
|
export type Result<T, E> = { tag: 'ok', val: T } | { tag: 'err', val: E };
|
|
620
631
|
|
|
621
|
-
export class
|
|
622
|
-
|
|
623
|
-
|
|
632
|
+
export class OutgoingBody {
|
|
633
|
+
write(): OutputStream;
|
|
634
|
+
static finish(this_: OutgoingBody, trailers: Trailers | undefined): void;
|
|
624
635
|
}
|
|
625
636
|
|
|
626
637
|
export class Fields {
|
|
627
638
|
constructor()
|
|
628
639
|
static fromList(entries: [FieldKey, FieldValue][]): Fields;
|
|
629
640
|
get(name: FieldKey): FieldValue[];
|
|
641
|
+
has(name: FieldKey): boolean;
|
|
630
642
|
set(name: FieldKey, value: FieldValue[]): void;
|
|
631
643
|
delete(name: FieldKey): void;
|
|
632
644
|
append(name: FieldKey, value: FieldValue): void;
|
|
@@ -634,33 +646,18 @@ export class Fields {
|
|
|
634
646
|
clone(): Fields;
|
|
635
647
|
}
|
|
636
648
|
|
|
637
|
-
export class
|
|
649
|
+
export class FutureIncomingResponse {
|
|
638
650
|
subscribe(): Pollable;
|
|
639
|
-
get(): Result<
|
|
651
|
+
get(): Result<Result<IncomingResponse, ErrorCode>, void> | undefined;
|
|
640
652
|
}
|
|
641
653
|
|
|
642
|
-
export class
|
|
643
|
-
constructor(headers: Headers)
|
|
644
|
-
body(): OutgoingBody;
|
|
654
|
+
export class IncomingRequest {
|
|
645
655
|
method(): Method;
|
|
646
|
-
setMethod(method: Method): void;
|
|
647
656
|
pathWithQuery(): string | undefined;
|
|
648
|
-
setPathWithQuery(pathWithQuery: string | undefined): void;
|
|
649
657
|
scheme(): Scheme | undefined;
|
|
650
|
-
setScheme(scheme: Scheme | undefined): void;
|
|
651
658
|
authority(): string | undefined;
|
|
652
|
-
setAuthority(authority: string | undefined): void;
|
|
653
659
|
headers(): Headers;
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
export class RequestOptions {
|
|
657
|
-
constructor()
|
|
658
|
-
connectTimeoutMs(): Duration | undefined;
|
|
659
|
-
setConnectTimeoutMs(ms: Duration | undefined): void;
|
|
660
|
-
firstByteTimeoutMs(): Duration | undefined;
|
|
661
|
-
setFirstByteTimeoutMs(ms: Duration | undefined): void;
|
|
662
|
-
betweenBytesTimeoutMs(): Duration | undefined;
|
|
663
|
-
setBetweenBytesTimeoutMs(ms: Duration | undefined): void;
|
|
660
|
+
consume(): IncomingBody;
|
|
664
661
|
}
|
|
665
662
|
|
|
666
663
|
export class IncomingBody {
|
|
@@ -668,15 +665,13 @@ export class IncomingBody {
|
|
|
668
665
|
static finish(this_: IncomingBody): FutureTrailers;
|
|
669
666
|
}
|
|
670
667
|
|
|
671
|
-
export class
|
|
672
|
-
|
|
668
|
+
export class FutureTrailers {
|
|
669
|
+
subscribe(): Pollable;
|
|
670
|
+
get(): Result<Result<Trailers | undefined, ErrorCode>, void> | undefined;
|
|
673
671
|
}
|
|
674
672
|
|
|
675
|
-
export class
|
|
676
|
-
|
|
677
|
-
pathWithQuery(): string | undefined;
|
|
678
|
-
scheme(): Scheme | undefined;
|
|
679
|
-
authority(): string | undefined;
|
|
673
|
+
export class IncomingResponse {
|
|
674
|
+
status(): StatusCode;
|
|
680
675
|
headers(): Headers;
|
|
681
676
|
consume(): IncomingBody;
|
|
682
677
|
}
|
|
@@ -689,13 +684,30 @@ export class OutgoingResponse {
|
|
|
689
684
|
body(): OutgoingBody;
|
|
690
685
|
}
|
|
691
686
|
|
|
692
|
-
export class
|
|
693
|
-
|
|
687
|
+
export class OutgoingRequest {
|
|
688
|
+
constructor(headers: Headers)
|
|
689
|
+
body(): OutgoingBody;
|
|
690
|
+
method(): Method;
|
|
691
|
+
setMethod(method: Method): void;
|
|
692
|
+
pathWithQuery(): string | undefined;
|
|
693
|
+
setPathWithQuery(pathWithQuery: string | undefined): void;
|
|
694
|
+
scheme(): Scheme | undefined;
|
|
695
|
+
setScheme(scheme: Scheme | undefined): void;
|
|
696
|
+
authority(): string | undefined;
|
|
697
|
+
setAuthority(authority: string | undefined): void;
|
|
694
698
|
headers(): Headers;
|
|
695
|
-
consume(): IncomingBody;
|
|
696
699
|
}
|
|
697
700
|
|
|
698
|
-
export class
|
|
699
|
-
|
|
700
|
-
|
|
701
|
+
export class RequestOptions {
|
|
702
|
+
constructor()
|
|
703
|
+
connectTimeout(): Duration | undefined;
|
|
704
|
+
setConnectTimeout(duration: Duration | undefined): void;
|
|
705
|
+
firstByteTimeout(): Duration | undefined;
|
|
706
|
+
setFirstByteTimeout(duration: Duration | undefined): void;
|
|
707
|
+
betweenBytesTimeout(): Duration | undefined;
|
|
708
|
+
setBetweenBytesTimeout(duration: Duration | undefined): void;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export class ResponseOutparam {
|
|
712
|
+
static set(param: ResponseOutparam, response: Result<OutgoingResponse, ErrorCode>): void;
|
|
701
713
|
}
|
|
@@ -24,6 +24,11 @@ export namespace WasiSocketsTcp {
|
|
|
24
24
|
* - `not-in-progress`: A `bind` operation is not in progress.
|
|
25
25
|
* - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
|
|
26
26
|
*
|
|
27
|
+
* # Implementors note
|
|
28
|
+
* When binding to a non-zero port, this bind operation shouldn't be affected by the TIME_WAIT
|
|
29
|
+
* state of a recently closed socket on the same local address (i.e. the SO_REUSEADDR socket
|
|
30
|
+
* option should be set implicitly on platforms that require it).
|
|
31
|
+
*
|
|
27
32
|
* # References
|
|
28
33
|
* - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html>
|
|
29
34
|
* - <https://man7.org/linux/man-pages/man2/bind.2.html>
|
package/lib/common/assert.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
export function cappedUint32(value) {
|
|
2
|
-
// Note: cap the value to the highest possible BigInt value that can be represented as a
|
|
3
|
-
// unsigned 32-bit integer.
|
|
4
|
-
const width = 32n;
|
|
5
|
-
return BigInt.asUintN(Number(width), value);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function noop() {}
|
|
9
|
-
|
|
10
|
-
function tupleToIPv6(arr) {
|
|
11
|
-
if (arr.length !== 8) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
return arr.map((segment) => segment.toString(16)).join(":");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function tupleToIpv4(arr) {
|
|
18
|
-
if (arr.length !== 4) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
return arr.map((segment) => segment.toString(10)).join(".");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// TODO: write a better (faste?) parser for ipv6
|
|
25
|
-
function ipv6ToTuple(ipv6) {
|
|
26
|
-
if (ipv6 === "::1") {
|
|
27
|
-
return [0, 0, 0, 0, 0, 0, 0, 1];
|
|
28
|
-
} else if (ipv6 === "::") {
|
|
29
|
-
return [0, 0, 0, 0, 0, 0, 0, 0];
|
|
30
|
-
} else if (ipv6.includes("::")) {
|
|
31
|
-
const [head, tail] = ipv6.split("::");
|
|
32
|
-
const headSegments = head.split(":").map((segment) => parseInt(segment, 16));
|
|
33
|
-
const tailSegments = tail.split(":").map((segment) => parseInt(segment, 16));
|
|
34
|
-
const missingSegments = 8 - headSegments.length - tailSegments.length;
|
|
35
|
-
const middleSegments = Array(missingSegments).fill(0);
|
|
36
|
-
return headSegments.concat(middleSegments).concat(tailSegments);
|
|
37
|
-
}
|
|
38
|
-
return ipv6.split(":").map((segment) => parseInt(segment, 16));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function ipv4ToTuple(ipv4) {
|
|
42
|
-
return ipv4.split(".").map((segment) => parseInt(segment, 10));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function serializeIpAddress(addr = undefined, includePort = false) {
|
|
46
|
-
if (addr === undefined) {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const family = addr.tag;
|
|
51
|
-
|
|
52
|
-
let { address } = addr.val;
|
|
53
|
-
if (family.toLocaleLowerCase() === "ipv4") {
|
|
54
|
-
address = tupleToIpv4(address);
|
|
55
|
-
} else if (family.toLocaleLowerCase() === "ipv6") {
|
|
56
|
-
address = tupleToIPv6(address);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (includePort) {
|
|
60
|
-
address = `${address}:${addr.val.port}`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return address;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function deserializeIpAddress(addr, family) {
|
|
67
|
-
let address = [];
|
|
68
|
-
if (family.toLocaleLowerCase() === "ipv4") {
|
|
69
|
-
address = ipv4ToTuple(addr);
|
|
70
|
-
} else if (family.toLocaleLowerCase() === "ipv6") {
|
|
71
|
-
address = ipv6ToTuple(addr);
|
|
72
|
-
}
|
|
73
|
-
return address;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function findUnsuedLocalAddress(family) {
|
|
77
|
-
let address = [127, 0, 0, 1];
|
|
78
|
-
if (family.toLocaleLowerCase() === "ipv6") {
|
|
79
|
-
address = [0, 0, 0, 0, 0, 0, 0, 1];
|
|
80
|
-
}
|
|
81
|
-
return {
|
|
82
|
-
tag: family,
|
|
83
|
-
val: {
|
|
84
|
-
address,
|
|
85
|
-
port: 0,
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function isUnicastIpAddress(ipSocketAddress) {
|
|
91
|
-
return !isMulticastIpAddress(ipSocketAddress) && !isBroadcastIpAddress(ipSocketAddress);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function isMulticastIpAddress(ipSocketAddress) {
|
|
95
|
-
// ipv6: [0xff00, 0, 0, 0, 0, 0, 0, 0]
|
|
96
|
-
// ipv4: [224, 0, 0, 0]
|
|
97
|
-
return ipSocketAddress.val.address[0] === 224 || ipSocketAddress.val.address[0] === 0xff00;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function isBroadcastIpAddress(ipSocketAddress) {
|
|
101
|
-
// ipv4: [255, 255, 255, 255]
|
|
102
|
-
return (
|
|
103
|
-
ipSocketAddress.val.address[0] === 0xff && // 255
|
|
104
|
-
ipSocketAddress.val.address[1] === 0xff && // 255
|
|
105
|
-
ipSocketAddress.val.address[2] === 0xff && // 255
|
|
106
|
-
ipSocketAddress.val.address[3] === 0xff // 255
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function isIPv4MappedAddress(ipSocketAddress) {
|
|
111
|
-
// ipv6: [0, 0, 0, 0, 0, 0xffff, 0, 0]
|
|
112
|
-
if (ipSocketAddress.val.address.length !== 8) {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
return ipSocketAddress.val.address[5] === 0xffff;
|
|
116
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { platform } from "node:os";
|
|
2
|
-
import { _errnoException } from "node:util";
|
|
3
|
-
import { types, refType } from "ref-napi";
|
|
4
|
-
import { Library, errno as _errno } from "ffi-napi";
|
|
5
|
-
|
|
6
|
-
const tryGetUV = (() => {
|
|
7
|
-
let UV = null;
|
|
8
|
-
return () => {
|
|
9
|
-
if (UV === null) {
|
|
10
|
-
try {
|
|
11
|
-
UV = typeof process.binding === "function" ? process.binding("uv") : undefined;
|
|
12
|
-
} catch (ex) {
|
|
13
|
-
// Continue regardless
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return UV;
|
|
17
|
-
};
|
|
18
|
-
})();
|
|
19
|
-
|
|
20
|
-
const uvErrName = (errno) => {
|
|
21
|
-
const UV = tryGetUV();
|
|
22
|
-
return UV && UV.errname ? UV.errname(errno) : "UNKNOWN";
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const errnoException = (errno, syscall, original) => {
|
|
26
|
-
if (_errnoException) {
|
|
27
|
-
return _errnoException(-errno, syscall, original);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const errname = uvErrName(-errno),
|
|
31
|
-
message = original ? `${syscall} ${errname} (${errno}) ${original}` : `${syscall} ${errname} (${errno})`;
|
|
32
|
-
|
|
33
|
-
const e = new Error(message);
|
|
34
|
-
e.code = errname;
|
|
35
|
-
e.errno = errname;
|
|
36
|
-
e.syscall = syscall;
|
|
37
|
-
return e;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const createFFI = () => {
|
|
41
|
-
const cInt = types.int;
|
|
42
|
-
const cVoid = types.void;
|
|
43
|
-
|
|
44
|
-
return Library(null, {
|
|
45
|
-
//name ret 1 2 3 4 5
|
|
46
|
-
setsockopt: [cInt, [cInt, cInt, cInt, refType(cVoid), cInt]],
|
|
47
|
-
getsockopt: [cInt, [cInt, cInt, cInt, refType(cVoid), refType(cInt)]],
|
|
48
|
-
});
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const ffi = (() => {
|
|
52
|
-
let instance;
|
|
53
|
-
return () => {
|
|
54
|
-
if (!instance) {
|
|
55
|
-
instance = createFFI();
|
|
56
|
-
}
|
|
57
|
-
return instance;
|
|
58
|
-
};
|
|
59
|
-
})();
|
|
60
|
-
|
|
61
|
-
const _setsockopt = (fd, level, name, value, valueLength) => {
|
|
62
|
-
if (fd == null) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const err = ffi().setsockopt(fd, level, name, value, valueLength);
|
|
67
|
-
|
|
68
|
-
if (err !== 0) {
|
|
69
|
-
const errno = _errno();
|
|
70
|
-
throw errnoException(errno, "setsockopt");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return true;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const _getsockopt = (fd, level, name, value, valueLength) => {
|
|
77
|
-
if (fd == null) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const err = ffi().getsockopt(fd, level, name, value, valueLength);
|
|
82
|
-
|
|
83
|
-
if (err !== 0) {
|
|
84
|
-
const errno = _errno();
|
|
85
|
-
throw errnoException(errno, "getsockopt");
|
|
86
|
-
}
|
|
87
|
-
return true;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const noop = () => false;
|
|
91
|
-
const isWin32 = platform() === "win32";
|
|
92
|
-
|
|
93
|
-
export const setsockopt = isWin32 ? noop : _setsockopt;
|
|
94
|
-
export const getsockopt = isWin32 ? noop : _getsockopt;
|