@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.
- package/content/best-practices/architectural-patterns.md +3 -3
- package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/content/best-practices/contribution-workflow.md +2 -2
- package/content/best-practices/error-handling.md +94 -89
- package/content/best-practices/security-guidelines.md +5 -5
- package/content/extensions/components/api-reference.md +22 -21
- package/content/extensions/components/authentication/api.md +64 -28
- package/content/extensions/components/authentication/errors.md +19 -5
- package/content/extensions/components/authentication/index.md +19 -18
- package/content/extensions/components/authentication/usage.md +55 -30
- package/content/extensions/components/authorization/api.md +351 -84
- package/content/extensions/components/authorization/errors.md +51 -17
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +24 -16
- package/content/extensions/components/authorization/usage.md +45 -21
- package/content/extensions/components/health-check.md +15 -9
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +105 -54
- package/content/extensions/components/mail/errors.md +12 -10
- package/content/extensions/components/mail/index.md +32 -13
- package/content/extensions/components/mail/usage.md +26 -18
- package/content/extensions/components/request-tracker.md +18 -14
- package/content/extensions/components/socket-io/api.md +377 -882
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +72 -88
- package/content/extensions/components/socket-io/usage.md +107 -117
- package/content/extensions/components/static-asset/api.md +83 -31
- package/content/extensions/components/static-asset/errors.md +18 -7
- package/content/extensions/components/static-asset/index.md +18 -11
- package/content/extensions/components/static-asset/usage.md +11 -6
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +58 -27
- package/content/extensions/components/websocket/errors.md +3 -3
- package/content/extensions/components/websocket/index.md +8 -7
- package/content/extensions/components/websocket/usage.md +21 -8
- package/content/extensions/helpers/cron/index.md +8 -7
- package/content/extensions/helpers/crypto/index.md +16 -8
- package/content/extensions/helpers/crypto/reference.md +96 -24
- package/content/extensions/helpers/env/index.md +14 -10
- package/content/extensions/helpers/error/index.md +99 -23
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +23 -6
- package/content/extensions/helpers/inversion/reference.md +30 -22
- package/content/extensions/helpers/kafka/admin.md +3 -2
- package/content/extensions/helpers/kafka/compile-binary.md +69 -44
- package/content/extensions/helpers/kafka/consumer.md +24 -21
- package/content/extensions/helpers/kafka/examples.md +22 -234
- package/content/extensions/helpers/kafka/index.md +30 -62
- package/content/extensions/helpers/kafka/producer.md +31 -26
- package/content/extensions/helpers/kafka/schema-registry.md +19 -14
- package/content/extensions/helpers/logger/hf-logger.md +49 -22
- package/content/extensions/helpers/logger/index.md +37 -12
- package/content/extensions/helpers/logger/pino.md +31 -11
- package/content/extensions/helpers/logger/reference.md +243 -52
- package/content/extensions/helpers/network/api.md +65 -30
- package/content/extensions/helpers/network/index.md +32 -11
- package/content/extensions/helpers/queue/index.md +17 -6
- package/content/extensions/helpers/queue/reference.md +52 -25
- package/content/extensions/helpers/redis/index.md +29 -11
- package/content/extensions/helpers/redis/reference.md +85 -28
- package/content/extensions/helpers/secrets/index.md +82 -12
- package/content/extensions/helpers/socket-io/api.md +40 -21
- package/content/extensions/helpers/socket-io/index.md +26 -10
- package/content/extensions/helpers/storage/api.md +42 -24
- package/content/extensions/helpers/storage/index.md +10 -7
- package/content/extensions/helpers/types/index.md +20 -7
- package/content/extensions/helpers/types/reference.md +53 -14
- package/content/extensions/helpers/uid/index.md +166 -10
- package/content/extensions/helpers/websocket/api.md +52 -13
- package/content/extensions/helpers/websocket/index.md +7 -4
- package/content/extensions/helpers/worker-thread/index.md +9 -5
- package/content/extensions/helpers/worker-thread/reference.md +20 -20
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +26 -14
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +4 -3
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +7 -6
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +63 -21
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +14 -14
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +32 -31
- package/content/references/base/datasources.md +6 -6
- package/content/references/base/dependency-injection.md +12 -11
- package/content/references/base/filter-system/application-usage.md +54 -30
- package/content/references/base/filter-system/array-operators.md +24 -46
- package/content/references/base/filter-system/comparison-operators.md +47 -67
- package/content/references/base/filter-system/default-filter.md +59 -53
- package/content/references/base/filter-system/fields-order-pagination.md +92 -146
- package/content/references/base/filter-system/index.md +25 -13
- package/content/references/base/filter-system/json-filtering.md +45 -184
- package/content/references/base/filter-system/list-operators.md +23 -53
- package/content/references/base/filter-system/logical-operators.md +63 -121
- package/content/references/base/filter-system/null-operators.md +34 -104
- package/content/references/base/filter-system/pattern-matching.md +40 -55
- package/content/references/base/filter-system/quick-reference.md +86 -198
- package/content/references/base/filter-system/range-operators.md +18 -46
- package/content/references/base/filter-system/tips.md +6 -6
- package/content/references/base/filter-system/use-cases.md +33 -15
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +11 -10
- package/content/references/base/models-reference.md +17 -17
- package/content/references/base/models.md +4 -3
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +224 -326
- package/content/references/base/repositories/index.md +19 -6
- package/content/references/base/repositories/mixins.md +5 -5
- package/content/references/base/repositories/relations.md +160 -293
- package/content/references/base/repositories/soft-deletable.md +16 -6
- package/content/references/base/secrets.md +17 -13
- package/content/references/base/services.md +6 -4
- package/content/references/configuration/environment-variables.md +31 -23
- package/content/references/configuration/index.md +6 -4
- package/content/references/index.md +1 -1
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +5 -1
- package/content/references/utilities/jsx-reference.md +11 -11
- package/content/references/utilities/jsx.md +2 -2
- package/content/references/utilities/module.md +78 -25
- package/content/references/utilities/request.md +2 -1
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +2 -2
- package/content/references/utilities/statuses-reference.md +4 -4
- package/content/references/utilities/statuses.md +5 -5
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- 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
|
|
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`)
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
201
|
-
- **
|
|
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
|
|
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
|
|
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 (`
|
|
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()
|
|
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
|
|
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
|
|
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
|
-
| `
|
|
332
|
-
| `
|
|
333
|
-
| `
|
|
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`)
|
|
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
|
|
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
|
|
56
|
-
- **
|
|
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
|
|
@@ -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` |
|
|
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
|
|
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
|
|
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`)
|
|
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`
|