@gjsify/fetch 0.0.4 → 0.1.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 (88) hide show
  1. package/README.md +27 -2
  2. package/globals.mjs +12 -0
  3. package/lib/body.d.ts +69 -0
  4. package/lib/body.js +375 -0
  5. package/lib/errors/abort-error.d.ts +7 -0
  6. package/lib/errors/abort-error.js +9 -0
  7. package/lib/errors/base.d.ts +6 -0
  8. package/lib/errors/base.js +17 -0
  9. package/lib/errors/fetch-error.d.ts +16 -0
  10. package/lib/errors/fetch-error.js +23 -0
  11. package/lib/esm/body.js +104 -56
  12. package/lib/esm/errors/base.js +3 -1
  13. package/lib/esm/headers.js +116 -131
  14. package/lib/esm/index.js +145 -190
  15. package/lib/esm/request.js +42 -41
  16. package/lib/esm/response.js +19 -4
  17. package/lib/esm/utils/blob-from.js +2 -98
  18. package/lib/esm/utils/data-uri.js +23 -0
  19. package/lib/esm/utils/is.js +7 -3
  20. package/lib/esm/utils/multipart-parser.js +5 -2
  21. package/lib/esm/utils/referrer.js +10 -10
  22. package/lib/esm/utils/soup-helpers.js +22 -0
  23. package/lib/headers.d.ts +33 -0
  24. package/lib/headers.js +195 -0
  25. package/lib/index.d.ts +18 -0
  26. package/lib/index.js +205 -0
  27. package/lib/request.d.ts +101 -0
  28. package/lib/request.js +308 -0
  29. package/lib/response.d.ts +73 -0
  30. package/lib/response.js +158 -0
  31. package/lib/types/index.d.ts +1 -0
  32. package/lib/types/index.js +1 -0
  33. package/lib/types/system-error.d.ts +11 -0
  34. package/lib/types/system-error.js +2 -0
  35. package/lib/utils/blob-from.d.ts +2 -0
  36. package/lib/utils/blob-from.js +4 -0
  37. package/lib/utils/data-uri.d.ts +10 -0
  38. package/lib/utils/data-uri.js +27 -0
  39. package/lib/utils/get-search.d.ts +1 -0
  40. package/lib/utils/get-search.js +8 -0
  41. package/lib/utils/is-redirect.d.ts +7 -0
  42. package/lib/utils/is-redirect.js +10 -0
  43. package/lib/utils/is.d.ts +35 -0
  44. package/lib/utils/is.js +74 -0
  45. package/lib/utils/multipart-parser.d.ts +2 -0
  46. package/lib/utils/multipart-parser.js +396 -0
  47. package/lib/utils/referrer.d.ts +76 -0
  48. package/lib/utils/referrer.js +283 -0
  49. package/lib/utils/soup-helpers.d.ts +12 -0
  50. package/lib/utils/soup-helpers.js +25 -0
  51. package/package.json +23 -27
  52. package/src/body.ts +181 -169
  53. package/src/errors/base.ts +3 -1
  54. package/src/headers.ts +155 -202
  55. package/src/index.spec.ts +268 -3
  56. package/src/index.ts +199 -312
  57. package/src/request.ts +84 -75
  58. package/src/response.ts +48 -18
  59. package/src/test.mts +1 -1
  60. package/src/utils/blob-from.ts +4 -164
  61. package/src/utils/data-uri.ts +29 -0
  62. package/src/utils/is.ts +15 -15
  63. package/src/utils/multipart-parser.ts +3 -3
  64. package/src/utils/referrer.ts +11 -11
  65. package/src/utils/soup-helpers.ts +37 -0
  66. package/tsconfig.json +4 -4
  67. package/tsconfig.tsbuildinfo +1 -0
  68. package/lib/cjs/body.js +0 -255
  69. package/lib/cjs/errors/abort-error.js +0 -9
  70. package/lib/cjs/errors/base.js +0 -17
  71. package/lib/cjs/errors/fetch-error.js +0 -21
  72. package/lib/cjs/headers.js +0 -202
  73. package/lib/cjs/index.js +0 -224
  74. package/lib/cjs/request.js +0 -281
  75. package/lib/cjs/response.js +0 -133
  76. package/lib/cjs/types/index.js +0 -1
  77. package/lib/cjs/types/system-error.js +0 -1
  78. package/lib/cjs/utils/blob-from.js +0 -101
  79. package/lib/cjs/utils/get-search.js +0 -11
  80. package/lib/cjs/utils/is-redirect.js +0 -7
  81. package/lib/cjs/utils/is.js +0 -28
  82. package/lib/cjs/utils/multipart-parser.js +0 -353
  83. package/lib/cjs/utils/referrer.js +0 -153
  84. package/test.gjs.js +0 -34758
  85. package/test.gjs.mjs +0 -53172
  86. package/test.node.js +0 -1226
  87. package/test.node.mjs +0 -6273
  88. package/tsconfig.types.json +0 -8
@@ -1,101 +1,5 @@
1
- import { DOMException } from "@gjsify/deno-runtime/ext/web/01_dom_exception";
2
- import { Blob, File } from "@gjsify/deno-runtime/ext/web/09_file";
3
- import {
4
- realpathSync,
5
- statSync,
6
- rmdirSync,
7
- createReadStream,
8
- promises as fs
9
- } from "node:fs";
10
- import { basename, sep, join } from "node:path";
11
- import { tmpdir } from "node:os";
12
- import process from "node:process";
13
- const { stat, mkdtemp } = fs;
14
- let i = 0, tempDir, registry;
15
- const blobFromSync = (path, type) => fromBlob(statSync(path), path, type);
16
- const blobFrom = (path, type) => stat(path).then((stat2) => fromBlob(stat2, path, type));
17
- const fileFrom = (path, type) => stat(path).then((stat2) => fromFile(stat2, path, type));
18
- const fileFromSync = (path, type) => fromFile(statSync(path), path, type);
19
- const fromBlob = (stat2, path, type = "") => new Blob([new BlobDataItem({
20
- path,
21
- size: stat2.size,
22
- lastModified: stat2.mtimeMs,
23
- start: 0
24
- })], { type });
25
- const fromFile = (stat2, path, type = "") => new File([new BlobDataItem({
26
- path,
27
- size: stat2.size,
28
- lastModified: stat2.mtimeMs,
29
- start: 0
30
- })], basename(path), { type, lastModified: stat2.mtimeMs });
31
- const createTemporaryBlob = async (data, { signal, type } = {}) => {
32
- registry = registry || new FinalizationRegistry(fs.unlink);
33
- tempDir = tempDir || await mkdtemp(realpathSync(tmpdir()) + sep);
34
- const id = `${i++}`;
35
- const destination = join(tempDir, id);
36
- if (data instanceof ArrayBuffer)
37
- data = new Uint8Array(data);
38
- await fs.writeFile(destination, data, { signal });
39
- const blob = await blobFrom(destination, type);
40
- registry.register(blob, destination);
41
- return blob;
42
- };
43
- const createTemporaryFile = async (data, name, opts) => {
44
- const blob = await createTemporaryBlob(data);
45
- return new File([blob], name, opts);
46
- };
47
- class BlobDataItem {
48
- #path;
49
- #start;
50
- size;
51
- lastModified;
52
- originalSize;
53
- constructor(options) {
54
- this.#path = options.path;
55
- this.#start = options.start;
56
- this.size = options.size;
57
- this.lastModified = options.lastModified;
58
- this.originalSize = options.originalSize === void 0 ? options.size : options.originalSize;
59
- }
60
- /**
61
- * Slicing arguments is first validated and formatted
62
- * to not be out of range by Blob.prototype.slice
63
- */
64
- slice(start, end) {
65
- return new BlobDataItem({
66
- path: this.#path,
67
- lastModified: this.lastModified,
68
- originalSize: this.originalSize,
69
- size: end - start,
70
- start: this.#start + start
71
- });
72
- }
73
- async *stream() {
74
- const { mtimeMs, size } = await stat(this.#path);
75
- if (mtimeMs > this.lastModified || this.originalSize !== size) {
76
- throw new DOMException("The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.", "NotReadableError");
77
- }
78
- yield* createReadStream(this.#path, {
79
- start: this.#start,
80
- end: this.#start + this.size - 1
81
- });
82
- }
83
- get [Symbol.toStringTag]() {
84
- return "Blob";
85
- }
86
- }
87
- process.once("exit", () => {
88
- tempDir && rmdirSync(tempDir, { recursive: true });
89
- });
90
- var blob_from_default = blobFromSync;
1
+ import { Blob, File } from "node:buffer";
91
2
  export {
92
3
  Blob,
93
- File,
94
- blobFrom,
95
- blobFromSync,
96
- createTemporaryBlob,
97
- createTemporaryFile,
98
- blob_from_default as default,
99
- fileFrom,
100
- fileFromSync
4
+ File
101
5
  };
@@ -0,0 +1,23 @@
1
+ function parseDataUri(uri) {
2
+ const match = uri.match(/^data:([^,]*?)(;base64)?,(.*)$/s);
3
+ if (!match) {
4
+ throw new TypeError(`Invalid data URI: ${uri.slice(0, 50)}...`);
5
+ }
6
+ const typeFull = match[1] || "text/plain;charset=US-ASCII";
7
+ const isBase64 = !!match[2];
8
+ const data = match[3];
9
+ let buffer;
10
+ if (isBase64) {
11
+ const binaryString = atob(data);
12
+ buffer = new Uint8Array(binaryString.length);
13
+ for (let i = 0; i < binaryString.length; i++) {
14
+ buffer[i] = binaryString.charCodeAt(i);
15
+ }
16
+ } else {
17
+ buffer = new TextEncoder().encode(decodeURIComponent(data));
18
+ }
19
+ return { buffer, typeFull };
20
+ }
21
+ export {
22
+ parseDataUri
23
+ };
@@ -1,13 +1,17 @@
1
- import { URL } from "@gjsify/deno-runtime/ext/url/00_url";
1
+ import { URL } from "@gjsify/url";
2
2
  const NAME = Symbol.toStringTag;
3
3
  const isURLSearchParameters = (object) => {
4
4
  return typeof object === "object" && typeof object.append === "function" && typeof object.delete === "function" && typeof object.get === "function" && typeof object.getAll === "function" && typeof object.has === "function" && typeof object.set === "function" && typeof object.sort === "function" && object[NAME] === "URLSearchParams";
5
5
  };
6
6
  const isBlob = (value) => {
7
- return value && typeof value === "object" && typeof value.arrayBuffer === "function" && typeof value.type === "string" && typeof value.stream === "function" && typeof value.constructor === "function" && /^(Blob|File)$/.test(value[NAME]);
7
+ if (!value || typeof value !== "object") return false;
8
+ const obj = value;
9
+ return typeof obj.arrayBuffer === "function" && typeof obj.type === "string" && typeof obj.stream === "function" && typeof obj.constructor === "function" && /^(Blob|File)$/.test(obj[NAME]);
8
10
  };
9
11
  const isAbortSignal = (object) => {
10
- return typeof object === "object" && (object[NAME] === "AbortSignal" || object[NAME] === "EventTarget");
12
+ if (typeof object !== "object" || object === null) return false;
13
+ const obj = object;
14
+ return obj[NAME] === "AbortSignal" || obj[NAME] === "EventTarget";
11
15
  };
12
16
  const isDomainOrSubdomain = (destination, original) => {
13
17
  const orig = new URL(original).hostname;
@@ -1,5 +1,5 @@
1
1
  import { File } from "./blob-from.js";
2
- import { FormData } from "formdata-polyfill/esm.min.js";
2
+ import { FormData } from "@gjsify/formdata";
3
3
  var S = /* @__PURE__ */ ((S2) => {
4
4
  S2[S2["START_BOUNDARY"] = 0] = "START_BOUNDARY";
5
5
  S2[S2["HEADER_FIELD_START"] = 1] = "HEADER_FIELD_START";
@@ -26,7 +26,7 @@ const COLON = 58;
26
26
  const A = 97;
27
27
  const Z = 122;
28
28
  const lower = (c) => c | 32;
29
- const noop = (...args) => {
29
+ const noop = (..._args) => {
30
30
  };
31
31
  class MultipartParser {
32
32
  index = 0;
@@ -128,6 +128,7 @@ class MultipartParser {
128
128
  state = 2 /* HEADER_FIELD */;
129
129
  mark("onHeaderField");
130
130
  index = 0;
131
+ // falls through
131
132
  case 2 /* HEADER_FIELD */:
132
133
  if (c === CR) {
133
134
  clear("onHeaderField");
@@ -157,6 +158,7 @@ class MultipartParser {
157
158
  }
158
159
  mark("onHeaderValue");
159
160
  state = 4 /* HEADER_VALUE */;
161
+ // falls through
160
162
  case 4 /* HEADER_VALUE */:
161
163
  if (c === CR) {
162
164
  dataCallback("onHeaderValue", true);
@@ -180,6 +182,7 @@ class MultipartParser {
180
182
  case 7 /* PART_DATA_START */:
181
183
  state = 8 /* PART_DATA */;
182
184
  mark("onPartData");
185
+ // falls through
183
186
  case 8 /* PART_DATA */:
184
187
  previousIndex = index;
185
188
  if (index === 0) {
@@ -1,21 +1,21 @@
1
- import { URL } from "@gjsify/deno-runtime/ext/url/00_url";
2
- import { isIP } from "net";
1
+ import { URL } from "@gjsify/url";
2
+ import { isIP } from "node:net";
3
3
  function stripURLForUseAsAReferrer(url, originOnly = false) {
4
4
  if (url == null || url === "no-referrer") {
5
5
  return "no-referrer";
6
6
  }
7
- url = new URL(url);
8
- if (/^(about|blob|data):$/.test(url.protocol)) {
7
+ const u = new URL(url);
8
+ if (/^(about|blob|data):$/.test(u.protocol)) {
9
9
  return "no-referrer";
10
10
  }
11
- url.username = "";
12
- url.password = "";
13
- url.hash = "";
11
+ u.username = "";
12
+ u.password = "";
13
+ u.hash = "";
14
14
  if (originOnly) {
15
- url.pathname = "";
16
- url.search = "";
15
+ u.pathname = "";
16
+ u.search = "";
17
17
  }
18
- return url;
18
+ return u;
19
19
  }
20
20
  const ReferrerPolicy = /* @__PURE__ */ new Set([
21
21
  "",
@@ -0,0 +1,22 @@
1
+ import GLib from "@girs/glib-2.0";
2
+ import { Readable } from "node:stream";
3
+ import { inputStreamAsyncIterator } from "@gjsify/utils";
4
+ async function soupSendAsync(session, msg, ioPriority = GLib.PRIORITY_DEFAULT, cancellable = null) {
5
+ return new Promise((resolve, reject) => {
6
+ session.send_async(msg, ioPriority, cancellable, (_self, asyncRes) => {
7
+ try {
8
+ const inputStream = session.send_finish(asyncRes);
9
+ resolve(inputStream);
10
+ } catch (error) {
11
+ reject(error);
12
+ }
13
+ });
14
+ });
15
+ }
16
+ function inputStreamToReadable(inputStream, options = {}) {
17
+ return Readable.from(inputStreamAsyncIterator(inputStream), options);
18
+ }
19
+ export {
20
+ inputStreamToReadable,
21
+ soupSendAsync
22
+ };
@@ -0,0 +1,33 @@
1
+ import Soup from '@girs/soup-3.0';
2
+ declare const _headers: unique symbol;
3
+ export default class Headers implements Iterable<[string, string]> {
4
+ [_headers]: Map<string, string[]>;
5
+ constructor(init?: HeadersInit | Headers | null);
6
+ append(name: string, value: string): void;
7
+ set(name: string, value: string): void;
8
+ delete(name: string): void;
9
+ has(name: string): boolean;
10
+ get(name: string): string | null;
11
+ getAll(name: string): string[];
12
+ getSetCookie(): string[];
13
+ forEach(callback: (value: string, name: string, parent: Headers) => void, thisArg?: unknown): void;
14
+ keys(): IterableIterator<string>;
15
+ values(): IterableIterator<string>;
16
+ entries(): IterableIterator<[string, string]>;
17
+ [Symbol.iterator](): IterableIterator<[string, string]>;
18
+ get [Symbol.toStringTag](): string;
19
+ toString(): string;
20
+ /**
21
+ * Node-fetch non-spec method: return all headers and their values as arrays.
22
+ */
23
+ raw(): Record<string, string[]>;
24
+ /**
25
+ * Append all headers to a Soup.Message for sending.
26
+ */
27
+ _appendToSoupMessage(message?: Soup.Message, type?: Soup.MessageHeadersType): Soup.MessageHeaders;
28
+ /**
29
+ * Create a Headers instance from a Soup.Message's headers.
30
+ */
31
+ static _newFromSoupMessage(message: Soup.Message, type?: Soup.MessageHeadersType): Headers;
32
+ }
33
+ export {};
package/lib/headers.js ADDED
@@ -0,0 +1,195 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Adapted from node-fetch (https://github.com/node-fetch/node-fetch/blob/main/src/headers.js)
3
+ // Copyright (c) node-fetch contributors. MIT license.
4
+ // Modifications: Standalone implementation using internal Map, libsoup integration
5
+ import Soup from '@girs/soup-3.0';
6
+ import { validateHeaderName, validateHeaderValue } from '@gjsify/http';
7
+ const _headers = Symbol('Headers.headers');
8
+ function isBoxedPrimitive(val) {
9
+ return (val instanceof String ||
10
+ val instanceof Number ||
11
+ val instanceof Boolean ||
12
+ (typeof Symbol !== 'undefined' && val instanceof Symbol) ||
13
+ (typeof BigInt !== 'undefined' && val instanceof BigInt));
14
+ }
15
+ export default class Headers {
16
+ [_headers];
17
+ constructor(init) {
18
+ this[_headers] = new Map();
19
+ if (init == null) {
20
+ return;
21
+ }
22
+ if (init instanceof Headers) {
23
+ for (const [name, values] of init[_headers]) {
24
+ this[_headers].set(name, [...values]);
25
+ }
26
+ return;
27
+ }
28
+ if (typeof init === 'object' && !isBoxedPrimitive(init)) {
29
+ const method = init[Symbol.iterator];
30
+ if (method == null) {
31
+ // Record<string, string>
32
+ for (const [name, value] of Object.entries(init)) {
33
+ validateHeaderName(name);
34
+ validateHeaderValue(name, String(value));
35
+ this.append(name, String(value));
36
+ }
37
+ }
38
+ else {
39
+ if (typeof method !== 'function') {
40
+ throw new TypeError('Header pairs must be iterable');
41
+ }
42
+ for (const pair of init) {
43
+ if (typeof pair !== 'object' || isBoxedPrimitive(pair)) {
44
+ throw new TypeError('Each header pair must be an iterable object');
45
+ }
46
+ const arr = [...pair];
47
+ if (arr.length !== 2) {
48
+ throw new TypeError('Each header pair must be a name/value tuple');
49
+ }
50
+ validateHeaderName(arr[0]);
51
+ validateHeaderValue(arr[0], String(arr[1]));
52
+ this.append(arr[0], String(arr[1]));
53
+ }
54
+ }
55
+ }
56
+ else {
57
+ throw new TypeError('Failed to construct \'Headers\': The provided value is not of type ' +
58
+ '\'(sequence<sequence<ByteString>> or record<ByteString, ByteString>)\'');
59
+ }
60
+ }
61
+ append(name, value) {
62
+ validateHeaderName(name);
63
+ validateHeaderValue(name, value);
64
+ const lowerName = String(name).toLowerCase();
65
+ const strValue = String(value);
66
+ const existing = this[_headers].get(lowerName);
67
+ if (existing) {
68
+ existing.push(strValue);
69
+ }
70
+ else {
71
+ this[_headers].set(lowerName, [strValue]);
72
+ }
73
+ }
74
+ set(name, value) {
75
+ validateHeaderName(name);
76
+ validateHeaderValue(name, value);
77
+ const lowerName = String(name).toLowerCase();
78
+ this[_headers].set(lowerName, [String(value)]);
79
+ }
80
+ delete(name) {
81
+ this[_headers].delete(String(name).toLowerCase());
82
+ }
83
+ has(name) {
84
+ return this[_headers].has(String(name).toLowerCase());
85
+ }
86
+ get(name) {
87
+ const values = this[_headers].get(String(name).toLowerCase());
88
+ if (!values || values.length === 0) {
89
+ return null;
90
+ }
91
+ let value = values.join(', ');
92
+ if (/^content-encoding$/i.test(name)) {
93
+ value = value.toLowerCase();
94
+ }
95
+ return value;
96
+ }
97
+ getAll(name) {
98
+ return this[_headers].get(String(name).toLowerCase()) ?? [];
99
+ }
100
+ getSetCookie() {
101
+ return this[_headers].get('set-cookie') ?? [];
102
+ }
103
+ forEach(callback, thisArg) {
104
+ for (const name of this.keys()) {
105
+ Reflect.apply(callback, thisArg, [this.get(name), name, this]);
106
+ }
107
+ }
108
+ *keys() {
109
+ const sorted = [...this[_headers].keys()].sort();
110
+ const seen = new Set();
111
+ for (const key of sorted) {
112
+ if (!seen.has(key)) {
113
+ seen.add(key);
114
+ yield key;
115
+ }
116
+ }
117
+ }
118
+ *values() {
119
+ for (const name of this.keys()) {
120
+ yield this.get(name);
121
+ }
122
+ }
123
+ *entries() {
124
+ for (const name of this.keys()) {
125
+ yield [name, this.get(name)];
126
+ }
127
+ }
128
+ [Symbol.iterator]() {
129
+ return this.entries();
130
+ }
131
+ get [Symbol.toStringTag]() {
132
+ return 'Headers';
133
+ }
134
+ toString() {
135
+ return Object.prototype.toString.call(this);
136
+ }
137
+ /**
138
+ * Node-fetch non-spec method: return all headers and their values as arrays.
139
+ */
140
+ raw() {
141
+ const result = {};
142
+ for (const name of this.keys()) {
143
+ result[name] = this.getAll(name);
144
+ }
145
+ return result;
146
+ }
147
+ /**
148
+ * Append all headers to a Soup.Message for sending.
149
+ */
150
+ _appendToSoupMessage(message, type = Soup.MessageHeadersType.REQUEST) {
151
+ const soupHeaders = message ? message.get_request_headers() : new Soup.MessageHeaders(type);
152
+ for (const [name, value] of this.entries()) {
153
+ soupHeaders.append(name, value);
154
+ }
155
+ return soupHeaders;
156
+ }
157
+ /**
158
+ * Create a Headers instance from a Soup.Message's headers.
159
+ */
160
+ static _newFromSoupMessage(message, type = Soup.MessageHeadersType.RESPONSE) {
161
+ const headers = new Headers();
162
+ let soupHeaders;
163
+ if (type === Soup.MessageHeadersType.RESPONSE) {
164
+ soupHeaders = message.get_response_headers();
165
+ }
166
+ else {
167
+ soupHeaders = message.get_request_headers();
168
+ }
169
+ // Soup.MessageHeaders.foreach iterates all header name/value pairs
170
+ soupHeaders.foreach((name, value) => {
171
+ headers.append(name, value);
172
+ });
173
+ return headers;
174
+ }
175
+ /**
176
+ * For better console.log(headers)
177
+ */
178
+ [Symbol.for('nodejs.util.inspect.custom')]() {
179
+ const result = {};
180
+ for (const key of this.keys()) {
181
+ const values = this.getAll(key);
182
+ if (key === 'host') {
183
+ result[key] = values[0];
184
+ }
185
+ else {
186
+ result[key] = values.length > 1 ? values : values[0];
187
+ }
188
+ }
189
+ return result;
190
+ }
191
+ }
192
+ Object.defineProperties(Headers.prototype, ['get', 'entries', 'forEach', 'values'].reduce((result, property) => {
193
+ result[property] = { enumerable: true };
194
+ return result;
195
+ }, {}));
package/lib/index.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import Response from './response.js';
2
+ import Headers from './headers.js';
3
+ import Request from './request.js';
4
+ import { FetchError } from './errors/fetch-error.js';
5
+ import { AbortError } from './errors/abort-error.js';
6
+ import { isRedirect } from './utils/is-redirect.js';
7
+ import { FormData } from '@gjsify/formdata';
8
+ import { Blob, File } from './utils/blob-from.js';
9
+ import { URL } from '@gjsify/url';
10
+ export { FormData, Headers, Request, Response, FetchError, AbortError, isRedirect };
11
+ export { Blob, File };
12
+ /**
13
+ * Fetch function
14
+ *
15
+ * @param url Absolute url or Request instance
16
+ * @param init Fetch options
17
+ */
18
+ export default function fetch(url: RequestInfo | URL | Request, init?: RequestInit): Promise<Response>;