Made with ❤ī¸ by Apexx Cloud

Apexx Uploader

A powerful and flexible file upload library for AWS S3, Cloudflare R2, and Apexx Cloud

Installation

For React applications

npm install apexx-uploader-react

For vanilla JavaScript

npm install apexx-uploader-core

Note: If you're using React, you only need to install apexx-uploader-react. It includes the core functionality internally.

Features

đŸŒĨī¸

Multiple Storage Support

AWS S3, Cloudflare R2, S3-compatible, Apexx Cloud

📂

Multi-File Uploads

Upload multiple files simultaneously with progress tracking

📊

Progress Tracking

Real-time upload progress and status management

đŸ“Ļ

Multipart Upload

Handle large files with multipart upload support

⏚ī¸

Cancel Uploads

Cancel individual files or all uploads at once

🛡ī¸

Error Handling

Robust error handling and reporting

Live Demo

Note: The UI can be created using the hooks and can be customized to your needs. We provide optional pre-built components for quick implementation.

AWS Uploader Dashboard

Upload Files

Upload up to 10 files (image/*, video/*, application/pdf, max 50 MB)

Apexx Uploader Dashboard

Upload Files

Upload up to 10 files (image/*, video/*, application/pdf, max 50 MB)

AWS Uploader Button

Supports image/*, video/*, application/pdf up to 50 MB, max 2 files

Apexx Uploader Button

Supports image/*, video/*, application/pdf up to 50 MB, max 2 files

React Hooks API

useUploader

A powerful hook for handling multiple file uploads with progress tracking, cancellation, and error handling. You need to add server side implementation for the provider you are using.

import { useUploader } from "apexx-uploader-react";

// Call your server side implementation for the provider you are using
  const getSignedUrl = async (
    operation: string,
    params: Record<string, any>
  ) => {
    const response = await fetch(
      "http://localhost:3000/presigned-url-aws",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ operation, params }),
      }
    );
    return (await response.json()).url;
  };

function FileUploader() {
  const {
    upload,          // Function to start the upload
    cancelUpload,    // Function to cancel all uploads
    cancelFileUpload,// Function to cancel a specific file
    reset,           // Function to reset the upload state
    files,           // Current state of all files
    totalProgress,   // Overall upload progress
    status          // Current upload status
  } = useUploader({
    provider: "aws", // or "apexx"
    getSignedUrl: getSignedUrl
  });

  const handleFiles = async (event) => {
    const files = Array.from(event.target.files);
    await upload(files, {
      multipart: true,
      partSize: 5 * 1024 * 1024, // 5MB chunks
      concurrency: 3,
      onProgress: (progress, file) => console.log(`${file.name}: ${progress}%`),
      onComplete: (response, file) => console.log(`${file.name} complete`),
      onError: (error, file) => console.error(`${file.name} failed`, error)
    });
  };

  return (
    <div>
      <input type="file" multiple onChange={handleFiles} />
      <div>Total Progress: {totalProgress}%</div>
      {Object.entries(files).map(([name, file]) => (
        <div key={name}>
          {name}: {file.progress}%
          {file.status === "uploading" && (
            <button onClick={() => cancelFileUpload(name)}>Cancel</button>
          )}
        </div>
      ))}
      <button onClick={() => cancelUpload()}>Cancel All</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

Configuration

interface UploaderConfig {
  provider: 'aws' | 'apexx';
  getSignedUrl: (operation: string, params: Record<string, any>) => Promise<string>;
}

Upload Options

interface UploadOptions {
  key?: string;                                              // Custom key for the file
  multipart?: boolean;                                       // Enable multipart upload
  partSize?: number;                                         // Size of each part in bytes
  concurrency?: number;                                      // Number of concurrent uploads
  onProgress?: (progressData: any, file: File) => void;      // Progress callback
  onComplete?: (response: any, file: File) => void;          // Completion callback
  onError?: (error: Error, file: File) => void;              // Error callback
  onStart?: (file: File) => void;                           // Start callback
}

Return Values

upload
Function to start uploading files with options
cancelUpload
Cancels all uploads
cancelFileUpload
Cancels upload for a specific file by name
reset
Resets the upload state
files
Object containing state for each file: { progress, status, error, response }
totalProgress
Overall progress percentage across all files
status
Current status: 'idle' | 'uploading' | 'completed' | 'error'

Server Side Implementation for AWS or S3-compatible Storage

const aws = require("aws-sdk");

let s3 = new aws.S3({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  signatureVersion: "v4",
  region: "ap-south-1",
});

const getPresignedUrl = async (req, res) => {
  try {
    const { operation = "putObject" } = req.body;
    const { params } = req.body;
  
    const url = await s3.getSignedUrlPromise(operation, {
      ...params,
      Bucket: "your-bucket-name",
    });

    res.status(200).json({
      url,
    });
  } catch (error) {
    console.log(error);
    res.status(500).json({
      error: error.message,
    });
  }
};

Server Side Implementation for Apexx Cloud

const ApexxCloud = require("@apexxcloud/sdk-node");

const storage = new ApexxCloud({
  accessKey: process.env.APEXXCLOUD_ACCESS_KEY,
  secretKey: process.env.APEXXCLOUD_SECRET_KEY,
  region: process.env.APEXXCLOUD_REGION,
  bucket: process.env.APEXXCLOUD_BUCKET,
});

const getSignedUrl = async (req, res) => {
  try {
    const { operation } = req.body;
    const { params } = req.body; // Contains key, mimeType, totalParts, etc.

    const signedUrl = await storage.files.getSignedUrl(
      operation,

      {
        ...params,
      }
    );

    res.send({
      url: signedUrl,
    });
  } catch (error) {
    res.status(500).send({
      error: error.message,
    });
  }
};

Core Libraries

AWS Core

Core implementation for AWS S3 and S3-compatible storage services (including Cloudflare R2).

import { AwsCore } from 'apexx-uploader-core';

// Initialize uploader
const uploader = new AwsCore();

// Simple upload
const response = await uploader.files.upload(file, getSignedUrl, {
  onProgress: (progress) => console.log(`Progress: ${progress}%`),
  onComplete: (response) => console.log('Complete:', response)
});

// Multipart upload
const response = await uploader.files.uploadMultipart(file, getSignedUrl, {
  partSize: 5 * 1024 * 1024, // 5MB chunks
  concurrency: 3,
  onProgress: (progress) => console.log(`Progress: ${progress}%`),
  onComplete: (response) => console.log('Complete:', response)
});

Methods

files.upload(file, getSignedUrl, options)
Simple upload for files under 5GB
files.uploadMultipart(file, getSignedUrl, options)
Multipart upload for large files, with concurrent part uploads

Apexx Cloud Core

Core implementation for Apexx Cloud storage service, with optimized upload handling.

import { ApexxCloudCore } from 'apexx-uploader-core';

// Initialize uploader
const uploader = new ApexxCloudCore();

// Simple upload
const response = await uploader.files.upload(file, getSignedUrl, {
  onProgress: (progress) => console.log(`Progress: ${progress}%`),
  onComplete: (response) => console.log('Complete:', response)
});

// Multipart upload
const response = await uploader.files.uploadMultipart(file, getSignedUrl, {
  partSize: 5 * 1024 * 1024, // 5MB chunks
  concurrency: 3,
  onProgress: (progress) => console.log(`Progress: ${progress}%`),
  onComplete: (response) => console.log('Complete:', response)
});

Common Options

interface UploadOptions {
  key?: string;                                              // Custom key for the file
  partSize?: number;                                         // Size of each part for multipart uploads
  concurrency?: number;                                      // Number of concurrent part uploads
  onProgress?: (progressData: ProgressData) => void;         // Progress callback
  onComplete?: (response: Response) => void;                 // Completion callback
  onError?: (error: Error) => void;                         // Error callback
  signal?: AbortSignal;                                     // AbortController signal for cancellation
}

Usage Examples

Use the hooks, Apexx Uploader handles the upload logic

import { useUploader } from "apexx-uploader-react";
 
 // Get signed url from your server
 const getSignedUrl = async (
    operation: string,
    params: Record<string, any>
  ) => {
    const response = await fetch(
      "http://localhost:3000/presigned-url-aws",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ operation, params }),
      }
    );
    return (await response.json()).url;
  };

function CustomMultiUploader() {
  const { 
    upload, 
    cancelUpload,
    cancelFileUpload,
    files,
    totalProgress,
    status 
  } = useUploader({
    provider: "aws",
    getSignedUrl: getSignedUrl
  });

  const handleFiles = async (event) => {
    const files = Array.from(event.target.files);
    await upload(files);
  };

  return (
    <div>
      <input type="file" multiple onChange={handleFiles} />
      <div>Total Progress: {totalProgress}%</div>
      {Object.entries(files).map(([name, file]) => (
        <div key={name}>
          {name}: {file.progress}%
          {file.status === "uploading" && (
            <button onClick={() => cancelFileUpload(name)}>
              Cancel
            </button>
          )}
        </div>
      ))}
    </div>
  );
}

Vanilla JavaScript

import { ApexxCloudCore, AwsCore } from 'apexx-uploader-core';

// Initialize uploader
const uploader = new AwsCore(); // or new ApexxCloudCore()

// Simple upload
const response = await uploader.files.upload(file, getSignedUrl, {
  onProgress: (progress) => console.log(`Progress: ${progress}%`),
  onComplete: (response) => console.log('Complete:', response)
});

Pre-built Components (Optional)

We provide optional pre-built components for quick implementation. These components are built using our hooks and can serve as examples for building your own custom components. You can find the source code for these components on GitHub.

// Using pre-built components
import { UploadDashboard } from "../components/uploadDashboard";
import { UploaderButton } from "../components/uploaderButton";

// Dashboard component with detailed UI
<UploadDashboard
  provider="aws"
  getSignedUrl={getSignedUrl}
  accept={["image/*"]}
  maxSize="50 MB"
  onComplete={(response) => console.log("Complete:", response)}
/>

// Simple button component
<UploaderButton
  provider="aws"
  getSignedUrl={getSignedUrl}
  accept={["image/*"]}
  maxSize="50 MB"
  onComplete={(response) => console.log("Complete:", response)}
/>