2024-10-26 14:14:41 +02:00
|
|
|
import * as plugins from './plugins.js';
|
2022-04-14 10:36:24 +02:00
|
|
|
import * as paths from './paths.js';
|
2025-11-21 14:32:19 +00:00
|
|
|
import { Smarts3Server } from './classes/smarts3-server.js';
|
2021-12-18 01:41:50 +01:00
|
|
|
|
2025-11-23 22:31:44 +00:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-23 23:31:26 +00:00
|
|
|
/**
|
|
|
|
|
* Multipart upload configuration
|
|
|
|
|
*/
|
|
|
|
|
export interface IMultipartConfig {
|
|
|
|
|
expirationDays?: number;
|
|
|
|
|
cleanupIntervalMinutes?: number;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-23 22:31:44 +00:00
|
|
|
/**
|
|
|
|
|
* Server configuration
|
|
|
|
|
*/
|
|
|
|
|
export interface IServerConfig {
|
2021-12-18 01:41:50 +01:00
|
|
|
port?: number;
|
2025-11-23 22:31:44 +00:00
|
|
|
address?: string;
|
|
|
|
|
silent?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Storage configuration
|
|
|
|
|
*/
|
|
|
|
|
export interface IStorageConfig {
|
|
|
|
|
directory?: string;
|
2021-12-18 01:41:50 +01:00
|
|
|
cleanSlate?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-23 22:31:44 +00:00
|
|
|
/**
|
|
|
|
|
* Complete smarts3 configuration
|
|
|
|
|
*/
|
|
|
|
|
export interface ISmarts3Config {
|
|
|
|
|
server?: IServerConfig;
|
|
|
|
|
storage?: IStorageConfig;
|
|
|
|
|
auth?: IAuthConfig;
|
|
|
|
|
cors?: ICorsConfig;
|
|
|
|
|
logging?: ILoggingConfig;
|
|
|
|
|
limits?: ILimitsConfig;
|
2025-11-23 23:31:26 +00:00
|
|
|
multipart?: IMultipartConfig;
|
2025-11-23 22:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
},
|
2025-11-23 23:31:26 +00:00
|
|
|
multipart: {
|
|
|
|
|
expirationDays: 7,
|
|
|
|
|
cleanupIntervalMinutes: 60,
|
|
|
|
|
},
|
2025-11-23 22:31:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Merge user config with defaults (deep merge)
|
|
|
|
|
*/
|
|
|
|
|
function mergeConfig(userConfig: ISmarts3Config): Required<ISmarts3Config> {
|
|
|
|
|
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 || {}),
|
|
|
|
|
},
|
2025-11-23 23:31:26 +00:00
|
|
|
multipart: {
|
|
|
|
|
...DEFAULT_CONFIG.multipart!,
|
|
|
|
|
...(userConfig.multipart || {}),
|
|
|
|
|
},
|
2025-11-23 22:31:44 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Main Smarts3 class - production-ready S3-compatible server
|
|
|
|
|
*/
|
2021-12-18 01:41:50 +01:00
|
|
|
export class Smarts3 {
|
2021-12-20 17:06:42 +01:00
|
|
|
// STATIC
|
2025-11-23 22:42:47 +00:00
|
|
|
public static async createAndStart(configArg: ISmarts3Config = {}) {
|
2025-11-23 22:31:44 +00:00
|
|
|
const smartS3Instance = new Smarts3(configArg);
|
2021-12-20 17:06:42 +01:00
|
|
|
await smartS3Instance.start();
|
|
|
|
|
return smartS3Instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// INSTANCE
|
2025-11-23 22:31:44 +00:00
|
|
|
public config: Required<ISmarts3Config>;
|
2025-11-21 14:36:30 +00:00
|
|
|
public s3Instance: Smarts3Server;
|
2021-12-18 01:41:50 +01:00
|
|
|
|
2025-11-23 22:42:47 +00:00
|
|
|
constructor(configArg: ISmarts3Config = {}) {
|
2025-11-23 22:31:44 +00:00
|
|
|
this.config = mergeConfig(configArg);
|
2021-12-18 01:41:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async start() {
|
2025-11-21 14:36:30 +00:00
|
|
|
this.s3Instance = new Smarts3Server({
|
2025-11-23 22:31:44 +00:00
|
|
|
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
|
2025-11-21 14:36:30 +00:00
|
|
|
});
|
|
|
|
|
await this.s3Instance.start();
|
2025-11-23 22:31:44 +00:00
|
|
|
|
|
|
|
|
if (!this.config.server.silent) {
|
|
|
|
|
console.log('s3 server is running');
|
|
|
|
|
}
|
2021-12-18 01:41:50 +01:00
|
|
|
}
|
|
|
|
|
|
2025-08-16 16:22:15 +00:00
|
|
|
public async getS3Descriptor(
|
2025-11-20 08:10:17 +00:00
|
|
|
optionsArg?: Partial<plugins.tsclass.storage.IS3Descriptor>,
|
2025-08-16 16:22:15 +00:00
|
|
|
): Promise<plugins.tsclass.storage.IS3Descriptor> {
|
2025-11-21 14:36:30 +00:00
|
|
|
const descriptor = this.s3Instance.getS3Descriptor();
|
2021-12-20 16:33:13 +01:00
|
|
|
return {
|
2025-11-21 14:36:30 +00:00
|
|
|
...descriptor,
|
2025-11-20 08:10:17 +00:00
|
|
|
...(optionsArg ? optionsArg : {}),
|
2022-04-14 10:38:14 +02:00
|
|
|
};
|
2021-12-20 16:33:13 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-20 19:36:54 +01:00
|
|
|
public async createBucket(bucketNameArg: string) {
|
2025-11-23 22:31:44 +00:00
|
|
|
// Call the filesystem store directly instead of using the client library
|
|
|
|
|
await this.s3Instance.store.createBucket(bucketNameArg);
|
|
|
|
|
return { name: bucketNameArg };
|
2021-12-20 19:36:54 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-18 01:41:50 +01:00
|
|
|
public async stop() {
|
2025-11-21 14:36:30 +00:00
|
|
|
await this.s3Instance.stop();
|
2021-12-18 01:41:50 +01:00
|
|
|
}
|
2022-04-14 10:38:14 +02:00
|
|
|
}
|
2025-11-21 14:32:19 +00:00
|
|
|
|
|
|
|
|
// Export the custom server class for direct use
|
|
|
|
|
export { Smarts3Server } from './classes/smarts3-server.js';
|