better-sse 0.12.1 → 0.13.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.
- package/build/Channel.d.ts +13 -5
- package/build/Session.d.ts +9 -3
- package/build/createChannel.d.ts +1 -1
- package/build/createSession.d.ts +1 -1
- package/build/index.js +1 -1
- package/package.json +1 -1
package/build/Channel.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { Session, DefaultSessionState } from "./Session";
|
|
2
2
|
import { TypedEmitter, EventMap } from "./lib/TypedEmitter";
|
|
3
|
-
interface
|
|
3
|
+
interface ChannelOptions<State = DefaultChannelState> {
|
|
4
|
+
/**
|
|
5
|
+
* Custom state for this channel.
|
|
6
|
+
*
|
|
7
|
+
* Use this object to safely store information related to the channel.
|
|
8
|
+
*/
|
|
9
|
+
state?: State;
|
|
10
|
+
}
|
|
11
|
+
interface BroadcastOptions<SessionState = DefaultSessionState> {
|
|
4
12
|
/**
|
|
5
13
|
* Unique ID for the event being broadcast.
|
|
6
14
|
*
|
|
@@ -14,7 +22,7 @@ interface BroadcastOptions<SessionState extends Record<string, unknown> = Defaul
|
|
|
14
22
|
*/
|
|
15
23
|
filter?: (session: Session<SessionState>) => boolean;
|
|
16
24
|
}
|
|
17
|
-
interface ChannelEvents<SessionState
|
|
25
|
+
interface ChannelEvents<SessionState = DefaultSessionState> extends EventMap {
|
|
18
26
|
"session-registered": (session: Session<SessionState>) => void;
|
|
19
27
|
"session-deregistered": (session: Session<SessionState>) => void;
|
|
20
28
|
"session-disconnected": (session: Session<SessionState>) => void;
|
|
@@ -30,7 +38,7 @@ interface DefaultChannelState {
|
|
|
30
38
|
*
|
|
31
39
|
* You may use the second generic argument `SessionState` to enforce that only sessions with the same state type may be registered with this channel.
|
|
32
40
|
*/
|
|
33
|
-
declare class Channel<State
|
|
41
|
+
declare class Channel<State = DefaultChannelState, SessionState = DefaultSessionState> extends TypedEmitter<ChannelEvents<SessionState>> {
|
|
34
42
|
/**
|
|
35
43
|
* Custom state for this channel.
|
|
36
44
|
*
|
|
@@ -38,7 +46,7 @@ declare class Channel<State extends Record<string, unknown> = DefaultChannelStat
|
|
|
38
46
|
*/
|
|
39
47
|
state: State;
|
|
40
48
|
private sessions;
|
|
41
|
-
constructor();
|
|
49
|
+
constructor(options?: ChannelOptions<State>);
|
|
42
50
|
/**
|
|
43
51
|
* List of the currently active sessions subscribed to this channel.
|
|
44
52
|
*/
|
|
@@ -77,5 +85,5 @@ declare class Channel<State extends Record<string, unknown> = DefaultChannelStat
|
|
|
77
85
|
*/
|
|
78
86
|
broadcast: (data: unknown, eventName?: string, options?: BroadcastOptions<SessionState>) => this;
|
|
79
87
|
}
|
|
80
|
-
export type { BroadcastOptions, ChannelEvents, DefaultChannelState };
|
|
88
|
+
export type { ChannelOptions, BroadcastOptions, ChannelEvents, DefaultChannelState, };
|
|
81
89
|
export { Channel };
|
package/build/Session.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { IncomingMessage as Http1ServerRequest, ServerResponse as Http1ServerRes
|
|
|
4
4
|
import { Http2ServerRequest, Http2ServerResponse } from "http2";
|
|
5
5
|
import { EventBuffer, EventBufferOptions } from "./EventBuffer";
|
|
6
6
|
import { TypedEmitter, EventMap } from "./lib/TypedEmitter";
|
|
7
|
-
interface SessionOptions extends Pick<EventBufferOptions, "serializer" | "sanitizer"> {
|
|
7
|
+
interface SessionOptions<State = DefaultSessionState> extends Pick<EventBufferOptions, "serializer" | "sanitizer"> {
|
|
8
8
|
/**
|
|
9
9
|
* Whether to trust or ignore the last event ID given by the client in the `Last-Event-ID` request header.
|
|
10
10
|
*
|
|
@@ -50,6 +50,12 @@ interface SessionOptions extends Pick<EventBufferOptions, "serializer" | "saniti
|
|
|
50
50
|
* Additional headers to be sent along with the response.
|
|
51
51
|
*/
|
|
52
52
|
headers?: OutgoingHttpHeaders;
|
|
53
|
+
/**
|
|
54
|
+
* Custom state for this session.
|
|
55
|
+
*
|
|
56
|
+
* Use this object to safely store information related to the session and user.
|
|
57
|
+
*/
|
|
58
|
+
state?: State;
|
|
53
59
|
}
|
|
54
60
|
interface DefaultSessionState {
|
|
55
61
|
[key: string]: unknown;
|
|
@@ -74,7 +80,7 @@ interface SessionEvents extends EventMap {
|
|
|
74
80
|
* @param res - The Node HTTP {@link https://nodejs.org/api/http.html#http_class_http_serverresponse | IncomingMessage} object.
|
|
75
81
|
* @param options - Options given to the session instance.
|
|
76
82
|
*/
|
|
77
|
-
declare class Session<State
|
|
83
|
+
declare class Session<State = DefaultSessionState> extends TypedEmitter<SessionEvents> {
|
|
78
84
|
/**
|
|
79
85
|
* The last event ID sent to the client.
|
|
80
86
|
*
|
|
@@ -118,7 +124,7 @@ declare class Session<State extends Record<string, unknown> = DefaultSessionStat
|
|
|
118
124
|
private keepAliveTimer?;
|
|
119
125
|
private statusCode;
|
|
120
126
|
private headers;
|
|
121
|
-
constructor(req: Http1ServerRequest | Http2ServerRequest, res: Http1ServerResponse | Http2ServerResponse, options?: SessionOptions);
|
|
127
|
+
constructor(req: Http1ServerRequest | Http2ServerRequest, res: Http1ServerResponse | Http2ServerResponse, options?: SessionOptions<State>);
|
|
122
128
|
private initialize;
|
|
123
129
|
private onDisconnected;
|
|
124
130
|
private keepAlive;
|
package/build/createChannel.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Channel } from "./Channel";
|
|
2
|
-
declare const createChannel: <State
|
|
2
|
+
declare const createChannel: <State, SessionState>(options?: import("./Channel").ChannelOptions<State> | undefined) => Channel<State, SessionState>;
|
|
3
3
|
export { createChannel };
|
package/build/createSession.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { Session } from "./Session";
|
|
|
2
2
|
/**
|
|
3
3
|
* Create a new session and return the session instance once it has connected.
|
|
4
4
|
*/
|
|
5
|
-
declare const createSession: <State
|
|
5
|
+
declare const createSession: <State>(req: import("http").IncomingMessage | import("http2").Http2ServerRequest, res: import("http").ServerResponse<import("http").IncomingMessage> | import("http2").Http2ServerResponse, options?: import("./Session").SessionOptions<State> | undefined) => Promise<Session<State>>;
|
|
6
6
|
export { createSession };
|
package/build/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var s=t();for(var i in s)("object"==typeof exports?exports:e)[i]=s[i]}}(global,(()=>(()=>{"use strict";var e={n:t=>{var s=t&&t.__esModule?()=>t.default:()=>t;return e.d(s,{a:s}),s},d:(t,s)=>{for(var i in s)e.o(s,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:s[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{Channel:()=>g,EventBuffer:()=>d,Session:()=>m,SseError:()=>v,createChannel:()=>y,createEventBuffer:()=>w,createSession:()=>b});const s=require("http"),i=e=>JSON.stringify(e),r=/(\r\n|\r|\n)/g,n=/\n+$/g,o=e=>{let t=e;return t=t.replace(r,"\n"),t=t.replace(n,""),t},h=require("crypto");let a;a=h.randomUUID?()=>(0,h.randomUUID)():()=>(0,h.randomBytes)(4).toString("hex");const
|
|
1
|
+
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var s=t();for(var i in s)("object"==typeof exports?exports:e)[i]=s[i]}}(global,(()=>(()=>{"use strict";var e={n:t=>{var s=t&&t.__esModule?()=>t.default:()=>t;return e.d(s,{a:s}),s},d:(t,s)=>{for(var i in s)e.o(s,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:s[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{Channel:()=>g,EventBuffer:()=>d,Session:()=>m,SseError:()=>v,createChannel:()=>y,createEventBuffer:()=>w,createSession:()=>b});const s=require("http"),i=e=>JSON.stringify(e),r=/(\r\n|\r|\n)/g,n=/\n+$/g,o=e=>{let t=e;return t=t.replace(r,"\n"),t=t.replace(n,""),t},h=require("crypto");let a;a=h.randomUUID?()=>(0,h.randomUUID)():()=>(0,h.randomBytes)(4).toString("hex");const l=e=>async(t,s={})=>{const{eventName:i="stream"}=s;return await new Promise(((s,r)=>{t.on("data",(t=>{let s;s=Buffer.isBuffer(t)?t.toString():t,e(s,i)})),t.once("end",(()=>s(!0))),t.once("close",(()=>s(!0))),t.once("error",(e=>r(e)))}))},c=e=>async(t,s={})=>{const{eventName:i="iteration"}=s;for await(const s of t)e(s,i)};class d{constructor(e={}){var t,s;this.buffer="",this.writeField=(e,t)=>{const s=this.sanitize(t);return this.buffer+=e+":"+s+"\n",this},this.data=e=>{const t=this.serialize(e);return this.writeField("data",t),this},this.id=(e="")=>(this.writeField("id",e),this),this.retry=e=>{const t=e.toString();return this.writeField("retry",t),this},this.comment=(e="")=>(this.writeField("",e),this),this.dispatch=()=>(this.buffer+="\n",this),this.push=(e,t="message",s=a())=>(this.event(t).id(s).data(e).dispatch(),this),this.stream=l(this.push),this.iterate=c(this.push),this.clear=()=>(this.buffer="",this),this.read=()=>this.buffer,this.serialize=null!==(t=e.serializer)&&void 0!==t?t:i,this.sanitize=null!==(s=e.sanitizer)&&void 0!==s?s:o}event(e){return this.writeField("event",e),this}}const u=require("events");var f=e.n(u);class p extends(f()){addListener(e,t){return super.addListener(e,t)}prependListener(e,t){return super.prependListener(e,t)}prependOnceListener(e,t){return super.prependOnceListener(e,t)}on(e,t){return super.on(e,t)}once(e,t){return super.once(e,t)}emit(e,...t){return super.emit(e,...t)}off(e,t){return super.off(e,t)}removeListener(e,t){return super.removeListener(e,t)}}class v extends Error{constructor(e){super(e),this.message=`better-sse: ${e}`}}class m extends p{constructor(e,t,r={}){var n,h,u,f,p,m,b,g;super(),this.lastId="",this.isConnected=!1,this.initialize=()=>{var e,t,i;const r=`http://${this.req.headers.host}${this.req.url}`,n=new URL(r).searchParams;if(this.trustClientEventId){const s=null!==(i=null!==(t=null!==(e=this.req.headers["last-event-id"])&&void 0!==e?e:n.get("lastEventId"))&&void 0!==t?t:n.get("evs_last_event_id"))&&void 0!==i?i:"";this.lastId=s}const o={};this.res instanceof s.ServerResponse?(o["Content-Type"]="text/event-stream",o["Cache-Control"]="private, no-cache, no-store, no-transform, must-revalidate, max-age=0",o.Connection="keep-alive",o.Pragma="no-cache",o["X-Accel-Buffering"]="no"):(o["content-type"]="text/event-stream",o["cache-control"]="private, no-cache, no-store, no-transform, must-revalidate, max-age=0",o.pragma="no-cache",o["x-accel-buffering"]="no");for(const[e,t]of Object.entries(this.headers))o[e]=null!=t?t:"";this.res.writeHead(this.statusCode,o),n.has("padding")&&this.buffer.comment(" ".repeat(2049)).dispatch(),n.has("evs_preamble")&&this.buffer.comment(" ".repeat(2056)).dispatch(),null!==this.initialRetry&&this.buffer.retry(this.initialRetry).dispatch(),this.flush(),null!==this.keepAliveInterval&&(this.keepAliveTimer=setInterval(this.keepAlive,this.keepAliveInterval)),this.isConnected=!0,this.emit("connected")},this.onDisconnected=()=>{this.req.removeListener("close",this.onDisconnected),this.res.removeListener("close",this.onDisconnected),this.keepAliveTimer&&clearInterval(this.keepAliveTimer),this.isConnected=!1,this.emit("disconnected")},this.keepAlive=()=>{this.buffer.comment().dispatch(),this.flush()},this.data=e=>(this.buffer.data(e),this),this.id=(e="")=>(this.buffer.id(e),this.lastId=e,this),this.retry=e=>(this.buffer.retry(e),this),this.comment=e=>(this.buffer.comment(e),this),this.dispatch=()=>(this.buffer.dispatch(),this),this.flush=()=>(this.res.write(this.buffer.read()),this.buffer.clear(),this),this.push=(e,t="message",s=a())=>{if(!this.isConnected)throw new v("Cannot push data to a non-active session.");return this.buffer.push(e,t,s),this.flush(),this.lastId=s,this.emit("push",e,t,s),this},this.stream=l(this.push),this.iterate=c(this.push),this.batch=async e=>{if(e instanceof d)this.res.write(e.read());else{const t=new d({serializer:this.serialize,sanitizer:this.sanitize});await e(t),this.res.write(t.read())}},this.req=e,this.res=t;const y=null!==(n=r.serializer)&&void 0!==n?n:i,w=null!==(h=r.sanitizer)&&void 0!==h?h:o;this.serialize=y,this.sanitize=w,this.buffer=new d({serializer:y,sanitizer:w}),this.trustClientEventId=null===(u=r.trustClientEventId)||void 0===u||u,this.initialRetry=null===r.retry?null:null!==(f=r.retry)&&void 0!==f?f:2e3,this.keepAliveInterval=null===r.keepAlive?null:null!==(p=r.keepAlive)&&void 0!==p?p:1e4,this.statusCode=null!==(m=r.statusCode)&&void 0!==m?m:200,this.headers=null!==(b=r.headers)&&void 0!==b?b:{},this.state=null!==(g=r.state)&&void 0!==g?g:{},this.req.once("close",this.onDisconnected),this.res.once("close",this.onDisconnected),setImmediate(this.initialize)}event(e){return this.buffer.event(e),this}}const b=(...e)=>new Promise((t=>{const s=new m(...e);s.once("connected",(()=>{t(s)}))}));class g extends p{constructor(e={}){var t;super(),this.sessions=new Set,this.broadcast=(e,t="message",s={})=>{var i;const r=null!==(i=s.eventId)&&void 0!==i?i:a(),n=s.filter?this.activeSessions.filter(s.filter):this.sessions;for(const s of n)s.push(e,t,r);return this.emit("broadcast",e,t,r),this},this.state=null!==(t=e.state)&&void 0!==t?t:{}}get activeSessions(){return Array.from(this.sessions)}get sessionCount(){return this.sessions.size}register(e){if(this.sessions.has(e))return this;if(!e.isConnected)throw new v("Cannot register a non-active session.");return e.once("disconnected",(()=>{this.emit("session-disconnected",e),this.deregister(e)})),this.sessions.add(e),this.emit("session-registered",e),this}deregister(e){return this.sessions.has(e)?(this.sessions.delete(e),this.emit("session-deregistered",e),this):this}}const y=(...e)=>new g(...e),w=(...e)=>new d(...e);return t})()));
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-sse",
|
|
3
3
|
"description": "Dead simple, dependency-less, spec-compliant server-sent events implementation for Node, written in TypeScript.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.13.0",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
7
7
|
"license": "MIT",
|