@gjsify/fetch 0.4.20 → 0.4.22
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/esm/index.js +1 -1
- package/lib/esm/register/fetch.js +1 -1
- package/lib/esm/utils/multipart-parser.js +2 -2
- package/lib/index.js +5 -18
- package/lib/register/fetch.js +5 -4
- package/package.json +12 -12
package/lib/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{Blob as e,File as t}from"./utils/blob-from.js";import{FetchError as n}from"./errors/fetch-error.js";import{isDomainOrSubdomain as r,isSameProtocol as i}from"./utils/is.js";import{clone as a}from"./body.js";import o from"./headers.js";import{parseDataUri as s}from"./utils/data-uri.js";import{isRedirect as c}from"./utils/is-redirect.js";import{Response as l}from"./response.js";import{parseReferrerPolicyFromHeader as u}from"./utils/referrer.js";import{Request as d,getSoupRequestOptions as f}from"./request.js";import{AbortError as p}from"./errors/abort-error.js";import{XMLHttpRequest as m,XMLHttpRequestUpload as h}from"./xhr.js";import{URL as g}from"@gjsify/url";import _ from"node:stream";import{FormData as v}from"@gjsify/formdata";import y from"@girs/glib-2.0";const b=new Set([`data:`,`http:`,`https:`,`file:`]);function rewriteRootRelativeUrl(e){if(typeof e!=`string`||!e.startsWith(`/`)||e.startsWith(`//`))return e;let t=globalThis.__GJSIFY_DEBUG_FETCH===!0;try{let
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{Blob as e,File as t}from"./utils/blob-from.js";import{FetchError as n}from"./errors/fetch-error.js";import{isDomainOrSubdomain as r,isSameProtocol as i}from"./utils/is.js";import{clone as a}from"./body.js";import o from"./headers.js";import{parseDataUri as s}from"./utils/data-uri.js";import{isRedirect as c}from"./utils/is-redirect.js";import{Response as l}from"./response.js";import{parseReferrerPolicyFromHeader as u}from"./utils/referrer.js";import{Request as d,getSoupRequestOptions as f}from"./request.js";import{AbortError as p}from"./errors/abort-error.js";import{XMLHttpRequest as m,XMLHttpRequestUpload as h}from"./xhr.js";import{URL as g}from"@gjsify/url";import _ from"node:stream";import{FormData as v}from"@gjsify/formdata";import y from"@girs/glib-2.0";const b=new Set([`data:`,`http:`,`https:`,`file:`]);function rewriteRootRelativeUrl(e){if(typeof e!=`string`||!e.startsWith(`/`)||e.startsWith(`//`))return e;let t=globalThis,n=t.__GJSIFY_DEBUG_FETCH===!0;try{let r=t.imports?.system?.programPath??t.imports?.system?.programInvocationName??``;if(!r)return e;let i=`file://${y.path_get_dirname(r)}${e}`;return n&&console.log(`[fetch] rewrite ${e} → ${i}`),i}catch(t){return n&&console.warn(`[fetch] rewrite FAILED: ${t instanceof Error?t.message:String(t)}`),e}}async function fetch(e,t={}){e=rewriteRootRelativeUrl(e);let m=new d(e,t),{parsedURL:h,options:v}=f(m);if(!b.has(h.protocol))throw TypeError(`@gjsify/fetch cannot load ${e}. URL scheme "${h.protocol.replace(/:$/,``)}" is not supported.`);if(h.protocol===`data:`){let{buffer:e,typeFull:t}=s(m.url);return new l(Buffer.from(e),{headers:{"Content-Type":t}})}if(h.protocol===`file:`){let e=globalThis.__GJSIFY_DEBUG_FETCH===!0;e&&console.log(`[fetch] file:// ${m.url}`);try{let t=y.filename_from_uri(m.url)[0];e&&console.log(`[fetch] file:// path=${t}`);let[r,i]=y.file_get_contents(t);if(e&&console.log(`[fetch] file:// ok=${r} bytes=${i?.byteLength??`?`}`),!r)throw new n(`Failed to read file: ${t}`,`system`);let a=i,o=new Uint8Array(a.byteLength);o.set(a);let s=new l(o);return e&&console.log(`[fetch] file:// response created`),s}catch(t){let r=t instanceof Error?t:Error(String(t));throw e&&console.warn(`[fetch] file:// FAIL: ${r.message}`),new n(`request to ${m.url} failed, reason: ${r.message}`,`system`,r)}}let{signal:x}=m;if(x&&x.aborted)throw new p(`The operation was aborted.`);let S,C;try{let e=await m._send(v);S=e.readable,C=e.cancellable}catch(e){let t=e instanceof Error?e:Error(String(e));throw new n(`request to ${m.url} failed, reason: ${t.message}`,`system`,t)}let abortHandler=()=>{C.cancel()};x&&x.addEventListener(`abort`,abortHandler,{once:!0});let finalize=()=>{x&&x.removeEventListener(`abort`,abortHandler)};C.connect(()=>{S.destroy(new p(`The operation was aborted.`))}),S.on(`error`,e=>{finalize()});let w=m._message,T=o._newFromSoupMessage(w),E=w.status_code,D=w.get_reason_phrase();if(c(E)){let e=T.get(`Location`),s=null;try{s=e===null?null:new g(e,m.url)}catch{if(m.redirect!==`manual`)throw finalize(),new n(`uri requested responds with an invalid redirect URL: ${e}`,`invalid-redirect`)}switch(m.redirect){case`error`:throw finalize(),new n(`uri requested responds with a redirect, redirect mode is set to error: ${m.url}`,`no-redirect`);case`manual`:break;case`follow`:{if(s===null)break;if(m.counter>=m.follow)throw finalize(),new n(`maximum redirect reached at: ${m.url}`,`max-redirect`);let e={headers:new o(m.headers),follow:m.follow,counter:m.counter+1,agent:m.agent,compress:m.compress,method:m.method,body:a(m),signal:m.signal,size:m.size,referrer:m.referrer,referrerPolicy:m.referrerPolicy};if(!r(m.url,s)||!i(m.url,s))for(let t of[`authorization`,`www-authenticate`,`cookie`,`cookie2`])e.headers.delete(t);if(E!==303&&m.body&&t.body instanceof _.Readable)throw finalize(),new n(`Cannot follow redirect with body being a readable stream`,`unsupported-redirect`);(E===303||(E===301||E===302)&&m.method===`POST`)&&(e.method=`GET`,e.body=void 0,e.headers.delete(`content-length`));let c=u(T);return c&&(e.referrerPolicy=c),finalize(),fetch(new d(s,e))}default:throw TypeError(`Redirect option '${m.redirect}' is not a valid value of RequestRedirect`)}}let O={url:m.url,status:E,statusText:D,headers:T,size:m.size,counter:m.counter,highWaterMark:m.highWaterMark},k=T.get(`Content-Encoding`);if(!m.compress||m.method===`HEAD`||k===null||E===204||E===304)return finalize(),new l(S,O);if(typeof DecompressionStream<`u`){let e=null;if(k===`gzip`||k===`x-gzip`?e=`gzip`:(k===`deflate`||k===`x-deflate`)&&(e=`deflate`),e){let t=new l(S,O).body;if(t){let n=t.pipeThrough(new DecompressionStream(e));return finalize(),new l(n,O)}}}return finalize(),new l(S,O)}export{p as AbortError,e as Blob,n as FetchError,t as File,v as FormData,o as Headers,d as Request,l as Response,m as XMLHttpRequest,h as XMLHttpRequestUpload,fetch as default,c as isRedirect};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"../headers.js";import{Response as t}from"../response.js";import{Request as n}from"../request.js";import r from"../index.js";globalThis.fetch===void 0&&(
|
|
1
|
+
import e from"../headers.js";import{Response as t}from"../response.js";import{Request as n}from"../request.js";import r from"../index.js";const i=globalThis;globalThis.fetch===void 0&&(i.fetch=r),globalThis.Headers===void 0&&(i.Headers=e),globalThis.Request===void 0&&(i.Request=n),globalThis.Response===void 0&&(i.Response=t);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"../_virtual/_rolldown/runtime.js";import{File as e}from"./blob-from.js";import{FormData as t}from"@gjsify/formdata";
|
|
2
|
-
--`+e;let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n),this.boundaryChars[t[n]]=!0;this.boundary=t,this.lookbehind=new Uint8Array(this.boundary.length+8)}write(e){let t=0,n=e.length,
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{File as e}from"./blob-from.js";import{FormData as t}from"@gjsify/formdata";let n=1;const r={PART_BOUNDARY:n,LAST_BOUNDARY:n*=2},lower=e=>e|32,noop=(...e)=>{};var MultipartParser=class{index=0;flags=0;boundary;lookbehind;state=0;onHeaderEnd=noop;onHeaderField=noop;onHeadersEnd=noop;onHeaderValue=noop;onPartBegin=noop;onPartData=noop;onPartEnd=noop;boundaryChars={};constructor(e){e=`\r
|
|
2
|
+
--`+e;let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n),this.boundaryChars[t[n]]=!0;this.boundary=t,this.lookbehind=new Uint8Array(this.boundary.length+8)}write(e){let t=0,n=e.length,i=this.index,{lookbehind:a,boundary:o,boundaryChars:s,index:c,state:l,flags:u}=this,d=this.boundary.length,f=d-1,p=e.length,m,h,mark=e=>{this[e+`Mark`]=t},clear=e=>{delete this[e+`Mark`]},callback=(e,t,n,r)=>{(t===void 0||t!==n)&&this[e](r&&r.subarray(t,n))},dataCallback=(n,r=!1)=>{let i=n+`Mark`;i in this&&(r?(callback(n,this[i],t,e),delete this[i]):(callback(n,this[i],e.length,e),this[i]=0))};for(t=0;t<n;t++)switch(m=e[t],l){case 0:if(c===o.length-2){if(m===45)u|=r.LAST_BOUNDARY;else if(m!==13)return;c++;break}else if(c-1==o.length-2){if(u&r.LAST_BOUNDARY&&m===45)l=9,u=0;else if(!(u&r.LAST_BOUNDARY)&&m===10)c=0,callback(`onPartBegin`),l=1;else return;break}m!==o[c+2]&&(c=-2),m===o[c+2]&&c++;break;case 1:l=2,mark(`onHeaderField`),c=0;case 2:if(m===13){clear(`onHeaderField`),l=6;break}if(c++,m===45)break;if(m===58){if(c===1)return;dataCallback(`onHeaderField`,!0),l=3;break}if(h=lower(m),h<97||h>122)return;break;case 3:if(m===32)break;mark(`onHeaderValue`),l=4;case 4:m===13&&(dataCallback(`onHeaderValue`,!0),callback(`onHeaderEnd`),l=5);break;case 5:if(m!==10)return;l=1;break;case 6:if(m!==10)return;callback(`onHeadersEnd`),l=7;break;case 7:l=8,mark(`onPartData`);case 8:if(i=c,c===0){for(t+=f;t<p&&!(e[t]in s);)t+=d;t-=f,m=e[t]}if(c<o.length)o[c]===m?(c===0&&dataCallback(`onPartData`,!0),c++):c=0;else if(c===o.length)c++,m===13?u|=r.PART_BOUNDARY:m===45?u|=r.LAST_BOUNDARY:c=0;else if(c-1===o.length)if(u&r.PART_BOUNDARY){if(c=0,m===10){u&=~r.PART_BOUNDARY,callback(`onPartEnd`),callback(`onPartBegin`),l=1;break}}else u&r.LAST_BOUNDARY&&m===45?(callback(`onPartEnd`),l=9,u=0):c=0;if(c>0)a[c-1]=m;else if(i>0){let e=new Uint8Array(a.buffer,a.byteOffset,a.byteLength);callback(`onPartData`,0,i,e),i=0,mark(`onPartData`),t--}break;case 9:break;default:throw Error(`Unexpected state entered: ${l}`)}dataCallback(`onHeaderField`),dataCallback(`onHeaderValue`),dataCallback(`onPartData`),this.index=c,this.state=l,this.flags=u}end(){if(this.state===1&&this.index===0||this.state===8&&this.index===this.boundary.length)this.onPartEnd();else if(this.state!==9)throw Error(`MultipartParser.end(): stream ended unexpectedly`)}};function _fileName(e){let t=e.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);if(!t)return;let n=t[2]||t[3]||``,r=n.slice(n.lastIndexOf(`\\`)+1);return r=r.replace(/%22/g,`"`),r=r.replace(/&#(\d{4});/g,(e,t)=>String.fromCharCode(t)),r}async function toFormData(n,r){if(!/multipart/i.test(r))throw TypeError(`Failed to fetch`);let i=r.match(/boundary=(?:"([^"]+)"|([^;]+))/i);if(!i)throw TypeError(`no or bad content-type header, no multipart boundary`);let a=new MultipartParser(i[1]||i[2]),o,s,c,l,u,d,f=[],p=new t,onPartData=e=>{c+=m.decode(e,{stream:!0})},appendToFile=e=>{f.push(e)},appendFileToFormData=()=>{let t=new e(f,d,{type:u});p.append(l,t)},appendEntryToFormData=()=>{p.append(l,c)},m=new TextDecoder(`utf-8`);m.decode(),a.onPartBegin=function(){a.onPartData=onPartData,a.onPartEnd=appendEntryToFormData,o=``,s=``,c=``,l=``,u=``,d=null,f.length=0},a.onHeaderField=function(e){o+=m.decode(e,{stream:!0})},a.onHeaderValue=function(e){s+=m.decode(e,{stream:!0})},a.onHeaderEnd=function(){if(s+=m.decode(),o=o.toLowerCase(),o===`content-disposition`){let e=s.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);e&&(l=e[2]||e[3]||``),d=_fileName(s),d&&(a.onPartData=appendToFile,a.onPartEnd=appendFileToFormData)}else o===`content-type`&&(u=s);s=``,o=``};for await(let e of n)a.write(e);return a.end(),p}export{toFormData};
|
package/lib/index.js
CHANGED
|
@@ -21,30 +21,17 @@ export { FormData, Headers, Request, Response, FetchError, AbortError, isRedirec
|
|
|
21
21
|
export { Blob, File };
|
|
22
22
|
export { XMLHttpRequest, XMLHttpRequestUpload } from './xhr.js';
|
|
23
23
|
const supportedSchemas = new Set(['data:', 'http:', 'https:', 'file:']);
|
|
24
|
-
/**
|
|
25
|
-
* Rewrite root-relative URLs (e.g. `/res/images/foo.png`) to `file://` relative
|
|
26
|
-
* to the program directory. In a browser these would resolve against the page
|
|
27
|
-
* origin; in GJS there is no origin, so we map them to the running bundle's
|
|
28
|
-
* directory. This lets apps use the same asset paths across browser and GJS.
|
|
29
|
-
*/
|
|
30
|
-
/**
|
|
31
|
-
* Rewrite root-relative URLs (e.g. `/res/images/foo.png`) to `file://` relative
|
|
32
|
-
* to the program directory. This lets GJS apps load bundled assets using the
|
|
33
|
-
* same paths as in the browser. The security implications (arbitrary file
|
|
34
|
-
* reads via fetch) are acceptable for the current use cases — revisit if
|
|
35
|
-
* @gjsify/fetch is ever used to handle untrusted input.
|
|
36
|
-
*/
|
|
37
24
|
function rewriteRootRelativeUrl(input) {
|
|
38
25
|
if (typeof input !== 'string')
|
|
39
26
|
return input;
|
|
40
27
|
if (!input.startsWith('/') || input.startsWith('//'))
|
|
41
28
|
return input;
|
|
42
|
-
const
|
|
29
|
+
const _g = globalThis;
|
|
30
|
+
const DEBUG = _g.__GJSIFY_DEBUG_FETCH === true;
|
|
43
31
|
try {
|
|
44
32
|
// GJS-only: derive program dir from System.programInvocationName.
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
?? imports?.system?.programInvocationName
|
|
33
|
+
const programPath = _g.imports?.system?.programPath
|
|
34
|
+
?? _g.imports?.system?.programInvocationName
|
|
48
35
|
?? '';
|
|
49
36
|
if (!programPath)
|
|
50
37
|
return input;
|
|
@@ -56,7 +43,7 @@ function rewriteRootRelativeUrl(input) {
|
|
|
56
43
|
}
|
|
57
44
|
catch (err) {
|
|
58
45
|
if (DEBUG)
|
|
59
|
-
console.warn(`[fetch] rewrite FAILED: ${err
|
|
46
|
+
console.warn(`[fetch] rewrite FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
60
47
|
return input;
|
|
61
48
|
}
|
|
62
49
|
}
|
package/lib/register/fetch.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
// Registers: fetch, Headers, Request, Response
|
|
2
2
|
import fetch, { Headers, Request, Response } from '../index.js';
|
|
3
|
+
const g = globalThis;
|
|
3
4
|
if (typeof globalThis.fetch === 'undefined') {
|
|
4
|
-
|
|
5
|
+
g.fetch = fetch;
|
|
5
6
|
}
|
|
6
7
|
if (typeof globalThis.Headers === 'undefined') {
|
|
7
|
-
|
|
8
|
+
g.Headers = Headers;
|
|
8
9
|
}
|
|
9
10
|
if (typeof globalThis.Request === 'undefined') {
|
|
10
|
-
|
|
11
|
+
g.Request = Request;
|
|
11
12
|
}
|
|
12
13
|
if (typeof globalThis.Response === 'undefined') {
|
|
13
|
-
|
|
14
|
+
g.Response = Response;
|
|
14
15
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/fetch",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
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,19 +48,19 @@
|
|
|
48
48
|
"fetch"
|
|
49
49
|
],
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@gjsify/cli": "^0.4.
|
|
52
|
-
"@gjsify/unit": "^0.4.
|
|
53
|
-
"@types/node": "^25.
|
|
51
|
+
"@gjsify/cli": "^0.4.22",
|
|
52
|
+
"@gjsify/unit": "^0.4.22",
|
|
53
|
+
"@types/node": "^25.9.1",
|
|
54
54
|
"typescript": "^6.0.3"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@girs/gio-2.0": "2.88.0-4.0.
|
|
58
|
-
"@girs/gjs": "4.0.
|
|
59
|
-
"@girs/glib-2.0": "2.88.0-4.0.
|
|
60
|
-
"@girs/soup-3.0": "3.6.6-4.0.
|
|
61
|
-
"@gjsify/formdata": "^0.4.
|
|
62
|
-
"@gjsify/http": "^0.4.
|
|
63
|
-
"@gjsify/url": "^0.4.
|
|
64
|
-
"@gjsify/utils": "^0.4.
|
|
57
|
+
"@girs/gio-2.0": "2.88.0-4.0.1",
|
|
58
|
+
"@girs/gjs": "4.0.1",
|
|
59
|
+
"@girs/glib-2.0": "2.88.0-4.0.1",
|
|
60
|
+
"@girs/soup-3.0": "3.6.6-4.0.1",
|
|
61
|
+
"@gjsify/formdata": "^0.4.22",
|
|
62
|
+
"@gjsify/http": "^0.4.22",
|
|
63
|
+
"@gjsify/url": "^0.4.22",
|
|
64
|
+
"@gjsify/utils": "^0.4.22"
|
|
65
65
|
}
|
|
66
66
|
}
|