@gjsify/http2 0.48.0 → 0.50.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{__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
+ 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});this._session._acceptsAnyCertificate()&&l.connect(`accept-certificate`,()=>!0);let 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;_acceptAnyCertificate;_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,this._acceptAnyCertificate=t.rejectUnauthorized===!1;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}_acceptsAnyCertificate(){return this._acceptAnyCertificate}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};
@@ -114,6 +114,21 @@ export declare class ClientHttp2Session extends Http2Session {
114
114
  readonly encrypted: boolean;
115
115
  private _authority;
116
116
  private _soupSession;
117
+ /**
118
+ * `rejectUnauthorized: false` — accept the peer certificate on every message
119
+ * this session sends.
120
+ *
121
+ * It is a per-MESSAGE decision because `accept-certificate` is a `Soup.Message`
122
+ * signal and libsoup 3 installs none of that name on `Soup.Session`. This used to
123
+ * connect it on the session, which THROWS — measured on libsoup 3:
124
+ * `No signal 'accept-certificate' on object 'SoupSession'`, and `signal_list_ids`
125
+ * on `SoupSession` answers `request-queued, request-unqueued` and nothing else.
126
+ * Nothing caught it because `@girs` 4.x let `connect` take any string, so the call
127
+ * type-checked and the option was simply dead. `@girs` 5.0.0 types `connect` on the
128
+ * object's own signal names and the line stopped compiling, which is what surfaced
129
+ * it. `@gjsify/fetch` already did it per message; this is the same idiom.
130
+ */
131
+ private _acceptAnyCertificate;
117
132
  private _streams;
118
133
  private _nativeClient;
119
134
  get nativeClient(): Http2NativeClientDispatcher | null;
@@ -125,6 +140,8 @@ export declare class ClientHttp2Session extends Http2Session {
125
140
  _getNativeClient(): Http2NativeClientDispatcher | null;
126
141
  /** @internal Used by ClientHttp2Stream to build the request URL */
127
142
  _getAuthority(): string;
143
+ /** @internal Whether this session was opened with `rejectUnauthorized: false`. */
144
+ _acceptsAnyCertificate(): boolean;
128
145
  request(headers: Record<string, string | string[]>, options?: ClientStreamOptions): ClientHttp2Stream;
129
146
  close(callback?: () => void): void;
130
147
  destroy(error?: Error, code?: number): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/http2",
3
- "version": "0.48.0",
3
+ "version": "0.50.0",
4
4
  "description": "Node.js http2 module for Gjs",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -33,19 +33,19 @@
33
33
  "http2"
34
34
  ],
35
35
  "devDependencies": {
36
- "@gjsify/cli": "^0.48.0",
37
- "@gjsify/unit": "^0.48.0",
36
+ "@gjsify/cli": "^0.50.0",
37
+ "@gjsify/unit": "^0.50.0",
38
38
  "@types/node": "^25.9.2",
39
39
  "typescript": "^6.0.3"
40
40
  },
41
41
  "dependencies": {
42
- "@girs/gio-2.0": "4.6.0",
43
- "@girs/glib-2.0": "4.6.0",
44
- "@girs/gobject-2.0": "4.6.0",
45
- "@girs/soup-3.0": "4.6.0",
46
- "@gjsify/events": "^0.48.0",
47
- "@gjsify/http2-native": "^0.48.0",
48
- "@gjsify/utils": "^0.48.0"
42
+ "@girs/gio-2.0": "5.0.0",
43
+ "@girs/glib-2.0": "5.0.0",
44
+ "@girs/gobject-2.0": "5.0.0",
45
+ "@girs/soup-3.0": "5.0.0",
46
+ "@gjsify/events": "^0.50.0",
47
+ "@gjsify/http2-native": "^0.50.0",
48
+ "@gjsify/utils": "^0.50.0"
49
49
  },
50
50
  "gjsify": {
51
51
  "runtimes": {