Installation
Get started with @gentleduck/upload in your project.
Install the Package
Choose your preferred package manager:
@gentleduck/upload@gentleduck/uploadOr install manually:
bun add @gentleduck/uploadbun add @gentleduck/uploadnpm install @gentleduck/upload
npm install @gentleduck/upload
pnpm add @gentleduck/uploadpnpm add @gentleduck/uploadBasic Setup
1. Create a Strategy Registry
Register the upload strategies your app needs:
import { createStrategyRegistry, PostStrategy, multipartStrategy } from '@gentleduck/upload/strategies'
const strategies = createStrategyRegistry()
strategies.set(PostStrategy())
strategies.set(multipartStrategy())import { createStrategyRegistry, PostStrategy, multipartStrategy } from '@gentleduck/upload/strategies'
const strategies = createStrategyRegistry()
strategies.set(PostStrategy())
strategies.set(multipartStrategy())2. Implement the Upload API
Your backend adapter must implement the UploadApi interface:
import type { UploadApi } from '@gentleduck/upload/core'
const api: UploadApi = {
createIntent: async ({ file, purpose }) => {
// Call your backend to create an upload intent
const res = await fetch('/api/uploads/intent', {
method: 'POST',
body: JSON.stringify({ fileName: file.name, purpose }),
})
return res.json()
},
complete: async ({ fileId }) => {
// Notify your backend that the upload finished
const res = await fetch(`/api/uploads/${fileId}/complete`, { method: 'POST' })
return res.json()
},
}import type { UploadApi } from '@gentleduck/upload/core'
const api: UploadApi = {
createIntent: async ({ file, purpose }) => {
// Call your backend to create an upload intent
const res = await fetch('/api/uploads/intent', {
method: 'POST',
body: JSON.stringify({ fileName: file.name, purpose }),
})
return res.json()
},
complete: async ({ fileId }) => {
// Notify your backend that the upload finished
const res = await fetch(`/api/uploads/${fileId}/complete`, { method: 'POST' })
return res.json()
},
}3. Create the Upload Store
import { createUploadStore } from '@gentleduck/upload/core'
const store = createUploadStore({
api,
strategies,
config: {
maxConcurrentUploads: 3,
autoStart: (purpose) => purpose === 'avatar',
},
})import { createUploadStore } from '@gentleduck/upload/core'
const store = createUploadStore({
api,
strategies,
config: {
maxConcurrentUploads: 3,
autoStart: (purpose) => purpose === 'avatar',
},
})4. Connect to React (Optional)
If you are using React, wrap your app with the UploadProvider:
import { UploadProvider } from '@gentleduck/upload/react'
function App() {
return (
<UploadProvider store={store}>
<YourUploadUI />
</UploadProvider>
)
}import { UploadProvider } from '@gentleduck/upload/react'
function App() {
return (
<UploadProvider store={store}>
<YourUploadUI />
</UploadProvider>
)
}Then use the useUploader hook in your components:
import { useUploader } from '@gentleduck/upload/react'
function UploadList() {
const { items, dispatch } = useUploader()
return (
<div>
<input
type="file"
onChange={(e) => {
dispatch({ type: 'addFiles', files: Array.from(e.target.files!), purpose: 'doc' })
}}
/>
{items.map((item) => (
<div key={item.localId}>{item.file?.name} - {item.phase}</div>
))}
</div>
)
}import { useUploader } from '@gentleduck/upload/react'
function UploadList() {
const { items, dispatch } = useUploader()
return (
<div>
<input
type="file"
onChange={(e) => {
dispatch({ type: 'addFiles', files: Array.from(e.target.files!), purpose: 'doc' })
}}
/>
{items.map((item) => (
<div key={item.localId}>{item.file?.name} - {item.phase}</div>
))}
</div>
)
}Import Paths
The package exposes three entry points:
| Import | Description |
|---|---|
@gentleduck/upload/core | Engine, contracts, persistence, utilities |
@gentleduck/upload/strategies | Strategy implementations and registry |
@gentleduck/upload/react | React provider and hooks |