@kumix/storage 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/s3.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"s3.js","names":[],"sources":["../src/operations/file-operations.ts","../src/operations/folder-operations.ts","../src/providers/s3.ts","../src/services/s3.ts","../src/s3.ts"],"sourcesContent":["/**\n * S3 file operations implementation\n * Provides comprehensive file management operations for S3-compatible storage providers\n */\n\nimport {\n CopyObjectCommand,\n DeleteObjectCommand,\n DeleteObjectsCommand,\n GetObjectCommand,\n HeadObjectCommand,\n ListObjectsV2Command,\n PutObjectCommand,\n type S3Client,\n} from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nimport { buildPublicUrl, getMimeType } from \"../helpers\";\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CopyOptions,\n CopyResult,\n DeleteOptions,\n DeleteResult,\n DownloadOptions,\n DownloadResult,\n DuplicateOptions,\n DuplicateResult,\n ExistsResult,\n FileInfo,\n ListOptions,\n ListResult,\n MoveOptions,\n MoveResult,\n PresignedUrlOptions,\n PresignedUrlResult,\n S3Config,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * S3 file operations implementation\n * Handles all file-related operations for S3-compatible storage providers\n * @internal\n */\nexport class FileOperations {\n constructor(\n private client: S3Client,\n private config: S3Config,\n ) {}\n\n async upload(options: UploadOptions): Promise<UploadResult> {\n try {\n const contentType = options.contentType || getMimeType(options.key);\n\n const command = new PutObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n Body: options.file,\n ContentType: contentType,\n Metadata: options.metadata,\n CacheControl: options.cacheControl,\n ContentDisposition: options.contentDisposition,\n ACL: options.acl,\n Expires: options.expires,\n });\n\n const result = await this.client.send(command);\n\n const publicUrl = this.getPublicUrl(options.key);\n\n return {\n success: true,\n key: options.key,\n url: publicUrl,\n publicUrl,\n etag: result.ETag?.replace(/\"/g, \"\"),\n size:\n typeof options.file === \"string\"\n ? Buffer.byteLength(options.file, \"utf8\")\n : options.file.length,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Upload failed\",\n };\n }\n }\n\n async download(options: DownloadOptions): Promise<DownloadResult> {\n try {\n const command = new GetObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n Range: options.range,\n });\n\n const result = await this.client.send(command);\n\n if (!result.Body) {\n return {\n success: false,\n error: \"No data received\",\n };\n }\n\n // Convert stream to buffer\n const chunks: Uint8Array[] = [];\n const reader = result.Body.transformToWebStream().getReader();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n\n const data = Buffer.concat(chunks);\n\n return {\n success: true,\n content: data, // Main content field\n data, // Alias for backward compatibility\n contentType: result.ContentType,\n contentLength: result.ContentLength,\n lastModified: result.LastModified,\n etag: result.ETag?.replace(/\"/g, \"\"),\n metadata: result.Metadata,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Download failed\",\n };\n }\n }\n\n async delete(options: DeleteOptions): Promise<DeleteResult> {\n try {\n const command = new DeleteObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n });\n\n await this.client.send(command);\n\n return {\n success: true,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Delete failed\",\n };\n }\n }\n\n async batchDelete(options: BatchDeleteOptions): Promise<BatchDeleteResult> {\n try {\n const command = new DeleteObjectsCommand({\n Bucket: this.config.bucket,\n Delete: {\n Objects: options.keys.map((key) => ({ Key: key })),\n Quiet: false,\n },\n });\n\n const result = await this.client.send(command);\n\n const deleted = result.Deleted?.map((obj) => obj.Key).filter(Boolean) as string[];\n const errors =\n result.Errors?.map((err) => ({\n key: err.Key || \"\",\n error: err.Message || \"Unknown error\",\n })) || [];\n\n return {\n success: true,\n deleted,\n errors: errors.length > 0 ? errors : undefined,\n };\n } catch (error) {\n return {\n success: false,\n errors: options.keys.map((key) => ({\n key,\n error: error instanceof Error ? error.message : \"Batch delete failed\",\n })),\n };\n }\n }\n\n async list(options: ListOptions = {}): Promise<ListResult> {\n try {\n const command = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: options.prefix,\n Delimiter: options.delimiter,\n MaxKeys: options.maxKeys,\n ContinuationToken: options.continuationToken,\n });\n\n const result = await this.client.send(command);\n\n const files: FileInfo[] =\n result.Contents?.map((obj) => ({\n key: obj.Key!,\n size: obj.Size || 0,\n lastModified: obj.LastModified || new Date(),\n etag: obj.ETag?.replace(/\"/g, \"\") || \"\",\n contentType: getMimeType(obj.Key!),\n })) || [];\n\n return {\n success: true,\n files,\n isTruncated: result.IsTruncated,\n nextContinuationToken: result.NextContinuationToken,\n commonPrefixes: result.CommonPrefixes?.map((cp) => cp.Prefix!),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"List failed\",\n };\n }\n }\n\n async exists(key: string): Promise<ExistsResult> {\n try {\n const command = new HeadObjectCommand({\n Bucket: this.config.bucket,\n Key: key,\n });\n\n const result = await this.client.send(command);\n\n return {\n exists: true,\n fileInfo: {\n key,\n size: result.ContentLength || 0,\n lastModified: result.LastModified || new Date(),\n etag: result.ETag?.replace(/\"/g, \"\") || \"\",\n contentType: result.ContentType,\n metadata: result.Metadata,\n },\n };\n } catch (error) {\n if (error instanceof Error && error.name === \"NotFound\") {\n return { exists: false };\n }\n\n return {\n exists: false,\n error: error instanceof Error ? error.message : \"Check existence failed\",\n };\n }\n }\n\n async copy(options: CopyOptions): Promise<CopyResult> {\n try {\n const command = new CopyObjectCommand({\n Bucket: this.config.bucket,\n CopySource: `${this.config.bucket}/${options.sourceKey}`,\n Key: options.destinationKey,\n Metadata: options.metadata,\n MetadataDirective: options.metadataDirective || \"COPY\",\n });\n\n const result = await this.client.send(command);\n\n return {\n success: true,\n etag: result.CopyObjectResult?.ETag?.replace(/\"/g, \"\"),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Copy failed\",\n };\n }\n }\n\n async move(options: MoveOptions): Promise<MoveResult> {\n try {\n // First copy the object\n const copyResult = await this.copy({\n sourceKey: options.sourceKey,\n destinationKey: options.destinationKey,\n metadata: options.metadata,\n metadataDirective: options.metadataDirective,\n });\n\n if (!copyResult.success) {\n return {\n success: false,\n error: copyResult.error || \"Move failed during copy operation\",\n };\n }\n\n // Then delete the source object\n const deleteResult = await this.delete({ key: options.sourceKey });\n\n if (!deleteResult.success) {\n return {\n success: false,\n error: deleteResult.error || \"Move failed during delete operation\",\n };\n }\n\n return {\n success: true,\n etag: copyResult.etag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Move failed\",\n };\n }\n }\n\n async duplicate(options: DuplicateOptions): Promise<DuplicateResult> {\n // Duplicate is just an alias for copy\n return this.copy(options);\n }\n\n async getPresignedUrl(options: PresignedUrlOptions): Promise<PresignedUrlResult> {\n try {\n const expiresIn = options.expiresIn || 3600; // 1 hour default\n\n let command: GetObjectCommand | PutObjectCommand;\n if (options.operation === \"get\") {\n command = new GetObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n });\n } else {\n command = new PutObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n ContentType: options.contentType,\n });\n }\n\n const url = await getSignedUrl(this.client, command, {\n expiresIn,\n });\n\n return {\n success: true,\n url,\n expiresAt: new Date(Date.now() + expiresIn * 1000),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Presigned URL generation failed\",\n };\n }\n }\n\n getPublicUrl(key: string): string {\n const isCloudflare = this.config.provider === \"cloudflare-r2\";\n const isSupabase = this.config.provider === \"supabase\";\n\n if (this.config.publicUrl) {\n return buildPublicUrl(\n this.config.publicUrl,\n isCloudflare ? \"\" : this.config.bucket,\n key,\n isSupabase,\n );\n }\n\n if (this.config.endpoint) {\n return buildPublicUrl(this.config.endpoint, this.config.bucket, key, isSupabase);\n }\n\n // Default AWS S3 URL format\n return `https://${this.config.bucket}.s3.${this.config.region}.amazonaws.com/${key}`;\n }\n}\n","/**\n * S3 folder operations implementation\n * Provides comprehensive folder management operations for S3-compatible storage providers\n */\n\nimport {\n CopyObjectCommand,\n DeleteObjectsCommand,\n ListObjectsV2Command,\n PutObjectCommand,\n type S3Client,\n} from \"@aws-sdk/client-s3\";\n\nimport { getMimeType } from \"../helpers\";\nimport type {\n CopyFolderOptions,\n CopyFolderResult,\n CreateFolderOptions,\n CreateFolderResult,\n DeleteFolderOptions,\n DeleteFolderResult,\n FileInfo,\n FolderExistsResult,\n FolderInfo,\n ListFoldersOptions,\n ListFoldersResult,\n RenameFolderOptions,\n RenameFolderResult,\n S3Config,\n} from \"../types\";\n\n/**\n * S3 folder operations implementation\n * Handles all folder-related operations for S3-compatible storage providers\n * @internal\n */\nexport class FolderOperations {\n constructor(\n private client: S3Client,\n private config: S3Config,\n ) {}\n\n async createFolder(options: CreateFolderOptions): Promise<CreateFolderResult> {\n try {\n // Ensure path ends with /\n const folderPath = options.path.endsWith(\"/\") ? options.path : `${options.path}/`;\n\n // Create a placeholder object to represent the folder\n const command = new PutObjectCommand({\n Bucket: this.config.bucket,\n Key: folderPath,\n Body: \"\",\n ContentType: \"application/x-directory\",\n });\n\n await this.client.send(command);\n\n return {\n success: true,\n path: folderPath,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Create folder failed\",\n };\n }\n }\n\n async deleteFolder(options: DeleteFolderOptions): Promise<DeleteFolderResult> {\n try {\n // Ensure path ends with /\n const folderPath = options.path.endsWith(\"/\") ? options.path : `${options.path}/`;\n\n if (options.recursive) {\n // List all objects with the folder prefix\n const listCommand = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: folderPath,\n });\n\n const listResult = await this.client.send(listCommand);\n\n if (!listResult.Contents || listResult.Contents.length === 0) {\n return {\n success: true,\n deletedFiles: [],\n };\n }\n\n // Delete all objects in the folder\n const deleteCommand = new DeleteObjectsCommand({\n Bucket: this.config.bucket,\n Delete: {\n Objects: listResult.Contents.map((obj) => ({ Key: obj.Key! })),\n Quiet: false,\n },\n });\n\n const deleteResult = await this.client.send(deleteCommand);\n\n const deletedFiles = deleteResult.Deleted?.map((obj) => obj.Key!).filter(Boolean) || [];\n\n return {\n success: true,\n deletedFiles,\n };\n } else {\n // Just delete the folder placeholder\n const deleteCommand = new DeleteObjectsCommand({\n Bucket: this.config.bucket,\n Delete: {\n Objects: [{ Key: folderPath }],\n Quiet: false,\n },\n });\n\n await this.client.send(deleteCommand);\n\n return {\n success: true,\n deletedFiles: [folderPath],\n };\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Delete folder failed\",\n };\n }\n }\n\n async listFolders(options: ListFoldersOptions = {}): Promise<ListFoldersResult> {\n try {\n const command = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: options.prefix,\n Delimiter: options.delimiter || \"/\",\n MaxKeys: options.maxKeys,\n ContinuationToken: options.continuationToken,\n });\n\n const result = await this.client.send(command);\n\n // Parse folders from common prefixes\n const folders: FolderInfo[] =\n result.CommonPrefixes?.map((cp) => {\n const path = cp.Prefix!;\n const name = path.split(\"/\").filter(Boolean).pop() || \"\";\n\n return {\n name,\n path,\n size: 0, // Will be calculated separately if needed\n fileCount: 0, // Will be calculated separately if needed\n lastModified: new Date(),\n };\n }) || [];\n\n // Parse files from contents\n const files: FileInfo[] =\n result.Contents?.map((obj) => ({\n key: obj.Key!,\n size: obj.Size || 0,\n lastModified: obj.LastModified || new Date(),\n etag: obj.ETag?.replace(/\"/g, \"\") || \"\",\n contentType: getMimeType(obj.Key!),\n })) || [];\n\n return {\n success: true,\n folders,\n files,\n isTruncated: result.IsTruncated,\n nextContinuationToken: result.NextContinuationToken,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"List folders failed\",\n };\n }\n }\n\n async folderExists(path: string): Promise<FolderExistsResult> {\n try {\n // Ensure path ends with /\n const folderPath = path.endsWith(\"/\") ? path : `${path}/`;\n\n const command = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: folderPath,\n MaxKeys: 1,\n });\n\n const result = await this.client.send(command);\n\n const exists =\n (result.Contents && result.Contents.length > 0) ||\n (result.CommonPrefixes && result.CommonPrefixes.length > 0);\n\n if (exists) {\n const name = folderPath.split(\"/\").filter(Boolean).pop() || \"\";\n\n return {\n exists: true,\n folderInfo: {\n name,\n path: folderPath,\n size: 0,\n fileCount: 0,\n lastModified: new Date(),\n },\n };\n }\n\n return { exists: false };\n } catch (error) {\n return {\n exists: false,\n error: error instanceof Error ? error.message : \"Check folder existence failed\",\n };\n }\n }\n\n async renameFolder(options: RenameFolderOptions): Promise<RenameFolderResult> {\n try {\n // This is essentially a copy + delete operation for all files in the folder\n const oldPath = options.oldPath.endsWith(\"/\") ? options.oldPath : `${options.oldPath}/`;\n const newPath = options.newPath.endsWith(\"/\") ? options.newPath : `${options.newPath}/`;\n\n // List all objects in the old folder\n const listCommand = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: oldPath,\n });\n\n const listResult = await this.client.send(listCommand);\n\n if (!listResult.Contents || listResult.Contents.length === 0) {\n return {\n success: true,\n movedFiles: [],\n };\n }\n\n const movedFiles: string[] = [];\n\n // Copy each file to new location and delete old one\n for (const obj of listResult.Contents) {\n const oldKey = obj.Key!;\n const newKey = oldKey.replace(oldPath, newPath);\n\n // Copy object using CopyObjectCommand\n const copyCommand = new CopyObjectCommand({\n Bucket: this.config.bucket,\n Key: newKey,\n CopySource: `${this.config.bucket}/${oldKey}`,\n });\n\n await this.client.send(copyCommand);\n movedFiles.push(newKey);\n }\n\n // Delete old folder contents\n const deleteCommand = new DeleteObjectsCommand({\n Bucket: this.config.bucket,\n Delete: {\n Objects: listResult.Contents.map((obj) => ({ Key: obj.Key! })),\n Quiet: true,\n },\n });\n\n await this.client.send(deleteCommand);\n\n return {\n success: true,\n movedFiles,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Rename folder failed\",\n };\n }\n }\n\n async copyFolder(options: CopyFolderOptions): Promise<CopyFolderResult> {\n try {\n const sourcePath = options.sourcePath.endsWith(\"/\")\n ? options.sourcePath\n : `${options.sourcePath}/`;\n const destPath = options.destinationPath.endsWith(\"/\")\n ? options.destinationPath\n : `${options.destinationPath}/`;\n\n // List all objects in the source folder\n const listCommand = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: sourcePath,\n });\n\n const listResult = await this.client.send(listCommand);\n\n if (!listResult.Contents || listResult.Contents.length === 0) {\n return {\n success: true,\n copiedFiles: [],\n };\n }\n\n const copiedFiles: string[] = [];\n\n // Copy each file to new location\n for (const obj of listResult.Contents) {\n const sourceKey = obj.Key!;\n const destKey = sourceKey.replace(sourcePath, destPath);\n\n // Copy object using CopyObjectCommand\n const copyCommand = new CopyObjectCommand({\n Bucket: this.config.bucket,\n Key: destKey,\n CopySource: `${this.config.bucket}/${sourceKey}`,\n });\n\n await this.client.send(copyCommand);\n copiedFiles.push(destKey);\n }\n\n return {\n success: true,\n copiedFiles,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Copy folder failed\",\n };\n }\n }\n}\n","/**\n * S3-compatible storage provider implementation\n * Provides cloud storage operations using AWS S3 SDK for S3-compatible services\n */\n\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nimport { FileOperations } from \"../operations/file-operations\";\nimport { FolderOperations } from \"../operations/folder-operations\";\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CopyFolderOptions,\n CopyFolderResult,\n CopyOptions,\n CopyResult,\n CreateFolderOptions,\n CreateFolderResult,\n DeleteFolderOptions,\n DeleteFolderResult,\n DeleteOptions,\n DeleteResult,\n DownloadOptions,\n DownloadResult,\n DuplicateOptions,\n DuplicateResult,\n ExistsResult,\n FolderExistsResult,\n ListFoldersOptions,\n ListFoldersResult,\n ListOptions,\n ListResult,\n MoveOptions,\n MoveResult,\n PresignedUrlOptions,\n PresignedUrlResult,\n RenameFolderOptions,\n RenameFolderResult,\n S3Config,\n StorageInterface,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * S3-compatible storage provider\n * Implements StorageInterface for AWS S3 and S3-compatible services\n * @internal\n */\nexport class S3Provider implements StorageInterface {\n private client: S3Client;\n private config: S3Config;\n private fileOps: FileOperations;\n private folderOps: FolderOperations;\n\n constructor(config: S3Config) {\n this.config = config;\n\n this.client = new S3Client({\n region: config.region,\n credentials: {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n },\n endpoint: config.endpoint,\n forcePathStyle: config.forcePathStyle || false,\n });\n\n this.fileOps = new FileOperations(this.client, this.config);\n this.folderOps = new FolderOperations(this.client, this.config);\n }\n\n // File operations\n async upload(options: UploadOptions): Promise<UploadResult> {\n return this.fileOps.upload(options);\n }\n\n async download(options: DownloadOptions): Promise<DownloadResult> {\n return this.fileOps.download(options);\n }\n\n async delete(options: DeleteOptions): Promise<DeleteResult> {\n return this.fileOps.delete(options);\n }\n\n async batchDelete(options: BatchDeleteOptions): Promise<BatchDeleteResult> {\n return this.fileOps.batchDelete(options);\n }\n\n async list(options?: ListOptions): Promise<ListResult> {\n return this.fileOps.list(options);\n }\n\n async exists(key: string): Promise<ExistsResult> {\n return this.fileOps.exists(key);\n }\n\n async copy(options: CopyOptions): Promise<CopyResult> {\n return this.fileOps.copy(options);\n }\n\n async move(options: MoveOptions): Promise<MoveResult> {\n return this.fileOps.move(options);\n }\n\n async duplicate(options: DuplicateOptions): Promise<DuplicateResult> {\n return this.fileOps.duplicate(options);\n }\n\n async getPresignedUrl(options: PresignedUrlOptions): Promise<PresignedUrlResult> {\n return this.fileOps.getPresignedUrl(options);\n }\n\n getPublicUrl(key: string): string {\n return this.fileOps.getPublicUrl(key);\n }\n\n // Folder operations\n async createFolder(options: CreateFolderOptions): Promise<CreateFolderResult> {\n return this.folderOps.createFolder(options);\n }\n\n async deleteFolder(options: DeleteFolderOptions): Promise<DeleteFolderResult> {\n return this.folderOps.deleteFolder(options);\n }\n\n async listFolders(options?: ListFoldersOptions): Promise<ListFoldersResult> {\n return this.folderOps.listFolders(options);\n }\n\n async folderExists(path: string): Promise<FolderExistsResult> {\n return this.folderOps.folderExists(path);\n }\n\n async renameFolder(options: RenameFolderOptions): Promise<RenameFolderResult> {\n return this.folderOps.renameFolder(options);\n }\n\n async copyFolder(options: CopyFolderOptions): Promise<CopyFolderResult> {\n return this.folderOps.copyFolder(options);\n }\n}\n","/**\n * S3 storage service implementation\n * High-level service wrapper for S3-compatible storage operations with convenience methods\n */\n\nimport { loadS3Config } from \"../config\";\nimport { S3Provider } from \"../providers/s3\";\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CopyFolderOptions,\n CopyFolderResult,\n CopyOptions,\n CopyResult,\n CreateFolderOptions,\n CreateFolderResult,\n DeleteFolderOptions,\n DeleteFolderResult,\n DeleteOptions,\n DeleteResult,\n DownloadOptions,\n DownloadResult,\n DuplicateOptions,\n DuplicateResult,\n ExistsResult,\n FolderExistsResult,\n ListFoldersOptions,\n ListFoldersResult,\n ListOptions,\n ListResult,\n MoveOptions,\n MoveResult,\n PresignedUrlOptions,\n PresignedUrlResult,\n RenameFolderOptions,\n RenameFolderResult,\n S3Config,\n StorageInterface,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * S3 storage service\n * High-level service for S3-compatible storage operations with convenience methods\n * @public\n */\nexport class S3Service implements StorageInterface {\n private provider: S3Provider;\n private config: S3Config;\n\n constructor();\n constructor(config: S3Config);\n constructor(config?: S3Config) {\n this.config = config || loadS3Config();\n this.provider = this.createProvider(this.config);\n }\n\n private createProvider(config: S3Config): S3Provider {\n switch (config.provider) {\n case \"aws\":\n case \"cloudflare-r2\":\n case \"minio\":\n case \"digitalocean\":\n case \"supabase\":\n case \"custom\":\n return new S3Provider(config);\n default:\n throw new Error(`Unsupported S3 provider: ${config.provider}`);\n }\n }\n\n // Utility methods\n getConfig(): S3Config {\n return { ...this.config };\n }\n\n getBucket(): string {\n return this.config.bucket;\n }\n\n getRegion(): string {\n return this.config.region;\n }\n\n getProvider(): string {\n return this.config.provider;\n }\n\n getPublicUrl(key: string): string {\n return this.provider.getPublicUrl(key);\n }\n\n // File operations\n async upload(options: UploadOptions): Promise<UploadResult> {\n return this.provider.upload(options);\n }\n\n async download(options: DownloadOptions): Promise<DownloadResult> {\n return this.provider.download(options);\n }\n\n async delete(options: DeleteOptions): Promise<DeleteResult> {\n return this.provider.delete(options);\n }\n\n async batchDelete(options: BatchDeleteOptions): Promise<BatchDeleteResult> {\n return this.provider.batchDelete(options);\n }\n\n async list(options?: ListOptions): Promise<ListResult> {\n return this.provider.list(options);\n }\n\n async exists(key: string): Promise<ExistsResult> {\n return this.provider.exists(key);\n }\n\n async copy(options: CopyOptions): Promise<CopyResult> {\n return this.provider.copy(options);\n }\n\n async move(options: MoveOptions): Promise<MoveResult> {\n return this.provider.move(options);\n }\n\n async duplicate(options: DuplicateOptions): Promise<DuplicateResult> {\n return this.provider.duplicate(options);\n }\n\n async getPresignedUrl(options: PresignedUrlOptions): Promise<PresignedUrlResult> {\n return this.provider.getPresignedUrl(options);\n }\n\n // Folder operations\n async createFolder(options: CreateFolderOptions): Promise<CreateFolderResult> {\n return this.provider.createFolder(options);\n }\n\n async deleteFolder(options: DeleteFolderOptions): Promise<DeleteFolderResult> {\n return this.provider.deleteFolder(options);\n }\n\n async listFolders(options?: ListFoldersOptions): Promise<ListFoldersResult> {\n return this.provider.listFolders(options);\n }\n\n async folderExists(path: string): Promise<FolderExistsResult> {\n return this.provider.folderExists(path);\n }\n\n async renameFolder(options: RenameFolderOptions): Promise<RenameFolderResult> {\n return this.provider.renameFolder(options);\n }\n\n async copyFolder(options: CopyFolderOptions): Promise<CopyFolderResult> {\n return this.provider.copyFolder(options);\n }\n\n // Convenience methods\n async uploadFile(\n key: string,\n file: Buffer | Uint8Array | string,\n options?: Partial<UploadOptions>,\n ): Promise<UploadResult> {\n return this.upload({\n key,\n file,\n ...options,\n });\n }\n\n async downloadFile(key: string): Promise<DownloadResult> {\n return this.download({ key });\n }\n\n async deleteFile(key: string): Promise<DeleteResult> {\n return this.delete({ key });\n }\n\n async deleteFiles(keys: string[]): Promise<BatchDeleteResult> {\n return this.batchDelete({ keys });\n }\n\n async listFiles(prefix?: string, maxKeys?: number): Promise<ListResult> {\n return this.list({ prefix, maxKeys });\n }\n\n async fileExists(key: string): Promise<boolean> {\n const result = await this.exists(key);\n return result.exists;\n }\n\n async copyFile(\n sourceKey: string,\n destinationKey: string,\n options?: Partial<CopyOptions>,\n ): Promise<CopyResult> {\n return this.copy({\n sourceKey,\n destinationKey,\n ...options,\n });\n }\n\n async moveFile(\n sourceKey: string,\n destinationKey: string,\n options?: Partial<MoveOptions>,\n ): Promise<MoveResult> {\n return this.move({\n sourceKey,\n destinationKey,\n ...options,\n });\n }\n\n async duplicateFile(\n sourceKey: string,\n destinationKey: string,\n options?: Partial<DuplicateOptions>,\n ): Promise<DuplicateResult> {\n return this.duplicate({\n sourceKey,\n destinationKey,\n ...options,\n });\n }\n\n async renameFile(\n sourceKey: string,\n newKey: string,\n options?: Partial<MoveOptions>,\n ): Promise<MoveResult> {\n return this.moveFile(sourceKey, newKey, options);\n }\n\n async getDownloadUrl(key: string, expiresIn?: number): Promise<PresignedUrlResult> {\n return this.getPresignedUrl({\n key,\n operation: \"get\",\n expiresIn,\n });\n }\n\n async getUploadUrl(\n key: string,\n contentType?: string,\n expiresIn?: number,\n ): Promise<PresignedUrlResult> {\n return this.getPresignedUrl({\n key,\n operation: \"put\",\n contentType,\n expiresIn,\n });\n }\n\n // Folder convenience methods\n async createFolderPath(path: string): Promise<CreateFolderResult> {\n return this.createFolder({ path });\n }\n\n async deleteFolderPath(path: string, recursive = false): Promise<DeleteFolderResult> {\n return this.deleteFolder({ path, recursive });\n }\n\n async folderPathExists(path: string): Promise<boolean> {\n const result = await this.folderExists(path);\n return result.exists;\n }\n\n async renameFolderPath(oldPath: string, newPath: string): Promise<RenameFolderResult> {\n return this.renameFolder({ oldPath, newPath });\n }\n\n async copyFolderPath(\n sourcePath: string,\n destinationPath: string,\n recursive = true,\n ): Promise<CopyFolderResult> {\n return this.copyFolder({ sourcePath, destinationPath, recursive });\n }\n}\n","import type { EnvRecord } from \"./config\";\nimport { loadS3Config } from \"./config\";\nimport { S3Service } from \"./services/s3\";\nimport type { S3Config } from \"./types\";\n\nexport type { EnvRecord } from \"./config\";\n// === SERVICE CLASSES ===\nexport { S3Service } from \"./services/s3\";\n\n// === MAIN FACTORY FUNCTIONS (Primary API) ===\n/**\n * Create S3 service using environment variables or manual configuration\n * @param config Optional S3 configuration. If not provided, loads from environment variables\n * @param env - Optional environment record\n * @returns S3Service instance\n * @throws Error if configuration is invalid or environment variables are missing\n * @public\n *\n * @example\n * ```typescript\n * import { createS3 } from '@kumix/storage/s3';\n *\n * // Using environment variables\n * // Set: KUMIX_S3_PROVIDER=aws, KUMIX_S3_REGION=us-east-1, etc.\n * const s3FromEnv = createS3();\n * await s3FromEnv.uploadFile('test.txt', 'Hello World');\n *\n * // Using manual configuration\n * const s3Manual = createS3({\n * provider: 'aws',\n * region: 'us-east-1',\n * bucket: 'my-bucket',\n * accessKeyId: 'AKIA...',\n * secretAccessKey: 'secret...'\n * });\n *\n * // Cloudflare R2\n * const r2 = createS3({\n * provider: 'cloudflare-r2',\n * region: 'auto',\n * bucket: 'my-r2-bucket',\n * accessKeyId: 'your-r2-key',\n * secretAccessKey: 'your-r2-secret',\n * endpoint: 'https://account-id.r2.cloudflarestorage.com'\n * });\n *\n * // MinIO\n * const minio = createS3({\n * provider: 'minio',\n * region: 'us-east-1',\n * bucket: 'my-minio-bucket',\n * accessKeyId: 'minioadmin',\n * secretAccessKey: 'minioadmin',\n * endpoint: 'http://localhost:9000',\n * forcePathStyle: true\n * });\n * ```\n */\nexport function createS3(): S3Service;\nexport function createS3(config: S3Config): S3Service;\nexport function createS3(config: S3Config, env: EnvRecord): S3Service;\nexport function createS3(config?: S3Config, env?: EnvRecord): S3Service {\n if (config) {\n return new S3Service(config);\n }\n const envConfig = loadS3Config(env);\n return new S3Service(envConfig);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"s3.js","names":[],"sources":["../src/operations/file-operations.ts","../src/operations/folder-operations.ts","../src/providers/s3.ts","../src/services/s3.ts","../src/s3.ts"],"sourcesContent":["/**\n * S3 file operations implementation\n * Provides comprehensive file management operations for S3-compatible storage providers\n */\n\nimport {\n CopyObjectCommand,\n DeleteObjectCommand,\n DeleteObjectsCommand,\n GetObjectCommand,\n HeadObjectCommand,\n ListObjectsV2Command,\n PutObjectCommand,\n type S3Client,\n} from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nimport { buildPublicUrl, getMimeType } from \"../helpers\";\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CopyOptions,\n CopyResult,\n DeleteOptions,\n DeleteResult,\n DownloadOptions,\n DownloadResult,\n DuplicateOptions,\n DuplicateResult,\n ExistsResult,\n FileInfo,\n ListOptions,\n ListResult,\n MoveOptions,\n MoveResult,\n PresignedUrlOptions,\n PresignedUrlResult,\n S3Config,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * S3 file operations implementation\n * Handles all file-related operations for S3-compatible storage providers\n * @internal\n */\nexport class FileOperations {\n constructor(\n private client: S3Client,\n private config: S3Config,\n ) {}\n\n async upload(options: UploadOptions): Promise<UploadResult> {\n try {\n const contentType = options.contentType || getMimeType(options.key);\n\n const command = new PutObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n Body: options.file,\n ContentType: contentType,\n Metadata: options.metadata,\n CacheControl: options.cacheControl,\n ContentDisposition: options.contentDisposition,\n // R2, MinIO, and Supabase reject canned ACLs. Only apply an ACL when the\n // caller explicitly set one AND the provider supports it (aws/digitalocean).\n ...(options.acl &&\n (this.config.provider === \"aws\" || this.config.provider === \"digitalocean\")\n ? { ACL: options.acl }\n : {}),\n Expires: options.expires,\n });\n\n const result = await this.client.send(command);\n\n const publicUrl = this.getPublicUrl(options.key);\n\n return {\n success: true,\n key: options.key,\n url: publicUrl,\n publicUrl,\n etag: result.ETag?.replace(/\"/g, \"\"),\n size:\n typeof options.file === \"string\"\n ? Buffer.byteLength(options.file, \"utf8\")\n : options.file.length,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Upload failed\",\n };\n }\n }\n\n async download(options: DownloadOptions): Promise<DownloadResult> {\n try {\n const command = new GetObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n Range: options.range,\n });\n\n const result = await this.client.send(command);\n\n if (!result.Body) {\n return {\n success: false,\n error: \"No data received\",\n };\n }\n\n // Convert stream to buffer\n const chunks: Uint8Array[] = [];\n const reader = result.Body.transformToWebStream().getReader();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n\n const data = Buffer.concat(chunks);\n\n return {\n success: true,\n content: data, // Main content field\n data, // Alias for backward compatibility\n contentType: result.ContentType,\n contentLength: result.ContentLength,\n lastModified: result.LastModified,\n etag: result.ETag?.replace(/\"/g, \"\"),\n metadata: result.Metadata,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Download failed\",\n };\n }\n }\n\n async delete(options: DeleteOptions): Promise<DeleteResult> {\n try {\n const command = new DeleteObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n });\n\n await this.client.send(command);\n\n return {\n success: true,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Delete failed\",\n };\n }\n }\n\n async batchDelete(options: BatchDeleteOptions): Promise<BatchDeleteResult> {\n try {\n const command = new DeleteObjectsCommand({\n Bucket: this.config.bucket,\n Delete: {\n Objects: options.keys.map((key) => ({ Key: key })),\n Quiet: false,\n },\n });\n\n const result = await this.client.send(command);\n\n const deleted = result.Deleted?.map((obj) => obj.Key).filter(Boolean) as string[];\n const errors =\n result.Errors?.map((err) => ({\n key: err.Key || \"\",\n error: err.Message || \"Unknown error\",\n })) || [];\n\n return {\n // Partial failures: S3 returns `result.Errors` for objects it could not\n // delete. Treat the operation as failed when any per-key error exists\n // so callers using `if (result.success)` don't silently miss that some\n // objects remain. The full per-key breakdown is still on `errors`/`deleted`.\n success: errors.length === 0,\n deleted,\n errors: errors.length > 0 ? errors : undefined,\n };\n } catch (error) {\n return {\n success: false,\n errors: options.keys.map((key) => ({\n key,\n error: error instanceof Error ? error.message : \"Batch delete failed\",\n })),\n };\n }\n }\n\n async list(options: ListOptions = {}): Promise<ListResult> {\n try {\n const command = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: options.prefix,\n Delimiter: options.delimiter,\n MaxKeys: options.maxKeys,\n ContinuationToken: options.continuationToken,\n });\n\n const result = await this.client.send(command);\n\n const files: FileInfo[] =\n result.Contents?.map((obj) => ({\n key: obj.Key!,\n size: obj.Size || 0,\n lastModified: obj.LastModified || new Date(),\n etag: obj.ETag?.replace(/\"/g, \"\") || \"\",\n contentType: getMimeType(obj.Key!),\n })) || [];\n\n return {\n success: true,\n files,\n isTruncated: result.IsTruncated,\n nextContinuationToken: result.NextContinuationToken,\n commonPrefixes: result.CommonPrefixes?.map((cp) => cp.Prefix!),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"List failed\",\n };\n }\n }\n\n async exists(key: string): Promise<ExistsResult> {\n try {\n const command = new HeadObjectCommand({\n Bucket: this.config.bucket,\n Key: key,\n });\n\n const result = await this.client.send(command);\n\n return {\n exists: true,\n fileInfo: {\n key,\n size: result.ContentLength || 0,\n lastModified: result.LastModified || new Date(),\n etag: result.ETag?.replace(/\"/g, \"\") || \"\",\n contentType: result.ContentType,\n metadata: result.Metadata,\n },\n };\n } catch (error) {\n if (error instanceof Error && error.name === \"NotFound\") {\n return { exists: false };\n }\n\n return {\n exists: false,\n error: error instanceof Error ? error.message : \"Check existence failed\",\n };\n }\n }\n\n async copy(options: CopyOptions): Promise<CopyResult> {\n try {\n const command = new CopyObjectCommand({\n Bucket: this.config.bucket,\n // CopySource must be percent-encoded; keys containing `?`, `&`, `=`,\n // `+`, spaces, or non-ASCII would otherwise break the copy request.\n // Encode each path segment so `/` separators survive while reserved\n // chars within a segment are escaped.\n CopySource: `${this.config.bucket}/${options.sourceKey.split(\"/\").map(encodeURIComponent).join(\"/\")}`,\n Key: options.destinationKey,\n Metadata: options.metadata,\n MetadataDirective: options.metadataDirective || \"COPY\",\n });\n\n const result = await this.client.send(command);\n\n return {\n success: true,\n etag: result.CopyObjectResult?.ETag?.replace(/\"/g, \"\"),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Copy failed\",\n };\n }\n }\n\n async move(options: MoveOptions): Promise<MoveResult> {\n try {\n // First copy the object\n const copyResult = await this.copy({\n sourceKey: options.sourceKey,\n destinationKey: options.destinationKey,\n metadata: options.metadata,\n metadataDirective: options.metadataDirective,\n });\n\n if (!copyResult.success) {\n return {\n success: false,\n error: copyResult.error || \"Move failed during copy operation\",\n };\n }\n\n // Then delete the source object\n const deleteResult = await this.delete({ key: options.sourceKey });\n\n if (!deleteResult.success) {\n return {\n success: false,\n error: deleteResult.error || \"Move failed during delete operation\",\n };\n }\n\n return {\n success: true,\n etag: copyResult.etag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Move failed\",\n };\n }\n }\n\n async duplicate(options: DuplicateOptions): Promise<DuplicateResult> {\n // Duplicate is just an alias for copy\n return this.copy(options);\n }\n\n async getPresignedUrl(options: PresignedUrlOptions): Promise<PresignedUrlResult> {\n try {\n const expiresIn = options.expiresIn || 3600; // 1 hour default\n\n let command: GetObjectCommand | PutObjectCommand;\n if (options.operation === \"get\") {\n command = new GetObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n });\n } else {\n command = new PutObjectCommand({\n Bucket: this.config.bucket,\n Key: options.key,\n ContentType: options.contentType,\n });\n }\n\n const url = await getSignedUrl(this.client, command, {\n expiresIn,\n });\n\n return {\n success: true,\n url,\n expiresAt: new Date(Date.now() + expiresIn * 1000),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Presigned URL generation failed\",\n };\n }\n }\n\n getPublicUrl(key: string): string {\n const isCloudflare = this.config.provider === \"cloudflare-r2\";\n const isSupabase = this.config.provider === \"supabase\";\n\n if (this.config.publicUrl) {\n return buildPublicUrl(\n this.config.publicUrl,\n isCloudflare ? \"\" : this.config.bucket,\n key,\n isSupabase,\n );\n }\n\n if (this.config.endpoint) {\n return buildPublicUrl(this.config.endpoint, this.config.bucket, key, isSupabase);\n }\n\n // MinIO is self-hosted and does not expose objects at the AWS URL format —\n // synthesizing one would just produce a 404 the caller can't distinguish\n // from a real miss. Surface the misconfiguration explicitly instead.\n if (this.config.provider === \"minio\") {\n throw new Error(\n \"MinIO public URL could not be built: set `publicUrl` (or `endpoint`) on the S3 config \" +\n \"to a publicly reachable base, since MinIO has no default public host.\",\n );\n }\n\n // Default AWS / DigitalOcean Spaces URL format\n return `https://${this.config.bucket}.s3.${this.config.region}.amazonaws.com/${key}`;\n }\n}\n","/**\n * S3 folder operations implementation\n * Provides comprehensive folder management operations for S3-compatible storage providers\n */\n\nimport {\n type _Object,\n CopyObjectCommand,\n DeleteObjectsCommand,\n ListObjectsV2Command,\n PutObjectCommand,\n type S3Client,\n} from \"@aws-sdk/client-s3\";\n\nimport { getMimeType } from \"../helpers\";\nimport type {\n CopyFolderOptions,\n CopyFolderResult,\n CreateFolderOptions,\n CreateFolderResult,\n DeleteFolderOptions,\n DeleteFolderResult,\n FileInfo,\n FolderExistsResult,\n FolderInfo,\n ListFoldersOptions,\n ListFoldersResult,\n RenameFolderOptions,\n RenameFolderResult,\n S3Config,\n} from \"../types\";\n\n/** S3 DeleteObjectsCommand allows at most 1000 keys per request */\nconst S3_DELETE_MAX_KEYS = 1000;\n\n/**\n * List ALL objects under a prefix, following pagination (handles >1000 keys)\n */\nasync function listAllObjects(\n client: S3Client,\n bucket: string,\n prefix: string,\n): Promise<_Object[]> {\n const objects: _Object[] = [];\n let continuationToken: string | undefined;\n do {\n const command = new ListObjectsV2Command({\n Bucket: bucket,\n Prefix: prefix,\n ContinuationToken: continuationToken,\n });\n const result = await client.send(command);\n if (result.Contents) {\n objects.push(...result.Contents);\n }\n continuationToken = result.IsTruncated ? result.NextContinuationToken : undefined;\n } while (continuationToken);\n return objects;\n}\n\n/** Delete objects in batches of 1000 (S3 hard limit per DeleteObjectsCommand) */\nasync function deleteObjectsBatched(\n client: S3Client,\n bucket: string,\n keys: string[],\n): Promise<string[]> {\n const deleted: string[] = [];\n for (let i = 0; i < keys.length; i += S3_DELETE_MAX_KEYS) {\n const batch = keys.slice(i, i + S3_DELETE_MAX_KEYS);\n const command = new DeleteObjectsCommand({\n Bucket: bucket,\n Delete: {\n Objects: batch.map((key) => ({ Key: key })),\n Quiet: true,\n },\n });\n const result = await client.send(command);\n if (result.Deleted) {\n for (const obj of result.Deleted) {\n if (obj.Key) deleted.push(obj.Key);\n }\n }\n }\n return deleted;\n}\n\n/**\n * S3 folder operations implementation\n * Handles all folder-related operations for S3-compatible storage providers\n * @internal\n */\nexport class FolderOperations {\n constructor(\n private client: S3Client,\n private config: S3Config,\n ) {}\n\n async createFolder(options: CreateFolderOptions): Promise<CreateFolderResult> {\n try {\n // Ensure path ends with /\n const folderPath = options.path.endsWith(\"/\") ? options.path : `${options.path}/`;\n\n // Create a placeholder object to represent the folder\n const command = new PutObjectCommand({\n Bucket: this.config.bucket,\n Key: folderPath,\n Body: \"\",\n ContentType: \"application/x-directory\",\n });\n\n await this.client.send(command);\n\n return {\n success: true,\n path: folderPath,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Create folder failed\",\n };\n }\n }\n\n async deleteFolder(options: DeleteFolderOptions): Promise<DeleteFolderResult> {\n try {\n // Ensure path ends with /\n const folderPath = options.path.endsWith(\"/\") ? options.path : `${options.path}/`;\n\n if (options.recursive) {\n // List all objects with the folder prefix (handles >1000 keys)\n const allObjects = await listAllObjects(this.client, this.config.bucket, folderPath);\n\n if (allObjects.length === 0) {\n return {\n success: true,\n deletedFiles: [],\n };\n }\n\n // Delete all objects in batches of 1000\n const keys = allObjects.map((obj) => obj.Key!).filter(Boolean);\n const deletedFiles = await deleteObjectsBatched(this.client, this.config.bucket, keys);\n\n return {\n success: true,\n deletedFiles,\n };\n } else {\n // Just delete the folder placeholder\n const deleteCommand = new DeleteObjectsCommand({\n Bucket: this.config.bucket,\n Delete: {\n Objects: [{ Key: folderPath }],\n Quiet: false,\n },\n });\n\n await this.client.send(deleteCommand);\n\n return {\n success: true,\n deletedFiles: [folderPath],\n };\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Delete folder failed\",\n };\n }\n }\n\n async listFolders(options: ListFoldersOptions = {}): Promise<ListFoldersResult> {\n try {\n const command = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: options.prefix,\n Delimiter: options.delimiter || \"/\",\n MaxKeys: options.maxKeys,\n ContinuationToken: options.continuationToken,\n });\n\n const result = await this.client.send(command);\n\n // Parse folders from common prefixes\n const folders: FolderInfo[] =\n result.CommonPrefixes?.map((cp) => {\n const path = cp.Prefix!;\n const name = path.split(\"/\").filter(Boolean).pop() || \"\";\n\n return {\n name,\n path,\n };\n }) || [];\n\n // Parse files from contents\n const files: FileInfo[] =\n result.Contents?.map((obj) => ({\n key: obj.Key!,\n size: obj.Size || 0,\n lastModified: obj.LastModified || new Date(),\n etag: obj.ETag?.replace(/\"/g, \"\") || \"\",\n contentType: getMimeType(obj.Key!),\n })) || [];\n\n return {\n success: true,\n folders,\n files,\n isTruncated: result.IsTruncated,\n nextContinuationToken: result.NextContinuationToken,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"List folders failed\",\n };\n }\n }\n\n async folderExists(path: string): Promise<FolderExistsResult> {\n try {\n // Ensure path ends with /\n const folderPath = path.endsWith(\"/\") ? path : `${path}/`;\n\n const command = new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: folderPath,\n MaxKeys: 1,\n });\n\n const result = await this.client.send(command);\n\n const exists =\n (result.Contents && result.Contents.length > 0) ||\n (result.CommonPrefixes && result.CommonPrefixes.length > 0);\n\n if (exists) {\n const name = folderPath.split(\"/\").filter(Boolean).pop() || \"\";\n\n return {\n exists: true,\n folderInfo: {\n name,\n path: folderPath,\n },\n };\n }\n\n return { exists: false };\n } catch (error) {\n return {\n exists: false,\n error: error instanceof Error ? error.message : \"Check folder existence failed\",\n };\n }\n }\n\n async renameFolder(options: RenameFolderOptions): Promise<RenameFolderResult> {\n try {\n // This is essentially a copy + delete operation for all files in the folder\n const oldPath = options.oldPath.endsWith(\"/\") ? options.oldPath : `${options.oldPath}/`;\n const newPath = options.newPath.endsWith(\"/\") ? options.newPath : `${options.newPath}/`;\n\n // List all objects in the old folder (handles >1000 keys)\n const allObjects = await listAllObjects(this.client, this.config.bucket, oldPath);\n\n if (allObjects.length === 0) {\n return {\n success: true,\n movedFiles: [],\n };\n }\n\n const movedFiles: string[] = [];\n\n // Copy each file to new location\n for (const obj of allObjects) {\n const oldKey = obj.Key!;\n // Anchor the prefix substitution to the start of the key. `String.replace`\n // replaces the first occurrence *anywhere*, which over-replaces when the\n // path segment also appears mid-key.\n const newKey = newPath + oldKey.slice(oldPath.length);\n\n // Copy object using CopyObjectCommand\n const copyCommand = new CopyObjectCommand({\n Bucket: this.config.bucket,\n Key: newKey,\n // CopySource must be percent-encoded; keys with special chars break the\n // copy request otherwise.\n CopySource: `${this.config.bucket}/${oldKey.split(\"/\").map(encodeURIComponent).join(\"/\")}`,\n });\n\n await this.client.send(copyCommand);\n movedFiles.push(newKey);\n }\n\n // Delete old folder contents in batches\n const oldKeys = allObjects.map((obj) => obj.Key!).filter(Boolean);\n await deleteObjectsBatched(this.client, this.config.bucket, oldKeys);\n\n return {\n success: true,\n movedFiles,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Rename folder failed\",\n };\n }\n }\n\n async copyFolder(options: CopyFolderOptions): Promise<CopyFolderResult> {\n try {\n const sourcePath = options.sourcePath.endsWith(\"/\")\n ? options.sourcePath\n : `${options.sourcePath}/`;\n const destPath = options.destinationPath.endsWith(\"/\")\n ? options.destinationPath\n : `${options.destinationPath}/`;\n\n // List all objects in the source folder (handles >1000 keys).\n // Non-recursive filtering is applied per-object below (the list call is\n // identical either way — the previous ternary was dead code).\n const allObjects = await listAllObjects(this.client, this.config.bucket, sourcePath);\n\n if (allObjects.length === 0) {\n return {\n success: true,\n copiedFiles: [],\n };\n }\n\n const copiedFiles: string[] = [];\n\n // Copy each file to new location\n for (const obj of allObjects) {\n const sourceKey = obj.Key!;\n // When not recursive, skip nested objects (files in subfolders)\n if (!options.recursive) {\n const relativeKey = sourceKey.slice(sourcePath.length);\n if (relativeKey.includes(\"/\")) continue;\n }\n // Anchor the prefix substitution to the start of the key.\n const destKey = destPath + sourceKey.slice(sourcePath.length);\n\n // Copy object using CopyObjectCommand\n const copyCommand = new CopyObjectCommand({\n Bucket: this.config.bucket,\n Key: destKey,\n // CopySource must be percent-encoded.\n CopySource: `${this.config.bucket}/${sourceKey.split(\"/\").map(encodeURIComponent).join(\"/\")}`,\n });\n\n await this.client.send(copyCommand);\n copiedFiles.push(destKey);\n }\n\n return {\n success: true,\n copiedFiles,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Copy folder failed\",\n };\n }\n }\n}\n","/**\n * S3-compatible storage provider implementation\n * Provides cloud storage operations using AWS S3 SDK for S3-compatible services\n */\n\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nimport { FileOperations } from \"../operations/file-operations\";\nimport { FolderOperations } from \"../operations/folder-operations\";\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CopyFolderOptions,\n CopyFolderResult,\n CopyOptions,\n CopyResult,\n CreateFolderOptions,\n CreateFolderResult,\n DeleteFolderOptions,\n DeleteFolderResult,\n DeleteOptions,\n DeleteResult,\n DownloadOptions,\n DownloadResult,\n DuplicateOptions,\n DuplicateResult,\n ExistsResult,\n FolderExistsResult,\n ListFoldersOptions,\n ListFoldersResult,\n ListOptions,\n ListResult,\n MoveOptions,\n MoveResult,\n PresignedUrlOptions,\n PresignedUrlResult,\n RenameFolderOptions,\n RenameFolderResult,\n S3Config,\n StorageInterface,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * S3-compatible storage provider\n * Implements StorageInterface for AWS S3 and S3-compatible services\n * @internal\n */\nexport class S3Provider implements StorageInterface {\n private client: S3Client;\n private config: S3Config;\n private fileOps: FileOperations;\n private folderOps: FolderOperations;\n\n constructor(config: S3Config) {\n this.config = config;\n\n this.client = new S3Client({\n region: config.region,\n credentials: {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n // Surface STS / temporary credentials when provided. Previously the\n // session token was dropped, breaking AWS STS / SSO / role-chain auth.\n ...(config.sessionToken ? { sessionToken: config.sessionToken } : {}),\n },\n endpoint: config.endpoint,\n forcePathStyle: config.forcePathStyle ?? false,\n });\n\n this.fileOps = new FileOperations(this.client, this.config);\n this.folderOps = new FolderOperations(this.client, this.config);\n }\n\n // File operations\n async upload(options: UploadOptions): Promise<UploadResult> {\n return this.fileOps.upload(options);\n }\n\n async download(options: DownloadOptions): Promise<DownloadResult> {\n return this.fileOps.download(options);\n }\n\n async delete(options: DeleteOptions): Promise<DeleteResult> {\n return this.fileOps.delete(options);\n }\n\n async batchDelete(options: BatchDeleteOptions): Promise<BatchDeleteResult> {\n return this.fileOps.batchDelete(options);\n }\n\n async list(options?: ListOptions): Promise<ListResult> {\n return this.fileOps.list(options);\n }\n\n async exists(key: string): Promise<ExistsResult> {\n return this.fileOps.exists(key);\n }\n\n async copy(options: CopyOptions): Promise<CopyResult> {\n return this.fileOps.copy(options);\n }\n\n async move(options: MoveOptions): Promise<MoveResult> {\n return this.fileOps.move(options);\n }\n\n async duplicate(options: DuplicateOptions): Promise<DuplicateResult> {\n return this.fileOps.duplicate(options);\n }\n\n async getPresignedUrl(options: PresignedUrlOptions): Promise<PresignedUrlResult> {\n return this.fileOps.getPresignedUrl(options);\n }\n\n getPublicUrl(key: string): string {\n return this.fileOps.getPublicUrl(key);\n }\n\n // Folder operations\n async createFolder(options: CreateFolderOptions): Promise<CreateFolderResult> {\n return this.folderOps.createFolder(options);\n }\n\n async deleteFolder(options: DeleteFolderOptions): Promise<DeleteFolderResult> {\n return this.folderOps.deleteFolder(options);\n }\n\n async listFolders(options?: ListFoldersOptions): Promise<ListFoldersResult> {\n return this.folderOps.listFolders(options);\n }\n\n async folderExists(path: string): Promise<FolderExistsResult> {\n return this.folderOps.folderExists(path);\n }\n\n async renameFolder(options: RenameFolderOptions): Promise<RenameFolderResult> {\n return this.folderOps.renameFolder(options);\n }\n\n async copyFolder(options: CopyFolderOptions): Promise<CopyFolderResult> {\n return this.folderOps.copyFolder(options);\n }\n}\n","/**\n * S3 storage service implementation\n * High-level service wrapper for S3-compatible storage operations with convenience methods\n */\n\nimport { loadS3Config } from \"../config\";\nimport { S3Provider } from \"../providers/s3\";\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CopyFolderOptions,\n CopyFolderResult,\n CopyOptions,\n CopyResult,\n CreateFolderOptions,\n CreateFolderResult,\n DeleteFolderOptions,\n DeleteFolderResult,\n DeleteOptions,\n DeleteResult,\n DownloadOptions,\n DownloadResult,\n DuplicateOptions,\n DuplicateResult,\n ExistsResult,\n FolderExistsResult,\n ListFoldersOptions,\n ListFoldersResult,\n ListOptions,\n ListResult,\n MoveOptions,\n MoveResult,\n PresignedUrlOptions,\n PresignedUrlResult,\n RenameFolderOptions,\n RenameFolderResult,\n S3Config,\n StorageInterface,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * S3 storage service\n * High-level service for S3-compatible storage operations with convenience methods\n * @public\n */\nexport class S3Service implements StorageInterface {\n private provider: S3Provider;\n private config: S3Config;\n\n constructor();\n constructor(config: S3Config);\n constructor(config?: S3Config) {\n this.config = config || loadS3Config();\n this.provider = this.createProvider(this.config);\n }\n\n private createProvider(config: S3Config): S3Provider {\n switch (config.provider) {\n case \"aws\":\n case \"cloudflare-r2\":\n case \"minio\":\n case \"digitalocean\":\n case \"supabase\":\n case \"custom\":\n return new S3Provider(config);\n default:\n throw new Error(`Unsupported S3 provider: ${config.provider}`);\n }\n }\n\n // Utility methods\n getConfig(): S3Config {\n return { ...this.config };\n }\n\n getBucket(): string {\n return this.config.bucket;\n }\n\n getRegion(): string {\n return this.config.region;\n }\n\n getProvider(): string {\n return this.config.provider;\n }\n\n getPublicUrl(key: string): string {\n return this.provider.getPublicUrl(key);\n }\n\n // File operations\n async upload(options: UploadOptions): Promise<UploadResult> {\n return this.provider.upload(options);\n }\n\n async download(options: DownloadOptions): Promise<DownloadResult> {\n return this.provider.download(options);\n }\n\n async delete(options: DeleteOptions): Promise<DeleteResult> {\n return this.provider.delete(options);\n }\n\n async batchDelete(options: BatchDeleteOptions): Promise<BatchDeleteResult> {\n return this.provider.batchDelete(options);\n }\n\n async list(options?: ListOptions): Promise<ListResult> {\n return this.provider.list(options);\n }\n\n async exists(key: string): Promise<ExistsResult> {\n return this.provider.exists(key);\n }\n\n async copy(options: CopyOptions): Promise<CopyResult> {\n return this.provider.copy(options);\n }\n\n async move(options: MoveOptions): Promise<MoveResult> {\n return this.provider.move(options);\n }\n\n async duplicate(options: DuplicateOptions): Promise<DuplicateResult> {\n return this.provider.duplicate(options);\n }\n\n async getPresignedUrl(options: PresignedUrlOptions): Promise<PresignedUrlResult> {\n return this.provider.getPresignedUrl(options);\n }\n\n // Folder operations\n async createFolder(options: CreateFolderOptions): Promise<CreateFolderResult> {\n return this.provider.createFolder(options);\n }\n\n async deleteFolder(options: DeleteFolderOptions): Promise<DeleteFolderResult> {\n return this.provider.deleteFolder(options);\n }\n\n async listFolders(options?: ListFoldersOptions): Promise<ListFoldersResult> {\n return this.provider.listFolders(options);\n }\n\n async folderExists(path: string): Promise<FolderExistsResult> {\n return this.provider.folderExists(path);\n }\n\n async renameFolder(options: RenameFolderOptions): Promise<RenameFolderResult> {\n return this.provider.renameFolder(options);\n }\n\n async copyFolder(options: CopyFolderOptions): Promise<CopyFolderResult> {\n return this.provider.copyFolder(options);\n }\n\n // Convenience methods\n async uploadFile(\n key: string,\n file: Buffer | Uint8Array | string,\n options?: Partial<UploadOptions>,\n ): Promise<UploadResult> {\n return this.upload({\n key,\n file,\n ...options,\n });\n }\n\n async downloadFile(key: string): Promise<DownloadResult> {\n return this.download({ key });\n }\n\n async deleteFile(key: string): Promise<DeleteResult> {\n return this.delete({ key });\n }\n\n async deleteFiles(keys: string[]): Promise<BatchDeleteResult> {\n return this.batchDelete({ keys });\n }\n\n async listFiles(prefix?: string, maxKeys?: number): Promise<ListResult> {\n return this.list({ prefix, maxKeys });\n }\n\n async fileExists(key: string): Promise<boolean> {\n const result = await this.exists(key);\n return result.exists;\n }\n\n async copyFile(\n sourceKey: string,\n destinationKey: string,\n options?: Partial<CopyOptions>,\n ): Promise<CopyResult> {\n return this.copy({\n sourceKey,\n destinationKey,\n ...options,\n });\n }\n\n async moveFile(\n sourceKey: string,\n destinationKey: string,\n options?: Partial<MoveOptions>,\n ): Promise<MoveResult> {\n return this.move({\n sourceKey,\n destinationKey,\n ...options,\n });\n }\n\n async duplicateFile(\n sourceKey: string,\n destinationKey: string,\n options?: Partial<DuplicateOptions>,\n ): Promise<DuplicateResult> {\n return this.duplicate({\n sourceKey,\n destinationKey,\n ...options,\n });\n }\n\n async renameFile(\n sourceKey: string,\n newKey: string,\n options?: Partial<MoveOptions>,\n ): Promise<MoveResult> {\n return this.moveFile(sourceKey, newKey, options);\n }\n\n async getDownloadUrl(key: string, expiresIn?: number): Promise<PresignedUrlResult> {\n return this.getPresignedUrl({\n key,\n operation: \"get\",\n expiresIn,\n });\n }\n\n async getUploadUrl(\n key: string,\n contentType?: string,\n expiresIn?: number,\n ): Promise<PresignedUrlResult> {\n return this.getPresignedUrl({\n key,\n operation: \"put\",\n contentType,\n expiresIn,\n });\n }\n\n // Folder convenience methods\n async createFolderPath(path: string): Promise<CreateFolderResult> {\n return this.createFolder({ path });\n }\n\n async deleteFolderPath(path: string, recursive = false): Promise<DeleteFolderResult> {\n return this.deleteFolder({ path, recursive });\n }\n\n async folderPathExists(path: string): Promise<boolean> {\n const result = await this.folderExists(path);\n return result.exists;\n }\n\n async renameFolderPath(oldPath: string, newPath: string): Promise<RenameFolderResult> {\n return this.renameFolder({ oldPath, newPath });\n }\n\n async copyFolderPath(\n sourcePath: string,\n destinationPath: string,\n recursive = true,\n ): Promise<CopyFolderResult> {\n return this.copyFolder({ sourcePath, destinationPath, recursive });\n }\n}\n","import type { EnvRecord } from \"./config\";\nimport { loadS3Config } from \"./config\";\nimport { S3Service } from \"./services/s3\";\nimport type { S3Config } from \"./types\";\n\nexport type { EnvRecord } from \"./config\";\n// === SERVICE CLASSES ===\nexport { S3Service } from \"./services/s3\";\n\n// === MAIN FACTORY FUNCTIONS (Primary API) ===\n/**\n * Create S3 service using environment variables or manual configuration\n * @param config Optional S3 configuration. If not provided, loads from environment variables\n * @param env - Optional environment record\n * @returns S3Service instance\n * @throws Error if configuration is invalid or environment variables are missing\n * @public\n *\n * @example\n * ```typescript\n * import { createS3 } from '@kumix/storage/s3';\n *\n * // Using environment variables\n * // Set: KUMIX_S3_PROVIDER=aws, KUMIX_S3_REGION=us-east-1, etc.\n * const s3FromEnv = createS3();\n * await s3FromEnv.uploadFile('test.txt', 'Hello World');\n *\n * // Using manual configuration\n * const s3Manual = createS3({\n * provider: 'aws',\n * region: 'us-east-1',\n * bucket: 'my-bucket',\n * accessKeyId: 'AKIA...',\n * secretAccessKey: 'secret...'\n * });\n *\n * // Cloudflare R2\n * const r2 = createS3({\n * provider: 'cloudflare-r2',\n * region: 'auto',\n * bucket: 'my-r2-bucket',\n * accessKeyId: 'your-r2-key',\n * secretAccessKey: 'your-r2-secret',\n * endpoint: 'https://account-id.r2.cloudflarestorage.com'\n * });\n *\n * // MinIO\n * const minio = createS3({\n * provider: 'minio',\n * region: 'us-east-1',\n * bucket: 'my-minio-bucket',\n * accessKeyId: 'minioadmin',\n * secretAccessKey: 'minioadmin',\n * endpoint: 'http://localhost:9000',\n * forcePathStyle: true\n * });\n * ```\n */\nexport function createS3(): S3Service;\nexport function createS3(config: S3Config): S3Service;\nexport function createS3(config: S3Config, env: EnvRecord): S3Service;\nexport function createS3(config: undefined, env: EnvRecord): S3Service;\nexport function createS3(config?: S3Config, env?: EnvRecord): S3Service {\n if (config) {\n return new S3Service(config);\n }\n // When `config` is omitted, build the config from env. This overload also\n // covers `createS3(undefined, env)` which was previously rejected by the\n // published signatures despite being a valid call.\n const envConfig = loadS3Config(env);\n return new S3Service(envConfig);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,30 +1,29 @@
1
1
  {
2
2
  "name": "@kumix/storage",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Storage utilities for SaaS applications.",
5
5
  "author": "Kumix Labs <hai@kumix.io>",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "main": "./dist/index.js",
9
- "module": "./dist/index.js",
10
9
  "types": "./dist/index.d.ts",
11
10
  "sideEffects": false,
12
11
  "exports": {
13
12
  ".": {
14
13
  "types": "./dist/index.d.ts",
15
- "import": "./dist/index.js"
14
+ "default": "./dist/index.js"
16
15
  },
17
16
  "./s3": {
18
17
  "types": "./dist/s3.d.ts",
19
- "import": "./dist/s3.js"
18
+ "default": "./dist/s3.js"
20
19
  },
21
20
  "./cloudinary": {
22
21
  "types": "./dist/cloudinary.d.ts",
23
- "import": "./dist/cloudinary.js"
22
+ "default": "./dist/cloudinary.js"
24
23
  },
25
24
  "./helpers": {
26
25
  "types": "./dist/helpers.d.ts",
27
- "import": "./dist/helpers.js"
26
+ "default": "./dist/helpers.js"
28
27
  }
29
28
  },
30
29
  "scripts": {
@@ -58,14 +57,10 @@
58
57
  "digitalocean",
59
58
  "supabase"
60
59
  ],
61
- "dependencies": {
62
- "mime-types": "^3.0.2"
63
- },
64
60
  "devDependencies": {
65
61
  "@aws-sdk/client-s3": "^3.1079.0",
66
62
  "@aws-sdk/s3-request-presigner": "^3.1079.0",
67
63
  "@kumix/tsconfig": "^0.1.0",
68
- "@types/mime-types": "^3.0.1",
69
64
  "@types/node": "^26.1.0",
70
65
  "cloudinary": "^2.10.0",
71
66
  "tsdown": "^0.22.3",
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-J6AdDh_c.d.ts","names":[],"sources":["../src/types/base.ts","../src/types/file-operations.ts","../src/types/folder-operations.ts","../src/types/storage-interface.ts","../src/config.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-t-NVJICl.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * Storage configuration from environment variables\n * Provides automatic configuration loading from environment variables\n */\n\nimport type { CloudinaryConfig, S3Config, StorageConfig } from \"./types\";\n\n/**\n * Cross-runtime environment record.\n * Pass `process.env` on Node.js, `ctx.env` on Cloudflare Workers,\n * `Deno.env.toObject()` on Deno, or a plain object in the browser.\n */\nexport type EnvRecord = Record<string, string | undefined>;\n\nfunction getDefaultEnv(): EnvRecord | undefined {\n if (typeof process !== \"undefined\" && process?.env) {\n return process.env as EnvRecord;\n }\n return undefined;\n}\n\nfunction resolveEnv(env?: EnvRecord): EnvRecord | undefined {\n return env ?? getDefaultEnv();\n}\n\n/**\n * Environment variable names for storage configuration\n * @public\n *\n * @example\n * ```typescript\n * import { ENV_VARS } from '@kumix/storage';\n *\n * // Check if specific env vars are set\n * console.log(process.env[ENV_VARS.KUMIX_S3_BUCKET]);\n * console.log(process.env[ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME]);\n * ```\n */\nexport const ENV_VARS = {\n // S3 Configuration\n KUMIX_S3_PROVIDER: \"KUMIX_S3_PROVIDER\",\n KUMIX_S3_REGION: \"KUMIX_S3_REGION\",\n KUMIX_S3_BUCKET: \"KUMIX_S3_BUCKET\",\n KUMIX_S3_ACCESS_KEY_ID: \"KUMIX_S3_ACCESS_KEY_ID\",\n KUMIX_S3_SECRET_ACCESS_KEY: \"KUMIX_S3_SECRET_ACCESS_KEY\",\n KUMIX_S3_ENDPOINT: \"KUMIX_S3_ENDPOINT\",\n KUMIX_S3_FORCE_PATH_STYLE: \"KUMIX_S3_FORCE_PATH_STYLE\",\n KUMIX_S3_PUBLIC_URL: \"KUMIX_S3_PUBLIC_URL\",\n\n // Cloudinary Configuration\n KUMIX_CLOUDINARY_CLOUD_NAME: \"KUMIX_CLOUDINARY_CLOUD_NAME\",\n KUMIX_CLOUDINARY_API_KEY: \"KUMIX_CLOUDINARY_API_KEY\",\n KUMIX_CLOUDINARY_API_SECRET: \"KUMIX_CLOUDINARY_API_SECRET\",\n KUMIX_CLOUDINARY_SECURE: \"KUMIX_CLOUDINARY_SECURE\",\n KUMIX_CLOUDINARY_FOLDER: \"KUMIX_CLOUDINARY_FOLDER\",\n} as const;\n\n/**\n * Get environment variable value\n * @param key - Environment variable name\n * @param env - Optional environment record\n * @internal\n */\nfunction getEnvVar(key: string, env?: EnvRecord): string | undefined {\n const e = resolveEnv(env);\n if (!e) return undefined;\n return e[key];\n}\n\n/**\n * Get required environment variable value\n * @param key - Environment variable name\n * @param env - Optional environment record\n * @internal\n */\nfunction getRequiredEnvVar(key: string, env?: EnvRecord): string {\n const value = getEnvVar(key, env);\n if (!value) {\n throw new Error(`Missing required environment variable: ${key}`);\n }\n return value;\n}\n\n/**\n * Get boolean environment variable value\n * @param key - Environment variable name\n * @param defaultValue - Default boolean value if not set\n * @param env - Optional environment record\n * @internal\n */\nfunction getBooleanEnvVar(key: string, defaultValue = false, env?: EnvRecord): boolean {\n const value = getEnvVar(key, env);\n if (!value) return defaultValue;\n return value.toLowerCase() === \"true\" || value === \"1\";\n}\n\n/**\n * Load S3 configuration from environment variables\n * @param env - Optional environment record\n * @returns S3 configuration object\n * @throws Error if required environment variables are missing\n * @public\n *\n * @example\n * ```typescript\n * import { loadS3Config } from '@kumix/storage';\n *\n * // Set environment variables first:\n * // KUMIX_S3_PROVIDER=aws\n * // KUMIX_S3_REGION=us-east-1\n * // KUMIX_S3_BUCKET=my-bucket\n * // KUMIX_S3_ACCESS_KEY_ID=AKIA...\n * // KUMIX_S3_SECRET_ACCESS_KEY=secret...\n *\n * try {\n * const config = loadS3Config();\n * console.log(config);\n * // Returns: {\n * // provider: 'aws',\n * // region: 'us-east-1',\n * // bucket: 'my-bucket',\n * // accessKeyId: 'AKIA...',\n * // secretAccessKey: 'secret...'\n * // }\n * } catch (error) {\n * console.error('Missing S3 configuration:', error.message);\n * }\n * ```\n */\nexport function loadS3Config(env?: EnvRecord): S3Config {\n const provider = getRequiredEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env) as S3Config[\"provider\"];\n\n // Validate provider\n const validProviders: S3Config[\"provider\"][] = [\n \"aws\",\n \"cloudflare-r2\",\n \"minio\",\n \"digitalocean\",\n \"supabase\",\n \"custom\",\n ];\n if (!validProviders.includes(provider)) {\n throw new Error(\n `Invalid S3 provider: ${provider}. Must be one of: ${validProviders.join(\", \")}`,\n );\n }\n\n return {\n provider,\n region: getRequiredEnvVar(ENV_VARS.KUMIX_S3_REGION, env),\n bucket: getRequiredEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env),\n accessKeyId: getRequiredEnvVar(ENV_VARS.KUMIX_S3_ACCESS_KEY_ID, env),\n secretAccessKey: getRequiredEnvVar(ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY, env),\n endpoint: getEnvVar(ENV_VARS.KUMIX_S3_ENDPOINT, env),\n forcePathStyle: getBooleanEnvVar(ENV_VARS.KUMIX_S3_FORCE_PATH_STYLE, false, env),\n publicUrl: getEnvVar(ENV_VARS.KUMIX_S3_PUBLIC_URL, env),\n };\n}\n\n/**\n * Load Cloudinary configuration from environment variables\n * @param env - Optional environment record\n * @returns Cloudinary configuration object\n * @throws Error if required environment variables are missing\n * @public\n *\n * @example\n * ```typescript\n * import { loadCloudinaryConfig } from '@kumix/storage';\n *\n * // Set environment variables first:\n * // KUMIX_CLOUDINARY_CLOUD_NAME=my-cloud\n * // KUMIX_CLOUDINARY_API_KEY=123456789\n * // KUMIX_CLOUDINARY_API_SECRET=secret...\n * // KUMIX_CLOUDINARY_SECURE=true (optional)\n * // KUMIX_CLOUDINARY_FOLDER=uploads (optional)\n *\n * try {\n * const config = loadCloudinaryConfig();\n * console.log(config);\n * // Returns: {\n * // provider: 'cloudinary',\n * // cloudName: 'my-cloud',\n * // apiKey: '123456789',\n * // apiSecret: 'secret...',\n * // secure: true,\n * // folder: 'uploads'\n * // }\n * } catch (error) {\n * console.error('Missing Cloudinary configuration:', error.message);\n * }\n * ```\n */\nexport function loadCloudinaryConfig(env?: EnvRecord): CloudinaryConfig {\n return {\n provider: \"cloudinary\",\n cloudName: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env),\n apiKey: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_KEY, env),\n apiSecret: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_SECRET, env),\n secure: getBooleanEnvVar(ENV_VARS.KUMIX_CLOUDINARY_SECURE, true, env),\n folder: getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_FOLDER, env),\n };\n}\n\n/**\n * Auto-detect and load storage configuration from environment variables\n * Determines the provider based on available environment variables\n * @param env - Optional environment record\n * @returns Storage configuration object (S3 or Cloudinary)\n * @throws Error if no valid configuration is found\n * @public\n *\n * @example\n * ```typescript\n * import { loadStorageConfig } from '@kumix/storage';\n *\n * // Auto-detection based on available env vars\n * try {\n * const config = loadStorageConfig();\n *\n * if (config.provider === 'cloudinary') {\n * console.log('Using Cloudinary:', config.cloudName);\n * } else {\n * console.log('Using S3:', config.provider, config.bucket);\n * }\n * } catch (error) {\n * console.error('No storage configuration found:', error.message);\n * }\n *\n * // Explicit provider (set KUMIX_S3_PROVIDER=cloudinary)\n * // Will load Cloudinary config even if S3 vars are also present\n * ```\n */\nexport function loadStorageConfig(env?: EnvRecord): StorageConfig {\n const provider = getEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env);\n\n // If provider is explicitly set, use it\n if (provider) {\n if (provider === \"cloudinary\") {\n return loadCloudinaryConfig(env);\n }\n return loadS3Config(env);\n }\n\n // Auto-detect based on available environment variables\n const hasCloudinaryVars =\n getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env) &&\n getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_KEY, env) &&\n getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_SECRET, env);\n\n const hasS3Vars =\n getEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env) &&\n getEnvVar(ENV_VARS.KUMIX_S3_ACCESS_KEY_ID, env) &&\n getEnvVar(ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY, env);\n\n if (hasCloudinaryVars) {\n return loadCloudinaryConfig(env);\n }\n if (hasS3Vars) {\n // Default to AWS if no provider specified\n const config = loadS3Config(env);\n if (!config.provider) {\n config.provider = \"aws\";\n }\n return config;\n }\n\n throw new Error(\n \"No storage configuration found. Please set either:\\n\" +\n \"- S3: KUMIX_S3_PROVIDER, KUMIX_S3_REGION, KUMIX_S3_BUCKET, KUMIX_S3_ACCESS_KEY_ID, KUMIX_S3_SECRET_ACCESS_KEY\\n\" +\n \"- Cloudinary: KUMIX_CLOUDINARY_CLOUD_NAME, KUMIX_CLOUDINARY_API_KEY, KUMIX_CLOUDINARY_API_SECRET\",\n );\n}\n\n/**\n * Check if storage configuration is available in environment variables\n * @param env - Optional environment record\n * @returns True if valid storage configuration is found\n * @public\n *\n * @example\n * ```typescript\n * import { hasStorageConfig, loadStorageConfig } from '@kumix/storage';\n *\n * if (hasStorageConfig()) {\n * const config = loadStorageConfig();\n * console.log('Storage configured:', config.provider);\n * } else {\n * console.log('Please set storage environment variables');\n * }\n *\n * // Use in conditional initialization\n * const storage = hasStorageConfig() ? createStorage() : null;\n * ```\n */\nexport function hasStorageConfig(env?: EnvRecord): boolean {\n try {\n loadStorageConfig(env);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if storage configuration is available in environment variables\n * @param env - Optional environment record\n * @returns True if either S3 or Cloudinary configuration is available\n * @public\n *\n * @example\n * ```typescript\n * import { isStorageConfigured, createS3, createCloudinary } from '@kumix/storage';\n *\n * if (isStorageConfigured()) {\n * // Choose your preferred provider\n * const s3 = createS3();\n * // OR\n * const cloudinary = createCloudinary();\n *\n * await s3.uploadFile('test.txt', 'Hello World');\n * } else {\n * console.log('Storage not configured. Please set environment variables.');\n * }\n *\n * // Use in conditional initialization\n * const storage = isStorageConfigured() ? createS3() : null;\n * if (storage) {\n * await storage.uploadFile('file.txt', content);\n * }\n * ```\n */\nexport function isStorageConfigured(env?: EnvRecord): boolean {\n return hasStorageConfig(env);\n}\n\n/**\n * Get storage provider name from environment variables without loading full config\n * @param env - Optional environment record\n * @returns Provider name or undefined if not configured\n * @public\n *\n * @example\n * ```typescript\n * import { getStorageProvider } from '@kumix/storage';\n *\n * const provider = getStorageProvider();\n *\n * switch (provider) {\n * case 'aws':\n * console.log('Using AWS S3');\n * break;\n * case 'cloudinary':\n * console.log('Using Cloudinary');\n * break;\n * case 'cloudflare-r2':\n * console.log('Using Cloudflare R2');\n * break;\n * default:\n * console.log('No storage provider configured');\n * }\n *\n * // Quick check without throwing errors\n * if (getStorageProvider()) {\n * // Storage is configured\n * }\n * ```\n */\nexport function getStorageProvider(env?: EnvRecord): string | undefined {\n const provider = getEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env);\n if (provider) return provider;\n\n // Auto-detect\n const hasCloudinaryVars = getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env);\n const hasS3Vars = getEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env);\n\n if (hasCloudinaryVars) return \"cloudinary\";\n if (hasS3Vars) return \"aws\"; // Default S3 provider\n\n return undefined;\n}\n\n/**\n * Validate if all required environment variables are set for S3\n * @param env - Optional environment record\n * @returns Validation result with missing variables\n * @public\n *\n * @example\n * ```typescript\n * import { validateS3EnvVars } from '@kumix/storage';\n *\n * const validation = validateS3EnvVars();\n *\n * if (validation.valid) {\n * console.log('S3 configuration is complete');\n * } else {\n * console.log('Missing S3 variables:', validation.missing);\n * // Returns: [\"KUMIX_S3_REGION\", \"KUMIX_S3_BUCKET\"]\n * }\n * ```\n */\nexport function validateS3EnvVars(env?: EnvRecord): {\n valid: boolean;\n missing: string[];\n} {\n const required = [\n ENV_VARS.KUMIX_S3_PROVIDER,\n ENV_VARS.KUMIX_S3_REGION,\n ENV_VARS.KUMIX_S3_BUCKET,\n ENV_VARS.KUMIX_S3_ACCESS_KEY_ID,\n ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY,\n ];\n\n const missing = required.filter((key) => !getEnvVar(key, env));\n\n return {\n valid: missing.length === 0,\n missing,\n };\n}\n\n/**\n * Validate if all required environment variables are set for Cloudinary\n * @param env - Optional environment record\n * @returns Validation result with missing variables\n * @public\n *\n * @example\n * ```typescript\n * import { validateCloudinaryEnvVars } from '@kumix/storage';\n *\n * const validation = validateCloudinaryEnvVars();\n *\n * if (validation.valid) {\n * console.log('Cloudinary configuration is complete');\n * } else {\n * console.log('Missing Cloudinary variables:', validation.missing);\n * // Returns: [\"KUMIX_CLOUDINARY_API_KEY\"]\n * }\n * ```\n */\nexport function validateCloudinaryEnvVars(env?: EnvRecord): {\n valid: boolean;\n missing: string[];\n} {\n const required = [\n ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME,\n ENV_VARS.KUMIX_CLOUDINARY_API_KEY,\n ENV_VARS.KUMIX_CLOUDINARY_API_SECRET,\n ];\n\n const missing = required.filter((key) => !getEnvVar(key, env));\n\n return {\n valid: missing.length === 0,\n missing,\n };\n}\n\n/**\n * Get all available environment variables for debugging\n * @param env - Optional environment record\n * @returns Object containing all storage-related env vars\n * @public\n *\n * @example\n * ```typescript\n * import { getStorageEnvVars } from '@kumix/storage';\n *\n * const envVars = getStorageEnvVars();\n * console.log('Storage environment variables:', envVars);\n * // Returns: {\n * // KUMIX_S3_PROVIDER: 'aws',\n * // KUMIX_S3_REGION: 'us-east-1',\n * // KUMIX_S3_BUCKET: 'my-bucket',\n * // // ... other set variables (secrets are masked)\n * // }\n * ```\n */\nexport function getStorageEnvVars(env?: EnvRecord): Record<string, string | undefined> {\n const result: Record<string, string | undefined> = {};\n\n Object.values(ENV_VARS).forEach((key) => {\n const value = getEnvVar(key, env);\n if (value) {\n // Mask sensitive values\n if (key.includes(\"SECRET\") || key.includes(\"API_SECRET\")) {\n result[key] = `${value.substring(0, 4)}***`;\n } else {\n result[key] = value;\n }\n }\n });\n\n return result;\n}\n"],"mappings":";AAcA,SAAS,gBAAuC;CAC9C,IAAI,OAAO,YAAY,eAAe,SAAS,KAC7C,OAAO,QAAQ;AAGnB;AAEA,SAAS,WAAW,KAAwC;CAC1D,OAAO,OAAO,cAAc;AAC9B;;;;;;;;;;;;;;AAeA,MAAa,WAAW;CAEtB,mBAAmB;CACnB,iBAAiB;CACjB,iBAAiB;CACjB,wBAAwB;CACxB,4BAA4B;CAC5B,mBAAmB;CACnB,2BAA2B;CAC3B,qBAAqB;CAGrB,6BAA6B;CAC7B,0BAA0B;CAC1B,6BAA6B;CAC7B,yBAAyB;CACzB,yBAAyB;AAC3B;;;;;;;AAQA,SAAS,UAAU,KAAa,KAAqC;CACnE,MAAM,IAAI,WAAW,GAAG;CACxB,IAAI,CAAC,GAAG,OAAO,KAAA;CACf,OAAO,EAAE;AACX;;;;;;;AAQA,SAAS,kBAAkB,KAAa,KAAyB;CAC/D,MAAM,QAAQ,UAAU,KAAK,GAAG;CAChC,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,0CAA0C,KAAK;CAEjE,OAAO;AACT;;;;;;;;AASA,SAAS,iBAAiB,KAAa,eAAe,OAAO,KAA0B;CACrF,MAAM,QAAQ,UAAU,KAAK,GAAG;CAChC,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO,MAAM,YAAY,MAAM,UAAU,UAAU;AACrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,aAAa,KAA2B;CACtD,MAAM,WAAW,kBAAkB,SAAS,mBAAmB,GAAG;CAGlE,MAAM,iBAAyC;EAC7C;EACA;EACA;EACA;EACA;EACA;CACF;CACA,IAAI,CAAC,eAAe,SAAS,QAAQ,GACnC,MAAM,IAAI,MACR,wBAAwB,SAAS,oBAAoB,eAAe,KAAK,IAAI,GAC/E;CAGF,OAAO;EACL;EACA,QAAQ,kBAAkB,SAAS,iBAAiB,GAAG;EACvD,QAAQ,kBAAkB,SAAS,iBAAiB,GAAG;EACvD,aAAa,kBAAkB,SAAS,wBAAwB,GAAG;EACnE,iBAAiB,kBAAkB,SAAS,4BAA4B,GAAG;EAC3E,UAAU,UAAU,SAAS,mBAAmB,GAAG;EACnD,gBAAgB,iBAAiB,SAAS,2BAA2B,OAAO,GAAG;EAC/E,WAAW,UAAU,SAAS,qBAAqB,GAAG;CACxD;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,qBAAqB,KAAmC;CACtE,OAAO;EACL,UAAU;EACV,WAAW,kBAAkB,SAAS,6BAA6B,GAAG;EACtE,QAAQ,kBAAkB,SAAS,0BAA0B,GAAG;EAChE,WAAW,kBAAkB,SAAS,6BAA6B,GAAG;EACtE,QAAQ,iBAAiB,SAAS,yBAAyB,MAAM,GAAG;EACpE,QAAQ,UAAU,SAAS,yBAAyB,GAAG;CACzD;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,kBAAkB,KAAgC;CAChE,MAAM,WAAW,UAAU,SAAS,mBAAmB,GAAG;CAG1D,IAAI,UAAU;EACZ,IAAI,aAAa,cACf,OAAO,qBAAqB,GAAG;EAEjC,OAAO,aAAa,GAAG;CACzB;CAGA,MAAM,oBACJ,UAAU,SAAS,6BAA6B,GAAG,KACnD,UAAU,SAAS,0BAA0B,GAAG,KAChD,UAAU,SAAS,6BAA6B,GAAG;CAErD,MAAM,YACJ,UAAU,SAAS,iBAAiB,GAAG,KACvC,UAAU,SAAS,wBAAwB,GAAG,KAC9C,UAAU,SAAS,4BAA4B,GAAG;CAEpD,IAAI,mBACF,OAAO,qBAAqB,GAAG;CAEjC,IAAI,WAAW;EAEb,MAAM,SAAS,aAAa,GAAG;EAC/B,IAAI,CAAC,OAAO,UACV,OAAO,WAAW;EAEpB,OAAO;CACT;CAEA,MAAM,IAAI,MACR,qQAGF;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,iBAAiB,KAA0B;CACzD,IAAI;EACF,kBAAkB,GAAG;EACrB,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,oBAAoB,KAA0B;CAC5D,OAAO,iBAAiB,GAAG;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgB,mBAAmB,KAAqC;CACtE,MAAM,WAAW,UAAU,SAAS,mBAAmB,GAAG;CAC1D,IAAI,UAAU,OAAO;CAGrB,MAAM,oBAAoB,UAAU,SAAS,6BAA6B,GAAG;CAC7E,MAAM,YAAY,UAAU,SAAS,iBAAiB,GAAG;CAEzD,IAAI,mBAAmB,OAAO;CAC9B,IAAI,WAAW,OAAO;AAGxB;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,kBAAkB,KAGhC;CASA,MAAM,UAAU;EAPd,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;CAGY,CAAC,CAAC,QAAQ,QAAQ,CAAC,UAAU,KAAK,GAAG,CAAC;CAE7D,OAAO;EACL,OAAO,QAAQ,WAAW;EAC1B;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,0BAA0B,KAGxC;CAOA,MAAM,UAAU;EALd,SAAS;EACT,SAAS;EACT,SAAS;CAGY,CAAC,CAAC,QAAQ,QAAQ,CAAC,UAAU,KAAK,GAAG,CAAC;CAE7D,OAAO;EACL,OAAO,QAAQ,WAAW;EAC1B;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,kBAAkB,KAAqD;CACrF,MAAM,SAA6C,CAAC;CAEpD,OAAO,OAAO,QAAQ,CAAC,CAAC,SAAS,QAAQ;EACvC,MAAM,QAAQ,UAAU,KAAK,GAAG;EAChC,IAAI,OAEF,IAAI,IAAI,SAAS,QAAQ,KAAK,IAAI,SAAS,YAAY,GACrD,OAAO,OAAO,GAAG,MAAM,UAAU,GAAG,CAAC,EAAE;OAEvC,OAAO,OAAO;CAGpB,CAAC;CAED,OAAO;AACT"}