@flusys/nestjs-storage 9.1.2 → 9.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +13 -0
  2. package/controllers/file-manager.controller.d.ts +1 -0
  3. package/controllers/folder.controller.d.ts +1 -0
  4. package/controllers/storage-config.controller.d.ts +1 -0
  5. package/fesm/493.js +416 -251
  6. package/fesm/537.js +25 -21
  7. package/fesm/562.js +184 -172
  8. package/fesm/chunks/190.js +6 -6
  9. package/fesm/chunks/252.js +1 -1
  10. package/fesm/chunks/327.js +1 -1
  11. package/fesm/chunks/385.js +1 -1
  12. package/fesm/chunks/591.js +11 -11
  13. package/fesm/chunks/746.js +1 -1
  14. package/fesm/chunks/798.js +1 -1
  15. package/fesm/chunks/918.js +19 -7
  16. package/fesm/config/index.js +8 -8
  17. package/fesm/controllers/index.js +1 -1
  18. package/fesm/docs/index.js +11 -15
  19. package/fesm/dtos/index.js +24 -20
  20. package/fesm/entities/index.js +6 -6
  21. package/fesm/enums/index.js +4 -4
  22. package/fesm/index.js +30 -34
  23. package/fesm/interfaces/index.js +2 -2
  24. package/fesm/modules/index.js +1 -1
  25. package/fesm/providers/index.js +123 -129
  26. package/fesm/services/index.js +1 -1
  27. package/fesm/utils/index.js +88 -84
  28. package/middlewares/file-serve.middleware.d.ts +3 -1
  29. package/package.json +3 -3
  30. package/providers/local-provider.d.ts +2 -0
  31. package/providers/sftp-provider.optional.d.ts +1 -0
  32. package/providers/storage-factory.service.d.ts +4 -2
  33. package/services/file-manager.service.d.ts +5 -6
  34. package/services/folder.service.d.ts +5 -5
  35. package/services/storage-provider-config.service.d.ts +5 -2
  36. package/services/upload.service.d.ts +3 -1
  37. package/utils/company-ownership.util.d.ts +3 -0
  38. package/utils/file-validator.util.d.ts +1 -0
package/fesm/493.js CHANGED
@@ -8,13 +8,14 @@ import * as __rspack_external__nestjs_common_a04939da from "@nestjs/common";
8
8
  import * as __rspack_external__nestjs_swagger_7cd450b5 from "@nestjs/swagger";
9
9
  import * as __rspack_external_class_transformer_c5a479fb from "class-transformer";
10
10
  import * as __rspack_external_class_validator_7b99ef4d from "class-validator";
11
+ import * as __rspack_external_path from "path";
11
12
  import * as __rspack_external_typeorm from "typeorm";
12
13
  import * as __rspack_external__nestjs_core_d7b00a1a from "@nestjs/core";
13
14
  import * as __rspack_external_crypto from "crypto";
14
15
  export const __rspack_esm_id = 493;
15
16
  export const __rspack_esm_ids = [493];
16
17
  export const __webpack_modules__ = {
17
- 884(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
18
+ 4884(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
18
19
  /**
19
20
  * Domain event actions published by the storage module, alongside the CRUD
20
21
  * lifecycle actions every ApiService emits.
@@ -38,7 +39,7 @@ __webpack_require__.d(__webpack_exports__, {
38
39
 
39
40
 
40
41
  },
41
- 450(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
42
+ 5450(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
42
43
  // ==================== STORAGE MODULE MESSAGE KEYS ====================
43
44
  const FILE_MESSAGES = {
44
45
  GET_ALL_SUCCESS: 'file.get.all.success',
@@ -72,7 +73,7 @@ __webpack_require__.d(__webpack_exports__, {
72
73
 
73
74
 
74
75
  },
75
- 188(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
76
+ 9188(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
76
77
  /**
77
78
  * Storage Module Constants
78
79
  */ const STORAGE_MODULE_OPTIONS = 'STORAGE_MODULE_OPTIONS';
@@ -90,10 +91,10 @@ __webpack_require__.d(__webpack_exports__, {
90
91
 
91
92
 
92
93
  },
93
- 322(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
94
- /* import */ var _nestjs_swagger__rspack_import_0 = __webpack_require__(176);
95
- /* import */ var class_transformer__rspack_import_1 = __webpack_require__(812);
96
- /* import */ var class_validator__rspack_import_2 = __webpack_require__(421);
94
+ 7322(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
95
+ /* import */ var _nestjs_swagger__rspack_import_0 = __webpack_require__(6176);
96
+ /* import */ var class_transformer__rspack_import_1 = __webpack_require__(5812);
97
+ /* import */ var class_validator__rspack_import_2 = __webpack_require__(5421);
97
98
  function _ts_decorate(decorators, target, key, desc) {
98
99
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
99
100
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -266,7 +267,7 @@ _ts_decorate([
266
267
  default: true
267
268
  }),
268
269
  (0,class_validator__rspack_import_2.IsOptional)(),
269
- (0,class_transformer__rspack_import_1.Type)(()=>Boolean),
270
+ (0,class_transformer__rspack_import_1.Transform)(({ value })=>value === 'true' ? true : value === 'false' ? false : value),
270
271
  (0,class_validator__rspack_import_2.IsBoolean)(),
271
272
  _ts_metadata("design:type", Boolean)
272
273
  ], UploadOptionsDto.prototype, "compress", void 0);
@@ -338,7 +339,7 @@ __webpack_require__.d(__webpack_exports__, {
338
339
 
339
340
 
340
341
  },
341
- 975(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
342
+ 1975(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
342
343
 
343
344
  // EXPORTS
344
345
  __webpack_require__.d(__webpack_exports__, {
@@ -359,7 +360,7 @@ __webpack_require__.d(__webpack_exports__, {
359
360
  ;// CONCATENATED MODULE: external "@flusys/nestjs-shared/entities"
360
361
 
361
362
  // EXTERNAL MODULE: external "typeorm"
362
- var external_typeorm_ = __webpack_require__(158);
363
+ var external_typeorm_ = __webpack_require__(7158);
363
364
  ;// CONCATENATED MODULE: ./projects/nestjs-storage/src/entities/file-manager.entity.ts
364
365
  function _ts_decorate(decorators, target, key, desc) {
365
366
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -530,7 +531,7 @@ Folder = folder_entity_ts_decorate([
530
531
  ], Folder);
531
532
 
532
533
  // EXTERNAL MODULE: external "@flusys/nestjs-shared"
533
- var nestjs_shared_ = __webpack_require__(422);
534
+ var nestjs_shared_ = __webpack_require__(3422);
534
535
  ;// CONCATENATED MODULE: ./projects/nestjs-storage/src/entities/storage-config.entity.ts
535
536
  function storage_config_entity_ts_decorate(decorators, target, key, desc) {
536
537
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -779,7 +780,7 @@ function getStorageEntitiesByConfig(enableCompanyFeature) {
779
780
 
780
781
 
781
782
  },
782
- 733(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
783
+ 2733(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
783
784
  var FileLocationEnum = /*#__PURE__*/ function(FileLocationEnum) {
784
785
  FileLocationEnum["AWS"] = "aws";
785
786
  FileLocationEnum["AZURE"] = "azure";
@@ -794,7 +795,7 @@ __webpack_require__.d(__webpack_exports__, {
794
795
 
795
796
 
796
797
  },
797
- 192(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
798
+ 2192(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
798
799
 
799
800
  // EXPORTS
800
801
  __webpack_require__.d(__webpack_exports__, {
@@ -802,15 +803,15 @@ __webpack_require__.d(__webpack_exports__, {
802
803
  });
803
804
 
804
805
  // EXTERNAL MODULE: external "@flusys/nestjs-shared/constants"
805
- var constants_ = __webpack_require__(140);
806
+ var constants_ = __webpack_require__(9140);
806
807
  // EXTERNAL MODULE: external "@nestjs/common"
807
- var common_ = __webpack_require__(157);
808
+ var common_ = __webpack_require__(6157);
808
809
  ;// CONCATENATED MODULE: external "crypto"
809
810
 
810
811
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/services/index.ts
811
- var services = __webpack_require__(148);
812
+ var services = __webpack_require__(4148);
812
813
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/providers/storage-provider.registry.ts
813
- var storage_provider_registry = __webpack_require__(264);
814
+ var storage_provider_registry = __webpack_require__(9264);
814
815
  ;// CONCATENATED MODULE: ./projects/nestjs-storage/src/providers/storage-factory.service.ts
815
816
  function _ts_decorate(decorators, target, key, desc) {
816
817
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -840,6 +841,8 @@ function _ts_param(paramIndex, decorator) {
840
841
 
841
842
 
842
843
 
844
+ const MAX_CACHED_PROVIDERS = 50;
845
+ const PROVIDER_IDLE_TTL_MS = 30 * 60 * 1000;
843
846
  class StorageFactoryService {
844
847
  configService;
845
848
  cache = new Map();
@@ -848,8 +851,14 @@ class StorageFactoryService {
848
851
  }
849
852
  async createProvider(config) {
850
853
  const cacheKey = this.generateCacheKey(config);
854
+ const now = Date.now();
851
855
  const cached = this.cache.get(cacheKey);
852
- if (cached) return cached;
856
+ if (cached) {
857
+ cached.lastUsed = now;
858
+ this.cache.delete(cacheKey);
859
+ this.cache.set(cacheKey, cached);
860
+ return cached.provider;
861
+ }
853
862
  const ProviderClass = storage_provider_registry/* .StorageProviderRegistry.get */.C.get(config.provider);
854
863
  if (!ProviderClass) {
855
864
  throw new common_.NotFoundException({
@@ -861,10 +870,37 @@ class StorageFactoryService {
861
870
  }
862
871
  });
863
872
  }
873
+ // The pending promise is cached so concurrent first requests share one client instead of leaking extras
874
+ const entry = {
875
+ provider: this.instantiate(ProviderClass, config),
876
+ lastUsed: now
877
+ };
878
+ this.cache.set(cacheKey, entry);
879
+ entry.provider.catch(()=>{
880
+ if (this.cache.get(cacheKey) === entry) this.cache.delete(cacheKey);
881
+ });
882
+ this.evict(now);
883
+ return entry.provider;
884
+ }
885
+ /** A provider that needs no configuration; never one created for a specific StorageConfig row */ async getProvider(providerName) {
886
+ return this.createProvider({
887
+ provider: providerName,
888
+ config: {}
889
+ });
890
+ }
891
+ async clearCache() {
892
+ const entries = Array.from(this.cache.values());
893
+ this.cache.clear();
894
+ await Promise.allSettled(entries.map((entry)=>this.closeEntry(entry)));
895
+ }
896
+ async onModuleDestroy() {
897
+ await this.clearCache();
898
+ }
899
+ // ─── Private Helpers ──────────────────────────────────────────────────────────
900
+ async instantiate(ProviderClass, config) {
864
901
  try {
865
902
  const instance = new ProviderClass();
866
903
  await this.initializeProvider(instance, config);
867
- this.cache.set(cacheKey, instance);
868
904
  return instance;
869
905
  } catch (error) {
870
906
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
@@ -878,32 +914,25 @@ class StorageFactoryService {
878
914
  });
879
915
  }
880
916
  }
881
- async getProvider(providerName) {
882
- const cachedKey = Array.from(this.cache.keys()).find((k)=>k.startsWith(providerName));
883
- if (cachedKey) return this.cache.get(cachedKey);
884
- return this.createProvider({
885
- provider: providerName,
886
- config: {}
887
- });
888
- }
889
- getLocalProviderBasePath() {
890
- const localKey = Array.from(this.cache.keys()).find((k)=>k.startsWith('local'));
891
- const provider = localKey ? this.cache.get(localKey) : null;
892
- return provider && 'basePath' in provider ? provider.basePath : null;
893
- }
894
- clearCache() {
895
- this.cache.clear();
917
+ evict(now) {
918
+ for (const [key, entry] of this.cache){
919
+ const overCapacity = this.cache.size > MAX_CACHED_PROVIDERS;
920
+ if (!overCapacity && now - entry.lastUsed < PROVIDER_IDLE_TTL_MS) continue;
921
+ this.cache.delete(key);
922
+ void this.closeEntry(entry);
923
+ }
896
924
  }
897
- async onModuleDestroy() {
898
- const closePromises = Array.from(this.cache.entries()).filter(([, p])=>'close' in p && typeof p.close === 'function').map(([, p])=>p.close().catch(()=>{}));
899
- await Promise.allSettled(closePromises);
900
- this.cache.clear();
925
+ async closeEntry(entry) {
926
+ try {
927
+ const provider = await entry.provider;
928
+ if (typeof provider.close === 'function') await provider.close();
929
+ } catch {
930
+ // A client that failed to initialize or to close has nothing left to release
931
+ }
901
932
  }
902
- // ─── Private Helpers ──────────────────────────────────────────────────────────
903
933
  generateCacheKey(config) {
904
- const sortedKeys = Object.keys(config.config || {}).sort();
905
- const hash = __rspack_external_crypto.createHash('sha256').update(JSON.stringify(config.config, sortedKeys)).digest('hex').substring(0, 16);
906
- return `${config.provider}-${hash}`;
934
+ const hash = __rspack_external_crypto.createHash('sha256').update(stableStringify(config.config ?? {})).digest('hex');
935
+ return `${config.provider}:${hash}`;
907
936
  }
908
937
  async initializeProvider(instance, config) {
909
938
  if (!('initialize' in instance) || typeof instance.initialize !== 'function') {
@@ -931,10 +960,18 @@ StorageFactoryService = _ts_decorate([
931
960
  typeof services/* .StorageConfigService */.tP === "undefined" ? Object : services/* .StorageConfigService */.tP
932
961
  ])
933
962
  ], StorageFactoryService);
963
+ /** Key order never changes the key, and nested values always do - two configs must never share a client */ function stableStringify(value) {
964
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;
965
+ if (value && typeof value === 'object') {
966
+ const entries = Object.keys(value).toSorted().map((key)=>`${JSON.stringify(key)}:${stableStringify(value[key])}`);
967
+ return `{${entries.join(',')}}`;
968
+ }
969
+ return JSON.stringify(value) ?? 'undefined';
970
+ }
934
971
 
935
972
 
936
973
  },
937
- 264(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
974
+ 9264(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
938
975
  /**
939
976
  * Static registry for storage provider classes
940
977
  * Allows dynamic registration at runtime
@@ -963,22 +1000,23 @@ __webpack_require__.d(__webpack_exports__, {
963
1000
 
964
1001
 
965
1002
  },
966
- 955(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1003
+ 7955(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
967
1004
  __webpack_require__.d(__webpack_exports__, {
968
1005
  D: () => (FileManagerService)
969
1006
  });
970
- /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(937);
971
- /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(236);
972
- /* import */ var _flusys_nestjs_shared_utils__rspack_import_2 = __webpack_require__(216);
973
- /* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(157);
974
- /* import */ var typeorm__rspack_import_4 = __webpack_require__(158);
975
- /* import */ var _config_index_js__rspack_import_9 = __webpack_require__(884);
976
- /* import */ var _config_index_js__rspack_import_10 = __webpack_require__(450);
977
- /* import */ var _entities_index_js__rspack_import_5 = __webpack_require__(975);
978
- /* import */ var _enums_file_location_enum_js__rspack_import_11 = __webpack_require__(733);
979
- /* import */ var _storage_config_service_js__rspack_import_6 = __webpack_require__(397);
980
- /* import */ var _storage_datasource_provider_js__rspack_import_7 = __webpack_require__(616);
981
- /* import */ var _upload_service_js__rspack_import_8 = __webpack_require__(18);
1007
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
1008
+ /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(1236);
1009
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_2 = __webpack_require__(9216);
1010
+ /* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(6157);
1011
+ /* import */ var typeorm__rspack_import_4 = __webpack_require__(7158);
1012
+ /* import */ var _config_index_js__rspack_import_10 = __webpack_require__(4884);
1013
+ /* import */ var _config_index_js__rspack_import_11 = __webpack_require__(5450);
1014
+ /* import */ var _entities_index_js__rspack_import_5 = __webpack_require__(1975);
1015
+ /* import */ var _enums_file_location_enum_js__rspack_import_12 = __webpack_require__(2733);
1016
+ /* import */ var _utils_company_ownership_util_js__rspack_import_6 = __webpack_require__(5198);
1017
+ /* import */ var _storage_config_service_js__rspack_import_7 = __webpack_require__(6397);
1018
+ /* import */ var _storage_datasource_provider_js__rspack_import_8 = __webpack_require__(8616);
1019
+ /* import */ var _upload_service_js__rspack_import_9 = __webpack_require__(5018);
982
1020
  function _ts_decorate(decorators, target, key, desc) {
983
1021
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
984
1022
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -1013,6 +1051,7 @@ function _ts_param(paramIndex, decorator) {
1013
1051
 
1014
1052
 
1015
1053
 
1054
+
1016
1055
  const URL_EXPIRY_SECONDS = 3600;
1017
1056
  const DEFAULT_SELECT_FIELDS = [
1018
1057
  'id',
@@ -1035,9 +1074,15 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1035
1074
  dataSourceProvider;
1036
1075
  permissionCacheService;
1037
1076
  constructor(cacheManager, utilsService, uploadService, storageConfig, dataSourceProvider, permissionCacheService){
1038
- super(_config_index_js__rspack_import_9/* .STORAGE_EVENT_ENTITIES.FILE */.fR.FILE, cacheManager, utilsService, FileManagerService.name, true, _config_index_js__rspack_import_9/* .STORAGE_EVENT_MODULE */.qh, dataSourceProvider, storageConfig.isCompanyFeatureEnabled() ? _entities_index_js__rspack_import_5.FileManagerWithCompany : _entities_index_js__rspack_import_5.FileManager), this.cacheManager = cacheManager, this.utilsService = utilsService, this.uploadService = uploadService, this.storageConfig = storageConfig, this.dataSourceProvider = dataSourceProvider, this.permissionCacheService = permissionCacheService;
1077
+ super(_config_index_js__rspack_import_10/* .STORAGE_EVENT_ENTITIES.FILE */.fR.FILE, cacheManager, utilsService, FileManagerService.name, true, _config_index_js__rspack_import_10/* .STORAGE_EVENT_MODULE */.qh, dataSourceProvider, storageConfig.isCompanyFeatureEnabled() ? _entities_index_js__rspack_import_5.FileManagerWithCompany : _entities_index_js__rspack_import_5.FileManager), this.cacheManager = cacheManager, this.utilsService = utilsService, this.uploadService = uploadService, this.storageConfig = storageConfig, this.dataSourceProvider = dataSourceProvider, this.permissionCacheService = permissionCacheService;
1039
1078
  }
1040
1079
  // ─── Override Methods ───────────────────────────────────────────────────────
1080
+ /** Cached reads join the folder (id, name), and a hard folder delete nulls file.folder_id */ cacheDependencies() {
1081
+ return [
1082
+ this.entityName,
1083
+ _config_index_js__rspack_import_10/* .STORAGE_EVENT_ENTITIES.FOLDER */.fR.FOLDER
1084
+ ];
1085
+ }
1041
1086
  async convertSingleDtoToEntity(dto, user) {
1042
1087
  let entity = {};
1043
1088
  if ('id' in dto && dto.id && typeof dto.id === 'string') {
@@ -1048,30 +1093,36 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1048
1093
  });
1049
1094
  if (!existing) throw new _nestjs_common__rspack_import_3.NotFoundException({
1050
1095
  message: 'Entity not found for update',
1051
- messageKey: _config_index_js__rspack_import_10/* .FILE_MESSAGES.NOT_FOUND */.uA.NOT_FOUND
1096
+ messageKey: _config_index_js__rspack_import_11/* .FILE_MESSAGES.NOT_FOUND */.uA.NOT_FOUND
1052
1097
  });
1053
1098
  entity = existing;
1054
1099
  }
1055
- const validatedFolder = dto.folderId ? await this.validateFolder(dto.folderId, user) : null;
1056
- const storageLocation = await this.resolveStorageLocation(dto, user);
1057
1100
  const merged = {
1058
1101
  ...entity,
1059
1102
  ...dto,
1060
- location: storageLocation,
1061
- folder: validatedFolder
1103
+ location: await this.resolveStorageLocation(dto, user, entity.location)
1062
1104
  };
1105
+ // A partial update that leaves folderId out keeps the file where it is; null moves it to the root
1106
+ if (dto.folderId !== undefined || !entity.id) {
1107
+ merged.folder = dto.folderId ? await this.validateFolder(dto.folderId, user) : null;
1108
+ }
1063
1109
  if (this.storageConfig.isCompanyFeatureEnabled()) {
1064
1110
  merged.companyId = user?.companyId ?? null;
1065
1111
  }
1066
1112
  return merged;
1067
1113
  }
1068
- async getSelectQuery(query, _user, select) {
1114
+ /** Every read (get-all, get/:id, get-by-ids) is scoped here: company first, then private files */ async getSelectQuery(query, user, select) {
1069
1115
  const fields = (select?.length ? select : DEFAULT_SELECT_FIELDS).map((f)=>`${this.entityName}.${f}`);
1070
1116
  if (this.storageConfig.isCompanyFeatureEnabled()) {
1071
1117
  fields.push('file_manager.companyId');
1072
1118
  }
1073
1119
  fields.push('folder.id', 'folder.name');
1074
1120
  query.leftJoinAndSelect('file_manager.folder', 'folder').select(fields);
1121
+ (0,_flusys_nestjs_shared_utils__rspack_import_2.applyCompanyFilter)(query, {
1122
+ isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
1123
+ entityAlias: 'file_manager'
1124
+ }, user);
1125
+ await this.applyPrivateFileFilter(query, user);
1075
1126
  return {
1076
1127
  query,
1077
1128
  isRaw: false
@@ -1090,27 +1141,28 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1090
1141
  isRaw: false
1091
1142
  };
1092
1143
  }
1093
- async getExtraManipulateQuery(query, filterDto, user) {
1094
- const result = await super.getExtraManipulateQuery(query, filterDto, user);
1095
- (0,_flusys_nestjs_shared_utils__rspack_import_2.applyCompanyFilter)(query, {
1096
- isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
1097
- entityAlias: 'file_manager'
1098
- }, user);
1099
- await this.applyPrivateFileFilter(query, user);
1100
- return result;
1144
+ async beforeUpdateOperation(dto, user) {
1145
+ const ids = (Array.isArray(dto) ? dto : [
1146
+ dto
1147
+ ]).map((d)=>d.id).filter(Boolean);
1148
+ await this.assertInUserCompany(ids, user);
1101
1149
  }
1102
1150
  async beforeDeleteOperation(dto, user, _qr) {
1103
- if (dto.type !== 'permanent') return;
1104
1151
  const ids = Array.isArray(dto.id) ? dto.id : [
1105
1152
  dto.id
1106
1153
  ];
1107
- const files = await this.repository.findBy({
1108
- id: (0,typeorm__rspack_import_4.In)(ids)
1154
+ await this.assertInUserCompany(ids, user);
1155
+ if (dto.type !== 'permanent') return;
1156
+ const files = await this.repository.find({
1157
+ where: {
1158
+ id: (0,typeorm__rspack_import_4.In)(ids)
1159
+ },
1160
+ withDeleted: true
1109
1161
  });
1110
1162
  const grouped = this.groupFilesByConfig(files);
1111
1163
  for (const [configId, { keys, location }] of grouped){
1112
1164
  let deleteKeys = keys;
1113
- if (location === _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.LOCAL */.N.LOCAL && configId !== 'default') {
1165
+ if (location === _enums_file_location_enum_js__rspack_import_12/* .FileLocationEnum.LOCAL */.N.LOCAL && configId !== 'default') {
1114
1166
  const basePath = await this.getStorageConfigBasePath(configId);
1115
1167
  if (basePath) {
1116
1168
  deleteKeys = keys.map((k)=>k.includes('/') ? k : `${basePath}/${k}`);
@@ -1125,7 +1177,7 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1125
1177
  const ids = dtos.map((d)=>d.id).filter(Boolean);
1126
1178
  if (!ids.length) throw new _nestjs_common__rspack_import_3.BadRequestException({
1127
1179
  message: 'No valid file IDs provided',
1128
- messageKey: _config_index_js__rspack_import_10/* .UPLOAD_MESSAGES.NO_FILES_PROVIDED */.dS.NO_FILES_PROVIDED
1180
+ messageKey: _config_index_js__rspack_import_11/* .UPLOAD_MESSAGES.NO_FILES_PROVIDED */.dS.NO_FILES_PROVIDED
1129
1181
  });
1130
1182
  const fetched = await this.repository.findBy({
1131
1183
  id: (0,typeorm__rspack_import_4.In)(ids)
@@ -1141,28 +1193,25 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1141
1193
  if (updatedFiles.length) {
1142
1194
  try {
1143
1195
  await this.repository.save(updatedFiles);
1144
- await Promise.all([
1145
- this.clearCacheForAll(),
1146
- this.clearCacheForId(updatedFiles)
1147
- ]);
1148
1196
  } catch {
1149
1197
  // Silent failure - URL update is non-critical
1150
1198
  }
1199
+ await this.invalidateCache();
1151
1200
  }
1152
1201
  return responses;
1153
1202
  }
1154
1203
  // ─── Private Helpers ────────────────────────────────────────────────────────
1155
1204
  buildWhereWithCompany(id, user) {
1156
- const where = {
1205
+ return (0,_flusys_nestjs_shared_utils__rspack_import_2.buildCompanyWhereCondition)({
1157
1206
  id
1158
- };
1159
- if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
1160
- where.companyId = user.companyId;
1161
- }
1162
- return where;
1207
+ }, this.storageConfig.isCompanyFeatureEnabled(), user);
1208
+ }
1209
+ async assertInUserCompany(ids, user) {
1210
+ await this.ensureDataSourceRepository();
1211
+ await (0,_utils_company_ownership_util_js__rspack_import_6/* .assertRowsInUserCompany */.p)(this.repository, ids, user, this.storageConfig.isCompanyFeatureEnabled(), 'File');
1163
1212
  }
1164
1213
  async getStorageConfigRepository() {
1165
- const entity = this.storageConfig.isCompanyFeatureEnabled() ? (await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 975))).StorageConfigWithCompany : (await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 975))).StorageConfig;
1214
+ const entity = this.storageConfig.isCompanyFeatureEnabled() ? (await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 1975))).StorageConfigWithCompany : (await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 1975))).StorageConfig;
1166
1215
  return this.dataSourceProvider.getRepository(entity);
1167
1216
  }
1168
1217
  async getStorageConfigBasePath(configId) {
@@ -1191,7 +1240,7 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1191
1240
  if (!folder) {
1192
1241
  throw new _nestjs_common__rspack_import_3.BadRequestException({
1193
1242
  message: `Folder "${folderId}" not found or access denied`,
1194
- messageKey: _config_index_js__rspack_import_10/* .FOLDER_MESSAGES.NOT_FOUND */.Ee.NOT_FOUND,
1243
+ messageKey: _config_index_js__rspack_import_11/* .FOLDER_MESSAGES.NOT_FOUND */.Ee.NOT_FOUND,
1195
1244
  messageVariables: {
1196
1245
  folderId
1197
1246
  }
@@ -1199,22 +1248,23 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1199
1248
  }
1200
1249
  return folder;
1201
1250
  }
1202
- async resolveStorageLocation(dto, user) {
1251
+ async resolveStorageLocation(dto, user, currentLocation) {
1252
+ const fallback = dto.location || currentLocation || _enums_file_location_enum_js__rspack_import_12/* .FileLocationEnum.LOCAL */.N.LOCAL;
1203
1253
  const configId = dto.storageConfigId;
1204
- if (!configId) return dto.location || _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.LOCAL */.N.LOCAL;
1254
+ if (!configId) return fallback;
1205
1255
  try {
1206
1256
  const repo = await this.getStorageConfigRepository();
1207
1257
  const config = await repo.findOne({
1208
1258
  where: this.buildWhereWithCompany(configId, user)
1209
1259
  });
1210
- return config?.storage || dto.location || _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.LOCAL */.N.LOCAL;
1260
+ return config?.storage || fallback;
1211
1261
  } catch {
1212
- return dto.location || _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.LOCAL */.N.LOCAL;
1262
+ return fallback;
1213
1263
  }
1214
1264
  }
1215
1265
  applyContentTypeFilter(query, value) {
1216
1266
  const patterns = value.split(',').map((t)=>t.trim().replace('*', '%'));
1217
- query.where(new typeorm__rspack_import_4.Brackets((qb)=>{
1267
+ query.andWhere(new typeorm__rspack_import_4.Brackets((qb)=>{
1218
1268
  patterns.forEach((p, i)=>{
1219
1269
  const method = i === 0 ? 'where' : 'orWhere';
1220
1270
  qb[method](`${this.entityName}.contentType LIKE :p${i}`, {
@@ -1230,8 +1280,8 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1230
1280
  * for any file ID, including other companies' or other users' private files.
1231
1281
  */ async scopeFilesToRequester(files, user) {
1232
1282
  let scoped = files;
1233
- if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
1234
- scoped = scoped.filter((file)=>file.companyId === user.companyId);
1283
+ if (this.storageConfig.isCompanyFeatureEnabled() && user) {
1284
+ scoped = user.companyId ? scoped.filter((file)=>file.companyId === user.companyId) : [];
1235
1285
  }
1236
1286
  const canViewPrivate = user ? await this.permissionCacheService.hasPermission({
1237
1287
  userId: user.id,
@@ -1280,7 +1330,7 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1280
1330
  return appUrl || `${protocol}://${host}`;
1281
1331
  }
1282
1332
  async refreshFileUrl(file, protocol, host, now, user) {
1283
- const isCloudProvider = file.location === _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.AWS */.N.AWS || file.location === _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.AZURE */.N.AZURE;
1333
+ const isCloudProvider = file.location === _enums_file_location_enum_js__rspack_import_12/* .FileLocationEnum.AWS */.N.AWS || file.location === _enums_file_location_enum_js__rspack_import_12/* .FileLocationEnum.AZURE */.N.AZURE;
1284
1334
  const needsNewUrl = !file.url || isCloudProvider && (typeof file.expiresAt !== 'number' || now >= file.expiresAt);
1285
1335
  if (needsNewUrl && file.storageConfigId) {
1286
1336
  try {
@@ -1291,7 +1341,7 @@ class FileManagerService extends _flusys_nestjs_shared_classes__rspack_import_0.
1291
1341
  file.url = `${this.getFileBaseUrl(protocol, host)}/storage/upload/file/${file.key}`;
1292
1342
  }
1293
1343
  }
1294
- if (file.location === _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.SFTP */.N.SFTP || file.location === _enums_file_location_enum_js__rspack_import_11/* .FileLocationEnum.LOCAL */.N.LOCAL) {
1344
+ if (file.location === _enums_file_location_enum_js__rspack_import_12/* .FileLocationEnum.SFTP */.N.SFTP || file.location === _enums_file_location_enum_js__rspack_import_12/* .FileLocationEnum.LOCAL */.N.LOCAL) {
1295
1345
  let fileKey = file.key;
1296
1346
  if (!fileKey.includes('/') && file.storageConfigId) {
1297
1347
  const basePath = await this.getStorageConfigBasePath(file.storageConfigId);
@@ -1322,32 +1372,33 @@ FileManagerService = _ts_decorate([
1322
1372
  }),
1323
1373
  _ts_param(0, (0,_nestjs_common__rspack_import_3.Inject)('CACHE_INSTANCE')),
1324
1374
  _ts_param(1, (0,_nestjs_common__rspack_import_3.Inject)(_flusys_nestjs_shared_modules__rspack_import_1.UtilsService)),
1325
- _ts_param(2, (0,_nestjs_common__rspack_import_3.Inject)(_upload_service_js__rspack_import_8/* .UploadService */.B)),
1326
- _ts_param(3, (0,_nestjs_common__rspack_import_3.Inject)(_storage_config_service_js__rspack_import_6/* .StorageConfigService */.t)),
1327
- _ts_param(4, (0,_nestjs_common__rspack_import_3.Inject)(_storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M)),
1375
+ _ts_param(2, (0,_nestjs_common__rspack_import_3.Inject)(_upload_service_js__rspack_import_9/* .UploadService */.B)),
1376
+ _ts_param(3, (0,_nestjs_common__rspack_import_3.Inject)(_storage_config_service_js__rspack_import_7/* .StorageConfigService */.t)),
1377
+ _ts_param(4, (0,_nestjs_common__rspack_import_3.Inject)(_storage_datasource_provider_js__rspack_import_8/* .StorageDataSourceProvider */.M)),
1328
1378
  _ts_param(5, (0,_nestjs_common__rspack_import_3.Inject)(_flusys_nestjs_shared_modules__rspack_import_1.SharedPermissionCacheService)),
1329
1379
  _ts_metadata("design:type", Function),
1330
1380
  _ts_metadata("design:paramtypes", [
1331
1381
  typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
1332
1382
  typeof _flusys_nestjs_shared_modules__rspack_import_1.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_1.UtilsService,
1333
- typeof _upload_service_js__rspack_import_8/* .UploadService */.B === "undefined" ? Object : _upload_service_js__rspack_import_8/* .UploadService */.B,
1334
- typeof _storage_config_service_js__rspack_import_6/* .StorageConfigService */.t === "undefined" ? Object : _storage_config_service_js__rspack_import_6/* .StorageConfigService */.t,
1335
- typeof _storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M === "undefined" ? Object : _storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M,
1383
+ typeof _upload_service_js__rspack_import_9/* .UploadService */.B === "undefined" ? Object : _upload_service_js__rspack_import_9/* .UploadService */.B,
1384
+ typeof _storage_config_service_js__rspack_import_7/* .StorageConfigService */.t === "undefined" ? Object : _storage_config_service_js__rspack_import_7/* .StorageConfigService */.t,
1385
+ typeof _storage_datasource_provider_js__rspack_import_8/* .StorageDataSourceProvider */.M === "undefined" ? Object : _storage_datasource_provider_js__rspack_import_8/* .StorageDataSourceProvider */.M,
1336
1386
  typeof _flusys_nestjs_shared_modules__rspack_import_1.SharedPermissionCacheService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_1.SharedPermissionCacheService
1337
1387
  ])
1338
1388
  ], FileManagerService);
1339
1389
 
1340
1390
 
1341
1391
  },
1342
- 195(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1343
- /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(937);
1344
- /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(236);
1345
- /* import */ var _flusys_nestjs_shared_utils__rspack_import_2 = __webpack_require__(216);
1346
- /* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(157);
1347
- /* import */ var _config_index_js__rspack_import_7 = __webpack_require__(884);
1348
- /* import */ var _entities_index_js__rspack_import_4 = __webpack_require__(975);
1349
- /* import */ var _storage_config_service_js__rspack_import_5 = __webpack_require__(397);
1350
- /* import */ var _storage_datasource_provider_js__rspack_import_6 = __webpack_require__(616);
1392
+ 8195(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1393
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
1394
+ /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(1236);
1395
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_2 = __webpack_require__(9216);
1396
+ /* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(6157);
1397
+ /* import */ var _config_index_js__rspack_import_8 = __webpack_require__(4884);
1398
+ /* import */ var _entities_index_js__rspack_import_4 = __webpack_require__(1975);
1399
+ /* import */ var _utils_company_ownership_util_js__rspack_import_5 = __webpack_require__(5198);
1400
+ /* import */ var _storage_config_service_js__rspack_import_6 = __webpack_require__(6397);
1401
+ /* import */ var _storage_datasource_provider_js__rspack_import_7 = __webpack_require__(8616);
1351
1402
  function _ts_decorate(decorators, target, key, desc) {
1352
1403
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1353
1404
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -1379,12 +1430,13 @@ function _ts_param(paramIndex, decorator) {
1379
1430
 
1380
1431
 
1381
1432
 
1433
+
1382
1434
  class FolderService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiService {
1383
1435
  cacheManager;
1384
1436
  utilsService;
1385
1437
  storageConfig;
1386
1438
  constructor(cacheManager, utilsService, storageConfig, dataSourceProvider){
1387
- super(_config_index_js__rspack_import_7/* .STORAGE_EVENT_ENTITIES.FOLDER */.fR.FOLDER, cacheManager, utilsService, FolderService.name, true, _config_index_js__rspack_import_7/* .STORAGE_EVENT_MODULE */.qh, dataSourceProvider, storageConfig.isCompanyFeatureEnabled() ? _entities_index_js__rspack_import_4.FolderWithCompany : _entities_index_js__rspack_import_4.Folder), this.cacheManager = cacheManager, this.utilsService = utilsService, this.storageConfig = storageConfig;
1439
+ super(_config_index_js__rspack_import_8/* .STORAGE_EVENT_ENTITIES.FOLDER */.fR.FOLDER, cacheManager, utilsService, FolderService.name, true, _config_index_js__rspack_import_8/* .STORAGE_EVENT_MODULE */.qh, dataSourceProvider, storageConfig.isCompanyFeatureEnabled() ? _entities_index_js__rspack_import_4.FolderWithCompany : _entities_index_js__rspack_import_4.Folder), this.cacheManager = cacheManager, this.utilsService = utilsService, this.storageConfig = storageConfig;
1388
1440
  }
1389
1441
  // ─── Override Methods ───────────────────────────────────────────────────────
1390
1442
  async convertSingleDtoToEntity(dto, user) {
@@ -1394,7 +1446,7 @@ class FolderService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiSe
1394
1446
  }
1395
1447
  return entity;
1396
1448
  }
1397
- async getSelectQuery(query, _user, select) {
1449
+ async getSelectQuery(query, user, select) {
1398
1450
  if (!select?.length) {
1399
1451
  select = [
1400
1452
  'id',
@@ -1408,18 +1460,28 @@ class FolderService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiSe
1408
1460
  }
1409
1461
  }
1410
1462
  query.select(select.map((f)=>`${this.entityName}.${f}`));
1463
+ (0,_flusys_nestjs_shared_utils__rspack_import_2.applyCompanyFilter)(query, {
1464
+ isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
1465
+ entityAlias: 'folder'
1466
+ }, user);
1411
1467
  return {
1412
1468
  query,
1413
1469
  isRaw: false
1414
1470
  };
1415
1471
  }
1416
- async getExtraManipulateQuery(query, filterDto, user) {
1417
- const result = await super.getExtraManipulateQuery(query, filterDto, user);
1418
- (0,_flusys_nestjs_shared_utils__rspack_import_2.applyCompanyFilter)(query, {
1419
- isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
1420
- entityAlias: 'folder'
1421
- }, user);
1422
- return result;
1472
+ async beforeUpdateOperation(dto, user) {
1473
+ await this.assertInUserCompany((Array.isArray(dto) ? dto : [
1474
+ dto
1475
+ ]).map((d)=>d.id), user);
1476
+ }
1477
+ async beforeDeleteOperation(dto, user) {
1478
+ await this.assertInUserCompany(Array.isArray(dto.id) ? dto.id : [
1479
+ dto.id
1480
+ ], user);
1481
+ }
1482
+ async assertInUserCompany(ids, user) {
1483
+ await this.ensureDataSourceRepository();
1484
+ await (0,_utils_company_ownership_util_js__rspack_import_5/* .assertRowsInUserCompany */.p)(this.repository, ids.filter(Boolean), user, this.storageConfig.isCompanyFeatureEnabled(), 'Folder');
1423
1485
  }
1424
1486
  }
1425
1487
  FolderService = _ts_decorate([
@@ -1428,14 +1490,14 @@ FolderService = _ts_decorate([
1428
1490
  }),
1429
1491
  _ts_param(0, (0,_nestjs_common__rspack_import_3.Inject)('CACHE_INSTANCE')),
1430
1492
  _ts_param(1, (0,_nestjs_common__rspack_import_3.Inject)(_flusys_nestjs_shared_modules__rspack_import_1.UtilsService)),
1431
- _ts_param(2, (0,_nestjs_common__rspack_import_3.Inject)(_storage_config_service_js__rspack_import_5/* .StorageConfigService */.t)),
1432
- _ts_param(3, (0,_nestjs_common__rspack_import_3.Inject)(_storage_datasource_provider_js__rspack_import_6/* .StorageDataSourceProvider */.M)),
1493
+ _ts_param(2, (0,_nestjs_common__rspack_import_3.Inject)(_storage_config_service_js__rspack_import_6/* .StorageConfigService */.t)),
1494
+ _ts_param(3, (0,_nestjs_common__rspack_import_3.Inject)(_storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M)),
1433
1495
  _ts_metadata("design:type", Function),
1434
1496
  _ts_metadata("design:paramtypes", [
1435
1497
  typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
1436
1498
  typeof _flusys_nestjs_shared_modules__rspack_import_1.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_1.UtilsService,
1437
- typeof _storage_config_service_js__rspack_import_5/* .StorageConfigService */.t === "undefined" ? Object : _storage_config_service_js__rspack_import_5/* .StorageConfigService */.t,
1438
- typeof _storage_datasource_provider_js__rspack_import_6/* .StorageDataSourceProvider */.M === "undefined" ? Object : _storage_datasource_provider_js__rspack_import_6/* .StorageDataSourceProvider */.M
1499
+ typeof _storage_config_service_js__rspack_import_6/* .StorageConfigService */.t === "undefined" ? Object : _storage_config_service_js__rspack_import_6/* .StorageConfigService */.t,
1500
+ typeof _storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M === "undefined" ? Object : _storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M
1439
1501
  ])
1440
1502
  ], FolderService);
1441
1503
 
@@ -1445,7 +1507,7 @@ __webpack_require__.d(__webpack_exports__, {
1445
1507
 
1446
1508
 
1447
1509
  },
1448
- 148(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1510
+ 4148(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1449
1511
  __webpack_require__.d(__webpack_exports__, {
1450
1512
  BB: () => (/* reexport safe */ _upload_service_js__rspack_import_5.B),
1451
1513
  DL: () => (/* reexport safe */ _file_manager_service_js__rspack_import_0.D),
@@ -1454,12 +1516,12 @@ __webpack_require__.d(__webpack_exports__, {
1454
1516
  ol: () => (/* reexport safe */ _storage_provider_config_service_js__rspack_import_3.o),
1455
1517
  tP: () => (/* reexport safe */ _storage_config_service_js__rspack_import_2.t)
1456
1518
  });
1457
- /* import */ var _file_manager_service_js__rspack_import_0 = __webpack_require__(955);
1458
- /* import */ var _folder_service_js__rspack_import_1 = __webpack_require__(195);
1459
- /* import */ var _storage_config_service_js__rspack_import_2 = __webpack_require__(397);
1460
- /* import */ var _storage_provider_config_service_js__rspack_import_3 = __webpack_require__(623);
1461
- /* import */ var _storage_datasource_provider_js__rspack_import_4 = __webpack_require__(616);
1462
- /* import */ var _upload_service_js__rspack_import_5 = __webpack_require__(18);
1519
+ /* import */ var _file_manager_service_js__rspack_import_0 = __webpack_require__(7955);
1520
+ /* import */ var _folder_service_js__rspack_import_1 = __webpack_require__(8195);
1521
+ /* import */ var _storage_config_service_js__rspack_import_2 = __webpack_require__(6397);
1522
+ /* import */ var _storage_provider_config_service_js__rspack_import_3 = __webpack_require__(8623);
1523
+ /* import */ var _storage_datasource_provider_js__rspack_import_4 = __webpack_require__(8616);
1524
+ /* import */ var _upload_service_js__rspack_import_5 = __webpack_require__(5018);
1463
1525
 
1464
1526
 
1465
1527
 
@@ -1469,10 +1531,10 @@ __webpack_require__.d(__webpack_exports__, {
1469
1531
 
1470
1532
 
1471
1533
  },
1472
- 397(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1473
- /* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(157);
1474
- /* import */ var _config_index_js__rspack_import_2 = __webpack_require__(450);
1475
- /* import */ var _config_storage_constants_js__rspack_import_1 = __webpack_require__(188);
1534
+ 6397(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1535
+ /* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
1536
+ /* import */ var _config_index_js__rspack_import_2 = __webpack_require__(5450);
1537
+ /* import */ var _config_storage_constants_js__rspack_import_1 = __webpack_require__(9188);
1476
1538
  function _ts_decorate(decorators, target, key, desc) {
1477
1539
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1478
1540
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -1539,7 +1601,7 @@ class StorageConfigService {
1539
1601
  if (allowedTypes.includes('*/*')) {
1540
1602
  return true;
1541
1603
  }
1542
- return allowedTypes.some((type)=>type.endsWith('/*') ? mimeType.startsWith(type.slice(0, -2)) : type === mimeType);
1604
+ return allowedTypes.some((type)=>type.endsWith('/*') ? mimeType.startsWith(type.slice(0, -1)) : type === mimeType);
1543
1605
  }
1544
1606
  validateFileSize(fileSize) {
1545
1607
  const maxSize = this.getMaxFileSize();
@@ -1594,7 +1656,7 @@ __webpack_require__.d(__webpack_exports__, {
1594
1656
 
1595
1657
 
1596
1658
  },
1597
- 616(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1659
+ 8616(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1598
1660
 
1599
1661
  // EXPORTS
1600
1662
  __webpack_require__.d(__webpack_exports__, {
@@ -1602,13 +1664,13 @@ __webpack_require__.d(__webpack_exports__, {
1602
1664
  });
1603
1665
 
1604
1666
  // EXTERNAL MODULE: external "@flusys/nestjs-shared/modules"
1605
- var modules_ = __webpack_require__(236);
1667
+ var modules_ = __webpack_require__(1236);
1606
1668
  // EXTERNAL MODULE: external "@nestjs/common"
1607
- var common_ = __webpack_require__(157);
1669
+ var common_ = __webpack_require__(6157);
1608
1670
  ;// CONCATENATED MODULE: external "@nestjs/core"
1609
1671
 
1610
1672
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/services/storage-config.service.ts
1611
- var storage_config_service = __webpack_require__(397);
1673
+ var storage_config_service = __webpack_require__(6397);
1612
1674
  ;// CONCATENATED MODULE: ./projects/nestjs-storage/src/services/storage-datasource.provider.ts
1613
1675
  function _ts_decorate(decorators, target, key, desc) {
1614
1676
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -1661,7 +1723,7 @@ class StorageDataSourceProvider extends modules_.MultiTenantDataSourceService {
1661
1723
  }
1662
1724
  async getStorageEntities(enableCompanyFeature) {
1663
1725
  const enable = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
1664
- const entities = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 975));
1726
+ const entities = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 1975));
1665
1727
  return enable ? [
1666
1728
  entities.FileManagerWithCompany,
1667
1729
  entities.FolderWithCompany,
@@ -1695,17 +1757,20 @@ StorageDataSourceProvider = _ts_decorate([
1695
1757
 
1696
1758
 
1697
1759
  },
1698
- 623(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1699
- /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(937);
1700
- /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(236);
1701
- /* import */ var _flusys_nestjs_shared_utils__rspack_import_2 = __webpack_require__(216);
1702
- /* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(157);
1703
- /* import */ var typeorm__rspack_import_4 = __webpack_require__(158);
1704
- /* import */ var _config_index_js__rspack_import_8 = __webpack_require__(884);
1705
- /* import */ var _config_index_js__rspack_import_9 = __webpack_require__(450);
1706
- /* import */ var _entities_index_js__rspack_import_5 = __webpack_require__(975);
1707
- /* import */ var _storage_config_service_js__rspack_import_6 = __webpack_require__(397);
1708
- /* import */ var _storage_datasource_provider_js__rspack_import_7 = __webpack_require__(616);
1760
+ 8623(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1761
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
1762
+ /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(1236);
1763
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_2 = __webpack_require__(9216);
1764
+ /* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(6157);
1765
+ /* import */ var path__rspack_import_4 = __webpack_require__(2521);
1766
+ /* import */ var typeorm__rspack_import_5 = __webpack_require__(7158);
1767
+ /* import */ var _config_index_js__rspack_import_10 = __webpack_require__(4884);
1768
+ /* import */ var _config_index_js__rspack_import_11 = __webpack_require__(5450);
1769
+ /* import */ var _enums_file_location_enum_js__rspack_import_12 = __webpack_require__(2733);
1770
+ /* import */ var _entities_index_js__rspack_import_6 = __webpack_require__(1975);
1771
+ /* import */ var _utils_company_ownership_util_js__rspack_import_7 = __webpack_require__(5198);
1772
+ /* import */ var _storage_config_service_js__rspack_import_8 = __webpack_require__(6397);
1773
+ /* import */ var _storage_datasource_provider_js__rspack_import_9 = __webpack_require__(8616);
1709
1774
  function _ts_decorate(decorators, target, key, desc) {
1710
1775
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1711
1776
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -1738,30 +1803,39 @@ function _ts_param(paramIndex, decorator) {
1738
1803
 
1739
1804
 
1740
1805
 
1806
+
1807
+
1808
+
1741
1809
  class StorageProviderConfigService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiService {
1742
1810
  cacheManager;
1743
1811
  utilsService;
1744
1812
  storageConfig;
1745
1813
  constructor(cacheManager, utilsService, storageConfig, dataSourceProvider){
1746
- super(_config_index_js__rspack_import_8/* .STORAGE_EVENT_ENTITIES.STORAGE_CONFIG */.fR.STORAGE_CONFIG, cacheManager, utilsService, StorageProviderConfigService.name, true, _config_index_js__rspack_import_8/* .STORAGE_EVENT_MODULE */.qh, dataSourceProvider, storageConfig.isCompanyFeatureEnabled() ? _entities_index_js__rspack_import_5.StorageConfigWithCompany : _entities_index_js__rspack_import_5.StorageConfig), this.cacheManager = cacheManager, this.utilsService = utilsService, this.storageConfig = storageConfig;
1814
+ super(_config_index_js__rspack_import_10/* .STORAGE_EVENT_ENTITIES.STORAGE_CONFIG */.fR.STORAGE_CONFIG, cacheManager, utilsService, StorageProviderConfigService.name, // Rows carry provider credentials - keep them out of the shared cache
1815
+ false, _config_index_js__rspack_import_10/* .STORAGE_EVENT_MODULE */.qh, dataSourceProvider, storageConfig.isCompanyFeatureEnabled() ? _entities_index_js__rspack_import_6.StorageConfigWithCompany : _entities_index_js__rspack_import_6.StorageConfig), this.cacheManager = cacheManager, this.utilsService = utilsService, this.storageConfig = storageConfig;
1816
+ }
1817
+ async beforeUpdateOperation(dto, user) {
1818
+ await this.assertInUserCompany((Array.isArray(dto) ? dto : [
1819
+ dto
1820
+ ]).map((d)=>d.id), user);
1747
1821
  }
1748
- async beforeDeleteOperation(dto, _user, _queryRunner) {
1822
+ async beforeDeleteOperation(dto, user, _queryRunner) {
1749
1823
  const ids = Array.isArray(dto.id) ? dto.id : [
1750
1824
  dto.id
1751
1825
  ];
1752
- await this.ensureDataSourceRepository();
1826
+ await this.assertInUserCompany(ids, user);
1753
1827
  const defaultConfigs = await this.repository.find({
1754
1828
  where: {
1755
- id: (0,typeorm__rspack_import_4.In)(ids),
1829
+ id: (0,typeorm__rspack_import_5.In)(ids),
1756
1830
  isDefault: true,
1757
- deletedAt: (0,typeorm__rspack_import_4.IsNull)()
1831
+ deletedAt: (0,typeorm__rspack_import_5.IsNull)()
1758
1832
  }
1759
1833
  });
1760
1834
  if (defaultConfigs.length > 0) {
1761
1835
  const names = defaultConfigs.map((c)=>c.name).join(', ');
1762
1836
  throw new _nestjs_common__rspack_import_3.ForbiddenException({
1763
1837
  message: `Cannot delete the default storage config(s): ${names}. Set another config as default first.`,
1764
- messageKey: _config_index_js__rspack_import_9/* .STORAGE_CONFIG_MESSAGES.DEFAULT_DELETE_FORBIDDEN */.Y8.DEFAULT_DELETE_FORBIDDEN,
1838
+ messageKey: _config_index_js__rspack_import_11/* .STORAGE_CONFIG_MESSAGES.DEFAULT_DELETE_FORBIDDEN */.Y8.DEFAULT_DELETE_FORBIDDEN,
1765
1839
  messageVariables: {
1766
1840
  names
1767
1841
  }
@@ -1776,7 +1850,7 @@ class StorageProviderConfigService extends _flusys_nestjs_shared_classes__rspack
1776
1850
  }
1777
1851
  return entity;
1778
1852
  }
1779
- async getSelectQuery(query, _user, select) {
1853
+ async getSelectQuery(query, user, select) {
1780
1854
  if (!select?.length) {
1781
1855
  select = [
1782
1856
  'id',
@@ -1793,6 +1867,10 @@ class StorageProviderConfigService extends _flusys_nestjs_shared_classes__rspack
1793
1867
  }
1794
1868
  }
1795
1869
  query.select(select.map((f)=>`${this.entityName}.${f}`));
1870
+ (0,_flusys_nestjs_shared_utils__rspack_import_2.applyCompanyFilter)(query, {
1871
+ isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
1872
+ entityAlias: this.entityName
1873
+ }, user);
1796
1874
  return {
1797
1875
  query,
1798
1876
  isRaw: false
@@ -1800,10 +1878,6 @@ class StorageProviderConfigService extends _flusys_nestjs_shared_classes__rspack
1800
1878
  }
1801
1879
  async getExtraManipulateQuery(query, filterDto, user) {
1802
1880
  const result = await super.getExtraManipulateQuery(query, filterDto, user);
1803
- (0,_flusys_nestjs_shared_utils__rspack_import_2.applyCompanyFilter)(query, {
1804
- isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
1805
- entityAlias: 'storageConfig'
1806
- }, user);
1807
1881
  query.orderBy(`${this.entityName}.createdAt`, 'DESC');
1808
1882
  return result;
1809
1883
  }
@@ -1839,6 +1913,10 @@ class StorageProviderConfigService extends _flusys_nestjs_shared_classes__rspack
1839
1913
  }
1840
1914
  });
1841
1915
  }
1916
+ async assertInUserCompany(ids, user) {
1917
+ await this.ensureDataSourceRepository();
1918
+ await (0,_utils_company_ownership_util_js__rspack_import_7/* .assertRowsInUserCompany */.p)(this.repository, ids.filter(Boolean), user, this.storageConfig.isCompanyFeatureEnabled(), 'Storage configuration');
1919
+ }
1842
1920
  async getConfigByType(storage, user) {
1843
1921
  await this.ensureDataSourceRepository();
1844
1922
  const where = (0,_flusys_nestjs_shared_utils__rspack_import_2.buildCompanyWhereCondition)({
@@ -1849,6 +1927,42 @@ class StorageProviderConfigService extends _flusys_nestjs_shared_classes__rspack
1849
1927
  where
1850
1928
  });
1851
1929
  }
1930
+ /**
1931
+ * Absolute storage roots of every active local config in the current tenant, resolved the way
1932
+ * LocalProvider resolves them. Cached under the storage-config stamp, which every config write
1933
+ * moves, so an edited or deactivated config stops being served on all instances.
1934
+ */ async getActiveLocalBasePaths() {
1935
+ await this.ensureDataSourceRepository();
1936
+ const tenantId = this.cacheTenant();
1937
+ let cacheKey = null;
1938
+ try {
1939
+ const stamp = await this.utilsService.getCacheStamp(this.cacheManager, [
1940
+ this.entityName
1941
+ ], tenantId);
1942
+ cacheKey = this.utilsService.getCacheKey(this.entityName, {
1943
+ localBasePaths: true
1944
+ }, undefined, tenantId, stamp);
1945
+ const cached = await this.cacheManager.get(cacheKey);
1946
+ if (cached) return cached;
1947
+ } catch {
1948
+ cacheKey = null;
1949
+ }
1950
+ const configs = await this.repository.find({
1951
+ where: {
1952
+ storage: _enums_file_location_enum_js__rspack_import_12/* .FileLocationEnum.LOCAL */.N.LOCAL,
1953
+ isActive: true
1954
+ },
1955
+ select: [
1956
+ 'id',
1957
+ 'config'
1958
+ ]
1959
+ });
1960
+ const basePaths = [
1961
+ ...new Set(configs.map((c)=>path__rspack_import_4.resolve(c.config?.basePath || './uploads')))
1962
+ ];
1963
+ if (cacheKey) await this.cacheManager.set(cacheKey, basePaths).catch(()=>undefined);
1964
+ return basePaths;
1965
+ }
1852
1966
  }
1853
1967
  StorageProviderConfigService = _ts_decorate([
1854
1968
  (0,_nestjs_common__rspack_import_3.Injectable)({
@@ -1856,14 +1970,14 @@ StorageProviderConfigService = _ts_decorate([
1856
1970
  }),
1857
1971
  _ts_param(0, (0,_nestjs_common__rspack_import_3.Inject)('CACHE_INSTANCE')),
1858
1972
  _ts_param(1, (0,_nestjs_common__rspack_import_3.Inject)(_flusys_nestjs_shared_modules__rspack_import_1.UtilsService)),
1859
- _ts_param(2, (0,_nestjs_common__rspack_import_3.Inject)(_storage_config_service_js__rspack_import_6/* .StorageConfigService */.t)),
1860
- _ts_param(3, (0,_nestjs_common__rspack_import_3.Inject)(_storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M)),
1973
+ _ts_param(2, (0,_nestjs_common__rspack_import_3.Inject)(_storage_config_service_js__rspack_import_8/* .StorageConfigService */.t)),
1974
+ _ts_param(3, (0,_nestjs_common__rspack_import_3.Inject)(_storage_datasource_provider_js__rspack_import_9/* .StorageDataSourceProvider */.M)),
1861
1975
  _ts_metadata("design:type", Function),
1862
1976
  _ts_metadata("design:paramtypes", [
1863
1977
  typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
1864
1978
  typeof _flusys_nestjs_shared_modules__rspack_import_1.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_1.UtilsService,
1865
- typeof _storage_config_service_js__rspack_import_6/* .StorageConfigService */.t === "undefined" ? Object : _storage_config_service_js__rspack_import_6/* .StorageConfigService */.t,
1866
- typeof _storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M === "undefined" ? Object : _storage_datasource_provider_js__rspack_import_7/* .StorageDataSourceProvider */.M
1979
+ typeof _storage_config_service_js__rspack_import_8/* .StorageConfigService */.t === "undefined" ? Object : _storage_config_service_js__rspack_import_8/* .StorageConfigService */.t,
1980
+ typeof _storage_datasource_provider_js__rspack_import_9/* .StorageDataSourceProvider */.M === "undefined" ? Object : _storage_datasource_provider_js__rspack_import_9/* .StorageDataSourceProvider */.M
1867
1981
  ])
1868
1982
  ], StorageProviderConfigService);
1869
1983
 
@@ -1873,7 +1987,7 @@ __webpack_require__.d(__webpack_exports__, {
1873
1987
 
1874
1988
 
1875
1989
  },
1876
- 18(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1990
+ 5018(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1877
1991
 
1878
1992
  // EXPORTS
1879
1993
  __webpack_require__.d(__webpack_exports__, {
@@ -1881,23 +1995,23 @@ __webpack_require__.d(__webpack_exports__, {
1881
1995
  });
1882
1996
 
1883
1997
  // EXTERNAL MODULE: external "@flusys/nestjs-shared"
1884
- var nestjs_shared_ = __webpack_require__(422);
1998
+ var nestjs_shared_ = __webpack_require__(3422);
1885
1999
  // EXTERNAL MODULE: external "@flusys/nestjs-shared/classes"
1886
- var classes_ = __webpack_require__(937);
2000
+ var classes_ = __webpack_require__(6937);
1887
2001
  // EXTERNAL MODULE: external "@flusys/nestjs-shared/utils"
1888
- var utils_ = __webpack_require__(216);
2002
+ var utils_ = __webpack_require__(9216);
1889
2003
  // EXTERNAL MODULE: external "@nestjs/common"
1890
- var common_ = __webpack_require__(157);
2004
+ var common_ = __webpack_require__(6157);
1891
2005
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/config/message-keys.ts
1892
- var message_keys = __webpack_require__(450);
2006
+ var message_keys = __webpack_require__(5450);
1893
2007
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/config/event-actions.ts
1894
- var event_actions = __webpack_require__(884);
2008
+ var event_actions = __webpack_require__(4884);
1895
2009
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/dtos/upload.dto.ts
1896
- var upload_dto = __webpack_require__(322);
2010
+ var upload_dto = __webpack_require__(7322);
1897
2011
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/enums/file-location.enum.ts
1898
- var file_location_enum = __webpack_require__(733);
2012
+ var file_location_enum = __webpack_require__(2733);
1899
2013
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/providers/storage-factory.service.ts + 1 modules
1900
- var storage_factory_service = __webpack_require__(192);
2014
+ var storage_factory_service = __webpack_require__(2192);
1901
2015
  ;// CONCATENATED MODULE: ./projects/nestjs-storage/src/utils/file-validator.util.ts
1902
2016
  /**
1903
2017
  * Result of file content validation.
@@ -1963,12 +2077,12 @@ var storage_factory_service = __webpack_require__(192);
1963
2077
  },
1964
2078
  {
1965
2079
  signature: [
1966
- 0x52,
1967
- 0x49,
1968
- 0x46,
1969
- 0x46
2080
+ 0x57,
2081
+ 0x45,
2082
+ 0x42,
2083
+ 0x50
1970
2084
  ],
1971
- offset: 0,
2085
+ offset: 8,
1972
2086
  mimeType: 'image/webp'
1973
2087
  },
1974
2088
  {
@@ -2058,33 +2172,25 @@ var storage_factory_service = __webpack_require__(192);
2058
2172
  offset: 0,
2059
2173
  mimeType: 'audio/flac'
2060
2174
  },
2061
- // Video
2062
2175
  {
2063
2176
  signature: [
2064
- 0x00,
2065
- 0x00,
2066
- 0x00,
2067
- 0x1c,
2068
- 0x66,
2069
- 0x74,
2070
- 0x79,
2071
- 0x70
2177
+ 0x57,
2178
+ 0x41,
2179
+ 0x56,
2180
+ 0x45
2072
2181
  ],
2073
- offset: 0,
2074
- mimeType: 'video/mp4'
2182
+ offset: 8,
2183
+ mimeType: 'audio/wav'
2075
2184
  },
2185
+ // Video
2076
2186
  {
2077
2187
  signature: [
2078
- 0x00,
2079
- 0x00,
2080
- 0x00,
2081
- 0x20,
2082
2188
  0x66,
2083
2189
  0x74,
2084
2190
  0x79,
2085
2191
  0x70
2086
2192
  ],
2087
- offset: 0,
2193
+ offset: 4,
2088
2194
  mimeType: 'video/mp4'
2089
2195
  },
2090
2196
  {
@@ -2099,12 +2205,12 @@ var storage_factory_service = __webpack_require__(192);
2099
2205
  },
2100
2206
  {
2101
2207
  signature: [
2102
- 0x52,
2208
+ 0x41,
2209
+ 0x56,
2103
2210
  0x49,
2104
- 0x46,
2105
- 0x46
2211
+ 0x20
2106
2212
  ],
2107
- offset: 0,
2213
+ offset: 8,
2108
2214
  mimeType: 'video/avi'
2109
2215
  },
2110
2216
  // Archives
@@ -2237,7 +2343,8 @@ var storage_factory_service = __webpack_require__(192);
2237
2343
  /**
2238
2344
  * Check if a MIME type is a dangerous text type that can execute scripts.
2239
2345
  */ static isDangerousTextType(mimeType) {
2240
- return DANGEROUS_TEXT_TYPES.some((t)=>mimeType === t);
2346
+ const baseType = mimeType.split(';')[0].trim().toLowerCase();
2347
+ return DANGEROUS_TEXT_TYPES.includes(baseType);
2241
2348
  }
2242
2349
  /**
2243
2350
  * Check if two MIME types are compatible (exact match or aliases).
@@ -2267,7 +2374,7 @@ var storage_factory_service = __webpack_require__(192);
2267
2374
  return allowedTypes.some((allowed)=>{
2268
2375
  // Category wildcard (e.g., "image/*")
2269
2376
  if (allowed.endsWith('/*')) {
2270
- const category = allowed.slice(0, -2);
2377
+ const category = allowed.slice(0, -1);
2271
2378
  return mimeType.startsWith(category);
2272
2379
  }
2273
2380
  return allowed === mimeType;
@@ -2283,6 +2390,8 @@ var storage_factory_service = __webpack_require__(192);
2283
2390
  '*/*'
2284
2391
  ]) {
2285
2392
  try {
2393
+ const dangerous = this.rejectUnlistedDangerousType(declaredMimeType, allowedTypes);
2394
+ if (dangerous) return dangerous;
2286
2395
  const detectedType = this.detectFileType(buffer);
2287
2396
  // No magic bytes detected - handle text-based types
2288
2397
  if (!detectedType) {
@@ -2302,15 +2411,16 @@ var storage_factory_service = __webpack_require__(192);
2302
2411
  }
2303
2412
  }
2304
2413
  /**
2414
+ * Script-capable types (HTML, JS, SVG) pass only when listed by exact name - a polyglot
2415
+ * with a GIF or PNG header must not slip through as "same category as the content".
2416
+ */ static rejectUnlistedDangerousType(declaredMimeType, allowedTypes) {
2417
+ if (!this.isDangerousTextType(declaredMimeType)) return null;
2418
+ if (allowedTypes.includes(declaredMimeType)) return null;
2419
+ return this.failureResult(`File type "${declaredMimeType}" is potentially dangerous and not explicitly allowed`, declaredMimeType, declaredMimeType);
2420
+ }
2421
+ /**
2305
2422
  * Handle validation for files without detectable magic bytes.
2306
2423
  */ static validateUndetectedType(declaredMimeType, allowedTypes) {
2307
- // Check for dangerous text types first (HTML, JS, SVG)
2308
- if (this.isDangerousTextType(declaredMimeType)) {
2309
- const explicitlyAllowed = allowedTypes.some((t)=>t === declaredMimeType && t !== '*/*' && !t.endsWith('/*'));
2310
- if (!explicitlyAllowed) {
2311
- return this.failureResult(`File type "${declaredMimeType}" is potentially dangerous and not explicitly allowed`, declaredMimeType, declaredMimeType);
2312
- }
2313
- }
2314
2424
  // Safe text-based files don't have magic bytes, trust declared type
2315
2425
  if (this.isTextBasedType(declaredMimeType)) {
2316
2426
  const isAllowed = this.isTypeAllowed(declaredMimeType, allowedTypes);
@@ -2334,9 +2444,9 @@ var storage_factory_service = __webpack_require__(192);
2334
2444
  }
2335
2445
 
2336
2446
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/services/storage-config.service.ts
2337
- var storage_config_service = __webpack_require__(397);
2447
+ var storage_config_service = __webpack_require__(6397);
2338
2448
  // EXTERNAL MODULE: ./projects/nestjs-storage/src/services/storage-provider-config.service.ts
2339
- var storage_provider_config_service = __webpack_require__(623);
2449
+ var storage_provider_config_service = __webpack_require__(8623);
2340
2450
  ;// CONCATENATED MODULE: ./projects/nestjs-storage/src/services/upload.service.ts
2341
2451
  function _ts_decorate(decorators, target, key, desc) {
2342
2452
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -2442,7 +2552,7 @@ class UploadService {
2442
2552
  /**
2443
2553
  * Get storage provider and config info based on storage config ID
2444
2554
  * Validates company ownership when company feature is enabled
2445
- */ async getStorageProviderWithConfig(storageConfigId, user) {
2555
+ */ async getStorageProviderWithConfig(storageConfigId, user, requireActive = false) {
2446
2556
  let storageConfig;
2447
2557
  // Get storage config from database
2448
2558
  if (storageConfigId) {
@@ -2456,6 +2566,13 @@ class UploadService {
2456
2566
  }
2457
2567
  // Validate company ownership using shared utility
2458
2568
  (0,utils_.validateCompanyOwnership)(config, user, this.storageConfigService.isCompanyFeatureEnabled(), 'Storage configuration');
2569
+ // A deactivated config keeps serving and deleting its existing files but takes no new uploads
2570
+ if (requireActive && config.isActive === false) {
2571
+ throw new common_.NotFoundException({
2572
+ message: 'Storage configuration is inactive',
2573
+ messageKey: message_keys/* .UPLOAD_MESSAGES.CONFIG_NOT_FOUND */.dS.CONFIG_NOT_FOUND
2574
+ });
2575
+ }
2459
2576
  storageConfig = config;
2460
2577
  } else {
2461
2578
  // Use default config (scoped to user's company/branch)
@@ -2483,6 +2600,7 @@ class UploadService {
2483
2600
  if (storageConfigId) {
2484
2601
  const config = await this.storageProviderConfigService.findByIdDirect(storageConfigId);
2485
2602
  if (config) {
2603
+ (0,utils_.validateCompanyOwnership)(config, user, this.storageConfigService.isCompanyFeatureEnabled(), 'Storage configuration');
2486
2604
  return this.createProviderFromConfig(config);
2487
2605
  }
2488
2606
  }
@@ -2504,8 +2622,11 @@ class UploadService {
2504
2622
  return this.createFallbackLocalProvider();
2505
2623
  }
2506
2624
  async uploadSingleFile(file, options, user) {
2625
+ this.assertFilesProvided(file ? [
2626
+ file
2627
+ ] : []);
2507
2628
  this.validateFile(file);
2508
- const { provider, location, configId } = await this.getStorageProviderWithConfig(options.storageConfigId, user);
2629
+ const { provider, location, configId } = await this.getStorageProviderWithConfig(options.storageConfigId, user, true);
2509
2630
  const result = await provider.uploadFile(file, options);
2510
2631
  await this.publishFileEvent(event_actions/* .STORAGE_EVENT_ACTIONS.UPLOADED */.hw.UPLOADED, [
2511
2632
  result.key
@@ -2522,11 +2643,12 @@ class UploadService {
2522
2643
  };
2523
2644
  }
2524
2645
  async uploadMultipleFiles(files, options, user) {
2646
+ this.assertFilesProvided(files);
2525
2647
  for (const file of files){
2526
2648
  this.validateFile(file);
2527
2649
  }
2528
- const { provider, location, configId } = await this.getStorageProviderWithConfig(options.storageConfigId, user);
2529
- const results = await provider.uploadMultipleFiles(files, options);
2650
+ const { provider, location, configId } = await this.getStorageProviderWithConfig(options.storageConfigId, user, true);
2651
+ const results = await this.uploadAllOrNothing(provider, files, options);
2530
2652
  await this.publishFileEvent(event_actions/* .STORAGE_EVENT_ACTIONS.UPLOADED */.hw.UPLOADED, results.map((result)=>result.key), user, {
2531
2653
  location,
2532
2654
  storageConfigId: configId,
@@ -2567,6 +2689,26 @@ class UploadService {
2567
2689
  });
2568
2690
  return true;
2569
2691
  }
2692
+ assertFilesProvided(files) {
2693
+ if (!files?.length) {
2694
+ throw new common_.BadRequestException({
2695
+ message: 'No files provided',
2696
+ messageKey: message_keys/* .UPLOAD_MESSAGES.NO_FILES_PROVIDED */.dS.NO_FILES_PROVIDED
2697
+ });
2698
+ }
2699
+ }
2700
+ /** One failed file fails the batch, and the files already stored are removed again */ async uploadAllOrNothing(provider, files, options) {
2701
+ const settled = await Promise.allSettled(files.map((file)=>provider.uploadFile(file, options)));
2702
+ const uploaded = settled.filter((r)=>r.status === 'fulfilled').map((r)=>r.value);
2703
+ const failure = settled.find((r)=>r.status === 'rejected');
2704
+ if (failure) {
2705
+ if (uploaded.length) {
2706
+ await provider.deleteMultipleFiles(uploaded.map((r)=>r.key)).catch(()=>undefined);
2707
+ }
2708
+ throw failure.reason;
2709
+ }
2710
+ return uploaded;
2711
+ }
2570
2712
  async publishFileEvent(action, keys, user, metadata) {
2571
2713
  await (0,classes_.publishDomainEvent)({
2572
2714
  module: event_actions/* .STORAGE_EVENT_MODULE */.qh,
@@ -2580,31 +2722,11 @@ class UploadService {
2580
2722
  bytesToKb(bytes) {
2581
2723
  return Number((bytes * 0.001).toFixed(2));
2582
2724
  }
2583
- /**
2584
- * Get local storage basePath from DB config
2585
- * Initializes local provider if not cached, ensuring basePath is from DB
2586
- */ async getLocalStorageBasePath() {
2725
+ /** Storage roots the public file route may serve from; empty when they cannot be read */ async getLocalStorageBasePaths() {
2587
2726
  try {
2588
- // First check if already cached
2589
- const cachedPath = this.storageFactory.getLocalProviderBasePath();
2590
- if (cachedPath) {
2591
- return cachedPath;
2592
- }
2593
- // Get local config from DB (without user context for public access)
2594
- const localConfigs = await this.storageProviderConfigService.getConfigByType(file_location_enum/* .FileLocationEnum.LOCAL */.N.LOCAL);
2595
- if (localConfigs.length > 0) {
2596
- const localConfig = localConfigs[0];
2597
- // Initialize provider to cache it
2598
- await this.storageFactory.createProvider({
2599
- provider: file_location_enum/* .FileLocationEnum.LOCAL */.N.LOCAL,
2600
- config: localConfig.config
2601
- });
2602
- // Now get the cached basePath
2603
- return this.storageFactory.getLocalProviderBasePath();
2604
- }
2605
- return null;
2727
+ return await this.storageProviderConfigService.getActiveLocalBasePaths();
2606
2728
  } catch {
2607
- return null;
2729
+ return [];
2608
2730
  }
2609
2731
  }
2610
2732
  async makeFileUrl(key, storageConfigId, expiresIn = 3600, user) {
@@ -2702,61 +2824,104 @@ UploadService = _ts_decorate([
2702
2824
 
2703
2825
 
2704
2826
  },
2705
- 422(module) {
2827
+ 5198(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2828
+ /* import */ var _flusys_nestjs_shared_constants__rspack_import_0 = __webpack_require__(9140);
2829
+ /* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
2830
+ /* import */ var typeorm__rspack_import_2 = __webpack_require__(7158);
2831
+
2832
+
2833
+
2834
+ /**
2835
+ * Write paths of ApiService load rows by id alone, so a caller could update or delete another
2836
+ * company's row by guessing its id. Every row must belong to the caller's company - a caller
2837
+ * without a company may only touch rows without one.
2838
+ */ async function assertRowsInUserCompany(repository, ids, user, isCompanyFeatureEnabled, entityName) {
2839
+ if (!isCompanyFeatureEnabled || !user || !ids.length) return;
2840
+ const rows = await repository.find({
2841
+ where: {
2842
+ id: (0,typeorm__rspack_import_2.In)(ids)
2843
+ },
2844
+ withDeleted: true
2845
+ });
2846
+ const userCompanyId = user.companyId ?? null;
2847
+ if (rows.some((row)=>(row.companyId ?? null) !== userCompanyId)) {
2848
+ throw new _nestjs_common__rspack_import_1.ForbiddenException({
2849
+ message: `${entityName} belongs to another company`,
2850
+ messageKey: _flusys_nestjs_shared_constants__rspack_import_0.AUTH_MESSAGES.ENTITY_BELOG_ANOTHER_COMPANY,
2851
+ messageVariables: {
2852
+ entity: entityName
2853
+ }
2854
+ });
2855
+ }
2856
+ }
2857
+
2858
+ __webpack_require__.d(__webpack_exports__, {
2859
+ p: () => (assertRowsInUserCompany)
2860
+ });
2861
+
2862
+
2863
+ },
2864
+ 3422(module) {
2706
2865
 
2707
2866
  module.exports = __rspack_external__flusys_nestjs_shared_393d2cae;
2708
2867
 
2709
2868
 
2710
2869
  },
2711
- 937(module) {
2870
+ 6937(module) {
2712
2871
 
2713
2872
  module.exports = __rspack_external__flusys_nestjs_shared_classes_6076a329;
2714
2873
 
2715
2874
 
2716
2875
  },
2717
- 140(module) {
2876
+ 9140(module) {
2718
2877
 
2719
2878
  module.exports = __rspack_external__flusys_nestjs_shared_constants_81f33d5b;
2720
2879
 
2721
2880
 
2722
2881
  },
2723
- 236(module) {
2882
+ 1236(module) {
2724
2883
 
2725
2884
  module.exports = __rspack_external__flusys_nestjs_shared_modules_24702bee;
2726
2885
 
2727
2886
 
2728
2887
  },
2729
- 216(module) {
2888
+ 9216(module) {
2730
2889
 
2731
2890
  module.exports = __rspack_external__flusys_nestjs_shared_utils_9125c1f1;
2732
2891
 
2733
2892
 
2734
2893
  },
2735
- 157(module) {
2894
+ 6157(module) {
2736
2895
 
2737
2896
  module.exports = __rspack_external__nestjs_common_a04939da;
2738
2897
 
2739
2898
 
2740
2899
  },
2741
- 176(module) {
2900
+ 6176(module) {
2742
2901
 
2743
2902
  module.exports = __rspack_external__nestjs_swagger_7cd450b5;
2744
2903
 
2745
2904
 
2746
2905
  },
2747
- 812(module) {
2906
+ 5812(module) {
2748
2907
 
2749
2908
  module.exports = __rspack_external_class_transformer_c5a479fb;
2750
2909
 
2751
2910
 
2752
2911
  },
2753
- 421(module) {
2912
+ 5421(module) {
2754
2913
 
2755
2914
  module.exports = __rspack_external_class_validator_7b99ef4d;
2756
2915
 
2757
2916
 
2758
2917
  },
2759
- 158(module) {
2918
+ 2521(module) {
2919
+
2920
+ module.exports = __rspack_external_path;
2921
+
2922
+
2923
+ },
2924
+ 7158(module) {
2760
2925
 
2761
2926
  module.exports = __rspack_external_typeorm;
2762
2927