dialogue-ts 0.0.1
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 +446 -0
- package/dist/client/index.cjs +393 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +273 -0
- package/dist/client/index.d.ts +273 -0
- package/dist/client/index.js +365 -0
- package/dist/client/index.js.map +1 -0
- package/dist/src/index.cjs +1424 -0
- package/dist/src/index.cjs.map +1 -0
- package/dist/src/index.d.cts +664 -0
- package/dist/src/index.d.ts +664 -0
- package/dist/src/index.js +1389 -0
- package/dist/src/index.js.map +1 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# Dialogue Ts
|
|
2
|
+
|
|
3
|
+
An event-based realtime communication library based on Socket.IO, Hono, and Bun.
|
|
4
|
+
|
|
5
|
+
Dialogue is basically asking how do we scale to different real time use cases using same mental model and api.
|
|
6
|
+
|
|
7
|
+
## 📚 Documentation
|
|
8
|
+
|
|
9
|
+
**[📖 View Full Documentation →](https://hussseinkizz.github.io/dialogue/)**
|
|
10
|
+
|
|
11
|
+
Complete guides, API references, and examples available at: **https://hussseinkizz.github.io/dialogue/**
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
- [Bun](https://bun.sh/) - Fast all-in-one JavaScript runtime (required for server)
|
|
16
|
+
- [Zod](https://zod.dev/) - TypeScript-first schema validation
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bun add dialogue-ts zod
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Key Concepts
|
|
25
|
+
|
|
26
|
+
### Events
|
|
27
|
+
|
|
28
|
+
Events are the core building blocks. Each event has a name and an optional Zod schema for validation:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { defineEvent } from "dialogue-ts";
|
|
32
|
+
import { z } from "zod";
|
|
33
|
+
|
|
34
|
+
const Message = defineEvent("message", {
|
|
35
|
+
schema: z.object({
|
|
36
|
+
text: z.string().min(1).max(1000),
|
|
37
|
+
senderId: z.string(),
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const Typing = defineEvent("typing", {
|
|
42
|
+
schema: z.object({ isTyping: z.boolean() }),
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Rooms
|
|
47
|
+
|
|
48
|
+
Rooms are channels where events are broadcast. Clients join rooms to send and receive events:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const dialogue = createDialogue({
|
|
52
|
+
port: 3000,
|
|
53
|
+
rooms: {
|
|
54
|
+
chat: {
|
|
55
|
+
name: "Chat Room",
|
|
56
|
+
events: [Message, Typing],
|
|
57
|
+
defaultSubscriptions: ["message"],
|
|
58
|
+
maxSize: 100, // Optional capacity limit
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Subscriptions
|
|
65
|
+
|
|
66
|
+
Clients can subscribe to specific event types within a room. Only subscribed events are received, reducing unnecessary traffic.
|
|
67
|
+
|
|
68
|
+
## Quick Start: Chat Example
|
|
69
|
+
|
|
70
|
+
### Server (Bun)
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// server.ts
|
|
74
|
+
import { createDialogue, defineEvent } from "dialogue-ts";
|
|
75
|
+
import { z } from "zod";
|
|
76
|
+
|
|
77
|
+
// Define events
|
|
78
|
+
const Message = defineEvent("message", {
|
|
79
|
+
schema: z.object({
|
|
80
|
+
text: z.string().min(1),
|
|
81
|
+
username: z.string(),
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const UserJoined = defineEvent("user-joined", {
|
|
86
|
+
schema: z.object({ username: z.string() }),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Create dialogue instance
|
|
90
|
+
const dialogue = createDialogue({
|
|
91
|
+
port: 3000,
|
|
92
|
+
rooms: {
|
|
93
|
+
general: {
|
|
94
|
+
name: "General Chat",
|
|
95
|
+
events: [Message, UserJoined],
|
|
96
|
+
defaultSubscriptions: ["message", "user-joined"],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
hooks: {
|
|
100
|
+
clients: {
|
|
101
|
+
onConnected: (client) => {
|
|
102
|
+
console.log(`Client connected: ${client.userId}`);
|
|
103
|
+
client.join("general");
|
|
104
|
+
|
|
105
|
+
// Notify others
|
|
106
|
+
dialogue.trigger("general", UserJoined, {
|
|
107
|
+
username: client.userId,
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
onDisconnected: (client) => {
|
|
111
|
+
console.log(`Client disconnected: ${client.userId}`);
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Start server
|
|
118
|
+
await dialogue.start();
|
|
119
|
+
console.log("Chat server running on http://localhost:3000");
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Run with:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bun run server.ts
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Client (Browser/Node)
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// client.ts
|
|
132
|
+
import { createDialogueClient } from "dialogue-ts/client";
|
|
133
|
+
|
|
134
|
+
const client = createDialogueClient({
|
|
135
|
+
url: "ws://localhost:3000",
|
|
136
|
+
auth: { userId: "alice" },
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Connect and join room
|
|
140
|
+
await client.connect();
|
|
141
|
+
const chat = await client.join("general");
|
|
142
|
+
|
|
143
|
+
// Listen for messages
|
|
144
|
+
chat.on("message", (msg) => {
|
|
145
|
+
console.log(`${msg.data.username}: ${msg.data.text}`);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Listen for users joining
|
|
149
|
+
chat.on("user-joined", (msg) => {
|
|
150
|
+
console.log(`${msg.data.username} joined the chat`);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Send a message
|
|
154
|
+
chat.trigger("message", {
|
|
155
|
+
text: "Hello everyone!",
|
|
156
|
+
username: "alice",
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Server API
|
|
161
|
+
|
|
162
|
+
### createDialogue(config)
|
|
163
|
+
|
|
164
|
+
Creates a Dialogue server instance.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const dialogue = createDialogue({
|
|
168
|
+
port: 3000,
|
|
169
|
+
rooms: { /* room configs */ },
|
|
170
|
+
hooks: {
|
|
171
|
+
clients: {
|
|
172
|
+
onConnected: (client) => { /* handle connection */ },
|
|
173
|
+
onDisconnected: (client) => { /* handle disconnection */ },
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
logger: createDefaultLogger(), // Optional custom logger
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### dialogue.start()
|
|
181
|
+
|
|
182
|
+
Starts the server. Returns a promise.
|
|
183
|
+
|
|
184
|
+
### dialogue.trigger(roomId, event, data, from?)
|
|
185
|
+
|
|
186
|
+
Triggers an event from the server to all subscribers in a room.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
dialogue.trigger("general", Message, { text: "Hello!", username: "system" });
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### dialogue.getRoom(roomId)
|
|
193
|
+
|
|
194
|
+
Gets a room instance for direct manipulation.
|
|
195
|
+
|
|
196
|
+
### dialogue.createRoom(id, config, createdById?)
|
|
197
|
+
|
|
198
|
+
Creates a new room at runtime.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const room = dialogue.createRoom("project-123", {
|
|
202
|
+
name: "Project Discussion",
|
|
203
|
+
events: [Message, UserJoined],
|
|
204
|
+
defaultSubscriptions: ["message"],
|
|
205
|
+
maxSize: 50,
|
|
206
|
+
}, "user-456");
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### dialogue.deleteRoom(id)
|
|
210
|
+
|
|
211
|
+
Deletes a room. Returns `true` if successful.
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
dialogue.deleteRoom("project-123");
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### User Management
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// Get all connections for a user
|
|
221
|
+
const clients = dialogue.getClients("user-123");
|
|
222
|
+
|
|
223
|
+
// Get rooms a user is in
|
|
224
|
+
const rooms = dialogue.getClientRooms("user-123");
|
|
225
|
+
|
|
226
|
+
// Check if user is in a room
|
|
227
|
+
if (dialogue.isInRoom("user-123", "vip-room")) { ... }
|
|
228
|
+
|
|
229
|
+
// Remove user from all rooms (with notifications)
|
|
230
|
+
dialogue.getClientRooms("user-123").leaveAll((roomId) => {
|
|
231
|
+
dialogue.trigger(roomId, UserLeft, { username: "user-123" });
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Client API
|
|
236
|
+
|
|
237
|
+
### DialogueClient
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
import { createDialogueClient } from "dialogue-ts/client";
|
|
241
|
+
|
|
242
|
+
const client = createDialogueClient({
|
|
243
|
+
url: "ws://localhost:3000",
|
|
244
|
+
auth: { userId: "user-123", token: "jwt-token" },
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### client.connect() / client.disconnect()
|
|
249
|
+
|
|
250
|
+
Connect to or disconnect from the server.
|
|
251
|
+
|
|
252
|
+
### client.join(roomId)
|
|
253
|
+
|
|
254
|
+
Joins a room and returns a `RoomContext`.
|
|
255
|
+
|
|
256
|
+
### client.createRoom(options)
|
|
257
|
+
|
|
258
|
+
Creates a new room on the server.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
const roomInfo = await client.createRoom({
|
|
262
|
+
id: "tech-talk",
|
|
263
|
+
name: "Tech Talk",
|
|
264
|
+
description: "Discuss technology",
|
|
265
|
+
maxSize: 100,
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### client.deleteRoom(roomId)
|
|
270
|
+
|
|
271
|
+
Deletes a room (only creator can delete).
|
|
272
|
+
|
|
273
|
+
### client.onRoomCreated(handler) / client.onRoomDeleted(handler)
|
|
274
|
+
|
|
275
|
+
Listen for room lifecycle events.
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
client.onRoomCreated((room) => console.log("New room:", room.name));
|
|
279
|
+
client.onRoomDeleted((roomId) => console.log("Deleted:", roomId));
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### RoomContext
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
const room = await client.join("chat");
|
|
286
|
+
|
|
287
|
+
// Listen for events
|
|
288
|
+
const unsubscribe = room.on("message", (msg) => {
|
|
289
|
+
console.log(msg.data);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Send events
|
|
293
|
+
room.trigger("message", { text: "Hello!" });
|
|
294
|
+
|
|
295
|
+
// Subscribe/unsubscribe from event types
|
|
296
|
+
room.subscribe("typing");
|
|
297
|
+
room.unsubscribe("typing");
|
|
298
|
+
|
|
299
|
+
// Leave room
|
|
300
|
+
room.leave();
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Hooks
|
|
304
|
+
|
|
305
|
+
Hooks provide lifecycle callbacks for clients, rooms, and events.
|
|
306
|
+
|
|
307
|
+
### Client Hooks
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
const dialogue = createDialogue({
|
|
311
|
+
rooms: { /* ... */ },
|
|
312
|
+
hooks: {
|
|
313
|
+
clients: {
|
|
314
|
+
onConnected: (client) => {
|
|
315
|
+
console.log(`${client.userId} connected`);
|
|
316
|
+
client.join("general");
|
|
317
|
+
},
|
|
318
|
+
onDisconnected: (client) => {
|
|
319
|
+
console.log(`${client.userId} disconnected`);
|
|
320
|
+
},
|
|
321
|
+
onJoined: (client, roomId) => {
|
|
322
|
+
dialogue.trigger(roomId, UserJoined, { username: client.userId });
|
|
323
|
+
},
|
|
324
|
+
onLeft: (client, roomId) => {
|
|
325
|
+
dialogue.trigger(roomId, UserLeft, { username: client.userId });
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Room Hooks
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
hooks: {
|
|
336
|
+
rooms: {
|
|
337
|
+
onCreated: (room) => {
|
|
338
|
+
console.log(`Room ${room.name} created`);
|
|
339
|
+
},
|
|
340
|
+
onDeleted: (roomId) => {
|
|
341
|
+
console.log(`Room ${roomId} deleted`);
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Event Hooks (for persistence)
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
hooks: {
|
|
351
|
+
events: {
|
|
352
|
+
onTriggered: (roomId, event) => {
|
|
353
|
+
// Called for every event
|
|
354
|
+
analytics.track(event.event, event.data);
|
|
355
|
+
},
|
|
356
|
+
onCleanup: async (roomId, eventName, events) => {
|
|
357
|
+
// Called when events are evicted from memory
|
|
358
|
+
await db.events.insertMany(events);
|
|
359
|
+
},
|
|
360
|
+
onLoad: async (roomId, eventName, start, end) => {
|
|
361
|
+
// Load historical events from database for pagination
|
|
362
|
+
return db.events.find({ roomId, eventName }).skip(start).limit(end - start);
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Event History
|
|
369
|
+
|
|
370
|
+
Store and retrieve historical events per room. Useful for chat history, activity feeds, etc.
|
|
371
|
+
|
|
372
|
+
### Enabling History
|
|
373
|
+
|
|
374
|
+
Enable history per event type:
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
const Message = defineEvent("message", {
|
|
378
|
+
schema: z.object({ text: z.string(), username: z.string() }),
|
|
379
|
+
history: { enabled: true, limit: 100 }, // Keep last 100 messages
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Auto-sync on Join
|
|
384
|
+
|
|
385
|
+
Automatically send history when clients join a room:
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
const dialogue = createDialogue({
|
|
389
|
+
rooms: {
|
|
390
|
+
chat: {
|
|
391
|
+
name: "Chat",
|
|
392
|
+
events: [Message],
|
|
393
|
+
syncHistoryOnJoin: true, // Send all history
|
|
394
|
+
// syncHistoryOnJoin: 50, // Or limit to 50 events
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Client-side History
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
// Automatic history on join
|
|
404
|
+
client.onHistory((roomId, events) => {
|
|
405
|
+
events.forEach((event) => renderMessage(event));
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Manual pagination
|
|
409
|
+
const room = await client.join("chat");
|
|
410
|
+
const olderMessages = await room.getHistory("message", 50, 100); // Skip 50, get 50
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Server-side History Access
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
const room = dialogue.room("chat");
|
|
417
|
+
const recentMessages = await room.history("message", 0, 20); // Last 20 messages
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Documentation
|
|
421
|
+
|
|
422
|
+
For complete documentation, visit **[hussseinkizz.github.io/dialogue](https://hussseinkizz.github.io/dialogue/)**
|
|
423
|
+
|
|
424
|
+
Quick links:
|
|
425
|
+
- [Getting Started](https://hussseinkizz.github.io/dialogue/guide/start/getting-started) - Installation and basic setup
|
|
426
|
+
- [Configuration Guide](https://hussseinkizz.github.io/dialogue/guide/api/configuration/) - Detailed configuration options
|
|
427
|
+
- [Backend API](https://hussseinkizz.github.io/dialogue/guide/api/backend-api) - Server-side API reference
|
|
428
|
+
- [Client API](https://hussseinkizz.github.io/dialogue/guide/api/client-api) - Client SDK reference
|
|
429
|
+
- [Examples](https://hussseinkizz.github.io/dialogue/guide/examples/chat-application) - Complete use-case implementations
|
|
430
|
+
- [Architecture](https://hussseinkizz.github.io/dialogue/guide/others/architecture) - Internal design and patterns
|
|
431
|
+
|
|
432
|
+
## Example App
|
|
433
|
+
|
|
434
|
+
A working chat application is included in the [`example/`](./example) folder. See the [example README](./example/README.md) for setup instructions.
|
|
435
|
+
|
|
436
|
+
## Built With
|
|
437
|
+
|
|
438
|
+
- [Socket.IO](https://socket.io/) - Real-time bidirectional event-based communication
|
|
439
|
+
- [Slang Ts](https://github.com/Hussseinkizz/slang-ts) - Pattern Matching And Functional Utilities
|
|
440
|
+
- [Hono](https://hono.dev/) - Ultrafast web framework for the Edge
|
|
441
|
+
- [Bun](https://bun.sh/) - Fast all-in-one JavaScript runtime
|
|
442
|
+
- [Zod](https://zod.dev/) - TypeScript-first schema validation
|
|
443
|
+
|
|
444
|
+
## License
|
|
445
|
+
|
|
446
|
+
MIT
|