@enclave-vm/react 0.0.1
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/package.json +40 -0
- package/src/EnclaveProvider.d.ts +60 -0
- package/src/EnclaveProvider.js +97 -0
- package/src/EnclaveProvider.js.map +1 -0
- package/src/index.d.ts +11 -0
- package/src/index.js +19 -0
- package/src/index.js.map +1 -0
- package/src/test-setup.d.ts +4 -0
- package/src/test-setup.js +7 -0
- package/src/test-setup.js.map +1 -0
- package/src/types.d.ts +142 -0
- package/src/types.js +10 -0
- package/src/types.js.map +1 -0
- package/src/useEnclaveSession.d.ts +38 -0
- package/src/useEnclaveSession.js +181 -0
- package/src/useEnclaveSession.js.map +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@enclave-vm/react",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "React hooks and components for the EnclaveJS streaming runtime",
|
|
5
|
+
"author": "AgentFront <info@agentfront.dev>",
|
|
6
|
+
"homepage": "https://github.com/agentfront/enclave",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"enclavejs",
|
|
10
|
+
"enclave",
|
|
11
|
+
"react",
|
|
12
|
+
"hooks",
|
|
13
|
+
"streaming",
|
|
14
|
+
"runtime"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/agentfront/enclave.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/agentfront/enclave/issues"
|
|
22
|
+
},
|
|
23
|
+
"main": "./src/index.js",
|
|
24
|
+
"types": "./src/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
"./package.json": "./package.json",
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./src/index.d.ts",
|
|
29
|
+
"import": "./src/index.js",
|
|
30
|
+
"default": "./src/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@enclave-vm/client": "0.0.1"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": ">=17.0.0"
|
|
38
|
+
},
|
|
39
|
+
"type": "commonjs"
|
|
40
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnclaveProvider
|
|
3
|
+
*
|
|
4
|
+
* React context provider for the EnclaveJS client.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { EnclaveClient } from '@enclave-vm/client';
|
|
10
|
+
import type { EnclaveProviderProps, EnclaveContextValue } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* React context for the Enclave client
|
|
13
|
+
*/
|
|
14
|
+
declare const EnclaveContext: React.Context<EnclaveContextValue | null>;
|
|
15
|
+
/**
|
|
16
|
+
* EnclaveProvider component
|
|
17
|
+
*
|
|
18
|
+
* Provides the EnclaveClient to child components via React context.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* function App() {
|
|
23
|
+
* return (
|
|
24
|
+
* <EnclaveProvider config={{ baseUrl: 'https://api.example.com' }}>
|
|
25
|
+
* <MyComponent />
|
|
26
|
+
* </EnclaveProvider>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function EnclaveProvider({ config, client: providedClient, children, }: EnclaveProviderProps): React.ReactElement;
|
|
32
|
+
/**
|
|
33
|
+
* useEnclaveContext hook
|
|
34
|
+
*
|
|
35
|
+
* Access the Enclave context directly. Throws if used outside EnclaveProvider.
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare function useEnclaveContext(): EnclaveContextValue;
|
|
40
|
+
/**
|
|
41
|
+
* useEnclaveClient hook
|
|
42
|
+
*
|
|
43
|
+
* Get the EnclaveClient instance from context.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* function MyComponent() {
|
|
48
|
+
* const client = useEnclaveClient();
|
|
49
|
+
*
|
|
50
|
+
* const handleClick = async () => {
|
|
51
|
+
* const result = await client.execute('return 1 + 1');
|
|
52
|
+
* console.log(result.value);
|
|
53
|
+
* };
|
|
54
|
+
*
|
|
55
|
+
* return <button onClick={handleClick}>Execute</button>;
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function useEnclaveClient(): EnclaveClient;
|
|
60
|
+
export { EnclaveContext };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EnclaveContext = void 0;
|
|
4
|
+
exports.EnclaveProvider = EnclaveProvider;
|
|
5
|
+
exports.useEnclaveContext = useEnclaveContext;
|
|
6
|
+
exports.useEnclaveClient = useEnclaveClient;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
/**
|
|
9
|
+
* EnclaveProvider
|
|
10
|
+
*
|
|
11
|
+
* React context provider for the EnclaveJS client.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
const react_1 = require("react");
|
|
16
|
+
const client_1 = require("@enclave-vm/client");
|
|
17
|
+
/**
|
|
18
|
+
* React context for the Enclave client
|
|
19
|
+
*/
|
|
20
|
+
const EnclaveContext = (0, react_1.createContext)(null);
|
|
21
|
+
exports.EnclaveContext = EnclaveContext;
|
|
22
|
+
/**
|
|
23
|
+
* EnclaveProvider component
|
|
24
|
+
*
|
|
25
|
+
* Provides the EnclaveClient to child components via React context.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* function App() {
|
|
30
|
+
* return (
|
|
31
|
+
* <EnclaveProvider config={{ baseUrl: 'https://api.example.com' }}>
|
|
32
|
+
* <MyComponent />
|
|
33
|
+
* </EnclaveProvider>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
function EnclaveProvider({ config, client: providedClient, children, }) {
|
|
39
|
+
// Use ref to ensure client is only created once
|
|
40
|
+
const clientRef = (0, react_1.useRef)(null);
|
|
41
|
+
// Create or use provided client
|
|
42
|
+
const client = (0, react_1.useMemo)(() => {
|
|
43
|
+
if (providedClient) {
|
|
44
|
+
return providedClient;
|
|
45
|
+
}
|
|
46
|
+
// Create new client if not already created
|
|
47
|
+
if (!clientRef.current) {
|
|
48
|
+
clientRef.current = new client_1.EnclaveClient(config);
|
|
49
|
+
}
|
|
50
|
+
return clientRef.current;
|
|
51
|
+
}, [providedClient, config]);
|
|
52
|
+
// Memoize context value
|
|
53
|
+
const contextValue = (0, react_1.useMemo)(() => ({
|
|
54
|
+
client,
|
|
55
|
+
config,
|
|
56
|
+
}), [client, config]);
|
|
57
|
+
return (0, jsx_runtime_1.jsx)(EnclaveContext.Provider, { value: contextValue, children: children });
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* useEnclaveContext hook
|
|
61
|
+
*
|
|
62
|
+
* Access the Enclave context directly. Throws if used outside EnclaveProvider.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
function useEnclaveContext() {
|
|
67
|
+
const context = (0, react_1.useContext)(EnclaveContext);
|
|
68
|
+
if (!context) {
|
|
69
|
+
throw new Error('useEnclaveContext must be used within an EnclaveProvider. ' +
|
|
70
|
+
'Wrap your component tree with <EnclaveProvider config={{...}}>.');
|
|
71
|
+
}
|
|
72
|
+
return context;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* useEnclaveClient hook
|
|
76
|
+
*
|
|
77
|
+
* Get the EnclaveClient instance from context.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```tsx
|
|
81
|
+
* function MyComponent() {
|
|
82
|
+
* const client = useEnclaveClient();
|
|
83
|
+
*
|
|
84
|
+
* const handleClick = async () => {
|
|
85
|
+
* const result = await client.execute('return 1 + 1');
|
|
86
|
+
* console.log(result.value);
|
|
87
|
+
* };
|
|
88
|
+
*
|
|
89
|
+
* return <button onClick={handleClick}>Execute</button>;
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
function useEnclaveClient() {
|
|
94
|
+
const { client } = useEnclaveContext();
|
|
95
|
+
return client;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=EnclaveProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnclaveProvider.js","sourceRoot":"","sources":["../../src/EnclaveProvider.tsx"],"names":[],"mappings":";;;AAiCA,0CAgCC;AASD,8CAWC;AAqBD,4CAGC;;AA7GD;;;;;;GAMG;AAEH,iCAA0E;AAC1E,+CAAmD;AAGnD;;GAEG;AACH,MAAM,cAAc,GAAG,IAAA,qBAAa,EAA6B,IAAI,CAAC,CAAC;AAgG9D,wCAAc;AA9FvB;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,MAAM,EAAE,cAAc,EACtB,QAAQ,GACa;IACrB,gDAAgD;IAChD,MAAM,SAAS,GAAG,IAAA,cAAM,EAAuB,IAAI,CAAC,CAAC;IAErD,gCAAgC;IAChC,MAAM,MAAM,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE;QAC1B,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,2CAA2C;QAC3C,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACvB,SAAS,CAAC,OAAO,GAAG,IAAI,sBAAa,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,SAAS,CAAC,OAAO,CAAC;IAC3B,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;IAE7B,wBAAwB;IACxB,MAAM,YAAY,GAAG,IAAA,eAAO,EAC1B,GAAG,EAAE,CAAC,CAAC;QACL,MAAM;QACN,MAAM;KACP,CAAC,EACF,CAAC,MAAM,EAAE,MAAM,CAAC,CACjB,CAAC;IAEF,OAAO,uBAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YAAG,QAAQ,GAA2B,CAAC;AAC5F,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB;IAC/B,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,cAAc,CAAC,CAAC;IAE3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,4DAA4D;YAC1D,iEAAiE,CACpE,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,gBAAgB;IAC9B,MAAM,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["/**\n * EnclaveProvider\n *\n * React context provider for the EnclaveJS client.\n *\n * @packageDocumentation\n */\n\nimport React, { createContext, useContext, useMemo, useRef } from 'react';\nimport { EnclaveClient } from '@enclave-vm/client';\nimport type { EnclaveProviderProps, EnclaveContextValue } from './types.js';\n\n/**\n * React context for the Enclave client\n */\nconst EnclaveContext = createContext<EnclaveContextValue | null>(null);\n\n/**\n * EnclaveProvider component\n *\n * Provides the EnclaveClient to child components via React context.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <EnclaveProvider config={{ baseUrl: 'https://api.example.com' }}>\n * <MyComponent />\n * </EnclaveProvider>\n * );\n * }\n * ```\n */\nexport function EnclaveProvider({\n config,\n client: providedClient,\n children,\n}: EnclaveProviderProps): React.ReactElement {\n // Use ref to ensure client is only created once\n const clientRef = useRef<EnclaveClient | null>(null);\n\n // Create or use provided client\n const client = useMemo(() => {\n if (providedClient) {\n return providedClient;\n }\n\n // Create new client if not already created\n if (!clientRef.current) {\n clientRef.current = new EnclaveClient(config);\n }\n\n return clientRef.current;\n }, [providedClient, config]);\n\n // Memoize context value\n const contextValue = useMemo<EnclaveContextValue>(\n () => ({\n client,\n config,\n }),\n [client, config],\n );\n\n return <EnclaveContext.Provider value={contextValue}>{children}</EnclaveContext.Provider>;\n}\n\n/**\n * useEnclaveContext hook\n *\n * Access the Enclave context directly. Throws if used outside EnclaveProvider.\n *\n * @internal\n */\nexport function useEnclaveContext(): EnclaveContextValue {\n const context = useContext(EnclaveContext);\n\n if (!context) {\n throw new Error(\n 'useEnclaveContext must be used within an EnclaveProvider. ' +\n 'Wrap your component tree with <EnclaveProvider config={{...}}>.',\n );\n }\n\n return context;\n}\n\n/**\n * useEnclaveClient hook\n *\n * Get the EnclaveClient instance from context.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useEnclaveClient();\n *\n * const handleClick = async () => {\n * const result = await client.execute('return 1 + 1');\n * console.log(result.value);\n * };\n *\n * return <button onClick={handleClick}>Execute</button>;\n * }\n * ```\n */\nexport function useEnclaveClient(): EnclaveClient {\n const { client } = useEnclaveContext();\n return client;\n}\n\nexport { EnclaveContext };\n"]}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @enclave-vm/react
|
|
3
|
+
*
|
|
4
|
+
* React hooks and components for the EnclaveJS streaming runtime.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
export { EnclaveProvider, useEnclaveClient, useEnclaveContext } from './EnclaveProvider.js';
|
|
9
|
+
export { useEnclaveSession } from './useEnclaveSession.js';
|
|
10
|
+
export type { SessionState, UseEnclaveSessionOptions, UseEnclaveSessionReturn, EnclaveProviderProps, EnclaveContextValue, } from './types.js';
|
|
11
|
+
export type { EnclaveClient, EnclaveClientConfig, SessionResult, SessionHandle, StreamEvent, SessionId, } from '@enclave-vm/client';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @enclave-vm/react
|
|
4
|
+
*
|
|
5
|
+
* React hooks and components for the EnclaveJS streaming runtime.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.useEnclaveSession = exports.useEnclaveContext = exports.useEnclaveClient = exports.EnclaveProvider = void 0;
|
|
11
|
+
// Provider and context
|
|
12
|
+
var EnclaveProvider_js_1 = require("./EnclaveProvider.js");
|
|
13
|
+
Object.defineProperty(exports, "EnclaveProvider", { enumerable: true, get: function () { return EnclaveProvider_js_1.EnclaveProvider; } });
|
|
14
|
+
Object.defineProperty(exports, "useEnclaveClient", { enumerable: true, get: function () { return EnclaveProvider_js_1.useEnclaveClient; } });
|
|
15
|
+
Object.defineProperty(exports, "useEnclaveContext", { enumerable: true, get: function () { return EnclaveProvider_js_1.useEnclaveContext; } });
|
|
16
|
+
// Hooks
|
|
17
|
+
var useEnclaveSession_js_1 = require("./useEnclaveSession.js");
|
|
18
|
+
Object.defineProperty(exports, "useEnclaveSession", { enumerable: true, get: function () { return useEnclaveSession_js_1.useEnclaveSession; } });
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,uBAAuB;AACvB,2DAA4F;AAAnF,qHAAA,eAAe,OAAA;AAAE,sHAAA,gBAAgB,OAAA;AAAE,uHAAA,iBAAiB,OAAA;AAE7D,QAAQ;AACR,+DAA2D;AAAlD,yHAAA,iBAAiB,OAAA","sourcesContent":["/**\n * @enclave-vm/react\n *\n * React hooks and components for the EnclaveJS streaming runtime.\n *\n * @packageDocumentation\n */\n\n// Provider and context\nexport { EnclaveProvider, useEnclaveClient, useEnclaveContext } from './EnclaveProvider.js';\n\n// Hooks\nexport { useEnclaveSession } from './useEnclaveSession.js';\n\n// Types\nexport type {\n SessionState,\n UseEnclaveSessionOptions,\n UseEnclaveSessionReturn,\n EnclaveProviderProps,\n EnclaveContextValue,\n} from './types.js';\n\n// Re-export commonly used types from @enclave-vm/client\nexport type {\n EnclaveClient,\n EnclaveClientConfig,\n SessionResult,\n SessionHandle,\n StreamEvent,\n SessionId,\n} from '@enclave-vm/client';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-setup.js","sourceRoot":"","sources":["../../src/test-setup.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAEH,qCAAmC","sourcesContent":["/**\n * Test setup for React Testing Library\n */\n\nimport '@testing-library/jest-dom';\n"]}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Types
|
|
3
|
+
*
|
|
4
|
+
* Types for the EnclaveJS React hooks and components.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { EnclaveClient, EnclaveClientConfig, SessionResult, StreamEvent, SessionId } from '@enclave-vm/client';
|
|
9
|
+
/**
|
|
10
|
+
* Session state enum
|
|
11
|
+
*/
|
|
12
|
+
export type SessionState = 'idle' | 'running' | 'completed' | 'error' | 'cancelled';
|
|
13
|
+
/**
|
|
14
|
+
* useEnclaveSession hook options
|
|
15
|
+
*/
|
|
16
|
+
export interface UseEnclaveSessionOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Custom session ID (generated if not provided)
|
|
19
|
+
*/
|
|
20
|
+
sessionId?: SessionId;
|
|
21
|
+
/**
|
|
22
|
+
* Session timeout in milliseconds
|
|
23
|
+
*/
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Maximum number of tool calls
|
|
27
|
+
*/
|
|
28
|
+
maxToolCalls?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Heartbeat interval in milliseconds
|
|
31
|
+
*/
|
|
32
|
+
heartbeatIntervalMs?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Callback when session starts
|
|
35
|
+
*/
|
|
36
|
+
onStart?: () => void;
|
|
37
|
+
/**
|
|
38
|
+
* Callback for stdout output
|
|
39
|
+
*/
|
|
40
|
+
onStdout?: (chunk: string) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Callback for log messages
|
|
43
|
+
*/
|
|
44
|
+
onLog?: (level: string, message: string, data?: Record<string, unknown>) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Callback for tool calls
|
|
47
|
+
*/
|
|
48
|
+
onToolCall?: (callId: string, toolName: string, args: unknown) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Callback when tool result is applied
|
|
51
|
+
*/
|
|
52
|
+
onToolResultApplied?: (callId: string) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Callback on completion
|
|
55
|
+
*/
|
|
56
|
+
onComplete?: (result: SessionResult) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Callback on error
|
|
59
|
+
*/
|
|
60
|
+
onError?: (error: {
|
|
61
|
+
code?: string;
|
|
62
|
+
message: string;
|
|
63
|
+
}) => void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* useEnclaveSession hook return type
|
|
67
|
+
*/
|
|
68
|
+
export interface UseEnclaveSessionReturn<T = unknown> {
|
|
69
|
+
/**
|
|
70
|
+
* Execute code in the enclave
|
|
71
|
+
*/
|
|
72
|
+
execute: (code: string) => Promise<SessionResult<T>>;
|
|
73
|
+
/**
|
|
74
|
+
* Cancel the current session
|
|
75
|
+
*/
|
|
76
|
+
cancel: (reason?: string) => Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Current session state
|
|
79
|
+
*/
|
|
80
|
+
state: SessionState;
|
|
81
|
+
/**
|
|
82
|
+
* Whether a session is currently running
|
|
83
|
+
*/
|
|
84
|
+
isRunning: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Current session ID (if running)
|
|
87
|
+
*/
|
|
88
|
+
sessionId: SessionId | null;
|
|
89
|
+
/**
|
|
90
|
+
* Result of the last execution (if completed)
|
|
91
|
+
*/
|
|
92
|
+
result: SessionResult<T> | null;
|
|
93
|
+
/**
|
|
94
|
+
* Error from the last execution (if failed)
|
|
95
|
+
*/
|
|
96
|
+
error: {
|
|
97
|
+
code?: string;
|
|
98
|
+
message: string;
|
|
99
|
+
} | null;
|
|
100
|
+
/**
|
|
101
|
+
* Stdout output accumulated during execution
|
|
102
|
+
*/
|
|
103
|
+
stdout: string;
|
|
104
|
+
/**
|
|
105
|
+
* Events received during execution
|
|
106
|
+
*/
|
|
107
|
+
events: StreamEvent[];
|
|
108
|
+
/**
|
|
109
|
+
* Reset the hook state
|
|
110
|
+
*/
|
|
111
|
+
reset: () => void;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* EnclaveProvider props
|
|
115
|
+
*/
|
|
116
|
+
export interface EnclaveProviderProps {
|
|
117
|
+
/**
|
|
118
|
+
* Client configuration
|
|
119
|
+
*/
|
|
120
|
+
config: EnclaveClientConfig;
|
|
121
|
+
/**
|
|
122
|
+
* Pre-created client instance (alternative to config)
|
|
123
|
+
*/
|
|
124
|
+
client?: EnclaveClient;
|
|
125
|
+
/**
|
|
126
|
+
* Children to render
|
|
127
|
+
*/
|
|
128
|
+
children: React.ReactNode;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Enclave context value
|
|
132
|
+
*/
|
|
133
|
+
export interface EnclaveContextValue {
|
|
134
|
+
/**
|
|
135
|
+
* The EnclaveClient instance
|
|
136
|
+
*/
|
|
137
|
+
client: EnclaveClient;
|
|
138
|
+
/**
|
|
139
|
+
* Client configuration
|
|
140
|
+
*/
|
|
141
|
+
config: EnclaveClientConfig;
|
|
142
|
+
}
|
package/src/types.js
ADDED
package/src/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG","sourcesContent":["/**\n * React Types\n *\n * Types for the EnclaveJS React hooks and components.\n *\n * @packageDocumentation\n */\n\nimport type { EnclaveClient, EnclaveClientConfig, SessionResult, StreamEvent, SessionId } from '@enclave-vm/client';\n\n/**\n * Session state enum\n */\nexport type SessionState = 'idle' | 'running' | 'completed' | 'error' | 'cancelled';\n\n/**\n * useEnclaveSession hook options\n */\nexport interface UseEnclaveSessionOptions {\n /**\n * Custom session ID (generated if not provided)\n */\n sessionId?: SessionId;\n\n /**\n * Session timeout in milliseconds\n */\n timeoutMs?: number;\n\n /**\n * Maximum number of tool calls\n */\n maxToolCalls?: number;\n\n /**\n * Heartbeat interval in milliseconds\n */\n heartbeatIntervalMs?: number;\n\n /**\n * Callback when session starts\n */\n onStart?: () => void;\n\n /**\n * Callback for stdout output\n */\n onStdout?: (chunk: string) => void;\n\n /**\n * Callback for log messages\n */\n onLog?: (level: string, message: string, data?: Record<string, unknown>) => void;\n\n /**\n * Callback for tool calls\n */\n onToolCall?: (callId: string, toolName: string, args: unknown) => void;\n\n /**\n * Callback when tool result is applied\n */\n onToolResultApplied?: (callId: string) => void;\n\n /**\n * Callback on completion\n */\n onComplete?: (result: SessionResult) => void;\n\n /**\n * Callback on error\n */\n onError?: (error: { code?: string; message: string }) => void;\n}\n\n/**\n * useEnclaveSession hook return type\n */\nexport interface UseEnclaveSessionReturn<T = unknown> {\n /**\n * Execute code in the enclave\n */\n execute: (code: string) => Promise<SessionResult<T>>;\n\n /**\n * Cancel the current session\n */\n cancel: (reason?: string) => Promise<void>;\n\n /**\n * Current session state\n */\n state: SessionState;\n\n /**\n * Whether a session is currently running\n */\n isRunning: boolean;\n\n /**\n * Current session ID (if running)\n */\n sessionId: SessionId | null;\n\n /**\n * Result of the last execution (if completed)\n */\n result: SessionResult<T> | null;\n\n /**\n * Error from the last execution (if failed)\n */\n error: { code?: string; message: string } | null;\n\n /**\n * Stdout output accumulated during execution\n */\n stdout: string;\n\n /**\n * Events received during execution\n */\n events: StreamEvent[];\n\n /**\n * Reset the hook state\n */\n reset: () => void;\n}\n\n/**\n * EnclaveProvider props\n */\nexport interface EnclaveProviderProps {\n /**\n * Client configuration\n */\n config: EnclaveClientConfig;\n\n /**\n * Pre-created client instance (alternative to config)\n */\n client?: EnclaveClient;\n\n /**\n * Children to render\n */\n children: React.ReactNode;\n}\n\n/**\n * Enclave context value\n */\nexport interface EnclaveContextValue {\n /**\n * The EnclaveClient instance\n */\n client: EnclaveClient;\n\n /**\n * Client configuration\n */\n config: EnclaveClientConfig;\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useEnclaveSession Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for executing code in the EnclaveJS runtime with state management.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { UseEnclaveSessionOptions, UseEnclaveSessionReturn } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* useEnclaveSession hook
|
|
11
|
+
*
|
|
12
|
+
* Provides a stateful interface for executing code in the Enclave runtime.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* function Calculator() {
|
|
17
|
+
* const { execute, isRunning, result, stdout } = useEnclaveSession({
|
|
18
|
+
* onStdout: (chunk) => console.log(chunk),
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* const calculate = async () => {
|
|
22
|
+
* const result = await execute('return 1 + 1');
|
|
23
|
+
* console.log('Result:', result.value);
|
|
24
|
+
* };
|
|
25
|
+
*
|
|
26
|
+
* return (
|
|
27
|
+
* <div>
|
|
28
|
+
* <button onClick={calculate} disabled={isRunning}>
|
|
29
|
+
* Calculate
|
|
30
|
+
* </button>
|
|
31
|
+
* {result && <p>Result: {JSON.stringify(result.value)}</p>}
|
|
32
|
+
* <pre>{stdout}</pre>
|
|
33
|
+
* </div>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function useEnclaveSession<T = unknown>(options?: UseEnclaveSessionOptions): UseEnclaveSessionReturn<T>;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useEnclaveSession Hook
|
|
4
|
+
*
|
|
5
|
+
* React hook for executing code in the EnclaveJS runtime with state management.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.useEnclaveSession = useEnclaveSession;
|
|
11
|
+
const react_1 = require("react");
|
|
12
|
+
const EnclaveProvider_js_1 = require("./EnclaveProvider.js");
|
|
13
|
+
/**
|
|
14
|
+
* useEnclaveSession hook
|
|
15
|
+
*
|
|
16
|
+
* Provides a stateful interface for executing code in the Enclave runtime.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* function Calculator() {
|
|
21
|
+
* const { execute, isRunning, result, stdout } = useEnclaveSession({
|
|
22
|
+
* onStdout: (chunk) => console.log(chunk),
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* const calculate = async () => {
|
|
26
|
+
* const result = await execute('return 1 + 1');
|
|
27
|
+
* console.log('Result:', result.value);
|
|
28
|
+
* };
|
|
29
|
+
*
|
|
30
|
+
* return (
|
|
31
|
+
* <div>
|
|
32
|
+
* <button onClick={calculate} disabled={isRunning}>
|
|
33
|
+
* Calculate
|
|
34
|
+
* </button>
|
|
35
|
+
* {result && <p>Result: {JSON.stringify(result.value)}</p>}
|
|
36
|
+
* <pre>{stdout}</pre>
|
|
37
|
+
* </div>
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
function useEnclaveSession(options = {}) {
|
|
43
|
+
const client = (0, EnclaveProvider_js_1.useEnclaveClient)();
|
|
44
|
+
// State
|
|
45
|
+
const [state, setState] = (0, react_1.useState)('idle');
|
|
46
|
+
const [sessionId, setSessionId] = (0, react_1.useState)(null);
|
|
47
|
+
const [result, setResult] = (0, react_1.useState)(null);
|
|
48
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
49
|
+
const [stdout, setStdout] = (0, react_1.useState)('');
|
|
50
|
+
const [events, setEvents] = (0, react_1.useState)([]);
|
|
51
|
+
// Refs for current session handle
|
|
52
|
+
const handleRef = (0, react_1.useRef)(null);
|
|
53
|
+
/**
|
|
54
|
+
* Reset the hook state
|
|
55
|
+
*/
|
|
56
|
+
const reset = (0, react_1.useCallback)(() => {
|
|
57
|
+
setState('idle');
|
|
58
|
+
setSessionId(null);
|
|
59
|
+
setResult(null);
|
|
60
|
+
setError(null);
|
|
61
|
+
setStdout('');
|
|
62
|
+
setEvents([]);
|
|
63
|
+
handleRef.current = null;
|
|
64
|
+
}, []);
|
|
65
|
+
/**
|
|
66
|
+
* Execute code in the enclave
|
|
67
|
+
*/
|
|
68
|
+
const execute = (0, react_1.useCallback)(async (code) => {
|
|
69
|
+
// Reset state for new execution
|
|
70
|
+
setState('running');
|
|
71
|
+
setResult(null);
|
|
72
|
+
setError(null);
|
|
73
|
+
setStdout('');
|
|
74
|
+
setEvents([]);
|
|
75
|
+
// Call onStart callback
|
|
76
|
+
options.onStart?.();
|
|
77
|
+
// Build limits from options
|
|
78
|
+
const limits = {};
|
|
79
|
+
if (options.timeoutMs !== undefined) {
|
|
80
|
+
limits.sessionTtlMs = options.timeoutMs;
|
|
81
|
+
}
|
|
82
|
+
if (options.maxToolCalls !== undefined) {
|
|
83
|
+
limits.maxToolCalls = options.maxToolCalls;
|
|
84
|
+
}
|
|
85
|
+
if (options.heartbeatIntervalMs !== undefined) {
|
|
86
|
+
limits.heartbeatIntervalMs = options.heartbeatIntervalMs;
|
|
87
|
+
}
|
|
88
|
+
// Start streaming execution
|
|
89
|
+
const handle = client.executeStream(code, {
|
|
90
|
+
sessionId: options.sessionId,
|
|
91
|
+
limits: Object.keys(limits).length > 0 ? limits : undefined,
|
|
92
|
+
onEvent: (event) => {
|
|
93
|
+
setEvents((prev) => [...prev, event]);
|
|
94
|
+
},
|
|
95
|
+
onStdout: (chunk) => {
|
|
96
|
+
setStdout((prev) => prev + chunk);
|
|
97
|
+
options.onStdout?.(chunk);
|
|
98
|
+
},
|
|
99
|
+
onLog: (level, message, data) => {
|
|
100
|
+
options.onLog?.(level, message, data);
|
|
101
|
+
},
|
|
102
|
+
onToolCall: (callId, toolName, args) => {
|
|
103
|
+
options.onToolCall?.(callId, toolName, args);
|
|
104
|
+
},
|
|
105
|
+
onToolResultApplied: (callId) => {
|
|
106
|
+
options.onToolResultApplied?.(callId);
|
|
107
|
+
},
|
|
108
|
+
onError: (code, message) => {
|
|
109
|
+
options.onError?.({ code, message });
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
handleRef.current = handle;
|
|
113
|
+
setSessionId(handle.sessionId);
|
|
114
|
+
try {
|
|
115
|
+
// Wait for completion
|
|
116
|
+
const sessionResult = (await handle.wait());
|
|
117
|
+
// Update state based on result
|
|
118
|
+
if (sessionResult.success) {
|
|
119
|
+
setState('completed');
|
|
120
|
+
setResult(sessionResult);
|
|
121
|
+
}
|
|
122
|
+
else if (sessionResult.error?.code === 'CANCELLED') {
|
|
123
|
+
setState('cancelled');
|
|
124
|
+
setResult(sessionResult);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
setState('error');
|
|
128
|
+
setResult(sessionResult);
|
|
129
|
+
setError(sessionResult.error ?? { message: 'Unknown error' });
|
|
130
|
+
options.onError?.(sessionResult.error ?? { message: 'Unknown error' });
|
|
131
|
+
}
|
|
132
|
+
// Call onComplete callback
|
|
133
|
+
options.onComplete?.(sessionResult);
|
|
134
|
+
return sessionResult;
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
// Handle unexpected errors
|
|
138
|
+
const errorInfo = {
|
|
139
|
+
code: 'UNEXPECTED_ERROR',
|
|
140
|
+
message: err instanceof Error ? err.message : 'Unknown error',
|
|
141
|
+
};
|
|
142
|
+
setState('error');
|
|
143
|
+
setError(errorInfo);
|
|
144
|
+
options.onError?.(errorInfo);
|
|
145
|
+
// Return error result
|
|
146
|
+
const errorResult = {
|
|
147
|
+
success: false,
|
|
148
|
+
sessionId: handle.sessionId,
|
|
149
|
+
error: errorInfo,
|
|
150
|
+
events: handle.getEvents(),
|
|
151
|
+
};
|
|
152
|
+
setResult(errorResult);
|
|
153
|
+
options.onComplete?.(errorResult);
|
|
154
|
+
return errorResult;
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
handleRef.current = null;
|
|
158
|
+
}
|
|
159
|
+
}, [client, options]);
|
|
160
|
+
/**
|
|
161
|
+
* Cancel the current session
|
|
162
|
+
*/
|
|
163
|
+
const cancel = (0, react_1.useCallback)(async (reason) => {
|
|
164
|
+
if (handleRef.current) {
|
|
165
|
+
await handleRef.current.cancel(reason);
|
|
166
|
+
}
|
|
167
|
+
}, []);
|
|
168
|
+
return {
|
|
169
|
+
execute,
|
|
170
|
+
cancel,
|
|
171
|
+
state,
|
|
172
|
+
isRunning: state === 'running',
|
|
173
|
+
sessionId,
|
|
174
|
+
result,
|
|
175
|
+
error,
|
|
176
|
+
stdout,
|
|
177
|
+
events,
|
|
178
|
+
reset,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=useEnclaveSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEnclaveSession.js","sourceRoot":"","sources":["../../src/useEnclaveSession.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * useEnclaveSession Hook\n *\n * React hook for executing code in the EnclaveJS runtime with state management.\n *\n * @packageDocumentation\n */\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { SessionResult, SessionHandle, StreamEvent, SessionId } from '@enclave-vm/client';\nimport { useEnclaveClient } from './EnclaveProvider.js';\nimport type { SessionState, UseEnclaveSessionOptions, UseEnclaveSessionReturn } from './types.js';\n\n/**\n * useEnclaveSession hook\n *\n * Provides a stateful interface for executing code in the Enclave runtime.\n *\n * @example\n * ```tsx\n * function Calculator() {\n * const { execute, isRunning, result, stdout } = useEnclaveSession({\n * onStdout: (chunk) => console.log(chunk),\n * });\n *\n * const calculate = async () => {\n * const result = await execute('return 1 + 1');\n * console.log('Result:', result.value);\n * };\n *\n * return (\n * <div>\n * <button onClick={calculate} disabled={isRunning}>\n * Calculate\n * </button>\n * {result && <p>Result: {JSON.stringify(result.value)}</p>}\n * <pre>{stdout}</pre>\n * </div>\n * );\n * }\n * ```\n */\nexport function useEnclaveSession<T = unknown>(options: UseEnclaveSessionOptions = {}): UseEnclaveSessionReturn<T> {\n const client = useEnclaveClient();\n\n // State\n const [state, setState] = useState<SessionState>('idle');\n const [sessionId, setSessionId] = useState<SessionId | null>(null);\n const [result, setResult] = useState<SessionResult<T> | null>(null);\n const [error, setError] = useState<{ code?: string; message: string } | null>(null);\n const [stdout, setStdout] = useState<string>('');\n const [events, setEvents] = useState<StreamEvent[]>([]);\n\n // Refs for current session handle\n const handleRef = useRef<SessionHandle | null>(null);\n\n /**\n * Reset the hook state\n */\n const reset = useCallback(() => {\n setState('idle');\n setSessionId(null);\n setResult(null);\n setError(null);\n setStdout('');\n setEvents([]);\n handleRef.current = null;\n }, []);\n\n /**\n * Execute code in the enclave\n */\n const execute = useCallback(\n async (code: string): Promise<SessionResult<T>> => {\n // Reset state for new execution\n setState('running');\n setResult(null);\n setError(null);\n setStdout('');\n setEvents([]);\n\n // Call onStart callback\n options.onStart?.();\n\n // Build limits from options\n const limits: Record<string, number> = {};\n if (options.timeoutMs !== undefined) {\n limits.sessionTtlMs = options.timeoutMs;\n }\n if (options.maxToolCalls !== undefined) {\n limits.maxToolCalls = options.maxToolCalls;\n }\n if (options.heartbeatIntervalMs !== undefined) {\n limits.heartbeatIntervalMs = options.heartbeatIntervalMs;\n }\n\n // Start streaming execution\n const handle = client.executeStream(code, {\n sessionId: options.sessionId,\n limits: Object.keys(limits).length > 0 ? limits : undefined,\n onEvent: (event) => {\n setEvents((prev) => [...prev, event]);\n },\n onStdout: (chunk) => {\n setStdout((prev) => prev + chunk);\n options.onStdout?.(chunk);\n },\n onLog: (level, message, data) => {\n options.onLog?.(level, message, data);\n },\n onToolCall: (callId, toolName, args) => {\n options.onToolCall?.(callId, toolName, args);\n },\n onToolResultApplied: (callId) => {\n options.onToolResultApplied?.(callId);\n },\n onError: (code, message) => {\n options.onError?.({ code, message });\n },\n });\n\n handleRef.current = handle;\n setSessionId(handle.sessionId);\n\n try {\n // Wait for completion\n const sessionResult = (await handle.wait()) as SessionResult<T>;\n\n // Update state based on result\n if (sessionResult.success) {\n setState('completed');\n setResult(sessionResult);\n } else if (sessionResult.error?.code === 'CANCELLED') {\n setState('cancelled');\n setResult(sessionResult);\n } else {\n setState('error');\n setResult(sessionResult);\n setError(sessionResult.error ?? { message: 'Unknown error' });\n options.onError?.(sessionResult.error ?? { message: 'Unknown error' });\n }\n\n // Call onComplete callback\n options.onComplete?.(sessionResult);\n\n return sessionResult;\n } catch (err) {\n // Handle unexpected errors\n const errorInfo = {\n code: 'UNEXPECTED_ERROR',\n message: err instanceof Error ? err.message : 'Unknown error',\n };\n\n setState('error');\n setError(errorInfo);\n options.onError?.(errorInfo);\n\n // Return error result\n const errorResult: SessionResult<T> = {\n success: false,\n sessionId: handle.sessionId,\n error: errorInfo,\n events: handle.getEvents(),\n };\n\n setResult(errorResult);\n options.onComplete?.(errorResult);\n\n return errorResult;\n } finally {\n handleRef.current = null;\n }\n },\n [client, options],\n );\n\n /**\n * Cancel the current session\n */\n const cancel = useCallback(async (reason?: string): Promise<void> => {\n if (handleRef.current) {\n await handleRef.current.cancel(reason);\n }\n }, []);\n\n return {\n execute,\n cancel,\n state,\n isRunning: state === 'running',\n sessionId,\n result,\n error,\n stdout,\n events,\n reset,\n };\n}\n"]}
|