@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.
Files changed (88) hide show
  1. package/README.md +27 -2
  2. package/globals.mjs +12 -0
  3. package/lib/body.d.ts +69 -0
  4. package/lib/body.js +375 -0
  5. package/lib/errors/abort-error.d.ts +7 -0
  6. package/lib/errors/abort-error.js +9 -0
  7. package/lib/errors/base.d.ts +6 -0
  8. package/lib/errors/base.js +17 -0
  9. package/lib/errors/fetch-error.d.ts +16 -0
  10. package/lib/errors/fetch-error.js +23 -0
  11. package/lib/esm/body.js +104 -56
  12. package/lib/esm/errors/base.js +3 -1
  13. package/lib/esm/headers.js +116 -131
  14. package/lib/esm/index.js +145 -190
  15. package/lib/esm/request.js +42 -41
  16. package/lib/esm/response.js +19 -4
  17. package/lib/esm/utils/blob-from.js +2 -98
  18. package/lib/esm/utils/data-uri.js +23 -0
  19. package/lib/esm/utils/is.js +7 -3
  20. package/lib/esm/utils/multipart-parser.js +5 -2
  21. package/lib/esm/utils/referrer.js +10 -10
  22. package/lib/esm/utils/soup-helpers.js +22 -0
  23. package/lib/headers.d.ts +33 -0
  24. package/lib/headers.js +195 -0
  25. package/lib/index.d.ts +18 -0
  26. package/lib/index.js +205 -0
  27. package/lib/request.d.ts +101 -0
  28. package/lib/request.js +308 -0
  29. package/lib/response.d.ts +73 -0
  30. package/lib/response.js +158 -0
  31. package/lib/types/index.d.ts +1 -0
  32. package/lib/types/index.js +1 -0
  33. package/lib/types/system-error.d.ts +11 -0
  34. package/lib/types/system-error.js +2 -0
  35. package/lib/utils/blob-from.d.ts +2 -0
  36. package/lib/utils/blob-from.js +4 -0
  37. package/lib/utils/data-uri.d.ts +10 -0
  38. package/lib/utils/data-uri.js +27 -0
  39. package/lib/utils/get-search.d.ts +1 -0
  40. package/lib/utils/get-search.js +8 -0
  41. package/lib/utils/is-redirect.d.ts +7 -0
  42. package/lib/utils/is-redirect.js +10 -0
  43. package/lib/utils/is.d.ts +35 -0
  44. package/lib/utils/is.js +74 -0
  45. package/lib/utils/multipart-parser.d.ts +2 -0
  46. package/lib/utils/multipart-parser.js +396 -0
  47. package/lib/utils/referrer.d.ts +76 -0
  48. package/lib/utils/referrer.js +283 -0
  49. package/lib/utils/soup-helpers.d.ts +12 -0
  50. package/lib/utils/soup-helpers.js +25 -0
  51. package/package.json +23 -27
  52. package/src/body.ts +181 -169
  53. package/src/errors/base.ts +3 -1
  54. package/src/headers.ts +155 -202
  55. package/src/index.spec.ts +268 -3
  56. package/src/index.ts +199 -312
  57. package/src/request.ts +84 -75
  58. package/src/response.ts +48 -18
  59. package/src/test.mts +1 -1
  60. package/src/utils/blob-from.ts +4 -164
  61. package/src/utils/data-uri.ts +29 -0
  62. package/src/utils/is.ts +15 -15
  63. package/src/utils/multipart-parser.ts +3 -3
  64. package/src/utils/referrer.ts +11 -11
  65. package/src/utils/soup-helpers.ts +37 -0
  66. package/tsconfig.json +4 -4
  67. package/tsconfig.tsbuildinfo +1 -0
  68. package/lib/cjs/body.js +0 -255
  69. package/lib/cjs/errors/abort-error.js +0 -9
  70. package/lib/cjs/errors/base.js +0 -17
  71. package/lib/cjs/errors/fetch-error.js +0 -21
  72. package/lib/cjs/headers.js +0 -202
  73. package/lib/cjs/index.js +0 -224
  74. package/lib/cjs/request.js +0 -281
  75. package/lib/cjs/response.js +0 -133
  76. package/lib/cjs/types/index.js +0 -1
  77. package/lib/cjs/types/system-error.js +0 -1
  78. package/lib/cjs/utils/blob-from.js +0 -101
  79. package/lib/cjs/utils/get-search.js +0 -11
  80. package/lib/cjs/utils/is-redirect.js +0 -7
  81. package/lib/cjs/utils/is.js +0 -28
  82. package/lib/cjs/utils/multipart-parser.js +0 -353
  83. package/lib/cjs/utils/referrer.js +0 -153
  84. package/test.gjs.js +0 -34758
  85. package/test.gjs.mjs +0 -53172
  86. package/test.node.js +0 -1226
  87. package/test.node.mjs +0 -6273
  88. package/tsconfig.types.json +0 -8
@@ -0,0 +1,283 @@
1
+ import { URL } from '@gjsify/url';
2
+ import { isIP } from 'node:net';
3
+ /**
4
+ * @external URL
5
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/URL URL}
6
+ */
7
+ /**
8
+ * @module utils/referrer
9
+ * @private
10
+ */
11
+ /**
12
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#strip-url Referrer Policy §8.4. Strip url for use as a referrer}
13
+ * @param url
14
+ * @param originOnly
15
+ */
16
+ export function stripURLForUseAsAReferrer(url, originOnly = false) {
17
+ // 1. If url is null, return no referrer.
18
+ if (url == null || url === "no-referrer") { // eslint-disable-line no-eq-null, eqeqeq
19
+ return 'no-referrer';
20
+ }
21
+ const u = new URL(url);
22
+ // 2. If url's scheme is a local scheme, then return no referrer.
23
+ if (/^(about|blob|data):$/.test(u.protocol)) {
24
+ return 'no-referrer';
25
+ }
26
+ // 3. Set url's username to the empty string.
27
+ u.username = '';
28
+ // 4. Set url's password to null.
29
+ // Note: `null` appears to be a mistake as this actually results in the password being `"null"`.
30
+ u.password = '';
31
+ // 5. Set url's fragment to null.
32
+ // Note: `null` appears to be a mistake as this actually results in the fragment being `"#null"`.
33
+ u.hash = '';
34
+ // 6. If the origin-only flag is true, then:
35
+ if (originOnly) {
36
+ // 6.1. Set url's path to null.
37
+ // Note: `null` appears to be a mistake as this actually results in the path being `"/null"`.
38
+ u.pathname = '';
39
+ // 6.2. Set url's query to null.
40
+ // Note: `null` appears to be a mistake as this actually results in the query being `"?null"`.
41
+ u.search = '';
42
+ }
43
+ // 7. Return url.
44
+ return u;
45
+ }
46
+ /**
47
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#enumdef-referrerpolicy enum ReferrerPolicy}
48
+ */
49
+ export const ReferrerPolicy = new Set([
50
+ '',
51
+ 'no-referrer',
52
+ 'no-referrer-when-downgrade',
53
+ 'same-origin',
54
+ 'origin',
55
+ 'strict-origin',
56
+ 'origin-when-cross-origin',
57
+ 'strict-origin-when-cross-origin',
58
+ 'unsafe-url'
59
+ ]);
60
+ /**
61
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#default-referrer-policy default referrer policy}
62
+ */
63
+ export const DEFAULT_REFERRER_POLICY = 'strict-origin-when-cross-origin';
64
+ /**
65
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#referrer-policies Referrer Policy §3. Referrer Policies}
66
+ * @param referrerPolicy
67
+ * @returns referrerPolicy
68
+ */
69
+ export function validateReferrerPolicy(referrerPolicy) {
70
+ if (!ReferrerPolicy.has(referrerPolicy)) {
71
+ throw new TypeError(`Invalid referrerPolicy: ${referrerPolicy}`);
72
+ }
73
+ return referrerPolicy;
74
+ }
75
+ /**
76
+ * @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy Referrer Policy §3.2. Is origin potentially trustworthy?}
77
+ * @param url
78
+ * @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy"
79
+ */
80
+ export function isOriginPotentiallyTrustworthy(url) {
81
+ // 1. If origin is an opaque origin, return "Not Trustworthy".
82
+ // Not applicable
83
+ // 2. Assert: origin is a tuple origin.
84
+ // Not for implementations
85
+ // 3. If origin's scheme is either "https" or "wss", return "Potentially Trustworthy".
86
+ if (/^(http|ws)s:$/.test(url.protocol)) {
87
+ return true;
88
+ }
89
+ // 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
+ const hostIp = url.host.replace(/(^\[)|(]$)/g, '');
91
+ const hostIPVersion = isIP(hostIp);
92
+ if (hostIPVersion === 4 && /^127\./.test(hostIp)) {
93
+ return true;
94
+ }
95
+ if (hostIPVersion === 6 && /^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(hostIp)) {
96
+ return true;
97
+ }
98
+ // 5. If origin's host component is "localhost" or falls within ".localhost", and the user agent conforms to the name resolution rules in [let-localhost-be-localhost], return "Potentially Trustworthy".
99
+ // We are returning FALSE here because we cannot ensure conformance to
100
+ // let-localhost-be-loalhost (https://tools.ietf.org/html/draft-west-let-localhost-be-localhost)
101
+ if (url.host === 'localhost' || url.host.endsWith('.localhost')) {
102
+ return false;
103
+ }
104
+ // 6. If origin's scheme component is file, return "Potentially Trustworthy".
105
+ if (url.protocol === 'file:') {
106
+ return true;
107
+ }
108
+ // 7. If origin's scheme component is one which the user agent considers to be authenticated, return "Potentially Trustworthy".
109
+ // Not supported
110
+ // 8. If origin has been configured as a trustworthy origin, return "Potentially Trustworthy".
111
+ // Not supported
112
+ // 9. Return "Not Trustworthy".
113
+ return false;
114
+ }
115
+ /**
116
+ * @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-url-trustworthy Referrer Policy §3.3. Is url potentially trustworthy?}
117
+ * @param url
118
+ * @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy"
119
+ */
120
+ export function isUrlPotentiallyTrustworthy(url) {
121
+ // 1. If url is "about:blank" or "about:srcdoc", return "Potentially Trustworthy".
122
+ if (/^about:(blank|srcdoc)$/.test(url.toString())) {
123
+ return true;
124
+ }
125
+ if (typeof url === 'string') {
126
+ url = new URL(url);
127
+ }
128
+ // 2. If url's scheme is "data", return "Potentially Trustworthy".
129
+ if (url.protocol === 'data:') {
130
+ return true;
131
+ }
132
+ // Note: The origin of blob: and filesystem: URLs is the origin of the context in which they were
133
+ // created. Therefore, blobs created in a trustworthy origin will themselves be potentially
134
+ // trustworthy.
135
+ if (/^(blob|filesystem):$/.test(url.protocol)) {
136
+ return true;
137
+ }
138
+ // 3. Return the result of executing §3.2 Is origin potentially trustworthy? on url's origin.
139
+ return isOriginPotentiallyTrustworthy(url);
140
+ }
141
+ /**
142
+ * Modifies the referrerURL to enforce any extra security policy considerations.
143
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}, step 7
144
+ * @callback module:utils/referrer~referrerURLCallback
145
+ * @param {external:URL} referrerURL
146
+ * @returns {external:URL} modified referrerURL
147
+ */
148
+ /**
149
+ * Modifies the referrerOrigin to enforce any extra security policy considerations.
150
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}, step 7
151
+ * @callback module:utils/referrer~referrerOriginCallback
152
+ * @param {external:URL} referrerOrigin
153
+ * @returns {external:URL} modified referrerOrigin
154
+ */
155
+ /**
156
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}
157
+ * @param request
158
+ * @param {object} o
159
+ * @param {module:utils/referrer~referrerURLCallback} o.referrerURLCallback
160
+ * @param {module:utils/referrer~referrerOriginCallback} o.referrerOriginCallback
161
+ * @returns {external:URL} Request's referrer
162
+ */
163
+ export function determineRequestsReferrer(request, obj = {}) {
164
+ const { referrerURLCallback, referrerOriginCallback } = obj;
165
+ // There are 2 notes in the specification about invalid pre-conditions. We return null, here, for
166
+ // these cases:
167
+ // > Note: If request's referrer is "no-referrer", Fetch will not call into this algorithm.
168
+ // > Note: If request's referrer policy is the empty string, Fetch will not call into this
169
+ // > algorithm.
170
+ if (request.referrer === 'no-referrer' || request.referrerPolicy === '') {
171
+ return null;
172
+ }
173
+ // 1. Let policy be request's associated referrer policy.
174
+ const policy = request.referrerPolicy;
175
+ // 2. Let environment be request's client.
176
+ // not applicable to node.js
177
+ // 3. Switch on request's referrer:
178
+ if (request.referrer === 'about:client') {
179
+ return 'no-referrer';
180
+ }
181
+ // "a URL": Let referrerSource be request's referrer.
182
+ const referrerSource = new URL(request.referrer);
183
+ // 4. Let request's referrerURL be the result of stripping referrerSource for use as a referrer.
184
+ let referrerURL = stripURLForUseAsAReferrer(referrerSource);
185
+ // 5. Let referrerOrigin be the result of stripping referrerSource for use as a referrer, with the
186
+ // origin-only flag set to true.
187
+ let referrerOrigin = stripURLForUseAsAReferrer(referrerSource, true);
188
+ // 6. If the result of serializing referrerURL is a string whose length is greater than 4096, set
189
+ // referrerURL to referrerOrigin.
190
+ if (referrerURL.toString().length > 4096) {
191
+ referrerURL = referrerOrigin;
192
+ }
193
+ // 7. The user agent MAY alter referrerURL or referrerOrigin at this point to enforce arbitrary
194
+ // policy considerations in the interests of minimizing data leakage. For example, the user
195
+ // agent could strip the URL down to an origin, modify its host, replace it with an empty
196
+ // string, etc.
197
+ if (referrerURLCallback) {
198
+ referrerURL = referrerURLCallback(referrerURL);
199
+ }
200
+ if (referrerOriginCallback) {
201
+ referrerOrigin = referrerOriginCallback(referrerOrigin);
202
+ }
203
+ // 8.Execute the statements corresponding to the value of policy:
204
+ const currentURL = new URL(request.url);
205
+ switch (policy) {
206
+ case 'no-referrer':
207
+ return 'no-referrer';
208
+ case 'origin':
209
+ return referrerOrigin;
210
+ case 'unsafe-url':
211
+ return referrerURL;
212
+ case 'strict-origin':
213
+ // 1. If referrerURL is a potentially trustworthy URL and request's current URL is not a
214
+ // potentially trustworthy URL, then return no referrer.
215
+ if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
216
+ return 'no-referrer';
217
+ }
218
+ // 2. Return referrerOrigin.
219
+ return referrerOrigin.toString();
220
+ case 'strict-origin-when-cross-origin':
221
+ // 1. If the origin of referrerURL and the origin of request's current URL are the same, then
222
+ // return referrerURL.
223
+ if (referrerURL.origin === currentURL.origin) {
224
+ return referrerURL;
225
+ }
226
+ // 2. If referrerURL is a potentially trustworthy URL and request's current URL is not a
227
+ // potentially trustworthy URL, then return no referrer.
228
+ if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
229
+ return 'no-referrer';
230
+ }
231
+ // 3. Return referrerOrigin.
232
+ return referrerOrigin;
233
+ case 'same-origin':
234
+ // 1. If the origin of referrerURL and the origin of request's current URL are the same, then
235
+ // return referrerURL.
236
+ if (referrerURL.origin === currentURL.origin) {
237
+ return referrerURL;
238
+ }
239
+ // 2. Return no referrer.
240
+ return 'no-referrer';
241
+ case 'origin-when-cross-origin':
242
+ // 1. If the origin of referrerURL and the origin of request's current URL are the same, then
243
+ // return referrerURL.
244
+ if (referrerURL.origin === currentURL.origin) {
245
+ return referrerURL;
246
+ }
247
+ // Return referrerOrigin.
248
+ return referrerOrigin;
249
+ case 'no-referrer-when-downgrade':
250
+ // 1. If referrerURL is a potentially trustworthy URL and request's current URL is not a
251
+ // potentially trustworthy URL, then return no referrer.
252
+ if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
253
+ return 'no-referrer';
254
+ }
255
+ // 2. Return referrerURL.
256
+ return referrerURL;
257
+ default:
258
+ throw new TypeError(`Invalid referrerPolicy: ${policy}`);
259
+ }
260
+ }
261
+ /**
262
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#parse-referrer-policy-from-header|Referrer Policy §8.1. Parse a referrer policy from a Referrer-Policy header}
263
+ * @param {Headers} headers Response headers
264
+ * @returns {string} policy
265
+ */
266
+ export function parseReferrerPolicyFromHeader(headers) {
267
+ // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy`
268
+ // and response’s header list.
269
+ const policyTokens = (headers.get('referrer-policy') || '').split(/[,\s]+/);
270
+ // 2. Let policy be the empty string.
271
+ let policy = '';
272
+ // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty
273
+ // string, then set policy to token.
274
+ // Note: This algorithm loops over multiple policy values to allow deployment of new policy
275
+ // values with fallbacks for older user agents, as described in § 11.1 Unknown Policy Values.
276
+ for (const token of policyTokens) {
277
+ if (token && ReferrerPolicy.has(token)) {
278
+ policy = token;
279
+ }
280
+ }
281
+ // 4. Return policy.
282
+ return policy;
283
+ }
@@ -0,0 +1,12 @@
1
+ import Gio from '@girs/gio-2.0';
2
+ import Soup from '@girs/soup-3.0';
3
+ import { Readable } from 'node:stream';
4
+ import type { ReadableOptions } from 'node:stream';
5
+ /**
6
+ * Promise wrapper around `Soup.Session.send_async` / `send_finish`.
7
+ */
8
+ export declare function soupSendAsync(session: Soup.Session, msg: Soup.Message, ioPriority?: number, cancellable?: Gio.Cancellable | null): Promise<Gio.InputStream>;
9
+ /**
10
+ * Converts a `Gio.InputStream` to a Node.js `Readable` stream.
11
+ */
12
+ export declare function inputStreamToReadable(inputStream: Gio.InputStream, options?: ReadableOptions): Readable;
@@ -0,0 +1,25 @@
1
+ import GLib from '@girs/glib-2.0';
2
+ import { Readable } from 'node:stream';
3
+ import { inputStreamAsyncIterator } from '@gjsify/utils';
4
+ /**
5
+ * Promise wrapper around `Soup.Session.send_async` / `send_finish`.
6
+ */
7
+ export async function soupSendAsync(session, msg, ioPriority = GLib.PRIORITY_DEFAULT, cancellable = null) {
8
+ return new Promise((resolve, reject) => {
9
+ session.send_async(msg, ioPriority, cancellable, (_self, asyncRes) => {
10
+ try {
11
+ const inputStream = session.send_finish(asyncRes);
12
+ resolve(inputStream);
13
+ }
14
+ catch (error) {
15
+ reject(error);
16
+ }
17
+ });
18
+ });
19
+ }
20
+ /**
21
+ * Converts a `Gio.InputStream` to a Node.js `Readable` stream.
22
+ */
23
+ export function inputStreamToReadable(inputStream, options = {}) {
24
+ return Readable.from(inputStreamAsyncIterator(inputStream), options);
25
+ }
package/package.json CHANGED
@@ -1,32 +1,27 @@
1
1
  {
2
2
  "name": "@gjsify/fetch",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "description": "Web and Node.js fetch module for Gjs",
5
- "main": "lib/cjs/index.js",
6
5
  "module": "lib/esm/index.js",
6
+ "types": "lib/types/index.d.ts",
7
7
  "type": "module",
8
8
  "exports": {
9
9
  ".": {
10
- "import": {
11
- "types": "./lib/types/index.d.ts",
12
- "default": "./lib/esm/index.js"
13
- },
14
- "require": {
15
- "types": "./lib/types/index.d.ts",
16
- "default": "./lib/cjs/index.js"
17
- }
18
- }
10
+ "types": "./lib/types/index.d.ts",
11
+ "default": "./lib/esm/index.js"
12
+ },
13
+ "./globals": "./globals.mjs"
19
14
  },
20
15
  "scripts": {
21
- "clear": "rm -rf lib tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo || exit 0",
22
- "print:name": "echo '@gjsify/fetch'",
23
- "build": "yarn print:name && yarn build:gjsify",
16
+ "clear": "rm -rf lib tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
17
+ "check": "tsc --noEmit",
18
+ "build": "yarn build:gjsify && yarn build:types",
24
19
  "build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.{mts,ts}'",
25
- "build:types": "tsc --project tsconfig.types.json",
20
+ "build:types": "tsc",
26
21
  "build:test": "yarn build:test:gjs && yarn build:test:node",
27
22
  "build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
28
23
  "build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
29
- "test": "yarn print:name && yarn build:gjsify && yarn build:test && yarn test:node && yarn test:gjs",
24
+ "test": "yarn build:gjsify && yarn build:test:node && yarn test:node",
30
25
  "test:gjs": "gjs -m test.gjs.mjs",
31
26
  "test:node": "node test.node.mjs"
32
27
  },
@@ -36,18 +31,19 @@
36
31
  "fetch"
37
32
  ],
38
33
  "devDependencies": {
39
- "@gjsify/cli": "^0.0.4",
40
- "@gjsify/http": "^0.0.4",
41
- "@gjsify/unit": "^0.0.4",
42
- "@types/node": "^20.10.5"
34
+ "@gjsify/cli": "^0.1.0",
35
+ "@gjsify/unit": "^0.1.0",
36
+ "@types/node": "^25.5.0",
37
+ "typescript": "^6.0.2"
43
38
  },
44
39
  "dependencies": {
45
- "@gjsify/deno-runtime": "^0.0.4",
46
- "@gjsify/gio-2.0": "^0.0.4",
47
- "@gjsify/soup-3.0": "^0.0.4",
48
- "@types/node-fetch": "^2.6.10",
49
- "data-uri-to-buffer": "^6.0.1",
50
- "formdata-polyfill": "^4.0.10",
51
- "node-fetch": "^3.3.2"
40
+ "@girs/gio-2.0": "^2.88.0-4.0.0-beta.42",
41
+ "@girs/gjs": "^4.0.0-beta.42",
42
+ "@girs/glib-2.0": "^2.88.0-4.0.0-beta.42",
43
+ "@girs/soup-3.0": "^3.6.6-4.0.0-beta.42",
44
+ "@gjsify/formdata": "^0.1.0",
45
+ "@gjsify/http": "^0.1.0",
46
+ "@gjsify/url": "^0.1.0",
47
+ "@gjsify/utils": "^0.1.0"
52
48
  }
53
49
  }