@bytecodealliance/preview3-shim 0.1.2 → 0.2.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.
Files changed (112) hide show
  1. package/dist/nodejs/cli.d.ts +51 -0
  2. package/dist/nodejs/cli.js +106 -0
  3. package/dist/nodejs/clocks.d.ts +55 -0
  4. package/dist/nodejs/clocks.js +83 -0
  5. package/dist/nodejs/filesystem/descriptor.d.ts +443 -0
  6. package/dist/nodejs/filesystem/descriptor.js +1010 -0
  7. package/dist/nodejs/filesystem/error.d.ts +61 -0
  8. package/dist/nodejs/filesystem/error.js +86 -0
  9. package/dist/nodejs/filesystem/utils.d.ts +8 -0
  10. package/dist/nodejs/filesystem/utils.js +25 -0
  11. package/dist/nodejs/filesystem.js +2 -0
  12. package/dist/nodejs/finalization.d.ts +2 -0
  13. package/{lib → dist}/nodejs/finalization.js +15 -21
  14. package/dist/nodejs/future.d.ts +98 -0
  15. package/dist/nodejs/future.js +176 -0
  16. package/dist/nodejs/http/client.d.ts +22 -0
  17. package/dist/nodejs/http/client.js +138 -0
  18. package/dist/nodejs/http/error.d.ts +18 -0
  19. package/dist/nodejs/http/error.js +62 -0
  20. package/dist/nodejs/http/fields.d.ts +144 -0
  21. package/dist/nodejs/http/fields.js +332 -0
  22. package/dist/nodejs/http/request.d.ts +256 -0
  23. package/dist/nodejs/http/request.js +606 -0
  24. package/dist/nodejs/http/response.d.ts +82 -0
  25. package/dist/nodejs/http/response.js +202 -0
  26. package/dist/nodejs/http/server.d.ts +13 -0
  27. package/dist/nodejs/http/server.js +127 -0
  28. package/dist/nodejs/http.d.ts +19 -0
  29. package/{lib → dist}/nodejs/http.js +13 -18
  30. package/dist/nodejs/index.js +8 -0
  31. package/dist/nodejs/random.d.ts +5 -0
  32. package/{lib → dist}/nodejs/random.js +2 -8
  33. package/dist/nodejs/sockets/address.d.ts +78 -0
  34. package/dist/nodejs/sockets/address.js +120 -0
  35. package/dist/nodejs/sockets/error.d.ts +83 -0
  36. package/dist/nodejs/sockets/error.js +120 -0
  37. package/dist/nodejs/sockets/ip-name-lookup.d.ts +18 -0
  38. package/dist/nodejs/sockets/ip-name-lookup.js +84 -0
  39. package/dist/nodejs/sockets/tcp.d.ts +333 -0
  40. package/dist/nodejs/sockets/tcp.js +723 -0
  41. package/dist/nodejs/sockets/udp.d.ts +224 -0
  42. package/dist/nodejs/sockets/udp.js +475 -0
  43. package/dist/nodejs/sockets.d.ts +11 -0
  44. package/{lib → dist}/nodejs/sockets.js +2 -5
  45. package/dist/nodejs/stream.d.ts +161 -0
  46. package/dist/nodejs/stream.js +388 -0
  47. package/dist/nodejs/workers/cli-worker.d.ts +1 -0
  48. package/dist/nodejs/workers/cli-worker.js +41 -0
  49. package/dist/nodejs/workers/filesystem-worker.d.ts +1 -0
  50. package/dist/nodejs/workers/filesystem-worker.js +109 -0
  51. package/dist/nodejs/workers/http-worker.d.ts +1 -0
  52. package/dist/nodejs/workers/http-worker.js +355 -0
  53. package/dist/nodejs/workers/resource-worker.d.ts +13 -0
  54. package/dist/nodejs/workers/resource-worker.js +152 -0
  55. package/dist/nodejs/workers/tcp-worker.d.ts +2 -0
  56. package/dist/nodejs/workers/tcp-worker.js +318 -0
  57. package/dist/nodejs/workers/udp-worker.d.ts +1 -0
  58. package/dist/nodejs/workers/udp-worker.js +156 -0
  59. package/package.json +20 -12
  60. package/types/interfaces/wasi-cli-environment.d.ts +3 -3
  61. package/types/interfaces/wasi-cli-exit.d.ts +12 -1
  62. package/types/interfaces/wasi-cli-run.d.ts +1 -1
  63. package/types/interfaces/wasi-cli-stderr.d.ts +3 -3
  64. package/types/interfaces/wasi-cli-stdin.d.ts +5 -5
  65. package/types/interfaces/wasi-cli-stdout.d.ts +3 -3
  66. package/types/interfaces/wasi-cli-terminal-input.d.ts +1 -1
  67. package/types/interfaces/wasi-cli-terminal-output.d.ts +1 -1
  68. package/types/interfaces/wasi-cli-terminal-stderr.d.ts +1 -1
  69. package/types/interfaces/wasi-cli-terminal-stdin.d.ts +1 -1
  70. package/types/interfaces/wasi-cli-terminal-stdout.d.ts +1 -1
  71. package/types/interfaces/wasi-cli-types.d.ts +5 -5
  72. package/types/interfaces/wasi-clocks-monotonic-clock.d.ts +3 -3
  73. package/types/interfaces/wasi-clocks-system-clock.d.ts +6 -6
  74. package/types/interfaces/wasi-clocks-types.d.ts +1 -1
  75. package/types/interfaces/wasi-filesystem-preopens.d.ts +1 -1
  76. package/types/interfaces/wasi-filesystem-types.d.ts +74 -74
  77. package/types/interfaces/wasi-http-client.d.ts +1 -1
  78. package/types/interfaces/wasi-http-handler.d.ts +1 -1
  79. package/types/interfaces/wasi-http-types.d.ts +34 -34
  80. package/types/interfaces/wasi-random-insecure-seed.d.ts +5 -5
  81. package/types/interfaces/wasi-random-insecure.d.ts +5 -5
  82. package/types/interfaces/wasi-random-random.d.ts +5 -5
  83. package/types/interfaces/wasi-sockets-ip-name-lookup.d.ts +11 -11
  84. package/types/interfaces/wasi-sockets-types.d.ts +121 -121
  85. package/types/wasi-cli-command.d.ts +23 -23
  86. package/types/wasi-http-service.d.ts +14 -14
  87. package/lib/nodejs/cli.js +0 -127
  88. package/lib/nodejs/clocks.js +0 -98
  89. package/lib/nodejs/filesystem/descriptor.js +0 -1093
  90. package/lib/nodejs/filesystem/error.js +0 -92
  91. package/lib/nodejs/filesystem/utils.js +0 -19
  92. package/lib/nodejs/future.js +0 -190
  93. package/lib/nodejs/http/client.js +0 -161
  94. package/lib/nodejs/http/error.js +0 -71
  95. package/lib/nodejs/http/fields.js +0 -373
  96. package/lib/nodejs/http/request.js +0 -691
  97. package/lib/nodejs/http/response.js +0 -227
  98. package/lib/nodejs/http/server.js +0 -157
  99. package/lib/nodejs/sockets/address.js +0 -146
  100. package/lib/nodejs/sockets/error.js +0 -123
  101. package/lib/nodejs/sockets/ip-name-lookup.js +0 -93
  102. package/lib/nodejs/sockets/tcp.js +0 -801
  103. package/lib/nodejs/sockets/udp.js +0 -516
  104. package/lib/nodejs/stream.js +0 -437
  105. package/lib/nodejs/workers/cli-worker.js +0 -49
  106. package/lib/nodejs/workers/filesystem-worker.js +0 -119
  107. package/lib/nodejs/workers/http-worker.js +0 -417
  108. package/lib/nodejs/workers/resource-worker.js +0 -195
  109. package/lib/nodejs/workers/tcp-worker.js +0 -370
  110. package/lib/nodejs/workers/udp-worker.js +0 -194
  111. /package/{lib/nodejs/filesystem.js → dist/nodejs/filesystem.d.ts} +0 -0
  112. /package/{lib/nodejs/index.js → dist/nodejs/index.d.ts} +0 -0
@@ -0,0 +1,606 @@
1
+ import { HttpError } from "./error.js";
2
+ import { _fieldsLock, Fields } from "./fields.js";
3
+ import { FutureReader, future } from "../future.js";
4
+ import { DEFAULT_BYTE_STREAM_CHUNK_SIZE, StreamReader, _byteChunk, readableByteStreamFromReader, } from "../stream.js";
5
+ const symbolDispose = Symbol.dispose || Symbol.for("dispose");
6
+ const SUPPORTED_METHODS = [
7
+ "get",
8
+ "head",
9
+ "post",
10
+ "put",
11
+ "delete",
12
+ "connect",
13
+ "options",
14
+ "trace",
15
+ "patch",
16
+ ];
17
+ let REQUEST_CREATE_TOKEN = null;
18
+ function token() {
19
+ return (REQUEST_CREATE_TOKEN ??= Symbol("RequestCreateToken"));
20
+ }
21
+ export class RequestOptions {
22
+ #connectTimeoutNs = undefined;
23
+ #firstByteTimeoutNs = undefined;
24
+ #betweenBytesTimeoutNs = undefined;
25
+ #immutable = false;
26
+ /**
27
+ * Construct a default ~RequestOptions~ value.
28
+ * WIT:
29
+ * ```
30
+ * constructor()
31
+ * ```
32
+ */
33
+ constructor() { }
34
+ /**
35
+ * The timeout for the initial connect to the HTTP Server.
36
+ * WIT:
37
+ * ```
38
+ * connect-timeout: func() -> option<duration>
39
+ * ```
40
+ *
41
+ * @returns {?number} Duration in milliseconds, or `null` if not set
42
+ */
43
+ getConnectTimeout() {
44
+ return this.#connectTimeoutNs;
45
+ }
46
+ /**
47
+ * Set the timeout for the initial connect to the HTTP Server.
48
+ * WIT:
49
+ * ```
50
+ * set-connect-timeout: func(duration: option<duration>) -> result<_, request-options-error>
51
+ * ```
52
+ *
53
+ * @param {?bigint} duration Duration in nanoseconds, or `null` to clear
54
+ * @throws {HttpError} with payload.tag 'immutable' if this handle is immutable
55
+ */
56
+ setConnectTimeout(duration) {
57
+ this._ensureMutable();
58
+ this.#connectTimeoutNs = duration ?? undefined;
59
+ }
60
+ /**
61
+ * The timeout for receiving the first byte of the Response body.
62
+ * WIT:
63
+ * ```
64
+ * first-byte-timeout: func() -> option<duration>
65
+ * ```
66
+ *
67
+ * @returns {?bigint} Duration in nanoseconds, or `null` if not set
68
+ */
69
+ getFirstByteTimeout() {
70
+ return this.#firstByteTimeoutNs;
71
+ }
72
+ /**
73
+ * Set the timeout for receiving the first byte of the Response body.
74
+ * WIT:
75
+ * ```
76
+ * set-first-byte-timeout: func(duration: option<duration>) -> result<_, request-options-error>
77
+ * ```
78
+ *
79
+ * @param {?bigint} duration Duration in nanoseconds, or `null` to clear
80
+ * @throws {HttpError} with payload.tag 'immutable' if this handle is immutable
81
+ */
82
+ setFirstByteTimeout(duration) {
83
+ this._ensureMutable();
84
+ this.#firstByteTimeoutNs = duration ?? undefined;
85
+ }
86
+ /**
87
+ * The timeout for receiving subsequent chunks of bytes in the Response body.
88
+ * WIT:
89
+ * ```
90
+ * between-bytes-timeout: func() -> option<duration>
91
+ * ```
92
+ *
93
+ * @returns {?bigint} Duration in nanoseconds, or `null` if not set
94
+ */
95
+ getBetweenBytesTimeout() {
96
+ return this.#betweenBytesTimeoutNs;
97
+ }
98
+ /**
99
+ * Set the timeout for receiving subsequent chunks of bytes in the Response body.
100
+ * WIT:
101
+ * ```
102
+ * set-between-bytes-timeout: func(duration: option<duration>) -> result<_, request-options-error>
103
+ * ```
104
+ *
105
+ * @param {?bigint} duration Duration in nanoseconds, or `null` to clear
106
+ * @throws {HttpError} with payload.tag 'immutable' if this handle is immutable
107
+ */
108
+ setBetweenBytesTimeout(duration) {
109
+ this._ensureMutable();
110
+ this.#betweenBytesTimeoutNs = duration ?? undefined;
111
+ }
112
+ /**
113
+ * Make a deep copy of the ~RequestOptions~.
114
+ * WIT:
115
+ * ```
116
+ * clone: func() -> request-options
117
+ * ```
118
+ *
119
+ * @returns {RequestOptions} A new mutable copy
120
+ */
121
+ clone() {
122
+ const cloned = new RequestOptions();
123
+ cloned.#connectTimeoutNs = this.#connectTimeoutNs;
124
+ cloned.#firstByteTimeoutNs = this.#firstByteTimeoutNs;
125
+ cloned.#betweenBytesTimeoutNs = this.#betweenBytesTimeoutNs;
126
+ return cloned;
127
+ }
128
+ /**
129
+ * Mark options as immutable
130
+ *
131
+ * @param {RequestOptions} opts - The RequestOptions instance to mark as immutable
132
+ * @returns {RequestOptions} The same instance, now immutable
133
+ */
134
+ static _lock(fields) {
135
+ if (fields) {
136
+ fields.#immutable = true;
137
+ }
138
+ return fields;
139
+ }
140
+ _ensureMutable() {
141
+ if (this.#immutable) {
142
+ throw new HttpError("immutable", "Cannot modify immutable RequestOptions");
143
+ }
144
+ }
145
+ }
146
+ export function _optionsLock(fields) {
147
+ return RequestOptions._lock(fields);
148
+ }
149
+ export class Request {
150
+ #method = { tag: "get" };
151
+ #headers = null;
152
+ #contents = null;
153
+ #options = null;
154
+ #scheme = undefined;
155
+ #authority = undefined;
156
+ #pathWithQuery = undefined;
157
+ #trailersFuture = null;
158
+ #requestFuture = null;
159
+ #contentsDispose = null;
160
+ #bodyOpen = false;
161
+ #bodyEnded = false;
162
+ constructor(t) {
163
+ if (t !== token()) {
164
+ throw new Error("Use Request.new(...) to create a Request");
165
+ }
166
+ }
167
+ /**
168
+ * Construct a new Request with default values.
169
+ *
170
+ * WIT:
171
+ * ```
172
+ * new: static func(
173
+ * headers: headers,
174
+ * contents: option<stream<u8>>,
175
+ * trailers: future<result<option<trailers>, error-code>>,
176
+ * options: option<request-options>
177
+ * ) -> tuple<request, future<result<_, error-code>>>;
178
+ * ```
179
+ *
180
+ * @param {Fields} headers immutable headers resource
181
+ * @param {?StreamReader|object} contents optional body stream
182
+ * @param {FutureReader|Promise} trailers future for trailers
183
+ * @param {?RequestOptions} options optional RequestOptions
184
+ * @returns {[Request, FutureReader]}
185
+ * @throws {HttpError} with payload.tag 'invalid-argument' for invalid arguments
186
+ *
187
+ */
188
+ static new(headers, contents, trailers, options) {
189
+ if (options != null && !(options instanceof RequestOptions)) {
190
+ throw new HttpError("invalid-argument", "options must be RequestOptions");
191
+ }
192
+ if (!(headers instanceof Fields)) {
193
+ throw new HttpError("invalid-argument", "headers must be Fields");
194
+ }
195
+ if (!(trailers instanceof FutureReader) && (!trailers || typeof trailers.then !== "function")) {
196
+ throw new HttpError("invalid-argument", "trailers must be FutureReader or Promise");
197
+ }
198
+ let dispose = null;
199
+ if (contents != null && !(contents instanceof StreamReader)) {
200
+ try {
201
+ dispose = contents[symbolDispose]?.bind(contents);
202
+ const inner = readableContentsStream(contents, headers);
203
+ contents = new StreamReader(inner);
204
+ }
205
+ catch (err) {
206
+ throw new HttpError("invalid-argument", err.message);
207
+ }
208
+ }
209
+ // Generated P3 futures are lazy thenables so we want to observe them now so early error paths don't hang.
210
+ if (!(trailers instanceof FutureReader)) {
211
+ const promise = Promise.resolve(trailers);
212
+ trailers = new FutureReader(promise);
213
+ }
214
+ let request = new Request(token());
215
+ request.#headers = headers;
216
+ request.#contents = contents;
217
+ request.#contentsDispose = dispose;
218
+ request.#options = options;
219
+ request.#trailersFuture = trailers;
220
+ request.#pathWithQuery = undefined;
221
+ request.#scheme = undefined;
222
+ request.#authority = undefined;
223
+ _fieldsLock(request.#headers);
224
+ _optionsLock(request.#options);
225
+ const { tx, rx } = future();
226
+ request.#requestFuture = tx;
227
+ return [request, rx];
228
+ }
229
+ [symbolDispose]() {
230
+ if (this.#contents && !this.#bodyOpen && !this.#bodyEnded) {
231
+ this.#contentsDispose?.();
232
+ this.#contents.close();
233
+ }
234
+ this.#contents = null;
235
+ this.#contentsDispose = null;
236
+ this.#bodyOpen = false;
237
+ this.#bodyEnded = true;
238
+ }
239
+ /**
240
+ * Get the Method for the Request.
241
+ *
242
+ * WIT:
243
+ * ```
244
+ * method: func() -> method;
245
+ * ```
246
+ *
247
+ * @returns {method}
248
+ */
249
+ getMethod() {
250
+ return this.#method;
251
+ }
252
+ /**
253
+ * Set the Method for the Request.
254
+ *
255
+ * WIT:
256
+ * ```
257
+ * set-method: func(method: method) -> result;
258
+ * ```
259
+ *
260
+ * @param {method} method
261
+ * @throws {HttpError} with payload.tag 'invalid-syntax' if method is invalid
262
+ */
263
+ setMethod(method) {
264
+ this.#method = normalizeMethod(method);
265
+ }
266
+ /**
267
+ * Get the HTTP Path and Query.
268
+ *
269
+ * WIT:
270
+ * ```
271
+ * path-with-query: func() -> option<string>;
272
+ * ```
273
+ *
274
+ * @returns {?string}
275
+ */
276
+ getPathWithQuery() {
277
+ return this.#pathWithQuery;
278
+ }
279
+ /**
280
+ * Set the HTTP Path and Query.
281
+ *
282
+ * WIT:
283
+ * ```
284
+ * set-path-with-query: func(path-with-query: option<string>) -> result;
285
+ * ```
286
+ *
287
+ * @param {?string} pathWithQuery
288
+ * @throws {HttpError} with payload.tag 'invalid-syntax' if invalid URI component
289
+ */
290
+ setPathWithQuery(pathWithQuery) {
291
+ validateUrlPart(pathWithQuery, UrlPart.PATH_WITH_QUERY);
292
+ this.#pathWithQuery = pathWithQuery === "" ? "/" : (pathWithQuery ?? undefined);
293
+ }
294
+ /**
295
+ * Get the HTTP Scheme.
296
+ *
297
+ * WIT:
298
+ * ```
299
+ * scheme: func() -> option<scheme>;
300
+ * ```
301
+ *
302
+ * @returns {?scheme}
303
+ */
304
+ getScheme() {
305
+ return this.#scheme;
306
+ }
307
+ /**
308
+ * Set the HTTP Scheme.
309
+ *
310
+ * WIT:
311
+ * ```
312
+ * set-scheme: func(scheme: option<scheme>) -> result;
313
+ * ```
314
+ *
315
+ * @param {?scheme} scheme
316
+ * @throws {HttpError} with payload.tag 'invalid-syntax' if invalid scheme
317
+ */
318
+ setScheme(scheme) {
319
+ this.#scheme = normalizeScheme(scheme);
320
+ }
321
+ /**
322
+ * Get the authority for the target URI.
323
+ *
324
+ * WIT:
325
+ * ```
326
+ * authority: func() -> option<string>;
327
+ * ```
328
+ *
329
+ * @returns {?string}
330
+ */
331
+ getAuthority() {
332
+ return this.#authority;
333
+ }
334
+ /**
335
+ * Set the authority for the target URI.
336
+ *
337
+ * WIT:
338
+ * ```
339
+ * set-authority: func(authority: option<string>) -> result;
340
+ * ```
341
+ *
342
+ * @param {?string} authority
343
+ * @throws {HttpError} with payload.tag 'invalid-syntax' if invalid authority
344
+ */
345
+ setAuthority(authority) {
346
+ validateUrlPart(authority, UrlPart.AUTHORITY);
347
+ this.#authority = authority ?? undefined;
348
+ }
349
+ /**
350
+ * Get the associated request-options resource.
351
+ *
352
+ * WIT:
353
+ * ```
354
+ * options: func() -> option<request-options>;
355
+ * ```
356
+ *
357
+ * @returns {?RequestOptions}
358
+ */
359
+ getOptions() {
360
+ return this.#options;
361
+ }
362
+ /**
363
+ * Get the headers resource (immutable).
364
+ *
365
+ * WIT:
366
+ * ```
367
+ * headers: func() -> headers;
368
+ * ```
369
+ *
370
+ * @returns {Fields}
371
+ */
372
+ getHeaders() {
373
+ return this.#headers;
374
+ }
375
+ /**
376
+ * Get body stream and trailers future, consuming the resource.
377
+ *
378
+ * WIT:
379
+ * ```
380
+ * consume-body: static func(this: request, res: future<result<_, error-code>>)
381
+ * -> tuple<stream<u8>, future<result<option<trailers>, error-code>>>;
382
+ * ```
383
+ *
384
+ * @param {Request} request - The request to consume.
385
+ * @param {FutureReader} res - A future for communicating errors.
386
+ * @returns {[StreamReader, FutureReader]} A tuple of [body stream, trailers future].
387
+ * @throws {HttpError} with payload.tag 'invalid-state' if body already open or consumed.
388
+ */
389
+ static consumeBody(request, res) {
390
+ if (res && typeof res.then === "function") {
391
+ // TODO: Use res to abort/close the body transport on errors.
392
+ void Promise.resolve(res).catch(() => { });
393
+ }
394
+ if (request.#bodyOpen) {
395
+ throw new HttpError("invalid-state", "body already called and not yet closed");
396
+ }
397
+ if (request.#bodyEnded) {
398
+ throw new HttpError("invalid-state", "body has already been consumed");
399
+ }
400
+ if (!request.#contents) {
401
+ request.#bodyEnded = true;
402
+ return [request.#contents, request.#trailersFuture];
403
+ }
404
+ const reader = request.#contents;
405
+ request.#bodyOpen = true;
406
+ const readFn = reader.read.bind(reader);
407
+ reader.read = async (...args) => {
408
+ const chunk = await readFn(...args);
409
+ if (chunk === null) {
410
+ request.#bodyEnded = true;
411
+ request.#bodyOpen = false;
412
+ }
413
+ return chunk;
414
+ };
415
+ const closedFn = reader.close.bind(reader);
416
+ reader.close = () => {
417
+ closedFn();
418
+ request.#bodyEnded = true;
419
+ request.#bodyOpen = false;
420
+ };
421
+ return [request.#contents, request.#trailersFuture];
422
+ }
423
+ // TODO: placeholder
424
+ _resolve(result) {
425
+ if (this.#requestFuture) {
426
+ this.#requestFuture.write(result);
427
+ this.#requestFuture = null;
428
+ }
429
+ }
430
+ }
431
+ function readableContentsStream(reader, headers) {
432
+ const expectedLength = contentLength(headers.copyAll());
433
+ if (expectedLength === null) {
434
+ return readableByteStreamFromReader(reader, { name: "contents" });
435
+ }
436
+ const source = typeof reader?.read === "function"
437
+ ? reader
438
+ : new StreamReader(readableByteStreamFromReader(reader, { name: "contents" }));
439
+ return readableByteStreamFromReader(contentLengthReader(source, expectedLength), {
440
+ name: "contents",
441
+ });
442
+ }
443
+ function contentLengthReader(reader, expectedLength) {
444
+ let sent = 0n;
445
+ return {
446
+ async read() {
447
+ const result = await reader.read(readOpts(expectedLength - sent));
448
+ if (isIteratorResult(result) && result.rejectedLength !== undefined) {
449
+ throw requestBodySizeError(sent + BigInt(result.rejectedLength));
450
+ }
451
+ if (isIteratorResult(result) && result.done) {
452
+ if (sent < expectedLength) {
453
+ throw requestBodySizeError(sent);
454
+ }
455
+ return result;
456
+ }
457
+ const value = isIteratorResult(result) ? result.value : result;
458
+ const chunk = _byteChunk(value);
459
+ sent += BigInt(chunk.byteLength);
460
+ if (sent > expectedLength) {
461
+ throw requestBodySizeError(sent);
462
+ }
463
+ return { value: chunk, done: false };
464
+ },
465
+ cancel(reason) {
466
+ if (typeof reader.cancel === "function") {
467
+ return reader.cancel(reason);
468
+ }
469
+ if (typeof reader.close === "function") {
470
+ return reader.close();
471
+ }
472
+ return reader[symbolDispose]?.();
473
+ },
474
+ };
475
+ }
476
+ function readOpts(remaining) {
477
+ if (remaining <= 0n) {
478
+ return { count: 0, rejectLength: 0 };
479
+ }
480
+ const count = Number(remaining <= BigInt(DEFAULT_BYTE_STREAM_CHUNK_SIZE)
481
+ ? remaining
482
+ : BigInt(DEFAULT_BYTE_STREAM_CHUNK_SIZE));
483
+ const opts = { count };
484
+ if (remaining <= BigInt(Number.MAX_SAFE_INTEGER)) {
485
+ opts.rejectLength = Number(remaining);
486
+ }
487
+ return opts;
488
+ }
489
+ function requestBodySizeError(bytes) {
490
+ return { tag: "HTTP-request-body-size", val: bytes };
491
+ }
492
+ function isIteratorResult(value) {
493
+ return value != null && typeof value === "object" && typeof value.done === "boolean";
494
+ }
495
+ const decoder = new TextDecoder();
496
+ const contentLength = (entries) => {
497
+ const entry = entries.findLast(([name]) => name.toLowerCase() === "content-length");
498
+ if (!entry) {
499
+ return null;
500
+ }
501
+ const value = decoder.decode(entry[1]);
502
+ return /^\d+$/.test(value) ? BigInt(value) : null;
503
+ };
504
+ const UrlPart = {
505
+ PATH_WITH_QUERY: "pathWithQuery",
506
+ SCHEME: "scheme",
507
+ AUTHORITY: "authority",
508
+ };
509
+ function normalizeMethod(method) {
510
+ const VALUE_TOKEN_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
511
+ if (typeof method === "string") {
512
+ if (!VALUE_TOKEN_RE.test(method)) {
513
+ throw new HttpError("invalid-syntax");
514
+ }
515
+ const lowercase = method.toLowerCase();
516
+ return SUPPORTED_METHODS.includes(lowercase)
517
+ ? { tag: lowercase }
518
+ : { tag: "other", val: lowercase };
519
+ }
520
+ if (!method || typeof method !== "object" || typeof method.tag !== "string") {
521
+ throw new HttpError("invalid-syntax");
522
+ }
523
+ if (SUPPORTED_METHODS.includes(method.tag)) {
524
+ return { tag: method.tag };
525
+ }
526
+ if (method.tag === "other" && typeof method.val === "string" && VALUE_TOKEN_RE.test(method.val)) {
527
+ const standard = method.val.toLowerCase();
528
+ return SUPPORTED_METHODS.includes(standard) && method.val === method.val.toUpperCase()
529
+ ? { tag: standard }
530
+ : { tag: "other", val: method.val };
531
+ }
532
+ throw new HttpError("invalid-syntax");
533
+ }
534
+ function normalizeScheme(scheme) {
535
+ if (scheme == null) {
536
+ return undefined;
537
+ }
538
+ if (typeof scheme === "string") {
539
+ validateUrlPart(scheme, UrlPart.SCHEME);
540
+ const uppercase = scheme.toUpperCase();
541
+ if (uppercase === "HTTP" || uppercase === "HTTPS") {
542
+ return { tag: uppercase };
543
+ }
544
+ return { tag: "other", val: scheme };
545
+ }
546
+ if (typeof scheme !== "object" || typeof scheme.tag !== "string") {
547
+ throw new HttpError("invalid-syntax");
548
+ }
549
+ if (scheme.tag === "HTTP" || scheme.tag === "HTTPS") {
550
+ return { tag: scheme.tag };
551
+ }
552
+ if (scheme.tag === "other" && typeof scheme.val === "string") {
553
+ validateUrlPart(scheme.val, UrlPart.SCHEME);
554
+ const uppercase = scheme.val.toUpperCase();
555
+ if (uppercase === "HTTP" || uppercase === "HTTPS") {
556
+ return { tag: uppercase };
557
+ }
558
+ return { tag: "other", val: scheme.val };
559
+ }
560
+ throw new HttpError("invalid-syntax");
561
+ }
562
+ export function _schemeToString(scheme) {
563
+ if (scheme === undefined) {
564
+ return undefined;
565
+ }
566
+ switch (scheme.tag) {
567
+ case "HTTP":
568
+ return "http";
569
+ case "HTTPS":
570
+ return "https";
571
+ case "other":
572
+ return scheme.val;
573
+ default:
574
+ throw new HttpError("invalid-syntax", `Invalid scheme: ${scheme.tag}`);
575
+ }
576
+ }
577
+ function validateUrlPart(value, part) {
578
+ if (value == null) {
579
+ return;
580
+ }
581
+ // URL parsing may normalize some raw control characters but wasi treats them as invalid syntax.
582
+ if (/[\u0000-\u001f\u007f]/.test(value)) {
583
+ throw new HttpError("invalid-syntax", `Invalid ${part}: ${value}`);
584
+ }
585
+ if (part === UrlPart.PATH_WITH_QUERY && /[ <>`]/.test(value)) {
586
+ throw new HttpError("invalid-syntax", `Invalid ${part}: ${value}`);
587
+ }
588
+ try {
589
+ switch (part) {
590
+ case UrlPart.PATH_WITH_QUERY:
591
+ new URL(value, "http://example");
592
+ break;
593
+ case UrlPart.SCHEME:
594
+ new URL(`${value}://example`);
595
+ break;
596
+ case UrlPart.AUTHORITY:
597
+ new URL(`http://${value}`);
598
+ break;
599
+ default:
600
+ throw new Error(`Unknown URL part: ${part}`);
601
+ }
602
+ }
603
+ catch {
604
+ throw new HttpError("invalid-syntax", `Invalid ${part}: ${value}`);
605
+ }
606
+ }
@@ -0,0 +1,82 @@
1
+ import { FutureReader } from "../future.js";
2
+ declare const symbolDispose: symbol;
3
+ export declare class Response {
4
+ #private;
5
+ [symbolDispose]: () => void;
6
+ /**
7
+ * @private
8
+ * Use Response.new(...) to create an instance
9
+ */
10
+ constructor(t: any);
11
+ /**
12
+ * Construct a new Response with default status-code 200.
13
+ *
14
+ * WIT:
15
+ * ```
16
+ * new: static func(
17
+ * headers: headers,
18
+ * contents: option<stream<u8>>,
19
+ * trailers: future<result<option<trailers>, error-code>>
20
+ * ) -> tuple<response, future<result<_, error-code>>>;
21
+ * ```
22
+ *
23
+ * @param {Fields} headers immutable headers resource
24
+ * @param {?StreamReader|object} contents optional body stream
25
+ * @param {FutureReader|Promise} trailers future for trailers
26
+ * @returns {{ res: Response, future: FutureReader }}
27
+ * @throws {HttpError} with payload.tag 'invalid-argument' for invalid arguments
28
+ */
29
+ static new(headers: any, contents: any, trailers: any): [Response, FutureReader];
30
+ /**
31
+ * Get the HTTP Status Code for the Response.
32
+ *
33
+ * WIT:
34
+ * ```
35
+ * status-code: func() -> status-code;
36
+ * ```
37
+ *
38
+ * @returns {number}
39
+ */
40
+ getStatusCode(): number;
41
+ /**
42
+ * Set the HTTP Status Code for the Response.
43
+ *
44
+ * WIT:
45
+ * ```
46
+ * set-status-code: func(status-code: status-code) -> result;
47
+ * ```
48
+ *
49
+ * @param {number} code
50
+ * @throws {HttpError} with payload.tag 'invalid-argument'
51
+ * if code is not an integer in [100,599]
52
+ */
53
+ setStatusCode(code: any): void;
54
+ /**
55
+ * Get the headers associated with the Response.
56
+ *
57
+ * WIT:
58
+ * ```
59
+ * headers: func() -> headers;
60
+ * ```
61
+ *
62
+ * @returns {Fields}
63
+ */
64
+ getHeaders(): any;
65
+ /**
66
+ * Get body stream and trailers future, consuming the resource.
67
+ *
68
+ * WIT:
69
+ * ```
70
+ * consume-body: static func(this: response, res: future<result<_, error-code>>)
71
+ * -> tuple<stream<u8>, future<result<option<trailers>, error-code>>>;
72
+ * ```
73
+ *
74
+ * @param {Response} response - The response to consume.
75
+ * @param {FutureReader} res - A future for communicating errors.
76
+ * @returns {[StreamReader, FutureReader]} A tuple of [body stream, trailers future].
77
+ * @throws {HttpError} with payload.tag 'invalid-state' if body has already been opened or consumed.
78
+ */
79
+ static consumeBody(response: any, res: any): any[];
80
+ _resolve(result: any): void;
81
+ }
82
+ export {};