@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,50 @@
1
- # Date Utility
2
-
3
- The Date utility provides a set of functions for date and time manipulation, built on top of the powerful `dayjs` library. It also configures `dayjs` with useful plugins and a default timezone.
1
+ ---
2
+ title: Date Utility
3
+ description: Pre-configured dayjs re-export plus sleep, weekday, timezone, and high-resolution timing helpers
4
+ difficulty: beginner
5
+ lastUpdated: 2026-07-16
6
+ ---
4
7
 
5
- ## `dayjs`
8
+ # Date Utility
6
9
 
7
- The `dayjs` object is re-exported, so you can use it directly for any date and time operations. It is pre-configured with the following plugins: `CustomParseFormat`, `UTC`, `Timezone`, `Weekday`, and `IsoWeek`.
10
+ A pre-configured `dayjs` re-export, plus small standalone helpers for sleeping, weekday math, timezone conversion, and high-resolution timing.
8
11
 
9
- The default timezone is set to `Asia/Ho_Chi_Minh` and can be overridden via the `APP_ENV_APPLICATION_TIMEZONE` environment variable.
12
+ ## In one example
10
13
 
11
14
  ```typescript
12
- import { dayjs } from '@venizia/ignis-helpers';
13
-
14
- // Get the current date and time
15
- const now = dayjs();
16
-
17
- // Format a date
18
- const formatted = now.format('YYYY-MM-DD HH:mm:ss');
19
- ```
15
+ import { dayjs, sleep, getDateTz } from '@venizia/ignis-helpers';
20
16
 
21
- ## `sleep`
17
+ const now = dayjs().format('YYYY-MM-DD HH:mm:ss');
22
18
 
23
- The `sleep` function pauses execution for a specified number of milliseconds.
19
+ await sleep(2000); // pause for 2 seconds
24
20
 
25
- ```typescript
26
- import { sleep } from '@venizia/ignis-helpers';
27
-
28
- async function myAsyncFunction() {
29
- console.log('Start');
30
- await sleep(2000); // Wait for 2 seconds
31
- console.log('End');
32
- }
21
+ const tokyoTime = getDateTz({ date: '2023-10-27T10:00:00Z', timezone: 'Asia/Tokyo' });
33
22
  ```
34
23
 
35
- ## Weekday Functions
36
-
37
- - **`isWeekday(date)`**: Checks if a given date is a weekday (Monday to Friday). Accepts a `string` or `dayjs.Dayjs` instance.
38
- - **`getPreviousWeekday(opts?)`**: Returns the previous weekday from a given date. If no date is provided, defaults to today.
39
- - **`getNextWeekday(opts?)`**: Returns the next weekday from a given date. If no date is provided, defaults to today.
24
+ ## Functions
40
25
 
41
- ```typescript
42
- import { isWeekday, getPreviousWeekday, getNextWeekday } from '@venizia/ignis-helpers';
43
-
44
- const isTodayWeekday = isWeekday('2026-03-15');
26
+ | Function | Signature | What it does |
27
+ |----------|-----------|---------------|
28
+ | `dayjs` | re-exported `dayjs` object | The `dayjs` factory, pre-loaded with plugins - use it exactly like raw `dayjs`. |
29
+ | `sleep` | `sleep(ms: number): Promise<void>` | Resolves after `ms` milliseconds (`setTimeout` wrapped in a Promise). |
30
+ | `isWeekday` | `isWeekday(date: string \| dayjs.Dayjs): boolean` | `true` when `date` falls Monday through Friday (ISO weekday 1-5). |
31
+ | `getPreviousWeekday` | `getPreviousWeekday(opts?: { date?: string \| dayjs.Dayjs }): dayjs.Dayjs` | Walks backward a day at a time from `date` (default: today) until it lands on a weekday. |
32
+ | `getNextWeekday` | `getNextWeekday(opts?: { date?: string \| dayjs.Dayjs }): dayjs.Dayjs` | Walks forward a day at a time from `date` (default: today) until it lands on a weekday. |
33
+ | `getDateTz` | `getDateTz(opts: { date: string; timezone: string; useClientTz?: boolean; timeOffset?: number }): dayjs.Dayjs` | Parses `date` and converts it to `timezone`, optionally shifting by `timeOffset` hours. |
34
+ | `hrTime` | `hrTime(): number` | High-resolution seconds from `process.hrtime()`, rounded to 9 decimal places - for benchmarking. |
45
35
 
46
- const lastBusinessDay = getPreviousWeekday();
47
- const nextBusinessDay = getNextWeekday({ date: '2026-03-13' });
48
- ```
36
+ ## Notes
49
37
 
50
- ## `getDateTz`
38
+ - **Plugins loaded once at module import:** `CustomParseFormat`, `UTC`, `Timezone`, `Weekday`, `IsoWeek`.
39
+ - **Default timezone is `Asia/Ho_Chi_Minh`**, set via `dayjs.tz.setDefault()` at module load. Override with the `APP_ENV_APPLICATION_TIMEZONE` environment variable - it is read once, so changing it at runtime needs a restart.
40
+ - **`getPreviousWeekday` / `getNextWeekday` are day-by-day loops**, not calendar lookups. They call `isWeekday()` after each step, so the worst case (stepping over a weekend) is only 2-3 iterations.
41
+ - **`getDateTz`'s `useClientTz`** defaults to `false` and controls whether `dayjs().tz()` keeps the original wall-clock time or converts it - see the [Day.js Timezone plugin docs](https://day.js.org/docs/en/timezone/timezone) for the exact semantics.
51
42
 
52
- The `getDateTz` function allows you to get a `dayjs` object in a specific timezone, with an optional hour offset.
43
+ ## See also
53
44
 
54
- ### `getDateTz(opts)`
45
+ - [Utilities Overview](/references/utilities/) - all utility functions
46
+ - [Day.js documentation](https://day.js.org/docs/en/installation/installation) - underlying date library
55
47
 
56
- - `opts` (object):
57
- - `date` (string): The date string to parse.
58
- - `timezone` (string): The IANA timezone name.
59
- - `useClientTz` (boolean, optional): Whether to keep the client's timezone. Defaults to `false`.
60
- - `timeOffset` (number, optional): Number of hours to add to the result. Defaults to `0`.
48
+ **Files:**
61
49
 
62
- ```typescript
63
- import { getDateTz } from '@venizia/ignis-helpers';
64
-
65
- const tokyoTime = getDateTz({
66
- date: '2023-10-27T10:00:00Z',
67
- timezone: 'Asia/Tokyo',
68
- });
69
-
70
- // With hour offset
71
- const offsetTime = getDateTz({
72
- date: '2023-10-27T10:00:00Z',
73
- timezone: 'Asia/Tokyo',
74
- timeOffset: 2, // Add 2 hours
75
- });
76
- ```
77
-
78
- ## `hrTime`
79
-
80
- The `hrTime` function returns a high-resolution time measurement in seconds using `process.hrtime()`, useful for performance benchmarking. The result is rounded to 9 decimal places.
81
-
82
- ```typescript
83
- import { hrTime } from '@venizia/ignis-helpers';
84
-
85
- const start = hrTime();
86
- // ... some long-running operation
87
- const end = hrTime();
88
-
89
- console.log(`Operation took ${end - start} seconds.`);
90
- ```
50
+ - [`packages/helpers/src/utilities/date.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/utilities/date.utility.ts)
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: Duration Utility
3
+ description: A unit vocabulary, written-duration parsing, and conversion between units and milliseconds
4
+ difficulty: beginner
5
+ lastUpdated: 2026-08-15
6
+ ---
7
+
8
+ # Duration Utility
9
+
10
+ A duration is `{ unit, value }`. This turns that into milliseconds, reads it out of a written string like `30d`, and converts between units.
11
+
12
+ ## In one example
13
+
14
+ ```typescript
15
+ import { DurationMultipliers, DurationUnits } from '@venizia/ignis-helpers/common';
16
+
17
+ const gracePeriod = { unit: DurationUnits.DAY, value: 30 };
18
+
19
+ DurationMultipliers.toMilliseconds(gracePeriod); // 2_592_000_000
20
+ DurationMultipliers.parseToMilliseconds('30d'); // 2_592_000_000
21
+ DurationMultipliers.convert({ value: 36, from: 'hour', to: 'day' }); // 1.5
22
+ ```
23
+
24
+ Everything here is browser-pure, so it works unchanged in a Worker. Import from `@venizia/ignis-helpers/common`, or from the root barrel if you already depend on it.
25
+
26
+ ## Units
27
+
28
+ | Constant | Value | Milliseconds |
29
+ |---|---|---|
30
+ | `DurationUnits.MILLISECOND` | `'millisecond'` | 1 |
31
+ | `DurationUnits.SECOND` | `'second'` | 1 000 |
32
+ | `DurationUnits.MINUTE` | `'minute'` | 60 000 |
33
+ | `DurationUnits.HOUR` | `'hour'` | 3 600 000 |
34
+ | `DurationUnits.DAY` | `'day'` | 86 400 000 |
35
+ | `DurationUnits.WEEK` | `'week'` | 604 800 000 |
36
+ | `DurationUnits.MONTH` | `'month'` | 2 592 000 000 |
37
+ | `DurationUnits.YEAR` | `'year'` | 31 536 000 000 |
38
+
39
+ `TDurationUnit` is the union of those eight values. `IDuration` is `{ unit: TDurationUnit; value: number }`.
40
+
41
+ ## Functions
42
+
43
+ | Function | Signature | What it does |
44
+ |---|---|---|
45
+ | `DurationUnits.isValid` | `isValid(input: string): input is TDurationUnit` | `true` when `input` is one of the eight canonical names. |
46
+ | `DurationAliases.resolve` | `resolve(input: string): TDurationUnit \| null` | Reads a written unit - `'d'`, `'days'`, `'DAY'` - into its canonical name. |
47
+ | `DurationMultipliers.toMilliseconds` | `toMilliseconds(opts: IDuration \| null): number \| null` | Converts a duration to milliseconds, rounded. |
48
+ | `DurationMultipliers.fromMilliseconds` | `fromMilliseconds(opts: { milliseconds: number; unit: TDurationUnit }): number \| null` | The inverse. Fractional, not rounded. |
49
+ | `DurationMultipliers.convert` | `convert(opts: { value: number; from: TDurationUnit; to: TDurationUnit }): number \| null` | Converts between two units. Fractional. |
50
+ | `DurationMultipliers.parse` | `parse(input: string): IDuration \| null` | Reads `'30d'`, `'1500 ms'`, `'2 hours'` into an `IDuration`. |
51
+ | `DurationMultipliers.parseToMilliseconds` | `parseToMilliseconds(input: string): number \| null` | `parse` followed by `toMilliseconds`. |
52
+
53
+ ## A month is 30 days and a year is 365
54
+
55
+ These size a **window** - a grace period, a cache TTL, a near-expiry horizon. They are not calendar arithmetic.
56
+
57
+ Adding `MONTH` to 31 January lands on 2 March in a leap year and 3 March otherwise. If you need a real calendar date, use [the date utility](./date.md) and let `dayjs` handle months.
58
+
59
+ ## Every function answers `null`, never throws
60
+
61
+ An unknown unit, a `NaN` value, an unreadable string - all return `null`. A caller that wants an error raises its own, with its own context:
62
+
63
+ ```typescript
64
+ const ttlMs = DurationMultipliers.parseToMilliseconds(config.cacheTtl);
65
+
66
+ if (ttlMs === null) {
67
+ throw getError({ message: `[cache] Unreadable TTL: '${config.cacheTtl}'` });
68
+ }
69
+ ```
70
+
71
+ Zero is a real duration, not an absent one - `{ unit: 'day', value: 0 }` converts to `0`. A negative value converts too, so a caller deciding what a negative window means keeps that decision.
72
+
73
+ ## Writing a duration
74
+
75
+ `parse` accepts one number, an optional space, and one unit: `30d`, `1.5h`, `-2 Hours`, `1500 ms`. Anything it cannot read whole is `null` - there is no partial credit, so `'30d extra'` fails rather than silently meaning 30 days.
76
+
77
+ Accepted spellings are the member names of `DurationAliases`, lower-cased: short (`d`), abbreviated (`wk`), singular (`day`) and plural (`days`).
78
+
79
+ **`m` is minute and `mo` is month.** That is the choice every duration library makes, and the one ambiguity worth checking before you write a config value. There is no single-letter month.
80
+
81
+ ## Notes
82
+
83
+ - **The fast path allocates nothing.** `resolve` tries your input as given before normalising it, so a canonical `'day'` costs about 2ns while a messy `' Days '` pays the ~80ns that trimming and upper-casing costs. Pass canonical spellings in a loop.
84
+ - **`toMilliseconds` rounds; `fromMilliseconds` and `convert` do not.** Rounding on the way out would silently lose a 36-hour window asked for in days.
85
+ - **The alias table is derived from `DurationAliases`**, not hand-listed beside it, so a new spelling is one member and the two cannot drift.
@@ -8,12 +8,14 @@ Pure, standalone functions providing common, reusable logic for the IGNIS framew
8
8
  |---------|---------|---------|---------------|
9
9
  | **Crypto** | `ignis-helpers` | Cryptographic hashing | `hash()` |
10
10
  | **Date** | `ignis-helpers` | Date/time manipulation | `dayjs`, `sleep()`, `isWeekday()`, `getDateTz()`, `hrTime()` |
11
+ | **Duration** | `ignis-helpers` | Duration units and conversion | `DurationUnits`, `DurationMultipliers.toMilliseconds()`, `.parseToMilliseconds()` |
11
12
  | **JSX** | `ignis` | HTML/JSX responses | `htmlContent()`, `htmlResponse()` |
12
- | **Module** | `ignis-helpers` | Module validation | `validateModule()` |
13
+ | **Module** | `ignis-helpers` | Optional peer loading | `ModuleUtility` |
13
14
  | **Parse** | `ignis-helpers` | Data type conversion | `int()`, `float()`, `toBoolean()`, `toCamel()` |
14
15
  | **Performance** | `ignis-helpers` | Execution timing | `executeWithPerformanceMeasure()`, `getPerformanceCheckpoint()` |
15
16
  | **Promise** | `ignis-helpers` | Promise helpers | `executePromiseWithLimit()`, `isPromiseLike()`, `getDeepProperty()` |
16
17
  | **Request** | `ignis-helpers` | HTTP utilities | `parseMultipartBody()`, `sanitizeFilename()`, `createContentDispositionHeader()` |
18
+ | **Retry** | `ignis-helpers` | Backoff-driven retries | `executeWithRetry()`, `executeWithRetryUntil()`, `computeBackoffDelayMs()` |
17
19
  | **Schema** | `ignis` | Zod schema helpers | `jsonContent()`, `jsonResponse()`, `requiredString()`, `idParamsSchema()` |
18
20
  | **Statuses** | `ignis` | Status code constants | `Statuses`, `CommonStatuses`, `UserStatuses`, `RoleStatuses` |
19
21
 
@@ -22,13 +24,14 @@ Pure, standalone functions providing common, reusable logic for the IGNIS framew
22
24
  ### Data Processing
23
25
 
24
26
  - [**Crypto**](./crypto.md) - Simple, stateless cryptographic functions for hashing (SHA256 HMAC, MD5)
25
- - [**Parse**](./parse.md) - Functions for parsing and converting data types safely (integers, floats, booleans, camelCase, locale-aware numbers, array-to-map)
27
+ - [**Parse**](./parse.md) - Functions for parsing and converting data types safely (integers, floats, booleans, camelCase, array-to-map)
26
28
  - [**Schema**](./schema.md) - Helpers for creating Zod schemas for OpenAPI request/response validation
27
29
  - [**Statuses**](./statuses.md) - Standardized status code constants for entity lifecycle management
28
30
 
29
31
  ### Time & Performance
30
32
 
31
33
  - [**Date**](./date.md) - Date and time manipulation functions built on `dayjs` with timezone support
34
+ - [**Duration**](./duration.md) - A unit vocabulary, written-duration parsing, and conversion between units and milliseconds
32
35
  - [**Performance**](./performance.md) - Utilities for measuring code execution time and performance profiling
33
36
 
34
37
  ### Async & HTTP
@@ -36,6 +39,7 @@ Pure, standalone functions providing common, reusable logic for the IGNIS framew
36
39
  - [**JSX**](./jsx.md) - HTML and JSX response utilities for server-side rendering and OpenAPI documentation
37
40
  - [**Promise**](./promise.md) - Helper functions for working with Promises including concurrency limiting and value transformation
38
41
  - [**Request**](./request.md) - HTTP request utilities for parsing multipart form data and creating secure Content-Disposition headers
42
+ - [**Retry**](./retry.md) - Backoff-driven retry helpers - error-triggered (`executeWithRetry`) and predicate-driven (`executeWithRetryUntil`)
39
43
 
40
44
  ### Runtime
41
45
 
@@ -0,0 +1,298 @@
1
+ ---
2
+ title: JSX/HTML Utility - Full Reference
3
+ description: Complete reference for the JSX/HTML response helpers, defineJSXRoute, and Hono JSX component patterns
4
+ difficulty: beginner
5
+ ---
6
+
7
+ # JSX/HTML Utility - Full Reference
8
+
9
+ Exhaustive reference for `htmlContent()`, `htmlResponse()`, and `BaseRestController.defineJSXRoute()`. For a readable introduction and the common tasks, start with the [JSX/HTML overview](/references/utilities/jsx).
10
+
11
+ **Files:**
12
+
13
+ - [`packages/core-server/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/utilities/jsx.utility.ts) - `htmlContent`, `htmlResponse`
14
+ - [`packages/core-server/src/base/controllers/rest/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/controllers/rest/base.ts) - `BaseRestController.defineJSXRoute`
15
+ - [`packages/core-server/src/base/controllers/rest/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/controllers/rest/abstract.ts) - `AbstractRestController.getJSXRouteConfigs`
16
+ - [`packages/helpers/src/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/common/types.ts) - `FC`, `PropsWithChildren`, `Child` (re-exported from `hono/jsx`)
17
+
18
+ ## `htmlContent()`
19
+
20
+ Creates a standard OpenAPI content object for `text/html` responses.
21
+
22
+ `Source ->` [`packages/core-server/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/utilities/jsx.utility.ts)
23
+
24
+ ```typescript
25
+ const htmlContent = (opts: { description: string; required?: boolean }) => ({
26
+ description: opts.description,
27
+ content: {
28
+ 'text/html': {
29
+ schema: z.string().openapi({
30
+ description: 'HTML content',
31
+ example: '<!DOCTYPE html><html><head><title>Page</title></head><body>...</body></html>',
32
+ }),
33
+ },
34
+ },
35
+ required: opts.required ?? false,
36
+ });
37
+ ```
38
+
39
+ ### Parameters
40
+
41
+ | Parameter | Type | Required | Default | Description |
42
+ |-----------|------|----------|---------|-------------|
43
+ | `description` | `string` | Yes | - | Description of the HTML content, shown in the generated OpenAPI document |
44
+ | `required` | `boolean` | No | `false` | Whether the content is required |
45
+
46
+ ### Returns
47
+
48
+ An OpenAPI content configuration object: `description`, `content['text/html'].schema` (a `z.string()`), and `required`.
49
+
50
+ ## `htmlResponse()`
51
+
52
+ Creates a standard OpenAPI response object for HTML endpoints. It pairs a success (`200`) HTML response with a JSON error response for `4xx | 5xx` status codes using `ErrorSchema`.
53
+
54
+ `Source ->` [`packages/core-server/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/utilities/jsx.utility.ts)
55
+
56
+ ```typescript
57
+ const htmlResponse = (opts: { description: string; required?: boolean }) => ({
58
+ [HTTP.ResultCodes.RS_2.Ok]: htmlContent({ description: opts.description, required: opts.required }),
59
+ ['4xx | 5xx']: {
60
+ description: 'Error Response',
61
+ content: { 'application/json': { schema: ErrorSchema } },
62
+ },
63
+ });
64
+ ```
65
+
66
+ ### Parameters
67
+
68
+ | Parameter | Type | Required | Default | Description |
69
+ |-----------|------|----------|---------|-------------|
70
+ | `description` | `string` | Yes | - | Description of the successful HTML response |
71
+ | `required` | `boolean` | No | `false` | Whether the content is required |
72
+
73
+ ### Returns
74
+
75
+ A responses object: `200` (via `htmlContent()`) plus `4xx | 5xx` (JSON `ErrorSchema`).
76
+
77
+ ```typescript
78
+ import { htmlResponse } from '@venizia/ignis';
79
+
80
+ this.defineRoute({
81
+ configs: {
82
+ path: '/dashboard',
83
+ method: 'get',
84
+ responses: htmlResponse({ description: 'Dashboard HTML page' }),
85
+ },
86
+ handler: c => c.html(<h1>Dashboard</h1>),
87
+ });
88
+ ```
89
+
90
+ ## `BaseRestController.defineJSXRoute()`
91
+
92
+ Defines and registers a JSX/HTML route in a single call - the JSX counterpart of `defineRoute()`.
93
+
94
+ `Source ->` [`packages/core-server/src/base/controllers/rest/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/controllers/rest/base.ts)
95
+
96
+ ```typescript
97
+ defineJSXRoute<RouteConfig extends IAuthRouteConfig, ResponseType = unknown>(opts: {
98
+ configs: RouteConfig;
99
+ handler: TRouteHandler<ResponseType, RouteEnv>;
100
+ hook?: Hook<any, RouteEnv, string, ValueOrPromise<any>>;
101
+ }): IDefineRouteOptions<RouteConfig, RouteEnv, RouteSchema, BasePath>
102
+ ```
103
+
104
+ | Parameter | Type | Required | Description |
105
+ |-----------|------|----------|-------------|
106
+ | `configs` | `RouteConfig` (extends `IAuthRouteConfig`) | Yes | `path`, `method`, `responses`, plus the same `authenticate`/`authorize`/`request`/`middleware` fields `defineRoute` accepts |
107
+ | `handler` | `TRouteHandler<ResponseType, RouteEnv>` | Yes | Receives the route context (`TRouteContext`); return `c.html(<Component />)` |
108
+ | `hook` | `Hook<...>` | No | Same validation hook `defineRoute` accepts |
109
+
110
+ ### Behavior
111
+
112
+ `defineJSXRoute` is `defineRoute` with one difference: it builds the route configuration through `getJSXRouteConfigs` instead of `getRouteConfigs`.
113
+
114
+ `Source ->` [`packages/core-server/src/base/controllers/rest/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/controllers/rest/abstract.ts)
115
+
116
+ ```typescript
117
+ getJSXRouteConfigs<RouteConfig extends IAuthRouteConfig>(opts: { configs: RouteConfig }) {
118
+ const { restConfig, security, mws } = this.buildRouteMiddlewares(opts);
119
+ const { responses, tags = [] } = restConfig;
120
+
121
+ return createRoute<string, RouteConfig>(
122
+ Object.assign({}, restConfig, {
123
+ middleware: mws,
124
+ responses: Object.assign({}, htmlResponse({ description: 'HTML page' }), responses),
125
+ tags: [...tags, this.scope],
126
+ security,
127
+ }) as any,
128
+ );
129
+ }
130
+ ```
131
+
132
+ - **Default response merged in first.** `htmlResponse({ description: 'HTML page' })` is the base object. Your own `responses` is merged over it with `Object.assign`, so any status code you declare (typically `200`) overrides the default entry with the same key.
133
+ - **Everything else matches `defineRoute`.** Auth middleware, tags (`this.scope` is always appended), and OpenAPI security are built the same way as JSON routes via `buildRouteMiddlewares`.
134
+ - **Handler contract is unchanged.** The handler still returns whatever `c.html(...)` produces (a `Response`). `defineJSXRoute` only changes how the route's OpenAPI shape is computed, not how the handler runs.
135
+
136
+ ## JSX setup
137
+
138
+ ### `tsconfig.json`
139
+
140
+ `.tsx` files compile against Hono's JSX runtime, not React's:
141
+
142
+ ```json
143
+ {
144
+ "compilerOptions": {
145
+ "jsx": "react-jsx",
146
+ "jsxImportSource": "hono/jsx"
147
+ }
148
+ }
149
+ ```
150
+
151
+ Verified in [`packages/core-server/tsconfig.json`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/tsconfig.json) and the JSX example app's [`examples/rpc-api-server/tsconfig.json`](https://github.com/VENIZIA-AI/ignis/blob/main/examples/rpc-api-server/tsconfig.json).
152
+
153
+ ### Component types
154
+
155
+ `FC`, `PropsWithChildren`, and `Child` are re-exported from `@venizia/ignis-helpers` (sourced from `hono/jsx`) - import them from there rather than reaching into `hono/jsx` directly.
156
+
157
+ `Source ->` [`packages/helpers/src/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/common/types.ts)
158
+
159
+ ```typescript
160
+ export type { Child, FC, PropsWithChildren } from 'hono/jsx';
161
+ ```
162
+
163
+ ### No separate renderer
164
+
165
+ IGNIS registers no `jsxRenderer` middleware and no template engine. A handler builds a JSX tree and calls Hono's own `c.html()` on it - that call is what triggers rendering to an HTML string.
166
+
167
+ ## Component patterns
168
+
169
+ ### Layout composition
170
+
171
+ A layout component takes `children` (typed via `PropsWithChildren`) and wraps them in the surrounding document shell. Page components render into a layout the same way any JSX component nests another.
172
+
173
+ ```tsx
174
+ import type { FC, PropsWithChildren } from '@venizia/ignis-helpers';
175
+
176
+ interface MainLayoutProps {
177
+ title: string;
178
+ description?: string;
179
+ }
180
+
181
+ export const MainLayout: FC<PropsWithChildren<MainLayoutProps>> = ({ title, description, children }) => (
182
+ <html lang="en">
183
+ <head>
184
+ <meta charSet="UTF-8" />
185
+ <title>{title}</title>
186
+ {description && <meta name="description" content={description} />}
187
+ </head>
188
+ <body>
189
+ <main>{children}</main>
190
+ </body>
191
+ </html>
192
+ );
193
+
194
+ interface HomePageProps {
195
+ timestamp?: string;
196
+ }
197
+
198
+ export const HomePage: FC<HomePageProps> = ({ timestamp }) => (
199
+ <MainLayout title="Home" description="Welcome to IGNIS">
200
+ <h1>Welcome to IGNIS!</h1>
201
+ {timestamp && <p>Page rendered at: {timestamp}</p>}
202
+ </MainLayout>
203
+ );
204
+ ```
205
+
206
+ ### Wiring pages into a controller
207
+
208
+ ```tsx
209
+ import { BaseRestController, controller, htmlContent, type IControllerOptions, type ValueOrPromise } from '@venizia/ignis';
210
+ import { HTTP } from '@venizia/ignis-helpers';
211
+ import { HomePage } from '@/views/pages/home.page';
212
+
213
+ @controller({ path: '/' })
214
+ export class ViewController extends BaseRestController {
215
+ constructor(opts: IControllerOptions) {
216
+ super({ ...opts, scope: ViewController.name, path: '/' });
217
+ }
218
+
219
+ override binding(): ValueOrPromise<void> {
220
+ this.defineJSXRoute({
221
+ configs: {
222
+ path: '/',
223
+ method: 'get',
224
+ description: 'Home page rendered with JSX',
225
+ tags: ['Views'],
226
+ responses: {
227
+ [HTTP.ResultCodes.RS_2.Ok]: htmlContent({ description: 'Home page HTML' }),
228
+ },
229
+ },
230
+ handler: c => {
231
+ const timestamp = new Date().toISOString();
232
+ return c.html(<HomePage timestamp={timestamp} />);
233
+ },
234
+ });
235
+ }
236
+ }
237
+ ```
238
+
239
+ ### Raw HTML with `dangerouslySetInnerHTML`
240
+
241
+ Hono JSX's intrinsic elements accept a `dangerouslySetInnerHTML` prop - an object with an `__html` string - matching React's escape hatch. Use it only for HTML you already trust (a stored template, sanitized markdown output) - never for unsanitized user input.
242
+
243
+ ```tsx
244
+ async previewTemplate(c: TRouteContext) {
245
+ const { templateId } = c.req.valid<{ templateId: string }>('param');
246
+ const template = await this.emailService.getTemplate(templateId);
247
+
248
+ return c.html(
249
+ <html>
250
+ <head>
251
+ <title>Email Preview: {template.subject}</title>
252
+ </head>
253
+ <body>
254
+ <div dangerouslySetInnerHTML={{ __html: template.html }} />
255
+ </body>
256
+ </html>,
257
+ );
258
+ }
259
+ ```
260
+
261
+ ## Comparison with JSON utilities
262
+
263
+ ### `htmlContent` vs `jsonContent`
264
+
265
+ | Aspect | `htmlContent()` | `jsonContent()` |
266
+ |--------|------------------|-------------------|
267
+ | Content type | `text/html` | `application/json` |
268
+ | Schema | `z.string()` | Caller-supplied Zod schema |
269
+ | Use case | HTML pages, JSX rendering | API responses, structured data |
270
+
271
+ ### `htmlResponse` vs `jsonResponse`
272
+
273
+ | Aspect | `htmlResponse()` | `jsonResponse()` |
274
+ |--------|---------------------|----------------------|
275
+ | Success type | `text/html` (`200`) | `application/json` (`200`) |
276
+ | Error type | `application/json` (`4xx \| 5xx`) | `application/json` (`4xx \| 5xx`) |
277
+ | Use case | Server-rendered web pages | REST APIs |
278
+
279
+ See [Schema Utility](./schema.md) for `jsonContent`/`jsonResponse`.
280
+
281
+ ## Route definition choices
282
+
283
+ `defineJSXRoute` is the recommended way to register a JSX route because it fills in a default HTML `200` response automatically. Two equivalent alternatives exist when you need more control:
284
+
285
+ | Approach | When to use |
286
+ |----------|-------------|
287
+ | `this.defineJSXRoute({ configs, handler })` | Default choice - HTML response shape is inferred, override `responses[200]` only if you need a custom description |
288
+ | `this.defineRoute({ configs: { responses: htmlResponse({ description }) }, handler })` | You want the full `responses` object built explicitly via `htmlResponse()`, without relying on the JSX default merge |
289
+ | `this.bindRoute({ configs }).to({ handler })` | Fluent two-step registration, same `configs` shape as either of the above |
290
+
291
+ Authentication and authorization on a JSX route use the same `configs.authenticate` / `configs.authorize` fields as JSON routes - see [Controllers](../base/controllers.md).
292
+
293
+ ## See also
294
+
295
+ - [JSX/HTML overview](/references/utilities/jsx) - introduction and common tasks
296
+ - [Schema Utility](./schema.md) - `jsonContent`, `jsonResponse`, and the wider response-helper family
297
+ - [Controllers](../base/controllers.md) - `defineRoute`, `bindRoute`, route configuration, authentication
298
+ - **External:** [Hono JSX Documentation](https://hono.dev/docs/guides/jsx)