From 95d78d0d0830c35ed7c4de64301ce42a0971e5f1 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Sun, 23 Nov 2025 22:31:44 +0000 Subject: [PATCH] fix(smarts3): Use filesystem store for bucket creation and remove smartbucket runtime dependency --- changelog.md | 8 ++ package.json | 2 +- pnpm-lock.yaml | 6 +- ts/00_commitinfo_data.ts | 2 +- ts/classes/smarts3-server.ts | 2 +- ts/index.ts | 182 +++++++++++++++++++++++++++++++---- ts/plugins.ts | 3 +- 7 files changed, 178 insertions(+), 27 deletions(-) diff --git a/changelog.md b/changelog.md index d9cc45f..0a5a19b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2025-11-23 - 3.0.4 - fix(smarts3) +Use filesystem store for bucket creation and remove smartbucket runtime dependency + +- Switched createBucket to call the internal FilesystemStore.createBucket instead of using @push.rocks/smartbucket +- Made Smarts3Server.store public so Smarts3 can access the filesystem store directly +- Removed runtime import/export of @push.rocks/smartbucket from plugins and moved @push.rocks/smartbucket to devDependencies in package.json +- Updated createBucket to return a simple { name } object after creating the bucket via the filesystem store + ## 2025-11-23 - 3.0.3 - fix(filesystem) Migrate filesystem implementation to @push.rocks/smartfs and add Web Streams handling diff --git a/package.json b/package.json index 6d138b8..00f83df 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@git.zone/tsbundle": "^2.5.2", "@git.zone/tsrun": "^2.0.0", "@git.zone/tstest": "^3.1.0", + "@push.rocks/smartbucket": "^4.3.0", "@types/node": "^22.9.0" }, "browserslist": [ @@ -37,7 +38,6 @@ "readme.md" ], "dependencies": { - "@push.rocks/smartbucket": "^4.3.0", "@push.rocks/smartfs": "^1.1.0", "@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartxml": "^2.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be3f402..3f69a2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - '@push.rocks/smartbucket': - specifier: ^4.3.0 - version: 4.3.0 '@push.rocks/smartfs': specifier: ^1.1.0 version: 1.1.0 @@ -39,6 +36,9 @@ importers: '@git.zone/tstest': specifier: ^3.1.0 version: 3.1.0(socks@2.8.7)(typescript@5.9.3) + '@push.rocks/smartbucket': + specifier: ^4.3.0 + version: 4.3.0 '@types/node': specifier: ^22.9.0 version: 22.19.1 diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index e376941..ef50220 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smarts3', - version: '3.0.3', + version: '3.0.4', description: 'A Node.js TypeScript package to create a local S3 endpoint for simulating AWS S3 operations using mapped local directories for development and testing purposes.' } diff --git a/ts/classes/smarts3-server.ts b/ts/classes/smarts3-server.ts index ef4c2fb..17c368c 100644 --- a/ts/classes/smarts3-server.ts +++ b/ts/classes/smarts3-server.ts @@ -24,7 +24,7 @@ export class Smarts3Server { private httpServer?: plugins.http.Server; private router: S3Router; private middlewares: MiddlewareStack; - private store: FilesystemStore; + public store: FilesystemStore; // Made public for direct access from Smarts3 class private options: Required; constructor(options: ISmarts3ServerOptions = {}) { diff --git a/ts/index.ts b/ts/index.ts index 3377756..f223184 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -2,39 +2,185 @@ import * as plugins from './plugins.js'; import * as paths from './paths.js'; import { Smarts3Server } from './classes/smarts3-server.js'; -export interface ISmarts3ContructorOptions { +/** + * 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( - optionsArg: ConstructorParameters[0], - ) { - const smartS3Instance = new Smarts3(optionsArg); + public static async createAndStart(configArg: ISmarts3Config = {}) { + const smartS3Instance = new Smarts3(configArg); await smartS3Instance.start(); return smartS3Instance; } // INSTANCE - public options: ISmarts3ContructorOptions; + public config: Required; public s3Instance: Smarts3Server; - constructor(optionsArg: ISmarts3ContructorOptions) { - this.options = optionsArg; + constructor(configArg: ISmarts3Config = {}) { + this.config = mergeConfig(configArg); } public async start() { this.s3Instance = new Smarts3Server({ - port: this.options.port || 3000, - address: '0.0.0.0', - directory: paths.bucketsDir, - cleanSlate: this.options.cleanSlate || false, - silent: false, + 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(); - console.log('s3 server is running'); + + if (!this.config.server.silent) { + console.log('s3 server is running'); + } } public async getS3Descriptor( @@ -48,11 +194,9 @@ export class Smarts3 { } public async createBucket(bucketNameArg: string) { - const smartbucketInstance = new plugins.smartbucket.SmartBucket( - await this.getS3Descriptor(), - ); - const bucket = await smartbucketInstance.createBucket(bucketNameArg); - return bucket; + // Call the filesystem store directly instead of using the client library + await this.s3Instance.store.createBucket(bucketNameArg); + return { name: bucketNameArg }; } public async stop() { diff --git a/ts/plugins.ts b/ts/plugins.ts index 63af4e7..a793054 100644 --- a/ts/plugins.ts +++ b/ts/plugins.ts @@ -7,7 +7,6 @@ import * as url from 'url'; export { path, http, crypto, url }; // @push.rocks scope -import * as smartbucket from '@push.rocks/smartbucket'; import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs'; import * as smartpath from '@push.rocks/smartpath'; import { SmartXml } from '@push.rocks/smartxml'; @@ -15,7 +14,7 @@ import { SmartXml } from '@push.rocks/smartxml'; // Create SmartFs instance with Node.js provider export const smartfs = new SmartFs(new SmartFsProviderNode()); -export { smartbucket, smartpath, SmartXml }; +export { smartpath, SmartXml }; // @tsclass scope import * as tsclass from '@tsclass/tsclass';