@venizia/ignis-docs 0.2.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 (142) 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 +78 -62
  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 +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 +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 +41 -35
  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 -610
  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/models.md +1 -1
  89. package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
  90. package/content/guides/core-concepts/persistent/transactions.md +1 -1
  91. package/content/guides/core-concepts/secrets-vault.md +177 -0
  92. package/content/guides/core-concepts/services.md +1 -1
  93. package/content/guides/migrations/redis-helpers-migration.md +1 -1
  94. package/content/guides/migrations/unified-connectors-migration.md +2 -2
  95. package/content/guides/tutorials/ecommerce-api.md +3 -8
  96. package/content/references/base/application.md +1 -1
  97. package/content/references/base/connectors.md +79 -136
  98. package/content/references/base/datasources-reference.md +599 -0
  99. package/content/references/base/datasources.md +84 -444
  100. package/content/references/base/dependency-injection.md +17 -39
  101. package/content/references/base/filter-system/application-usage.md +69 -121
  102. package/content/references/base/filter-system/array-operators.md +12 -0
  103. package/content/references/base/filter-system/comparison-operators.md +12 -0
  104. package/content/references/base/filter-system/default-filter.md +136 -348
  105. package/content/references/base/filter-system/fields-order-pagination.md +38 -16
  106. package/content/references/base/filter-system/index.md +106 -257
  107. package/content/references/base/filter-system/json-filtering.md +12 -2
  108. package/content/references/base/filter-system/list-operators.md +16 -2
  109. package/content/references/base/filter-system/logical-operators.md +13 -0
  110. package/content/references/base/filter-system/null-operators.md +13 -0
  111. package/content/references/base/filter-system/pattern-matching.md +12 -0
  112. package/content/references/base/filter-system/quick-reference.md +11 -2
  113. package/content/references/base/filter-system/range-operators.md +12 -0
  114. package/content/references/base/filter-system/tips.md +70 -133
  115. package/content/references/base/filter-system/use-cases.md +156 -233
  116. package/content/references/base/middlewares.md +35 -21
  117. package/content/references/base/models-reference.md +886 -0
  118. package/content/references/base/models.md +80 -1452
  119. package/content/references/base/repositories/advanced.md +156 -192
  120. package/content/references/base/repositories/index.md +77 -650
  121. package/content/references/base/repositories/mixins.md +22 -18
  122. package/content/references/base/repositories/relations.md +123 -171
  123. package/content/references/base/repositories/soft-deletable.md +58 -56
  124. package/content/references/base/secrets.md +263 -0
  125. package/content/references/base/services.md +2 -2
  126. package/content/references/configuration/environment-variables.md +48 -4
  127. package/content/references/configuration/index.md +49 -31
  128. package/content/references/quick-reference.md +3 -16
  129. package/content/references/utilities/crypto.md +35 -76
  130. package/content/references/utilities/date.md +33 -73
  131. package/content/references/utilities/index.md +1 -1
  132. package/content/references/utilities/jsx-reference.md +298 -0
  133. package/content/references/utilities/jsx.md +82 -525
  134. package/content/references/utilities/module.md +29 -62
  135. package/content/references/utilities/parse.md +34 -64
  136. package/content/references/utilities/performance.md +33 -58
  137. package/content/references/utilities/promise.md +28 -62
  138. package/content/references/utilities/request.md +57 -218
  139. package/content/references/utilities/schema.md +43 -137
  140. package/content/references/utilities/statuses-reference.md +361 -0
  141. package/content/references/utilities/statuses.md +63 -667
  142. package/package.json +8 -8
@@ -1,46 +1,15 @@
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.
4
-
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/`.
6
-
7
- ## `validateModule`
8
-
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.
10
-
11
- ### Signature
12
-
13
- ```typescript
14
- validateModule(opts: {
15
- scope?: string;
16
- modules: Array<string>;
17
- }): Promise<void>
18
- ```
19
-
20
- **Options**
21
-
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. |
1
+ ---
2
+ title: Module Utility
3
+ description: Pre-flight check that fails fast with an install instruction when an optional peer dependency is missing
4
+ difficulty: beginner
5
+ lastUpdated: 2026-07-16
6
+ ---
26
7
 
27
- ### Error message format
28
-
29
- When a module is missing the thrown error reads:
30
-
31
- ```
32
- [validateModule] <module> is required for <scope>. Please install '<module>'
33
- ```
34
-
35
- If `scope` is omitted:
36
-
37
- ```
38
- [validateModule] <module> is required. Please install '<module>'
39
- ```
8
+ # Module Utility
40
9
 
41
- ### Example - gRPC controller (optional dep guard)
10
+ A pre-flight check for optional peer dependencies. IGNIS helpers and components often depend on packages that are not bundled with the framework (`@connectrpc/connect` for gRPC, `@hono/swagger-ui` for the Swagger component, and so on). Calling `validateModule` before a lazy `import()` throws a clear, actionable error instead of a cryptic "Cannot find module" crash.
42
11
 
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.
12
+ ## In one example
44
13
 
45
14
  ```typescript
46
15
  import { validateModule } from '@venizia/ignis-helpers';
@@ -58,33 +27,31 @@ export class MyGrpcController extends BaseGrpcController {
58
27
  }
59
28
  ```
60
29
 
61
- ### Example - custom helper with multiple optional deps
30
+ ## Functions
62
31
 
63
- When a feature requires several packages, list them all. The first missing one stops the check.
32
+ | Function | Signature | What it does |
33
+ |----------|-----------|---------------|
34
+ | `validateModule` | `validateModule(opts: { scope?: string; modules: Array<string> }): Promise<void>` | Resolves each module in `modules`, in order, via `require.resolve`. Throws an `ApplicationError` on the first one that cannot be found. |
64
35
 
65
- ```typescript
66
- import { validateModule } from '@venizia/ignis-helpers';
67
- import { BaseHelper } from '@venizia/ignis-helpers';
36
+ ## Error message format
68
37
 
69
- export class KafkaQueueHelper extends BaseHelper {
70
- async configure() {
71
- await validateModule({
72
- scope: KafkaQueueHelper.name,
73
- modules: ['kafkajs', 'kafkajs-snappy'],
74
- });
38
+ | `scope` | Message |
39
+ |---------|---------|
40
+ | provided | `[validateModule] <module> is required for <scope>. Please install '<module>'` |
41
+ | omitted | `[validateModule] <module> is required. Please install '<module>'` |
75
42
 
76
- const { Kafka } = await import('kafkajs');
77
- // ... initialise Kafka client
78
- }
79
- }
80
- ```
43
+ ## Notes
44
+
45
+ - **Resolution is rooted at `process.cwd()/node_modules`** via Node's `createRequire`, so peer dependencies installed in the consuming application resolve correctly even though this utility ships inside `packages/helpers/dist/`.
46
+ - **Evaluated in order - first miss wins.** With multiple `modules`, the loop stops at the first unresolved one and throws; later entries are never checked.
47
+ - **`async` for call-site consistency only.** Resolution itself is synchronous (`require.resolve`); the function returns a `Promise<void>` so every call site can `await` it uniformly.
48
+ - **Call it once, at startup - not per request.** Place it in an initialisation hook (`configure`, `binding`, `boot`), before the guarded `import()`.
49
+ - **Recommended pattern:** declare the dependency as `peerDependenciesMeta` with `optional: true` in `package.json`, call `validateModule` at the top of the method that needs it, and pass the feature or class name as `scope` so the thrown message pinpoints the caller.
81
50
 
82
- ## When to use
51
+ ## See also
83
52
 
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:
53
+ - [Utilities Overview](/references/utilities/) - all utility functions
85
54
 
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.
55
+ **Files:**
89
56
 
90
- Avoid calling `validateModule` on every request. Place it in an initialisation hook (`configure`, `binding`, `boot`) that runs once at startup.
57
+ - [`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)