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.
- package/README.md +153 -189
- package/dist/actor-runtime-83AF97II.mjs +1 -0
- package/dist/{actor-runtime-BOmyu8Vl.d.mts → actor-runtime-BqF6_7z_.d.mts} +201 -2
- package/dist/actor-runtime-CCoZUVrQ.cjs +1 -0
- package/dist/{actor-runtime-1TpQk-wg.d.cts → actor-runtime-gFDsFVsU.d.cts} +201 -2
- package/dist/client-C3K_PiKE.cjs +1 -0
- package/dist/client-DQnA1Oel.mjs +1 -0
- package/dist/client.cjs +1 -1
- package/dist/client.mjs +1 -1
- package/dist/typed-client.cjs +1 -1
- package/dist/typed-client.mjs +1 -1
- package/dist/typed.cjs +1 -1
- package/dist/typed.d.cts +1 -1
- package/dist/typed.d.mts +1 -1
- package/dist/typed.mjs +1 -1
- package/dist/verani.cjs +1 -1
- package/dist/verani.d.cts +213 -2
- package/dist/verani.d.mts +213 -2
- package/dist/verani.mjs +1 -1
- package/package.json +2 -1
- package/dist/actor-runtime-Fr0n1XGB.cjs +0 -1
- package/dist/actor-runtime-mfMYeKoB.mjs +0 -1
- package/dist/client-oItOePHL.mjs +0 -1
- package/dist/client-ofEyep6Z.cjs +0 -1
|
@@ -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,
|
|
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,
|
|
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-
|
|
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-
|
|
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};
|
package/dist/typed-client.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./encode-BYFW_6TI.cjs`);const require_client=require(`./client-
|
|
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;
|
package/dist/typed-client.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./encode-BhJqnsto.mjs";import{t as VeraniClient}from"./client-
|
|
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-
|
|
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 {
|
|
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 {
|
|
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
|
|