@schmitech/chatbot-api 0.4.4 → 0.5.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 +125 -159
- package/api.d.ts +1 -0
- package/dist/api.cjs +2 -2
- package/dist/api.cjs.map +1 -1
- package/dist/api.mjs +217 -100
- package/dist/api.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,140 +1,74 @@
|
|
|
1
|
-
# 🤖 Chatbot API Client
|
|
1
|
+
# 🤖 ORBIT Chatbot API Client
|
|
2
2
|
|
|
3
|
-
A JavaScript
|
|
4
|
-
|
|
5
|
-
---
|
|
3
|
+
A TypeScript/JavaScript client for seamless interaction with the ORBIT server, supporting secure API key authentication, temporary key exchange, and session tracking.
|
|
6
4
|
|
|
7
5
|
## 📥 Installation
|
|
8
6
|
|
|
9
|
-
### 📍 Local Development (npm link)
|
|
10
|
-
|
|
11
|
-
Use during local development:
|
|
12
|
-
|
|
13
7
|
```bash
|
|
14
|
-
npm
|
|
15
|
-
npm link
|
|
16
|
-
|
|
17
|
-
# In your project directory
|
|
18
|
-
npm link @schmitech/chatbot-api
|
|
8
|
+
npm install @schmitech/chatbot-api
|
|
19
9
|
```
|
|
20
10
|
|
|
21
|
-
|
|
11
|
+
## ⚙️ Basic Usage
|
|
22
12
|
|
|
23
|
-
|
|
13
|
+
### Configuration
|
|
24
14
|
|
|
25
|
-
|
|
26
|
-
npm run build
|
|
27
|
-
npm install /path/to/qa-chatbot-server/api
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### 🌐 CDN Integration
|
|
15
|
+
First, configure the API client with your server details:
|
|
31
16
|
|
|
32
|
-
|
|
17
|
+
```typescript
|
|
18
|
+
import { configureApi, streamChat, initializeChatbot } from '@schmitech/chatbot-api';
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
import { configureApi, streamChat } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api/dist/api.mjs';
|
|
20
|
+
// Basic configuration
|
|
21
|
+
configureApi('https://your-api-server.com', 'your-api-key');
|
|
37
22
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
apiKey: 'your-api-key',
|
|
41
|
-
sessionId: 'your-session-id' // Optional
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
async function handleChat() {
|
|
45
|
-
for await (const response of streamChat('Hello', false)) {
|
|
46
|
-
console.log(response.text);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
</script>
|
|
23
|
+
// For enhanced security with temporary key exchange
|
|
24
|
+
await initializeChatbot('your-api-key', 'https://your-origin.com');
|
|
50
25
|
```
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
## ⚙️ Usage
|
|
55
|
-
|
|
56
|
-
### 🚨 Configuration (Required)
|
|
27
|
+
### Streaming Chat Example
|
|
57
28
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```javascript
|
|
61
|
-
import { configureApi, streamChat } from '@schmitech/chatbot-api';
|
|
62
|
-
|
|
63
|
-
configureApi({
|
|
64
|
-
apiUrl: 'https://your-api-server.com',
|
|
65
|
-
apiKey: 'your-api-key',
|
|
66
|
-
sessionId: 'your-session-id' // Optional
|
|
67
|
-
});
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### 📖 Basic Example
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
29
|
+
```typescript
|
|
73
30
|
async function chat() {
|
|
74
|
-
|
|
75
|
-
apiUrl: 'https://your-api-server.com',
|
|
76
|
-
apiKey: 'your-api-key',
|
|
77
|
-
sessionId: 'user_123_session_456' // Optional
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
for await (const response of streamChat('Hello, how can I help?', false)) {
|
|
31
|
+
for await (const response of streamChat('Hello, how can I help?', true)) {
|
|
81
32
|
console.log(response.text);
|
|
82
|
-
if (response.done)
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
chat();
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### 🎙️ Voice-enabled Example
|
|
90
|
-
|
|
91
|
-
```javascript
|
|
92
|
-
async function chatWithVoice() {
|
|
93
|
-
configureApi({
|
|
94
|
-
apiUrl: 'https://your-api-server.com',
|
|
95
|
-
apiKey: 'your-api-key',
|
|
96
|
-
sessionId: 'user_123_session_456' // Optional
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
for await (const response of streamChat('Tell me a joke', true)) {
|
|
100
|
-
if (response.type === 'audio') {
|
|
101
|
-
console.log('Received audio content');
|
|
102
|
-
} else {
|
|
103
|
-
console.log(response.text);
|
|
33
|
+
if (response.done) {
|
|
34
|
+
console.log('Chat complete!');
|
|
104
35
|
}
|
|
105
|
-
if (response.done) console.log('Chat complete!');
|
|
106
36
|
}
|
|
107
37
|
}
|
|
108
|
-
|
|
109
|
-
chatWithVoice();
|
|
110
38
|
```
|
|
111
39
|
|
|
112
|
-
---
|
|
113
|
-
|
|
114
40
|
## ⚛️ React Integration
|
|
115
41
|
|
|
116
|
-
|
|
42
|
+
Here's how to use the API in a React component:
|
|
117
43
|
|
|
118
|
-
```
|
|
119
|
-
import React, { useState } from 'react';
|
|
120
|
-
import { configureApi, streamChat } from '@schmitech/chatbot-api';
|
|
121
|
-
|
|
122
|
-
configureApi({
|
|
123
|
-
apiUrl: 'https://your-api-server.com',
|
|
124
|
-
apiKey: 'your-api-key',
|
|
125
|
-
sessionId: 'user_123_session_456' // Optional
|
|
126
|
-
});
|
|
44
|
+
```tsx
|
|
45
|
+
import React, { useState, useEffect } from 'react';
|
|
46
|
+
import { configureApi, streamChat, initializeChatbot } from '@schmitech/chatbot-api';
|
|
127
47
|
|
|
128
48
|
function ChatComponent() {
|
|
129
|
-
const [messages, setMessages] = useState([]);
|
|
49
|
+
const [messages, setMessages] = useState<Array<{ text: string; isUser: boolean }>>([]);
|
|
130
50
|
const [input, setInput] = useState('');
|
|
131
51
|
|
|
132
|
-
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
// Configure API and initialize secure key exchange
|
|
54
|
+
const setupApi = async () => {
|
|
55
|
+
try {
|
|
56
|
+
configureApi('https://your-api-server.com', 'your-api-key');
|
|
57
|
+
await initializeChatbot('your-api-key', window.location.origin);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error('Failed to initialize secure API:', error);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
setupApi();
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
133
67
|
e.preventDefault();
|
|
134
68
|
setMessages(prev => [...prev, { text: input, isUser: true }]);
|
|
135
69
|
|
|
136
70
|
let responseText = '';
|
|
137
|
-
for await (const response of streamChat(input,
|
|
71
|
+
for await (const response of streamChat(input, true)) {
|
|
138
72
|
responseText += response.text;
|
|
139
73
|
setMessages(prev => [...prev, { text: responseText, isUser: false }]);
|
|
140
74
|
if (response.done) break;
|
|
@@ -144,91 +78,123 @@ function ChatComponent() {
|
|
|
144
78
|
|
|
145
79
|
return (
|
|
146
80
|
<form onSubmit={handleSubmit}>
|
|
147
|
-
<input
|
|
81
|
+
<input
|
|
82
|
+
value={input}
|
|
83
|
+
onChange={(e) => setInput(e.target.value)}
|
|
84
|
+
placeholder="Type your message..."
|
|
85
|
+
/>
|
|
148
86
|
<button type="submit">Send</button>
|
|
149
87
|
</form>
|
|
150
88
|
);
|
|
151
89
|
}
|
|
152
|
-
|
|
153
|
-
export default ChatComponent;
|
|
154
90
|
```
|
|
155
91
|
|
|
156
|
-
---
|
|
157
|
-
|
|
158
92
|
## 📱 Mobile Usage
|
|
159
93
|
|
|
160
|
-
###
|
|
94
|
+
### React Native Example
|
|
161
95
|
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
apiUrl: 'https://your-api-server.com',
|
|
165
|
-
apiKey: 'your-api-key',
|
|
166
|
-
sessionId: 'user_123_session_456' // Optional
|
|
167
|
-
});
|
|
96
|
+
```typescript
|
|
97
|
+
import { configureApi, streamChat, initializeChatbot } from '@schmitech/chatbot-api';
|
|
168
98
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
99
|
+
// Configure API and initialize secure key exchange
|
|
100
|
+
const setupApi = async () => {
|
|
101
|
+
try {
|
|
102
|
+
configureApi('https://your-api-server.com', 'your-api-key');
|
|
103
|
+
await initializeChatbot('your-api-key', 'react-native-client');
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error('Failed to initialize secure API:', error);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
async function handleChat(message: string) {
|
|
110
|
+
for await (const response of streamChat(message, true)) {
|
|
111
|
+
// Handle streaming response
|
|
112
|
+
console.log(response.text);
|
|
113
|
+
if (response.done) {
|
|
114
|
+
console.log('Chat complete!');
|
|
115
|
+
}
|
|
172
116
|
}
|
|
173
117
|
}
|
|
174
118
|
```
|
|
175
119
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
## 📚 API Reference
|
|
120
|
+
## 🌐 CDN Integration
|
|
179
121
|
|
|
180
|
-
|
|
122
|
+
You can also use the API directly in the browser via CDN:
|
|
181
123
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
124
|
+
```html
|
|
125
|
+
<script type="module">
|
|
126
|
+
import { configureApi, streamChat, initializeChatbot } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api/dist/api.mjs';
|
|
127
|
+
|
|
128
|
+
// Configure API and initialize secure key exchange
|
|
129
|
+
const setupApi = async () => {
|
|
130
|
+
try {
|
|
131
|
+
configureApi('https://your-api-server.com', 'your-api-key');
|
|
132
|
+
await initializeChatbot('your-api-key', window.location.origin);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error('Failed to initialize secure API:', error);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
193
137
|
|
|
194
|
-
|
|
195
|
-
|
|
138
|
+
async function handleChat() {
|
|
139
|
+
for await (const response of streamChat('Hello', true)) {
|
|
140
|
+
console.log(response.text);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
</script>
|
|
196
144
|
```
|
|
197
145
|
|
|
198
|
-
|
|
146
|
+
## 📚 API Reference
|
|
199
147
|
|
|
200
|
-
|
|
201
|
-
npm pack --dry-run
|
|
202
|
-
```
|
|
148
|
+
### `configureApi(apiUrl: string, apiKey?: string, sessionId?: string)`
|
|
203
149
|
|
|
204
|
-
|
|
150
|
+
Configure the API client with server details.
|
|
205
151
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
152
|
+
| Parameter | Type | Required | Description |
|
|
153
|
+
|-----------|------|----------|-------------|
|
|
154
|
+
| `apiUrl` | string | Yes | Chatbot API server URL |
|
|
155
|
+
| `apiKey` | string | No | API key for authentication |
|
|
156
|
+
| `sessionId` | string | No | Session ID for conversation tracking |
|
|
209
157
|
|
|
210
|
-
|
|
158
|
+
### `initializeChatbot(apiKey: string, origin: string)`
|
|
211
159
|
|
|
212
|
-
|
|
213
|
-
npm publish --access public
|
|
214
|
-
```
|
|
160
|
+
Initialize secure key exchange for enhanced security.
|
|
215
161
|
|
|
216
|
-
|
|
162
|
+
| Parameter | Type | Required | Description |
|
|
163
|
+
|-----------|------|----------|-------------|
|
|
164
|
+
| `apiKey` | string | Yes | Your permanent API key |
|
|
165
|
+
| `origin` | string | Yes | The origin of your application (e.g., window.location.origin) |
|
|
217
166
|
|
|
218
|
-
|
|
167
|
+
### `streamChat(message: string, stream: boolean = true)`
|
|
219
168
|
|
|
220
|
-
|
|
169
|
+
Stream chat responses from the server.
|
|
221
170
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
171
|
+
| Parameter | Type | Default | Description |
|
|
172
|
+
|-----------|------|---------|-------------|
|
|
173
|
+
| `message` | string | - | The message to send to the chat |
|
|
174
|
+
| `stream` | boolean | true | Whether to stream the response |
|
|
175
|
+
|
|
176
|
+
Returns an AsyncGenerator that yields `StreamResponse` objects:
|
|
225
177
|
|
|
226
|
-
|
|
227
|
-
|
|
178
|
+
```typescript
|
|
179
|
+
interface StreamResponse {
|
|
180
|
+
text: string; // The text content of the response
|
|
181
|
+
done: boolean; // Whether this is the final response
|
|
182
|
+
}
|
|
228
183
|
```
|
|
229
184
|
|
|
230
|
-
|
|
185
|
+
## 🔒 Security Features
|
|
186
|
+
|
|
187
|
+
- **Temporary Key Exchange**: Permanent API keys are exchanged for temporary session keys
|
|
188
|
+
- **Origin Validation**: Server validates the origin of requests for enhanced security
|
|
189
|
+
- **Automatic Key Refresh**: Temporary keys are automatically refreshed before expiration
|
|
190
|
+
- **Request Signing**: Requests are signed for additional security
|
|
191
|
+
- **Rate Limiting**: Built-in rate limiting to prevent abuse
|
|
192
|
+
- **Session Tracking**: Secure session management for conversation continuity
|
|
231
193
|
|
|
232
|
-
|
|
194
|
+
### Security Best Practices
|
|
233
195
|
|
|
234
|
-
|
|
196
|
+
- Always use HTTPS for your API URL
|
|
197
|
+
- Keep your API key secure and never expose it in client-side code
|
|
198
|
+
- Use environment variables for sensitive configuration
|
|
199
|
+
- Implement proper error handling for authentication failures
|
|
200
|
+
- Monitor for security events using the `chatbot:auth:failed` event
|
package/api.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ interface MCPResponse {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
export declare const configureApi: (apiUrl: string, apiKey?: string | null, sessionId?: string | null) => void;
|
|
29
|
+
export declare const initializeChatbot: (permanentApiKey: string, customOrigin?: string) => Promise<void>;
|
|
29
30
|
export declare function streamChat(message: string, stream?: boolean): AsyncGenerator<StreamResponse>;
|
|
30
31
|
export declare function sendToolsRequest(tools: Array<{
|
|
31
32
|
name: string;
|
package/dist/api.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let
|
|
2
|
-
|
|
1
|
+
"use strict";var F=Object.defineProperty;var K=(t,e,n)=>e in t?F(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var M=(t,e,n)=>K(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let E=null,S=null,q=null,C=null,f=null;const _=(t,e=null,n=null)=>{if(!t||typeof t!="string")throw new Error("API URL must be a valid string");if(e!==null&&typeof e!="string")throw new Error("API key must be a valid string or null");if(n!==null&&typeof n!="string")throw new Error("Session ID must be a valid string or null");E=t,S=e,q=n},w=()=>{if(!E)throw new Error("API URL not configured. Please call configureApi() with your server URL before using any API functions.");return E},z=()=>S,L=()=>q,H=async(t,e)=>{try{const n=w(),r=await fetch(`${n}/api/v1/exchange-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t,origin:e||(typeof window<"u"?window.location.origin:"node-client")})});if(!r.ok){const i=await r.text();throw new Error(`Failed to exchange API key: ${r.status} ${i}`)}const o=await r.json();C=o.sessionId,S=o.temporaryKey,q=o.sessionId,t="";const c=o.expiresIn*.9*1e3;f&&clearTimeout(f),f=setTimeout(()=>U(),c)}catch(n){throw n}},U=async()=>{if(C)try{const t=w(),e=await fetch(`${t}/api/v1/refresh-key`,{method:"POST",headers:{"Content-Type":"application/json","X-Session-ID":C,Origin:typeof window<"u"?window.location.origin:"node-client"}});if(!e.ok){const o=await e.text();throw new Error(`Failed to refresh key: ${e.status} ${o}`)}const n=await e.json();S=n.temporaryKey,f&&clearTimeout(f);const r=n.expiresIn*.9*1e3;f=setTimeout(()=>U(),r)}catch(t){typeof window<"u"&&window.dispatchEvent(new CustomEvent("chatbot:auth:failed",{detail:t}))}},X=(t,e={})=>{t.startsWith("https:");const n=Date.now().toString(36)+Math.random().toString(36).substring(2),r=Date.now(),o={Connection:"keep-alive","X-Request-ID":n,"X-Timestamp":r.toString()};typeof window<"u"&&(o["X-Origin"]=window.location.origin,o["X-Referrer"]=document.referrer||"direct");const c=z();c&&(o["X-API-Key"]=c,typeof window<"u"&&(o["X-Signature"]=B(n,r,e.body)));const i=L();return i&&(o["X-Session-ID"]=i),{...e,headers:{...e.headers,...o}}},B=(t,e,n)=>{const r=`${t}:${e}:${n?JSON.stringify(n):""}`;return btoa(r).substring(0,16)};class G{constructor(){M(this,"requests",new Map)}canMakeRequest(e,n=20,r=6e4){const o=Date.now(),i=(this.requests.get(e)||[]).filter(g=>o-g<r);return i.length>=n?!1:(i.push(o),this.requests.set(e,i),this.requests.size>1e3&&this.cleanup(r),!0)}cleanup(e){const n=Date.now();for(const[r,o]of this.requests.entries()){const c=o.filter(i=>n-i<e);c.length===0?this.requests.delete(r):this.requests.set(r,c)}}}const Q=new G,V={config:{monitoring:{enabled:!0}},async loadConfig(){try{const t=w(),e=await fetch(`${t}/api/v1/security/config`);if(e.ok){const n=await e.json();n.monitoring&&(this.config.monitoring={...this.config.monitoring,...n.monitoring})}}catch{}},detectDevTools(){if(typeof window>"u")return!1;const t=160;return window.outerHeight-window.innerHeight>t||window.outerWidth-window.innerWidth>t},async init(){typeof window>"u"||await this.loadConfig()}};typeof window<"u"&&V.init().catch(()=>{});const Y=(t,e=!0)=>({jsonrpc:"2.0",method:"tools/call",params:{name:"chat",arguments:{messages:[{role:"user",content:t}],stream:e}},id:Date.now().toString(36)+Math.random().toString(36).substring(2)}),Z=t=>({jsonrpc:"2.0",method:"tools/call",params:{name:"tools",arguments:{tools:t}},id:Date.now().toString(36)+Math.random().toString(36).substring(2)});async function*ee(t,e=!0){var n,r,o,c,i,g,A,$,O;try{const l=L()||"anonymous";if(!Q.canMakeRequest(l,20,6e4)){yield{text:"Rate limit exceeded. Please wait a moment before sending more messages.",done:!0};return}const j=w(),D=new AbortController,J=setTimeout(()=>D.abort(),6e4),h=await fetch(`${j}/v1/chat`,{...X(j,{method:"POST",headers:{"Content-Type":"application/json",Accept:e?"text/event-stream":"application/json"},body:JSON.stringify(Y(t,e))}),signal:D.signal});if(clearTimeout(J),!h.ok){const a=await h.text();throw new Error(`Network response was not ok: ${h.status} ${a}`)}if(!e){const a=await h.json();if(a.error)throw new Error(`MCP Error: ${a.error.message}`);(c=(o=(r=(n=a.result)==null?void 0:n.output)==null?void 0:r.messages)==null?void 0:o[0])!=null&&c.content&&(yield{text:a.result.output.messages[0].content,done:!0});return}const T=(i=h.body)==null?void 0:i.getReader();if(!T)throw new Error("No reader available");const W=new TextDecoder;let u="",b="",y=!1;try{for(;;){const{done:a,value:p}=await T.read();if(a)break;const m=W.decode(p,{stream:!0});u+=m;let k=0,P;for(;(P=u.indexOf(`
|
|
2
|
+
`,k))!==-1;){const R=u.slice(k,P).trim();if(k=P+1,R&&R.startsWith("data: "))try{const x=R.slice(6).trim();if(x==="[DONE]"){yield{text:"",done:!0};return}if(!x)continue;const s=JSON.parse(x);if(s.error)throw new Error(`MCP Error: ${s.error.message}`);let d="",I=!1;if(s.result){if(s.result.type==="start")continue;if(s.result.type==="chunk"&&s.result.chunk)d=s.result.chunk.content;else if(s.result.type==="complete"&&((A=(g=s.result.output)==null?void 0:g.messages)!=null&&A[0]))if(!y)d=s.result.output.messages[0].content,I=!0;else continue}if(!d&&"response"in s&&typeof s.response=="string"&&(d=s.response),"done"in s&&s.done===!0&&(I=!0),d){const v=N(d,b);v&&(b+=v,y=!0,yield{text:v,done:I})}if(I){y||(yield{text:"",done:!0});return}}catch{}}u=u.slice(k),u.length>1e6&&(u=u.slice(-5e5))}y&&(yield{text:"",done:!0})}finally{T.releaseLock()}if(u&&u.startsWith("data: "))try{const a=u.slice(6).trim();if(a&&a!=="[DONE]"){const p=JSON.parse(a);if((O=($=p.result)==null?void 0:$.chunk)!=null&&O.content){const m=N(p.result.chunk.content,b);m&&(yield{text:m,done:!0})}}}catch{}}catch(l){l.name==="AbortError"?yield{text:"Connection timed out. Please check if the server is running.",done:!0}:l.name==="TypeError"&&l.message.includes("Failed to fetch")?yield{text:"Could not connect to the server. Please check if the server is running.",done:!0}:yield{text:`Error: ${l.message}`,done:!0}}}function N(t,e){return e&&t.length>e.length&&t.startsWith(e)?t.slice(e.length):t}async function te(t){const e=w(),n=await fetch(`${e}/v1/chat`,X(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(Z(t))}));if(!n.ok){const o=await n.text();throw new Error(`Network response was not ok: ${n.status} ${o}`)}const r=await n.json();if(r.error)throw new Error(`MCP Error: ${r.error.message}`);return r}exports.configureApi=_;exports.initializeChatbot=H;exports.sendToolsRequest=te;exports.streamChat=ee;
|
|
3
3
|
//# sourceMappingURL=api.cjs.map
|
package/dist/api.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.cjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// MCP Protocol interfaces\ninterface MCPRequest {\n jsonrpc: \"2.0\";\n method: string;\n params: {\n name: string;\n arguments: {\n messages?: Array<{\n role: string;\n content: string;\n }>;\n stream?: boolean;\n tools?: Array<{\n name: string;\n parameters: Record<string, any>;\n }>;\n };\n };\n id: string;\n}\n\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: {\n type?: \"start\" | \"chunk\" | \"complete\";\n chunk?: {\n content: string;\n };\n output?: {\n messages: Array<{\n role: string;\n content: string;\n }>;\n };\n };\n error?: {\n code: number;\n message: string;\n };\n}\n\n// Store the configured API URL, key, and session ID\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\nlet configuredSessionId: string | null = null;\n\n// Configure the API with a custom URL, API key (optional), and session ID (optional)\nexport const configureApi = (apiUrl: string, apiKey: string | null = null, sessionId: string | null = null): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (apiKey !== null && typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n configuredSessionId = sessionId;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or return null if not configured\nconst getApiKey = (): string | null => {\n return configuredApiKey;\n};\n\n// Get the configured session ID or return null if not configured\nconst getSessionId = (): string | null => {\n return configuredSessionId;\n};\n\n// Helper to get fetch options with connection pooling if available\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n \n // Use keep-alive header in browser environments\n const headers: Record<string, string> = {\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId\n };\n \n // Add API key to headers only if it exists\n const apiKey = getApiKey();\n if (apiKey) {\n headers['X-API-Key'] = apiKey;\n }\n \n // Add session ID to headers only if it exists\n const sessionId = getSessionId();\n if (sessionId) {\n headers['X-Session-ID'] = sessionId;\n }\n \n return {\n ...options,\n headers: {\n ...options.headers,\n ...headers\n }\n };\n};\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n const API_URL = getApiUrl();\n \n // Add timeout to the fetch request\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 second timeout\n\n const response = await fetch(`${API_URL}/v1/chat`, {\n ...getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n break;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n if (data.result) {\n let content = '';\n \n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n content = data.result.output.messages[0].content;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n } else if (data.result.type === 'complete') {\n yield { text: '', done: true };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing JSON chunk:', line, 'Error:', error);\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // Handle any remaining buffer\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing final JSON buffer:', buffer, 'Error:', error);\n }\n }\n } catch (error: any) {\n if (error.name === 'AbortError') {\n yield { \n text: 'Connection timed out. Please check if the server is running.', \n done: true \n };\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n yield { \n text: 'Could not connect to the server. Please check if the server is running.', \n done: true \n };\n } else {\n yield { \n text: `Error: ${error.message}`, \n done: true \n };\n }\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n if (!currentText) return incomingText;\n if (currentText.endsWith(incomingText)) return '';\n \n if (incomingText.length > currentText.length) {\n if (incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n let i = 0;\n const minLength = Math.min(currentText.length, incomingText.length);\n while (i < minLength && currentText[i] === incomingText[i]) {\n i++;\n }\n \n if (i > currentText.length / 2) {\n return incomingText.slice(i);\n }\n }\n \n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configuredSessionId","configureApi","apiUrl","apiKey","sessionId","getApiUrl","getApiKey","getSessionId","getFetchOptions","options","headers","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","API_URL","controller","timeoutId","response","errorText","data","_d","_c","_b","_a","reader","_e","decoder","buffer","currentFullText","done","value","chunk","lines","line","jsonText","content","_g","_f","newText","extractNewText","error","_i","_h","incomingText","currentText","i","minLength","sendToolsRequest"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.cjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// MCP Protocol interfaces\ninterface MCPRequest {\n jsonrpc: \"2.0\";\n method: string;\n params: {\n name: string;\n arguments: {\n messages?: Array<{\n role: string;\n content: string;\n }>;\n stream?: boolean;\n tools?: Array<{\n name: string;\n parameters: Record<string, any>;\n }>;\n };\n };\n id: string;\n}\n\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: {\n type?: \"start\" | \"chunk\" | \"complete\";\n chunk?: {\n content: string;\n };\n output?: {\n messages: Array<{\n role: string;\n content: string;\n }>;\n };\n };\n error?: {\n code: number;\n message: string;\n };\n}\n\n// Store the configured API URL, key, and session ID\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\nlet configuredSessionId: string | null = null;\n\n// Temporary key management\nlet sessionId: string | null = null;\nlet keyRefreshTimer: number | null = null;\n\n// Key Exchange Response interface\ninterface KeyExchangeResponse {\n temporaryKey: string;\n sessionId: string;\n expiresIn: number; // seconds\n expiresAt: number; // timestamp\n}\n\n// Configure the API with a custom URL, API key (optional), and session ID (optional)\nexport const configureApi = (apiUrl: string, apiKey: string | null = null, sessionId: string | null = null): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (apiKey !== null && typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n configuredSessionId = sessionId;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or return null if not configured\nconst getApiKey = (): string | null => {\n return configuredApiKey;\n};\n\n// Get the configured session ID or return null if not configured\nconst getSessionId = (): string | null => {\n return configuredSessionId;\n};\n\n// Initialize chatbot with temporary key exchange\nexport const initializeChatbot = async (permanentApiKey: string, customOrigin?: string): Promise<void> => {\n try {\n const API_URL = getApiUrl();\n \n // Exchange permanent key for temporary session key\n const response = await fetch(`${API_URL}/api/v1/exchange-key`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n apiKey: permanentApiKey,\n origin: customOrigin || (typeof window !== 'undefined' ? window.location.origin : 'node-client')\n })\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to exchange API key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Store only the temporary key and session\n sessionId = data.sessionId;\n configuredApiKey = data.temporaryKey; // Use temporary key as the main API key\n configuredSessionId = data.sessionId;\n \n // Clear permanent key from memory (security measure)\n permanentApiKey = '';\n \n // Set up auto-refresh (90% of expiry time)\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any; \n } catch (error) {\n throw error;\n }\n};\n\n// Refresh temporary key before it expires\nconst refreshTemporaryKey = async (): Promise<void> => {\n if (!sessionId) return;\n \n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/api/v1/refresh-key`, {\n method: 'POST',\n headers: { \n 'Content-Type': 'application/json',\n 'X-Session-ID': sessionId,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : 'node-client'\n }\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to refresh key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Update keys\n configuredApiKey = data.temporaryKey;\n \n // Reset timer\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any;\n } catch (error) {\n // Emit event for handling by consumer\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent('chatbot:auth:failed', { detail: error }));\n }\n }\n};\n\n// Helper to get fetch options with connection pooling and enhanced security\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment with enhanced security headers\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n const timestamp = Date.now();\n \n // Enhanced security headers\n const headers: Record<string, string> = {\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId,\n 'X-Timestamp': timestamp.toString()\n };\n \n // Add origin and referrer for security validation\n if (typeof window !== 'undefined') {\n headers['X-Origin'] = window.location.origin;\n headers['X-Referrer'] = document.referrer || 'direct';\n }\n \n // Add API key to headers only if it exists\n const apiKey = getApiKey();\n if (apiKey) {\n headers['X-API-Key'] = apiKey;\n \n // Add request signature for enhanced security\n if (typeof window !== 'undefined') {\n headers['X-Signature'] = generateRequestSignature(\n requestId,\n timestamp,\n options.body\n );\n }\n }\n \n // Add session ID to headers only if it exists\n const sessionId = getSessionId();\n if (sessionId) {\n headers['X-Session-ID'] = sessionId;\n }\n \n return {\n ...options,\n headers: {\n ...options.headers,\n ...headers\n }\n };\n};\n\n// Generate request signature for enhanced security\nconst generateRequestSignature = (\n requestId: string, \n timestamp: number, \n body?: any\n): string => {\n const payload = `${requestId}:${timestamp}:${body ? JSON.stringify(body) : ''}`;\n // Simple base64 encoding - in production, you should use HMAC\n return btoa(payload).substring(0, 16);\n};\n\n// Rate limiter implementation\nclass RateLimiter {\n private requests: Map<string, number[]> = new Map();\n \n canMakeRequest(\n identifier: string, \n maxRequests: number = 20, \n windowMs: number = 60000\n ): boolean {\n const now = Date.now();\n const userRequests = this.requests.get(identifier) || [];\n const recentRequests = userRequests.filter(time => now - time < windowMs);\n \n if (recentRequests.length >= maxRequests) {\n return false;\n }\n \n recentRequests.push(now);\n this.requests.set(identifier, recentRequests);\n \n // Cleanup old entries\n if (this.requests.size > 1000) {\n this.cleanup(windowMs);\n }\n \n return true;\n }\n \n private cleanup(windowMs: number): void {\n const now = Date.now();\n for (const [key, requests] of this.requests.entries()) {\n const recent = requests.filter(time => now - time < windowMs);\n if (recent.length === 0) {\n this.requests.delete(key);\n } else {\n this.requests.set(key, recent);\n }\n }\n }\n}\n\n// Global rate limiter instance\nconst rateLimiter = new RateLimiter();\n\n// Security monitoring (client-side)\nconst securityMonitor = {\n config: {\n monitoring: {\n enabled: true\n }\n },\n\n async loadConfig(): Promise<void> {\n try {\n const API_URL = getApiUrl();\n const response = await fetch(`${API_URL}/api/v1/security/config`);\n if (response.ok) {\n const config = await response.json();\n if (config.monitoring) {\n this.config.monitoring = {\n ...this.config.monitoring,\n ...config.monitoring\n };\n }\n }\n } catch (e) {\n // Fail silently, use default config\n }\n },\n\n detectDevTools(): boolean {\n if (typeof window === 'undefined') return false;\n const threshold = 160;\n return (window.outerHeight - window.innerHeight > threshold) || \n (window.outerWidth - window.innerWidth > threshold);\n },\n \n async init(): Promise<void> {\n if (typeof window === 'undefined') return;\n \n // Load configuration first\n await this.loadConfig();\n }\n};\n\n// Initialize security monitoring if in browser\nif (typeof window !== 'undefined') {\n securityMonitor.init().catch(() => {\n // Fail silently, security monitoring will use default config\n });\n}\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n // Check rate limiting\n const sessionIdentifier = getSessionId() || 'anonymous';\n \n if (!rateLimiter.canMakeRequest(sessionIdentifier, 20, 60000)) {\n yield { \n text: 'Rate limit exceeded. Please wait a moment before sending more messages.', \n done: true \n };\n return;\n }\n \n const API_URL = getApiUrl();\n \n // Add timeout to the fetch request\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 second timeout\n\n const response = await fetch(`${API_URL}/v1/chat`, {\n ...getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n let hasReceivedContent = false;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n \n // Process complete lines immediately as they arrive\n let lineStartIndex = 0;\n let newlineIndex;\n \n while ((newlineIndex = buffer.indexOf('\\n', lineStartIndex)) !== -1) {\n const line = buffer.slice(lineStartIndex, newlineIndex).trim();\n lineStartIndex = newlineIndex + 1;\n \n if (line && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n \n // Check for [DONE] message (legacy format)\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n return;\n }\n\n // Skip empty data lines\n if (!jsonText) {\n continue;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n // Handle errors\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n \n let content = '';\n let isDone = false;\n \n // Handle MCP protocol format\n if (data.result) {\n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n // For complete messages, only yield if we haven't received any content yet\n if (!hasReceivedContent) {\n content = data.result.output.messages[0].content;\n isDone = true;\n } else {\n // Skip the complete message if we've already received chunks\n continue;\n }\n }\n }\n \n // Handle direct server response format (from LLM clients)\n // This is what the server actually sends: { \"response\": \"...\", \"done\": false/true }\n if (!content && 'response' in data && typeof data.response === 'string') {\n content = data.response;\n }\n \n // Check for done signal in the data\n if ('done' in data && data.done === true) {\n isDone = true;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n hasReceivedContent = true;\n yield {\n text: newText,\n done: isDone\n };\n }\n }\n \n // If we received a done signal, exit\n if (isDone) {\n if (!hasReceivedContent) {\n // Yield empty response to indicate completion\n yield { text: '', done: true };\n }\n return;\n }\n } catch (parseError) {\n // Don't throw, just continue processing\n }\n }\n }\n \n // Keep remaining incomplete line in buffer\n buffer = buffer.slice(lineStartIndex);\n \n // Prevent buffer from growing too large\n if (buffer.length > 1000000) { // 1MB limit\n buffer = buffer.slice(-500000); // Keep last 500KB\n }\n }\n \n // If we exit the while loop naturally, ensure we send a done signal\n if (hasReceivedContent) {\n yield { text: '', done: true };\n }\n \n } finally {\n reader.releaseLock();\n }\n\n // Handle any remaining buffer (fallback)\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText && jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: true\n };\n }\n }\n }\n } catch (error) {\n // Fail silently for final buffer parsing\n }\n }\n \n } catch (error: any) {\n if (error.name === 'AbortError') {\n yield { \n text: 'Connection timed out. Please check if the server is running.', \n done: true \n };\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n yield { \n text: 'Could not connect to the server. Please check if the server is running.', \n done: true \n };\n } else {\n yield { \n text: `Error: ${error.message}`, \n done: true \n };\n }\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n // Simplified version - just check if we have new content at the end\n if (!currentText) return incomingText;\n \n // If incoming text is longer and starts with current text, return the new part\n if (incomingText.length > currentText.length && incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n // Otherwise return the full incoming text (fallback)\n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configuredSessionId","sessionId","keyRefreshTimer","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getSessionId","initializeChatbot","permanentApiKey","customOrigin","API_URL","response","errorText","data","refreshInterval","refreshTemporaryKey","error","getFetchOptions","options","requestId","timestamp","headers","generateRequestSignature","body","payload","RateLimiter","__publicField","identifier","maxRequests","windowMs","now","recentRequests","time","key","requests","recent","rateLimiter","securityMonitor","config","threshold","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","sessionIdentifier","controller","timeoutId","_d","_c","_b","_a","reader","_e","decoder","buffer","currentFullText","hasReceivedContent","done","value","chunk","lineStartIndex","newlineIndex","line","jsonText","content","isDone","_g","_f","newText","extractNewText","_i","_h","incomingText","currentText","sendToolsRequest"],"mappings":"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"}
|
package/dist/api.mjs
CHANGED
|
@@ -1,32 +1,135 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
var F = Object.defineProperty;
|
|
2
|
+
var K = (t, e, n) => e in t ? F(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n;
|
|
3
|
+
var N = (t, e, n) => K(t, typeof e != "symbol" ? e + "" : e, n);
|
|
4
|
+
let v = null, S = null, q = null, $ = null, f = null;
|
|
5
|
+
const Z = (t, e = null, n = null) => {
|
|
3
6
|
if (!t || typeof t != "string")
|
|
4
7
|
throw new Error("API URL must be a valid string");
|
|
5
8
|
if (e !== null && typeof e != "string")
|
|
6
9
|
throw new Error("API key must be a valid string or null");
|
|
7
|
-
if (
|
|
10
|
+
if (n !== null && typeof n != "string")
|
|
8
11
|
throw new Error("Session ID must be a valid string or null");
|
|
9
|
-
|
|
10
|
-
},
|
|
11
|
-
if (!
|
|
12
|
+
v = t, S = e, q = n;
|
|
13
|
+
}, w = () => {
|
|
14
|
+
if (!v)
|
|
12
15
|
throw new Error("API URL not configured. Please call configureApi() with your server URL before using any API functions.");
|
|
13
|
-
return
|
|
14
|
-
},
|
|
16
|
+
return v;
|
|
17
|
+
}, _ = () => S, M = () => q, ee = async (t, e) => {
|
|
18
|
+
try {
|
|
19
|
+
const n = w(), r = await fetch(`${n}/api/v1/exchange-key`, {
|
|
20
|
+
method: "POST",
|
|
21
|
+
headers: { "Content-Type": "application/json" },
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
apiKey: t,
|
|
24
|
+
origin: e || (typeof window < "u" ? window.location.origin : "node-client")
|
|
25
|
+
})
|
|
26
|
+
});
|
|
27
|
+
if (!r.ok) {
|
|
28
|
+
const i = await r.text();
|
|
29
|
+
throw new Error(`Failed to exchange API key: ${r.status} ${i}`);
|
|
30
|
+
}
|
|
31
|
+
const o = await r.json();
|
|
32
|
+
$ = o.sessionId, S = o.temporaryKey, q = o.sessionId, t = "";
|
|
33
|
+
const c = o.expiresIn * 0.9 * 1e3;
|
|
34
|
+
f && clearTimeout(f), f = setTimeout(() => U(), c);
|
|
35
|
+
} catch (n) {
|
|
36
|
+
throw n;
|
|
37
|
+
}
|
|
38
|
+
}, U = async () => {
|
|
39
|
+
if ($)
|
|
40
|
+
try {
|
|
41
|
+
const t = w(), e = await fetch(`${t}/api/v1/refresh-key`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
"X-Session-ID": $,
|
|
46
|
+
Origin: typeof window < "u" ? window.location.origin : "node-client"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
if (!e.ok) {
|
|
50
|
+
const o = await e.text();
|
|
51
|
+
throw new Error(`Failed to refresh key: ${e.status} ${o}`);
|
|
52
|
+
}
|
|
53
|
+
const n = await e.json();
|
|
54
|
+
S = n.temporaryKey, f && clearTimeout(f);
|
|
55
|
+
const r = n.expiresIn * 0.9 * 1e3;
|
|
56
|
+
f = setTimeout(() => U(), r);
|
|
57
|
+
} catch (t) {
|
|
58
|
+
typeof window < "u" && window.dispatchEvent(new CustomEvent("chatbot:auth:failed", { detail: t }));
|
|
59
|
+
}
|
|
60
|
+
}, X = (t, e = {}) => {
|
|
15
61
|
t.startsWith("https:");
|
|
16
|
-
const o = {
|
|
62
|
+
const n = Date.now().toString(36) + Math.random().toString(36).substring(2), r = Date.now(), o = {
|
|
17
63
|
Connection: "keep-alive",
|
|
18
|
-
"X-Request-ID":
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
64
|
+
"X-Request-ID": n,
|
|
65
|
+
"X-Timestamp": r.toString()
|
|
66
|
+
};
|
|
67
|
+
typeof window < "u" && (o["X-Origin"] = window.location.origin, o["X-Referrer"] = document.referrer || "direct");
|
|
68
|
+
const c = _();
|
|
69
|
+
c && (o["X-API-Key"] = c, typeof window < "u" && (o["X-Signature"] = z(
|
|
70
|
+
n,
|
|
71
|
+
r,
|
|
72
|
+
e.body
|
|
73
|
+
)));
|
|
74
|
+
const i = M();
|
|
75
|
+
return i && (o["X-Session-ID"] = i), {
|
|
23
76
|
...e,
|
|
24
77
|
headers: {
|
|
25
78
|
...e.headers,
|
|
26
79
|
...o
|
|
27
80
|
}
|
|
28
81
|
};
|
|
29
|
-
},
|
|
82
|
+
}, z = (t, e, n) => {
|
|
83
|
+
const r = `${t}:${e}:${n ? JSON.stringify(n) : ""}`;
|
|
84
|
+
return btoa(r).substring(0, 16);
|
|
85
|
+
};
|
|
86
|
+
class H {
|
|
87
|
+
constructor() {
|
|
88
|
+
N(this, "requests", /* @__PURE__ */ new Map());
|
|
89
|
+
}
|
|
90
|
+
canMakeRequest(e, n = 20, r = 6e4) {
|
|
91
|
+
const o = Date.now(), i = (this.requests.get(e) || []).filter((g) => o - g < r);
|
|
92
|
+
return i.length >= n ? !1 : (i.push(o), this.requests.set(e, i), this.requests.size > 1e3 && this.cleanup(r), !0);
|
|
93
|
+
}
|
|
94
|
+
cleanup(e) {
|
|
95
|
+
const n = Date.now();
|
|
96
|
+
for (const [r, o] of this.requests.entries()) {
|
|
97
|
+
const c = o.filter((i) => n - i < e);
|
|
98
|
+
c.length === 0 ? this.requests.delete(r) : this.requests.set(r, c);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const B = new H(), G = {
|
|
103
|
+
config: {
|
|
104
|
+
monitoring: {
|
|
105
|
+
enabled: !0
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
async loadConfig() {
|
|
109
|
+
try {
|
|
110
|
+
const t = w(), e = await fetch(`${t}/api/v1/security/config`);
|
|
111
|
+
if (e.ok) {
|
|
112
|
+
const n = await e.json();
|
|
113
|
+
n.monitoring && (this.config.monitoring = {
|
|
114
|
+
...this.config.monitoring,
|
|
115
|
+
...n.monitoring
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
detectDevTools() {
|
|
122
|
+
if (typeof window > "u") return !1;
|
|
123
|
+
const t = 160;
|
|
124
|
+
return window.outerHeight - window.innerHeight > t || window.outerWidth - window.innerWidth > t;
|
|
125
|
+
},
|
|
126
|
+
async init() {
|
|
127
|
+
typeof window > "u" || await this.loadConfig();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
typeof window < "u" && G.init().catch(() => {
|
|
131
|
+
});
|
|
132
|
+
const Q = (t, e = !0) => ({
|
|
30
133
|
jsonrpc: "2.0",
|
|
31
134
|
method: "tools/call",
|
|
32
135
|
params: {
|
|
@@ -39,7 +142,7 @@ const J = (t, e = null, r = null) => {
|
|
|
39
142
|
}
|
|
40
143
|
},
|
|
41
144
|
id: Date.now().toString(36) + Math.random().toString(36).substring(2)
|
|
42
|
-
}),
|
|
145
|
+
}), V = (t) => ({
|
|
43
146
|
jsonrpc: "2.0",
|
|
44
147
|
method: "tools/call",
|
|
45
148
|
params: {
|
|
@@ -50,139 +153,153 @@ const J = (t, e = null, r = null) => {
|
|
|
50
153
|
},
|
|
51
154
|
id: Date.now().toString(36) + Math.random().toString(36).substring(2)
|
|
52
155
|
});
|
|
53
|
-
async function*
|
|
54
|
-
var r, o,
|
|
156
|
+
async function* te(t, e = !0) {
|
|
157
|
+
var n, r, o, c, i, g, A, C, O;
|
|
55
158
|
try {
|
|
56
|
-
const
|
|
57
|
-
|
|
159
|
+
const l = M() || "anonymous";
|
|
160
|
+
if (!B.canMakeRequest(l, 20, 6e4)) {
|
|
161
|
+
yield {
|
|
162
|
+
text: "Rate limit exceeded. Please wait a moment before sending more messages.",
|
|
163
|
+
done: !0
|
|
164
|
+
};
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const D = w(), j = new AbortController(), J = setTimeout(() => j.abort(), 6e4), h = await fetch(`${D}/v1/chat`, {
|
|
168
|
+
...X(D, {
|
|
58
169
|
method: "POST",
|
|
59
170
|
headers: {
|
|
60
171
|
"Content-Type": "application/json",
|
|
61
172
|
Accept: e ? "text/event-stream" : "application/json"
|
|
62
173
|
},
|
|
63
|
-
body: JSON.stringify(
|
|
174
|
+
body: JSON.stringify(Q(t, e))
|
|
64
175
|
}),
|
|
65
|
-
signal:
|
|
176
|
+
signal: j.signal
|
|
66
177
|
});
|
|
67
|
-
if (clearTimeout(
|
|
68
|
-
const
|
|
69
|
-
throw new Error(`Network response was not ok: ${
|
|
178
|
+
if (clearTimeout(J), !h.ok) {
|
|
179
|
+
const a = await h.text();
|
|
180
|
+
throw new Error(`Network response was not ok: ${h.status} ${a}`);
|
|
70
181
|
}
|
|
71
182
|
if (!e) {
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
74
|
-
throw new Error(`MCP Error: ${
|
|
75
|
-
(c = (
|
|
76
|
-
text:
|
|
183
|
+
const a = await h.json();
|
|
184
|
+
if (a.error)
|
|
185
|
+
throw new Error(`MCP Error: ${a.error.message}`);
|
|
186
|
+
(c = (o = (r = (n = a.result) == null ? void 0 : n.output) == null ? void 0 : r.messages) == null ? void 0 : o[0]) != null && c.content && (yield {
|
|
187
|
+
text: a.result.output.messages[0].content,
|
|
77
188
|
done: !0
|
|
78
189
|
});
|
|
79
190
|
return;
|
|
80
191
|
}
|
|
81
|
-
const
|
|
82
|
-
if (!
|
|
83
|
-
const
|
|
84
|
-
let
|
|
192
|
+
const T = (i = h.body) == null ? void 0 : i.getReader();
|
|
193
|
+
if (!T) throw new Error("No reader available");
|
|
194
|
+
const W = new TextDecoder();
|
|
195
|
+
let u = "", P = "", p = !1;
|
|
85
196
|
try {
|
|
86
197
|
for (; ; ) {
|
|
87
|
-
const { done:
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
198
|
+
const { done: a, value: y } = await T.read();
|
|
199
|
+
if (a)
|
|
200
|
+
break;
|
|
201
|
+
const m = W.decode(y, { stream: !0 });
|
|
202
|
+
u += m;
|
|
203
|
+
let k = 0, R;
|
|
204
|
+
for (; (R = u.indexOf(`
|
|
205
|
+
`, k)) !== -1; ) {
|
|
206
|
+
const b = u.slice(k, R).trim();
|
|
207
|
+
if (k = R + 1, b && b.startsWith("data: "))
|
|
96
208
|
try {
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
209
|
+
const x = b.slice(6).trim();
|
|
210
|
+
if (x === "[DONE]") {
|
|
99
211
|
yield { text: "", done: !0 };
|
|
100
|
-
|
|
212
|
+
return;
|
|
101
213
|
}
|
|
102
|
-
|
|
214
|
+
if (!x)
|
|
215
|
+
continue;
|
|
216
|
+
const s = JSON.parse(x);
|
|
217
|
+
if (s.error)
|
|
218
|
+
throw new Error(`MCP Error: ${s.error.message}`);
|
|
219
|
+
let d = "", I = !1;
|
|
103
220
|
if (s.result) {
|
|
104
|
-
let g = "";
|
|
105
221
|
if (s.result.type === "start")
|
|
106
222
|
continue;
|
|
107
|
-
if (s.result.type === "chunk" && s.result.chunk
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
223
|
+
if (s.result.type === "chunk" && s.result.chunk)
|
|
224
|
+
d = s.result.chunk.content;
|
|
225
|
+
else if (s.result.type === "complete" && ((A = (g = s.result.output) == null ? void 0 : g.messages) != null && A[0]))
|
|
226
|
+
if (!p)
|
|
227
|
+
d = s.result.output.messages[0].content, I = !0;
|
|
228
|
+
else
|
|
229
|
+
continue;
|
|
114
230
|
}
|
|
115
|
-
|
|
116
|
-
|
|
231
|
+
if (!d && "response" in s && typeof s.response == "string" && (d = s.response), "done" in s && s.done === !0 && (I = !0), d) {
|
|
232
|
+
const E = L(d, P);
|
|
233
|
+
E && (P += E, p = !0, yield {
|
|
234
|
+
text: E,
|
|
235
|
+
done: I
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
if (I) {
|
|
239
|
+
p || (yield { text: "", done: !0 });
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
} catch {
|
|
117
243
|
}
|
|
244
|
+
}
|
|
245
|
+
u = u.slice(k), u.length > 1e6 && (u = u.slice(-5e5));
|
|
118
246
|
}
|
|
247
|
+
p && (yield { text: "", done: !0 });
|
|
119
248
|
} finally {
|
|
120
|
-
|
|
249
|
+
T.releaseLock();
|
|
121
250
|
}
|
|
122
|
-
if (
|
|
251
|
+
if (u && u.startsWith("data: "))
|
|
123
252
|
try {
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
const
|
|
127
|
-
if ((
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
text:
|
|
131
|
-
done:
|
|
253
|
+
const a = u.slice(6).trim();
|
|
254
|
+
if (a && a !== "[DONE]") {
|
|
255
|
+
const y = JSON.parse(a);
|
|
256
|
+
if ((O = (C = y.result) == null ? void 0 : C.chunk) != null && O.content) {
|
|
257
|
+
const m = L(y.result.chunk.content, P);
|
|
258
|
+
m && (yield {
|
|
259
|
+
text: m,
|
|
260
|
+
done: !0
|
|
132
261
|
});
|
|
133
262
|
}
|
|
134
263
|
}
|
|
135
|
-
} catch
|
|
136
|
-
console.warn("Error parsing final JSON buffer:", l, "Error:", n);
|
|
264
|
+
} catch {
|
|
137
265
|
}
|
|
138
|
-
} catch (
|
|
139
|
-
|
|
266
|
+
} catch (l) {
|
|
267
|
+
l.name === "AbortError" ? yield {
|
|
140
268
|
text: "Connection timed out. Please check if the server is running.",
|
|
141
269
|
done: !0
|
|
142
|
-
} :
|
|
270
|
+
} : l.name === "TypeError" && l.message.includes("Failed to fetch") ? yield {
|
|
143
271
|
text: "Could not connect to the server. Please check if the server is running.",
|
|
144
272
|
done: !0
|
|
145
273
|
} : yield {
|
|
146
|
-
text: `Error: ${
|
|
274
|
+
text: `Error: ${l.message}`,
|
|
147
275
|
done: !0
|
|
148
276
|
};
|
|
149
277
|
}
|
|
150
278
|
}
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
if (e.endsWith(t)) return "";
|
|
154
|
-
if (t.length > e.length) {
|
|
155
|
-
if (t.startsWith(e))
|
|
156
|
-
return t.slice(e.length);
|
|
157
|
-
let r = 0;
|
|
158
|
-
const o = Math.min(e.length, t.length);
|
|
159
|
-
for (; r < o && e[r] === t[r]; )
|
|
160
|
-
r++;
|
|
161
|
-
if (r > e.length / 2)
|
|
162
|
-
return t.slice(r);
|
|
163
|
-
}
|
|
164
|
-
return t;
|
|
279
|
+
function L(t, e) {
|
|
280
|
+
return e && t.length > e.length && t.startsWith(e) ? t.slice(e.length) : t;
|
|
165
281
|
}
|
|
166
|
-
async function
|
|
167
|
-
const e =
|
|
282
|
+
async function ne(t) {
|
|
283
|
+
const e = w(), n = await fetch(`${e}/v1/chat`, X(e, {
|
|
168
284
|
method: "POST",
|
|
169
285
|
headers: {
|
|
170
286
|
"Content-Type": "application/json"
|
|
171
287
|
},
|
|
172
|
-
body: JSON.stringify(
|
|
288
|
+
body: JSON.stringify(V(t))
|
|
173
289
|
}));
|
|
174
|
-
if (!
|
|
175
|
-
const
|
|
176
|
-
throw new Error(`Network response was not ok: ${
|
|
290
|
+
if (!n.ok) {
|
|
291
|
+
const o = await n.text();
|
|
292
|
+
throw new Error(`Network response was not ok: ${n.status} ${o}`);
|
|
177
293
|
}
|
|
178
|
-
const
|
|
179
|
-
if (
|
|
180
|
-
throw new Error(`MCP Error: ${
|
|
181
|
-
return
|
|
294
|
+
const r = await n.json();
|
|
295
|
+
if (r.error)
|
|
296
|
+
throw new Error(`MCP Error: ${r.error.message}`);
|
|
297
|
+
return r;
|
|
182
298
|
}
|
|
183
299
|
export {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
300
|
+
Z as configureApi,
|
|
301
|
+
ee as initializeChatbot,
|
|
302
|
+
ne as sendToolsRequest,
|
|
303
|
+
te as streamChat
|
|
187
304
|
};
|
|
188
305
|
//# sourceMappingURL=api.mjs.map
|
package/dist/api.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.mjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// MCP Protocol interfaces\ninterface MCPRequest {\n jsonrpc: \"2.0\";\n method: string;\n params: {\n name: string;\n arguments: {\n messages?: Array<{\n role: string;\n content: string;\n }>;\n stream?: boolean;\n tools?: Array<{\n name: string;\n parameters: Record<string, any>;\n }>;\n };\n };\n id: string;\n}\n\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: {\n type?: \"start\" | \"chunk\" | \"complete\";\n chunk?: {\n content: string;\n };\n output?: {\n messages: Array<{\n role: string;\n content: string;\n }>;\n };\n };\n error?: {\n code: number;\n message: string;\n };\n}\n\n// Store the configured API URL, key, and session ID\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\nlet configuredSessionId: string | null = null;\n\n// Configure the API with a custom URL, API key (optional), and session ID (optional)\nexport const configureApi = (apiUrl: string, apiKey: string | null = null, sessionId: string | null = null): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (apiKey !== null && typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n configuredSessionId = sessionId;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or return null if not configured\nconst getApiKey = (): string | null => {\n return configuredApiKey;\n};\n\n// Get the configured session ID or return null if not configured\nconst getSessionId = (): string | null => {\n return configuredSessionId;\n};\n\n// Helper to get fetch options with connection pooling if available\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n \n // Use keep-alive header in browser environments\n const headers: Record<string, string> = {\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId\n };\n \n // Add API key to headers only if it exists\n const apiKey = getApiKey();\n if (apiKey) {\n headers['X-API-Key'] = apiKey;\n }\n \n // Add session ID to headers only if it exists\n const sessionId = getSessionId();\n if (sessionId) {\n headers['X-Session-ID'] = sessionId;\n }\n \n return {\n ...options,\n headers: {\n ...options.headers,\n ...headers\n }\n };\n};\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n const API_URL = getApiUrl();\n \n // Add timeout to the fetch request\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 second timeout\n\n const response = await fetch(`${API_URL}/v1/chat`, {\n ...getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n break;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n if (data.result) {\n let content = '';\n \n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n content = data.result.output.messages[0].content;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n } else if (data.result.type === 'complete') {\n yield { text: '', done: true };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing JSON chunk:', line, 'Error:', error);\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // Handle any remaining buffer\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing final JSON buffer:', buffer, 'Error:', error);\n }\n }\n } catch (error: any) {\n if (error.name === 'AbortError') {\n yield { \n text: 'Connection timed out. Please check if the server is running.', \n done: true \n };\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n yield { \n text: 'Could not connect to the server. Please check if the server is running.', \n done: true \n };\n } else {\n yield { \n text: `Error: ${error.message}`, \n done: true \n };\n }\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n if (!currentText) return incomingText;\n if (currentText.endsWith(incomingText)) return '';\n \n if (incomingText.length > currentText.length) {\n if (incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n let i = 0;\n const minLength = Math.min(currentText.length, incomingText.length);\n while (i < minLength && currentText[i] === incomingText[i]) {\n i++;\n }\n \n if (i > currentText.length / 2) {\n return incomingText.slice(i);\n }\n }\n \n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configuredSessionId","configureApi","apiUrl","apiKey","sessionId","getApiUrl","getApiKey","getSessionId","getFetchOptions","options","headers","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","_a","_b","_c","_d","_e","_f","_g","_h","_i","API_URL","controller","timeoutId","response","errorText","data","reader","decoder","buffer","currentFullText","done","value","chunk","lines","line","jsonText","content","newText","extractNewText","error","incomingText","currentText","i","minLength","sendToolsRequest"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.mjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// MCP Protocol interfaces\ninterface MCPRequest {\n jsonrpc: \"2.0\";\n method: string;\n params: {\n name: string;\n arguments: {\n messages?: Array<{\n role: string;\n content: string;\n }>;\n stream?: boolean;\n tools?: Array<{\n name: string;\n parameters: Record<string, any>;\n }>;\n };\n };\n id: string;\n}\n\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: {\n type?: \"start\" | \"chunk\" | \"complete\";\n chunk?: {\n content: string;\n };\n output?: {\n messages: Array<{\n role: string;\n content: string;\n }>;\n };\n };\n error?: {\n code: number;\n message: string;\n };\n}\n\n// Store the configured API URL, key, and session ID\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\nlet configuredSessionId: string | null = null;\n\n// Temporary key management\nlet sessionId: string | null = null;\nlet keyRefreshTimer: number | null = null;\n\n// Key Exchange Response interface\ninterface KeyExchangeResponse {\n temporaryKey: string;\n sessionId: string;\n expiresIn: number; // seconds\n expiresAt: number; // timestamp\n}\n\n// Configure the API with a custom URL, API key (optional), and session ID (optional)\nexport const configureApi = (apiUrl: string, apiKey: string | null = null, sessionId: string | null = null): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (apiKey !== null && typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n configuredSessionId = sessionId;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or return null if not configured\nconst getApiKey = (): string | null => {\n return configuredApiKey;\n};\n\n// Get the configured session ID or return null if not configured\nconst getSessionId = (): string | null => {\n return configuredSessionId;\n};\n\n// Initialize chatbot with temporary key exchange\nexport const initializeChatbot = async (permanentApiKey: string, customOrigin?: string): Promise<void> => {\n try {\n const API_URL = getApiUrl();\n \n // Exchange permanent key for temporary session key\n const response = await fetch(`${API_URL}/api/v1/exchange-key`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n apiKey: permanentApiKey,\n origin: customOrigin || (typeof window !== 'undefined' ? window.location.origin : 'node-client')\n })\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to exchange API key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Store only the temporary key and session\n sessionId = data.sessionId;\n configuredApiKey = data.temporaryKey; // Use temporary key as the main API key\n configuredSessionId = data.sessionId;\n \n // Clear permanent key from memory (security measure)\n permanentApiKey = '';\n \n // Set up auto-refresh (90% of expiry time)\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any; \n } catch (error) {\n throw error;\n }\n};\n\n// Refresh temporary key before it expires\nconst refreshTemporaryKey = async (): Promise<void> => {\n if (!sessionId) return;\n \n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/api/v1/refresh-key`, {\n method: 'POST',\n headers: { \n 'Content-Type': 'application/json',\n 'X-Session-ID': sessionId,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : 'node-client'\n }\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to refresh key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Update keys\n configuredApiKey = data.temporaryKey;\n \n // Reset timer\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any;\n } catch (error) {\n // Emit event for handling by consumer\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent('chatbot:auth:failed', { detail: error }));\n }\n }\n};\n\n// Helper to get fetch options with connection pooling and enhanced security\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment with enhanced security headers\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n const timestamp = Date.now();\n \n // Enhanced security headers\n const headers: Record<string, string> = {\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId,\n 'X-Timestamp': timestamp.toString()\n };\n \n // Add origin and referrer for security validation\n if (typeof window !== 'undefined') {\n headers['X-Origin'] = window.location.origin;\n headers['X-Referrer'] = document.referrer || 'direct';\n }\n \n // Add API key to headers only if it exists\n const apiKey = getApiKey();\n if (apiKey) {\n headers['X-API-Key'] = apiKey;\n \n // Add request signature for enhanced security\n if (typeof window !== 'undefined') {\n headers['X-Signature'] = generateRequestSignature(\n requestId,\n timestamp,\n options.body\n );\n }\n }\n \n // Add session ID to headers only if it exists\n const sessionId = getSessionId();\n if (sessionId) {\n headers['X-Session-ID'] = sessionId;\n }\n \n return {\n ...options,\n headers: {\n ...options.headers,\n ...headers\n }\n };\n};\n\n// Generate request signature for enhanced security\nconst generateRequestSignature = (\n requestId: string, \n timestamp: number, \n body?: any\n): string => {\n const payload = `${requestId}:${timestamp}:${body ? JSON.stringify(body) : ''}`;\n // Simple base64 encoding - in production, you should use HMAC\n return btoa(payload).substring(0, 16);\n};\n\n// Rate limiter implementation\nclass RateLimiter {\n private requests: Map<string, number[]> = new Map();\n \n canMakeRequest(\n identifier: string, \n maxRequests: number = 20, \n windowMs: number = 60000\n ): boolean {\n const now = Date.now();\n const userRequests = this.requests.get(identifier) || [];\n const recentRequests = userRequests.filter(time => now - time < windowMs);\n \n if (recentRequests.length >= maxRequests) {\n return false;\n }\n \n recentRequests.push(now);\n this.requests.set(identifier, recentRequests);\n \n // Cleanup old entries\n if (this.requests.size > 1000) {\n this.cleanup(windowMs);\n }\n \n return true;\n }\n \n private cleanup(windowMs: number): void {\n const now = Date.now();\n for (const [key, requests] of this.requests.entries()) {\n const recent = requests.filter(time => now - time < windowMs);\n if (recent.length === 0) {\n this.requests.delete(key);\n } else {\n this.requests.set(key, recent);\n }\n }\n }\n}\n\n// Global rate limiter instance\nconst rateLimiter = new RateLimiter();\n\n// Security monitoring (client-side)\nconst securityMonitor = {\n config: {\n monitoring: {\n enabled: true\n }\n },\n\n async loadConfig(): Promise<void> {\n try {\n const API_URL = getApiUrl();\n const response = await fetch(`${API_URL}/api/v1/security/config`);\n if (response.ok) {\n const config = await response.json();\n if (config.monitoring) {\n this.config.monitoring = {\n ...this.config.monitoring,\n ...config.monitoring\n };\n }\n }\n } catch (e) {\n // Fail silently, use default config\n }\n },\n\n detectDevTools(): boolean {\n if (typeof window === 'undefined') return false;\n const threshold = 160;\n return (window.outerHeight - window.innerHeight > threshold) || \n (window.outerWidth - window.innerWidth > threshold);\n },\n \n async init(): Promise<void> {\n if (typeof window === 'undefined') return;\n \n // Load configuration first\n await this.loadConfig();\n }\n};\n\n// Initialize security monitoring if in browser\nif (typeof window !== 'undefined') {\n securityMonitor.init().catch(() => {\n // Fail silently, security monitoring will use default config\n });\n}\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n // Check rate limiting\n const sessionIdentifier = getSessionId() || 'anonymous';\n \n if (!rateLimiter.canMakeRequest(sessionIdentifier, 20, 60000)) {\n yield { \n text: 'Rate limit exceeded. Please wait a moment before sending more messages.', \n done: true \n };\n return;\n }\n \n const API_URL = getApiUrl();\n \n // Add timeout to the fetch request\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 second timeout\n\n const response = await fetch(`${API_URL}/v1/chat`, {\n ...getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n let hasReceivedContent = false;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n \n // Process complete lines immediately as they arrive\n let lineStartIndex = 0;\n let newlineIndex;\n \n while ((newlineIndex = buffer.indexOf('\\n', lineStartIndex)) !== -1) {\n const line = buffer.slice(lineStartIndex, newlineIndex).trim();\n lineStartIndex = newlineIndex + 1;\n \n if (line && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n \n // Check for [DONE] message (legacy format)\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n return;\n }\n\n // Skip empty data lines\n if (!jsonText) {\n continue;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n // Handle errors\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n \n let content = '';\n let isDone = false;\n \n // Handle MCP protocol format\n if (data.result) {\n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n // For complete messages, only yield if we haven't received any content yet\n if (!hasReceivedContent) {\n content = data.result.output.messages[0].content;\n isDone = true;\n } else {\n // Skip the complete message if we've already received chunks\n continue;\n }\n }\n }\n \n // Handle direct server response format (from LLM clients)\n // This is what the server actually sends: { \"response\": \"...\", \"done\": false/true }\n if (!content && 'response' in data && typeof data.response === 'string') {\n content = data.response;\n }\n \n // Check for done signal in the data\n if ('done' in data && data.done === true) {\n isDone = true;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n hasReceivedContent = true;\n yield {\n text: newText,\n done: isDone\n };\n }\n }\n \n // If we received a done signal, exit\n if (isDone) {\n if (!hasReceivedContent) {\n // Yield empty response to indicate completion\n yield { text: '', done: true };\n }\n return;\n }\n } catch (parseError) {\n // Don't throw, just continue processing\n }\n }\n }\n \n // Keep remaining incomplete line in buffer\n buffer = buffer.slice(lineStartIndex);\n \n // Prevent buffer from growing too large\n if (buffer.length > 1000000) { // 1MB limit\n buffer = buffer.slice(-500000); // Keep last 500KB\n }\n }\n \n // If we exit the while loop naturally, ensure we send a done signal\n if (hasReceivedContent) {\n yield { text: '', done: true };\n }\n \n } finally {\n reader.releaseLock();\n }\n\n // Handle any remaining buffer (fallback)\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText && jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: true\n };\n }\n }\n }\n } catch (error) {\n // Fail silently for final buffer parsing\n }\n }\n \n } catch (error: any) {\n if (error.name === 'AbortError') {\n yield { \n text: 'Connection timed out. Please check if the server is running.', \n done: true \n };\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n yield { \n text: 'Could not connect to the server. Please check if the server is running.', \n done: true \n };\n } else {\n yield { \n text: `Error: ${error.message}`, \n done: true \n };\n }\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n // Simplified version - just check if we have new content at the end\n if (!currentText) return incomingText;\n \n // If incoming text is longer and starts with current text, return the new part\n if (incomingText.length > currentText.length && incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n // Otherwise return the full incoming text (fallback)\n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configuredSessionId","sessionId","keyRefreshTimer","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getSessionId","initializeChatbot","permanentApiKey","customOrigin","API_URL","response","errorText","data","refreshInterval","refreshTemporaryKey","error","getFetchOptions","options","requestId","timestamp","headers","generateRequestSignature","body","payload","RateLimiter","__publicField","identifier","maxRequests","windowMs","now","recentRequests","time","key","requests","recent","rateLimiter","securityMonitor","config","threshold","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","_a","_b","_c","_d","_e","_f","_g","_h","_i","sessionIdentifier","controller","timeoutId","reader","decoder","buffer","currentFullText","hasReceivedContent","done","value","chunk","lineStartIndex","newlineIndex","line","jsonText","content","isDone","newText","extractNewText","incomingText","currentText","sendToolsRequest"],"mappings":"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"}
|