verani 0.4.0 → 0.4.2

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/verani.cjs CHANGED
@@ -1 +1 @@
1
- const require_types=require(`./types-083oWz55.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(e,x){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(x)}off(e,x){let S=this.handlers.get(e);S&&(x?(S.delete(x),S.size===0&&this.handlers.delete(e)):this.handlers.delete(e))}async emit(e,x,S){let C=this.handlers.get(e);if(C&&C.size>0){let e=[];for(let w of C)try{let C=w(x,S);C instanceof Promise&&e.push(C)}catch{}await Promise.all(e)}let w=this.handlers.get(`*`);if(w&&w.size>0){let e=[];for(let C of w)try{let w=C(x,S);w instanceof Promise&&e.push(w)}catch{}await Promise.all(e)}}hasHandlers(e){return this.handlers.has(e)&&this.handlers.get(e).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(e){let x=crypto.randomUUID(),S=crypto.randomUUID(),C=new URL(e.url).searchParams.get(`channels`);return{userId:x,clientId:S,channels:C?C.split(`,`).map(e=>e.trim()).filter(Boolean):[`default`]}}function defineRoom(e){let x=e.eventEmitter||createRoomEventEmitter();return{name:e.name,websocketPath:e.websocketPath,extractMeta:e.extractMeta||defaultExtractMeta,onConnect:e.onConnect,onDisconnect:e.onDisconnect,onMessage:e.onMessage,onError:e.onError,onHibernationRestore:e.onHibernationRestore,eventEmitter:x,on(e,S){x.on(e,S)},off(e,S){x.off(e,S)}}}function cleanupStaleSessions(e){let x=0,S=[];for(let[x,C]of e.entries())x.readyState!==WebSocket.OPEN&&S.push(x);for(let C of S)e.delete(C),x++;return x}function decodeFrame$1(x){return require_types.o(x)??{type:`invalid`}}function encodeFrame$1(x){return require_types.r(x)}function broadcast(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:x,data:S}),E=[];for(let{ws:S,meta:D}of e.values())if(D.channels.includes(x)&&!(C?.except&&S===C.except)&&!(C?.userIds&&!C.userIds.includes(D.userId))&&!(C?.clientIds&&!C.clientIds.includes(D.clientId))){if(S.readyState!==WebSocket.OPEN){E.push(S);continue}try{S.send(T),w++}catch{E.push(S)}}for(let x of E)e.delete(x);return E.length,w}function sendToUser(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:S,data:C}),E=[];for(let{ws:C,meta:D}of e.values())if(D.userId===x&&D.channels.includes(S)){if(C.readyState!==WebSocket.OPEN){E.push(C);continue}try{C.send(T),w++}catch{E.push(C)}}for(let x of E)e.delete(x);return E.length,w}function getSessionCount(e){return e.size}function getConnectedUserIds(e){let x=new Set;for(let{meta:S}of e.values())x.add(S.userId);return Array.from(x)}function getUserSessions(e,x){let S=[];for(let{ws:C,meta:w}of e.values())w.userId===x&&S.push(C);return S}function getStorage(e){return e.storage}function sanitizeToClassName(e){return e.replace(/^\/+/,``).split(/[-_\/\s]+/).map(e=>e.replace(/[^a-zA-Z0-9]/g,``)).filter(e=>e.length>0).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(e){return function(x){return{locationHint:`me`,sockets:{upgradePath:e.websocketPath}}}}function isValidConnectionMeta(e){return!(!e||typeof e!=`object`||typeof e.userId!=`string`||!e.userId||typeof e.clientId!=`string`||!e.clientId||!Array.isArray(e.channels)||!e.channels.every(e=>typeof e==`string`))}function storeAttachment(e,x){e.serializeAttachment(x)}function restoreSessions(e){let x=0,S=0;for(let C of e.ctx.getWebSockets()){if(C.readyState!==WebSocket.OPEN){S++;continue}let w=C.deserializeAttachment();if(!w){S++;continue}if(!isValidConnectionMeta(w)){S++;continue}e.sessions.set(C,{ws:C,meta:w}),x++}}async function onInit(e,x){try{restoreSessions(e)}catch{}if(x.onHibernationRestore&&e.sessions.size>0)try{await x.onHibernationRestore(e)}catch{}else x.onHibernationRestore&&e.sessions.size}function createUserEmitBuilder(e,x,S){return{emit(C,w){return sendToUser(x,e,S,{type:C,...w})}}}function createChannelEmitBuilder(e,x,S){return{emit(C,w){return broadcast(x,e,{type:C,...w},S)}}}function createSocketEmit(e){let x=e.meta.channels[0]||`default`;return{emit(S,C){if(e.ws.readyState===WebSocket.OPEN)try{let w={type:`event`,channel:x,data:{type:S,...C}};e.ws.send(encodeFrame$1(w))}catch{}},to(S){return e.meta.channels.includes(S)?createChannelEmitBuilder(S,e.actor.sessions,{except:e.ws}):createUserEmitBuilder(S,e.actor.sessions,x)}}}function createActorEmit(e){return{emit(x,S){let C={type:x,...S};return broadcast(e.sessions,`default`,C)},to(x){return createChannelEmitBuilder(x,e.sessions)}}}async function onWebSocketConnect(e,x,S,C){let w;try{w=x.extractMeta?await x.extractMeta(C):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(S,w);let T={actor:e,ws:S,meta:w,frame:{type:`connect`}};if(x.onConnect){let C={actor:e,ws:S,meta:w,emit:createSocketEmit(T)};await x.onConnect(C)}e.sessions.set(S,{ws:S,meta:w})}catch(C){if(x.onError&&w)try{let T={actor:e,ws:S,meta:w,frame:{type:`error`}};await x.onError(C,{actor:e,ws:S,meta:w,emit:createSocketEmit(T)})}catch{}S.close(1011,`Internal server error`)}}async function onWebSocketMessage(e,x,S,C){let w;try{let T=decodeFrame$1(C);if(T&&T.type===`ping`){if(S.readyState===WebSocket.OPEN)try{S.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!T||T.type===`invalid`||(w=e.sessions.get(S),!w))return;let E={actor:e,ws:S,meta:w.meta,frame:T,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:T})},O=x.eventEmitter;O&&O.hasHandlers&&O.hasHandlers(T.type)?await O.emit(T.type,E,T.data||{}):x.onMessage&&await x.onMessage(E,T)}catch(C){if(x.onError&&w)try{await x.onError(C,{actor:e,ws:S,meta:w.meta,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(e,x,S){try{let C=e.sessions.get(S);if(e.sessions.delete(S),C&&x.onDisconnect){let w={actor:e,ws:S,meta:C.meta,frame:{type:`disconnect`}},T={actor:e,ws:S,meta:C.meta,emit:createSocketEmit(w)};await x.onDisconnect(T)}}catch{}}function createActorHandler(e){let S=sanitizeToClassName(e.name||e.websocketPath||`VeraniActor`);class C extends __cloudflare_actors.Actor{constructor(...e){super(...e),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(e)}async shouldUpgradeWebSocket(e){return!0}async fetch(x){let S=new URL(x.url),C=x.headers.get(`Upgrade`);return S.pathname===e.websocketPath&&C===`websocket`&&await this.shouldUpgradeWebSocket(x)?this.onWebSocketUpgrade(x):this.onRequest(x)}async onInit(){await onInit(this,e)}async onWebSocketConnect(x,S){await onWebSocketConnect(this,e,x,S)}async onWebSocketMessage(x,S){await onWebSocketMessage(this,e,x,S)}async onWebSocketDisconnect(x){await onWebSocketDisconnect(this,e,x)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(e,x,S){return broadcast(this.sessions,e,x,S)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(e){return getUserSessions(this.sessions,e)}sendToUser(e,x,S){return sendToUser(this.sessions,e,x,S)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(C,`name`,{value:S,writable:!1,configurable:!0}),C}exports.PROTOCOL_VERSION=require_types.t,exports.createActorHandler=createActorHandler,exports.decodeClientMessage=require_types.a,exports.decodeFrame=require_types.o,exports.decodeServerMessage=require_types.s,exports.defineRoom=defineRoom,exports.encodeClientMessage=require_types.n,exports.encodeFrame=require_types.r,exports.encodeServerMessage=require_types.i,exports.restoreSessions=restoreSessions,exports.storeAttachment=storeAttachment;
1
+ const require_types=require(`./types-083oWz55.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(e,x){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(x)}off(e,x){let S=this.handlers.get(e);S&&(x?(S.delete(x),S.size===0&&this.handlers.delete(e)):this.handlers.delete(e))}async emit(e,x,S){let C=this.handlers.get(e);if(C&&C.size>0){let e=[];for(let w of C)try{let C=w(x,S);C instanceof Promise&&e.push(C)}catch{}await Promise.all(e)}let w=this.handlers.get(`*`);if(w&&w.size>0){let e=[];for(let C of w)try{let w=C(x,S);w instanceof Promise&&e.push(w)}catch{}await Promise.all(e)}}hasHandlers(e){return this.handlers.has(e)&&this.handlers.get(e).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(e){let x=crypto.randomUUID(),S=crypto.randomUUID(),C=new URL(e.url).searchParams.get(`channels`);return{userId:x,clientId:S,channels:C?C.split(`,`).map(e=>e.trim()).filter(Boolean):[`default`]}}function defineRoom(e){let x=e.eventEmitter||createRoomEventEmitter();return{name:e.name,websocketPath:e.websocketPath,extractMeta:e.extractMeta||(e=>defaultExtractMeta(e)),onConnect:e.onConnect,onDisconnect:e.onDisconnect,onMessage:e.onMessage,onError:e.onError,onHibernationRestore:e.onHibernationRestore,eventEmitter:x,on(e,S){x.on(e,S)},off(e,S){x.off(e,S)}}}function cleanupStaleSessions(e){let x=0,S=[];for(let[x,C]of e.entries())x.readyState!==WebSocket.OPEN&&S.push(x);for(let C of S)e.delete(C),x++;return x}function decodeFrame$1(x){return require_types.o(x)??{type:`invalid`}}function encodeFrame$1(x){return require_types.r(x)}function broadcast(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:x,data:S}),E=[];for(let{ws:S,meta:D}of e.values())if(D.channels.includes(x)&&!(C?.except&&S===C.except)&&!(C?.userIds&&!C.userIds.includes(D.userId))&&!(C?.clientIds&&!C.clientIds.includes(D.clientId))){if(S.readyState!==WebSocket.OPEN){E.push(S);continue}try{S.send(T),w++}catch{E.push(S)}}for(let x of E)e.delete(x);return E.length,w}function sendToUser(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:S,data:C}),E=[];for(let{ws:C,meta:D}of e.values())if(D.userId===x&&D.channels.includes(S)){if(C.readyState!==WebSocket.OPEN){E.push(C);continue}try{C.send(T),w++}catch{E.push(C)}}for(let x of E)e.delete(x);return E.length,w}function getSessionCount(e){return e.size}function getConnectedUserIds(e){let x=new Set;for(let{meta:S}of e.values())x.add(S.userId);return Array.from(x)}function getUserSessions(e,x){let S=[];for(let{ws:C,meta:w}of e.values())w.userId===x&&S.push(C);return S}function getStorage(e){return e.storage}function sanitizeToClassName(e){return e.replace(/^\/+/,``).split(/[-_\/\s]+/).map(e=>e.replace(/[^a-zA-Z0-9]/g,``)).filter(e=>e.length>0).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(e){return function(x){return{locationHint:`me`,sockets:{upgradePath:e.websocketPath}}}}function isValidConnectionMeta(e){return!(!e||typeof e!=`object`||typeof e.userId!=`string`||!e.userId||typeof e.clientId!=`string`||!e.clientId||!Array.isArray(e.channels)||!e.channels.every(e=>typeof e==`string`))}function storeAttachment(e,x){e.serializeAttachment(x)}function restoreSessions(e){let x=0,S=0;for(let C of e.ctx.getWebSockets()){if(C.readyState!==WebSocket.OPEN){S++;continue}let w=C.deserializeAttachment();if(!w){S++;continue}if(!isValidConnectionMeta(w)){S++;continue}e.sessions.set(C,{ws:C,meta:w}),x++}}async function onInit(e,x){try{restoreSessions(e)}catch{}if(x.onHibernationRestore&&e.sessions.size>0)try{await x.onHibernationRestore(e)}catch{}else x.onHibernationRestore&&e.sessions.size}function createUserEmitBuilder(e,x,S){return{emit(C,w){return sendToUser(x,e,S,{type:C,...w})}}}function createChannelEmitBuilder(e,x,S){return{emit(C,w){return broadcast(x,e,{type:C,...w},S)}}}function createSocketEmit(e){let x=e.meta.channels[0]||`default`;return{emit(S,C){if(e.ws.readyState===WebSocket.OPEN)try{let w={type:`event`,channel:x,data:{type:S,...C}};e.ws.send(encodeFrame$1(w))}catch{}},to(S){return e.meta.channels.includes(S)?createChannelEmitBuilder(S,e.actor.sessions,{except:e.ws}):createUserEmitBuilder(S,e.actor.sessions,x)}}}function createActorEmit(e){return{emit(x,S){let C={type:x,...S};return broadcast(e.sessions,`default`,C)},to(x){return createChannelEmitBuilder(x,e.sessions)}}}async function onWebSocketConnect(e,x,S,C){let w;try{w=x.extractMeta?await x.extractMeta(C):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(S,w);let T={actor:e,ws:S,meta:w,frame:{type:`connect`}};if(x.onConnect){let C={actor:e,ws:S,meta:w,emit:createSocketEmit(T)};await x.onConnect(C)}e.sessions.set(S,{ws:S,meta:w})}catch(C){if(x.onError&&w)try{let T={actor:e,ws:S,meta:w,frame:{type:`error`}};await x.onError(C,{actor:e,ws:S,meta:w,emit:createSocketEmit(T)})}catch{}S.close(1011,`Internal server error`)}}async function onWebSocketMessage(e,x,S,C){let w;try{let T=decodeFrame$1(C);if(T&&T.type===`ping`){if(S.readyState===WebSocket.OPEN)try{S.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!T||T.type===`invalid`||(w=e.sessions.get(S),!w))return;let E={actor:e,ws:S,meta:w.meta,frame:T,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:T})},O=x.eventEmitter;O&&O.hasHandlers&&O.hasHandlers(T.type)?await O.emit(T.type,E,T.data||{}):x.onMessage&&await x.onMessage(E,T)}catch(C){if(x.onError&&w)try{await x.onError(C,{actor:e,ws:S,meta:w.meta,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(e,x,S){try{let C=e.sessions.get(S);if(e.sessions.delete(S),C&&x.onDisconnect){let w={actor:e,ws:S,meta:C.meta,frame:{type:`disconnect`}},T={actor:e,ws:S,meta:C.meta,emit:createSocketEmit(w)};await x.onDisconnect(T)}}catch{}}function createActorHandler(e){let S=sanitizeToClassName(e.name||e.websocketPath||`VeraniActor`);class C extends __cloudflare_actors.Actor{constructor(...e){super(...e),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(e)}async shouldUpgradeWebSocket(e){return!0}async fetch(x){let S=new URL(x.url),C=x.headers.get(`Upgrade`);return S.pathname===e.websocketPath&&C===`websocket`&&await this.shouldUpgradeWebSocket(x)?this.onWebSocketUpgrade(x):this.onRequest(x)}async onInit(){await onInit(this,e)}async onWebSocketConnect(x,S){await onWebSocketConnect(this,e,x,S)}async onWebSocketMessage(x,S){await onWebSocketMessage(this,e,x,S)}async onWebSocketDisconnect(x){await onWebSocketDisconnect(this,e,x)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(e,x,S){return broadcast(this.sessions,e,x,S)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(e){return getUserSessions(this.sessions,e)}sendToUser(e,x,S){return sendToUser(this.sessions,e,x,S)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(C,`name`,{value:S,writable:!1,configurable:!0}),C}exports.PROTOCOL_VERSION=require_types.t,exports.createActorHandler=createActorHandler,exports.decodeClientMessage=require_types.a,exports.decodeFrame=require_types.o,exports.decodeServerMessage=require_types.s,exports.defineRoom=defineRoom,exports.encodeClientMessage=require_types.n,exports.encodeFrame=require_types.r,exports.encodeServerMessage=require_types.i,exports.restoreSessions=restoreSessions,exports.storeAttachment=storeAttachment;
package/dist/verani.d.cts CHANGED
@@ -249,13 +249,13 @@ interface RoomDefinitionWithHandlers<TMeta extends ConnectionMeta = ConnectionMe
249
249
  * @param event - Event name
250
250
  * @param handler - Handler function
251
251
  */
252
- on(event: string, handler: (ctx: any, data: any) => void | Promise<void>): void;
252
+ on(event: string, handler: EventHandler<TMeta, E>): void;
253
253
  /**
254
254
  * Remove an event handler (socket.io-like API)
255
255
  * @param event - Event name
256
256
  * @param handler - Optional specific handler to remove
257
257
  */
258
- off(event: string, handler?: (ctx: any, data: any) => void | Promise<void>): void;
258
+ off(event: string, handler?: EventHandler<TMeta, E>): void;
259
259
  }
260
260
  /**
261
261
  * Defines a room with lifecycle hooks and metadata extraction
package/dist/verani.d.mts CHANGED
@@ -249,13 +249,13 @@ interface RoomDefinitionWithHandlers<TMeta extends ConnectionMeta = ConnectionMe
249
249
  * @param event - Event name
250
250
  * @param handler - Handler function
251
251
  */
252
- on(event: string, handler: (ctx: any, data: any) => void | Promise<void>): void;
252
+ on(event: string, handler: EventHandler<TMeta, E>): void;
253
253
  /**
254
254
  * Remove an event handler (socket.io-like API)
255
255
  * @param event - Event name
256
256
  * @param handler - Optional specific handler to remove
257
257
  */
258
- off(event: string, handler?: (ctx: any, data: any) => void | Promise<void>): void;
258
+ off(event: string, handler?: EventHandler<TMeta, E>): void;
259
259
  }
260
260
  /**
261
261
  * Defines a room with lifecycle hooks and metadata extraction
package/dist/verani.mjs CHANGED
@@ -1 +1 @@
1
- import{a as decodeClientMessage,i as encodeServerMessage,n as encodeClientMessage,o as decodeFrame,r as encodeFrame,s as decodeServerMessage,t as PROTOCOL_VERSION}from"./types-CJLnZrA8.mjs";import{Actor}from"@cloudflare/actors";var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(u,O){this.handlers.has(u)||this.handlers.set(u,new Set),this.handlers.get(u).add(O)}off(u,O){let k=this.handlers.get(u);k&&(O?(k.delete(O),k.size===0&&this.handlers.delete(u)):this.handlers.delete(u))}async emit(u,O,k){let A=this.handlers.get(u);if(A&&A.size>0){let u=[];for(let j of A)try{let A=j(O,k);A instanceof Promise&&u.push(A)}catch{}await Promise.all(u)}let j=this.handlers.get(`*`);if(j&&j.size>0){let u=[];for(let A of j)try{let j=A(O,k);j instanceof Promise&&u.push(j)}catch{}await Promise.all(u)}}hasHandlers(u){return this.handlers.has(u)&&this.handlers.get(u).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(u){let O=crypto.randomUUID(),k=crypto.randomUUID(),A=new URL(u.url).searchParams.get(`channels`);return{userId:O,clientId:k,channels:A?A.split(`,`).map(u=>u.trim()).filter(Boolean):[`default`]}}function defineRoom(u){let O=u.eventEmitter||createRoomEventEmitter();return{name:u.name,websocketPath:u.websocketPath,extractMeta:u.extractMeta||defaultExtractMeta,onConnect:u.onConnect,onDisconnect:u.onDisconnect,onMessage:u.onMessage,onError:u.onError,onHibernationRestore:u.onHibernationRestore,eventEmitter:O,on(u,k){O.on(u,k)},off(u,k){O.off(u,k)}}}function cleanupStaleSessions(u){let O=0,k=[];for(let[O,A]of u.entries())O.readyState!==WebSocket.OPEN&&k.push(O);for(let A of k)u.delete(A),O++;return O}function decodeFrame$1(u){return decodeFrame(u)??{type:`invalid`}}function encodeFrame$1(u){return encodeFrame(u)}function broadcast(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:O,data:k}),N=[];for(let{ws:k,meta:P}of u.values())if(P.channels.includes(O)&&!(A?.except&&k===A.except)&&!(A?.userIds&&!A.userIds.includes(P.userId))&&!(A?.clientIds&&!A.clientIds.includes(P.clientId))){if(k.readyState!==WebSocket.OPEN){N.push(k);continue}try{k.send(M),j++}catch{N.push(k)}}for(let O of N)u.delete(O);return N.length,j}function sendToUser(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:k,data:A}),N=[];for(let{ws:A,meta:P}of u.values())if(P.userId===O&&P.channels.includes(k)){if(A.readyState!==WebSocket.OPEN){N.push(A);continue}try{A.send(M),j++}catch{N.push(A)}}for(let O of N)u.delete(O);return N.length,j}function getSessionCount(u){return u.size}function getConnectedUserIds(u){let O=new Set;for(let{meta:k}of u.values())O.add(k.userId);return Array.from(O)}function getUserSessions(u,O){let k=[];for(let{ws:A,meta:j}of u.values())j.userId===O&&k.push(A);return k}function getStorage(u){return u.storage}function sanitizeToClassName(u){return u.replace(/^\/+/,``).split(/[-_\/\s]+/).map(u=>u.replace(/[^a-zA-Z0-9]/g,``)).filter(u=>u.length>0).map(u=>u.charAt(0).toUpperCase()+u.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(u){return function(O){return{locationHint:`me`,sockets:{upgradePath:u.websocketPath}}}}function isValidConnectionMeta(u){return!(!u||typeof u!=`object`||typeof u.userId!=`string`||!u.userId||typeof u.clientId!=`string`||!u.clientId||!Array.isArray(u.channels)||!u.channels.every(u=>typeof u==`string`))}function storeAttachment(u,O){u.serializeAttachment(O)}function restoreSessions(u){let O=0,k=0;for(let A of u.ctx.getWebSockets()){if(A.readyState!==WebSocket.OPEN){k++;continue}let j=A.deserializeAttachment();if(!j){k++;continue}if(!isValidConnectionMeta(j)){k++;continue}u.sessions.set(A,{ws:A,meta:j}),O++}}async function onInit(u,O){try{restoreSessions(u)}catch{}if(O.onHibernationRestore&&u.sessions.size>0)try{await O.onHibernationRestore(u)}catch{}else O.onHibernationRestore&&u.sessions.size}function createUserEmitBuilder(u,O,k){return{emit(A,j){return sendToUser(O,u,k,{type:A,...j})}}}function createChannelEmitBuilder(u,O,k){return{emit(A,j){return broadcast(O,u,{type:A,...j},k)}}}function createSocketEmit(u){let O=u.meta.channels[0]||`default`;return{emit(k,A){if(u.ws.readyState===WebSocket.OPEN)try{let j={type:`event`,channel:O,data:{type:k,...A}};u.ws.send(encodeFrame$1(j))}catch{}},to(k){return u.meta.channels.includes(k)?createChannelEmitBuilder(k,u.actor.sessions,{except:u.ws}):createUserEmitBuilder(k,u.actor.sessions,O)}}}function createActorEmit(u){return{emit(O,k){let A={type:O,...k};return broadcast(u.sessions,`default`,A)},to(O){return createChannelEmitBuilder(O,u.sessions)}}}async function onWebSocketConnect(u,O,k,A){let j;try{j=O.extractMeta?await O.extractMeta(A):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(k,j);let M={actor:u,ws:k,meta:j,frame:{type:`connect`}};if(O.onConnect){let A={actor:u,ws:k,meta:j,emit:createSocketEmit(M)};await O.onConnect(A)}u.sessions.set(k,{ws:k,meta:j})}catch(A){if(O.onError&&j)try{let M={actor:u,ws:k,meta:j,frame:{type:`error`}};await O.onError(A,{actor:u,ws:k,meta:j,emit:createSocketEmit(M)})}catch{}k.close(1011,`Internal server error`)}}async function onWebSocketMessage(u,O,k,A){let j;try{let M=decodeFrame$1(A);if(M&&M.type===`ping`){if(k.readyState===WebSocket.OPEN)try{k.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!M||M.type===`invalid`||(j=u.sessions.get(k),!j))return;let N={actor:u,ws:k,meta:j.meta,frame:M,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:M})},P=O.eventEmitter;P&&P.hasHandlers&&P.hasHandlers(M.type)?await P.emit(M.type,N,M.data||{}):O.onMessage&&await O.onMessage(N,M)}catch(A){if(O.onError&&j)try{await O.onError(A,{actor:u,ws:k,meta:j.meta,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(u,O,k){try{let A=u.sessions.get(k);if(u.sessions.delete(k),A&&O.onDisconnect){let j={actor:u,ws:k,meta:A.meta,frame:{type:`disconnect`}},M={actor:u,ws:k,meta:A.meta,emit:createSocketEmit(j)};await O.onDisconnect(M)}}catch{}}function createActorHandler(u){let O=sanitizeToClassName(u.name||u.websocketPath||`VeraniActor`);class k extends Actor{constructor(...u){super(...u),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(u)}async shouldUpgradeWebSocket(u){return!0}async fetch(O){let k=new URL(O.url),A=O.headers.get(`Upgrade`);return k.pathname===u.websocketPath&&A===`websocket`&&await this.shouldUpgradeWebSocket(O)?this.onWebSocketUpgrade(O):this.onRequest(O)}async onInit(){await onInit(this,u)}async onWebSocketConnect(O,k){await onWebSocketConnect(this,u,O,k)}async onWebSocketMessage(O,k){await onWebSocketMessage(this,u,O,k)}async onWebSocketDisconnect(O){await onWebSocketDisconnect(this,u,O)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(u,O,k){return broadcast(this.sessions,u,O,k)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(u){return getUserSessions(this.sessions,u)}sendToUser(u,O,k){return sendToUser(this.sessions,u,O,k)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(k,`name`,{value:O,writable:!1,configurable:!0}),k}export{PROTOCOL_VERSION,createActorHandler,decodeClientMessage,decodeFrame,decodeServerMessage,defineRoom,encodeClientMessage,encodeFrame,encodeServerMessage,restoreSessions,storeAttachment};
1
+ import{a as decodeClientMessage,i as encodeServerMessage,n as encodeClientMessage,o as decodeFrame,r as encodeFrame,s as decodeServerMessage,t as PROTOCOL_VERSION}from"./types-CJLnZrA8.mjs";import{Actor}from"@cloudflare/actors";var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(u,O){this.handlers.has(u)||this.handlers.set(u,new Set),this.handlers.get(u).add(O)}off(u,O){let k=this.handlers.get(u);k&&(O?(k.delete(O),k.size===0&&this.handlers.delete(u)):this.handlers.delete(u))}async emit(u,O,k){let A=this.handlers.get(u);if(A&&A.size>0){let u=[];for(let j of A)try{let A=j(O,k);A instanceof Promise&&u.push(A)}catch{}await Promise.all(u)}let j=this.handlers.get(`*`);if(j&&j.size>0){let u=[];for(let A of j)try{let j=A(O,k);j instanceof Promise&&u.push(j)}catch{}await Promise.all(u)}}hasHandlers(u){return this.handlers.has(u)&&this.handlers.get(u).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(u){let O=crypto.randomUUID(),k=crypto.randomUUID(),A=new URL(u.url).searchParams.get(`channels`);return{userId:O,clientId:k,channels:A?A.split(`,`).map(u=>u.trim()).filter(Boolean):[`default`]}}function defineRoom(u){let O=u.eventEmitter||createRoomEventEmitter();return{name:u.name,websocketPath:u.websocketPath,extractMeta:u.extractMeta||(u=>defaultExtractMeta(u)),onConnect:u.onConnect,onDisconnect:u.onDisconnect,onMessage:u.onMessage,onError:u.onError,onHibernationRestore:u.onHibernationRestore,eventEmitter:O,on(u,k){O.on(u,k)},off(u,k){O.off(u,k)}}}function cleanupStaleSessions(u){let O=0,k=[];for(let[O,A]of u.entries())O.readyState!==WebSocket.OPEN&&k.push(O);for(let A of k)u.delete(A),O++;return O}function decodeFrame$1(u){return decodeFrame(u)??{type:`invalid`}}function encodeFrame$1(u){return encodeFrame(u)}function broadcast(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:O,data:k}),N=[];for(let{ws:k,meta:P}of u.values())if(P.channels.includes(O)&&!(A?.except&&k===A.except)&&!(A?.userIds&&!A.userIds.includes(P.userId))&&!(A?.clientIds&&!A.clientIds.includes(P.clientId))){if(k.readyState!==WebSocket.OPEN){N.push(k);continue}try{k.send(M),j++}catch{N.push(k)}}for(let O of N)u.delete(O);return N.length,j}function sendToUser(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:k,data:A}),N=[];for(let{ws:A,meta:P}of u.values())if(P.userId===O&&P.channels.includes(k)){if(A.readyState!==WebSocket.OPEN){N.push(A);continue}try{A.send(M),j++}catch{N.push(A)}}for(let O of N)u.delete(O);return N.length,j}function getSessionCount(u){return u.size}function getConnectedUserIds(u){let O=new Set;for(let{meta:k}of u.values())O.add(k.userId);return Array.from(O)}function getUserSessions(u,O){let k=[];for(let{ws:A,meta:j}of u.values())j.userId===O&&k.push(A);return k}function getStorage(u){return u.storage}function sanitizeToClassName(u){return u.replace(/^\/+/,``).split(/[-_\/\s]+/).map(u=>u.replace(/[^a-zA-Z0-9]/g,``)).filter(u=>u.length>0).map(u=>u.charAt(0).toUpperCase()+u.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(u){return function(O){return{locationHint:`me`,sockets:{upgradePath:u.websocketPath}}}}function isValidConnectionMeta(u){return!(!u||typeof u!=`object`||typeof u.userId!=`string`||!u.userId||typeof u.clientId!=`string`||!u.clientId||!Array.isArray(u.channels)||!u.channels.every(u=>typeof u==`string`))}function storeAttachment(u,O){u.serializeAttachment(O)}function restoreSessions(u){let O=0,k=0;for(let A of u.ctx.getWebSockets()){if(A.readyState!==WebSocket.OPEN){k++;continue}let j=A.deserializeAttachment();if(!j){k++;continue}if(!isValidConnectionMeta(j)){k++;continue}u.sessions.set(A,{ws:A,meta:j}),O++}}async function onInit(u,O){try{restoreSessions(u)}catch{}if(O.onHibernationRestore&&u.sessions.size>0)try{await O.onHibernationRestore(u)}catch{}else O.onHibernationRestore&&u.sessions.size}function createUserEmitBuilder(u,O,k){return{emit(A,j){return sendToUser(O,u,k,{type:A,...j})}}}function createChannelEmitBuilder(u,O,k){return{emit(A,j){return broadcast(O,u,{type:A,...j},k)}}}function createSocketEmit(u){let O=u.meta.channels[0]||`default`;return{emit(k,A){if(u.ws.readyState===WebSocket.OPEN)try{let j={type:`event`,channel:O,data:{type:k,...A}};u.ws.send(encodeFrame$1(j))}catch{}},to(k){return u.meta.channels.includes(k)?createChannelEmitBuilder(k,u.actor.sessions,{except:u.ws}):createUserEmitBuilder(k,u.actor.sessions,O)}}}function createActorEmit(u){return{emit(O,k){let A={type:O,...k};return broadcast(u.sessions,`default`,A)},to(O){return createChannelEmitBuilder(O,u.sessions)}}}async function onWebSocketConnect(u,O,k,A){let j;try{j=O.extractMeta?await O.extractMeta(A):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(k,j);let M={actor:u,ws:k,meta:j,frame:{type:`connect`}};if(O.onConnect){let A={actor:u,ws:k,meta:j,emit:createSocketEmit(M)};await O.onConnect(A)}u.sessions.set(k,{ws:k,meta:j})}catch(A){if(O.onError&&j)try{let M={actor:u,ws:k,meta:j,frame:{type:`error`}};await O.onError(A,{actor:u,ws:k,meta:j,emit:createSocketEmit(M)})}catch{}k.close(1011,`Internal server error`)}}async function onWebSocketMessage(u,O,k,A){let j;try{let M=decodeFrame$1(A);if(M&&M.type===`ping`){if(k.readyState===WebSocket.OPEN)try{k.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!M||M.type===`invalid`||(j=u.sessions.get(k),!j))return;let N={actor:u,ws:k,meta:j.meta,frame:M,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:M})},P=O.eventEmitter;P&&P.hasHandlers&&P.hasHandlers(M.type)?await P.emit(M.type,N,M.data||{}):O.onMessage&&await O.onMessage(N,M)}catch(A){if(O.onError&&j)try{await O.onError(A,{actor:u,ws:k,meta:j.meta,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(u,O,k){try{let A=u.sessions.get(k);if(u.sessions.delete(k),A&&O.onDisconnect){let j={actor:u,ws:k,meta:A.meta,frame:{type:`disconnect`}},M={actor:u,ws:k,meta:A.meta,emit:createSocketEmit(j)};await O.onDisconnect(M)}}catch{}}function createActorHandler(u){let O=sanitizeToClassName(u.name||u.websocketPath||`VeraniActor`);class k extends Actor{constructor(...u){super(...u),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(u)}async shouldUpgradeWebSocket(u){return!0}async fetch(O){let k=new URL(O.url),A=O.headers.get(`Upgrade`);return k.pathname===u.websocketPath&&A===`websocket`&&await this.shouldUpgradeWebSocket(O)?this.onWebSocketUpgrade(O):this.onRequest(O)}async onInit(){await onInit(this,u)}async onWebSocketConnect(O,k){await onWebSocketConnect(this,u,O,k)}async onWebSocketMessage(O,k){await onWebSocketMessage(this,u,O,k)}async onWebSocketDisconnect(O){await onWebSocketDisconnect(this,u,O)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(u,O,k){return broadcast(this.sessions,u,O,k)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(u){return getUserSessions(this.sessions,u)}sendToUser(u,O,k){return sendToUser(this.sessions,u,O,k)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(k,`name`,{value:O,writable:!1,configurable:!0}),k}export{PROTOCOL_VERSION,createActorHandler,decodeClientMessage,decodeFrame,decodeServerMessage,defineRoom,encodeClientMessage,encodeFrame,encodeServerMessage,restoreSessions,storeAttachment};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "verani",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "A simple, focused realtime SDK for Cloudflare Actors with Socket.io-like semantics",
5
5
  "license": "ISC",
6
6
  "keywords": [