@robosystems/client 0.1.10 → 0.1.11
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/extensions/OperationClient.js +297 -0
- package/extensions/OperationClient.ts +322 -0
- package/extensions/QueryClient.js +245 -0
- package/extensions/QueryClient.ts +283 -0
- package/extensions/SSEClient.js +166 -0
- package/extensions/SSEClient.ts +189 -0
- package/extensions/config.js +66 -0
- package/extensions/config.ts +91 -0
- package/extensions/hooks.js +435 -0
- package/extensions/hooks.ts +438 -0
- package/extensions/index.js +118 -0
- package/extensions/index.ts +123 -0
- package/package.json +2 -1
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* React hooks for SDK extensions
|
|
5
|
+
* Provides easy-to-use hooks for Next.js/React applications
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
9
|
+
import { client } from '../client.gen'
|
|
10
|
+
import { getSDKExtensionsConfig } from './config'
|
|
11
|
+
import type { OperationProgress, OperationResult } from './OperationClient'
|
|
12
|
+
import { OperationClient } from './OperationClient'
|
|
13
|
+
import type { QueryOptions, QueryResult } from './QueryClient'
|
|
14
|
+
import { QueryClient } from './QueryClient'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Hook for executing Cypher queries with loading states and error handling
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const { execute, loading, error, data } = useQuery('graph_123')
|
|
22
|
+
*
|
|
23
|
+
* const handleSearch = async () => {
|
|
24
|
+
* const result = await execute('MATCH (n:Company) RETURN n LIMIT 10')
|
|
25
|
+
* console.log(result.data)
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function useQuery(graphId: string) {
|
|
30
|
+
const [loading, setLoading] = useState(false)
|
|
31
|
+
const [error, setError] = useState<Error | null>(null)
|
|
32
|
+
const [data, setData] = useState<QueryResult | null>(null)
|
|
33
|
+
const [queuePosition, setQueuePosition] = useState<number | null>(null)
|
|
34
|
+
const clientRef = useRef<QueryClient>()
|
|
35
|
+
|
|
36
|
+
// Initialize client
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const sdkConfig = getSDKExtensionsConfig()
|
|
39
|
+
const clientConfig = client.getConfig()
|
|
40
|
+
clientRef.current = new QueryClient({
|
|
41
|
+
baseUrl: sdkConfig.baseUrl || clientConfig.baseUrl || 'http://localhost:8000',
|
|
42
|
+
credentials: sdkConfig.credentials,
|
|
43
|
+
headers: sdkConfig.headers,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return () => {
|
|
47
|
+
clientRef.current?.close()
|
|
48
|
+
}
|
|
49
|
+
}, [])
|
|
50
|
+
|
|
51
|
+
const execute = useCallback(
|
|
52
|
+
async (
|
|
53
|
+
query: string,
|
|
54
|
+
parameters?: Record<string, any>,
|
|
55
|
+
options?: QueryOptions
|
|
56
|
+
): Promise<QueryResult | null> => {
|
|
57
|
+
if (!clientRef.current) return null
|
|
58
|
+
|
|
59
|
+
setLoading(true)
|
|
60
|
+
setError(null)
|
|
61
|
+
setData(null)
|
|
62
|
+
setQueuePosition(null)
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const result = (await clientRef.current.executeQuery(
|
|
66
|
+
graphId,
|
|
67
|
+
{ query, parameters },
|
|
68
|
+
{
|
|
69
|
+
...options,
|
|
70
|
+
onQueueUpdate: (position) => {
|
|
71
|
+
setQueuePosition(position)
|
|
72
|
+
},
|
|
73
|
+
onProgress: () => {
|
|
74
|
+
setQueuePosition(null) // Clear queue position when executing
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
)) as QueryResult
|
|
78
|
+
|
|
79
|
+
setData(result)
|
|
80
|
+
return result
|
|
81
|
+
} catch (err) {
|
|
82
|
+
const error = err as Error
|
|
83
|
+
setError(error)
|
|
84
|
+
return null
|
|
85
|
+
} finally {
|
|
86
|
+
setLoading(false)
|
|
87
|
+
setQueuePosition(null)
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
[graphId]
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
// Simple query method that returns just the data
|
|
94
|
+
const query = useCallback(
|
|
95
|
+
async (cypher: string, parameters?: Record<string, any>) => {
|
|
96
|
+
const result = await execute(cypher, parameters)
|
|
97
|
+
return result?.data || []
|
|
98
|
+
},
|
|
99
|
+
[execute]
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
execute,
|
|
104
|
+
query,
|
|
105
|
+
loading,
|
|
106
|
+
error,
|
|
107
|
+
data,
|
|
108
|
+
queuePosition,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Hook for streaming large query results
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* const { stream, isStreaming, error, cancel } = useStreamingQuery('graph_123')
|
|
118
|
+
*
|
|
119
|
+
* const handleStream = async () => {
|
|
120
|
+
* const iterator = stream('MATCH (n) RETURN n')
|
|
121
|
+
* for await (const batch of iterator) {
|
|
122
|
+
* console.log('Received batch:', batch)
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export function useStreamingQuery(graphId: string) {
|
|
128
|
+
const [isStreaming, setIsStreaming] = useState(false)
|
|
129
|
+
const [error, setError] = useState<Error | null>(null)
|
|
130
|
+
const [rowsReceived, setRowsReceived] = useState(0)
|
|
131
|
+
const clientRef = useRef<QueryClient>()
|
|
132
|
+
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
const sdkConfig = getSDKExtensionsConfig()
|
|
135
|
+
const clientConfig = client.getConfig()
|
|
136
|
+
clientRef.current = new QueryClient({
|
|
137
|
+
baseUrl: sdkConfig.baseUrl || clientConfig.baseUrl || 'http://localhost:8000',
|
|
138
|
+
credentials: sdkConfig.credentials,
|
|
139
|
+
headers: sdkConfig.headers,
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
return () => {
|
|
143
|
+
clientRef.current?.close()
|
|
144
|
+
}
|
|
145
|
+
}, [])
|
|
146
|
+
|
|
147
|
+
const stream = useCallback(
|
|
148
|
+
async function* (
|
|
149
|
+
query: string,
|
|
150
|
+
parameters?: Record<string, any>,
|
|
151
|
+
chunkSize: number = 100
|
|
152
|
+
): AsyncIterableIterator<any[]> {
|
|
153
|
+
if (!clientRef.current) return
|
|
154
|
+
|
|
155
|
+
setIsStreaming(true)
|
|
156
|
+
setError(null)
|
|
157
|
+
setRowsReceived(0)
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const iterator = clientRef.current.streamQuery(graphId, query, parameters, chunkSize)
|
|
161
|
+
|
|
162
|
+
let buffer: any[] = []
|
|
163
|
+
let count = 0
|
|
164
|
+
|
|
165
|
+
for await (const row of iterator) {
|
|
166
|
+
buffer.push(row)
|
|
167
|
+
count++
|
|
168
|
+
|
|
169
|
+
if (buffer.length >= chunkSize) {
|
|
170
|
+
setRowsReceived(count)
|
|
171
|
+
yield buffer
|
|
172
|
+
buffer = []
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Yield any remaining items
|
|
177
|
+
if (buffer.length > 0) {
|
|
178
|
+
setRowsReceived(count)
|
|
179
|
+
yield buffer
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
setError(err as Error)
|
|
183
|
+
throw err
|
|
184
|
+
} finally {
|
|
185
|
+
setIsStreaming(false)
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
[graphId]
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
const cancel = useCallback(() => {
|
|
192
|
+
clientRef.current?.close()
|
|
193
|
+
setIsStreaming(false)
|
|
194
|
+
}, [])
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
stream,
|
|
198
|
+
isStreaming,
|
|
199
|
+
error,
|
|
200
|
+
rowsReceived,
|
|
201
|
+
cancel,
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Hook for monitoring long-running operations
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```tsx
|
|
210
|
+
* const { monitor, status, progress, error, result } = useOperation<BackupResult>()
|
|
211
|
+
*
|
|
212
|
+
* const handleBackup = async () => {
|
|
213
|
+
* const { operation_id } = await createBackup({ ... })
|
|
214
|
+
* const result = await monitor(operation_id)
|
|
215
|
+
* console.log('Backup completed:', result)
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export function useOperation<T = any>(operationId?: string) {
|
|
220
|
+
const [status, setStatus] = useState<'idle' | 'running' | 'completed' | 'error'>('idle')
|
|
221
|
+
const [progress, setProgress] = useState<OperationProgress | null>(null)
|
|
222
|
+
const [error, setError] = useState<Error | null>(null)
|
|
223
|
+
const [result, setResult] = useState<OperationResult<T> | null>(null)
|
|
224
|
+
const clientRef = useRef<OperationClient>()
|
|
225
|
+
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
const sdkConfig = getSDKExtensionsConfig()
|
|
228
|
+
const clientConfig = client.getConfig()
|
|
229
|
+
clientRef.current = new OperationClient({
|
|
230
|
+
baseUrl: sdkConfig.baseUrl || clientConfig.baseUrl || 'http://localhost:8000',
|
|
231
|
+
credentials: sdkConfig.credentials,
|
|
232
|
+
maxRetries: sdkConfig.maxRetries,
|
|
233
|
+
retryDelay: sdkConfig.retryDelay,
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
return () => {
|
|
237
|
+
clientRef.current?.closeAll()
|
|
238
|
+
}
|
|
239
|
+
}, [])
|
|
240
|
+
|
|
241
|
+
const monitor = useCallback(
|
|
242
|
+
async (id: string, timeout?: number): Promise<OperationResult<T> | null> => {
|
|
243
|
+
if (!clientRef.current) return null
|
|
244
|
+
|
|
245
|
+
setStatus('running')
|
|
246
|
+
setError(null)
|
|
247
|
+
setResult(null)
|
|
248
|
+
setProgress(null)
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
const opResult = await clientRef.current.monitorOperation<T>(id, {
|
|
252
|
+
onProgress: (p) => {
|
|
253
|
+
setProgress(p)
|
|
254
|
+
},
|
|
255
|
+
onQueueUpdate: (position, estimatedWait) => {
|
|
256
|
+
setProgress({
|
|
257
|
+
message: `Queue position: ${position}`,
|
|
258
|
+
progressPercent: 0,
|
|
259
|
+
details: { position, estimatedWait },
|
|
260
|
+
})
|
|
261
|
+
},
|
|
262
|
+
timeout,
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
setResult(opResult)
|
|
266
|
+
setStatus(opResult.success ? 'completed' : 'error')
|
|
267
|
+
|
|
268
|
+
if (!opResult.success && opResult.error) {
|
|
269
|
+
setError(new Error(opResult.error))
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return opResult
|
|
273
|
+
} catch (err) {
|
|
274
|
+
const error = err as Error
|
|
275
|
+
setError(error)
|
|
276
|
+
setStatus('error')
|
|
277
|
+
return null
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
[]
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
const cancel = useCallback(async (id: string) => {
|
|
284
|
+
if (!clientRef.current) return
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
await clientRef.current.cancelOperation(id)
|
|
288
|
+
setStatus('idle')
|
|
289
|
+
} catch (err) {
|
|
290
|
+
setError(err as Error)
|
|
291
|
+
}
|
|
292
|
+
}, [])
|
|
293
|
+
|
|
294
|
+
// Auto-monitor if operationId is provided
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
if (operationId && status === 'idle') {
|
|
297
|
+
monitor(operationId)
|
|
298
|
+
}
|
|
299
|
+
}, [operationId, monitor, status])
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
monitor,
|
|
303
|
+
cancel,
|
|
304
|
+
status,
|
|
305
|
+
progress,
|
|
306
|
+
error,
|
|
307
|
+
result,
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Hook for monitoring multiple operations concurrently
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```tsx
|
|
316
|
+
* const { monitorAll, results, allCompleted, hasErrors } = useMultipleOperations()
|
|
317
|
+
*
|
|
318
|
+
* const handleMultiple = async () => {
|
|
319
|
+
* const operations = await Promise.all([
|
|
320
|
+
* createBackup(...),
|
|
321
|
+
* createExport(...),
|
|
322
|
+
* ])
|
|
323
|
+
*
|
|
324
|
+
* const results = await monitorAll(operations.map(op => op.operation_id))
|
|
325
|
+
* }
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
export function useMultipleOperations<T = any>() {
|
|
329
|
+
const [results, setResults] = useState<Map<string, OperationResult<T>>>(new Map())
|
|
330
|
+
const [loading, setLoading] = useState(false)
|
|
331
|
+
const [errors, setErrors] = useState<Map<string, Error>>(new Map())
|
|
332
|
+
const clientRef = useRef<OperationClient>()
|
|
333
|
+
|
|
334
|
+
useEffect(() => {
|
|
335
|
+
const sdkConfig = getSDKExtensionsConfig()
|
|
336
|
+
const clientConfig = client.getConfig()
|
|
337
|
+
clientRef.current = new OperationClient({
|
|
338
|
+
baseUrl: sdkConfig.baseUrl || clientConfig.baseUrl || 'http://localhost:8000',
|
|
339
|
+
credentials: sdkConfig.credentials,
|
|
340
|
+
maxRetries: sdkConfig.maxRetries,
|
|
341
|
+
retryDelay: sdkConfig.retryDelay,
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
return () => {
|
|
345
|
+
clientRef.current?.closeAll()
|
|
346
|
+
}
|
|
347
|
+
}, [])
|
|
348
|
+
|
|
349
|
+
const monitorAll = useCallback(
|
|
350
|
+
async (operationIds: string[]): Promise<Map<string, OperationResult<T>>> => {
|
|
351
|
+
if (!clientRef.current) return new Map()
|
|
352
|
+
|
|
353
|
+
setLoading(true)
|
|
354
|
+
setResults(new Map())
|
|
355
|
+
setErrors(new Map())
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
const allResults = await clientRef.current.monitorMultiple<T>(operationIds)
|
|
359
|
+
setResults(allResults)
|
|
360
|
+
|
|
361
|
+
// Extract any errors
|
|
362
|
+
const newErrors = new Map<string, Error>()
|
|
363
|
+
allResults.forEach((result, id) => {
|
|
364
|
+
if (!result.success && result.error) {
|
|
365
|
+
newErrors.set(id, new Error(result.error))
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
setErrors(newErrors)
|
|
369
|
+
|
|
370
|
+
return allResults
|
|
371
|
+
} finally {
|
|
372
|
+
setLoading(false)
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
[]
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
const allCompleted =
|
|
379
|
+
results.size > 0 && Array.from(results.values()).every((r) => r.success || r.error)
|
|
380
|
+
|
|
381
|
+
const hasErrors = errors.size > 0
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
monitorAll,
|
|
385
|
+
results,
|
|
386
|
+
errors,
|
|
387
|
+
loading,
|
|
388
|
+
allCompleted,
|
|
389
|
+
hasErrors,
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Hook that provides access to all SDK extension clients
|
|
395
|
+
* Useful when you need direct access to the underlying clients
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* ```tsx
|
|
399
|
+
* const clients = useSDKClients()
|
|
400
|
+
*
|
|
401
|
+
* // Direct access to clients
|
|
402
|
+
* const result = await clients.query.query('graph_123', 'MATCH (n) RETURN n')
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
export function useSDKClients() {
|
|
406
|
+
const [clients, setClients] = useState<{
|
|
407
|
+
query: QueryClient | null
|
|
408
|
+
operations: OperationClient | null
|
|
409
|
+
}>({
|
|
410
|
+
query: null,
|
|
411
|
+
operations: null,
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
useEffect(() => {
|
|
415
|
+
const sdkConfig = getSDKExtensionsConfig()
|
|
416
|
+
const clientConfig = client.getConfig()
|
|
417
|
+
const baseConfig = {
|
|
418
|
+
baseUrl: sdkConfig.baseUrl || clientConfig.baseUrl || 'http://localhost:8000',
|
|
419
|
+
credentials: sdkConfig.credentials,
|
|
420
|
+
headers: sdkConfig.headers,
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const queryClient = new QueryClient(baseConfig)
|
|
424
|
+
const operationsClient = new OperationClient(baseConfig)
|
|
425
|
+
|
|
426
|
+
setClients({
|
|
427
|
+
query: queryClient,
|
|
428
|
+
operations: operationsClient,
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
return () => {
|
|
432
|
+
queryClient.close()
|
|
433
|
+
operationsClient.closeAll()
|
|
434
|
+
}
|
|
435
|
+
}, [])
|
|
436
|
+
|
|
437
|
+
return clients
|
|
438
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoboSystems SDK Extensions
|
|
3
|
+
* Enhanced clients with SSE support for the RoboSystems API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { client } from '../client.gen'
|
|
7
|
+
import { OperationClient } from './OperationClient'
|
|
8
|
+
import { QueryClient } from './QueryClient'
|
|
9
|
+
import { SSEClient } from './SSEClient'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export class RoboSystemsExtensions {
|
|
14
|
+
public readonly query
|
|
15
|
+
public readonly operations
|
|
16
|
+
private config
|
|
17
|
+
|
|
18
|
+
constructor(config = {}) {
|
|
19
|
+
// Get base URL from SDK client config or use provided/default
|
|
20
|
+
const sdkConfig = client.getConfig()
|
|
21
|
+
|
|
22
|
+
this.config = {
|
|
23
|
+
baseUrl.baseUrl || sdkConfig.baseUrl || 'http://localhost:8000',
|
|
24
|
+
credentials.credentials || 'include',
|
|
25
|
+
maxRetries.maxRetries || 5,
|
|
26
|
+
retryDelay.retryDelay || 1000,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.query = new QueryClient({
|
|
30
|
+
baseUrl.config.baseUrl,
|
|
31
|
+
credentials.config.credentials,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
this.operations = new OperationClient({
|
|
35
|
+
baseUrl.config.baseUrl,
|
|
36
|
+
credentials.config.credentials,
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convenience method to monitor any operation
|
|
42
|
+
*/
|
|
43
|
+
async monitorOperation(operationId, onProgress?) {
|
|
44
|
+
return this.operations.monitorOperation(operationId, { onProgress })
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Create custom SSE client for advanced use cases
|
|
49
|
+
*/
|
|
50
|
+
createSSEClient() {
|
|
51
|
+
return new SSEClient({
|
|
52
|
+
baseUrl.config.baseUrl,
|
|
53
|
+
credentials.config.credentials,
|
|
54
|
+
maxRetries.config.maxRetries,
|
|
55
|
+
retryDelay.config.retryDelay,
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Clean up all active connections
|
|
61
|
+
*/
|
|
62
|
+
close() {
|
|
63
|
+
this.query.close()
|
|
64
|
+
this.operations.closeAll()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Export all types and classes
|
|
69
|
+
export * from './OperationClient'
|
|
70
|
+
export * from './QueryClient'
|
|
71
|
+
export * from './SSEClient'
|
|
72
|
+
export { OperationClient, QueryClient, SSEClient }
|
|
73
|
+
|
|
74
|
+
// Export React hooks
|
|
75
|
+
export {
|
|
76
|
+
useMultipleOperations,
|
|
77
|
+
useOperation,
|
|
78
|
+
useQuery,
|
|
79
|
+
useSDKClients,
|
|
80
|
+
useStreamingQuery,
|
|
81
|
+
} from './hooks'
|
|
82
|
+
|
|
83
|
+
// Lazy initialization of default instance
|
|
84
|
+
let _extensions | null = null
|
|
85
|
+
|
|
86
|
+
function getExtensions() {
|
|
87
|
+
if (!_extensions) {
|
|
88
|
+
_extensions = new RoboSystemsExtensions()
|
|
89
|
+
}
|
|
90
|
+
return _extensions
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const extensions = {
|
|
94
|
+
get query() {
|
|
95
|
+
return getExtensions().query
|
|
96
|
+
},
|
|
97
|
+
get operations() {
|
|
98
|
+
return getExtensions().operations
|
|
99
|
+
},
|
|
100
|
+
monitorOperation) =>
|
|
101
|
+
getExtensions().monitorOperation(operationId, onProgress),
|
|
102
|
+
createSSEClient: () => getExtensions().createSSEClient(),
|
|
103
|
+
close: () => getExtensions().close(),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Export convenience functions that use the default instance
|
|
107
|
+
export const monitorOperation = (operationId, onProgress?) =>
|
|
108
|
+
getExtensions().monitorOperation(operationId, onProgress)
|
|
109
|
+
|
|
110
|
+
export const executeQuery = (graphId, query, parameters?) =>
|
|
111
|
+
getExtensions().query.query(graphId, query, parameters)
|
|
112
|
+
|
|
113
|
+
export const streamQuery = (
|
|
114
|
+
graphId,
|
|
115
|
+
query,
|
|
116
|
+
parameters?,
|
|
117
|
+
chunkSize?
|
|
118
|
+
) => getExtensions().query.streamQuery(graphId, query, parameters, chunkSize)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoboSystems SDK Extensions
|
|
3
|
+
* Enhanced clients with SSE support for the RoboSystems API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { client } from '../client.gen'
|
|
7
|
+
import { OperationClient } from './OperationClient'
|
|
8
|
+
import { QueryClient } from './QueryClient'
|
|
9
|
+
import { SSEClient } from './SSEClient'
|
|
10
|
+
|
|
11
|
+
export interface RoboSystemsExtensionConfig {
|
|
12
|
+
baseUrl?: string
|
|
13
|
+
credentials?: 'include' | 'same-origin' | 'omit'
|
|
14
|
+
maxRetries?: number
|
|
15
|
+
retryDelay?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class RoboSystemsExtensions {
|
|
19
|
+
public readonly query: QueryClient
|
|
20
|
+
public readonly operations: OperationClient
|
|
21
|
+
private config: Required<RoboSystemsExtensionConfig>
|
|
22
|
+
|
|
23
|
+
constructor(config: RoboSystemsExtensionConfig = {}) {
|
|
24
|
+
// Get base URL from SDK client config or use provided/default
|
|
25
|
+
const sdkConfig = client.getConfig()
|
|
26
|
+
|
|
27
|
+
this.config = {
|
|
28
|
+
baseUrl: config.baseUrl || sdkConfig.baseUrl || 'http://localhost:8000',
|
|
29
|
+
credentials: config.credentials || 'include',
|
|
30
|
+
maxRetries: config.maxRetries || 5,
|
|
31
|
+
retryDelay: config.retryDelay || 1000,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.query = new QueryClient({
|
|
35
|
+
baseUrl: this.config.baseUrl,
|
|
36
|
+
credentials: this.config.credentials,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
this.operations = new OperationClient({
|
|
40
|
+
baseUrl: this.config.baseUrl,
|
|
41
|
+
credentials: this.config.credentials,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Convenience method to monitor any operation
|
|
47
|
+
*/
|
|
48
|
+
async monitorOperation(operationId: string, onProgress?: (progress: any) => void): Promise<any> {
|
|
49
|
+
return this.operations.monitorOperation(operationId, { onProgress })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create custom SSE client for advanced use cases
|
|
54
|
+
*/
|
|
55
|
+
createSSEClient(): SSEClient {
|
|
56
|
+
return new SSEClient({
|
|
57
|
+
baseUrl: this.config.baseUrl,
|
|
58
|
+
credentials: this.config.credentials,
|
|
59
|
+
maxRetries: this.config.maxRetries,
|
|
60
|
+
retryDelay: this.config.retryDelay,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Clean up all active connections
|
|
66
|
+
*/
|
|
67
|
+
close(): void {
|
|
68
|
+
this.query.close()
|
|
69
|
+
this.operations.closeAll()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Export all types and classes
|
|
74
|
+
export * from './OperationClient'
|
|
75
|
+
export * from './QueryClient'
|
|
76
|
+
export * from './SSEClient'
|
|
77
|
+
export { OperationClient, QueryClient, SSEClient }
|
|
78
|
+
|
|
79
|
+
// Export React hooks
|
|
80
|
+
export {
|
|
81
|
+
useMultipleOperations,
|
|
82
|
+
useOperation,
|
|
83
|
+
useQuery,
|
|
84
|
+
useSDKClients,
|
|
85
|
+
useStreamingQuery,
|
|
86
|
+
} from './hooks'
|
|
87
|
+
|
|
88
|
+
// Lazy initialization of default instance
|
|
89
|
+
let _extensions: RoboSystemsExtensions | null = null
|
|
90
|
+
|
|
91
|
+
function getExtensions(): RoboSystemsExtensions {
|
|
92
|
+
if (!_extensions) {
|
|
93
|
+
_extensions = new RoboSystemsExtensions()
|
|
94
|
+
}
|
|
95
|
+
return _extensions
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const extensions = {
|
|
99
|
+
get query() {
|
|
100
|
+
return getExtensions().query
|
|
101
|
+
},
|
|
102
|
+
get operations() {
|
|
103
|
+
return getExtensions().operations
|
|
104
|
+
},
|
|
105
|
+
monitorOperation: (operationId: string, onProgress?: (progress: any) => void) =>
|
|
106
|
+
getExtensions().monitorOperation(operationId, onProgress),
|
|
107
|
+
createSSEClient: () => getExtensions().createSSEClient(),
|
|
108
|
+
close: () => getExtensions().close(),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Export convenience functions that use the default instance
|
|
112
|
+
export const monitorOperation = (operationId: string, onProgress?: (progress: any) => void) =>
|
|
113
|
+
getExtensions().monitorOperation(operationId, onProgress)
|
|
114
|
+
|
|
115
|
+
export const executeQuery = (graphId: string, query: string, parameters?: Record<string, any>) =>
|
|
116
|
+
getExtensions().query.query(graphId, query, parameters)
|
|
117
|
+
|
|
118
|
+
export const streamQuery = (
|
|
119
|
+
graphId: string,
|
|
120
|
+
query: string,
|
|
121
|
+
parameters?: Record<string, any>,
|
|
122
|
+
chunkSize?: number
|
|
123
|
+
) => getExtensions().query.streamQuery(graphId, query, parameters, chunkSize)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robosystems/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "TypeScript client library for RoboSystems Financial Knowledge Graph API",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"*.d.ts",
|
|
11
11
|
"client/**/*",
|
|
12
12
|
"core/**/*",
|
|
13
|
+
"extensions/**/*",
|
|
13
14
|
"src/**/*",
|
|
14
15
|
"README.md",
|
|
15
16
|
"LICENSE"
|