@ragbits/api-client 0.0.1 → 0.0.3
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 +252 -58
- package/dist/index.cjs +220 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +189 -0
- package/dist/types.d.ts +238 -0
- package/package.json +5 -4
- package/eslint.config.js +0 -21
- package/prettier.config.js +0 -6
- package/src/index.ts +0 -213
- package/src/test/RagbitsClient.test.ts +0 -484
- package/src/test/mocks/handlers.ts +0 -98
- package/src/test/setup.ts +0 -23
- package/src/test/types.test.ts +0 -35
- package/src/test/utils.ts +0 -28
- package/src/types.ts +0 -259
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -20
package/dist/index.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var MessageRole = /* @__PURE__ */ ((MessageRole2) => {
|
|
3
|
+
MessageRole2["USER"] = "user";
|
|
4
|
+
MessageRole2["ASSISTANT"] = "assistant";
|
|
5
|
+
MessageRole2["SYSTEM"] = "system";
|
|
6
|
+
return MessageRole2;
|
|
7
|
+
})(MessageRole || {});
|
|
8
|
+
var ChatResponseType = /* @__PURE__ */ ((ChatResponseType2) => {
|
|
9
|
+
ChatResponseType2["MESSAGE"] = "message";
|
|
10
|
+
ChatResponseType2["REFERENCE"] = "reference";
|
|
11
|
+
ChatResponseType2["STATE_UPDATE"] = "state_update";
|
|
12
|
+
ChatResponseType2["TEXT"] = "text";
|
|
13
|
+
ChatResponseType2["MESSAGE_ID"] = "message_id";
|
|
14
|
+
ChatResponseType2["CONVERSATION_ID"] = "conversation_id";
|
|
15
|
+
ChatResponseType2["LIVE_UPDATE"] = "live_update";
|
|
16
|
+
ChatResponseType2["FOLLOWUP_MESSAGES"] = "followup_messages";
|
|
17
|
+
return ChatResponseType2;
|
|
18
|
+
})(ChatResponseType || {});
|
|
19
|
+
var FeedbackType = /* @__PURE__ */ ((FeedbackType2) => {
|
|
20
|
+
FeedbackType2["LIKE"] = "like";
|
|
21
|
+
FeedbackType2["DISLIKE"] = "dislike";
|
|
22
|
+
return FeedbackType2;
|
|
23
|
+
})(FeedbackType || {});
|
|
24
|
+
var LiveUpdateType = /* @__PURE__ */ ((LiveUpdateType2) => {
|
|
25
|
+
LiveUpdateType2["START"] = "START";
|
|
26
|
+
LiveUpdateType2["FINISH"] = "FINISH";
|
|
27
|
+
return LiveUpdateType2;
|
|
28
|
+
})(LiveUpdateType || {});
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var RagbitsClient = class {
|
|
32
|
+
/**
|
|
33
|
+
* @param config - Configuration object
|
|
34
|
+
*/
|
|
35
|
+
constructor(config = {}) {
|
|
36
|
+
this.baseUrl = config.baseUrl || "http://127.0.0.1:8000";
|
|
37
|
+
try {
|
|
38
|
+
new URL(this.baseUrl);
|
|
39
|
+
} catch {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Invalid base URL: ${this.baseUrl}. Please provide a valid URL.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (this.baseUrl.endsWith("/")) {
|
|
45
|
+
this.baseUrl = this.baseUrl.slice(0, -1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the base URL used by this client
|
|
50
|
+
*/
|
|
51
|
+
getBaseUrl() {
|
|
52
|
+
return this.baseUrl;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build full API URL from path
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
_buildApiUrl(path) {
|
|
59
|
+
return `${this.baseUrl}${path}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Make a request to the API
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
async _makeRequest(url, options = {}) {
|
|
66
|
+
const defaultOptions = {
|
|
67
|
+
headers: {
|
|
68
|
+
"Content-Type": "application/json"
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const response = await fetch(url, { ...defaultOptions, ...options });
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
74
|
+
}
|
|
75
|
+
return response;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Method to make API requests to known endpoints only
|
|
79
|
+
* @param endpoint - API endpoint path (must be predefined)
|
|
80
|
+
* @param options - Typed request options for the specific endpoint
|
|
81
|
+
*/
|
|
82
|
+
async makeRequest(endpoint, options) {
|
|
83
|
+
const {
|
|
84
|
+
method = "GET",
|
|
85
|
+
body,
|
|
86
|
+
headers = {},
|
|
87
|
+
...restOptions
|
|
88
|
+
} = options || {};
|
|
89
|
+
const requestOptions = {
|
|
90
|
+
method,
|
|
91
|
+
headers,
|
|
92
|
+
...restOptions
|
|
93
|
+
// This will include signal and other fetch options
|
|
94
|
+
};
|
|
95
|
+
if (body && method !== "GET") {
|
|
96
|
+
requestOptions.body = typeof body === "string" ? body : JSON.stringify(body);
|
|
97
|
+
}
|
|
98
|
+
const response = await this._makeRequest(
|
|
99
|
+
this._buildApiUrl(endpoint),
|
|
100
|
+
requestOptions
|
|
101
|
+
);
|
|
102
|
+
return response.json();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Method for streaming requests to known endpoints only
|
|
106
|
+
* @param endpoint - Streaming endpoint path (must be predefined)
|
|
107
|
+
* @param data - Request data
|
|
108
|
+
* @param callbacks - Stream callbacks
|
|
109
|
+
* @param signal - Optional AbortSignal for cancelling the request
|
|
110
|
+
*/
|
|
111
|
+
makeStreamRequest(endpoint, data, callbacks, signal) {
|
|
112
|
+
let isCancelled = false;
|
|
113
|
+
const processStream = async (response) => {
|
|
114
|
+
const reader = response.body?.pipeThrough(new TextDecoderStream()).getReader();
|
|
115
|
+
if (!reader) {
|
|
116
|
+
throw new Error("Response body is null");
|
|
117
|
+
}
|
|
118
|
+
while (!isCancelled && !signal?.aborted) {
|
|
119
|
+
try {
|
|
120
|
+
const { value, done } = await reader.read();
|
|
121
|
+
if (done) {
|
|
122
|
+
callbacks.onClose?.();
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
const lines = value.split("\n");
|
|
126
|
+
for (const line of lines) {
|
|
127
|
+
if (!line.startsWith("data: ")) continue;
|
|
128
|
+
try {
|
|
129
|
+
const jsonString = line.replace("data: ", "").trim();
|
|
130
|
+
const parsedData = JSON.parse(
|
|
131
|
+
jsonString
|
|
132
|
+
);
|
|
133
|
+
await callbacks.onMessage(parsedData);
|
|
134
|
+
} catch (parseError) {
|
|
135
|
+
console.error("Error parsing JSON:", parseError);
|
|
136
|
+
await callbacks.onError(
|
|
137
|
+
new Error("Error processing server response")
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} catch (streamError) {
|
|
142
|
+
console.error("Stream error:", streamError);
|
|
143
|
+
await callbacks.onError(new Error("Error reading stream"));
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const startStream = async () => {
|
|
149
|
+
try {
|
|
150
|
+
const response = await fetch(this._buildApiUrl(endpoint), {
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: {
|
|
153
|
+
"Content-Type": "application/json",
|
|
154
|
+
Accept: "text/event-stream"
|
|
155
|
+
},
|
|
156
|
+
body: JSON.stringify(data),
|
|
157
|
+
signal
|
|
158
|
+
});
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
161
|
+
}
|
|
162
|
+
await processStream(response);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (signal?.aborted) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
console.error("Request error:", error);
|
|
168
|
+
const errorMessage = error instanceof Error ? error.message : "Error connecting to server";
|
|
169
|
+
await callbacks.onError(new Error(errorMessage));
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
try {
|
|
173
|
+
startStream();
|
|
174
|
+
} catch (error) {
|
|
175
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to start stream";
|
|
176
|
+
callbacks.onError(new Error(errorMessage));
|
|
177
|
+
}
|
|
178
|
+
return () => {
|
|
179
|
+
isCancelled = true;
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
export {
|
|
184
|
+
ChatResponseType,
|
|
185
|
+
FeedbackType,
|
|
186
|
+
LiveUpdateType,
|
|
187
|
+
MessageRole,
|
|
188
|
+
RagbitsClient
|
|
189
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { RJSFSchema } from '@rjsf/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Message roles for chat conversations
|
|
4
|
+
*/
|
|
5
|
+
export declare enum MessageRole {
|
|
6
|
+
USER = "user",
|
|
7
|
+
ASSISTANT = "assistant",
|
|
8
|
+
SYSTEM = "system"
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Message structure for chat conversations
|
|
12
|
+
*/
|
|
13
|
+
export interface Message {
|
|
14
|
+
role: MessageRole;
|
|
15
|
+
content: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Reference structure for document references
|
|
20
|
+
*/
|
|
21
|
+
export interface Reference {
|
|
22
|
+
title: string;
|
|
23
|
+
content: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Response types from the API
|
|
28
|
+
*/
|
|
29
|
+
export declare enum ChatResponseType {
|
|
30
|
+
MESSAGE = "message",
|
|
31
|
+
REFERENCE = "reference",
|
|
32
|
+
STATE_UPDATE = "state_update",
|
|
33
|
+
TEXT = "text",
|
|
34
|
+
MESSAGE_ID = "message_id",
|
|
35
|
+
CONVERSATION_ID = "conversation_id",
|
|
36
|
+
LIVE_UPDATE = "live_update",
|
|
37
|
+
FOLLOWUP_MESSAGES = "followup_messages"
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Feedback types for user feedback
|
|
41
|
+
*/
|
|
42
|
+
export declare enum FeedbackType {
|
|
43
|
+
LIKE = "like",
|
|
44
|
+
DISLIKE = "dislike"
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Server state interface for state updates
|
|
48
|
+
*/
|
|
49
|
+
export interface ServerState {
|
|
50
|
+
state: Record<string, unknown>;
|
|
51
|
+
signature: string;
|
|
52
|
+
}
|
|
53
|
+
export declare enum LiveUpdateType {
|
|
54
|
+
START = "START",
|
|
55
|
+
FINISH = "FINISH"
|
|
56
|
+
}
|
|
57
|
+
export interface LiveUpdate {
|
|
58
|
+
update_id: string;
|
|
59
|
+
type: LiveUpdateType;
|
|
60
|
+
content: {
|
|
61
|
+
label: string;
|
|
62
|
+
description?: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Specific chat response types
|
|
67
|
+
*/
|
|
68
|
+
interface MessageIdChatResponse {
|
|
69
|
+
type: ChatResponseType.MESSAGE_ID;
|
|
70
|
+
content: string;
|
|
71
|
+
}
|
|
72
|
+
interface TextChatResponse {
|
|
73
|
+
type: ChatResponseType.TEXT;
|
|
74
|
+
content: string;
|
|
75
|
+
}
|
|
76
|
+
interface ReferenceChatResponse {
|
|
77
|
+
type: ChatResponseType.REFERENCE;
|
|
78
|
+
content: Reference;
|
|
79
|
+
}
|
|
80
|
+
interface ConversationIdChatResponse {
|
|
81
|
+
type: ChatResponseType.CONVERSATION_ID;
|
|
82
|
+
content: string;
|
|
83
|
+
}
|
|
84
|
+
interface StateUpdateChatResponse {
|
|
85
|
+
type: ChatResponseType.STATE_UPDATE;
|
|
86
|
+
content: ServerState;
|
|
87
|
+
}
|
|
88
|
+
interface LiveUpdateChatResponse {
|
|
89
|
+
type: ChatResponseType.LIVE_UPDATE;
|
|
90
|
+
content: LiveUpdate;
|
|
91
|
+
}
|
|
92
|
+
interface FollowupMessagesChatResponse {
|
|
93
|
+
type: ChatResponseType.FOLLOWUP_MESSAGES;
|
|
94
|
+
content: string[];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Typed chat response union
|
|
98
|
+
*/
|
|
99
|
+
export type TypedChatResponse = TextChatResponse | ReferenceChatResponse | MessageIdChatResponse | ConversationIdChatResponse | StateUpdateChatResponse | LiveUpdateChatResponse | FollowupMessagesChatResponse;
|
|
100
|
+
/**
|
|
101
|
+
* Base chat request to the API
|
|
102
|
+
*/
|
|
103
|
+
export interface ChatRequest {
|
|
104
|
+
message: string;
|
|
105
|
+
history: Message[];
|
|
106
|
+
context?: Record<string, unknown>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Feedback request to the API
|
|
110
|
+
*/
|
|
111
|
+
export interface FeedbackRequest {
|
|
112
|
+
message_id: string;
|
|
113
|
+
feedback: FeedbackType;
|
|
114
|
+
payload: Record<string, unknown> | null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Feedback response from the API
|
|
118
|
+
*/
|
|
119
|
+
export interface FeedbackResponse {
|
|
120
|
+
status: string;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* UI customization configuration
|
|
124
|
+
*/
|
|
125
|
+
export interface UICustomization {
|
|
126
|
+
header: {
|
|
127
|
+
title?: string;
|
|
128
|
+
subtitle?: string;
|
|
129
|
+
logo?: string;
|
|
130
|
+
};
|
|
131
|
+
welcome_message?: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Configuration response from the API
|
|
135
|
+
*/
|
|
136
|
+
export interface ConfigResponse {
|
|
137
|
+
feedback: {
|
|
138
|
+
like: {
|
|
139
|
+
enabled: boolean;
|
|
140
|
+
form: RJSFSchema | null;
|
|
141
|
+
};
|
|
142
|
+
dislike: {
|
|
143
|
+
enabled: boolean;
|
|
144
|
+
form: RJSFSchema | null;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
customization: UICustomization | null;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Configuration for the client
|
|
151
|
+
*/
|
|
152
|
+
export interface ClientConfig {
|
|
153
|
+
baseUrl?: string;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Callbacks for handling streaming responses
|
|
157
|
+
*/
|
|
158
|
+
export interface StreamCallbacks<T, E = Error> {
|
|
159
|
+
onMessage: (data: T) => void | Promise<void>;
|
|
160
|
+
onError: (error: E) => void | Promise<void>;
|
|
161
|
+
onClose?: () => void | Promise<void>;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Regular API endpoint definitions with their request/response types
|
|
165
|
+
*/
|
|
166
|
+
export interface ApiEndpoints {
|
|
167
|
+
'/api/config': {
|
|
168
|
+
method: 'GET';
|
|
169
|
+
request: never;
|
|
170
|
+
response: ConfigResponse;
|
|
171
|
+
};
|
|
172
|
+
'/api/feedback': {
|
|
173
|
+
method: 'POST';
|
|
174
|
+
request: FeedbackRequest;
|
|
175
|
+
response: FeedbackResponse;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Streaming API endpoint definitions with their request/stream response types
|
|
180
|
+
*/
|
|
181
|
+
export interface StreamingEndpoints {
|
|
182
|
+
'/api/chat': {
|
|
183
|
+
method: 'POST';
|
|
184
|
+
request: ChatRequest;
|
|
185
|
+
stream: TypedChatResponse;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Extract endpoint paths as a union type
|
|
190
|
+
*/
|
|
191
|
+
export type ApiEndpointPath = keyof ApiEndpoints;
|
|
192
|
+
/**
|
|
193
|
+
* Extract streaming endpoint paths as a union type
|
|
194
|
+
*/
|
|
195
|
+
export type StreamingEndpointPath = keyof StreamingEndpoints;
|
|
196
|
+
/**
|
|
197
|
+
* Extract request type for a specific API endpoint
|
|
198
|
+
*/
|
|
199
|
+
export type ApiEndpointRequest<T extends ApiEndpointPath> = ApiEndpoints[T]['request'];
|
|
200
|
+
/**
|
|
201
|
+
* Extract response type for a specific API endpoint
|
|
202
|
+
*/
|
|
203
|
+
export type ApiEndpointResponse<T extends ApiEndpointPath> = ApiEndpoints[T]['response'];
|
|
204
|
+
/**
|
|
205
|
+
* Extract HTTP method for a specific API endpoint
|
|
206
|
+
*/
|
|
207
|
+
export type ApiEndpointMethod<T extends ApiEndpointPath> = ApiEndpoints[T]['method'];
|
|
208
|
+
/**
|
|
209
|
+
* Extract request type for a specific streaming endpoint
|
|
210
|
+
*/
|
|
211
|
+
export type StreamingEndpointRequest<T extends StreamingEndpointPath> = StreamingEndpoints[T]['request'];
|
|
212
|
+
/**
|
|
213
|
+
* Extract stream response type for a specific streaming endpoint
|
|
214
|
+
*/
|
|
215
|
+
export type StreamingEndpointStream<T extends StreamingEndpointPath> = StreamingEndpoints[T]['stream'];
|
|
216
|
+
/**
|
|
217
|
+
* Extract HTTP method for a specific streaming endpoint
|
|
218
|
+
*/
|
|
219
|
+
export type StreamingEndpointMethod<T extends StreamingEndpointPath> = StreamingEndpoints[T]['method'];
|
|
220
|
+
/**
|
|
221
|
+
* Generic request options for API endpoints with typed methods and body
|
|
222
|
+
*/
|
|
223
|
+
export interface TypedApiRequestOptions<T extends ApiEndpointPath> {
|
|
224
|
+
method?: ApiEndpointMethod<T>;
|
|
225
|
+
body?: ApiEndpointRequest<T> extends never ? undefined : ApiEndpointRequest<T>;
|
|
226
|
+
headers?: Record<string, string>;
|
|
227
|
+
signal?: AbortSignal;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Typed request options for specific streaming endpoints
|
|
231
|
+
*/
|
|
232
|
+
export interface TypedStreamRequestOptions<T extends StreamingEndpointPath> {
|
|
233
|
+
method?: StreamingEndpointMethod<T>;
|
|
234
|
+
body?: StreamingEndpointRequest<T>;
|
|
235
|
+
headers?: Record<string, string>;
|
|
236
|
+
signal?: AbortSignal;
|
|
237
|
+
}
|
|
238
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ragbits/api-client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "JavaScript client for the Ragbits API",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "tsup src/index.ts --format cjs,esm --
|
|
18
|
-
"dev": "
|
|
17
|
+
"build": "npm run clean && tsup src/index.ts --format cjs,esm && tsc --emitDeclarationOnly --declaration --project tsconfig.json",
|
|
18
|
+
"dev": "tsc -b . --watch",
|
|
19
19
|
"test": "vitest",
|
|
20
20
|
"test:run": "vitest run",
|
|
21
21
|
"test:coverage": "vitest run --coverage",
|
|
22
22
|
"lint": "eslint .",
|
|
23
23
|
"format": "prettier --write .",
|
|
24
|
-
"format:check": "prettier --check ."
|
|
24
|
+
"format:check": "prettier --check .",
|
|
25
|
+
"clean": "rm -rf ./dist"
|
|
25
26
|
},
|
|
26
27
|
"keywords": [
|
|
27
28
|
"ragbits",
|
package/eslint.config.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import js from '@eslint/js'
|
|
2
|
-
import globals from 'globals'
|
|
3
|
-
import tseslint from 'typescript-eslint'
|
|
4
|
-
|
|
5
|
-
export default tseslint.config(
|
|
6
|
-
{ ignores: ['dist', 'coverage'] },
|
|
7
|
-
{
|
|
8
|
-
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
9
|
-
files: ['**/*.{ts,tsx}'],
|
|
10
|
-
languageOptions: {
|
|
11
|
-
ecmaVersion: 2020,
|
|
12
|
-
globals: globals.node,
|
|
13
|
-
},
|
|
14
|
-
rules: {
|
|
15
|
-
'@typescript-eslint/no-unused-vars': [
|
|
16
|
-
'error',
|
|
17
|
-
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
|
18
|
-
],
|
|
19
|
-
},
|
|
20
|
-
}
|
|
21
|
-
)
|
package/prettier.config.js
DELETED
package/src/index.ts
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ClientConfig,
|
|
3
|
-
StreamCallbacks,
|
|
4
|
-
ApiEndpointPath,
|
|
5
|
-
ApiEndpointResponse,
|
|
6
|
-
TypedApiRequestOptions,
|
|
7
|
-
StreamingEndpointPath,
|
|
8
|
-
StreamingEndpointRequest,
|
|
9
|
-
StreamingEndpointStream,
|
|
10
|
-
} from './types'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Client for communicating with the Ragbits API
|
|
14
|
-
*/
|
|
15
|
-
export class RagbitsClient {
|
|
16
|
-
private readonly baseUrl: string
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param config - Configuration object
|
|
20
|
-
*/
|
|
21
|
-
constructor(config: ClientConfig = {}) {
|
|
22
|
-
this.baseUrl = config.baseUrl || 'http://127.0.0.1:8000'
|
|
23
|
-
|
|
24
|
-
// Validate the base URL
|
|
25
|
-
try {
|
|
26
|
-
new URL(this.baseUrl)
|
|
27
|
-
} catch {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`Invalid base URL: ${this.baseUrl}. Please provide a valid URL.`
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (this.baseUrl.endsWith('/')) {
|
|
34
|
-
this.baseUrl = this.baseUrl.slice(0, -1)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get the base URL used by this client
|
|
40
|
-
*/
|
|
41
|
-
getBaseUrl(): string {
|
|
42
|
-
return this.baseUrl
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Build full API URL from path
|
|
47
|
-
* @private
|
|
48
|
-
*/
|
|
49
|
-
private _buildApiUrl(path: string): string {
|
|
50
|
-
return `${this.baseUrl}${path}`
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Make a request to the API
|
|
55
|
-
* @private
|
|
56
|
-
*/
|
|
57
|
-
private async _makeRequest(
|
|
58
|
-
url: string,
|
|
59
|
-
options: RequestInit = {}
|
|
60
|
-
): Promise<Response> {
|
|
61
|
-
const defaultOptions: RequestInit = {
|
|
62
|
-
headers: {
|
|
63
|
-
'Content-Type': 'application/json',
|
|
64
|
-
},
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const response = await fetch(url, { ...defaultOptions, ...options })
|
|
68
|
-
if (!response.ok) {
|
|
69
|
-
throw new Error(`HTTP error! status: ${response.status}`)
|
|
70
|
-
}
|
|
71
|
-
return response
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Method to make API requests to known endpoints only
|
|
76
|
-
* @param endpoint - API endpoint path (must be predefined)
|
|
77
|
-
* @param options - Typed request options for the specific endpoint
|
|
78
|
-
*/
|
|
79
|
-
async makeRequest<T extends ApiEndpointPath>(
|
|
80
|
-
endpoint: T,
|
|
81
|
-
options?: TypedApiRequestOptions<T>
|
|
82
|
-
): Promise<ApiEndpointResponse<T>> {
|
|
83
|
-
const {
|
|
84
|
-
method = 'GET',
|
|
85
|
-
body,
|
|
86
|
-
headers = {},
|
|
87
|
-
...restOptions
|
|
88
|
-
} = options || {}
|
|
89
|
-
|
|
90
|
-
const requestOptions: RequestInit = {
|
|
91
|
-
method,
|
|
92
|
-
headers,
|
|
93
|
-
...restOptions, // This will include signal and other fetch options
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (body && method !== 'GET') {
|
|
97
|
-
requestOptions.body =
|
|
98
|
-
typeof body === 'string' ? body : JSON.stringify(body)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const response = await this._makeRequest(
|
|
102
|
-
this._buildApiUrl(endpoint),
|
|
103
|
-
requestOptions
|
|
104
|
-
)
|
|
105
|
-
return response.json()
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Method for streaming requests to known endpoints only
|
|
110
|
-
* @param endpoint - Streaming endpoint path (must be predefined)
|
|
111
|
-
* @param data - Request data
|
|
112
|
-
* @param callbacks - Stream callbacks
|
|
113
|
-
* @param signal - Optional AbortSignal for cancelling the request
|
|
114
|
-
*/
|
|
115
|
-
makeStreamRequest<T extends StreamingEndpointPath>(
|
|
116
|
-
endpoint: T,
|
|
117
|
-
data: StreamingEndpointRequest<T>,
|
|
118
|
-
callbacks: StreamCallbacks<StreamingEndpointStream<T>>,
|
|
119
|
-
signal?: AbortSignal
|
|
120
|
-
): () => void {
|
|
121
|
-
let isCancelled = false
|
|
122
|
-
|
|
123
|
-
const processStream = async (response: Response): Promise<void> => {
|
|
124
|
-
const reader = response.body
|
|
125
|
-
?.pipeThrough(new TextDecoderStream())
|
|
126
|
-
.getReader()
|
|
127
|
-
|
|
128
|
-
if (!reader) {
|
|
129
|
-
throw new Error('Response body is null')
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
while (!isCancelled && !signal?.aborted) {
|
|
133
|
-
try {
|
|
134
|
-
const { value, done } = await reader.read()
|
|
135
|
-
if (done) {
|
|
136
|
-
callbacks.onClose?.()
|
|
137
|
-
break
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const lines = value.split('\n')
|
|
141
|
-
for (const line of lines) {
|
|
142
|
-
if (!line.startsWith('data: ')) continue
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
const jsonString = line.replace('data: ', '').trim()
|
|
146
|
-
const parsedData = JSON.parse(
|
|
147
|
-
jsonString
|
|
148
|
-
) as StreamingEndpointStream<T>
|
|
149
|
-
await callbacks.onMessage(parsedData)
|
|
150
|
-
} catch (parseError) {
|
|
151
|
-
console.error('Error parsing JSON:', parseError)
|
|
152
|
-
await callbacks.onError(
|
|
153
|
-
new Error('Error processing server response')
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
} catch (streamError) {
|
|
158
|
-
console.error('Stream error:', streamError)
|
|
159
|
-
await callbacks.onError(new Error('Error reading stream'))
|
|
160
|
-
break
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const startStream = async (): Promise<void> => {
|
|
166
|
-
try {
|
|
167
|
-
const response = await fetch(this._buildApiUrl(endpoint), {
|
|
168
|
-
method: 'POST',
|
|
169
|
-
headers: {
|
|
170
|
-
'Content-Type': 'application/json',
|
|
171
|
-
Accept: 'text/event-stream',
|
|
172
|
-
},
|
|
173
|
-
body: JSON.stringify(data),
|
|
174
|
-
signal,
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
if (!response.ok) {
|
|
178
|
-
throw new Error(`HTTP error! status: ${response.status}`)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
await processStream(response)
|
|
182
|
-
} catch (error) {
|
|
183
|
-
if (signal?.aborted) {
|
|
184
|
-
return
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
console.error('Request error:', error)
|
|
188
|
-
const errorMessage =
|
|
189
|
-
error instanceof Error
|
|
190
|
-
? error.message
|
|
191
|
-
: 'Error connecting to server'
|
|
192
|
-
await callbacks.onError(new Error(errorMessage))
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
startStream()
|
|
198
|
-
} catch (error) {
|
|
199
|
-
const errorMessage =
|
|
200
|
-
error instanceof Error
|
|
201
|
-
? error.message
|
|
202
|
-
: 'Failed to start stream'
|
|
203
|
-
callbacks.onError(new Error(errorMessage))
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return () => {
|
|
207
|
-
isCancelled = true
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Re-export types
|
|
213
|
-
export * from './types'
|