verani 0.4.1 → 0.4.3
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 +74 -28
- package/dist/verani.cjs +1 -1
- package/dist/verani.d.cts +2 -2
- package/dist/verani.d.mts +2 -2
- package/dist/verani.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,28 +40,30 @@ export const chatRoom = defineRoom({
|
|
|
40
40
|
|
|
41
41
|
onConnect(ctx) {
|
|
42
42
|
console.log(`User ${ctx.meta.userId} connected`);
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// Use emit API (socket.io-like)
|
|
44
|
+
ctx.actor.emit.to("default").emit("user.joined", {
|
|
45
45
|
userId: ctx.meta.userId
|
|
46
46
|
});
|
|
47
47
|
},
|
|
48
48
|
|
|
49
|
-
onMessage(ctx, frame) {
|
|
50
|
-
if (frame.type === "chat.message") {
|
|
51
|
-
// Broadcast to everyone except sender
|
|
52
|
-
ctx.actor.broadcast("default", {
|
|
53
|
-
type: "chat.message",
|
|
54
|
-
from: ctx.meta.userId,
|
|
55
|
-
text: frame.data.text
|
|
56
|
-
}, { except: ctx.ws });
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
|
|
60
49
|
onDisconnect(ctx) {
|
|
61
50
|
console.log(`User ${ctx.meta.userId} disconnected`);
|
|
51
|
+
ctx.actor.emit.to("default").emit("user.left", {
|
|
52
|
+
userId: ctx.meta.userId
|
|
53
|
+
});
|
|
62
54
|
}
|
|
63
55
|
});
|
|
64
56
|
|
|
57
|
+
// Register event handlers (socket.io-like, recommended)
|
|
58
|
+
chatRoom.on("chat.message", (ctx, data) => {
|
|
59
|
+
// Broadcast to all in default channel
|
|
60
|
+
ctx.actor.emit.to("default").emit("chat.message", {
|
|
61
|
+
from: ctx.meta.userId,
|
|
62
|
+
text: data.text,
|
|
63
|
+
timestamp: Date.now()
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
65
67
|
// Create the Durable Object class
|
|
66
68
|
export const ChatRoom = createActorHandler(chatRoom);
|
|
67
69
|
```
|
|
@@ -99,14 +101,27 @@ The three-way relationship:
|
|
|
99
101
|
```typescript
|
|
100
102
|
import { VeraniClient } from "verani";
|
|
101
103
|
|
|
102
|
-
// Connect to your Cloudflare Worker
|
|
103
|
-
const client = new VeraniClient("wss://your-worker.dev/ws?userId=alice"
|
|
104
|
+
// Connect to your Cloudflare Worker with ping/pong keepalive
|
|
105
|
+
const client = new VeraniClient("wss://your-worker.dev/ws?userId=alice", {
|
|
106
|
+
pingInterval: 5000, // Send ping every 5 seconds
|
|
107
|
+
pongTimeout: 5000, // Expect pong within 5 seconds
|
|
108
|
+
reconnection: {
|
|
109
|
+
enabled: true,
|
|
110
|
+
maxAttempts: 10,
|
|
111
|
+
initialDelay: 1000,
|
|
112
|
+
maxDelay: 30000
|
|
113
|
+
}
|
|
114
|
+
});
|
|
104
115
|
|
|
105
116
|
// Listen for messages
|
|
106
117
|
client.on("chat.message", (data) => {
|
|
107
118
|
console.log(`${data.from}: ${data.text}`);
|
|
108
119
|
});
|
|
109
120
|
|
|
121
|
+
client.on("user.joined", (data) => {
|
|
122
|
+
console.log(`User ${data.userId} joined`);
|
|
123
|
+
});
|
|
124
|
+
|
|
110
125
|
// Send messages
|
|
111
126
|
client.emit("chat.message", { text: "Hello, world!" });
|
|
112
127
|
|
|
@@ -118,6 +133,10 @@ client.onOpen(() => {
|
|
|
118
133
|
client.onStateChange((state) => {
|
|
119
134
|
console.log("Connection state:", state);
|
|
120
135
|
});
|
|
136
|
+
|
|
137
|
+
// Wait for connection before sending
|
|
138
|
+
await client.waitForConnection();
|
|
139
|
+
client.emit("ready", {});
|
|
121
140
|
```
|
|
122
141
|
|
|
123
142
|
## Key Concepts
|
|
@@ -135,8 +154,11 @@ Each Cloudflare Actor instance represents a **logical container** for realtime c
|
|
|
135
154
|
Inside an Actor, connections can join **channels** for selective message routing:
|
|
136
155
|
|
|
137
156
|
```typescript
|
|
138
|
-
// Server: broadcast to specific channel
|
|
139
|
-
ctx.actor.
|
|
157
|
+
// Server: broadcast to specific channel using emit API
|
|
158
|
+
ctx.actor.emit.to("game-updates").emit("update", data);
|
|
159
|
+
|
|
160
|
+
// Or send to a specific user (all their sessions)
|
|
161
|
+
ctx.emit.to("alice").emit("notification", { message: "Hello!" });
|
|
140
162
|
|
|
141
163
|
// Client: joins "default" channel automatically
|
|
142
164
|
// You can implement join/leave for custom channels
|
|
@@ -152,37 +174,61 @@ Verani handles Cloudflare's hibernation automatically:
|
|
|
152
174
|
|
|
153
175
|
## Documentation
|
|
154
176
|
|
|
155
|
-
- **[Getting Started](./docs/
|
|
156
|
-
- **[
|
|
157
|
-
- **[
|
|
158
|
-
- **[Examples](./docs/
|
|
159
|
-
- **[
|
|
160
|
-
- **[
|
|
177
|
+
- **[Getting Started](./docs/getting-started/)** - Installation and quick start guide
|
|
178
|
+
- **[API Reference](./docs/api/)** - Complete server and client API documentation
|
|
179
|
+
- **[Guides](./docs/guides/)** - Configuration, deployment, scaling, and RPC
|
|
180
|
+
- **[Examples](./docs/examples/)** - Common usage patterns and code samples
|
|
181
|
+
- **[Concepts](./docs/concepts/)** - Architecture, hibernation, and core concepts
|
|
182
|
+
- **[Security](./docs/security/)** - Authentication, authorization, and best practices
|
|
161
183
|
|
|
162
184
|
## Features
|
|
163
185
|
|
|
164
186
|
### Server (Actor) Side
|
|
165
187
|
|
|
166
|
-
-
|
|
188
|
+
- **Socket.io-like event handlers** - `room.on()` and `room.off()` for clean event handling
|
|
189
|
+
- **Emit API** - `ctx.emit` and `ctx.actor.emit.to()` for intuitive message sending
|
|
190
|
+
- Room-based architecture with lifecycle hooks (`onConnect`, `onDisconnect`, `onHibernationRestore`)
|
|
167
191
|
- WebSocket attachment management for hibernation
|
|
168
|
-
- Selective broadcasting with filters
|
|
192
|
+
- Selective broadcasting with filters (userIds, clientIds, except)
|
|
169
193
|
- User and client ID tracking
|
|
170
194
|
- **RPC methods** - Call Actor methods remotely from Workers or other Actors
|
|
195
|
+
- Durable Object storage access for persistent state
|
|
171
196
|
- Error boundaries and logging
|
|
172
197
|
- Flexible metadata extraction from requests
|
|
173
198
|
|
|
174
199
|
### Client Side
|
|
175
200
|
|
|
176
201
|
- Automatic reconnection with exponential backoff
|
|
177
|
-
- Connection state management
|
|
202
|
+
- Connection state management (`getState()`, `getConnectionState()`, `isConnecting`)
|
|
178
203
|
- Message queueing when disconnected
|
|
179
204
|
- Event-based API (on/off/once/emit)
|
|
180
|
-
- Promise-based connection waiting
|
|
181
|
-
- Lifecycle callbacks
|
|
205
|
+
- Promise-based connection waiting (`waitForConnection()`)
|
|
206
|
+
- Lifecycle callbacks (`onOpen`, `onClose`, `onError`, `onStateChange`)
|
|
182
207
|
- **Ping/pong keepalive** with automatic Page Visibility API resync
|
|
208
|
+
- Configurable connection timeout and queue size
|
|
183
209
|
|
|
184
210
|
### RPC Support
|
|
185
211
|
|
|
212
|
+
Call Actor methods remotely from Workers or other Actors:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// In your Worker fetch handler
|
|
216
|
+
const stub = ChatRoom.get("room-id");
|
|
217
|
+
|
|
218
|
+
// Send to user
|
|
219
|
+
await stub.sendToUser("alice", "notifications", {
|
|
220
|
+
type: "alert",
|
|
221
|
+
message: "You have a new message"
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Broadcast to channel
|
|
225
|
+
await stub.broadcast("default", { type: "announcement", text: "Hello!" });
|
|
226
|
+
|
|
227
|
+
// Query state
|
|
228
|
+
const count = await stub.getSessionCount();
|
|
229
|
+
const userIds = await stub.getConnectedUserIds();
|
|
230
|
+
```
|
|
231
|
+
|
|
186
232
|
- Send messages to users from HTTP endpoints
|
|
187
233
|
- Query actor state remotely
|
|
188
234
|
- Broadcast from external events or scheduled tasks
|
package/dist/verani.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const require_types=require(`./types-083oWz55.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(e,x){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(x)}off(e,x){let S=this.handlers.get(e);S&&(x?(S.delete(x),S.size===0&&this.handlers.delete(e)):this.handlers.delete(e))}async emit(e,x,S){let C=this.handlers.get(e);if(C&&C.size>0){let e=[];for(let w of C)try{let C=w(x,S);C instanceof Promise&&e.push(C)}catch{}await Promise.all(e)}let w=this.handlers.get(`*`);if(w&&w.size>0){let e=[];for(let C of w)try{let w=C(x,S);w instanceof Promise&&e.push(w)}catch{}await Promise.all(e)}}hasHandlers(e){return this.handlers.has(e)&&this.handlers.get(e).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(e){let x=crypto.randomUUID(),S=crypto.randomUUID(),C=new URL(e.url).searchParams.get(`channels`);return{userId:x,clientId:S,channels:C?C.split(`,`).map(e=>e.trim()).filter(Boolean):[`default`]}}function defineRoom(e){let x=e.eventEmitter||createRoomEventEmitter();return{name:e.name,websocketPath:e.websocketPath,extractMeta:e.extractMeta||defaultExtractMeta,onConnect:e.onConnect,onDisconnect:e.onDisconnect,onMessage:e.onMessage,onError:e.onError,onHibernationRestore:e.onHibernationRestore,eventEmitter:x,on(e,S){x.on(e,S)},off(e,S){x.off(e,S)}}}function cleanupStaleSessions(e){let x=0,S=[];for(let[x,C]of e.entries())x.readyState!==WebSocket.OPEN&&S.push(x);for(let C of S)e.delete(C),x++;return x}function decodeFrame$1(x){return require_types.o(x)??{type:`invalid`}}function encodeFrame$1(x){return require_types.r(x)}function broadcast(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:x,data:S}),E=[];for(let{ws:S,meta:D}of e.values())if(D.channels.includes(x)&&!(C?.except&&S===C.except)&&!(C?.userIds&&!C.userIds.includes(D.userId))&&!(C?.clientIds&&!C.clientIds.includes(D.clientId))){if(S.readyState!==WebSocket.OPEN){E.push(S);continue}try{S.send(T),w++}catch{E.push(S)}}for(let x of E)e.delete(x);return E.length,w}function sendToUser(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:S,data:C}),E=[];for(let{ws:C,meta:D}of e.values())if(D.userId===x&&D.channels.includes(S)){if(C.readyState!==WebSocket.OPEN){E.push(C);continue}try{C.send(T),w++}catch{E.push(C)}}for(let x of E)e.delete(x);return E.length,w}function getSessionCount(e){return e.size}function getConnectedUserIds(e){let x=new Set;for(let{meta:S}of e.values())x.add(S.userId);return Array.from(x)}function getUserSessions(e,x){let S=[];for(let{ws:C,meta:w}of e.values())w.userId===x&&S.push(C);return S}function getStorage(e){return e.storage}function sanitizeToClassName(e){return e.replace(/^\/+/,``).split(/[-_\/\s]+/).map(e=>e.replace(/[^a-zA-Z0-9]/g,``)).filter(e=>e.length>0).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(e){return function(x){return{locationHint:`me`,sockets:{upgradePath:e.websocketPath}}}}function isValidConnectionMeta(e){return!(!e||typeof e!=`object`||typeof e.userId!=`string`||!e.userId||typeof e.clientId!=`string`||!e.clientId||!Array.isArray(e.channels)||!e.channels.every(e=>typeof e==`string`))}function storeAttachment(e,x){e.serializeAttachment(x)}function restoreSessions(e){let x=0,S=0;for(let C of e.ctx.getWebSockets()){if(C.readyState!==WebSocket.OPEN){S++;continue}let w=C.deserializeAttachment();if(!w){S++;continue}if(!isValidConnectionMeta(w)){S++;continue}e.sessions.set(C,{ws:C,meta:w}),x++}}async function onInit(e,x){try{restoreSessions(e)}catch{}if(x.onHibernationRestore&&e.sessions.size>0)try{await x.onHibernationRestore(e)}catch{}else x.onHibernationRestore&&e.sessions.size}function createUserEmitBuilder(e,x,S){return{emit(C,w){return sendToUser(x,e,S,{type:C,...w})}}}function createChannelEmitBuilder(e,x,S){return{emit(C,w){return broadcast(x,e,{type:C,...w},S)}}}function createSocketEmit(e){let x=e.meta.channels[0]||`default`;return{emit(S,C){if(e.ws.readyState===WebSocket.OPEN)try{let w={type:`event`,channel:x,data:{type:S,...C}};e.ws.send(encodeFrame$1(w))}catch{}},to(S){return e.meta.channels.includes(S)?createChannelEmitBuilder(S,e.actor.sessions,{except:e.ws}):createUserEmitBuilder(S,e.actor.sessions,x)}}}function createActorEmit(e){return{emit(x,S){let C={type:x,...S};return broadcast(e.sessions,`default`,C)},to(x){return createChannelEmitBuilder(x,e.sessions)}}}async function onWebSocketConnect(e,x,S,C){let w;try{w=x.extractMeta?await x.extractMeta(C):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(S,w);let T={actor:e,ws:S,meta:w,frame:{type:`connect`}};if(x.onConnect){let C={actor:e,ws:S,meta:w,emit:createSocketEmit(T)};await x.onConnect(C)}e.sessions.set(S,{ws:S,meta:w})}catch(C){if(x.onError&&w)try{let T={actor:e,ws:S,meta:w,frame:{type:`error`}};await x.onError(C,{actor:e,ws:S,meta:w,emit:createSocketEmit(T)})}catch{}S.close(1011,`Internal server error`)}}async function onWebSocketMessage(e,x,S,C){let w;try{let T=decodeFrame$1(C);if(T&&T.type===`ping`){if(S.readyState===WebSocket.OPEN)try{S.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!T||T.type===`invalid`||(w=e.sessions.get(S),!w))return;let E={actor:e,ws:S,meta:w.meta,frame:T,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:T})},O=x.eventEmitter;O&&O.hasHandlers&&O.hasHandlers(T.type)?await O.emit(T.type,E,T.data||{}):x.onMessage&&await x.onMessage(E,T)}catch(C){if(x.onError&&w)try{await x.onError(C,{actor:e,ws:S,meta:w.meta,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(e,x,S){try{let C=e.sessions.get(S);if(e.sessions.delete(S),C&&x.onDisconnect){let w={actor:e,ws:S,meta:C.meta,frame:{type:`disconnect`}},T={actor:e,ws:S,meta:C.meta,emit:createSocketEmit(w)};await x.onDisconnect(T)}}catch{}}function createActorHandler(e){let S=sanitizeToClassName(e.name||e.websocketPath||`VeraniActor`);class C extends __cloudflare_actors.Actor{constructor(...e){super(...e),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(e)}async shouldUpgradeWebSocket(e){return!0}async fetch(x){let S=new URL(x.url),C=x.headers.get(`Upgrade`);return S.pathname===e.websocketPath&&C===`websocket`&&await this.shouldUpgradeWebSocket(x)?this.onWebSocketUpgrade(x):this.onRequest(x)}async onInit(){await onInit(this,e)}async onWebSocketConnect(x,S){await onWebSocketConnect(this,e,x,S)}async onWebSocketMessage(x,S){await onWebSocketMessage(this,e,x,S)}async onWebSocketDisconnect(x){await onWebSocketDisconnect(this,e,x)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(e,x,S){return broadcast(this.sessions,e,x,S)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(e){return getUserSessions(this.sessions,e)}sendToUser(e,x,S){return sendToUser(this.sessions,e,x,S)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(C,`name`,{value:S,writable:!1,configurable:!0}),C}exports.PROTOCOL_VERSION=require_types.t,exports.createActorHandler=createActorHandler,exports.decodeClientMessage=require_types.a,exports.decodeFrame=require_types.o,exports.decodeServerMessage=require_types.s,exports.defineRoom=defineRoom,exports.encodeClientMessage=require_types.n,exports.encodeFrame=require_types.r,exports.encodeServerMessage=require_types.i,exports.restoreSessions=restoreSessions,exports.storeAttachment=storeAttachment;
|
|
1
|
+
const require_types=require(`./types-083oWz55.cjs`);let __cloudflare_actors=require(`@cloudflare/actors`);var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(e,x){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(x)}off(e,x){let S=this.handlers.get(e);S&&(x?(S.delete(x),S.size===0&&this.handlers.delete(e)):this.handlers.delete(e))}async emit(e,x,S){let C=this.handlers.get(e);if(C&&C.size>0){let e=[];for(let w of C)try{let C=w(x,S);C instanceof Promise&&e.push(C)}catch{}await Promise.all(e)}let w=this.handlers.get(`*`);if(w&&w.size>0){let e=[];for(let C of w)try{let w=C(x,S);w instanceof Promise&&e.push(w)}catch{}await Promise.all(e)}}hasHandlers(e){return this.handlers.has(e)&&this.handlers.get(e).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(e){let x=crypto.randomUUID(),S=crypto.randomUUID(),C=new URL(e.url).searchParams.get(`channels`);return{userId:x,clientId:S,channels:C?C.split(`,`).map(e=>e.trim()).filter(Boolean):[`default`]}}function defineRoom(e){let x=e.eventEmitter||createRoomEventEmitter();return{name:e.name,websocketPath:e.websocketPath,extractMeta:e.extractMeta||(e=>defaultExtractMeta(e)),onConnect:e.onConnect,onDisconnect:e.onDisconnect,onMessage:e.onMessage,onError:e.onError,onHibernationRestore:e.onHibernationRestore,eventEmitter:x,on(e,S){x.on(e,S)},off(e,S){x.off(e,S)}}}function cleanupStaleSessions(e){let x=0,S=[];for(let[x,C]of e.entries())x.readyState!==WebSocket.OPEN&&S.push(x);for(let C of S)e.delete(C),x++;return x}function decodeFrame$1(x){return require_types.o(x)??{type:`invalid`}}function encodeFrame$1(x){return require_types.r(x)}function broadcast(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:x,data:S}),E=[];for(let{ws:S,meta:D}of e.values())if(D.channels.includes(x)&&!(C?.except&&S===C.except)&&!(C?.userIds&&!C.userIds.includes(D.userId))&&!(C?.clientIds&&!C.clientIds.includes(D.clientId))){if(S.readyState!==WebSocket.OPEN){E.push(S);continue}try{S.send(T),w++}catch{E.push(S)}}for(let x of E)e.delete(x);return E.length,w}function sendToUser(e,x,S,C){let w=0,T=encodeFrame$1({type:`event`,channel:S,data:C}),E=[];for(let{ws:C,meta:D}of e.values())if(D.userId===x&&D.channels.includes(S)){if(C.readyState!==WebSocket.OPEN){E.push(C);continue}try{C.send(T),w++}catch{E.push(C)}}for(let x of E)e.delete(x);return E.length,w}function getSessionCount(e){return e.size}function getConnectedUserIds(e){let x=new Set;for(let{meta:S}of e.values())x.add(S.userId);return Array.from(x)}function getUserSessions(e,x){let S=[];for(let{ws:C,meta:w}of e.values())w.userId===x&&S.push(C);return S}function getStorage(e){return e.storage}function sanitizeToClassName(e){return e.replace(/^\/+/,``).split(/[-_\/\s]+/).map(e=>e.replace(/[^a-zA-Z0-9]/g,``)).filter(e=>e.length>0).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(e){return function(x){return{locationHint:`me`,sockets:{upgradePath:e.websocketPath}}}}function isValidConnectionMeta(e){return!(!e||typeof e!=`object`||typeof e.userId!=`string`||!e.userId||typeof e.clientId!=`string`||!e.clientId||!Array.isArray(e.channels)||!e.channels.every(e=>typeof e==`string`))}function storeAttachment(e,x){e.serializeAttachment(x)}function restoreSessions(e){let x=0,S=0;for(let C of e.ctx.getWebSockets()){if(C.readyState!==WebSocket.OPEN){S++;continue}let w=C.deserializeAttachment();if(!w){S++;continue}if(!isValidConnectionMeta(w)){S++;continue}e.sessions.set(C,{ws:C,meta:w}),x++}}async function onInit(e,x){try{restoreSessions(e)}catch{}if(x.onHibernationRestore&&e.sessions.size>0)try{await x.onHibernationRestore(e)}catch{}else x.onHibernationRestore&&e.sessions.size}function createUserEmitBuilder(e,x,S){return{emit(C,w){return sendToUser(x,e,S,{type:C,...w})}}}function createChannelEmitBuilder(e,x,S){return{emit(C,w){return broadcast(x,e,{type:C,...w},S)}}}function createSocketEmit(e){let x=e.meta.channels[0]||`default`;return{emit(S,C){if(e.ws.readyState===WebSocket.OPEN)try{let w={type:`event`,channel:x,data:{type:S,...C}};e.ws.send(encodeFrame$1(w))}catch{}},to(S){return e.meta.channels.includes(S)?createChannelEmitBuilder(S,e.actor.sessions,{except:e.ws}):createUserEmitBuilder(S,e.actor.sessions,x)}}}function createActorEmit(e){return{emit(x,S){let C={type:x,...S};return broadcast(e.sessions,`default`,C)},to(x){return createChannelEmitBuilder(x,e.sessions)}}}async function onWebSocketConnect(e,x,S,C){let w;try{w=x.extractMeta?await x.extractMeta(C):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(S,w);let T={actor:e,ws:S,meta:w,frame:{type:`connect`}};if(x.onConnect){let C={actor:e,ws:S,meta:w,emit:createSocketEmit(T)};await x.onConnect(C)}e.sessions.set(S,{ws:S,meta:w})}catch(C){if(x.onError&&w)try{let T={actor:e,ws:S,meta:w,frame:{type:`error`}};await x.onError(C,{actor:e,ws:S,meta:w,emit:createSocketEmit(T)})}catch{}S.close(1011,`Internal server error`)}}async function onWebSocketMessage(e,x,S,C){let w;try{let T=decodeFrame$1(C);if(T&&T.type===`ping`){if(S.readyState===WebSocket.OPEN)try{S.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!T||T.type===`invalid`||(w=e.sessions.get(S),!w))return;let E={actor:e,ws:S,meta:w.meta,frame:T,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:T})},O=x.eventEmitter;O&&O.hasHandlers&&O.hasHandlers(T.type)?await O.emit(T.type,E,T.data||{}):x.onMessage&&await x.onMessage(E,T)}catch(C){if(x.onError&&w)try{await x.onError(C,{actor:e,ws:S,meta:w.meta,emit:createSocketEmit({actor:e,ws:S,meta:w.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(e,x,S){try{let C=e.sessions.get(S);if(e.sessions.delete(S),C&&x.onDisconnect){let w={actor:e,ws:S,meta:C.meta,frame:{type:`disconnect`}},T={actor:e,ws:S,meta:C.meta,emit:createSocketEmit(w)};await x.onDisconnect(T)}}catch{}}function createActorHandler(e){let S=sanitizeToClassName(e.name||e.websocketPath||`VeraniActor`);class C extends __cloudflare_actors.Actor{constructor(...e){super(...e),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(e)}async shouldUpgradeWebSocket(e){return!0}async fetch(x){let S=new URL(x.url),C=x.headers.get(`Upgrade`);return S.pathname===e.websocketPath&&C===`websocket`&&await this.shouldUpgradeWebSocket(x)?this.onWebSocketUpgrade(x):this.onRequest(x)}async onInit(){await onInit(this,e)}async onWebSocketConnect(x,S){await onWebSocketConnect(this,e,x,S)}async onWebSocketMessage(x,S){await onWebSocketMessage(this,e,x,S)}async onWebSocketDisconnect(x){await onWebSocketDisconnect(this,e,x)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(e,x,S){return broadcast(this.sessions,e,x,S)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(e){return getUserSessions(this.sessions,e)}sendToUser(e,x,S){return sendToUser(this.sessions,e,x,S)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(C,`name`,{value:S,writable:!1,configurable:!0}),C}exports.PROTOCOL_VERSION=require_types.t,exports.createActorHandler=createActorHandler,exports.decodeClientMessage=require_types.a,exports.decodeFrame=require_types.o,exports.decodeServerMessage=require_types.s,exports.defineRoom=defineRoom,exports.encodeClientMessage=require_types.n,exports.encodeFrame=require_types.r,exports.encodeServerMessage=require_types.i,exports.restoreSessions=restoreSessions,exports.storeAttachment=storeAttachment;
|
package/dist/verani.d.cts
CHANGED
|
@@ -249,13 +249,13 @@ interface RoomDefinitionWithHandlers<TMeta extends ConnectionMeta = ConnectionMe
|
|
|
249
249
|
* @param event - Event name
|
|
250
250
|
* @param handler - Handler function
|
|
251
251
|
*/
|
|
252
|
-
on(event: string, handler:
|
|
252
|
+
on(event: string, handler: EventHandler<TMeta, E>): void;
|
|
253
253
|
/**
|
|
254
254
|
* Remove an event handler (socket.io-like API)
|
|
255
255
|
* @param event - Event name
|
|
256
256
|
* @param handler - Optional specific handler to remove
|
|
257
257
|
*/
|
|
258
|
-
off(event: string, handler?:
|
|
258
|
+
off(event: string, handler?: EventHandler<TMeta, E>): void;
|
|
259
259
|
}
|
|
260
260
|
/**
|
|
261
261
|
* Defines a room with lifecycle hooks and metadata extraction
|
package/dist/verani.d.mts
CHANGED
|
@@ -249,13 +249,13 @@ interface RoomDefinitionWithHandlers<TMeta extends ConnectionMeta = ConnectionMe
|
|
|
249
249
|
* @param event - Event name
|
|
250
250
|
* @param handler - Handler function
|
|
251
251
|
*/
|
|
252
|
-
on(event: string, handler:
|
|
252
|
+
on(event: string, handler: EventHandler<TMeta, E>): void;
|
|
253
253
|
/**
|
|
254
254
|
* Remove an event handler (socket.io-like API)
|
|
255
255
|
* @param event - Event name
|
|
256
256
|
* @param handler - Optional specific handler to remove
|
|
257
257
|
*/
|
|
258
|
-
off(event: string, handler?:
|
|
258
|
+
off(event: string, handler?: EventHandler<TMeta, E>): void;
|
|
259
259
|
}
|
|
260
260
|
/**
|
|
261
261
|
* Defines a room with lifecycle hooks and metadata extraction
|
package/dist/verani.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as decodeClientMessage,i as encodeServerMessage,n as encodeClientMessage,o as decodeFrame,r as encodeFrame,s as decodeServerMessage,t as PROTOCOL_VERSION}from"./types-CJLnZrA8.mjs";import{Actor}from"@cloudflare/actors";var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(u,O){this.handlers.has(u)||this.handlers.set(u,new Set),this.handlers.get(u).add(O)}off(u,O){let k=this.handlers.get(u);k&&(O?(k.delete(O),k.size===0&&this.handlers.delete(u)):this.handlers.delete(u))}async emit(u,O,k){let A=this.handlers.get(u);if(A&&A.size>0){let u=[];for(let j of A)try{let A=j(O,k);A instanceof Promise&&u.push(A)}catch{}await Promise.all(u)}let j=this.handlers.get(`*`);if(j&&j.size>0){let u=[];for(let A of j)try{let j=A(O,k);j instanceof Promise&&u.push(j)}catch{}await Promise.all(u)}}hasHandlers(u){return this.handlers.has(u)&&this.handlers.get(u).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(u){let O=crypto.randomUUID(),k=crypto.randomUUID(),A=new URL(u.url).searchParams.get(`channels`);return{userId:O,clientId:k,channels:A?A.split(`,`).map(u=>u.trim()).filter(Boolean):[`default`]}}function defineRoom(u){let O=u.eventEmitter||createRoomEventEmitter();return{name:u.name,websocketPath:u.websocketPath,extractMeta:u.extractMeta||defaultExtractMeta,onConnect:u.onConnect,onDisconnect:u.onDisconnect,onMessage:u.onMessage,onError:u.onError,onHibernationRestore:u.onHibernationRestore,eventEmitter:O,on(u,k){O.on(u,k)},off(u,k){O.off(u,k)}}}function cleanupStaleSessions(u){let O=0,k=[];for(let[O,A]of u.entries())O.readyState!==WebSocket.OPEN&&k.push(O);for(let A of k)u.delete(A),O++;return O}function decodeFrame$1(u){return decodeFrame(u)??{type:`invalid`}}function encodeFrame$1(u){return encodeFrame(u)}function broadcast(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:O,data:k}),N=[];for(let{ws:k,meta:P}of u.values())if(P.channels.includes(O)&&!(A?.except&&k===A.except)&&!(A?.userIds&&!A.userIds.includes(P.userId))&&!(A?.clientIds&&!A.clientIds.includes(P.clientId))){if(k.readyState!==WebSocket.OPEN){N.push(k);continue}try{k.send(M),j++}catch{N.push(k)}}for(let O of N)u.delete(O);return N.length,j}function sendToUser(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:k,data:A}),N=[];for(let{ws:A,meta:P}of u.values())if(P.userId===O&&P.channels.includes(k)){if(A.readyState!==WebSocket.OPEN){N.push(A);continue}try{A.send(M),j++}catch{N.push(A)}}for(let O of N)u.delete(O);return N.length,j}function getSessionCount(u){return u.size}function getConnectedUserIds(u){let O=new Set;for(let{meta:k}of u.values())O.add(k.userId);return Array.from(O)}function getUserSessions(u,O){let k=[];for(let{ws:A,meta:j}of u.values())j.userId===O&&k.push(A);return k}function getStorage(u){return u.storage}function sanitizeToClassName(u){return u.replace(/^\/+/,``).split(/[-_\/\s]+/).map(u=>u.replace(/[^a-zA-Z0-9]/g,``)).filter(u=>u.length>0).map(u=>u.charAt(0).toUpperCase()+u.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(u){return function(O){return{locationHint:`me`,sockets:{upgradePath:u.websocketPath}}}}function isValidConnectionMeta(u){return!(!u||typeof u!=`object`||typeof u.userId!=`string`||!u.userId||typeof u.clientId!=`string`||!u.clientId||!Array.isArray(u.channels)||!u.channels.every(u=>typeof u==`string`))}function storeAttachment(u,O){u.serializeAttachment(O)}function restoreSessions(u){let O=0,k=0;for(let A of u.ctx.getWebSockets()){if(A.readyState!==WebSocket.OPEN){k++;continue}let j=A.deserializeAttachment();if(!j){k++;continue}if(!isValidConnectionMeta(j)){k++;continue}u.sessions.set(A,{ws:A,meta:j}),O++}}async function onInit(u,O){try{restoreSessions(u)}catch{}if(O.onHibernationRestore&&u.sessions.size>0)try{await O.onHibernationRestore(u)}catch{}else O.onHibernationRestore&&u.sessions.size}function createUserEmitBuilder(u,O,k){return{emit(A,j){return sendToUser(O,u,k,{type:A,...j})}}}function createChannelEmitBuilder(u,O,k){return{emit(A,j){return broadcast(O,u,{type:A,...j},k)}}}function createSocketEmit(u){let O=u.meta.channels[0]||`default`;return{emit(k,A){if(u.ws.readyState===WebSocket.OPEN)try{let j={type:`event`,channel:O,data:{type:k,...A}};u.ws.send(encodeFrame$1(j))}catch{}},to(k){return u.meta.channels.includes(k)?createChannelEmitBuilder(k,u.actor.sessions,{except:u.ws}):createUserEmitBuilder(k,u.actor.sessions,O)}}}function createActorEmit(u){return{emit(O,k){let A={type:O,...k};return broadcast(u.sessions,`default`,A)},to(O){return createChannelEmitBuilder(O,u.sessions)}}}async function onWebSocketConnect(u,O,k,A){let j;try{j=O.extractMeta?await O.extractMeta(A):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(k,j);let M={actor:u,ws:k,meta:j,frame:{type:`connect`}};if(O.onConnect){let A={actor:u,ws:k,meta:j,emit:createSocketEmit(M)};await O.onConnect(A)}u.sessions.set(k,{ws:k,meta:j})}catch(A){if(O.onError&&j)try{let M={actor:u,ws:k,meta:j,frame:{type:`error`}};await O.onError(A,{actor:u,ws:k,meta:j,emit:createSocketEmit(M)})}catch{}k.close(1011,`Internal server error`)}}async function onWebSocketMessage(u,O,k,A){let j;try{let M=decodeFrame$1(A);if(M&&M.type===`ping`){if(k.readyState===WebSocket.OPEN)try{k.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!M||M.type===`invalid`||(j=u.sessions.get(k),!j))return;let N={actor:u,ws:k,meta:j.meta,frame:M,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:M})},P=O.eventEmitter;P&&P.hasHandlers&&P.hasHandlers(M.type)?await P.emit(M.type,N,M.data||{}):O.onMessage&&await O.onMessage(N,M)}catch(A){if(O.onError&&j)try{await O.onError(A,{actor:u,ws:k,meta:j.meta,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(u,O,k){try{let A=u.sessions.get(k);if(u.sessions.delete(k),A&&O.onDisconnect){let j={actor:u,ws:k,meta:A.meta,frame:{type:`disconnect`}},M={actor:u,ws:k,meta:A.meta,emit:createSocketEmit(j)};await O.onDisconnect(M)}}catch{}}function createActorHandler(u){let O=sanitizeToClassName(u.name||u.websocketPath||`VeraniActor`);class k extends Actor{constructor(...u){super(...u),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(u)}async shouldUpgradeWebSocket(u){return!0}async fetch(O){let k=new URL(O.url),A=O.headers.get(`Upgrade`);return k.pathname===u.websocketPath&&A===`websocket`&&await this.shouldUpgradeWebSocket(O)?this.onWebSocketUpgrade(O):this.onRequest(O)}async onInit(){await onInit(this,u)}async onWebSocketConnect(O,k){await onWebSocketConnect(this,u,O,k)}async onWebSocketMessage(O,k){await onWebSocketMessage(this,u,O,k)}async onWebSocketDisconnect(O){await onWebSocketDisconnect(this,u,O)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(u,O,k){return broadcast(this.sessions,u,O,k)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(u){return getUserSessions(this.sessions,u)}sendToUser(u,O,k){return sendToUser(this.sessions,u,O,k)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(k,`name`,{value:O,writable:!1,configurable:!0}),k}export{PROTOCOL_VERSION,createActorHandler,decodeClientMessage,decodeFrame,decodeServerMessage,defineRoom,encodeClientMessage,encodeFrame,encodeServerMessage,restoreSessions,storeAttachment};
|
|
1
|
+
import{a as decodeClientMessage,i as encodeServerMessage,n as encodeClientMessage,o as decodeFrame,r as encodeFrame,s as decodeServerMessage,t as PROTOCOL_VERSION}from"./types-CJLnZrA8.mjs";import{Actor}from"@cloudflare/actors";var RoomEventEmitterImpl=class{constructor(){this.handlers=new Map}on(u,O){this.handlers.has(u)||this.handlers.set(u,new Set),this.handlers.get(u).add(O)}off(u,O){let k=this.handlers.get(u);k&&(O?(k.delete(O),k.size===0&&this.handlers.delete(u)):this.handlers.delete(u))}async emit(u,O,k){let A=this.handlers.get(u);if(A&&A.size>0){let u=[];for(let j of A)try{let A=j(O,k);A instanceof Promise&&u.push(A)}catch{}await Promise.all(u)}let j=this.handlers.get(`*`);if(j&&j.size>0){let u=[];for(let A of j)try{let j=A(O,k);j instanceof Promise&&u.push(j)}catch{}await Promise.all(u)}}hasHandlers(u){return this.handlers.has(u)&&this.handlers.get(u).size>0||this.handlers.has(`*`)&&this.handlers.get(`*`).size>0}getEventNames(){return Array.from(this.handlers.keys())}};function createRoomEventEmitter(){return new RoomEventEmitterImpl}function defaultExtractMeta(u){let O=crypto.randomUUID(),k=crypto.randomUUID(),A=new URL(u.url).searchParams.get(`channels`);return{userId:O,clientId:k,channels:A?A.split(`,`).map(u=>u.trim()).filter(Boolean):[`default`]}}function defineRoom(u){let O=u.eventEmitter||createRoomEventEmitter();return{name:u.name,websocketPath:u.websocketPath,extractMeta:u.extractMeta||(u=>defaultExtractMeta(u)),onConnect:u.onConnect,onDisconnect:u.onDisconnect,onMessage:u.onMessage,onError:u.onError,onHibernationRestore:u.onHibernationRestore,eventEmitter:O,on(u,k){O.on(u,k)},off(u,k){O.off(u,k)}}}function cleanupStaleSessions(u){let O=0,k=[];for(let[O,A]of u.entries())O.readyState!==WebSocket.OPEN&&k.push(O);for(let A of k)u.delete(A),O++;return O}function decodeFrame$1(u){return decodeFrame(u)??{type:`invalid`}}function encodeFrame$1(u){return encodeFrame(u)}function broadcast(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:O,data:k}),N=[];for(let{ws:k,meta:P}of u.values())if(P.channels.includes(O)&&!(A?.except&&k===A.except)&&!(A?.userIds&&!A.userIds.includes(P.userId))&&!(A?.clientIds&&!A.clientIds.includes(P.clientId))){if(k.readyState!==WebSocket.OPEN){N.push(k);continue}try{k.send(M),j++}catch{N.push(k)}}for(let O of N)u.delete(O);return N.length,j}function sendToUser(u,O,k,A){let j=0,M=encodeFrame$1({type:`event`,channel:k,data:A}),N=[];for(let{ws:A,meta:P}of u.values())if(P.userId===O&&P.channels.includes(k)){if(A.readyState!==WebSocket.OPEN){N.push(A);continue}try{A.send(M),j++}catch{N.push(A)}}for(let O of N)u.delete(O);return N.length,j}function getSessionCount(u){return u.size}function getConnectedUserIds(u){let O=new Set;for(let{meta:k}of u.values())O.add(k.userId);return Array.from(O)}function getUserSessions(u,O){let k=[];for(let{ws:A,meta:j}of u.values())j.userId===O&&k.push(A);return k}function getStorage(u){return u.storage}function sanitizeToClassName(u){return u.replace(/^\/+/,``).split(/[-_\/\s]+/).map(u=>u.replace(/[^a-zA-Z0-9]/g,``)).filter(u=>u.length>0).map(u=>u.charAt(0).toUpperCase()+u.slice(1).toLowerCase()).join(``)||`VeraniActor`}function createConfiguration(u){return function(O){return{locationHint:`me`,sockets:{upgradePath:u.websocketPath}}}}function isValidConnectionMeta(u){return!(!u||typeof u!=`object`||typeof u.userId!=`string`||!u.userId||typeof u.clientId!=`string`||!u.clientId||!Array.isArray(u.channels)||!u.channels.every(u=>typeof u==`string`))}function storeAttachment(u,O){u.serializeAttachment(O)}function restoreSessions(u){let O=0,k=0;for(let A of u.ctx.getWebSockets()){if(A.readyState!==WebSocket.OPEN){k++;continue}let j=A.deserializeAttachment();if(!j){k++;continue}if(!isValidConnectionMeta(j)){k++;continue}u.sessions.set(A,{ws:A,meta:j}),O++}}async function onInit(u,O){try{restoreSessions(u)}catch{}if(O.onHibernationRestore&&u.sessions.size>0)try{await O.onHibernationRestore(u)}catch{}else O.onHibernationRestore&&u.sessions.size}function createUserEmitBuilder(u,O,k){return{emit(A,j){return sendToUser(O,u,k,{type:A,...j})}}}function createChannelEmitBuilder(u,O,k){return{emit(A,j){return broadcast(O,u,{type:A,...j},k)}}}function createSocketEmit(u){let O=u.meta.channels[0]||`default`;return{emit(k,A){if(u.ws.readyState===WebSocket.OPEN)try{let j={type:`event`,channel:O,data:{type:k,...A}};u.ws.send(encodeFrame$1(j))}catch{}},to(k){return u.meta.channels.includes(k)?createChannelEmitBuilder(k,u.actor.sessions,{except:u.ws}):createUserEmitBuilder(k,u.actor.sessions,O)}}}function createActorEmit(u){return{emit(O,k){let A={type:O,...k};return broadcast(u.sessions,`default`,A)},to(O){return createChannelEmitBuilder(O,u.sessions)}}}async function onWebSocketConnect(u,O,k,A){let j;try{j=O.extractMeta?await O.extractMeta(A):{userId:`anonymous`,clientId:crypto.randomUUID(),channels:[`default`]},storeAttachment(k,j);let M={actor:u,ws:k,meta:j,frame:{type:`connect`}};if(O.onConnect){let A={actor:u,ws:k,meta:j,emit:createSocketEmit(M)};await O.onConnect(A)}u.sessions.set(k,{ws:k,meta:j})}catch(A){if(O.onError&&j)try{let M={actor:u,ws:k,meta:j,frame:{type:`error`}};await O.onError(A,{actor:u,ws:k,meta:j,emit:createSocketEmit(M)})}catch{}k.close(1011,`Internal server error`)}}async function onWebSocketMessage(u,O,k,A){let j;try{let M=decodeFrame$1(A);if(M&&M.type===`ping`){if(k.readyState===WebSocket.OPEN)try{k.send(encodeFrame$1({type:`pong`}))}catch{}return}if(!M||M.type===`invalid`||(j=u.sessions.get(k),!j))return;let N={actor:u,ws:k,meta:j.meta,frame:M,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:M})},P=O.eventEmitter;P&&P.hasHandlers&&P.hasHandlers(M.type)?await P.emit(M.type,N,M.data||{}):O.onMessage&&await O.onMessage(N,M)}catch(A){if(O.onError&&j)try{await O.onError(A,{actor:u,ws:k,meta:j.meta,emit:createSocketEmit({actor:u,ws:k,meta:j.meta,frame:{type:`error`}})})}catch{}}}async function onWebSocketDisconnect(u,O,k){try{let A=u.sessions.get(k);if(u.sessions.delete(k),A&&O.onDisconnect){let j={actor:u,ws:k,meta:A.meta,frame:{type:`disconnect`}},M={actor:u,ws:k,meta:A.meta,emit:createSocketEmit(j)};await O.onDisconnect(M)}}catch{}}function createActorHandler(u){let O=sanitizeToClassName(u.name||u.websocketPath||`VeraniActor`);class k extends Actor{constructor(...u){super(...u),this.sessions=new Map,this.emit=createActorEmit(this)}static{this.configuration=createConfiguration(u)}async shouldUpgradeWebSocket(u){return!0}async fetch(O){let k=new URL(O.url),A=O.headers.get(`Upgrade`);return k.pathname===u.websocketPath&&A===`websocket`&&await this.shouldUpgradeWebSocket(O)?this.onWebSocketUpgrade(O):this.onRequest(O)}async onInit(){await onInit(this,u)}async onWebSocketConnect(O,k){await onWebSocketConnect(this,u,O,k)}async onWebSocketMessage(O,k){await onWebSocketMessage(this,u,O,k)}async onWebSocketDisconnect(O){await onWebSocketDisconnect(this,u,O)}cleanupStaleSessions(){return cleanupStaleSessions(this.sessions)}broadcast(u,O,k){return broadcast(this.sessions,u,O,k)}getSessionCount(){return getSessionCount(this.sessions)}getConnectedUserIds(){return getConnectedUserIds(this.sessions)}getUserSessions(u){return getUserSessions(this.sessions,u)}sendToUser(u,O,k){return sendToUser(this.sessions,u,O,k)}getStorage(){return getStorage(this.ctx)}}return Object.defineProperty(k,`name`,{value:O,writable:!1,configurable:!0}),k}export{PROTOCOL_VERSION,createActorHandler,decodeClientMessage,decodeFrame,decodeServerMessage,defineRoom,encodeClientMessage,encodeFrame,encodeServerMessage,restoreSessions,storeAttachment};
|