@venizia/ignis-docs 0.2.1-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 (145) hide show
  1. package/content/best-practices/architectural-patterns.md +3 -3
  2. package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
  3. package/content/best-practices/contribution-workflow.md +2 -2
  4. package/content/best-practices/error-handling.md +94 -89
  5. package/content/best-practices/security-guidelines.md +5 -5
  6. package/content/extensions/components/api-reference.md +22 -21
  7. package/content/extensions/components/authentication/api.md +64 -28
  8. package/content/extensions/components/authentication/errors.md +19 -5
  9. package/content/extensions/components/authentication/index.md +19 -18
  10. package/content/extensions/components/authentication/usage.md +55 -30
  11. package/content/extensions/components/authorization/api.md +351 -84
  12. package/content/extensions/components/authorization/errors.md +51 -17
  13. package/content/extensions/components/authorization/getting-started.md +227 -0
  14. package/content/extensions/components/authorization/index.md +24 -16
  15. package/content/extensions/components/authorization/usage.md +45 -21
  16. package/content/extensions/components/health-check.md +15 -9
  17. package/content/extensions/components/index.md +24 -90
  18. package/content/extensions/components/mail/api.md +105 -54
  19. package/content/extensions/components/mail/errors.md +12 -10
  20. package/content/extensions/components/mail/index.md +32 -13
  21. package/content/extensions/components/mail/usage.md +26 -18
  22. package/content/extensions/components/request-tracker.md +18 -14
  23. package/content/extensions/components/socket-io/api.md +377 -882
  24. package/content/extensions/components/socket-io/errors.md +49 -51
  25. package/content/extensions/components/socket-io/index.md +72 -88
  26. package/content/extensions/components/socket-io/usage.md +107 -117
  27. package/content/extensions/components/static-asset/api.md +83 -31
  28. package/content/extensions/components/static-asset/errors.md +18 -7
  29. package/content/extensions/components/static-asset/index.md +18 -11
  30. package/content/extensions/components/static-asset/usage.md +11 -6
  31. package/content/extensions/components/template/index.md +3 -3
  32. package/content/extensions/components/websocket/api.md +58 -27
  33. package/content/extensions/components/websocket/errors.md +3 -3
  34. package/content/extensions/components/websocket/index.md +8 -7
  35. package/content/extensions/components/websocket/usage.md +21 -8
  36. package/content/extensions/helpers/cron/index.md +8 -7
  37. package/content/extensions/helpers/crypto/index.md +16 -8
  38. package/content/extensions/helpers/crypto/reference.md +96 -24
  39. package/content/extensions/helpers/env/index.md +14 -10
  40. package/content/extensions/helpers/error/index.md +99 -23
  41. package/content/extensions/helpers/index.md +61 -47
  42. package/content/extensions/helpers/inversion/index.md +23 -6
  43. package/content/extensions/helpers/inversion/reference.md +30 -22
  44. package/content/extensions/helpers/kafka/admin.md +3 -2
  45. package/content/extensions/helpers/kafka/compile-binary.md +69 -44
  46. package/content/extensions/helpers/kafka/consumer.md +24 -21
  47. package/content/extensions/helpers/kafka/examples.md +22 -234
  48. package/content/extensions/helpers/kafka/index.md +30 -62
  49. package/content/extensions/helpers/kafka/producer.md +31 -26
  50. package/content/extensions/helpers/kafka/schema-registry.md +19 -14
  51. package/content/extensions/helpers/logger/hf-logger.md +49 -22
  52. package/content/extensions/helpers/logger/index.md +37 -12
  53. package/content/extensions/helpers/logger/pino.md +31 -11
  54. package/content/extensions/helpers/logger/reference.md +243 -52
  55. package/content/extensions/helpers/network/api.md +65 -30
  56. package/content/extensions/helpers/network/index.md +32 -11
  57. package/content/extensions/helpers/queue/index.md +17 -6
  58. package/content/extensions/helpers/queue/reference.md +52 -25
  59. package/content/extensions/helpers/redis/index.md +29 -11
  60. package/content/extensions/helpers/redis/reference.md +85 -28
  61. package/content/extensions/helpers/secrets/index.md +82 -12
  62. package/content/extensions/helpers/socket-io/api.md +40 -21
  63. package/content/extensions/helpers/socket-io/index.md +26 -10
  64. package/content/extensions/helpers/storage/api.md +42 -24
  65. package/content/extensions/helpers/storage/index.md +10 -7
  66. package/content/extensions/helpers/types/index.md +20 -7
  67. package/content/extensions/helpers/types/reference.md +53 -14
  68. package/content/extensions/helpers/uid/index.md +166 -10
  69. package/content/extensions/helpers/websocket/api.md +52 -13
  70. package/content/extensions/helpers/websocket/index.md +7 -4
  71. package/content/extensions/helpers/worker-thread/index.md +9 -5
  72. package/content/extensions/helpers/worker-thread/reference.md +20 -20
  73. package/content/extensions/index.md +38 -39
  74. package/content/extensions/src-details/mcp-server.md +96 -548
  75. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  76. package/content/guides/core-concepts/persistent/index.md +5 -1
  77. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  78. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  79. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  80. package/content/guides/core-concepts/persistent/search-typesense.md +26 -14
  81. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  82. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  83. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  84. package/content/guides/get-started/philosophy.md +135 -670
  85. package/content/guides/get-started/setup.md +53 -74
  86. package/content/guides/migrations/redis-helpers-migration.md +4 -3
  87. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  88. package/content/guides/migrations/unified-connectors-migration.md +7 -6
  89. package/content/guides/tutorials/realtime-chat.md +1 -1
  90. package/content/references/base/application.md +63 -21
  91. package/content/references/base/components.md +3 -3
  92. package/content/references/base/connectors.md +14 -14
  93. package/content/references/base/controllers.md +12 -12
  94. package/content/references/base/datasources-reference.md +32 -31
  95. package/content/references/base/datasources.md +6 -6
  96. package/content/references/base/dependency-injection.md +12 -11
  97. package/content/references/base/filter-system/application-usage.md +54 -30
  98. package/content/references/base/filter-system/array-operators.md +24 -46
  99. package/content/references/base/filter-system/comparison-operators.md +47 -67
  100. package/content/references/base/filter-system/default-filter.md +59 -53
  101. package/content/references/base/filter-system/fields-order-pagination.md +92 -146
  102. package/content/references/base/filter-system/index.md +25 -13
  103. package/content/references/base/filter-system/json-filtering.md +45 -184
  104. package/content/references/base/filter-system/list-operators.md +23 -53
  105. package/content/references/base/filter-system/logical-operators.md +63 -121
  106. package/content/references/base/filter-system/null-operators.md +34 -104
  107. package/content/references/base/filter-system/pattern-matching.md +40 -55
  108. package/content/references/base/filter-system/quick-reference.md +86 -198
  109. package/content/references/base/filter-system/range-operators.md +18 -46
  110. package/content/references/base/filter-system/tips.md +6 -6
  111. package/content/references/base/filter-system/use-cases.md +33 -15
  112. package/content/references/base/grpc-controllers.md +53 -17
  113. package/content/references/base/index.md +5 -3
  114. package/content/references/base/middlewares.md +11 -10
  115. package/content/references/base/models-reference.md +17 -17
  116. package/content/references/base/models.md +4 -3
  117. package/content/references/base/providers.md +8 -8
  118. package/content/references/base/repositories/advanced.md +224 -326
  119. package/content/references/base/repositories/index.md +19 -6
  120. package/content/references/base/repositories/mixins.md +5 -5
  121. package/content/references/base/repositories/relations.md +160 -293
  122. package/content/references/base/repositories/soft-deletable.md +16 -6
  123. package/content/references/base/secrets.md +17 -13
  124. package/content/references/base/services.md +6 -4
  125. package/content/references/configuration/environment-variables.md +31 -23
  126. package/content/references/configuration/index.md +6 -4
  127. package/content/references/index.md +1 -1
  128. package/content/references/utilities/duration.md +85 -0
  129. package/content/references/utilities/index.md +5 -1
  130. package/content/references/utilities/jsx-reference.md +11 -11
  131. package/content/references/utilities/jsx.md +2 -2
  132. package/content/references/utilities/module.md +78 -25
  133. package/content/references/utilities/request.md +2 -1
  134. package/content/references/utilities/retry.md +139 -0
  135. package/content/references/utilities/schema.md +2 -2
  136. package/content/references/utilities/statuses-reference.md +4 -4
  137. package/content/references/utilities/statuses.md +5 -5
  138. package/dist/mcp-server/index.js +0 -0
  139. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  140. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  141. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  142. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  143. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  144. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  145. package/package.json +17 -16
@@ -6,12 +6,12 @@ difficulty: advanced
6
6
 
7
7
  # Deep Dive: Secrets & Vault
8
8
 
9
- Technical reference for the `Secrets` provider family - how IGNIS loads configuration and credentials from a vault instead of reading `process.env` directly, hydrates static secrets at boot, and rotates dynamic database credentials into a live connection pool without a restart.
9
+ Technical reference for the `Secrets` provider family. It covers how IGNIS loads configuration and credentials from a vault instead of reading `process.env` directly, hydrates static secrets at boot, and rotates dynamic database credentials into a live connection pool without a restart.
10
10
 
11
11
  > [!IMPORTANT] Dormant by default
12
12
  > An application that does not override `registerSecrets()` gets the `system-envs` provider, which reads `process.env` exactly as before. The whole subsystem is additive - existing apps behave identically until they opt in.
13
13
 
14
- **Files:** `packages/helpers/src/modules/secrets/*.ts` (provider family) and `packages/core/src/base/applications/base.ts` (`hydrateSecrets()` lifecycle, DI binding, rotation wiring)
14
+ **Files:** `packages/helpers/src/modules/secrets/*.ts` (provider family) and `packages/core-server/src/base/applications/base.ts` (`hydrateSecrets()` lifecycle, DI binding, rotation wiring)
15
15
 
16
16
  ## Quick Reference
17
17
 
@@ -45,7 +45,7 @@ AbstractSecretsHelper (BaseHelper; TTL cache, lease registry, renewal scheduler,
45
45
  └── DotenvVaultHelper // 'dotenv-vault' - encrypted .env.vault, static only.
46
46
  ```
47
47
 
48
- The renewal scheduler, TTL cache, lease registry, and `onRotate` dispatch all live in `AbstractSecretsHelper`. A concrete provider implements only the raw calls against its backend (`fetchRaw`, `renewRaw`, `revokeRaw`), which is why the two static providers are thin and why only HashiCorp exercises the lease machinery.
48
+ The renewal scheduler, TTL cache, lease registry, and `onRotate` dispatch all live in `AbstractSecretsHelper`. A concrete provider implements only the raw calls against its backend (`fetchRaw`, `renewRaw`, `revokeRaw`). That's why the two static providers are thin, and why only HashiCorp exercises the lease machinery.
49
49
 
50
50
  ## `ISecretsHelper` Interface
51
51
 
@@ -92,7 +92,7 @@ interface ISecretRotatable {
92
92
  ```
93
93
 
94
94
  > [!NOTE] Static vs dynamic secrets
95
- > `get()` / `getBundle()` return static values (KV, env) and are TTL-cached. `lease()` returns a dynamic, lease-bearing secret and is supported only by `HashiCorpVaultHelper`; the static providers throw an explicit NotSupported error rather than returning a fake lease.
95
+ > `get()` / `getBundle()` return static values (KV, env) and are TTL-cached. `lease()` returns a dynamic, lease-bearing secret and is supported only by `HashiCorpVaultHelper`. The static providers throw an explicit NotSupported error instead of returning a fake lease.
96
96
 
97
97
  ## Registration
98
98
 
@@ -121,7 +121,7 @@ interface ISecretsRegistration {
121
121
  ### `registerSecrets()` default
122
122
 
123
123
  ```typescript
124
- // packages/core/src/base/applications/base.ts
124
+ // packages/core-server/src/base/applications/base.ts
125
125
  registerSecrets(): ValueOrPromise<ISecretsRegistration> {
126
126
  return { provider: SecretProviders.SYSTEM_ENVS };
127
127
  }
@@ -176,7 +176,7 @@ validateEnvs → staticConfigure → preConfigure
176
176
  3. Binds the live provider at `CoreBindings.APPLICATION_CONFIG` (`@app/config`) as a singleton.
177
177
  4. Registers a post-stop hook (`secrets.shutdown`) so `provider.shutdown()` runs on teardown, revoking outstanding leases.
178
178
 
179
- `wireSecretRotatables()` runs after datasources are registered: for each `lease` entry it resolves the datasource at `entry.key` and, if the instance implements `onSecretRotated`, calls `provider.registerRotatable({ key, target })`. A datasource that does not implement the hook is skipped.
179
+ `wireSecretRotatables()` runs after datasources are registered. For each `lease` entry it resolves the datasource at `entry.key` and, if the instance implements `onSecretRotated`, calls `provider.registerRotatable({ key, target })`. A datasource that does not implement the hook is skipped.
180
180
 
181
181
  > [!TIP] Why a lifecycle phase and not a Component
182
182
  > Components register *after* datasources, but secrets must be resolved *before* datasources build their pools. Hydration is therefore a dedicated phase, not a component.
@@ -190,15 +190,16 @@ validateEnvs → staticConfigure → preConfigure
190
190
  | Development set | Log a warning, fall back to a `system-envs` provider, continue booting |
191
191
  | Everything else (prod, staging, and any unrecognized name) | Throw `ApplicationError`, crash the boot |
192
192
 
193
- The fallback in development builds a fresh `SystemEnvsHelper` and shuts down the partially-built provider first, so a half-authenticated Vault client leaves no renewal timer or lease behind.
193
+ The fallback in development builds a fresh `SystemEnvsHelper`. It shuts down the partially-built provider first, so a half-authenticated Vault client leaves no renewal timer or lease behind.
194
194
 
195
195
  ## `AbstractSecretsHelper` Machinery
196
196
 
197
197
  **File:** `packages/helpers/src/modules/secrets/base/abstract.helper.ts`
198
198
 
199
199
  - **TTL cache** - `get()` / `getBundle()` cache each path for `cacheTtlSeconds` (default 300) and re-fetch on expiry.
200
- - **Renewal scheduler** - each lease schedules a renewal at `ttlSeconds × renewBeforeRatio` (default 0.66) through an injectable timer seam. On fire, `renewRaw()` extends the same lease; on renew failure or max-TTL, `fetchRaw()` mints a fresh lease and a single rotation is dispatched.
201
- - **Rotation dispatch** - `onRotate` handlers run first, then the registered rotatables for that key run **in series**; a throwing consumer is logged and does not abort the others.
200
+ - **Renewal scheduler** - each lease schedules a renewal at `ttlSeconds × renewBeforeRatio` (default 0.66) through an injectable timer seam.
201
+ - **On renewal fire** - `renewRaw()` extends the same lease. On renew failure or max-TTL, `fetchRaw()` mints a fresh lease and a single rotation is dispatched instead.
202
+ - **Rotation dispatch** - `onRotate` handlers run first. The registered rotatables for that key then run **in series**; a throwing consumer is logged and does not abort the others.
202
203
  - **Shutdown** - clears every timer and revokes every lease via `revokeRaw()`.
203
204
 
204
205
  The scheduler, cache, and clock are injectable, so the machinery is tested deterministically without real timers or a live vault.
@@ -207,12 +208,15 @@ The scheduler, cache, and clock are injectable, so the machinery is tested deter
207
208
 
208
209
  **File:** `packages/helpers/src/modules/secrets/hashicorp/hashicorp.helper.ts`
209
210
 
210
- - **Auth** - a Zod discriminated union on `method`: `token`, `app-role` (`roleId` + `secretId`), `kubernetes` (`role`, optional `jwtPath`). `configure()` logs in and stores the Vault token.
211
+ - **Auth** - a Zod discriminated union on `method`: `token` (`token`), `app-role` (`roleId` + `secretId`, optional `mountPath`), `kubernetes` (`role`, optional `jwtPath` and `mountPath`). `configure()` logs in and stores the Vault token. `mountPath` defaults to the method name - `approle` and `kubernetes`.
211
212
  - **KV v2** - `getBundle()` unwraps the KV-v2 `.data.data` envelope automatically.
212
213
  - **Dynamic secrets** - a read against a dynamic engine (for example `database/creds/...`) returns a lease (`lease_id`, `lease_duration`, `renewable`), which drives the renewal scheduler.
213
- - **Token self-renewal** - the Vault auth token has its own TTL. The provider schedules the token for renewal in the same cadence and re-runs the login flow (re-auth) if the token can no longer be renewed, so AppRole / Kubernetes deployments survive past the token TTL without a restart.
214
+ - **Token self-renewal** - the Vault auth token has its own TTL. The provider schedules the token for renewal in the same cadence as leases.
215
+ - **Re-auth on expiry** - if the token can no longer be renewed, the provider re-runs the login flow, so AppRole / Kubernetes deployments survive past the token TTL without a restart.
214
216
 
215
- `node-vault` is an optional peer. It is reached only through the `@venizia/ignis-helpers/hashicorp-vault` sub-path and a bundler-invisible dynamic import (`importOptionalModule`), so importing the root package never requires it - and `Bun.build`-compiled applications need no `external: ['node-vault']` workaround. An application that does use this provider and compiles a binary must ship `node-vault` in `node_modules` next to the binary, or inject a ready-made `client` through the helper options.
217
+ `node-vault` is an optional peer. It is reached only through the `@venizia/ignis-helpers/hashicorp-vault` sub-path and a bundler-invisible dynamic import (`ModuleUtility.load`), so importing the root package never requires it. `Bun.build`-compiled applications need no `external: ['node-vault']` workaround.
218
+
219
+ An application that does use this provider and compiles a binary must ship `node-vault` in `node_modules` next to the binary. Alternatively, inject a ready-made `client` through the helper options, or import `node-vault` statically and hand it over with `ModuleUtility.register({ modules: { 'node-vault': nodeVault } })` at startup.
216
220
 
217
221
  ## Dotenv Vault Provider
218
222
 
@@ -229,7 +233,7 @@ The PostgreSQL datasource implements `onSecretRotated()` on `AbstractRelationalD
229
233
  1. Capture the current pool.
230
234
  2. Apply the new credentials onto `this.settings` (`{ username, password }` maps to pg's `{ user, password }`).
231
235
  3. Clear the driver / connector / client, re-run `configure()` to build a fresh pool, and re-wire the driver.
232
- 4. Drain the old pool with `end()` - which resolves once checked-out clients are released, so in-flight transactions finish on the old pool while new work uses the new one.
236
+ 4. Drain the old pool with `end()`. It resolves once checked-out clients are released, so in-flight transactions finish on the old pool while new work uses the new one.
233
237
 
234
238
  > [!WARNING] configure() must read from this.settings
235
239
  > Rotation applies new credentials by writing them onto `this.settings` and re-running `configure()`. A `configure()` that builds its pool from a hard-coded connection string, or reads `Envs` directly, will rebuild with **stale** credentials.
@@ -8,7 +8,7 @@ difficulty: beginner
8
8
 
9
9
  Technical reference for `BaseService` - the foundation for the business logic layer in IGNIS.
10
10
 
11
- **File:** `packages/core/src/base/services/base.ts`
11
+ **File:** `packages/core-server/src/base/services/base.ts`
12
12
 
13
13
  ## Quick Reference
14
14
 
@@ -29,7 +29,7 @@ Technical reference for `BaseService` - the foundation for the business logic la
29
29
  Abstract class that all application services must extend.
30
30
 
31
31
  ```typescript
32
- // packages/core/src/base/services/base.ts
32
+ // packages/core-server/src/base/services/base.ts
33
33
  import { BaseHelper } from '@venizia/ignis-helpers';
34
34
  import { IService } from './types';
35
35
 
@@ -65,7 +65,7 @@ this.service(GreeterService); // binds as 'services.GreeterService'
65
65
  `this.service(Ctor)` is implemented directly on `BaseApplication`:
66
66
 
67
67
  ```typescript
68
- // packages/core/src/base/applications/base.ts
68
+ // packages/core-server/src/base/applications/base.ts
69
69
  service<Base extends IService, Args extends AnyObject = any>(
70
70
  ctor: TClass<Base>,
71
71
  opts?: TMixinOpts<Args>,
@@ -244,7 +244,9 @@ this.service(OrderService);
244
244
 
245
245
  ### Abstract Base Services
246
246
 
247
- For shared dependencies across multiple related services, define an abstract base. The container only ever `instantiate()`s the **concrete** class (`this.service(UserAuditTestService)` registers `UserAuditTestService`, never `BaseTestService`), and the hard DI rule - every constructor parameter of a container-instantiated class must carry `@inject` - applies to that concrete constructor. A `scope: string` computed from `ClassName.name` is not something the container can supply anyway, so it cannot sit as a bare constructor parameter next to an `@inject`-decorated one. The shared repository is injected as a **property** on the base instead, and the concrete subclass's constructor is left with zero parameters - nothing to decorate, nothing to violate:
247
+ For shared dependencies across multiple related services, define an abstract base. The container only ever `instantiate()`s the **concrete** class - `this.service(UserAuditTestService)` registers `UserAuditTestService`, never `BaseTestService`. The hard DI rule - every constructor parameter of a container-instantiated class must carry `@inject` - applies to that concrete constructor.
248
+
249
+ A `scope: string` computed from `ClassName.name` is not something the container can supply. So it cannot sit as a bare constructor parameter next to an `@inject`-decorated one. The shared repository is injected as a **property** on the base instead. The concrete subclass's constructor is left with zero parameters - nothing to decorate, nothing to violate:
248
250
 
249
251
  ```typescript
250
252
  // Shared repository access for a group of test services - property injection,
@@ -4,10 +4,10 @@ Complete reference of all environment variables used by the IGNIS framework, gro
4
4
 
5
5
  **Files:**
6
6
 
7
- - [`packages/core/src/common/environments.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/environments.ts) - `EnvironmentKeys`
7
+ - [`packages/core-server/src/common/environments.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/environments.ts) - `EnvironmentKeys`
8
8
  - [`packages/helpers/src/modules/env/app-env.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/env/app-env.ts) - `applicationEnvironment`, `Environment`
9
- - [`packages/core/src/base/applications/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/applications/abstract.ts) - `validateEnvs()`, host/port resolution priority
10
- - [`packages/core/src/base/applications/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/applications/base.ts) - `registerSecrets()`, `hydrateSecrets()`
9
+ - [`packages/core-server/src/base/applications/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/applications/abstract.ts) - `validateEnvs()`, host/port resolution priority
10
+ - [`packages/core-server/src/base/applications/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/applications/base.ts) - `registerSecrets()`, `hydrateSecrets()`
11
11
  - [`packages/helpers/src/modules/secrets/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/secrets/common/constants.ts) - `SecretProviders`, `VaultAuthMethods`
12
12
  - [`packages/helpers/src/modules/secrets/hashicorp/hashicorp.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/secrets/hashicorp/hashicorp.helper.ts) - HashiCorp Vault helper
13
13
 
@@ -43,38 +43,38 @@ Create a `.env` file in your project root:
43
43
  ```bash
44
44
  # .env
45
45
 
46
- # =====================
46
+ # ----------------------
47
47
  # APPLICATION
48
- # =====================
48
+ # ----------------------
49
49
  APP_ENV_APPLICATION_NAME=my-app
50
50
  APP_ENV_APPLICATION_TIMEZONE=UTC
51
51
 
52
- # =====================
52
+ # ----------------------
53
53
  # SERVER
54
- # =====================
54
+ # ----------------------
55
55
  APP_ENV_SERVER_HOST=0.0.0.0
56
56
  APP_ENV_SERVER_PORT=3000
57
57
  APP_ENV_SERVER_BASE_PATH=/api
58
58
 
59
- # =====================
59
+ # ----------------------
60
60
  # DATABASE (PostgreSQL)
61
- # =====================
61
+ # ----------------------
62
62
  APP_ENV_POSTGRES_HOST=localhost
63
63
  APP_ENV_POSTGRES_PORT=5432
64
64
  APP_ENV_POSTGRES_USERNAME=postgres
65
65
  APP_ENV_POSTGRES_PASSWORD=your_password_here
66
66
  APP_ENV_POSTGRES_DATABASE=my_database
67
67
 
68
- # =====================
68
+ # ----------------------
69
69
  # AUTHENTICATION
70
- # =====================
70
+ # ----------------------
71
71
  APP_ENV_APPLICATION_SECRET=generate-a-strong-random-secret
72
72
  APP_ENV_JWT_SECRET=generate-another-strong-random-secret
73
73
  APP_ENV_JWT_EXPIRES_IN=86400
74
74
 
75
- # =====================
75
+ # ----------------------
76
76
  # LOGGING
77
- # =====================
77
+ # ----------------------
78
78
  APP_ENV_LOGGER_FOLDER_PATH=./logs
79
79
  ```
80
80
 
@@ -124,7 +124,7 @@ APP_ENV_SERVER_BASE_PATH=/v1/api
124
124
 
125
125
  ### Priority Order
126
126
 
127
- The server host/port resolution uses this priority (`packages/core/src/base/applications/abstract.ts`):
127
+ The server host/port resolution uses this priority (`packages/core-server/src/base/applications/abstract.ts`):
128
128
  1. Explicit config passed to the application constructor
129
129
  2. `HOST`/`PORT` variables (for cloud platforms)
130
130
  3. `APP_ENV_SERVER_HOST`/`APP_ENV_SERVER_PORT` variables
@@ -199,7 +199,7 @@ export class PostgresDataSource extends BaseDataSource {
199
199
 
200
200
  - **Not read directly.** The `AuthenticateComponent` receives its secrets programmatically via the `jwtOptions` binding (`jwtSecret`, `getTokenExpiresFn`) - it never reads these environment variables itself.
201
201
  - **`EnvironmentKeys` is the convention, not a requirement.** These constants are the conventional way for your application to supply those values into the binding.
202
- - **A missing or placeholder secret fails the boot.** The component throws at startup if `jwtSecret` is missing or left at the placeholder value - wiring it from an unset environment variable fails the same way.
202
+ - **A missing or placeholder secret fails the boot.** The component throws at startup if `jwtSecret` is missing or left at the placeholder value. Wiring it from an unset environment variable fails the same way.
203
203
 
204
204
  ### Generate Strong Secrets
205
205
 
@@ -236,6 +236,7 @@ APP_ENV_JWT_EXPIRES_IN=86400
236
236
  | `APP_ENV_LOGGER_LEVEL` | No | `debug` | Logger-level floor; transports without their own level inherit it |
237
237
  | `APP_ENV_LOGGER_INSPECT_DEPTH` | No | `5` | How deep a `%s` argument is inspected. Node hard-codes depth `0` for `%s`, which prints `[Object]` one level in; IGNIS widens it. Non-negative integers only - an absent, invalid or negative value falls back to `5` |
238
238
  | `APP_ENV_LOGGER_DO_REDACT` | No | `true` | Secret redaction in logged values. ONLY the literal `false` disables it (reveals raw credentials in log lines); anything else keeps redaction ON. Never disable in production |
239
+ | `APP_ENV_LOGGER_COLOR` | No | _(unset)_ | ANSI color on console log lines. Unset means auto: ON in a development `NODE_ENV`, OFF in `production`, `staging`, `uat` and any unrecognized name. `NO_COLOR` also turns it off |
239
240
  | `APP_ENV_LOGGER_FILE_FREQUENCY` | No | `1h` | Log file rotation frequency |
240
241
  | `APP_ENV_LOGGER_FILE_MAX_SIZE` | No | `100m` | Max size per log file |
241
242
  | `APP_ENV_LOGGER_FILE_MAX_FILES` | No | `5d` | Log file retention |
@@ -328,9 +329,14 @@ APP_ENV_MAIL_REFRESH_TOKEN=your-oauth2-refresh-token
328
329
 
329
330
  | Variable | Required | Default | Description |
330
331
  |----------|----------|---------|-------------|
331
- | `APP_ENV_APPLICATION_DS_MIGRATION` | No | - | DataSource name for migrations |
332
- | `APP_ENV_APPLICATION_DS_AUTHORIZE` | No | - | DataSource name for auth |
333
- | `APP_ENV_APPLICATION_DS_OAUTH2` | No | - | DataSource name for OAuth2 |
332
+ | `APP_ENV_DS_MIGRATION` | No | `postgres` | DataSource name for migrations. Read at boot and printed in the startup banner |
333
+ | `APP_ENV_DS_AUTHORIZE` | No | `postgres` | DataSource name for authorization. Read at boot and printed in the startup banner |
334
+ | `APP_ENV_AUTO_PROVISION_COLLECTION` | No | `false` | Lets a search datasource create a missing collection on first use. `true` or `1` enables it; the `autoProvision` constructor option overrides it |
335
+
336
+ > [!WARNING] These two name the datasource, they do not select it
337
+ > `APP_ENV_DS_MIGRATION` and `APP_ENV_DS_AUTHORIZE` reach the startup banner and nothing else - the framework does not resolve a datasource from either. Wire your own lookup if you need one.
338
+
339
+ `Environments` (`packages/core-server/src/common/environments.ts`) also declares `APP_ENV_APPLICATION_DS_MIGRATION`, `APP_ENV_APPLICATION_DS_AUTHORIZE` and `APP_ENV_APPLICATION_DS_OAUTH2`. Those are name constants with no reader anywhere in the framework - setting them changes nothing.
334
340
 
335
341
 
336
342
  ## Debug Variables
@@ -340,6 +346,7 @@ APP_ENV_MAIL_REFRESH_TOKEN=your-oauth2-refresh-token
340
346
  | `DEBUG` | No | - | Enable debug mode |
341
347
  | `NODE_ENV` | No | `development` | Environment mode. One of `local`, `debug`, `development`, `dev`, `sit`, `uat`, `alpha`, `beta`, `staging`, `production` |
342
348
  | `ALLOW_EMPTY_ENV_VALUE` | No | `false` | Allow empty env values |
349
+ | `RUN_MODE` | No | - | Printed in the startup banner. The framework never branches on it - read it yourself to split a migrate run from a serve run |
343
350
 
344
351
  - **Fail-closed by default.** An environment IGNIS does not recognize is treated as production, so error responses are sanitized.
345
352
  - **Development environments expose error detail.** `local`, `debug`, `development`, `dev`, and `sit` are the development set - only these show internal error detail.
@@ -359,7 +366,8 @@ NODE_ENV=production
359
366
 
360
367
  ## Secrets & Vault
361
368
 
362
- - **A `.env` file is one option, not a requirement.** IGNIS can load these variables from a vault (HashiCorp Vault, an encrypted `.env.vault`, or plain `process.env`) and **hydrate** them into the same `APP_ENV_*` keys at boot. Code that reads `process.env.APP_ENV_*` keeps working unchanged - the values simply arrive from the vault instead of a file.
369
+ - **A `.env` file is one option, not a requirement.** IGNIS can load these variables from a vault (HashiCorp Vault, an encrypted `.env.vault`, or plain `process.env`). It **hydrates** them into the same `APP_ENV_*` keys at boot.
370
+ - **Hydration is transparent to your code.** Code that reads `process.env.APP_ENV_*` keeps working unchanged - the values arrive from the vault instead of a file.
363
371
  - **Hydration runs before datasources are configured** (after `preConfigure()`, before `registerDataSources()`), so a hydrated `APP_ENV_DS_PASSWORD` is available exactly where a file-based one would be.
364
372
  - **Vault values take precedence over `process.env`** when the provider is live - a hydrated key overwrites whatever was already in `process.env`.
365
373
 
@@ -375,7 +383,7 @@ override registerSecrets() {
375
383
  ```
376
384
 
377
385
  > [!NOTE] Failure policy
378
- > If the vault is unreachable, development environments (`local`, `debug`, `development`, `dev`, `sit`) fall back to `process.env`; every other environment fails the boot rather than starting with missing secrets.
386
+ > If the vault is unreachable, development environments (`local`, `debug`, `development`, `dev`, `sit`) fall back to `process.env`. Every other environment fails the boot rather than starting with missing secrets.
379
387
 
380
388
  See the [Secrets & Vault guide](/guides/core-concepts/secrets-vault) for setup and the [Secrets & Vault reference](/references/base/secrets) for the full API.
381
389
 
@@ -414,7 +422,7 @@ MY_APP_POSTGRES_HOST=localhost
414
422
 
415
423
  ## Validation
416
424
 
417
- On startup, IGNIS iterates every `APP_ENV_*` (prefixed) variable that is set and throws if any has an empty value (`validateEnvs` in `packages/core/src/base/applications/abstract.ts`). It does not check for variables that are absent entirely - component-level validation (e.g., the authentication component's `jwtSecret` check) covers required values.
425
+ On startup, IGNIS iterates every `APP_ENV_*` (prefixed) variable that is set and throws if any has an empty value (`validateEnvs` in `packages/core-server/src/base/applications/abstract.ts`). It does not check for variables that are absent entirely - component-level validation (e.g., the authentication component's `jwtSecret` check) covers required values.
418
426
 
419
427
  ### Disable Validation
420
428
 
@@ -436,9 +444,9 @@ ALLOW_EMPTY_ENV_VALUE=true
436
444
  ## Complete .env.example
437
445
 
438
446
  ```bash
439
- # ===========================================
447
+ # ----------------------
440
448
  # IGNIS ENVIRONMENT VARIABLES
441
- # ===========================================
449
+ # ----------------------
442
450
  # Copy this file to .env and fill in values
443
451
 
444
452
  # APPLICATION
@@ -52,8 +52,10 @@ const host = applicationEnvironment.get<string>(EnvironmentKeys.APP_ENV_POSTGRES
52
52
  ## How it works
53
53
 
54
54
  - **One prefix, layered files.** Everything IGNIS reads is prefixed `APP_ENV_` (configurable - see the [Environment Variables Reference](./environment-variables.md#custom-environment-prefix)). Layer `.env`, `.env.local`, and `.env.{NODE_ENV}` the same way any dotenv-based tool does.
55
- - **`applicationEnvironment` snapshots `process.env` once at import.** It's built from whatever is in `process.env` when `@venizia/ignis-helpers` loads - values arriving after that (e.g., set programmatically at runtime) won't appear in `.keys()` unless merged in explicitly (secret hydration does this - see below).
56
- - **Startup validation is fail-closed on emptiness, not absence.** IGNIS iterates every `APP_ENV_*` key that IS set and throws if its value is empty; it does not require a variable to exist at all. Bypass with `ALLOW_EMPTY_ENV_VALUE=true`. Component-level checks (e.g., the authentication component's `jwtSecret` check) cover values that must be present.
55
+ - **`applicationEnvironment` snapshots `process.env` once at import.** It's built from whatever is in `process.env` when `@venizia/ignis-helpers` loads.
56
+ - **Late values need an explicit merge.** A value set programmatically at runtime, after that snapshot, won't appear in `.keys()` unless merged in - secret hydration does this, see below.
57
+ - **Startup validation is fail-closed on emptiness, not absence.** IGNIS iterates every `APP_ENV_*` key that IS set and throws if its value is empty. It does not require a variable to exist at all.
58
+ - **Bypass and per-component checks.** Bypass emptiness validation with `ALLOW_EMPTY_ENV_VALUE=true`. Component-level checks (e.g., the authentication component's `jwtSecret` check) still cover values that must be present.
57
59
  - **Secrets don't have to live in a file.** IGNIS can hydrate `APP_ENV_*` keys from a vault at boot, before datasources are configured - see [Secrets & Vault](./environment-variables.md#secrets-vault).
58
60
 
59
61
  ## Common tasks
@@ -125,6 +127,6 @@ import { EnvironmentKeys } from '@venizia/ignis';
125
127
 
126
128
  **Files:**
127
129
 
128
- - [`packages/core/src/common/environments.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/environments.ts) - `EnvironmentKeys`
130
+ - [`packages/core-server/src/common/environments.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/environments.ts) - `EnvironmentKeys`
129
131
  - [`packages/helpers/src/modules/env/app-env.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/env/app-env.ts) - `applicationEnvironment`, `Environment`, `ApplicationEnvironment`
130
- - [`packages/core/src/base/applications/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/applications/abstract.ts) - `validateEnvs()`, host/port resolution
132
+ - [`packages/core-server/src/base/applications/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/applications/abstract.ts) - `validateEnvs()`, host/port resolution
@@ -162,7 +162,7 @@ import {
162
162
  import {
163
163
  LoggerFactory,
164
164
  RedisSingleHelper,
165
- QueueHelper,
165
+ SequentialQueueHelper,
166
166
  } from '@venizia/ignis-helpers';
167
167
 
168
168
  // DI Container
@@ -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
 
@@ -29,6 +31,7 @@ Pure, standalone functions providing common, reusable logic for the IGNIS framew
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
 
@@ -10,16 +10,16 @@ Exhaustive reference for `htmlContent()`, `htmlResponse()`, and `BaseRestControl
10
10
 
11
11
  **Files:**
12
12
 
13
- - [`packages/core/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/utilities/jsx.utility.ts) - `htmlContent`, `htmlResponse`
14
- - [`packages/core/src/base/controllers/rest/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/controllers/rest/base.ts) - `BaseRestController.defineJSXRoute`
15
- - [`packages/core/src/base/controllers/rest/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/controllers/rest/abstract.ts) - `AbstractRestController.getJSXRouteConfigs`
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
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
17
 
18
18
  ## `htmlContent()`
19
19
 
20
20
  Creates a standard OpenAPI content object for `text/html` responses.
21
21
 
22
- `Source ->` [`packages/core/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/utilities/jsx.utility.ts)
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
23
 
24
24
  ```typescript
25
25
  const htmlContent = (opts: { description: string; required?: boolean }) => ({
@@ -49,9 +49,9 @@ An OpenAPI content configuration object: `description`, `content['text/html'].sc
49
49
 
50
50
  ## `htmlResponse()`
51
51
 
52
- Creates a standard OpenAPI response object for HTML endpoints: a success (`200`) HTML response plus a JSON error response for `4xx | 5xx` status codes using `ErrorSchema`.
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
53
 
54
- `Source ->` [`packages/core/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/utilities/jsx.utility.ts)
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
55
 
56
56
  ```typescript
57
57
  const htmlResponse = (opts: { description: string; required?: boolean }) => ({
@@ -91,7 +91,7 @@ this.defineRoute({
91
91
 
92
92
  Defines and registers a JSX/HTML route in a single call - the JSX counterpart of `defineRoute()`.
93
93
 
94
- `Source ->` [`packages/core/src/base/controllers/rest/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/controllers/rest/base.ts)
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
95
 
96
96
  ```typescript
97
97
  defineJSXRoute<RouteConfig extends IAuthRouteConfig, ResponseType = unknown>(opts: {
@@ -111,7 +111,7 @@ defineJSXRoute<RouteConfig extends IAuthRouteConfig, ResponseType = unknown>(opt
111
111
 
112
112
  `defineJSXRoute` is `defineRoute` with one difference: it builds the route configuration through `getJSXRouteConfigs` instead of `getRouteConfigs`.
113
113
 
114
- `Source ->` [`packages/core/src/base/controllers/rest/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/controllers/rest/abstract.ts)
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
115
 
116
116
  ```typescript
117
117
  getJSXRouteConfigs<RouteConfig extends IAuthRouteConfig>(opts: { configs: RouteConfig }) {
@@ -129,9 +129,9 @@ getJSXRouteConfigs<RouteConfig extends IAuthRouteConfig>(opts: { configs: RouteC
129
129
  }
130
130
  ```
131
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.
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
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.
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
135
 
136
136
  ## JSX setup
137
137
 
@@ -148,7 +148,7 @@ getJSXRouteConfigs<RouteConfig extends IAuthRouteConfig>(opts: { configs: RouteC
148
148
  }
149
149
  ```
150
150
 
151
- Verified in [`packages/core/tsconfig.json`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/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).
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
152
 
153
153
  ### Component types
154
154
 
@@ -127,5 +127,5 @@ this.defineJSXRoute({
127
127
 
128
128
  **Files:**
129
129
 
130
- - [`packages/core/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/utilities/jsx.utility.ts) - `htmlContent`, `htmlResponse`
131
- - [`packages/core/src/base/controllers/rest/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/controllers/rest/base.ts) - `defineJSXRoute`
130
+ - [`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`
131
+ - [`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) - `defineJSXRoute`