@kumix/storage 0.1.0

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/README.md ADDED
@@ -0,0 +1,291 @@
1
+ # @kumix/storage
2
+
3
+ [![Version](https://img.shields.io/npm/v/@kumix/storage.svg)](https://www.npmjs.com/package/@kumix/storage)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A comprehensive storage utilities package for SaaS applications. This package provides a unified interface for working with various storage providers including AWS S3, Cloudflare R2, MinIO, DigitalOcean Spaces, Supabase Storage, and Cloudinary.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @kumix/storage
12
+ # or
13
+ bun add @kumix/storage
14
+
15
+ # Install peer dependencies for the provider(s) you need
16
+ npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner # For S3-compatible providers
17
+ npm install cloudinary # For Cloudinary
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### S3-Compatible Storage (AWS, R2, MinIO, etc.)
23
+
24
+ ```typescript
25
+ import { S3Service } from "@kumix/storage/s3";
26
+
27
+ const storage = new S3Service({
28
+ provider: "aws", // or 'cloudflare-r2', 'minio', 'digitalocean', 'supabase'
29
+ region: "us-east-1",
30
+ bucket: "my-bucket",
31
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
32
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
33
+ });
34
+
35
+ // Upload a file
36
+ await storage.upload({
37
+ key: "documents/file.pdf",
38
+ file: fileBuffer,
39
+ contentType: "application/pdf",
40
+ });
41
+
42
+ // Download a file
43
+ const result = await storage.download({ key: "documents/file.pdf" });
44
+
45
+ // Generate a presigned URL (temporary access)
46
+ const url = await storage.getPresignedUrl({
47
+ key: "documents/file.pdf",
48
+ operation: "get",
49
+ expiresIn: 3600, // 1 hour
50
+ });
51
+ ```
52
+
53
+ ### Cloudinary Storage
54
+
55
+ ```typescript
56
+ import { CloudinaryService } from "@kumix/storage/cloudinary";
57
+
58
+ const storage = new CloudinaryService({
59
+ provider: "cloudinary",
60
+ cloudName: process.env.CLOUDINARY_CLOUD_NAME,
61
+ apiKey: process.env.CLOUDINARY_API_KEY,
62
+ apiSecret: process.env.CLOUDINARY_API_SECRET,
63
+ });
64
+
65
+ // Upload an image
66
+ await storage.upload({
67
+ key: "images/photo.jpg",
68
+ file: imageBuffer,
69
+ contentType: "image/jpeg",
70
+ });
71
+ ```
72
+
73
+ ## Key Features
74
+
75
+ - **Unified Interface**: Single API for multiple storage providers
76
+ - **S3-Compatible Providers**: AWS S3, Cloudflare R2, MinIO, DigitalOcean Spaces, Supabase Storage
77
+ - **Cloudinary Support**: Image and media management with built-in optimizations
78
+ - **File Operations**: Upload, download, delete, copy, move, and check existence
79
+ - **Folder Operations**: Create, delete, list, and manage folders
80
+ - **Presigned URLs**: Generate time-limited access URLs for secure sharing
81
+ - **Public URLs**: Get public access URLs with optional CDN support
82
+ - **Type-Safe**: Full TypeScript support with comprehensive types
83
+ - **Flexible Configuration**: Support for custom endpoints and CDN URLs
84
+
85
+ ## Supported Providers
86
+
87
+ ### S3-Compatible
88
+
89
+ - **AWS S3** - Amazon's object storage service
90
+ - **Cloudflare R2** - Cloudflare's S3-compatible storage (no egress fees)
91
+ - **MinIO** - Self-hosted S3-compatible storage
92
+ - **DigitalOcean Spaces** - DigitalOcean's object storage
93
+ - **Supabase Storage** - Supabase's S3-compatible storage
94
+
95
+ ### Other Providers
96
+
97
+ - **Cloudinary** - Image and video management platform
98
+
99
+ ## Configuration
100
+
101
+ ### AWS S3
102
+
103
+ ```typescript
104
+ const storage = new S3Service({
105
+ provider: "aws",
106
+ region: "us-east-1",
107
+ bucket: "my-bucket",
108
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
109
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
110
+ publicUrl: "https://cdn.example.com", // Optional CDN URL
111
+ });
112
+ ```
113
+
114
+ ### Cloudflare R2
115
+
116
+ ```typescript
117
+ const storage = new S3Service({
118
+ provider: "cloudflare-r2",
119
+ region: "auto",
120
+ bucket: "my-bucket",
121
+ accessKeyId: process.env.R2_ACCESS_KEY_ID,
122
+ secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
123
+ endpoint: "https://<account-id>.r2.cloudflarestorage.com",
124
+ });
125
+ ```
126
+
127
+ ### MinIO
128
+
129
+ ```typescript
130
+ const storage = new S3Service({
131
+ provider: "minio",
132
+ region: "us-east-1",
133
+ bucket: "my-bucket",
134
+ accessKeyId: "minioadmin",
135
+ secretAccessKey: "minioadmin",
136
+ endpoint: "http://localhost:9000",
137
+ forcePathStyle: true, // Required for MinIO
138
+ });
139
+ ```
140
+
141
+ ## Basic Usage
142
+
143
+ ### File Operations
144
+
145
+ ```typescript
146
+ // Upload with options
147
+ await storage.upload({
148
+ key: "uploads/document.pdf",
149
+ file: buffer,
150
+ contentType: "application/pdf",
151
+ metadata: { userId: "123", category: "documents" },
152
+ cacheControl: "max-age=31536000",
153
+ });
154
+
155
+ // Download file
156
+ const { content, metadata } = await storage.download({
157
+ key: "uploads/document.pdf",
158
+ });
159
+
160
+ // Check if file exists
161
+ const exists = await storage.exists("uploads/document.pdf");
162
+
163
+ // Delete file
164
+ await storage.delete({ key: "uploads/document.pdf" });
165
+
166
+ // Copy file
167
+ await storage.copy({
168
+ sourceKey: "uploads/old.pdf",
169
+ destinationKey: "uploads/new.pdf",
170
+ });
171
+
172
+ // Move file
173
+ await storage.move({
174
+ sourceKey: "uploads/temp.pdf",
175
+ destinationKey: "uploads/final.pdf",
176
+ });
177
+
178
+ // List files
179
+ const files = await storage.list({
180
+ prefix: "uploads/",
181
+ maxKeys: 100,
182
+ });
183
+ ```
184
+
185
+ ### Folder Operations
186
+
187
+ ```typescript
188
+ // Create folder
189
+ await storage.createFolder({ path: "documents/" });
190
+
191
+ // Delete folder (recursive)
192
+ await storage.deleteFolder({
193
+ path: "documents/",
194
+ recursive: true,
195
+ });
196
+
197
+ // List folders
198
+ const folders = await storage.listFolders({
199
+ prefix: "uploads/",
200
+ });
201
+
202
+ // Check if folder exists
203
+ const exists = await storage.folderExists("documents/");
204
+ ```
205
+
206
+ ### URL Generation
207
+
208
+ ```typescript
209
+ // Get public URL
210
+ const publicUrl = storage.getPublicUrl("images/photo.jpg");
211
+
212
+ // Generate presigned URL for download
213
+ const downloadUrl = await storage.getPresignedUrl({
214
+ key: "documents/private.pdf",
215
+ operation: "get",
216
+ expiresIn: 3600, // 1 hour
217
+ });
218
+
219
+ // Generate presigned URL for upload
220
+ const uploadUrl = await storage.getPresignedUrl({
221
+ key: "uploads/new-file.pdf",
222
+ operation: "put",
223
+ expiresIn: 900, // 15 minutes
224
+ contentType: "application/pdf",
225
+ });
226
+ ```
227
+
228
+ ## API Reference
229
+
230
+ ### File Operations
231
+
232
+ - `upload(options)` - Upload a file
233
+ - `download(options)` - Download a file
234
+ - `delete(options)` - Delete a file
235
+ - `exists(key)` - Check if file exists
236
+ - `copy(options)` - Copy a file
237
+ - `move(options)` - Move a file
238
+ - `list(options)` - List files with prefix
239
+ - `getPresignedUrl(options)` - Generate presigned URL
240
+ - `getPublicUrl(key)` - Get public URL
241
+
242
+ ### Folder Operations
243
+
244
+ - `createFolder(options)` - Create a folder
245
+ - `deleteFolder(options)` - Delete a folder
246
+ - `listFolders(options)` - List folders
247
+ - `folderExists(path)` - Check if folder exists
248
+
249
+ ## Runtime Compatibility
250
+
251
+ | Export | Node.js | Bun | CF Workers | Deno | Browser |
252
+ | -------------- | ------- | --- | ---------- | ---- | ------- |
253
+ | `.` (config) | Yes | Yes | Yes\* | Yes | Yes |
254
+ | `./helpers` | Yes | Yes | Yes | Yes | Yes |
255
+ | `./s3` | Yes | Yes | No | Yes | No |
256
+ | `./cloudinary` | Yes | Yes | No | Yes | No |
257
+
258
+ \* Pass env via `EnvRecord`: `loadS3Config(myEnv)`.
259
+
260
+ ### `EnvRecord` Pattern
261
+
262
+ All config functions accept an optional `env` parameter. On Node/Bun it defaults to `process.env`. On other runtimes, pass your environment explicitly:
263
+
264
+ ```typescript
265
+ import { loadS3Config, loadCloudinaryConfig, hasStorageConfig } from "@kumix/storage";
266
+
267
+ // Cloudflare Workers
268
+ const config = loadS3Config(ctx.env);
269
+
270
+ // Deno
271
+ const config = loadCloudinaryConfig(Deno.env.toObject());
272
+
273
+ // Manual config (works everywhere, no env needed)
274
+ const s3 = createS3({ provider: "aws", region: "us-east-1", ... });
275
+ const cloudinary = createCloudinary({ provider: "cloudinary", cloudName: "...", ... });
276
+ ```
277
+
278
+ > **Note**: `./s3` and `./cloudinary` subpaths require the AWS SDK or Cloudinary SDK
279
+ > peer dependencies respectively, which are Node.js packages. Use these subpaths only in
280
+ > Node.js, Bun, or Deno environments.
281
+
282
+ ## Links
283
+
284
+ - [npm Package](https://www.npmjs.com/package/@kumix/storage)
285
+ - [Contributing Guide](../../CONTRIBUTING.md)
286
+ - [Code of Conduct](../../CODE_OF_CONDUCT.md)
287
+ - [License](../../LICENSE)
288
+
289
+ ## License
290
+
291
+ MIT © [Kumix Labs](../../LICENSE)
@@ -0,0 +1,93 @@
1
+ import { A as DownloadOptions, B as PresignedUrlResult, C as RenameFolderResult, D as CopyResult, E as CopyOptions, F as ListOptions, H as UploadResult, I as ListResult, L as MoveOptions, M as DuplicateOptions, N as DuplicateResult, O as DeleteOptions, P as ExistsResult, R as MoveResult, S as RenameFolderOptions, T as BatchDeleteResult, U as CloudinaryConfig, V as UploadOptions, _ as DeleteFolderOptions, b as ListFoldersOptions, f as StorageInterface, g as CreateFolderResult, h as CreateFolderOptions, j as DownloadResult, k as DeleteResult, m as CopyFolderResult, n as EnvRecord, p as CopyFolderOptions, v as DeleteFolderResult, w as BatchDeleteOptions, x as ListFoldersResult, y as FolderExistsResult, z as PresignedUrlOptions } from "./config-J6AdDh_c.js";
2
+
3
+ //#region src/services/cloudinary.d.ts
4
+ /**
5
+ * Cloudinary storage service
6
+ * High-level service for Cloudinary storage operations with convenience methods
7
+ * @public
8
+ */
9
+ declare class CloudinaryService implements StorageInterface {
10
+ private provider;
11
+ private config;
12
+ constructor();
13
+ constructor(config: CloudinaryConfig);
14
+ getConfig(): CloudinaryConfig;
15
+ getProvider(): string;
16
+ getPublicUrl(key: string): string;
17
+ upload(options: UploadOptions): Promise<UploadResult>;
18
+ download(options: DownloadOptions): Promise<DownloadResult>;
19
+ delete(options: DeleteOptions): Promise<DeleteResult>;
20
+ batchDelete(options: BatchDeleteOptions): Promise<BatchDeleteResult>;
21
+ list(options?: ListOptions): Promise<ListResult>;
22
+ exists(key: string): Promise<ExistsResult>;
23
+ copy(options: CopyOptions): Promise<CopyResult>;
24
+ move(options: MoveOptions): Promise<MoveResult>;
25
+ duplicate(options: DuplicateOptions): Promise<DuplicateResult>;
26
+ getPresignedUrl(options: PresignedUrlOptions): Promise<PresignedUrlResult>;
27
+ createFolder(options: CreateFolderOptions): Promise<CreateFolderResult>;
28
+ deleteFolder(options: DeleteFolderOptions): Promise<DeleteFolderResult>;
29
+ listFolders(options?: ListFoldersOptions): Promise<ListFoldersResult>;
30
+ folderExists(path: string): Promise<FolderExistsResult>;
31
+ renameFolder(options: RenameFolderOptions): Promise<RenameFolderResult>;
32
+ copyFolder(options: CopyFolderOptions): Promise<CopyFolderResult>;
33
+ uploadFile(key: string, file: Buffer | Uint8Array | string, contentType?: string, metadata?: Record<string, string>): Promise<UploadResult>;
34
+ downloadFile(key: string): Promise<DownloadResult>;
35
+ deleteFile(key: string): Promise<DeleteResult>;
36
+ deleteFiles(keys: string[]): Promise<BatchDeleteResult>;
37
+ listFiles(prefix?: string, maxKeys?: number): Promise<ListResult>;
38
+ fileExists(key: string): Promise<boolean>;
39
+ copyFile(sourceKey: string, destinationKey: string, metadata?: Record<string, string>): Promise<CopyResult>;
40
+ moveFile(sourceKey: string, destinationKey: string, metadata?: Record<string, string>): Promise<MoveResult>;
41
+ duplicateFile(sourceKey: string, destinationKey: string, metadata?: Record<string, string>): Promise<DuplicateResult>;
42
+ renameFile(sourceKey: string, destinationKey: string, metadata?: Record<string, string>): Promise<MoveResult>;
43
+ getDownloadUrl(key: string, expiresIn?: number): Promise<PresignedUrlResult>;
44
+ getUploadUrl(key: string, contentType?: string, expiresIn?: number): Promise<PresignedUrlResult>;
45
+ createFolderPath(path: string): Promise<CreateFolderResult>;
46
+ deleteFolderPath(path: string, recursive?: boolean): Promise<DeleteFolderResult>;
47
+ folderPathExists(path: string): Promise<boolean>;
48
+ renameFolderPath(oldPath: string, newPath: string): Promise<RenameFolderResult>;
49
+ copyFolderPath(sourcePath: string, destinationPath: string, recursive?: boolean): Promise<CopyFolderResult>;
50
+ }
51
+ //#endregion
52
+ //#region src/cloudinary.d.ts
53
+ /**
54
+ * Create Cloudinary service using environment variables or manual configuration
55
+ * @param config Optional Cloudinary configuration. If not provided, loads from environment variables
56
+ * @param env - Optional environment record
57
+ * @returns CloudinaryService instance
58
+ * @throws Error if configuration is invalid or environment variables are missing
59
+ * @public
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * import { createCloudinary } from '@kumix/storage/cloudinary';
64
+ *
65
+ * // Using environment variables
66
+ * // Set: KUMIX_CLOUDINARY_CLOUD_NAME=my-cloud, KUMIX_CLOUDINARY_API_KEY=123..., etc.
67
+ * const cloudinaryFromEnv = createCloudinary();
68
+ * await cloudinaryFromEnv.uploadFile('photo.jpg', imageBuffer);
69
+ *
70
+ * // Using manual configuration
71
+ * const cloudinary = createCloudinary({
72
+ * provider: 'cloudinary',
73
+ * cloudName: 'my-cloud-name',
74
+ * apiKey: '123456789012345',
75
+ * apiSecret: 'your-api-secret',
76
+ * secure: true,
77
+ * folder: 'uploads'
78
+ * });
79
+ *
80
+ * // Upload with transformations
81
+ * await cloudinary.uploadFile('profile-pic.jpg', imageBuffer);
82
+ *
83
+ * // Get optimized URL
84
+ * const publicUrl = cloudinary.getPublicUrl('profile-pic.jpg');
85
+ * console.log(publicUrl); // Cloudinary optimized URL
86
+ * ```
87
+ */
88
+ declare function createCloudinary(): CloudinaryService;
89
+ declare function createCloudinary(config: CloudinaryConfig): CloudinaryService;
90
+ declare function createCloudinary(config: CloudinaryConfig, env: EnvRecord): CloudinaryService;
91
+ //#endregion
92
+ export { CloudinaryService, createCloudinary };
93
+ //# sourceMappingURL=cloudinary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudinary.d.ts","names":[],"sources":["../src/services/cloudinary.ts","../src/cloudinary.ts"],"mappings":"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"}