@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/preview2-shim",
3
- "version": "0.14.1",
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 10000"
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` represents that either the HTTP Request or Response body,
259
- * as well as any trailers, were received successfully, or that an error
260
- * occured receiving them. The optional `trailers` indicates whether or not
261
- * trailers were present in the body.
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 FutureIncomingResponse {
622
- subscribe(): Pollable;
623
- get(): Result<Result<IncomingResponse, ErrorCode>, void> | undefined;
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 FutureTrailers {
649
+ export class FutureIncomingResponse {
638
650
  subscribe(): Pollable;
639
- get(): Result<Trailers | undefined, ErrorCode> | undefined;
651
+ get(): Result<Result<IncomingResponse, ErrorCode>, void> | undefined;
640
652
  }
641
653
 
642
- export class OutgoingRequest {
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 ResponseOutparam {
672
- static set(param: ResponseOutparam, response: Result<OutgoingResponse, ErrorCode>): void;
668
+ export class FutureTrailers {
669
+ subscribe(): Pollable;
670
+ get(): Result<Result<Trailers | undefined, ErrorCode>, void> | undefined;
673
671
  }
674
672
 
675
- export class IncomingRequest {
676
- method(): Method;
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 IncomingResponse {
693
- status(): StatusCode;
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 OutgoingBody {
699
- write(): OutputStream;
700
- static finish(this_: OutgoingBody, trailers: Trailers | undefined): void;
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>
@@ -1,7 +0,0 @@
1
- export function assert(condition, tag, _val) {
2
- if (condition) {
3
- // TODO: throw meaningful errors
4
- // NOTE: wasmtime conformance tests are expecting a string here (a tag)
5
- throw tag;
6
- }
7
- }
@@ -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;