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