rust-fetch 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,7 +43,7 @@ const { body: user } = await api.get('/users/42');
43
43
  - **Streaming** responses as a `ReadableStream`, and **download progress** callbacks.
44
44
  - **Interceptors** for requests and responses, e.g. auth headers and token refresh.
45
45
  - **TypeScript** definitions for the whole API.
46
- - **Tested**: 100% line coverage of the Rust core, plus wasm tests and end-to-end tests of the packed npm package. See [Development](#development).
46
+ - **Tested**: 100% line coverage of the Rust core and of the Node.js transport, plus wasm tests and end-to-end tests of the packed npm package. See [Development](#development).
47
47
 
48
48
  ## Installation
49
49
 
@@ -105,7 +105,7 @@ await client.get('/search', { params: { q: 'rust wasm', page: 2, tag: ['a', 'b']
105
105
  await client.fetch('/users/1', { method: 'DELETE', headers: { 'X-Reason': 'cleanup' } });
106
106
  ```
107
107
 
108
- Relative URLs need a `baseUrl`. In a browser page without one, they resolve against the page URL. Absolute URLs always win over `baseUrl`. `TRACE` and `CONNECT` are rejected because `fetch()` forbids them.
108
+ Relative URLs need a `baseUrl`. In a browser page without one, they resolve against the page URL. Absolute URLs always win over `baseUrl`. `TRACE` and `CONNECT` are rejected, because browsers' `fetch()` forbids them.
109
109
 
110
110
  #### Request options
111
111
 
@@ -223,7 +223,7 @@ controller.abort(); // rejects with a CancelledError
223
223
  await client.get('/report', { signal: AbortSignal.timeout(5_000) }); // total deadline, including retries
224
224
  ```
225
225
 
226
- Aborting cancels the underlying `fetch`, any pending retry delay, and a body being streamed.
226
+ Aborting cancels the request in flight, any pending retry delay, and a body being streamed.
227
227
 
228
228
  ### Streaming
229
229
 
@@ -352,18 +352,20 @@ Request futures are `Send`, so you can `tokio::spawn` them. Progress callbacks (
352
352
 
353
353
  ## Performance
354
354
 
355
- rust-fetch makes its requests through the runtime's own `fetch()`, so the network work is the same as plain `fetch`. The extra cost comes from crossing the JS ↔ Wasm boundary and copying bodies. It is **not faster than native `fetch`**. Use it for the reliability features, not for speed.
355
+ **In Node.js, rust-fetch is as fast as or faster than the built-in `fetch()` for typical API traffic.** Node's `fetch()` implements browser semantics (WHATWG streams) on top of its sockets. rust-fetch uses its own lean transport on `node:http`/`node:https` with keep-alive. Retries, timeouts, validation and errors still come from the Rust core.
356
356
 
357
- `npm run bench` (Node 22.13, Apple M1 Pro, local server):
357
+ `npm run bench` (Node 22.13, Apple M1 Pro, local server, median of 5 alternating rounds):
358
358
 
359
359
  | Scenario | native `fetch` | rust-fetch | rust-fetch / native |
360
360
  | --- | ---: | ---: | ---: |
361
- | Small JSON, sequential | 5,465 req/s | 4,015 req/s | 73% |
362
- | Small JSON, 50 concurrent | 12,155 req/s | 6,035 req/s | 50% |
363
- | JSON 0.6 MB | 219 req/s | 212 req/s | 97% |
364
- | Binary 8 MB | 189 req/s | 147 req/s | 77% |
361
+ | Small JSON, sequential | 10,558 req/s | 10,634 req/s | **101%** |
362
+ | Small JSON, 50 concurrent | 13,401 req/s | 13,895 req/s | **104%** |
363
+ | JSON 0.6 MB | 219 req/s | 203 req/s | 92% |
364
+ | Binary 8 MB | 177 req/s | 181 req/s | **102%** |
365
365
 
366
- The overhead per request is a fraction of a millisecond, which matters little once a request crosses a real network.
366
+ Large JSON is dominated by `JSON.parse`, which both clients pay; the remaining gap is extra garbage collection from crossing into Wasm.
367
+
368
+ **In browsers**, `fetch()` is the only way to make requests, so rust-fetch uses it and can't be faster than it. The difference is a fraction of a millisecond per request, which matters little once a request crosses a real network.
367
369
 
368
370
  ## Roadmap
369
371
 
@@ -379,9 +381,9 @@ The overhead per request is a fraction of a millisecond, which matters little on
379
381
  - [ ] Upload progress tracking: not possible on top of `fetch()`, which has no upload progress events
380
382
  - [ ] WebSocket support
381
383
  - Handled by the runtime, not by rust-fetch:
382
- - **Connection pooling:** browsers and Node.js pool connections for `fetch()` themselves.
383
- - **Proxies:** set them up in the runtime, e.g. with undici's `setGlobalDispatcher(new ProxyAgent(url))` in Node.js, or with system settings in browsers.
384
- - **HTTP/2:** browsers negotiate it automatically; in Node.js it depends on undici's dispatcher (`allowH2`).
384
+ - **Connection pooling:** browsers pool connections for `fetch()`; in Node.js rust-fetch reuses connections through Node's default keep-alive agents.
385
+ - **Proxies:** in Node.js, install a proxy agent as `http.globalAgent` / `https.globalAgent` (for example from `https-proxy-agent`). In browsers, use the system settings.
386
+ - **HTTP/2:** browsers negotiate it automatically; the Node.js transport uses HTTP/1.1 with keep-alive.
385
387
 
386
388
  ## Upgrading to 2.0
387
389
 
@@ -420,6 +422,7 @@ npm run test:js # JS end-to-end tests against the built package (requires a b
420
422
  npm run bench # rust-fetch vs native fetch (requires a build)
421
423
  npm run size # size budget for the built package
422
424
  npm run api:check # public TypeScript API vs the committed snapshot
425
+ npm run coverage:js # Node.js transport coverage (100% lines and functions)
423
426
 
424
427
  cd wasm-module
425
428
  wasm-pack test --node # wasm unit tests for the JS bindings
@@ -434,7 +437,7 @@ cargo llvm-cov --ignore-filename-regex 'src/(wasm/|http\.rs)|tests/' # coverag
434
437
  | JS end-to-end tests | `wasm-module/js/test/client.test.mjs` | The built package against a local server |
435
438
  | Package tests | `wasm-module/js/test/package.test.mjs` | Installs the packed tarball and uses it via `import`, `require`, the browser entry and its types |
436
439
 
437
- CI runs the Rust suites with a coverage gate that fails if line or function coverage of the Rust core drops below 100%. It also runs the wasm and JS suites on Node 20, 22 and 24, and checks formatting, dependencies (security advisories and licenses), API compatibility and the size budget. See [CONTRIBUTING.md](CONTRIBUTING.md#pull-requests). The JS-only bindings in `src/wasm/` and `src/http.rs` need a JS engine, so they're covered by the wasm and JS suites instead.
440
+ CI runs the Rust suites with a coverage gate that fails if line or function coverage of the Rust core, or of the Node.js transport, drops below 100%. It also runs the wasm and JS suites on Node 20, 22 and 24, and checks formatting, dependencies (security advisories and licenses), API compatibility and the size budget. See [CONTRIBUTING.md](CONTRIBUTING.md#pull-requests). The JS-only bindings in `src/wasm/` and `src/http.rs` need a JS engine, so they're covered by the wasm and JS suites instead.
438
441
 
439
442
  Releases are published by CI when a version tag is pushed. See [CONTRIBUTING.md](CONTRIBUTING.md#releasing).
440
443
 
package/node.js CHANGED
@@ -4,10 +4,262 @@
4
4
  // file: URLs. Here the module is compiled synchronously on import instead, so
5
5
  // the API is ready to use immediately; calling `init()` is optional and
6
6
  // returns the already-initialized module.
7
+ //
8
+ // It also registers a transport built on node:http/node:https. Node's global
9
+ // fetch() implements browser semantics (WHATWG streams) on top of the same
10
+ // sockets and is considerably slower; this transport only moves bytes.
11
+ // Retries, timeouts, validation and decoding stay in the Rust core.
7
12
  import { readFileSync } from 'node:fs';
13
+ import http from 'node:http';
14
+ import https from 'node:https';
15
+ import zlib from 'node:zlib';
8
16
  import { initSync } from './rust_fetch.js';
9
17
 
10
18
  initSync({ module: readFileSync(new URL('./rust_fetch_bg.wasm', import.meta.url)) });
11
19
 
20
+ const MAX_REDIRECTS = 20;
21
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
22
+ const ACCEPT_ENCODING = typeof zlib.zstdDecompressSync === 'function' ? 'gzip, deflate, br, zstd' : 'gzip, deflate, br';
23
+
24
+ const textDecoder = new TextDecoder();
25
+ // Response body types, numbered like `BodyType` in src/wasm/mod.rs
26
+ const AUTO = 0;
27
+ const JSON_BODY = 1;
28
+ const TEXT = 2;
29
+ const BINARY = 3;
30
+
31
+ // Same rules as is_json_content_type / is_text_content_type in src/types.rs
32
+ function mimeEssence(contentType) {
33
+ return (contentType ?? '').split(';')[0].trim().toLowerCase();
34
+ }
35
+ function isJsonType(essence) {
36
+ return essence === 'application/json' || essence.endsWith('+json');
37
+ }
38
+ function isTextType(essence) {
39
+ return (
40
+ essence.startsWith('text/') ||
41
+ essence.endsWith('+xml') ||
42
+ essence === 'application/xml' ||
43
+ essence === 'application/javascript' ||
44
+ essence === 'application/x-www-form-urlencoded'
45
+ );
46
+ }
47
+
48
+ function coded(error, code) {
49
+ error.code = code;
50
+ return error;
51
+ }
52
+
53
+ /**
54
+ * Decode a body like `decode_body` in src/wasm/transport.rs, in JS so the
55
+ * text never crosses into wasm. TextDecoder replaces invalid UTF-8 and strips
56
+ * a BOM; the length is checked first, since a BOM-only body is not empty.
57
+ */
58
+ function decodeBody(bytes, contentType, bodyType) {
59
+ if (bytes.length === 0) return bodyType === TEXT ? '' : bodyType === BINARY ? new Uint8Array(0) : null;
60
+ const essence = mimeEssence(contentType);
61
+ const json = bodyType === JSON_BODY || (bodyType === AUTO && isJsonType(essence));
62
+ const text = json || bodyType === TEXT || (bodyType === AUTO && isTextType(essence));
63
+ if (!text) return bytes;
64
+ const decoded = textDecoder.decode(bytes);
65
+ if (!json) return decoded;
66
+ try {
67
+ return JSON.parse(decoded);
68
+ } catch (error) {
69
+ if (bodyType === AUTO) return decoded; // mislabelled responses fall back to text
70
+ throw coded(error, 'RUST_FETCH_PARSE');
71
+ }
72
+ }
73
+
74
+ /** Undo one Content-Encoding; unknown encodings are passed through, like fetch() */
75
+ function decode(body, encoding) {
76
+ switch (encoding) {
77
+ case 'gzip':
78
+ case 'x-gzip':
79
+ return zlib.gunzipSync(body, { finishFlush: zlib.constants.Z_SYNC_FLUSH });
80
+ case 'deflate':
81
+ // Servers send both zlib-wrapped and raw deflate under this name
82
+ return body[0] === 0x78 ? zlib.inflateSync(body) : zlib.inflateRawSync(body);
83
+ case 'br':
84
+ return zlib.brotliDecompressSync(body);
85
+ case 'zstd':
86
+ return typeof zlib.zstdDecompressSync === 'function' ? zlib.zstdDecompressSync(body) : body;
87
+ default:
88
+ return body;
89
+ }
90
+ }
91
+
92
+ function decompress(body, contentEncoding) {
93
+ if (!contentEncoding || body.length === 0) return body;
94
+ // Encodings are listed in the order they were applied
95
+ const encodings = contentEncoding.toLowerCase().split(',').map((e) => e.trim()).filter((e) => e && e !== 'identity');
96
+ for (let i = encodings.length - 1; i >= 0; i--) body = decode(body, encodings[i]);
97
+ return body;
98
+ }
99
+
100
+ /** Response headers as one string per name; repeated headers joined with ", " */
101
+ function flattenHeaders(raw) {
102
+ const headers = {};
103
+ for (const name in raw) {
104
+ const value = raw[name];
105
+ headers[name] = Array.isArray(value) ? value.join(', ') : value;
106
+ }
107
+ return headers;
108
+ }
109
+
110
+ /**
111
+ * A plain Uint8Array that owns its memory. Small Node Buffers share a pooled
112
+ * ArrayBuffer, so those are copied; larger ones are wrapped without copying.
113
+ */
114
+ function ownedBytes(bytes) {
115
+ return bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength
116
+ ? new Uint8Array(bytes.buffer)
117
+ : new Uint8Array(bytes);
118
+ }
119
+
120
+ function withoutHeaders(headers, names) {
121
+ const copy = { ...headers };
122
+ for (const name of names) delete copy[name];
123
+ return copy;
124
+ }
125
+
126
+ function send(state, method, url, headers, body, redirects, resolve, reject) {
127
+ if (state.cancelled) return;
128
+ const transport = url.protocol === 'https:' ? https : http;
129
+ const request = transport.request(url, { method, headers }, (response) => {
130
+ const status = response.statusCode;
131
+ const location = response.headers.location;
132
+
133
+ if (REDIRECT_STATUSES.has(status) && location) {
134
+ response.resume();
135
+ if (redirects >= MAX_REDIRECTS) return reject(new TypeError(`Too many redirects (more than ${MAX_REDIRECTS})`));
136
+ let next;
137
+ try {
138
+ next = new URL(location, url);
139
+ } catch {
140
+ return reject(new TypeError(`Invalid redirect location: ${location}`));
141
+ }
142
+ if (next.protocol !== 'http:' && next.protocol !== 'https:') {
143
+ return reject(new TypeError(`Unsupported redirect to ${next.protocol}`));
144
+ }
145
+ // Same rules as fetch(): 303, and 301/302 after POST, become a bodiless GET
146
+ let nextMethod = method;
147
+ let nextBody = body;
148
+ let nextHeaders = headers;
149
+ if ((status === 303 && method !== 'GET' && method !== 'HEAD') || ((status === 301 || status === 302) && method === 'POST')) {
150
+ nextMethod = 'GET';
151
+ nextBody = undefined;
152
+ nextHeaders = withoutHeaders(nextHeaders, ['content-type', 'content-length', 'content-encoding', 'content-language', 'content-location']);
153
+ }
154
+ // Never forward credentials to another origin
155
+ if (next.origin !== url.origin) {
156
+ nextHeaders = withoutHeaders(nextHeaders, ['authorization', 'cookie', 'proxy-authorization']);
157
+ }
158
+ return send(state, nextMethod, next, nextHeaders, nextBody, redirects + 1, resolve, reject);
159
+ }
160
+
161
+ // With a Content-Length, fill one preallocated buffer (a single copy);
162
+ // otherwise collect chunks and join them at the end.
163
+ const expected = Number(response.headers['content-length']);
164
+ const preallocated = !response.headers['content-encoding'] && Number.isSafeInteger(expected) && expected > 0 && expected <= 512 * 1024 * 1024;
165
+ const buffer = preallocated ? new Uint8Array(expected) : undefined;
166
+ let received = 0;
167
+ const chunks = [];
168
+ response.on('data', (chunk) => {
169
+ if (buffer && received + chunk.length <= expected) buffer.set(chunk, received);
170
+ else chunks.push(chunk);
171
+ received += chunk.length;
172
+ });
173
+ response.on('error', reject);
174
+ // A socket closed mid-body may emit 'close' without 'end' (a settled promise ignores this)
175
+ response.on('close', () => {
176
+ if (!response.complete) reject(new TypeError('The connection closed before the response body was complete'));
177
+ });
178
+ response.on('end', () => {
179
+ if (!response.complete) return reject(new TypeError('The connection closed before the response body was complete'));
180
+ try {
181
+ let body;
182
+ if (buffer && received === expected && chunks.length === 0) {
183
+ body = buffer;
184
+ } else {
185
+ const raw = buffer ? Buffer.concat([buffer.subarray(0, Math.min(received, expected)), ...chunks]) : Buffer.concat(chunks);
186
+ body = ownedBytes(method === 'HEAD' ? raw : decompress(raw, response.headers['content-encoding']));
187
+ }
188
+ resolve({ status, url: url.href, headers: flattenHeaders(response.headers), body });
189
+ } catch (error) {
190
+ reject(error);
191
+ }
192
+ });
193
+ });
194
+ request.on('error', reject);
195
+ request.end(body);
196
+ state.request = request;
197
+ }
198
+
199
+ /**
200
+ * One attempt, called by the Rust core with
201
+ * `{ method, url, headers, body?, timeout?, bodyType }`. Resolves to the
202
+ * finished `{ status, statusText, ok, url, headers, body }` (the core fills
203
+ * in statusText). Rejects with code RUST_FETCH_TIMEOUT or RUST_FETCH_PARSE,
204
+ * or any other error for network failures.
205
+ *
206
+ * The promise has a `cancel()` method, which the core calls only when it
207
+ * abandons an attempt (e.g. AbortSignal); this is much cheaper than wiring an
208
+ * AbortSignal into every request.
209
+ */
210
+ function nodeTransport(request) {
211
+ const state = { cancelled: false, request: undefined, bodyType: request.bodyType ?? AUTO };
212
+ let timer;
213
+ const promise = new Promise((resolve, reject) => {
214
+ if (request.timeout > 0) {
215
+ // Covers the whole attempt: connecting, redirects and reading the body
216
+ timer = setTimeout(() => {
217
+ cancel();
218
+ reject(coded(new Error(`Request timeout after ${request.timeout}ms`), 'RUST_FETCH_TIMEOUT'));
219
+ }, request.timeout);
220
+ }
221
+ let url;
222
+ try {
223
+ url = new URL(request.url);
224
+ } catch (error) {
225
+ clearTimeout(timer);
226
+ return reject(error);
227
+ }
228
+ const headers = { ...request.headers };
229
+ headers['accept'] ??= '*/*';
230
+ headers['accept-encoding'] ??= ACCEPT_ENCODING;
231
+ headers['user-agent'] ??= 'rust-fetch';
232
+ if (request.body) headers['content-length'] ??= String(request.body.length);
233
+ const settle = (fn) => (value) => {
234
+ clearTimeout(timer);
235
+ fn(value);
236
+ };
237
+ send(state, request.method, url, headers, request.body, 0, settle(resolve), settle(reject));
238
+ });
239
+ const cancel = () => {
240
+ state.cancelled = true;
241
+ state.request?.destroy();
242
+ };
243
+ // Decode only after the socket's event handlers have returned: decoding
244
+ // inside them keeps the raw chunks and stream state alive during
245
+ // JSON.parse, which costs several times more garbage collection.
246
+ const finished = promise.then((response) => finishResponse(response, state.bodyType));
247
+ finished.cancel = () => {
248
+ clearTimeout(timer);
249
+ cancel();
250
+ };
251
+ return finished;
252
+ }
253
+
254
+ /** The response object handed to the Rust core (which fills in statusText) */
255
+ function finishResponse({ status, url, headers, body }, bodyType) {
256
+ const ok = status >= 200 && status < 300;
257
+ // Error statuses carry their body as text (for HttpError.body)
258
+ const decoded = ok ? decodeBody(body, headers['content-type'], bodyType) : decodeBody(body, '', TEXT);
259
+ return { status, statusText: '', ok, url, headers, body: decoded };
260
+ }
261
+
262
+ globalThis[Symbol.for('rust-fetch.transport')] = nodeTransport;
263
+
12
264
  export { default } from './rust_fetch.js';
13
265
  export * from './rust_fetch.js';
package/package.json CHANGED
@@ -4,8 +4,8 @@
4
4
  "collaborators": [
5
5
  "Asem Qaffaf <asem@qaffaf.com>"
6
6
  ],
7
- "description": "A high-performance HTTP client for JavaScript/TypeScript powered by WebAssembly, for browsers and Node.js",
8
- "version": "2.0.0",
7
+ "description": "A reliable HTTP client for JavaScript and TypeScript, written in Rust and compiled to WebAssembly: timeouts, retries, typed errors and interceptors, faster than fetch() in Node.js",
8
+ "version": "2.1.0",
9
9
  "license": "MIT OR Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",
package/rust_fetch.js CHANGED
@@ -513,6 +513,10 @@ function __wbg_get_imports() {
513
513
  __wbg_append_1938ed58fb5613b8: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
514
514
  arg0.append(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
515
515
  }, arguments); },
516
+ __wbg_arrayBuffer_f07be74819944ea2: function() { return handleError(function (arg0) {
517
+ const ret = arg0.arrayBuffer();
518
+ return ret;
519
+ }, arguments); },
516
520
  __wbg_body_4e088733babc630d: function(arg0) {
517
521
  const ret = arg0.body;
518
522
  return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
@@ -525,6 +529,10 @@ function __wbg_get_imports() {
525
529
  const ret = arg0.byobRequest;
526
530
  return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
527
531
  },
532
+ __wbg_byteLength_27689b065d089962: function(arg0) {
533
+ const ret = arg0.byteLength;
534
+ return ret;
535
+ },
528
536
  __wbg_byteLength_9f985b8373f1f3fe: function(arg0) {
529
537
  const ret = arg0.byteLength;
530
538
  return ret;
@@ -553,7 +561,7 @@ function __wbg_get_imports() {
553
561
  const ret = clearTimeout(arg0);
554
562
  return ret;
555
563
  },
556
- __wbg_clearTimeout_80e0bf42f165386a: function(arg0) {
564
+ __wbg_clearTimeout_2d18004c33139d44: function(arg0) {
557
565
  clearTimeout(arg0);
558
566
  },
559
567
  __wbg_close_185286988f30f252: function() { return handleError(function (arg0) {
@@ -562,6 +570,10 @@ function __wbg_get_imports() {
562
570
  __wbg_close_748f26698dabe269: function() { return handleError(function (arg0) {
563
571
  arg0.close();
564
572
  }, arguments); },
573
+ __wbg_decode_0be77be735437c76: function() { return handleError(function (arg0, arg1) {
574
+ const ret = arg0.decode(arg1);
575
+ return ret;
576
+ }, arguments); },
565
577
  __wbg_done_b41a1d26cdb37fb6: function(arg0) {
566
578
  const ret = arg0.done;
567
579
  return ret;
@@ -577,6 +589,10 @@ function __wbg_get_imports() {
577
589
  const ret = Object.entries(arg0);
578
590
  return ret;
579
591
  },
592
+ __wbg_fetch_43bae44b7171a171: function() { return handleError(function (arg0) {
593
+ const ret = fetch(arg0);
594
+ return ret;
595
+ }, arguments); },
580
596
  __wbg_fetch_7a37768ab67c5bd8: function(arg0) {
581
597
  const ret = fetch(arg0);
582
598
  return ret;
@@ -585,6 +601,14 @@ function __wbg_get_imports() {
585
601
  const ret = arg0.fetch(arg1);
586
602
  return ret;
587
603
  },
604
+ __wbg_for_beb5dc4e908dd8b8: function(arg0, arg1) {
605
+ const ret = Symbol.for(getStringFromWasm0(arg0, arg1));
606
+ return ret;
607
+ },
608
+ __wbg_fromEntries_5159142be68954c3: function() { return handleError(function (arg0) {
609
+ const ret = Object.fromEntries(arg0);
610
+ return ret;
611
+ }, arguments); },
588
612
  __wbg_from_296ca31f8d0f1c52: function(arg0) {
589
613
  const ret = Array.from(arg0);
590
614
  return ret;
@@ -609,6 +633,13 @@ function __wbg_get_imports() {
609
633
  const ret = arg0.done;
610
634
  return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0;
611
635
  },
636
+ __wbg_get_f75619e20cb68514: function() { return handleError(function (arg0, arg1, arg2, arg3) {
637
+ const ret = arg1.get(getStringFromWasm0(arg2, arg3));
638
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
639
+ var len1 = WASM_VECTOR_LEN;
640
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
641
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
642
+ }, arguments); },
612
643
  __wbg_get_unchecked_288889d017702237: function(arg0, arg1) {
613
644
  const ret = arg0[arg1 >>> 0];
614
645
  return ret;
@@ -707,6 +738,10 @@ function __wbg_get_imports() {
707
738
  const ret = new Headers();
708
739
  return ret;
709
740
  }, arguments); },
741
+ __wbg_new_cdac6c2ae368ec54: function() {
742
+ const ret = new TextDecoder();
743
+ return ret;
744
+ },
710
745
  __wbg_new_from_slice_9a868026ffa4208a: function(arg0, arg1) {
711
746
  const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
712
747
  return ret;
@@ -753,13 +788,25 @@ function __wbg_get_imports() {
753
788
  const ret = arg0.next();
754
789
  return ret;
755
790
  }, arguments); },
791
+ __wbg_of_20798cb14708764f: function(arg0, arg1) {
792
+ const ret = Array.of(arg0, arg1);
793
+ return ret;
794
+ },
756
795
  __wbg_parse_0fc53dead14b3b42: function() { return handleError(function (arg0, arg1) {
757
796
  const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
758
797
  return ret;
759
798
  }, arguments); },
799
+ __wbg_parse_33ce4953982abfa3: function() { return handleError(function (arg0) {
800
+ const ret = JSON.parse(arg0);
801
+ return ret;
802
+ }, arguments); },
760
803
  __wbg_prototypesetcall_bc27214492979395: function(arg0, arg1, arg2) {
761
804
  Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
762
805
  },
806
+ __wbg_push_2baf45db356cf468: function(arg0, arg1) {
807
+ const ret = arg0.push(arg1);
808
+ return ret;
809
+ },
763
810
  __wbg_queueMicrotask_9833f9a49df95a49: function(arg0) {
764
811
  const ret = arg0.queueMicrotask;
765
812
  return ret;
@@ -792,7 +839,7 @@ function __wbg_get_imports() {
792
839
  __wbg_respond_c102fabcc79e5ef0: function() { return handleError(function (arg0, arg1) {
793
840
  arg0.respond(arg1 >>> 0);
794
841
  }, arguments); },
795
- __wbg_setTimeout_52f32a16f2242504: function(arg0, arg1) {
842
+ __wbg_setTimeout_61cdece84a7288cf: function(arg0, arg1) {
796
843
  const ret = setTimeout(arg0, arg1);
797
844
  return ret;
798
845
  },
@@ -807,6 +854,9 @@ function __wbg_get_imports() {
807
854
  __wbg_set_575d3ddb70fe831d: function(arg0, arg1, arg2) {
808
855
  arg0.set(getArrayU8FromWasm0(arg1, arg2));
809
856
  },
857
+ __wbg_set_af5932e3f78b5648: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
858
+ arg0.set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
859
+ }, arguments); },
810
860
  __wbg_set_body_1fb0f1008bfc7df6: function(arg0, arg1) {
811
861
  arg0.body = arg1;
812
862
  },
@@ -900,17 +950,17 @@ function __wbg_get_imports() {
900
950
  return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
901
951
  },
902
952
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
903
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 211, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
953
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 220, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
904
954
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_6b82e471f4a4091b___convert__closures_____invoke___wasm_bindgen_6b82e471f4a4091b___JsValue______true_);
905
955
  return ret;
906
956
  },
907
957
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
908
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 331, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
958
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 340, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
909
959
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_6b82e471f4a4091b___convert__closures_____invoke___wasm_bindgen_6b82e471f4a4091b___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_6b82e471f4a4091b___JsError___true_);
910
960
  return ret;
911
961
  },
912
962
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
913
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 176, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
963
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 185, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
914
964
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_6b82e471f4a4091b___convert__closures_____invoke_______true_);
915
965
  return ret;
916
966
  },
Binary file