@venizia/ignis-docs 0.0.8 → 0.2.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 +7 -7
- package/content/best-practices/api-usage-examples.md +15 -12
- package/content/best-practices/architectural-patterns.md +70 -78
- package/content/best-practices/architecture-decisions.md +91 -60
- package/content/best-practices/code-style-standards/advanced-patterns.md +56 -44
- package/content/best-practices/code-style-standards/constants-configuration.md +11 -11
- package/content/best-practices/code-style-standards/control-flow.md +5 -2
- package/content/best-practices/code-style-standards/documentation.md +13 -13
- package/content/best-practices/code-style-standards/function-patterns.md +9 -10
- package/content/best-practices/code-style-standards/index.md +1 -1
- package/content/best-practices/code-style-standards/naming-conventions.md +10 -8
- package/content/best-practices/code-style-standards/route-definitions.md +30 -12
- package/content/best-practices/code-style-standards/tooling.md +8 -5
- package/content/best-practices/code-style-standards/type-safety.md +13 -12
- package/content/best-practices/common-pitfalls.md +56 -37
- package/content/best-practices/contribution-workflow.md +13 -14
- package/content/best-practices/data-modeling.md +46 -22
- package/content/best-practices/deployment-strategies.md +28 -27
- package/content/best-practices/error-handling.md +48 -24
- package/content/best-practices/index.md +5 -5
- package/content/best-practices/performance-optimization.md +40 -31
- package/content/best-practices/security-guidelines.md +52 -23
- package/content/best-practices/testing-strategies.md +65 -51
- package/content/best-practices/troubleshooting-tips.md +24 -24
- package/content/extensions/components/{swagger.md → api-reference.md} +40 -31
- package/content/extensions/components/authentication/api.md +19 -19
- package/content/extensions/components/authentication/errors.md +7 -7
- package/content/extensions/components/authentication/index.md +10 -8
- package/content/extensions/components/authentication/usage.md +101 -6
- package/content/extensions/components/authorization/api.md +45 -25
- package/content/extensions/components/authorization/errors.md +6 -6
- package/content/extensions/components/authorization/index.md +11 -10
- package/content/extensions/components/authorization/usage.md +21 -21
- package/content/extensions/components/health-check.md +1 -1
- package/content/extensions/components/index.md +5 -5
- package/content/extensions/components/mail/errors.md +15 -15
- package/content/extensions/components/mail/index.md +1 -2
- package/content/extensions/components/mail/usage.md +1 -1
- package/content/extensions/components/request-tracker.md +1 -1
- package/content/extensions/components/socket-io/api.md +9 -9
- package/content/extensions/components/socket-io/errors.md +5 -5
- package/content/extensions/components/socket-io/index.md +8 -8
- package/content/extensions/components/socket-io/usage.md +1 -1
- package/content/extensions/components/static-asset/api.md +17 -4
- package/content/extensions/components/static-asset/errors.md +4 -4
- package/content/extensions/components/static-asset/index.md +26 -28
- package/content/extensions/components/static-asset/usage.md +13 -12
- package/content/extensions/components/template/index.md +2 -2
- package/content/extensions/components/template/setup-page.md +1 -1
- package/content/extensions/components/websocket/api.md +3 -3
- package/content/extensions/components/websocket/errors.md +5 -5
- package/content/extensions/components/websocket/index.md +5 -5
- package/content/extensions/components/websocket/usage.md +3 -3
- package/content/extensions/helpers/cron/index.md +2 -2
- package/content/extensions/helpers/crypto/index.md +1 -1
- package/content/extensions/helpers/env/index.md +27 -12
- package/content/extensions/helpers/error/index.md +81 -25
- package/content/extensions/helpers/index.md +2 -3
- package/content/extensions/helpers/inversion/index.md +15 -7
- package/content/extensions/helpers/kafka/compile-binary.md +92 -0
- package/content/extensions/helpers/kafka/examples.md +1 -1
- package/content/extensions/helpers/kafka/index.md +3 -0
- package/content/extensions/helpers/logger/index.md +32 -2
- package/content/extensions/helpers/network/index.md +6 -0
- package/content/extensions/helpers/queue/index.md +14 -17
- package/content/extensions/helpers/redis/index.md +548 -323
- package/content/extensions/helpers/socket-io/index.md +14 -10
- package/content/extensions/helpers/storage/api.md +44 -8
- package/content/extensions/helpers/storage/index.md +43 -7
- package/content/extensions/helpers/template/index.md +6 -3
- package/content/extensions/helpers/types/index.md +11 -8
- package/content/extensions/helpers/websocket/api.md +9 -9
- package/content/extensions/helpers/websocket/index.md +7 -7
- package/content/extensions/helpers/worker-thread/index.md +2 -2
- package/content/extensions/index.md +3 -4
- package/content/extensions/src-details/mcp-server.md +18 -24
- package/content/guides/core-concepts/application/bootstrapping.md +11 -14
- package/content/guides/core-concepts/application/index.md +3 -3
- package/content/guides/core-concepts/components.md +19 -10
- package/content/guides/core-concepts/dependency-injection.md +6 -3
- package/content/guides/core-concepts/grpc-controllers.md +6 -5
- package/content/guides/core-concepts/persistent/datasources.md +42 -43
- package/content/guides/core-concepts/persistent/index.md +16 -7
- package/content/guides/core-concepts/persistent/models.md +24 -20
- package/content/guides/core-concepts/persistent/postgres-drivers.md +201 -0
- package/content/guides/core-concepts/persistent/repositories.md +40 -23
- package/content/guides/core-concepts/persistent/search-meilisearch.md +185 -0
- package/content/guides/core-concepts/persistent/search-typesense.md +431 -0
- package/content/guides/core-concepts/persistent/transactions.md +61 -25
- package/content/guides/core-concepts/rest-controllers.md +12 -9
- package/content/guides/core-concepts/services.md +330 -60
- package/content/guides/get-started/5-minute-quickstart.md +15 -15
- package/content/guides/get-started/philosophy.md +36 -36
- package/content/guides/get-started/setup.md +3 -3
- package/content/guides/index.md +3 -3
- package/content/guides/migrations/redis-helpers-migration.md +177 -0
- package/content/guides/migrations/scoped-rbac-migration.md +17 -17
- package/content/guides/migrations/unified-connectors-migration.md +113 -0
- package/content/guides/reference/glossary.md +19 -12
- package/content/guides/reference/mcp-docs-server.md +22 -18
- package/content/guides/tutorials/building-a-crud-api.md +37 -44
- package/content/guides/tutorials/complete-installation.md +17 -17
- package/content/guides/tutorials/ecommerce-api.md +163 -124
- package/content/guides/tutorials/realtime-chat.md +181 -135
- package/content/guides/tutorials/testing.md +65 -523
- package/content/index.md +2 -180
- package/content/public/apple-touch-icon.png +0 -0
- package/content/public/og-image.png +0 -0
- package/content/public/site.webmanifest +11 -0
- package/content/references/base/application.md +4 -5
- package/content/references/base/bootstrapping.md +18 -5
- package/content/references/base/components.md +149 -120
- package/content/references/base/connectors.md +178 -0
- package/content/references/base/controllers.md +41 -30
- package/content/references/base/datasources.md +163 -92
- package/content/references/base/dependency-injection.md +34 -22
- package/content/references/base/filter-system/application-usage.md +17 -14
- package/content/references/base/filter-system/array-operators.md +7 -2
- package/content/references/base/filter-system/comparison-operators.md +3 -0
- package/content/references/base/filter-system/default-filter.md +89 -71
- package/content/references/base/filter-system/fields-order-pagination.md +22 -22
- package/content/references/base/filter-system/index.md +6 -3
- package/content/references/base/filter-system/json-filtering.md +20 -1
- package/content/references/base/filter-system/list-operators.md +1 -1
- package/content/references/base/filter-system/logical-operators.md +33 -1
- package/content/references/base/filter-system/null-operators.md +30 -1
- package/content/references/base/filter-system/quick-reference.md +23 -4
- package/content/references/base/filter-system/tips.md +5 -5
- package/content/references/base/filter-system/use-cases.md +12 -12
- package/content/references/base/grpc-controllers.md +13 -13
- package/content/references/base/index.md +24 -12
- package/content/references/base/middlewares.md +265 -327
- package/content/references/base/models.md +63 -49
- package/content/references/base/providers.md +136 -130
- package/content/references/base/repositories/advanced.md +59 -58
- package/content/references/base/repositories/index.md +115 -91
- package/content/references/base/repositories/mixins.md +55 -291
- package/content/references/base/repositories/relations.md +54 -64
- package/content/references/base/repositories/soft-deletable.md +31 -30
- package/content/references/base/services.md +296 -93
- package/content/references/configuration/environment-variables.md +49 -31
- package/content/references/configuration/index.md +6 -6
- package/content/references/index.md +17 -12
- package/content/references/quick-reference.md +65 -106
- package/content/references/utilities/crypto.md +65 -23
- package/content/references/utilities/index.md +3 -3
- package/content/references/utilities/jsx.md +6 -4
- package/content/references/utilities/module.md +68 -20
- package/content/references/utilities/parse.md +4 -14
- package/content/references/utilities/promise.md +9 -7
- package/content/references/utilities/schema.md +5 -3
- package/dist/mcp-server/common/guards.d.ts +8 -0
- package/dist/mcp-server/common/guards.d.ts.map +1 -0
- package/dist/mcp-server/common/guards.js +14 -0
- package/dist/mcp-server/common/guards.js.map +1 -0
- package/dist/mcp-server/common/index.d.ts +1 -0
- package/dist/mcp-server/common/index.d.ts.map +1 -1
- package/dist/mcp-server/common/index.js +1 -0
- package/dist/mcp-server/common/index.js.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.js +4 -2
- package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
- package/dist/mcp-server/helpers/github.helper.js +1 -1
- package/dist/mcp-server/index.js +7 -2
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/mcp-server/tools/base.tool.d.ts +6 -2
- package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/base.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
- package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
- package/package.json +9 -9
- package/content/extensions/helpers/testing/index.md +0 -510
- package/content/references/base/middleware.md +0 -347
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
SocketIOClientHelper,
|
|
18
18
|
SocketIOConstants,
|
|
19
19
|
SocketIOClientStates,
|
|
20
|
-
} from '@venizia/ignis-helpers';
|
|
20
|
+
} from '@venizia/ignis-helpers/socket-io';
|
|
21
21
|
|
|
22
22
|
import type {
|
|
23
23
|
TSocketIOServerOptions,
|
|
@@ -33,7 +33,7 @@ import type {
|
|
|
33
33
|
TSocketIOClientConnectedFn,
|
|
34
34
|
TSocketIOEventHandler,
|
|
35
35
|
TSocketIOClientState,
|
|
36
|
-
} from '@venizia/ignis-helpers';
|
|
36
|
+
} from '@venizia/ignis-helpers/socket-io';
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Creating an Instance
|
|
@@ -43,16 +43,17 @@ import type {
|
|
|
43
43
|
`SocketIOServerHelper` requires a Redis connection for the pub/sub adapter, an HTTP server (Node.js) or Bun engine instance, and an authentication function.
|
|
44
44
|
|
|
45
45
|
```typescript
|
|
46
|
-
import { SocketIOServerHelper } from '@venizia/ignis-helpers';
|
|
47
|
-
import {
|
|
46
|
+
import { SocketIOServerHelper } from '@venizia/ignis-helpers/socket-io';
|
|
47
|
+
import { RedisSingleHelper } from '@venizia/ignis-helpers';
|
|
48
48
|
import { createServer } from 'node:http';
|
|
49
49
|
|
|
50
50
|
const httpServer = createServer();
|
|
51
51
|
|
|
52
|
-
const redisHelper = new
|
|
52
|
+
const redisHelper = new RedisSingleHelper({
|
|
53
53
|
name: 'socket-redis',
|
|
54
54
|
host: 'localhost',
|
|
55
55
|
port: 6379,
|
|
56
|
+
password: '',
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
const socketServer = new SocketIOServerHelper({
|
|
@@ -91,8 +92,8 @@ A discriminated union based on the `runtime` field:
|
|
|
91
92
|
| `runtime` | `'node' \| 'bun'` | -- | Runtime environment. Determines which server field is required |
|
|
92
93
|
| `server` | `HTTPServer` | -- | Node.js HTTP server instance. **Required when `runtime` is `'node'`** |
|
|
93
94
|
| `engine` | `any` | -- | `@socket.io/bun-engine` Server instance. **Required when `runtime` is `'bun'`** |
|
|
94
|
-
| `serverOptions` | `Partial<ServerOptions>` |
|
|
95
|
-
| `redisConnection` | `
|
|
95
|
+
| `serverOptions` | `Partial<ServerOptions>` | -- | **Required by the type.** Socket.IO `ServerOptions` (cors, path, transports, etc.). Pass `{}` when no options are needed; nullish values fall back to `{}` at runtime |
|
|
96
|
+
| `redisConnection` | `IRedisHelper` | -- | **Required.** Redis helper used to create pub, sub, and emitter clients |
|
|
96
97
|
| `authenticateFn` | `TSocketIOAuthenticateFn` | -- | **Required.** Called with the client's handshake data. Return `true` to accept, `false` to reject |
|
|
97
98
|
| `validateRoomFn` | `TSocketIOValidateRoomFn` | `undefined` | Called when a client requests to join rooms. Return the allowed subset |
|
|
98
99
|
| `clientConnectedFn` | `TSocketIOClientConnectedFn` | `undefined` | Called after a client is fully authenticated and has joined default rooms |
|
|
@@ -108,7 +109,7 @@ A discriminated union based on the `runtime` field:
|
|
|
108
109
|
`SocketIOClientHelper` connects to a Socket.IO server. Configuration is done entirely via the constructor -- `configure()` is called automatically.
|
|
109
110
|
|
|
110
111
|
```typescript
|
|
111
|
-
import { SocketIOClientHelper } from '@venizia/ignis-helpers';
|
|
112
|
+
import { SocketIOClientHelper } from '@venizia/ignis-helpers/socket-io';
|
|
112
113
|
|
|
113
114
|
const socketClient = new SocketIOClientHelper({
|
|
114
115
|
identifier: 'my-client',
|
|
@@ -191,7 +192,7 @@ httpServer.listen(3000, () => {
|
|
|
191
192
|
For Bun, pass the `@socket.io/bun-engine` instance instead of an HTTP server:
|
|
192
193
|
|
|
193
194
|
```typescript
|
|
194
|
-
import { SocketIOServerHelper } from '@venizia/ignis-helpers';
|
|
195
|
+
import { SocketIOServerHelper } from '@venizia/ignis-helpers/socket-io';
|
|
195
196
|
|
|
196
197
|
const socketServer = new SocketIOServerHelper({
|
|
197
198
|
identifier: 'my-bun-server',
|
|
@@ -425,6 +426,9 @@ The server uses `@socket.io/redis-adapter` and `@socket.io/redis-emitter` for ho
|
|
|
425
426
|
|
|
426
427
|
All three connections are initialized and awaited during `configure()`. If the parent client uses `lazyConnect`, the duplicated clients will connect automatically.
|
|
427
428
|
|
|
429
|
+
> [!NOTE]
|
|
430
|
+
> `configure()` fails fast: if any of the three Redis clients never reaches the `ready` state, it rejects after **30 seconds** rather than hanging boot indefinitely.
|
|
431
|
+
|
|
428
432
|
```typescript
|
|
429
433
|
// Messages sent via send() use the Redis emitter,
|
|
430
434
|
// so they reach clients on ANY server instance
|
|
@@ -481,7 +485,7 @@ client.shutdown();
|
|
|
481
485
|
|
|
482
486
|
**Cause:** The `redisConnection` option is missing, `null`, or `undefined`.
|
|
483
487
|
|
|
484
|
-
**Fix:** Pass a valid `
|
|
488
|
+
**Fix:** Pass a valid `IRedisHelper` instance (e.g., `RedisSingleHelper` or `RedisClusterHelper`).
|
|
485
489
|
|
|
486
490
|
### `[on] Invalid topic to start binding handler`
|
|
487
491
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Architecture
|
|
4
4
|
|
|
5
|
-
The storage system uses a class hierarchy with an abstract base class providing shared logic and
|
|
5
|
+
The storage system uses a class hierarchy with an abstract base class providing shared logic and three concrete implementations for different backends. `MemoryStorageHelper` is a separate, standalone class that does not participate in the `IStorageHelper` hierarchy.
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
BaseHelper
|
|
@@ -83,11 +83,11 @@ Returns the MIME type for a filename based on its extension. Extracts the extens
|
|
|
83
83
|
isValidName(name: string): boolean
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Validates a bucket or file name against security rules. Logs specific error messages for each validation failure.
|
|
86
|
+
Validates a **single path segment** (bucket name or bare file name - no slashes) against security rules. Used internally by `isValidPath` to validate each segment. Logs specific error messages for each validation failure.
|
|
87
87
|
|
|
88
88
|
| Parameter | Type | Description |
|
|
89
89
|
|-----------|------|-------------|
|
|
90
|
-
| `name` | `string` |
|
|
90
|
+
| `name` | `string` | Single-segment name to validate (must not contain `/`). |
|
|
91
91
|
|
|
92
92
|
**Returns:** `true` if the name passes all checks, `false` otherwise.
|
|
93
93
|
|
|
@@ -102,6 +102,30 @@ Validates a bucket or file name against security rules. Logs specific error mess
|
|
|
102
102
|
7. Must not exceed 255 characters (DoS prevention)
|
|
103
103
|
8. Must not be whitespace-only
|
|
104
104
|
|
|
105
|
+
#### isValidPath
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
isValidPath(pathStr: string, opts?: { maxDepth?: number }): boolean
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Validates a **full object path** that may include folder segments (e.g., `2025/uploads/report.pdf`). Splits the path on `/`, validates each segment with `isValidName`, and enforces a maximum folder depth. Used for object name validation where paths with folder structure are allowed.
|
|
112
|
+
|
|
113
|
+
| Parameter | Type | Description |
|
|
114
|
+
|-----------|------|-------------|
|
|
115
|
+
| `pathStr` | `string` | Path string to validate (may contain `/` separators). |
|
|
116
|
+
| `opts.maxDepth` | `number` | Maximum folder depth. Default: `2`. |
|
|
117
|
+
|
|
118
|
+
**Returns:** `true` if the path and all its segments are valid, `false` otherwise.
|
|
119
|
+
|
|
120
|
+
**Validation rules (checked in order):**
|
|
121
|
+
|
|
122
|
+
1. Must be a non-empty string
|
|
123
|
+
2. After stripping leading/trailing slashes, must not be empty
|
|
124
|
+
3. Must not contain empty segments (double slashes, e.g., `a//b`)
|
|
125
|
+
4. Folder depth must not exceed `maxDepth` (depth = number of `/` separators)
|
|
126
|
+
5. Every segment must pass `isValidName()`
|
|
127
|
+
6. Total path length must not exceed 1024 characters
|
|
128
|
+
|
|
105
129
|
#### getFileType
|
|
106
130
|
|
|
107
131
|
```typescript
|
|
@@ -132,6 +156,7 @@ abstract upload(opts: {
|
|
|
132
156
|
files: IUploadFile[];
|
|
133
157
|
normalizeNameFn?: (opts: { originalName: string; folderPath?: string }) => string;
|
|
134
158
|
normalizeLinkFn?: (opts: { bucketName: string; normalizeName: string }) => string;
|
|
159
|
+
maxFolderDepth?: number;
|
|
135
160
|
}): Promise<IUploadResult[]>;
|
|
136
161
|
|
|
137
162
|
abstract getFile(opts: { bucket: string; name: string; options?: any }): Promise<Readable>;
|
|
@@ -228,14 +253,19 @@ async upload(opts: {
|
|
|
228
253
|
files: IUploadFile[];
|
|
229
254
|
normalizeNameFn?: (opts: { originalName: string; folderPath?: string }) => string;
|
|
230
255
|
normalizeLinkFn?: (opts: { bucketName: string; normalizeName: string }) => string;
|
|
256
|
+
maxFolderDepth?: number;
|
|
231
257
|
}): Promise<IUploadResult[]>
|
|
232
258
|
```
|
|
233
259
|
|
|
234
260
|
Uploads files to a MinIO bucket. Returns `[]` if `files` is empty. Validates the bucket exists and all file names/sizes before uploading. Uploads run in parallel via `Promise.all()`.
|
|
235
261
|
|
|
262
|
+
| Parameter | Type | Default | Description |
|
|
263
|
+
|-----------|------|---------|-------------|
|
|
264
|
+
| `opts.maxFolderDepth` | `number` | `BaseStorageHelper.DEFAULT_MAX_FOLDER_DEPTH` (`2`) | Folder nesting the caller allows, for both `folderPath` and the normalized object name. |
|
|
265
|
+
|
|
236
266
|
**Default name normalization:** Lowercased with spaces replaced by `_`. If `folderPath` is set, prepends `{folderPath}/`.
|
|
237
267
|
|
|
238
|
-
**Default link format:** `/static-assets/{bucket}/{encodeURIComponent(
|
|
268
|
+
**Default link format:** `/static-assets/{bucket}/{normalizeName}`, with each `/`-separated segment of `normalizeName` URI-encoded via `encodeURIComponent()`.
|
|
239
269
|
|
|
240
270
|
**Metadata stored:** `originalName`, `normalizeName`, `size`, `encoding`, `mimeType`.
|
|
241
271
|
|
|
@@ -244,6 +274,7 @@ Uploads files to a MinIO bucket. Returns `[]` if `files` is empty. Validates the
|
|
|
244
274
|
- `'[upload] Invalid original file name'`
|
|
245
275
|
- `'[upload] Invalid folder path'`
|
|
246
276
|
- `'[upload] Invalid file size'`
|
|
277
|
+
- `'[upload] Invalid normalized object name | name: {name}'` -- the value returned by a custom `normalizeNameFn` is path-validated before use; a traversal payload is rejected here even if the original name passed validation.
|
|
247
278
|
|
|
248
279
|
#### getFile
|
|
249
280
|
|
|
@@ -401,12 +432,13 @@ async upload(opts: {
|
|
|
401
432
|
files: IUploadFile[];
|
|
402
433
|
normalizeNameFn?: (opts: { originalName: string; folderPath?: string }) => string;
|
|
403
434
|
normalizeLinkFn?: (opts: { bucketName: string; normalizeName: string }) => string;
|
|
435
|
+
maxFolderDepth?: number;
|
|
404
436
|
}): Promise<IUploadResult[]>
|
|
405
437
|
```
|
|
406
438
|
|
|
407
|
-
Uploads files using `client.write(name, buffer, { bucket, type })`. Same validation and normalization behavior as MinioHelper.
|
|
439
|
+
Uploads files using `client.write(name, buffer, { bucket, type })`. Same validation and normalization behavior as MinioHelper, including `maxFolderDepth` and the normalized-name path validation.
|
|
408
440
|
|
|
409
|
-
**Default link format:** `/static-assets/{bucket}/{encodeURIComponent(
|
|
441
|
+
**Default link format:** `/static-assets/{bucket}/{normalizeName}`, with each `/`-separated segment of `normalizeName` URI-encoded via `encodeURIComponent()`.
|
|
410
442
|
|
|
411
443
|
#### getFile
|
|
412
444
|
|
|
@@ -553,6 +585,7 @@ async upload(opts: {
|
|
|
553
585
|
files: IUploadFile[];
|
|
554
586
|
normalizeNameFn?: (opts: { originalName: string; folderPath?: string }) => string;
|
|
555
587
|
normalizeLinkFn?: (opts: { bucketName: string; normalizeName: string }) => string;
|
|
588
|
+
maxFolderDepth?: number;
|
|
556
589
|
}): Promise<IUploadResult[]>
|
|
557
590
|
```
|
|
558
591
|
|
|
@@ -560,13 +593,14 @@ Writes files to the bucket directory. Returns `[]` if `files` is empty. Validate
|
|
|
560
593
|
|
|
561
594
|
**Default name normalization:** Same as MinioHelper -- lowercased with spaces replaced by `_`.
|
|
562
595
|
|
|
563
|
-
**Default link format:** `/static-resources/{bucket}/{encodeURIComponent(
|
|
596
|
+
**Default link format:** `/static-resources/{bucket}/{normalizeName}`, with each `/`-separated segment of `normalizeName` URI-encoded via `encodeURIComponent()`.
|
|
564
597
|
|
|
565
598
|
**Throws:**
|
|
566
599
|
- `'[upload] Bucket does not exist | name: {bucket}'`
|
|
567
600
|
- `'[upload] Invalid original file name'`
|
|
568
601
|
- `'[upload] Invalid folder path'`
|
|
569
602
|
- `'[upload] Invalid file size'`
|
|
603
|
+
- `'[upload] Invalid normalized object name | name: {name}'` -- the value returned by a custom `normalizeNameFn` is path-validated before it is written to disk; an unvalidated `../../../etc/cron.d/pwn` would otherwise write outside `basePath`.
|
|
570
604
|
|
|
571
605
|
#### getFile
|
|
572
606
|
|
|
@@ -727,6 +761,7 @@ The unified interface implemented by `MinioHelper`, `BunS3Helper`, and `DiskHelp
|
|
|
727
761
|
```typescript
|
|
728
762
|
interface IStorageHelper {
|
|
729
763
|
isValidName(name: string): boolean;
|
|
764
|
+
isValidPath(pathStr: string, opts?: { maxDepth?: number }): boolean;
|
|
730
765
|
|
|
731
766
|
isBucketExists(opts: { name: string }): Promise<boolean>;
|
|
732
767
|
getBuckets(): Promise<IBucketInfo[]>;
|
|
@@ -739,6 +774,7 @@ interface IStorageHelper {
|
|
|
739
774
|
files: IUploadFile[];
|
|
740
775
|
normalizeNameFn?: (opts: { originalName: string; folderPath?: string }) => string;
|
|
741
776
|
normalizeLinkFn?: (opts: { bucketName: string; normalizeName: string }) => string;
|
|
777
|
+
maxFolderDepth?: number;
|
|
742
778
|
}): Promise<IUploadResult[]>;
|
|
743
779
|
|
|
744
780
|
getFile(opts: { bucket: string; name: string; options?: any }): Promise<Readable>;
|
|
@@ -793,7 +829,7 @@ interface IFileStat {
|
|
|
793
829
|
size: number; // File size in bytes
|
|
794
830
|
metadata: Record<string, any>; // Storage-specific metadata
|
|
795
831
|
lastModified?: Date; // Last modification date
|
|
796
|
-
etag?: string; // Entity tag (MinioHelper only)
|
|
832
|
+
etag?: string; // Entity tag (MinioHelper and BunS3Helper only)
|
|
797
833
|
versionId?: string; // Version ID (MinioHelper only)
|
|
798
834
|
}
|
|
799
835
|
```
|
|
@@ -209,6 +209,23 @@ const results = await storage.upload({
|
|
|
209
209
|
});
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
+
> [!NOTE]
|
|
213
|
+
> The output of `normalizeNameFn` is validated with `isValidPath()` before it reaches the filesystem or object store - a traversal payload returned from a custom function (e.g. `../../../etc/cron.d/pwn`) is rejected with `'[upload] Invalid normalized object name | name: {name}'`, not trusted just because it came from application code.
|
|
214
|
+
|
|
215
|
+
#### Controlling Folder Depth
|
|
216
|
+
|
|
217
|
+
`upload()` accepts an optional `maxFolderDepth` that overrides `BaseStorageHelper.DEFAULT_MAX_FOLDER_DEPTH` (`2`) for that call. It bounds both the incoming `folderPath` on each file and the folder depth of the resulting normalized object name:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
const results = await storage.upload({
|
|
221
|
+
bucket: 'my-bucket',
|
|
222
|
+
files: files,
|
|
223
|
+
maxFolderDepth: 4, // allow up to 4 folder segments instead of the default 2
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Omit it to keep the default of `2`.
|
|
228
|
+
|
|
212
229
|
#### Upload with Folder Path
|
|
213
230
|
|
|
214
231
|
When `folderPath` is provided in an `IUploadFile`, the default normalization creates subdirectory-based paths:
|
|
@@ -281,7 +298,7 @@ console.log(stat);
|
|
|
281
298
|
// size: 204800,
|
|
282
299
|
// lastModified: 2025-01-15T10:30:00.000Z,
|
|
283
300
|
// metadata: { mimetype: 'application/pdf' },
|
|
284
|
-
// etag: 'abc123', // MinioHelper only
|
|
301
|
+
// etag: 'abc123', // MinioHelper and BunS3Helper only
|
|
285
302
|
// versionId: 'v1', // MinioHelper only (if versioning enabled)
|
|
286
303
|
// }
|
|
287
304
|
```
|
|
@@ -389,7 +406,14 @@ cache.clear();
|
|
|
389
406
|
|
|
390
407
|
### Name Validation
|
|
391
408
|
|
|
392
|
-
|
|
409
|
+
Storage helpers use two validation methods depending on context:
|
|
410
|
+
|
|
411
|
+
- **`isValidName(name)`** - validates a single path segment (bucket names, raw file names). Rejects names that contain `/`, `\`, or `..`.
|
|
412
|
+
- **`isValidPath(pathStr)`** - validates a full object path that may include folder segments (e.g., `folder/file.pdf`). Splits on `/` and validates each segment with `isValidName`. Also enforces a max folder depth (default: 2).
|
|
413
|
+
|
|
414
|
+
Bucket operations (create, remove) validate the bucket name with `isValidName()`. `upload()` validates each file's `originalName` with `isValidName()` and, when provided, the file's `folderPath` with `isValidPath()` so that folder structures like `2025/uploads` are accepted. Read and delete operations (`getFile`, `getStat`, `removeObject`, `listObjects`) do not re-validate names.
|
|
415
|
+
|
|
416
|
+
The following single-segment inputs are rejected by `isValidName()`:
|
|
393
417
|
|
|
394
418
|
| Rule | Example | Reason |
|
|
395
419
|
|------|---------|--------|
|
|
@@ -401,9 +425,15 @@ All bucket and file operations validate names using `isValidName()` before execu
|
|
|
401
425
|
| Empty or whitespace-only | `""`, `" "` | Invalid input |
|
|
402
426
|
|
|
403
427
|
```typescript
|
|
428
|
+
// Single-segment name validation (buckets, raw file names)
|
|
404
429
|
storage.isValidName('my-file.pdf'); // true
|
|
405
|
-
storage.isValidName('../etc/passwd'); // false
|
|
406
|
-
storage.isValidName('.hidden'); // false
|
|
430
|
+
storage.isValidName('../etc/passwd'); // false - contains path separators
|
|
431
|
+
storage.isValidName('.hidden'); // false - starts with dot
|
|
432
|
+
|
|
433
|
+
// Multi-segment path validation (object names with folder structure)
|
|
434
|
+
storage.isValidPath('folder/file.pdf'); // true
|
|
435
|
+
storage.isValidPath('../etc/passwd'); // false - path traversal
|
|
436
|
+
storage.isValidPath('a/b/c/d/file.pdf'); // false - exceeds max depth (2)
|
|
407
437
|
```
|
|
408
438
|
|
|
409
439
|
### MIME Type Detection
|
|
@@ -536,7 +566,7 @@ await storage.removeBucket({ name: 'my-bucket' });
|
|
|
536
566
|
|
|
537
567
|
### "[upload] Bucket does not exist | name: {bucket}"
|
|
538
568
|
|
|
539
|
-
**Cause:** The target bucket does not exist.
|
|
569
|
+
**Cause:** The target bucket does not exist. DiskHelper, MinioHelper, and BunS3Helper all validate bucket existence before uploading.
|
|
540
570
|
|
|
541
571
|
**Fix:** Create the bucket before uploading:
|
|
542
572
|
|
|
@@ -566,7 +596,7 @@ await storage.upload({
|
|
|
566
596
|
|
|
567
597
|
### "[upload] Invalid file size"
|
|
568
598
|
|
|
569
|
-
**Cause:** A file's `size` property is `
|
|
599
|
+
**Cause:** A file's `size` property is `undefined`, `null`, or negative. A zero-byte file is a legal upload - it is not what triggers this error.
|
|
570
600
|
|
|
571
601
|
**Fix:** Ensure every file in the upload array has a valid `size` value:
|
|
572
602
|
|
|
@@ -575,10 +605,16 @@ const file: IUploadFile = {
|
|
|
575
605
|
originalName: 'doc.pdf',
|
|
576
606
|
mimetype: 'application/pdf',
|
|
577
607
|
buffer: fileBuffer,
|
|
578
|
-
size: fileBuffer.length, // Must be
|
|
608
|
+
size: fileBuffer.length, // Must be a number >= 0
|
|
579
609
|
};
|
|
580
610
|
```
|
|
581
611
|
|
|
612
|
+
### "[upload] Invalid normalized object name | name: {name}"
|
|
613
|
+
|
|
614
|
+
**Cause:** A custom `normalizeNameFn` returned a value that fails `isValidPath()` - typically a path-traversal payload (e.g. `../../../etc/cron.d/pwn`) or a name exceeding `maxFolderDepth`.
|
|
615
|
+
|
|
616
|
+
**Fix:** Ensure `normalizeNameFn` returns a plain relative name/path with no `..` segments, no leading `/`, and no more folder segments than `maxFolderDepth` (default `2`) allows.
|
|
617
|
+
|
|
582
618
|
### "[getFile] File not found | bucket: {bucket} | name: {name}"
|
|
583
619
|
|
|
584
620
|
**Cause:** DiskHelper throws when the requested file does not exist on the filesystem.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Helper Documentation Template
|
|
2
2
|
|
|
3
|
-
Guide for writing consistent, professional helper reference docs for
|
|
3
|
+
Guide for writing consistent, professional helper reference docs for IGNIS.
|
|
4
4
|
|
|
5
5
|
## Tiers
|
|
6
6
|
|
|
@@ -21,6 +21,9 @@ Guide for writing consistent, professional helper reference docs for Ignis.
|
|
|
21
21
|
| Socket.IO | 2 | Server + Client helpers, Redis integration |
|
|
22
22
|
| WebSocket | 2 | Largest helper, Server + Emitter, complex internals |
|
|
23
23
|
|
|
24
|
+
> [!NOTE]
|
|
25
|
+
> Kafka uses an extended multi-page structure (`index.md` + `producer.md`, `consumer.md`, `admin.md`, `schema-registry.md`, `examples.md`) that goes beyond the Tier 2 two-page pattern.
|
|
26
|
+
|
|
24
27
|
## Principles
|
|
25
28
|
|
|
26
29
|
- **Usage-first** -- Show working code early, not abstract API tables
|
|
@@ -54,13 +57,13 @@ Use **GitHub-style only**:
|
|
|
54
57
|
|----------|---------|
|
|
55
58
|
| [Single Page](./single-page) | Tier 1 template -- one file per helper |
|
|
56
59
|
|
|
57
|
-
Tier 2
|
|
60
|
+
Tier 2 helpers use two pages (`index.md` + `api.md`) -- see the existing Tier 2 helper docs (Network, Storage, Socket.IO, WebSocket) for the pattern. Note this differs from [Component Tier 2](../../components/template/), which is a four-page set.
|
|
58
61
|
|
|
59
62
|
## Source Paths
|
|
60
63
|
|
|
61
64
|
| Package | Path |
|
|
62
65
|
|---------|------|
|
|
63
|
-
| Helpers | `packages/helpers/src/
|
|
66
|
+
| Helpers | `packages/helpers/src/modules/{name}/` |
|
|
64
67
|
| Inversion | `packages/inversion/src/` |
|
|
65
68
|
| Common types | `packages/helpers/src/common/types.ts` |
|
|
66
69
|
| Utilities | `packages/helpers/src/utilities/` |
|
|
@@ -8,6 +8,7 @@ Shared utility types, resolver functions, and constants exported from `@venizia/
|
|
|
8
8
|
|------|-------|
|
|
9
9
|
| **Package** | `@venizia/ignis-helpers` |
|
|
10
10
|
| **Module** | Common types and constants |
|
|
11
|
+
| **Source** | `packages/helpers/src/common/types.ts` (types + resolvers), `packages/helpers/src/common/constants/` (constants) |
|
|
11
12
|
| **Runtimes** | Both |
|
|
12
13
|
|
|
13
14
|
#### Import Paths
|
|
@@ -195,7 +196,7 @@ Synchronously resolves a lazy value:
|
|
|
195
196
|
- **Class constructors** -- returned as-is (not invoked)
|
|
196
197
|
- **Resolver functions** -- invoked and result returned
|
|
197
198
|
|
|
198
|
-
Class constructors are detected via `
|
|
199
|
+
Class constructors are detected via `isClass()` (a source-level class-syntax check), which lives in `@venizia/ignis-inversion` and is re-exported by `helpers`; they are never called as resolver functions. `isClassConstructor` does not exist.
|
|
199
200
|
|
|
200
201
|
#### resolveValueAsync
|
|
201
202
|
|
|
@@ -369,7 +370,7 @@ Schema data type constants with validation. `SCHEME_SET` contains all valid type
|
|
|
369
370
|
|
|
370
371
|
The `HTTP` class groups all HTTP-related constants into nested objects.
|
|
371
372
|
|
|
372
|
-
**Headers
|
|
373
|
+
**Headers** (commonly used subset -- the full list in `packages/helpers/src/common/constants/http.ts` also covers content negotiation, CORS, security, proxy/forwarding, and rate-limit headers):
|
|
373
374
|
|
|
374
375
|
| Constant | Value |
|
|
375
376
|
|----------|-------|
|
|
@@ -389,7 +390,7 @@ The `HTTP` class groups all HTTP-related constants into nested objects.
|
|
|
389
390
|
| `HTTP.Headers.RESPONSE_COUNT_DATA` | `'x-response-count'` |
|
|
390
391
|
| `HTTP.Headers.RESPONSE_FORMAT` | `'x-response-format'` |
|
|
391
392
|
|
|
392
|
-
**Header Values
|
|
393
|
+
**Header Values** (commonly used subset -- the full list also covers XML, PDF, zip, image, CSS/CSV/HTML, and event-stream types):
|
|
393
394
|
|
|
394
395
|
| Constant | Value |
|
|
395
396
|
|----------|-------|
|
|
@@ -413,11 +414,13 @@ The `HTTP` class groups all HTTP-related constants into nested objects.
|
|
|
413
414
|
|
|
414
415
|
**Result Codes:**
|
|
415
416
|
|
|
417
|
+
Status codes are grouped by class under `HTTP.ResultCodes.RS_1` through `HTTP.ResultCodes.RS_5` (e.g. `HTTP.ResultCodes.RS_4.NotFound`).
|
|
418
|
+
|
|
416
419
|
| Group | Constant | Value |
|
|
417
420
|
|-------|----------|-------|
|
|
418
|
-
|
|
|
419
|
-
| | `
|
|
420
|
-
| | `
|
|
421
|
+
| **RS_1** (1xx) | `Continue` | `100` |
|
|
422
|
+
| | `SwitchingProtocols` | `101` |
|
|
423
|
+
| | `EarlyHints` | `103` |
|
|
421
424
|
| **RS_2** (2xx) | `Ok` | `200` |
|
|
422
425
|
| | `Created` | `201` |
|
|
423
426
|
| | `Accepted` | `202` |
|
|
@@ -470,8 +473,8 @@ The `HTTP` class groups all HTTP-related constants into nested objects.
|
|
|
470
473
|
**Derived Types:**
|
|
471
474
|
|
|
472
475
|
```typescript
|
|
473
|
-
type THttpMethod = ValueOf<typeof HTTP.Methods>;
|
|
474
|
-
type THttpResultCode = ValueOf<typeof HTTP.ResultCodes>; //
|
|
476
|
+
type THttpMethod = ValueOf<typeof HTTP.Methods>; // 'get' | 'post' | 'put' | ...
|
|
477
|
+
type THttpResultCode = ValueOf<typeof HTTP.ResultCodes>; // union of the RS_1..RS_5 group objects
|
|
475
478
|
```
|
|
476
479
|
|
|
477
480
|
#### GRPC
|
|
@@ -17,8 +17,8 @@ The WebSocket helper provides two classes: `WebSocketServerHelper` for managing
|
|
|
17
17
|
| |-- Store callbacks (auth, rooms, messages) |
|
|
18
18
|
| |-- Apply defaults (rooms, timeouts) |
|
|
19
19
|
| +-- initRedisClients(redisConnection) |
|
|
20
|
-
| +-- redisPub =
|
|
21
|
-
| +-- redisSub =
|
|
20
|
+
| +-- redisPub = duplicateClient() |
|
|
21
|
+
| +-- redisSub = duplicateClient() |
|
|
22
22
|
| |
|
|
23
23
|
| configure() [async] |
|
|
24
24
|
| |-- Connect Redis clients (if lazyConnect) |
|
|
@@ -39,7 +39,7 @@ The WebSocket helper provides two classes: `WebSocketServerHelper` for managing
|
|
|
39
39
|
WebSocketEmitter
|
|
40
40
|
+---------------------------------------------------+
|
|
41
41
|
| constructor(opts) |
|
|
42
|
-
| +-- redisPub =
|
|
42
|
+
| +-- redisPub = duplicateClient() |
|
|
43
43
|
| |
|
|
44
44
|
| configure() [async] |
|
|
45
45
|
| +-- await Redis ready |
|
|
@@ -95,14 +95,14 @@ Client connects via WebSocket upgrade
|
|
|
95
95
|
#### Redis 2-Client Architecture
|
|
96
96
|
|
|
97
97
|
```
|
|
98
|
-
|
|
98
|
+
RedisSingleHelper (parent -- NOT consumed)
|
|
99
99
|
|
|
|
100
|
-
+--
|
|
100
|
+
+-- duplicateClient() --> redisPub (publishes cross-instance messages)
|
|
101
101
|
|
|
|
102
|
-
+--
|
|
102
|
+
+-- duplicateClient() --> redisSub (subscribes to cross-instance messages)
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
Both single-instance `Redis` and `Cluster` connections from ioredis are supported. The parent `
|
|
105
|
+
Both single-instance `Redis` and `Cluster` connections from ioredis are supported. The parent `RedisSingleHelper` connection remains independent.
|
|
106
106
|
|
|
107
107
|
## Server API
|
|
108
108
|
|
|
@@ -549,7 +549,7 @@ interface IWebSocketServerOptions<
|
|
|
549
549
|
> {
|
|
550
550
|
identifier: string;
|
|
551
551
|
path?: string; // Default: '/ws'
|
|
552
|
-
redisConnection:
|
|
552
|
+
redisConnection: IRedisHelper;
|
|
553
553
|
server: IBunServer;
|
|
554
554
|
defaultRooms?: string[]; // Default: ['ws-default', 'ws-notification']
|
|
555
555
|
serverOptions?: IBunWebSocketConfig;
|
|
@@ -570,7 +570,7 @@ interface IWebSocketServerOptions<
|
|
|
570
570
|
|
|
571
571
|
interface IWebSocketEmitterOptions {
|
|
572
572
|
identifier?: string; // Default: 'WebSocketEmitter'
|
|
573
|
-
redisConnection:
|
|
573
|
+
redisConnection: IRedisHelper;
|
|
574
574
|
}
|
|
575
575
|
```
|
|
576
576
|
|
|
@@ -58,7 +58,7 @@ const helper = new WebSocketServerHelper({
|
|
|
58
58
|
identifier: 'my-ws-server',
|
|
59
59
|
path: '/ws',
|
|
60
60
|
server: bunServerInstance, // Bun.Server
|
|
61
|
-
redisConnection: myRedisHelper, //
|
|
61
|
+
redisConnection: myRedisHelper, // IRedisHelper
|
|
62
62
|
authenticateFn: async (data) => {
|
|
63
63
|
const { token } = data as { token: string };
|
|
64
64
|
const user = await verifyJWT(token);
|
|
@@ -89,7 +89,7 @@ await helper.configure();
|
|
|
89
89
|
| `identifier` | `string` | Yes | -- | Unique name for this WebSocket server instance |
|
|
90
90
|
| `path` | `string` | No | `'/ws'` | URL path for WebSocket upgrade requests |
|
|
91
91
|
| `server` | `IBunServer` | Yes | -- | Bun server instance (provides `publish()` for native pub/sub) |
|
|
92
|
-
| `redisConnection` | `
|
|
92
|
+
| `redisConnection` | `IRedisHelper` | Yes | -- | Redis helper for cross-instance messaging. Creates 2 duplicate connections internally |
|
|
93
93
|
| `defaultRooms` | `string[]` | No | `['ws-default', 'ws-notification']` | Rooms clients auto-join after authentication |
|
|
94
94
|
| `serverOptions` | `IBunWebSocketConfig` | No | See defaults below | Bun native WebSocket configuration |
|
|
95
95
|
| `authTimeout` | `number` | No | `5000` (5s) | Milliseconds before unauthenticated clients are disconnected (close code `4001`) |
|
|
@@ -155,7 +155,7 @@ await emitter.configure();
|
|
|
155
155
|
| Option | Type | Required | Default | Description |
|
|
156
156
|
|--------|------|----------|---------|-------------|
|
|
157
157
|
| `identifier` | `string` | No | `'WebSocketEmitter'` | Unique name for logging |
|
|
158
|
-
| `redisConnection` | `
|
|
158
|
+
| `redisConnection` | `IRedisHelper` | Yes | -- | Redis helper. Creates 1 duplicate connection internally |
|
|
159
159
|
|
|
160
160
|
## Usage
|
|
161
161
|
|
|
@@ -555,20 +555,20 @@ Authentication succeeds but the client is immediately closed with code `4004`.
|
|
|
555
555
|
|
|
556
556
|
### "[WebSocketServerHelper] Invalid redis connection!"
|
|
557
557
|
|
|
558
|
-
Thrown during construction when `redisConnection` is `null`/`undefined`. Ensure you pass a valid `
|
|
558
|
+
Thrown during construction when `redisConnection` is `null`/`undefined`. Ensure you pass a valid `IRedisHelper` instance (e.g., `RedisSingleHelper`).
|
|
559
559
|
|
|
560
560
|
### "[WebSocketEmitter] Invalid redis connection!"
|
|
561
561
|
|
|
562
|
-
Thrown during `WebSocketEmitter` construction when `redisConnection` is `null`/`undefined`. Ensure you pass a valid `
|
|
562
|
+
Thrown during `WebSocketEmitter` construction when `redisConnection` is `null`/`undefined`. Ensure you pass a valid `IRedisHelper` instance (e.g., `RedisSingleHelper`).
|
|
563
563
|
|
|
564
564
|
### "Redis client did not become ready within 30000ms"
|
|
565
565
|
|
|
566
|
-
Thrown during `configure()` when a Redis client fails to reach `ready` status. Check that the Redis server is reachable and the
|
|
566
|
+
Thrown during `configure()` when a Redis client fails to reach `ready` status. Check that the Redis server is reachable and the `IRedisHelper` instance is properly configured.
|
|
567
567
|
|
|
568
568
|
## See Also
|
|
569
569
|
|
|
570
570
|
- [API Reference](./api) -- Full method signatures, types, and constants
|
|
571
571
|
- [Socket.IO Helper](../socket-io/) -- Socket.IO-based alternative with Node.js support
|
|
572
|
-
- [Redis Helper](../redis/) -- `
|
|
572
|
+
- [Redis Helper](../redis/) -- `RedisSingleHelper` or `RedisClusterHelper` used for cross-instance messaging
|
|
573
573
|
- [Crypto Helper](../crypto/) -- ECDH key exchange for WebSocket encryption
|
|
574
574
|
- [WebSocket Component](/extensions/components/websocket/) -- Component-level lifecycle integration
|
|
@@ -94,7 +94,7 @@ const worker = new BaseWorkerHelper<MyMessageType>({
|
|
|
94
94
|
| `identifier` | `string` | -- | A unique name for this worker instance, used in log output. Required. |
|
|
95
95
|
| `path` | `string \| URL` | -- | Path to the worker script file. Required. |
|
|
96
96
|
| `options` | `WorkerOptions` | -- | Node.js `WorkerOptions` passed directly to `new Worker()`. Required. Supports `workerData`, `transferList`, `env`, etc. |
|
|
97
|
-
| `scope` | `string` | `'BaseWorkerHelper'` |
|
|
97
|
+
| `scope` | `string` | `'BaseWorkerHelper'` | Accepted but currently ignored -- the constructor always sets the logger scope to `'BaseWorkerHelper'`. |
|
|
98
98
|
| `eventHandlers` | `Partial<Pick<IWorker<MessageType>, ...>>` | `undefined` | Optional overrides for lifecycle event callbacks. Any handler not provided falls back to default logging behavior. |
|
|
99
99
|
|
|
100
100
|
#### Event Handler Overrides
|
|
@@ -425,7 +425,7 @@ const bus = thread.getWorkerBus({ key: 'my-bus' });
|
|
|
425
425
|
|
|
426
426
|
### "Failed to post message to main | Invalid parentPort!"
|
|
427
427
|
|
|
428
|
-
**Cause:** `BaseWorkerBusHelper.postMessage()` was called but the `port` property is null or undefined. This typically means the bus was constructed with an invalid `MessagePort`.
|
|
428
|
+
**Cause:** `BaseWorkerBusHelper.postMessage()` was called but the `port` property is null or undefined. This typically means the bus was constructed with an invalid `MessagePort`. Note this is logged at error level, not thrown -- the message is silently dropped.
|
|
429
429
|
|
|
430
430
|
**Fix:** Ensure a valid `MessagePort` (e.g., `parentPort` from `node:worker_threads` or a port from `new MessageChannel()`) is passed to the constructor:
|
|
431
431
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Extensions
|
|
2
2
|
|
|
3
|
-
Extensions are optional packages and built-in modules that add functionality on top of the
|
|
3
|
+
Extensions are optional packages and built-in modules that add functionality on top of the IGNIS core framework. They are organized into two categories:
|
|
4
4
|
|
|
5
5
|
## Components
|
|
6
6
|
|
|
@@ -10,12 +10,12 @@ Components are self-contained feature modules that plug into your application vi
|
|
|
10
10
|
| :--- | :--- | :--- |
|
|
11
11
|
| [Authentication](./components/authentication/) | Identity verification | JWT, Basic, JWKS strategies |
|
|
12
12
|
| [Authorization](./components/authorization/) | Access control | Casbin-based RBAC, per-route policies |
|
|
13
|
-
| [Health Check](./components/health-check) | Liveness
|
|
13
|
+
| [Health Check](./components/health-check) | Liveness check | `GET /health`, `POST /health/ping` |
|
|
14
14
|
| [Mail](./components/mail/) | Email delivery | Nodemailer, Mailgun, queue support |
|
|
15
15
|
| [Request Tracker](./components/request-tracker) | Request tracing | `x-request-id` header, body parsing |
|
|
16
16
|
| [Socket.IO](./components/socket-io/) | Real-time (Socket.IO) | Redis adapter, room-based messaging |
|
|
17
17
|
| [Static Asset](./components/static-asset/) | File management | Upload/download, MinIO, Disk, BunS3 |
|
|
18
|
-
| [Swagger](./components/
|
|
18
|
+
| [Swagger](./components/api-reference) | API docs | OpenAPI UI, Swagger UI, Scalar UI |
|
|
19
19
|
| [WebSocket](./components/websocket/) | Real-time (native) | Bun native WebSocket, encryption |
|
|
20
20
|
|
|
21
21
|
## Helpers
|
|
@@ -36,7 +36,6 @@ Helpers are standalone utility classes for infrastructure concerns. They extend
|
|
|
36
36
|
| [Redis](./helpers/redis/) | Redis client | `ioredis` |
|
|
37
37
|
| [Socket.IO](./helpers/socket-io/) | Socket.IO server | `socket.io` |
|
|
38
38
|
| [Storage](./helpers/storage/) | File storage | `minio` (optional) |
|
|
39
|
-
| [Testing](./helpers/testing/) | Test utilities | Built-in |
|
|
40
39
|
| [Types](./helpers/types/) | Shared types | Built-in |
|
|
41
40
|
| [UID](./helpers/uid/) | Snowflake IDs | Built-in |
|
|
42
41
|
| [WebSocket](./helpers/websocket/) | WebSocket server | Built-in |
|