@venizia/ignis-docs 0.0.1-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mcp-server/dist/common/config.d.ts +27 -0
- package/mcp-server/dist/common/config.d.ts.map +1 -0
- package/mcp-server/dist/common/config.js +27 -0
- package/mcp-server/dist/common/config.js.map +1 -0
- package/mcp-server/dist/common/index.d.ts +3 -0
- package/mcp-server/dist/common/index.d.ts.map +1 -0
- package/mcp-server/dist/common/index.js +19 -0
- package/mcp-server/dist/common/index.js.map +1 -0
- package/mcp-server/dist/common/paths.d.ts +13 -0
- package/mcp-server/dist/common/paths.d.ts.map +1 -0
- package/mcp-server/dist/common/paths.js +23 -0
- package/mcp-server/dist/common/paths.js.map +1 -0
- package/mcp-server/dist/helpers/docs.helper.d.ts +81 -0
- package/mcp-server/dist/helpers/docs.helper.d.ts.map +1 -0
- package/mcp-server/dist/helpers/docs.helper.js +171 -0
- package/mcp-server/dist/helpers/docs.helper.js.map +1 -0
- package/mcp-server/dist/helpers/index.d.ts +3 -0
- package/mcp-server/dist/helpers/index.d.ts.map +1 -0
- package/mcp-server/dist/helpers/index.js +19 -0
- package/mcp-server/dist/helpers/index.js.map +1 -0
- package/mcp-server/dist/helpers/logger.helper.d.ts +7 -0
- package/mcp-server/dist/helpers/logger.helper.d.ts.map +1 -0
- package/mcp-server/dist/helpers/logger.helper.js +22 -0
- package/mcp-server/dist/helpers/logger.helper.js.map +1 -0
- package/mcp-server/dist/index.d.ts +3 -0
- package/mcp-server/dist/index.d.ts.map +1 -0
- package/mcp-server/dist/index.js +62 -0
- package/mcp-server/dist/index.js.map +1 -0
- package/mcp-server/dist/tools/base.tool.d.ts +98 -0
- package/mcp-server/dist/tools/base.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/base.tool.js +47 -0
- package/mcp-server/dist/tools/base.tool.js.map +1 -0
- package/mcp-server/dist/tools/get-doc-content.tool.d.ts +30 -0
- package/mcp-server/dist/tools/get-doc-content.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/get-doc-content.tool.js +127 -0
- package/mcp-server/dist/tools/get-doc-content.tool.js.map +1 -0
- package/mcp-server/dist/tools/get-doc-metadata.tool.d.ts +40 -0
- package/mcp-server/dist/tools/get-doc-metadata.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/get-doc-metadata.tool.js +121 -0
- package/mcp-server/dist/tools/get-doc-metadata.tool.js.map +1 -0
- package/mcp-server/dist/tools/index.d.ts +8 -0
- package/mcp-server/dist/tools/index.d.ts.map +1 -0
- package/mcp-server/dist/tools/index.js +18 -0
- package/mcp-server/dist/tools/index.js.map +1 -0
- package/mcp-server/dist/tools/list-categories.tool.d.ts +20 -0
- package/mcp-server/dist/tools/list-categories.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/list-categories.tool.js +105 -0
- package/mcp-server/dist/tools/list-categories.tool.js.map +1 -0
- package/mcp-server/dist/tools/list-docs.tool.d.ts +32 -0
- package/mcp-server/dist/tools/list-docs.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/list-docs.tool.js +121 -0
- package/mcp-server/dist/tools/list-docs.tool.js.map +1 -0
- package/mcp-server/dist/tools/search-docs.tool.d.ts +32 -0
- package/mcp-server/dist/tools/search-docs.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/search-docs.tool.js +120 -0
- package/mcp-server/dist/tools/search-docs.tool.js.map +1 -0
- package/package.json +102 -0
- package/wiki/get-started/5-minute-quickstart.md +266 -0
- package/wiki/get-started/best-practices/api-usage-examples.md +222 -0
- package/wiki/get-started/best-practices/architectural-patterns.md +129 -0
- package/wiki/get-started/best-practices/code-style-standards.md +122 -0
- package/wiki/get-started/best-practices/common-pitfalls.md +136 -0
- package/wiki/get-started/best-practices/contribution-workflow.md +145 -0
- package/wiki/get-started/best-practices/deployment-strategies.md +121 -0
- package/wiki/get-started/best-practices/performance-optimization.md +88 -0
- package/wiki/get-started/best-practices/security-guidelines.md +97 -0
- package/wiki/get-started/best-practices/troubleshooting-tips.md +100 -0
- package/wiki/get-started/building-a-crud-api.md +717 -0
- package/wiki/get-started/core-concepts/application.md +168 -0
- package/wiki/get-started/core-concepts/components.md +96 -0
- package/wiki/get-started/core-concepts/controllers.md +441 -0
- package/wiki/get-started/core-concepts/dependency-injection.md +160 -0
- package/wiki/get-started/core-concepts/persistent.md +591 -0
- package/wiki/get-started/core-concepts/services.md +88 -0
- package/wiki/get-started/index.md +65 -0
- package/wiki/get-started/mcp-docs-server.md +840 -0
- package/wiki/get-started/philosophy.md +123 -0
- package/wiki/get-started/prerequisites.md +113 -0
- package/wiki/get-started/quickstart.md +382 -0
- package/wiki/index.md +48 -0
- package/wiki/references/base/application.md +67 -0
- package/wiki/references/base/components.md +80 -0
- package/wiki/references/base/controllers.md +361 -0
- package/wiki/references/base/datasources.md +105 -0
- package/wiki/references/base/dependency-injection.md +83 -0
- package/wiki/references/base/models.md +104 -0
- package/wiki/references/base/repositories.md +118 -0
- package/wiki/references/base/services.md +97 -0
- package/wiki/references/components/authentication.md +224 -0
- package/wiki/references/components/health-check.md +190 -0
- package/wiki/references/components/index.md +61 -0
- package/wiki/references/components/request-tracker.md +35 -0
- package/wiki/references/components/socket-io.md +127 -0
- package/wiki/references/components/swagger.md +175 -0
- package/wiki/references/helpers/cron.md +94 -0
- package/wiki/references/helpers/crypto.md +117 -0
- package/wiki/references/helpers/env.md +67 -0
- package/wiki/references/helpers/error.md +80 -0
- package/wiki/references/helpers/index.md +21 -0
- package/wiki/references/helpers/inversion.md +141 -0
- package/wiki/references/helpers/logger.md +98 -0
- package/wiki/references/helpers/network.md +143 -0
- package/wiki/references/helpers/queue.md +131 -0
- package/wiki/references/helpers/redis.md +121 -0
- package/wiki/references/helpers/socket-io.md +103 -0
- package/wiki/references/helpers/storage.md +130 -0
- package/wiki/references/helpers/testing.md +115 -0
- package/wiki/references/helpers/worker-thread.md +162 -0
- package/wiki/references/src-details/core.md +249 -0
- package/wiki/references/src-details/dev-configs.md +302 -0
- package/wiki/references/src-details/docs.md +61 -0
- package/wiki/references/src-details/helpers.md +211 -0
- package/wiki/references/src-details/inversion.md +345 -0
- package/wiki/references/src-details/mcp-server.md +726 -0
- package/wiki/references/utilities/crypto.md +39 -0
- package/wiki/references/utilities/date.md +72 -0
- package/wiki/references/utilities/index.md +12 -0
- package/wiki/references/utilities/module.md +40 -0
- package/wiki/references/utilities/parse.md +68 -0
- package/wiki/references/utilities/performance.md +64 -0
- package/wiki/references/utilities/promise.md +83 -0
- package/wiki/references/utilities/request.md +66 -0
- package/wiki/references/utilities/schema.md +88 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Deep Dive: Application
|
|
2
|
+
|
|
3
|
+
Technical reference for `AbstractApplication` and `BaseApplication` - the foundation classes for every Ignis application.
|
|
4
|
+
|
|
5
|
+
**Files:**
|
|
6
|
+
- `packages/core/src/base/applications/abstract.ts`
|
|
7
|
+
- `packages/core/src/base/applications/base.ts`
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Class | Purpose | Key Methods |
|
|
12
|
+
|-------|---------|-------------|
|
|
13
|
+
| **AbstractApplication** | Base class with lifecycle management | `preConfigure()`, `postConfigure()`, `validateEnvs()` |
|
|
14
|
+
| **BaseApplication** | Concrete implementation with resource registration | `component()`, `controller()`, `service()`, `repository()`, `dataSource()` |
|
|
15
|
+
|
|
16
|
+
## `AbstractApplication`
|
|
17
|
+
|
|
18
|
+
Base class responsible for core lifecycle and server management.
|
|
19
|
+
|
|
20
|
+
### Key Features
|
|
21
|
+
|
|
22
|
+
| Feature | Description |
|
|
23
|
+
| :--- | :--- |
|
|
24
|
+
| **Hono Instance** | Creates and holds the `OpenAPIHono` instance (underlying web server) |
|
|
25
|
+
| **Runtime Detection** | Auto-detects Bun or Node.js and uses appropriate server implementation |
|
|
26
|
+
| **Core Bindings** | Registers essential services (`CoreBindings.APPLICATION_INSTANCE`, `CoreBindings.APPLICATION_SERVER`) |
|
|
27
|
+
| **Lifecycle Management** | Defines abstract methods (`preConfigure`, `postConfigure`, `setupMiddlewares`) |
|
|
28
|
+
| **Environment Validation** | Validates all required `APP_ENV_*` environment variables |
|
|
29
|
+
|
|
30
|
+
## `BaseApplication`
|
|
31
|
+
|
|
32
|
+
Extends `AbstractApplication` with concrete lifecycle implementations and resource registration.
|
|
33
|
+
|
|
34
|
+
### Resource Registration Methods
|
|
35
|
+
|
|
36
|
+
`BaseApplication` provides a set of convenient methods for registering your application's building blocks. These methods bind the provided classes to the DI container with conventional keys.
|
|
37
|
+
|
|
38
|
+
| Method | DI Binding Key Convention |
|
|
39
|
+
| :--- | :--- |
|
|
40
|
+
| `component(MyComponent)` | `components.MyComponent` |
|
|
41
|
+
| `controller(MyController)` | `controllers.MyController` |
|
|
42
|
+
| `service(MyService)` | `services.MyService` |
|
|
43
|
+
| `repository(MyRepository)`| `repositories.MyRepository` |
|
|
44
|
+
| `dataSource(MyDataSource)`| `datasources.MyDataSource` |
|
|
45
|
+
|
|
46
|
+
### `initialize()` Method Flow
|
|
47
|
+
|
|
48
|
+
Startup sequence executed by the `initialize()` method:
|
|
49
|
+
|
|
50
|
+
```mermaid
|
|
51
|
+
graph TD
|
|
52
|
+
A(start) --> B(printStartUpInfo);
|
|
53
|
+
B --> C(validateEnvs);
|
|
54
|
+
C --> D(registerDefaultMiddlewares);
|
|
55
|
+
D --> E(staticConfigure);
|
|
56
|
+
E --> F(preConfigure);
|
|
57
|
+
F --> G(registerDataSources);
|
|
58
|
+
G --> H(registerComponents);
|
|
59
|
+
H --> I(registerControllers);
|
|
60
|
+
I --> J(postConfigure);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Hook | When to Use | Notes |
|
|
64
|
+
|------|-------------|-------|
|
|
65
|
+
| **`preConfigure()`** | Register all resources (datasources, services, controllers) | Nothing instantiated yet - order doesn't matter |
|
|
66
|
+
| **`register...()`** | Framework iterates bindings and instantiates classes | DataSources initialized first (other layers depend on them) |
|
|
67
|
+
| **`postConfigure()`** | Logic after all resources configured | Example: fetch initial data from repository |
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Deep Dive: Components
|
|
2
|
+
|
|
3
|
+
Technical reference for `BaseComponent` - creating pluggable, reusable modules in Ignis.
|
|
4
|
+
|
|
5
|
+
**File:** `packages/core/src/base/components/base.ts`
|
|
6
|
+
|
|
7
|
+
## Quick Reference
|
|
8
|
+
|
|
9
|
+
| Feature | Benefit |
|
|
10
|
+
|---------|---------|
|
|
11
|
+
| **Encapsulation** | Bundle feature bindings (services, controllers) into single class |
|
|
12
|
+
| **Lifecycle Management** | Auto-called `binding()` method during startup |
|
|
13
|
+
| **Default Bindings** | Self-contained with automatic DI registration |
|
|
14
|
+
|
|
15
|
+
## `BaseComponent` Class
|
|
16
|
+
|
|
17
|
+
Abstract class for all components - structures resource binding and lifecycle management.
|
|
18
|
+
|
|
19
|
+
### Key Features
|
|
20
|
+
|
|
21
|
+
| Feature | Description |
|
|
22
|
+
| :--- | :--- |
|
|
23
|
+
| **Encapsulation** | Bundles necessary bindings (services, controllers) for a feature |
|
|
24
|
+
| **Lifecycle Management** | `binding()` method auto-called during startup |
|
|
25
|
+
| **Default Bindings** | Auto-registers with application container (self-contained) |
|
|
26
|
+
|
|
27
|
+
### Constructor Options
|
|
28
|
+
|
|
29
|
+
The `super()` constructor in your component can take the following options:
|
|
30
|
+
|
|
31
|
+
| Option | Type | Description |
|
|
32
|
+
| :--- | :--- | :--- |
|
|
33
|
+
| `scope` | `string` | **Required.** A unique name for the component, typically `MyComponent.name`. Used for logging. |
|
|
34
|
+
| `initDefault` | `{ enable: boolean; container: Container }` | If `enable` is `true`, the `bindings` defined below will be automatically registered with the provided `container` (usually the application instance) if they are not already bound. |
|
|
35
|
+
| `bindings` | `Record<string, Binding>` | An object where keys are binding keys (e.g., `'services.MyService'`) and values are `Binding` instances. These are the default services, values, or providers that your component offers. |
|
|
36
|
+
|
|
37
|
+
### Lifecycle Flow
|
|
38
|
+
|
|
39
|
+
1. **Application Instantiates Component**: When you call `this.component(MyComponent)` in your application, the DI container creates an instance of your component.
|
|
40
|
+
2. **Constructor Runs**: Your component's constructor calls `super()`, setting up its scope and defining its default `bindings`. If `initDefault` is enabled, these bindings are immediately registered with the application container.
|
|
41
|
+
3. **Application Calls `binding()`**: During the `registerComponents` phase of the application startup, the `binding()` method of your component is called. This is where you can perform additional setup that might depend on the default bindings being available.
|
|
42
|
+
|
|
43
|
+
### Example Implementation
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { BaseApplication, BaseComponent, inject, CoreBindings, ValueOrPromise, Binding } from '@venizia/ignis';
|
|
47
|
+
|
|
48
|
+
// A service this component provides
|
|
49
|
+
class MyComponentService { /* ... */ }
|
|
50
|
+
|
|
51
|
+
// A controller that uses the service
|
|
52
|
+
@controller({ path: '/my-feature' })
|
|
53
|
+
class MyComponentController extends BaseController {
|
|
54
|
+
constructor(@inject({ key: 'services.MyComponentService' }) service: MyComponentService) { /* ... */ }
|
|
55
|
+
// ...
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class MyCustomComponent extends BaseComponent {
|
|
59
|
+
constructor(
|
|
60
|
+
@inject({ key: CoreBindings.APPLICATION_INSTANCE }) private application: BaseApplication,
|
|
61
|
+
) {
|
|
62
|
+
super({
|
|
63
|
+
scope: MyCustomComponent.name,
|
|
64
|
+
initDefault: { enable: true, container: application },
|
|
65
|
+
bindings: {
|
|
66
|
+
'services.MyComponentService': Binding.bind({ key: 'services.MyComponentService' })
|
|
67
|
+
.toClass(MyComponentService)
|
|
68
|
+
.setScope(BindingScopes.SINGLETON),
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// This method is called after the default bindings are registered.
|
|
74
|
+
override binding(): ValueOrPromise<void> {
|
|
75
|
+
// We can now register the controller, which depends on the service.
|
|
76
|
+
this.application.controller(MyComponentController);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
This architecture makes features modular. The `AuthenticateComponent`, for example, uses this pattern to provide the `JWTTokenService` as a default binding and then registers the `AuthController` which depends on it.
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# Deep Dive: Controllers
|
|
2
|
+
|
|
3
|
+
Technical reference for controller classes - the foundation for creating API endpoints in Ignis.
|
|
4
|
+
|
|
5
|
+
**Files:**
|
|
6
|
+
- `packages/core/src/base/controllers/abstract.ts`
|
|
7
|
+
- `packages/core/src/base/controllers/base.ts`
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Class | Purpose | Route Definition Methods |
|
|
12
|
+
|-------|---------|--------------------------|
|
|
13
|
+
| **AbstractController** | Base class with Hono router integration | `binding()`, `registerRoutesFromRegistry()` |
|
|
14
|
+
| **BaseController** | Concrete implementation for API routes | `defineRoute()`, `bindRoute()`, `@get`, `@post`, `@api` decorators |
|
|
15
|
+
|
|
16
|
+
## Routing Approaches
|
|
17
|
+
|
|
18
|
+
| Approach | When to Use | Example |
|
|
19
|
+
|----------|-------------|---------|
|
|
20
|
+
| **Decorator-Based** (Recommended) | Clean, declarative routes | `@get({ configs: {...} })` |
|
|
21
|
+
| **Manual Definition** | Complex routing logic | `this.defineRoute({ configs, handler })` |
|
|
22
|
+
|
|
23
|
+
## `AbstractController`
|
|
24
|
+
|
|
25
|
+
Base class integrating Hono routing with Ignis DI and OpenAPI generation.
|
|
26
|
+
|
|
27
|
+
### Key Features
|
|
28
|
+
|
|
29
|
+
| Feature | Description |
|
|
30
|
+
| :--- | :--- |
|
|
31
|
+
| **Hono Router** | Each controller manages its own `OpenAPIHono` router |
|
|
32
|
+
| **Lifecycle** | `binding()` for manual routes, `registerRoutesFromRegistry()` for decorators |
|
|
33
|
+
| **OpenAPI Integration** | Integrates with `@hono/zod-openapi` for schema generation |
|
|
34
|
+
| **Standard Route Configs** | `getRouteConfigs` adds auth strategies, default responses, controller tags |
|
|
35
|
+
|
|
36
|
+
## `BaseController`
|
|
37
|
+
|
|
38
|
+
Extends `AbstractController` with concrete implementations for defining API routes.
|
|
39
|
+
|
|
40
|
+
### Decorator-Based Routing (Recommended)
|
|
41
|
+
|
|
42
|
+
With the latest updates, the recommended way to define routes is by using decorators directly on your controller methods. This approach is more declarative, cleaner, and reduces boilerplate. The framework automatically discovers and registers these routes during startup via the `registerRoutesFromRegistry()` method.
|
|
43
|
+
|
|
44
|
+
The `binding()` method is no longer required if you are using only decorator-based routing.
|
|
45
|
+
|
|
46
|
+
:::tip Type Safety without Boilerplate
|
|
47
|
+
For decorator-based routes, you do not need to explicitly annotate the return type with `TRouteResponse`. TypeScript will automatically infer and validate the return type against the OpenAPI response schema you define in your `configs`. This gives you full type safety with less code.
|
|
48
|
+
:::
|
|
49
|
+
|
|
50
|
+
#### `@api` Decorator
|
|
51
|
+
|
|
52
|
+
The generic `@api` decorator allows you to define a route with a full configuration object. The decorated method will automatically have its `context` parameter and return type inferred and type-checked against the provided route configuration. This ensures strong type safety throughout your API definitions.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { api, BaseController, controller, HTTP, jsonContent, jsonResponse, z, TRouteContext } from '@venizia/ignis';
|
|
56
|
+
|
|
57
|
+
const MyRouteConfig = {
|
|
58
|
+
method: 'get',
|
|
59
|
+
path: '/data',
|
|
60
|
+
responses: jsonResponse({ schema: z.object({ success: z.boolean() }) }),
|
|
61
|
+
} as const;
|
|
62
|
+
|
|
63
|
+
@controller({ path: '/my-feature' })
|
|
64
|
+
export class MyFeatureController extends BaseController {
|
|
65
|
+
|
|
66
|
+
@api({ configs: MyRouteConfig })
|
|
67
|
+
getData(c: TRouteContext<typeof MyRouteConfig>) { // Return type is automatically inferred and validated
|
|
68
|
+
return c.json({ success: true });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### HTTP Method Decorators (`@get`, `@post`, etc.)
|
|
74
|
+
|
|
75
|
+
For convenience, `Ignis` provides decorator shortcuts for each HTTP method: These decorators accept the same `configs` object as `@api`, but without the `method` property.
|
|
76
|
+
|
|
77
|
+
- `@get(opts)`
|
|
78
|
+
- `@post(opts)`
|
|
79
|
+
- `@put(opts)`
|
|
80
|
+
- `@patch(opts)`
|
|
81
|
+
- `@del(opts)`
|
|
82
|
+
|
|
83
|
+
**Example using `@get` and `@post` with type inference:**
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { get, post, z, jsonContent, jsonResponse, Authentication, TRouteContext } from '@venizia/ignis';
|
|
87
|
+
|
|
88
|
+
// Define route configs as const for full type inference
|
|
89
|
+
const USER_ROUTES = {
|
|
90
|
+
listUsers: {
|
|
91
|
+
path: '/',
|
|
92
|
+
method: 'get',
|
|
93
|
+
responses: jsonResponse({
|
|
94
|
+
description: 'A list of users',
|
|
95
|
+
schema: z.array(z.object({ id: z.string(), name: z.string() })),
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
getUser: {
|
|
99
|
+
path: '/:id',
|
|
100
|
+
method: 'get',
|
|
101
|
+
request: {
|
|
102
|
+
params: z.object({ id: z.string() }),
|
|
103
|
+
},
|
|
104
|
+
responses: jsonResponse({
|
|
105
|
+
description: 'A single user',
|
|
106
|
+
schema: z.object({ id: z.string(), name: z.string() }),
|
|
107
|
+
}),
|
|
108
|
+
},
|
|
109
|
+
createUser: {
|
|
110
|
+
path: '/',
|
|
111
|
+
method: 'post',
|
|
112
|
+
authStrategies: [Authentication.STRATEGY_JWT], // Secure this endpoint
|
|
113
|
+
request: {
|
|
114
|
+
body: jsonContent({
|
|
115
|
+
schema: z.object({ name: z.string() }),
|
|
116
|
+
}),
|
|
117
|
+
},
|
|
118
|
+
responses: jsonResponse({
|
|
119
|
+
schema: z.object({ id: z.string(), name: z.string() }),
|
|
120
|
+
}),
|
|
121
|
+
},
|
|
122
|
+
} as const; // Crucial for type inference!
|
|
123
|
+
|
|
124
|
+
// ... inside a controller class
|
|
125
|
+
|
|
126
|
+
@get({ configs: USER_ROUTES.listUsers })
|
|
127
|
+
getAllUsers(c: TRouteContext<typeof USER_ROUTES.listUsers>) { // Return type is automatically inferred
|
|
128
|
+
return c.json([{ id: '1', name: 'John Doe' }]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@get({ configs: USER_ROUTES.getUser })
|
|
132
|
+
getUserById(c: TRouteContext<typeof USER_ROUTES.getUser>) { // Return type is automatically inferred
|
|
133
|
+
const { id } = c.req.valid('param'); // id is typed as string
|
|
134
|
+
return c.json({ id, name: 'John Doe' });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@post({ configs: USER_ROUTES.createUser })
|
|
138
|
+
createUser(c: TRouteContext<typeof USER_ROUTES.createUser>) { // Return type is automatically inferred
|
|
139
|
+
const { name } = c.req.valid('json'); // name is typed as string
|
|
140
|
+
const newUser = { id: '2', name };
|
|
141
|
+
return c.json(newUser, 201); // Return type is validated
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Example using shared `ROUTE_CONFIGS`:**
|
|
146
|
+
|
|
147
|
+
For better organization, you can define all your route configurations in a constant and reference them in your decorators. This approach also allows you to get a typed context for your handler.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { api, BaseController, controller, TRouteContext, jsonContent, jsonResponse, HTTP } from '@venizia/ignis';
|
|
151
|
+
import { z } from 'hono/zod-openapi';
|
|
152
|
+
|
|
153
|
+
const HEALTH_CHECK_ROUTES = {
|
|
154
|
+
'/ping': {
|
|
155
|
+
method: HTTP.Methods.POST,
|
|
156
|
+
path: '/ping',
|
|
157
|
+
request: {
|
|
158
|
+
body: jsonContent({
|
|
159
|
+
schema: z.object({ message: z.string().min(1) }),
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
responses: jsonResponse({
|
|
163
|
+
schema: z.object({ pong: z.string() }),
|
|
164
|
+
}),
|
|
165
|
+
},
|
|
166
|
+
} as const; // Use 'as const' for strict type inference
|
|
167
|
+
|
|
168
|
+
@controller({ path: '/health' })
|
|
169
|
+
export class HealthCheckController extends BaseController {
|
|
170
|
+
|
|
171
|
+
@api({ configs: HEALTH_CHECK_ROUTES['/ping'] })
|
|
172
|
+
ping(c: TRouteContext<typeof HEALTH_CHECK_ROUTES['/ping']>) { // Return type is automatically inferred
|
|
173
|
+
const { message } = c.req.valid('json');
|
|
174
|
+
return c.json({ pong: message });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Manual Route Definition Methods
|
|
180
|
+
|
|
181
|
+
While decorator-based routing is available, the recommended way to define routes is by using the `defineRoute` and `bindRoute` methods inside the `binding()` method. This approach offers a clear and declarative syntax that keeps your route definitions organized and easy to manage.
|
|
182
|
+
|
|
183
|
+
:::tip Recommendation
|
|
184
|
+
For better organization and a more declarative approach, we strongly recommend using `defineRoute` or `bindRoute` within the `binding()` method to define your controller's routes. This keeps all route definitions in one place, making your controller easier to read and maintain.
|
|
185
|
+
:::
|
|
186
|
+
|
|
187
|
+
#### `defineRoute`
|
|
188
|
+
|
|
189
|
+
This method is for creating API endpoints. It now handles both public and authenticated routes by accepting an `authStrategies` array within the `configs`.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
this.defineRoute({
|
|
193
|
+
configs: TAuthRouteConfig<RouteConfig>; // You would define this inline or via a const
|
|
194
|
+
handler: TLazyRouteHandler<typeof configs, RouteEnv>; // Inferred from configs
|
|
195
|
+
hook?: Hook;
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
- **`configs`**: An object that defines the route's OpenAPI specification. It now includes an optional `authStrategies` array. See the table below for details.
|
|
200
|
+
- **`handler`**: The Hono route handler function `(c: Context) => Response`.
|
|
201
|
+
- **`hook`**: An optional hook for processing the request or response, often used for validation error handling.
|
|
202
|
+
|
|
203
|
+
#### `bindRoute`
|
|
204
|
+
|
|
205
|
+
This method offers a fluent API for defining routes, similar to `defineRoute`, but structured for chaining. It also supports `authStrategies`.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
this.bindRoute({
|
|
209
|
+
configs: TAuthRouteConfig<RouteConfig>; // You would define this inline or via a const
|
|
210
|
+
}).to({
|
|
211
|
+
handler: TLazyRouteHandler<typeof configs, RouteEnv>; // Inferred from configs
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- **`configs`**: Same as `defineRoute`, including `authStrategies`.
|
|
216
|
+
- **`to`**: A method that accepts an object with the `handler` function.
|
|
217
|
+
|
|
218
|
+
### `TRouteConfig` Options
|
|
219
|
+
|
|
220
|
+
The `configs` object accepts properties based on the OpenAPI 3.0 specification.
|
|
221
|
+
|
|
222
|
+
| Property | Type | Description |
|
|
223
|
+
| :--- | :--- | :--- |
|
|
224
|
+
| `path` | `string` | The route path, relative to the controller's base path (e.g., `/:id`). |
|
|
225
|
+
| `method` | `'get' \| 'post' \| ...` | The HTTP method for the route. |
|
|
226
|
+
| `request` | `object` | Defines the request, including `params`, `query`, and `body`. You can use Zod schemas for validation. |
|
|
227
|
+
| `responses`| `object` | An object mapping HTTP status codes to response descriptions and schemas. The `jsonContent` and `jsonResponse` utilities can simplify this. |
|
|
228
|
+
| `tags` | `string[]` | An array of tags for grouping routes in the OpenAPI documentation. The controller's name is automatically added as a tag. |
|
|
229
|
+
| `summary` | `string` | A short summary of what the operation does. |
|
|
230
|
+
| `description`| `string` | A detailed description of the operation. |
|
|
231
|
+
| `authStrategies`| `TAuthStrategy[]` | An optional array of authentication strategy names (e.g., `[Authentication.STRATEGY_JWT]`). If provided, the framework will automatically add the necessary middleware to enforce these strategies. |
|
|
232
|
+
|
|
233
|
+
### Example of `request` Configuration
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { z } from '@hono/zod-openapi';
|
|
237
|
+
import { jsonContent } from '@venizia/ignis';
|
|
238
|
+
|
|
239
|
+
// ...
|
|
240
|
+
request: {
|
|
241
|
+
params: z.object({ id: z.string() }),
|
|
242
|
+
query: z.object({ format: z.string().optional() }),
|
|
243
|
+
body: jsonContent({
|
|
244
|
+
schema: z.object({ name: z.string() })
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
// ...
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### `defineRouteConfigs`
|
|
251
|
+
|
|
252
|
+
- **File:** `packages/core/src/base/controllers/factory/definition.ts`
|
|
253
|
+
|
|
254
|
+
The `defineRouteConfigs` function is a simple helper for creating a typed object containing multiple route configurations. This is particularly useful for organizing all of a controller's route definitions in a single, type-checked constant.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { defineRouteConfigs, HTTP, jsonResponse, z } from '@venizia/ignis';
|
|
258
|
+
|
|
259
|
+
const ROUTE_CONFIGS = defineRouteConfigs({
|
|
260
|
+
'/': {
|
|
261
|
+
method: HTTP.Methods.GET,
|
|
262
|
+
path: '/',
|
|
263
|
+
responses: jsonResponse({
|
|
264
|
+
schema: z.object({ status: z.string() }),
|
|
265
|
+
}),
|
|
266
|
+
},
|
|
267
|
+
'/ping': {
|
|
268
|
+
method: HTTP.Methods.POST,
|
|
269
|
+
path: '/ping',
|
|
270
|
+
request: {
|
|
271
|
+
body: jsonContent({
|
|
272
|
+
schema: z.object({ message: z.string() }),
|
|
273
|
+
}),
|
|
274
|
+
},
|
|
275
|
+
responses: jsonResponse({
|
|
276
|
+
schema: z.object({ message: z.string() }),
|
|
277
|
+
}),
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## `ControllerFactory`
|
|
283
|
+
|
|
284
|
+
The `ControllerFactory` provides a static method `defineCrudController` to quickly generate a pre-configured CRUD controller for any given `BaseEntity` and its corresponding repository. This significantly reduces boilerplate for standard RESTful resources.
|
|
285
|
+
|
|
286
|
+
- **File:** `packages/core/src/base/controllers/factory/controller.ts`
|
|
287
|
+
|
|
288
|
+
### `static defineCrudController<EntitySchema>(opts: ICrudControllerOptions<EntitySchema>)`
|
|
289
|
+
|
|
290
|
+
This factory method returns a `BaseController` class that is already set up with the following standard CRUD endpoints:
|
|
291
|
+
|
|
292
|
+
| Name | Method | Path | Description |
|
|
293
|
+
| :--- | :--- | :--- | :--- |
|
|
294
|
+
| `count` | `GET` | `/count` | Get the number of records matching a filter. |
|
|
295
|
+
| `find` | `GET` | `/` | Retrieve all records matching a filter. |
|
|
296
|
+
| `findById` | `GET` | `/:id` | Retrieve a single record by its ID. |
|
|
297
|
+
| `findOne` | `GET` | `/find-one` | Retrieve a single record matching a filter. |
|
|
298
|
+
| `create` | `POST` | `/` | Create a new record. |
|
|
299
|
+
| `updateById` | `PATCH` | `/:id` | Update a record by its ID. |
|
|
300
|
+
| `updateAll` | `PATCH` | `/` | Update multiple records matching a filter. |
|
|
301
|
+
| `deleteById` | `DELETE` | `/:id` | Delete a record by its ID. |
|
|
302
|
+
| `deleteAll` | `DELETE` | `/` | Delete multiple records matching a filter. |
|
|
303
|
+
|
|
304
|
+
### `ICrudControllerOptions<EntitySchema>`
|
|
305
|
+
|
|
306
|
+
| Option | Type | Description |
|
|
307
|
+
| :--- | :--- | :--- |
|
|
308
|
+
| `entity` | `TClass<BaseEntity<EntitySchema>> \| TResolver<TClass<BaseEntity<EntitySchema>>>` | The entity class (or a resolver function returning it) that this CRUD controller manages. This is used to derive request/response schemas. |
|
|
309
|
+
| `repository.name` | `string` | The binding key name of the repository associated with this entity (e.g., `'ConfigurationRepository'`). |
|
|
310
|
+
| `controller.name` | `string` | A unique name for the generated controller (e.g., `'ConfigurationController'`). |
|
|
311
|
+
| `controller.basePath`| `string` | The base path for all routes in this CRUD controller (e.g., `'/configurations'`). |
|
|
312
|
+
| `controller.isStrict` | `boolean` | If `true`, query parameters like `where` will be strictly validated. Defaults to `true`. |
|
|
313
|
+
| `controller.defaultLimit`| `number` | The default limit for `find` operations. Defaults to `10`. |
|
|
314
|
+
| `schema` | `object` | An optional object to override the default Zod schemas for specific CRUD endpoints (e.g., `find`, `create`, `updateByIdRequestBody`). This allows for fine-grained control over the request and response validation and OpenAPI documentation. |
|
|
315
|
+
| `doDeleteWithReturn` | `boolean` | If `true`, the `deleteById` and `deleteAll` endpoints will return the deleted record(s) in the response body. Defaults to `false`. |
|
|
316
|
+
|
|
317
|
+
### Example
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// src/controllers/configuration.controller.ts
|
|
321
|
+
import { Configuration } from '@/models';
|
|
322
|
+
import { ConfigurationRepository } from '@/repositories';
|
|
323
|
+
import {
|
|
324
|
+
controller,
|
|
325
|
+
ControllerFactory,
|
|
326
|
+
inject,
|
|
327
|
+
BindingKeys,
|
|
328
|
+
BindingNamespaces,
|
|
329
|
+
} from '@venizia/ignis';
|
|
330
|
+
|
|
331
|
+
const BASE_PATH = '/configurations';
|
|
332
|
+
|
|
333
|
+
// Define the CRUD controller using the factory
|
|
334
|
+
const _ConfigurationController = ControllerFactory.defineCrudController({
|
|
335
|
+
repository: { name: ConfigurationRepository.name },
|
|
336
|
+
controller: {
|
|
337
|
+
name: 'ConfigurationController',
|
|
338
|
+
basePath: BASE_PATH,
|
|
339
|
+
isStrict: true,
|
|
340
|
+
},
|
|
341
|
+
entity: () => Configuration, // Provide the entity class
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Extend the generated controller to add custom logic or inject dependencies
|
|
345
|
+
@controller({ path: BASE_PATH })
|
|
346
|
+
export class ConfigurationController extends _ConfigurationController {
|
|
347
|
+
constructor(
|
|
348
|
+
@inject({
|
|
349
|
+
key: BindingKeys.build({
|
|
350
|
+
namespace: BindingNamespaces.REPOSITORY,
|
|
351
|
+
key: ConfigurationRepository.name,
|
|
352
|
+
}),
|
|
353
|
+
})
|
|
354
|
+
repository: ConfigurationRepository,
|
|
355
|
+
) {
|
|
356
|
+
super(repository); // Pass the injected repository to the super constructor
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
By leveraging these structured configuration options and the `ControllerFactory`, you ensure that your API is not only functional but also well-documented, easy to validate, and rapidly deployable for standard CRUD operations.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Deep Dive: DataSources
|
|
2
|
+
|
|
3
|
+
Technical reference for DataSource classes - managing database connections in Ignis.
|
|
4
|
+
|
|
5
|
+
**Files:** `packages/core/src/base/datasources/*.ts`
|
|
6
|
+
|
|
7
|
+
## Quick Reference
|
|
8
|
+
|
|
9
|
+
| Class/Interface | Purpose | Key Members |
|
|
10
|
+
|-----------------|---------|-------------|
|
|
11
|
+
| **IDataSource** | Contract for all datasources | `name`, `settings`, `connector`, `schema`, `configure()` |
|
|
12
|
+
| **AbstractDataSource** | Base implementation with logging | Extends `BaseHelper` |
|
|
13
|
+
| **BaseDataSource** | Concrete class to extend | Constructor accepts `name`, `driver`, `config`, `schema` |
|
|
14
|
+
|
|
15
|
+
## `IDataSource` Interface
|
|
16
|
+
|
|
17
|
+
Contract for all datasource classes in the framework.
|
|
18
|
+
|
|
19
|
+
**File:** `packages/core/src/base/datasources/types.ts`
|
|
20
|
+
|
|
21
|
+
### Properties & Methods
|
|
22
|
+
|
|
23
|
+
| Member | Type | Description |
|
|
24
|
+
|--------|------|-------------|
|
|
25
|
+
| `name` | `string` | Datasource name |
|
|
26
|
+
| `settings` | `object` | Configuration object |
|
|
27
|
+
| `connector` | `TDatabaseConnector` | Database connector instance (e.g., Drizzle) |
|
|
28
|
+
| `schema` | `object` | Combined Drizzle schema (tables + relations) |
|
|
29
|
+
| `configure()` | Method | Initializes the `connector` |
|
|
30
|
+
| `getConnectionString()` | Method | Returns connection string |
|
|
31
|
+
|
|
32
|
+
## `AbstractDataSource` & `BaseDataSource`
|
|
33
|
+
|
|
34
|
+
**File:** `packages/core/src/base/datasources/base.ts`
|
|
35
|
+
|
|
36
|
+
### `AbstractDataSource`
|
|
37
|
+
|
|
38
|
+
This is the top-level abstract class that implements the `IDataSource` interface. It initializes the `BaseHelper` for logging and sets up the basic properties.
|
|
39
|
+
|
|
40
|
+
### `BaseDataSource`
|
|
41
|
+
|
|
42
|
+
This class extends `AbstractDataSource` and provides a constructor that standardizes how datasources are created. When you create your own datasource, you extend `BaseDataSource`.
|
|
43
|
+
|
|
44
|
+
### Constructor and Configuration Flow
|
|
45
|
+
|
|
46
|
+
1. **Your DataSource's `constructor` is called**:
|
|
47
|
+
- You call `super()` with the `name`, `driver`, `config` (connection settings), and the crucial `schema` object.
|
|
48
|
+
- The `schema` object **must** contain all your Drizzle tables and `relations` definitions.
|
|
49
|
+
|
|
50
|
+
2. **`Application.registerDataSources()` is called during startup**:
|
|
51
|
+
- The application gets your `DataSource` instance from the DI container.
|
|
52
|
+
- It calls the `configure()` method on your instance.
|
|
53
|
+
|
|
54
|
+
3. **Your `configure()` method runs**:
|
|
55
|
+
- This is where you instantiate the Drizzle ORM.
|
|
56
|
+
- You pass the `this.settings` (your config) and `this.schema` to Drizzle, creating the `this.connector`.
|
|
57
|
+
|
|
58
|
+
### Example Implementation
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// src/datasources/postgres.datasource.ts
|
|
62
|
+
import {
|
|
63
|
+
// ... import your models and relations
|
|
64
|
+
} from '@/models/entities';
|
|
65
|
+
import {
|
|
66
|
+
BaseDataSource,
|
|
67
|
+
datasource,
|
|
68
|
+
TNodePostgresConnector,
|
|
69
|
+
ValueOrPromise,
|
|
70
|
+
} from '@venizia/ignis';
|
|
71
|
+
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
72
|
+
import { Pool } from 'pg';
|
|
73
|
+
|
|
74
|
+
// Decorator to mark this class as a datasource for DI
|
|
75
|
+
@datasource()
|
|
76
|
+
export class PostgresDataSource extends BaseDataSource<
|
|
77
|
+
TNodePostgresConnector, // Type of the connector
|
|
78
|
+
IDSConfigs // Type of the config object
|
|
79
|
+
> {
|
|
80
|
+
constructor() {
|
|
81
|
+
super({
|
|
82
|
+
name: PostgresDataSource.name,
|
|
83
|
+
driver: 'node-postgres',
|
|
84
|
+
config: { /* ... connection details from environment ... */ },
|
|
85
|
+
schema: {
|
|
86
|
+
// Register all tables and relations here
|
|
87
|
+
usersTable,
|
|
88
|
+
configurationTable,
|
|
89
|
+
...configurationRelations,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// This method is called by the application at startup
|
|
95
|
+
override configure(): ValueOrPromise<void> {
|
|
96
|
+
this.connector = drizzle({
|
|
97
|
+
client: new Pool(this.settings),
|
|
98
|
+
schema: this.schema,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// ...
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This architecture ensures that datasources are configured consistently and that the fully-initialized Drizzle connector, aware of all schemas and relations, is available to repositories for querying.
|