@stacksjs/realtime 0.72.102 → 0.73.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/dist/broadcast.js +1 -1
- package/package.json +1 -1
package/dist/broadcast.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{log}from"@stacksjs/logging";import{recordBroadcast}from"./replay-buffer";import{getServer}from"./server-instance";let backpressureConfig=null;export function setBackpressureGuard(cfg){if(!cfg){backpressureConfig=null;return}backpressureConfig={maxPerSocketBytes:cfg.maxPerSocketBytes??1048576,onSlow:cfg.onSlow??((info)=>{log.warn(`[realtime] slow consumer on '${info.channelName}': ${info.backpressure} bytes buffered`)})}}export function getBackpressureGuard(){return backpressureConfig}function checkBackpressure(server,channelName){if(!backpressureConfig)return;try{const channels=server.channels??server.clients,set=channels&&typeof channels.get==="function"?channels.get(channelName):null;if(!set||typeof set[Symbol.iterator]!=="function")return;const{maxPerSocketBytes,onSlow}=backpressureConfig;for(const entry of set){const ws=entry&&typeof entry==="object"&&"ws"in entry?entry.ws:entry,bp=ws&&typeof ws==="object"&&"backpressure"in ws?ws.backpressure:null;if(typeof bp==="number"&&bp>maxPerSocketBytes)onSlow({channelName,backpressure:bp,socket:ws})}}catch{}}function hasSubscribers(server,channelName){try{if(typeof server.hasSubscribers==="function")return Boolean(server.hasSubscribers(channelName));if(typeof server.subscriberCount==="function")return server.subscriberCount(channelName)>0;const channels=server.channels??server.clients;if(channels&&typeof channels.get==="function"){const set=channels.get(channelName),size=(set&&(set.size??set.length))??null;if(typeof size==="number")return size>0}}catch{}return!0}export class Broadcast{async connect(){}async disconnect(){}subscribe(channel,callback){log.warn("Broadcast.subscribe() is a client-side operation. Use BroadcastClient instead.")}unsubscribe(channel){log.warn("Broadcast.unsubscribe() is a client-side operation. Use BroadcastClient instead.")}broadcast(channel,event,data,type="public"){const server=getServer();if(!server){log.warn("Broadcast server not initialized");return}let channelName=channel;if(type==="private"&&!channel.startsWith("private-"))channelName=`private-${channel}`;else if(type==="presence"&&!channel.startsWith("presence-"))channelName=`presence-${channel}`;if(!hasSubscribers(server,channelName)){log.debug(`[Broadcast] Skipping '${event}' on '${channelName}' - no subscribers`);return}checkBackpressure(server,channelName);recordBroadcast(channelName,event,data);try{server.broadcast(channelName,event,data)}catch(err){log.error(`[Broadcast] Failed to broadcast event '${event}' to channel '${channelName}':`,err)}}isConnected(){return getServer()!==null}}export async function runBroadcast(name,payload){const{appPath}=await import("@stacksjs/path"),bun=await import("bun");let broadcastFiles;try{broadcastFiles=bun.
|
|
1
|
+
import{log}from"@stacksjs/logging";import{recordBroadcast}from"./replay-buffer";import{getServer}from"./server-instance";let backpressureConfig=null;export function setBackpressureGuard(cfg){if(!cfg){backpressureConfig=null;return}backpressureConfig={maxPerSocketBytes:cfg.maxPerSocketBytes??1048576,onSlow:cfg.onSlow??((info)=>{log.warn(`[realtime] slow consumer on '${info.channelName}': ${info.backpressure} bytes buffered`)})}}export function getBackpressureGuard(){return backpressureConfig}function checkBackpressure(server,channelName){if(!backpressureConfig)return;try{const channels=server.channels??server.clients,set=channels&&typeof channels.get==="function"?channels.get(channelName):null;if(!set||typeof set[Symbol.iterator]!=="function")return;const{maxPerSocketBytes,onSlow}=backpressureConfig;for(const entry of set){const ws=entry&&typeof entry==="object"&&"ws"in entry?entry.ws:entry,bp=ws&&typeof ws==="object"&&"backpressure"in ws?ws.backpressure:null;if(typeof bp==="number"&&bp>maxPerSocketBytes)onSlow({channelName,backpressure:bp,socket:ws})}}catch{}}function hasSubscribers(server,channelName){try{if(typeof server.hasSubscribers==="function")return Boolean(server.hasSubscribers(channelName));if(typeof server.subscriberCount==="function")return server.subscriberCount(channelName)>0;const channels=server.channels??server.clients;if(channels&&typeof channels.get==="function"){const set=channels.get(channelName),size=(set&&(set.size??set.length))??null;if(typeof size==="number")return size>0}}catch{}return!0}export class Broadcast{async connect(){}async disconnect(){}subscribe(channel,callback){log.warn("Broadcast.subscribe() is a client-side operation. Use BroadcastClient instead.")}unsubscribe(channel){log.warn("Broadcast.unsubscribe() is a client-side operation. Use BroadcastClient instead.")}broadcast(channel,event,data,type="public"){const server=getServer();if(!server){log.warn("Broadcast server not initialized");return}let channelName=channel;if(type==="private"&&!channel.startsWith("private-"))channelName=`private-${channel}`;else if(type==="presence"&&!channel.startsWith("presence-"))channelName=`presence-${channel}`;if(!hasSubscribers(server,channelName)){log.debug(`[Broadcast] Skipping '${event}' on '${channelName}' - no subscribers`);return}checkBackpressure(server,channelName);recordBroadcast(channelName,event,data);try{server.broadcast(channelName,event,data)}catch(err){log.error(`[Broadcast] Failed to broadcast event '${event}' to channel '${channelName}':`,err)}}isConnected(){return getServer()!==null}}export async function runBroadcast(name,payload){const{appPath}=await import("@stacksjs/path"),bun=await import("bun");let broadcastFiles;try{broadcastFiles=[...new bun.Glob("Broadcasts/**/*.ts").scanSync({cwd:appPath(),absolute:!0})]}catch(error){throw Error(`Failed to scan broadcast files: ${error instanceof Error?error.message:String(error)}`)}const broadcastFile=broadcastFiles.find((file)=>file.endsWith(`${name}.ts`));if(!broadcastFile)throw Error(`Broadcast ${name} not found`);let broadcastModule;try{broadcastModule=await import(broadcastFile)}catch(error){throw Error(`Failed to import broadcast '${name}': ${error instanceof Error?error.message:String(error)}`)}const instance=broadcastModule.default;if(instance.handle){await instance.handle(payload);return}const server=getServer();if(!server)throw Error("Broadcast server not initialized");const channels=instance.broadcastOn?.()||instance.channel?.()||[],eventName=instance.broadcastAs?.()||instance.event?.()||name,data=instance.broadcastWith?.()||instance.data?.()||payload,event={shouldBroadcast:()=>!0,broadcastOn:()=>channels,broadcastAs:()=>eventName,broadcastWith:()=>data};await server.broadcaster.broadcast(event)}export async function broadcast(name,payload){if(typeof name!=="string"||name.trim().length===0)throw Error("[realtime] broadcast() requires a non-empty event name");await runBroadcast(name,payload)}
|
package/package.json
CHANGED