@venizia/ignis-docs 0.0.8-3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/{wiki → content}/best-practices/api-usage-examples.md +15 -12
- package/{wiki → content}/best-practices/architectural-patterns.md +70 -78
- package/{wiki → content}/best-practices/architecture-decisions.md +91 -60
- package/{wiki → content}/best-practices/code-style-standards/advanced-patterns.md +56 -44
- package/{wiki → content}/best-practices/code-style-standards/constants-configuration.md +11 -11
- package/{wiki → content}/best-practices/code-style-standards/control-flow.md +5 -2
- package/{wiki → content}/best-practices/code-style-standards/documentation.md +13 -13
- package/{wiki → content}/best-practices/code-style-standards/function-patterns.md +9 -10
- package/{wiki → content}/best-practices/code-style-standards/index.md +1 -1
- package/{wiki → content}/best-practices/code-style-standards/naming-conventions.md +10 -8
- package/{wiki → content}/best-practices/code-style-standards/route-definitions.md +30 -12
- package/{wiki → content}/best-practices/code-style-standards/tooling.md +8 -5
- package/{wiki → content}/best-practices/code-style-standards/type-safety.md +13 -12
- package/{wiki → content}/best-practices/common-pitfalls.md +56 -37
- package/{wiki → content}/best-practices/contribution-workflow.md +13 -14
- package/{wiki → content}/best-practices/data-modeling.md +44 -20
- package/{wiki → content}/best-practices/deployment-strategies.md +28 -27
- package/{wiki → content}/best-practices/error-handling.md +48 -24
- package/{wiki → content}/best-practices/index.md +5 -5
- package/{wiki → content}/best-practices/performance-optimization.md +36 -28
- package/{wiki → content}/best-practices/security-guidelines.md +52 -23
- package/{wiki → content}/best-practices/testing-strategies.md +65 -51
- package/{wiki → content}/best-practices/troubleshooting-tips.md +24 -24
- package/{wiki/extensions/components/swagger.md → content/extensions/components/api-reference.md} +40 -31
- package/{wiki → content}/extensions/components/authentication/api.md +19 -19
- package/{wiki → content}/extensions/components/authentication/errors.md +7 -7
- package/{wiki → content}/extensions/components/authentication/index.md +10 -8
- package/{wiki → content}/extensions/components/authentication/usage.md +101 -6
- package/{wiki → content}/extensions/components/authorization/api.md +45 -25
- package/{wiki → content}/extensions/components/authorization/errors.md +6 -6
- package/{wiki → content}/extensions/components/authorization/index.md +11 -10
- package/{wiki → content}/extensions/components/authorization/usage.md +21 -21
- package/{wiki → content}/extensions/components/health-check.md +1 -1
- package/{wiki → content}/extensions/components/index.md +5 -5
- package/{wiki → content}/extensions/components/mail/errors.md +15 -15
- package/{wiki → content}/extensions/components/mail/index.md +1 -2
- package/{wiki → content}/extensions/components/mail/usage.md +1 -1
- package/{wiki → content}/extensions/components/request-tracker.md +1 -1
- package/{wiki → content}/extensions/components/socket-io/api.md +9 -9
- package/{wiki → content}/extensions/components/socket-io/errors.md +5 -5
- package/{wiki → content}/extensions/components/socket-io/index.md +8 -8
- package/{wiki → content}/extensions/components/socket-io/usage.md +1 -1
- package/{wiki → content}/extensions/components/static-asset/api.md +17 -4
- package/{wiki → content}/extensions/components/static-asset/errors.md +4 -4
- package/{wiki → content}/extensions/components/static-asset/index.md +26 -28
- package/{wiki → content}/extensions/components/static-asset/usage.md +13 -12
- package/{wiki → content}/extensions/components/template/index.md +2 -2
- package/{wiki → content}/extensions/components/template/setup-page.md +1 -1
- package/{wiki → content}/extensions/components/websocket/api.md +3 -3
- package/{wiki → content}/extensions/components/websocket/errors.md +5 -5
- package/{wiki → content}/extensions/components/websocket/index.md +5 -5
- package/{wiki → content}/extensions/components/websocket/usage.md +3 -3
- package/{wiki → content}/extensions/helpers/cron/index.md +2 -2
- package/{wiki → content}/extensions/helpers/crypto/index.md +1 -1
- package/{wiki → content}/extensions/helpers/env/index.md +27 -12
- package/content/extensions/helpers/error/index.md +283 -0
- package/{wiki → content}/extensions/helpers/index.md +2 -3
- package/{wiki → content}/extensions/helpers/inversion/index.md +15 -7
- package/{wiki → content}/extensions/helpers/kafka/examples.md +1 -1
- package/{wiki → content}/extensions/helpers/logger/index.md +32 -2
- package/{wiki → content}/extensions/helpers/network/index.md +6 -0
- package/{wiki → content}/extensions/helpers/queue/index.md +14 -17
- package/content/extensions/helpers/redis/index.md +713 -0
- package/{wiki → content}/extensions/helpers/socket-io/index.md +14 -10
- package/{wiki → content}/extensions/helpers/storage/api.md +44 -8
- package/{wiki → content}/extensions/helpers/storage/index.md +43 -7
- package/{wiki → content}/extensions/helpers/template/index.md +6 -3
- package/{wiki → content}/extensions/helpers/types/index.md +11 -8
- package/{wiki → content}/extensions/helpers/websocket/api.md +9 -9
- package/{wiki → content}/extensions/helpers/websocket/index.md +7 -7
- package/{wiki → content}/extensions/helpers/worker-thread/index.md +2 -2
- package/{wiki → content}/extensions/index.md +3 -4
- package/{wiki → content}/extensions/src-details/mcp-server.md +18 -24
- package/{wiki → content}/guides/core-concepts/application/bootstrapping.md +11 -14
- package/{wiki → content}/guides/core-concepts/application/index.md +3 -3
- package/{wiki → content}/guides/core-concepts/components.md +19 -10
- package/{wiki → content}/guides/core-concepts/dependency-injection.md +6 -3
- package/{wiki → content}/guides/core-concepts/grpc-controllers.md +6 -5
- package/{wiki → content}/guides/core-concepts/persistent/datasources.md +33 -27
- package/{wiki → content}/guides/core-concepts/persistent/index.md +16 -5
- package/{wiki → content}/guides/core-concepts/persistent/models.md +24 -20
- package/content/guides/core-concepts/persistent/postgres-drivers.md +167 -0
- package/{wiki → content}/guides/core-concepts/persistent/repositories.md +40 -23
- package/content/guides/core-concepts/persistent/search-meilisearch.md +183 -0
- package/content/guides/core-concepts/persistent/search-typesense.md +429 -0
- package/{wiki → content}/guides/core-concepts/persistent/transactions.md +61 -25
- package/{wiki → content}/guides/core-concepts/rest-controllers.md +12 -9
- package/content/guides/core-concepts/services.md +389 -0
- package/{wiki → content}/guides/get-started/5-minute-quickstart.md +19 -19
- package/{wiki → content}/guides/get-started/philosophy.md +36 -36
- package/{wiki → content}/guides/get-started/setup.md +3 -3
- package/{wiki → content}/guides/index.md +3 -3
- package/content/guides/migrations/redis-helpers-migration.md +177 -0
- package/{wiki → content}/guides/migrations/scoped-rbac-migration.md +17 -17
- package/content/guides/migrations/unified-connectors-migration.md +113 -0
- package/{wiki → content}/guides/reference/glossary.md +19 -12
- package/{wiki → content}/guides/reference/mcp-docs-server.md +22 -18
- package/{wiki → content}/guides/tutorials/building-a-crud-api.md +30 -33
- package/{wiki → content}/guides/tutorials/complete-installation.md +17 -17
- package/{wiki → content}/guides/tutorials/ecommerce-api.md +158 -119
- package/{wiki → content}/guides/tutorials/realtime-chat.md +176 -130
- package/content/guides/tutorials/testing.md +264 -0
- package/content/index.md +5 -0
- 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/{wiki → content}/references/base/application.md +4 -5
- package/{wiki → content}/references/base/bootstrapping.md +18 -5
- package/{wiki → content}/references/base/components.md +149 -120
- package/content/references/base/connectors.md +178 -0
- package/{wiki → content}/references/base/controllers.md +41 -30
- package/content/references/base/datasources.md +527 -0
- package/{wiki → content}/references/base/dependency-injection.md +34 -22
- package/{wiki → content}/references/base/filter-system/application-usage.md +17 -14
- package/{wiki → content}/references/base/filter-system/array-operators.md +7 -2
- package/{wiki → content}/references/base/filter-system/comparison-operators.md +3 -0
- package/{wiki → content}/references/base/filter-system/default-filter.md +89 -71
- package/{wiki → content}/references/base/filter-system/fields-order-pagination.md +22 -22
- package/{wiki → content}/references/base/filter-system/index.md +6 -3
- package/{wiki → content}/references/base/filter-system/json-filtering.md +20 -1
- package/{wiki → content}/references/base/filter-system/list-operators.md +1 -1
- package/{wiki → content}/references/base/filter-system/logical-operators.md +33 -1
- package/{wiki → content}/references/base/filter-system/null-operators.md +30 -1
- package/{wiki → content}/references/base/filter-system/quick-reference.md +23 -4
- package/{wiki → content}/references/base/filter-system/tips.md +5 -5
- package/{wiki → content}/references/base/filter-system/use-cases.md +12 -12
- package/{wiki → content}/references/base/grpc-controllers.md +13 -13
- package/{wiki → content}/references/base/index.md +24 -12
- package/{wiki/references/base/middleware.md → content/references/base/middlewares.md} +205 -24
- package/{wiki → content}/references/base/models.md +63 -49
- package/{wiki → content}/references/base/providers.md +136 -130
- package/{wiki → content}/references/base/repositories/advanced.md +59 -58
- package/{wiki → content}/references/base/repositories/index.md +115 -91
- package/content/references/base/repositories/mixins.md +99 -0
- package/{wiki → content}/references/base/repositories/relations.md +54 -64
- package/{wiki → content}/references/base/repositories/soft-deletable.md +31 -30
- package/content/references/base/services.md +404 -0
- package/{wiki → content}/references/configuration/environment-variables.md +46 -30
- package/{wiki → content}/references/configuration/index.md +6 -6
- package/{wiki → content}/references/index.md +17 -12
- package/{wiki → content}/references/quick-reference.md +65 -106
- package/content/references/utilities/crypto.md +98 -0
- package/{wiki → content}/references/utilities/index.md +3 -3
- package/{wiki → content}/references/utilities/jsx.md +6 -4
- package/content/references/utilities/module.md +90 -0
- package/{wiki → content}/references/utilities/parse.md +4 -14
- package/{wiki → content}/references/utilities/promise.md +9 -7
- package/{wiki → 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/common/paths.d.ts.map +1 -1
- package/dist/mcp-server/common/paths.js +2 -2
- package/dist/mcp-server/common/paths.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 +12 -12
- package/wiki/extensions/helpers/error/index.md +0 -227
- package/wiki/extensions/helpers/redis/index.md +0 -488
- package/wiki/extensions/helpers/testing/index.md +0 -510
- package/wiki/guides/core-concepts/services.md +0 -119
- package/wiki/guides/tutorials/testing.md +0 -722
- package/wiki/index.md +0 -183
- package/wiki/references/base/datasources.md +0 -454
- package/wiki/references/base/middlewares.md +0 -590
- package/wiki/references/base/repositories/mixins.md +0 -335
- package/wiki/references/base/services.md +0 -201
- package/wiki/references/utilities/crypto.md +0 -56
- package/wiki/references/utilities/module.md +0 -42
- /package/{wiki → content}/extensions/components/mail/api.md +0 -0
- /package/{wiki → content}/extensions/components/template/api-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/errors-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/usage-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/admin.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/consumer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/index.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/producer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/schema-registry.md +0 -0
- /package/{wiki → content}/extensions/helpers/network/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/socket-io/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/uid/index.md +0 -0
- /package/{wiki → content}/guides/core-concepts/components-guide.md +0 -0
- /package/{wiki → content}/public/logo.svg +0 -0
- /package/{wiki → content}/references/base/filter-system/pattern-matching.md +0 -0
- /package/{wiki → content}/references/base/filter-system/range-operators.md +0 -0
- /package/{wiki → content}/references/utilities/date.md +0 -0
- /package/{wiki → content}/references/utilities/performance.md +0 -0
- /package/{wiki → content}/references/utilities/request.md +0 -0
- /package/{wiki → content}/references/utilities/statuses.md +0 -0
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Repository Mixins
|
|
3
|
-
description: Composable mixins for repository functionality
|
|
4
|
-
difficulty: intermediate
|
|
5
|
-
lastUpdated: 2026-01-02
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Repository Mixins <Badge type="tip" text="v0.0.5+" />
|
|
9
|
-
|
|
10
|
-
Composable mixins that provide reusable functionality for repository classes.
|
|
11
|
-
|
|
12
|
-
> [!NOTE] Refactored in v0.0.5
|
|
13
|
-
> Repository mixins were extracted and refactored in v0.0.5 to provide better composition and reusability.
|
|
14
|
-
|
|
15
|
-
**Files:** `packages/core/src/base/repositories/mixins/`
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
## Overview
|
|
19
|
-
|
|
20
|
-
Ignis uses the mixin pattern to compose repository features. This enables:
|
|
21
|
-
|
|
22
|
-
- **Separation of concerns** - Each mixin handles one responsibility
|
|
23
|
-
- **Reusability** - Mixins can be applied to different base classes
|
|
24
|
-
- **Testability** - Individual features can be tested in isolation
|
|
25
|
-
- **Flexibility** - Create custom repositories with only needed features
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
## Available Mixins
|
|
29
|
-
|
|
30
|
-
| Mixin | Responsibility |
|
|
31
|
-
|-------|----------------|
|
|
32
|
-
| `FieldsVisibilityMixin` | Hidden properties exclusion at SQL level |
|
|
33
|
-
| `DefaultFilterMixin` | Automatic filter application from model settings |
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
## FieldsVisibilityMixin
|
|
37
|
-
|
|
38
|
-
Provides hidden properties management for SQL-level field exclusion. Reads `hiddenProperties` from `@model` metadata settings and builds a visible columns map for Drizzle's `select()` and `returning()` calls.
|
|
39
|
-
|
|
40
|
-
**File:** `packages/core/src/base/repositories/mixins/fields-visibility.ts`
|
|
41
|
-
|
|
42
|
-
### Abstract Requirements
|
|
43
|
-
|
|
44
|
-
Classes using this mixin must implement:
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
abstract getEntity(): BaseEntity<TTableSchemaWithId>;
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Properties
|
|
51
|
-
|
|
52
|
-
| Property | Type | Description |
|
|
53
|
-
|----------|------|-------------|
|
|
54
|
-
| `_hiddenProperties` | `Set<string> \| null` | Cached hidden property names (`null` = not yet computed) |
|
|
55
|
-
| `_visibleProperties` | `Record<string, any> \| null \| undefined` | Cached visible columns (`null` = not yet computed, `undefined` = computed with no hidden props) |
|
|
56
|
-
|
|
57
|
-
### Methods
|
|
58
|
-
|
|
59
|
-
| Method | Returns | Description |
|
|
60
|
-
|--------|---------|-------------|
|
|
61
|
-
| `get hiddenProperties` | `Set<string>` | Getter that delegates to `getHiddenProperties()` |
|
|
62
|
-
| `set hiddenProperties` | `void` | Override hidden properties set |
|
|
63
|
-
| `getHiddenProperties()` | `Set<string>` | Get hidden properties from model metadata (cached) |
|
|
64
|
-
| `hasHiddenProperties()` | `boolean` | Check if model has any hidden properties |
|
|
65
|
-
| `get visibleProperties` | `Record<string, any> \| undefined` | Getter that delegates to `getVisibleProperties()` |
|
|
66
|
-
| `set visibleProperties` | `void` | Override visible properties |
|
|
67
|
-
| `getVisibleProperties()` | `Record<string, any> \| undefined` | Build visible columns object for Drizzle (cached). Returns `undefined` if no hidden props. |
|
|
68
|
-
|
|
69
|
-
### Usage
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
import { FieldsVisibilityMixin } from '@venizia/ignis';
|
|
73
|
-
import { BaseHelper } from '@venizia/ignis-helpers';
|
|
74
|
-
|
|
75
|
-
class MyRepository extends FieldsVisibilityMixin(BaseHelper) {
|
|
76
|
-
// Required abstract implementation
|
|
77
|
-
abstract getEntity(): BaseEntity;
|
|
78
|
-
|
|
79
|
-
// Now has access to:
|
|
80
|
-
// - hiddenProperties (getter/setter)
|
|
81
|
-
// - visibleProperties (getter/setter)
|
|
82
|
-
// - getHiddenProperties()
|
|
83
|
-
// - hasHiddenProperties()
|
|
84
|
-
// - getVisibleProperties()
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Visible Properties for Drizzle
|
|
89
|
-
|
|
90
|
-
The `getVisibleProperties()` method returns a columns object for Drizzle's `select()` or `returning()`:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
// Model with hiddenProperties: ['password', 'apiKey']
|
|
94
|
-
// Schema columns: { id, email, password, apiKey, createdAt }
|
|
95
|
-
|
|
96
|
-
const visibleProps = this.getVisibleProperties();
|
|
97
|
-
// Result: { id: column, email: column, createdAt: column }
|
|
98
|
-
// (password and apiKey excluded)
|
|
99
|
-
|
|
100
|
-
// Used in Drizzle queries
|
|
101
|
-
await connector.select(visibleProps).from(schema);
|
|
102
|
-
// SELECT id, email, created_at FROM users
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### How It Resolves Hidden Properties
|
|
106
|
-
|
|
107
|
-
1. Checks the cache (`_hiddenProperties`). If not `null`, returns cached value.
|
|
108
|
-
2. Looks up the entity name in `MetadataRegistry.getModelEntry()`.
|
|
109
|
-
3. Reads `metadata.settings.hiddenProperties` (array of field names).
|
|
110
|
-
4. Converts to a `Set<string>` and caches.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
## DefaultFilterMixin
|
|
114
|
-
|
|
115
|
-
Provides automatic default filter application for all repository queries. Reads `defaultFilter` from `@model` metadata settings and merges it with user-provided filters.
|
|
116
|
-
|
|
117
|
-
**File:** `packages/core/src/base/repositories/mixins/default-filter.ts`
|
|
118
|
-
|
|
119
|
-
### Abstract Requirements
|
|
120
|
-
|
|
121
|
-
Classes using this mixin must implement:
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
abstract getEntity(): BaseEntity<TTableSchemaWithId>;
|
|
125
|
-
abstract get filterBuilder(): FilterBuilder;
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Properties
|
|
129
|
-
|
|
130
|
-
| Property | Type | Description |
|
|
131
|
-
|----------|------|-------------|
|
|
132
|
-
| `_defaultFilter` | `TFilter \| null \| undefined` | Cached default filter (`null` = not yet computed, `undefined` = computed with no default filter) |
|
|
133
|
-
|
|
134
|
-
### Methods
|
|
135
|
-
|
|
136
|
-
| Method | Returns | Description |
|
|
137
|
-
|--------|---------|-------------|
|
|
138
|
-
| `getDefaultFilter()` | `TFilter \| undefined` | Get default filter from model metadata (cached) |
|
|
139
|
-
| `hasDefaultFilter()` | `boolean` | Check if model has a default filter configured |
|
|
140
|
-
| `applyDefaultFilter(opts)` | `TFilter` | Merge default filter with user filter |
|
|
141
|
-
|
|
142
|
-
### Usage
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
import { DefaultFilterMixin } from '@venizia/ignis';
|
|
146
|
-
import { BaseHelper } from '@venizia/ignis-helpers';
|
|
147
|
-
|
|
148
|
-
class MyRepository extends DefaultFilterMixin(BaseHelper) {
|
|
149
|
-
// Required abstract implementations
|
|
150
|
-
abstract getEntity(): BaseEntity;
|
|
151
|
-
abstract get filterBuilder(): FilterBuilder;
|
|
152
|
-
|
|
153
|
-
// Now has access to:
|
|
154
|
-
// - getDefaultFilter()
|
|
155
|
-
// - hasDefaultFilter()
|
|
156
|
-
// - applyDefaultFilter()
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### applyDefaultFilter Options
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
applyDefaultFilter<DataObject = any>(opts: {
|
|
164
|
-
userFilter?: TFilter<DataObject>; // User-provided filter
|
|
165
|
-
shouldSkipDefaultFilter?: boolean; // If true, bypass default filter
|
|
166
|
-
}): TFilter<DataObject>
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
**Behavior:**
|
|
170
|
-
|
|
171
|
-
1. If `shouldSkipDefaultFilter` is `true`, returns the user filter as-is (or `{}` if none).
|
|
172
|
-
2. If no default filter is configured, returns the user filter as-is (or `{}` if none).
|
|
173
|
-
3. Otherwise, delegates to `filterBuilder.mergeFilter({ defaultFilter, userFilter })` which deep-merges `where` conditions and uses user values for other filter properties (`order`, `limit`, `offset`, `skip`, `fields`, `include`).
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
## Mixin Composition
|
|
177
|
-
|
|
178
|
-
The `AbstractRepository` composes both mixins:
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
export abstract class AbstractRepository<...>
|
|
182
|
-
extends DefaultFilterMixin(FieldsVisibilityMixin(BaseHelper))
|
|
183
|
-
implements IPersistableRepository<...>
|
|
184
|
-
{
|
|
185
|
-
// Inherits from both mixins:
|
|
186
|
-
// From FieldsVisibilityMixin:
|
|
187
|
-
// - hiddenProperties (getter/setter)
|
|
188
|
-
// - visibleProperties (getter/setter)
|
|
189
|
-
// - getHiddenProperties()
|
|
190
|
-
// - hasHiddenProperties()
|
|
191
|
-
// - getVisibleProperties()
|
|
192
|
-
//
|
|
193
|
-
// From DefaultFilterMixin:
|
|
194
|
-
// - getDefaultFilter()
|
|
195
|
-
// - hasDefaultFilter()
|
|
196
|
-
// - applyDefaultFilter()
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Composition Order
|
|
201
|
-
|
|
202
|
-
Mixins are applied right-to-left:
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
// FieldsVisibilityMixin applied first (to BaseHelper)
|
|
206
|
-
// DefaultFilterMixin applied second (to the result)
|
|
207
|
-
DefaultFilterMixin(FieldsVisibilityMixin(BaseHelper))
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
## Creating Custom Mixins
|
|
212
|
-
|
|
213
|
-
Follow the TypeScript mixin pattern using `TMixinTarget`:
|
|
214
|
-
|
|
215
|
-
```typescript
|
|
216
|
-
import { TMixinTarget } from '@venizia/ignis-helpers';
|
|
217
|
-
|
|
218
|
-
export const AuditLogMixin = <T extends TMixinTarget<object>>(baseClass: T) => {
|
|
219
|
-
abstract class Mixed extends baseClass {
|
|
220
|
-
// Properties
|
|
221
|
-
private _auditEnabled: boolean = true;
|
|
222
|
-
|
|
223
|
-
// Abstract dependencies (if needed)
|
|
224
|
-
abstract getEntity(): BaseEntity;
|
|
225
|
-
|
|
226
|
-
// Public methods
|
|
227
|
-
enableAudit(): void {
|
|
228
|
-
this._auditEnabled = true;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
disableAudit(): void {
|
|
232
|
-
this._auditEnabled = false;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
isAuditEnabled(): boolean {
|
|
236
|
-
return this._auditEnabled;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
logOperation(operation: string, data: any): void {
|
|
240
|
-
if (this._auditEnabled) {
|
|
241
|
-
console.log(`[${this.getEntity().name}] ${operation}:`, data);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return Mixed;
|
|
247
|
-
};
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Using Custom Mixins
|
|
251
|
-
|
|
252
|
-
```typescript
|
|
253
|
-
// Compose with existing mixins
|
|
254
|
-
class MyRepository extends AuditLogMixin(DefaultFilterMixin(BaseHelper)) {
|
|
255
|
-
getEntity() {
|
|
256
|
-
return this._entity;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
get filterBuilder() {
|
|
260
|
-
return this._filterBuilder;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Or create a composed base
|
|
265
|
-
const AuditableRepository = AuditLogMixin(DefaultFilterMixin(FieldsVisibilityMixin(BaseHelper)));
|
|
266
|
-
|
|
267
|
-
class ProductRepository extends AuditableRepository {
|
|
268
|
-
// Has all mixin functionality
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
## Caching Behavior
|
|
274
|
-
|
|
275
|
-
Both mixins use a three-state caching pattern for performance:
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
// DefaultFilterMixin caching
|
|
279
|
-
// null = not computed yet
|
|
280
|
-
// undefined = computed, no default filter exists
|
|
281
|
-
// TFilter = computed, has default filter
|
|
282
|
-
_defaultFilter: TFilter | null | undefined = null;
|
|
283
|
-
|
|
284
|
-
getDefaultFilter() {
|
|
285
|
-
if (this._defaultFilter !== null) {
|
|
286
|
-
return this._defaultFilter; // Return cached value (either TFilter or undefined)
|
|
287
|
-
}
|
|
288
|
-
// Compute from MetadataRegistry and cache...
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// FieldsVisibilityMixin caching
|
|
292
|
-
// null = not computed yet
|
|
293
|
-
// Set<string> = computed (may be empty)
|
|
294
|
-
_hiddenProperties: Set<string> | null = null;
|
|
295
|
-
|
|
296
|
-
// null = not computed yet
|
|
297
|
-
// undefined = computed, no hidden properties exist
|
|
298
|
-
// Record<string, any> = computed, has visible column map
|
|
299
|
-
_visibleProperties: Record<string, any> | null | undefined = null;
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
This ensures metadata lookups happen only once per repository instance, with subsequent calls returning the cached value.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
## Quick Reference
|
|
306
|
-
|
|
307
|
-
| Mixin | Method | Purpose |
|
|
308
|
-
|-------|--------|---------|
|
|
309
|
-
| `FieldsVisibilityMixin` | `hasHiddenProperties()` | Check if hidden props exist |
|
|
310
|
-
| `FieldsVisibilityMixin` | `getHiddenProperties()` | Get hidden property names as `Set<string>` |
|
|
311
|
-
| `FieldsVisibilityMixin` | `getVisibleProperties()` | Get Drizzle columns object (excludes hidden) |
|
|
312
|
-
| `DefaultFilterMixin` | `hasDefaultFilter()` | Check if default filter exists |
|
|
313
|
-
| `DefaultFilterMixin` | `getDefaultFilter()` | Get raw default filter from model metadata |
|
|
314
|
-
| `DefaultFilterMixin` | `applyDefaultFilter()` | Merge default filter with user filter |
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
## Next Steps
|
|
318
|
-
|
|
319
|
-
- [Default Filter](../filter-system/default-filter.md) - Full default filter documentation
|
|
320
|
-
- [Advanced Features](./advanced.md) - Hidden properties usage
|
|
321
|
-
- [Repository Overview](./index.md) - Repository basics
|
|
322
|
-
|
|
323
|
-
## See Also
|
|
324
|
-
|
|
325
|
-
- **Related Concepts:**
|
|
326
|
-
- [Repositories Overview](./index) - Core repository operations
|
|
327
|
-
- [Models](/guides/core-concepts/persistent/models) - Entity definitions
|
|
328
|
-
|
|
329
|
-
- **Related Topics:**
|
|
330
|
-
- [Default Filter](../filter-system/default-filter) - Automatic filtering
|
|
331
|
-
- [Advanced Features](./advanced) - Hidden properties and transactions
|
|
332
|
-
- [Relations & Includes](./relations) - Loading related data
|
|
333
|
-
|
|
334
|
-
- **Best Practices:**
|
|
335
|
-
- [Data Modeling](/best-practices/data-modeling) - Soft delete patterns
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Services Reference
|
|
3
|
-
description: Technical reference for BaseService and business logic layer
|
|
4
|
-
difficulty: beginner
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Deep Dive: Services
|
|
8
|
-
|
|
9
|
-
Technical reference for `BaseService` - the foundation for business logic layers in Ignis.
|
|
10
|
-
|
|
11
|
-
**File:** `packages/core/src/base/services/base.ts`
|
|
12
|
-
|
|
13
|
-
## Quick Reference
|
|
14
|
-
|
|
15
|
-
| Feature | Benefit |
|
|
16
|
-
|---------|---------|
|
|
17
|
-
| **Extends `BaseHelper`** | Auto-configured scoped logger (`this.logger`) |
|
|
18
|
-
| **DI Integration** | Fits into framework's dependency injection system |
|
|
19
|
-
| **Business Logic Layer** | Bridge between Controllers and Repositories |
|
|
20
|
-
| **No built-in CRUD** | Services are for business logic, not data access — that's what Repositories are for |
|
|
21
|
-
|
|
22
|
-
## `BaseService` Class
|
|
23
|
-
|
|
24
|
-
Abstract class that all application services should extend. It implements the `IService` interface (currently a marker interface with no required methods).
|
|
25
|
-
|
|
26
|
-
### Class Definition
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import { BaseHelper } from '@venizia/ignis-helpers';
|
|
30
|
-
import { IService } from './types';
|
|
31
|
-
|
|
32
|
-
export abstract class BaseService extends BaseHelper implements IService {
|
|
33
|
-
constructor(opts: { scope: string }) {
|
|
34
|
-
super({ scope: opts.scope });
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Key Features
|
|
40
|
-
|
|
41
|
-
| Feature | Description |
|
|
42
|
-
| :--- | :--- |
|
|
43
|
-
| **Standardization** | Common base for all services, fits framework architecture |
|
|
44
|
-
| **Logging** | Extends `BaseHelper` from `@venizia/ignis-helpers` — auto-configured logger at `this.logger` (scope = class name) |
|
|
45
|
-
| **Clarity** | Signals the class contains business logic |
|
|
46
|
-
|
|
47
|
-
### Constructor
|
|
48
|
-
|
|
49
|
-
The constructor requires an options object with a `scope` string, which is typically set to the class name:
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
class UserService extends BaseService {
|
|
53
|
-
constructor() {
|
|
54
|
-
super({ scope: UserService.name });
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## `IService` Interface
|
|
60
|
-
|
|
61
|
-
The `IService` interface is a marker interface with no required methods. It exists to provide a type-level contract for services.
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
export interface IService {}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## No Built-in CRUD Service
|
|
68
|
-
|
|
69
|
-
Ignis intentionally does not provide a `BaseCrudService`. CRUD operations belong in the Repository layer (`DefaultCRUDRepository`). Services are for business logic that orchestrates one or more repositories, performs validation, handles transactions, or coordinates cross-cutting concerns.
|
|
70
|
-
|
|
71
|
-
## Registration
|
|
72
|
-
|
|
73
|
-
Services are registered with the DI container using the `app.service()` method or via the boot system's auto-discovery:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
// Manual registration (in preConfigure or registerComponents)
|
|
77
|
-
app.service(UserService); // Binds as 'services.UserService'
|
|
78
|
-
|
|
79
|
-
// Or via boot system auto-discovery:
|
|
80
|
-
// Place file at src/services/user.service.ts → auto-discovered and bound
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## How Services Fit into the Architecture
|
|
84
|
-
|
|
85
|
-
Services are the core of your application's logic. They act as a bridge between the presentation layer (Controllers) and the data access layer (Repositories).
|
|
86
|
-
|
|
87
|
-
### Typical Service Flow
|
|
88
|
-
|
|
89
|
-
1. **Instantiated by DI Container**: When the application starts, the DI container creates instances of your services.
|
|
90
|
-
2. **Dependencies Injected**: The service's constructor receives instances of any repositories or other services it depends on.
|
|
91
|
-
3. **Called by a Controller**: An HTTP request comes into a controller, which then calls a method on a service to handle the business logic for that request.
|
|
92
|
-
4. **Orchestrates Logic**: The service method executes the business logic. This may involve:
|
|
93
|
-
- Validating input data.
|
|
94
|
-
- Calling one or more repository methods to fetch or save data.
|
|
95
|
-
- Calling other services to perform related tasks.
|
|
96
|
-
- Performing calculations or data transformations.
|
|
97
|
-
5. **Returns Data**: The service returns the result of the operation back to the controller, which then formats it into an HTTP response.
|
|
98
|
-
|
|
99
|
-
### Example
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
import { BaseService, inject, injectable } from '@venizia/ignis';
|
|
103
|
-
import { getError } from '@venizia/ignis-helpers';
|
|
104
|
-
import { UserRepository } from '../repositories/user.repository';
|
|
105
|
-
import { TUser } from '../models/entities';
|
|
106
|
-
|
|
107
|
-
// 1. Service is decorated with @injectable (or registered via app.service())
|
|
108
|
-
@injectable()
|
|
109
|
-
export class UserService extends BaseService {
|
|
110
|
-
// 2. Dependencies (like UserRepository) are injected
|
|
111
|
-
constructor(
|
|
112
|
-
@inject({ key: 'repositories.UserRepository' })
|
|
113
|
-
private _userRepository: UserRepository,
|
|
114
|
-
) {
|
|
115
|
-
super({ scope: UserService.name });
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// 3. Method is called by a controller
|
|
119
|
-
async getUserProfile(opts: { userId: string }): Promise<Partial<TUser>> {
|
|
120
|
-
this.logger.info(`Fetching profile for user ${opts.userId}`);
|
|
121
|
-
|
|
122
|
-
// 4. Orchestrates logic: calls the repository
|
|
123
|
-
const user = await this._userRepository.findById({ id: opts.userId });
|
|
124
|
-
|
|
125
|
-
if (!user) {
|
|
126
|
-
throw getError({ message: 'User not found' });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// 5. Returns transformed data
|
|
130
|
-
return {
|
|
131
|
-
id: user.id,
|
|
132
|
-
name: user.name,
|
|
133
|
-
email: user.email,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Transaction Orchestration
|
|
140
|
-
|
|
141
|
-
A common service pattern is orchestrating transactions across multiple repositories:
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
@injectable()
|
|
145
|
-
export class OrderService extends BaseService {
|
|
146
|
-
constructor(
|
|
147
|
-
@inject({ key: 'repositories.OrderRepository' })
|
|
148
|
-
private orderRepo: OrderRepository,
|
|
149
|
-
|
|
150
|
-
@inject({ key: 'repositories.InventoryRepository' })
|
|
151
|
-
private inventoryRepo: InventoryRepository,
|
|
152
|
-
|
|
153
|
-
@inject({ key: 'datasources.PostgresDataSource' })
|
|
154
|
-
private dataSource: PostgresDataSource,
|
|
155
|
-
) {
|
|
156
|
-
super({ scope: OrderService.name });
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async placeOrder(opts: { userId: string; items: OrderItem[] }) {
|
|
160
|
-
const transaction = await this.dataSource.beginTransaction();
|
|
161
|
-
try {
|
|
162
|
-
const order = await this.orderRepo.create({
|
|
163
|
-
data: { userId: opts.userId, items: opts.items },
|
|
164
|
-
options: { transaction },
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
for (const item of opts.items) {
|
|
168
|
-
await this.inventoryRepo.updateById({
|
|
169
|
-
id: item.productId,
|
|
170
|
-
data: { quantity: item.quantity },
|
|
171
|
-
options: { transaction },
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
await transaction.commit();
|
|
176
|
-
return order;
|
|
177
|
-
} catch (error) {
|
|
178
|
-
await transaction.rollback();
|
|
179
|
-
throw error;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
By adhering to this pattern, you keep your code organized, testable, and maintainable. You can easily test `UserService` by providing a mock `UserRepository` without needing a real database connection.
|
|
186
|
-
|
|
187
|
-
## See Also
|
|
188
|
-
|
|
189
|
-
- **Related References:**
|
|
190
|
-
- [Controllers](./controllers.md) - HTTP request handlers that call services
|
|
191
|
-
- [Repositories](./repositories/) - Data access layer used by services
|
|
192
|
-
- [Providers](./providers.md) - Factory pattern for runtime instantiation
|
|
193
|
-
- [Dependency Injection](./dependency-injection.md) - DI container and injection patterns
|
|
194
|
-
|
|
195
|
-
- **Guides:**
|
|
196
|
-
- [Building Services](/guides/core-concepts/services.md)
|
|
197
|
-
- [Dependency Injection Guide](/guides/core-concepts/dependency-injection.md)
|
|
198
|
-
|
|
199
|
-
- **Best Practices:**
|
|
200
|
-
- [Architectural Patterns](/best-practices/architectural-patterns)
|
|
201
|
-
- [Testing Guide](/guides/tutorials/testing)
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Crypto Utility
|
|
2
|
-
|
|
3
|
-
The Crypto utility provides simple, stateless functions for cryptographic hashing using Node.js's built-in `node:crypto` module.
|
|
4
|
-
|
|
5
|
-
## `hash`
|
|
6
|
-
|
|
7
|
-
The `hash` function allows you to create a hash of a string using either `SHA256` (with a secret for HMAC) or `MD5`.
|
|
8
|
-
|
|
9
|
-
### `hash(text, options)`
|
|
10
|
-
|
|
11
|
-
- `text` (string): The input string to hash.
|
|
12
|
-
- `options` (object):
|
|
13
|
-
- `algorithm` (`'SHA256'` | `'MD5'`): The hashing algorithm to use.
|
|
14
|
-
- `secret` (string, optional): The secret key for HMAC-SHA256. If `algorithm` is `'SHA256'` and no `secret` is provided, the original text is returned unchanged.
|
|
15
|
-
- `outputType` (`BinaryToTextEncoding`): The output encoding (e.g., `'hex'`, `'base64'`).
|
|
16
|
-
|
|
17
|
-
### Behavior
|
|
18
|
-
|
|
19
|
-
- **SHA256**: Creates an HMAC using the provided `secret`. Returns the original text if no secret is given.
|
|
20
|
-
- **MD5**: Creates a standard hash digest (no secret needed).
|
|
21
|
-
- **Other algorithms**: Returns the original text unchanged.
|
|
22
|
-
|
|
23
|
-
### Examples
|
|
24
|
-
|
|
25
|
-
**MD5 Hash**
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
import { hash } from '@venizia/ignis-helpers';
|
|
29
|
-
|
|
30
|
-
const md5Hash = hash('some text', { algorithm: 'MD5', outputType: 'hex' });
|
|
31
|
-
// => '552e21cd4cd99186789c2370c7482837'
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**SHA256 HMAC**
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { hash } from '@venizia/ignis-helpers';
|
|
38
|
-
|
|
39
|
-
const sha256Hash = hash('some text', {
|
|
40
|
-
algorithm: 'SHA256',
|
|
41
|
-
secret: 'a-secret-key',
|
|
42
|
-
outputType: 'hex',
|
|
43
|
-
});
|
|
44
|
-
// => 'b8a1c3f2... (64-character hex string)'
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
**Base64 output**
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { hash } from '@venizia/ignis-helpers';
|
|
51
|
-
|
|
52
|
-
const base64Hash = hash('some text', {
|
|
53
|
-
algorithm: 'MD5',
|
|
54
|
-
outputType: 'base64',
|
|
55
|
-
});
|
|
56
|
-
```
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Module Utility
|
|
2
|
-
|
|
3
|
-
The Module utility provides a function to validate the existence of Node.js modules at runtime. It uses `createRequire` from `node:module` rooted at the application's `process.cwd()/node_modules`, so peer dependencies in the consuming application are properly resolved even though this utility lives inside `packages/helpers`.
|
|
4
|
-
|
|
5
|
-
## `validateModule`
|
|
6
|
-
|
|
7
|
-
The `validateModule` function checks if a list of modules can be resolved. If a module is not found, it logs the error and throws a descriptive error, prompting the developer to install it. This is particularly useful for features that have optional peer dependencies.
|
|
8
|
-
|
|
9
|
-
### `validateModule(opts)`
|
|
10
|
-
|
|
11
|
-
- `opts` (object):
|
|
12
|
-
- `scope` (string, optional): A string to identify the feature or component that requires the module, making the error message more informative. Defaults to empty string.
|
|
13
|
-
- `modules` (Array<string>): An array of module names to validate. Defaults to empty array.
|
|
14
|
-
|
|
15
|
-
This is an `async` function, though it performs synchronous resolution internally.
|
|
16
|
-
|
|
17
|
-
### Example
|
|
18
|
-
|
|
19
|
-
The `SwaggerComponent` uses `validateModule` to ensure that `@hono/swagger-ui` is installed before attempting to use it.
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
import { validateModule } from '@venizia/ignis-helpers';
|
|
23
|
-
|
|
24
|
-
export class SwaggerComponent extends BaseComponent {
|
|
25
|
-
// ...
|
|
26
|
-
|
|
27
|
-
override async binding() {
|
|
28
|
-
// This will throw an error if '@hono/swagger-ui' is not installed
|
|
29
|
-
await validateModule({ scope: SwaggerComponent.name, modules: ['@hono/swagger-ui'] });
|
|
30
|
-
|
|
31
|
-
const { swaggerUI } = await import('@hono/swagger-ui');
|
|
32
|
-
|
|
33
|
-
// ... rest of the setup
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
If the module is missing, the application will fail with an error message like:
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
[validateModule] @hono/swagger-ui is required for SwaggerComponent. Please install '@hono/swagger-ui'
|
|
42
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|