FluxMedia
Copy page
Open in ChatGPTOpen in Claude

Getting Started

Learn how to install and configure FluxMedia in your project.

Installation

Choose your package manager:

npm install @fluxmedia/core @fluxmedia/cloudinary
yarn add @fluxmedia/core @fluxmedia/cloudinary
pnpm add @fluxmedia/core @fluxmedia/cloudinary
bun add @fluxmedia/core @fluxmedia/cloudinary

Available Packages

Install only what you need:

# Core (required)
pnpm add @fluxmedia/core

# Pick a provider
pnpm add @fluxmedia/cloudinary  # Full featured with transformations
pnpm add @fluxmedia/s3          # AWS S3
pnpm add @fluxmedia/r2          # Cloudflare R2

# Optional: Official plugins
pnpm add @fluxmedia/plugins

# Optional: React integration
pnpm add @fluxmedia/react

Basic Usage

Node.js / Server

import { MediaUploader } from '@fluxmedia/core';
import { CloudinaryProvider } from '@fluxmedia/cloudinary';

// Create uploader with your provider
const uploader = new MediaUploader(
  new CloudinaryProvider({
    cloudName: process.env.CLOUDINARY_CLOUD_NAME!,
    apiKey: process.env.CLOUDINARY_API_KEY!,
    apiSecret: process.env.CLOUDINARY_API_SECRET!,
  })
);

// Upload a file
const result = await uploader.upload(fileBuffer, {
  folder: 'user-avatars',
  filename: 'avatar-123',
});

console.log(result.url); // https://res.cloudinary.com/...
console.log(result.id); // user-avatars/avatar-123
console.log(result.storageKey); // Provider-specific storage key
console.log(result.format); // jpg

Streaming Uploads

FluxMedia accepts multiple input types — not just File and Buffer:

import { createReadStream } from 'fs';

// Upload from Node.js Readable stream
const stream = createReadStream('/path/to/large-file.mp4');
const result = await uploader.upload(stream, {
  folder: 'videos',
  contentType: 'video/mp4',
});

// Upload from web ReadableStream
const response = await fetch('https://example.com/image.jpg');
const result = await uploader.upload(response.body!, {
  folder: 'imports',
});

With React

import { useMediaUpload } from '@fluxmedia/react';

function UploadButton() {
  const { upload, uploading, progress, result, error } = useMediaUpload({
    mode: 'signed',
    signUrlEndpoint: '/api/upload/sign',
  });

  return (
    <input
      type="file"
      disabled={uploading}
      onChange={(e) => {
        const file = e.target.files?.[0];
        if (file) upload(file);
      }}
    />
  );
}

Using Multiple Providers

FluxMedia lets you use multiple providers in the same application with a consistent API:

// Cloudinary for media
const uploader = new MediaUploader(
  new CloudinaryProvider({ ... })
);

// S3 for archives — same interface
import { S3Provider } from '@fluxmedia/s3';

const uploader = new MediaUploader(
  new S3Provider({
    region: 'us-east-1',
    bucket: 'my-bucket',
    accessKeyId: process.env.AWS_ACCESS_KEY!,
    secretAccessKey: process.env.AWS_SECRET_KEY!,
  })
);

// All your upload code stays exactly the same
await uploader.upload(file, { folder: 'uploads' });

Fallback Providers

Configure automatic failover when the primary provider is unavailable:

import { MediaUploader, MediaErrorCode } from '@fluxmedia/core';

const uploader = new MediaUploader(
  new CloudinaryProvider({ ... }),  // Primary
  [],                                // No plugins
  {
    fallbackProvider: new S3Provider({ ... }),  // Fallback
    fallbackOnErrors: [
      MediaErrorCode.NETWORK_ERROR,
      MediaErrorCode.RATE_LIMITED,
      MediaErrorCode.PROVIDER_ERROR,
    ],
    onFallback: (error, fallback) => {
      console.warn(`Using ${fallback.name} due to: ${error.message}`);
    },
  }
);

// If Cloudinary fails with a qualifying error, S3 is used automatically
const result = await uploader.upload(file, { folder: 'uploads' });

Upload with Abort

Cancel in-flight uploads using AbortController:

const controller = new AbortController();

// Cancel after 30 seconds
setTimeout(() => controller.abort(), 30000);

const result = await uploader.upload(file, {
  folder: 'uploads',
  signal: controller.signal,
});

Progress Tracking

Track upload progress at two levels:

const result = await uploader.upload(file, {
  folder: 'uploads',
  onProgress: (percent) => {
    // Normalized 0-100 percentage
    progressBar.style.width = `${percent}%`;
  },
  onByteProgress: (loaded, total) => {
    // Raw byte counts for precise tracking
    console.log(`${loaded}/${total} bytes`);
  },
});

Feature Detection

Check if a provider supports specific features:

if (uploader.supports('transformations.resize')) {
  // Apply resize transformation
  const url = uploader.getUrl(id, { width: 200, height: 200 });
}

if (uploader.supports('capabilities.videoProcessing')) {
  // Provider supports video processing
}

Next Steps