@uploadista/react 0.0.15-beta.2 → 0.0.15-beta.4
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 +3 -3
- package/dist/hooks/index.mjs +1 -1
- package/dist/index.d.mts +76 -4
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1 -1
- package/dist/{upload-zone-DFStubbe.mjs → upload-zone-pXt4LdcC.mjs} +2 -2
- package/dist/{upload-zone-DFStubbe.mjs.map → upload-zone-pXt4LdcC.mjs.map} +1 -1
- package/dist/{uploadista-provider-CrS6TmpJ.d.mts → uploadista-provider-k2P1_Ms-.d.mts} +4 -8
- package/dist/uploadista-provider-k2P1_Ms-.d.mts.map +1 -0
- package/dist/use-upload-DSYzF2Et.mjs +2 -0
- package/dist/use-upload-DSYzF2Et.mjs.map +1 -0
- package/dist/use-upload-metrics-DFVcWvCk.mjs +2 -0
- package/dist/use-upload-metrics-DFVcWvCk.mjs.map +1 -0
- package/dist/{use-upload-metrics-IXxUORce.d.mts → use-upload-metrics-Vho0Lzmq.d.mts} +250 -4
- package/dist/use-upload-metrics-Vho0Lzmq.d.mts.map +1 -0
- package/dist/{use-uploadista-client--ivZPO88.d.mts → use-uploadista-client-CRUhyWoy.d.mts} +5 -5
- package/dist/use-uploadista-client-CRUhyWoy.d.mts.map +1 -0
- package/package.json +5 -5
- package/src/components/uploadista-provider.tsx +16 -31
- package/src/contexts/flow-manager-context.tsx +230 -0
- package/src/hooks/event-utils.ts +44 -0
- package/src/hooks/index.ts +16 -0
- package/src/hooks/use-flow-events.ts +140 -0
- package/src/hooks/use-flow-upload.ts +47 -112
- package/src/hooks/use-upload-events.ts +195 -0
- package/src/hooks/use-uploadista-client.ts +1 -0
- package/src/hooks/use-uploadista-events.ts +41 -0
- package/src/index.ts +22 -0
- package/dist/uploadista-provider-CrS6TmpJ.d.mts.map +0 -1
- package/dist/use-upload-BNiPsNBv.mjs +0 -2
- package/dist/use-upload-BNiPsNBv.mjs.map +0 -1
- package/dist/use-upload-metrics-C1amBY1k.mjs +0 -2
- package/dist/use-upload-metrics-C1amBY1k.mjs.map +0 -1
- package/dist/use-upload-metrics-IXxUORce.d.mts.map +0 -1
- package/dist/use-uploadista-client--ivZPO88.d.mts.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BrowserUploadInput, FlowUploadOptions, UploadistaClientOptions, createUploadistaClient } from "@uploadista/client-browser";
|
|
2
|
-
import { FlowUploadState, FlowUploadStatus, UploadMetrics, UploadState, UploadStatus } from "@uploadista/client-core";
|
|
3
1
|
import { UploadFile } from "@uploadista/core/types";
|
|
2
|
+
import { FlowUploadState, FlowUploadStatus, UploadMetrics, UploadState, UploadStatus } from "@uploadista/client-core";
|
|
3
|
+
import { BrowserUploadInput, FlowUploadOptions, UploadistaClientOptions, createUploadistaClient } from "@uploadista/client-browser";
|
|
4
4
|
|
|
5
5
|
//#region src/hooks/use-drag-drop.d.ts
|
|
6
6
|
interface DragDropOptions {
|
|
@@ -209,8 +209,8 @@ interface UseFlowUploadReturn<TOutput = UploadFile> {
|
|
|
209
209
|
* The flow engine processes the uploaded file through a DAG of nodes, which can
|
|
210
210
|
* perform operations like image optimization, storage saving, webhooks, etc.
|
|
211
211
|
*
|
|
212
|
-
* Must be used within
|
|
213
|
-
* are automatically
|
|
212
|
+
* Must be used within FlowManagerProvider (which must be within UploadistaProvider).
|
|
213
|
+
* Flow events are automatically routed by the provider to the appropriate manager.
|
|
214
214
|
*
|
|
215
215
|
* @template TOutput - Type of the final result from the flow (defaults to UploadFile)
|
|
216
216
|
* @param options - Flow upload configuration including flow ID and event handlers
|
|
@@ -684,4 +684,4 @@ interface UseUploadistaClientReturn {
|
|
|
684
684
|
declare function useUploadistaClient(options: UseUploadistaClientOptions): UseUploadistaClientReturn;
|
|
685
685
|
//#endregion
|
|
686
686
|
export { useFlowUpload as _, MultiUploadState as a, UseDragDropReturn as b, useMultiUpload as c, UseUploadOptions as d, UseUploadReturn as f, UseFlowUploadReturn as g, FlowUploadStatus as h, MultiUploadOptions as i, UploadState as l, FlowUploadState as m, UseUploadistaClientReturn as n, UploadItem as o, useUpload as p, useUploadistaClient as r, UseMultiUploadReturn as s, UseUploadistaClientOptions as t, UploadStatus as u, DragDropOptions as v, useDragDrop as x, DragDropState as y };
|
|
687
|
-
//# sourceMappingURL=use-uploadista-client
|
|
687
|
+
//# sourceMappingURL=use-uploadista-client-CRUhyWoy.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-uploadista-client-CRUhyWoy.d.mts","names":[],"sources":["../src/hooks/use-drag-drop.ts","../src/hooks/use-flow-upload.ts","../src/hooks/use-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-uploadista-client.ts"],"sourcesContent":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uploadista/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.15-beta.
|
|
4
|
+
"version": "0.0.15-beta.4",
|
|
5
5
|
"description": "React client for Uploadista",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Uploadista",
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"react": "19.2.0",
|
|
24
24
|
"react-dom": "19.2.0",
|
|
25
|
-
"@uploadista/core": "0.0.15-beta.
|
|
26
|
-
"@uploadista/client-core": "0.0.15-beta.
|
|
27
|
-
"@uploadista/client-browser": "0.0.15-beta.
|
|
25
|
+
"@uploadista/core": "0.0.15-beta.4",
|
|
26
|
+
"@uploadista/client-core": "0.0.15-beta.4",
|
|
27
|
+
"@uploadista/client-browser": "0.0.15-beta.4"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/react": "19.2.4",
|
|
31
31
|
"@types/react-dom": "19.2.3",
|
|
32
32
|
"tsdown": "0.16.4",
|
|
33
33
|
"vitest": "4.0.8",
|
|
34
|
-
"@uploadista/typescript-config": "0.0.15-beta.
|
|
34
|
+
"@uploadista/typescript-config": "0.0.15-beta.4"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsdown",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { UploadistaEvent } from "@uploadista/client-browser";
|
|
3
3
|
import type React from "react";
|
|
4
4
|
import { createContext, useCallback, useContext, useMemo, useRef } from "react";
|
|
5
|
+
import { FlowManagerProvider } from "../contexts/flow-manager-context";
|
|
5
6
|
import {
|
|
6
7
|
type UseUploadistaClientOptions,
|
|
7
8
|
type UseUploadistaClientReturn,
|
|
@@ -16,10 +17,10 @@ import {
|
|
|
16
17
|
* @property baseUrl - API base URL for uploads
|
|
17
18
|
* @property storageId - Default storage identifier
|
|
18
19
|
* @property chunkSize - Upload chunk size in bytes
|
|
19
|
-
* @property onEvent - Global event handler for all upload events
|
|
20
20
|
* @property ... - All other UploadistaClientOptions
|
|
21
21
|
*/
|
|
22
|
-
export interface UploadistaProviderProps
|
|
22
|
+
export interface UploadistaProviderProps
|
|
23
|
+
extends Omit<UseUploadistaClientOptions, "onEvent"> {
|
|
23
24
|
/**
|
|
24
25
|
* Children components that will have access to the upload client
|
|
25
26
|
*/
|
|
@@ -53,9 +54,6 @@ const UploadistaContext = createContext<UploadistaContextValue | null>(null);
|
|
|
53
54
|
* baseUrl="https://api.example.com"
|
|
54
55
|
* storageId="my-storage"
|
|
55
56
|
* chunkSize={1024 * 1024} // 1MB chunks
|
|
56
|
-
* onEvent={(event) => {
|
|
57
|
-
* console.log('Global upload event:', event);
|
|
58
|
-
* }}
|
|
59
57
|
* >
|
|
60
58
|
* <UploadInterface />
|
|
61
59
|
* </UploadistaProvider>
|
|
@@ -89,34 +87,21 @@ export function UploadistaProvider({
|
|
|
89
87
|
new Set(),
|
|
90
88
|
);
|
|
91
89
|
|
|
92
|
-
//
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
eventSubscribersRef.current.size,
|
|
104
|
-
"subscribers",
|
|
105
|
-
);
|
|
106
|
-
eventSubscribersRef.current.forEach((handler) => {
|
|
107
|
-
try {
|
|
108
|
-
handler(event);
|
|
109
|
-
} catch (err) {
|
|
110
|
-
console.error("Error in event subscriber:", err);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
},
|
|
114
|
-
[options.onEvent],
|
|
115
|
-
);
|
|
90
|
+
// Event handler that broadcasts to all subscribers
|
|
91
|
+
const handleEvent = useCallback((event: UploadistaEvent) => {
|
|
92
|
+
// Broadcast to all subscribers
|
|
93
|
+
eventSubscribersRef.current.forEach((handler) => {
|
|
94
|
+
try {
|
|
95
|
+
handler(event);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error("Error in event subscriber:", err);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}, []);
|
|
116
101
|
|
|
117
102
|
const uploadClient = useUploadistaClient({
|
|
118
103
|
...options,
|
|
119
|
-
onEvent:
|
|
104
|
+
onEvent: handleEvent,
|
|
120
105
|
});
|
|
121
106
|
|
|
122
107
|
const subscribeToEvents = useCallback(
|
|
@@ -140,7 +125,7 @@ export function UploadistaProvider({
|
|
|
140
125
|
|
|
141
126
|
return (
|
|
142
127
|
<UploadistaContext.Provider value={contextValue}>
|
|
143
|
-
{children}
|
|
128
|
+
<FlowManagerProvider>{children}</FlowManagerProvider>
|
|
144
129
|
</UploadistaContext.Provider>
|
|
145
130
|
);
|
|
146
131
|
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type { UploadistaEvent } from "@uploadista/client-browser";
|
|
2
|
+
import {
|
|
3
|
+
FlowManager,
|
|
4
|
+
type FlowManagerCallbacks,
|
|
5
|
+
type FlowUploadState,
|
|
6
|
+
} from "@uploadista/client-core";
|
|
7
|
+
import { EventType, type FlowEvent } from "@uploadista/core/flow";
|
|
8
|
+
import { UploadEventType } from "@uploadista/core/types";
|
|
9
|
+
import type { ReactNode } from "react";
|
|
10
|
+
import {
|
|
11
|
+
createContext,
|
|
12
|
+
useCallback,
|
|
13
|
+
useContext,
|
|
14
|
+
useEffect,
|
|
15
|
+
useRef,
|
|
16
|
+
} from "react";
|
|
17
|
+
import { useUploadistaContext } from "../components/uploadista-provider";
|
|
18
|
+
import type { FlowUploadOptions } from "@uploadista/client-browser";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Type guard to check if an event is a flow event
|
|
22
|
+
*/
|
|
23
|
+
function isFlowEvent(event: UploadistaEvent): event is FlowEvent {
|
|
24
|
+
const flowEvent = event as FlowEvent;
|
|
25
|
+
return (
|
|
26
|
+
flowEvent.eventType === EventType.FlowStart ||
|
|
27
|
+
flowEvent.eventType === EventType.FlowEnd ||
|
|
28
|
+
flowEvent.eventType === EventType.FlowError ||
|
|
29
|
+
flowEvent.eventType === EventType.NodeStart ||
|
|
30
|
+
flowEvent.eventType === EventType.NodeEnd ||
|
|
31
|
+
flowEvent.eventType === EventType.NodePause ||
|
|
32
|
+
flowEvent.eventType === EventType.NodeResume ||
|
|
33
|
+
flowEvent.eventType === EventType.NodeError
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Internal manager registry entry with ref counting
|
|
39
|
+
*/
|
|
40
|
+
interface ManagerEntry<TOutput> {
|
|
41
|
+
manager: FlowManager<unknown, TOutput>;
|
|
42
|
+
refCount: number;
|
|
43
|
+
flowId: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Context value providing access to flow managers
|
|
48
|
+
*/
|
|
49
|
+
interface FlowManagerContextValue {
|
|
50
|
+
/**
|
|
51
|
+
* Get or create a flow manager for the given flow ID.
|
|
52
|
+
* Increments ref count - must call releaseManager when done.
|
|
53
|
+
*
|
|
54
|
+
* @param flowId - Unique identifier for the flow
|
|
55
|
+
* @param callbacks - Callbacks for state changes and lifecycle events
|
|
56
|
+
* @param options - Flow configuration options
|
|
57
|
+
* @returns FlowManager instance
|
|
58
|
+
*/
|
|
59
|
+
getManager: <TOutput = unknown>(
|
|
60
|
+
flowId: string,
|
|
61
|
+
callbacks: FlowManagerCallbacks<TOutput>,
|
|
62
|
+
options: FlowUploadOptions<TOutput>,
|
|
63
|
+
) => FlowManager<unknown, TOutput>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Release a flow manager reference.
|
|
67
|
+
* Decrements ref count and cleans up when reaching zero.
|
|
68
|
+
*
|
|
69
|
+
* @param flowId - Unique identifier for the flow to release
|
|
70
|
+
*/
|
|
71
|
+
releaseManager: (flowId: string) => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const FlowManagerContext = createContext<FlowManagerContextValue | undefined>(
|
|
75
|
+
undefined,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Props for FlowManagerProvider
|
|
80
|
+
*/
|
|
81
|
+
interface FlowManagerProviderProps {
|
|
82
|
+
children: ReactNode;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Provider that manages FlowManager instances with ref counting and event routing.
|
|
87
|
+
* Ensures managers persist across component re-renders and are only cleaned up
|
|
88
|
+
* when all consuming components unmount.
|
|
89
|
+
*
|
|
90
|
+
* This provider should be nested inside UploadistaProvider to access the upload client
|
|
91
|
+
* and event subscription system.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```tsx
|
|
95
|
+
* <UploadistaProvider baseUrl="https://api.example.com" storageId="default">
|
|
96
|
+
* <FlowManagerProvider>
|
|
97
|
+
* <App />
|
|
98
|
+
* </FlowManagerProvider>
|
|
99
|
+
* </UploadistaProvider>
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function FlowManagerProvider({ children }: FlowManagerProviderProps) {
|
|
103
|
+
const { client, subscribeToEvents } = useUploadistaContext();
|
|
104
|
+
const managersRef = useRef(
|
|
105
|
+
new Map<string, ManagerEntry<unknown>>(),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Subscribe to all events and route to appropriate managers
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
const unsubscribe = subscribeToEvents((event: UploadistaEvent) => {
|
|
111
|
+
// Route flow events to all managers (they filter by jobId internally)
|
|
112
|
+
if (isFlowEvent(event)) {
|
|
113
|
+
for (const entry of managersRef.current.values()) {
|
|
114
|
+
entry.manager.handleFlowEvent(event);
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Route upload progress events to all managers
|
|
120
|
+
if (
|
|
121
|
+
"type" in event &&
|
|
122
|
+
event.type === UploadEventType.UPLOAD_PROGRESS &&
|
|
123
|
+
"data" in event
|
|
124
|
+
) {
|
|
125
|
+
const uploadEvent = event as {
|
|
126
|
+
type: UploadEventType;
|
|
127
|
+
uploadId: string;
|
|
128
|
+
data: { progress: number; total: number | null };
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
for (const entry of managersRef.current.values()) {
|
|
132
|
+
entry.manager.handleUploadProgress(
|
|
133
|
+
uploadEvent.uploadId,
|
|
134
|
+
uploadEvent.data.progress,
|
|
135
|
+
uploadEvent.data.total,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return unsubscribe;
|
|
142
|
+
}, [subscribeToEvents]);
|
|
143
|
+
|
|
144
|
+
const getManager = useCallback(
|
|
145
|
+
<TOutput,>(
|
|
146
|
+
flowId: string,
|
|
147
|
+
callbacks: FlowManagerCallbacks<TOutput>,
|
|
148
|
+
options: FlowUploadOptions<TOutput>,
|
|
149
|
+
): FlowManager<unknown, TOutput> => {
|
|
150
|
+
const existing = managersRef.current.get(flowId);
|
|
151
|
+
|
|
152
|
+
if (existing) {
|
|
153
|
+
// Increment ref count for existing manager
|
|
154
|
+
existing.refCount++;
|
|
155
|
+
return existing.manager as FlowManager<unknown, TOutput>;
|
|
156
|
+
}
|
|
157
|
+
|
|
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,
|
|
169
|
+
callbacks,
|
|
170
|
+
options,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
managersRef.current.set(flowId, {
|
|
174
|
+
manager: manager as FlowManager<unknown, unknown>,
|
|
175
|
+
refCount: 1,
|
|
176
|
+
flowId,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return manager;
|
|
180
|
+
},
|
|
181
|
+
[client],
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const releaseManager = useCallback((flowId: string) => {
|
|
185
|
+
const existing = managersRef.current.get(flowId);
|
|
186
|
+
if (!existing) return;
|
|
187
|
+
|
|
188
|
+
existing.refCount--;
|
|
189
|
+
|
|
190
|
+
// Clean up when no more refs
|
|
191
|
+
if (existing.refCount <= 0) {
|
|
192
|
+
existing.manager.cleanup();
|
|
193
|
+
managersRef.current.delete(flowId);
|
|
194
|
+
}
|
|
195
|
+
}, []);
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<FlowManagerContext.Provider value={{ getManager, releaseManager }}>
|
|
199
|
+
{children}
|
|
200
|
+
</FlowManagerContext.Provider>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Hook to access the FlowManager context.
|
|
206
|
+
* Must be used within a FlowManagerProvider.
|
|
207
|
+
*
|
|
208
|
+
* @returns FlowManager context value with getManager and releaseManager functions
|
|
209
|
+
* @throws Error if used outside of FlowManagerProvider
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```tsx
|
|
213
|
+
* function MyComponent() {
|
|
214
|
+
* const { getManager, releaseManager } = useFlowManagerContext();
|
|
215
|
+
* // Use to create managers...
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export function useFlowManagerContext(): FlowManagerContextValue {
|
|
220
|
+
const context = useContext(FlowManagerContext);
|
|
221
|
+
|
|
222
|
+
if (context === undefined) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
"useFlowManagerContext must be used within a FlowManagerProvider. " +
|
|
225
|
+
"Make sure to wrap your component tree with <FlowManagerProvider>.",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return context;
|
|
230
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { UploadistaEvent } from "@uploadista/client-browser";
|
|
2
|
+
import { EventType, type FlowEvent } from "@uploadista/core/flow";
|
|
3
|
+
import { UploadEventType, type UploadEvent } from "@uploadista/core/types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Type guard to check if an event is a flow event
|
|
7
|
+
*/
|
|
8
|
+
export function isFlowEvent(event: UploadistaEvent): event is FlowEvent {
|
|
9
|
+
if (!("eventType" in event)) return false;
|
|
10
|
+
const e = event as { eventType: unknown };
|
|
11
|
+
return (
|
|
12
|
+
e.eventType === EventType.JobStart ||
|
|
13
|
+
e.eventType === EventType.JobEnd ||
|
|
14
|
+
e.eventType === EventType.FlowStart ||
|
|
15
|
+
e.eventType === EventType.FlowEnd ||
|
|
16
|
+
e.eventType === EventType.FlowError ||
|
|
17
|
+
e.eventType === EventType.FlowPause ||
|
|
18
|
+
e.eventType === EventType.FlowCancel ||
|
|
19
|
+
e.eventType === EventType.NodeStart ||
|
|
20
|
+
e.eventType === EventType.NodeEnd ||
|
|
21
|
+
e.eventType === EventType.NodePause ||
|
|
22
|
+
e.eventType === EventType.NodeResume ||
|
|
23
|
+
e.eventType === EventType.NodeError ||
|
|
24
|
+
e.eventType === EventType.NodeStream ||
|
|
25
|
+
e.eventType === EventType.NodeResponse
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Type guard to check if an event is an upload event
|
|
31
|
+
*/
|
|
32
|
+
export function isUploadEvent(event: UploadistaEvent): event is UploadEvent {
|
|
33
|
+
if (!("type" in event)) return false;
|
|
34
|
+
const e = event as { type: unknown };
|
|
35
|
+
return (
|
|
36
|
+
e.type === UploadEventType.UPLOAD_STARTED ||
|
|
37
|
+
e.type === UploadEventType.UPLOAD_PROGRESS ||
|
|
38
|
+
e.type === UploadEventType.UPLOAD_COMPLETE ||
|
|
39
|
+
e.type === UploadEventType.UPLOAD_FAILED ||
|
|
40
|
+
e.type === UploadEventType.UPLOAD_VALIDATION_SUCCESS ||
|
|
41
|
+
e.type === UploadEventType.UPLOAD_VALIDATION_FAILED ||
|
|
42
|
+
e.type === UploadEventType.UPLOAD_VALIDATION_WARNING
|
|
43
|
+
);
|
|
44
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
// Event Hooks
|
|
2
|
+
export { isFlowEvent, isUploadEvent } from "./event-utils";
|
|
3
|
+
export { useUploadistaEvents } from "./use-uploadista-events";
|
|
4
|
+
export type { UseFlowEventsOptions } from "./use-flow-events";
|
|
5
|
+
export { useFlowEvents } from "./use-flow-events";
|
|
6
|
+
export type {
|
|
7
|
+
UploadFailedEventData,
|
|
8
|
+
UploadFileEventData,
|
|
9
|
+
UploadProgressEventData,
|
|
10
|
+
UploadValidationFailedEventData,
|
|
11
|
+
UploadValidationSuccessEventData,
|
|
12
|
+
UploadValidationWarningEventData,
|
|
13
|
+
UseUploadEventsOptions,
|
|
14
|
+
} from "./use-upload-events";
|
|
15
|
+
export { useUploadEvents } from "./use-upload-events";
|
|
16
|
+
|
|
1
17
|
// Flow Upload Hooks
|
|
2
18
|
|
|
3
19
|
// Upload Hooks
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FlowEventFlowCancel,
|
|
3
|
+
FlowEventFlowEnd,
|
|
4
|
+
FlowEventFlowError,
|
|
5
|
+
FlowEventFlowPause,
|
|
6
|
+
FlowEventFlowStart,
|
|
7
|
+
FlowEventJobEnd,
|
|
8
|
+
FlowEventJobStart,
|
|
9
|
+
FlowEventNodeEnd,
|
|
10
|
+
FlowEventNodeError,
|
|
11
|
+
FlowEventNodePause,
|
|
12
|
+
FlowEventNodeResume,
|
|
13
|
+
FlowEventNodeStart,
|
|
14
|
+
} from "@uploadista/core/flow";
|
|
15
|
+
import { EventType } from "@uploadista/core/flow";
|
|
16
|
+
import { useEffect } from "react";
|
|
17
|
+
import { useUploadistaContext } from "../components/uploadista-provider";
|
|
18
|
+
import { isFlowEvent } from "./event-utils";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for handling flow execution events.
|
|
22
|
+
*
|
|
23
|
+
* All callbacks are optional - only provide handlers for events you care about.
|
|
24
|
+
*/
|
|
25
|
+
export interface UseFlowEventsOptions {
|
|
26
|
+
/** Called when a job starts execution */
|
|
27
|
+
onJobStart?: (event: FlowEventJobStart) => void;
|
|
28
|
+
/** Called when a job completes (success or failure) */
|
|
29
|
+
onJobEnd?: (event: FlowEventJobEnd) => void;
|
|
30
|
+
/** Called when a flow begins execution */
|
|
31
|
+
onFlowStart?: (event: FlowEventFlowStart) => void;
|
|
32
|
+
/** Called when a flow completes successfully */
|
|
33
|
+
onFlowEnd?: (event: FlowEventFlowEnd) => void;
|
|
34
|
+
/** Called when a flow encounters an error */
|
|
35
|
+
onFlowError?: (event: FlowEventFlowError) => void;
|
|
36
|
+
/** Called when a flow is paused by user request */
|
|
37
|
+
onFlowPause?: (event: FlowEventFlowPause) => void;
|
|
38
|
+
/** Called when a flow is cancelled by user request */
|
|
39
|
+
onFlowCancel?: (event: FlowEventFlowCancel) => void;
|
|
40
|
+
/** Called when a node starts processing */
|
|
41
|
+
onNodeStart?: (event: FlowEventNodeStart) => void;
|
|
42
|
+
/** Called when a node completes successfully */
|
|
43
|
+
onNodeEnd?: (event: FlowEventNodeEnd) => void;
|
|
44
|
+
/** Called when a node pauses (waiting for additional data) */
|
|
45
|
+
onNodePause?: (event: FlowEventNodePause) => void;
|
|
46
|
+
/** Called when a paused node resumes execution */
|
|
47
|
+
onNodeResume?: (event: FlowEventNodeResume) => void;
|
|
48
|
+
/** Called when a node encounters an error */
|
|
49
|
+
onNodeError?: (event: FlowEventNodeError) => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Structured hook for handling flow execution events with type-safe callbacks.
|
|
54
|
+
*
|
|
55
|
+
* This hook provides a clean API for listening to specific flow events without
|
|
56
|
+
* needing to manually filter events or use type guards.
|
|
57
|
+
*
|
|
58
|
+
* Must be used within UploadistaProvider.
|
|
59
|
+
*
|
|
60
|
+
* @param options - Object with optional callbacks for each flow event type
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* import { useFlowEvents } from '@uploadista/react';
|
|
65
|
+
*
|
|
66
|
+
* function FlowMonitor() {
|
|
67
|
+
* useFlowEvents({
|
|
68
|
+
* onFlowStart: (event) => {
|
|
69
|
+
* console.log('Flow started:', event.flowId);
|
|
70
|
+
* },
|
|
71
|
+
* onNodeStart: (event) => {
|
|
72
|
+
* console.log('Node started:', event.nodeName);
|
|
73
|
+
* },
|
|
74
|
+
* onNodeEnd: (event) => {
|
|
75
|
+
* console.log('Node completed:', event.nodeName, event.result);
|
|
76
|
+
* },
|
|
77
|
+
* onFlowEnd: (event) => {
|
|
78
|
+
* console.log('Flow completed with outputs:', event.outputs);
|
|
79
|
+
* },
|
|
80
|
+
* onFlowError: (event) => {
|
|
81
|
+
* console.error('Flow failed:', event.error);
|
|
82
|
+
* },
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* return <div>Monitoring flow execution...</div>;
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export function useFlowEvents(options: UseFlowEventsOptions): void {
|
|
90
|
+
const { subscribeToEvents } = useUploadistaContext();
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const unsubscribe = subscribeToEvents((event) => {
|
|
94
|
+
// Only handle flow events
|
|
95
|
+
if (!isFlowEvent(event)) return;
|
|
96
|
+
|
|
97
|
+
// Route to appropriate callback based on event type
|
|
98
|
+
switch (event.eventType) {
|
|
99
|
+
case EventType.JobStart:
|
|
100
|
+
options.onJobStart?.(event);
|
|
101
|
+
break;
|
|
102
|
+
case EventType.JobEnd:
|
|
103
|
+
options.onJobEnd?.(event);
|
|
104
|
+
break;
|
|
105
|
+
case EventType.FlowStart:
|
|
106
|
+
options.onFlowStart?.(event);
|
|
107
|
+
break;
|
|
108
|
+
case EventType.FlowEnd:
|
|
109
|
+
options.onFlowEnd?.(event);
|
|
110
|
+
break;
|
|
111
|
+
case EventType.FlowError:
|
|
112
|
+
options.onFlowError?.(event);
|
|
113
|
+
break;
|
|
114
|
+
case EventType.FlowPause:
|
|
115
|
+
options.onFlowPause?.(event);
|
|
116
|
+
break;
|
|
117
|
+
case EventType.FlowCancel:
|
|
118
|
+
options.onFlowCancel?.(event);
|
|
119
|
+
break;
|
|
120
|
+
case EventType.NodeStart:
|
|
121
|
+
options.onNodeStart?.(event);
|
|
122
|
+
break;
|
|
123
|
+
case EventType.NodeEnd:
|
|
124
|
+
options.onNodeEnd?.(event);
|
|
125
|
+
break;
|
|
126
|
+
case EventType.NodePause:
|
|
127
|
+
options.onNodePause?.(event);
|
|
128
|
+
break;
|
|
129
|
+
case EventType.NodeResume:
|
|
130
|
+
options.onNodeResume?.(event);
|
|
131
|
+
break;
|
|
132
|
+
case EventType.NodeError:
|
|
133
|
+
options.onNodeError?.(event);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return unsubscribe;
|
|
139
|
+
}, [subscribeToEvents, options]);
|
|
140
|
+
}
|