@dexto/client-sdk 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3,7 +3,6 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
6
  var __export = (target, all) => {
8
7
  for (var name in all)
9
8
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -17,833 +16,150 @@ var __copyProps = (to, from, except, desc) => {
17
16
  return to;
18
17
  };
19
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
21
19
 
22
20
  // src/index.ts
23
21
  var index_exports = {};
24
22
  __export(index_exports, {
25
- ClientError: () => ClientError,
26
- DextoClient: () => DextoClient
23
+ SSEError: () => SSEError,
24
+ createDextoClient: () => createDextoClient,
25
+ createMessageStream: () => createMessageStream,
26
+ createStream: () => createStream,
27
+ stream: () => stream
27
28
  });
28
29
  module.exports = __toCommonJS(index_exports);
29
30
 
30
- // src/errors.ts
31
- var ClientError = class {
32
- /**
33
- * Connection and Network Errors
34
- */
35
- static connectionFailed(baseUrl, originalError) {
36
- const error = new Error(`Failed to connect to Dexto server at ${baseUrl}`);
37
- error.name = "ConnectionError";
38
- error.baseUrl = baseUrl;
39
- error.originalError = originalError == null ? void 0 : originalError.message;
40
- return error;
41
- }
42
- static networkError(message, originalError) {
43
- const error = new Error(`Network error: ${message}`);
44
- error.name = "NetworkError";
45
- error.originalError = originalError == null ? void 0 : originalError.message;
46
- return error;
47
- }
48
- static httpError(status, statusText, endpoint, details) {
49
- const error = new Error(`HTTP ${status}: ${statusText}${endpoint ? ` (${endpoint})` : ""}`);
50
- error.name = "HttpError";
51
- error.status = status;
52
- error.statusText = statusText;
53
- error.endpoint = endpoint;
54
- error.details = details;
55
- return error;
56
- }
57
- static timeoutError(operation, timeout) {
58
- const error = new Error(`Operation '${operation}' timed out after ${timeout}ms`);
59
- error.name = "TimeoutError";
60
- error.operation = operation;
61
- error.timeout = timeout;
62
- return error;
63
- }
64
- /**
65
- * WebSocket Errors
66
- */
67
- static websocketConnectionFailed(url, originalError) {
68
- const error = new Error(`Failed to connect WebSocket to ${url}`);
69
- error.name = "WebSocketConnectionError";
70
- error.url = url;
71
- error.originalError = originalError == null ? void 0 : originalError.message;
72
- return error;
73
- }
74
- static websocketSendFailed(originalError) {
75
- const error = new Error("Failed to send WebSocket message");
76
- error.name = "WebSocketSendError";
77
- error.originalError = originalError == null ? void 0 : originalError.message;
78
- return error;
79
- }
80
- /**
81
- * Configuration Errors
82
- */
83
- static invalidConfig(field, value, reason) {
84
- const error = new Error(`Invalid configuration for ${field}: ${reason}`);
85
- error.name = "InvalidConfigError";
86
- error.field = field;
87
- error.value = value;
88
- error.reason = reason;
89
- return error;
90
- }
91
- static responseParseError(originalError) {
92
- const error = new Error("Failed to parse server response");
93
- error.name = "ResponseParseError";
94
- error.originalError = originalError == null ? void 0 : originalError.message;
95
- return error;
96
- }
97
- };
31
+ // src/client.ts
32
+ var import_client = require("hono/client");
98
33
 
99
- // src/http-client.ts
100
- var HttpClient = class {
101
- constructor(config) {
102
- __publicField(this, "config");
103
- __publicField(this, "fetchFn");
104
- this.config = config;
105
- if (typeof window !== "undefined" && window.fetch) {
106
- this.fetchFn = window.fetch.bind(window);
107
- } else if (typeof globalThis !== "undefined" && globalThis.fetch) {
108
- this.fetchFn = globalThis.fetch;
109
- } else {
110
- throw ClientError.invalidConfig(
111
- "fetch",
112
- "unavailable",
113
- "No fetch implementation available. Use Node.js 18+ or a browser."
114
- );
115
- }
34
+ // src/streaming.ts
35
+ var SSEError = class extends Error {
36
+ constructor(status, body) {
37
+ super(`SSE Error: ${status}`);
38
+ this.status = status;
39
+ this.body = body;
40
+ this.name = "SSEError";
116
41
  }
117
- async request(endpoint, options = {}) {
118
- var _a;
119
- const { method = "GET", body, headers = {}, timeout = this.config.timeout } = options;
120
- const url = new URL(endpoint, this.config.baseUrl).toString();
121
- const requestHeaders = { ...headers };
122
- const hasContentType = Object.keys(requestHeaders).some(
123
- (k) => k.toLowerCase() === "content-type"
124
- );
125
- let payload = void 0;
126
- const isBodyInit = (b) => {
127
- if (b == null) return false;
128
- return typeof b === "string" || typeof globalThis.Blob !== "undefined" && b instanceof globalThis.Blob || typeof globalThis.FormData !== "undefined" && b instanceof globalThis.FormData || typeof globalThis.URLSearchParams !== "undefined" && b instanceof globalThis.URLSearchParams || typeof globalThis.ReadableStream !== "undefined" && b instanceof globalThis.ReadableStream || typeof ArrayBuffer !== "undefined" && b instanceof ArrayBuffer;
129
- };
130
- if (body !== void 0) {
131
- if (isBodyInit(body)) {
132
- payload = body;
133
- } else {
134
- payload = JSON.stringify(body);
135
- if (!hasContentType) {
136
- requestHeaders["Content-Type"] = "application/json";
137
- }
138
- }
139
- }
140
- if (this.config.apiKey) {
141
- requestHeaders["Authorization"] = `Bearer ${this.config.apiKey}`;
142
- }
143
- const requestInit = {
144
- method,
145
- headers: requestHeaders,
146
- ...payload !== void 0 && { body: payload }
147
- };
148
- const controller = new AbortController();
149
- const resolvedTimeout = (_a = timeout != null ? timeout : this.config.timeout) != null ? _a : 3e4;
150
- const timeoutId = setTimeout(() => controller.abort(), resolvedTimeout);
151
- requestInit.signal = controller.signal;
42
+ };
43
+ async function* stream(response, options) {
44
+ var _a;
45
+ if (!response.ok) {
46
+ const contentType = response.headers.get("content-type");
47
+ let errorBody;
152
48
  try {
153
- const response = await this.fetchWithRetry(url, requestInit);
154
- clearTimeout(timeoutId);
155
- if (!response.ok) {
156
- const errorData = await this.safeParseJson(response);
157
- throw ClientError.httpError(
158
- response.status,
159
- response.statusText,
160
- endpoint,
161
- errorData
162
- );
163
- }
164
- if (response.status === 204 || response.headers.get("content-length") === "0") {
165
- return {};
166
- }
167
- const contentType = response.headers.get("content-type") || "";
168
- if (contentType.includes("application/json")) {
169
- const data = await response.json();
170
- return data;
171
- }
172
- const text = await response.text();
173
- return text ? text : {};
174
- } catch (error) {
175
- clearTimeout(timeoutId);
176
- if (error instanceof Error && error.name.startsWith("ClientError")) {
177
- throw error;
178
- }
179
- if (error instanceof Error && error.name === "AbortError") {
180
- throw ClientError.timeoutError(endpoint, resolvedTimeout);
181
- }
182
- throw ClientError.networkError(
183
- error instanceof Error ? error.message : "Unknown network error",
184
- error instanceof Error ? error : void 0
185
- );
186
- }
187
- }
188
- async fetchWithRetry(url, init) {
189
- var _a;
190
- let lastError = null;
191
- const method = (init.method || "GET").toUpperCase();
192
- const canRetry = ["GET", "HEAD", "PUT", "DELETE"].includes(method);
193
- const maxRetries = (_a = this.config.retries) != null ? _a : 3;
194
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
195
- try {
196
- const response = await this.fetchFn(url, init);
197
- const transientStatus = [429, 502, 503, 504];
198
- if (canRetry && transientStatus.includes(response.status) && attempt < maxRetries) {
199
- const retryAfter = response.headers.get("retry-after");
200
- let delay = Math.min(1e3 * Math.pow(2, attempt), 1e4);
201
- if (retryAfter) {
202
- const secs = Number(retryAfter);
203
- if (Number.isFinite(secs) && secs >= 0) {
204
- delay = secs * 1e3;
205
- } else {
206
- const retryTime = Date.parse(retryAfter);
207
- if (retryTime > Date.now()) {
208
- delay = Math.max(0, retryTime - Date.now());
209
- }
210
- }
211
- }
212
- delay = Math.min(delay, 3e4);
213
- await new Promise((resolve) => setTimeout(resolve, delay));
214
- continue;
215
- }
216
- return response;
217
- } catch (error) {
218
- lastError = error instanceof Error ? error : ClientError.networkError(
219
- error instanceof Error ? error.message : String(error),
220
- error instanceof Error ? error : void 0
221
- );
222
- if (attempt === maxRetries || !canRetry || error instanceof Error && error.name === "AbortError") {
223
- break;
224
- }
225
- const delay = Math.min(1e3 * Math.pow(2, attempt), 1e4);
226
- await new Promise((resolve) => setTimeout(resolve, delay));
49
+ if (contentType && contentType.includes("application/json")) {
50
+ errorBody = await response.json();
51
+ } else {
52
+ errorBody = await response.text();
227
53
  }
228
- }
229
- throw lastError;
230
- }
231
- async safeParseJson(response) {
232
- try {
233
- return await response.json();
234
54
  } catch (e) {
235
- return null;
55
+ errorBody = "Unknown error";
236
56
  }
57
+ throw new SSEError(response.status, errorBody);
237
58
  }
238
- // Convenience methods
239
- async get(endpoint, headers) {
240
- const options = { method: "GET" };
241
- if (headers) options.headers = headers;
242
- return this.request(endpoint, options);
243
- }
244
- async post(endpoint, body, headers) {
245
- const options = { method: "POST" };
246
- if (body !== void 0) options.body = body;
247
- if (headers) options.headers = headers;
248
- return this.request(endpoint, options);
249
- }
250
- async put(endpoint, body, headers) {
251
- const options = { method: "PUT" };
252
- if (body !== void 0) options.body = body;
253
- if (headers) options.headers = headers;
254
- return this.request(endpoint, options);
59
+ const reader = (_a = response.body) == null ? void 0 : _a.getReader();
60
+ if (!reader) {
61
+ throw new Error("Response body is null");
255
62
  }
256
- async delete(endpoint, headers) {
257
- const options = { method: "DELETE" };
258
- if (headers) options.headers = headers;
259
- return this.request(endpoint, options);
260
- }
261
- };
262
-
263
- // src/websocket-client.ts
264
- var WebSocketClient = class {
265
- constructor(url, options = {}) {
266
- __publicField(this, "ws", null);
267
- __publicField(this, "url");
268
- __publicField(this, "eventHandlers", /* @__PURE__ */ new Map());
269
- __publicField(this, "stateHandlers", /* @__PURE__ */ new Set());
270
- __publicField(this, "reconnectEnabled", true);
271
- __publicField(this, "reconnectInterval", 5e3);
272
- __publicField(this, "maxReconnectAttempts", 10);
273
- __publicField(this, "reconnectAttempts", 0);
274
- __publicField(this, "isIntentionallyClosed", false);
275
- var _a, _b, _c;
276
- this.url = url;
277
- this.reconnectEnabled = (_a = options.reconnect) != null ? _a : true;
278
- this.reconnectInterval = (_b = options.reconnectInterval) != null ? _b : 5e3;
279
- this.maxReconnectAttempts = (_c = options.maxReconnectAttempts) != null ? _c : 10;
280
- }
281
- connect() {
282
- return new Promise((resolve, reject) => {
283
- try {
284
- this.isIntentionallyClosed = false;
285
- this.emitState("connecting");
286
- if (typeof WebSocket !== "undefined") {
287
- this.ws = new WebSocket(this.url);
288
- } else {
289
- reject(
290
- ClientError.websocketConnectionFailed(
291
- this.url,
292
- new Error(
293
- "WebSocket not available in this environment. Use HTTP methods or run in a browser."
294
- )
295
- )
296
- );
297
- return;
298
- }
299
- this.setupEventHandlers(resolve, reject);
300
- } catch (error) {
301
- reject(
302
- ClientError.websocketConnectionFailed(
303
- this.url,
304
- error instanceof Error ? error : new Error("Failed to create WebSocket connection")
305
- )
306
- );
307
- }
63
+ const decoder = new globalThis.TextDecoder();
64
+ let buffer = "";
65
+ const signal = options == null ? void 0 : options.signal;
66
+ let aborted = false;
67
+ const abortHandler = () => {
68
+ aborted = true;
69
+ reader.cancel().catch(() => {
308
70
  });
309
- }
310
- setupEventHandlers(resolve, reject) {
311
- if (!this.ws) return;
312
- this.ws.onopen = () => {
313
- this.reconnectAttempts = 0;
314
- this.emitState("open");
315
- resolve();
316
- };
317
- this.ws.onmessage = (event) => {
318
- const raw = event.data;
319
- const tryDispatch = (text) => {
320
- try {
321
- this.handleIncomingMessage(JSON.parse(text));
322
- } catch (err) {
323
- console.warn(
324
- `[WebSocketClient] Failed to parse WebSocket message: ${err instanceof Error ? err.message : String(err)}`
325
- );
326
- }
327
- };
328
- if (typeof raw === "string") {
329
- tryDispatch(raw);
330
- } else if (typeof globalThis.Blob !== "undefined" && raw instanceof globalThis.Blob) {
331
- raw.text().then(tryDispatch).catch((err) => {
332
- console.warn(
333
- `[WebSocketClient] Failed to read Blob message: ${err instanceof Error ? err.message : String(err)}`
334
- );
335
- });
336
- } else if (typeof ArrayBuffer !== "undefined" && raw instanceof ArrayBuffer) {
337
- try {
338
- const text = new globalThis.TextDecoder().decode(raw);
339
- tryDispatch(text);
340
- } catch (err) {
341
- console.warn(
342
- `[WebSocketClient] Failed to decode ArrayBuffer message: ${err instanceof Error ? err.message : String(err)}`
343
- );
344
- }
345
- } else {
346
- console.warn(
347
- `[WebSocketClient] Ignoring non-text WebSocket message of type: ${Object.prototype.toString.call(raw)}`
348
- );
349
- }
350
- };
351
- this.ws.onclose = (_event) => {
352
- this.emitState("closed");
353
- const shouldReconnect = !this.isIntentionallyClosed && this.reconnectEnabled && this.reconnectAttempts < this.maxReconnectAttempts;
354
- if (shouldReconnect) {
355
- this.scheduleReconnect(resolve, reject);
356
- } else if (!this.isIntentionallyClosed && this.reconnectAttempts >= this.maxReconnectAttempts) {
357
- reject(
358
- ClientError.websocketConnectionFailed(
359
- this.url,
360
- new Error(`Max reconnect attempts reached (${this.maxReconnectAttempts})`)
361
- )
362
- );
363
- }
364
- };
365
- this.ws.onerror = (_error) => {
366
- this.emitState("error");
367
- if (this.reconnectAttempts === 0) {
368
- reject(ClientError.websocketConnectionFailed(this.url));
369
- }
370
- };
371
- }
372
- scheduleReconnect(resolve, reject) {
373
- this.reconnectAttempts++;
374
- setTimeout(() => {
375
- if (!this.isIntentionallyClosed) {
376
- this.emitState("connecting");
377
- if (resolve && reject) {
378
- this.connect().then(resolve).catch(reject);
379
- } else {
380
- this.connect().catch(() => {
381
- });
382
- }
383
- }
384
- }, this.reconnectInterval);
385
- }
386
- handleIncomingMessage(data) {
387
- var _a;
388
- const msgData = data;
389
- const eventType = msgData.type || msgData.event;
390
- if (!eventType) {
391
- console.warn("Received WebSocket message without event type:", msgData);
392
- return;
393
- }
394
- const event = {
395
- type: eventType,
396
- data: msgData.data || msgData,
397
- sessionId: msgData.sessionId || ((_a = msgData.data) == null ? void 0 : _a.sessionId)
398
- };
399
- const handlers = this.eventHandlers.get(event.type);
400
- if (handlers) {
401
- handlers.forEach((handler) => {
402
- try {
403
- handler(event);
404
- } catch (error) {
405
- console.error(
406
- `Error in event handler for ${event.type}: ${error instanceof Error ? error.message : String(error)}`
407
- );
408
- }
409
- });
410
- }
411
- const wildcardHandlers = this.eventHandlers.get("*");
412
- if (wildcardHandlers) {
413
- wildcardHandlers.forEach((handler) => {
414
- try {
415
- handler(event);
416
- } catch (error) {
417
- console.error(
418
- `Error in wildcard event handler: ${error instanceof Error ? error.message : String(error)}`
419
- );
420
- }
71
+ };
72
+ if (signal) {
73
+ if (signal.aborted) {
74
+ reader.cancel().catch(() => {
421
75
  });
76
+ return;
422
77
  }
78
+ signal.addEventListener("abort", abortHandler);
423
79
  }
424
- // Send a message through the WebSocket
425
- send(message) {
426
- if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
427
- return false;
428
- }
429
- try {
430
- this.ws.send(JSON.stringify(message));
431
- return true;
432
- } catch (error) {
433
- console.error(
434
- `Failed to send WebSocket message: ${error instanceof Error ? error.message : String(error)}`
435
- );
436
- return false;
437
- }
438
- }
439
- // Subscribe to specific event types
440
- on(eventType, handler) {
441
- if (!this.eventHandlers.has(eventType)) {
442
- this.eventHandlers.set(eventType, /* @__PURE__ */ new Set());
443
- }
444
- this.eventHandlers.get(eventType).add(handler);
445
- return () => {
446
- const handlers = this.eventHandlers.get(eventType);
447
- if (handlers) {
448
- handlers.delete(handler);
449
- if (handlers.size === 0) {
450
- this.eventHandlers.delete(eventType);
80
+ try {
81
+ while (true) {
82
+ if (aborted || (signal == null ? void 0 : signal.aborted)) {
83
+ return;
84
+ }
85
+ const parts = buffer.split("\n\n");
86
+ if (parts.length > 1) {
87
+ const eventString = parts.shift();
88
+ buffer = parts.join("\n\n");
89
+ const event = parseSSE(eventString);
90
+ if (event) {
91
+ yield event;
451
92
  }
93
+ continue;
94
+ }
95
+ const { done, value } = await reader.read();
96
+ if (done) {
97
+ if (buffer.trim()) {
98
+ const event = parseSSE(buffer);
99
+ if (event) {
100
+ yield event;
101
+ }
102
+ }
103
+ return;
452
104
  }
453
- };
454
- }
455
- // Subscribe to connection state changes
456
- onConnectionState(handler) {
457
- this.stateHandlers.add(handler);
458
- return () => {
459
- this.stateHandlers.delete(handler);
460
- };
461
- }
462
- emitState(state) {
463
- this.stateHandlers.forEach((handler) => {
464
- try {
465
- handler(state);
466
- } catch (error) {
467
- console.error(
468
- `Error in connection state handler: ${error instanceof Error ? error.message : String(error)}`
469
- );
470
- }
471
- });
472
- }
473
- // Get current connection state
474
- get state() {
475
- if (!this.ws) return "closed";
476
- switch (this.ws.readyState) {
477
- case WebSocket.CONNECTING:
478
- return "connecting";
479
- case WebSocket.OPEN:
480
- return "open";
481
- case WebSocket.CLOSING:
482
- case WebSocket.CLOSED:
483
- return "closed";
484
- default:
485
- return "closed";
486
- }
487
- }
488
- // Close the connection
489
- close() {
490
- this.isIntentionallyClosed = true;
491
- this.reconnectEnabled = false;
492
- if (this.ws) {
493
- this.ws.close();
494
- this.ws = null;
495
- }
496
- }
497
- // Enable/disable automatic reconnection
498
- setReconnectEnabled(enabled) {
499
- this.reconnectEnabled = enabled;
500
- }
501
- };
502
-
503
- // src/schemas.ts
504
- function isValidUrl(url) {
505
- try {
506
- new URL(url);
507
- return /^https?:\/\//i.test(url);
508
- } catch (e) {
509
- return false;
510
- }
511
- }
512
-
513
- // src/client.ts
514
- var DextoClient = class {
515
- constructor(config, options = {}) {
516
- __publicField(this, "http");
517
- __publicField(this, "ws", null);
518
- __publicField(this, "config");
519
- __publicField(this, "options");
520
- var _a, _b, _c, _d, _e, _f;
521
- if (!isValidUrl(config.baseUrl)) {
522
- throw ClientError.invalidConfig(
523
- "baseUrl",
524
- config.baseUrl,
525
- "Must be a valid HTTP/HTTPS URL"
526
- );
105
+ buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");
527
106
  }
528
- this.config = {
529
- baseUrl: config.baseUrl,
530
- apiKey: config.apiKey,
531
- timeout: (_a = config.timeout) != null ? _a : 3e4,
532
- retries: (_b = config.retries) != null ? _b : 3
533
- };
534
- this.options = {
535
- enableWebSocket: (_c = options.enableWebSocket) != null ? _c : true,
536
- reconnect: (_d = options.reconnect) != null ? _d : true,
537
- reconnectInterval: (_e = options.reconnectInterval) != null ? _e : 5e3,
538
- debug: (_f = options.debug) != null ? _f : false
539
- };
540
- this.http = new HttpClient(this.config);
541
- if (this.options.enableWebSocket) {
542
- this.initializeWebSocket();
107
+ } finally {
108
+ if (signal) {
109
+ signal.removeEventListener("abort", abortHandler);
543
110
  }
544
- }
545
- initializeWebSocket() {
546
- var _a, _b;
547
- const wsUrl = this.config.baseUrl.replace(/^https/, "wss").replace(/^http/, "ws");
548
- this.ws = new WebSocketClient(wsUrl, {
549
- reconnect: (_a = this.options.reconnect) != null ? _a : true,
550
- reconnectInterval: (_b = this.options.reconnectInterval) != null ? _b : 5e3
111
+ reader.cancel().catch(() => {
551
112
  });
552
113
  }
553
- // ============= CONNECTION MANAGEMENT =============
554
- /**
555
- * Establish connection to Dexto server (including WebSocket if enabled)
556
- */
557
- async connect() {
558
- try {
559
- await this.http.get("/health");
560
- } catch (error) {
561
- throw ClientError.connectionFailed(
562
- this.config.baseUrl,
563
- error instanceof Error ? error : void 0
564
- );
565
- }
566
- if (this.options.enableWebSocket && this.ws) {
114
+ }
115
+ async function* createStream(responsePromise, options) {
116
+ const response = await responsePromise;
117
+ yield* stream(response, options);
118
+ }
119
+ async function* createMessageStream(responsePromise, options) {
120
+ const sseStream = createStream(responsePromise, options);
121
+ for await (const event of sseStream) {
122
+ if (event.data) {
567
123
  try {
568
- await this.ws.connect();
569
- } catch (error) {
570
- if (this.options.debug) {
571
- console.warn(
572
- `WebSocket connection failed, continuing with HTTP-only mode: ${error instanceof Error ? error.message : String(error)}`
573
- );
124
+ const parsed = JSON.parse(event.data);
125
+ if (event.event && !parsed.type) {
126
+ parsed.type = event.event;
574
127
  }
575
- this.ws = null;
128
+ yield parsed;
129
+ } catch (e) {
576
130
  }
577
131
  }
578
132
  }
579
- /**
580
- * Disconnect from Dexto server
581
- */
582
- disconnect() {
583
- if (this.ws) {
584
- this.ws.close();
585
- this.ws = null;
586
- }
587
- }
588
- // ============= MESSAGING =============
589
- /**
590
- * Send a message to the Dexto agent
591
- */
592
- async sendMessage(input) {
593
- if (input.stream === true) {
594
- throw ClientError.invalidConfig(
595
- "input.stream",
596
- input.stream,
597
- "Use sendMessageStream() for streaming responses"
598
- );
599
- }
600
- const endpoint = "/api/message-sync";
601
- const requestBody = {
602
- message: input.content,
603
- ...input.sessionId && { sessionId: input.sessionId },
604
- ...input.imageData && { imageData: input.imageData },
605
- ...input.fileData && { fileData: input.fileData }
606
- };
607
- return this.http.post(endpoint, requestBody);
608
- }
609
- /**
610
- * Send a message via WebSocket for streaming responses
611
- */
612
- sendMessageStream(input) {
613
- if (!this.ws || this.ws.state !== "open") {
614
- throw ClientError.connectionFailed(
615
- "WebSocket endpoint",
616
- new Error("WebSocket connection not available for streaming")
617
- );
618
- }
619
- return this.ws.send({
620
- type: "message",
621
- content: input.content,
622
- ...input.sessionId && { sessionId: input.sessionId },
623
- ...input.imageData && { imageData: input.imageData },
624
- ...input.fileData && { fileData: input.fileData },
625
- stream: true
626
- });
627
- }
628
- // ============= SESSION MANAGEMENT =============
629
- /**
630
- * List all sessions
631
- */
632
- async listSessions() {
633
- const response = await this.http.get("/api/sessions");
634
- return response.sessions;
635
- }
636
- /**
637
- * Create a new session
638
- */
639
- async createSession(sessionId) {
640
- const response = await this.http.post("/api/sessions", {
641
- ...sessionId && { sessionId }
642
- });
643
- return response.session;
644
- }
645
- /**
646
- * Get session details
647
- */
648
- async getSession(sessionId) {
649
- const response = await this.http.get(
650
- `/api/sessions/${encodeURIComponent(sessionId)}`
651
- );
652
- return response.session;
653
- }
654
- /**
655
- * Get session conversation history
656
- */
657
- async getSessionHistory(sessionId) {
658
- const response = await this.http.get(
659
- `/api/sessions/${encodeURIComponent(sessionId)}/history`
660
- );
661
- return response.history;
662
- }
663
- /**
664
- * Delete a session permanently
665
- */
666
- async deleteSession(sessionId) {
667
- await this.http.delete(`/api/sessions/${encodeURIComponent(sessionId)}`);
668
- }
669
- /**
670
- * Load a session as the current working session
671
- */
672
- async loadSession(sessionId) {
673
- const id = sessionId === null ? "null" : sessionId;
674
- await this.http.post(`/api/sessions/${encodeURIComponent(id)}/load`);
675
- }
676
- /**
677
- * Get the current working session
678
- */
679
- async getCurrentSession() {
680
- const response = await this.http.get("/api/sessions/current");
681
- return response.currentSessionId;
682
- }
683
- /**
684
- * Reset conversation (clear history while keeping session alive)
685
- */
686
- async resetConversation(sessionId) {
687
- await this.http.post("/api/reset", {
688
- ...sessionId && { sessionId }
689
- });
690
- }
691
- // ============= LLM MANAGEMENT =============
692
- /**
693
- * Get current LLM configuration
694
- */
695
- async getCurrentLLMConfig(sessionId) {
696
- const params = sessionId ? `?sessionId=${encodeURIComponent(sessionId)}` : "";
697
- const response = await this.http.get(`/api/llm/current${params}`);
698
- return response.config;
699
- }
700
- /**
701
- * Switch LLM configuration
702
- */
703
- async switchLLM(config, sessionId) {
704
- const requestBody = {
705
- ...config,
706
- ...sessionId && { sessionId }
133
+ }
134
+ function parseSSE(raw) {
135
+ const lines = raw.split("\n").map((line) => line.replace(/\r$/, ""));
136
+ const event = {};
137
+ let hasData = false;
138
+ for (const line of lines) {
139
+ if (line.startsWith(":")) continue;
140
+ if (line.startsWith("data: ")) {
141
+ const data = line.slice(6);
142
+ event.data = event.data ? event.data + "\n" + data : data;
143
+ hasData = true;
144
+ } else if (line.startsWith("event: ")) {
145
+ event.event = line.slice(7);
146
+ } else if (line.startsWith("id: ")) {
147
+ event.id = line.slice(4);
148
+ } else if (line.startsWith("retry: ")) {
149
+ event.retry = parseInt(line.slice(7), 10);
150
+ }
151
+ }
152
+ if (!hasData && !event.event && !event.id) return null;
153
+ return event;
154
+ }
155
+
156
+ // src/client.ts
157
+ function createDextoClient(config) {
158
+ const options = {};
159
+ if (config.apiKey) {
160
+ options.headers = {
161
+ Authorization: `Bearer ${config.apiKey}`
707
162
  };
708
- const response = await this.http.post(
709
- "/api/llm/switch",
710
- requestBody
711
- );
712
- return response.config;
713
- }
714
- /**
715
- * Get available LLM providers and models
716
- */
717
- async getLLMProviders() {
718
- const response = await this.http.get(
719
- "/api/llm/providers"
720
- );
721
- return response.providers;
722
- }
723
- /**
724
- * Get LLM catalog with filtering options
725
- */
726
- async getLLMCatalog(options = {}) {
727
- const params = new globalThis.URLSearchParams();
728
- if (options.provider) params.set("provider", options.provider);
729
- if (options.hasKey !== void 0) params.set("hasKey", options.hasKey.toString());
730
- if (options.router) params.set("router", options.router);
731
- if (options.fileType) params.set("fileType", options.fileType);
732
- if (options.defaultOnly) params.set("defaultOnly", "true");
733
- if (options.mode) params.set("mode", options.mode);
734
- const queryString = params.toString();
735
- const endpoint = queryString ? `/api/llm/catalog?${queryString}` : "/api/llm/catalog";
736
- return this.http.get(endpoint);
737
163
  }
738
- // ============= MCP SERVER MANAGEMENT =============
739
- /**
740
- * List connected MCP servers
741
- */
742
- async listMCPServers() {
743
- const response = await this.http.get("/api/mcp/servers");
744
- return response.servers;
745
- }
746
- /**
747
- * Connect to a new MCP server
748
- */
749
- async connectMCPServer(name, config) {
750
- await this.http.post("/api/mcp/servers", { name, config });
751
- }
752
- /**
753
- * Disconnect from an MCP server
754
- */
755
- async disconnectMCPServer(serverId) {
756
- await this.http.delete(`/api/mcp/servers/${encodeURIComponent(serverId)}`);
757
- }
758
- /**
759
- * Get tools from a specific MCP server
760
- */
761
- async getMCPServerTools(serverId) {
762
- const response = await this.http.get(
763
- `/api/mcp/servers/${encodeURIComponent(serverId)}/tools`
764
- );
765
- return response.tools;
766
- }
767
- /**
768
- * Execute a tool from an MCP server
769
- */
770
- async executeMCPTool(serverId, toolName, args) {
771
- const response = await this.http.post(
772
- `/api/mcp/servers/${encodeURIComponent(serverId)}/tools/${encodeURIComponent(toolName)}/execute`,
773
- args
774
- );
775
- return response.data;
776
- }
777
- // ============= SEARCH =============
778
- /**
779
- * Search messages across sessions
780
- */
781
- async searchMessages(query, options = {}) {
782
- const params = new globalThis.URLSearchParams();
783
- params.append("q", query);
784
- if (options.limit !== void 0) params.append("limit", String(options.limit));
785
- if (options.offset !== void 0) params.append("offset", String(options.offset));
786
- if (options.sessionId) params.append("sessionId", options.sessionId);
787
- if (options.role) params.append("role", options.role);
788
- return this.http.get(`/api/search/messages?${params}`);
789
- }
790
- /**
791
- * Search sessions that contain the query
792
- */
793
- async searchSessions(query) {
794
- const params = new globalThis.URLSearchParams({ q: query });
795
- return this.http.get(`/api/search/sessions?${params}`);
796
- }
797
- // ============= EVENT HANDLING =============
798
- /**
799
- * Subscribe to real-time events
800
- */
801
- on(eventType, handler) {
802
- if (!this.ws) {
803
- if (this.options.debug) {
804
- console.warn("WebSocket not available, events will not be received");
805
- }
806
- return () => {
807
- };
808
- }
809
- return this.ws.on(eventType, handler);
810
- }
811
- /**
812
- * Subscribe to connection state changes
813
- */
814
- onConnectionState(handler) {
815
- if (!this.ws) {
816
- return () => {
817
- };
818
- }
819
- return this.ws.onConnectionState(handler);
820
- }
821
- // ============= GREETING =============
822
- /**
823
- * Get agent greeting message
824
- */
825
- async getGreeting(sessionId) {
826
- const params = sessionId ? `?sessionId=${encodeURIComponent(sessionId)}` : "";
827
- const response = await this.http.get(`/api/greeting${params}`);
828
- return response.greeting;
829
- }
830
- // ============= UTILITY METHODS =============
831
- /**
832
- * Get connection status
833
- */
834
- get connectionState() {
835
- return this.ws ? this.ws.state : "closed";
836
- }
837
- /**
838
- * Check if client is connected
839
- */
840
- get isConnected() {
841
- return this.connectionState === "open";
842
- }
843
- /**
844
- * Get client configuration
845
- */
846
- get clientConfig() {
847
- return { ...this.config };
848
- }
849
- };
164
+ return (0, import_client.hc)(config.baseUrl, options);
165
+ }