@gjsify/fetch 0.0.2

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 (58) hide show
  1. package/README.md +9 -0
  2. package/lib/cjs/body.js +284 -0
  3. package/lib/cjs/errors/abort-error.js +28 -0
  4. package/lib/cjs/errors/base.js +36 -0
  5. package/lib/cjs/errors/fetch-error.js +40 -0
  6. package/lib/cjs/headers.js +231 -0
  7. package/lib/cjs/index.js +246 -0
  8. package/lib/cjs/request.js +306 -0
  9. package/lib/cjs/response.js +162 -0
  10. package/lib/cjs/types/index.js +17 -0
  11. package/lib/cjs/types/system-error.js +16 -0
  12. package/lib/cjs/utils/blob-from.js +124 -0
  13. package/lib/cjs/utils/get-search.js +30 -0
  14. package/lib/cjs/utils/is-redirect.js +26 -0
  15. package/lib/cjs/utils/is.js +47 -0
  16. package/lib/cjs/utils/multipart-parser.js +372 -0
  17. package/lib/cjs/utils/referrer.js +172 -0
  18. package/lib/esm/body.js +255 -0
  19. package/lib/esm/errors/abort-error.js +9 -0
  20. package/lib/esm/errors/base.js +17 -0
  21. package/lib/esm/errors/fetch-error.js +21 -0
  22. package/lib/esm/headers.js +202 -0
  23. package/lib/esm/index.js +224 -0
  24. package/lib/esm/request.js +281 -0
  25. package/lib/esm/response.js +133 -0
  26. package/lib/esm/types/index.js +1 -0
  27. package/lib/esm/types/system-error.js +1 -0
  28. package/lib/esm/utils/blob-from.js +101 -0
  29. package/lib/esm/utils/get-search.js +11 -0
  30. package/lib/esm/utils/is-redirect.js +7 -0
  31. package/lib/esm/utils/is.js +28 -0
  32. package/lib/esm/utils/multipart-parser.js +353 -0
  33. package/lib/esm/utils/referrer.js +153 -0
  34. package/package.json +53 -0
  35. package/src/body.ts +415 -0
  36. package/src/errors/abort-error.ts +10 -0
  37. package/src/errors/base.ts +20 -0
  38. package/src/errors/fetch-error.ts +26 -0
  39. package/src/headers.ts +279 -0
  40. package/src/index.spec.ts +13 -0
  41. package/src/index.ts +367 -0
  42. package/src/request.ts +396 -0
  43. package/src/response.ts +197 -0
  44. package/src/test.mts +6 -0
  45. package/src/types/index.ts +1 -0
  46. package/src/types/system-error.ts +11 -0
  47. package/src/utils/blob-from.ts +168 -0
  48. package/src/utils/get-search.ts +9 -0
  49. package/src/utils/is-redirect.ts +11 -0
  50. package/src/utils/is.ts +88 -0
  51. package/src/utils/multipart-parser.ts +448 -0
  52. package/src/utils/referrer.ts +350 -0
  53. package/test.gjs.js +34758 -0
  54. package/test.gjs.mjs +53177 -0
  55. package/test.node.js +1226 -0
  56. package/test.node.mjs +6294 -0
  57. package/tsconfig.json +19 -0
  58. package/tsconfig.types.json +8 -0
@@ -0,0 +1,224 @@
1
+ import Soup from "@girs/soup-3.0";
2
+ import Request from "./request.js";
3
+ import zlib from "zlib";
4
+ import Stream, { PassThrough, pipeline as pump } from "stream";
5
+ import dataUriToBuffer from "data-uri-to-buffer";
6
+ import { writeToStream, clone } from "./body.js";
7
+ import Response from "./response.js";
8
+ import Headers from "./headers.js";
9
+ import { getSoupRequestOptions } from "./request.js";
10
+ import { FetchError } from "./errors/fetch-error.js";
11
+ import { AbortError } from "./errors/abort-error.js";
12
+ import { isRedirect } from "./utils/is-redirect.js";
13
+ import { FormData } from "formdata-polyfill/esm.min.js";
14
+ import { isDomainOrSubdomain, isSameProtocol } from "./utils/is.js";
15
+ import { parseReferrerPolicyFromHeader } from "./utils/referrer.js";
16
+ import {
17
+ Blob,
18
+ File,
19
+ fileFromSync,
20
+ fileFrom,
21
+ blobFromSync,
22
+ blobFrom
23
+ } from "./utils/blob-from.js";
24
+ import { URL } from "@gjsify/deno-runtime/ext/url/00_url";
25
+ const supportedSchemas = /* @__PURE__ */ new Set(["data:", "http:", "https:"]);
26
+ async function fetch(url, init = {}) {
27
+ return new Promise(async (resolve, reject) => {
28
+ const request = new Request(url, init);
29
+ const { parsedURL, options } = getSoupRequestOptions(request);
30
+ if (!supportedSchemas.has(parsedURL.protocol)) {
31
+ throw new TypeError(`@gjsify/fetch cannot load ${url}. URL scheme "${parsedURL.protocol.replace(/:$/, "")}" is not supported.`);
32
+ }
33
+ if (parsedURL.protocol === "data:") {
34
+ const data = dataUriToBuffer(request.url);
35
+ const response2 = new Response(data, { headers: { "Content-Type": data.typeFull } });
36
+ resolve(response2);
37
+ return;
38
+ }
39
+ const { signal } = request;
40
+ let response = null;
41
+ const abort = () => {
42
+ const error = new AbortError("The operation was aborted.");
43
+ reject(error);
44
+ if (request.body && request.body instanceof Stream.Readable) {
45
+ request.body.destroy(error);
46
+ }
47
+ if (!response || !response.body) {
48
+ return;
49
+ }
50
+ response.body.emit("error", error);
51
+ };
52
+ if (signal && signal.aborted) {
53
+ abort();
54
+ return;
55
+ }
56
+ const abortAndFinalize = () => {
57
+ abort();
58
+ finalize();
59
+ };
60
+ let readable;
61
+ let cancellable;
62
+ try {
63
+ const sendRes = await request._send(options);
64
+ readable = sendRes.readable;
65
+ cancellable = sendRes.cancellable;
66
+ } catch (error) {
67
+ reject(error);
68
+ }
69
+ if (signal) {
70
+ signal.addEventListener("abort", abortAndFinalize);
71
+ }
72
+ const cancelledSignalId = cancellable.connect("cancelled", () => {
73
+ abortAndFinalize();
74
+ });
75
+ const finalize = () => {
76
+ cancellable.cancel();
77
+ if (signal) {
78
+ signal.removeEventListener("abort", abortAndFinalize);
79
+ }
80
+ cancellable.disconnect(cancelledSignalId);
81
+ };
82
+ const message = request._message;
83
+ readable.on("error", (error) => {
84
+ reject(new FetchError(`request to ${request.url} failed, reason: ${error.message}`, "system", error));
85
+ finalize();
86
+ });
87
+ message.connect("finished", (message2) => {
88
+ const headers = Headers._newFromSoupMessage(request._message, Soup.MessageHeadersType.RESPONSE);
89
+ const statusCode = message2.status_code;
90
+ const statusMessage = message2.get_reason_phrase();
91
+ if (isRedirect(statusCode)) {
92
+ const location = headers.get("Location");
93
+ let locationURL = null;
94
+ try {
95
+ locationURL = location === null ? null : new URL(location, request.url);
96
+ } catch {
97
+ if (request.redirect !== "manual") {
98
+ reject(new FetchError(`uri requested responds with an invalid redirect URL: ${location}`, "invalid-redirect"));
99
+ finalize();
100
+ return;
101
+ }
102
+ }
103
+ switch (request.redirect) {
104
+ case "error":
105
+ reject(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${request.url}`, "no-redirect"));
106
+ finalize();
107
+ return;
108
+ case "manual":
109
+ break;
110
+ case "follow": {
111
+ if (locationURL === null) {
112
+ break;
113
+ }
114
+ if (request.counter >= request.follow) {
115
+ reject(new FetchError(`maximum redirect reached at: ${request.url}`, "max-redirect"));
116
+ finalize();
117
+ return;
118
+ }
119
+ const requestOptions = {
120
+ headers: new Headers(request.headers),
121
+ follow: request.follow,
122
+ counter: request.counter + 1,
123
+ agent: request.agent,
124
+ compress: request.compress,
125
+ method: request.method,
126
+ body: clone(request),
127
+ signal: request.signal,
128
+ size: request.size,
129
+ referrer: request.referrer,
130
+ referrerPolicy: request.referrerPolicy
131
+ };
132
+ if (!isDomainOrSubdomain(request.url, locationURL) || !isSameProtocol(request.url, locationURL)) {
133
+ for (const name of ["authorization", "www-authenticate", "cookie", "cookie2"]) {
134
+ requestOptions.headers.delete(name);
135
+ }
136
+ }
137
+ if (statusCode !== 303 && request.body && init.body instanceof Stream.Readable) {
138
+ reject(new FetchError("Cannot follow redirect with body being a readable stream", "unsupported-redirect"));
139
+ finalize();
140
+ return;
141
+ }
142
+ if (statusCode === 303 || (statusCode === 301 || statusCode === 302) && request.method === "POST") {
143
+ requestOptions.method = "GET";
144
+ requestOptions.body = void 0;
145
+ requestOptions.headers.delete("content-length");
146
+ }
147
+ const responseReferrerPolicy = parseReferrerPolicyFromHeader(headers);
148
+ if (responseReferrerPolicy) {
149
+ requestOptions.referrerPolicy = responseReferrerPolicy;
150
+ }
151
+ resolve(fetch(new Request(locationURL, requestOptions)));
152
+ finalize();
153
+ return;
154
+ }
155
+ default:
156
+ return reject(new TypeError(`Redirect option '${request.redirect}' is not a valid value of RequestRedirect`));
157
+ }
158
+ }
159
+ let body = pump(response_, new PassThrough(), (error) => {
160
+ if (error) {
161
+ reject(error);
162
+ }
163
+ });
164
+ const responseOptions = {
165
+ url: request.url,
166
+ status: statusCode,
167
+ statusText: statusMessage,
168
+ headers,
169
+ size: request.size,
170
+ counter: request.counter,
171
+ highWaterMark: request.highWaterMark
172
+ };
173
+ const codings = headers.get("Content-Encoding");
174
+ if (!request.compress || request.method === "HEAD" || codings === null || statusCode === 204 || statusCode === 304) {
175
+ response = new Response(body, responseOptions);
176
+ resolve(response);
177
+ return;
178
+ }
179
+ const zlibOptions = {
180
+ flush: zlib.Z_SYNC_FLUSH,
181
+ finishFlush: zlib.Z_SYNC_FLUSH
182
+ };
183
+ if (codings === "gzip" || codings === "x-gzip") {
184
+ body = pump(body, zlib.createGunzip(zlibOptions), (error) => {
185
+ if (error) {
186
+ reject(error);
187
+ }
188
+ });
189
+ response = new Response(body, responseOptions);
190
+ resolve(response);
191
+ return;
192
+ }
193
+ if (codings === "br") {
194
+ body = pump(body, zlib.createBrotliDecompress(), (error) => {
195
+ if (error) {
196
+ reject(error);
197
+ }
198
+ });
199
+ response = new Response(body, responseOptions);
200
+ resolve(response);
201
+ return;
202
+ }
203
+ response = new Response(body, responseOptions);
204
+ resolve(response);
205
+ });
206
+ writeToStream(inputStream, request).catch(reject);
207
+ });
208
+ }
209
+ export {
210
+ AbortError,
211
+ Blob,
212
+ FetchError,
213
+ File,
214
+ FormData,
215
+ Headers,
216
+ Request,
217
+ Response,
218
+ blobFrom,
219
+ blobFromSync,
220
+ fetch as default,
221
+ fileFrom,
222
+ fileFromSync,
223
+ isRedirect
224
+ };
@@ -0,0 +1,281 @@
1
+ import "@girs/gjs";
2
+ import "@girs/gio-2.0";
3
+ import GLib from "@girs/glib-2.0";
4
+ import Soup from "@girs/soup-3.0";
5
+ import Gio from "@girs/gio-2.0";
6
+ import * as SoupExt from "@gjsify/soup-3.0";
7
+ import { URL } from "@gjsify/deno-runtime/ext/url/00_url";
8
+ import Headers from "./headers.js";
9
+ import Body, { clone, extractContentType, getTotalBytes } from "./body.js";
10
+ import { isAbortSignal } from "./utils/is.js";
11
+ import {
12
+ validateReferrerPolicy,
13
+ determineRequestsReferrer,
14
+ DEFAULT_REFERRER_POLICY
15
+ } from "./utils/referrer.js";
16
+ const INTERNALS = Symbol("Request internals");
17
+ const isRequest = (obj) => {
18
+ return typeof obj === "object" && typeof obj.url === "string";
19
+ };
20
+ class Request extends Body {
21
+ /** Returns the cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching. */
22
+ cache;
23
+ /** Returns the credentials mode associated with request, which is a string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. */
24
+ credentials;
25
+ /** Returns the kind of resource requested by request, e.g., "document" or "script". */
26
+ destination;
27
+ /** Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the "Host" header. */
28
+ get headers() {
29
+ return this[INTERNALS].headers;
30
+ }
31
+ /** Returns request's subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. [SRI] */
32
+ integrity;
33
+ /** Returns a boolean indicating whether or not request can outlive the global in which it was created. */
34
+ keepalive;
35
+ /** Returns request's HTTP method, which is "GET" by default. */
36
+ get method() {
37
+ return this[INTERNALS].method;
38
+ }
39
+ /** Returns the mode associated with request, which is a string indicating whether the request will use CORS, or will be restricted to same-origin URLs. */
40
+ mode;
41
+ /** Returns the redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default. */
42
+ get redirect() {
43
+ return this[INTERNALS].redirect;
44
+ }
45
+ /**
46
+ * Returns the referrer of request.
47
+ * Its value can be a same-origin URL if explicitly set in init, the empty string to indicate no referrer, and "about:client" when defaulting to the global's default.
48
+ * This is used during fetching to determine the value of the `Referer` header of the request being made.
49
+ * @see https://fetch.spec.whatwg.org/#dom-request-referrer
50
+ **/
51
+ get referrer() {
52
+ if (this[INTERNALS].referrer === "no-referrer") {
53
+ return "";
54
+ }
55
+ if (this[INTERNALS].referrer === "client") {
56
+ return "about:client";
57
+ }
58
+ if (this[INTERNALS].referrer) {
59
+ return this[INTERNALS].referrer.toString();
60
+ }
61
+ return void 0;
62
+ }
63
+ /** Returns the referrer policy associated with request. This is used during fetching to compute the value of the request's referrer. */
64
+ get referrerPolicy() {
65
+ return this[INTERNALS].referrerPolicy;
66
+ }
67
+ set referrerPolicy(referrerPolicy) {
68
+ this[INTERNALS].referrerPolicy = validateReferrerPolicy(referrerPolicy);
69
+ }
70
+ /** Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler. */
71
+ get signal() {
72
+ return this[INTERNALS].signal;
73
+ }
74
+ /** Returns the URL of request as a string. */
75
+ get url() {
76
+ return this[INTERNALS].parsedURL.toString();
77
+ }
78
+ get _uri() {
79
+ return GLib.Uri.parse(this.url, GLib.UriFlags.NONE);
80
+ }
81
+ get _session() {
82
+ return this[INTERNALS].session;
83
+ }
84
+ get _message() {
85
+ return this[INTERNALS].message;
86
+ }
87
+ get _inputStream() {
88
+ return this[INTERNALS].inputStream;
89
+ }
90
+ get [Symbol.toStringTag]() {
91
+ return "Request";
92
+ }
93
+ [INTERNALS];
94
+ // Node-fetch-only options
95
+ follow;
96
+ compress = false;
97
+ counter = 0;
98
+ agent = "";
99
+ highWaterMark = 16384;
100
+ insecureHTTPParser = false;
101
+ constructor(input, init) {
102
+ let parsedURL;
103
+ let requestObj = {};
104
+ if (isRequest(input)) {
105
+ parsedURL = new URL(input.url);
106
+ requestObj = input;
107
+ } else {
108
+ parsedURL = new URL(input);
109
+ }
110
+ if (parsedURL.username !== "" || parsedURL.password !== "") {
111
+ throw new TypeError(`${parsedURL} is an url with embedded credentials.`);
112
+ }
113
+ let method = init.method || requestObj.method || "GET";
114
+ if (/^(delete|get|head|options|post|put)$/i.test(method)) {
115
+ method = method.toUpperCase();
116
+ }
117
+ if ((init.body != null || isRequest(input) && input.body !== null) && (method === "GET" || method === "HEAD")) {
118
+ throw new TypeError("Request with GET/HEAD method cannot have body");
119
+ }
120
+ const inputBody = init.body ? init.body : isRequest(input) && input.body !== null ? clone(input) : null;
121
+ super(inputBody, {
122
+ size: init.size || init.size || 0
123
+ });
124
+ const headers = new Headers(init.headers || input.headers || {});
125
+ if (inputBody !== null && !headers.has("Content-Type")) {
126
+ const contentType = extractContentType(inputBody, this);
127
+ if (contentType) {
128
+ headers.set("Content-Type", contentType);
129
+ }
130
+ }
131
+ let signal = isRequest(input) ? input.signal : null;
132
+ if ("signal" in init) {
133
+ signal = init.signal;
134
+ }
135
+ if (signal != null && !isAbortSignal(signal)) {
136
+ throw new TypeError("Expected signal to be an instanceof AbortSignal or EventTarget");
137
+ }
138
+ let referrer = init.referrer == null ? input.referrer : init.referrer;
139
+ if (referrer === "") {
140
+ referrer = "no-referrer";
141
+ } else if (referrer) {
142
+ const parsedReferrer = new URL(referrer);
143
+ referrer = /^about:(\/\/)?client$/.test(parsedReferrer.toString()) ? "client" : parsedReferrer;
144
+ } else {
145
+ referrer = void 0;
146
+ }
147
+ const session = SoupExt.ExtSession.new();
148
+ const message = new Soup.Message({
149
+ method,
150
+ uri: this._uri
151
+ });
152
+ this[INTERNALS] = {
153
+ method,
154
+ redirect: init.redirect || input.redirect || "follow",
155
+ headers,
156
+ parsedURL,
157
+ signal,
158
+ referrer,
159
+ referrerPolicy: "",
160
+ session,
161
+ message
162
+ };
163
+ this.follow = init.follow === void 0 ? input.follow === void 0 ? 20 : input.follow : init.follow;
164
+ this.compress = init.compress === void 0 ? input.compress === void 0 ? true : input.compress : init.compress;
165
+ this.counter = init.counter || input.counter || 0;
166
+ this.agent = init.agent || input.agent;
167
+ this.highWaterMark = init.highWaterMark || input.highWaterMark || 16384;
168
+ this.insecureHTTPParser = init.insecureHTTPParser || input.insecureHTTPParser || false;
169
+ this.referrerPolicy = init.referrerPolicy || input.referrerPolicy || "";
170
+ }
171
+ /**
172
+ * Custom send method using Soup, used in fetch to send the request
173
+ * @param options
174
+ * @returns
175
+ */
176
+ async _send(options) {
177
+ options.headers._appendToSoupMessage(this._message);
178
+ const cancellable = new Gio.Cancellable();
179
+ this[INTERNALS].inputStream = await this._session.sendAsync(this._message, GLib.PRIORITY_DEFAULT, cancellable);
180
+ this[INTERNALS].readable = this[INTERNALS].inputStream.toReadable({});
181
+ return {
182
+ inputStream: this[INTERNALS].inputStream,
183
+ readable: this[INTERNALS].readable,
184
+ cancellable
185
+ };
186
+ }
187
+ /**
188
+ * Clone this request
189
+ */
190
+ clone() {
191
+ return new Request(this);
192
+ }
193
+ async arrayBuffer() {
194
+ return super.arrayBuffer();
195
+ }
196
+ async blob() {
197
+ return super.blob();
198
+ }
199
+ async formData() {
200
+ return super.formData();
201
+ }
202
+ async json() {
203
+ return super.json();
204
+ }
205
+ async text() {
206
+ return super.text();
207
+ }
208
+ }
209
+ Object.defineProperties(Request.prototype, {
210
+ method: { enumerable: true },
211
+ url: { enumerable: true },
212
+ headers: { enumerable: true },
213
+ redirect: { enumerable: true },
214
+ clone: { enumerable: true },
215
+ signal: { enumerable: true },
216
+ referrer: { enumerable: true },
217
+ referrerPolicy: { enumerable: true }
218
+ });
219
+ var request_default = Request;
220
+ const getSoupRequestOptions = (request) => {
221
+ const { parsedURL } = request[INTERNALS];
222
+ const headers = new Headers(request[INTERNALS].headers);
223
+ if (!headers.has("Accept")) {
224
+ headers.set("Accept", "*/*");
225
+ }
226
+ let contentLengthValue = null;
227
+ if (request.body === null && /^(post|put)$/i.test(request.method)) {
228
+ contentLengthValue = "0";
229
+ }
230
+ if (request.body !== null) {
231
+ const totalBytes = getTotalBytes(request);
232
+ if (typeof totalBytes === "number" && !Number.isNaN(totalBytes)) {
233
+ contentLengthValue = String(totalBytes);
234
+ }
235
+ }
236
+ if (contentLengthValue) {
237
+ headers.set("Content-Length", contentLengthValue);
238
+ }
239
+ if (request.referrerPolicy === "") {
240
+ request.referrerPolicy = DEFAULT_REFERRER_POLICY;
241
+ }
242
+ if (request.referrer && request.referrer !== "no-referrer") {
243
+ request[INTERNALS].referrer = determineRequestsReferrer(request);
244
+ } else {
245
+ request[INTERNALS].referrer = "no-referrer";
246
+ }
247
+ if (request[INTERNALS].referrer instanceof URL) {
248
+ headers.set("Referer", request.referrer);
249
+ }
250
+ if (!headers.has("User-Agent")) {
251
+ headers.set("User-Agent", "node-fetch");
252
+ }
253
+ if (request.compress && !headers.has("Accept-Encoding")) {
254
+ headers.set("Accept-Encoding", "gzip, deflate, br");
255
+ }
256
+ let { agent } = request;
257
+ if (typeof agent === "function") {
258
+ agent = agent(parsedURL);
259
+ }
260
+ if (!headers.has("Connection") && !agent) {
261
+ headers.set("Connection", "close");
262
+ }
263
+ const options = {
264
+ // Overwrite search to retain trailing ? (issue #776)
265
+ // path: parsedURL.pathname + search,
266
+ // The following options are not expressed in the URL
267
+ // method: request.method,
268
+ headers
269
+ // insecureHTTPParser: request.insecureHTTPParser,
270
+ // agent
271
+ };
272
+ return {
273
+ parsedURL,
274
+ options
275
+ };
276
+ };
277
+ export {
278
+ Request,
279
+ request_default as default,
280
+ getSoupRequestOptions
281
+ };
@@ -0,0 +1,133 @@
1
+ import GLib from "@girs/glib-2.0";
2
+ import Gio from "@girs/gio-2.0";
3
+ import Headers from "./headers.js";
4
+ import Body, { clone, extractContentType } from "./body.js";
5
+ import { isRedirect } from "./utils/is-redirect.js";
6
+ import { URL } from "@gjsify/deno-runtime/ext/url/00_url";
7
+ const INTERNALS = Symbol("Response internals");
8
+ class Response extends Body {
9
+ [INTERNALS];
10
+ _inputStream = null;
11
+ constructor(body = null, options = {}) {
12
+ super(body, options);
13
+ const status = options.status != null ? options.status : 200;
14
+ const headers = new Headers(options.headers);
15
+ if (body !== null && !headers.has("Content-Type")) {
16
+ const contentType = extractContentType(body, this);
17
+ if (contentType) {
18
+ headers.append("Content-Type", contentType);
19
+ }
20
+ }
21
+ this[INTERNALS] = {
22
+ type: "default",
23
+ url: options.url,
24
+ status,
25
+ statusText: options.statusText || "",
26
+ headers,
27
+ counter: options.counter,
28
+ highWaterMark: options.highWaterMark
29
+ };
30
+ }
31
+ get type() {
32
+ return this[INTERNALS].type;
33
+ }
34
+ get url() {
35
+ return this[INTERNALS].url || "";
36
+ }
37
+ get status() {
38
+ return this[INTERNALS].status;
39
+ }
40
+ /**
41
+ * Convenience property representing if the request ended normally
42
+ */
43
+ get ok() {
44
+ return this[INTERNALS].status >= 200 && this[INTERNALS].status < 300;
45
+ }
46
+ get redirected() {
47
+ return this[INTERNALS].counter > 0;
48
+ }
49
+ get statusText() {
50
+ return this[INTERNALS].statusText;
51
+ }
52
+ get headers() {
53
+ return this[INTERNALS].headers;
54
+ }
55
+ get highWaterMark() {
56
+ return this[INTERNALS].highWaterMark;
57
+ }
58
+ /**
59
+ * Clone this response
60
+ *
61
+ * @return Response
62
+ */
63
+ // @ts-ignore
64
+ clone() {
65
+ return new Response(clone(this, this.highWaterMark), {
66
+ type: this.type,
67
+ url: this.url,
68
+ status: this.status,
69
+ statusText: this.statusText,
70
+ headers: this.headers,
71
+ ok: this.ok,
72
+ redirected: this.redirected,
73
+ size: this.size,
74
+ highWaterMark: this.highWaterMark
75
+ });
76
+ }
77
+ /**
78
+ * @param url The URL that the new response is to originate from.
79
+ * @param status An optional status code for the response (e.g., 302.)
80
+ * @returns A Response object.
81
+ */
82
+ static redirect(url, status = 302) {
83
+ if (!isRedirect(status)) {
84
+ throw new RangeError('Failed to execute "redirect" on "response": Invalid status code');
85
+ }
86
+ return new Response(null, {
87
+ headers: {
88
+ location: new URL(url).toString()
89
+ },
90
+ status
91
+ });
92
+ }
93
+ static error() {
94
+ const response = new Response(null, { status: 0, statusText: "" });
95
+ response[INTERNALS].type = "error";
96
+ return response;
97
+ }
98
+ get [Symbol.toStringTag]() {
99
+ return "Response";
100
+ }
101
+ async text() {
102
+ if (!this._inputStream) {
103
+ return super.text();
104
+ }
105
+ const outputStream = Gio.MemoryOutputStream.new_resizable();
106
+ await new Promise((resolve, reject) => {
107
+ outputStream.splice_async(this._inputStream, Gio.OutputStreamSpliceFlags.CLOSE_TARGET | Gio.OutputStreamSpliceFlags.CLOSE_SOURCE, GLib.PRIORITY_DEFAULT, null, (self, res) => {
108
+ try {
109
+ resolve(outputStream.splice_finish(res));
110
+ } catch (error) {
111
+ reject(error);
112
+ }
113
+ });
114
+ });
115
+ const bytes = outputStream.steal_as_bytes();
116
+ return new TextDecoder().decode(bytes.toArray());
117
+ }
118
+ }
119
+ Object.defineProperties(Response.prototype, {
120
+ type: { enumerable: true },
121
+ url: { enumerable: true },
122
+ status: { enumerable: true },
123
+ ok: { enumerable: true },
124
+ redirected: { enumerable: true },
125
+ statusText: { enumerable: true },
126
+ headers: { enumerable: true },
127
+ clone: { enumerable: true }
128
+ });
129
+ var response_default = Response;
130
+ export {
131
+ Response,
132
+ response_default as default
133
+ };
@@ -0,0 +1 @@
1
+ export * from "./system-error.js";
@@ -0,0 +1 @@
1
+ ;