@ragbits/api-client 0.0.2 → 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/dist/index.cjs CHANGED
@@ -20,34 +20,45 @@ 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,
26
+ LiveUpdateType: () => LiveUpdateType,
25
27
  MessageRole: () => MessageRole,
26
28
  RagbitsClient: () => RagbitsClient
27
29
  });
28
30
  module.exports = __toCommonJS(index_exports);
29
31
 
30
- // src/types.ts
31
- var MessageRole = /* @__PURE__ */ ((MessageRole2) => {
32
- MessageRole2["USER"] = "user";
33
- MessageRole2["ASSISTANT"] = "assistant";
34
- MessageRole2["SYSTEM"] = "system";
35
- return MessageRole2;
36
- })(MessageRole || {});
37
- var ChatResponseType = /* @__PURE__ */ ((ChatResponseType2) => {
38
- ChatResponseType2["MESSAGE"] = "message";
39
- ChatResponseType2["REFERENCE"] = "reference";
40
- ChatResponseType2["STATE_UPDATE"] = "state_update";
41
- ChatResponseType2["TEXT"] = "text";
42
- ChatResponseType2["MESSAGE_ID"] = "message_id";
43
- ChatResponseType2["CONVERSATION_ID"] = "conversation_id";
44
- return ChatResponseType2;
45
- })(ChatResponseType || {});
46
- var FeedbackType = /* @__PURE__ */ ((FeedbackType2) => {
47
- FeedbackType2["LIKE"] = "like";
48
- FeedbackType2["DISLIKE"] = "dislike";
49
- return FeedbackType2;
50
- })(FeedbackType || {});
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
+ };
51
62
 
52
63
  // src/index.ts
53
64
  var RagbitsClient = class {
@@ -55,7 +66,15 @@ var RagbitsClient = class {
55
66
  * @param config - Configuration object
56
67
  */
57
68
  constructor(config = {}) {
58
- this.baseUrl = config.baseUrl || "http://127.0.0.1:8000";
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
+ }
59
78
  try {
60
79
  new URL(this.baseUrl);
61
80
  } catch {
@@ -63,9 +82,6 @@ var RagbitsClient = class {
63
82
  `Invalid base URL: ${this.baseUrl}. Please provide a valid URL.`
64
83
  );
65
84
  }
66
- if (this.baseUrl.endsWith("/")) {
67
- this.baseUrl = this.baseUrl.slice(0, -1);
68
- }
69
85
  }
70
86
  /**
71
87
  * Get the base URL used by this client
@@ -85,12 +101,20 @@ var RagbitsClient = class {
85
101
  * @private
86
102
  */
87
103
  async _makeRequest(url, options = {}) {
88
- const defaultOptions = {
89
- headers: {
90
- "Content-Type": "application/json"
91
- }
104
+ const defaultHeaders = {
105
+ "Content-Type": "application/json"
106
+ };
107
+ const headers = {
108
+ ...defaultHeaders,
109
+ ...this.normalizeHeaders(options.headers)
92
110
  };
93
- const response = await fetch(url, { ...defaultOptions, ...options });
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
+ }
94
118
  if (!response.ok) {
95
119
  throw new Error(`HTTP error! status: ${response.status}`);
96
120
  }
@@ -98,7 +122,7 @@ var RagbitsClient = class {
98
122
  }
99
123
  /**
100
124
  * Method to make API requests to known endpoints only
101
- * @param endpoint - API endpoint path (must be predefined)
125
+ * @param endpoint - API endpoint path
102
126
  * @param options - Typed request options for the specific endpoint
103
127
  */
104
128
  async makeRequest(endpoint, options) {
@@ -118,25 +142,26 @@ var RagbitsClient = class {
118
142
  requestOptions.body = typeof body === "string" ? body : JSON.stringify(body);
119
143
  }
120
144
  const response = await this._makeRequest(
121
- this._buildApiUrl(endpoint),
145
+ this._buildApiUrl(endpoint.toString()),
122
146
  requestOptions
123
147
  );
124
148
  return response.json();
125
149
  }
126
150
  /**
127
151
  * Method for streaming requests to known endpoints only
128
- * @param endpoint - Streaming endpoint path (must be predefined)
152
+ * @param endpoint - Streaming endpoint path
129
153
  * @param data - Request data
130
154
  * @param callbacks - Stream callbacks
131
155
  * @param signal - Optional AbortSignal for cancelling the request
132
156
  */
133
- makeStreamRequest(endpoint, data, callbacks, signal) {
157
+ makeStreamRequest(endpoint, data, callbacks, signal, customHeaders) {
134
158
  let isCancelled = false;
135
159
  const processStream = async (response) => {
136
160
  const reader = response.body?.pipeThrough(new TextDecoderStream()).getReader();
137
161
  if (!reader) {
138
162
  throw new Error("Response body is null");
139
163
  }
164
+ let buffer = "";
140
165
  while (!isCancelled && !signal?.aborted) {
141
166
  try {
142
167
  const { value, done } = await reader.read();
@@ -144,7 +169,9 @@ var RagbitsClient = class {
144
169
  callbacks.onClose?.();
145
170
  break;
146
171
  }
147
- const lines = value.split("\n");
172
+ buffer += value;
173
+ const lines = buffer.split("\n");
174
+ buffer = lines.pop() ?? "";
148
175
  for (const line of lines) {
149
176
  if (!line.startsWith("data: ")) continue;
150
177
  try {
@@ -152,6 +179,10 @@ var RagbitsClient = class {
152
179
  const parsedData = JSON.parse(
153
180
  jsonString
154
181
  );
182
+ if (parsedData.type === ChatResponseType.ChunkedContent) {
183
+ this.handleChunkedContent(parsedData, callbacks);
184
+ continue;
185
+ }
155
186
  await callbacks.onMessage(parsedData);
156
187
  } catch (parseError) {
157
188
  console.error("Error parsing JSON:", parseError);
@@ -161,6 +192,9 @@ var RagbitsClient = class {
161
192
  }
162
193
  }
163
194
  } catch (streamError) {
195
+ if (signal?.aborted) {
196
+ return;
197
+ }
164
198
  console.error("Stream error:", streamError);
165
199
  await callbacks.onError(new Error("Error reading stream"));
166
200
  break;
@@ -169,15 +203,29 @@ var RagbitsClient = class {
169
203
  };
170
204
  const startStream = async () => {
171
205
  try {
172
- const response = await fetch(this._buildApiUrl(endpoint), {
173
- method: "POST",
174
- headers: {
175
- "Content-Type": "application/json",
176
- Accept: "text/event-stream"
177
- },
178
- body: JSON.stringify(data),
179
- signal
180
- });
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
+ }
181
229
  if (!response.ok) {
182
230
  throw new Error(`HTTP error! status: ${response.status}`);
183
231
  }
@@ -201,11 +249,68 @@ var RagbitsClient = class {
201
249
  isCancelled = true;
202
250
  };
203
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
+ }
204
307
  };
205
308
  // Annotate the CommonJS export names for ESM import in node:
206
309
  0 && (module.exports = {
310
+ AuthType,
207
311
  ChatResponseType,
208
312
  FeedbackType,
313
+ LiveUpdateType,
209
314
  MessageRole,
210
315
  RagbitsClient
211
316
  });
package/dist/index.d.ts CHANGED
@@ -1,225 +1,11 @@
1
- import { RJSFSchema } from '@rjsf/utils';
2
-
3
- /**
4
- * Message roles for chat conversations
5
- */
6
- declare enum MessageRole {
7
- USER = "user",
8
- ASSISTANT = "assistant",
9
- SYSTEM = "system"
10
- }
11
- /**
12
- * Message structure for chat conversations
13
- */
14
- interface Message {
15
- role: MessageRole;
16
- content: string;
17
- id?: string;
18
- }
19
- /**
20
- * Reference structure for document references
21
- */
22
- interface Reference {
23
- title: string;
24
- content: string;
25
- url?: string;
26
- }
27
- /**
28
- * Response types from the API
29
- */
30
- declare enum ChatResponseType {
31
- MESSAGE = "message",
32
- REFERENCE = "reference",
33
- STATE_UPDATE = "state_update",
34
- TEXT = "text",
35
- MESSAGE_ID = "message_id",
36
- CONVERSATION_ID = "conversation_id"
37
- }
38
- /**
39
- * Feedback types for user feedback
40
- */
41
- declare enum FeedbackType {
42
- LIKE = "like",
43
- DISLIKE = "dislike"
44
- }
45
- /**
46
- * Server state interface for state updates
47
- */
48
- interface ServerState {
49
- state: Record<string, unknown>;
50
- signature: string;
51
- }
52
- /**
53
- * Specific chat response types
54
- */
55
- interface MessageIdChatResponse {
56
- type: ChatResponseType.MESSAGE_ID;
57
- content: string;
58
- }
59
- interface TextChatResponse {
60
- type: ChatResponseType.TEXT;
61
- content: string;
62
- }
63
- interface ReferenceChatResponse {
64
- type: ChatResponseType.REFERENCE;
65
- content: Reference;
66
- }
67
- interface ConversationIdChatResponse {
68
- type: ChatResponseType.CONVERSATION_ID;
69
- content: string;
70
- }
71
- interface StateUpdateChatResponse {
72
- type: ChatResponseType.STATE_UPDATE;
73
- content: ServerState;
74
- }
75
- /**
76
- * Typed chat response union
77
- */
78
- type TypedChatResponse = TextChatResponse | ReferenceChatResponse | MessageIdChatResponse | ConversationIdChatResponse | StateUpdateChatResponse;
79
- /**
80
- * Base chat request to the API
81
- */
82
- interface ChatRequest {
83
- message: string;
84
- history: Message[];
85
- context?: Record<string, unknown>;
86
- }
87
- /**
88
- * Feedback request to the API
89
- */
90
- interface FeedbackRequest {
91
- message_id: string;
92
- feedback: FeedbackType;
93
- payload: Record<string, unknown> | null;
94
- }
95
- /**
96
- * Feedback response from the API
97
- */
98
- interface FeedbackResponse {
99
- status: string;
100
- }
101
- /**
102
- * UI customization configuration
103
- */
104
- interface UICustomization {
105
- header: {
106
- title?: string;
107
- subtitle?: string;
108
- logo?: string;
109
- };
110
- welcome_message?: string;
111
- }
112
- /**
113
- * Configuration response from the API
114
- */
115
- interface ConfigResponse {
116
- feedback: {
117
- like: {
118
- enabled: boolean;
119
- form: RJSFSchema | null;
120
- };
121
- dislike: {
122
- enabled: boolean;
123
- form: RJSFSchema | null;
124
- };
125
- };
126
- customization: UICustomization | null;
127
- }
128
- /**
129
- * Configuration for the client
130
- */
131
- interface ClientConfig {
132
- baseUrl?: string;
133
- }
134
- /**
135
- * Callbacks for handling streaming responses
136
- */
137
- interface StreamCallbacks<T, E = Error> {
138
- onMessage: (data: T) => void | Promise<void>;
139
- onError: (error: E) => void | Promise<void>;
140
- onClose?: () => void | Promise<void>;
141
- }
142
- /**
143
- * Regular API endpoint definitions with their request/response types
144
- */
145
- interface ApiEndpoints {
146
- '/api/config': {
147
- method: 'GET';
148
- request: never;
149
- response: ConfigResponse;
150
- };
151
- '/api/feedback': {
152
- method: 'POST';
153
- request: FeedbackRequest;
154
- response: FeedbackResponse;
155
- };
156
- }
157
- /**
158
- * Streaming API endpoint definitions with their request/stream response types
159
- */
160
- interface StreamingEndpoints {
161
- '/api/chat': {
162
- method: 'POST';
163
- request: ChatRequest;
164
- stream: TypedChatResponse;
165
- };
166
- }
167
- /**
168
- * Extract endpoint paths as a union type
169
- */
170
- type ApiEndpointPath = keyof ApiEndpoints;
171
- /**
172
- * Extract streaming endpoint paths as a union type
173
- */
174
- type StreamingEndpointPath = keyof StreamingEndpoints;
175
- /**
176
- * Extract request type for a specific API endpoint
177
- */
178
- type ApiEndpointRequest<T extends ApiEndpointPath> = ApiEndpoints[T]['request'];
179
- /**
180
- * Extract response type for a specific API endpoint
181
- */
182
- type ApiEndpointResponse<T extends ApiEndpointPath> = ApiEndpoints[T]['response'];
183
- /**
184
- * Extract HTTP method for a specific API endpoint
185
- */
186
- type ApiEndpointMethod<T extends ApiEndpointPath> = ApiEndpoints[T]['method'];
187
- /**
188
- * Extract request type for a specific streaming endpoint
189
- */
190
- type StreamingEndpointRequest<T extends StreamingEndpointPath> = StreamingEndpoints[T]['request'];
191
- /**
192
- * Extract stream response type for a specific streaming endpoint
193
- */
194
- type StreamingEndpointStream<T extends StreamingEndpointPath> = StreamingEndpoints[T]['stream'];
195
- /**
196
- * Extract HTTP method for a specific streaming endpoint
197
- */
198
- type StreamingEndpointMethod<T extends StreamingEndpointPath> = StreamingEndpoints[T]['method'];
199
- /**
200
- * Generic request options for API endpoints with typed methods and body
201
- */
202
- interface TypedApiRequestOptions<T extends ApiEndpointPath> {
203
- method?: ApiEndpointMethod<T>;
204
- body?: ApiEndpointRequest<T> extends never ? undefined : ApiEndpointRequest<T>;
205
- headers?: Record<string, string>;
206
- signal?: AbortSignal;
207
- }
208
- /**
209
- * Typed request options for specific streaming endpoints
210
- */
211
- interface TypedStreamRequestOptions<T extends StreamingEndpointPath> {
212
- method?: StreamingEndpointMethod<T>;
213
- body?: StreamingEndpointRequest<T>;
214
- headers?: Record<string, string>;
215
- signal?: AbortSignal;
216
- }
217
-
1
+ import type { ClientConfig, StreamCallbacks, BaseApiEndpoints, EndpointDefinition, EndpointResponse, RequestOptions, BaseStreamingEndpoints, EndpointRequest } from './types';
218
2
  /**
219
3
  * Client for communicating with the Ragbits API
220
4
  */
221
- declare class RagbitsClient {
5
+ export declare class RagbitsClient {
222
6
  private readonly baseUrl;
7
+ private readonly auth;
8
+ private chunkQueue;
223
9
  /**
224
10
  * @param config - Configuration object
225
11
  */
@@ -240,18 +26,24 @@ declare class RagbitsClient {
240
26
  private _makeRequest;
241
27
  /**
242
28
  * Method to make API requests to known endpoints only
243
- * @param endpoint - API endpoint path (must be predefined)
29
+ * @param endpoint - API endpoint path
244
30
  * @param options - Typed request options for the specific endpoint
245
31
  */
246
- makeRequest<T extends ApiEndpointPath>(endpoint: T, options?: TypedApiRequestOptions<T>): Promise<ApiEndpointResponse<T>>;
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>>;
247
35
  /**
248
36
  * Method for streaming requests to known endpoints only
249
- * @param endpoint - Streaming endpoint path (must be predefined)
37
+ * @param endpoint - Streaming endpoint path
250
38
  * @param data - Request data
251
39
  * @param callbacks - Stream callbacks
252
40
  * @param signal - Optional AbortSignal for cancelling the request
253
41
  */
254
- makeStreamRequest<T extends StreamingEndpointPath>(endpoint: T, data: StreamingEndpointRequest<T>, callbacks: StreamCallbacks<StreamingEndpointStream<T>>, signal?: AbortSignal): () => void;
255
- }
256
-
257
- export { type ApiEndpointMethod, type ApiEndpointPath, type ApiEndpointRequest, type ApiEndpointResponse, type ApiEndpoints, type ChatRequest, ChatResponseType, type ClientConfig, type ConfigResponse, type FeedbackRequest, type FeedbackResponse, FeedbackType, type Message, MessageRole, RagbitsClient, type Reference, type ServerState, type StreamCallbacks, type StreamingEndpointMethod, type StreamingEndpointPath, type StreamingEndpointRequest, type StreamingEndpointStream, type StreamingEndpoints, type TypedApiRequestOptions, type TypedChatResponse, type TypedStreamRequestOptions, type UICustomization };
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;
47
+ }
48
+ export * from './types';
49
+ export * from './autogen.types';