@sanvika/cloudinary 0.1.1 → 0.1.3
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/client.js +139 -0
- package/dist/index.js +15 -80
- package/package.json +9 -4
package/dist/client.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/SanvikaCloudinaryProvider.jsx
|
|
4
|
+
import { createContext, useContext, useMemo } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
var SanvikaCloudinaryContext = createContext(null);
|
|
7
|
+
function SanvikaCloudinaryProvider({ appName, cloudName, uploadPreset = "ml_default", children }) {
|
|
8
|
+
const value = useMemo(
|
|
9
|
+
() => ({ appName, cloudName, uploadPreset }),
|
|
10
|
+
[appName, cloudName, uploadPreset]
|
|
11
|
+
);
|
|
12
|
+
return /* @__PURE__ */ jsx(SanvikaCloudinaryContext.Provider, { value, children });
|
|
13
|
+
}
|
|
14
|
+
function useSanvikaCloudinary() {
|
|
15
|
+
const ctx = useContext(SanvikaCloudinaryContext);
|
|
16
|
+
if (!ctx) {
|
|
17
|
+
throw new Error("useSanvikaCloudinary must be used within a SanvikaCloudinaryProvider");
|
|
18
|
+
}
|
|
19
|
+
return ctx;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/useCloudinaryUpload.js
|
|
23
|
+
import { useState, useCallback } from "react";
|
|
24
|
+
function useCloudinaryUpload(options = {}) {
|
|
25
|
+
const { folder, resourceType = "image", onProgress } = options;
|
|
26
|
+
const { appName, cloudName, uploadPreset } = useSanvikaCloudinary();
|
|
27
|
+
const [uploading, setUploading] = useState(false);
|
|
28
|
+
const [error, setError] = useState(null);
|
|
29
|
+
const reset = useCallback(() => {
|
|
30
|
+
setError(null);
|
|
31
|
+
setUploading(false);
|
|
32
|
+
}, []);
|
|
33
|
+
const upload = useCallback(
|
|
34
|
+
async (file) => {
|
|
35
|
+
setError(null);
|
|
36
|
+
setUploading(true);
|
|
37
|
+
try {
|
|
38
|
+
const folderPath = folder ? `${appName}/${folder}` : appName;
|
|
39
|
+
const formData = new FormData();
|
|
40
|
+
formData.append("file", file);
|
|
41
|
+
formData.append("upload_preset", uploadPreset);
|
|
42
|
+
formData.append("folder", folderPath);
|
|
43
|
+
const xhr = new XMLHttpRequest();
|
|
44
|
+
const url = `https://api.cloudinary.com/v1_1/${cloudName}/${resourceType}/upload`;
|
|
45
|
+
const result = await new Promise((resolve, reject) => {
|
|
46
|
+
xhr.open("POST", url);
|
|
47
|
+
if (onProgress) {
|
|
48
|
+
xhr.upload.onprogress = (e) => {
|
|
49
|
+
if (e.lengthComputable) onProgress(Math.round(e.loaded / e.total * 100));
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
xhr.onload = () => {
|
|
53
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
54
|
+
resolve(JSON.parse(xhr.responseText));
|
|
55
|
+
} else {
|
|
56
|
+
reject(new Error(xhr.responseText || "Upload failed"));
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
xhr.onerror = () => reject(new Error("Network error during upload"));
|
|
60
|
+
xhr.send(formData);
|
|
61
|
+
});
|
|
62
|
+
return result;
|
|
63
|
+
} catch (err) {
|
|
64
|
+
const msg = (err == null ? void 0 : err.message) || "Upload failed";
|
|
65
|
+
setError(msg);
|
|
66
|
+
throw err;
|
|
67
|
+
} finally {
|
|
68
|
+
setUploading(false);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
[appName, cloudName, uploadPreset, folder, resourceType, onProgress]
|
|
72
|
+
);
|
|
73
|
+
return { upload, uploading, error, reset };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/cloudinaryUtils.js
|
|
77
|
+
function isCloudinaryUrl(url) {
|
|
78
|
+
return typeof url === "string" && (url.includes("res.cloudinary.com") || url.includes("cloudinary.com"));
|
|
79
|
+
}
|
|
80
|
+
function extractPublicId(url) {
|
|
81
|
+
if (!isCloudinaryUrl(url)) return null;
|
|
82
|
+
try {
|
|
83
|
+
const parts = url.split("/");
|
|
84
|
+
const uploadIdx = parts.indexOf("upload");
|
|
85
|
+
if (uploadIdx === -1) return null;
|
|
86
|
+
let publicIdPath = parts.slice(uploadIdx + 1).join("/");
|
|
87
|
+
const versionMatch = publicIdPath.match(/^v\d+\//);
|
|
88
|
+
if (versionMatch) {
|
|
89
|
+
publicIdPath = publicIdPath.substring(versionMatch[0].length);
|
|
90
|
+
}
|
|
91
|
+
const lastDot = publicIdPath.lastIndexOf(".");
|
|
92
|
+
if (lastDot !== -1) {
|
|
93
|
+
const ext = publicIdPath.substring(lastDot + 1);
|
|
94
|
+
if (/^[a-zA-Z0-9]{2,5}$/.test(ext)) {
|
|
95
|
+
publicIdPath = publicIdPath.substring(0, lastDot);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return publicIdPath || null;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function validatePublicId(publicId) {
|
|
104
|
+
if (!publicId || typeof publicId !== "string") return false;
|
|
105
|
+
const parts = publicId.split("/");
|
|
106
|
+
return parts.length >= 2 && parts.every((p) => p.length > 0);
|
|
107
|
+
}
|
|
108
|
+
function getFolderPath(appName, subfolder) {
|
|
109
|
+
if (!appName) throw new Error("appName is required for getFolderPath");
|
|
110
|
+
const parts = [appName];
|
|
111
|
+
if (subfolder) {
|
|
112
|
+
const cleaned = subfolder.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean).join("/");
|
|
113
|
+
if (cleaned) parts.push(cleaned);
|
|
114
|
+
}
|
|
115
|
+
return parts.join("/");
|
|
116
|
+
}
|
|
117
|
+
function getOptimizedUrl(cloudName, publicId, transforms = {}, resourceType = "image") {
|
|
118
|
+
const base = `https://res.cloudinary.com/${cloudName}/${resourceType}/upload`;
|
|
119
|
+
const parts = Object.entries(transforms).map(([k, v]) => `${k}_${v}`).join(",");
|
|
120
|
+
return parts ? `${base}/${parts}/${publicId}` : `${base}/${publicId}`;
|
|
121
|
+
}
|
|
122
|
+
var TRANSFORM_PRESETS = {
|
|
123
|
+
thumbnail: { w: 150, h: 150, c: "fill", g: "auto", q: "auto", f: "auto" },
|
|
124
|
+
adCard: { w: 300, h: 200, c: "fill", g: "auto", q: "auto", f: "auto" },
|
|
125
|
+
profilePicture: { w: 100, h: 100, c: "fill", g: "face", r: "max", q: "auto", f: "auto" },
|
|
126
|
+
adDetail: { w: 800, h: 600, c: "fill", q: "auto", f: "auto" },
|
|
127
|
+
responsive: { w: "auto", dpr: "auto", q: "auto", f: "auto" }
|
|
128
|
+
};
|
|
129
|
+
export {
|
|
130
|
+
SanvikaCloudinaryProvider,
|
|
131
|
+
TRANSFORM_PRESETS,
|
|
132
|
+
extractPublicId,
|
|
133
|
+
getFolderPath,
|
|
134
|
+
getOptimizedUrl,
|
|
135
|
+
isCloudinaryUrl,
|
|
136
|
+
useCloudinaryUpload,
|
|
137
|
+
useSanvikaCloudinary,
|
|
138
|
+
validatePublicId
|
|
139
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
1
|
// src/cloudinaryCore.js
|
|
4
2
|
import { v2 as cloudinary } from "cloudinary";
|
|
5
3
|
|
|
@@ -144,16 +142,25 @@ function getAppName() {
|
|
|
144
142
|
}
|
|
145
143
|
async function uploadImage(fileOrBuffer, options = {}) {
|
|
146
144
|
ensureConfigured();
|
|
147
|
-
const {
|
|
145
|
+
const {
|
|
146
|
+
folder,
|
|
147
|
+
resourceType = "image",
|
|
148
|
+
tags = [],
|
|
149
|
+
transforms,
|
|
150
|
+
publicId,
|
|
151
|
+
overwrite = false,
|
|
152
|
+
notificationUrl
|
|
153
|
+
} = options;
|
|
148
154
|
const uploadFolder = getFolderPath(_appName, folder);
|
|
149
155
|
const uploadOpts = {
|
|
150
156
|
folder: uploadFolder,
|
|
151
|
-
resource_type:
|
|
157
|
+
resource_type: resourceType,
|
|
152
158
|
overwrite,
|
|
153
159
|
tags: [_appName, ...tags]
|
|
154
160
|
};
|
|
155
161
|
if (publicId) uploadOpts.public_id = publicId;
|
|
156
162
|
if (transforms) uploadOpts.eager = transforms;
|
|
163
|
+
if (notificationUrl) uploadOpts.notification_url = notificationUrl;
|
|
157
164
|
return withRetry(
|
|
158
165
|
() => {
|
|
159
166
|
if (Buffer.isBuffer(fileOrBuffer)) {
|
|
@@ -170,6 +177,9 @@ async function uploadImage(fileOrBuffer, options = {}) {
|
|
|
170
177
|
{ operationName: "uploadImage", maxAttempts: 3 }
|
|
171
178
|
);
|
|
172
179
|
}
|
|
180
|
+
async function uploadVideo(fileOrBuffer, options = {}) {
|
|
181
|
+
return uploadImage(fileOrBuffer, { ...options, resourceType: "video" });
|
|
182
|
+
}
|
|
173
183
|
async function uploadImages(files, options = {}) {
|
|
174
184
|
if (!Array.isArray(files) || files.length === 0) return [];
|
|
175
185
|
return Promise.all(files.map((file) => uploadImage(file, options)));
|
|
@@ -243,82 +253,8 @@ async function pingCloudinary() {
|
|
|
243
253
|
ensureConfigured();
|
|
244
254
|
return cloudinary.api.ping();
|
|
245
255
|
}
|
|
246
|
-
|
|
247
|
-
// src/SanvikaCloudinaryProvider.jsx
|
|
248
|
-
import { createContext, useContext, useMemo } from "react";
|
|
249
|
-
import { jsx } from "react/jsx-runtime";
|
|
250
|
-
var SanvikaCloudinaryContext = createContext(null);
|
|
251
|
-
function SanvikaCloudinaryProvider({ appName, cloudName, uploadPreset = "ml_default", children }) {
|
|
252
|
-
const value = useMemo(
|
|
253
|
-
() => ({ appName, cloudName, uploadPreset }),
|
|
254
|
-
[appName, cloudName, uploadPreset]
|
|
255
|
-
);
|
|
256
|
-
return /* @__PURE__ */ jsx(SanvikaCloudinaryContext.Provider, { value, children });
|
|
257
|
-
}
|
|
258
|
-
function useSanvikaCloudinary() {
|
|
259
|
-
const ctx = useContext(SanvikaCloudinaryContext);
|
|
260
|
-
if (!ctx) {
|
|
261
|
-
throw new Error("useSanvikaCloudinary must be used within a SanvikaCloudinaryProvider");
|
|
262
|
-
}
|
|
263
|
-
return ctx;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// src/useCloudinaryUpload.js
|
|
267
|
-
import { useState, useCallback } from "react";
|
|
268
|
-
function useCloudinaryUpload(options = {}) {
|
|
269
|
-
const { folder, resourceType = "image", onProgress } = options;
|
|
270
|
-
const { appName, cloudName, uploadPreset } = useSanvikaCloudinary();
|
|
271
|
-
const [uploading, setUploading] = useState(false);
|
|
272
|
-
const [error, setError] = useState(null);
|
|
273
|
-
const reset = useCallback(() => {
|
|
274
|
-
setError(null);
|
|
275
|
-
setUploading(false);
|
|
276
|
-
}, []);
|
|
277
|
-
const upload = useCallback(
|
|
278
|
-
async (file) => {
|
|
279
|
-
setError(null);
|
|
280
|
-
setUploading(true);
|
|
281
|
-
try {
|
|
282
|
-
const folderPath = folder ? `${appName}/${folder}` : appName;
|
|
283
|
-
const formData = new FormData();
|
|
284
|
-
formData.append("file", file);
|
|
285
|
-
formData.append("upload_preset", uploadPreset);
|
|
286
|
-
formData.append("folder", folderPath);
|
|
287
|
-
const xhr = new XMLHttpRequest();
|
|
288
|
-
const url = `https://api.cloudinary.com/v1_1/${cloudName}/${resourceType}/upload`;
|
|
289
|
-
const result = await new Promise((resolve, reject) => {
|
|
290
|
-
xhr.open("POST", url);
|
|
291
|
-
if (onProgress) {
|
|
292
|
-
xhr.upload.onprogress = (e) => {
|
|
293
|
-
if (e.lengthComputable) onProgress(Math.round(e.loaded / e.total * 100));
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
xhr.onload = () => {
|
|
297
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
298
|
-
resolve(JSON.parse(xhr.responseText));
|
|
299
|
-
} else {
|
|
300
|
-
reject(new Error(xhr.responseText || "Upload failed"));
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
xhr.onerror = () => reject(new Error("Network error during upload"));
|
|
304
|
-
xhr.send(formData);
|
|
305
|
-
});
|
|
306
|
-
return result;
|
|
307
|
-
} catch (err) {
|
|
308
|
-
const msg = (err == null ? void 0 : err.message) || "Upload failed";
|
|
309
|
-
setError(msg);
|
|
310
|
-
throw err;
|
|
311
|
-
} finally {
|
|
312
|
-
setUploading(false);
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
[appName, cloudName, uploadPreset, folder, resourceType, onProgress]
|
|
316
|
-
);
|
|
317
|
-
return { upload, uploading, error, reset };
|
|
318
|
-
}
|
|
319
256
|
export {
|
|
320
257
|
CloudinaryError,
|
|
321
|
-
SanvikaCloudinaryProvider,
|
|
322
258
|
TRANSFORM_PRESETS,
|
|
323
259
|
configureSanvikaCloudinary,
|
|
324
260
|
deleteImage,
|
|
@@ -333,8 +269,7 @@ export {
|
|
|
333
269
|
uploadImage,
|
|
334
270
|
uploadImages,
|
|
335
271
|
uploadRawFile,
|
|
336
|
-
|
|
337
|
-
useSanvikaCloudinary,
|
|
272
|
+
uploadVideo,
|
|
338
273
|
validatePublicId,
|
|
339
274
|
withRetry
|
|
340
275
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanvika/cloudinary",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Centralized Cloudinary SDK for the Sanvika ecosystem — upload, delete, transform, and manage media across 50+ projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
8
8
|
"exports": {
|
|
9
|
-
".": "./dist/index.js"
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./client": "./dist/client.js"
|
|
10
11
|
},
|
|
11
12
|
"files": [
|
|
12
13
|
"dist"
|
|
@@ -36,8 +37,12 @@
|
|
|
36
37
|
"react-dom": ">=18.0.0"
|
|
37
38
|
},
|
|
38
39
|
"peerDependenciesMeta": {
|
|
39
|
-
"react": {
|
|
40
|
-
|
|
40
|
+
"react": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"react-dom": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
41
46
|
},
|
|
42
47
|
"engines": {
|
|
43
48
|
"node": ">=18.0.0"
|