@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
|
@@ -8,6 +8,23 @@ difficulty: advanced
|
|
|
8
8
|
|
|
9
9
|
Task-oriented examples for the Authorization component. See the [Overview](./) for initial setup and the [API Reference](./api) for every option and class.
|
|
10
10
|
|
|
11
|
+
## Find what you need
|
|
12
|
+
|
|
13
|
+
| You want to | Go to |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Add `authorize` to a REST or gRPC route | [Securing routes](#securing-routes) |
|
|
16
|
+
| Call `authorize()` outside a route config | [Using the standalone authorize() function](#using-the-standalone-authorize-function) |
|
|
17
|
+
| Add custom allow/deny logic before the enforcer | [Voters](#voters) |
|
|
18
|
+
| Bypass the enforcer for trusted roles | [Role-based shortcuts](#role-based-shortcuts) |
|
|
19
|
+
| Wire authorization into generated CRUD routes | [CRUD factory integration](#crud-factory-integration) |
|
|
20
|
+
| Skip authorization for one request at runtime | [Dynamic skip authorization](#dynamic-skip-authorization) |
|
|
21
|
+
| Read the resolved user, rules, or domain in a handler | [Accessing context variables](#accessing-context-variables) |
|
|
22
|
+
| Replace Casbin with your own enforcer | [Custom enforcer](#custom-enforcer) |
|
|
23
|
+
| Store policies in a schema `ScopedCasbinAdapter` doesn't fit | [Custom filtered adapter](#custom-filtered-adapter) |
|
|
24
|
+
| Compare roles by priority | [AuthorizationRole comparison](#authorizationrole-comparison) |
|
|
25
|
+
| Reference a model instead of a hardcoded resource string | [Model-Based Resource References](#model-based-resource-references) |
|
|
26
|
+
| Scope grants to a tenant (multi-tenant apps) | [RBAC with domains](#rbac-with-domains-multi-tenant) |
|
|
27
|
+
|
|
11
28
|
## Securing routes
|
|
12
29
|
|
|
13
30
|
**Imperative route.** Add `authorize` to `defineRoute()`'s `configs`, next to `authenticate`.
|
|
@@ -74,9 +91,9 @@ authorize: [
|
|
|
74
91
|
```
|
|
75
92
|
|
|
76
93
|
> [!NOTE]
|
|
77
|
-
> When several specs run on the same route, rules are built once
|
|
94
|
+
> When several specs run on the same route, rules are built once per ENFORCER, via `enforcer.buildRules()`, and cached on `Authorization.RULES` - a `Map` keyed by enforcer name - for the rest of the request. A second spec on the same enforcer reuses them; a spec on a different enforcer builds its own. The cache used to be a single slot shared by every enforcer, so one enforcer's rules could answer another's check.
|
|
78
95
|
|
|
79
|
-
**gRPC route.** Same `authorize` field, inside RPC metadata
|
|
96
|
+
**gRPC route.** Same `authorize` field, inside RPC metadata. `AbstractGrpcController.buildRpcMiddlewares()` injects it in the same order as REST: authenticate, then authorize.
|
|
80
97
|
|
|
81
98
|
```typescript
|
|
82
99
|
@unary({
|
|
@@ -93,7 +110,7 @@ See [gRPC Controllers](/guides/core-concepts/grpc-controllers) for the full deco
|
|
|
93
110
|
|
|
94
111
|
## Using the standalone `authorize()` function
|
|
95
112
|
|
|
96
|
-
`authorize({ spec, enforcerName? })` returns a plain Hono `MiddlewareHandler
|
|
113
|
+
`authorize({ spec, enforcerName? })` returns a plain Hono `MiddlewareHandler`. Use it outside route configs - for example, when you wire a Hono sub-app directly.
|
|
97
114
|
|
|
98
115
|
```typescript
|
|
99
116
|
import { authorize, authenticate, Authentication, AuthorizationActions } from '@venizia/ignis';
|
|
@@ -149,7 +166,7 @@ authorize: {
|
|
|
149
166
|
```
|
|
150
167
|
|
|
151
168
|
> [!TIP]
|
|
152
|
-
> Default to `ABSTAIN` when a voter has no strong opinion. Only return `DENY` when the request should be blocked regardless of any other check
|
|
169
|
+
> Default to `ABSTAIN` when a voter has no strong opinion. Only return `DENY` when the request should be blocked regardless of any other check. It short-circuits everything, including a later `ALLOW` voter.
|
|
153
170
|
|
|
154
171
|
## Role-based shortcuts
|
|
155
172
|
|
|
@@ -221,7 +238,7 @@ Per-route config is typed `TRouteAuthorizeConfig = { skip: true } | IAuthorizati
|
|
|
221
238
|
|
|
222
239
|
## Dynamic skip authorization
|
|
223
240
|
|
|
224
|
-
Set `Authorization.SKIP_AUTHORIZATION` from an earlier middleware to bypass authorization for that one request (pipeline step 1)
|
|
241
|
+
Set `Authorization.SKIP_AUTHORIZATION` from an earlier middleware to bypass authorization for that one request (pipeline step 1). This is useful for trusted service-to-service calls.
|
|
225
242
|
|
|
226
243
|
```typescript
|
|
227
244
|
import { Authorization } from '@venizia/ignis';
|
|
@@ -250,7 +267,7 @@ c.set(Authorization.RULES, null); // force a rebuild later in the SAME request
|
|
|
250
267
|
```
|
|
251
268
|
|
|
252
269
|
> [!TIP]
|
|
253
|
-
> Rules are cached per-request only - every new HTTP request starts with an empty cache. `c.set(Authorization.RULES, null)` only matters if you need to force a rebuild mid-request
|
|
270
|
+
> Rules are cached per-request only - every new HTTP request starts with an empty cache. `c.set(Authorization.RULES, null)` only matters if you need to force a rebuild mid-request, for example after mutating the user's roles inline.
|
|
254
271
|
|
|
255
272
|
## Custom enforcer
|
|
256
273
|
|
|
@@ -309,7 +326,14 @@ AuthorizationEnforcerRegistry.getInstance().register({
|
|
|
309
326
|
|
|
310
327
|
Use the ready-made [`ScopedCasbinAdapter`](./api#scopedcasbinadapter) for most apps - it reads one edge table and needs no subclassing. Write a custom adapter only when your storage model differs.
|
|
311
328
|
|
|
312
|
-
`BaseFilteredAdapter` provides
|
|
329
|
+
`BaseFilteredAdapter` provides:
|
|
330
|
+
|
|
331
|
+
- Datasource/connector plumbing
|
|
332
|
+
- `isFiltered()`
|
|
333
|
+
- The no-op write methods
|
|
334
|
+
- A `loadLines` helper
|
|
335
|
+
|
|
336
|
+
A subclass implements only `loadFilteredPolicy`: query your store for ONE principal's policies and turn them into casbin lines.
|
|
313
337
|
|
|
314
338
|
```typescript
|
|
315
339
|
import { BaseFilteredAdapter, ICasbinPolicyFilter, type ICasbinPolicySource } from '@venizia/ignis';
|
|
@@ -337,7 +361,7 @@ class MyCustomAdapter extends BaseFilteredAdapter<ICasbinPolicyFilter> {
|
|
|
337
361
|
}
|
|
338
362
|
```
|
|
339
363
|
|
|
340
|
-
|
|
364
|
+
The base has no template-method query hooks or line formatters - a subclass owns its own queries and line construction. See `ScopedCasbinAdapter` for a full reference implementation (role closure, structural trees, soft-delete, schema-qualified SQL).
|
|
341
365
|
|
|
342
366
|
## AuthorizationRole comparison
|
|
343
367
|
|
|
@@ -391,7 +415,7 @@ authorize: {
|
|
|
391
415
|
}
|
|
392
416
|
```
|
|
393
417
|
|
|
394
|
-
**Query every declared principal at runtime
|
|
418
|
+
**Query every declared principal at runtime** - for example, to seed Casbin policies.
|
|
395
419
|
|
|
396
420
|
```typescript
|
|
397
421
|
import { MetadataRegistry } from '@venizia/ignis';
|
|
@@ -409,18 +433,18 @@ registry.getAuthorizeModelSettings({ format: 'array' });
|
|
|
409
433
|
```
|
|
410
434
|
|
|
411
435
|
> [!TIP]
|
|
412
|
-
> Declaring `authorize.principal` on the model makes it the single source of truth for the
|
|
436
|
+
> Declaring `authorize.principal` on the model makes it the single source of truth for the authorization subject. Route configs and policy setup no longer duplicate the string. See the [Persistent Models guide](/guides/core-concepts/persistent/models#authorization-settings) for the full `@model` settings surface.
|
|
413
437
|
|
|
414
438
|
## RBAC with domains (multi-tenant)
|
|
415
439
|
|
|
416
|
-
|
|
440
|
+
Some apps hand out roles **scoped to a specific tenant**. A user might be `owner` in Merchant A, only `viewer` in Merchant B, and hold a global role everywhere too. Casbin's [RBAC with domains](https://casbin.apache.org/docs/rbac-with-domains/) pattern keeps that policy **linear**: `memberships + permissions`, not a `permissions x tenants` cross-product. At 30 tenants and 700 permissions, that's roughly 730 lines instead of 21,000.
|
|
417
441
|
|
|
418
|
-
|
|
442
|
+
You have two ways to get there:
|
|
419
443
|
|
|
420
|
-
| Approach |
|
|
421
|
-
|
|
422
|
-
| **Scoped model (recommended)** | `isScoped: true` + `ScopedCasbinAdapter` + `CASBIN_RBAC_DOMAIN_SCOPED_MODEL
|
|
423
|
-
| **Manual flat model (lower-level)** | Keep a flat `g + p` model
|
|
444
|
+
| Approach | Setup | Matchers |
|
|
445
|
+
|---|---|---|
|
|
446
|
+
| **Scoped model (recommended)** | `isScoped: true` + `ScopedCasbinAdapter` + `CASBIN_RBAC_DOMAIN_SCOPED_MODEL`. Supply the domain per route via `spec.domain`, or globally via `domainResolver`. | Registered for you |
|
|
447
|
+
| **Manual flat model (lower-level)** | Keep a flat `g + p` model. See [The flat model](#the-flat-model). | Register `domainMatching` and `normalizePayloadFn` yourself |
|
|
424
448
|
|
|
425
449
|
### Scoped model + per-route domain (recommended)
|
|
426
450
|
|
|
@@ -483,7 +507,7 @@ m = g(r.sub, p.sub, r.dom) && keyMatch(r.dom, p.dom) && r.obj == p.obj && r.act
|
|
|
483
507
|
```
|
|
484
508
|
|
|
485
509
|
- `g = _, _, _` - the membership relation is **domain-aware** (subject, role, domain).
|
|
486
|
-
- `g(r.sub, p.sub, r.dom)` - the registered domain matching function decides whether the request domain matches the stored membership domain
|
|
510
|
+
- `g(r.sub, p.sub, r.dom)` - the registered domain matching function decides whether the request domain matches the stored membership domain. This is what makes `*` a wildcard.
|
|
487
511
|
- `keyMatch(r.dom, p.dom)` - a **built-in** matcher (no registration needed) that lets a permission with `p.dom = "*"` match any request domain.
|
|
488
512
|
|
|
489
513
|
**Register the domain matching function.** Pass `domainMatching` in the enforcer options - it registers once during `configure()`.
|
|
@@ -520,7 +544,7 @@ AuthorizationEnforcerRegistry.getInstance().register({
|
|
|
520
544
|
> [!NOTE]
|
|
521
545
|
> `domainMatching` is opt-in. When omitted, domains are compared as exact strings and behavior is unchanged. The enforcer calls Casbin's `addNamedDomainMatchingFunc(roleDefinition, Util.keyMatchFunc)` internally - never call it directly.
|
|
522
546
|
|
|
523
|
-
**Choosing the matching function.** `keyMatch` is the safe default for opaque domain identifiers like `Merchant_<uuid
|
|
547
|
+
**Choosing the matching function.** `keyMatch` is the safe default for opaque domain identifiers like `Merchant_<uuid>`. It treats only `*` as special and never splits on `/` or `:`, so it cannot accidentally match one tenant against another. Use the others only for structured path-style domains.
|
|
524
548
|
|
|
525
549
|
| Function | Adds |
|
|
526
550
|
|---|---|
|
|
@@ -530,14 +554,14 @@ AuthorizationEnforcerRegistry.getInstance().register({
|
|
|
530
554
|
| `CasbinDomainMatchingFunctions.KEY_MATCH_4` | `{param}` segments with repeated-name equality checks |
|
|
531
555
|
| `CasbinDomainMatchingFunctions.REGEX_MATCH` | Full regular-expression matching on the stored value |
|
|
532
556
|
|
|
533
|
-
**Policy lines and outcomes**,
|
|
557
|
+
**Policy lines and outcomes**, using the flat model above with `keyMatch` registered on `g`. Each row calls `enforceSync(subject, domain, resource, action)`:
|
|
534
558
|
|
|
535
559
|
| Case | Policy lines | Request | Outcome |
|
|
536
560
|
|------|--------------|---------|---------|
|
|
537
561
|
| Scoped role (owner in a tenant) | `g, User_u, Role_owner, Merchant_A`<br/>`p, Role_owner, *, Material.find, read, allow` | `(User_u, Merchant_A, Material.find, read)` | allow |
|
|
538
562
|
| Scoped role - isolation | (same as above) | `(User_u, Merchant_B, Material.find, read)` | deny (`g` domain doesn't match) |
|
|
539
563
|
| Multi-tenant role | `g, User_u, Role_owner, Merchant_A`<br/>`g, User_u, Role_owner, Merchant_B`<br/>`p, Role_owner, *, Material.find, read, allow` | `(User_u, Merchant_B, Material.find, read)` | allow (one `g` line per tenant; a single `p` line) |
|
|
540
|
-
| Global role (
|
|
564
|
+
| Global role (for example, guest/onboarding) | `g, User_u, Role_guest, *`<br/>`p, Role_guest, *, Organizer.onBoarding, create, allow` | `(User_u, Merchant_anything, Organizer.onBoarding, create)` | allow (wildcard `g` domain) |
|
|
541
565
|
| Direct user permission (scoped) | `p, User_u, Merchant_A, Report.read, read, allow` | `(User_u, Merchant_A, Report.read, read)` | allow (reflexive `g(u,u,dom)` + `keyMatch`) |
|
|
542
566
|
| Direct user permission - isolation | (same as above) | `(User_u, Merchant_B, Report.read, read)` | deny |
|
|
543
567
|
| Deny override | `p, Role_x, *, Secret.read, read, deny`<br/>`p, Role_y, *, Secret.read, read, allow` | any domain where the user has both roles | deny (`!some(p.eft == deny)`) |
|
|
@@ -545,7 +569,7 @@ AuthorizationEnforcerRegistry.getInstance().register({
|
|
|
545
569
|
> [!IMPORTANT]
|
|
546
570
|
> The matching function is applied as `fn(requestDomain, policyDomain)` - the wildcard belongs on the **stored** side. Store only `*` or exact domain values (never `Merchant_*`) to keep tenant isolation guaranteed.
|
|
547
571
|
|
|
548
|
-
**Misconfiguration is caught early.** If `roleDefinition` is not declared under `[role_definition]` in the model, `configure()` throws at boot
|
|
572
|
+
**Misconfiguration is caught early.** If `roleDefinition` is not declared under `[role_definition]` in the model, `configure()` throws at boot. Without that check, Casbin would silently register the function as a no-op, leaving wildcard domains permanently unmatched - global roles would be silently denied.
|
|
549
573
|
|
|
550
574
|
```typescript
|
|
551
575
|
// model declares `g` only
|
|
@@ -38,10 +38,16 @@ curl localhost:3000/health
|
|
|
38
38
|
|
|
39
39
|
## How it works
|
|
40
40
|
|
|
41
|
-
- **Auto-registered controller.** `HealthCheckComponent.binding()` applies `@controller({ path })` to `HealthCheckController` via `Reflect.decorate` at runtime, then calls `this.application.controller(HealthCheckController)
|
|
42
|
-
- **Options are optional, field by field.** `IHealthCheckOptions.restOptions.path` is optional; a partially-filled binding (e.g., `{ restOptions: {} }`) still resolves
|
|
43
|
-
- **The default binding wins the race if you're late.** The constructor
|
|
44
|
-
- **Three route styles, one controller.** `HealthCheckController` demonstrates all three IGNIS route patterns
|
|
41
|
+
- **Auto-registered controller.** `HealthCheckComponent.binding()` applies `@controller({ path })` to `HealthCheckController` via `Reflect.decorate` at runtime, then calls `this.application.controller(HealthCheckController)`. The path comes from DI, not a hardcoded class decorator.
|
|
42
|
+
- **Options are optional, field by field.** `IHealthCheckOptions.restOptions.path` is optional; a partially-filled binding (e.g., `{ restOptions: {} }`) still resolves. The component reads `healthOptions?.restOptions?.path ?? '/health'`, falling back per field rather than discarding the whole binding.
|
|
43
|
+
- **The default binding wins the race if you're late.** The constructor pre-binds `HEALTH_CHECK_OPTIONS` via `initDefault`, filling only an unbound key. A custom binding must exist BEFORE `this.component(HealthCheckComponent)` runs - otherwise the default has already claimed the slot.
|
|
44
|
+
- **Three route styles, one controller.** `HealthCheckController` demonstrates all three IGNIS route patterns - use it as a reference when picking a style for your own controllers:
|
|
45
|
+
|
|
46
|
+
| Style | API | Route |
|
|
47
|
+
|-------|-----|-------|
|
|
48
|
+
| Fluent | `bindRoute().to()` | `GET /` |
|
|
49
|
+
| Decorator | `@api()` | `POST /ping` |
|
|
50
|
+
| Imperative | `defineRoute()` (commented out in source) | - |
|
|
45
51
|
|
|
46
52
|
## Common tasks
|
|
47
53
|
|
|
@@ -214,8 +220,8 @@ export class HealthCheckController extends BaseRestController {
|
|
|
214
220
|
|
|
215
221
|
**Files:**
|
|
216
222
|
|
|
217
|
-
- [`packages/core/src/components/health-check/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/health-check/component.ts) - `HealthCheckComponent`
|
|
218
|
-
- [`packages/core/src/components/health-check/controller.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/health-check/controller.ts) - `HealthCheckController`
|
|
219
|
-
- [`packages/core/src/components/health-check/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/health-check/common/types.ts) - `IHealthCheckOptions`
|
|
220
|
-
- [`packages/core/src/components/health-check/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/health-check/common/keys.ts) - `HealthCheckBindingKeys`
|
|
221
|
-
- [`packages/core/src/components/health-check/common/rest-paths.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/health-check/common/rest-paths.ts) - `HealthCheckRestPaths`
|
|
223
|
+
- [`packages/core-server/src/components/health-check/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/health-check/component.ts) - `HealthCheckComponent`
|
|
224
|
+
- [`packages/core-server/src/components/health-check/controller.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/health-check/controller.ts) - `HealthCheckController`
|
|
225
|
+
- [`packages/core-server/src/components/health-check/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/health-check/common/types.ts) - `IHealthCheckOptions`
|
|
226
|
+
- [`packages/core-server/src/components/health-check/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/health-check/common/keys.ts) - `HealthCheckBindingKeys`
|
|
227
|
+
- [`packages/core-server/src/components/health-check/common/rest-paths.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/health-check/common/rest-paths.ts) - `HealthCheckRestPaths`
|
|
@@ -1,92 +1,26 @@
|
|
|
1
1
|
# Components
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Built-in
|
|
6
|
-
|
|
7
|
-
| Component |
|
|
8
|
-
|
|
9
|
-
| [Authentication](./authentication/) | JWT
|
|
10
|
-
| [Authorization](./authorization/) <Badge type="warning" text="Experimental" /> | Enforcer-based
|
|
11
|
-
| [Health Check](./health-check) |
|
|
12
|
-
| [Mail](./mail/) | Email sending
|
|
13
|
-
| [Request Tracker](./request-tracker) | Request logging |
|
|
14
|
-
| [Socket.IO](./socket-io/) | Real-time
|
|
15
|
-
| [WebSocket](./websocket/) |
|
|
16
|
-
| [Static Asset](./static-asset/) |
|
|
17
|
-
| [
|
|
18
|
-
| [gRPC](/references/base/grpc-controllers) |
|
|
19
|
-
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export class MyCustomComponent extends BaseComponent {
|
|
28
|
-
constructor(
|
|
29
|
-
@inject({ key: CoreBindings.APPLICATION_INSTANCE }) private application: BaseApplication,
|
|
30
|
-
) {
|
|
31
|
-
super({ scope: MyCustomComponent.name });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
override binding(): ValueOrPromise<void> {
|
|
35
|
-
// This is where you bind your component's resources.
|
|
36
|
-
this.application.service(MyCustomService);
|
|
37
|
-
this.application.controller(MyCustomController);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Component Lifecycle
|
|
43
|
-
|
|
44
|
-
| Phase | When | Purpose |
|
|
45
|
-
|-------|------|---------|
|
|
46
|
-
| **`constructor()`** | Component instantiation | Receive dependencies, define default bindings |
|
|
47
|
-
| **`binding()`** | Application startup | Register controllers, services, repositories with DI container |
|
|
48
|
-
|
|
49
|
-
## Registering a Component
|
|
50
|
-
|
|
51
|
-
To use a component, you need to register it with the application instance, usually in the `preConfigure` method of your `Application` class.
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
// in src/application.ts
|
|
55
|
-
import { MyCustomComponent } from './components/my-custom.component';
|
|
56
|
-
|
|
57
|
-
// ... inside your Application class
|
|
58
|
-
|
|
59
|
-
preConfigure(): ValueOrPromise<void> {
|
|
60
|
-
// ...
|
|
61
|
-
this.component(MyCustomComponent);
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
When the application starts, it will automatically call the `binding()` method of the registered component, setting up all the resources it provides.
|
|
66
|
-
|
|
67
|
-
Using components is a great way to organize your application's features into modular, reusable pieces of code, keeping your main application class clean and focused on high-level configuration.
|
|
68
|
-
|
|
69
|
-
## See Also
|
|
70
|
-
|
|
71
|
-
- **Component Guides:**
|
|
72
|
-
- [Components Overview](/guides/core-concepts/components) - What components are
|
|
73
|
-
- [Creating Components](/guides/core-concepts/components-guide) - Build your own components
|
|
74
|
-
|
|
75
|
-
- **Built-in Components:**
|
|
76
|
-
- [Authentication](./authentication/) - JWT/Basic authentication
|
|
77
|
-
- [Authorization](./authorization/) - Enforcer-based authorization
|
|
78
|
-
- [Health Check](./health-check) - Health check endpoints
|
|
79
|
-
- [Mail](./mail/) - Email functionality
|
|
80
|
-
- [Request Tracker](./request-tracker) - Request tracking
|
|
81
|
-
- [Socket.IO](./socket-io/) - Socket.IO WebSocket support
|
|
82
|
-
- [WebSocket](./websocket/) - Bun native WebSocket
|
|
83
|
-
- [Static Asset](./static-asset/) - File upload/download management
|
|
84
|
-
- [Swagger](./api-reference) - API documentation
|
|
85
|
-
- [gRPC](/references/base/grpc-controllers) - gRPC transport (ConnectRPC)
|
|
86
|
-
|
|
87
|
-
- **References:**
|
|
88
|
-
- [BaseComponent API](/references/base/components) - Component base class
|
|
89
|
-
- [Application](/references/base/application) - Registering components
|
|
90
|
-
|
|
91
|
-
- **Best Practices:**
|
|
92
|
-
- [Architectural Patterns](/best-practices/architectural-patterns) - Component design patterns
|
|
3
|
+
Self-contained feature modules you register with `this.component(SomeComponent)`.
|
|
4
|
+
|
|
5
|
+
## Built-in components
|
|
6
|
+
|
|
7
|
+
| Component | What it does | When you reach for it |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| [Authentication](./authentication/) | JWT and Basic auth - token generation, protected routes, multi-strategy | A route needs to know who the caller is |
|
|
10
|
+
| [Authorization](./authorization/) <Badge type="warning" text="Experimental" /> | Enforcer-based RBAC/ABAC, voters, Casbin integration | A route needs a permission check beyond authentication |
|
|
11
|
+
| [Health Check](./health-check) | `/health` endpoint, ping/pong | A load balancer or Kubernetes needs a liveness probe |
|
|
12
|
+
| [Mail](./mail/) | Email sending - multiple transports, templating, queue-based | The app sends transactional or templated email |
|
|
13
|
+
| [Request Tracker](./request-tracker) | Request ID, timing, structured request logging | Always on - registered automatically, nothing to configure |
|
|
14
|
+
| [Socket.IO](./socket-io/) | Real-time over Socket.IO - Redis adapter, event-based | Clients need rooms or Socket.IO-specific features |
|
|
15
|
+
| [WebSocket](./websocket/) | Native Bun WebSocket, Redis pub/sub, heartbeat | Clients need a raw WebSocket without Socket.IO |
|
|
16
|
+
| [Static Asset](./static-asset/) | Upload/download files - MinIO, Bun S3, local disk | The app stores or serves user-uploaded files |
|
|
17
|
+
| [API Reference](./api-reference) | OpenAPI generation, Scalar UI by default, Swagger UI optional | You want a browsable UI for your REST routes |
|
|
18
|
+
| [gRPC](/references/base/grpc-controllers) | ConnectRPC transport, unary RPC, decorator-based | The app serves gRPC alongside or instead of REST |
|
|
19
|
+
|
|
20
|
+
## See also
|
|
21
|
+
|
|
22
|
+
- [Components Overview](/guides/core-concepts/components) - What components are
|
|
23
|
+
- [Creating Components](/guides/core-concepts/components-guide) - Build your own
|
|
24
|
+
- [BaseComponent API](/references/base/components) - Component base class
|
|
25
|
+
- [Application](/references/base/application) - Registering components
|
|
26
|
+
- [Architectural Patterns](/best-practices/architectural-patterns) - Component design patterns
|