@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.
- package/README.md +27 -2
- package/globals.mjs +12 -0
- package/lib/body.d.ts +69 -0
- package/lib/body.js +375 -0
- package/lib/errors/abort-error.d.ts +7 -0
- package/lib/errors/abort-error.js +9 -0
- package/lib/errors/base.d.ts +6 -0
- package/lib/errors/base.js +17 -0
- package/lib/errors/fetch-error.d.ts +16 -0
- package/lib/errors/fetch-error.js +23 -0
- package/lib/esm/body.js +104 -56
- package/lib/esm/errors/base.js +3 -1
- package/lib/esm/headers.js +116 -131
- package/lib/esm/index.js +145 -190
- package/lib/esm/request.js +42 -41
- package/lib/esm/response.js +19 -4
- package/lib/esm/utils/blob-from.js +2 -98
- package/lib/esm/utils/data-uri.js +23 -0
- package/lib/esm/utils/is.js +7 -3
- package/lib/esm/utils/multipart-parser.js +5 -2
- package/lib/esm/utils/referrer.js +10 -10
- package/lib/esm/utils/soup-helpers.js +22 -0
- package/lib/headers.d.ts +33 -0
- package/lib/headers.js +195 -0
- package/lib/index.d.ts +18 -0
- package/lib/index.js +205 -0
- package/lib/request.d.ts +101 -0
- package/lib/request.js +308 -0
- package/lib/response.d.ts +73 -0
- package/lib/response.js +158 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +1 -0
- package/lib/types/system-error.d.ts +11 -0
- package/lib/types/system-error.js +2 -0
- package/lib/utils/blob-from.d.ts +2 -0
- package/lib/utils/blob-from.js +4 -0
- package/lib/utils/data-uri.d.ts +10 -0
- package/lib/utils/data-uri.js +27 -0
- package/lib/utils/get-search.d.ts +1 -0
- package/lib/utils/get-search.js +8 -0
- package/lib/utils/is-redirect.d.ts +7 -0
- package/lib/utils/is-redirect.js +10 -0
- package/lib/utils/is.d.ts +35 -0
- package/lib/utils/is.js +74 -0
- package/lib/utils/multipart-parser.d.ts +2 -0
- package/lib/utils/multipart-parser.js +396 -0
- package/lib/utils/referrer.d.ts +76 -0
- package/lib/utils/referrer.js +283 -0
- package/lib/utils/soup-helpers.d.ts +12 -0
- package/lib/utils/soup-helpers.js +25 -0
- package/package.json +23 -27
- package/src/body.ts +181 -169
- package/src/errors/base.ts +3 -1
- package/src/headers.ts +155 -202
- package/src/index.spec.ts +268 -3
- package/src/index.ts +199 -312
- package/src/request.ts +84 -75
- package/src/response.ts +48 -18
- package/src/test.mts +1 -1
- package/src/utils/blob-from.ts +4 -164
- package/src/utils/data-uri.ts +29 -0
- package/src/utils/is.ts +15 -15
- package/src/utils/multipart-parser.ts +3 -3
- package/src/utils/referrer.ts +11 -11
- package/src/utils/soup-helpers.ts +37 -0
- package/tsconfig.json +4 -4
- package/tsconfig.tsbuildinfo +1 -0
- package/lib/cjs/body.js +0 -255
- package/lib/cjs/errors/abort-error.js +0 -9
- package/lib/cjs/errors/base.js +0 -17
- package/lib/cjs/errors/fetch-error.js +0 -21
- package/lib/cjs/headers.js +0 -202
- package/lib/cjs/index.js +0 -224
- package/lib/cjs/request.js +0 -281
- package/lib/cjs/response.js +0 -133
- package/lib/cjs/types/index.js +0 -1
- package/lib/cjs/types/system-error.js +0 -1
- package/lib/cjs/utils/blob-from.js +0 -101
- package/lib/cjs/utils/get-search.js +0 -11
- package/lib/cjs/utils/is-redirect.js +0 -7
- package/lib/cjs/utils/is.js +0 -28
- package/lib/cjs/utils/multipart-parser.js +0 -353
- package/lib/cjs/utils/referrer.js +0 -153
- package/test.gjs.js +0 -34758
- package/test.gjs.mjs +0 -53172
- package/test.node.js +0 -1226
- package/test.node.mjs +0 -6273
- package/tsconfig.types.json +0 -8
|
@@ -1,101 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
+
};
|
package/lib/esm/utils/is.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { URL } from "@gjsify/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 = (...
|
|
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/
|
|
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
|
-
|
|
8
|
-
if (/^(about|blob|data):$/.test(
|
|
7
|
+
const u = new URL(url);
|
|
8
|
+
if (/^(about|blob|data):$/.test(u.protocol)) {
|
|
9
9
|
return "no-referrer";
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
u.username = "";
|
|
12
|
+
u.password = "";
|
|
13
|
+
u.hash = "";
|
|
14
14
|
if (originOnly) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
u.pathname = "";
|
|
16
|
+
u.search = "";
|
|
17
17
|
}
|
|
18
|
-
return
|
|
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
|
+
};
|
package/lib/headers.d.ts
ADDED
|
@@ -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>;
|