@ragbits/api-client 0.0.3 → 1.3.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.
- package/README.md +51 -101
- package/__tests__/mocks/handlers.ts +98 -0
- package/__tests__/setup.ts +23 -0
- package/__tests__/utils.ts +45 -0
- package/dist/autogen.types.d.ts +426 -0
- package/dist/index.cjs +147 -51
- package/dist/index.d.ts +14 -5
- package/dist/index.js +146 -51
- package/dist/types.d.ts +37 -198
- package/package.json +6 -2
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AuthType: () => AuthType,
|
|
23
24
|
ChatResponseType: () => ChatResponseType,
|
|
24
25
|
FeedbackType: () => FeedbackType,
|
|
25
26
|
LiveUpdateType: () => LiveUpdateType,
|
|
@@ -28,34 +29,36 @@ __export(index_exports, {
|
|
|
28
29
|
});
|
|
29
30
|
module.exports = __toCommonJS(index_exports);
|
|
30
31
|
|
|
31
|
-
// src/types.ts
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
var
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
32
|
+
// src/autogen.types.ts
|
|
33
|
+
var ChatResponseType = {
|
|
34
|
+
Text: "text",
|
|
35
|
+
Reference: "reference",
|
|
36
|
+
StateUpdate: "state_update",
|
|
37
|
+
MessageId: "message_id",
|
|
38
|
+
ConversationId: "conversation_id",
|
|
39
|
+
LiveUpdate: "live_update",
|
|
40
|
+
FollowupMessages: "followup_messages",
|
|
41
|
+
Image: "image",
|
|
42
|
+
ChunkedContent: "chunked_content",
|
|
43
|
+
ClearMessage: "clear_message",
|
|
44
|
+
Usage: "usage"
|
|
45
|
+
};
|
|
46
|
+
var FeedbackType = {
|
|
47
|
+
Like: "like",
|
|
48
|
+
Dislike: "dislike"
|
|
49
|
+
};
|
|
50
|
+
var LiveUpdateType = {
|
|
51
|
+
Start: "START",
|
|
52
|
+
Finish: "FINISH"
|
|
53
|
+
};
|
|
54
|
+
var MessageRole = {
|
|
55
|
+
User: "user",
|
|
56
|
+
Assistant: "assistant",
|
|
57
|
+
System: "system"
|
|
58
|
+
};
|
|
59
|
+
var AuthType = {
|
|
60
|
+
Credentials: "credentials"
|
|
61
|
+
};
|
|
59
62
|
|
|
60
63
|
// src/index.ts
|
|
61
64
|
var RagbitsClient = class {
|
|
@@ -63,7 +66,15 @@ var RagbitsClient = class {
|
|
|
63
66
|
* @param config - Configuration object
|
|
64
67
|
*/
|
|
65
68
|
constructor(config = {}) {
|
|
66
|
-
this.
|
|
69
|
+
this.chunkQueue = /* @__PURE__ */ new Map();
|
|
70
|
+
this.baseUrl = config.baseUrl ?? "";
|
|
71
|
+
this.auth = config.auth;
|
|
72
|
+
if (this.baseUrl.endsWith("/")) {
|
|
73
|
+
this.baseUrl = this.baseUrl.slice(0, -1);
|
|
74
|
+
}
|
|
75
|
+
if (!this.baseUrl) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
67
78
|
try {
|
|
68
79
|
new URL(this.baseUrl);
|
|
69
80
|
} catch {
|
|
@@ -71,9 +82,6 @@ var RagbitsClient = class {
|
|
|
71
82
|
`Invalid base URL: ${this.baseUrl}. Please provide a valid URL.`
|
|
72
83
|
);
|
|
73
84
|
}
|
|
74
|
-
if (this.baseUrl.endsWith("/")) {
|
|
75
|
-
this.baseUrl = this.baseUrl.slice(0, -1);
|
|
76
|
-
}
|
|
77
85
|
}
|
|
78
86
|
/**
|
|
79
87
|
* Get the base URL used by this client
|
|
@@ -93,12 +101,20 @@ var RagbitsClient = class {
|
|
|
93
101
|
* @private
|
|
94
102
|
*/
|
|
95
103
|
async _makeRequest(url, options = {}) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
const defaultHeaders = {
|
|
105
|
+
"Content-Type": "application/json"
|
|
106
|
+
};
|
|
107
|
+
const headers = {
|
|
108
|
+
...defaultHeaders,
|
|
109
|
+
...this.normalizeHeaders(options.headers)
|
|
100
110
|
};
|
|
101
|
-
|
|
111
|
+
if (this.auth?.getToken) {
|
|
112
|
+
headers["Authorization"] = `Bearer ${this.auth.getToken()}`;
|
|
113
|
+
}
|
|
114
|
+
const response = await fetch(url, { ...options, headers });
|
|
115
|
+
if (response.status === 401) {
|
|
116
|
+
this.auth?.onUnauthorized?.();
|
|
117
|
+
}
|
|
102
118
|
if (!response.ok) {
|
|
103
119
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
104
120
|
}
|
|
@@ -106,7 +122,7 @@ var RagbitsClient = class {
|
|
|
106
122
|
}
|
|
107
123
|
/**
|
|
108
124
|
* Method to make API requests to known endpoints only
|
|
109
|
-
* @param endpoint - API endpoint path
|
|
125
|
+
* @param endpoint - API endpoint path
|
|
110
126
|
* @param options - Typed request options for the specific endpoint
|
|
111
127
|
*/
|
|
112
128
|
async makeRequest(endpoint, options) {
|
|
@@ -126,25 +142,26 @@ var RagbitsClient = class {
|
|
|
126
142
|
requestOptions.body = typeof body === "string" ? body : JSON.stringify(body);
|
|
127
143
|
}
|
|
128
144
|
const response = await this._makeRequest(
|
|
129
|
-
this._buildApiUrl(endpoint),
|
|
145
|
+
this._buildApiUrl(endpoint.toString()),
|
|
130
146
|
requestOptions
|
|
131
147
|
);
|
|
132
148
|
return response.json();
|
|
133
149
|
}
|
|
134
150
|
/**
|
|
135
151
|
* Method for streaming requests to known endpoints only
|
|
136
|
-
* @param endpoint - Streaming endpoint path
|
|
152
|
+
* @param endpoint - Streaming endpoint path
|
|
137
153
|
* @param data - Request data
|
|
138
154
|
* @param callbacks - Stream callbacks
|
|
139
155
|
* @param signal - Optional AbortSignal for cancelling the request
|
|
140
156
|
*/
|
|
141
|
-
makeStreamRequest(endpoint, data, callbacks, signal) {
|
|
157
|
+
makeStreamRequest(endpoint, data, callbacks, signal, customHeaders) {
|
|
142
158
|
let isCancelled = false;
|
|
143
159
|
const processStream = async (response) => {
|
|
144
160
|
const reader = response.body?.pipeThrough(new TextDecoderStream()).getReader();
|
|
145
161
|
if (!reader) {
|
|
146
162
|
throw new Error("Response body is null");
|
|
147
163
|
}
|
|
164
|
+
let buffer = "";
|
|
148
165
|
while (!isCancelled && !signal?.aborted) {
|
|
149
166
|
try {
|
|
150
167
|
const { value, done } = await reader.read();
|
|
@@ -152,7 +169,9 @@ var RagbitsClient = class {
|
|
|
152
169
|
callbacks.onClose?.();
|
|
153
170
|
break;
|
|
154
171
|
}
|
|
155
|
-
|
|
172
|
+
buffer += value;
|
|
173
|
+
const lines = buffer.split("\n");
|
|
174
|
+
buffer = lines.pop() ?? "";
|
|
156
175
|
for (const line of lines) {
|
|
157
176
|
if (!line.startsWith("data: ")) continue;
|
|
158
177
|
try {
|
|
@@ -160,6 +179,10 @@ var RagbitsClient = class {
|
|
|
160
179
|
const parsedData = JSON.parse(
|
|
161
180
|
jsonString
|
|
162
181
|
);
|
|
182
|
+
if (parsedData.type === ChatResponseType.ChunkedContent) {
|
|
183
|
+
this.handleChunkedContent(parsedData, callbacks);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
163
186
|
await callbacks.onMessage(parsedData);
|
|
164
187
|
} catch (parseError) {
|
|
165
188
|
console.error("Error parsing JSON:", parseError);
|
|
@@ -169,6 +192,9 @@ var RagbitsClient = class {
|
|
|
169
192
|
}
|
|
170
193
|
}
|
|
171
194
|
} catch (streamError) {
|
|
195
|
+
if (signal?.aborted) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
172
198
|
console.error("Stream error:", streamError);
|
|
173
199
|
await callbacks.onError(new Error("Error reading stream"));
|
|
174
200
|
break;
|
|
@@ -177,15 +203,29 @@ var RagbitsClient = class {
|
|
|
177
203
|
};
|
|
178
204
|
const startStream = async () => {
|
|
179
205
|
try {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
206
|
+
const defaultHeaders = {
|
|
207
|
+
"Content-Type": "application/json",
|
|
208
|
+
Accept: "text/event-stream"
|
|
209
|
+
};
|
|
210
|
+
const headers = {
|
|
211
|
+
...defaultHeaders,
|
|
212
|
+
...customHeaders
|
|
213
|
+
};
|
|
214
|
+
if (this.auth?.getToken) {
|
|
215
|
+
headers["Authorization"] = `Bearer ${this.auth.getToken()}`;
|
|
216
|
+
}
|
|
217
|
+
const response = await fetch(
|
|
218
|
+
this._buildApiUrl(endpoint.toString()),
|
|
219
|
+
{
|
|
220
|
+
method: "POST",
|
|
221
|
+
headers,
|
|
222
|
+
body: JSON.stringify(data),
|
|
223
|
+
signal
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
if (response.status === 401) {
|
|
227
|
+
this.auth?.onUnauthorized?.();
|
|
228
|
+
}
|
|
189
229
|
if (!response.ok) {
|
|
190
230
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
191
231
|
}
|
|
@@ -209,9 +249,65 @@ var RagbitsClient = class {
|
|
|
209
249
|
isCancelled = true;
|
|
210
250
|
};
|
|
211
251
|
}
|
|
252
|
+
normalizeHeaders(init) {
|
|
253
|
+
if (!init) return {};
|
|
254
|
+
if (init instanceof Headers) {
|
|
255
|
+
return Object.fromEntries(init.entries());
|
|
256
|
+
}
|
|
257
|
+
if (Array.isArray(init)) {
|
|
258
|
+
return Object.fromEntries(init);
|
|
259
|
+
}
|
|
260
|
+
return init;
|
|
261
|
+
}
|
|
262
|
+
async handleChunkedContent(data, callbacks) {
|
|
263
|
+
const response = data;
|
|
264
|
+
const content = response.content;
|
|
265
|
+
const {
|
|
266
|
+
content_type: contentType,
|
|
267
|
+
id,
|
|
268
|
+
chunk_index: chunkIndex,
|
|
269
|
+
total_chunks: totalChunks,
|
|
270
|
+
mime_type: mimeType,
|
|
271
|
+
data: chunkData
|
|
272
|
+
} = content;
|
|
273
|
+
if (!this.chunkQueue.has(id)) {
|
|
274
|
+
this.chunkQueue.set(id, {
|
|
275
|
+
chunks: /* @__PURE__ */ new Map(),
|
|
276
|
+
totalChunks,
|
|
277
|
+
mimeType
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
const imageInfo = this.chunkQueue.get(id);
|
|
281
|
+
imageInfo.chunks.set(chunkIndex, chunkData);
|
|
282
|
+
if (imageInfo.chunks.size !== totalChunks) return;
|
|
283
|
+
const sortedChunks = Array.from(
|
|
284
|
+
{ length: totalChunks },
|
|
285
|
+
(_, i) => imageInfo.chunks.get(i)
|
|
286
|
+
);
|
|
287
|
+
const completeBase64 = sortedChunks.join("");
|
|
288
|
+
try {
|
|
289
|
+
atob(completeBase64);
|
|
290
|
+
} catch (e) {
|
|
291
|
+
this.chunkQueue.delete(id);
|
|
292
|
+
console.error("\u274C Invalid base64 data: ", e);
|
|
293
|
+
await callbacks.onError(new Error("Error reading stream"));
|
|
294
|
+
}
|
|
295
|
+
if (contentType === ChatResponseType.Image) {
|
|
296
|
+
const completeImageResponse = {
|
|
297
|
+
type: ChatResponseType.Image,
|
|
298
|
+
content: {
|
|
299
|
+
id,
|
|
300
|
+
url: `${imageInfo.mimeType},${completeBase64}`
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
await callbacks.onMessage(completeImageResponse);
|
|
304
|
+
}
|
|
305
|
+
this.chunkQueue.delete(id);
|
|
306
|
+
}
|
|
212
307
|
};
|
|
213
308
|
// Annotate the CommonJS export names for ESM import in node:
|
|
214
309
|
0 && (module.exports = {
|
|
310
|
+
AuthType,
|
|
215
311
|
ChatResponseType,
|
|
216
312
|
FeedbackType,
|
|
217
313
|
LiveUpdateType,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type { ClientConfig, StreamCallbacks,
|
|
1
|
+
import type { ClientConfig, StreamCallbacks, BaseApiEndpoints, EndpointDefinition, EndpointResponse, RequestOptions, BaseStreamingEndpoints, EndpointRequest } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Client for communicating with the Ragbits API
|
|
4
4
|
*/
|
|
5
5
|
export declare class RagbitsClient {
|
|
6
6
|
private readonly baseUrl;
|
|
7
|
+
private readonly auth;
|
|
8
|
+
private chunkQueue;
|
|
7
9
|
/**
|
|
8
10
|
* @param config - Configuration object
|
|
9
11
|
*/
|
|
@@ -24,17 +26,24 @@ export declare class RagbitsClient {
|
|
|
24
26
|
private _makeRequest;
|
|
25
27
|
/**
|
|
26
28
|
* Method to make API requests to known endpoints only
|
|
27
|
-
* @param endpoint - API endpoint path
|
|
29
|
+
* @param endpoint - API endpoint path
|
|
28
30
|
* @param options - Typed request options for the specific endpoint
|
|
29
31
|
*/
|
|
30
|
-
makeRequest<
|
|
32
|
+
makeRequest<Endpoints extends {
|
|
33
|
+
[K in keyof Endpoints]: EndpointDefinition;
|
|
34
|
+
} = BaseApiEndpoints, URL extends keyof Endpoints = keyof Endpoints>(endpoint: URL, options?: RequestOptions<URL, Endpoints>): Promise<EndpointResponse<URL, Endpoints>>;
|
|
31
35
|
/**
|
|
32
36
|
* Method for streaming requests to known endpoints only
|
|
33
|
-
* @param endpoint - Streaming endpoint path
|
|
37
|
+
* @param endpoint - Streaming endpoint path
|
|
34
38
|
* @param data - Request data
|
|
35
39
|
* @param callbacks - Stream callbacks
|
|
36
40
|
* @param signal - Optional AbortSignal for cancelling the request
|
|
37
41
|
*/
|
|
38
|
-
makeStreamRequest<
|
|
42
|
+
makeStreamRequest<Endpoints extends {
|
|
43
|
+
[K in keyof Endpoints]: EndpointDefinition;
|
|
44
|
+
} = BaseStreamingEndpoints, URL extends keyof Endpoints = keyof Endpoints>(endpoint: URL, data: EndpointRequest<URL, Endpoints>, callbacks: StreamCallbacks<EndpointResponse<URL, Endpoints>>, signal?: AbortSignal, customHeaders?: Record<string, string>): () => void;
|
|
45
|
+
private normalizeHeaders;
|
|
46
|
+
private handleChunkedContent;
|
|
39
47
|
}
|
|
40
48
|
export * from './types';
|
|
49
|
+
export * from './autogen.types';
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
|
-
// src/types.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
var
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
// src/autogen.types.ts
|
|
2
|
+
var ChatResponseType = {
|
|
3
|
+
Text: "text",
|
|
4
|
+
Reference: "reference",
|
|
5
|
+
StateUpdate: "state_update",
|
|
6
|
+
MessageId: "message_id",
|
|
7
|
+
ConversationId: "conversation_id",
|
|
8
|
+
LiveUpdate: "live_update",
|
|
9
|
+
FollowupMessages: "followup_messages",
|
|
10
|
+
Image: "image",
|
|
11
|
+
ChunkedContent: "chunked_content",
|
|
12
|
+
ClearMessage: "clear_message",
|
|
13
|
+
Usage: "usage"
|
|
14
|
+
};
|
|
15
|
+
var FeedbackType = {
|
|
16
|
+
Like: "like",
|
|
17
|
+
Dislike: "dislike"
|
|
18
|
+
};
|
|
19
|
+
var LiveUpdateType = {
|
|
20
|
+
Start: "START",
|
|
21
|
+
Finish: "FINISH"
|
|
22
|
+
};
|
|
23
|
+
var MessageRole = {
|
|
24
|
+
User: "user",
|
|
25
|
+
Assistant: "assistant",
|
|
26
|
+
System: "system"
|
|
27
|
+
};
|
|
28
|
+
var AuthType = {
|
|
29
|
+
Credentials: "credentials"
|
|
30
|
+
};
|
|
29
31
|
|
|
30
32
|
// src/index.ts
|
|
31
33
|
var RagbitsClient = class {
|
|
@@ -33,7 +35,15 @@ var RagbitsClient = class {
|
|
|
33
35
|
* @param config - Configuration object
|
|
34
36
|
*/
|
|
35
37
|
constructor(config = {}) {
|
|
36
|
-
this.
|
|
38
|
+
this.chunkQueue = /* @__PURE__ */ new Map();
|
|
39
|
+
this.baseUrl = config.baseUrl ?? "";
|
|
40
|
+
this.auth = config.auth;
|
|
41
|
+
if (this.baseUrl.endsWith("/")) {
|
|
42
|
+
this.baseUrl = this.baseUrl.slice(0, -1);
|
|
43
|
+
}
|
|
44
|
+
if (!this.baseUrl) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
37
47
|
try {
|
|
38
48
|
new URL(this.baseUrl);
|
|
39
49
|
} catch {
|
|
@@ -41,9 +51,6 @@ var RagbitsClient = class {
|
|
|
41
51
|
`Invalid base URL: ${this.baseUrl}. Please provide a valid URL.`
|
|
42
52
|
);
|
|
43
53
|
}
|
|
44
|
-
if (this.baseUrl.endsWith("/")) {
|
|
45
|
-
this.baseUrl = this.baseUrl.slice(0, -1);
|
|
46
|
-
}
|
|
47
54
|
}
|
|
48
55
|
/**
|
|
49
56
|
* Get the base URL used by this client
|
|
@@ -63,12 +70,20 @@ var RagbitsClient = class {
|
|
|
63
70
|
* @private
|
|
64
71
|
*/
|
|
65
72
|
async _makeRequest(url, options = {}) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
const defaultHeaders = {
|
|
74
|
+
"Content-Type": "application/json"
|
|
75
|
+
};
|
|
76
|
+
const headers = {
|
|
77
|
+
...defaultHeaders,
|
|
78
|
+
...this.normalizeHeaders(options.headers)
|
|
70
79
|
};
|
|
71
|
-
|
|
80
|
+
if (this.auth?.getToken) {
|
|
81
|
+
headers["Authorization"] = `Bearer ${this.auth.getToken()}`;
|
|
82
|
+
}
|
|
83
|
+
const response = await fetch(url, { ...options, headers });
|
|
84
|
+
if (response.status === 401) {
|
|
85
|
+
this.auth?.onUnauthorized?.();
|
|
86
|
+
}
|
|
72
87
|
if (!response.ok) {
|
|
73
88
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
74
89
|
}
|
|
@@ -76,7 +91,7 @@ var RagbitsClient = class {
|
|
|
76
91
|
}
|
|
77
92
|
/**
|
|
78
93
|
* Method to make API requests to known endpoints only
|
|
79
|
-
* @param endpoint - API endpoint path
|
|
94
|
+
* @param endpoint - API endpoint path
|
|
80
95
|
* @param options - Typed request options for the specific endpoint
|
|
81
96
|
*/
|
|
82
97
|
async makeRequest(endpoint, options) {
|
|
@@ -96,25 +111,26 @@ var RagbitsClient = class {
|
|
|
96
111
|
requestOptions.body = typeof body === "string" ? body : JSON.stringify(body);
|
|
97
112
|
}
|
|
98
113
|
const response = await this._makeRequest(
|
|
99
|
-
this._buildApiUrl(endpoint),
|
|
114
|
+
this._buildApiUrl(endpoint.toString()),
|
|
100
115
|
requestOptions
|
|
101
116
|
);
|
|
102
117
|
return response.json();
|
|
103
118
|
}
|
|
104
119
|
/**
|
|
105
120
|
* Method for streaming requests to known endpoints only
|
|
106
|
-
* @param endpoint - Streaming endpoint path
|
|
121
|
+
* @param endpoint - Streaming endpoint path
|
|
107
122
|
* @param data - Request data
|
|
108
123
|
* @param callbacks - Stream callbacks
|
|
109
124
|
* @param signal - Optional AbortSignal for cancelling the request
|
|
110
125
|
*/
|
|
111
|
-
makeStreamRequest(endpoint, data, callbacks, signal) {
|
|
126
|
+
makeStreamRequest(endpoint, data, callbacks, signal, customHeaders) {
|
|
112
127
|
let isCancelled = false;
|
|
113
128
|
const processStream = async (response) => {
|
|
114
129
|
const reader = response.body?.pipeThrough(new TextDecoderStream()).getReader();
|
|
115
130
|
if (!reader) {
|
|
116
131
|
throw new Error("Response body is null");
|
|
117
132
|
}
|
|
133
|
+
let buffer = "";
|
|
118
134
|
while (!isCancelled && !signal?.aborted) {
|
|
119
135
|
try {
|
|
120
136
|
const { value, done } = await reader.read();
|
|
@@ -122,7 +138,9 @@ var RagbitsClient = class {
|
|
|
122
138
|
callbacks.onClose?.();
|
|
123
139
|
break;
|
|
124
140
|
}
|
|
125
|
-
|
|
141
|
+
buffer += value;
|
|
142
|
+
const lines = buffer.split("\n");
|
|
143
|
+
buffer = lines.pop() ?? "";
|
|
126
144
|
for (const line of lines) {
|
|
127
145
|
if (!line.startsWith("data: ")) continue;
|
|
128
146
|
try {
|
|
@@ -130,6 +148,10 @@ var RagbitsClient = class {
|
|
|
130
148
|
const parsedData = JSON.parse(
|
|
131
149
|
jsonString
|
|
132
150
|
);
|
|
151
|
+
if (parsedData.type === ChatResponseType.ChunkedContent) {
|
|
152
|
+
this.handleChunkedContent(parsedData, callbacks);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
133
155
|
await callbacks.onMessage(parsedData);
|
|
134
156
|
} catch (parseError) {
|
|
135
157
|
console.error("Error parsing JSON:", parseError);
|
|
@@ -139,6 +161,9 @@ var RagbitsClient = class {
|
|
|
139
161
|
}
|
|
140
162
|
}
|
|
141
163
|
} catch (streamError) {
|
|
164
|
+
if (signal?.aborted) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
142
167
|
console.error("Stream error:", streamError);
|
|
143
168
|
await callbacks.onError(new Error("Error reading stream"));
|
|
144
169
|
break;
|
|
@@ -147,15 +172,29 @@ var RagbitsClient = class {
|
|
|
147
172
|
};
|
|
148
173
|
const startStream = async () => {
|
|
149
174
|
try {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
175
|
+
const defaultHeaders = {
|
|
176
|
+
"Content-Type": "application/json",
|
|
177
|
+
Accept: "text/event-stream"
|
|
178
|
+
};
|
|
179
|
+
const headers = {
|
|
180
|
+
...defaultHeaders,
|
|
181
|
+
...customHeaders
|
|
182
|
+
};
|
|
183
|
+
if (this.auth?.getToken) {
|
|
184
|
+
headers["Authorization"] = `Bearer ${this.auth.getToken()}`;
|
|
185
|
+
}
|
|
186
|
+
const response = await fetch(
|
|
187
|
+
this._buildApiUrl(endpoint.toString()),
|
|
188
|
+
{
|
|
189
|
+
method: "POST",
|
|
190
|
+
headers,
|
|
191
|
+
body: JSON.stringify(data),
|
|
192
|
+
signal
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
if (response.status === 401) {
|
|
196
|
+
this.auth?.onUnauthorized?.();
|
|
197
|
+
}
|
|
159
198
|
if (!response.ok) {
|
|
160
199
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
161
200
|
}
|
|
@@ -179,8 +218,64 @@ var RagbitsClient = class {
|
|
|
179
218
|
isCancelled = true;
|
|
180
219
|
};
|
|
181
220
|
}
|
|
221
|
+
normalizeHeaders(init) {
|
|
222
|
+
if (!init) return {};
|
|
223
|
+
if (init instanceof Headers) {
|
|
224
|
+
return Object.fromEntries(init.entries());
|
|
225
|
+
}
|
|
226
|
+
if (Array.isArray(init)) {
|
|
227
|
+
return Object.fromEntries(init);
|
|
228
|
+
}
|
|
229
|
+
return init;
|
|
230
|
+
}
|
|
231
|
+
async handleChunkedContent(data, callbacks) {
|
|
232
|
+
const response = data;
|
|
233
|
+
const content = response.content;
|
|
234
|
+
const {
|
|
235
|
+
content_type: contentType,
|
|
236
|
+
id,
|
|
237
|
+
chunk_index: chunkIndex,
|
|
238
|
+
total_chunks: totalChunks,
|
|
239
|
+
mime_type: mimeType,
|
|
240
|
+
data: chunkData
|
|
241
|
+
} = content;
|
|
242
|
+
if (!this.chunkQueue.has(id)) {
|
|
243
|
+
this.chunkQueue.set(id, {
|
|
244
|
+
chunks: /* @__PURE__ */ new Map(),
|
|
245
|
+
totalChunks,
|
|
246
|
+
mimeType
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
const imageInfo = this.chunkQueue.get(id);
|
|
250
|
+
imageInfo.chunks.set(chunkIndex, chunkData);
|
|
251
|
+
if (imageInfo.chunks.size !== totalChunks) return;
|
|
252
|
+
const sortedChunks = Array.from(
|
|
253
|
+
{ length: totalChunks },
|
|
254
|
+
(_, i) => imageInfo.chunks.get(i)
|
|
255
|
+
);
|
|
256
|
+
const completeBase64 = sortedChunks.join("");
|
|
257
|
+
try {
|
|
258
|
+
atob(completeBase64);
|
|
259
|
+
} catch (e) {
|
|
260
|
+
this.chunkQueue.delete(id);
|
|
261
|
+
console.error("\u274C Invalid base64 data: ", e);
|
|
262
|
+
await callbacks.onError(new Error("Error reading stream"));
|
|
263
|
+
}
|
|
264
|
+
if (contentType === ChatResponseType.Image) {
|
|
265
|
+
const completeImageResponse = {
|
|
266
|
+
type: ChatResponseType.Image,
|
|
267
|
+
content: {
|
|
268
|
+
id,
|
|
269
|
+
url: `${imageInfo.mimeType},${completeBase64}`
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
await callbacks.onMessage(completeImageResponse);
|
|
273
|
+
}
|
|
274
|
+
this.chunkQueue.delete(id);
|
|
275
|
+
}
|
|
182
276
|
};
|
|
183
277
|
export {
|
|
278
|
+
AuthType,
|
|
184
279
|
ChatResponseType,
|
|
185
280
|
FeedbackType,
|
|
186
281
|
LiveUpdateType,
|