@flusys/nestjs-storage 1.1.0-beta → 2.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 +148 -6
  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 +70 -34
  10. package/cjs/dtos/folder.dto.js +15 -9
  11. package/cjs/dtos/storage-config.dto.js +4 -85
  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 +74 -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 +15 -37
  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 +12 -5
  41. package/dtos/folder.dto.d.ts +5 -5
  42. package/dtos/storage-config.dto.d.ts +7 -13
  43. package/entities/file-manager-with-company.entity.d.ts +2 -2
  44. package/entities/file-manager.entity.d.ts +12 -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 +8 -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 +71 -35
  58. package/fesm/dtos/folder.dto.js +16 -10
  59. package/fesm/dtos/storage-config.dto.js +8 -95
  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 +75 -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 +13 -35
  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 +0 -20
  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 +4 -4
  104. package/services/upload.service.d.ts +3 -2
  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 -93
  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 -9
  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 -83
  117. package/fesm/interfaces/file-upload-response.interface.js +0 -1
  118. package/interfaces/file-upload-response.interface.d.ts +0 -6
@@ -25,129 +25,84 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
- import { StorageProviderRegistry } from './storage-provider.registry';
29
28
  import { Inject, Injectable, Logger, NotFoundException } from '@nestjs/common';
30
29
  import * as crypto from 'crypto';
31
- import { StorageConfigService } from '../config';
30
+ import { StorageConfigService } from '../services';
31
+ import { StorageProviderRegistry } from './storage-provider.registry';
32
32
  export class StorageFactoryService {
33
- /**
34
- * Generate a stable cache key for provider configuration
35
- * Uses SHA256 hash to handle complex config objects consistently
36
- */ generateCacheKey(config) {
37
- // Sort keys for consistent ordering, then hash
38
- const configString = JSON.stringify(config.config, Object.keys(config.config || {}).sort());
39
- const configHash = crypto.createHash('sha256').update(configString).digest('hex').substring(0, 16);
40
- return `${config.provider}-${configHash}`;
41
- }
42
- /**
43
- * Create a storage provider instance based on configuration
44
- * Uses lazy loading - provider is only instantiated when requested
45
- */ async createProvider(config) {
46
- const providerKey = this.generateCacheKey(config);
47
- // Check cache first
48
- if (this.providerCache.has(providerKey)) {
49
- return this.providerCache.get(providerKey);
50
- }
51
- // Get provider class from registry
33
+ async createProvider(config) {
34
+ const cacheKey = this.generateCacheKey(config);
35
+ const cached = this.cache.get(cacheKey);
36
+ if (cached) return cached;
52
37
  const ProviderClass = StorageProviderRegistry.get(config.provider);
53
38
  if (!ProviderClass) {
54
- throw new NotFoundException(`Storage provider '${config.provider}' is not registered. ` + `Available providers: ${StorageProviderRegistry.getAll().join(', ')}`);
39
+ throw new NotFoundException(`Storage provider '${config.provider}' not registered. Available: ${StorageProviderRegistry.getAll().join(', ')}`);
55
40
  }
56
- // Instantiate provider
57
41
  try {
58
42
  const instance = new ProviderClass();
59
- // Initialize if method exists
60
- if ('initialize' in instance && typeof instance.initialize === 'function') {
61
- // For local provider, inject appUrl as fallback for baseUrl
62
- let initConfig = config.config;
63
- if (config.provider === 'local' && !config.config?.baseUrl) {
64
- const appUrl = this.storageConfigService.getAppUrl();
65
- if (appUrl) {
66
- initConfig = {
67
- ...config.config,
68
- baseUrl: appUrl
69
- };
70
- this.logger.debug(`Using appUrl from config as baseUrl: ${appUrl}`);
71
- }
72
- }
73
- await instance.initialize(initConfig);
74
- }
75
- // Cache the instance
76
- this.providerCache.set(providerKey, instance);
77
- this.logger.log(`Created storage provider: ${config.provider} (key: ${providerKey})`);
43
+ await this.initializeProvider(instance, config);
44
+ this.cache.set(cacheKey, instance);
45
+ this.logger.log(`Created provider: ${config.provider} (${cacheKey})`);
78
46
  return instance;
79
47
  } catch (error) {
80
- this.logger.error(`Failed to create provider ${config.provider}:`, error);
81
- // Preserve original error message for better debugging
82
- const originalMessage = error?.message || 'Unknown error';
83
- throw new Error(`Failed to initialize storage provider '${config.provider}': ${originalMessage}`);
48
+ const message = error instanceof Error ? error.message : 'Unknown error';
49
+ throw new Error(`Failed to initialize '${config.provider}': ${message}`);
84
50
  }
85
51
  }
86
- /**
87
- * Get provider by name (creates with default config if not cached)
88
- */ async getProvider(providerName) {
89
- const cachedKey = Array.from(this.providerCache.keys()).find((key)=>key.startsWith(providerName));
90
- if (cachedKey) {
91
- return this.providerCache.get(cachedKey);
92
- }
93
- // Create with empty config
52
+ async getProvider(providerName) {
53
+ const cachedKey = Array.from(this.cache.keys()).find((k)=>k.startsWith(providerName));
54
+ if (cachedKey) return this.cache.get(cachedKey);
94
55
  return this.createProvider({
95
56
  provider: providerName,
96
57
  config: {}
97
58
  });
98
59
  }
99
- /**
100
- * Clear cached providers
101
- */ clearCache() {
102
- this.providerCache.clear();
60
+ getLocalProviderBasePath() {
61
+ const localKey = Array.from(this.cache.keys()).find((k)=>k.startsWith('local'));
62
+ const provider = localKey ? this.cache.get(localKey) : null;
63
+ return provider && 'basePath' in provider ? provider.basePath : null;
103
64
  }
104
- /**
105
- * Check if a provider is available
106
- */ isProviderAvailable(providerName) {
107
- return StorageProviderRegistry.has(providerName);
65
+ clearCache() {
66
+ this.cache.clear();
108
67
  }
109
- /**
110
- * Get list of available providers
111
- */ getAvailableProviders() {
112
- return StorageProviderRegistry.getAll();
68
+ async onModuleDestroy() {
69
+ this.logger.log('Cleaning up storage providers...');
70
+ const closePromises = Array.from(this.cache.entries()).filter(([, p])=>'close' in p && typeof p.close === 'function').map(([key, p])=>p.close().then(()=>this.logger.debug(`Closed: ${key}`)).catch((e)=>this.logger.warn(`Failed to close ${key}: ${e.message}`)));
71
+ await Promise.allSettled(closePromises);
72
+ this.cache.clear();
73
+ this.logger.log('Storage provider cleanup complete');
113
74
  }
114
- /**
115
- * Get the basePath from cached local provider
116
- * Returns null if no local provider is cached
117
- */ getLocalProviderBasePath() {
118
- // Find cached local provider
119
- const localKey = Array.from(this.providerCache.keys()).find((key)=>key.startsWith('local'));
120
- if (localKey) {
121
- const provider = this.providerCache.get(localKey);
122
- if (provider && 'basePath' in provider) {
123
- return provider.basePath;
124
- }
125
- }
126
- return null;
75
+ // ─── Private Helpers ──────────────────────────────────────────────────────────
76
+ generateCacheKey(config) {
77
+ const sortedKeys = Object.keys(config.config || {}).sort();
78
+ const hash = crypto.createHash('sha256').update(JSON.stringify(config.config, sortedKeys)).digest('hex').substring(0, 16);
79
+ return `${config.provider}-${hash}`;
127
80
  }
128
- /**
129
- * Cleanup all cached provider connections on module destroy
130
- * Ensures SFTP connections and other resources are properly released
131
- */ async onModuleDestroy() {
132
- this.logger.log('Cleaning up storage provider connections...');
133
- const closePromises = [];
134
- for (const [key, provider] of this.providerCache.entries()){
135
- // Check if provider has a close method (e.g., SFTP)
136
- if ('close' in provider && typeof provider.close === 'function') {
137
- closePromises.push(provider.close().then(()=>this.logger.debug(`Closed provider: ${key}`)).catch((err)=>this.logger.warn(`Failed to close provider ${key}: ${err.message}`)));
81
+ async initializeProvider(instance, config) {
82
+ if (!('initialize' in instance) || typeof instance.initialize !== 'function') {
83
+ return;
84
+ }
85
+ let initConfig = config.config;
86
+ // Inject appUrl as baseUrl fallback for local provider
87
+ if (config.provider === 'local' && !config.config?.baseUrl) {
88
+ const appUrl = this.configService.getAppUrl();
89
+ if (appUrl) {
90
+ initConfig = {
91
+ ...config.config,
92
+ baseUrl: appUrl
93
+ };
94
+ this.logger.debug(`Using appUrl as baseUrl: ${appUrl}`);
138
95
  }
139
96
  }
140
- await Promise.allSettled(closePromises);
141
- this.providerCache.clear();
142
- this.logger.log('Storage provider cleanup complete');
97
+ await instance.initialize(initConfig);
143
98
  }
144
- constructor(storageConfigService){
145
- _define_property(this, "storageConfigService", void 0);
99
+ constructor(configService){
100
+ _define_property(this, "configService", void 0);
146
101
  _define_property(this, "logger", void 0);
147
- _define_property(this, "providerCache", void 0);
148
- this.storageConfigService = storageConfigService;
102
+ _define_property(this, "cache", void 0);
103
+ this.configService = configService;
149
104
  this.logger = new Logger(StorageFactoryService.name);
150
- this.providerCache = new Map();
105
+ this.cache = new Map();
151
106
  }
152
107
  }
153
108
  StorageFactoryService = _ts_decorate([
@@ -12,32 +12,22 @@ function _define_property(obj, key, value) {
12
12
  return obj;
13
13
  }
14
14
  /**
15
- * Registry for storage providers
16
- * Allows dynamic registration of providers at runtime
15
+ * Static registry for storage provider classes
16
+ * Allows dynamic registration at runtime
17
17
  */ export class StorageProviderRegistry {
18
- /**
19
- * Register a storage provider
20
- */ static register(providerName, providerClass) {
21
- this.providers.set(providerName.toLowerCase(), providerClass);
18
+ static register(name, providerClass) {
19
+ this.providers.set(name.toLowerCase(), providerClass);
22
20
  }
23
- /**
24
- * Get a registered provider class
25
- */ static get(providerName) {
26
- return this.providers.get(providerName.toLowerCase());
21
+ static get(name) {
22
+ return this.providers.get(name.toLowerCase());
27
23
  }
28
- /**
29
- * Check if a provider is registered
30
- */ static has(providerName) {
31
- return this.providers.has(providerName.toLowerCase());
24
+ static has(name) {
25
+ return this.providers.has(name.toLowerCase());
32
26
  }
33
- /**
34
- * Get all registered provider names
35
- */ static getAll() {
27
+ static getAll() {
36
28
  return Array.from(this.providers.keys());
37
29
  }
38
- /**
39
- * Clear all providers (useful for testing)
40
- */ static clear() {
30
+ static clear() {
41
31
  this.providers.clear();
42
32
  }
43
33
  }