@gjsify/http2 0.4.30 → 0.4.32

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{__toCommonJS as e}from"./_virtual/_rolldown/runtime.js";import{constants as t,getDefaultSettings as n}from"./protocol.js";import{init_native_client_dispatcher as r,native_client_dispatcher_exports as i}from"./native-client-dispatcher.js";import a from"@girs/soup-3.0";import o from"@girs/gio-2.0";import s from"@girs/glib-2.0";import{EventEmitter as c}from"node:events";import{Duplex as l}from"node:stream";import{Buffer as u}from"node:buffer";import{readBytesAsync as d}from"@gjsify/utils";var Http2Session=class extends c{type=t.NGHTTP2_SESSION_CLIENT;alpnProtocol=void 0;encrypted=!1;_closed=!1;_destroyed=!1;_settings;constructor(){super(),this._settings=n()}get closed(){return this._closed}get destroyed(){return this._destroyed}get connecting(){return!1}get pendingSettingsAck(){return!1}get localSettings(){return{...this._settings}}get remoteSettings(){return n()}get originSet(){return new Set}settings(e,t){Object.assign(this._settings,e),t&&Promise.resolve().then(t)}goaway(e,n,r){this.emit(`goaway`,e??t.NGHTTP2_NO_ERROR),this.destroy()}ping(e,t){let n=e||new Uint8Array(8);return t&&Promise.resolve().then(()=>t(null,0,n)),!0}close(e){this._closed||(this._closed=!0,this.emit(`close`),e&&e())}destroy(e,t){this._destroyed||(this._destroyed=!0,this._closed=!0,e&&this.emit(`error`,e),t!==void 0&&this.emit(`goaway`,t),this.emit(`close`))}ref(){}unref(){}},ClientHttp2Stream=class extends l{_id=1;pending=!1;aborted=!1;bufferSize=0;endAfterHeaders=!1;_session;_requestHeaders;_requestChunks=[];_cancellable;_state=t.NGHTTP2_STREAM_STATE_OPEN;_responseHeaders={};_nativeStreamId=0;get id(){return this._id}get state(){return this._state}get rstCode(){return t.NGHTTP2_NO_ERROR}get session(){return this._session}get sentHeaders(){return this._requestHeaders}_setNativeStreamId(e){this._id=e,this._nativeStreamId=e,this._wireNativeBody()}constructor(e,t){super(),this._session=e,this._requestHeaders=t,this._cancellable=new o.Cancellable}_read(e){}_write(e,t,n){let r=u.isBuffer(e)?e:u.from(e,t);this._nativeStreamId>0?this._session._getNativeClient().writeData(this._nativeStreamId,r,!1):this._requestChunks.push(r),n()}_final(e){let t=this._session._getNativeClient();if(t){try{if(this._nativeStreamId>0)t.writeData(this._nativeStreamId,u.alloc(0),!0);else{let n=u.concat(this._requestChunks),r=n.length===0,i=t.submitRequest(this._requestHeaders,r);if(i===0){e(Error(`Failed to submit HTTP/2 request stream`));return}this._id=i,this._nativeStreamId=i,n.length>0&&t.writeData(i,n,!0),this._wireNativeBody()}e()}catch(t){e(t instanceof Error?t:Error(String(t)))}return}this._sendRequest().then(()=>e()).catch(t=>e(t instanceof Error?t:Error(String(t))))}_wireNativeBody(){let e=this._session._getNativeClient();if(!e||this._nativeStreamId===0)return;let n=this._nativeStreamId;(async()=>{try{let r=Date.now()+3e4,i=null;for(;Date.now()<r&&(i=e.responseHeaders(n),!i);)await new Promise(e=>s.idle_add(s.PRIORITY_DEFAULT,()=>(e(),!1)));if(!i){this.destroy(Error(`Native HTTP/2 client: response headers timeout`));return}this._responseHeaders=i,this._state=t.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,this.emit(`response`,i,0);for await(let t of e.body(n))t.length>0&&this.push(t);this.push(null),this._state=t.NGHTTP2_STREAM_STATE_CLOSED}catch(e){this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this.destroy(e instanceof Error?e:Error(String(e)))}})()}async _sendRequest(){let e=this._session._getSoupSession(),n=this._session._getAuthority(),r=this._requestHeaders[`:method`]||`GET`,i=this._requestHeaders[`:path`]||`/`,o=`${this._requestHeaders[`:scheme`]||(n.startsWith(`https`)?`https`:`http`)}://${this._requestHeaders[`:authority`]||n.replace(/^https?:\/\//,``)}${i}`,c;try{c=s.Uri.parse(o,s.UriFlags.NONE)}catch{throw Error(`Invalid HTTP/2 request URL: ${o}`)}let l=new a.Message({method:r,uri:c}),f=l.get_request_headers();for(let[e,t]of Object.entries(this._requestHeaders))if(!e.startsWith(`:`))if(Array.isArray(t))for(let n of t)f.append(e,n);else f.replace(e,t);let p=u.concat(this._requestChunks);if(p.length>0){let e=this._requestHeaders[`content-type`]||`application/octet-stream`;l.set_request_body_from_bytes(e,new s.Bytes(p))}try{let n=await new Promise((t,n)=>{e.send_async(l,s.PRIORITY_DEFAULT,this._cancellable,(r,i)=>{try{t(e.send_finish(i))}catch(e){n(e)}})}),r=l.status_code,i=l.get_response_headers(),a={":status":String(r)};i.foreach((e,t)=>{let n=e.toLowerCase();if(n in a){let e=a[n];Array.isArray(e)?e.push(t):a[n]=[e,t]}else a[n]=t}),this._responseHeaders=a,this._state=t.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,this.emit(`response`,a,0);try{let e;for(;(e=await d(n,16384,s.PRIORITY_DEFAULT,this._cancellable))!==null;)e.length>0&&this.push(u.from(e))}catch{}this.push(null),this._state=t.NGHTTP2_STREAM_STATE_CLOSED}catch(e){this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this._cancellable.is_cancelled()||this.destroy(e instanceof Error?e:Error(String(e)))}}close(e,n){this._cancellable.cancel(),this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this.emit(`close`,e??t.NGHTTP2_NO_ERROR),n&&n()}priority(e){}sendTrailers(e){}setTimeout(e,t){return this}},ClientHttp2Session=class extends Http2Session{type=t.NGHTTP2_SESSION_CLIENT;_authority;_soupSession;_streams=new Set;_nativeClient=null;get nativeClient(){return this._nativeClient}constructor(e,t={}){super(),this._authority=e,this.encrypted=e.startsWith(`https:`),this._soupSession=new a.Session,t.rejectUnauthorized===!1&&this._soupSession.connect(`accept-certificate`,(e,t,n)=>!0);let n=t.nativeDispatcher??`auto`;n===`force`&&this._setupNativeClient(e,n),Promise.resolve().then(()=>{if(!this.destroyed){let e=this;e.alpnProtocol=this.encrypted?`h2`:this._nativeClient?`h2c`:void 0,this.emit(`connect`,this,null)}})}_setupNativeClient(t,n){let{Http2NativeClientDispatcher:a}=(r(),e(i));if(!a.available()){if(n===`force`)throw Error(`@gjsify/http2-native prebuild not loadable — nativeDispatcher: "force" cannot proceed`);return}let[o,s]=t.replace(/^https?:\/\//,``).split(`:`),c=parseInt(s||(this.encrypted?`443`:`80`),10);this._nativeClient=new a({onPushPromise:e=>{let t=new ClientHttp2Stream(this,e.headers);t._setNativeStreamId(e.promisedStreamId),this._streams.add(t),this.emit(`stream`,t,e.headers,0)},onGoaway:(e,t)=>{this.emit(`goaway`,t,e)},onClose:()=>{}});try{this._nativeClient.connect(o||`localhost`,c)}catch(e){if(this._nativeClient=null,n===`force`)throw e}}_getSoupSession(){return this._soupSession}_getNativeClient(){return this._nativeClient}_getAuthority(){return this._authority}request(e,t){if(this.destroyed||this.closed)throw Error(`Session is closed`);let n={},r={};for(let[t,i]of Object.entries(e))t.startsWith(`:`)?n[t]=i:r[t]=i;n[`:method`]||=`GET`,n[`:scheme`]||=this.encrypted?`https`:`http`,n[`:authority`]||=this._authority.replace(/^https?:\/\//,``),n[`:path`]||=`/`;let i={...n,...r},a=new ClientHttp2Stream(this,i);return this._streams.add(a),a.once(`close`,()=>this._streams.delete(a)),t?.endStream&&a.end(),a}close(e){for(let e of this._streams)e.close();this._streams.clear(),super.close(e)}destroy(e,t){for(let e of this._streams)e.close();this._streams.clear(),super.destroy(e,t)}};export{ClientHttp2Session,ClientHttp2Stream,Http2Session};
1
+ import{__toCommonJS as e}from"./_virtual/_rolldown/runtime.js";import{constants as t,getDefaultSettings as n}from"./protocol.js";import{init_native_client_dispatcher as r,native_client_dispatcher_exports as i}from"./native-client-dispatcher.js";import a from"@girs/soup-3.0";import o from"@girs/gio-2.0";import s from"@girs/glib-2.0";import{EventEmitter as c}from"node:events";import{Duplex as l}from"node:stream";import{Buffer as u}from"node:buffer";import{readBytesAsync as d}from"@gjsify/utils";var Http2Session=class extends c{type=t.NGHTTP2_SESSION_CLIENT;alpnProtocol=void 0;encrypted=!1;_closed=!1;_destroyed=!1;_settings;constructor(){super(),this._settings=n()}get closed(){return this._closed}get destroyed(){return this._destroyed}get connecting(){return!1}get pendingSettingsAck(){return!1}get localSettings(){return{...this._settings}}get remoteSettings(){return n()}get originSet(){return new Set}settings(e,t){Object.assign(this._settings,e),t&&Promise.resolve().then(t)}goaway(e,n,r){this.emit(`goaway`,e??t.NGHTTP2_NO_ERROR),this.destroy()}ping(e,t){let n=e||new Uint8Array(8);return t&&Promise.resolve().then(()=>t(null,0,n)),!0}close(e){this._closed||(this._closed=!0,this.emit(`close`),e&&e())}destroy(e,t){this._destroyed||(this._destroyed=!0,this._closed=!0,e&&this.emit(`error`,e),t!==void 0&&this.emit(`goaway`,t),this.emit(`close`))}ref(){}unref(){}},ClientHttp2Stream=class extends l{_id=1;pending=!1;aborted=!1;bufferSize=0;endAfterHeaders=!1;_session;_requestHeaders;_requestChunks=[];_cancellable;_state=t.NGHTTP2_STREAM_STATE_OPEN;_responseHeaders={};_nativeStreamId=0;get id(){return this._id}get state(){return this._state}get rstCode(){return t.NGHTTP2_NO_ERROR}get session(){return this._session}get sentHeaders(){return this._requestHeaders}_setNativeStreamId(e){this._id=e,this._nativeStreamId=e,this._wireNativeBody()}constructor(e,t){super(),this._session=e,this._requestHeaders=t,this._cancellable=new o.Cancellable}_read(e){}_write(e,t,n){let r=u.isBuffer(e)?e:typeof e==`string`?u.from(e,t):u.from(e);this._nativeStreamId>0?this._session._getNativeClient().writeData(this._nativeStreamId,r,!1):this._requestChunks.push(r),n()}_final(e){let t=this._session._getNativeClient();if(t){try{if(this._nativeStreamId>0)t.writeData(this._nativeStreamId,u.alloc(0),!0);else{let n=u.concat(this._requestChunks),r=n.length===0,i=t.submitRequest(this._requestHeaders,r);if(i===0){e(Error(`Failed to submit HTTP/2 request stream`));return}this._id=i,this._nativeStreamId=i,n.length>0&&t.writeData(i,n,!0),this._wireNativeBody()}e()}catch(t){e(t instanceof Error?t:Error(String(t)))}return}this._sendRequest().then(()=>e()).catch(t=>e(t instanceof Error?t:Error(String(t))))}_wireNativeBody(){let e=this._session._getNativeClient();if(!e||this._nativeStreamId===0)return;let n=this._nativeStreamId;(async()=>{try{let r=Date.now()+3e4,i=null;for(;Date.now()<r&&(i=e.responseHeaders(n),!i);)await new Promise(e=>s.idle_add(s.PRIORITY_DEFAULT,()=>(e(),!1)));if(!i){this.destroy(Error(`Native HTTP/2 client: response headers timeout`));return}this._responseHeaders=i,this._state=t.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,this.emit(`response`,i,0);for await(let t of e.body(n))t.length>0&&this.push(t);this.push(null),this._state=t.NGHTTP2_STREAM_STATE_CLOSED}catch(e){this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this.destroy(e instanceof Error?e:Error(String(e)))}})()}async _sendRequest(){let e=this._session._getSoupSession(),n=this._session._getAuthority(),r=this._requestHeaders[`:method`]||`GET`,i=this._requestHeaders[`:path`]||`/`,o=`${this._requestHeaders[`:scheme`]||(n.startsWith(`https`)?`https`:`http`)}://${this._requestHeaders[`:authority`]||n.replace(/^https?:\/\//,``)}${i}`,c;try{c=s.Uri.parse(o,s.UriFlags.NONE)}catch{throw Error(`Invalid HTTP/2 request URL: ${o}`)}let l=new a.Message({method:r,uri:c}),f=l.get_request_headers();for(let[e,t]of Object.entries(this._requestHeaders))if(!e.startsWith(`:`))if(Array.isArray(t))for(let n of t)f.append(e,n);else f.replace(e,t);let p=u.concat(this._requestChunks);if(p.length>0){let e=this._requestHeaders[`content-type`]||`application/octet-stream`;l.set_request_body_from_bytes(e,new s.Bytes(p))}try{let n=await new Promise((t,n)=>{e.send_async(l,s.PRIORITY_DEFAULT,this._cancellable,(r,i)=>{try{t(e.send_finish(i))}catch(e){n(e)}})}),r=l.status_code,i=l.get_response_headers(),a={":status":String(r)};i.foreach((e,t)=>{let n=e.toLowerCase();if(n in a){let e=a[n];Array.isArray(e)?e.push(t):a[n]=[e,t]}else a[n]=t}),this._responseHeaders=a,this._state=t.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,this.emit(`response`,a,0);try{let e;for(;(e=await d(n,16384,s.PRIORITY_DEFAULT,this._cancellable))!==null;)e.length>0&&this.push(u.from(e))}catch{}this.push(null),this._state=t.NGHTTP2_STREAM_STATE_CLOSED}catch(e){this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this._cancellable.is_cancelled()||this.destroy(e instanceof Error?e:Error(String(e)))}}close(e,n){this._cancellable.cancel(),this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this.emit(`close`,e??t.NGHTTP2_NO_ERROR),n&&n()}priority(e){}sendTrailers(e){}setTimeout(e,t){return this}},ClientHttp2Session=class extends Http2Session{type=t.NGHTTP2_SESSION_CLIENT;_authority;_soupSession;_streams=new Set;_nativeClient=null;get nativeClient(){return this._nativeClient}constructor(e,t={}){super(),this._authority=e,this.encrypted=e.startsWith(`https:`),this._soupSession=new a.Session,t.rejectUnauthorized===!1&&this._soupSession.connect(`accept-certificate`,(e,t,n)=>!0);let n=t.nativeDispatcher??`auto`;n===`force`&&this._setupNativeClient(e,n),Promise.resolve().then(()=>{if(!this.destroyed){let e=this;e.alpnProtocol=this.encrypted?`h2`:this._nativeClient?`h2c`:void 0,this.emit(`connect`,this,null)}})}_setupNativeClient(t,n){let{Http2NativeClientDispatcher:a}=(r(),e(i));if(!a.available()){if(n===`force`)throw Error(`@gjsify/http2-native prebuild not loadable — nativeDispatcher: "force" cannot proceed`);return}let[o,s]=t.replace(/^https?:\/\//,``).split(`:`),c=parseInt(s||(this.encrypted?`443`:`80`),10);this._nativeClient=new a({onPushPromise:e=>{let t=new ClientHttp2Stream(this,e.headers);t._setNativeStreamId(e.promisedStreamId),this._streams.add(t),this.emit(`stream`,t,e.headers,0)},onGoaway:(e,t)=>{this.emit(`goaway`,t,e)},onClose:()=>{}});try{this._nativeClient.connect(o||`localhost`,c)}catch(e){if(this._nativeClient=null,n===`force`)throw e}}_getSoupSession(){return this._soupSession}_getNativeClient(){return this._nativeClient}_getAuthority(){return this._authority}request(e,t){if(this.destroyed||this.closed)throw Error(`Session is closed`);let n={},r={};for(let[t,i]of Object.entries(e))t.startsWith(`:`)?n[t]=i:r[t]=i;n[`:method`]||=`GET`,n[`:scheme`]||=this.encrypted?`https`:`http`,n[`:authority`]||=this._authority.replace(/^https?:\/\//,``),n[`:path`]||=`/`;let i={...n,...r},a=new ClientHttp2Stream(this,i);return this._streams.add(a),a.once(`close`,()=>this._streams.delete(a)),t?.endStream&&a.end(),a}close(e){for(let e of this._streams)e.close();this._streams.clear(),super.close(e)}destroy(e,t){for(let e of this._streams)e.close();this._streams.clear(),super.destroy(e,t)}};export{ClientHttp2Session,ClientHttp2Stream,Http2Session};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{constants as e}from"../protocol.js";import t from"@girs/soup-3.0";import{EventEmitter as n}from"node:events";import{Writable as r}from"node:stream";import{Buffer as i}from"node:buffer";import{closeSync as a,openSync as o,read as s,statSync as c}from"node:fs";var Http2ServerResponse=class extends r{statusCode=200;statusMessage=``;headersSent=!1;finished=!1;sendDate=!0;_soupMsg;_nativeBackend;_headers=new Map;_streaming=!1;_timeoutTimer=null;_stream=null;_detachedBody=null;get stream(){return this._stream}get socket(){return null}get isDetached(){return this._soupMsg===null&&this._nativeBackend===null}get detachedBody(){return this._detachedBody?i.concat(this._detachedBody):null}get isNative(){return this._nativeBackend!==null}get nativeBackend(){return this._nativeBackend}_setStream(e){this._stream=e}_setNativeBackend(e){this._nativeBackend=e}constructor(e,t=null){super(),this._soupMsg=e,this._nativeBackend=t,e===null&&t===null&&(this._detachedBody=[])}setHeader(e,t){return this._headers.set(e.toLowerCase(),typeof t==`number`?String(t):t),this}getHeader(e){return this._headers.get(e.toLowerCase())}removeHeader(e){this._headers.delete(e.toLowerCase())}hasHeader(e){return this._headers.has(e.toLowerCase())}getHeaderNames(){return Array.from(this._headers.keys())}getHeaders(){let e={};for(let[t,n]of this._headers)e[t]=n;return e}appendHeader(e,t){let n=e.toLowerCase(),r=this._headers.get(n);return r===void 0?this._headers.set(n,t):Array.isArray(r)?Array.isArray(t)?r.push(...t):r.push(t):this._headers.set(n,Array.isArray(t)?[r,...t]:[r,t]),this}flushHeaders(){this.headersSent||=!0}writeHead(e,t,n){if(this.statusCode=e,typeof t==`object`&&(n=t,t=void 0),typeof t==`string`&&(this.statusMessage=t),n)for(let[e,t]of Object.entries(n))this.setHeader(e,t);return this}respond(e,t){let n=Number(e[`:status`]??200),r={};for(let[t,n]of Object.entries(e))t!==`:status`&&(r[t]=typeof n==`number`?String(n):n);this.writeHead(n,r),t?.endStream&&this.end()}writeContinue(e){e&&Promise.resolve().then(e)}writeEarlyHints(e,t){t&&Promise.resolve().then(t)}addTrailers(e){}setTimeout(e,t){return this._timeoutTimer&&=(clearTimeout(this._timeoutTimer),null),t&&this.once(`timeout`,t),e>0&&(this._timeoutTimer=setTimeout(()=>{this._timeoutTimer=null,this.emit(`timeout`)},e)),this}_startStreaming(){if(this._streaming)return;if(this._streaming=!0,this.headersSent=!0,this._timeoutTimer&&=(clearTimeout(this._timeoutTimer),null),this._nativeBackend){this._nativeBackend.submitResponse(this.statusCode,this.statusMessage,this._headers,!1);return}if(!this._soupMsg)return;this._soupMsg.set_status(this.statusCode,this.statusMessage||null);let e=this._soupMsg.get_response_headers();this._headers.has(`content-length`)?e.set_encoding(t.Encoding.CONTENT_LENGTH):e.set_encoding(t.Encoding.CHUNKED);for(let[t,n]of this._headers)if(Array.isArray(n))for(let r of n)e.append(t,r);else e.replace(t,n)}_write(e,t,n){let r=i.isBuffer(e)?e:i.from(e,t);this._startStreaming(),this._nativeBackend?this._nativeBackend.submitData(r,!1):this._soupMsg?(this._soupMsg.get_response_body().append(new Uint8Array(r.buffer,r.byteOffset,r.byteLength)),this._soupMsg.unpause()):this._detachedBody&&this._detachedBody.push(r),n()}_final(e){this._streaming?this._nativeBackend?this._nativeBackend.submitData(i.alloc(0),!0):this._soupMsg&&(this._soupMsg.get_response_body().complete(),this._soupMsg.unpause()):this._sendBatchResponse(),this.finished=!0,e()}_sendBatchResponse(){if(this.headersSent)return;if(this.headersSent=!0,this._timeoutTimer&&=(clearTimeout(this._timeoutTimer),null),this._nativeBackend){this._nativeBackend.submitResponse(this.statusCode,this.statusMessage,this._headers,!0);return}if(!this._soupMsg)return;this._soupMsg.set_status(this.statusCode,this.statusMessage||null);let e=this._soupMsg.get_response_headers();for(let[t,n]of this._headers)if(Array.isArray(n))for(let r of n)e.append(t,r);else e.replace(t,n);let n=this._headers.get(`content-type`)||`text/plain`;this._soupMsg.set_response(n,t.MemoryUse.COPY,new Uint8Array)}end(e,t,n){return typeof e==`function`?(n=e,e=void 0):typeof t==`function`&&(n=t,t=void 0),e!=null&&this.write(e,t),super.end(n),this}respondWithFD(e,t,n){_respondFromFD(this,e,t,n??{},!1)}respondWithFile(e,t,n){let r;try{r=o(e,`r`)}catch(e){if(n?.onError){n.onError(e);return}throw e}_respondFromFD(this,r,t,n??{},!0)}pushStream(e,t,n){if(typeof t==`function`&&(n=t,t={}),!n)throw TypeError(`callback must be a function`);if(!this._stream){n(Error(`No associated stream`),null,{});return}this._stream.pushStream(e,t,n)}createPushResponse(e,t){if(typeof t!=`function`)throw TypeError(`callback must be a function`);this.pushStream(e,{},(e,n)=>{if(e){t(e,null);return}let r=n._res;t(null,r??null)})}},l=class ServerHttp2Stream extends n{id;pushAllowed;sentHeaders={};_res;_session;_isPushedStream;_pushedChildren=[];_pushPromiseFrame=null;_pushRequestHeaders=null;get session(){return this._session}get headersSent(){return this._res.headersSent}get closed(){return this._res.writableEnded}get destroyed(){return this._res.destroyed}get pending(){return!1}get state(){return this.closed?e.NGHTTP2_STREAM_STATE_CLOSED:e.NGHTTP2_STREAM_STATE_OPEN}get pushPromiseFrame(){return this._pushPromiseFrame}get pushRequestHeaders(){return this._pushRequestHeaders}get pushedChildren(){return this._pushedChildren}constructor(e,t=null,n={}){super(),this._res=e,this._session=t,this._isPushedStream=n.isPushedStream===!0,this.id=n.streamId??1,this.pushAllowed=!this._isPushedStream&&t?.canPush!==!1,e.on(`finish`,()=>this.emit(`close`)),e.on(`error`,e=>this.emit(`error`,e))}respond(e,t){this._res.respond(e,t)}write(e,t,n){return this._res.write(e,t,n)}end(e,t,n){return this._res.end(e,t,n),this}destroy(e){return this._res.destroy(e),this}close(t,n){n&&this.once(`close`,n);let r=this._res.nativeBackend;if(r)try{r.reset(t??e.NGHTTP2_NO_ERROR)}catch{}this._res.end()}priority(e){}setTimeout(e,t){return this._res.setTimeout(e,t),this}sendTrailers(e){}additionalHeaders(e){}respondWithFD(e,t,n){this._res.respondWithFD(e,t,n)}respondWithFile(e,t,n){this._res.respondWithFile(e,t,n)}pushStream(e,t,n){if(typeof t==`function`&&(n=t,t={}),!n)throw TypeError(`callback must be a function`);if(this._isPushedStream){let e=Object.assign(Error(`Cannot initiate nested push streams`),{code:`ERR_HTTP2_NESTED_PUSH`});n(e,null,{});return}if(this._session&&this._session.canPush===!1){let e=Object.assign(Error(`HTTP/2 server push has been disabled`),{code:`ERR_HTTP2_PUSH_DISABLED`});n(e,null,{});return}let r,i=null,a={},o={};for(let[t,n]of Object.entries(e))o[t]=typeof n==`number`?String(n):n;o[`:method`]||=`GET`,a=o;let s=this._res.nativeBackend,c=null;if(s){if(c=s.pushPromise(o),!c){let e=Object.assign(Error(`No available stream ids`),{code:`ERR_HTTP2_OUT_OF_STREAMS`});n(e,null,{});return}r=c.streamId,i=null}else if(this._session){if(r=this._session._allocatePushId(),r===0){let e=Object.assign(Error(`No available stream ids`),{code:`ERR_HTTP2_OUT_OF_STREAMS`});n(e,null,{});return}i=this._session._buildPushPromise(this.id,r,o)}else r=2;let l=c?new Http2ServerResponse(null,c):new Http2ServerResponse(_makeDetachedSoupMessage()),u=new ServerHttp2Stream(l,this._session,{isPushedStream:!0,streamId:r});u._pushPromiseFrame=i,u._pushRequestHeaders=o,l._setStream(u),this._pushedChildren.push(u),Promise.resolve().then(()=>{n(null,u,a)})}};function _makeDetachedSoupMessage(){return null}function _respondFromFD(e,t,n,r,o){let l=typeof t==`number`?t:t.fd,u=l,d={...n};if(r.statCheck)try{let t=c(_fdPath(l)??`/proc/self/fd/`+l);if(r.statCheck(t,d,r)===!1){o&&a(l),e.end();return}}catch(e){if(r.onError){r.onError(e),o&&a(l);return}}let f=Number(d[`:status`]??200);delete d[`:status`];let p={};for(let[e,t]of Object.entries(d))p[e]=typeof t==`number`?String(t):t;e.writeHead(f,p),e.flushHeaders();let m=Math.max(0,r.offset??0),h=r.length,g=64*1024,_=i.alloc(g),v=m,y=typeof h==`number`?h:1/0,b=0,readNext=()=>{if(y<=0){finish();return}s(u,_,0,Math.min(g,y),v,(t,n)=>{if(t){cleanup(t);return}if(n===0){finish();return}v+=n,b+=n,y-=n;let r=i.allocUnsafe(n);_.copy(r,0,0,n),e.write(r)?readNext():e.once(`drain`,readNext)})},finish=()=>{if(e.end(),o)try{a(u)}catch{}},cleanup=t=>{if(r.onError?r.onError(t):e.destroy(t),o)try{a(u)}catch{}};if(y===0){finish();return}readNext()}function _fdPath(e){return typeof e!=`number`||e<0?null:`/proc/self/fd/`+e}export{Http2ServerResponse,l as ServerHttp2Stream};
1
+ import"../_virtual/_rolldown/runtime.js";import{constants as e}from"../protocol.js";import t from"@girs/soup-3.0";import{EventEmitter as n}from"node:events";import{Writable as r}from"node:stream";import{Buffer as i}from"node:buffer";import{closeSync as a,openSync as o,read as s,statSync as c}from"node:fs";var Http2ServerResponse=class extends r{statusCode=200;statusMessage=``;headersSent=!1;finished=!1;sendDate=!0;_soupMsg;_nativeBackend;_headers=new Map;_streaming=!1;_timeoutTimer=null;_stream=null;_detachedBody=null;get stream(){return this._stream}get socket(){return null}get isDetached(){return this._soupMsg===null&&this._nativeBackend===null}get detachedBody(){return this._detachedBody?i.concat(this._detachedBody):null}get isNative(){return this._nativeBackend!==null}get nativeBackend(){return this._nativeBackend}_setStream(e){this._stream=e}_setNativeBackend(e){this._nativeBackend=e}constructor(e,t=null){super(),this._soupMsg=e,this._nativeBackend=t,e===null&&t===null&&(this._detachedBody=[])}setHeader(e,t){return this._headers.set(e.toLowerCase(),typeof t==`number`?String(t):t),this}getHeader(e){return this._headers.get(e.toLowerCase())}removeHeader(e){this._headers.delete(e.toLowerCase())}hasHeader(e){return this._headers.has(e.toLowerCase())}getHeaderNames(){return Array.from(this._headers.keys())}getHeaders(){let e={};for(let[t,n]of this._headers)e[t]=n;return e}appendHeader(e,t){let n=e.toLowerCase(),r=this._headers.get(n);return r===void 0?this._headers.set(n,t):Array.isArray(r)?Array.isArray(t)?r.push(...t):r.push(t):this._headers.set(n,Array.isArray(t)?[r,...t]:[r,t]),this}flushHeaders(){this.headersSent||=!0}writeHead(e,t,n){if(this.statusCode=e,typeof t==`object`&&(n=t,t=void 0),typeof t==`string`&&(this.statusMessage=t),n)for(let[e,t]of Object.entries(n))this.setHeader(e,t);return this}respond(e,t){let n=Number(e[`:status`]??200),r={};for(let[t,n]of Object.entries(e))t!==`:status`&&(r[t]=typeof n==`number`?String(n):n);this.writeHead(n,r),t?.endStream&&this.end()}writeContinue(e){e&&Promise.resolve().then(e)}writeEarlyHints(e,t){t&&Promise.resolve().then(t)}addTrailers(e){}setTimeout(e,t){return this._timeoutTimer&&=(clearTimeout(this._timeoutTimer),null),t&&this.once(`timeout`,t),e>0&&(this._timeoutTimer=setTimeout(()=>{this._timeoutTimer=null,this.emit(`timeout`)},e)),this}_startStreaming(){if(this._streaming)return;if(this._streaming=!0,this.headersSent=!0,this._timeoutTimer&&=(clearTimeout(this._timeoutTimer),null),this._nativeBackend){this._nativeBackend.submitResponse(this.statusCode,this.statusMessage,this._headers,!1);return}if(!this._soupMsg)return;this._soupMsg.set_status(this.statusCode,this.statusMessage||null);let e=this._soupMsg.get_response_headers();this._headers.has(`content-length`)?e.set_encoding(t.Encoding.CONTENT_LENGTH):e.set_encoding(t.Encoding.CHUNKED);for(let[t,n]of this._headers)if(Array.isArray(n))for(let r of n)e.append(t,r);else e.replace(t,n)}_write(e,t,n){let r=i.isBuffer(e)?e:typeof e==`string`?i.from(e,t):i.from(e);this._startStreaming(),this._nativeBackend?this._nativeBackend.submitData(r,!1):this._soupMsg?(this._soupMsg.get_response_body().append(new Uint8Array(r.buffer,r.byteOffset,r.byteLength)),this._soupMsg.unpause()):this._detachedBody&&this._detachedBody.push(r),n()}_final(e){this._streaming?this._nativeBackend?this._nativeBackend.submitData(i.alloc(0),!0):this._soupMsg&&(this._soupMsg.get_response_body().complete(),this._soupMsg.unpause()):this._sendBatchResponse(),this.finished=!0,e()}_sendBatchResponse(){if(this.headersSent)return;if(this.headersSent=!0,this._timeoutTimer&&=(clearTimeout(this._timeoutTimer),null),this._nativeBackend){this._nativeBackend.submitResponse(this.statusCode,this.statusMessage,this._headers,!0);return}if(!this._soupMsg)return;this._soupMsg.set_status(this.statusCode,this.statusMessage||null);let e=this._soupMsg.get_response_headers();for(let[t,n]of this._headers)if(Array.isArray(n))for(let r of n)e.append(t,r);else e.replace(t,n);let n=this._headers.get(`content-type`)||`text/plain`;this._soupMsg.set_response(n,t.MemoryUse.COPY,new Uint8Array)}end(e,t,n){return typeof e==`function`?(n=e,e=void 0):typeof t==`function`&&(n=t,t=void 0),e!=null&&this.write(e,t),super.end(n),this}respondWithFD(e,t,n){_respondFromFD(this,e,t,n??{},!1)}respondWithFile(e,t,n){let r;try{r=o(e,`r`)}catch(e){if(n?.onError){n.onError(e);return}throw e}_respondFromFD(this,r,t,n??{},!0)}pushStream(e,t,n){if(typeof t==`function`&&(n=t,t={}),!n)throw TypeError(`callback must be a function`);if(!this._stream){n(Error(`No associated stream`),null,{});return}this._stream.pushStream(e,t,n)}createPushResponse(e,t){if(typeof t!=`function`)throw TypeError(`callback must be a function`);this.pushStream(e,{},(e,n)=>{if(e){t(e,null);return}let r=n._res;t(null,r??null)})}},l=class ServerHttp2Stream extends n{id;pushAllowed;sentHeaders={};_res;_session;_isPushedStream;_pushedChildren=[];_pushPromiseFrame=null;_pushRequestHeaders=null;get session(){return this._session}get headersSent(){return this._res.headersSent}get closed(){return this._res.writableEnded}get destroyed(){return this._res.destroyed}get pending(){return!1}get state(){return this.closed?e.NGHTTP2_STREAM_STATE_CLOSED:e.NGHTTP2_STREAM_STATE_OPEN}get pushPromiseFrame(){return this._pushPromiseFrame}get pushRequestHeaders(){return this._pushRequestHeaders}get pushedChildren(){return this._pushedChildren}constructor(e,t=null,n={}){super(),this._res=e,this._session=t,this._isPushedStream=n.isPushedStream===!0,this.id=n.streamId??1,this.pushAllowed=!this._isPushedStream&&t?.canPush!==!1,e.on(`finish`,()=>this.emit(`close`)),e.on(`error`,e=>this.emit(`error`,e))}respond(e,t){this._res.respond(e,t)}write(e,t,n){return this._res.write(e,t,n)}end(e,t,n){return this._res.end(e,t,n),this}destroy(e){return this._res.destroy(e),this}close(t,n){n&&this.once(`close`,n);let r=this._res.nativeBackend;if(r)try{r.reset(t??e.NGHTTP2_NO_ERROR)}catch{}this._res.end()}priority(e){}setTimeout(e,t){return this._res.setTimeout(e,t),this}sendTrailers(e){}additionalHeaders(e){}respondWithFD(e,t,n){this._res.respondWithFD(e,t,n)}respondWithFile(e,t,n){this._res.respondWithFile(e,t,n)}pushStream(e,t,n){if(typeof t==`function`&&(n=t,t={}),!n)throw TypeError(`callback must be a function`);if(this._isPushedStream){let e=Object.assign(Error(`Cannot initiate nested push streams`),{code:`ERR_HTTP2_NESTED_PUSH`});n(e,null,{});return}if(this._session&&this._session.canPush===!1){let e=Object.assign(Error(`HTTP/2 server push has been disabled`),{code:`ERR_HTTP2_PUSH_DISABLED`});n(e,null,{});return}let r,i=null,a={},o={};for(let[t,n]of Object.entries(e))o[t]=typeof n==`number`?String(n):n;o[`:method`]||=`GET`,a=o;let s=this._res.nativeBackend,c=null;if(s){if(c=s.pushPromise(o),!c){let e=Object.assign(Error(`No available stream ids`),{code:`ERR_HTTP2_OUT_OF_STREAMS`});n(e,null,{});return}r=c.streamId,i=null}else if(this._session){if(r=this._session._allocatePushId(),r===0){let e=Object.assign(Error(`No available stream ids`),{code:`ERR_HTTP2_OUT_OF_STREAMS`});n(e,null,{});return}i=this._session._buildPushPromise(this.id,r,o)}else r=2;let l=c?new Http2ServerResponse(null,c):new Http2ServerResponse(_makeDetachedSoupMessage()),u=new ServerHttp2Stream(l,this._session,{isPushedStream:!0,streamId:r});u._pushPromiseFrame=i,u._pushRequestHeaders=o,l._setStream(u),this._pushedChildren.push(u),Promise.resolve().then(()=>{n(null,u,a)})}};function _makeDetachedSoupMessage(){return null}function _respondFromFD(e,t,n,r,o){let l=typeof t==`number`?t:t.fd,u=l,d={...n};if(r.statCheck)try{let t=c(_fdPath(l)??`/proc/self/fd/`+l);if(r.statCheck(t,d,r)===!1){o&&a(l),e.end();return}}catch(e){if(r.onError){r.onError(e),o&&a(l);return}}let f=Number(d[`:status`]??200);delete d[`:status`];let p={};for(let[e,t]of Object.entries(d))p[e]=typeof t==`number`?String(t):t;e.writeHead(f,p),e.flushHeaders();let m=Math.max(0,r.offset??0),h=r.length,g=64*1024,_=i.alloc(g),v=m,y=typeof h==`number`?h:1/0,b=0,readNext=()=>{if(y<=0){finish();return}s(u,_,0,Math.min(g,y),v,(t,n)=>{if(t){cleanup(t);return}if(n===0){finish();return}v+=n,b+=n,y-=n;let r=i.allocUnsafe(n);_.copy(r,0,0,n),e.write(r)?readNext():e.once(`drain`,readNext)})},finish=()=>{if(e.end(),o)try{a(u)}catch{}},cleanup=t=>{if(r.onError?r.onError(t):e.destroy(t),o)try{a(u)}catch{}};if(y===0){finish();return}readNext()}function _fdPath(e){return typeof e!=`number`||e<0?null:`/proc/self/fd/`+e}export{Http2ServerResponse,l as ServerHttp2Stream};
@@ -94,7 +94,7 @@ export declare class ClientHttp2Stream extends Duplex {
94
94
  _setNativeStreamId(streamId: number): void;
95
95
  constructor(session: ClientHttp2Session, requestHeaders: Record<string, string | string[]>);
96
96
  _read(_size: number): void;
97
- _write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
97
+ _write(chunk: string | Buffer | Uint8Array, encoding: string, callback: (error?: Error | null) => void): void;
98
98
  _final(callback: (error?: Error | null) => void): void;
99
99
  /** Wire response headers + body iteration when running on the native path. */
100
100
  private _wireNativeBody;
@@ -4,9 +4,19 @@ export { Http2ServerRequest, Http2ServerResponse, ServerHttp2Stream, ServerHttp2
4
4
  import { Http2ServerRequest, Http2ServerResponse, ServerHttp2Stream, ServerHttp2Session, Http2Server, Http2SecureServer, type ServerOptions, type SecureServerOptions } from './server.js';
5
5
  export { Http2Session, ClientHttp2Session, ClientHttp2Stream, type ClientSessionOptions, type ClientStreamOptions, } from './client-session.js';
6
6
  import { Http2Session, ClientHttp2Session, ClientHttp2Stream, type ClientSessionOptions } from './client-session.js';
7
+ import type { Socket } from 'node:net';
8
+ import type { TLSSocket } from 'node:tls';
9
+ /**
10
+ * Socket type for the `connect()` callback — matches Node's
11
+ * `net.Socket | tls.TLSSocket` shape. gjsify currently passes `null` from
12
+ * `ClientHttp2Session` because the underlying transport is Soup-managed
13
+ * (or the @gjsify/http2-native bridge); a real socket handle isn't surfaced.
14
+ * Typed as the Node union so consumer callbacks stay drop-in.
15
+ */
16
+ type ConnectSocket = Socket | TLSSocket;
7
17
  export declare function createServer(options?: ServerOptions | ((req: Http2ServerRequest, res: Http2ServerResponse) => void), handler?: (req: Http2ServerRequest, res: Http2ServerResponse) => void): Http2Server;
8
18
  export declare function createSecureServer(options: SecureServerOptions, handler?: (req: Http2ServerRequest, res: Http2ServerResponse) => void): Http2SecureServer;
9
- export declare function connect(authority: string | URL, options?: ClientSessionOptions | ((session: ClientHttp2Session, socket: any) => void), listener?: (session: ClientHttp2Session, socket: any) => void): ClientHttp2Session;
19
+ export declare function connect(authority: string | URL, options?: ClientSessionOptions | ((session: ClientHttp2Session, socket: ConnectSocket) => void), listener?: (session: ClientHttp2Session, socket: ConnectSocket) => void): ClientHttp2Session;
10
20
  export declare const sensitiveHeaders: unique symbol;
11
21
  export declare function performServerHandshake(_socket: unknown): unknown;
12
22
  declare const _default: {
@@ -16,8 +16,8 @@ export interface ServerOptions {
16
16
  peerMaxHeaderListSize?: number;
17
17
  selectPadding?: (frameLen: number, maxFrameLen: number) => number;
18
18
  settings?: Http2Settings;
19
- Http1IncomingMessage?: any;
20
- Http1ServerResponse?: any;
19
+ Http1IncomingMessage?: new (...args: unknown[]) => unknown;
20
+ Http1ServerResponse?: new (...args: unknown[]) => unknown;
21
21
  unknownProtocolTimeout?: number;
22
22
  /**
23
23
  * Native dispatcher mode (gjsify-specific, defaults to `'auto'`).
@@ -1,4 +1,6 @@
1
1
  import { Readable } from 'node:stream';
2
+ import type { Socket } from 'node:net';
3
+ import type { TLSSocket } from 'node:tls';
2
4
  import type { ServerHttp2Stream } from './response.js';
3
5
  export declare class Http2ServerRequest extends Readable {
4
6
  method: string;
@@ -11,7 +13,7 @@ export declare class Http2ServerRequest extends Readable {
11
13
  httpVersionMajor: number;
12
14
  httpVersionMinor: number;
13
15
  complete: boolean;
14
- socket: any;
16
+ socket: Socket | TLSSocket | null;
15
17
  trailers: Record<string, string>;
16
18
  rawTrailers: string[];
17
19
  private _stream;
@@ -2,7 +2,21 @@ import Soup from '@girs/soup-3.0';
2
2
  import { EventEmitter } from 'node:events';
3
3
  import { Writable } from 'node:stream';
4
4
  import { Buffer } from 'node:buffer';
5
+ import { type Stats } from 'node:fs';
6
+ import type { OutgoingHttpHeaders } from 'node:http';
5
7
  import type { ServerHttp2Session } from './session.js';
8
+ /**
9
+ * StatCheck callback signature — matches Node's
10
+ * `http2.ServerStreamFileResponseOptions.statCheck`:
11
+ * `(stats: fs.Stats, headers: OutgoingHttpHeaders, statOptions: { offset, length }) => void`.
12
+ * The user mutates headers based on stat results; returning `false` cancels
13
+ * the send (Node behaviour — wired through `_respondFromFD`).
14
+ */
15
+ type StatCheckOptions = {
16
+ offset?: number;
17
+ length?: number;
18
+ };
19
+ type StatCheck = (stats: Stats, headers: OutgoingHttpHeaders, statOptions: StatCheckOptions) => void | boolean;
6
20
  /**
7
21
  * Per-stream backend that routes writes through `SessionBridge.submit_*`
8
22
  * instead of into a Soup message. Set on responses produced by the native
@@ -66,7 +80,7 @@ export declare class Http2ServerResponse extends Writable {
66
80
  addTrailers(_headers: Record<string, string>): void;
67
81
  setTimeout(msecs: number, callback?: () => void): this;
68
82
  private _startStreaming;
69
- _write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
83
+ _write(chunk: string | Buffer | Uint8Array, encoding: string, callback: (error?: Error | null) => void): void;
70
84
  _final(callback: (error?: Error | null) => void): void;
71
85
  private _sendBatchResponse;
72
86
  end(chunk?: unknown, encoding?: BufferEncoding | (() => void), callback?: () => void): this;
@@ -83,7 +97,7 @@ export declare class Http2ServerResponse extends Writable {
83
97
  }, headers?: Record<string, string | string[] | number>, options?: {
84
98
  offset?: number;
85
99
  length?: number;
86
- statCheck?: (stat: any, headers: any, statOptions: any) => void;
100
+ statCheck?: StatCheck;
87
101
  }): void;
88
102
  /**
89
103
  * respondWithFile — stream a regular file by path. Opens the file with
@@ -96,7 +110,7 @@ export declare class Http2ServerResponse extends Writable {
96
110
  respondWithFile(path: string, headers?: Record<string, string | string[] | number>, options?: {
97
111
  offset?: number;
98
112
  length?: number;
99
- statCheck?: (stat: any, headers: any, statOptions: any) => void;
113
+ statCheck?: StatCheck;
100
114
  onError?: (err: Error) => void;
101
115
  }): void;
102
116
  /**
@@ -176,13 +190,13 @@ export declare class ServerHttp2Stream extends EventEmitter {
176
190
  }, headers?: Record<string, string | string[] | number>, options?: {
177
191
  offset?: number;
178
192
  length?: number;
179
- statCheck?: (stat: any, headers: any, statOptions: any) => void;
193
+ statCheck?: StatCheck;
180
194
  }): void;
181
195
  /** See {@link Http2ServerResponse.respondWithFile}. */
182
196
  respondWithFile(path: string, headers?: Record<string, string | string[] | number>, options?: {
183
197
  offset?: number;
184
198
  length?: number;
185
- statCheck?: (stat: any, headers: any, statOptions: any) => void;
199
+ statCheck?: StatCheck;
186
200
  onError?: (err: Error) => void;
187
201
  }): void;
188
202
  /**
@@ -199,3 +213,4 @@ export declare class ServerHttp2Stream extends EventEmitter {
199
213
  exclusive?: boolean;
200
214
  } | ((err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void), callback?: (err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void): void;
201
215
  }
216
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/http2",
3
- "version": "0.4.30",
3
+ "version": "0.4.32",
4
4
  "description": "Node.js http2 module for Gjs",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -33,8 +33,8 @@
33
33
  "http2"
34
34
  ],
35
35
  "devDependencies": {
36
- "@gjsify/cli": "^0.4.30",
37
- "@gjsify/unit": "^0.4.30",
36
+ "@gjsify/cli": "^0.4.32",
37
+ "@gjsify/unit": "^0.4.32",
38
38
  "@types/node": "^25.9.1",
39
39
  "typescript": "^6.0.3"
40
40
  },
@@ -43,8 +43,15 @@
43
43
  "@girs/glib-2.0": "2.88.0-4.0.1",
44
44
  "@girs/gobject-2.0": "2.88.0-4.0.1",
45
45
  "@girs/soup-3.0": "3.6.6-4.0.1",
46
- "@gjsify/events": "^0.4.30",
47
- "@gjsify/http2-native": "^0.4.30",
48
- "@gjsify/utils": "^0.4.30"
46
+ "@gjsify/events": "^0.4.32",
47
+ "@gjsify/http2-native": "^0.4.32",
48
+ "@gjsify/utils": "^0.4.32"
49
+ },
50
+ "gjsify": {
51
+ "runtimes": {
52
+ "gjs": "polyfill",
53
+ "node": "none",
54
+ "browser": "none"
55
+ }
49
56
  }
50
57
  }