@gjsify/fetch 0.35.0 → 0.37.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/lib/body.d.ts +18 -0
- package/lib/body.js +23 -1
- package/lib/esm/body.js +1 -1
- package/lib/index.spec.js +32 -0
- package/lib/utils/root-relative.d.ts +11 -17
- package/lib/utils/root-relative.js +21 -35
- package/package.json +8 -8
package/lib/body.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export default class Body {
|
|
|
19
19
|
[INTERNALS]: {
|
|
20
20
|
body: null | Buffer | Readable | Blob;
|
|
21
21
|
stream: Readable | null;
|
|
22
|
+
/** Memoized `body` wrapper — see the getter for why identity matters. */
|
|
23
|
+
webStream: ReadableStream<Uint8Array> | null;
|
|
22
24
|
boundary: string;
|
|
23
25
|
disturbed: boolean;
|
|
24
26
|
error: null | FetchBaseError;
|
|
@@ -28,6 +30,22 @@ export default class Body {
|
|
|
28
30
|
size?: number;
|
|
29
31
|
headers?: unknown;
|
|
30
32
|
});
|
|
33
|
+
/**
|
|
34
|
+
* The body as a `ReadableStream`.
|
|
35
|
+
*
|
|
36
|
+
* Per the Fetch spec `body` is an ATTRIBUTE holding one stream, so every
|
|
37
|
+
* read must return the SAME object — `res.body === res.body`. This used to
|
|
38
|
+
* build a fresh wrapper per access, each one subscribing to the same
|
|
39
|
+
* already-flowing `Readable`: the first reader got every byte and every
|
|
40
|
+
* later one got an immediate `done`, with no error anywhere.
|
|
41
|
+
*
|
|
42
|
+
* That is not a theoretical spec detail. Consumers legitimately touch
|
|
43
|
+
* `.body` several times in a row — three.js' `FileLoader` guards with
|
|
44
|
+
* `response.body === undefined`, then `response.body.getReader === undefined`,
|
|
45
|
+
* and only then calls `response.body.getReader()`, so it read the THIRD,
|
|
46
|
+
* empty stream. Downstream: an empty response text, an LDraw model that
|
|
47
|
+
* parsed to zero meshes, and a viewer showing nothing but its clear colour.
|
|
48
|
+
*/
|
|
31
49
|
get body(): ReadableStream<Uint8Array> | null;
|
|
32
50
|
get _stream(): Readable;
|
|
33
51
|
/** Return the raw body buffer without consuming the stream (used by Request._send). */
|
package/lib/body.js
CHANGED
|
@@ -34,6 +34,7 @@ export default class Body {
|
|
|
34
34
|
[INTERNALS] = {
|
|
35
35
|
body: null,
|
|
36
36
|
stream: null,
|
|
37
|
+
webStream: null,
|
|
37
38
|
boundary: '',
|
|
38
39
|
disturbed: false,
|
|
39
40
|
error: null,
|
|
@@ -110,14 +111,33 @@ export default class Body {
|
|
|
110
111
|
});
|
|
111
112
|
}
|
|
112
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* The body as a `ReadableStream`.
|
|
116
|
+
*
|
|
117
|
+
* Per the Fetch spec `body` is an ATTRIBUTE holding one stream, so every
|
|
118
|
+
* read must return the SAME object — `res.body === res.body`. This used to
|
|
119
|
+
* build a fresh wrapper per access, each one subscribing to the same
|
|
120
|
+
* already-flowing `Readable`: the first reader got every byte and every
|
|
121
|
+
* later one got an immediate `done`, with no error anywhere.
|
|
122
|
+
*
|
|
123
|
+
* That is not a theoretical spec detail. Consumers legitimately touch
|
|
124
|
+
* `.body` several times in a row — three.js' `FileLoader` guards with
|
|
125
|
+
* `response.body === undefined`, then `response.body.getReader === undefined`,
|
|
126
|
+
* and only then calls `response.body.getReader()`, so it read the THIRD,
|
|
127
|
+
* empty stream. Downstream: an empty response text, an LDraw model that
|
|
128
|
+
* parsed to zero meshes, and a viewer showing nothing but its clear colour.
|
|
129
|
+
*/
|
|
113
130
|
get body() {
|
|
114
131
|
const stream = this[INTERNALS].stream;
|
|
115
132
|
if (!stream)
|
|
116
133
|
return null;
|
|
134
|
+
const memoized = this[INTERNALS].webStream;
|
|
135
|
+
if (memoized)
|
|
136
|
+
return memoized;
|
|
117
137
|
// If ReadableStream is available, wrap the Readable into one
|
|
118
138
|
if (typeof ReadableStream !== 'undefined') {
|
|
119
139
|
let closed = false;
|
|
120
|
-
|
|
140
|
+
const webStream = new ReadableStream({
|
|
121
141
|
start(controller) {
|
|
122
142
|
stream.on('data', (chunk) => {
|
|
123
143
|
if (closed)
|
|
@@ -160,6 +180,8 @@ export default class Body {
|
|
|
160
180
|
stream.destroy();
|
|
161
181
|
},
|
|
162
182
|
});
|
|
183
|
+
this[INTERNALS].webStream = webStream;
|
|
184
|
+
return webStream;
|
|
163
185
|
}
|
|
164
186
|
return null;
|
|
165
187
|
}
|
package/lib/esm/body.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__name as e}from"./_virtual/_rolldown/runtime.js";import{Blob as t}from"./utils/blob-from.js";import{FetchBaseError as n}from"./errors/base.js";import{FetchError as r}from"./errors/fetch-error.js";import{isBlob as i,isURLSearchParameters as a}from"./utils/is.js";import{URLSearchParams as o}from"@gjsify/url";import{Buffer as s}from"node:buffer";import{PassThrough as c,Readable as l,Stream as u,pipeline as d}from"node:stream";import{FormData as f,formDataToBlob as p}from"@gjsify/formdata";const m=e((e,t)=>new Promise((n,r)=>{d(e,t,e=>{e?r(e):n()})}),`pipeline`),h=Symbol(`Body internals`);function isAnyArrayBuffer(e){return e instanceof ArrayBuffer||typeof SharedArrayBuffer<`u`&&e instanceof SharedArrayBuffer}var Body=class{[h]={body:null,stream:null,boundary:``,disturbed:!1,error:null};size=0;constructor(e,t={size:0}){if(this.size=t.size||0,e==null)this[h].body=null;else if(a(e))this[h].body=s.from(e.toString());else if(i(e))this[h].body=e;else if(s.isBuffer(e))this[h].body=e;else if(isAnyArrayBuffer(e))this[h].body=s.from(e);else if(ArrayBuffer.isView(e))this[h].body=s.from(e.buffer,e.byteOffset,e.byteLength);else if(e instanceof l)this[h].body=e;else if(typeof ReadableStream<`u`&&e instanceof ReadableStream)this[h].body=readableStreamToReadable(e);else if(e instanceof f){let t=p(e);this[h].body=t,this[h].boundary=t.type?.split(`boundary=`)?.[1]??``}else typeof e==`string`?this[h].body=s.from(e):e instanceof o?this[h].body=s.from(e.toString()):(console.warn(`Unknown body type "${typeof e}", try to parse the body to string!`),this[h].body=s.from(String(e)));let c=this[h].body;s.isBuffer(c)?this[h].stream=l.from(c):i(c)?this[h].stream=l.from(blobToAsyncIterable(c)):c instanceof l&&(this[h].stream=c),c instanceof u&&c.on(`error`,e=>{let t=e instanceof n?e:new r(`Invalid response body while trying to fetch ${this.url}: ${e.message}`,`system`,e);this[h].error=t})}get body(){let e=this[h].stream;if(!e)return null;if(typeof ReadableStream<`u`){let t=!1
|
|
1
|
+
import{__name as e}from"./_virtual/_rolldown/runtime.js";import{Blob as t}from"./utils/blob-from.js";import{FetchBaseError as n}from"./errors/base.js";import{FetchError as r}from"./errors/fetch-error.js";import{isBlob as i,isURLSearchParameters as a}from"./utils/is.js";import{URLSearchParams as o}from"@gjsify/url";import{Buffer as s}from"node:buffer";import{PassThrough as c,Readable as l,Stream as u,pipeline as d}from"node:stream";import{FormData as f,formDataToBlob as p}from"@gjsify/formdata";const m=e((e,t)=>new Promise((n,r)=>{d(e,t,e=>{e?r(e):n()})}),`pipeline`),h=Symbol(`Body internals`);function isAnyArrayBuffer(e){return e instanceof ArrayBuffer||typeof SharedArrayBuffer<`u`&&e instanceof SharedArrayBuffer}var Body=class{[h]={body:null,stream:null,webStream:null,boundary:``,disturbed:!1,error:null};size=0;constructor(e,t={size:0}){if(this.size=t.size||0,e==null)this[h].body=null;else if(a(e))this[h].body=s.from(e.toString());else if(i(e))this[h].body=e;else if(s.isBuffer(e))this[h].body=e;else if(isAnyArrayBuffer(e))this[h].body=s.from(e);else if(ArrayBuffer.isView(e))this[h].body=s.from(e.buffer,e.byteOffset,e.byteLength);else if(e instanceof l)this[h].body=e;else if(typeof ReadableStream<`u`&&e instanceof ReadableStream)this[h].body=readableStreamToReadable(e);else if(e instanceof f){let t=p(e);this[h].body=t,this[h].boundary=t.type?.split(`boundary=`)?.[1]??``}else typeof e==`string`?this[h].body=s.from(e):e instanceof o?this[h].body=s.from(e.toString()):(console.warn(`Unknown body type "${typeof e}", try to parse the body to string!`),this[h].body=s.from(String(e)));let c=this[h].body;s.isBuffer(c)?this[h].stream=l.from(c):i(c)?this[h].stream=l.from(blobToAsyncIterable(c)):c instanceof l&&(this[h].stream=c),c instanceof u&&c.on(`error`,e=>{let t=e instanceof n?e:new r(`Invalid response body while trying to fetch ${this.url}: ${e.message}`,`system`,e);this[h].error=t})}get body(){let e=this[h].stream;if(!e)return null;let t=this[h].webStream;if(t)return t;if(typeof ReadableStream<`u`){let t=!1,n=new ReadableStream({start(n){e.on(`data`,e=>{if(!t)try{n.enqueue(e instanceof Uint8Array?e:new Uint8Array(e))}catch{}}),e.on(`end`,()=>{if(!t){t=!0;try{n.close()}catch{}}}),e.on(`error`,e=>{if(!t){t=!0;try{n.error(e)}catch{}}})},cancel(){t=!0,e.destroy()}});return this[h].webStream=n,n}return null}get _stream(){return this[h].stream}get _rawBodyBuffer(){let e=this[h].body;return e===null?null:s.isBuffer(e)?e:e instanceof Uint8Array?s.from(e.buffer,e.byteOffset,e.byteLength):null}get bodyUsed(){return this[h].disturbed}async arrayBuffer(){let{buffer:e,byteOffset:t,byteLength:n}=await consumeBody(this);return e.slice(t,t+n)}async formData(){let e=this.headers?.get(`content-type`);if(e?.startsWith(`application/x-www-form-urlencoded`)){let e=new f,t=new o(await this.text());for(let[n,r]of t)e.append(n,r);return e}let{toFormData:t}=await import(`./utils/multipart-parser.js`);return t(this.body,e)}async blob(){let e=this.headers?.get(`content-type`)||this[h].body&&this[h].body.type||``;return new t([await this.arrayBuffer()],{type:e})}async json(){let e=await this.text();return JSON.parse(e)}async text(){let e=await consumeBody(this);return new TextDecoder().decode(e)}};Object.defineProperties(Body.prototype,{body:{enumerable:!0},bodyUsed:{enumerable:!0},arrayBuffer:{enumerable:!0},blob:{enumerable:!0},json:{enumerable:!0},text:{enumerable:!0}});async function consumeBody(e){if(e[h].disturbed)throw TypeError(`body used already for: ${e.url}`);if(e[h].disturbed=!0,e[h].error)throw e[h].error;let{_stream:t}=e;if(t===null||!(t instanceof u))return s.alloc(0);let i=[],a=0;try{for await(let n of t){if(e.size>0&&a+n.length>e.size){let n=new r(`content size at ${e.url} over limit: ${e.size}`,`max-size`);throw t.destroy(n),n}a+=n.length,i.push(n)}}catch(t){let i=t instanceof Error?t:Error(String(t));throw t instanceof n?t:new r(`Invalid response body while trying to fetch ${e.url}: ${i.message}`,`system`,i)}try{return i.every(e=>typeof e==`string`)?s.from(i.join(``)):s.concat(i,a)}catch(t){let n=t instanceof Error?t:Error(String(t));throw new r(`Could not create Buffer from response body for ${e.url}: ${n.message}`,`system`,n)}}const clone=(e,t)=>{let n,r,{body:i}=e[h];if(e.bodyUsed)throw Error(`cannot clone body after it is used`);return i instanceof u&&typeof i.getBoundary!=`function`&&(n=new c({highWaterMark:t}),r=new c({highWaterMark:t}),i.pipe(n),i.pipe(r),e[h].stream=n,i=r),i},extractContentType=(e,t)=>e===null?null:typeof e==`string`?`text/plain;charset=UTF-8`:a(e)?`application/x-www-form-urlencoded;charset=UTF-8`:i(e)?e.type||null:s.isBuffer(e)||isAnyArrayBuffer(e)||ArrayBuffer.isView(e)?null:e instanceof f?`multipart/form-data; boundary=${t[h].boundary}`:e instanceof u?null:`text/plain;charset=UTF-8`,getTotalBytes=e=>{let{body:t}=e[h];if(t===null)return 0;if(i(t))return t.size;if(s.isBuffer(t))return t.length;if(t&&typeof t.getLengthSync==`function`){let e=t;return e.hasKnownLength&&e.hasKnownLength()?e.getLengthSync():null}return null},writeToStream=async(e,{body:t})=>{t===null?e.end():await m(t,e)};function readableStreamToReadable(e){let t=e.getReader();return new l({async read(){try{let{done:e,value:n}=await t.read();e?this.push(null):this.push(s.from(n))}catch(e){this.destroy(e)}},destroy(e,n){t.cancel().then(()=>n(null),n)}})}async function*blobToAsyncIterable(e){if(typeof e.stream==`function`){let t=e.stream().getReader();for(;;){let{done:e,value:n}=await t.read();if(e)break;yield n}}else yield new Uint8Array(await e.arrayBuffer())}export{clone,Body as default,extractContentType,getTotalBytes,writeToStream};
|
package/lib/index.spec.js
CHANGED
|
@@ -197,6 +197,38 @@ export default async () => {
|
|
|
197
197
|
await r.text();
|
|
198
198
|
expect(r.bodyUsed).toBe(true);
|
|
199
199
|
});
|
|
200
|
+
// `body` is an ATTRIBUTE holding one stream, not a factory. Reading it
|
|
201
|
+
// twice used to build two wrappers over the same flowing Readable, so
|
|
202
|
+
// the first reader drained everything and every later one saw an
|
|
203
|
+
// immediate `done` — silently, with no error. three.js' FileLoader
|
|
204
|
+
// reads `.body` three times in its feature guard before taking a
|
|
205
|
+
// reader, and so received an empty document.
|
|
206
|
+
await it('should return the same body stream on every read', async () => {
|
|
207
|
+
const r = new Response('stable body');
|
|
208
|
+
expect(r.body).toBe(r.body);
|
|
209
|
+
});
|
|
210
|
+
await it('should deliver the full body to a reader taken after re-reading body', async () => {
|
|
211
|
+
const r = new Response('the whole payload');
|
|
212
|
+
// Touch `.body` twice first, exactly like a feature guard does.
|
|
213
|
+
expect(r.body !== undefined).toBe(true);
|
|
214
|
+
expect(typeof r.body?.getReader).toBe('function');
|
|
215
|
+
const reader = r.body.getReader();
|
|
216
|
+
const chunks = [];
|
|
217
|
+
for (;;) {
|
|
218
|
+
const { done, value } = await reader.read();
|
|
219
|
+
if (done)
|
|
220
|
+
break;
|
|
221
|
+
chunks.push(value);
|
|
222
|
+
}
|
|
223
|
+
const total = chunks.reduce((n, c) => n + c.byteLength, 0);
|
|
224
|
+
const joined = new Uint8Array(total);
|
|
225
|
+
let offset = 0;
|
|
226
|
+
for (const c of chunks) {
|
|
227
|
+
joined.set(c, offset);
|
|
228
|
+
offset += c.byteLength;
|
|
229
|
+
}
|
|
230
|
+
expect(new TextDecoder().decode(joined)).toBe('the whole payload');
|
|
231
|
+
});
|
|
200
232
|
await it('Response.error() should return error response', async () => {
|
|
201
233
|
const r = Response.error();
|
|
202
234
|
expect(r.type).toBe('error');
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Rewrite a root-relative URL (starts with `/` but not
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Rewrite a root-relative URL (starts with `/` but not `//`) to a `file://` URL under the
|
|
3
|
+
* program path's directory, so a GJS/GTK app loads bundled assets with the same paths a
|
|
4
|
+
* browser resolves against its origin. Returns the input unchanged when it is not
|
|
5
|
+
* root-relative or no usable program path is given.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* acceptable for the current use cases — revisit if these packages ever handle
|
|
10
|
-
* untrusted input.
|
|
7
|
+
* The security implications (arbitrary file reads) are acceptable for the current use
|
|
8
|
+
* cases — revisit if these packages ever handle untrusted input.
|
|
11
9
|
*
|
|
12
|
-
* Deliberately no `GLib.path_get_dirname`: `@girs/glib-2.0` is emptied to `{}`
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* program path is `/`-separated on every runtime this rewrite serves, making
|
|
16
|
-
* dirname a string slice.
|
|
10
|
+
* Deliberately no `GLib.path_get_dirname`: `@girs/glib-2.0` is emptied to `{}` in a
|
|
11
|
+
* plain-Node bundle, so a GLib call here only ever "worked" behind a swallowing catch. The
|
|
12
|
+
* program path is `/`-separated on every runtime this serves, making dirname a slice.
|
|
17
13
|
*
|
|
18
|
-
* @param
|
|
19
|
-
*
|
|
20
|
-
* System.programInvocationName` on gjs; `process.argv[1]` — the bundle
|
|
21
|
-
* itself — on the node-gi reverse bridge).
|
|
14
|
+
* @param programPath `System.programPath ?? System.programInvocationName` on gjs;
|
|
15
|
+
* `process.argv[1]` — the bundle itself — on the node-gi reverse bridge.
|
|
22
16
|
*/
|
|
23
17
|
export declare function rewriteRootRelativeUrl(url: string, programPath: string): string;
|
|
@@ -1,43 +1,29 @@
|
|
|
1
|
-
// Root-relative URL → `file://` under the program directory.
|
|
1
|
+
// Root-relative URL → `file://` under the program directory. THE one copy: `@gjsify/fetch`
|
|
2
|
+
// and `@gjsify/xmlhttprequest` used to carry two spellings, and they drifted — the fetch
|
|
3
|
+
// copy read `globalThis.imports.system` (GJS-only) while the XHR copy imported the `system`
|
|
4
|
+
// built-in, so on the node-gi reverse bridge XHR-loaded assets resolved and every
|
|
5
|
+
// root-relative `fetch()` died with `ERR_INVALID_URL` (#869).
|
|
2
6
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// with `ERR_INVALID_URL` (#869 — the excalibur-jelly-jumper showcase rendered an
|
|
9
|
-
// empty level because its Tiled map is the one asset fetched rather than XHR'd).
|
|
10
|
-
//
|
|
11
|
-
// This module is deliberately PURE — the program path is a PARAMETER, and the
|
|
12
|
-
// `system` built-in is read one module over (`root-relative-system.ts`). The
|
|
13
|
-
// split is load-bearing for cross-platform loadability: on `--app node` the
|
|
14
|
-
// bare `system` specifier is aliased to `@gjsify/node-gi/system` and kept
|
|
15
|
-
// EXTERNAL, so any module that imports it makes the emitted bundle hard-require
|
|
16
|
-
// the node-gi bridge at load. `@gjsify/fetch` is a cross-platform package whose
|
|
17
|
-
// node test bundle must load on plain Node — its spec therefore covers THIS
|
|
18
|
-
// pure function on gjs AND node, while the `system` read stays confined to the
|
|
19
|
-
// GJS-reachable wrapper.
|
|
7
|
+
// Deliberately PURE — the program path is a PARAMETER and the `system` built-in is read one
|
|
8
|
+
// module over (`root-relative-system.ts`). The split is load-bearing: on `--app node` the
|
|
9
|
+
// bare `system` specifier is aliased to `@gjsify/node-gi/system` and kept EXTERNAL, so any
|
|
10
|
+
// module importing it makes the bundle hard-require the bridge at load, and this package's
|
|
11
|
+
// node test bundle must load on plain Node.
|
|
20
12
|
/**
|
|
21
|
-
* Rewrite a root-relative URL (starts with `/` but not
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
13
|
+
* Rewrite a root-relative URL (starts with `/` but not `//`) to a `file://` URL under the
|
|
14
|
+
* program path's directory, so a GJS/GTK app loads bundled assets with the same paths a
|
|
15
|
+
* browser resolves against its origin. Returns the input unchanged when it is not
|
|
16
|
+
* root-relative or no usable program path is given.
|
|
25
17
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* acceptable for the current use cases — revisit if these packages ever handle
|
|
29
|
-
* untrusted input.
|
|
18
|
+
* The security implications (arbitrary file reads) are acceptable for the current use
|
|
19
|
+
* cases — revisit if these packages ever handle untrusted input.
|
|
30
20
|
*
|
|
31
|
-
* Deliberately no `GLib.path_get_dirname`: `@girs/glib-2.0` is emptied to `{}`
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* program path is `/`-separated on every runtime this rewrite serves, making
|
|
35
|
-
* dirname a string slice.
|
|
21
|
+
* Deliberately no `GLib.path_get_dirname`: `@girs/glib-2.0` is emptied to `{}` in a
|
|
22
|
+
* plain-Node bundle, so a GLib call here only ever "worked" behind a swallowing catch. The
|
|
23
|
+
* program path is `/`-separated on every runtime this serves, making dirname a slice.
|
|
36
24
|
*
|
|
37
|
-
* @param
|
|
38
|
-
*
|
|
39
|
-
* System.programInvocationName` on gjs; `process.argv[1]` — the bundle
|
|
40
|
-
* itself — on the node-gi reverse bridge).
|
|
25
|
+
* @param programPath `System.programPath ?? System.programInvocationName` on gjs;
|
|
26
|
+
* `process.argv[1]` — the bundle itself — on the node-gi reverse bridge.
|
|
41
27
|
*/
|
|
42
28
|
export function rewriteRootRelativeUrl(url, programPath) {
|
|
43
29
|
if (!url.startsWith('/') || url.startsWith('//'))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/fetch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
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",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"fetch"
|
|
52
52
|
],
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@gjsify/cli": "^0.
|
|
55
|
-
"@gjsify/unit": "^0.
|
|
54
|
+
"@gjsify/cli": "^0.37.0",
|
|
55
|
+
"@gjsify/unit": "^0.37.0",
|
|
56
56
|
"@types/node": "^25.9.2",
|
|
57
57
|
"typescript": "^6.0.3"
|
|
58
58
|
},
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"@girs/gjs": "^4.1.0",
|
|
62
62
|
"@girs/glib-2.0": "^4.1.0",
|
|
63
63
|
"@girs/soup-3.0": "^4.1.0",
|
|
64
|
-
"@gjsify/dom-events": "^0.
|
|
65
|
-
"@gjsify/formdata": "^0.
|
|
66
|
-
"@gjsify/http": "^0.
|
|
67
|
-
"@gjsify/url": "^0.
|
|
68
|
-
"@gjsify/utils": "^0.
|
|
64
|
+
"@gjsify/dom-events": "^0.37.0",
|
|
65
|
+
"@gjsify/formdata": "^0.37.0",
|
|
66
|
+
"@gjsify/http": "^0.37.0",
|
|
67
|
+
"@gjsify/url": "^0.37.0",
|
|
68
|
+
"@gjsify/utils": "^0.37.0"
|
|
69
69
|
},
|
|
70
70
|
"gjsify": {
|
|
71
71
|
"runtimes": {
|