@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.
Files changed (180) hide show
  1. package/README.md +7 -7
  2. package/content/best-practices/api-usage-examples.md +15 -12
  3. package/content/best-practices/architectural-patterns.md +70 -78
  4. package/content/best-practices/architecture-decisions.md +91 -60
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +56 -44
  6. package/content/best-practices/code-style-standards/constants-configuration.md +11 -11
  7. package/content/best-practices/code-style-standards/control-flow.md +5 -2
  8. package/content/best-practices/code-style-standards/documentation.md +13 -13
  9. package/content/best-practices/code-style-standards/function-patterns.md +9 -10
  10. package/content/best-practices/code-style-standards/index.md +1 -1
  11. package/content/best-practices/code-style-standards/naming-conventions.md +10 -8
  12. package/content/best-practices/code-style-standards/route-definitions.md +30 -12
  13. package/content/best-practices/code-style-standards/tooling.md +8 -5
  14. package/content/best-practices/code-style-standards/type-safety.md +13 -12
  15. package/content/best-practices/common-pitfalls.md +56 -37
  16. package/content/best-practices/contribution-workflow.md +13 -14
  17. package/content/best-practices/data-modeling.md +46 -22
  18. package/content/best-practices/deployment-strategies.md +28 -27
  19. package/content/best-practices/error-handling.md +48 -24
  20. package/content/best-practices/index.md +5 -5
  21. package/content/best-practices/performance-optimization.md +40 -31
  22. package/content/best-practices/security-guidelines.md +52 -23
  23. package/content/best-practices/testing-strategies.md +65 -51
  24. package/content/best-practices/troubleshooting-tips.md +24 -24
  25. package/content/extensions/components/{swagger.md → api-reference.md} +40 -31
  26. package/content/extensions/components/authentication/api.md +19 -19
  27. package/content/extensions/components/authentication/errors.md +7 -7
  28. package/content/extensions/components/authentication/index.md +10 -8
  29. package/content/extensions/components/authentication/usage.md +101 -6
  30. package/content/extensions/components/authorization/api.md +45 -25
  31. package/content/extensions/components/authorization/errors.md +6 -6
  32. package/content/extensions/components/authorization/index.md +11 -10
  33. package/content/extensions/components/authorization/usage.md +21 -21
  34. package/content/extensions/components/health-check.md +1 -1
  35. package/content/extensions/components/index.md +5 -5
  36. package/content/extensions/components/mail/errors.md +15 -15
  37. package/content/extensions/components/mail/index.md +1 -2
  38. package/content/extensions/components/mail/usage.md +1 -1
  39. package/content/extensions/components/request-tracker.md +1 -1
  40. package/content/extensions/components/socket-io/api.md +9 -9
  41. package/content/extensions/components/socket-io/errors.md +5 -5
  42. package/content/extensions/components/socket-io/index.md +8 -8
  43. package/content/extensions/components/socket-io/usage.md +1 -1
  44. package/content/extensions/components/static-asset/api.md +17 -4
  45. package/content/extensions/components/static-asset/errors.md +4 -4
  46. package/content/extensions/components/static-asset/index.md +26 -28
  47. package/content/extensions/components/static-asset/usage.md +13 -12
  48. package/content/extensions/components/template/index.md +2 -2
  49. package/content/extensions/components/template/setup-page.md +1 -1
  50. package/content/extensions/components/websocket/api.md +3 -3
  51. package/content/extensions/components/websocket/errors.md +5 -5
  52. package/content/extensions/components/websocket/index.md +5 -5
  53. package/content/extensions/components/websocket/usage.md +3 -3
  54. package/content/extensions/helpers/cron/index.md +2 -2
  55. package/content/extensions/helpers/crypto/index.md +1 -1
  56. package/content/extensions/helpers/env/index.md +27 -12
  57. package/content/extensions/helpers/error/index.md +81 -25
  58. package/content/extensions/helpers/index.md +2 -3
  59. package/content/extensions/helpers/inversion/index.md +15 -7
  60. package/content/extensions/helpers/kafka/compile-binary.md +92 -0
  61. package/content/extensions/helpers/kafka/examples.md +1 -1
  62. package/content/extensions/helpers/kafka/index.md +3 -0
  63. package/content/extensions/helpers/logger/index.md +32 -2
  64. package/content/extensions/helpers/network/index.md +6 -0
  65. package/content/extensions/helpers/queue/index.md +14 -17
  66. package/content/extensions/helpers/redis/index.md +548 -323
  67. package/content/extensions/helpers/socket-io/index.md +14 -10
  68. package/content/extensions/helpers/storage/api.md +44 -8
  69. package/content/extensions/helpers/storage/index.md +43 -7
  70. package/content/extensions/helpers/template/index.md +6 -3
  71. package/content/extensions/helpers/types/index.md +11 -8
  72. package/content/extensions/helpers/websocket/api.md +9 -9
  73. package/content/extensions/helpers/websocket/index.md +7 -7
  74. package/content/extensions/helpers/worker-thread/index.md +2 -2
  75. package/content/extensions/index.md +3 -4
  76. package/content/extensions/src-details/mcp-server.md +18 -24
  77. package/content/guides/core-concepts/application/bootstrapping.md +11 -14
  78. package/content/guides/core-concepts/application/index.md +3 -3
  79. package/content/guides/core-concepts/components.md +19 -10
  80. package/content/guides/core-concepts/dependency-injection.md +6 -3
  81. package/content/guides/core-concepts/grpc-controllers.md +6 -5
  82. package/content/guides/core-concepts/persistent/datasources.md +42 -43
  83. package/content/guides/core-concepts/persistent/index.md +16 -7
  84. package/content/guides/core-concepts/persistent/models.md +24 -20
  85. package/content/guides/core-concepts/persistent/postgres-drivers.md +201 -0
  86. package/content/guides/core-concepts/persistent/repositories.md +40 -23
  87. package/content/guides/core-concepts/persistent/search-meilisearch.md +185 -0
  88. package/content/guides/core-concepts/persistent/search-typesense.md +431 -0
  89. package/content/guides/core-concepts/persistent/transactions.md +61 -25
  90. package/content/guides/core-concepts/rest-controllers.md +12 -9
  91. package/content/guides/core-concepts/services.md +330 -60
  92. package/content/guides/get-started/5-minute-quickstart.md +15 -15
  93. package/content/guides/get-started/philosophy.md +36 -36
  94. package/content/guides/get-started/setup.md +3 -3
  95. package/content/guides/index.md +3 -3
  96. package/content/guides/migrations/redis-helpers-migration.md +177 -0
  97. package/content/guides/migrations/scoped-rbac-migration.md +17 -17
  98. package/content/guides/migrations/unified-connectors-migration.md +113 -0
  99. package/content/guides/reference/glossary.md +19 -12
  100. package/content/guides/reference/mcp-docs-server.md +22 -18
  101. package/content/guides/tutorials/building-a-crud-api.md +37 -44
  102. package/content/guides/tutorials/complete-installation.md +17 -17
  103. package/content/guides/tutorials/ecommerce-api.md +163 -124
  104. package/content/guides/tutorials/realtime-chat.md +181 -135
  105. package/content/guides/tutorials/testing.md +65 -523
  106. package/content/index.md +2 -180
  107. package/content/public/apple-touch-icon.png +0 -0
  108. package/content/public/og-image.png +0 -0
  109. package/content/public/site.webmanifest +11 -0
  110. package/content/references/base/application.md +4 -5
  111. package/content/references/base/bootstrapping.md +18 -5
  112. package/content/references/base/components.md +149 -120
  113. package/content/references/base/connectors.md +178 -0
  114. package/content/references/base/controllers.md +41 -30
  115. package/content/references/base/datasources.md +163 -92
  116. package/content/references/base/dependency-injection.md +34 -22
  117. package/content/references/base/filter-system/application-usage.md +17 -14
  118. package/content/references/base/filter-system/array-operators.md +7 -2
  119. package/content/references/base/filter-system/comparison-operators.md +3 -0
  120. package/content/references/base/filter-system/default-filter.md +89 -71
  121. package/content/references/base/filter-system/fields-order-pagination.md +22 -22
  122. package/content/references/base/filter-system/index.md +6 -3
  123. package/content/references/base/filter-system/json-filtering.md +20 -1
  124. package/content/references/base/filter-system/list-operators.md +1 -1
  125. package/content/references/base/filter-system/logical-operators.md +33 -1
  126. package/content/references/base/filter-system/null-operators.md +30 -1
  127. package/content/references/base/filter-system/quick-reference.md +23 -4
  128. package/content/references/base/filter-system/tips.md +5 -5
  129. package/content/references/base/filter-system/use-cases.md +12 -12
  130. package/content/references/base/grpc-controllers.md +13 -13
  131. package/content/references/base/index.md +24 -12
  132. package/content/references/base/middlewares.md +265 -327
  133. package/content/references/base/models.md +63 -49
  134. package/content/references/base/providers.md +136 -130
  135. package/content/references/base/repositories/advanced.md +59 -58
  136. package/content/references/base/repositories/index.md +115 -91
  137. package/content/references/base/repositories/mixins.md +55 -291
  138. package/content/references/base/repositories/relations.md +54 -64
  139. package/content/references/base/repositories/soft-deletable.md +31 -30
  140. package/content/references/base/services.md +296 -93
  141. package/content/references/configuration/environment-variables.md +49 -31
  142. package/content/references/configuration/index.md +6 -6
  143. package/content/references/index.md +17 -12
  144. package/content/references/quick-reference.md +65 -106
  145. package/content/references/utilities/crypto.md +65 -23
  146. package/content/references/utilities/index.md +3 -3
  147. package/content/references/utilities/jsx.md +6 -4
  148. package/content/references/utilities/module.md +68 -20
  149. package/content/references/utilities/parse.md +4 -14
  150. package/content/references/utilities/promise.md +9 -7
  151. package/content/references/utilities/schema.md +5 -3
  152. package/dist/mcp-server/common/guards.d.ts +8 -0
  153. package/dist/mcp-server/common/guards.d.ts.map +1 -0
  154. package/dist/mcp-server/common/guards.js +14 -0
  155. package/dist/mcp-server/common/guards.js.map +1 -0
  156. package/dist/mcp-server/common/index.d.ts +1 -0
  157. package/dist/mcp-server/common/index.d.ts.map +1 -1
  158. package/dist/mcp-server/common/index.js +1 -0
  159. package/dist/mcp-server/common/index.js.map +1 -1
  160. package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
  161. package/dist/mcp-server/helpers/docs.helper.js +4 -2
  162. package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
  163. package/dist/mcp-server/helpers/github.helper.js +1 -1
  164. package/dist/mcp-server/index.js +7 -2
  165. package/dist/mcp-server/index.js.map +1 -1
  166. package/dist/mcp-server/tools/base.tool.d.ts +6 -2
  167. package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
  168. package/dist/mcp-server/tools/base.tool.js.map +1 -1
  169. package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  171. package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
  172. package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
  173. package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
  174. package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
  175. package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
  176. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
  177. package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
  178. package/package.json +9 -9
  179. package/content/extensions/helpers/testing/index.md +0 -510
  180. package/content/references/base/middleware.md +0 -347
@@ -11,7 +11,7 @@ Reusable classes and functions providing common functionality - designed for eas
11
11
  | [Crypto](./crypto/) | Cryptographic operations | AES/RSA/ECDH encryption, key exchange, hashing |
12
12
  | [Environment](./env/) | Environment variables | Centralized config access |
13
13
  | [Error](./error/) | Error handling | `ApplicationError`, consistent responses |
14
- | [Inversion](./inversion/) | Dependency injection | DI container implementation |
14
+ | [Inversion](./inversion/) | Dependency injection | IoC container - separate package `@venizia/ignis-inversion` |
15
15
  | [Logger](./logger/) | Logging | Winston-based, multiple transports, scopes |
16
16
  | [Network](./network/) | Network requests | HTTP, TCP, UDP helpers |
17
17
  | [Kafka](./kafka/) | Event streaming | Apache Kafka producer/consumer/admin/schema registry |
@@ -19,8 +19,7 @@ Reusable classes and functions providing common functionality - designed for eas
19
19
  | [Redis](./redis/) | Redis operations | Single/cluster, key-value, hashes, JSON, pub/sub |
20
20
  | [Socket.IO](./socket-io/) | Real-time communication | Socket.IO client/server helpers |
21
21
  | [WebSocket](./websocket/) | Real-time communication | Bun native WebSocket server/emitter, Redis scaling |
22
- | [Storage](./storage/) | File storage | In-memory, Minio object storage |
23
- | [Testing](./testing/) | Test utilities | Test plan runner, base test classes |
22
+ | [Storage](./storage/) | File storage | In-memory, disk, MinIO, Bun S3 object storage |
24
23
  | [UID](./uid/) | Unique ID generation | Snowflake IDs, Base62 encoding |
25
24
  | [Worker Thread](./worker-thread/) | Worker threads | Node.js worker management |
26
25
 
@@ -1,6 +1,6 @@
1
1
  # Inversion (DI)
2
2
 
3
- Standalone IoC container with decorator-based injection, fluent binding API, and singleton/transient scoping -- the foundation layer for all Ignis packages.
3
+ Standalone IoC container with decorator-based injection, fluent binding API, and singleton/transient scoping -- the foundation layer for all IGNIS packages.
4
4
 
5
5
  ## Quick Reference
6
6
 
@@ -50,7 +50,7 @@ import type {
50
50
  ```
51
51
 
52
52
  > [!NOTE]
53
- > The framework package `@venizia/ignis` re-exports DI-specific symbols (`Binding`, `BindingKeys`, `BindingScopes`, `BindingValueTypes`, `IProvider`, `isClass`, `isClassProvider`, `isClassConstructor`, `TBindingScope`, `TBindingValueType`, `IBindingTag`) from `@venizia/ignis-inversion` and adds higher-level helpers (`app.controller()`, `app.service()`, etc.). All types from inversion are also available via type-only re-exports.
53
+ > The framework package `@venizia/ignis` re-exports DI-specific symbols (`Binding`, `BindingKeys`, `BindingScopes`, `BindingValueTypes`, `IProvider`, `isClass`, `isClassProvider`, `TBindingScope`, `TBindingValueType`, `IBindingTag`) from `@venizia/ignis-inversion` and adds higher-level helpers (`app.controller()`, `app.service()`, etc.). All types from inversion are also available via type-only re-exports.
54
54
 
55
55
  ## Creating an Instance
56
56
 
@@ -160,7 +160,7 @@ import { inject, injectable, BindingScopes } from '@venizia/ignis-inversion';
160
160
  class UserService {
161
161
  constructor(
162
162
  @inject({ key: 'repositories.UserRepository' })
163
- private userRepo: UserRepository,
163
+ private userRepository: UserRepository,
164
164
 
165
165
  @inject({ key: 'services.Logger', isOptional: true })
166
166
  private logger?: Logger,
@@ -168,7 +168,10 @@ class UserService {
168
168
  }
169
169
  ```
170
170
 
171
- The container reads `@inject` metadata during `instantiate()`, sorts by parameter index, resolves each dependency, and passes them as constructor arguments.
171
+ The container reads `@inject` metadata during `instantiate()` by constructor index (the `Reflect`-stored array is already index-keyed - no sort is performed), resolves each dependency, and passes them as constructor arguments.
172
+
173
+ > [!IMPORTANT]
174
+ > Every constructor parameter of a container-instantiated class must carry `@inject`. Mixing decorated and undecorated parameters is refused: an undecorated parameter leaves a hole in the index-keyed metadata array, and there is no channel through which the container could supply it anyway. `instantiate()` throws `[ClassName] Constructor parameter N has no @inject | Every parameter of a container-instantiated class must be decorated - the container cannot supply an undecorated one`.
172
175
 
173
176
  ### Property Injection
174
177
 
@@ -178,7 +181,7 @@ import { inject, injectable } from '@venizia/ignis-inversion';
178
181
  @injectable({})
179
182
  class UserService {
180
183
  @inject({ key: 'repositories.UserRepository' })
181
- private userRepo: UserRepository;
184
+ private userRepository: UserRepository;
182
185
 
183
186
  @inject({ key: 'services.Logger', isOptional: true })
184
187
  private logger?: Logger;
@@ -189,7 +192,7 @@ class UserService {
189
192
  > Property-injected classes must be instantiated through the container (`container.resolve()` or `container.instantiate()`). Using `new MyClass()` directly will leave `@inject` properties as `undefined`.
190
193
 
191
194
  The instantiation algorithm is two-phase:
192
- 1. **Constructor injection** -- reads `@inject` metadata on the constructor, sorts by parameter index, resolves from container
195
+ 1. **Constructor injection** -- reads `@inject` metadata on the constructor by parameter index (no sort - the metadata is already index-keyed), resolves from container
193
196
  2. **Property injection** -- reads property metadata, resolves and assigns each dependency to the instance
194
197
 
195
198
  ### Scopes (Singleton / Transient)
@@ -511,7 +514,6 @@ interface IInjectableMetadata {
511
514
  // Type guards
512
515
  function isClass<T>(target: any): target is TClass<T>;
513
516
  function isClassProvider<T>(target: any): target is TClass<IProvider<T>>;
514
- function isClassConstructor(fn: Function): boolean;
515
517
  ```
516
518
 
517
519
  ## Troubleshooting
@@ -555,6 +557,12 @@ function isClassConstructor(fn: Function): boolean;
555
557
 
556
558
  **Fix:** Provide a non-empty `key` string: `BindingKeys.build({ namespace: 'services', key: 'UserService' })`.
557
559
 
560
+ ### "[ClassName] Constructor parameter N has no @inject"
561
+
562
+ **Cause:** A container-instantiated class has a constructor with a mix of decorated and undecorated parameters. `@inject` stores its metadata at the parameter's index, so an undecorated parameter leaves a hole in that index-keyed array; there is no channel through which the container could supply it anyway. `instantiate()` refuses the shape by name and index rather than passing `undefined`.
563
+
564
+ **Fix:** Decorate every constructor parameter of the class with `@inject`. There is no partial-injection escape hatch - if a value does not come from the container (e.g. a plain `scope: string`), pass it through a factory/provider instead of a bare constructor parameter, or have the subclass forward it via its own `@inject`-decorated parameter.
565
+
558
566
  ### "@inject decorator can only be used on class properties or constructor parameters"
559
567
 
560
568
  **Cause:** The `@inject` decorator was applied to something other than a class property or constructor parameter.
@@ -0,0 +1,92 @@
1
+ # Compiling to a Single Binary
2
+
3
+ `bun build --compile` produces a standalone executable that crashes on startup when the application
4
+ imports any Kafka helper, unless the build registers `platformaticWasmPlugin`.
5
+
6
+ ```
7
+ ENOENT: no such file or directory, open '/$bunfs/dist/native.wasm'
8
+ ```
9
+
10
+ The failure happens while the module graph is still loading -- before the IGNIS application boots, so
11
+ no log line, no lifecycle hook, and no error handler of yours ever runs.
12
+
13
+ ## Why it happens
14
+
15
+ `@platformatic/kafka` computes Kafka's CRC32C checksums and lz4/snappy compression in WebAssembly,
16
+ through `@platformatic/wasm-utils`. The default entrypoint of that package reads the wasm payload
17
+ from disk at module load time:
18
+
19
+ ```javascript
20
+ // @platformatic/wasm-utils/dist/index.js
21
+ const wasm = readFileSync(new URL('../dist/native.wasm', import.meta.url));
22
+ ```
23
+
24
+ `bun build --compile` embeds JavaScript modules only -- assets such as `native.wasm` are not carried
25
+ into the executable. Inside the binary, `import.meta.url` resolves against the virtual `/$bunfs`
26
+ filesystem, the file is not there, and the read throws.
27
+
28
+ Running from source (`bun run`, `bun .`) is unaffected: `node_modules` is on disk, so the read
29
+ succeeds. The bug only exists in compiled binaries.
30
+
31
+ ## The fix
32
+
33
+ `@platformatic/wasm-utils` ships a second entrypoint, `@platformatic/wasm-utils/bundled`, exposing
34
+ the same API with the wasm payload inlined as base64 -- no filesystem read. `platformaticWasmPlugin`
35
+ swaps one entrypoint for the other at bundle time.
36
+
37
+ Compile through a Bun build script instead of the `bun build --compile` CLI, which cannot register
38
+ plugins:
39
+
40
+ ```typescript
41
+ // scripts/compile.ts
42
+ import { platformaticWasmPlugin } from '@venizia/ignis-helpers/kafka';
43
+
44
+ const built = await Bun.build({
45
+ entrypoints: ['./dist/index.js'],
46
+ target: 'bun',
47
+ minify: { whitespace: true, syntax: true },
48
+ sourcemap: 'linked',
49
+ compile: {
50
+ target: process.env.BUN_TARGET ?? 'bun-linux-x64',
51
+ outfile: './dist/bin',
52
+ },
53
+ plugins: [platformaticWasmPlugin()],
54
+ });
55
+
56
+ if (!built.success) {
57
+ console.error(built.logs);
58
+ process.exit(1);
59
+ }
60
+ ```
61
+
62
+ ```json
63
+ {
64
+ "scripts": {
65
+ "compile": "bun run ./scripts/compile.ts"
66
+ }
67
+ }
68
+ ```
69
+
70
+ The plugin resolves `@platformatic/wasm-utils/bundled` from the importing module's own directory, so
71
+ it works with hoisted and isolated `node_modules` layouts alike, and pins no package version.
72
+
73
+ ## Verifying
74
+
75
+ A correctly built binary contains no reference to the wasm file on disk:
76
+
77
+ ```bash
78
+ grep -c 'native.wasm' ./dist/bin # 0 -- the payload is inlined
79
+ ./dist/bin # boots instead of throwing ENOENT
80
+ ```
81
+
82
+ The binary grows by roughly 76 KB, the base64 form of the 57 KB wasm module.
83
+
84
+ ## Notes
85
+
86
+ - Upgrading `@platformatic/kafka` does not remove the need for the plugin: every release to date,
87
+ including 2.6.1, imports the default `@platformatic/wasm-utils` entrypoint.
88
+ - Applications that never import a Kafka helper need no plugin -- nothing pulls in
89
+ `@platformatic/wasm-utils`, and the plugin's resolver never fires.
90
+ - Patching `node_modules` during the build achieves the same result, but mutates a dependency in
91
+ place, pins the store path to one version, and leaves the tree dirty when a build fails. The
92
+ plugin needs neither.
@@ -251,7 +251,7 @@ const consumer = KafkaConsumerHelper.newInstance({
251
251
  await consumer.start({ topics: ['orders'] });
252
252
  ```
253
253
 
254
- ## Using Helpers with Ignis IoC
254
+ ## Using Helpers with IGNIS IoC
255
255
 
256
256
  ```typescript
257
257
  import {
@@ -88,6 +88,9 @@ import type {
88
88
  > [!NOTE]
89
89
  > Kafka helpers are **not** re-exported from the main `@venizia/ignis-helpers` entry point. You must use the `@venizia/ignis-helpers/kafka` subpath import. This keeps the optional `@platformatic/kafka` peer dependency isolated for tree-shaking.
90
90
 
91
+ > [!WARNING]
92
+ > Compiling an application that uses these helpers with `bun build --compile` produces a binary that dies on startup with `ENOENT: /$bunfs/dist/native.wasm`. The build must register `platformaticWasmPlugin` from `@venizia/ignis-helpers/kafka` -- see [Compiling to a Single Binary](./compile-binary.md).
93
+
91
94
  ### Installation
92
95
 
93
96
  ```bash
@@ -189,6 +189,34 @@ class UserService {
189
189
  }
190
190
  ```
191
191
 
192
+ ### Logging Errors: `%s`, Never `%j`
193
+
194
+ `message` and `stack` are non-enumerable properties on a native `Error`. `%j` formats via `JSON.stringify`, which only visits enumerable own properties, so `logger.error('Failed: %j', error)` silently drops both `message` and `stack` -- the two fields the log line exists to capture. Always pair an `Error` argument with `%s`; reserve `%j`/`%o` for plain data objects.
195
+
196
+ ```typescript
197
+ // ✅ Good - %s prints message + stack
198
+ logger.error('Failed to create user: %s', error);
199
+
200
+ // ❌ Bad - %j drops message and stack (non-enumerable on Error)
201
+ logger.error('Failed to create user: %j', error);
202
+ ```
203
+
204
+ ### Object Inspection Depth for `%s`
205
+
206
+ Node hard-codes `depth: 0` for `%s` in `util.format` -- an object passed to `%s` collapses to `[Object]`, hiding the nested `extra` or `cause` a wrapped error carries. IGNIS's formatter (`formatLogMessage`/`deepSplat`) pre-inspects any object bound to a `%s` placeholder before handing the message to Winston, widening that depth so nested fields print instead of collapsing.
207
+
208
+ ```typescript
209
+ logger.error('Failed: %s', error); // nested `error.cause` is now visible, not `[Object]`
210
+ ```
211
+
212
+ The inspection depth defaults to `5` and is configurable via `APP_ENV_LOGGER_INSPECT_DEPTH`:
213
+
214
+ ```bash
215
+ APP_ENV_LOGGER_INSPECT_DEPTH=8
216
+ ```
217
+
218
+ The value must be a non-negative integer. An absent, empty, negative, or unparseable value falls back to the default of `5` -- there is no "unlimited" setting.
219
+
192
220
  ### Log Formats
193
221
 
194
222
  The logger supports two output formats, controlled by the `APP_ENV_LOGGER_FORMAT` environment variable (default: `text`).
@@ -396,7 +424,7 @@ Debug logs require **both** conditions to be met:
396
424
  1. `DEBUG=true` environment variable is set (parsed via `toBoolean`)
397
425
  2. `NODE_ENV` is either unset **or** is present in the `Environment.COMMON_ENVS` set
398
426
 
399
- The `COMMON_ENVS` set includes: `local`, `debug`, `development`, `alpha`, `beta`, `staging`, `production`. You can extend this set with `APP_ENV_EXTRA_LOG_ENVS`:
427
+ The `COMMON_ENVS` set includes: `local`, `debug`, `development`, `dev`, `sit`, `uat`, `alpha`, `beta`, `staging`, `production`. You can extend this set with `APP_ENV_EXTRA_LOG_ENVS`:
400
428
 
401
429
  ```bash
402
430
  DEBUG=true
@@ -473,6 +501,7 @@ The buffer wraps around at 65,536 entries using bitwise AND masking (`writeIndex
473
501
  | `APP_ENV_EXTRA_LOG_ENVS` | _(empty)_ | Comma-separated additional environments to allow debug |
474
502
  | `APP_ENV_LOGGER_FORMAT` | `text` | Output format (`json` or `text`) |
475
503
  | `APP_ENV_LOGGER_FOLDER_PATH` | `./` | Log files directory |
504
+ | `APP_ENV_LOGGER_INSPECT_DEPTH` | `5` | Object inspection depth for `%s` placeholders. Non-negative integer only; invalid or absent falls back to `5` |
476
505
 
477
506
  #### File Rotation
478
507
 
@@ -502,6 +531,7 @@ APP_ENV_APPLICATION_NAME=my-service
502
531
  DEBUG=true
503
532
  APP_ENV_LOGGER_FORMAT=json
504
533
  APP_ENV_LOGGER_FOLDER_PATH=./app_data/logs
534
+ APP_ENV_LOGGER_INSPECT_DEPTH=5
505
535
 
506
536
  # File rotation
507
537
  APP_ENV_LOGGER_FILE_FREQUENCY=24h
@@ -547,7 +577,7 @@ APP_ENV_LOGGER_DGRAM_LEVELS=error,warn,info
547
577
 
548
578
  **Fix:**
549
579
  1. Verify `DEBUG=true` is set in your environment.
550
- 2. Verify `NODE_ENV` is set to one of: `local`, `debug`, `development`, `alpha`, `beta`, `staging`, `production` -- or is unset entirely.
580
+ 2. Verify `NODE_ENV` is set to one of: `local`, `debug`, `development`, `dev`, `sit`, `uat`, `alpha`, `beta`, `staging`, `production` -- or is unset entirely.
551
581
  3. If you use a custom environment name (e.g. `qa`), add it to `APP_ENV_EXTRA_LOG_ENVS=qa`.
552
582
 
553
583
  ```bash
@@ -332,6 +332,12 @@ class PaymentGateway extends AxiosNetworkRequest {
332
332
  }
333
333
  ```
334
334
 
335
+ #### Request Logging & Redaction
336
+
337
+ Both `NodeFetcher` and `AxiosFetcher` log every outbound request at `info` level (`URL: %s | Props: %s | ...`), including the request config -- headers, body, and any other options passed to `send()`. Before that log line is written, the request config is run through `redactSecrets()`, so values under secret-looking keys never reach the log.
338
+
339
+ Redaction matches by key name, case-insensitively, at any depth -- both options-object spellings (`apiKey`, `token`, `password`, `authorization`, ...) and HTTP header spellings (`x-api-key`, `x-csrf-token`, `cookie`, `set-cookie`, `proxy-authorization`, `www-authenticate`, ...). A header like `'X-API-Key': process.env.PAYMENT_API_KEY` or `'Authorization': 'Bearer my-token'` (as in the examples above) is logged as `'[REDACTED]'`, not the real value. This redaction happens automatically -- there is nothing to configure.
340
+
335
341
  #### Convenience Methods
336
342
 
337
343
  ```typescript
@@ -75,7 +75,7 @@ All queue helpers extend `BaseHelper` (Kafka helpers via `BaseKafkaHelper`), pro
75
75
  The `BullMQHelper` wraps the BullMQ library for Redis-backed job queuing. It operates in one of two roles: `'queue'` (producer) or `'worker'` (consumer). The role is set at construction time and determines which BullMQ primitives are initialized.
76
76
 
77
77
  ```typescript
78
- import { DefaultRedisHelper } from '@venizia/ignis-helpers';
78
+ import { RedisSingleHelper } from '@venizia/ignis-helpers';
79
79
  import { BullMQHelper } from '@venizia/ignis-helpers/bullmq';
80
80
 
81
81
  const worker = new BullMQHelper({
@@ -107,7 +107,7 @@ const worker = new BullMQHelper({
107
107
  | `queueName` | `string` | -- | Name of the BullMQ queue. Must be non-empty. |
108
108
  | `identifier` | `string` | -- | Unique identifier used for scoped logging. |
109
109
  | `role` | `TBullQueueRole` | -- | `'queue'` (producer) or `'worker'` (consumer). |
110
- | `redisConnection` | `DefaultRedisHelper` | -- | Redis helper instance. The helper calls `getClient().duplicate()` internally. |
110
+ | `redisConnection` | `IRedisHelper` | -- | Redis helper instance. The helper calls `duplicateClient()` internally. |
111
111
  | `numberOfWorker` | `number` | `1` | Worker concurrency (number of jobs processed in parallel). |
112
112
  | `lockDuration` | `number` | `5400000` | Job lock duration in milliseconds (default: 90 minutes). |
113
113
  | `onWorkerData` | `(job: Job<TQueueElement, TQueueResult>) => Promise<any>` | `undefined` | Job processing callback. If omitted, the worker logs job details. |
@@ -115,7 +115,7 @@ const worker = new BullMQHelper({
115
115
  | `onWorkerDataFail` | `(job: Job<TQueueElement, TQueueResult> \| undefined, error: Error) => Promise<void>` | `undefined` | Callback fired when a job fails. |
116
116
 
117
117
  > [!IMPORTANT]
118
- > Pass the `DefaultRedisHelper` instance to `redisConnection`, **not** the raw ioredis client. The helper internally calls `redisConnection.getClient().duplicate()` to create dedicated connections for the queue and worker.
118
+ > Pass an `IRedisHelper` instance to `redisConnection`, **not** the raw ioredis client. The helper internally calls `redisConnection.duplicateClient()` to create dedicated connections for the queue and worker.
119
119
 
120
120
  ### MQTTClientHelper
121
121
 
@@ -162,6 +162,9 @@ const mqttClient = new MQTTClientHelper({
162
162
  | `onError` | `(error: Error) => void` | `undefined` | Callback fired on client errors. |
163
163
  | `onClose` | `(error?: Error) => void` | `undefined` | Callback fired when the connection is closed. |
164
164
 
165
+ > [!NOTE]
166
+ > At connect time, `MQTTClientHelper` logs the broker `url` through `redactUrlCredentials()` and the `options` object through `redactSecrets()`. If `url` embeds a password (e.g. `mqtts://user:hunter2@broker:8883`), the password never reaches the log -- only `mqtts://user:[REDACTED]@broker:8883` does.
167
+
165
168
  ### QueueHelper
166
169
 
167
170
  The `QueueHelper` is a generator-based, in-memory queue with a built-in state machine. It processes enqueued items one at a time, making it suitable for sequential task processing within a single process.
@@ -442,34 +445,28 @@ If `onWorkerData` is not provided, the worker logs the job's `id`, `name`, and `
442
445
 
443
446
  ### BullMQ -- Redis Cluster
444
447
 
445
- When using Redis Cluster with BullMQ, you must set `maxRetriesPerRequest: null` on the cluster config -- this is **required** by BullMQ.
448
+ When using Redis Cluster with BullMQ, use `RedisClusterHelper`. Set `maxRetriesPerRequest: null` inside `clusterOptions.redisOptions` -- this is **required** by BullMQ.
446
449
 
447
450
  ```typescript
448
- import { Cluster } from 'ioredis';
449
- import { DefaultRedisHelper } from '@venizia/ignis-helpers';
451
+ import { RedisClusterHelper } from '@venizia/ignis-helpers';
450
452
  import { BullMQHelper } from '@venizia/ignis-helpers/bullmq';
451
453
 
452
- const cluster = new Cluster(
453
- [
454
+ const redisHelper = new RedisClusterHelper({
455
+ name: 'cluster-redis',
456
+ nodes: [
454
457
  { host: 'node1.redis.example.com', port: 6379 },
455
458
  { host: 'node2.redis.example.com', port: 6379 },
456
459
  { host: 'node3.redis.example.com', port: 6379 },
457
460
  ],
458
- {
459
- maxRetriesPerRequest: null, // Required by BullMQ
461
+ clusterOptions: {
460
462
  enableReadyCheck: true,
461
463
  scaleReads: 'slave',
462
464
  redisOptions: {
463
465
  password: 'your-password',
464
466
  tls: {},
467
+ maxRetriesPerRequest: null, // Required by BullMQ
465
468
  },
466
- }
467
- );
468
-
469
- const redisHelper = new DefaultRedisHelper({
470
- scope: 'BullMQ',
471
- identifier: 'cluster-redis',
472
- client: cluster,
469
+ },
473
470
  });
474
471
 
475
472
  const worker = BullMQHelper.newInstance({