@robosystems/client 0.1.12 → 0.1.13
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 +237 -283
- package/extensions/QueryClient.js +175 -230
- package/extensions/SSEClient.js +138 -156
- package/extensions/config.js +51 -43
- package/extensions/hooks.js +289 -353
- package/extensions/index.js +98 -106
- package/package.json +1 -1
- package/prepare.js +15 -23
- package/extensions/OperationClient.d.js +0 -45
- package/extensions/QueryClient.d.js +0 -22
- package/extensions/SSEClient.d.js +0 -35
- package/extensions/config.d.js +0 -25
- package/extensions/hooks.d.js +0 -80
- package/extensions/index.d.js +0 -35
|
@@ -1,297 +1,251 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.OperationClient = void 0;
|
|
3
5
|
/**
|
|
4
6
|
* General Operations Client for monitoring async operations
|
|
5
7
|
* Handles graph creation, backups, imports, and other long-running tasks
|
|
6
8
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
+
});
|
|
71
91
|
})
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
result.result || data,
|
|
80
|
-
metadata.metadata,
|
|
81
|
-
}
|
|
82
|
-
// Schedule cleanup after a short delay to ensure all data is received
|
|
83
|
-
this.scheduleCleanup(operationId, 5000)
|
|
84
|
-
resolve(result)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
// Handle errors
|
|
88
|
-
sseClient.on(EventType.OPERATION_ERROR, (error) => {
|
|
89
|
-
if (timeoutHandle) clearTimeout(timeoutHandle)
|
|
90
|
-
result = {
|
|
91
|
-
success,
|
|
92
|
-
error.message || error.error || 'Operation failed',
|
|
93
|
-
metadata.metadata,
|
|
94
|
-
}
|
|
95
|
-
// Schedule cleanup after a short delay
|
|
96
|
-
this.scheduleCleanup(operationId, 5000)
|
|
97
|
-
resolve(result) // Resolve with error result, not reject
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
// Handle cancellation
|
|
101
|
-
sseClient.on(EventType.OPERATION_CANCELLED, (data) => {
|
|
102
|
-
if (timeoutHandle) clearTimeout(timeoutHandle)
|
|
103
|
-
result = {
|
|
104
|
-
success,
|
|
105
|
-
error: 'Operation cancelled',
|
|
106
|
-
metadata,
|
|
107
|
-
}
|
|
108
|
-
// Schedule cleanup after a short delay
|
|
109
|
-
this.scheduleCleanup(operationId, 5000)
|
|
110
|
-
resolve(result)
|
|
111
|
-
})
|
|
112
|
-
})
|
|
113
|
-
.catch((error) => {
|
|
114
|
-
if (timeoutHandle) clearTimeout(timeoutHandle)
|
|
115
|
-
this.cleanupClient(operationId)
|
|
116
|
-
reject(error)
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Monitor multiple operations concurrently
|
|
123
|
-
*/
|
|
124
|
-
async monitorMultiple(
|
|
125
|
-
operationIds,
|
|
126
|
-
options = {}
|
|
127
|
-
)>> {
|
|
128
|
-
const results = await Promise.all(
|
|
129
|
-
operationIds.map(async (id) => {
|
|
130
|
-
const result = await this.monitorOperation(id, options)
|
|
131
|
-
return [id, result] as [string, OperationResult]
|
|
132
|
-
})
|
|
133
|
-
)
|
|
134
|
-
return new Map(results)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Get the current status of an operation (point-in-time check)
|
|
139
|
-
*/
|
|
140
|
-
async getStatus(operationId) {
|
|
141
|
-
const response = await getOperationStatus({
|
|
142
|
-
path,
|
|
143
|
-
})
|
|
144
|
-
return response.data
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Cancel a pending or running operation
|
|
149
|
-
*/
|
|
150
|
-
async cancelOperation(operationId) {
|
|
151
|
-
// First close any active SSE connection
|
|
152
|
-
this.cleanupClient(operationId)
|
|
153
|
-
|
|
154
|
-
// Then cancel the operation
|
|
155
|
-
await cancelOperationSDK({
|
|
156
|
-
path,
|
|
157
|
-
})
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Wait for an operation with a simple promise interface
|
|
162
|
-
*/
|
|
163
|
-
async waitForOperation(operationId, timeoutMs?) {
|
|
164
|
-
const result = await this.monitorOperation(operationId, {
|
|
165
|
-
timeout,
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
if (!result.success) {
|
|
169
|
-
throw new Error(result.error || 'Operation failed')
|
|
92
|
+
.catch((error) => {
|
|
93
|
+
if (timeoutHandle)
|
|
94
|
+
clearTimeout(timeoutHandle);
|
|
95
|
+
this.cleanupClient(operationId);
|
|
96
|
+
reject(error);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
170
99
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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');
|
|
209
139
|
}
|
|
210
|
-
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
// Yield progress updates come
|
|
214
|
-
while (!completed || progressQueue.length > 0) {
|
|
215
|
-
if (progressQueue.length > 0) {
|
|
216
|
-
yield progressQueue.shift()!
|
|
217
|
-
} else if (!completed) {
|
|
218
|
-
// Wait for more progress
|
|
219
|
-
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
220
|
-
}
|
|
140
|
+
return result.result;
|
|
221
141
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
+
}
|
|
226
189
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
+
}
|
|
234
202
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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);
|
|
241
218
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
+
});
|
|
252
230
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
this.cleanupClient(operationId)
|
|
272
|
-
}
|
|
273
|
-
})
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Close all active SSE connections and clean up resources
|
|
278
|
-
*/
|
|
279
|
-
closeAll() {
|
|
280
|
-
// Clear periodic cleanup interval
|
|
281
|
-
if (this.cleanupInterval) {
|
|
282
|
-
clearInterval(this.cleanupInterval)
|
|
283
|
-
this.cleanupInterval = undefined
|
|
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
|
+
});
|
|
284
249
|
}
|
|
285
|
-
|
|
286
|
-
// Clear all cleanup timeouts
|
|
287
|
-
this.cleanupTimeouts.forEach((timeout) => {
|
|
288
|
-
clearTimeout(timeout)
|
|
289
|
-
})
|
|
290
|
-
this.cleanupTimeouts.clear()
|
|
291
|
-
|
|
292
|
-
// Close all SSE clients
|
|
293
|
-
this.sseClients.forEach((client, operationId) => {
|
|
294
|
-
this.cleanupClient(operationId)
|
|
295
|
-
})
|
|
296
|
-
}
|
|
297
250
|
}
|
|
251
|
+
exports.OperationClient = OperationClient;
|