@bytecodealliance/preview3-shim 0.1.1 → 0.2.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/dist/nodejs/cli.d.ts +51 -0
- package/dist/nodejs/cli.js +106 -0
- package/dist/nodejs/clocks.d.ts +55 -0
- package/dist/nodejs/clocks.js +83 -0
- package/dist/nodejs/filesystem/descriptor.d.ts +443 -0
- package/dist/nodejs/filesystem/descriptor.js +1010 -0
- package/dist/nodejs/filesystem/error.d.ts +61 -0
- package/dist/nodejs/filesystem/error.js +86 -0
- package/dist/nodejs/filesystem/utils.d.ts +8 -0
- package/dist/nodejs/filesystem/utils.js +25 -0
- package/dist/nodejs/filesystem.js +2 -0
- package/dist/nodejs/finalization.d.ts +2 -0
- package/{lib → dist}/nodejs/finalization.js +15 -21
- package/dist/nodejs/future.d.ts +98 -0
- package/dist/nodejs/future.js +176 -0
- package/dist/nodejs/http/client.d.ts +22 -0
- package/dist/nodejs/http/client.js +138 -0
- package/dist/nodejs/http/error.d.ts +18 -0
- package/dist/nodejs/http/error.js +62 -0
- package/dist/nodejs/http/fields.d.ts +144 -0
- package/dist/nodejs/http/fields.js +327 -0
- package/dist/nodejs/http/request.d.ts +256 -0
- package/dist/nodejs/http/request.js +606 -0
- package/dist/nodejs/http/response.d.ts +82 -0
- package/dist/nodejs/http/response.js +202 -0
- package/dist/nodejs/http/server.d.ts +13 -0
- package/dist/nodejs/http/server.js +127 -0
- package/dist/nodejs/http.d.ts +19 -0
- package/{lib → dist}/nodejs/http.js +13 -18
- package/dist/nodejs/index.js +8 -0
- package/dist/nodejs/random.d.ts +5 -0
- package/{lib → dist}/nodejs/random.js +2 -8
- package/dist/nodejs/sockets/address.d.ts +78 -0
- package/dist/nodejs/sockets/address.js +120 -0
- package/dist/nodejs/sockets/error.d.ts +83 -0
- package/dist/nodejs/sockets/error.js +120 -0
- package/dist/nodejs/sockets/ip-name-lookup.d.ts +18 -0
- package/dist/nodejs/sockets/ip-name-lookup.js +84 -0
- package/dist/nodejs/sockets/tcp.d.ts +333 -0
- package/dist/nodejs/sockets/tcp.js +723 -0
- package/dist/nodejs/sockets/udp.d.ts +224 -0
- package/dist/nodejs/sockets/udp.js +475 -0
- package/dist/nodejs/sockets.d.ts +11 -0
- package/{lib → dist}/nodejs/sockets.js +2 -5
- package/dist/nodejs/stream.d.ts +161 -0
- package/dist/nodejs/stream.js +388 -0
- package/dist/nodejs/workers/cli-worker.d.ts +1 -0
- package/dist/nodejs/workers/cli-worker.js +41 -0
- package/dist/nodejs/workers/filesystem-worker.d.ts +1 -0
- package/dist/nodejs/workers/filesystem-worker.js +102 -0
- package/dist/nodejs/workers/http-worker.d.ts +1 -0
- package/dist/nodejs/workers/http-worker.js +355 -0
- package/dist/nodejs/workers/resource-worker.d.ts +13 -0
- package/dist/nodejs/workers/resource-worker.js +152 -0
- package/dist/nodejs/workers/tcp-worker.d.ts +2 -0
- package/dist/nodejs/workers/tcp-worker.js +318 -0
- package/dist/nodejs/workers/udp-worker.d.ts +1 -0
- package/dist/nodejs/workers/udp-worker.js +156 -0
- package/package.json +20 -12
- package/types/interfaces/wasi-cli-environment.d.ts +3 -3
- package/types/interfaces/wasi-cli-exit.d.ts +12 -1
- package/types/interfaces/wasi-cli-run.d.ts +1 -1
- package/types/interfaces/wasi-cli-stderr.d.ts +3 -3
- package/types/interfaces/wasi-cli-stdin.d.ts +5 -5
- package/types/interfaces/wasi-cli-stdout.d.ts +3 -3
- package/types/interfaces/wasi-cli-terminal-input.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-output.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stderr.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stdin.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stdout.d.ts +1 -1
- package/types/interfaces/wasi-cli-types.d.ts +5 -5
- package/types/interfaces/wasi-clocks-monotonic-clock.d.ts +3 -3
- package/types/interfaces/wasi-clocks-system-clock.d.ts +6 -6
- package/types/interfaces/wasi-clocks-types.d.ts +1 -1
- package/types/interfaces/wasi-filesystem-preopens.d.ts +1 -1
- package/types/interfaces/wasi-filesystem-types.d.ts +74 -74
- package/types/interfaces/wasi-http-client.d.ts +1 -1
- package/types/interfaces/wasi-http-handler.d.ts +1 -1
- package/types/interfaces/wasi-http-types.d.ts +34 -34
- package/types/interfaces/wasi-random-insecure-seed.d.ts +5 -5
- package/types/interfaces/wasi-random-insecure.d.ts +5 -5
- package/types/interfaces/wasi-random-random.d.ts +5 -5
- package/types/interfaces/wasi-sockets-ip-name-lookup.d.ts +11 -11
- package/types/interfaces/wasi-sockets-types.d.ts +121 -121
- package/types/wasi-cli-command.d.ts +23 -23
- package/types/wasi-http-service.d.ts +14 -14
- package/lib/nodejs/cli.js +0 -127
- package/lib/nodejs/clocks.js +0 -100
- package/lib/nodejs/filesystem/descriptor.js +0 -1093
- package/lib/nodejs/filesystem/error.js +0 -92
- package/lib/nodejs/filesystem/utils.js +0 -19
- package/lib/nodejs/future.js +0 -190
- package/lib/nodejs/http/client.js +0 -161
- package/lib/nodejs/http/error.js +0 -71
- package/lib/nodejs/http/fields.js +0 -373
- package/lib/nodejs/http/request.js +0 -691
- package/lib/nodejs/http/response.js +0 -227
- package/lib/nodejs/http/server.js +0 -157
- package/lib/nodejs/sockets/address.js +0 -146
- package/lib/nodejs/sockets/error.js +0 -123
- package/lib/nodejs/sockets/ip-name-lookup.js +0 -93
- package/lib/nodejs/sockets/tcp.js +0 -801
- package/lib/nodejs/sockets/udp.js +0 -516
- package/lib/nodejs/stream.js +0 -437
- package/lib/nodejs/workers/cli-worker.js +0 -49
- package/lib/nodejs/workers/filesystem-worker.js +0 -119
- package/lib/nodejs/workers/http-worker.js +0 -417
- package/lib/nodejs/workers/resource-worker.js +0 -195
- package/lib/nodejs/workers/tcp-worker.js +0 -370
- package/lib/nodejs/workers/udp-worker.js +0 -194
- /package/{lib/nodejs/filesystem.js → dist/nodejs/filesystem.d.ts} +0 -0
- /package/{lib/nodejs/index.js → dist/nodejs/index.d.ts} +0 -0
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
export const ERROR_MAP = {
|
|
2
|
-
EACCES: "access",
|
|
3
|
-
EALREADY: "already",
|
|
4
|
-
EBADF: "bad-descriptor",
|
|
5
|
-
EBUSY: "busy",
|
|
6
|
-
EDEADLK: "deadlock",
|
|
7
|
-
EDQUOT: "quota",
|
|
8
|
-
EEXIST: "exist",
|
|
9
|
-
EFBIG: "file-too-large",
|
|
10
|
-
EILSEQ: "illegal-byte-sequence",
|
|
11
|
-
EINPROGRESS: "in-progress",
|
|
12
|
-
EINTR: "interrupted",
|
|
13
|
-
EINVAL: "invalid",
|
|
14
|
-
EIO: "io",
|
|
15
|
-
EISDIR: "is-directory",
|
|
16
|
-
ELOOP: "loop",
|
|
17
|
-
EMLINK: "too-many-links",
|
|
18
|
-
EMSGSIZE: "message-size",
|
|
19
|
-
ENAMETOOLONG: "name-too-long",
|
|
20
|
-
ENODEV: "no-device",
|
|
21
|
-
ENOENT: "no-entry",
|
|
22
|
-
ENOLCK: "no-lock",
|
|
23
|
-
ENOMEM: "insufficient-memory",
|
|
24
|
-
ENOSPC: "insufficient-space",
|
|
25
|
-
ENOTDIR: "not-directory",
|
|
26
|
-
ERR_FS_EISDIR: "not-directory",
|
|
27
|
-
ENOTEMPTY: "not-empty",
|
|
28
|
-
ENOTRECOVERABLE: "not-recoverable",
|
|
29
|
-
ENOTSUP: "unsupported",
|
|
30
|
-
ENOTTY: "no-tty",
|
|
31
|
-
ENXIO: "no-such-device",
|
|
32
|
-
EOVERFLOW: "overflow",
|
|
33
|
-
EPERM: "not-permitted",
|
|
34
|
-
EPIPE: "pipe",
|
|
35
|
-
EROFS: "read-only",
|
|
36
|
-
ESPIPE: "invalid-seek",
|
|
37
|
-
ETXTBSY: "text-file-busy",
|
|
38
|
-
EXDEV: "cross-device",
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
function getErrorTag(e) {
|
|
42
|
-
if (e.code in ERROR_MAP) {
|
|
43
|
-
return ERROR_MAP[e.code];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Windows gives this error for badly structured `//` reads, this seems like
|
|
47
|
-
// a slightly better error than unknown given that it's a common footgun.
|
|
48
|
-
if (e.code === -4094 || (e.code === "UNKNOWN" && e.errno === -4094)) {
|
|
49
|
-
return "no-such-device";
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
throw e;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Custom error for File operations with JCO compatible payload.
|
|
57
|
-
*/
|
|
58
|
-
export class FSError extends Error {
|
|
59
|
-
/**
|
|
60
|
-
* @param {string} tag – machine‐readable error tag
|
|
61
|
-
* @param {string} [message] – human‐readable message
|
|
62
|
-
* @param {any} [val] – optional extra data
|
|
63
|
-
* @param {object} [opts]
|
|
64
|
-
* @param {Error} [opts.cause]
|
|
65
|
-
*/
|
|
66
|
-
constructor(tag, message, val, opts = {}) {
|
|
67
|
-
super(message ?? `Error: ${tag}`, { cause: opts.cause });
|
|
68
|
-
this.name = "FSError";
|
|
69
|
-
this.payload = val !== undefined ? { tag, val } : { tag };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Create or rewrap an error into FSError
|
|
74
|
-
* @param {any} err – number, string, Error, or FSError
|
|
75
|
-
*/
|
|
76
|
-
static from(err) {
|
|
77
|
-
if (err instanceof FSError) {
|
|
78
|
-
return err;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const tag = getErrorTag(err);
|
|
82
|
-
const message = err?.message;
|
|
83
|
-
return new FSError(tag, message, undefined, { cause: err });
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function filesystemErrorCode(err) {
|
|
88
|
-
if (err?.payload?.tag) {
|
|
89
|
-
return err.payload;
|
|
90
|
-
}
|
|
91
|
-
return { tag: getErrorTag(err) };
|
|
92
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/** Map fs.Dirent -> WASI type */
|
|
2
|
-
export function wasiTypeFromDirent(obj) {
|
|
3
|
-
if (obj.isFile()) {
|
|
4
|
-
return { tag: "regular-file" };
|
|
5
|
-
} else if (obj.isSocket()) {
|
|
6
|
-
return { tag: "socket" };
|
|
7
|
-
} else if (obj.isSymbolicLink()) {
|
|
8
|
-
return { tag: "symbolic-link" };
|
|
9
|
-
} else if (obj.isFIFO()) {
|
|
10
|
-
return { tag: "fifo" };
|
|
11
|
-
} else if (obj.isDirectory()) {
|
|
12
|
-
return { tag: "directory" };
|
|
13
|
-
} else if (obj.isCharacterDevice()) {
|
|
14
|
-
return { tag: "character-device" };
|
|
15
|
-
} else if (obj.isBlockDevice()) {
|
|
16
|
-
return { tag: "block-device" };
|
|
17
|
-
}
|
|
18
|
-
return { tag: "other", val: undefined };
|
|
19
|
-
}
|
package/lib/nodejs/future.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a future with a reader and writer.
|
|
3
|
-
*
|
|
4
|
-
* @returns {Object} An object containing:
|
|
5
|
-
* - `tx` {FutureWriter}: The writer for the future.
|
|
6
|
-
* - `rx` {FutureReader}: The reader for the future.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* // Basic usage - creating a communication channel
|
|
10
|
-
* const { tx, rx } = future();
|
|
11
|
-
*
|
|
12
|
-
* const message = 'Hello world!';
|
|
13
|
-
* await tx.write(message);
|
|
14
|
-
*
|
|
15
|
-
* // first read yields the message
|
|
16
|
-
* const value = await rx.read();
|
|
17
|
-
* expect(value).toBe(message);
|
|
18
|
-
*
|
|
19
|
-
* // subsequent reads yield null
|
|
20
|
-
* const noValue = await rx.read();
|
|
21
|
-
* expect(noValue).toBeNull();
|
|
22
|
-
*/
|
|
23
|
-
export function future() {
|
|
24
|
-
const def = deferred();
|
|
25
|
-
const tx = new FutureWriter(def);
|
|
26
|
-
const rx = new FutureReader(def.promise);
|
|
27
|
-
return { tx, rx };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function deferred() {
|
|
31
|
-
let resolve, reject;
|
|
32
|
-
const promise = new Promise((res, rej) => {
|
|
33
|
-
resolve = res;
|
|
34
|
-
reject = rej;
|
|
35
|
-
});
|
|
36
|
-
return { promise, resolve, reject };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export class FutureReader {
|
|
40
|
-
/** The underlying Promise to read from */
|
|
41
|
-
#promise;
|
|
42
|
-
/** Tracks if read() has been called (prevents multiple reads) */
|
|
43
|
-
#consumed = false;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Constructs a FutureReader.
|
|
47
|
-
*
|
|
48
|
-
* @param {Promise} promise - The promise to be read.
|
|
49
|
-
* @throws {Error} If the provided argument is not a promise.
|
|
50
|
-
*/
|
|
51
|
-
constructor(promise) {
|
|
52
|
-
if (!promise || typeof promise.then !== "function") {
|
|
53
|
-
throw new Error("Provided future must be a Promise");
|
|
54
|
-
}
|
|
55
|
-
if (promise instanceof Promise) {
|
|
56
|
-
promise.catch(() => {});
|
|
57
|
-
}
|
|
58
|
-
this.#promise = promise;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Reads the value from the promise. Can only be called once.
|
|
63
|
-
*
|
|
64
|
-
* @returns {Promise<any>} Resolves with the value of the promise or null if already consumed.
|
|
65
|
-
* @throws {Error} If the promise is rejected.
|
|
66
|
-
*/
|
|
67
|
-
async read() {
|
|
68
|
-
if (this.#consumed) {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
try {
|
|
72
|
-
return await this.#promise;
|
|
73
|
-
} catch (err) {
|
|
74
|
-
throw err;
|
|
75
|
-
} finally {
|
|
76
|
-
this.#consumed = true;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
then(resolve, reject) {
|
|
81
|
-
return this.read().then(resolve, reject);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Cancels the future. Not supported for FutureReader.
|
|
86
|
-
*/
|
|
87
|
-
async cancel() {
|
|
88
|
-
throw new Error("FutureReader does not support cancel");
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Closes the reader. No resources are released in this implementation.
|
|
93
|
-
*/
|
|
94
|
-
close() {
|
|
95
|
-
// Nothing to release.
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Converts the reader back into a promise.
|
|
100
|
-
*
|
|
101
|
-
* @returns {Promise} The original promise.
|
|
102
|
-
*/
|
|
103
|
-
intoPromise() {
|
|
104
|
-
const promise = this.#promise;
|
|
105
|
-
this.#promise = null;
|
|
106
|
-
return promise;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export class FutureWriter {
|
|
111
|
-
/** Deferred object with resolve/reject methods for controlling promise state */
|
|
112
|
-
#deferred;
|
|
113
|
-
/** Tracks if writer has been used */
|
|
114
|
-
#written = false;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Constructs a FutureWriter.
|
|
118
|
-
*
|
|
119
|
-
* @param {Object} deferred - A deferred object with `resolve` and `reject` methods.
|
|
120
|
-
* @throws {Error} If the deferred object is invalid.
|
|
121
|
-
*/
|
|
122
|
-
constructor(deferred) {
|
|
123
|
-
if (!deferred || typeof deferred.resolve !== "function") {
|
|
124
|
-
throw new Error("Provided deferred object must have a resolve method");
|
|
125
|
-
}
|
|
126
|
-
this.#deferred = deferred;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Resolves the promise with the given value.
|
|
131
|
-
*
|
|
132
|
-
* @param {any} value - The value to resolve the promise with.
|
|
133
|
-
* @throws {Error} If the writer is already closed.
|
|
134
|
-
*/
|
|
135
|
-
async write(value) {
|
|
136
|
-
this.#ensureState();
|
|
137
|
-
this.#written = true;
|
|
138
|
-
this.#deferred.resolve(value);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Rejects the promise with the given reason.
|
|
143
|
-
*
|
|
144
|
-
* @param {any} reason - The reason for rejecting the promise.
|
|
145
|
-
* @throws {Error} If the writer is already closed.
|
|
146
|
-
*/
|
|
147
|
-
async abort(reason) {
|
|
148
|
-
this.#ensureState();
|
|
149
|
-
this.#written = true;
|
|
150
|
-
this.#deferred.reject(reason);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Resolves the promise with null and closes the writer.
|
|
155
|
-
*/
|
|
156
|
-
async close() {
|
|
157
|
-
this.#ensureState();
|
|
158
|
-
this.#written = true;
|
|
159
|
-
this.#deferred.resolve(null);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Rejects the promise with the given error and closes the writer.
|
|
164
|
-
*
|
|
165
|
-
* @param {Error} error - The error to reject the promise with.
|
|
166
|
-
*/
|
|
167
|
-
async closeWithError(error) {
|
|
168
|
-
this.#ensureState();
|
|
169
|
-
this.#written = true;
|
|
170
|
-
this.#deferred.reject(error);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Converts the writer back into a promise.
|
|
175
|
-
*
|
|
176
|
-
* @returns {Promise} The original promise.
|
|
177
|
-
*/
|
|
178
|
-
intoPromise() {
|
|
179
|
-
this.close();
|
|
180
|
-
const promise = this.#deferred.promise;
|
|
181
|
-
this.#deferred = null;
|
|
182
|
-
return promise;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
#ensureState() {
|
|
186
|
-
if (this.#written) {
|
|
187
|
-
throw new Error("FutureWriter is closed (already written)");
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { ResourceWorker } from "../workers/resource-worker.js";
|
|
2
|
-
import { StreamReader, readableByteStreamFromReader } from "../stream.js";
|
|
3
|
-
import { FutureReader, future } from "../future.js";
|
|
4
|
-
import { HttpError } from "./error.js";
|
|
5
|
-
import { _schemeToString, Request } from "./request.js";
|
|
6
|
-
import { Response } from "./response.js";
|
|
7
|
-
import {
|
|
8
|
-
_fieldsFromEntriesChecked,
|
|
9
|
-
_readTrailersForTransport,
|
|
10
|
-
_trailerResultFromEntries,
|
|
11
|
-
} from "./fields.js";
|
|
12
|
-
|
|
13
|
-
let WORKER = null;
|
|
14
|
-
function worker() {
|
|
15
|
-
return (WORKER ??= new ResourceWorker(new URL("../workers/http-worker.js", import.meta.url)));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* HTTP client interface.
|
|
20
|
-
*
|
|
21
|
-
* WIT:
|
|
22
|
-
* ```
|
|
23
|
-
* interface client {
|
|
24
|
-
* use types.{request, response, error-code};
|
|
25
|
-
* send: async func(request) -> result<response, error-code>;
|
|
26
|
-
* }
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export const client = {
|
|
30
|
-
/**
|
|
31
|
-
* Send an HTTP request and return a response.
|
|
32
|
-
*
|
|
33
|
-
* @param {Request} req
|
|
34
|
-
* @returns {Promise<Response>}
|
|
35
|
-
* @throws {HttpError}
|
|
36
|
-
*/
|
|
37
|
-
async send(req) {
|
|
38
|
-
const scheme = _schemeToString(req.getScheme()) ?? "http";
|
|
39
|
-
const authority = req.getAuthority();
|
|
40
|
-
|
|
41
|
-
if (!authority) {
|
|
42
|
-
const err = new HttpError("internal-error", "Request.authority must be set for client.send");
|
|
43
|
-
req._resolve({ tag: "err", val: err.payload });
|
|
44
|
-
throw err;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const path = req.getPathWithQuery();
|
|
48
|
-
if (path == null) {
|
|
49
|
-
const err = new HttpError("HTTP-request-URI-invalid", "Request.pathWithQuery must be set");
|
|
50
|
-
req._resolve({ tag: "err", val: err.payload });
|
|
51
|
-
throw err;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const url = `${scheme}://${authority}${path}`;
|
|
55
|
-
|
|
56
|
-
const opts = req.getOptions();
|
|
57
|
-
const connectTimeoutNs = opts?.getConnectTimeout() ?? null;
|
|
58
|
-
const firstByteTimeoutNs = opts?.getFirstByteTimeout() ?? null;
|
|
59
|
-
const betweenBytesTimeoutNs = opts?.getBetweenBytesTimeout() ?? null;
|
|
60
|
-
|
|
61
|
-
const { rx: resRx } = future();
|
|
62
|
-
const [body, trailers] = Request.consumeBody(req, resRx);
|
|
63
|
-
const { port1: tx, port2: rx } = new MessageChannel();
|
|
64
|
-
const { port1: transmitRx, port2: transmitTx } = new MessageChannel();
|
|
65
|
-
|
|
66
|
-
const transfer = [rx, transmitTx];
|
|
67
|
-
const stream = body ? readableByteStreamFromReader(body, { name: "request body" }) : undefined;
|
|
68
|
-
if (stream) {
|
|
69
|
-
transfer.unshift(stream);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let transmitSettled = false;
|
|
73
|
-
const settleTransmit = (result) => {
|
|
74
|
-
if (transmitSettled) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
transmitSettled = true;
|
|
78
|
-
transmitRx.close();
|
|
79
|
-
req._resolve(result);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
transmitRx.once("message", ({ val, err }) => {
|
|
83
|
-
if (err) {
|
|
84
|
-
settleTransmit({ tag: "err", val: err });
|
|
85
|
-
} else {
|
|
86
|
-
settleTransmit({ tag: "ok", val });
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
_readTrailersForTransport(trailers)
|
|
91
|
-
.then((val) => tx.postMessage({ val }))
|
|
92
|
-
.catch((err) => tx.postMessage({ err: HttpError.from(err).payload }))
|
|
93
|
-
.finally(() => tx.close());
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const method = req.getMethod();
|
|
97
|
-
const parts = await worker().run(
|
|
98
|
-
{
|
|
99
|
-
op: "client-request",
|
|
100
|
-
url,
|
|
101
|
-
method: method.tag === "other" ? method.val : method.tag,
|
|
102
|
-
headers: req.getHeaders().copyAll(),
|
|
103
|
-
timeouts: {
|
|
104
|
-
connectTimeoutNs,
|
|
105
|
-
firstByteTimeoutNs,
|
|
106
|
-
betweenBytesTimeoutNs,
|
|
107
|
-
},
|
|
108
|
-
trailers: rx,
|
|
109
|
-
transmit: transmitTx,
|
|
110
|
-
body: stream,
|
|
111
|
-
},
|
|
112
|
-
transfer,
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
return responseFromParts(parts);
|
|
116
|
-
} catch (e) {
|
|
117
|
-
const err = HttpError.from(e);
|
|
118
|
-
settleTransmit({ tag: "err", val: err.payload });
|
|
119
|
-
throw err;
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const responseFromParts = (parts) => {
|
|
125
|
-
const { headers, body, trailers, statusCode } = parts;
|
|
126
|
-
|
|
127
|
-
// Create a promise that resolves when the worker sends a message with trailers
|
|
128
|
-
const promise = new Promise((resolve, reject) => {
|
|
129
|
-
trailers.once("message", ({ val, err }) => {
|
|
130
|
-
trailers.close();
|
|
131
|
-
if (err) {
|
|
132
|
-
reject(err);
|
|
133
|
-
} else {
|
|
134
|
-
resolve(val);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const future = new TrailerFutureReader(promise.then(_trailerResultFromEntries), trailers);
|
|
140
|
-
const contents = new StreamReader(body);
|
|
141
|
-
const fields = _fieldsFromEntriesChecked(headers);
|
|
142
|
-
|
|
143
|
-
const [res] = Response.new(fields, contents, future);
|
|
144
|
-
res.setStatusCode(statusCode);
|
|
145
|
-
return res;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
class TrailerFutureReader extends FutureReader {
|
|
149
|
-
#trailers;
|
|
150
|
-
|
|
151
|
-
constructor(promise, trailers) {
|
|
152
|
-
super(promise);
|
|
153
|
-
this.#trailers = trailers;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
close() {
|
|
157
|
-
this.#trailers?.close();
|
|
158
|
-
this.#trailers = null;
|
|
159
|
-
super.close();
|
|
160
|
-
}
|
|
161
|
-
}
|
package/lib/nodejs/http/error.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom error class for WASI http interface that properly formats payload for Jco compatibility
|
|
3
|
-
*
|
|
4
|
-
* https://bytecodealliance.github.io/jco/wit-type-representations.html#result-considerations-idiomatic-js-errors-for-host-implementations
|
|
5
|
-
*/
|
|
6
|
-
export class HttpError extends Error {
|
|
7
|
-
/**
|
|
8
|
-
* Create a new WASI http error
|
|
9
|
-
* @param {string} tag - The error tag/type
|
|
10
|
-
* @param {string} [message] - Human-readable error message
|
|
11
|
-
* @param {any} [val] - Optional value/data for the error
|
|
12
|
-
*/
|
|
13
|
-
constructor(tag, message, val, opts = {}) {
|
|
14
|
-
super(message || `Error: ${tag}`, { cause: opts.cause });
|
|
15
|
-
this.name = "HttpError";
|
|
16
|
-
this.payload = val !== undefined ? { tag, val } : { tag };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
static from(err) {
|
|
20
|
-
if (err instanceof HttpError) {
|
|
21
|
-
return err;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (err?.tag) {
|
|
25
|
-
return new HttpError(err.tag, undefined, err.val);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const e = getFirstError(err);
|
|
29
|
-
let tag, val;
|
|
30
|
-
|
|
31
|
-
switch (e.code) {
|
|
32
|
-
case "ECONNRESET":
|
|
33
|
-
tag = "HTTP-protocol-error";
|
|
34
|
-
break;
|
|
35
|
-
|
|
36
|
-
case "ENOTFOUND":
|
|
37
|
-
tag = "DNS-error";
|
|
38
|
-
val = {
|
|
39
|
-
rcode: e.code,
|
|
40
|
-
infoCode: e.errno < 0 ? -e.errno : e.errno,
|
|
41
|
-
};
|
|
42
|
-
break;
|
|
43
|
-
|
|
44
|
-
case "ECONNREFUSED":
|
|
45
|
-
tag = "connection-refused";
|
|
46
|
-
break;
|
|
47
|
-
|
|
48
|
-
default:
|
|
49
|
-
tag = "internal-error";
|
|
50
|
-
val = e.toString();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const httpErr = new HttpError(tag, e.message, val, { cause: e });
|
|
54
|
-
Error.captureStackTrace(httpErr, HttpError.from);
|
|
55
|
-
|
|
56
|
-
return httpErr;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function getFirstError(e) {
|
|
61
|
-
if (typeof e !== "object" || e === null) {
|
|
62
|
-
return e;
|
|
63
|
-
}
|
|
64
|
-
if (e.cause) {
|
|
65
|
-
return getFirstError(e.cause);
|
|
66
|
-
}
|
|
67
|
-
if (e instanceof AggregateError) {
|
|
68
|
-
return getFirstError(e.errors[0]);
|
|
69
|
-
}
|
|
70
|
-
return e;
|
|
71
|
-
}
|