@venizia/ignis-docs 0.1.0 → 0.2.1-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +14 -14
  2. package/content/best-practices/api-usage-examples.md +39 -19
  3. package/content/best-practices/architectural-patterns.md +22 -11
  4. package/content/best-practices/architecture-decisions.md +29 -16
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
  6. package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
  7. package/content/best-practices/code-style-standards/control-flow.md +33 -1
  8. package/content/best-practices/code-style-standards/documentation.md +28 -8
  9. package/content/best-practices/code-style-standards/function-patterns.md +15 -4
  10. package/content/best-practices/code-style-standards/index.md +7 -2
  11. package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
  12. package/content/best-practices/code-style-standards/route-definitions.md +9 -5
  13. package/content/best-practices/code-style-standards/tooling.md +14 -1
  14. package/content/best-practices/code-style-standards/type-safety.md +39 -6
  15. package/content/best-practices/common-pitfalls.md +59 -35
  16. package/content/best-practices/contribution-workflow.md +6 -2
  17. package/content/best-practices/data-modeling.md +83 -67
  18. package/content/best-practices/deployment-strategies.md +56 -19
  19. package/content/best-practices/error-handling.md +182 -93
  20. package/content/best-practices/index.md +6 -0
  21. package/content/best-practices/performance-optimization.md +31 -17
  22. package/content/best-practices/security-guidelines.md +35 -9
  23. package/content/best-practices/testing-strategies.md +7 -2
  24. package/content/best-practices/troubleshooting-tips.md +27 -17
  25. package/content/extensions/components/api-reference.md +107 -322
  26. package/content/extensions/components/authentication/api.md +454 -603
  27. package/content/extensions/components/authentication/errors.md +121 -498
  28. package/content/extensions/components/authentication/index.md +88 -801
  29. package/content/extensions/components/authentication/usage.md +207 -956
  30. package/content/extensions/components/authorization/api.md +736 -656
  31. package/content/extensions/components/authorization/errors.md +168 -206
  32. package/content/extensions/components/authorization/index.md +82 -797
  33. package/content/extensions/components/authorization/usage.md +194 -527
  34. package/content/extensions/components/health-check.md +71 -243
  35. package/content/extensions/components/mail/api.md +504 -287
  36. package/content/extensions/components/mail/errors.md +73 -61
  37. package/content/extensions/components/mail/index.md +96 -467
  38. package/content/extensions/components/mail/usage.md +130 -172
  39. package/content/extensions/components/request-tracker.md +66 -173
  40. package/content/extensions/components/socket-io/api.md +195 -13
  41. package/content/extensions/components/socket-io/errors.md +3 -3
  42. package/content/extensions/components/socket-io/index.md +50 -337
  43. package/content/extensions/components/socket-io/usage.md +143 -26
  44. package/content/extensions/components/static-asset/api.md +410 -142
  45. package/content/extensions/components/static-asset/errors.md +110 -53
  46. package/content/extensions/components/static-asset/index.md +79 -608
  47. package/content/extensions/components/static-asset/usage.md +180 -300
  48. package/content/extensions/components/websocket/api.md +275 -399
  49. package/content/extensions/components/websocket/errors.md +47 -56
  50. package/content/extensions/components/websocket/index.md +74 -407
  51. package/content/extensions/components/websocket/usage.md +110 -341
  52. package/content/extensions/helpers/cron/index.md +51 -160
  53. package/content/extensions/helpers/crypto/index.md +62 -483
  54. package/content/extensions/helpers/crypto/reference.md +456 -0
  55. package/content/extensions/helpers/env/index.md +60 -178
  56. package/content/extensions/helpers/error/index.md +221 -207
  57. package/content/extensions/helpers/inversion/index.md +65 -556
  58. package/content/extensions/helpers/inversion/reference.md +522 -0
  59. package/content/extensions/helpers/kafka/admin.md +20 -1
  60. package/content/extensions/helpers/kafka/compile-binary.md +98 -0
  61. package/content/extensions/helpers/kafka/consumer.md +54 -20
  62. package/content/extensions/helpers/kafka/examples.md +21 -16
  63. package/content/extensions/helpers/kafka/index.md +80 -607
  64. package/content/extensions/helpers/kafka/producer.md +134 -5
  65. package/content/extensions/helpers/kafka/schema-registry.md +45 -70
  66. package/content/extensions/helpers/logger/hf-logger.md +193 -0
  67. package/content/extensions/helpers/logger/index.md +64 -563
  68. package/content/extensions/helpers/logger/pino.md +85 -0
  69. package/content/extensions/helpers/logger/reference.md +746 -0
  70. package/content/extensions/helpers/network/api.md +241 -195
  71. package/content/extensions/helpers/network/index.md +72 -530
  72. package/content/extensions/helpers/queue/index.md +72 -900
  73. package/content/extensions/helpers/queue/reference.md +467 -0
  74. package/content/extensions/helpers/redis/index.md +73 -645
  75. package/content/extensions/helpers/redis/reference.md +727 -0
  76. package/content/extensions/helpers/secrets/index.md +66 -0
  77. package/content/extensions/helpers/socket-io/api.md +305 -203
  78. package/content/extensions/helpers/socket-io/index.md +66 -432
  79. package/content/extensions/helpers/storage/api.md +564 -462
  80. package/content/extensions/helpers/storage/index.md +77 -573
  81. package/content/extensions/helpers/types/index.md +66 -499
  82. package/content/extensions/helpers/types/reference.md +650 -0
  83. package/content/extensions/helpers/uid/index.md +58 -227
  84. package/content/extensions/helpers/websocket/api.md +329 -216
  85. package/content/extensions/helpers/websocket/index.md +65 -503
  86. package/content/extensions/helpers/worker-thread/index.md +58 -396
  87. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  88. package/content/guides/core-concepts/persistent/datasources.md +13 -20
  89. package/content/guides/core-concepts/persistent/index.md +2 -4
  90. package/content/guides/core-concepts/persistent/models.md +1 -1
  91. package/content/guides/core-concepts/persistent/postgres-drivers.md +59 -25
  92. package/content/guides/core-concepts/persistent/search-meilisearch.md +3 -1
  93. package/content/guides/core-concepts/persistent/search-typesense.md +7 -5
  94. package/content/guides/core-concepts/persistent/transactions.md +1 -1
  95. package/content/guides/core-concepts/secrets-vault.md +177 -0
  96. package/content/guides/core-concepts/services.md +1 -1
  97. package/content/guides/migrations/redis-helpers-migration.md +1 -1
  98. package/content/guides/migrations/unified-connectors-migration.md +2 -2
  99. package/content/guides/tutorials/building-a-crud-api.md +9 -13
  100. package/content/guides/tutorials/ecommerce-api.md +10 -15
  101. package/content/guides/tutorials/realtime-chat.md +7 -7
  102. package/content/references/base/application.md +1 -1
  103. package/content/references/base/connectors.md +79 -136
  104. package/content/references/base/datasources-reference.md +599 -0
  105. package/content/references/base/datasources.md +85 -447
  106. package/content/references/base/dependency-injection.md +17 -39
  107. package/content/references/base/filter-system/application-usage.md +69 -121
  108. package/content/references/base/filter-system/array-operators.md +12 -0
  109. package/content/references/base/filter-system/comparison-operators.md +12 -0
  110. package/content/references/base/filter-system/default-filter.md +136 -348
  111. package/content/references/base/filter-system/fields-order-pagination.md +38 -16
  112. package/content/references/base/filter-system/index.md +106 -257
  113. package/content/references/base/filter-system/json-filtering.md +12 -2
  114. package/content/references/base/filter-system/list-operators.md +16 -2
  115. package/content/references/base/filter-system/logical-operators.md +13 -0
  116. package/content/references/base/filter-system/null-operators.md +13 -0
  117. package/content/references/base/filter-system/pattern-matching.md +12 -0
  118. package/content/references/base/filter-system/quick-reference.md +11 -2
  119. package/content/references/base/filter-system/range-operators.md +12 -0
  120. package/content/references/base/filter-system/tips.md +70 -133
  121. package/content/references/base/filter-system/use-cases.md +156 -233
  122. package/content/references/base/middlewares.md +35 -21
  123. package/content/references/base/models-reference.md +886 -0
  124. package/content/references/base/models.md +80 -1452
  125. package/content/references/base/repositories/advanced.md +156 -192
  126. package/content/references/base/repositories/index.md +77 -650
  127. package/content/references/base/repositories/mixins.md +22 -18
  128. package/content/references/base/repositories/relations.md +123 -171
  129. package/content/references/base/repositories/soft-deletable.md +58 -56
  130. package/content/references/base/secrets.md +263 -0
  131. package/content/references/base/services.md +2 -2
  132. package/content/references/configuration/environment-variables.md +51 -5
  133. package/content/references/configuration/index.md +49 -31
  134. package/content/references/quick-reference.md +3 -16
  135. package/content/references/utilities/crypto.md +35 -76
  136. package/content/references/utilities/date.md +33 -73
  137. package/content/references/utilities/index.md +1 -1
  138. package/content/references/utilities/jsx-reference.md +298 -0
  139. package/content/references/utilities/jsx.md +82 -525
  140. package/content/references/utilities/module.md +29 -62
  141. package/content/references/utilities/parse.md +34 -64
  142. package/content/references/utilities/performance.md +33 -58
  143. package/content/references/utilities/promise.md +28 -62
  144. package/content/references/utilities/request.md +57 -218
  145. package/content/references/utilities/schema.md +43 -137
  146. package/content/references/utilities/statuses-reference.md +361 -0
  147. package/content/references/utilities/statuses.md +63 -667
  148. package/package.json +8 -8
@@ -0,0 +1,428 @@
1
+ ---
2
+ title: Worker Thread - Full Reference
3
+ description: Complete reference for WorkerPoolHelper, BaseWorkerHelper, BaseWorkerThreadHelper, BaseWorkerBusHelper, and every constructor option and error message
4
+ difficulty: intermediate
5
+ ---
6
+
7
+ # Worker Thread - Full Reference
8
+
9
+ Exhaustive reference for the worker-thread classes, every constructor option, event-handler default, and troubleshooting case. For a readable introduction and the common tasks, start with the [Worker Thread overview](/extensions/helpers/worker-thread/).
10
+
11
+ **Files:**
12
+
13
+ - [`packages/helpers/src/modules/worker-thread/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/base.ts) - `AbstractWorkerHelper`, `BaseWorkerHelper`, `AbstractWorkerThreadHelper`, `BaseWorkerThreadHelper`
14
+ - [`packages/helpers/src/modules/worker-thread/worker-bus.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/worker-bus.ts) - `AbstractWorkerBusHelper`, `BaseWorkerBusHelper`, `AbstractWorkerMessageBusHandlerHelper`, `BaseWorkerMessageBusHandlerHelper`
15
+ - [`packages/helpers/src/modules/worker-thread/worker-pool.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/worker-pool.ts) - `WorkerPoolHelper`
16
+ - [`packages/helpers/src/modules/worker-thread/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/types.ts) - `IWorker`, `IWorkerThread`, `IWorkerBus`, `IWorkerMessageBusHandler`
17
+ - [`packages/helpers/src/modules/worker-thread/index.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/index.ts) - barrel
18
+
19
+ ## Quick Reference
20
+
21
+ | Class | Extends | Use Case |
22
+ |-------|---------|----------|
23
+ | `WorkerPoolHelper` | `BaseHelper` | Singleton registry that tracks and limits active worker instances |
24
+ | `BaseWorkerHelper<MessageType>` | `AbstractWorkerHelper<MessageType>` | Wraps a `Worker` with event lifecycle hooks (online, exit, error, message) |
25
+ | `BaseWorkerThreadHelper` | `AbstractWorkerThreadHelper` | Runs inside a worker thread; manages named `WorkerBus` channels |
26
+ | `BaseWorkerBusHelper<IC, IP>` | `AbstractWorkerBusHelper<IC, IP>` | Bidirectional `MessagePort` communication with pre/post hooks |
27
+ | `BaseWorkerMessageBusHandlerHelper<IC>` | `AbstractWorkerMessageBusHandlerHelper<IC>` | Defines event handlers for a worker bus (message, close, error, exit) |
28
+
29
+ | Item | Value |
30
+ |------|-------|
31
+ | **Package** | `@venizia/ignis-helpers` |
32
+ | **Peer Dependency** | None (uses built-in `node:worker_threads`) |
33
+ | **Runtimes** | Node.js (uses `node:worker_threads` and `node:os`) |
34
+
35
+ ### Import paths
36
+
37
+ ```typescript
38
+ import {
39
+ WorkerPoolHelper,
40
+ BaseWorkerHelper,
41
+ BaseWorkerThreadHelper,
42
+ BaseWorkerBusHelper,
43
+ BaseWorkerMessageBusHandlerHelper,
44
+ AbstractWorkerHelper,
45
+ AbstractWorkerThreadHelper,
46
+ AbstractWorkerBusHelper,
47
+ AbstractWorkerMessageBusHandlerHelper,
48
+ } from '@venizia/ignis-helpers';
49
+
50
+ import type {
51
+ IWorker,
52
+ IWorkerThread,
53
+ IWorkerBus,
54
+ IWorkerMessageBusHandler,
55
+ } from '@venizia/ignis-helpers';
56
+ ```
57
+
58
+ ## WorkerPoolHelper
59
+
60
+ `Source ->` [`worker-pool.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/worker-pool.ts)
61
+
62
+ Singleton registry for active workers. Limits the pool size to the number of CPU cores by default.
63
+
64
+ ```typescript
65
+ import { WorkerPoolHelper } from '@venizia/ignis-helpers';
66
+
67
+ // Get the singleton instance
68
+ const pool = WorkerPoolHelper.getInstance();
69
+
70
+ // Or construct a custom instance directly
71
+ const customPool = new WorkerPoolHelper({ ignoreMaxWarning: true });
72
+ ```
73
+
74
+ > [!NOTE]
75
+ > `WorkerPoolHelper.getInstance()` always creates the singleton with `ignoreMaxWarning: false`. To override this behavior, construct a new instance manually - the singleton and a manually-constructed instance are independent registries.
76
+
77
+ ### Constructor options
78
+
79
+ | Option | Type | Default | Description |
80
+ |--------|------|---------|-------------|
81
+ | `ignoreMaxWarning` | `boolean` | `false` | When `true`, allows registering workers beyond the CPU core count. When `false`, registration is skipped once the pool reaches the CPU core limit. |
82
+
83
+ ### Methods
84
+
85
+ | Method | Signature | Description |
86
+ |--------|-----------|-------------|
87
+ | `getInstance` | `static getInstance(): WorkerPoolHelper` | Returns the singleton pool instance (creates one with `ignoreMaxWarning: false` if needed) |
88
+ | `register` | `register<MessageType>(opts: { key: string; worker: IWorker<MessageType> }): boolean` | Adds a worker to the pool. Returns `false` and logs instead of registering if the key already exists or the pool is at the CPU limit |
89
+ | `unregister` | `async unregister(opts: { key: string }): Promise<void>` | Terminates the worker (`worker.terminate()`) and removes it from the pool. The registry entry is deleted even if termination throws |
90
+ | `get` | `get<MessageType>(opts: { key: string }): IWorker<MessageType> \| undefined` | Retrieves a registered worker by key |
91
+ | `has` | `has(opts: { key: string }): boolean` | Checks if a worker is registered under the given key |
92
+ | `size` | `size(): number` | Returns the number of currently registered workers |
93
+
94
+ > [!WARNING]
95
+ > When the pool reaches the CPU core limit and `ignoreMaxWarning` is `false`, further `register()` calls return `false` and log a warning. No error is thrown.
96
+
97
+ ## BaseWorkerHelper (main thread worker wrapper)
98
+
99
+ `Source ->` [`base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/base.ts)
100
+
101
+ Creates a `Worker` from a file path and automatically binds all lifecycle events.
102
+
103
+ ```typescript
104
+ import { BaseWorkerHelper } from '@venizia/ignis-helpers';
105
+
106
+ const worker = new BaseWorkerHelper<MyMessageType>({
107
+ identifier: 'data-processor',
108
+ path: './workers/data-processor.js',
109
+ options: { workerData: { batchSize: 100 } },
110
+ eventHandlers: {
111
+ onMessage: opts => console.log('Received:', opts.message),
112
+ onError: opts => console.error('Worker error:', opts.error),
113
+ },
114
+ });
115
+ ```
116
+
117
+ ### Constructor options
118
+
119
+ | Option | Type | Default | Description |
120
+ |--------|------|---------|-------------|
121
+ | `identifier` | `string` | - | A unique name for this worker instance, used as the `BaseHelper` identifier and in log output. Required. |
122
+ | `path` | `string \| URL` | - | Path to the worker script file, passed directly to `new Worker()`. Required. |
123
+ | `options` | `WorkerOptions` (Node.js) | - | Passed directly to `new Worker()`. Required. Supports `workerData`, `transferList`, `env`, etc. |
124
+ | `scope` | `string` | `'BaseWorkerHelper'` | Accepted but currently ignored - the constructor always sets the logger scope to `BaseWorkerHelper.name`, not `opts.scope`. |
125
+ | `eventHandlers` | `Partial<Pick<IWorker<MessageType>, 'onOnline' \| 'onExit' \| 'onError' \| 'onMessage' \| 'onMessageError'>>` | `undefined` | Optional overrides for lifecycle event callbacks. Any handler not provided falls back to default logging behavior. |
126
+
127
+ ### Event handler overrides
128
+
129
+ | Handler | Signature | Default behavior |
130
+ |---------|-----------|-------------------|
131
+ | `onOnline` | `() => ValueOrPromise<void>` | Logs `"Worker ONLINE"` at info level |
132
+ | `onExit` | `(opts: { code: string \| number }) => ValueOrPromise<void>` | Logs `"Worker EXIT | Code: %s"` at warn level |
133
+ | `onError` | `(opts: { error: Error }) => ValueOrPromise<void>` | Logs `"Worker ERROR | Error: %s"` at error level |
134
+ | `onMessage` | `(opts: { message: MessageType }) => ValueOrPromise<void>` | Logs `"Worker MESSAGE | message: %j"` at error level |
135
+ | `onMessageError` | `(opts: { error: Error }) => ValueOrPromise<void>` | Logs `"Worker MESSAGE_ERROR | Error: %s"` at error level |
136
+
137
+ ### Methods
138
+
139
+ | Method | Signature | Description |
140
+ |--------|-----------|-------------|
141
+ | `binding` | `binding(): void` | Binds all five event handlers (`online`, `exit`, `error`, `message`, `messageerror`) to the internal `Worker` instance. Called automatically by the constructor. Throws `[binding] Invalid worker instance to bind event handlers` if `this.worker` is falsy |
142
+
143
+ Every handler runs through `invokeHook`, which wraps the call in a `try/catch`: a synchronous throw inside a user handler is caught and logged (`"Hook execution FAILED | Error: %s"`) rather than crashing the process. Async rejections are settled the same way via `voidExecution`.
144
+
145
+ ### AbstractWorkerHelper (subclassing)
146
+
147
+ For full control, extend `AbstractWorkerHelper` and implement all five lifecycle methods directly instead of passing `eventHandlers`:
148
+
149
+ ```typescript
150
+ import { AbstractWorkerHelper } from '@venizia/ignis-helpers';
151
+
152
+ class CustomWorker extends AbstractWorkerHelper<MyMessage> {
153
+ onOnline() {
154
+ // Custom online handling
155
+ }
156
+
157
+ onExit(opts: { code: string | number }) {
158
+ // Custom exit handling, e.g., restart logic
159
+ }
160
+
161
+ onError(opts: { error: Error }) {
162
+ // Custom error handling
163
+ }
164
+
165
+ onMessage(opts: { message: MyMessage }) {
166
+ // Custom message processing
167
+ }
168
+
169
+ onMessageError(opts: { error: Error }) {
170
+ // Custom message error handling
171
+ }
172
+ }
173
+ ```
174
+
175
+ `AbstractWorkerHelper<MessageType>` declares `worker: Worker`, `options: WorkerOptions`, and the five abstract lifecycle methods above; it does not implement `binding()` itself.
176
+
177
+ ## BaseWorkerThreadHelper (inside a worker thread)
178
+
179
+ `Source ->` [`base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/base.ts)
180
+
181
+ Used inside a worker script to manage named communication buses. Must be instantiated from within a worker thread - constructing it on the main thread throws.
182
+
183
+ ```typescript
184
+ // Inside worker-script.js
185
+ import { BaseWorkerThreadHelper } from '@venizia/ignis-helpers';
186
+
187
+ const thread = new BaseWorkerThreadHelper({ scope: 'DataProcessor' });
188
+ ```
189
+
190
+ ### Constructor options
191
+
192
+ | Option | Type | Default | Description |
193
+ |--------|------|---------|-------------|
194
+ | `scope` | `string` | - | Logger scope and `BaseHelper` identifier for this worker thread. Required. |
195
+
196
+ The constructor checks `isMainThread` (from `node:worker_threads`) and throws `[BaseWorker] Cannot start worker in MAIN_THREAD` if `true`.
197
+
198
+ ### Methods
199
+
200
+ | Method | Signature | Description |
201
+ |--------|-----------|-------------|
202
+ | `bindWorkerBus` | `bindWorkerBus<IC, IP>(opts: { key: string; bus: IWorkerBus<IC, IP> }): void` | Registers a bus under the given key. Logs a warning and returns without overwriting if the key already exists |
203
+ | `unbindWorkerBus` | `unbindWorkerBus(opts: { key: string }): void` | Calls `port.removeAllListeners()` on the bus's port, then deletes it from the registry. Logs a warning if the key is not found |
204
+ | `getWorkerBus` | `getWorkerBus<IC, IP>(opts: { key: string }): IWorkerBus<IC, IP>` | Returns the bus for the given key. Throws `[getWorkerBus] Not found worker bus | key: {key}` if not found |
205
+
206
+ `unbindWorkerBus` is defined only on `BaseWorkerThreadHelper`, not on the `AbstractWorkerThreadHelper` interface - `AbstractWorkerThreadHelper` declares `buses`, `bindWorkerBus`, and `getWorkerBus` as abstract.
207
+
208
+ ## BaseWorkerMessageBusHandlerHelper
209
+
210
+ `Source ->` [`worker-bus.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/worker-bus.ts)
211
+
212
+ Defines the event callbacks for a worker bus.
213
+
214
+ ```typescript
215
+ const handler = new BaseWorkerMessageBusHandlerHelper<MyPayload>({
216
+ scope: 'ProcessorHandler',
217
+ onMessage: opts => console.log('Processing:', opts.message),
218
+ onError: opts => console.error('Bus error:', opts.error),
219
+ });
220
+ ```
221
+
222
+ ### Constructor options
223
+
224
+ | Option | Type | Default | Description |
225
+ |--------|------|---------|-------------|
226
+ | `scope` | `string` | - | Logger scope and identifier. Required. |
227
+ | `onMessage` | `(opts: { message: IConsumePayload }) => ValueOrPromise<void>` | - | Handler called when a message is received on the port. Required. |
228
+ | `onClose` | `() => ValueOrPromise<void>` | No-op `() => {}` | Handler called when the port emits `close`. |
229
+ | `onError` | `(opts: { error: Error }) => ValueOrPromise<void>` | Logs `"worker error: %s"` at error level | Handler called on port `error` and `messageerror` events. |
230
+ | `onExit` | `(opts: { exitCode: number \| string }) => ValueOrPromise<void>` | Logs `"worker EXITED | exitCode: %s"` at warn level | Handler called when the port emits `exit`. |
231
+
232
+ ## BaseWorkerBusHelper (MessagePort communication)
233
+
234
+ `Source ->` [`worker-bus.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/worker-bus.ts)
235
+
236
+ Wraps a `MessagePort` to provide structured bidirectional messaging with lifecycle event handlers.
237
+
238
+ ```typescript
239
+ import { BaseWorkerBusHelper, BaseWorkerMessageBusHandlerHelper } from '@venizia/ignis-helpers';
240
+ import { parentPort } from 'node:worker_threads';
241
+
242
+ const handler = new BaseWorkerMessageBusHandlerHelper<IncomingMessage>({
243
+ scope: 'MyBusHandler',
244
+ onMessage: opts => console.log('Received:', opts.message),
245
+ });
246
+
247
+ const bus = new BaseWorkerBusHelper<IncomingMessage, OutgoingMessage>({
248
+ scope: 'MyBus',
249
+ port: parentPort!,
250
+ busHandler: handler,
251
+ });
252
+ ```
253
+
254
+ ### Constructor options
255
+
256
+ | Option | Type | Default | Description |
257
+ |--------|------|---------|-------------|
258
+ | `scope` | `string` | - | Logger scope and identifier. Required. |
259
+ | `port` | `MessagePort` | - | The `MessagePort` to bind for communication. Required. |
260
+ | `busHandler` | `IWorkerMessageBusHandler<IConsumePayload>` | - | Handler that receives incoming messages and lifecycle events. Required. |
261
+
262
+ The constructor binds `message`, `error`, `messageerror`, `exit`, and `close` listeners on `port`, each routed through the handler's matching callback (`error` and `messageerror` both call `handler.onError`).
263
+
264
+ ### Methods
265
+
266
+ | Method | Signature | Description |
267
+ |--------|-----------|-------------|
268
+ | `postMessage` | `postMessage(opts: { message: IPublishPayload; transferList: readonly Transferable[] \| undefined }): ValueOrPromise<void>` | Sends a message through the port. If `transferList` is provided, calls `port.postMessage(message, [...transferList])`; otherwise `port.postMessage(message)`. Logs and returns (does not throw) if `port` is falsy |
269
+
270
+ ### Pre/post message hooks
271
+
272
+ `onBeforePostMessage` and `onAfterPostMessage` are optional properties declared on the class but left `undefined` by the constructor - assign them after construction:
273
+
274
+ ```typescript
275
+ bus.onBeforePostMessage = opts => {
276
+ console.log('About to send:', opts.message);
277
+ };
278
+
279
+ bus.onAfterPostMessage = opts => {
280
+ console.log('Sent:', opts.message);
281
+ };
282
+ ```
283
+
284
+ `postMessage` invokes `onBeforePostMessage` (if set) before the port write and `onAfterPostMessage` (if set) after, both through the same `try/catch`-wrapped `invokeHook` used for the port event listeners.
285
+
286
+ ### Sending transferable objects
287
+
288
+ ```typescript
289
+ // Send a simple message
290
+ bus.postMessage({
291
+ message: { result: 'processed' },
292
+ transferList: undefined,
293
+ });
294
+
295
+ // Send with transferable objects (zero-copy)
296
+ const buffer = new ArrayBuffer(1024);
297
+ bus.postMessage({
298
+ message: { result: 'binary-data' },
299
+ transferList: [buffer],
300
+ });
301
+ ```
302
+
303
+ ## Types
304
+
305
+ `Source ->` [`types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/worker-thread/types.ts)
306
+
307
+ ```typescript
308
+ interface IWorker<MessageType> {
309
+ worker: Worker;
310
+ options: WorkerOptions;
311
+
312
+ onOnline(): ValueOrPromise<void>;
313
+ onExit(opts: { code: string | number }): ValueOrPromise<void>;
314
+ onError(opts: { error: Error }): ValueOrPromise<void>;
315
+ onMessage(opts: { message: MessageType }): ValueOrPromise<void>;
316
+ onMessageError(opts: { error: Error }): ValueOrPromise<void>;
317
+ }
318
+
319
+ interface IWorkerThread {
320
+ buses: { [workerKey: string | symbol]: IWorkerBus<AnyType, AnyType> };
321
+ }
322
+
323
+ interface IWorkerMessageBusHandler<IConsumePayload> {
324
+ onMessage: (opts: { message: IConsumePayload }) => ValueOrPromise<void>;
325
+ onClose: () => ValueOrPromise<void>;
326
+ onError: (opts: { error: Error }) => ValueOrPromise<void>;
327
+ onExit: (opts: { exitCode: number | string }) => ValueOrPromise<void>;
328
+ }
329
+
330
+ interface IWorkerBus<IConsumePayload, IPublishPayload> {
331
+ port: MessagePort;
332
+ handler: IWorkerMessageBusHandler<IConsumePayload>;
333
+
334
+ onBeforePostMessage?(opts: { message: IPublishPayload }): ValueOrPromise<void>;
335
+ onAfterPostMessage?(opts: { message: IPublishPayload }): ValueOrPromise<void>;
336
+ postMessage(opts: {
337
+ message: IPublishPayload;
338
+ transferList: readonly Transferable[] | undefined;
339
+ }): ValueOrPromise<void>;
340
+ }
341
+ ```
342
+
343
+ ## Troubleshooting
344
+
345
+ ### "[BaseWorker] Cannot start worker in MAIN_THREAD"
346
+
347
+ **Cause:** `BaseWorkerThreadHelper` was instantiated on the main thread. This class is designed to run only inside a worker thread (where `isMainThread` from `node:worker_threads` is `false`).
348
+
349
+ **Fix:** Only create `BaseWorkerThreadHelper` instances inside worker scripts that are spawned via `new Worker(path)`:
350
+
351
+ ```typescript
352
+ // worker-script.js (spawned by the main thread)
353
+ import { BaseWorkerThreadHelper } from '@venizia/ignis-helpers';
354
+
355
+ const thread = new BaseWorkerThreadHelper({ scope: 'MyWorker' }); // OK here
356
+ ```
357
+
358
+ ### "[binding] Invalid worker instance to bind event handlers"
359
+
360
+ **Cause:** `BaseWorkerHelper.binding()` was called but the internal `Worker` instance is falsy. This can occur if the worker script path is invalid and the `Worker` constructor fails.
361
+
362
+ **Fix:** Ensure the `path` passed to `BaseWorkerHelper` points to a valid, existing JavaScript file:
363
+
364
+ ```typescript
365
+ const worker = new BaseWorkerHelper({
366
+ identifier: 'my-worker',
367
+ path: './workers/my-worker.js', // Must exist and be a valid worker script
368
+ options: {},
369
+ });
370
+ ```
371
+
372
+ ### "[register] Invalid worker registry instance | please init registry before register new worker!"
373
+
374
+ **Cause:** `WorkerPoolHelper.register()` was called but the internal registry `Map` is falsy. This is a defensive check that should not occur under normal usage.
375
+
376
+ **Fix:** Ensure you are using either `WorkerPoolHelper.getInstance()` or `new WorkerPoolHelper()`, both of which initialize the registry in the constructor.
377
+
378
+ ### "[getWorkerBus] Not found worker bus | key: {key}"
379
+
380
+ **Cause:** `BaseWorkerThreadHelper.getWorkerBus()` was called with a key that has not been registered via `bindWorkerBus()`.
381
+
382
+ **Fix:** Verify the bus was bound before retrieving it:
383
+
384
+ ```typescript
385
+ thread.bindWorkerBus({ key: 'my-bus', bus: myBus });
386
+
387
+ // Now safe to retrieve
388
+ const bus = thread.getWorkerBus({ key: 'my-bus' });
389
+ ```
390
+
391
+ ### "Failed to post message to main | Invalid parentPort!"
392
+
393
+ **Cause:** `BaseWorkerBusHelper.postMessage()` was called but the `port` property is falsy. This typically means the bus was constructed with an invalid `MessagePort`. This is logged at error level, not thrown - the message is silently dropped.
394
+
395
+ **Fix:** Ensure a valid `MessagePort` (e.g., `parentPort` from `node:worker_threads` or a port from `new MessageChannel()`) is passed to the constructor:
396
+
397
+ ```typescript
398
+ import { parentPort } from 'node:worker_threads';
399
+
400
+ const bus = new BaseWorkerBusHelper({
401
+ scope: 'MyBus',
402
+ port: parentPort!, // Must be a valid MessagePort
403
+ busHandler: handler,
404
+ });
405
+ ```
406
+
407
+ ### Worker pool silently skips registration
408
+
409
+ **Cause:** The pool has reached the CPU core limit and `ignoreMaxWarning` is `false` (the default for `getInstance()`). `register()` returns `false` and logs a warning instead of throwing.
410
+
411
+ **Fix:** Either free up pool slots first, or create a pool with `ignoreMaxWarning: true`:
412
+
413
+ ```typescript
414
+ // Option 1: Free up pool slots
415
+ await pool.unregister({ key: 'old-worker' });
416
+ pool.register({ key: 'new-worker', worker: newWorker });
417
+
418
+ // Option 2: Allow exceeding the limit
419
+ const pool = new WorkerPoolHelper({ ignoreMaxWarning: true });
420
+ ```
421
+
422
+ ## See also
423
+
424
+ - [Worker Thread overview](/extensions/helpers/worker-thread/) - introduction and the most common tasks
425
+ - [Queue Helper](/extensions/helpers/queue/) - message-queue processing as an alternative to worker threads
426
+ - [Node.js Worker Threads](https://nodejs.org/api/worker_threads.html) - official `worker_threads` documentation
427
+ - [MessagePort API](https://nodejs.org/api/worker_threads.html#class-messageport) - underlying port communication
428
+ - [Transferable Objects](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects) - zero-copy data transfer
@@ -14,7 +14,7 @@ import {
14
14
  datasource,
15
15
  ValueOrPromise,
16
16
  } from '@venizia/ignis';
17
- import { drizzle } from 'drizzle-orm/node-postgres';
17
+ import { NodePostgresDriver } from '@venizia/ignis/postgres/node-postgres';
18
18
  import { Pool } from 'pg';
19
19
 
20
20
  interface IDSConfigs {
@@ -25,7 +25,7 @@ interface IDSConfigs {
25
25
  password: string;
26
26
  }
27
27
 
28
- @datasource({ driver: 'node-postgres' })
28
+ @datasource({ driver: NodePostgresDriver })
29
29
  export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
30
30
  constructor() {
31
31
  super({
@@ -42,16 +42,11 @@ export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
42
42
  }
43
43
 
44
44
  override configure(): ValueOrPromise<void> {
45
- // getSchema() auto-discovers models from @repository bindings
46
- const schema = this.getSchema();
47
-
48
- this.logger.debug(
49
- '[configure] Auto-discovered schema | Keys: %o',
50
- Object.keys(schema),
51
- );
45
+ const schema = Object.keys(this.getSchema());
46
+ this.logger.debug('[configure] Auto-discovered schema | Keys: %o', schema);
52
47
 
48
+ // That is all - naming NodePostgresDriver above is what wires the driver and connector.
53
49
  this.client = new Pool(this.settings);
54
- this.connector = drizzle({ client: this.client, schema });
55
50
  }
56
51
 
57
52
  override getConnectionString(): ValueOrPromise<string> {
@@ -62,22 +57,22 @@ export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
62
57
  ```
63
58
 
64
59
  > [!NOTE] Driver seam: the raw client goes on `this.client`
65
- > `this.client = new Pool(...)` is the short path: IGNIS resolves a `node-postgres` driver from that client on first use. There is no `pool` field - the raw-client slot is `client`, whatever the client happens to be. The alternative is to wire a driver yourself: `configure()` calls `this.useDriver({ driver, schema? })`, which assigns `this.driver` **and** builds `this.connector` in one step (so the half-wired state cannot exist). That is also how you select the `postgres-js` driver or run on Supabase. See [Postgres Drivers & Supabase](./postgres-drivers).
60
+ > `this.client = new Pool(...)` is the short path: `configure()` builds only the client, and `getConnector()`/`beginTransaction()` lazily instantiate the class named in `@datasource({ driver })` over it - `NodePostgresDriver` here. There is no `pool` field - the raw-client slot is `client`, whatever the client happens to be. Naming the driver class (rather than a driver-name string) is what carries `pg` into the app's bundle - a bundler only packages a real value reference, never text. The alternative is to wire a driver yourself for a custom or third-party driver: `configure()` calls `this.useDriver({ driver, schema? })`, which assigns `this.driver` **and** builds `this.connector` in one step (so the half-wired state cannot exist), bypassing `@datasource({ driver })` entirely. See [Postgres Drivers & Supabase](./postgres-drivers) for `postgres-js` and Supabase.
66
61
 
67
62
  **How auto-discovery works:**
68
63
 
69
64
  1. `@repository` decorators register model-datasource bindings in the `MetadataRegistry`
70
- 2. When `configure()` is called, `getSchema()` invokes `discoverSchema()` which calls `MetadataRegistry.buildSchema({ dataSource })` to collect all bound models and their relations
71
- 3. Drizzle is initialized with the complete schema (tables + Drizzle relations)
65
+ 2. `getSchema()` invokes `discoverSchema()` which calls `MetadataRegistry.buildSchema({ dataSource })` to collect all bound models and their relations
66
+ 3. The lazily-built Drizzle connector is initialized with the complete schema (tables + Drizzle relations)
72
67
 
73
- You can disable auto-discovery per datasource via `@datasource({ driver: 'node-postgres', autoDiscovery: false })`.
68
+ You can disable auto-discovery per datasource via `@datasource({ driver: NodePostgresDriver, autoDiscovery: false })`.
74
69
 
75
70
  ## Manual Schema (Optional)
76
71
 
77
72
  If you need explicit control, you can still provide schema manually:
78
73
 
79
74
  ```typescript
80
- @datasource({ driver: 'node-postgres' })
75
+ @datasource({ driver: NodePostgresDriver })
81
76
  export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
82
77
  constructor() {
83
78
  super({
@@ -99,7 +94,7 @@ export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
99
94
  AbstractDataSource extends BaseHelper # engine-neutral, src/base - no pool, no Drizzle
100
95
  └── AbstractPostgresDataSource # connectors/postgres - adds pool, connector
101
96
  └── BasePostgresDataSource (alias: BaseDataSource)
102
- ├── configure() # Setup pool + Drizzle connector (abstract)
97
+ ├── configure() # Assign this.client (abstract) - base wires driver + connector
103
98
  ├── getConnectionString() # Build connection URL (abstract)
104
99
  ├── getSchema() # Auto-discover from @repository bindings
105
100
  ├── discoverSchema() # Internal: reads MetadataRegistry
@@ -135,7 +130,7 @@ DataSources are bound as **singletons** to ensure connection pool sharing across
135
130
 
136
131
  ```typescript
137
132
  import { BasePostgresDataSource, datasource, ValueOrPromise } from '@venizia/ignis';
138
- import { drizzle } from 'drizzle-orm/node-postgres';
133
+ import { NodePostgresDriver } from '@venizia/ignis/postgres/node-postgres';
139
134
  import { Pool } from 'pg';
140
135
 
141
136
  interface IDSConfigs {
@@ -146,7 +141,7 @@ interface IDSConfigs {
146
141
  password: string;
147
142
  }
148
143
 
149
- @datasource({ driver: 'node-postgres' })
144
+ @datasource({ driver: NodePostgresDriver })
150
145
  export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
151
146
  constructor() {
152
147
  super({
@@ -162,9 +157,7 @@ export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
162
157
  }
163
158
 
164
159
  override configure(): ValueOrPromise<void> {
165
- const schema = this.getSchema();
166
160
  this.client = new Pool(this.settings);
167
- this.connector = drizzle({ client: this.client, schema });
168
161
  }
169
162
 
170
163
  override getConnectionString(): ValueOrPromise<string> {
@@ -49,7 +49,7 @@ export class User extends BasePostgresEntity<typeof User.schema> {
49
49
  }
50
50
 
51
51
  // 2. Create a DataSource
52
- @datasource({ driver: 'node-postgres' })
52
+ @datasource({ driver: NodePostgresDriver })
53
53
  export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
54
54
  constructor() {
55
55
  super({
@@ -65,9 +65,7 @@ export class PostgresDataSource extends BasePostgresDataSource<IDSConfigs> {
65
65
  }
66
66
 
67
67
  override configure(): ValueOrPromise<void> {
68
- const schema = this.getSchema();
69
- this.client = new Pool(this.settings);
70
- this.connector = drizzle({ client: this.client, schema });
68
+ this.client = new Pool(this.settings); // NodePostgresDriver above wires the driver + connector
71
69
  }
72
70
 
73
71
  override getConnectionString(): ValueOrPromise<string> {
@@ -200,7 +200,7 @@ const user = await userRepo.findById({ id: '123' });
200
200
  // { id: '123', email: 'john@example.com' }
201
201
 
202
202
  // Connector query - includes all fields
203
- const connector = userRepo.getConnector();
203
+ const connector = userRepo.connector;
204
204
  const [fullUser] = await connector
205
205
  .select()
206
206
  .from(User.schema)