@stacksjs/realtime 0.75.120 → 0.75.122

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/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export type { BroadcastStreamOptions } from './stream';
1
2
  export type { EmitOptions } from './emit';
2
3
  export type { BroadcastInstance } from './broadcast';
3
4
  export type { BufferedMessage, ReplayBufferConfig } from './replay-buffer';
@@ -13,7 +14,8 @@ export * from 'ts-broadcasting';
13
14
  // Note: all exports are already provided by `export * from 'ts-broadcasting'` above.
14
15
  // Aliases are provided below for convenience.
15
16
  // Server instance management
16
- export { getServer, setServer, createServer, stopServer } from './server-instance';
17
+ export { getServer, setServer, createServer, createBroadcastHub, stopServer } from './server-instance';
18
+ export { createBroadcastResponse } from './stream';
17
19
  // Stacks-specific exports
18
20
  export { emit, emitToUser, emitToUsers } from './emit';
19
21
  export { channel, channel as createChannel, Channel as StacksChannel } from './channel';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export*from"ts-broadcasting";export{getServer,setServer,createServer,stopServer}from"./server-instance";export{emit,emitToUser,emitToUsers}from"./emit";export{channel,channel as createChannel,Channel as StacksChannel}from"./channel";export{broadcast as dispatchBroadcast,runBroadcast,Broadcast as LegacyBroadcast}from"./broadcast";export{debugSnapshot,getReplayBuffer,pruneExpired,recordBroadcast,replaySince,setReplayBuffer}from"./replay-buffer";export{storeWebSocketEvent}from"./ws";export{setWsAuthenticator,getWsAuthenticator}from"./ws";
1
+ export*from"ts-broadcasting";export{getServer,setServer,createServer,createBroadcastHub,stopServer}from"./server-instance";export{createBroadcastResponse}from"./stream";export{emit,emitToUser,emitToUsers}from"./emit";export{channel,channel as createChannel,Channel as StacksChannel}from"./channel";export{broadcast as dispatchBroadcast,runBroadcast,Broadcast as LegacyBroadcast}from"./broadcast";export{debugSnapshot,getReplayBuffer,pruneExpired,recordBroadcast,replaySince,setReplayBuffer}from"./replay-buffer";export{storeWebSocketEvent}from"./ws";export{setWsAuthenticator,getWsAuthenticator}from"./ws";
@@ -21,6 +21,8 @@ export declare function setServer(server: BroadcastServer | null): void;
21
21
  * Get the global broadcast server instance
22
22
  */
23
23
  export declare function getServer(): BroadcastServer | null;
24
+ /** Initialize the native broadcast engine for HTTP stream consumers, without binding a socket port. */
25
+ export declare function createBroadcastHub(config?: ServerConfig): BroadcastServer;
24
26
  /**
25
27
  * Create and start a new broadcast server.
26
28
  *
@@ -1 +1 @@
1
- import{Broadcast}from"ts-broadcasting";import{recordBroadcast}from"./replay-buffer";import{getWsAuthenticator}from"./ws";let serverInstance=null,removeReplayHook=null;export function setServer(server){removeReplayHook?.();removeReplayHook=null;serverInstance=server;Broadcast.setServer(server);if(server)removeReplayHook=server.addBroadcastHook(({channel,event,data})=>{const seq=recordBroadcast(channel,event,data);return seq===null?void 0:{seq}})}export function getServer(){return serverInstance}function stacksConnectionAuthorizer(config){return async(req,user)=>{let accepted={};const authenticate=getWsAuthenticator();if(authenticate){const result=await authenticate(req);if(!result.ok)return{ok:!1,status:result.status,message:result.message};accepted={user:result.user,data:result.data}}const resolvedUser=accepted.user!==void 0?accepted.user:user;if(config.authorizeConnection){const result=await config.authorizeConnection(req,resolvedUser);if(result===!0)return{ok:!0,user:resolvedUser,data:accepted.data};return result}return{ok:!0,user:resolvedUser,data:accepted.data}}}export async function createServer(config){const server=new(await import("ts-broadcasting")).BroadcastServer({...config,authorizeConnection:stacksConnectionAuthorizer(config)});await server.start();setServer(server);return server}export async function stopServer(){if(serverInstance){await serverInstance.stop();setServer(null)}}
1
+ import{Broadcast,BroadcastServer as Server}from"ts-broadcasting";import{recordBroadcast}from"./replay-buffer";import{getWsAuthenticator}from"./ws";let serverInstance=null,removeReplayHook=null;export function setServer(server){removeReplayHook?.();removeReplayHook=null;serverInstance=server;Broadcast.setServer(server);if(server)removeReplayHook=server.addBroadcastHook(({channel,event,data})=>{const seq=recordBroadcast(channel,event,data);return seq===null?void 0:{seq}})}export function getServer(){return serverInstance}export function createBroadcastHub(config={}){if(serverInstance)return serverInstance;const server=new Server(config);setServer(server);return server}function stacksConnectionAuthorizer(config){return async(req,user)=>{let accepted={};const authenticate=getWsAuthenticator();if(authenticate){const result=await authenticate(req);if(!result.ok)return{ok:!1,status:result.status,message:result.message};accepted={user:result.user,data:result.data}}const resolvedUser=accepted.user!==void 0?accepted.user:user;if(config.authorizeConnection){const result=await config.authorizeConnection(req,resolvedUser);if(result===!0)return{ok:!0,user:resolvedUser,data:accepted.data};return result}return{ok:!0,user:resolvedUser,data:accepted.data}}}export async function createServer(config){const server=new(await import("ts-broadcasting")).BroadcastServer({...config,authorizeConnection:stacksConnectionAuthorizer(config)});await server.start();setServer(server);return server}export async function stopServer(){if(serverInstance){await serverInstance.stop();setServer(null)}}
@@ -0,0 +1,9 @@
1
+ /** Authenticated SSE transport for the same engine used by emit(), channels and model broadcasts. */
2
+ export declare function createBroadcastResponse(options: BroadcastStreamOptions): Promise<Response>;
3
+ export declare interface BroadcastStreamOptions {
4
+ channels: readonly string[]
5
+ authorize: () => boolean | Promise<boolean>
6
+ signal?: AbortSignal
7
+ heartbeatMs?: number
8
+ maxPending?: number
9
+ }
package/dist/stream.js ADDED
@@ -0,0 +1,7 @@
1
+ import{getServer}from"./server-instance";export async function createBroadcastResponse(options){if(!options.channels.length||typeof options.authorize!=="function")throw Error("Broadcast streams require channels and authorization");if(!await options.authorize())return new Response("Unauthorized",{status:401});const server=getServer();if(!server)throw Error("Broadcast server not initialized");const channels=new Set(options.channels),encoder=new TextEncoder,maxPending=options.maxPending??64;if(!Number.isSafeInteger(maxPending)||maxPending<1||maxPending>1024||options.heartbeatMs!==void 0&&(!Number.isFinite(options.heartbeatMs)||options.heartbeatMs<1))throw Error("Invalid broadcast stream configuration");let cleanup=()=>{};const stream=new ReadableStream({start(controller){let closed=!1,pending=0,chain=Promise.resolve(),timer,remove=()=>{};function close(){if(closed)return;closed=!0;remove();clearInterval(timer);options.signal?.removeEventListener("abort",close);try{controller.close()}catch{}}function enqueue(frame){if(closed)return;if((controller.desiredSize??0)<=0){close();return}controller.enqueue(encoder.encode(frame))}function deliver(frame){if(closed)return;if(++pending>maxPending){close();return}chain=chain.then(async()=>{if(closed)return;if(!await options.authorize()){close();return}enqueue(frame)}).catch(close).finally(()=>{pending--})}cleanup=close;remove=server.addBroadcastHook(({channel,event,data})=>{if(channels.has(channel))deliver(`data: ${JSON.stringify({channel,event,data})}
2
+
3
+ `)});enqueue(`: connected
4
+
5
+ `);timer=setInterval(()=>deliver(`: heartbeat
6
+
7
+ `),options.heartbeatMs??15000);options.signal?.addEventListener("abort",close,{once:!0});if(options.signal?.aborted)close()},cancel(){cleanup()}},{highWaterMark:maxPending});return new Response(stream,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-store","X-Accel-Buffering":"no"}})}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/realtime",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.120",
5
+ "version": "0.75.122",
6
6
  "description": "The Stacks realtime integration. Built on top of ts-broadcasting.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -58,8 +58,8 @@
58
58
  "prepublishOnly": "bun run build"
59
59
  },
60
60
  "dependencies": {
61
- "@stacksjs/logging": "0.75.120",
62
- "@stacksjs/path": "0.75.120",
61
+ "@stacksjs/logging": "0.75.122",
62
+ "@stacksjs/path": "0.75.122",
63
63
  "ts-broadcasting": "^0.0.11"
64
64
  },
65
65
  "devDependencies": {