@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.
@@ -0,0 +1,516 @@
1
+ import { o as loadCloudinaryConfig } from "./config-t-NVJICl.js";
2
+ import { v2 } from "cloudinary";
3
+ //#region src/providers/cloudinary.ts
4
+ /**
5
+ * Cloudinary storage provider implementation
6
+ * Provides cloud storage operations using Cloudinary's API for media management
7
+ */
8
+ /**
9
+ * Cloudinary storage provider
10
+ * Implements StorageInterface for Cloudinary cloud storage
11
+ * @internal
12
+ */
13
+ var CloudinaryProvider = class {
14
+ config;
15
+ constructor(config) {
16
+ this.config = config;
17
+ v2.config({
18
+ cloud_name: config.cloudName,
19
+ api_key: config.apiKey,
20
+ api_secret: config.apiSecret,
21
+ secure: config.secure !== false
22
+ });
23
+ }
24
+ async upload(options) {
25
+ try {
26
+ let fileData;
27
+ if (typeof options.file === "string") fileData = options.file;
28
+ else fileData = `data:${options.contentType || "application/octet-stream"};base64,${Buffer.from(options.file).toString("base64")}`;
29
+ let resourceType = "raw";
30
+ if (options.contentType?.startsWith("image/")) resourceType = "image";
31
+ else if (options.contentType?.startsWith("video/")) resourceType = "video";
32
+ const keyParts = options.key.split("/");
33
+ let folder = "";
34
+ let publicId = keyParts[keyParts.length - 1];
35
+ if (keyParts.length > 1) folder = keyParts.slice(0, -1).join("/");
36
+ const dotIndex = publicId.lastIndexOf(".");
37
+ if (dotIndex > 0) publicId = publicId.slice(0, dotIndex);
38
+ const uploadOptions = {
39
+ public_id: publicId,
40
+ resource_type: resourceType,
41
+ overwrite: true,
42
+ invalidate: true,
43
+ ...options.metadata
44
+ };
45
+ if (folder) uploadOptions.folder = folder;
46
+ if (this.config.folder) uploadOptions.folder = `${this.config.folder}/${folder}`;
47
+ const result = await v2.uploader.upload(fileData, uploadOptions);
48
+ const publicUrl = this.getPublicUrl(result.public_id, result.format);
49
+ return {
50
+ success: true,
51
+ key: result.public_id,
52
+ url: result.secure_url,
53
+ publicUrl,
54
+ etag: result.etag,
55
+ size: result.bytes
56
+ };
57
+ } catch (error) {
58
+ return {
59
+ success: false,
60
+ error: error instanceof Error ? error.message : "Upload failed"
61
+ };
62
+ }
63
+ }
64
+ async download(options) {
65
+ try {
66
+ const publicUrl = this.getPublicUrl(options.key);
67
+ const response = await fetch(publicUrl);
68
+ if (!response.ok) return {
69
+ success: false,
70
+ error: `Failed to download: ${response.status} ${response.statusText}`
71
+ };
72
+ const arrayBuffer = await response.arrayBuffer();
73
+ const content = Buffer.from(arrayBuffer);
74
+ return {
75
+ success: true,
76
+ content,
77
+ data: content,
78
+ contentType: response.headers.get("content-type") || void 0,
79
+ contentLength: content.length,
80
+ lastModified: response.headers.get("last-modified") ? new Date(response.headers.get("last-modified")) : /* @__PURE__ */ new Date()
81
+ };
82
+ } catch (error) {
83
+ return {
84
+ success: false,
85
+ error: error instanceof Error ? error.message : "Download failed"
86
+ };
87
+ }
88
+ }
89
+ async delete(options) {
90
+ try {
91
+ const keyParts = options.key.split("/");
92
+ let publicId = options.key;
93
+ if (keyParts.length > 1) publicId = `${keyParts.slice(0, -1).join("/")}/${keyParts[keyParts.length - 1]}`;
94
+ const dotIndex = publicId.lastIndexOf(".");
95
+ if (dotIndex > 0) publicId = publicId.slice(0, dotIndex);
96
+ if (this.config.folder) publicId = `${this.config.folder}/${publicId}`;
97
+ let resourceType = "raw";
98
+ try {
99
+ await v2.api.resource(publicId, { resource_type: "image" });
100
+ resourceType = "image";
101
+ } catch {
102
+ try {
103
+ await v2.api.resource(publicId, { resource_type: "video" });
104
+ resourceType = "video";
105
+ } catch {
106
+ resourceType = "raw";
107
+ }
108
+ }
109
+ await v2.uploader.destroy(publicId, {
110
+ resource_type: resourceType,
111
+ invalidate: true
112
+ });
113
+ return { success: true };
114
+ } catch (error) {
115
+ return {
116
+ success: false,
117
+ error: error instanceof Error ? error.message : "Delete failed"
118
+ };
119
+ }
120
+ }
121
+ async batchDelete(options) {
122
+ try {
123
+ return {
124
+ success: false,
125
+ errors: options.keys.map((key) => ({
126
+ key,
127
+ error: "Cloudinary batch delete not implemented yet"
128
+ }))
129
+ };
130
+ } catch (error) {
131
+ return {
132
+ success: false,
133
+ errors: options.keys.map((key) => ({
134
+ key,
135
+ error: error instanceof Error ? error.message : "Batch delete failed"
136
+ }))
137
+ };
138
+ }
139
+ }
140
+ async list(options = {}) {
141
+ try {
142
+ const prefix = options.prefix || "";
143
+ const maxResults = options.maxKeys || 50;
144
+ const [images, videos, rawFiles] = await Promise.all([
145
+ v2.api.resources({
146
+ type: "upload",
147
+ resource_type: "image",
148
+ prefix,
149
+ max_results: maxResults,
150
+ next_cursor: options.continuationToken
151
+ }).catch(() => ({
152
+ resources: [],
153
+ next_cursor: void 0
154
+ })),
155
+ v2.api.resources({
156
+ type: "upload",
157
+ resource_type: "video",
158
+ prefix,
159
+ max_results: maxResults,
160
+ next_cursor: options.continuationToken
161
+ }).catch(() => ({
162
+ resources: [],
163
+ next_cursor: void 0
164
+ })),
165
+ v2.api.resources({
166
+ type: "upload",
167
+ resource_type: "raw",
168
+ prefix,
169
+ max_results: maxResults,
170
+ next_cursor: options.continuationToken
171
+ }).catch(() => ({
172
+ resources: [],
173
+ next_cursor: void 0
174
+ }))
175
+ ]);
176
+ return {
177
+ success: true,
178
+ files: [
179
+ ...images.resources || [],
180
+ ...videos.resources || [],
181
+ ...rawFiles.resources || []
182
+ ].map((resource) => ({
183
+ key: String(resource.public_id || ""),
184
+ size: Number(resource.bytes) || 0,
185
+ lastModified: new Date(String(resource.created_at || /* @__PURE__ */ new Date())),
186
+ etag: String(resource.etag || ""),
187
+ contentType: resource.format ? `${resource.resource_type}/${resource.format}` : "application/octet-stream"
188
+ })),
189
+ isTruncated: !!(images.next_cursor || videos.next_cursor || rawFiles.next_cursor),
190
+ nextContinuationToken: images.next_cursor || videos.next_cursor || rawFiles.next_cursor
191
+ };
192
+ } catch (error) {
193
+ return {
194
+ success: false,
195
+ error: error instanceof Error ? error.message : "List failed"
196
+ };
197
+ }
198
+ }
199
+ async exists(_key) {
200
+ try {
201
+ return {
202
+ exists: false,
203
+ error: "Cloudinary exists check not implemented yet"
204
+ };
205
+ } catch (error) {
206
+ return {
207
+ exists: false,
208
+ error: error instanceof Error ? error.message : "Check existence failed"
209
+ };
210
+ }
211
+ }
212
+ async copy(_options) {
213
+ try {
214
+ return {
215
+ success: false,
216
+ error: "Cloudinary copy not implemented yet"
217
+ };
218
+ } catch (error) {
219
+ return {
220
+ success: false,
221
+ error: error instanceof Error ? error.message : "Copy failed"
222
+ };
223
+ }
224
+ }
225
+ async move(_options) {
226
+ try {
227
+ return {
228
+ success: false,
229
+ error: "Cloudinary move not implemented yet"
230
+ };
231
+ } catch (error) {
232
+ return {
233
+ success: false,
234
+ error: error instanceof Error ? error.message : "Move failed"
235
+ };
236
+ }
237
+ }
238
+ async duplicate(options) {
239
+ return this.copy(options);
240
+ }
241
+ async getPresignedUrl(_options) {
242
+ try {
243
+ return {
244
+ success: false,
245
+ error: "Cloudinary presigned URL not implemented yet"
246
+ };
247
+ } catch (error) {
248
+ return {
249
+ success: false,
250
+ error: error instanceof Error ? error.message : "Presigned URL generation failed"
251
+ };
252
+ }
253
+ }
254
+ getPublicUrl(key, extension) {
255
+ return `${`${this.config.secure !== false ? "https" : "http"}://res.cloudinary.com/${this.config.cloudName}`}/image/upload/${key}${extension ? `.${extension}` : ""}`;
256
+ }
257
+ async createFolder(options) {
258
+ try {
259
+ return {
260
+ success: true,
261
+ path: options.path
262
+ };
263
+ } catch (error) {
264
+ return {
265
+ success: false,
266
+ error: error instanceof Error ? error.message : "Create folder failed"
267
+ };
268
+ }
269
+ }
270
+ async deleteFolder(options) {
271
+ try {
272
+ const folderPath = options.path.endsWith("/") ? options.path.slice(0, -1) : options.path;
273
+ if (options.recursive) await v2.api.delete_resources_by_prefix(folderPath);
274
+ await v2.api.delete_folder(folderPath);
275
+ return { success: true };
276
+ } catch (error) {
277
+ return {
278
+ success: false,
279
+ error: error instanceof Error ? error.message : "Delete folder failed"
280
+ };
281
+ }
282
+ }
283
+ async listFolders(_options) {
284
+ try {
285
+ return {
286
+ success: true,
287
+ folders: ((await v2.api.root_folders()).folders || []).map((folder) => ({
288
+ name: folder.name,
289
+ path: folder.path
290
+ })),
291
+ isTruncated: false,
292
+ nextContinuationToken: void 0
293
+ };
294
+ } catch (error) {
295
+ return {
296
+ success: false,
297
+ error: error instanceof Error ? error.message : "List folders failed"
298
+ };
299
+ }
300
+ }
301
+ async folderExists(_path) {
302
+ try {
303
+ return {
304
+ exists: false,
305
+ error: "Cloudinary folder exists check not implemented yet"
306
+ };
307
+ } catch (error) {
308
+ return {
309
+ exists: false,
310
+ error: error instanceof Error ? error.message : "Check folder existence failed"
311
+ };
312
+ }
313
+ }
314
+ async renameFolder(_options) {
315
+ try {
316
+ return {
317
+ success: false,
318
+ error: "Cloudinary rename folder not implemented yet"
319
+ };
320
+ } catch (error) {
321
+ return {
322
+ success: false,
323
+ error: error instanceof Error ? error.message : "Rename folder failed"
324
+ };
325
+ }
326
+ }
327
+ async copyFolder(_options) {
328
+ try {
329
+ return {
330
+ success: false,
331
+ error: "Cloudinary copy folder not implemented yet"
332
+ };
333
+ } catch (error) {
334
+ return {
335
+ success: false,
336
+ error: error instanceof Error ? error.message : "Copy folder failed"
337
+ };
338
+ }
339
+ }
340
+ };
341
+ //#endregion
342
+ //#region src/services/cloudinary.ts
343
+ /**
344
+ * Cloudinary storage service implementation
345
+ * High-level service wrapper for Cloudinary storage operations with convenience methods
346
+ */
347
+ /**
348
+ * Cloudinary storage service
349
+ * High-level service for Cloudinary storage operations with convenience methods
350
+ * @public
351
+ */
352
+ var CloudinaryService = class {
353
+ provider;
354
+ config;
355
+ constructor(config) {
356
+ this.config = config || loadCloudinaryConfig();
357
+ this.provider = new CloudinaryProvider(this.config);
358
+ }
359
+ getConfig() {
360
+ return { ...this.config };
361
+ }
362
+ getProvider() {
363
+ return this.config.provider;
364
+ }
365
+ getPublicUrl(key) {
366
+ return this.provider.getPublicUrl(key);
367
+ }
368
+ async upload(options) {
369
+ return this.provider.upload(options);
370
+ }
371
+ async download(options) {
372
+ return this.provider.download(options);
373
+ }
374
+ async delete(options) {
375
+ return this.provider.delete(options);
376
+ }
377
+ async batchDelete(options) {
378
+ return this.provider.batchDelete(options);
379
+ }
380
+ async list(options) {
381
+ return this.provider.list(options);
382
+ }
383
+ async exists(key) {
384
+ return this.provider.exists(key);
385
+ }
386
+ async copy(options) {
387
+ return this.provider.copy(options);
388
+ }
389
+ async move(options) {
390
+ return this.provider.move(options);
391
+ }
392
+ async duplicate(options) {
393
+ return this.provider.duplicate(options);
394
+ }
395
+ async getPresignedUrl(options) {
396
+ return this.provider.getPresignedUrl(options);
397
+ }
398
+ async createFolder(options) {
399
+ return this.provider.createFolder(options);
400
+ }
401
+ async deleteFolder(options) {
402
+ return this.provider.deleteFolder(options);
403
+ }
404
+ async listFolders(options) {
405
+ return this.provider.listFolders(options);
406
+ }
407
+ async folderExists(path) {
408
+ return this.provider.folderExists(path);
409
+ }
410
+ async renameFolder(options) {
411
+ return this.provider.renameFolder(options);
412
+ }
413
+ async copyFolder(options) {
414
+ return this.provider.copyFolder(options);
415
+ }
416
+ async uploadFile(key, file, contentType, metadata) {
417
+ return this.upload({
418
+ key,
419
+ file,
420
+ contentType,
421
+ metadata
422
+ });
423
+ }
424
+ async downloadFile(key) {
425
+ return this.download({ key });
426
+ }
427
+ async deleteFile(key) {
428
+ return this.delete({ key });
429
+ }
430
+ async deleteFiles(keys) {
431
+ return this.batchDelete({ keys });
432
+ }
433
+ async listFiles(prefix, maxKeys) {
434
+ return this.list({
435
+ prefix,
436
+ maxKeys
437
+ });
438
+ }
439
+ async fileExists(key) {
440
+ return (await this.exists(key)).exists;
441
+ }
442
+ async copyFile(sourceKey, destinationKey, metadata) {
443
+ return this.copy({
444
+ sourceKey,
445
+ destinationKey,
446
+ metadata
447
+ });
448
+ }
449
+ async moveFile(sourceKey, destinationKey, metadata) {
450
+ return this.move({
451
+ sourceKey,
452
+ destinationKey,
453
+ metadata
454
+ });
455
+ }
456
+ async duplicateFile(sourceKey, destinationKey, metadata) {
457
+ return this.duplicate({
458
+ sourceKey,
459
+ destinationKey,
460
+ metadata
461
+ });
462
+ }
463
+ async renameFile(sourceKey, destinationKey, metadata) {
464
+ return this.moveFile(sourceKey, destinationKey, metadata);
465
+ }
466
+ async getDownloadUrl(key, expiresIn) {
467
+ return this.getPresignedUrl({
468
+ key,
469
+ operation: "get",
470
+ expiresIn
471
+ });
472
+ }
473
+ async getUploadUrl(key, contentType, expiresIn) {
474
+ return this.getPresignedUrl({
475
+ key,
476
+ operation: "put",
477
+ contentType,
478
+ expiresIn
479
+ });
480
+ }
481
+ async createFolderPath(path) {
482
+ return this.createFolder({ path });
483
+ }
484
+ async deleteFolderPath(path, recursive = false) {
485
+ return this.deleteFolder({
486
+ path,
487
+ recursive
488
+ });
489
+ }
490
+ async folderPathExists(path) {
491
+ return (await this.folderExists(path)).exists;
492
+ }
493
+ async renameFolderPath(oldPath, newPath) {
494
+ return this.renameFolder({
495
+ oldPath,
496
+ newPath
497
+ });
498
+ }
499
+ async copyFolderPath(sourcePath, destinationPath, recursive = true) {
500
+ return this.copyFolder({
501
+ sourcePath,
502
+ destinationPath,
503
+ recursive
504
+ });
505
+ }
506
+ };
507
+ //#endregion
508
+ //#region src/cloudinary.ts
509
+ function createCloudinary(config, env) {
510
+ if (config) return new CloudinaryService(config);
511
+ return new CloudinaryService(loadCloudinaryConfig(env));
512
+ }
513
+ //#endregion
514
+ export { CloudinaryService, createCloudinary };
515
+
516
+ //# sourceMappingURL=cloudinary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudinary.js","names":["cloudinary","publicId"],"sources":["../src/providers/cloudinary.ts","../src/services/cloudinary.ts","../src/cloudinary.ts"],"sourcesContent":["/**\n * Cloudinary storage provider implementation\n * Provides cloud storage operations using Cloudinary's API for media management\n */\n\nimport { v2 as cloudinary } from \"cloudinary\";\n\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CloudinaryConfig,\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 StorageInterface,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * Cloudinary storage provider\n * Implements StorageInterface for Cloudinary cloud storage\n * @internal\n */\nexport class CloudinaryProvider implements StorageInterface {\n private config: CloudinaryConfig;\n\n constructor(config: CloudinaryConfig) {\n this.config = config;\n\n // Configure Cloudinary\n cloudinary.config({\n cloud_name: config.cloudName,\n api_key: config.apiKey,\n api_secret: config.apiSecret,\n secure: config.secure !== false,\n });\n }\n\n // File operations\n async upload(options: UploadOptions): Promise<UploadResult> {\n try {\n // Convert Buffer/Uint8Array to base64 for Cloudinary\n let fileData: string;\n if (typeof options.file === \"string\") {\n fileData = options.file;\n } else {\n fileData = `data:${options.contentType || \"application/octet-stream\"};base64,${Buffer.from(options.file).toString(\"base64\")}`;\n }\n\n // Determine resource type based on content type\n let resourceType: \"image\" | \"video\" | \"raw\" = \"raw\";\n if (options.contentType?.startsWith(\"image/\")) {\n resourceType = \"image\";\n } else if (options.contentType?.startsWith(\"video/\")) {\n resourceType = \"video\";\n }\n\n // Extract folder and filename from key for Cloudinary folder support\n const keyParts = options.key.split(\"/\");\n let folder = \"\";\n let publicId = keyParts[keyParts.length - 1];\n\n if (keyParts.length > 1) {\n folder = keyParts.slice(0, -1).join(\"/\");\n }\n\n const dotIndex = publicId.lastIndexOf(\".\");\n if (dotIndex > 0) {\n publicId = publicId.slice(0, dotIndex);\n }\n\n const uploadOptions: Record<string, unknown> = {\n public_id: publicId,\n resource_type: resourceType,\n overwrite: true,\n invalidate: true,\n ...options.metadata,\n };\n\n // Add folder if extracted from key\n if (folder) {\n uploadOptions.folder = folder;\n }\n\n // Add folder if enabled in config\n if (this.config.folder) {\n uploadOptions.folder = `${this.config.folder}/${folder}`;\n }\n\n const result = await cloudinary.uploader.upload(fileData, uploadOptions);\n\n // Sample result structure\n // {\n // asset_id: 'b4033628c0897843e61e362167f338d6',\n // public_id: 'starter/workspaces/logo/ws_1KBQ2V0VRKK5EN936G8S2XZ30',\n // version: 1765965394,\n // version_id: 'abd49804c49061cef406f8d703466849',\n // signature: 'ff52169a483bada7ca4943ce322132137bec4d2f',\n // width: 256,\n // height: 256,\n // format: 'png',\n // resource_type: 'image',\n // created_at: '2025-12-17T09:52:12Z',\n // tags: [],\n // bytes: 76429,\n // type: 'upload',\n // etag: '85e34db0ea9ce8e771e25bd8eb33ba56',\n // placeholder: false,\n // url: 'http://res.cloudinary.com/droen5ejq/image/upload/v1765965394/starter/workspaces/logo/ws_1KBQ2V0VRKK5EN936G8S2XZ30.png',\n // secure_url: 'https://res.cloudinary.com/droen5ejq/image/upload/v1765965394/starter/workspaces/logo/ws_1KBQ2V0VRKK5EN936G8S2XZ30.png',\n // asset_folder: 'starter/workspaces/logo',\n // display_name: 'ws_1KBQ2V0VRKK5EN936G8S2XZ30',\n // overwritten: true,\n // api_key: '255239588173378'\n // }\n\n const publicUrl = this.getPublicUrl(result.public_id, result.format);\n\n return {\n success: true,\n key: result.public_id,\n url: result.secure_url,\n publicUrl,\n etag: result.etag,\n size: result.bytes,\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 // Cloudinary doesn't support direct download like S3\n // We need to fetch from the public URL\n const publicUrl = this.getPublicUrl(options.key);\n\n const response = await fetch(publicUrl);\n if (!response.ok) {\n return {\n success: false,\n error: `Failed to download: ${response.status} ${response.statusText}`,\n };\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const content = Buffer.from(arrayBuffer);\n\n return {\n success: true,\n content, // Main content field\n data: content, // Alias for backward compatibility\n contentType: response.headers.get(\"content-type\") || undefined,\n contentLength: content.length,\n lastModified: response.headers.get(\"last-modified\")\n ? new Date(response.headers.get(\"last-modified\")!)\n : new Date(),\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 // Extract folder and filename for proper deletion\n const keyParts = options.key.split(\"/\");\n let publicId = options.key;\n\n if (keyParts.length > 1) {\n const folder = keyParts.slice(0, -1).join(\"/\");\n const filename = keyParts[keyParts.length - 1];\n publicId = `${folder}/${filename}`;\n }\n\n const dotIndex = publicId.lastIndexOf(\".\");\n if (dotIndex > 0) {\n publicId = publicId.slice(0, dotIndex);\n }\n\n // Add folder if enabled in config\n if (this.config.folder) {\n publicId = `${this.config.folder}/${publicId}`;\n }\n\n // Determine resource type from key/path\n let resourceType: \"image\" | \"video\" | \"raw\" = \"raw\";\n\n // Try to get resource info first to determine type\n try {\n await cloudinary.api.resource(publicId, { resource_type: \"image\" });\n resourceType = \"image\";\n } catch {\n try {\n await cloudinary.api.resource(publicId, { resource_type: \"video\" });\n resourceType = \"video\";\n } catch {\n resourceType = \"raw\";\n }\n }\n\n await cloudinary.uploader.destroy(publicId, {\n resource_type: resourceType,\n invalidate: true,\n });\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 // Use Cloudinary Admin API for batch delete\n return {\n success: false,\n errors: options.keys.map((key) => ({\n key,\n error: \"Cloudinary batch delete not implemented yet\",\n })),\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 prefix = options.prefix || \"\";\n const maxResults = options.maxKeys || 50;\n\n // List all resource types\n const [images, videos, rawFiles] = await Promise.all([\n cloudinary.api\n .resources({\n type: \"upload\",\n resource_type: \"image\",\n prefix,\n max_results: maxResults,\n next_cursor: options.continuationToken,\n })\n .catch(() => ({ resources: [], next_cursor: undefined })),\n\n cloudinary.api\n .resources({\n type: \"upload\",\n resource_type: \"video\",\n prefix,\n max_results: maxResults,\n next_cursor: options.continuationToken,\n })\n .catch(() => ({ resources: [], next_cursor: undefined })),\n\n cloudinary.api\n .resources({\n type: \"upload\",\n resource_type: \"raw\",\n prefix,\n max_results: maxResults,\n next_cursor: options.continuationToken,\n })\n .catch(() => ({ resources: [], next_cursor: undefined })),\n ]);\n\n const allResources = [\n ...(images.resources || []),\n ...(videos.resources || []),\n ...(rawFiles.resources || []),\n ];\n\n const files = allResources.map((resource: Record<string, unknown>) => ({\n key: String(resource.public_id || \"\"),\n size: Number(resource.bytes) || 0,\n lastModified: new Date(String(resource.created_at || new Date())),\n etag: String(resource.etag || \"\"),\n contentType: resource.format\n ? `${resource.resource_type}/${resource.format}`\n : \"application/octet-stream\",\n }));\n\n return {\n success: true,\n files,\n isTruncated: !!(images.next_cursor || videos.next_cursor || rawFiles.next_cursor),\n nextContinuationToken: images.next_cursor || videos.next_cursor || rawFiles.next_cursor,\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 // Use Cloudinary Admin API to check if resource exists\n return {\n exists: false,\n error: \"Cloudinary exists check not implemented yet\",\n };\n } catch (error) {\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 // Cloudinary doesn't have direct copy, would need to download and re-upload\n return {\n success: false,\n error: \"Cloudinary copy not implemented yet\",\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 // Use Cloudinary Admin API to rename/move\n return {\n success: false,\n error: \"Cloudinary move not implemented yet\",\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 // Cloudinary uses different approach - signed URLs\n return {\n success: false,\n error: \"Cloudinary presigned URL not implemented yet\",\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, extension?: string): string {\n // Generate Cloudinary URL\n const protocol = this.config.secure !== false ? \"https\" : \"http\";\n const baseUrl = `${protocol}://res.cloudinary.com/${this.config.cloudName}`;\n\n // Use key directly as public ID - folder structure comes from the key itself\n const publicId = key;\n\n // For images: /image/upload/v1234567890/sample.jpg\n // For videos: /video/upload/v1234567890/sample.mp4\n // For raw files: /raw/upload/v1234567890/sample.pdf\n\n // Default to image for now, in real implementation you'd detect file type\n return `${baseUrl}/image/upload/${publicId}${extension ? `.${extension}` : \"\"}`;\n }\n\n // Folder operations\n async createFolder(options: CreateFolderOptions): Promise<CreateFolderResult> {\n try {\n // Cloudinary folders are created implicitly when uploading files\n return {\n success: true,\n path: options.path,\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 // Cloudinary requires deleting all assets in folder first\n // Then delete the folder itself\n const folderPath = options.path.endsWith(\"/\") ? options.path.slice(0, -1) : options.path;\n\n if (options.recursive) {\n // Delete all resources in the folder\n await cloudinary.api.delete_resources_by_prefix(folderPath);\n }\n\n // Delete the folder\n await cloudinary.api.delete_folder(folderPath);\n\n return {\n success: true,\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 // Use Cloudinary Admin API to list folders\n const result = await cloudinary.api.root_folders();\n\n const folders = (result.folders || []).map((folder: Record<string, unknown>) => ({\n name: folder.name,\n path: folder.path,\n }));\n\n return {\n success: true,\n folders,\n isTruncated: false,\n nextContinuationToken: undefined,\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 // Check if folder exists in Cloudinary\n return {\n exists: false,\n error: \"Cloudinary folder exists check not implemented yet\",\n };\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 // Cloudinary folder rename would require moving all assets\n return {\n success: false,\n error: \"Cloudinary rename folder not implemented yet\",\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 // Cloudinary folder copy would require copying all assets\n return {\n success: false,\n error: \"Cloudinary copy folder not implemented yet\",\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 * Cloudinary storage service implementation\n * High-level service wrapper for Cloudinary storage operations with convenience methods\n */\n\nimport { loadCloudinaryConfig } from \"../config\";\nimport { CloudinaryProvider } from \"../providers/cloudinary\";\nimport type {\n BatchDeleteOptions,\n BatchDeleteResult,\n CloudinaryConfig,\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 StorageInterface,\n UploadOptions,\n UploadResult,\n} from \"../types\";\n\n/**\n * Cloudinary storage service\n * High-level service for Cloudinary storage operations with convenience methods\n * @public\n */\nexport class CloudinaryService implements StorageInterface {\n private provider: CloudinaryProvider;\n private config: CloudinaryConfig;\n\n constructor();\n constructor(config: CloudinaryConfig);\n constructor(config?: CloudinaryConfig) {\n this.config = config || loadCloudinaryConfig();\n this.provider = new CloudinaryProvider(this.config);\n }\n\n // Utility methods\n getConfig(): CloudinaryConfig {\n return { ...this.config };\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 contentType?: string,\n metadata?: Record<string, string>,\n ): Promise<UploadResult> {\n return this.upload({ key, file, contentType, metadata });\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 metadata?: Record<string, string>,\n ): Promise<CopyResult> {\n return this.copy({ sourceKey, destinationKey, metadata });\n }\n\n async moveFile(\n sourceKey: string,\n destinationKey: string,\n metadata?: Record<string, string>,\n ): Promise<MoveResult> {\n return this.move({ sourceKey, destinationKey, metadata });\n }\n\n async duplicateFile(\n sourceKey: string,\n destinationKey: string,\n metadata?: Record<string, string>,\n ): Promise<DuplicateResult> {\n return this.duplicate({ sourceKey, destinationKey, metadata });\n }\n\n async renameFile(\n sourceKey: string,\n destinationKey: string,\n metadata?: Record<string, string>,\n ): Promise<MoveResult> {\n return this.moveFile(sourceKey, destinationKey, metadata);\n }\n\n async getDownloadUrl(key: string, expiresIn?: number): Promise<PresignedUrlResult> {\n return this.getPresignedUrl({ key, operation: \"get\", expiresIn });\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 { loadCloudinaryConfig } from \"./config\";\nimport { CloudinaryService } from \"./services/cloudinary\";\nimport type { CloudinaryConfig } from \"./types\";\n\n// === SERVICE CLASSES ===\nexport { CloudinaryService } from \"./services/cloudinary\";\n\n// === MAIN FACTORY FUNCTIONS (Primary API) ===\n/**\n * Create Cloudinary service using environment variables or manual configuration\n * @param config Optional Cloudinary configuration. If not provided, loads from environment variables\n * @param env - Optional environment record\n * @returns CloudinaryService instance\n * @throws Error if configuration is invalid or environment variables are missing\n * @public\n *\n * @example\n * ```typescript\n * import { createCloudinary } from '@kumix/storage/cloudinary';\n *\n * // Using environment variables\n * // Set: KUMIX_CLOUDINARY_CLOUD_NAME=my-cloud, KUMIX_CLOUDINARY_API_KEY=123..., etc.\n * const cloudinaryFromEnv = createCloudinary();\n * await cloudinaryFromEnv.uploadFile('photo.jpg', imageBuffer);\n *\n * // Using manual configuration\n * const cloudinary = createCloudinary({\n * provider: 'cloudinary',\n * cloudName: 'my-cloud-name',\n * apiKey: '123456789012345',\n * apiSecret: 'your-api-secret',\n * secure: true,\n * folder: 'uploads'\n * });\n *\n * // Upload with transformations\n * await cloudinary.uploadFile('profile-pic.jpg', imageBuffer);\n *\n * // Get optimized URL\n * const publicUrl = cloudinary.getPublicUrl('profile-pic.jpg');\n * console.log(publicUrl); // Cloudinary optimized URL\n * ```\n */\nexport function createCloudinary(): CloudinaryService;\nexport function createCloudinary(config: CloudinaryConfig): CloudinaryService;\nexport function createCloudinary(config: CloudinaryConfig, env: EnvRecord): CloudinaryService;\nexport function createCloudinary(config?: CloudinaryConfig, env?: EnvRecord): CloudinaryService {\n if (config) {\n return new CloudinaryService(config);\n }\n const envConfig = loadCloudinaryConfig(env);\n return new CloudinaryService(envConfig);\n}\n"],"mappings":"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"}