@venizia/ignis-docs 0.2.1-0 → 0.2.1-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/content/best-practices/architectural-patterns.md +3 -3
- package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/content/best-practices/contribution-workflow.md +2 -2
- package/content/best-practices/error-handling.md +94 -89
- package/content/best-practices/security-guidelines.md +5 -5
- package/content/extensions/components/api-reference.md +22 -21
- package/content/extensions/components/authentication/api.md +64 -28
- package/content/extensions/components/authentication/errors.md +19 -5
- package/content/extensions/components/authentication/index.md +19 -18
- package/content/extensions/components/authentication/usage.md +55 -30
- package/content/extensions/components/authorization/api.md +351 -84
- package/content/extensions/components/authorization/errors.md +51 -17
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +24 -16
- package/content/extensions/components/authorization/usage.md +45 -21
- package/content/extensions/components/health-check.md +15 -9
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +105 -54
- package/content/extensions/components/mail/errors.md +12 -10
- package/content/extensions/components/mail/index.md +32 -13
- package/content/extensions/components/mail/usage.md +26 -18
- package/content/extensions/components/request-tracker.md +18 -14
- package/content/extensions/components/socket-io/api.md +377 -882
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +72 -88
- package/content/extensions/components/socket-io/usage.md +107 -117
- package/content/extensions/components/static-asset/api.md +83 -31
- package/content/extensions/components/static-asset/errors.md +18 -7
- package/content/extensions/components/static-asset/index.md +18 -11
- package/content/extensions/components/static-asset/usage.md +11 -6
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +58 -27
- package/content/extensions/components/websocket/errors.md +3 -3
- package/content/extensions/components/websocket/index.md +8 -7
- package/content/extensions/components/websocket/usage.md +21 -8
- package/content/extensions/helpers/cron/index.md +8 -7
- package/content/extensions/helpers/crypto/index.md +16 -8
- package/content/extensions/helpers/crypto/reference.md +96 -24
- package/content/extensions/helpers/env/index.md +14 -10
- package/content/extensions/helpers/error/index.md +99 -23
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +23 -6
- package/content/extensions/helpers/inversion/reference.md +30 -22
- package/content/extensions/helpers/kafka/admin.md +3 -2
- package/content/extensions/helpers/kafka/compile-binary.md +69 -44
- package/content/extensions/helpers/kafka/consumer.md +24 -21
- package/content/extensions/helpers/kafka/examples.md +22 -234
- package/content/extensions/helpers/kafka/index.md +30 -62
- package/content/extensions/helpers/kafka/producer.md +31 -26
- package/content/extensions/helpers/kafka/schema-registry.md +19 -14
- package/content/extensions/helpers/logger/hf-logger.md +49 -22
- package/content/extensions/helpers/logger/index.md +37 -12
- package/content/extensions/helpers/logger/pino.md +31 -11
- package/content/extensions/helpers/logger/reference.md +243 -52
- package/content/extensions/helpers/network/api.md +65 -30
- package/content/extensions/helpers/network/index.md +32 -11
- package/content/extensions/helpers/queue/index.md +17 -6
- package/content/extensions/helpers/queue/reference.md +52 -25
- package/content/extensions/helpers/redis/index.md +29 -11
- package/content/extensions/helpers/redis/reference.md +85 -28
- package/content/extensions/helpers/secrets/index.md +82 -12
- package/content/extensions/helpers/socket-io/api.md +40 -21
- package/content/extensions/helpers/socket-io/index.md +26 -10
- package/content/extensions/helpers/storage/api.md +42 -24
- package/content/extensions/helpers/storage/index.md +10 -7
- package/content/extensions/helpers/types/index.md +20 -7
- package/content/extensions/helpers/types/reference.md +53 -14
- package/content/extensions/helpers/uid/index.md +166 -10
- package/content/extensions/helpers/websocket/api.md +52 -13
- package/content/extensions/helpers/websocket/index.md +7 -4
- package/content/extensions/helpers/worker-thread/index.md +9 -5
- package/content/extensions/helpers/worker-thread/reference.md +20 -20
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +26 -14
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +4 -3
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +7 -6
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +63 -21
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +14 -14
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +32 -31
- package/content/references/base/datasources.md +6 -6
- package/content/references/base/dependency-injection.md +12 -11
- package/content/references/base/filter-system/application-usage.md +54 -30
- package/content/references/base/filter-system/array-operators.md +24 -46
- package/content/references/base/filter-system/comparison-operators.md +47 -67
- package/content/references/base/filter-system/default-filter.md +59 -53
- package/content/references/base/filter-system/fields-order-pagination.md +92 -146
- package/content/references/base/filter-system/index.md +25 -13
- package/content/references/base/filter-system/json-filtering.md +45 -184
- package/content/references/base/filter-system/list-operators.md +23 -53
- package/content/references/base/filter-system/logical-operators.md +63 -121
- package/content/references/base/filter-system/null-operators.md +34 -104
- package/content/references/base/filter-system/pattern-matching.md +40 -55
- package/content/references/base/filter-system/quick-reference.md +86 -198
- package/content/references/base/filter-system/range-operators.md +18 -46
- package/content/references/base/filter-system/tips.md +6 -6
- package/content/references/base/filter-system/use-cases.md +33 -15
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +11 -10
- package/content/references/base/models-reference.md +17 -17
- package/content/references/base/models.md +4 -3
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +224 -326
- package/content/references/base/repositories/index.md +19 -6
- package/content/references/base/repositories/mixins.md +5 -5
- package/content/references/base/repositories/relations.md +160 -293
- package/content/references/base/repositories/soft-deletable.md +16 -6
- package/content/references/base/secrets.md +17 -13
- package/content/references/base/services.md +6 -4
- package/content/references/configuration/environment-variables.md +31 -23
- package/content/references/configuration/index.md +6 -4
- package/content/references/index.md +1 -1
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +5 -1
- package/content/references/utilities/jsx-reference.md +11 -11
- package/content/references/utilities/jsx.md +2 -2
- package/content/references/utilities/module.md +78 -25
- package/content/references/utilities/request.md +2 -1
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +2 -2
- package/content/references/utilities/statuses-reference.md +4 -4
- package/content/references/utilities/statuses.md +5 -5
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +17 -16
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Socket.IO Component - Usage & Examples
|
|
3
|
+
description: Full setup steps, server-side usage, the client helper, and advanced patterns
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
# Usage & Examples
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
Task-oriented patterns for the Socket.IO component: full setup, sending messages from a service, using the standalone client helper, and reading the example app.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
## Full setup
|
|
12
|
+
|
|
13
|
+
### 1. Install dependencies
|
|
8
14
|
|
|
9
15
|
```bash
|
|
10
16
|
# Core dependency (already included via @venizia/ignis)
|
|
11
17
|
# ioredis is required for the Redis adapter
|
|
12
18
|
|
|
13
|
-
#
|
|
19
|
+
# Bun runtime only - optional peer dependency
|
|
14
20
|
bun add @socket.io/bun-engine
|
|
15
21
|
```
|
|
16
22
|
|
|
17
|
-
### 2. Bind
|
|
23
|
+
### 2. Bind required and optional services
|
|
18
24
|
|
|
19
25
|
```typescript
|
|
20
26
|
import { BaseApplication } from '@venizia/ignis';
|
|
@@ -51,7 +57,7 @@ export class Application extends BaseApplication {
|
|
|
51
57
|
// 2. Authentication handler (required)
|
|
52
58
|
const authenticateFn: TSocketIOAuthenticateFn = handshake => {
|
|
53
59
|
const token = handshake.headers.authorization;
|
|
54
|
-
// Implement your auth logic
|
|
60
|
+
// Implement your auth logic: JWT verification, session check, etc.
|
|
55
61
|
return !!token;
|
|
56
62
|
};
|
|
57
63
|
|
|
@@ -59,11 +65,10 @@ export class Application extends BaseApplication {
|
|
|
59
65
|
key: SocketIOBindingKeys.AUTHENTICATE_HANDLER,
|
|
60
66
|
}).toValue(authenticateFn);
|
|
61
67
|
|
|
62
|
-
// 3. Room validation handler (optional
|
|
68
|
+
// 3. Room validation handler (optional - joins rejected without this)
|
|
63
69
|
const validateRoomFn: TSocketIOValidateRoomFn = ({ socket, rooms }) => {
|
|
64
70
|
// Return the rooms that the client is allowed to join
|
|
65
|
-
|
|
66
|
-
return allowedRooms;
|
|
71
|
+
return rooms.filter(room => room.startsWith('public-'));
|
|
67
72
|
};
|
|
68
73
|
|
|
69
74
|
this.bind<TSocketIOValidateRoomFn>({
|
|
@@ -80,7 +85,7 @@ export class Application extends BaseApplication {
|
|
|
80
85
|
key: SocketIOBindingKeys.CLIENT_CONNECTED_HANDLER,
|
|
81
86
|
}).toValue(clientConnectedFn);
|
|
82
87
|
|
|
83
|
-
// 5. Register the component
|
|
88
|
+
// 5. Register the component - that's it!
|
|
84
89
|
this.component(SocketIOComponent);
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -88,11 +93,18 @@ export class Application extends BaseApplication {
|
|
|
88
93
|
|
|
89
94
|
### 3. Why `autoConnect: false`
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
The helper owns the connection timing, not you. `RedisSingleHelper` is created with `autoConnect: false` because the server helper calls `duplicateClient()` three times:
|
|
97
|
+
|
|
98
|
+
| Duplicate | Role |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `redisPub` | Redis adapter - publishes room broadcasts |
|
|
101
|
+
| `redisSub` | Redis adapter - subscribes to room broadcasts |
|
|
102
|
+
| `redisEmitter` | Redis emitter - direct cross-instance send |
|
|
103
|
+
|
|
104
|
+
- **Duplicates inherit `lazyConnect`, not connection state.** During `configure()`, the helper checks each client's status. Any client still `wait`ing gets `connect()` called on it explicitly. The helper then waits for all three to reach `ready` before proceeding.
|
|
105
|
+
- **This avoids a race.** If the parent connects before the duplicates exist, the duplicates can end up in a state inconsistent with the parent's connection lifecycle.
|
|
94
106
|
|
|
95
|
-
### Redis
|
|
107
|
+
### Redis connection alternatives
|
|
96
108
|
|
|
97
109
|
`RedisSingleHelper` (single instance), `RedisClusterHelper` (cluster mode), and `RedisSentinelHelper` (Sentinel HA) all extend `AbstractRedisHelper` and satisfy the `IRedisHelper` interface the component validates against.
|
|
98
110
|
|
|
@@ -116,17 +128,14 @@ this.bind<RedisClusterHelper>({
|
|
|
116
128
|
}).toValue(redisHelper);
|
|
117
129
|
```
|
|
118
130
|
|
|
119
|
-
The internal `TRedisClient` type is `Redis | Cluster`, so both ioredis connection types
|
|
131
|
+
The internal `TRedisClient` type is `Redis | Cluster`, so both ioredis connection types work transparently.
|
|
120
132
|
|
|
121
133
|
> [!NOTE]
|
|
122
|
-
> Full defaults, the complete binding key table, and every system event/room constant are in the [
|
|
134
|
+
> Full defaults, the complete binding key table, and every system event/room constant are in the [Full Reference](./api#configuration-reference).
|
|
123
135
|
|
|
124
|
-
##
|
|
136
|
+
## Inject the helper in a service or controller
|
|
125
137
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
- **`SOCKET_IO_INSTANCE` does not exist at construction time.** The component binds `SocketIOServerHelper` from a post-start hook, which runs after the server starts -- well after every service/controller has already been constructed by the DI container.
|
|
129
|
-
- **Use a lazy getter, not `@inject`.** Resolve the helper from the application container on first access, and cache it. `@inject`-ing `SOCKET_IO_INSTANCE` directly in a constructor will resolve to nothing.
|
|
138
|
+
`SocketIOServerHelper` is bound to `SOCKET_IO_INSTANCE` inside a post-start hook. That hook runs after the server starts - well after the DI container already built every service and controller. Use a lazy getter that resolves the helper on first access. Never `@inject` it in a constructor.
|
|
130
139
|
|
|
131
140
|
```typescript
|
|
132
141
|
import {
|
|
@@ -178,30 +187,27 @@ export class NotificationService extends BaseService {
|
|
|
178
187
|
notifyRoom(opts: { room: string; message: string }) {
|
|
179
188
|
this.io.send({
|
|
180
189
|
destination: opts.room,
|
|
181
|
-
payload: {
|
|
182
|
-
topic: 'room:update',
|
|
183
|
-
data: { message: opts.message },
|
|
184
|
-
},
|
|
190
|
+
payload: { topic: 'room:update', data: { message: opts.message } },
|
|
185
191
|
});
|
|
186
192
|
}
|
|
187
193
|
|
|
188
194
|
// Broadcast to all clients
|
|
189
195
|
broadcastAnnouncement(opts: { message: string }) {
|
|
190
196
|
this.io.send({
|
|
191
|
-
payload: {
|
|
192
|
-
topic: 'system:announcement',
|
|
193
|
-
data: { message: opts.message },
|
|
194
|
-
},
|
|
197
|
+
payload: { topic: 'system:announcement', data: { message: opts.message } },
|
|
195
198
|
});
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
```
|
|
199
202
|
|
|
200
|
-
|
|
203
|
+
- **Never `@inject` `SOCKET_IO_INSTANCE` in a constructor.** It is not bound yet at that point.
|
|
204
|
+
- **`send()` reads via the Redis emitter.** It works even if the destination client is connected to a different server instance - see [`send()` in the Full Reference](./api#messaging-via-send).
|
|
201
205
|
|
|
202
|
-
|
|
206
|
+
## Use the client helper
|
|
203
207
|
|
|
204
|
-
|
|
208
|
+
`SocketIOClientHelper` wraps `socket.io-client` with authentication flow, lifecycle callbacks, and error-safe event subscription. Use it when your process needs to connect *to* a Socket.IO server, not run one - service-to-service communication, testing, or relay services.
|
|
209
|
+
|
|
210
|
+
### Client setup
|
|
205
211
|
|
|
206
212
|
```typescript
|
|
207
213
|
import { SocketIOClientHelper } from '@venizia/ignis-helpers/socket-io';
|
|
@@ -211,9 +217,7 @@ const client = new SocketIOClientHelper({
|
|
|
211
217
|
host: 'http://localhost:3000',
|
|
212
218
|
options: {
|
|
213
219
|
path: '/io',
|
|
214
|
-
extraHeaders: {
|
|
215
|
-
authorization: 'Bearer <token>',
|
|
216
|
-
},
|
|
220
|
+
extraHeaders: { authorization: 'Bearer <token>' },
|
|
217
221
|
},
|
|
218
222
|
|
|
219
223
|
// Lifecycle callbacks (all optional)
|
|
@@ -221,57 +225,52 @@ const client = new SocketIOClientHelper({
|
|
|
221
225
|
console.log('Connected to server');
|
|
222
226
|
client.authenticate();
|
|
223
227
|
},
|
|
224
|
-
onDisconnected:
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
console.error('Connection error:', error);
|
|
229
|
-
},
|
|
230
|
-
onAuthenticated: () => {
|
|
231
|
-
console.log('Authentication successful');
|
|
232
|
-
},
|
|
233
|
-
onUnauthenticated: (message) => {
|
|
234
|
-
console.warn('Authentication failed:', message);
|
|
235
|
-
},
|
|
228
|
+
onDisconnected: reason => console.log('Disconnected:', reason),
|
|
229
|
+
onError: error => console.error('Connection error:', error),
|
|
230
|
+
onAuthenticated: () => console.log('Authentication successful'),
|
|
231
|
+
onUnauthenticated: message => console.warn('Authentication failed:', message),
|
|
236
232
|
});
|
|
237
233
|
```
|
|
238
234
|
|
|
239
|
-
- **The constructor calls `configure()` immediately.**
|
|
240
|
-
- **The socket
|
|
235
|
+
- **The constructor calls `configure()` immediately.** It creates the `socket.io-client` `Socket` instance via `io(host, options)` and registers the internal event handlers. See the [full handler table](./api#client-configure-event-handlers) in the Full Reference.
|
|
236
|
+
- **The socket connects on its own unless you disable it.** Set `autoConnect: false` in `options` and call `client.connect()` yourself when you're ready.
|
|
237
|
+
|
|
238
|
+
#### `connect` vs `connection` event
|
|
239
|
+
|
|
240
|
+
Client and server fire different event names for the same moment:
|
|
241
241
|
|
|
242
|
-
|
|
242
|
+
| Side | Fires |
|
|
243
|
+
|---|---|
|
|
244
|
+
| Client (`socket.io-client`) | `connect` - no suffix |
|
|
245
|
+
| Server (`socket.io`) | `connection` - with the suffix |
|
|
243
246
|
|
|
244
|
-
|
|
245
|
-
- **The two helpers mirror this.** The client helper registers on `'connect'`; the server helper registers on `SocketIOConstants.EVENT_CONNECT`, which equals `'connection'`.
|
|
247
|
+
This is a Socket.IO convention, not an IGNIS one. The client helper listens on `'connect'`. The server helper listens on `SocketIOConstants.EVENT_CONNECT`, which equals `'connection'`.
|
|
246
248
|
|
|
247
|
-
### Authentication
|
|
249
|
+
### Authentication flow
|
|
248
250
|
|
|
249
|
-
After connecting, the client must emit `authenticate` to start the
|
|
251
|
+
After connecting, the client must emit `authenticate` to start the handshake. The server validates credentials from the socket handshake (headers, query params, `auth` object) and responds with either `authenticated` or `unauthenticated`.
|
|
250
252
|
|
|
251
253
|
```typescript
|
|
252
|
-
// Manual authentication after connection
|
|
253
254
|
client.authenticate();
|
|
254
255
|
```
|
|
255
256
|
|
|
256
|
-
`authenticate()`
|
|
257
|
+
`authenticate()` is a no-op with a warning log unless both conditions hold:
|
|
257
258
|
|
|
258
|
-
1. The socket
|
|
259
|
-
2. The current state
|
|
259
|
+
1. The socket is connected (`client.connected === true`).
|
|
260
|
+
2. The current state is `unauthorized` - calling `authenticate()` while `authenticating` or already `authenticated` does nothing.
|
|
260
261
|
|
|
261
|
-
#### Authentication
|
|
262
|
+
#### Authentication failure messages
|
|
262
263
|
|
|
263
|
-
The server sends
|
|
264
|
+
The server sends a different message depending on how `authenticateFn` failed. Both paths reset the client to `unauthorized`, emit `unauthenticated` with the message, and disconnect the socket after delivery (via `setImmediate`).
|
|
264
265
|
|
|
265
|
-
| Failure
|
|
266
|
-
|
|
267
|
-
| `authenticateFn` returned `false` | `"Invalid token to authenticate! Please login again!"` |
|
|
268
|
-
| `authenticateFn` threw an error | `"Failed to authenticate connection! Please login again!"` |
|
|
266
|
+
| Failure mode | Message |
|
|
267
|
+
|---|---|
|
|
268
|
+
| `authenticateFn` returned `false` | `"Invalid token to authenticate! Please login again!"` |
|
|
269
|
+
| `authenticateFn` threw an error | `"Failed to authenticate connection! Please login again!"` |
|
|
269
270
|
|
|
270
|
-
|
|
271
|
+
### Event subscription
|
|
271
272
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
Subscribe to custom events with automatic error safety. Handlers are wrapped in a dual try-catch that catches both synchronous throws and asynchronous rejections:
|
|
273
|
+
Handlers are wrapped in a dual try-catch. It catches both synchronous throws and asynchronous rejections, so a broken handler never crashes the client.
|
|
275
274
|
|
|
276
275
|
```typescript
|
|
277
276
|
// Subscribe to a single event
|
|
@@ -282,27 +281,24 @@ client.subscribe({
|
|
|
282
281
|
},
|
|
283
282
|
});
|
|
284
283
|
|
|
285
|
-
//
|
|
284
|
+
// ignoreDuplicate: false stacks a second handler for the same event
|
|
286
285
|
client.subscribe({
|
|
287
286
|
event: 'chat:message',
|
|
288
|
-
handler:
|
|
289
|
-
ignoreDuplicate: false,
|
|
287
|
+
handler: data => { /* second handler */ },
|
|
288
|
+
ignoreDuplicate: false,
|
|
290
289
|
});
|
|
291
290
|
|
|
292
291
|
// Subscribe to multiple events at once
|
|
293
292
|
client.subscribeMany({
|
|
294
293
|
events: {
|
|
295
|
-
'user:joined':
|
|
296
|
-
'user:left':
|
|
297
|
-
'room:updated':
|
|
294
|
+
'user:joined': data => console.log('User joined:', data),
|
|
295
|
+
'user:left': data => console.log('User left:', data),
|
|
296
|
+
'room:updated': data => console.log('Room updated:', data),
|
|
298
297
|
},
|
|
299
298
|
});
|
|
300
299
|
```
|
|
301
300
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
- **The default (`ignoreDuplicate: true`) checks `socket.hasListeners(event)` first.** If listeners already exist for the event, `subscribe()` is a no-op and logs an info message.
|
|
305
|
-
- **Set `ignoreDuplicate: false` to stack handlers.** This allows multiple handlers to run for the same event.
|
|
301
|
+
The default (`ignoreDuplicate: true`) checks `socket.hasListeners(event)` first. If a listener already exists, `subscribe()` is a no-op that logs an info message. Set `ignoreDuplicate: false` to stack handlers instead.
|
|
306
302
|
|
|
307
303
|
### Unsubscribing
|
|
308
304
|
|
|
@@ -317,7 +313,7 @@ client.unsubscribe({ event: 'chat:message', handler: myHandler });
|
|
|
317
313
|
client.unsubscribeMany({ events: ['chat:message', 'user:joined', 'room:updated'] });
|
|
318
314
|
```
|
|
319
315
|
|
|
320
|
-
### Emitting
|
|
316
|
+
### Emitting events
|
|
321
317
|
|
|
322
318
|
```typescript
|
|
323
319
|
client.emit({
|
|
@@ -330,9 +326,9 @@ client.emit({
|
|
|
330
326
|
});
|
|
331
327
|
```
|
|
332
328
|
|
|
333
|
-
`emit()` throws if the socket is not connected or if
|
|
329
|
+
`emit()` throws if the socket is not connected or if `topic` is missing. The server helper's `send()` silently drops a message with a missing field - `emit()` never does that. It always throws instead.
|
|
334
330
|
|
|
335
|
-
### Room
|
|
331
|
+
### Room management
|
|
336
332
|
|
|
337
333
|
```typescript
|
|
338
334
|
// Request to join rooms (server validates via validateRoomFn)
|
|
@@ -342,9 +338,9 @@ client.joinRooms({ rooms: ['chat-room-1', 'notifications'] });
|
|
|
342
338
|
client.leaveRooms({ rooms: ['chat-room-1'] });
|
|
343
339
|
```
|
|
344
340
|
|
|
345
|
-
Both methods emit Socket.IO
|
|
341
|
+
Both methods emit a Socket.IO event to the server: `join` or `leave`. The actual join or leave happens server-side. If the socket isn't connected, the call is a no-op with a warning log.
|
|
346
342
|
|
|
347
|
-
### Connection
|
|
343
|
+
### Connection management
|
|
348
344
|
|
|
349
345
|
```typescript
|
|
350
346
|
// Manually connect (useful when autoConnect: false in options)
|
|
@@ -363,35 +359,30 @@ const rawSocket = client.getSocketClient();
|
|
|
363
359
|
### Shutdown
|
|
364
360
|
|
|
365
361
|
```typescript
|
|
366
|
-
// Clean shutdown: removes all listeners, disconnects, resets state
|
|
367
362
|
client.shutdown();
|
|
368
363
|
```
|
|
369
364
|
|
|
370
365
|
`shutdown()` does three things, in order:
|
|
371
366
|
|
|
372
|
-
1. Calls `removeAllListeners()` on the underlying socket to prevent memory leaks
|
|
373
|
-
2. Disconnects if still connected
|
|
374
|
-
3. Resets state to `unauthorized
|
|
367
|
+
1. Calls `removeAllListeners()` on the underlying socket to prevent memory leaks.
|
|
368
|
+
2. Disconnects if still connected.
|
|
369
|
+
3. Resets state to `unauthorized`.
|
|
375
370
|
|
|
376
|
-
##
|
|
371
|
+
## Run the complete example
|
|
377
372
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
A full working example is available at `examples/socket-io-test/`. It demonstrates:
|
|
373
|
+
A full working example lives at `examples/socket-io-test/`.
|
|
381
374
|
|
|
382
375
|
| Feature | Implementation |
|
|
383
|
-
|
|
384
|
-
| Application setup | `src/application.ts`
|
|
385
|
-
| REST endpoints | `src/controllers/socket-test.controller.ts`
|
|
386
|
-
| Event handling | `src/services/socket-event.service.ts`
|
|
387
|
-
| Automated test client | `client.ts`
|
|
388
|
-
|
|
389
|
-
#### REST API Endpoints
|
|
376
|
+
|---|---|
|
|
377
|
+
| Application setup | `src/application.ts` - bindings, component registration, graceful shutdown |
|
|
378
|
+
| REST endpoints | `src/controllers/socket-test.controller.ts` - 9 endpoints for Socket.IO management |
|
|
379
|
+
| Event handling | `src/services/socket-event.service.ts` - chat, echo, room management |
|
|
380
|
+
| Automated test client | `client.ts` - 15+ test cases covering all features |
|
|
390
381
|
|
|
391
|
-
|
|
382
|
+
### REST API endpoints
|
|
392
383
|
|
|
393
384
|
| Method | Path | Description |
|
|
394
|
-
|
|
385
|
+
|---|---|---|
|
|
395
386
|
| `GET` | `/socket/info` | Server status + connected client count |
|
|
396
387
|
| `GET` | `/socket/clients` | List all connected client IDs |
|
|
397
388
|
| `GET` | `/socket/health` | Health check (is SocketIO ready?) |
|
|
@@ -402,38 +393,37 @@ The example provides a REST API for managing Socket.IO:
|
|
|
402
393
|
| `POST` | `/socket/client/{clientId}/leave` | Remove client from <code v-pre>{{ rooms: string[] }}</code> |
|
|
403
394
|
| `GET` | `/socket/client/{clientId}/rooms` | List rooms a client belongs to |
|
|
404
395
|
|
|
405
|
-
|
|
396
|
+
### Running the example
|
|
406
397
|
|
|
407
398
|
```bash
|
|
408
399
|
# Start the server
|
|
409
400
|
cd examples/socket-io-test
|
|
410
401
|
bun run server:dev
|
|
411
402
|
|
|
412
|
-
# In another terminal
|
|
403
|
+
# In another terminal - run automated tests
|
|
413
404
|
bun client.ts
|
|
414
405
|
```
|
|
415
406
|
|
|
416
|
-
The automated client
|
|
407
|
+
The automated client exercises:
|
|
417
408
|
|
|
418
|
-
- Authentication
|
|
409
|
+
- Authentication with valid and invalid tokens
|
|
419
410
|
- Ping/pong keepalive
|
|
420
411
|
- Room join/leave with validation
|
|
421
412
|
- Client-to-client messaging
|
|
422
|
-
- Room broadcasting
|
|
423
|
-
-
|
|
424
|
-
- REST API for Socket.IO management
|
|
413
|
+
- Room and global broadcasting
|
|
414
|
+
- The REST API
|
|
425
415
|
- Graceful disconnection
|
|
426
416
|
|
|
427
|
-
|
|
417
|
+
Read the example for these production-ready patterns:
|
|
428
418
|
|
|
429
|
-
- Binding multiple handlers in
|
|
430
|
-
-
|
|
419
|
+
- Binding multiple handlers in one `setupSocketIO()` method
|
|
420
|
+
- The lazy getter pattern for `SocketIOServerHelper`
|
|
431
421
|
- Custom event registration via `CLIENT_CONNECTED_HANDLER`
|
|
432
|
-
- Room validation
|
|
433
|
-
-
|
|
422
|
+
- Room validation that blocks unauthorized rooms
|
|
423
|
+
- A graceful shutdown sequence in `application.stop()`
|
|
434
424
|
|
|
435
|
-
## See
|
|
425
|
+
## See also
|
|
436
426
|
|
|
437
|
-
- [
|
|
438
|
-
- [
|
|
439
|
-
- [Error Reference](./errors)
|
|
427
|
+
- [Overview](./) - quick start, imports, common configuration tasks
|
|
428
|
+
- [Full Reference](./api) - architecture, configuration reference, method signatures, internals, types
|
|
429
|
+
- [Error Reference](./errors) - error conditions and troubleshooting
|