@gjsify/http2 0.4.34 → 0.4.36
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/server/response/headers.js +1 -0
- package/lib/esm/server/response/push.js +1 -0
- package/lib/esm/server/response/respond-with-file.js +1 -0
- package/lib/esm/server/response/stream-io.js +1 -0
- package/lib/esm/server/response.js +1 -1
- package/lib/types/server/response/headers.d.ts +25 -0
- package/lib/types/server/response/push.d.ts +24 -0
- package/lib/types/server/response/respond-with-file.d.ts +35 -0
- package/lib/types/server/response/stream-io.d.ts +22 -0
- package/lib/types/server/response.d.ts +36 -121
- package/package.json +22 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../../_virtual/_rolldown/runtime.js";const e={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}};function installHeaderMethods(t){Object.assign(t,e)}export{installHeaderMethods};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../../_virtual/_rolldown/runtime.js";import{Http2ServerResponse as e,ServerHttp2Stream as t}from"../response.js";const n={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)})}},r={pushStream(n,r,i){if(typeof r==`function`&&(i=r,r={}),!i)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`});i(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`});i(e,null,{});return}let a,o=null,s={},c={};for(let[e,t]of Object.entries(n))c[e]=typeof t==`number`?String(t):t;c[`:method`]||=`GET`,s=c;let l=this._res.nativeBackend,u=null;if(l){if(u=l.pushPromise(c),!u){let e=Object.assign(Error(`No available stream ids`),{code:`ERR_HTTP2_OUT_OF_STREAMS`});i(e,null,{});return}a=u.streamId,o=null}else if(this._session){if(a=this._session._allocatePushId(),a===0){let e=Object.assign(Error(`No available stream ids`),{code:`ERR_HTTP2_OUT_OF_STREAMS`});i(e,null,{});return}o=this._session._buildPushPromise(this.id,a,c)}else a=2;let d=u?new e(null,u):new e(_makeDetachedSoupMessage()),f=new t(d,this._session,{isPushedStream:!0,streamId:a});f._pushPromiseFrame=o,f._pushRequestHeaders=c,d._setStream(f),this._pushedChildren.push(f),Promise.resolve().then(()=>{i(null,f,s)})}};function _makeDetachedSoupMessage(){return null}function installPushMethods(e,t){Object.assign(e,n),Object.assign(t,r)}export{installPushMethods};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../../_virtual/_rolldown/runtime.js";import{Buffer as e}from"node:buffer";import{closeSync as t,openSync as n,read as r,statSync as i}from"node:fs";const a={respondWithFD(e,t,n){_respondFromFD(this,e,t,n??{},!1)},respondWithFile(e,t,r){let i;try{i=n(e,`r`)}catch(e){if(r?.onError){r.onError(e);return}throw e}_respondFromFD(this,i,t,r??{},!0)}};function _respondFromFD(n,a,o,s,c){let l=typeof a==`number`?a:a.fd,u=l,d={...o};if(s.statCheck)try{let e=i(_fdPath(l)??`/proc/self/fd/`+l);if(s.statCheck(e,d,s)===!1){c&&t(l),n.end();return}}catch(e){if(s.onError){s.onError(e),c&&t(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;n.writeHead(f,p),n.flushHeaders();let m=Math.max(0,s.offset??0),h=s.length,g=64*1024,_=e.alloc(g),v=m,y=typeof h==`number`?h:1/0,b=0,readNext=()=>{if(y<=0){finish();return}r(u,_,0,Math.min(g,y),v,(t,r)=>{if(t){cleanup(t);return}if(r===0){finish();return}v+=r,b+=r,y-=r;let i=e.allocUnsafe(r);_.copy(i,0,0,r),n.write(i)?readNext():n.once(`drain`,readNext)})},finish=()=>{if(n.end(),c)try{t(u)}catch{}},cleanup=e=>{if(s.onError?s.onError(e):n.destroy(e),c)try{t(u)}catch{}};if(y===0){finish();return}readNext()}function _fdPath(e){return typeof e!=`number`||e<0?null:`/proc/self/fd/`+e}function installRespondWithFileMethods(e){Object.assign(e,a)}export{installRespondWithFileMethods};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../../_virtual/_rolldown/runtime.js";import e from"@girs/soup-3.0";import{Writable as t}from"node:stream";import{Buffer as n}from"node:buffer";const r={_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 t=this._soupMsg.get_response_headers();this._headers.has(`content-length`)?t.set_encoding(e.Encoding.CONTENT_LENGTH):t.set_encoding(e.Encoding.CHUNKED);for(let[e,n]of this._headers)if(Array.isArray(n))for(let r of n)t.append(e,r);else t.replace(e,n)},_write(e,t,r){let i=n.isBuffer(e)?e:typeof e==`string`?n.from(e,t):n.from(e);this._startStreaming(),this._nativeBackend?this._nativeBackend.submitData(i,!1):this._soupMsg?(this._soupMsg.get_response_body().append(new Uint8Array(i.buffer,i.byteOffset,i.byteLength)),this._soupMsg.unpause()):this._detachedBody&&this._detachedBody.push(i),r()},_final(e){this._streaming?this._nativeBackend?this._nativeBackend.submitData(n.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 t=this._soupMsg.get_response_headers();for(let[e,n]of this._headers)if(Array.isArray(n))for(let r of n)t.append(e,r);else t.replace(e,n);let n=this._headers.get(`content-type`)||`text/plain`;this._soupMsg.set_response(n,e.MemoryUse.COPY,new Uint8Array)},end(e,n,r){return typeof e==`function`?(r=e,e=void 0):typeof n==`function`&&(r=n,n=void 0),e!=null&&this.write(e,n),t.prototype.end.call(this,r),this}};function installStreamIoMethods(e){Object.assign(e,r)}export{installStreamIoMethods};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"../_virtual/_rolldown/runtime.js";import{constants as e}from"../protocol.js";import t
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{constants as e}from"../protocol.js";import{installHeaderMethods as t}from"./response/headers.js";import{installStreamIoMethods as n}from"./response/stream-io.js";import{installRespondWithFileMethods as r}from"./response/respond-with-file.js";import{installPushMethods as i}from"./response/push.js";import{EventEmitter as a}from"node:events";import{Writable as o}from"node:stream";import{Buffer as s}from"node:buffer";var Http2ServerResponse=class extends o{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?s.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=[])}},ServerHttp2Stream=class extends a{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)}};t(Http2ServerResponse.prototype),n(Http2ServerResponse.prototype),r(Http2ServerResponse.prototype),i(Http2ServerResponse.prototype,ServerHttp2Stream.prototype);export{Http2ServerResponse,ServerHttp2Stream};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Http2ServerResponse } from '../response.js';
|
|
2
|
+
export interface HeaderMethods {
|
|
3
|
+
setHeader(name: string, value: string | number | string[]): Http2ServerResponse;
|
|
4
|
+
getHeader(name: string): string | string[] | undefined;
|
|
5
|
+
removeHeader(name: string): void;
|
|
6
|
+
hasHeader(name: string): boolean;
|
|
7
|
+
getHeaderNames(): string[];
|
|
8
|
+
getHeaders(): Record<string, string | string[]>;
|
|
9
|
+
appendHeader(name: string, value: string | string[]): Http2ServerResponse;
|
|
10
|
+
flushHeaders(): void;
|
|
11
|
+
writeHead(statusCode: number, statusMessage?: string | Record<string, string | string[]>, headers?: Record<string, string | string[]>): Http2ServerResponse;
|
|
12
|
+
respond(headers: Record<string, string | string[] | number>, options?: {
|
|
13
|
+
endStream?: boolean;
|
|
14
|
+
}): void;
|
|
15
|
+
writeContinue(callback?: () => void): void;
|
|
16
|
+
writeEarlyHints(hints: Record<string, string | string[]>, callback?: () => void): void;
|
|
17
|
+
addTrailers(headers: Record<string, string>): void;
|
|
18
|
+
setTimeout(msecs: number, callback?: () => void): Http2ServerResponse;
|
|
19
|
+
}
|
|
20
|
+
declare module '../response.js' {
|
|
21
|
+
interface Http2ServerResponse extends HeaderMethods {
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Install header-management methods on Http2ServerResponse.prototype. */
|
|
25
|
+
export declare function installHeaderMethods(proto: object): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Http2ServerResponse, ServerHttp2Stream } from '../response.js';
|
|
2
|
+
export interface ResponsePushMethods {
|
|
3
|
+
pushStream(headers: Record<string, string | string[] | number>, options: {
|
|
4
|
+
parent?: number;
|
|
5
|
+
weight?: number;
|
|
6
|
+
exclusive?: boolean;
|
|
7
|
+
} | ((err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void), callback?: (err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void): void;
|
|
8
|
+
createPushResponse(headers: Record<string, string | string[] | number>, callback: (err: Error | null, res: Http2ServerResponse) => void): void;
|
|
9
|
+
}
|
|
10
|
+
export interface StreamPushMethods {
|
|
11
|
+
pushStream(headers: Record<string, string | string[] | number>, options: {
|
|
12
|
+
parent?: number;
|
|
13
|
+
weight?: number;
|
|
14
|
+
exclusive?: boolean;
|
|
15
|
+
} | ((err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void), callback?: (err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void): void;
|
|
16
|
+
}
|
|
17
|
+
declare module '../response.js' {
|
|
18
|
+
interface Http2ServerResponse extends ResponsePushMethods {
|
|
19
|
+
}
|
|
20
|
+
interface ServerHttp2Stream extends StreamPushMethods {
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Install push-stream methods on both class prototypes. */
|
|
24
|
+
export declare function installPushMethods(responseProto: object, streamProto: object): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Stats } from 'node:fs';
|
|
2
|
+
import type { OutgoingHttpHeaders } from 'node:http';
|
|
3
|
+
/**
|
|
4
|
+
* StatCheck callback signature — matches Node's
|
|
5
|
+
* `http2.ServerStreamFileResponseOptions.statCheck`:
|
|
6
|
+
* `(stats: fs.Stats, headers: OutgoingHttpHeaders, statOptions: { offset, length }) => void`.
|
|
7
|
+
* The user mutates headers based on stat results; returning `false` cancels
|
|
8
|
+
* the send (Node behaviour — wired through `_respondFromFD`).
|
|
9
|
+
*/
|
|
10
|
+
export type StatCheckOptions = {
|
|
11
|
+
offset?: number;
|
|
12
|
+
length?: number;
|
|
13
|
+
};
|
|
14
|
+
export type StatCheck = (stats: Stats, headers: OutgoingHttpHeaders, statOptions: StatCheckOptions) => void | boolean;
|
|
15
|
+
export interface RespondWithFileMethods {
|
|
16
|
+
respondWithFD(fd: number | {
|
|
17
|
+
fd: number;
|
|
18
|
+
}, headers?: Record<string, string | string[] | number>, options?: {
|
|
19
|
+
offset?: number;
|
|
20
|
+
length?: number;
|
|
21
|
+
statCheck?: StatCheck;
|
|
22
|
+
}): void;
|
|
23
|
+
respondWithFile(path: string, headers?: Record<string, string | string[] | number>, options?: {
|
|
24
|
+
offset?: number;
|
|
25
|
+
length?: number;
|
|
26
|
+
statCheck?: StatCheck;
|
|
27
|
+
onError?: (err: Error) => void;
|
|
28
|
+
}): void;
|
|
29
|
+
}
|
|
30
|
+
declare module '../response.js' {
|
|
31
|
+
interface Http2ServerResponse extends RespondWithFileMethods {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Install respondWithFD + respondWithFile on Http2ServerResponse.prototype. */
|
|
35
|
+
export declare function installRespondWithFileMethods(proto: object): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal streaming helpers (no Writable counterpart). Declaration-merged
|
|
3
|
+
* onto `Http2ServerResponse` so sibling methods can call them as `this.*`
|
|
4
|
+
* without type-checker complaints.
|
|
5
|
+
*
|
|
6
|
+
* We deliberately exclude the Writable lifecycle hooks (`_write` / `_final`)
|
|
7
|
+
* and the public `end()` override from the merge — their signatures already
|
|
8
|
+
* exist on the base class via `extends Writable`, and re-declaring them
|
|
9
|
+
* would collide with the inherited `Writable._write(chunk: any, ...)`
|
|
10
|
+
* overload. Those still get attached to the runtime prototype below;
|
|
11
|
+
* `Object.assign` doesn't care about the type-level merge.
|
|
12
|
+
*/
|
|
13
|
+
export interface StreamIoMethods {
|
|
14
|
+
_startStreaming(): void;
|
|
15
|
+
_sendBatchResponse(): void;
|
|
16
|
+
}
|
|
17
|
+
declare module '../response.js' {
|
|
18
|
+
interface Http2ServerResponse extends StreamIoMethods {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Install write + chunked-output + end-semantics methods on Http2ServerResponse.prototype. */
|
|
22
|
+
export declare function installStreamIoMethods(proto: object): void;
|
|
@@ -1,22 +1,9 @@
|
|
|
1
|
-
import Soup from '@girs/soup-3.0';
|
|
1
|
+
import type 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';
|
|
7
5
|
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
|
+
import type { StatCheck } from './response/respond-with-file.js';
|
|
20
7
|
/**
|
|
21
8
|
* Per-stream backend that routes writes through `SessionBridge.submit_*`
|
|
22
9
|
* instead of into a Soup message. Set on responses produced by the native
|
|
@@ -41,14 +28,20 @@ export declare class Http2ServerResponse extends Writable {
|
|
|
41
28
|
headersSent: boolean;
|
|
42
29
|
finished: boolean;
|
|
43
30
|
sendDate: boolean;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
|
|
31
|
+
/** @internal — sibling response/*.ts modules access this directly. */
|
|
32
|
+
_soupMsg: Soup.ServerMessage | null;
|
|
33
|
+
/** @internal */
|
|
34
|
+
_nativeBackend: Http2NativeBackend | null;
|
|
35
|
+
/** @internal */
|
|
36
|
+
_headers: Map<string, string | string[]>;
|
|
37
|
+
/** @internal */
|
|
38
|
+
_streaming: boolean;
|
|
39
|
+
/** @internal */
|
|
40
|
+
_timeoutTimer: ReturnType<typeof setTimeout> | null;
|
|
41
|
+
/** @internal */
|
|
42
|
+
_stream: ServerHttp2Stream | null;
|
|
43
|
+
/** @internal Detached responses (PUSH_PROMISE children) buffer their output. */
|
|
44
|
+
_detachedBody: Buffer[] | null;
|
|
52
45
|
get stream(): ServerHttp2Stream | null;
|
|
53
46
|
get socket(): null;
|
|
54
47
|
/** Whether this response is detached from a Soup connection (push streams). */
|
|
@@ -63,95 +56,23 @@ export declare class Http2ServerResponse extends Writable {
|
|
|
63
56
|
/** @internal Used by the native dispatcher to attach its submit backend. */
|
|
64
57
|
_setNativeBackend(backend: Http2NativeBackend): void;
|
|
65
58
|
constructor(soupMsg: Soup.ServerMessage | null, nativeBackend?: Http2NativeBackend | null);
|
|
66
|
-
setHeader(name: string, value: string | number | string[]): this;
|
|
67
|
-
getHeader(name: string): string | string[] | undefined;
|
|
68
|
-
removeHeader(name: string): void;
|
|
69
|
-
hasHeader(name: string): boolean;
|
|
70
|
-
getHeaderNames(): string[];
|
|
71
|
-
getHeaders(): Record<string, string | string[]>;
|
|
72
|
-
appendHeader(name: string, value: string | string[]): this;
|
|
73
|
-
flushHeaders(): void;
|
|
74
|
-
writeHead(statusCode: number, statusMessage?: string | Record<string, string | string[]>, headers?: Record<string, string | string[]>): this;
|
|
75
|
-
respond(headers: Record<string, string | string[] | number>, options?: {
|
|
76
|
-
endStream?: boolean;
|
|
77
|
-
}): void;
|
|
78
|
-
writeContinue(callback?: () => void): void;
|
|
79
|
-
writeEarlyHints(_hints: Record<string, string | string[]>, callback?: () => void): void;
|
|
80
|
-
addTrailers(_headers: Record<string, string>): void;
|
|
81
|
-
setTimeout(msecs: number, callback?: () => void): this;
|
|
82
|
-
private _startStreaming;
|
|
83
|
-
_write(chunk: string | Buffer | Uint8Array, encoding: string, callback: (error?: Error | null) => void): void;
|
|
84
|
-
_final(callback: (error?: Error | null) => void): void;
|
|
85
|
-
private _sendBatchResponse;
|
|
86
|
-
end(chunk?: unknown, encoding?: BufferEncoding | (() => void), callback?: () => void): this;
|
|
87
|
-
/**
|
|
88
|
-
* respondWithFD — stream the contents of an open file descriptor as the
|
|
89
|
-
* response body. Headers are sent once `statCheck()` (if provided) has
|
|
90
|
-
* had a chance to mutate them; payload is read in 64 KiB chunks via
|
|
91
|
-
* `fs.read()` and dispatched through the existing Soup chunked-write path.
|
|
92
|
-
*
|
|
93
|
-
* Reference: Node.js doc/api/http2.md § respondWithFD()
|
|
94
|
-
*/
|
|
95
|
-
respondWithFD(fd: number | {
|
|
96
|
-
fd: number;
|
|
97
|
-
}, headers?: Record<string, string | string[] | number>, options?: {
|
|
98
|
-
offset?: number;
|
|
99
|
-
length?: number;
|
|
100
|
-
statCheck?: StatCheck;
|
|
101
|
-
}): void;
|
|
102
|
-
/**
|
|
103
|
-
* respondWithFile — stream a regular file by path. Opens the file with
|
|
104
|
-
* fs.openSync, runs the optional `statCheck()` callback so the user can
|
|
105
|
-
* mutate headers based on stat results (last-modified, size, etag, …),
|
|
106
|
-
* then delegates to the same FD-streaming path as `respondWithFD()`.
|
|
107
|
-
*
|
|
108
|
-
* Reference: Node.js doc/api/http2.md § respondWithFile()
|
|
109
|
-
*/
|
|
110
|
-
respondWithFile(path: string, headers?: Record<string, string | string[] | number>, options?: {
|
|
111
|
-
offset?: number;
|
|
112
|
-
length?: number;
|
|
113
|
-
statCheck?: StatCheck;
|
|
114
|
-
onError?: (err: Error) => void;
|
|
115
|
-
}): void;
|
|
116
|
-
/**
|
|
117
|
-
* pushStream — request the server to push an additional resource on a
|
|
118
|
-
* fresh server-initiated stream. The Vala/nghttp2 bridge allocates the
|
|
119
|
-
* promised even stream-id and constructs the PUSH_PROMISE frame; wire-level
|
|
120
|
-
* delivery requires raw nghttp2-on-socket access that Soup does not expose,
|
|
121
|
-
* so the byte-frame is currently a no-op on the wire — but the bridge
|
|
122
|
-
* allocator and frame builder are exercised end-to-end and the callback
|
|
123
|
-
* receives a fully-usable `ServerHttp2Stream` whose `respond()` / `end()`
|
|
124
|
-
* calls write into a synthetic in-memory stream observable from tests.
|
|
125
|
-
*
|
|
126
|
-
* See STATUS.md "Open TODOs" → "http2 PUSH_PROMISE wire delivery".
|
|
127
|
-
*/
|
|
128
|
-
pushStream(headers: Record<string, string | string[] | number>, options: {
|
|
129
|
-
parent?: number;
|
|
130
|
-
weight?: number;
|
|
131
|
-
exclusive?: boolean;
|
|
132
|
-
} | ((err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void), callback?: (err: Error | null, pushStream: ServerHttp2Stream, headers: Record<string, string | string[]>) => void): void;
|
|
133
|
-
/**
|
|
134
|
-
* createPushResponse — alternate API: create a child Http2ServerResponse
|
|
135
|
-
* for the push without needing to bridge through ServerHttp2Stream. The
|
|
136
|
-
* created response shares the parent's stream allocator + bridge.
|
|
137
|
-
*
|
|
138
|
-
* Reference: Node.js doc/api/http2.md § Http2ServerResponse#createPushResponse()
|
|
139
|
-
*/
|
|
140
|
-
createPushResponse(headers: Record<string, string | string[] | number>, callback: (err: Error | null, res: Http2ServerResponse) => void): void;
|
|
141
59
|
}
|
|
142
60
|
export declare class ServerHttp2Stream extends EventEmitter {
|
|
143
61
|
readonly id: number;
|
|
144
62
|
readonly pushAllowed: boolean;
|
|
145
63
|
readonly sentHeaders: Record<string, string | string[]>;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
64
|
+
/** @internal — sibling response/*.ts modules access this directly. */
|
|
65
|
+
_res: Http2ServerResponse;
|
|
66
|
+
/** @internal */
|
|
67
|
+
_session: ServerHttp2Session | null;
|
|
68
|
+
/** @internal */
|
|
69
|
+
_isPushedStream: boolean;
|
|
70
|
+
/** @internal Children pushed off this request stream (parent → array). */
|
|
71
|
+
_pushedChildren: ServerHttp2Stream[];
|
|
72
|
+
/** @internal Cached PUSH_PROMISE frame bytes for inspection in tests. */
|
|
73
|
+
_pushPromiseFrame: Uint8Array | null;
|
|
74
|
+
/** @internal Push request headers (`:method`, `:path`, …). */
|
|
75
|
+
_pushRequestHeaders: Record<string, string | string[]> | null;
|
|
155
76
|
get session(): ServerHttp2Session | null;
|
|
156
77
|
get headersSent(): boolean;
|
|
157
78
|
get closed(): boolean;
|
|
@@ -199,18 +120,12 @@ export declare class ServerHttp2Stream extends EventEmitter {
|
|
|
199
120
|
statCheck?: StatCheck;
|
|
200
121
|
onError?: (err: Error) => void;
|
|
201
122
|
}): void;
|
|
202
|
-
/**
|
|
203
|
-
* pushStream — see {@link Http2ServerResponse.pushStream} for the full
|
|
204
|
-
* contract. This is the lower-level entry point: it allocates a promised
|
|
205
|
-
* stream-id from the session-bound `GjsifyHttp2.StreamIdAllocator`, builds
|
|
206
|
-
* the PUSH_PROMISE frame via `GjsifyHttp2.FrameEncoder`, then synthesises
|
|
207
|
-
* a child `ServerHttp2Stream` whose response surface is independent of
|
|
208
|
-
* the parent's underlying SoupServerMessage.
|
|
209
|
-
*/
|
|
210
|
-
pushStream(headers: Record<string, string | string[] | number>, options: {
|
|
211
|
-
parent?: number;
|
|
212
|
-
weight?: number;
|
|
213
|
-
exclusive?: boolean;
|
|
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;
|
|
215
123
|
}
|
|
216
|
-
|
|
124
|
+
import './response/headers.js';
|
|
125
|
+
import './response/headers.js';
|
|
126
|
+
import './response/stream-io.js';
|
|
127
|
+
import './response/stream-io.js';
|
|
128
|
+
import './response/respond-with-file.js';
|
|
129
|
+
import './response/respond-with-file.js';
|
|
130
|
+
import './response/push.js';
|
|
131
|
+
import './response/push.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/http2",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.36",
|
|
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.4.
|
|
37
|
-
"@gjsify/unit": "^0.4.
|
|
36
|
+
"@gjsify/cli": "^0.4.36",
|
|
37
|
+
"@gjsify/unit": "^0.4.36",
|
|
38
38
|
"@types/node": "^25.9.1",
|
|
39
|
-
"typescript": "^
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@girs/gio-2.0": "2.88.0-4.0.
|
|
43
|
-
"@girs/glib-2.0": "2.88.0-4.0.
|
|
44
|
-
"@girs/gobject-2.0": "2.88.0-4.0.
|
|
45
|
-
"@girs/soup-3.0": "3.6.6-4.0.
|
|
46
|
-
"@gjsify/events": "^0.4.
|
|
47
|
-
"@gjsify/http2-native": "^0.4.
|
|
48
|
-
"@gjsify/utils": "^0.4.
|
|
42
|
+
"@girs/gio-2.0": "2.88.0-4.0.4",
|
|
43
|
+
"@girs/glib-2.0": "2.88.0-4.0.4",
|
|
44
|
+
"@girs/gobject-2.0": "2.88.0-4.0.4",
|
|
45
|
+
"@girs/soup-3.0": "3.6.6-4.0.4",
|
|
46
|
+
"@gjsify/events": "^0.4.36",
|
|
47
|
+
"@gjsify/http2-native": "^0.4.36",
|
|
48
|
+
"@gjsify/utils": "^0.4.36"
|
|
49
49
|
},
|
|
50
50
|
"gjsify": {
|
|
51
51
|
"runtimes": {
|
|
@@ -53,5 +53,15 @@
|
|
|
53
53
|
"node": "none",
|
|
54
54
|
"browser": "none"
|
|
55
55
|
}
|
|
56
|
-
}
|
|
56
|
+
},
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+https://github.com/gjsify/gjsify.git",
|
|
61
|
+
"directory": "packages/node/http2"
|
|
62
|
+
},
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/gjsify/gjsify/issues"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/node/http2#readme"
|
|
57
67
|
}
|