@trustgraph/client 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +319 -0
  3. package/dist/__tests__/flows-api.test.d.ts +2 -0
  4. package/dist/__tests__/flows-api.test.d.ts.map +1 -0
  5. package/dist/__tests__/messages.test.d.ts +2 -0
  6. package/dist/__tests__/messages.test.d.ts.map +1 -0
  7. package/dist/__tests__/service-call-multi.test.d.ts +2 -0
  8. package/dist/__tests__/service-call-multi.test.d.ts.map +1 -0
  9. package/dist/__tests__/service-call.test.d.ts +2 -0
  10. package/dist/__tests__/service-call.test.d.ts.map +1 -0
  11. package/dist/api/authenticated-fetch.d.ts +18 -0
  12. package/dist/api/authenticated-fetch.d.ts.map +1 -0
  13. package/dist/api/trustgraph/SocketContext.d.ts +2 -0
  14. package/dist/api/trustgraph/SocketContext.d.ts.map +1 -0
  15. package/dist/api/trustgraph/SocketProvider.d.ts +21 -0
  16. package/dist/api/trustgraph/SocketProvider.d.ts.map +1 -0
  17. package/dist/api/trustgraph/Triple.d.ts +17 -0
  18. package/dist/api/trustgraph/Triple.d.ts.map +1 -0
  19. package/dist/api/trustgraph/messages.d.ts +205 -0
  20. package/dist/api/trustgraph/messages.d.ts.map +1 -0
  21. package/dist/api/trustgraph/service-call-multi.d.ts +17 -0
  22. package/dist/api/trustgraph/service-call-multi.d.ts.map +1 -0
  23. package/dist/api/trustgraph/service-call.d.ts +57 -0
  24. package/dist/api/trustgraph/service-call.d.ts.map +1 -0
  25. package/dist/api/trustgraph/socket.d.ts +2 -0
  26. package/dist/api/trustgraph/socket.d.ts.map +1 -0
  27. package/dist/api/trustgraph/trustgraph-socket.d.ts +429 -0
  28. package/dist/api/trustgraph/trustgraph-socket.d.ts.map +1 -0
  29. package/dist/index.cjs +1370 -0
  30. package/dist/index.cjs.map +1 -0
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.esm.js +1361 -0
  34. package/dist/index.esm.js.map +1 -0
  35. package/dist/index.js +1375 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/models/Triple.d.ts +17 -0
  38. package/dist/models/Triple.d.ts.map +1 -0
  39. package/dist/models/messages.d.ts +215 -0
  40. package/dist/models/messages.d.ts.map +1 -0
  41. package/dist/socket/service-call-multi.d.ts +30 -0
  42. package/dist/socket/service-call-multi.d.ts.map +1 -0
  43. package/dist/socket/service-call.d.ts +69 -0
  44. package/dist/socket/service-call.d.ts.map +1 -0
  45. package/dist/socket/trustgraph-socket.d.ts +433 -0
  46. package/dist/socket/trustgraph-socket.d.ts.map +1 -0
  47. package/dist/types.d.ts +2 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/package.json +68 -0
@@ -0,0 +1,1361 @@
1
+ // Constant defining the delay before attempting to reconnect a WebSocket
2
+ // (2 seconds)
3
+ const SOCKET_RECONNECTION_TIMEOUT$2 = 2000;
4
+ class ServiceCallMulti {
5
+ constructor(mid, msg, success, error, timeout, retries, socket, receiver) {
6
+ this.mid = mid;
7
+ this.msg = msg;
8
+ this.success = success;
9
+ this.error = error;
10
+ this.timeout = timeout;
11
+ this.retries = retries;
12
+ this.socket = socket;
13
+ this.complete = false;
14
+ this.receiver = receiver;
15
+ }
16
+ start() {
17
+ this.socket.inflight[this.mid] = this;
18
+ this.attempt();
19
+ }
20
+ onReceived(resp) {
21
+ if (this.complete == true)
22
+ console.log(this.mid, "should not happen, request is already complete");
23
+ const fin = this.receiver(resp);
24
+ if (fin) {
25
+ this.complete = true;
26
+ // console.log("Received for", this.mid);
27
+ clearTimeout(this.timeoutId);
28
+ this.timeoutId = undefined;
29
+ delete this.socket.inflight[this.mid];
30
+ this.success(resp);
31
+ }
32
+ }
33
+ onTimeout() {
34
+ if (this.complete == true)
35
+ console.log(this.mid, "timeout should not happen, request is already complete");
36
+ console.log("Request", this.mid, "timed out");
37
+ clearTimeout(this.timeoutId);
38
+ this.attempt();
39
+ }
40
+ attempt() {
41
+ // console.log("attempt:", this.mid);
42
+ if (this.complete == true)
43
+ console.log(this.mid, "attempt should not be called, request is already complete");
44
+ this.retries--;
45
+ if (this.retries < 0) {
46
+ console.log("Request", this.mid, "ran out of retries");
47
+ clearTimeout(this.timeoutId);
48
+ delete this.socket.inflight[this.mid];
49
+ this.error("Ran out of retries");
50
+ return; // Exit early - no more attempts
51
+ }
52
+ // Check if WebSocket connection is available and ready
53
+ if (this.socket.ws && this.socket.ws.readyState === WebSocket.OPEN) {
54
+ try {
55
+ this.socket.ws.send(JSON.stringify(this.msg));
56
+ this.timeoutId = setTimeout(this.onTimeout.bind(this), this.timeout);
57
+ return;
58
+ }
59
+ catch (e) {
60
+ console.log("Error:", e);
61
+ console.log("Message send failure, retry...");
62
+ // Calculate backoff delay with jitter
63
+ const backoffDelay = Math.min(SOCKET_RECONNECTION_TIMEOUT$2 * Math.pow(2, 3 - this.retries) +
64
+ Math.random() * 1000, 30000);
65
+ this.timeoutId = setTimeout(this.attempt.bind(this), backoffDelay);
66
+ console.log("Reopen...");
67
+ // Attempt to reopen the WebSocket connection
68
+ this.socket.reopen();
69
+ }
70
+ }
71
+ else {
72
+ // No WebSocket connection available or not ready
73
+ // Check if socket is connecting
74
+ if (this.socket.ws &&
75
+ this.socket.ws.readyState === WebSocket.CONNECTING) {
76
+ // Wait a bit longer for connection to establish
77
+ setTimeout(this.attempt.bind(this), 500);
78
+ }
79
+ else {
80
+ // Socket is closed or closing, trigger reopen
81
+ console.log("Socket not ready, reopening...");
82
+ this.socket.reopen();
83
+ // Calculate backoff delay
84
+ const backoffDelay = Math.min(SOCKET_RECONNECTION_TIMEOUT$2 * Math.pow(2, 3 - this.retries) +
85
+ Math.random() * 1000, 30000);
86
+ setTimeout(this.attempt.bind(this), backoffDelay);
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ // Constant defining the delay before attempting to reconnect a WebSocket
93
+ // (2 seconds)
94
+ const SOCKET_RECONNECTION_TIMEOUT$1 = 2000;
95
+ /**
96
+ * ServiceCall represents a single request/response cycle over a WebSocket
97
+ * connection with built-in retry logic, timeout handling, and completion
98
+ * tracking.
99
+ *
100
+ * This class manages the lifecycle of a service call including:
101
+ * - Sending the initial request
102
+ * - Handling timeouts and retries
103
+ * - Managing completion state
104
+ * - Cleaning up resources
105
+ */
106
+ class ServiceCall {
107
+ constructor(mid, // Message ID - unique identifier for this request
108
+ msg, // The actual message/request to send
109
+ success, // Callback function called on
110
+ // successful response
111
+ error, // Callback function called on error/failure
112
+ timeout, // Timeout duration in milliseconds
113
+ retries, // Number of retry attempts allowed
114
+ socket) {
115
+ this.mid = mid;
116
+ this.msg = msg;
117
+ this.success = success;
118
+ this.error = error;
119
+ this.timeout = timeout;
120
+ this.retries = retries;
121
+ this.socket = socket;
122
+ this.complete = false; // Track if this request has completed
123
+ }
124
+ /**
125
+ * Initiates the service call by registering it with the socket's inflight
126
+ * requests and making the first attempt to send the message
127
+ */
128
+ start() {
129
+ // Register this request as "in-flight" so responses can be matched to it
130
+ this.socket.inflight[this.mid] = this;
131
+ // Make the first attempt to send the message
132
+ this.attempt();
133
+ }
134
+ /**
135
+ * Called when a response is received for this request
136
+ * Handles cleanup and calls the success or error callback based on response
137
+ *
138
+ * @param resp - The response object received from the server
139
+ */
140
+ onReceived(resp) {
141
+ // Defensive check - this shouldn't happen but log if it does
142
+ if (this.complete == true)
143
+ console.log(this.mid, "should not happen, request is already complete");
144
+ // Mark as complete to prevent duplicate processing
145
+ this.complete = true;
146
+ // Clean up timeout timer
147
+ clearTimeout(this.timeoutId);
148
+ this.timeoutId = undefined;
149
+ // Remove from inflight requests tracker
150
+ delete this.socket.inflight[this.mid];
151
+ // Check if the response contains an error (error can be directly in resp or nested under response)
152
+ let errorToHandle = null;
153
+ // Check for direct error in response
154
+ if (resp && typeof resp === "object" && "error" in resp) {
155
+ errorToHandle = resp.error;
156
+ }
157
+ // Check for nested error under response property
158
+ else if (resp && typeof resp === "object" && "response" in resp) {
159
+ const response = resp.response;
160
+ if (response && typeof response === "object" && "error" in response) {
161
+ errorToHandle = response.error;
162
+ }
163
+ }
164
+ if (errorToHandle) {
165
+ // Response contains an error - call error callback
166
+ const errorObj = errorToHandle;
167
+ const errorMessage = (typeof errorObj.message === "string" ? errorObj.message : null) ||
168
+ (typeof errorObj.type === "string" ? errorObj.type : null) ||
169
+ "Unknown error";
170
+ console.log("ServiceCall: API error detected in response:", errorMessage, "Full error:", errorToHandle);
171
+ this.error(new Error(errorMessage));
172
+ return;
173
+ }
174
+ // Call success callback with the response
175
+ this.success(resp);
176
+ }
177
+ /**
178
+ * Called when the request times out
179
+ * Triggers another attempt if retries are available
180
+ */
181
+ onTimeout() {
182
+ // Defensive check - this shouldn't happen but log if it does
183
+ if (this.complete == true)
184
+ console.log(this.mid, "timeout should not happen, request is already complete");
185
+ console.log("Request", this.mid, "timed out");
186
+ // Clear the current timeout
187
+ clearTimeout(this.timeoutId);
188
+ // Try again (this will check retry count)
189
+ this.attempt();
190
+ }
191
+ /**
192
+ * Calculates exponential backoff delay with jitter
193
+ * @returns backoff delay in milliseconds
194
+ */
195
+ calculateBackoff() {
196
+ return Math.min(SOCKET_RECONNECTION_TIMEOUT$1 * Math.pow(2, 3 - this.retries) +
197
+ Math.random() * 1000, 30000);
198
+ }
199
+ /**
200
+ * Core retry logic - attempts to send the message over the WebSocket
201
+ * Handles retries and waits for BaseApi to handle reconnection
202
+ */
203
+ attempt() {
204
+ // Defensive check - this shouldn't be called on completed requests
205
+ if (this.complete == true)
206
+ console.log(this.mid, "attempt should not be called, request is already complete");
207
+ // Decrement retry counter
208
+ this.retries--;
209
+ // Check if we've exhausted all retries
210
+ if (this.retries < 0) {
211
+ console.log("Request", this.mid, "ran out of retries");
212
+ // Clean up and call error callback
213
+ clearTimeout(this.timeoutId);
214
+ delete this.socket.inflight[this.mid];
215
+ this.error("Ran out of retries");
216
+ return; // Exit early - no more attempts
217
+ }
218
+ // Check if WebSocket connection is available and ready
219
+ if (this.socket.ws && this.socket.ws.readyState === WebSocket.OPEN) {
220
+ try {
221
+ // Attempt to send the message as JSON
222
+ this.socket.ws.send(JSON.stringify(this.msg));
223
+ // Set up timeout for this attempt
224
+ this.timeoutId = setTimeout(this.onTimeout.bind(this), this.timeout);
225
+ return; // Success - message sent, waiting for response or timeout
226
+ }
227
+ catch (e) {
228
+ // Handle send failure - wait for BaseApi to handle reconnection
229
+ console.log("Error:", e);
230
+ console.log("Message send failure, waiting for socket reconnection...");
231
+ // Schedule retry with backoff - let BaseApi handle the reconnection
232
+ this.timeoutId = setTimeout(this.attempt.bind(this), this.calculateBackoff());
233
+ }
234
+ }
235
+ else {
236
+ // No WebSocket connection available or not ready
237
+ // Let BaseApi handle reconnection, just wait and retry
238
+ console.log("Request", this.mid, "waiting for socket reconnection...");
239
+ // Use consistent backoff for all waiting scenarios
240
+ setTimeout(this.attempt.bind(this), this.calculateBackoff());
241
+ }
242
+ }
243
+ }
244
+
245
+ // Configuration constants
246
+ const SOCKET_RECONNECTION_TIMEOUT = 2000; // 2 seconds between reconnection
247
+ // attempts
248
+ const SOCKET_URL = "/api/socket"; // WebSocket endpoint path
249
+ /**
250
+ * Generates a random message ID using cryptographically secure random values
251
+ * @param length - Number of random characters to generate
252
+ * @returns Random string of specified length
253
+ */
254
+ function makeid(length) {
255
+ const array = new Uint32Array(length);
256
+ crypto.getRandomValues(array);
257
+ const characters = "abcdefghijklmnopqrstuvwxyz1234567890";
258
+ return array.reduce((acc, current) => acc + characters[current % characters.length], "");
259
+ }
260
+ class BaseApi {
261
+ constructor(user, token) {
262
+ this.inflight = {}; // Track active requests by
263
+ // message ID
264
+ this.reconnectAttempts = 0; // Track reconnection attempts
265
+ this.maxReconnectAttempts = 10; // Maximum reconnection attempts
266
+ this.reconnectionState = "idle"; // Connection state
267
+ // Connection state tracking for UI
268
+ this.connectionStateListeners = [];
269
+ this.tag = makeid(16); // Generate unique client tag
270
+ this.id = 1; // Start message ID counter
271
+ this.token = token; // Store authentication token
272
+ this.user = user; // Store user identifier
273
+ console.log("SOCKET: opening socket...", token ? "with auth" : "without auth", "user:", user);
274
+ this.openSocket(); // Establish WebSocket connection
275
+ console.log("SOCKET: socket opened");
276
+ }
277
+ /**
278
+ * Subscribe to connection state changes for UI updates
279
+ */
280
+ onConnectionStateChange(listener) {
281
+ this.connectionStateListeners.push(listener);
282
+ // Immediately send current state
283
+ listener(this.getConnectionState());
284
+ // Return unsubscribe function
285
+ return () => {
286
+ const index = this.connectionStateListeners.indexOf(listener);
287
+ if (index > -1) {
288
+ this.connectionStateListeners.splice(index, 1);
289
+ }
290
+ };
291
+ }
292
+ /**
293
+ * Get current connection state
294
+ */
295
+ getConnectionState() {
296
+ const hasApiKey = !!this.token;
297
+ // Determine status based on WebSocket state and reconnection state
298
+ let status;
299
+ if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
300
+ if (this.reconnectionState === "failed") {
301
+ status = "failed";
302
+ }
303
+ else if (this.reconnectionState === "reconnecting") {
304
+ status = "reconnecting";
305
+ }
306
+ else {
307
+ status = "connecting";
308
+ }
309
+ }
310
+ else if (this.ws.readyState === WebSocket.CONNECTING) {
311
+ status = "connecting";
312
+ }
313
+ else if (this.ws.readyState === WebSocket.OPEN) {
314
+ status = hasApiKey ? "authenticated" : "unauthenticated";
315
+ }
316
+ else {
317
+ status = "connecting";
318
+ }
319
+ const state = {
320
+ status,
321
+ hasApiKey,
322
+ lastError: this.lastError,
323
+ };
324
+ // Add reconnection details if applicable
325
+ if (status === "reconnecting") {
326
+ state.reconnectAttempt = this.reconnectAttempts;
327
+ state.maxAttempts = this.maxReconnectAttempts;
328
+ }
329
+ return state;
330
+ }
331
+ /**
332
+ * Notify all listeners of connection state changes
333
+ */
334
+ notifyStateChange() {
335
+ const state = this.getConnectionState();
336
+ this.connectionStateListeners.forEach((listener) => {
337
+ try {
338
+ listener(state);
339
+ }
340
+ catch (error) {
341
+ console.error("Error in connection state listener:", error);
342
+ }
343
+ });
344
+ }
345
+ /**
346
+ * Establishes WebSocket connection and sets up event handlers
347
+ */
348
+ openSocket() {
349
+ // Don't create multiple connections
350
+ if (this.ws &&
351
+ (this.ws.readyState === WebSocket.CONNECTING ||
352
+ this.ws.readyState === WebSocket.OPEN)) {
353
+ return;
354
+ }
355
+ // Clean up old socket if exists
356
+ if (this.ws) {
357
+ this.ws.removeEventListener("message", this.onMessage);
358
+ this.ws.removeEventListener("close", this.onClose);
359
+ this.ws.removeEventListener("open", this.onOpen);
360
+ this.ws.removeEventListener("error", this.onError);
361
+ this.ws = undefined;
362
+ }
363
+ try {
364
+ // Build WebSocket URL with optional token parameter
365
+ const wsUrl = this.token
366
+ ? `${SOCKET_URL}?token=${this.token}`
367
+ : SOCKET_URL;
368
+ console.log("SOCKET: connecting to", wsUrl.replace(/token=[^&]*/, "token=***"));
369
+ this.ws = new WebSocket(wsUrl);
370
+ }
371
+ catch (e) {
372
+ console.error("[socket creation error]", e);
373
+ this.scheduleReconnect();
374
+ return;
375
+ }
376
+ // Bind event handlers to maintain proper 'this' context
377
+ this.onMessage = this.onMessage.bind(this);
378
+ this.onClose = this.onClose.bind(this);
379
+ this.onOpen = this.onOpen.bind(this);
380
+ this.onError = this.onError.bind(this);
381
+ // Attach event listeners
382
+ this.ws.addEventListener("message", this.onMessage);
383
+ this.ws.addEventListener("close", this.onClose);
384
+ this.ws.addEventListener("open", this.onOpen);
385
+ this.ws.addEventListener("error", this.onError);
386
+ }
387
+ // Handle incoming messages from server
388
+ onMessage(message) {
389
+ if (!message.data)
390
+ return;
391
+ try {
392
+ const obj = JSON.parse(message.data);
393
+ // Skip messages without ID (can't route them)
394
+ if (!obj.id)
395
+ return;
396
+ // Route response to the corresponding inflight request
397
+ if (this.inflight[obj.id]) {
398
+ this.inflight[obj.id].onReceived(obj.response);
399
+ }
400
+ }
401
+ catch (e) {
402
+ console.error("[socket message parse error]", e);
403
+ }
404
+ }
405
+ // Handle connection closure - automatically attempt reconnection
406
+ onClose(event) {
407
+ console.log("[socket close]", event.code, event.reason);
408
+ this.lastError = `Connection closed: ${event.reason || "Unknown reason"}`;
409
+ this.ws = undefined;
410
+ this.notifyStateChange();
411
+ this.scheduleReconnect();
412
+ }
413
+ // Handle successful connection
414
+ onOpen() {
415
+ console.log("[socket open]");
416
+ this.reconnectAttempts = 0; // Reset reconnection attempts on success
417
+ this.reconnectionState = "idle"; // Reset connection state
418
+ this.lastError = undefined; // Clear any previous errors
419
+ // Clear any pending reconnect timer
420
+ if (this.reconnectTimer) {
421
+ clearTimeout(this.reconnectTimer);
422
+ this.reconnectTimer = undefined;
423
+ }
424
+ // Notify UI of successful connection
425
+ this.notifyStateChange();
426
+ }
427
+ // Handle socket errors
428
+ onError(event) {
429
+ console.error("[socket error]", event);
430
+ this.lastError = "Connection error occurred";
431
+ this.notifyStateChange();
432
+ }
433
+ /**
434
+ * Schedules a reconnection attempt with exponential backoff
435
+ */
436
+ scheduleReconnect() {
437
+ // Prevent concurrent reconnection attempts
438
+ if (this.reconnectionState === "reconnecting") {
439
+ console.log("[socket] Reconnection already in progress, skipping");
440
+ return;
441
+ }
442
+ // Don't schedule if already scheduled
443
+ if (this.reconnectTimer)
444
+ return;
445
+ this.reconnectionState = "reconnecting";
446
+ this.reconnectAttempts++;
447
+ this.notifyStateChange(); // Notify UI of reconnection attempt
448
+ if (this.reconnectAttempts > this.maxReconnectAttempts) {
449
+ console.error("[socket] Max reconnection attempts reached");
450
+ this.reconnectionState = "failed";
451
+ this.lastError = "Max reconnection attempts exceeded";
452
+ this.notifyStateChange();
453
+ // Notify all pending requests of the failure
454
+ for (const mid in this.inflight) {
455
+ this.inflight[mid].error(new Error("WebSocket connection failed"));
456
+ }
457
+ return;
458
+ }
459
+ // Calculate exponential backoff with jitter
460
+ const backoffDelay = Math.min(SOCKET_RECONNECTION_TIMEOUT * Math.pow(2, this.reconnectAttempts - 1) +
461
+ Math.random() * 1000, 30000);
462
+ console.log(`[socket] Reconnecting in ${backoffDelay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
463
+ this.reconnectTimer = setTimeout(() => {
464
+ this.reconnectTimer = undefined;
465
+ this.reopen();
466
+ }, backoffDelay);
467
+ }
468
+ /**
469
+ * Reopens the WebSocket connection (used after connection failures)
470
+ */
471
+ reopen() {
472
+ console.log("[socket reopen]");
473
+ // Check if we're already connected or connecting
474
+ if (this.ws &&
475
+ (this.ws.readyState === WebSocket.OPEN ||
476
+ this.ws.readyState === WebSocket.CONNECTING)) {
477
+ return;
478
+ }
479
+ this.openSocket();
480
+ }
481
+ /**
482
+ * Closes the WebSocket connection and cleans up
483
+ */
484
+ close() {
485
+ // Clear reconnection timer
486
+ if (this.reconnectTimer) {
487
+ clearTimeout(this.reconnectTimer);
488
+ this.reconnectTimer = undefined;
489
+ }
490
+ // Clean up WebSocket
491
+ if (this.ws) {
492
+ // Remove event listeners to prevent memory leaks
493
+ this.ws.removeEventListener("message", this.onMessage);
494
+ this.ws.removeEventListener("close", this.onClose);
495
+ this.ws.removeEventListener("open", this.onOpen);
496
+ this.ws.removeEventListener("error", this.onError);
497
+ this.ws.close();
498
+ this.ws = undefined;
499
+ }
500
+ // Clear any remaining inflight requests
501
+ for (const mid in this.inflight) {
502
+ this.inflight[mid].error(new Error("Socket closed"));
503
+ }
504
+ this.inflight = {};
505
+ }
506
+ /**
507
+ * Generates the next unique message ID for requests
508
+ * Format: {clientTag}-{incrementingNumber}
509
+ */
510
+ getNextId() {
511
+ const mid = this.tag + "-" + this.id.toString();
512
+ this.id++;
513
+ return mid;
514
+ }
515
+ /**
516
+ * Core method for making service requests over WebSocket
517
+ * @param service - Name of the service to call
518
+ * @param request - Request payload
519
+ * @param timeout - Request timeout in milliseconds (default: 10000)
520
+ * @param retries - Number of retry attempts (default: 3)
521
+ * @param flow - Optional flow identifier
522
+ * @returns Promise resolving to the service response
523
+ */
524
+ makeRequest(service, request, timeout, retries, flow) {
525
+ const mid = this.getNextId();
526
+ // Set default values
527
+ if (timeout == undefined)
528
+ timeout = 10000;
529
+ if (retries == undefined)
530
+ retries = 3;
531
+ // Construct the request message
532
+ const msg = {
533
+ id: mid,
534
+ service: service,
535
+ request: request,
536
+ };
537
+ // Add flow identifier if provided
538
+ if (flow)
539
+ msg.flow = flow;
540
+ // Return a Promise that will be resolved/rejected by the ServiceCall
541
+ return new Promise((resolve, reject) => {
542
+ const call = new ServiceCall(mid, msg, resolve, reject, timeout, retries, this);
543
+ call.start();
544
+ // Commented out debug logging: console.log("-->", msg);
545
+ }).then((obj) => {
546
+ // Commented out success logging: console.log("Success for", mid);
547
+ return obj;
548
+ });
549
+ }
550
+ /**
551
+ * Makes a request that can receive multiple responses (streaming)
552
+ * Used for operations that return data in chunks
553
+ */
554
+ makeRequestMulti(service, request, receiver, // Callback to handle each response chunk
555
+ timeout, retries, flow) {
556
+ const mid = this.getNextId();
557
+ // Set defaults
558
+ if (timeout == undefined)
559
+ timeout = 10000;
560
+ if (retries == undefined)
561
+ retries = 3;
562
+ // Construct request message
563
+ const msg = {
564
+ id: mid,
565
+ service: service,
566
+ request: request,
567
+ };
568
+ if (flow)
569
+ msg.flow = flow;
570
+ return new Promise((resolve, reject) => {
571
+ const call = new ServiceCallMulti(mid, msg, resolve, reject, timeout, retries, this, // eslint-disable-line @typescript-eslint/no-explicit-any
572
+ receiver);
573
+ call.start();
574
+ }).then((obj) => {
575
+ return obj;
576
+ });
577
+ }
578
+ /**
579
+ * Convenience method for making flow-specific requests
580
+ * Defaults to "default" flow if none specified
581
+ */
582
+ makeFlowRequest(service, request, timeout, retries, flow) {
583
+ if (!flow)
584
+ flow = "default";
585
+ return this.makeRequest(service, request, timeout, retries, flow);
586
+ }
587
+ // Factory methods for creating specialized API instances
588
+ librarian() {
589
+ return new LibrarianApi(this);
590
+ }
591
+ flows() {
592
+ return new FlowsApi(this);
593
+ }
594
+ flow(id) {
595
+ return new FlowApi(this, id);
596
+ }
597
+ knowledge() {
598
+ return new KnowledgeApi(this);
599
+ }
600
+ config() {
601
+ return new ConfigApi(this);
602
+ }
603
+ collectionManagement() {
604
+ return new CollectionManagementApi(this);
605
+ }
606
+ }
607
+ /**
608
+ * LibrarianApi - Manages document storage and retrieval
609
+ * Handles document lifecycle including upload, processing, and removal
610
+ */
611
+ class LibrarianApi {
612
+ constructor(api) {
613
+ this.api = api;
614
+ }
615
+ /**
616
+ * Retrieves list of all documents in the system
617
+ */
618
+ getDocuments() {
619
+ return this.api
620
+ .makeRequest("librarian", {
621
+ operation: "list-documents",
622
+ user: this.api.user,
623
+ }, 60000)
624
+ .then((r) => r["document-metadatas"] || []);
625
+ }
626
+ /**
627
+ * Retrieves list of documents currently being processed
628
+ */
629
+ getProcessing() {
630
+ return this.api
631
+ .makeRequest("librarian", {
632
+ operation: "list-processing",
633
+ user: this.api.user,
634
+ }, 60000)
635
+ .then((r) => r["processing-metadata"] || []);
636
+ }
637
+ /**
638
+ * Uploads a document to the library with full metadata
639
+ * @param document - Base64-encoded document content
640
+ * @param id - Optional document identifier
641
+ * @param metadata - Optional metadata as triples
642
+ * @param mimeType - Document MIME type
643
+ * @param title - Document title
644
+ * @param comments - Additional comments
645
+ * @param tags - Document tags for categorization
646
+ */
647
+ loadDocument(document, // base64-encoded doc
648
+ mimeType, title, comments, tags, id, metadata) {
649
+ return this.api.makeRequest("librarian", {
650
+ operation: "add-document",
651
+ "document-metadata": {
652
+ id: id,
653
+ time: Math.floor(Date.now() / 1000), // Unix timestamp
654
+ kind: mimeType,
655
+ title: title,
656
+ comments: comments,
657
+ metadata: metadata,
658
+ user: this.api.user,
659
+ tags: tags,
660
+ },
661
+ content: document,
662
+ }, 30000);
663
+ }
664
+ /**
665
+ * Removes a document from the library
666
+ */
667
+ removeDocument(id, collection) {
668
+ return this.api.makeRequest("librarian", {
669
+ operation: "remove-document",
670
+ "document-id": id,
671
+ user: this.api.user,
672
+ collection: collection || "default",
673
+ }, 30000);
674
+ }
675
+ /**
676
+ * Adds a document to the processing queue
677
+ * @param id - Processing job identifier
678
+ * @param doc_id - Document to process
679
+ * @param flow - Processing flow to use
680
+ * @param collection - Collection to add processed data to
681
+ * @param tags - Tags for the processing job
682
+ */
683
+ addProcessing(id, doc_id, flow, collection, tags) {
684
+ return this.api.makeRequest("librarian", {
685
+ operation: "add-processing",
686
+ "processing-metadata": {
687
+ id: id,
688
+ "document-id": doc_id,
689
+ time: Math.floor(Date.now() / 1000),
690
+ flow: flow,
691
+ user: this.api.user,
692
+ collection: collection ? collection : "default",
693
+ tags: tags ? tags : [],
694
+ },
695
+ }, 30000);
696
+ }
697
+ }
698
+ /**
699
+ * FlowsApi - Manages processing flows and configuration
700
+ * Flows define how documents and data are processed through the system
701
+ */
702
+ class FlowsApi {
703
+ constructor(api) {
704
+ this.api = api;
705
+ }
706
+ /**
707
+ * Retrieves list of available flows
708
+ */
709
+ getFlows() {
710
+ return this.api
711
+ .makeRequest("flow", {
712
+ operation: "list-flows",
713
+ }, 60000)
714
+ .then((r) => r["flow-ids"] || []);
715
+ }
716
+ /**
717
+ * Retrieves definition of a specific flow
718
+ */
719
+ getFlow(id) {
720
+ return this.api
721
+ .makeRequest("flow", {
722
+ operation: "get-flow",
723
+ "flow-id": id,
724
+ }, 60000)
725
+ .then((r) => JSON.parse(r.flow || "{}")); // Parse JSON flow definition
726
+ }
727
+ // Configuration management methods
728
+ /**
729
+ * Retrieves all configuration settings
730
+ */
731
+ getConfigAll() {
732
+ return this.api.makeRequest("config", {
733
+ operation: "config",
734
+ }, 60000);
735
+ }
736
+ /**
737
+ * Retrieves specific configuration values by key
738
+ */
739
+ getConfig(keys) {
740
+ return this.api.makeRequest("config", {
741
+ operation: "get",
742
+ keys: keys,
743
+ }, 60000);
744
+ }
745
+ /**
746
+ * Updates configuration values
747
+ */
748
+ putConfig(values) {
749
+ return this.api.makeRequest("config", {
750
+ operation: "put",
751
+ values: values,
752
+ }, 60000);
753
+ }
754
+ /**
755
+ * Deletes configuration entries
756
+ */
757
+ deleteConfig(keys) {
758
+ return this.api.makeRequest("config", {
759
+ operation: "delete",
760
+ keys: keys,
761
+ }, 30000);
762
+ }
763
+ // Prompt management - specialized config operations for AI prompts
764
+ /**
765
+ * Retrieves list of available prompt templates
766
+ */
767
+ getPrompts() {
768
+ return this.getConfigAll().then((r) => {
769
+ const config = r;
770
+ return JSON.parse(config.config.prompt["template-index"]);
771
+ });
772
+ }
773
+ /**
774
+ * Retrieves a specific prompt template
775
+ */
776
+ getPrompt(id) {
777
+ return this.getConfigAll().then((r) => {
778
+ const config = r;
779
+ return JSON.parse(config.config.prompt[`template.${id}`]);
780
+ });
781
+ }
782
+ /**
783
+ * Retrieves the system prompt configuration
784
+ */
785
+ getSystemPrompt() {
786
+ return this.getConfigAll().then((r) => {
787
+ const config = r;
788
+ return JSON.parse(config.config.prompt.system);
789
+ });
790
+ }
791
+ // Flow class management - templates for creating flows
792
+ /**
793
+ * Retrieves list of available flow classes (templates)
794
+ */
795
+ getFlowClasses() {
796
+ return this.api
797
+ .makeRequest("flow", {
798
+ operation: "list-classes",
799
+ }, 60000)
800
+ .then((r) => r["class-names"]);
801
+ }
802
+ /**
803
+ * Retrieves definition of a specific flow class
804
+ */
805
+ getFlowClass(name) {
806
+ return this.api
807
+ .makeRequest("flow", {
808
+ operation: "get-class",
809
+ "class-name": name,
810
+ }, 60000)
811
+ .then((r) => JSON.parse(r["class-definition"] || "{}"));
812
+ }
813
+ /**
814
+ * Deletes a flow class
815
+ */
816
+ deleteFlowClass(name) {
817
+ return this.api.makeRequest("flow", {
818
+ operation: "delete-class",
819
+ "class-name": name,
820
+ }, 30000);
821
+ }
822
+ // Flow lifecycle management
823
+ /**
824
+ * Starts a new flow instance
825
+ */
826
+ startFlow(id, class_name, description, parameters) {
827
+ const request = {
828
+ operation: "start-flow",
829
+ "flow-id": id,
830
+ "class-name": class_name,
831
+ description: description,
832
+ };
833
+ // Only include parameters if provided and not empty
834
+ if (parameters && Object.keys(parameters).length > 0) {
835
+ request.parameters = parameters;
836
+ }
837
+ return this.api
838
+ .makeRequest("flow", request, 30000)
839
+ .then((response) => {
840
+ if (response.error) {
841
+ let errorMessage = "Flow start failed";
842
+ if (typeof response.error === "object" &&
843
+ response.error &&
844
+ "message" in response.error) {
845
+ errorMessage =
846
+ response.error.message || errorMessage;
847
+ }
848
+ else if (typeof response.error === "string") {
849
+ errorMessage = response.error;
850
+ }
851
+ throw new Error(errorMessage);
852
+ }
853
+ return response;
854
+ });
855
+ }
856
+ /**
857
+ * Stops a running flow instance
858
+ */
859
+ stopFlow(id) {
860
+ return this.api.makeRequest("flow", {
861
+ operation: "stop-flow",
862
+ "flow-id": id,
863
+ }, 30000);
864
+ }
865
+ }
866
+ /**
867
+ * FlowApi - Interface for interacting with a specific flow instance
868
+ * Provides flow-specific versions of core AI/ML operations
869
+ */
870
+ class FlowApi {
871
+ constructor(api, flowId) {
872
+ this.api = api;
873
+ this.flowId = flowId; // All requests will be routed through this flow
874
+ }
875
+ /**
876
+ * Performs text completion using AI models within this flow
877
+ */
878
+ textCompletion(system, text) {
879
+ return this.api
880
+ .makeRequest("text-completion", {
881
+ system: system, // System prompt/instructions
882
+ prompt: text, // User prompt
883
+ }, 30000, undefined, // Use default retries
884
+ this.flowId)
885
+ .then((r) => r.response);
886
+ }
887
+ /**
888
+ * Performs Graph RAG (Retrieval Augmented Generation) query
889
+ */
890
+ graphRag(text, options, collection) {
891
+ return this.api
892
+ .makeRequest("graph-rag", {
893
+ query: text,
894
+ user: this.api.user,
895
+ collection: collection || "default",
896
+ "entity-limit": options?.entityLimit,
897
+ "triple-limit": options?.tripleLimit,
898
+ "max-subgraph-size": options?.maxSubgraphSize,
899
+ "max-path-length": options?.pathLength,
900
+ }, 60000, // Longer timeout for complex graph operations
901
+ undefined, this.flowId)
902
+ .then((r) => r.response);
903
+ }
904
+ /**
905
+ * Performs Document RAG (Retrieval Augmented Generation) query
906
+ */
907
+ documentRag(text, docLimit, collection) {
908
+ return this.api
909
+ .makeRequest("document-rag", {
910
+ query: text,
911
+ user: this.api.user,
912
+ collection: collection || "default",
913
+ "doc-limit": docLimit || 20,
914
+ }, 60000, // Longer timeout for document operations
915
+ undefined, this.flowId)
916
+ .then((r) => r.response);
917
+ }
918
+ /**
919
+ * Interacts with an AI agent that provides streaming responses
920
+ */
921
+ agent(question, think, // Called when agent is thinking
922
+ observe, // Called when agent observes something
923
+ answer, // Called when agent provides answer
924
+ error) {
925
+ // Create a receiver function to handle streaming responses
926
+ const receiver = (response) => {
927
+ console.log("Agent response received:", response);
928
+ const resp = response;
929
+ // Check for backend errors
930
+ if (resp.error) {
931
+ const errorObj = resp.error;
932
+ const errorMessage = (typeof errorObj.message === "string" ? errorObj.message : null) ||
933
+ "Unknown agent error";
934
+ error(`Agent error: ${errorMessage}`);
935
+ return true; // End streaming on error
936
+ }
937
+ // Handle different response types
938
+ if (typeof resp.thought === "string")
939
+ think(resp.thought);
940
+ if (typeof resp.observation === "string")
941
+ observe(resp.observation);
942
+ if (typeof resp.answer === "string") {
943
+ answer(resp.answer);
944
+ return true; // End streaming when final answer is received
945
+ }
946
+ return false; // Continue streaming
947
+ };
948
+ // Use the existing makeRequestMulti infrastructure
949
+ return this.api
950
+ .makeRequestMulti("agent", {
951
+ question: question,
952
+ user: this.api.user,
953
+ }, receiver, 120000, // 120 second timeout
954
+ 2, // 2 retries
955
+ this.flowId)
956
+ .catch((err) => {
957
+ // Handle any errors from makeRequestMulti
958
+ const errorMessage = err instanceof Error
959
+ ? err.message
960
+ : err?.toString() || "Unknown error";
961
+ error(`Agent request failed: ${errorMessage}`);
962
+ });
963
+ }
964
+ /**
965
+ * Generates embeddings for text within this flow
966
+ */
967
+ embeddings(text) {
968
+ return this.api
969
+ .makeRequest("embeddings", {
970
+ text: text,
971
+ }, 30000, undefined, this.flowId)
972
+ .then((r) => r.vectors);
973
+ }
974
+ /**
975
+ * Queries the knowledge graph using embedding vectors
976
+ */
977
+ graphEmbeddingsQuery(vecs, limit, collection) {
978
+ return this.api
979
+ .makeRequest("graph-embeddings", {
980
+ vectors: vecs,
981
+ limit: limit ? limit : 20, // Default to 20 results
982
+ user: this.api.user,
983
+ collection: collection || "default",
984
+ }, 30000, undefined, this.flowId)
985
+ .then((r) => r.entities);
986
+ }
987
+ /**
988
+ * Queries knowledge graph triples (subject-predicate-object relationships)
989
+ * All parameters are optional - omitted parameters act as wildcards
990
+ */
991
+ triplesQuery(s, p, o, limit, collection) {
992
+ return this.api
993
+ .makeRequest("triples", {
994
+ s: s, // Subject
995
+ p: p, // Predicate
996
+ o: o, // Object
997
+ limit: limit ? limit : 20,
998
+ user: this.api.user,
999
+ collection: collection || "default",
1000
+ }, 30000, undefined, this.flowId)
1001
+ .then((r) => r.response);
1002
+ }
1003
+ /**
1004
+ * Loads a document into this flow for processing
1005
+ */
1006
+ loadDocument(document, // base64-encoded document
1007
+ id, metadata) {
1008
+ return this.api.makeRequest("document-load", {
1009
+ id: id,
1010
+ metadata: metadata,
1011
+ data: document,
1012
+ }, 30000, undefined, this.flowId);
1013
+ }
1014
+ /**
1015
+ * Loads plain text into this flow for processing
1016
+ */
1017
+ loadText(text, // Text content
1018
+ id, metadata, charset) {
1019
+ return this.api.makeRequest("text-load", {
1020
+ id: id,
1021
+ metadata: metadata,
1022
+ text: text,
1023
+ charset: charset,
1024
+ }, 30000, undefined, this.flowId);
1025
+ }
1026
+ /**
1027
+ * Executes a GraphQL query against structured data objects
1028
+ */
1029
+ objectsQuery(query, collection, variables, operationName) {
1030
+ return this.api
1031
+ .makeRequest("objects", {
1032
+ query: query,
1033
+ user: this.api.user,
1034
+ collection: collection || "default",
1035
+ variables: variables,
1036
+ operation_name: operationName,
1037
+ }, 30000, undefined, this.flowId)
1038
+ .then((r) => {
1039
+ // Return the GraphQL response structure directly
1040
+ const result = {};
1041
+ if (r.data !== undefined)
1042
+ result.data = r.data;
1043
+ if (r.errors)
1044
+ result.errors = r.errors;
1045
+ if (r.extensions)
1046
+ result.extensions = r.extensions;
1047
+ return result;
1048
+ });
1049
+ }
1050
+ /**
1051
+ * Converts a natural language question to a GraphQL query
1052
+ */
1053
+ nlpQuery(question, maxResults) {
1054
+ return this.api
1055
+ .makeRequest("nlp-query", {
1056
+ question: question,
1057
+ max_results: maxResults || 100,
1058
+ }, 30000, undefined, this.flowId)
1059
+ .then((r) => r);
1060
+ }
1061
+ /**
1062
+ * Executes a natural language question against structured data
1063
+ * Combines NLP query conversion and GraphQL execution
1064
+ */
1065
+ structuredQuery(question, collection) {
1066
+ return this.api
1067
+ .makeRequest("structured-query", {
1068
+ question: question,
1069
+ user: this.api.user,
1070
+ collection: collection || "default",
1071
+ }, 30000, undefined, this.flowId)
1072
+ .then((r) => {
1073
+ // Return the response structure directly
1074
+ const result = {};
1075
+ if (r.data !== undefined)
1076
+ result.data = r.data;
1077
+ if (r.errors)
1078
+ result.errors = r.errors;
1079
+ return result;
1080
+ });
1081
+ }
1082
+ }
1083
+ /**
1084
+ * ConfigApi - Dedicated configuration management interface
1085
+ * Handles system configuration, prompts, and token cost tracking
1086
+ */
1087
+ class ConfigApi {
1088
+ constructor(api) {
1089
+ this.api = api;
1090
+ }
1091
+ /**
1092
+ * Retrieves complete configuration
1093
+ */
1094
+ getConfigAll() {
1095
+ return this.api.makeRequest("config", {
1096
+ operation: "config",
1097
+ }, 60000);
1098
+ }
1099
+ /**
1100
+ * Retrieves specific configuration entries
1101
+ */
1102
+ getConfig(keys) {
1103
+ return this.api.makeRequest("config", {
1104
+ operation: "get",
1105
+ keys: keys,
1106
+ }, 60000);
1107
+ }
1108
+ /**
1109
+ * Updates configuration values
1110
+ */
1111
+ putConfig(values) {
1112
+ return this.api.makeRequest("config", {
1113
+ operation: "put",
1114
+ values: values,
1115
+ }, 60000);
1116
+ }
1117
+ /**
1118
+ * Deletes configuration entries
1119
+ */
1120
+ deleteConfig(keys) {
1121
+ return this.api.makeRequest("config", {
1122
+ operation: "delete",
1123
+ keys: keys,
1124
+ }, 30000);
1125
+ }
1126
+ // Specialized prompt management methods
1127
+ /**
1128
+ * Retrieves available prompt templates
1129
+ */
1130
+ getPrompts() {
1131
+ return this.getConfigAll().then((r) => {
1132
+ const config = r;
1133
+ return JSON.parse(config.config.prompt["template-index"]);
1134
+ });
1135
+ }
1136
+ /**
1137
+ * Retrieves a specific prompt template
1138
+ */
1139
+ getPrompt(id) {
1140
+ return this.getConfigAll().then((r) => {
1141
+ const config = r;
1142
+ return JSON.parse(config.config.prompt[`template.${id}`]);
1143
+ });
1144
+ }
1145
+ /**
1146
+ * Retrieves system prompt configuration
1147
+ */
1148
+ getSystemPrompt() {
1149
+ return this.getConfigAll().then((r) => {
1150
+ const config = r;
1151
+ return JSON.parse(config.config.prompt.system);
1152
+ });
1153
+ }
1154
+ /**
1155
+ * Lists available configuration types
1156
+ */
1157
+ list(type) {
1158
+ return this.api
1159
+ .makeRequest("config", {
1160
+ operation: "list",
1161
+ type: type,
1162
+ }, 60000)
1163
+ .then((r) => r);
1164
+ }
1165
+ /**
1166
+ * Retrieves all key/values for a specific type
1167
+ */
1168
+ getValues(type) {
1169
+ return this.api
1170
+ .makeRequest("config", {
1171
+ operation: "getvalues",
1172
+ type: type,
1173
+ }, 60000)
1174
+ .then((r) => r.values);
1175
+ }
1176
+ /**
1177
+ * Retrieves token cost information for different AI models
1178
+ * Useful for cost tracking and optimization
1179
+ */
1180
+ getTokenCosts() {
1181
+ return this.api
1182
+ .makeRequest("config", {
1183
+ operation: "getvalues",
1184
+ type: "token-costs",
1185
+ }, 60000)
1186
+ .then((r) => {
1187
+ // Parse JSON values and restructure data
1188
+ const response = r;
1189
+ return (response.values || []).map((x) => {
1190
+ const item = x;
1191
+ return { key: item.key, value: JSON.parse(item.value) };
1192
+ });
1193
+ })
1194
+ .then((r) =>
1195
+ // Transform to more usable format
1196
+ r.map((x) => {
1197
+ const item = x;
1198
+ const value = item.value;
1199
+ return {
1200
+ model: item.key,
1201
+ input_price: value.input_price, // Cost per input token
1202
+ output_price: value.output_price, // Cost per output token
1203
+ };
1204
+ }));
1205
+ }
1206
+ }
1207
+ /**
1208
+ * KnowledgeApi - Manages knowledge graph cores and data
1209
+ * Knowledge cores appear to be collections of processed knowledge graph data
1210
+ */
1211
+ class KnowledgeApi {
1212
+ constructor(api) {
1213
+ this.api = api;
1214
+ }
1215
+ /**
1216
+ * Retrieves list of available knowledge graph cores
1217
+ */
1218
+ getKnowledgeCores() {
1219
+ return this.api
1220
+ .makeRequest("knowledge", {
1221
+ operation: "list-kg-cores",
1222
+ user: this.api.user,
1223
+ }, 60000)
1224
+ .then((r) => r.ids || []);
1225
+ }
1226
+ /**
1227
+ * Deletes a knowledge graph core
1228
+ */
1229
+ deleteKgCore(id, collection) {
1230
+ return this.api.makeRequest("knowledge", {
1231
+ operation: "delete-kg-core",
1232
+ id: id,
1233
+ user: this.api.user,
1234
+ collection: collection || "default",
1235
+ }, 30000);
1236
+ }
1237
+ /**
1238
+ * Deletes a knowledge graph core
1239
+ */
1240
+ loadKgCore(id, flow, collection) {
1241
+ return this.api.makeRequest("knowledge", {
1242
+ operation: "load-kg-core",
1243
+ id: id,
1244
+ flow: flow,
1245
+ user: this.api.user,
1246
+ collection: collection || "default",
1247
+ }, 30000);
1248
+ }
1249
+ /**
1250
+ * Retrieves a knowledge graph core with streaming data
1251
+ * Uses multi-request pattern for large datasets
1252
+ * @param receiver - Callback function to handle streaming data chunks
1253
+ */
1254
+ getKgCore(id, collection, receiver) {
1255
+ // Wrapper to handle end-of-stream detection
1256
+ const recv = (msg) => {
1257
+ const response = msg;
1258
+ if (response.eos) {
1259
+ // End of stream - notify receiver and signal completion
1260
+ receiver(msg, true);
1261
+ return true;
1262
+ }
1263
+ else {
1264
+ // Regular message - continue streaming
1265
+ receiver(msg, false);
1266
+ return false;
1267
+ }
1268
+ };
1269
+ return this.api.makeRequestMulti("knowledge", {
1270
+ operation: "get-kg-core",
1271
+ id: id,
1272
+ user: this.api.user,
1273
+ collection: collection || "default",
1274
+ }, recv, // Stream handler
1275
+ 30000);
1276
+ }
1277
+ }
1278
+ /**
1279
+ * CollectionManagementApi - Manages collections for organizing documents
1280
+ * Provides operations for listing, creating, updating, and deleting collections
1281
+ */
1282
+ class CollectionManagementApi {
1283
+ constructor(api) {
1284
+ this.api = api;
1285
+ }
1286
+ /**
1287
+ * Lists all collections for the current user with optional tag filtering
1288
+ * @param tagFilter - Optional array of tags to filter collections
1289
+ * @returns Promise resolving to array of collection metadata
1290
+ */
1291
+ listCollections(tagFilter) {
1292
+ const request = {
1293
+ operation: "list-collections",
1294
+ user: this.api.user,
1295
+ };
1296
+ if (tagFilter && tagFilter.length > 0) {
1297
+ request.tag_filter = tagFilter;
1298
+ }
1299
+ return this.api
1300
+ .makeRequest("collection-management", request, 30000)
1301
+ .then((r) => r.collections || []);
1302
+ }
1303
+ /**
1304
+ * Creates or updates a collection for the current user
1305
+ * @param collection - Collection ID (unique identifier)
1306
+ * @param name - Display name for the collection
1307
+ * @param description - Description of the collection
1308
+ * @param tags - Array of tags for categorization
1309
+ * @returns Promise resolving to updated collection metadata
1310
+ */
1311
+ updateCollection(collection, name, description, tags) {
1312
+ const request = {
1313
+ operation: "update-collection",
1314
+ user: this.api.user,
1315
+ collection,
1316
+ };
1317
+ if (name !== undefined) {
1318
+ request.name = name;
1319
+ }
1320
+ if (description !== undefined) {
1321
+ request.description = description;
1322
+ }
1323
+ if (tags !== undefined) {
1324
+ request.tags = tags;
1325
+ }
1326
+ return this.api
1327
+ .makeRequest("collection-management", request, 30000)
1328
+ .then((r) => {
1329
+ if (r.collections &&
1330
+ Array.isArray(r.collections) &&
1331
+ r.collections.length > 0) {
1332
+ return r.collections[0];
1333
+ }
1334
+ throw new Error("Failed to update collection");
1335
+ });
1336
+ }
1337
+ /**
1338
+ * Deletes a collection and all its data for the current user
1339
+ * @param collection - Collection ID to delete
1340
+ * @returns Promise resolving when deletion is complete
1341
+ */
1342
+ deleteCollection(collection) {
1343
+ return this.api.makeRequest("collection-management", {
1344
+ operation: "delete-collection",
1345
+ user: this.api.user,
1346
+ collection,
1347
+ }, 30000);
1348
+ }
1349
+ }
1350
+ /**
1351
+ * Factory function to create a new TrustGraph WebSocket connection
1352
+ * This is the main entry point for using the TrustGraph API
1353
+ * @param user - User identifier for API requests
1354
+ * @param token - Optional authentication token for secure connections
1355
+ */
1356
+ const createTrustGraphSocket = (user, token) => {
1357
+ return new BaseApi(user, token);
1358
+ };
1359
+
1360
+ export { BaseApi, CollectionManagementApi, ConfigApi, FlowApi, FlowsApi, KnowledgeApi, LibrarianApi, createTrustGraphSocket };
1361
+ //# sourceMappingURL=index.esm.js.map