0.4.108 • Published 4 months ago

@api-buddy/cloudinary v0.4.108

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

@api-buddy/cloudinary

npm version License: MIT

A comprehensive Cloudinary integration for Next.js applications, providing a simple and type-safe way to upload, transform, and deliver images and videos.

Features

  • 🚀 Easy Setup: Get started quickly with a few simple steps
  • 🔒 Type-Safe: Full TypeScript support for all Cloudinary options and responses
  • Performance Optimized: Automatic image optimization and responsive images
  • 🎣 React Hooks: Custom hooks for easy file uploads and media management
  • 🖼️ Components: Pre-built React components for images and videos
  • 🛠 CLI Tool: Quick project setup with the included CLI
  • 🔄 Server & Client Support: Works with both server components and client components
  • 📱 Responsive Images: Automatic srcset generation for responsive images
  • 🎥 Video Support: Upload, transform, and deliver videos with ease

Installation

# Using npm
npm install @api-buddy/cloudinary cloudinary

# Using yarn
yarn add @api-buddy/cloudinary cloudinary

# Using pnpm
pnpm add @api-buddy/cloudinary cloudinary

If you're using TypeScript, you'll also want to install the Cloudinary types:

npm install --save-dev @types/cloudinary

Quick Start

1. Set Up Environment Variables

Create a .env.local file in your project root and add your Cloudinary credentials:

NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name
NEXT_PUBLIC_CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET=your_upload_preset

2. Set Up the Cloudinary Provider

Wrap your application with the CloudinaryProvider in your root layout:

// app/layout.tsx
'use client';

import { CloudinaryProvider } from '@api-buddy/cloudinary';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <CloudinaryProvider 
          config={{
            // Optional: Configure default settings here
            cloudName: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
            apiKey: process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY,
            apiSecret: process.env.CLOUDINARY_API_SECRET,
            uploadPreset: process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET,
          }}
        >
          {children}
        </CloudinaryProvider>
      </body>
    </html>
  );
}

3. Upload Files

Create an API route to handle file uploads:

// app/api/upload/route.ts
import { NextResponse } from 'next/server';
import { upload } from '@api-buddy/cloudinary';

export async function POST(request: Request) {
  try {
    const formData = await request.formData();
    const file = formData.get('file') as File;
    
    if (!file) {
      return NextResponse.json(
        { success: false, error: 'No file provided' },
        { status: 400 }
      );
    }

    // Convert the file to a buffer
    const buffer = Buffer.from(await file.arrayBuffer());
    
    // Upload to Cloudinary
    const result = await upload(buffer, {
      folder: 'uploads',
      resourceType: 'auto',
      public_id: file.name.replace(/\.[^/.]+$/, ''), // Remove file extension
      filename_override: file.name,
      context: {
        filename: file.name,
        format: file.type,
        size: file.size,
      },
    });

    return NextResponse.json({ success: true, data: result });
  } catch (error) {
    console.error('Upload error:', error);
    return NextResponse.json(
      { success: false, error: 'Failed to upload file' },
      { status: 500 }
    );
  }
}

4. Use the useCloudinaryUpload Hook

'use client';

import { useCloudinaryUpload } from '@api-buddy/cloudinary';

export default function UploadForm() {
  const { uploadFile, isUploading, progress, error } = useCloudinaryUpload({
    options: {
      folder: 'images',
      resourceType: 'image',
    },
    onSuccess: (result) => {
      console.log('Upload successful:', result);
    },
    onError: (error) => {
      console.error('Upload error:', error);
    },
  });

  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      await uploadFile(file);
    }
  };

  return (
    <div className="p-6 max-w-md mx-auto bg-white rounded-xl shadow-md">
      <h2 className="text-xl font-semibold mb-4">Upload an Image</h2>
      
      <div className="mb-4">
        <input
          type="file"
          accept="image/*"
          onChange={handleFileChange}
          disabled={isUploading}
          className="block w-full text-sm text-gray-500
            file:mr-4 file:py-2 file:px-4
            file:rounded-md file:border-0
            file:text-sm file:font-semibold
            file:bg-blue-50 file:text-blue-700
            hover:file:bg-blue-100"
        />
      </div>

      {isUploading && (
        <div className="w-full bg-gray-200 rounded-full h-2.5">
          <div
            className="bg-blue-600 h-2.5 rounded-full"
            style={{ width: `${progress}%` }}
          ></div>
          <p className="text-sm text-gray-600 mt-1">Uploading: {progress}%</p>
        </div>
      )}

      {error && (
        <div className="mt-4 p-3 bg-red-100 text-red-700 rounded-md">
          Error: {error.message}
        </div>
      )}
    </div>
  );
}

5. Display Images

import { CloudinaryImage } from '@api-buddy/cloudinary';

export default function ProfileImage({ publicId }: { publicId: string }) {
  return (
    <div className="w-32 h-32 rounded-full overflow-hidden">
      <CloudinaryImage
        publicId={publicId}
        alt="Profile image"
        width={128}
        height={128}
        className="w-full h-full object-cover"
        transformation={[
          { width: 256, height: 256, crop: 'thumb', gravity: 'face' },
          { radius: 'max' },
        ]}
      />
    </div>
  );
}

CLI Setup

For a quick setup, use the included CLI:

npx @api-buddy/cloudinary setup

This will: 1. Install required dependencies 2. Set up environment variables 3. Create example components and API routes 4. Configure your Next.js app to use Cloudinary

API Reference

CloudinaryProvider

A context provider that makes the Cloudinary client available throughout your application.

Props

  • config: Configuration object
    • cloudName: Your Cloudinary cloud name (required)
    • apiKey: Your Cloudinary API key (optional, defaults to process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY)
    • apiSecret: Your Cloudinary API secret (optional, defaults to process.env.CLOUDINARY_API_SECRET)
    • uploadPreset: Your Cloudinary upload preset (optional)
    • defaultUploadOptions: Default options for all uploads

useCloudinary()

A hook to access the Cloudinary client from the nearest CloudinaryProvider.

Returns

  • client: The Cloudinary client instance
  • config: The current Cloudinary configuration

useCloudinaryUpload(options)

A hook for handling file uploads to Cloudinary.

Parameters

  • options: Upload options
    • options: Default upload options for all uploads
    • onSuccess: Callback when an upload succeeds
    • onError: Callback when an upload fails
    • onProgress: Callback with upload progress (0-100)

Returns

  • uploadFile: Function to upload a single file
  • uploadFiles: Function to upload multiple files
  • isUploading: Boolean indicating if an upload is in progress
  • progress: Current upload progress (0-100)
  • error: Error object if an upload failed
  • reset: Function to reset the hook state

CloudinaryImage

A React component for displaying Cloudinary images with automatic optimization.

Props

  • publicId: The public ID of the image (required)
  • alt: Alternative text for the image (required)
  • width: Width of the image
  • height: Height of the image
  • className: CSS class name
  • style: Inline styles
  • loading: Loading behavior (lazy or eager)
  • transformation: Array of Cloudinary transformations
  • format: Image format to convert to
  • quality: Image quality (1-100)
  • responsive: Whether to generate responsive images
  • sizes: Sizes attribute for responsive images
  • srcSet: Custom srcset for responsive images
  • onLoad: Callback when the image loads
  • onError: Callback when the image fails to load

CloudinaryVideo

A React component for displaying Cloudinary videos.

Props

  • publicId: The public ID of the video (required)
  • width: Width of the video player
  • height: Height of the video player
  • className: CSS class name
  • style: Inline styles
  • autoPlay: Whether to autoplay the video
  • loop: Whether to loop the video
  • muted: Whether to mute the video
  • controls: Whether to show video controls
  • poster: URL of the poster image
  • transformation: Array of Cloudinary transformations
  • onPlay: Callback when the video starts playing
  • onPause: Callback when the video is paused
  • onEnded: Callback when the video ends
  • onError: Callback when the video fails to load

upload(file, options)

Upload a file to Cloudinary.

Parameters

Returns

A promise that resolves to the upload result.

deleteFile(publicId, options)

Delete a file from Cloudinary.

Parameters

  • publicId: The public ID of the file to delete
  • options: Delete options
    • resourceType: Type of resource (image, video, raw, or auto)
    • type: The type of the resource
    • invalidate: Whether to invalidate the CDN cache

Returns

A promise that resolves to the delete result.

getUrl(publicId, options)

Generate a URL for a Cloudinary resource.

Parameters

  • publicId: The public ID of the resource
  • options: URL and transformation options
    • transformation: Array of Cloudinary transformations
    • resourceType: Type of resource (image, video, raw, or auto)
    • type: The type of the resource
    • format: Format to convert the resource to
    • secure: Whether to use HTTPS
    • signUrl: Whether to sign the URL
    • version: The version of the resource

Returns

The generated URL as a string.

Examples

Uploading a File

import { upload } from '@api-buddy/cloudinary';

// In an API route or server component
const file = // your file buffer or stream
const result = await upload(file, {
  folder: 'uploads',
  resourceType: 'auto',
  public_id: 'my-file',
});

console.log('File uploaded:', result.url);

Using Transformations

import { CloudinaryImage } from '@api-buddy/cloudinary';

function ProductImage({ publicId }: { publicId: string }) {
  return (
    <CloudinaryImage
      publicId={publicId}
      alt="Product image"
      width={400}
      height={400}
      transformation={[
        { width: 800, height: 800, crop: 'fill' },
        { effect: 'sharpen' },
        { quality: 'auto' },
      ]}
    />
  );
}

Responsive Images

import { CloudinaryImage } from '@api-buddy/cloudinary';

function HeroImage({ publicId }: { publicId: string }) {
  return (
    <CloudinaryImage
      publicId={publicId}
      alt="Hero image"
      width={1200}
      height={630}
      className="w-full h-auto"
      responsive
      sizes="(max-width: 768px) 100vw, 50vw"
      transformation={[
        { width: 1200, height: 630, crop: 'fill' },
        { quality: 'auto' },
      ]}
    />
  );
}

Error Handling

All functions throw a CloudinaryError when something goes wrong. You can catch and handle these errors:

try {
  await upload(file, options);
} catch (error) {
  if (error.name === 'CloudinaryError') {
    console.error('Cloudinary error:', error.message);
    // Handle specific error cases
    if (error.code === 'LIMIT_FILE_SIZE') {
      // Handle file size limit exceeded
    } else if (error.code === 'UNAUTHORIZED') {
      // Handle authentication error
    } else {
      // Handle other errors
    }
  } else {
    // Handle non-Cloudinary errors
    console.error('Unexpected error:', error);
  }
}

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

MIT

Acknowledgments