@venizia/ignis-docs 0.0.1-9 → 0.0.2
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/LICENSE.md +1 -0
- package/package.json +2 -2
- package/wiki/changelogs/{v0.0.1-7-initial-architecture.md → 2025-12-16-initial-architecture.md} +20 -12
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +300 -0
- package/wiki/changelogs/2025-12-17-refactor.md +80 -12
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +28 -90
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +101 -297
- package/wiki/changelogs/index.md +20 -8
- package/wiki/changelogs/planned-schema-migrator.md +561 -0
- package/wiki/changelogs/planned-transaction-support.md +216 -0
- package/wiki/changelogs/template.md +123 -0
- package/wiki/get-started/best-practices/api-usage-examples.md +0 -2
- package/wiki/get-started/best-practices/architectural-patterns.md +2 -2
- package/wiki/get-started/best-practices/code-style-standards.md +575 -10
- package/wiki/get-started/best-practices/common-pitfalls.md +5 -3
- package/wiki/get-started/best-practices/contribution-workflow.md +2 -0
- package/wiki/get-started/best-practices/data-modeling.md +91 -34
- package/wiki/get-started/best-practices/security-guidelines.md +3 -1
- package/wiki/get-started/building-a-crud-api.md +3 -3
- package/wiki/get-started/core-concepts/application.md +72 -3
- package/wiki/get-started/core-concepts/bootstrapping.md +566 -0
- package/wiki/get-started/core-concepts/components.md +4 -2
- package/wiki/get-started/core-concepts/persistent.md +350 -378
- package/wiki/get-started/core-concepts/services.md +21 -27
- package/wiki/references/base/bootstrapping.md +789 -0
- package/wiki/references/base/components.md +1 -1
- package/wiki/references/base/dependency-injection.md +95 -2
- package/wiki/references/base/services.md +2 -2
- package/wiki/references/components/authentication.md +4 -3
- package/wiki/references/components/index.md +1 -1
- package/wiki/references/helpers/error.md +2 -2
- package/wiki/references/src-details/boot.md +379 -0
- package/wiki/references/src-details/core.md +2 -2
- package/wiki/changelogs/v0.0.1-8-model-repo-datasource-refactor.md +0 -278
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Deep Dive: Components
|
|
2
2
|
|
|
3
|
-
Technical reference for `BaseComponent
|
|
3
|
+
Technical reference for `BaseComponent`—the foundation for creating reusable, pluggable features in Ignis. Components are powerful containers that can group together multiple providers, services, controllers, repositories, and even entire mini-applications into a single, redistributable module.
|
|
4
4
|
|
|
5
5
|
**File:** `packages/core/src/base/components/base.ts`
|
|
6
6
|
|
|
@@ -13,9 +13,10 @@ Technical reference for the DI system in Ignis - managing resource lifecycles an
|
|
|
13
13
|
| Component | Purpose | Key Methods |
|
|
14
14
|
|-----------|---------|-------------|
|
|
15
15
|
| **Container** | DI registry managing resource lifecycles | `bind()`, `get()`, `instantiate()`, `findByTag()` |
|
|
16
|
-
| **Binding** | Single registered dependency configuration | `toClass()`, `toValue()`, `toProvider()`, `setScope()` |
|
|
16
|
+
| **Binding** | Single registered dependency configuration | `toClass()`, `toValue()`, `toProvider()`, `setScope()`, `setTags()` |
|
|
17
17
|
| **@inject** | Decorator marking injection points | Applied to constructor parameters/properties |
|
|
18
18
|
| **MetadataRegistry** | Stores decorator metadata | Singleton accessed via `getInstance()` |
|
|
19
|
+
| **Boot System** | Automatic artifact discovery and binding | Integrates with Container via tags and bindings |
|
|
19
20
|
|
|
20
21
|
## `Container` Class
|
|
21
22
|
|
|
@@ -81,4 +82,96 @@ The `MetadataRegistry` is a crucial part of the DI and routing systems. It's a s
|
|
|
81
82
|
- When you use a decorator (e.g., `@inject`), it calls a method on the `MetadataRegistry.getInstance()` to store information about the injection (like the binding key and target property/parameter).
|
|
82
83
|
- When the `Container` instantiates a class, it queries the `MetadataRegistry` to find out which dependencies need to be injected and where.
|
|
83
84
|
|
|
84
|
-
You typically won't interact with the `MetadataRegistry` directly, but it's the underlying mechanism that makes the decorator-based DI and routing systems work seamlessly.
|
|
85
|
+
You typically won't interact with the `MetadataRegistry` directly, but it's the underlying mechanism that makes the decorator-based DI and routing systems work seamlessly.
|
|
86
|
+
|
|
87
|
+
## Boot System Integration
|
|
88
|
+
|
|
89
|
+
The boot system (`@venizia/ignis-boot`) extends the DI container to support automatic artifact discovery and registration.
|
|
90
|
+
|
|
91
|
+
### Key Bindings
|
|
92
|
+
|
|
93
|
+
When boot system is enabled, the following bindings are created:
|
|
94
|
+
|
|
95
|
+
| Binding Key | Type | Description |
|
|
96
|
+
|-------------|------|-------------|
|
|
97
|
+
| `@app/instance` | Value | The application container instance |
|
|
98
|
+
| `@app/project_root` | Value | Absolute path to project root |
|
|
99
|
+
| `@app/boot-options` | Value | Boot configuration options |
|
|
100
|
+
| `bootstrapper` | Class (Singleton) | Main boot orchestrator |
|
|
101
|
+
| `booter.DatasourceBooter` | Class (Tagged: 'booter') | Datasource discovery booter |
|
|
102
|
+
| `booter.RepositoryBooter` | Class (Tagged: 'booter') | Repository discovery booter |
|
|
103
|
+
| `booter.ServiceBooter` | Class (Tagged: 'booter') | Service discovery booter |
|
|
104
|
+
| `booter.ControllerBooter` | Class (Tagged: 'booter') | Controller discovery booter |
|
|
105
|
+
|
|
106
|
+
### Tag-based Discovery
|
|
107
|
+
|
|
108
|
+
The boot system uses container tags for automatic discovery:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Register a booter with tag
|
|
112
|
+
this.bind({ key: 'booter.CustomBooter' })
|
|
113
|
+
.toClass(CustomBooter)
|
|
114
|
+
.setTags('booter');
|
|
115
|
+
|
|
116
|
+
// Find all booters
|
|
117
|
+
const booterBindings = this.findByTag<IBooter>({ tag: 'booter' });
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
This pattern allows the `Bootstrapper` to automatically discover and execute all registered booters without explicit registration.
|
|
121
|
+
|
|
122
|
+
### Artifact Bindings
|
|
123
|
+
|
|
124
|
+
Once artifacts are discovered and loaded, they're bound using consistent patterns:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Controllers
|
|
128
|
+
this.bind({ key: 'controllers.UserController' }).toClass(UserController);
|
|
129
|
+
|
|
130
|
+
// Services
|
|
131
|
+
this.bind({ key: 'services.UserService' }).toClass(UserService);
|
|
132
|
+
|
|
133
|
+
// Repositories
|
|
134
|
+
this.bind({ key: 'repositories.UserRepository' }).toClass(UserRepository);
|
|
135
|
+
|
|
136
|
+
// Datasources
|
|
137
|
+
this.bind({ key: 'datasources.PostgresDataSource' }).toClass(PostgresDataSource);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Boot Lifecycle & DI
|
|
141
|
+
|
|
142
|
+
The boot system integrates into the application lifecycle:
|
|
143
|
+
|
|
144
|
+
1. **Application Constructor** - Binds boot infrastructure if `bootOptions` configured
|
|
145
|
+
2. **initialize()** - Calls `boot()` which:
|
|
146
|
+
- Discovers booters from container (via `findByTag`)
|
|
147
|
+
- Instantiates booters (via `container.get()` or `binding.getValue()`)
|
|
148
|
+
- Executes boot phases (configure → discover → load)
|
|
149
|
+
- Each booter binds discovered artifacts to container
|
|
150
|
+
3. **Post-Boot** - All artifacts available for dependency injection
|
|
151
|
+
|
|
152
|
+
**Example Flow:**
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// 1. Boot discovers UserController.js file
|
|
156
|
+
// 2. Boot loads UserController class
|
|
157
|
+
// 3. Boot binds to container:
|
|
158
|
+
app.bind({ key: 'controllers.UserController' }).toClass(UserController);
|
|
159
|
+
|
|
160
|
+
// 4. Later, when UserController is instantiated:
|
|
161
|
+
@injectable()
|
|
162
|
+
class UserController {
|
|
163
|
+
constructor(
|
|
164
|
+
@inject({ key: 'services.UserService' })
|
|
165
|
+
private userService: UserService // Auto-injected!
|
|
166
|
+
) {}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Benefits
|
|
171
|
+
|
|
172
|
+
- **Zero-configuration DI**: Artifacts auto-discovered and registered
|
|
173
|
+
- **Convention-based**: Follow naming patterns, get DI for free
|
|
174
|
+
- **Extensible**: Custom booters integrate seamlessly via tags
|
|
175
|
+
- **Type-safe**: Full TypeScript support throughout boot process
|
|
176
|
+
|
|
177
|
+
> **Learn More:** See [Bootstrapping Concepts](/get-started/core-concepts/bootstrapping.md) and [Boot Package Reference](/references/src-details/boot.md)
|
|
@@ -58,7 +58,7 @@ Services are the core of your application's logic. They act as a bridge between
|
|
|
58
58
|
### Example
|
|
59
59
|
|
|
60
60
|
```typescript
|
|
61
|
-
import { BaseService, inject } from '@venizia/ignis';
|
|
61
|
+
import { BaseService, inject, getError } from '@venizia/ignis';
|
|
62
62
|
import { UserRepository } from '../repositories/user.repository';
|
|
63
63
|
import { TUser } from '../models/entities';
|
|
64
64
|
|
|
@@ -81,7 +81,7 @@ export class UserService extends BaseService {
|
|
|
81
81
|
const user = await this.userRepository.findById({ id: userId });
|
|
82
82
|
|
|
83
83
|
if (!user) {
|
|
84
|
-
throw
|
|
84
|
+
throw getError({ message: 'User not found' });
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// 5. Returns transformed data
|
|
@@ -236,6 +236,7 @@ import {
|
|
|
236
236
|
IJWTTokenPayload,
|
|
237
237
|
JWTTokenService,
|
|
238
238
|
TSignInRequest,
|
|
239
|
+
getError,
|
|
239
240
|
} from '@venizia/ignis';
|
|
240
241
|
import { Context } from 'hono';
|
|
241
242
|
|
|
@@ -256,7 +257,7 @@ export class AuthenticationService extends BaseService implements IAuthService {
|
|
|
256
257
|
const user = { id: 'user-id-from-db', roles: [] }; // Dummy user
|
|
257
258
|
|
|
258
259
|
if (identifier.value !== 'test_username' || credential.value !== 'test_password') {
|
|
259
|
-
throw
|
|
260
|
+
throw getError({ message: 'Invalid credentials' });
|
|
260
261
|
}
|
|
261
262
|
// --- End of custom logic ---
|
|
262
263
|
|
|
@@ -272,12 +273,12 @@ export class AuthenticationService extends BaseService implements IAuthService {
|
|
|
272
273
|
|
|
273
274
|
async signUp(context: Context, opts: any): Promise<any> {
|
|
274
275
|
// Implement your sign-up logic
|
|
275
|
-
throw
|
|
276
|
+
throw getError({ message: 'Method not implemented.' });
|
|
276
277
|
}
|
|
277
278
|
|
|
278
279
|
async changePassword(context: Context, opts: any): Promise<any> {
|
|
279
280
|
// Implement your change password logic
|
|
280
|
-
throw
|
|
281
|
+
throw getError({ message: 'Method not implemented.' });
|
|
281
282
|
}
|
|
282
283
|
}
|
|
283
284
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Components
|
|
2
2
|
|
|
3
|
-
Reusable, pluggable modules that
|
|
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
4
|
|
|
5
5
|
## Built-in Components
|
|
6
6
|
|
|
@@ -26,10 +26,10 @@ Extends native `Error` with HTTP status codes and machine-readable message codes
|
|
|
26
26
|
You can create a new `ApplicationError` with a message, status code, and an optional message code.
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
import {
|
|
29
|
+
import { getError, HTTP } from '@venizia/ignis';
|
|
30
30
|
|
|
31
31
|
// Throw an error for a resource not found
|
|
32
|
-
throw
|
|
32
|
+
throw getError({
|
|
33
33
|
message: 'User not found',
|
|
34
34
|
statusCode: HTTP.ResultCodes.RS_4.NotFound,
|
|
35
35
|
messageCode: 'USER_NOT_FOUND',
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# @venizia/ignis-boot
|
|
2
|
+
|
|
3
|
+
> **Package**: `@venizia/ignis-boot`
|
|
4
|
+
> **Purpose**: Application bootstrapping system with artifact auto-discovery
|
|
5
|
+
> **Version**: 0.0.0
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The `@venizia/ignis-boot` package provides a powerful bootstrapping system that automatically discovers and loads application artifacts (controllers, services, repositories, datasources) during application startup. It eliminates the need for manual registration of each artifact, making application setup cleaner and more maintainable.
|
|
10
|
+
|
|
11
|
+
## Key Concepts
|
|
12
|
+
|
|
13
|
+
### Boot Phases
|
|
14
|
+
|
|
15
|
+
The boot process consists of three phases executed in order:
|
|
16
|
+
|
|
17
|
+
1. **Configure** - Booters configure their discovery patterns
|
|
18
|
+
2. **Discover** - Booters scan filesystem for matching artifacts
|
|
19
|
+
3. **Load** - Booters load classes and bind them to the application container
|
|
20
|
+
|
|
21
|
+
### Artifacts
|
|
22
|
+
|
|
23
|
+
An artifact is any application component that can be auto-discovered:
|
|
24
|
+
- **Controllers** - REST/API endpoint handlers
|
|
25
|
+
- **Services** - Business logic layer
|
|
26
|
+
- **Repositories** - Data access layer
|
|
27
|
+
- **Datasources** - Database connections
|
|
28
|
+
|
|
29
|
+
### Booters
|
|
30
|
+
|
|
31
|
+
Booters are specialized classes that handle discovery and loading of specific artifact types. Each booter:
|
|
32
|
+
- Defines default discovery patterns (directories, file extensions)
|
|
33
|
+
- Scans filesystem for matching files
|
|
34
|
+
- Loads classes from discovered files
|
|
35
|
+
- Binds loaded classes to application container
|
|
36
|
+
|
|
37
|
+
## Core Components
|
|
38
|
+
|
|
39
|
+
### Bootstrapper
|
|
40
|
+
|
|
41
|
+
Orchestrates the entire boot process.
|
|
42
|
+
|
|
43
|
+
| Feature | Description |
|
|
44
|
+
|---------|-------------|
|
|
45
|
+
| **Phase Execution** | Runs configure → discover → load phases |
|
|
46
|
+
| **Booter Discovery** | Automatically finds all registered booters |
|
|
47
|
+
| **Error Handling** | Catches and reports errors during boot |
|
|
48
|
+
| **Performance Tracking** | Measures time taken for each phase |
|
|
49
|
+
|
|
50
|
+
**Usage:**
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { Bootstrapper, IBootExecutionOptions } from '@venizia/ignis-boot';
|
|
54
|
+
|
|
55
|
+
const bootstrapper = app.get<Bootstrapper>({ key: 'bootstrapper' });
|
|
56
|
+
await bootstrapper.boot({
|
|
57
|
+
phases: ['configure', 'discover', 'load'], // optional, default: all phases
|
|
58
|
+
booters: ['ControllerBooter', 'ServiceBooter'], // optional, default: all booters
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### BaseArtifactBooter
|
|
63
|
+
|
|
64
|
+
Abstract base class for creating custom booters.
|
|
65
|
+
|
|
66
|
+
| Method | Phase | Description |
|
|
67
|
+
|--------|-------|-------------|
|
|
68
|
+
| `configure()` | Configure | Sets up discovery patterns |
|
|
69
|
+
| `discover()` | Discover | Scans filesystem for artifacts |
|
|
70
|
+
| `load()` | Load | Loads classes and binds to container |
|
|
71
|
+
| `getPattern()` | - | Generates glob pattern for file discovery |
|
|
72
|
+
| `bind()` | - | Abstract method - implement to bind loaded classes |
|
|
73
|
+
|
|
74
|
+
**Custom Booter Example:**
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { BaseArtifactBooter, IBooterOptions } from '@venizia/ignis-boot';
|
|
78
|
+
import { inject } from '@venizia/ignis-inversion';
|
|
79
|
+
|
|
80
|
+
export class CustomBooter extends BaseArtifactBooter {
|
|
81
|
+
constructor(
|
|
82
|
+
@inject({ key: '@app/project_root' }) root: string,
|
|
83
|
+
@inject({ key: '@app/instance' }) private app: IApplication,
|
|
84
|
+
@inject({ key: '@app/boot-options' }) bootOptions: IBootOptions,
|
|
85
|
+
) {
|
|
86
|
+
super({
|
|
87
|
+
scope: CustomBooter.name,
|
|
88
|
+
root,
|
|
89
|
+
artifactOptions: bootOptions.custom ?? {}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
protected getDefaultDirs(): string[] {
|
|
94
|
+
return ['custom'];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected getDefaultExtensions(): string[] {
|
|
98
|
+
return ['.custom.js'];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected async bind(): Promise<void> {
|
|
102
|
+
for (const cls of this.loadedClasses) {
|
|
103
|
+
this.app.bind({ key: `custom.${cls.name}` }).toClass(cls);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Built-in Booters
|
|
110
|
+
|
|
111
|
+
#### ControllerBooter
|
|
112
|
+
|
|
113
|
+
Auto-discovers and registers controllers.
|
|
114
|
+
|
|
115
|
+
| Configuration | Default Value |
|
|
116
|
+
|---------------|---------------|
|
|
117
|
+
| **Directories** | `['controllers']` |
|
|
118
|
+
| **Extensions** | `['.controller.js']` |
|
|
119
|
+
| **Binding Pattern** | `controllers.{ClassName}` |
|
|
120
|
+
|
|
121
|
+
#### ServiceBooter
|
|
122
|
+
|
|
123
|
+
Auto-discovers and registers services.
|
|
124
|
+
|
|
125
|
+
| Configuration | Default Value |
|
|
126
|
+
|---------------|---------------|
|
|
127
|
+
| **Directories** | `['services']` |
|
|
128
|
+
| **Extensions** | `['.service.js']` |
|
|
129
|
+
| **Binding Pattern** | `services.{ClassName}` |
|
|
130
|
+
|
|
131
|
+
#### RepositoryBooter
|
|
132
|
+
|
|
133
|
+
Auto-discovers and registers repositories.
|
|
134
|
+
|
|
135
|
+
| Configuration | Default Value |
|
|
136
|
+
|---------------|---------------|
|
|
137
|
+
| **Directories** | `['repositories']` |
|
|
138
|
+
| **Extensions** | `['.repository.js']` |
|
|
139
|
+
| **Binding Pattern** | `repositories.{ClassName}` |
|
|
140
|
+
|
|
141
|
+
#### DatasourceBooter
|
|
142
|
+
|
|
143
|
+
Auto-discovers and registers datasources.
|
|
144
|
+
|
|
145
|
+
| Configuration | Default Value |
|
|
146
|
+
|---------------|---------------|
|
|
147
|
+
| **Directories** | `['datasources']` |
|
|
148
|
+
| **Extensions** | `['.datasource.js']` |
|
|
149
|
+
| **Binding Pattern** | `datasources.{ClassName}` |
|
|
150
|
+
|
|
151
|
+
### BootMixin
|
|
152
|
+
|
|
153
|
+
Mixin that adds bootable capability to any application.
|
|
154
|
+
|
|
155
|
+
**Features:**
|
|
156
|
+
- Automatically binds default booters
|
|
157
|
+
- Exposes `boot()` method
|
|
158
|
+
- Configurable via `bootOptions`
|
|
159
|
+
|
|
160
|
+
**Usage:**
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { BootMixin } from '@venizia/ignis-boot';
|
|
164
|
+
import { Container } from '@venizia/ignis-inversion';
|
|
165
|
+
|
|
166
|
+
class MyApp extends BootMixin(Container) {
|
|
167
|
+
bootOptions = {
|
|
168
|
+
controllers: {
|
|
169
|
+
dirs: ['private-controllers', 'public-controllers'],
|
|
170
|
+
extensions: ['.controller.js', '.controller.ts']
|
|
171
|
+
},
|
|
172
|
+
services: {
|
|
173
|
+
isNested: true // scan subdirectories
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const app = new MyApp();
|
|
179
|
+
await app.boot();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Boot Options
|
|
183
|
+
|
|
184
|
+
Configure artifact discovery per artifact type.
|
|
185
|
+
|
|
186
|
+
### IArtifactOptions
|
|
187
|
+
|
|
188
|
+
| Property | Type | Default | Description |
|
|
189
|
+
|----------|------|---------|-------------|
|
|
190
|
+
| `dirs` | `string[]` | Varies | Directories to scan |
|
|
191
|
+
| `extensions` | `string[]` | Varies | File extensions to match |
|
|
192
|
+
| `isNested` | `boolean` | `true` | Scan subdirectories |
|
|
193
|
+
| `glob` | `string` | - | Custom glob pattern (overrides dirs/extensions) |
|
|
194
|
+
|
|
195
|
+
### IBootOptions
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
interface IBootOptions {
|
|
199
|
+
controllers?: IArtifactOptions;
|
|
200
|
+
services?: IArtifactOptions;
|
|
201
|
+
repositories?: IArtifactOptions;
|
|
202
|
+
datasources?: IArtifactOptions;
|
|
203
|
+
[artifactType: string]: IArtifactOptions | undefined;
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Example Configuration:**
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
const bootOptions: IBootOptions = {
|
|
211
|
+
controllers: {
|
|
212
|
+
dirs: ['controllers/private', 'controllers/public'],
|
|
213
|
+
extensions: ['.controller.js'],
|
|
214
|
+
isNested: true
|
|
215
|
+
},
|
|
216
|
+
repositories: {
|
|
217
|
+
glob: 'data-access/**/*.repository.js' // custom pattern
|
|
218
|
+
},
|
|
219
|
+
services: {
|
|
220
|
+
dirs: ['services'],
|
|
221
|
+
extensions: ['.service.js', '.service.ts'],
|
|
222
|
+
isNested: false // only scan root level
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Integration with Core
|
|
228
|
+
|
|
229
|
+
### BaseApplication Integration
|
|
230
|
+
|
|
231
|
+
Boot system is integrated into `BaseApplication` via `IBootableApplication` interface:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
export abstract class BaseApplication
|
|
235
|
+
extends AbstractApplication
|
|
236
|
+
implements IRestApplication, IBootableApplication {
|
|
237
|
+
|
|
238
|
+
bootOptions?: IBootOptions;
|
|
239
|
+
|
|
240
|
+
boot(): Promise<IBootReport> {
|
|
241
|
+
const bootstrapper = this.get<Bootstrapper>({ key: 'bootstrapper' });
|
|
242
|
+
return bootstrapper.boot({});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Automatic Initialization
|
|
248
|
+
|
|
249
|
+
If `bootOptions` is defined in application config, boot runs automatically during `initialize()`:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
override async initialize() {
|
|
253
|
+
if (this.configs.bootOptions) {
|
|
254
|
+
// Bind boot infrastructure
|
|
255
|
+
this.bind({ key: '@app/boot-options' }).toValue(this.bootOptions ?? {});
|
|
256
|
+
this.bind({ key: 'bootstrapper' }).toClass(Bootstrapper);
|
|
257
|
+
|
|
258
|
+
// Register default booters
|
|
259
|
+
this.booter(DatasourceBooter);
|
|
260
|
+
this.booter(RepositoryBooter);
|
|
261
|
+
this.booter(ServiceBooter);
|
|
262
|
+
this.booter(ControllerBooter);
|
|
263
|
+
|
|
264
|
+
// Execute boot
|
|
265
|
+
await this.boot();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ... rest of initialization
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Utilities
|
|
273
|
+
|
|
274
|
+
### discoverFiles
|
|
275
|
+
|
|
276
|
+
Discovers files matching a glob pattern.
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
const files = await discoverFiles({
|
|
280
|
+
pattern: 'controllers/**/*.controller.js',
|
|
281
|
+
root: '/path/to/project'
|
|
282
|
+
});
|
|
283
|
+
// Returns: ['/path/to/project/controllers/user.controller.js', ...]
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### loadClasses
|
|
287
|
+
|
|
288
|
+
Loads class constructors from files.
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
const classes = await loadClasses({
|
|
292
|
+
files: ['/path/to/file1.js', '/path/to/file2.js'],
|
|
293
|
+
root: '/path/to/project'
|
|
294
|
+
});
|
|
295
|
+
// Returns: [UserController, ProductController, ...]
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### isClass
|
|
299
|
+
|
|
300
|
+
Type guard to check if value is a class constructor.
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
if (isClass(exported)) {
|
|
304
|
+
// exported is TClass<any>
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Complete Example
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { BaseApplication, IApplicationConfigs } from '@venizia/ignis';
|
|
312
|
+
import { IBootOptions } from '@venizia/ignis-boot';
|
|
313
|
+
|
|
314
|
+
export const appConfigs: IApplicationConfigs = {
|
|
315
|
+
name: 'MyApp',
|
|
316
|
+
bootOptions: {
|
|
317
|
+
controllers: {
|
|
318
|
+
dirs: ['controllers'],
|
|
319
|
+
extensions: ['.controller.js'],
|
|
320
|
+
isNested: true
|
|
321
|
+
},
|
|
322
|
+
services: {
|
|
323
|
+
dirs: ['services'],
|
|
324
|
+
extensions: ['.service.js'],
|
|
325
|
+
isNested: true
|
|
326
|
+
},
|
|
327
|
+
repositories: {
|
|
328
|
+
dirs: ['repositories'],
|
|
329
|
+
extensions: ['.repository.js']
|
|
330
|
+
},
|
|
331
|
+
datasources: {
|
|
332
|
+
dirs: ['datasources'],
|
|
333
|
+
extensions: ['.datasource.js']
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
export class MyApp extends BaseApplication {
|
|
339
|
+
constructor() {
|
|
340
|
+
super(appConfigs);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Boot runs automatically during initialize()
|
|
345
|
+
const app = new MyApp();
|
|
346
|
+
await app.start(); // Calls initialize() which triggers boot
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Benefits
|
|
350
|
+
|
|
351
|
+
| Benefit | Description |
|
|
352
|
+
|---------|-------------|
|
|
353
|
+
| **Auto-discovery** | No manual registration of controllers/services/repositories |
|
|
354
|
+
| **Convention-based** | Follow naming conventions, framework handles the rest |
|
|
355
|
+
| **Flexible** | Customize discovery patterns per artifact type |
|
|
356
|
+
| **Extensible** | Create custom booters for new artifact types |
|
|
357
|
+
| **Performance** | Track boot time per phase |
|
|
358
|
+
| **Developer Experience** | Focus on writing code, not wiring infrastructure |
|
|
359
|
+
|
|
360
|
+
## When to Use
|
|
361
|
+
|
|
362
|
+
✅ **Use Boot System When:**
|
|
363
|
+
- Building applications with many controllers/services/repositories
|
|
364
|
+
- Want convention-over-configuration approach
|
|
365
|
+
- Need consistent artifact registration across projects
|
|
366
|
+
- Building modular applications with clear folder structure
|
|
367
|
+
|
|
368
|
+
❌ **Manual Registration When:**
|
|
369
|
+
- Very small applications (< 5 artifacts)
|
|
370
|
+
- Need fine-grained control over registration order
|
|
371
|
+
- Dynamic artifact registration based on runtime conditions
|
|
372
|
+
- Artifacts don't follow file naming conventions
|
|
373
|
+
|
|
374
|
+
## Related Documentation
|
|
375
|
+
|
|
376
|
+
- [Bootstrapping Concepts](/get-started/core-concepts/bootstrapping.md)
|
|
377
|
+
- [Application Guide](/get-started/core-concepts/application.md)
|
|
378
|
+
- [Dependency Injection](/references/base/dependency-injection.md)
|
|
379
|
+
- [Core Package](/references/src-details/core.md)
|
|
@@ -52,8 +52,8 @@ This is the foundational layer of Ignis, defining the core architecture and abst
|
|
|
52
52
|
| File/Folder | Purpose/Key Details |
|
|
53
53
|
| :------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
54
54
|
| `abstract.ts` | Defines `AbstractApplication`, the base class for Ignis applications. Handles core server setup (Hono instance, runtime detection for Bun/Node.js), environment validation, and route inspection. Mandates abstract methods for middleware setup and configuration. |
|
|
55
|
-
| `base.ts` | Extends `AbstractApplication` to provide `BaseApplication`, implementing common functionalities like component, controller, service, repository, and datasource registration. Includes default middleware registration (e.g., error handling, favicon, request tracking) and startup information logging. |
|
|
56
|
-
| `types.ts` | Contains interfaces for application configurations (`IApplicationConfigs`), application information (`IApplicationInfo`), and various middleware options (e.g., `ICORSOptions`, `ICSRFOptions`).
|
|
55
|
+
| `base.ts` | Extends `AbstractApplication` to provide `BaseApplication`, implementing common functionalities like component, controller, service, repository, and datasource registration. Includes default middleware registration (e.g., error handling, favicon, request tracking) and startup information logging. Integrates with `@venizia/ignis-boot` for automatic artifact discovery when `bootOptions` is configured. |
|
|
56
|
+
| `types.ts` | Contains interfaces for application configurations (`IApplicationConfigs`), application information (`IApplicationInfo`), and various middleware options (e.g., `ICORSOptions`, `ICSRFOptions`). Now includes `IBootableApplication` interface for boot system integration. |
|
|
57
57
|
|
|
58
58
|
#### `base/components`
|
|
59
59
|
|