← All @molecule/* packages · App templates

@molecule/app-file-upload

Core interface · file-upload · App (browser) · v1.0.1 · Apache-2.0

File upload core interface for molecule.dev — progress tracking, validation, multi-file queues

npm install @molecule/app-file-upload

npm · Source on GitHub

How it works

@molecule/app-file-upload is the file-upload core interface on the app (browser) side: the API your app calls, with no vendor inside.

Choose the implementation by bonding one of its 1 provider: @molecule/app-file-upload-filepond.

import { createUploader } from '@molecule/app-file-upload'

const uploader = createUploader({
  destination: { url: '/api/upload' },
  validation: { maxSize: 10 * 1024 * 1024, acceptedTypes: ['image/*'] },
  multiple: true,
  autoUpload: true,
  events: {
    onComplete: (file) => console.log(`Uploaded: ${file.name}`),
  },
})

Providers (1): @molecule/app-file-upload-filepond

Works with: @molecule/app-bond

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

File upload core interface for molecule.dev.

Provides a framework-agnostic contract for file uploads with progress tracking, validation, drag-and-drop support, and multi-file queues. Bond a provider (e.g. @molecule/app-file-upload-filepond) at startup, then use {@link createUploader} anywhere.

Quick Start

import { createUploader } from '@molecule/app-file-upload'

const uploader = createUploader({
  destination: { url: '/api/upload' },
  validation: { maxSize: 10 * 1024 * 1024, acceptedTypes: ['image/*'] },
  multiple: true,
  autoUpload: true,
  events: {
    onComplete: (file) => console.log(`Uploaded: ${file.name}`),
  },
})

Type

core

Installation

npm install @molecule/app-file-upload @molecule/app-bond

API

Interfaces

FileUploadEvents

Event callbacks for the file upload lifecycle.

interface FileUploadEvents {
  /** Called when files are added to the upload queue. */
  onFilesAdded?: (files: UploadFile[]) => void
  /** Called when a file is removed from the queue. */
  onFileRemoved?: (file: UploadFile) => void
  /** Called when a file's upload progress changes. */
  onProgress?: (file: UploadFile, progress: number) => void
  /** Called when a file upload completes successfully. */
  onComplete?: (file: UploadFile) => void
  /** Called when a file upload fails. */
  onError?: (file: UploadFile, error: string) => void
  /** Called when all files in the queue have been processed. */
  onAllComplete?: (files: UploadFile[]) => void
  /** Called when a file fails validation. */
  onValidationError?: (file: UploadFile, errors: string[]) => void
}

FileUploadInstance

A live file upload instance exposing queue management and upload control.

interface FileUploadInstance {
  // -- Queue management ---------------------------------------------------

  /**
   * Adds files to the upload queue.
   *
   * @param files - Files to add (browser `File` objects).
   * @returns The `UploadFile` representations that were added (after validation).
   */
  addFiles(files: File[]): UploadFile[]

  /**
   * Removes a file from the upload queue.
   *
   * @param fileId - The ID of the file to remove.
   */
  removeFile(fileId: string): void

  /** Removes all files from the upload queue. */
  clearFiles(): void

  /** Returns all files currently in the upload queue. */
  getFiles(): UploadFile[]

  /**
   * Returns a single file by ID, or `undefined` if not found.
   *
   * @param fileId - The ID of the file to retrieve.
   * @returns The file, or `undefined`.
   */
  getFile(fileId: string): UploadFile | undefined

  // -- Upload control -----------------------------------------------------

  /** Starts uploading all queued files that are in `'idle'` status. */
  upload(): void

  /**
   * Cancels the upload for a specific file.
   *
   * @param fileId - The ID of the file whose upload to cancel.
   */
  cancelUpload(fileId: string): void

  /** Cancels all active uploads. */
  cancelAll(): void

  /**
   * Retries a failed upload.
   *
   * @param fileId - The ID of the file to retry.
   */
  retry(fileId: string): void

  /** Retries all failed uploads. */
  retryAll(): void

  // -- State queries ------------------------------------------------------

  /** Returns `true` if any file is currently uploading. */
  isUploading(): boolean

  /**
   * Returns the overall upload progress as a percentage (0–100)
   * across all files.
   */
  getTotalProgress(): number

  // -- Lifecycle ----------------------------------------------------------

  /** Releases resources held by the upload instance. */
  destroy(): void
}

FileUploadOptions

Configuration for creating a file upload instance.

interface FileUploadOptions {
  /** Upload destination configuration. */
  destination: UploadDestination
  /** File validation constraints. */
  validation?: FileValidation
  /** Whether to allow multiple file selection. Defaults to `true`. */
  multiple?: boolean
  /** Whether to start uploading immediately when files are added. Defaults to `false`. */
  autoUpload?: boolean
  /** Maximum number of concurrent uploads. Defaults to `3`. */
  maxConcurrent?: number
  /** Whether to generate image previews for image files. Defaults to `false`. */
  imagePreview?: boolean
  /** Maximum width/height in pixels for image previews. Defaults to `200`. */
  imagePreviewMaxSize?: number
  /** Event callbacks. */
  events?: FileUploadEvents
}

FileUploadProvider

Contract that bond packages must implement to provide file upload functionality.

interface FileUploadProvider {
  /**
   * Creates a new file upload instance from the given options.
   *
   * @param options - Upload configuration including destination, validation, and events.
   * @returns A file upload instance for managing queued files and uploads.
   */
  createUploader(options: FileUploadOptions): FileUploadInstance
}

FileValidation

Validation constraints applied to files before uploading.

interface FileValidation {
  /** Maximum file size in bytes. */
  maxSize?: number
  /** Minimum file size in bytes. */
  minSize?: number
  /** Accepted MIME types (e.g. `['image/png', 'image/jpeg']`). */
  acceptedTypes?: string[]
  /** Accepted file extensions including the dot (e.g. `['.png', '.jpg']`). */
  acceptedExtensions?: string[]
  /** Maximum number of files allowed when multi-file is enabled. */
  maxFiles?: number
  /**
   * Custom validation function. Return `null` for valid, or an error
   * message string for invalid.
   *
   * @param file - The file to validate.
   * @returns `null` if valid, or an error message string.
   */
  custom?: (file: UploadFile) => string | null
}

UploadDestination

Configuration for where and how files are uploaded.

interface UploadDestination {
  /** Target URL for the upload request. */
  url: string
  /** HTTP method to use. Defaults to `'POST'`. */
  method?: 'POST' | 'PUT' | 'PATCH'
  /** Additional HTTP headers to include with the upload request. */
  headers?: Record<string, string>
  /** Form field name for the file data. Defaults to `'file'`. */
  fieldName?: string
  /** Additional form data to include with the upload request. */
  additionalData?: Record<string, string>
  /**
   * Custom function to extract the result identifier from the upload
   * response. Called after a successful upload.
   *
   * @param response - The raw response body.
   * @returns The result identifier string.
   */
  parseResponse?: (response: unknown) => string
}

UploadFile

Represents a file in the upload queue, including metadata and progress.

interface UploadFile {
  /** Unique identifier for this file within the upload instance. */
  id: string
  /** Original file name. */
  name: string
  /** File size in bytes. */
  size: number
  /** MIME type of the file. */
  type: string
  /** Current upload status. */
  status: FileUploadStatus
  /** Upload progress as a percentage (0–100). */
  progress: number
  /** Error message if `status` is `'error'`. */
  error?: string
  /** URL or identifier of the uploaded file after completion. */
  result?: string
  /** The source `File` object when available (browser environments). */
  source?: File
  /** Optional thumbnail/preview data URL for image files. */
  preview?: string
}

Types

FileUploadStatus

Possible states of a file during the upload lifecycle.

type FileUploadStatus =
  'idle' | 'preparing' | 'uploading' | 'processing' | 'complete' | 'error' | 'cancelled'

Functions

createUploader(options)

Creates a new file upload instance using the bonded provider.

function createUploader(options: FileUploadOptions): FileUploadInstance
  • options — Upload configuration including destination, validation, and events.

Returns: A file upload instance for managing queued files and uploads.

getProvider()

Retrieves the bonded file upload provider, throwing if none is configured.

function getProvider(): FileUploadProvider

Returns: The bonded file upload provider.

hasProvider()

Checks whether a file upload provider is currently bonded.

function hasProvider(): boolean

Returns: true if a file upload provider is bonded.

setProvider(provider)

Registers a file upload provider as the active singleton. Called by bond packages (e.g. @molecule/app-file-upload-filepond) during app startup.

function setProvider(provider: FileUploadProvider): void
  • provider — The file upload provider implementation to bond.

Available Providers

ProviderPackage
File Upload@molecule/app-file-upload-filepond

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-bond ^1.0.1

Runtime Dependencies

  • @molecule/app-bond

  • Client-side validation is UX, NOT a security boundary. It gives instant feedback, but a request can skip the uploader entirely — the SERVER must re-validate size, type, and content of every upload, and enforce authorization.

  • Uploads do NOT go through the app's HTTP client. The provider sends directly to destination.url, so the HTTP client's baseURL and auth interceptors are not applied: give the full relative path (e.g. '/api/upload' — never an absolute http://localhost… host), and pass auth via destination.headers if the endpoint requires it.

  • autoUpload defaults to false — without it, call upload() on the instance or files sit queued forever.

  • Wire the bond once at startup (setProvider(provider) from e.g. @molecule/app-file-upload-filepond); createUploader throws with the fix named if nothing is bonded. Any upload UI you render (drop zone, progress, errors) styles via getClassMap()/cm.* with text through t('key', values, { defaultValue }).

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • Picking a valid file via the picker starts the upload and shows per-file progress through to a completed state.
  • Dragging and dropping a file onto the drop zone uploads it the same way.
  • The completed upload appears wherever this app uses it (file list, avatar, attachment) — completion is not just a toast.
  • A file that fails validation (too large, wrong type) is rejected with a visible message and is never sent to the server.
  • With multiple files (if enabled), each file's progress and completion track independently and all complete.
  • Canceling/removing a queued or in-flight file stops it and clears it from the queue.