@agentuity/react 1.0.48 → 2.0.0-beta.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.
Files changed (52) hide show
  1. package/AGENTS.md +26 -45
  2. package/README.md +28 -182
  3. package/dist/client-entrypoint.d.ts +8 -12
  4. package/dist/client-entrypoint.d.ts.map +1 -1
  5. package/dist/client-entrypoint.js +8 -15
  6. package/dist/client-entrypoint.js.map +1 -1
  7. package/dist/context.d.ts +1 -1
  8. package/dist/context.d.ts.map +1 -1
  9. package/dist/context.js +3 -12
  10. package/dist/context.js.map +1 -1
  11. package/dist/index.d.ts +1 -6
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -5
  14. package/dist/index.js.map +1 -1
  15. package/dist/server.d.ts +6 -14
  16. package/dist/server.d.ts.map +1 -1
  17. package/dist/server.js +5 -10
  18. package/dist/server.js.map +1 -1
  19. package/dist/webrtc.d.ts.map +1 -1
  20. package/dist/webrtc.js +2 -2
  21. package/dist/webrtc.js.map +1 -1
  22. package/package.json +5 -5
  23. package/src/client-entrypoint.tsx +8 -22
  24. package/src/context.tsx +3 -14
  25. package/src/index.ts +1 -52
  26. package/src/server.ts +5 -43
  27. package/src/webrtc.tsx +2 -1
  28. package/dist/api.d.ts +0 -302
  29. package/dist/api.d.ts.map +0 -1
  30. package/dist/api.js +0 -487
  31. package/dist/api.js.map +0 -1
  32. package/dist/client.d.ts +0 -75
  33. package/dist/client.d.ts.map +0 -1
  34. package/dist/client.js +0 -102
  35. package/dist/client.js.map +0 -1
  36. package/dist/eventstream.d.ts +0 -79
  37. package/dist/eventstream.d.ts.map +0 -1
  38. package/dist/eventstream.js +0 -122
  39. package/dist/eventstream.js.map +0 -1
  40. package/dist/types.d.ts +0 -18
  41. package/dist/types.d.ts.map +0 -1
  42. package/dist/types.js +0 -18
  43. package/dist/types.js.map +0 -1
  44. package/dist/websocket.d.ts +0 -88
  45. package/dist/websocket.d.ts.map +0 -1
  46. package/dist/websocket.js +0 -151
  47. package/dist/websocket.js.map +0 -1
  48. package/src/api.ts +0 -954
  49. package/src/client.ts +0 -136
  50. package/src/eventstream.ts +0 -188
  51. package/src/types.ts +0 -23
  52. package/src/websocket.ts +0 -241
package/src/client.ts DELETED
@@ -1,136 +0,0 @@
1
- import {
2
- createClient as coreCreateClient,
3
- type Client,
4
- type ClientOptions,
5
- type RPCRouteRegistry,
6
- } from '@agentuity/frontend';
7
-
8
- // Re-export RPCRouteRegistry for backwards compatibility
9
- // The canonical definition is in @agentuity/frontend
10
- export type { RPCRouteRegistry };
11
-
12
- let globalBaseUrl: string | undefined;
13
- let globalAuthHeader: string | null | undefined;
14
-
15
- /**
16
- * Set the global base URL for RPC clients.
17
- * This is automatically called by AgentuityProvider.
18
- * @internal
19
- */
20
- export function setGlobalBaseUrl(url: string): void {
21
- globalBaseUrl = url;
22
- }
23
-
24
- /**
25
- * Get the global base URL for RPC clients.
26
- * Returns the configured base URL or falls back to window.location.origin.
27
- * @internal
28
- */
29
- export function getGlobalBaseUrl(): string {
30
- return globalBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');
31
- }
32
-
33
- /**
34
- * Set the global auth header for RPC clients.
35
- * This is automatically called by AgentuityProvider when auth state changes.
36
- * @internal
37
- */
38
- export function setGlobalAuthHeader(authHeader: string | null): void {
39
- globalAuthHeader = authHeader;
40
- }
41
-
42
- /**
43
- * Get the global auth header for RPC clients.
44
- * Returns the current auth header or undefined if not set.
45
- * @internal
46
- */
47
- export function getGlobalAuthHeader(): string | null | undefined {
48
- return globalAuthHeader;
49
- }
50
-
51
- /**
52
- * Create a type-safe RPC client for React applications.
53
- *
54
- * This is a React-specific wrapper around @agentuity/core's createClient that
55
- * automatically uses the baseUrl and auth headers from AgentuityProvider context.
56
- *
57
- * @example
58
- * ```typescript
59
- * import { createClient } from '@agentuity/react';
60
- * import type { RPCRouteRegistry } from '@agentuity/react';
61
- *
62
- * const client = createClient<RPCRouteRegistry>();
63
- *
64
- * // Inside component
65
- * const result = await client.hello.post({ name: 'World' });
66
- * ```
67
- */
68
- export function createClient<R>(
69
- options?: Omit<ClientOptions, 'baseUrl' | 'headers'> & {
70
- baseUrl?: string | (() => string);
71
- headers?: Record<string, string> | (() => Record<string, string>);
72
- },
73
- metadata?: unknown
74
- ): Client<R> {
75
- // Merge user headers with auth headers
76
- // User-provided headers take precedence over global auth header
77
- const mergedHeaders = (): Record<string, string> => {
78
- const authHeader = getGlobalAuthHeader();
79
- const userHeaders =
80
- typeof options?.headers === 'function' ? options.headers() : options?.headers || {};
81
-
82
- const headers: Record<string, string> = {};
83
-
84
- // Add global auth header first (lower priority)
85
- if (authHeader) {
86
- headers.Authorization = authHeader;
87
- }
88
-
89
- // User headers override global auth
90
- return { ...headers, ...userHeaders };
91
- };
92
-
93
- return coreCreateClient<R>(
94
- {
95
- ...options,
96
- baseUrl: (options?.baseUrl || getGlobalBaseUrl) as string | (() => string),
97
- headers: mergedHeaders,
98
- } as ClientOptions,
99
- metadata
100
- );
101
- }
102
-
103
- /**
104
- * Create a type-safe API client with optional configuration.
105
- *
106
- * This is the recommended way to create an API client in React applications.
107
- * It automatically includes auth headers from AgentuityProvider and allows
108
- * custom headers to be passed.
109
- *
110
- * The generic type parameter defaults to RPCRouteRegistry which is augmented
111
- * by generated code, so you don't need to specify it manually.
112
- *
113
- * @example
114
- * ```typescript
115
- * import { createAPIClient } from '@agentuity/react';
116
- *
117
- * // Types are automatically inferred from generated routes
118
- * const api = createAPIClient();
119
- * await api.hello.post({ name: 'World' });
120
- *
121
- * // With custom headers
122
- * const api = createAPIClient({ headers: { 'X-Custom': 'value' } });
123
- * await api.hello.post({ name: 'World' });
124
- * ```
125
- */
126
- export function createAPIClient<R = RPCRouteRegistry>(
127
- options?: Omit<ClientOptions, 'baseUrl' | 'headers'> & {
128
- baseUrl?: string | (() => string);
129
- headers?: Record<string, string> | (() => Record<string, string>);
130
- }
131
- ): Client<R> {
132
- // This function is designed to be used with generated metadata
133
- // The metadata will be provided by the code generator
134
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
135
- return createClient<R>(options, (globalThis as any).__rpcRouteMetadata);
136
- }
@@ -1,188 +0,0 @@
1
- import type { InferOutput } from '@agentuity/core';
2
- import {
3
- buildUrl,
4
- EventStreamManager,
5
- jsonEqual,
6
- type SSERouteRegistry,
7
- } from '@agentuity/frontend';
8
- import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
9
- import { AgentuityContext } from './context';
10
-
11
- /**
12
- * Extract SSE route keys (e.g., '/events', '/notifications')
13
- */
14
- export type SSERouteKey = keyof SSERouteRegistry;
15
-
16
- /**
17
- * Extract output type for an SSE route (SSE is typically one-way server->client)
18
- */
19
- export type SSERouteOutput<TRoute extends SSERouteKey> = TRoute extends keyof SSERouteRegistry
20
- ? SSERouteRegistry[TRoute] extends { outputSchema: infer TSchema }
21
- ? TSchema extends undefined | never
22
- ? void
23
- : InferOutput<TSchema>
24
- : void
25
- : void;
26
-
27
- /**
28
- * Options for EventStream hooks
29
- */
30
- export interface EventStreamOptions {
31
- /**
32
- * Optional query parameters to append to the EventStream URL
33
- */
34
- query?: URLSearchParams;
35
- /**
36
- * Optional subpath to append to the EventStream path
37
- */
38
- subpath?: string;
39
- /**
40
- * Optional AbortSignal to cancel the EventStream connection
41
- */
42
- signal?: AbortSignal;
43
- }
44
-
45
- /**
46
- * Type-safe EventStream (SSE) hook for connecting to SSE routes.
47
- *
48
- * Provides automatic type inference for route outputs based on
49
- * the SSERouteRegistry generated from your routes.
50
- *
51
- * @template TRoute - SSE route key from SSERouteRegistry (e.g., '/events', '/notifications')
52
- * @template TOutput - Optional type override for SSE event data. When provided, this type
53
- * is used instead of the inferred type from the route registry. This is useful for SSE
54
- * routes where outputSchema is `never` in the generated types.
55
- *
56
- * @example Simple SSE connection
57
- * ```typescript
58
- * const { isConnected, data } = useEventStream('/events');
59
- *
60
- * // data is fully typed based on route output schema!
61
- * ```
62
- *
63
- * @example SSE with query parameters
64
- * ```typescript
65
- * const { isConnected, data } = useEventStream('/notifications', {
66
- * query: new URLSearchParams({ userId: '123' })
67
- * });
68
- * ```
69
- *
70
- * @example SSE with custom output type (when registry has outputSchema: never)
71
- * ```typescript
72
- * interface StreamMessage {
73
- * type: 'token' | 'complete';
74
- * content?: string;
75
- * }
76
- *
77
- * const { isConnected, data } = useEventStream<'/api/search', StreamMessage>('/api/search');
78
- *
79
- * // data is typed as StreamMessage | undefined
80
- * if (data?.type === 'token') {
81
- * console.log(data.content);
82
- * }
83
- * ```
84
- */
85
- export function useEventStream<TRoute extends SSERouteKey, TOutput = SSERouteOutput<TRoute>>(
86
- route: TRoute,
87
- options?: EventStreamOptions
88
- ): {
89
- isConnected: boolean;
90
- close: () => void;
91
- data?: TOutput;
92
- error: Error | null;
93
- isError: boolean;
94
- reset: () => void;
95
- readyState: number;
96
- } {
97
- const context = useContext(AgentuityContext);
98
-
99
- if (!context) {
100
- throw new Error('useEventStream must be used within a AgentuityProvider');
101
- }
102
-
103
- const managerRef = useRef<EventStreamManager<TOutput> | null>(null);
104
-
105
- const [data, setData] = useState<TOutput>();
106
- const [error, setError] = useState<Error | null>(null);
107
- const [isError, setIsError] = useState(false);
108
- const [isConnected, setIsConnected] = useState(false);
109
- const [readyState, setReadyState] = useState<number>(2); // EventSource.CLOSED = 2
110
-
111
- // Build EventStream URL
112
- // Track both query object and its string representation to detect mutations.
113
- // URLSearchParams can be mutated in-place without changing object identity,
114
- // so we compare the string value to trigger recomputation when params change.
115
- const _queryString = options?.query?.toString();
116
- const esUrl = useMemo(
117
- () => buildUrl(context.baseUrl!, route as string, options?.subpath, options?.query),
118
- [context.baseUrl, route, options?.subpath, options?.query]
119
- );
120
-
121
- // Initialize manager and connect
122
- useEffect(() => {
123
- const manager = new EventStreamManager<TOutput>({
124
- url: esUrl,
125
- callbacks: {
126
- onConnect: () => {
127
- setIsConnected(true);
128
- setError(null);
129
- setIsError(false);
130
- setReadyState(1); // EventSource.OPEN = 1
131
- },
132
- onDisconnect: () => {
133
- setIsConnected(false);
134
- setReadyState(2); // EventSource.CLOSED = 2
135
- },
136
- onError: (err) => {
137
- setError(err);
138
- setIsError(true);
139
- },
140
- },
141
- });
142
-
143
- // Set message handler with JSON memoization
144
- manager.setMessageHandler((message) => {
145
- setData((prev) => (prev !== undefined && jsonEqual(prev, message) ? prev : message));
146
- });
147
-
148
- manager.connect();
149
- managerRef.current = manager;
150
-
151
- return () => {
152
- manager.dispose();
153
- managerRef.current = null;
154
- };
155
- }, [esUrl]);
156
-
157
- // Handle abort signal
158
- useEffect(() => {
159
- if (options?.signal) {
160
- const listener = () => {
161
- managerRef.current?.close();
162
- };
163
- options.signal.addEventListener('abort', listener);
164
- return () => {
165
- options.signal?.removeEventListener('abort', listener);
166
- };
167
- }
168
- }, [options?.signal]);
169
-
170
- const reset = useCallback(() => {
171
- setError(null);
172
- setIsError(false);
173
- }, []);
174
-
175
- const close = useCallback(() => {
176
- managerRef.current?.close();
177
- }, []);
178
-
179
- return {
180
- isConnected,
181
- close,
182
- data,
183
- error,
184
- isError,
185
- reset,
186
- readyState,
187
- };
188
- }
package/src/types.ts DELETED
@@ -1,23 +0,0 @@
1
- /**
2
- * Route Registry Types for @agentuity/react
3
- *
4
- * These interfaces are re-exported from @agentuity/frontend and augmented by
5
- * generated code (src/generated/routes.ts) to provide type-safe routing for
6
- * useAPI, useWebsocket, useEventStream, and createAPIClient.
7
- *
8
- * @remarks
9
- * The generated code uses `declare module '@agentuity/frontend'` to augment
10
- * these interfaces. Since @agentuity/react re-exports them, the augmented
11
- * types are available when importing from either package.
12
- *
13
- * This design ensures that in monorepo setups with multiple node_modules,
14
- * TypeScript sees consistent types as long as @agentuity/frontend is properly
15
- * resolved (via hoisting or tsconfig paths).
16
- */
17
-
18
- export type {
19
- RouteRegistry,
20
- WebSocketRouteRegistry,
21
- SSERouteRegistry,
22
- RPCRouteRegistry,
23
- } from '@agentuity/frontend';
package/src/websocket.ts DELETED
@@ -1,241 +0,0 @@
1
- import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
2
- import type { InferInput, InferOutput } from '@agentuity/core';
3
- import { buildUrl, WebSocketManager, type WebSocketRouteRegistry } from '@agentuity/frontend';
4
- import { AgentuityContext } from './context';
5
-
6
- // WebSocket ready state constants for SSR compatibility
7
- // (WebSocket global may not exist during SSR)
8
- const WS_OPEN = 1;
9
- const WS_CLOSED = 3;
10
-
11
- /**
12
- * Extract WebSocket route keys (e.g., '/ws', '/chat')
13
- */
14
- export type WebSocketRouteKey = keyof WebSocketRouteRegistry;
15
-
16
- /**
17
- * Extract input type for a WebSocket route
18
- */
19
- export type WebSocketRouteInput<TRoute extends WebSocketRouteKey> =
20
- TRoute extends keyof WebSocketRouteRegistry
21
- ? WebSocketRouteRegistry[TRoute] extends { inputSchema: infer TSchema }
22
- ? TSchema extends undefined | never
23
- ? never
24
- : InferInput<TSchema>
25
- : never
26
- : never;
27
-
28
- /**
29
- * Extract output type for a WebSocket route
30
- */
31
- export type WebSocketRouteOutput<TRoute extends WebSocketRouteKey> =
32
- TRoute extends keyof WebSocketRouteRegistry
33
- ? WebSocketRouteRegistry[TRoute] extends { outputSchema: infer TSchema }
34
- ? TSchema extends undefined | never
35
- ? void
36
- : InferOutput<TSchema>
37
- : void
38
- : void;
39
-
40
- /**
41
- * Options for WebSocket hooks
42
- */
43
- export interface WebsocketOptions {
44
- /**
45
- * Optional query parameters to append to the websocket URL
46
- */
47
- query?: URLSearchParams;
48
- /**
49
- * Optional subpath to append to the websocket path
50
- */
51
- subpath?: string;
52
- /**
53
- * Optional AbortSignal to cancel the websocket connection
54
- */
55
- signal?: AbortSignal;
56
- /**
57
- * Maximum number of messages to keep in the messages array.
58
- * When exceeded, oldest messages are removed.
59
- * @default undefined (no limit)
60
- */
61
- maxMessages?: number;
62
- }
63
-
64
- /**
65
- * Type-safe WebSocket hook for connecting to WebSocket routes.
66
- *
67
- * Provides automatic type inference for route inputs and outputs based on
68
- * the WebSocketRouteRegistry generated from your routes.
69
- *
70
- * @template TRoute - WebSocket route key from WebSocketRouteRegistry (e.g., '/ws', '/chat')
71
- *
72
- * @example Simple WebSocket connection
73
- * ```typescript
74
- * const { isConnected, data, send } = useWebsocket('/ws');
75
- *
76
- * // Send typed data
77
- * send({ message: 'Hello' }); // Fully typed based on route schema!
78
- * ```
79
- *
80
- * @example WebSocket with query parameters
81
- * ```typescript
82
- * const { isConnected, data, send } = useWebsocket('/chat', {
83
- * query: new URLSearchParams({ room: 'general' })
84
- * });
85
- * ```
86
- *
87
- * @example Access all messages (prevents message loss in rapid succession)
88
- * ```typescript
89
- * const { messages, clearMessages } = useWebsocket('/chat');
90
- *
91
- * // messages array contains ALL received messages
92
- * messages.forEach(msg => console.log(msg));
93
- *
94
- * // Clear messages when needed
95
- * clearMessages();
96
- * ```
97
- */
98
- export function useWebsocket<TRoute extends WebSocketRouteKey>(
99
- route: TRoute,
100
- options?: WebsocketOptions
101
- ): {
102
- isConnected: boolean;
103
- close: () => void;
104
- data?: WebSocketRouteOutput<TRoute>;
105
- messages: WebSocketRouteOutput<TRoute>[];
106
- clearMessages: () => void;
107
- error: Error | null;
108
- isError: boolean;
109
- reset: () => void;
110
- send: (data: WebSocketRouteInput<TRoute>) => void;
111
- readyState: WebSocket['readyState'];
112
- } {
113
- const context = useContext(AgentuityContext);
114
-
115
- if (!context) {
116
- throw new Error('useWebsocket must be used within a AgentuityProvider');
117
- }
118
-
119
- const managerRef = useRef<WebSocketManager<
120
- WebSocketRouteInput<TRoute>,
121
- WebSocketRouteOutput<TRoute>
122
- > | null>(null);
123
-
124
- const [data, setData] = useState<WebSocketRouteOutput<TRoute>>();
125
- const [messages, setMessages] = useState<WebSocketRouteOutput<TRoute>[]>([]);
126
- const [error, setError] = useState<Error | null>(null);
127
- const [isError, setIsError] = useState(false);
128
- const [isConnected, setIsConnected] = useState(false);
129
- const [readyState, setReadyState] = useState<number>(WS_CLOSED);
130
-
131
- // Build WebSocket URL
132
- const wsUrl = useMemo(() => {
133
- const base = context.baseUrl!;
134
- const wsBase = base.replace(/^http(s?):/, 'ws$1:');
135
-
136
- // Add auth token to query params if present
137
- // (WebSocket doesn't support custom headers, so we pass via query string)
138
- let queryParams = options?.query;
139
- if (context.authHeader) {
140
- const token = context.authHeader.replace(/^Bearer\s+/i, '');
141
- const authQuery = new URLSearchParams({ token });
142
- if (queryParams) {
143
- queryParams = new URLSearchParams([...queryParams, ...authQuery]);
144
- } else {
145
- queryParams = authQuery;
146
- }
147
- }
148
-
149
- return buildUrl(wsBase, route as string, options?.subpath, queryParams);
150
- }, [context.baseUrl, context.authHeader, route, options?.subpath, options?.query]);
151
-
152
- // Initialize manager and connect
153
- useEffect(() => {
154
- const manager = new WebSocketManager<
155
- WebSocketRouteInput<TRoute>,
156
- WebSocketRouteOutput<TRoute>
157
- >({
158
- url: wsUrl,
159
- callbacks: {
160
- onConnect: () => {
161
- setIsConnected(true);
162
- setError(null);
163
- setIsError(false);
164
- setReadyState(WS_OPEN);
165
- },
166
- onDisconnect: () => {
167
- setIsConnected(false);
168
- setReadyState(WS_CLOSED);
169
- },
170
- onError: (err) => {
171
- setError(err);
172
- setIsError(true);
173
- },
174
- },
175
- });
176
-
177
- // Set message handler
178
- manager.setMessageHandler((message) => {
179
- setData(message);
180
- setMessages((prev) => {
181
- const newMessages = [...prev, message];
182
- // Enforce maxMessages limit if specified
183
- if (options?.maxMessages && newMessages.length > options.maxMessages) {
184
- return newMessages.slice(-options.maxMessages);
185
- }
186
- return newMessages;
187
- });
188
- });
189
-
190
- manager.connect();
191
- managerRef.current = manager;
192
-
193
- return () => {
194
- manager.dispose();
195
- managerRef.current = null;
196
- };
197
- }, [wsUrl, options?.maxMessages]);
198
-
199
- // Handle abort signal
200
- useEffect(() => {
201
- if (options?.signal) {
202
- const listener = () => {
203
- managerRef.current?.close();
204
- };
205
- options.signal.addEventListener('abort', listener);
206
- return () => {
207
- options.signal?.removeEventListener('abort', listener);
208
- };
209
- }
210
- }, [options?.signal]);
211
-
212
- const reset = useCallback(() => {
213
- setError(null);
214
- setIsError(false);
215
- }, []);
216
-
217
- const send = useCallback((sendData: WebSocketRouteInput<TRoute>) => {
218
- managerRef.current?.send(sendData);
219
- }, []);
220
-
221
- const close = useCallback(() => {
222
- managerRef.current?.close();
223
- }, []);
224
-
225
- const clearMessages = useCallback(() => {
226
- setMessages([]);
227
- }, []);
228
-
229
- return {
230
- isConnected,
231
- close,
232
- data,
233
- messages,
234
- clearMessages,
235
- error,
236
- isError,
237
- reset,
238
- send,
239
- readyState,
240
- };
241
- }