@venizia/ignis-docs 0.2.0 → 0.2.1-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +22 -11
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +6 -2
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +182 -93
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +107 -322
- package/content/extensions/components/authentication/api.md +454 -603
- package/content/extensions/components/authentication/errors.md +121 -498
- package/content/extensions/components/authentication/index.md +88 -801
- package/content/extensions/components/authentication/usage.md +207 -956
- package/content/extensions/components/authorization/api.md +736 -656
- package/content/extensions/components/authorization/errors.md +168 -206
- package/content/extensions/components/authorization/index.md +82 -797
- package/content/extensions/components/authorization/usage.md +194 -527
- package/content/extensions/components/health-check.md +71 -243
- package/content/extensions/components/mail/api.md +504 -287
- package/content/extensions/components/mail/errors.md +73 -61
- package/content/extensions/components/mail/index.md +96 -467
- package/content/extensions/components/mail/usage.md +130 -172
- package/content/extensions/components/request-tracker.md +66 -173
- package/content/extensions/components/socket-io/api.md +195 -13
- package/content/extensions/components/socket-io/errors.md +3 -3
- package/content/extensions/components/socket-io/index.md +50 -337
- package/content/extensions/components/socket-io/usage.md +143 -26
- package/content/extensions/components/static-asset/api.md +410 -142
- package/content/extensions/components/static-asset/errors.md +110 -53
- package/content/extensions/components/static-asset/index.md +79 -608
- package/content/extensions/components/static-asset/usage.md +180 -300
- package/content/extensions/components/websocket/api.md +275 -399
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +74 -407
- package/content/extensions/components/websocket/usage.md +110 -341
- package/content/extensions/helpers/cron/index.md +51 -160
- package/content/extensions/helpers/crypto/index.md +62 -483
- package/content/extensions/helpers/crypto/reference.md +456 -0
- package/content/extensions/helpers/env/index.md +60 -178
- package/content/extensions/helpers/error/index.md +221 -207
- package/content/extensions/helpers/inversion/index.md +65 -556
- package/content/extensions/helpers/inversion/reference.md +522 -0
- package/content/extensions/helpers/kafka/admin.md +20 -1
- package/content/extensions/helpers/kafka/compile-binary.md +41 -35
- package/content/extensions/helpers/kafka/consumer.md +54 -20
- package/content/extensions/helpers/kafka/examples.md +21 -16
- package/content/extensions/helpers/kafka/index.md +80 -610
- package/content/extensions/helpers/kafka/producer.md +134 -5
- package/content/extensions/helpers/kafka/schema-registry.md +45 -70
- package/content/extensions/helpers/logger/hf-logger.md +193 -0
- package/content/extensions/helpers/logger/index.md +64 -563
- package/content/extensions/helpers/logger/pino.md +85 -0
- package/content/extensions/helpers/logger/reference.md +746 -0
- package/content/extensions/helpers/network/api.md +241 -195
- package/content/extensions/helpers/network/index.md +72 -530
- package/content/extensions/helpers/queue/index.md +72 -900
- package/content/extensions/helpers/queue/reference.md +467 -0
- package/content/extensions/helpers/redis/index.md +73 -645
- package/content/extensions/helpers/redis/reference.md +727 -0
- package/content/extensions/helpers/secrets/index.md +66 -0
- package/content/extensions/helpers/socket-io/api.md +305 -203
- package/content/extensions/helpers/socket-io/index.md +66 -432
- package/content/extensions/helpers/storage/api.md +564 -462
- package/content/extensions/helpers/storage/index.md +77 -573
- package/content/extensions/helpers/types/index.md +66 -499
- package/content/extensions/helpers/types/reference.md +650 -0
- package/content/extensions/helpers/uid/index.md +58 -227
- package/content/extensions/helpers/websocket/api.md +329 -216
- package/content/extensions/helpers/websocket/index.md +65 -503
- package/content/extensions/helpers/worker-thread/index.md +58 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
- package/content/guides/core-concepts/persistent/transactions.md +1 -1
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/migrations/redis-helpers-migration.md +1 -1
- package/content/guides/migrations/unified-connectors-migration.md +2 -2
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/references/base/application.md +1 -1
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/datasources-reference.md +599 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +17 -39
- package/content/references/base/filter-system/application-usage.md +69 -121
- package/content/references/base/filter-system/array-operators.md +12 -0
- package/content/references/base/filter-system/comparison-operators.md +12 -0
- package/content/references/base/filter-system/default-filter.md +136 -348
- package/content/references/base/filter-system/fields-order-pagination.md +38 -16
- package/content/references/base/filter-system/index.md +106 -257
- package/content/references/base/filter-system/json-filtering.md +12 -2
- package/content/references/base/filter-system/list-operators.md +16 -2
- package/content/references/base/filter-system/logical-operators.md +13 -0
- package/content/references/base/filter-system/null-operators.md +13 -0
- package/content/references/base/filter-system/pattern-matching.md +12 -0
- package/content/references/base/filter-system/quick-reference.md +11 -2
- package/content/references/base/filter-system/range-operators.md +12 -0
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +156 -233
- package/content/references/base/middlewares.md +35 -21
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +80 -1452
- package/content/references/base/repositories/advanced.md +156 -192
- package/content/references/base/repositories/index.md +77 -650
- package/content/references/base/repositories/mixins.md +22 -18
- package/content/references/base/repositories/relations.md +123 -171
- package/content/references/base/repositories/soft-deletable.md +58 -56
- package/content/references/base/secrets.md +263 -0
- package/content/references/base/services.md +2 -2
- package/content/references/configuration/environment-variables.md +48 -4
- package/content/references/configuration/index.md +49 -31
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/index.md +1 -1
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +29 -62
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +57 -218
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/package.json +8 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Socket.IO -- Setup & Configuration
|
|
2
2
|
|
|
3
|
-
> Real-time, bidirectional, event-based communication using Socket.IO -- with automatic runtime detection for
|
|
3
|
+
> Real-time, bidirectional, event-based communication using Socket.IO -- with automatic runtime detection for Node.js and Bun, horizontal scaling via Redis, and a built-in authentication handshake.
|
|
4
4
|
|
|
5
5
|
## Quick Reference
|
|
6
6
|
|
|
@@ -13,394 +13,101 @@
|
|
|
13
13
|
| **Runtimes** | Node.js (`@hono/node-server`) and Bun (native) |
|
|
14
14
|
| **Scaling** | `@socket.io/redis-adapter` + `@socket.io/redis-emitter` |
|
|
15
15
|
|
|
16
|
-
#### Import Paths
|
|
17
|
-
|
|
18
16
|
> [!IMPORTANT]
|
|
19
|
-
> `SocketIOComponent` and `SocketIOBindingKeys` are **not** exported from the `@venizia/ignis` barrel
|
|
17
|
+
> `SocketIOComponent` and `SocketIOBindingKeys` are **not** exported from the `@venizia/ignis` barrel -- import from the `@venizia/ignis/socket-io` subpath.
|
|
20
18
|
|
|
21
19
|
```typescript
|
|
22
20
|
// From core -- subpath import (NOT from '@venizia/ignis')
|
|
23
|
-
import {
|
|
24
|
-
SocketIOComponent,
|
|
25
|
-
SocketIOBindingKeys,
|
|
26
|
-
} from '@venizia/ignis/socket-io';
|
|
21
|
+
import { SocketIOComponent, SocketIOBindingKeys } from '@venizia/ignis/socket-io';
|
|
27
22
|
|
|
28
23
|
// From helpers -- subpath import
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
SocketIOClientHelper,
|
|
32
|
-
SocketIOConstants,
|
|
33
|
-
SocketIOClientStates,
|
|
34
|
-
} from '@venizia/ignis-helpers/socket-io';
|
|
35
|
-
|
|
36
|
-
// Types from helpers subpath
|
|
37
|
-
import type {
|
|
38
|
-
TSocketIOAuthenticateFn,
|
|
39
|
-
TSocketIOValidateRoomFn,
|
|
40
|
-
TSocketIOClientConnectedFn,
|
|
41
|
-
ISocketIOClientOptions,
|
|
42
|
-
IOptions,
|
|
43
|
-
TSocketIOEventHandler,
|
|
44
|
-
TSocketIOClientState,
|
|
45
|
-
} from '@venizia/ignis-helpers/socket-io';
|
|
24
|
+
import { SocketIOServerHelper, SocketIOClientHelper, SocketIOConstants } from '@venizia/ignis-helpers/socket-io';
|
|
25
|
+
import type { TSocketIOAuthenticateFn, TSocketIOValidateRoomFn } from '@venizia/ignis-helpers/socket-io';
|
|
46
26
|
```
|
|
47
27
|
|
|
48
|
-
|
|
28
|
+
**Use cases:**
|
|
49
29
|
|
|
50
30
|
- Live notifications and alerts
|
|
51
|
-
- Real-time chat and
|
|
52
|
-
-
|
|
53
|
-
- Live data streams (dashboards, monitoring)
|
|
31
|
+
- Real-time chat and collaborative editing
|
|
32
|
+
- Live dashboards and monitoring streams
|
|
54
33
|
- Multiplayer game state synchronization
|
|
55
|
-
- Service-to-service real-time
|
|
56
|
-
|
|
57
|
-
## Server Helper Setup
|
|
58
|
-
|
|
59
|
-
### Step 1: Install Dependencies
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
# Core dependency (already included via @venizia/ignis)
|
|
63
|
-
# ioredis is required for the Redis adapter
|
|
34
|
+
- Service-to-service real-time messaging (via `SocketIOClientHelper`)
|
|
64
35
|
|
|
65
|
-
|
|
66
|
-
bun add @socket.io/bun-engine
|
|
67
|
-
```
|
|
36
|
+
## Setup
|
|
68
37
|
|
|
69
|
-
|
|
38
|
+
Three pieces are bound in `preConfigure()`, before the component itself is registered:
|
|
70
39
|
|
|
71
|
-
|
|
40
|
+
| Step | Binding key | Required |
|
|
41
|
+
|------|-------------|----------|
|
|
42
|
+
| 1. Redis connection | `SocketIOBindingKeys.REDIS_CONNECTION` | Yes |
|
|
43
|
+
| 2. Authenticate handler | `SocketIOBindingKeys.AUTHENTICATE_HANDLER` | Yes |
|
|
44
|
+
| 3. Room / connected handlers | `VALIDATE_ROOM_HANDLER`, `CLIENT_CONNECTED_HANDLER` | No |
|
|
72
45
|
|
|
73
46
|
```typescript
|
|
74
47
|
import { BaseApplication } from '@venizia/ignis';
|
|
75
|
-
import {
|
|
76
|
-
SocketIOComponent,
|
|
77
|
-
SocketIOBindingKeys,
|
|
78
|
-
} from '@venizia/ignis/socket-io';
|
|
48
|
+
import { SocketIOComponent, SocketIOBindingKeys } from '@venizia/ignis/socket-io';
|
|
79
49
|
import { RedisSingleHelper, ValueOrPromise } from '@venizia/ignis-helpers';
|
|
80
|
-
import type {
|
|
81
|
-
TSocketIOAuthenticateFn,
|
|
82
|
-
TSocketIOValidateRoomFn,
|
|
83
|
-
TSocketIOClientConnectedFn,
|
|
84
|
-
} from '@venizia/ignis-helpers/socket-io';
|
|
50
|
+
import type { TSocketIOAuthenticateFn } from '@venizia/ignis-helpers/socket-io';
|
|
85
51
|
|
|
86
52
|
export class Application extends BaseApplication {
|
|
87
|
-
private redisHelper: RedisSingleHelper;
|
|
88
|
-
|
|
89
53
|
preConfigure(): ValueOrPromise<void> {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
setupSocketIO() {
|
|
95
|
-
// 1. Redis connection (required for adapter + emitter)
|
|
96
|
-
this.redisHelper = new RedisSingleHelper({
|
|
54
|
+
// 1. Redis connection -- required for the adapter + emitter
|
|
55
|
+
const redisHelper = new RedisSingleHelper({
|
|
97
56
|
name: 'socket-io-redis',
|
|
98
57
|
host: process.env.REDIS_HOST ?? 'localhost',
|
|
99
58
|
port: +(process.env.REDIS_PORT ?? 6379),
|
|
100
|
-
password: process.env.REDIS_PASSWORD,
|
|
101
59
|
autoConnect: false,
|
|
102
60
|
});
|
|
61
|
+
this.bind({ key: SocketIOBindingKeys.REDIS_CONNECTION }).toValue(redisHelper);
|
|
103
62
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}).toValue(
|
|
107
|
-
|
|
108
|
-
// 2. Authentication handler (required)
|
|
109
|
-
const authenticateFn: TSocketIOAuthenticateFn = handshake => {
|
|
110
|
-
const token = handshake.headers.authorization;
|
|
111
|
-
// Implement your auth logic -- JWT verification, session check, etc.
|
|
112
|
-
return !!token;
|
|
113
|
-
};
|
|
63
|
+
// 2. Authentication handler -- required
|
|
64
|
+
const authenticateFn: TSocketIOAuthenticateFn = handshake => !!handshake.headers.authorization;
|
|
65
|
+
this.bind({ key: SocketIOBindingKeys.AUTHENTICATE_HANDLER }).toValue(authenticateFn);
|
|
114
66
|
|
|
115
|
-
|
|
116
|
-
key: SocketIOBindingKeys.AUTHENTICATE_HANDLER,
|
|
117
|
-
}).toValue(authenticateFn);
|
|
118
|
-
|
|
119
|
-
// 3. Room validation handler (optional -- joins rejected without this)
|
|
120
|
-
const validateRoomFn: TSocketIOValidateRoomFn = ({ socket, rooms }) => {
|
|
121
|
-
// Return the rooms that the client is allowed to join
|
|
122
|
-
const allowedRooms = rooms.filter(room => room.startsWith('public-'));
|
|
123
|
-
return allowedRooms;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
this.bind<TSocketIOValidateRoomFn>({
|
|
127
|
-
key: SocketIOBindingKeys.VALIDATE_ROOM_HANDLER,
|
|
128
|
-
}).toValue(validateRoomFn);
|
|
129
|
-
|
|
130
|
-
// 4. Client connected handler (optional)
|
|
131
|
-
const clientConnectedFn: TSocketIOClientConnectedFn = ({ socket }) => {
|
|
132
|
-
console.log('Client connected:', socket.id);
|
|
133
|
-
// Register custom event handlers on the socket
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
this.bind<TSocketIOClientConnectedFn>({
|
|
137
|
-
key: SocketIOBindingKeys.CLIENT_CONNECTED_HANDLER,
|
|
138
|
-
}).toValue(clientConnectedFn);
|
|
139
|
-
|
|
140
|
-
// 5. Register the component -- that's it!
|
|
67
|
+
// 3. Register the component
|
|
141
68
|
this.component(SocketIOComponent);
|
|
142
69
|
}
|
|
143
70
|
}
|
|
144
71
|
```
|
|
145
72
|
|
|
146
|
-
#### `autoConnect: false` Rationale
|
|
147
|
-
|
|
148
|
-
The `RedisSingleHelper` is created with `autoConnect: false` because the server helper internally calls `client.duplicate()` to create 3 independent Redis connections (pub, sub, emitter). The duplicated clients inherit the `lazyConnect` setting from the parent. During `configure()`, the helper detects clients in `wait` status and explicitly calls `client.connect()` on each, then awaits all 3 to reach `ready` status before proceeding. This avoids race conditions where the parent connects before the duplicates are created.
|
|
149
|
-
|
|
150
|
-
#### Redis Connection Alternatives
|
|
151
|
-
|
|
152
|
-
You can use `RedisSingleHelper` (single Redis instance), `RedisClusterHelper` (Redis Cluster mode), or `RedisSentinelHelper` (Sentinel HA). All extend `AbstractRedisHelper` and satisfy the `IRedisHelper` interface that the component validates against:
|
|
153
|
-
|
|
154
|
-
```typescript
|
|
155
|
-
import { RedisClusterHelper } from '@venizia/ignis-helpers';
|
|
156
|
-
|
|
157
|
-
// For Redis Cluster deployments
|
|
158
|
-
const redisHelper = new RedisClusterHelper({
|
|
159
|
-
name: 'socket-io-redis-cluster',
|
|
160
|
-
nodes: [
|
|
161
|
-
{ host: 'redis-node-1', port: 6379 },
|
|
162
|
-
{ host: 'redis-node-2', port: 6380 },
|
|
163
|
-
{ host: 'redis-node-3', port: 6381 },
|
|
164
|
-
],
|
|
165
|
-
password: process.env.REDIS_PASSWORD,
|
|
166
|
-
autoConnect: false,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
this.bind<RedisClusterHelper>({
|
|
170
|
-
key: SocketIOBindingKeys.REDIS_CONNECTION,
|
|
171
|
-
}).toValue(redisHelper);
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
The internal `TRedisClient` type is `Redis | Cluster`, so both ioredis connection types are supported transparently.
|
|
175
|
-
|
|
176
|
-
## Configuration
|
|
177
|
-
|
|
178
|
-
### Default Server Options
|
|
179
|
-
|
|
180
|
-
The component applies these defaults if `SocketIOBindingKeys.SERVER_OPTIONS` is not bound or partially overridden:
|
|
181
|
-
|
|
182
|
-
| Option | Default | Description |
|
|
183
|
-
|--------|---------|-------------|
|
|
184
|
-
| `identifier` | `'SOCKET_IO_SERVER'` | Unique identifier for the helper instance |
|
|
185
|
-
| `path` | `'/io'` | URL path for Socket.IO handshake/polling |
|
|
186
|
-
| `cors.origin` | `'*'` | Allowed origins (restrict in production!) |
|
|
187
|
-
| `cors.methods` | `['GET', 'POST']` | Allowed HTTP methods for CORS preflight |
|
|
188
|
-
| `cors.preflightContinue` | `false` | Pass preflight to next handler |
|
|
189
|
-
| `cors.optionsSuccessStatus` | `204` | Status code for successful OPTIONS requests |
|
|
190
|
-
| `cors.credentials` | `true` | Allow cookies/auth headers |
|
|
191
|
-
| `perMessageDeflate.threshold` | `4096` | Minimum message size to compress (bytes) |
|
|
192
|
-
| `perMessageDeflate.concurrencyLimit` | `20` | Max concurrent compression operations |
|
|
193
|
-
| `perMessageDeflate.clientNoContextTakeover` | `true` | Client releases compression context after each message |
|
|
194
|
-
| `perMessageDeflate.serverNoContextTakeover` | `true` | Server releases compression context after each message |
|
|
195
|
-
| `perMessageDeflate.serverMaxWindowBits` | `10` | Server-side maximum window size (2^10 = 1KB) |
|
|
196
|
-
|
|
197
73
|
> [!WARNING]
|
|
198
|
-
>
|
|
74
|
+
> `autoConnect: false` is required on the Redis helper -- the server helper duplicates the connection into 3 independent clients and connects them itself during `configure()`. Connecting the parent first races against the duplicates. Full step-by-step setup (Bun peer dependency, room validation, cluster/sentinel Redis, the `autoConnect` rationale) is in [Usage & Examples](./usage#full-setup).
|
|
199
75
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
methods: ['GET', 'POST'],
|
|
208
|
-
preflightContinue: false,
|
|
209
|
-
optionsSuccessStatus: 204,
|
|
210
|
-
credentials: true,
|
|
211
|
-
},
|
|
212
|
-
perMessageDeflate: {
|
|
213
|
-
threshold: 4096,
|
|
214
|
-
zlibDeflateOptions: { chunkSize: 10 * 1024 },
|
|
215
|
-
zlibInflateOptions: { windowBits: 12, memLevel: 8 },
|
|
216
|
-
clientNoContextTakeover: true,
|
|
217
|
-
serverNoContextTakeover: true,
|
|
218
|
-
serverMaxWindowBits: 10,
|
|
219
|
-
concurrencyLimit: 20,
|
|
220
|
-
},
|
|
221
|
-
};
|
|
222
|
-
```
|
|
76
|
+
## How It Works
|
|
77
|
+
|
|
78
|
+
- **Post-start hook, not immediate init.** Socket.IO needs a running server, but components initialize *before* the server starts. `binding()` resolves all bindings and registers a post-start hook; the hook builds `SocketIOServerHelper` and binds it to `SOCKET_IO_INSTANCE` only after `start()` brings the server up.
|
|
79
|
+
- **Runtime detection picks the wiring.** `RuntimeModules.detect()` selects Node.js (Socket.IO attaches to `node:http.Server` directly) or Bun (`@socket.io/bun-engine` is dynamically imported and wired into `server.reload()`). See the [runtime matrix](./api#runtime-specific-behavior) for the full comparison.
|
|
80
|
+
- **One Redis connection becomes three.** The connection you bind is never consumed directly -- the helper calls `duplicateClient()` three times: a pub/sub pair for the Redis adapter (cross-instance room broadcast) and a third client for the Redis emitter (cross-instance direct send).
|
|
81
|
+
- **Authentication is mandatory.** Every client starts `unauthorized` and must emit `authenticate` within `authenticateTimeout` (default 10s) or it is disconnected. Success joins the client to the default rooms and starts a keep-alive ping.
|
|
82
|
+
- **Room joins are opt-in by default.** Without a bound `VALIDATE_ROOM_HANDLER`, every `join` request is silently rejected -- security-by-default, not a bug.
|
|
223
83
|
|
|
224
|
-
|
|
84
|
+
## Common Tasks
|
|
225
85
|
|
|
226
|
-
|
|
86
|
+
**Restrict CORS for production.** Bind `SERVER_OPTIONS` before registering the component -- the default (`cors.origin: '*'`) is for local development only.
|
|
227
87
|
|
|
228
88
|
```typescript
|
|
229
|
-
import { SocketIOBindingKeys } from '@venizia/ignis/socket-io';
|
|
230
89
|
import type { ServerOptions } from 'socket.io';
|
|
231
90
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
origin: ['https://myapp.com', 'https://admin.myapp.com'],
|
|
236
|
-
methods: ['GET', 'POST'],
|
|
237
|
-
credentials: true,
|
|
238
|
-
},
|
|
239
|
-
pingTimeout: 60000,
|
|
240
|
-
pingInterval: 25000,
|
|
241
|
-
maxHttpBufferSize: 1e6, // 1MB
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
this.bind<Partial<ServerOptions>>({
|
|
245
|
-
key: SocketIOBindingKeys.SERVER_OPTIONS,
|
|
246
|
-
}).toValue(customOptions);
|
|
247
|
-
|
|
91
|
+
this.bind<Partial<ServerOptions>>({ key: SocketIOBindingKeys.SERVER_OPTIONS }).toValue({
|
|
92
|
+
cors: { origin: ['https://myapp.com'], credentials: true },
|
|
93
|
+
});
|
|
248
94
|
this.component(SocketIOComponent);
|
|
249
95
|
```
|
|
250
96
|
|
|
251
|
-
|
|
252
|
-
> The `identifier` field is part of the component's `IServerOptions` interface (which extends `ServerOptions`), not Socket.IO's native options. To set the identifier, include it in the bound options object.
|
|
253
|
-
|
|
254
|
-
## Binding Keys
|
|
255
|
-
|
|
256
|
-
All binding keys are available in `SocketIOBindingKeys`:
|
|
257
|
-
|
|
258
|
-
| Binding Key | Constant | Type | Required | Default |
|
|
259
|
-
|------------|----------|------|----------|---------|
|
|
260
|
-
| `@app/socket-io/server-options` | `SERVER_OPTIONS` | `Partial<ServerOptions>` | No | See defaults above |
|
|
261
|
-
| `@app/socket-io/redis-connection` | `REDIS_CONNECTION` | `IRedisHelper` (`RedisSingleHelper` / `RedisClusterHelper` / `RedisSentinelHelper`) | **Yes** | `null` |
|
|
262
|
-
| `@app/socket-io/authenticate-handler` | `AUTHENTICATE_HANDLER` | `TSocketIOAuthenticateFn` | **Yes** | `null` |
|
|
263
|
-
| `@app/socket-io/validate-room-handler` | `VALIDATE_ROOM_HANDLER` | `TSocketIOValidateRoomFn` | No | `null` |
|
|
264
|
-
| `@app/socket-io/client-connected-handler` | `CLIENT_CONNECTED_HANDLER` | `TSocketIOClientConnectedFn` | No | `null` |
|
|
265
|
-
| `@app/socket-io/instance` | `SOCKET_IO_INSTANCE` | `SocketIOServerHelper` | -- | *Set by component* |
|
|
97
|
+
**Send a message from a service.** `SOCKET_IO_INSTANCE` is bound by the component after the server starts, so resolve it lazily -- never `@inject` it in a constructor. Full pattern in [Usage & Examples](./usage).
|
|
266
98
|
|
|
267
|
-
> [!NOTE]
|
|
268
|
-
> `SOCKET_IO_INSTANCE` is **not** set by you -- the component creates and binds it automatically after the server starts. Inject it in services/controllers to interact with Socket.IO.
|
|
269
|
-
|
|
270
|
-
## Constants
|
|
271
|
-
|
|
272
|
-
Constants are exported from `@venizia/ignis-helpers/socket-io` and used internally by both the component and the helper.
|
|
273
|
-
|
|
274
|
-
### System Events
|
|
275
|
-
|
|
276
|
-
| Constant | Value | Description |
|
|
277
|
-
|----------|-------|-------------|
|
|
278
|
-
| `SocketIOConstants.EVENT_PING` | `'ping'` | Keep-alive ping emitted at `pingInterval` (default: 30s) |
|
|
279
|
-
| `SocketIOConstants.EVENT_CONNECT` | `'connection'` | New client connected (server-side event) |
|
|
280
|
-
| `SocketIOConstants.EVENT_DISCONNECT` | `'disconnect'` | Client disconnected |
|
|
281
|
-
| `SocketIOConstants.EVENT_JOIN` | `'join'` | Client requests to join room(s) |
|
|
282
|
-
| `SocketIOConstants.EVENT_LEAVE` | `'leave'` | Client requests to leave room(s) |
|
|
283
|
-
| `SocketIOConstants.EVENT_AUTHENTICATE` | `'authenticate'` | Client sends auth credentials |
|
|
284
|
-
| `SocketIOConstants.EVENT_AUTHENTICATED` | `'authenticated'` | Auth success response sent to client |
|
|
285
|
-
| `SocketIOConstants.EVENT_UNAUTHENTICATE` | `'unauthenticated'` | Auth failure response sent to client |
|
|
286
|
-
|
|
287
|
-
### Default Rooms
|
|
288
|
-
|
|
289
|
-
All authenticated clients are automatically joined to these rooms:
|
|
290
|
-
|
|
291
|
-
| Constant | Value | Description |
|
|
292
|
-
|----------|-------|-------------|
|
|
293
|
-
| `SocketIOConstants.ROOM_DEFAULT` | `'io-default'` | Default room all authenticated clients join |
|
|
294
|
-
| `SocketIOConstants.ROOM_NOTIFICATION` | `'io-notification'` | Notification broadcast room |
|
|
295
|
-
|
|
296
|
-
> [!TIP]
|
|
297
|
-
> You can override default rooms via the `defaultRooms` option on `SocketIOServerHelper`. The component uses the defaults above when not overridden.
|
|
298
|
-
|
|
299
|
-
### Internal Constants (Server Helper)
|
|
300
|
-
|
|
301
|
-
These constants are defined at module scope in the server helper and are not exported, but they govern default behavior:
|
|
302
|
-
|
|
303
|
-
| Constant | Value | Description |
|
|
304
|
-
|----------|-------|-------------|
|
|
305
|
-
| `CLIENT_AUTHENTICATE_TIMEOUT` | `10_000` (10s) | Time allowed for a client to authenticate before forced disconnect |
|
|
306
|
-
| `CLIENT_PING_INTERVAL` | `30_000` (30s) | Interval between server-to-client ping emissions |
|
|
307
|
-
|
|
308
|
-
Both can be overridden via the `authenticateTimeout` and `pingInterval` constructor options on `SocketIOServerHelper`.
|
|
309
|
-
|
|
310
|
-
### Client States
|
|
311
|
-
|
|
312
|
-
Each connected client tracks an authentication state that governs what actions are permitted:
|
|
313
|
-
|
|
314
|
-
| State | Constant | Description |
|
|
315
|
-
|-------|----------|-------------|
|
|
316
|
-
| `unauthorized` | `SocketIOClientStates.UNAUTHORIZED` | Initial state -- client must emit `authenticate` within the timeout (default: 10s) |
|
|
317
|
-
| `authenticating` | `SocketIOClientStates.AUTHENTICATING` | Auth in progress -- `authenticateFn` is executing |
|
|
318
|
-
| `authenticated` | `SocketIOClientStates.AUTHENTICATED` | Auth successful -- client can send/receive events and join rooms |
|
|
319
|
-
|
|
320
|
-
#### State Machine Diagram
|
|
321
|
-
```
|
|
322
|
-
+------------------+
|
|
323
|
-
connect ---------->| unauthorized |
|
|
324
|
-
+--------+---------+
|
|
325
|
-
| emit('authenticate')
|
|
326
|
-
+--------v---------+
|
|
327
|
-
| authenticating |
|
|
328
|
-
+---+----------+---+
|
|
329
|
-
success | | failure
|
|
330
|
-
+---------v--+ +-------v-----------+
|
|
331
|
-
|authenticated| | unauthorized |--> disconnect
|
|
332
|
-
+-------------+ +------------------+
|
|
333
|
-
^
|
|
334
|
-
timeout (10s)
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
#### `SocketIOClientStates` Source
|
|
338
99
|
```typescript
|
|
339
|
-
|
|
340
|
-
static readonly UNAUTHORIZED = 'unauthorized';
|
|
341
|
-
static readonly AUTHENTICATING = 'authenticating';
|
|
342
|
-
static readonly AUTHENTICATED = 'authenticated';
|
|
343
|
-
|
|
344
|
-
static readonly SCHEME_SET = new Set([
|
|
345
|
-
this.UNAUTHORIZED,
|
|
346
|
-
this.AUTHENTICATING,
|
|
347
|
-
this.AUTHENTICATED,
|
|
348
|
-
]);
|
|
349
|
-
|
|
350
|
-
static isValid(input: string): input is TConstValue<typeof SocketIOClientStates> {
|
|
351
|
-
return this.SCHEME_SET.has(input);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
100
|
+
this.io.send({ destination: userId, payload: { topic: 'notification', data } });
|
|
354
101
|
```
|
|
355
102
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
The component resolves all binding keys into a single `IResolvedBindings` object during the `binding()` phase:
|
|
103
|
+
**Scale Redis beyond a single node.** Swap `RedisSingleHelper` for `RedisClusterHelper` or `RedisSentinelHelper` -- both satisfy the `IRedisHelper` interface the component validates against. See [Redis Connection Alternatives](./usage#redis-connection-alternatives).
|
|
359
104
|
|
|
360
|
-
|
|
361
|
-
```typescript
|
|
362
|
-
interface IResolvedBindings {
|
|
363
|
-
redisConnection: IRedisHelper;
|
|
364
|
-
authenticateFn: TSocketIOAuthenticateFn;
|
|
365
|
-
validateRoomFn?: TSocketIOValidateRoomFn;
|
|
366
|
-
clientConnectedFn?: TSocketIOClientConnectedFn;
|
|
367
|
-
}
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
#### Callback Type Signatures
|
|
371
|
-
```typescript
|
|
372
|
-
// Called with the socket handshake -- return true to authenticate, false to reject
|
|
373
|
-
type TSocketIOAuthenticateFn = (args: IHandshake) => ValueOrPromise<boolean>;
|
|
374
|
-
|
|
375
|
-
// Called when client emits 'join' -- return the subset of rooms the client is allowed to join
|
|
376
|
-
type TSocketIOValidateRoomFn = (opts: {
|
|
377
|
-
socket: IOSocket;
|
|
378
|
-
rooms: string[];
|
|
379
|
-
}) => ValueOrPromise<string[]>;
|
|
380
|
-
|
|
381
|
-
// Called after successful authentication -- register custom event handlers here
|
|
382
|
-
type TSocketIOClientConnectedFn = (opts: { socket: IOSocket }) => ValueOrPromise<void>;
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
#### `IHandshake` Interface
|
|
386
|
-
```typescript
|
|
387
|
-
interface IHandshake {
|
|
388
|
-
headers: IncomingHttpHeaders;
|
|
389
|
-
time: string;
|
|
390
|
-
address: string;
|
|
391
|
-
xdomain: boolean;
|
|
392
|
-
secure: boolean;
|
|
393
|
-
issued: number;
|
|
394
|
-
url: string;
|
|
395
|
-
query: ParsedUrlQuery;
|
|
396
|
-
auth: { [key: string]: any };
|
|
397
|
-
}
|
|
398
|
-
```
|
|
105
|
+
**Look up every default, binding key, and constant.** Full `DEFAULT_SERVER_OPTIONS`, the binding key table, system events, default rooms, and the client state machine are in the [API Reference](./api#configuration-reference).
|
|
399
106
|
|
|
400
107
|
## See Also
|
|
401
108
|
|
|
402
|
-
- [Usage & Examples](./usage) --
|
|
403
|
-
- [API Reference](./api) -- Architecture, method signatures, internals, types
|
|
109
|
+
- [Usage & Examples](./usage) -- Full setup steps, server-side usage, client helper, advanced patterns
|
|
110
|
+
- [API Reference](./api) -- Architecture, configuration reference, method signatures, internals, types
|
|
404
111
|
- [Error Reference](./errors) -- Error conditions and troubleshooting
|
|
405
112
|
- **Guides:**
|
|
406
113
|
- [Components Overview](/guides/core-concepts/components) -- Component system basics
|
|
@@ -417,3 +124,9 @@ interface IHandshake {
|
|
|
417
124
|
- [Real-Time Chat](/guides/tutorials/realtime-chat) -- Building a chat app with Socket.IO
|
|
418
125
|
- **Changelog:**
|
|
419
126
|
- [2026-02-06: Socket.IO Integration Fix](/changelogs/2026-02-06-socket-io-integration-fix) -- Lifecycle timing fix + Bun runtime support
|
|
127
|
+
|
|
128
|
+
**Files:**
|
|
129
|
+
|
|
130
|
+
- [`packages/core/src/components/socket-io/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/socket-io/component.ts) -- `SocketIOComponent`
|
|
131
|
+
- [`packages/core/src/components/socket-io/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/socket-io/common/keys.ts) -- `SocketIOBindingKeys`
|
|
132
|
+
- [`packages/core/src/components/socket-io/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/socket-io/common/types.ts) -- `IServerOptions`, `DEFAULT_SERVER_OPTIONS`
|