Skip to main content

Introduction

WIP

A modular, strategy-based file upload engine with React bindings.

What is Duck Upload?

Duck Upload is a file upload engine with strategy plugins and thin React bindings. The shape is similar to React Query: a core client that owns state and scheduling, strategies that handle the transport, and a React adapter.

Package Structure

src/
  core/           # engine + contracts + persistence + utilities
  strategies/     # protocol implementations + registry helper
  react/          # provider + hooks
src/
  core/           # engine + contracts + persistence + utilities
  strategies/     # protocol implementations + registry helper
  react/          # provider + hooks

Architecture at a Glance

Loading diagram...

Quick Lifecycle

  1. addFiles dispatches files into the store with validation
  2. start or autoStart queues the item for upload
  3. The matched strategy uploads bytes, reporting progress
  4. complete finalizes the upload and returns a typed result
  5. Public events emit from a single transition layer

Quick Start

import { createUploadStore } from '@gentleduck/upload/core'
import { createStrategyRegistry, PostStrategy, multipartStrategy } from '@gentleduck/upload/strategies'
 
const strategies = createStrategyRegistry()
strategies.set(PostStrategy())
strategies.set(multipartStrategy())
 
const store = createUploadStore({
  api, // implements UploadApi
  strategies,
  config: {
    autoStart: (purpose) => purpose === 'avatar',
  },
})
import { createUploadStore } from '@gentleduck/upload/core'
import { createStrategyRegistry, PostStrategy, multipartStrategy } from '@gentleduck/upload/strategies'
 
const strategies = createStrategyRegistry()
strategies.set(PostStrategy())
strategies.set(multipartStrategy())
 
const store = createUploadStore({
  api, // implements UploadApi
  strategies,
  config: {
    autoStart: (purpose) => purpose === 'avatar',
  },
})

Wait For Results

const { items } = store.getSnapshot()
const localIds = Array.from(items.keys())
 
const outcomes = await store.waitFor(localIds)
for (const outcome of outcomes) {
  if (outcome.status === 'completed') {
    console.log(outcome.result.fileId, outcome.result.key)
  }
}
const { items } = store.getSnapshot()
const localIds = Array.from(items.keys())
 
const outcomes = await store.waitFor(localIds)
for (const outcome of outcomes) {
  if (outcome.status === 'completed') {
    console.log(outcome.result.fileId, outcome.result.key)
  }
}

Architecture Goals

  • One core with immutable state updates and centralized event emission.
  • Strategies are pluggable; they do not leak into core.
  • The React layer consumes store APIs and nothing else.
  • Types live next to their module (no mega types folder).

What This Documentation Covers

  • Core: engine behavior, state machine, contracts, persistence.
  • Strategies: POST and multipart protocols, strategy registry.
  • React: provider, hooks, UI patterns.
  • Utilities: shared helpers and guards.
  • Design: architecture decisions and rationale.

Start with Core Overview, then Engine, then React Overview.