verani 0.8.2 → 0.9.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.
@@ -103,8 +103,10 @@ declare function clearPersistedState(actor: PersistableActor): Promise<void>;
103
103
  * Options for broadcasting messages to connections
104
104
  */
105
105
  interface BroadcastOptions {
106
- /** Exclude specific WebSocket from receiving the broadcast */
106
+ /** Exclude specific WebSocket from receiving the broadcast (local only) */
107
107
  except?: WebSocket;
108
+ /** Exclude a specific userId from receiving the broadcast (RPC-safe) */
109
+ exceptUserId?: string;
108
110
  /** Only send to specific user IDs */
109
111
  userIds?: string[];
110
112
  /** Only send to specific client IDs */
@@ -115,11 +117,104 @@ interface BroadcastOptions {
115
117
  * Excludes the `except` field since WebSocket cannot be serialized over RPC.
116
118
  */
117
119
  interface RpcBroadcastOptions {
120
+ /** Exclude a specific userId from receiving the broadcast */
121
+ exceptUserId?: string;
118
122
  /** Only send to specific user IDs */
119
123
  userIds?: string[];
120
124
  /** Only send to specific client IDs */
121
125
  clientIds?: string[];
122
126
  }
127
+ /**
128
+ * Represents a member in a RoomDO
129
+ */
130
+ interface RoomMember {
131
+ /** The user's unique identifier */
132
+ userId: string;
133
+ /** Timestamp when the user joined this room */
134
+ joinedAt: number;
135
+ /** Optional metadata associated with this member */
136
+ metadata?: Record<string, unknown>;
137
+ }
138
+ /**
139
+ * Definition for creating a RoomDO (coordination Durable Object)
140
+ *
141
+ * RoomDOs manage room membership and coordinate message delivery between
142
+ * ConnectionDOs. They do NOT hold WebSocket connections directly.
143
+ */
144
+ interface RoomCoordinatorDefinition<E = unknown> {
145
+ /** Optional room name for debugging */
146
+ name?: string;
147
+ /**
148
+ * Called when the RoomDO initializes or wakes from hibernation
149
+ */
150
+ onInit?(roomState: Record<string, unknown>): void | Promise<void>;
151
+ /**
152
+ * Called when a user joins this room
153
+ */
154
+ onJoin?(roomState: Record<string, unknown>, userId: string, metadata?: Record<string, unknown>): void | Promise<void>;
155
+ /**
156
+ * Called when a user leaves this room
157
+ */
158
+ onLeave?(roomState: Record<string, unknown>, userId: string): void | Promise<void>;
159
+ }
160
+ /**
161
+ * Stub interface for ConnectionDO - supports RPC calls from other DOs
162
+ *
163
+ * ConnectionDOs own a single WebSocket connection and receive messages
164
+ * from RoomDOs via RPC for delivery to their connected client.
165
+ */
166
+ interface ConnectionActorStub {
167
+ /**
168
+ * Standard fetch method for handling HTTP requests and WebSocket upgrades
169
+ */
170
+ fetch(request: Request): Promise<Response>;
171
+ /**
172
+ * Deliver a message to this connection's WebSocket (called via RPC from RoomDO)
173
+ * @param event - Event name
174
+ * @param data - Event data
175
+ * @returns Promise resolving to true if delivered, false if connection is closed
176
+ */
177
+ deliverMessage(event: string, data?: any): Promise<boolean>;
178
+ /**
179
+ * Deliver a system event to this connection (presence updates, room events, etc.)
180
+ * @param type - System event type
181
+ * @param payload - Event payload
182
+ */
183
+ deliverSystemEvent(type: string, payload?: any): Promise<void>;
184
+ /**
185
+ * Get the userId this connection belongs to
186
+ */
187
+ getUserId(): Promise<string | null>;
188
+ /**
189
+ * Check if this connection is still active
190
+ */
191
+ isConnected(): Promise<boolean>;
192
+ /**
193
+ * Join a room (registers with the RoomDO)
194
+ * @param roomName - Name of the room to join
195
+ * @param metadata - Optional metadata to include with membership
196
+ */
197
+ joinRoom(roomName: string, metadata?: Record<string, unknown>): Promise<void>;
198
+ /**
199
+ * Leave a room (unregisters from the RoomDO)
200
+ * @param roomName - Name of the room to leave
201
+ */
202
+ leaveRoom(roomName: string): Promise<void>;
203
+ /**
204
+ * Get list of rooms this connection is a member of
205
+ */
206
+ getRooms(): Promise<string[]>;
207
+ }
208
+ /**
209
+ * Environment type with Durable Object bindings for Verani
210
+ * Users should extend this with their own bindings
211
+ */
212
+ interface VeraniEnv {
213
+ /** ConnectionDO binding - required for per-user connection routing */
214
+ CONNECTION_DO?: DurableObjectNamespace;
215
+ /** RoomDO binding - required for room coordination */
216
+ ROOM_DO?: DurableObjectNamespace;
217
+ }
123
218
  /**
124
219
  * Actor stub interface returned by .get() method.
125
220
  * Provides RPC access to actor methods that can be called remotely.
@@ -127,6 +222,8 @@ interface RpcBroadcastOptions {
127
222
  * Note: RPC methods return Promises even if the underlying method is synchronous.
128
223
  * Methods that return non-serializable types (like WebSocket[] or DurableObjectStorage)
129
224
  * are excluded from this interface.
225
+ *
226
+ * @deprecated Use ConnectionActorStub for per-connection DOs in the new architecture
130
227
  */
131
228
  interface ActorStub {
132
229
  /**
@@ -265,6 +362,101 @@ interface VeraniActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
265
362
  */
266
363
  emit: ActorEmit<TMeta, E>;
267
364
  }
365
+ /**
366
+ * ConnectionActor interface for single-WebSocket-per-DO model
367
+ *
368
+ * Unlike VeraniActor which holds multiple sessions, ConnectionActor owns
369
+ * exactly one WebSocket connection for a single user.
370
+ */
371
+ interface ConnectionActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>> extends Actor<E> {
372
+ /**
373
+ * The single WebSocket connection owned by this DO (null if not connected)
374
+ */
375
+ ws: WebSocket | null;
376
+ /**
377
+ * Connection metadata for this user
378
+ */
379
+ meta: TMeta | null;
380
+ /**
381
+ * Set of room names this connection is a member of
382
+ */
383
+ rooms: Set<string>;
384
+ /**
385
+ * User-defined persisted state for this connection actor
386
+ */
387
+ connectionState: TState;
388
+ /**
389
+ * Check if this connection has an active WebSocket
390
+ */
391
+ isConnected(): boolean;
392
+ /**
393
+ * Deliver a message to this connection's WebSocket
394
+ * Called via RPC from RoomDO
395
+ */
396
+ deliverMessage(event: string, data?: any): Promise<boolean>;
397
+ /**
398
+ * Deliver a system event (presence, room events, etc.)
399
+ */
400
+ deliverSystemEvent(type: string, payload?: any): Promise<void>;
401
+ /**
402
+ * Join a room (register with RoomDO)
403
+ */
404
+ joinRoom(roomName: string, metadata?: Record<string, unknown>): Promise<void>;
405
+ /**
406
+ * Leave a room (unregister from RoomDO)
407
+ */
408
+ leaveRoom(roomName: string): Promise<void>;
409
+ /**
410
+ * Socket.io-like emit API for this connection
411
+ */
412
+ emit: ConnectionEmit<TMeta, E>;
413
+ /**
414
+ * Access the Durable Object storage API
415
+ */
416
+ getStorage(): DurableObjectStorage;
417
+ }
418
+ /**
419
+ * Connection-level emit API (for single-connection DO)
420
+ * Routes to appropriate RoomDO or ConnectionDO via RPC
421
+ */
422
+ interface ConnectionEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown> {
423
+ /**
424
+ * Emit to this connection's WebSocket
425
+ * @param event - Event name
426
+ * @param data - Event data
427
+ */
428
+ emit(event: string, data?: any): void;
429
+ /**
430
+ * Target a specific room or user for emitting
431
+ * @param target - Room name (if starts with "room:") or userId
432
+ * @returns Builder for emitting to the target via RPC
433
+ */
434
+ to(target: string): AsyncEmitBuilder;
435
+ /**
436
+ * Target a specific room for broadcasting
437
+ * @param roomName - Room name
438
+ * @returns Builder for broadcasting to the room via RPC
439
+ */
440
+ toRoom(roomName: string): AsyncEmitBuilder;
441
+ /**
442
+ * Target a specific user for direct messaging
443
+ * @param userId - User ID
444
+ * @returns Builder for sending to the user via RPC
445
+ */
446
+ toUser(userId: string): AsyncEmitBuilder;
447
+ }
448
+ /**
449
+ * Async emit builder for RPC-based emit operations
450
+ */
451
+ interface AsyncEmitBuilder {
452
+ /**
453
+ * Emit to the targeted scope via RPC
454
+ * @param event - Event name
455
+ * @param data - Event data
456
+ * @returns Promise resolving to number of recipients
457
+ */
458
+ emit(event: string, data?: any): Promise<number>;
459
+ }
268
460
  /**
269
461
  * Event handler function type for socket.io-like event handling
270
462
  */
@@ -292,6 +484,13 @@ interface RoomEventEmitter<TMeta extends ConnectionMeta = ConnectionMeta, E = un
292
484
  * @param data - Event data
293
485
  */
294
486
  emit(event: string, ctx: MessageContext<TMeta, E, TState>, data: any): Promise<void>;
487
+ /**
488
+ * Check if there are any handlers registered for a given event.
489
+ * Returns true if handlers exist for the specific event or for the wildcard "*" event.
490
+ * @param event - Event name to check
491
+ * @returns True if handlers exist for the event or wildcard, false otherwise
492
+ */
493
+ hasHandlers(event: string): boolean;
295
494
  /**
296
495
  * Rebuild handlers from static storage.
297
496
  * Called after hibernation to restore handlers from the room definition.
@@ -494,4 +693,4 @@ type ActorHandlerClass<E = unknown> = {
494
693
  */
495
694
  declare function createActorHandler<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>>(room: RoomDefinition<TMeta, E, TState>): ActorHandlerClass<E>;
496
695
  //#endregion
497
- export { safeSerialize as C, safeDeserialize as S, getPersistedKeys as _, EventHandler as a, isStateReady as b, RoomDefinition as c, PersistError as d, PersistNotReadyError as f, deletePersistedKey as g, clearPersistedState as h, BroadcastOptions as i, RpcBroadcastOptions as l, SafePersistOptions as m, createActorHandler as n, MessageContext as o, PersistableActor as p, ActorStub as r, RoomContext as s, ActorHandlerClass as t, VeraniActor as u, getPersistedState as v, setPeristErrorHandler as w, persistKey as x, initializePersistedState as y };
696
+ export { safeSerialize as A, deletePersistedKey as C, isStateReady as D, initializePersistedState as E, persistKey as O, clearPersistedState as S, getPersistedState as T, VeraniEnv as _, BroadcastOptions as a, PersistableActor as b, ConnectionEmit as c, RoomContext as d, RoomCoordinatorDefinition as f, VeraniActor as g, RpcBroadcastOptions as h, AsyncEmitBuilder as i, setPeristErrorHandler as j, safeDeserialize as k, EventHandler as l, RoomMember as m, createActorHandler as n, ConnectionActor as o, RoomDefinition as p, ActorStub as r, ConnectionActorStub as s, ActorHandlerClass as t, MessageContext as u, PersistError as v, getPersistedKeys as w, SafePersistOptions as x, PersistNotReadyError as y };
@@ -0,0 +1 @@
1
+ const require_encode=require(`./encode-BYFW_6TI.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);function isValidConnectionMeta(s){return!(!s||typeof s!=`object`||typeof s.userId!=`string`||!s.userId||typeof s.clientId!=`string`||!s.clientId||!Array.isArray(s.channels)||!s.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}s.sessions.set(I,{ws:I,meta:L}),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}});
@@ -103,8 +103,10 @@ declare function clearPersistedState(actor: PersistableActor): Promise<void>;
103
103
  * Options for broadcasting messages to connections
104
104
  */
105
105
  interface BroadcastOptions {
106
- /** Exclude specific WebSocket from receiving the broadcast */
106
+ /** Exclude specific WebSocket from receiving the broadcast (local only) */
107
107
  except?: WebSocket;
108
+ /** Exclude a specific userId from receiving the broadcast (RPC-safe) */
109
+ exceptUserId?: string;
108
110
  /** Only send to specific user IDs */
109
111
  userIds?: string[];
110
112
  /** Only send to specific client IDs */
@@ -115,11 +117,104 @@ interface BroadcastOptions {
115
117
  * Excludes the `except` field since WebSocket cannot be serialized over RPC.
116
118
  */
117
119
  interface RpcBroadcastOptions {
120
+ /** Exclude a specific userId from receiving the broadcast */
121
+ exceptUserId?: string;
118
122
  /** Only send to specific user IDs */
119
123
  userIds?: string[];
120
124
  /** Only send to specific client IDs */
121
125
  clientIds?: string[];
122
126
  }
127
+ /**
128
+ * Represents a member in a RoomDO
129
+ */
130
+ interface RoomMember {
131
+ /** The user's unique identifier */
132
+ userId: string;
133
+ /** Timestamp when the user joined this room */
134
+ joinedAt: number;
135
+ /** Optional metadata associated with this member */
136
+ metadata?: Record<string, unknown>;
137
+ }
138
+ /**
139
+ * Definition for creating a RoomDO (coordination Durable Object)
140
+ *
141
+ * RoomDOs manage room membership and coordinate message delivery between
142
+ * ConnectionDOs. They do NOT hold WebSocket connections directly.
143
+ */
144
+ interface RoomCoordinatorDefinition<E = unknown> {
145
+ /** Optional room name for debugging */
146
+ name?: string;
147
+ /**
148
+ * Called when the RoomDO initializes or wakes from hibernation
149
+ */
150
+ onInit?(roomState: Record<string, unknown>): void | Promise<void>;
151
+ /**
152
+ * Called when a user joins this room
153
+ */
154
+ onJoin?(roomState: Record<string, unknown>, userId: string, metadata?: Record<string, unknown>): void | Promise<void>;
155
+ /**
156
+ * Called when a user leaves this room
157
+ */
158
+ onLeave?(roomState: Record<string, unknown>, userId: string): void | Promise<void>;
159
+ }
160
+ /**
161
+ * Stub interface for ConnectionDO - supports RPC calls from other DOs
162
+ *
163
+ * ConnectionDOs own a single WebSocket connection and receive messages
164
+ * from RoomDOs via RPC for delivery to their connected client.
165
+ */
166
+ interface ConnectionActorStub {
167
+ /**
168
+ * Standard fetch method for handling HTTP requests and WebSocket upgrades
169
+ */
170
+ fetch(request: Request): Promise<Response>;
171
+ /**
172
+ * Deliver a message to this connection's WebSocket (called via RPC from RoomDO)
173
+ * @param event - Event name
174
+ * @param data - Event data
175
+ * @returns Promise resolving to true if delivered, false if connection is closed
176
+ */
177
+ deliverMessage(event: string, data?: any): Promise<boolean>;
178
+ /**
179
+ * Deliver a system event to this connection (presence updates, room events, etc.)
180
+ * @param type - System event type
181
+ * @param payload - Event payload
182
+ */
183
+ deliverSystemEvent(type: string, payload?: any): Promise<void>;
184
+ /**
185
+ * Get the userId this connection belongs to
186
+ */
187
+ getUserId(): Promise<string | null>;
188
+ /**
189
+ * Check if this connection is still active
190
+ */
191
+ isConnected(): Promise<boolean>;
192
+ /**
193
+ * Join a room (registers with the RoomDO)
194
+ * @param roomName - Name of the room to join
195
+ * @param metadata - Optional metadata to include with membership
196
+ */
197
+ joinRoom(roomName: string, metadata?: Record<string, unknown>): Promise<void>;
198
+ /**
199
+ * Leave a room (unregisters from the RoomDO)
200
+ * @param roomName - Name of the room to leave
201
+ */
202
+ leaveRoom(roomName: string): Promise<void>;
203
+ /**
204
+ * Get list of rooms this connection is a member of
205
+ */
206
+ getRooms(): Promise<string[]>;
207
+ }
208
+ /**
209
+ * Environment type with Durable Object bindings for Verani
210
+ * Users should extend this with their own bindings
211
+ */
212
+ interface VeraniEnv {
213
+ /** ConnectionDO binding - required for per-user connection routing */
214
+ CONNECTION_DO?: DurableObjectNamespace;
215
+ /** RoomDO binding - required for room coordination */
216
+ ROOM_DO?: DurableObjectNamespace;
217
+ }
123
218
  /**
124
219
  * Actor stub interface returned by .get() method.
125
220
  * Provides RPC access to actor methods that can be called remotely.
@@ -127,6 +222,8 @@ interface RpcBroadcastOptions {
127
222
  * Note: RPC methods return Promises even if the underlying method is synchronous.
128
223
  * Methods that return non-serializable types (like WebSocket[] or DurableObjectStorage)
129
224
  * are excluded from this interface.
225
+ *
226
+ * @deprecated Use ConnectionActorStub for per-connection DOs in the new architecture
130
227
  */
131
228
  interface ActorStub {
132
229
  /**
@@ -265,6 +362,101 @@ interface VeraniActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown
265
362
  */
266
363
  emit: ActorEmit<TMeta, E>;
267
364
  }
365
+ /**
366
+ * ConnectionActor interface for single-WebSocket-per-DO model
367
+ *
368
+ * Unlike VeraniActor which holds multiple sessions, ConnectionActor owns
369
+ * exactly one WebSocket connection for a single user.
370
+ */
371
+ interface ConnectionActor<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>> extends Actor<E> {
372
+ /**
373
+ * The single WebSocket connection owned by this DO (null if not connected)
374
+ */
375
+ ws: WebSocket | null;
376
+ /**
377
+ * Connection metadata for this user
378
+ */
379
+ meta: TMeta | null;
380
+ /**
381
+ * Set of room names this connection is a member of
382
+ */
383
+ rooms: Set<string>;
384
+ /**
385
+ * User-defined persisted state for this connection actor
386
+ */
387
+ connectionState: TState;
388
+ /**
389
+ * Check if this connection has an active WebSocket
390
+ */
391
+ isConnected(): boolean;
392
+ /**
393
+ * Deliver a message to this connection's WebSocket
394
+ * Called via RPC from RoomDO
395
+ */
396
+ deliverMessage(event: string, data?: any): Promise<boolean>;
397
+ /**
398
+ * Deliver a system event (presence, room events, etc.)
399
+ */
400
+ deliverSystemEvent(type: string, payload?: any): Promise<void>;
401
+ /**
402
+ * Join a room (register with RoomDO)
403
+ */
404
+ joinRoom(roomName: string, metadata?: Record<string, unknown>): Promise<void>;
405
+ /**
406
+ * Leave a room (unregister from RoomDO)
407
+ */
408
+ leaveRoom(roomName: string): Promise<void>;
409
+ /**
410
+ * Socket.io-like emit API for this connection
411
+ */
412
+ emit: ConnectionEmit<TMeta, E>;
413
+ /**
414
+ * Access the Durable Object storage API
415
+ */
416
+ getStorage(): DurableObjectStorage;
417
+ }
418
+ /**
419
+ * Connection-level emit API (for single-connection DO)
420
+ * Routes to appropriate RoomDO or ConnectionDO via RPC
421
+ */
422
+ interface ConnectionEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown> {
423
+ /**
424
+ * Emit to this connection's WebSocket
425
+ * @param event - Event name
426
+ * @param data - Event data
427
+ */
428
+ emit(event: string, data?: any): void;
429
+ /**
430
+ * Target a specific room or user for emitting
431
+ * @param target - Room name (if starts with "room:") or userId
432
+ * @returns Builder for emitting to the target via RPC
433
+ */
434
+ to(target: string): AsyncEmitBuilder;
435
+ /**
436
+ * Target a specific room for broadcasting
437
+ * @param roomName - Room name
438
+ * @returns Builder for broadcasting to the room via RPC
439
+ */
440
+ toRoom(roomName: string): AsyncEmitBuilder;
441
+ /**
442
+ * Target a specific user for direct messaging
443
+ * @param userId - User ID
444
+ * @returns Builder for sending to the user via RPC
445
+ */
446
+ toUser(userId: string): AsyncEmitBuilder;
447
+ }
448
+ /**
449
+ * Async emit builder for RPC-based emit operations
450
+ */
451
+ interface AsyncEmitBuilder {
452
+ /**
453
+ * Emit to the targeted scope via RPC
454
+ * @param event - Event name
455
+ * @param data - Event data
456
+ * @returns Promise resolving to number of recipients
457
+ */
458
+ emit(event: string, data?: any): Promise<number>;
459
+ }
268
460
  /**
269
461
  * Event handler function type for socket.io-like event handling
270
462
  */
@@ -292,6 +484,13 @@ interface RoomEventEmitter<TMeta extends ConnectionMeta = ConnectionMeta, E = un
292
484
  * @param data - Event data
293
485
  */
294
486
  emit(event: string, ctx: MessageContext<TMeta, E, TState>, data: any): Promise<void>;
487
+ /**
488
+ * Check if there are any handlers registered for a given event.
489
+ * Returns true if handlers exist for the specific event or for the wildcard "*" event.
490
+ * @param event - Event name to check
491
+ * @returns True if handlers exist for the event or wildcard, false otherwise
492
+ */
493
+ hasHandlers(event: string): boolean;
295
494
  /**
296
495
  * Rebuild handlers from static storage.
297
496
  * Called after hibernation to restore handlers from the room definition.
@@ -494,4 +693,4 @@ type ActorHandlerClass<E = unknown> = {
494
693
  */
495
694
  declare function createActorHandler<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>>(room: RoomDefinition<TMeta, E, TState>): ActorHandlerClass<E>;
496
695
  //#endregion
497
- export { safeSerialize as C, safeDeserialize as S, getPersistedKeys as _, EventHandler as a, isStateReady as b, RoomDefinition as c, PersistError as d, PersistNotReadyError as f, deletePersistedKey as g, clearPersistedState as h, BroadcastOptions as i, RpcBroadcastOptions as l, SafePersistOptions as m, createActorHandler as n, MessageContext as o, PersistableActor as p, ActorStub as r, RoomContext as s, ActorHandlerClass as t, VeraniActor as u, getPersistedState as v, setPeristErrorHandler as w, persistKey as x, initializePersistedState as y };
696
+ export { safeSerialize as A, deletePersistedKey as C, isStateReady as D, initializePersistedState as E, persistKey as O, clearPersistedState as S, getPersistedState as T, VeraniEnv as _, BroadcastOptions as a, PersistableActor as b, ConnectionEmit as c, RoomContext as d, RoomCoordinatorDefinition as f, VeraniActor as g, RpcBroadcastOptions as h, AsyncEmitBuilder as i, setPeristErrorHandler as j, safeDeserialize as k, EventHandler as l, RoomMember as m, createActorHandler as n, ConnectionActor as o, RoomDefinition as p, ActorStub as r, ConnectionActorStub as s, ActorHandlerClass as t, MessageContext as u, PersistError as v, getPersistedKeys as w, SafePersistOptions as x, PersistNotReadyError as y };
@@ -0,0 +1 @@
1
+ const require_encode=require(`./encode-BYFW_6TI.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;f.type===`event`&&f.data&&typeof f.data==`object`&&`type`in f.data&&(p=f.data.type,m=f.data),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}});
@@ -0,0 +1 @@
1
+ import{o as decodeServerMessage$1,t as encodeClientMessage$1}from"./encode-BhJqnsto.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;p.type===`event`&&p.data&&typeof p.data==`object`&&`type`in p.data&&(m=p.data.type,h=p.data),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-ofEyep6Z.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-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;
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-oItOePHL.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-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 +1 @@
1
- require(`./encode-BYFW_6TI.cjs`);const require_client=require(`./client-ofEyep6Z.cjs`),require_validation=require(`./validation-DvWPGkXK.cjs`);function createTypedClient(n,r,i){let a=new require_client.t(r,i),o=new Map,s=require_validation.o(n),c=s?require_validation.a(n):void 0;return{on(e,r){o.has(e)||o.set(e,new Map);let i=i=>{if(s){let a=require_validation.i(n,e);if(a){let n=require_validation.s(a,i,e,`server`,c);if(n===void 0)return;r(n);return}}r(i)};return o.get(e).set(r,i),a.on(e,i),()=>{let t=o.get(e),n=t?.get(r);n&&(a.off(e,n),t?.delete(r))}},off(e,t){let n=o.get(e),r=n?.get(t);r&&(a.off(e,r),n?.delete(t))},once(e,t){a.once(e,e=>{t(e)})},emit(e,t){a.emit(e,t)},onOpen(e){a.onOpen(e)},onClose(e){a.onClose(e)},onError(e){a.onError(e)},onStateChange(e){a.onStateChange(e)},getState(){return a.getState()},isConnected(){return a.isConnected()},get isConnecting(){return a.isConnecting},getConnectionState(){return a.getConnectionState()},waitForConnection(){return a.waitForConnection()},reconnect(){a.reconnect()},disconnect(){a.disconnect()},close(){a.close(),o.clear()},get _client(){return a},contract:n}}exports.createTypedClient=createTypedClient,exports.createValidatedListener=require_validation.n,exports.defineContract=require_validation.l,exports.getServerValidator=require_validation.i,exports.isContract=require_validation.u,exports.isValidatedContract=require_validation.o,exports.payload=require_validation.d,exports.validateData=require_validation.s,exports.withValidation=require_validation.c;
1
+ require(`./encode-BYFW_6TI.cjs`);const require_client=require(`./client-C3K_PiKE.cjs`),require_validation=require(`./validation-DvWPGkXK.cjs`);function createTypedClient(n,r,i){let a=new require_client.t(r,i),o=new Map,s=require_validation.o(n),c=s?require_validation.a(n):void 0;return{on(e,r){o.has(e)||o.set(e,new Map);let i=i=>{if(s){let a=require_validation.i(n,e);if(a){let n=require_validation.s(a,i,e,`server`,c);if(n===void 0)return;r(n);return}}r(i)};return o.get(e).set(r,i),a.on(e,i),()=>{let t=o.get(e),n=t?.get(r);n&&(a.off(e,n),t?.delete(r))}},off(e,t){let n=o.get(e),r=n?.get(t);r&&(a.off(e,r),n?.delete(t))},once(e,t){a.once(e,e=>{t(e)})},emit(e,t){a.emit(e,t)},onOpen(e){a.onOpen(e)},onClose(e){a.onClose(e)},onError(e){a.onError(e)},onStateChange(e){a.onStateChange(e)},getState(){return a.getState()},isConnected(){return a.isConnected()},get isConnecting(){return a.isConnecting},getConnectionState(){return a.getConnectionState()},waitForConnection(){return a.waitForConnection()},reconnect(){a.reconnect()},disconnect(){a.disconnect()},close(){a.close(),o.clear()},get _client(){return a},contract:n}}exports.createTypedClient=createTypedClient,exports.createValidatedListener=require_validation.n,exports.defineContract=require_validation.l,exports.getServerValidator=require_validation.i,exports.isContract=require_validation.u,exports.isValidatedContract=require_validation.o,exports.payload=require_validation.d,exports.validateData=require_validation.s,exports.withValidation=require_validation.c;
@@ -1 +1 @@
1
- import"./encode-BhJqnsto.mjs";import{t as VeraniClient}from"./client-oItOePHL.mjs";import{a as getValidationErrorHandler,c as withValidation,d as payload,i as getServerValidator,l as defineContract,n as createValidatedListener,o as isValidatedContract,s as validateData,u as isContract}from"./validation-NB7a2Sf1.mjs";function createTypedClient(a,o,s){let c=new VeraniClient(o,s),l=new Map,u=isValidatedContract(a),d=u?getValidationErrorHandler(a):void 0;return{on(e,i){l.has(e)||l.set(e,new Map);let o=o=>{if(u){let s=getServerValidator(a,e);if(s){let a=validateData(s,o,e,`server`,d);if(a===void 0)return;i(a);return}}i(o)};return l.get(e).set(i,o),c.on(e,o),()=>{let a=l.get(e),o=a?.get(i);o&&(c.off(e,o),a?.delete(i))}},off(e,i){let a=l.get(e),o=a?.get(i);o&&(c.off(e,o),a?.delete(i))},once(e,i){c.once(e,e=>{i(e)})},emit(e,i){c.emit(e,i)},onOpen(e){c.onOpen(e)},onClose(e){c.onClose(e)},onError(e){c.onError(e)},onStateChange(e){c.onStateChange(e)},getState(){return c.getState()},isConnected(){return c.isConnected()},get isConnecting(){return c.isConnecting},getConnectionState(){return c.getConnectionState()},waitForConnection(){return c.waitForConnection()},reconnect(){c.reconnect()},disconnect(){c.disconnect()},close(){c.close(),l.clear()},get _client(){return c},contract:a}}export{createTypedClient,createValidatedListener,defineContract,getServerValidator,isContract,isValidatedContract,payload,validateData,withValidation};
1
+ import"./encode-BhJqnsto.mjs";import{t as VeraniClient}from"./client-DQnA1Oel.mjs";import{a as getValidationErrorHandler,c as withValidation,d as payload,i as getServerValidator,l as defineContract,n as createValidatedListener,o as isValidatedContract,s as validateData,u as isContract}from"./validation-NB7a2Sf1.mjs";function createTypedClient(a,o,s){let c=new VeraniClient(o,s),l=new Map,u=isValidatedContract(a),d=u?getValidationErrorHandler(a):void 0;return{on(e,i){l.has(e)||l.set(e,new Map);let o=o=>{if(u){let s=getServerValidator(a,e);if(s){let a=validateData(s,o,e,`server`,d);if(a===void 0)return;i(a);return}}i(o)};return l.get(e).set(i,o),c.on(e,o),()=>{let a=l.get(e),o=a?.get(i);o&&(c.off(e,o),a?.delete(i))}},off(e,i){let a=l.get(e),o=a?.get(i);o&&(c.off(e,o),a?.delete(i))},once(e,i){c.once(e,e=>{i(e)})},emit(e,i){c.emit(e,i)},onOpen(e){c.onOpen(e)},onClose(e){c.onClose(e)},onError(e){c.onError(e)},onStateChange(e){c.onStateChange(e)},getState(){return c.getState()},isConnected(){return c.isConnected()},get isConnecting(){return c.isConnecting},getConnectionState(){return c.getConnectionState()},waitForConnection(){return c.waitForConnection()},reconnect(){c.reconnect()},disconnect(){c.disconnect()},close(){c.close(),l.clear()},get _client(){return c},contract:a}}export{createTypedClient,createValidatedListener,defineContract,getServerValidator,isContract,isValidatedContract,payload,validateData,withValidation};
package/dist/typed.cjs CHANGED
@@ -1 +1 @@
1
- const require_actor_runtime=require(`./actor-runtime-Fr0n1XGB.cjs`);require(`./encode-BYFW_6TI.cjs`);const require_validation=require(`./validation-DvWPGkXK.cjs`);function createTypedSocketEmit(e){let n=((n,r)=>{e.emit(n,r)});return n.to=n=>{let r=e.to(n);return{emit:(e,n)=>r.emit(e,n)}},n}function createTypedActorEmit(e){let n=((n,r)=>e.emit.emit(n,r));return n.to=n=>{let r=e.emit.to(n);return{emit:(e,n)=>r.emit(e,n)}},n}function wrapContext(e){return{actor:Object.assign({},e.actor,{emit:createTypedActorEmit(e.actor)}),ws:e.ws,meta:e.meta,emit:createTypedSocketEmit(e.emit)}}function wrapMessageContext(e){return{...wrapContext(e),frame:e.frame}}function createTypedRoom(r,i){let o=require_actor_runtime.g({name:i.name,websocketPath:i.websocketPath??`/ws`,extractMeta:i.extractMeta,onConnect:i.onConnect?e=>i.onConnect(wrapContext(e)):void 0,onDisconnect:i.onDisconnect?e=>i.onDisconnect(wrapContext(e)):void 0,onError:i.onError?(e,n)=>i.onError(e,wrapContext(n)):void 0,onHibernationRestore:i.onHibernationRestore}),s=require_validation.o(r),c=s?require_validation.a(r):void 0;return{on(e,i){o.on(e,(a,o)=>{let l=wrapMessageContext(a);if(s){let a=require_validation.r(r,e);if(a){let r=require_validation.s(a,o,e,`client`,c);return r===void 0?void 0:i(l,r)}}return i(l,o)})},off(e,n){o.off(e)},get definition(){return o},contract:r}}exports.createActorHandler=require_actor_runtime.t,exports.createTypedRoom=createTypedRoom,exports.createValidatedHandler=require_validation.t,exports.defineContract=require_validation.l,exports.getClientValidator=require_validation.r,exports.getValidationErrorHandler=require_validation.a,exports.isContract=require_validation.u,exports.isValidatedContract=require_validation.o,exports.payload=require_validation.d,exports.validateData=require_validation.s,exports.withValidation=require_validation.c;
1
+ const require_actor_runtime=require(`./actor-runtime-CCoZUVrQ.cjs`);require(`./encode-BYFW_6TI.cjs`);const require_validation=require(`./validation-DvWPGkXK.cjs`);function createTypedSocketEmit(e){let n=((n,r)=>{e.emit(n,r)});return n.to=n=>{let r=e.to(n);return{emit:(e,n)=>r.emit(e,n)}},n}function createTypedActorEmit(e){let n=((n,r)=>e.emit.emit(n,r));return n.to=n=>{let r=e.emit.to(n);return{emit:(e,n)=>r.emit(e,n)}},n}function wrapContext(e){return{actor:Object.assign({},e.actor,{emit:createTypedActorEmit(e.actor)}),ws:e.ws,meta:e.meta,emit:createTypedSocketEmit(e.emit)}}function wrapMessageContext(e){return{...wrapContext(e),frame:e.frame}}function createTypedRoom(r,i){let o=require_actor_runtime.n({name:i.name,websocketPath:i.websocketPath??`/ws`,extractMeta:i.extractMeta,onConnect:i.onConnect?e=>i.onConnect(wrapContext(e)):void 0,onDisconnect:i.onDisconnect?e=>i.onDisconnect(wrapContext(e)):void 0,onError:i.onError?(e,n)=>i.onError(e,wrapContext(n)):void 0,onHibernationRestore:i.onHibernationRestore}),s=require_validation.o(r),c=s?require_validation.a(r):void 0;return{on(e,i){o.on(e,(a,o)=>{let l=wrapMessageContext(a);if(s){let a=require_validation.r(r,e);if(a){let r=require_validation.s(a,o,e,`client`,c);return r===void 0?void 0:i(l,r)}}return i(l,o)})},off(e,n){o.off(e)},get definition(){return o},contract:r}}exports.createActorHandler=require_actor_runtime.t,exports.createTypedRoom=createTypedRoom,exports.createValidatedHandler=require_validation.t,exports.defineContract=require_validation.l,exports.getClientValidator=require_validation.r,exports.getValidationErrorHandler=require_validation.a,exports.isContract=require_validation.u,exports.isValidatedContract=require_validation.o,exports.payload=require_validation.d,exports.validateData=require_validation.s,exports.withValidation=require_validation.c;
package/dist/typed.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as ConnectionMeta } from "./types-DOI6EHQJ.cjs";
2
2
  import { A as TypedServerEmit, B as payload, C as InferServerEvents, D as ServerPayloadMap, E as ServerPayload, F as EventPayloads, I as ExtractPayload, L as PayloadMarker, M as Contract, N as ContractDefinition, O as TypedClientEmit, P as EventMap, R as defineContract, S as InferClientEvents, T as ServerEventNames, _ as ClientEventHandler, a as ValidationResult, b as ClientPayloadMap, c as createValidatedHandler, f as getValidationErrorHandler, g as AllEventNames, h as withValidation, i as ValidationIssue, j as TypedServerListener, k as TypedClientListener, m as validateData, n as ValidationConfig, o as Validator, p as isValidatedContract, r as ValidationError, s as ValidatorMap, t as ValidatedContract, u as getClientValidator, v as ClientEventNames, w as ServerEventHandler, x as InferChannels, y as ClientPayload, z as isContract } from "./validation-Dw-KMz9Q.cjs";
3
- import { c as RoomDefinition, n as createActorHandler, r as ActorStub, u as VeraniActor } from "./actor-runtime-1TpQk-wg.cjs";
3
+ import { g as VeraniActor, n as createActorHandler, p as RoomDefinition, r as ActorStub } from "./actor-runtime-gFDsFVsU.cjs";
4
4
 
5
5
  //#region src/typed/server.d.ts
6
6
 
package/dist/typed.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as ConnectionMeta } from "./types-_41fL9Dn.mjs";
2
2
  import { A as TypedServerEmit, B as payload, C as InferServerEvents, D as ServerPayloadMap, E as ServerPayload, F as EventPayloads, I as ExtractPayload, L as PayloadMarker, M as Contract, N as ContractDefinition, O as TypedClientEmit, P as EventMap, R as defineContract, S as InferClientEvents, T as ServerEventNames, _ as ClientEventHandler, a as ValidationResult, b as ClientPayloadMap, c as createValidatedHandler, f as getValidationErrorHandler, g as AllEventNames, h as withValidation, i as ValidationIssue, j as TypedServerListener, k as TypedClientListener, m as validateData, n as ValidationConfig, o as Validator, p as isValidatedContract, r as ValidationError, s as ValidatorMap, t as ValidatedContract, u as getClientValidator, v as ClientEventNames, w as ServerEventHandler, x as InferChannels, y as ClientPayload, z as isContract } from "./validation-DCongzPL.mjs";
3
- import { c as RoomDefinition, n as createActorHandler, r as ActorStub, u as VeraniActor } from "./actor-runtime-BOmyu8Vl.mjs";
3
+ import { g as VeraniActor, n as createActorHandler, p as RoomDefinition, r as ActorStub } from "./actor-runtime-BqF6_7z_.mjs";
4
4
 
5
5
  //#region src/typed/server.d.ts
6
6