@gune/storage-nestjs
v0.1.0
Published
NestJS integration for @gune/storage
Readme
@gune/storage-nestjs
NestJS integration module for @gune/storage with dependency injection support.
Installation
npm install @gune/storage-core @gune/storage-nestjs
# Plus your storage strategy
npm install @gune/storage-s3Features
- 🔌 Dynamic Module: Configure via
forRoot()orforRootAsync() - 💉 Dependency Injection: Inject storage via
@InjectStorage()decorator - 🎯 Multi-Storage: Support multiple storage strategies simultaneously
- 🌍 Global Module: Optional global registration
- ⚙️ Async Configuration: Integrate with
ConfigService
Quick Start
1. Synchronous Configuration
import { Module } from '@nestjs/common';
import { StorageModule } from '@gune/storage-nestjs';
import { S3StorageStrategy } from '@gune/storage-s3';
@Module({
imports: [
StorageModule.forRoot({
strategy: new S3StorageStrategy({
region: 'us-east-1',
bucket: 'my-bucket',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
}),
isGlobal: true, // Available in all modules
}),
],
})
export class AppModule {}2. Async Configuration
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { StorageModule } from '@gune/storage-nestjs';
import { S3StorageStrategy } from '@gune/storage-s3';
@Module({
imports: [
ConfigModule.forRoot(),
StorageModule.forRootAsync({
imports: [ConfigModule],
isGlobal: true,
useFactory: (config: ConfigService) => ({
strategy: new S3StorageStrategy({
region: config.getOrThrow('AWS_REGION'),
bucket: config.getOrThrow('S3_BUCKET'),
credentials: {
accessKeyId: config.getOrThrow('AWS_ACCESS_KEY_ID'),
secretAccessKey: config.getOrThrow('AWS_SECRET_ACCESS_KEY'),
},
}),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}3. Using in Services
import { Injectable } from '@nestjs/common';
import { InjectStorage } from '@gune/storage-nestjs';
import { StorageInstance } from '@gune/storage-core';
import { Readable } from 'stream';
@Injectable()
export class FileService {
constructor(
@InjectStorage() private readonly storage: StorageInstance,
) {}
async uploadFile(file: Express.Multer.File) {
const result = await this.storage.uploadFile({
stream: Readable.from(file.buffer),
filename: file.originalname,
contentType: file.mimetype,
size: file.size,
});
return result;
}
async deleteFile(key: string) {
await this.storage.deleteFile(key);
}
}Multi-Storage Configuration
Use multiple storage strategies in the same application:
@Module({
imports: [
// Default storage (S3)
StorageModule.forRoot({
strategy: new S3StorageStrategy({ ... }),
isGlobal: true,
}),
// Named storage for temporary files
StorageModule.forRoot({
name: 'temp',
strategy: new LocalStorageStrategy({
basePath: './temp-storage',
baseUrl: '/temp',
}),
}),
// Named storage for media processing
StorageModule.forRoot({
name: 'media',
strategy: new CloudinaryStorageStrategy({ ... }),
}),
],
})
export class AppModule {}Inject named storage instances:
@Injectable()
export class MediaService {
constructor(
@InjectStorage() private readonly storage: StorageInstance, // Default
@InjectStorage('temp') private readonly tempStorage: StorageInstance, // Named
@InjectStorage('media') private readonly mediaStorage: StorageInstance,
) {}
async processMedia(file: Buffer) {
// Upload to temp storage first
const temp = await this.tempStorage.uploadFile({ ... });
// Process and upload to media storage
const processed = await this.processImage(temp.url);
const result = await this.mediaStorage.uploadFile(processed);
// Clean up temp file
await this.tempStorage.deleteFile(temp.key);
return result;
}
}Advanced Patterns
Factory Class Configuration
import { Injectable } from '@nestjs/common';
import { StorageModuleOptionsFactory, StorageModuleOptions } from '@gune/storage-nestjs';
@Injectable()
export class StorageConfigService implements StorageModuleOptionsFactory {
constructor(private config: ConfigService) {}
createStorageOptions(): StorageModuleOptions {
const driver = this.config.get('STORAGE_DRIVER');
if (driver === 's3') {
return {
strategy: new S3StorageStrategy({ ... }),
};
}
return {
strategy: new LocalStorageStrategy({ ... }),
};
}
}
@Module({
imports: [
StorageModule.forRootAsync({
useClass: StorageConfigService,
inject: [ConfigService],
}),
],
})
export class AppModule {}Custom Logger Integration
import { Logger } from '@nestjs/common';
import { StorageLogger } from '@gune/storage-core';
class NestStorageLogger implements StorageLogger {
private logger = new Logger('StorageModule');
debug(message: string, context?: Record<string, unknown>): void {
this.logger.debug(message, context);
}
info(message: string, context?: Record<string, unknown>): void {
this.logger.log(message, context);
}
warn(message: string, context?: Record<string, unknown>): void {
this.logger.warn(message, context);
}
error(message: string, error?: Error, context?: Record<string, unknown>): void {
this.logger.error(message, error?.stack, context);
}
}
// Use in strategy configuration
StorageModule.forRoot({
strategy: new S3StorageStrategy({
...config,
logger: new NestStorageLogger(),
}),
});API Reference
StorageModule
Static Methods
forRoot(options: StorageModuleOptions): DynamicModule
Configure storage module synchronously.
Options:
strategy: StorageStrategy- Storage strategy instancename?: string- Name for multi-storage (optional)isGlobal?: boolean- Register as global module (default: false)
forRootAsync(options: StorageModuleAsyncOptions): DynamicModule
Configure storage module asynchronously.
Options:
imports?: any[]- Modules to importuseFactory?: (...args) => StorageModuleOptions- Factory functioninject?: any[]- Dependencies for factoryuseClass?: Type<StorageModuleOptionsFactory>- Factory classuseExisting?: Type<StorageModuleOptionsFactory>- Existing factoryname?: string- Name for multi-storageisGlobal?: boolean- Register as global module
@InjectStorage(name?: string)
Decorator to inject storage instance.
constructor(
@InjectStorage() private storage: StorageInstance,
@InjectStorage('temp') private tempStorage: StorageInstance,
) {}Migration from Existing Implementation
Before (Your Current Code)
// src/internal/storage/storage.module.ts
@Global()
@Module({
providers: [
{
provide: IStorageStrategy,
useFactory: (config: ConfigService) => {
const driver = config.getOrThrow<string>(configKeys.storage.driver);
switch (driver) {
case 's3':
return new S3Strategy(config);
// ...
}
},
inject: [ConfigService],
},
],
exports: [IStorageStrategy],
})
export class StorageModule {}
// Usage
constructor(private readonly storageStrategy: IStorageStrategy) {}After (Using @gune/storage-nestjs)
// app.module.ts
@Module({
imports: [
StorageModule.forRootAsync({
imports: [ConfigModule],
isGlobal: true,
useFactory: (config: ConfigService) => {
const driver = config.getOrThrow(configKeys.storage.driver);
if (driver === 's3') {
return {
strategy: new S3StorageStrategy({
region: config.getOrThrow(configKeys.storage.region),
bucket: config.getOrThrow(configKeys.storage.bucketName),
credentials: {
accessKeyId: config.getOrThrow(configKeys.storage.accessKey),
secretAccessKey: config.getOrThrow(configKeys.storage.secretKey),
},
}),
};
}
return {
strategy: new LocalStorageStrategy({
basePath: './storage',
baseUrl: config.get(configKeys.appUrl) + '/storage',
}),
};
},
inject: [ConfigService],
}),
],
})
export class AppModule {}
// Usage
constructor(@InjectStorage() private readonly storage: StorageInstance) {}License
MIT
