@agentuity/react 0.0.69 → 0.0.70
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/api.d.ts +196 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +325 -0
- package/dist/api.js.map +1 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +3 -0
- package/dist/env.js.map +1 -1
- package/dist/eventstream.d.ts +52 -13
- package/dist/eventstream.d.ts.map +1 -1
- package/dist/eventstream.js +45 -13
- package/dist/eventstream.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/memo.d.ts +7 -0
- package/dist/memo.d.ts.map +1 -0
- package/dist/memo.js +32 -0
- package/dist/memo.js.map +1 -0
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +5 -7
- package/dist/serialization.js.map +1 -1
- package/dist/types.d.ts +10 -25
- package/dist/types.d.ts.map +1 -1
- package/dist/url.d.ts.map +1 -1
- package/dist/url.js +6 -0
- package/dist/url.js.map +1 -1
- package/dist/websocket.d.ts +60 -13
- package/dist/websocket.d.ts.map +1 -1
- package/dist/websocket.js +47 -13
- package/dist/websocket.js.map +1 -1
- package/package.json +3 -2
- package/src/api.ts +529 -0
- package/src/env.ts +3 -0
- package/src/eventstream.ts +87 -40
- package/src/index.ts +2 -1
- package/src/memo.ts +32 -0
- package/src/serialization.ts +4 -6
- package/src/types.ts +19 -29
- package/src/url.ts +7 -0
- package/src/websocket.ts +109 -43
- package/dist/run.d.ts +0 -34
- package/dist/run.d.ts.map +0 -1
- package/dist/run.js +0 -68
- package/dist/run.js.map +0 -1
- package/src/run.ts +0 -119
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { InferInput, InferOutput } from '@agentuity/core';
|
|
2
|
+
import type { RouteRegistry } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Extract route keys from RouteRegistry (e.g., 'GET /users', 'POST /users')
|
|
5
|
+
*/
|
|
6
|
+
export type RouteKey = keyof RouteRegistry;
|
|
7
|
+
/**
|
|
8
|
+
* Extract HTTP method from route key
|
|
9
|
+
*/
|
|
10
|
+
export type ExtractMethod<TRoute extends RouteKey> = TRoute extends `${infer Method} ${string}` ? Method : never;
|
|
11
|
+
/**
|
|
12
|
+
* Extract input type for a specific route
|
|
13
|
+
*/
|
|
14
|
+
export type RouteInput<TRoute extends RouteKey> = TRoute extends keyof RouteRegistry ? RouteRegistry[TRoute] extends {
|
|
15
|
+
inputSchema: any;
|
|
16
|
+
} ? InferInput<RouteRegistry[TRoute]['inputSchema']> : never : never;
|
|
17
|
+
/**
|
|
18
|
+
* Extract output type for a specific route
|
|
19
|
+
* Returns void if no outputSchema is defined (e.g., 204 No Content)
|
|
20
|
+
*/
|
|
21
|
+
export type RouteOutput<TRoute extends RouteKey> = TRoute extends keyof RouteRegistry ? RouteRegistry[TRoute] extends {
|
|
22
|
+
outputSchema: infer TSchema;
|
|
23
|
+
} ? TSchema extends undefined | never ? void : InferOutput<TSchema> : void : void;
|
|
24
|
+
/**
|
|
25
|
+
* Common options shared by all UseAPI configurations
|
|
26
|
+
*/
|
|
27
|
+
type UseAPICommonOptions<TRoute extends RouteKey> = {
|
|
28
|
+
/** Additional query parameters */
|
|
29
|
+
query?: URLSearchParams | Record<string, string>;
|
|
30
|
+
/** Additional request headers */
|
|
31
|
+
headers?: Record<string, string>;
|
|
32
|
+
/** Whether to execute the request immediately on mount (default: true for GET, false for others) */
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
/** How long data stays fresh before refetching (ms, default: 0 - always stale) */
|
|
35
|
+
staleTime?: number;
|
|
36
|
+
/** Refetch interval in milliseconds (default: disabled) */
|
|
37
|
+
refetchInterval?: number;
|
|
38
|
+
/** Callback when request succeeds */
|
|
39
|
+
onSuccess?: (data: RouteOutput<TRoute>) => void;
|
|
40
|
+
/** Callback when request fails */
|
|
41
|
+
onError?: (error: Error) => void;
|
|
42
|
+
} & (ExtractMethod<TRoute> extends 'GET' ? {
|
|
43
|
+
/** GET requests cannot have input (use query params instead) */
|
|
44
|
+
input?: never;
|
|
45
|
+
} : {
|
|
46
|
+
/** Input data for the request (required for POST/PUT/PATCH/DELETE) */
|
|
47
|
+
input?: RouteInput<TRoute>;
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* Options with route property (e.g., { route: 'GET /users' })
|
|
51
|
+
*/
|
|
52
|
+
type UseAPIOptionsWithRoute<TRoute extends RouteKey> = UseAPICommonOptions<TRoute> & {
|
|
53
|
+
/** Route key (e.g., 'GET /users', 'POST /users') */
|
|
54
|
+
route: TRoute;
|
|
55
|
+
/** Method cannot be specified when using route */
|
|
56
|
+
method?: never;
|
|
57
|
+
/** Path cannot be specified when using route */
|
|
58
|
+
path?: never;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Options with method and path properties (e.g., { method: 'GET', path: '/users' })
|
|
62
|
+
*/
|
|
63
|
+
type UseAPIOptionsWithMethodPath<TRoute extends RouteKey> = UseAPICommonOptions<TRoute> & {
|
|
64
|
+
/** HTTP method (e.g., 'GET', 'POST') */
|
|
65
|
+
method: ExtractMethod<TRoute>;
|
|
66
|
+
/** Request path (e.g., '/users') */
|
|
67
|
+
path: string;
|
|
68
|
+
/** Route cannot be specified when using method/path */
|
|
69
|
+
route?: never;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Options for useAPI hook with smart input typing based on HTTP method
|
|
73
|
+
* Supports either route OR {method, path} but not both
|
|
74
|
+
*/
|
|
75
|
+
export type UseAPIOptions<TRoute extends RouteKey> = UseAPIOptionsWithRoute<TRoute> | UseAPIOptionsWithMethodPath<TRoute>;
|
|
76
|
+
/**
|
|
77
|
+
* Base return value from useAPI hook (without data property or execute)
|
|
78
|
+
*/
|
|
79
|
+
interface UseAPIResultBase {
|
|
80
|
+
/** Error if request failed */
|
|
81
|
+
error: Error | null;
|
|
82
|
+
/** Whether request is currently in progress */
|
|
83
|
+
isLoading: boolean;
|
|
84
|
+
/** Whether request has completed successfully at least once */
|
|
85
|
+
isSuccess: boolean;
|
|
86
|
+
/** Whether request has failed */
|
|
87
|
+
isError: boolean;
|
|
88
|
+
/** Whether data is currently being fetched (including refetches) */
|
|
89
|
+
isFetching: boolean;
|
|
90
|
+
/** Reset state to initial values */
|
|
91
|
+
reset: () => void;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Return value for GET requests (auto-executing)
|
|
95
|
+
*/
|
|
96
|
+
type UseAPIResultQuery<TRoute extends RouteKey> = UseAPIResultBase & (RouteOutput<TRoute> extends void ? {
|
|
97
|
+
/** No data property - route returns no content (204 No Content) */
|
|
98
|
+
data?: never;
|
|
99
|
+
/** Manually trigger a refetch */
|
|
100
|
+
refetch: () => Promise<void>;
|
|
101
|
+
} : {
|
|
102
|
+
/** Response data (undefined until loaded) */
|
|
103
|
+
data: RouteOutput<TRoute> | undefined;
|
|
104
|
+
/** Manually trigger a refetch */
|
|
105
|
+
refetch: () => Promise<void>;
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* Return value for POST/PUT/PATCH/DELETE requests (manual execution)
|
|
109
|
+
*/
|
|
110
|
+
type UseAPIResultMutation<TRoute extends RouteKey> = UseAPIResultBase & (RouteOutput<TRoute> extends void ? {
|
|
111
|
+
/** No data property - route returns no content (204 No Content) */
|
|
112
|
+
data?: never;
|
|
113
|
+
/** Invoke the mutation with required input */
|
|
114
|
+
invoke: RouteInput<TRoute> extends never ? () => Promise<void> : (input: RouteInput<TRoute>) => Promise<void>;
|
|
115
|
+
} : {
|
|
116
|
+
/** Response data (undefined until invoked) */
|
|
117
|
+
data: RouteOutput<TRoute> | undefined;
|
|
118
|
+
/** Invoke the mutation with required input */
|
|
119
|
+
invoke: RouteInput<TRoute> extends never ? () => Promise<RouteOutput<TRoute>> : (input: RouteInput<TRoute>) => Promise<RouteOutput<TRoute>>;
|
|
120
|
+
});
|
|
121
|
+
/**
|
|
122
|
+
* Return value from useAPI hook
|
|
123
|
+
* - GET requests: Auto-executes, returns refetch()
|
|
124
|
+
* - POST/PUT/PATCH/DELETE: Manual execution, returns execute(input)
|
|
125
|
+
*/
|
|
126
|
+
export type UseAPIResult<TRoute extends RouteKey> = ExtractMethod<TRoute> extends 'GET' ? UseAPIResultQuery<TRoute> : UseAPIResultMutation<TRoute>;
|
|
127
|
+
/**
|
|
128
|
+
* Type-safe API client hook with TanStack Query-inspired features.
|
|
129
|
+
*
|
|
130
|
+
* Provides automatic type inference for route inputs and outputs based on
|
|
131
|
+
* the RouteRegistry generated from your routes.
|
|
132
|
+
*
|
|
133
|
+
* **Smart input typing:**
|
|
134
|
+
* - GET requests: `input` is `never` (use `query` params instead)
|
|
135
|
+
* - POST/PUT/PATCH/DELETE: `input` is properly typed from route schema
|
|
136
|
+
*
|
|
137
|
+
* @template TRoute - Route key from RouteRegistry (e.g., 'GET /users')
|
|
138
|
+
*
|
|
139
|
+
* @example Simple GET request with string
|
|
140
|
+
* ```typescript
|
|
141
|
+
* const { data, isLoading } = useAPI('GET /users');
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* @example GET request with route property
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const { data, isLoading } = useAPI({
|
|
147
|
+
* route: 'GET /users',
|
|
148
|
+
* query: { search: 'alice' }, // ✅ Use query params for GET
|
|
149
|
+
* // input: { ... }, // ❌ TypeScript error - GET cannot have input!
|
|
150
|
+
* staleTime: 5000,
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @example GET request with method and path
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const { data, isLoading } = useAPI({
|
|
157
|
+
* method: 'GET',
|
|
158
|
+
* path: '/users',
|
|
159
|
+
* query: { search: 'alice' },
|
|
160
|
+
* });
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @example POST request with manual invocation
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const { invoke, data, isLoading } = useAPI('POST /users');
|
|
166
|
+
*
|
|
167
|
+
* // Invoke manually with input
|
|
168
|
+
* await invoke({ name: 'Alice', email: 'alice@example.com' }); // ✅ Fully typed!
|
|
169
|
+
* // data now contains the created user
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* @example GET with query parameters
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const { data } = useAPI({
|
|
175
|
+
* route: 'GET /search',
|
|
176
|
+
* query: { q: 'react', limit: '10' },
|
|
177
|
+
* });
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @example DELETE with no response body (204 No Content)
|
|
181
|
+
* ```typescript
|
|
182
|
+
* const { invoke, isSuccess } = useAPI('DELETE /users/:id');
|
|
183
|
+
*
|
|
184
|
+
* // Invoke when needed
|
|
185
|
+
* await invoke({ reason: 'Account closed' });
|
|
186
|
+
*
|
|
187
|
+
* // result.data doesn't exist! ❌ TypeScript error
|
|
188
|
+
* // Use isSuccess instead ✅
|
|
189
|
+
* if (isSuccess) {
|
|
190
|
+
* console.log('User deleted');
|
|
191
|
+
* }
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export declare function useAPI<TRoute extends RouteKey>(routeOrOptions: TRoute | UseAPIOptions<TRoute>): UseAPIResult<TRoute>;
|
|
195
|
+
export {};
|
|
196
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { AgentuityContext } from './context';
|
|
4
|
+
import { deserializeData } from './serialization';
|
|
5
|
+
import { buildUrl } from './url';
|
|
6
|
+
/**
|
|
7
|
+
* Parse route key into method and path
|
|
8
|
+
*/
|
|
9
|
+
function parseRouteKey(routeKey) {
|
|
10
|
+
const parts = routeKey.split(' ');
|
|
11
|
+
if (parts.length !== 2) {
|
|
12
|
+
throw new Error(`Invalid route key format: "${routeKey}". Expected "METHOD /path"`);
|
|
13
|
+
}
|
|
14
|
+
return { method: parts[0], path: parts[1] };
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert query object to URLSearchParams
|
|
18
|
+
*/
|
|
19
|
+
function toSearchParams(query) {
|
|
20
|
+
if (!query)
|
|
21
|
+
return undefined;
|
|
22
|
+
if (query instanceof URLSearchParams)
|
|
23
|
+
return query;
|
|
24
|
+
return new URLSearchParams(query);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Type-safe API client hook with TanStack Query-inspired features.
|
|
28
|
+
*
|
|
29
|
+
* Provides automatic type inference for route inputs and outputs based on
|
|
30
|
+
* the RouteRegistry generated from your routes.
|
|
31
|
+
*
|
|
32
|
+
* **Smart input typing:**
|
|
33
|
+
* - GET requests: `input` is `never` (use `query` params instead)
|
|
34
|
+
* - POST/PUT/PATCH/DELETE: `input` is properly typed from route schema
|
|
35
|
+
*
|
|
36
|
+
* @template TRoute - Route key from RouteRegistry (e.g., 'GET /users')
|
|
37
|
+
*
|
|
38
|
+
* @example Simple GET request with string
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const { data, isLoading } = useAPI('GET /users');
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example GET request with route property
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const { data, isLoading } = useAPI({
|
|
46
|
+
* route: 'GET /users',
|
|
47
|
+
* query: { search: 'alice' }, // ✅ Use query params for GET
|
|
48
|
+
* // input: { ... }, // ❌ TypeScript error - GET cannot have input!
|
|
49
|
+
* staleTime: 5000,
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example GET request with method and path
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const { data, isLoading } = useAPI({
|
|
56
|
+
* method: 'GET',
|
|
57
|
+
* path: '/users',
|
|
58
|
+
* query: { search: 'alice' },
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example POST request with manual invocation
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const { invoke, data, isLoading } = useAPI('POST /users');
|
|
65
|
+
*
|
|
66
|
+
* // Invoke manually with input
|
|
67
|
+
* await invoke({ name: 'Alice', email: 'alice@example.com' }); // ✅ Fully typed!
|
|
68
|
+
* // data now contains the created user
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example GET with query parameters
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const { data } = useAPI({
|
|
74
|
+
* route: 'GET /search',
|
|
75
|
+
* query: { q: 'react', limit: '10' },
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @example DELETE with no response body (204 No Content)
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const { invoke, isSuccess } = useAPI('DELETE /users/:id');
|
|
82
|
+
*
|
|
83
|
+
* // Invoke when needed
|
|
84
|
+
* await invoke({ reason: 'Account closed' });
|
|
85
|
+
*
|
|
86
|
+
* // result.data doesn't exist! ❌ TypeScript error
|
|
87
|
+
* // Use isSuccess instead ✅
|
|
88
|
+
* if (isSuccess) {
|
|
89
|
+
* console.log('User deleted');
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export function useAPI(routeOrOptions) {
|
|
94
|
+
// Normalize to options object
|
|
95
|
+
const options = typeof routeOrOptions === 'string'
|
|
96
|
+
? { route: routeOrOptions }
|
|
97
|
+
: routeOrOptions;
|
|
98
|
+
const context = useContext(AgentuityContext);
|
|
99
|
+
const { input, query, headers, enabled, staleTime = 0, refetchInterval, onSuccess, onError, } = options;
|
|
100
|
+
if (!context) {
|
|
101
|
+
throw new Error('useAPI must be used within AgentuityProvider');
|
|
102
|
+
}
|
|
103
|
+
// Extract method and path from either route OR {method, path}
|
|
104
|
+
let method;
|
|
105
|
+
let path;
|
|
106
|
+
if ('route' in options && options.route) {
|
|
107
|
+
const parsed = parseRouteKey(options.route);
|
|
108
|
+
method = parsed.method;
|
|
109
|
+
path = parsed.path;
|
|
110
|
+
}
|
|
111
|
+
else if ('method' in options && 'path' in options && options.method && options.path) {
|
|
112
|
+
method = options.method;
|
|
113
|
+
path = options.path;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
throw new Error('useAPI requires either route OR {method, path}');
|
|
117
|
+
}
|
|
118
|
+
const [data, setData] = useState(undefined);
|
|
119
|
+
const [error, setError] = useState(null);
|
|
120
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
121
|
+
const [isFetching, setIsFetching] = useState(false);
|
|
122
|
+
const [isSuccess, setIsSuccess] = useState(false);
|
|
123
|
+
const [isError, setIsError] = useState(false);
|
|
124
|
+
const lastFetchTimeRef = useRef(0);
|
|
125
|
+
// Track mounted state to prevent state updates after unmount
|
|
126
|
+
const mountedRef = useRef(true);
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
mountedRef.current = true;
|
|
129
|
+
return () => {
|
|
130
|
+
mountedRef.current = false;
|
|
131
|
+
};
|
|
132
|
+
}, []);
|
|
133
|
+
const fetchData = useCallback(async () => {
|
|
134
|
+
if (!mountedRef.current)
|
|
135
|
+
return;
|
|
136
|
+
const now = Date.now();
|
|
137
|
+
const lastFetchTime = lastFetchTimeRef.current;
|
|
138
|
+
// Check if data is still fresh based on last fetch time
|
|
139
|
+
const isFresh = staleTime > 0 && lastFetchTime !== 0 && now - lastFetchTime < staleTime;
|
|
140
|
+
if (isFresh) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
setIsFetching(true);
|
|
144
|
+
// isLoading = only for first load (or after reset)
|
|
145
|
+
if (lastFetchTime === 0) {
|
|
146
|
+
setIsLoading(true);
|
|
147
|
+
}
|
|
148
|
+
setError(null);
|
|
149
|
+
setIsError(false);
|
|
150
|
+
try {
|
|
151
|
+
const url = buildUrl(context.baseUrl || '', path, undefined, toSearchParams(query));
|
|
152
|
+
const requestInit = {
|
|
153
|
+
method,
|
|
154
|
+
headers: {
|
|
155
|
+
'Content-Type': 'application/json',
|
|
156
|
+
...headers,
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
// Add body for non-GET requests
|
|
160
|
+
if (method !== 'GET' && input !== undefined) {
|
|
161
|
+
requestInit.body = JSON.stringify(input);
|
|
162
|
+
}
|
|
163
|
+
const response = await fetch(url, requestInit);
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
166
|
+
}
|
|
167
|
+
let responseData;
|
|
168
|
+
// Handle 204 No Content - no response body expected
|
|
169
|
+
if (response.status === 204) {
|
|
170
|
+
responseData = undefined;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
const contentType = response.headers.get('Content-Type') || '';
|
|
174
|
+
if (contentType.includes('application/json')) {
|
|
175
|
+
responseData = await response.json();
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const text = await response.text();
|
|
179
|
+
responseData = deserializeData(text);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (!mountedRef.current)
|
|
183
|
+
return;
|
|
184
|
+
// Use JSON memoization to prevent re-renders when data hasn't changed
|
|
185
|
+
setData((prev) => {
|
|
186
|
+
const newData = responseData;
|
|
187
|
+
if (prev !== undefined && JSON.stringify(prev) === JSON.stringify(newData)) {
|
|
188
|
+
return prev;
|
|
189
|
+
}
|
|
190
|
+
return newData;
|
|
191
|
+
});
|
|
192
|
+
setIsSuccess(true);
|
|
193
|
+
lastFetchTimeRef.current = Date.now();
|
|
194
|
+
onSuccess?.(responseData);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
if (!mountedRef.current)
|
|
198
|
+
return;
|
|
199
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
200
|
+
setError(error);
|
|
201
|
+
setIsError(true);
|
|
202
|
+
onError?.(error);
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
if (mountedRef.current) {
|
|
206
|
+
setIsLoading(false);
|
|
207
|
+
setIsFetching(false);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}, [context.baseUrl, path, method, input, query, headers, staleTime, onSuccess, onError]);
|
|
211
|
+
const reset = useCallback(() => {
|
|
212
|
+
setData(undefined);
|
|
213
|
+
setError(null);
|
|
214
|
+
setIsLoading(false);
|
|
215
|
+
setIsFetching(false);
|
|
216
|
+
setIsSuccess(false);
|
|
217
|
+
setIsError(false);
|
|
218
|
+
lastFetchTimeRef.current = 0;
|
|
219
|
+
}, []);
|
|
220
|
+
// For GET requests: auto-fetch and provide refetch
|
|
221
|
+
if (method === 'GET') {
|
|
222
|
+
const refetch = useCallback(async () => {
|
|
223
|
+
await fetchData();
|
|
224
|
+
}, [fetchData]);
|
|
225
|
+
// Auto-fetch on mount if enabled (default: true for GET)
|
|
226
|
+
const shouldAutoFetch = enabled ?? true;
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
if (shouldAutoFetch) {
|
|
229
|
+
fetchData();
|
|
230
|
+
}
|
|
231
|
+
}, [shouldAutoFetch, fetchData]);
|
|
232
|
+
// Refetch interval
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
if (!refetchInterval || refetchInterval <= 0)
|
|
235
|
+
return;
|
|
236
|
+
const interval = setInterval(() => {
|
|
237
|
+
fetchData();
|
|
238
|
+
}, refetchInterval);
|
|
239
|
+
return () => clearInterval(interval);
|
|
240
|
+
}, [refetchInterval, fetchData]);
|
|
241
|
+
return {
|
|
242
|
+
data,
|
|
243
|
+
error,
|
|
244
|
+
isLoading,
|
|
245
|
+
isSuccess,
|
|
246
|
+
isError,
|
|
247
|
+
isFetching,
|
|
248
|
+
refetch,
|
|
249
|
+
reset,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
// For POST/PUT/PATCH/DELETE: provide invoke method (manual invocation)
|
|
253
|
+
const invoke = useCallback(async (invokeInput) => {
|
|
254
|
+
// Use invokeInput parameter if provided
|
|
255
|
+
const effectiveInput = invokeInput !== undefined ? invokeInput : input;
|
|
256
|
+
setIsFetching(true);
|
|
257
|
+
setIsLoading(true);
|
|
258
|
+
setError(null);
|
|
259
|
+
setIsError(false);
|
|
260
|
+
try {
|
|
261
|
+
const url = buildUrl(context.baseUrl || '', path, undefined, toSearchParams(query));
|
|
262
|
+
const requestInit = {
|
|
263
|
+
method,
|
|
264
|
+
headers: {
|
|
265
|
+
'Content-Type': 'application/json',
|
|
266
|
+
...headers,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
if (effectiveInput !== undefined) {
|
|
270
|
+
requestInit.body = JSON.stringify(effectiveInput);
|
|
271
|
+
}
|
|
272
|
+
const response = await fetch(url, requestInit);
|
|
273
|
+
if (!response.ok) {
|
|
274
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
275
|
+
}
|
|
276
|
+
let responseData;
|
|
277
|
+
if (response.status === 204) {
|
|
278
|
+
responseData = undefined;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const contentType = response.headers.get('Content-Type') || '';
|
|
282
|
+
if (contentType.includes('application/json')) {
|
|
283
|
+
responseData = await response.json();
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const text = await response.text();
|
|
287
|
+
responseData = deserializeData(text);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (!mountedRef.current)
|
|
291
|
+
return responseData;
|
|
292
|
+
setData(responseData);
|
|
293
|
+
setIsSuccess(true);
|
|
294
|
+
lastFetchTimeRef.current = Date.now();
|
|
295
|
+
onSuccess?.(responseData);
|
|
296
|
+
return responseData;
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
if (!mountedRef.current)
|
|
300
|
+
throw err;
|
|
301
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
302
|
+
setError(error);
|
|
303
|
+
setIsError(true);
|
|
304
|
+
onError?.(error);
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
finally {
|
|
308
|
+
if (mountedRef.current) {
|
|
309
|
+
setIsLoading(false);
|
|
310
|
+
setIsFetching(false);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}, [context.baseUrl, path, method, query, headers, input, onSuccess, onError]);
|
|
314
|
+
return {
|
|
315
|
+
data,
|
|
316
|
+
error,
|
|
317
|
+
isLoading,
|
|
318
|
+
isSuccess,
|
|
319
|
+
isError,
|
|
320
|
+
isFetching,
|
|
321
|
+
invoke,
|
|
322
|
+
reset,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAQpD,CAAC"}
|
package/dist/env.js
CHANGED
|
@@ -2,6 +2,9 @@ export const getProcessEnv = (key) => {
|
|
|
2
2
|
if (typeof process !== 'undefined' && process.env) {
|
|
3
3
|
return process.env[key];
|
|
4
4
|
}
|
|
5
|
+
if (typeof import.meta.env !== 'undefined') {
|
|
6
|
+
return import.meta.env[key];
|
|
7
|
+
}
|
|
5
8
|
return undefined;
|
|
6
9
|
};
|
|
7
10
|
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAsB,EAAE;IAChE,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAsB,EAAE;IAChE,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;QAC5C,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC"}
|
package/dist/eventstream.d.ts
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
import type { InferOutput } from '@agentuity/core';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SSERouteRegistry } from './types';
|
|
3
3
|
type onMessageHandler<T = unknown> = (data: T) => void;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Extract SSE route keys (e.g., '/events', '/notifications')
|
|
6
|
+
*/
|
|
7
|
+
export type SSERouteKey = keyof SSERouteRegistry;
|
|
8
|
+
/**
|
|
9
|
+
* Extract output type for an SSE route (SSE is typically one-way server->client)
|
|
10
|
+
*/
|
|
11
|
+
export type SSERouteOutput<TRoute extends SSERouteKey> = TRoute extends keyof SSERouteRegistry ? SSERouteRegistry[TRoute] extends {
|
|
12
|
+
outputSchema: infer TSchema;
|
|
13
|
+
} ? TSchema extends undefined | never ? void : InferOutput<TSchema> : void : void;
|
|
14
|
+
/**
|
|
15
|
+
* Options for EventStream hooks
|
|
16
|
+
*/
|
|
17
|
+
export interface EventStreamOptions {
|
|
5
18
|
/**
|
|
6
19
|
* Optional query parameters to append to the EventStream URL
|
|
7
20
|
*/
|
|
8
21
|
query?: URLSearchParams;
|
|
9
22
|
/**
|
|
10
|
-
* Optional subpath to append to the
|
|
23
|
+
* Optional subpath to append to the EventStream path
|
|
11
24
|
*/
|
|
12
25
|
subpath?: string;
|
|
13
26
|
/**
|
|
@@ -15,22 +28,48 @@ interface EventStreamArgs {
|
|
|
15
28
|
*/
|
|
16
29
|
signal?: AbortSignal;
|
|
17
30
|
}
|
|
18
|
-
interface
|
|
19
|
-
connected
|
|
31
|
+
interface EventStreamResponseInternal<TOutput> {
|
|
32
|
+
/** Whether EventStream is currently connected */
|
|
33
|
+
isConnected: boolean;
|
|
34
|
+
/** Most recent data received from EventStream */
|
|
20
35
|
data?: TOutput;
|
|
36
|
+
/** Error if connection or message failed */
|
|
21
37
|
error: Error | null;
|
|
38
|
+
/** Whether an error has occurred */
|
|
39
|
+
isError: boolean;
|
|
40
|
+
/** Set handler for incoming messages (use data property instead) */
|
|
22
41
|
setHandler: (handler: onMessageHandler<TOutput>) => void;
|
|
42
|
+
/** EventStream connection state (CONNECTING=0, OPEN=1, CLOSED=2) */
|
|
23
43
|
readyState: number;
|
|
44
|
+
/** Close the EventStream connection */
|
|
24
45
|
close: () => void;
|
|
46
|
+
/** Reset state to initial values */
|
|
25
47
|
reset: () => void;
|
|
26
48
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Type-safe EventStream (SSE) hook for connecting to SSE routes.
|
|
51
|
+
*
|
|
52
|
+
* Provides automatic type inference for route outputs based on
|
|
53
|
+
* the SSERouteRegistry generated from your routes.
|
|
54
|
+
*
|
|
55
|
+
* @template TRoute - SSE route key from SSERouteRegistry (e.g., '/events', '/notifications')
|
|
56
|
+
*
|
|
57
|
+
* @example Simple SSE connection
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const { isConnected, data } = useEventStream('/events');
|
|
60
|
+
*
|
|
61
|
+
* // data is fully typed based on route output schema!
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example SSE with query parameters
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const { isConnected, data } = useEventStream('/notifications', {
|
|
67
|
+
* query: new URLSearchParams({ userId: '123' })
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function useEventStream<TRoute extends SSERouteKey>(route: TRoute, options?: EventStreamOptions): Omit<EventStreamResponseInternal<SSERouteOutput<TRoute>>, 'setHandler'> & {
|
|
72
|
+
data?: SSERouteOutput<TRoute>;
|
|
73
|
+
};
|
|
35
74
|
export {};
|
|
36
75
|
//# sourceMappingURL=eventstream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eventstream.d.ts","sourceRoot":"","sources":["../src/eventstream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"eventstream.d.ts","sourceRoot":"","sources":["../src/eventstream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAMnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,KAAK,gBAAgB,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;AAEvD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,MAAM,SAAS,WAAW,IAAI,MAAM,SAAS,MAAM,gBAAgB,GAC3F,gBAAgB,CAAC,MAAM,CAAC,SAAS;IAAE,YAAY,EAAE,MAAM,OAAO,CAAA;CAAE,GAC/D,OAAO,SAAS,SAAS,GAAG,KAAK,GAChC,IAAI,GACJ,WAAW,CAAC,OAAO,CAAC,GACrB,IAAI,GACL,IAAI,CAAC;AAER;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,UAAU,2BAA2B,CAAC,OAAO;IAC5C,iDAAiD;IACjD,WAAW,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,UAAU,EAAE,CAAC,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACzD,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,oCAAoC;IACpC,KAAK,EAAE,MAAM,IAAI,CAAC;CAClB;AA8JD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,MAAM,SAAS,WAAW,EACxD,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,kBAAkB,GAC1B,IAAI,CAAC,2BAA2B,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG;IAC5E,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CAC9B,CAkBA"}
|