@flusys/nestjs-storage 9.1.2 → 9.2.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/README.md +13 -0
- package/controllers/file-manager.controller.d.ts +1 -0
- package/controllers/folder.controller.d.ts +1 -0
- package/controllers/storage-config.controller.d.ts +1 -0
- package/fesm/493.js +416 -251
- package/fesm/537.js +25 -21
- package/fesm/562.js +184 -172
- package/fesm/chunks/190.js +6 -6
- package/fesm/chunks/252.js +1 -1
- package/fesm/chunks/327.js +1 -1
- package/fesm/chunks/385.js +1 -1
- package/fesm/chunks/591.js +11 -11
- package/fesm/chunks/746.js +1 -1
- package/fesm/chunks/798.js +1 -1
- package/fesm/chunks/918.js +19 -7
- package/fesm/config/index.js +8 -8
- package/fesm/controllers/index.js +1 -1
- package/fesm/docs/index.js +11 -15
- package/fesm/dtos/index.js +24 -20
- package/fesm/entities/index.js +6 -6
- package/fesm/enums/index.js +4 -4
- package/fesm/index.js +30 -34
- package/fesm/interfaces/index.js +2 -2
- package/fesm/modules/index.js +1 -1
- package/fesm/providers/index.js +123 -129
- package/fesm/services/index.js +1 -1
- package/fesm/utils/index.js +88 -84
- package/middlewares/file-serve.middleware.d.ts +3 -1
- package/package.json +3 -3
- package/providers/local-provider.d.ts +2 -0
- package/providers/sftp-provider.optional.d.ts +1 -0
- package/providers/storage-factory.service.d.ts +4 -2
- package/services/file-manager.service.d.ts +5 -6
- package/services/folder.service.d.ts +5 -5
- package/services/storage-provider-config.service.d.ts +5 -2
- package/services/upload.service.d.ts +3 -1
- package/utils/company-ownership.util.d.ts +3 -0
- package/utils/file-validator.util.d.ts +1 -0
package/fesm/562.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as __rspack_external_sharp from "sharp";
|
|
2
|
-
import * as __rspack_external_path from "path";
|
|
3
2
|
import * as __rspack_external_uuid from "uuid";
|
|
4
3
|
import * as __rspack_external_fs from "fs";
|
|
5
4
|
import * as __rspack_external_mime_types_1e2a4730 from "mime-types";
|
|
@@ -7,7 +6,7 @@ import * as __rspack_external_fs_promises_e1851c9c from "fs/promises";
|
|
|
7
6
|
export const __rspack_esm_id = 562;
|
|
8
7
|
export const __rspack_esm_ids = [562];
|
|
9
8
|
export const __webpack_modules__ = {
|
|
10
|
-
|
|
9
|
+
5968(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
11
10
|
|
|
12
11
|
// EXPORTS
|
|
13
12
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -15,17 +14,17 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
15
14
|
});
|
|
16
15
|
|
|
17
16
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
18
|
-
var common_ = __webpack_require__(
|
|
17
|
+
var common_ = __webpack_require__(6157);
|
|
19
18
|
;// CONCATENATED MODULE: external "fs"
|
|
20
19
|
|
|
21
20
|
// EXTERNAL MODULE: external "path"
|
|
22
|
-
var external_path_ = __webpack_require__(
|
|
21
|
+
var external_path_ = __webpack_require__(2521);
|
|
23
22
|
;// CONCATENATED MODULE: external "mime-types"
|
|
24
23
|
|
|
25
24
|
// EXTERNAL MODULE: ./projects/nestjs-storage/src/config/message-keys.ts
|
|
26
|
-
var message_keys = __webpack_require__(
|
|
25
|
+
var message_keys = __webpack_require__(5450);
|
|
27
26
|
// EXTERNAL MODULE: ./projects/nestjs-storage/src/services/upload.service.ts + 1 modules
|
|
28
|
-
var upload_service = __webpack_require__(
|
|
27
|
+
var upload_service = __webpack_require__(5018);
|
|
29
28
|
;// CONCATENATED MODULE: ./projects/nestjs-storage/src/middlewares/file-serve.middleware.ts
|
|
30
29
|
function _ts_decorate(decorators, target, key, desc) {
|
|
31
30
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -65,6 +64,15 @@ function _ts_param(paramIndex, decorator) {
|
|
|
65
64
|
'application/json',
|
|
66
65
|
'application/xml'
|
|
67
66
|
];
|
|
67
|
+
/** Types a browser would run script from if rendered inline on the API origin */ const ACTIVE_CONTENT_TYPES = [
|
|
68
|
+
'text/html',
|
|
69
|
+
'application/xhtml+xml',
|
|
70
|
+
'image/svg+xml',
|
|
71
|
+
'text/xml',
|
|
72
|
+
'application/xml',
|
|
73
|
+
'text/javascript',
|
|
74
|
+
'application/javascript'
|
|
75
|
+
];
|
|
68
76
|
class FileServeMiddleware {
|
|
69
77
|
uploadService;
|
|
70
78
|
uploadDir = process.cwd();
|
|
@@ -107,27 +115,23 @@ class FileServeMiddleware {
|
|
|
107
115
|
}
|
|
108
116
|
return normalizedPath;
|
|
109
117
|
}
|
|
110
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* Resolve file path using multiple fallback strategies. Only files inside the local storage
|
|
120
|
+
* base directory are served - never the rest of the working directory (.env, sources, dist).
|
|
121
|
+
*/ async resolveFilePath(normalizedPath) {
|
|
111
122
|
// Strategy 1: Path relative to CWD (new format: key includes basePath)
|
|
112
|
-
|
|
123
|
+
const fullPath = (0,external_path_.join)(this.uploadDir, normalizedPath);
|
|
113
124
|
const resolvedPath = (0,external_path_.resolve)(fullPath);
|
|
114
125
|
// Prevent path traversal attacks (boundary-safe: avoids matching sibling dirs like uploadDir + '-evil')
|
|
115
|
-
if (
|
|
126
|
+
if (!this.isWithin(resolvedPath, this.uploadDir)) {
|
|
116
127
|
throw new common_.BadRequestException({
|
|
117
128
|
message: 'Invalid file path',
|
|
118
129
|
messageKey: message_keys/* .UPLOAD_MESSAGES.INVALID_FILE_PATH */.dS.INVALID_FILE_PATH
|
|
119
130
|
});
|
|
120
131
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Try fallback strategies with basePath
|
|
125
|
-
const basePath = await this.uploadService.getLocalStorageBasePath();
|
|
126
|
-
if (basePath) {
|
|
127
|
-
const fallbackPath = this.tryFallbackPaths(normalizedPath, basePath);
|
|
128
|
-
if (fallbackPath) {
|
|
129
|
-
return fallbackPath;
|
|
130
|
-
}
|
|
132
|
+
for (const basePath of (await this.uploadService.getLocalStorageBasePaths())){
|
|
133
|
+
const found = this.findInStorageRoot(normalizedPath, fullPath, basePath);
|
|
134
|
+
if (found) return found;
|
|
131
135
|
}
|
|
132
136
|
throw new common_.NotFoundException({
|
|
133
137
|
message: `File not found: ${normalizedPath}`,
|
|
@@ -137,20 +141,32 @@ class FileServeMiddleware {
|
|
|
137
141
|
}
|
|
138
142
|
});
|
|
139
143
|
}
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
+
findInStorageRoot(normalizedPath, fullPath, basePath) {
|
|
145
|
+
const storageRoot = (0,external_path_.resolve)(basePath);
|
|
146
|
+
// A base path at or above the working directory would expose the whole application
|
|
147
|
+
if (this.isWithin(this.uploadDir, storageRoot)) return null;
|
|
148
|
+
const candidates = [
|
|
149
|
+
fullPath,
|
|
150
|
+
...this.fallbackPaths(normalizedPath, basePath)
|
|
151
|
+
];
|
|
152
|
+
return candidates.find((candidate)=>this.isWithin((0,external_path_.resolve)(candidate), storageRoot) && (0,__rspack_external_fs.existsSync)(candidate)) ?? null;
|
|
153
|
+
}
|
|
154
|
+
isWithin(target, root) {
|
|
155
|
+
return target === root || target.startsWith(root + external_path_.sep);
|
|
156
|
+
}
|
|
157
|
+
/** basePath-based fallback strategies */ fallbackPaths(normalizedPath, basePath) {
|
|
158
|
+
const normalizedBasePath = (0,external_path_.relative)(this.uploadDir, (0,external_path_.resolve)(basePath)).split(external_path_.sep).join('/');
|
|
159
|
+
if (normalizedPath.startsWith(normalizedBasePath)) {
|
|
144
160
|
// Strategy 2: basePath + remaining path
|
|
145
161
|
const remainingPath = normalizedPath.substring(normalizedBasePath.length).replace(/^\//, '');
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// Strategy 3: Old format - prepend basePath
|
|
150
|
-
const fallbackPath = (0,external_path_.join)(basePath, normalizedPath);
|
|
151
|
-
if ((0,__rspack_external_fs.existsSync)(fallbackPath)) return fallbackPath;
|
|
162
|
+
return [
|
|
163
|
+
(0,external_path_.join)(basePath, remainingPath)
|
|
164
|
+
];
|
|
152
165
|
}
|
|
153
|
-
|
|
166
|
+
// Strategy 3: Old format - prepend basePath
|
|
167
|
+
return [
|
|
168
|
+
(0,external_path_.join)(basePath, normalizedPath)
|
|
169
|
+
];
|
|
154
170
|
}
|
|
155
171
|
/** Get MIME type with SVG special handling */ getMimeType(fullPath) {
|
|
156
172
|
if (fullPath.toLowerCase().endsWith('.svg')) {
|
|
@@ -159,14 +175,15 @@ class FileServeMiddleware {
|
|
|
159
175
|
return __rspack_external_mime_types_1e2a4730.lookup(fullPath) || 'application/octet-stream';
|
|
160
176
|
}
|
|
161
177
|
/** Set response headers for file serving */ setResponseHeaders(res, size, mimeType, normalizedPath) {
|
|
162
|
-
const isViewable = VIEWABLE_TYPE_PREFIXES.some((type)=>mimeType.startsWith(type));
|
|
178
|
+
const isViewable = !ACTIVE_CONTENT_TYPES.includes(mimeType) && VIEWABLE_TYPE_PREFIXES.some((type)=>mimeType.startsWith(type));
|
|
163
179
|
const filename = normalizedPath.split('/').pop() || 'download';
|
|
164
180
|
const contentDisposition = isViewable ? 'inline' : `attachment; filename="${encodeURIComponent(filename)}"`;
|
|
165
181
|
res.set({
|
|
166
182
|
'Content-Type': mimeType,
|
|
167
183
|
'Content-Length': size,
|
|
168
184
|
'Content-Disposition': contentDisposition,
|
|
169
|
-
|
|
185
|
+
// The route cannot tell private files apart, so no shared proxy/CDN may keep a copy
|
|
186
|
+
'Cache-Control': 'private, max-age=3600',
|
|
170
187
|
'Accept-Ranges': 'bytes',
|
|
171
188
|
'Cross-Origin-Resource-Policy': 'cross-origin',
|
|
172
189
|
'Access-Control-Allow-Origin': '*',
|
|
@@ -223,7 +240,7 @@ FileServeMiddleware = _ts_decorate([
|
|
|
223
240
|
|
|
224
241
|
|
|
225
242
|
},
|
|
226
|
-
|
|
243
|
+
2329(module, __webpack_exports__, __webpack_require__) {
|
|
227
244
|
__webpack_require__.a(module, async function (__rspack_load_async_deps, __rspack_async_done) { try {
|
|
228
245
|
/* import */ var _storage_module_js__rspack_import_0 = __webpack_require__(624);
|
|
229
246
|
var __rspack_async_deps = __rspack_load_async_deps([_storage_module_js__rspack_import_0]);
|
|
@@ -239,16 +256,16 @@ __rspack_async_done();
|
|
|
239
256
|
},
|
|
240
257
|
624(module, __webpack_exports__, __webpack_require__) {
|
|
241
258
|
__webpack_require__.a(module, async function (__rspack_load_async_deps, __rspack_async_done) { try {
|
|
242
|
-
/* import */ var _flusys_nestjs_shared_modules__rspack_import_0 = __webpack_require__(
|
|
243
|
-
/* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(
|
|
244
|
-
/* import */ var _middlewares_index_js__rspack_import_2 = __webpack_require__(
|
|
245
|
-
/* import */ var _services_index_js__rspack_import_3 = __webpack_require__(
|
|
246
|
-
/* import */ var _config_storage_constants_js__rspack_import_9 = __webpack_require__(
|
|
247
|
-
/* import */ var _controllers_index_js__rspack_import_4 = __webpack_require__(
|
|
248
|
-
/* import */ var _enums_file_location_enum_js__rspack_import_8 = __webpack_require__(
|
|
249
|
-
/* import */ var _providers_index_js__rspack_import_5 = __webpack_require__(
|
|
259
|
+
/* import */ var _flusys_nestjs_shared_modules__rspack_import_0 = __webpack_require__(1236);
|
|
260
|
+
/* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
|
|
261
|
+
/* import */ var _middlewares_index_js__rspack_import_2 = __webpack_require__(5968);
|
|
262
|
+
/* import */ var _services_index_js__rspack_import_3 = __webpack_require__(4148);
|
|
263
|
+
/* import */ var _config_storage_constants_js__rspack_import_9 = __webpack_require__(9188);
|
|
264
|
+
/* import */ var _controllers_index_js__rspack_import_4 = __webpack_require__(5488);
|
|
265
|
+
/* import */ var _enums_file_location_enum_js__rspack_import_8 = __webpack_require__(2733);
|
|
266
|
+
/* import */ var _providers_index_js__rspack_import_5 = __webpack_require__(1922);
|
|
250
267
|
/* import */ var _providers_local_provider_js__rspack_import_6 = __webpack_require__(632);
|
|
251
|
-
/* import */ var _services_storage_provider_config_service_js__rspack_import_7 = __webpack_require__(
|
|
268
|
+
/* import */ var _services_storage_provider_config_service_js__rspack_import_7 = __webpack_require__(8623);
|
|
252
269
|
function _ts_decorate(decorators, target, key, desc) {
|
|
253
270
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
254
271
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -306,9 +323,9 @@ async function registerOptionalProvider(location, name, dep, loader) {
|
|
|
306
323
|
logger.debug(`${name} not available (install ${dep} to enable)`);
|
|
307
324
|
}
|
|
308
325
|
}
|
|
309
|
-
await registerOptionalProvider(_enums_file_location_enum_js__rspack_import_8/* .FileLocationEnum.AWS */.N.AWS, 'S3Provider', '@aws-sdk/client-s3', ()=>__webpack_require__.e(/* import() */ 591).then(__webpack_require__.bind(__webpack_require__,
|
|
310
|
-
await registerOptionalProvider(_enums_file_location_enum_js__rspack_import_8/* .FileLocationEnum.AZURE */.N.AZURE, 'AzureProvider', '@azure/storage-blob', ()=>__webpack_require__.e(/* import() */ 190).then(__webpack_require__.bind(__webpack_require__,
|
|
311
|
-
await registerOptionalProvider(_enums_file_location_enum_js__rspack_import_8/* .FileLocationEnum.SFTP */.N.SFTP, 'SftpProvider', 'ssh2-sftp-client', ()=>__webpack_require__.e(/* import() */ 918).then(__webpack_require__.bind(__webpack_require__,
|
|
326
|
+
await registerOptionalProvider(_enums_file_location_enum_js__rspack_import_8/* .FileLocationEnum.AWS */.N.AWS, 'S3Provider', '@aws-sdk/client-s3', ()=>__webpack_require__.e(/* import() */ 591).then(__webpack_require__.bind(__webpack_require__, 9970)));
|
|
327
|
+
await registerOptionalProvider(_enums_file_location_enum_js__rspack_import_8/* .FileLocationEnum.AZURE */.N.AZURE, 'AzureProvider', '@azure/storage-blob', ()=>__webpack_require__.e(/* import() */ 190).then(__webpack_require__.bind(__webpack_require__, 7269)));
|
|
328
|
+
await registerOptionalProvider(_enums_file_location_enum_js__rspack_import_8/* .FileLocationEnum.SFTP */.N.SFTP, 'SftpProvider', 'ssh2-sftp-client', ()=>__webpack_require__.e(/* import() */ 918).then(__webpack_require__.bind(__webpack_require__, 1005)));
|
|
312
329
|
class StorageModule {
|
|
313
330
|
configure(consumer) {
|
|
314
331
|
consumer.apply(_middlewares_index_js__rspack_import_2/* .FileServeMiddleware */.u).forRoutes({
|
|
@@ -409,9 +426,9 @@ __rspack_async_done();
|
|
|
409
426
|
} catch(e) { __rspack_async_done(e); } }, 1);
|
|
410
427
|
|
|
411
428
|
},
|
|
412
|
-
|
|
413
|
-
/* import */ var _storage_factory_service_js__rspack_import_0 = __webpack_require__(
|
|
414
|
-
/* import */ var _storage_provider_registry_js__rspack_import_1 = __webpack_require__(
|
|
429
|
+
1922(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
430
|
+
/* import */ var _storage_factory_service_js__rspack_import_0 = __webpack_require__(2192);
|
|
431
|
+
/* import */ var _storage_provider_registry_js__rspack_import_1 = __webpack_require__(9264);
|
|
415
432
|
/* import */ var _local_provider_js__rspack_import_2 = __webpack_require__(632);
|
|
416
433
|
// Core exports
|
|
417
434
|
|
|
@@ -439,15 +456,15 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
439
456
|
});
|
|
440
457
|
|
|
441
458
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
442
|
-
var common_ = __webpack_require__(
|
|
459
|
+
var common_ = __webpack_require__(6157);
|
|
443
460
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/constants"
|
|
444
|
-
var constants_ = __webpack_require__(
|
|
461
|
+
var constants_ = __webpack_require__(9140);
|
|
445
462
|
// EXTERNAL MODULE: ./projects/nestjs-storage/src/utils/image-compressor.util.ts + 1 modules
|
|
446
|
-
var image_compressor_util = __webpack_require__(
|
|
463
|
+
var image_compressor_util = __webpack_require__(1872);
|
|
447
464
|
;// CONCATENATED MODULE: external "fs/promises"
|
|
448
465
|
|
|
449
466
|
// EXTERNAL MODULE: external "path"
|
|
450
|
-
var external_path_ = __webpack_require__(
|
|
467
|
+
var external_path_ = __webpack_require__(2521);
|
|
451
468
|
// EXTERNAL MODULE: external "uuid"
|
|
452
469
|
var external_uuid_ = __webpack_require__(37);
|
|
453
470
|
;// CONCATENATED MODULE: ./projects/nestjs-storage/src/providers/local-provider.ts
|
|
@@ -475,20 +492,26 @@ var external_uuid_ = __webpack_require__(37);
|
|
|
475
492
|
basePath = '';
|
|
476
493
|
baseUrl = '';
|
|
477
494
|
relativeBasePath = '';
|
|
495
|
+
isWithinBase(targetPath) {
|
|
496
|
+
const normalizedBasePath = external_path_.resolve(this.basePath);
|
|
497
|
+
const normalizedTargetPath = external_path_.resolve(targetPath);
|
|
498
|
+
return normalizedTargetPath.startsWith(normalizedBasePath + external_path_.sep) || normalizedTargetPath === normalizedBasePath;
|
|
499
|
+
}
|
|
478
500
|
/**
|
|
479
501
|
* SECURITY: Validates that a target path does not escape the base directory
|
|
480
502
|
* Prevents path traversal attacks using ../ sequences
|
|
481
503
|
* @throws Error if path traversal is detected
|
|
482
504
|
*/ validatePathWithinBase(targetPath) {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
if (!normalizedTargetPath.startsWith(normalizedBasePath + external_path_.sep) && normalizedTargetPath !== normalizedBasePath) {
|
|
486
|
-
throw new common_.BadRequestException({
|
|
487
|
-
message: 'Invalid path: Path traversal attempt detected',
|
|
488
|
-
messageKey: constants_.SYSTEM_MESSAGES.PATH_TRAVERSAL_DETECTED
|
|
489
|
-
});
|
|
505
|
+
if (!this.isWithinBase(targetPath)) {
|
|
506
|
+
this.throwTraversal();
|
|
490
507
|
}
|
|
491
508
|
}
|
|
509
|
+
throwTraversal() {
|
|
510
|
+
throw new common_.BadRequestException({
|
|
511
|
+
message: 'Invalid path: Path traversal attempt detected',
|
|
512
|
+
messageKey: constants_.SYSTEM_MESSAGES.PATH_TRAVERSAL_DETECTED
|
|
513
|
+
});
|
|
514
|
+
}
|
|
492
515
|
/**
|
|
493
516
|
* SECURITY: Validates file key format to prevent malicious input
|
|
494
517
|
* @throws Error if key contains suspicious patterns
|
|
@@ -563,36 +586,27 @@ var external_uuid_ = __webpack_require__(37);
|
|
|
563
586
|
return Promise.all(files.map((file)=>this.uploadFile(file, options)));
|
|
564
587
|
}
|
|
565
588
|
async deleteFile(key) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
this.
|
|
573
|
-
|
|
589
|
+
// SECURITY: Validate key format first
|
|
590
|
+
this.validateKeyFormat(key);
|
|
591
|
+
// New keys include the basePath and resolve from cwd; old keys are relative to basePath.
|
|
592
|
+
// Only candidates inside the base directory are ever touched.
|
|
593
|
+
const candidates = [
|
|
594
|
+
external_path_.resolve(key),
|
|
595
|
+
external_path_.join(this.basePath, key)
|
|
596
|
+
].filter((candidate)=>this.isWithinBase(candidate) && external_path_.resolve(candidate) !== this.basePath);
|
|
597
|
+
if (!candidates.length) this.throwTraversal();
|
|
598
|
+
for (const candidate of candidates){
|
|
574
599
|
try {
|
|
575
|
-
await __rspack_external_fs_promises_e1851c9c.access(
|
|
600
|
+
await __rspack_external_fs_promises_e1851c9c.access(candidate);
|
|
576
601
|
} catch {
|
|
577
|
-
|
|
578
|
-
const fallbackPath = external_path_.join(this.basePath, key);
|
|
579
|
-
// SECURITY: Validate fallback path as well
|
|
580
|
-
this.validatePathWithinBase(fallbackPath);
|
|
581
|
-
try {
|
|
582
|
-
await __rspack_external_fs_promises_e1851c9c.access(fallbackPath);
|
|
583
|
-
filePath = fallbackPath;
|
|
584
|
-
} catch {
|
|
585
|
-
// File doesn't exist at either location - silent return
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
602
|
+
continue;
|
|
588
603
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
throw error;
|
|
604
|
+
try {
|
|
605
|
+
await __rspack_external_fs_promises_e1851c9c.unlink(candidate);
|
|
606
|
+
} catch {
|
|
607
|
+
// Silent failure - the file may have been removed concurrently
|
|
594
608
|
}
|
|
595
|
-
|
|
609
|
+
return;
|
|
596
610
|
}
|
|
597
611
|
}
|
|
598
612
|
async deleteMultipleFiles(keys) {
|
|
@@ -621,7 +635,7 @@ var external_uuid_ = __webpack_require__(37);
|
|
|
621
635
|
|
|
622
636
|
|
|
623
637
|
},
|
|
624
|
-
|
|
638
|
+
1872(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
625
639
|
|
|
626
640
|
// EXPORTS
|
|
627
641
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -634,6 +648,10 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
634
648
|
|
|
635
649
|
// Handle ESM/CJS interop - sharp exports differently in each module system
|
|
636
650
|
const sharp = __rspack_external_sharp["default"] || __rspack_external_sharp;
|
|
651
|
+
const MULTI_FRAME_FORMATS = [
|
|
652
|
+
'gif',
|
|
653
|
+
'webp'
|
|
654
|
+
];
|
|
637
655
|
/**
|
|
638
656
|
* Image Compression Utility
|
|
639
657
|
* Handles image compression and format conversion using sharp
|
|
@@ -651,87 +669,87 @@ const sharp = __rspack_external_sharp["default"] || __rspack_external_sharp;
|
|
|
651
669
|
format: mimetype
|
|
652
670
|
};
|
|
653
671
|
}
|
|
654
|
-
|
|
655
|
-
const image = sharp(buffer, {
|
|
656
|
-
failOnError: false,
|
|
657
|
-
density: 300
|
|
658
|
-
});
|
|
659
|
-
// Apply initial resize
|
|
660
|
-
image.resize({
|
|
661
|
-
width: maxWidth,
|
|
662
|
-
height: maxHeight,
|
|
663
|
-
fit: 'inside',
|
|
664
|
-
withoutEnlargement: true
|
|
665
|
-
});
|
|
666
|
-
// Determine target format
|
|
667
|
-
let targetFormat = format !== 'original' ? format : mimetype.split('/')[1];
|
|
668
|
-
// Format-specific optimizations
|
|
669
|
-
switch(targetFormat.toLowerCase()){
|
|
670
|
-
case 'jpeg':
|
|
671
|
-
case 'jpg':
|
|
672
|
-
image.jpeg({
|
|
673
|
-
quality,
|
|
674
|
-
mozjpeg: true,
|
|
675
|
-
chromaSubsampling: '4:4:4'
|
|
676
|
-
});
|
|
677
|
-
break;
|
|
678
|
-
case 'png':
|
|
679
|
-
image.png({
|
|
680
|
-
compressionLevel: 9,
|
|
681
|
-
adaptiveFiltering: true,
|
|
682
|
-
palette: true,
|
|
683
|
-
quality,
|
|
684
|
-
colors: 256,
|
|
685
|
-
dither: 1.0
|
|
686
|
-
});
|
|
687
|
-
break;
|
|
688
|
-
case 'webp':
|
|
689
|
-
image.webp({
|
|
690
|
-
quality,
|
|
691
|
-
smartSubsample: true,
|
|
692
|
-
effort: 6,
|
|
693
|
-
lossless: quality === 100
|
|
694
|
-
});
|
|
695
|
-
break;
|
|
696
|
-
case 'avif':
|
|
697
|
-
image.avif({
|
|
698
|
-
quality,
|
|
699
|
-
effort: 6,
|
|
700
|
-
chromaSubsampling: '4:4:4'
|
|
701
|
-
});
|
|
702
|
-
break;
|
|
703
|
-
case 'tiff':
|
|
704
|
-
image.tiff({
|
|
705
|
-
quality,
|
|
706
|
-
compression: 'lzw',
|
|
707
|
-
predictor: 'horizontal',
|
|
708
|
-
pyramid: true
|
|
709
|
-
});
|
|
710
|
-
break;
|
|
711
|
-
case 'gif':
|
|
712
|
-
image.gif({
|
|
713
|
-
colours: 256,
|
|
714
|
-
effort: 10,
|
|
715
|
-
dither: 1
|
|
716
|
-
});
|
|
717
|
-
break;
|
|
718
|
-
case 'jp2':
|
|
719
|
-
image.jp2({
|
|
720
|
-
quality,
|
|
721
|
-
lossless: quality === 100
|
|
722
|
-
});
|
|
723
|
-
break;
|
|
724
|
-
default:
|
|
725
|
-
// Fallback to WebP for best compression/quality ratio
|
|
726
|
-
targetFormat = 'webp';
|
|
727
|
-
image.webp({
|
|
728
|
-
quality,
|
|
729
|
-
smartSubsample: true,
|
|
730
|
-
effort: 6
|
|
731
|
-
});
|
|
732
|
-
break;
|
|
733
|
-
}
|
|
672
|
+
let targetFormat = (format !== 'original' ? format : mimetype.split('/')[1]).toLowerCase();
|
|
734
673
|
try {
|
|
674
|
+
// Read every frame only when the output can hold them - a multi-page JPEG/PNG would be one tall strip
|
|
675
|
+
const image = sharp(buffer, {
|
|
676
|
+
failOnError: false,
|
|
677
|
+
density: 300,
|
|
678
|
+
animated: MULTI_FRAME_FORMATS.includes(targetFormat)
|
|
679
|
+
});
|
|
680
|
+
// Apply initial resize
|
|
681
|
+
image.resize({
|
|
682
|
+
width: maxWidth,
|
|
683
|
+
height: maxHeight,
|
|
684
|
+
fit: 'inside',
|
|
685
|
+
withoutEnlargement: true
|
|
686
|
+
});
|
|
687
|
+
// Format-specific optimizations
|
|
688
|
+
switch(targetFormat){
|
|
689
|
+
case 'jpeg':
|
|
690
|
+
case 'jpg':
|
|
691
|
+
image.jpeg({
|
|
692
|
+
quality,
|
|
693
|
+
mozjpeg: true,
|
|
694
|
+
chromaSubsampling: '4:4:4'
|
|
695
|
+
});
|
|
696
|
+
break;
|
|
697
|
+
case 'png':
|
|
698
|
+
image.png({
|
|
699
|
+
compressionLevel: 9,
|
|
700
|
+
adaptiveFiltering: true,
|
|
701
|
+
palette: true,
|
|
702
|
+
quality,
|
|
703
|
+
colors: 256,
|
|
704
|
+
dither: 1.0
|
|
705
|
+
});
|
|
706
|
+
break;
|
|
707
|
+
case 'webp':
|
|
708
|
+
image.webp({
|
|
709
|
+
quality,
|
|
710
|
+
smartSubsample: true,
|
|
711
|
+
effort: 6,
|
|
712
|
+
lossless: quality === 100
|
|
713
|
+
});
|
|
714
|
+
break;
|
|
715
|
+
case 'avif':
|
|
716
|
+
image.avif({
|
|
717
|
+
quality,
|
|
718
|
+
effort: 6,
|
|
719
|
+
chromaSubsampling: '4:4:4'
|
|
720
|
+
});
|
|
721
|
+
break;
|
|
722
|
+
case 'tiff':
|
|
723
|
+
image.tiff({
|
|
724
|
+
quality,
|
|
725
|
+
compression: 'lzw',
|
|
726
|
+
predictor: 'horizontal',
|
|
727
|
+
pyramid: true
|
|
728
|
+
});
|
|
729
|
+
break;
|
|
730
|
+
case 'gif':
|
|
731
|
+
image.gif({
|
|
732
|
+
colours: 256,
|
|
733
|
+
effort: 10,
|
|
734
|
+
dither: 1
|
|
735
|
+
});
|
|
736
|
+
break;
|
|
737
|
+
case 'jp2':
|
|
738
|
+
image.jp2({
|
|
739
|
+
quality,
|
|
740
|
+
lossless: quality === 100
|
|
741
|
+
});
|
|
742
|
+
break;
|
|
743
|
+
default:
|
|
744
|
+
// Fallback to WebP for best compression/quality ratio
|
|
745
|
+
targetFormat = 'webp';
|
|
746
|
+
image.webp({
|
|
747
|
+
quality,
|
|
748
|
+
smartSubsample: true,
|
|
749
|
+
effort: 6
|
|
750
|
+
});
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
735
753
|
const compressedBuffer = await image.toBuffer();
|
|
736
754
|
return {
|
|
737
755
|
buffer: compressedBuffer,
|
|
@@ -747,12 +765,6 @@ const sharp = __rspack_external_sharp["default"] || __rspack_external_sharp;
|
|
|
747
765
|
}
|
|
748
766
|
|
|
749
767
|
|
|
750
|
-
},
|
|
751
|
-
521(module) {
|
|
752
|
-
|
|
753
|
-
module.exports = __rspack_external_path;
|
|
754
|
-
|
|
755
|
-
|
|
756
768
|
},
|
|
757
769
|
37(module) {
|
|
758
770
|
|
package/fesm/chunks/190.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const __rspack_esm_id = 190;
|
|
2
2
|
export const __rspack_esm_ids = [190];
|
|
3
3
|
export const __webpack_modules__ = {
|
|
4
|
-
|
|
4
|
+
7269(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
5
5
|
__webpack_require__.r(__webpack_exports__);
|
|
6
|
-
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(
|
|
7
|
-
/* import */ var _flusys_nestjs_shared_constants__rspack_import_1 = __webpack_require__(
|
|
6
|
+
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
7
|
+
/* import */ var _flusys_nestjs_shared_constants__rspack_import_1 = __webpack_require__(9140);
|
|
8
8
|
/* import */ var uuid__rspack_import_2 = __webpack_require__(37);
|
|
9
|
-
/* import */ var _utils_image_compressor_util_js__rspack_import_3 = __webpack_require__(
|
|
9
|
+
/* import */ var _utils_image_compressor_util_js__rspack_import_3 = __webpack_require__(1872);
|
|
10
10
|
/**
|
|
11
11
|
* Optional Azure Blob Storage Provider
|
|
12
12
|
* Requires: npm install @azure/storage-blob
|
|
@@ -21,7 +21,7 @@ class AzureProvider {
|
|
|
21
21
|
accountName = '';
|
|
22
22
|
async initialize(config) {
|
|
23
23
|
try {
|
|
24
|
-
const { BlobServiceClient, StorageSharedKeyCredential } = await __webpack_require__.e(/* import() */ 746).then(__webpack_require__.bind(__webpack_require__,
|
|
24
|
+
const { BlobServiceClient, StorageSharedKeyCredential } = await __webpack_require__.e(/* import() */ 746).then(__webpack_require__.bind(__webpack_require__, 4737));
|
|
25
25
|
this.accountName = config.accountName;
|
|
26
26
|
this.containerName = config.containerName;
|
|
27
27
|
this.blobServiceClient = config.connectionString ? BlobServiceClient.fromConnectionString(config.connectionString) : new BlobServiceClient(`https://${config.accountName}.blob.core.windows.net`, new StorageSharedKeyCredential(config.accountName, config.accountKey));
|
|
@@ -74,7 +74,7 @@ class AzureProvider {
|
|
|
74
74
|
await Promise.all(keys.map((key)=>this.deleteFile(key)));
|
|
75
75
|
}
|
|
76
76
|
async generatePresignedUrl(key, expiresInSeconds = 3600) {
|
|
77
|
-
const { BlobSASPermissions, generateBlobSASQueryParameters } = await __webpack_require__.e(/* import() */ 746).then(__webpack_require__.bind(__webpack_require__,
|
|
77
|
+
const { BlobSASPermissions, generateBlobSASQueryParameters } = await __webpack_require__.e(/* import() */ 746).then(__webpack_require__.bind(__webpack_require__, 4737));
|
|
78
78
|
const blockBlobClient = this.containerClient.getBlockBlobClient(key);
|
|
79
79
|
const startsOn = new Date();
|
|
80
80
|
const expiresOn = new Date(startsOn.getTime() + expiresInSeconds * 1000);
|
package/fesm/chunks/252.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as __rspack_external__aws_sdk_s3_request_presigner_e09eabb8 from "@aws-
|
|
|
2
2
|
export const __rspack_esm_id = 252;
|
|
3
3
|
export const __rspack_esm_ids = [252];
|
|
4
4
|
export const __webpack_modules__ = {
|
|
5
|
-
|
|
5
|
+
5207(module) {
|
|
6
6
|
|
|
7
7
|
module.exports = __rspack_external__aws_sdk_s3_request_presigner_e09eabb8;
|
|
8
8
|
|
package/fesm/chunks/327.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as __rspack_external__aws_sdk_lib_storage_4348b131 from "@aws-sdk/lib-s
|
|
|
2
2
|
export const __rspack_esm_id = 327;
|
|
3
3
|
export const __rspack_esm_ids = [327];
|
|
4
4
|
export const __webpack_modules__ = {
|
|
5
|
-
|
|
5
|
+
5354(module) {
|
|
6
6
|
|
|
7
7
|
module.exports = __rspack_external__aws_sdk_lib_storage_4348b131;
|
|
8
8
|
|
package/fesm/chunks/385.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as __rspack_external_ssh2_sftp_client_29ee4624 from "ssh2-sftp-client";
|
|
|
2
2
|
export const __rspack_esm_id = 385;
|
|
3
3
|
export const __rspack_esm_ids = [385];
|
|
4
4
|
export const __webpack_modules__ = {
|
|
5
|
-
|
|
5
|
+
2240(module) {
|
|
6
6
|
|
|
7
7
|
module.exports = __rspack_external_ssh2_sftp_client_29ee4624;
|
|
8
8
|
|
package/fesm/chunks/591.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const __rspack_esm_id = 591;
|
|
2
2
|
export const __rspack_esm_ids = [591];
|
|
3
3
|
export const __webpack_modules__ = {
|
|
4
|
-
|
|
4
|
+
9970(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
5
5
|
__webpack_require__.r(__webpack_exports__);
|
|
6
|
-
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(
|
|
7
|
-
/* import */ var _flusys_nestjs_shared_constants__rspack_import_1 = __webpack_require__(
|
|
6
|
+
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
7
|
+
/* import */ var _flusys_nestjs_shared_constants__rspack_import_1 = __webpack_require__(9140);
|
|
8
8
|
/* import */ var uuid__rspack_import_2 = __webpack_require__(37);
|
|
9
|
-
/* import */ var _utils_image_compressor_util_js__rspack_import_3 = __webpack_require__(
|
|
9
|
+
/* import */ var _utils_image_compressor_util_js__rspack_import_3 = __webpack_require__(1872);
|
|
10
10
|
/**
|
|
11
11
|
* Optional AWS S3 Storage Provider
|
|
12
12
|
* Requires: npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner
|
|
@@ -20,7 +20,7 @@ class S3Provider {
|
|
|
20
20
|
region = '';
|
|
21
21
|
async initialize(config) {
|
|
22
22
|
try {
|
|
23
|
-
const { S3Client } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__,
|
|
23
|
+
const { S3Client } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__, 2965));
|
|
24
24
|
this.region = config.region;
|
|
25
25
|
this.bucketName = config.bucket;
|
|
26
26
|
this.s3 = new S3Client({
|
|
@@ -42,7 +42,7 @@ class S3Provider {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
async uploadFile(file, options) {
|
|
45
|
-
const { Upload } = await __webpack_require__.e(/* import() */ 327).then(__webpack_require__.bind(__webpack_require__,
|
|
45
|
+
const { Upload } = await __webpack_require__.e(/* import() */ 327).then(__webpack_require__.bind(__webpack_require__, 5354));
|
|
46
46
|
let processedBuffer = file.buffer;
|
|
47
47
|
let contentType = file.mimetype;
|
|
48
48
|
const fileName = `${(0,uuid__rspack_import_2.v4)()}-${file.originalname}`;
|
|
@@ -77,14 +77,14 @@ class S3Provider {
|
|
|
77
77
|
return Promise.all(files.map((file)=>this.uploadFile(file, options)));
|
|
78
78
|
}
|
|
79
79
|
async deleteFile(key) {
|
|
80
|
-
const { DeleteObjectCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__,
|
|
80
|
+
const { DeleteObjectCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__, 2965));
|
|
81
81
|
await this.s3.send(new DeleteObjectCommand({
|
|
82
82
|
Bucket: this.bucketName,
|
|
83
83
|
Key: key
|
|
84
84
|
}));
|
|
85
85
|
}
|
|
86
86
|
async deleteMultipleFiles(keys) {
|
|
87
|
-
const { DeleteObjectsCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__,
|
|
87
|
+
const { DeleteObjectsCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__, 2965));
|
|
88
88
|
await this.s3.send(new DeleteObjectsCommand({
|
|
89
89
|
Bucket: this.bucketName,
|
|
90
90
|
Delete: {
|
|
@@ -95,8 +95,8 @@ class S3Provider {
|
|
|
95
95
|
}));
|
|
96
96
|
}
|
|
97
97
|
async generatePresignedUrl(key, expiresInSeconds = 3600) {
|
|
98
|
-
const { GetObjectCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__,
|
|
99
|
-
const { getSignedUrl } = await __webpack_require__.e(/* import() */ 252).then(__webpack_require__.bind(__webpack_require__,
|
|
98
|
+
const { GetObjectCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__, 2965));
|
|
99
|
+
const { getSignedUrl } = await __webpack_require__.e(/* import() */ 252).then(__webpack_require__.bind(__webpack_require__, 5207));
|
|
100
100
|
return getSignedUrl(this.s3, new GetObjectCommand({
|
|
101
101
|
Bucket: this.bucketName,
|
|
102
102
|
Key: key
|
|
@@ -106,7 +106,7 @@ class S3Provider {
|
|
|
106
106
|
}
|
|
107
107
|
async healthCheck() {
|
|
108
108
|
try {
|
|
109
|
-
const { HeadBucketCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__,
|
|
109
|
+
const { HeadBucketCommand } = await __webpack_require__.e(/* import() */ 798).then(__webpack_require__.bind(__webpack_require__, 2965));
|
|
110
110
|
await this.s3.send(new HeadBucketCommand({
|
|
111
111
|
Bucket: this.bucketName
|
|
112
112
|
}));
|