@uploadista/react 0.0.13 → 0.0.14
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/dist/components/index.d.mts +2 -2
- package/dist/components/index.mjs +1 -1
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.mjs +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +1 -1
- package/dist/{upload-zone-CsaXN9yD.mjs → upload-zone-8khVLLYF.mjs} +2 -2
- package/dist/{upload-zone-CsaXN9yD.mjs.map → upload-zone-8khVLLYF.mjs.map} +1 -1
- package/dist/{uploadista-provider-Cj34PdHg.d.mts → uploadista-provider-CrS6TmpJ.d.mts} +2 -2
- package/dist/{uploadista-provider-Cj34PdHg.d.mts.map → uploadista-provider-CrS6TmpJ.d.mts.map} +1 -1
- package/dist/{use-upload-metrics-2HKWi6GZ.mjs → use-upload-metrics-BE7UcAaz.mjs} +2 -2
- package/dist/{use-upload-metrics-2HKWi6GZ.mjs.map → use-upload-metrics-BE7UcAaz.mjs.map} +1 -1
- package/dist/{use-upload-metrics-DESSCpN5.d.mts → use-upload-metrics-IXxUORce.d.mts} +10 -10
- package/dist/{use-upload-metrics-DESSCpN5.d.mts.map → use-upload-metrics-IXxUORce.d.mts.map} +1 -1
- package/dist/use-upload-xcqz090n.mjs +2 -0
- package/dist/use-upload-xcqz090n.mjs.map +1 -0
- package/dist/{use-uploadista-client-Dp8_ZO7d.d.mts → use-uploadista-client--ivZPO88.d.mts} +21 -110
- package/dist/use-uploadista-client--ivZPO88.d.mts.map +1 -0
- package/package.json +7 -7
- package/src/hooks/use-flow-upload.ts +84 -342
- package/src/hooks/use-multi-upload.ts +2 -6
- package/src/hooks/use-upload.ts +78 -239
- package/dist/use-upload-CvPqdohl.mjs +0 -2
- package/dist/use-upload-CvPqdohl.mjs.map +0 -1
- package/dist/use-uploadista-client-Dp8_ZO7d.d.mts.map +0 -1
package/src/hooks/use-upload.ts
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "@uploadista/client-
|
|
1
|
+
import type { BrowserUploadInput } from "@uploadista/client-browser";
|
|
2
|
+
import type { UploadMetrics, UploadOptions } from "@uploadista/client-core";
|
|
3
|
+
import {
|
|
4
|
+
UploadManager,
|
|
5
|
+
type UploadState,
|
|
6
|
+
type UploadStatus,
|
|
7
|
+
} from "@uploadista/client-core";
|
|
8
8
|
import type { UploadFile } from "@uploadista/core/types";
|
|
9
|
-
import { UploadEventType } from "@uploadista/core/types";
|
|
10
9
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
10
|
import { useUploadistaContext } from "../components/uploadista-provider";
|
|
12
11
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
| "uploading"
|
|
16
|
-
| "success"
|
|
17
|
-
| "error"
|
|
18
|
-
| "aborted";
|
|
19
|
-
|
|
20
|
-
export interface UploadState {
|
|
21
|
-
status: UploadStatus;
|
|
22
|
-
progress: number;
|
|
23
|
-
bytesUploaded: number;
|
|
24
|
-
totalBytes: number | null;
|
|
25
|
-
error: Error | null;
|
|
26
|
-
result: UploadFile | null;
|
|
27
|
-
}
|
|
12
|
+
// Re-export types from core for convenience
|
|
13
|
+
export type { UploadState, UploadStatus };
|
|
28
14
|
|
|
29
15
|
export interface UseUploadOptions {
|
|
30
16
|
/**
|
|
@@ -44,15 +30,23 @@ export interface UseUploadOptions {
|
|
|
44
30
|
|
|
45
31
|
/**
|
|
46
32
|
* Called when upload progress updates
|
|
33
|
+
*
|
|
34
|
+
* @param uploadId - The unique identifier for this upload
|
|
35
|
+
* @param bytesUploaded - Number of bytes uploaded
|
|
36
|
+
* @param totalBytes - Total bytes to upload, null if unknown
|
|
47
37
|
*/
|
|
48
38
|
onProgress?: (
|
|
49
|
-
|
|
39
|
+
uploadId: string,
|
|
50
40
|
bytesUploaded: number,
|
|
51
41
|
totalBytes: number | null,
|
|
52
42
|
) => void;
|
|
53
43
|
|
|
54
44
|
/**
|
|
55
45
|
* Called when a chunk completes
|
|
46
|
+
*
|
|
47
|
+
* @param chunkSize - Size of the completed chunk
|
|
48
|
+
* @param bytesAccepted - Total bytes accepted so far
|
|
49
|
+
* @param bytesTotal - Total bytes to upload, null if unknown
|
|
56
50
|
*/
|
|
57
51
|
onChunkComplete?: (
|
|
58
52
|
chunkSize: number,
|
|
@@ -62,11 +56,15 @@ export interface UseUploadOptions {
|
|
|
62
56
|
|
|
63
57
|
/**
|
|
64
58
|
* Called when upload succeeds
|
|
59
|
+
*
|
|
60
|
+
* @param result - The uploaded file result
|
|
65
61
|
*/
|
|
66
62
|
onSuccess?: (result: UploadFile) => void;
|
|
67
63
|
|
|
68
64
|
/**
|
|
69
65
|
* Called when upload fails
|
|
66
|
+
*
|
|
67
|
+
* @param error - The error that caused the failure
|
|
70
68
|
*/
|
|
71
69
|
onError?: (error: Error) => void;
|
|
72
70
|
|
|
@@ -77,41 +75,14 @@ export interface UseUploadOptions {
|
|
|
77
75
|
|
|
78
76
|
/**
|
|
79
77
|
* Custom retry logic
|
|
78
|
+
*
|
|
79
|
+
* @param error - The error that triggered the retry check
|
|
80
|
+
* @param retryAttempt - The current retry attempt number
|
|
81
|
+
* @returns true to retry, false to fail
|
|
80
82
|
*/
|
|
81
83
|
onShouldRetry?: (error: Error, retryAttempt: number) => boolean;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
export interface UploadMetrics {
|
|
85
|
-
/**
|
|
86
|
-
* Get performance insights from the upload client
|
|
87
|
-
*/
|
|
88
|
-
getInsights: () => PerformanceInsights;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Export detailed metrics from the upload client
|
|
92
|
-
*/
|
|
93
|
-
exportMetrics: () => {
|
|
94
|
-
session: Partial<UploadSessionMetrics>;
|
|
95
|
-
chunks: ChunkMetrics[];
|
|
96
|
-
insights: PerformanceInsights;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Get current network metrics
|
|
101
|
-
*/
|
|
102
|
-
getNetworkMetrics: () => unknown;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Get current network condition
|
|
106
|
-
*/
|
|
107
|
-
getNetworkCondition: () => unknown;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Reset all metrics
|
|
111
|
-
*/
|
|
112
|
-
resetMetrics: () => void;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
86
|
export interface UseUploadReturn {
|
|
116
87
|
/**
|
|
117
88
|
* Current upload state
|
|
@@ -154,15 +125,6 @@ export interface UseUploadReturn {
|
|
|
154
125
|
metrics: UploadMetrics;
|
|
155
126
|
}
|
|
156
127
|
|
|
157
|
-
const initialState: UploadState = {
|
|
158
|
-
status: "idle",
|
|
159
|
-
progress: 0,
|
|
160
|
-
bytesUploaded: 0,
|
|
161
|
-
totalBytes: null,
|
|
162
|
-
error: null,
|
|
163
|
-
result: null,
|
|
164
|
-
};
|
|
165
|
-
|
|
166
128
|
/**
|
|
167
129
|
* React hook for managing individual file uploads with full state management.
|
|
168
130
|
* Provides upload progress tracking, error handling, abort functionality, and retry logic.
|
|
@@ -178,7 +140,10 @@ const initialState: UploadState = {
|
|
|
178
140
|
* const upload = useUpload({
|
|
179
141
|
* onSuccess: (result) => console.log('Upload complete:', result),
|
|
180
142
|
* onError: (error) => console.error('Upload failed:', error),
|
|
181
|
-
* onProgress: (
|
|
143
|
+
* onProgress: (uploadId, bytesUploaded, totalBytes) => {
|
|
144
|
+
* const progress = totalBytes ? Math.round((bytesUploaded / totalBytes) * 100) : 0;
|
|
145
|
+
* console.log(`Upload ${uploadId}: ${progress}% (${bytesUploaded}/${totalBytes} bytes)`);
|
|
146
|
+
* },
|
|
182
147
|
* });
|
|
183
148
|
*
|
|
184
149
|
* return (
|
|
@@ -199,195 +164,69 @@ const initialState: UploadState = {
|
|
|
199
164
|
* }
|
|
200
165
|
* ```
|
|
201
166
|
*/
|
|
167
|
+
const initialState: UploadState = {
|
|
168
|
+
status: "idle",
|
|
169
|
+
progress: 0,
|
|
170
|
+
bytesUploaded: 0,
|
|
171
|
+
totalBytes: null,
|
|
172
|
+
error: null,
|
|
173
|
+
result: null,
|
|
174
|
+
};
|
|
175
|
+
|
|
202
176
|
export function useUpload(options: UseUploadOptions = {}): UseUploadReturn {
|
|
203
177
|
const uploadClient = useUploadistaContext();
|
|
204
178
|
const [state, setState] = useState<UploadState>(initialState);
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
setState((prev) => ({ ...prev, ...update }));
|
|
210
|
-
}, []);
|
|
211
|
-
|
|
212
|
-
const reset = useCallback(() => {
|
|
213
|
-
if (abortControllerRef.current) {
|
|
214
|
-
abortControllerRef.current.abort();
|
|
215
|
-
abortControllerRef.current = null;
|
|
216
|
-
}
|
|
217
|
-
setState(initialState);
|
|
218
|
-
lastFileRef.current = null;
|
|
219
|
-
}, []);
|
|
220
|
-
|
|
221
|
-
const abort = useCallback(() => {
|
|
222
|
-
if (abortControllerRef.current) {
|
|
223
|
-
abortControllerRef.current.abort();
|
|
224
|
-
abortControllerRef.current = null;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
updateState({
|
|
228
|
-
status: "aborted",
|
|
229
|
-
});
|
|
179
|
+
const managerRef = useRef<UploadManager<
|
|
180
|
+
BrowserUploadInput,
|
|
181
|
+
UploadOptions
|
|
182
|
+
> | null>(null);
|
|
230
183
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// Start the upload and handle the promise
|
|
246
|
-
const uploadPromise = uploadClient.client.upload(file, {
|
|
184
|
+
// Create UploadManager instance
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
managerRef.current = new UploadManager(
|
|
187
|
+
(file: BrowserUploadInput, opts: UploadOptions) =>
|
|
188
|
+
uploadClient.client.upload(file, opts),
|
|
189
|
+
{
|
|
190
|
+
onStateChange: setState,
|
|
191
|
+
onProgress: options.onProgress,
|
|
192
|
+
onChunkComplete: options.onChunkComplete,
|
|
193
|
+
onSuccess: options.onSuccess,
|
|
194
|
+
onError: options.onError,
|
|
195
|
+
onAbort: options.onAbort,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
247
198
|
metadata: options.metadata,
|
|
248
199
|
uploadLengthDeferred: options.uploadLengthDeferred,
|
|
249
200
|
uploadSize: options.uploadSize,
|
|
250
|
-
|
|
251
|
-
onStart: ({ uploadId }) => {
|
|
252
|
-
currentUploadIdRef.current = uploadId;
|
|
253
|
-
},
|
|
254
|
-
|
|
255
|
-
onProgress: (
|
|
256
|
-
_uploadId: string,
|
|
257
|
-
bytesUploaded: number,
|
|
258
|
-
totalBytes: number | null,
|
|
259
|
-
) => {
|
|
260
|
-
const progress = totalBytes
|
|
261
|
-
? Math.round((bytesUploaded / totalBytes) * 100)
|
|
262
|
-
: 0;
|
|
263
|
-
|
|
264
|
-
updateState({
|
|
265
|
-
progress,
|
|
266
|
-
bytesUploaded,
|
|
267
|
-
totalBytes,
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
options.onProgress?.(progress, bytesUploaded, totalBytes);
|
|
271
|
-
},
|
|
272
|
-
|
|
273
|
-
onChunkComplete: (
|
|
274
|
-
chunkSize: number,
|
|
275
|
-
bytesAccepted: number,
|
|
276
|
-
bytesTotal: number | null,
|
|
277
|
-
) => {
|
|
278
|
-
options.onChunkComplete?.(chunkSize, bytesAccepted, bytesTotal);
|
|
279
|
-
},
|
|
280
|
-
|
|
281
|
-
onSuccess: (result: UploadFile) => {
|
|
282
|
-
updateState({
|
|
283
|
-
status: "success",
|
|
284
|
-
result,
|
|
285
|
-
progress: 100,
|
|
286
|
-
bytesUploaded: result.size || 0,
|
|
287
|
-
totalBytes: result.size || null,
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
options.onSuccess?.(result);
|
|
291
|
-
abortControllerRef.current = null;
|
|
292
|
-
},
|
|
293
|
-
|
|
294
|
-
onError: (error: Error) => {
|
|
295
|
-
updateState({
|
|
296
|
-
status: "error",
|
|
297
|
-
error,
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
options.onError?.(error);
|
|
301
|
-
abortControllerRef.current = null;
|
|
302
|
-
},
|
|
303
|
-
|
|
304
201
|
onShouldRetry: options.onShouldRetry,
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Handle the promise to get the abort controller
|
|
308
|
-
uploadPromise
|
|
309
|
-
.then((controller) => {
|
|
310
|
-
abortControllerRef.current = controller;
|
|
311
|
-
})
|
|
312
|
-
.catch((error) => {
|
|
313
|
-
updateState({
|
|
314
|
-
status: "error",
|
|
315
|
-
error: error as Error,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
options.onError?.(error as Error);
|
|
319
|
-
abortControllerRef.current = null;
|
|
320
|
-
});
|
|
321
|
-
},
|
|
322
|
-
[uploadClient, options, updateState],
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
const retry = useCallback(() => {
|
|
326
|
-
if (
|
|
327
|
-
lastFileRef.current &&
|
|
328
|
-
(state.status === "error" || state.status === "aborted")
|
|
329
|
-
) {
|
|
330
|
-
upload(lastFileRef.current);
|
|
331
|
-
}
|
|
332
|
-
}, [upload, state.status]);
|
|
333
|
-
|
|
334
|
-
// Store current upload ID for event matching
|
|
335
|
-
const currentUploadIdRef = useRef<string | null>(null);
|
|
336
|
-
|
|
337
|
-
// Subscribe to events from context (WebSocket events)
|
|
338
|
-
useEffect(() => {
|
|
339
|
-
const unsubscribe = uploadClient.subscribeToEvents(
|
|
340
|
-
(event: UploadistaEvent) => {
|
|
341
|
-
// Handle upload progress events
|
|
342
|
-
const uploadEvent = event as {
|
|
343
|
-
type: string;
|
|
344
|
-
data?: { id: string; progress: number; total: number };
|
|
345
|
-
};
|
|
346
|
-
if (
|
|
347
|
-
uploadEvent.type === UploadEventType.UPLOAD_PROGRESS &&
|
|
348
|
-
uploadEvent.data
|
|
349
|
-
) {
|
|
350
|
-
const {
|
|
351
|
-
id: uploadId,
|
|
352
|
-
progress: bytesUploaded,
|
|
353
|
-
total: totalBytes,
|
|
354
|
-
} = uploadEvent.data;
|
|
202
|
+
},
|
|
203
|
+
);
|
|
355
204
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
205
|
+
return () => {
|
|
206
|
+
managerRef.current?.cleanup();
|
|
207
|
+
};
|
|
208
|
+
}, [uploadClient, options]);
|
|
359
209
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
: 0;
|
|
210
|
+
// Wrap manager methods with useCallback
|
|
211
|
+
const upload = useCallback((file: BrowserUploadInput) => {
|
|
212
|
+
managerRef.current?.upload(file);
|
|
213
|
+
}, []);
|
|
365
214
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
return {
|
|
370
|
-
...prev,
|
|
371
|
-
progress,
|
|
372
|
-
bytesUploaded,
|
|
373
|
-
totalBytes,
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
return prev;
|
|
377
|
-
});
|
|
215
|
+
const abort = useCallback(() => {
|
|
216
|
+
managerRef.current?.abort();
|
|
217
|
+
}, []);
|
|
378
218
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
);
|
|
219
|
+
const reset = useCallback(() => {
|
|
220
|
+
managerRef.current?.reset();
|
|
221
|
+
}, []);
|
|
383
222
|
|
|
384
|
-
|
|
385
|
-
|
|
223
|
+
const retry = useCallback(() => {
|
|
224
|
+
managerRef.current?.retry();
|
|
225
|
+
}, []);
|
|
386
226
|
|
|
227
|
+
// Derive computed values from state
|
|
387
228
|
const isUploading = state.status === "uploading";
|
|
388
|
-
const canRetry =
|
|
389
|
-
(state.status === "error" || state.status === "aborted") &&
|
|
390
|
-
lastFileRef.current !== null;
|
|
229
|
+
const canRetry = managerRef.current?.canRetry() ?? false;
|
|
391
230
|
|
|
392
231
|
// Create metrics object that delegates to the upload client
|
|
393
232
|
const metrics: UploadMetrics = {
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{createContext as e,useCallback as t,useContext as n,useEffect as r,useMemo as i,useRef as a,useState as o}from"react";import{createUploadistaClient as s}from"@uploadista/client-browser";import{jsx as c}from"react/jsx-runtime";import{EventType as l}from"@uploadista/core/flow";import{UploadEventType as u}from"@uploadista/core/types";function d(e){let t=a(e);return t.current=e,{client:i(()=>s({baseUrl:e.baseUrl,storageId:e.storageId,uploadistaBasePath:e.uploadistaBasePath,chunkSize:e.chunkSize,storeFingerprintForResuming:e.storeFingerprintForResuming,retryDelays:e.retryDelays,parallelUploads:e.parallelUploads,parallelChunkSize:e.parallelChunkSize,uploadStrategy:e.uploadStrategy,smartChunking:e.smartChunking,networkMonitoring:e.networkMonitoring,uploadMetrics:e.uploadMetrics,connectionPooling:e.connectionPooling,auth:e.auth,onEvent:e.onEvent}),[e]),config:e}}const f=e(null);function p({children:e,...n}){let r=a(new Set),o=t(e=>{console.log(`[UploadistaProvider] Received event:`,e),n.onEvent?.(e),console.log(`[UploadistaProvider] Broadcasting to`,r.current.size,`subscribers`),r.current.forEach(t=>{try{t(e)}catch(e){console.error(`Error in event subscriber:`,e)}})},[n.onEvent]),s=d({...n,onEvent:o}),l=t(e=>(r.current.add(e),()=>{r.current.delete(e)}),[]),u=i(()=>({...s,subscribeToEvents:l}),[s,l]);return c(f.Provider,{value:u,children:e})}function m(){let e=n(f);if(e===null)throw Error(`useUploadistaContext must be used within an UploadistaProvider. Make sure to wrap your component tree with <UploadistaProvider>.`);return e}function h(e){let n=m(),[r,i]=o([]),s=a(new Map),c=a([]),l=a(0),u=e.maxConcurrent??3,d=t(e=>{if(e.length===0)return 0;let t=e.reduce((e,t)=>e+t.progress,0);return Math.round(t/e.length)},[]),f=t(async()=>{if(l.current>=u||c.current.length===0)return;let t=c.current.shift();if(!t)return;let a=r.find(e=>e.id===t);if(!a||a.status!==`pending`){f();return}l.current++,i(e=>e.map(e=>e.id===t?{...e,status:`uploading`}:e));try{let{abort:r,jobId:o}=await n.client.uploadWithFlow(a.file,e.flowConfig,{onJobStart:e=>{i(n=>n.map(n=>n.id===t?{...n,jobId:e}:n))},onProgress:(n,r,a)=>{let o=a?Math.round(r/a*100):0;i(n=>{let i=n.map(e=>e.id===t?{...e,progress:o,bytesUploaded:r,totalBytes:a||0}:e),s=i.find(e=>e.id===t);return s&&e.onItemProgress?.(s),i})},onSuccess:n=>{i(r=>{let i=r.map(e=>e.id===t?{...e,status:`success`,result:n,progress:100}:e),a=i.find(e=>e.id===t);return a&&e.onItemSuccess?.(a),i.every(e=>e.status===`success`||e.status===`error`||e.status===`aborted`)&&e.onComplete?.(i),i}),s.current.delete(t),l.current--,f()},onError:n=>{i(r=>{let i=r.map(e=>e.id===t?{...e,status:`error`,error:n}:e),a=i.find(e=>e.id===t);return a&&e.onItemError?.(a,n),i.every(e=>e.status===`success`||e.status===`error`||e.status===`aborted`)&&e.onComplete?.(i),i}),s.current.delete(t),l.current--,f()},onShouldRetry:e.onShouldRetry});s.current.set(t,r),i(e=>e.map(e=>e.id===t?{...e,jobId:o}:e))}catch(e){i(n=>n.map(n=>n.id===t?{...n,status:`error`,error:e}:n)),l.current--,f()}},[n,r,u,e]),p=t(e=>{let t=Array.from(e).map(e=>({id:`${Date.now()}-${Math.random().toString(36).substr(2,9)}`,file:e,status:`pending`,progress:0,bytesUploaded:0,totalBytes:e.size,error:null,result:null,jobId:null}));i(e=>[...e,...t])},[]),h=t(e=>{let t=s.current.get(e);t&&(t(),s.current.delete(e)),i(t=>t.filter(t=>t.id!==e)),c.current=c.current.filter(t=>t!==e)},[]),g=t(()=>{let e=r.filter(e=>e.status===`pending`);c.current.push(...e.map(e=>e.id));for(let e=0;e<u;e++)f()},[r,u,f]),_=t(e=>{let t=s.current.get(e);t&&(t(),s.current.delete(e),i(t=>t.map(t=>t.id===e?{...t,status:`aborted`}:t)),l.current--,f())},[f]),v=t(()=>{for(let e of s.current.values())e();s.current.clear(),c.current=[],l.current=0,i(e=>e.map(e=>e.status===`uploading`?{...e,status:`aborted`}:e))},[]),y=t(()=>{v(),i([])},[v]),b=t(e=>{i(t=>t.map(t=>t.id===e?{...t,status:`pending`,progress:0,bytesUploaded:0,error:null}:t)),c.current.push(e),f()},[f]),x={items:r,totalProgress:d(r),activeUploads:r.filter(e=>e.status===`uploading`).length,completedUploads:r.filter(e=>e.status===`success`).length,failedUploads:r.filter(e=>e.status===`error`).length};return{state:x,addFiles:p,removeFile:h,startUpload:g,abortUpload:_,abortAll:v,clear:y,retryUpload:b,isUploading:x.activeUploads>0}}const g={isDragging:!1,isOver:!1,isValid:!0,errors:[]};function _(e={}){let{accept:n,maxFiles:r,maxFileSize:i,multiple:s=!0,validator:c,onFilesReceived:l,onValidationError:u,onDragStateChange:d}=e,[f,p]=o(g),m=a(null),h=a(0),_=t(e=>{p(t=>({...t,...e}))},[]),v=t(e=>{let t=[];r&&e.length>r&&t.push(`Maximum ${r} files allowed. You selected ${e.length} files.`);for(let r of e){if(i&&r.size>i){let e=(i/(1024*1024)).toFixed(1),n=(r.size/(1024*1024)).toFixed(1);t.push(`File "${r.name}" (${n}MB) exceeds maximum size of ${e}MB.`)}n&&n.length>0&&(n.some(e=>{if(e.startsWith(`.`))return r.name.toLowerCase().endsWith(e.toLowerCase());if(e.endsWith(`/*`)){let t=e.slice(0,-2);return r.type.startsWith(t)}else return r.type===e})||t.push(`File "${r.name}" type "${r.type}" is not accepted. Accepted types: ${n.join(`, `)}.`))}if(c){let n=c(e);n&&t.push(...n)}return t},[n,r,i,c]),y=t(e=>{let t=Array.from(e),n=v(t);n.length>0?(_({errors:n,isValid:!1}),u?.(n)):(_({errors:[],isValid:!0}),l?.(t))},[v,_,l,u]),b=t(e=>{let t=[];if(e.items)for(let n=0;n<e.items.length;n++){let r=e.items[n];if(r&&r.kind===`file`){let e=r.getAsFile();e&&t.push(e)}}else for(let n=0;n<e.files.length;n++){let r=e.files[n];r&&t.push(r)}return t},[]),x=t(e=>{e.preventDefault(),e.stopPropagation(),h.current++,h.current===1&&(_({isDragging:!0,isOver:!0}),d?.(!0))},[_,d]),S=t(e=>{e.preventDefault(),e.stopPropagation(),e.dataTransfer&&(e.dataTransfer.dropEffect=`copy`)},[]),C=t(e=>{e.preventDefault(),e.stopPropagation(),h.current--,h.current===0&&(_({isDragging:!1,isOver:!1,errors:[]}),d?.(!1))},[_,d]),w=t(e=>{if(e.preventDefault(),e.stopPropagation(),h.current=0,_({isDragging:!1,isOver:!1}),d?.(!1),e.dataTransfer){let t=b(e.dataTransfer);t.length>0&&y(t)}},[_,d,b,y]),T=t(()=>{m.current?.click()},[]),E=t(e=>{e.target.files&&e.target.files.length>0&&y(Array.from(e.target.files)),e.target.value=``},[y]),D=t(()=>{p(g),h.current=0},[]);return{state:f,dragHandlers:{onDragEnter:x,onDragOver:S,onDragLeave:C,onDrop:w},inputProps:{type:`file`,multiple:s,accept:n?.join(`, `),onChange:E,style:{display:`none`},ref:m},openFilePicker:T,processFiles:y,reset:D}}function v(e){let t=e;return t.eventType===l.FlowStart||t.eventType===l.FlowEnd||t.eventType===l.FlowError||t.eventType===l.NodeStart||t.eventType===l.NodeEnd||t.eventType===l.NodePause||t.eventType===l.NodeResume||t.eventType===l.NodeError}const y={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,result:null,jobId:null,flowStarted:!1,currentNodeName:null,currentNodeType:null,flowOutputs:null};function b(e){let n=m(),[i,s]=o(y),c=a(null),d=a(null),f=a(e.onSuccess),p=a(e.onError),h=a(e.onFlowComplete),g=a(e.flowConfig.outputNodeId);r(()=>{f.current=e.onSuccess,p.current=e.onError,h.current=e.onFlowComplete,g.current=e.flowConfig.outputNodeId},[e.onSuccess,e.onError,e.onFlowComplete,e.flowConfig.outputNodeId]);let _=a(null);r(()=>{_.current=i.jobId},[i.jobId]);let b=t(e=>{if(console.log(`[useFlowUpload] Received event:`,e,`Current jobId:`,_.current),!_.current||e.jobId!==_.current){console.log(`[useFlowUpload] Ignoring event - jobId mismatch`);return}switch(console.log(`[useFlowUpload] Processing event type:`,e.eventType),e.eventType){case l.FlowStart:console.log(`[useFlowUpload] Flow started`),s(e=>({...e,flowStarted:!0,status:`processing`}));break;case l.NodeStart:console.log(`[useFlowUpload] Node started:`,e.nodeName),s(t=>({...t,status:`processing`,currentNodeName:e.nodeName,currentNodeType:e.nodeType}));break;case l.NodePause:console.log(`[useFlowUpload] Node paused (waiting for upload):`,e.nodeName),s(t=>({...t,status:`uploading`,currentNodeName:e.nodeName}));break;case l.NodeResume:console.log(`[useFlowUpload] Node resumed (upload complete):`,e.nodeName),s(t=>({...t,status:`processing`,currentNodeName:e.nodeName,currentNodeType:e.nodeType}));break;case l.NodeEnd:console.log(`[useFlowUpload] Node ended:`,e.nodeName),s(e=>({...e,status:e.status===`uploading`?`processing`:e.status,currentNodeName:null,currentNodeType:null}));break;case l.FlowEnd:console.log(`[useFlowUpload] Flow ended, processing outputs`),s(t=>{let n=e.result||null;console.log(`[useFlowUpload] Flow outputs:`,n),n&&h.current&&(console.log(`[useFlowUpload] Calling onFlowComplete with outputs:`,n),h.current(n));let r=null;return n&&(g.current&&g.current in n?(r=n[g.current],console.log(`[useFlowUpload] Extracted output from specified node:`,g.current)):(r=Object.values(n)[0],console.log(`[useFlowUpload] Extracted output from first node`))),r&&f.current?(console.log(`[useFlowUpload] Calling onSuccess with result:`,r),f.current(r)):!r&&f.current&&console.warn(`[useFlowUpload] No result available for onSuccess`),{...t,status:`success`,currentNodeName:null,currentNodeType:null,result:r,flowOutputs:n}});break;case l.FlowError:console.log(`[useFlowUpload] Flow error:`,e.error),s(t=>({...t,status:`error`,error:Error(e.error)})),p.current?.(Error(e.error));break;case l.NodeError:console.log(`[useFlowUpload] Node error:`,e.error),s(t=>({...t,status:`error`,error:Error(e.error)})),p.current?.(Error(e.error));break}},[]);return r(()=>(console.log(`[useFlowUpload] Subscribing to events from context`),n.subscribeToEvents(e=>{if(v(e)){b(e);return}let t=e;if(t.type===u.UPLOAD_PROGRESS&&t.flow?.jobId===_.current&&t.data){let{progress:e,total:n}=t.data,r=n?Math.round(e/n*100):0;console.log(`[useFlowUpload] Upload progress event:`,{progress:r,bytesUploaded:e,totalBytes:n,jobId:t.flow.jobId}),s(t=>({...t,progress:r,bytesUploaded:e,totalBytes:n}))}})),[n,b]),{state:i,upload:t(async t=>{_.current=null,s({...y,status:`uploading`,totalBytes:t.size});try{let{abort:r,pause:i}=await n.client.uploadWithFlow(t,e.flowConfig,{onJobStart:e=>{_.current=e,s(t=>({...t,jobId:e}))},onProgress:(t,n,r)=>{let i=r?Math.round(n/r*100):0;s(e=>({...e,progress:i,bytesUploaded:n,totalBytes:r})),e.onProgress?.(i,n,r)},onChunkComplete:e.onChunkComplete,onSuccess:e=>{s(e=>({...e,progress:100}))},onError:t=>{s(e=>({...e,status:`error`,error:t})),e.onError?.(t)},onShouldRetry:e.onShouldRetry});c.current=r,d.current=i}catch(t){s(e=>({...e,status:`error`,error:t})),e.onError?.(t)}},[n,e]),abort:t(()=>{c.current&&(c.current(),c.current=null,s(e=>({...e,status:`aborted`})),e.onAbort?.())},[e]),pause:t(()=>{d.current&&=(d.current(),null)},[]),reset:t(()=>{s(y),c.current=null,_.current=null},[]),isUploading:i.status===`uploading`||i.status===`processing`,isUploadingFile:i.status===`uploading`,isProcessing:i.status===`processing`}}function x(e={}){let n=m(),{maxConcurrent:r=3}=e,[i,s]=o([]),c=a([]),l=a(0),u=a(new Set),d=a(new Map);c.current=i;let f=t(()=>`upload-${Date.now()}-${l.current++}`,[]),p=t((e,t)=>{s(n=>{let r=n.map(n=>n.id===e?{...n,state:{...n.state,...t}}:n);return c.current=r,r})},[]),h=t(()=>{let t=c.current;if(t.every(e=>[`success`,`error`,`aborted`].includes(e.state.status))&&t.length>0){let n=t.filter(e=>e.state.status===`success`),r=t.filter(e=>[`error`,`aborted`].includes(e.state.status));e.onComplete?.({successful:n,failed:r,total:t.length})}},[e]),g=t(()=>{if(u.current.size>=r)return;let t=c.current.find(e=>e.state.status===`idle`&&!u.current.has(e.id));t&&(async()=>{u.current.add(t.id),e.onUploadStart?.(t),p(t.id,{status:`uploading`});try{let r=await n.client.upload(t.file,{metadata:e.metadata,uploadLengthDeferred:e.uploadLengthDeferred,uploadSize:e.uploadSize,onProgress:(n,r,i)=>{let a=i?Math.round(r/i*100):0;p(t.id,{progress:a,bytesUploaded:r,totalBytes:i}),e.onUploadProgress?.(t,a,r,i)},onChunkComplete:()=>{},onSuccess:n=>{p(t.id,{status:`success`,result:n,progress:100});let r={...t,state:{...t.state,status:`success`,result:n}};e.onUploadSuccess?.(r,n),u.current.delete(t.id),d.current.delete(t.id),g(),h()},onError:n=>{p(t.id,{status:`error`,error:n});let r={...t,state:{...t.state,status:`error`,error:n}};e.onUploadError?.(r,n),u.current.delete(t.id),d.current.delete(t.id),g(),h()},onShouldRetry:e.onShouldRetry});d.current.set(t.id,r)}catch(n){p(t.id,{status:`error`,error:n});let r={...t,state:{...t.state,status:`error`,error:n}};e.onUploadError?.(r,n),u.current.delete(t.id),d.current.delete(t.id),g(),h()}})()},[r,n,e,p,h]),_={total:i.length,completed:i.filter(e=>[`success`,`error`,`aborted`].includes(e.state.status)).length,successful:i.filter(e=>e.state.status===`success`).length,failed:i.filter(e=>[`error`,`aborted`].includes(e.state.status)).length,uploading:i.filter(e=>e.state.status===`uploading`).length,progress:i.length>0?Math.round(i.reduce((e,t)=>e+t.state.progress,0)/i.length):0,totalBytesUploaded:i.reduce((e,t)=>e+t.state.bytesUploaded,0),totalBytes:i.reduce((e,t)=>e+(t.state.totalBytes||0),0),isUploading:i.some(e=>e.state.status===`uploading`),isComplete:i.length>0&&i.every(e=>[`success`,`error`,`aborted`].includes(e.state.status))},v=t(e=>{let t=e.map(e=>({id:f(),file:e,state:{status:`idle`,progress:0,bytesUploaded:0,totalBytes:e instanceof File?e.size:null,error:null,result:null}}));console.log(`addFiles: Adding`,t.length,`files`);let n=[...c.current,...t];c.current=n,console.log(`addFiles: Updated itemsRef.current to`,n.length,`items`),s(n)},[f]),y=t(e=>{let t=c.current.find(t=>t.id===e);if(t&&t.state.status===`uploading`){let t=d.current.get(e);t&&(t.abort(),d.current.delete(e))}s(t=>{let n=t.filter(t=>t.id!==e);return c.current=n,n}),u.current.delete(e)},[]),b=t(e=>{let t=c.current.find(t=>t.id===e);if(t&&t.state.status===`uploading`){let t=d.current.get(e);t&&(t.abort(),d.current.delete(e)),u.current.delete(e),s(t=>{let n=t.map(t=>t.id===e?{...t,state:{...t.state,status:`aborted`}}:t);return c.current=n,n}),g()}},[g]),x=t(e=>{let t=c.current.find(t=>t.id===e);t&&[`error`,`aborted`].includes(t.state.status)&&(s(t=>{let n=t.map(t=>t.id===e?{...t,state:{...t.state,status:`idle`,error:null}}:t);return c.current=n,n}),setTimeout(()=>g(),0))},[g]),S=t(()=>{let e=c.current;console.log(`Starting all uploads`,e);let t=e.filter(e=>e.state.status===`idle`),n=r-u.current.size,i=t.slice(0,n);for(let e of i)console.log(`Starting next upload`,e),g()},[r,g]),C=t(()=>{c.current.filter(e=>e.state.status===`uploading`).forEach(e=>{let t=d.current.get(e.id);t&&(t.abort(),d.current.delete(e.id))}),u.current.clear(),s(e=>{let t=e.map(e=>e.state.status===`uploading`?{...e,state:{...e.state,status:`aborted`}}:e);return c.current=t,t})},[]);return{state:_,items:i,addFiles:v,removeItem:y,removeFile:y,startAll:S,abortUpload:b,abortAll:C,retryUpload:x,retryFailed:t(()=>{let e=c.current.filter(e=>[`error`,`aborted`].includes(e.state.status));e.length>0&&(s(t=>{let n=t.map(t=>e.some(e=>e.id===t.id)?{...t,state:{...t.state,status:`idle`,error:null}}:t);return c.current=n,n}),setTimeout(S,0))},[S]),clearCompleted:t(()=>{s(e=>{let t=e.filter(e=>![`success`,`error`,`aborted`].includes(e.state.status));return c.current=t,t})},[]),clearAll:t(()=>{C(),s([]),c.current=[],u.current.clear()},[C]),getItemsByStatus:t(e=>c.current.filter(t=>t.state.status===e),[]),metrics:{getInsights:()=>n.client.getChunkingInsights(),exportMetrics:()=>n.client.exportMetrics(),getNetworkMetrics:()=>n.client.getNetworkMetrics(),getNetworkCondition:()=>n.client.getNetworkCondition(),resetMetrics:()=>n.client.resetMetrics()}}}const S={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,result:null};function C(e={}){let n=m(),[i,s]=o(S),c=a(null),l=a(null),d=t(e=>{s(t=>({...t,...e}))},[]),f=t(()=>{c.current&&=(c.current.abort(),null),s(S),l.current=null},[]),p=t(()=>{c.current&&=(c.current.abort(),null),d({status:`aborted`}),e.onAbort?.()},[e,d]),h=t(t=>{s({...S,status:`uploading`,totalBytes:t instanceof File?t.size:null}),l.current=t,n.client.upload(t,{metadata:e.metadata,uploadLengthDeferred:e.uploadLengthDeferred,uploadSize:e.uploadSize,onStart:({uploadId:e})=>{_.current=e},onProgress:(t,n,r)=>{let i=r?Math.round(n/r*100):0;d({progress:i,bytesUploaded:n,totalBytes:r}),e.onProgress?.(i,n,r)},onChunkComplete:(t,n,r)=>{e.onChunkComplete?.(t,n,r)},onSuccess:t=>{d({status:`success`,result:t,progress:100,bytesUploaded:t.size||0,totalBytes:t.size||null}),e.onSuccess?.(t),c.current=null},onError:t=>{d({status:`error`,error:t}),e.onError?.(t),c.current=null},onShouldRetry:e.onShouldRetry}).then(e=>{c.current=e}).catch(t=>{d({status:`error`,error:t}),e.onError?.(t),c.current=null})},[n,e,d]),g=t(()=>{l.current&&(i.status===`error`||i.status===`aborted`)&&h(l.current)},[h,i.status]),_=a(null);return r(()=>n.subscribeToEvents(t=>{let n=t;if(n.type===u.UPLOAD_PROGRESS&&n.data){let{id:t,progress:r,total:i}=n.data;if(t!==_.current)return;let a=i?Math.round(r/i*100):0;s(e=>e.status===`uploading`?{...e,progress:a,bytesUploaded:r,totalBytes:i}:e),e.onProgress?.(a,r,i)}}),[n,e]),{state:i,upload:h,abort:p,reset:f,retry:g,isUploading:i.status===`uploading`,canRetry:(i.status===`error`||i.status===`aborted`)&&l.current!==null,metrics:{getInsights:()=>n.client.getChunkingInsights(),exportMetrics:()=>n.client.exportMetrics(),getNetworkMetrics:()=>n.client.getNetworkMetrics(),getNetworkCondition:()=>n.client.getNetworkCondition(),resetMetrics:()=>n.client.resetMetrics()}}}export{h as a,d as c,_ as i,x as n,p as o,b as r,m as s,C as t};
|
|
2
|
-
//# sourceMappingURL=use-upload-CvPqdohl.mjs.map
|