@flusys/nestjs-storage 1.0.0-beta → 1.0.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.
Files changed (118) hide show
  1. package/README.md +174 -13
  2. package/cjs/config/index.js +0 -1
  3. package/cjs/config/storage.constants.js +0 -17
  4. package/cjs/controllers/file-manager.controller.js +44 -1
  5. package/cjs/controllers/folder.controller.js +44 -1
  6. package/cjs/controllers/storage-config.controller.js +44 -1
  7. package/cjs/controllers/upload.controller.js +18 -29
  8. package/cjs/docs/storage-swagger.config.js +24 -136
  9. package/cjs/dtos/file-manager.dto.js +71 -35
  10. package/cjs/dtos/folder.dto.js +15 -9
  11. package/cjs/dtos/storage-config.dto.js +25 -66
  12. package/cjs/dtos/upload.dto.js +24 -17
  13. package/cjs/entities/file-manager-with-company.entity.js +3 -4
  14. package/cjs/entities/file-manager.entity.js +71 -3
  15. package/cjs/entities/folder-with-company.entity.js +3 -4
  16. package/cjs/entities/folder.entity.js +19 -3
  17. package/cjs/entities/index.js +9 -10
  18. package/cjs/entities/storage-config-with-company.entity.js +3 -4
  19. package/cjs/entities/storage-config.entity.js +73 -3
  20. package/cjs/interfaces/index.js +0 -1
  21. package/cjs/middlewares/file-serve.middleware.js +113 -100
  22. package/cjs/modules/storage.module.js +82 -136
  23. package/cjs/providers/azure-provider.optional.js +10 -38
  24. package/cjs/providers/local-provider.js +38 -31
  25. package/cjs/providers/s3-provider.optional.js +19 -40
  26. package/cjs/providers/storage-factory.service.js +54 -99
  27. package/cjs/providers/storage-provider.registry.js +8 -18
  28. package/cjs/services/file-manager.service.js +238 -323
  29. package/cjs/services/folder.service.js +8 -11
  30. package/cjs/services/index.js +1 -0
  31. package/cjs/{config → services}/storage-config.service.js +32 -76
  32. package/cjs/services/storage-datasource.provider.js +16 -26
  33. package/cjs/services/storage-provider-config.service.js +21 -38
  34. package/cjs/services/upload.service.js +72 -88
  35. package/cjs/utils/file-validator.util.js +458 -0
  36. package/cjs/utils/image-compressor.util.js +3 -8
  37. package/config/index.d.ts +0 -1
  38. package/config/storage.constants.d.ts +0 -8
  39. package/controllers/upload.controller.d.ts +3 -6
  40. package/dtos/file-manager.dto.d.ts +13 -7
  41. package/dtos/folder.dto.d.ts +5 -5
  42. package/dtos/storage-config.dto.d.ts +13 -14
  43. package/entities/file-manager-with-company.entity.d.ts +2 -2
  44. package/entities/file-manager.entity.d.ts +11 -2
  45. package/entities/folder-with-company.entity.d.ts +2 -2
  46. package/entities/folder.entity.d.ts +4 -2
  47. package/entities/index.d.ts +3 -4
  48. package/entities/storage-config-with-company.entity.d.ts +2 -2
  49. package/entities/storage-config.entity.d.ts +7 -2
  50. package/fesm/config/index.js +0 -1
  51. package/fesm/config/storage.constants.js +0 -8
  52. package/fesm/controllers/file-manager.controller.js +45 -2
  53. package/fesm/controllers/folder.controller.js +45 -2
  54. package/fesm/controllers/storage-config.controller.js +45 -2
  55. package/fesm/controllers/upload.controller.js +19 -30
  56. package/fesm/docs/storage-swagger.config.js +27 -142
  57. package/fesm/dtos/file-manager.dto.js +72 -36
  58. package/fesm/dtos/folder.dto.js +16 -10
  59. package/fesm/dtos/storage-config.dto.js +29 -76
  60. package/fesm/dtos/upload.dto.js +25 -19
  61. package/fesm/entities/file-manager-with-company.entity.js +3 -4
  62. package/fesm/entities/file-manager.entity.js +72 -4
  63. package/fesm/entities/folder-with-company.entity.js +3 -4
  64. package/fesm/entities/folder.entity.js +20 -4
  65. package/fesm/entities/index.js +5 -13
  66. package/fesm/entities/storage-config-with-company.entity.js +3 -4
  67. package/fesm/entities/storage-config.entity.js +74 -4
  68. package/fesm/interfaces/index.js +0 -1
  69. package/fesm/interfaces/storage-config.interface.js +1 -3
  70. package/fesm/middlewares/file-serve.middleware.js +114 -101
  71. package/fesm/modules/storage.module.js +83 -136
  72. package/fesm/providers/azure-provider.optional.js +11 -42
  73. package/fesm/providers/local-provider.js +38 -31
  74. package/fesm/providers/s3-provider.optional.js +20 -44
  75. package/fesm/providers/storage-factory.service.js +52 -97
  76. package/fesm/providers/storage-provider.registry.js +10 -20
  77. package/fesm/services/file-manager.service.js +237 -322
  78. package/fesm/services/folder.service.js +6 -9
  79. package/fesm/services/index.js +1 -0
  80. package/fesm/{config → services}/storage-config.service.js +32 -76
  81. package/fesm/services/storage-datasource.provider.js +16 -26
  82. package/fesm/services/storage-provider-config.service.js +19 -36
  83. package/fesm/services/upload.service.js +71 -87
  84. package/fesm/utils/file-validator.util.js +451 -0
  85. package/fesm/utils/image-compressor.util.js +3 -8
  86. package/interfaces/file-manager.interface.d.ts +7 -4
  87. package/interfaces/index.d.ts +0 -1
  88. package/interfaces/storage-config.interface.d.ts +3 -22
  89. package/interfaces/storage-module-options.interface.d.ts +0 -5
  90. package/middlewares/file-serve.middleware.d.ts +9 -1
  91. package/modules/storage.module.d.ts +1 -2
  92. package/package.json +6 -6
  93. package/providers/azure-provider.optional.d.ts +8 -6
  94. package/providers/local-provider.d.ts +2 -7
  95. package/providers/s3-provider.optional.d.ts +9 -7
  96. package/providers/storage-factory.service.d.ts +8 -9
  97. package/providers/storage-provider.registry.d.ts +4 -4
  98. package/services/file-manager.service.d.ts +23 -16
  99. package/services/folder.service.d.ts +4 -4
  100. package/services/index.d.ts +1 -0
  101. package/services/storage-config.service.d.ts +24 -0
  102. package/services/storage-datasource.provider.d.ts +3 -4
  103. package/services/storage-provider-config.service.d.ts +5 -6
  104. package/services/upload.service.d.ts +5 -5
  105. package/utils/file-validator.util.d.ts +19 -0
  106. package/cjs/entities/file-manager-base.entity.js +0 -115
  107. package/cjs/entities/folder-base.entity.js +0 -55
  108. package/cjs/entities/storage-config-base.entity.js +0 -64
  109. package/cjs/interfaces/file-upload-response.interface.js +0 -4
  110. package/config/storage-config.service.d.ts +0 -22
  111. package/entities/file-manager-base.entity.d.ts +0 -13
  112. package/entities/folder-base.entity.d.ts +0 -5
  113. package/entities/storage-config-base.entity.d.ts +0 -7
  114. package/fesm/entities/file-manager-base.entity.js +0 -108
  115. package/fesm/entities/folder-base.entity.js +0 -48
  116. package/fesm/entities/storage-config-base.entity.js +0 -57
  117. package/fesm/interfaces/file-upload-response.interface.js +0 -1
  118. package/interfaces/file-upload-response.interface.d.ts +0 -6
@@ -27,8 +27,9 @@ function _ts_param(paramIndex, decorator) {
27
27
  }
28
28
  import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
29
29
  import { UtilsService } from '@flusys/nestjs-shared/modules';
30
+ import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
30
31
  import { Inject, Injectable, Scope } from '@nestjs/common';
31
- import { StorageConfigService } from '../config';
32
+ import { StorageConfigService } from './storage-config.service';
32
33
  import { Folder, FolderWithCompany } from '../entities';
33
34
  import { StorageDataSourceProvider } from './storage-datasource.provider';
34
35
  export class FolderService extends RequestScopedApiService {
@@ -38,16 +39,13 @@ export class FolderService extends RequestScopedApiService {
38
39
  getDataSourceProvider() {
39
40
  return this.dataSourceProvider;
40
41
  }
41
- // Entity Conversion
42
42
  async convertSingleDtoToEntity(dto, user) {
43
43
  const entity = await super.convertSingleDtoToEntity(dto, user);
44
- // Set companyId from user context if company feature enabled
45
44
  if (this.storageConfig.isCompanyFeatureEnabled()) {
46
45
  entity.companyId = user?.companyId ?? null;
47
46
  }
48
47
  return entity;
49
48
  }
50
- // Query Customization
51
49
  async getSelectQuery(query, _user, select) {
52
50
  if (!select?.length) {
53
51
  select = [
@@ -69,11 +67,10 @@ export class FolderService extends RequestScopedApiService {
69
67
  }
70
68
  async getExtraManipulateQuery(query, filterDto, user) {
71
69
  const result = await super.getExtraManipulateQuery(query, filterDto, user);
72
- if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
73
- query.andWhere('folder.companyId = :companyId', {
74
- companyId: user.companyId
75
- });
76
- }
70
+ applyCompanyFilter(query, {
71
+ isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
72
+ entityAlias: 'folder'
73
+ }, user);
77
74
  return result;
78
75
  }
79
76
  constructor(cacheManager, utilsService, storageConfig, dataSourceProvider){
@@ -1,5 +1,6 @@
1
1
  export * from './file-manager.service';
2
2
  export * from './folder.service';
3
+ export * from './storage-config.service';
3
4
  export * from './storage-provider-config.service';
4
5
  export * from './storage-datasource.provider';
5
6
  export * from './upload.service';
@@ -27,115 +27,71 @@ function _ts_param(paramIndex, decorator) {
27
27
  }
28
28
  import { Inject, Injectable } from '@nestjs/common';
29
29
  import { StorageModuleOptions } from '../interfaces';
30
- import { STORAGE_MODULE_OPTIONS, DEFAULT_MAX_FILE_SIZE, DEFAULT_ALLOWED_FILE_TYPES } from './storage.constants';
30
+ import { STORAGE_MODULE_OPTIONS, DEFAULT_MAX_FILE_SIZE, DEFAULT_ALLOWED_FILE_TYPES } from '../config/storage.constants';
31
+ const BYTES_PER_MB = 1024 * 1024;
32
+ const DEFAULT_LOCAL_PATH = './uploads';
33
+ const DEFAULT_PORT = '3000';
31
34
  export class StorageConfigService {
32
- /**
33
- * Check if company feature is enabled
34
- */ isCompanyFeatureEnabled() {
35
+ // ─── IModuleConfigService Implementation ────────────────────────────────────
36
+ isCompanyFeatureEnabled() {
35
37
  return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
36
38
  }
37
- /**
38
- * Get database mode
39
- */ getDatabaseMode() {
39
+ getDatabaseMode() {
40
40
  return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
41
41
  }
42
- /**
43
- * Get maximum file size in bytes
44
- */ getMaxFileSize() {
42
+ isMultiTenant() {
43
+ return this.getDatabaseMode() === 'multi-tenant';
44
+ }
45
+ // ─── Config Getters ─────────────────────────────────────────────────────────
46
+ getMaxFileSize() {
45
47
  return this.options.config?.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
46
48
  }
47
- /**
48
- * Get allowed file types (MIME types or patterns)
49
- */ getAllowedFileTypes() {
49
+ getAllowedFileTypes() {
50
50
  return this.options.config?.allowedFileTypes ?? DEFAULT_ALLOWED_FILE_TYPES;
51
51
  }
52
- /**
53
- * Check if file type is allowed
54
- */ isFileTypeAllowed(mimeType) {
52
+ getOptions() {
53
+ return this.options;
54
+ }
55
+ getDefaultLocalStoragePath() {
56
+ return this.options.config?.localStoragePath ?? DEFAULT_LOCAL_PATH;
57
+ }
58
+ getAppUrl() {
59
+ return this.options.config?.appUrl ?? process.env.APP_URL ?? `http://localhost:${process.env.PORT ?? DEFAULT_PORT}`;
60
+ }
61
+ // ─── Validation Methods ─────────────────────────────────────────────────────
62
+ isFileTypeAllowed(mimeType) {
55
63
  const allowedTypes = this.getAllowedFileTypes();
56
- // If wildcard, allow all
57
64
  if (allowedTypes.includes('*/*')) {
58
65
  return true;
59
66
  }
60
- // Check exact match or wildcard pattern
61
- return allowedTypes.some((allowedType)=>{
62
- if (allowedType.endsWith('/*')) {
63
- const prefix = allowedType.slice(0, -2);
64
- return mimeType.startsWith(prefix);
65
- }
66
- return allowedType === mimeType;
67
- });
67
+ return allowedTypes.some((type)=>type.endsWith('/*') ? mimeType.startsWith(type.slice(0, -2)) : type === mimeType);
68
68
  }
69
- /**
70
- * Validate file size
71
- */ validateFileSize(fileSize) {
69
+ validateFileSize(fileSize) {
72
70
  const maxSize = this.getMaxFileSize();
73
71
  if (fileSize > maxSize) {
74
- const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(2);
75
- const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
76
72
  return {
77
73
  valid: false,
78
- message: `File size (${fileSizeMB}MB) exceeds the maximum allowed size of ${maxSizeMB}MB`
74
+ message: `File size (${this.toMB(fileSize)}MB) exceeds maximum ${this.toMB(maxSize)}MB`
79
75
  };
80
76
  }
81
77
  return {
82
78
  valid: true
83
79
  };
84
80
  }
85
- /**
86
- * Validate file type
87
- */ validateFileType(mimeType) {
81
+ validateFileType(mimeType) {
88
82
  if (!this.isFileTypeAllowed(mimeType)) {
89
- const allowedTypes = this.getAllowedFileTypes();
90
83
  return {
91
84
  valid: false,
92
- message: `File type "${mimeType}" is not allowed. Allowed types: ${allowedTypes.join(', ')}`
85
+ message: `File type "${mimeType}" not allowed. Allowed: ${this.getAllowedFileTypes().join(', ')}`
93
86
  };
94
87
  }
95
88
  return {
96
89
  valid: true
97
90
  };
98
91
  }
99
- /**
100
- * Get default database config
101
- */ getDefaultDatabaseConfig() {
102
- return this.options.config?.defaultDatabaseConfig;
103
- }
104
- /**
105
- * Get all options
106
- */ getOptions() {
107
- return this.options;
108
- }
109
- /**
110
- * Get default local storage base path
111
- * Used for serving local files without database lookup
112
- * Falls back to './uploads' if not configured
113
- */ getDefaultLocalStoragePath() {
114
- // Check if localStoragePath is configured in module options
115
- const configuredPath = this.options.config?.localStoragePath;
116
- if (configuredPath) {
117
- return configuredPath;
118
- }
119
- // Default to ./uploads in the project root
120
- return './uploads';
121
- }
122
- /**
123
- * Get application base URL for generating file URLs
124
- * - First tries module config
125
- * - Falls back to APP_URL env var
126
- * - Finally constructs from PORT env var
127
- */ getAppUrl() {
128
- // Try from module config first
129
- if (this.options.config?.appUrl) {
130
- return this.options.config.appUrl;
131
- }
132
- // Fallback: read directly from environment
133
- if (process.env.APP_URL) {
134
- return process.env.APP_URL;
135
- }
136
- // Last resort: construct from PORT
137
- const port = process.env.PORT || '3000';
138
- return `http://localhost:${port}`;
92
+ // ─── Private Helpers ────────────────────────────────────────────────────────
93
+ toMB(bytes) {
94
+ return (bytes / BYTES_PER_MB).toFixed(2);
139
95
  }
140
96
  constructor(options){
141
97
  _define_property(this, "options", void 0);
@@ -29,8 +29,7 @@ import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
29
29
  import { Inject, Injectable, Logger, Optional, Scope } from '@nestjs/common';
30
30
  import { REQUEST } from '@nestjs/core';
31
31
  import { Request } from 'express';
32
- import { StorageModuleOptions } from '../interfaces';
33
- import { STORAGE_MODULE_OPTIONS } from '../config/storage.constants';
32
+ import { StorageConfigService } from './storage-config.service';
34
33
  export class StorageDataSourceProvider extends MultiTenantDataSourceService {
35
34
  // Factory Methods
36
35
  /** Build parent options from StorageModuleOptions */ static buildParentOptions(options) {
@@ -42,14 +41,11 @@ export class StorageDataSourceProvider extends MultiTenantDataSourceService {
42
41
  };
43
42
  }
44
43
  // Feature Flags
45
- /** Get global enable company feature flag */ getEnableCompanyFeature() {
46
- return this.storageOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
47
- }
48
44
  /**
49
45
  * Get enable company feature for specific tenant
50
46
  * Falls back to global setting if not specified per-tenant
51
47
  */ getEnableCompanyFeatureForTenant(tenant) {
52
- return tenant?.enableCompanyFeature ?? this.getEnableCompanyFeature();
48
+ return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
53
49
  }
54
50
  /**
55
51
  * Get enable company feature for current request context
@@ -62,22 +58,16 @@ export class StorageDataSourceProvider extends MultiTenantDataSourceService {
62
58
  * For TypeORM repositories, we always use the base entities (FileManager, etc.)
63
59
  * but for migrations, we need the correct entity based on the feature flag.
64
60
  */ async getStorageEntities(enableCompanyFeature) {
65
- const enable = enableCompanyFeature ?? this.getEnableCompanyFeature();
66
- const { FileManager, Folder, StorageConfig } = await import('../entities');
67
- // For migrations and schema sync, return the appropriate entity
68
- // Both versions map to the same table, but with different columns
69
- if (enable) {
70
- const { FileManagerWithCompany, FolderWithCompany, StorageConfigWithCompany } = await import('../entities');
71
- return [
72
- FileManagerWithCompany,
73
- FolderWithCompany,
74
- StorageConfigWithCompany
75
- ];
76
- }
77
- return [
78
- FileManager,
79
- Folder,
80
- StorageConfig
61
+ const enable = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
62
+ const entities = await import('../entities');
63
+ return enable ? [
64
+ entities.FileManagerWithCompany,
65
+ entities.FolderWithCompany,
66
+ entities.StorageConfigWithCompany
67
+ ] : [
68
+ entities.FileManager,
69
+ entities.Folder,
70
+ entities.StorageConfig
81
71
  ];
82
72
  }
83
73
  // Overrides
@@ -138,8 +128,8 @@ export class StorageDataSourceProvider extends MultiTenantDataSourceService {
138
128
  StorageDataSourceProvider.connectionLocks.delete(tenant.id);
139
129
  }
140
130
  }
141
- constructor(storageOptions, request){
142
- super(StorageDataSourceProvider.buildParentOptions(storageOptions), request), _define_property(this, "storageOptions", void 0), _define_property(this, "logger", void 0), this.storageOptions = storageOptions, this.logger = new Logger(StorageDataSourceProvider.name);
131
+ constructor(configService, request){
132
+ super(StorageDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), _define_property(this, "logger", void 0), this.configService = configService, this.logger = new Logger(StorageDataSourceProvider.name);
143
133
  }
144
134
  }
145
135
  // Override parent's static properties to have Storage-specific cache
@@ -153,12 +143,12 @@ StorageDataSourceProvider = _ts_decorate([
153
143
  Injectable({
154
144
  scope: Scope.REQUEST
155
145
  }),
156
- _ts_param(0, Inject(STORAGE_MODULE_OPTIONS)),
146
+ _ts_param(0, Inject(StorageConfigService)),
157
147
  _ts_param(1, Optional()),
158
148
  _ts_param(1, Inject(REQUEST)),
159
149
  _ts_metadata("design:type", Function),
160
150
  _ts_metadata("design:paramtypes", [
161
- typeof StorageModuleOptions === "undefined" ? Object : StorageModuleOptions,
151
+ typeof StorageConfigService === "undefined" ? Object : StorageConfigService,
162
152
  typeof Request === "undefined" ? Object : Request
163
153
  ])
164
154
  ], StorageDataSourceProvider);
@@ -27,8 +27,9 @@ function _ts_param(paramIndex, decorator) {
27
27
  }
28
28
  import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
29
29
  import { UtilsService } from '@flusys/nestjs-shared/modules';
30
+ import { applyCompanyFilter, buildCompanyWhereCondition } from '@flusys/nestjs-shared/utils';
30
31
  import { Inject, Injectable, Scope } from '@nestjs/common';
31
- import { StorageConfigService } from '../config';
32
+ import { StorageConfigService } from './storage-config.service';
32
33
  import { StorageConfig, StorageConfigWithCompany } from '../entities';
33
34
  import { StorageDataSourceProvider } from './storage-datasource.provider';
34
35
  export class StorageProviderConfigService extends RequestScopedApiService {
@@ -38,16 +39,13 @@ export class StorageProviderConfigService extends RequestScopedApiService {
38
39
  getDataSourceProvider() {
39
40
  return this.dataSourceProvider;
40
41
  }
41
- // Entity Conversion
42
42
  async convertSingleDtoToEntity(dto, user) {
43
43
  const entity = await super.convertSingleDtoToEntity(dto, user);
44
- // Set companyId from user context if company feature enabled
45
44
  if (this.storageConfig.isCompanyFeatureEnabled()) {
46
45
  entity.companyId = user?.companyId ?? null;
47
46
  }
48
47
  return entity;
49
48
  }
50
- // Query Customization
51
49
  async getSelectQuery(query, _user, select) {
52
50
  if (!select?.length) {
53
51
  select = [
@@ -55,6 +53,8 @@ export class StorageProviderConfigService extends RequestScopedApiService {
55
53
  'name',
56
54
  'storage',
57
55
  'config',
56
+ 'isActive',
57
+ 'isDefault',
58
58
  'createdAt',
59
59
  'updatedAt'
60
60
  ];
@@ -70,19 +70,14 @@ export class StorageProviderConfigService extends RequestScopedApiService {
70
70
  }
71
71
  async getExtraManipulateQuery(query, filterDto, user) {
72
72
  const result = await super.getExtraManipulateQuery(query, filterDto, user);
73
- if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
74
- query.andWhere('storageConfig.companyId = :companyId', {
75
- companyId: user.companyId
76
- });
77
- }
73
+ applyCompanyFilter(query, {
74
+ isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
75
+ entityAlias: 'storageConfig'
76
+ }, user);
78
77
  query.orderBy(`${this.entityName}.createdAt`, 'DESC');
79
78
  return result;
80
79
  }
81
- /**
82
- * Find storage config by ID without throwing (returns null if not found)
83
- * Uses direct repository query - bypasses company filtering
84
- * Use for internal operations like file deletion where config ID is already known
85
- */ async findByIdDirect(id) {
80
+ async findByIdDirect(id) {
86
81
  await this.ensureRepositoryInitialized();
87
82
  return await this.repository.findOne({
88
83
  where: {
@@ -90,21 +85,15 @@ export class StorageProviderConfigService extends RequestScopedApiService {
90
85
  }
91
86
  });
92
87
  }
93
- /**
94
- * Get default storage configuration (scoped to user's company if enabled)
95
- * Falls back to any available config if 'default' not found
96
- */ async getDefaultConfig(user) {
88
+ async getDefaultConfig(user) {
97
89
  await this.ensureRepositoryInitialized();
98
- const baseWhere = {};
99
- // Filter by company only if company feature is enabled and user is provided
100
- if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
101
- baseWhere.companyId = user.companyId;
102
- }
103
- // First try to find config named 'default'
90
+ const baseWhere = buildCompanyWhereCondition({
91
+ isActive: true
92
+ }, this.storageConfig.isCompanyFeatureEnabled(), user);
104
93
  const defaultConfig = await this.repository.findOne({
105
94
  where: {
106
95
  ...baseWhere,
107
- name: 'default'
96
+ isDefault: true
108
97
  },
109
98
  order: {
110
99
  createdAt: 'ASC'
@@ -113,7 +102,6 @@ export class StorageProviderConfigService extends RequestScopedApiService {
113
102
  if (defaultConfig) {
114
103
  return defaultConfig;
115
104
  }
116
- // Fall back to any available config for this company/user
117
105
  return await this.repository.findOne({
118
106
  where: baseWhere,
119
107
  order: {
@@ -121,17 +109,12 @@ export class StorageProviderConfigService extends RequestScopedApiService {
121
109
  }
122
110
  });
123
111
  }
124
- /**
125
- * Get storage configuration by type (scoped to user's company if enabled)
126
- */ async getConfigByType(storage, user) {
112
+ async getConfigByType(storage, user) {
127
113
  await this.ensureRepositoryInitialized();
128
- const where = {
129
- storage
130
- };
131
- // Filter by company only if company feature is enabled and user is provided
132
- if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
133
- where.companyId = user.companyId;
134
- }
114
+ const where = buildCompanyWhereCondition({
115
+ storage,
116
+ isActive: true
117
+ }, this.storageConfig.isCompanyFeatureEnabled(), user);
135
118
  return await this.repository.find({
136
119
  where
137
120
  });