@gjsify/fetch 0.0.4 → 0.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 +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
package/src/headers.ts
CHANGED
|
@@ -1,176 +1,108 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*/
|
|
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
|
|
6
5
|
|
|
7
6
|
import Soup from '@girs/soup-3.0';
|
|
8
|
-
import {
|
|
7
|
+
import { validateHeaderName, validateHeaderValue } from '@gjsify/http';
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
import * as http from 'http';
|
|
12
|
-
import type { IncomingMessage } from 'http';
|
|
9
|
+
const _headers = Symbol('Headers.headers');
|
|
13
10
|
|
|
11
|
+
function isBoxedPrimitive(val: unknown): boolean {
|
|
12
|
+
return (
|
|
13
|
+
val instanceof String ||
|
|
14
|
+
val instanceof Number ||
|
|
15
|
+
val instanceof Boolean ||
|
|
16
|
+
(typeof Symbol !== 'undefined' && val instanceof Symbol) ||
|
|
17
|
+
(typeof BigInt !== 'undefined' && val instanceof (BigInt as unknown as typeof Number))
|
|
18
|
+
);
|
|
19
|
+
}
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
export default class Headers implements Iterable<[string, string]> {
|
|
22
|
+
[_headers]: Map<string, string[]>;
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
constructor(init?: HeadersInit | Headers | null) {
|
|
25
|
+
this[_headers] = new Map();
|
|
26
|
+
|
|
27
|
+
if (init == null) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
19
30
|
|
|
20
|
-
/**
|
|
21
|
-
* This Fetch API interface allows you to perform various actions on HTTP request and response headers.
|
|
22
|
-
* These actions include retrieving, setting, adding to, and removing.
|
|
23
|
-
* A Headers object has an associated header list, which is initially empty and consists of zero or more name and value pairs.
|
|
24
|
-
* You can add to this using methods like append() (see Examples.)
|
|
25
|
-
* In all methods of this interface, header names are matched by case-insensitive byte sequence.
|
|
26
|
-
*
|
|
27
|
-
*/
|
|
28
|
-
export default class Headers extends URLSearchParams implements globalThis.Headers, Iterable<[string, string]> {
|
|
29
|
-
/**
|
|
30
|
-
* Headers class
|
|
31
|
-
*
|
|
32
|
-
* @constructor
|
|
33
|
-
* @param init Response headers
|
|
34
|
-
*/
|
|
35
|
-
constructor(init?: HeadersInit) {
|
|
36
|
-
// Validate and normalize init object in [name, value(s)][]
|
|
37
|
-
let result: string[][] = [];
|
|
38
31
|
if (init instanceof Headers) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
result.push(...values.map(value => [name, value]));
|
|
32
|
+
for (const [name, values] of init[_headers]) {
|
|
33
|
+
this[_headers].set(name, [...values]);
|
|
42
34
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (typeof init === 'object' && !isBoxedPrimitive(init)) {
|
|
39
|
+
const method = (init as Iterable<string[]>)[Symbol.iterator];
|
|
48
40
|
if (method == null) {
|
|
49
|
-
// Record<
|
|
50
|
-
|
|
41
|
+
// Record<string, string>
|
|
42
|
+
for (const [name, value] of Object.entries(init)) {
|
|
43
|
+
validateHeaderName(name);
|
|
44
|
+
validateHeaderValue(name, String(value));
|
|
45
|
+
this.append(name, String(value));
|
|
46
|
+
}
|
|
51
47
|
} else {
|
|
52
48
|
if (typeof method !== 'function') {
|
|
53
49
|
throw new TypeError('Header pairs must be iterable');
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (
|
|
61
|
-
typeof pair !== 'object' || types.isBoxedPrimitive(pair)
|
|
62
|
-
) {
|
|
63
|
-
throw new TypeError('Each header pair must be an iterable object');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return [...pair];
|
|
67
|
-
}).map(pair => {
|
|
68
|
-
if (pair.length !== 2) {
|
|
69
|
-
throw new TypeError('Each header pair must be a name/value tuple');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return [...pair];
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
throw new TypeError('Failed to construct \'Headers\': The provided value is not of type \'(sequence<sequence<ByteString>> or record<ByteString, ByteString>)');
|
|
77
|
-
}
|
|
52
|
+
for (const pair of init as Iterable<string[]>) {
|
|
53
|
+
if (typeof pair !== 'object' || isBoxedPrimitive(pair)) {
|
|
54
|
+
throw new TypeError('Each header pair must be an iterable object');
|
|
55
|
+
}
|
|
78
56
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
undefined;
|
|
88
|
-
|
|
89
|
-
super(result);
|
|
90
|
-
|
|
91
|
-
// Returning a Proxy that will lowercase key names, validate parameters and sort keys
|
|
92
|
-
// eslint-disable-next-line no-constructor-return
|
|
93
|
-
return new Proxy(this, {
|
|
94
|
-
get(target, p, receiver) {
|
|
95
|
-
switch (p) {
|
|
96
|
-
case 'append':
|
|
97
|
-
case 'set':
|
|
98
|
-
return (name: string, value: any) => {
|
|
99
|
-
validateHeaderName(name);
|
|
100
|
-
validateHeaderValue(name, String(value));
|
|
101
|
-
return URLSearchParams.prototype[p].call(
|
|
102
|
-
target,
|
|
103
|
-
String(name).toLowerCase(),
|
|
104
|
-
String(value)
|
|
105
|
-
);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
case 'delete':
|
|
109
|
-
case 'has':
|
|
110
|
-
case 'getAll':
|
|
111
|
-
return (name: string) => {
|
|
112
|
-
validateHeaderName(name);
|
|
113
|
-
return URLSearchParams.prototype[p].call(
|
|
114
|
-
target,
|
|
115
|
-
String(name).toLowerCase()
|
|
116
|
-
);
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
case 'keys':
|
|
120
|
-
return () => {
|
|
121
|
-
target.sort();
|
|
122
|
-
return new Set(URLSearchParams.prototype.keys.call(target)).keys();
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
default:
|
|
126
|
-
return Reflect.get(target, p, receiver);
|
|
57
|
+
const arr = [...pair];
|
|
58
|
+
if (arr.length !== 2) {
|
|
59
|
+
throw new TypeError('Each header pair must be a name/value tuple');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
validateHeaderName(arr[0]);
|
|
63
|
+
validateHeaderValue(arr[0], String(arr[1]));
|
|
64
|
+
this.append(arr[0], String(arr[1]));
|
|
127
65
|
}
|
|
128
66
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
67
|
+
} else {
|
|
68
|
+
throw new TypeError(
|
|
69
|
+
'Failed to construct \'Headers\': The provided value is not of type ' +
|
|
70
|
+
'\'(sequence<sequence<ByteString>> or record<ByteString, ByteString>)\''
|
|
71
|
+
);
|
|
72
|
+
}
|
|
131
73
|
}
|
|
132
74
|
|
|
133
|
-
|
|
134
|
-
|
|
75
|
+
append(name: string, value: string): void {
|
|
76
|
+
validateHeaderName(name);
|
|
77
|
+
validateHeaderValue(name, value);
|
|
78
|
+
const lowerName = String(name).toLowerCase();
|
|
79
|
+
const strValue = String(value);
|
|
80
|
+
const existing = this[_headers].get(lowerName);
|
|
81
|
+
if (existing) {
|
|
82
|
+
existing.push(strValue);
|
|
83
|
+
} else {
|
|
84
|
+
this[_headers].set(lowerName, [strValue]);
|
|
85
|
+
}
|
|
135
86
|
}
|
|
136
87
|
|
|
137
|
-
|
|
138
|
-
|
|
88
|
+
set(name: string, value: string): void {
|
|
89
|
+
validateHeaderName(name);
|
|
90
|
+
validateHeaderValue(name, value);
|
|
91
|
+
const lowerName = String(name).toLowerCase();
|
|
92
|
+
this[_headers].set(lowerName, [String(value)]);
|
|
139
93
|
}
|
|
140
94
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
for (const header in this.entries()) {
|
|
144
|
-
soupHeaders.append(header, this.get(header));
|
|
145
|
-
}
|
|
146
|
-
return soupHeaders;
|
|
95
|
+
delete(name: string): void {
|
|
96
|
+
this[_headers].delete(String(name).toLowerCase());
|
|
147
97
|
}
|
|
148
98
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
let soupHeaders: Soup.MessageHeaders;
|
|
152
|
-
const headers = new Headers();
|
|
153
|
-
|
|
154
|
-
if (type === Soup.MessageHeadersType.RESPONSE) {
|
|
155
|
-
soupHeaders = message.get_response_headers();
|
|
156
|
-
} else if(type === Soup.MessageHeadersType.REQUEST) {
|
|
157
|
-
soupHeaders = message.get_request_headers();
|
|
158
|
-
} else {
|
|
159
|
-
for (const header in message.get_request_headers()) {
|
|
160
|
-
headers.append(header, soupHeaders[header]);
|
|
161
|
-
}
|
|
162
|
-
soupHeaders = message.get_response_headers();
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
for (const header in soupHeaders) {
|
|
166
|
-
headers.append(header, soupHeaders[header]);
|
|
167
|
-
}
|
|
168
|
-
return headers;
|
|
99
|
+
has(name: string): boolean {
|
|
100
|
+
return this[_headers].has(String(name).toLowerCase());
|
|
169
101
|
}
|
|
170
102
|
|
|
171
|
-
get(name: string) {
|
|
172
|
-
const values = this.
|
|
173
|
-
if (values.length === 0) {
|
|
103
|
+
get(name: string): string | null {
|
|
104
|
+
const values = this[_headers].get(String(name).toLowerCase());
|
|
105
|
+
if (!values || values.length === 0) {
|
|
174
106
|
return null;
|
|
175
107
|
}
|
|
176
108
|
|
|
@@ -182,98 +114,119 @@ export default class Headers extends URLSearchParams implements globalThis.Heade
|
|
|
182
114
|
return value;
|
|
183
115
|
}
|
|
184
116
|
|
|
185
|
-
|
|
117
|
+
getAll(name: string): string[] {
|
|
118
|
+
return this[_headers].get(String(name).toLowerCase()) ?? [];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getSetCookie(): string[] {
|
|
122
|
+
return this[_headers].get('set-cookie') ?? [];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
forEach(callback: (value: string, name: string, parent: Headers) => void, thisArg?: unknown): void {
|
|
186
126
|
for (const name of this.keys()) {
|
|
187
127
|
Reflect.apply(callback, thisArg, [this.get(name), name, this]);
|
|
188
128
|
}
|
|
189
129
|
}
|
|
190
130
|
|
|
191
|
-
*
|
|
131
|
+
*keys(): IterableIterator<string> {
|
|
132
|
+
const sorted = [...this[_headers].keys()].sort();
|
|
133
|
+
const seen = new Set<string>();
|
|
134
|
+
for (const key of sorted) {
|
|
135
|
+
if (!seen.has(key)) {
|
|
136
|
+
seen.add(key);
|
|
137
|
+
yield key;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
*values(): IterableIterator<string> {
|
|
143
|
+
for (const name of this.keys()) {
|
|
144
|
+
yield this.get(name)!;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
*entries(): IterableIterator<[string, string]> {
|
|
192
149
|
for (const name of this.keys()) {
|
|
193
|
-
yield this.get(name);
|
|
150
|
+
yield [name, this.get(name)!];
|
|
194
151
|
}
|
|
195
152
|
}
|
|
196
153
|
|
|
154
|
+
[Symbol.iterator](): IterableIterator<[string, string]> {
|
|
155
|
+
return this.entries();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get [Symbol.toStringTag](): string {
|
|
159
|
+
return 'Headers';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
toString(): string {
|
|
163
|
+
return Object.prototype.toString.call(this);
|
|
164
|
+
}
|
|
165
|
+
|
|
197
166
|
/**
|
|
198
|
-
*
|
|
167
|
+
* Node-fetch non-spec method: return all headers and their values as arrays.
|
|
199
168
|
*/
|
|
200
|
-
|
|
169
|
+
raw(): Record<string, string[]> {
|
|
170
|
+
const result: Record<string, string[]> = {};
|
|
201
171
|
for (const name of this.keys()) {
|
|
202
|
-
|
|
172
|
+
result[name] = this.getAll(name);
|
|
203
173
|
}
|
|
174
|
+
return result;
|
|
204
175
|
}
|
|
205
176
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
177
|
+
/**
|
|
178
|
+
* Append all headers to a Soup.Message for sending.
|
|
179
|
+
*/
|
|
180
|
+
_appendToSoupMessage(message?: Soup.Message, type = Soup.MessageHeadersType.REQUEST): Soup.MessageHeaders {
|
|
181
|
+
const soupHeaders = message ? message.get_request_headers() : new Soup.MessageHeaders(type);
|
|
182
|
+
for (const [name, value] of this.entries()) {
|
|
183
|
+
soupHeaders.append(name, value);
|
|
184
|
+
}
|
|
185
|
+
return soupHeaders;
|
|
186
|
+
}
|
|
209
187
|
|
|
210
188
|
/**
|
|
211
|
-
*
|
|
212
|
-
* returning all headers and their values as array
|
|
189
|
+
* Create a Headers instance from a Soup.Message's headers.
|
|
213
190
|
*/
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
191
|
+
static _newFromSoupMessage(message: Soup.Message, type: Soup.MessageHeadersType = Soup.MessageHeadersType.RESPONSE): Headers {
|
|
192
|
+
const headers = new Headers();
|
|
193
|
+
let soupHeaders: Soup.MessageHeaders;
|
|
194
|
+
|
|
195
|
+
if (type === Soup.MessageHeadersType.RESPONSE) {
|
|
196
|
+
soupHeaders = message.get_response_headers();
|
|
197
|
+
} else {
|
|
198
|
+
soupHeaders = message.get_request_headers();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Soup.MessageHeaders.foreach iterates all header name/value pairs
|
|
202
|
+
soupHeaders.foreach((name: string, value: string) => {
|
|
203
|
+
headers.append(name, value);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
return headers;
|
|
219
207
|
}
|
|
220
208
|
|
|
221
209
|
/**
|
|
222
|
-
* For better console.log(headers)
|
|
210
|
+
* For better console.log(headers)
|
|
223
211
|
*/
|
|
224
212
|
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
225
|
-
|
|
213
|
+
const result: Record<string, string | string[]> = {};
|
|
214
|
+
for (const key of this.keys()) {
|
|
226
215
|
const values = this.getAll(key);
|
|
227
|
-
// Http.request() only supports string as Host header.
|
|
228
|
-
// This hack makes specifying custom Host header possible.
|
|
229
216
|
if (key === 'host') {
|
|
230
217
|
result[key] = values[0];
|
|
231
218
|
} else {
|
|
232
219
|
result[key] = values.length > 1 ? values : values[0];
|
|
233
220
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}, {});
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
237
223
|
}
|
|
238
224
|
}
|
|
239
225
|
|
|
240
|
-
/**
|
|
241
|
-
* Re-shaping object for Web IDL tests
|
|
242
|
-
* Only need to do it for overridden methods
|
|
243
|
-
*/
|
|
244
226
|
Object.defineProperties(
|
|
245
227
|
Headers.prototype,
|
|
246
|
-
['get', 'entries', 'forEach', 'values'].reduce((result, property) => {
|
|
228
|
+
['get', 'entries', 'forEach', 'values'].reduce((result: PropertyDescriptorMap, property) => {
|
|
247
229
|
result[property] = { enumerable: true };
|
|
248
230
|
return result;
|
|
249
231
|
}, {})
|
|
250
232
|
);
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Create a Headers object from an http.IncomingMessage.rawHeaders, ignoring those that do
|
|
254
|
-
* not conform to HTTP grammar productions.
|
|
255
|
-
* @param headers
|
|
256
|
-
*/
|
|
257
|
-
export function fromRawHeaders(headers: IncomingMessage['rawHeaders'] = []) {
|
|
258
|
-
return new Headers(
|
|
259
|
-
headers
|
|
260
|
-
// Split into pairs
|
|
261
|
-
.reduce((result, value, index, array) => {
|
|
262
|
-
if (index % 2 === 0) {
|
|
263
|
-
result.push(array.slice(index, index + 2));
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return result;
|
|
267
|
-
}, [])
|
|
268
|
-
.filter(([name, value]) => {
|
|
269
|
-
try {
|
|
270
|
-
validateHeaderName(name);
|
|
271
|
-
validateHeaderValue(name, String(value));
|
|
272
|
-
return true;
|
|
273
|
-
} catch {
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
);
|
|
279
|
-
}
|