@venizia/ignis-docs 0.2.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/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +24 -13
- 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 +27 -3
- 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 +8 -4
- 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 +247 -153
- 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 +109 -323
- package/content/extensions/components/authentication/api.md +489 -602
- package/content/extensions/components/authentication/errors.md +135 -498
- package/content/extensions/components/authentication/index.md +89 -801
- package/content/extensions/components/authentication/usage.md +231 -955
- package/content/extensions/components/authorization/api.md +991 -644
- package/content/extensions/components/authorization/errors.md +204 -208
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +88 -795
- package/content/extensions/components/authorization/usage.md +219 -528
- package/content/extensions/components/health-check.md +77 -243
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +553 -285
- package/content/extensions/components/mail/errors.md +76 -62
- package/content/extensions/components/mail/index.md +111 -463
- package/content/extensions/components/mail/usage.md +139 -173
- package/content/extensions/components/request-tracker.md +70 -173
- package/content/extensions/components/socket-io/api.md +462 -785
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +69 -372
- package/content/extensions/components/socket-io/usage.md +212 -105
- package/content/extensions/components/static-asset/api.md +461 -141
- package/content/extensions/components/static-asset/errors.md +121 -53
- package/content/extensions/components/static-asset/index.md +84 -606
- package/content/extensions/components/static-asset/usage.md +184 -299
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +311 -404
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +75 -407
- package/content/extensions/components/websocket/usage.md +120 -338
- package/content/extensions/helpers/cron/index.md +52 -160
- package/content/extensions/helpers/crypto/index.md +67 -480
- package/content/extensions/helpers/crypto/reference.md +528 -0
- package/content/extensions/helpers/env/index.md +64 -178
- package/content/extensions/helpers/error/index.md +286 -196
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +76 -550
- package/content/extensions/helpers/inversion/reference.md +530 -0
- package/content/extensions/helpers/kafka/admin.md +23 -3
- package/content/extensions/helpers/kafka/compile-binary.md +83 -52
- package/content/extensions/helpers/kafka/consumer.md +65 -28
- package/content/extensions/helpers/kafka/examples.md +46 -253
- package/content/extensions/helpers/kafka/index.md +55 -617
- package/content/extensions/helpers/kafka/producer.md +156 -22
- package/content/extensions/helpers/kafka/schema-registry.md +59 -79
- package/content/extensions/helpers/logger/hf-logger.md +220 -0
- package/content/extensions/helpers/logger/index.md +78 -552
- package/content/extensions/helpers/logger/pino.md +105 -0
- package/content/extensions/helpers/logger/reference.md +937 -0
- package/content/extensions/helpers/network/api.md +276 -195
- package/content/extensions/helpers/network/index.md +87 -524
- package/content/extensions/helpers/queue/index.md +80 -897
- package/content/extensions/helpers/queue/reference.md +494 -0
- package/content/extensions/helpers/redis/index.md +86 -640
- package/content/extensions/helpers/redis/reference.md +784 -0
- package/content/extensions/helpers/secrets/index.md +136 -0
- package/content/extensions/helpers/socket-io/api.md +325 -204
- package/content/extensions/helpers/socket-io/index.md +79 -429
- package/content/extensions/helpers/storage/api.md +584 -464
- package/content/extensions/helpers/storage/index.md +80 -573
- package/content/extensions/helpers/types/index.md +75 -495
- package/content/extensions/helpers/types/reference.md +689 -0
- package/content/extensions/helpers/uid/index.md +176 -189
- package/content/extensions/helpers/websocket/api.md +366 -214
- package/content/extensions/helpers/websocket/index.md +68 -503
- package/content/extensions/helpers/worker-thread/index.md +62 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- 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/models.md +1 -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 +28 -16
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- 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 +5 -4
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +8 -7
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +64 -22
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +600 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +25 -46
- package/content/references/base/filter-system/application-usage.md +95 -123
- package/content/references/base/filter-system/array-operators.md +33 -43
- package/content/references/base/filter-system/comparison-operators.md +55 -63
- package/content/references/base/filter-system/default-filter.md +144 -350
- package/content/references/base/filter-system/fields-order-pagination.md +116 -148
- package/content/references/base/filter-system/index.md +114 -253
- package/content/references/base/filter-system/json-filtering.md +52 -181
- package/content/references/base/filter-system/list-operators.md +28 -44
- package/content/references/base/filter-system/logical-operators.md +69 -114
- package/content/references/base/filter-system/null-operators.md +41 -98
- package/content/references/base/filter-system/pattern-matching.md +48 -51
- package/content/references/base/filter-system/quick-reference.md +93 -196
- package/content/references/base/filter-system/range-operators.md +22 -38
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +173 -232
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +43 -28
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +81 -1452
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +281 -419
- package/content/references/base/repositories/index.md +84 -644
- package/content/references/base/repositories/mixins.md +25 -21
- package/content/references/base/repositories/relations.md +194 -375
- package/content/references/base/repositories/soft-deletable.md +67 -55
- package/content/references/base/secrets.md +267 -0
- package/content/references/base/services.md +8 -6
- package/content/references/configuration/environment-variables.md +73 -21
- package/content/references/configuration/index.md +51 -31
- package/content/references/index.md +1 -1
- 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/duration.md +85 -0
- package/content/references/utilities/index.md +6 -2
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +81 -61
- 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 +58 -218
- package/content/references/utilities/retry.md +139 -0
- 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/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 +24 -23
|
@@ -1,419 +1,116 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Socket.IO Component
|
|
3
|
+
description: Wires SocketIOServerHelper into the app lifecycle for Node.js and Bun, with Redis-backed horizontal scaling and a mandatory authentication handshake
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
# Socket.IO Component
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
`SocketIOComponent` registers a [`SocketIOServerHelper`](/extensions/helpers/socket-io/) on your application once the server starts. It runs on both Node.js and Bun, and scales across instances through a Redis adapter. Every client must authenticate before it can send or receive anything.
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
| **Package** | `@venizia/ignis` (core) |
|
|
10
|
-
| **Class** | `SocketIOComponent` |
|
|
11
|
-
| **Server Helper** | [`SocketIOServerHelper`](/extensions/helpers/socket-io/) |
|
|
12
|
-
| **Client Helper** | [`SocketIOClientHelper`](/extensions/helpers/socket-io/) |
|
|
13
|
-
| **Runtimes** | Node.js (`@hono/node-server`) and Bun (native) |
|
|
14
|
-
| **Scaling** | `@socket.io/redis-adapter` + `@socket.io/redis-emitter` |
|
|
15
|
-
|
|
16
|
-
#### Import Paths
|
|
17
|
-
|
|
18
|
-
> [!IMPORTANT]
|
|
19
|
-
> `SocketIOComponent` and `SocketIOBindingKeys` are **not** exported from the `@venizia/ignis` barrel. You must import from the `@venizia/ignis/socket-io` subpath.
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
// From core -- subpath import (NOT from '@venizia/ignis')
|
|
23
|
-
import {
|
|
24
|
-
SocketIOComponent,
|
|
25
|
-
SocketIOBindingKeys,
|
|
26
|
-
} from '@venizia/ignis/socket-io';
|
|
27
|
-
|
|
28
|
-
// From helpers -- subpath import
|
|
29
|
-
import {
|
|
30
|
-
SocketIOServerHelper,
|
|
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';
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Use Cases
|
|
49
|
-
|
|
50
|
-
- Live notifications and alerts
|
|
51
|
-
- Real-time chat and messaging
|
|
52
|
-
- Collaborative editing (docs, whiteboards)
|
|
53
|
-
- Live data streams (dashboards, monitoring)
|
|
54
|
-
- Multiplayer game state synchronization
|
|
55
|
-
- Service-to-service real-time communication (via `SocketIOClientHelper`)
|
|
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
|
|
64
|
-
|
|
65
|
-
# For Bun runtime only -- optional peer dependency
|
|
66
|
-
bun add @socket.io/bun-engine
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Step 2: Bind Required Services
|
|
11
|
+
> [!TIP]
|
|
12
|
+
> Bun-only and don't need Socket.IO's handshake protocol? The [WebSocket Component](../websocket/) is a lighter alternative.
|
|
70
13
|
|
|
71
|
-
In
|
|
14
|
+
## In one example
|
|
72
15
|
|
|
73
16
|
```typescript
|
|
74
17
|
import { BaseApplication } from '@venizia/ignis';
|
|
75
|
-
import {
|
|
76
|
-
SocketIOComponent,
|
|
77
|
-
SocketIOBindingKeys,
|
|
78
|
-
} from '@venizia/ignis/socket-io';
|
|
18
|
+
import { SocketIOComponent, SocketIOBindingKeys } from '@venizia/ignis/socket-io';
|
|
79
19
|
import { RedisSingleHelper, ValueOrPromise } from '@venizia/ignis-helpers';
|
|
80
|
-
import type {
|
|
81
|
-
TSocketIOAuthenticateFn,
|
|
82
|
-
TSocketIOValidateRoomFn,
|
|
83
|
-
TSocketIOClientConnectedFn,
|
|
84
|
-
} from '@venizia/ignis-helpers/socket-io';
|
|
20
|
+
import type { TSocketIOAuthenticateFn } from '@venizia/ignis-helpers/socket-io';
|
|
85
21
|
|
|
86
22
|
export class Application extends BaseApplication {
|
|
87
|
-
private redisHelper: RedisSingleHelper;
|
|
88
|
-
|
|
89
23
|
preConfigure(): ValueOrPromise<void> {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
setupSocketIO() {
|
|
95
|
-
// 1. Redis connection (required for adapter + emitter)
|
|
96
|
-
this.redisHelper = new RedisSingleHelper({
|
|
97
|
-
name: 'socket-io-redis',
|
|
98
|
-
host: process.env.REDIS_HOST ?? 'localhost',
|
|
99
|
-
port: +(process.env.REDIS_PORT ?? 6379),
|
|
100
|
-
password: process.env.REDIS_PASSWORD,
|
|
101
|
-
autoConnect: false,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
this.bind<RedisSingleHelper>({
|
|
105
|
-
key: SocketIOBindingKeys.REDIS_CONNECTION,
|
|
106
|
-
}).toValue(this.redisHelper);
|
|
24
|
+
// 1. Redis connection (required - used for the adapter + emitter)
|
|
25
|
+
this.bind({ key: SocketIOBindingKeys.REDIS_CONNECTION }).toValue(
|
|
26
|
+
new RedisSingleHelper({ name: 'socket-io-redis', host: 'localhost', port: 6379, autoConnect: false }),
|
|
27
|
+
);
|
|
107
28
|
|
|
108
|
-
// 2.
|
|
109
|
-
const authenticateFn: TSocketIOAuthenticateFn = handshake =>
|
|
110
|
-
|
|
111
|
-
// Implement your auth logic -- JWT verification, session check, etc.
|
|
112
|
-
return !!token;
|
|
113
|
-
};
|
|
29
|
+
// 2. Authenticate handler (required - decides accept/reject per client)
|
|
30
|
+
const authenticateFn: TSocketIOAuthenticateFn = handshake => !!handshake.headers.authorization;
|
|
31
|
+
this.bind({ key: SocketIOBindingKeys.AUTHENTICATE_HANDLER }).toValue(authenticateFn);
|
|
114
32
|
|
|
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!
|
|
33
|
+
// 3. Register - binding() validates the two bindings above and defers the rest
|
|
141
34
|
this.component(SocketIOComponent);
|
|
142
35
|
}
|
|
143
36
|
}
|
|
144
37
|
```
|
|
145
38
|
|
|
146
|
-
|
|
39
|
+
`SocketIOComponent` and `SocketIOBindingKeys` come from the `@venizia/ignis/socket-io` subpath. They are **not** exported from the `@venizia/ignis` root barrel. Helper types (`TSocketIOAuthenticateFn`, `SocketIOServerHelper`, `SocketIOClientHelper`, `SocketIOConstants`, ...) come from `@venizia/ignis-helpers/socket-io`.
|
|
147
40
|
|
|
148
|
-
|
|
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
|
|
41
|
+
> [!WARNING]
|
|
42
|
+
> `autoConnect: false` is required on the Redis helper. The server helper duplicates the connection into 3 independent clients and connects them itself during `configure()`. Connect the parent first and it races against the duplicates. Full explanation in [Usage & Examples](./usage#full-setup).
|
|
179
43
|
|
|
180
|
-
|
|
44
|
+
## How it works
|
|
181
45
|
|
|
182
|
-
|
|
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) |
|
|
46
|
+
Socket.IO needs a running server, but components initialize before the server exists. Five mechanisms bridge that gap and keep every client on a security-by-default path:
|
|
196
47
|
|
|
197
|
-
|
|
198
|
-
|
|
48
|
+
| Mechanism | What happens |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Post-start hook | `binding()` runs during `initialize()`, resolves bindings, and registers a hook. The hook builds `SocketIOServerHelper` and binds it to `SOCKET_IO_INSTANCE` only after `start()` runs. |
|
|
51
|
+
| Runtime detection | `RuntimeModules.detect()` picks 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 comparison](./api#runtime-specific-behavior). |
|
|
52
|
+
| Redis fan-out | The connection you bind is never consumed directly. The helper calls `duplicateClient()` three times: a pub/sub pair for the Redis adapter, and a third client for the Redis emitter. |
|
|
53
|
+
| Mandatory authentication | Every client starts `unauthorized`. It must emit `authenticate` within `authenticateTimeout` (default 10s) or it gets disconnected. Success joins the client to the default rooms and starts a keep-alive ping. |
|
|
54
|
+
| Opt-in rooms | No `VALIDATE_ROOM_HANDLER` bound means every `join` request is rejected. That's security-by-default, not a bug. |
|
|
199
55
|
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
const DEFAULT_SERVER_OPTIONS: Partial<IServerOptions> = {
|
|
203
|
-
identifier: 'SOCKET_IO_SERVER',
|
|
204
|
-
path: '/io',
|
|
205
|
-
cors: {
|
|
206
|
-
origin: '*',
|
|
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
|
-
```
|
|
56
|
+
## Common tasks
|
|
223
57
|
|
|
224
|
-
###
|
|
58
|
+
### Restrict CORS for production
|
|
225
59
|
|
|
226
|
-
Bind
|
|
60
|
+
Bind `SERVER_OPTIONS` before registering the component. The default (`cors.origin: '*'`) is for local development only.
|
|
227
61
|
|
|
228
62
|
```typescript
|
|
229
|
-
import { SocketIOBindingKeys } from '@venizia/ignis/socket-io';
|
|
230
63
|
import type { ServerOptions } from 'socket.io';
|
|
231
64
|
|
|
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
|
-
|
|
65
|
+
this.bind<Partial<ServerOptions>>({ key: SocketIOBindingKeys.SERVER_OPTIONS }).toValue({
|
|
66
|
+
cors: { origin: ['https://myapp.com'], credentials: true },
|
|
67
|
+
});
|
|
248
68
|
this.component(SocketIOComponent);
|
|
249
69
|
```
|
|
250
70
|
|
|
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* |
|
|
266
|
-
|
|
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:
|
|
71
|
+
### Send a message from a service
|
|
302
72
|
|
|
303
|
-
|
|
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 |
|
|
73
|
+
`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 [Inject the helper in a service or controller](./usage#inject-the-helper-in-a-service-or-controller).
|
|
307
74
|
|
|
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
75
|
```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
|
-
}
|
|
76
|
+
this.io.send({ destination: userId, payload: { topic: 'notification', data } });
|
|
354
77
|
```
|
|
355
78
|
|
|
356
|
-
###
|
|
79
|
+
### Scale Redis beyond a single node
|
|
357
80
|
|
|
358
|
-
|
|
81
|
+
Swap `RedisSingleHelper` for `RedisClusterHelper` or `RedisSentinelHelper`. Both satisfy the `IRedisHelper` interface the component validates against. See [Redis connection alternatives](./usage#redis-connection-alternatives) for the full example.
|
|
359
82
|
|
|
360
|
-
#### `IResolvedBindings` Interface
|
|
361
83
|
```typescript
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
84
|
+
import { RedisClusterHelper } from '@venizia/ignis-helpers';
|
|
85
|
+
|
|
86
|
+
this.bind({ key: SocketIOBindingKeys.REDIS_CONNECTION }).toValue(
|
|
87
|
+
new RedisClusterHelper({
|
|
88
|
+
name: 'socket-io-redis-cluster',
|
|
89
|
+
nodes: [{ host: 'redis-node-1', port: 6379 }],
|
|
90
|
+
autoConnect: false,
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
368
93
|
```
|
|
369
94
|
|
|
370
|
-
|
|
371
|
-
```typescript
|
|
372
|
-
// Called with the socket handshake -- return true to authenticate, false to reject
|
|
373
|
-
type TSocketIOAuthenticateFn = (args: IHandshake) => ValueOrPromise<boolean>;
|
|
95
|
+
### Look up a default, binding key, or event name
|
|
374
96
|
|
|
375
|
-
|
|
376
|
-
type TSocketIOValidateRoomFn = (opts: {
|
|
377
|
-
socket: IOSocket;
|
|
378
|
-
rooms: string[];
|
|
379
|
-
}) => ValueOrPromise<string[]>;
|
|
97
|
+
Every `DEFAULT_SERVER_OPTIONS` field, the binding key table, system events, default rooms, and the client state machine live in the [Full Reference](./api#configuration-reference).
|
|
380
98
|
|
|
381
|
-
|
|
382
|
-
type TSocketIOClientConnectedFn = (opts: { socket: IOSocket }) => ValueOrPromise<void>;
|
|
383
|
-
```
|
|
99
|
+
## See also
|
|
384
100
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
query: ParsedUrlQuery;
|
|
396
|
-
auth: { [key: string]: any };
|
|
397
|
-
}
|
|
398
|
-
```
|
|
101
|
+
- [Usage & Examples](./usage) - full setup steps, server-side usage, client helper, advanced patterns
|
|
102
|
+
- [Full Reference](./api) - architecture, configuration reference, method signatures, internals, types
|
|
103
|
+
- [Error Reference](./errors) - error conditions and troubleshooting
|
|
104
|
+
- [Socket.IO Helper](/extensions/helpers/socket-io/) - full `SocketIOServerHelper` + `SocketIOClientHelper` API reference
|
|
105
|
+
- [WebSocket Component](../websocket/) - Bun-only alternative
|
|
106
|
+
- [Real-Time Chat tutorial](/guides/tutorials/realtime-chat) - building a chat app with Socket.IO
|
|
107
|
+
- [Socket.IO Documentation](https://socket.io/docs/) - official docs
|
|
108
|
+
- [Socket.IO Redis Adapter](https://socket.io/docs/v4/redis-adapter/) - horizontal scaling guide
|
|
109
|
+
- [@socket.io/bun-engine](https://github.com/socketio/bun-engine) - Bun runtime support
|
|
110
|
+
- [2026-02-06: Socket.IO Integration Fix](/changelogs/2026-02-06-socket-io-integration-fix) - lifecycle timing fix + Bun runtime support
|
|
399
111
|
|
|
400
|
-
|
|
112
|
+
**Files:**
|
|
401
113
|
|
|
402
|
-
- [
|
|
403
|
-
- [
|
|
404
|
-
- [
|
|
405
|
-
- **Guides:**
|
|
406
|
-
- [Components Overview](/guides/core-concepts/components) -- Component system basics
|
|
407
|
-
- [Application](/guides/core-concepts/application/) -- Registering components
|
|
408
|
-
- **Components:**
|
|
409
|
-
- [Components Index](../index) -- All built-in components
|
|
410
|
-
- **Helpers:**
|
|
411
|
-
- [Socket.IO Helper](/extensions/helpers/socket-io/) -- Full `SocketIOServerHelper` + `SocketIOClientHelper` API reference
|
|
412
|
-
- **External Resources:**
|
|
413
|
-
- [Socket.IO Documentation](https://socket.io/docs/) -- Official docs
|
|
414
|
-
- [Socket.IO Redis Adapter](https://socket.io/docs/v4/redis-adapter/) -- Horizontal scaling guide
|
|
415
|
-
- [@socket.io/bun-engine](https://github.com/socketio/bun-engine) -- Bun runtime support
|
|
416
|
-
- **Tutorials:**
|
|
417
|
-
- [Real-Time Chat](/guides/tutorials/realtime-chat) -- Building a chat app with Socket.IO
|
|
418
|
-
- **Changelog:**
|
|
419
|
-
- [2026-02-06: Socket.IO Integration Fix](/changelogs/2026-02-06-socket-io-integration-fix) -- Lifecycle timing fix + Bun runtime support
|
|
114
|
+
- [`packages/core-server/src/components/socket-io/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/socket-io/component.ts) - `SocketIOComponent`
|
|
115
|
+
- [`packages/core-server/src/components/socket-io/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/socket-io/common/keys.ts) - `SocketIOBindingKeys`
|
|
116
|
+
- [`packages/core-server/src/components/socket-io/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/socket-io/common/types.ts) - `IServerOptions`, `DEFAULT_SERVER_OPTIONS`
|