@bytecodealliance/preview2-shim 0.18.1 → 0.19.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/browser/cli.d.ts +16 -0
- package/dist/browser/cli.js +109 -0
- package/dist/browser/clocks.d.ts +3 -0
- package/dist/browser/clocks.js +36 -0
- package/dist/browser/config.d.ts +2 -0
- package/{lib → dist}/browser/config.js +2 -4
- package/dist/browser/environment.d.ts +5 -0
- package/dist/browser/environment.js +24 -0
- package/dist/browser/filesystem.d.ts +132 -0
- package/dist/browser/filesystem.js +464 -0
- package/dist/browser/http.d.ts +4 -0
- package/dist/browser/http.js +643 -0
- package/dist/browser/index.d.ts +7 -0
- package/dist/browser/index.js +7 -0
- package/dist/browser/io.d.ts +58 -0
- package/dist/browser/io.js +205 -0
- package/dist/browser/random.d.ts +4 -0
- package/dist/browser/random.js +49 -0
- package/dist/browser/sockets.d.ts +8 -0
- package/dist/browser/sockets.js +66 -0
- package/dist/common/instantiation.d.ts +97 -0
- package/dist/common/instantiation.js +227 -0
- package/dist/io/calls.d.ts +91 -0
- package/{lib → dist}/io/calls.js +4 -19
- package/dist/io/worker-http.d.ts +17 -0
- package/dist/io/worker-http.js +192 -0
- package/dist/io/worker-io.d.ts +84 -0
- package/dist/io/worker-io.js +375 -0
- package/dist/io/worker-socket-tcp.d.ts +34 -0
- package/dist/io/worker-socket-tcp.js +251 -0
- package/dist/io/worker-socket-udp.d.ts +54 -0
- package/dist/io/worker-socket-udp.js +492 -0
- package/dist/io/worker-sockets.d.ts +32 -0
- package/dist/io/worker-sockets.js +265 -0
- package/dist/io/worker-thread.d.ts +73 -0
- package/dist/io/worker-thread.js +791 -0
- package/dist/nodejs/cli.d.ts +30 -0
- package/dist/nodejs/cli.js +86 -0
- package/dist/nodejs/clocks.d.ts +3 -0
- package/dist/nodejs/clocks.js +61 -0
- package/dist/nodejs/filesystem.d.ts +113 -0
- package/dist/nodejs/filesystem.js +758 -0
- package/dist/nodejs/http.d.ts +82 -0
- package/dist/nodejs/http.js +674 -0
- package/dist/nodejs/index.d.ts +7 -0
- package/dist/nodejs/index.js +7 -0
- package/dist/nodejs/io.d.ts +1 -0
- package/dist/nodejs/io.js +1 -0
- package/dist/nodejs/random.d.ts +4 -0
- package/dist/nodejs/random.js +42 -0
- package/dist/nodejs/sockets.d.ts +21 -0
- package/dist/nodejs/sockets.js +482 -0
- package/dist/synckit/index.d.ts +2 -0
- package/dist/synckit/index.js +117 -0
- package/package.json +26 -13
- package/types/instantiation.d.ts +7 -7
- package/lib/browser/cli.js +0 -135
- package/lib/browser/clocks.js +0 -39
- package/lib/browser/environment.js +0 -29
- package/lib/browser/filesystem.js +0 -503
- package/lib/browser/http.js +0 -707
- package/lib/browser/index.js +0 -9
- package/lib/browser/io.js +0 -262
- package/lib/browser/random.js +0 -56
- package/lib/browser/sockets.js +0 -88
- package/lib/common/instantiation.js +0 -253
- package/lib/io/worker-http.js +0 -206
- package/lib/io/worker-io.js +0 -468
- package/lib/io/worker-socket-tcp.js +0 -331
- package/lib/io/worker-socket-udp.js +0 -587
- package/lib/io/worker-sockets.js +0 -364
- package/lib/io/worker-thread.js +0 -1051
- package/lib/nodejs/cli.js +0 -109
- package/lib/nodejs/clocks.js +0 -67
- package/lib/nodejs/filesystem.js +0 -829
- package/lib/nodejs/http.js +0 -764
- package/lib/nodejs/index.js +0 -9
- package/lib/nodejs/io.js +0 -1
- package/lib/nodejs/random.js +0 -49
- package/lib/nodejs/sockets.js +0 -565
- package/lib/synckit/index.js +0 -127
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
import { inputStreamCreate, outputStreamCreate, pollableCreate } from "./io.js";
|
|
2
|
+
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
3
|
+
const utf8Decoder = new TextDecoder();
|
|
4
|
+
const forbiddenHeaders = new Set(["connection", "keep-alive", "host"]);
|
|
5
|
+
const DEFAULT_HTTP_TIMEOUT_NS = 600000000000n;
|
|
6
|
+
// RFC 9110 compliant header validation
|
|
7
|
+
const TOKEN_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
8
|
+
const FIELD_VALUE_RE = /^[\t\x20-\x7E\x80-\xFF]*$/;
|
|
9
|
+
function validateHeaderName(name) {
|
|
10
|
+
if (!TOKEN_RE.test(name)) {
|
|
11
|
+
throw { tag: "invalid-syntax" };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function validateHeaderValue(value) {
|
|
15
|
+
const str = typeof value === "string" ? value : utf8Decoder.decode(value);
|
|
16
|
+
if (!FIELD_VALUE_RE.test(str)) {
|
|
17
|
+
throw { tag: "invalid-syntax" };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
class Fields {
|
|
21
|
+
#immutable = false;
|
|
22
|
+
#entries = [];
|
|
23
|
+
#table = new Map();
|
|
24
|
+
static fromList(entries) {
|
|
25
|
+
const fields = new Fields();
|
|
26
|
+
for (const [key, value] of entries) {
|
|
27
|
+
fields.append(key, value);
|
|
28
|
+
}
|
|
29
|
+
return fields;
|
|
30
|
+
}
|
|
31
|
+
get(name) {
|
|
32
|
+
const tableEntries = this.#table.get(name.toLowerCase());
|
|
33
|
+
if (!tableEntries) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
return tableEntries.map(([, v]) => v);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* WIT spec (https://github.com/WebAssembly/WASI/blob/91bb44c3c3a9b1e09187db23c85fa844d1fd6b15/proposals/http/wit/types.wit#L215-L223):
|
|
40
|
+
*
|
|
41
|
+
* > Set all of the values for a name. Clears any existing values for that
|
|
42
|
+
* > name, if they have been set.
|
|
43
|
+
* >
|
|
44
|
+
* > Fails with `header-error.immutable` if the `fields` are immutable.
|
|
45
|
+
* >
|
|
46
|
+
* > Fails with `header-error.invalid-syntax` if the `field-name` or any of
|
|
47
|
+
* > the `field-value`s are syntactically invalid.
|
|
48
|
+
*
|
|
49
|
+
* The existing-branch splice/reuse is an allocation optimization — values are cleared, not retained.
|
|
50
|
+
*/
|
|
51
|
+
set(name, values) {
|
|
52
|
+
if (this.#immutable) {
|
|
53
|
+
throw { tag: "immutable" };
|
|
54
|
+
}
|
|
55
|
+
validateHeaderName(name);
|
|
56
|
+
for (const value of values) {
|
|
57
|
+
validateHeaderValue(value);
|
|
58
|
+
}
|
|
59
|
+
const lowercased = name.toLowerCase();
|
|
60
|
+
if (forbiddenHeaders.has(lowercased)) {
|
|
61
|
+
throw { tag: "forbidden" };
|
|
62
|
+
}
|
|
63
|
+
const tableEntries = this.#table.get(lowercased);
|
|
64
|
+
if (tableEntries) {
|
|
65
|
+
this.#entries = this.#entries.filter((entry) => !tableEntries.includes(entry));
|
|
66
|
+
tableEntries.splice(0, tableEntries.length);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.#table.set(lowercased, []);
|
|
70
|
+
}
|
|
71
|
+
const newTableEntries = this.#table.get(lowercased);
|
|
72
|
+
for (const value of values) {
|
|
73
|
+
const entry = [name, value];
|
|
74
|
+
this.#entries.push(entry);
|
|
75
|
+
newTableEntries.push(entry);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
has(name) {
|
|
79
|
+
return this.#table.has(name.toLowerCase());
|
|
80
|
+
}
|
|
81
|
+
delete(name) {
|
|
82
|
+
if (this.#immutable) {
|
|
83
|
+
throw { tag: "immutable" };
|
|
84
|
+
}
|
|
85
|
+
const lowercased = name.toLowerCase();
|
|
86
|
+
const tableEntries = this.#table.get(lowercased);
|
|
87
|
+
if (tableEntries) {
|
|
88
|
+
this.#entries = this.#entries.filter((entry) => !tableEntries.includes(entry));
|
|
89
|
+
this.#table.delete(lowercased);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
append(name, value) {
|
|
93
|
+
if (this.#immutable) {
|
|
94
|
+
throw { tag: "immutable" };
|
|
95
|
+
}
|
|
96
|
+
validateHeaderName(name);
|
|
97
|
+
validateHeaderValue(value);
|
|
98
|
+
const lowercased = name.toLowerCase();
|
|
99
|
+
if (forbiddenHeaders.has(lowercased)) {
|
|
100
|
+
throw { tag: "forbidden" };
|
|
101
|
+
}
|
|
102
|
+
const entry = [name, value];
|
|
103
|
+
this.#entries.push(entry);
|
|
104
|
+
const tableEntries = this.#table.get(lowercased);
|
|
105
|
+
if (tableEntries) {
|
|
106
|
+
tableEntries.push(entry);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
this.#table.set(lowercased, [entry]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
entries() {
|
|
113
|
+
return this.#entries;
|
|
114
|
+
}
|
|
115
|
+
clone() {
|
|
116
|
+
return fieldsFromEntriesChecked(this.#entries);
|
|
117
|
+
}
|
|
118
|
+
static _lock(fields) {
|
|
119
|
+
fields.#immutable = true;
|
|
120
|
+
return fields;
|
|
121
|
+
}
|
|
122
|
+
static _fromEntriesChecked(entries) {
|
|
123
|
+
const fields = new Fields();
|
|
124
|
+
fields.#entries = entries;
|
|
125
|
+
for (const entry of entries) {
|
|
126
|
+
const lowercase = entry[0].toLowerCase();
|
|
127
|
+
const existing = fields.#table.get(lowercase);
|
|
128
|
+
if (existing) {
|
|
129
|
+
existing.push(entry);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
fields.#table.set(lowercase, [entry]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return fields;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const fieldsLock = Fields._lock;
|
|
139
|
+
// @ts-expect-error - Deleting static method
|
|
140
|
+
delete Fields._lock;
|
|
141
|
+
const fieldsFromEntriesChecked = Fields._fromEntriesChecked;
|
|
142
|
+
// @ts-expect-error - Deleting static method
|
|
143
|
+
delete Fields._fromEntriesChecked;
|
|
144
|
+
class RequestOptions {
|
|
145
|
+
#connectTimeout = DEFAULT_HTTP_TIMEOUT_NS;
|
|
146
|
+
#firstByteTimeout = DEFAULT_HTTP_TIMEOUT_NS;
|
|
147
|
+
#betweenBytesTimeout = DEFAULT_HTTP_TIMEOUT_NS;
|
|
148
|
+
connectTimeout() {
|
|
149
|
+
return this.#connectTimeout;
|
|
150
|
+
}
|
|
151
|
+
setConnectTimeout(duration) {
|
|
152
|
+
if (duration < 0n) {
|
|
153
|
+
throw new Error("duration must not be negative");
|
|
154
|
+
}
|
|
155
|
+
this.#connectTimeout = duration;
|
|
156
|
+
}
|
|
157
|
+
firstByteTimeout() {
|
|
158
|
+
return this.#firstByteTimeout;
|
|
159
|
+
}
|
|
160
|
+
setFirstByteTimeout(duration) {
|
|
161
|
+
if (duration < 0n) {
|
|
162
|
+
throw new Error("duration must not be negative");
|
|
163
|
+
}
|
|
164
|
+
this.#firstByteTimeout = duration;
|
|
165
|
+
}
|
|
166
|
+
betweenBytesTimeout() {
|
|
167
|
+
return this.#betweenBytesTimeout;
|
|
168
|
+
}
|
|
169
|
+
setBetweenBytesTimeout(duration) {
|
|
170
|
+
if (duration < 0n) {
|
|
171
|
+
throw new Error("duration must not be negative");
|
|
172
|
+
}
|
|
173
|
+
this.#betweenBytesTimeout = duration;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
class OutgoingBody {
|
|
177
|
+
#outputStream = null;
|
|
178
|
+
#chunks = [];
|
|
179
|
+
#finished = false;
|
|
180
|
+
write() {
|
|
181
|
+
const outputStream = this.#outputStream;
|
|
182
|
+
if (outputStream === null) {
|
|
183
|
+
throw undefined;
|
|
184
|
+
}
|
|
185
|
+
this.#outputStream = null;
|
|
186
|
+
return outputStream;
|
|
187
|
+
}
|
|
188
|
+
static finish(body, trailers) {
|
|
189
|
+
if (trailers) {
|
|
190
|
+
throw { tag: "internal-error", val: "trailers unsupported" };
|
|
191
|
+
}
|
|
192
|
+
if (body.#finished) {
|
|
193
|
+
throw { tag: "internal-error", val: "body already finished" };
|
|
194
|
+
}
|
|
195
|
+
body.#finished = true;
|
|
196
|
+
}
|
|
197
|
+
static _bodyData(outgoingBody) {
|
|
198
|
+
if (outgoingBody.#chunks.length === 0) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
let totalLen = 0;
|
|
202
|
+
for (const chunk of outgoingBody.#chunks) {
|
|
203
|
+
totalLen += chunk.byteLength;
|
|
204
|
+
}
|
|
205
|
+
const result = new Uint8Array(totalLen);
|
|
206
|
+
let offset = 0;
|
|
207
|
+
for (const chunk of outgoingBody.#chunks) {
|
|
208
|
+
result.set(chunk, offset);
|
|
209
|
+
offset += chunk.byteLength;
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
static _create() {
|
|
214
|
+
const outgoingBody = new OutgoingBody();
|
|
215
|
+
const chunks = outgoingBody.#chunks;
|
|
216
|
+
outgoingBody.#outputStream = outputStreamCreate({
|
|
217
|
+
write(buf) {
|
|
218
|
+
chunks.push(new Uint8Array(buf));
|
|
219
|
+
},
|
|
220
|
+
blockingFlush() { },
|
|
221
|
+
subscribe() {
|
|
222
|
+
return pollableCreate();
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
return outgoingBody;
|
|
226
|
+
}
|
|
227
|
+
[symbolDispose]() { }
|
|
228
|
+
}
|
|
229
|
+
const outgoingBodyCreate = OutgoingBody._create;
|
|
230
|
+
// @ts-expect-error - Deleting static method
|
|
231
|
+
delete OutgoingBody._create;
|
|
232
|
+
const outgoingBodyData = OutgoingBody._bodyData;
|
|
233
|
+
// @ts-expect-error - Deleting static method
|
|
234
|
+
delete OutgoingBody._bodyData;
|
|
235
|
+
class OutgoingRequest {
|
|
236
|
+
#method = { tag: "get" };
|
|
237
|
+
#scheme = undefined;
|
|
238
|
+
#pathWithQuery = undefined;
|
|
239
|
+
#authority = undefined;
|
|
240
|
+
#headers;
|
|
241
|
+
#body;
|
|
242
|
+
#bodyRequested = false;
|
|
243
|
+
constructor(headers) {
|
|
244
|
+
fieldsLock(headers);
|
|
245
|
+
this.#headers = headers;
|
|
246
|
+
this.#body = outgoingBodyCreate();
|
|
247
|
+
}
|
|
248
|
+
body() {
|
|
249
|
+
if (this.#bodyRequested) {
|
|
250
|
+
throw new Error("Body already requested");
|
|
251
|
+
}
|
|
252
|
+
this.#bodyRequested = true;
|
|
253
|
+
return this.#body;
|
|
254
|
+
}
|
|
255
|
+
method() {
|
|
256
|
+
return this.#method;
|
|
257
|
+
}
|
|
258
|
+
setMethod(method) {
|
|
259
|
+
if (method.tag === "other" && method.val && !method.val.match(/^[a-zA-Z-]+$/)) {
|
|
260
|
+
throw undefined;
|
|
261
|
+
}
|
|
262
|
+
this.#method = method;
|
|
263
|
+
}
|
|
264
|
+
pathWithQuery() {
|
|
265
|
+
return this.#pathWithQuery;
|
|
266
|
+
}
|
|
267
|
+
setPathWithQuery(pathWithQuery) {
|
|
268
|
+
if (pathWithQuery && !pathWithQuery.match(/^[a-zA-Z0-9.\-_~!$&'()*+,;=:@%?/]+$/)) {
|
|
269
|
+
throw undefined;
|
|
270
|
+
}
|
|
271
|
+
this.#pathWithQuery = pathWithQuery;
|
|
272
|
+
}
|
|
273
|
+
scheme() {
|
|
274
|
+
return this.#scheme;
|
|
275
|
+
}
|
|
276
|
+
setScheme(scheme) {
|
|
277
|
+
if (scheme?.tag === "other" && scheme.val && !scheme.val.match(/^[a-zA-Z]+$/)) {
|
|
278
|
+
throw undefined;
|
|
279
|
+
}
|
|
280
|
+
this.#scheme = scheme;
|
|
281
|
+
}
|
|
282
|
+
authority() {
|
|
283
|
+
return this.#authority;
|
|
284
|
+
}
|
|
285
|
+
setAuthority(authority) {
|
|
286
|
+
if (authority) {
|
|
287
|
+
const [host, port, ...extra] = authority.split(":");
|
|
288
|
+
const portNum = Number(port);
|
|
289
|
+
if (extra.length ||
|
|
290
|
+
(port !== undefined && (portNum.toString() !== port || portNum > 65535)) ||
|
|
291
|
+
!host.match(/^[a-zA-Z0-9-.]+$/)) {
|
|
292
|
+
throw undefined;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
this.#authority = authority;
|
|
296
|
+
}
|
|
297
|
+
headers() {
|
|
298
|
+
return this.#headers;
|
|
299
|
+
}
|
|
300
|
+
[symbolDispose]() { }
|
|
301
|
+
static _handle(request, options) {
|
|
302
|
+
const scheme = schemeString(request.#scheme);
|
|
303
|
+
const method = "val" in request.#method ? request.#method.val : request.#method.tag;
|
|
304
|
+
if (!request.#pathWithQuery) {
|
|
305
|
+
throw { tag: "HTTP-request-URI-invalid" };
|
|
306
|
+
}
|
|
307
|
+
const url = `${scheme}//${request.#authority || ""}${request.#pathWithQuery}`;
|
|
308
|
+
const headers = new Headers();
|
|
309
|
+
for (const [key, value] of request.#headers.entries()) {
|
|
310
|
+
const lowerKey = key.toLowerCase();
|
|
311
|
+
if (!forbiddenHeaders.has(lowerKey)) {
|
|
312
|
+
headers.set(key, utf8Decoder.decode(value));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const bodyData = outgoingBodyData(request.#body);
|
|
316
|
+
let timeoutMs = Number(DEFAULT_HTTP_TIMEOUT_NS / 1000000n);
|
|
317
|
+
if (options) {
|
|
318
|
+
const ct = options.connectTimeout?.() ?? DEFAULT_HTTP_TIMEOUT_NS;
|
|
319
|
+
const fbt = options.firstByteTimeout?.() ?? DEFAULT_HTTP_TIMEOUT_NS;
|
|
320
|
+
const minTimeout = ct < fbt ? ct : fbt;
|
|
321
|
+
timeoutMs = Number(minTimeout / 1000000n);
|
|
322
|
+
}
|
|
323
|
+
return futureIncomingResponseCreate(url, method.toUpperCase(), headers, bodyData, timeoutMs);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const outgoingRequestHandle = OutgoingRequest._handle;
|
|
327
|
+
// @ts-expect-error - Deleting static method
|
|
328
|
+
delete OutgoingRequest._handle;
|
|
329
|
+
class IncomingBody {
|
|
330
|
+
#finished = false;
|
|
331
|
+
#stream = undefined;
|
|
332
|
+
stream() {
|
|
333
|
+
if (!this.#stream) {
|
|
334
|
+
throw undefined;
|
|
335
|
+
}
|
|
336
|
+
const stream = this.#stream;
|
|
337
|
+
this.#stream = null;
|
|
338
|
+
return stream;
|
|
339
|
+
}
|
|
340
|
+
static finish(incomingBody) {
|
|
341
|
+
if (incomingBody.#finished) {
|
|
342
|
+
throw new Error("incoming body already finished");
|
|
343
|
+
}
|
|
344
|
+
incomingBody.#finished = true;
|
|
345
|
+
return futureTrailersCreate();
|
|
346
|
+
}
|
|
347
|
+
[symbolDispose]() { }
|
|
348
|
+
static _create(fetchResponse) {
|
|
349
|
+
const incomingBody = new IncomingBody();
|
|
350
|
+
let buffer = null;
|
|
351
|
+
let bufferOffset = 0;
|
|
352
|
+
let done = false;
|
|
353
|
+
let reader = null;
|
|
354
|
+
let readPromise = null;
|
|
355
|
+
function ensureReader() {
|
|
356
|
+
if (!reader && fetchResponse.body) {
|
|
357
|
+
reader = fetchResponse.body.getReader();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function startRead() {
|
|
361
|
+
if (readPromise || done) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
ensureReader();
|
|
365
|
+
if (!reader) {
|
|
366
|
+
done = true;
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
readPromise = reader.read().then((result) => {
|
|
370
|
+
readPromise = null;
|
|
371
|
+
if (result.done) {
|
|
372
|
+
done = true;
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
buffer = result.value;
|
|
376
|
+
bufferOffset = 0;
|
|
377
|
+
}
|
|
378
|
+
}, () => {
|
|
379
|
+
readPromise = null;
|
|
380
|
+
done = true;
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
incomingBody.#stream = inputStreamCreate({
|
|
384
|
+
read(len) {
|
|
385
|
+
if (done && (buffer === null || bufferOffset >= buffer.byteLength)) {
|
|
386
|
+
throw { tag: "closed" };
|
|
387
|
+
}
|
|
388
|
+
if (buffer !== null && bufferOffset < buffer.byteLength) {
|
|
389
|
+
const available = buffer.byteLength - bufferOffset;
|
|
390
|
+
const toRead = Math.min(Number(len), available);
|
|
391
|
+
const slice = buffer.slice(bufferOffset, bufferOffset + toRead);
|
|
392
|
+
bufferOffset += toRead;
|
|
393
|
+
if (bufferOffset >= buffer.byteLength) {
|
|
394
|
+
buffer = null;
|
|
395
|
+
bufferOffset = 0;
|
|
396
|
+
if (!done) {
|
|
397
|
+
startRead();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return slice;
|
|
401
|
+
}
|
|
402
|
+
throw { tag: "would-block" };
|
|
403
|
+
},
|
|
404
|
+
blockingRead(len) {
|
|
405
|
+
if (done && (buffer === null || bufferOffset >= buffer.byteLength)) {
|
|
406
|
+
throw { tag: "closed" };
|
|
407
|
+
}
|
|
408
|
+
if (buffer !== null && bufferOffset < buffer.byteLength) {
|
|
409
|
+
const available = buffer.byteLength - bufferOffset;
|
|
410
|
+
const toRead = Math.min(Number(len), available);
|
|
411
|
+
const slice = buffer.slice(bufferOffset, bufferOffset + toRead);
|
|
412
|
+
bufferOffset += toRead;
|
|
413
|
+
if (bufferOffset >= buffer.byteLength) {
|
|
414
|
+
buffer = null;
|
|
415
|
+
bufferOffset = 0;
|
|
416
|
+
if (!done) {
|
|
417
|
+
startRead();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return slice;
|
|
421
|
+
}
|
|
422
|
+
startRead();
|
|
423
|
+
const waitFor = readPromise || Promise.resolve();
|
|
424
|
+
return waitFor.then(() => {
|
|
425
|
+
if (done && (buffer === null || bufferOffset >= buffer.byteLength)) {
|
|
426
|
+
throw { tag: "closed" };
|
|
427
|
+
}
|
|
428
|
+
if (buffer !== null && bufferOffset < buffer.byteLength) {
|
|
429
|
+
const available = buffer.byteLength - bufferOffset;
|
|
430
|
+
const toRead = Math.min(Number(len), available);
|
|
431
|
+
const slice = buffer.slice(bufferOffset, bufferOffset + toRead);
|
|
432
|
+
bufferOffset += toRead;
|
|
433
|
+
if (bufferOffset >= buffer.byteLength) {
|
|
434
|
+
buffer = null;
|
|
435
|
+
bufferOffset = 0;
|
|
436
|
+
if (!done) {
|
|
437
|
+
startRead();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return slice;
|
|
441
|
+
}
|
|
442
|
+
throw { tag: "closed" };
|
|
443
|
+
});
|
|
444
|
+
},
|
|
445
|
+
subscribe() {
|
|
446
|
+
if (done || (buffer !== null && bufferOffset < buffer.byteLength)) {
|
|
447
|
+
return pollableCreate();
|
|
448
|
+
}
|
|
449
|
+
startRead();
|
|
450
|
+
if (readPromise) {
|
|
451
|
+
return pollableCreate(readPromise);
|
|
452
|
+
}
|
|
453
|
+
return pollableCreate();
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
startRead();
|
|
457
|
+
return incomingBody;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
const incomingBodyCreate = IncomingBody._create;
|
|
461
|
+
// @ts-expect-error - Deleting static method
|
|
462
|
+
delete IncomingBody._create;
|
|
463
|
+
class IncomingResponse {
|
|
464
|
+
#headers;
|
|
465
|
+
#status = 0;
|
|
466
|
+
#body;
|
|
467
|
+
status() {
|
|
468
|
+
return this.#status;
|
|
469
|
+
}
|
|
470
|
+
headers() {
|
|
471
|
+
return this.#headers;
|
|
472
|
+
}
|
|
473
|
+
consume() {
|
|
474
|
+
if (this.#body === undefined) {
|
|
475
|
+
throw undefined;
|
|
476
|
+
}
|
|
477
|
+
const body = this.#body;
|
|
478
|
+
this.#body = undefined;
|
|
479
|
+
return body;
|
|
480
|
+
}
|
|
481
|
+
[symbolDispose]() { }
|
|
482
|
+
static _create(fetchResponse) {
|
|
483
|
+
const res = new IncomingResponse();
|
|
484
|
+
res.#status = fetchResponse.status;
|
|
485
|
+
const headerEntries = [];
|
|
486
|
+
const encoder = new TextEncoder();
|
|
487
|
+
fetchResponse.headers.forEach((value, key) => {
|
|
488
|
+
headerEntries.push([key, encoder.encode(value)]);
|
|
489
|
+
});
|
|
490
|
+
res.#headers = fieldsLock(fieldsFromEntriesChecked(headerEntries));
|
|
491
|
+
res.#body = incomingBodyCreate(fetchResponse);
|
|
492
|
+
return res;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const incomingResponseCreate = IncomingResponse._create;
|
|
496
|
+
// @ts-expect-error - Deleting static method
|
|
497
|
+
delete IncomingResponse._create;
|
|
498
|
+
class FutureTrailers {
|
|
499
|
+
#requested = false;
|
|
500
|
+
subscribe() {
|
|
501
|
+
return pollableCreate();
|
|
502
|
+
}
|
|
503
|
+
get() {
|
|
504
|
+
if (this.#requested) {
|
|
505
|
+
return { tag: "err", val: undefined };
|
|
506
|
+
}
|
|
507
|
+
this.#requested = true;
|
|
508
|
+
return {
|
|
509
|
+
tag: "ok",
|
|
510
|
+
val: {
|
|
511
|
+
tag: "ok",
|
|
512
|
+
val: undefined,
|
|
513
|
+
},
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
static _create() {
|
|
517
|
+
return new FutureTrailers();
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
const futureTrailersCreate = FutureTrailers._create;
|
|
521
|
+
// @ts-expect-error - Deleting static method
|
|
522
|
+
delete FutureTrailers._create;
|
|
523
|
+
function mapFetchError(err) {
|
|
524
|
+
if (err.name === "AbortError") {
|
|
525
|
+
return { tag: "connection-timeout" };
|
|
526
|
+
}
|
|
527
|
+
if (err.name === "TypeError") {
|
|
528
|
+
return { tag: "connection-refused" };
|
|
529
|
+
}
|
|
530
|
+
return { tag: "internal-error", val: err.message };
|
|
531
|
+
}
|
|
532
|
+
class FutureIncomingResponse {
|
|
533
|
+
#result = undefined;
|
|
534
|
+
#promise = null;
|
|
535
|
+
subscribe() {
|
|
536
|
+
return pollableCreate(this.#promise);
|
|
537
|
+
}
|
|
538
|
+
get() {
|
|
539
|
+
if (this.#result === undefined) {
|
|
540
|
+
return undefined;
|
|
541
|
+
}
|
|
542
|
+
const result = this.#result;
|
|
543
|
+
this.#result = { tag: "err" };
|
|
544
|
+
return result;
|
|
545
|
+
}
|
|
546
|
+
[symbolDispose]() {
|
|
547
|
+
this.#promise = null;
|
|
548
|
+
}
|
|
549
|
+
static _create(url, method, headers, bodyData, timeoutMs) {
|
|
550
|
+
const future = new FutureIncomingResponse();
|
|
551
|
+
const controller = new AbortController();
|
|
552
|
+
let timer;
|
|
553
|
+
if (timeoutMs < Infinity) {
|
|
554
|
+
timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
555
|
+
}
|
|
556
|
+
const init = {
|
|
557
|
+
method,
|
|
558
|
+
headers,
|
|
559
|
+
signal: controller.signal,
|
|
560
|
+
};
|
|
561
|
+
if (bodyData && method !== "GET" && method !== "HEAD") {
|
|
562
|
+
init.body = bodyData;
|
|
563
|
+
}
|
|
564
|
+
future.#promise = fetch(url, init).then((response) => {
|
|
565
|
+
if (timer) {
|
|
566
|
+
clearTimeout(timer);
|
|
567
|
+
}
|
|
568
|
+
future.#result = {
|
|
569
|
+
tag: "ok",
|
|
570
|
+
val: {
|
|
571
|
+
tag: "ok",
|
|
572
|
+
val: incomingResponseCreate(response),
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
}, (err) => {
|
|
576
|
+
if (timer) {
|
|
577
|
+
clearTimeout(timer);
|
|
578
|
+
}
|
|
579
|
+
future.#result = {
|
|
580
|
+
tag: "ok",
|
|
581
|
+
val: {
|
|
582
|
+
tag: "err",
|
|
583
|
+
val: mapFetchError(err),
|
|
584
|
+
},
|
|
585
|
+
};
|
|
586
|
+
});
|
|
587
|
+
return future;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const futureIncomingResponseCreate = FutureIncomingResponse._create;
|
|
591
|
+
// @ts-expect-error - Deleting static method
|
|
592
|
+
delete FutureIncomingResponse._create;
|
|
593
|
+
function schemeString(scheme) {
|
|
594
|
+
if (!scheme) {
|
|
595
|
+
return "https:";
|
|
596
|
+
}
|
|
597
|
+
switch (scheme.tag) {
|
|
598
|
+
case "HTTP":
|
|
599
|
+
return "http:";
|
|
600
|
+
case "HTTPS":
|
|
601
|
+
return "https:";
|
|
602
|
+
case "other":
|
|
603
|
+
return scheme.val.toLowerCase() + ":";
|
|
604
|
+
}
|
|
605
|
+
return "https:";
|
|
606
|
+
}
|
|
607
|
+
function httpErrorCode(err) {
|
|
608
|
+
if ("payload" in err) {
|
|
609
|
+
return err.payload;
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
tag: "internal-error",
|
|
613
|
+
val: "message" in err ? err.message : err.toDebugString(),
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
export const outgoingHandler = {
|
|
617
|
+
// @ts-expect-error Not matching signature in WIT
|
|
618
|
+
handle: outgoingRequestHandle,
|
|
619
|
+
};
|
|
620
|
+
export const incomingHandler = {
|
|
621
|
+
// Not implemented
|
|
622
|
+
handle() { },
|
|
623
|
+
};
|
|
624
|
+
export const types = {
|
|
625
|
+
Fields,
|
|
626
|
+
FutureIncomingResponse,
|
|
627
|
+
FutureTrailers,
|
|
628
|
+
IncomingBody,
|
|
629
|
+
// @ts-expect-error Not implemented
|
|
630
|
+
IncomingRequest: class IncomingRequest {
|
|
631
|
+
},
|
|
632
|
+
IncomingResponse,
|
|
633
|
+
OutgoingBody,
|
|
634
|
+
OutgoingRequest,
|
|
635
|
+
// @ts-expect-error Not implemented
|
|
636
|
+
OutgoingResponse: class OutgoingResponse {
|
|
637
|
+
},
|
|
638
|
+
// @ts-expect-error Not implemented
|
|
639
|
+
ResponseOutparam: class ResponseOutparam {
|
|
640
|
+
},
|
|
641
|
+
RequestOptions,
|
|
642
|
+
httpErrorCode,
|
|
643
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * as cli from "./cli.js";
|
|
2
|
+
export * as clocks from "./clocks.js";
|
|
3
|
+
export * as filesystem from "./filesystem.js";
|
|
4
|
+
export * as http from "./http.js";
|
|
5
|
+
export * as io from "./io.js";
|
|
6
|
+
export * as random from "./random.js";
|
|
7
|
+
export * as sockets from "./sockets.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * as cli from "./cli.js";
|
|
2
|
+
export * as clocks from "./clocks.js";
|
|
3
|
+
export * as filesystem from "./filesystem.js";
|
|
4
|
+
export * as http from "./http.js";
|
|
5
|
+
export * as io from "./io.js";
|
|
6
|
+
export * as random from "./random.js";
|
|
7
|
+
export * as sockets from "./sockets.js";
|