UNPKG

upcloud

Version:

A powerful and user friendly npm package for smooth file management and uploads with Cloudinary that integrates Multer to process incoming file requests.

525 lines (436 loc) 19.1 kB
# upcloud A powerful and user friendly npm package for smooth file management and uploads with Cloudinary that integrates Multer to process incoming file requests. ## Badges ![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white) ![JavaScript](https://img.shields.io/badge/JavaScript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black) ![npm](https://img.shields.io/badge/npm-CB3837?style=for-the-badge&logo=npm&logoColor=white) ![Cloudinary](https://img.shields.io/badge/Cloudinary-3448C5?style=for-the-badge&logo=cloudinary&logoColor=white) ![Multer](https://img.shields.io/badge/Multer-000000?style=for-the-badge&logo=npm&logoColor=white) ![Files](https://img.shields.io/badge/Files-4285F4?style=for-the-badge&logo=google-drive&logoColor=white) ![upcloud](https://img.shields.io/badge/upcloud-007ACC?style=for-the-badge&logo=npm&logoColor=white) ## Key Features - **Effortless Cloudinary Integration**: Easily upload and manage files on Cloudinary - **Multer Middleware**: Seamlessly integrate with Express.js for handling `multipart/form-data` primarily for file uploads - **Flexible Upload Options**: Supports single and multiple file uploads with options for specifying folders and resource types - **File Deletion**: Conveniently delete files from Cloudinary using their public IDs - **Comprehensive Error Handling**: Provides detailed error responses for robust application development - **Multiple Upload Methods**: Supports uploading from local paths, buffers, and streams, including a dedicated function for large files - **Dual Module Support**: Works seamlessly with both CommonJS (`require`) and ES Modules (`import`) ## Installation You can install `upcloud` using npm or yarn: ```bash npm install upcloud # or yarn add upcloud ``` Additionally, for Express.js integration, you'll need `express` and `dotenv` (for environment variables): ```bash npm install express dotenv ``` ## Usage ### 1. Configure Cloudinary Before using any upload functions, you need to configure your Cloudinary credentials. It's recommended to use environment variables. **Create a `.env` file in your project root:** ```dotenv CLOUDINARY_CLOUD_NAME=your_cloud_name CLOUDINARY_API_KEY=your_api_key CLOUDINARY_API_SECRET=your_api_secret ``` **CommonJS (`.js` file):** ```javascript const { configureCloudinary } = require("upcloud"); const dotenv = require("dotenv"); dotenv.config(); configureCloudinary({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); ``` **ES Modules (`.mjs` file):** ```javascript import { configureCloudinary } from "upcloud"; import dotenv from "dotenv"; dotenv.config(); configureCloudinary({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); ``` ### 2. Express.js Integration with Multer This demonstrates setting up an Express server to handle file uploads via HTTP POST requests. **CommonJS (`server.js`):** ```javascript const express = require("express"); const dotenv = require("dotenv"); const fs = require("fs/promises"); const { configureCloudinary, createMulterDiskMiddleware, uploadFile, uploadMultipleFiles, } = require("upcloud"); dotenv.config(); configureCloudinary({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); const app = express(); const port = 3000; const upload = createMulterDiskMiddleware({ dest: "./uploads" }); fs.mkdir("./uploads", { recursive: true }).catch(console.error); // single file upload app.post("/upload-single", upload.single("image"), async (req, res) => { if (!req.file) return res.status(400).json({ message: "No file uploaded" }); try { const result = await uploadFile(req.file.path, { folder: "express-uploads", }); await fs.unlink(req.file.path); res.status(result.statusCode).json(result); } catch (error) { console.error("Upload error:", error); res .status(500) .json({ message: "File upload failed", error: error.message }); } }); // multiple files upload app.post("/upload-multiple", upload.array("images", 5), async (req, res) => { if (!req.files || req.files.length === 0) return res.status(400).json({ message: "No files uploaded" }); const filePaths = req.files.map((file) => file.path); try { const results = await uploadMultipleFiles(filePaths, { folder: "express-multiple-uploads", }); await Promise.all(filePaths.map((p) => fs.unlink(p))); res.status(200).json({ status: true, statusCode: 200, message: "Files uploaded successfully", data: results, }); } catch (error) { console.error("Multiple upload error:", error); res .status(500) .json({ message: "Multiple file upload failed", error: error.message }); } }); app.listen(port, () => console.log(`Server running on http://localhost:${port}`) ); ``` **ES Modules (`server.mjs`):** ```javascript import express from "express"; import dotenv from "dotenv"; import fs from "fs/promises"; import { fileURLToPath } from "url"; import path from "path"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); import { configureCloudinary, createMulterDiskMiddleware, uploadFile, uploadMultipleFiles, } from "upcloud"; dotenv.config(); configureCloudinary({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); const app = express(); const port = 3000; const upload = createMulterDiskMiddleware({ dest: "./uploads" }); fs.mkdir("./uploads", { recursive: true }).catch(console.error); app.post("/upload-single", upload.single("image"), async (req, res) => { if (!req.file) return res.status(400).json({ message: "No file uploaded" }); try { const result = await uploadFile(req.file.path, { folder: "express-uploads-esm", }); await fs.unlink(req.file.path); res.status(result.statusCode).json(result); } catch (error) { console.error("Upload error:", error); res .status(500) .json({ message: "File upload failed", error: error.message }); } }); app.post("/upload-multiple", upload.array("images", 5), async (req, res) => { if (!req.files || req.files.length === 0) return res.status(400).json({ message: "No files uploaded" }); const filePaths = req.files.map((file) => file.path); try { const results = await uploadMultipleFiles(filePaths, { folder: "express-multiple-uploads-esm", }); await Promise.all(filePaths.map((p) => fs.unlink(p))); res.status(200).json({ status: true, statusCode: 200, message: "Files uploaded successfully", data: results, }); } catch (error) { console.error("Multiple upload error:", error); res .status(500) .json({ message: "Multiple file upload failed", error: error.message }); } }); app.listen(port, () => console.log(`Server running on http://localhost:${port}`) ); ``` **To test the Express routes:** 1. Start the server: `node server.js` (for CommonJS) or `node server.mjs` (for ES Modules) 2. Use `curl` or a tool like Postman/Insomnia to send `multipart/form-data` requests - **Single file:** `curl -X POST -F 'image=@./path/to/your/image.jpg' http://localhost:3000/upload-single` - **Multiple files:** `curl -X POST -F 'images=@./path/to/doc1.pdf' -F 'images=@./path/to/doc2.pdf' http://localhost:3000/upload-multiple` ### 3. Direct File Operations These examples show how to use the `upcloud` functions directly without an Express server. **CommonJS (`app.js`):** ```javascript const { configureCloudinary, uploadFile, uploadMultipleFiles, deleteFile, } = require("upcloud"); const { uploadFromPath, uploadBuffer, uploadStream, uploadLarge, cloudinary, } = require("upcloud/cloudinaryClient"); const dotenv = require("dotenv"); const path = require("path"); const fs = require("fs"); dotenv.config(); configureCloudinary({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); async function runDirectExamples() { const imagePath = path.join(__dirname, "test-image.jpg"); const docPaths = [ path.join(__dirname, "test-doc1.pdf"), path.join(__dirname, "test-doc2.pdf"), ]; const videoPath = path.join(__dirname, "test-video.mp4"); let uploadedPublicId = null; // Example: Upload Single File try { const response = await uploadFile(imagePath, { folder: "direct-commonjs" }); console.log("Upload successful:", response.data[0].secure_url); uploadedPublicId = response.data[0].public_id; } catch (error) { console.error("Upload failed:", error.message); } // Example: Upload Multiple Files try { const results = await uploadMultipleFiles(docPaths, { folder: "direct-commonjs-docs", }); results.forEach((res) => console.log(res.secure_url)); } catch (error) { console.error("Multiple uploads failed:", error.message); } // Example: Upload from Buffer try { const buffer = Buffer.from("This is a test text file from a buffer."); const result = await uploadBuffer(buffer, { resource_type: "raw", public_id: "buffer-test-commonjs", }); console.log("Buffer upload successful:", result.secure_url); } catch (error) { console.error("Buffer upload failed:", error.message); } // Example: Upload from Stream try { const readableStream = fs.createReadStream(videoPath); const result = await uploadStream(readableStream, { resource_type: "video", folder: "stream-commonjs", }); console.log("Stream upload successful:", result.secure_url); } catch (error) { console.error("Stream upload failed:", error.message); } // Example: Delete File if (uploadedPublicId) { try { const result = await deleteFile(uploadedPublicId); console.log("Deletion successful:", result); } catch (error) { console.error("Deletion failed:", error.message); } } else { } // Example: Using raw cloudinary instance try { const resources = await cloudinary.api.resources({ type: "upload", max_results: 3, }); console.log( "First 3 uploaded resources:", resources.resources.map((r) => r.public_id) ); } catch (error) { console.error("Failed to list resources:", error.message); } } runDirectExamples(); ``` **ES Modules (`app.mjs`):** ```javascript import { configureCloudinary, uploadFile, uploadMultipleFiles, deleteFile, } from "upcloud"; import { uploadFromPath, uploadBuffer, uploadStream, uploadLarge, cloudinary, } from "upcloud/cloudinaryClient"; import dotenv from "dotenv"; import path from "path"; import fs from "fs"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); dotenv.config(); configureCloudinary({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); async function runDirectExamples() { const imagePath = path.join(__dirname, "test-image.jpg"); const docPaths = [ path.join(__dirname, "test-doc1.pdf"), path.join(__dirname, "test-doc2.pdf"), ]; const videoPath = path.join(__dirname, "test-video.mp4"); let uploadedPublicId = null; try { const response = await uploadFile(imagePath, { folder: "direct-esm" }); console.log("Upload successful:", response.data[0].secure_url); uploadedPublicId = response.data[0].public_id; } catch (error) { console.error("Upload failed:", error.message); } try { const results = await uploadMultipleFiles(docPaths, { folder: "direct-esm-docs", }); results.forEach((res) => console.log(res.secure_url)); } catch (error) { console.error("Multiple uploads failed:", error.message); } try { const buffer = Buffer.from("This is a test text file from a buffer (ESM)."); const result = await uploadBuffer(buffer, { resource_type: "raw", public_id: "buffer-test-esm", }); console.log("Buffer upload successful:", result.secure_url); } catch (error) { console.error("Buffer upload failed:", error.message); } try { const readableStream = fs.createReadStream(videoPath); const result = await uploadStream(readableStream, { resource_type: "video", folder: "stream-esm", }); console.log("Stream upload successful:", result.secure_url); } catch (error) { console.error("Stream upload failed:", error.message); } // Example: Delete File if (uploadedPublicId) { try { const result = await deleteFile(uploadedPublicId); console.log("Deletion successful:", result); } catch (error) { console.error("Deletion failed:", error.message); } } else { } // Example: Using raw cloudinary instance try { const resources = await cloudinary.api.resources({ type: "upload", max_results: 3, }); console.log( "First 3 uploaded resources:", resources.resources.map((r) => r.public_id) ); } catch (error) { console.error("Failed to list resources:", error.message); } } runDirectExamples(); ``` **To run these direct usage examples:** - For CommonJS: `node app.js` - For ES Modules: `node app.mjs` ## Available Functions and Options | Function / Interface | Description | Parameters | Returns | | :--------------------------- | :------------------------------------------------------------------------------------------------ | :-------------------------------------------------------- | :----------------------------------------------------------------------- | | `configureCloudinary` | Configures the Cloudinary SDK with your credentials. | `config: CloudinaryConfig` | `void` | | `createMulterDiskMiddleware` | Creates a Multer middleware instance configured for disk storage. | `options?: multer.Options` (Multer options) | `multer.Multer` instance | | `uploadFile` | Uploads a single file from a local path to Cloudinary. | `filePath: string`, `options?: UploadApiOptions` | `{ status: boolean; statusCode: number; message: string; data: any[]; }` | | `uploadMultipleFiles` | Uploads an array of files from local paths to Cloudinary. | `filePaths: string[]`, `options?: UploadApiOptions` | `Promise<UploadApiResponse[]>` | | `deleteFile` | Deletes a file from Cloudinary using its public ID. | `publicId: string`, `options?: UploadApiOptions` | `Promise<UploadApiResponse>` | | `uploadFromPath` | (Advanced) Uploads a file from a local path. Returns raw Cloudinary response. | `localPath: string`, `opts?: Record<string, any>` | `Promise<UploadResult>` | | `uploadBuffer` | (Advanced) Uploads a file from a Buffer. Returns raw Cloudinary response. | `buffer: Buffer`, `opts?: Record<string, any>` | `Promise<UploadResult>` | | `uploadStream` | (Advanced) Uploads a file from a Readable Stream. Returns raw Cloudinary response. | `readable: stream.Readable`, `opts?: Record<string, any>` | `Promise<UploadResult>` | | `uploadLarge` | (Advanced) Uploads a very large file (>100MB) from a local path. Returns raw Cloudinary response. | `localPath: string`, `opts?: Record<string, any>` | `Promise<UploadResult>` | | `cloudinary` | (Advanced) The raw configured Cloudinary SDK instance for direct API calls. | N/A | `cloudinary.v2` instance | --- #### `CloudinaryConfig` Interface | Property | Type | Description | Required | | :----------- | :------- | :-------------------------- | :------- | | `cloud_name` | `string` | Your Cloudinary cloud name. | Yes | | `api_key` | `string` | Your Cloudinary API key. | Yes | | `api_secret` | `string` | Your Cloudinary API secret. | Yes | #### `UploadApiOptions` Interface | Property | Type | Description | Required | | :-------------- | :------------------------------------------------------- | :------------------------------------------------------------------------------------------------ | :------- | | `folder` | `string` | The name of the folder in your Cloudinary account to upload the file to. | No | | `resource_type` | `ResourceType` (`"image" \| "video" \| "raw" \| "auto"`) | The type of resource being uploaded. Defaults to `"image"`. Use `"auto"` for automatic detection. | No | #### `UploadApiResponse` Interface | Property | Type | Description | | :------------ | :------- | :------------------------------------------- | | `public_id` | `string` | The public ID of the uploaded asset. | | `secure_url` | `string` | The secure URL of the uploaded asset. | | `[k: string]` | `any` | Other properties returned by Cloudinary API. | ## Contribution Contributions are welcome. If you have suggestions for improvements, bug fixes or new features please open an issue or submit a pull request. 1. Fork the repository 2. Create a new branch (`git checkout -b feature/your-feature`) 3. Make your changes 4. Commit your changes (`git commit -m 'Add new feature'`) 5. Push to the branch (`git push origin feature/your-feature`) 6. Open a pull request ## License This project is licensed under the MIT License - see the [LICENSE](https://mit-license.org) file for details.