verani 0.9.0 → 0.11.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.
Files changed (38) hide show
  1. package/README.md +1 -1
  2. package/dist/actor-runtime-BoaZjQPs.cjs +1 -0
  3. package/dist/{actor-runtime-BqF6_7z_.d.mts → actor-runtime-DCvCJ1UN.d.mts} +25 -20
  4. package/dist/actor-runtime-DecQvWnw.mjs +1 -0
  5. package/dist/{actor-runtime-gFDsFVsU.d.cts → actor-runtime-Dqodm1HR.d.cts} +25 -20
  6. package/dist/client-Cf_oqaqp.cjs +1 -0
  7. package/dist/{client-C3BlxAY_.d.cts → client-D7P17bMd.d.mts} +4 -4
  8. package/dist/{client-CV5RrpZX.d.mts → client-JCkzlxJL.d.cts} +4 -4
  9. package/dist/client-oy-w-Ky5.mjs +1 -0
  10. package/dist/client.cjs +1 -1
  11. package/dist/client.d.cts +3 -3
  12. package/dist/client.d.mts +3 -3
  13. package/dist/client.mjs +1 -1
  14. package/dist/{decode--RaAAv0U.d.cts → decode-DwdLTFvb.d.mts} +4 -4
  15. package/dist/{decode-BUzd77kA.d.mts → decode-otE_3S_-.d.cts} +4 -4
  16. package/dist/encode-CFndA-BQ.mjs +1 -0
  17. package/dist/encode-SjZrKIyU.cjs +1 -0
  18. package/dist/typed-client.cjs +1 -1
  19. package/dist/typed-client.d.cts +1 -1
  20. package/dist/typed-client.d.mts +1 -1
  21. package/dist/typed-client.mjs +1 -1
  22. package/dist/typed.cjs +1 -1
  23. package/dist/typed.d.cts +2 -2
  24. package/dist/typed.d.mts +2 -2
  25. package/dist/typed.mjs +1 -1
  26. package/dist/{types-DOI6EHQJ.d.cts → types-6m1L8QLb.d.mts} +16 -13
  27. package/dist/{types-_41fL9Dn.d.mts → types-DIIeb2YQ.d.cts} +16 -13
  28. package/dist/verani.cjs +1 -1
  29. package/dist/verani.d.cts +33 -12
  30. package/dist/verani.d.mts +33 -12
  31. package/dist/verani.mjs +1 -1
  32. package/package.json +1 -1
  33. package/dist/actor-runtime-83AF97II.mjs +0 -1
  34. package/dist/actor-runtime-CCoZUVrQ.cjs +0 -1
  35. package/dist/client-C3K_PiKE.cjs +0 -1
  36. package/dist/client-DQnA1Oel.mjs +0 -1
  37. package/dist/encode-BYFW_6TI.cjs +0 -1
  38. package/dist/encode-BhJqnsto.mjs +0 -1
package/README.md CHANGED
@@ -126,7 +126,7 @@ Update `wrangler.jsonc`:
126
126
  {
127
127
  "name": "my-verani-app",
128
128
  "main": "src/index.ts",
129
- "compatibility_date": "2024-01-01",
129
+ "compatibility_date": "2025-11-26",
130
130
 
131
131
  "durable_objects": {
132
132
  "bindings": [
@@ -0,0 +1 @@
1
+ const require_encode=require(`./encode-SjZrKIyU.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);function isValidConnectionMeta(s){if(typeof s!=`object`||!s)return!1;let N=s;return!(typeof N.userId!=`string`||!N.userId||typeof N.clientId!=`string`||!N.clientId||!Array.isArray(N.channels)||!N.channels.every(s=>typeof s==`string`))}function storeAttachment(s,N){s.serializeAttachment(N)}function restoreSessions(s){let N=0,F=0;for(let I of s.ctx.getWebSockets()){if(I.readyState!==WebSocket.OPEN){F++;continue}let L=I.deserializeAttachment();if(!L){F++;continue}if(!isValidConnectionMeta(L)){F++;continue}let R=L;s.sessions.set(I,{ws:I,meta:R}),N++}}function decodeFrame(N){return require_encode.a(N)??{type:`invalid`}}function encodeFrame(N){return require_encode.n(N)}const PERSIST_ERROR_HANDLER=Symbol(`PERSIST_ERROR_HANDLER`),PERSISTED_STATE=Symbol(`PERSISTED_STATE`),STATE_READY=Symbol(`STATE_READY`);var PersistNotReadyError=class extends Error{constructor(s){super(`Cannot access persisted state key "${s}" before storage is initialized. Wait for onInit to complete or check actor.isStateReady().`),this.name=`PersistNotReadyError`}},PersistError=class extends Error{constructor(s,N){super(`Failed to persist key "${s}": ${N.message}`),this.name=`PersistError`,this.originalCause=N}};function safeSerialize(s){let N=new WeakSet;return JSON.stringify(s,(s,P)=>{if(P instanceof Date)return{__type:`Date`,value:P.toISOString()};if(P instanceof RegExp)return{__type:`RegExp`,source:P.source,flags:P.flags};if(P instanceof Map)return{__type:`Map`,entries:Array.from(P.entries())};if(P instanceof Set)return{__type:`Set`,values:Array.from(P.values())};if(P instanceof Error)return{__type:`Error`,name:P.name,message:P.message};if(typeof P==`object`&&P){if(N.has(P))return;N.add(P)}if(!(typeof P==`function`||typeof P==`symbol`))return P})}function safeDeserialize(s){return JSON.parse(s,(s,N)=>{if(N&&typeof N==`object`&&N.__type)switch(N.__type){case`Date`:return new Date(N.value);case`RegExp`:return new RegExp(N.source,N.flags);case`Map`:return new Map(N.entries);case`Set`:return new Set(N.values);case`Error`:{let s=Error(N.message);return s.name=N.name,s}}return N})}function createShallowProxy(s,N,P){return new Proxy(s,{set(s,P,F){let I=Reflect.set(s,P,F);return I&&typeof P==`string`&&N(P,F),I},deleteProperty(s,N){let F=Reflect.deleteProperty(s,N);return F&&typeof N==`string`&&P(N),F}})}async function initializePersistedState(s,N,P=[],F={}){let{shallow:I=!0,throwOnError:L=!0}=F,R=s.ctx.storage,H=P.length>0?P.map(String):Object.keys(N),U={...N};for(let s of H)try{let N=await R.get(`_verani_persist:${s}`);if(N!==void 0)try{U[s]=safeDeserialize(N)}catch(N){if(L)throw new PersistError(s,N)}}catch(N){if(L&&!(N instanceof PersistError))throw new PersistError(s,N)}let W=async(N,P)=>{if(H.includes(N))try{let s=safeSerialize(P);await R.put(`_verani_persist:${N}`,s)}catch(P){let F=s[PERSIST_ERROR_HANDLER];if(F&&F(N,P),L)throw new PersistError(N,P)}},G=async N=>{if(H.includes(N))try{await R.delete(`_verani_persist:${N}`)}catch(P){let F=s[PERSIST_ERROR_HANDLER];if(F&&F(N,P),L)throw new PersistError(N,P)}},K;return K=I?createShallowProxy(U,(s,N)=>{W(String(s),N)},s=>{G(String(s))}):createDeepProxy(U,(s,N)=>{W(s,N)},s=>{G(s)},H),s[STATE_READY]=!0,s[PERSISTED_STATE]=K,K}function createDeepProxy(s,N,P,F,I){return new Proxy(s,{get(s,L){let R=Reflect.get(s,L);if(R&&typeof R==`object`&&!Array.isArray(R)){let s=I??String(L);if(F.includes(s)||I!==void 0)return createDeepProxy(R,N,P,F,s)}return R},set(s,P,L){let R=Reflect.set(s,P,L);if(R){let s=I??String(P);F.includes(s)&&(I?N(I,void 0):N(String(P),L))}return R},deleteProperty(s,L){let R=Reflect.deleteProperty(s,L);if(R){let s=I??String(L);F.includes(s)&&(I?N(I,void 0):P(String(L)))}return R}})}function isStateReady(s){return s[STATE_READY]===!0}function getPersistedState(s){if(!isStateReady(s))throw new PersistNotReadyError(`state`);return s[PERSISTED_STATE]}function setPeristErrorHandler(s,N){s[PERSIST_ERROR_HANDLER]=N}async function persistKey(s,N,P){let F=s.ctx.storage,I=safeSerialize(P);await F.put(`_verani_persist:${N}`,I)}async function deletePersistedKey(s,N){await s.ctx.storage.delete(`_verani_persist:${N}`)}async function getPersistedKeys(s){let N=await s.ctx.storage.list({prefix:`_verani_persist:`});return Array.from(N.keys()).map(s=>s.replace(`_verani_persist:`,``))}async function clearPersistedState(s){let N=s.ctx.storage,P=await N.list({prefix:`_verani_persist:`}),F=Array.from(P.keys());await N.delete(F)}var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(s,N){this.handlers.has(s)||this.handlers.set(s,new Set),this.handlers.get(s).add(N)}off(s,N){let P=this.handlers.get(s);P&&(N?(P.delete(N),P.size===0&&this.handlers.delete(s)):this.handlers.delete(s))}async emit(s,N,P){let F=this.handlers.get(s);if(F&&F.size>0){let s=[];for(let I of F)try{let F=I(N,P);F instanceof Promise&&s.push(F)}catch{}await Promise.all(s)}let I=this.handlers.get(`*`);if(I&&I.size>0){let s=[];for(let F of I)try{let I=F(N,P);I instanceof Promise&&s.push(I)}catch{}await Promise.all(s)}}hasHandlers(s){return this.handlers.has(s)&&this.handlers.get(s).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}rebuildHandlers(s){this.handlers.clear();for(let[N,P]of s.entries())this.handlers.set(N,new Set(P))}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(s){let N=crypto.randomUUID(),P=crypto.randomUUID(),F=new URL(s.url).searchParams.get(`channels`);return{userId:N,clientId:P,channels:F?F.split(`,`).map(s=>s.trim()).filter(Boolean):[`default`]}}function defineRoom(s){let N=s.eventEmitter||createRoomEventEmitter(),P=s._staticHandlers||new Map;return{name:s.name,websocketPath:s.websocketPath,extractMeta:s.extractMeta||(s=>defaultExtractMeta(s)),onConnect:s.onConnect,onDisconnect:s.onDisconnect,onMessage:s.onMessage,onError:s.onError,onHibernationRestore:s.onHibernationRestore,eventEmitter:N,_staticHandlers:P,state:s.state,persistedKeys:s.persistedKeys,persistOptions:s.persistOptions,onPersistError:s.onPersistError,on(s,F){N.on(s,F),P.has(s)||P.set(s,new Set),P.get(s).add(F)},off(s,F){N.off(s,F);let I=P.get(s);I&&(F?(I.delete(F),I.size===0&&P.delete(s)):P.delete(s))}}}function cleanupStaleSessions(s){let N=0,P=[];for(let[N,F]of s.entries())N.readyState!==WebSocket.OPEN&&P.push(N);for(let F of P)s.delete(F),N++;return N}function broadcast(s,N,P,F){let I=0,L=encodeFrame({type:`event`,channel:N,data:P}),z=[];for(let{ws:P,meta:R}of s.values())if(R.channels.includes(N)&&!(F?.except&&P===F.except)&&!(F?.userIds&&!F.userIds.includes(R.userId))&&!(F?.clientIds&&!F.clientIds.includes(R.clientId))){if(P.readyState!==WebSocket.OPEN){z.push(P);continue}try{P.send(L),I++}catch{z.push(P)}}for(let N of z)s.delete(N);return z.length,I}function sendToUser(s,N,P,F){let I=0,L=encodeFrame({type:`event`,channel:P,data:F}),z=[];for(let{ws:F,meta:R}of s.values())if(R.userId===N&&R.channels.includes(P)){if(F.readyState!==WebSocket.OPEN){z.push(F);continue}try{F.send(L),I++}catch{z.push(F)}}for(let N of z)s.delete(N);return z.length,I}function getSessionCount(s){return s.size}function getConnectedUserIds(s){let N=new Set;for(let{meta:P}of s.values())N.add(P.userId);return Array.from(N)}function getUserSessions(s,N){let P=[];for(let{ws:F,meta:I}of s.values())I.userId===N&&P.push(F);return P}function getStorage(s){return s.storage}function sanitizeToClassName(s){return s.replace(/^\/+/,``).split(/[-_\/\s]+/).map(s=>s.replace(/[^a-zA-Z0-9]/g,``)).filter(s=>s.length>0).map(s=>s.charAt(0).toUpperCase()+s.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(s){return function(N){return{sockets:{upgradePath:s.websocketPath}}}}async function onInit(s,N){if(N.eventEmitter&&N._staticHandlers)try{N.eventEmitter.rebuildHandlers(N._staticHandlers)}catch{}try{restoreSessions(s)}catch{}if(N.onHibernationRestore&&s.sessions.size>0)try{await N.onHibernationRestore(s)}catch{}else N.onHibernationRestore&&s.sessions.size}function createUserEmitBuilder(s,N,P){return{emit(F,I){return sendToUser(N,s,P,{type:F,...I})}}}function createChannelEmitBuilder(s,N,P){return{emit(F,I){return broadcast(N,s,{type:F,...I},P)}}}function createSocketEmit(s){let N=s.meta.channels[0]||`default`;return{emit(P,F){if(s.ws.readyState===WebSocket.OPEN)try{let I={type:`event`,channel:N,data:{type:P,...F}};s.ws.send(encodeFrame(I))}catch{}},to(P){return s.meta.channels.includes(P)?createChannelEmitBuilder(P,s.actor.sessions,{except:s.ws}):createUserEmitBuilder(P,s.actor.sessions,N)}}}function createActorEmit(s){return{emit(N,P){let F={type:N,...P};return broadcast(s.sessions,`default`,F)},to(N){return createChannelEmitBuilder(N,s.sessions)}}}async function onWebSocketConnect(s,N,P,I){let L;try{if(L=N.extractMeta?await N.extractMeta(I):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(P,L),N.onConnect){let F={actor:s,ws:P,meta:L,frame:{type:`connect`}};F.emit=createSocketEmit(F);let I={actor:s,ws:P,meta:L,emit:F.emit};await N.onConnect(I)}s.sessions.set(P,{ws:P,meta:L})}catch(F){if(N.onError&&L)try{let I={actor:s,ws:P,meta:L,frame:{type:`error`}};I.emit=createSocketEmit(I),await N.onError(F,{actor:s,ws:P,meta:L,emit:I.emit})}catch{}P.close(1011,`Internal server error`)}}async function onWebSocketMessage(s,N,P,F){let I;try{let z=decodeFrame(F);if(z&&z.type===`ping`){if(P.readyState===WebSocket.OPEN)try{P.send(encodeFrame({type:`pong`}))}catch{}return}if(!z||z.type===`invalid`||(I=s.sessions.get(P),!I))return;let B={actor:s,ws:P,meta:I.meta,frame:z,emit:createSocketEmit({actor:s,ws:P,meta:I.meta,frame:z})},V=N.eventEmitter;V?.hasHandlers(z.type)?await V.emit(z.type,B,z.data||{}):N.onMessage&&await N.onMessage(B,z)}catch(F){if(N.onError&&I)try{await N.onError(F,{actor:s,ws:P,meta:I.meta,emit:createSocketEmit({actor:s,ws:P,meta:I.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(s,N,P){try{let F=s.sessions.get(P);if(s.sessions.delete(P),F&&N.onDisconnect){let I={actor:s,ws:P,meta:F.meta,frame:{type:`disconnect`}};I.emit=createSocketEmit(I);let L={actor:s,ws:P,meta:F.meta,emit:I.emit};await N.onDisconnect(L)}}catch{}}function createFetch(s,N){return async function(P){let F=new URL(P.url),I=P.headers.get(`Upgrade`);return F.pathname===s.websocketPath&&I===`websocket`&&await N.shouldUpgradeWebSocket(P)?N.onWebSocketUpgrade(P):N.onRequest(P)}}function createActorHandler(s){let P=sanitizeToClassName(s.name||s.websocketPath||`VeraniActor`),F=s;class I extends __cloudflare_actors.Actor{constructor(...N){super(...N),this.sessions=new Map,this.emit=createActorEmit(this),this[STATE_READY]=!1,this[PERSISTED_STATE]=s.state?{...s.state}:{},this.fetch=createFetch(F,this)}get roomState(){return this[PERSISTED_STATE]}isStateReady(){return isStateReady(this)}static{this.configuration=createConfiguration(F)}async shouldUpgradeWebSocket(s){return!0}async onInit(){if(s.state){s.onPersistError&&setPeristErrorHandler(this,s.onPersistError);let N=s.persistedKeys;this[PERSISTED_STATE]=await initializePersistedState(this,s.state,N,s.persistOptions)}await onInit(this,F)}async onWebSocketConnect(s,N){await onWebSocketConnect(this,F,s,N)}async onWebSocketMessage(s,N){await onWebSocketMessage(this,F,s,N)}async onWebSocketDisconnect(s){await onWebSocketDisconnect(this,F,s)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(s,N,P){return broadcast(this.sessions,s,N,P)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(s){return getUserSessions(this.sessions,s)}sendToUser(s,N,P){return sendToUser(this.sessions,s,N,P)}emitToChannel(s,N,P){let F={type:N,...P};return broadcast(this.sessions,s,F)}emitToUser(s,N,P){let F=encodeFrame({type:`event`,channel:`default`,data:{type:N,...P}}),I=0,L=[];for(let{ws:N,meta:P}of this.sessions.values())if(P.userId===s){if(N.readyState!==WebSocket.OPEN){L.push(N);continue}try{N.send(F),I++}catch{L.push(N)}}for(let s of L)this.sessions.delete(s);return I}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(I,`name`,{value:P,writable:!1,configurable:!0}),I}Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return encodeFrame}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return PersistNotReadyError}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return deletePersistedKey}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return initializePersistedState}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return isStateReady}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return setPeristErrorHandler}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return safeSerialize}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return PersistError}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return getPersistedKeys}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return safeDeserialize}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return defineRoom}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return STATE_READY}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return persistKey}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return PERSISTED_STATE}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return clearPersistedState}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return createActorHandler}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return getPersistedState}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return restoreSessions}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return storeAttachment}});
@@ -1,4 +1,4 @@
1
- import { n as ConnectionMeta, r as MessageFrame } from "./types-_41fL9Dn.mjs";
1
+ import { n as ConnectionMeta, r as MessageFrame } from "./types-6m1L8QLb.mjs";
2
2
  import { Actor, ActorConfiguration } from "@cloudflare/actors";
3
3
 
4
4
  //#region src/actor/persist.d.ts
@@ -174,13 +174,13 @@ interface ConnectionActorStub {
174
174
  * @param data - Event data
175
175
  * @returns Promise resolving to true if delivered, false if connection is closed
176
176
  */
177
- deliverMessage(event: string, data?: any): Promise<boolean>;
177
+ deliverMessage<TData = unknown>(event: string, data?: TData): Promise<boolean>;
178
178
  /**
179
179
  * Deliver a system event to this connection (presence updates, room events, etc.)
180
180
  * @param type - System event type
181
181
  * @param payload - Event payload
182
182
  */
183
- deliverSystemEvent(type: string, payload?: any): Promise<void>;
183
+ deliverSystemEvent<TPayload = unknown>(type: string, payload?: TPayload): Promise<void>;
184
184
  /**
185
185
  * Get the userId this connection belongs to
186
186
  */
@@ -241,7 +241,7 @@ interface ActorStub {
241
241
  * await stub.emitToChannel("default", "announcement", { text: "Hello!" });
242
242
  * ```
243
243
  */
244
- emitToChannel(channel: string, event: string, data?: any): Promise<number>;
244
+ emitToChannel<TData = unknown>(channel: string, event: string, data?: TData): Promise<number>;
245
245
  /**
246
246
  * Socket.IO-like emit API: Emit an event to a specific user (all their sessions) via RPC.
247
247
  * @param userId - User ID to emit to
@@ -253,7 +253,7 @@ interface ActorStub {
253
253
  * await stub.emitToUser("alice", "notification", { message: "Hello!" });
254
254
  * ```
255
255
  */
256
- emitToUser(userId: string, event: string, data?: any): Promise<number>;
256
+ emitToUser<TData = unknown>(userId: string, event: string, data?: TData): Promise<number>;
257
257
  /**
258
258
  * @deprecated Use `emitToUser()` instead for Socket.IO-like API.
259
259
  * Sends a message to a specific user (all their sessions) via RPC.
@@ -262,7 +262,7 @@ interface ActorStub {
262
262
  * @param data - Message data
263
263
  * @returns Promise resolving to the number of sessions that received the message
264
264
  */
265
- sendToUser(userId: string, channel: string, data?: any): Promise<number>;
265
+ sendToUser<TData = unknown>(userId: string, channel: string, data?: TData): Promise<number>;
266
266
  /**
267
267
  * @deprecated Use `emitToChannel()` instead for Socket.IO-like API.
268
268
  * Broadcasts a message to all connections in a channel via RPC.
@@ -273,7 +273,7 @@ interface ActorStub {
273
273
  * @param opts - Broadcast options (filtering by userIds or clientIds)
274
274
  * @returns Promise resolving to the number of connections that received the message
275
275
  */
276
- broadcast(channel: string, data: any, opts?: RpcBroadcastOptions): Promise<number>;
276
+ broadcast<TData = unknown>(channel: string, data: TData, opts?: RpcBroadcastOptions): Promise<number>;
277
277
  /**
278
278
  * Gets the total number of active sessions via RPC.
279
279
  * @returns Promise resolving to the number of connected WebSockets
@@ -321,7 +321,7 @@ interface VeraniActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
321
321
  * Returns the number of connections the message was sent to.
322
322
  * @see @src/actor/actor-runtime.ts broadcast()
323
323
  */
324
- broadcast(channel: string, data: any, opts?: BroadcastOptions): number;
324
+ broadcast<TData = unknown>(channel: string, data: TData, opts?: BroadcastOptions): number;
325
325
  /**
326
326
  * Returns the number of currently connected WebSocket sessions.
327
327
  * @see @src/actor/actor-runtime.ts getSessionCount()
@@ -344,7 +344,7 @@ interface VeraniActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
344
344
  * The message "type" is always "event" (see src/actor/actor-runtime.ts).
345
345
  * @see @src/actor/actor-runtime.ts sendToUser()
346
346
  */
347
- sendToUser(userId: string, channel: string, data?: any): number;
347
+ sendToUser<TData = unknown>(userId: string, channel: string, data?: TData): number;
348
348
  /**
349
349
  * Validates and removes stale WebSocket sessions.
350
350
  * Called automatically during broadcast/send operations, but can be called manually.
@@ -393,11 +393,11 @@ interface ConnectionActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unk
393
393
  * Deliver a message to this connection's WebSocket
394
394
  * Called via RPC from RoomDO
395
395
  */
396
- deliverMessage(event: string, data?: any): Promise<boolean>;
396
+ deliverMessage<TData = unknown>(event: string, data?: TData): Promise<boolean>;
397
397
  /**
398
398
  * Deliver a system event (presence, room events, etc.)
399
399
  */
400
- deliverSystemEvent(type: string, payload?: any): Promise<void>;
400
+ deliverSystemEvent<TPayload = unknown>(type: string, payload?: TPayload): Promise<void>;
401
401
  /**
402
402
  * Join a room (register with RoomDO)
403
403
  */
@@ -425,7 +425,7 @@ interface ConnectionEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unkn
425
425
  * @param event - Event name
426
426
  * @param data - Event data
427
427
  */
428
- emit(event: string, data?: any): void;
428
+ emit<TData = unknown>(event: string, data?: TData): void;
429
429
  /**
430
430
  * Target a specific room or user for emitting
431
431
  * @param target - Room name (if starts with "room:") or userId
@@ -455,12 +455,17 @@ interface AsyncEmitBuilder {
455
455
  * @param data - Event data
456
456
  * @returns Promise resolving to number of recipients
457
457
  */
458
- emit(event: string, data?: any): Promise<number>;
458
+ emit<TData = unknown>(event: string, data?: TData): Promise<number>;
459
459
  }
460
460
  /**
461
461
  * Event handler function type for socket.io-like event handling
462
+ *
463
+ * @template TMeta - Connection metadata type
464
+ * @template E - Environment type
465
+ * @template TState - Room state type
466
+ * @template TData - Event data type (defaults to unknown for type safety)
462
467
  */
463
- type EventHandler<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>> = (ctx: MessageContext<TMeta, E, TState>, data: any) => void | Promise<void>;
468
+ type EventHandler<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>, TData = unknown> = (ctx: MessageContext<TMeta, E, TState>, data: TData) => void | Promise<void>;
464
469
  /**
465
470
  * Event emitter interface for room-level event handling
466
471
  */
@@ -470,20 +475,20 @@ interface RoomEventEmitter<TMeta extends ConnectionMeta = ConnectionMeta, E = un
470
475
  * @param event - Event name (supports wildcard "*")
471
476
  * @param handler - Handler function
472
477
  */
473
- on(event: string, handler: EventHandler<TMeta, E, TState>): void;
478
+ on<TData = unknown>(event: string, handler: EventHandler<TMeta, E, TState, TData>): void;
474
479
  /**
475
480
  * Remove an event handler
476
481
  * @param event - Event name
477
482
  * @param handler - Optional specific handler to remove, or remove all handlers for event
478
483
  */
479
- off(event: string, handler?: EventHandler<TMeta, E, TState>): void;
484
+ off<TData = unknown>(event: string, handler?: EventHandler<TMeta, E, TState, TData>): void;
480
485
  /**
481
486
  * Emit an event to registered handlers
482
487
  * @param event - Event name
483
488
  * @param ctx - Message context
484
489
  * @param data - Event data
485
490
  */
486
- emit(event: string, ctx: MessageContext<TMeta, E, TState>, data: any): Promise<void>;
491
+ emit<TData = unknown>(event: string, ctx: MessageContext<TMeta, E, TState>, data: TData): Promise<void>;
487
492
  /**
488
493
  * Check if there are any handlers registered for a given event.
489
494
  * Returns true if handlers exist for the specific event or for the wildcard "*" event.
@@ -509,7 +514,7 @@ interface EmitBuilder<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
509
514
  * @param data - Event data
510
515
  * @returns Number of connections that received the message
511
516
  */
512
- emit(event: string, data?: any): number;
517
+ emit<TData = unknown>(event: string, data?: TData): number;
513
518
  }
514
519
  /**
515
520
  * Socket-level emit API (available on context)
@@ -521,7 +526,7 @@ interface SocketEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown>
521
526
  * @param event - Event name
522
527
  * @param data - Event data
523
528
  */
524
- emit(event: string, data?: any): void;
529
+ emit<TData = unknown>(event: string, data?: TData): void;
525
530
  /**
526
531
  * Target a specific user or channel for emitting
527
532
  * @param target - User ID or channel name
@@ -540,7 +545,7 @@ interface ActorEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown>
540
545
  * @param data - Event data
541
546
  * @returns Number of connections that received the message
542
547
  */
543
- emit(event: string, data?: any): number;
548
+ emit<TData = unknown>(event: string, data?: TData): number;
544
549
  /**
545
550
  * Target a specific channel for broadcasting
546
551
  * @param channel - Channel name
@@ -0,0 +1 @@
1
+ import{a as decodeFrame$1,n as encodeFrame$1}from"./encode-CFndA-BQ.mjs";import{Actor}from"@cloudflare/actors";function isValidConnectionMeta(d){if(typeof d!=`object`||!d)return!1;let F=d;return!(typeof F.userId!=`string`||!F.userId||typeof F.clientId!=`string`||!F.clientId||!Array.isArray(F.channels)||!F.channels.every(d=>typeof d==`string`))}function storeAttachment(d,F){d.serializeAttachment(F)}function restoreSessions(d){let F=0,I=0;for(let R of d.ctx.getWebSockets()){if(R.readyState!==WebSocket.OPEN){I++;continue}let z=R.deserializeAttachment();if(!z){I++;continue}if(!isValidConnectionMeta(z)){I++;continue}let B=z;d.sessions.set(R,{ws:R,meta:B}),F++}}function decodeFrame(F){return decodeFrame$1(F)??{type:`invalid`}}function encodeFrame(d){return encodeFrame$1(d)}const PERSIST_ERROR_HANDLER=Symbol(`PERSIST_ERROR_HANDLER`),PERSISTED_STATE=Symbol(`PERSISTED_STATE`),STATE_READY=Symbol(`STATE_READY`);var PersistNotReadyError=class extends Error{constructor(d){super(`Cannot access persisted state key "${d}" before storage is initialized. Wait for onInit to complete or check actor.isStateReady().`),this.name=`PersistNotReadyError`}},PersistError=class extends Error{constructor(d,F){super(`Failed to persist key "${d}": ${F.message}`),this.name=`PersistError`,this.originalCause=F}};function safeSerialize(d){let F=new WeakSet;return JSON.stringify(d,(d,I)=>{if(I instanceof Date)return{__type:`Date`,value:I.toISOString()};if(I instanceof RegExp)return{__type:`RegExp`,source:I.source,flags:I.flags};if(I instanceof Map)return{__type:`Map`,entries:Array.from(I.entries())};if(I instanceof Set)return{__type:`Set`,values:Array.from(I.values())};if(I instanceof Error)return{__type:`Error`,name:I.name,message:I.message};if(typeof I==`object`&&I){if(F.has(I))return;F.add(I)}if(!(typeof I==`function`||typeof I==`symbol`))return I})}function safeDeserialize(d){return JSON.parse(d,(d,F)=>{if(F&&typeof F==`object`&&F.__type)switch(F.__type){case`Date`:return new Date(F.value);case`RegExp`:return new RegExp(F.source,F.flags);case`Map`:return new Map(F.entries);case`Set`:return new Set(F.values);case`Error`:{let d=Error(F.message);return d.name=F.name,d}}return F})}function createShallowProxy(d,F,I){return new Proxy(d,{set(d,I,L){let R=Reflect.set(d,I,L);return R&&typeof I==`string`&&F(I,L),R},deleteProperty(d,F){let L=Reflect.deleteProperty(d,F);return L&&typeof F==`string`&&I(F),L}})}async function initializePersistedState(d,F,I=[],L={}){let{shallow:R=!0,throwOnError:z=!0}=L,B=d.ctx.storage,V=I.length>0?I.map(String):Object.keys(F),W={...F};for(let d of V)try{let F=await B.get(`_verani_persist:${d}`);if(F!==void 0)try{W[d]=safeDeserialize(F)}catch(F){if(z)throw new PersistError(d,F)}}catch(F){if(z&&!(F instanceof PersistError))throw new PersistError(d,F)}let G=async(F,I)=>{if(V.includes(F))try{let d=safeSerialize(I);await B.put(`_verani_persist:${F}`,d)}catch(I){let L=d[PERSIST_ERROR_HANDLER];if(L&&L(F,I),z)throw new PersistError(F,I)}},K=async F=>{if(V.includes(F))try{await B.delete(`_verani_persist:${F}`)}catch(I){let L=d[PERSIST_ERROR_HANDLER];if(L&&L(F,I),z)throw new PersistError(F,I)}},q;return q=R?createShallowProxy(W,(d,F)=>{G(String(d),F)},d=>{K(String(d))}):createDeepProxy(W,(d,F)=>{G(d,F)},d=>{K(d)},V),d[STATE_READY]=!0,d[PERSISTED_STATE]=q,q}function createDeepProxy(d,F,I,L,R){return new Proxy(d,{get(d,z){let B=Reflect.get(d,z);if(B&&typeof B==`object`&&!Array.isArray(B)){let d=R??String(z);if(L.includes(d)||R!==void 0)return createDeepProxy(B,F,I,L,d)}return B},set(d,I,z){let B=Reflect.set(d,I,z);if(B){let d=R??String(I);L.includes(d)&&(R?F(R,void 0):F(String(I),z))}return B},deleteProperty(d,z){let B=Reflect.deleteProperty(d,z);if(B){let d=R??String(z);L.includes(d)&&(R?F(R,void 0):I(String(z)))}return B}})}function isStateReady(d){return d[STATE_READY]===!0}function getPersistedState(d){if(!isStateReady(d))throw new PersistNotReadyError(`state`);return d[PERSISTED_STATE]}function setPeristErrorHandler(d,F){d[PERSIST_ERROR_HANDLER]=F}async function persistKey(d,F,I){let L=d.ctx.storage,R=safeSerialize(I);await L.put(`_verani_persist:${F}`,R)}async function deletePersistedKey(d,F){await d.ctx.storage.delete(`_verani_persist:${F}`)}async function getPersistedKeys(d){let F=await d.ctx.storage.list({prefix:`_verani_persist:`});return Array.from(F.keys()).map(d=>d.replace(`_verani_persist:`,``))}async function clearPersistedState(d){let F=d.ctx.storage,I=await F.list({prefix:`_verani_persist:`}),L=Array.from(I.keys());await F.delete(L)}var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(d,F){this.handlers.has(d)||this.handlers.set(d,new Set),this.handlers.get(d).add(F)}off(d,F){let I=this.handlers.get(d);I&&(F?(I.delete(F),I.size===0&&this.handlers.delete(d)):this.handlers.delete(d))}async emit(d,F,I){let L=this.handlers.get(d);if(L&&L.size>0){let d=[];for(let R of L)try{let L=R(F,I);L instanceof Promise&&d.push(L)}catch{}await Promise.all(d)}let R=this.handlers.get(`*`);if(R&&R.size>0){let d=[];for(let L of R)try{let R=L(F,I);R instanceof Promise&&d.push(R)}catch{}await Promise.all(d)}}hasHandlers(d){return this.handlers.has(d)&&this.handlers.get(d).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}rebuildHandlers(d){this.handlers.clear();for(let[F,I]of d.entries())this.handlers.set(F,new Set(I))}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(d){let F=crypto.randomUUID(),I=crypto.randomUUID(),L=new URL(d.url).searchParams.get(`channels`);return{userId:F,clientId:I,channels:L?L.split(`,`).map(d=>d.trim()).filter(Boolean):[`default`]}}function defineRoom(d){let F=d.eventEmitter||createRoomEventEmitter(),I=d._staticHandlers||new Map;return{name:d.name,websocketPath:d.websocketPath,extractMeta:d.extractMeta||(d=>defaultExtractMeta(d)),onConnect:d.onConnect,onDisconnect:d.onDisconnect,onMessage:d.onMessage,onError:d.onError,onHibernationRestore:d.onHibernationRestore,eventEmitter:F,_staticHandlers:I,state:d.state,persistedKeys:d.persistedKeys,persistOptions:d.persistOptions,onPersistError:d.onPersistError,on(d,L){F.on(d,L),I.has(d)||I.set(d,new Set),I.get(d).add(L)},off(d,L){F.off(d,L);let R=I.get(d);R&&(L?(R.delete(L),R.size===0&&I.delete(d)):I.delete(d))}}}function cleanupStaleSessions(d){let F=0,I=[];for(let[F,L]of d.entries())F.readyState!==WebSocket.OPEN&&I.push(F);for(let L of I)d.delete(L),F++;return F}function broadcast(d,F,I,L){let R=0,z=encodeFrame({type:`event`,channel:F,data:I}),B=[];for(let{ws:I,meta:V}of d.values())if(V.channels.includes(F)&&!(L?.except&&I===L.except)&&!(L?.userIds&&!L.userIds.includes(V.userId))&&!(L?.clientIds&&!L.clientIds.includes(V.clientId))){if(I.readyState!==WebSocket.OPEN){B.push(I);continue}try{I.send(z),R++}catch{B.push(I)}}for(let F of B)d.delete(F);return B.length,R}function sendToUser(d,F,I,L){let R=0,z=encodeFrame({type:`event`,channel:I,data:L}),B=[];for(let{ws:L,meta:V}of d.values())if(V.userId===F&&V.channels.includes(I)){if(L.readyState!==WebSocket.OPEN){B.push(L);continue}try{L.send(z),R++}catch{B.push(L)}}for(let F of B)d.delete(F);return B.length,R}function getSessionCount(d){return d.size}function getConnectedUserIds(d){let F=new Set;for(let{meta:I}of d.values())F.add(I.userId);return Array.from(F)}function getUserSessions(d,F){let I=[];for(let{ws:L,meta:R}of d.values())R.userId===F&&I.push(L);return I}function getStorage(d){return d.storage}function sanitizeToClassName(d){return d.replace(/^\/+/,``).split(/[-_\/\s]+/).map(d=>d.replace(/[^a-zA-Z0-9]/g,``)).filter(d=>d.length>0).map(d=>d.charAt(0).toUpperCase()+d.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(d){return function(F){return{sockets:{upgradePath:d.websocketPath}}}}async function onInit(d,F){if(F.eventEmitter&&F._staticHandlers)try{F.eventEmitter.rebuildHandlers(F._staticHandlers)}catch{}try{restoreSessions(d)}catch{}if(F.onHibernationRestore&&d.sessions.size>0)try{await F.onHibernationRestore(d)}catch{}else F.onHibernationRestore&&d.sessions.size}function createUserEmitBuilder(d,F,I){return{emit(L,R){return sendToUser(F,d,I,{type:L,...R})}}}function createChannelEmitBuilder(d,F,I){return{emit(L,R){return broadcast(F,d,{type:L,...R},I)}}}function createSocketEmit(d){let F=d.meta.channels[0]||`default`;return{emit(I,L){if(d.ws.readyState===WebSocket.OPEN)try{let R={type:`event`,channel:F,data:{type:I,...L}};d.ws.send(encodeFrame(R))}catch{}},to(I){return d.meta.channels.includes(I)?createChannelEmitBuilder(I,d.actor.sessions,{except:d.ws}):createUserEmitBuilder(I,d.actor.sessions,F)}}}function createActorEmit(d){return{emit(F,I){let L={type:F,...I};return broadcast(d.sessions,`default`,L)},to(F){return createChannelEmitBuilder(F,d.sessions)}}}async function onWebSocketConnect(d,F,I,L){let z;try{if(z=F.extractMeta?await F.extractMeta(L):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(I,z),F.onConnect){let L={actor:d,ws:I,meta:z,frame:{type:`connect`}};L.emit=createSocketEmit(L);let R={actor:d,ws:I,meta:z,emit:L.emit};await F.onConnect(R)}d.sessions.set(I,{ws:I,meta:z})}catch(L){if(F.onError&&z)try{let R={actor:d,ws:I,meta:z,frame:{type:`error`}};R.emit=createSocketEmit(R),await F.onError(L,{actor:d,ws:I,meta:z,emit:R.emit})}catch{}I.close(1011,`Internal server error`)}}async function onWebSocketMessage(d,F,I,L){let R;try{let z=decodeFrame(L);if(z&&z.type===`ping`){if(I.readyState===WebSocket.OPEN)try{I.send(encodeFrame({type:`pong`}))}catch{}return}if(!z||z.type===`invalid`||(R=d.sessions.get(I),!R))return;let H={actor:d,ws:I,meta:R.meta,frame:z,emit:createSocketEmit({actor:d,ws:I,meta:R.meta,frame:z})},U=F.eventEmitter;U?.hasHandlers(z.type)?await U.emit(z.type,H,z.data||{}):F.onMessage&&await F.onMessage(H,z)}catch(L){if(F.onError&&R)try{await F.onError(L,{actor:d,ws:I,meta:R.meta,emit:createSocketEmit({actor:d,ws:I,meta:R.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(d,F,I){try{let L=d.sessions.get(I);if(d.sessions.delete(I),L&&F.onDisconnect){let R={actor:d,ws:I,meta:L.meta,frame:{type:`disconnect`}};R.emit=createSocketEmit(R);let z={actor:d,ws:I,meta:L.meta,emit:R.emit};await F.onDisconnect(z)}}catch{}}function createFetch(d,F){return async function(I){let L=new URL(I.url),R=I.headers.get(`Upgrade`);return L.pathname===d.websocketPath&&R===`websocket`&&await F.shouldUpgradeWebSocket(I)?F.onWebSocketUpgrade(I):F.onRequest(I)}}function createActorHandler(d){let F=sanitizeToClassName(d.name||d.websocketPath||`VeraniActor`),L=d;class R extends Actor{constructor(...F){super(...F),this.sessions=new Map,this.emit=createActorEmit(this),this[STATE_READY]=!1,this[PERSISTED_STATE]=d.state?{...d.state}:{},this.fetch=createFetch(L,this)}get roomState(){return this[PERSISTED_STATE]}isStateReady(){return isStateReady(this)}static{this.configuration=createConfiguration(L)}async shouldUpgradeWebSocket(d){return!0}async onInit(){if(d.state){d.onPersistError&&setPeristErrorHandler(this,d.onPersistError);let F=d.persistedKeys;this[PERSISTED_STATE]=await initializePersistedState(this,d.state,F,d.persistOptions)}await onInit(this,L)}async onWebSocketConnect(d,F){await onWebSocketConnect(this,L,d,F)}async onWebSocketMessage(d,F){await onWebSocketMessage(this,L,d,F)}async onWebSocketDisconnect(d){await onWebSocketDisconnect(this,L,d)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(d,F,I){return broadcast(this.sessions,d,F,I)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(d){return getUserSessions(this.sessions,d)}sendToUser(d,F,I){return sendToUser(this.sessions,d,F,I)}emitToChannel(d,F,I){let L={type:F,...I};return broadcast(this.sessions,d,L)}emitToUser(d,F,I){let L=encodeFrame({type:`event`,channel:`default`,data:{type:F,...I}}),R=0,z=[];for(let{ws:F,meta:I}of this.sessions.values())if(I.userId===d){if(F.readyState!==WebSocket.OPEN){z.push(F);continue}try{F.send(L),R++}catch{z.push(F)}}for(let d of z)this.sessions.delete(d);return R}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(R,`name`,{value:F,writable:!1,configurable:!0}),R}export{encodeFrame as _,PersistNotReadyError as a,deletePersistedKey as c,initializePersistedState as d,isStateReady as f,setPeristErrorHandler as g,safeSerialize as h,PersistError as i,getPersistedKeys as l,safeDeserialize as m,defineRoom as n,STATE_READY as o,persistKey as p,PERSISTED_STATE as r,clearPersistedState as s,createActorHandler as t,getPersistedState as u,restoreSessions as v,storeAttachment as y};
@@ -1,4 +1,4 @@
1
- import { n as ConnectionMeta, r as MessageFrame } from "./types-DOI6EHQJ.cjs";
1
+ import { n as ConnectionMeta, r as MessageFrame } from "./types-DIIeb2YQ.cjs";
2
2
  import { Actor, ActorConfiguration } from "@cloudflare/actors";
3
3
 
4
4
  //#region src/actor/persist.d.ts
@@ -174,13 +174,13 @@ interface ConnectionActorStub {
174
174
  * @param data - Event data
175
175
  * @returns Promise resolving to true if delivered, false if connection is closed
176
176
  */
177
- deliverMessage(event: string, data?: any): Promise<boolean>;
177
+ deliverMessage<TData = unknown>(event: string, data?: TData): Promise<boolean>;
178
178
  /**
179
179
  * Deliver a system event to this connection (presence updates, room events, etc.)
180
180
  * @param type - System event type
181
181
  * @param payload - Event payload
182
182
  */
183
- deliverSystemEvent(type: string, payload?: any): Promise<void>;
183
+ deliverSystemEvent<TPayload = unknown>(type: string, payload?: TPayload): Promise<void>;
184
184
  /**
185
185
  * Get the userId this connection belongs to
186
186
  */
@@ -241,7 +241,7 @@ interface ActorStub {
241
241
  * await stub.emitToChannel("default", "announcement", { text: "Hello!" });
242
242
  * ```
243
243
  */
244
- emitToChannel(channel: string, event: string, data?: any): Promise<number>;
244
+ emitToChannel<TData = unknown>(channel: string, event: string, data?: TData): Promise<number>;
245
245
  /**
246
246
  * Socket.IO-like emit API: Emit an event to a specific user (all their sessions) via RPC.
247
247
  * @param userId - User ID to emit to
@@ -253,7 +253,7 @@ interface ActorStub {
253
253
  * await stub.emitToUser("alice", "notification", { message: "Hello!" });
254
254
  * ```
255
255
  */
256
- emitToUser(userId: string, event: string, data?: any): Promise<number>;
256
+ emitToUser<TData = unknown>(userId: string, event: string, data?: TData): Promise<number>;
257
257
  /**
258
258
  * @deprecated Use `emitToUser()` instead for Socket.IO-like API.
259
259
  * Sends a message to a specific user (all their sessions) via RPC.
@@ -262,7 +262,7 @@ interface ActorStub {
262
262
  * @param data - Message data
263
263
  * @returns Promise resolving to the number of sessions that received the message
264
264
  */
265
- sendToUser(userId: string, channel: string, data?: any): Promise<number>;
265
+ sendToUser<TData = unknown>(userId: string, channel: string, data?: TData): Promise<number>;
266
266
  /**
267
267
  * @deprecated Use `emitToChannel()` instead for Socket.IO-like API.
268
268
  * Broadcasts a message to all connections in a channel via RPC.
@@ -273,7 +273,7 @@ interface ActorStub {
273
273
  * @param opts - Broadcast options (filtering by userIds or clientIds)
274
274
  * @returns Promise resolving to the number of connections that received the message
275
275
  */
276
- broadcast(channel: string, data: any, opts?: RpcBroadcastOptions): Promise<number>;
276
+ broadcast<TData = unknown>(channel: string, data: TData, opts?: RpcBroadcastOptions): Promise<number>;
277
277
  /**
278
278
  * Gets the total number of active sessions via RPC.
279
279
  * @returns Promise resolving to the number of connected WebSockets
@@ -321,7 +321,7 @@ interface VeraniActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
321
321
  * Returns the number of connections the message was sent to.
322
322
  * @see @src/actor/actor-runtime.ts broadcast()
323
323
  */
324
- broadcast(channel: string, data: any, opts?: BroadcastOptions): number;
324
+ broadcast<TData = unknown>(channel: string, data: TData, opts?: BroadcastOptions): number;
325
325
  /**
326
326
  * Returns the number of currently connected WebSocket sessions.
327
327
  * @see @src/actor/actor-runtime.ts getSessionCount()
@@ -344,7 +344,7 @@ interface VeraniActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
344
344
  * The message "type" is always "event" (see src/actor/actor-runtime.ts).
345
345
  * @see @src/actor/actor-runtime.ts sendToUser()
346
346
  */
347
- sendToUser(userId: string, channel: string, data?: any): number;
347
+ sendToUser<TData = unknown>(userId: string, channel: string, data?: TData): number;
348
348
  /**
349
349
  * Validates and removes stale WebSocket sessions.
350
350
  * Called automatically during broadcast/send operations, but can be called manually.
@@ -393,11 +393,11 @@ interface ConnectionActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unk
393
393
  * Deliver a message to this connection's WebSocket
394
394
  * Called via RPC from RoomDO
395
395
  */
396
- deliverMessage(event: string, data?: any): Promise<boolean>;
396
+ deliverMessage<TData = unknown>(event: string, data?: TData): Promise<boolean>;
397
397
  /**
398
398
  * Deliver a system event (presence, room events, etc.)
399
399
  */
400
- deliverSystemEvent(type: string, payload?: any): Promise<void>;
400
+ deliverSystemEvent<TPayload = unknown>(type: string, payload?: TPayload): Promise<void>;
401
401
  /**
402
402
  * Join a room (register with RoomDO)
403
403
  */
@@ -425,7 +425,7 @@ interface ConnectionEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unkn
425
425
  * @param event - Event name
426
426
  * @param data - Event data
427
427
  */
428
- emit(event: string, data?: any): void;
428
+ emit<TData = unknown>(event: string, data?: TData): void;
429
429
  /**
430
430
  * Target a specific room or user for emitting
431
431
  * @param target - Room name (if starts with "room:") or userId
@@ -455,12 +455,17 @@ interface AsyncEmitBuilder {
455
455
  * @param data - Event data
456
456
  * @returns Promise resolving to number of recipients
457
457
  */
458
- emit(event: string, data?: any): Promise<number>;
458
+ emit<TData = unknown>(event: string, data?: TData): Promise<number>;
459
459
  }
460
460
  /**
461
461
  * Event handler function type for socket.io-like event handling
462
+ *
463
+ * @template TMeta - Connection metadata type
464
+ * @template E - Environment type
465
+ * @template TState - Room state type
466
+ * @template TData - Event data type (defaults to unknown for type safety)
462
467
  */
463
- type EventHandler<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>> = (ctx: MessageContext<TMeta, E, TState>, data: any) => void | Promise<void>;
468
+ type EventHandler<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>, TData = unknown> = (ctx: MessageContext<TMeta, E, TState>, data: TData) => void | Promise<void>;
464
469
  /**
465
470
  * Event emitter interface for room-level event handling
466
471
  */
@@ -470,20 +475,20 @@ interface RoomEventEmitter<TMeta extends ConnectionMeta = ConnectionMeta, E = un
470
475
  * @param event - Event name (supports wildcard "*")
471
476
  * @param handler - Handler function
472
477
  */
473
- on(event: string, handler: EventHandler<TMeta, E, TState>): void;
478
+ on<TData = unknown>(event: string, handler: EventHandler<TMeta, E, TState, TData>): void;
474
479
  /**
475
480
  * Remove an event handler
476
481
  * @param event - Event name
477
482
  * @param handler - Optional specific handler to remove, or remove all handlers for event
478
483
  */
479
- off(event: string, handler?: EventHandler<TMeta, E, TState>): void;
484
+ off<TData = unknown>(event: string, handler?: EventHandler<TMeta, E, TState, TData>): void;
480
485
  /**
481
486
  * Emit an event to registered handlers
482
487
  * @param event - Event name
483
488
  * @param ctx - Message context
484
489
  * @param data - Event data
485
490
  */
486
- emit(event: string, ctx: MessageContext<TMeta, E, TState>, data: any): Promise<void>;
491
+ emit<TData = unknown>(event: string, ctx: MessageContext<TMeta, E, TState>, data: TData): Promise<void>;
487
492
  /**
488
493
  * Check if there are any handlers registered for a given event.
489
494
  * Returns true if handlers exist for the specific event or for the wildcard "*" event.
@@ -509,7 +514,7 @@ interface EmitBuilder<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
509
514
  * @param data - Event data
510
515
  * @returns Number of connections that received the message
511
516
  */
512
- emit(event: string, data?: any): number;
517
+ emit<TData = unknown>(event: string, data?: TData): number;
513
518
  }
514
519
  /**
515
520
  * Socket-level emit API (available on context)
@@ -521,7 +526,7 @@ interface SocketEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown>
521
526
  * @param event - Event name
522
527
  * @param data - Event data
523
528
  */
524
- emit(event: string, data?: any): void;
529
+ emit<TData = unknown>(event: string, data?: TData): void;
525
530
  /**
526
531
  * Target a specific user or channel for emitting
527
532
  * @param target - User ID or channel name
@@ -540,7 +545,7 @@ interface ActorEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown>
540
545
  * @param data - Event data
541
546
  * @returns Number of connections that received the message
542
547
  */
543
- emit(event: string, data?: any): number;
548
+ emit<TData = unknown>(event: string, data?: TData): number;
544
549
  /**
545
550
  * Target a specific channel for broadcasting
546
551
  * @param channel - Channel name
@@ -0,0 +1 @@
1
+ const require_encode=require(`./encode-SjZrKIyU.cjs`);function encodeClientMessage(l){return require_encode.t(l)}function decodeServerMessage(l){return require_encode.o(l)}const DEFAULT_RECONNECTION_CONFIG={enabled:!0,maxAttempts:10,initialDelay:1e3,maxDelay:3e4,backoffMultiplier:1.5};var ConnectionManager=class{constructor(e=DEFAULT_RECONNECTION_CONFIG,l){this.config=e,this.onStateChange=l,this.state=`disconnected`,this.reconnectAttempts=0,this.currentDelay=e.initialDelay}getState(){return this.state}isValidStateTransition(e,l){return{disconnected:[`connecting`,`reconnecting`],connecting:[`connected`,`disconnected`,`error`,`reconnecting`],connected:[`disconnected`,`reconnecting`],reconnecting:[`connecting`,`disconnected`,`error`],error:[`reconnecting`,`disconnected`,`connecting`]}[e]?.includes(l)??!1}setState(e){this.state!==e&&(this.isValidStateTransition(this.state,e),this.state=e,this.onStateChange?.(e))}resetReconnection(){this.reconnectAttempts=0,this.currentDelay=this.config.initialDelay,this.clearReconnectTimer()}scheduleReconnect(e){return this.config.enabled?this.config.maxAttempts>0&&this.reconnectAttempts>=this.config.maxAttempts?(this.setState(`error`),!1):(this.clearReconnectTimer(),this.setState(`reconnecting`),this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{e(),this.currentDelay=Math.min(this.currentDelay*this.config.backoffMultiplier,this.config.maxDelay)},this.currentDelay),!0):!1}cancelReconnect(){this.clearReconnectTimer(),this.state===`reconnecting`&&this.setState(`disconnected`)}clearReconnectTimer(){this.reconnectTimer!==void 0&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0)}getReconnectAttempts(){return this.reconnectAttempts}getNextDelay(){return this.currentDelay}destroy(){this.clearReconnectTimer()}};function resolveClientOptions(e){return{reconnection:{enabled:e.reconnection?.enabled??DEFAULT_RECONNECTION_CONFIG.enabled,maxAttempts:e.reconnection?.maxAttempts??DEFAULT_RECONNECTION_CONFIG.maxAttempts,initialDelay:e.reconnection?.initialDelay??DEFAULT_RECONNECTION_CONFIG.initialDelay,maxDelay:e.reconnection?.maxDelay??DEFAULT_RECONNECTION_CONFIG.maxDelay,backoffMultiplier:e.reconnection?.backoffMultiplier??DEFAULT_RECONNECTION_CONFIG.backoffMultiplier},maxQueueSize:e.maxQueueSize??100,connectionTimeout:e.connectionTimeout??1e4,pingInterval:e.pingInterval??5e3,pongTimeout:e.pongTimeout??5e3}}var MessageQueue=class{constructor(e){this.maxQueueSize=e,this.queue=[]}queueMessage(e){this.queue.length>=this.maxQueueSize&&this.queue.shift(),this.queue.push(e)}flushMessageQueue(e){if(!(!e||e.readyState!==WebSocket.OPEN))for(;this.queue.length>0;){let u=this.queue.shift();try{e.send(encodeClientMessage(u))}catch{}}}clear(){this.queue=[]}getLength(){return this.queue.length}};function isBrowserEnvironment(){return typeof globalThis<`u`&&`document`in globalThis&&globalThis.document!==void 0&&globalThis.document.hidden!==void 0&&typeof globalThis.document.addEventListener==`function`}function getDocument(){return isBrowserEnvironment()&&`document`in globalThis?globalThis.document:null}function isPageVisible(){let e=getDocument();return e?!e.hidden:!0}function onVisibilityChange(e){let l=getDocument();if(!l)return null;let u=()=>{e(isPageVisible())};return l.addEventListener(`visibilitychange`,u),()=>{l.removeEventListener(`visibilitychange`,u)}}var KeepaliveManager=class{constructor(e,l){this.options=e,this.getWebSocket=l,this.lastPongReceived=0}startPingInterval(){this.options.pingInterval===0||this.pingInterval!==void 0||(this.lastPongReceived=Date.now(),this.visibilityCleanup=onVisibilityChange(e=>{e&&this.resyncPingInterval()}),this.pingInterval=setInterval(this.createPingInterval(),this.options.pingInterval))}createPingInterval(){return()=>{let e=this.getWebSocket();if(!e||e.readyState!==WebSocket.OPEN){this.stopPingInterval();return}if(Date.now()-this.lastPongReceived>this.options.pongTimeout+this.options.pingInterval){this.stopPingInterval(),e.close(1006,`Pong timeout`);return}try{e.send(encodeClientMessage({type:`ping`}))}catch{}}}resyncPingInterval(){let e=this.getWebSocket();if(!(!e||e.readyState!==WebSocket.OPEN)){this.pingInterval!==void 0&&(clearInterval(this.pingInterval),this.pingInterval=void 0);try{e.send(encodeClientMessage({type:`ping`}))}catch{}this.lastPongReceived=Date.now(),this.pingInterval=setInterval(this.createPingInterval(),this.options.pingInterval)}}stopPingInterval(){this.pingInterval!==void 0&&(clearInterval(this.pingInterval),this.pingInterval=void 0),this.visibilityCleanup&&=(this.visibilityCleanup(),void 0)}recordPong(){this.lastPongReceived=Date.now()}},EventEmitter=class{constructor(){this.listeners=new Map}on(e,l){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(l)}off(e,l){let u=this.listeners.get(e);u&&(u.delete(l),u.size===0&&this.listeners.delete(e))}once(e,l){let u=d=>{this.off(e,u),l(d)};this.on(e,u)}emitLifecycleEvent(e,l){let u=this.listeners.get(e);if(u)for(let e of u)try{e(l)}catch{}}dispatch(e,l){let u=this.listeners.get(e);if(u)for(let e of u)try{e(l)}catch{}}clear(){this.listeners.clear()}};function handleWebSocketOpen(e,l,u,d,f,p,m,h){e.clear(),l.setState(`connected`),l.resetReconnection(),u.startPingInterval(),d.flushMessageQueue(f),p.resolve&&(p.resolve(),p.clear()),m.emitLifecycleEvent(`open`),m.emitLifecycleEvent(`connected`),h?.()}function handleWebSocketMessage(e,l,d){let f=decodeServerMessage(e.data);if(!f)return;if(f.type===`pong`){l.recordPong();return}let p=f.type,m=f.data,h=f.data;f.type===`event`&&h&&typeof h==`object`&&`type`in h&&(p=h.type,m=h),d.dispatch(p,m)}function handleWebSocketClose(e,l,u,d,f,p,m,h){m&&(m.value=!1),l.clear(),u.setState(`disconnected`),d.reject&&(d.reject(Error(`Connection closed: ${e.reason||`Unknown reason`}`)),d.clear()),f.emitLifecycleEvent(`close`,e),f.emitLifecycleEvent(`disconnected`,e),h?.(e),e.code!==1e3&&e.code!==1001&&u.scheduleReconnect(p)&&f.emitLifecycleEvent(`reconnecting`)}function handleWebSocketError(e,l,u,d,f,p){f&&(f.value=!1),l.clear(),u.emitLifecycleEvent(`error`,e),p?.(e),d(Error(`WebSocket error`))}function handleConnectionError(e,l,u,d,f,p,m){m&&(m.value=!1),l.clear(),u.reject&&(u.reject(e),u.clear()),f.emitLifecycleEvent(`error`,e),d.scheduleReconnect(p)&&f.emitLifecycleEvent(`reconnecting`)}var ConnectionHandler=class{constructor(e,l,u,d,f,p,m,h,g,_,v,y){this.url=e,this.options=l,this.connectionManager=u,this.keepalive=d,this.eventEmitter=f,this.messageQueue=p,this.connectionPromise=m,this.isConnectingRef=h,this.isConnectedFn=g,this.onOpenCallback=_,this.onCloseCallback=v,this.onErrorCallback=y,this.connectionId=0,this.connectionTimeoutState={value:void 0,clear:()=>{this.connectionTimeoutState.value!==void 0&&(clearTimeout(this.connectionTimeoutState.value),this.connectionTimeoutState.value=void 0)}}}connect(){if(!this.isConnectingRef.value&&!this.isConnectedFn()){this.cleanupWebSocket();try{this.isConnectingRef.value=!0,this.connectionId++;let e=this.connectionId;this.connectionManager.setState(`connecting`),this.eventEmitter.emitLifecycleEvent(`connecting`),this.ws=new WebSocket(this.url),this.connectionTimeoutState.value=setTimeout(()=>{this.isConnectingRef.value&&this.connectionId===e&&(this.ws?.close(),this.handleConnectionErrorInternal(Error(`Connection timeout`)))},this.options.connectionTimeout),this.ws.addEventListener(`open`,()=>{this.connectionId===e&&this.handleOpenInternal()}),this.ws.addEventListener(`message`,l=>{this.connectionId===e&&handleWebSocketMessage(l,this.keepalive,this.eventEmitter)}),this.ws.addEventListener(`close`,l=>{this.connectionId===e&&handleWebSocketClose(l,this.connectionTimeoutState,this.connectionManager,this.connectionPromise,this.eventEmitter,()=>this.connect(),this.isConnectingRef,this.onCloseCallback)}),this.ws.addEventListener(`error`,l=>{this.connectionId===e&&handleWebSocketError(l,this.connectionTimeoutState,this.eventEmitter,e=>this.handleConnectionErrorInternal(e),this.isConnectingRef,this.onErrorCallback)})}catch(e){this.isConnectingRef.value=!1,this.handleConnectionErrorInternal(e)}}}cleanupWebSocket(){if(this.keepalive.stopPingInterval(),this.connectionTimeoutState.clear(),this.ws){let e=this.ws;if(this.ws=void 0,e.readyState===WebSocket.OPEN||e.readyState===WebSocket.CONNECTING)try{e.close(1e3,`Cleanup`)}catch{}}}getWebSocket(){return this.ws}getConnectionId(){return this.connectionId}handleOpenInternal(){handleWebSocketOpen(this.connectionTimeoutState,this.connectionManager,this.keepalive,this.messageQueue,this.ws,this.connectionPromise,this.eventEmitter,this.onOpenCallback),this.isConnectingRef.value=!1}handleConnectionErrorInternal(e){handleConnectionError(e,this.connectionTimeoutState,this.connectionPromise,this.connectionManager,this.eventEmitter,()=>this.connect(),this.isConnectingRef)}},VeraniClient=class{constructor(e,l={}){this.url=e,this.connectionPromiseState={promise:void 0,resolve:void 0,reject:void 0,clear:()=>{this.connectionPromiseState.promise=void 0,this.connectionPromiseState.resolve=void 0,this.connectionPromiseState.reject=void 0}},this.options=resolveClientOptions(l),this.connectionManager=new ConnectionManager(this.options.reconnection,e=>{this.onStateChangeCallback?.(e)}),this.messageQueue=new MessageQueue(this.options.maxQueueSize),this.eventEmitter=new EventEmitter,this.isConnectingRef={value:!1},this.keepalive=new KeepaliveManager(this.options,()=>this.connectionHandler.getWebSocket()),this.connectionHandler=new ConnectionHandler(this.url,this.options,this.connectionManager,this.keepalive,this.eventEmitter,this.messageQueue,this.connectionPromiseState,this.isConnectingRef,()=>this.isConnected(),this.onOpenCallback,this.onCloseCallback,this.onErrorCallback),Object.defineProperty(this,`isConnecting`,{get:()=>this.isConnectingRef.value,enumerable:!0,configurable:!0}),this.connect()}connect(){this.connectionHandler.connect()}cleanupWebSocket(){this.connectionHandler.cleanupWebSocket()}getState(){return this.connectionManager.getState()}isConnected(){return this.connectionHandler.getWebSocket()?.readyState===WebSocket.OPEN&&this.connectionManager.getState()===`connected`}getConnectionState(){return{state:this.connectionManager.getState(),isConnected:this.isConnected(),isConnecting:this.isConnectingRef.value,reconnectAttempts:this.connectionManager.getReconnectAttempts(),connectionId:this.connectionHandler.getConnectionId()}}waitForConnection(){return this.isConnected()?Promise.resolve():(this.connectionPromiseState.promise||(this.connectionPromiseState.promise=new Promise((e,l)=>{this.connectionPromiseState.resolve=e,this.connectionPromiseState.reject=l;let u=setTimeout(()=>{this.connectionPromiseState.reject&&(this.connectionPromiseState.reject(Error(`Connection wait timeout`)),this.connectionPromiseState.clear())},this.options.connectionTimeout*2);this.connectionPromiseState.promise&&this.connectionPromiseState.promise.finally(()=>{clearTimeout(u)})})),this.connectionPromiseState.promise)}on(e,l){this.eventEmitter.on(e,l)}off(e,l){this.eventEmitter.off(e,l)}once(e,l){this.eventEmitter.once(e,l)}emit(e,u){let d={type:e,data:u};if(this.isConnected()){let e=this.connectionHandler.getWebSocket();if(e)try{e.send(encodeClientMessage(d))}catch{this.messageQueue.queueMessage(d)}}else this.messageQueue.queueMessage(d)}onOpen(e){this.onOpenCallback=e}onClose(e){this.onCloseCallback=e}onError(e){this.onErrorCallback=e}onStateChange(e){this.onStateChangeCallback=e}reconnect(){this.connectionManager.resetReconnection(),this.connectionManager.cancelReconnect(),this.cleanupWebSocket(),this.isConnectingRef.value=!1,this.connectionManager.setState(`disconnected`),this.connect()}disconnect(){this.connectionManager.cancelReconnect(),this.isConnectingRef.value=!1,this.connectionPromiseState.reject&&(this.connectionPromiseState.reject(Error(`Connection disconnected`)),this.connectionPromiseState.clear()),this.cleanupWebSocket(),this.connectionManager.setState(`disconnected`)}close(){this.connectionPromiseState.reject&&(this.connectionPromiseState.reject(Error(`Client closed`)),this.connectionPromiseState.clear()),this.disconnect(),this.eventEmitter.clear(),this.messageQueue.clear(),this.connectionManager.destroy()}};Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return ConnectionManager}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return DEFAULT_RECONNECTION_CONFIG}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return VeraniClient}});
@@ -180,25 +180,25 @@ declare class VeraniClient {
180
180
  * @param event - Event type to listen for
181
181
  * @param callback - Callback function to invoke when event is received
182
182
  */
183
- on(event: string, callback: (data: any) => void): void;
183
+ on<TData = unknown>(event: string, callback: (data: TData) => void): void;
184
184
  /**
185
185
  * Removes an event listener
186
186
  * @param event - Event type to remove listener from
187
187
  * @param callback - Callback function to remove
188
188
  */
189
- off(event: string, callback: (data: any) => void): void;
189
+ off<TData = unknown>(event: string, callback: (data: TData) => void): void;
190
190
  /**
191
191
  * Registers a one-time event listener
192
192
  * @param event - Event type to listen for
193
193
  * @param callback - Callback function to invoke once
194
194
  */
195
- once(event: string, callback: (data: any) => void): void;
195
+ once<TData = unknown>(event: string, callback: (data: TData) => void): void;
196
196
  /**
197
197
  * Sends a message to the server
198
198
  * @param type - Message type
199
199
  * @param data - Optional message data
200
200
  */
201
- emit(type: string, data?: any): void;
201
+ emit<TData = unknown>(type: string, data?: TData): void;
202
202
  /**
203
203
  * Registers lifecycle callback for connection open
204
204
  */
@@ -180,25 +180,25 @@ declare class VeraniClient {
180
180
  * @param event - Event type to listen for
181
181
  * @param callback - Callback function to invoke when event is received
182
182
  */
183
- on(event: string, callback: (data: any) => void): void;
183
+ on<TData = unknown>(event: string, callback: (data: TData) => void): void;
184
184
  /**
185
185
  * Removes an event listener
186
186
  * @param event - Event type to remove listener from
187
187
  * @param callback - Callback function to remove
188
188
  */
189
- off(event: string, callback: (data: any) => void): void;
189
+ off<TData = unknown>(event: string, callback: (data: TData) => void): void;
190
190
  /**
191
191
  * Registers a one-time event listener
192
192
  * @param event - Event type to listen for
193
193
  * @param callback - Callback function to invoke once
194
194
  */
195
- once(event: string, callback: (data: any) => void): void;
195
+ once<TData = unknown>(event: string, callback: (data: TData) => void): void;
196
196
  /**
197
197
  * Sends a message to the server
198
198
  * @param type - Message type
199
199
  * @param data - Optional message data
200
200
  */
201
- emit(type: string, data?: any): void;
201
+ emit<TData = unknown>(type: string, data?: TData): void;
202
202
  /**
203
203
  * Registers lifecycle callback for connection open
204
204
  */
@@ -0,0 +1 @@
1
+ import{o as decodeServerMessage$1,t as encodeClientMessage$1}from"./encode-CFndA-BQ.mjs";function encodeClientMessage(e){return encodeClientMessage$1(e)}function decodeServerMessage(u){return decodeServerMessage$1(u)}const DEFAULT_RECONNECTION_CONFIG={enabled:!0,maxAttempts:10,initialDelay:1e3,maxDelay:3e4,backoffMultiplier:1.5};var ConnectionManager=class{constructor(e=DEFAULT_RECONNECTION_CONFIG,u){this.config=e,this.onStateChange=u,this.state=`disconnected`,this.reconnectAttempts=0,this.currentDelay=e.initialDelay}getState(){return this.state}isValidStateTransition(e,u){return{disconnected:[`connecting`,`reconnecting`],connecting:[`connected`,`disconnected`,`error`,`reconnecting`],connected:[`disconnected`,`reconnecting`],reconnecting:[`connecting`,`disconnected`,`error`],error:[`reconnecting`,`disconnected`,`connecting`]}[e]?.includes(u)??!1}setState(e){this.state!==e&&(this.isValidStateTransition(this.state,e),this.state=e,this.onStateChange?.(e))}resetReconnection(){this.reconnectAttempts=0,this.currentDelay=this.config.initialDelay,this.clearReconnectTimer()}scheduleReconnect(e){return this.config.enabled?this.config.maxAttempts>0&&this.reconnectAttempts>=this.config.maxAttempts?(this.setState(`error`),!1):(this.clearReconnectTimer(),this.setState(`reconnecting`),this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{e(),this.currentDelay=Math.min(this.currentDelay*this.config.backoffMultiplier,this.config.maxDelay)},this.currentDelay),!0):!1}cancelReconnect(){this.clearReconnectTimer(),this.state===`reconnecting`&&this.setState(`disconnected`)}clearReconnectTimer(){this.reconnectTimer!==void 0&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0)}getReconnectAttempts(){return this.reconnectAttempts}getNextDelay(){return this.currentDelay}destroy(){this.clearReconnectTimer()}};function resolveClientOptions(e){return{reconnection:{enabled:e.reconnection?.enabled??DEFAULT_RECONNECTION_CONFIG.enabled,maxAttempts:e.reconnection?.maxAttempts??DEFAULT_RECONNECTION_CONFIG.maxAttempts,initialDelay:e.reconnection?.initialDelay??DEFAULT_RECONNECTION_CONFIG.initialDelay,maxDelay:e.reconnection?.maxDelay??DEFAULT_RECONNECTION_CONFIG.maxDelay,backoffMultiplier:e.reconnection?.backoffMultiplier??DEFAULT_RECONNECTION_CONFIG.backoffMultiplier},maxQueueSize:e.maxQueueSize??100,connectionTimeout:e.connectionTimeout??1e4,pingInterval:e.pingInterval??5e3,pongTimeout:e.pongTimeout??5e3}}var MessageQueue=class{constructor(e){this.maxQueueSize=e,this.queue=[]}queueMessage(e){this.queue.length>=this.maxQueueSize&&this.queue.shift(),this.queue.push(e)}flushMessageQueue(e){if(!(!e||e.readyState!==WebSocket.OPEN))for(;this.queue.length>0;){let u=this.queue.shift();try{e.send(encodeClientMessage(u))}catch{}}}clear(){this.queue=[]}getLength(){return this.queue.length}};function isBrowserEnvironment(){return typeof globalThis<`u`&&`document`in globalThis&&globalThis.document!==void 0&&globalThis.document.hidden!==void 0&&typeof globalThis.document.addEventListener==`function`}function getDocument(){return isBrowserEnvironment()&&`document`in globalThis?globalThis.document:null}function isPageVisible(){let e=getDocument();return e?!e.hidden:!0}function onVisibilityChange(e){let u=getDocument();if(!u)return null;let d=()=>{e(isPageVisible())};return u.addEventListener(`visibilitychange`,d),()=>{u.removeEventListener(`visibilitychange`,d)}}var KeepaliveManager=class{constructor(e,u){this.options=e,this.getWebSocket=u,this.lastPongReceived=0}startPingInterval(){this.options.pingInterval===0||this.pingInterval!==void 0||(this.lastPongReceived=Date.now(),this.visibilityCleanup=onVisibilityChange(e=>{e&&this.resyncPingInterval()}),this.pingInterval=setInterval(this.createPingInterval(),this.options.pingInterval))}createPingInterval(){return()=>{let e=this.getWebSocket();if(!e||e.readyState!==WebSocket.OPEN){this.stopPingInterval();return}if(Date.now()-this.lastPongReceived>this.options.pongTimeout+this.options.pingInterval){this.stopPingInterval(),e.close(1006,`Pong timeout`);return}try{e.send(encodeClientMessage({type:`ping`}))}catch{}}}resyncPingInterval(){let e=this.getWebSocket();if(!(!e||e.readyState!==WebSocket.OPEN)){this.pingInterval!==void 0&&(clearInterval(this.pingInterval),this.pingInterval=void 0);try{e.send(encodeClientMessage({type:`ping`}))}catch{}this.lastPongReceived=Date.now(),this.pingInterval=setInterval(this.createPingInterval(),this.options.pingInterval)}}stopPingInterval(){this.pingInterval!==void 0&&(clearInterval(this.pingInterval),this.pingInterval=void 0),this.visibilityCleanup&&=(this.visibilityCleanup(),void 0)}recordPong(){this.lastPongReceived=Date.now()}},EventEmitter=class{constructor(){this.listeners=new Map}on(e,u){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(u)}off(e,u){let d=this.listeners.get(e);d&&(d.delete(u),d.size===0&&this.listeners.delete(e))}once(e,u){let d=f=>{this.off(e,d),u(f)};this.on(e,d)}emitLifecycleEvent(e,u){let d=this.listeners.get(e);if(d)for(let e of d)try{e(u)}catch{}}dispatch(e,u){let d=this.listeners.get(e);if(d)for(let e of d)try{e(u)}catch{}}clear(){this.listeners.clear()}};function handleWebSocketOpen(e,u,d,f,p,m,h,g){e.clear(),u.setState(`connected`),u.resetReconnection(),d.startPingInterval(),f.flushMessageQueue(p),m.resolve&&(m.resolve(),m.clear()),h.emitLifecycleEvent(`open`),h.emitLifecycleEvent(`connected`),g?.()}function handleWebSocketMessage(e,u,d){let p=decodeServerMessage(e.data);if(!p)return;if(p.type===`pong`){u.recordPong();return}let m=p.type,h=p.data,g=p.data;p.type===`event`&&g&&typeof g==`object`&&`type`in g&&(m=g.type,h=g),d.dispatch(m,h)}function handleWebSocketClose(e,u,d,f,p,m,h,g){h&&(h.value=!1),u.clear(),d.setState(`disconnected`),f.reject&&(f.reject(Error(`Connection closed: ${e.reason||`Unknown reason`}`)),f.clear()),p.emitLifecycleEvent(`close`,e),p.emitLifecycleEvent(`disconnected`,e),g?.(e),e.code!==1e3&&e.code!==1001&&d.scheduleReconnect(m)&&p.emitLifecycleEvent(`reconnecting`)}function handleWebSocketError(e,u,d,f,p,m){p&&(p.value=!1),u.clear(),d.emitLifecycleEvent(`error`,e),m?.(e),f(Error(`WebSocket error`))}function handleConnectionError(e,u,d,f,p,m,h){h&&(h.value=!1),u.clear(),d.reject&&(d.reject(e),d.clear()),p.emitLifecycleEvent(`error`,e),f.scheduleReconnect(m)&&p.emitLifecycleEvent(`reconnecting`)}var ConnectionHandler=class{constructor(e,u,d,f,p,m,h,g,_,v,y,b){this.url=e,this.options=u,this.connectionManager=d,this.keepalive=f,this.eventEmitter=p,this.messageQueue=m,this.connectionPromise=h,this.isConnectingRef=g,this.isConnectedFn=_,this.onOpenCallback=v,this.onCloseCallback=y,this.onErrorCallback=b,this.connectionId=0,this.connectionTimeoutState={value:void 0,clear:()=>{this.connectionTimeoutState.value!==void 0&&(clearTimeout(this.connectionTimeoutState.value),this.connectionTimeoutState.value=void 0)}}}connect(){if(!this.isConnectingRef.value&&!this.isConnectedFn()){this.cleanupWebSocket();try{this.isConnectingRef.value=!0,this.connectionId++;let e=this.connectionId;this.connectionManager.setState(`connecting`),this.eventEmitter.emitLifecycleEvent(`connecting`),this.ws=new WebSocket(this.url),this.connectionTimeoutState.value=setTimeout(()=>{this.isConnectingRef.value&&this.connectionId===e&&(this.ws?.close(),this.handleConnectionErrorInternal(Error(`Connection timeout`)))},this.options.connectionTimeout),this.ws.addEventListener(`open`,()=>{this.connectionId===e&&this.handleOpenInternal()}),this.ws.addEventListener(`message`,u=>{this.connectionId===e&&handleWebSocketMessage(u,this.keepalive,this.eventEmitter)}),this.ws.addEventListener(`close`,u=>{this.connectionId===e&&handleWebSocketClose(u,this.connectionTimeoutState,this.connectionManager,this.connectionPromise,this.eventEmitter,()=>this.connect(),this.isConnectingRef,this.onCloseCallback)}),this.ws.addEventListener(`error`,u=>{this.connectionId===e&&handleWebSocketError(u,this.connectionTimeoutState,this.eventEmitter,e=>this.handleConnectionErrorInternal(e),this.isConnectingRef,this.onErrorCallback)})}catch(e){this.isConnectingRef.value=!1,this.handleConnectionErrorInternal(e)}}}cleanupWebSocket(){if(this.keepalive.stopPingInterval(),this.connectionTimeoutState.clear(),this.ws){let e=this.ws;if(this.ws=void 0,e.readyState===WebSocket.OPEN||e.readyState===WebSocket.CONNECTING)try{e.close(1e3,`Cleanup`)}catch{}}}getWebSocket(){return this.ws}getConnectionId(){return this.connectionId}handleOpenInternal(){handleWebSocketOpen(this.connectionTimeoutState,this.connectionManager,this.keepalive,this.messageQueue,this.ws,this.connectionPromise,this.eventEmitter,this.onOpenCallback),this.isConnectingRef.value=!1}handleConnectionErrorInternal(e){handleConnectionError(e,this.connectionTimeoutState,this.connectionPromise,this.connectionManager,this.eventEmitter,()=>this.connect(),this.isConnectingRef)}},VeraniClient=class{constructor(e,u={}){this.url=e,this.connectionPromiseState={promise:void 0,resolve:void 0,reject:void 0,clear:()=>{this.connectionPromiseState.promise=void 0,this.connectionPromiseState.resolve=void 0,this.connectionPromiseState.reject=void 0}},this.options=resolveClientOptions(u),this.connectionManager=new ConnectionManager(this.options.reconnection,e=>{this.onStateChangeCallback?.(e)}),this.messageQueue=new MessageQueue(this.options.maxQueueSize),this.eventEmitter=new EventEmitter,this.isConnectingRef={value:!1},this.keepalive=new KeepaliveManager(this.options,()=>this.connectionHandler.getWebSocket()),this.connectionHandler=new ConnectionHandler(this.url,this.options,this.connectionManager,this.keepalive,this.eventEmitter,this.messageQueue,this.connectionPromiseState,this.isConnectingRef,()=>this.isConnected(),this.onOpenCallback,this.onCloseCallback,this.onErrorCallback),Object.defineProperty(this,`isConnecting`,{get:()=>this.isConnectingRef.value,enumerable:!0,configurable:!0}),this.connect()}connect(){this.connectionHandler.connect()}cleanupWebSocket(){this.connectionHandler.cleanupWebSocket()}getState(){return this.connectionManager.getState()}isConnected(){return this.connectionHandler.getWebSocket()?.readyState===WebSocket.OPEN&&this.connectionManager.getState()===`connected`}getConnectionState(){return{state:this.connectionManager.getState(),isConnected:this.isConnected(),isConnecting:this.isConnectingRef.value,reconnectAttempts:this.connectionManager.getReconnectAttempts(),connectionId:this.connectionHandler.getConnectionId()}}waitForConnection(){return this.isConnected()?Promise.resolve():(this.connectionPromiseState.promise||(this.connectionPromiseState.promise=new Promise((e,u)=>{this.connectionPromiseState.resolve=e,this.connectionPromiseState.reject=u;let d=setTimeout(()=>{this.connectionPromiseState.reject&&(this.connectionPromiseState.reject(Error(`Connection wait timeout`)),this.connectionPromiseState.clear())},this.options.connectionTimeout*2);this.connectionPromiseState.promise&&this.connectionPromiseState.promise.finally(()=>{clearTimeout(d)})})),this.connectionPromiseState.promise)}on(e,u){this.eventEmitter.on(e,u)}off(e,u){this.eventEmitter.off(e,u)}once(e,u){this.eventEmitter.once(e,u)}emit(e,u){let f={type:e,data:u};if(this.isConnected()){let e=this.connectionHandler.getWebSocket();if(e)try{e.send(encodeClientMessage(f))}catch{this.messageQueue.queueMessage(f)}}else this.messageQueue.queueMessage(f)}onOpen(e){this.onOpenCallback=e}onClose(e){this.onCloseCallback=e}onError(e){this.onErrorCallback=e}onStateChange(e){this.onStateChangeCallback=e}reconnect(){this.connectionManager.resetReconnection(),this.connectionManager.cancelReconnect(),this.cleanupWebSocket(),this.isConnectingRef.value=!1,this.connectionManager.setState(`disconnected`),this.connect()}disconnect(){this.connectionManager.cancelReconnect(),this.isConnectingRef.value=!1,this.connectionPromiseState.reject&&(this.connectionPromiseState.reject(Error(`Connection disconnected`)),this.connectionPromiseState.clear()),this.cleanupWebSocket(),this.connectionManager.setState(`disconnected`)}close(){this.connectionPromiseState.reject&&(this.connectionPromiseState.reject(Error(`Client closed`)),this.connectionPromiseState.clear()),this.disconnect(),this.eventEmitter.clear(),this.messageQueue.clear(),this.connectionManager.destroy()}};export{ConnectionManager as n,DEFAULT_RECONNECTION_CONFIG as r,VeraniClient as t};
package/dist/client.cjs CHANGED
@@ -1 +1 @@
1
- const require_encode=require(`./encode-BYFW_6TI.cjs`),require_types=require(`./types-DUO6RVw1.cjs`),require_client=require(`./client-C3K_PiKE.cjs`);exports.ConnectionManager=require_client.n,exports.DEFAULT_RECONNECTION_CONFIG=require_client.r,exports.PROTOCOL_VERSION=require_types.t,exports.VeraniClient=require_client.t,exports.decodeClientMessage=require_encode.i,exports.decodeFrame=require_encode.a,exports.decodeServerMessage=require_encode.o,exports.encodeClientMessage=require_encode.t,exports.encodeFrame=require_encode.n,exports.encodeServerMessage=require_encode.r;
1
+ const require_encode=require(`./encode-SjZrKIyU.cjs`),require_types=require(`./types-DUO6RVw1.cjs`),require_client=require(`./client-Cf_oqaqp.cjs`);exports.ConnectionManager=require_client.n,exports.DEFAULT_RECONNECTION_CONFIG=require_client.r,exports.PROTOCOL_VERSION=require_types.t,exports.VeraniClient=require_client.t,exports.decodeClientMessage=require_encode.i,exports.decodeFrame=require_encode.a,exports.decodeServerMessage=require_encode.o,exports.encodeClientMessage=require_encode.t,exports.encodeFrame=require_encode.n,exports.encodeServerMessage=require_encode.r;
package/dist/client.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as DEFAULT_RECONNECTION_CONFIG, i as ConnectionState, n as VeraniClientOptions, o as ReconnectionConfig, r as ConnectionManager, t as VeraniClient } from "./client-C3BlxAY_.cjs";
2
- import { a as ServerMessage, i as PROTOCOL_VERSION, o as VeraniMessage, t as ClientMessage } from "./types-DOI6EHQJ.cjs";
3
- import { a as encodeFrame, i as encodeClientMessage, n as decodeFrame, o as encodeServerMessage, r as decodeServerMessage, t as decodeClientMessage } from "./decode--RaAAv0U.cjs";
1
+ import { a as DEFAULT_RECONNECTION_CONFIG, i as ConnectionState, n as VeraniClientOptions, o as ReconnectionConfig, r as ConnectionManager, t as VeraniClient } from "./client-JCkzlxJL.cjs";
2
+ import { a as ServerMessage, i as PROTOCOL_VERSION, o as VeraniMessage, t as ClientMessage } from "./types-DIIeb2YQ.cjs";
3
+ import { a as encodeFrame, i as encodeClientMessage, n as decodeFrame, o as encodeServerMessage, r as decodeServerMessage, t as decodeClientMessage } from "./decode-otE_3S_-.cjs";
4
4
  export { type ClientMessage, ConnectionManager, type ConnectionState, DEFAULT_RECONNECTION_CONFIG, PROTOCOL_VERSION, type ReconnectionConfig, type ServerMessage, VeraniClient, type VeraniClientOptions, type VeraniMessage, decodeClientMessage, decodeFrame, decodeServerMessage, encodeClientMessage, encodeFrame, encodeServerMessage };
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as DEFAULT_RECONNECTION_CONFIG, i as ConnectionState, n as VeraniClientOptions, o as ReconnectionConfig, r as ConnectionManager, t as VeraniClient } from "./client-CV5RrpZX.mjs";
2
- import { a as ServerMessage, i as PROTOCOL_VERSION, o as VeraniMessage, t as ClientMessage } from "./types-_41fL9Dn.mjs";
3
- import { a as encodeFrame, i as encodeClientMessage, n as decodeFrame, o as encodeServerMessage, r as decodeServerMessage, t as decodeClientMessage } from "./decode-BUzd77kA.mjs";
1
+ import { a as DEFAULT_RECONNECTION_CONFIG, i as ConnectionState, n as VeraniClientOptions, o as ReconnectionConfig, r as ConnectionManager, t as VeraniClient } from "./client-D7P17bMd.mjs";
2
+ import { a as ServerMessage, i as PROTOCOL_VERSION, o as VeraniMessage, t as ClientMessage } from "./types-6m1L8QLb.mjs";
3
+ import { a as encodeFrame, i as encodeClientMessage, n as decodeFrame, o as encodeServerMessage, r as decodeServerMessage, t as decodeClientMessage } from "./decode-DwdLTFvb.mjs";
4
4
  export { type ClientMessage, ConnectionManager, type ConnectionState, DEFAULT_RECONNECTION_CONFIG, PROTOCOL_VERSION, type ReconnectionConfig, type ServerMessage, VeraniClient, type VeraniClientOptions, type VeraniMessage, decodeClientMessage, decodeFrame, decodeServerMessage, encodeClientMessage, encodeFrame, encodeServerMessage };
package/dist/client.mjs CHANGED
@@ -1 +1 @@
1
- import{a as decodeFrame,i as decodeClientMessage,n as encodeFrame,o as decodeServerMessage,r as encodeServerMessage,t as encodeClientMessage}from"./encode-BhJqnsto.mjs";import{t as PROTOCOL_VERSION}from"./types-rZsftNPE.mjs";import{n as ConnectionManager,r as DEFAULT_RECONNECTION_CONFIG,t as VeraniClient}from"./client-DQnA1Oel.mjs";export{ConnectionManager,DEFAULT_RECONNECTION_CONFIG,PROTOCOL_VERSION,VeraniClient,decodeClientMessage,decodeFrame,decodeServerMessage,encodeClientMessage,encodeFrame,encodeServerMessage};
1
+ import{a as decodeFrame,i as decodeClientMessage,n as encodeFrame,o as decodeServerMessage,r as encodeServerMessage,t as encodeClientMessage}from"./encode-CFndA-BQ.mjs";import{t as PROTOCOL_VERSION}from"./types-rZsftNPE.mjs";import{n as ConnectionManager,r as DEFAULT_RECONNECTION_CONFIG,t as VeraniClient}from"./client-oy-w-Ky5.mjs";export{ConnectionManager,DEFAULT_RECONNECTION_CONFIG,PROTOCOL_VERSION,VeraniClient,decodeClientMessage,decodeFrame,decodeServerMessage,encodeClientMessage,encodeFrame,encodeServerMessage};
@@ -1,4 +1,4 @@
1
- import { r as MessageFrame } from "./types-DOI6EHQJ.cjs";
1
+ import { r as MessageFrame, s as WebSocketRawData } from "./types-6m1L8QLb.mjs";
2
2
 
3
3
  //#region src/shared/encode.d.ts
4
4
 
@@ -37,7 +37,7 @@ declare function encodeServerMessage(message: MessageFrame): string;
37
37
  * @param raw - Raw data from WebSocket (string, ArrayBuffer, etc)
38
38
  * @returns Decoded MessageFrame or null if parsing or validation fails
39
39
  */
40
- declare function decodeFrame(raw: any): MessageFrame | null;
40
+ declare function decodeFrame(raw: WebSocketRawData): MessageFrame | null;
41
41
  /**
42
42
  * Decodes a client message.
43
43
  * Alias for decodeFrame, provided for semantic clarity when decoding client messages.
@@ -45,7 +45,7 @@ declare function decodeFrame(raw: any): MessageFrame | null;
45
45
  * @param raw - Raw data from client WebSocket
46
46
  * @returns Decoded message or null if invalid
47
47
  */
48
- declare function decodeClientMessage(raw: any): MessageFrame | null;
48
+ declare function decodeClientMessage(raw: WebSocketRawData): MessageFrame | null;
49
49
  /**
50
50
  * Decodes a server message.
51
51
  * Alias for decodeFrame, provided for semantic clarity when decoding server messages.
@@ -53,6 +53,6 @@ declare function decodeClientMessage(raw: any): MessageFrame | null;
53
53
  * @param raw - Raw data from server WebSocket
54
54
  * @returns Decoded message or null if invalid
55
55
  */
56
- declare function decodeServerMessage(raw: any): MessageFrame | null;
56
+ declare function decodeServerMessage(raw: WebSocketRawData): MessageFrame | null;
57
57
  //#endregion
58
58
  export { encodeFrame as a, encodeClientMessage as i, decodeFrame as n, encodeServerMessage as o, decodeServerMessage as r, decodeClientMessage as t };
@@ -1,4 +1,4 @@
1
- import { r as MessageFrame } from "./types-_41fL9Dn.mjs";
1
+ import { r as MessageFrame, s as WebSocketRawData } from "./types-DIIeb2YQ.cjs";
2
2
 
3
3
  //#region src/shared/encode.d.ts
4
4
 
@@ -37,7 +37,7 @@ declare function encodeServerMessage(message: MessageFrame): string;
37
37
  * @param raw - Raw data from WebSocket (string, ArrayBuffer, etc)
38
38
  * @returns Decoded MessageFrame or null if parsing or validation fails
39
39
  */
40
- declare function decodeFrame(raw: any): MessageFrame | null;
40
+ declare function decodeFrame(raw: WebSocketRawData): MessageFrame | null;
41
41
  /**
42
42
  * Decodes a client message.
43
43
  * Alias for decodeFrame, provided for semantic clarity when decoding client messages.
@@ -45,7 +45,7 @@ declare function decodeFrame(raw: any): MessageFrame | null;
45
45
  * @param raw - Raw data from client WebSocket
46
46
  * @returns Decoded message or null if invalid
47
47
  */
48
- declare function decodeClientMessage(raw: any): MessageFrame | null;
48
+ declare function decodeClientMessage(raw: WebSocketRawData): MessageFrame | null;
49
49
  /**
50
50
  * Decodes a server message.
51
51
  * Alias for decodeFrame, provided for semantic clarity when decoding server messages.
@@ -53,6 +53,6 @@ declare function decodeClientMessage(raw: any): MessageFrame | null;
53
53
  * @param raw - Raw data from server WebSocket
54
54
  * @returns Decoded message or null if invalid
55
55
  */
56
- declare function decodeServerMessage(raw: any): MessageFrame | null;
56
+ declare function decodeServerMessage(raw: WebSocketRawData): MessageFrame | null;
57
57
  //#endregion
58
58
  export { encodeFrame as a, encodeClientMessage as i, decodeFrame as n, encodeServerMessage as o, decodeServerMessage as r, decodeClientMessage as t };