@flusys/nestjs-storage 0.1.0-alpha.1 → 0.1.0-beta.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.
- package/cjs/controllers-index.js +2 -2
- package/cjs/dtos-index.js +1 -1
- package/cjs/entities-index.js +1 -1
- package/cjs/index.js +3 -3
- package/cjs/modules-index.js +2 -2
- package/cjs/providers-index.js +1 -1
- package/cjs/services-index.js +1 -1
- package/cjs/utils-index.js +1 -1
- package/controllers/file-manager.controller.d.ts +1 -1
- package/controllers/folder.controller.d.ts +1 -1
- package/controllers/storage-config.controller.d.ts +1 -1
- package/controllers/upload.controller.d.ts +1 -1
- package/dtos/file-manager.dto.d.ts +1 -1
- package/dtos/storage-config.dto.d.ts +1 -1
- package/entities/file-manager-base.entity.d.ts +1 -1
- package/entities/storage-config-base.entity.d.ts +1 -1
- package/fesm/controllers-index.js +2 -2
- package/fesm/dtos-index.js +1 -1
- package/fesm/entities-index.js +1 -1
- package/fesm/index.js +3 -3
- package/fesm/modules-index.js +2 -2
- package/fesm/providers-index.js +1 -1
- package/fesm/services-index.js +1 -1
- package/fesm/utils-index.js +1 -1
- package/interfaces/storage-config.interface.d.ts +1 -1
- package/package.json +8 -3
- package/providers/azure-provider.optional.d.ts +2 -2
- package/providers/s3-provider.optional.d.ts +2 -2
- package/providers/sftp-provider.optional.d.ts +2 -2
- package/providers/storage-provider.registry.d.ts +1 -1
- package/services/file-manager.service.d.ts +4 -4
- package/services/folder.service.d.ts +3 -3
- package/services/storage-provider-config.service.d.ts +4 -4
- package/services/upload.service.d.ts +1 -3
package/fesm/providers-index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __name=(target,value)=>__defProp(target,"name",{value,configurable:true});var __decorateClass=(decorators,target,key,kind)=>{var result=kind>1?void 0:kind?__getOwnPropDesc(target,key):target;for(var i=decorators.length-1,decorator;i>=0;i--)if(decorator=decorators[i])result=(kind?decorator(target,key,result):decorator(result))||result;if(kind&&result)__defProp(target,key,result);return result};var StorageProviderRegistry=class{static{__name(this,"StorageProviderRegistry")}static providers=new Map;static register(providerName,providerClass){this.providers.set(providerName.toLowerCase(),providerClass)}static get(providerName){return this.providers.get(providerName.toLowerCase())}static has(providerName){return this.providers.has(providerName.toLowerCase())}static getAll(){return Array.from(this.providers.keys())}static clear(){this.providers.clear()}};import{Injectable,Logger,NotFoundException}from"@nestjs/common";import*as crypto from"crypto";var StorageFactoryService=class{logger=new Logger(StorageFactoryService.name);providerCache=new Map;generateCacheKey(config){const configString=JSON.stringify(config.config,Object.keys(config.config||{}).sort());const configHash=crypto.createHash("sha256").update(configString).digest("hex").substring(0,16);return`${config.provider}-${configHash}`}async createProvider(config){const providerKey=this.generateCacheKey(config);if(this.providerCache.has(providerKey)){return this.providerCache.get(providerKey)}const ProviderClass=StorageProviderRegistry.get(config.provider);if(!ProviderClass){throw new NotFoundException(`Storage provider '${config.provider}' is not registered. Available providers: ${StorageProviderRegistry.getAll().join(", ")}`)}try{const instance=new ProviderClass;if("initialize"in instance&&typeof instance.initialize==="function"){await instance.initialize(config.config)}this.providerCache.set(providerKey,instance);this.logger.log(`Created storage provider: ${config.provider} (key: ${providerKey})`);return instance}catch(error){this.logger.error(`Failed to create provider ${config.provider}:`,error);const originalMessage=error?.message||"Unknown error";throw new Error(`Failed to initialize storage provider '${config.provider}': ${originalMessage}`)}}async getProvider(providerName){const cachedKey=Array.from(this.providerCache.keys()).find(key=>key.startsWith(providerName));if(cachedKey){return this.providerCache.get(cachedKey)}return this.createProvider({provider:providerName,config:{}})}clearCache(){this.providerCache.clear()}isProviderAvailable(providerName){return StorageProviderRegistry.has(providerName)}getAvailableProviders(){return StorageProviderRegistry.getAll()}async onModuleDestroy(){this.logger.log("Cleaning up storage provider connections...");const closePromises=[];for(const[key,provider]of this.providerCache.entries()){if("close"in provider&&typeof provider.close==="function"){closePromises.push(provider.close().then(()=>this.logger.debug(`Closed provider: ${key}`)).catch(err=>this.logger.warn(`Failed to close provider ${key}: ${err.message}`)))}}await Promise.allSettled(closePromises);this.providerCache.clear();this.logger.log("Storage provider cleanup complete")}};__name(StorageFactoryService,"StorageFactoryService");StorageFactoryService=__decorateClass([Injectable()],StorageFactoryService);import
|
|
1
|
+
var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __name=(target,value)=>__defProp(target,"name",{value,configurable:true});var __decorateClass=(decorators,target,key,kind)=>{var result=kind>1?void 0:kind?__getOwnPropDesc(target,key):target;for(var i=decorators.length-1,decorator;i>=0;i--)if(decorator=decorators[i])result=(kind?decorator(target,key,result):decorator(result))||result;if(kind&&result)__defProp(target,key,result);return result};var StorageProviderRegistry=class{static{__name(this,"StorageProviderRegistry")}static providers=new Map;static register(providerName,providerClass){this.providers.set(providerName.toLowerCase(),providerClass)}static get(providerName){return this.providers.get(providerName.toLowerCase())}static has(providerName){return this.providers.has(providerName.toLowerCase())}static getAll(){return Array.from(this.providers.keys())}static clear(){this.providers.clear()}};import{Injectable,Logger,NotFoundException}from"@nestjs/common";import*as crypto from"crypto";var StorageFactoryService=class{logger=new Logger(StorageFactoryService.name);providerCache=new Map;generateCacheKey(config){const configString=JSON.stringify(config.config,Object.keys(config.config||{}).sort());const configHash=crypto.createHash("sha256").update(configString).digest("hex").substring(0,16);return`${config.provider}-${configHash}`}async createProvider(config){const providerKey=this.generateCacheKey(config);if(this.providerCache.has(providerKey)){return this.providerCache.get(providerKey)}const ProviderClass=StorageProviderRegistry.get(config.provider);if(!ProviderClass){throw new NotFoundException(`Storage provider '${config.provider}' is not registered. Available providers: ${StorageProviderRegistry.getAll().join(", ")}`)}try{const instance=new ProviderClass;if("initialize"in instance&&typeof instance.initialize==="function"){await instance.initialize(config.config)}this.providerCache.set(providerKey,instance);this.logger.log(`Created storage provider: ${config.provider} (key: ${providerKey})`);return instance}catch(error){this.logger.error(`Failed to create provider ${config.provider}:`,error);const originalMessage=error?.message||"Unknown error";throw new Error(`Failed to initialize storage provider '${config.provider}': ${originalMessage}`)}}async getProvider(providerName){const cachedKey=Array.from(this.providerCache.keys()).find(key=>key.startsWith(providerName));if(cachedKey){return this.providerCache.get(cachedKey)}return this.createProvider({provider:providerName,config:{}})}clearCache(){this.providerCache.clear()}isProviderAvailable(providerName){return StorageProviderRegistry.has(providerName)}getAvailableProviders(){return StorageProviderRegistry.getAll()}async onModuleDestroy(){this.logger.log("Cleaning up storage provider connections...");const closePromises=[];for(const[key,provider]of this.providerCache.entries()){if("close"in provider&&typeof provider.close==="function"){closePromises.push(provider.close().then(()=>this.logger.debug(`Closed provider: ${key}`)).catch(err=>this.logger.warn(`Failed to close provider ${key}: ${err.message}`)))}}await Promise.allSettled(closePromises);this.providerCache.clear();this.logger.log("Storage provider cleanup complete")}};__name(StorageFactoryService,"StorageFactoryService");StorageFactoryService=__decorateClass([Injectable()],StorageFactoryService);import sharp from"sharp";var ImageCompressor=class{static{__name(this,"ImageCompressor")}static async compress(buffer,mimetype,options={}){const{maxWidth=1280,maxHeight=1280,quality=85,format="original"}=options;if(mimetype==="image/svg+xml"){return{buffer,format:mimetype}}const image=sharp(buffer,{failOnError:false,density:300});image.resize({width:maxWidth,height:maxHeight,fit:"inside",withoutEnlargement:true});let targetFormat=format!=="original"?format:mimetype.split("/")[1];switch(targetFormat.toLowerCase()){case"jpeg":case"jpg":image.jpeg({quality,mozjpeg:true,chromaSubsampling:"4:4:4"});break;case"png":image.png({compressionLevel:9,adaptiveFiltering:true,palette:true,quality,colors:256,dither:1});break;case"webp":image.webp({quality,smartSubsample:true,effort:6,lossless:quality===100});break;case"avif":image.avif({quality,effort:6,chromaSubsampling:"4:4:4"});break;case"tiff":image.tiff({quality,compression:"lzw",predictor:"horizontal",pyramid:true});break;case"gif":image.gif({colours:256,effort:10,dither:1});break;case"jp2":image.jp2({quality,lossless:quality===100});break;default:targetFormat="webp";image.webp({quality,smartSubsample:true,effort:6});break}try{const{data,info}=await image.toBuffer({resolveWithObject:true});return{buffer:data,format:`image/${targetFormat}`}}catch(error){console.warn(`Image processing failed: ${error instanceof Error?error.message:String(error)}`);return{buffer,format:mimetype}}}};import{Logger as Logger2}from"@nestjs/common";import*as fs from"fs/promises";import*as path from"path";import{v4 as uuidv4}from"uuid";var LocalProvider=class _LocalProvider{static{__name(this,"LocalProvider")}logger=new Logger2(_LocalProvider.name);basePath="";baseUrl="";async initialize(config){this.basePath=path.resolve(config.basePath);this.baseUrl=config.baseUrl||"";await fs.mkdir(this.basePath,{recursive:true});this.logger.log(`Local Provider initialized: ${this.basePath}`)}async uploadFile(file,options){let processedBuffer=file.buffer;let contentType=file.mimetype;const fileName=`${uuidv4()}-${file.originalname}`;if(options.compress&&file.mimetype.startsWith("image/")){const result=await ImageCompressor.compress(file.buffer,file.mimetype,{maxWidth:options.maxWidth,maxHeight:options.maxHeight,quality:options.quality,format:options.format});processedBuffer=result.buffer;contentType=result.format}const folderPath=options.folderPath?path.join(this.basePath,options.folderPath):this.basePath;const filePath=path.join(folderPath,fileName);await fs.mkdir(folderPath,{recursive:true});await fs.writeFile(filePath,processedBuffer);const relativeKey=path.relative(this.basePath,filePath);this.logger.log(`Uploaded file to local storage: ${relativeKey}`);return{name:fileName,key:relativeKey,size:processedBuffer.length,contentType}}async uploadMultipleFiles(files,options){return Promise.all(files.map(file=>this.uploadFile(file,options)))}async deleteFile(key){try{const filePath=path.join(this.basePath,key);await fs.unlink(filePath);this.logger.log(`Deleted file from local storage: ${key}`)}catch(_error){this.logger.warn(`Failed to delete file from local storage: ${key}`)}}async deleteMultipleFiles(keys){await Promise.all(keys.map(key=>this.deleteFile(key)));this.logger.log(`Deleted ${keys.length} files from local storage`)}async generatePresignedUrl(key,_expiresInSeconds){return this.baseUrl?`${this.baseUrl}/${key}`:`/${key}`}async healthCheck(){try{await fs.access(this.basePath);return true}catch{return false}}getAbsolutePath(key){return path.join(this.basePath,key)}async fileExists(key){try{const filePath=path.join(this.basePath,key);await fs.access(filePath);return true}catch{return false}}async getFileStats(key){const filePath=path.join(this.basePath,key);const stats=await fs.stat(filePath);return{size:stats.size,createdAt:stats.birthtime,modifiedAt:stats.mtime}}};export{LocalProvider,StorageFactoryService,StorageProviderRegistry};
|
package/fesm/services-index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:true,configurable:true,writable:true,value}):obj[key]=value;var __name=(target,value)=>__defProp(target,"name",{value,configurable:true});var __esm=(fn,res)=>function __init(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __decorateClass=(decorators,target,key,kind)=>{var result=kind>1?void 0:kind?__getOwnPropDesc(target,key):target;for(var i=decorators.length-1,decorator;i>=0;i--)if(decorator=decorators[i])result=(kind?decorator(target,key,result):decorator(result))||result;if(kind&&result)__defProp(target,key,result);return result};var __decorateParam=(index,decorator)=>(target,key)=>decorator(target,key,index);var __publicField=(obj,key,value)=>__defNormalProp(obj,typeof key!=="symbol"?key+"":key,value);import*as sharp from"sharp";var ImageCompressor;var init_image_compressor_util=__esm({"projects/nestjs-storage/src/utils/image-compressor.util.ts"(){"use strict";ImageCompressor=class{static{__name(this,"ImageCompressor")}static async compress(buffer,mimetype,options={}){const{maxWidth=1280,maxHeight=1280,quality=85,format="original"}=options;if(mimetype==="image/svg+xml"){return{buffer,format:mimetype}}const image=sharp(buffer,{failOnError:false,density:300});image.resize({width:maxWidth,height:maxHeight,fit:"inside",withoutEnlargement:true});let targetFormat=format!=="original"?format:mimetype.split("/")[1];switch(targetFormat.toLowerCase()){case"jpeg":case"jpg":image.jpeg({quality,mozjpeg:true,chromaSubsampling:"4:4:4"});break;case"png":image.png({compressionLevel:9,adaptiveFiltering:true,palette:true,quality,colors:256,dither:1});break;case"webp":image.webp({quality,smartSubsample:true,effort:6,lossless:quality===100});break;case"avif":image.avif({quality,effort:6,chromaSubsampling:"4:4:4"});break;case"tiff":image.tiff({quality,compression:"lzw",predictor:"horizontal",pyramid:true});break;case"gif":image.gif({colours:256,effort:10,dither:1});break;case"jp2":image.jp2({quality,lossless:quality===100});break;default:targetFormat="webp";image.webp({quality,smartSubsample:true,effort:6});break}try{const{data,info}=await image.toBuffer({resolveWithObject:true});return{buffer:data,format:`image/${targetFormat}`}}catch(error){console.warn(`Image processing failed: ${error instanceof Error?error.message:String(error)}`);return{buffer,format:mimetype}}}}}});var local_provider_exports={};__export(local_provider_exports,{LocalProvider:()=>LocalProvider});import{Logger}from"@nestjs/common";import*as fs from"fs/promises";import*as path from"path";import{v4 as uuidv4}from"uuid";var LocalProvider;var init_local_provider=__esm({"projects/nestjs-storage/src/providers/local-provider.ts"(){"use strict";init_image_compressor_util();LocalProvider=class _LocalProvider{static{__name(this,"LocalProvider")}logger=new Logger(_LocalProvider.name);basePath="";baseUrl="";async initialize(config){this.basePath=path.resolve(config.basePath);this.baseUrl=config.baseUrl||"";await fs.mkdir(this.basePath,{recursive:true});this.logger.log(`Local Provider initialized: ${this.basePath}`)}async uploadFile(file,options){let processedBuffer=file.buffer;let contentType=file.mimetype;const fileName=`${uuidv4()}-${file.originalname}`;if(options.compress&&file.mimetype.startsWith("image/")){const result=await ImageCompressor.compress(file.buffer,file.mimetype,{maxWidth:options.maxWidth,maxHeight:options.maxHeight,quality:options.quality,format:options.format});processedBuffer=result.buffer;contentType=result.format}const folderPath=options.folderPath?path.join(this.basePath,options.folderPath):this.basePath;const filePath=path.join(folderPath,fileName);await fs.mkdir(folderPath,{recursive:true});await fs.writeFile(filePath,processedBuffer);const relativeKey=path.relative(this.basePath,filePath);this.logger.log(`Uploaded file to local storage: ${relativeKey}`);return{name:fileName,key:relativeKey,size:processedBuffer.length,contentType}}async uploadMultipleFiles(files,options){return Promise.all(files.map(file=>this.uploadFile(file,options)))}async deleteFile(key){try{const filePath=path.join(this.basePath,key);await fs.unlink(filePath);this.logger.log(`Deleted file from local storage: ${key}`)}catch(_error){this.logger.warn(`Failed to delete file from local storage: ${key}`)}}async deleteMultipleFiles(keys){await Promise.all(keys.map(key=>this.deleteFile(key)));this.logger.log(`Deleted ${keys.length} files from local storage`)}async generatePresignedUrl(key,_expiresInSeconds){return this.baseUrl?`${this.baseUrl}/${key}`:`/${key}`}async healthCheck(){try{await fs.access(this.basePath);return true}catch{return false}}getAbsolutePath(key){return path.join(this.basePath,key)}async fileExists(key){try{const filePath=path.join(this.basePath,key);await fs.access(filePath);return true}catch{return false}}async getFileStats(key){const filePath=path.join(this.basePath,key);const stats=await fs.stat(filePath);return{size:stats.size,createdAt:stats.birthtime,modifiedAt:stats.mtime}}}}});var s3_provider_optional_exports={};__export(s3_provider_optional_exports,{S3Provider:()=>S3Provider});import{Logger as Logger2}from"@nestjs/common";import{v4 as uuidv42}from"uuid";var S3Provider;var init_s3_provider_optional=__esm({"projects/nestjs-storage/src/providers/s3-provider.optional.ts"(){"use strict";init_image_compressor_util();S3Provider=class _S3Provider{static{__name(this,"S3Provider")}logger=new Logger2(_S3Provider.name);s3;bucketName="";region="";async initialize(config){try{const{S3Client}=await import("@aws-sdk/client-s3");this.region=config.region;this.bucketName=config.bucket;this.s3=new S3Client({region:config.region,credentials:config.accessKeyId&&config.secretAccessKey?{accessKeyId:config.accessKeyId,secretAccessKey:config.secretAccessKey}:void 0,endpoint:config.endpoint});this.logger.log(`S3 Provider initialized: region=${config.region}, bucket=${config.bucket}`)}catch(_error){this.logger.error("Failed to initialize S3Provider. Make sure @aws-sdk packages are installed.");throw new Error("AWS SDK not found. Install it with: npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner")}}async uploadFile(file,options){const{Upload}=await import("@aws-sdk/lib-storage");let processedBuffer=file.buffer;let contentType=file.mimetype;const fileName=`${uuidv42()}-${file.originalname}`;if(options.compress&&file.mimetype.startsWith("image/")){const result=await ImageCompressor.compress(file.buffer,file.mimetype,{maxWidth:options.maxWidth,maxHeight:options.maxHeight,quality:options.quality,format:options.format});processedBuffer=result.buffer;contentType=result.format}const key=options.folderPath?`${options.folderPath}/${fileName}`:fileName;const upload=new Upload({client:this.s3,params:{Bucket:this.bucketName,Key:key,Body:processedBuffer,ContentType:contentType}});await upload.done();return{name:fileName,key,size:processedBuffer.length,contentType}}async uploadMultipleFiles(files,options){return Promise.all(files.map(file=>this.uploadFile(file,options)))}async deleteFile(key){const{DeleteObjectCommand}=await import("@aws-sdk/client-s3");const command=new DeleteObjectCommand({Bucket:this.bucketName,Key:key});await this.s3.send(command);this.logger.log(`Deleted file from S3: ${key}`)}async deleteMultipleFiles(keys){const{DeleteObjectsCommand}=await import("@aws-sdk/client-s3");const command=new DeleteObjectsCommand({Bucket:this.bucketName,Delete:{Objects:keys.map(key=>({Key:key}))}});await this.s3.send(command);this.logger.log(`Deleted ${keys.length} files from S3`)}async generatePresignedUrl(key,expiresInSeconds=3600){const{GetObjectCommand}=await import("@aws-sdk/client-s3");const{getSignedUrl}=await import("@aws-sdk/s3-request-presigner");const command=new GetObjectCommand({Bucket:this.bucketName,Key:key});return getSignedUrl(this.s3,command,{expiresIn:expiresInSeconds})}async healthCheck(){try{const{HeadBucketCommand}=await import("@aws-sdk/client-s3");const command=new HeadBucketCommand({Bucket:this.bucketName});await this.s3.send(command);return true}catch{return false}}}}});var azure_provider_optional_exports={};__export(azure_provider_optional_exports,{AzureProvider:()=>AzureProvider});import{Logger as Logger3}from"@nestjs/common";import{v4 as uuidv43}from"uuid";var AzureProvider;var init_azure_provider_optional=__esm({"projects/nestjs-storage/src/providers/azure-provider.optional.ts"(){"use strict";init_image_compressor_util();AzureProvider=class _AzureProvider{static{__name(this,"AzureProvider")}logger=new Logger3(_AzureProvider.name);blobServiceClient;containerClient;containerName="";accountName="";async initialize(config){try{const{BlobServiceClient}=await import("@azure/storage-blob");this.accountName=config.accountName;this.containerName=config.containerName;if(config.connectionString){this.blobServiceClient=BlobServiceClient.fromConnectionString(config.connectionString)}else{const{StorageSharedKeyCredential}=await import("@azure/storage-blob");const sharedKeyCredential=new StorageSharedKeyCredential(config.accountName,config.accountKey);this.blobServiceClient=new BlobServiceClient(`https://${config.accountName}.blob.core.windows.net`,sharedKeyCredential)}this.containerClient=this.blobServiceClient.getContainerClient(config.containerName);await this.containerClient.createIfNotExists();this.logger.log(`Azure Provider initialized: account=${config.accountName}, container=${config.containerName}`)}catch(error){this.logger.error("Failed to initialize AzureProvider. Make sure @azure/storage-blob is installed.");throw new Error("Azure Storage SDK not found. Install it with: npm install @azure/storage-blob")}}async uploadFile(file,options){let processedBuffer=file.buffer;let contentType=file.mimetype;const fileName=`${uuidv43()}-${file.originalname}`;if(options.compress&&file.mimetype.startsWith("image/")){const result=await ImageCompressor.compress(file.buffer,file.mimetype,{maxWidth:options.maxWidth,maxHeight:options.maxHeight,quality:options.quality,format:options.format});processedBuffer=result.buffer;contentType=result.format}const blobName=options.folderPath?`${options.folderPath}/${fileName}`:fileName;const blockBlobClient=this.containerClient.getBlockBlobClient(blobName);await blockBlobClient.upload(processedBuffer,processedBuffer.length,{blobHTTPHeaders:{blobContentType:contentType}});const url=blockBlobClient.url;return{name:fileName,key:blobName,size:processedBuffer.length,contentType}}async uploadMultipleFiles(files,options){return Promise.all(files.map(file=>this.uploadFile(file,options)))}async deleteFile(key){const blockBlobClient=this.containerClient.getBlockBlobClient(key);await blockBlobClient.deleteIfExists();this.logger.log(`Deleted file from Azure: ${key}`)}async deleteMultipleFiles(keys){await Promise.all(keys.map(key=>this.deleteFile(key)));this.logger.log(`Deleted ${keys.length} files from Azure`)}async generatePresignedUrl(key,expiresInSeconds=3600){const{BlobSASPermissions,generateBlobSASQueryParameters}=await import("@azure/storage-blob");const blockBlobClient=this.containerClient.getBlockBlobClient(key);const startsOn=new Date;const expiresOn=new Date(startsOn.getTime()+expiresInSeconds*1e3);const sasToken=generateBlobSASQueryParameters({containerName:this.containerName,blobName:key,permissions:BlobSASPermissions.parse("r"),startsOn,expiresOn},blockBlobClient.credential).toString();return`${blockBlobClient.url}?${sasToken}`}async healthCheck(){try{await this.containerClient.exists();return true}catch{return false}}}}});var sftp_provider_optional_exports={};__export(sftp_provider_optional_exports,{SftpProvider:()=>SftpProvider});import{Logger as Logger4}from"@nestjs/common";import*as path2 from"path";import{v4 as uuidv44}from"uuid";var SftpProvider;var init_sftp_provider_optional=__esm({"projects/nestjs-storage/src/providers/sftp-provider.optional.ts"(){"use strict";init_image_compressor_util();SftpProvider=class _SftpProvider{static{__name(this,"SftpProvider")}logger=new Logger4(_SftpProvider.name);sftp;config;connected=false;async initialize(config){try{const sftp=await import("ssh2-sftp-client");const SftpClient=sftp.default||sftp;this.sftp=new SftpClient;this.config={host:config.host,port:config.port||22,username:config.username,password:config.password,privateKey:config.privateKey,basePath:config.basePath||"/uploads"};await this.connect();await this.ensureDirectory(this.config.basePath);this.logger.log(`SFTP Provider initialized: ${config.username}@${config.host}:${config.port||22}`)}catch(_error){this.logger.error("Failed to initialize SftpProvider. Make sure ssh2-sftp-client is installed.");throw new Error("SFTP client not found. Install it with: npm install ssh2-sftp-client")}}async connect(){if(!this.connected){await this.sftp.connect({host:this.config.host,port:this.config.port,username:this.config.username,password:this.config.password,privateKey:this.config.privateKey});this.connected=true}}async ensureDirectory(dirPath){try{await this.sftp.mkdir(dirPath,true)}catch(_error){}}async uploadFile(file,options){await this.connect();let processedBuffer=file.buffer;let contentType=file.mimetype;const fileName=`${uuidv44()}-${file.originalname}`;if(options.compress&&file.mimetype.startsWith("image/")){const result=await ImageCompressor.compress(file.buffer,file.mimetype,{maxWidth:options.maxWidth,maxHeight:options.maxHeight,quality:options.quality,format:options.format});processedBuffer=result.buffer;contentType=result.format}const remotePath=options.folderPath?path2.join(this.config.basePath,options.folderPath,fileName):path2.join(this.config.basePath,fileName);const remoteDir=path2.dirname(remotePath);await this.ensureDirectory(remoteDir);await this.sftp.put(processedBuffer,remotePath);return{name:fileName,key:remotePath,size:processedBuffer.length,contentType}}async uploadMultipleFiles(files,options){return Promise.all(files.map(file=>this.uploadFile(file,options)))}async deleteFile(key){await this.connect();try{await this.sftp.delete(key);this.logger.log(`Deleted file from SFTP: ${key}`)}catch(_error){this.logger.warn(`Failed to delete file from SFTP: ${key}`)}}async deleteMultipleFiles(keys){await Promise.all(keys.map(key=>this.deleteFile(key)));this.logger.log(`Deleted ${keys.length} files from SFTP`)}async generatePresignedUrl(key,_expiresInSeconds){return key}async healthCheck(){try{await this.connect();return this.connected}catch{return false}}async close(){if(this.connected){await this.sftp.end();this.connected=false}}}}});import{Identity}from"@flusys/nestjs-shared/entities";import{Column}from"typeorm";var FileManagerBase;var init_file_manager_base_entity=__esm({"projects/nestjs-storage/src/entities/file-manager-base.entity.ts"(){"use strict";FileManagerBase=class extends Identity{static{__name(this,"FileManagerBase")}name;contentType;size;key;url;location;storageConfigId;expiresAt=null;isPrivate};__decorateClass([Column({type:"varchar",length:255,nullable:false})],FileManagerBase.prototype,"name",2);__decorateClass([Column({type:"varchar",length:255,nullable:false})],FileManagerBase.prototype,"contentType",2);__decorateClass([Column({type:"varchar",length:255,nullable:false})],FileManagerBase.prototype,"size",2);__decorateClass([Column({type:"text",nullable:false})],FileManagerBase.prototype,"key",2);__decorateClass([Column({type:"text",nullable:true})],FileManagerBase.prototype,"url",2);__decorateClass([Column({type:"text",nullable:false})],FileManagerBase.prototype,"location",2);__decorateClass([Column({type:"uuid",nullable:true})],FileManagerBase.prototype,"storageConfigId",2);__decorateClass([Column({type:"bigint",nullable:true})],FileManagerBase.prototype,"expiresAt",2);__decorateClass([Column({type:"boolean",nullable:false,default:false})],FileManagerBase.prototype,"isPrivate",2)}});import{Identity as Identity2}from"@flusys/nestjs-shared/entities";import{Column as Column2}from"typeorm";var FolderBase;var init_folder_base_entity=__esm({"projects/nestjs-storage/src/entities/folder-base.entity.ts"(){"use strict";FolderBase=class extends Identity2{static{__name(this,"FolderBase")}name;slug};__decorateClass([Column2({type:"varchar",length:255,nullable:false})],FolderBase.prototype,"name",2);__decorateClass([Column2({type:"varchar",length:255,nullable:false})],FolderBase.prototype,"slug",2)}});import{Identity as Identity3}from"@flusys/nestjs-shared/entities";import{FileLocationEnum as FileLocationEnum2}from"@flusys/nestjs-storage/enums";import{Column as Column3}from"typeorm";var StorageConfigBase;var init_storage_config_base_entity=__esm({"projects/nestjs-storage/src/entities/storage-config-base.entity.ts"(){"use strict";StorageConfigBase=class extends Identity3{static{__name(this,"StorageConfigBase")}name;storage;config};__decorateClass([Column3({type:"varchar",length:255,nullable:false})],StorageConfigBase.prototype,"name",2);__decorateClass([Column3({type:"enum",enum:FileLocationEnum2,nullable:false})],StorageConfigBase.prototype,"storage",2);__decorateClass([Column3({type:"json",nullable:false})],StorageConfigBase.prototype,"config",2)}});import{Entity,JoinColumn,ManyToOne}from"typeorm";var FileManager;var init_file_manager_entity=__esm({"projects/nestjs-storage/src/entities/file-manager.entity.ts"(){"use strict";init_file_manager_base_entity();FileManager=class extends FileManagerBase{folder};__name(FileManager,"FileManager");__decorateClass([ManyToOne("Folder",folder=>folder.fileManager,{nullable:true,onDelete:"SET NULL"}),JoinColumn({name:"folder_id"})],FileManager.prototype,"folder",2);FileManager=__decorateClass([Entity({name:"file_manager"})],FileManager)}});import{Entity as Entity2,OneToMany}from"typeorm";var Folder;var init_folder_entity=__esm({"projects/nestjs-storage/src/entities/folder.entity.ts"(){"use strict";init_folder_base_entity();Folder=class extends FolderBase{fileManager};__name(Folder,"Folder");__decorateClass([OneToMany("FileManager",fileManager=>fileManager.folder)],Folder.prototype,"fileManager",2);Folder=__decorateClass([Entity2({name:"folder"})],Folder)}});import{Entity as Entity3}from"typeorm";var StorageConfig;var init_storage_config_entity=__esm({"projects/nestjs-storage/src/entities/storage-config.entity.ts"(){"use strict";init_storage_config_base_entity();StorageConfig=class extends StorageConfigBase{};__name(StorageConfig,"StorageConfig");StorageConfig=__decorateClass([Entity3({name:"storage_config"})],StorageConfig)}});import{Column as Column4,Entity as Entity4,JoinColumn as JoinColumn2,ManyToOne as ManyToOne2}from"typeorm";var FileManagerWithCompany;var init_file_manager_with_company_entity=__esm({"projects/nestjs-storage/src/entities/file-manager-with-company.entity.ts"(){"use strict";init_file_manager_base_entity();FileManagerWithCompany=class extends FileManagerBase{companyId;folder};__name(FileManagerWithCompany,"FileManagerWithCompany");__decorateClass([Column4({type:"uuid",nullable:true})],FileManagerWithCompany.prototype,"companyId",2);__decorateClass([ManyToOne2("FolderWithCompany",folder=>folder.fileManager,{nullable:true,onDelete:"SET NULL"}),JoinColumn2({name:"folder_id"})],FileManagerWithCompany.prototype,"folder",2);FileManagerWithCompany=__decorateClass([Entity4({name:"file_manager"})],FileManagerWithCompany)}});import{Column as Column5,Entity as Entity5,OneToMany as OneToMany2}from"typeorm";var FolderWithCompany;var init_folder_with_company_entity=__esm({"projects/nestjs-storage/src/entities/folder-with-company.entity.ts"(){"use strict";init_folder_base_entity();FolderWithCompany=class extends FolderBase{companyId;fileManager};__name(FolderWithCompany,"FolderWithCompany");__decorateClass([Column5({type:"uuid",nullable:true})],FolderWithCompany.prototype,"companyId",2);__decorateClass([OneToMany2("FileManagerWithCompany",fileManager=>fileManager.folder)],FolderWithCompany.prototype,"fileManager",2);FolderWithCompany=__decorateClass([Entity5({name:"folder"})],FolderWithCompany)}});import{Column as Column6,Entity as Entity6}from"typeorm";var StorageConfigWithCompany;var init_storage_config_with_company_entity=__esm({"projects/nestjs-storage/src/entities/storage-config-with-company.entity.ts"(){"use strict";init_storage_config_base_entity();StorageConfigWithCompany=class extends StorageConfigBase{companyId};__name(StorageConfigWithCompany,"StorageConfigWithCompany");__decorateClass([Column6({type:"uuid",nullable:true})],StorageConfigWithCompany.prototype,"companyId",2);StorageConfigWithCompany=__decorateClass([Entity6({name:"storage_config"})],StorageConfigWithCompany)}});var entities_exports={};__export(entities_exports,{FileManager:()=>FileManager,FileManagerBase:()=>FileManagerBase,FileManagerWithCompany:()=>FileManagerWithCompany,Folder:()=>Folder,FolderBase:()=>FolderBase,FolderWithCompany:()=>FolderWithCompany,StorageAllEntities:()=>StorageAllEntities,StorageCompanyEntities:()=>StorageCompanyEntities,StorageConfig:()=>StorageConfig,StorageConfigBase:()=>StorageConfigBase,StorageConfigWithCompany:()=>StorageConfigWithCompany,StorageCoreEntities:()=>StorageCoreEntities,getStorageEntitiesByConfig:()=>getStorageEntitiesByConfig});function getStorageEntitiesByConfig(enableCompanyFeature){return enableCompanyFeature?StorageCompanyEntities:StorageCoreEntities}var StorageCoreEntities,StorageCompanyEntities,StorageAllEntities;var init_entities=__esm({"projects/nestjs-storage/src/entities/index.ts"(){"use strict";init_file_manager_base_entity();init_folder_base_entity();init_storage_config_base_entity();init_file_manager_entity();init_folder_entity();init_storage_config_entity();init_file_manager_with_company_entity();init_folder_with_company_entity();init_storage_config_with_company_entity();init_file_manager_entity();init_folder_entity();init_storage_config_entity();init_file_manager_with_company_entity();init_folder_with_company_entity();init_storage_config_with_company_entity();StorageCoreEntities=[FileManager,Folder,StorageConfig];StorageCompanyEntities=[FileManagerWithCompany,FolderWithCompany,StorageConfigWithCompany];StorageAllEntities=[...StorageCoreEntities,...StorageCompanyEntities];__name(getStorageEntitiesByConfig,"getStorageEntitiesByConfig")}});import{RequestScopedApiService}from"@flusys/nestjs-shared/classes";import{UpdateFileManagerDto}from"@flusys/nestjs-storage/dtos";import{FileLocationEnum as FileLocationEnum3}from"@flusys/nestjs-storage/enums/file-location.enum";import{FileManager as FileManager2,FileManagerWithCompany as FileManagerWithCompany2,Folder as Folder2,FolderWithCompany as FolderWithCompany2}from"@flusys/nestjs-storage/entities";import{BadRequestException as BadRequestException2,Inject as Inject2,Injectable as Injectable3,NotFoundException as NotFoundException2}from"@nestjs/common";import{Brackets,In}from"typeorm";import{BadRequestException,Injectable,InternalServerErrorException,Logger as Logger5,NotFoundException}from"@nestjs/common";var StorageProviderRegistry=class{static{__name(this,"StorageProviderRegistry")}static providers=new Map;static register(providerName,providerClass){this.providers.set(providerName.toLowerCase(),providerClass)}static get(providerName){return this.providers.get(providerName.toLowerCase())}static has(providerName){return this.providers.has(providerName.toLowerCase())}static getAll(){return Array.from(this.providers.keys())}static clear(){this.providers.clear()}};var UploadService=class{constructor(storageFactory,storageConfigService,storageProviderConfigService){this.storageFactory=storageFactory;this.storageConfigService=storageConfigService;this.storageProviderConfigService=storageProviderConfigService}logger=new Logger5(UploadService.name);async onModuleInit(){try{const{LocalProvider:LocalProvider2}=await Promise.resolve().then(()=>(init_local_provider(),local_provider_exports));StorageProviderRegistry.register("local",LocalProvider2);this.logger.log("\u2705 Local Storage Provider registered")}catch(error){this.logger.error("\u274C Failed to register Local Storage Provider",error)}try{const{S3Provider:S3Provider2}=await Promise.resolve().then(()=>(init_s3_provider_optional(),s3_provider_optional_exports));StorageProviderRegistry.register("aws",S3Provider2);this.logger.log("\u2705 AWS S3 Provider registered")}catch{this.logger.warn("\u26A0\uFE0F AWS S3 Provider not available")}try{const{AzureProvider:AzureProvider2}=await Promise.resolve().then(()=>(init_azure_provider_optional(),azure_provider_optional_exports));StorageProviderRegistry.register("azure",AzureProvider2);this.logger.log("\u2705 Azure Blob Provider registered")}catch{this.logger.warn("\u26A0\uFE0F Azure Blob Provider not available")}try{const{SftpProvider:SftpProvider2}=await Promise.resolve().then(()=>(init_sftp_provider_optional(),sftp_provider_optional_exports));StorageProviderRegistry.register("sftp",SftpProvider2);this.logger.log("\u2705 SFTP Provider registered")}catch{this.logger.warn("\u26A0\uFE0F SFTP Provider not available")}this.logger.log(`Available providers: ${this.storageFactory.getAvailableProviders().join(", ")}`)}validateFile(file){const sizeValidation=this.storageConfigService.validateFileSize(file.size);if(!sizeValidation.valid){throw new BadRequestException(sizeValidation.message)}const typeValidation=this.storageConfigService.validateFileType(file.mimetype);if(!typeValidation.valid){throw new BadRequestException(typeValidation.message)}}async getStorageProvider(storageConfigId,user){let storageConfig;if(storageConfigId){const config=await this.storageProviderConfigService.findById(storageConfigId,user??null,["name","storage","config","companyId"]);if(!config){throw new NotFoundException("Storage configuration not found")}if(this.storageConfigService.isCompanyFeatureEnabled()&&user?.companyId){const configWithCompany=config;if(configWithCompany.companyId&&configWithCompany.companyId!==user.companyId){throw new BadRequestException("Storage configuration belongs to another company")}}storageConfig=config}else{const defaultConfig=await this.storageProviderConfigService.getDefaultConfig(user);if(!defaultConfig){throw new NotFoundException("No default storage configuration found for your company/branch. Please create one.")}storageConfig=defaultConfig}const providerConfig={provider:storageConfig.storage,config:storageConfig.config};return await this.storageFactory.createProvider(providerConfig)}async uploadSingleFile(file,options,user){try{this.validateFile(file);const provider=await this.getStorageProvider(options.storageConfigId,user);return await provider.uploadFile(file,options)}catch(err){this.logger.error("Single file upload failed",err);throw new InternalServerErrorException(err.message)}}async uploadMultipleFiles(files,options,user){try{for(const file of files){this.validateFile(file)}const provider=await this.getStorageProvider(options.storageConfigId,user);return await provider.uploadMultipleFiles(files,options)}catch(err){this.logger.error("Multiple files upload failed",err);throw new InternalServerErrorException(err.message)}}async deleteSingleFile(key,storageConfigId,user){try{if(!key)throw new Error("No file path provided");const provider=await this.getStorageProvider(storageConfigId,user);await provider.deleteFile(key);return true}catch(err){this.logger.error("Delete single file failed",err);throw new InternalServerErrorException(err.message)}}async deleteMultipleFile(keys,storageConfigId,user){try{if(!keys||!keys.length)throw new Error("No file paths provided");const provider=await this.getStorageProvider(storageConfigId,user);await provider.deleteMultipleFiles(keys);return true}catch(err){this.logger.error("Delete multiple files failed",err);throw new InternalServerErrorException(err.message)}}bytesToKb(bytes){return Number((bytes*.001).toFixed(2))}async makeFileUrl(key,storageConfigId,expiresIn=3600,user){try{const provider=await this.getStorageProvider(storageConfigId,user);if(provider.generatePresignedUrl){return await provider.generatePresignedUrl(key,expiresIn)}return key}catch(err){this.logger.error("Generate file URL failed",err);throw new InternalServerErrorException(err.message)}}};__name(UploadService,"UploadService");UploadService=__decorateClass([Injectable()],UploadService);var STORAGE_MODULE_OPTIONS="STORAGE_MODULE_OPTIONS";var DEFAULT_MAX_FILE_SIZE=100*1024*1024;var DEFAULT_ALLOWED_FILE_TYPES=["*/*"];import{Inject,Injectable as Injectable2}from"@nestjs/common";var StorageConfigService=class{constructor(options){this.options=options}isCompanyFeatureEnabled(){return this.options.bootstrapAppConfig?.enableCompanyFeature??false}getDatabaseMode(){return this.options.bootstrapAppConfig?.databaseMode??"single"}getMaxFileSize(){return this.options.config?.maxFileSize??DEFAULT_MAX_FILE_SIZE}getAllowedFileTypes(){return this.options.config?.allowedFileTypes??DEFAULT_ALLOWED_FILE_TYPES}isFileTypeAllowed(mimeType){const allowedTypes=this.getAllowedFileTypes();if(allowedTypes.includes("*/*")){return true}return allowedTypes.some(allowedType=>{if(allowedType.endsWith("/*")){const prefix=allowedType.slice(0,-2);return mimeType.startsWith(prefix)}return allowedType===mimeType})}validateFileSize(fileSize){const maxSize=this.getMaxFileSize();if(fileSize>maxSize){const maxSizeMB=(maxSize/(1024*1024)).toFixed(2);const fileSizeMB=(fileSize/(1024*1024)).toFixed(2);return{valid:false,message:`File size (${fileSizeMB}MB) exceeds the maximum allowed size of ${maxSizeMB}MB`}}return{valid:true}}validateFileType(mimeType){if(!this.isFileTypeAllowed(mimeType)){const allowedTypes=this.getAllowedFileTypes();return{valid:false,message:`File type "${mimeType}" is not allowed. Allowed types: ${allowedTypes.join(", ")}`}}return{valid:true}}getDefaultDatabaseConfig(){return this.options.config?.defaultDatabaseConfig}getOptions(){return this.options}};__name(StorageConfigService,"StorageConfigService");StorageConfigService=__decorateClass([Injectable2(),__decorateParam(0,Inject(STORAGE_MODULE_OPTIONS))],StorageConfigService);var USER_ACTION_PERMISSION_CACHE_KEY="user_action_permission";var SHOW_PRIVATE_FILE_ACTION="storage.file.viewPrivate";var FileManagerService=class extends RequestScopedApiService{constructor(cacheManager,utilsService,uploadService,storageConfig,dataSourceProvider){super("file_manager",null,cacheManager,utilsService,FileManagerService.name,true);this.cacheManager=cacheManager;this.utilsService=utilsService;this.uploadService=uploadService;this.storageConfig=storageConfig;this.dataSourceProvider=dataSourceProvider}FILE_URL_EXPIRY_SECONDS=3600;resolveEntity(){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();return enableCompanyFeature?FileManagerWithCompany2:FileManager2}getDataSourceProvider(){return this.dataSourceProvider}async convertSingleDtoToEntity(dto,user){let fileManager={};if(dto instanceof UpdateFileManagerDto&&dto.id){const dbData=await this.repository.findOne({where:{id:dto.id}});if(!dbData){throw new NotFoundException2("No such entity data found for update! Please, Try Again.")}fileManager=dbData}let validatedFolder=null;if(dto.folderId){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();const folderEntity=enableCompanyFeature?FolderWithCompany2:Folder2;const folderRepository=await this.dataSourceProvider.getRepository(folderEntity);const whereCondition={id:dto.folderId};if(enableCompanyFeature&&user?.companyId){whereCondition.companyId=user.companyId}const folder=await folderRepository.findOne({where:whereCondition});if(!folder){throw new BadRequestException2(`Folder with ID ${dto.folderId} does not exist or you don't have access to it.`)}validatedFolder={id:dto.folderId}}let storageLocation=dto.location||FileLocationEnum3.LOCAL;if(dto.storageConfigId){try{const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();const storageConfigEntity=enableCompanyFeature?(await Promise.resolve().then(()=>(init_entities(),entities_exports))).StorageConfigWithCompany:(await Promise.resolve().then(()=>(init_entities(),entities_exports))).StorageConfig;const storageConfigRepository=await this.dataSourceProvider.getRepository(storageConfigEntity);const whereCondition={id:dto.storageConfigId};if(enableCompanyFeature&&user?.companyId){whereCondition.companyId=user.companyId}const storageConfig=await storageConfigRepository.findOne({where:whereCondition});if(storageConfig){storageLocation=storageConfig.storage}}catch(error){this.logger.warn(`Failed to get storage location from config: ${error}`)}}fileManager={...fileManager,...dto,location:storageLocation,folder:validatedFolder};if("companyId"in fileManager){fileManager.companyId=user?.companyId??null}return fileManager}async getSelectQuery(query,_user,select){if(!select||!select.length){select=["id","name","contentType","size","key","url","location","isPrivate","createdAt","deletedAt"]}const selectFields=select.map(field=>`${this.entityName}.${field}`);if(this.storageConfig.isCompanyFeatureEnabled()){selectFields.push("file_manager.companyId")}selectFields.push("folder.id");selectFields.push("folder.name");query.leftJoinAndSelect("file_manager.folder","folder");query.select(selectFields);return{query,isRaw:false}}async getFilterQuery(query,filter,_user){Object.entries(filter).forEach(([key,value])=>{if(key==="contentType"){const types=value.split(",").map(t=>t.trim());const patterns=types.map(t=>t.replace("*","%"));query.where(new Brackets(qb1=>{patterns.forEach((p,i)=>{const param=`p${i}`;if(i===0)qb1.where(`${this.entityName}.contentType LIKE :${param}`,{[param]:p});else qb1.orWhere(`${this.entityName}.contentType LIKE :${param}`,{[param]:p})})}));return}query.andWhere(`${this.entityName}.${key} = :value`,{value})});return{query,isRaw:false}}async getExtraManipulateQuery(query,filterDto,user){const result=await super.getExtraManipulateQuery(query,filterDto,user);const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();if(enableCompanyFeature&&user?.companyId){query.andWhere("file_manager.companyId = :companyId",{companyId:user.companyId})}if(user){const cacheKey=enableCompanyFeature?`${USER_ACTION_PERMISSION_CACHE_KEY}_${user.id}_${user.companyId}`:`${USER_ACTION_PERMISSION_CACHE_KEY}_${user.id}`;const userActions=await this.cacheManager.get(cacheKey);if(userActions){const userActionUrls=userActions.map(item=>item.url);if(!userActionUrls.includes(SHOW_PRIVATE_FILE_ACTION)){query.andWhere("file_manager.isPrivate = :isPrivate",{isPrivate:false})}}else{query.andWhere("file_manager.isPrivate = :isPrivate",{isPrivate:false})}}else{query.andWhere("file_manager.isPrivate = :isPrivate",{isPrivate:false})}return result}async beforeDeleteOperation(dto,_user,_queryRunner){if(dto.type==="permanent"){const ids=Array.isArray(dto.id)?dto.id:[dto.id];const fileManager=await this.repository.findBy({id:In(ids)});const filesByConfig=new Map;fileManager.forEach(file=>{const configId=file.storageConfigId||"default";if(!filesByConfig.has(configId)){filesByConfig.set(configId,[])}filesByConfig.get(configId).push(file.key)});for(const[configId,keys]of filesByConfig){await this.uploadService.deleteMultipleFile(keys,configId==="default"?void 0:configId)}}}async getFiles(dtos,protocol,host,user){await this.ensureRepositoryInitialized();const ids=dtos.map(d=>d.id).filter(Boolean);if(!ids.length)throw new BadRequestException2("No valid file IDs provided");const files=await this.repository.findBy({id:In(ids)});const now=Date.now();const expiresIn=this.FILE_URL_EXPIRY_SECONDS;const updatedFiles=[];const responses=await Promise.all(files.map(async file=>{let shouldUpdate=false;if(!file.storageConfigId){this.logger.warn(`File ${file.id} has no storageConfigId. Please update this file with a valid storage config.`)}const needsNewUrl=!file.url||file.location===FileLocationEnum3.AWS&&(typeof file.expiresAt!=="number"||now>=file.expiresAt)||file.location===FileLocationEnum3.AZURE&&(typeof file.expiresAt!=="number"||now>=file.expiresAt);if(needsNewUrl&&file.storageConfigId){try{file.url=await this.uploadService.makeFileUrl(file.key,file.storageConfigId,expiresIn,user);file.expiresAt=now+expiresIn*1e3;shouldUpdate=true}catch(error){this.logger.error(`Failed to generate URL for file ${file.id}: ${error?.message||"Unknown error"}`);file.url=`${protocol}://${host}/storage/upload/file/${file.key}`}}if(file.location===FileLocationEnum3.SFTP||file.location===FileLocationEnum3.LOCAL){const expectedUrl=`${protocol}://${host}/storage/upload/file/${file.key}`;if(file.url!==expectedUrl){file.url=expectedUrl;shouldUpdate=true}}if(shouldUpdate)updatedFiles.push(file);return{id:file.id,name:file.name,contentType:file.contentType,url:file.url||""}}));if(updatedFiles.length>0){try{await this.repository.save(updatedFiles)}catch(error){this.logger.error(`Failed to save updated file URLs: ${error?.message||"Unknown error"}`)}}return responses}};__name(FileManagerService,"FileManagerService");FileManagerService=__decorateClass([Injectable3(),__decorateParam(0,Inject2("CACHE_INSTANCE")),__decorateParam(2,Inject2(UploadService)),__decorateParam(3,Inject2(StorageConfigService))],FileManagerService);import{RequestScopedApiService as RequestScopedApiService2}from"@flusys/nestjs-shared/classes";import{UpdateFolderDto}from"@flusys/nestjs-storage/dtos";import{Folder as Folder3,FolderWithCompany as FolderWithCompany3}from"@flusys/nestjs-storage/entities";import{Inject as Inject3,Injectable as Injectable4,NotFoundException as NotFoundException3}from"@nestjs/common";var FolderService=class extends RequestScopedApiService2{constructor(cacheManager,utilsService,storageConfig,dataSourceProvider){super("folder",null,cacheManager,utilsService,FolderService.name,true);this.cacheManager=cacheManager;this.utilsService=utilsService;this.storageConfig=storageConfig;this.dataSourceProvider=dataSourceProvider}resolveEntity(){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();return enableCompanyFeature?FolderWithCompany3:Folder3}getDataSourceProvider(){return this.dataSourceProvider}async convertSingleDtoToEntity(dto,user){let folder={};if(dto instanceof UpdateFolderDto&&dto.id){const dbData=await this.repository.findOne({where:{id:dto.id}});if(!dbData){throw new NotFoundException3("No such entity data found for update! Please, Try Again.")}folder=dbData}folder={...folder,...dto};if("companyId"in folder){folder.companyId=user?.companyId??null}return folder}async getSelectQuery(query,_user,select){if(!select||!select.length){select=["id","name","slug","createdAt","deletedAt"]}const selectFields=select.map(field=>`${this.entityName}.${field}`);if(this.storageConfig.isCompanyFeatureEnabled()){selectFields.push("folder.companyId")}query.select(selectFields);return{query,isRaw:false}}async getExtraManipulateQuery(query,filterDto,user){const result=await super.getExtraManipulateQuery(query,filterDto,user);const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();if(enableCompanyFeature&&user?.companyId){query.andWhere("folder.companyId = :companyId",{companyId:user.companyId})}return result}};__name(FolderService,"FolderService");FolderService=__decorateClass([Injectable4(),__decorateParam(0,Inject3("CACHE_INSTANCE")),__decorateParam(2,Inject3(StorageConfigService))],FolderService);import{RequestScopedApiService as RequestScopedApiService3}from"@flusys/nestjs-shared/classes";import{StorageConfig as StorageConfig2,StorageConfigWithCompany as StorageConfigWithCompany2}from"@flusys/nestjs-storage/entities";import{Inject as Inject4,Injectable as Injectable5}from"@nestjs/common";var StorageProviderConfigService=class extends RequestScopedApiService3{constructor(cacheManager,utilsService,storageConfig,dataSourceProvider){super("storageConfig",null,cacheManager,utilsService,StorageProviderConfigService.name,true);this.cacheManager=cacheManager;this.utilsService=utilsService;this.storageConfig=storageConfig;this.dataSourceProvider=dataSourceProvider}resolveEntity(){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();return enableCompanyFeature?StorageConfigWithCompany2:StorageConfig2}getDataSourceProvider(){return this.dataSourceProvider}async convertSingleDtoToEntity(dto,user){let storageConfig={};storageConfig={...storageConfig,...dto};if("companyId"in storageConfig){storageConfig.companyId=user?.companyId??null}return storageConfig}async getSelectQuery(query,_user,select){if(!select||!select.length){select=["id","name","storage","config","createdAt","updatedAt"];if(this.storageConfig.isCompanyFeatureEnabled()){select.push("companyId")}}const selectFields=select.map(field=>`${this.entityName}.${field}`);query.select(selectFields);return{query,isRaw:false}}async getExtraManipulateQuery(query,filterDto,user){const result=await super.getExtraManipulateQuery(query,filterDto,user);const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();if(enableCompanyFeature&&user?.companyId){query.andWhere("storageConfig.companyId = :companyId",{companyId:user.companyId})}query.orderBy(`${this.entityName}.createdAt`,"DESC");return result}async getDefaultConfig(user){await this.ensureRepositoryInitialized();const baseWhere={};if(this.storageConfig.isCompanyFeatureEnabled()&&user?.companyId){baseWhere.companyId=user.companyId}const defaultConfig=await this.repository.findOne({where:{...baseWhere,name:"default"},order:{createdAt:"ASC"}});if(defaultConfig){return defaultConfig}return await this.repository.findOne({where:baseWhere,order:{createdAt:"ASC"}})}async getConfigByType(storage,user){await this.ensureRepositoryInitialized();const where={storage};if(this.storageConfig.isCompanyFeatureEnabled()&&user?.companyId){where.companyId=user.companyId}return await this.repository.find({where})}};__name(StorageProviderConfigService,"StorageProviderConfigService");StorageProviderConfigService=__decorateClass([Injectable5(),__decorateParam(0,Inject4("CACHE_INSTANCE")),__decorateParam(2,Inject4(StorageConfigService))],StorageProviderConfigService);import{MultiTenantDataSourceService}from"@flusys/nestjs-shared/modules";import{Inject as Inject5,Injectable as Injectable6,Logger as Logger6,Optional,Scope}from"@nestjs/common";import{REQUEST}from"@nestjs/core";var StorageDataSourceProvider=class extends MultiTenantDataSourceService{constructor(storageOptions,request){super(StorageDataSourceProvider.buildParentOptions(storageOptions),request);this.storageOptions=storageOptions}logger=new Logger6(StorageDataSourceProvider.name);static buildParentOptions(options){return{bootstrapAppConfig:options.bootstrapAppConfig,defaultDatabaseConfig:options.config?.defaultDatabaseConfig,tenantDefaultDatabaseConfig:options.config?.tenantDefaultDatabaseConfig,tenants:options.config?.tenants}}getEnableCompanyFeature(){return this.storageOptions.bootstrapAppConfig?.enableCompanyFeature??false}getEnableCompanyFeatureForTenant(tenant){return tenant?.enableCompanyFeature??this.getEnableCompanyFeature()}getEnableCompanyFeatureForCurrentTenant(){return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant()??void 0)}async getStorageEntities(enableCompanyFeature){const enable=enableCompanyFeature??this.getEnableCompanyFeature();const{FileManager:FileManager3,Folder:Folder4,StorageConfig:StorageConfig3}=await Promise.resolve().then(()=>(init_entities(),entities_exports));if(enable){const{FileManagerWithCompany:FileManagerWithCompany3,FolderWithCompany:FolderWithCompany4,StorageConfigWithCompany:StorageConfigWithCompany3}=await Promise.resolve().then(()=>(init_entities(),entities_exports));return[FileManagerWithCompany3,FolderWithCompany4,StorageConfigWithCompany3]}return[FileManager3,Folder4,StorageConfig3]}async createDataSourceFromConfig(config){const currentTenant=this.getCurrentTenant();const enableCompanyFeature=this.getEnableCompanyFeatureForTenant(currentTenant??void 0);const entities=await this.getStorageEntities(enableCompanyFeature);return super.createDataSourceFromConfig(config,entities)}async getSingleDataSource(){if(StorageDataSourceProvider.singleDataSource?.isInitialized){return StorageDataSourceProvider.singleDataSource}if(StorageDataSourceProvider.singleConnectionLock){return StorageDataSourceProvider.singleConnectionLock}const config=this.getDefaultDatabaseConfig();if(!config){throw new Error("No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.")}const connectionPromise=this.createDataSourceFromConfig(config);StorageDataSourceProvider.singleConnectionLock=connectionPromise;try{const dataSource=await connectionPromise;StorageDataSourceProvider.singleDataSource=dataSource;return dataSource}finally{StorageDataSourceProvider.singleConnectionLock=null}}async getOrCreateTenantConnection(tenant){const existing=StorageDataSourceProvider.tenantConnections.get(tenant.id);if(existing?.isInitialized){return existing}const pendingConnection=StorageDataSourceProvider.connectionLocks.get(tenant.id);if(pendingConnection){return pendingConnection}const config=this.buildTenantDatabaseConfig(tenant);const connectionPromise=this.createDataSourceFromConfig(config);StorageDataSourceProvider.connectionLocks.set(tenant.id,connectionPromise);try{const dataSource=await connectionPromise;StorageDataSourceProvider.tenantConnections.set(tenant.id,dataSource);return dataSource}finally{StorageDataSourceProvider.connectionLocks.delete(tenant.id)}}};__name(StorageDataSourceProvider,"StorageDataSourceProvider");__publicField(StorageDataSourceProvider,"tenantConnections",new Map);__publicField(StorageDataSourceProvider,"singleDataSource",null);__publicField(StorageDataSourceProvider,"tenantsRegistry",new Map);__publicField(StorageDataSourceProvider,"initialized",false);__publicField(StorageDataSourceProvider,"connectionLocks",new Map);__publicField(StorageDataSourceProvider,"singleConnectionLock",null);StorageDataSourceProvider=__decorateClass([Injectable6({scope:Scope.REQUEST}),__decorateParam(0,Inject5(STORAGE_MODULE_OPTIONS)),__decorateParam(1,Optional()),__decorateParam(1,Inject5(REQUEST))],StorageDataSourceProvider);export{FileManagerService,FolderService,StorageDataSourceProvider,StorageProviderConfigService,UploadService};
|
|
1
|
+
var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:true,configurable:true,writable:true,value}):obj[key]=value;var __name=(target,value)=>__defProp(target,"name",{value,configurable:true});var __esm=(fn,res)=>function __init(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __decorateClass=(decorators,target,key,kind)=>{var result=kind>1?void 0:kind?__getOwnPropDesc(target,key):target;for(var i=decorators.length-1,decorator;i>=0;i--)if(decorator=decorators[i])result=(kind?decorator(target,key,result):decorator(result))||result;if(kind&&result)__defProp(target,key,result);return result};var __decorateParam=(index,decorator)=>(target,key)=>decorator(target,key,index);var __publicField=(obj,key,value)=>__defNormalProp(obj,typeof key!=="symbol"?key+"":key,value);import{Identity}from"@flusys/nestjs-shared/entities";import{Column}from"typeorm";var FileManagerBase;var init_file_manager_base_entity=__esm({"projects/nestjs-storage/src/entities/file-manager-base.entity.ts"(){"use strict";FileManagerBase=class extends Identity{static{__name(this,"FileManagerBase")}name;contentType;size;key;url;location;storageConfigId;expiresAt=null;isPrivate};__decorateClass([Column({type:"varchar",length:255,nullable:false})],FileManagerBase.prototype,"name",2);__decorateClass([Column({type:"varchar",length:255,nullable:false})],FileManagerBase.prototype,"contentType",2);__decorateClass([Column({type:"varchar",length:255,nullable:false})],FileManagerBase.prototype,"size",2);__decorateClass([Column({type:"text",nullable:false})],FileManagerBase.prototype,"key",2);__decorateClass([Column({type:"text",nullable:true})],FileManagerBase.prototype,"url",2);__decorateClass([Column({type:"text",nullable:false})],FileManagerBase.prototype,"location",2);__decorateClass([Column({type:"uuid",nullable:true})],FileManagerBase.prototype,"storageConfigId",2);__decorateClass([Column({type:"bigint",nullable:true})],FileManagerBase.prototype,"expiresAt",2);__decorateClass([Column({type:"boolean",nullable:false,default:false})],FileManagerBase.prototype,"isPrivate",2)}});import{Identity as Identity2}from"@flusys/nestjs-shared/entities";import{Column as Column2}from"typeorm";var FolderBase;var init_folder_base_entity=__esm({"projects/nestjs-storage/src/entities/folder-base.entity.ts"(){"use strict";FolderBase=class extends Identity2{static{__name(this,"FolderBase")}name;slug};__decorateClass([Column2({type:"varchar",length:255,nullable:false})],FolderBase.prototype,"name",2);__decorateClass([Column2({type:"varchar",length:255,nullable:false})],FolderBase.prototype,"slug",2)}});var FileLocationEnum;var init_file_location_enum=__esm({"projects/nestjs-storage/src/enums/file-location.enum.ts"(){"use strict";FileLocationEnum=(FileLocationEnum2=>{FileLocationEnum2["AWS"]="aws";FileLocationEnum2["AZURE"]="azure";FileLocationEnum2["SFTP"]="sftp";FileLocationEnum2["LOCAL"]="local";return FileLocationEnum2})(FileLocationEnum||{})}});var init_enums=__esm({"projects/nestjs-storage/src/enums/index.ts"(){"use strict";init_file_location_enum()}});import{Identity as Identity3}from"@flusys/nestjs-shared/entities";import{Column as Column3}from"typeorm";var StorageConfigBase;var init_storage_config_base_entity=__esm({"projects/nestjs-storage/src/entities/storage-config-base.entity.ts"(){"use strict";init_enums();StorageConfigBase=class extends Identity3{static{__name(this,"StorageConfigBase")}name;storage;config};__decorateClass([Column3({type:"varchar",length:255,nullable:false})],StorageConfigBase.prototype,"name",2);__decorateClass([Column3({type:"enum",enum:FileLocationEnum,nullable:false})],StorageConfigBase.prototype,"storage",2);__decorateClass([Column3({type:"json",nullable:false})],StorageConfigBase.prototype,"config",2)}});import{Entity,JoinColumn,ManyToOne}from"typeorm";var FileManager;var init_file_manager_entity=__esm({"projects/nestjs-storage/src/entities/file-manager.entity.ts"(){"use strict";init_file_manager_base_entity();FileManager=class extends FileManagerBase{folder};__name(FileManager,"FileManager");__decorateClass([ManyToOne("Folder",folder=>folder.fileManager,{nullable:true,onDelete:"SET NULL"}),JoinColumn({name:"folder_id"})],FileManager.prototype,"folder",2);FileManager=__decorateClass([Entity({name:"file_manager"})],FileManager)}});import{Entity as Entity2,OneToMany}from"typeorm";var Folder;var init_folder_entity=__esm({"projects/nestjs-storage/src/entities/folder.entity.ts"(){"use strict";init_folder_base_entity();Folder=class extends FolderBase{fileManager};__name(Folder,"Folder");__decorateClass([OneToMany("FileManager",fileManager=>fileManager.folder)],Folder.prototype,"fileManager",2);Folder=__decorateClass([Entity2({name:"folder"})],Folder)}});import{Entity as Entity3}from"typeorm";var StorageConfig;var init_storage_config_entity=__esm({"projects/nestjs-storage/src/entities/storage-config.entity.ts"(){"use strict";init_storage_config_base_entity();StorageConfig=class extends StorageConfigBase{};__name(StorageConfig,"StorageConfig");StorageConfig=__decorateClass([Entity3({name:"storage_config"})],StorageConfig)}});import{Column as Column4,Entity as Entity4,JoinColumn as JoinColumn2,ManyToOne as ManyToOne2}from"typeorm";var FileManagerWithCompany;var init_file_manager_with_company_entity=__esm({"projects/nestjs-storage/src/entities/file-manager-with-company.entity.ts"(){"use strict";init_file_manager_base_entity();FileManagerWithCompany=class extends FileManagerBase{companyId;folder};__name(FileManagerWithCompany,"FileManagerWithCompany");__decorateClass([Column4({type:"uuid",nullable:true})],FileManagerWithCompany.prototype,"companyId",2);__decorateClass([ManyToOne2("FolderWithCompany",folder=>folder.fileManager,{nullable:true,onDelete:"SET NULL"}),JoinColumn2({name:"folder_id"})],FileManagerWithCompany.prototype,"folder",2);FileManagerWithCompany=__decorateClass([Entity4({name:"file_manager"})],FileManagerWithCompany)}});import{Column as Column5,Entity as Entity5,OneToMany as OneToMany2}from"typeorm";var FolderWithCompany;var init_folder_with_company_entity=__esm({"projects/nestjs-storage/src/entities/folder-with-company.entity.ts"(){"use strict";init_folder_base_entity();FolderWithCompany=class extends FolderBase{companyId;fileManager};__name(FolderWithCompany,"FolderWithCompany");__decorateClass([Column5({type:"uuid",nullable:true})],FolderWithCompany.prototype,"companyId",2);__decorateClass([OneToMany2("FileManagerWithCompany",fileManager=>fileManager.folder)],FolderWithCompany.prototype,"fileManager",2);FolderWithCompany=__decorateClass([Entity5({name:"folder"})],FolderWithCompany)}});import{Column as Column6,Entity as Entity6}from"typeorm";var StorageConfigWithCompany;var init_storage_config_with_company_entity=__esm({"projects/nestjs-storage/src/entities/storage-config-with-company.entity.ts"(){"use strict";init_storage_config_base_entity();StorageConfigWithCompany=class extends StorageConfigBase{companyId};__name(StorageConfigWithCompany,"StorageConfigWithCompany");__decorateClass([Column6({type:"uuid",nullable:true})],StorageConfigWithCompany.prototype,"companyId",2);StorageConfigWithCompany=__decorateClass([Entity6({name:"storage_config"})],StorageConfigWithCompany)}});var entities_exports={};__export(entities_exports,{FileManager:()=>FileManager,FileManagerBase:()=>FileManagerBase,FileManagerWithCompany:()=>FileManagerWithCompany,Folder:()=>Folder,FolderBase:()=>FolderBase,FolderWithCompany:()=>FolderWithCompany,StorageAllEntities:()=>StorageAllEntities,StorageCompanyEntities:()=>StorageCompanyEntities,StorageConfig:()=>StorageConfig,StorageConfigBase:()=>StorageConfigBase,StorageConfigWithCompany:()=>StorageConfigWithCompany,StorageCoreEntities:()=>StorageCoreEntities,getStorageEntitiesByConfig:()=>getStorageEntitiesByConfig});function getStorageEntitiesByConfig(enableCompanyFeature){return enableCompanyFeature?StorageCompanyEntities:StorageCoreEntities}var StorageCoreEntities,StorageCompanyEntities,StorageAllEntities;var init_entities=__esm({"projects/nestjs-storage/src/entities/index.ts"(){"use strict";init_file_manager_base_entity();init_folder_base_entity();init_storage_config_base_entity();init_file_manager_entity();init_folder_entity();init_storage_config_entity();init_file_manager_with_company_entity();init_folder_with_company_entity();init_storage_config_with_company_entity();init_file_manager_entity();init_folder_entity();init_storage_config_entity();init_file_manager_with_company_entity();init_folder_with_company_entity();init_storage_config_with_company_entity();StorageCoreEntities=[FileManager,Folder,StorageConfig];StorageCompanyEntities=[FileManagerWithCompany,FolderWithCompany,StorageConfigWithCompany];StorageAllEntities=[...StorageCoreEntities,...StorageCompanyEntities];__name(getStorageEntitiesByConfig,"getStorageEntitiesByConfig")}});import{RequestScopedApiService as RequestScopedApiService2}from"@flusys/nestjs-shared/classes";import{UtilsService as UtilsService2}from"@flusys/nestjs-shared/modules";import{BadRequestException as BadRequestException2,Inject as Inject5,Injectable as Injectable6,NotFoundException as NotFoundException3,Scope as Scope4}from"@nestjs/common";import{Brackets,In}from"typeorm";var STORAGE_MODULE_OPTIONS="STORAGE_MODULE_OPTIONS";var DEFAULT_MAX_FILE_SIZE=100*1024*1024;var DEFAULT_ALLOWED_FILE_TYPES=["*/*"];import{Inject,Injectable}from"@nestjs/common";var StorageConfigService=class{constructor(options){this.options=options}isCompanyFeatureEnabled(){return this.options.bootstrapAppConfig?.enableCompanyFeature??false}getDatabaseMode(){return this.options.bootstrapAppConfig?.databaseMode??"single"}getMaxFileSize(){return this.options.config?.maxFileSize??DEFAULT_MAX_FILE_SIZE}getAllowedFileTypes(){return this.options.config?.allowedFileTypes??DEFAULT_ALLOWED_FILE_TYPES}isFileTypeAllowed(mimeType){const allowedTypes=this.getAllowedFileTypes();if(allowedTypes.includes("*/*")){return true}return allowedTypes.some(allowedType=>{if(allowedType.endsWith("/*")){const prefix=allowedType.slice(0,-2);return mimeType.startsWith(prefix)}return allowedType===mimeType})}validateFileSize(fileSize){const maxSize=this.getMaxFileSize();if(fileSize>maxSize){const maxSizeMB=(maxSize/(1024*1024)).toFixed(2);const fileSizeMB=(fileSize/(1024*1024)).toFixed(2);return{valid:false,message:`File size (${fileSizeMB}MB) exceeds the maximum allowed size of ${maxSizeMB}MB`}}return{valid:true}}validateFileType(mimeType){if(!this.isFileTypeAllowed(mimeType)){const allowedTypes=this.getAllowedFileTypes();return{valid:false,message:`File type "${mimeType}" is not allowed. Allowed types: ${allowedTypes.join(", ")}`}}return{valid:true}}getDefaultDatabaseConfig(){return this.options.config?.defaultDatabaseConfig}getOptions(){return this.options}};__name(StorageConfigService,"StorageConfigService");StorageConfigService=__decorateClass([Injectable(),__decorateParam(0,Inject(STORAGE_MODULE_OPTIONS))],StorageConfigService);init_entities();init_file_location_enum();import{MultiTenantDataSourceService}from"@flusys/nestjs-shared/modules";import{Inject as Inject2,Injectable as Injectable2,Logger,Optional,Scope}from"@nestjs/common";import{REQUEST}from"@nestjs/core";var StorageDataSourceProvider=class extends MultiTenantDataSourceService{constructor(storageOptions,request){super(StorageDataSourceProvider.buildParentOptions(storageOptions),request);this.storageOptions=storageOptions}logger=new Logger(StorageDataSourceProvider.name);static buildParentOptions(options){return{bootstrapAppConfig:options.bootstrapAppConfig,defaultDatabaseConfig:options.config?.defaultDatabaseConfig,tenantDefaultDatabaseConfig:options.config?.tenantDefaultDatabaseConfig,tenants:options.config?.tenants}}getEnableCompanyFeature(){return this.storageOptions.bootstrapAppConfig?.enableCompanyFeature??false}getEnableCompanyFeatureForTenant(tenant){return tenant?.enableCompanyFeature??this.getEnableCompanyFeature()}getEnableCompanyFeatureForCurrentTenant(){return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant()??void 0)}async getStorageEntities(enableCompanyFeature){const enable=enableCompanyFeature??this.getEnableCompanyFeature();const{FileManager:FileManager2,Folder:Folder2,StorageConfig:StorageConfig2}=await Promise.resolve().then(()=>(init_entities(),entities_exports));if(enable){const{FileManagerWithCompany:FileManagerWithCompany2,FolderWithCompany:FolderWithCompany2,StorageConfigWithCompany:StorageConfigWithCompany2}=await Promise.resolve().then(()=>(init_entities(),entities_exports));return[FileManagerWithCompany2,FolderWithCompany2,StorageConfigWithCompany2]}return[FileManager2,Folder2,StorageConfig2]}async createDataSourceFromConfig(config){const currentTenant=this.getCurrentTenant();const enableCompanyFeature=this.getEnableCompanyFeatureForTenant(currentTenant??void 0);const entities=await this.getStorageEntities(enableCompanyFeature);return super.createDataSourceFromConfig(config,entities)}async getSingleDataSource(){if(StorageDataSourceProvider.singleDataSource?.isInitialized){return StorageDataSourceProvider.singleDataSource}if(StorageDataSourceProvider.singleConnectionLock){return StorageDataSourceProvider.singleConnectionLock}const config=this.getDefaultDatabaseConfig();if(!config){throw new Error("No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.")}const connectionPromise=this.createDataSourceFromConfig(config);StorageDataSourceProvider.singleConnectionLock=connectionPromise;try{const dataSource=await connectionPromise;StorageDataSourceProvider.singleDataSource=dataSource;return dataSource}finally{StorageDataSourceProvider.singleConnectionLock=null}}async getOrCreateTenantConnection(tenant){const existing=StorageDataSourceProvider.tenantConnections.get(tenant.id);if(existing?.isInitialized){return existing}const pendingConnection=StorageDataSourceProvider.connectionLocks.get(tenant.id);if(pendingConnection){return pendingConnection}const config=this.buildTenantDatabaseConfig(tenant);const connectionPromise=this.createDataSourceFromConfig(config);StorageDataSourceProvider.connectionLocks.set(tenant.id,connectionPromise);try{const dataSource=await connectionPromise;StorageDataSourceProvider.tenantConnections.set(tenant.id,dataSource);return dataSource}finally{StorageDataSourceProvider.connectionLocks.delete(tenant.id)}}};__name(StorageDataSourceProvider,"StorageDataSourceProvider");__publicField(StorageDataSourceProvider,"tenantConnections",new Map);__publicField(StorageDataSourceProvider,"singleDataSource",null);__publicField(StorageDataSourceProvider,"tenantsRegistry",new Map);__publicField(StorageDataSourceProvider,"initialized",false);__publicField(StorageDataSourceProvider,"connectionLocks",new Map);__publicField(StorageDataSourceProvider,"singleConnectionLock",null);StorageDataSourceProvider=__decorateClass([Injectable2({scope:Scope.REQUEST}),__decorateParam(0,Inject2(STORAGE_MODULE_OPTIONS)),__decorateParam(1,Optional()),__decorateParam(1,Inject2(REQUEST))],StorageDataSourceProvider);import{BadRequestException,Inject as Inject4,Injectable as Injectable5,InternalServerErrorException,Logger as Logger3,NotFoundException as NotFoundException2,Scope as Scope3}from"@nestjs/common";var StorageProviderRegistry=class{static{__name(this,"StorageProviderRegistry")}static providers=new Map;static register(providerName,providerClass){this.providers.set(providerName.toLowerCase(),providerClass)}static get(providerName){return this.providers.get(providerName.toLowerCase())}static has(providerName){return this.providers.has(providerName.toLowerCase())}static getAll(){return Array.from(this.providers.keys())}static clear(){this.providers.clear()}};import{Injectable as Injectable3,Logger as Logger2,NotFoundException}from"@nestjs/common";import*as crypto from"crypto";var StorageFactoryService=class{logger=new Logger2(StorageFactoryService.name);providerCache=new Map;generateCacheKey(config){const configString=JSON.stringify(config.config,Object.keys(config.config||{}).sort());const configHash=crypto.createHash("sha256").update(configString).digest("hex").substring(0,16);return`${config.provider}-${configHash}`}async createProvider(config){const providerKey=this.generateCacheKey(config);if(this.providerCache.has(providerKey)){return this.providerCache.get(providerKey)}const ProviderClass=StorageProviderRegistry.get(config.provider);if(!ProviderClass){throw new NotFoundException(`Storage provider '${config.provider}' is not registered. Available providers: ${StorageProviderRegistry.getAll().join(", ")}`)}try{const instance=new ProviderClass;if("initialize"in instance&&typeof instance.initialize==="function"){await instance.initialize(config.config)}this.providerCache.set(providerKey,instance);this.logger.log(`Created storage provider: ${config.provider} (key: ${providerKey})`);return instance}catch(error){this.logger.error(`Failed to create provider ${config.provider}:`,error);const originalMessage=error?.message||"Unknown error";throw new Error(`Failed to initialize storage provider '${config.provider}': ${originalMessage}`)}}async getProvider(providerName){const cachedKey=Array.from(this.providerCache.keys()).find(key=>key.startsWith(providerName));if(cachedKey){return this.providerCache.get(cachedKey)}return this.createProvider({provider:providerName,config:{}})}clearCache(){this.providerCache.clear()}isProviderAvailable(providerName){return StorageProviderRegistry.has(providerName)}getAvailableProviders(){return StorageProviderRegistry.getAll()}async onModuleDestroy(){this.logger.log("Cleaning up storage provider connections...");const closePromises=[];for(const[key,provider]of this.providerCache.entries()){if("close"in provider&&typeof provider.close==="function"){closePromises.push(provider.close().then(()=>this.logger.debug(`Closed provider: ${key}`)).catch(err=>this.logger.warn(`Failed to close provider ${key}: ${err.message}`)))}}await Promise.allSettled(closePromises);this.providerCache.clear();this.logger.log("Storage provider cleanup complete")}};__name(StorageFactoryService,"StorageFactoryService");StorageFactoryService=__decorateClass([Injectable3()],StorageFactoryService);import{RequestScopedApiService}from"@flusys/nestjs-shared/classes";import{UtilsService}from"@flusys/nestjs-shared/modules";import{Inject as Inject3,Injectable as Injectable4,Scope as Scope2}from"@nestjs/common";init_entities();var StorageProviderConfigService=class extends RequestScopedApiService{constructor(cacheManager,utilsService,storageConfig,dataSourceProvider){super("storageConfig",null,cacheManager,utilsService,StorageProviderConfigService.name,true);this.cacheManager=cacheManager;this.utilsService=utilsService;this.storageConfig=storageConfig;this.dataSourceProvider=dataSourceProvider}resolveEntity(){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();return enableCompanyFeature?StorageConfigWithCompany:StorageConfig}getDataSourceProvider(){return this.dataSourceProvider}async convertSingleDtoToEntity(dto,user){let storageConfig={};storageConfig={...storageConfig,...dto};if("companyId"in storageConfig){storageConfig.companyId=user?.companyId??null}return storageConfig}async getSelectQuery(query,_user,select){if(!select||!select.length){select=["id","name","storage","config","createdAt","updatedAt"];if(this.storageConfig.isCompanyFeatureEnabled()){select.push("companyId")}}const selectFields=select.map(field=>`${this.entityName}.${field}`);query.select(selectFields);return{query,isRaw:false}}async getExtraManipulateQuery(query,filterDto,user){const result=await super.getExtraManipulateQuery(query,filterDto,user);const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();if(enableCompanyFeature&&user?.companyId){query.andWhere("storageConfig.companyId = :companyId",{companyId:user.companyId})}query.orderBy(`${this.entityName}.createdAt`,"DESC");return result}async getDefaultConfig(user){await this.ensureRepositoryInitialized();const baseWhere={};if(this.storageConfig.isCompanyFeatureEnabled()&&user?.companyId){baseWhere.companyId=user.companyId}const defaultConfig=await this.repository.findOne({where:{...baseWhere,name:"default"},order:{createdAt:"ASC"}});if(defaultConfig){return defaultConfig}return await this.repository.findOne({where:baseWhere,order:{createdAt:"ASC"}})}async getConfigByType(storage,user){await this.ensureRepositoryInitialized();const where={storage};if(this.storageConfig.isCompanyFeatureEnabled()&&user?.companyId){where.companyId=user.companyId}return await this.repository.find({where})}};__name(StorageProviderConfigService,"StorageProviderConfigService");StorageProviderConfigService=__decorateClass([Injectable4({scope:Scope2.REQUEST}),__decorateParam(0,Inject3("CACHE_INSTANCE")),__decorateParam(1,Inject3(UtilsService)),__decorateParam(2,Inject3(StorageConfigService)),__decorateParam(3,Inject3(StorageDataSourceProvider))],StorageProviderConfigService);var UploadService=class{constructor(storageFactory,storageConfigService,storageProviderConfigService){this.storageFactory=storageFactory;this.storageConfigService=storageConfigService;this.storageProviderConfigService=storageProviderConfigService}logger=new Logger3(UploadService.name);validateFile(file){const sizeValidation=this.storageConfigService.validateFileSize(file.size);if(!sizeValidation.valid){throw new BadRequestException(sizeValidation.message)}const typeValidation=this.storageConfigService.validateFileType(file.mimetype);if(!typeValidation.valid){throw new BadRequestException(typeValidation.message)}}async getStorageProvider(storageConfigId,user){let storageConfig;if(storageConfigId){const config=await this.storageProviderConfigService.findById(storageConfigId,user??null,["name","storage","config","companyId"]);if(!config){throw new NotFoundException2("Storage configuration not found")}if(this.storageConfigService.isCompanyFeatureEnabled()&&user?.companyId){const configWithCompany=config;if(configWithCompany.companyId&&configWithCompany.companyId!==user.companyId){throw new BadRequestException("Storage configuration belongs to another company")}}storageConfig=config}else{const defaultConfig=await this.storageProviderConfigService.getDefaultConfig(user);if(!defaultConfig){throw new NotFoundException2("No default storage configuration found for your company/branch. Please create one.")}storageConfig=defaultConfig}const providerConfig={provider:storageConfig.storage,config:storageConfig.config};return await this.storageFactory.createProvider(providerConfig)}async uploadSingleFile(file,options,user){try{this.validateFile(file);const provider=await this.getStorageProvider(options.storageConfigId,user);return await provider.uploadFile(file,options)}catch(err){this.logger.error("Single file upload failed",err);throw new InternalServerErrorException(err.message)}}async uploadMultipleFiles(files,options,user){try{for(const file of files){this.validateFile(file)}const provider=await this.getStorageProvider(options.storageConfigId,user);return await provider.uploadMultipleFiles(files,options)}catch(err){this.logger.error("Multiple files upload failed",err);throw new InternalServerErrorException(err.message)}}async deleteSingleFile(key,storageConfigId,user){try{if(!key)throw new Error("No file path provided");const provider=await this.getStorageProvider(storageConfigId,user);await provider.deleteFile(key);return true}catch(err){this.logger.error("Delete single file failed",err);throw new InternalServerErrorException(err.message)}}async deleteMultipleFile(keys,storageConfigId,user){try{if(!keys||!keys.length)throw new Error("No file paths provided");const provider=await this.getStorageProvider(storageConfigId,user);await provider.deleteMultipleFiles(keys);return true}catch(err){this.logger.error("Delete multiple files failed",err);throw new InternalServerErrorException(err.message)}}bytesToKb(bytes){return Number((bytes*.001).toFixed(2))}async makeFileUrl(key,storageConfigId,expiresIn=3600,user){try{const provider=await this.getStorageProvider(storageConfigId,user);if(provider.generatePresignedUrl){return await provider.generatePresignedUrl(key,expiresIn)}return key}catch(err){this.logger.error("Generate file URL failed",err);throw new InternalServerErrorException(err.message)}}};__name(UploadService,"UploadService");UploadService=__decorateClass([Injectable5({scope:Scope3.REQUEST}),__decorateParam(0,Inject4(StorageFactoryService)),__decorateParam(1,Inject4(StorageConfigService)),__decorateParam(2,Inject4(StorageProviderConfigService))],UploadService);var USER_ACTION_PERMISSION_CACHE_KEY="user_action_permission";var SHOW_PRIVATE_FILE_ACTION="storage.file.viewPrivate";var FileManagerService=class extends RequestScopedApiService2{constructor(cacheManager,utilsService,uploadService,storageConfig,dataSourceProvider){super("file_manager",null,cacheManager,utilsService,FileManagerService.name,true);this.cacheManager=cacheManager;this.utilsService=utilsService;this.uploadService=uploadService;this.storageConfig=storageConfig;this.dataSourceProvider=dataSourceProvider}FILE_URL_EXPIRY_SECONDS=3600;resolveEntity(){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();return enableCompanyFeature?FileManagerWithCompany:FileManager}getDataSourceProvider(){return this.dataSourceProvider}async convertSingleDtoToEntity(dto,user){let fileManager={};if("id"in dto&&dto.id&&typeof dto.id==="string"){const dbData=await this.repository.findOne({where:{id:dto.id}});if(!dbData){throw new NotFoundException3("No such entity data found for update! Please, Try Again.")}fileManager=dbData}let validatedFolder=null;if(dto.folderId){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();const folderEntity=enableCompanyFeature?FolderWithCompany:Folder;const folderRepository=await this.dataSourceProvider.getRepository(folderEntity);const whereCondition={id:dto.folderId};if(enableCompanyFeature&&user?.companyId){whereCondition.companyId=user.companyId}const folder=await folderRepository.findOne({where:whereCondition});if(!folder){throw new BadRequestException2(`Folder with ID ${dto.folderId} does not exist or you don't have access to it.`)}validatedFolder={id:dto.folderId}}let storageLocation=dto.location||"local";if(dto.storageConfigId){try{const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();const storageConfigEntity=enableCompanyFeature?(await Promise.resolve().then(()=>(init_entities(),entities_exports))).StorageConfigWithCompany:(await Promise.resolve().then(()=>(init_entities(),entities_exports))).StorageConfig;const storageConfigRepository=await this.dataSourceProvider.getRepository(storageConfigEntity);const whereCondition={id:dto.storageConfigId};if(enableCompanyFeature&&user?.companyId){whereCondition.companyId=user.companyId}const storageConfig=await storageConfigRepository.findOne({where:whereCondition});if(storageConfig){storageLocation=storageConfig.storage}}catch(error){this.logger.warn(`Failed to get storage location from config: ${error}`)}}fileManager={...fileManager,...dto,location:storageLocation,folder:validatedFolder};if("companyId"in fileManager){fileManager.companyId=user?.companyId??null}return fileManager}async getSelectQuery(query,_user,select){if(!select||!select.length){select=["id","name","contentType","size","key","url","location","isPrivate","createdAt","deletedAt"]}const selectFields=select.map(field=>`${this.entityName}.${field}`);if(this.storageConfig.isCompanyFeatureEnabled()){selectFields.push("file_manager.companyId")}selectFields.push("folder.id");selectFields.push("folder.name");query.leftJoinAndSelect("file_manager.folder","folder");query.select(selectFields);return{query,isRaw:false}}async getFilterQuery(query,filter,_user){Object.entries(filter).forEach(([key,value])=>{if(key==="contentType"){const types=value.split(",").map(t=>t.trim());const patterns=types.map(t=>t.replace("*","%"));query.where(new Brackets(qb1=>{patterns.forEach((p,i)=>{const param=`p${i}`;if(i===0)qb1.where(`${this.entityName}.contentType LIKE :${param}`,{[param]:p});else qb1.orWhere(`${this.entityName}.contentType LIKE :${param}`,{[param]:p})})}));return}query.andWhere(`${this.entityName}.${key} = :value`,{value})});return{query,isRaw:false}}async getExtraManipulateQuery(query,filterDto,user){const result=await super.getExtraManipulateQuery(query,filterDto,user);const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();if(enableCompanyFeature&&user?.companyId){query.andWhere("file_manager.companyId = :companyId",{companyId:user.companyId})}if(user){const cacheKey=enableCompanyFeature?`${USER_ACTION_PERMISSION_CACHE_KEY}_${user.id}_${user.companyId}`:`${USER_ACTION_PERMISSION_CACHE_KEY}_${user.id}`;const userActions=await this.cacheManager.get(cacheKey);if(userActions){const userActionUrls=userActions.map(item=>item.url);if(!userActionUrls.includes(SHOW_PRIVATE_FILE_ACTION)){query.andWhere("file_manager.isPrivate = :isPrivate",{isPrivate:false})}}else{query.andWhere("file_manager.isPrivate = :isPrivate",{isPrivate:false})}}else{query.andWhere("file_manager.isPrivate = :isPrivate",{isPrivate:false})}return result}async beforeDeleteOperation(dto,_user,_queryRunner){if(dto.type==="permanent"){const ids=Array.isArray(dto.id)?dto.id:[dto.id];const fileManager=await this.repository.findBy({id:In(ids)});const filesByConfig=new Map;fileManager.forEach(file=>{const configId=file.storageConfigId||"default";if(!filesByConfig.has(configId)){filesByConfig.set(configId,[])}filesByConfig.get(configId).push(file.key)});for(const[configId,keys]of filesByConfig){await this.uploadService.deleteMultipleFile(keys,configId==="default"?void 0:configId)}}}async getFiles(dtos,protocol,host,user){await this.ensureRepositoryInitialized();const ids=dtos.map(d=>d.id).filter(Boolean);if(!ids.length)throw new BadRequestException2("No valid file IDs provided");const files=await this.repository.findBy({id:In(ids)});const now=Date.now();const expiresIn=this.FILE_URL_EXPIRY_SECONDS;const updatedFiles=[];const responses=await Promise.all(files.map(async file=>{let shouldUpdate=false;if(!file.storageConfigId){this.logger.warn(`File ${file.id} has no storageConfigId. Please update this file with a valid storage config.`)}const needsNewUrl=!file.url||file.location==="aws"&&(typeof file.expiresAt!=="number"||now>=file.expiresAt)||file.location==="azure"&&(typeof file.expiresAt!=="number"||now>=file.expiresAt);if(needsNewUrl&&file.storageConfigId){try{file.url=await this.uploadService.makeFileUrl(file.key,file.storageConfigId,expiresIn,user);file.expiresAt=now+expiresIn*1e3;shouldUpdate=true}catch(error){this.logger.error(`Failed to generate URL for file ${file.id}: ${error?.message||"Unknown error"}`);file.url=`${protocol}://${host}/storage/upload/file/${file.key}`}}if(file.location==="sftp"||file.location==="local"){const expectedUrl=`${protocol}://${host}/storage/upload/file/${file.key}`;if(file.url!==expectedUrl){file.url=expectedUrl;shouldUpdate=true}}if(shouldUpdate)updatedFiles.push(file);return{id:file.id,name:file.name,contentType:file.contentType,url:file.url||""}}));if(updatedFiles.length>0){try{await this.repository.save(updatedFiles)}catch(error){this.logger.error(`Failed to save updated file URLs: ${error?.message||"Unknown error"}`)}}return responses}};__name(FileManagerService,"FileManagerService");FileManagerService=__decorateClass([Injectable6({scope:Scope4.REQUEST}),__decorateParam(0,Inject5("CACHE_INSTANCE")),__decorateParam(1,Inject5(UtilsService2)),__decorateParam(2,Inject5(UploadService)),__decorateParam(3,Inject5(StorageConfigService)),__decorateParam(4,Inject5(StorageDataSourceProvider))],FileManagerService);import{RequestScopedApiService as RequestScopedApiService3}from"@flusys/nestjs-shared/classes";import{UtilsService as UtilsService3}from"@flusys/nestjs-shared/modules";import{Inject as Inject6,Injectable as Injectable7,NotFoundException as NotFoundException4,Scope as Scope5}from"@nestjs/common";init_entities();var FolderService=class extends RequestScopedApiService3{constructor(cacheManager,utilsService,storageConfig,dataSourceProvider){super("folder",null,cacheManager,utilsService,FolderService.name,true);this.cacheManager=cacheManager;this.utilsService=utilsService;this.storageConfig=storageConfig;this.dataSourceProvider=dataSourceProvider}resolveEntity(){const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();return enableCompanyFeature?FolderWithCompany:Folder}getDataSourceProvider(){return this.dataSourceProvider}async convertSingleDtoToEntity(dto,user){let folder={};if("id"in dto&&dto.id&&typeof dto.id==="string"){const dbData=await this.repository.findOne({where:{id:dto.id}});if(!dbData){throw new NotFoundException4("No such entity data found for update! Please, Try Again.")}folder=dbData}folder={...folder,...dto};if("companyId"in folder){folder.companyId=user?.companyId??null}return folder}async getSelectQuery(query,_user,select){if(!select||!select.length){select=["id","name","slug","createdAt","deletedAt"]}const selectFields=select.map(field=>`${this.entityName}.${field}`);if(this.storageConfig.isCompanyFeatureEnabled()){selectFields.push("folder.companyId")}query.select(selectFields);return{query,isRaw:false}}async getExtraManipulateQuery(query,filterDto,user){const result=await super.getExtraManipulateQuery(query,filterDto,user);const enableCompanyFeature=this.storageConfig.isCompanyFeatureEnabled();if(enableCompanyFeature&&user?.companyId){query.andWhere("folder.companyId = :companyId",{companyId:user.companyId})}return result}};__name(FolderService,"FolderService");FolderService=__decorateClass([Injectable7({scope:Scope5.REQUEST}),__decorateParam(0,Inject6("CACHE_INSTANCE")),__decorateParam(1,Inject6(UtilsService3)),__decorateParam(2,Inject6(StorageConfigService)),__decorateParam(3,Inject6(StorageDataSourceProvider))],FolderService);export{FileManagerService,FolderService,StorageDataSourceProvider,StorageProviderConfigService,UploadService};
|
package/fesm/utils-index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:true});import
|
|
1
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:true});import sharp from"sharp";var ImageCompressor=class{static{__name(this,"ImageCompressor")}static async compress(buffer,mimetype,options={}){const{maxWidth=1280,maxHeight=1280,quality=85,format="original"}=options;if(mimetype==="image/svg+xml"){return{buffer,format:mimetype}}const image=sharp(buffer,{failOnError:false,density:300});image.resize({width:maxWidth,height:maxHeight,fit:"inside",withoutEnlargement:true});let targetFormat=format!=="original"?format:mimetype.split("/")[1];switch(targetFormat.toLowerCase()){case"jpeg":case"jpg":image.jpeg({quality,mozjpeg:true,chromaSubsampling:"4:4:4"});break;case"png":image.png({compressionLevel:9,adaptiveFiltering:true,palette:true,quality,colors:256,dither:1});break;case"webp":image.webp({quality,smartSubsample:true,effort:6,lossless:quality===100});break;case"avif":image.avif({quality,effort:6,chromaSubsampling:"4:4:4"});break;case"tiff":image.tiff({quality,compression:"lzw",predictor:"horizontal",pyramid:true});break;case"gif":image.gif({colours:256,effort:10,dither:1});break;case"jp2":image.jp2({quality,lossless:quality===100});break;default:targetFormat="webp";image.webp({quality,smartSubsample:true,effort:6});break}try{const{data,info}=await image.toBuffer({resolveWithObject:true});return{buffer:data,format:`image/${targetFormat}`}}catch(error){console.warn(`Image processing failed: ${error instanceof Error?error.message:String(error)}`);return{buffer,format:mimetype}}}};export{ImageCompressor};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IIdentity } from '@flusys/nestjs-shared/interfaces';
|
|
2
|
-
import { FileLocationEnum } from '
|
|
2
|
+
import { FileLocationEnum } from '../enums';
|
|
3
3
|
export interface IStorageConfig extends IIdentity {
|
|
4
4
|
name: string;
|
|
5
5
|
storage: FileLocationEnum;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-storage",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
4
|
"description": "Modular storage package with optional AWS S3, Azure Blob, and SFTP providers",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -77,6 +77,11 @@
|
|
|
77
77
|
"types": "./utils/index.d.ts",
|
|
78
78
|
"import": "./fesm/utils-index.js",
|
|
79
79
|
"require": "./cjs/utils-index.js"
|
|
80
|
+
},
|
|
81
|
+
"./*": {
|
|
82
|
+
"types": "./*.d.ts",
|
|
83
|
+
"import": "./*.js",
|
|
84
|
+
"require": "./*.js"
|
|
80
85
|
}
|
|
81
86
|
},
|
|
82
87
|
"peerDependencies": {
|
|
@@ -96,8 +101,8 @@
|
|
|
96
101
|
}
|
|
97
102
|
},
|
|
98
103
|
"dependencies": {
|
|
99
|
-
"@flusys/nestjs-core": "0.1.0-
|
|
100
|
-
"@flusys/nestjs-shared": "0.1.0-
|
|
104
|
+
"@flusys/nestjs-core": "0.1.0-beta.1",
|
|
105
|
+
"@flusys/nestjs-shared": "0.1.0-beta.1"
|
|
101
106
|
},
|
|
102
107
|
"optionalDependencies": {
|
|
103
108
|
"@aws-sdk/client-s3": "^3.400.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { UploadOptionsDto } from '
|
|
2
|
-
import { IStorageProvider, IUploadedFileInfo } from '
|
|
1
|
+
import { UploadOptionsDto } from '../dtos';
|
|
2
|
+
import { IStorageProvider, IUploadedFileInfo } from '../interfaces';
|
|
3
3
|
export declare class AzureProvider implements IStorageProvider {
|
|
4
4
|
private logger;
|
|
5
5
|
private blobServiceClient;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { UploadOptionsDto } from '
|
|
2
|
-
import { IStorageProvider, IUploadedFileInfo } from '
|
|
1
|
+
import { UploadOptionsDto } from '../dtos';
|
|
2
|
+
import { IStorageProvider, IUploadedFileInfo } from '../interfaces';
|
|
3
3
|
export declare class S3Provider implements IStorageProvider {
|
|
4
4
|
private logger;
|
|
5
5
|
private s3;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { UploadOptionsDto } from '
|
|
2
|
-
import { IStorageProvider, IUploadedFileInfo } from '
|
|
1
|
+
import { UploadOptionsDto } from '../dtos';
|
|
2
|
+
import { IStorageProvider, IUploadedFileInfo } from '../interfaces';
|
|
3
3
|
export declare class SftpProvider implements IStorageProvider {
|
|
4
4
|
private logger;
|
|
5
5
|
private sftp;
|
|
@@ -2,13 +2,13 @@ import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/clas
|
|
|
2
2
|
import { DeleteDto, FilterAndPaginationDto } from '@flusys/nestjs-shared/dtos';
|
|
3
3
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
4
4
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
5
|
-
import { CreateFileManagerDto, FilesResponseDto, GetFilesRequestDto, UpdateFileManagerDto } from '@flusys/nestjs-storage/dtos';
|
|
6
|
-
import { IFileManager } from '@flusys/nestjs-storage/interfaces';
|
|
7
|
-
import { FileManagerBase } from '@flusys/nestjs-storage/entities';
|
|
8
5
|
import { QueryRunner, EntityTarget, Repository, SelectQueryBuilder } from 'typeorm';
|
|
9
|
-
import { UploadService } from './upload.service';
|
|
10
6
|
import { StorageConfigService } from '../config';
|
|
7
|
+
import { CreateFileManagerDto, FilesResponseDto, GetFilesRequestDto, UpdateFileManagerDto } from '../dtos';
|
|
8
|
+
import { FileManagerBase } from '../entities';
|
|
9
|
+
import { IFileManager } from '../interfaces';
|
|
11
10
|
import { StorageDataSourceProvider } from './storage-datasource.provider';
|
|
11
|
+
import { UploadService } from './upload.service';
|
|
12
12
|
export declare class FileManagerService extends RequestScopedApiService<CreateFileManagerDto, UpdateFileManagerDto, IFileManager, FileManagerBase, Repository<FileManagerBase>> {
|
|
13
13
|
protected cacheManager: HybridCache;
|
|
14
14
|
protected utilsService: UtilsService;
|
|
@@ -2,11 +2,11 @@ import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/clas
|
|
|
2
2
|
import { FilterAndPaginationDto } from '@flusys/nestjs-shared/dtos';
|
|
3
3
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
4
4
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
5
|
-
import { CreateFolderDto, UpdateFolderDto } from '@flusys/nestjs-storage/dtos';
|
|
6
|
-
import { IFolder } from '@flusys/nestjs-storage/interfaces';
|
|
7
|
-
import { FolderBase } from '@flusys/nestjs-storage/entities';
|
|
8
5
|
import { EntityTarget, Repository, SelectQueryBuilder } from 'typeorm';
|
|
9
6
|
import { StorageConfigService } from '../config';
|
|
7
|
+
import { CreateFolderDto, UpdateFolderDto } from '../dtos';
|
|
8
|
+
import { FolderBase } from '../entities';
|
|
9
|
+
import { IFolder } from '../interfaces';
|
|
10
10
|
import { StorageDataSourceProvider } from './storage-datasource.provider';
|
|
11
11
|
export declare class FolderService extends RequestScopedApiService<CreateFolderDto, UpdateFolderDto, IFolder, FolderBase, Repository<FolderBase>> {
|
|
12
12
|
protected cacheManager: HybridCache;
|
|
@@ -2,12 +2,12 @@ import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/clas
|
|
|
2
2
|
import { FilterAndPaginationDto } from '@flusys/nestjs-shared/dtos';
|
|
3
3
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
4
4
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
5
|
-
import { CreateStorageConfigDto, UpdateStorageConfigDto } from '@flusys/nestjs-storage/dtos';
|
|
6
|
-
import { FileLocationEnum } from '@flusys/nestjs-storage/enums';
|
|
7
|
-
import { IStorageConfig } from '@flusys/nestjs-storage/interfaces';
|
|
8
|
-
import { StorageConfigBase } from '@flusys/nestjs-storage/entities';
|
|
9
5
|
import { EntityTarget, Repository, SelectQueryBuilder } from 'typeorm';
|
|
10
6
|
import { StorageConfigService } from '../config';
|
|
7
|
+
import { CreateStorageConfigDto, UpdateStorageConfigDto } from '../dtos';
|
|
8
|
+
import { StorageConfigBase } from '../entities';
|
|
9
|
+
import { FileLocationEnum } from '../enums';
|
|
10
|
+
import { IStorageConfig } from '../interfaces';
|
|
11
11
|
import { StorageDataSourceProvider } from './storage-datasource.provider';
|
|
12
12
|
export declare class StorageProviderConfigService extends RequestScopedApiService<CreateStorageConfigDto, UpdateStorageConfigDto, IStorageConfig, StorageConfigBase, Repository<StorageConfigBase>> {
|
|
13
13
|
protected cacheManager: HybridCache;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
2
|
-
import { OnModuleInit } from '@nestjs/common';
|
|
3
2
|
import { StorageConfigService } from '../config';
|
|
4
3
|
import { UploadOptionsDto } from '../dtos/upload.dto';
|
|
5
4
|
import { IUploadedFileInfo } from '../interfaces/storage-provider.interface';
|
|
6
5
|
import { StorageFactoryService } from '../providers/storage-factory.service';
|
|
7
6
|
import { StorageProviderConfigService } from './storage-provider-config.service';
|
|
8
|
-
export declare class UploadService
|
|
7
|
+
export declare class UploadService {
|
|
9
8
|
private readonly storageFactory;
|
|
10
9
|
private readonly storageConfigService;
|
|
11
10
|
private readonly storageProviderConfigService;
|
|
12
11
|
private logger;
|
|
13
12
|
constructor(storageFactory: StorageFactoryService, storageConfigService: StorageConfigService, storageProviderConfigService: StorageProviderConfigService);
|
|
14
|
-
onModuleInit(): Promise<void>;
|
|
15
13
|
private validateFile;
|
|
16
14
|
private getStorageProvider;
|
|
17
15
|
uploadSingleFile(file: Express.Multer.File, options: UploadOptionsDto, user?: ILoggedUserInfo): Promise<IUploadedFileInfo>;
|