@sanvika/cloudinary 0.1.3 → 0.1.4

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.
Files changed (2) hide show
  1. package/dist/index.js +121 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -146,10 +146,17 @@ async function uploadImage(fileOrBuffer, options = {}) {
146
146
  folder,
147
147
  resourceType = "image",
148
148
  tags = [],
149
+ eager,
149
150
  transforms,
151
+ eagerAsync,
152
+ eagerNotificationUrl,
150
153
  publicId,
151
154
  overwrite = false,
152
- notificationUrl
155
+ notificationUrl,
156
+ chunked,
157
+ chunkSize = 6 * 1024 * 1024,
158
+ timeout,
159
+ maxAttempts = 3
153
160
  } = options;
154
161
  const uploadFolder = getFolderPath(_appName, folder);
155
162
  const uploadOpts = {
@@ -159,22 +166,40 @@ async function uploadImage(fileOrBuffer, options = {}) {
159
166
  tags: [_appName, ...tags]
160
167
  };
161
168
  if (publicId) uploadOpts.public_id = publicId;
162
- if (transforms) uploadOpts.eager = transforms;
169
+ const eagerValue = eager || transforms;
170
+ if (eagerValue) uploadOpts.eager = eagerValue;
171
+ if (eagerAsync) uploadOpts.eager_async = true;
172
+ if (eagerNotificationUrl) uploadOpts.eager_notification_url = eagerNotificationUrl;
163
173
  if (notificationUrl) uploadOpts.notification_url = notificationUrl;
174
+ if (timeout) uploadOpts.timeout = timeout;
175
+ const fileSize = Buffer.isBuffer(fileOrBuffer) ? fileOrBuffer.length : null;
176
+ const useChunked = chunked || resourceType === "video" && fileSize !== null && fileSize > 10 * 1024 * 1024;
177
+ if (useChunked) {
178
+ uploadOpts.chunk_size = chunkSize;
179
+ }
164
180
  return withRetry(
165
181
  () => {
166
182
  if (Buffer.isBuffer(fileOrBuffer)) {
167
183
  return new Promise((resolve, reject) => {
168
- const stream = cloudinary.uploader.upload_stream(uploadOpts, (err, result) => {
184
+ const streamFactory = useChunked ? cloudinary.uploader.upload_chunked_stream : cloudinary.uploader.upload_stream;
185
+ const stream = streamFactory.call(cloudinary.uploader, uploadOpts, (err, result) => {
169
186
  if (err) return reject(err);
170
187
  resolve(result);
171
188
  });
172
189
  stream.end(fileOrBuffer);
173
190
  });
174
191
  }
192
+ if (useChunked) {
193
+ return new Promise((resolve, reject) => {
194
+ cloudinary.uploader.upload_large(fileOrBuffer, uploadOpts, (err, result) => {
195
+ if (err) return reject(err);
196
+ resolve(result);
197
+ });
198
+ });
199
+ }
175
200
  return cloudinary.uploader.upload(fileOrBuffer, uploadOpts);
176
201
  },
177
- { operationName: "uploadImage", maxAttempts: 3 }
202
+ { operationName: "uploadImage", maxAttempts }
178
203
  );
179
204
  }
180
205
  async function uploadVideo(fileOrBuffer, options = {}) {
@@ -253,6 +278,94 @@ async function pingCloudinary() {
253
278
  ensureConfigured();
254
279
  return cloudinary.api.ping();
255
280
  }
281
+ async function getCloudinaryUsage(options = {}) {
282
+ ensureConfigured();
283
+ const { resourceType } = options;
284
+ return cloudinary.api.usage(resourceType ? { resource_type: resourceType } : {});
285
+ }
286
+ function getCloudinarySdkVersion() {
287
+ return cloudinary.CLOUDINARY_VERSION;
288
+ }
289
+
290
+ // src/cloudinaryDiagnostics.js
291
+ import crypto from "crypto";
292
+ function testCloudinaryWebhookSignature(apiSecret, options = {}) {
293
+ try {
294
+ if (!apiSecret) {
295
+ return { success: false, error: "apiSecret is required" };
296
+ }
297
+ const testPayload = { test: "data", timestamp: Math.floor(Date.now() / 1e3) };
298
+ const testPayloadString = JSON.stringify(testPayload);
299
+ const testTimestamp = testPayload.timestamp.toString();
300
+ const signatureData = testTimestamp + testPayloadString;
301
+ const signature = crypto.createHmac("sha1", apiSecret).update(signatureData).digest("hex");
302
+ return {
303
+ success: true,
304
+ testPayload,
305
+ testTimestamp,
306
+ signature,
307
+ headers: {
308
+ "X-Cld-Timestamp": testTimestamp,
309
+ "X-Cld-Signature": signature
310
+ },
311
+ testEndpoint: options.testEndpoint || "/api/webhooks/cloudinary/debug"
312
+ };
313
+ } catch (error) {
314
+ return { success: false, error: error.message };
315
+ }
316
+ }
317
+ async function runCloudinaryDiagnostics(options = {}) {
318
+ const {
319
+ testWebhook = false,
320
+ webhookSecret,
321
+ testFolder = "diagnostics"
322
+ } = options;
323
+ const report = {
324
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
325
+ cloudinaryVersion: getCloudinarySdkVersion(),
326
+ nodeVersion: process.version,
327
+ configuration: {
328
+ cloudName: process.env.CLOUDINARY_CLOUD_NAME || process.env.CLOUDINARY_NAME ? "set" : "missing",
329
+ apiKey: process.env.CLOUDINARY_API_KEY ? "set" : "missing",
330
+ apiSecret: process.env.CLOUDINARY_API_SECRET ? "set" : "missing",
331
+ uploadPreset: process.env.CLOUDINARY_UPLOAD_PRESET ? "set" : "missing"
332
+ },
333
+ tests: {}
334
+ };
335
+ report.tests.ping = await pingCloudinary().then(
336
+ (result) => ({ success: true, result }),
337
+ (error) => ({ success: false, error: error.message })
338
+ );
339
+ const testBuffer = Buffer.from("Cloudinary diagnostic test");
340
+ report.tests.upload = await uploadImage(testBuffer, {
341
+ folder: testFolder,
342
+ resourceType: "raw",
343
+ tags: ["test", "diagnostics"],
344
+ publicId: `diagnostic_${Date.now()}`,
345
+ overwrite: true
346
+ }).then(
347
+ (result) => ({
348
+ success: true,
349
+ publicId: result.public_id,
350
+ url: result.secure_url,
351
+ bytes: result.bytes
352
+ }),
353
+ (error) => ({
354
+ success: false,
355
+ error: error.message,
356
+ httpCode: error.http_code,
357
+ name: error.name
358
+ })
359
+ );
360
+ report.tests.videoLimits = await getCloudinaryUsage({ resourceType: "video" }).then(
361
+ (result) => ({ success: true, result }),
362
+ (error) => ({ success: false, error: error.message })
363
+ );
364
+ if (testWebhook) {
365
+ report.tests.webhook = testCloudinaryWebhookSignature(webhookSecret);
366
+ }
367
+ return report;
368
+ }
256
369
  export {
257
370
  CloudinaryError,
258
371
  TRANSFORM_PRESETS,
@@ -261,11 +374,15 @@ export {
261
374
  deleteImages,
262
375
  extractPublicId,
263
376
  getAppName,
377
+ getCloudinarySdkVersion,
378
+ getCloudinaryUsage,
264
379
  getFolderPath,
265
380
  getOptimizedUrl,
266
381
  isCloudinaryUrl,
267
382
  isRetriableError,
268
383
  pingCloudinary,
384
+ runCloudinaryDiagnostics,
385
+ testCloudinaryWebhookSignature,
269
386
  uploadImage,
270
387
  uploadImages,
271
388
  uploadRawFile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanvika/cloudinary",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
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",