AuraImage

Uploader

Drop-and-paste upload widget with progress, retry, and a multi-file queue.

<AuraUploader /> is a Shadcn-registry component you copy into your project. It handles drag-and-drop, click-to-browse, paste-from-clipboard, a multi-file queue with per-row progress, cancel/retry, and drag-reorder of queued files.

Uploads go directly to cdn.auraimage.ai — your backend only mints the signature, never handles the bytes.

Install

npx shadcn@latest add https://auraimage.ai/registry/uploader.json

This copies src/components/aura/uploader.tsx and pulls in its lucide-react and shadcn cn() deps. It reads your CDN base URL from NEXT_PUBLIC_AURA_CDN_URL.

Usage

import { AuraUploader } from '@/components/aura/uploader';

export default function ProfilePage() {
  return (
    <AuraUploader
      project='my-app'
      onUpload={(result) => {
        console.log(result.url);      // final CDN URL
        console.log(result.key);      // store this for setVisibility / getSignedUrl
        console.log(result.blurhash); // store for placeholder rendering
      }}
      maxSize='5mb'
      multiple
    />
  );
}

Signature delivery

The component supports three ways to obtain a signature, resolved in this precedence order:

  1. getSignature — async function. Highest precedence. Use for custom auth flows, signature caching, or refresh logic.
  2. signature — pre-computed string. Useful from a Server Component that mints the signature at render time.
  3. project — project name. The component POSTs { project, filename, contentType, size } to /api/aura/sign on your own backend and expects { signature } back.

You only need one. The most common pattern is project="my-app" + a small route handler:

app/api/aura/sign/route.ts
import { AuraImage } from '@auraimage/sdk';

const aura = new AuraImage({
  secretKey: process.env.AURA_SECRET_KEY!,
  projectName: process.env.NEXT_PUBLIC_AURA_PROJECT_NAME!
});

export async function POST() {
  const signature = await aura.signUpload({
    maxSize: '5mb',
    allowedTypes: ['image/*'],
    expiresIn: 3600
  });
  return Response.json({ signature });
}

For RSC-minted signatures:

import { AuraUploader } from '@/components/aura/uploader';
import { aura } from '@/lib/aura';

export default async function Page() {
  const signature = await aura.signUpload({ maxSize: '5mb' });
  return <AuraUploader signature={signature} />;
}

For custom auth (Firebase, Clerk, …):

<AuraUploader
  getSignature={async () => {
    const token = await getFirebaseIdToken();
    const res = await fetch('/api/sign', { headers: { Authorization: `Bearer ${token}` } });
    return (await res.json()).signature;
  }}
/>

Props

PropTypeDefaultDescription
onUpload(result: UploadResult) => voidCalled once per successful file.
onError(error: Error) => voidCalled on validation failure (size cap) or upload failure.
maxSizestring"5mb"Client-side size cap. The edge enforces its own limit from the signature — keep them in sync.
acceptstring"image/*"MIME filter for the file picker.
multiplebooleanfalseAllow multiple files. When false, dropping a new file replaces the queue.
concurrencynumber3Max simultaneous uploads.
classNamestringExtra classes merged onto the dropzone container.
getSignature() => Promise<string> | stringAsync signature provider (highest precedence).
signaturestringPre-computed signature.
projectstringProject name. Triggers the /api/aura/sign convention.

UploadResult shape (matches the upload response):

interface UploadResult {
  url: string;
  key: string;
  blurhash: string;
  width: number;
  height: number;
  format: string;
  size: number;
}

Behavior

  • Drag-and-drop with an outlined active state on the whole container.
  • Click to browse — the container is keyboard-focusable (Enter / Space opens the picker).
  • Paste-from-clipboard — while the uploader has focus, pasted images are queued automatically.
  • Per-row UI — thumbnail, filename, byte size, 2 px progress bar, status, and per-row remove / cancel / retry.
  • Drag-reorder of queued (not-yet-uploaded) items.
  • Concurrency — uploads run in parallel up to concurrency (default 3).
  • Copy-URL pill on each successful row.

All thumbnails use object URLs that are revoked on unmount or removal — no leaks.

Live demo

The landing page runs a real <AuraUploader> against production. Drop an image into the Edge proxy upload tile on auraimage.ai to see the full flow.