@venizia/ignis-docs 0.0.1-4 → 0.0.1-6
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 +58 -21
- package/mcp-server/dist/common/config.d.ts.map +1 -1
- package/mcp-server/dist/common/config.js +67 -12
- package/mcp-server/dist/common/config.js.map +1 -1
- package/mcp-server/dist/helpers/docs.helper.d.ts +5 -5
- package/mcp-server/dist/helpers/docs.helper.d.ts.map +1 -1
- package/mcp-server/dist/helpers/docs.helper.js +31 -27
- package/mcp-server/dist/helpers/docs.helper.js.map +1 -1
- package/mcp-server/dist/helpers/github.helper.d.ts +37 -0
- package/mcp-server/dist/helpers/github.helper.d.ts.map +1 -0
- package/mcp-server/dist/helpers/github.helper.js +100 -0
- package/mcp-server/dist/helpers/github.helper.js.map +1 -0
- package/mcp-server/dist/helpers/index.d.ts +1 -0
- package/mcp-server/dist/helpers/index.d.ts.map +1 -1
- package/mcp-server/dist/helpers/index.js +1 -0
- package/mcp-server/dist/helpers/index.js.map +1 -1
- package/mcp-server/dist/index.js +60 -32
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/tools/base.tool.d.ts +6 -10
- package/mcp-server/dist/tools/base.tool.d.ts.map +1 -1
- package/mcp-server/dist/tools/base.tool.js +3 -5
- package/mcp-server/dist/tools/base.tool.js.map +1 -1
- package/mcp-server/dist/tools/{get-doc-content.tool.d.ts → docs/get-document-content.tool.d.ts} +4 -4
- package/mcp-server/dist/tools/docs/get-document-content.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/{get-doc-content.tool.js → docs/get-document-content.tool.js} +12 -11
- package/mcp-server/dist/tools/docs/get-document-content.tool.js.map +1 -0
- package/mcp-server/dist/tools/{get-doc-metadata.tool.d.ts → docs/get-document-metadata.tool.d.ts} +4 -4
- package/mcp-server/dist/tools/docs/get-document-metadata.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/{get-doc-metadata.tool.js → docs/get-document-metadata.tool.js} +11 -10
- package/mcp-server/dist/tools/docs/get-document-metadata.tool.js.map +1 -0
- package/mcp-server/dist/tools/docs/get-package-overview.tool.d.ts +50 -0
- package/mcp-server/dist/tools/docs/get-package-overview.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/docs/get-package-overview.tool.js +221 -0
- package/mcp-server/dist/tools/docs/get-package-overview.tool.js.map +1 -0
- package/mcp-server/dist/tools/docs/index.d.ts +7 -0
- package/mcp-server/dist/tools/docs/index.d.ts.map +1 -0
- package/mcp-server/dist/tools/docs/index.js +23 -0
- package/mcp-server/dist/tools/docs/index.js.map +1 -0
- package/mcp-server/dist/tools/{list-categories.tool.d.ts → docs/list-categories.tool.d.ts} +2 -2
- package/mcp-server/dist/tools/docs/list-categories.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/{list-categories.tool.js → docs/list-categories.tool.js} +7 -6
- package/mcp-server/dist/tools/docs/list-categories.tool.js.map +1 -0
- package/mcp-server/dist/tools/{list-docs.tool.d.ts → docs/list-documents.tool.d.ts} +4 -4
- package/mcp-server/dist/tools/docs/list-documents.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/{list-docs.tool.js → docs/list-documents.tool.js} +10 -9
- package/mcp-server/dist/tools/docs/list-documents.tool.js.map +1 -0
- package/mcp-server/dist/tools/{search-docs.tool.d.ts → docs/search-documents.tool.d.ts} +4 -4
- package/mcp-server/dist/tools/docs/search-documents.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/{search-docs.tool.js → docs/search-documents.tool.js} +19 -18
- package/mcp-server/dist/tools/docs/search-documents.tool.js.map +1 -0
- package/mcp-server/dist/tools/github/index.d.ts +5 -0
- package/mcp-server/dist/tools/github/index.d.ts.map +1 -0
- package/mcp-server/dist/tools/github/index.js +21 -0
- package/mcp-server/dist/tools/github/index.js.map +1 -0
- package/mcp-server/dist/tools/github/list-project-files.tool.d.ts +28 -0
- package/mcp-server/dist/tools/github/list-project-files.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/github/list-project-files.tool.js +98 -0
- package/mcp-server/dist/tools/github/list-project-files.tool.js.map +1 -0
- package/mcp-server/dist/tools/github/search-code.tool.d.ts +42 -0
- package/mcp-server/dist/tools/github/search-code.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/github/search-code.tool.js +194 -0
- package/mcp-server/dist/tools/github/search-code.tool.js.map +1 -0
- package/mcp-server/dist/tools/github/verify-dependencies.tool.d.ts +55 -0
- package/mcp-server/dist/tools/github/verify-dependencies.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/github/verify-dependencies.tool.js +167 -0
- package/mcp-server/dist/tools/github/verify-dependencies.tool.js.map +1 -0
- package/mcp-server/dist/tools/github/view-source-file.tool.d.ts +26 -0
- package/mcp-server/dist/tools/github/view-source-file.tool.d.ts.map +1 -0
- package/mcp-server/dist/tools/github/view-source-file.tool.js +91 -0
- package/mcp-server/dist/tools/github/view-source-file.tool.js.map +1 -0
- package/mcp-server/dist/tools/index.d.ts +3 -7
- package/mcp-server/dist/tools/index.d.ts.map +1 -1
- package/mcp-server/dist/tools/index.js +17 -13
- package/mcp-server/dist/tools/index.js.map +1 -1
- package/package.json +25 -6
- package/wiki/get-started/best-practices/api-usage-examples.md +42 -0
- package/wiki/get-started/best-practices/architectural-patterns.md +42 -1
- package/wiki/get-started/best-practices/code-style-standards.md +41 -0
- package/wiki/get-started/best-practices/contribution-workflow.md +40 -6
- package/wiki/get-started/best-practices/data-modeling.md +126 -0
- package/wiki/get-started/core-concepts/dependency-injection.md +13 -1
- package/wiki/get-started/mcp-docs-server.md +130 -32
- package/wiki/get-started/philosophy.md +198 -25
- package/wiki/public/logo.svg +1 -0
- package/wiki/references/base/application.md +5 -5
- package/wiki/references/base/controllers.md +3 -1
- package/wiki/references/base/dependency-injection.md +6 -5
- package/wiki/references/base/models.md +319 -1
- package/wiki/references/components/index.md +3 -1
- package/wiki/references/components/static-asset.md +1289 -0
- package/wiki/references/helpers/inversion.md +21 -11
- package/wiki/references/helpers/storage.md +538 -11
- package/wiki/references/src-details/core.md +15 -1
- package/wiki/references/src-details/docs.md +19 -9
- package/wiki/references/src-details/mcp-server.md +185 -234
- package/wiki/references/utilities/index.md +1 -1
- package/wiki/references/utilities/request.md +150 -0
- package/mcp-server/dist/tools/get-doc-content.tool.d.ts.map +0 -1
- package/mcp-server/dist/tools/get-doc-content.tool.js.map +0 -1
- package/mcp-server/dist/tools/get-doc-metadata.tool.d.ts.map +0 -1
- package/mcp-server/dist/tools/get-doc-metadata.tool.js.map +0 -1
- package/mcp-server/dist/tools/list-categories.tool.d.ts.map +0 -1
- package/mcp-server/dist/tools/list-categories.tool.js.map +0 -1
- package/mcp-server/dist/tools/list-docs.tool.d.ts.map +0 -1
- package/mcp-server/dist/tools/list-docs.tool.js.map +0 -1
- package/mcp-server/dist/tools/search-docs.tool.d.ts.map +0 -1
- package/mcp-server/dist/tools/search-docs.tool.js.map +0 -1
|
@@ -15,14 +15,24 @@ Core DI system enabling loosely coupled, testable, and extensible code.
|
|
|
15
15
|
|
|
16
16
|
### Binding Methods
|
|
17
17
|
|
|
18
|
-
| Method | Purpose |
|
|
19
|
-
|
|
20
|
-
| `app.service(MyService)` | Bind service |
|
|
21
|
-
| `app.controller(MyController)` | Bind controller |
|
|
22
|
-
| `app.repository(MyRepo)` | Bind repository |
|
|
18
|
+
| Method | Purpose | Default Key |
|
|
19
|
+
|--------|---------|-------------|
|
|
20
|
+
| `app.service(MyService, opts?)` | Bind service | `services.MyService` |
|
|
21
|
+
| `app.controller(MyController, opts?)` | Bind controller | `controllers.MyController` |
|
|
22
|
+
| `app.repository(MyRepo, opts?)` | Bind repository | `repositories.MyRepo` |
|
|
23
|
+
| `app.component(MyComponent, opts?)` | Bind component | `components.MyComponent` |
|
|
24
|
+
| `app.dataSource(MyDS, opts?)` | Bind datasource | `datasources.MyDS` |
|
|
23
25
|
| `bind().toClass()` | Custom class binding | `bind({ key: 'MyClass' }).toClass(MyClass)` |
|
|
24
26
|
| `bind().toValue()` | Bind constant value | `bind({ key: 'API_KEY' }).toValue('secret')` |
|
|
25
27
|
|
|
28
|
+
All registration methods accept an optional `opts` parameter to customize the binding key:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
app.controller(UserController, {
|
|
32
|
+
binding: { namespace: 'controllers', key: 'CustomUserController' }
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
26
36
|
### Binding Scopes
|
|
27
37
|
|
|
28
38
|
| Scope | Behavior |
|
|
@@ -41,13 +51,13 @@ Core DI system enabling loosely coupled, testable, and extensible code.
|
|
|
41
51
|
|
|
42
52
|
Before a dependency can be injected, it must be bound to the container. The `Application` class provides helper methods for binding common resource types:
|
|
43
53
|
|
|
44
|
-
- `app.component(MyComponent)`
|
|
45
|
-
- `app.controller(MyController)`
|
|
46
|
-
- `app.service(MyService)`
|
|
47
|
-
- `app.repository(MyRepository)`
|
|
48
|
-
- `app.dataSource(MyDataSource)`
|
|
54
|
+
- `app.component(MyComponent, opts?)`
|
|
55
|
+
- `app.controller(MyController, opts?)`
|
|
56
|
+
- `app.service(MyService, opts?)`
|
|
57
|
+
- `app.repository(MyRepository, opts?)`
|
|
58
|
+
- `app.dataSource(MyDataSource, opts?)`
|
|
49
59
|
|
|
50
|
-
These methods automatically create a binding for the class with a conventional key (e.g., `services.MyService`).
|
|
60
|
+
These methods automatically create a binding for the class with a conventional key (e.g., `services.MyService`). Use the optional `opts` parameter to customize binding keys when needed.
|
|
51
61
|
|
|
52
62
|
### Advanced Binding
|
|
53
63
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# Storage Helpers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Storage solutions for in-memory, local filesystem, and cloud object storage with a unified interface.
|
|
4
4
|
|
|
5
5
|
## Quick Reference
|
|
6
6
|
|
|
7
|
-
| Helper | Type | Use Case |
|
|
8
|
-
|
|
9
|
-
| **MemoryStorageHelper** | In-memory key-value | Caching, temporary state, single-process data |
|
|
10
|
-
| **
|
|
7
|
+
| Helper | Type | Implements | Use Case |
|
|
8
|
+
|--------|------|------------|----------|
|
|
9
|
+
| **MemoryStorageHelper** | In-memory key-value | - | Caching, temporary state, single-process data |
|
|
10
|
+
| **DiskHelper** | Local filesystem | `IStorageHelper` | Local file storage, development, small-scale apps |
|
|
11
|
+
| **MinioHelper** | S3-compatible storage | `IStorageHelper` | Cloud storage, production, scalable file management |
|
|
11
12
|
|
|
12
13
|
### MemoryStorageHelper Methods
|
|
13
14
|
|
|
@@ -19,14 +20,79 @@ In-memory and external object storage solutions.
|
|
|
19
20
|
| `keys()` | Get all keys |
|
|
20
21
|
| `clear()` | Clear all data |
|
|
21
22
|
|
|
22
|
-
###
|
|
23
|
+
### IStorageHelper Operations
|
|
24
|
+
|
|
25
|
+
All storage helpers implementing `IStorageHelper` provide these operations:
|
|
23
26
|
|
|
24
27
|
| Operation | Methods |
|
|
25
28
|
|-----------|---------|
|
|
26
|
-
| **
|
|
27
|
-
| **
|
|
28
|
-
| **
|
|
29
|
+
| **Validation** | `isValidName()` |
|
|
30
|
+
| **Bucket** | `isBucketExists()`, `getBuckets()`, `getBucket()`, `createBucket()`, `removeBucket()` |
|
|
31
|
+
| **Upload** | `upload({ bucket, files, normalizeNameFn, normalizeLinkFn })` |
|
|
32
|
+
| **Download** | `getFile({ bucket, name })`, `getStat({ bucket, name })` |
|
|
29
33
|
| **Delete** | `removeObject()`, `removeObjects()` |
|
|
34
|
+
| **List** | `listObjects({ bucket, prefix, useRecursive, maxKeys })` |
|
|
35
|
+
| **Utility** | `getFileType({ mimeType })` |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Storage Architecture
|
|
40
|
+
|
|
41
|
+
### IStorageHelper Interface
|
|
42
|
+
|
|
43
|
+
The unified storage interface implemented by all file storage helpers:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
interface IStorageHelper {
|
|
47
|
+
// Name validation
|
|
48
|
+
isValidName(name: string): boolean;
|
|
49
|
+
|
|
50
|
+
// Bucket operations
|
|
51
|
+
isBucketExists(opts: { name: string }): Promise<boolean>;
|
|
52
|
+
getBuckets(): Promise<IBucketInfo[]>;
|
|
53
|
+
getBucket(opts: { name: string }): Promise<IBucketInfo | null>;
|
|
54
|
+
createBucket(opts: { name: string }): Promise<IBucketInfo | null>;
|
|
55
|
+
removeBucket(opts: { name: string }): Promise<boolean>;
|
|
56
|
+
|
|
57
|
+
// File operations
|
|
58
|
+
upload(opts: {
|
|
59
|
+
bucket: string;
|
|
60
|
+
files: IUploadFile[];
|
|
61
|
+
normalizeNameFn?: (opts: { originalName: string; folderPath?: string }) => string;
|
|
62
|
+
normalizeLinkFn?: (opts: { bucketName: string; normalizeName: string }) => string;
|
|
63
|
+
}): Promise<IUploadResult[]>;
|
|
64
|
+
|
|
65
|
+
getFile(opts: { bucket: string; name: string; options?: any }): Promise<Readable>;
|
|
66
|
+
getStat(opts: { bucket: string; name: string }): Promise<IFileStat>;
|
|
67
|
+
removeObject(opts: { bucket: string; name: string }): Promise<void>;
|
|
68
|
+
removeObjects(opts: { bucket: string; names: string[] }): Promise<void>;
|
|
69
|
+
listObjects(opts: IListObjectsOptions): Promise<IObjectInfo[]>;
|
|
70
|
+
|
|
71
|
+
// Utility
|
|
72
|
+
getFileType(opts: { mimeType: string }): string;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### BaseStorageHelper
|
|
77
|
+
|
|
78
|
+
Abstract base class providing common functionality:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
abstract class BaseStorageHelper implements IStorageHelper {
|
|
82
|
+
// Built-in security validation
|
|
83
|
+
isValidName(name: string): boolean;
|
|
84
|
+
|
|
85
|
+
// MIME type detection
|
|
86
|
+
getFileType(opts: { mimeType: string }): string;
|
|
87
|
+
|
|
88
|
+
// Abstract methods that implementations must provide
|
|
89
|
+
abstract isBucketExists(opts: { name: string }): Promise<boolean>;
|
|
90
|
+
abstract upload(opts: { /* ... */ }): Promise<IUploadResult[]>;
|
|
91
|
+
// ... other abstract methods
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
30
96
|
|
|
31
97
|
## `MemoryStorageHelper`
|
|
32
98
|
|
|
@@ -62,9 +128,228 @@ const allKeys = memoryStore.keys();
|
|
|
62
128
|
memoryStore.clear();
|
|
63
129
|
```
|
|
64
130
|
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## `DiskHelper`
|
|
134
|
+
|
|
135
|
+
The `DiskHelper` provides local filesystem storage using a bucket-based directory structure. It implements the `IStorageHelper` interface, making it easy to switch between local and cloud storage.
|
|
136
|
+
|
|
137
|
+
### Creating an Instance
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { DiskHelper } from '@venizia/ignis-helpers';
|
|
141
|
+
|
|
142
|
+
const diskHelper = new DiskHelper({
|
|
143
|
+
basePath: './app_data/storage', // Base directory for storage
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Options:**
|
|
148
|
+
- `basePath` (string, required): Base directory where buckets will be created
|
|
149
|
+
- `scope` (string, optional): Logger scope name
|
|
150
|
+
- `identifier` (string, optional): Helper identifier
|
|
151
|
+
|
|
152
|
+
**Directory Structure:**
|
|
153
|
+
```
|
|
154
|
+
app_data/storage/ ← basePath
|
|
155
|
+
├── bucket-1/ ← bucket (directory)
|
|
156
|
+
│ ├── file1.pdf ← object (file)
|
|
157
|
+
│ └── file2.jpg
|
|
158
|
+
├── bucket-2/
|
|
159
|
+
│ └── document.docx
|
|
160
|
+
└── user-uploads/
|
|
161
|
+
├── avatar.png
|
|
162
|
+
└── resume.pdf
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Key Features
|
|
166
|
+
|
|
167
|
+
✅ **Automatic Directory Creation** - Creates directories as needed
|
|
168
|
+
✅ **Built-in Security** - Path traversal protection, name validation
|
|
169
|
+
✅ **Stream-Based** - Efficient for large files
|
|
170
|
+
✅ **Metadata Support** - Uses filesystem stats
|
|
171
|
+
✅ **Compatible Interface** - Same API as MinioHelper
|
|
172
|
+
|
|
173
|
+
### Bucket Operations
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// Check if bucket exists
|
|
177
|
+
const exists = await diskHelper.isBucketExists({ name: 'my-bucket' });
|
|
178
|
+
|
|
179
|
+
// Create a bucket (creates directory)
|
|
180
|
+
const bucket = await diskHelper.createBucket({ name: 'my-bucket' });
|
|
181
|
+
// Returns: { name: 'my-bucket', creationDate: Date }
|
|
182
|
+
|
|
183
|
+
// Get all buckets
|
|
184
|
+
const buckets = await diskHelper.getBuckets();
|
|
185
|
+
// Returns: [{ name: 'bucket-1', creationDate: Date }, ...]
|
|
186
|
+
|
|
187
|
+
// Get specific bucket
|
|
188
|
+
const bucket = await diskHelper.getBucket({ name: 'my-bucket' });
|
|
189
|
+
// Returns: { name: 'my-bucket', creationDate: Date } | null
|
|
190
|
+
|
|
191
|
+
// Remove bucket (removes directory, must be empty)
|
|
192
|
+
const removed = await diskHelper.removeBucket({ name: 'my-bucket' });
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### File Operations
|
|
196
|
+
|
|
197
|
+
#### Upload Files
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// Basic upload
|
|
201
|
+
const result = await diskHelper.upload({
|
|
202
|
+
bucket: 'my-bucket',
|
|
203
|
+
files: [
|
|
204
|
+
{
|
|
205
|
+
originalname: 'document.pdf',
|
|
206
|
+
mimetype: 'application/pdf',
|
|
207
|
+
buffer: fileBuffer,
|
|
208
|
+
size: fileBuffer.length,
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
});
|
|
212
|
+
// Returns: [{ bucketName: 'my-bucket', objectName: 'document.pdf', link: '...' }]
|
|
213
|
+
|
|
214
|
+
// Upload with custom normalization
|
|
215
|
+
const result = await diskHelper.upload({
|
|
216
|
+
bucket: 'my-bucket',
|
|
217
|
+
files: files,
|
|
218
|
+
normalizeNameFn: ({` originalName, folderPath `}) => {
|
|
219
|
+
return folderPath ? `${folderPath}/${name}` : name;
|
|
220
|
+
},
|
|
221
|
+
normalizeLinkFn: ({ bucketName, normalizeName }) => {
|
|
222
|
+
return `/files/${bucketName}/${normalizeName}`;
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### Get File (Stream)
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
const fileStream = await diskHelper.getFile({
|
|
231
|
+
bucket: 'my-bucket',
|
|
232
|
+
name: 'document.pdf',
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Pipe to response
|
|
236
|
+
fileStream.pipe(response);
|
|
237
|
+
|
|
238
|
+
// Or save to another location
|
|
239
|
+
import fs from 'fs';
|
|
240
|
+
const writeStream = fs.createWriteStream('./backup/document.pdf');
|
|
241
|
+
fileStream.pipe(writeStream);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Get File Metadata
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
const stat = await diskHelper.getStat({
|
|
248
|
+
bucket: 'my-bucket',
|
|
249
|
+
name: 'document.pdf',
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
console.log(stat);
|
|
253
|
+
// {
|
|
254
|
+
// size: 1024,
|
|
255
|
+
// metadata: { /* filesystem stats */ },
|
|
256
|
+
// lastModified: Date,
|
|
257
|
+
// etag: 'hash',
|
|
258
|
+
// }
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
#### List Objects
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// List all objects in bucket
|
|
265
|
+
const objects = await diskHelper.listObjects({
|
|
266
|
+
bucket: 'my-bucket',
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// List with prefix (folder-like behavior)
|
|
270
|
+
const objects = await diskHelper.listObjects({
|
|
271
|
+
bucket: 'my-bucket',
|
|
272
|
+
prefix: 'documents/',
|
|
273
|
+
useRecursive: false, // Non-recursive by default
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Limit results
|
|
277
|
+
const objects = await diskHelper.listObjects({
|
|
278
|
+
bucket: 'my-bucket',
|
|
279
|
+
maxKeys: 100,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
console.log(objects);
|
|
283
|
+
// [
|
|
284
|
+
// { name: 'file1.pdf', size: 1024, lastModified: Date },
|
|
285
|
+
// { name: 'file2.jpg', size: 2048, lastModified: Date },
|
|
286
|
+
// ]
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
#### Delete Objects
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// Delete single object
|
|
293
|
+
await diskHelper.removeObject({
|
|
294
|
+
bucket: 'my-bucket',
|
|
295
|
+
name: 'old-file.pdf',
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// Delete multiple objects
|
|
299
|
+
await diskHelper.removeObjects({
|
|
300
|
+
bucket: 'my-bucket',
|
|
301
|
+
names: ['file1.pdf', 'file2.jpg', 'file3.png'],
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Security & Validation
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Name validation (inherited from BaseStorageHelper)
|
|
309
|
+
const isValid = diskHelper.isValidName('my-file.pdf'); // true
|
|
310
|
+
const isValid = diskHelper.isValidName('../etc/passwd'); // false ❌ path traversal
|
|
311
|
+
const isValid = diskHelper.isValidName('.hidden'); // false ❌ hidden file
|
|
312
|
+
const isValid = diskHelper.isValidName('file;rm -rf'); // false ❌ shell injection
|
|
313
|
+
|
|
314
|
+
// All operations validate names before execution
|
|
315
|
+
try {
|
|
316
|
+
await diskHelper.createBucket({ name: '../../../etc' });
|
|
317
|
+
} catch (error) {
|
|
318
|
+
// Error: Invalid bucket name
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Use Cases
|
|
323
|
+
|
|
324
|
+
**Development & Testing:**
|
|
325
|
+
```typescript
|
|
326
|
+
const devStorage = new DiskHelper({ basePath: './dev-storage' });
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Small-Scale Production:**
|
|
330
|
+
```typescript
|
|
331
|
+
const prodStorage = new DiskHelper({ basePath: '/var/app/storage' });
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Temporary Files:**
|
|
335
|
+
```typescript
|
|
336
|
+
const tempStorage = new DiskHelper({ basePath: './temp' });
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Hybrid Setup:**
|
|
340
|
+
```typescript
|
|
341
|
+
// User uploads → Cloud (MinIO)
|
|
342
|
+
const cloudStorage = new MinioHelper({ /* ... */ });
|
|
343
|
+
|
|
344
|
+
// System files → Local (Disk)
|
|
345
|
+
const localStorage = new DiskHelper({ basePath: './system-files' });
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
65
350
|
## `MinioHelper`
|
|
66
351
|
|
|
67
|
-
The `MinioHelper` is a comprehensive client for interacting with MinIO or any S3-compatible object storage service.
|
|
352
|
+
The `MinioHelper` is a comprehensive client for interacting with MinIO or any S3-compatible object storage service. It implements the `IStorageHelper` interface for unified storage operations.
|
|
68
353
|
|
|
69
354
|
### Creating a MinIO Client
|
|
70
355
|
|
|
@@ -98,14 +383,43 @@ if (!bucketExists) {
|
|
|
98
383
|
The `upload` method takes an array of file objects, typically from a multipart form data request.
|
|
99
384
|
|
|
100
385
|
```typescript
|
|
101
|
-
//
|
|
386
|
+
// Basic upload
|
|
102
387
|
const uploadResult = await minioClient.upload({
|
|
103
388
|
bucket: 'my-bucket',
|
|
104
389
|
files: files,
|
|
105
390
|
});
|
|
106
391
|
// => [{ bucket: 'my-bucket', fileName: '...', link: '...' }]
|
|
392
|
+
|
|
393
|
+
// Upload with custom filename normalization
|
|
394
|
+
const uploadResult = await minioClient.upload({
|
|
395
|
+
bucket: 'my-bucket',
|
|
396
|
+
files: files,
|
|
397
|
+
normalizeLinkFn: ({ bucketName, normalizeName }) => {
|
|
398
|
+
// Custom link generation
|
|
399
|
+
return `/api/files/${bucketName}/${encodeURIComponent(normalizeName)}`;
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Options:**
|
|
405
|
+
- `bucket` (string): Target bucket name
|
|
406
|
+
- `files` (`Array<IUploadFile>`): Array of file objects to upload
|
|
407
|
+
- `normalizeNameFn` (optional): Custom function to normalize filenames (default: lowercase + replace spaces with underscores)
|
|
408
|
+
- `normalizeLinkFn` (optional): Custom function to generate file access links (default: `/static-assets/{bucket}/{encodedName}`)
|
|
409
|
+
|
|
410
|
+
**IUploadFile Interface:**
|
|
411
|
+
```typescript
|
|
412
|
+
interface IUploadFile {
|
|
413
|
+
originalname: string;
|
|
414
|
+
mimetype: string;
|
|
415
|
+
buffer: Buffer;
|
|
416
|
+
size: number;
|
|
417
|
+
encoding?: string; // Optional encoding information
|
|
418
|
+
}
|
|
107
419
|
```
|
|
108
420
|
|
|
421
|
+
**Note:** MinioHelper now implements the same `IStorageHelper` interface as `DiskHelper`, making them interchangeable. See the DiskHelper section for detailed API documentation, which applies to both helpers.
|
|
422
|
+
|
|
109
423
|
#### Getting an Object
|
|
110
424
|
|
|
111
425
|
The `getFile` method returns a `Readable` stream for an object.
|
|
@@ -128,3 +442,216 @@ await minioClient.removeObject({ bucket: 'my-bucket', name: 'my-file.txt' });
|
|
|
128
442
|
// Remove multiple objects
|
|
129
443
|
await minioClient.removeObjects({ bucket: 'my-bucket', names: ['file1.txt', 'file2.txt'] });
|
|
130
444
|
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## DiskHelper vs MinioHelper Comparison
|
|
449
|
+
|
|
450
|
+
Both helpers implement the same `IStorageHelper` interface, making them functionally equivalent from an API perspective.
|
|
451
|
+
|
|
452
|
+
### Feature Comparison
|
|
453
|
+
|
|
454
|
+
| Feature | DiskHelper | MinioHelper |
|
|
455
|
+
|---------|------------|-------------|
|
|
456
|
+
| **Storage Type** | Local filesystem | S3-compatible cloud |
|
|
457
|
+
| **Interface** | `IStorageHelper` | `IStorageHelper` |
|
|
458
|
+
| **Scalability** | Limited to single server | Horizontally scalable |
|
|
459
|
+
| **Setup Complexity** | Simple (just a directory) | Requires MinIO server |
|
|
460
|
+
| **Performance** | Fast (local disk I/O) | Network-dependent |
|
|
461
|
+
| **Backup** | Manual filesystem backup | Built-in replication |
|
|
462
|
+
| **Cost** | Disk space only | Server + storage costs |
|
|
463
|
+
| **Use Case** | Development, small apps | Production, large scale |
|
|
464
|
+
|
|
465
|
+
### When to Use Each
|
|
466
|
+
|
|
467
|
+
**Use DiskHelper when:**
|
|
468
|
+
- Developing/testing locally
|
|
469
|
+
- Running on a single server
|
|
470
|
+
- Storage needs are < 100GB
|
|
471
|
+
- Simplicity is priority
|
|
472
|
+
- No cloud infrastructure
|
|
473
|
+
|
|
474
|
+
**Use MinioHelper when:**
|
|
475
|
+
- Deploying to production
|
|
476
|
+
- Need horizontal scaling
|
|
477
|
+
- Storage needs > 100GB
|
|
478
|
+
- Need backup/replication
|
|
479
|
+
- Multi-server deployment
|
|
480
|
+
|
|
481
|
+
### Hybrid Approach
|
|
482
|
+
|
|
483
|
+
Use both simultaneously for different purposes:
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
import { DiskHelper, MinioHelper } from '@venizia/ignis-helpers';
|
|
487
|
+
|
|
488
|
+
// Cloud storage for user content
|
|
489
|
+
const userStorage = new MinioHelper({ /* ... */ });
|
|
490
|
+
|
|
491
|
+
// Local storage for system files
|
|
492
|
+
const systemStorage = new DiskHelper({ basePath: './system' });
|
|
493
|
+
|
|
494
|
+
// Local storage for temporary files
|
|
495
|
+
const tempStorage = new DiskHelper({ basePath: './temp' });
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Common Patterns
|
|
501
|
+
|
|
502
|
+
### Pattern 1: Storage Abstraction
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
class FileService {
|
|
506
|
+
constructor(private storage: IStorageHelper) {}
|
|
507
|
+
|
|
508
|
+
async uploadFile(bucket: string, file: IUploadFile) {
|
|
509
|
+
return await this.storage.upload({ bucket, files: [file] });
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async getFile(bucket: string, name: string) {
|
|
513
|
+
return await this.storage.getFile({ bucket, name });
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Use with either storage type
|
|
518
|
+
const service1 = new FileService(new DiskHelper({ basePath: './files' }));
|
|
519
|
+
const service2 = new FileService(new MinioHelper({ /* ... */ }));
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Pattern 2: Environment-Based Selection
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
import { applicationEnvironment } from '@venizia/ignis';
|
|
526
|
+
|
|
527
|
+
const createStorageHelper = (): IStorageHelper => {
|
|
528
|
+
const storageType = applicationEnvironment.get('STORAGE_TYPE');
|
|
529
|
+
|
|
530
|
+
if (storageType === 'minio') {
|
|
531
|
+
return new MinioHelper({
|
|
532
|
+
endPoint: applicationEnvironment.get('MINIO_HOST'),
|
|
533
|
+
port: Number(applicationEnvironment.get('MINIO_PORT')),
|
|
534
|
+
accessKey: applicationEnvironment.get('MINIO_ACCESS_KEY'),
|
|
535
|
+
secretKey: applicationEnvironment.get('MINIO_SECRET_KEY'),
|
|
536
|
+
useSSL: applicationEnvironment.get('MINIO_USE_SSL') === 'true',
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return new DiskHelper({
|
|
541
|
+
basePath: applicationEnvironment.get('DISK_STORAGE_PATH') || './storage',
|
|
542
|
+
});
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
const storage = createStorageHelper();
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Pattern 3: Fallback Strategy
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
class ResilientStorage implements IStorageHelper {
|
|
552
|
+
constructor(
|
|
553
|
+
private primary: IStorageHelper,
|
|
554
|
+
private fallback: IStorageHelper,
|
|
555
|
+
) {}
|
|
556
|
+
|
|
557
|
+
async upload(opts: any) {
|
|
558
|
+
try {
|
|
559
|
+
return await this.primary.upload(opts);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
console.error('Primary storage failed, using fallback', error);
|
|
562
|
+
return await this.fallback.upload(opts);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Implement other methods with similar fallback logic...
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Usage
|
|
570
|
+
const storage = new ResilientStorage(
|
|
571
|
+
new MinioHelper({ /* ... */ }), // Primary: Cloud
|
|
572
|
+
new DiskHelper({ basePath: './backup' }), // Fallback: Local
|
|
573
|
+
);
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Related Documentation
|
|
579
|
+
|
|
580
|
+
- [Static Asset Component](../components/static-asset.md) - Uses storage helpers
|
|
581
|
+
- [Request Utilities](../utilities/request.md) - `parseMultipartBody`
|
|
582
|
+
- [Base Helpers](./index.md) - Helper architecture
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## TypeScript Interfaces Reference
|
|
587
|
+
|
|
588
|
+
### IUploadFile
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
interface IUploadFile {
|
|
592
|
+
originalName: string; // Original filename (renamed from 'originalname')
|
|
593
|
+
mimetype: string; // MIME type (e.g., 'image/png')
|
|
594
|
+
buffer: Buffer; // File content
|
|
595
|
+
size: number; // File size in bytes
|
|
596
|
+
encoding?: string; // Optional encoding (e.g., '7bit', 'base64')
|
|
597
|
+
folderPath?: string; // Optional folder path for organization
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
**Note:** The property was renamed from `originalname` to `originalName` for consistency.
|
|
602
|
+
|
|
603
|
+
### IUploadResult
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
interface IUploadResult {
|
|
607
|
+
bucketName: string; // Bucket where file was stored
|
|
608
|
+
objectName: string; // Stored filename
|
|
609
|
+
link: string; // Access URL
|
|
610
|
+
metaLink?: any; // MetaLink database record (if enabled)
|
|
611
|
+
metaLinkError?: any; // Error message if MetaLink creation failed
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### IFileStat
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
interface IFileStat {
|
|
619
|
+
size: number; // File size in bytes
|
|
620
|
+
metadata: Record<string, any>; // Storage-specific metadata
|
|
621
|
+
lastModified?: Date; // Last modification date
|
|
622
|
+
etag?: string; // Entity tag
|
|
623
|
+
versionId?: string; // Version ID (if versioning enabled)
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### IBucketInfo
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
interface IBucketInfo {
|
|
631
|
+
name: string; // Bucket name
|
|
632
|
+
creationDate: Date; // When bucket was created
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### IObjectInfo
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
interface IObjectInfo {
|
|
640
|
+
name?: string; // Object name
|
|
641
|
+
size?: number; // Object size in bytes
|
|
642
|
+
lastModified?: Date; // Last modification date
|
|
643
|
+
etag?: string; // Entity tag
|
|
644
|
+
prefix?: string; // Prefix (for directory-like listing)
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### IListObjectsOptions
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
interface IListObjectsOptions {
|
|
652
|
+
bucket: string; // Bucket to list
|
|
653
|
+
prefix?: string; // Filter by prefix
|
|
654
|
+
useRecursive?: boolean; // Recursive listing
|
|
655
|
+
maxKeys?: number; // Maximum objects to return
|
|
656
|
+
}
|
|
657
|
+
```
|
|
@@ -117,7 +117,21 @@ Contains mixins to extend the functionality of core classes, particularly `Abstr
|
|
|
117
117
|
| `controller.mixin.ts` | Adds `controller()` and `registerControllers()` methods. |
|
|
118
118
|
| `repository.mixin.ts` | Adds `dataSource()` and `repository()` methods. |
|
|
119
119
|
| `service.mixin.ts` | Adds `service()` method. |
|
|
120
|
-
| `types.ts` | Defines interfaces
|
|
120
|
+
| `types.ts` | Defines interfaces and types (`TMixinOpts`, `IComponentMixin`, `IControllerMixin`, etc.). |
|
|
121
|
+
|
|
122
|
+
All registration methods accept an optional `opts?: TMixinOpts` parameter for custom binding configuration:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
type TMixinOpts<Args extends AnyObject = any> = {
|
|
126
|
+
binding: { namespace: string; key: string };
|
|
127
|
+
args?: Args;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Example: Custom binding key
|
|
131
|
+
this.controller(UserController, {
|
|
132
|
+
binding: { namespace: 'controllers', key: 'CustomUserController' }
|
|
133
|
+
});
|
|
134
|
+
```
|
|
121
135
|
|
|
122
136
|
#### `base/models`
|
|
123
137
|
|