@gjsify/fetch 0.38.0 → 0.39.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
import"../_virtual/_rolldown/runtime.js";function rewriteRootRelativeUrl(
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{lastPathSeparatorIndex as e,pathToFileUrlHref as t}from"@gjsify/utils/core";function rewriteRootRelativeUrl(n,r){if(!n.startsWith(`/`)||n.startsWith(`//`))return n;let i=e(r);return i<=0?n:`${t(r.slice(0,i))}${n}`}export{rewriteRootRelativeUrl};
|
|
@@ -34,6 +34,32 @@ export default async () => {
|
|
|
34
34
|
expect(rewriteRootRelativeUrl('/res/x.png', '')).toBe('/res/x.png');
|
|
35
35
|
expect(rewriteRootRelativeUrl('/res/x.png', 'main.js')).toBe('/res/x.png');
|
|
36
36
|
});
|
|
37
|
+
// #1143, measured on Windows 11: the program path is `C:\…\dist\main.js`, the old
|
|
38
|
+
// `lastIndexOf('/')` returned -1, the "no program dir" guard swallowed it, and the
|
|
39
|
+
// URL reached the `Request` constructor unrewritten — `Invalid URL` on bun and
|
|
40
|
+
// deno, then a SIGSEGV / 0xC0000005. These run on the LINUX runner: the win32
|
|
41
|
+
// answer is decided from the path's shape, so it needs no win32 host to check.
|
|
42
|
+
await it('maps a root-relative URL under a win32 drive program path', async () => {
|
|
43
|
+
expect(rewriteRootRelativeUrl('/res/tilemaps/level1.tmx', 'C:\\app\\dist\\main.js')).toBe('file:///C:/app/dist/res/tilemaps/level1.tmx');
|
|
44
|
+
});
|
|
45
|
+
await it('maps a root-relative URL under a UNC program path', async () => {
|
|
46
|
+
expect(rewriteRootRelativeUrl('/res/x.png', '\\\\build\\share\\app\\dist\\main.js')).toBe('file://build/share/app/dist/res/x.png');
|
|
47
|
+
});
|
|
48
|
+
await it('keeps the query string a cache-busted asset request carries', async () => {
|
|
49
|
+
// Only the DIRECTORY is percent-encoded. Encoding the URL half would turn
|
|
50
|
+
// `?v=2` into `%3Fv=2` and ask for a file whose name contains a question mark.
|
|
51
|
+
expect(rewriteRootRelativeUrl('/res/x.png?v=2', 'C:\\app\\dist\\main.js')).toBe('file:///C:/app/dist/res/x.png?v=2');
|
|
52
|
+
expect(rewriteRootRelativeUrl('/res/x.png?v=2', '/opt/app/dist/main.js')).toBe('file:///opt/app/dist/res/x.png?v=2');
|
|
53
|
+
});
|
|
54
|
+
await it('percent-encodes a program dir that needs it', async () => {
|
|
55
|
+
// A space in the program directory is ordinary on Windows (`C:\Program Files`)
|
|
56
|
+
// and was previously emitted raw.
|
|
57
|
+
expect(rewriteRootRelativeUrl('/res/x.png', 'C:\\Program Files\\app\\main.js')).toBe('file:///C:/Program%20Files/app/res/x.png');
|
|
58
|
+
});
|
|
59
|
+
await it('treats a backslash in a POSIX program path as part of the name', async () => {
|
|
60
|
+
// `\` is legal in a POSIX filename, so this must NOT be read as a separator.
|
|
61
|
+
expect(rewriteRootRelativeUrl('/res/x.png', '/opt/od\\d/main.js')).toBe('file:///opt/od%5Cd/res/x.png');
|
|
62
|
+
});
|
|
37
63
|
});
|
|
38
64
|
// The `system`-reading wrapper, end to end on gjs — the runtime where the
|
|
39
65
|
// program path is real. Reached through the aliased package root so the
|
|
@@ -8,8 +8,18 @@
|
|
|
8
8
|
* cases — revisit if these packages ever handle untrusted input.
|
|
9
9
|
*
|
|
10
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.
|
|
12
|
-
*
|
|
11
|
+
* plain-Node bundle, so a GLib call here only ever "worked" behind a swallowing catch.
|
|
12
|
+
* The separator question goes to `@gjsify/utils/core` instead, which answers it from the
|
|
13
|
+
* SHAPE of the path — this function's own `lastIndexOf('/')` returned -1 for
|
|
14
|
+
* `C:\…\dist\main.js`, the `slash <= 0` guard read that as "no program dir", and every
|
|
15
|
+
* root-relative `fetch()` on win32 died as `Invalid URL` in the `Request` constructor
|
|
16
|
+
* (#1143).
|
|
17
|
+
*
|
|
18
|
+
* The base and the URL are CONCATENATED rather than resolved through `new URL(url, base)`:
|
|
19
|
+
* resolving a root-relative path against `file:///C:/app/dist` drops the program directory
|
|
20
|
+
* and keeps only the root — and the runtimes do not agree on what the root is. Measured:
|
|
21
|
+
* Node keeps the drive (`file:///C:/res/…`), GJS/SpiderMonkey does not (`file:///res/…`).
|
|
22
|
+
* So resolution is both wrong for this purpose and host-dependent.
|
|
13
23
|
*
|
|
14
24
|
* @param programPath `System.programPath ?? System.programInvocationName` on gjs;
|
|
15
25
|
* `process.argv[1]` — the bundle itself — on the node-gi reverse bridge.
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
// bare `system` specifier is aliased to `@gjsify/node-gi/system` and kept EXTERNAL, so any
|
|
10
10
|
// module importing it makes the bundle hard-require the bridge at load, and this package's
|
|
11
11
|
// node test bundle must load on plain Node.
|
|
12
|
+
// `/core` and not the `@gjsify/utils` root: the root reaches Gio/GLib, which would undo the
|
|
13
|
+
// plain-Node loadability this module's split exists to protect.
|
|
14
|
+
import { lastPathSeparatorIndex, pathToFileUrlHref } from '@gjsify/utils/core';
|
|
12
15
|
/**
|
|
13
16
|
* Rewrite a root-relative URL (starts with `/` but not `//`) to a `file://` URL under the
|
|
14
17
|
* program path's directory, so a GJS/GTK app loads bundled assets with the same paths a
|
|
@@ -19,8 +22,18 @@
|
|
|
19
22
|
* cases — revisit if these packages ever handle untrusted input.
|
|
20
23
|
*
|
|
21
24
|
* 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.
|
|
23
|
-
*
|
|
25
|
+
* plain-Node bundle, so a GLib call here only ever "worked" behind a swallowing catch.
|
|
26
|
+
* The separator question goes to `@gjsify/utils/core` instead, which answers it from the
|
|
27
|
+
* SHAPE of the path — this function's own `lastIndexOf('/')` returned -1 for
|
|
28
|
+
* `C:\…\dist\main.js`, the `slash <= 0` guard read that as "no program dir", and every
|
|
29
|
+
* root-relative `fetch()` on win32 died as `Invalid URL` in the `Request` constructor
|
|
30
|
+
* (#1143).
|
|
31
|
+
*
|
|
32
|
+
* The base and the URL are CONCATENATED rather than resolved through `new URL(url, base)`:
|
|
33
|
+
* resolving a root-relative path against `file:///C:/app/dist` drops the program directory
|
|
34
|
+
* and keeps only the root — and the runtimes do not agree on what the root is. Measured:
|
|
35
|
+
* Node keeps the drive (`file:///C:/res/…`), GJS/SpiderMonkey does not (`file:///res/…`).
|
|
36
|
+
* So resolution is both wrong for this purpose and host-dependent.
|
|
24
37
|
*
|
|
25
38
|
* @param programPath `System.programPath ?? System.programInvocationName` on gjs;
|
|
26
39
|
* `process.argv[1]` — the bundle itself — on the node-gi reverse bridge.
|
|
@@ -28,8 +41,11 @@
|
|
|
28
41
|
export function rewriteRootRelativeUrl(url, programPath) {
|
|
29
42
|
if (!url.startsWith('/') || url.startsWith('//'))
|
|
30
43
|
return url;
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
44
|
+
const separator = lastPathSeparatorIndex(programPath);
|
|
45
|
+
if (separator <= 0)
|
|
33
46
|
return url; // no usable program dir ('' or a bare name)
|
|
34
|
-
|
|
47
|
+
// Only the DIRECTORY is percent-encoded. `url` is already a URL and carries its own
|
|
48
|
+
// `?query` and `#fragment` semantics — encoding it would turn a cache-busting
|
|
49
|
+
// `/res/x.png?v=2` into a request for a file literally called `x.png?v=2`.
|
|
50
|
+
return `${pathToFileUrlHref(programPath.slice(0, separator))}${url}`;
|
|
35
51
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/fetch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.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.39.0",
|
|
55
|
+
"@gjsify/unit": "^0.39.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.39.0",
|
|
65
|
+
"@gjsify/formdata": "^0.39.0",
|
|
66
|
+
"@gjsify/http": "^0.39.0",
|
|
67
|
+
"@gjsify/url": "^0.39.0",
|
|
68
|
+
"@gjsify/utils": "^0.39.0"
|
|
69
69
|
},
|
|
70
70
|
"gjsify": {
|
|
71
71
|
"runtimes": {
|