@venizia/ignis-docs 0.2.0 → 0.2.1-0
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 +22 -11
- 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 +26 -2
- 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 +6 -2
- 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 +182 -93
- 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 +107 -322
- package/content/extensions/components/authentication/api.md +454 -603
- package/content/extensions/components/authentication/errors.md +121 -498
- package/content/extensions/components/authentication/index.md +88 -801
- package/content/extensions/components/authentication/usage.md +207 -956
- package/content/extensions/components/authorization/api.md +736 -656
- package/content/extensions/components/authorization/errors.md +168 -206
- package/content/extensions/components/authorization/index.md +82 -797
- package/content/extensions/components/authorization/usage.md +194 -527
- package/content/extensions/components/health-check.md +71 -243
- package/content/extensions/components/mail/api.md +504 -287
- package/content/extensions/components/mail/errors.md +73 -61
- package/content/extensions/components/mail/index.md +96 -467
- package/content/extensions/components/mail/usage.md +130 -172
- package/content/extensions/components/request-tracker.md +66 -173
- package/content/extensions/components/socket-io/api.md +195 -13
- package/content/extensions/components/socket-io/errors.md +3 -3
- package/content/extensions/components/socket-io/index.md +50 -337
- package/content/extensions/components/socket-io/usage.md +143 -26
- package/content/extensions/components/static-asset/api.md +410 -142
- package/content/extensions/components/static-asset/errors.md +110 -53
- package/content/extensions/components/static-asset/index.md +79 -608
- package/content/extensions/components/static-asset/usage.md +180 -300
- package/content/extensions/components/websocket/api.md +275 -399
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +74 -407
- package/content/extensions/components/websocket/usage.md +110 -341
- package/content/extensions/helpers/cron/index.md +51 -160
- package/content/extensions/helpers/crypto/index.md +62 -483
- package/content/extensions/helpers/crypto/reference.md +456 -0
- package/content/extensions/helpers/env/index.md +60 -178
- package/content/extensions/helpers/error/index.md +221 -207
- package/content/extensions/helpers/inversion/index.md +65 -556
- package/content/extensions/helpers/inversion/reference.md +522 -0
- package/content/extensions/helpers/kafka/admin.md +20 -1
- package/content/extensions/helpers/kafka/compile-binary.md +41 -35
- package/content/extensions/helpers/kafka/consumer.md +54 -20
- package/content/extensions/helpers/kafka/examples.md +21 -16
- package/content/extensions/helpers/kafka/index.md +80 -610
- package/content/extensions/helpers/kafka/producer.md +134 -5
- package/content/extensions/helpers/kafka/schema-registry.md +45 -70
- package/content/extensions/helpers/logger/hf-logger.md +193 -0
- package/content/extensions/helpers/logger/index.md +64 -563
- package/content/extensions/helpers/logger/pino.md +85 -0
- package/content/extensions/helpers/logger/reference.md +746 -0
- package/content/extensions/helpers/network/api.md +241 -195
- package/content/extensions/helpers/network/index.md +72 -530
- package/content/extensions/helpers/queue/index.md +72 -900
- package/content/extensions/helpers/queue/reference.md +467 -0
- package/content/extensions/helpers/redis/index.md +73 -645
- package/content/extensions/helpers/redis/reference.md +727 -0
- package/content/extensions/helpers/secrets/index.md +66 -0
- package/content/extensions/helpers/socket-io/api.md +305 -203
- package/content/extensions/helpers/socket-io/index.md +66 -432
- package/content/extensions/helpers/storage/api.md +564 -462
- package/content/extensions/helpers/storage/index.md +77 -573
- package/content/extensions/helpers/types/index.md +66 -499
- package/content/extensions/helpers/types/reference.md +650 -0
- package/content/extensions/helpers/uid/index.md +58 -227
- package/content/extensions/helpers/websocket/api.md +329 -216
- package/content/extensions/helpers/websocket/index.md +65 -503
- package/content/extensions/helpers/worker-thread/index.md +58 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
- package/content/guides/core-concepts/persistent/transactions.md +1 -1
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/migrations/redis-helpers-migration.md +1 -1
- package/content/guides/migrations/unified-connectors-migration.md +2 -2
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/references/base/application.md +1 -1
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/datasources-reference.md +599 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +17 -39
- package/content/references/base/filter-system/application-usage.md +69 -121
- package/content/references/base/filter-system/array-operators.md +12 -0
- package/content/references/base/filter-system/comparison-operators.md +12 -0
- package/content/references/base/filter-system/default-filter.md +136 -348
- package/content/references/base/filter-system/fields-order-pagination.md +38 -16
- package/content/references/base/filter-system/index.md +106 -257
- package/content/references/base/filter-system/json-filtering.md +12 -2
- package/content/references/base/filter-system/list-operators.md +16 -2
- package/content/references/base/filter-system/logical-operators.md +13 -0
- package/content/references/base/filter-system/null-operators.md +13 -0
- package/content/references/base/filter-system/pattern-matching.md +12 -0
- package/content/references/base/filter-system/quick-reference.md +11 -2
- package/content/references/base/filter-system/range-operators.md +12 -0
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +156 -233
- package/content/references/base/middlewares.md +35 -21
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +80 -1452
- package/content/references/base/repositories/advanced.md +156 -192
- package/content/references/base/repositories/index.md +77 -650
- package/content/references/base/repositories/mixins.md +22 -18
- package/content/references/base/repositories/relations.md +123 -171
- package/content/references/base/repositories/soft-deletable.md +58 -56
- package/content/references/base/secrets.md +263 -0
- package/content/references/base/services.md +2 -2
- package/content/references/configuration/environment-variables.md +48 -4
- package/content/references/configuration/index.md +49 -31
- 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/index.md +1 -1
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +29 -62
- 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 +57 -218
- 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/package.json +8 -8
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inversion (DI) - Full Reference
|
|
3
|
+
description: Complete reference for Container, Binding, MetadataRegistry, decorators, and every error message
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Inversion (DI) - Full Reference
|
|
8
|
+
|
|
9
|
+
Exhaustive reference for `Container`, `Binding`, `MetadataRegistry`, the `@inject` decorator, and every type, constant, and error message in `@venizia/ignis-inversion`. For a readable introduction and the most common tasks, start with the [Inversion overview](/extensions/helpers/inversion/).
|
|
10
|
+
|
|
11
|
+
**Files:**
|
|
12
|
+
|
|
13
|
+
- [`packages/inversion/src/modules/container/container.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/container.ts) - `Container`
|
|
14
|
+
- [`packages/inversion/src/modules/container/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/base.ts) - `BaseContainer`
|
|
15
|
+
- [`packages/inversion/src/modules/container/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/abstract.ts) - `AbstractContainer`
|
|
16
|
+
- [`packages/inversion/src/modules/binding/binding.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/binding/binding.ts) - `Binding`
|
|
17
|
+
- [`packages/inversion/src/modules/binding/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/binding/common/constants.ts) - `BindingScopes`, `BindingValueTypes`, `BindingKeys`
|
|
18
|
+
- [`packages/inversion/src/modules/binding/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/binding/common/types.ts) - `IBinding`, `IProvider`, `isClassProvider`
|
|
19
|
+
- [`packages/inversion/src/modules/metadata/injectors.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/metadata/injectors.ts) - `@inject`
|
|
20
|
+
- [`packages/inversion/src/modules/metadata/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/metadata/common/constants.ts) - `MetadataKeys`
|
|
21
|
+
- [`packages/inversion/src/modules/registry/registry.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/registry/registry.ts) - `MetadataRegistry`, `metadataRegistry`
|
|
22
|
+
- [`packages/inversion/src/modules/registry/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/registry/common/types.ts) - `IInjectMetadata`, `IPropertyMetadata`
|
|
23
|
+
- [`packages/inversion/src/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/common/types.ts) - `TNullable`, `ValueOrPromise`, `TClass`, `TConstValue`, `isClass`
|
|
24
|
+
- [`packages/inversion/src/modules/error/app-error.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/error/app-error.ts) - `ApplicationError`, `getError`, `isApplicationError`
|
|
25
|
+
- [`packages/inversion/src/modules/error/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/error/types.ts) - `TError`, `TErrorDefinition`, `TErrorNormalized`, `IErrorKeyRegistry`
|
|
26
|
+
- [`packages/inversion/src/common/logger.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/common/logger.ts) - `Logger`
|
|
27
|
+
|
|
28
|
+
## Quick Reference
|
|
29
|
+
|
|
30
|
+
| Item | Value |
|
|
31
|
+
|------|-------|
|
|
32
|
+
| Package | `@venizia/ignis-inversion` |
|
|
33
|
+
| Classes | `Container`, `BaseContainer`, `AbstractContainer`, `Binding`, `MetadataRegistry` |
|
|
34
|
+
| Decorators | `@inject` |
|
|
35
|
+
| Runtimes | Both Bun and Node.js |
|
|
36
|
+
| Build | Dual CJS + ESM |
|
|
37
|
+
|
|
38
|
+
### Import paths
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import {
|
|
42
|
+
Container,
|
|
43
|
+
Binding,
|
|
44
|
+
MetadataRegistry,
|
|
45
|
+
metadataRegistry,
|
|
46
|
+
inject,
|
|
47
|
+
BindingKeys,
|
|
48
|
+
BindingScopes,
|
|
49
|
+
BindingValueTypes,
|
|
50
|
+
MetadataKeys,
|
|
51
|
+
BaseHelper,
|
|
52
|
+
ApplicationError,
|
|
53
|
+
getError,
|
|
54
|
+
isApplicationError,
|
|
55
|
+
MessageCode,
|
|
56
|
+
ErrorScopes,
|
|
57
|
+
Logger,
|
|
58
|
+
isClass,
|
|
59
|
+
isClassProvider,
|
|
60
|
+
} from '@venizia/ignis-inversion';
|
|
61
|
+
|
|
62
|
+
import type {
|
|
63
|
+
TNullable,
|
|
64
|
+
ValueOrPromise,
|
|
65
|
+
ValueOf,
|
|
66
|
+
TClass,
|
|
67
|
+
TConstructor,
|
|
68
|
+
TAbstractConstructor,
|
|
69
|
+
TConstValue,
|
|
70
|
+
TBindingKey,
|
|
71
|
+
TBindingScope,
|
|
72
|
+
TBindingValueType,
|
|
73
|
+
IProvider,
|
|
74
|
+
IBinding,
|
|
75
|
+
IContainer,
|
|
76
|
+
IInjectMetadata,
|
|
77
|
+
IPropertyMetadata,
|
|
78
|
+
IBindingTag,
|
|
79
|
+
} from '@venizia/ignis-inversion';
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> [!NOTE]
|
|
83
|
+
> The framework package `@venizia/ignis` re-exports DI-specific symbols (`Binding`, `BindingKeys`, `BindingScopes`, `BindingValueTypes`, `IProvider`, `isClass`, `isClassProvider`, `TBindingScope`, `TBindingValueType`, `IBindingTag`) from `@venizia/ignis-inversion` and adds higher-level helpers (`app.controller()`, `app.service()`, etc.). All types are also available via type-only re-exports.
|
|
84
|
+
|
|
85
|
+
## Class Hierarchy
|
|
86
|
+
|
|
87
|
+
`Source ->` [`container/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/abstract.ts), [`container/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/base.ts), [`container/container.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/container.ts)
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
AbstractContainer extends BaseHelper implements IContainer # contract only - every member abstract
|
|
91
|
+
└── BaseContainer # storage: bind/lookup/tags/lifecycle, `instantiate` still abstract
|
|
92
|
+
└── Container # instantiate() = two-phase decorator injection
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`AbstractContainer` exists so a container implementation that shares nothing with the shipped storage can start there; one that only wants to vary resolution extends `BaseContainer` instead. `binding/` and `container/` only talk to each other through `IContainer`/`IBinding` - there is no import cycle between the two folders.
|
|
96
|
+
|
|
97
|
+
## Creating a Container
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { Container } from '@venizia/ignis-inversion';
|
|
101
|
+
|
|
102
|
+
const container = new Container({ scope: 'MyApp' });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`scope` is optional and defaults to `'Container'` (or `'BaseContainer'`/`'AbstractContainer'` for those classes). It is passed through to `BaseHelper` and used for logging/error context only - it has no effect on binding resolution.
|
|
106
|
+
|
|
107
|
+
## Container
|
|
108
|
+
|
|
109
|
+
`Source ->` [`container/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/base.ts), [`container/container.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/container/container.ts)
|
|
110
|
+
|
|
111
|
+
| Method | Signature | Description |
|
|
112
|
+
|--------|-----------|--------------|
|
|
113
|
+
| `bind` | `bind<T>(opts: { key: TBindingKey }): Binding<T>` | Create a new `Binding`, register it under `String(key)`, and return it |
|
|
114
|
+
| `get` | `get<T>(opts: { key: TBindingKey \| { namespace, key }, isOptional?: boolean }): T \| undefined` | Resolve a dependency by key. Throws if not found and `isOptional` is falsy |
|
|
115
|
+
| `gets` | `gets<T>(opts: { bindings: Array<{ key, isOptional? }> }): T[]` | Resolve multiple dependencies; every entry is internally re-issued with `isOptional: true` regardless of what was passed |
|
|
116
|
+
| `getBinding` | `getBinding<T>(opts: { key: TBindingKey \| { namespace, key } }): Binding<T> \| undefined` | Retrieve the raw `Binding` without resolving it |
|
|
117
|
+
| `set` | `set<T>(opts: { binding: Binding<T> }): void` | Register an externally created `Binding` under its own `.key` |
|
|
118
|
+
| `isBound` | `isBound(opts: { key: TBindingKey }): boolean` | Check whether a key is registered |
|
|
119
|
+
| `unbind` | `unbind(opts: { key: TBindingKey }): boolean` | Remove a binding; returns `true` if one was removed |
|
|
120
|
+
| `resolve` | `resolve<T>(cls: TClass<T>): T` | Alias for `instantiate` |
|
|
121
|
+
| `instantiate` | `instantiate<T>(cls: TClass<T>): T` | Build an instance with full DI (constructor + property injection), see below |
|
|
122
|
+
| `findByTag` | `findByTag<T>(opts: { tag: string, exclude?: string[] \| Set<string> }): Binding<T>[]` | Find every binding with a matching tag, optionally excluding keys |
|
|
123
|
+
| `clear` | `clear(): void` | Clear every binding's singleton cache; bindings themselves remain registered |
|
|
124
|
+
| `reset` | `reset(): void` | Remove all bindings entirely |
|
|
125
|
+
| `getMetadataRegistry` | `getMetadataRegistry(): MetadataRegistry` | Return the shared `metadataRegistry` singleton |
|
|
126
|
+
|
|
127
|
+
All keys passed to `bind`, `isBound`, and `unbind` are normalized with `String(key)` before being used as the `Map` key - a `Symbol` key resolves to its `.toString()` form (`'Symbol(...)'`), so a `symbol` and the equivalent string are distinct entries.
|
|
128
|
+
|
|
129
|
+
### `instantiate()` - two-phase algorithm
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
override instantiate<T>(cls: TClass<T>): T
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Phase 1 - constructor injection.** Reads `registry.getInjectMetadata({ target: cls })`, which returns the index-keyed `IInjectMetadata[]` array built by `@inject`. For every index in that array:
|
|
136
|
+
|
|
137
|
+
- If the slot is empty (an undecorated parameter left a hole), throws `[ClassName] Constructor parameter N has no @inject | Every parameter of a container-instantiated class must be decorated - the container cannot supply an undecorated one`.
|
|
138
|
+
- Otherwise resolves `this.get({ key: meta.key, isOptional: meta.isOptional ?? false })` and places it at `args[meta.index]`.
|
|
139
|
+
|
|
140
|
+
The array is already index-keyed (`setInjectMetadata` writes to `injects[index]`) - there is no sort step. Once all arguments are resolved, `new cls(...args)` builds the instance.
|
|
141
|
+
|
|
142
|
+
**Phase 2 - property injection.** Reads `registry.getPropertiesMetadata({ target: instance })`. If there is none, returns the instance as-is. Otherwise, for each `[propertyKey, metadata]` entry, resolves `this.get({ key: metadata.bindingKey, isOptional: metadata.optional ?? false })` and assigns it to `instance[propertyKey]`.
|
|
143
|
+
|
|
144
|
+
> [!WARNING]
|
|
145
|
+
> Property injection's optional check reads `metadata.optional`, but `@inject` writes `IPropertyMetadata.isOptional` (see [`IPropertyMetadata`](#metadataregistry-types) below) - `metadata.optional` is always `undefined` at runtime, so `metadata.optional ?? false` always evaluates to `false`. In practice, `@inject({ key, isOptional: true })` on a **property** has no effect: an unbound property dependency still throws. This is a verified source-level discrepancy in `container.ts`, not a documented API - `isOptional` on a **constructor parameter** (`meta.isOptional`, phase 1) works correctly. If you need an optional dependency, use `@inject` on a constructor parameter, or resolve it manually with `container.get({ key, isOptional: true })` inside the constructor.
|
|
146
|
+
|
|
147
|
+
### Key formats
|
|
148
|
+
|
|
149
|
+
`get`, `getBinding`, and `gets` accept three key shapes:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
container.get<UserService>({ key: 'services.UserService' });
|
|
153
|
+
container.get<UserService>({ key: Symbol.for('services.UserService') });
|
|
154
|
+
container.get<UserService>({ key: { namespace: 'services', key: 'UserService' } });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`getBinding` throws `[getBinding] Invalid binding key type | ...` if `opts.key` is not a `string`, `symbol`, or `{ namespace, key }` object.
|
|
158
|
+
|
|
159
|
+
### `gets()` behavior
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const [svcA, svcB] = container.gets<[ServiceA, ServiceB]>({
|
|
163
|
+
bindings: [
|
|
164
|
+
{ key: 'services.ServiceA' },
|
|
165
|
+
{ key: 'services.ServiceB', isOptional: true },
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Internally maps each entry through `this.get({ ...opt, isOptional: true })` - regardless of what `isOptional` was set to on the entry, `gets()` always resolves with `isOptional: true` and returns `undefined` for anything unbound rather than throwing.
|
|
171
|
+
|
|
172
|
+
## Binding
|
|
173
|
+
|
|
174
|
+
`Source ->` [`binding/binding.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/binding/binding.ts)
|
|
175
|
+
|
|
176
|
+
| Method | Signature | Description |
|
|
177
|
+
|--------|-----------|--------------|
|
|
178
|
+
| `toClass` | `toClass(value: TClass<T>): this` | Container instantiates `value` with full DI when resolved |
|
|
179
|
+
| `toValue` | `toValue(value: T): this` | Returns `value` directly, no instantiation |
|
|
180
|
+
| `toProvider` | `toProvider(value: ((container) => T) \| TClass<IProvider<T>>): this` | Factory function, or a class whose prototype has a `value()` method |
|
|
181
|
+
| `setScope` | `setScope(scope: TBindingScope): this` | `'singleton'` or `'transient'` (default) |
|
|
182
|
+
| `setTags` | `setTags(...tags: string[]): this` | Adds tags to the internal `Set<string>` |
|
|
183
|
+
| `hasTag` | `hasTag(tag: string): boolean` | Check for a specific tag |
|
|
184
|
+
| `getTags` | `getTags(): string[]` | All tags as an array |
|
|
185
|
+
| `getScope` | `getScope(): TBindingScope` | Current scope |
|
|
186
|
+
| `getValue` | `getValue(container?: IContainer): T` | Resolve the bound value, respecting scope caching |
|
|
187
|
+
| `getBindingMeta` | `getBindingMeta(opts: { type: TBindingValueType }): TBindingResolverValue<T>` | Raw resolver value; throws if `type` does not match the actual resolver |
|
|
188
|
+
| `clearCache` | `clearCache(): void` | Clears this binding's singleton cache (no-op if nothing cached) |
|
|
189
|
+
| `bind` (static) | `static bind<T>(opts: { key: string }): Binding<T>` | Create a `Binding` outside a container |
|
|
190
|
+
|
|
191
|
+
### Constructor and namespace auto-tagging
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
constructor(opts: { key: string })
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Splits `key` on `.`; if there is more than one segment, the first segment is auto-added as a tag via `setTags()`. `'services.UserService'` auto-tags `'services'`; a key with no `.` gets no automatic tag.
|
|
198
|
+
|
|
199
|
+
### `getValue()` resolution by type
|
|
200
|
+
|
|
201
|
+
| Resolver type | Behavior | Throws when |
|
|
202
|
+
|----------------|----------|--------------|
|
|
203
|
+
| `VALUE` | Returns the stored value directly | Never |
|
|
204
|
+
| `PROVIDER` | If the stored value is a plain function, calls `provider(container)`. If it is a class matching `isClassProvider` (prototype has a `value()` method), the container `instantiate()`s the class first, then calls `.value(container)` on the instance | No `container` argument was passed - `[getValue] Invalid context/container to get provider value` |
|
|
205
|
+
| `CLASS` | `container.instantiate(this.resolver.value)` | No `container` argument was passed - `[getValue] Invalid context/container to instantiate class` |
|
|
206
|
+
|
|
207
|
+
If `bindScope` is `SINGLETON`, the resolved instance is cached on `this.cached` and returned directly on every subsequent call without re-invoking the resolver - caching is per-`Binding` instance, not per-container.
|
|
208
|
+
|
|
209
|
+
### Class-based provider
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { IProvider, Container } from '@venizia/ignis-inversion';
|
|
213
|
+
|
|
214
|
+
class DatabaseConnectionProvider implements IProvider<DatabaseConnection> {
|
|
215
|
+
value(container: Container): DatabaseConnection {
|
|
216
|
+
const config = container.get<Config>({ key: 'config.database' });
|
|
217
|
+
return new DatabaseConnection(config);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
container.bind<DatabaseConnection>({ key: 'db.connection' }).toProvider(DatabaseConnectionProvider);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`isClassProvider` detects this shape at runtime: `typeof target === 'function' && target.prototype && typeof target.prototype.value === 'function'`.
|
|
225
|
+
|
|
226
|
+
### Static factory
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { Binding, BindingScopes } from '@venizia/ignis-inversion';
|
|
230
|
+
|
|
231
|
+
const binding = Binding.bind<IHealthCheckOptions>({ key: 'options.healthCheck' })
|
|
232
|
+
.toValue({ restOptions: { path: '/health' } });
|
|
233
|
+
|
|
234
|
+
container.set({ binding }); // registers under binding.key
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## MetadataRegistry
|
|
238
|
+
|
|
239
|
+
`Source ->` [`registry/registry.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/registry/registry.ts)
|
|
240
|
+
|
|
241
|
+
Singleton (`metadataRegistry`) backing `@inject`, built entirely on `reflect-metadata`'s `Reflect.defineMetadata`/`getMetadata`/`hasMetadata`/`deleteMetadata`. You typically interact with it only through `container.getMetadataRegistry()` or the decorators.
|
|
242
|
+
|
|
243
|
+
| Method | Signature | Description |
|
|
244
|
+
|--------|-----------|--------------|
|
|
245
|
+
| `define` | `define<Target, Value>(opts: { target, key: TBindingKey, value: Value }): void` | Store arbitrary metadata on a target |
|
|
246
|
+
| `get` | `get<Target, Value>(opts: { target, key: TBindingKey }): Value \| undefined` | Retrieve metadata by key |
|
|
247
|
+
| `has` | `has<Target>(opts: { target, key: TBindingKey }): boolean` | Check if metadata exists |
|
|
248
|
+
| `delete` | `delete<Target>(opts: { target, key: TBindingKey }): boolean` | Remove metadata by key |
|
|
249
|
+
| `getKeys` | `getKeys<Target>(opts: { target }): TBindingKey[]` | List all metadata keys (`string`/`symbol` only) on a target |
|
|
250
|
+
| `getMethodNames` | `getMethodNames<T>(opts: { target: TClass<T> }): string[]` | Non-constructor function-valued own property names on the prototype |
|
|
251
|
+
| `clearMetadata` | `clearMetadata<T>(opts: { target }): void` | Delete every metadata key on a target |
|
|
252
|
+
| `setInjectMetadata` | `setInjectMetadata<T>(opts: { target, index: number, metadata: IInjectMetadata }): void` | Write constructor `@inject` metadata at parameter `index` into the `MetadataKeys.INJECT` array |
|
|
253
|
+
| `getInjectMetadata` | `getInjectMetadata<T>(opts: { target }): IInjectMetadata[] \| undefined` | Read the constructor injection array |
|
|
254
|
+
| `setPropertyMetadata` | `setPropertyMetadata<T>(opts: { target, propertyName, metadata: IPropertyMetadata }): void` | Write property `@inject` metadata into a `Map` keyed by property name, stored on `target.constructor` |
|
|
255
|
+
| `getPropertiesMetadata` | `getPropertiesMetadata<T>(opts: { target }): Map<string \| symbol, IPropertyMetadata> \| undefined` | Read the full property metadata map |
|
|
256
|
+
| `getPropertyMetadata` | `getPropertyMetadata<T>(opts: { target, propertyName }): IPropertyMetadata \| undefined` | Read metadata for one property |
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { MetadataKeys, metadataRegistry } from '@venizia/ignis-inversion';
|
|
260
|
+
|
|
261
|
+
MetadataKeys.PROPERTIES; // Symbol.for('ignis:properties')
|
|
262
|
+
MetadataKeys.INJECT; // Symbol.for('ignis:inject')
|
|
263
|
+
|
|
264
|
+
metadataRegistry.define({ target: myObj, key: 'custom:flag', value: true });
|
|
265
|
+
metadataRegistry.get({ target: myObj, key: 'custom:flag' }); // true
|
|
266
|
+
metadataRegistry.has({ target: myObj, key: 'custom:flag' }); // true
|
|
267
|
+
metadataRegistry.delete({ target: myObj, key: 'custom:flag' }); // true
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### MetadataRegistry types
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
interface IInjectMetadata {
|
|
274
|
+
key: TBindingKey;
|
|
275
|
+
index: number;
|
|
276
|
+
isOptional?: boolean;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
interface IPropertyMetadata {
|
|
280
|
+
bindingKey: TBindingKey;
|
|
281
|
+
isOptional?: boolean;
|
|
282
|
+
[key: string]: any;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Decorators
|
|
287
|
+
|
|
288
|
+
`Source ->` [`metadata/injectors.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/metadata/injectors.ts)
|
|
289
|
+
|
|
290
|
+
### `@inject`
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
inject(opts: { key: TBindingKey; isOptional?: boolean; registry?: MetadataRegistry }): PropertyDecorator | ParameterDecorator
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Dispatches on how the decorator was invoked:
|
|
297
|
+
|
|
298
|
+
| Applied to | Detection | Stored via |
|
|
299
|
+
|------------|-----------|------------|
|
|
300
|
+
| Constructor parameter | `parameterIndex` is a `number` | `registry.setInjectMetadata({ target, index: parameterIndex, metadata: { key, index: parameterIndex, isOptional } })` |
|
|
301
|
+
| Class property | `propertyName !== undefined` | `registry.setPropertyMetadata({ target, propertyName, metadata: { bindingKey: key, isOptional } })` |
|
|
302
|
+
| Anything else | neither condition matches | Throws `@inject decorator can only be used on class properties or constructor parameters` |
|
|
303
|
+
|
|
304
|
+
`isOptional` defaults to `false` in both branches. Pass a custom `registry` to target a non-default `MetadataRegistry` instance (rare - almost always omitted, using the shared `metadataRegistry`).
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
class UserService {
|
|
308
|
+
constructor(
|
|
309
|
+
@inject({ key: 'repositories.UserRepository' }) private userRepository: UserRepository,
|
|
310
|
+
@inject({ key: 'services.Logger', isOptional: true }) private logger?: Logger,
|
|
311
|
+
) {}
|
|
312
|
+
|
|
313
|
+
@inject({ key: 'config.retryCount' })
|
|
314
|
+
private retryCount: number;
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Namespaces and Tags
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { BindingKeys } from '@venizia/ignis-inversion';
|
|
322
|
+
|
|
323
|
+
BindingKeys.build({ namespace: 'services', key: 'UserService' });
|
|
324
|
+
// => 'services.UserService'
|
|
325
|
+
|
|
326
|
+
BindingKeys.build({ namespace: '', key: 'UserService' });
|
|
327
|
+
// => 'UserService' (empty namespace segment is dropped)
|
|
328
|
+
|
|
329
|
+
BindingKeys.build({ namespace: 'services', key: '' });
|
|
330
|
+
// throws: [BindingKeys][build] Invalid key to build | key:
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
`key` is required and must be non-empty; `namespace` is optional and silently omitted from the joined string when empty.
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
container.bind({ key: 'workers.EmailWorker' }).toClass(EmailWorker).setTags('background', 'email');
|
|
337
|
+
// tags: ['workers', 'background', 'email']
|
|
338
|
+
|
|
339
|
+
const serviceBindings = container.findByTag({ tag: 'services' });
|
|
340
|
+
const filtered = container.findByTag({ tag: 'services', exclude: ['services.InternalService'] });
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Utilities
|
|
344
|
+
|
|
345
|
+
### ApplicationError and getError
|
|
346
|
+
|
|
347
|
+
`Source ->` [`modules/error/app-error.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/error/app-error.ts)
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
class ApplicationError extends Error {
|
|
351
|
+
statusCode: number;
|
|
352
|
+
normalized: { text: string; code: string; args: Record<string, unknown> };
|
|
353
|
+
extra?: Record<string, unknown>;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
getError(opts: TError): ApplicationError; // factory function
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
`opts.message` accepts two shapes: the historical string (paired with sibling `messageCode?`/`messageArgs?`), or an object mirroring `normalized` - `{ text, code?, args? }`. Both resolve to the same `normalized`; `messageCode`/`messageArgs` are lowest precedence, so `message.code`/`message.args` (or a catalogued definition's own `message.code`/`message.args`) win when both are present. There is no flat `error.messageCode`, and `extra` never mirrors `messageArgs`. `normalized.args` is always populated (`{}` when empty).
|
|
360
|
+
|
|
361
|
+
The catalogued form (`{ error: TErrorDefinition }`) takes `message` as a **partial** override - `{ message: { args } }` amends just the args and keeps the definition's `text`/`code`. `error` is refused on the free-form branch (`error?: never`) - wrap a caught failure with `cause` instead.
|
|
362
|
+
|
|
363
|
+
`ApplicationError`'s constructor defaults `statusCode` to `400` when omitted, and moves any property it does not model into `this.extra`. The error RESPONSE schema (`ErrorSchema`, for OpenAPI) lives in `@venizia/ignis-helpers`, not here - it needs `@hono/zod-openapi`, which inversion must not depend on because it ships to browsers.
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
throw getError({ message: 'Something failed', statusCode: 500, messageCode: 'ERR_INTERNAL' });
|
|
367
|
+
throw new ApplicationError({ message: 'Not found', statusCode: 404 });
|
|
368
|
+
throw new ApplicationError({ message: { text: 'Not found', code: 'core.user.not_found' }, statusCode: 404 });
|
|
369
|
+
|
|
370
|
+
// The code and args are read off `normalized`, never off the error directly.
|
|
371
|
+
error.normalized.code; // 'err_internal'
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
See the [Error reference](/extensions/helpers/error/) for the full input shape, precedence rules, and the catalogued (`TErrorDefinition`) pattern.
|
|
375
|
+
|
|
376
|
+
### Logger
|
|
377
|
+
|
|
378
|
+
`Source ->` [`common/logger.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/common/logger.ts)
|
|
379
|
+
|
|
380
|
+
A minimal `console`-backed static logger, independent of `@venizia/ignis-helpers`' `Logger`/`LoggerFactory` - this one exists so the inversion package has zero dependency on the logging package.
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
Logger.info('Server started on port %d', 3000); // console.log('[INFO] ...')
|
|
384
|
+
Logger.warn('Deprecation warning'); // console.warn('[WARN] ...')
|
|
385
|
+
Logger.error('Connection failed: %s', err.message); // console.error('[ERROR] ...')
|
|
386
|
+
Logger.debug('Resolved binding: %s', key); // console.log('[DEBUG] ...') only if process.env.DEBUG is set
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Type guards and shared types
|
|
390
|
+
|
|
391
|
+
`Source ->` [`common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/common/types.ts)
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
type TNullable<T> = T | undefined | null;
|
|
395
|
+
type ValueOrPromise<T> = T | Promise<T>;
|
|
396
|
+
type ValueOf<T> = T[keyof T];
|
|
397
|
+
type TConstructor<T> = new (...args: any[]) => T;
|
|
398
|
+
type TAbstractConstructor<T> = abstract new (...args: any[]) => T;
|
|
399
|
+
type TClass<T> = TConstructor<T> & { [property: string]: any };
|
|
400
|
+
type TConstValue<T extends TClass<any>> = Extract<ValueOf<T>, string | number>;
|
|
401
|
+
type TBindingKey = string | symbol;
|
|
402
|
+
|
|
403
|
+
interface IBindingTag {
|
|
404
|
+
[name: string]: any;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function isClass<T>(target: any): target is TClass<T>;
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`isClass` tests `typeof target === 'function' && target.prototype !== undefined` plus a regex match on the function's stringified source (`/^class[\s{]/`) - it relies on the class being emitted as an ES2024 `class`, not transpiled down to an ES5 constructor function.
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
interface IProvider<T> {
|
|
414
|
+
value(container: Container): T;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function isClassProvider<T>(target: any): target is TClass<IProvider<T>>;
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Constants
|
|
421
|
+
|
|
422
|
+
| Constant | Values | Description |
|
|
423
|
+
|----------|--------|--------------|
|
|
424
|
+
| `BindingScopes.SINGLETON` | `'singleton'` | Cached after first resolution |
|
|
425
|
+
| `BindingScopes.TRANSIENT` | `'transient'` | New instance each resolution |
|
|
426
|
+
| `BindingValueTypes.CLASS` | `'class'` | Container instantiates with DI |
|
|
427
|
+
| `BindingValueTypes.VALUE` | `'value'` | Direct value return |
|
|
428
|
+
| `BindingValueTypes.PROVIDER` | `'provider'` | Factory function or `IProvider` class |
|
|
429
|
+
| `MetadataKeys.PROPERTIES` | `Symbol.for('ignis:properties')` | Property injection metadata key |
|
|
430
|
+
| `MetadataKeys.INJECT` | `Symbol.for('ignis:inject')` | Constructor injection metadata key |
|
|
431
|
+
|
|
432
|
+
## Troubleshooting
|
|
433
|
+
|
|
434
|
+
### "Binding key: X is not bounded in context!"
|
|
435
|
+
|
|
436
|
+
**Cause:** The dependency was never registered with the container, or the key does not match exactly.
|
|
437
|
+
|
|
438
|
+
**Fix:**
|
|
439
|
+
1. Verify the binding exists: `container.isBound({ key: 'services.UserService' })`.
|
|
440
|
+
2. Check for typos between `@inject({ key: '...' })` and the key used in `container.bind({ key: '...' })`.
|
|
441
|
+
3. If the dependency is genuinely optional, use `@inject({ key: '...', isOptional: true })` on a **constructor parameter** (not a property - see the warning above), or `container.get({ key: '...', isOptional: true })`.
|
|
442
|
+
|
|
443
|
+
### "[getValue] Invalid context/container to instantiate class"
|
|
444
|
+
|
|
445
|
+
**Cause:** A `Binding` configured with `toClass()` was resolved by calling `binding.getValue()` directly, without a `Container` argument.
|
|
446
|
+
|
|
447
|
+
**Fix:** Resolve class bindings through the container - `container.get({ key })` - rather than calling `binding.getValue()` with no arguments.
|
|
448
|
+
|
|
449
|
+
### "[getValue] Invalid context/container to get provider value"
|
|
450
|
+
|
|
451
|
+
**Cause:** A `Binding` configured with `toProvider()` was resolved without a `Container` argument.
|
|
452
|
+
|
|
453
|
+
**Fix:** Same as above - always resolve through `container.get({ key })`.
|
|
454
|
+
|
|
455
|
+
### "[getBindingMeta] Invalid resolver type"
|
|
456
|
+
|
|
457
|
+
**Cause:** `getBindingMeta({ type })` was called with a type that does not match the binding's actual resolver (e.g. `'class'` on a value binding).
|
|
458
|
+
|
|
459
|
+
**Fix:** Match `type` to how the binding was created: `toClass()` -> `'class'`, `toValue()` -> `'value'`, `toProvider()` -> `'provider'`.
|
|
460
|
+
|
|
461
|
+
### "[getBinding] Invalid binding key type"
|
|
462
|
+
|
|
463
|
+
**Cause:** The key passed to `getBinding()` is not a `string`, `symbol`, or `{ namespace, key }` object.
|
|
464
|
+
|
|
465
|
+
**Fix:** Use one of the three supported key formats.
|
|
466
|
+
|
|
467
|
+
### "[BindingKeys][build] Invalid key to build"
|
|
468
|
+
|
|
469
|
+
**Cause:** `BindingKeys.build()` was called with an empty `key`.
|
|
470
|
+
|
|
471
|
+
**Fix:** Provide a non-empty `key`: `BindingKeys.build({ namespace: 'services', key: 'UserService' })`.
|
|
472
|
+
|
|
473
|
+
### "[ClassName] Constructor parameter N has no @inject"
|
|
474
|
+
|
|
475
|
+
**Cause:** A container-instantiated class has a constructor mixing decorated and undecorated parameters. `@inject` stores metadata at the parameter's index, so an undecorated parameter leaves a hole in that array; there is no channel through which the container could supply it anyway.
|
|
476
|
+
|
|
477
|
+
**Fix:** Decorate every constructor parameter with `@inject`. There is no partial-injection escape hatch - if a value does not come from the container (e.g. a plain `scope: string`), pass it through a factory/provider instead of a bare constructor parameter, or have the subclass forward it via its own `@inject`-decorated parameter.
|
|
478
|
+
|
|
479
|
+
### "@inject decorator can only be used on class properties or constructor parameters"
|
|
480
|
+
|
|
481
|
+
**Cause:** `@inject` was applied to something other than a class property or constructor parameter.
|
|
482
|
+
|
|
483
|
+
**Fix:** Only use `@inject` on constructor parameters or class properties.
|
|
484
|
+
|
|
485
|
+
### Property injection returns `undefined` even without `isOptional`
|
|
486
|
+
|
|
487
|
+
**Cause:** Either (a) the class was instantiated with `new MyClass()` directly instead of through the container - only the container reads `@inject` metadata and populates properties - or (b) the binding key really is unbound, and the `isOptional: true` you set on the property has no effect (see the phase-2 warning above, `metadata.optional` vs `metadata.isOptional`).
|
|
488
|
+
|
|
489
|
+
**Fix:** Always use `container.resolve(MyClass)` or `container.instantiate(MyClass)` to create instances. If the dependency may legitimately be absent, inject it on the constructor instead of a property, or resolve it manually inside the constructor with `container.get({ key, isOptional: true })`.
|
|
490
|
+
|
|
491
|
+
### "getInjectMetadata returns undefined"
|
|
492
|
+
|
|
493
|
+
**Cause:** `reflect-metadata` was not imported before decorators were evaluated, or `experimentalDecorators`/`emitDecoratorMetadata` are not enabled in `tsconfig.json`.
|
|
494
|
+
|
|
495
|
+
**Fix:**
|
|
496
|
+
1. Ensure `import 'reflect-metadata'` runs before any decorated class is evaluated - `@venizia/ignis-inversion`'s entry point already does this, so importing anything from the package is enough.
|
|
497
|
+
2. Verify `tsconfig.json` includes:
|
|
498
|
+
```json
|
|
499
|
+
{
|
|
500
|
+
"compilerOptions": {
|
|
501
|
+
"experimentalDecorators": true,
|
|
502
|
+
"emitDecoratorMetadata": true
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Singleton returns a stale instance after rebinding
|
|
508
|
+
|
|
509
|
+
**Cause:** Singleton caching is per-`Binding` object. Holding a direct reference to an old `Binding` (e.g. from `getBinding()`) keeps its cache independent of any new binding registered under the same key.
|
|
510
|
+
|
|
511
|
+
**Fix:**
|
|
512
|
+
1. Always resolve via `container.get()` rather than caching `Binding` references.
|
|
513
|
+
2. Call `container.clear()` to clear every binding's singleton cache without removing registrations.
|
|
514
|
+
3. Call `container.reset()` to remove all bindings entirely.
|
|
515
|
+
|
|
516
|
+
## See also
|
|
517
|
+
|
|
518
|
+
- [Inversion overview](/extensions/helpers/inversion/) - introduction and the most common tasks
|
|
519
|
+
- [Dependency Injection Guide](/guides/core-concepts/dependency-injection) - DI fundamentals in the framework layer
|
|
520
|
+
- [Application](/guides/core-concepts/application/) - `Application` extends `Container`
|
|
521
|
+
- [Dependency Injection API](/references/base/dependency-injection) - the framework-layer DI reference
|
|
522
|
+
- [Architectural Patterns](/best-practices/architectural-patterns) - DI patterns
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Kafka Admin
|
|
3
|
+
description: KafkaAdminHelper - topic, group, offset, ACL, and quota management
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# Admin
|
|
2
8
|
|
|
3
9
|
The `KafkaAdminHelper` wraps `@platformatic/kafka`'s `Admin` with health tracking, graceful shutdown, and broker event callbacks. Use `getAdmin()` to access the full Admin API directly.
|
|
@@ -31,7 +37,7 @@ interface IKafkaAdminOptions extends IKafkaConnectionOptions {
|
|
|
31
37
|
}
|
|
32
38
|
```
|
|
33
39
|
|
|
34
|
-
Plus
|
|
40
|
+
Plus the shared [Connection & Authentication](./producer#connection--authentication) options (`bootstrapBrokers`, `clientId`, `retries`, `sasl`, `tls`, ...), documented once on the Producer page.
|
|
35
41
|
|
|
36
42
|
## Basic Example
|
|
37
43
|
|
|
@@ -188,3 +194,16 @@ await admin.alterConsumerGroupOffsets({
|
|
|
188
194
|
| Method | Signature | Description |
|
|
189
195
|
|--------|-----------|-------------|
|
|
190
196
|
| `describeLogDirs(opts)` | `(opts: { topics }): Promise<BrokerLogDirDescription[]>` | Describe broker log directories |
|
|
197
|
+
|
|
198
|
+
## See also
|
|
199
|
+
|
|
200
|
+
- [Kafka Overview](./) - the four helpers, shared health/close API, and the compile-binary caveat
|
|
201
|
+
- [Producer](./producer) - the shared Connection & Authentication options
|
|
202
|
+
- [Consumer](./consumer) - `groupInstanceId`, rebalance behavior, and lag monitoring for the groups this page manages
|
|
203
|
+
- [Examples & Troubleshooting](./examples) - a full topic-setup script and IoC wiring
|
|
204
|
+
|
|
205
|
+
**Files:**
|
|
206
|
+
|
|
207
|
+
- [`packages/helpers/src/modules/queue/kafka/admin.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/admin.ts) - `KafkaAdminHelper`
|
|
208
|
+
- [`packages/helpers/src/modules/queue/kafka/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/base.ts) - `BaseKafkaHelper`, shared health tracking and shutdown
|
|
209
|
+
- [`packages/helpers/src/modules/queue/kafka/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/common/types.ts) - `IKafkaAdminOptions`
|