@venizia/ignis-docs 0.0.8 → 0.2.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 +7 -7
- package/content/best-practices/api-usage-examples.md +15 -12
- package/content/best-practices/architectural-patterns.md +70 -78
- package/content/best-practices/architecture-decisions.md +91 -60
- package/content/best-practices/code-style-standards/advanced-patterns.md +56 -44
- package/content/best-practices/code-style-standards/constants-configuration.md +11 -11
- package/content/best-practices/code-style-standards/control-flow.md +5 -2
- package/content/best-practices/code-style-standards/documentation.md +13 -13
- package/content/best-practices/code-style-standards/function-patterns.md +9 -10
- package/content/best-practices/code-style-standards/index.md +1 -1
- package/content/best-practices/code-style-standards/naming-conventions.md +10 -8
- package/content/best-practices/code-style-standards/route-definitions.md +30 -12
- package/content/best-practices/code-style-standards/tooling.md +8 -5
- package/content/best-practices/code-style-standards/type-safety.md +13 -12
- package/content/best-practices/common-pitfalls.md +56 -37
- package/content/best-practices/contribution-workflow.md +13 -14
- package/content/best-practices/data-modeling.md +46 -22
- package/content/best-practices/deployment-strategies.md +28 -27
- package/content/best-practices/error-handling.md +48 -24
- package/content/best-practices/index.md +5 -5
- package/content/best-practices/performance-optimization.md +40 -31
- package/content/best-practices/security-guidelines.md +52 -23
- package/content/best-practices/testing-strategies.md +65 -51
- package/content/best-practices/troubleshooting-tips.md +24 -24
- package/content/extensions/components/{swagger.md → api-reference.md} +40 -31
- package/content/extensions/components/authentication/api.md +19 -19
- package/content/extensions/components/authentication/errors.md +7 -7
- package/content/extensions/components/authentication/index.md +10 -8
- package/content/extensions/components/authentication/usage.md +101 -6
- package/content/extensions/components/authorization/api.md +45 -25
- package/content/extensions/components/authorization/errors.md +6 -6
- package/content/extensions/components/authorization/index.md +11 -10
- package/content/extensions/components/authorization/usage.md +21 -21
- package/content/extensions/components/health-check.md +1 -1
- package/content/extensions/components/index.md +5 -5
- package/content/extensions/components/mail/errors.md +15 -15
- package/content/extensions/components/mail/index.md +1 -2
- package/content/extensions/components/mail/usage.md +1 -1
- package/content/extensions/components/request-tracker.md +1 -1
- package/content/extensions/components/socket-io/api.md +9 -9
- package/content/extensions/components/socket-io/errors.md +5 -5
- package/content/extensions/components/socket-io/index.md +8 -8
- package/content/extensions/components/socket-io/usage.md +1 -1
- package/content/extensions/components/static-asset/api.md +17 -4
- package/content/extensions/components/static-asset/errors.md +4 -4
- package/content/extensions/components/static-asset/index.md +26 -28
- package/content/extensions/components/static-asset/usage.md +13 -12
- package/content/extensions/components/template/index.md +2 -2
- package/content/extensions/components/template/setup-page.md +1 -1
- package/content/extensions/components/websocket/api.md +3 -3
- package/content/extensions/components/websocket/errors.md +5 -5
- package/content/extensions/components/websocket/index.md +5 -5
- package/content/extensions/components/websocket/usage.md +3 -3
- package/content/extensions/helpers/cron/index.md +2 -2
- package/content/extensions/helpers/crypto/index.md +1 -1
- package/content/extensions/helpers/env/index.md +27 -12
- package/content/extensions/helpers/error/index.md +81 -25
- package/content/extensions/helpers/index.md +2 -3
- package/content/extensions/helpers/inversion/index.md +15 -7
- package/content/extensions/helpers/kafka/compile-binary.md +92 -0
- package/content/extensions/helpers/kafka/examples.md +1 -1
- package/content/extensions/helpers/kafka/index.md +3 -0
- package/content/extensions/helpers/logger/index.md +32 -2
- package/content/extensions/helpers/network/index.md +6 -0
- package/content/extensions/helpers/queue/index.md +14 -17
- package/content/extensions/helpers/redis/index.md +548 -323
- package/content/extensions/helpers/socket-io/index.md +14 -10
- package/content/extensions/helpers/storage/api.md +44 -8
- package/content/extensions/helpers/storage/index.md +43 -7
- package/content/extensions/helpers/template/index.md +6 -3
- package/content/extensions/helpers/types/index.md +11 -8
- package/content/extensions/helpers/websocket/api.md +9 -9
- package/content/extensions/helpers/websocket/index.md +7 -7
- package/content/extensions/helpers/worker-thread/index.md +2 -2
- package/content/extensions/index.md +3 -4
- package/content/extensions/src-details/mcp-server.md +18 -24
- package/content/guides/core-concepts/application/bootstrapping.md +11 -14
- package/content/guides/core-concepts/application/index.md +3 -3
- package/content/guides/core-concepts/components.md +19 -10
- package/content/guides/core-concepts/dependency-injection.md +6 -3
- package/content/guides/core-concepts/grpc-controllers.md +6 -5
- package/content/guides/core-concepts/persistent/datasources.md +42 -43
- package/content/guides/core-concepts/persistent/index.md +16 -7
- package/content/guides/core-concepts/persistent/models.md +24 -20
- package/content/guides/core-concepts/persistent/postgres-drivers.md +201 -0
- package/content/guides/core-concepts/persistent/repositories.md +40 -23
- package/content/guides/core-concepts/persistent/search-meilisearch.md +185 -0
- package/content/guides/core-concepts/persistent/search-typesense.md +431 -0
- package/content/guides/core-concepts/persistent/transactions.md +61 -25
- package/content/guides/core-concepts/rest-controllers.md +12 -9
- package/content/guides/core-concepts/services.md +330 -60
- package/content/guides/get-started/5-minute-quickstart.md +15 -15
- package/content/guides/get-started/philosophy.md +36 -36
- package/content/guides/get-started/setup.md +3 -3
- package/content/guides/index.md +3 -3
- package/content/guides/migrations/redis-helpers-migration.md +177 -0
- package/content/guides/migrations/scoped-rbac-migration.md +17 -17
- package/content/guides/migrations/unified-connectors-migration.md +113 -0
- package/content/guides/reference/glossary.md +19 -12
- package/content/guides/reference/mcp-docs-server.md +22 -18
- package/content/guides/tutorials/building-a-crud-api.md +37 -44
- package/content/guides/tutorials/complete-installation.md +17 -17
- package/content/guides/tutorials/ecommerce-api.md +163 -124
- package/content/guides/tutorials/realtime-chat.md +181 -135
- package/content/guides/tutorials/testing.md +65 -523
- package/content/index.md +2 -180
- package/content/public/apple-touch-icon.png +0 -0
- package/content/public/og-image.png +0 -0
- package/content/public/site.webmanifest +11 -0
- package/content/references/base/application.md +4 -5
- package/content/references/base/bootstrapping.md +18 -5
- package/content/references/base/components.md +149 -120
- package/content/references/base/connectors.md +178 -0
- package/content/references/base/controllers.md +41 -30
- package/content/references/base/datasources.md +163 -92
- package/content/references/base/dependency-injection.md +34 -22
- package/content/references/base/filter-system/application-usage.md +17 -14
- package/content/references/base/filter-system/array-operators.md +7 -2
- package/content/references/base/filter-system/comparison-operators.md +3 -0
- package/content/references/base/filter-system/default-filter.md +89 -71
- package/content/references/base/filter-system/fields-order-pagination.md +22 -22
- package/content/references/base/filter-system/index.md +6 -3
- package/content/references/base/filter-system/json-filtering.md +20 -1
- package/content/references/base/filter-system/list-operators.md +1 -1
- package/content/references/base/filter-system/logical-operators.md +33 -1
- package/content/references/base/filter-system/null-operators.md +30 -1
- package/content/references/base/filter-system/quick-reference.md +23 -4
- package/content/references/base/filter-system/tips.md +5 -5
- package/content/references/base/filter-system/use-cases.md +12 -12
- package/content/references/base/grpc-controllers.md +13 -13
- package/content/references/base/index.md +24 -12
- package/content/references/base/middlewares.md +265 -327
- package/content/references/base/models.md +63 -49
- package/content/references/base/providers.md +136 -130
- package/content/references/base/repositories/advanced.md +59 -58
- package/content/references/base/repositories/index.md +115 -91
- package/content/references/base/repositories/mixins.md +55 -291
- package/content/references/base/repositories/relations.md +54 -64
- package/content/references/base/repositories/soft-deletable.md +31 -30
- package/content/references/base/services.md +296 -93
- package/content/references/configuration/environment-variables.md +49 -31
- package/content/references/configuration/index.md +6 -6
- package/content/references/index.md +17 -12
- package/content/references/quick-reference.md +65 -106
- package/content/references/utilities/crypto.md +65 -23
- package/content/references/utilities/index.md +3 -3
- package/content/references/utilities/jsx.md +6 -4
- package/content/references/utilities/module.md +68 -20
- package/content/references/utilities/parse.md +4 -14
- package/content/references/utilities/promise.md +9 -7
- package/content/references/utilities/schema.md +5 -3
- package/dist/mcp-server/common/guards.d.ts +8 -0
- package/dist/mcp-server/common/guards.d.ts.map +1 -0
- package/dist/mcp-server/common/guards.js +14 -0
- package/dist/mcp-server/common/guards.js.map +1 -0
- package/dist/mcp-server/common/index.d.ts +1 -0
- package/dist/mcp-server/common/index.d.ts.map +1 -1
- package/dist/mcp-server/common/index.js +1 -0
- package/dist/mcp-server/common/index.js.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.js +4 -2
- package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
- package/dist/mcp-server/helpers/github.helper.js +1 -1
- package/dist/mcp-server/index.js +7 -2
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/mcp-server/tools/base.tool.d.ts +6 -2
- package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/base.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
- package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
- package/package.json +9 -9
- package/content/extensions/helpers/testing/index.md +0 -510
- package/content/references/base/middleware.md +0 -347
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
# :fire: IGNIS - @venizia/ignis-docs
|
|
4
4
|
|
|
5
|
-
**Documentation site and MCP server for the
|
|
5
|
+
**Documentation site and MCP server for the IGNIS Framework**
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@venizia/ignis-docs)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
[](https://www.typescriptlang.org/)
|
|
10
10
|
[](https://modelcontextprotocol.io/)
|
|
11
11
|
|
|
12
|
-
VitePress-powered documentation site and an MCP server with 11 tools that gives AI assistants real-time access to
|
|
12
|
+
VitePress-powered documentation site and an MCP server with 11 tools that gives AI assistants real-time access to IGNIS knowledge -- search docs, browse source code, and verify dependencies.
|
|
13
13
|
|
|
14
14
|
[Installation](#installation) • [MCP Setup](#mcp-server-setup) • [Available Tools](#available-mcp-tools) • [Online Docs](https://venizia-ai.github.io/ignis)
|
|
15
15
|
|
|
@@ -106,13 +106,13 @@ Add to your Claude Code MCP settings:
|
|
|
106
106
|
| **listDocs** | List all available documentation pages |
|
|
107
107
|
| **listCategories** | List documentation categories and their structure |
|
|
108
108
|
| **getDocMetadata** | Get metadata (title, path, category) for a document |
|
|
109
|
-
| **getPackageOverview** | Get an overview of a specific
|
|
109
|
+
| **getPackageOverview** | Get an overview of a specific IGNIS package |
|
|
110
110
|
|
|
111
111
|
### GitHub Tools
|
|
112
112
|
|
|
113
113
|
| Tool | Description |
|
|
114
114
|
| --- | --- |
|
|
115
|
-
| **searchCode** | Search the
|
|
115
|
+
| **searchCode** | Search the IGNIS source code by keyword |
|
|
116
116
|
| **listProjectFiles** | List files in a specific directory of the repository |
|
|
117
117
|
| **viewSourceFile** | View the contents of a source file |
|
|
118
118
|
| **verifyDependencies** | Check dependency versions and compatibility |
|
|
@@ -140,7 +140,7 @@ bun run docs:preview
|
|
|
140
140
|
wiki/
|
|
141
141
|
├── guides/ # Getting started, core concepts, tutorials
|
|
142
142
|
├── references/ # API documentation
|
|
143
|
-
│ ├── base/ # BaseApplication,
|
|
143
|
+
│ ├── base/ # BaseApplication, BaseRestController, BaseEntity, etc.
|
|
144
144
|
│ ├── components/ # HealthCheck, Swagger, Auth, Mail, SocketIO, etc.
|
|
145
145
|
│ ├── helpers/ # Logger, Redis, Queue, Storage, Crypto, etc.
|
|
146
146
|
│ └── utilities/ # Parse, Date, Promise, Performance utilities
|
|
@@ -184,9 +184,9 @@ bun run mcp:rebuild
|
|
|
184
184
|
|
|
185
185
|
## Related Links
|
|
186
186
|
|
|
187
|
-
- [
|
|
187
|
+
- [IGNIS Framework](https://github.com/VENIZIA-AI/ignis) -- Main repository
|
|
188
188
|
- [Online Documentation](https://venizia-ai.github.io/ignis) -- Full documentation site
|
|
189
|
-
- [MCP Server Guide](https://github.com/VENIZIA-AI/ignis/blob/main/
|
|
189
|
+
- [MCP Server Guide](https://github.com/VENIZIA-AI/ignis/blob/main/docs/wiki/content/guides/reference/mcp-docs-server.md) -- Detailed setup guide
|
|
190
190
|
- [Model Context Protocol](https://modelcontextprotocol.io/) -- MCP specification
|
|
191
191
|
|
|
192
192
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# API Usage Examples
|
|
2
2
|
|
|
3
|
-
Practical examples for defining endpoints and working with data in
|
|
3
|
+
Practical examples for defining endpoints and working with data in IGNIS applications.
|
|
4
4
|
|
|
5
5
|
## Routing Patterns
|
|
6
6
|
|
|
@@ -28,7 +28,7 @@ export const RouteConfigs = {
|
|
|
28
28
|
CREATE_ITEM: {
|
|
29
29
|
method: HTTP.Methods.POST,
|
|
30
30
|
path: '/items',
|
|
31
|
-
|
|
31
|
+
authenticate: { strategies: [Authentication.STRATEGY_JWT] }, // Secure this endpoint
|
|
32
32
|
request: {
|
|
33
33
|
body: jsonContent({
|
|
34
34
|
description: 'Request body for POST',
|
|
@@ -229,7 +229,7 @@ const deleted = await configurationRepository.deleteById({
|
|
|
229
229
|
|
|
230
230
|
## Server-Side Rendering (JSX)
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
IGNIS supports server-side rendering using Hono's JSX middleware. This is useful for returning HTML content, such as landing pages or simple admin views.
|
|
233
233
|
|
|
234
234
|
**Usage:**
|
|
235
235
|
|
|
@@ -250,7 +250,7 @@ export class PageController extends BaseRestController {
|
|
|
250
250
|
responses: htmlResponse({ description: 'HTML Welcome Page' }),
|
|
251
251
|
},
|
|
252
252
|
handler: (c) => {
|
|
253
|
-
const title = 'Welcome to
|
|
253
|
+
const title = 'Welcome to IGNIS';
|
|
254
254
|
|
|
255
255
|
// Return JSX directly
|
|
256
256
|
return c.html(
|
|
@@ -378,18 +378,20 @@ export class UserService extends BaseService {
|
|
|
378
378
|
}
|
|
379
379
|
|
|
380
380
|
async getUserWithOrders(userId: string) {
|
|
381
|
+
// findById returns the record or null (no wrapper object)
|
|
381
382
|
const user = await this.userRepository.findById({ id: userId });
|
|
382
|
-
if (!user
|
|
383
|
+
if (!user) {
|
|
383
384
|
return null;
|
|
384
385
|
}
|
|
385
386
|
|
|
387
|
+
// find returns a plain array
|
|
386
388
|
const orders = await this.orderRepository.find({
|
|
387
389
|
filter: { where: { userId } },
|
|
388
390
|
});
|
|
389
391
|
|
|
390
392
|
return {
|
|
391
|
-
...user
|
|
392
|
-
orders
|
|
393
|
+
...user,
|
|
394
|
+
orders,
|
|
393
395
|
};
|
|
394
396
|
}
|
|
395
397
|
|
|
@@ -502,7 +504,7 @@ import { getError, HTTP } from '@venizia/ignis-helpers';
|
|
|
502
504
|
|
|
503
505
|
// Basic error
|
|
504
506
|
throw getError({ message: 'Something went wrong' });
|
|
505
|
-
// Returns: { statusCode: 400, message: 'Something went wrong' }
|
|
507
|
+
// Returns: { statusCode: 400, message: 'Something went wrong', messageCode: 'core.system_error' }
|
|
506
508
|
|
|
507
509
|
// With status code
|
|
508
510
|
throw getError({
|
|
@@ -514,7 +516,7 @@ throw getError({
|
|
|
514
516
|
throw getError({
|
|
515
517
|
statusCode: 404,
|
|
516
518
|
message: 'User not found',
|
|
517
|
-
messageCode: '
|
|
519
|
+
messageCode: 'core.user.not_found',
|
|
518
520
|
});
|
|
519
521
|
```
|
|
520
522
|
|
|
@@ -527,14 +529,14 @@ async getUser(c: TRouteContext) {
|
|
|
527
529
|
|
|
528
530
|
const user = await this.userRepository.findById({ id });
|
|
529
531
|
|
|
530
|
-
if (!user
|
|
532
|
+
if (!user) {
|
|
531
533
|
throw getError({
|
|
532
534
|
statusCode: 404,
|
|
533
535
|
message: `User with ID '${id}' not found`,
|
|
534
536
|
});
|
|
535
537
|
}
|
|
536
538
|
|
|
537
|
-
return c.json(user
|
|
539
|
+
return c.json(user, HTTP.ResultCodes.RS_2.Ok);
|
|
538
540
|
}
|
|
539
541
|
```
|
|
540
542
|
|
|
@@ -546,7 +548,7 @@ All errors are automatically formatted:
|
|
|
546
548
|
{
|
|
547
549
|
"statusCode": 404,
|
|
548
550
|
"message": "User not found",
|
|
549
|
-
"messageCode": "
|
|
551
|
+
"messageCode": "core.user.not_found",
|
|
550
552
|
"requestId": "abc123"
|
|
551
553
|
}
|
|
552
554
|
```
|
|
@@ -592,3 +594,4 @@ async processOrder(c: Context) {
|
|
|
592
594
|
});
|
|
593
595
|
}
|
|
594
596
|
}
|
|
597
|
+
```
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Architectural Patterns
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
IGNIS promotes separation of concerns, dependency injection, and modularity for scalable, maintainable applications.
|
|
4
4
|
|
|
5
5
|
## 1. Layered Architecture
|
|
6
6
|
|
|
7
|
-
Each layer has a single responsibility.
|
|
7
|
+
Each layer has a single responsibility. IGNIS supports **two architectural approaches**:
|
|
8
8
|
|
|
9
9
|
```mermaid
|
|
10
10
|
graph TD
|
|
@@ -117,11 +117,11 @@ REST controllers extend `BaseRestController`, while gRPC controllers extend `Bas
|
|
|
117
117
|
|
|
118
118
|
## 3. Component-Based Modularity
|
|
119
119
|
|
|
120
|
-
Components bundle a group of related, reusable, and pluggable features into self-contained modules. A single component can encapsulate multiple providers, services, controllers, and repositories, essentially functioning as a mini-application that can be easily "plugged in" to any
|
|
120
|
+
Components bundle a group of related, reusable, and pluggable features into self-contained modules. A single component can encapsulate multiple providers, services, controllers, and repositories, essentially functioning as a mini-application that can be easily "plugged in" to any IGNIS project.
|
|
121
121
|
|
|
122
122
|
**Built-in Components:**
|
|
123
123
|
- `AuthenticateComponent` - JWT authentication
|
|
124
|
-
- `
|
|
124
|
+
- `ApiReferenceComponent` - OpenAPI documentation
|
|
125
125
|
- `HealthCheckComponent` - Health check endpoint
|
|
126
126
|
- `RequestTrackerComponent` - Request logging
|
|
127
127
|
|
|
@@ -135,7 +135,7 @@ export class Application extends BaseApplication {
|
|
|
135
135
|
// ...
|
|
136
136
|
// Registering components plugs their functionality into the application.
|
|
137
137
|
this.component(HealthCheckComponent);
|
|
138
|
-
this.component(
|
|
138
|
+
this.component(ApiReferenceComponent);
|
|
139
139
|
// ...
|
|
140
140
|
}
|
|
141
141
|
}
|
|
@@ -154,7 +154,7 @@ You can encapsulate your own logic or third-party integrations (like Socket.IO,
|
|
|
154
154
|
**Example (`SocketIOComponent`):**
|
|
155
155
|
|
|
156
156
|
```typescript
|
|
157
|
-
import { BaseComponent, inject, CoreBindings, Binding } from '@venizia/ignis';
|
|
157
|
+
import { BaseApplication, BaseComponent, inject, CoreBindings, Binding } from '@venizia/ignis';
|
|
158
158
|
|
|
159
159
|
export class MySocketComponent extends BaseComponent {
|
|
160
160
|
constructor(
|
|
@@ -171,7 +171,7 @@ export class MySocketComponent extends BaseComponent {
|
|
|
171
171
|
});
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
// The binding method is called
|
|
174
|
+
// The binding method is called when the application configures components (registerComponents)
|
|
175
175
|
override binding(): void {
|
|
176
176
|
const options = this.application.get({ key: 'my.socket.options' });
|
|
177
177
|
|
|
@@ -185,7 +185,7 @@ export class MySocketComponent extends BaseComponent {
|
|
|
185
185
|
|
|
186
186
|
## 5. Application Lifecycle Hooks
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
IGNIS applications follow a predictable startup sequence with hooks for customization:
|
|
189
189
|
|
|
190
190
|
```
|
|
191
191
|
┌─────────────────────────────────────────────────────────────┐
|
|
@@ -248,25 +248,25 @@ export class Application extends BaseApplication {
|
|
|
248
248
|
|
|
249
249
|
// Components
|
|
250
250
|
this.component(AuthenticateComponent);
|
|
251
|
-
this.component(
|
|
251
|
+
this.component(ApiReferenceComponent);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
// Called after all registrations complete
|
|
255
255
|
async postConfigure(): Promise<void> {
|
|
256
256
|
// Access registered services
|
|
257
|
-
const
|
|
257
|
+
const userRepository = this.get<UserRepository>({
|
|
258
258
|
key: BindingKeys.build({
|
|
259
259
|
namespace: BindingNamespaces.REPOSITORY,
|
|
260
260
|
key: UserRepository.name,
|
|
261
261
|
}),
|
|
262
262
|
});
|
|
263
263
|
|
|
264
|
-
// Seed initial data
|
|
265
|
-
const adminExists = await
|
|
264
|
+
// Seed initial data (findOne returns the record or null)
|
|
265
|
+
const adminExists = await userRepository.findOne({
|
|
266
266
|
filter: { where: { role: 'admin' } },
|
|
267
267
|
});
|
|
268
|
-
if (!adminExists
|
|
269
|
-
await
|
|
268
|
+
if (!adminExists) {
|
|
269
|
+
await userRepository.create({ data: { name: 'Admin', role: 'admin' } });
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
|
|
@@ -280,55 +280,40 @@ export class Application extends BaseApplication {
|
|
|
280
280
|
> [!WARNING]
|
|
281
281
|
> Do not register new datasources, components, or controllers in `postConfigure()`. They will not be automatically initialized. Use `preConfigure()` for all registrations.
|
|
282
282
|
|
|
283
|
-
## 6.
|
|
283
|
+
## 6. Registration Surface & Capability Interfaces
|
|
284
284
|
|
|
285
|
-
|
|
285
|
+
`BaseApplication` implements the full resource-registration surface directly - `service()`, `repository()`, `dataSource()`, `controller()`, `component()`, and `booter()`. Extend `BaseApplication` and call these methods straight from your lifecycle hooks; there is nothing to compose.
|
|
286
286
|
|
|
287
|
-
**How
|
|
287
|
+
**How registration works:**
|
|
288
288
|
```typescript
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
return
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}).toClass(ctor);
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
};
|
|
289
|
+
// BaseApplication implements service() directly (no mixin composition):
|
|
290
|
+
service<Base extends IService>(ctor: TClass<Base>): Binding<Base> {
|
|
291
|
+
return this.bind<Base>({
|
|
292
|
+
key: BindingKeys.build({
|
|
293
|
+
namespace: BindingNamespaces.SERVICE,
|
|
294
|
+
key: ctor.name,
|
|
295
|
+
}),
|
|
296
|
+
}).toClass(ctor);
|
|
297
|
+
}
|
|
302
298
|
```
|
|
303
299
|
|
|
304
|
-
**
|
|
300
|
+
**Capability interfaces:**
|
|
305
301
|
|
|
306
|
-
|
|
307
|
-
|-------|---------------|---------|
|
|
308
|
-
| `ServiceMixin` | `service()` | Register service classes |
|
|
309
|
-
| `RepositoryMixin` | `repository()`, `dataSource()`, `registerDataSources()` | Register data layer |
|
|
310
|
-
| `ControllerMixin` | `controller()` | Register HTTP controllers |
|
|
311
|
-
| `ComponentMixin` | `component()` | Register modular components |
|
|
302
|
+
Each registration capability is declared as a TypeScript interface that `IRestApplication` (and therefore `BaseApplication`) implements. Reference these when you type your own application contracts:
|
|
312
303
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
ServiceMixin(
|
|
319
|
-
RepositoryMixin(BaseClass)
|
|
320
|
-
)
|
|
321
|
-
)
|
|
322
|
-
) {
|
|
323
|
-
// Now has: service(), repository(), dataSource(), controller(), component()
|
|
324
|
-
}
|
|
325
|
-
```
|
|
304
|
+
| Interface | Methods | Purpose |
|
|
305
|
+
|-----------|---------|---------|
|
|
306
|
+
| `IServiceMixin` | `service()` | Register service classes |
|
|
307
|
+
| `IRepositoryMixin` | `repository()`, `dataSource()`, `registerDataSources()` | Register data layer |
|
|
308
|
+
| `IComponentMixin` | `component()`, `registerComponents()` | Register modular components |
|
|
326
309
|
|
|
327
|
-
|
|
328
|
-
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
-
|
|
310
|
+
> [!NOTE]
|
|
311
|
+
> Earlier releases also exported `ServiceMixin`, `RepositoryMixin`, and `ComponentMixin` as class-mixin **functions** you composed onto `AbstractApplication`. They duplicated `BaseApplication`'s own methods verbatim, drifted out of sync, and had no known consumers, so they were removed. The `IServiceMixin` / `IRepositoryMixin` / `IComponentMixin` **interfaces** remain - extend `BaseApplication` and call its registration methods directly.
|
|
312
|
+
|
|
313
|
+
**Why direct methods over composed mixins?**
|
|
314
|
+
- One implementation, no drift between a mixin and the base class
|
|
315
|
+
- Registration is available the moment you extend `BaseApplication`
|
|
316
|
+
- The interfaces still express each capability for typed contracts
|
|
332
317
|
|
|
333
318
|
## 7. Controller Factory Pattern
|
|
334
319
|
|
|
@@ -337,13 +322,13 @@ class AbstractApplication extends ComponentMixin(
|
|
|
337
322
|
**Basic Usage:**
|
|
338
323
|
```typescript
|
|
339
324
|
const _Controller = ControllerFactory.defineCrudController({
|
|
340
|
-
entity: () => User,
|
|
325
|
+
entity: () => User, // Entity class or resolver function
|
|
341
326
|
repository: { name: UserRepository.name },
|
|
342
327
|
controller: {
|
|
343
328
|
name: 'UserController',
|
|
344
329
|
basePath: '/users',
|
|
345
|
-
|
|
346
|
-
|
|
330
|
+
// Default: { path: true, requestSchema: true }
|
|
331
|
+
isStrict: { path: true, requestSchema: true },
|
|
347
332
|
},
|
|
348
333
|
});
|
|
349
334
|
|
|
@@ -366,14 +351,14 @@ const _Controller = ControllerFactory.defineCrudController({
|
|
|
366
351
|
controller: { name: 'UserController', basePath: '/users' },
|
|
367
352
|
|
|
368
353
|
// Apply JWT to all routes by default
|
|
369
|
-
|
|
354
|
+
authenticate: { strategies: [Authentication.STRATEGY_JWT] },
|
|
370
355
|
|
|
371
356
|
// Override per-route
|
|
372
357
|
routes: {
|
|
373
358
|
// Public read endpoints
|
|
374
|
-
find: {
|
|
375
|
-
findById: {
|
|
376
|
-
count: {
|
|
359
|
+
find: { authenticate: { skip: true } },
|
|
360
|
+
findById: { authenticate: { skip: true } },
|
|
361
|
+
count: { authenticate: { skip: true } },
|
|
377
362
|
|
|
378
363
|
// Protected write endpoints (use controller-level auth)
|
|
379
364
|
create: {},
|
|
@@ -393,22 +378,26 @@ const _Controller = ControllerFactory.defineCrudController({
|
|
|
393
378
|
routes: {
|
|
394
379
|
// Custom request body schema for create
|
|
395
380
|
create: {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
381
|
+
authenticate: { strategies: [Authentication.STRATEGY_JWT] },
|
|
382
|
+
request: {
|
|
383
|
+
body: z.object({
|
|
384
|
+
email: z.string().email(),
|
|
385
|
+
name: z.string().min(2),
|
|
386
|
+
// Exclude sensitive fields from client input
|
|
387
|
+
}),
|
|
388
|
+
},
|
|
402
389
|
},
|
|
403
390
|
|
|
404
391
|
// Custom response schema
|
|
405
392
|
find: {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
393
|
+
authenticate: { skip: true },
|
|
394
|
+
response: {
|
|
395
|
+
schema: z.array(z.object({
|
|
396
|
+
id: z.string(),
|
|
397
|
+
name: z.string(),
|
|
398
|
+
// Exclude internal fields from response
|
|
399
|
+
})),
|
|
400
|
+
},
|
|
412
401
|
},
|
|
413
402
|
},
|
|
414
403
|
});
|
|
@@ -420,10 +409,13 @@ const _Controller = ControllerFactory.defineCrudController({
|
|
|
420
409
|
|-------|--------|------|-------------|
|
|
421
410
|
| `count` | GET | `/count` | Count records matching filter |
|
|
422
411
|
| `find` | GET | `/` | List records with filter |
|
|
423
|
-
| `findById` | GET |
|
|
412
|
+
| `findById` | GET | `/{id}` | Get single record |
|
|
424
413
|
| `findOne` | GET | `/find-one` | Get first matching record |
|
|
425
414
|
| `create` | POST | `/` | Create new record |
|
|
426
|
-
| `updateById` | PATCH |
|
|
415
|
+
| `updateById` | PATCH | `/{id}` | Update record by ID |
|
|
427
416
|
| `updateBy` | PATCH | `/` | Bulk update by filter |
|
|
428
|
-
| `deleteById` | DELETE |
|
|
429
|
-
| `deleteBy` | DELETE | `/` | Bulk delete by filter |
|
|
417
|
+
| `deleteById` | DELETE | `/{id}` | Delete by ID |
|
|
418
|
+
| `deleteBy` | DELETE | `/` | Bulk delete by filter |
|
|
419
|
+
|
|
420
|
+
> [!TIP]
|
|
421
|
+
> `TDataObject`/`TPersistObject` cannot be inferred from `entity` - pass them explicitly for typed handlers: `ControllerFactory.defineCrudController<TUserRecord>({ ... })`. Use `controller.enabledRoutes` to whitelist routes and `controller.readonly` to disable all write routes.
|