@elchinabilov/nestjs-media-library 1.0.2
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 +308 -0
- package/dist/controllers/media.controller.d.ts +13 -0
- package/dist/controllers/media.controller.js +81 -0
- package/dist/controllers/media.controller.js.map +1 -0
- package/dist/entities/media.entity.d.ts +12 -0
- package/dist/entities/media.entity.js +60 -0
- package/dist/entities/media.entity.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/media-config.interface.d.ts +20 -0
- package/dist/interfaces/media-config.interface.js +3 -0
- package/dist/interfaces/media-config.interface.js.map +1 -0
- package/dist/media-library.module.d.ts +5 -0
- package/dist/media-library.module.js +102 -0
- package/dist/media-library.module.js.map +1 -0
- package/dist/migrations/1703000000000-CreateMediaTable.d.ts +5 -0
- package/dist/migrations/1703000000000-CreateMediaTable.js +64 -0
- package/dist/migrations/1703000000000-CreateMediaTable.js.map +1 -0
- package/dist/migrations/CreateMediaTable.d.ts +5 -0
- package/dist/migrations/CreateMediaTable.js +65 -0
- package/dist/migrations/CreateMediaTable.js.map +1 -0
- package/dist/services/image.service.d.ts +7 -0
- package/dist/services/image.service.js +51 -0
- package/dist/services/image.service.js.map +1 -0
- package/dist/services/media.service.d.ts +17 -0
- package/dist/services/media.service.js +165 -0
- package/dist/services/media.service.js.map +1 -0
- package/dist/services/s3.service.d.ts +11 -0
- package/dist/services/s3.service.js +64 -0
- package/dist/services/s3.service.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +43 -0
- package/tsconfig.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# @elchinabilov/nestjs-media-library
|
|
2
|
+
|
|
3
|
+
Complete NestJS media management library with S3 integration, automatic image optimization, and multiple size conversions.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ **Database Migrations** - TypeORM migrations included
|
|
8
|
+
✅ **Single/Multiple File Upload** - Support for both single and multiple file uploads
|
|
9
|
+
✅ **Retrieve Files** - Get files as objects or arrays
|
|
10
|
+
✅ **Automatic Image Optimization** - Built-in image compression to WebP format
|
|
11
|
+
✅ **Multiple Conversions** - Generate thumbnails, medium, large sizes automatically
|
|
12
|
+
✅ **AWS S3 Integration** - Seamless S3 upload support
|
|
13
|
+
✅ **Easy Integration** - Simple NestJS dependency injection
|
|
14
|
+
✅ **RESTful API** - Ready-to-use controllers
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @elchinabilov/nestjs-media-library
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Import Module
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { Module } from "@nestjs/common";
|
|
28
|
+
import { TypeOrmModule } from "@nestjs/typeorm";
|
|
29
|
+
import { MediaLibraryModule } from "@elchinabilov/nestjs-media-library";
|
|
30
|
+
|
|
31
|
+
@Module({
|
|
32
|
+
imports: [
|
|
33
|
+
TypeOrmModule.forRoot({
|
|
34
|
+
// your database config
|
|
35
|
+
}),
|
|
36
|
+
MediaLibraryModule.forRoot({
|
|
37
|
+
disk: "s3", // or 'local'
|
|
38
|
+
uploadPath: "media",
|
|
39
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
40
|
+
conversions: [
|
|
41
|
+
{ suffix: "thumbnail", width: 150 },
|
|
42
|
+
{ suffix: "medium", width: 500 },
|
|
43
|
+
{ suffix: "large", width: 1200, height: 800 },
|
|
44
|
+
],
|
|
45
|
+
s3: {
|
|
46
|
+
region: "us-east-1",
|
|
47
|
+
bucket: "your-bucket",
|
|
48
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
49
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
50
|
+
publicUrl: "https://your-cdn.com", // optional
|
|
51
|
+
},
|
|
52
|
+
allowedMimeTypes: ["image/jpeg", "image/png", "image/webp"], // optional
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
55
|
+
})
|
|
56
|
+
export class AppModule {}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Run Migration
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// In your TypeORM config
|
|
63
|
+
import { CreateMediaTable1703000000000 } from "@elchinabilov/nestjs-media-library";
|
|
64
|
+
|
|
65
|
+
export const dataSource = new DataSource({
|
|
66
|
+
// ... your config
|
|
67
|
+
migrations: [CreateMediaTable1703000000000],
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Or run manually:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm run migration:run
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3. Use in Your Service
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Injectable } from "@nestjs/common";
|
|
81
|
+
import { MediaService } from "@elchinabilov/nestjs-media-library";
|
|
82
|
+
|
|
83
|
+
@Injectable()
|
|
84
|
+
export class YourService {
|
|
85
|
+
constructor(private mediaService: MediaService) {}
|
|
86
|
+
|
|
87
|
+
async uploadFile(file: Express.Multer.File) {
|
|
88
|
+
const media = await this.mediaService.uploadSingle(file);
|
|
89
|
+
console.log("Original:", media.url);
|
|
90
|
+
console.log("Thumbnail:", media.conversions.thumbnail);
|
|
91
|
+
console.log("Medium:", media.conversions.medium);
|
|
92
|
+
return media;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async uploadMultiple(files: Express.Multer.File[]) {
|
|
96
|
+
return await this.mediaService.uploadMultiple(files);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async getMedia(id: string) {
|
|
100
|
+
return await this.mediaService.findOne(id);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async getAllMedia() {
|
|
104
|
+
return await this.mediaService.findAll();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async deleteMedia(id: string) {
|
|
108
|
+
await this.mediaService.delete(id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## API Endpoints
|
|
114
|
+
|
|
115
|
+
The package provides ready-to-use REST endpoints:
|
|
116
|
+
|
|
117
|
+
### Upload Single File
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
POST /media/upload
|
|
121
|
+
Content-Type: multipart/form-data
|
|
122
|
+
Body: file (form-data)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Response:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"id": "uuid",
|
|
130
|
+
"filename": "uuid.webp",
|
|
131
|
+
"originalName": "photo.jpg",
|
|
132
|
+
"mimeType": "image/jpeg",
|
|
133
|
+
"size": 102400,
|
|
134
|
+
"path": "media/uuid.webp",
|
|
135
|
+
"url": "https://bucket.s3.amazonaws.com/media/uuid.webp",
|
|
136
|
+
"conversions": {
|
|
137
|
+
"thumbnail": "https://bucket.s3.amazonaws.com/media/uuid-thumbnail.webp",
|
|
138
|
+
"medium": "https://bucket.s3.amazonaws.com/media/uuid-medium.webp",
|
|
139
|
+
"large": "https://bucket.s3.amazonaws.com/media/uuid-large.webp"
|
|
140
|
+
},
|
|
141
|
+
"disk": "s3",
|
|
142
|
+
"createdAt": "2024-01-01T00:00:00.000Z"
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Upload Multiple Files
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
POST /media/upload-multiple
|
|
150
|
+
Content-Type: multipart/form-data
|
|
151
|
+
Body: files (form-data, multiple)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Get All Media
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
GET /media
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Get Single Media
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
GET /media/:id
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Delete Media
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
DELETE /media/:id
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Configuration Options
|
|
173
|
+
|
|
174
|
+
| Option | Type | Default | Description |
|
|
175
|
+
| ------------------ | -------------------- | ----------- | ----------------------------- |
|
|
176
|
+
| `disk` | `'local' \| 's3'` | `'local'` | Storage driver |
|
|
177
|
+
| `uploadPath` | `string` | `'uploads'` | Upload directory path |
|
|
178
|
+
| `maxFileSize` | `number` | `10485760` | Max file size in bytes (10MB) |
|
|
179
|
+
| `conversions` | `ConversionConfig[]` | `[]` | Image size conversions |
|
|
180
|
+
| `s3` | `S3Config` | - | AWS S3 configuration |
|
|
181
|
+
| `allowedMimeTypes` | `string[]` | - | Allowed file types |
|
|
182
|
+
|
|
183
|
+
### Conversion Config
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
interface ConversionConfig {
|
|
187
|
+
suffix: string; // e.g., 'thumbnail', 'medium'
|
|
188
|
+
width: number; // Width in pixels
|
|
189
|
+
height?: number; // Optional height (maintains aspect ratio if omitted)
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Local Storage Setup
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
MediaLibraryModule.forRoot({
|
|
197
|
+
disk: "local",
|
|
198
|
+
uploadPath: "public/uploads",
|
|
199
|
+
conversions: [{ suffix: "thumb", width: 200 }],
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Don't forget to serve static files:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// main.ts
|
|
207
|
+
import { NestFactory } from "@nestjs/core";
|
|
208
|
+
import { NestExpressApplication } from "@nestjs/platform-express";
|
|
209
|
+
import { join } from "path";
|
|
210
|
+
|
|
211
|
+
async function bootstrap() {
|
|
212
|
+
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
|
213
|
+
app.useStaticAssets(join(__dirname, "..", "public"));
|
|
214
|
+
await app.listen(3000);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Advanced Usage
|
|
219
|
+
|
|
220
|
+
### Custom Controller
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import {
|
|
224
|
+
Controller,
|
|
225
|
+
Post,
|
|
226
|
+
UseInterceptors,
|
|
227
|
+
UploadedFile,
|
|
228
|
+
} from "@nestjs/common";
|
|
229
|
+
import { FileInterceptor } from "@nestjs/platform-express";
|
|
230
|
+
import { MediaService } from "@elchinabilov/nestjs-media-library";
|
|
231
|
+
|
|
232
|
+
@Controller("custom")
|
|
233
|
+
export class CustomController {
|
|
234
|
+
constructor(private mediaService: MediaService) {}
|
|
235
|
+
|
|
236
|
+
@Post("avatar")
|
|
237
|
+
@UseInterceptors(FileInterceptor("avatar"))
|
|
238
|
+
async uploadAvatar(@UploadedFile() file: Express.Multer.File) {
|
|
239
|
+
const media = await this.mediaService.uploadSingle(file);
|
|
240
|
+
return {
|
|
241
|
+
avatarUrl: media.url,
|
|
242
|
+
thumbnailUrl: media.conversions?.thumbnail,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Direct S3 Service Usage
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { S3Service } from "@elchinabilov/nestjs-media-library";
|
|
252
|
+
|
|
253
|
+
@Injectable()
|
|
254
|
+
export class MyService {
|
|
255
|
+
constructor(private s3Service: S3Service) {}
|
|
256
|
+
|
|
257
|
+
async uploadCustom(buffer: Buffer) {
|
|
258
|
+
return await this.s3Service.uploadFile(
|
|
259
|
+
buffer,
|
|
260
|
+
"custom/path/file.jpg",
|
|
261
|
+
"image/jpeg"
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Image Processing
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import { ImageService } from "@elchinabilov/nestjs-media-library";
|
|
271
|
+
|
|
272
|
+
@Injectable()
|
|
273
|
+
export class MyService {
|
|
274
|
+
constructor(private imageService: ImageService) {}
|
|
275
|
+
|
|
276
|
+
async processImage(buffer: Buffer) {
|
|
277
|
+
// Optimize to WebP
|
|
278
|
+
const optimized = await this.imageService.optimizeImage(buffer);
|
|
279
|
+
|
|
280
|
+
// Create custom sizes
|
|
281
|
+
const conversions = await this.imageService.createConversions(buffer, [
|
|
282
|
+
{ suffix: "small", width: 100 },
|
|
283
|
+
{ suffix: "large", width: 2000 },
|
|
284
|
+
]);
|
|
285
|
+
|
|
286
|
+
return { optimized, conversions };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Environment Variables
|
|
292
|
+
|
|
293
|
+
Create a `.env` file:
|
|
294
|
+
|
|
295
|
+
```env
|
|
296
|
+
AWS_ACCESS_KEY_ID=your_access_key
|
|
297
|
+
AWS_SECRET_ACCESS_KEY=your_secret_key
|
|
298
|
+
AWS_REGION=us-east-1
|
|
299
|
+
AWS_BUCKET=your-bucket-name
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT © Elchin Abilov
|
|
305
|
+
|
|
306
|
+
## Support
|
|
307
|
+
|
|
308
|
+
For issues and questions, please open an issue on GitHub.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MediaService } from "../services/media.service";
|
|
2
|
+
import { Media } from "../entities/media.entity";
|
|
3
|
+
export declare class MediaController {
|
|
4
|
+
private readonly mediaService;
|
|
5
|
+
constructor(mediaService: MediaService);
|
|
6
|
+
uploadSingle(file: Express.Multer.File): Promise<Media>;
|
|
7
|
+
uploadMultiple(files: Express.Multer.File[]): Promise<Media[]>;
|
|
8
|
+
findAll(): Promise<Media[]>;
|
|
9
|
+
findOne(id: string): Promise<Media>;
|
|
10
|
+
delete(id: string): Promise<{
|
|
11
|
+
message: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MediaController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const platform_express_1 = require("@nestjs/platform-express");
|
|
18
|
+
const media_service_1 = require("../services/media.service");
|
|
19
|
+
let MediaController = class MediaController {
|
|
20
|
+
constructor(mediaService) {
|
|
21
|
+
this.mediaService = mediaService;
|
|
22
|
+
}
|
|
23
|
+
async uploadSingle(file) {
|
|
24
|
+
return this.mediaService.uploadSingle(file);
|
|
25
|
+
}
|
|
26
|
+
async uploadMultiple(files) {
|
|
27
|
+
return this.mediaService.uploadMultiple(files);
|
|
28
|
+
}
|
|
29
|
+
async findAll() {
|
|
30
|
+
return this.mediaService.findAll();
|
|
31
|
+
}
|
|
32
|
+
async findOne(id) {
|
|
33
|
+
return this.mediaService.findOne(id);
|
|
34
|
+
}
|
|
35
|
+
async delete(id) {
|
|
36
|
+
await this.mediaService.delete(id);
|
|
37
|
+
return { message: "Media deleted successfully" };
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.MediaController = MediaController;
|
|
41
|
+
__decorate([
|
|
42
|
+
(0, common_1.Post)("upload"),
|
|
43
|
+
(0, common_1.UseInterceptors)((0, platform_express_1.FileInterceptor)("file")),
|
|
44
|
+
__param(0, (0, common_1.UploadedFile)()),
|
|
45
|
+
__metadata("design:type", Function),
|
|
46
|
+
__metadata("design:paramtypes", [Object]),
|
|
47
|
+
__metadata("design:returntype", Promise)
|
|
48
|
+
], MediaController.prototype, "uploadSingle", null);
|
|
49
|
+
__decorate([
|
|
50
|
+
(0, common_1.Post)("upload-multiple"),
|
|
51
|
+
(0, common_1.UseInterceptors)((0, platform_express_1.FilesInterceptor)("files", 10)),
|
|
52
|
+
__param(0, (0, common_1.UploadedFiles)()),
|
|
53
|
+
__metadata("design:type", Function),
|
|
54
|
+
__metadata("design:paramtypes", [Array]),
|
|
55
|
+
__metadata("design:returntype", Promise)
|
|
56
|
+
], MediaController.prototype, "uploadMultiple", null);
|
|
57
|
+
__decorate([
|
|
58
|
+
(0, common_1.Get)(),
|
|
59
|
+
__metadata("design:type", Function),
|
|
60
|
+
__metadata("design:paramtypes", []),
|
|
61
|
+
__metadata("design:returntype", Promise)
|
|
62
|
+
], MediaController.prototype, "findAll", null);
|
|
63
|
+
__decorate([
|
|
64
|
+
(0, common_1.Get)(":id"),
|
|
65
|
+
__param(0, (0, common_1.Param)("id")),
|
|
66
|
+
__metadata("design:type", Function),
|
|
67
|
+
__metadata("design:paramtypes", [String]),
|
|
68
|
+
__metadata("design:returntype", Promise)
|
|
69
|
+
], MediaController.prototype, "findOne", null);
|
|
70
|
+
__decorate([
|
|
71
|
+
(0, common_1.Delete)(":id"),
|
|
72
|
+
__param(0, (0, common_1.Param)("id")),
|
|
73
|
+
__metadata("design:type", Function),
|
|
74
|
+
__metadata("design:paramtypes", [String]),
|
|
75
|
+
__metadata("design:returntype", Promise)
|
|
76
|
+
], MediaController.prototype, "delete", null);
|
|
77
|
+
exports.MediaController = MediaController = __decorate([
|
|
78
|
+
(0, common_1.Controller)("media"),
|
|
79
|
+
__metadata("design:paramtypes", [media_service_1.MediaService])
|
|
80
|
+
], MediaController);
|
|
81
|
+
//# sourceMappingURL=media.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.controller.js","sourceRoot":"","sources":["../../src/controllers/media.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CASwB;AACxB,+DAA6E;AAC7E,6DAAyD;AAIlD,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B,YAA6B,YAA0B;QAA1B,iBAAY,GAAZ,YAAY,CAAc;IAAG,CAAC;IAIrD,AAAN,KAAK,CAAC,YAAY,CACA,IAAyB;QAEzC,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC;IAIK,AAAN,KAAK,CAAC,cAAc,CACD,KAA4B;QAE7C,OAAO,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAc,EAAU;QACnC,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM,CAAc,EAAU;QAClC,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC;IACnD,CAAC;CACF,CAAA;AAlCY,0CAAe;AAKpB;IAFL,IAAA,aAAI,EAAC,QAAQ,CAAC;IACd,IAAA,wBAAe,EAAC,IAAA,kCAAe,EAAC,MAAM,CAAC,CAAC;IAEtC,WAAA,IAAA,qBAAY,GAAE,CAAA;;;;mDAGhB;AAIK;IAFL,IAAA,aAAI,EAAC,iBAAiB,CAAC;IACvB,IAAA,wBAAe,EAAC,IAAA,mCAAgB,EAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAE5C,WAAA,IAAA,sBAAa,GAAE,CAAA;;;;qDAGjB;AAGK;IADL,IAAA,YAAG,GAAE;;;;8CAGL;AAGK;IADL,IAAA,YAAG,EAAC,KAAK,CAAC;IACI,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;8CAEzB;AAGK;IADL,IAAA,eAAM,EAAC,KAAK,CAAC;IACA,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;6CAGxB;0BAjCU,eAAe;IAD3B,IAAA,mBAAU,EAAC,OAAO,CAAC;qCAEyB,4BAAY;GAD5C,eAAe,CAkC3B"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Media = void 0;
|
|
13
|
+
const typeorm_1 = require("typeorm");
|
|
14
|
+
let Media = class Media {
|
|
15
|
+
};
|
|
16
|
+
exports.Media = Media;
|
|
17
|
+
__decorate([
|
|
18
|
+
(0, typeorm_1.PrimaryGeneratedColumn)("uuid"),
|
|
19
|
+
__metadata("design:type", String)
|
|
20
|
+
], Media.prototype, "id", void 0);
|
|
21
|
+
__decorate([
|
|
22
|
+
(0, typeorm_1.Column)(),
|
|
23
|
+
__metadata("design:type", String)
|
|
24
|
+
], Media.prototype, "filename", void 0);
|
|
25
|
+
__decorate([
|
|
26
|
+
(0, typeorm_1.Column)(),
|
|
27
|
+
__metadata("design:type", String)
|
|
28
|
+
], Media.prototype, "originalName", void 0);
|
|
29
|
+
__decorate([
|
|
30
|
+
(0, typeorm_1.Column)(),
|
|
31
|
+
__metadata("design:type", String)
|
|
32
|
+
], Media.prototype, "mimeType", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, typeorm_1.Column)(),
|
|
35
|
+
__metadata("design:type", Number)
|
|
36
|
+
], Media.prototype, "size", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
(0, typeorm_1.Column)(),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], Media.prototype, "path", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], Media.prototype, "url", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
(0, typeorm_1.Column)({ type: "json", nullable: true }),
|
|
47
|
+
__metadata("design:type", Object)
|
|
48
|
+
], Media.prototype, "conversions", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
51
|
+
__metadata("design:type", String)
|
|
52
|
+
], Media.prototype, "disk", void 0);
|
|
53
|
+
__decorate([
|
|
54
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
55
|
+
__metadata("design:type", Date)
|
|
56
|
+
], Media.prototype, "createdAt", void 0);
|
|
57
|
+
exports.Media = Media = __decorate([
|
|
58
|
+
(0, typeorm_1.Entity)("media")
|
|
59
|
+
], Media);
|
|
60
|
+
//# sourceMappingURL=media.entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.entity.js","sourceRoot":"","sources":["../../src/entities/media.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAKiB;AAGV,IAAM,KAAK,GAAX,MAAM,KAAK;CA8BjB,CAAA;AA9BY,sBAAK;AAEhB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;iCACpB;AAGX;IADC,IAAA,gBAAM,GAAE;;uCACQ;AAGjB;IADC,IAAA,gBAAM,GAAE;;2CACY;AAGrB;IADC,IAAA,gBAAM,GAAE;;uCACQ;AAGjB;IADC,IAAA,gBAAM,GAAE;;mCACI;AAGb;IADC,IAAA,gBAAM,GAAE;;mCACI;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kCACf;AAGZ;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;0CACL;AAGpC;IADC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mCACd;AAGb;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;wCAAC;gBA7BL,KAAK;IADjB,IAAA,gBAAM,EAAC,OAAO,CAAC;GACH,KAAK,CA8BjB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./media-library.module";
|
|
2
|
+
export * from "./entities/media.entity";
|
|
3
|
+
export * from "./services/media.service";
|
|
4
|
+
export * from "./services/s3.service";
|
|
5
|
+
export * from "./services/image.service";
|
|
6
|
+
export * from "./controllers/media.controller";
|
|
7
|
+
export * from "./interfaces/media-config.interface";
|
|
8
|
+
export * from "./migrations/1703000000000-CreateMediaTable";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./media-library.module"), exports);
|
|
18
|
+
__exportStar(require("./entities/media.entity"), exports);
|
|
19
|
+
__exportStar(require("./services/media.service"), exports);
|
|
20
|
+
__exportStar(require("./services/s3.service"), exports);
|
|
21
|
+
__exportStar(require("./services/image.service"), exports);
|
|
22
|
+
__exportStar(require("./controllers/media.controller"), exports);
|
|
23
|
+
__exportStar(require("./interfaces/media-config.interface"), exports);
|
|
24
|
+
__exportStar(require("./migrations/1703000000000-CreateMediaTable"), exports);
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,0DAAwC;AACxC,2DAAyC;AACzC,wDAAsC;AACtC,2DAAyC;AACzC,iEAA+C;AAC/C,sEAAoD;AACpD,8EAA4D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ConversionConfig {
|
|
2
|
+
suffix: string;
|
|
3
|
+
width: number;
|
|
4
|
+
height?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface S3Config {
|
|
7
|
+
region: string;
|
|
8
|
+
bucket: string;
|
|
9
|
+
accessKeyId: string;
|
|
10
|
+
secretAccessKey: string;
|
|
11
|
+
publicUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface MediaLibraryConfig {
|
|
14
|
+
disk?: "local" | "s3";
|
|
15
|
+
uploadPath?: string;
|
|
16
|
+
conversions?: ConversionConfig[];
|
|
17
|
+
s3?: S3Config;
|
|
18
|
+
maxFileSize?: number;
|
|
19
|
+
allowedMimeTypes?: string[];
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-config.interface.js","sourceRoot":"","sources":["../../src/interfaces/media-config.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var MediaLibraryModule_1;
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.MediaLibraryModule = void 0;
|
|
44
|
+
const common_1 = require("@nestjs/common");
|
|
45
|
+
const typeorm_1 = require("@nestjs/typeorm");
|
|
46
|
+
const platform_express_1 = require("@nestjs/platform-express");
|
|
47
|
+
const media_entity_1 = require("./entities/media.entity");
|
|
48
|
+
const media_service_1 = require("./services/media.service");
|
|
49
|
+
const s3_service_1 = require("./services/s3.service");
|
|
50
|
+
const image_service_1 = require("./services/image.service");
|
|
51
|
+
const media_controller_1 = require("./controllers/media.controller");
|
|
52
|
+
const multer = __importStar(require("multer"));
|
|
53
|
+
let MediaLibraryModule = MediaLibraryModule_1 = class MediaLibraryModule {
|
|
54
|
+
static forRoot(config) {
|
|
55
|
+
return {
|
|
56
|
+
module: MediaLibraryModule_1,
|
|
57
|
+
imports: [
|
|
58
|
+
typeorm_1.TypeOrmModule.forFeature([media_entity_1.Media]),
|
|
59
|
+
platform_express_1.MulterModule.register({
|
|
60
|
+
storage: multer.memoryStorage(),
|
|
61
|
+
limits: {
|
|
62
|
+
fileSize: config.maxFileSize || 10 * 1024 * 1024,
|
|
63
|
+
},
|
|
64
|
+
fileFilter: (req, file, cb) => {
|
|
65
|
+
if (config.allowedMimeTypes && config.allowedMimeTypes.length > 0) {
|
|
66
|
+
if (config.allowedMimeTypes.includes(file.mimetype)) {
|
|
67
|
+
cb(null, true);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
cb(new Error("Invalid file type"), false);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
cb(null, true);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
],
|
|
79
|
+
controllers: [media_controller_1.MediaController],
|
|
80
|
+
providers: [
|
|
81
|
+
{
|
|
82
|
+
provide: "MEDIA_CONFIG",
|
|
83
|
+
useValue: config,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
provide: "S3_CONFIG",
|
|
87
|
+
useValue: config.s3,
|
|
88
|
+
},
|
|
89
|
+
media_service_1.MediaService,
|
|
90
|
+
s3_service_1.S3Service,
|
|
91
|
+
image_service_1.ImageService,
|
|
92
|
+
],
|
|
93
|
+
exports: [media_service_1.MediaService, s3_service_1.S3Service, image_service_1.ImageService],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
exports.MediaLibraryModule = MediaLibraryModule;
|
|
98
|
+
exports.MediaLibraryModule = MediaLibraryModule = MediaLibraryModule_1 = __decorate([
|
|
99
|
+
(0, common_1.Global)(),
|
|
100
|
+
(0, common_1.Module)({})
|
|
101
|
+
], MediaLibraryModule);
|
|
102
|
+
//# sourceMappingURL=media-library.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-library.module.js","sourceRoot":"","sources":["../src/media-library.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA+D;AAC/D,6CAAgD;AAChD,+DAAwD;AACxD,0DAAgD;AAChD,4DAAwD;AACxD,sDAAkD;AAClD,4DAAwD;AACxD,qEAAiE;AAEjE,+CAAiC;AAI1B,IAAM,kBAAkB,0BAAxB,MAAM,kBAAkB;IAC7B,MAAM,CAAC,OAAO,CAAC,MAA0B;QACvC,OAAO;YACL,MAAM,EAAE,oBAAkB;YAC1B,OAAO,EAAE;gBACP,uBAAa,CAAC,UAAU,CAAC,CAAC,oBAAK,CAAC,CAAC;gBACjC,+BAAY,CAAC,QAAQ,CAAC;oBACpB,OAAO,EAAE,MAAM,CAAC,aAAa,EAAE;oBAC/B,MAAM,EAAE;wBACN,QAAQ,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI;qBACjD;oBACD,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;wBAC5B,IAAI,MAAM,CAAC,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAClE,IAAI,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gCACpD,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;4BACjB,CAAC;iCAAM,CAAC;gCACN,EAAE,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC,CAAC;4BAC5C,CAAC;wBACH,CAAC;6BAAM,CAAC;4BACN,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;wBACjB,CAAC;oBACH,CAAC;iBACF,CAAC;aACH;YACD,WAAW,EAAE,CAAC,kCAAe,CAAC;YAC9B,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,cAAc;oBACvB,QAAQ,EAAE,MAAM;iBACjB;gBACD;oBACE,OAAO,EAAE,WAAW;oBACpB,QAAQ,EAAE,MAAM,CAAC,EAAE;iBACpB;gBACD,4BAAY;gBACZ,sBAAS;gBACT,4BAAY;aACb;YACD,OAAO,EAAE,CAAC,4BAAY,EAAE,sBAAS,EAAE,4BAAY,CAAC;SACjD,CAAC;IACJ,CAAC;CACF,CAAA;AAzCY,gDAAkB;6BAAlB,kBAAkB;IAF9B,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,kBAAkB,CAyC9B"}
|