@uploadista/react 0.0.15-beta.4 → 0.0.15

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.
Files changed (31) hide show
  1. package/dist/components/index.d.mts +2 -2
  2. package/dist/components/index.mjs +1 -1
  3. package/dist/hooks/index.d.mts +2 -2
  4. package/dist/hooks/index.mjs +1 -1
  5. package/dist/index.d.mts +4 -4
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +1 -1
  8. package/dist/{upload-zone-pXt4LdcC.mjs → upload-zone-DN7Gem65.mjs} +2 -2
  9. package/dist/{upload-zone-pXt4LdcC.mjs.map → upload-zone-DN7Gem65.mjs.map} +1 -1
  10. package/dist/{uploadista-provider-k2P1_Ms-.d.mts → uploadista-provider-DIMEpwsu.d.mts} +2 -2
  11. package/dist/{uploadista-provider-k2P1_Ms-.d.mts.map → uploadista-provider-DIMEpwsu.d.mts.map} +1 -1
  12. package/dist/use-upload-C7QZSt1M.mjs +2 -0
  13. package/dist/use-upload-C7QZSt1M.mjs.map +1 -0
  14. package/dist/use-upload-metrics-DEaujDeM.mjs +2 -0
  15. package/dist/use-upload-metrics-DEaujDeM.mjs.map +1 -0
  16. package/dist/{use-upload-metrics-Vho0Lzmq.d.mts → use-upload-metrics-R1xNz6Aa.d.mts} +5 -5
  17. package/dist/use-upload-metrics-R1xNz6Aa.d.mts.map +1 -0
  18. package/dist/{use-uploadista-client-CRUhyWoy.d.mts → use-uploadista-client-ty1ffKD7.d.mts} +16 -13
  19. package/dist/use-uploadista-client-ty1ffKD7.d.mts.map +1 -0
  20. package/package.json +5 -5
  21. package/src/contexts/flow-manager-context.tsx +22 -35
  22. package/src/hooks/use-flow-upload.ts +45 -30
  23. package/src/hooks/use-multi-flow-upload.ts +7 -3
  24. package/src/hooks/use-upload-events.ts +43 -21
  25. package/src/hooks/use-uploadista-events.ts +1 -1
  26. package/dist/use-upload-DSYzF2Et.mjs +0 -2
  27. package/dist/use-upload-DSYzF2Et.mjs.map +0 -1
  28. package/dist/use-upload-metrics-DFVcWvCk.mjs +0 -2
  29. package/dist/use-upload-metrics-DFVcWvCk.mjs.map +0 -1
  30. package/dist/use-upload-metrics-Vho0Lzmq.d.mts.map +0 -1
  31. package/dist/use-uploadista-client-CRUhyWoy.d.mts.map +0 -1
@@ -1,8 +1,11 @@
1
- import type { UploadistaEvent } from "@uploadista/client-browser";
1
+ import type {
2
+ BrowserUploadInput,
3
+ FlowUploadOptions,
4
+ UploadistaEvent,
5
+ } from "@uploadista/client-browser";
2
6
  import {
3
7
  FlowManager,
4
8
  type FlowManagerCallbacks,
5
- type FlowUploadState,
6
9
  } from "@uploadista/client-core";
7
10
  import { EventType, type FlowEvent } from "@uploadista/core/flow";
8
11
  import { UploadEventType } from "@uploadista/core/types";
@@ -15,7 +18,6 @@ import {
15
18
  useRef,
16
19
  } from "react";
17
20
  import { useUploadistaContext } from "../components/uploadista-provider";
18
- import type { FlowUploadOptions } from "@uploadista/client-browser";
19
21
 
20
22
  /**
21
23
  * Type guard to check if an event is a flow event
@@ -37,8 +39,8 @@ function isFlowEvent(event: UploadistaEvent): event is FlowEvent {
37
39
  /**
38
40
  * Internal manager registry entry with ref counting
39
41
  */
40
- interface ManagerEntry<TOutput> {
41
- manager: FlowManager<unknown, TOutput>;
42
+ interface ManagerEntry {
43
+ manager: FlowManager<unknown>;
42
44
  refCount: number;
43
45
  flowId: string;
44
46
  }
@@ -56,11 +58,11 @@ interface FlowManagerContextValue {
56
58
  * @param options - Flow configuration options
57
59
  * @returns FlowManager instance
58
60
  */
59
- getManager: <TOutput = unknown>(
61
+ getManager: (
60
62
  flowId: string,
61
- callbacks: FlowManagerCallbacks<TOutput>,
62
- options: FlowUploadOptions<TOutput>,
63
- ) => FlowManager<unknown, TOutput>;
63
+ callbacks: FlowManagerCallbacks,
64
+ options: FlowUploadOptions,
65
+ ) => FlowManager<unknown>;
64
66
 
65
67
  /**
66
68
  * Release a flow manager reference.
@@ -101,9 +103,7 @@ interface FlowManagerProviderProps {
101
103
  */
102
104
  export function FlowManagerProvider({ children }: FlowManagerProviderProps) {
103
105
  const { client, subscribeToEvents } = useUploadistaContext();
104
- const managersRef = useRef(
105
- new Map<string, ManagerEntry<unknown>>(),
106
- );
106
+ const managersRef = useRef(new Map<string, ManagerEntry>());
107
107
 
108
108
  // Subscribe to all events and route to appropriate managers
109
109
  useEffect(() => {
@@ -122,15 +122,11 @@ export function FlowManagerProvider({ children }: FlowManagerProviderProps) {
122
122
  event.type === UploadEventType.UPLOAD_PROGRESS &&
123
123
  "data" in event
124
124
  ) {
125
- const uploadEvent = event as {
126
- type: UploadEventType;
127
- uploadId: string;
128
- data: { progress: number; total: number | null };
129
- };
125
+ const uploadEvent = event;
130
126
 
131
127
  for (const entry of managersRef.current.values()) {
132
128
  entry.manager.handleUploadProgress(
133
- uploadEvent.uploadId,
129
+ uploadEvent.data.id,
134
130
  uploadEvent.data.progress,
135
131
  uploadEvent.data.total,
136
132
  );
@@ -142,36 +138,27 @@ export function FlowManagerProvider({ children }: FlowManagerProviderProps) {
142
138
  }, [subscribeToEvents]);
143
139
 
144
140
  const getManager = useCallback(
145
- <TOutput,>(
141
+ (
146
142
  flowId: string,
147
- callbacks: FlowManagerCallbacks<TOutput>,
148
- options: FlowUploadOptions<TOutput>,
149
- ): FlowManager<unknown, TOutput> => {
143
+ callbacks: FlowManagerCallbacks,
144
+ options: FlowUploadOptions,
145
+ ): FlowManager<unknown> => {
150
146
  const existing = managersRef.current.get(flowId);
151
147
 
152
148
  if (existing) {
153
149
  // Increment ref count for existing manager
154
150
  existing.refCount++;
155
- return existing.manager as FlowManager<unknown, TOutput>;
151
+ return existing.manager;
156
152
  }
157
153
 
158
- // Create new manager using client from hook scope
159
- const flowUploadFn = (
160
- input: unknown,
161
- flowConfig: FlowUploadOptions<TOutput>["flowConfig"],
162
- internalOptions: unknown,
163
- ) => {
164
- return client.uploadWithFlow(input, flowConfig, internalOptions);
165
- };
166
-
167
- const manager = new FlowManager<unknown, TOutput>(
168
- flowUploadFn,
154
+ const manager = new FlowManager<BrowserUploadInput>(
155
+ client.uploadWithFlow,
169
156
  callbacks,
170
157
  options,
171
158
  );
172
159
 
173
160
  managersRef.current.set(flowId, {
174
- manager: manager as FlowManager<unknown, unknown>,
161
+ manager,
175
162
  refCount: 1,
176
163
  flowId,
177
164
  });
@@ -1,11 +1,10 @@
1
1
  import type { FlowUploadOptions } from "@uploadista/client-browser";
2
- import {
3
- type FlowManager,
4
- type FlowUploadState,
5
- type FlowUploadStatus,
2
+ import type {
3
+ FlowManager,
4
+ FlowUploadState,
5
+ FlowUploadStatus,
6
6
  } from "@uploadista/client-core";
7
7
  import type { TypedOutput } from "@uploadista/core/flow";
8
- import type { UploadFile } from "@uploadista/core/types";
9
8
  import { useCallback, useEffect, useRef, useState } from "react";
10
9
  import { useFlowManagerContext } from "../contexts/flow-manager-context";
11
10
 
@@ -15,8 +14,6 @@ export type { FlowUploadState, FlowUploadStatus };
15
14
  /**
16
15
  * Return value from the useFlowUpload hook with upload control methods and state.
17
16
  *
18
- * @template TOutput - Type of the final output from the flow (defaults to UploadFile)
19
- *
20
17
  * @property state - Complete flow upload state with progress and outputs
21
18
  * @property upload - Function to initiate file upload through the flow
22
19
  * @property abort - Cancel the current upload and flow execution
@@ -26,11 +23,11 @@ export type { FlowUploadState, FlowUploadStatus };
26
23
  * @property isUploadingFile - True only during file upload phase
27
24
  * @property isProcessing - True only during flow processing phase
28
25
  */
29
- export interface UseFlowUploadReturn<TOutput = UploadFile> {
26
+ export interface UseFlowUploadReturn {
30
27
  /**
31
28
  * Current upload state
32
29
  */
33
- state: FlowUploadState<TOutput>;
30
+ state: FlowUploadState;
34
31
 
35
32
  /**
36
33
  * Upload a file through the flow
@@ -74,7 +71,6 @@ const initialState: FlowUploadState = {
74
71
  bytesUploaded: 0,
75
72
  totalBytes: null,
76
73
  error: null,
77
- result: null,
78
74
  jobId: null,
79
75
  flowStarted: false,
80
76
  currentNodeName: null,
@@ -93,7 +89,6 @@ const initialState: FlowUploadState = {
93
89
  * Must be used within FlowManagerProvider (which must be within UploadistaProvider).
94
90
  * Flow events are automatically routed by the provider to the appropriate manager.
95
91
  *
96
- * @template TOutput - Type of the final result from the flow (defaults to UploadFile)
97
92
  * @param options - Flow upload configuration including flow ID and event handlers
98
93
  * @returns Flow upload state and control methods
99
94
  *
@@ -105,14 +100,16 @@ const initialState: FlowUploadState = {
105
100
  * flowConfig: {
106
101
  * flowId: "image-optimization-flow",
107
102
  * storageId: "s3-images",
108
- * outputNodeId: "optimized-output", // Optional: specify which output to use
109
103
  * },
110
- * onSuccess: (result) => {
111
- * console.log("Image optimized and saved:", result);
104
+ * onSuccess: (outputs) => {
105
+ * console.log("Flow outputs:", outputs);
106
+ * // Access all outputs from the flow
107
+ * for (const output of outputs) {
108
+ * console.log(`${output.nodeId}:`, output.data);
109
+ * }
112
110
  * },
113
111
  * onFlowComplete: (outputs) => {
114
112
  * console.log("All flow outputs:", outputs);
115
- * // outputs might include: { thumbnail: {...}, optimized: {...}, original: {...} }
116
113
  * },
117
114
  * onError: (error) => {
118
115
  * console.error("Upload or processing failed:", error);
@@ -146,8 +143,12 @@ const initialState: FlowUploadState = {
146
143
  * {flowUpload.state.status === "success" && (
147
144
  * <div>
148
145
  * <p>Upload complete!</p>
149
- * {flowUpload.state.result && (
150
- * <img src={flowUpload.state.result.url} alt="Uploaded" />
146
+ * {flowUpload.state.flowOutputs && (
147
+ * <div>
148
+ * {flowUpload.state.flowOutputs.map((output) => (
149
+ * <div key={output.nodeId}>{output.nodeId}: {JSON.stringify(output.data)}</div>
150
+ * ))}
151
+ * </div>
151
152
  * )}
152
153
  * </div>
153
154
  * )}
@@ -170,14 +171,10 @@ const initialState: FlowUploadState = {
170
171
  * @see {@link useMultiFlowUpload} for uploading multiple files through a flow
171
172
  * @see {@link useUpload} for simple uploads without flow processing
172
173
  */
173
- export function useFlowUpload<TOutput = UploadFile>(
174
- options: FlowUploadOptions<TOutput>,
175
- ): UseFlowUploadReturn<TOutput> {
174
+ export function useFlowUpload(options: FlowUploadOptions): UseFlowUploadReturn {
176
175
  const { getManager, releaseManager } = useFlowManagerContext();
177
- const [state, setState] = useState<FlowUploadState<TOutput>>(
178
- initialState as FlowUploadState<TOutput>,
179
- );
180
- const managerRef = useRef<FlowManager<unknown, TOutput> | null>(null);
176
+ const [state, setState] = useState<FlowUploadState>(initialState);
177
+ const managerRef = useRef<FlowManager<unknown> | null>(null);
181
178
 
182
179
  // Store callbacks in refs so they can be updated without recreating the manager
183
180
  const callbacksRef = useRef(options);
@@ -195,17 +192,29 @@ export function useFlowUpload<TOutput = UploadFile>(
195
192
  // Create stable callback wrappers that call the latest callbacks via refs
196
193
  const stableCallbacks = {
197
194
  onStateChange: setState,
198
- onProgress: (uploadId: string, bytesUploaded: number, totalBytes: number | null) => {
195
+ onProgress: (
196
+ uploadId: string,
197
+ bytesUploaded: number,
198
+ totalBytes: number | null,
199
+ ) => {
199
200
  callbacksRef.current.onProgress?.(uploadId, bytesUploaded, totalBytes);
200
201
  },
201
- onChunkComplete: (chunkSize: number, bytesAccepted: number, bytesTotal: number | null) => {
202
- callbacksRef.current.onChunkComplete?.(chunkSize, bytesAccepted, bytesTotal);
202
+ onChunkComplete: (
203
+ chunkSize: number,
204
+ bytesAccepted: number,
205
+ bytesTotal: number | null,
206
+ ) => {
207
+ callbacksRef.current.onChunkComplete?.(
208
+ chunkSize,
209
+ bytesAccepted,
210
+ bytesTotal,
211
+ );
203
212
  },
204
213
  onFlowComplete: (outputs: TypedOutput[]) => {
205
214
  callbacksRef.current.onFlowComplete?.(outputs);
206
215
  },
207
- onSuccess: (result: TOutput) => {
208
- callbacksRef.current.onSuccess?.(result);
216
+ onSuccess: (outputs: TypedOutput[]) => {
217
+ callbacksRef.current.onSuccess?.(outputs);
209
218
  },
210
219
  onError: (error: Error) => {
211
220
  callbacksRef.current.onError?.(error);
@@ -223,7 +232,13 @@ export function useFlowUpload<TOutput = UploadFile>(
223
232
  releaseManager(flowId);
224
233
  managerRef.current = null;
225
234
  };
226
- }, [options.flowConfig.flowId, options.flowConfig.storageId, options.flowConfig.outputNodeId, getManager, releaseManager]);
235
+ }, [
236
+ options.flowConfig.flowId,
237
+ options.flowConfig.storageId,
238
+ options.flowConfig.outputNodeId,
239
+ getManager,
240
+ releaseManager,
241
+ ]);
227
242
 
228
243
  // Wrap manager methods with useCallback
229
244
  const upload = useCallback(async (file: File | Blob) => {
@@ -4,7 +4,6 @@ import type {
4
4
  MultiFlowUploadOptions,
5
5
  MultiFlowUploadState,
6
6
  } from "@uploadista/client-browser";
7
- import type { UploadFile } from "@uploadista/core/types";
8
7
  import { useCallback, useRef, useState } from "react";
9
8
  import { useUploadistaContext } from "../components/uploadista-provider";
10
9
 
@@ -271,11 +270,16 @@ export function useMultiFlowUpload(
271
270
  return updated;
272
271
  });
273
272
  },
274
- onSuccess: (result: UploadFile) => {
273
+ onSuccess: (outputs) => {
275
274
  setItems((prev) => {
276
275
  const updated = prev.map((i) =>
277
276
  i.id === itemId
278
- ? { ...i, status: "success" as const, result, progress: 100 }
277
+ ? {
278
+ ...i,
279
+ status: "success" as const,
280
+ result: outputs,
281
+ progress: 100,
282
+ }
279
283
  : i,
280
284
  );
281
285
  const updatedItem = updated.find((i) => i.id === itemId);
@@ -151,41 +151,63 @@ export function useUploadEvents(options: UseUploadEventsOptions): void {
151
151
  if (!isUploadEvent(event)) return;
152
152
 
153
153
  // Route to appropriate callback based on event type
154
+ // Note: flow context is at the top level of the event, not inside data
155
+ const flowContext = "flow" in event ? event.flow : undefined;
156
+
154
157
  switch (event.type) {
155
158
  case UploadEventType.UPLOAD_STARTED:
156
- options.onUploadStarted?.(
157
- event.data as unknown as UploadFileEventData,
158
- );
159
+ options.onUploadStarted?.({
160
+ ...(event.data as unknown as Omit<UploadFileEventData, "flow">),
161
+ flow: flowContext,
162
+ });
159
163
  break;
160
164
  case UploadEventType.UPLOAD_PROGRESS:
161
- options.onUploadProgress?.(
162
- event.data as unknown as UploadProgressEventData,
163
- );
165
+ options.onUploadProgress?.({
166
+ ...(event.data as unknown as Omit<
167
+ UploadProgressEventData,
168
+ "flow"
169
+ >),
170
+ flow: flowContext,
171
+ });
164
172
  break;
165
173
  case UploadEventType.UPLOAD_COMPLETE:
166
- options.onUploadComplete?.(
167
- event.data as unknown as UploadFileEventData,
168
- );
174
+ options.onUploadComplete?.({
175
+ ...(event.data as unknown as Omit<UploadFileEventData, "flow">),
176
+ flow: flowContext,
177
+ });
169
178
  break;
170
179
  case UploadEventType.UPLOAD_FAILED:
171
- options.onUploadFailed?.(
172
- event.data as unknown as UploadFailedEventData,
173
- );
180
+ options.onUploadFailed?.({
181
+ ...(event.data as unknown as Omit<UploadFailedEventData, "flow">),
182
+ flow: flowContext,
183
+ });
174
184
  break;
175
185
  case UploadEventType.UPLOAD_VALIDATION_SUCCESS:
176
- options.onUploadValidationSuccess?.(
177
- event.data as unknown as UploadValidationSuccessEventData,
178
- );
186
+ options.onUploadValidationSuccess?.({
187
+ ...(event.data as unknown as Omit<
188
+ UploadValidationSuccessEventData,
189
+ "flow"
190
+ >),
191
+ flow: flowContext,
192
+ });
179
193
  break;
180
194
  case UploadEventType.UPLOAD_VALIDATION_FAILED:
181
- options.onUploadValidationFailed?.(
182
- event.data as unknown as UploadValidationFailedEventData,
183
- );
195
+ options.onUploadValidationFailed?.({
196
+ ...(event.data as unknown as Omit<
197
+ UploadValidationFailedEventData,
198
+ "flow"
199
+ >),
200
+ flow: flowContext,
201
+ });
184
202
  break;
185
203
  case UploadEventType.UPLOAD_VALIDATION_WARNING:
186
- options.onUploadValidationWarning?.(
187
- event.data as unknown as UploadValidationWarningEventData,
188
- );
204
+ options.onUploadValidationWarning?.({
205
+ ...(event.data as unknown as Omit<
206
+ UploadValidationWarningEventData,
207
+ "flow"
208
+ >),
209
+ flow: flowContext,
210
+ });
189
211
  break;
190
212
  }
191
213
  });
@@ -1,4 +1,4 @@
1
- import type { UploadistaEvent } from "@uploadista/client-browser";
1
+ import type { UploadistaEvent } from "@uploadista/client-core";
2
2
  import { useEffect } from "react";
3
3
  import { useUploadistaContext } from "../components/uploadista-provider";
4
4
 
@@ -1,2 +0,0 @@
1
- import{EventType as e}from"@uploadista/core/flow";import{UploadEventType as t}from"@uploadista/core/types";import{createContext as n,useCallback as r,useContext as i,useEffect as a,useMemo as o,useRef as s,useState as c}from"react";import{FlowManager as l,UploadManager as u}from"@uploadista/client-core";import{jsx as d}from"react/jsx-runtime";import{createUploadistaClient as f}from"@uploadista/client-browser";function p(t){let n=t;return n.eventType===e.FlowStart||n.eventType===e.FlowEnd||n.eventType===e.FlowError||n.eventType===e.NodeStart||n.eventType===e.NodeEnd||n.eventType===e.NodePause||n.eventType===e.NodeResume||n.eventType===e.NodeError}const m=n(void 0);function h({children:e}){let{client:n,subscribeToEvents:i}=b(),o=s(new Map);a(()=>i(e=>{if(p(e)){for(let t of o.current.values())t.manager.handleFlowEvent(e);return}if(`type`in e&&e.type===t.UPLOAD_PROGRESS&&`data`in e){let t=e;for(let e of o.current.values())e.manager.handleUploadProgress(t.uploadId,t.data.progress,t.data.total)}}),[i]);let c=r((e,t,r)=>{let i=o.current.get(e);if(i)return i.refCount++,i.manager;let a=new l((e,t,r)=>n.uploadWithFlow(e,t,r),t,r);return o.current.set(e,{manager:a,refCount:1,flowId:e}),a},[n]),u=r(e=>{let t=o.current.get(e);t&&(t.refCount--,t.refCount<=0&&(t.manager.cleanup(),o.current.delete(e)))},[]);return d(m.Provider,{value:{getManager:c,releaseManager:u},children:e})}function g(){let e=i(m);if(e===void 0)throw Error(`useFlowManagerContext must be used within a FlowManagerProvider. Make sure to wrap your component tree with <FlowManagerProvider>.`);return e}function _(e){let t=s(e);return t.current=e,{client:o(()=>(console.log(`[useUploadistaClient] Creating NEW client instance with onEvent:`,e.onEvent),f({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.baseUrl,e.storageId,e.uploadistaBasePath,e.chunkSize,e.storeFingerprintForResuming,e.retryDelays,e.parallelUploads,e.parallelChunkSize,e.uploadStrategy,e.smartChunking,e.networkMonitoring,e.uploadMetrics,e.connectionPooling,e.auth,e.onEvent]),config:e}}const v=n(null);function y({children:e,...t}){let n=s(new Set),i=r(e=>{n.current.forEach(t=>{try{t(e)}catch(e){console.error(`Error in event subscriber:`,e)}})},[]),a=_({...t,onEvent:i}),c=r(e=>(n.current.add(e),()=>{n.current.delete(e)}),[]),l=o(()=>({...a,subscribeToEvents:c}),[a,c]);return d(v.Provider,{value:l,children:d(h,{children:e})})}function b(){let e=i(v);if(e===null)throw Error(`useUploadistaContext must be used within an UploadistaProvider. Make sure to wrap your component tree with <UploadistaProvider>.`);return e}function x(e){let t=b(),[n,i]=c([]),a=s(new Map),o=s([]),l=s(0),u=e.maxConcurrent??3,d=r(e=>{if(e.length===0)return 0;let t=e.reduce((e,t)=>e+t.progress,0);return Math.round(t/e.length)},[]),f=r(async()=>{if(l.current>=u||o.current.length===0)return;let r=o.current.shift();if(!r)return;let s=n.find(e=>e.id===r);if(!s||s.status!==`pending`){f();return}l.current++,i(e=>e.map(e=>e.id===r?{...e,status:`uploading`}:e));try{let{abort:n,jobId:o}=await t.client.uploadWithFlow(s.file,e.flowConfig,{onJobStart:e=>{i(t=>t.map(t=>t.id===r?{...t,jobId:e}:t))},onProgress:(t,n,a)=>{let o=a?Math.round(n/a*100):0;i(t=>{let i=t.map(e=>e.id===r?{...e,progress:o,bytesUploaded:n,totalBytes:a||0}:e),s=i.find(e=>e.id===r);return s&&e.onItemProgress?.(s),i})},onSuccess:t=>{i(n=>{let i=n.map(e=>e.id===r?{...e,status:`success`,result:t,progress:100}:e),a=i.find(e=>e.id===r);return a&&e.onItemSuccess?.(a),i.every(e=>e.status===`success`||e.status===`error`||e.status===`aborted`)&&e.onComplete?.(i),i}),a.current.delete(r),l.current--,f()},onError:t=>{i(n=>{let i=n.map(e=>e.id===r?{...e,status:`error`,error:t}:e),a=i.find(e=>e.id===r);return a&&e.onItemError?.(a,t),i.every(e=>e.status===`success`||e.status===`error`||e.status===`aborted`)&&e.onComplete?.(i),i}),a.current.delete(r),l.current--,f()},onShouldRetry:e.onShouldRetry});a.current.set(r,n),i(e=>e.map(e=>e.id===r?{...e,jobId:o}:e))}catch(e){i(t=>t.map(t=>t.id===r?{...t,status:`error`,error:e}:t)),l.current--,f()}},[t,n,u,e]),p=r(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])},[]),m=r(e=>{let t=a.current.get(e);t&&(t(),a.current.delete(e)),i(t=>t.filter(t=>t.id!==e)),o.current=o.current.filter(t=>t!==e)},[]),h=r(()=>{let e=n.filter(e=>e.status===`pending`);o.current.push(...e.map(e=>e.id));for(let e=0;e<u;e++)f()},[n,u,f]),g=r(e=>{let t=a.current.get(e);t&&(t(),a.current.delete(e),i(t=>t.map(t=>t.id===e?{...t,status:`aborted`}:t)),l.current--,f())},[f]),_=r(()=>{for(let e of a.current.values())e();a.current.clear(),o.current=[],l.current=0,i(e=>e.map(e=>e.status===`uploading`?{...e,status:`aborted`}:e))},[]),v=r(()=>{_(),i([])},[_]),y=r(e=>{i(t=>t.map(t=>t.id===e?{...t,status:`pending`,progress:0,bytesUploaded:0,error:null}:t)),o.current.push(e),f()},[f]),x={items:n,totalProgress:d(n),activeUploads:n.filter(e=>e.status===`uploading`).length,completedUploads:n.filter(e=>e.status===`success`).length,failedUploads:n.filter(e=>e.status===`error`).length};return{state:x,addFiles:p,removeFile:m,startUpload:h,abortUpload:g,abortAll:_,clear:v,retryUpload:y,isUploading:x.activeUploads>0}}const S={isDragging:!1,isOver:!1,isValid:!0,errors:[]};function C(e={}){let{accept:t,maxFiles:n,maxFileSize:i,multiple:a=!0,validator:o,onFilesReceived:l,onValidationError:u,onDragStateChange:d}=e,[f,p]=c(S),m=s(null),h=s(0),g=r(e=>{p(t=>({...t,...e}))},[]),_=r(e=>{let r=[];n&&e.length>n&&r.push(`Maximum ${n} files allowed. You selected ${e.length} files.`);for(let n of e){if(i&&n.size>i){let e=(i/(1024*1024)).toFixed(1),t=(n.size/(1024*1024)).toFixed(1);r.push(`File "${n.name}" (${t}MB) exceeds maximum size of ${e}MB.`)}t&&t.length>0&&(t.some(e=>{if(e.startsWith(`.`))return n.name.toLowerCase().endsWith(e.toLowerCase());if(e.endsWith(`/*`)){let t=e.slice(0,-2);return n.type.startsWith(t)}else return n.type===e})||r.push(`File "${n.name}" type "${n.type}" is not accepted. Accepted types: ${t.join(`, `)}.`))}if(o){let t=o(e);t&&r.push(...t)}return r},[t,n,i,o]),v=r(e=>{let t=Array.from(e),n=_(t);n.length>0?(g({errors:n,isValid:!1}),u?.(n)):(g({errors:[],isValid:!0}),l?.(t))},[_,g,l,u]),y=r(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},[]),b=r(e=>{e.preventDefault(),e.stopPropagation(),h.current++,h.current===1&&(g({isDragging:!0,isOver:!0}),d?.(!0))},[g,d]),x=r(e=>{e.preventDefault(),e.stopPropagation(),e.dataTransfer&&(e.dataTransfer.dropEffect=`copy`)},[]),C=r(e=>{e.preventDefault(),e.stopPropagation(),h.current--,h.current===0&&(g({isDragging:!1,isOver:!1,errors:[]}),d?.(!1))},[g,d]),w=r(e=>{if(e.preventDefault(),e.stopPropagation(),h.current=0,g({isDragging:!1,isOver:!1}),d?.(!1),e.dataTransfer){let t=y(e.dataTransfer);t.length>0&&v(t)}},[g,d,y,v]),T=r(()=>{m.current?.click()},[]),E=r(e=>{e.target.files&&e.target.files.length>0&&v(Array.from(e.target.files)),e.target.value=``},[v]),D=r(()=>{p(S),h.current=0},[]);return{state:f,dragHandlers:{onDragEnter:b,onDragOver:x,onDragLeave:C,onDrop:w},inputProps:{type:`file`,multiple:a,accept:t?.join(`, `),onChange:E,style:{display:`none`},ref:m},openFilePicker:T,processFiles:v,reset:D}}const w={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,result:null,jobId:null,flowStarted:!1,currentNodeName:null,currentNodeType:null,flowOutputs:null};function T(e){let{getManager:t,releaseManager:n}=g(),[i,o]=c(w),l=s(null),u=s(e);return a(()=>{u.current=e}),a(()=>{let r=e.flowConfig.flowId;return l.current=t(r,{onStateChange:o,onProgress:(e,t,n)=>{u.current.onProgress?.(e,t,n)},onChunkComplete:(e,t,n)=>{u.current.onChunkComplete?.(e,t,n)},onFlowComplete:e=>{u.current.onFlowComplete?.(e)},onSuccess:e=>{u.current.onSuccess?.(e)},onError:e=>{u.current.onError?.(e)},onAbort:()=>{u.current.onAbort?.()}},e),()=>{n(r),l.current=null}},[e.flowConfig.flowId,e.flowConfig.storageId,e.flowConfig.outputNodeId,t,n]),{state:i,upload:r(async e=>{await l.current?.upload(e)},[]),abort:r(()=>{l.current?.abort()},[]),pause:r(()=>{l.current?.pause()},[]),reset:r(()=>{l.current?.reset()},[]),isUploading:i.status===`uploading`||i.status===`processing`,isUploadingFile:i.status===`uploading`,isProcessing:i.status===`processing`}}function E(e={}){let t=b(),{maxConcurrent:n=3}=e,[i,a]=c([]),o=s([]),l=s(0),u=s(new Set),d=s(new Map);o.current=i;let f=r(()=>`upload-${Date.now()}-${l.current++}`,[]),p=r((e,t)=>{a(n=>{let r=n.map(n=>n.id===e?{...n,state:{...n.state,...t}}:n);return o.current=r,r})},[]),m=r(()=>{let t=o.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]),h=r(()=>{if(u.current.size>=n)return;let r=o.current.find(e=>e.state.status===`idle`&&!u.current.has(e.id));r&&(async()=>{u.current.add(r.id),e.onUploadStart?.(r),p(r.id,{status:`uploading`});try{let n=await t.client.upload(r.file,{metadata:e.metadata,uploadLengthDeferred:e.uploadLengthDeferred,uploadSize:e.uploadSize,onProgress:(t,n,i)=>{let a=i?Math.round(n/i*100):0;p(r.id,{progress:a,bytesUploaded:n,totalBytes:i}),e.onUploadProgress?.(r,a,n,i)},onChunkComplete:()=>{},onSuccess:t=>{p(r.id,{status:`success`,result:t,progress:100});let n={...r,state:{...r.state,status:`success`,result:t}};e.onUploadSuccess?.(n,t),u.current.delete(r.id),d.current.delete(r.id),h(),m()},onError:t=>{p(r.id,{status:`error`,error:t});let n={...r,state:{...r.state,status:`error`,error:t}};e.onUploadError?.(n,t),u.current.delete(r.id),d.current.delete(r.id),h(),m()},onShouldRetry:e.onShouldRetry});d.current.set(r.id,n)}catch(t){p(r.id,{status:`error`,error:t});let n={...r,state:{...r.state,status:`error`,error:t}};e.onUploadError?.(n,t),u.current.delete(r.id),d.current.delete(r.id),h(),m()}})()},[n,t,e,p,m]),g={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))},_=r(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=[...o.current,...t];o.current=n,console.log(`addFiles: Updated itemsRef.current to`,n.length,`items`),a(n)},[f]),v=r(e=>{let t=o.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))}a(t=>{let n=t.filter(t=>t.id!==e);return o.current=n,n}),u.current.delete(e)},[]),y=r(e=>{let t=o.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),a(t=>{let n=t.map(t=>t.id===e?{...t,state:{...t.state,status:`aborted`}}:t);return o.current=n,n}),h()}},[h]),x=r(e=>{let t=o.current.find(t=>t.id===e);t&&[`error`,`aborted`].includes(t.state.status)&&(a(t=>{let n=t.map(t=>t.id===e?{...t,state:{...t.state,status:`idle`,error:null}}:t);return o.current=n,n}),setTimeout(()=>h(),0))},[h]),S=r(()=>{let e=o.current;console.log(`Starting all uploads`,e);let t=e.filter(e=>e.state.status===`idle`),r=n-u.current.size,i=t.slice(0,r);for(let e of i)console.log(`Starting next upload`,e),h()},[n,h]),C=r(()=>{o.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(),a(e=>{let t=e.map(e=>e.state.status===`uploading`?{...e,state:{...e.state,status:`aborted`}}:e);return o.current=t,t})},[]);return{state:g,items:i,addFiles:_,removeItem:v,removeFile:v,startAll:S,abortUpload:y,abortAll:C,retryUpload:x,retryFailed:r(()=>{let e=o.current.filter(e=>[`error`,`aborted`].includes(e.state.status));e.length>0&&(a(t=>{let n=t.map(t=>e.some(e=>e.id===t.id)?{...t,state:{...t.state,status:`idle`,error:null}}:t);return o.current=n,n}),setTimeout(S,0))},[S]),clearCompleted:r(()=>{a(e=>{let t=e.filter(e=>![`success`,`error`,`aborted`].includes(e.state.status));return o.current=t,t})},[]),clearAll:r(()=>{C(),a([]),o.current=[],u.current.clear()},[C]),getItemsByStatus:r(e=>o.current.filter(t=>t.state.status===e),[]),metrics:{getInsights:()=>t.client.getChunkingInsights(),exportMetrics:()=>t.client.exportMetrics(),getNetworkMetrics:()=>t.client.getNetworkMetrics(),getNetworkCondition:()=>t.client.getNetworkCondition(),resetMetrics:()=>t.client.resetMetrics()}}}const D={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,result:null};function O(e={}){let t=b(),[n,i]=c(D),o=s(null);return a(()=>(o.current=new u((e,n)=>t.client.upload(e,n),{onStateChange:i,onProgress:e.onProgress,onChunkComplete:e.onChunkComplete,onSuccess:e.onSuccess,onError:e.onError,onAbort:e.onAbort},{metadata:e.metadata,uploadLengthDeferred:e.uploadLengthDeferred,uploadSize:e.uploadSize,onShouldRetry:e.onShouldRetry}),()=>{o.current?.cleanup()}),[t,e]),{state:n,upload:r(e=>{o.current?.upload(e)},[]),abort:r(()=>{o.current?.abort()},[]),reset:r(()=>{o.current?.reset()},[]),retry:r(()=>{o.current?.retry()},[]),isUploading:n.status===`uploading`,canRetry:o.current?.canRetry()??!1,metrics:{getInsights:()=>t.client.getChunkingInsights(),exportMetrics:()=>t.client.exportMetrics(),getNetworkMetrics:()=>t.client.getNetworkMetrics(),getNetworkCondition:()=>t.client.getNetworkCondition(),resetMetrics:()=>t.client.resetMetrics()}}}export{x as a,_ as c,C as i,h as l,E as n,y as o,T as r,b as s,O as t,g as u};
2
- //# sourceMappingURL=use-upload-DSYzF2Et.mjs.map