@venizia/ignis-docs 0.2.0 → 0.2.1-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +24 -13
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +8 -4
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +247 -153
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +109 -323
- package/content/extensions/components/authentication/api.md +489 -602
- package/content/extensions/components/authentication/errors.md +135 -498
- package/content/extensions/components/authentication/index.md +89 -801
- package/content/extensions/components/authentication/usage.md +231 -955
- package/content/extensions/components/authorization/api.md +991 -644
- package/content/extensions/components/authorization/errors.md +204 -208
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +88 -795
- package/content/extensions/components/authorization/usage.md +219 -528
- package/content/extensions/components/health-check.md +77 -243
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +553 -285
- package/content/extensions/components/mail/errors.md +76 -62
- package/content/extensions/components/mail/index.md +111 -463
- package/content/extensions/components/mail/usage.md +139 -173
- package/content/extensions/components/request-tracker.md +70 -173
- package/content/extensions/components/socket-io/api.md +462 -785
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +69 -372
- package/content/extensions/components/socket-io/usage.md +212 -105
- package/content/extensions/components/static-asset/api.md +461 -141
- package/content/extensions/components/static-asset/errors.md +121 -53
- package/content/extensions/components/static-asset/index.md +84 -606
- package/content/extensions/components/static-asset/usage.md +184 -299
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +311 -404
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +75 -407
- package/content/extensions/components/websocket/usage.md +120 -338
- package/content/extensions/helpers/cron/index.md +52 -160
- package/content/extensions/helpers/crypto/index.md +67 -480
- package/content/extensions/helpers/crypto/reference.md +528 -0
- package/content/extensions/helpers/env/index.md +64 -178
- package/content/extensions/helpers/error/index.md +286 -196
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +76 -550
- package/content/extensions/helpers/inversion/reference.md +530 -0
- package/content/extensions/helpers/kafka/admin.md +23 -3
- package/content/extensions/helpers/kafka/compile-binary.md +83 -52
- package/content/extensions/helpers/kafka/consumer.md +65 -28
- package/content/extensions/helpers/kafka/examples.md +46 -253
- package/content/extensions/helpers/kafka/index.md +55 -617
- package/content/extensions/helpers/kafka/producer.md +156 -22
- package/content/extensions/helpers/kafka/schema-registry.md +59 -79
- package/content/extensions/helpers/logger/hf-logger.md +220 -0
- package/content/extensions/helpers/logger/index.md +78 -552
- package/content/extensions/helpers/logger/pino.md +105 -0
- package/content/extensions/helpers/logger/reference.md +937 -0
- package/content/extensions/helpers/network/api.md +276 -195
- package/content/extensions/helpers/network/index.md +87 -524
- package/content/extensions/helpers/queue/index.md +80 -897
- package/content/extensions/helpers/queue/reference.md +494 -0
- package/content/extensions/helpers/redis/index.md +86 -640
- package/content/extensions/helpers/redis/reference.md +784 -0
- package/content/extensions/helpers/secrets/index.md +136 -0
- package/content/extensions/helpers/socket-io/api.md +325 -204
- package/content/extensions/helpers/socket-io/index.md +79 -429
- package/content/extensions/helpers/storage/api.md +584 -464
- package/content/extensions/helpers/storage/index.md +80 -573
- package/content/extensions/helpers/types/index.md +75 -495
- package/content/extensions/helpers/types/reference.md +689 -0
- package/content/extensions/helpers/uid/index.md +176 -189
- package/content/extensions/helpers/websocket/api.md +366 -214
- package/content/extensions/helpers/websocket/index.md +68 -503
- package/content/extensions/helpers/worker-thread/index.md +62 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- 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/models.md +1 -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 +28 -16
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- 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 +5 -4
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +8 -7
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +64 -22
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +600 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +25 -46
- package/content/references/base/filter-system/application-usage.md +95 -123
- package/content/references/base/filter-system/array-operators.md +33 -43
- package/content/references/base/filter-system/comparison-operators.md +55 -63
- package/content/references/base/filter-system/default-filter.md +144 -350
- package/content/references/base/filter-system/fields-order-pagination.md +116 -148
- package/content/references/base/filter-system/index.md +114 -253
- package/content/references/base/filter-system/json-filtering.md +52 -181
- package/content/references/base/filter-system/list-operators.md +28 -44
- package/content/references/base/filter-system/logical-operators.md +69 -114
- package/content/references/base/filter-system/null-operators.md +41 -98
- package/content/references/base/filter-system/pattern-matching.md +48 -51
- package/content/references/base/filter-system/quick-reference.md +93 -196
- package/content/references/base/filter-system/range-operators.md +22 -38
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +173 -232
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +43 -28
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +81 -1452
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +281 -419
- package/content/references/base/repositories/index.md +84 -644
- package/content/references/base/repositories/mixins.md +25 -21
- package/content/references/base/repositories/relations.md +194 -375
- package/content/references/base/repositories/soft-deletable.md +67 -55
- package/content/references/base/secrets.md +267 -0
- package/content/references/base/services.md +8 -6
- package/content/references/configuration/environment-variables.md +73 -21
- package/content/references/configuration/index.md +51 -31
- package/content/references/index.md +1 -1
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +6 -2
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +81 -61
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +58 -218
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- 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 +24 -23
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Secrets & Vault
|
|
3
|
+
description: Load configuration and credentials from a vault, hydrate them at boot, and rotate database credentials without a restart
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Secrets & Vault
|
|
8
|
+
|
|
9
|
+
IGNIS can load configuration and credentials from a vault instead of reading `process.env` directly. This guide shows how to enable it, how to consume secrets in your code, and how to rotate dynamic database credentials into a live pool without restarting the server.
|
|
10
|
+
|
|
11
|
+
> [!TIP] You do not have to do anything to keep working as before
|
|
12
|
+
> Until you override `registerSecrets()`, IGNIS uses the `system-envs` provider, which reads `process.env`. Everything below is opt-in.
|
|
13
|
+
|
|
14
|
+
## The Mental Model
|
|
15
|
+
|
|
16
|
+
Secrets reach your app through two paths:
|
|
17
|
+
|
|
18
|
+
- **Hydrate** - at boot, IGNIS fetches secrets and merges them into `process.env` / `Envs`. Existing code that reads `process.env.APP_ENV_*` keeps working with no change.
|
|
19
|
+
- **Provider** - the resolved provider is bound in the container at `@app/config`. Inject it wherever you need on-demand reads, dynamic credentials, or rotation.
|
|
20
|
+
|
|
21
|
+
You configure both in one place: a `registerSecrets()` override on your application class.
|
|
22
|
+
|
|
23
|
+
## Enabling a Provider
|
|
24
|
+
|
|
25
|
+
Override `registerSecrets()` on your `Application extends BaseApplication`.
|
|
26
|
+
|
|
27
|
+
### HashiCorp Vault
|
|
28
|
+
|
|
29
|
+
Recommended for enterprise: KV v2 static secrets plus dynamic database credentials with automatic rotation.
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { SecretProviders, VaultAuthMethods } from '@venizia/ignis-helpers';
|
|
33
|
+
|
|
34
|
+
export class Application extends BaseApplication {
|
|
35
|
+
override registerSecrets() {
|
|
36
|
+
return {
|
|
37
|
+
provider: SecretProviders.HASHICORP_VAULT,
|
|
38
|
+
|
|
39
|
+
config: {
|
|
40
|
+
endpoint: 'https://vault.internal:8200',
|
|
41
|
+
// Dev: a raw token. Production: AppRole or Kubernetes.
|
|
42
|
+
auth: { method: VaultAuthMethods.APP_ROLE, roleId, secretId },
|
|
43
|
+
// or: { method: VaultAuthMethods.TOKEN, token }
|
|
44
|
+
// or: { method: VaultAuthMethods.KUBERNETES, role: 'my-app' }
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Static KV v2 secrets -> merged into Envs once at boot.
|
|
48
|
+
hydrate: [
|
|
49
|
+
{ path: 'secret/data/myapp/config' }, // keys land as-is
|
|
50
|
+
{ path: 'secret/data/myapp/db', prefix: 'APP_ENV_DS_' }, // optional prefix
|
|
51
|
+
// { path: 'secret/data/myapp/db', keys: { password: 'APP_ENV_DS_PASSWORD' } },
|
|
52
|
+
],
|
|
53
|
+
|
|
54
|
+
// Dynamic engine secrets -> renewed and rotated automatically.
|
|
55
|
+
lease: [
|
|
56
|
+
{ key: 'datasources.PostgresDataSource', path: 'database/creds/app-role' },
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`node-vault` is an optional peer. Install it in the application that uses this provider:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
bun add node-vault
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Applications that do not use this provider never need it - not even when compiling a binary with
|
|
70
|
+
`Bun.build`. If your application uses this provider **and** compiles a binary, ship `node-vault` in
|
|
71
|
+
`node_modules` next to the binary, or inject a ready-made `client` through the helper options.
|
|
72
|
+
|
|
73
|
+
### Dotenv Vault
|
|
74
|
+
|
|
75
|
+
An encrypted `.env.vault` file decrypted at runtime with a per-environment `DOTENV_KEY`. Static only.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { SecretProviders } from '@venizia/ignis-helpers';
|
|
79
|
+
|
|
80
|
+
export class Application extends BaseApplication {
|
|
81
|
+
override registerSecrets() {
|
|
82
|
+
return {
|
|
83
|
+
provider: SecretProviders.DOTENV_VAULT,
|
|
84
|
+
config: { path: '.env.vault', dotenvKey: process.env.DOTENV_KEY },
|
|
85
|
+
hydrate: [{ path: 'ignored' }], // decrypts the file and merges it into Envs
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
bun add @dotenvx/dotenvx
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### System Env (default)
|
|
96
|
+
|
|
97
|
+
The default; shown here only to be explicit. Reads `process.env`, no dependencies.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
override registerSecrets() {
|
|
101
|
+
return { provider: SecretProviders.SYSTEM_ENVS };
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Addressing and Merging
|
|
106
|
+
|
|
107
|
+
Each `hydrate` entry resolves a path to a flat key-value object that is merged into `Envs` and `process.env`:
|
|
108
|
+
|
|
109
|
+
- **Convention** - store the keys in the vault already named `APP_ENV_...` and they merge as-is, no mapping needed.
|
|
110
|
+
- **`prefix`** - prepend a string to every merged key.
|
|
111
|
+
- **`keys`** - an explicit `vaultKey -> envKey` map for precise control (wins over `prefix`).
|
|
112
|
+
|
|
113
|
+
When the provider is live, vault values take precedence over `process.env`.
|
|
114
|
+
|
|
115
|
+
## Reading Secrets in Your Code
|
|
116
|
+
|
|
117
|
+
Inject the provider bound at `@app/config`.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import type { ISecretsHelper } from '@venizia/ignis-helpers';
|
|
121
|
+
|
|
122
|
+
@service()
|
|
123
|
+
export class BillingService {
|
|
124
|
+
constructor(
|
|
125
|
+
@inject({ key: '@app/config' }) private secrets: ISecretsHelper,
|
|
126
|
+
) {}
|
|
127
|
+
|
|
128
|
+
async run() {
|
|
129
|
+
// A single keyed value (TTL-cached):
|
|
130
|
+
const apiKey = await this.secrets.get({ path: 'secret/data/myapp/stripe', key: 'apiKey' });
|
|
131
|
+
|
|
132
|
+
// Or the whole bundle at a path:
|
|
133
|
+
const bundle = await this.secrets.getBundle({ path: 'secret/data/myapp/stripe' });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Code that only relies on hydrated values keeps reading `process.env.APP_ENV_*` and needs no injection at all.
|
|
139
|
+
|
|
140
|
+
## Rotating Database Credentials
|
|
141
|
+
|
|
142
|
+
Dynamic secrets let Vault mint short-lived database credentials that expire and rotate. IGNIS renews them and, on rotation, rebuilds the connection pool gracefully.
|
|
143
|
+
|
|
144
|
+
You do **not** write any rotation code for PostgreSQL. Two steps enable it:
|
|
145
|
+
|
|
146
|
+
1. Configure a dynamic database engine in Vault so a read against `database/creds/<role>` returns fresh credentials with a TTL.
|
|
147
|
+
2. Add a `lease` entry whose `key` is the DI binding key of your datasource (`datasources.<ClassName>`), as in the HashiCorp example above.
|
|
148
|
+
|
|
149
|
+
From there IGNIS:
|
|
150
|
+
|
|
151
|
+
- renews the lease before it expires;
|
|
152
|
+
- when Vault issues fresh credentials, calls the datasource's `onSecretRotated()`, which swaps the new credentials in, builds a new pool, and drains the old one so in-flight transactions finish;
|
|
153
|
+
- keeps the app running - no restart.
|
|
154
|
+
|
|
155
|
+
> [!WARNING] Your datasource configure() must read from this.settings
|
|
156
|
+
> Rotation writes the new credentials onto `this.settings` and re-runs `configure()`. If your `configure()` builds the pool from a hard-coded connection string instead, rotation rebuilds with stale credentials. Build the pool from `this.settings`:
|
|
157
|
+
> ```typescript
|
|
158
|
+
> override configure(): void {
|
|
159
|
+
> this.client = new Pool(this.settings);
|
|
160
|
+
> }
|
|
161
|
+
> ```
|
|
162
|
+
|
|
163
|
+
## Behaviour When the Vault Is Down
|
|
164
|
+
|
|
165
|
+
The failure policy is keyed on `NODE_ENV`:
|
|
166
|
+
|
|
167
|
+
- **Development** (`local`, `debug`, `development`, `dev`, `sit`) - a vault failure logs a warning and falls back to `process.env`, so you can work offline.
|
|
168
|
+
- **Everything else** - a vault failure throws and crashes the boot. The app never starts with missing or empty secrets.
|
|
169
|
+
|
|
170
|
+
## Testing Against a Real Vault
|
|
171
|
+
|
|
172
|
+
A local end-to-end setup (Vault dev-mode plus a throwaway PostgreSQL) is described in `docs/superpowers/vault-integration-local-testing.md` in the repository.
|
|
173
|
+
|
|
174
|
+
## See Also
|
|
175
|
+
|
|
176
|
+
- [Secrets & Vault Reference](/references/base/secrets) - full API, machinery, and const-classes
|
|
177
|
+
- [DataSources](/guides/core-concepts/persistent/datasources) - the pool that rotation rebuilds
|
|
@@ -57,7 +57,7 @@ export class UserService extends BaseService {
|
|
|
57
57
|
|
|
58
58
|
## Registering a Service
|
|
59
59
|
|
|
60
|
-
Registration is always imperative - call `this.service(ClassName)` inside an application lifecycle method
|
|
60
|
+
Registration is always imperative - call `this.service(ClassName)` inside an application lifecycle method, which handles the binding. There is no class-level decorator for this.
|
|
61
61
|
|
|
62
62
|
```typescript
|
|
63
63
|
import { BaseApplication } from '@venizia/ignis';
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
# 5-Minute Quickstart
|
|
2
2
|
|
|
3
|
-
Build
|
|
3
|
+
Build a working IGNIS API: one controller, one route, dependency injection, and generated API docs - no database required.
|
|
4
4
|
|
|
5
|
-
**Time to
|
|
5
|
+
**Time to complete:** ~5 minutes
|
|
6
6
|
|
|
7
|
-
> **
|
|
7
|
+
> **Prerequisite:** [Install Bun](./setup) 1.3 or later before you start.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 1. Create the project
|
|
10
|
+
|
|
11
|
+
Scaffold a project and install IGNIS:
|
|
10
12
|
|
|
11
13
|
```bash
|
|
12
14
|
mkdir my-app && cd my-app
|
|
13
15
|
bun init -y
|
|
14
16
|
bun add hono @hono/zod-openapi @scalar/hono-api-reference @venizia/ignis @venizia/ignis-helpers
|
|
15
|
-
bun add -d typescript @types/bun @venizia/dev-configs
|
|
17
|
+
bun add -d typescript @types/bun @venizia/dev-configs
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
Both commands finish in a few seconds. You now have a `package.json` with IGNIS in `dependencies`.
|
|
21
|
+
|
|
22
|
+
## 2. Configure TypeScript for decorators
|
|
23
|
+
|
|
24
|
+
IGNIS controllers use TypeScript's legacy decorators (`@controller`, `@get`). Set the two decorator flags directly in your own `tsconfig.json`. Bun does not reliably resolve them through an `extends` chain, and a missing flag drops your routes silently.
|
|
19
25
|
|
|
20
26
|
Create `tsconfig.json`:
|
|
21
27
|
|
|
@@ -26,59 +32,23 @@ Create `tsconfig.json`:
|
|
|
26
32
|
"compilerOptions": {
|
|
27
33
|
"outDir": "dist",
|
|
28
34
|
"rootDir": "src",
|
|
29
|
-
"baseUrl": "src",
|
|
30
35
|
"paths": {
|
|
31
|
-
"@/*": ["
|
|
32
|
-
}
|
|
36
|
+
"@/*": ["./src/*"]
|
|
37
|
+
},
|
|
38
|
+
"experimentalDecorators": true,
|
|
39
|
+
"emitDecoratorMetadata": true
|
|
33
40
|
},
|
|
34
41
|
"include": ["src"],
|
|
35
42
|
"exclude": ["node_modules", "dist"]
|
|
36
43
|
}
|
|
37
44
|
```
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
```javascript
|
|
42
|
-
import { eslintConfigs } from "@venizia/dev-configs";
|
|
43
|
-
|
|
44
|
-
export default eslintConfigs;
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Create `.prettierrc.mjs`:
|
|
48
|
-
|
|
49
|
-
```javascript
|
|
50
|
-
import { prettierConfigs } from "@venizia/dev-configs";
|
|
51
|
-
|
|
52
|
-
export default prettierConfigs;
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Create `.prettierignore`:
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
dist
|
|
59
|
-
node_modules
|
|
60
|
-
*.log
|
|
61
|
-
.*-audit.json
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Step 3: Write Your API (2 minutes)
|
|
65
|
-
|
|
66
|
-
:::info What is a Decorator?
|
|
67
|
-
A decorator is a TypeScript feature that adds behavior to classes, methods, or properties. It's the `@something` syntax you see before definitions (like `@controller`, `@get`, `@inject`). Decorators in IGNIS handle routing, dependency injection, and API documentation automatically.
|
|
68
|
-
|
|
69
|
-
[Learn more →](/guides/reference/glossary#decorators)
|
|
70
|
-
:::
|
|
71
|
-
|
|
72
|
-
:::info What is Binding?
|
|
73
|
-
"Binding" means registering a component (like a service or repository) with the application's dependency injection container. Think of it as telling the app: "Hey, this service exists and here's how to create it." Once bound, you can inject it anywhere using `@inject`.
|
|
74
|
-
|
|
75
|
-
[Learn more →](/guides/core-concepts/dependency-injection)
|
|
76
|
-
:::
|
|
46
|
+
## 3. Write the API
|
|
77
47
|
|
|
78
48
|
Create `src/index.ts`:
|
|
79
49
|
|
|
80
50
|
```typescript
|
|
81
|
-
import { z } from
|
|
51
|
+
import { z } from '@hono/zod-openapi';
|
|
82
52
|
import {
|
|
83
53
|
BaseApplication,
|
|
84
54
|
BaseRestController,
|
|
@@ -87,224 +57,107 @@ import {
|
|
|
87
57
|
IApplicationInfo,
|
|
88
58
|
jsonContent,
|
|
89
59
|
ApiReferenceComponent,
|
|
90
|
-
} from
|
|
91
|
-
import { HTTP } from
|
|
92
|
-
import { Context } from
|
|
93
|
-
import appInfo from
|
|
60
|
+
} from '@venizia/ignis';
|
|
61
|
+
import { HTTP } from '@venizia/ignis-helpers';
|
|
62
|
+
import { Context } from 'hono';
|
|
63
|
+
import appInfo from './../package.json';
|
|
94
64
|
|
|
95
|
-
|
|
96
|
-
@controller({ path: "/hello" })
|
|
65
|
+
@controller({ path: '/hello' })
|
|
97
66
|
class HelloController extends BaseRestController {
|
|
98
67
|
constructor() {
|
|
99
|
-
super({ scope:
|
|
68
|
+
super({ scope: 'HelloController', path: '/hello' });
|
|
100
69
|
}
|
|
101
70
|
|
|
102
|
-
//
|
|
103
|
-
// For decorator-based routes (@get, @post), this can be empty.
|
|
71
|
+
// binding() is abstract - leave it empty when every route uses @get/@post decorators.
|
|
104
72
|
override binding() {}
|
|
105
73
|
|
|
106
74
|
@get({
|
|
107
75
|
configs: {
|
|
108
|
-
path:
|
|
76
|
+
path: '/',
|
|
109
77
|
responses: {
|
|
110
78
|
[HTTP.ResultCodes.RS_2.Ok]: jsonContent({
|
|
111
|
-
description:
|
|
79
|
+
description: 'Says hello',
|
|
112
80
|
schema: z.object({ message: z.string() }),
|
|
113
81
|
}),
|
|
114
82
|
},
|
|
115
83
|
},
|
|
116
84
|
})
|
|
117
85
|
sayHello(c: Context) {
|
|
118
|
-
return c.json({ message:
|
|
86
|
+
return c.json({ message: 'Hello from IGNIS!' }, HTTP.ResultCodes.RS_2.Ok);
|
|
119
87
|
}
|
|
120
88
|
}
|
|
121
89
|
|
|
122
|
-
// 2. Create the application
|
|
123
90
|
class App extends BaseApplication {
|
|
124
91
|
getAppInfo(): IApplicationInfo {
|
|
125
92
|
return appInfo;
|
|
126
93
|
}
|
|
127
94
|
|
|
128
|
-
staticConfigure() {
|
|
129
|
-
// Static configuration before dependency injection
|
|
130
|
-
}
|
|
95
|
+
staticConfigure() {}
|
|
131
96
|
|
|
132
97
|
preConfigure() {
|
|
133
98
|
this.component(ApiReferenceComponent);
|
|
134
99
|
this.controller(HelloController);
|
|
135
100
|
}
|
|
136
101
|
|
|
137
|
-
postConfigure() {
|
|
138
|
-
// Configuration after all bindings are complete
|
|
139
|
-
}
|
|
102
|
+
postConfigure() {}
|
|
140
103
|
|
|
141
|
-
setupMiddlewares() {
|
|
142
|
-
// Custom middleware setup (optional)
|
|
143
|
-
}
|
|
104
|
+
setupMiddlewares() {}
|
|
144
105
|
}
|
|
145
106
|
|
|
146
|
-
// 3. Start the server
|
|
147
107
|
const app = new App({
|
|
148
|
-
scope:
|
|
108
|
+
scope: 'App',
|
|
149
109
|
config: {
|
|
150
|
-
host:
|
|
110
|
+
host: '0.0.0.0',
|
|
151
111
|
port: 3000,
|
|
152
|
-
path: { base:
|
|
153
|
-
debug: { shouldShowRoutes: true }, // Prints all registered routes on startup
|
|
112
|
+
path: { base: '/api', isStrict: false },
|
|
154
113
|
},
|
|
155
114
|
});
|
|
156
115
|
|
|
157
|
-
|
|
158
|
-
app.start();
|
|
116
|
+
app.init();
|
|
117
|
+
await app.start();
|
|
159
118
|
```
|
|
160
119
|
|
|
161
|
-
|
|
120
|
+
`@controller` groups routes under `/hello`. `@get` registers a GET route together with its OpenAPI schema. `preConfigure()` wires the controller and the API docs component into dependency injection before the server starts. `app.init()` registers the application's core bindings - call it before `app.start()`.
|
|
162
121
|
|
|
163
|
-
|
|
164
|
-
{
|
|
165
|
-
"name": "5-mins-qs",
|
|
166
|
-
"version": "1.0.0",
|
|
167
|
-
"description": "5-minute quickstart example",
|
|
168
|
-
"private": true,
|
|
169
|
-
"scripts": {
|
|
170
|
-
"start": "bun run src/index.ts",
|
|
171
|
-
"lint": "eslint --report-unused-disable-directives . && prettier \"**/*.{js,ts}\" -l",
|
|
172
|
-
"lint:fix": "eslint --report-unused-disable-directives . --fix && prettier \"**/*.{js,ts}\" --write",
|
|
173
|
-
"build": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
|
|
174
|
-
"clean": "sh ./scripts/clean.sh",
|
|
175
|
-
"rebuild": "bun run clean && bun run build",
|
|
176
|
-
"server:dev": "NODE_ENV=development bun run src/index.ts",
|
|
177
|
-
"server:prod": "NODE_ENV=production bun run dist/index.js"
|
|
178
|
-
},
|
|
179
|
-
"dependencies": {
|
|
180
|
-
"hono": "^4.12.25",
|
|
181
|
-
"@hono/zod-openapi": "latest",
|
|
182
|
-
"@scalar/hono-api-reference": "latest",
|
|
183
|
-
"@venizia/ignis": "latest",
|
|
184
|
-
"@venizia/ignis-helpers": "latest"
|
|
185
|
-
},
|
|
186
|
-
"devDependencies": {
|
|
187
|
-
"typescript": "^6.0.3",
|
|
188
|
-
"@types/bun": "latest",
|
|
189
|
-
"@venizia/dev-configs": "latest",
|
|
190
|
-
"eslint": "^10.5.0",
|
|
191
|
-
"prettier": "^3.8.4",
|
|
192
|
-
"tsc-alias": "^1.8.10"
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
```
|
|
122
|
+
New to decorators or dependency injection? See the [glossary](/guides/reference/glossary#decorators) and [Dependency Injection](../core-concepts/dependency-injection.md).
|
|
196
123
|
|
|
197
|
-
|
|
124
|
+
## 4. Run it
|
|
198
125
|
|
|
199
|
-
|
|
200
|
-
#!/bin/bash
|
|
126
|
+
Start the server:
|
|
201
127
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
128
|
+
```bash
|
|
129
|
+
bun run src/index.ts
|
|
130
|
+
```
|
|
205
131
|
|
|
206
|
-
|
|
207
|
-
rm -f *.log
|
|
208
|
-
rm -f .*.log
|
|
209
|
-
rm -f .*-audit.json
|
|
132
|
+
After a moment you'll see:
|
|
210
133
|
|
|
211
|
-
|
|
134
|
+
```
|
|
135
|
+
[App-start] Server STARTED | Address: 0.0.0.0:3000
|
|
212
136
|
```
|
|
213
137
|
|
|
214
|
-
|
|
138
|
+
In a new terminal, request the endpoint:
|
|
215
139
|
|
|
216
140
|
```bash
|
|
217
|
-
|
|
141
|
+
curl http://localhost:3000/api/hello
|
|
218
142
|
```
|
|
219
143
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
**Response:**
|
|
144
|
+
You get:
|
|
223
145
|
|
|
224
146
|
```json
|
|
225
|
-
{
|
|
147
|
+
{"message":"Hello from IGNIS!"}
|
|
226
148
|
```
|
|
227
149
|
|
|
228
|
-
## View API
|
|
229
|
-
|
|
230
|
-
Open `http://localhost:3000/doc/explorer` to see interactive Swagger UI documentation!
|
|
231
|
-
|
|
232
|
-
## What Just Happened?
|
|
233
|
-
|
|
234
|
-
### Framework Patterns
|
|
235
|
-
|
|
236
|
-
| Component | What It Does |
|
|
237
|
-
|-----------|--------------|
|
|
238
|
-
| `@controller` | Registers a class as an API controller at `/api/hello`. Supports `transport` field for REST (default) or gRPC |
|
|
239
|
-
| `@get` | Defines a GET endpoint with OpenAPI metadata (auto-sets HTTP method) |
|
|
240
|
-
| `Zod schema` | Validates request/response and auto-generates OpenAPI docs |
|
|
241
|
-
| `BaseRestController` | Provides lifecycle hooks, route binding, and OpenAPI integration for REST controllers |
|
|
242
|
-
| `BaseApplication` | Manages dependency injection, middleware, and server startup |
|
|
243
|
-
| `ApiReferenceComponent` | Generates interactive API docs at `/doc/explorer` |
|
|
244
|
-
| `app.start()` | Runs the full lifecycle (preConfigure → register resources → middlewares) then starts HTTP server on port 3000 |
|
|
245
|
-
|
|
246
|
-
### Why Development Configs?
|
|
247
|
-
|
|
248
|
-
You might wonder why we set up TypeScript, ESLint, and Prettier configs in a "quickstart". Here's why:
|
|
249
|
-
|
|
250
|
-
**IGNIS is opinionated about code quality.** We believe clean, consistent code from day one prevents technical debt later. The `@venizia/dev-configs` package provides pre-configured settings that:
|
|
251
|
-
|
|
252
|
-
| Config | Purpose |
|
|
253
|
-
|--------|---------|
|
|
254
|
-
| `tsconfig.json` | Strict TypeScript settings optimized for IGNIS decorators and path aliases |
|
|
255
|
-
| `eslint.config.mjs` | Catches common errors, enforces best practices, works with TypeScript |
|
|
256
|
-
| `.prettierrc.mjs` | Consistent formatting across your team - no more style debates |
|
|
150
|
+
## 5. View the API docs
|
|
257
151
|
|
|
258
|
-
|
|
152
|
+
Open `http://localhost:3000/api/doc/explorer` in your browser. You'll see an interactive Scalar API reference listing `GET /hello`, generated from the Zod schema you wrote.
|
|
259
153
|
|
|
260
|
-
|
|
261
|
-
- **IDE Support** - Better autocomplete, error detection, and refactoring
|
|
262
|
-
- **Team Ready** - New developers can onboard faster with familiar structure
|
|
263
|
-
- **CI/CD Friendly** - Lint and format checks work out of the box
|
|
154
|
+
## What you built
|
|
264
155
|
|
|
265
|
-
|
|
266
|
-
> All configs extend from `@venizia/dev-configs`, so you get updates automatically. Customize by overriding specific rules in your local config files.
|
|
156
|
+
A running IGNIS REST API: one controller, one route, dependency injection wired through `BaseApplication`, and OpenAPI docs served automatically - all in a single file.
|
|
267
157
|
|
|
268
|
-
## Next
|
|
158
|
+
## Next steps
|
|
269
159
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
- **Add a database?** → [Building a CRUD API](../tutorials/building-a-crud-api.md)
|
|
275
|
-
- **Production setup?** → [Complete Setup Guide](../tutorials/complete-installation.md) (ESLint, Prettier, etc.)
|
|
276
|
-
- **Understand the architecture?** → [Core Concepts](../core-concepts/application/)
|
|
277
|
-
|
|
278
|
-
**Quick additions:**
|
|
279
|
-
|
|
280
|
-
**Add a POST endpoint:**
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
@post({
|
|
284
|
-
configs: {
|
|
285
|
-
path: '/greet',
|
|
286
|
-
request: {
|
|
287
|
-
body: jsonContent({
|
|
288
|
-
schema: z.object({ name: z.string() }),
|
|
289
|
-
}),
|
|
290
|
-
},
|
|
291
|
-
responses: {
|
|
292
|
-
[HTTP.ResultCodes.RS_2.Ok]: jsonContent({
|
|
293
|
-
schema: z.object({ greeting: z.string() }),
|
|
294
|
-
}),
|
|
295
|
-
},
|
|
296
|
-
},
|
|
297
|
-
})
|
|
298
|
-
async greet(c: Context) {
|
|
299
|
-
const { name } = c.req.valid('json');
|
|
300
|
-
return c.json({ greeting: `Hello, ${name}!` }, HTTP.ResultCodes.RS_2.Ok);
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
Test it:
|
|
305
|
-
|
|
306
|
-
```bash
|
|
307
|
-
curl -X POST http://localhost:3000/api/hello/greet \
|
|
308
|
-
-H "Content-Type: application/json" \
|
|
309
|
-
-d '{"name":"World"}'
|
|
310
|
-
```
|
|
160
|
+
- Add a database: [Building a CRUD API](../tutorials/building-a-crud-api.md)
|
|
161
|
+
- Add lint, formatting, and build scripts: [Complete Installation](../tutorials/complete-installation.md)
|
|
162
|
+
- Add more routes and methods: [REST Controllers](../core-concepts/rest-controllers.md)
|
|
163
|
+
- Understand the application lifecycle: [Core Concepts: Application](../core-concepts/application/)
|