@lenne.tech/nest-server 11.7.3 → 11.8.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/core/common/interfaces/server-options.interface.d.ts +22 -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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- 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 +3 -1
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -1
- package/src/core/common/interfaces/server-options.interface.ts +154 -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/index.ts +6 -0
- package/src/server/modules/file/file.controller.ts +14 -34
- package/src/server/server.module.ts +5 -1
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# TUS Module
|
|
2
|
+
|
|
3
|
+
Integration of the [tus.io](https://tus.io) resumable upload protocol with @lenne.tech/nest-server via [@tus/server](https://github.com/tus/tus-node-server).
|
|
4
|
+
|
|
5
|
+
## TL;DR
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// TUS is ENABLED BY DEFAULT - no configuration needed!
|
|
9
|
+
// Just update to the latest @lenne.tech/nest-server version
|
|
10
|
+
|
|
11
|
+
// To customize:
|
|
12
|
+
TusModule.forRoot({
|
|
13
|
+
config: {
|
|
14
|
+
maxSize: 100 * 1024 * 1024, // 100 MB instead of 50 GB default
|
|
15
|
+
path: '/uploads', // Custom path instead of /tus
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
// To disable:
|
|
20
|
+
TusModule.forRoot({ config: false })
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Quick Links:** [Integration Checklist](./INTEGRATION-CHECKLIST.md) | [Endpoints](#endpoints) | [Configuration](#configuration) | [Client Usage](#client-usage)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Table of Contents
|
|
28
|
+
|
|
29
|
+
- [Features](#features)
|
|
30
|
+
- [Default Behavior](#default-behavior)
|
|
31
|
+
- [Endpoints](#endpoints)
|
|
32
|
+
- [Configuration](#configuration)
|
|
33
|
+
- [Client Usage](#client-usage)
|
|
34
|
+
- [Customization](#customization)
|
|
35
|
+
- [Integration with FileModule](#integration-with-filemodule)
|
|
36
|
+
- [Troubleshooting](#troubleshooting)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **Resumable Uploads** - Upload large files with automatic resume on connection loss
|
|
43
|
+
- **Enabled by Default** - Works out of the box without configuration
|
|
44
|
+
- **GridFS Integration** - Completed uploads are automatically migrated to GridFS
|
|
45
|
+
- **Module Inheritance Pattern** - Customize permissions via controller extension
|
|
46
|
+
- **All TUS Extensions** - Creation, termination, expiration, checksum, concatenation
|
|
47
|
+
|
|
48
|
+
### TUS Protocol Extensions (All Enabled by Default)
|
|
49
|
+
|
|
50
|
+
| Extension | Description |
|
|
51
|
+
|-----------|-------------|
|
|
52
|
+
| **creation** | Create new uploads via POST |
|
|
53
|
+
| **creation-with-upload** | Include data in creation request |
|
|
54
|
+
| **termination** | Delete incomplete uploads |
|
|
55
|
+
| **expiration** | Auto-cleanup of abandoned uploads |
|
|
56
|
+
| **checksum** | Verify data integrity |
|
|
57
|
+
| **concatenation** | Combine multiple uploads |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Default Behavior
|
|
62
|
+
|
|
63
|
+
TUS is **enabled by default** with the following configuration:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
{
|
|
67
|
+
enabled: true,
|
|
68
|
+
path: '/tus',
|
|
69
|
+
maxSize: 50 * 1024 * 1024 * 1024, // 50 GB
|
|
70
|
+
allowedTypes: undefined, // All types allowed
|
|
71
|
+
allowedHeaders: [], // Additional custom headers (TUS headers already included)
|
|
72
|
+
uploadDir: 'uploads/tus',
|
|
73
|
+
creation: true,
|
|
74
|
+
creationWithUpload: true,
|
|
75
|
+
termination: true,
|
|
76
|
+
expiration: { enabled: true, expiresIn: '24h' },
|
|
77
|
+
checksum: true,
|
|
78
|
+
concatenation: true,
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**No configuration required** - TUS works immediately after updating @lenne.tech/nest-server.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Endpoints
|
|
87
|
+
|
|
88
|
+
All endpoints are handled by the TUS protocol via `@tus/server`:
|
|
89
|
+
|
|
90
|
+
| Method | Endpoint | Description |
|
|
91
|
+
|--------|----------|-------------|
|
|
92
|
+
| OPTIONS | `/tus` | Get server capabilities |
|
|
93
|
+
| POST | `/tus` | Create new upload |
|
|
94
|
+
| HEAD | `/tus/:id` | Get upload status/offset |
|
|
95
|
+
| PATCH | `/tus/:id` | Continue upload |
|
|
96
|
+
| DELETE | `/tus/:id` | Terminate upload |
|
|
97
|
+
|
|
98
|
+
### CORS Headers
|
|
99
|
+
|
|
100
|
+
The TUS server automatically handles CORS headers for browser-based clients:
|
|
101
|
+
|
|
102
|
+
- `Tus-Resumable`
|
|
103
|
+
- `Tus-Version`
|
|
104
|
+
- `Tus-Extension`
|
|
105
|
+
- `Tus-Max-Size`
|
|
106
|
+
- `Upload-Length`
|
|
107
|
+
- `Upload-Offset`
|
|
108
|
+
- `Upload-Metadata`
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Configuration
|
|
113
|
+
|
|
114
|
+
### Disable TUS
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// In server.module.ts
|
|
118
|
+
TusModule.forRoot({ config: false })
|
|
119
|
+
|
|
120
|
+
// Or via environment config
|
|
121
|
+
tus: false
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Custom Configuration
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
TusModule.forRoot({
|
|
128
|
+
config: {
|
|
129
|
+
// Custom endpoint path
|
|
130
|
+
path: '/uploads',
|
|
131
|
+
|
|
132
|
+
// Limit file size (default: 50 GB)
|
|
133
|
+
maxSize: 100 * 1024 * 1024, // 100 MB
|
|
134
|
+
|
|
135
|
+
// Restrict allowed file types
|
|
136
|
+
allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
|
|
137
|
+
|
|
138
|
+
// Custom upload directory for temporary files
|
|
139
|
+
uploadDir: 'temp/uploads',
|
|
140
|
+
|
|
141
|
+
// Disable specific extensions
|
|
142
|
+
termination: false,
|
|
143
|
+
concatenation: false,
|
|
144
|
+
|
|
145
|
+
// Custom expiration
|
|
146
|
+
expiration: {
|
|
147
|
+
enabled: true,
|
|
148
|
+
expiresIn: '12h', // Cleanup after 12 hours
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Configuration Options
|
|
155
|
+
|
|
156
|
+
| Option | Type | Default | Description |
|
|
157
|
+
|--------|------|---------|-------------|
|
|
158
|
+
| `enabled` | boolean | `true` | Enable/disable TUS |
|
|
159
|
+
| `path` | string | `/tus` | Endpoint path |
|
|
160
|
+
| `maxSize` | number | 50 GB | Maximum file size in bytes |
|
|
161
|
+
| `allowedTypes` | string[] | undefined | Allowed MIME types (all if undefined) |
|
|
162
|
+
| `allowedHeaders` | string[] | `[]` | Additional custom headers (TUS headers already included) |
|
|
163
|
+
| `uploadDir` | string | `uploads/tus` | Temporary upload directory |
|
|
164
|
+
| `creation` | boolean | `true` | Enable creation extension |
|
|
165
|
+
| `creationWithUpload` | boolean | `true` | Enable creation-with-upload extension |
|
|
166
|
+
| `termination` | boolean | `true` | Enable termination extension |
|
|
167
|
+
| `expiration` | boolean \| object | `{ expiresIn: '24h' }` | Expiration configuration |
|
|
168
|
+
| `checksum` | boolean | `true` | Enable checksum extension |
|
|
169
|
+
| `concatenation` | boolean | `true` | Enable concatenation extension |
|
|
170
|
+
|
|
171
|
+
**Note on `allowedHeaders`:**
|
|
172
|
+
|
|
173
|
+
`@tus/server` already includes all TUS protocol headers by default:
|
|
174
|
+
- Authorization, Content-Type, Location, Tus-Extension, Tus-Max-Size
|
|
175
|
+
- Tus-Resumable, Tus-Version, Upload-Concat, Upload-Defer-Length
|
|
176
|
+
- Upload-Length, Upload-Metadata, Upload-Offset, X-HTTP-Method-Override
|
|
177
|
+
- X-Requested-With, X-Forwarded-Host, X-Forwarded-Proto, Forwarded
|
|
178
|
+
|
|
179
|
+
The `allowedHeaders` option is only for **project-specific custom headers**.
|
|
180
|
+
|
|
181
|
+
### Expiration Configuration
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Boolean shorthand
|
|
185
|
+
expiration: true // Enabled with 24h default
|
|
186
|
+
expiration: false // Disabled
|
|
187
|
+
|
|
188
|
+
// Object configuration
|
|
189
|
+
expiration: {
|
|
190
|
+
enabled: true,
|
|
191
|
+
expiresIn: '12h', // Supports: '24h', '1d', '30m', '3600s'
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Client Usage
|
|
198
|
+
|
|
199
|
+
### Using tus-js-client
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { Upload } from 'tus-js-client';
|
|
203
|
+
|
|
204
|
+
const file = document.querySelector('input[type=file]').files[0];
|
|
205
|
+
|
|
206
|
+
const upload = new Upload(file, {
|
|
207
|
+
endpoint: 'http://localhost:3000/tus',
|
|
208
|
+
retryDelays: [0, 3000, 5000, 10000, 20000],
|
|
209
|
+
metadata: {
|
|
210
|
+
filename: file.name,
|
|
211
|
+
filetype: file.type,
|
|
212
|
+
},
|
|
213
|
+
onError: (error) => {
|
|
214
|
+
console.log('Upload failed:', error);
|
|
215
|
+
},
|
|
216
|
+
onProgress: (bytesUploaded, bytesTotal) => {
|
|
217
|
+
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
|
|
218
|
+
console.log(`${percentage}%`);
|
|
219
|
+
},
|
|
220
|
+
onSuccess: () => {
|
|
221
|
+
console.log('Upload complete!');
|
|
222
|
+
console.log('File URL:', upload.url);
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Start or resume upload
|
|
227
|
+
upload.start();
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### With Authentication
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const upload = new Upload(file, {
|
|
234
|
+
endpoint: 'http://localhost:3000/tus',
|
|
235
|
+
headers: {
|
|
236
|
+
Authorization: `Bearer ${token}`,
|
|
237
|
+
},
|
|
238
|
+
// ... other options
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Resume Interrupted Upload
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// Store upload URL for resumption
|
|
246
|
+
localStorage.setItem('uploadUrl', upload.url);
|
|
247
|
+
|
|
248
|
+
// Later, resume with stored URL
|
|
249
|
+
const upload = new Upload(file, {
|
|
250
|
+
endpoint: 'http://localhost:3000/tus',
|
|
251
|
+
uploadUrl: localStorage.getItem('uploadUrl'),
|
|
252
|
+
// ... other options
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
upload.start(); // Resumes from where it left off
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Customization
|
|
261
|
+
|
|
262
|
+
### Require Authentication
|
|
263
|
+
|
|
264
|
+
By default, TUS allows everyone (`S_EVERYONE`) to upload. To require authentication, create a custom controller:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// src/server/modules/tus/tus.controller.ts
|
|
268
|
+
import { Controller } from '@nestjs/common';
|
|
269
|
+
import { CoreTusController, Roles, RoleEnum } from '@lenne.tech/nest-server';
|
|
270
|
+
|
|
271
|
+
@Controller('tus')
|
|
272
|
+
@Roles(RoleEnum.S_USER) // Require authenticated user
|
|
273
|
+
export class TusController extends CoreTusController {
|
|
274
|
+
// All methods inherit S_USER requirement
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Then register with custom controller:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
// server.module.ts
|
|
282
|
+
TusModule.forRoot({
|
|
283
|
+
controller: TusController,
|
|
284
|
+
})
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Custom Upload Handler
|
|
288
|
+
|
|
289
|
+
Override `onUploadComplete` to customize what happens after upload:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// src/server/modules/tus/tus.service.ts
|
|
293
|
+
import { Injectable } from '@nestjs/common';
|
|
294
|
+
import { CoreTusService } from '@lenne.tech/nest-server';
|
|
295
|
+
import { Upload } from '@tus/server';
|
|
296
|
+
|
|
297
|
+
@Injectable()
|
|
298
|
+
export class TusService extends CoreTusService {
|
|
299
|
+
protected override async onUploadComplete(upload: Upload): Promise<void> {
|
|
300
|
+
// Call parent to migrate to GridFS
|
|
301
|
+
await super.onUploadComplete(upload);
|
|
302
|
+
|
|
303
|
+
// Custom logic after upload
|
|
304
|
+
const metadata = upload.metadata;
|
|
305
|
+
await this.notificationService.sendUploadComplete(metadata.filename);
|
|
306
|
+
await this.analyticsService.trackUpload(upload.id, upload.size);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Integration with FileModule
|
|
314
|
+
|
|
315
|
+
After a TUS upload completes, the file is automatically:
|
|
316
|
+
|
|
317
|
+
1. **Migrated to GridFS** - The temporary file is uploaded to MongoDB GridFS
|
|
318
|
+
2. **Metadata preserved** - Filename, content type, and TUS metadata are stored
|
|
319
|
+
3. **Temporary file deleted** - The local temporary file is removed
|
|
320
|
+
|
|
321
|
+
### Accessing Uploaded Files
|
|
322
|
+
|
|
323
|
+
Use the existing FileModule to access uploaded files:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
# Via REST - by ID (recommended for TUS uploads)
|
|
327
|
+
GET /files/id/:id
|
|
328
|
+
|
|
329
|
+
# Via REST - by filename
|
|
330
|
+
GET /files/:filename
|
|
331
|
+
|
|
332
|
+
# Via GraphQL
|
|
333
|
+
query {
|
|
334
|
+
file(id: "...") {
|
|
335
|
+
id
|
|
336
|
+
filename
|
|
337
|
+
contentType
|
|
338
|
+
length
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Recommendation:** Use the ID-based endpoint (`/files/id/:id`) for TUS uploads as filenames may not be unique.
|
|
344
|
+
|
|
345
|
+
### File Metadata
|
|
346
|
+
|
|
347
|
+
The following metadata is stored with each GridFS file:
|
|
348
|
+
|
|
349
|
+
| Field | Source |
|
|
350
|
+
|-------|--------|
|
|
351
|
+
| `filename` | From TUS `Upload-Metadata` header |
|
|
352
|
+
| `contentType` | From TUS `filetype` metadata |
|
|
353
|
+
| `tusUploadId` | Original TUS upload ID |
|
|
354
|
+
| `originalMetadata` | All TUS metadata |
|
|
355
|
+
| `uploadedAt` | Completion timestamp |
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Troubleshooting
|
|
360
|
+
|
|
361
|
+
### Upload returns 503 "TUS uploads not available"
|
|
362
|
+
|
|
363
|
+
**Cause:** TUS server not initialized
|
|
364
|
+
|
|
365
|
+
**Solutions:**
|
|
366
|
+
1. Check if TUS is disabled in config (`tus: false`)
|
|
367
|
+
2. Verify MongoDB connection is established
|
|
368
|
+
3. Check server logs for initialization errors
|
|
369
|
+
|
|
370
|
+
### Upload stalls or fails to resume
|
|
371
|
+
|
|
372
|
+
**Cause:** Upload expired or server restarted
|
|
373
|
+
|
|
374
|
+
**Solutions:**
|
|
375
|
+
1. Check expiration configuration (default: 24h)
|
|
376
|
+
2. Increase `expiration.expiresIn` if needed
|
|
377
|
+
3. Client should handle `onError` and create new upload
|
|
378
|
+
|
|
379
|
+
### CORS errors in browser
|
|
380
|
+
|
|
381
|
+
**Cause:** Missing or incorrect CORS configuration
|
|
382
|
+
|
|
383
|
+
**Solutions:**
|
|
384
|
+
1. Verify client sends correct headers
|
|
385
|
+
2. Check that `Tus-Resumable` header is included
|
|
386
|
+
3. Ensure server CORS allows TUS headers
|
|
387
|
+
|
|
388
|
+
### File not appearing in GridFS after upload
|
|
389
|
+
|
|
390
|
+
**Cause:** Upload incomplete or migration failed
|
|
391
|
+
|
|
392
|
+
**Solutions:**
|
|
393
|
+
1. Verify upload completed (check `onSuccess` callback)
|
|
394
|
+
2. Check server logs for migration errors
|
|
395
|
+
3. Verify MongoDB GridFS bucket exists (`fs.files`, `fs.chunks`)
|
|
396
|
+
|
|
397
|
+
### Large uploads failing
|
|
398
|
+
|
|
399
|
+
**Cause:** File exceeds `maxSize` limit
|
|
400
|
+
|
|
401
|
+
**Solutions:**
|
|
402
|
+
1. Increase `maxSize` in configuration
|
|
403
|
+
2. Check for proxy/nginx upload limits
|
|
404
|
+
3. Verify client `chunkSize` is reasonable
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Technical Details
|
|
409
|
+
|
|
410
|
+
### Dependencies
|
|
411
|
+
|
|
412
|
+
- `@tus/server` ^2.3.0 - TUS protocol server implementation
|
|
413
|
+
- `@tus/file-store` ^2.0.0 - File system storage for uploads
|
|
414
|
+
|
|
415
|
+
### Upload Flow
|
|
416
|
+
|
|
417
|
+
```
|
|
418
|
+
1. Client: POST /tus (create upload)
|
|
419
|
+
2. Server: Returns Upload-Location header
|
|
420
|
+
3. Client: PATCH /tus/:id (send chunks)
|
|
421
|
+
4. Server: Returns Upload-Offset
|
|
422
|
+
5. Client: Repeat PATCH until complete
|
|
423
|
+
6. Server: Migrate to GridFS, cleanup temp file
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### File Storage
|
|
427
|
+
|
|
428
|
+
- **During upload:** Files stored in `uploadDir` (default: `uploads/tus`)
|
|
429
|
+
- **After completion:** Files migrated to MongoDB GridFS
|
|
430
|
+
- **Expiration:** Incomplete uploads cleaned up after `expiresIn` (default: 24h)
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Related Documentation
|
|
435
|
+
|
|
436
|
+
- [tus.io Protocol](https://tus.io/protocols/resumable-upload)
|
|
437
|
+
- [tus-js-client](https://github.com/tus/tus-js-client)
|
|
438
|
+
- [@tus/server](https://github.com/tus/tus-node-server)
|
|
439
|
+
- [FileModule Documentation](../file/README.md)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { All, Controller, Logger, Req, Res } from '@nestjs/common';
|
|
2
|
+
import { Request, Response } from 'express';
|
|
3
|
+
|
|
4
|
+
import { Roles } from '../../common/decorators/roles.decorator';
|
|
5
|
+
import { RoleEnum } from '../../common/enums/role.enum';
|
|
6
|
+
import { CoreTusService } from './core-tus.service';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Core TUS Controller
|
|
10
|
+
*
|
|
11
|
+
* Handles all TUS protocol requests and delegates to the @tus/server handler.
|
|
12
|
+
* This controller uses S_EVERYONE by default, allowing all users to upload.
|
|
13
|
+
*
|
|
14
|
+
* Projects can extend this controller to add authentication/authorization:
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* @Controller('tus')
|
|
19
|
+
* @Roles(RoleEnum.S_USER) // Require authentication
|
|
20
|
+
* export class TusController extends CoreTusController {
|
|
21
|
+
* // Customize as needed
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
@Controller('tus')
|
|
26
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
27
|
+
export class CoreTusController {
|
|
28
|
+
private readonly logger = new Logger(CoreTusController.name);
|
|
29
|
+
|
|
30
|
+
constructor(protected readonly tusService: CoreTusService) {}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Handle all TUS protocol requests
|
|
34
|
+
*
|
|
35
|
+
* The @tus/server handles:
|
|
36
|
+
* - OPTIONS: Return server capabilities
|
|
37
|
+
* - POST: Create new upload
|
|
38
|
+
* - HEAD: Get upload status/offset
|
|
39
|
+
* - PATCH: Continue upload
|
|
40
|
+
* - DELETE: Terminate upload (if termination extension enabled)
|
|
41
|
+
*/
|
|
42
|
+
@All()
|
|
43
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
44
|
+
async handleTus(@Req() req: Request, @Res() res: Response): Promise<void> {
|
|
45
|
+
const server = this.tusService.getServer();
|
|
46
|
+
|
|
47
|
+
if (!server) {
|
|
48
|
+
this.logger.warn('TUS server not initialized');
|
|
49
|
+
res.status(503).json({ message: 'TUS uploads not available' });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
await server.handle(req, res);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
this.logger.error(`TUS request error: ${error.message}`);
|
|
57
|
+
if (!res.headersSent) {
|
|
58
|
+
res.status(500).json({ message: 'Upload error' });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Handle requests with upload ID parameter
|
|
65
|
+
*
|
|
66
|
+
* Routes like /tus/:id for HEAD, PATCH, DELETE
|
|
67
|
+
*/
|
|
68
|
+
@All(':id')
|
|
69
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
70
|
+
async handleTusWithId(@Req() req: Request, @Res() res: Response): Promise<void> {
|
|
71
|
+
const server = this.tusService.getServer();
|
|
72
|
+
|
|
73
|
+
if (!server) {
|
|
74
|
+
this.logger.warn('TUS server not initialized');
|
|
75
|
+
res.status(503).json({ message: 'TUS uploads not available' });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
await server.handle(req, res);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
this.logger.error(`TUS request error for upload ${req.params.id}: ${error.message}`);
|
|
83
|
+
if (!res.headersSent) {
|
|
84
|
+
res.status(500).json({ message: 'Upload error' });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|