@better-s3/react 3.1049.0 → 3.1051.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -58
- package/dist/helpers/format-accept-labels.d.ts +2 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,75 +1,30 @@
|
|
|
1
1
|
# @better-s3/react
|
|
2
2
|
|
|
3
|
-
Headless React hooks for S3 upload, download, and delete
|
|
3
|
+
Headless React hooks for S3 upload, download, and delete flows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Full documentation: [better-s3-docs.vercel.app](https://better-s3-docs.vercel.app/docs/react)
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
pnpm add @better-s3/react @better-s3/
|
|
10
|
+
pnpm add @better-s3/react @better-s3/core
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { createS3Api } from "@better-s3/core";
|
|
17
|
-
|
|
18
|
-
const api = createS3Api();
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Hooks
|
|
22
|
-
|
|
23
|
-
| Hook | Use case |
|
|
24
|
-
| ------------------------ | --------------------------------------- |
|
|
25
|
-
| `useUploadControls` | Single file — picker + drag-and-drop |
|
|
26
|
-
| `useMultiUploadControls` | Multiple files — picker + drag-and-drop |
|
|
27
|
-
| `useUpload` | Single file — call `upload()` yourself |
|
|
28
|
-
| `useMultiUpload` | Batch — call `upload()` yourself |
|
|
29
|
-
| `useDownload` | Presigned URL → native browser download |
|
|
30
|
-
| `useFetchDownload` | Fetch with progress and cancel |
|
|
31
|
-
| `useDelete` | Two-step delete with confirmation |
|
|
32
|
-
|
|
33
|
-
### Upload — single file
|
|
34
|
-
|
|
35
|
-
```tsx
|
|
36
|
-
const { openFilePicker, inputProps, dropHandlers, progress, isUploading } =
|
|
37
|
-
useUploadControls({
|
|
38
|
-
api,
|
|
39
|
-
objectKey: (file) => `uploads/${file.name}`,
|
|
40
|
-
accept: ["image/*"],
|
|
41
|
-
maxFileSize: 10 * 1024 * 1024,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// <input {...inputProps} />
|
|
45
|
-
// <div {...dropHandlers} onClick={openFilePicker}>…</div>
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Upload — multiple files
|
|
13
|
+
## Minimal setup
|
|
49
14
|
|
|
50
15
|
```tsx
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
api,
|
|
54
|
-
objectKey: (file) => `uploads/${file.name}`,
|
|
55
|
-
maxFiles: 5,
|
|
56
|
-
concurrentFiles: 3,
|
|
57
|
-
});
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Download
|
|
16
|
+
import { createS3Api } from "@better-s3/core";
|
|
17
|
+
import { S3Provider, useUploadControls } from "@better-s3/react";
|
|
61
18
|
|
|
62
|
-
|
|
63
|
-
const { download } = useDownload({ api });
|
|
64
|
-
download("uploads/photo.jpg", "photo.jpg");
|
|
65
|
-
```
|
|
19
|
+
const client = createS3Api();
|
|
66
20
|
|
|
67
|
-
|
|
21
|
+
// App root
|
|
22
|
+
<S3Provider client={client}>{children}</S3Provider>;
|
|
68
23
|
|
|
69
|
-
|
|
70
|
-
const {
|
|
71
|
-
|
|
72
|
-
|
|
24
|
+
// In a component
|
|
25
|
+
const { openFilePicker, inputProps } = useUploadControls({
|
|
26
|
+
objectKey: (file) => `uploads/${file.name}`,
|
|
27
|
+
});
|
|
73
28
|
```
|
|
74
29
|
|
|
75
30
|
## License
|
package/dist/helpers/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { createS3Client } from "./api";
|
|
|
3
3
|
export { S3Provider, useS3Client, S3Context } from "./s3-provider";
|
|
4
4
|
export { createLocalStorageStore, createMemoryStore } from "./store";
|
|
5
5
|
export { uploadFile, uploadFiles, type UploadEngineCallbacks, type FileItem, type FileItemStatus, type MultiUploadCallbacks, } from "./upload";
|
|
6
|
-
export { formatUploadProgress, formatSpeed, formatEta, createSpeedTracker, type SpeedTracker, } from "./helpers";
|
|
6
|
+
export { formatAcceptLabels, formatUploadProgress, formatSpeed, formatEta, createSpeedTracker, type SpeedTracker, } from "./helpers";
|
|
7
7
|
export { useUpload, type UseUploadOptions, type UseUploadState, type UseUploadReturn, } from "./hooks/use-upload";
|
|
8
8
|
export { useMultiUpload, type UseMultiUploadOptions, type UseMultiUploadState, type UseMultiUploadReturn, } from "./hooks/use-multi-upload";
|
|
9
9
|
export { useUploadControls, type UseUploadControlsOptions, type UseUploadControlsReturn, } from "./hooks/use-upload-controls";
|
package/dist/index.js
CHANGED
|
@@ -517,6 +517,33 @@ async function uploadFiles(api, items, config = {}, callbacks = {}, signal, getR
|
|
|
517
517
|
await Promise.all(workers);
|
|
518
518
|
return results;
|
|
519
519
|
}
|
|
520
|
+
|
|
521
|
+
// src/helpers/format-accept-labels.ts
|
|
522
|
+
function formatAcceptLabel(type) {
|
|
523
|
+
if (type.startsWith(".")) {
|
|
524
|
+
const ext = type.slice(1).toLowerCase();
|
|
525
|
+
return ext === "jpg" || ext === "jpeg" ? "JPEG" : ext.toUpperCase();
|
|
526
|
+
}
|
|
527
|
+
if (type.endsWith("/*")) {
|
|
528
|
+
const base = type.slice(0, -2);
|
|
529
|
+
return base.charAt(0).toUpperCase() + base.slice(1) + "s";
|
|
530
|
+
}
|
|
531
|
+
const sub = type.split("/")[1];
|
|
532
|
+
return sub ? sub.toUpperCase() : type;
|
|
533
|
+
}
|
|
534
|
+
function formatAcceptLabels(accept) {
|
|
535
|
+
if (!accept?.length) return [];
|
|
536
|
+
const labels = [];
|
|
537
|
+
const seen = /* @__PURE__ */ new Set();
|
|
538
|
+
for (const type of accept) {
|
|
539
|
+
const label = formatAcceptLabel(type);
|
|
540
|
+
if (!seen.has(label)) {
|
|
541
|
+
seen.add(label);
|
|
542
|
+
labels.push(label);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return labels;
|
|
546
|
+
}
|
|
520
547
|
function formatUploadProgress(loaded, total, percent) {
|
|
521
548
|
const loadedStr = formatFileSize(loaded);
|
|
522
549
|
if (!total) return loadedStr;
|
|
@@ -1328,6 +1355,6 @@ function useDelete(options) {
|
|
|
1328
1355
|
};
|
|
1329
1356
|
}
|
|
1330
1357
|
|
|
1331
|
-
export { S3Context, S3Provider, S3UploadError, createLocalStorageStore, createMemoryStore, createS3Client, createSpeedTracker, formatEta, formatSpeed, formatUploadProgress, uploadFile, uploadFiles, useDelete, useDownload, useFetchDownload, useMultiUpload, useMultiUploadControls, useS3Client, useUpload, useUploadControls };
|
|
1358
|
+
export { S3Context, S3Provider, S3UploadError, createLocalStorageStore, createMemoryStore, createS3Client, createSpeedTracker, formatAcceptLabels, formatEta, formatSpeed, formatUploadProgress, uploadFile, uploadFiles, useDelete, useDownload, useFetchDownload, useMultiUpload, useMultiUploadControls, useS3Client, useUpload, useUploadControls };
|
|
1332
1359
|
//# sourceMappingURL=index.js.map
|
|
1333
1360
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/error.ts","../src/api.ts","../src/s3-provider.tsx","../src/store/local-storage-store.ts","../src/store/memory-store.ts","../src/upload/constants.ts","../src/upload/retry.ts","../src/upload/simple.ts","../src/upload/part.ts","../src/upload/multipart.ts","../src/upload/upload-file.ts","../src/upload/upload-files.ts","../src/helpers/format-upload-progress.ts","../src/helpers/format-speed.ts","../src/helpers/format-eta.ts","../src/helpers/speed-tracker.ts","../src/internal-helpers.ts","../src/hooks/use-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-upload-controls.ts","../src/hooks/use-multi-upload-controls.ts","../src/hooks/use-download.ts","../src/hooks/use-fetch-download.ts","../src/hooks/use-delete.ts"],"names":["parts","formatFileSize","useContext","useRef","INITIAL_PROGRESS","INITIAL_STATE","useState","useCallback","validateFile"],"mappings":"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","file":"index.js","sourcesContent":["import type { UploadPhase } from \"./upload\";\n\n/**\n * Structured error thrown by the upload engine.\n *\n * - `code` — machine-readable error code (e.g. `\"VALIDATION_ERROR\"`, `\"NETWORK_ERROR\"`)\n * - `statusCode` — HTTP status code when the error originated from a server response\n * - `phase` — upload phase in which the error occurred\n */\nexport class S3UploadError extends Error {\n readonly code: string;\n readonly statusCode: number | undefined;\n readonly phase: UploadPhase | undefined;\n\n constructor(\n message: string,\n code: string,\n statusCode?: number,\n phase?: UploadPhase,\n ) {\n super(message);\n this.name = \"S3UploadError\";\n this.code = code;\n this.statusCode = statusCode;\n this.phase = phase;\n }\n}\n","/**\n * Client-side factory for the better-s3 presign API.\n *\n * Accepts an `S3Api` object — implement each method to call your own backend\n * endpoint, tRPC mutation, GraphQL query, or anything else. The object is\n * returned as-is; `createS3Client` just enforces the type contract.\n *\n * If you are using the default better-s3 route layout, use `createS3Api` from\n * `@better-s3/core` — it builds a standard fetch client from a base path.\n *\n * @example\n * ```ts\n * import { createS3Client } from \"@better-s3/react\";\n *\n * export const s3Client = createS3Client({\n * async upload(payload) {\n * return fetch(\"/api/storage/presign\", { method: \"POST\", body: JSON.stringify(payload) })\n * .then(r => r.json());\n * },\n * async confirm(payload) { ... },\n * async download(key, options) { ... },\n * async delete(key) { ... },\n * multipart: { init, signPart, listParts, complete, abort },\n * });\n * ```\n */\nimport type { S3Api } from \"@better-s3/core\";\n\nexport function createS3Client(input: S3Api): S3Api {\n return input;\n}\n","\"use client\";\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\n\n/**\n * Internal context — use `S3Provider` to supply and `useS3Client` to consume.\n * Exported so hooks can call `useContext(S3Context)` directly without throwing\n * when `api` is passed explicitly.\n */\nexport const S3Context = createContext<S3Api | null>(null);\n\n/**\n * Provides an `S3Api` client to all child hooks and UI components.\n *\n * Wrap your app (or a sub-tree) once; hooks no longer need `api` passed\n * individually.\n *\n * @example\n * ```tsx\n * // With @better-s3/server:\n * import { createS3Api } from \"@better-s3/core\";\n * import { S3Provider } from \"@better-s3/react\";\n *\n * const s3Client = createS3Api();\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return <S3Provider client={s3Client}>{children}</S3Provider>;\n * }\n *\n * // Custom base path:\n * import { createS3Api } from \"@better-s3/core\";\n *\n * const s3Client = createS3Api(\"/api/my-s3\");\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return <S3Provider client={s3Client}>{children}</S3Provider>;\n * }\n * ```\n */\nexport function S3Provider({\n client,\n children,\n}: {\n client: S3Api;\n children: ReactNode;\n}) {\n return <S3Context.Provider value={client}>{children}</S3Context.Provider>;\n}\n\n/**\n * Returns the `S3Api` client from the nearest `S3Provider`.\n * Throws if called outside a provider and no `api` prop was given to the hook.\n *\n * @throws if no `S3Provider` is found in the tree.\n */\nexport function useS3Client(): S3Api {\n const ctx = useContext(S3Context);\n if (!ctx) {\n throw new Error(\n \"[better-s3] No S3Api client found. \" +\n \"Either wrap your app with <S3Provider client={...}> or pass `api` directly to the hook.\",\n );\n }\n return ctx;\n}\n","import type { StoredUpload, UploadStore } from \"../types/upload-store\";\n\nconst STORAGE_PREFIX = \"better-s3:upload:\";\n\n/**\n * Default `UploadStore` implementation backed by `localStorage`.\n * Stores one pending upload per S3 object key.\n *\n * Falls back silently when `localStorage` is unavailable (SSR, private\n * browsing with full quota, or environments without a `window` object).\n */\nexport function createLocalStorageStore(): UploadStore {\n return {\n get(key, fileSize) {\n try {\n const raw = localStorage.getItem(STORAGE_PREFIX + key);\n if (!raw) return null;\n const stored = JSON.parse(raw) as StoredUpload;\n // Reject if the stored size doesn't match — different file for the same key.\n return stored.fileSize === fileSize ? stored : null;\n } catch {\n return null;\n }\n },\n\n set(upload) {\n try {\n localStorage.setItem(\n STORAGE_PREFIX + upload.key,\n JSON.stringify(upload),\n );\n } catch {\n // localStorage unavailable (SSR, quota exceeded) — silently skip.\n }\n },\n\n delete(key) {\n try {\n localStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // ignore\n }\n },\n };\n}\n","import type { StoredUpload, UploadStore } from \"../types/upload-store\";\n\n/**\n * In-memory `UploadStore` — safe for SSR and server-component environments.\n *\n * State is cleared on page reload. Useful as a fallback, for testing, or\n * when you want session-scoped resume without touching `localStorage`.\n *\n * @example\n * ```ts\n * const store = createMemoryStore();\n * useUpload({ api, uploadStore: store });\n * ```\n */\nexport function createMemoryStore(): UploadStore {\n const map = new Map<string, StoredUpload>();\n\n return {\n get(key, fileSize) {\n const stored = map.get(key);\n if (!stored) return null;\n return stored.fileSize === fileSize ? stored : null;\n },\n\n set(upload) {\n map.set(upload.key, upload);\n },\n\n delete(key) {\n map.delete(key);\n },\n };\n}\n","export const DEFAULT_MULTIPART_THRESHOLD = 50 * 1024 * 1024; // 50 MB\nexport const DEFAULT_PART_SIZE = 5 * 1024 * 1024; // 5 MB\nexport const MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY = 1_000; // ms\nexport const DEFAULT_CONCURRENT_PARTS = 2;\nexport const DEFAULT_CONCURRENT_FILES = 2;\n","import { MAX_RETRIES, RETRY_BASE_DELAY } from \"./constants\";\nimport type { RetryConfig } from \"../types\";\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n retryConfig: RetryConfig | undefined,\n signal?: AbortSignal,\n): Promise<T> {\n const maxRetries = retryConfig?.maxRetries ?? MAX_RETRIES;\n const baseDelay = retryConfig?.baseDelay ?? RETRY_BASE_DELAY;\n\n let lastError: unknown;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n if ((err as Error).name === \"AbortError\") throw err;\n lastError = err;\n if (attempt < maxRetries) {\n const delay = baseDelay * 2 ** attempt;\n await new Promise((r) => setTimeout(r, delay));\n if (signal?.aborted)\n throw new DOMException(\"Upload aborted\", \"AbortError\");\n }\n }\n }\n throw lastError;\n}\n","import type { UploadProgress } from \"../types\";\n\n/**\n * Uploads a file directly to S3 using a presigned POST form.\n *\n * All policy fields (acl, Content-Type, content-length-range, signature, etc.)\n * are embedded in `fields` and must be appended to the FormData **before** the\n * file — this is an S3 requirement. The size constraint is enforced by S3 at\n * the storage layer, so the server never needs to re-validate it.\n */\nexport function uploadSimple(\n file: File,\n url: string,\n fields: Record<string, string>,\n onProgress?: (progress: UploadProgress) => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n const onAbort = () => {\n xhr.abort();\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) {\n onProgress?.({\n loaded: e.loaded,\n total: e.total,\n percent: Math.round((e.loaded / e.total) * 100),\n });\n }\n });\n\n xhr.addEventListener(\"load\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (xhr.status >= 200 && xhr.status < 300) {\n onProgress?.({ loaded: file.size, total: file.size, percent: 100 });\n resolve();\n } else {\n reject(new Error(`Upload failed: ${xhr.status} ${xhr.statusText}`));\n }\n });\n\n xhr.addEventListener(\"error\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"Upload failed: network error\"));\n });\n\n xhr.addEventListener(\"abort\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n });\n\n // S3 presigned POST: policy fields must come before the file field.\n const formData = new FormData();\n for (const [k, v] of Object.entries(fields)) {\n formData.append(k, v);\n }\n formData.append(\"file\", file);\n\n xhr.open(\"POST\", url);\n xhr.send(formData);\n });\n}\n\n/**\n * Uploads a file directly to S3 using a presigned PUT URL.\n *\n * Use this when the server is configured with `upload.method = \"PUT\"` — for\n * example with Cloudflare R2 which does not support presigned POST.\n * The `headers` object must match exactly what was signed on the server\n * (Content-Type, Content-Disposition, x-amz-meta-*, etc.).\n */\nexport function uploadPut(\n file: File,\n url: string,\n headers: Record<string, string>,\n onProgress?: (progress: UploadProgress) => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n const onAbort = () => {\n xhr.abort();\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) {\n onProgress?.({\n loaded: e.loaded,\n total: e.total,\n percent: Math.round((e.loaded / e.total) * 100),\n });\n }\n });\n\n xhr.addEventListener(\"load\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (xhr.status >= 200 && xhr.status < 300) {\n onProgress?.({ loaded: file.size, total: file.size, percent: 100 });\n resolve();\n } else {\n reject(new Error(`Upload failed: ${xhr.status} ${xhr.statusText}`));\n }\n });\n\n xhr.addEventListener(\"error\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"Upload failed: network error\"));\n });\n\n xhr.addEventListener(\"abort\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n });\n\n xhr.open(\"PUT\", url);\n for (const [k, v] of Object.entries(headers)) {\n xhr.setRequestHeader(k, v);\n }\n xhr.send(file);\n });\n}\n","export function uploadPart(\n blob: Blob,\n presignedUrl: string,\n partLoaded: { bytes: number },\n totalSize: number,\n reportProgress: () => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n const onAbort = () => {\n xhr.abort();\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) {\n partLoaded.bytes = e.loaded;\n reportProgress();\n }\n });\n\n xhr.addEventListener(\"load\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (xhr.status >= 200 && xhr.status < 300) {\n partLoaded.bytes = blob.size;\n reportProgress();\n resolve();\n } else {\n reject(new Error(`Part upload failed: ${xhr.status}`));\n }\n });\n\n xhr.addEventListener(\"error\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"Part upload failed: network error\"));\n });\n\n xhr.addEventListener(\"abort\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n });\n\n xhr.open(\"PUT\", presignedUrl);\n xhr.send(blob);\n });\n}\n","import type {\n UploadProgress,\n UploadRequestOptions,\n RetryConfig,\n} from \"../types\";\nimport type { S3Api } from \"@better-s3/core\";\nimport type { UploadStore } from \"../types/upload-store\";\nimport { withRetry } from \"./retry\";\nimport { uploadPart } from \"./part\";\n\n/** Returns the byte size of a specific part (last part may be smaller). */\nfunction resolvePartSize(\n partIndex: number,\n totalParts: number,\n partSize: number,\n fileSize: number,\n): number {\n return partIndex === totalParts - 1\n ? fileSize - partIndex * partSize\n : partSize;\n}\n\nexport async function uploadMultipart(\n api: S3Api,\n file: File,\n objectKey: string,\n partSize: number,\n concurrentParts: number,\n onProgress?: (progress: UploadProgress) => void,\n signal?: AbortSignal,\n requestOptions?: UploadRequestOptions,\n retryConfig?: RetryConfig,\n uploadStore?: UploadStore | false,\n onPartUpload?: (partNumber: number, totalParts: number) => void,\n onMultipartInit?: (uploadId: string, key: string) => void,\n): Promise<string | undefined> {\n const bucket = requestOptions?.bucket;\n const contentType = requestOptions?.contentType ?? file.type;\n\n // Resolve the active store.\n // null → resumability disabled (uploadStore omitted, false, or SSR)\n // store → resumability enabled; persist uploadId across sessions\n const store: UploadStore | null =\n uploadStore != null && uploadStore !== false ? uploadStore : null;\n\n let uploadId: string;\n let key: string;\n const completedPartNumbers = new Set<number>();\n\n // ── Attempt to resume an existing upload ─────────────────────────────────\n const existing = store ? await store.get(objectKey, file.size) : null;\n\n if (existing) {\n try {\n // Verify the uploadId is still valid on S3 and fetch already-done parts.\n const { parts } = await api.multipart.listParts({\n key: existing.key,\n uploadId: existing.uploadId,\n bucket: bucket ?? existing.bucket,\n });\n uploadId = existing.uploadId;\n key = existing.key;\n for (const p of parts) completedPartNumbers.add(p.partNumber);\n onMultipartInit?.(uploadId, key);\n } catch {\n // uploadId is expired or no longer valid — start a fresh upload.\n await store?.delete(objectKey);\n const result = await api.multipart.init({\n key: objectKey,\n contentType,\n fileSize: file.size,\n fileName:\n requestOptions?.fileName !== null\n ? (requestOptions?.fileName ?? file.name)\n : undefined,\n metadata: requestOptions?.metadata,\n bucket,\n acl: requestOptions?.acl,\n });\n uploadId = result.uploadId;\n key = result.key;\n await store?.set({ uploadId, key, fileSize: file.size, bucket });\n onMultipartInit?.(uploadId, key);\n }\n } else {\n const result = await api.multipart.init({\n key: objectKey,\n contentType,\n fileSize: file.size,\n fileName:\n requestOptions?.fileName !== null\n ? (requestOptions?.fileName ?? file.name)\n : undefined,\n metadata: requestOptions?.metadata,\n bucket,\n acl: requestOptions?.acl,\n });\n uploadId = result.uploadId;\n key = result.key;\n await store?.set({ uploadId, key, fileSize: file.size, bucket });\n onMultipartInit?.(uploadId, key);\n }\n\n // ── Setup progress tracking ───────────────────────────────────────────────\n const totalParts = Math.ceil(file.size / partSize);\n\n // Pre-fill progress bytes for already-completed parts.\n const partProgress: Array<{ bytes: number }> = Array.from(\n { length: totalParts },\n (_, i) => ({\n bytes: completedPartNumbers.has(i + 1)\n ? resolvePartSize(i, totalParts, partSize, file.size)\n : 0,\n }),\n );\n\n // Pre-register completed parts so complete() receives a full list.\n const parts: Array<{ partNumber: number }> = Array.from(\n completedPartNumbers,\n (n) => ({ partNumber: n }),\n );\n\n const reportProgress = () => {\n const loaded = partProgress.reduce((sum, p) => sum + p.bytes, 0);\n onProgress?.({\n loaded,\n total: file.size,\n percent: Math.round((loaded / file.size) * 100),\n });\n };\n\n // Report initial progress for pre-completed parts before uploading starts.\n if (completedPartNumbers.size > 0) {\n reportProgress();\n }\n\n // ── Upload remaining parts ────────────────────────────────────────────────\n try {\n for (\n let batchStart = 0;\n batchStart < totalParts;\n batchStart += concurrentParts\n ) {\n if (signal?.aborted) {\n throw new DOMException(\"Upload aborted\", \"AbortError\");\n }\n\n const batchEnd = Math.min(batchStart + concurrentParts, totalParts);\n const batch: Array<Promise<{ partNumber: number }>> = [];\n\n for (let i = batchStart; i < batchEnd; i++) {\n const partNumber = i + 1;\n\n // Skip parts that were already uploaded in a previous attempt.\n if (completedPartNumbers.has(partNumber)) continue;\n\n const start = i * partSize;\n const end = Math.min(start + partSize, file.size);\n const blob = file.slice(start, end);\n\n batch.push(\n withRetry(\n async () => {\n const { presignedUrl } = await api.multipart.signPart({\n key,\n uploadId,\n partNumber,\n partSize: blob.size,\n bucket,\n });\n\n partProgress[i].bytes = 0;\n\n await uploadPart(\n blob,\n presignedUrl,\n partProgress[i],\n file.size,\n reportProgress,\n signal,\n );\n\n onPartUpload?.(partNumber, totalParts);\n return { partNumber };\n },\n retryConfig,\n signal,\n ),\n );\n }\n\n const batchResults = await Promise.all(batch);\n parts.push(...batchResults);\n }\n\n parts.sort((a, b) => a.partNumber - b.partNumber);\n\n const result = await api.multipart.complete({\n key,\n uploadId,\n parts,\n bucket,\n });\n\n // Upload finished successfully — remove from store.\n await store?.delete(objectKey);\n\n onProgress?.({ loaded: file.size, total: file.size, percent: 100 });\n return result.eTag;\n } catch (err) {\n if (store === null) {\n // Resumability is disabled — clean up the S3 multipart upload immediately.\n api.multipart.abort({ key, uploadId, bucket }).catch(() => {});\n }\n // With store active: preserve uploadId so the upload can be resumed later.\n // The S3 multipart upload is left open (expires automatically per bucket policy).\n throw err;\n }\n}\n","import type {\n UploadConfig,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n} from \"../types\";\nimport type { S3Api } from \"@better-s3/core\";\nimport {\n DEFAULT_MULTIPART_THRESHOLD,\n DEFAULT_CONCURRENT_PARTS,\n DEFAULT_PART_SIZE,\n} from \"./constants\";\nimport { withRetry } from \"./retry\";\nimport { uploadSimple, uploadPut } from \"./simple\";\nimport { uploadMultipart } from \"./multipart\";\n\nexport type UploadEngineCallbacks = {\n onProgress?: (progress: UploadProgress) => void;\n /** Called when the upload transitions between internal phases. */\n onPhaseChange?: (phase: \"presigning\" | \"uploading\" | \"finalizing\") => void;\n /** Called after each individual multipart part is successfully uploaded. */\n onPartUpload?: (partNumber: number, totalParts: number) => void;\n /** Called once after `CreateMultipartUpload` succeeds with the S3-assigned `uploadId` and final object `key`. */\n onMultipartInit?: (uploadId: string, key: string) => void;\n};\n\nexport async function uploadFile(\n api: S3Api,\n file: File,\n objectKey: string,\n config: UploadConfig = {},\n callbacks: UploadEngineCallbacks = {},\n signal?: AbortSignal,\n requestOptions?: UploadRequestOptions,\n): Promise<UploadResult> {\n const threshold = config.multipartThreshold ?? DEFAULT_MULTIPART_THRESHOLD;\n const useMultipart = config.multipart === true && file.size >= threshold;\n const concurrentParts = config.concurrentParts ?? DEFAULT_CONCURRENT_PARTS;\n const partSize =\n requestOptions?.partSize ?? config.partSize ?? DEFAULT_PART_SIZE;\n const contentType = requestOptions?.contentType ?? file.type;\n\n let eTag: string | undefined;\n\n if (useMultipart) {\n callbacks.onPhaseChange?.(\"uploading\");\n eTag = await uploadMultipart(\n api,\n file,\n objectKey,\n partSize,\n concurrentParts,\n callbacks.onProgress,\n signal,\n requestOptions,\n config.retry,\n config.uploadStore,\n callbacks.onPartUpload,\n callbacks.onMultipartInit,\n );\n } else {\n await withRetry(\n async () => {\n callbacks.onPhaseChange?.(\"presigning\");\n const presign = await api.upload({\n key: objectKey,\n contentType,\n fileSize: file.size,\n fileName:\n requestOptions?.fileName !== null\n ? (requestOptions?.fileName ?? file.name)\n : undefined,\n metadata: requestOptions?.metadata,\n bucket: requestOptions?.bucket,\n acl: requestOptions?.acl,\n });\n callbacks.onPhaseChange?.(\"uploading\");\n if (presign.method === \"PUT\") {\n await uploadPut(\n file,\n presign.url,\n presign.headers ?? {},\n callbacks.onProgress,\n signal,\n );\n } else {\n await uploadSimple(\n file,\n presign.url,\n presign.fields ?? {},\n callbacks.onProgress,\n signal,\n );\n }\n },\n config.retry,\n signal,\n );\n\n callbacks.onPhaseChange?.(\"finalizing\");\n const confirmed = await api.confirm({\n key: objectKey,\n bucket: requestOptions?.bucket,\n });\n eTag = confirmed.eTag;\n }\n\n return { key: objectKey, eTag };\n}\n","import type {\n UploadConfig,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n} from \"../types\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { DEFAULT_CONCURRENT_FILES } from \"./constants\";\nimport { uploadFile } from \"./upload-file\";\n\nexport type FileItemStatus = \"pending\" | \"uploading\" | \"success\" | \"error\";\n\nexport type FileItem = {\n id: string;\n file: File;\n objectKey: string;\n status: FileItemStatus;\n progress: UploadProgress;\n result: UploadResult | null;\n error: string | null;\n};\n\nexport type MultiUploadCallbacks = {\n onFileProgress?: (id: string, progress: UploadProgress) => void;\n onFileSuccess?: (id: string, result: UploadResult) => void;\n onFileError?: (id: string, error: string) => void;\n onTotalProgress?: (progress: UploadProgress) => void;\n};\n\nexport async function uploadFiles(\n api: S3Api,\n items: Array<{ id: string; file: File; objectKey: string }>,\n config: UploadConfig = {},\n callbacks: MultiUploadCallbacks = {},\n signal?: AbortSignal,\n getRequestOptions?: (file: File) => UploadRequestOptions,\n): Promise<FileItem[]> {\n const results: FileItem[] = items.map((item) => ({\n ...item,\n status: \"pending\" as FileItemStatus,\n progress: { loaded: 0, total: item.file.size, percent: 0 },\n result: null,\n error: null,\n }));\n\n const reportTotalProgress = () => {\n const loaded = results.reduce((sum, r) => sum + r.progress.loaded, 0);\n const total = results.reduce((sum, r) => sum + r.progress.total, 0);\n callbacks.onTotalProgress?.({\n loaded,\n total,\n percent: total > 0 ? Math.round((loaded / total) * 100) : 0,\n });\n };\n\n let nextIndex = 0;\n\n const processNext = async (): Promise<void> => {\n while (nextIndex < results.length) {\n if (signal?.aborted) return;\n const idx = nextIndex++;\n const item = results[idx];\n\n item.status = \"uploading\";\n\n try {\n const result = await uploadFile(\n api,\n item.file,\n item.objectKey,\n config,\n {\n onProgress: (progress) => {\n item.progress = progress;\n callbacks.onFileProgress?.(item.id, progress);\n reportTotalProgress();\n },\n },\n signal,\n getRequestOptions?.(item.file),\n );\n item.status = \"success\";\n item.result = result;\n item.progress = {\n loaded: item.file.size,\n total: item.file.size,\n percent: 100,\n };\n callbacks.onFileSuccess?.(item.id, result);\n reportTotalProgress();\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n item.status = \"error\";\n item.error = \"Upload cancelled\";\n return;\n }\n const message = err instanceof Error ? err.message : \"Upload failed\";\n item.status = \"error\";\n item.error = message;\n callbacks.onFileError?.(item.id, message);\n reportTotalProgress();\n }\n }\n };\n\n const concurrentFiles = config.concurrentFiles ?? DEFAULT_CONCURRENT_FILES;\n const workers = Array.from(\n { length: Math.min(concurrentFiles, items.length) },\n () => processNext(),\n );\n await Promise.all(workers);\n\n return results;\n}\n","import { formatFileSize } from \"@better-s3/core\";\n\n/**\n * Formats upload progress as a human-readable transfer string.\n *\n * @param loaded Bytes transferred so far.\n * @param total Total bytes to transfer (0 means unknown).\n * @param percent Transfer percentage (0–100).\n *\n * @example\n * ```ts\n * formatUploadProgress(1_200_000, 5_600_000, 21)\n * // → \"1.2 MB / 5.6 MB (21%)\"\n *\n * formatUploadProgress(1_200_000, 0, 0)\n * // → \"1.2 MB\"\n * ```\n */\nexport function formatUploadProgress(\n loaded: number,\n total: number,\n percent: number,\n): string {\n const loadedStr = formatFileSize(loaded);\n if (!total) return loadedStr;\n return `${loadedStr} / ${formatFileSize(total)} (${Math.round(percent)}%)`;\n}\n","import { formatFileSize } from \"@better-s3/core\";\n\n/**\n * Formats a transfer speed (bytes/second) as a human-readable string.\n *\n * @example\n * formatSpeed(1_200_000) // → \"1.2 MB/s\"\n * formatSpeed(512) // → \"512 B/s\"\n */\nexport function formatSpeed(bytesPerSecond: number): string {\n return `${formatFileSize(bytesPerSecond)}/s`;\n}\n","/**\n * Formats an estimated remaining time given the remaining bytes and current speed.\n *\n * Returns `null` when speed is 0 or nothing remains (not yet calculable).\n *\n * @example\n * formatEta(4_400_000, 450_000) // → \"9s\"\n * formatEta(4_400_000, 75_000) // → \"58s\"\n * formatEta(90_000_000, 1_500_000) // → \"1m\"\n * formatEta(5_400_000_000, 500_000) // → \"3h\"\n */\nexport function formatEta(\n remainingBytes: number,\n bytesPerSecond: number,\n): string | null {\n if (bytesPerSecond <= 0 || remainingBytes <= 0) return null;\n const totalSeconds = remainingBytes / bytesPerSecond;\n\n if (totalSeconds < 60) return `${Math.ceil(totalSeconds)}s`;\n\n const totalMinutes = totalSeconds / 60;\n if (totalMinutes < 60) return `${Math.ceil(totalMinutes)}m`;\n\n const hours = Math.floor(totalMinutes / 60);\n const mins = Math.ceil(totalMinutes % 60);\n return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;\n}\n","/**\n * Creates a sliding-window transfer speed calculator.\n *\n * Tracks bytes transferred over a rolling time window to produce a smooth,\n * instantaneous speed reading in bytes/second.\n *\n * @param windowMs Rolling window duration in milliseconds. @default 3000\n */\nexport function createSpeedTracker(windowMs = 3000) {\n const samples: Array<{ t: number; loaded: number }> = [];\n\n return {\n /**\n * Record the latest cumulative `loaded` byte count.\n * Returns the current speed in bytes/second (0 until at least 2 samples exist).\n */\n update(loaded: number): number {\n const now = Date.now();\n samples.push({ t: now, loaded });\n\n // Prune samples older than the window, but keep at least one anchor.\n const cutoff = now - windowMs;\n while (samples.length > 1 && samples[0].t < cutoff) {\n samples.shift();\n }\n\n if (samples.length < 2) return 0;\n\n const oldest = samples[0];\n const newest = samples[samples.length - 1];\n const deltaMs = newest.t - oldest.t;\n const deltaBytes = newest.loaded - oldest.loaded;\n\n return deltaMs > 0 ? Math.round((deltaBytes / deltaMs) * 1000) : 0;\n },\n\n reset() {\n samples.length = 0;\n },\n };\n}\n\nexport type SpeedTracker = ReturnType<typeof createSpeedTracker>;\n","import { useRef } from \"react\";\n\n/**\n * Keeps a ref in sync with the latest value on every render.\n *\n * Use inside `useCallback(fn, [])` to read the latest prop / option value\n * without making the callback depend on it (stale-closure-free stable refs).\n *\n * @internal — not part of the public API.\n */\nexport function useLiveRef<T>(value: T) {\n const ref = useRef(value);\n ref.current = value;\n return ref;\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { validateFile } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { createSpeedTracker } from \"../helpers/speed-tracker\";\nimport { useLiveRef } from \"../internal-helpers\";\nimport type {\n UploadConfig,\n UploadHooks,\n UploadPhase,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n} from \"../types\";\nimport { uploadFile } from \"../upload\";\n\n/** Options for {@link useUpload}. */\nexport type UseUploadOptions = UploadConfig &\n UploadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n };\n\nexport type UseUploadState = {\n /** Current upload phase. */\n phase: UploadPhase;\n /** Byte transfer progress. */\n progress: UploadProgress;\n /** Error message, or `null`. */\n error: string | null;\n /** Result after success, or `null`. */\n result: UploadResult | null;\n /** Name of the file being uploaded. */\n fileName: string | null;\n /** Size of the file being uploaded in bytes. */\n fileSize: number | null;\n};\n\nexport type UseUploadReturn = UseUploadState & {\n /**\n * Start an upload.\n *\n * Safe to call again after `success`, `error`, or `cancel` — state is reset\n * automatically before the new upload begins.\n *\n * If `uploadStore` is configured and a previous upload for the same\n * `objectKey` was interrupted (e.g. via `detach()`), the engine will find\n * the stored `uploadId`, call `listParts`, and resume from the last completed\n * part rather than starting a new multipart upload.\n */\n upload: (\n file: File,\n objectKey: string,\n requestOptions?: UploadRequestOptions,\n ) => Promise<void>;\n /**\n * Abort the upload and fully clean up all resources.\n *\n * - Stops the in-flight network request immediately.\n * - For multipart uploads: calls `AbortMultipartUpload` on S3 so incomplete\n * parts are freed right away (instead of waiting for the bucket lifecycle\n * policy to expire them).\n * - Removes the `uploadStore` entry if one was provided.\n * - Resets state to `idle`.\n *\n * Use this for a \"Cancel\" button that the user explicitly clicks to abandon\n * the upload entirely.\n */\n cancel: () => void;\n /**\n * Stop the upload and — when multipart with `uploadStore` is active —\n * preserve S3 parts and the store entry for a future resume.\n *\n * Compared to `cancel()`:\n * - Does **not** call `AbortMultipartUpload` (parts stay on S3).\n * - Does **not** remove the `uploadStore` entry.\n * - Does **not** fire the `onCancel` callback.\n *\n * The next call to `upload(sameFile, sameKey)` will detect the stored\n * `uploadId`, verify the existing parts via `listParts`, and continue\n * uploading from where it stopped.\n *\n * For **simple uploads** or multipart **without** `uploadStore`, this is\n * identical to `cancel()` — there is no S3 state worth preserving.\n *\n * Intended for custom UIs that want to offer a \"save for later / resume\"\n * workflow. The built-in UI components always use `cancel()`.\n */\n detach: () => void;\n /**\n * Reset UI state to `idle` without touching any S3 or store resources.\n *\n * - Stops the in-flight network request if one is active.\n * - Does **not** call `AbortMultipartUpload`.\n * - Does **not** modify `uploadStore`.\n * - Does **not** fire `onCancel`.\n *\n * Use this to clear an error or success state from the UI, or when you\n * handle cleanup yourself outside this hook.\n */\n reset: () => void;\n};\n\nconst INITIAL_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\n\nconst INITIAL_STATE: UseUploadState = {\n phase: \"idle\",\n progress: INITIAL_PROGRESS,\n error: null,\n result: null,\n fileName: null,\n fileSize: null,\n};\n\ntype ActiveUpload = {\n file: File;\n objectKey: string;\n /** S3 key as returned by the server (may differ from objectKey). */\n serverKey: string;\n uploadId?: string;\n bucket?: string;\n requestOptions?: UploadRequestOptions;\n};\n\nexport function useUpload(options: UseUploadOptions): UseUploadReturn {\n const [state, setState] = useState<UseUploadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const abortRef = useRef<AbortController | null>(null);\n /** Tracks the in-flight upload so cancel/detach can access uploadId and key. */\n const activeUploadRef = useRef<ActiveUpload | null>(null);\n /** Set before aborting so the AbortError catch skips cancel callbacks. */\n const detachingRef = useRef(false);\n const speedTrackerRef = useRef(createSpeedTracker());\n const lastSpeedRef = useRef<number | undefined>(undefined);\n const lastSpeedUpdateRef = useRef(0);\n\n const upload = useCallback(\n async (\n file: File,\n objectKey: string,\n requestOptions?: UploadRequestOptions,\n ) => {\n setState({\n ...INITIAL_STATE,\n phase: \"validating\",\n fileName: file.name,\n fileSize: file.size,\n });\n\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useUpload or wrap with <S3Provider>.\",\n );\n\n const validationError = validateFile(file, {\n accept: opts.accept,\n maxFileSize: opts.maxFileSize,\n });\n if (validationError) {\n setState((s) => ({ ...s, phase: \"error\", error: validationError }));\n opts.onError?.(file, new Error(validationError), \"validating\");\n return;\n }\n\n if (opts.beforeUpload) {\n const allowed = await opts.beforeUpload(file);\n if (!allowed) {\n setState((s) => ({\n ...s,\n phase: \"error\",\n error: \"Upload blocked by beforeUpload hook\",\n }));\n opts.onError?.(file, new Error(\"blocked\"), \"validating\");\n return;\n }\n }\n\n speedTrackerRef.current.reset();\n lastSpeedRef.current = undefined;\n lastSpeedUpdateRef.current = 0;\n setState((s) => ({ ...s, phase: \"presigning\" }));\n opts.onUploadStart?.(file, objectKey);\n\n const controller = new AbortController();\n abortRef.current = controller;\n activeUploadRef.current = {\n file,\n objectKey,\n serverKey: objectKey,\n bucket: requestOptions?.bucket,\n requestOptions,\n };\n\n try {\n const result = await uploadFile(\n api,\n file,\n objectKey,\n {\n multipart: opts.multipart,\n multipartThreshold: opts.multipartThreshold,\n concurrentParts: opts.concurrentParts,\n partSize: opts.partSize,\n retry: opts.retry,\n uploadStore: opts.uploadStore,\n },\n {\n onProgress: (progress) => {\n const rawSpeed = speedTrackerRef.current.update(progress.loaded);\n const now = Date.now();\n if (rawSpeed > 0 && now - lastSpeedUpdateRef.current >= 500) {\n lastSpeedRef.current = rawSpeed;\n lastSpeedUpdateRef.current = now;\n }\n const speed = lastSpeedRef.current;\n const p = speed ? { ...progress, speed } : progress;\n setState((s) => ({ ...s, progress: p }));\n opts.onProgress?.(file, p);\n },\n onPhaseChange: (phase) => setState((s) => ({ ...s, phase })),\n onPartUpload: (partNumber, totalParts) =>\n opts.onPartUpload?.(file, partNumber, totalParts),\n onMultipartInit: (uploadId, serverKey) => {\n if (activeUploadRef.current) {\n activeUploadRef.current.uploadId = uploadId;\n activeUploadRef.current.serverKey = serverKey;\n }\n opts.onMultipartInit?.(file, uploadId);\n },\n },\n controller.signal,\n requestOptions,\n );\n\n setState((s) => ({\n ...s,\n phase: \"success\",\n result,\n progress: { loaded: file.size, total: file.size, percent: 100 },\n }));\n await opts.onSuccess?.(file, result);\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n if (detachingRef.current) {\n detachingRef.current = false;\n return;\n }\n opts.onCancel?.(file);\n setState(INITIAL_STATE);\n return;\n }\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(file, err, \"uploading\");\n } finally {\n abortRef.current = null;\n activeUploadRef.current = null;\n }\n },\n [],\n );\n\n const cancel = useCallback(() => {\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n const active = activeUploadRef.current;\n abortRef.current?.abort();\n if (active && api) {\n const { objectKey, serverKey, uploadId, bucket } = active;\n const store = opts.uploadStore;\n if (store != null && store !== false) {\n void Promise.resolve(store.delete(objectKey)).catch(() => {});\n }\n if (uploadId) {\n api.multipart\n .abort({ key: serverKey, uploadId, bucket })\n .catch(() => {});\n }\n }\n setState(INITIAL_STATE);\n }, []);\n\n const detach = useCallback(() => {\n const active = activeUploadRef.current;\n if (!active) return;\n // Signal the AbortError catch not to fire onCancel or re-reset state.\n detachingRef.current = true;\n abortRef.current?.abort();\n // multipart.ts already preserves the store entry when store != null,\n // so no extra cleanup is needed here for the resumable path.\n // For simple uploads or multipart without store the abort triggers\n // AbortMultipartUpload automatically inside multipart.ts.\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n return { ...state, upload, cancel, detach, reset };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { validateFile } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { createSpeedTracker } from \"../helpers/speed-tracker\";\nimport { useLiveRef } from \"../internal-helpers\";\nimport type {\n UploadConfig,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n MultiUploadPhase,\n MultiUploadFileState,\n MultiUploadHooks,\n} from \"../types\";\nimport { uploadFiles } from \"../upload\";\n\n/** Options for {@link useMultiUpload}. */\nexport type UseMultiUploadOptions = UploadConfig &\n MultiUploadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Static request options applied to all files. */\n uploadOptions?: UploadRequestOptions;\n /** Per-file request options (overrides `uploadOptions`). */\n getUploadOptions?: (file: File) => UploadRequestOptions;\n };\n\nexport type UseMultiUploadState = {\n /** Current batch upload phase. */\n phase: MultiUploadPhase;\n /** Per-file upload states. */\n files: MultiUploadFileState[];\n /** Aggregated progress across all files. */\n totalProgress: UploadProgress;\n /** Batch-level error message, or `null`. */\n error: string | null;\n};\n\nexport type UseMultiUploadReturn = UseMultiUploadState & {\n /** Upload multiple files. */\n upload: (files: File[], resolveKey: (file: File) => string) => Promise<void>;\n /** Abort all in-flight uploads. */\n cancel: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\nconst INITIAL_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\n\nconst INITIAL_STATE: UseMultiUploadState = {\n phase: \"idle\",\n files: [],\n totalProgress: INITIAL_PROGRESS,\n error: null,\n};\n\nfunction generateId() {\n return crypto.randomUUID();\n}\n\nexport function useMultiUpload(\n options: UseMultiUploadOptions,\n): UseMultiUploadReturn {\n const [state, setState] = useState<UseMultiUploadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const abortRef = useRef<AbortController | null>(null);\n const resettingRef = useRef(false);\n const fileMapRef = useRef<Map<string, File>>(new Map());\n const fileSpeedTrackersRef = useRef<\n Map<string, ReturnType<typeof createSpeedTracker>>\n >(new Map());\n const totalSpeedTrackerRef = useRef(createSpeedTracker());\n const fileLastSpeedRef = useRef<Map<string, number>>(new Map());\n const fileLastSpeedUpdateRef = useRef<Map<string, number>>(new Map());\n const lastTotalSpeedRef = useRef<number | undefined>(undefined);\n const lastTotalSpeedUpdateRef = useRef(0);\n\n const upload = useCallback(\n async (files: File[], resolveKey: (file: File) => string) => {\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useMultiUpload or wrap with <S3Provider>.\",\n );\n\n const items: Array<{\n id: string;\n file: File;\n objectKey: string;\n }> = [];\n const fileStates: MultiUploadFileState[] = [];\n const fileMap = new Map<string, File>();\n\n setState((s) => ({ ...s, phase: \"validating\", error: null }));\n\n if (opts.maxFiles && files.length > opts.maxFiles) {\n const msg = `Too many files. Maximum is ${opts.maxFiles}.`;\n setState((s) => ({ ...s, phase: \"error\", error: msg }));\n opts.onError?.(new Error(msg));\n return;\n }\n\n for (const file of files) {\n const validationError = validateFile(file, {\n accept: opts.accept,\n maxFileSize: opts.maxFileSize,\n });\n if (validationError) {\n const msg = `${file.name}: ${validationError}`;\n setState((s) => ({ ...s, phase: \"error\", error: msg }));\n opts.onError?.(new Error(msg));\n return;\n }\n }\n\n if (opts.beforeUpload) {\n const allowed = await opts.beforeUpload(files);\n if (!allowed) {\n setState((s) => ({\n ...s,\n phase: \"error\",\n error: \"Upload blocked by beforeUpload hook\",\n }));\n opts.onError?.(new Error(\"blocked\"));\n return;\n }\n }\n\n for (const file of files) {\n const id = generateId();\n const objectKey = resolveKey(file);\n items.push({ id, file, objectKey });\n fileMap.set(id, file);\n fileStates.push({\n id,\n fileName: file.name,\n fileSize: file.size,\n status: \"pending\",\n progress: { loaded: 0, total: file.size, percent: 0 },\n error: null,\n });\n }\n\n fileMapRef.current = fileMap;\n\n setState({\n phase: \"uploading\",\n files: fileStates,\n totalProgress: {\n loaded: 0,\n total: files.reduce((s, f) => s + f.size, 0),\n percent: 0,\n },\n error: null,\n });\n\n opts.onUploadStart?.(files);\n\n // Reset speed trackers for this batch\n fileSpeedTrackersRef.current.clear();\n for (const item of items) {\n fileSpeedTrackersRef.current.set(item.id, createSpeedTracker());\n }\n totalSpeedTrackerRef.current.reset();\n fileLastSpeedRef.current.clear();\n fileLastSpeedUpdateRef.current.clear();\n lastTotalSpeedRef.current = undefined;\n lastTotalSpeedUpdateRef.current = 0;\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n try {\n const results = await uploadFiles(\n api,\n items,\n {\n multipart: opts.multipart,\n multipartThreshold: opts.multipartThreshold,\n concurrentParts: opts.concurrentParts,\n concurrentFiles: opts.concurrentFiles,\n partSize: opts.partSize,\n retry: opts.retry,\n uploadStore: opts.uploadStore,\n },\n {\n onFileProgress: (id, progress) => {\n const tracker = fileSpeedTrackersRef.current.get(id);\n const rawSpeed = tracker ? tracker.update(progress.loaded) : 0;\n const now = Date.now();\n if (\n rawSpeed > 0 &&\n now - (fileLastSpeedUpdateRef.current.get(id) ?? 0) >= 500\n ) {\n fileLastSpeedRef.current.set(id, rawSpeed);\n fileLastSpeedUpdateRef.current.set(id, now);\n }\n const speed = fileLastSpeedRef.current.get(id);\n const p = speed ? { ...progress, speed } : progress;\n setState((s) => ({\n ...s,\n files: s.files.map((f) =>\n f.id === id ? { ...f, status: \"uploading\", progress: p } : f,\n ),\n }));\n const file = fileMap.get(id);\n if (file) opts.onFileProgress?.(file, p);\n },\n onFileSuccess: (id, result) => {\n setState((s) => ({\n ...s,\n files: s.files.map((f) =>\n f.id === id\n ? {\n ...f,\n status: \"success\",\n progress: {\n loaded: f.fileSize,\n total: f.fileSize,\n percent: 100,\n },\n }\n : f,\n ),\n }));\n const file = fileMap.get(id);\n if (file) opts.onFileSuccess?.(file, result);\n },\n onFileError: (id, error) => {\n setState((s) => ({\n ...s,\n files: s.files.map((f) =>\n f.id === id ? { ...f, status: \"error\", error } : f,\n ),\n }));\n const file = fileMap.get(id);\n if (file) opts.onFileError?.(file, error);\n },\n onTotalProgress: (progress) => {\n const rawSpeed = totalSpeedTrackerRef.current.update(\n progress.loaded,\n );\n const now = Date.now();\n if (\n rawSpeed > 0 &&\n now - lastTotalSpeedUpdateRef.current >= 1000\n ) {\n lastTotalSpeedRef.current = rawSpeed;\n lastTotalSpeedUpdateRef.current = now;\n }\n const speed = lastTotalSpeedRef.current;\n const p = speed ? { ...progress, speed } : progress;\n setState((s) => ({ ...s, totalProgress: p }));\n opts.onProgress?.(p);\n },\n },\n controller.signal,\n (file) => {\n const perFile = opts.getUploadOptions?.(file);\n if (!opts.uploadOptions) return perFile ?? {};\n return { ...opts.uploadOptions, ...perFile };\n },\n );\n\n const hasErrors = results.some((r) => r.status === \"error\");\n const successResults = results\n .filter((r) => r.result !== null)\n .map((r) => r.result!);\n\n setState((s) => ({\n ...s,\n phase: hasErrors ? \"error\" : \"success\",\n error: hasErrors\n ? `${results.filter((r) => r.status === \"error\").length} file(s) failed`\n : null,\n totalProgress: hasErrors\n ? s.totalProgress\n : {\n loaded: s.totalProgress.total,\n total: s.totalProgress.total,\n percent: 100,\n },\n }));\n\n if (!hasErrors) {\n await opts.onSuccess?.(successResults);\n }\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n if (!resettingRef.current) opts.onCancel?.();\n resettingRef.current = false;\n setState(INITIAL_STATE);\n return;\n }\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(err);\n } finally {\n abortRef.current = null;\n }\n },\n [],\n );\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n resettingRef.current = true;\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n return { ...state, upload, cancel, reset };\n}\n","\"use client\";\n\nimport { useRef, useState } from \"react\";\nimport type {\n UploadPhase,\n UploadProgress,\n UploadRequestOptions,\n} from \"../types\";\nimport { useUpload, type UseUploadOptions } from \"./use-upload\";\n\n/** Options for {@link useUploadControls}. */\nexport type UseUploadControlsOptions = UseUploadOptions & {\n /** S3 object key, or a function that derives it from the file. */\n objectKey: string | ((file: File) => string);\n /** Static request options applied to the upload. */\n uploadOptions?: UploadRequestOptions;\n /** Per-upload request options override. */\n getUploadOptions?: (file: File) => UploadRequestOptions;\n};\n\nexport type UseUploadControlsReturn = {\n /** Current upload phase. */\n phase: UploadPhase;\n /** Info about the selected file. */\n fileInfo: { name: string; size: number } | null;\n /** Byte transfer progress. */\n progress: UploadProgress;\n /** Error message, or `null`. */\n error: string | null;\n /** `true` while uploading. */\n isUploading: boolean;\n /** Handle files from drag-and-drop or a file input. */\n handleFiles: (files: FileList | null) => void;\n /** Open the hidden file picker. */\n openFilePicker: () => void;\n /** Abort and reset to idle. */\n cancel: () => void;\n /**\n * Soft-stop: preserves S3 parts and store entry so a future `upload()` can\n * resume. For non-resumable uploads, identical to `cancel()`.\n * See `UseUploadReturn.detach` for full semantics.\n */\n detach: () => void;\n reset: () => void;\n /** Spread on a hidden `<input>` element. */\n inputProps: {\n ref: React.RefObject<HTMLInputElement | null>;\n type: \"file\";\n accept?: string;\n hidden: true;\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n };\n /** Spread on a container to enable drag-and-drop. */\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => void;\n onDrop: (e: React.DragEvent) => void;\n };\n};\n\nexport function useUploadControls(\n options: UseUploadControlsOptions,\n): UseUploadControlsReturn {\n const single = useUpload(options);\n const inputRef = useRef<HTMLInputElement>(null);\n const [fileInfo, setFileInfo] = useState<{\n name: string;\n size: number;\n } | null>(null);\n\n const resolveKey = (file: File): string =>\n typeof options.objectKey === \"function\"\n ? options.objectKey(file)\n : options.objectKey;\n\n const handleFiles = async (files: FileList | null) => {\n const file = files?.[0];\n if (!file) return;\n setFileInfo({ name: file.name, size: file.size });\n await single.upload(file, resolveKey(file), {\n ...options.uploadOptions,\n ...options.getUploadOptions?.(file),\n });\n };\n\n return {\n phase: single.phase,\n fileInfo,\n progress: single.progress,\n error: single.error,\n isUploading: single.phase === \"uploading\",\n handleFiles,\n openFilePicker: () => inputRef.current?.click(),\n cancel: single.cancel,\n detach: single.detach,\n reset: () => {\n single.reset();\n setFileInfo(null);\n },\n inputProps: {\n ref: inputRef,\n type: \"file\",\n accept: options.accept?.join(\",\"),\n hidden: true,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n handleFiles(e.target.files);\n e.target.value = \"\";\n },\n },\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n },\n onDrop: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (single.phase !== \"uploading\") handleFiles(e.dataTransfer.files);\n },\n },\n };\n}\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport type {\n UploadProgress,\n UploadRequestOptions,\n MultiUploadFileState,\n MultiUploadPhase,\n} from \"../types\";\nimport { useMultiUpload, type UseMultiUploadOptions } from \"./use-multi-upload\";\n\n/** Options for {@link useMultiUploadControls}. */\nexport type UseMultiUploadControlsOptions = UseMultiUploadOptions & {\n /** S3 object key, or a function that derives it from each file. */\n objectKey: string | ((file: File) => string);\n};\n\nexport type UseMultiUploadControlsReturn = {\n /** Current batch upload phase. */\n phase: MultiUploadPhase;\n /** Per-file upload states. */\n files: MultiUploadFileState[];\n /** Aggregated progress across all files. */\n totalProgress: UploadProgress;\n /** Batch-level error message, or `null`. */\n error: string | null;\n /** `true` while uploading. */\n isUploading: boolean;\n /** Handle files from drag-and-drop or a file input. */\n handleFiles: (files: FileList | null) => void;\n /** Open the hidden file picker. */\n openFilePicker: () => void;\n /** Abort all in-flight uploads. */\n cancel: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n /** Spread on a hidden `<input>` element. */\n inputProps: {\n ref: React.RefObject<HTMLInputElement | null>;\n type: \"file\";\n multiple: true;\n accept?: string;\n hidden: true;\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n };\n /** Spread on a container to enable drag-and-drop. */\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => void;\n onDrop: (e: React.DragEvent) => void;\n };\n};\n\nexport function useMultiUploadControls(\n options: UseMultiUploadControlsOptions,\n): UseMultiUploadControlsReturn {\n const multi = useMultiUpload(options);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const resolveKey = (file: File): string =>\n typeof options.objectKey === \"function\"\n ? options.objectKey(file)\n : options.objectKey;\n\n const handleFiles = async (files: FileList | null) => {\n if (!files?.length) return;\n await multi.upload(Array.from(files), resolveKey);\n };\n\n return {\n phase: multi.phase,\n files: multi.files,\n totalProgress: multi.totalProgress,\n error: multi.error,\n isUploading: multi.phase === \"uploading\",\n handleFiles,\n openFilePicker: () => inputRef.current?.click(),\n cancel: multi.cancel,\n reset: multi.reset,\n inputProps: {\n ref: inputRef,\n type: \"file\",\n multiple: true,\n accept: options.accept?.join(\",\"),\n hidden: true,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n handleFiles(e.target.files);\n e.target.value = \"\";\n },\n },\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n },\n onDrop: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (multi.phase !== \"uploading\") handleFiles(e.dataTransfer.files);\n },\n },\n };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { useLiveRef } from \"../internal-helpers\";\n\nexport type { DownloadPhase, DownloadHooks } from \"../types/download\";\n\nimport type { DownloadPhase, DownloadHooks } from \"../types/download\";\n\n/** Options for {@link useDownload}. */\nexport type UseDownloadOptions = DownloadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Target bucket (overrides server default). */\n bucket?: string;\n};\n\nexport type UseDownloadState = {\n /** Current download phase. */\n phase: DownloadPhase;\n /** Error message, or `null`. */\n error: string | null;\n /** Presigned URL — set after a successful presign, cleared on reset. */\n url: string | null;\n /** Validity window in seconds for the presigned URL. */\n expiresIn: number | null;\n};\n\nexport type UseDownloadReturn = UseDownloadState & {\n /** Presign and trigger a native browser download. */\n download: (key: string, downloadName?: string) => Promise<void>;\n /** Fetch the presigned URL without triggering a browser download. */\n presign: (\n key: string,\n downloadName?: string,\n ) => Promise<{ url: string; expiresIn: number } | null>;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\nconst INITIAL_STATE: UseDownloadState = {\n phase: \"idle\",\n error: null,\n url: null,\n expiresIn: null,\n};\n\nexport function useDownload(options: UseDownloadOptions): UseDownloadReturn {\n const [state, setState] = useState<UseDownloadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n\n const presign = useCallback(async (key: string, downloadName?: string) => {\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useDownload or wrap with <S3Provider>.\",\n );\n setState({ phase: \"presigning\", error: null, url: null, expiresIn: null });\n try {\n const result = await api.download(key, {\n fileName: downloadName,\n bucket: opts.bucket,\n });\n setState({\n phase: \"idle\",\n error: null,\n url: result.url,\n expiresIn: result.expiresIn,\n });\n return { url: result.url, expiresIn: result.expiresIn };\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Download failed\";\n setState({ phase: \"error\", error: message, url: null, expiresIn: null });\n opts.onError?.(key, err);\n return null;\n }\n }, []);\n\n const download = useCallback(\n async (key: string, downloadName?: string) => {\n const opts = optsRef.current;\n if (opts.beforeDownload) {\n const allowed = await opts.beforeDownload(key);\n if (!allowed) {\n setState({\n phase: \"error\",\n error: \"Download blocked by beforeDownload hook\",\n url: null,\n expiresIn: null,\n });\n opts.onError?.(key, new Error(\"blocked\"));\n return;\n }\n }\n const result = await presign(key, downloadName);\n if (!result) return;\n window.location.href = result.url;\n opts.onInitiated?.(key);\n },\n [presign],\n );\n\n const reset = useCallback(() => setState(INITIAL_STATE), []);\n\n return { ...state, download, presign, reset };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { parseFileName } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { createSpeedTracker } from \"../helpers/speed-tracker\";\nimport type { FetchDownloadPhase, FetchDownloadHooks } from \"../types/download\";\nimport type { UploadProgress } from \"../types/upload\";\nimport { useLiveRef } from \"../internal-helpers\";\n\nexport type {\n FetchDownloadPhase,\n FetchDownloadProgress,\n FetchDownloadHooks,\n} from \"../types/download\";\n\n/** Options for {@link useFetchDownload}. */\nexport type UseFetchDownloadOptions = FetchDownloadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Target bucket (overrides server default). */\n bucket?: string;\n};\n\nexport type UseFetchDownloadState = {\n /** Current download phase. */\n phase: FetchDownloadPhase;\n /** Byte transfer progress. */\n progress: UploadProgress;\n /** Error message, or `null`. */\n error: string | null;\n /** Resolved download filename. */\n fileName: string | null;\n /** Total file size in bytes. */\n fileSize: number | null;\n};\n\nexport type UseFetchDownloadReturn = UseFetchDownloadState & {\n /** Presign, fetch bytes, and save via the browser. */\n download: (key: string, downloadName?: string) => Promise<void>;\n /** Abort the active download. */\n cancel: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\nconst INITIAL_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\n\nconst INITIAL_STATE: UseFetchDownloadState = {\n phase: \"idle\",\n progress: INITIAL_PROGRESS,\n error: null,\n fileName: null,\n fileSize: null,\n};\n\nexport function useFetchDownload(\n options: UseFetchDownloadOptions,\n): UseFetchDownloadReturn {\n const [state, setState] = useState<UseFetchDownloadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const abortRef = useRef<AbortController | null>(null);\n const resettingRef = useRef(false);\n const speedTrackerRef = useRef(createSpeedTracker());\n const lastSpeedRef = useRef<number | undefined>(undefined);\n const lastSpeedUpdateRef = useRef(0);\n\n const download = useCallback(async (key: string, downloadName?: string) => {\n const fallback = key.split(\"/\").pop() ?? key;\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useFetchDownload or wrap with <S3Provider>.\",\n );\n\n if (opts.beforeDownload) {\n const allowed = await opts.beforeDownload(key);\n if (!allowed) {\n setState((s) => ({\n ...s,\n phase: \"error\",\n error: \"Download blocked by beforeDownload hook\",\n }));\n opts.onError?.(key, new Error(\"blocked\"), \"presigning\");\n return;\n }\n }\n\n setState({\n phase: \"presigning\",\n progress: INITIAL_PROGRESS,\n error: null,\n fileName: downloadName ?? null,\n fileSize: null,\n });\n\n try {\n const { url } = await api.download(key, {\n fileName: downloadName,\n bucket: opts.bucket,\n });\n setState((s) => ({ ...s, phase: \"downloading\" }));\n opts.onDownloadStart?.(key);\n\n speedTrackerRef.current.reset();\n lastSpeedRef.current = undefined;\n lastSpeedUpdateRef.current = 0;\n const controller = new AbortController();\n abortRef.current = controller;\n\n const res = await fetch(url, { signal: controller.signal });\n if (!res.ok) {\n throw new Error(\n res.status === 404\n ? \"File not found\"\n : `Download failed (${res.status})`,\n );\n }\n\n const contentLength = Number(res.headers.get(\"content-length\") || 0);\n const name =\n downloadName ??\n parseFileName(res.headers.get(\"content-disposition\")) ??\n fallback;\n setState((s) => ({\n ...s,\n fileName: name,\n fileSize: contentLength || null,\n }));\n\n const reader = res.body?.getReader();\n if (!reader) throw new Error(\"ReadableStream not supported\");\n\n const chunks: BlobPart[] = [];\n let loaded = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n loaded += value.byteLength;\n const percent =\n contentLength > 0 ? Math.round((loaded / contentLength) * 100) : 0;\n const rawSpeed = speedTrackerRef.current.update(loaded);\n const now = Date.now();\n if (rawSpeed > 0 && now - lastSpeedUpdateRef.current >= 500) {\n lastSpeedRef.current = rawSpeed;\n lastSpeedUpdateRef.current = now;\n }\n const speed = lastSpeedRef.current;\n const progress: UploadProgress = {\n loaded,\n total: contentLength,\n percent,\n ...(speed && { speed }),\n };\n setState((s) => ({ ...s, progress }));\n opts.onProgress?.(key, progress);\n }\n\n const blob = new Blob(chunks);\n const blobUrl = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = blobUrl;\n anchor.download = name ?? fallback;\n anchor.click();\n URL.revokeObjectURL(blobUrl);\n\n setState((s) => ({\n ...s,\n phase: \"success\",\n fileSize: blob.size,\n progress: { loaded: blob.size, total: blob.size, percent: 100 },\n }));\n await opts.onSuccess?.(key, name ?? fallback);\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n if (!resettingRef.current) opts.onCancel?.(key);\n resettingRef.current = false;\n setState(INITIAL_STATE);\n return;\n }\n const message = err instanceof Error ? err.message : \"Download failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(key, err, \"downloading\");\n } finally {\n abortRef.current = null;\n }\n }, []);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n resettingRef.current = true;\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n return { ...state, download, cancel, reset };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport type { DeletePhase, DeleteHooks } from \"../types\";\nimport { useLiveRef } from \"../internal-helpers\";\n\n/** Options for {@link useDelete}. */\nexport type UseDeleteOptions = DeleteHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Target bucket (overrides server default). */\n bucket?: string;\n};\n\nexport type UseDeleteState = {\n /** Current delete phase. */\n phase: DeletePhase;\n /** Error message, or `null`. */\n error: string | null;\n};\n\nexport type UseDeleteReturn = UseDeleteState & {\n /** Key awaiting confirmation, or `null`. */\n pendingKey: string | null;\n /** Move to the `confirming` phase for the given key. */\n requestDelete: (key: string) => void;\n /** Send the delete request for the pending key. */\n confirmDelete: () => Promise<void>;\n /** Cancel confirmation and return to `idle`. */\n cancelDelete: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\ntype InternalState = {\n phase: DeletePhase;\n error: string | null;\n pendingKey: string | null;\n};\n\nconst INITIAL_STATE: InternalState = {\n phase: \"idle\",\n error: null,\n pendingKey: null,\n};\n\nexport function useDelete(options: UseDeleteOptions): UseDeleteReturn {\n const [state, setState] = useState<InternalState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const pendingKeyRef = useRef<string | null>(null);\n\n const requestDelete = useCallback((key: string) => {\n pendingKeyRef.current = key;\n setState({ phase: \"confirming\", error: null, pendingKey: key });\n }, []);\n\n const confirmDelete = useCallback(async () => {\n const key = pendingKeyRef.current;\n if (!key) return;\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useDelete or wrap with <S3Provider>.\",\n );\n\n if (opts.beforeDelete) {\n const allowed = await opts.beforeDelete(key);\n if (!allowed) {\n setState({\n phase: \"error\",\n error: \"Delete blocked by beforeDelete hook\",\n pendingKey: null,\n });\n opts.onError?.(key, new Error(\"blocked\"), \"confirming\");\n pendingKeyRef.current = null;\n return;\n }\n }\n\n setState((s) => ({ ...s, phase: \"deleting\", error: null }));\n opts.onDeleteStart?.(key);\n\n try {\n await api.delete(key, { bucket: opts.bucket });\n pendingKeyRef.current = null;\n setState({ phase: \"success\", error: null, pendingKey: null });\n await opts.onSuccess?.(key);\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Delete failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(key, err, \"deleting\");\n }\n }, []);\n\n const cancelDelete = useCallback(() => {\n pendingKeyRef.current = null;\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n pendingKeyRef.current = null;\n setState(INITIAL_STATE);\n }, []);\n\n return {\n phase: state.phase,\n error: state.error,\n pendingKey: state.pendingKey,\n requestDelete,\n confirmDelete,\n cancelDelete,\n reset,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types/error.ts","../src/api.ts","../src/s3-provider.tsx","../src/store/local-storage-store.ts","../src/store/memory-store.ts","../src/upload/constants.ts","../src/upload/retry.ts","../src/upload/simple.ts","../src/upload/part.ts","../src/upload/multipart.ts","../src/upload/upload-file.ts","../src/upload/upload-files.ts","../src/helpers/format-accept-labels.ts","../src/helpers/format-upload-progress.ts","../src/helpers/format-speed.ts","../src/helpers/format-eta.ts","../src/helpers/speed-tracker.ts","../src/internal-helpers.ts","../src/hooks/use-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-upload-controls.ts","../src/hooks/use-multi-upload-controls.ts","../src/hooks/use-download.ts","../src/hooks/use-fetch-download.ts","../src/hooks/use-delete.ts"],"names":["parts","formatFileSize","useContext","useRef","INITIAL_PROGRESS","INITIAL_STATE","useState","useCallback","validateFile"],"mappings":"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","file":"index.js","sourcesContent":["import type { UploadPhase } from \"./upload\";\n\n/**\n * Structured error thrown by the upload engine.\n *\n * - `code` — machine-readable error code (e.g. `\"VALIDATION_ERROR\"`, `\"NETWORK_ERROR\"`)\n * - `statusCode` — HTTP status code when the error originated from a server response\n * - `phase` — upload phase in which the error occurred\n */\nexport class S3UploadError extends Error {\n readonly code: string;\n readonly statusCode: number | undefined;\n readonly phase: UploadPhase | undefined;\n\n constructor(\n message: string,\n code: string,\n statusCode?: number,\n phase?: UploadPhase,\n ) {\n super(message);\n this.name = \"S3UploadError\";\n this.code = code;\n this.statusCode = statusCode;\n this.phase = phase;\n }\n}\n","/**\n * Client-side factory for the better-s3 presign API.\n *\n * Accepts an `S3Api` object — implement each method to call your own backend\n * endpoint, tRPC mutation, GraphQL query, or anything else. The object is\n * returned as-is; `createS3Client` just enforces the type contract.\n *\n * If you are using the default better-s3 route layout, use `createS3Api` from\n * `@better-s3/core` — it builds a standard fetch client from a base path.\n *\n * @example\n * ```ts\n * import { createS3Client } from \"@better-s3/react\";\n *\n * export const s3Client = createS3Client({\n * async upload(payload) {\n * return fetch(\"/api/storage/presign\", { method: \"POST\", body: JSON.stringify(payload) })\n * .then(r => r.json());\n * },\n * async confirm(payload) { ... },\n * async download(key, options) { ... },\n * async delete(key) { ... },\n * multipart: { init, signPart, listParts, complete, abort },\n * });\n * ```\n */\nimport type { S3Api } from \"@better-s3/core\";\n\nexport function createS3Client(input: S3Api): S3Api {\n return input;\n}\n","\"use client\";\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\n\n/**\n * Internal context — use `S3Provider` to supply and `useS3Client` to consume.\n * Exported so hooks can call `useContext(S3Context)` directly without throwing\n * when `api` is passed explicitly.\n */\nexport const S3Context = createContext<S3Api | null>(null);\n\n/**\n * Provides an `S3Api` client to all child hooks and UI components.\n *\n * Wrap your app (or a sub-tree) once; hooks no longer need `api` passed\n * individually.\n *\n * @example\n * ```tsx\n * // With @better-s3/server:\n * import { createS3Api } from \"@better-s3/core\";\n * import { S3Provider } from \"@better-s3/react\";\n *\n * const s3Client = createS3Api();\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return <S3Provider client={s3Client}>{children}</S3Provider>;\n * }\n *\n * // Custom base path:\n * import { createS3Api } from \"@better-s3/core\";\n *\n * const s3Client = createS3Api(\"/api/my-s3\");\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return <S3Provider client={s3Client}>{children}</S3Provider>;\n * }\n * ```\n */\nexport function S3Provider({\n client,\n children,\n}: {\n client: S3Api;\n children: ReactNode;\n}) {\n return <S3Context.Provider value={client}>{children}</S3Context.Provider>;\n}\n\n/**\n * Returns the `S3Api` client from the nearest `S3Provider`.\n * Throws if called outside a provider and no `api` prop was given to the hook.\n *\n * @throws if no `S3Provider` is found in the tree.\n */\nexport function useS3Client(): S3Api {\n const ctx = useContext(S3Context);\n if (!ctx) {\n throw new Error(\n \"[better-s3] No S3Api client found. \" +\n \"Either wrap your app with <S3Provider client={...}> or pass `api` directly to the hook.\",\n );\n }\n return ctx;\n}\n","import type { StoredUpload, UploadStore } from \"../types/upload-store\";\n\nconst STORAGE_PREFIX = \"better-s3:upload:\";\n\n/**\n * Default `UploadStore` implementation backed by `localStorage`.\n * Stores one pending upload per S3 object key.\n *\n * Falls back silently when `localStorage` is unavailable (SSR, private\n * browsing with full quota, or environments without a `window` object).\n */\nexport function createLocalStorageStore(): UploadStore {\n return {\n get(key, fileSize) {\n try {\n const raw = localStorage.getItem(STORAGE_PREFIX + key);\n if (!raw) return null;\n const stored = JSON.parse(raw) as StoredUpload;\n // Reject if the stored size doesn't match — different file for the same key.\n return stored.fileSize === fileSize ? stored : null;\n } catch {\n return null;\n }\n },\n\n set(upload) {\n try {\n localStorage.setItem(\n STORAGE_PREFIX + upload.key,\n JSON.stringify(upload),\n );\n } catch {\n // localStorage unavailable (SSR, quota exceeded) — silently skip.\n }\n },\n\n delete(key) {\n try {\n localStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // ignore\n }\n },\n };\n}\n","import type { StoredUpload, UploadStore } from \"../types/upload-store\";\n\n/**\n * In-memory `UploadStore` — safe for SSR and server-component environments.\n *\n * State is cleared on page reload. Useful as a fallback, for testing, or\n * when you want session-scoped resume without touching `localStorage`.\n *\n * @example\n * ```ts\n * const store = createMemoryStore();\n * useUpload({ api, uploadStore: store });\n * ```\n */\nexport function createMemoryStore(): UploadStore {\n const map = new Map<string, StoredUpload>();\n\n return {\n get(key, fileSize) {\n const stored = map.get(key);\n if (!stored) return null;\n return stored.fileSize === fileSize ? stored : null;\n },\n\n set(upload) {\n map.set(upload.key, upload);\n },\n\n delete(key) {\n map.delete(key);\n },\n };\n}\n","export const DEFAULT_MULTIPART_THRESHOLD = 50 * 1024 * 1024; // 50 MB\nexport const DEFAULT_PART_SIZE = 5 * 1024 * 1024; // 5 MB\nexport const MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY = 1_000; // ms\nexport const DEFAULT_CONCURRENT_PARTS = 2;\nexport const DEFAULT_CONCURRENT_FILES = 2;\n","import { MAX_RETRIES, RETRY_BASE_DELAY } from \"./constants\";\nimport type { RetryConfig } from \"../types\";\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n retryConfig: RetryConfig | undefined,\n signal?: AbortSignal,\n): Promise<T> {\n const maxRetries = retryConfig?.maxRetries ?? MAX_RETRIES;\n const baseDelay = retryConfig?.baseDelay ?? RETRY_BASE_DELAY;\n\n let lastError: unknown;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n if ((err as Error).name === \"AbortError\") throw err;\n lastError = err;\n if (attempt < maxRetries) {\n const delay = baseDelay * 2 ** attempt;\n await new Promise((r) => setTimeout(r, delay));\n if (signal?.aborted)\n throw new DOMException(\"Upload aborted\", \"AbortError\");\n }\n }\n }\n throw lastError;\n}\n","import type { UploadProgress } from \"../types\";\n\n/**\n * Uploads a file directly to S3 using a presigned POST form.\n *\n * All policy fields (acl, Content-Type, content-length-range, signature, etc.)\n * are embedded in `fields` and must be appended to the FormData **before** the\n * file — this is an S3 requirement. The size constraint is enforced by S3 at\n * the storage layer, so the server never needs to re-validate it.\n */\nexport function uploadSimple(\n file: File,\n url: string,\n fields: Record<string, string>,\n onProgress?: (progress: UploadProgress) => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n const onAbort = () => {\n xhr.abort();\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) {\n onProgress?.({\n loaded: e.loaded,\n total: e.total,\n percent: Math.round((e.loaded / e.total) * 100),\n });\n }\n });\n\n xhr.addEventListener(\"load\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (xhr.status >= 200 && xhr.status < 300) {\n onProgress?.({ loaded: file.size, total: file.size, percent: 100 });\n resolve();\n } else {\n reject(new Error(`Upload failed: ${xhr.status} ${xhr.statusText}`));\n }\n });\n\n xhr.addEventListener(\"error\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"Upload failed: network error\"));\n });\n\n xhr.addEventListener(\"abort\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n });\n\n // S3 presigned POST: policy fields must come before the file field.\n const formData = new FormData();\n for (const [k, v] of Object.entries(fields)) {\n formData.append(k, v);\n }\n formData.append(\"file\", file);\n\n xhr.open(\"POST\", url);\n xhr.send(formData);\n });\n}\n\n/**\n * Uploads a file directly to S3 using a presigned PUT URL.\n *\n * Use this when the server is configured with `upload.method = \"PUT\"` — for\n * example with Cloudflare R2 which does not support presigned POST.\n * The `headers` object must match exactly what was signed on the server\n * (Content-Type, Content-Disposition, x-amz-meta-*, etc.).\n */\nexport function uploadPut(\n file: File,\n url: string,\n headers: Record<string, string>,\n onProgress?: (progress: UploadProgress) => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n const onAbort = () => {\n xhr.abort();\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) {\n onProgress?.({\n loaded: e.loaded,\n total: e.total,\n percent: Math.round((e.loaded / e.total) * 100),\n });\n }\n });\n\n xhr.addEventListener(\"load\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (xhr.status >= 200 && xhr.status < 300) {\n onProgress?.({ loaded: file.size, total: file.size, percent: 100 });\n resolve();\n } else {\n reject(new Error(`Upload failed: ${xhr.status} ${xhr.statusText}`));\n }\n });\n\n xhr.addEventListener(\"error\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"Upload failed: network error\"));\n });\n\n xhr.addEventListener(\"abort\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n });\n\n xhr.open(\"PUT\", url);\n for (const [k, v] of Object.entries(headers)) {\n xhr.setRequestHeader(k, v);\n }\n xhr.send(file);\n });\n}\n","export function uploadPart(\n blob: Blob,\n presignedUrl: string,\n partLoaded: { bytes: number },\n totalSize: number,\n reportProgress: () => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n const onAbort = () => {\n xhr.abort();\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) {\n partLoaded.bytes = e.loaded;\n reportProgress();\n }\n });\n\n xhr.addEventListener(\"load\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (xhr.status >= 200 && xhr.status < 300) {\n partLoaded.bytes = blob.size;\n reportProgress();\n resolve();\n } else {\n reject(new Error(`Part upload failed: ${xhr.status}`));\n }\n });\n\n xhr.addEventListener(\"error\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"Part upload failed: network error\"));\n });\n\n xhr.addEventListener(\"abort\", () => {\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"Upload aborted\", \"AbortError\"));\n });\n\n xhr.open(\"PUT\", presignedUrl);\n xhr.send(blob);\n });\n}\n","import type {\n UploadProgress,\n UploadRequestOptions,\n RetryConfig,\n} from \"../types\";\nimport type { S3Api } from \"@better-s3/core\";\nimport type { UploadStore } from \"../types/upload-store\";\nimport { withRetry } from \"./retry\";\nimport { uploadPart } from \"./part\";\n\n/** Returns the byte size of a specific part (last part may be smaller). */\nfunction resolvePartSize(\n partIndex: number,\n totalParts: number,\n partSize: number,\n fileSize: number,\n): number {\n return partIndex === totalParts - 1\n ? fileSize - partIndex * partSize\n : partSize;\n}\n\nexport async function uploadMultipart(\n api: S3Api,\n file: File,\n objectKey: string,\n partSize: number,\n concurrentParts: number,\n onProgress?: (progress: UploadProgress) => void,\n signal?: AbortSignal,\n requestOptions?: UploadRequestOptions,\n retryConfig?: RetryConfig,\n uploadStore?: UploadStore | false,\n onPartUpload?: (partNumber: number, totalParts: number) => void,\n onMultipartInit?: (uploadId: string, key: string) => void,\n): Promise<string | undefined> {\n const bucket = requestOptions?.bucket;\n const contentType = requestOptions?.contentType ?? file.type;\n\n // Resolve the active store.\n // null → resumability disabled (uploadStore omitted, false, or SSR)\n // store → resumability enabled; persist uploadId across sessions\n const store: UploadStore | null =\n uploadStore != null && uploadStore !== false ? uploadStore : null;\n\n let uploadId: string;\n let key: string;\n const completedPartNumbers = new Set<number>();\n\n // ── Attempt to resume an existing upload ─────────────────────────────────\n const existing = store ? await store.get(objectKey, file.size) : null;\n\n if (existing) {\n try {\n // Verify the uploadId is still valid on S3 and fetch already-done parts.\n const { parts } = await api.multipart.listParts({\n key: existing.key,\n uploadId: existing.uploadId,\n bucket: bucket ?? existing.bucket,\n });\n uploadId = existing.uploadId;\n key = existing.key;\n for (const p of parts) completedPartNumbers.add(p.partNumber);\n onMultipartInit?.(uploadId, key);\n } catch {\n // uploadId is expired or no longer valid — start a fresh upload.\n await store?.delete(objectKey);\n const result = await api.multipart.init({\n key: objectKey,\n contentType,\n fileSize: file.size,\n fileName:\n requestOptions?.fileName !== null\n ? (requestOptions?.fileName ?? file.name)\n : undefined,\n metadata: requestOptions?.metadata,\n bucket,\n acl: requestOptions?.acl,\n });\n uploadId = result.uploadId;\n key = result.key;\n await store?.set({ uploadId, key, fileSize: file.size, bucket });\n onMultipartInit?.(uploadId, key);\n }\n } else {\n const result = await api.multipart.init({\n key: objectKey,\n contentType,\n fileSize: file.size,\n fileName:\n requestOptions?.fileName !== null\n ? (requestOptions?.fileName ?? file.name)\n : undefined,\n metadata: requestOptions?.metadata,\n bucket,\n acl: requestOptions?.acl,\n });\n uploadId = result.uploadId;\n key = result.key;\n await store?.set({ uploadId, key, fileSize: file.size, bucket });\n onMultipartInit?.(uploadId, key);\n }\n\n // ── Setup progress tracking ───────────────────────────────────────────────\n const totalParts = Math.ceil(file.size / partSize);\n\n // Pre-fill progress bytes for already-completed parts.\n const partProgress: Array<{ bytes: number }> = Array.from(\n { length: totalParts },\n (_, i) => ({\n bytes: completedPartNumbers.has(i + 1)\n ? resolvePartSize(i, totalParts, partSize, file.size)\n : 0,\n }),\n );\n\n // Pre-register completed parts so complete() receives a full list.\n const parts: Array<{ partNumber: number }> = Array.from(\n completedPartNumbers,\n (n) => ({ partNumber: n }),\n );\n\n const reportProgress = () => {\n const loaded = partProgress.reduce((sum, p) => sum + p.bytes, 0);\n onProgress?.({\n loaded,\n total: file.size,\n percent: Math.round((loaded / file.size) * 100),\n });\n };\n\n // Report initial progress for pre-completed parts before uploading starts.\n if (completedPartNumbers.size > 0) {\n reportProgress();\n }\n\n // ── Upload remaining parts ────────────────────────────────────────────────\n try {\n for (\n let batchStart = 0;\n batchStart < totalParts;\n batchStart += concurrentParts\n ) {\n if (signal?.aborted) {\n throw new DOMException(\"Upload aborted\", \"AbortError\");\n }\n\n const batchEnd = Math.min(batchStart + concurrentParts, totalParts);\n const batch: Array<Promise<{ partNumber: number }>> = [];\n\n for (let i = batchStart; i < batchEnd; i++) {\n const partNumber = i + 1;\n\n // Skip parts that were already uploaded in a previous attempt.\n if (completedPartNumbers.has(partNumber)) continue;\n\n const start = i * partSize;\n const end = Math.min(start + partSize, file.size);\n const blob = file.slice(start, end);\n\n batch.push(\n withRetry(\n async () => {\n const { presignedUrl } = await api.multipart.signPart({\n key,\n uploadId,\n partNumber,\n partSize: blob.size,\n bucket,\n });\n\n partProgress[i].bytes = 0;\n\n await uploadPart(\n blob,\n presignedUrl,\n partProgress[i],\n file.size,\n reportProgress,\n signal,\n );\n\n onPartUpload?.(partNumber, totalParts);\n return { partNumber };\n },\n retryConfig,\n signal,\n ),\n );\n }\n\n const batchResults = await Promise.all(batch);\n parts.push(...batchResults);\n }\n\n parts.sort((a, b) => a.partNumber - b.partNumber);\n\n const result = await api.multipart.complete({\n key,\n uploadId,\n parts,\n bucket,\n });\n\n // Upload finished successfully — remove from store.\n await store?.delete(objectKey);\n\n onProgress?.({ loaded: file.size, total: file.size, percent: 100 });\n return result.eTag;\n } catch (err) {\n if (store === null) {\n // Resumability is disabled — clean up the S3 multipart upload immediately.\n api.multipart.abort({ key, uploadId, bucket }).catch(() => {});\n }\n // With store active: preserve uploadId so the upload can be resumed later.\n // The S3 multipart upload is left open (expires automatically per bucket policy).\n throw err;\n }\n}\n","import type {\n UploadConfig,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n} from \"../types\";\nimport type { S3Api } from \"@better-s3/core\";\nimport {\n DEFAULT_MULTIPART_THRESHOLD,\n DEFAULT_CONCURRENT_PARTS,\n DEFAULT_PART_SIZE,\n} from \"./constants\";\nimport { withRetry } from \"./retry\";\nimport { uploadSimple, uploadPut } from \"./simple\";\nimport { uploadMultipart } from \"./multipart\";\n\nexport type UploadEngineCallbacks = {\n onProgress?: (progress: UploadProgress) => void;\n /** Called when the upload transitions between internal phases. */\n onPhaseChange?: (phase: \"presigning\" | \"uploading\" | \"finalizing\") => void;\n /** Called after each individual multipart part is successfully uploaded. */\n onPartUpload?: (partNumber: number, totalParts: number) => void;\n /** Called once after `CreateMultipartUpload` succeeds with the S3-assigned `uploadId` and final object `key`. */\n onMultipartInit?: (uploadId: string, key: string) => void;\n};\n\nexport async function uploadFile(\n api: S3Api,\n file: File,\n objectKey: string,\n config: UploadConfig = {},\n callbacks: UploadEngineCallbacks = {},\n signal?: AbortSignal,\n requestOptions?: UploadRequestOptions,\n): Promise<UploadResult> {\n const threshold = config.multipartThreshold ?? DEFAULT_MULTIPART_THRESHOLD;\n const useMultipart = config.multipart === true && file.size >= threshold;\n const concurrentParts = config.concurrentParts ?? DEFAULT_CONCURRENT_PARTS;\n const partSize =\n requestOptions?.partSize ?? config.partSize ?? DEFAULT_PART_SIZE;\n const contentType = requestOptions?.contentType ?? file.type;\n\n let eTag: string | undefined;\n\n if (useMultipart) {\n callbacks.onPhaseChange?.(\"uploading\");\n eTag = await uploadMultipart(\n api,\n file,\n objectKey,\n partSize,\n concurrentParts,\n callbacks.onProgress,\n signal,\n requestOptions,\n config.retry,\n config.uploadStore,\n callbacks.onPartUpload,\n callbacks.onMultipartInit,\n );\n } else {\n await withRetry(\n async () => {\n callbacks.onPhaseChange?.(\"presigning\");\n const presign = await api.upload({\n key: objectKey,\n contentType,\n fileSize: file.size,\n fileName:\n requestOptions?.fileName !== null\n ? (requestOptions?.fileName ?? file.name)\n : undefined,\n metadata: requestOptions?.metadata,\n bucket: requestOptions?.bucket,\n acl: requestOptions?.acl,\n });\n callbacks.onPhaseChange?.(\"uploading\");\n if (presign.method === \"PUT\") {\n await uploadPut(\n file,\n presign.url,\n presign.headers ?? {},\n callbacks.onProgress,\n signal,\n );\n } else {\n await uploadSimple(\n file,\n presign.url,\n presign.fields ?? {},\n callbacks.onProgress,\n signal,\n );\n }\n },\n config.retry,\n signal,\n );\n\n callbacks.onPhaseChange?.(\"finalizing\");\n const confirmed = await api.confirm({\n key: objectKey,\n bucket: requestOptions?.bucket,\n });\n eTag = confirmed.eTag;\n }\n\n return { key: objectKey, eTag };\n}\n","import type {\n UploadConfig,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n} from \"../types\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { DEFAULT_CONCURRENT_FILES } from \"./constants\";\nimport { uploadFile } from \"./upload-file\";\n\nexport type FileItemStatus = \"pending\" | \"uploading\" | \"success\" | \"error\";\n\nexport type FileItem = {\n id: string;\n file: File;\n objectKey: string;\n status: FileItemStatus;\n progress: UploadProgress;\n result: UploadResult | null;\n error: string | null;\n};\n\nexport type MultiUploadCallbacks = {\n onFileProgress?: (id: string, progress: UploadProgress) => void;\n onFileSuccess?: (id: string, result: UploadResult) => void;\n onFileError?: (id: string, error: string) => void;\n onTotalProgress?: (progress: UploadProgress) => void;\n};\n\nexport async function uploadFiles(\n api: S3Api,\n items: Array<{ id: string; file: File; objectKey: string }>,\n config: UploadConfig = {},\n callbacks: MultiUploadCallbacks = {},\n signal?: AbortSignal,\n getRequestOptions?: (file: File) => UploadRequestOptions,\n): Promise<FileItem[]> {\n const results: FileItem[] = items.map((item) => ({\n ...item,\n status: \"pending\" as FileItemStatus,\n progress: { loaded: 0, total: item.file.size, percent: 0 },\n result: null,\n error: null,\n }));\n\n const reportTotalProgress = () => {\n const loaded = results.reduce((sum, r) => sum + r.progress.loaded, 0);\n const total = results.reduce((sum, r) => sum + r.progress.total, 0);\n callbacks.onTotalProgress?.({\n loaded,\n total,\n percent: total > 0 ? Math.round((loaded / total) * 100) : 0,\n });\n };\n\n let nextIndex = 0;\n\n const processNext = async (): Promise<void> => {\n while (nextIndex < results.length) {\n if (signal?.aborted) return;\n const idx = nextIndex++;\n const item = results[idx];\n\n item.status = \"uploading\";\n\n try {\n const result = await uploadFile(\n api,\n item.file,\n item.objectKey,\n config,\n {\n onProgress: (progress) => {\n item.progress = progress;\n callbacks.onFileProgress?.(item.id, progress);\n reportTotalProgress();\n },\n },\n signal,\n getRequestOptions?.(item.file),\n );\n item.status = \"success\";\n item.result = result;\n item.progress = {\n loaded: item.file.size,\n total: item.file.size,\n percent: 100,\n };\n callbacks.onFileSuccess?.(item.id, result);\n reportTotalProgress();\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n item.status = \"error\";\n item.error = \"Upload cancelled\";\n return;\n }\n const message = err instanceof Error ? err.message : \"Upload failed\";\n item.status = \"error\";\n item.error = message;\n callbacks.onFileError?.(item.id, message);\n reportTotalProgress();\n }\n }\n };\n\n const concurrentFiles = config.concurrentFiles ?? DEFAULT_CONCURRENT_FILES;\n const workers = Array.from(\n { length: Math.min(concurrentFiles, items.length) },\n () => processNext(),\n );\n await Promise.all(workers);\n\n return results;\n}\n","function formatAcceptLabel(type: string): string {\n if (type.startsWith(\".\")) {\n const ext = type.slice(1).toLowerCase();\n return ext === \"jpg\" || ext === \"jpeg\" ? \"JPEG\" : ext.toUpperCase();\n }\n if (type.endsWith(\"/*\")) {\n const base = type.slice(0, -2);\n return base.charAt(0).toUpperCase() + base.slice(1) + \"s\";\n }\n const sub = type.split(\"/\")[1];\n return sub ? sub.toUpperCase() : type;\n}\n\n/** Normalizes HTML `accept` entries to short display labels (e.g. `\".jpeg\"` → `\"JPEG\"`). */\nexport function formatAcceptLabels(accept?: string[]): string[] {\n if (!accept?.length) return [];\n\n const labels: string[] = [];\n const seen = new Set<string>();\n\n for (const type of accept) {\n const label = formatAcceptLabel(type);\n if (!seen.has(label)) {\n seen.add(label);\n labels.push(label);\n }\n }\n\n return labels;\n}\n","import { formatFileSize } from \"@better-s3/core\";\n\n/**\n * Formats upload progress as a human-readable transfer string.\n *\n * @param loaded Bytes transferred so far.\n * @param total Total bytes to transfer (0 means unknown).\n * @param percent Transfer percentage (0–100).\n *\n * @example\n * ```ts\n * formatUploadProgress(1_200_000, 5_600_000, 21)\n * // → \"1.2 MB / 5.6 MB (21%)\"\n *\n * formatUploadProgress(1_200_000, 0, 0)\n * // → \"1.2 MB\"\n * ```\n */\nexport function formatUploadProgress(\n loaded: number,\n total: number,\n percent: number,\n): string {\n const loadedStr = formatFileSize(loaded);\n if (!total) return loadedStr;\n return `${loadedStr} / ${formatFileSize(total)} (${Math.round(percent)}%)`;\n}\n","import { formatFileSize } from \"@better-s3/core\";\n\n/**\n * Formats a transfer speed (bytes/second) as a human-readable string.\n *\n * @example\n * formatSpeed(1_200_000) // → \"1.2 MB/s\"\n * formatSpeed(512) // → \"512 B/s\"\n */\nexport function formatSpeed(bytesPerSecond: number): string {\n return `${formatFileSize(bytesPerSecond)}/s`;\n}\n","/**\n * Formats an estimated remaining time given the remaining bytes and current speed.\n *\n * Returns `null` when speed is 0 or nothing remains (not yet calculable).\n *\n * @example\n * formatEta(4_400_000, 450_000) // → \"9s\"\n * formatEta(4_400_000, 75_000) // → \"58s\"\n * formatEta(90_000_000, 1_500_000) // → \"1m\"\n * formatEta(5_400_000_000, 500_000) // → \"3h\"\n */\nexport function formatEta(\n remainingBytes: number,\n bytesPerSecond: number,\n): string | null {\n if (bytesPerSecond <= 0 || remainingBytes <= 0) return null;\n const totalSeconds = remainingBytes / bytesPerSecond;\n\n if (totalSeconds < 60) return `${Math.ceil(totalSeconds)}s`;\n\n const totalMinutes = totalSeconds / 60;\n if (totalMinutes < 60) return `${Math.ceil(totalMinutes)}m`;\n\n const hours = Math.floor(totalMinutes / 60);\n const mins = Math.ceil(totalMinutes % 60);\n return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;\n}\n","/**\n * Creates a sliding-window transfer speed calculator.\n *\n * Tracks bytes transferred over a rolling time window to produce a smooth,\n * instantaneous speed reading in bytes/second.\n *\n * @param windowMs Rolling window duration in milliseconds. @default 3000\n */\nexport function createSpeedTracker(windowMs = 3000) {\n const samples: Array<{ t: number; loaded: number }> = [];\n\n return {\n /**\n * Record the latest cumulative `loaded` byte count.\n * Returns the current speed in bytes/second (0 until at least 2 samples exist).\n */\n update(loaded: number): number {\n const now = Date.now();\n samples.push({ t: now, loaded });\n\n // Prune samples older than the window, but keep at least one anchor.\n const cutoff = now - windowMs;\n while (samples.length > 1 && samples[0].t < cutoff) {\n samples.shift();\n }\n\n if (samples.length < 2) return 0;\n\n const oldest = samples[0];\n const newest = samples[samples.length - 1];\n const deltaMs = newest.t - oldest.t;\n const deltaBytes = newest.loaded - oldest.loaded;\n\n return deltaMs > 0 ? Math.round((deltaBytes / deltaMs) * 1000) : 0;\n },\n\n reset() {\n samples.length = 0;\n },\n };\n}\n\nexport type SpeedTracker = ReturnType<typeof createSpeedTracker>;\n","import { useRef } from \"react\";\n\n/**\n * Keeps a ref in sync with the latest value on every render.\n *\n * Use inside `useCallback(fn, [])` to read the latest prop / option value\n * without making the callback depend on it (stale-closure-free stable refs).\n *\n * @internal — not part of the public API.\n */\nexport function useLiveRef<T>(value: T) {\n const ref = useRef(value);\n ref.current = value;\n return ref;\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { validateFile } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { createSpeedTracker } from \"../helpers/speed-tracker\";\nimport { useLiveRef } from \"../internal-helpers\";\nimport type {\n UploadConfig,\n UploadHooks,\n UploadPhase,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n} from \"../types\";\nimport { uploadFile } from \"../upload\";\n\n/** Options for {@link useUpload}. */\nexport type UseUploadOptions = UploadConfig &\n UploadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n };\n\nexport type UseUploadState = {\n /** Current upload phase. */\n phase: UploadPhase;\n /** Byte transfer progress. */\n progress: UploadProgress;\n /** Error message, or `null`. */\n error: string | null;\n /** Result after success, or `null`. */\n result: UploadResult | null;\n /** Name of the file being uploaded. */\n fileName: string | null;\n /** Size of the file being uploaded in bytes. */\n fileSize: number | null;\n};\n\nexport type UseUploadReturn = UseUploadState & {\n /**\n * Start an upload.\n *\n * Safe to call again after `success`, `error`, or `cancel` — state is reset\n * automatically before the new upload begins.\n *\n * If `uploadStore` is configured and a previous upload for the same\n * `objectKey` was interrupted (e.g. via `detach()`), the engine will find\n * the stored `uploadId`, call `listParts`, and resume from the last completed\n * part rather than starting a new multipart upload.\n */\n upload: (\n file: File,\n objectKey: string,\n requestOptions?: UploadRequestOptions,\n ) => Promise<void>;\n /**\n * Abort the upload and fully clean up all resources.\n *\n * - Stops the in-flight network request immediately.\n * - For multipart uploads: calls `AbortMultipartUpload` on S3 so incomplete\n * parts are freed right away (instead of waiting for the bucket lifecycle\n * policy to expire them).\n * - Removes the `uploadStore` entry if one was provided.\n * - Resets state to `idle`.\n *\n * Use this for a \"Cancel\" button that the user explicitly clicks to abandon\n * the upload entirely.\n */\n cancel: () => void;\n /**\n * Stop the upload and — when multipart with `uploadStore` is active —\n * preserve S3 parts and the store entry for a future resume.\n *\n * Compared to `cancel()`:\n * - Does **not** call `AbortMultipartUpload` (parts stay on S3).\n * - Does **not** remove the `uploadStore` entry.\n * - Does **not** fire the `onCancel` callback.\n *\n * The next call to `upload(sameFile, sameKey)` will detect the stored\n * `uploadId`, verify the existing parts via `listParts`, and continue\n * uploading from where it stopped.\n *\n * For **simple uploads** or multipart **without** `uploadStore`, this is\n * identical to `cancel()` — there is no S3 state worth preserving.\n *\n * Intended for custom UIs that want to offer a \"save for later / resume\"\n * workflow. The built-in UI components always use `cancel()`.\n */\n detach: () => void;\n /**\n * Reset UI state to `idle` without touching any S3 or store resources.\n *\n * - Stops the in-flight network request if one is active.\n * - Does **not** call `AbortMultipartUpload`.\n * - Does **not** modify `uploadStore`.\n * - Does **not** fire `onCancel`.\n *\n * Use this to clear an error or success state from the UI, or when you\n * handle cleanup yourself outside this hook.\n */\n reset: () => void;\n};\n\nconst INITIAL_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\n\nconst INITIAL_STATE: UseUploadState = {\n phase: \"idle\",\n progress: INITIAL_PROGRESS,\n error: null,\n result: null,\n fileName: null,\n fileSize: null,\n};\n\ntype ActiveUpload = {\n file: File;\n objectKey: string;\n /** S3 key as returned by the server (may differ from objectKey). */\n serverKey: string;\n uploadId?: string;\n bucket?: string;\n requestOptions?: UploadRequestOptions;\n};\n\nexport function useUpload(options: UseUploadOptions): UseUploadReturn {\n const [state, setState] = useState<UseUploadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const abortRef = useRef<AbortController | null>(null);\n /** Tracks the in-flight upload so cancel/detach can access uploadId and key. */\n const activeUploadRef = useRef<ActiveUpload | null>(null);\n /** Set before aborting so the AbortError catch skips cancel callbacks. */\n const detachingRef = useRef(false);\n const speedTrackerRef = useRef(createSpeedTracker());\n const lastSpeedRef = useRef<number | undefined>(undefined);\n const lastSpeedUpdateRef = useRef(0);\n\n const upload = useCallback(\n async (\n file: File,\n objectKey: string,\n requestOptions?: UploadRequestOptions,\n ) => {\n setState({\n ...INITIAL_STATE,\n phase: \"validating\",\n fileName: file.name,\n fileSize: file.size,\n });\n\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useUpload or wrap with <S3Provider>.\",\n );\n\n const validationError = validateFile(file, {\n accept: opts.accept,\n maxFileSize: opts.maxFileSize,\n });\n if (validationError) {\n setState((s) => ({ ...s, phase: \"error\", error: validationError }));\n opts.onError?.(file, new Error(validationError), \"validating\");\n return;\n }\n\n if (opts.beforeUpload) {\n const allowed = await opts.beforeUpload(file);\n if (!allowed) {\n setState((s) => ({\n ...s,\n phase: \"error\",\n error: \"Upload blocked by beforeUpload hook\",\n }));\n opts.onError?.(file, new Error(\"blocked\"), \"validating\");\n return;\n }\n }\n\n speedTrackerRef.current.reset();\n lastSpeedRef.current = undefined;\n lastSpeedUpdateRef.current = 0;\n setState((s) => ({ ...s, phase: \"presigning\" }));\n opts.onUploadStart?.(file, objectKey);\n\n const controller = new AbortController();\n abortRef.current = controller;\n activeUploadRef.current = {\n file,\n objectKey,\n serverKey: objectKey,\n bucket: requestOptions?.bucket,\n requestOptions,\n };\n\n try {\n const result = await uploadFile(\n api,\n file,\n objectKey,\n {\n multipart: opts.multipart,\n multipartThreshold: opts.multipartThreshold,\n concurrentParts: opts.concurrentParts,\n partSize: opts.partSize,\n retry: opts.retry,\n uploadStore: opts.uploadStore,\n },\n {\n onProgress: (progress) => {\n const rawSpeed = speedTrackerRef.current.update(progress.loaded);\n const now = Date.now();\n if (rawSpeed > 0 && now - lastSpeedUpdateRef.current >= 500) {\n lastSpeedRef.current = rawSpeed;\n lastSpeedUpdateRef.current = now;\n }\n const speed = lastSpeedRef.current;\n const p = speed ? { ...progress, speed } : progress;\n setState((s) => ({ ...s, progress: p }));\n opts.onProgress?.(file, p);\n },\n onPhaseChange: (phase) => setState((s) => ({ ...s, phase })),\n onPartUpload: (partNumber, totalParts) =>\n opts.onPartUpload?.(file, partNumber, totalParts),\n onMultipartInit: (uploadId, serverKey) => {\n if (activeUploadRef.current) {\n activeUploadRef.current.uploadId = uploadId;\n activeUploadRef.current.serverKey = serverKey;\n }\n opts.onMultipartInit?.(file, uploadId);\n },\n },\n controller.signal,\n requestOptions,\n );\n\n setState((s) => ({\n ...s,\n phase: \"success\",\n result,\n progress: { loaded: file.size, total: file.size, percent: 100 },\n }));\n await opts.onSuccess?.(file, result);\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n if (detachingRef.current) {\n detachingRef.current = false;\n return;\n }\n opts.onCancel?.(file);\n setState(INITIAL_STATE);\n return;\n }\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(file, err, \"uploading\");\n } finally {\n abortRef.current = null;\n activeUploadRef.current = null;\n }\n },\n [],\n );\n\n const cancel = useCallback(() => {\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n const active = activeUploadRef.current;\n abortRef.current?.abort();\n if (active && api) {\n const { objectKey, serverKey, uploadId, bucket } = active;\n const store = opts.uploadStore;\n if (store != null && store !== false) {\n void Promise.resolve(store.delete(objectKey)).catch(() => {});\n }\n if (uploadId) {\n api.multipart\n .abort({ key: serverKey, uploadId, bucket })\n .catch(() => {});\n }\n }\n setState(INITIAL_STATE);\n }, []);\n\n const detach = useCallback(() => {\n const active = activeUploadRef.current;\n if (!active) return;\n // Signal the AbortError catch not to fire onCancel or re-reset state.\n detachingRef.current = true;\n abortRef.current?.abort();\n // multipart.ts already preserves the store entry when store != null,\n // so no extra cleanup is needed here for the resumable path.\n // For simple uploads or multipart without store the abort triggers\n // AbortMultipartUpload automatically inside multipart.ts.\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n return { ...state, upload, cancel, detach, reset };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { validateFile } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { createSpeedTracker } from \"../helpers/speed-tracker\";\nimport { useLiveRef } from \"../internal-helpers\";\nimport type {\n UploadConfig,\n UploadProgress,\n UploadResult,\n UploadRequestOptions,\n MultiUploadPhase,\n MultiUploadFileState,\n MultiUploadHooks,\n} from \"../types\";\nimport { uploadFiles } from \"../upload\";\n\n/** Options for {@link useMultiUpload}. */\nexport type UseMultiUploadOptions = UploadConfig &\n MultiUploadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Static request options applied to all files. */\n uploadOptions?: UploadRequestOptions;\n /** Per-file request options (overrides `uploadOptions`). */\n getUploadOptions?: (file: File) => UploadRequestOptions;\n };\n\nexport type UseMultiUploadState = {\n /** Current batch upload phase. */\n phase: MultiUploadPhase;\n /** Per-file upload states. */\n files: MultiUploadFileState[];\n /** Aggregated progress across all files. */\n totalProgress: UploadProgress;\n /** Batch-level error message, or `null`. */\n error: string | null;\n};\n\nexport type UseMultiUploadReturn = UseMultiUploadState & {\n /** Upload multiple files. */\n upload: (files: File[], resolveKey: (file: File) => string) => Promise<void>;\n /** Abort all in-flight uploads. */\n cancel: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\nconst INITIAL_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\n\nconst INITIAL_STATE: UseMultiUploadState = {\n phase: \"idle\",\n files: [],\n totalProgress: INITIAL_PROGRESS,\n error: null,\n};\n\nfunction generateId() {\n return crypto.randomUUID();\n}\n\nexport function useMultiUpload(\n options: UseMultiUploadOptions,\n): UseMultiUploadReturn {\n const [state, setState] = useState<UseMultiUploadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const abortRef = useRef<AbortController | null>(null);\n const resettingRef = useRef(false);\n const fileMapRef = useRef<Map<string, File>>(new Map());\n const fileSpeedTrackersRef = useRef<\n Map<string, ReturnType<typeof createSpeedTracker>>\n >(new Map());\n const totalSpeedTrackerRef = useRef(createSpeedTracker());\n const fileLastSpeedRef = useRef<Map<string, number>>(new Map());\n const fileLastSpeedUpdateRef = useRef<Map<string, number>>(new Map());\n const lastTotalSpeedRef = useRef<number | undefined>(undefined);\n const lastTotalSpeedUpdateRef = useRef(0);\n\n const upload = useCallback(\n async (files: File[], resolveKey: (file: File) => string) => {\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useMultiUpload or wrap with <S3Provider>.\",\n );\n\n const items: Array<{\n id: string;\n file: File;\n objectKey: string;\n }> = [];\n const fileStates: MultiUploadFileState[] = [];\n const fileMap = new Map<string, File>();\n\n setState((s) => ({ ...s, phase: \"validating\", error: null }));\n\n if (opts.maxFiles && files.length > opts.maxFiles) {\n const msg = `Too many files. Maximum is ${opts.maxFiles}.`;\n setState((s) => ({ ...s, phase: \"error\", error: msg }));\n opts.onError?.(new Error(msg));\n return;\n }\n\n for (const file of files) {\n const validationError = validateFile(file, {\n accept: opts.accept,\n maxFileSize: opts.maxFileSize,\n });\n if (validationError) {\n const msg = `${file.name}: ${validationError}`;\n setState((s) => ({ ...s, phase: \"error\", error: msg }));\n opts.onError?.(new Error(msg));\n return;\n }\n }\n\n if (opts.beforeUpload) {\n const allowed = await opts.beforeUpload(files);\n if (!allowed) {\n setState((s) => ({\n ...s,\n phase: \"error\",\n error: \"Upload blocked by beforeUpload hook\",\n }));\n opts.onError?.(new Error(\"blocked\"));\n return;\n }\n }\n\n for (const file of files) {\n const id = generateId();\n const objectKey = resolveKey(file);\n items.push({ id, file, objectKey });\n fileMap.set(id, file);\n fileStates.push({\n id,\n fileName: file.name,\n fileSize: file.size,\n status: \"pending\",\n progress: { loaded: 0, total: file.size, percent: 0 },\n error: null,\n });\n }\n\n fileMapRef.current = fileMap;\n\n setState({\n phase: \"uploading\",\n files: fileStates,\n totalProgress: {\n loaded: 0,\n total: files.reduce((s, f) => s + f.size, 0),\n percent: 0,\n },\n error: null,\n });\n\n opts.onUploadStart?.(files);\n\n // Reset speed trackers for this batch\n fileSpeedTrackersRef.current.clear();\n for (const item of items) {\n fileSpeedTrackersRef.current.set(item.id, createSpeedTracker());\n }\n totalSpeedTrackerRef.current.reset();\n fileLastSpeedRef.current.clear();\n fileLastSpeedUpdateRef.current.clear();\n lastTotalSpeedRef.current = undefined;\n lastTotalSpeedUpdateRef.current = 0;\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n try {\n const results = await uploadFiles(\n api,\n items,\n {\n multipart: opts.multipart,\n multipartThreshold: opts.multipartThreshold,\n concurrentParts: opts.concurrentParts,\n concurrentFiles: opts.concurrentFiles,\n partSize: opts.partSize,\n retry: opts.retry,\n uploadStore: opts.uploadStore,\n },\n {\n onFileProgress: (id, progress) => {\n const tracker = fileSpeedTrackersRef.current.get(id);\n const rawSpeed = tracker ? tracker.update(progress.loaded) : 0;\n const now = Date.now();\n if (\n rawSpeed > 0 &&\n now - (fileLastSpeedUpdateRef.current.get(id) ?? 0) >= 500\n ) {\n fileLastSpeedRef.current.set(id, rawSpeed);\n fileLastSpeedUpdateRef.current.set(id, now);\n }\n const speed = fileLastSpeedRef.current.get(id);\n const p = speed ? { ...progress, speed } : progress;\n setState((s) => ({\n ...s,\n files: s.files.map((f) =>\n f.id === id ? { ...f, status: \"uploading\", progress: p } : f,\n ),\n }));\n const file = fileMap.get(id);\n if (file) opts.onFileProgress?.(file, p);\n },\n onFileSuccess: (id, result) => {\n setState((s) => ({\n ...s,\n files: s.files.map((f) =>\n f.id === id\n ? {\n ...f,\n status: \"success\",\n progress: {\n loaded: f.fileSize,\n total: f.fileSize,\n percent: 100,\n },\n }\n : f,\n ),\n }));\n const file = fileMap.get(id);\n if (file) opts.onFileSuccess?.(file, result);\n },\n onFileError: (id, error) => {\n setState((s) => ({\n ...s,\n files: s.files.map((f) =>\n f.id === id ? { ...f, status: \"error\", error } : f,\n ),\n }));\n const file = fileMap.get(id);\n if (file) opts.onFileError?.(file, error);\n },\n onTotalProgress: (progress) => {\n const rawSpeed = totalSpeedTrackerRef.current.update(\n progress.loaded,\n );\n const now = Date.now();\n if (\n rawSpeed > 0 &&\n now - lastTotalSpeedUpdateRef.current >= 1000\n ) {\n lastTotalSpeedRef.current = rawSpeed;\n lastTotalSpeedUpdateRef.current = now;\n }\n const speed = lastTotalSpeedRef.current;\n const p = speed ? { ...progress, speed } : progress;\n setState((s) => ({ ...s, totalProgress: p }));\n opts.onProgress?.(p);\n },\n },\n controller.signal,\n (file) => {\n const perFile = opts.getUploadOptions?.(file);\n if (!opts.uploadOptions) return perFile ?? {};\n return { ...opts.uploadOptions, ...perFile };\n },\n );\n\n const hasErrors = results.some((r) => r.status === \"error\");\n const successResults = results\n .filter((r) => r.result !== null)\n .map((r) => r.result!);\n\n setState((s) => ({\n ...s,\n phase: hasErrors ? \"error\" : \"success\",\n error: hasErrors\n ? `${results.filter((r) => r.status === \"error\").length} file(s) failed`\n : null,\n totalProgress: hasErrors\n ? s.totalProgress\n : {\n loaded: s.totalProgress.total,\n total: s.totalProgress.total,\n percent: 100,\n },\n }));\n\n if (!hasErrors) {\n await opts.onSuccess?.(successResults);\n }\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n if (!resettingRef.current) opts.onCancel?.();\n resettingRef.current = false;\n setState(INITIAL_STATE);\n return;\n }\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(err);\n } finally {\n abortRef.current = null;\n }\n },\n [],\n );\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n resettingRef.current = true;\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n return { ...state, upload, cancel, reset };\n}\n","\"use client\";\n\nimport { useRef, useState } from \"react\";\nimport type {\n UploadPhase,\n UploadProgress,\n UploadRequestOptions,\n} from \"../types\";\nimport { useUpload, type UseUploadOptions } from \"./use-upload\";\n\n/** Options for {@link useUploadControls}. */\nexport type UseUploadControlsOptions = UseUploadOptions & {\n /** S3 object key, or a function that derives it from the file. */\n objectKey: string | ((file: File) => string);\n /** Static request options applied to the upload. */\n uploadOptions?: UploadRequestOptions;\n /** Per-upload request options override. */\n getUploadOptions?: (file: File) => UploadRequestOptions;\n};\n\nexport type UseUploadControlsReturn = {\n /** Current upload phase. */\n phase: UploadPhase;\n /** Info about the selected file. */\n fileInfo: { name: string; size: number } | null;\n /** Byte transfer progress. */\n progress: UploadProgress;\n /** Error message, or `null`. */\n error: string | null;\n /** `true` while uploading. */\n isUploading: boolean;\n /** Handle files from drag-and-drop or a file input. */\n handleFiles: (files: FileList | null) => void;\n /** Open the hidden file picker. */\n openFilePicker: () => void;\n /** Abort and reset to idle. */\n cancel: () => void;\n /**\n * Soft-stop: preserves S3 parts and store entry so a future `upload()` can\n * resume. For non-resumable uploads, identical to `cancel()`.\n * See `UseUploadReturn.detach` for full semantics.\n */\n detach: () => void;\n reset: () => void;\n /** Spread on a hidden `<input>` element. */\n inputProps: {\n ref: React.RefObject<HTMLInputElement | null>;\n type: \"file\";\n accept?: string;\n hidden: true;\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n };\n /** Spread on a container to enable drag-and-drop. */\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => void;\n onDrop: (e: React.DragEvent) => void;\n };\n};\n\nexport function useUploadControls(\n options: UseUploadControlsOptions,\n): UseUploadControlsReturn {\n const single = useUpload(options);\n const inputRef = useRef<HTMLInputElement>(null);\n const [fileInfo, setFileInfo] = useState<{\n name: string;\n size: number;\n } | null>(null);\n\n const resolveKey = (file: File): string =>\n typeof options.objectKey === \"function\"\n ? options.objectKey(file)\n : options.objectKey;\n\n const handleFiles = async (files: FileList | null) => {\n const file = files?.[0];\n if (!file) return;\n setFileInfo({ name: file.name, size: file.size });\n await single.upload(file, resolveKey(file), {\n ...options.uploadOptions,\n ...options.getUploadOptions?.(file),\n });\n };\n\n return {\n phase: single.phase,\n fileInfo,\n progress: single.progress,\n error: single.error,\n isUploading: single.phase === \"uploading\",\n handleFiles,\n openFilePicker: () => inputRef.current?.click(),\n cancel: single.cancel,\n detach: single.detach,\n reset: () => {\n single.reset();\n setFileInfo(null);\n },\n inputProps: {\n ref: inputRef,\n type: \"file\",\n accept: options.accept?.join(\",\"),\n hidden: true,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n handleFiles(e.target.files);\n e.target.value = \"\";\n },\n },\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n },\n onDrop: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (single.phase !== \"uploading\") handleFiles(e.dataTransfer.files);\n },\n },\n };\n}\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport type {\n UploadProgress,\n UploadRequestOptions,\n MultiUploadFileState,\n MultiUploadPhase,\n} from \"../types\";\nimport { useMultiUpload, type UseMultiUploadOptions } from \"./use-multi-upload\";\n\n/** Options for {@link useMultiUploadControls}. */\nexport type UseMultiUploadControlsOptions = UseMultiUploadOptions & {\n /** S3 object key, or a function that derives it from each file. */\n objectKey: string | ((file: File) => string);\n};\n\nexport type UseMultiUploadControlsReturn = {\n /** Current batch upload phase. */\n phase: MultiUploadPhase;\n /** Per-file upload states. */\n files: MultiUploadFileState[];\n /** Aggregated progress across all files. */\n totalProgress: UploadProgress;\n /** Batch-level error message, or `null`. */\n error: string | null;\n /** `true` while uploading. */\n isUploading: boolean;\n /** Handle files from drag-and-drop or a file input. */\n handleFiles: (files: FileList | null) => void;\n /** Open the hidden file picker. */\n openFilePicker: () => void;\n /** Abort all in-flight uploads. */\n cancel: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n /** Spread on a hidden `<input>` element. */\n inputProps: {\n ref: React.RefObject<HTMLInputElement | null>;\n type: \"file\";\n multiple: true;\n accept?: string;\n hidden: true;\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n };\n /** Spread on a container to enable drag-and-drop. */\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => void;\n onDrop: (e: React.DragEvent) => void;\n };\n};\n\nexport function useMultiUploadControls(\n options: UseMultiUploadControlsOptions,\n): UseMultiUploadControlsReturn {\n const multi = useMultiUpload(options);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const resolveKey = (file: File): string =>\n typeof options.objectKey === \"function\"\n ? options.objectKey(file)\n : options.objectKey;\n\n const handleFiles = async (files: FileList | null) => {\n if (!files?.length) return;\n await multi.upload(Array.from(files), resolveKey);\n };\n\n return {\n phase: multi.phase,\n files: multi.files,\n totalProgress: multi.totalProgress,\n error: multi.error,\n isUploading: multi.phase === \"uploading\",\n handleFiles,\n openFilePicker: () => inputRef.current?.click(),\n cancel: multi.cancel,\n reset: multi.reset,\n inputProps: {\n ref: inputRef,\n type: \"file\",\n multiple: true,\n accept: options.accept?.join(\",\"),\n hidden: true,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n handleFiles(e.target.files);\n e.target.value = \"\";\n },\n },\n dropHandlers: {\n onDragOver: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n },\n onDrop: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (multi.phase !== \"uploading\") handleFiles(e.dataTransfer.files);\n },\n },\n };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { useLiveRef } from \"../internal-helpers\";\n\nexport type { DownloadPhase, DownloadHooks } from \"../types/download\";\n\nimport type { DownloadPhase, DownloadHooks } from \"../types/download\";\n\n/** Options for {@link useDownload}. */\nexport type UseDownloadOptions = DownloadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Target bucket (overrides server default). */\n bucket?: string;\n};\n\nexport type UseDownloadState = {\n /** Current download phase. */\n phase: DownloadPhase;\n /** Error message, or `null`. */\n error: string | null;\n /** Presigned URL — set after a successful presign, cleared on reset. */\n url: string | null;\n /** Validity window in seconds for the presigned URL. */\n expiresIn: number | null;\n};\n\nexport type UseDownloadReturn = UseDownloadState & {\n /** Presign and trigger a native browser download. */\n download: (key: string, downloadName?: string) => Promise<void>;\n /** Fetch the presigned URL without triggering a browser download. */\n presign: (\n key: string,\n downloadName?: string,\n ) => Promise<{ url: string; expiresIn: number } | null>;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\nconst INITIAL_STATE: UseDownloadState = {\n phase: \"idle\",\n error: null,\n url: null,\n expiresIn: null,\n};\n\nexport function useDownload(options: UseDownloadOptions): UseDownloadReturn {\n const [state, setState] = useState<UseDownloadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n\n const presign = useCallback(async (key: string, downloadName?: string) => {\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useDownload or wrap with <S3Provider>.\",\n );\n setState({ phase: \"presigning\", error: null, url: null, expiresIn: null });\n try {\n const result = await api.download(key, {\n fileName: downloadName,\n bucket: opts.bucket,\n });\n setState({\n phase: \"idle\",\n error: null,\n url: result.url,\n expiresIn: result.expiresIn,\n });\n return { url: result.url, expiresIn: result.expiresIn };\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Download failed\";\n setState({ phase: \"error\", error: message, url: null, expiresIn: null });\n opts.onError?.(key, err);\n return null;\n }\n }, []);\n\n const download = useCallback(\n async (key: string, downloadName?: string) => {\n const opts = optsRef.current;\n if (opts.beforeDownload) {\n const allowed = await opts.beforeDownload(key);\n if (!allowed) {\n setState({\n phase: \"error\",\n error: \"Download blocked by beforeDownload hook\",\n url: null,\n expiresIn: null,\n });\n opts.onError?.(key, new Error(\"blocked\"));\n return;\n }\n }\n const result = await presign(key, downloadName);\n if (!result) return;\n window.location.href = result.url;\n opts.onInitiated?.(key);\n },\n [presign],\n );\n\n const reset = useCallback(() => setState(INITIAL_STATE), []);\n\n return { ...state, download, presign, reset };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { parseFileName } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport { createSpeedTracker } from \"../helpers/speed-tracker\";\nimport type { FetchDownloadPhase, FetchDownloadHooks } from \"../types/download\";\nimport type { UploadProgress } from \"../types/upload\";\nimport { useLiveRef } from \"../internal-helpers\";\n\nexport type {\n FetchDownloadPhase,\n FetchDownloadProgress,\n FetchDownloadHooks,\n} from \"../types/download\";\n\n/** Options for {@link useFetchDownload}. */\nexport type UseFetchDownloadOptions = FetchDownloadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Target bucket (overrides server default). */\n bucket?: string;\n};\n\nexport type UseFetchDownloadState = {\n /** Current download phase. */\n phase: FetchDownloadPhase;\n /** Byte transfer progress. */\n progress: UploadProgress;\n /** Error message, or `null`. */\n error: string | null;\n /** Resolved download filename. */\n fileName: string | null;\n /** Total file size in bytes. */\n fileSize: number | null;\n};\n\nexport type UseFetchDownloadReturn = UseFetchDownloadState & {\n /** Presign, fetch bytes, and save via the browser. */\n download: (key: string, downloadName?: string) => Promise<void>;\n /** Abort the active download. */\n cancel: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\nconst INITIAL_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\n\nconst INITIAL_STATE: UseFetchDownloadState = {\n phase: \"idle\",\n progress: INITIAL_PROGRESS,\n error: null,\n fileName: null,\n fileSize: null,\n};\n\nexport function useFetchDownload(\n options: UseFetchDownloadOptions,\n): UseFetchDownloadReturn {\n const [state, setState] = useState<UseFetchDownloadState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const abortRef = useRef<AbortController | null>(null);\n const resettingRef = useRef(false);\n const speedTrackerRef = useRef(createSpeedTracker());\n const lastSpeedRef = useRef<number | undefined>(undefined);\n const lastSpeedUpdateRef = useRef(0);\n\n const download = useCallback(async (key: string, downloadName?: string) => {\n const fallback = key.split(\"/\").pop() ?? key;\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useFetchDownload or wrap with <S3Provider>.\",\n );\n\n if (opts.beforeDownload) {\n const allowed = await opts.beforeDownload(key);\n if (!allowed) {\n setState((s) => ({\n ...s,\n phase: \"error\",\n error: \"Download blocked by beforeDownload hook\",\n }));\n opts.onError?.(key, new Error(\"blocked\"), \"presigning\");\n return;\n }\n }\n\n setState({\n phase: \"presigning\",\n progress: INITIAL_PROGRESS,\n error: null,\n fileName: downloadName ?? null,\n fileSize: null,\n });\n\n try {\n const { url } = await api.download(key, {\n fileName: downloadName,\n bucket: opts.bucket,\n });\n setState((s) => ({ ...s, phase: \"downloading\" }));\n opts.onDownloadStart?.(key);\n\n speedTrackerRef.current.reset();\n lastSpeedRef.current = undefined;\n lastSpeedUpdateRef.current = 0;\n const controller = new AbortController();\n abortRef.current = controller;\n\n const res = await fetch(url, { signal: controller.signal });\n if (!res.ok) {\n throw new Error(\n res.status === 404\n ? \"File not found\"\n : `Download failed (${res.status})`,\n );\n }\n\n const contentLength = Number(res.headers.get(\"content-length\") || 0);\n const name =\n downloadName ??\n parseFileName(res.headers.get(\"content-disposition\")) ??\n fallback;\n setState((s) => ({\n ...s,\n fileName: name,\n fileSize: contentLength || null,\n }));\n\n const reader = res.body?.getReader();\n if (!reader) throw new Error(\"ReadableStream not supported\");\n\n const chunks: BlobPart[] = [];\n let loaded = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n loaded += value.byteLength;\n const percent =\n contentLength > 0 ? Math.round((loaded / contentLength) * 100) : 0;\n const rawSpeed = speedTrackerRef.current.update(loaded);\n const now = Date.now();\n if (rawSpeed > 0 && now - lastSpeedUpdateRef.current >= 500) {\n lastSpeedRef.current = rawSpeed;\n lastSpeedUpdateRef.current = now;\n }\n const speed = lastSpeedRef.current;\n const progress: UploadProgress = {\n loaded,\n total: contentLength,\n percent,\n ...(speed && { speed }),\n };\n setState((s) => ({ ...s, progress }));\n opts.onProgress?.(key, progress);\n }\n\n const blob = new Blob(chunks);\n const blobUrl = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = blobUrl;\n anchor.download = name ?? fallback;\n anchor.click();\n URL.revokeObjectURL(blobUrl);\n\n setState((s) => ({\n ...s,\n phase: \"success\",\n fileSize: blob.size,\n progress: { loaded: blob.size, total: blob.size, percent: 100 },\n }));\n await opts.onSuccess?.(key, name ?? fallback);\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n if (!resettingRef.current) opts.onCancel?.(key);\n resettingRef.current = false;\n setState(INITIAL_STATE);\n return;\n }\n const message = err instanceof Error ? err.message : \"Download failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(key, err, \"downloading\");\n } finally {\n abortRef.current = null;\n }\n }, []);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n resettingRef.current = true;\n abortRef.current?.abort();\n setState(INITIAL_STATE);\n }, []);\n\n return { ...state, download, cancel, reset };\n}\n","\"use client\";\n\nimport { useCallback, useContext, useRef, useState } from \"react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { S3Context } from \"../s3-provider\";\nimport type { DeletePhase, DeleteHooks } from \"../types\";\nimport { useLiveRef } from \"../internal-helpers\";\n\n/** Options for {@link useDelete}. */\nexport type UseDeleteOptions = DeleteHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** Target bucket (overrides server default). */\n bucket?: string;\n};\n\nexport type UseDeleteState = {\n /** Current delete phase. */\n phase: DeletePhase;\n /** Error message, or `null`. */\n error: string | null;\n};\n\nexport type UseDeleteReturn = UseDeleteState & {\n /** Key awaiting confirmation, or `null`. */\n pendingKey: string | null;\n /** Move to the `confirming` phase for the given key. */\n requestDelete: (key: string) => void;\n /** Send the delete request for the pending key. */\n confirmDelete: () => Promise<void>;\n /** Cancel confirmation and return to `idle`. */\n cancelDelete: () => void;\n /** Reset state to `idle`. */\n reset: () => void;\n};\n\ntype InternalState = {\n phase: DeletePhase;\n error: string | null;\n pendingKey: string | null;\n};\n\nconst INITIAL_STATE: InternalState = {\n phase: \"idle\",\n error: null,\n pendingKey: null,\n};\n\nexport function useDelete(options: UseDeleteOptions): UseDeleteReturn {\n const [state, setState] = useState<InternalState>(INITIAL_STATE);\n const contextApi = useContext(S3Context);\n const optsRef = useLiveRef(options);\n const apiRef = useLiveRef(contextApi);\n const pendingKeyRef = useRef<string | null>(null);\n\n const requestDelete = useCallback((key: string) => {\n pendingKeyRef.current = key;\n setState({ phase: \"confirming\", error: null, pendingKey: key });\n }, []);\n\n const confirmDelete = useCallback(async () => {\n const key = pendingKeyRef.current;\n if (!key) return;\n const opts = optsRef.current;\n const api = opts.api ?? apiRef.current;\n if (!api)\n throw new Error(\n \"[better-s3] No S3Api client found. Pass `api` to useDelete or wrap with <S3Provider>.\",\n );\n\n if (opts.beforeDelete) {\n const allowed = await opts.beforeDelete(key);\n if (!allowed) {\n setState({\n phase: \"error\",\n error: \"Delete blocked by beforeDelete hook\",\n pendingKey: null,\n });\n opts.onError?.(key, new Error(\"blocked\"), \"confirming\");\n pendingKeyRef.current = null;\n return;\n }\n }\n\n setState((s) => ({ ...s, phase: \"deleting\", error: null }));\n opts.onDeleteStart?.(key);\n\n try {\n await api.delete(key, { bucket: opts.bucket });\n pendingKeyRef.current = null;\n setState({ phase: \"success\", error: null, pendingKey: null });\n await opts.onSuccess?.(key);\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Delete failed\";\n setState((s) => ({ ...s, phase: \"error\", error: message }));\n opts.onError?.(key, err, \"deleting\");\n }\n }, []);\n\n const cancelDelete = useCallback(() => {\n pendingKeyRef.current = null;\n setState(INITIAL_STATE);\n }, []);\n\n const reset = useCallback(() => {\n pendingKeyRef.current = null;\n setState(INITIAL_STATE);\n }, []);\n\n return {\n phase: state.phase,\n error: state.error,\n pendingKey: state.pendingKey,\n requestDelete,\n confirmDelete,\n cancelDelete,\n reset,\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-s3/react",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1051.0",
|
|
4
4
|
"description": "React hooks for S3-compatible file uploads, downloads, and deletes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"s3",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dist"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@better-s3/core": "3.
|
|
36
|
+
"@better-s3/core": "3.1051.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": ">=18"
|