@computekit/react 0.1.0 → 0.1.2
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 +298 -0
- package/dist/index.cjs +21 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +21 -7
- package/dist/index.js.map +1 -1
- package/package.json +10 -3
- package/src/index.tsx +25 -4
package/README.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# @computekit/react
|
|
2
|
+
|
|
3
|
+
React bindings for ComputeKit - run heavy computations in Web Workers with simple hooks.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @computekit/core @computekit/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { ComputeKitProvider, useComputeKit, useCompute } from '@computekit/react';
|
|
15
|
+
|
|
16
|
+
// 1. Wrap your app with the provider
|
|
17
|
+
function App() {
|
|
18
|
+
return (
|
|
19
|
+
<ComputeKitProvider options={{ maxWorkers: 4 }}>
|
|
20
|
+
<MyApp />
|
|
21
|
+
</ComputeKitProvider>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 2. Register functions and use them
|
|
26
|
+
function MyApp() {
|
|
27
|
+
const kit = useComputeKit();
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
kit.register('fibonacci', (n: number) => {
|
|
31
|
+
let a = 0,
|
|
32
|
+
b = 1;
|
|
33
|
+
for (let i = 0; i < n; i++) {
|
|
34
|
+
[a, b] = [b, a + b];
|
|
35
|
+
}
|
|
36
|
+
return a;
|
|
37
|
+
});
|
|
38
|
+
}, [kit]);
|
|
39
|
+
|
|
40
|
+
return <FibCalculator />;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 3. Use the compute function
|
|
44
|
+
function FibCalculator() {
|
|
45
|
+
const { data, loading, error, run } = useCompute<number, number>('fibonacci');
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div>
|
|
49
|
+
<button onClick={() => run(50)} disabled={loading}>
|
|
50
|
+
Calculate Fibonacci(50)
|
|
51
|
+
</button>
|
|
52
|
+
{loading && <p>Computing...</p>}
|
|
53
|
+
{error && <p>Error: {error.message}</p>}
|
|
54
|
+
{data !== null && <p>Result: {data}</p>}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API Reference
|
|
61
|
+
|
|
62
|
+
### `<ComputeKitProvider>`
|
|
63
|
+
|
|
64
|
+
Provider component that creates and manages the ComputeKit instance.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<ComputeKitProvider
|
|
68
|
+
options={{
|
|
69
|
+
maxWorkers: 4, // Max workers in pool (default: CPU cores)
|
|
70
|
+
timeout: 30000, // Default timeout in ms
|
|
71
|
+
debug: false, // Enable debug logging
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
{children}
|
|
75
|
+
</ComputeKitProvider>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Props:**
|
|
79
|
+
|
|
80
|
+
| Prop | Type | Description |
|
|
81
|
+
| ---------- | ------------------- | ------------------------------------- |
|
|
82
|
+
| `options` | `ComputeKitOptions` | Configuration options |
|
|
83
|
+
| `instance` | `ComputeKit` | Custom ComputeKit instance (optional) |
|
|
84
|
+
| `children` | `ReactNode` | Child components |
|
|
85
|
+
|
|
86
|
+
### `useComputeKit()`
|
|
87
|
+
|
|
88
|
+
Get the ComputeKit instance from context.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
const kit = useComputeKit();
|
|
92
|
+
|
|
93
|
+
// Register functions
|
|
94
|
+
kit.register('myFunc', (input) => /* ... */);
|
|
95
|
+
|
|
96
|
+
// Run directly
|
|
97
|
+
const result = await kit.run('myFunc', data);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `useCompute<TInput, TOutput>(name, options?)`
|
|
101
|
+
|
|
102
|
+
Hook for running compute functions with full state management.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
const {
|
|
106
|
+
data, // Result (null until complete)
|
|
107
|
+
loading, // Boolean loading state
|
|
108
|
+
error, // Error object if failed
|
|
109
|
+
progress, // Progress info for long tasks
|
|
110
|
+
status, // 'idle' | 'running' | 'success' | 'error' | 'cancelled'
|
|
111
|
+
run, // Function to execute
|
|
112
|
+
reset, // Reset state
|
|
113
|
+
cancel, // Cancel ongoing computation
|
|
114
|
+
} = useCompute<number, number>('fibonacci');
|
|
115
|
+
|
|
116
|
+
// Execute
|
|
117
|
+
await run(50);
|
|
118
|
+
|
|
119
|
+
// With options
|
|
120
|
+
await run(50, { timeout: 5000 });
|
|
121
|
+
|
|
122
|
+
// React to status changes
|
|
123
|
+
if (status === 'success') {
|
|
124
|
+
console.log('Completed!', data);
|
|
125
|
+
} else if (status === 'error') {
|
|
126
|
+
console.error('Failed:', error);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Status values:**
|
|
131
|
+
|
|
132
|
+
| Status | Description |
|
|
133
|
+
| ----------- | ----------------------------------- |
|
|
134
|
+
| `idle` | Initial state, no computation yet |
|
|
135
|
+
| `running` | Computation in progress |
|
|
136
|
+
| `success` | Completed successfully |
|
|
137
|
+
| `error` | Failed with an error |
|
|
138
|
+
| `cancelled` | Cancelled via `cancel()` or unmount |
|
|
139
|
+
|
|
140
|
+
**Options:**
|
|
141
|
+
|
|
142
|
+
| Option | Type | Description |
|
|
143
|
+
| -------------- | -------------------- | -------------------------------------- |
|
|
144
|
+
| `timeout` | `number` | Operation timeout in ms |
|
|
145
|
+
| `autoRun` | `boolean` | Auto-run on mount |
|
|
146
|
+
| `initialInput` | `unknown` | Input for autoRun |
|
|
147
|
+
| `resetOnRun` | `boolean` | Reset state on new run (default: true) |
|
|
148
|
+
| `onProgress` | `(progress) => void` | Progress callback |
|
|
149
|
+
|
|
150
|
+
### `useComputeCallback<TInput, TOutput>(name, options?)`
|
|
151
|
+
|
|
152
|
+
Returns a memoized async function for simple use cases.
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
const calculate = useComputeCallback<number[], number>('sum');
|
|
156
|
+
|
|
157
|
+
const handleClick = async () => {
|
|
158
|
+
const result = await calculate([1, 2, 3, 4, 5]);
|
|
159
|
+
console.log(result); // 15
|
|
160
|
+
};
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### `useComputeFunction<TInput, TOutput>(name, fn, options?)`
|
|
164
|
+
|
|
165
|
+
Register and use a function in one hook. Useful for component-local compute functions.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
const { data, loading, run } = useComputeFunction('double', (n: number) => n * 2);
|
|
169
|
+
|
|
170
|
+
// Function is registered automatically
|
|
171
|
+
run(21); // data will be 42
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `usePoolStats(refreshInterval?)`
|
|
175
|
+
|
|
176
|
+
Get worker pool statistics.
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
const stats = usePoolStats(1000); // Refresh every second
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<div>
|
|
183
|
+
<p>
|
|
184
|
+
Active: {stats.activeWorkers}/{stats.totalWorkers}
|
|
185
|
+
</p>
|
|
186
|
+
<p>Queue: {stats.queueLength}</p>
|
|
187
|
+
<p>Completed: {stats.tasksCompleted}</p>
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Returns `PoolStats`:**
|
|
193
|
+
|
|
194
|
+
| Property | Type | Description |
|
|
195
|
+
| ---------------- | -------- | ---------------------- |
|
|
196
|
+
| `totalWorkers` | `number` | Total worker count |
|
|
197
|
+
| `activeWorkers` | `number` | Currently busy workers |
|
|
198
|
+
| `idleWorkers` | `number` | Currently idle workers |
|
|
199
|
+
| `queueLength` | `number` | Tasks waiting in queue |
|
|
200
|
+
| `tasksCompleted` | `number` | Total completed tasks |
|
|
201
|
+
| `tasksFailed` | `number` | Total failed tasks |
|
|
202
|
+
|
|
203
|
+
### `useWasmSupport()`
|
|
204
|
+
|
|
205
|
+
Check if WebAssembly is supported.
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
const isSupported = useWasmSupport();
|
|
209
|
+
|
|
210
|
+
if (!isSupported) {
|
|
211
|
+
return <p>WebAssembly not supported</p>;
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Patterns
|
|
216
|
+
|
|
217
|
+
### Cancellation on Unmount
|
|
218
|
+
|
|
219
|
+
The `useCompute` hook automatically cancels pending operations when the component unmounts:
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
function MyComponent() {
|
|
223
|
+
const { run, loading } = useCompute('heavyTask');
|
|
224
|
+
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
run(data); // Automatically cancelled if component unmounts
|
|
227
|
+
}, []);
|
|
228
|
+
|
|
229
|
+
// ...
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Manual Cancellation
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
function MyComponent() {
|
|
237
|
+
const { run, cancel, loading } = useCompute('heavyTask');
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<>
|
|
241
|
+
<button onClick={() => run(data)}>Start</button>
|
|
242
|
+
<button onClick={cancel} disabled={!loading}>
|
|
243
|
+
Cancel
|
|
244
|
+
</button>
|
|
245
|
+
</>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Progress Tracking
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
function MyComponent() {
|
|
254
|
+
const { run, progress, loading } = useCompute('heavyTask', {
|
|
255
|
+
onProgress: (p) => console.log(`${p.percent}%`),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
return (
|
|
259
|
+
<div>{loading && progress && <progress value={progress.percent} max={100} />}</div>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### With AbortController
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
function MyComponent() {
|
|
268
|
+
const controller = useRef(new AbortController());
|
|
269
|
+
const { run } = useCompute('task');
|
|
270
|
+
|
|
271
|
+
const handleRun = () => {
|
|
272
|
+
run(data, { signal: controller.current.signal });
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const handleCancel = () => {
|
|
276
|
+
controller.current.abort();
|
|
277
|
+
controller.current = new AbortController();
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## TypeScript
|
|
283
|
+
|
|
284
|
+
Full type inference is supported:
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
// Types are inferred from registration
|
|
288
|
+
kit.register('add', (nums: number[]) => nums.reduce((a, b) => a + b, 0));
|
|
289
|
+
|
|
290
|
+
// Explicit types for hooks
|
|
291
|
+
const { data, run } = useCompute<number[], number>('add');
|
|
292
|
+
// data: number | null
|
|
293
|
+
// run: (input: number[]) => Promise<void>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## License
|
|
297
|
+
|
|
298
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -33,29 +33,40 @@ function useComputeKit() {
|
|
|
33
33
|
function useCompute(functionName, options = {}) {
|
|
34
34
|
const kit = useComputeKit();
|
|
35
35
|
const abortControllerRef = react.useRef(null);
|
|
36
|
+
const cancelledRef = react.useRef(false);
|
|
36
37
|
const [state, setState] = react.useState({
|
|
37
38
|
data: null,
|
|
38
39
|
loading: false,
|
|
39
40
|
error: null,
|
|
40
|
-
progress: null
|
|
41
|
+
progress: null,
|
|
42
|
+
status: "idle"
|
|
41
43
|
});
|
|
42
44
|
const reset = react.useCallback(() => {
|
|
45
|
+
cancelledRef.current = false;
|
|
43
46
|
setState({
|
|
44
47
|
data: null,
|
|
45
48
|
loading: false,
|
|
46
49
|
error: null,
|
|
47
|
-
progress: null
|
|
50
|
+
progress: null,
|
|
51
|
+
status: "idle"
|
|
48
52
|
});
|
|
49
53
|
}, []);
|
|
50
54
|
const cancel = react.useCallback(() => {
|
|
51
55
|
if (abortControllerRef.current) {
|
|
56
|
+
cancelledRef.current = true;
|
|
52
57
|
abortControllerRef.current.abort();
|
|
53
58
|
abortControllerRef.current = null;
|
|
59
|
+
setState((prev) => ({
|
|
60
|
+
...prev,
|
|
61
|
+
loading: false,
|
|
62
|
+
status: "cancelled"
|
|
63
|
+
}));
|
|
54
64
|
}
|
|
55
65
|
}, []);
|
|
56
66
|
const run = react.useCallback(
|
|
57
67
|
async (input, runOptions) => {
|
|
58
68
|
cancel();
|
|
69
|
+
cancelledRef.current = false;
|
|
59
70
|
const abortController = new AbortController();
|
|
60
71
|
abortControllerRef.current = abortController;
|
|
61
72
|
if (options.resetOnRun !== false) {
|
|
@@ -63,10 +74,11 @@ function useCompute(functionName, options = {}) {
|
|
|
63
74
|
...prev,
|
|
64
75
|
loading: true,
|
|
65
76
|
error: null,
|
|
66
|
-
progress: null
|
|
77
|
+
progress: null,
|
|
78
|
+
status: "running"
|
|
67
79
|
}));
|
|
68
80
|
} else {
|
|
69
|
-
setState((prev) => ({ ...prev, loading: true }));
|
|
81
|
+
setState((prev) => ({ ...prev, loading: true, status: "running" }));
|
|
70
82
|
}
|
|
71
83
|
try {
|
|
72
84
|
const result = await kit.run(functionName, input, {
|
|
@@ -84,16 +96,18 @@ function useCompute(functionName, options = {}) {
|
|
|
84
96
|
data: result,
|
|
85
97
|
loading: false,
|
|
86
98
|
error: null,
|
|
87
|
-
progress: null
|
|
99
|
+
progress: null,
|
|
100
|
+
status: "success"
|
|
88
101
|
});
|
|
89
102
|
}
|
|
90
103
|
} catch (err) {
|
|
91
|
-
if (!abortController.signal.aborted) {
|
|
104
|
+
if (!abortController.signal.aborted && !cancelledRef.current) {
|
|
92
105
|
setState({
|
|
93
106
|
data: null,
|
|
94
107
|
loading: false,
|
|
95
108
|
error: err instanceof Error ? err : new Error(String(err)),
|
|
96
|
-
progress: null
|
|
109
|
+
progress: null,
|
|
110
|
+
status: "error"
|
|
97
111
|
});
|
|
98
112
|
}
|
|
99
113
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"names":["createContext","useMemo","ComputeKit","useEffect","useContext","useRef","useState","useCallback"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ComputeKit React Bindings\n * React hooks and utilities for ComputeKit\n */\n\nimport {\n useState,\n useEffect,\n useCallback,\n useRef,\n useMemo,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\n\nimport {\n ComputeKit,\n type ComputeKitOptions,\n type ComputeOptions,\n type ComputeProgress,\n type PoolStats,\n} from '@computekit/core';\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst ComputeKitContext = createContext<ComputeKit | null>(null);\n\n/**\n * Props for ComputeKitProvider\n */\nexport interface ComputeKitProviderProps {\n /** ComputeKit options */\n options?: ComputeKitOptions;\n /** Custom ComputeKit instance */\n instance?: ComputeKit;\n /** Children */\n children: ReactNode;\n}\n\n/**\n * Provider component for ComputeKit\n *\n * @example\n * ```tsx\n * import { ComputeKitProvider } from '@computekit/react';\n *\n * function App() {\n * return (\n * <ComputeKitProvider options={{ maxWorkers: 4 }}>\n * <MyApp />\n * </ComputeKitProvider>\n * );\n * }\n * ```\n */\nexport function ComputeKitProvider({\n options,\n instance,\n children,\n}: ComputeKitProviderProps): JSX.Element {\n const kit = useMemo(() => {\n return instance ?? new ComputeKit(options);\n }, [instance, options]);\n\n useEffect(() => {\n return () => {\n // Only terminate if we created the instance\n if (!instance) {\n kit.terminate();\n }\n };\n }, [kit, instance]);\n\n return <ComputeKitContext.Provider value={kit}>{children}</ComputeKitContext.Provider>;\n}\n\n/**\n * Get the ComputeKit instance from context\n */\nexport function useComputeKit(): ComputeKit {\n const kit = useContext(ComputeKitContext);\n if (!kit) {\n throw new Error('useComputeKit must be used within a ComputeKitProvider');\n }\n return kit;\n}\n\n// ============================================================================\n// useCompute Hook\n// ============================================================================\n\n/**\n * State returned by useCompute\n */\nexport interface UseComputeState<T> {\n /** The computed result */\n data: T | null;\n /** Loading state */\n loading: boolean;\n /** Error if computation failed */\n error: Error | null;\n /** Progress information */\n progress: ComputeProgress | null;\n}\n\n/**\n * Actions returned by useCompute\n */\nexport interface UseComputeActions<TInput> {\n /** Execute the compute function */\n run: (input: TInput, options?: ComputeOptions) => Promise<void>;\n /** Reset the state */\n reset: () => void;\n /** Cancel ongoing computation */\n cancel: () => void;\n}\n\n/**\n * Return type for useCompute\n */\nexport type UseComputeReturn<TInput, TOutput> = UseComputeState<TOutput> &\n UseComputeActions<TInput>;\n\n/**\n * Options for useCompute hook\n */\nexport interface UseComputeOptions extends ComputeOptions {\n /** Automatically run on mount with initial input */\n autoRun?: boolean;\n /** Initial input for autoRun */\n initialInput?: unknown;\n /** Reset state on new run */\n resetOnRun?: boolean;\n}\n\n/**\n * Hook for running compute functions\n *\n * @example\n * ```tsx\n * function FibonacciCalculator() {\n * const { data, loading, error, run } = useCompute<number, number>('fibonacci');\n *\n * return (\n * <div>\n * <button onClick={() => run(50)} disabled={loading}>\n * Calculate Fibonacci(50)\n * </button>\n * {loading && <p>Computing...</p>}\n * {error && <p>Error: {error.message}</p>}\n * {data !== null && <p>Result: {data}</p>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useCompute<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options: UseComputeOptions = {}\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const [state, setState] = useState<UseComputeState<TOutput>>({\n data: null,\n loading: false,\n error: null,\n progress: null,\n });\n\n const reset = useCallback(() => {\n setState({\n data: null,\n loading: false,\n error: null,\n progress: null,\n });\n }, []);\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n }, []);\n\n const run = useCallback(\n async (input: TInput, runOptions?: ComputeOptions) => {\n // Cancel any ongoing computation\n cancel();\n\n // Create new abort controller\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n // Reset state if configured\n if (options.resetOnRun !== false) {\n setState((prev) => ({\n ...prev,\n loading: true,\n error: null,\n progress: null,\n }));\n } else {\n setState((prev) => ({ ...prev, loading: true }));\n }\n\n try {\n const result = await kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n signal: runOptions?.signal ?? abortController.signal,\n onProgress: (progress) => {\n setState((prev) => ({ ...prev, progress }));\n options.onProgress?.(progress);\n runOptions?.onProgress?.(progress);\n },\n });\n\n if (!abortController.signal.aborted) {\n setState({\n data: result,\n loading: false,\n error: null,\n progress: null,\n });\n }\n } catch (err) {\n if (!abortController.signal.aborted) {\n setState({\n data: null,\n loading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n progress: null,\n });\n }\n }\n },\n [kit, functionName, options, cancel]\n );\n\n // Auto-run on mount if configured\n useEffect(() => {\n if (options.autoRun && options.initialInput !== undefined) {\n run(options.initialInput as TInput);\n }\n // Only run on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n cancel();\n };\n }, [cancel]);\n\n return {\n ...state,\n run,\n reset,\n cancel,\n };\n}\n\n// ============================================================================\n// useComputeCallback Hook\n// ============================================================================\n\n/**\n * Hook that returns a memoized async function for compute operations\n *\n * @example\n * ```tsx\n * function Calculator() {\n * const calculate = useComputeCallback<number[], number>('sum');\n *\n * const handleClick = async () => {\n * const result = await calculate([1, 2, 3, 4, 5]);\n * console.log(result);\n * };\n *\n * return <button onClick={handleClick}>Calculate Sum</button>;\n * }\n * ```\n */\nexport function useComputeCallback<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options?: ComputeOptions\n): (input: TInput, runOptions?: ComputeOptions) => Promise<TOutput> {\n const kit = useComputeKit();\n\n return useCallback(\n (input: TInput, runOptions?: ComputeOptions) => {\n return kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n });\n },\n [kit, functionName, options]\n );\n}\n\n// ============================================================================\n// useComputeFunction Hook\n// ============================================================================\n\n/**\n * Hook to register and use a compute function\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { run, loading, data } = useComputeFunction(\n * 'myFunction',\n * (input: number) => input * 2\n * );\n *\n * return (\n * <button onClick={() => run(5)} disabled={loading}>\n * {loading ? 'Computing...' : `Result: ${data}`}\n * </button>\n * );\n * }\n * ```\n */\nexport function useComputeFunction<TInput = unknown, TOutput = unknown>(\n name: string,\n fn: (input: TInput) => TOutput | Promise<TOutput>,\n options?: UseComputeOptions\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n\n // Register function on mount\n useEffect(() => {\n kit.register(name, fn);\n }, [kit, name, fn]);\n\n return useCompute<TInput, TOutput>(name, options);\n}\n\n// ============================================================================\n// usePoolStats Hook\n// ============================================================================\n\n/**\n * Hook to get worker pool statistics\n *\n * @example\n * ```tsx\n * function PoolMonitor() {\n * const stats = usePoolStats(1000); // Update every second\n *\n * return (\n * <div>\n * <p>Active Workers: {stats.activeWorkers}</p>\n * <p>Queue Length: {stats.queueLength}</p>\n * <p>Tasks Completed: {stats.tasksCompleted}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePoolStats(refreshInterval: number = 0): PoolStats {\n const kit = useComputeKit();\n const [stats, setStats] = useState<PoolStats>(() => kit.getStats());\n\n useEffect(() => {\n // For one-time fetch (refreshInterval <= 0), we rely on the initial state\n if (refreshInterval <= 0) {\n return;\n }\n\n const interval = setInterval(() => {\n setStats(kit.getStats());\n }, refreshInterval);\n\n return () => clearInterval(interval);\n }, [kit, refreshInterval]);\n\n return stats;\n}\n\n// ============================================================================\n// useWasmSupport Hook\n// ============================================================================\n\n/**\n * Hook to check WASM support\n */\nexport function useWasmSupport(): boolean {\n const kit = useComputeKit();\n return kit.isWasmSupported();\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type {\n ComputeKitOptions,\n ComputeOptions,\n ComputeProgress,\n PoolStats,\n} from '@computekit/core';\n\nexport { ComputeKit } from '@computekit/core';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["createContext","useMemo","ComputeKit","useEffect","useContext","useRef","useState","useCallback"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ComputeKit React Bindings\n * React hooks and utilities for ComputeKit\n */\n\nimport React, {\n useState,\n useEffect,\n useCallback,\n useRef,\n useMemo,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\n\nimport {\n ComputeKit,\n type ComputeKitOptions,\n type ComputeOptions,\n type ComputeProgress,\n type PoolStats,\n} from '@computekit/core';\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst ComputeKitContext = createContext<ComputeKit | null>(null);\n\n/**\n * Props for ComputeKitProvider\n */\nexport interface ComputeKitProviderProps {\n /** ComputeKit options */\n options?: ComputeKitOptions;\n /** Custom ComputeKit instance */\n instance?: ComputeKit;\n /** Children */\n children: ReactNode;\n}\n\n/**\n * Provider component for ComputeKit\n *\n * @example\n * ```tsx\n * import { ComputeKitProvider } from '@computekit/react';\n *\n * function App() {\n * return (\n * <ComputeKitProvider options={{ maxWorkers: 4 }}>\n * <MyApp />\n * </ComputeKitProvider>\n * );\n * }\n * ```\n */\nexport function ComputeKitProvider({\n options,\n instance,\n children,\n}: ComputeKitProviderProps): React.ReactElement {\n const kit = useMemo(() => {\n return instance ?? new ComputeKit(options);\n }, [instance, options]);\n\n useEffect(() => {\n return () => {\n // Only terminate if we created the instance\n if (!instance) {\n kit.terminate();\n }\n };\n }, [kit, instance]);\n\n return <ComputeKitContext.Provider value={kit}>{children}</ComputeKitContext.Provider>;\n}\n\n/**\n * Get the ComputeKit instance from context\n */\nexport function useComputeKit(): ComputeKit {\n const kit = useContext(ComputeKitContext);\n if (!kit) {\n throw new Error('useComputeKit must be used within a ComputeKitProvider');\n }\n return kit;\n}\n\n// ============================================================================\n// useCompute Hook\n// ============================================================================\n\n/**\n * Status of a compute operation\n */\nexport type ComputeStatus = 'idle' | 'running' | 'success' | 'error' | 'cancelled';\n\n/**\n * State returned by useCompute\n */\nexport interface UseComputeState<T> {\n /** The computed result */\n data: T | null;\n /** Loading state */\n loading: boolean;\n /** Error if computation failed */\n error: Error | null;\n /** Progress information */\n progress: ComputeProgress | null;\n /** Current status of the computation */\n status: ComputeStatus;\n}\n\n/**\n * Actions returned by useCompute\n */\nexport interface UseComputeActions<TInput> {\n /** Execute the compute function */\n run: (input: TInput, options?: ComputeOptions) => Promise<void>;\n /** Reset the state */\n reset: () => void;\n /** Cancel ongoing computation */\n cancel: () => void;\n}\n\n/**\n * Return type for useCompute\n */\nexport type UseComputeReturn<TInput, TOutput> = UseComputeState<TOutput> &\n UseComputeActions<TInput>;\n\n/**\n * Options for useCompute hook\n */\nexport interface UseComputeOptions extends ComputeOptions {\n /** Automatically run on mount with initial input */\n autoRun?: boolean;\n /** Initial input for autoRun */\n initialInput?: unknown;\n /** Reset state on new run */\n resetOnRun?: boolean;\n}\n\n/**\n * Hook for running compute functions\n *\n * @example\n * ```tsx\n * function FibonacciCalculator() {\n * const { data, loading, error, run } = useCompute<number, number>('fibonacci');\n *\n * return (\n * <div>\n * <button onClick={() => run(50)} disabled={loading}>\n * Calculate Fibonacci(50)\n * </button>\n * {loading && <p>Computing...</p>}\n * {error && <p>Error: {error.message}</p>}\n * {data !== null && <p>Result: {data}</p>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useCompute<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options: UseComputeOptions = {}\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n const abortControllerRef = useRef<AbortController | null>(null);\n const cancelledRef = useRef(false);\n\n const [state, setState] = useState<UseComputeState<TOutput>>({\n data: null,\n loading: false,\n error: null,\n progress: null,\n status: 'idle',\n });\n\n const reset = useCallback(() => {\n cancelledRef.current = false;\n setState({\n data: null,\n loading: false,\n error: null,\n progress: null,\n status: 'idle',\n });\n }, []);\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n cancelledRef.current = true;\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n setState((prev) => ({\n ...prev,\n loading: false,\n status: 'cancelled',\n }));\n }\n }, []);\n\n const run = useCallback(\n async (input: TInput, runOptions?: ComputeOptions) => {\n // Cancel any ongoing computation\n cancel();\n cancelledRef.current = false;\n\n // Create new abort controller\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n // Reset state if configured\n if (options.resetOnRun !== false) {\n setState((prev) => ({\n ...prev,\n loading: true,\n error: null,\n progress: null,\n status: 'running',\n }));\n } else {\n setState((prev) => ({ ...prev, loading: true, status: 'running' }));\n }\n\n try {\n const result = await kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n signal: runOptions?.signal ?? abortController.signal,\n onProgress: (progress) => {\n setState((prev) => ({ ...prev, progress }));\n options.onProgress?.(progress);\n runOptions?.onProgress?.(progress);\n },\n });\n\n if (!abortController.signal.aborted) {\n setState({\n data: result,\n loading: false,\n error: null,\n progress: null,\n status: 'success',\n });\n }\n } catch (err) {\n if (!abortController.signal.aborted && !cancelledRef.current) {\n setState({\n data: null,\n loading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n progress: null,\n status: 'error',\n });\n }\n }\n },\n [kit, functionName, options, cancel]\n );\n\n // Auto-run on mount if configured\n useEffect(() => {\n if (options.autoRun && options.initialInput !== undefined) {\n run(options.initialInput as TInput);\n }\n // Only run on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n cancel();\n };\n }, [cancel]);\n\n return {\n ...state,\n run,\n reset,\n cancel,\n };\n}\n\n// ============================================================================\n// useComputeCallback Hook\n// ============================================================================\n\n/**\n * Hook that returns a memoized async function for compute operations\n *\n * @example\n * ```tsx\n * function Calculator() {\n * const calculate = useComputeCallback<number[], number>('sum');\n *\n * const handleClick = async () => {\n * const result = await calculate([1, 2, 3, 4, 5]);\n * console.log(result);\n * };\n *\n * return <button onClick={handleClick}>Calculate Sum</button>;\n * }\n * ```\n */\nexport function useComputeCallback<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options?: ComputeOptions\n): (input: TInput, runOptions?: ComputeOptions) => Promise<TOutput> {\n const kit = useComputeKit();\n\n return useCallback(\n (input: TInput, runOptions?: ComputeOptions) => {\n return kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n });\n },\n [kit, functionName, options]\n );\n}\n\n// ============================================================================\n// useComputeFunction Hook\n// ============================================================================\n\n/**\n * Hook to register and use a compute function\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { run, loading, data } = useComputeFunction(\n * 'myFunction',\n * (input: number) => input * 2\n * );\n *\n * return (\n * <button onClick={() => run(5)} disabled={loading}>\n * {loading ? 'Computing...' : `Result: ${data}`}\n * </button>\n * );\n * }\n * ```\n */\nexport function useComputeFunction<TInput = unknown, TOutput = unknown>(\n name: string,\n fn: (input: TInput) => TOutput | Promise<TOutput>,\n options?: UseComputeOptions\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n\n // Register function on mount\n useEffect(() => {\n kit.register(name, fn);\n }, [kit, name, fn]);\n\n return useCompute<TInput, TOutput>(name, options);\n}\n\n// ============================================================================\n// usePoolStats Hook\n// ============================================================================\n\n/**\n * Hook to get worker pool statistics\n *\n * @example\n * ```tsx\n * function PoolMonitor() {\n * const stats = usePoolStats(1000); // Update every second\n *\n * return (\n * <div>\n * <p>Active Workers: {stats.activeWorkers}</p>\n * <p>Queue Length: {stats.queueLength}</p>\n * <p>Tasks Completed: {stats.tasksCompleted}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePoolStats(refreshInterval: number = 0): PoolStats {\n const kit = useComputeKit();\n const [stats, setStats] = useState<PoolStats>(() => kit.getStats());\n\n useEffect(() => {\n // For one-time fetch (refreshInterval <= 0), we rely on the initial state\n if (refreshInterval <= 0) {\n return;\n }\n\n const interval = setInterval(() => {\n setStats(kit.getStats());\n }, refreshInterval);\n\n return () => clearInterval(interval);\n }, [kit, refreshInterval]);\n\n return stats;\n}\n\n// ============================================================================\n// useWasmSupport Hook\n// ============================================================================\n\n/**\n * Hook to check WASM support\n */\nexport function useWasmSupport(): boolean {\n const kit = useComputeKit();\n return kit.isWasmSupported();\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type {\n ComputeKitOptions,\n ComputeOptions,\n ComputeProgress,\n PoolStats,\n} from '@computekit/core';\n\nexport { ComputeKit } from '@computekit/core';\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
2
|
import { ComputeKitOptions, ComputeKit, ComputeProgress, ComputeOptions, PoolStats } from '@computekit/core';
|
|
3
3
|
export { ComputeKit, ComputeKitOptions, ComputeOptions, ComputeProgress, PoolStats } from '@computekit/core';
|
|
4
4
|
|
|
@@ -34,11 +34,15 @@ interface ComputeKitProviderProps {
|
|
|
34
34
|
* }
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
declare function ComputeKitProvider({ options, instance, children, }: ComputeKitProviderProps):
|
|
37
|
+
declare function ComputeKitProvider({ options, instance, children, }: ComputeKitProviderProps): React.ReactElement;
|
|
38
38
|
/**
|
|
39
39
|
* Get the ComputeKit instance from context
|
|
40
40
|
*/
|
|
41
41
|
declare function useComputeKit(): ComputeKit;
|
|
42
|
+
/**
|
|
43
|
+
* Status of a compute operation
|
|
44
|
+
*/
|
|
45
|
+
type ComputeStatus = 'idle' | 'running' | 'success' | 'error' | 'cancelled';
|
|
42
46
|
/**
|
|
43
47
|
* State returned by useCompute
|
|
44
48
|
*/
|
|
@@ -51,6 +55,8 @@ interface UseComputeState<T> {
|
|
|
51
55
|
error: Error | null;
|
|
52
56
|
/** Progress information */
|
|
53
57
|
progress: ComputeProgress | null;
|
|
58
|
+
/** Current status of the computation */
|
|
59
|
+
status: ComputeStatus;
|
|
54
60
|
}
|
|
55
61
|
/**
|
|
56
62
|
* Actions returned by useCompute
|
|
@@ -162,4 +168,4 @@ declare function usePoolStats(refreshInterval?: number): PoolStats;
|
|
|
162
168
|
*/
|
|
163
169
|
declare function useWasmSupport(): boolean;
|
|
164
170
|
|
|
165
|
-
export { ComputeKitProvider, type ComputeKitProviderProps, type UseComputeActions, type UseComputeOptions, type UseComputeReturn, type UseComputeState, useCompute, useComputeCallback, useComputeFunction, useComputeKit, usePoolStats, useWasmSupport };
|
|
171
|
+
export { ComputeKitProvider, type ComputeKitProviderProps, type ComputeStatus, type UseComputeActions, type UseComputeOptions, type UseComputeReturn, type UseComputeState, useCompute, useComputeCallback, useComputeFunction, useComputeKit, usePoolStats, useWasmSupport };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
2
|
import { ComputeKitOptions, ComputeKit, ComputeProgress, ComputeOptions, PoolStats } from '@computekit/core';
|
|
3
3
|
export { ComputeKit, ComputeKitOptions, ComputeOptions, ComputeProgress, PoolStats } from '@computekit/core';
|
|
4
4
|
|
|
@@ -34,11 +34,15 @@ interface ComputeKitProviderProps {
|
|
|
34
34
|
* }
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
declare function ComputeKitProvider({ options, instance, children, }: ComputeKitProviderProps):
|
|
37
|
+
declare function ComputeKitProvider({ options, instance, children, }: ComputeKitProviderProps): React.ReactElement;
|
|
38
38
|
/**
|
|
39
39
|
* Get the ComputeKit instance from context
|
|
40
40
|
*/
|
|
41
41
|
declare function useComputeKit(): ComputeKit;
|
|
42
|
+
/**
|
|
43
|
+
* Status of a compute operation
|
|
44
|
+
*/
|
|
45
|
+
type ComputeStatus = 'idle' | 'running' | 'success' | 'error' | 'cancelled';
|
|
42
46
|
/**
|
|
43
47
|
* State returned by useCompute
|
|
44
48
|
*/
|
|
@@ -51,6 +55,8 @@ interface UseComputeState<T> {
|
|
|
51
55
|
error: Error | null;
|
|
52
56
|
/** Progress information */
|
|
53
57
|
progress: ComputeProgress | null;
|
|
58
|
+
/** Current status of the computation */
|
|
59
|
+
status: ComputeStatus;
|
|
54
60
|
}
|
|
55
61
|
/**
|
|
56
62
|
* Actions returned by useCompute
|
|
@@ -162,4 +168,4 @@ declare function usePoolStats(refreshInterval?: number): PoolStats;
|
|
|
162
168
|
*/
|
|
163
169
|
declare function useWasmSupport(): boolean;
|
|
164
170
|
|
|
165
|
-
export { ComputeKitProvider, type ComputeKitProviderProps, type UseComputeActions, type UseComputeOptions, type UseComputeReturn, type UseComputeState, useCompute, useComputeCallback, useComputeFunction, useComputeKit, usePoolStats, useWasmSupport };
|
|
171
|
+
export { ComputeKitProvider, type ComputeKitProviderProps, type ComputeStatus, type UseComputeActions, type UseComputeOptions, type UseComputeReturn, type UseComputeState, useCompute, useComputeCallback, useComputeFunction, useComputeKit, usePoolStats, useWasmSupport };
|
package/dist/index.js
CHANGED
|
@@ -32,29 +32,40 @@ function useComputeKit() {
|
|
|
32
32
|
function useCompute(functionName, options = {}) {
|
|
33
33
|
const kit = useComputeKit();
|
|
34
34
|
const abortControllerRef = useRef(null);
|
|
35
|
+
const cancelledRef = useRef(false);
|
|
35
36
|
const [state, setState] = useState({
|
|
36
37
|
data: null,
|
|
37
38
|
loading: false,
|
|
38
39
|
error: null,
|
|
39
|
-
progress: null
|
|
40
|
+
progress: null,
|
|
41
|
+
status: "idle"
|
|
40
42
|
});
|
|
41
43
|
const reset = useCallback(() => {
|
|
44
|
+
cancelledRef.current = false;
|
|
42
45
|
setState({
|
|
43
46
|
data: null,
|
|
44
47
|
loading: false,
|
|
45
48
|
error: null,
|
|
46
|
-
progress: null
|
|
49
|
+
progress: null,
|
|
50
|
+
status: "idle"
|
|
47
51
|
});
|
|
48
52
|
}, []);
|
|
49
53
|
const cancel = useCallback(() => {
|
|
50
54
|
if (abortControllerRef.current) {
|
|
55
|
+
cancelledRef.current = true;
|
|
51
56
|
abortControllerRef.current.abort();
|
|
52
57
|
abortControllerRef.current = null;
|
|
58
|
+
setState((prev) => ({
|
|
59
|
+
...prev,
|
|
60
|
+
loading: false,
|
|
61
|
+
status: "cancelled"
|
|
62
|
+
}));
|
|
53
63
|
}
|
|
54
64
|
}, []);
|
|
55
65
|
const run = useCallback(
|
|
56
66
|
async (input, runOptions) => {
|
|
57
67
|
cancel();
|
|
68
|
+
cancelledRef.current = false;
|
|
58
69
|
const abortController = new AbortController();
|
|
59
70
|
abortControllerRef.current = abortController;
|
|
60
71
|
if (options.resetOnRun !== false) {
|
|
@@ -62,10 +73,11 @@ function useCompute(functionName, options = {}) {
|
|
|
62
73
|
...prev,
|
|
63
74
|
loading: true,
|
|
64
75
|
error: null,
|
|
65
|
-
progress: null
|
|
76
|
+
progress: null,
|
|
77
|
+
status: "running"
|
|
66
78
|
}));
|
|
67
79
|
} else {
|
|
68
|
-
setState((prev) => ({ ...prev, loading: true }));
|
|
80
|
+
setState((prev) => ({ ...prev, loading: true, status: "running" }));
|
|
69
81
|
}
|
|
70
82
|
try {
|
|
71
83
|
const result = await kit.run(functionName, input, {
|
|
@@ -83,16 +95,18 @@ function useCompute(functionName, options = {}) {
|
|
|
83
95
|
data: result,
|
|
84
96
|
loading: false,
|
|
85
97
|
error: null,
|
|
86
|
-
progress: null
|
|
98
|
+
progress: null,
|
|
99
|
+
status: "success"
|
|
87
100
|
});
|
|
88
101
|
}
|
|
89
102
|
} catch (err) {
|
|
90
|
-
if (!abortController.signal.aborted) {
|
|
103
|
+
if (!abortController.signal.aborted && !cancelledRef.current) {
|
|
91
104
|
setState({
|
|
92
105
|
data: null,
|
|
93
106
|
loading: false,
|
|
94
107
|
error: err instanceof Error ? err : new Error(String(err)),
|
|
95
|
-
progress: null
|
|
108
|
+
progress: null,
|
|
109
|
+
status: "error"
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * ComputeKit React Bindings\n * React hooks and utilities for ComputeKit\n */\n\nimport {\n useState,\n useEffect,\n useCallback,\n useRef,\n useMemo,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\n\nimport {\n ComputeKit,\n type ComputeKitOptions,\n type ComputeOptions,\n type ComputeProgress,\n type PoolStats,\n} from '@computekit/core';\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst ComputeKitContext = createContext<ComputeKit | null>(null);\n\n/**\n * Props for ComputeKitProvider\n */\nexport interface ComputeKitProviderProps {\n /** ComputeKit options */\n options?: ComputeKitOptions;\n /** Custom ComputeKit instance */\n instance?: ComputeKit;\n /** Children */\n children: ReactNode;\n}\n\n/**\n * Provider component for ComputeKit\n *\n * @example\n * ```tsx\n * import { ComputeKitProvider } from '@computekit/react';\n *\n * function App() {\n * return (\n * <ComputeKitProvider options={{ maxWorkers: 4 }}>\n * <MyApp />\n * </ComputeKitProvider>\n * );\n * }\n * ```\n */\nexport function ComputeKitProvider({\n options,\n instance,\n children,\n}: ComputeKitProviderProps): JSX.Element {\n const kit = useMemo(() => {\n return instance ?? new ComputeKit(options);\n }, [instance, options]);\n\n useEffect(() => {\n return () => {\n // Only terminate if we created the instance\n if (!instance) {\n kit.terminate();\n }\n };\n }, [kit, instance]);\n\n return <ComputeKitContext.Provider value={kit}>{children}</ComputeKitContext.Provider>;\n}\n\n/**\n * Get the ComputeKit instance from context\n */\nexport function useComputeKit(): ComputeKit {\n const kit = useContext(ComputeKitContext);\n if (!kit) {\n throw new Error('useComputeKit must be used within a ComputeKitProvider');\n }\n return kit;\n}\n\n// ============================================================================\n// useCompute Hook\n// ============================================================================\n\n/**\n * State returned by useCompute\n */\nexport interface UseComputeState<T> {\n /** The computed result */\n data: T | null;\n /** Loading state */\n loading: boolean;\n /** Error if computation failed */\n error: Error | null;\n /** Progress information */\n progress: ComputeProgress | null;\n}\n\n/**\n * Actions returned by useCompute\n */\nexport interface UseComputeActions<TInput> {\n /** Execute the compute function */\n run: (input: TInput, options?: ComputeOptions) => Promise<void>;\n /** Reset the state */\n reset: () => void;\n /** Cancel ongoing computation */\n cancel: () => void;\n}\n\n/**\n * Return type for useCompute\n */\nexport type UseComputeReturn<TInput, TOutput> = UseComputeState<TOutput> &\n UseComputeActions<TInput>;\n\n/**\n * Options for useCompute hook\n */\nexport interface UseComputeOptions extends ComputeOptions {\n /** Automatically run on mount with initial input */\n autoRun?: boolean;\n /** Initial input for autoRun */\n initialInput?: unknown;\n /** Reset state on new run */\n resetOnRun?: boolean;\n}\n\n/**\n * Hook for running compute functions\n *\n * @example\n * ```tsx\n * function FibonacciCalculator() {\n * const { data, loading, error, run } = useCompute<number, number>('fibonacci');\n *\n * return (\n * <div>\n * <button onClick={() => run(50)} disabled={loading}>\n * Calculate Fibonacci(50)\n * </button>\n * {loading && <p>Computing...</p>}\n * {error && <p>Error: {error.message}</p>}\n * {data !== null && <p>Result: {data}</p>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useCompute<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options: UseComputeOptions = {}\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const [state, setState] = useState<UseComputeState<TOutput>>({\n data: null,\n loading: false,\n error: null,\n progress: null,\n });\n\n const reset = useCallback(() => {\n setState({\n data: null,\n loading: false,\n error: null,\n progress: null,\n });\n }, []);\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n }, []);\n\n const run = useCallback(\n async (input: TInput, runOptions?: ComputeOptions) => {\n // Cancel any ongoing computation\n cancel();\n\n // Create new abort controller\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n // Reset state if configured\n if (options.resetOnRun !== false) {\n setState((prev) => ({\n ...prev,\n loading: true,\n error: null,\n progress: null,\n }));\n } else {\n setState((prev) => ({ ...prev, loading: true }));\n }\n\n try {\n const result = await kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n signal: runOptions?.signal ?? abortController.signal,\n onProgress: (progress) => {\n setState((prev) => ({ ...prev, progress }));\n options.onProgress?.(progress);\n runOptions?.onProgress?.(progress);\n },\n });\n\n if (!abortController.signal.aborted) {\n setState({\n data: result,\n loading: false,\n error: null,\n progress: null,\n });\n }\n } catch (err) {\n if (!abortController.signal.aborted) {\n setState({\n data: null,\n loading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n progress: null,\n });\n }\n }\n },\n [kit, functionName, options, cancel]\n );\n\n // Auto-run on mount if configured\n useEffect(() => {\n if (options.autoRun && options.initialInput !== undefined) {\n run(options.initialInput as TInput);\n }\n // Only run on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n cancel();\n };\n }, [cancel]);\n\n return {\n ...state,\n run,\n reset,\n cancel,\n };\n}\n\n// ============================================================================\n// useComputeCallback Hook\n// ============================================================================\n\n/**\n * Hook that returns a memoized async function for compute operations\n *\n * @example\n * ```tsx\n * function Calculator() {\n * const calculate = useComputeCallback<number[], number>('sum');\n *\n * const handleClick = async () => {\n * const result = await calculate([1, 2, 3, 4, 5]);\n * console.log(result);\n * };\n *\n * return <button onClick={handleClick}>Calculate Sum</button>;\n * }\n * ```\n */\nexport function useComputeCallback<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options?: ComputeOptions\n): (input: TInput, runOptions?: ComputeOptions) => Promise<TOutput> {\n const kit = useComputeKit();\n\n return useCallback(\n (input: TInput, runOptions?: ComputeOptions) => {\n return kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n });\n },\n [kit, functionName, options]\n );\n}\n\n// ============================================================================\n// useComputeFunction Hook\n// ============================================================================\n\n/**\n * Hook to register and use a compute function\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { run, loading, data } = useComputeFunction(\n * 'myFunction',\n * (input: number) => input * 2\n * );\n *\n * return (\n * <button onClick={() => run(5)} disabled={loading}>\n * {loading ? 'Computing...' : `Result: ${data}`}\n * </button>\n * );\n * }\n * ```\n */\nexport function useComputeFunction<TInput = unknown, TOutput = unknown>(\n name: string,\n fn: (input: TInput) => TOutput | Promise<TOutput>,\n options?: UseComputeOptions\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n\n // Register function on mount\n useEffect(() => {\n kit.register(name, fn);\n }, [kit, name, fn]);\n\n return useCompute<TInput, TOutput>(name, options);\n}\n\n// ============================================================================\n// usePoolStats Hook\n// ============================================================================\n\n/**\n * Hook to get worker pool statistics\n *\n * @example\n * ```tsx\n * function PoolMonitor() {\n * const stats = usePoolStats(1000); // Update every second\n *\n * return (\n * <div>\n * <p>Active Workers: {stats.activeWorkers}</p>\n * <p>Queue Length: {stats.queueLength}</p>\n * <p>Tasks Completed: {stats.tasksCompleted}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePoolStats(refreshInterval: number = 0): PoolStats {\n const kit = useComputeKit();\n const [stats, setStats] = useState<PoolStats>(() => kit.getStats());\n\n useEffect(() => {\n // For one-time fetch (refreshInterval <= 0), we rely on the initial state\n if (refreshInterval <= 0) {\n return;\n }\n\n const interval = setInterval(() => {\n setStats(kit.getStats());\n }, refreshInterval);\n\n return () => clearInterval(interval);\n }, [kit, refreshInterval]);\n\n return stats;\n}\n\n// ============================================================================\n// useWasmSupport Hook\n// ============================================================================\n\n/**\n * Hook to check WASM support\n */\nexport function useWasmSupport(): boolean {\n const kit = useComputeKit();\n return kit.isWasmSupported();\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type {\n ComputeKitOptions,\n ComputeOptions,\n ComputeProgress,\n PoolStats,\n} from '@computekit/core';\n\nexport { ComputeKit } from '@computekit/core';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * ComputeKit React Bindings\n * React hooks and utilities for ComputeKit\n */\n\nimport React, {\n useState,\n useEffect,\n useCallback,\n useRef,\n useMemo,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\n\nimport {\n ComputeKit,\n type ComputeKitOptions,\n type ComputeOptions,\n type ComputeProgress,\n type PoolStats,\n} from '@computekit/core';\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst ComputeKitContext = createContext<ComputeKit | null>(null);\n\n/**\n * Props for ComputeKitProvider\n */\nexport interface ComputeKitProviderProps {\n /** ComputeKit options */\n options?: ComputeKitOptions;\n /** Custom ComputeKit instance */\n instance?: ComputeKit;\n /** Children */\n children: ReactNode;\n}\n\n/**\n * Provider component for ComputeKit\n *\n * @example\n * ```tsx\n * import { ComputeKitProvider } from '@computekit/react';\n *\n * function App() {\n * return (\n * <ComputeKitProvider options={{ maxWorkers: 4 }}>\n * <MyApp />\n * </ComputeKitProvider>\n * );\n * }\n * ```\n */\nexport function ComputeKitProvider({\n options,\n instance,\n children,\n}: ComputeKitProviderProps): React.ReactElement {\n const kit = useMemo(() => {\n return instance ?? new ComputeKit(options);\n }, [instance, options]);\n\n useEffect(() => {\n return () => {\n // Only terminate if we created the instance\n if (!instance) {\n kit.terminate();\n }\n };\n }, [kit, instance]);\n\n return <ComputeKitContext.Provider value={kit}>{children}</ComputeKitContext.Provider>;\n}\n\n/**\n * Get the ComputeKit instance from context\n */\nexport function useComputeKit(): ComputeKit {\n const kit = useContext(ComputeKitContext);\n if (!kit) {\n throw new Error('useComputeKit must be used within a ComputeKitProvider');\n }\n return kit;\n}\n\n// ============================================================================\n// useCompute Hook\n// ============================================================================\n\n/**\n * Status of a compute operation\n */\nexport type ComputeStatus = 'idle' | 'running' | 'success' | 'error' | 'cancelled';\n\n/**\n * State returned by useCompute\n */\nexport interface UseComputeState<T> {\n /** The computed result */\n data: T | null;\n /** Loading state */\n loading: boolean;\n /** Error if computation failed */\n error: Error | null;\n /** Progress information */\n progress: ComputeProgress | null;\n /** Current status of the computation */\n status: ComputeStatus;\n}\n\n/**\n * Actions returned by useCompute\n */\nexport interface UseComputeActions<TInput> {\n /** Execute the compute function */\n run: (input: TInput, options?: ComputeOptions) => Promise<void>;\n /** Reset the state */\n reset: () => void;\n /** Cancel ongoing computation */\n cancel: () => void;\n}\n\n/**\n * Return type for useCompute\n */\nexport type UseComputeReturn<TInput, TOutput> = UseComputeState<TOutput> &\n UseComputeActions<TInput>;\n\n/**\n * Options for useCompute hook\n */\nexport interface UseComputeOptions extends ComputeOptions {\n /** Automatically run on mount with initial input */\n autoRun?: boolean;\n /** Initial input for autoRun */\n initialInput?: unknown;\n /** Reset state on new run */\n resetOnRun?: boolean;\n}\n\n/**\n * Hook for running compute functions\n *\n * @example\n * ```tsx\n * function FibonacciCalculator() {\n * const { data, loading, error, run } = useCompute<number, number>('fibonacci');\n *\n * return (\n * <div>\n * <button onClick={() => run(50)} disabled={loading}>\n * Calculate Fibonacci(50)\n * </button>\n * {loading && <p>Computing...</p>}\n * {error && <p>Error: {error.message}</p>}\n * {data !== null && <p>Result: {data}</p>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useCompute<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options: UseComputeOptions = {}\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n const abortControllerRef = useRef<AbortController | null>(null);\n const cancelledRef = useRef(false);\n\n const [state, setState] = useState<UseComputeState<TOutput>>({\n data: null,\n loading: false,\n error: null,\n progress: null,\n status: 'idle',\n });\n\n const reset = useCallback(() => {\n cancelledRef.current = false;\n setState({\n data: null,\n loading: false,\n error: null,\n progress: null,\n status: 'idle',\n });\n }, []);\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n cancelledRef.current = true;\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n setState((prev) => ({\n ...prev,\n loading: false,\n status: 'cancelled',\n }));\n }\n }, []);\n\n const run = useCallback(\n async (input: TInput, runOptions?: ComputeOptions) => {\n // Cancel any ongoing computation\n cancel();\n cancelledRef.current = false;\n\n // Create new abort controller\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n // Reset state if configured\n if (options.resetOnRun !== false) {\n setState((prev) => ({\n ...prev,\n loading: true,\n error: null,\n progress: null,\n status: 'running',\n }));\n } else {\n setState((prev) => ({ ...prev, loading: true, status: 'running' }));\n }\n\n try {\n const result = await kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n signal: runOptions?.signal ?? abortController.signal,\n onProgress: (progress) => {\n setState((prev) => ({ ...prev, progress }));\n options.onProgress?.(progress);\n runOptions?.onProgress?.(progress);\n },\n });\n\n if (!abortController.signal.aborted) {\n setState({\n data: result,\n loading: false,\n error: null,\n progress: null,\n status: 'success',\n });\n }\n } catch (err) {\n if (!abortController.signal.aborted && !cancelledRef.current) {\n setState({\n data: null,\n loading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n progress: null,\n status: 'error',\n });\n }\n }\n },\n [kit, functionName, options, cancel]\n );\n\n // Auto-run on mount if configured\n useEffect(() => {\n if (options.autoRun && options.initialInput !== undefined) {\n run(options.initialInput as TInput);\n }\n // Only run on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n cancel();\n };\n }, [cancel]);\n\n return {\n ...state,\n run,\n reset,\n cancel,\n };\n}\n\n// ============================================================================\n// useComputeCallback Hook\n// ============================================================================\n\n/**\n * Hook that returns a memoized async function for compute operations\n *\n * @example\n * ```tsx\n * function Calculator() {\n * const calculate = useComputeCallback<number[], number>('sum');\n *\n * const handleClick = async () => {\n * const result = await calculate([1, 2, 3, 4, 5]);\n * console.log(result);\n * };\n *\n * return <button onClick={handleClick}>Calculate Sum</button>;\n * }\n * ```\n */\nexport function useComputeCallback<TInput = unknown, TOutput = unknown>(\n functionName: string,\n options?: ComputeOptions\n): (input: TInput, runOptions?: ComputeOptions) => Promise<TOutput> {\n const kit = useComputeKit();\n\n return useCallback(\n (input: TInput, runOptions?: ComputeOptions) => {\n return kit.run<TInput, TOutput>(functionName, input, {\n ...options,\n ...runOptions,\n });\n },\n [kit, functionName, options]\n );\n}\n\n// ============================================================================\n// useComputeFunction Hook\n// ============================================================================\n\n/**\n * Hook to register and use a compute function\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { run, loading, data } = useComputeFunction(\n * 'myFunction',\n * (input: number) => input * 2\n * );\n *\n * return (\n * <button onClick={() => run(5)} disabled={loading}>\n * {loading ? 'Computing...' : `Result: ${data}`}\n * </button>\n * );\n * }\n * ```\n */\nexport function useComputeFunction<TInput = unknown, TOutput = unknown>(\n name: string,\n fn: (input: TInput) => TOutput | Promise<TOutput>,\n options?: UseComputeOptions\n): UseComputeReturn<TInput, TOutput> {\n const kit = useComputeKit();\n\n // Register function on mount\n useEffect(() => {\n kit.register(name, fn);\n }, [kit, name, fn]);\n\n return useCompute<TInput, TOutput>(name, options);\n}\n\n// ============================================================================\n// usePoolStats Hook\n// ============================================================================\n\n/**\n * Hook to get worker pool statistics\n *\n * @example\n * ```tsx\n * function PoolMonitor() {\n * const stats = usePoolStats(1000); // Update every second\n *\n * return (\n * <div>\n * <p>Active Workers: {stats.activeWorkers}</p>\n * <p>Queue Length: {stats.queueLength}</p>\n * <p>Tasks Completed: {stats.tasksCompleted}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePoolStats(refreshInterval: number = 0): PoolStats {\n const kit = useComputeKit();\n const [stats, setStats] = useState<PoolStats>(() => kit.getStats());\n\n useEffect(() => {\n // For one-time fetch (refreshInterval <= 0), we rely on the initial state\n if (refreshInterval <= 0) {\n return;\n }\n\n const interval = setInterval(() => {\n setStats(kit.getStats());\n }, refreshInterval);\n\n return () => clearInterval(interval);\n }, [kit, refreshInterval]);\n\n return stats;\n}\n\n// ============================================================================\n// useWasmSupport Hook\n// ============================================================================\n\n/**\n * Hook to check WASM support\n */\nexport function useWasmSupport(): boolean {\n const kit = useComputeKit();\n return kit.isWasmSupported();\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type {\n ComputeKitOptions,\n ComputeOptions,\n ComputeProgress,\n PoolStats,\n} from '@computekit/core';\n\nexport { ComputeKit } from '@computekit/core';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@computekit/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React bindings for ComputeKit - WASM + Worker toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
|
-
"src"
|
|
18
|
+
"src",
|
|
19
|
+
"README.md"
|
|
19
20
|
],
|
|
20
21
|
"scripts": {
|
|
21
22
|
"build": "tsup",
|
|
@@ -27,7 +28,13 @@
|
|
|
27
28
|
"@computekit/core": "*"
|
|
28
29
|
},
|
|
29
30
|
"peerDependencies": {
|
|
30
|
-
"react": ">=17.0.0"
|
|
31
|
+
"react": ">=17.0.0",
|
|
32
|
+
"@types/react": ">=17.0.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@types/react": {
|
|
36
|
+
"optional": true
|
|
37
|
+
}
|
|
31
38
|
},
|
|
32
39
|
"devDependencies": {
|
|
33
40
|
"@types/react": "^18.2.45",
|
package/src/index.tsx
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* React hooks and utilities for ComputeKit
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import React, {
|
|
7
7
|
useState,
|
|
8
8
|
useEffect,
|
|
9
9
|
useCallback,
|
|
@@ -60,7 +60,7 @@ export function ComputeKitProvider({
|
|
|
60
60
|
options,
|
|
61
61
|
instance,
|
|
62
62
|
children,
|
|
63
|
-
}: ComputeKitProviderProps):
|
|
63
|
+
}: ComputeKitProviderProps): React.ReactElement {
|
|
64
64
|
const kit = useMemo(() => {
|
|
65
65
|
return instance ?? new ComputeKit(options);
|
|
66
66
|
}, [instance, options]);
|
|
@@ -92,6 +92,11 @@ export function useComputeKit(): ComputeKit {
|
|
|
92
92
|
// useCompute Hook
|
|
93
93
|
// ============================================================================
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Status of a compute operation
|
|
97
|
+
*/
|
|
98
|
+
export type ComputeStatus = 'idle' | 'running' | 'success' | 'error' | 'cancelled';
|
|
99
|
+
|
|
95
100
|
/**
|
|
96
101
|
* State returned by useCompute
|
|
97
102
|
*/
|
|
@@ -104,6 +109,8 @@ export interface UseComputeState<T> {
|
|
|
104
109
|
error: Error | null;
|
|
105
110
|
/** Progress information */
|
|
106
111
|
progress: ComputeProgress | null;
|
|
112
|
+
/** Current status of the computation */
|
|
113
|
+
status: ComputeStatus;
|
|
107
114
|
}
|
|
108
115
|
|
|
109
116
|
/**
|
|
@@ -163,27 +170,37 @@ export function useCompute<TInput = unknown, TOutput = unknown>(
|
|
|
163
170
|
): UseComputeReturn<TInput, TOutput> {
|
|
164
171
|
const kit = useComputeKit();
|
|
165
172
|
const abortControllerRef = useRef<AbortController | null>(null);
|
|
173
|
+
const cancelledRef = useRef(false);
|
|
166
174
|
|
|
167
175
|
const [state, setState] = useState<UseComputeState<TOutput>>({
|
|
168
176
|
data: null,
|
|
169
177
|
loading: false,
|
|
170
178
|
error: null,
|
|
171
179
|
progress: null,
|
|
180
|
+
status: 'idle',
|
|
172
181
|
});
|
|
173
182
|
|
|
174
183
|
const reset = useCallback(() => {
|
|
184
|
+
cancelledRef.current = false;
|
|
175
185
|
setState({
|
|
176
186
|
data: null,
|
|
177
187
|
loading: false,
|
|
178
188
|
error: null,
|
|
179
189
|
progress: null,
|
|
190
|
+
status: 'idle',
|
|
180
191
|
});
|
|
181
192
|
}, []);
|
|
182
193
|
|
|
183
194
|
const cancel = useCallback(() => {
|
|
184
195
|
if (abortControllerRef.current) {
|
|
196
|
+
cancelledRef.current = true;
|
|
185
197
|
abortControllerRef.current.abort();
|
|
186
198
|
abortControllerRef.current = null;
|
|
199
|
+
setState((prev) => ({
|
|
200
|
+
...prev,
|
|
201
|
+
loading: false,
|
|
202
|
+
status: 'cancelled',
|
|
203
|
+
}));
|
|
187
204
|
}
|
|
188
205
|
}, []);
|
|
189
206
|
|
|
@@ -191,6 +208,7 @@ export function useCompute<TInput = unknown, TOutput = unknown>(
|
|
|
191
208
|
async (input: TInput, runOptions?: ComputeOptions) => {
|
|
192
209
|
// Cancel any ongoing computation
|
|
193
210
|
cancel();
|
|
211
|
+
cancelledRef.current = false;
|
|
194
212
|
|
|
195
213
|
// Create new abort controller
|
|
196
214
|
const abortController = new AbortController();
|
|
@@ -203,9 +221,10 @@ export function useCompute<TInput = unknown, TOutput = unknown>(
|
|
|
203
221
|
loading: true,
|
|
204
222
|
error: null,
|
|
205
223
|
progress: null,
|
|
224
|
+
status: 'running',
|
|
206
225
|
}));
|
|
207
226
|
} else {
|
|
208
|
-
setState((prev) => ({ ...prev, loading: true }));
|
|
227
|
+
setState((prev) => ({ ...prev, loading: true, status: 'running' }));
|
|
209
228
|
}
|
|
210
229
|
|
|
211
230
|
try {
|
|
@@ -226,15 +245,17 @@ export function useCompute<TInput = unknown, TOutput = unknown>(
|
|
|
226
245
|
loading: false,
|
|
227
246
|
error: null,
|
|
228
247
|
progress: null,
|
|
248
|
+
status: 'success',
|
|
229
249
|
});
|
|
230
250
|
}
|
|
231
251
|
} catch (err) {
|
|
232
|
-
if (!abortController.signal.aborted) {
|
|
252
|
+
if (!abortController.signal.aborted && !cancelledRef.current) {
|
|
233
253
|
setState({
|
|
234
254
|
data: null,
|
|
235
255
|
loading: false,
|
|
236
256
|
error: err instanceof Error ? err : new Error(String(err)),
|
|
237
257
|
progress: null,
|
|
258
|
+
status: 'error',
|
|
238
259
|
});
|
|
239
260
|
}
|
|
240
261
|
}
|