better-sse 0.11.0 → 0.12.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/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
  <a href="https://github.com/MatthewWid/better-sse"><img src="https://img.shields.io/github/stars/MatthewWid/better-sse?style=social" /></a>
8
8
  </p>
9
9
 
10
- A dead simple, dependency-less, spec-compliant server-side events implementation for Node, written in TypeScript.
10
+ A dead simple, dependency-less, spec-compliant server-sent events implementation for Node, written in TypeScript.
11
11
 
12
- This package aims to be the easiest to use, most compliant and most streamlined solution to server-side events with Node that is framework-agnostic and feature-rich.
12
+ This package aims to be the easiest to use, most compliant and most streamlined solution to server-sent events with Node that is framework-agnostic and feature-rich.
13
13
 
14
14
  Please consider starring the project [on GitHub ⭐](https://github.com/MatthewWid/better-sse).
15
15
 
@@ -38,7 +38,7 @@ Compared to WebSockets it has comparable performance and bandwidth usage, especi
38
38
  * Add or override the response status code and headers.
39
39
  * Fine-grained control by either sending [individual fields](./docs/api.md#eventbuffer) of events or by sending [full events with simple helpers](./docs/api.md#sessionpush-data-unknown-eventname-string-eventid-string--this).
40
40
  * Pipe [streams](https://nodejs.org/api/stream.html#stream_readable_streams) and [iterables](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) directly from the server to the client as a series of events.
41
- * Support for popular EventStream polyfills [`event-source-polyfill`](https://www.npmjs.com/package/event-source-polyfill) and [`eventsource-polyfill`](https://www.npmjs.com/package/eventsource-polyfill).
41
+ * Support for popular EventSource polyfills [`event-source-polyfill`](https://www.npmjs.com/package/event-source-polyfill) and [`eventsource-polyfill`](https://www.npmjs.com/package/eventsource-polyfill).
42
42
 
43
43
  [See a comparison with other Node SSE libraries in the documentation.](./docs/comparison.md)
44
44
 
@@ -1,6 +1,12 @@
1
1
  import { Session, DefaultSessionState } from "./Session";
2
2
  import { TypedEmitter, EventMap } from "./lib/TypedEmitter";
3
3
  interface BroadcastOptions<SessionState extends Record<string, unknown> = DefaultSessionState> {
4
+ /**
5
+ * Unique ID for the event being broadcast.
6
+ *
7
+ * If no event ID is given, the event ID is set to a unique string generated using a cryptographic pseudorandom number generator.
8
+ */
9
+ eventId?: string;
4
10
  /**
5
11
  * Filter sessions that should receive the event.
6
12
  *
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 c=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)))}))},l=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=c(this.push),this.iterate=l(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;super(),this.lastId="",this.isConnected=!1,this.state={},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=c(this.push),this.iterate=l(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 g=null!==(n=r.serializer)&&void 0!==n?n:i,y=null!==(h=r.sanitizer)&&void 0!==h?h:o;this.serialize=g,this.sanitize=y,this.buffer=new d({serializer:g,sanitizer:y}),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.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(){super(),this.state={},this.sessions=new Set,this.broadcast=(e,t="message",s={})=>{const i=a(),r=s.filter?this.activeSessions.filter(s.filter):this.sessions;for(const s of r)s.push(e,t,i);return this.emit("broadcast",e,t,i),this}}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})()));
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 c=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)))}))},l=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=c(this.push),this.iterate=l(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;super(),this.lastId="",this.isConnected=!1,this.state={},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=c(this.push),this.iterate=l(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 g=null!==(n=r.serializer)&&void 0!==n?n:i,y=null!==(h=r.sanitizer)&&void 0!==h?h:o;this.serialize=g,this.sanitize=y,this.buffer=new d({serializer:g,sanitizer:y}),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.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(){super(),this.state={},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}}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
- "description": "Dead simple, dependency-less, spec-compliant server-side events implementation for Node, written in TypeScript.",
4
- "version": "0.11.0",
3
+ "description": "Dead simple, dependency-less, spec-compliant server-sent events implementation for Node, written in TypeScript.",
4
+ "version": "0.12.0",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
7
7
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "engines": {
25
25
  "node": ">=12",
26
- "pnpm": ">=6"
26
+ "pnpm": ">=9"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/eventsource": "^1.1.11",