@gjsify/fetch 0.4.27 → 0.4.29
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/lib/body.d.ts +2 -1
- package/lib/body.js +21 -19
- package/lib/esm/utils/referrer.js +1 -1
- package/lib/headers.js +2 -2
- package/lib/index.js +10 -8
- package/lib/index.spec.js +27 -14
- package/lib/request.d.ts +2 -2
- package/lib/request.js +22 -13
- package/lib/response.d.ts +1 -1
- package/lib/response.js +5 -5
- package/lib/types/system-error.js +0 -1
- package/lib/utils/blob-from.d.ts +1 -1
- package/lib/utils/blob-from.js +1 -1
- package/lib/utils/is-redirect.js +1 -1
- package/lib/utils/is.d.ts +1 -1
- package/lib/utils/is.js +2 -3
- package/lib/utils/multipart-parser.js +2 -2
- package/lib/utils/referrer.d.ts +2 -2
- package/lib/utils/referrer.js +4 -3
- package/lib/utils/soup-helpers.d.ts +2 -2
- package/lib/xhr.js +8 -7
- package/package.json +7 -7
package/lib/body.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Blob } from './utils/blob-from.js';
|
|
2
|
-
import {
|
|
2
|
+
import type { Writable } from 'node:stream';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
3
4
|
import { Buffer } from 'node:buffer';
|
|
4
5
|
import { FormData } from '@gjsify/formdata';
|
|
5
6
|
import { FetchBaseError } from './errors/base.js';
|
package/lib/body.js
CHANGED
|
@@ -20,15 +20,7 @@ const pipeline = (source, dest) => new Promise((resolve, reject) => {
|
|
|
20
20
|
});
|
|
21
21
|
const INTERNALS = Symbol('Body internals');
|
|
22
22
|
function isAnyArrayBuffer(val) {
|
|
23
|
-
return val instanceof ArrayBuffer ||
|
|
24
|
-
(typeof SharedArrayBuffer !== 'undefined' && val instanceof SharedArrayBuffer);
|
|
25
|
-
}
|
|
26
|
-
function isBoxedPrimitive(val) {
|
|
27
|
-
return (val instanceof String ||
|
|
28
|
-
val instanceof Number ||
|
|
29
|
-
val instanceof Boolean ||
|
|
30
|
-
(typeof Symbol !== 'undefined' && val instanceof Symbol) ||
|
|
31
|
-
(typeof BigInt !== 'undefined' && val instanceof BigInt));
|
|
23
|
+
return val instanceof ArrayBuffer || (typeof SharedArrayBuffer !== 'undefined' && val instanceof SharedArrayBuffer);
|
|
32
24
|
}
|
|
33
25
|
/**
|
|
34
26
|
* Body mixin
|
|
@@ -133,7 +125,9 @@ export default class Body {
|
|
|
133
125
|
try {
|
|
134
126
|
controller.enqueue(chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk));
|
|
135
127
|
}
|
|
136
|
-
catch {
|
|
128
|
+
catch {
|
|
129
|
+
/* consumer cancelled — drop */
|
|
130
|
+
}
|
|
137
131
|
});
|
|
138
132
|
stream.on('end', () => {
|
|
139
133
|
if (closed)
|
|
@@ -145,7 +139,9 @@ export default class Body {
|
|
|
145
139
|
try {
|
|
146
140
|
controller.close();
|
|
147
141
|
}
|
|
148
|
-
catch {
|
|
142
|
+
catch {
|
|
143
|
+
/* already closed/cancelled */
|
|
144
|
+
}
|
|
149
145
|
});
|
|
150
146
|
stream.on('error', (err) => {
|
|
151
147
|
if (closed)
|
|
@@ -154,13 +150,15 @@ export default class Body {
|
|
|
154
150
|
try {
|
|
155
151
|
controller.error(err);
|
|
156
152
|
}
|
|
157
|
-
catch {
|
|
153
|
+
catch {
|
|
154
|
+
/* already closed/cancelled */
|
|
155
|
+
}
|
|
158
156
|
});
|
|
159
157
|
},
|
|
160
158
|
cancel() {
|
|
161
159
|
closed = true;
|
|
162
160
|
stream.destroy();
|
|
163
|
-
}
|
|
161
|
+
},
|
|
164
162
|
});
|
|
165
163
|
}
|
|
166
164
|
return null;
|
|
@@ -206,10 +204,12 @@ export default class Body {
|
|
|
206
204
|
* Return raw response as Blob
|
|
207
205
|
*/
|
|
208
206
|
async blob() {
|
|
209
|
-
const ct =
|
|
207
|
+
const ct = this.headers?.get('content-type') ||
|
|
208
|
+
(this[INTERNALS].body && this[INTERNALS].body.type) ||
|
|
209
|
+
'';
|
|
210
210
|
const buf = await this.arrayBuffer();
|
|
211
211
|
return new Blob([buf], {
|
|
212
|
-
type: ct
|
|
212
|
+
type: ct,
|
|
213
213
|
});
|
|
214
214
|
}
|
|
215
215
|
/**
|
|
@@ -271,11 +271,13 @@ async function consumeBody(data) {
|
|
|
271
271
|
}
|
|
272
272
|
catch (error) {
|
|
273
273
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
274
|
-
const error_ = error instanceof FetchBaseError
|
|
274
|
+
const error_ = error instanceof FetchBaseError
|
|
275
|
+
? error
|
|
276
|
+
: new FetchError(`Invalid response body while trying to fetch ${data.url}: ${err.message}`, 'system', err);
|
|
275
277
|
throw error_;
|
|
276
278
|
}
|
|
277
279
|
try {
|
|
278
|
-
if (accum.every(c => typeof c === 'string')) {
|
|
280
|
+
if (accum.every((c) => typeof c === 'string')) {
|
|
279
281
|
return Buffer.from(accum.join(''));
|
|
280
282
|
}
|
|
281
283
|
return Buffer.concat(accum, accumBytes);
|
|
@@ -295,7 +297,7 @@ export const clone = (instance, highWaterMark) => {
|
|
|
295
297
|
if (instance.bodyUsed) {
|
|
296
298
|
throw new Error('cannot clone body after it is used');
|
|
297
299
|
}
|
|
298
|
-
if (
|
|
300
|
+
if (body instanceof Stream && typeof body.getBoundary !== 'function') {
|
|
299
301
|
p1 = new PassThrough({ highWaterMark });
|
|
300
302
|
p2 = new PassThrough({ highWaterMark });
|
|
301
303
|
body.pipe(p1);
|
|
@@ -385,7 +387,7 @@ function readableStreamToReadable(webStream) {
|
|
|
385
387
|
},
|
|
386
388
|
destroy(_err, callback) {
|
|
387
389
|
reader.cancel().then(() => callback(null), callback);
|
|
388
|
-
}
|
|
390
|
+
},
|
|
389
391
|
});
|
|
390
392
|
}
|
|
391
393
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"../_virtual/_rolldown/runtime.js";import{URL as e}from"@gjsify/url";import{isIP as t}from"node:net";function stripURLForUseAsAReferrer(t,n=!1){if(t==null||t===`no-referrer`)return`no-referrer`;let r=new e(t);return/^(about|blob|data):$/.test(r.protocol)?`no-referrer`:(r.username=``,r.password=``,r.hash=``,n&&(r.pathname=``,r.search=``),r)}const n=new Set([``,`no-referrer`,`no-referrer-when-downgrade`,`same-origin`,`origin`,`strict-origin`,`origin-when-cross-origin`,`strict-origin-when-cross-origin`,`unsafe-url`]),r=`strict-origin-when-cross-origin`;function validateReferrerPolicy(e){if(!n.has(e))throw TypeError(`Invalid referrerPolicy: ${e}`);return e}function isOriginPotentiallyTrustworthy(e){if(/^(http|ws)s:$/.test(e.protocol))return!0;let n=e.host.replace(/(^\[)|(]$)/g,``),r=t(n);return r===4
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{URL as e}from"@gjsify/url";import{isIP as t}from"node:net";function stripURLForUseAsAReferrer(t,n=!1){if(t==null||t===`no-referrer`)return`no-referrer`;let r=new e(t);return/^(about|blob|data):$/.test(r.protocol)?`no-referrer`:(r.username=``,r.password=``,r.hash=``,n&&(r.pathname=``,r.search=``),r)}const n=new Set([``,`no-referrer`,`no-referrer-when-downgrade`,`same-origin`,`origin`,`strict-origin`,`origin-when-cross-origin`,`strict-origin-when-cross-origin`,`unsafe-url`]),r=`strict-origin-when-cross-origin`;function validateReferrerPolicy(e){if(!n.has(e))throw TypeError(`Invalid referrerPolicy: ${e}`);return e}function isOriginPotentiallyTrustworthy(e){if(/^(http|ws)s:$/.test(e.protocol))return!0;let n=e.host.replace(/(^\[)|(]$)/g,``),r=t(n);return r===4&&n.startsWith(`127.`)||r===6&&/^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(n)?!0:e.host===`localhost`||e.host.endsWith(`.localhost`)?!1:e.protocol===`file:`}function isUrlPotentiallyTrustworthy(t){return/^about:(blank|srcdoc)$/.test(t.toString())||(typeof t==`string`&&(t=new e(t)),t.protocol===`data:`)||/^(blob|filesystem):$/.test(t.protocol)?!0:isOriginPotentiallyTrustworthy(t)}function determineRequestsReferrer(t,n={}){let{referrerURLCallback:r,referrerOriginCallback:i}=n;if(t.referrer===`no-referrer`||t.referrerPolicy===``)return null;let a=t.referrerPolicy;if(t.referrer===`about:client`)return`no-referrer`;let o=new e(t.referrer),s=stripURLForUseAsAReferrer(o),c=stripURLForUseAsAReferrer(o,!0);s.toString().length>4096&&(s=c),r&&(s=r(s)),i&&(c=i(c));let l=new e(t.url);switch(a){case`no-referrer`:return`no-referrer`;case`origin`:return c;case`unsafe-url`:return s;case`strict-origin`:return isUrlPotentiallyTrustworthy(s)&&!isUrlPotentiallyTrustworthy(l)?`no-referrer`:c.toString();case`strict-origin-when-cross-origin`:return s.origin===l.origin?s:isUrlPotentiallyTrustworthy(s)&&!isUrlPotentiallyTrustworthy(l)?`no-referrer`:c;case`same-origin`:return s.origin===l.origin?s:`no-referrer`;case`origin-when-cross-origin`:return s.origin===l.origin?s:c;case`no-referrer-when-downgrade`:return isUrlPotentiallyTrustworthy(s)&&!isUrlPotentiallyTrustworthy(l)?`no-referrer`:s;default:throw TypeError(`Invalid referrerPolicy: ${a}`)}}function parseReferrerPolicyFromHeader(e){let t=(e.get(`referrer-policy`)||``).split(/[,\s]+/),r=``;for(let e of t)e&&n.has(e)&&(r=e);return r}export{r as DEFAULT_REFERRER_POLICY,n as ReferrerPolicy,determineRequestsReferrer,isOriginPotentiallyTrustworthy,isUrlPotentiallyTrustworthy,parseReferrerPolicyFromHeader,stripURLForUseAsAReferrer,validateReferrerPolicy};
|
package/lib/headers.js
CHANGED
|
@@ -54,8 +54,8 @@ export default class Headers {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
else {
|
|
57
|
-
throw new TypeError(
|
|
58
|
-
'
|
|
57
|
+
throw new TypeError("Failed to construct 'Headers': The provided value is not of type " +
|
|
58
|
+
"'(sequence<sequence<ByteString>> or record<ByteString, ByteString>)'");
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
append(name, value) {
|
package/lib/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { isRedirect } from './utils/is-redirect.js';
|
|
|
15
15
|
import { FormData } from '@gjsify/formdata';
|
|
16
16
|
import { isDomainOrSubdomain, isSameProtocol } from './utils/is.js';
|
|
17
17
|
import { parseReferrerPolicyFromHeader } from './utils/referrer.js';
|
|
18
|
-
import { Blob, File
|
|
18
|
+
import { Blob, File } from './utils/blob-from.js';
|
|
19
19
|
import { URL } from '@gjsify/url';
|
|
20
20
|
export { FormData, Headers, Request, Response, FetchError, AbortError, isRedirect };
|
|
21
21
|
export { Blob, File };
|
|
@@ -30,9 +30,7 @@ function rewriteRootRelativeUrl(input) {
|
|
|
30
30
|
const DEBUG = _g.__GJSIFY_DEBUG_FETCH === true;
|
|
31
31
|
try {
|
|
32
32
|
// GJS-only: derive program dir from System.programInvocationName.
|
|
33
|
-
const programPath = _g.imports?.system?.programPath
|
|
34
|
-
?? _g.imports?.system?.programInvocationName
|
|
35
|
-
?? '';
|
|
33
|
+
const programPath = _g.imports?.system?.programPath ?? _g.imports?.system?.programInvocationName ?? '';
|
|
36
34
|
if (!programPath)
|
|
37
35
|
return input;
|
|
38
36
|
const dir = GLib.path_get_dirname(programPath);
|
|
@@ -136,7 +134,7 @@ export default async function fetch(url, init = {}) {
|
|
|
136
134
|
readable.destroy(new AbortError('The operation was aborted.'));
|
|
137
135
|
});
|
|
138
136
|
// Handle stream errors
|
|
139
|
-
readable.on('error', (
|
|
137
|
+
readable.on('error', (_error) => {
|
|
140
138
|
finalize();
|
|
141
139
|
// Error is consumed by the body when read
|
|
142
140
|
});
|
|
@@ -183,7 +181,7 @@ export default async function fetch(url, init = {}) {
|
|
|
183
181
|
signal: request.signal,
|
|
184
182
|
size: request.size,
|
|
185
183
|
referrer: request.referrer,
|
|
186
|
-
referrerPolicy: request.referrerPolicy
|
|
184
|
+
referrerPolicy: request.referrerPolicy,
|
|
187
185
|
};
|
|
188
186
|
// Don't forward sensitive headers to different domains/protocols
|
|
189
187
|
if (!isDomainOrSubdomain(request.url, locationURL) || !isSameProtocol(request.url, locationURL)) {
|
|
@@ -222,7 +220,7 @@ export default async function fetch(url, init = {}) {
|
|
|
222
220
|
headers,
|
|
223
221
|
size: request.size,
|
|
224
222
|
counter: request.counter,
|
|
225
|
-
highWaterMark: request.highWaterMark
|
|
223
|
+
highWaterMark: request.highWaterMark,
|
|
226
224
|
};
|
|
227
225
|
// Handle content encoding (decompression)
|
|
228
226
|
const codings = headers.get('Content-Encoding');
|
|
@@ -232,7 +230,11 @@ export default async function fetch(url, init = {}) {
|
|
|
232
230
|
// 3. no Content-Encoding header
|
|
233
231
|
// 4. no content response (204)
|
|
234
232
|
// 5. content not modified response (304)
|
|
235
|
-
if (!request.compress ||
|
|
233
|
+
if (!request.compress ||
|
|
234
|
+
request.method === 'HEAD' ||
|
|
235
|
+
codings === null ||
|
|
236
|
+
statusCode === 204 ||
|
|
237
|
+
statusCode === 304) {
|
|
236
238
|
finalize();
|
|
237
239
|
return new Response(readable, responseOptions);
|
|
238
240
|
}
|
package/lib/index.spec.js
CHANGED
|
@@ -7,7 +7,7 @@ import { describe, it, expect, on } from '@gjsify/unit';
|
|
|
7
7
|
export default async () => {
|
|
8
8
|
await describe('fetch', async () => {
|
|
9
9
|
await it('fetch should be a function', async () => {
|
|
10
|
-
expect(typeof fetch).toBe(
|
|
10
|
+
expect(typeof fetch).toBe('function');
|
|
11
11
|
});
|
|
12
12
|
});
|
|
13
13
|
await describe('Headers', async () => {
|
|
@@ -37,7 +37,10 @@ export default async () => {
|
|
|
37
37
|
expect(h.has('x-remove')).toBe(false);
|
|
38
38
|
});
|
|
39
39
|
await it('should construct from array pairs', async () => {
|
|
40
|
-
const h = new Headers([
|
|
40
|
+
const h = new Headers([
|
|
41
|
+
['a', '1'],
|
|
42
|
+
['b', '2'],
|
|
43
|
+
]);
|
|
41
44
|
expect(h.get('a')).toBe('1');
|
|
42
45
|
expect(h.get('b')).toBe('2');
|
|
43
46
|
});
|
|
@@ -71,15 +74,17 @@ export default async () => {
|
|
|
71
74
|
});
|
|
72
75
|
await describe('Headers forEach', async () => {
|
|
73
76
|
await it('should iterate all headers with forEach', async () => {
|
|
74
|
-
const h = new Headers({
|
|
77
|
+
const h = new Headers({ a: '1', b: '2' });
|
|
75
78
|
const collected = [];
|
|
76
|
-
h.forEach((value, key) => {
|
|
79
|
+
h.forEach((value, key) => {
|
|
80
|
+
collected.push(`${key}:${value}`);
|
|
81
|
+
});
|
|
77
82
|
expect(collected.length).toBe(2);
|
|
78
83
|
expect(collected[0]).toBe('a:1');
|
|
79
84
|
expect(collected[1]).toBe('b:2');
|
|
80
85
|
});
|
|
81
86
|
await it('should return correct values() iterator', async () => {
|
|
82
|
-
const h = new Headers({
|
|
87
|
+
const h = new Headers({ x: 'hello', y: 'world' });
|
|
83
88
|
const values = [...h.values()];
|
|
84
89
|
expect(values.length).toBe(2);
|
|
85
90
|
});
|
|
@@ -93,7 +98,7 @@ export default async () => {
|
|
|
93
98
|
expect(entries[1][0]).toBe('x-custom');
|
|
94
99
|
});
|
|
95
100
|
await it('should support spread operator', async () => {
|
|
96
|
-
const h = new Headers({
|
|
101
|
+
const h = new Headers({ a: '1' });
|
|
97
102
|
const arr = [...h];
|
|
98
103
|
expect(arr.length).toBe(1);
|
|
99
104
|
expect(arr[0][0]).toBe('a');
|
|
@@ -108,7 +113,7 @@ export default async () => {
|
|
|
108
113
|
expect(() => h.append('invalid header', 'value')).toThrow();
|
|
109
114
|
});
|
|
110
115
|
await it('should support entries() for destructuring', async () => {
|
|
111
|
-
const h = new Headers({
|
|
116
|
+
const h = new Headers({ host: 'example.com', accept: '*/*' });
|
|
112
117
|
const obj = {};
|
|
113
118
|
for (const [k, v] of h.entries())
|
|
114
119
|
obj[k] = v;
|
|
@@ -128,7 +133,7 @@ export default async () => {
|
|
|
128
133
|
});
|
|
129
134
|
await it('should set custom headers', async () => {
|
|
130
135
|
const r = new Request('https://example.com', {
|
|
131
|
-
headers: { 'X-Custom': 'test' }
|
|
136
|
+
headers: { 'X-Custom': 'test' },
|
|
132
137
|
});
|
|
133
138
|
expect(r.headers.get('x-custom')).toBe('test');
|
|
134
139
|
});
|
|
@@ -178,7 +183,7 @@ export default async () => {
|
|
|
178
183
|
});
|
|
179
184
|
await it('should parse json body', async () => {
|
|
180
185
|
const r = new Response('{"key": "value"}');
|
|
181
|
-
const json = await r.json();
|
|
186
|
+
const json = (await r.json());
|
|
182
187
|
expect(json.key).toBe('value');
|
|
183
188
|
});
|
|
184
189
|
await it('should parse arrayBuffer body', async () => {
|
|
@@ -207,7 +212,7 @@ export default async () => {
|
|
|
207
212
|
expect(r.status).toBe(200);
|
|
208
213
|
const ct = r.headers.get('content-type') || '';
|
|
209
214
|
expect(ct.includes('application/json')).toBe(true);
|
|
210
|
-
const data = await r.json();
|
|
215
|
+
const data = (await r.json());
|
|
211
216
|
expect(data.message).toBe('ok');
|
|
212
217
|
});
|
|
213
218
|
await it('should clone a response', async () => {
|
|
@@ -265,22 +270,30 @@ export default async () => {
|
|
|
265
270
|
xhr.send();
|
|
266
271
|
});
|
|
267
272
|
await it('responseType="arraybuffer" yields ArrayBuffer', async () => {
|
|
268
|
-
const xhr = await runXhr((x) => {
|
|
273
|
+
const xhr = await runXhr((x) => {
|
|
274
|
+
x.responseType = 'arraybuffer';
|
|
275
|
+
});
|
|
269
276
|
expect(xhr.response instanceof ArrayBuffer).toBe(true);
|
|
270
277
|
expect(xhr.response.byteLength).toBe(5);
|
|
271
278
|
});
|
|
272
279
|
await it('responseType="text" yields decoded string', async () => {
|
|
273
|
-
const xhr = await runXhr((x) => {
|
|
280
|
+
const xhr = await runXhr((x) => {
|
|
281
|
+
x.responseType = 'text';
|
|
282
|
+
});
|
|
274
283
|
expect(xhr.response).toBe('hello');
|
|
275
284
|
expect(xhr.responseText).toBe('hello');
|
|
276
285
|
});
|
|
277
286
|
await it('default responseType "" yields text', async () => {
|
|
278
|
-
const xhr = await runXhr(() => {
|
|
287
|
+
const xhr = await runXhr(() => {
|
|
288
|
+
/* responseType left at "" */
|
|
289
|
+
});
|
|
279
290
|
expect(xhr.response).toBe('hello');
|
|
280
291
|
expect(xhr.responseText).toBe('hello');
|
|
281
292
|
});
|
|
282
293
|
await it('responseType="blob" attaches _tmpPath for URL.createObjectURL', async () => {
|
|
283
|
-
const xhr = await runXhr((x) => {
|
|
294
|
+
const xhr = await runXhr((x) => {
|
|
295
|
+
x.responseType = 'blob';
|
|
296
|
+
});
|
|
284
297
|
const blob = xhr.response;
|
|
285
298
|
expect(blob instanceof Blob).toBe(true);
|
|
286
299
|
expect(typeof blob._tmpPath).toBe('string');
|
package/lib/request.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import GLib from '@girs/glib-2.0';
|
|
|
2
2
|
import Soup from '@girs/soup-3.0';
|
|
3
3
|
import Gio from '@girs/gio-2.0';
|
|
4
4
|
import { URL } from '@gjsify/url';
|
|
5
|
-
import { Blob } from './utils/blob-from.js';
|
|
6
|
-
import { Readable } from 'node:stream';
|
|
5
|
+
import type { Blob } from './utils/blob-from.js';
|
|
6
|
+
import type { Readable } from 'node:stream';
|
|
7
7
|
import Headers from './headers.js';
|
|
8
8
|
import Body from './body.js';
|
|
9
9
|
import type { FormData } from '@gjsify/formdata';
|
package/lib/request.js
CHANGED
|
@@ -16,8 +16,7 @@ const INTERNALS = Symbol('Request internals');
|
|
|
16
16
|
* Check if `obj` is an instance of Request.
|
|
17
17
|
*/
|
|
18
18
|
const isRequest = (obj) => {
|
|
19
|
-
return
|
|
20
|
-
typeof obj.url === 'string');
|
|
19
|
+
return typeof obj === 'object' && typeof obj.url === 'string';
|
|
21
20
|
};
|
|
22
21
|
/** This Fetch API interface represents a resource request. */
|
|
23
22
|
export class Request extends Body {
|
|
@@ -124,9 +123,13 @@ export class Request extends Body {
|
|
|
124
123
|
(method === 'GET' || method === 'HEAD')) {
|
|
125
124
|
throw new TypeError('Request with GET/HEAD method cannot have body');
|
|
126
125
|
}
|
|
127
|
-
const inputBody = init?.body
|
|
126
|
+
const inputBody = init?.body
|
|
127
|
+
? init.body
|
|
128
|
+
: isRequest(input) && inputRL.body !== null
|
|
129
|
+
? clone(input)
|
|
130
|
+
: null;
|
|
128
131
|
super(inputBody, {
|
|
129
|
-
size: initRL.size || 0
|
|
132
|
+
size: initRL.size || 0,
|
|
130
133
|
});
|
|
131
134
|
const headers = new Headers((init?.headers || inputRL.headers || {}));
|
|
132
135
|
if (inputBody !== null && !headers.has('Content-Type')) {
|
|
@@ -135,9 +138,7 @@ export class Request extends Body {
|
|
|
135
138
|
headers.set('Content-Type', contentType);
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
|
-
let signal = isRequest(input) ?
|
|
139
|
-
inputRL.signal :
|
|
140
|
-
null;
|
|
141
|
+
let signal = isRequest(input) ? inputRL.signal : null;
|
|
141
142
|
if (init && 'signal' in init) {
|
|
142
143
|
signal = init.signal;
|
|
143
144
|
}
|
|
@@ -182,8 +183,14 @@ export class Request extends Body {
|
|
|
182
183
|
message,
|
|
183
184
|
};
|
|
184
185
|
// Node-fetch-only options
|
|
185
|
-
this.follow =
|
|
186
|
-
|
|
186
|
+
this.follow =
|
|
187
|
+
initRL.follow === undefined ? (inputRL.follow === undefined ? 20 : inputRL.follow) : initRL.follow;
|
|
188
|
+
this.compress =
|
|
189
|
+
initRL.compress === undefined
|
|
190
|
+
? inputRL.compress === undefined
|
|
191
|
+
? true
|
|
192
|
+
: inputRL.compress
|
|
193
|
+
: initRL.compress;
|
|
187
194
|
this.counter = initRL.counter || inputRL.counter || 0;
|
|
188
195
|
this.agent = initRL.agent || inputRL.agent;
|
|
189
196
|
this.highWaterMark = initRL.highWaterMark || inputRL.highWaterMark || 16384;
|
|
@@ -207,7 +214,9 @@ export class Request extends Body {
|
|
|
207
214
|
try {
|
|
208
215
|
session.remove_feature_by_type(Soup.ContentDecoder.$gtype);
|
|
209
216
|
}
|
|
210
|
-
catch {
|
|
217
|
+
catch {
|
|
218
|
+
/* not present */
|
|
219
|
+
}
|
|
211
220
|
options.headers._appendToSoupMessage(message);
|
|
212
221
|
// Attach the request body to the Soup message (needed for POST/PUT/PATCH).
|
|
213
222
|
// Use _rawBodyBuffer to read the body without consuming the stream (the
|
|
@@ -224,7 +233,7 @@ export class Request extends Body {
|
|
|
224
233
|
return {
|
|
225
234
|
inputStream: this[INTERNALS].inputStream,
|
|
226
235
|
readable: this[INTERNALS].readable,
|
|
227
|
-
cancellable
|
|
236
|
+
cancellable,
|
|
228
237
|
};
|
|
229
238
|
}
|
|
230
239
|
/**
|
|
@@ -257,7 +266,7 @@ Object.defineProperties(Request.prototype, {
|
|
|
257
266
|
clone: { enumerable: true },
|
|
258
267
|
signal: { enumerable: true },
|
|
259
268
|
referrer: { enumerable: true },
|
|
260
|
-
referrerPolicy: { enumerable: true }
|
|
269
|
+
referrerPolicy: { enumerable: true },
|
|
261
270
|
});
|
|
262
271
|
export default Request;
|
|
263
272
|
/**
|
|
@@ -322,6 +331,6 @@ export const getSoupRequestOptions = (request) => {
|
|
|
322
331
|
};
|
|
323
332
|
return {
|
|
324
333
|
parsedURL,
|
|
325
|
-
options
|
|
334
|
+
options,
|
|
326
335
|
};
|
|
327
336
|
};
|
package/lib/response.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Gio from '@girs/gio-2.0';
|
|
2
2
|
import Headers from './headers.js';
|
|
3
3
|
import Body from './body.js';
|
|
4
|
-
import { Blob } from './utils/blob-from.js';
|
|
4
|
+
import type { Blob } from './utils/blob-from.js';
|
|
5
5
|
import type { Readable } from 'node:stream';
|
|
6
6
|
declare const INTERNALS: unique symbol;
|
|
7
7
|
interface ResponseOptions {
|
package/lib/response.js
CHANGED
|
@@ -38,7 +38,7 @@ export class Response extends Body {
|
|
|
38
38
|
statusText: options.statusText || '',
|
|
39
39
|
headers,
|
|
40
40
|
counter: options.counter,
|
|
41
|
-
highWaterMark: options.highWaterMark
|
|
41
|
+
highWaterMark: options.highWaterMark,
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
get type() {
|
|
@@ -83,7 +83,7 @@ export class Response extends Body {
|
|
|
83
83
|
ok: this.ok,
|
|
84
84
|
redirected: this.redirected,
|
|
85
85
|
size: this.size,
|
|
86
|
-
highWaterMark: this.highWaterMark
|
|
86
|
+
highWaterMark: this.highWaterMark,
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
@@ -97,9 +97,9 @@ export class Response extends Body {
|
|
|
97
97
|
}
|
|
98
98
|
return new Response(null, {
|
|
99
99
|
headers: {
|
|
100
|
-
location: new URL(url).toString()
|
|
100
|
+
location: new URL(url).toString(),
|
|
101
101
|
},
|
|
102
|
-
status
|
|
102
|
+
status,
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
static error() {
|
|
@@ -153,6 +153,6 @@ Object.defineProperties(Response.prototype, {
|
|
|
153
153
|
redirected: { enumerable: true },
|
|
154
154
|
statusText: { enumerable: true },
|
|
155
155
|
headers: { enumerable: true },
|
|
156
|
-
clone: { enumerable: true }
|
|
156
|
+
clone: { enumerable: true },
|
|
157
157
|
});
|
|
158
158
|
export default Response;
|
package/lib/utils/blob-from.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Blob, File } from 'node:buffer';
|
|
2
|
-
export { Blob, File
|
|
2
|
+
export { Blob, File };
|
package/lib/utils/blob-from.js
CHANGED
package/lib/utils/is-redirect.js
CHANGED
package/lib/utils/is.d.ts
CHANGED
package/lib/utils/is.js
CHANGED
|
@@ -11,7 +11,7 @@ const NAME = Symbol.toStringTag;
|
|
|
11
11
|
* @param {*} object - Object to check for
|
|
12
12
|
* @return {boolean}
|
|
13
13
|
*/
|
|
14
|
-
export const isURLSearchParameters = object => {
|
|
14
|
+
export const isURLSearchParameters = (object) => {
|
|
15
15
|
return (typeof object === 'object' &&
|
|
16
16
|
typeof object.append === 'function' &&
|
|
17
17
|
typeof object.delete === 'function' &&
|
|
@@ -44,8 +44,7 @@ export const isAbortSignal = (object) => {
|
|
|
44
44
|
if (typeof object !== 'object' || object === null)
|
|
45
45
|
return false;
|
|
46
46
|
const obj = object;
|
|
47
|
-
return
|
|
48
|
-
obj[NAME] === 'EventTarget');
|
|
47
|
+
return obj[NAME] === 'AbortSignal' || obj[NAME] === 'EventTarget';
|
|
49
48
|
};
|
|
50
49
|
/**
|
|
51
50
|
* isDomainOrSubdomain reports whether sub is a subdomain (or exact match) of
|
|
@@ -29,7 +29,7 @@ var S;
|
|
|
29
29
|
let f = 1;
|
|
30
30
|
const F = {
|
|
31
31
|
PART_BOUNDARY: f,
|
|
32
|
-
LAST_BOUNDARY: f *= 2
|
|
32
|
+
LAST_BOUNDARY: (f *= 2),
|
|
33
33
|
};
|
|
34
34
|
const LF = 10;
|
|
35
35
|
const CR = 13;
|
|
@@ -38,7 +38,7 @@ const HYPHEN = 45;
|
|
|
38
38
|
const COLON = 58;
|
|
39
39
|
const A = 97;
|
|
40
40
|
const Z = 122;
|
|
41
|
-
const lower = c => c | 0x20;
|
|
41
|
+
const lower = (c) => c | 0x20;
|
|
42
42
|
const noop = (..._args) => { };
|
|
43
43
|
class MultipartParser {
|
|
44
44
|
index = 0;
|
package/lib/utils/referrer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { URL } from '@gjsify/url';
|
|
2
|
-
import Request from '../request.js';
|
|
2
|
+
import type Request from '../request.js';
|
|
3
3
|
/**
|
|
4
4
|
* @external URL
|
|
5
5
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/URL URL}
|
|
@@ -13,7 +13,7 @@ import Request from '../request.js';
|
|
|
13
13
|
* @param url
|
|
14
14
|
* @param originOnly
|
|
15
15
|
*/
|
|
16
|
-
export declare function stripURLForUseAsAReferrer(url: null | URL |
|
|
16
|
+
export declare function stripURLForUseAsAReferrer(url: null | URL | 'no-referrer', originOnly?: boolean): URL | "no-referrer";
|
|
17
17
|
/**
|
|
18
18
|
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#enumdef-referrerpolicy enum ReferrerPolicy}
|
|
19
19
|
*/
|
package/lib/utils/referrer.js
CHANGED
|
@@ -15,7 +15,8 @@ import { isIP } from 'node:net';
|
|
|
15
15
|
*/
|
|
16
16
|
export function stripURLForUseAsAReferrer(url, originOnly = false) {
|
|
17
17
|
// 1. If url is null, return no referrer.
|
|
18
|
-
if (url == null || url ===
|
|
18
|
+
if (url == null || url === 'no-referrer') {
|
|
19
|
+
// eslint-disable-line no-eq-null, eqeqeq
|
|
19
20
|
return 'no-referrer';
|
|
20
21
|
}
|
|
21
22
|
const u = new URL(url);
|
|
@@ -55,7 +56,7 @@ export const ReferrerPolicy = new Set([
|
|
|
55
56
|
'strict-origin',
|
|
56
57
|
'origin-when-cross-origin',
|
|
57
58
|
'strict-origin-when-cross-origin',
|
|
58
|
-
'unsafe-url'
|
|
59
|
+
'unsafe-url',
|
|
59
60
|
]);
|
|
60
61
|
/**
|
|
61
62
|
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#default-referrer-policy default referrer policy}
|
|
@@ -89,7 +90,7 @@ export function isOriginPotentiallyTrustworthy(url) {
|
|
|
89
90
|
// 4. If origin's host component matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy".
|
|
90
91
|
const hostIp = url.host.replace(/(^\[)|(]$)/g, '');
|
|
91
92
|
const hostIPVersion = isIP(hostIp);
|
|
92
|
-
if (hostIPVersion === 4 &&
|
|
93
|
+
if (hostIPVersion === 4 && hostIp.startsWith('127.')) {
|
|
93
94
|
return true;
|
|
94
95
|
}
|
|
95
96
|
if (hostIPVersion === 6 && /^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(hostIp)) {
|
package/lib/xhr.js
CHANGED
|
@@ -43,10 +43,7 @@ function guessBlobExt(url) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
function writeBlobToTempFile(bytes, url) {
|
|
46
|
-
const tmpPath = GLib.build_filenamev([
|
|
47
|
-
GLib.get_tmp_dir(),
|
|
48
|
-
`gjsify-blob-${_blobCounter++}${guessBlobExt(url)}`,
|
|
49
|
-
]);
|
|
46
|
+
const tmpPath = GLib.build_filenamev([GLib.get_tmp_dir(), `gjsify-blob-${_blobCounter++}${guessBlobExt(url)}`]);
|
|
50
47
|
GLib.file_set_contents(tmpPath, bytes);
|
|
51
48
|
return tmpPath;
|
|
52
49
|
}
|
|
@@ -119,7 +116,9 @@ export class XMLHttpRequest extends EventTarget {
|
|
|
119
116
|
if (this._aborted)
|
|
120
117
|
return;
|
|
121
118
|
const headersInit = {};
|
|
122
|
-
this._headers.forEach((v, k) => {
|
|
119
|
+
this._headers.forEach((v, k) => {
|
|
120
|
+
headersInit[k] = v;
|
|
121
|
+
});
|
|
123
122
|
const fetchOptions = {
|
|
124
123
|
method: this._method,
|
|
125
124
|
headers: headersInit,
|
|
@@ -198,7 +197,7 @@ export class XMLHttpRequest extends EventTarget {
|
|
|
198
197
|
const text = await res.text();
|
|
199
198
|
// Strip UTF-8 BOM (U+FEFF) — browsers do this automatically; required
|
|
200
199
|
// for JSON.parse to succeed on BOM-prefixed JSON responses.
|
|
201
|
-
const stripped = text.charCodeAt(0) ===
|
|
200
|
+
const stripped = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
|
|
202
201
|
this.responseText = stripped;
|
|
203
202
|
this.response = stripped;
|
|
204
203
|
break;
|
|
@@ -248,7 +247,9 @@ export class XMLHttpRequest extends EventTarget {
|
|
|
248
247
|
if (this.onloadend)
|
|
249
248
|
this.onloadend(new ProgressEvent('loadend'));
|
|
250
249
|
}
|
|
251
|
-
overrideMimeType(_mime) {
|
|
250
|
+
overrideMimeType(_mime) {
|
|
251
|
+
/* no-op */
|
|
252
|
+
}
|
|
252
253
|
_onTimeout() {
|
|
253
254
|
if (this._aborted)
|
|
254
255
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/fetch",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.29",
|
|
4
4
|
"description": "Web and Node.js fetch module for Gjs",
|
|
5
5
|
"module": "lib/esm/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"fetch"
|
|
49
49
|
],
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@gjsify/cli": "^0.4.
|
|
52
|
-
"@gjsify/unit": "^0.4.
|
|
51
|
+
"@gjsify/cli": "^0.4.29",
|
|
52
|
+
"@gjsify/unit": "^0.4.29",
|
|
53
53
|
"@types/node": "^25.9.1",
|
|
54
54
|
"typescript": "^6.0.3"
|
|
55
55
|
},
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
"@girs/gjs": "4.0.1",
|
|
59
59
|
"@girs/glib-2.0": "2.88.0-4.0.1",
|
|
60
60
|
"@girs/soup-3.0": "3.6.6-4.0.1",
|
|
61
|
-
"@gjsify/formdata": "^0.4.
|
|
62
|
-
"@gjsify/http": "^0.4.
|
|
63
|
-
"@gjsify/url": "^0.4.
|
|
64
|
-
"@gjsify/utils": "^0.4.
|
|
61
|
+
"@gjsify/formdata": "^0.4.29",
|
|
62
|
+
"@gjsify/http": "^0.4.29",
|
|
63
|
+
"@gjsify/url": "^0.4.29",
|
|
64
|
+
"@gjsify/utils": "^0.4.29"
|
|
65
65
|
}
|
|
66
66
|
}
|