@computekit/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,170 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var core = require('@computekit/core');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/index.tsx
8
+ var ComputeKitContext = react.createContext(null);
9
+ function ComputeKitProvider({
10
+ options,
11
+ instance,
12
+ children
13
+ }) {
14
+ const kit = react.useMemo(() => {
15
+ return instance ?? new core.ComputeKit(options);
16
+ }, [instance, options]);
17
+ react.useEffect(() => {
18
+ return () => {
19
+ if (!instance) {
20
+ kit.terminate();
21
+ }
22
+ };
23
+ }, [kit, instance]);
24
+ return /* @__PURE__ */ jsxRuntime.jsx(ComputeKitContext.Provider, { value: kit, children });
25
+ }
26
+ function useComputeKit() {
27
+ const kit = react.useContext(ComputeKitContext);
28
+ if (!kit) {
29
+ throw new Error("useComputeKit must be used within a ComputeKitProvider");
30
+ }
31
+ return kit;
32
+ }
33
+ function useCompute(functionName, options = {}) {
34
+ const kit = useComputeKit();
35
+ const abortControllerRef = react.useRef(null);
36
+ const [state, setState] = react.useState({
37
+ data: null,
38
+ loading: false,
39
+ error: null,
40
+ progress: null
41
+ });
42
+ const reset = react.useCallback(() => {
43
+ setState({
44
+ data: null,
45
+ loading: false,
46
+ error: null,
47
+ progress: null
48
+ });
49
+ }, []);
50
+ const cancel = react.useCallback(() => {
51
+ if (abortControllerRef.current) {
52
+ abortControllerRef.current.abort();
53
+ abortControllerRef.current = null;
54
+ }
55
+ }, []);
56
+ const run = react.useCallback(
57
+ async (input, runOptions) => {
58
+ cancel();
59
+ const abortController = new AbortController();
60
+ abortControllerRef.current = abortController;
61
+ if (options.resetOnRun !== false) {
62
+ setState((prev) => ({
63
+ ...prev,
64
+ loading: true,
65
+ error: null,
66
+ progress: null
67
+ }));
68
+ } else {
69
+ setState((prev) => ({ ...prev, loading: true }));
70
+ }
71
+ try {
72
+ const result = await kit.run(functionName, input, {
73
+ ...options,
74
+ ...runOptions,
75
+ signal: runOptions?.signal ?? abortController.signal,
76
+ onProgress: (progress) => {
77
+ setState((prev) => ({ ...prev, progress }));
78
+ options.onProgress?.(progress);
79
+ runOptions?.onProgress?.(progress);
80
+ }
81
+ });
82
+ if (!abortController.signal.aborted) {
83
+ setState({
84
+ data: result,
85
+ loading: false,
86
+ error: null,
87
+ progress: null
88
+ });
89
+ }
90
+ } catch (err) {
91
+ if (!abortController.signal.aborted) {
92
+ setState({
93
+ data: null,
94
+ loading: false,
95
+ error: err instanceof Error ? err : new Error(String(err)),
96
+ progress: null
97
+ });
98
+ }
99
+ }
100
+ },
101
+ [kit, functionName, options, cancel]
102
+ );
103
+ react.useEffect(() => {
104
+ if (options.autoRun && options.initialInput !== void 0) {
105
+ run(options.initialInput);
106
+ }
107
+ }, []);
108
+ react.useEffect(() => {
109
+ return () => {
110
+ cancel();
111
+ };
112
+ }, [cancel]);
113
+ return {
114
+ ...state,
115
+ run,
116
+ reset,
117
+ cancel
118
+ };
119
+ }
120
+ function useComputeCallback(functionName, options) {
121
+ const kit = useComputeKit();
122
+ return react.useCallback(
123
+ (input, runOptions) => {
124
+ return kit.run(functionName, input, {
125
+ ...options,
126
+ ...runOptions
127
+ });
128
+ },
129
+ [kit, functionName, options]
130
+ );
131
+ }
132
+ function useComputeFunction(name, fn, options) {
133
+ const kit = useComputeKit();
134
+ react.useEffect(() => {
135
+ kit.register(name, fn);
136
+ }, [kit, name, fn]);
137
+ return useCompute(name, options);
138
+ }
139
+ function usePoolStats(refreshInterval = 0) {
140
+ const kit = useComputeKit();
141
+ const [stats, setStats] = react.useState(() => kit.getStats());
142
+ react.useEffect(() => {
143
+ if (refreshInterval <= 0) {
144
+ return;
145
+ }
146
+ const interval = setInterval(() => {
147
+ setStats(kit.getStats());
148
+ }, refreshInterval);
149
+ return () => clearInterval(interval);
150
+ }, [kit, refreshInterval]);
151
+ return stats;
152
+ }
153
+ function useWasmSupport() {
154
+ const kit = useComputeKit();
155
+ return kit.isWasmSupported();
156
+ }
157
+
158
+ Object.defineProperty(exports, "ComputeKit", {
159
+ enumerable: true,
160
+ get: function () { return core.ComputeKit; }
161
+ });
162
+ exports.ComputeKitProvider = ComputeKitProvider;
163
+ exports.useCompute = useCompute;
164
+ exports.useComputeCallback = useComputeCallback;
165
+ exports.useComputeFunction = useComputeFunction;
166
+ exports.useComputeKit = useComputeKit;
167
+ exports.usePoolStats = usePoolStats;
168
+ exports.useWasmSupport = useWasmSupport;
169
+ //# sourceMappingURL=index.cjs.map
170
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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"]}
@@ -0,0 +1,165 @@
1
+ import { ReactNode } from 'react';
2
+ import { ComputeKitOptions, ComputeKit, ComputeProgress, ComputeOptions, PoolStats } from '@computekit/core';
3
+ export { ComputeKit, ComputeKitOptions, ComputeOptions, ComputeProgress, PoolStats } from '@computekit/core';
4
+
5
+ /**
6
+ * ComputeKit React Bindings
7
+ * React hooks and utilities for ComputeKit
8
+ */
9
+
10
+ /**
11
+ * Props for ComputeKitProvider
12
+ */
13
+ interface ComputeKitProviderProps {
14
+ /** ComputeKit options */
15
+ options?: ComputeKitOptions;
16
+ /** Custom ComputeKit instance */
17
+ instance?: ComputeKit;
18
+ /** Children */
19
+ children: ReactNode;
20
+ }
21
+ /**
22
+ * Provider component for ComputeKit
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * import { ComputeKitProvider } from '@computekit/react';
27
+ *
28
+ * function App() {
29
+ * return (
30
+ * <ComputeKitProvider options={{ maxWorkers: 4 }}>
31
+ * <MyApp />
32
+ * </ComputeKitProvider>
33
+ * );
34
+ * }
35
+ * ```
36
+ */
37
+ declare function ComputeKitProvider({ options, instance, children, }: ComputeKitProviderProps): JSX.Element;
38
+ /**
39
+ * Get the ComputeKit instance from context
40
+ */
41
+ declare function useComputeKit(): ComputeKit;
42
+ /**
43
+ * State returned by useCompute
44
+ */
45
+ interface UseComputeState<T> {
46
+ /** The computed result */
47
+ data: T | null;
48
+ /** Loading state */
49
+ loading: boolean;
50
+ /** Error if computation failed */
51
+ error: Error | null;
52
+ /** Progress information */
53
+ progress: ComputeProgress | null;
54
+ }
55
+ /**
56
+ * Actions returned by useCompute
57
+ */
58
+ interface UseComputeActions<TInput> {
59
+ /** Execute the compute function */
60
+ run: (input: TInput, options?: ComputeOptions) => Promise<void>;
61
+ /** Reset the state */
62
+ reset: () => void;
63
+ /** Cancel ongoing computation */
64
+ cancel: () => void;
65
+ }
66
+ /**
67
+ * Return type for useCompute
68
+ */
69
+ type UseComputeReturn<TInput, TOutput> = UseComputeState<TOutput> & UseComputeActions<TInput>;
70
+ /**
71
+ * Options for useCompute hook
72
+ */
73
+ interface UseComputeOptions extends ComputeOptions {
74
+ /** Automatically run on mount with initial input */
75
+ autoRun?: boolean;
76
+ /** Initial input for autoRun */
77
+ initialInput?: unknown;
78
+ /** Reset state on new run */
79
+ resetOnRun?: boolean;
80
+ }
81
+ /**
82
+ * Hook for running compute functions
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * function FibonacciCalculator() {
87
+ * const { data, loading, error, run } = useCompute<number, number>('fibonacci');
88
+ *
89
+ * return (
90
+ * <div>
91
+ * <button onClick={() => run(50)} disabled={loading}>
92
+ * Calculate Fibonacci(50)
93
+ * </button>
94
+ * {loading && <p>Computing...</p>}
95
+ * {error && <p>Error: {error.message}</p>}
96
+ * {data !== null && <p>Result: {data}</p>}
97
+ * </div>
98
+ * );
99
+ * }
100
+ * ```
101
+ */
102
+ declare function useCompute<TInput = unknown, TOutput = unknown>(functionName: string, options?: UseComputeOptions): UseComputeReturn<TInput, TOutput>;
103
+ /**
104
+ * Hook that returns a memoized async function for compute operations
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * function Calculator() {
109
+ * const calculate = useComputeCallback<number[], number>('sum');
110
+ *
111
+ * const handleClick = async () => {
112
+ * const result = await calculate([1, 2, 3, 4, 5]);
113
+ * console.log(result);
114
+ * };
115
+ *
116
+ * return <button onClick={handleClick}>Calculate Sum</button>;
117
+ * }
118
+ * ```
119
+ */
120
+ declare function useComputeCallback<TInput = unknown, TOutput = unknown>(functionName: string, options?: ComputeOptions): (input: TInput, runOptions?: ComputeOptions) => Promise<TOutput>;
121
+ /**
122
+ * Hook to register and use a compute function
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * function MyComponent() {
127
+ * const { run, loading, data } = useComputeFunction(
128
+ * 'myFunction',
129
+ * (input: number) => input * 2
130
+ * );
131
+ *
132
+ * return (
133
+ * <button onClick={() => run(5)} disabled={loading}>
134
+ * {loading ? 'Computing...' : `Result: ${data}`}
135
+ * </button>
136
+ * );
137
+ * }
138
+ * ```
139
+ */
140
+ declare function useComputeFunction<TInput = unknown, TOutput = unknown>(name: string, fn: (input: TInput) => TOutput | Promise<TOutput>, options?: UseComputeOptions): UseComputeReturn<TInput, TOutput>;
141
+ /**
142
+ * Hook to get worker pool statistics
143
+ *
144
+ * @example
145
+ * ```tsx
146
+ * function PoolMonitor() {
147
+ * const stats = usePoolStats(1000); // Update every second
148
+ *
149
+ * return (
150
+ * <div>
151
+ * <p>Active Workers: {stats.activeWorkers}</p>
152
+ * <p>Queue Length: {stats.queueLength}</p>
153
+ * <p>Tasks Completed: {stats.tasksCompleted}</p>
154
+ * </div>
155
+ * );
156
+ * }
157
+ * ```
158
+ */
159
+ declare function usePoolStats(refreshInterval?: number): PoolStats;
160
+ /**
161
+ * Hook to check WASM support
162
+ */
163
+ declare function useWasmSupport(): boolean;
164
+
165
+ export { ComputeKitProvider, type ComputeKitProviderProps, type UseComputeActions, type UseComputeOptions, type UseComputeReturn, type UseComputeState, useCompute, useComputeCallback, useComputeFunction, useComputeKit, usePoolStats, useWasmSupport };
@@ -0,0 +1,165 @@
1
+ import { ReactNode } from 'react';
2
+ import { ComputeKitOptions, ComputeKit, ComputeProgress, ComputeOptions, PoolStats } from '@computekit/core';
3
+ export { ComputeKit, ComputeKitOptions, ComputeOptions, ComputeProgress, PoolStats } from '@computekit/core';
4
+
5
+ /**
6
+ * ComputeKit React Bindings
7
+ * React hooks and utilities for ComputeKit
8
+ */
9
+
10
+ /**
11
+ * Props for ComputeKitProvider
12
+ */
13
+ interface ComputeKitProviderProps {
14
+ /** ComputeKit options */
15
+ options?: ComputeKitOptions;
16
+ /** Custom ComputeKit instance */
17
+ instance?: ComputeKit;
18
+ /** Children */
19
+ children: ReactNode;
20
+ }
21
+ /**
22
+ * Provider component for ComputeKit
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * import { ComputeKitProvider } from '@computekit/react';
27
+ *
28
+ * function App() {
29
+ * return (
30
+ * <ComputeKitProvider options={{ maxWorkers: 4 }}>
31
+ * <MyApp />
32
+ * </ComputeKitProvider>
33
+ * );
34
+ * }
35
+ * ```
36
+ */
37
+ declare function ComputeKitProvider({ options, instance, children, }: ComputeKitProviderProps): JSX.Element;
38
+ /**
39
+ * Get the ComputeKit instance from context
40
+ */
41
+ declare function useComputeKit(): ComputeKit;
42
+ /**
43
+ * State returned by useCompute
44
+ */
45
+ interface UseComputeState<T> {
46
+ /** The computed result */
47
+ data: T | null;
48
+ /** Loading state */
49
+ loading: boolean;
50
+ /** Error if computation failed */
51
+ error: Error | null;
52
+ /** Progress information */
53
+ progress: ComputeProgress | null;
54
+ }
55
+ /**
56
+ * Actions returned by useCompute
57
+ */
58
+ interface UseComputeActions<TInput> {
59
+ /** Execute the compute function */
60
+ run: (input: TInput, options?: ComputeOptions) => Promise<void>;
61
+ /** Reset the state */
62
+ reset: () => void;
63
+ /** Cancel ongoing computation */
64
+ cancel: () => void;
65
+ }
66
+ /**
67
+ * Return type for useCompute
68
+ */
69
+ type UseComputeReturn<TInput, TOutput> = UseComputeState<TOutput> & UseComputeActions<TInput>;
70
+ /**
71
+ * Options for useCompute hook
72
+ */
73
+ interface UseComputeOptions extends ComputeOptions {
74
+ /** Automatically run on mount with initial input */
75
+ autoRun?: boolean;
76
+ /** Initial input for autoRun */
77
+ initialInput?: unknown;
78
+ /** Reset state on new run */
79
+ resetOnRun?: boolean;
80
+ }
81
+ /**
82
+ * Hook for running compute functions
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * function FibonacciCalculator() {
87
+ * const { data, loading, error, run } = useCompute<number, number>('fibonacci');
88
+ *
89
+ * return (
90
+ * <div>
91
+ * <button onClick={() => run(50)} disabled={loading}>
92
+ * Calculate Fibonacci(50)
93
+ * </button>
94
+ * {loading && <p>Computing...</p>}
95
+ * {error && <p>Error: {error.message}</p>}
96
+ * {data !== null && <p>Result: {data}</p>}
97
+ * </div>
98
+ * );
99
+ * }
100
+ * ```
101
+ */
102
+ declare function useCompute<TInput = unknown, TOutput = unknown>(functionName: string, options?: UseComputeOptions): UseComputeReturn<TInput, TOutput>;
103
+ /**
104
+ * Hook that returns a memoized async function for compute operations
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * function Calculator() {
109
+ * const calculate = useComputeCallback<number[], number>('sum');
110
+ *
111
+ * const handleClick = async () => {
112
+ * const result = await calculate([1, 2, 3, 4, 5]);
113
+ * console.log(result);
114
+ * };
115
+ *
116
+ * return <button onClick={handleClick}>Calculate Sum</button>;
117
+ * }
118
+ * ```
119
+ */
120
+ declare function useComputeCallback<TInput = unknown, TOutput = unknown>(functionName: string, options?: ComputeOptions): (input: TInput, runOptions?: ComputeOptions) => Promise<TOutput>;
121
+ /**
122
+ * Hook to register and use a compute function
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * function MyComponent() {
127
+ * const { run, loading, data } = useComputeFunction(
128
+ * 'myFunction',
129
+ * (input: number) => input * 2
130
+ * );
131
+ *
132
+ * return (
133
+ * <button onClick={() => run(5)} disabled={loading}>
134
+ * {loading ? 'Computing...' : `Result: ${data}`}
135
+ * </button>
136
+ * );
137
+ * }
138
+ * ```
139
+ */
140
+ declare function useComputeFunction<TInput = unknown, TOutput = unknown>(name: string, fn: (input: TInput) => TOutput | Promise<TOutput>, options?: UseComputeOptions): UseComputeReturn<TInput, TOutput>;
141
+ /**
142
+ * Hook to get worker pool statistics
143
+ *
144
+ * @example
145
+ * ```tsx
146
+ * function PoolMonitor() {
147
+ * const stats = usePoolStats(1000); // Update every second
148
+ *
149
+ * return (
150
+ * <div>
151
+ * <p>Active Workers: {stats.activeWorkers}</p>
152
+ * <p>Queue Length: {stats.queueLength}</p>
153
+ * <p>Tasks Completed: {stats.tasksCompleted}</p>
154
+ * </div>
155
+ * );
156
+ * }
157
+ * ```
158
+ */
159
+ declare function usePoolStats(refreshInterval?: number): PoolStats;
160
+ /**
161
+ * Hook to check WASM support
162
+ */
163
+ declare function useWasmSupport(): boolean;
164
+
165
+ export { ComputeKitProvider, type ComputeKitProviderProps, type UseComputeActions, type UseComputeOptions, type UseComputeReturn, type UseComputeState, useCompute, useComputeCallback, useComputeFunction, useComputeKit, usePoolStats, useWasmSupport };
package/dist/index.js ADDED
@@ -0,0 +1,159 @@
1
+ import { createContext, useMemo, useEffect, useContext, useRef, useState, useCallback } from 'react';
2
+ import { ComputeKit } from '@computekit/core';
3
+ export { ComputeKit } from '@computekit/core';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/index.tsx
7
+ var ComputeKitContext = createContext(null);
8
+ function ComputeKitProvider({
9
+ options,
10
+ instance,
11
+ children
12
+ }) {
13
+ const kit = useMemo(() => {
14
+ return instance ?? new ComputeKit(options);
15
+ }, [instance, options]);
16
+ useEffect(() => {
17
+ return () => {
18
+ if (!instance) {
19
+ kit.terminate();
20
+ }
21
+ };
22
+ }, [kit, instance]);
23
+ return /* @__PURE__ */ jsx(ComputeKitContext.Provider, { value: kit, children });
24
+ }
25
+ function useComputeKit() {
26
+ const kit = useContext(ComputeKitContext);
27
+ if (!kit) {
28
+ throw new Error("useComputeKit must be used within a ComputeKitProvider");
29
+ }
30
+ return kit;
31
+ }
32
+ function useCompute(functionName, options = {}) {
33
+ const kit = useComputeKit();
34
+ const abortControllerRef = useRef(null);
35
+ const [state, setState] = useState({
36
+ data: null,
37
+ loading: false,
38
+ error: null,
39
+ progress: null
40
+ });
41
+ const reset = useCallback(() => {
42
+ setState({
43
+ data: null,
44
+ loading: false,
45
+ error: null,
46
+ progress: null
47
+ });
48
+ }, []);
49
+ const cancel = useCallback(() => {
50
+ if (abortControllerRef.current) {
51
+ abortControllerRef.current.abort();
52
+ abortControllerRef.current = null;
53
+ }
54
+ }, []);
55
+ const run = useCallback(
56
+ async (input, runOptions) => {
57
+ cancel();
58
+ const abortController = new AbortController();
59
+ abortControllerRef.current = abortController;
60
+ if (options.resetOnRun !== false) {
61
+ setState((prev) => ({
62
+ ...prev,
63
+ loading: true,
64
+ error: null,
65
+ progress: null
66
+ }));
67
+ } else {
68
+ setState((prev) => ({ ...prev, loading: true }));
69
+ }
70
+ try {
71
+ const result = await kit.run(functionName, input, {
72
+ ...options,
73
+ ...runOptions,
74
+ signal: runOptions?.signal ?? abortController.signal,
75
+ onProgress: (progress) => {
76
+ setState((prev) => ({ ...prev, progress }));
77
+ options.onProgress?.(progress);
78
+ runOptions?.onProgress?.(progress);
79
+ }
80
+ });
81
+ if (!abortController.signal.aborted) {
82
+ setState({
83
+ data: result,
84
+ loading: false,
85
+ error: null,
86
+ progress: null
87
+ });
88
+ }
89
+ } catch (err) {
90
+ if (!abortController.signal.aborted) {
91
+ setState({
92
+ data: null,
93
+ loading: false,
94
+ error: err instanceof Error ? err : new Error(String(err)),
95
+ progress: null
96
+ });
97
+ }
98
+ }
99
+ },
100
+ [kit, functionName, options, cancel]
101
+ );
102
+ useEffect(() => {
103
+ if (options.autoRun && options.initialInput !== void 0) {
104
+ run(options.initialInput);
105
+ }
106
+ }, []);
107
+ useEffect(() => {
108
+ return () => {
109
+ cancel();
110
+ };
111
+ }, [cancel]);
112
+ return {
113
+ ...state,
114
+ run,
115
+ reset,
116
+ cancel
117
+ };
118
+ }
119
+ function useComputeCallback(functionName, options) {
120
+ const kit = useComputeKit();
121
+ return useCallback(
122
+ (input, runOptions) => {
123
+ return kit.run(functionName, input, {
124
+ ...options,
125
+ ...runOptions
126
+ });
127
+ },
128
+ [kit, functionName, options]
129
+ );
130
+ }
131
+ function useComputeFunction(name, fn, options) {
132
+ const kit = useComputeKit();
133
+ useEffect(() => {
134
+ kit.register(name, fn);
135
+ }, [kit, name, fn]);
136
+ return useCompute(name, options);
137
+ }
138
+ function usePoolStats(refreshInterval = 0) {
139
+ const kit = useComputeKit();
140
+ const [stats, setStats] = useState(() => kit.getStats());
141
+ useEffect(() => {
142
+ if (refreshInterval <= 0) {
143
+ return;
144
+ }
145
+ const interval = setInterval(() => {
146
+ setStats(kit.getStats());
147
+ }, refreshInterval);
148
+ return () => clearInterval(interval);
149
+ }, [kit, refreshInterval]);
150
+ return stats;
151
+ }
152
+ function useWasmSupport() {
153
+ const kit = useComputeKit();
154
+ return kit.isWasmSupported();
155
+ }
156
+
157
+ export { ComputeKitProvider, useCompute, useComputeCallback, useComputeFunction, useComputeKit, usePoolStats, useWasmSupport };
158
+ //# sourceMappingURL=index.js.map
159
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@computekit/react",
3
+ "version": "0.1.0",
4
+ "description": "React bindings for ComputeKit - WASM + Worker toolkit",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "dev": "tsup --watch",
23
+ "test": "vitest",
24
+ "typecheck": "tsc --noEmit"
25
+ },
26
+ "dependencies": {
27
+ "@computekit/core": "*"
28
+ },
29
+ "peerDependencies": {
30
+ "react": ">=17.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "^18.2.45",
34
+ "react": "^18.2.0",
35
+ "tsup": "^8.0.1",
36
+ "typescript": "^5.3.3",
37
+ "vitest": "^1.1.0"
38
+ },
39
+ "keywords": [
40
+ "react",
41
+ "wasm",
42
+ "webassembly",
43
+ "workers",
44
+ "hooks",
45
+ "compute",
46
+ "performance"
47
+ ],
48
+ "author": "Ghassen Lassoued <https://github.com/tapava>",
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/tapava/compute-kit",
53
+ "directory": "packages/react"
54
+ },
55
+ "sideEffects": false
56
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,410 @@
1
+ /**
2
+ * ComputeKit React Bindings
3
+ * React hooks and utilities for ComputeKit
4
+ */
5
+
6
+ import {
7
+ useState,
8
+ useEffect,
9
+ useCallback,
10
+ useRef,
11
+ useMemo,
12
+ createContext,
13
+ useContext,
14
+ type ReactNode,
15
+ } from 'react';
16
+
17
+ import {
18
+ ComputeKit,
19
+ type ComputeKitOptions,
20
+ type ComputeOptions,
21
+ type ComputeProgress,
22
+ type PoolStats,
23
+ } from '@computekit/core';
24
+
25
+ // ============================================================================
26
+ // Context
27
+ // ============================================================================
28
+
29
+ const ComputeKitContext = createContext<ComputeKit | null>(null);
30
+
31
+ /**
32
+ * Props for ComputeKitProvider
33
+ */
34
+ export interface ComputeKitProviderProps {
35
+ /** ComputeKit options */
36
+ options?: ComputeKitOptions;
37
+ /** Custom ComputeKit instance */
38
+ instance?: ComputeKit;
39
+ /** Children */
40
+ children: ReactNode;
41
+ }
42
+
43
+ /**
44
+ * Provider component for ComputeKit
45
+ *
46
+ * @example
47
+ * ```tsx
48
+ * import { ComputeKitProvider } from '@computekit/react';
49
+ *
50
+ * function App() {
51
+ * return (
52
+ * <ComputeKitProvider options={{ maxWorkers: 4 }}>
53
+ * <MyApp />
54
+ * </ComputeKitProvider>
55
+ * );
56
+ * }
57
+ * ```
58
+ */
59
+ export function ComputeKitProvider({
60
+ options,
61
+ instance,
62
+ children,
63
+ }: ComputeKitProviderProps): JSX.Element {
64
+ const kit = useMemo(() => {
65
+ return instance ?? new ComputeKit(options);
66
+ }, [instance, options]);
67
+
68
+ useEffect(() => {
69
+ return () => {
70
+ // Only terminate if we created the instance
71
+ if (!instance) {
72
+ kit.terminate();
73
+ }
74
+ };
75
+ }, [kit, instance]);
76
+
77
+ return <ComputeKitContext.Provider value={kit}>{children}</ComputeKitContext.Provider>;
78
+ }
79
+
80
+ /**
81
+ * Get the ComputeKit instance from context
82
+ */
83
+ export function useComputeKit(): ComputeKit {
84
+ const kit = useContext(ComputeKitContext);
85
+ if (!kit) {
86
+ throw new Error('useComputeKit must be used within a ComputeKitProvider');
87
+ }
88
+ return kit;
89
+ }
90
+
91
+ // ============================================================================
92
+ // useCompute Hook
93
+ // ============================================================================
94
+
95
+ /**
96
+ * State returned by useCompute
97
+ */
98
+ export interface UseComputeState<T> {
99
+ /** The computed result */
100
+ data: T | null;
101
+ /** Loading state */
102
+ loading: boolean;
103
+ /** Error if computation failed */
104
+ error: Error | null;
105
+ /** Progress information */
106
+ progress: ComputeProgress | null;
107
+ }
108
+
109
+ /**
110
+ * Actions returned by useCompute
111
+ */
112
+ export interface UseComputeActions<TInput> {
113
+ /** Execute the compute function */
114
+ run: (input: TInput, options?: ComputeOptions) => Promise<void>;
115
+ /** Reset the state */
116
+ reset: () => void;
117
+ /** Cancel ongoing computation */
118
+ cancel: () => void;
119
+ }
120
+
121
+ /**
122
+ * Return type for useCompute
123
+ */
124
+ export type UseComputeReturn<TInput, TOutput> = UseComputeState<TOutput> &
125
+ UseComputeActions<TInput>;
126
+
127
+ /**
128
+ * Options for useCompute hook
129
+ */
130
+ export interface UseComputeOptions extends ComputeOptions {
131
+ /** Automatically run on mount with initial input */
132
+ autoRun?: boolean;
133
+ /** Initial input for autoRun */
134
+ initialInput?: unknown;
135
+ /** Reset state on new run */
136
+ resetOnRun?: boolean;
137
+ }
138
+
139
+ /**
140
+ * Hook for running compute functions
141
+ *
142
+ * @example
143
+ * ```tsx
144
+ * function FibonacciCalculator() {
145
+ * const { data, loading, error, run } = useCompute<number, number>('fibonacci');
146
+ *
147
+ * return (
148
+ * <div>
149
+ * <button onClick={() => run(50)} disabled={loading}>
150
+ * Calculate Fibonacci(50)
151
+ * </button>
152
+ * {loading && <p>Computing...</p>}
153
+ * {error && <p>Error: {error.message}</p>}
154
+ * {data !== null && <p>Result: {data}</p>}
155
+ * </div>
156
+ * );
157
+ * }
158
+ * ```
159
+ */
160
+ export function useCompute<TInput = unknown, TOutput = unknown>(
161
+ functionName: string,
162
+ options: UseComputeOptions = {}
163
+ ): UseComputeReturn<TInput, TOutput> {
164
+ const kit = useComputeKit();
165
+ const abortControllerRef = useRef<AbortController | null>(null);
166
+
167
+ const [state, setState] = useState<UseComputeState<TOutput>>({
168
+ data: null,
169
+ loading: false,
170
+ error: null,
171
+ progress: null,
172
+ });
173
+
174
+ const reset = useCallback(() => {
175
+ setState({
176
+ data: null,
177
+ loading: false,
178
+ error: null,
179
+ progress: null,
180
+ });
181
+ }, []);
182
+
183
+ const cancel = useCallback(() => {
184
+ if (abortControllerRef.current) {
185
+ abortControllerRef.current.abort();
186
+ abortControllerRef.current = null;
187
+ }
188
+ }, []);
189
+
190
+ const run = useCallback(
191
+ async (input: TInput, runOptions?: ComputeOptions) => {
192
+ // Cancel any ongoing computation
193
+ cancel();
194
+
195
+ // Create new abort controller
196
+ const abortController = new AbortController();
197
+ abortControllerRef.current = abortController;
198
+
199
+ // Reset state if configured
200
+ if (options.resetOnRun !== false) {
201
+ setState((prev) => ({
202
+ ...prev,
203
+ loading: true,
204
+ error: null,
205
+ progress: null,
206
+ }));
207
+ } else {
208
+ setState((prev) => ({ ...prev, loading: true }));
209
+ }
210
+
211
+ try {
212
+ const result = await kit.run<TInput, TOutput>(functionName, input, {
213
+ ...options,
214
+ ...runOptions,
215
+ signal: runOptions?.signal ?? abortController.signal,
216
+ onProgress: (progress) => {
217
+ setState((prev) => ({ ...prev, progress }));
218
+ options.onProgress?.(progress);
219
+ runOptions?.onProgress?.(progress);
220
+ },
221
+ });
222
+
223
+ if (!abortController.signal.aborted) {
224
+ setState({
225
+ data: result,
226
+ loading: false,
227
+ error: null,
228
+ progress: null,
229
+ });
230
+ }
231
+ } catch (err) {
232
+ if (!abortController.signal.aborted) {
233
+ setState({
234
+ data: null,
235
+ loading: false,
236
+ error: err instanceof Error ? err : new Error(String(err)),
237
+ progress: null,
238
+ });
239
+ }
240
+ }
241
+ },
242
+ [kit, functionName, options, cancel]
243
+ );
244
+
245
+ // Auto-run on mount if configured
246
+ useEffect(() => {
247
+ if (options.autoRun && options.initialInput !== undefined) {
248
+ run(options.initialInput as TInput);
249
+ }
250
+ // Only run on mount
251
+ // eslint-disable-next-line react-hooks/exhaustive-deps
252
+ }, []);
253
+
254
+ // Cleanup on unmount
255
+ useEffect(() => {
256
+ return () => {
257
+ cancel();
258
+ };
259
+ }, [cancel]);
260
+
261
+ return {
262
+ ...state,
263
+ run,
264
+ reset,
265
+ cancel,
266
+ };
267
+ }
268
+
269
+ // ============================================================================
270
+ // useComputeCallback Hook
271
+ // ============================================================================
272
+
273
+ /**
274
+ * Hook that returns a memoized async function for compute operations
275
+ *
276
+ * @example
277
+ * ```tsx
278
+ * function Calculator() {
279
+ * const calculate = useComputeCallback<number[], number>('sum');
280
+ *
281
+ * const handleClick = async () => {
282
+ * const result = await calculate([1, 2, 3, 4, 5]);
283
+ * console.log(result);
284
+ * };
285
+ *
286
+ * return <button onClick={handleClick}>Calculate Sum</button>;
287
+ * }
288
+ * ```
289
+ */
290
+ export function useComputeCallback<TInput = unknown, TOutput = unknown>(
291
+ functionName: string,
292
+ options?: ComputeOptions
293
+ ): (input: TInput, runOptions?: ComputeOptions) => Promise<TOutput> {
294
+ const kit = useComputeKit();
295
+
296
+ return useCallback(
297
+ (input: TInput, runOptions?: ComputeOptions) => {
298
+ return kit.run<TInput, TOutput>(functionName, input, {
299
+ ...options,
300
+ ...runOptions,
301
+ });
302
+ },
303
+ [kit, functionName, options]
304
+ );
305
+ }
306
+
307
+ // ============================================================================
308
+ // useComputeFunction Hook
309
+ // ============================================================================
310
+
311
+ /**
312
+ * Hook to register and use a compute function
313
+ *
314
+ * @example
315
+ * ```tsx
316
+ * function MyComponent() {
317
+ * const { run, loading, data } = useComputeFunction(
318
+ * 'myFunction',
319
+ * (input: number) => input * 2
320
+ * );
321
+ *
322
+ * return (
323
+ * <button onClick={() => run(5)} disabled={loading}>
324
+ * {loading ? 'Computing...' : `Result: ${data}`}
325
+ * </button>
326
+ * );
327
+ * }
328
+ * ```
329
+ */
330
+ export function useComputeFunction<TInput = unknown, TOutput = unknown>(
331
+ name: string,
332
+ fn: (input: TInput) => TOutput | Promise<TOutput>,
333
+ options?: UseComputeOptions
334
+ ): UseComputeReturn<TInput, TOutput> {
335
+ const kit = useComputeKit();
336
+
337
+ // Register function on mount
338
+ useEffect(() => {
339
+ kit.register(name, fn);
340
+ }, [kit, name, fn]);
341
+
342
+ return useCompute<TInput, TOutput>(name, options);
343
+ }
344
+
345
+ // ============================================================================
346
+ // usePoolStats Hook
347
+ // ============================================================================
348
+
349
+ /**
350
+ * Hook to get worker pool statistics
351
+ *
352
+ * @example
353
+ * ```tsx
354
+ * function PoolMonitor() {
355
+ * const stats = usePoolStats(1000); // Update every second
356
+ *
357
+ * return (
358
+ * <div>
359
+ * <p>Active Workers: {stats.activeWorkers}</p>
360
+ * <p>Queue Length: {stats.queueLength}</p>
361
+ * <p>Tasks Completed: {stats.tasksCompleted}</p>
362
+ * </div>
363
+ * );
364
+ * }
365
+ * ```
366
+ */
367
+ export function usePoolStats(refreshInterval: number = 0): PoolStats {
368
+ const kit = useComputeKit();
369
+ const [stats, setStats] = useState<PoolStats>(() => kit.getStats());
370
+
371
+ useEffect(() => {
372
+ // For one-time fetch (refreshInterval <= 0), we rely on the initial state
373
+ if (refreshInterval <= 0) {
374
+ return;
375
+ }
376
+
377
+ const interval = setInterval(() => {
378
+ setStats(kit.getStats());
379
+ }, refreshInterval);
380
+
381
+ return () => clearInterval(interval);
382
+ }, [kit, refreshInterval]);
383
+
384
+ return stats;
385
+ }
386
+
387
+ // ============================================================================
388
+ // useWasmSupport Hook
389
+ // ============================================================================
390
+
391
+ /**
392
+ * Hook to check WASM support
393
+ */
394
+ export function useWasmSupport(): boolean {
395
+ const kit = useComputeKit();
396
+ return kit.isWasmSupported();
397
+ }
398
+
399
+ // ============================================================================
400
+ // Exports
401
+ // ============================================================================
402
+
403
+ export type {
404
+ ComputeKitOptions,
405
+ ComputeOptions,
406
+ ComputeProgress,
407
+ PoolStats,
408
+ } from '@computekit/core';
409
+
410
+ export { ComputeKit } from '@computekit/core';