fix(smarts3): Use filesystem store for bucket creation and remove smartbucket runtime dependency

This commit is contained in:
2025-11-23 22:31:44 +00:00
parent b62cb0bc97
commit 95d78d0d08
7 changed files with 178 additions and 27 deletions

View File

@@ -1,5 +1,13 @@
# Changelog # 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) ## 2025-11-23 - 3.0.3 - fix(filesystem)
Migrate filesystem implementation to @push.rocks/smartfs and add Web Streams handling Migrate filesystem implementation to @push.rocks/smartfs and add Web Streams handling

View File

@@ -19,6 +19,7 @@
"@git.zone/tsbundle": "^2.5.2", "@git.zone/tsbundle": "^2.5.2",
"@git.zone/tsrun": "^2.0.0", "@git.zone/tsrun": "^2.0.0",
"@git.zone/tstest": "^3.1.0", "@git.zone/tstest": "^3.1.0",
"@push.rocks/smartbucket": "^4.3.0",
"@types/node": "^22.9.0" "@types/node": "^22.9.0"
}, },
"browserslist": [ "browserslist": [
@@ -37,7 +38,6 @@
"readme.md" "readme.md"
], ],
"dependencies": { "dependencies": {
"@push.rocks/smartbucket": "^4.3.0",
"@push.rocks/smartfs": "^1.1.0", "@push.rocks/smartfs": "^1.1.0",
"@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartxml": "^2.0.0", "@push.rocks/smartxml": "^2.0.0",

6
pnpm-lock.yaml generated
View File

@@ -8,9 +8,6 @@ importers:
.: .:
dependencies: dependencies:
'@push.rocks/smartbucket':
specifier: ^4.3.0
version: 4.3.0
'@push.rocks/smartfs': '@push.rocks/smartfs':
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0 version: 1.1.0
@@ -39,6 +36,9 @@ importers:
'@git.zone/tstest': '@git.zone/tstest':
specifier: ^3.1.0 specifier: ^3.1.0
version: 3.1.0(socks@2.8.7)(typescript@5.9.3) 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': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.0
version: 22.19.1 version: 22.19.1

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smarts3', 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.' 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.'
} }

View File

@@ -24,7 +24,7 @@ export class Smarts3Server {
private httpServer?: plugins.http.Server; private httpServer?: plugins.http.Server;
private router: S3Router; private router: S3Router;
private middlewares: MiddlewareStack; private middlewares: MiddlewareStack;
private store: FilesystemStore; public store: FilesystemStore; // Made public for direct access from Smarts3 class
private options: Required<ISmarts3ServerOptions>; private options: Required<ISmarts3ServerOptions>;
constructor(options: ISmarts3ServerOptions = {}) { constructor(options: ISmarts3ServerOptions = {}) {

View File

@@ -2,39 +2,185 @@ import * as plugins from './plugins.js';
import * as paths from './paths.js'; import * as paths from './paths.js';
import { Smarts3Server } from './classes/smarts3-server.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; port?: number;
address?: string;
silent?: boolean;
}
/**
* Storage configuration
*/
export interface IStorageConfig {
directory?: string;
cleanSlate?: boolean; 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<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 || {}),
},
};
}
/**
* Main Smarts3 class - production-ready S3-compatible server
*/
export class Smarts3 { export class Smarts3 {
// STATIC // STATIC
public static async createAndStart( public static async createAndStart(configArg: ISmarts3Config = {}) {
optionsArg: ConstructorParameters<typeof Smarts3>[0], const smartS3Instance = new Smarts3(configArg);
) {
const smartS3Instance = new Smarts3(optionsArg);
await smartS3Instance.start(); await smartS3Instance.start();
return smartS3Instance; return smartS3Instance;
} }
// INSTANCE // INSTANCE
public options: ISmarts3ContructorOptions; public config: Required<ISmarts3Config>;
public s3Instance: Smarts3Server; public s3Instance: Smarts3Server;
constructor(optionsArg: ISmarts3ContructorOptions) { constructor(configArg: ISmarts3Config = {}) {
this.options = optionsArg; this.config = mergeConfig(configArg);
} }
public async start() { public async start() {
this.s3Instance = new Smarts3Server({ this.s3Instance = new Smarts3Server({
port: this.options.port || 3000, port: this.config.server.port,
address: '0.0.0.0', address: this.config.server.address,
directory: paths.bucketsDir, directory: this.config.storage.directory,
cleanSlate: this.options.cleanSlate || false, cleanSlate: this.config.storage.cleanSlate,
silent: false, silent: this.config.server.silent,
config: this.config, // Pass full config to server
}); });
await this.s3Instance.start(); await this.s3Instance.start();
console.log('s3 server is running');
if (!this.config.server.silent) {
console.log('s3 server is running');
}
} }
public async getS3Descriptor( public async getS3Descriptor(
@@ -48,11 +194,9 @@ export class Smarts3 {
} }
public async createBucket(bucketNameArg: string) { public async createBucket(bucketNameArg: string) {
const smartbucketInstance = new plugins.smartbucket.SmartBucket( // Call the filesystem store directly instead of using the client library
await this.getS3Descriptor(), await this.s3Instance.store.createBucket(bucketNameArg);
); return { name: bucketNameArg };
const bucket = await smartbucketInstance.createBucket(bucketNameArg);
return bucket;
} }
public async stop() { public async stop() {

View File

@@ -7,7 +7,6 @@ import * as url from 'url';
export { path, http, crypto, url }; export { path, http, crypto, url };
// @push.rocks scope // @push.rocks scope
import * as smartbucket from '@push.rocks/smartbucket';
import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs'; import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs';
import * as smartpath from '@push.rocks/smartpath'; import * as smartpath from '@push.rocks/smartpath';
import { SmartXml } from '@push.rocks/smartxml'; import { SmartXml } from '@push.rocks/smartxml';
@@ -15,7 +14,7 @@ import { SmartXml } from '@push.rocks/smartxml';
// Create SmartFs instance with Node.js provider // Create SmartFs instance with Node.js provider
export const smartfs = new SmartFs(new SmartFsProviderNode()); export const smartfs = new SmartFs(new SmartFsProviderNode());
export { smartbucket, smartpath, SmartXml }; export { smartpath, SmartXml };
// @tsclass scope // @tsclass scope
import * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';