@venizia/ignis-docs 0.2.1-0 → 0.2.1-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/content/best-practices/architectural-patterns.md +3 -3
  2. package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
  3. package/content/best-practices/contribution-workflow.md +2 -2
  4. package/content/best-practices/error-handling.md +94 -89
  5. package/content/best-practices/security-guidelines.md +5 -5
  6. package/content/extensions/components/api-reference.md +22 -21
  7. package/content/extensions/components/authentication/api.md +64 -28
  8. package/content/extensions/components/authentication/errors.md +19 -5
  9. package/content/extensions/components/authentication/index.md +19 -18
  10. package/content/extensions/components/authentication/usage.md +55 -30
  11. package/content/extensions/components/authorization/api.md +351 -84
  12. package/content/extensions/components/authorization/errors.md +51 -17
  13. package/content/extensions/components/authorization/getting-started.md +227 -0
  14. package/content/extensions/components/authorization/index.md +24 -16
  15. package/content/extensions/components/authorization/usage.md +45 -21
  16. package/content/extensions/components/health-check.md +15 -9
  17. package/content/extensions/components/index.md +24 -90
  18. package/content/extensions/components/mail/api.md +105 -54
  19. package/content/extensions/components/mail/errors.md +12 -10
  20. package/content/extensions/components/mail/index.md +32 -13
  21. package/content/extensions/components/mail/usage.md +26 -18
  22. package/content/extensions/components/request-tracker.md +18 -14
  23. package/content/extensions/components/socket-io/api.md +377 -882
  24. package/content/extensions/components/socket-io/errors.md +49 -51
  25. package/content/extensions/components/socket-io/index.md +72 -88
  26. package/content/extensions/components/socket-io/usage.md +107 -117
  27. package/content/extensions/components/static-asset/api.md +83 -31
  28. package/content/extensions/components/static-asset/errors.md +18 -7
  29. package/content/extensions/components/static-asset/index.md +18 -11
  30. package/content/extensions/components/static-asset/usage.md +11 -6
  31. package/content/extensions/components/template/index.md +3 -3
  32. package/content/extensions/components/websocket/api.md +58 -27
  33. package/content/extensions/components/websocket/errors.md +3 -3
  34. package/content/extensions/components/websocket/index.md +8 -7
  35. package/content/extensions/components/websocket/usage.md +21 -8
  36. package/content/extensions/helpers/cron/index.md +8 -7
  37. package/content/extensions/helpers/crypto/index.md +16 -8
  38. package/content/extensions/helpers/crypto/reference.md +96 -24
  39. package/content/extensions/helpers/env/index.md +14 -10
  40. package/content/extensions/helpers/error/index.md +99 -23
  41. package/content/extensions/helpers/index.md +61 -47
  42. package/content/extensions/helpers/inversion/index.md +23 -6
  43. package/content/extensions/helpers/inversion/reference.md +30 -22
  44. package/content/extensions/helpers/kafka/admin.md +3 -2
  45. package/content/extensions/helpers/kafka/compile-binary.md +69 -44
  46. package/content/extensions/helpers/kafka/consumer.md +24 -21
  47. package/content/extensions/helpers/kafka/examples.md +22 -234
  48. package/content/extensions/helpers/kafka/index.md +30 -62
  49. package/content/extensions/helpers/kafka/producer.md +31 -26
  50. package/content/extensions/helpers/kafka/schema-registry.md +19 -14
  51. package/content/extensions/helpers/logger/hf-logger.md +49 -22
  52. package/content/extensions/helpers/logger/index.md +37 -12
  53. package/content/extensions/helpers/logger/pino.md +31 -11
  54. package/content/extensions/helpers/logger/reference.md +243 -52
  55. package/content/extensions/helpers/network/api.md +65 -30
  56. package/content/extensions/helpers/network/index.md +32 -11
  57. package/content/extensions/helpers/queue/index.md +17 -6
  58. package/content/extensions/helpers/queue/reference.md +52 -25
  59. package/content/extensions/helpers/redis/index.md +29 -11
  60. package/content/extensions/helpers/redis/reference.md +85 -28
  61. package/content/extensions/helpers/secrets/index.md +82 -12
  62. package/content/extensions/helpers/socket-io/api.md +40 -21
  63. package/content/extensions/helpers/socket-io/index.md +26 -10
  64. package/content/extensions/helpers/storage/api.md +42 -24
  65. package/content/extensions/helpers/storage/index.md +10 -7
  66. package/content/extensions/helpers/types/index.md +20 -7
  67. package/content/extensions/helpers/types/reference.md +53 -14
  68. package/content/extensions/helpers/uid/index.md +166 -10
  69. package/content/extensions/helpers/websocket/api.md +52 -13
  70. package/content/extensions/helpers/websocket/index.md +7 -4
  71. package/content/extensions/helpers/worker-thread/index.md +9 -5
  72. package/content/extensions/helpers/worker-thread/reference.md +20 -20
  73. package/content/extensions/index.md +38 -39
  74. package/content/extensions/src-details/mcp-server.md +96 -548
  75. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  76. package/content/guides/core-concepts/persistent/index.md +5 -1
  77. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  78. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  79. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  80. package/content/guides/core-concepts/persistent/search-typesense.md +26 -14
  81. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  82. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  83. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  84. package/content/guides/get-started/philosophy.md +135 -670
  85. package/content/guides/get-started/setup.md +53 -74
  86. package/content/guides/migrations/redis-helpers-migration.md +4 -3
  87. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  88. package/content/guides/migrations/unified-connectors-migration.md +7 -6
  89. package/content/guides/tutorials/realtime-chat.md +1 -1
  90. package/content/references/base/application.md +63 -21
  91. package/content/references/base/components.md +3 -3
  92. package/content/references/base/connectors.md +14 -14
  93. package/content/references/base/controllers.md +12 -12
  94. package/content/references/base/datasources-reference.md +32 -31
  95. package/content/references/base/datasources.md +6 -6
  96. package/content/references/base/dependency-injection.md +12 -11
  97. package/content/references/base/filter-system/application-usage.md +54 -30
  98. package/content/references/base/filter-system/array-operators.md +24 -46
  99. package/content/references/base/filter-system/comparison-operators.md +47 -67
  100. package/content/references/base/filter-system/default-filter.md +59 -53
  101. package/content/references/base/filter-system/fields-order-pagination.md +92 -146
  102. package/content/references/base/filter-system/index.md +25 -13
  103. package/content/references/base/filter-system/json-filtering.md +45 -184
  104. package/content/references/base/filter-system/list-operators.md +23 -53
  105. package/content/references/base/filter-system/logical-operators.md +63 -121
  106. package/content/references/base/filter-system/null-operators.md +34 -104
  107. package/content/references/base/filter-system/pattern-matching.md +40 -55
  108. package/content/references/base/filter-system/quick-reference.md +86 -198
  109. package/content/references/base/filter-system/range-operators.md +18 -46
  110. package/content/references/base/filter-system/tips.md +6 -6
  111. package/content/references/base/filter-system/use-cases.md +33 -15
  112. package/content/references/base/grpc-controllers.md +53 -17
  113. package/content/references/base/index.md +5 -3
  114. package/content/references/base/middlewares.md +11 -10
  115. package/content/references/base/models-reference.md +17 -17
  116. package/content/references/base/models.md +4 -3
  117. package/content/references/base/providers.md +8 -8
  118. package/content/references/base/repositories/advanced.md +224 -326
  119. package/content/references/base/repositories/index.md +19 -6
  120. package/content/references/base/repositories/mixins.md +5 -5
  121. package/content/references/base/repositories/relations.md +160 -293
  122. package/content/references/base/repositories/soft-deletable.md +16 -6
  123. package/content/references/base/secrets.md +17 -13
  124. package/content/references/base/services.md +6 -4
  125. package/content/references/configuration/environment-variables.md +31 -23
  126. package/content/references/configuration/index.md +6 -4
  127. package/content/references/index.md +1 -1
  128. package/content/references/utilities/duration.md +85 -0
  129. package/content/references/utilities/index.md +5 -1
  130. package/content/references/utilities/jsx-reference.md +11 -11
  131. package/content/references/utilities/jsx.md +2 -2
  132. package/content/references/utilities/module.md +78 -25
  133. package/content/references/utilities/request.md +2 -1
  134. package/content/references/utilities/retry.md +139 -0
  135. package/content/references/utilities/schema.md +2 -2
  136. package/content/references/utilities/statuses-reference.md +4 -4
  137. package/content/references/utilities/statuses.md +5 -5
  138. package/dist/mcp-server/index.js +0 -0
  139. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  140. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  141. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  142. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  143. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  144. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  145. package/package.json +17 -16
@@ -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 (via `enforcer.buildRules()`) and cached on `Authorization.RULES` for the rest of the request - the second spec reuses them instead of rebuilding.
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 - `AbstractGrpcController.buildRpcMiddlewares()` injects it in the same order as REST (authenticate, then authorize).
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` - use it outside route configs, e.g. wiring a Hono sub-app directly.
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 - it short-circuits everything, including a later `ALLOW` voter.
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) - useful for trusted service-to-service calls.
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 (e.g. after mutating the user's roles inline).
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 the datasource/connector plumbing, `isFiltered()`, the no-op write methods, and a `loadLines` helper. A subclass implements only `loadFilteredPolicy` - query your store for ONE principal's policies and turn them into casbin lines.
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
- There are no template-method query hooks or line formatters on the base - 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).
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**, e.g. to seed Casbin policies.
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 model's authorization subject, eliminating string duplication across route configs and policy setup. See the [Persistent Models guide](/guides/core-concepts/persistent/models#authorization-settings) for the full `@model` settings surface.
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
- For apps where a user holds roles **scoped to specific tenants** (and sometimes globally), Casbin's [RBAC with domains](https://casbin.apache.org/docs/rbac-with-domains/) pattern keeps a user's materialized policy **linear** (`memberships + permissions`) instead of a `permissions x tenants` cross-product - 30 tenants x 700 permissions is ~730 lines instead of ~21,000.
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
- There are two ways to get there:
442
+ You have two ways to get there:
419
443
 
420
- | Approach | When |
421
- |---|---|
422
- | **Scoped model (recommended)** | `isScoped: true` + `ScopedCasbinAdapter` + `CASBIN_RBAC_DOMAIN_SCOPED_MODEL`; supply the request domain **per route** via `spec.domain` (or a global `domainResolver`). The enforcer registers its own matchers - no `domainMatching` or `normalizePayloadFn` needed. |
423
- | **Manual flat model (lower-level)** | Keep a flat `g + p` model and register `domainMatching` + `normalizePayloadFn` yourself. See [The flat model](#the-flat-model) below. |
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 (this is what makes `*` a wildcard).
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>` - 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.
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**, given the flat model above with `keyMatch` registered on `g`, request `enforceSync(subject, domain, resource, action)`:
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 (e.g. 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) |
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 - Casbin would otherwise silently register the function as a no-op, leaving wildcard domains permanently unmatched (global roles silently denied).
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)` - 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 registers `HEALTH_CHECK_OPTIONS` via `initDefault: { enable: true }`, which runs before `binding()`. `initDefaultBindings()` only sets a key when `container.isBound()` is false - so a custom binding must exist BEFORE `this.component(HealthCheckComponent)` runs, or the default has already claimed the slot.
44
- - **Three route styles, one controller.** `HealthCheckController` demonstrates all three IGNIS route patterns: fluent (`bindRoute().to()`) for `GET /`, decorator (`@api()`) for `POST /ping`, and imperative (`defineRoute()`, commented out in source) - a handy reference when picking a style for your own controllers.
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
- Reusable, pluggable modules that group together related features. A component can encapsulate various resources such as providers, services, controllers, repositories, or even an entire mini-application, providing a clean way to modularize and share complex logic across IGNIS applications.
4
-
5
- ## Built-in Components
6
-
7
- | Component | Purpose | Key Features |
8
- |-----------|---------|--------------|
9
- | [Authentication](./authentication/) | JWT/Basic auth | Token generation, protected routes, multi-strategy |
10
- | [Authorization](./authorization/) <Badge type="warning" text="Experimental" /> | Enforcer-based authz | RBAC, ABAC, voters, Casbin integration, role shortcuts |
11
- | [Health Check](./health-check) | Monitoring endpoint | `/health` endpoint, ping/pong functionality |
12
- | [Mail](./mail/) | Email sending system | Multiple transports, templating, queue-based processing |
13
- | [Request Tracker](./request-tracker) | Request logging | Request ID generation, timing, structured logging |
14
- | [Socket.IO](./socket-io/) | Real-time communication | WebSocket support, Redis adapter, event-based |
15
- | [WebSocket](./websocket/) | Real-time communication | Bun native WebSocket, Redis Pub/Sub, heartbeat |
16
- | [Static Asset](./static-asset/) | File management | Upload/download files, MinIO, Bun S3 & local filesystem support |
17
- | [Swagger](./api-reference) | API documentation | OpenAPI generation, Swagger UI, Scalar UI |
18
- | [gRPC](/references/base/grpc-controllers) | gRPC transport | ConnectRPC integration, unary RPC, decorator-based |
19
-
20
- ## Creating a Component
21
-
22
- To create a new component, you need to create a class that extends `BaseComponent`.
23
-
24
- ```typescript
25
- import { BaseApplication, BaseComponent, inject, CoreBindings, ValueOrPromise } from '@venizia/ignis';
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