@venizia/ignis-docs 0.0.5 → 0.0.6-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/wiki/best-practices/architectural-patterns.md +0 -2
- package/wiki/best-practices/architecture-decisions.md +0 -8
- package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
- package/wiki/best-practices/code-style-standards/index.md +0 -1
- package/wiki/best-practices/code-style-standards/tooling.md +0 -3
- package/wiki/best-practices/contribution-workflow.md +12 -12
- package/wiki/best-practices/index.md +4 -14
- package/wiki/best-practices/performance-optimization.md +3 -3
- package/wiki/best-practices/security-guidelines.md +2 -2
- package/wiki/best-practices/troubleshooting-tips.md +1 -1
- package/wiki/guides/core-concepts/application/bootstrapping.md +6 -7
- package/wiki/guides/core-concepts/components-guide.md +1 -1
- package/wiki/guides/core-concepts/components.md +2 -2
- package/wiki/guides/core-concepts/dependency-injection.md +4 -5
- package/wiki/guides/core-concepts/persistent/datasources.md +4 -5
- package/wiki/guides/core-concepts/services.md +1 -1
- package/wiki/guides/get-started/5-minute-quickstart.md +4 -5
- package/wiki/guides/get-started/philosophy.md +12 -24
- package/wiki/guides/index.md +2 -9
- package/wiki/guides/reference/mcp-docs-server.md +13 -13
- package/wiki/guides/tutorials/building-a-crud-api.md +10 -10
- package/wiki/guides/tutorials/complete-installation.md +11 -12
- package/wiki/guides/tutorials/ecommerce-api.md +3 -3
- package/wiki/guides/tutorials/realtime-chat.md +6 -6
- package/wiki/guides/tutorials/testing.md +4 -5
- package/wiki/index.md +8 -14
- package/wiki/references/base/bootstrapping.md +0 -3
- package/wiki/references/base/components.md +2 -2
- package/wiki/references/base/controllers.md +0 -1
- package/wiki/references/base/datasources.md +1 -1
- package/wiki/references/base/dependency-injection.md +2 -2
- package/wiki/references/base/filter-system/default-filter.md +2 -3
- package/wiki/references/base/filter-system/index.md +1 -1
- package/wiki/references/base/filter-system/quick-reference.md +0 -14
- package/wiki/references/base/middlewares.md +0 -8
- package/wiki/references/base/providers.md +0 -9
- package/wiki/references/base/repositories/advanced.md +1 -1
- package/wiki/references/base/repositories/mixins.md +2 -3
- package/wiki/references/base/services.md +0 -1
- package/wiki/references/components/authentication/api.md +444 -0
- package/wiki/references/components/authentication/errors.md +177 -0
- package/wiki/references/components/authentication/index.md +571 -0
- package/wiki/references/components/authentication/usage.md +781 -0
- package/wiki/references/components/health-check.md +292 -103
- package/wiki/references/components/index.md +14 -12
- package/wiki/references/components/mail/api.md +505 -0
- package/wiki/references/components/mail/errors.md +176 -0
- package/wiki/references/components/mail/index.md +535 -0
- package/wiki/references/components/mail/usage.md +404 -0
- package/wiki/references/components/request-tracker.md +229 -25
- package/wiki/references/components/socket-io/api.md +1051 -0
- package/wiki/references/components/socket-io/errors.md +119 -0
- package/wiki/references/components/socket-io/index.md +410 -0
- package/wiki/references/components/socket-io/usage.md +322 -0
- package/wiki/references/components/static-asset/api.md +261 -0
- package/wiki/references/components/static-asset/errors.md +89 -0
- package/wiki/references/components/static-asset/index.md +617 -0
- package/wiki/references/components/static-asset/usage.md +364 -0
- package/wiki/references/components/swagger.md +390 -110
- package/wiki/references/components/template/api-page.md +125 -0
- package/wiki/references/components/template/errors-page.md +100 -0
- package/wiki/references/components/template/index.md +104 -0
- package/wiki/references/components/template/setup-page.md +134 -0
- package/wiki/references/components/template/single-page.md +132 -0
- package/wiki/references/components/template/usage-page.md +127 -0
- package/wiki/references/components/websocket/api.md +508 -0
- package/wiki/references/components/websocket/errors.md +123 -0
- package/wiki/references/components/websocket/index.md +453 -0
- package/wiki/references/components/websocket/usage.md +475 -0
- package/wiki/references/helpers/cron/index.md +224 -0
- package/wiki/references/helpers/crypto/index.md +537 -0
- package/wiki/references/helpers/env/index.md +214 -0
- package/wiki/references/helpers/error/index.md +232 -0
- package/wiki/references/helpers/index.md +16 -15
- package/wiki/references/helpers/inversion/index.md +608 -0
- package/wiki/references/helpers/logger/index.md +600 -0
- package/wiki/references/helpers/network/api.md +986 -0
- package/wiki/references/helpers/network/index.md +620 -0
- package/wiki/references/helpers/queue/index.md +589 -0
- package/wiki/references/helpers/redis/index.md +495 -0
- package/wiki/references/helpers/socket-io/api.md +497 -0
- package/wiki/references/helpers/socket-io/index.md +513 -0
- package/wiki/references/helpers/storage/api.md +705 -0
- package/wiki/references/helpers/storage/index.md +583 -0
- package/wiki/references/helpers/template/index.md +66 -0
- package/wiki/references/helpers/template/single-page.md +126 -0
- package/wiki/references/helpers/testing/index.md +510 -0
- package/wiki/references/helpers/types/index.md +512 -0
- package/wiki/references/helpers/uid/index.md +272 -0
- package/wiki/references/helpers/websocket/api.md +736 -0
- package/wiki/references/helpers/websocket/index.md +574 -0
- package/wiki/references/helpers/worker-thread/index.md +470 -0
- package/wiki/references/index.md +2 -9
- package/wiki/references/quick-reference.md +3 -18
- package/wiki/references/utilities/jsx.md +1 -8
- package/wiki/references/utilities/statuses.md +0 -7
- package/wiki/references/components/authentication.md +0 -476
- package/wiki/references/components/mail.md +0 -687
- package/wiki/references/components/socket-io.md +0 -562
- package/wiki/references/components/static-asset.md +0 -1277
- package/wiki/references/helpers/cron.md +0 -108
- package/wiki/references/helpers/crypto.md +0 -132
- package/wiki/references/helpers/env.md +0 -83
- package/wiki/references/helpers/error.md +0 -97
- package/wiki/references/helpers/inversion.md +0 -176
- package/wiki/references/helpers/logger.md +0 -296
- package/wiki/references/helpers/network.md +0 -396
- package/wiki/references/helpers/queue.md +0 -150
- package/wiki/references/helpers/redis.md +0 -142
- package/wiki/references/helpers/socket-io.md +0 -932
- package/wiki/references/helpers/storage.md +0 -665
- package/wiki/references/helpers/testing.md +0 -133
- package/wiki/references/helpers/types.md +0 -167
- package/wiki/references/helpers/uid.md +0 -167
- package/wiki/references/helpers/worker-thread.md +0 -178
- package/wiki/references/src-details/boot.md +0 -379
- package/wiki/references/src-details/core.md +0 -263
- package/wiki/references/src-details/dev-configs.md +0 -298
- package/wiki/references/src-details/docs.md +0 -71
- package/wiki/references/src-details/helpers.md +0 -211
- package/wiki/references/src-details/index.md +0 -86
- package/wiki/references/src-details/inversion.md +0 -340
|
@@ -1,665 +0,0 @@
|
|
|
1
|
-
# Storage Helpers
|
|
2
|
-
|
|
3
|
-
Storage solutions for in-memory, local filesystem, and cloud object storage with a unified interface.
|
|
4
|
-
|
|
5
|
-
## Quick Reference
|
|
6
|
-
|
|
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 |
|
|
12
|
-
|
|
13
|
-
### MemoryStorageHelper Methods
|
|
14
|
-
|
|
15
|
-
| Method | Purpose |
|
|
16
|
-
|--------|---------|
|
|
17
|
-
| `set(key, value)` | Store value |
|
|
18
|
-
| `get<T>(key)` | Retrieve value |
|
|
19
|
-
| `isBound(key)` | Check if key exists |
|
|
20
|
-
| `keys()` | Get all keys |
|
|
21
|
-
| `clear()` | Clear all data |
|
|
22
|
-
|
|
23
|
-
### IStorageHelper Operations
|
|
24
|
-
|
|
25
|
-
All storage helpers implementing `IStorageHelper` provide these operations:
|
|
26
|
-
|
|
27
|
-
| Operation | Methods |
|
|
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 })` |
|
|
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
|
-
---
|
|
96
|
-
|
|
97
|
-
## `MemoryStorageHelper`
|
|
98
|
-
|
|
99
|
-
The `MemoryStorageHelper` is a simple in-memory key-value store. It's useful for caching, storing temporary application state, or passing data between loosely coupled parts of your application within a single process.
|
|
100
|
-
|
|
101
|
-
### Creating an Instance
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
import { MemoryStorageHelper } from '@venizia/ignis';
|
|
105
|
-
|
|
106
|
-
const memoryStore = new MemoryStorageHelper();
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Usage
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
// Set a value
|
|
113
|
-
memoryStore.set('my-key', { a: 1, b: 2 });
|
|
114
|
-
|
|
115
|
-
// Get a value
|
|
116
|
-
const value = memoryStore.get<{ a: number; b: number }>('my-key');
|
|
117
|
-
// => { a: 1, b: 2 }
|
|
118
|
-
|
|
119
|
-
// Check if a key exists
|
|
120
|
-
const hasKey = memoryStore.isBound('my-key');
|
|
121
|
-
// => true
|
|
122
|
-
|
|
123
|
-
// Get all keys
|
|
124
|
-
const allKeys = memoryStore.keys();
|
|
125
|
-
// => ['my-key']
|
|
126
|
-
|
|
127
|
-
// Clear the storage
|
|
128
|
-
memoryStore.clear();
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
## `DiskHelper`
|
|
133
|
-
|
|
134
|
-
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.
|
|
135
|
-
|
|
136
|
-
### Creating an Instance
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
import { DiskHelper } from '@venizia/ignis-helpers';
|
|
140
|
-
|
|
141
|
-
const diskHelper = new DiskHelper({
|
|
142
|
-
basePath: './app_data/storage', // Base directory for storage
|
|
143
|
-
});
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**Options:**
|
|
147
|
-
- `basePath` (string, required): Base directory where buckets will be created
|
|
148
|
-
- `scope` (string, optional): Logger scope name
|
|
149
|
-
- `identifier` (string, optional): Helper identifier
|
|
150
|
-
|
|
151
|
-
**Directory Structure:**
|
|
152
|
-
```
|
|
153
|
-
app_data/storage/ ← basePath
|
|
154
|
-
├── bucket-1/ ← bucket (directory)
|
|
155
|
-
│ ├── file1.pdf ← object (file)
|
|
156
|
-
│ └── file2.jpg
|
|
157
|
-
├── bucket-2/
|
|
158
|
-
│ └── document.docx
|
|
159
|
-
└── user-uploads/
|
|
160
|
-
├── avatar.png
|
|
161
|
-
└── resume.pdf
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Key Features
|
|
165
|
-
|
|
166
|
-
✅ **Automatic Directory Creation** - Creates directories as needed
|
|
167
|
-
✅ **Built-in Security** - Path traversal protection, name validation
|
|
168
|
-
✅ **Stream-Based** - Efficient for large files
|
|
169
|
-
✅ **Metadata Support** - Uses filesystem stats
|
|
170
|
-
✅ **Compatible Interface** - Same API as MinioHelper
|
|
171
|
-
|
|
172
|
-
### Bucket Operations
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
// Check if bucket exists
|
|
176
|
-
const exists = await diskHelper.isBucketExists({ name: 'my-bucket' });
|
|
177
|
-
|
|
178
|
-
// Create a bucket (creates directory)
|
|
179
|
-
const bucket = await diskHelper.createBucket({ name: 'my-bucket' });
|
|
180
|
-
// Returns: { name: 'my-bucket', creationDate: Date }
|
|
181
|
-
|
|
182
|
-
// Get all buckets
|
|
183
|
-
const buckets = await diskHelper.getBuckets();
|
|
184
|
-
// Returns: [{ name: 'bucket-1', creationDate: Date }, ...]
|
|
185
|
-
|
|
186
|
-
// Get specific bucket
|
|
187
|
-
const bucket = await diskHelper.getBucket({ name: 'my-bucket' });
|
|
188
|
-
// Returns: { name: 'my-bucket', creationDate: Date } | null
|
|
189
|
-
|
|
190
|
-
// Remove bucket (removes directory, must be empty)
|
|
191
|
-
const removed = await diskHelper.removeBucket({ name: 'my-bucket' });
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### File Operations
|
|
195
|
-
|
|
196
|
-
#### Upload Files
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
// Basic upload
|
|
200
|
-
const result = await diskHelper.upload({
|
|
201
|
-
bucket: 'my-bucket',
|
|
202
|
-
files: [
|
|
203
|
-
{
|
|
204
|
-
originalname: 'document.pdf',
|
|
205
|
-
mimetype: 'application/pdf',
|
|
206
|
-
buffer: fileBuffer,
|
|
207
|
-
size: fileBuffer.length,
|
|
208
|
-
},
|
|
209
|
-
],
|
|
210
|
-
});
|
|
211
|
-
// Returns: [{ bucketName: 'my-bucket', objectName: 'document.pdf', link: '...' }]
|
|
212
|
-
|
|
213
|
-
// Upload with custom normalization
|
|
214
|
-
const result = await diskHelper.upload({
|
|
215
|
-
bucket: 'my-bucket',
|
|
216
|
-
files: files,
|
|
217
|
-
normalizeNameFn: ({` originalName, folderPath `}) => {
|
|
218
|
-
return folderPath ? `${folderPath}/${name}` : name;
|
|
219
|
-
},
|
|
220
|
-
normalizeLinkFn: ({ bucketName, normalizeName }) => {
|
|
221
|
-
return `/files/${bucketName}/${normalizeName}`;
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
#### Get File (Stream)
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
const fileStream = await diskHelper.getFile({
|
|
230
|
-
bucket: 'my-bucket',
|
|
231
|
-
name: 'document.pdf',
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// Pipe to response
|
|
235
|
-
fileStream.pipe(response);
|
|
236
|
-
|
|
237
|
-
// Or save to another location
|
|
238
|
-
import fs from 'fs';
|
|
239
|
-
const writeStream = fs.createWriteStream('./backup/document.pdf');
|
|
240
|
-
fileStream.pipe(writeStream);
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
#### Get File Metadata
|
|
244
|
-
|
|
245
|
-
```typescript
|
|
246
|
-
const stat = await diskHelper.getStat({
|
|
247
|
-
bucket: 'my-bucket',
|
|
248
|
-
name: 'document.pdf',
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
console.log(stat);
|
|
252
|
-
// {
|
|
253
|
-
// size: 1024,
|
|
254
|
-
// metadata: { /* filesystem stats */ },
|
|
255
|
-
// lastModified: Date,
|
|
256
|
-
// etag: 'hash',
|
|
257
|
-
// }
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
#### List Objects
|
|
261
|
-
|
|
262
|
-
```typescript
|
|
263
|
-
// List all objects in bucket
|
|
264
|
-
const objects = await diskHelper.listObjects({
|
|
265
|
-
bucket: 'my-bucket',
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// List with prefix (folder-like behavior)
|
|
269
|
-
const objects = await diskHelper.listObjects({
|
|
270
|
-
bucket: 'my-bucket',
|
|
271
|
-
prefix: 'documents/',
|
|
272
|
-
useRecursive: false, // Non-recursive by default
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Limit results
|
|
276
|
-
const objects = await diskHelper.listObjects({
|
|
277
|
-
bucket: 'my-bucket',
|
|
278
|
-
maxKeys: 100,
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
console.log(objects);
|
|
282
|
-
// [
|
|
283
|
-
// { name: 'file1.pdf', size: 1024, lastModified: Date },
|
|
284
|
-
// { name: 'file2.jpg', size: 2048, lastModified: Date },
|
|
285
|
-
// ]
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
#### Delete Objects
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
// Delete single object
|
|
292
|
-
await diskHelper.removeObject({
|
|
293
|
-
bucket: 'my-bucket',
|
|
294
|
-
name: 'old-file.pdf',
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
// Delete multiple objects
|
|
298
|
-
await diskHelper.removeObjects({
|
|
299
|
-
bucket: 'my-bucket',
|
|
300
|
-
names: ['file1.pdf', 'file2.jpg', 'file3.png'],
|
|
301
|
-
});
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### Security & Validation
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
// Name validation (inherited from BaseStorageHelper)
|
|
308
|
-
const isValid = diskHelper.isValidName('my-file.pdf'); // true
|
|
309
|
-
const isValid = diskHelper.isValidName('../etc/passwd'); // false ❌ path traversal
|
|
310
|
-
const isValid = diskHelper.isValidName('.hidden'); // false ❌ hidden file
|
|
311
|
-
const isValid = diskHelper.isValidName('file;rm -rf'); // false ❌ shell injection
|
|
312
|
-
|
|
313
|
-
// All operations validate names before execution
|
|
314
|
-
try {
|
|
315
|
-
await diskHelper.createBucket({ name: '../../../etc' });
|
|
316
|
-
} catch (error) {
|
|
317
|
-
// Error: Invalid bucket name
|
|
318
|
-
}
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### Use Cases
|
|
322
|
-
|
|
323
|
-
**Development & Testing:**
|
|
324
|
-
```typescript
|
|
325
|
-
const devStorage = new DiskHelper({ basePath: './dev-storage' });
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
**Small-Scale Production:**
|
|
329
|
-
```typescript
|
|
330
|
-
const prodStorage = new DiskHelper({ basePath: '/var/app/storage' });
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
**Temporary Files:**
|
|
334
|
-
```typescript
|
|
335
|
-
const tempStorage = new DiskHelper({ basePath: './temp' });
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
**Hybrid Setup:**
|
|
339
|
-
```typescript
|
|
340
|
-
// User uploads → Cloud (MinIO)
|
|
341
|
-
const cloudStorage = new MinioHelper({ /* ... */ });
|
|
342
|
-
|
|
343
|
-
// System files → Local (Disk)
|
|
344
|
-
const localStorage = new DiskHelper({ basePath: './system-files' });
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
## `MinioHelper`
|
|
349
|
-
|
|
350
|
-
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.
|
|
351
|
-
|
|
352
|
-
### Creating a MinIO Client
|
|
353
|
-
|
|
354
|
-
```typescript
|
|
355
|
-
import { MinioHelper } from '@venizia/ignis';
|
|
356
|
-
|
|
357
|
-
const minioClient = new MinioHelper({
|
|
358
|
-
endPoint: 'localhost',
|
|
359
|
-
port: 9000,
|
|
360
|
-
useSSL: false,
|
|
361
|
-
accessKey: 'minioadmin',
|
|
362
|
-
secretKey: 'minioadmin',
|
|
363
|
-
});
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### Bucket Operations
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
// Create a bucket if it doesn't exist
|
|
370
|
-
const bucketName = 'my-bucket';
|
|
371
|
-
const bucketExists = await minioClient.isBucketExists({ name: bucketName });
|
|
372
|
-
if (!bucketExists) {
|
|
373
|
-
await minioClient.createBucket({ name: bucketName });
|
|
374
|
-
}
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Object Operations
|
|
378
|
-
|
|
379
|
-
#### Uploading a File
|
|
380
|
-
|
|
381
|
-
The `upload` method takes an array of file objects, typically from a multipart form data request.
|
|
382
|
-
|
|
383
|
-
```typescript
|
|
384
|
-
// Basic upload
|
|
385
|
-
const uploadResult = await minioClient.upload({
|
|
386
|
-
bucket: 'my-bucket',
|
|
387
|
-
files: files,
|
|
388
|
-
});
|
|
389
|
-
// => [{ bucket: 'my-bucket', fileName: '...', link: '...' }]
|
|
390
|
-
|
|
391
|
-
// Upload with custom filename normalization
|
|
392
|
-
const uploadResult = await minioClient.upload({
|
|
393
|
-
bucket: 'my-bucket',
|
|
394
|
-
files: files,
|
|
395
|
-
normalizeLinkFn: ({ bucketName, normalizeName }) => {
|
|
396
|
-
// Custom link generation
|
|
397
|
-
return `/api/files/${bucketName}/${encodeURIComponent(normalizeName)}`;
|
|
398
|
-
},
|
|
399
|
-
});
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
**Options:**
|
|
403
|
-
- `bucket` (string): Target bucket name
|
|
404
|
-
- `files` (`Array<IUploadFile>`): Array of file objects to upload
|
|
405
|
-
- `normalizeNameFn` (optional): Custom function to normalize filenames (default: lowercase + replace spaces with underscores)
|
|
406
|
-
- `normalizeLinkFn` (optional): Custom function to generate file access links (default: `/static-assets/{bucket}/{encodedName}`)
|
|
407
|
-
|
|
408
|
-
**IUploadFile Interface:**
|
|
409
|
-
```typescript
|
|
410
|
-
interface IUploadFile {
|
|
411
|
-
originalname: string;
|
|
412
|
-
mimetype: string;
|
|
413
|
-
buffer: Buffer;
|
|
414
|
-
size: number;
|
|
415
|
-
encoding?: string; // Optional encoding information
|
|
416
|
-
}
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
**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.
|
|
420
|
-
|
|
421
|
-
#### Getting an Object
|
|
422
|
-
|
|
423
|
-
The `getFile` method returns a `Readable` stream for an object.
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
const fileStream = await minioClient.getFile({
|
|
427
|
-
bucket: 'my-bucket',
|
|
428
|
-
name: 'my-file.txt',
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
fileStream.pipe(process.stdout);
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
#### Removing Objects
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
// Remove a single object
|
|
438
|
-
await minioClient.removeObject({ bucket: 'my-bucket', name: 'my-file.txt' });
|
|
439
|
-
|
|
440
|
-
// Remove multiple objects
|
|
441
|
-
await minioClient.removeObjects({ bucket: 'my-bucket', names: ['file1.txt', 'file2.txt'] });
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
## DiskHelper vs MinioHelper Comparison
|
|
446
|
-
|
|
447
|
-
Both helpers implement the same `IStorageHelper` interface, making them functionally equivalent from an API perspective.
|
|
448
|
-
|
|
449
|
-
### Feature Comparison
|
|
450
|
-
|
|
451
|
-
| Feature | DiskHelper | MinioHelper |
|
|
452
|
-
|---------|------------|-------------|
|
|
453
|
-
| **Storage Type** | Local filesystem | S3-compatible cloud |
|
|
454
|
-
| **Interface** | `IStorageHelper` | `IStorageHelper` |
|
|
455
|
-
| **Scalability** | Limited to single server | Horizontally scalable |
|
|
456
|
-
| **Setup Complexity** | Simple (just a directory) | Requires MinIO server |
|
|
457
|
-
| **Performance** | Fast (local disk I/O) | Network-dependent |
|
|
458
|
-
| **Backup** | Manual filesystem backup | Built-in replication |
|
|
459
|
-
| **Cost** | Disk space only | Server + storage costs |
|
|
460
|
-
| **Use Case** | Development, small apps | Production, large scale |
|
|
461
|
-
|
|
462
|
-
### When to Use Each
|
|
463
|
-
|
|
464
|
-
**Use DiskHelper when:**
|
|
465
|
-
- Developing/testing locally
|
|
466
|
-
- Running on a single server
|
|
467
|
-
- Storage needs are < 100GB
|
|
468
|
-
- Simplicity is priority
|
|
469
|
-
- No cloud infrastructure
|
|
470
|
-
|
|
471
|
-
**Use MinioHelper when:**
|
|
472
|
-
- Deploying to production
|
|
473
|
-
- Need horizontal scaling
|
|
474
|
-
- Storage needs > 100GB
|
|
475
|
-
- Need backup/replication
|
|
476
|
-
- Multi-server deployment
|
|
477
|
-
|
|
478
|
-
### Hybrid Approach
|
|
479
|
-
|
|
480
|
-
Use both simultaneously for different purposes:
|
|
481
|
-
|
|
482
|
-
```typescript
|
|
483
|
-
import { DiskHelper, MinioHelper } from '@venizia/ignis-helpers';
|
|
484
|
-
|
|
485
|
-
// Cloud storage for user content
|
|
486
|
-
const userStorage = new MinioHelper({ /* ... */ });
|
|
487
|
-
|
|
488
|
-
// Local storage for system files
|
|
489
|
-
const systemStorage = new DiskHelper({ basePath: './system' });
|
|
490
|
-
|
|
491
|
-
// Local storage for temporary files
|
|
492
|
-
const tempStorage = new DiskHelper({ basePath: './temp' });
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
## Common Patterns
|
|
497
|
-
|
|
498
|
-
### Pattern 1: Storage Abstraction
|
|
499
|
-
|
|
500
|
-
```typescript
|
|
501
|
-
class FileService {
|
|
502
|
-
constructor(private storage: IStorageHelper) {}
|
|
503
|
-
|
|
504
|
-
async uploadFile(bucket: string, file: IUploadFile) {
|
|
505
|
-
return await this.storage.upload({ bucket, files: [file] });
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
async getFile(bucket: string, name: string) {
|
|
509
|
-
return await this.storage.getFile({ bucket, name });
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// Use with either storage type
|
|
514
|
-
const service1 = new FileService(new DiskHelper({ basePath: './files' }));
|
|
515
|
-
const service2 = new FileService(new MinioHelper({ /* ... */ }));
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
### Pattern 2: Environment-Based Selection
|
|
519
|
-
|
|
520
|
-
```typescript
|
|
521
|
-
import { applicationEnvironment } from '@venizia/ignis';
|
|
522
|
-
|
|
523
|
-
const createStorageHelper = (): IStorageHelper => {
|
|
524
|
-
const storageType = applicationEnvironment.get('STORAGE_TYPE');
|
|
525
|
-
|
|
526
|
-
if (storageType === 'minio') {
|
|
527
|
-
return new MinioHelper({
|
|
528
|
-
endPoint: applicationEnvironment.get('MINIO_HOST'),
|
|
529
|
-
port: Number(applicationEnvironment.get('MINIO_PORT')),
|
|
530
|
-
accessKey: applicationEnvironment.get('MINIO_ACCESS_KEY'),
|
|
531
|
-
secretKey: applicationEnvironment.get('MINIO_SECRET_KEY'),
|
|
532
|
-
useSSL: applicationEnvironment.get('MINIO_USE_SSL') === 'true',
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
return new DiskHelper({
|
|
537
|
-
basePath: applicationEnvironment.get('DISK_STORAGE_PATH') || './storage',
|
|
538
|
-
});
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
const storage = createStorageHelper();
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
### Pattern 3: Fallback Strategy
|
|
545
|
-
|
|
546
|
-
```typescript
|
|
547
|
-
class ResilientStorage implements IStorageHelper {
|
|
548
|
-
constructor(
|
|
549
|
-
private primary: IStorageHelper,
|
|
550
|
-
private fallback: IStorageHelper,
|
|
551
|
-
) {}
|
|
552
|
-
|
|
553
|
-
async upload(opts: any) {
|
|
554
|
-
try {
|
|
555
|
-
return await this.primary.upload(opts);
|
|
556
|
-
} catch (error) {
|
|
557
|
-
console.error('Primary storage failed, using fallback', error);
|
|
558
|
-
return await this.fallback.upload(opts);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Implement other methods with similar fallback logic...
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// Usage
|
|
566
|
-
const storage = new ResilientStorage(
|
|
567
|
-
new MinioHelper({ /* ... */ }), // Primary: Cloud
|
|
568
|
-
new DiskHelper({ basePath: './backup' }), // Fallback: Local
|
|
569
|
-
);
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
## See Also
|
|
574
|
-
|
|
575
|
-
- **Related Concepts:**
|
|
576
|
-
- [Services](/guides/core-concepts/services) - File storage in services
|
|
577
|
-
|
|
578
|
-
- **Other Helpers:**
|
|
579
|
-
- [Helpers Index](./index) - All available helpers
|
|
580
|
-
|
|
581
|
-
- **References:**
|
|
582
|
-
- [Static Asset Component](/references/components/static-asset) - Serving stored files
|
|
583
|
-
- [Request Utilities](/references/utilities/request) - `parseMultipartBody` for file uploads
|
|
584
|
-
|
|
585
|
-
- **External Resources:**
|
|
586
|
-
- [MinIO Documentation](https://min.io/docs/minio/linux/index.html) - MinIO object storage
|
|
587
|
-
- [AWS S3 API](https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html) - S3-compatible API reference
|
|
588
|
-
|
|
589
|
-
- **Best Practices:**
|
|
590
|
-
- [Security Guidelines](/best-practices/security-guidelines) - File upload security
|
|
591
|
-
- [Deployment Strategies](/best-practices/deployment-strategies) - Storage in production
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
## TypeScript Interfaces Reference
|
|
595
|
-
|
|
596
|
-
### IUploadFile
|
|
597
|
-
|
|
598
|
-
```typescript
|
|
599
|
-
interface IUploadFile {
|
|
600
|
-
originalName: string; // Original filename (renamed from 'originalname')
|
|
601
|
-
mimetype: string; // MIME type (e.g., 'image/png')
|
|
602
|
-
buffer: Buffer; // File content
|
|
603
|
-
size: number; // File size in bytes
|
|
604
|
-
encoding?: string; // Optional encoding (e.g., '7bit', 'base64')
|
|
605
|
-
folderPath?: string; // Optional folder path for organization
|
|
606
|
-
}
|
|
607
|
-
```
|
|
608
|
-
|
|
609
|
-
**Note:** The property was renamed from `originalname` to `originalName` for consistency.
|
|
610
|
-
|
|
611
|
-
### IUploadResult
|
|
612
|
-
|
|
613
|
-
```typescript
|
|
614
|
-
interface IUploadResult {
|
|
615
|
-
bucketName: string; // Bucket where file was stored
|
|
616
|
-
objectName: string; // Stored filename
|
|
617
|
-
link: string; // Access URL
|
|
618
|
-
metaLink?: any; // MetaLink database record (if enabled)
|
|
619
|
-
metaLinkError?: any; // Error message if MetaLink creation failed
|
|
620
|
-
}
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
### IFileStat
|
|
624
|
-
|
|
625
|
-
```typescript
|
|
626
|
-
interface IFileStat {
|
|
627
|
-
size: number; // File size in bytes
|
|
628
|
-
metadata: Record<string, any>; // Storage-specific metadata
|
|
629
|
-
lastModified?: Date; // Last modification date
|
|
630
|
-
etag?: string; // Entity tag
|
|
631
|
-
versionId?: string; // Version ID (if versioning enabled)
|
|
632
|
-
}
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
### IBucketInfo
|
|
636
|
-
|
|
637
|
-
```typescript
|
|
638
|
-
interface IBucketInfo {
|
|
639
|
-
name: string; // Bucket name
|
|
640
|
-
creationDate: Date; // When bucket was created
|
|
641
|
-
}
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
### IObjectInfo
|
|
645
|
-
|
|
646
|
-
```typescript
|
|
647
|
-
interface IObjectInfo {
|
|
648
|
-
name?: string; // Object name
|
|
649
|
-
size?: number; // Object size in bytes
|
|
650
|
-
lastModified?: Date; // Last modification date
|
|
651
|
-
etag?: string; // Entity tag
|
|
652
|
-
prefix?: string; // Prefix (for directory-like listing)
|
|
653
|
-
}
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
### IListObjectsOptions
|
|
657
|
-
|
|
658
|
-
```typescript
|
|
659
|
-
interface IListObjectsOptions {
|
|
660
|
-
bucket: string; // Bucket to list
|
|
661
|
-
prefix?: string; // Filter by prefix
|
|
662
|
-
useRecursive?: boolean; // Recursive listing
|
|
663
|
-
maxKeys?: number; // Maximum objects to return
|
|
664
|
-
}
|
|
665
|
-
```
|