@lenne.tech/nest-server 11.7.3 → 11.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.env.js +3 -0
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +35 -0
- package/dist/core/modules/auth/guards/roles.guard.js +4 -3
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/auth/services/core-auth.service.js +5 -4
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/error-code/core-error-code.controller.d.ts +7 -0
- package/dist/core/modules/error-code/core-error-code.controller.js +45 -0
- package/dist/core/modules/error-code/core-error-code.controller.js.map +1 -0
- package/dist/core/modules/error-code/core-error-code.service.d.ts +16 -0
- package/dist/core/modules/error-code/core-error-code.service.js +65 -0
- package/dist/core/modules/error-code/core-error-code.service.js.map +1 -0
- package/dist/core/modules/error-code/error-code.module.d.ts +7 -0
- package/dist/core/modules/error-code/error-code.module.js +64 -0
- package/dist/core/modules/error-code/error-code.module.js.map +1 -0
- package/dist/core/modules/error-code/error-codes.d.ts +219 -0
- package/dist/core/modules/error-code/error-codes.js +204 -0
- package/dist/core/modules/error-code/error-codes.js.map +1 -0
- package/dist/core/modules/error-code/index.d.ts +5 -0
- package/dist/core/modules/error-code/index.js +22 -0
- package/dist/core/modules/error-code/index.js.map +1 -0
- package/dist/core/modules/error-code/interfaces/error-code.interfaces.d.ts +12 -0
- package/dist/core/modules/error-code/interfaces/error-code.interfaces.js +3 -0
- package/dist/core/modules/error-code/interfaces/error-code.interfaces.js.map +1 -0
- package/dist/core/modules/file/core-file.controller.d.ts +1 -0
- package/dist/core/modules/file/core-file.controller.js +22 -0
- package/dist/core/modules/file/core-file.controller.js.map +1 -1
- package/dist/core/modules/tus/core-tus.controller.d.ts +9 -0
- package/dist/core/modules/tus/core-tus.controller.js +85 -0
- package/dist/core/modules/tus/core-tus.controller.js.map +1 -0
- package/dist/core/modules/tus/core-tus.service.d.ts +30 -0
- package/dist/core/modules/tus/core-tus.service.js +284 -0
- package/dist/core/modules/tus/core-tus.service.js.map +1 -0
- package/dist/core/modules/tus/index.d.ts +4 -0
- package/dist/core/modules/tus/index.js +21 -0
- package/dist/core/modules/tus/index.js.map +1 -0
- package/dist/core/modules/tus/interfaces/tus-config.interface.d.ts +10 -0
- package/dist/core/modules/tus/interfaces/tus-config.interface.js +59 -0
- package/dist/core/modules/tus/interfaces/tus-config.interface.js.map +1 -0
- package/dist/core/modules/tus/tus.module.d.ts +21 -0
- package/dist/core/modules/tus/tus.module.js +99 -0
- package/dist/core/modules/tus/tus.module.js.map +1 -0
- package/dist/core.module.js +8 -0
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/error-code/error-code.controller.d.ts +8 -0
- package/dist/server/modules/error-code/error-code.controller.js +55 -0
- package/dist/server/modules/error-code/error-code.controller.js.map +1 -0
- package/dist/server/modules/error-code/error-code.service.d.ts +4 -0
- package/dist/server/modules/error-code/error-code.service.js +27 -0
- package/dist/server/modules/error-code/error-code.service.js.map +1 -0
- package/dist/server/modules/error-code/error-codes.d.ts +45 -0
- package/dist/server/modules/error-code/error-codes.js +24 -0
- package/dist/server/modules/error-code/error-codes.js.map +1 -0
- package/dist/server/modules/error-code/index.d.ts +3 -0
- package/dist/server/modules/error-code/index.js +20 -0
- package/dist/server/modules/error-code/index.js.map +1 -0
- package/dist/server/modules/file/file.controller.d.ts +5 -7
- package/dist/server/modules/file/file.controller.js +3 -31
- package/dist/server/modules/file/file.controller.js.map +1 -1
- package/dist/server/server.module.js +10 -1
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +5 -2
- package/src/config.env.ts +4 -0
- package/src/core/common/interfaces/server-options.interface.ts +243 -0
- package/src/core/modules/auth/guards/roles.guard.ts +5 -4
- package/src/core/modules/auth/services/core-auth.service.ts +5 -4
- package/src/core/modules/error-code/INTEGRATION-CHECKLIST.md +288 -0
- package/src/core/modules/error-code/core-error-code.controller.ts +54 -0
- package/src/core/modules/error-code/core-error-code.service.ts +135 -0
- package/src/core/modules/error-code/error-code.module.ts +119 -0
- package/src/core/modules/error-code/error-codes.ts +405 -0
- package/src/core/modules/error-code/index.ts +14 -0
- package/src/core/modules/error-code/interfaces/error-code.interfaces.ts +99 -0
- package/src/core/modules/file/README.md +165 -0
- package/src/core/modules/file/core-file.controller.ts +27 -1
- package/src/core/modules/tus/INTEGRATION-CHECKLIST.md +176 -0
- package/src/core/modules/tus/README.md +439 -0
- package/src/core/modules/tus/core-tus.controller.ts +88 -0
- package/src/core/modules/tus/core-tus.service.ts +424 -0
- package/src/core/modules/tus/index.ts +5 -0
- package/src/core/modules/tus/interfaces/tus-config.interface.ts +107 -0
- package/src/core/modules/tus/tus.module.ts +187 -0
- package/src/core.module.ts +16 -0
- package/src/index.ts +12 -0
- package/src/server/modules/error-code/README.md +131 -0
- package/src/server/modules/error-code/error-code.controller.ts +91 -0
- package/src/server/modules/error-code/error-code.service.ts +42 -0
- package/src/server/modules/error-code/error-codes.ts +65 -0
- package/src/server/modules/error-code/index.ts +8 -0
- package/src/server/modules/file/file.controller.ts +14 -34
- package/src/server/server.module.ts +15 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Controller
|
|
2
|
+
export * from './core-error-code.controller';
|
|
3
|
+
|
|
4
|
+
// Service
|
|
5
|
+
export * from './core-error-code.service';
|
|
6
|
+
|
|
7
|
+
// Module
|
|
8
|
+
export * from './error-code.module';
|
|
9
|
+
|
|
10
|
+
// Error Codes
|
|
11
|
+
export * from './error-codes';
|
|
12
|
+
|
|
13
|
+
// Interfaces
|
|
14
|
+
export * from './interfaces/error-code.interfaces';
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { CoreErrorCodeService } from '../core-error-code.service';
|
|
4
|
+
import { IErrorRegistry } from '../error-codes';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration for the error code module
|
|
8
|
+
*/
|
|
9
|
+
export interface IErrorCodeModuleConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Additional error registry to merge with core errors
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const ProjectErrors = {
|
|
16
|
+
* ORDER_NOT_FOUND: {
|
|
17
|
+
* code: 'PROJ_0001',
|
|
18
|
+
* message: 'Order not found',
|
|
19
|
+
* translations: { de: 'Bestellung nicht gefunden.', en: 'Order not found.' }
|
|
20
|
+
* }
|
|
21
|
+
* } as const satisfies IErrorRegistry;
|
|
22
|
+
*
|
|
23
|
+
* ErrorCodeModule.forRoot({ additionalErrorRegistry: ProjectErrors })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
additionalErrorRegistry?: IErrorRegistry;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Custom controller class to use instead of CoreErrorCodeController.
|
|
30
|
+
*
|
|
31
|
+
* **Note:** Use a standalone controller (not extending CoreErrorCodeController)
|
|
32
|
+
* to ensure correct route registration order when adding new routes.
|
|
33
|
+
* NestJS registers parent routes first, which can cause parameterized routes
|
|
34
|
+
* to intercept static routes.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Standalone controller (RECOMMENDED)
|
|
39
|
+
* @Controller('api/i18n/errors')
|
|
40
|
+
* export class ErrorCodeController {
|
|
41
|
+
* constructor(protected readonly errorCodeService: ErrorCodeService) {}
|
|
42
|
+
*
|
|
43
|
+
* @Get('codes') // Must be defined BEFORE :locale
|
|
44
|
+
* @Roles(RoleEnum.S_EVERYONE)
|
|
45
|
+
* getAllCodes(): string[] {
|
|
46
|
+
* return this.errorCodeService.getErrorCodes();
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* @Get(':locale')
|
|
50
|
+
* @Roles(RoleEnum.S_EVERYONE)
|
|
51
|
+
* getTranslations(@Param('locale') locale: string) { ... }
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* // In your module
|
|
55
|
+
* ErrorCodeModule.forRoot({
|
|
56
|
+
* controller: ErrorCodeController,
|
|
57
|
+
* service: ErrorCodeService,
|
|
58
|
+
* })
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
controller?: Type<any>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Custom service class to use instead of CoreErrorCodeService.
|
|
65
|
+
* The class must extend CoreErrorCodeService.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* // Your custom service with additional locales
|
|
70
|
+
* @Injectable()
|
|
71
|
+
* export class ErrorCodeService extends CoreErrorCodeService {
|
|
72
|
+
* protected override supportedLocales: SupportedLocale[] = ['de', 'en', 'fr', 'es'];
|
|
73
|
+
*
|
|
74
|
+
* constructor() {
|
|
75
|
+
* super();
|
|
76
|
+
* this.registerErrorRegistry(ProjectErrors);
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* // In your module
|
|
81
|
+
* ErrorCodeModule.forRoot({
|
|
82
|
+
* service: ErrorCodeService,
|
|
83
|
+
* })
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
service?: Type<CoreErrorCodeService>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Response format for the translation endpoint
|
|
91
|
+
*/
|
|
92
|
+
export interface IErrorTranslationResponse {
|
|
93
|
+
errors: Record<string, string>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Supported locales for error translations
|
|
98
|
+
*/
|
|
99
|
+
export type SupportedLocale = 'de' | 'en';
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# File Module
|
|
2
|
+
|
|
3
|
+
File upload and download functionality with MongoDB GridFS storage.
|
|
4
|
+
|
|
5
|
+
## Endpoints
|
|
6
|
+
|
|
7
|
+
### Public Endpoints (via CoreFileController)
|
|
8
|
+
|
|
9
|
+
| Method | Endpoint | Description |
|
|
10
|
+
|--------|----------|-------------|
|
|
11
|
+
| GET | `/files/id/:id` | Download file by ID |
|
|
12
|
+
| GET | `/files/:filename` | Download file by filename |
|
|
13
|
+
|
|
14
|
+
**Note:** These endpoints are public (`S_EVERYONE`) by default. Projects can restrict access by extending `CoreFileController`.
|
|
15
|
+
|
|
16
|
+
### Admin Endpoints (project-specific)
|
|
17
|
+
|
|
18
|
+
Projects typically add admin-only endpoints like:
|
|
19
|
+
|
|
20
|
+
| Method | Endpoint | Description |
|
|
21
|
+
|--------|----------|-------------|
|
|
22
|
+
| POST | `/files/upload` | Upload file (multipart/form-data) |
|
|
23
|
+
| GET | `/files/info/:id` | Get file metadata |
|
|
24
|
+
| DELETE | `/files/:id` | Delete file |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Usage in Projects
|
|
29
|
+
|
|
30
|
+
### Basic Setup (Extend CoreFileController)
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// src/server/modules/file/file.controller.ts
|
|
34
|
+
import { Controller } from '@nestjs/common';
|
|
35
|
+
import { CoreFileController, Roles, RoleEnum } from '@lenne.tech/nest-server';
|
|
36
|
+
import { FileService } from './file.service';
|
|
37
|
+
|
|
38
|
+
@Controller('files')
|
|
39
|
+
@Roles(RoleEnum.ADMIN)
|
|
40
|
+
export class FileController extends CoreFileController {
|
|
41
|
+
constructor(protected override readonly fileService: FileService) {
|
|
42
|
+
super(fileService);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Add admin-only endpoints here (upload, delete, etc.)
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Restrict Download Access
|
|
50
|
+
|
|
51
|
+
To require authentication for downloads, override the inherited methods:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
@Controller('files')
|
|
55
|
+
@Roles(RoleEnum.ADMIN)
|
|
56
|
+
export class FileController extends CoreFileController {
|
|
57
|
+
constructor(protected override readonly fileService: FileService) {
|
|
58
|
+
super(fileService);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Override to require authentication for ID-based download
|
|
62
|
+
@Get('id/:id')
|
|
63
|
+
@Roles(RoleEnum.S_USER) // Require logged-in user
|
|
64
|
+
override async getFileById(@Param('id') id: string, @Res() res: Response) {
|
|
65
|
+
return super.getFileById(id, res);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Override to require authentication for filename-based download
|
|
69
|
+
@Get(':filename')
|
|
70
|
+
@Roles(RoleEnum.S_USER)
|
|
71
|
+
override async getFile(@Param('filename') filename: string, @Res() res: Response) {
|
|
72
|
+
return super.getFile(filename, res);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## GraphQL Support
|
|
80
|
+
|
|
81
|
+
File operations are also available via GraphQL through `CoreFileResolver`:
|
|
82
|
+
|
|
83
|
+
```graphql
|
|
84
|
+
# Query file by ID
|
|
85
|
+
query {
|
|
86
|
+
file(id: "...") {
|
|
87
|
+
id
|
|
88
|
+
filename
|
|
89
|
+
contentType
|
|
90
|
+
length
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Query file by filename
|
|
95
|
+
query {
|
|
96
|
+
fileByFilename(filename: "...") {
|
|
97
|
+
id
|
|
98
|
+
filename
|
|
99
|
+
contentType
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Upload file (via GraphQL Upload scalar)
|
|
104
|
+
mutation {
|
|
105
|
+
uploadFile(file: Upload!) {
|
|
106
|
+
id
|
|
107
|
+
filename
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Delete file
|
|
112
|
+
mutation {
|
|
113
|
+
deleteFile(filename: "...") {
|
|
114
|
+
id
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Integration with TUS
|
|
122
|
+
|
|
123
|
+
Files uploaded via TUS are automatically stored in GridFS and can be accessed through the same endpoints:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# After TUS upload completes, download by ID
|
|
127
|
+
GET /files/id/<gridfs-file-id>
|
|
128
|
+
|
|
129
|
+
# Or by filename (if unique)
|
|
130
|
+
GET /files/<original-filename>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Recommendation:** Use ID-based downloads for TUS uploads as filenames may not be unique.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## GridFS Storage
|
|
138
|
+
|
|
139
|
+
Files are stored in MongoDB GridFS with the following structure:
|
|
140
|
+
|
|
141
|
+
**fs.files collection:**
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"_id": ObjectId,
|
|
145
|
+
"filename": "example.pdf",
|
|
146
|
+
"length": 1048576,
|
|
147
|
+
"uploadDate": ISODate,
|
|
148
|
+
"metadata": {
|
|
149
|
+
"contentType": "application/pdf",
|
|
150
|
+
"tusUploadId": "...", // If uploaded via TUS
|
|
151
|
+
"uploadedAt": ISODate
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**fs.chunks collection:**
|
|
157
|
+
- Binary file data split into 255KB chunks
|
|
158
|
+
- Automatically managed by GridFS
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Related Documentation
|
|
163
|
+
|
|
164
|
+
- [TUS Module](../tus/README.md) - Resumable upload protocol
|
|
165
|
+
- [CoreFileService](./core-file.service.ts) - File service implementation
|
|
@@ -17,7 +17,33 @@ export abstract class CoreFileController {
|
|
|
17
17
|
protected constructor(protected fileService: CoreFileService) {}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Download file
|
|
20
|
+
* Download file by ID
|
|
21
|
+
*
|
|
22
|
+
* More reliable than filename-based download as IDs are unique.
|
|
23
|
+
* Recommended for TUS uploads and when filename uniqueness cannot be guaranteed.
|
|
24
|
+
*/
|
|
25
|
+
@Get('id/:id')
|
|
26
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
27
|
+
async getFileById(@Param('id') id: string, @Res() res: Response) {
|
|
28
|
+
if (!id) {
|
|
29
|
+
throw new BadRequestException('Missing file ID for download');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const file = await this.fileService.getFileInfo(id);
|
|
33
|
+
if (!file) {
|
|
34
|
+
throw new NotFoundException('File not found');
|
|
35
|
+
}
|
|
36
|
+
const filestream = await this.fileService.getFileStream(id);
|
|
37
|
+
res.header('Content-Type', file.contentType || 'application/octet-stream');
|
|
38
|
+
res.header('Content-Disposition', `attachment; filename=${file.filename}`);
|
|
39
|
+
return filestream.pipe(res);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Download file by filename
|
|
44
|
+
*
|
|
45
|
+
* Note: If multiple files have the same filename, only the first match is returned.
|
|
46
|
+
* For unique file access, use GET /files/id/:id instead.
|
|
21
47
|
*/
|
|
22
48
|
@Get(':filename')
|
|
23
49
|
@Roles(RoleEnum.S_EVERYONE)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# TUS Integration Checklist
|
|
2
|
+
|
|
3
|
+
**For customizing TUS uploads in projects using `@lenne.tech/nest-server`.**
|
|
4
|
+
|
|
5
|
+
> **Note:** TUS is **enabled by default** with no configuration needed. This checklist is only for projects that need to customize behavior (e.g., require authentication).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Do You Need This Checklist?
|
|
10
|
+
|
|
11
|
+
| Scenario | Checklist Needed? |
|
|
12
|
+
|----------|-------------------|
|
|
13
|
+
| Use TUS with defaults (everyone can upload) | No - works automatically |
|
|
14
|
+
| Require authentication for uploads | Yes - Step 1 |
|
|
15
|
+
| Custom upload handling (notifications, etc.) | Yes - Step 2 |
|
|
16
|
+
| Disable TUS completely | No - just use `TusModule.forRoot({ config: false })` |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Reference Implementation
|
|
21
|
+
|
|
22
|
+
**Local (in your node_modules):**
|
|
23
|
+
```
|
|
24
|
+
node_modules/@lenne.tech/nest-server/src/server/server.module.ts
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**GitHub:**
|
|
28
|
+
https://github.com/lenneTech/nest-server/tree/develop/src/server
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Step 1: Custom Controller (Require Authentication)
|
|
33
|
+
|
|
34
|
+
**Create:** `src/server/modules/tus/tus.controller.ts`
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { Controller } from '@nestjs/common';
|
|
38
|
+
import { CoreTusController, Roles, RoleEnum } from '@lenne.tech/nest-server';
|
|
39
|
+
|
|
40
|
+
@Controller('tus')
|
|
41
|
+
@Roles(RoleEnum.S_USER) // Require authenticated user
|
|
42
|
+
export class TusController extends CoreTusController {
|
|
43
|
+
// All methods inherit the S_USER requirement
|
|
44
|
+
// Override methods here for custom logic
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Update ServerModule:**
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// src/server/server.module.ts
|
|
52
|
+
import { TusModule } from '@lenne.tech/nest-server';
|
|
53
|
+
import { TusController } from './modules/tus/tus.controller';
|
|
54
|
+
|
|
55
|
+
@Module({
|
|
56
|
+
imports: [
|
|
57
|
+
// ... other imports
|
|
58
|
+
TusModule.forRoot({
|
|
59
|
+
controller: TusController, // Use custom controller
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
})
|
|
63
|
+
export class ServerModule {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Step 2: Custom Service (Custom Upload Handling)
|
|
69
|
+
|
|
70
|
+
**Create:** `src/server/modules/tus/tus.service.ts`
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { Injectable } from '@nestjs/common';
|
|
74
|
+
import { CoreTusService } from '@lenne.tech/nest-server';
|
|
75
|
+
import { Upload } from '@tus/server';
|
|
76
|
+
|
|
77
|
+
@Injectable()
|
|
78
|
+
export class TusService extends CoreTusService {
|
|
79
|
+
protected override async onUploadComplete(upload: Upload): Promise<void> {
|
|
80
|
+
// Call parent to handle GridFS migration
|
|
81
|
+
await super.onUploadComplete(upload);
|
|
82
|
+
|
|
83
|
+
// Add custom logic
|
|
84
|
+
const metadata = upload.metadata;
|
|
85
|
+
console.log(`Upload complete: ${metadata.filename}`);
|
|
86
|
+
// await this.notificationService.sendUploadComplete(...);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Note:** To use a custom service, you'll need to create a custom TusModule that provides your service instead of CoreTusService.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Configuration Options
|
|
96
|
+
|
|
97
|
+
### Default Configuration (No Changes Needed)
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// TUS works with these defaults:
|
|
101
|
+
{
|
|
102
|
+
enabled: true,
|
|
103
|
+
path: '/tus',
|
|
104
|
+
maxSize: 50 * 1024 * 1024 * 1024, // 50 GB
|
|
105
|
+
expiration: { expiresIn: '24h' },
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Custom Configuration
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// server.module.ts
|
|
113
|
+
TusModule.forRoot({
|
|
114
|
+
config: {
|
|
115
|
+
maxSize: 100 * 1024 * 1024, // 100 MB
|
|
116
|
+
path: '/uploads',
|
|
117
|
+
expiration: { expiresIn: '12h' },
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Disable TUS
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
TusModule.forRoot({ config: false })
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Verification Checklist
|
|
131
|
+
|
|
132
|
+
- [ ] `npm run build` succeeds
|
|
133
|
+
- [ ] `npm test` passes
|
|
134
|
+
- [ ] `OPTIONS /tus` returns TUS capabilities
|
|
135
|
+
- [ ] Upload via tus-js-client works
|
|
136
|
+
- [ ] File appears in GridFS after upload completion
|
|
137
|
+
- [ ] (If customized) Authentication is required for uploads
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Common Mistakes
|
|
142
|
+
|
|
143
|
+
| Mistake | Symptom | Fix |
|
|
144
|
+
|---------|---------|-----|
|
|
145
|
+
| Forgot to register custom controller | Default S_EVERYONE permissions | Add `controller: TusController` to forRoot() |
|
|
146
|
+
| Custom controller missing @Roles | No authentication required | Add `@Roles(RoleEnum.S_USER)` to controller class |
|
|
147
|
+
| Using wrong endpoint path | 404 on upload | Ensure client uses same path as config |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Client Configuration
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { Upload } from 'tus-js-client';
|
|
155
|
+
|
|
156
|
+
const upload = new Upload(file, {
|
|
157
|
+
endpoint: 'http://localhost:3000/tus',
|
|
158
|
+
headers: {
|
|
159
|
+
Authorization: `Bearer ${token}`, // If authentication required
|
|
160
|
+
},
|
|
161
|
+
metadata: {
|
|
162
|
+
filename: file.name,
|
|
163
|
+
filetype: file.type,
|
|
164
|
+
},
|
|
165
|
+
onSuccess: () => console.log('Upload complete!'),
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
upload.start();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Detailed Documentation
|
|
174
|
+
|
|
175
|
+
- **README.md:** `node_modules/@lenne.tech/nest-server/src/core/modules/tus/README.md`
|
|
176
|
+
- **GitHub:** https://github.com/lenneTech/nest-server/blob/develop/src/core/modules/tus/README.md
|