verani 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ import{n as encodeFrame$1}from"./encode-CFndA-BQ.mjs";import{Actor}from"@cloudflare/actors";function storeAttachment(e,f){e.serializeAttachment(f)}function encodeFrame(f){return encodeFrame$1(f)}const PERSIST_ERROR_HANDLER=Symbol(`PERSIST_ERROR_HANDLER`),PERSISTED_STATE=Symbol(`PERSISTED_STATE`),STATE_READY=Symbol(`STATE_READY`);var PersistNotReadyError=class extends Error{constructor(e){super(`Cannot access persisted state key "${e}" before storage is initialized. Wait for onInit to complete or check actor.isStateReady().`),this.name=`PersistNotReadyError`}},PersistError=class extends Error{constructor(e,f){super(`Failed to persist key "${e}": ${f.message}`),this.name=`PersistError`,this.originalCause=f}};function safeSerialize(e){let f=new WeakSet;return JSON.stringify(e,(e,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(f.has(p))return;f.add(p)}if(!(typeof p==`function`||typeof p==`symbol`))return p})}function safeDeserialize(e){return JSON.parse(e,(e,f)=>{if(f&&typeof f==`object`&&f.__type)switch(f.__type){case`Date`:return new Date(f.value);case`RegExp`:return new RegExp(f.source,f.flags);case`Map`:return new Map(f.entries);case`Set`:return new Set(f.values);case`Error`:{let e=Error(f.message);return e.name=f.name,e}}return f})}function createShallowProxy(e,f,p){return new Proxy(e,{set(e,p,m){let h=Reflect.set(e,p,m);return h&&typeof p==`string`&&f(p,m),h},deleteProperty(e,f){let m=Reflect.deleteProperty(e,f);return m&&typeof f==`string`&&p(f),m}})}async function initializePersistedState(e,f,p=[],m={}){let{shallow:v=!0,throwOnError:b=!0}=m,x=e.ctx.storage,S=p.length>0?p.map(String):Object.keys(f),C={...f};for(let e of S)try{let f=await x.get(`_verani_persist:${e}`);if(f!==void 0)try{C[e]=safeDeserialize(f)}catch(f){if(b)throw new PersistError(e,f)}}catch(f){if(b&&!(f instanceof PersistError))throw new PersistError(e,f)}let w=async(f,p)=>{if(S.includes(f))try{let e=safeSerialize(p);await x.put(`_verani_persist:${f}`,e)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},T=async f=>{if(S.includes(f))try{await x.delete(`_verani_persist:${f}`)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},E;return E=v?createShallowProxy(C,(e,f)=>{w(String(e),f)},e=>{T(String(e))}):createDeepProxy(C,(e,f)=>{w(e,f)},e=>{T(e)},S),e[STATE_READY]=!0,e[PERSISTED_STATE]=E,E}function createDeepProxy(e,f,p,m,h,g){return new Proxy(e,{get(_,v){let y=Reflect.get(_,v);if(y&&typeof y==`object`&&!Array.isArray(y)){let _=g??String(v);if(m.includes(_)||g!==void 0)return createDeepProxy(y,f,p,m,h??e,_)}return y},set(e,p,_){let v=Reflect.set(e,p,_);if(v){let e=g??String(p);m.includes(e)&&(g&&h?f(g,h[g]):f(String(p),_))}return v},deleteProperty(e,_){let v=Reflect.deleteProperty(e,_);if(v){let e=g??String(_);m.includes(e)&&(g&&h?f(g,h[g]):p(String(_)))}return v}})}function isStateReady(e){return e[STATE_READY]===!0}function getPersistedState(e){if(!isStateReady(e))throw new PersistNotReadyError(`state`);return e[PERSISTED_STATE]}function setPersistErrorHandler(e,f){e[PERSIST_ERROR_HANDLER]=f}const setPeristErrorHandler=setPersistErrorHandler;async function persistKey(e,f,p){let m=safeSerialize(p);await e.ctx.storage.put(`_verani_persist:${f}`,m)}async function deletePersistedKey(e,f){await e.ctx.storage.delete(`_verani_persist:${f}`)}async function getPersistedKeys(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`});return Array.from(f.keys()).map(e=>e.replace(`_verani_persist:`,``))}async function clearPersistedState(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`}),p=Array.from(f.keys());await e.ctx.storage.delete(p)}const WS=Symbol(`WS`),META=Symbol(`META`),ROOMS=Symbol(`ROOMS`);function createConnectionHandler(e){let h=e.name||`VeraniConnectionDO`,v=e.websocketPath||`/ws`;class y extends Actor{constructor(...f){super(...f),this[WS]=null,this[META]=null,this[ROOMS]=new Map,this[STATE_READY]=!1,this[PERSISTED_STATE]=e.state?{...e.state}:{},this.handlers=new Map}get connectionState(){return this[PERSISTED_STATE]}isStateReady(){return isStateReady(this)}static configuration(e){return{sockets:{upgradePath:v}}}getRoomBinding(f){if(!e.rooms)throw Error(`Cannot access room "${f}": no "rooms" config provided in ConnectionDefinition. Add rooms: { "${f}": "YourRoomBinding" } to your definition.`);let p=e.rooms[f]??e.rooms[f.split(`:`,1)[0]];if(!p)throw Error(`Cannot access room "${f}": not found in "rooms" config. Available rooms: ${Object.keys(e.rooms).join(`, `)}`);let m=this.env[p];if(!m)throw Error(`Room "${f}" binding "${p}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return m}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in ConnectionDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let f=this.env[e.connectionBinding];if(!f)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return f}createEmit(){let e=this;return{emit(f,p){e.sendToWebSocket(f,p)},to(f){return f.startsWith(`room:`)?e.createRoomEmitBuilder(f.slice(5)):e.createUserEmitBuilder(f)},toRoom(f,p){return e.createRoomEmitBuilder(f,p)},toUser(f){return e.createUserEmitBuilder(f)}}}createRoomEmitBuilder(e,f){let p=this;return{async emit(m,h){try{let g=p.getRoomBinding(e).get(e),_=f?.includeSelf||!p[META]?.userId?void 0:{exceptUserId:p[META].userId};return await g.broadcast(m,h,_)}catch{return 0}}}}createUserEmitBuilder(e){let f=this;return{async emit(p,m){try{return await f.getConnectionBinding().get(e).deliverMessage(p,m)?1:0}catch{return 0}}}}sendToWebSocket(e,f){let p=this[WS];if(!p||p.readyState!==WebSocket.OPEN)return!1;try{let h={type:`event`,channel:`default`,data:{type:e,...f}};return p.send(encodeFrame(h)),!0}catch{return!1}}createContext(){return{actor:this,ws:this[WS],meta:this[META],emit:this.createEmit(),state:this.connectionState}}async onInit(){e.state&&(e.onPersistError&&setPeristErrorHandler(this,e.onPersistError),this[PERSISTED_STATE]=await initializePersistedState(this,e.state,e.persistedKeys,e.persistOptions));let f=await this.ctx.storage.get(`_connection_rooms`);if(f&&Array.isArray(f)&&(this[ROOMS]=new Map(f.map(e=>[e.roomName,e.metadata]))),e.handlers)for(let[f,p]of e.handlers.entries())this.handlers.set(f,p);let p=this.ctx.getWebSockets();if(p.length>0){let f=p[0];if(f.readyState===WebSocket.OPEN){this[WS]=f;let p=f.deserializeAttachment();p&&(this[META]=p,await this.rejoinRoomsAfterHibernation(),e.onHibernationRestore&&await e.onHibernationRestore(this))}}}shouldUpgradeSocket(e){return!0}onWebSocketUpgrade(e){let f=new WebSocketPair,[p,m]=Object.values(f);this.ctx.acceptWebSocket(m);let h=new Response(null,{status:101,webSocket:p});return Promise.resolve().then(()=>{this.onWebSocketConnect(m,e)}),h}async onWebSocketConnect(f,m){this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`New connection established`);let h;if(h=e.extractMeta?await e.extractMeta(m):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(f,h),this[WS]=f,this[META]=h,e.onConnect)try{await e.onConnect(this.createContext())}catch(p){e.onError&&await e.onError(p,this.createContext()),f.close(1011,`Connection handler error`);return}}async onWebSocketMessage(f,p){if(this[META])try{let f=typeof p==`string`?p:p.toString(),m=JSON.parse(f),h=m,g=h.data,_=g?.type||h.type,v=this.handlers.get(_);if(v){await v(this.createContext(),g);return}e.onMessage&&await e.onMessage(this.createContext(),m)}catch(f){e.onError&&await e.onError(f,this.createContext())}}async onWebSocketDisconnect(f){if(this[META]&&e.onDisconnect)try{await e.onDisconnect(this.createContext())}catch{}for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]=null}async deliverMessage(e,f){return this.sendToWebSocket(e,f)}async deliverSystemEvent(e,f){this.sendToWebSocket(`system:${e}`,f)}async getUserId(){return this[META]?.userId??null}async isConnected(){return this[WS]!==null&&this[WS].readyState===WebSocket.OPEN}async joinRoom(e,f){if(!this[META])throw Error(`Cannot join room: not connected`);await this.getRoomBinding(e).get(e).join(this[META].userId,f),this[ROOMS].set(e,f),await this.persistRooms()}async persistRooms(){let e=Array.from(this[ROOMS].entries()).map(([e,f])=>({roomName:e,metadata:f}));await this.ctx.storage.put(`_connection_rooms`,e)}async rejoinRoomsAfterHibernation(){if(this[ROOMS].size===0)return;let e=this[META]?.userId;if(!e)return;let f=[];for(let[p,m]of this[ROOMS].entries())try{await this.getRoomBinding(p).get(p).join(e,m)}catch{f.push(p)}if(f.length>0){for(let e of f)this[ROOMS].delete(e);await this.persistRooms()}}async leaveRoomInternal(e){this[META]&&await this.getRoomBinding(e).get(e).leave(this[META].userId)}async leaveRoom(e){if(!this[META])throw Error(`Cannot leave room: not connected`);await this.leaveRoomInternal(e),this[ROOMS].delete(e),await this.persistRooms()}async getRooms(){return Array.from(this[ROOMS].keys())}getStorage(){return this.ctx.storage}on(e,f){this.handlers.set(e,f)}off(e){this.handlers.delete(e)}async destroy(){for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`Actor destroyed`),e.onDestroy&&this[META]&&await e.onDestroy(this.createContext()),await super.destroy()}}return Object.defineProperty(y,`name`,{value:h,writable:!1,configurable:!0}),y}function defineConnection(e){let f=new Map;return{...e,handlers:f,on(e,p){f.set(e,p)},off(e){f.delete(e)}}}export{clearPersistedState as a,getPersistedState as c,persistKey as d,safeDeserialize as f,storeAttachment as g,setPersistErrorHandler as h,PersistNotReadyError as i,initializePersistedState as l,setPeristErrorHandler as m,defineConnection as n,deletePersistedKey as o,safeSerialize as p,PersistError as r,getPersistedKeys as s,createConnectionHandler as t,isStateReady as u};
@@ -16,6 +16,10 @@ interface BroadcastOptions {
16
16
  /** Only send to specific client IDs */
17
17
  clientIds?: string[];
18
18
  }
19
+ interface RoomEmitOptions {
20
+ /** Include the sender when broadcasting to a room */
21
+ includeSelf?: boolean;
22
+ }
19
23
  /**
20
24
  * RPC-safe version of BroadcastOptions for use over RPC calls.
21
25
  * Excludes the `except` field since WebSocket cannot be serialized over RPC.
@@ -217,7 +221,7 @@ interface ConnectionEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unkn
217
221
  * @param roomName - Room name
218
222
  * @returns Builder for broadcasting to the room via RPC
219
223
  */
220
- toRoom(roomName: string): AsyncEmitBuilder;
224
+ toRoom(roomName: string, options?: RoomEmitOptions): AsyncEmitBuilder;
221
225
  /**
222
226
  * Target a specific user for direct messaging
223
227
  * @param userId - User ID
@@ -397,4 +401,4 @@ interface ConnectionDefinitionWithHandlers<TMeta extends ConnectionMeta = Connec
397
401
  */
398
402
  declare function defineConnection<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>>(def: ConnectionDefinition<TMeta, E, TState>): ConnectionDefinitionWithHandlers<TMeta, E, TState>;
399
403
  //#endregion
400
- export { ConnectionHandlerInstance as a, AsyncEmitBuilder as c, ConnectionActorStub as d, ConnectionEmit as f, VeraniEnv as g, RpcBroadcastOptions as h, ConnectionHandlerClass as i, BroadcastOptions as l, RoomMember as m, ConnectionDefinition as n, createConnectionHandler as o, RoomCoordinatorDefinition as p, ConnectionDefinitionWithHandlers as r, defineConnection as s, ConnectionContext as t, ConnectionActor as u };
404
+ export { VeraniEnv as _, ConnectionHandlerInstance as a, AsyncEmitBuilder as c, ConnectionActorStub as d, ConnectionEmit as f, RpcBroadcastOptions as g, RoomMember as h, ConnectionHandlerClass as i, BroadcastOptions as l, RoomEmitOptions as m, ConnectionDefinition as n, createConnectionHandler as o, RoomCoordinatorDefinition as p, ConnectionDefinitionWithHandlers as r, defineConnection as s, ConnectionContext as t, ConnectionActor as u };
@@ -16,6 +16,10 @@ interface BroadcastOptions {
16
16
  /** Only send to specific client IDs */
17
17
  clientIds?: string[];
18
18
  }
19
+ interface RoomEmitOptions {
20
+ /** Include the sender when broadcasting to a room */
21
+ includeSelf?: boolean;
22
+ }
19
23
  /**
20
24
  * RPC-safe version of BroadcastOptions for use over RPC calls.
21
25
  * Excludes the `except` field since WebSocket cannot be serialized over RPC.
@@ -217,7 +221,7 @@ interface ConnectionEmit<TMeta extends ConnectionMeta = ConnectionMeta, E = unkn
217
221
  * @param roomName - Room name
218
222
  * @returns Builder for broadcasting to the room via RPC
219
223
  */
220
- toRoom(roomName: string): AsyncEmitBuilder;
224
+ toRoom(roomName: string, options?: RoomEmitOptions): AsyncEmitBuilder;
221
225
  /**
222
226
  * Target a specific user for direct messaging
223
227
  * @param userId - User ID
@@ -397,4 +401,4 @@ interface ConnectionDefinitionWithHandlers<TMeta extends ConnectionMeta = Connec
397
401
  */
398
402
  declare function defineConnection<TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>>(def: ConnectionDefinition<TMeta, E, TState>): ConnectionDefinitionWithHandlers<TMeta, E, TState>;
399
403
  //#endregion
400
- export { ConnectionHandlerInstance as a, AsyncEmitBuilder as c, ConnectionActorStub as d, ConnectionEmit as f, VeraniEnv as g, RpcBroadcastOptions as h, ConnectionHandlerClass as i, BroadcastOptions as l, RoomMember as m, ConnectionDefinition as n, createConnectionHandler as o, RoomCoordinatorDefinition as p, ConnectionDefinitionWithHandlers as r, defineConnection as s, ConnectionContext as t, ConnectionActor as u };
404
+ export { VeraniEnv as _, ConnectionHandlerInstance as a, AsyncEmitBuilder as c, ConnectionActorStub as d, ConnectionEmit as f, RpcBroadcastOptions as g, RoomMember as h, ConnectionHandlerClass as i, BroadcastOptions as l, RoomEmitOptions as m, ConnectionDefinition as n, createConnectionHandler as o, RoomCoordinatorDefinition as p, ConnectionDefinitionWithHandlers as r, defineConnection as s, ConnectionContext as t, ConnectionActor as u };
@@ -0,0 +1 @@
1
+ const require_encode=require(`./encode-SjZrKIyU.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);function storeAttachment(e,f){e.serializeAttachment(f)}function encodeFrame(f){return require_encode.n(f)}const PERSIST_ERROR_HANDLER=Symbol(`PERSIST_ERROR_HANDLER`),PERSISTED_STATE=Symbol(`PERSISTED_STATE`),STATE_READY=Symbol(`STATE_READY`);var PersistNotReadyError=class extends Error{constructor(e){super(`Cannot access persisted state key "${e}" before storage is initialized. Wait for onInit to complete or check actor.isStateReady().`),this.name=`PersistNotReadyError`}},PersistError=class extends Error{constructor(e,f){super(`Failed to persist key "${e}": ${f.message}`),this.name=`PersistError`,this.originalCause=f}};function safeSerialize(e){let f=new WeakSet;return JSON.stringify(e,(e,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(f.has(p))return;f.add(p)}if(!(typeof p==`function`||typeof p==`symbol`))return p})}function safeDeserialize(e){return JSON.parse(e,(e,f)=>{if(f&&typeof f==`object`&&f.__type)switch(f.__type){case`Date`:return new Date(f.value);case`RegExp`:return new RegExp(f.source,f.flags);case`Map`:return new Map(f.entries);case`Set`:return new Set(f.values);case`Error`:{let e=Error(f.message);return e.name=f.name,e}}return f})}function createShallowProxy(e,f,p){return new Proxy(e,{set(e,p,m){let h=Reflect.set(e,p,m);return h&&typeof p==`string`&&f(p,m),h},deleteProperty(e,f){let m=Reflect.deleteProperty(e,f);return m&&typeof f==`string`&&p(f),m}})}async function initializePersistedState(e,f,p=[],m={}){let{shallow:v=!0,throwOnError:b=!0}=m,x=e.ctx.storage,S=p.length>0?p.map(String):Object.keys(f),C={...f};for(let e of S)try{let f=await x.get(`_verani_persist:${e}`);if(f!==void 0)try{C[e]=safeDeserialize(f)}catch(f){if(b)throw new PersistError(e,f)}}catch(f){if(b&&!(f instanceof PersistError))throw new PersistError(e,f)}let w=async(f,p)=>{if(S.includes(f))try{let e=safeSerialize(p);await x.put(`_verani_persist:${f}`,e)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},T=async f=>{if(S.includes(f))try{await x.delete(`_verani_persist:${f}`)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},E;return E=v?createShallowProxy(C,(e,f)=>{w(String(e),f)},e=>{T(String(e))}):createDeepProxy(C,(e,f)=>{w(e,f)},e=>{T(e)},S),e[STATE_READY]=!0,e[PERSISTED_STATE]=E,E}function createDeepProxy(e,f,p,m,h,g){return new Proxy(e,{get(_,v){let y=Reflect.get(_,v);if(y&&typeof y==`object`&&!Array.isArray(y)){let _=g??String(v);if(m.includes(_)||g!==void 0)return createDeepProxy(y,f,p,m,h??e,_)}return y},set(e,p,_){let v=Reflect.set(e,p,_);if(v){let e=g??String(p);m.includes(e)&&(g&&h?f(g,h[g]):f(String(p),_))}return v},deleteProperty(e,_){let v=Reflect.deleteProperty(e,_);if(v){let e=g??String(_);m.includes(e)&&(g&&h?f(g,h[g]):p(String(_)))}return v}})}function isStateReady(e){return e[STATE_READY]===!0}function getPersistedState(e){if(!isStateReady(e))throw new PersistNotReadyError(`state`);return e[PERSISTED_STATE]}function setPersistErrorHandler(e,f){e[PERSIST_ERROR_HANDLER]=f}const setPeristErrorHandler=setPersistErrorHandler;async function persistKey(e,f,p){let m=safeSerialize(p);await e.ctx.storage.put(`_verani_persist:${f}`,m)}async function deletePersistedKey(e,f){await e.ctx.storage.delete(`_verani_persist:${f}`)}async function getPersistedKeys(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`});return Array.from(f.keys()).map(e=>e.replace(`_verani_persist:`,``))}async function clearPersistedState(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`}),p=Array.from(f.keys());await e.ctx.storage.delete(p)}const WS=Symbol(`WS`),META=Symbol(`META`),ROOMS=Symbol(`ROOMS`);function createConnectionHandler(e){let h=e.name||`VeraniConnectionDO`,v=e.websocketPath||`/ws`;class y extends __cloudflare_actors.Actor{constructor(...f){super(...f),this[WS]=null,this[META]=null,this[ROOMS]=new Map,this[STATE_READY]=!1,this[PERSISTED_STATE]=e.state?{...e.state}:{},this.handlers=new Map}get connectionState(){return this[PERSISTED_STATE]}isStateReady(){return isStateReady(this)}static configuration(e){return{sockets:{upgradePath:v}}}getRoomBinding(f){if(!e.rooms)throw Error(`Cannot access room "${f}": no "rooms" config provided in ConnectionDefinition. Add rooms: { "${f}": "YourRoomBinding" } to your definition.`);let p=e.rooms[f]??e.rooms[f.split(`:`,1)[0]];if(!p)throw Error(`Cannot access room "${f}": not found in "rooms" config. Available rooms: ${Object.keys(e.rooms).join(`, `)}`);let m=this.env[p];if(!m)throw Error(`Room "${f}" binding "${p}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return m}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in ConnectionDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let f=this.env[e.connectionBinding];if(!f)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return f}createEmit(){let e=this;return{emit(f,p){e.sendToWebSocket(f,p)},to(f){return f.startsWith(`room:`)?e.createRoomEmitBuilder(f.slice(5)):e.createUserEmitBuilder(f)},toRoom(f,p){return e.createRoomEmitBuilder(f,p)},toUser(f){return e.createUserEmitBuilder(f)}}}createRoomEmitBuilder(e,f){let p=this;return{async emit(m,h){try{let g=p.getRoomBinding(e).get(e),_=f?.includeSelf||!p[META]?.userId?void 0:{exceptUserId:p[META].userId};return await g.broadcast(m,h,_)}catch{return 0}}}}createUserEmitBuilder(e){let f=this;return{async emit(p,m){try{return await f.getConnectionBinding().get(e).deliverMessage(p,m)?1:0}catch{return 0}}}}sendToWebSocket(e,f){let p=this[WS];if(!p||p.readyState!==WebSocket.OPEN)return!1;try{let h={type:`event`,channel:`default`,data:{type:e,...f}};return p.send(encodeFrame(h)),!0}catch{return!1}}createContext(){return{actor:this,ws:this[WS],meta:this[META],emit:this.createEmit(),state:this.connectionState}}async onInit(){e.state&&(e.onPersistError&&setPeristErrorHandler(this,e.onPersistError),this[PERSISTED_STATE]=await initializePersistedState(this,e.state,e.persistedKeys,e.persistOptions));let f=await this.ctx.storage.get(`_connection_rooms`);if(f&&Array.isArray(f)&&(this[ROOMS]=new Map(f.map(e=>[e.roomName,e.metadata]))),e.handlers)for(let[f,p]of e.handlers.entries())this.handlers.set(f,p);let p=this.ctx.getWebSockets();if(p.length>0){let f=p[0];if(f.readyState===WebSocket.OPEN){this[WS]=f;let p=f.deserializeAttachment();p&&(this[META]=p,await this.rejoinRoomsAfterHibernation(),e.onHibernationRestore&&await e.onHibernationRestore(this))}}}shouldUpgradeSocket(e){return!0}onWebSocketUpgrade(e){let f=new WebSocketPair,[p,m]=Object.values(f);this.ctx.acceptWebSocket(m);let h=new Response(null,{status:101,webSocket:p});return Promise.resolve().then(()=>{this.onWebSocketConnect(m,e)}),h}async onWebSocketConnect(f,m){this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`New connection established`);let h;if(h=e.extractMeta?await e.extractMeta(m):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(f,h),this[WS]=f,this[META]=h,e.onConnect)try{await e.onConnect(this.createContext())}catch(p){e.onError&&await e.onError(p,this.createContext()),f.close(1011,`Connection handler error`);return}}async onWebSocketMessage(f,p){if(this[META])try{let f=typeof p==`string`?p:p.toString(),m=JSON.parse(f),h=m,g=h.data,_=g?.type||h.type,v=this.handlers.get(_);if(v){await v(this.createContext(),g);return}e.onMessage&&await e.onMessage(this.createContext(),m)}catch(f){e.onError&&await e.onError(f,this.createContext())}}async onWebSocketDisconnect(f){if(this[META]&&e.onDisconnect)try{await e.onDisconnect(this.createContext())}catch{}for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]=null}async deliverMessage(e,f){return this.sendToWebSocket(e,f)}async deliverSystemEvent(e,f){this.sendToWebSocket(`system:${e}`,f)}async getUserId(){return this[META]?.userId??null}async isConnected(){return this[WS]!==null&&this[WS].readyState===WebSocket.OPEN}async joinRoom(e,f){if(!this[META])throw Error(`Cannot join room: not connected`);await this.getRoomBinding(e).get(e).join(this[META].userId,f),this[ROOMS].set(e,f),await this.persistRooms()}async persistRooms(){let e=Array.from(this[ROOMS].entries()).map(([e,f])=>({roomName:e,metadata:f}));await this.ctx.storage.put(`_connection_rooms`,e)}async rejoinRoomsAfterHibernation(){if(this[ROOMS].size===0)return;let e=this[META]?.userId;if(!e)return;let f=[];for(let[p,m]of this[ROOMS].entries())try{await this.getRoomBinding(p).get(p).join(e,m)}catch{f.push(p)}if(f.length>0){for(let e of f)this[ROOMS].delete(e);await this.persistRooms()}}async leaveRoomInternal(e){this[META]&&await this.getRoomBinding(e).get(e).leave(this[META].userId)}async leaveRoom(e){if(!this[META])throw Error(`Cannot leave room: not connected`);await this.leaveRoomInternal(e),this[ROOMS].delete(e),await this.persistRooms()}async getRooms(){return Array.from(this[ROOMS].keys())}getStorage(){return this.ctx.storage}on(e,f){this.handlers.set(e,f)}off(e){this.handlers.delete(e)}async destroy(){for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`Actor destroyed`),e.onDestroy&&this[META]&&await e.onDestroy(this.createContext()),await super.destroy()}}return Object.defineProperty(y,`name`,{value:h,writable:!1,configurable:!0}),y}function defineConnection(e){let f=new Map;return{...e,handlers:f,on(e,p){f.set(e,p)},off(e){f.delete(e)}}}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return clearPersistedState}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return getPersistedState}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return persistKey}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return safeDeserialize}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return storeAttachment}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return setPersistErrorHandler}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return PersistNotReadyError}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return initializePersistedState}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return setPeristErrorHandler}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return defineConnection}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return deletePersistedKey}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return safeSerialize}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return PersistError}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return getPersistedKeys}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return createConnectionHandler}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return isStateReady}});
package/dist/typed.cjs CHANGED
@@ -1 +1 @@
1
- const require_connection_actor=require(`./connection-actor-5nKwCTdA.cjs`);require(`./encode-SjZrKIyU.cjs`);const require_validation=require(`./validation-DvWPGkXK.cjs`);function createTypedConnectionEmit(e){let t=((t,n)=>{e.emit(t,n)});return t.to=t=>{let n=e.to(t);return{emit:(e,t)=>n.emit(e,t)}},t.toRoom=t=>{let n=e.toRoom(t);return{emit:(e,t)=>n.emit(e,t)}},t.toUser=t=>{let n=e.toUser(t);return{emit:(e,t)=>n.emit(e,t)}},t}function wrapContext(e){return{actor:e.actor,ws:e.ws,meta:e.meta,emit:createTypedConnectionEmit(e.emit),state:e.state}}function createTypedConnection(n,i){let a=require_connection_actor.n({name:i.name,websocketPath:i.websocketPath??`/ws`,extractMeta:i.extractMeta,state:i.state,persistedKeys:i.persistedKeys,onConnect:i.onConnect?e=>i.onConnect(wrapContext(e)):void 0,onDisconnect:i.onDisconnect?e=>i.onDisconnect(wrapContext(e)):void 0,onError:i.onError?(e,t)=>i.onError(e,wrapContext(t)):void 0,onHibernationRestore:i.onHibernationRestore}),o=require_validation.o(n),s=o?require_validation.a(n):void 0;return{on(e,i){a.on(e,(a,c)=>{let l={...wrapContext(a),frame:{type:e,data:c}};if(o){let r=require_validation.r(n,e);if(r){let n=require_validation.s(r,c,e,`client`,s);return n===void 0?void 0:i(l,n)}}return i(l,c)})},off(e,t){a.off(e)},get definition(){return a},contract:n}}exports.createConnectionHandler=require_connection_actor.t,exports.createTypedConnection=createTypedConnection,exports.createTypedRoom=createTypedConnection,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_connection_actor=require(`./connection-actor-K3TH2ycP.cjs`);require(`./encode-SjZrKIyU.cjs`);const require_validation=require(`./validation-DvWPGkXK.cjs`);function createTypedConnectionEmit(e){let t=((t,n)=>{e.emit(t,n)});return t.to=t=>{let n=e.to(t);return{emit:(e,t)=>n.emit(e,t)}},t.toRoom=(t,n)=>{let r=e.toRoom(t,n);return{emit:(e,t)=>r.emit(e,t)}},t.toUser=t=>{let n=e.toUser(t);return{emit:(e,t)=>n.emit(e,t)}},t}function wrapContext(e){return{actor:e.actor,ws:e.ws,meta:e.meta,emit:createTypedConnectionEmit(e.emit),state:e.state}}function createTypedConnection(n,i){let a=require_connection_actor.n({name:i.name,websocketPath:i.websocketPath??`/ws`,rooms:i.rooms,connectionBinding:i.connectionBinding,extractMeta:i.extractMeta,state:i.state,persistedKeys:i.persistedKeys,onConnect:i.onConnect?e=>i.onConnect(wrapContext(e)):void 0,onDisconnect:i.onDisconnect?e=>i.onDisconnect(wrapContext(e)):void 0,onError:i.onError?(e,t)=>i.onError(e,wrapContext(t)):void 0,onHibernationRestore:i.onHibernationRestore}),o=require_validation.o(n),s=o?require_validation.a(n):void 0;return{on(e,i){a.on(e,(a,c)=>{let l={...wrapContext(a),frame:{type:e,data:c}};if(o){let r=require_validation.r(n,e);if(r){let n=require_validation.s(r,c,e,`client`,s);return n===void 0?void 0:i(l,n)}}return i(l,c)})},off(e,t){a.off(e)},get definition(){return a},contract:n}}exports.createConnectionHandler=require_connection_actor.t,exports.createTypedConnection=createTypedConnection,exports.createTypedRoom=createTypedConnection,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-DIIeb2YQ.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 { a as ConnectionHandlerInstance, d as ConnectionActorStub, n as ConnectionDefinition, o as createConnectionHandler } from "./connection-actor-DnM0bxkn.cjs";
3
+ import { a as ConnectionHandlerInstance, d as ConnectionActorStub, m as RoomEmitOptions, n as ConnectionDefinition, o as createConnectionHandler } from "./connection-actor-D61IMDIa.cjs";
4
4
 
5
5
  //#region src/typed/server.d.ts
6
6
 
@@ -35,7 +35,7 @@ interface TypedConnectionEmit<C extends Contract, TMeta extends ConnectionMeta>
35
35
  * Target a specific room for broadcasting.
36
36
  * @param roomName - Room name
37
37
  */
38
- toRoom(roomName: string): TypedAsyncEmitBuilder<C, TMeta>;
38
+ toRoom(roomName: string, options?: RoomEmitOptions): TypedAsyncEmitBuilder<C, TMeta>;
39
39
  /**
40
40
  * Target a specific user for direct messaging.
41
41
  * @param userId - User ID
@@ -100,6 +100,10 @@ interface TypedConnectionConfig<C extends Contract, TMeta extends ConnectionMeta
100
100
  * Initial state for this connection.
101
101
  */
102
102
  state?: TState;
103
+ /** Map room names or prefixes to Durable Object bindings */
104
+ rooms?: Record<string, string>;
105
+ /** Durable Object binding for this connection handler */
106
+ connectionBinding?: string;
103
107
  /**
104
108
  * Keys to persist to storage.
105
109
  */
@@ -185,4 +189,4 @@ interface TypedConnection<C extends Contract, TMeta extends ConnectionMeta = Con
185
189
  declare function createTypedConnection<C extends Contract, TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>>(contract: C, config: TypedConnectionConfig<C, TMeta, E, TState>): TypedConnection<C, TMeta, E, TState>;
186
190
  type TypedActorEmit<C extends Contract, TMeta extends ConnectionMeta> = TypedConnectionEmit<C, TMeta>;
187
191
  //#endregion
188
- export { type AllEventNames, type ClientEventHandler, type ClientEventNames, type ClientPayload, type ClientPayloadMap, type ConnectionActorStub, type ConnectionMeta, type Contract, type ContractDefinition, type EventMap, type EventPayloads, type ExtractPayload, type InferChannels, type InferClientEvents, type InferServerEvents, type PayloadMarker, type ServerEventHandler, type ServerEventNames, type ServerPayload, type ServerPayloadMap, type TypedActorEmit, type TypedAsyncEmitBuilder, type TypedAsyncEmitBuilder as TypedEmitBuilder, type TypedClientEmit, type TypedClientListener, type TypedConnection, type TypedConnection as TypedRoom, type TypedConnectionConfig, type TypedConnectionConfig as TypedRoomConfig, type TypedConnectionContext, type TypedConnectionContext as TypedRoomContext, type TypedConnectionEmit, type TypedConnectionEmit as TypedSocketEmit, type TypedEventHandler, type TypedMessageContext, type TypedServerEmit, type TypedServerListener, type ValidatedContract, type ValidationConfig, type ValidationError, type ValidationIssue, type ValidationResult, type Validator, type ValidatorMap, createConnectionHandler, createTypedConnection, createTypedConnection as createTypedRoom, createValidatedHandler, defineContract, getClientValidator, getValidationErrorHandler, isContract, isValidatedContract, payload, validateData, withValidation };
192
+ export { type AllEventNames, type ClientEventHandler, type ClientEventNames, type ClientPayload, type ClientPayloadMap, type ConnectionActorStub, type ConnectionMeta, type Contract, type ContractDefinition, type EventMap, type EventPayloads, type ExtractPayload, type InferChannels, type InferClientEvents, type InferServerEvents, type PayloadMarker, type RoomEmitOptions, type ServerEventHandler, type ServerEventNames, type ServerPayload, type ServerPayloadMap, type TypedActorEmit, type TypedAsyncEmitBuilder, type TypedAsyncEmitBuilder as TypedEmitBuilder, type TypedClientEmit, type TypedClientListener, type TypedConnection, type TypedConnection as TypedRoom, type TypedConnectionConfig, type TypedConnectionConfig as TypedRoomConfig, type TypedConnectionContext, type TypedConnectionContext as TypedRoomContext, type TypedConnectionEmit, type TypedConnectionEmit as TypedSocketEmit, type TypedEventHandler, type TypedMessageContext, type TypedServerEmit, type TypedServerListener, type ValidatedContract, type ValidationConfig, type ValidationError, type ValidationIssue, type ValidationResult, type Validator, type ValidatorMap, createConnectionHandler, createTypedConnection, createTypedConnection as createTypedRoom, createValidatedHandler, defineContract, getClientValidator, getValidationErrorHandler, isContract, isValidatedContract, payload, validateData, withValidation };
package/dist/typed.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as ConnectionMeta } from "./types-6m1L8QLb.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 { a as ConnectionHandlerInstance, d as ConnectionActorStub, n as ConnectionDefinition, o as createConnectionHandler } from "./connection-actor-CtqCgN3y.mjs";
3
+ import { a as ConnectionHandlerInstance, d as ConnectionActorStub, m as RoomEmitOptions, n as ConnectionDefinition, o as createConnectionHandler } from "./connection-actor-D1QRniw1.mjs";
4
4
 
5
5
  //#region src/typed/server.d.ts
6
6
 
@@ -35,7 +35,7 @@ interface TypedConnectionEmit<C extends Contract, TMeta extends ConnectionMeta>
35
35
  * Target a specific room for broadcasting.
36
36
  * @param roomName - Room name
37
37
  */
38
- toRoom(roomName: string): TypedAsyncEmitBuilder<C, TMeta>;
38
+ toRoom(roomName: string, options?: RoomEmitOptions): TypedAsyncEmitBuilder<C, TMeta>;
39
39
  /**
40
40
  * Target a specific user for direct messaging.
41
41
  * @param userId - User ID
@@ -100,6 +100,10 @@ interface TypedConnectionConfig<C extends Contract, TMeta extends ConnectionMeta
100
100
  * Initial state for this connection.
101
101
  */
102
102
  state?: TState;
103
+ /** Map room names or prefixes to Durable Object bindings */
104
+ rooms?: Record<string, string>;
105
+ /** Durable Object binding for this connection handler */
106
+ connectionBinding?: string;
103
107
  /**
104
108
  * Keys to persist to storage.
105
109
  */
@@ -185,4 +189,4 @@ interface TypedConnection<C extends Contract, TMeta extends ConnectionMeta = Con
185
189
  declare function createTypedConnection<C extends Contract, TMeta extends ConnectionMeta = ConnectionMeta, E = unknown, TState extends Record<string, unknown> = Record<string, unknown>>(contract: C, config: TypedConnectionConfig<C, TMeta, E, TState>): TypedConnection<C, TMeta, E, TState>;
186
190
  type TypedActorEmit<C extends Contract, TMeta extends ConnectionMeta> = TypedConnectionEmit<C, TMeta>;
187
191
  //#endregion
188
- export { type AllEventNames, type ClientEventHandler, type ClientEventNames, type ClientPayload, type ClientPayloadMap, type ConnectionActorStub, type ConnectionMeta, type Contract, type ContractDefinition, type EventMap, type EventPayloads, type ExtractPayload, type InferChannels, type InferClientEvents, type InferServerEvents, type PayloadMarker, type ServerEventHandler, type ServerEventNames, type ServerPayload, type ServerPayloadMap, type TypedActorEmit, type TypedAsyncEmitBuilder, type TypedAsyncEmitBuilder as TypedEmitBuilder, type TypedClientEmit, type TypedClientListener, type TypedConnection, type TypedConnection as TypedRoom, type TypedConnectionConfig, type TypedConnectionConfig as TypedRoomConfig, type TypedConnectionContext, type TypedConnectionContext as TypedRoomContext, type TypedConnectionEmit, type TypedConnectionEmit as TypedSocketEmit, type TypedEventHandler, type TypedMessageContext, type TypedServerEmit, type TypedServerListener, type ValidatedContract, type ValidationConfig, type ValidationError, type ValidationIssue, type ValidationResult, type Validator, type ValidatorMap, createConnectionHandler, createTypedConnection, createTypedConnection as createTypedRoom, createValidatedHandler, defineContract, getClientValidator, getValidationErrorHandler, isContract, isValidatedContract, payload, validateData, withValidation };
192
+ export { type AllEventNames, type ClientEventHandler, type ClientEventNames, type ClientPayload, type ClientPayloadMap, type ConnectionActorStub, type ConnectionMeta, type Contract, type ContractDefinition, type EventMap, type EventPayloads, type ExtractPayload, type InferChannels, type InferClientEvents, type InferServerEvents, type PayloadMarker, type RoomEmitOptions, type ServerEventHandler, type ServerEventNames, type ServerPayload, type ServerPayloadMap, type TypedActorEmit, type TypedAsyncEmitBuilder, type TypedAsyncEmitBuilder as TypedEmitBuilder, type TypedClientEmit, type TypedClientListener, type TypedConnection, type TypedConnection as TypedRoom, type TypedConnectionConfig, type TypedConnectionConfig as TypedRoomConfig, type TypedConnectionContext, type TypedConnectionContext as TypedRoomContext, type TypedConnectionEmit, type TypedConnectionEmit as TypedSocketEmit, type TypedEventHandler, type TypedMessageContext, type TypedServerEmit, type TypedServerListener, type ValidatedContract, type ValidationConfig, type ValidationError, type ValidationIssue, type ValidationResult, type Validator, type ValidatorMap, createConnectionHandler, createTypedConnection, createTypedConnection as createTypedRoom, createValidatedHandler, defineContract, getClientValidator, getValidationErrorHandler, isContract, isValidatedContract, payload, validateData, withValidation };
package/dist/typed.mjs CHANGED
@@ -1 +1 @@
1
- import{n as defineConnection,t as createConnectionHandler}from"./connection-actor-CVS554hv.mjs";import"./encode-CFndA-BQ.mjs";import{a as getValidationErrorHandler,c as withValidation,d as payload,l as defineContract,o as isValidatedContract,r as getClientValidator,s as validateData,t as createValidatedHandler,u as isContract}from"./validation-NB7a2Sf1.mjs";function createTypedConnectionEmit(e){let s=((s,c)=>{e.emit(s,c)});return s.to=s=>{let c=e.to(s);return{emit:(e,s)=>c.emit(e,s)}},s.toRoom=s=>{let c=e.toRoom(s);return{emit:(e,s)=>c.emit(e,s)}},s.toUser=s=>{let c=e.toUser(s);return{emit:(e,s)=>c.emit(e,s)}},s}function wrapContext(e){return{actor:e.actor,ws:e.ws,meta:e.meta,emit:createTypedConnectionEmit(e.emit),state:e.state}}function createTypedConnection(s,l){let u=defineConnection({name:l.name,websocketPath:l.websocketPath??`/ws`,extractMeta:l.extractMeta,state:l.state,persistedKeys:l.persistedKeys,onConnect:l.onConnect?e=>l.onConnect(wrapContext(e)):void 0,onDisconnect:l.onDisconnect?e=>l.onDisconnect(wrapContext(e)):void 0,onError:l.onError?(e,s)=>l.onError(e,wrapContext(s)):void 0,onHibernationRestore:l.onHibernationRestore}),d=isValidatedContract(s),p=d?getValidationErrorHandler(s):void 0;return{on(e,c){u.on(e,(l,u)=>{let f={...wrapContext(l),frame:{type:e,data:u}};if(d){let l=getClientValidator(s,e);if(l){let s=validateData(l,u,e,`client`,p);return s===void 0?void 0:c(f,s)}}return c(f,u)})},off(e,s){u.off(e)},get definition(){return u},contract:s}}export{createConnectionHandler,createTypedConnection,createTypedConnection as createTypedRoom,createValidatedHandler,defineContract,getClientValidator,getValidationErrorHandler,isContract,isValidatedContract,payload,validateData,withValidation};
1
+ import{n as defineConnection,t as createConnectionHandler}from"./connection-actor-B5AzPIkG.mjs";import"./encode-CFndA-BQ.mjs";import{a as getValidationErrorHandler,c as withValidation,d as payload,l as defineContract,o as isValidatedContract,r as getClientValidator,s as validateData,t as createValidatedHandler,u as isContract}from"./validation-NB7a2Sf1.mjs";function createTypedConnectionEmit(e){let s=((s,c)=>{e.emit(s,c)});return s.to=s=>{let c=e.to(s);return{emit:(e,s)=>c.emit(e,s)}},s.toRoom=(s,c)=>{let l=e.toRoom(s,c);return{emit:(e,s)=>l.emit(e,s)}},s.toUser=s=>{let c=e.toUser(s);return{emit:(e,s)=>c.emit(e,s)}},s}function wrapContext(e){return{actor:e.actor,ws:e.ws,meta:e.meta,emit:createTypedConnectionEmit(e.emit),state:e.state}}function createTypedConnection(s,l){let u=defineConnection({name:l.name,websocketPath:l.websocketPath??`/ws`,rooms:l.rooms,connectionBinding:l.connectionBinding,extractMeta:l.extractMeta,state:l.state,persistedKeys:l.persistedKeys,onConnect:l.onConnect?e=>l.onConnect(wrapContext(e)):void 0,onDisconnect:l.onDisconnect?e=>l.onDisconnect(wrapContext(e)):void 0,onError:l.onError?(e,s)=>l.onError(e,wrapContext(s)):void 0,onHibernationRestore:l.onHibernationRestore}),d=isValidatedContract(s),p=d?getValidationErrorHandler(s):void 0;return{on(e,c){u.on(e,(l,u)=>{let f={...wrapContext(l),frame:{type:e,data:u}};if(d){let l=getClientValidator(s,e);if(l){let s=validateData(l,u,e,`client`,p);return s===void 0?void 0:c(f,s)}}return c(f,u)})},off(e,s){u.off(e)},get definition(){return u},contract:s}}export{createConnectionHandler,createTypedConnection,createTypedConnection as createTypedRoom,createValidatedHandler,defineContract,getClientValidator,getValidationErrorHandler,isContract,isValidatedContract,payload,validateData,withValidation};
package/dist/verani.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_connection_actor=require(`./connection-actor-5nKwCTdA.cjs`),require_encode=require(`./encode-SjZrKIyU.cjs`),require_types=require(`./types-DUO6RVw1.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);const MEMBERS=Symbol(`MEMBERS`),ROOM_NAME=Symbol(`ROOM_NAME`),DELIVERY_FAILURES=Symbol(`DELIVERY_FAILURES`);function createRoomHandler(e={}){let n=e.name||`VeraniRoomDO`;class r extends __cloudflare_actors.Actor{constructor(...e){super(...e),this[MEMBERS]=new Map,this[ROOM_NAME]=``,this[DELIVERY_FAILURES]=new Map,this.roomState={}}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in RoomCoordinatorDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let n=this.env[e.connectionBinding];if(!n)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return n}async onInit(){this.ensureTables(),await this.migrateFromKV(),this.loadMembers(),this.loadRoomState(),e.onInit&&await e.onInit(this.roomState)}ensureTables(){this.sql`CREATE TABLE IF NOT EXISTS room_members (
1
+ const require_connection_actor=require(`./connection-actor-K3TH2ycP.cjs`),require_encode=require(`./encode-SjZrKIyU.cjs`),require_types=require(`./types-DUO6RVw1.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);const MEMBERS=Symbol(`MEMBERS`),ROOM_NAME=Symbol(`ROOM_NAME`),DELIVERY_FAILURES=Symbol(`DELIVERY_FAILURES`);function createRoomHandler(e={}){let n=e.name||`VeraniRoomDO`;class r extends __cloudflare_actors.Actor{constructor(...e){super(...e),this[MEMBERS]=new Map,this[ROOM_NAME]=``,this[DELIVERY_FAILURES]=new Map,this.roomState={}}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in RoomCoordinatorDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let n=this.env[e.connectionBinding];if(!n)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return n}async onInit(){this.ensureTables(),await this.migrateFromKV(),this.loadMembers(),this.loadRoomState(),e.onInit&&await e.onInit(this.roomState)}ensureTables(){this.sql`CREATE TABLE IF NOT EXISTS room_members (
2
2
  user_id TEXT PRIMARY KEY,
3
3
  joined_at INTEGER NOT NULL,
4
4
  metadata TEXT
package/dist/verani.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as ServerMessage, i as PROTOCOL_VERSION, n as ConnectionMeta, o as VeraniMessage, r as MessageFrame, t as ClientMessage } from "./types-DIIeb2YQ.cjs";
2
2
  import { a as encodeFrame, i as encodeClientMessage, n as decodeFrame, o as encodeServerMessage, r as decodeServerMessage, t as decodeClientMessage } from "./decode-otE_3S_-.cjs";
3
- import { c as AsyncEmitBuilder, d as ConnectionActorStub, f as ConnectionEmit, g as VeraniEnv, h as RpcBroadcastOptions, i as ConnectionHandlerClass, l as BroadcastOptions, m as RoomMember, n as ConnectionDefinition, o as createConnectionHandler, p as RoomCoordinatorDefinition, r as ConnectionDefinitionWithHandlers, s as defineConnection, t as ConnectionContext, u as ConnectionActor } from "./connection-actor-DnM0bxkn.cjs";
3
+ import { _ as VeraniEnv, c as AsyncEmitBuilder, d as ConnectionActorStub, f as ConnectionEmit, g as RpcBroadcastOptions, h as RoomMember, i as ConnectionHandlerClass, l as BroadcastOptions, m as RoomEmitOptions, n as ConnectionDefinition, o as createConnectionHandler, p as RoomCoordinatorDefinition, r as ConnectionDefinitionWithHandlers, s as defineConnection, t as ConnectionContext, u as ConnectionActor } from "./connection-actor-D61IMDIa.cjs";
4
4
  import { Actor } from "@cloudflare/actors";
5
5
 
6
6
  //#region src/actor/room-actor.d.ts
@@ -135,4 +135,4 @@ declare function deletePersistedKey(actor: PersistableActor, key: string): Promi
135
135
  declare function getPersistedKeys(actor: PersistableActor): Promise<string[]>;
136
136
  declare function clearPersistedState(actor: PersistableActor): Promise<void>;
137
137
  //#endregion
138
- export { type AsyncEmitBuilder, type BroadcastOptions, type ClientMessage, type ConnectionActor, type ConnectionActorStub, type ConnectionContext, type ConnectionDefinition, type ConnectionDefinitionWithHandlers, type ConnectionEmit, type ConnectionHandlerClass, type ConnectionMeta, type MessageFrame, PROTOCOL_VERSION, PersistError, PersistNotReadyError, type PersistableActor, type RoomActorStub, type RoomCoordinatorDefinition, type RoomHandlerClass, type RoomMember, type RpcBroadcastOptions, type SafePersistOptions, type ServerMessage, type VeraniEnv, type VeraniMessage, clearPersistedState, createConnectionHandler, createRoomHandler, decodeClientMessage, decodeFrame, decodeServerMessage, defineConnection, deletePersistedKey, enableDebug, encodeClientMessage, encodeFrame, encodeServerMessage, getPersistedKeys, getPersistedState, initializePersistedState, isStateReady, persistKey, safeDeserialize, safeSerialize, setPeristErrorHandler, setPersistErrorHandler, storeAttachment };
138
+ export { type AsyncEmitBuilder, type BroadcastOptions, type ClientMessage, type ConnectionActor, type ConnectionActorStub, type ConnectionContext, type ConnectionDefinition, type ConnectionDefinitionWithHandlers, type ConnectionEmit, type ConnectionHandlerClass, type ConnectionMeta, type MessageFrame, PROTOCOL_VERSION, PersistError, PersistNotReadyError, type PersistableActor, type RoomActorStub, type RoomCoordinatorDefinition, type RoomEmitOptions, type RoomHandlerClass, type RoomMember, type RpcBroadcastOptions, type SafePersistOptions, type ServerMessage, type VeraniEnv, type VeraniMessage, clearPersistedState, createConnectionHandler, createRoomHandler, decodeClientMessage, decodeFrame, decodeServerMessage, defineConnection, deletePersistedKey, enableDebug, encodeClientMessage, encodeFrame, encodeServerMessage, getPersistedKeys, getPersistedState, initializePersistedState, isStateReady, persistKey, safeDeserialize, safeSerialize, setPeristErrorHandler, setPersistErrorHandler, storeAttachment };
package/dist/verani.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as ServerMessage, i as PROTOCOL_VERSION, n as ConnectionMeta, o as VeraniMessage, r as MessageFrame, t as ClientMessage } from "./types-6m1L8QLb.mjs";
2
2
  import { a as encodeFrame, i as encodeClientMessage, n as decodeFrame, o as encodeServerMessage, r as decodeServerMessage, t as decodeClientMessage } from "./decode-DwdLTFvb.mjs";
3
- import { c as AsyncEmitBuilder, d as ConnectionActorStub, f as ConnectionEmit, g as VeraniEnv, h as RpcBroadcastOptions, i as ConnectionHandlerClass, l as BroadcastOptions, m as RoomMember, n as ConnectionDefinition, o as createConnectionHandler, p as RoomCoordinatorDefinition, r as ConnectionDefinitionWithHandlers, s as defineConnection, t as ConnectionContext, u as ConnectionActor } from "./connection-actor-CtqCgN3y.mjs";
3
+ import { _ as VeraniEnv, c as AsyncEmitBuilder, d as ConnectionActorStub, f as ConnectionEmit, g as RpcBroadcastOptions, h as RoomMember, i as ConnectionHandlerClass, l as BroadcastOptions, m as RoomEmitOptions, n as ConnectionDefinition, o as createConnectionHandler, p as RoomCoordinatorDefinition, r as ConnectionDefinitionWithHandlers, s as defineConnection, t as ConnectionContext, u as ConnectionActor } from "./connection-actor-D1QRniw1.mjs";
4
4
  import { Actor } from "@cloudflare/actors";
5
5
 
6
6
  //#region src/actor/room-actor.d.ts
@@ -135,4 +135,4 @@ declare function deletePersistedKey(actor: PersistableActor, key: string): Promi
135
135
  declare function getPersistedKeys(actor: PersistableActor): Promise<string[]>;
136
136
  declare function clearPersistedState(actor: PersistableActor): Promise<void>;
137
137
  //#endregion
138
- export { type AsyncEmitBuilder, type BroadcastOptions, type ClientMessage, type ConnectionActor, type ConnectionActorStub, type ConnectionContext, type ConnectionDefinition, type ConnectionDefinitionWithHandlers, type ConnectionEmit, type ConnectionHandlerClass, type ConnectionMeta, type MessageFrame, PROTOCOL_VERSION, PersistError, PersistNotReadyError, type PersistableActor, type RoomActorStub, type RoomCoordinatorDefinition, type RoomHandlerClass, type RoomMember, type RpcBroadcastOptions, type SafePersistOptions, type ServerMessage, type VeraniEnv, type VeraniMessage, clearPersistedState, createConnectionHandler, createRoomHandler, decodeClientMessage, decodeFrame, decodeServerMessage, defineConnection, deletePersistedKey, enableDebug, encodeClientMessage, encodeFrame, encodeServerMessage, getPersistedKeys, getPersistedState, initializePersistedState, isStateReady, persistKey, safeDeserialize, safeSerialize, setPeristErrorHandler, setPersistErrorHandler, storeAttachment };
138
+ export { type AsyncEmitBuilder, type BroadcastOptions, type ClientMessage, type ConnectionActor, type ConnectionActorStub, type ConnectionContext, type ConnectionDefinition, type ConnectionDefinitionWithHandlers, type ConnectionEmit, type ConnectionHandlerClass, type ConnectionMeta, type MessageFrame, PROTOCOL_VERSION, PersistError, PersistNotReadyError, type PersistableActor, type RoomActorStub, type RoomCoordinatorDefinition, type RoomEmitOptions, type RoomHandlerClass, type RoomMember, type RpcBroadcastOptions, type SafePersistOptions, type ServerMessage, type VeraniEnv, type VeraniMessage, clearPersistedState, createConnectionHandler, createRoomHandler, decodeClientMessage, decodeFrame, decodeServerMessage, defineConnection, deletePersistedKey, enableDebug, encodeClientMessage, encodeFrame, encodeServerMessage, getPersistedKeys, getPersistedState, initializePersistedState, isStateReady, persistKey, safeDeserialize, safeSerialize, setPeristErrorHandler, setPersistErrorHandler, storeAttachment };
package/dist/verani.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import{a as clearPersistedState,c as getPersistedState,d as persistKey,f as safeDeserialize,g as storeAttachment,h as setPersistErrorHandler,i as PersistNotReadyError,l as initializePersistedState,m as setPeristErrorHandler,n as defineConnection,o as deletePersistedKey,p as safeSerialize,r as PersistError,s as getPersistedKeys,t as createConnectionHandler,u as isStateReady}from"./connection-actor-CVS554hv.mjs";import{a as decodeFrame,i as decodeClientMessage,n as encodeFrame,o as decodeServerMessage,r as encodeServerMessage,t as encodeClientMessage}from"./encode-CFndA-BQ.mjs";import{t as PROTOCOL_VERSION}from"./types-rZsftNPE.mjs";import{Actor}from"@cloudflare/actors";const MEMBERS=Symbol(`MEMBERS`),ROOM_NAME=Symbol(`ROOM_NAME`),DELIVERY_FAILURES=Symbol(`DELIVERY_FAILURES`);function createRoomHandler(e={}){let b=e.name||`VeraniRoomDO`;class x extends Actor{constructor(...e){super(...e),this[MEMBERS]=new Map,this[ROOM_NAME]=``,this[DELIVERY_FAILURES]=new Map,this.roomState={}}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in RoomCoordinatorDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let b=this.env[e.connectionBinding];if(!b)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return b}async onInit(){this.ensureTables(),await this.migrateFromKV(),this.loadMembers(),this.loadRoomState(),e.onInit&&await e.onInit(this.roomState)}ensureTables(){this.sql`CREATE TABLE IF NOT EXISTS room_members (
1
+ import{a as clearPersistedState,c as getPersistedState,d as persistKey,f as safeDeserialize,g as storeAttachment,h as setPersistErrorHandler,i as PersistNotReadyError,l as initializePersistedState,m as setPeristErrorHandler,n as defineConnection,o as deletePersistedKey,p as safeSerialize,r as PersistError,s as getPersistedKeys,t as createConnectionHandler,u as isStateReady}from"./connection-actor-B5AzPIkG.mjs";import{a as decodeFrame,i as decodeClientMessage,n as encodeFrame,o as decodeServerMessage,r as encodeServerMessage,t as encodeClientMessage}from"./encode-CFndA-BQ.mjs";import{t as PROTOCOL_VERSION}from"./types-rZsftNPE.mjs";import{Actor}from"@cloudflare/actors";const MEMBERS=Symbol(`MEMBERS`),ROOM_NAME=Symbol(`ROOM_NAME`),DELIVERY_FAILURES=Symbol(`DELIVERY_FAILURES`);function createRoomHandler(e={}){let b=e.name||`VeraniRoomDO`;class x extends Actor{constructor(...e){super(...e),this[MEMBERS]=new Map,this[ROOM_NAME]=``,this[DELIVERY_FAILURES]=new Map,this.roomState={}}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in RoomCoordinatorDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let b=this.env[e.connectionBinding];if(!b)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return b}async onInit(){this.ensureTables(),await this.migrateFromKV(),this.loadMembers(),this.loadRoomState(),e.onInit&&await e.onInit(this.roomState)}ensureTables(){this.sql`CREATE TABLE IF NOT EXISTS room_members (
2
2
  user_id TEXT PRIMARY KEY,
3
3
  joined_at INTEGER NOT NULL,
4
4
  metadata TEXT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "verani",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "A simple, focused realtime SDK for Cloudflare Actors with Socket.io-like semantics",
5
5
  "license": "ISC",
6
6
  "workspaces": [
@@ -1 +0,0 @@
1
- const require_encode=require(`./encode-SjZrKIyU.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);function storeAttachment(e,f){e.serializeAttachment(f)}function encodeFrame(f){return require_encode.n(f)}const PERSIST_ERROR_HANDLER=Symbol(`PERSIST_ERROR_HANDLER`),PERSISTED_STATE=Symbol(`PERSISTED_STATE`),STATE_READY=Symbol(`STATE_READY`);var PersistNotReadyError=class extends Error{constructor(e){super(`Cannot access persisted state key "${e}" before storage is initialized. Wait for onInit to complete or check actor.isStateReady().`),this.name=`PersistNotReadyError`}},PersistError=class extends Error{constructor(e,f){super(`Failed to persist key "${e}": ${f.message}`),this.name=`PersistError`,this.originalCause=f}};function safeSerialize(e){let f=new WeakSet;return JSON.stringify(e,(e,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(f.has(p))return;f.add(p)}if(!(typeof p==`function`||typeof p==`symbol`))return p})}function safeDeserialize(e){return JSON.parse(e,(e,f)=>{if(f&&typeof f==`object`&&f.__type)switch(f.__type){case`Date`:return new Date(f.value);case`RegExp`:return new RegExp(f.source,f.flags);case`Map`:return new Map(f.entries);case`Set`:return new Set(f.values);case`Error`:{let e=Error(f.message);return e.name=f.name,e}}return f})}function createShallowProxy(e,f,p){return new Proxy(e,{set(e,p,m){let h=Reflect.set(e,p,m);return h&&typeof p==`string`&&f(p,m),h},deleteProperty(e,f){let m=Reflect.deleteProperty(e,f);return m&&typeof f==`string`&&p(f),m}})}async function initializePersistedState(e,f,p=[],m={}){let{shallow:v=!0,throwOnError:b=!0}=m,x=e.ctx.storage,S=p.length>0?p.map(String):Object.keys(f),C={...f};for(let e of S)try{let f=await x.get(`_verani_persist:${e}`);if(f!==void 0)try{C[e]=safeDeserialize(f)}catch(f){if(b)throw new PersistError(e,f)}}catch(f){if(b&&!(f instanceof PersistError))throw new PersistError(e,f)}let w=async(f,p)=>{if(S.includes(f))try{let e=safeSerialize(p);await x.put(`_verani_persist:${f}`,e)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},T=async f=>{if(S.includes(f))try{await x.delete(`_verani_persist:${f}`)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},E;return E=v?createShallowProxy(C,(e,f)=>{w(String(e),f)},e=>{T(String(e))}):createDeepProxy(C,(e,f)=>{w(e,f)},e=>{T(e)},S),e[STATE_READY]=!0,e[PERSISTED_STATE]=E,E}function createDeepProxy(e,f,p,m,h,g){return new Proxy(e,{get(_,v){let y=Reflect.get(_,v);if(y&&typeof y==`object`&&!Array.isArray(y)){let _=g??String(v);if(m.includes(_)||g!==void 0)return createDeepProxy(y,f,p,m,h??e,_)}return y},set(e,p,_){let v=Reflect.set(e,p,_);if(v){let e=g??String(p);m.includes(e)&&(g&&h?f(g,h[g]):f(String(p),_))}return v},deleteProperty(e,_){let v=Reflect.deleteProperty(e,_);if(v){let e=g??String(_);m.includes(e)&&(g&&h?f(g,h[g]):p(String(_)))}return v}})}function isStateReady(e){return e[STATE_READY]===!0}function getPersistedState(e){if(!isStateReady(e))throw new PersistNotReadyError(`state`);return e[PERSISTED_STATE]}function setPersistErrorHandler(e,f){e[PERSIST_ERROR_HANDLER]=f}const setPeristErrorHandler=setPersistErrorHandler;async function persistKey(e,f,p){let m=safeSerialize(p);await e.ctx.storage.put(`_verani_persist:${f}`,m)}async function deletePersistedKey(e,f){await e.ctx.storage.delete(`_verani_persist:${f}`)}async function getPersistedKeys(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`});return Array.from(f.keys()).map(e=>e.replace(`_verani_persist:`,``))}async function clearPersistedState(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`}),p=Array.from(f.keys());await e.ctx.storage.delete(p)}const WS=Symbol(`WS`),META=Symbol(`META`),ROOMS=Symbol(`ROOMS`);function createConnectionHandler(e){let h=e.name||`VeraniConnectionDO`,v=e.websocketPath||`/ws`;class y extends __cloudflare_actors.Actor{constructor(...f){super(...f),this[WS]=null,this[META]=null,this[ROOMS]=new Map,this[STATE_READY]=!1,this[PERSISTED_STATE]=e.state?{...e.state}:{},this.handlers=new Map}get connectionState(){return this[PERSISTED_STATE]}isStateReady(){return isStateReady(this)}static configuration(e){return{sockets:{upgradePath:v}}}getRoomBinding(f){if(!e.rooms)throw Error(`Cannot access room "${f}": no "rooms" config provided in ConnectionDefinition. Add rooms: { "${f}": "YourRoomBinding" } to your definition.`);let p=e.rooms[f];if(!p)throw Error(`Cannot access room "${f}": not found in "rooms" config. Available rooms: ${Object.keys(e.rooms).join(`, `)}`);let m=this.env[p];if(!m)throw Error(`Room "${f}" binding "${p}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return m}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in ConnectionDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let f=this.env[e.connectionBinding];if(!f)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return f}createEmit(){let e=this;return{emit(f,p){e.sendToWebSocket(f,p)},to(f){return f.startsWith(`room:`)?e.createRoomEmitBuilder(f.slice(5)):e.createUserEmitBuilder(f)},toRoom(f){return e.createRoomEmitBuilder(f)},toUser(f){return e.createUserEmitBuilder(f)}}}createRoomEmitBuilder(e){let f=this;return{async emit(p,m){try{let h=f.getRoomBinding(e).get(e),g={exceptUserId:f[META]?.userId};return await h.broadcast(p,m,g)}catch{return 0}}}}createUserEmitBuilder(e){let f=this;return{async emit(p,m){try{return await f.getConnectionBinding().get(e).deliverMessage(p,m)?1:0}catch{return 0}}}}sendToWebSocket(e,f){let p=this[WS];if(!p||p.readyState!==WebSocket.OPEN)return!1;try{let h={type:`event`,channel:`default`,data:{type:e,...f}};return p.send(encodeFrame(h)),!0}catch{return!1}}createContext(){return{actor:this,ws:this[WS],meta:this[META],emit:this.createEmit(),state:this.connectionState}}async onInit(){e.state&&(e.onPersistError&&setPeristErrorHandler(this,e.onPersistError),this[PERSISTED_STATE]=await initializePersistedState(this,e.state,e.persistedKeys,e.persistOptions));let f=await this.ctx.storage.get(`_connection_rooms`);if(f&&Array.isArray(f)&&(this[ROOMS]=new Map(f.map(e=>[e.roomName,e.metadata]))),e.handlers)for(let[f,p]of e.handlers.entries())this.handlers.set(f,p);let p=this.ctx.getWebSockets();if(p.length>0){let f=p[0];if(f.readyState===WebSocket.OPEN){this[WS]=f;let p=f.deserializeAttachment();p&&(this[META]=p,await this.rejoinRoomsAfterHibernation(),e.onHibernationRestore&&await e.onHibernationRestore(this))}}}shouldUpgradeSocket(e){return!0}onWebSocketUpgrade(e){let f=new WebSocketPair,[p,m]=Object.values(f);this.ctx.acceptWebSocket(m);let h=new Response(null,{status:101,webSocket:p});return Promise.resolve().then(()=>{this.onWebSocketConnect(m,e)}),h}async onWebSocketConnect(f,m){this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`New connection established`);let h;if(h=e.extractMeta?await e.extractMeta(m):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(f,h),this[WS]=f,this[META]=h,e.onConnect)try{await e.onConnect(this.createContext())}catch(p){e.onError&&await e.onError(p,this.createContext()),f.close(1011,`Connection handler error`);return}}async onWebSocketMessage(f,p){if(this[META])try{let f=typeof p==`string`?p:p.toString(),m=JSON.parse(f),h=m,g=h.data,_=g?.type||h.type,v=this.handlers.get(_);if(v){await v(this.createContext(),g);return}e.onMessage&&await e.onMessage(this.createContext(),m)}catch(f){e.onError&&await e.onError(f,this.createContext())}}async onWebSocketDisconnect(f){if(this[META]&&e.onDisconnect)try{await e.onDisconnect(this.createContext())}catch{}for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]=null}async deliverMessage(e,f){return this.sendToWebSocket(e,f)}async deliverSystemEvent(e,f){this.sendToWebSocket(`system:${e}`,f)}async getUserId(){return this[META]?.userId??null}async isConnected(){return this[WS]!==null&&this[WS].readyState===WebSocket.OPEN}async joinRoom(e,f){if(!this[META])throw Error(`Cannot join room: not connected`);await this.getRoomBinding(e).get(e).join(this[META].userId,f),this[ROOMS].set(e,f),await this.persistRooms()}async persistRooms(){let e=Array.from(this[ROOMS].entries()).map(([e,f])=>({roomName:e,metadata:f}));await this.ctx.storage.put(`_connection_rooms`,e)}async rejoinRoomsAfterHibernation(){if(this[ROOMS].size===0)return;let e=this[META]?.userId;if(!e)return;let f=[];for(let[p,m]of this[ROOMS].entries())try{await this.getRoomBinding(p).get(p).join(e,m)}catch{f.push(p)}if(f.length>0){for(let e of f)this[ROOMS].delete(e);await this.persistRooms()}}async leaveRoomInternal(e){this[META]&&await this.getRoomBinding(e).get(e).leave(this[META].userId)}async leaveRoom(e){if(!this[META])throw Error(`Cannot leave room: not connected`);await this.leaveRoomInternal(e),this[ROOMS].delete(e),await this.persistRooms()}async getRooms(){return Array.from(this[ROOMS].keys())}getStorage(){return this.ctx.storage}on(e,f){this.handlers.set(e,f)}off(e){this.handlers.delete(e)}async destroy(){for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`Actor destroyed`),e.onDestroy&&this[META]&&await e.onDestroy(this.createContext()),await super.destroy()}}return Object.defineProperty(y,`name`,{value:h,writable:!1,configurable:!0}),y}function defineConnection(e){let f=new Map;return{...e,handlers:f,on(e,p){f.set(e,p)},off(e){f.delete(e)}}}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return clearPersistedState}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return getPersistedState}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return persistKey}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return safeDeserialize}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return storeAttachment}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return setPersistErrorHandler}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return PersistNotReadyError}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return initializePersistedState}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return setPeristErrorHandler}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return defineConnection}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return deletePersistedKey}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return safeSerialize}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return PersistError}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return getPersistedKeys}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return createConnectionHandler}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return isStateReady}});
@@ -1 +0,0 @@
1
- import{n as encodeFrame$1}from"./encode-CFndA-BQ.mjs";import{Actor}from"@cloudflare/actors";function storeAttachment(e,f){e.serializeAttachment(f)}function encodeFrame(f){return encodeFrame$1(f)}const PERSIST_ERROR_HANDLER=Symbol(`PERSIST_ERROR_HANDLER`),PERSISTED_STATE=Symbol(`PERSISTED_STATE`),STATE_READY=Symbol(`STATE_READY`);var PersistNotReadyError=class extends Error{constructor(e){super(`Cannot access persisted state key "${e}" before storage is initialized. Wait for onInit to complete or check actor.isStateReady().`),this.name=`PersistNotReadyError`}},PersistError=class extends Error{constructor(e,f){super(`Failed to persist key "${e}": ${f.message}`),this.name=`PersistError`,this.originalCause=f}};function safeSerialize(e){let f=new WeakSet;return JSON.stringify(e,(e,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(f.has(p))return;f.add(p)}if(!(typeof p==`function`||typeof p==`symbol`))return p})}function safeDeserialize(e){return JSON.parse(e,(e,f)=>{if(f&&typeof f==`object`&&f.__type)switch(f.__type){case`Date`:return new Date(f.value);case`RegExp`:return new RegExp(f.source,f.flags);case`Map`:return new Map(f.entries);case`Set`:return new Set(f.values);case`Error`:{let e=Error(f.message);return e.name=f.name,e}}return f})}function createShallowProxy(e,f,p){return new Proxy(e,{set(e,p,m){let h=Reflect.set(e,p,m);return h&&typeof p==`string`&&f(p,m),h},deleteProperty(e,f){let m=Reflect.deleteProperty(e,f);return m&&typeof f==`string`&&p(f),m}})}async function initializePersistedState(e,f,p=[],m={}){let{shallow:v=!0,throwOnError:b=!0}=m,x=e.ctx.storage,S=p.length>0?p.map(String):Object.keys(f),C={...f};for(let e of S)try{let f=await x.get(`_verani_persist:${e}`);if(f!==void 0)try{C[e]=safeDeserialize(f)}catch(f){if(b)throw new PersistError(e,f)}}catch(f){if(b&&!(f instanceof PersistError))throw new PersistError(e,f)}let w=async(f,p)=>{if(S.includes(f))try{let e=safeSerialize(p);await x.put(`_verani_persist:${f}`,e)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},T=async f=>{if(S.includes(f))try{await x.delete(`_verani_persist:${f}`)}catch(p){let m=e[PERSIST_ERROR_HANDLER];if(m&&m(f,p),b)throw new PersistError(f,p)}},E;return E=v?createShallowProxy(C,(e,f)=>{w(String(e),f)},e=>{T(String(e))}):createDeepProxy(C,(e,f)=>{w(e,f)},e=>{T(e)},S),e[STATE_READY]=!0,e[PERSISTED_STATE]=E,E}function createDeepProxy(e,f,p,m,h,g){return new Proxy(e,{get(_,v){let y=Reflect.get(_,v);if(y&&typeof y==`object`&&!Array.isArray(y)){let _=g??String(v);if(m.includes(_)||g!==void 0)return createDeepProxy(y,f,p,m,h??e,_)}return y},set(e,p,_){let v=Reflect.set(e,p,_);if(v){let e=g??String(p);m.includes(e)&&(g&&h?f(g,h[g]):f(String(p),_))}return v},deleteProperty(e,_){let v=Reflect.deleteProperty(e,_);if(v){let e=g??String(_);m.includes(e)&&(g&&h?f(g,h[g]):p(String(_)))}return v}})}function isStateReady(e){return e[STATE_READY]===!0}function getPersistedState(e){if(!isStateReady(e))throw new PersistNotReadyError(`state`);return e[PERSISTED_STATE]}function setPersistErrorHandler(e,f){e[PERSIST_ERROR_HANDLER]=f}const setPeristErrorHandler=setPersistErrorHandler;async function persistKey(e,f,p){let m=safeSerialize(p);await e.ctx.storage.put(`_verani_persist:${f}`,m)}async function deletePersistedKey(e,f){await e.ctx.storage.delete(`_verani_persist:${f}`)}async function getPersistedKeys(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`});return Array.from(f.keys()).map(e=>e.replace(`_verani_persist:`,``))}async function clearPersistedState(e){let f=await e.ctx.storage.list({prefix:`_verani_persist:`}),p=Array.from(f.keys());await e.ctx.storage.delete(p)}const WS=Symbol(`WS`),META=Symbol(`META`),ROOMS=Symbol(`ROOMS`);function createConnectionHandler(e){let h=e.name||`VeraniConnectionDO`,v=e.websocketPath||`/ws`;class y extends Actor{constructor(...f){super(...f),this[WS]=null,this[META]=null,this[ROOMS]=new Map,this[STATE_READY]=!1,this[PERSISTED_STATE]=e.state?{...e.state}:{},this.handlers=new Map}get connectionState(){return this[PERSISTED_STATE]}isStateReady(){return isStateReady(this)}static configuration(e){return{sockets:{upgradePath:v}}}getRoomBinding(f){if(!e.rooms)throw Error(`Cannot access room "${f}": no "rooms" config provided in ConnectionDefinition. Add rooms: { "${f}": "YourRoomBinding" } to your definition.`);let p=e.rooms[f];if(!p)throw Error(`Cannot access room "${f}": not found in "rooms" config. Available rooms: ${Object.keys(e.rooms).join(`, `)}`);let m=this.env[p];if(!m)throw Error(`Room "${f}" binding "${p}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return m}getConnectionBinding(){if(!e.connectionBinding)throw Error(`Cannot resolve ConnectionDO: no "connectionBinding" provided in ConnectionDefinition. Add connectionBinding: "YourConnectionBinding" to your definition.`);let f=this.env[e.connectionBinding];if(!f)throw Error(`ConnectionDO binding "${e.connectionBinding}" not found in environment. Check your wrangler.toml durable_objects bindings.`);return f}createEmit(){let e=this;return{emit(f,p){e.sendToWebSocket(f,p)},to(f){return f.startsWith(`room:`)?e.createRoomEmitBuilder(f.slice(5)):e.createUserEmitBuilder(f)},toRoom(f){return e.createRoomEmitBuilder(f)},toUser(f){return e.createUserEmitBuilder(f)}}}createRoomEmitBuilder(e){let f=this;return{async emit(p,m){try{let h=f.getRoomBinding(e).get(e),g={exceptUserId:f[META]?.userId};return await h.broadcast(p,m,g)}catch{return 0}}}}createUserEmitBuilder(e){let f=this;return{async emit(p,m){try{return await f.getConnectionBinding().get(e).deliverMessage(p,m)?1:0}catch{return 0}}}}sendToWebSocket(e,f){let p=this[WS];if(!p||p.readyState!==WebSocket.OPEN)return!1;try{let h={type:`event`,channel:`default`,data:{type:e,...f}};return p.send(encodeFrame(h)),!0}catch{return!1}}createContext(){return{actor:this,ws:this[WS],meta:this[META],emit:this.createEmit(),state:this.connectionState}}async onInit(){e.state&&(e.onPersistError&&setPeristErrorHandler(this,e.onPersistError),this[PERSISTED_STATE]=await initializePersistedState(this,e.state,e.persistedKeys,e.persistOptions));let f=await this.ctx.storage.get(`_connection_rooms`);if(f&&Array.isArray(f)&&(this[ROOMS]=new Map(f.map(e=>[e.roomName,e.metadata]))),e.handlers)for(let[f,p]of e.handlers.entries())this.handlers.set(f,p);let p=this.ctx.getWebSockets();if(p.length>0){let f=p[0];if(f.readyState===WebSocket.OPEN){this[WS]=f;let p=f.deserializeAttachment();p&&(this[META]=p,await this.rejoinRoomsAfterHibernation(),e.onHibernationRestore&&await e.onHibernationRestore(this))}}}shouldUpgradeSocket(e){return!0}onWebSocketUpgrade(e){let f=new WebSocketPair,[p,m]=Object.values(f);this.ctx.acceptWebSocket(m);let h=new Response(null,{status:101,webSocket:p});return Promise.resolve().then(()=>{this.onWebSocketConnect(m,e)}),h}async onWebSocketConnect(f,m){this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`New connection established`);let h;if(h=e.extractMeta?await e.extractMeta(m):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(f,h),this[WS]=f,this[META]=h,e.onConnect)try{await e.onConnect(this.createContext())}catch(p){e.onError&&await e.onError(p,this.createContext()),f.close(1011,`Connection handler error`);return}}async onWebSocketMessage(f,p){if(this[META])try{let f=typeof p==`string`?p:p.toString(),m=JSON.parse(f),h=m,g=h.data,_=g?.type||h.type,v=this.handlers.get(_);if(v){await v(this.createContext(),g);return}e.onMessage&&await e.onMessage(this.createContext(),m)}catch(f){e.onError&&await e.onError(f,this.createContext())}}async onWebSocketDisconnect(f){if(this[META]&&e.onDisconnect)try{await e.onDisconnect(this.createContext())}catch{}for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]=null}async deliverMessage(e,f){return this.sendToWebSocket(e,f)}async deliverSystemEvent(e,f){this.sendToWebSocket(`system:${e}`,f)}async getUserId(){return this[META]?.userId??null}async isConnected(){return this[WS]!==null&&this[WS].readyState===WebSocket.OPEN}async joinRoom(e,f){if(!this[META])throw Error(`Cannot join room: not connected`);await this.getRoomBinding(e).get(e).join(this[META].userId,f),this[ROOMS].set(e,f),await this.persistRooms()}async persistRooms(){let e=Array.from(this[ROOMS].entries()).map(([e,f])=>({roomName:e,metadata:f}));await this.ctx.storage.put(`_connection_rooms`,e)}async rejoinRoomsAfterHibernation(){if(this[ROOMS].size===0)return;let e=this[META]?.userId;if(!e)return;let f=[];for(let[p,m]of this[ROOMS].entries())try{await this.getRoomBinding(p).get(p).join(e,m)}catch{f.push(p)}if(f.length>0){for(let e of f)this[ROOMS].delete(e);await this.persistRooms()}}async leaveRoomInternal(e){this[META]&&await this.getRoomBinding(e).get(e).leave(this[META].userId)}async leaveRoom(e){if(!this[META])throw Error(`Cannot leave room: not connected`);await this.leaveRoomInternal(e),this[ROOMS].delete(e),await this.persistRooms()}async getRooms(){return Array.from(this[ROOMS].keys())}getStorage(){return this.ctx.storage}on(e,f){this.handlers.set(e,f)}off(e){this.handlers.delete(e)}async destroy(){for(let e of this[ROOMS].keys())try{await this.leaveRoomInternal(e)}catch{}this[WS]&&this[WS].readyState===WebSocket.OPEN&&this[WS].close(1e3,`Actor destroyed`),e.onDestroy&&this[META]&&await e.onDestroy(this.createContext()),await super.destroy()}}return Object.defineProperty(y,`name`,{value:h,writable:!1,configurable:!0}),y}function defineConnection(e){let f=new Map;return{...e,handlers:f,on(e,p){f.set(e,p)},off(e){f.delete(e)}}}export{clearPersistedState as a,getPersistedState as c,persistKey as d,safeDeserialize as f,storeAttachment as g,setPersistErrorHandler as h,PersistNotReadyError as i,initializePersistedState as l,setPeristErrorHandler as m,defineConnection as n,deletePersistedKey as o,safeSerialize as p,PersistError as r,getPersistedKeys as s,createConnectionHandler as t,isStateReady as u};