@robosystems/client 0.1.15 → 0.1.17
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/hooks.d.ts +1 -1
- package/package.json +48 -6
- package/sdk/client/client.gen.d.ts +2 -0
- package/sdk/client/client.gen.js +153 -0
- package/sdk/client/client.gen.ts +200 -0
- package/sdk/client/index.d.ts +7 -0
- package/sdk/client/index.js +15 -0
- package/sdk/client/index.ts +25 -0
- package/sdk/client/types.gen.d.ts +122 -0
- package/sdk/client/types.gen.js +4 -0
- package/sdk/client/types.gen.ts +233 -0
- package/sdk/client/utils.gen.d.ts +45 -0
- package/sdk/client/utils.gen.js +296 -0
- package/sdk/client/utils.gen.ts +419 -0
- package/sdk/client.gen.d.ts +12 -0
- package/sdk/client.gen.js +8 -0
- package/sdk/client.gen.ts +18 -0
- package/sdk/core/auth.gen.d.ts +18 -0
- package/sdk/core/auth.gen.js +18 -0
- package/sdk/core/auth.gen.ts +42 -0
- package/sdk/core/bodySerializer.gen.d.ts +17 -0
- package/sdk/core/bodySerializer.gen.js +57 -0
- package/sdk/core/bodySerializer.gen.ts +90 -0
- package/sdk/core/params.gen.d.ts +33 -0
- package/sdk/core/params.gen.js +92 -0
- package/sdk/core/params.gen.ts +153 -0
- package/sdk/core/pathSerializer.gen.d.ts +33 -0
- package/sdk/core/pathSerializer.gen.js +123 -0
- package/sdk/core/pathSerializer.gen.ts +181 -0
- package/sdk/core/types.gen.d.ts +78 -0
- package/sdk/core/types.gen.js +4 -0
- package/sdk/core/types.gen.ts +121 -0
- package/sdk/index.d.ts +2 -0
- package/sdk/index.js +19 -0
- package/sdk/index.ts +3 -0
- package/sdk/sdk.gen.d.ts +1249 -0
- package/sdk/sdk.gen.js +2572 -0
- package/sdk/sdk.gen.ts +2585 -0
- package/sdk/types.gen.d.ts +6347 -0
- package/sdk/types.gen.js +3 -0
- package/sdk/types.gen.ts +6852 -0
- package/sdk-extensions/OperationClient.d.ts +64 -0
- package/sdk-extensions/OperationClient.js +251 -0
- package/sdk-extensions/OperationClient.ts +322 -0
- package/sdk-extensions/QueryClient.d.ts +50 -0
- package/sdk-extensions/QueryClient.js +190 -0
- package/sdk-extensions/QueryClient.ts +283 -0
- package/sdk-extensions/README.md +672 -0
- package/sdk-extensions/SSEClient.d.ts +48 -0
- package/sdk-extensions/SSEClient.js +148 -0
- package/sdk-extensions/SSEClient.ts +189 -0
- package/sdk-extensions/config.d.ts +32 -0
- package/sdk-extensions/config.js +74 -0
- package/sdk-extensions/config.ts +91 -0
- package/sdk-extensions/hooks.d.ts +110 -0
- package/sdk-extensions/hooks.js +371 -0
- package/sdk-extensions/hooks.ts +438 -0
- package/sdk-extensions/index.d.ts +46 -0
- package/sdk-extensions/index.js +110 -0
- package/sdk-extensions/index.ts +123 -0
- package/sdk.gen.d.ts +210 -104
- package/sdk.gen.js +409 -287
- package/sdk.gen.ts +404 -282
- package/types.gen.d.ts +1218 -567
- package/types.gen.ts +1236 -566
- package/openapi-ts.config.js +0 -9
- package/prepare.js +0 -220
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export interface OperationProgress {
|
|
2
|
+
message: string;
|
|
3
|
+
progressPercent?: number;
|
|
4
|
+
details?: Record<string, any>;
|
|
5
|
+
}
|
|
6
|
+
export interface OperationResult<T = any> {
|
|
7
|
+
success: boolean;
|
|
8
|
+
result?: T;
|
|
9
|
+
error?: string;
|
|
10
|
+
metadata?: Record<string, any>;
|
|
11
|
+
}
|
|
12
|
+
export interface OperationMonitorOptions {
|
|
13
|
+
onProgress?: (progress: OperationProgress) => void;
|
|
14
|
+
onQueueUpdate?: (position: number, estimatedWait: number) => void;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class OperationClient {
|
|
18
|
+
private sseClients;
|
|
19
|
+
private cleanupTimeouts;
|
|
20
|
+
private config;
|
|
21
|
+
private cleanupIntervalMs;
|
|
22
|
+
private cleanupInterval?;
|
|
23
|
+
constructor(config: {
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
credentials?: 'include' | 'same-origin' | 'omit';
|
|
26
|
+
headers?: Record<string, string>;
|
|
27
|
+
maxRetries?: number;
|
|
28
|
+
retryDelay?: number;
|
|
29
|
+
});
|
|
30
|
+
monitorOperation<T = any>(operationId: string, options?: OperationMonitorOptions): Promise<OperationResult<T>>;
|
|
31
|
+
/**
|
|
32
|
+
* Monitor multiple operations concurrently
|
|
33
|
+
*/
|
|
34
|
+
monitorMultiple<T = any>(operationIds: string[], options?: OperationMonitorOptions): Promise<Map<string, OperationResult<T>>>;
|
|
35
|
+
/**
|
|
36
|
+
* Get the current status of an operation (point-in-time check)
|
|
37
|
+
*/
|
|
38
|
+
getStatus(operationId: string): Promise<any>;
|
|
39
|
+
/**
|
|
40
|
+
* Cancel a pending or running operation
|
|
41
|
+
*/
|
|
42
|
+
cancelOperation(operationId: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Wait for an operation with a simple promise interface
|
|
45
|
+
*/
|
|
46
|
+
waitForOperation<T = any>(operationId: string, timeoutMs?: number): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Monitor operation with async iterator for progress updates
|
|
49
|
+
*/
|
|
50
|
+
monitorWithProgress<T = any>(operationId: string): AsyncIterableIterator<OperationProgress | OperationResult<T>>;
|
|
51
|
+
private cleanupClient;
|
|
52
|
+
/**
|
|
53
|
+
* Schedule automatic cleanup of SSE client after a delay
|
|
54
|
+
*/
|
|
55
|
+
private scheduleCleanup;
|
|
56
|
+
/**
|
|
57
|
+
* Perform periodic cleanup of stale SSE connections
|
|
58
|
+
*/
|
|
59
|
+
private performPeriodicCleanup;
|
|
60
|
+
/**
|
|
61
|
+
* Close all active SSE connections and clean up resources
|
|
62
|
+
*/
|
|
63
|
+
closeAll(): void;
|
|
64
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.OperationClient = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* General Operations Client for monitoring async operations
|
|
7
|
+
* Handles graph creation, backups, imports, and other long-running tasks
|
|
8
|
+
*/
|
|
9
|
+
const sdk_gen_1 = require("../sdk/sdk.gen");
|
|
10
|
+
const SSEClient_1 = require("./SSEClient");
|
|
11
|
+
class OperationClient {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.sseClients = new Map();
|
|
14
|
+
this.cleanupTimeouts = new Map();
|
|
15
|
+
this.cleanupIntervalMs = 300000; // 5 minutes
|
|
16
|
+
this.config = config;
|
|
17
|
+
// Start periodic cleanup check every 5 minutes
|
|
18
|
+
this.cleanupInterval = setInterval(() => {
|
|
19
|
+
this.performPeriodicCleanup();
|
|
20
|
+
}, this.cleanupIntervalMs);
|
|
21
|
+
}
|
|
22
|
+
async monitorOperation(operationId, options = {}) {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const sseClient = new SSEClient_1.SSEClient(this.config);
|
|
25
|
+
this.sseClients.set(operationId, sseClient);
|
|
26
|
+
const timeoutHandle = options.timeout
|
|
27
|
+
? setTimeout(() => {
|
|
28
|
+
this.cleanupClient(operationId);
|
|
29
|
+
reject(new Error(`Operation timeout after ${options.timeout}ms`));
|
|
30
|
+
}, options.timeout)
|
|
31
|
+
: undefined;
|
|
32
|
+
sseClient
|
|
33
|
+
.connect(operationId)
|
|
34
|
+
.then(() => {
|
|
35
|
+
let result = { success: false };
|
|
36
|
+
// Track queue updates
|
|
37
|
+
if (options.onQueueUpdate) {
|
|
38
|
+
sseClient.on(SSEClient_1.EventType.QUEUE_UPDATE, (data) => {
|
|
39
|
+
options.onQueueUpdate(data.position || data.queue_position, data.estimated_wait_seconds || 0);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// Track progress
|
|
43
|
+
if (options.onProgress) {
|
|
44
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_PROGRESS, (data) => {
|
|
45
|
+
options.onProgress({
|
|
46
|
+
message: data.message || data.status || 'Processing...',
|
|
47
|
+
progressPercent: data.progress_percent || data.progress,
|
|
48
|
+
details: data,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Handle completion
|
|
53
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_COMPLETED, (data) => {
|
|
54
|
+
if (timeoutHandle)
|
|
55
|
+
clearTimeout(timeoutHandle);
|
|
56
|
+
result = {
|
|
57
|
+
success: true,
|
|
58
|
+
result: data.result || data,
|
|
59
|
+
metadata: data.metadata,
|
|
60
|
+
};
|
|
61
|
+
// Schedule cleanup after a short delay to ensure all data is received
|
|
62
|
+
this.scheduleCleanup(operationId, 5000);
|
|
63
|
+
resolve(result);
|
|
64
|
+
});
|
|
65
|
+
// Handle errors
|
|
66
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_ERROR, (error) => {
|
|
67
|
+
if (timeoutHandle)
|
|
68
|
+
clearTimeout(timeoutHandle);
|
|
69
|
+
result = {
|
|
70
|
+
success: false,
|
|
71
|
+
error: error.message || error.error || 'Operation failed',
|
|
72
|
+
metadata: error.metadata,
|
|
73
|
+
};
|
|
74
|
+
// Schedule cleanup after a short delay
|
|
75
|
+
this.scheduleCleanup(operationId, 5000);
|
|
76
|
+
resolve(result); // Resolve with error result, not reject
|
|
77
|
+
});
|
|
78
|
+
// Handle cancellation
|
|
79
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_CANCELLED, (data) => {
|
|
80
|
+
if (timeoutHandle)
|
|
81
|
+
clearTimeout(timeoutHandle);
|
|
82
|
+
result = {
|
|
83
|
+
success: false,
|
|
84
|
+
error: 'Operation cancelled',
|
|
85
|
+
metadata: data,
|
|
86
|
+
};
|
|
87
|
+
// Schedule cleanup after a short delay
|
|
88
|
+
this.scheduleCleanup(operationId, 5000);
|
|
89
|
+
resolve(result);
|
|
90
|
+
});
|
|
91
|
+
})
|
|
92
|
+
.catch((error) => {
|
|
93
|
+
if (timeoutHandle)
|
|
94
|
+
clearTimeout(timeoutHandle);
|
|
95
|
+
this.cleanupClient(operationId);
|
|
96
|
+
reject(error);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Monitor multiple operations concurrently
|
|
102
|
+
*/
|
|
103
|
+
async monitorMultiple(operationIds, options = {}) {
|
|
104
|
+
const results = await Promise.all(operationIds.map(async (id) => {
|
|
105
|
+
const result = await this.monitorOperation(id, options);
|
|
106
|
+
return [id, result];
|
|
107
|
+
}));
|
|
108
|
+
return new Map(results);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get the current status of an operation (point-in-time check)
|
|
112
|
+
*/
|
|
113
|
+
async getStatus(operationId) {
|
|
114
|
+
const response = await (0, sdk_gen_1.getOperationStatus)({
|
|
115
|
+
path: { operation_id: operationId },
|
|
116
|
+
});
|
|
117
|
+
return response.data;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Cancel a pending or running operation
|
|
121
|
+
*/
|
|
122
|
+
async cancelOperation(operationId) {
|
|
123
|
+
// First close any active SSE connection
|
|
124
|
+
this.cleanupClient(operationId);
|
|
125
|
+
// Then cancel the operation
|
|
126
|
+
await (0, sdk_gen_1.cancelOperation)({
|
|
127
|
+
path: { operation_id: operationId },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Wait for an operation with a simple promise interface
|
|
132
|
+
*/
|
|
133
|
+
async waitForOperation(operationId, timeoutMs) {
|
|
134
|
+
const result = await this.monitorOperation(operationId, {
|
|
135
|
+
timeout: timeoutMs,
|
|
136
|
+
});
|
|
137
|
+
if (!result.success) {
|
|
138
|
+
throw new Error(result.error || 'Operation failed');
|
|
139
|
+
}
|
|
140
|
+
return result.result;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Monitor operation with async iterator for progress updates
|
|
144
|
+
*/
|
|
145
|
+
async *monitorWithProgress(operationId) {
|
|
146
|
+
const progressQueue = [];
|
|
147
|
+
let completed = false;
|
|
148
|
+
let finalResult = null;
|
|
149
|
+
// Start monitoring in background
|
|
150
|
+
const monitorPromise = this.monitorOperation(operationId, {
|
|
151
|
+
onProgress: (progress) => {
|
|
152
|
+
progressQueue.push(progress);
|
|
153
|
+
},
|
|
154
|
+
onQueueUpdate: (position, estimatedWait) => {
|
|
155
|
+
progressQueue.push({
|
|
156
|
+
message: `Queue position: ${position}`,
|
|
157
|
+
progressPercent: 0,
|
|
158
|
+
details: { position, estimatedWait },
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
// Handle completion
|
|
163
|
+
monitorPromise
|
|
164
|
+
.then((result) => {
|
|
165
|
+
finalResult = result;
|
|
166
|
+
completed = true;
|
|
167
|
+
})
|
|
168
|
+
.catch((error) => {
|
|
169
|
+
finalResult = {
|
|
170
|
+
success: false,
|
|
171
|
+
error: error.message,
|
|
172
|
+
};
|
|
173
|
+
completed = true;
|
|
174
|
+
});
|
|
175
|
+
// Yield progress updates as they come
|
|
176
|
+
while (!completed || progressQueue.length > 0) {
|
|
177
|
+
if (progressQueue.length > 0) {
|
|
178
|
+
yield progressQueue.shift();
|
|
179
|
+
}
|
|
180
|
+
else if (!completed) {
|
|
181
|
+
// Wait for more progress
|
|
182
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Yield final result
|
|
186
|
+
if (finalResult) {
|
|
187
|
+
yield finalResult;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
cleanupClient(operationId) {
|
|
191
|
+
const client = this.sseClients.get(operationId);
|
|
192
|
+
if (client) {
|
|
193
|
+
client.close();
|
|
194
|
+
this.sseClients.delete(operationId);
|
|
195
|
+
}
|
|
196
|
+
// Clear any cleanup timeout for this operation
|
|
197
|
+
const timeout = this.cleanupTimeouts.get(operationId);
|
|
198
|
+
if (timeout) {
|
|
199
|
+
clearTimeout(timeout);
|
|
200
|
+
this.cleanupTimeouts.delete(operationId);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Schedule automatic cleanup of SSE client after a delay
|
|
205
|
+
*/
|
|
206
|
+
scheduleCleanup(operationId, delayMs = 60000) {
|
|
207
|
+
// Clear any existing timeout
|
|
208
|
+
const existingTimeout = this.cleanupTimeouts.get(operationId);
|
|
209
|
+
if (existingTimeout) {
|
|
210
|
+
clearTimeout(existingTimeout);
|
|
211
|
+
}
|
|
212
|
+
// Schedule new cleanup
|
|
213
|
+
const timeout = setTimeout(() => {
|
|
214
|
+
this.cleanupClient(operationId);
|
|
215
|
+
this.cleanupTimeouts.delete(operationId);
|
|
216
|
+
}, delayMs);
|
|
217
|
+
this.cleanupTimeouts.set(operationId, timeout);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Perform periodic cleanup of stale SSE connections
|
|
221
|
+
*/
|
|
222
|
+
performPeriodicCleanup() {
|
|
223
|
+
// Check each SSE client for staleness
|
|
224
|
+
this.sseClients.forEach((client, operationId) => {
|
|
225
|
+
if (!client.isConnected()) {
|
|
226
|
+
// Clean up disconnected clients immediately
|
|
227
|
+
this.cleanupClient(operationId);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Close all active SSE connections and clean up resources
|
|
233
|
+
*/
|
|
234
|
+
closeAll() {
|
|
235
|
+
// Clear periodic cleanup interval
|
|
236
|
+
if (this.cleanupInterval) {
|
|
237
|
+
clearInterval(this.cleanupInterval);
|
|
238
|
+
this.cleanupInterval = undefined;
|
|
239
|
+
}
|
|
240
|
+
// Clear all cleanup timeouts
|
|
241
|
+
this.cleanupTimeouts.forEach((timeout) => {
|
|
242
|
+
clearTimeout(timeout);
|
|
243
|
+
});
|
|
244
|
+
this.cleanupTimeouts.clear();
|
|
245
|
+
// Close all SSE clients
|
|
246
|
+
this.sseClients.forEach((client, operationId) => {
|
|
247
|
+
this.cleanupClient(operationId);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
exports.OperationClient = OperationClient;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* General Operations Client for monitoring async operations
|
|
5
|
+
* Handles graph creation, backups, imports, and other long-running tasks
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { cancelOperation as cancelOperationSDK, getOperationStatus } from '../sdk/sdk.gen'
|
|
9
|
+
import { EventType, SSEClient } from './SSEClient'
|
|
10
|
+
|
|
11
|
+
export interface OperationProgress {
|
|
12
|
+
message: string
|
|
13
|
+
progressPercent?: number
|
|
14
|
+
details?: Record<string, any>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface OperationResult<T = any> {
|
|
18
|
+
success: boolean
|
|
19
|
+
result?: T
|
|
20
|
+
error?: string
|
|
21
|
+
metadata?: Record<string, any>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface OperationMonitorOptions {
|
|
25
|
+
onProgress?: (progress: OperationProgress) => void
|
|
26
|
+
onQueueUpdate?: (position: number, estimatedWait: number) => void
|
|
27
|
+
timeout?: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class OperationClient {
|
|
31
|
+
private sseClients: Map<string, SSEClient> = new Map()
|
|
32
|
+
private cleanupTimeouts: Map<string, ReturnType<typeof setTimeout>> = new Map()
|
|
33
|
+
private config: {
|
|
34
|
+
baseUrl: string
|
|
35
|
+
credentials?: 'include' | 'same-origin' | 'omit'
|
|
36
|
+
headers?: Record<string, string>
|
|
37
|
+
maxRetries?: number
|
|
38
|
+
retryDelay?: number
|
|
39
|
+
}
|
|
40
|
+
private cleanupIntervalMs = 300000 // 5 minutes
|
|
41
|
+
private cleanupInterval?: ReturnType<typeof setInterval>
|
|
42
|
+
|
|
43
|
+
constructor(config: {
|
|
44
|
+
baseUrl: string
|
|
45
|
+
credentials?: 'include' | 'same-origin' | 'omit'
|
|
46
|
+
headers?: Record<string, string>
|
|
47
|
+
maxRetries?: number
|
|
48
|
+
retryDelay?: number
|
|
49
|
+
}) {
|
|
50
|
+
this.config = config
|
|
51
|
+
|
|
52
|
+
// Start periodic cleanup check every 5 minutes
|
|
53
|
+
this.cleanupInterval = setInterval(() => {
|
|
54
|
+
this.performPeriodicCleanup()
|
|
55
|
+
}, this.cleanupIntervalMs)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async monitorOperation<T = any>(
|
|
59
|
+
operationId: string,
|
|
60
|
+
options: OperationMonitorOptions = {}
|
|
61
|
+
): Promise<OperationResult<T>> {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const sseClient = new SSEClient(this.config)
|
|
64
|
+
this.sseClients.set(operationId, sseClient)
|
|
65
|
+
|
|
66
|
+
const timeoutHandle = options.timeout
|
|
67
|
+
? setTimeout(() => {
|
|
68
|
+
this.cleanupClient(operationId)
|
|
69
|
+
reject(new Error(`Operation timeout after ${options.timeout}ms`))
|
|
70
|
+
}, options.timeout)
|
|
71
|
+
: undefined
|
|
72
|
+
|
|
73
|
+
sseClient
|
|
74
|
+
.connect(operationId)
|
|
75
|
+
.then(() => {
|
|
76
|
+
let result: OperationResult<T> = { success: false }
|
|
77
|
+
|
|
78
|
+
// Track queue updates
|
|
79
|
+
if (options.onQueueUpdate) {
|
|
80
|
+
sseClient.on(EventType.QUEUE_UPDATE, (data) => {
|
|
81
|
+
options.onQueueUpdate!(
|
|
82
|
+
data.position || data.queue_position,
|
|
83
|
+
data.estimated_wait_seconds || 0
|
|
84
|
+
)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Track progress
|
|
89
|
+
if (options.onProgress) {
|
|
90
|
+
sseClient.on(EventType.OPERATION_PROGRESS, (data) => {
|
|
91
|
+
options.onProgress!({
|
|
92
|
+
message: data.message || data.status || 'Processing...',
|
|
93
|
+
progressPercent: data.progress_percent || data.progress,
|
|
94
|
+
details: data,
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Handle completion
|
|
100
|
+
sseClient.on(EventType.OPERATION_COMPLETED, (data) => {
|
|
101
|
+
if (timeoutHandle) clearTimeout(timeoutHandle)
|
|
102
|
+
result = {
|
|
103
|
+
success: true,
|
|
104
|
+
result: data.result || data,
|
|
105
|
+
metadata: data.metadata,
|
|
106
|
+
}
|
|
107
|
+
// Schedule cleanup after a short delay to ensure all data is received
|
|
108
|
+
this.scheduleCleanup(operationId, 5000)
|
|
109
|
+
resolve(result)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// Handle errors
|
|
113
|
+
sseClient.on(EventType.OPERATION_ERROR, (error) => {
|
|
114
|
+
if (timeoutHandle) clearTimeout(timeoutHandle)
|
|
115
|
+
result = {
|
|
116
|
+
success: false,
|
|
117
|
+
error: error.message || error.error || 'Operation failed',
|
|
118
|
+
metadata: error.metadata,
|
|
119
|
+
}
|
|
120
|
+
// Schedule cleanup after a short delay
|
|
121
|
+
this.scheduleCleanup(operationId, 5000)
|
|
122
|
+
resolve(result) // Resolve with error result, not reject
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// Handle cancellation
|
|
126
|
+
sseClient.on(EventType.OPERATION_CANCELLED, (data) => {
|
|
127
|
+
if (timeoutHandle) clearTimeout(timeoutHandle)
|
|
128
|
+
result = {
|
|
129
|
+
success: false,
|
|
130
|
+
error: 'Operation cancelled',
|
|
131
|
+
metadata: data,
|
|
132
|
+
}
|
|
133
|
+
// Schedule cleanup after a short delay
|
|
134
|
+
this.scheduleCleanup(operationId, 5000)
|
|
135
|
+
resolve(result)
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
.catch((error) => {
|
|
139
|
+
if (timeoutHandle) clearTimeout(timeoutHandle)
|
|
140
|
+
this.cleanupClient(operationId)
|
|
141
|
+
reject(error)
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Monitor multiple operations concurrently
|
|
148
|
+
*/
|
|
149
|
+
async monitorMultiple<T = any>(
|
|
150
|
+
operationIds: string[],
|
|
151
|
+
options: OperationMonitorOptions = {}
|
|
152
|
+
): Promise<Map<string, OperationResult<T>>> {
|
|
153
|
+
const results = await Promise.all(
|
|
154
|
+
operationIds.map(async (id) => {
|
|
155
|
+
const result = await this.monitorOperation<T>(id, options)
|
|
156
|
+
return [id, result] as [string, OperationResult<T>]
|
|
157
|
+
})
|
|
158
|
+
)
|
|
159
|
+
return new Map(results)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get the current status of an operation (point-in-time check)
|
|
164
|
+
*/
|
|
165
|
+
async getStatus(operationId: string): Promise<any> {
|
|
166
|
+
const response = await getOperationStatus({
|
|
167
|
+
path: { operation_id: operationId },
|
|
168
|
+
})
|
|
169
|
+
return response.data
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Cancel a pending or running operation
|
|
174
|
+
*/
|
|
175
|
+
async cancelOperation(operationId: string): Promise<void> {
|
|
176
|
+
// First close any active SSE connection
|
|
177
|
+
this.cleanupClient(operationId)
|
|
178
|
+
|
|
179
|
+
// Then cancel the operation
|
|
180
|
+
await cancelOperationSDK({
|
|
181
|
+
path: { operation_id: operationId },
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Wait for an operation with a simple promise interface
|
|
187
|
+
*/
|
|
188
|
+
async waitForOperation<T = any>(operationId: string, timeoutMs?: number): Promise<T> {
|
|
189
|
+
const result = await this.monitorOperation<T>(operationId, {
|
|
190
|
+
timeout: timeoutMs,
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
if (!result.success) {
|
|
194
|
+
throw new Error(result.error || 'Operation failed')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return result.result as T
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Monitor operation with async iterator for progress updates
|
|
202
|
+
*/
|
|
203
|
+
async *monitorWithProgress<T = any>(
|
|
204
|
+
operationId: string
|
|
205
|
+
): AsyncIterableIterator<OperationProgress | OperationResult<T>> {
|
|
206
|
+
const progressQueue: (OperationProgress | OperationResult<T>)[] = []
|
|
207
|
+
let completed = false
|
|
208
|
+
let finalResult: OperationResult<T> | null = null
|
|
209
|
+
|
|
210
|
+
// Start monitoring in background
|
|
211
|
+
const monitorPromise = this.monitorOperation<T>(operationId, {
|
|
212
|
+
onProgress: (progress) => {
|
|
213
|
+
progressQueue.push(progress)
|
|
214
|
+
},
|
|
215
|
+
onQueueUpdate: (position, estimatedWait) => {
|
|
216
|
+
progressQueue.push({
|
|
217
|
+
message: `Queue position: ${position}`,
|
|
218
|
+
progressPercent: 0,
|
|
219
|
+
details: { position, estimatedWait },
|
|
220
|
+
})
|
|
221
|
+
},
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
// Handle completion
|
|
225
|
+
monitorPromise
|
|
226
|
+
.then((result) => {
|
|
227
|
+
finalResult = result
|
|
228
|
+
completed = true
|
|
229
|
+
})
|
|
230
|
+
.catch((error) => {
|
|
231
|
+
finalResult = {
|
|
232
|
+
success: false,
|
|
233
|
+
error: error.message,
|
|
234
|
+
}
|
|
235
|
+
completed = true
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
// Yield progress updates as they come
|
|
239
|
+
while (!completed || progressQueue.length > 0) {
|
|
240
|
+
if (progressQueue.length > 0) {
|
|
241
|
+
yield progressQueue.shift()!
|
|
242
|
+
} else if (!completed) {
|
|
243
|
+
// Wait for more progress
|
|
244
|
+
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Yield final result
|
|
249
|
+
if (finalResult) {
|
|
250
|
+
yield finalResult
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private cleanupClient(operationId: string): void {
|
|
255
|
+
const client = this.sseClients.get(operationId)
|
|
256
|
+
if (client) {
|
|
257
|
+
client.close()
|
|
258
|
+
this.sseClients.delete(operationId)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Clear any cleanup timeout for this operation
|
|
262
|
+
const timeout = this.cleanupTimeouts.get(operationId)
|
|
263
|
+
if (timeout) {
|
|
264
|
+
clearTimeout(timeout)
|
|
265
|
+
this.cleanupTimeouts.delete(operationId)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Schedule automatic cleanup of SSE client after a delay
|
|
271
|
+
*/
|
|
272
|
+
private scheduleCleanup(operationId: string, delayMs: number = 60000): void {
|
|
273
|
+
// Clear any existing timeout
|
|
274
|
+
const existingTimeout = this.cleanupTimeouts.get(operationId)
|
|
275
|
+
if (existingTimeout) {
|
|
276
|
+
clearTimeout(existingTimeout)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Schedule new cleanup
|
|
280
|
+
const timeout = setTimeout(() => {
|
|
281
|
+
this.cleanupClient(operationId)
|
|
282
|
+
this.cleanupTimeouts.delete(operationId)
|
|
283
|
+
}, delayMs)
|
|
284
|
+
|
|
285
|
+
this.cleanupTimeouts.set(operationId, timeout)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Perform periodic cleanup of stale SSE connections
|
|
290
|
+
*/
|
|
291
|
+
private performPeriodicCleanup(): void {
|
|
292
|
+
// Check each SSE client for staleness
|
|
293
|
+
this.sseClients.forEach((client, operationId) => {
|
|
294
|
+
if (!client.isConnected()) {
|
|
295
|
+
// Clean up disconnected clients immediately
|
|
296
|
+
this.cleanupClient(operationId)
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Close all active SSE connections and clean up resources
|
|
303
|
+
*/
|
|
304
|
+
closeAll(): void {
|
|
305
|
+
// Clear periodic cleanup interval
|
|
306
|
+
if (this.cleanupInterval) {
|
|
307
|
+
clearInterval(this.cleanupInterval)
|
|
308
|
+
this.cleanupInterval = undefined
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Clear all cleanup timeouts
|
|
312
|
+
this.cleanupTimeouts.forEach((timeout) => {
|
|
313
|
+
clearTimeout(timeout)
|
|
314
|
+
})
|
|
315
|
+
this.cleanupTimeouts.clear()
|
|
316
|
+
|
|
317
|
+
// Close all SSE clients
|
|
318
|
+
this.sseClients.forEach((client, operationId) => {
|
|
319
|
+
this.cleanupClient(operationId)
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface QueryRequest {
|
|
2
|
+
query: string;
|
|
3
|
+
parameters?: Record<string, any>;
|
|
4
|
+
timeout?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface QueryOptions {
|
|
7
|
+
mode?: 'auto' | 'sync' | 'async' | 'stream';
|
|
8
|
+
chunkSize?: number;
|
|
9
|
+
testMode?: boolean;
|
|
10
|
+
maxWait?: number;
|
|
11
|
+
onQueueUpdate?: (position: number, estimatedWait: number) => void;
|
|
12
|
+
onProgress?: (message: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface QueryResult {
|
|
15
|
+
data: any[];
|
|
16
|
+
columns: string[];
|
|
17
|
+
row_count: number;
|
|
18
|
+
execution_time_ms: number;
|
|
19
|
+
graph_id?: string;
|
|
20
|
+
timestamp?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface QueuedQueryResponse {
|
|
23
|
+
status: 'queued';
|
|
24
|
+
operation_id: string;
|
|
25
|
+
queue_position: number;
|
|
26
|
+
estimated_wait_seconds: number;
|
|
27
|
+
message: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class QueryClient {
|
|
30
|
+
private sseClient?;
|
|
31
|
+
private config;
|
|
32
|
+
constructor(config: {
|
|
33
|
+
baseUrl: string;
|
|
34
|
+
credentials?: 'include' | 'same-origin' | 'omit';
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
});
|
|
37
|
+
executeQuery(graphId: string, request: QueryRequest, options?: QueryOptions): Promise<QueryResult | AsyncIterableIterator<any>>;
|
|
38
|
+
private streamQueryResults;
|
|
39
|
+
private waitForQueryCompletion;
|
|
40
|
+
query(graphId: string, cypher: string, parameters?: Record<string, any>): Promise<QueryResult>;
|
|
41
|
+
streamQuery(graphId: string, cypher: string, parameters?: Record<string, any>, chunkSize?: number): AsyncIterableIterator<any>;
|
|
42
|
+
close(): void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Error thrown when query is queued and maxWait is 0
|
|
46
|
+
*/
|
|
47
|
+
export declare class QueuedQueryError extends Error {
|
|
48
|
+
queueInfo: QueuedQueryResponse;
|
|
49
|
+
constructor(queueInfo: QueuedQueryResponse);
|
|
50
|
+
}
|