@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 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 { folder, tags = [], transforms, publicId, overwrite = false } = options;
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: "image",
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
- useCloudinaryUpload,
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.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": { "optional": true },
40
- "react-dom": { "optional": true }
40
+ "react": {
41
+ "optional": true
42
+ },
43
+ "react-dom": {
44
+ "optional": true
45
+ }
41
46
  },
42
47
  "engines": {
43
48
  "node": ">=18.0.0"