import * as plugins from './plugins.js'; import * as paths from './paths.js'; import { Smarts3Server } from './classes/smarts3-server.js'; /** * Authentication configuration */ export interface IAuthConfig { enabled: boolean; credentials: Array<{ accessKeyId: string; secretAccessKey: string; }>; } /** * CORS configuration */ export interface ICorsConfig { enabled: boolean; allowedOrigins?: string[]; allowedMethods?: string[]; allowedHeaders?: string[]; exposedHeaders?: string[]; maxAge?: number; allowCredentials?: boolean; } /** * Logging configuration */ export interface ILoggingConfig { level?: 'error' | 'warn' | 'info' | 'debug'; format?: 'text' | 'json'; enabled?: boolean; } /** * Request limits configuration */ export interface ILimitsConfig { maxObjectSize?: number; maxMetadataSize?: number; requestTimeout?: number; } /** * Server configuration */ export interface IServerConfig { port?: number; address?: string; silent?: boolean; } /** * Storage configuration */ export interface IStorageConfig { directory?: string; cleanSlate?: boolean; } /** * Complete smarts3 configuration */ export interface ISmarts3Config { server?: IServerConfig; storage?: IStorageConfig; auth?: IAuthConfig; cors?: ICorsConfig; logging?: ILoggingConfig; limits?: ILimitsConfig; } /** * Default configuration values */ const DEFAULT_CONFIG: ISmarts3Config = { server: { port: 3000, address: '0.0.0.0', silent: false, }, storage: { directory: paths.bucketsDir, cleanSlate: false, }, auth: { enabled: false, credentials: [ { accessKeyId: 'S3RVER', secretAccessKey: 'S3RVER', }, ], }, cors: { enabled: false, allowedOrigins: ['*'], allowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'], allowedHeaders: ['*'], exposedHeaders: ['ETag', 'x-amz-request-id', 'x-amz-version-id'], maxAge: 86400, allowCredentials: false, }, logging: { level: 'info', format: 'text', enabled: true, }, limits: { maxObjectSize: 5 * 1024 * 1024 * 1024, // 5GB maxMetadataSize: 2048, requestTimeout: 300000, // 5 minutes }, }; /** * Merge user config with defaults (deep merge) */ function mergeConfig(userConfig: ISmarts3Config): Required { return { server: { ...DEFAULT_CONFIG.server!, ...(userConfig.server || {}), }, storage: { ...DEFAULT_CONFIG.storage!, ...(userConfig.storage || {}), }, auth: { ...DEFAULT_CONFIG.auth!, ...(userConfig.auth || {}), }, cors: { ...DEFAULT_CONFIG.cors!, ...(userConfig.cors || {}), }, logging: { ...DEFAULT_CONFIG.logging!, ...(userConfig.logging || {}), }, limits: { ...DEFAULT_CONFIG.limits!, ...(userConfig.limits || {}), }, }; } /** * Main Smarts3 class - production-ready S3-compatible server */ export class Smarts3 { // STATIC public static async createAndStart(configArg: ISmarts3Config = {}) { const smartS3Instance = new Smarts3(configArg); await smartS3Instance.start(); return smartS3Instance; } // INSTANCE public config: Required; public s3Instance: Smarts3Server; constructor(configArg: ISmarts3Config = {}) { this.config = mergeConfig(configArg); } public async start() { this.s3Instance = new Smarts3Server({ port: this.config.server.port, address: this.config.server.address, directory: this.config.storage.directory, cleanSlate: this.config.storage.cleanSlate, silent: this.config.server.silent, config: this.config, // Pass full config to server }); await this.s3Instance.start(); if (!this.config.server.silent) { console.log('s3 server is running'); } } public async getS3Descriptor( optionsArg?: Partial, ): Promise { const descriptor = this.s3Instance.getS3Descriptor(); return { ...descriptor, ...(optionsArg ? optionsArg : {}), }; } public async createBucket(bucketNameArg: string) { // Call the filesystem store directly instead of using the client library await this.s3Instance.store.createBucket(bucketNameArg); return { name: bucketNameArg }; } public async stop() { await this.s3Instance.stop(); } } // Export the custom server class for direct use export { Smarts3Server } from './classes/smarts3-server.js';