@sanvika/cloudinary 0.1.2 → 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 +0 -78
- 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
|
|
|
@@ -255,82 +253,8 @@ async function pingCloudinary() {
|
|
|
255
253
|
ensureConfigured();
|
|
256
254
|
return cloudinary.api.ping();
|
|
257
255
|
}
|
|
258
|
-
|
|
259
|
-
// src/SanvikaCloudinaryProvider.jsx
|
|
260
|
-
import { createContext, useContext, useMemo } from "react";
|
|
261
|
-
import { jsx } from "react/jsx-runtime";
|
|
262
|
-
var SanvikaCloudinaryContext = createContext(null);
|
|
263
|
-
function SanvikaCloudinaryProvider({ appName, cloudName, uploadPreset = "ml_default", children }) {
|
|
264
|
-
const value = useMemo(
|
|
265
|
-
() => ({ appName, cloudName, uploadPreset }),
|
|
266
|
-
[appName, cloudName, uploadPreset]
|
|
267
|
-
);
|
|
268
|
-
return /* @__PURE__ */ jsx(SanvikaCloudinaryContext.Provider, { value, children });
|
|
269
|
-
}
|
|
270
|
-
function useSanvikaCloudinary() {
|
|
271
|
-
const ctx = useContext(SanvikaCloudinaryContext);
|
|
272
|
-
if (!ctx) {
|
|
273
|
-
throw new Error("useSanvikaCloudinary must be used within a SanvikaCloudinaryProvider");
|
|
274
|
-
}
|
|
275
|
-
return ctx;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// src/useCloudinaryUpload.js
|
|
279
|
-
import { useState, useCallback } from "react";
|
|
280
|
-
function useCloudinaryUpload(options = {}) {
|
|
281
|
-
const { folder, resourceType = "image", onProgress } = options;
|
|
282
|
-
const { appName, cloudName, uploadPreset } = useSanvikaCloudinary();
|
|
283
|
-
const [uploading, setUploading] = useState(false);
|
|
284
|
-
const [error, setError] = useState(null);
|
|
285
|
-
const reset = useCallback(() => {
|
|
286
|
-
setError(null);
|
|
287
|
-
setUploading(false);
|
|
288
|
-
}, []);
|
|
289
|
-
const upload = useCallback(
|
|
290
|
-
async (file) => {
|
|
291
|
-
setError(null);
|
|
292
|
-
setUploading(true);
|
|
293
|
-
try {
|
|
294
|
-
const folderPath = folder ? `${appName}/${folder}` : appName;
|
|
295
|
-
const formData = new FormData();
|
|
296
|
-
formData.append("file", file);
|
|
297
|
-
formData.append("upload_preset", uploadPreset);
|
|
298
|
-
formData.append("folder", folderPath);
|
|
299
|
-
const xhr = new XMLHttpRequest();
|
|
300
|
-
const url = `https://api.cloudinary.com/v1_1/${cloudName}/${resourceType}/upload`;
|
|
301
|
-
const result = await new Promise((resolve, reject) => {
|
|
302
|
-
xhr.open("POST", url);
|
|
303
|
-
if (onProgress) {
|
|
304
|
-
xhr.upload.onprogress = (e) => {
|
|
305
|
-
if (e.lengthComputable) onProgress(Math.round(e.loaded / e.total * 100));
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
xhr.onload = () => {
|
|
309
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
310
|
-
resolve(JSON.parse(xhr.responseText));
|
|
311
|
-
} else {
|
|
312
|
-
reject(new Error(xhr.responseText || "Upload failed"));
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
xhr.onerror = () => reject(new Error("Network error during upload"));
|
|
316
|
-
xhr.send(formData);
|
|
317
|
-
});
|
|
318
|
-
return result;
|
|
319
|
-
} catch (err) {
|
|
320
|
-
const msg = (err == null ? void 0 : err.message) || "Upload failed";
|
|
321
|
-
setError(msg);
|
|
322
|
-
throw err;
|
|
323
|
-
} finally {
|
|
324
|
-
setUploading(false);
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
[appName, cloudName, uploadPreset, folder, resourceType, onProgress]
|
|
328
|
-
);
|
|
329
|
-
return { upload, uploading, error, reset };
|
|
330
|
-
}
|
|
331
256
|
export {
|
|
332
257
|
CloudinaryError,
|
|
333
|
-
SanvikaCloudinaryProvider,
|
|
334
258
|
TRANSFORM_PRESETS,
|
|
335
259
|
configureSanvikaCloudinary,
|
|
336
260
|
deleteImage,
|
|
@@ -346,8 +270,6 @@ export {
|
|
|
346
270
|
uploadImages,
|
|
347
271
|
uploadRawFile,
|
|
348
272
|
uploadVideo,
|
|
349
|
-
useCloudinaryUpload,
|
|
350
|
-
useSanvikaCloudinary,
|
|
351
273
|
validatePublicId,
|
|
352
274
|
withRetry
|
|
353
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"
|