@venizia/ignis-docs 0.2.0 → 0.2.1-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) 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 +24 -13
  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 +27 -3
  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 +8 -4
  17. package/content/best-practices/data-modeling.md +78 -62
  18. package/content/best-practices/deployment-strategies.md +56 -19
  19. package/content/best-practices/error-handling.md +247 -153
  20. package/content/best-practices/index.md +6 -0
  21. package/content/best-practices/performance-optimization.md +26 -13
  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 +109 -323
  26. package/content/extensions/components/authentication/api.md +489 -602
  27. package/content/extensions/components/authentication/errors.md +135 -498
  28. package/content/extensions/components/authentication/index.md +89 -801
  29. package/content/extensions/components/authentication/usage.md +231 -955
  30. package/content/extensions/components/authorization/api.md +991 -644
  31. package/content/extensions/components/authorization/errors.md +204 -208
  32. package/content/extensions/components/authorization/getting-started.md +227 -0
  33. package/content/extensions/components/authorization/index.md +88 -795
  34. package/content/extensions/components/authorization/usage.md +219 -528
  35. package/content/extensions/components/health-check.md +77 -243
  36. package/content/extensions/components/index.md +24 -90
  37. package/content/extensions/components/mail/api.md +553 -285
  38. package/content/extensions/components/mail/errors.md +76 -62
  39. package/content/extensions/components/mail/index.md +111 -463
  40. package/content/extensions/components/mail/usage.md +139 -173
  41. package/content/extensions/components/request-tracker.md +70 -173
  42. package/content/extensions/components/socket-io/api.md +462 -785
  43. package/content/extensions/components/socket-io/errors.md +49 -51
  44. package/content/extensions/components/socket-io/index.md +69 -372
  45. package/content/extensions/components/socket-io/usage.md +212 -105
  46. package/content/extensions/components/static-asset/api.md +461 -141
  47. package/content/extensions/components/static-asset/errors.md +121 -53
  48. package/content/extensions/components/static-asset/index.md +84 -606
  49. package/content/extensions/components/static-asset/usage.md +184 -299
  50. package/content/extensions/components/template/index.md +3 -3
  51. package/content/extensions/components/websocket/api.md +311 -404
  52. package/content/extensions/components/websocket/errors.md +47 -56
  53. package/content/extensions/components/websocket/index.md +75 -407
  54. package/content/extensions/components/websocket/usage.md +120 -338
  55. package/content/extensions/helpers/cron/index.md +52 -160
  56. package/content/extensions/helpers/crypto/index.md +67 -480
  57. package/content/extensions/helpers/crypto/reference.md +528 -0
  58. package/content/extensions/helpers/env/index.md +64 -178
  59. package/content/extensions/helpers/error/index.md +286 -196
  60. package/content/extensions/helpers/index.md +61 -47
  61. package/content/extensions/helpers/inversion/index.md +76 -550
  62. package/content/extensions/helpers/inversion/reference.md +530 -0
  63. package/content/extensions/helpers/kafka/admin.md +23 -3
  64. package/content/extensions/helpers/kafka/compile-binary.md +83 -52
  65. package/content/extensions/helpers/kafka/consumer.md +65 -28
  66. package/content/extensions/helpers/kafka/examples.md +46 -253
  67. package/content/extensions/helpers/kafka/index.md +55 -617
  68. package/content/extensions/helpers/kafka/producer.md +156 -22
  69. package/content/extensions/helpers/kafka/schema-registry.md +59 -79
  70. package/content/extensions/helpers/logger/hf-logger.md +220 -0
  71. package/content/extensions/helpers/logger/index.md +78 -552
  72. package/content/extensions/helpers/logger/pino.md +105 -0
  73. package/content/extensions/helpers/logger/reference.md +937 -0
  74. package/content/extensions/helpers/network/api.md +276 -195
  75. package/content/extensions/helpers/network/index.md +87 -524
  76. package/content/extensions/helpers/queue/index.md +80 -897
  77. package/content/extensions/helpers/queue/reference.md +494 -0
  78. package/content/extensions/helpers/redis/index.md +86 -640
  79. package/content/extensions/helpers/redis/reference.md +784 -0
  80. package/content/extensions/helpers/secrets/index.md +136 -0
  81. package/content/extensions/helpers/socket-io/api.md +325 -204
  82. package/content/extensions/helpers/socket-io/index.md +79 -429
  83. package/content/extensions/helpers/storage/api.md +584 -464
  84. package/content/extensions/helpers/storage/index.md +80 -573
  85. package/content/extensions/helpers/types/index.md +75 -495
  86. package/content/extensions/helpers/types/reference.md +689 -0
  87. package/content/extensions/helpers/uid/index.md +176 -189
  88. package/content/extensions/helpers/websocket/api.md +366 -214
  89. package/content/extensions/helpers/websocket/index.md +68 -503
  90. package/content/extensions/helpers/worker-thread/index.md +62 -396
  91. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  92. package/content/extensions/index.md +38 -39
  93. package/content/extensions/src-details/mcp-server.md +96 -548
  94. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  95. package/content/guides/core-concepts/persistent/index.md +5 -1
  96. package/content/guides/core-concepts/persistent/models.md +1 -1
  97. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  98. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  99. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  100. package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
  101. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  102. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  103. package/content/guides/core-concepts/secrets-vault.md +177 -0
  104. package/content/guides/core-concepts/services.md +1 -1
  105. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  106. package/content/guides/get-started/philosophy.md +135 -670
  107. package/content/guides/get-started/setup.md +53 -74
  108. package/content/guides/migrations/redis-helpers-migration.md +5 -4
  109. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  110. package/content/guides/migrations/unified-connectors-migration.md +8 -7
  111. package/content/guides/tutorials/ecommerce-api.md +3 -8
  112. package/content/guides/tutorials/realtime-chat.md +1 -1
  113. package/content/references/base/application.md +64 -22
  114. package/content/references/base/components.md +3 -3
  115. package/content/references/base/connectors.md +79 -136
  116. package/content/references/base/controllers.md +12 -12
  117. package/content/references/base/datasources-reference.md +600 -0
  118. package/content/references/base/datasources.md +84 -444
  119. package/content/references/base/dependency-injection.md +25 -46
  120. package/content/references/base/filter-system/application-usage.md +95 -123
  121. package/content/references/base/filter-system/array-operators.md +33 -43
  122. package/content/references/base/filter-system/comparison-operators.md +55 -63
  123. package/content/references/base/filter-system/default-filter.md +144 -350
  124. package/content/references/base/filter-system/fields-order-pagination.md +116 -148
  125. package/content/references/base/filter-system/index.md +114 -253
  126. package/content/references/base/filter-system/json-filtering.md +52 -181
  127. package/content/references/base/filter-system/list-operators.md +28 -44
  128. package/content/references/base/filter-system/logical-operators.md +69 -114
  129. package/content/references/base/filter-system/null-operators.md +41 -98
  130. package/content/references/base/filter-system/pattern-matching.md +48 -51
  131. package/content/references/base/filter-system/quick-reference.md +93 -196
  132. package/content/references/base/filter-system/range-operators.md +22 -38
  133. package/content/references/base/filter-system/tips.md +70 -133
  134. package/content/references/base/filter-system/use-cases.md +173 -232
  135. package/content/references/base/grpc-controllers.md +53 -17
  136. package/content/references/base/index.md +5 -3
  137. package/content/references/base/middlewares.md +43 -28
  138. package/content/references/base/models-reference.md +886 -0
  139. package/content/references/base/models.md +81 -1452
  140. package/content/references/base/providers.md +8 -8
  141. package/content/references/base/repositories/advanced.md +281 -419
  142. package/content/references/base/repositories/index.md +84 -644
  143. package/content/references/base/repositories/mixins.md +25 -21
  144. package/content/references/base/repositories/relations.md +194 -375
  145. package/content/references/base/repositories/soft-deletable.md +67 -55
  146. package/content/references/base/secrets.md +267 -0
  147. package/content/references/base/services.md +8 -6
  148. package/content/references/configuration/environment-variables.md +73 -21
  149. package/content/references/configuration/index.md +51 -31
  150. package/content/references/index.md +1 -1
  151. package/content/references/quick-reference.md +3 -16
  152. package/content/references/utilities/crypto.md +35 -76
  153. package/content/references/utilities/date.md +33 -73
  154. package/content/references/utilities/duration.md +85 -0
  155. package/content/references/utilities/index.md +6 -2
  156. package/content/references/utilities/jsx-reference.md +298 -0
  157. package/content/references/utilities/jsx.md +82 -525
  158. package/content/references/utilities/module.md +81 -61
  159. package/content/references/utilities/parse.md +34 -64
  160. package/content/references/utilities/performance.md +33 -58
  161. package/content/references/utilities/promise.md +28 -62
  162. package/content/references/utilities/request.md +58 -218
  163. package/content/references/utilities/retry.md +139 -0
  164. package/content/references/utilities/schema.md +43 -137
  165. package/content/references/utilities/statuses-reference.md +361 -0
  166. package/content/references/utilities/statuses.md +63 -667
  167. package/dist/mcp-server/index.js +0 -0
  168. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  169. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  171. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  172. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  173. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  174. package/package.json +24 -23
@@ -1,90 +1,110 @@
1
- # Module Utility
2
-
3
- The Module utility provides a pre-flight check for optional peer dependencies. IGNIS helpers and components often depend on packages that are not bundled with the framework (for example, `@connectrpc/connect` for gRPC, `@hono/swagger-ui` for the Swagger component). Calling `validateModule` at the start of a lazy-loaded code path ensures a clear, actionable error is thrown before any import is attempted, rather than a cryptic "Cannot find module" crash.
1
+ ---
2
+ title: Module Utility
3
+ description: Loads an optional peer dependency with a clear install error, and without letting the bundler see the specifier
4
+ difficulty: beginner
5
+ lastUpdated: 2026-07-27
6
+ ---
4
7
 
5
- Resolution is rooted at `process.cwd()/node_modules` via Node's `createRequire`, so peer dependencies installed in the consuming application are found correctly even though this utility lives inside `packages/helpers/dist/`.
8
+ # Module Utility
6
9
 
7
- ## `validateModule`
10
+ `ModuleUtility` loads an optional peer dependency. IGNIS components depend on packages the framework does not bundle - `nodemailer` for mail, `node-vault` for secrets. Loading one through `ModuleUtility` buys you two things: a missing package throws an install instruction instead of a cryptic crash, and the specifier stays invisible to `Bun.build`.
8
11
 
9
- Resolves each module name in sequence using `require.resolve`. If any module cannot be found it logs the failure and throws an `ApplicationError` with an install instruction. Returns a `Promise<void>` - it is async to support consistent `await` usage at call sites, though resolution itself is synchronous.
12
+ ## In one example
10
13
 
11
- ### Signature
14
+ This is how the secrets helper reaches `node-vault`:
12
15
 
13
16
  ```typescript
14
- validateModule(opts: {
15
- scope?: string;
16
- modules: Array<string>;
17
- }): Promise<void>
17
+ import { ModuleUtility } from '@venizia/ignis-helpers';
18
+
19
+ // Fails fast with a clear install instruction if the peer is absent.
20
+ ModuleUtility.assertInstalled({
21
+ scope: 'HashiCorpVaultHelper',
22
+ modules: ['node-vault'],
23
+ allowRegistered: true,
24
+ });
25
+
26
+ // The specifier is a parameter, so Bun.build never sees it.
27
+ const vault = await ModuleUtility.load({ module: 'node-vault' });
28
+ const client = vault.default({ endpoint, apiVersion: 'v1' });
18
29
  ```
19
30
 
20
- **Options**
31
+ ## Methods
21
32
 
22
- | Option | Type | Default | Description |
23
- |--------|------|---------|-------------|
24
- | `modules` | `Array<string>` | `[]` | Module names to check. Evaluated in order - the first missing module stops the loop and throws. |
25
- | `scope` | `string` | `''` | Human-readable label for the calling feature (e.g. the component or helper class name). Included in the error message to tell the developer which feature needs the package. |
33
+ | Method | Signature | What it does |
34
+ |--------|-----------|---------------|
35
+ | `load` | `load<T>(opts: { module: string }): Promise<T>` | Imports the module. Use this everywhere except a constructor |
36
+ | `loadSync` | `loadSync<T>(opts: { module: string }): T` | Same, without awaiting - for a constructor or any path that cannot be async |
37
+ | `assertInstalled` | `assertInstalled(opts: { modules: Array<string>; scope?: string; allowRegistered?: boolean }): void` | Presence check only. Resolves each module in order and throws on the first miss, without executing any of them |
38
+ | `register` | `register(opts: { modules: Record<string, AnyType> }): void` | Hands the framework peers the application already holds. `load` and `loadSync` serve a registered specifier from memory, with no filesystem lookup |
26
39
 
27
- ### Error message format
40
+ ### `allowRegistered`
28
41
 
29
- When a module is missing the thrown error reads:
42
+ `assertInstalled` reports what is on disk. Set `allowRegistered` to count a `register` entry as present too.
30
43
 
31
- ```
32
- [validateModule] <module> is required for <scope>. Please install '<module>'
33
- ```
44
+ Set it only where `load` or `loadSync` is what finally loads the module. A caller that resolves the specifier itself cannot see the registry - `pino.transport()` resolves inside a worker thread, and the gRPC adapter uses its own `createRequire`. For those, counting a registration as installed would replace a precise error with an opaque one.
34
45
 
35
- If `scope` is omitted:
46
+ ## Error message format
36
47
 
37
- ```
38
- [validateModule] <module> is required. Please install '<module>'
39
- ```
48
+ | `scope` | Message |
49
+ |---------|---------|
50
+ | provided | `[ModuleUtility.<method>] <module> is required for <scope>. Please install '<module>'` |
51
+ | omitted | `[ModuleUtility.<method>] <module> is required. Please install '<module>'` |
40
52
 
41
- ### Example - gRPC controller (optional dep guard)
53
+ ## Why not a plain import
42
54
 
43
- The `GrpcRequestAdapter` uses `validateModule` to gate the ConnectRPC import. The check runs once before the adapter is wired up, so the error surfaces at startup rather than on the first request.
55
+ `Bun.build` resolves a literal specifier at bundle time. A literal `require('mailgun.js')` anywhere reachable from an entry point forces every consumer who compiles a binary to install that peer or list it in `external` - even a consumer who never touches mail.
44
56
 
45
- ```typescript
46
- import { validateModule } from '@venizia/ignis-helpers';
57
+ A `const` does not help. `minify: { syntax: true }` folds `const s = 'mailgun.js'; import(s)` straight back into a resolvable literal.
47
58
 
48
- const GRPC_MODULES = ['@connectrpc/connect'];
59
+ Only a specifier that crosses a function boundary survives as a runtime import. That is the whole reason `ModuleUtility` takes the module name as a parameter.
49
60
 
50
- export class MyGrpcController extends BaseGrpcController {
51
- async configure() {
52
- // Fails fast with a clear install instruction if the peer dep is absent
53
- await validateModule({ scope: MyGrpcController.name, modules: GRPC_MODULES });
61
+ ## Compiled binaries
54
62
 
55
- const { ConnectRouter } = await import('@connectrpc/connect');
56
- // ... register routes
57
- }
58
- }
59
- ```
63
+ Runtime resolution needs a `node_modules` to resolve against. A `bun build --compile` binary usually runs without one - the deployment ships the executable and nothing else - so a peer the application genuinely installed is still unreachable at runtime, and the component that needs it dies at boot with the install hint.
60
64
 
61
- ### Example - custom helper with multiple optional deps
65
+ **Check the component's options first.** Every component that reaches a peer this way takes it through its own options:
62
66
 
63
- When a feature requires several packages, list them all. The first missing one stops the check.
67
+ | Component | Option | You pass |
68
+ |---|---|---|
69
+ | Mail transports | `module` | the `nodemailer` or `mailgun.js` module |
70
+ | gRPC component | `module` | `{ connect, protocol }` from `@connectrpc/connect` |
71
+ | `HashiCorpVaultHelper` | `client` | an already-built vault client |
72
+ | `DotenvVaultHelper` | `decode` | your own decode function |
73
+
74
+ Prefer the option. It is typed, it lands where it is used, and no ordering can defeat it.
75
+
76
+ `register` is the fallback for a peer the framework reaches with no options seam in between. The static import is what pulls the library into the binary; `register` is what lets the framework find it there:
64
77
 
65
78
  ```typescript
66
- import { validateModule } from '@venizia/ignis-helpers';
67
- import { BaseHelper } from '@venizia/ignis-helpers';
68
-
69
- export class KafkaQueueHelper extends BaseHelper {
70
- async configure() {
71
- await validateModule({
72
- scope: KafkaQueueHelper.name,
73
- modules: ['kafkajs', 'kafkajs-snappy'],
74
- });
75
-
76
- const { Kafka } = await import('kafkajs');
77
- // ... initialise Kafka client
78
- }
79
- }
79
+ import { ModuleUtility } from '@venizia/ignis-helpers';
80
+ import * as vault from 'node-vault';
81
+
82
+ // At the entrypoint, before anything that reaches the peer runs.
83
+ ModuleUtility.register({ modules: { 'node-vault': vault } });
80
84
  ```
81
85
 
82
- ## When to use
86
+ The registry is keyed by specifier and the value is returned as-is: what you register under `node-vault` is exactly what `load({ module: 'node-vault' })` hands the caller. `import * as` gives the right shape for a CommonJS peer.
87
+
88
+ Register before the consumer runs. Nothing enforces that ordering, which is the reason to prefer an options seam wherever one exists.
89
+
90
+ `register` cannot help a consumer that resolves the specifier itself. A `pino` transport target loads inside a worker thread the registry never reaches, so `pino-pretty` and `pino-roll` must be installed on disk.
91
+
92
+ Registration is only worth it for the compiled-binary case. An application running from source resolves its peers from `node_modules` already.
93
+
94
+ ## Notes
95
+
96
+ - **Resolution is rooted at `process.cwd()/node_modules`** via Node's `createRequire`, so peers installed in the consuming application resolve even though this utility ships inside `packages/helpers/dist/`.
97
+ - **`assertInstalled` stops at the first miss.** Later entries are never checked.
98
+ - **`assertInstalled` never executes the module** - it only locates the file. Reach for it when you want to fail at startup rather than on first use.
99
+ - **Call it once, at startup, not per request.** Place it in an initialisation hook (`configure`, `binding`, `boot`).
100
+ - **`register` wins over the filesystem.** `load` and `loadSync` check the registry first, so a registered peer is never resolved. `assertInstalled` ignores the registry unless you set `allowRegistered`.
101
+ - **`register` never logs.** It runs at the entrypoint of a compiled binary, which is exactly where no logger provider exists yet.
102
+ - **Recommended pattern:** declare the dependency in `peerDependenciesMeta` with `optional: true`, then load it through `ModuleUtility` and pass the feature or class name as `scope` so the thrown message pinpoints the caller.
103
+
104
+ ## See also
83
105
 
84
- Use `validateModule` whenever your code does a dynamic `import()` of a package that is listed as an optional peer dependency in `package.json`. The recommended pattern is:
106
+ - [Utilities Overview](/references/utilities/) - all utility functions
85
107
 
86
- 1. Declare the dep as `peerDependenciesMeta` with `optional: true` in `package.json`.
87
- 2. Call `validateModule` at the top of the method that needs the package - before any `import()`.
88
- 3. Pass the feature or class name as `scope` so the error message pinpoints which feature triggered the check.
108
+ **Files:**
89
109
 
90
- Avoid calling `validateModule` on every request. Place it in an initialisation hook (`configure`, `binding`, `boot`) that runs once at startup.
110
+ - [`packages/helpers/src/utilities/module.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/utilities/module.utility.ts)
@@ -1,85 +1,55 @@
1
- # Parse Utility
2
-
3
- The Parse utility provides a collection of functions for data type checking, conversion, and transformation.
1
+ ---
2
+ title: Parse Utility
3
+ description: Type checking, safe numeric and boolean conversion, camelCase transforms, and array-to-map helpers
4
+ difficulty: beginner
5
+ lastUpdated: 2026-07-16
6
+ ---
4
7
 
5
- ## Type Checking
6
-
7
- - **`isInt(n)`**: Checks if a value is an integer.
8
- - **`isFloat(n)`**: Checks if a value is a float.
8
+ # Parse Utility
9
9
 
10
- ## Type Conversion
10
+ A collection of standalone functions for type checking, safe type conversion, and string/object/array transformation - the small helpers repositories and controllers reach for when normalizing loosely typed input.
11
11
 
12
- - **`int(input)`**: Parses a value to an integer. Handles strings with commas and defaults to `0` if the input is invalid.
13
- - **`float(input, digit = 2)`**: Parses a value to a float, rounding to a specified number of digits. Handles strings with commas and defaults to `0` if the input is invalid.
14
- - **`toBoolean(input)`**: Converts a value to a boolean. Returns `false` for empty string, `'false'`, `'0'`, `false`, `0`, `null`, and `undefined`. Returns `true` for everything else.
12
+ ## In one example
15
13
 
16
14
  ```typescript
17
- import { int, float, toBoolean } from '@venizia/ignis-helpers';
15
+ import { int, float, toBoolean, toCamel, keysToCamel } from '@venizia/ignis-helpers';
18
16
 
19
17
  const myInt = int('1,000'); // => 1000
20
18
  const myFloat = float('1,234.567', 2); // => 1234.57
21
19
  const myBool = toBoolean('true'); // => true
22
- ```
23
-
24
- ## String and Object Transformation
25
-
26
- - **`toCamel(s)`**: Converts a string from snake_case or kebab-case to camelCase.
27
- - **`keysToCamel(object)`**: Recursively converts all keys in an object (and nested objects) to camelCase.
28
-
29
- ```typescript
30
- import { toCamel, keysToCamel } from '@venizia/ignis-helpers';
31
-
32
- const camelString = toCamel('my-snake_case-string');
33
- // => 'mySnakeCaseString'
34
20
 
35
21
  const camelObject = keysToCamel({ 'first-name': 'John', 'last_name': 'Doe' });
36
22
  // => { firstName: 'John', lastName: 'Doe' }
37
23
  ```
38
24
 
39
- ## Number Parsing
25
+ ## Functions
40
26
 
27
+ | Function | Signature | What it does |
28
+ |----------|-----------|---------------|
29
+ | `isInt` | `isInt(n: any): boolean` | `true` when `n` is (or coerces to) an integer. |
30
+ | `isFloat` | `isFloat(input: any): boolean` | `true` when `input` is (or coerces to) a non-integer number. |
31
+ | `int` | `int(input: any): number` | Parses `input` to an integer. Strips commas first; returns `0` for empty/invalid input. |
32
+ | `float` | `float(input: any, digit = 2): number` | Parses `input` to a float, rounded to `digit` places (via lodash `round`). Strips commas first; returns `0` for empty/invalid input. |
33
+ | `toBoolean` | `toBoolean(input: any): boolean` | `false` for `''`, `'false'`, `'0'`, `false`, `0`, `null`, `undefined`; `true` for everything else. |
34
+ | `toCamel` | `toCamel(s: string): string` | Converts a `snake_case` or `kebab-case` string to `camelCase`. |
35
+ | `keysToCamel` | `keysToCamel(object: object): any` | Recursively camelizes every key in `object`. Arrays stay arrays (their object elements are still camelized); `Date` values pass through untouched. |
36
+ | `parseArrayToMapWithKey` | `parseArrayToMapWithKey<T, K>(arr: T[], keyMap: K): Map<T[K], T>` | Turns an array of objects into a `Map` keyed by `keyMap`. Positional arguments, not an options object. Throws if `keyMap` is missing from an element; last element wins on duplicate keys. |
37
+ | `toDelimitedArray` | `toDelimitedArray(input: unknown, separator = ','): string[]` | Splits `input` on `separator` into trimmed, non-empty entries. `null`/`undefined` input returns `[]`. |
38
+ | `toTrimmed` | `toTrimmed(input: unknown): string` | Stringifies and trims `input`; `null`/`undefined` returns `''`. |
39
+ | `getUID` | `getUID(): string` | Generates a short, uppercase, `Math.random()`-based ID - not cryptographically unique. |
41
40
 
42
- ```typescript
43
-
44
- // US format (default) - comma is thousands separator
41
+ ## Notes
45
42
 
46
- // EU format - dot is thousands separator, comma is decimal
47
- ```
43
+ - **`int`/`float` are comma-tolerant.** Both strip `,` before parsing, so `'1,000'` and `1000` behave the same - useful for user-typed numeric input.
44
+ - **`parseArrayToMapWithKey` breaks the options-object convention on purpose** - it takes `(arr, keyMap)` positionally, unlike every other function on this page.
45
+ - **`toDelimitedArray` and `toTrimmed` are the transform functions for list-shaped and string env values** - typical use is `applicationEnvironment.get(KEY, { transform: toDelimitedArray })`.
46
+ - **`getUID` is for short, human-glanceable identifiers**, not for anything that needs global uniqueness guarantees - use the [UID helper](/extensions/helpers/) (Snowflake-based) for that.
48
47
 
49
- | Option | Type | Default | Description |
50
- |--------|------|---------|-------------|
51
- | `method` | `'int' \| 'float'` | `'int'` | Parse as integer or float |
52
- | `locale` | `'us' \| 'eu'` | `'us'` | Number format locale |
48
+ ## See also
53
49
 
54
- ## Array Transformation
50
+ - [Utilities Overview](/references/utilities/) - all utility functions
51
+ - [Schema Utility](/references/utilities/schema) - `snakeToCamel` for Zod schemas built on `toCamel`/`keysToCamel`
55
52
 
56
- - **`parseArrayToMapWithKey(arr, keyMap)`**: Transforms an array of objects into a `Map`, using a specified property of the objects as keys. Takes positional arguments (not an options object). Throws an error if `keyMap` is not found in an element. Last element wins on duplicate keys.
53
+ **Files:**
57
54
 
58
- ```typescript
59
- import { parseArrayToMapWithKey } from '@venizia/ignis-helpers';
60
-
61
- const users = [
62
- { id: 1, name: 'Alice' },
63
- { id: 2, name: 'Bob' },
64
- ];
65
-
66
- // Record (options object pattern)
67
- // => { 1: { id: 1, name: 'Alice' }, 2: { id: 2, name: 'Bob' } }
68
-
69
- // Map (positional arguments)
70
- const usersMap = parseArrayToMapWithKey(users, 'id');
71
- // => Map { 1 => { id: 1, name: 'Alice' }, 2 => { id: 2, name: 'Bob' } }
72
-
73
- const user = usersMap.get(1);
74
- // => { id: 1, name: 'Alice' }
75
- ```
76
-
77
- ## Unique ID
78
-
79
- - **`getUID()`**: Generates a simple, short unique ID string based on `Math.random()`, returned in uppercase.
80
-
81
- ```typescript
82
- import { getUID } from '@venizia/ignis-helpers';
83
-
84
- const uniqueId = getUID(); // => e.g., 'A1B2C3D4'
85
- ```
55
+ - [`packages/helpers/src/utilities/parse.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/utilities/parse.utility.ts)
@@ -1,79 +1,54 @@
1
- # Performance Utility
2
-
3
- The Performance utility provides functions for measuring and logging the execution time of code blocks, which is useful for identifying bottlenecks and optimizing your application. All timing uses `performance.now()` (milliseconds).
4
-
5
- ## `executeWithPerformanceMeasure`
6
-
7
- This is a higher-order function that wraps a task (a function), automatically logging its start time, end time, and total execution duration. Returns a Promise that resolves to the task's return value.
1
+ ---
2
+ title: Performance Utility
3
+ description: Checkpoint-based timing and a logging wrapper for measuring execution duration
4
+ difficulty: beginner
5
+ lastUpdated: 2026-07-16
6
+ ---
8
7
 
9
- ### `executeWithPerformanceMeasure(opts)`
10
-
11
- - `opts` (object):
12
- - `logger` (Logger, optional): A logger instance to use for logging. Defaults to `console`.
13
- - `level` (string, optional): The log level to use (e.g., `'debug'`, `'info'`). Defaults to `'debug'`.
14
- - `description` (string, optional): A description of the task being measured. Defaults to `'Executing'`.
15
- - `scope` (string): A scope to identify the context of the measurement.
16
- - `task` (Function): The function to be executed and measured. Can be sync or async (wrapped with `Promise.resolve()`).
17
- - `args` (any, optional): Arguments to include in the log output for debugging purposes. When provided, they are logged as JSON (`%j` format).
8
+ # Performance Utility
18
9
 
19
- ### Example
10
+ Functions for measuring and logging how long a code block takes to run, built on `performance.now()` (millisecond resolution). `BaseApplication` uses `executeWithPerformanceMeasure` internally to time component, controller, and datasource registration during startup.
20
11
 
21
- The `BaseApplication` uses this utility to measure the time taken to register components, controllers, and data sources during the startup process.
12
+ ## In one example
22
13
 
23
14
  ```typescript
24
- // Inside BaseApplication class
25
15
  import { executeWithPerformanceMeasure } from '@venizia/ignis-helpers';
26
16
 
27
- // ...
28
-
29
- async registerComponents() {
30
- await executeWithPerformanceMeasure({
31
- logger: this.logger,
32
- scope: this.registerComponents.name,
33
- description: 'Register application components',
34
- task: async () => {
35
- // ... logic to register components
36
- },
37
- });
38
- }
17
+ await executeWithPerformanceMeasure({
18
+ logger: this.logger,
19
+ scope: this.registerComponents.name,
20
+ description: 'Register application components',
21
+ task: async () => {
22
+ // ... logic to register components
23
+ },
24
+ });
39
25
  ```
40
26
 
41
- When `registerComponents` is called, it will produce log output similar to this:
42
-
43
27
  ```
44
28
  [RegisterComponents] START | Register application components ...
45
29
  [RegisterComponents] DONE | Register application components | Took: 12.3456 (ms)
46
30
  ```
47
31
 
48
- With `args` provided:
32
+ ## Functions
49
33
 
50
- ```
51
- [RegisterComponents] START | Register application components... | Args: {"name":"auth"}
52
- [RegisterComponents] DONE | Register application components | Args: {"name":"auth"} | Took: 12.3456 (ms)
53
- ```
34
+ | Function | Signature | What it does |
35
+ |----------|-----------|---------------|
36
+ | `executeWithPerformanceMeasure` | `executeWithPerformanceMeasure<R>(opts: { logger?: ILogger; level?: string; description?: string; args?: any; scope: string; task: Function }): Promise<R>` | Runs `task` (sync or async), logging a `START` line before and a `DONE` line after with the elapsed time. Resolves to whatever `task` returns. |
37
+ | `getPerformanceCheckpoint` | `getPerformanceCheckpoint(): number` | Returns `performance.now()` - a starting timestamp to pass to `getExecutedPerformance`. |
38
+ | `getExecutedPerformance` | `getExecutedPerformance(opts: { from: number; digit?: number }): number` | Elapsed milliseconds since `from`, rounded to `digit` places (default `6`). |
54
39
 
55
- ## Low-Level Utilities
40
+ ## Notes
56
41
 
57
- For more granular measurements, you can use the lower-level functions:
42
+ - **Defaults:** `logger` falls back to `console`, `level` to `'debug'`, `description` to `'Executing'`.
43
+ - **`args`, when provided, are logged as JSON (`%j`)** on both the `START` and `DONE` lines - handy for correlating a specific call's timing.
44
+ - **`task` is wrapped in `Promise.resolve()`**, so a plain synchronous function works exactly like an `async` one.
45
+ - **Prefer the checkpoint pair for granular, multi-point measurements** inside a single function, where wrapping the whole thing in `executeWithPerformanceMeasure` would not isolate the segment you care about.
58
46
 
59
- - **`getPerformanceCheckpoint()`**: Returns a high-resolution timestamp from `performance.now()`, which you can use as a starting point.
60
- - **`getExecutedPerformance(opts)`**: Calculates the elapsed time in milliseconds since a given checkpoint. Rounds to 6 decimal places by default.
61
- - `opts.from` (number): The starting checkpoint from `getPerformanceCheckpoint()`.
62
- - `opts.digit` (number, optional): Number of decimal places for rounding. Defaults to `6`.
47
+ ## See also
63
48
 
64
- ### Example
65
-
66
- ```typescript
67
- import { getPerformanceCheckpoint, getExecutedPerformance } from '@venizia/ignis-helpers';
49
+ - [Utilities Overview](/references/utilities/) - all utility functions
50
+ - [Logger](/extensions/helpers/logger/) - the `ILogger` type accepted by `executeWithPerformanceMeasure`
68
51
 
69
- const start = getPerformanceCheckpoint();
52
+ **Files:**
70
53
 
71
- // ... perform some work
72
-
73
- const duration = getExecutedPerformance({ from: start });
74
- console.log(`The work took ${duration} ms.`);
75
-
76
- // With custom precision
77
- const preciseDuration = getExecutedPerformance({ from: start, digit: 2 });
78
- console.log(`The work took ${preciseDuration} ms.`);
79
- ```
54
+ - [`packages/helpers/src/utilities/performance.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/utilities/performance.utility.ts)
@@ -1,19 +1,15 @@
1
- # Promise Utility
2
-
3
- The Promise utility provides helper functions for working with Promises, particularly for managing concurrency and transforming values.
4
-
5
- ## `executePromiseWithLimit`
1
+ ---
2
+ title: Promise Utility
3
+ description: Concurrency-limited task execution plus small Promise and object-path helpers
4
+ difficulty: beginner
5
+ lastUpdated: 2026-07-16
6
+ ---
6
7
 
7
- This function executes an array of asynchronous tasks concurrently, but with a specified limit on the number of promises running at any given time. This is useful for throttling asynchronous operations to avoid overwhelming a system (e.g., making a large number of concurrent API calls).
8
-
9
- ### `executePromiseWithLimit(opts)`
8
+ # Promise Utility
10
9
 
11
- - `opts` (object):
12
- - `tasks` (Array&lt;() => Promise&lt;T&gt;&gt;): An array of functions that each return a Promise.
13
- - `limit` (number): The maximum number of promises to execute in parallel.
14
- - `onTaskDone` (&lt;R&gt;(opts: { result: R }) => ValueOrPromise&lt;void&gt;, optional): A callback function that is executed whenever a task is completed (specifically, when the concurrency limit is reached and a task finishes to make room).
10
+ Helper functions for working with Promises - bounding concurrency, normalizing thrown values, type-guarding thenables, reading nested object paths, and firing-and-forgetting async work safely.
15
11
 
16
- ### Example
12
+ ## In one example
17
13
 
18
14
  ```typescript
19
15
  import { executePromiseWithLimit, sleep } from '@venizia/ignis-helpers';
@@ -22,67 +18,37 @@ const tasks = [
22
18
  () => sleep(1000).then(() => 'Task 1 done'),
23
19
  () => sleep(500).then(() => 'Task 2 done'),
24
20
  () => sleep(1200).then(() => 'Task 3 done'),
25
- () => sleep(800).then(() => 'Task 4 done'),
26
21
  ];
27
22
 
28
- console.log('Starting tasks with a limit of 2...');
29
-
30
23
  const results = await executePromiseWithLimit({
31
24
  tasks,
32
25
  limit: 2,
33
- onTaskDone: ({ result }) => {
34
- console.log('A task finished:', result);
35
- },
26
+ onTaskDone: ({ result }) => console.log('A task finished:', result),
36
27
  });
37
-
38
- console.log('All tasks finished:', results);
39
28
  ```
40
29
 
41
- ## `toError`
30
+ ## Functions
42
31
 
43
- Normalizes an unknown thrown value into an `Error` instance. Useful in `catch` blocks where the caught value is typed `unknown` and isn't guaranteed to already be an `Error`.
32
+ | Function | Signature | What it does |
33
+ |----------|-----------|---------------|
34
+ | `executePromiseWithLimit` | `executePromiseWithLimit<T>(opts: { tasks: Array<() => Promise<T>>; limit: number; onTaskDone?: <R>(opts: { result: R }) => ValueOrPromise<void> }): Promise<T[]>` | Runs `tasks` with at most `limit` running concurrently. Calls `onTaskDone` each time the limit is hit and a slot frees up. Throws if `limit` is not a positive integer. |
35
+ | `toError` | `toError(error: unknown): Error` | Normalizes a `catch`-block value into an `Error` - passes an existing `Error` through, wraps anything else with `new Error(String(error))`. |
36
+ | `isPromiseLike` | `isPromiseLike<T>(value: T \| PromiseLike<T>): value is PromiseLike<T>` | Type guard: `true` when `value` is non-null and has a callable `.then`. |
37
+ | `getDeepProperty` | `getDeepProperty<T, V>(obj: T, path: string): V` | Reads a dot-separated `path` off `obj`. Throws if any intermediate segment is `null`/`undefined`. |
38
+ | `voidExecution` | `voidExecution(opts: { logger?: ILogger; scope: string; execution: ValueOrPromise<unknown> }): void` | Fire-and-forget: if `execution` is a Promise, routes a rejection to `logger.for(scope).error(...)` (or `console.error` without a logger) instead of an unhandled rejection. Synchronous values pass through untouched. |
44
39
 
45
- ```typescript
46
- import { toError } from '@venizia/ignis-helpers';
40
+ ## Notes
47
41
 
48
- try {
49
- await riskyOperation();
50
- } catch (caught) {
51
- const error = toError(caught);
52
- console.error(error.message);
53
- }
54
- ```
42
+ - **`executePromiseWithLimit` validates `limit` eagerly** - a non-integer or a value below `1` throws immediately, before any task runs.
43
+ - **`onTaskDone` only fires under backpressure.** It runs when the number of in-flight tasks reaches `limit` and `Promise.race` resolves one of them - not after every task.
44
+ - **`voidExecution` exists because `BaseHelper` cannot carry `protected` members** on classes the container instantiates anonymously (TS4094) - it is a standalone function, not a helper method, precisely so factory-built controllers can still use it.
45
+ - **`getDeepProperty` throws, it does not return `undefined`**, on a missing intermediate segment - wrap the call if you need optional-path semantics instead.
55
46
 
56
- ## `isPromiseLike`
47
+ ## See also
57
48
 
58
- A type guard function to check if a given value is a Promise-like object (i.e., it has a `then` method). Checks that the value is non-null, is an object or function, and has a `then` property that is a function.
59
-
60
- ```typescript
61
- import { isPromiseLike } from '@venizia/ignis-helpers';
49
+ - [Utilities Overview](/references/utilities/) - all utility functions
50
+ - [Date Utility](/references/utilities/date) - `sleep()`, used to build the tasks in the example above
62
51
 
63
- const a = Promise.resolve(1);
64
- const b = 2;
52
+ **Files:**
65
53
 
66
- if (isPromiseLike(a)) {
67
- // This will run
68
- }
69
-
70
- if (isPromiseLike(b)) {
71
- // This will not run
72
- }
73
- ```
74
-
75
- ## `getDeepProperty`
76
-
77
- Traverses a dot-separated property path on an object and returns the value. It throws an error if any intermediate part of the path is null or undefined.
78
-
79
- ```typescript
80
- import { getDeepProperty } from '@venizia/ignis-helpers';
81
-
82
- const obj = { a: { b: { c: 'hello' } } };
83
-
84
- const value = getDeepProperty(obj, 'a.b.c'); // => 'hello'
85
-
86
- // Throws: Cannot read property 'x' of undefined
87
- getDeepProperty(obj, 'a.x.y');
88
- ```
54
+ - [`packages/helpers/src/utilities/promise.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/utilities/promise.utility.ts)