@schmitech/chatbot-api 0.4.5 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # 🤖 ORBIT Chatbot API Client
2
2
 
3
- A TypeScript/JavaScript client for seamless interaction with the ORBIT server, supporting API key authentication and session tracking.
3
+ A TypeScript/JavaScript client for seamless interaction with the ORBIT server, supporting secure API key authentication, temporary key exchange, and session tracking.
4
4
 
5
5
  ## 📥 Installation
6
6
 
@@ -15,13 +15,13 @@ npm install @schmitech/chatbot-api
15
15
  First, configure the API client with your server details:
16
16
 
17
17
  ```typescript
18
- import { configureApi, streamChat } from '@schmitech/chatbot-api';
18
+ import { configureApi, streamChat, initializeChatbot } from '@schmitech/chatbot-api';
19
19
 
20
- configureApi({
21
- apiUrl: 'https://your-api-server.com',
22
- apiKey: 'your-api-key',
23
- sessionId: 'optional-session-id' // Optional, for conversation tracking
24
- });
20
+ // Basic configuration
21
+ configureApi('https://your-api-server.com', 'your-api-key');
22
+
23
+ // For enhanced security with temporary key exchange
24
+ await initializeChatbot('your-api-key', 'https://your-origin.com');
25
25
  ```
26
26
 
27
27
  ### Streaming Chat Example
@@ -42,20 +42,27 @@ async function chat() {
42
42
  Here's how to use the API in a React component:
43
43
 
44
44
  ```tsx
45
- import React, { useState } from 'react';
46
- import { configureApi, streamChat } from '@schmitech/chatbot-api';
47
-
48
- // Configure once at app startup
49
- configureApi({
50
- apiUrl: 'https://your-api-server.com',
51
- apiKey: 'your-api-key',
52
- sessionId: 'user_123_session_456' // Optional
53
- });
45
+ import React, { useState, useEffect } from 'react';
46
+ import { configureApi, streamChat, initializeChatbot } from '@schmitech/chatbot-api';
54
47
 
55
48
  function ChatComponent() {
56
49
  const [messages, setMessages] = useState<Array<{ text: string; isUser: boolean }>>([]);
57
50
  const [input, setInput] = useState('');
58
51
 
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
+
59
66
  const handleSubmit = async (e: React.FormEvent) => {
60
67
  e.preventDefault();
61
68
  setMessages(prev => [...prev, { text: input, isUser: true }]);
@@ -87,14 +94,17 @@ function ChatComponent() {
87
94
  ### React Native Example
88
95
 
89
96
  ```typescript
90
- import { configureApi, streamChat } from '@schmitech/chatbot-api';
91
-
92
- // Configure once at app startup
93
- configureApi({
94
- apiUrl: 'https://your-api-server.com',
95
- apiKey: 'your-api-key',
96
- sessionId: 'user_123_session_456' // Optional
97
- });
97
+ import { configureApi, streamChat, initializeChatbot } from '@schmitech/chatbot-api';
98
+
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
+ };
98
108
 
99
109
  async function handleChat(message: string) {
100
110
  for await (const response of streamChat(message, true)) {
@@ -113,13 +123,17 @@ You can also use the API directly in the browser via CDN:
113
123
 
114
124
  ```html
115
125
  <script type="module">
116
- import { configureApi, streamChat } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api/dist/api.mjs';
117
-
118
- configureApi({
119
- apiUrl: 'https://your-api-server.com',
120
- apiKey: 'your-api-key',
121
- sessionId: 'your-session-id' // Optional
122
- });
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
+ };
123
137
 
124
138
  async function handleChat() {
125
139
  for await (const response of streamChat('Hello', true)) {
@@ -131,16 +145,25 @@ You can also use the API directly in the browser via CDN:
131
145
 
132
146
  ## 📚 API Reference
133
147
 
134
- ### `configureApi(config)`
148
+ ### `configureApi(apiUrl: string, apiKey?: string, sessionId?: string)`
135
149
 
136
150
  Configure the API client with server details.
137
151
 
138
152
  | Parameter | Type | Required | Description |
139
153
  |-----------|------|----------|-------------|
140
154
  | `apiUrl` | string | Yes | Chatbot API server URL |
141
- | `apiKey` | string | Yes | API key for authentication |
155
+ | `apiKey` | string | No | API key for authentication |
142
156
  | `sessionId` | string | No | Session ID for conversation tracking |
143
157
 
158
+ ### `initializeChatbot(apiKey: string, origin: string)`
159
+
160
+ Initialize secure key exchange for enhanced security.
161
+
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) |
166
+
144
167
  ### `streamChat(message: string, stream: boolean = true)`
145
168
 
146
169
  Stream chat responses from the server.
@@ -159,8 +182,19 @@ interface StreamResponse {
159
182
  }
160
183
  ```
161
184
 
162
- ## 🔒 Security
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
193
+
194
+ ### Security Best Practices
163
195
 
164
196
  - Always use HTTPS for your API URL
165
197
  - Keep your API key secure and never expose it in client-side code
166
- - Consider using environment variables for sensitive configuration
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 b=null,N=null,O=null;const $=(t,e=null,r=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(r!==null&&typeof r!="string")throw new Error("Session ID must be a valid string or null");b=t,N=e,O=r},R=()=>{if(!b)throw new Error("API URL not configured. Please call configureApi() with your server URL before using any API functions.");return b},q=()=>N,L=()=>O,j=(t,e={})=>{t.startsWith("https:");const n={Connection:"keep-alive","X-Request-ID":Date.now().toString(36)+Math.random().toString(36).substring(2)},i=q();i&&(n["X-API-Key"]=i);const u=L();return u&&(n["X-Session-ID"]=u),{...e,headers:{...e.headers,...n}}},x=(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)}),J=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*T(t,e=!0){var r,n,i,u,k,E,S,A,P;try{const a=R(),v=new AbortController,D=setTimeout(()=>v.abort(),6e4),c=await fetch(`${a}/v1/chat`,{...j(a,{method:"POST",headers:{"Content-Type":"application/json",Accept:e?"text/event-stream":"application/json"},body:JSON.stringify(x(t,e))}),signal:v.signal});if(clearTimeout(D),!c.ok){const o=await c.text();throw new Error(`Network response was not ok: ${c.status} ${o}`)}if(!e){const o=await c.json();if(o.error)throw new Error(`MCP Error: ${o.error.message}`);(u=(i=(n=(r=o.result)==null?void 0:r.output)==null?void 0:n.messages)==null?void 0:i[0])!=null&&u.content&&(yield{text:o.result.output.messages[0].content,done:!0});return}const w=(k=c.body)==null?void 0:k.getReader();if(!w)throw new Error("No reader available");const M=new TextDecoder;let l="",y="";try{for(;;){const{done:o,value:d}=await w.read();if(o)break;const f=M.decode(d,{stream:!0});l+=f;const I=l.split(`
2
- `);l=I.pop()||"";for(const h of I)if(h.trim()&&h.startsWith("data: "))try{const p=h.slice(6).trim();if(p==="[DONE]"){yield{text:"",done:!0};break}const s=JSON.parse(p);if(s.result){let g="";if(s.result.type==="start")continue;if(s.result.type==="chunk"&&s.result.chunk?g=s.result.chunk.content:s.result.type==="complete"&&((S=(E=s.result.output)==null?void 0:E.messages)!=null&&S[0])&&(g=s.result.output.messages[0].content),g){const m=C(g,y);m?(y+=m,yield{text:m,done:s.result.type==="complete"}):s.result.type==="complete"&&(yield{text:"",done:!0})}}}catch(p){console.warn("Error parsing JSON chunk:",h,"Error:",p)}}}finally{w.releaseLock()}if(l&&l.startsWith("data: "))try{const o=l.slice(6).trim();if(o!=="[DONE]"){const d=JSON.parse(o);if((P=(A=d.result)==null?void 0:A.chunk)!=null&&P.content){const f=C(d.result.chunk.content,y);f&&(yield{text:f,done:d.result.type==="complete"})}}}catch(o){console.warn("Error parsing final JSON buffer:",l,"Error:",o)}}catch(a){a.name==="AbortError"?yield{text:"Connection timed out. Please check if the server is running.",done:!0}:a.name==="TypeError"&&a.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: ${a.message}`,done:!0}}}function C(t,e){if(!e)return t;if(e.endsWith(t))return"";if(t.length>e.length){if(t.startsWith(e))return t.slice(e.length);let r=0;const n=Math.min(e.length,t.length);for(;r<n&&e[r]===t[r];)r++;if(r>e.length/2)return t.slice(r)}return t}async function U(t){const e=R(),r=await fetch(`${e}/v1/chat`,j(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(J(t))}));if(!r.ok){const i=await r.text();throw new Error(`Network response was not ok: ${r.status} ${i}`)}const n=await r.json();if(n.error)throw new Error(`MCP Error: ${n.error.message}`);return n}exports.configureApi=$;exports.sendToolsRequest=U;exports.streamChat=T;
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":"oPAyDA,IAAIA,EAAkC,KAClCC,EAAkC,KAClCC,EAAqC,KAGrCC,EAA2B,KAC3BC,EAAiC,KAW9B,MAAMC,EAAe,CAACC,EAAgBC,EAAwB,KAAMJ,EAA2B,OAAe,CACnH,GAAI,CAACG,GAAU,OAAOA,GAAW,SACzB,MAAA,IAAI,MAAM,gCAAgC,EAElD,GAAIC,IAAW,MAAQ,OAAOA,GAAW,SACjC,MAAA,IAAI,MAAM,wCAAwC,EAE1D,GAAIJ,IAAc,MAAQ,OAAOA,GAAc,SACvC,MAAA,IAAI,MAAM,2CAA2C,EAE1CH,EAAAM,EACAL,EAAAM,EACGJ,EAAAA,CACxB,EAGMK,EAAY,IAAc,CAC9B,GAAI,CAACR,EACG,MAAA,IAAI,MAAM,yGAAyG,EAEpH,OAAAA,CACT,EAGMS,EAAY,IACTR,EAIHS,EAAe,IACZR,EAIIS,EAAoB,MAAOC,EAAyBC,IAAyC,CACpG,GAAA,CACF,MAAMC,EAAUN,EAAU,EAGpBO,EAAW,MAAM,MAAM,GAAGD,CAAO,uBAAwB,CAC7D,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,UAAU,CACnB,OAAQF,EACR,OAAQC,IAAiB,OAAO,OAAW,IAAc,OAAO,SAAS,OAAS,cACnF,CAAA,CAAA,CACF,EAEG,GAAA,CAACE,EAAS,GAAI,CACV,MAAAC,EAAY,MAAMD,EAAS,KAAK,EACtC,MAAM,IAAI,MAAM,+BAA+BA,EAAS,MAAM,IAAIC,CAAS,EAAE,CAAA,CAGzE,MAAAC,EAA4B,MAAMF,EAAS,KAAK,EAGtDZ,EAAYc,EAAK,UACjBhB,EAAmBgB,EAAK,aACxBf,EAAsBe,EAAK,UAGTL,EAAA,GAGZ,MAAAM,EAAkBD,EAAK,UAAY,GAAM,IAC3Cb,GACF,aAAaA,CAAe,EAE9BA,EAAkB,WAAW,IAAMe,EAAoB,EAAGD,CAAe,QAClEE,EAAO,CACR,MAAAA,CAAA,CAEV,EAGMD,EAAsB,SAA2B,CACrD,GAAKhB,EAED,GAAA,CACF,MAAMW,EAAUN,EAAU,EAEpBO,EAAW,MAAM,MAAM,GAAGD,CAAO,sBAAuB,CAC5D,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,eAAgBX,EAChB,OAAU,OAAO,OAAW,IAAc,OAAO,SAAS,OAAS,aAAA,CACrE,CACD,EAEG,GAAA,CAACY,EAAS,GAAI,CACV,MAAAC,EAAY,MAAMD,EAAS,KAAK,EACtC,MAAM,IAAI,MAAM,0BAA0BA,EAAS,MAAM,IAAIC,CAAS,EAAE,CAAA,CAGpE,MAAAC,EAA4B,MAAMF,EAAS,KAAK,EAGtDd,EAAmBgB,EAAK,aAGpBb,GACF,aAAaA,CAAe,EAExB,MAAAc,EAAkBD,EAAK,UAAY,GAAM,IAC/Cb,EAAkB,WAAW,IAAMe,EAAoB,EAAGD,CAAe,QAClEE,EAAO,CAEV,OAAO,OAAW,KACb,OAAA,cAAc,IAAI,YAAY,sBAAuB,CAAE,OAAQA,CAAA,CAAO,CAAC,CAChF,CAEJ,EAGMC,EAAkB,CAACf,EAAgBgB,EAAuB,KAA0B,CACxEhB,EAAO,WAAW,QAAQ,EAY1C,MAAMiB,EAAY,KAAK,IAAI,EAAE,SAAS,EAAE,EAAI,KAAK,OAAS,EAAA,SAAS,EAAE,EAAE,UAAU,CAAC,EAC5EC,EAAY,KAAK,IAAI,EAGrBC,EAAkC,CACtC,WAAc,aACd,eAAgBF,EAChB,cAAeC,EAAU,SAAS,CACpC,EAGI,OAAO,OAAW,MACZC,EAAA,UAAU,EAAI,OAAO,SAAS,OAC9BA,EAAA,YAAY,EAAI,SAAS,UAAY,UAI/C,MAAMlB,EAASE,EAAU,EACrBF,IACFkB,EAAQ,WAAW,EAAIlB,EAGnB,OAAO,OAAW,MACpBkB,EAAQ,aAAa,EAAIC,EACvBH,EACAC,EACAF,EAAQ,IACV,IAKJ,MAAMnB,EAAYO,EAAa,EAC/B,OAAIP,IACFsB,EAAQ,cAAc,EAAItB,GAGrB,CACL,GAAGmB,EACH,QAAS,CACP,GAAGA,EAAQ,QACX,GAAGG,CAAA,CAEP,CACF,EAGMC,EAA2B,CAC/BH,EACAC,EACAG,IACW,CACL,MAAAC,EAAU,GAAGL,CAAS,IAAIC,CAAS,IAAIG,EAAO,KAAK,UAAUA,CAAI,EAAI,EAAE,GAE7E,OAAO,KAAKC,CAAO,EAAE,UAAU,EAAG,EAAE,CACtC,EAGA,MAAMC,CAAY,CAAlB,cACUC,EAAA,oBAAsC,KAE9C,eACEC,EACAC,EAAsB,GACtBC,EAAmB,IACV,CACH,MAAAC,EAAM,KAAK,IAAI,EAEfC,GADe,KAAK,SAAS,IAAIJ,CAAU,GAAK,CAAC,GACnB,OAAeK,GAAAF,EAAME,EAAOH,CAAQ,EAEpE,OAAAE,EAAe,QAAUH,EACpB,IAGTG,EAAe,KAAKD,CAAG,EAClB,KAAA,SAAS,IAAIH,EAAYI,CAAc,EAGxC,KAAK,SAAS,KAAO,KACvB,KAAK,QAAQF,CAAQ,EAGhB,GAAA,CAGD,QAAQA,EAAwB,CAChC,MAAAC,EAAM,KAAK,IAAI,EACrB,SAAW,CAACG,EAAKC,CAAQ,IAAK,KAAK,SAAS,UAAW,CACrD,MAAMC,EAASD,EAAS,OAAeF,GAAAF,EAAME,EAAOH,CAAQ,EACxDM,EAAO,SAAW,EACf,KAAA,SAAS,OAAOF,CAAG,EAEnB,KAAA,SAAS,IAAIA,EAAKE,CAAM,CAC/B,CACF,CAEJ,CAGA,MAAMC,EAAc,IAAIX,EAGlBY,EAAkB,CACtB,OAAQ,CACN,WAAY,CACV,QAAS,EAAA,CAEb,EAEA,MAAM,YAA4B,CAC5B,GAAA,CACF,MAAM3B,EAAUN,EAAU,EACpBO,EAAW,MAAM,MAAM,GAAGD,CAAO,yBAAyB,EAChE,GAAIC,EAAS,GAAI,CACT,MAAA2B,EAAS,MAAM3B,EAAS,KAAK,EAC/B2B,EAAO,aACT,KAAK,OAAO,WAAa,CACvB,GAAG,KAAK,OAAO,WACf,GAAGA,EAAO,UACZ,EACF,OAEQ,CAAA,CAGd,EAEA,gBAA0B,CACpB,GAAA,OAAO,OAAW,IAAoB,MAAA,GAC1C,MAAMC,EAAY,IACV,OAAA,OAAO,YAAc,OAAO,YAAcA,GAC1C,OAAO,WAAa,OAAO,WAAaA,CAClD,EAEA,MAAM,MAAsB,CACtB,OAAO,OAAW,KAGtB,MAAM,KAAK,WAAW,CAAA,CAE1B,EAGI,OAAO,OAAW,KACJF,EAAA,OAAO,MAAM,IAAM,CAAA,CAElC,EAIH,MAAMG,EAAmB,CAACC,EAAiBC,EAAkB,MACpD,CACL,QAAS,MACT,OAAQ,aACR,OAAQ,CACN,KAAM,OACN,UAAW,CACT,SAAU,CACR,CAAE,KAAM,OAAQ,QAASD,CAAQ,CACnC,EACA,OAAAC,CAAA,CAEJ,EACA,GAAI,KAAK,MAAM,SAAS,EAAE,EAAI,KAAK,OAAS,EAAA,SAAS,EAAE,EAAE,UAAU,CAAC,CACtE,GAIIC,EAAyBC,IACtB,CACL,QAAS,MACT,OAAQ,aACR,OAAQ,CACN,KAAM,QACN,UAAW,CACT,MAAAA,CAAA,CAEJ,EACA,GAAI,KAAK,MAAM,SAAS,EAAE,EAAI,KAAK,OAAS,EAAA,SAAS,EAAE,EAAE,UAAU,CAAC,CACtE,GAGqB,eAAAC,GACrBJ,EACAC,EAAkB,GACc,uBAC5B,GAAA,CAEI,MAAAI,EAAoBxC,KAAkB,YAE5C,GAAI,CAAC8B,EAAY,eAAeU,EAAmB,GAAI,GAAK,EAAG,CACvD,KAAA,CACJ,KAAM,0EACN,KAAM,EACR,EACA,MAAA,CAGF,MAAMpC,EAAUN,EAAU,EAGpB2C,EAAa,IAAI,gBACjBC,EAAY,WAAW,IAAMD,EAAW,MAAA,EAAS,GAAK,EAEtDpC,EAAW,MAAM,MAAM,GAAGD,CAAO,WAAY,CACjD,GAAGO,EAAgBP,EAAS,CAC1B,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,OAAUgC,EAAS,oBAAsB,kBAC3C,EACA,KAAM,KAAK,UAAUF,EAAiBC,EAASC,CAAM,CAAC,CAAA,CACvD,EACD,OAAQK,EAAW,MAAA,CACpB,EAIG,GAFJ,aAAaC,CAAS,EAElB,CAACrC,EAAS,GAAI,CACV,MAAAC,EAAY,MAAMD,EAAS,KAAK,EACtC,MAAM,IAAI,MAAM,gCAAgCA,EAAS,MAAM,IAAIC,CAAS,EAAE,CAAA,CAGhF,GAAI,CAAC8B,EAAQ,CAEL,MAAA7B,EAAO,MAAMF,EAAS,KAAK,EACjC,GAAIE,EAAK,MACP,MAAM,IAAI,MAAM,cAAcA,EAAK,MAAM,OAAO,EAAE,GAEhDoC,GAAAC,GAAAC,GAAAC,EAAAvC,EAAK,SAAL,YAAAuC,EAAa,SAAb,YAAAD,EAAqB,WAArB,YAAAD,EAAgC,KAAhC,MAAAD,EAAoC,UAChC,KAAA,CACJ,KAAMpC,EAAK,OAAO,OAAO,SAAS,CAAC,EAAE,QACrC,KAAM,EACR,GAEF,MAAA,CAGI,MAAAwC,GAASC,EAAA3C,EAAS,OAAT,YAAA2C,EAAe,YAC9B,GAAI,CAACD,EAAc,MAAA,IAAI,MAAM,qBAAqB,EAE5C,MAAAE,EAAU,IAAI,YACpB,IAAIC,EAAS,GACTC,EAAkB,GAClBC,EAAqB,GAErB,GAAA,CACF,OAAa,CACX,KAAM,CAAE,KAAAC,EAAM,MAAAC,CAAU,EAAA,MAAMP,EAAO,KAAK,EAC1C,GAAIM,EACF,MAGF,MAAME,EAAQN,EAAQ,OAAOK,EAAO,CAAE,OAAQ,GAAM,EAC1CJ,GAAAK,EAGV,IAAIC,EAAiB,EACjBC,EAEJ,MAAQA,EAAeP,EAAO,QAAQ;AAAA,EAAMM,CAAc,KAAO,IAAI,CACnE,MAAME,EAAOR,EAAO,MAAMM,EAAgBC,CAAY,EAAE,KAAK,EAG7D,GAFAD,EAAiBC,EAAe,EAE5BC,GAAQA,EAAK,WAAW,QAAQ,EAC9B,GAAA,CACF,MAAMC,EAAWD,EAAK,MAAM,CAAC,EAAE,KAAK,EAGpC,GAAIC,IAAa,SAAU,CACzB,KAAM,CAAE,KAAM,GAAI,KAAM,EAAK,EAC7B,MAAA,CAIF,GAAI,CAACA,EACH,SAGI,MAAApD,EAAO,KAAK,MAAMoD,CAAQ,EAGhC,GAAIpD,EAAK,MACP,MAAM,IAAI,MAAM,cAAcA,EAAK,MAAM,OAAO,EAAE,EAGpD,IAAIqD,EAAU,GACVC,EAAS,GAGb,GAAItD,EAAK,OAAQ,CACX,GAAAA,EAAK,OAAO,OAAS,QACvB,YACSA,EAAK,OAAO,OAAS,SAAWA,EAAK,OAAO,MAC3CqD,EAAArD,EAAK,OAAO,MAAM,gBACnBA,EAAK,OAAO,OAAS,cAAcuD,GAAAC,EAAAxD,EAAK,OAAO,SAAZ,YAAAwD,EAAoB,WAApB,MAAAD,EAA+B,IAE3E,GAAI,CAACV,EACHQ,EAAUrD,EAAK,OAAO,OAAO,SAAS,CAAC,EAAE,QAChCsD,EAAA,OAGT,SAEJ,CAcF,GATI,CAACD,GAAW,aAAcrD,GAAQ,OAAOA,EAAK,UAAa,WAC7DqD,EAAUrD,EAAK,UAIb,SAAUA,GAAQA,EAAK,OAAS,KACzBsD,EAAA,IAGPD,EAAS,CACL,MAAAI,EAAUC,EAAeL,EAAST,CAAe,EACnDa,IACiBb,GAAAa,EACEZ,EAAA,GACf,KAAA,CACJ,KAAMY,EACN,KAAMH,CACR,EACF,CAIF,GAAIA,EAAQ,CACLT,IAEH,KAAM,CAAE,KAAM,GAAI,KAAM,EAAK,GAE/B,MAAA,OAEiB,CAAA,CAGvB,CAIOF,EAAAA,EAAO,MAAMM,CAAc,EAGhCN,EAAO,OAAS,MACTA,EAAAA,EAAO,MAAM,IAAO,EAC/B,CAIEE,IACF,KAAM,CAAE,KAAM,GAAI,KAAM,EAAK,EAC/B,QAEA,CACAL,EAAO,YAAY,CAAA,CAIrB,GAAIG,GAAUA,EAAO,WAAW,QAAQ,EAClC,GAAA,CACF,MAAMS,EAAWT,EAAO,MAAM,CAAC,EAAE,KAAK,EAClC,GAAAS,GAAYA,IAAa,SAAU,CAC/B,MAAApD,EAAO,KAAK,MAAMoD,CAAQ,EAC5B,IAAAO,GAAAC,EAAA5D,EAAK,SAAL,YAAA4D,EAAa,QAAb,MAAAD,EAAoB,QAAS,CAC/B,MAAMF,EAAUC,EAAe1D,EAAK,OAAO,MAAM,QAAS4C,CAAe,EACrEa,IACI,KAAA,CACJ,KAAMA,EACN,KAAM,EACR,EACF,CACF,OAEY,CAAA,QAKXtD,EAAY,CACfA,EAAM,OAAS,aACX,KAAA,CACJ,KAAM,+DACN,KAAM,EACR,EACSA,EAAM,OAAS,aAAeA,EAAM,QAAQ,SAAS,iBAAiB,EACzE,KAAA,CACJ,KAAM,0EACN,KAAM,EACR,EAEM,KAAA,CACJ,KAAM,UAAUA,EAAM,OAAO,GAC7B,KAAM,EACR,CACF,CAEJ,CAGA,SAASuD,EAAeG,EAAsBC,EAA6B,CAErE,OAACA,GAGDD,EAAa,OAASC,EAAY,QAAUD,EAAa,WAAWC,CAAW,EAC1ED,EAAa,MAAMC,EAAY,MAAM,EAJrBD,CAS3B,CAGA,eAAsBE,GAAiBhC,EAAuF,CAC5H,MAAMlC,EAAUN,EAAU,EAEpBO,EAAW,MAAM,MAAM,GAAGD,CAAO,WAAYO,EAAgBP,EAAS,CAC1E,OAAQ,OACR,QAAS,CACP,eAAgB,kBAClB,EACA,KAAM,KAAK,UAAUiC,EAAsBC,CAAK,CAAC,CAAA,CAClD,CAAC,EAEE,GAAA,CAACjC,EAAS,GAAI,CACV,MAAAC,EAAY,MAAMD,EAAS,KAAK,EACtC,MAAM,IAAI,MAAM,gCAAgCA,EAAS,MAAM,IAAIC,CAAS,EAAE,CAAA,CAG1E,MAAAC,EAAO,MAAMF,EAAS,KAAK,EACjC,GAAIE,EAAK,MACP,MAAM,IAAI,MAAM,cAAcA,EAAK,MAAM,OAAO,EAAE,EAG7C,OAAAA,CACT"}
package/dist/api.mjs CHANGED
@@ -1,32 +1,135 @@
1
- let k = null, C = null, O = null;
2
- const J = (t, e = null, r = null) => {
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 (r !== null && typeof r != "string")
10
+ if (n !== null && typeof n != "string")
8
11
  throw new Error("Session ID must be a valid string or null");
9
- k = t, C = e, O = r;
10
- }, R = () => {
11
- if (!k)
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 k;
14
- }, M = () => C, x = () => O, j = (t, e = {}) => {
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": Date.now().toString(36) + Math.random().toString(36).substring(2)
19
- }, i = M();
20
- i && (o["X-API-Key"] = i);
21
- const c = x();
22
- return c && (o["X-Session-ID"] = c), {
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
- }, L = (t, e = !0) => ({
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
- }), q = (t) => ({
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* U(t, e = !0) {
54
- var r, o, i, c, E, b, S, A, P;
156
+ async function* te(t, e = !0) {
157
+ var n, r, o, c, i, g, A, C, O;
55
158
  try {
56
- const a = R(), I = new AbortController(), D = setTimeout(() => I.abort(), 6e4), u = await fetch(`${a}/v1/chat`, {
57
- ...j(a, {
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(L(t, e))
174
+ body: JSON.stringify(Q(t, e))
64
175
  }),
65
- signal: I.signal
176
+ signal: j.signal
66
177
  });
67
- if (clearTimeout(D), !u.ok) {
68
- const n = await u.text();
69
- throw new Error(`Network response was not ok: ${u.status} ${n}`);
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 n = await u.json();
73
- if (n.error)
74
- throw new Error(`MCP Error: ${n.error.message}`);
75
- (c = (i = (o = (r = n.result) == null ? void 0 : r.output) == null ? void 0 : o.messages) == null ? void 0 : i[0]) != null && c.content && (yield {
76
- text: n.result.output.messages[0].content,
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 w = (E = u.body) == null ? void 0 : E.getReader();
82
- if (!w) throw new Error("No reader available");
83
- const $ = new TextDecoder();
84
- let l = "", y = "";
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: n, value: d } = await w.read();
88
- if (n) break;
89
- const f = $.decode(d, { stream: !0 });
90
- l += f;
91
- const v = l.split(`
92
- `);
93
- l = v.pop() || "";
94
- for (const h of v)
95
- if (h.trim() && h.startsWith("data: "))
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 p = h.slice(6).trim();
98
- if (p === "[DONE]") {
209
+ const x = b.slice(6).trim();
210
+ if (x === "[DONE]") {
99
211
  yield { text: "", done: !0 };
100
- break;
212
+ return;
101
213
  }
102
- const s = JSON.parse(p);
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 ? g = s.result.chunk.content : s.result.type === "complete" && ((S = (b = s.result.output) == null ? void 0 : b.messages) != null && S[0]) && (g = s.result.output.messages[0].content), g) {
108
- const m = N(g, y);
109
- m ? (y += m, yield {
110
- text: m,
111
- done: s.result.type === "complete"
112
- }) : s.result.type === "complete" && (yield { text: "", done: !0 });
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
- } catch (p) {
116
- console.warn("Error parsing JSON chunk:", h, "Error:", p);
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
- w.releaseLock();
249
+ T.releaseLock();
121
250
  }
122
- if (l && l.startsWith("data: "))
251
+ if (u && u.startsWith("data: "))
123
252
  try {
124
- const n = l.slice(6).trim();
125
- if (n !== "[DONE]") {
126
- const d = JSON.parse(n);
127
- if ((P = (A = d.result) == null ? void 0 : A.chunk) != null && P.content) {
128
- const f = N(d.result.chunk.content, y);
129
- f && (yield {
130
- text: f,
131
- done: d.result.type === "complete"
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 (n) {
136
- console.warn("Error parsing final JSON buffer:", l, "Error:", n);
264
+ } catch {
137
265
  }
138
- } catch (a) {
139
- a.name === "AbortError" ? yield {
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
- } : a.name === "TypeError" && a.message.includes("Failed to fetch") ? yield {
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: ${a.message}`,
274
+ text: `Error: ${l.message}`,
147
275
  done: !0
148
276
  };
149
277
  }
150
278
  }
151
- function N(t, e) {
152
- if (!e) return t;
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 W(t) {
167
- const e = R(), r = await fetch(`${e}/v1/chat`, j(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(q(t))
288
+ body: JSON.stringify(V(t))
173
289
  }));
174
- if (!r.ok) {
175
- const i = await r.text();
176
- throw new Error(`Network response was not ok: ${r.status} ${i}`);
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 o = await r.json();
179
- if (o.error)
180
- throw new Error(`MCP Error: ${o.error.message}`);
181
- return o;
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
- J as configureApi,
185
- W as sendToolsRequest,
186
- U as streamChat
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":";;;AAyDA,IAAIA,IAAkC,MAClCC,IAAkC,MAClCC,IAAqC,MAGrCC,IAA2B,MAC3BC,IAAiC;AAW9B,MAAMC,IAAe,CAACC,GAAgBC,IAAwB,MAAMJ,IAA2B,SAAe;AACnH,MAAI,CAACG,KAAU,OAAOA,KAAW;AACzB,UAAA,IAAI,MAAM,gCAAgC;AAElD,MAAIC,MAAW,QAAQ,OAAOA,KAAW;AACjC,UAAA,IAAI,MAAM,wCAAwC;AAE1D,MAAIJ,MAAc,QAAQ,OAAOA,KAAc;AACvC,UAAA,IAAI,MAAM,2CAA2C;AAE1C,EAAAH,IAAAM,GACAL,IAAAM,GACGJ,IAAAA;AACxB,GAGMK,IAAY,MAAc;AAC9B,MAAI,CAACR;AACG,UAAA,IAAI,MAAM,yGAAyG;AAEpH,SAAAA;AACT,GAGMS,IAAY,MACTR,GAIHS,IAAe,MACZR,GAIIS,KAAoB,OAAOC,GAAyBC,MAAyC;AACpG,MAAA;AACF,UAAMC,IAAUN,EAAU,GAGpBO,IAAW,MAAM,MAAM,GAAGD,CAAO,wBAAwB;AAAA,MAC7D,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACnB,QAAQF;AAAA,QACR,QAAQC,MAAiB,OAAO,SAAW,MAAc,OAAO,SAAS,SAAS;AAAA,MACnF,CAAA;AAAA,IAAA,CACF;AAEG,QAAA,CAACE,EAAS,IAAI;AACV,YAAAC,IAAY,MAAMD,EAAS,KAAK;AACtC,YAAM,IAAI,MAAM,+BAA+BA,EAAS,MAAM,IAAIC,CAAS,EAAE;AAAA,IAAA;AAGzE,UAAAC,IAA4B,MAAMF,EAAS,KAAK;AAGtD,IAAAZ,IAAYc,EAAK,WACjBhB,IAAmBgB,EAAK,cACxBf,IAAsBe,EAAK,WAGTL,IAAA;AAGZ,UAAAM,IAAkBD,EAAK,YAAY,MAAM;AAC/C,IAAIb,KACF,aAAaA,CAAe,GAE9BA,IAAkB,WAAW,MAAMe,EAAoB,GAAGD,CAAe;AAAA,WAClEE,GAAO;AACR,UAAAA;AAAA,EAAA;AAEV,GAGMD,IAAsB,YAA2B;AACrD,MAAKhB;AAED,QAAA;AACF,YAAMW,IAAUN,EAAU,GAEpBO,IAAW,MAAM,MAAM,GAAGD,CAAO,uBAAuB;AAAA,QAC5D,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,gBAAgBX;AAAA,UAChB,QAAU,OAAO,SAAW,MAAc,OAAO,SAAS,SAAS;AAAA,QAAA;AAAA,MACrE,CACD;AAEG,UAAA,CAACY,EAAS,IAAI;AACV,cAAAC,IAAY,MAAMD,EAAS,KAAK;AACtC,cAAM,IAAI,MAAM,0BAA0BA,EAAS,MAAM,IAAIC,CAAS,EAAE;AAAA,MAAA;AAGpE,YAAAC,IAA4B,MAAMF,EAAS,KAAK;AAGtD,MAAAd,IAAmBgB,EAAK,cAGpBb,KACF,aAAaA,CAAe;AAExB,YAAAc,IAAkBD,EAAK,YAAY,MAAM;AAC/C,MAAAb,IAAkB,WAAW,MAAMe,EAAoB,GAAGD,CAAe;AAAA,aAClEE,GAAO;AAEV,MAAA,OAAO,SAAW,OACb,OAAA,cAAc,IAAI,YAAY,uBAAuB,EAAE,QAAQA,EAAA,CAAO,CAAC;AAAA,IAChF;AAEJ,GAGMC,IAAkB,CAACf,GAAgBgB,IAAuB,OAA0B;AACxE,EAAAhB,EAAO,WAAW,QAAQ;AAY1C,QAAMiB,IAAY,KAAK,IAAI,EAAE,SAAS,EAAE,IAAI,KAAK,OAAS,EAAA,SAAS,EAAE,EAAE,UAAU,CAAC,GAC5EC,IAAY,KAAK,IAAI,GAGrBC,IAAkC;AAAA,IACtC,YAAc;AAAA,IACd,gBAAgBF;AAAA,IAChB,eAAeC,EAAU,SAAS;AAAA,EACpC;AAGI,EAAA,OAAO,SAAW,QACZC,EAAA,UAAU,IAAI,OAAO,SAAS,QAC9BA,EAAA,YAAY,IAAI,SAAS,YAAY;AAI/C,QAAMlB,IAASE,EAAU;AACzB,EAAIF,MACFkB,EAAQ,WAAW,IAAIlB,GAGnB,OAAO,SAAW,QACpBkB,EAAQ,aAAa,IAAIC;AAAA,IACvBH;AAAA,IACAC;AAAA,IACAF,EAAQ;AAAA,EACV;AAKJ,QAAMnB,IAAYO,EAAa;AAC/B,SAAIP,MACFsB,EAAQ,cAAc,IAAItB,IAGrB;AAAA,IACL,GAAGmB;AAAA,IACH,SAAS;AAAA,MACP,GAAGA,EAAQ;AAAA,MACX,GAAGG;AAAA,IAAA;AAAA,EAEP;AACF,GAGMC,IAA2B,CAC/BH,GACAC,GACAG,MACW;AACL,QAAAC,IAAU,GAAGL,CAAS,IAAIC,CAAS,IAAIG,IAAO,KAAK,UAAUA,CAAI,IAAI,EAAE;AAE7E,SAAO,KAAKC,CAAO,EAAE,UAAU,GAAG,EAAE;AACtC;AAGA,MAAMC,EAAY;AAAA,EAAlB;AACU,IAAAC,EAAA,sCAAsC,IAAI;AAAA;AAAA,EAElD,eACEC,GACAC,IAAsB,IACtBC,IAAmB,KACV;AACH,UAAAC,IAAM,KAAK,IAAI,GAEfC,KADe,KAAK,SAAS,IAAIJ,CAAU,KAAK,CAAC,GACnB,OAAO,CAAQK,MAAAF,IAAME,IAAOH,CAAQ;AAEpE,WAAAE,EAAe,UAAUH,IACpB,MAGTG,EAAe,KAAKD,CAAG,GAClB,KAAA,SAAS,IAAIH,GAAYI,CAAc,GAGxC,KAAK,SAAS,OAAO,OACvB,KAAK,QAAQF,CAAQ,GAGhB;AAAA,EAAA;AAAA,EAGD,QAAQA,GAAwB;AAChC,UAAAC,IAAM,KAAK,IAAI;AACrB,eAAW,CAACG,GAAKC,CAAQ,KAAK,KAAK,SAAS,WAAW;AACrD,YAAMC,IAASD,EAAS,OAAO,CAAQF,MAAAF,IAAME,IAAOH,CAAQ;AACxD,MAAAM,EAAO,WAAW,IACf,KAAA,SAAS,OAAOF,CAAG,IAEnB,KAAA,SAAS,IAAIA,GAAKE,CAAM;AAAA,IAC/B;AAAA,EACF;AAEJ;AAGA,MAAMC,IAAc,IAAIX,EAAY,GAG9BY,IAAkB;AAAA,EACtB,QAAQ;AAAA,IACN,YAAY;AAAA,MACV,SAAS;AAAA,IAAA;AAAA,EAEb;AAAA,EAEA,MAAM,aAA4B;AAC5B,QAAA;AACF,YAAM3B,IAAUN,EAAU,GACpBO,IAAW,MAAM,MAAM,GAAGD,CAAO,yBAAyB;AAChE,UAAIC,EAAS,IAAI;AACT,cAAA2B,IAAS,MAAM3B,EAAS,KAAK;AACnC,QAAI2B,EAAO,eACT,KAAK,OAAO,aAAa;AAAA,UACvB,GAAG,KAAK,OAAO;AAAA,UACf,GAAGA,EAAO;AAAA,QACZ;AAAA,MACF;AAAA,YAEQ;AAAA,IAAA;AAAA,EAGd;AAAA,EAEA,iBAA0B;AACpB,QAAA,OAAO,SAAW,IAAoB,QAAA;AAC1C,UAAMC,IAAY;AACV,WAAA,OAAO,cAAc,OAAO,cAAcA,KAC1C,OAAO,aAAa,OAAO,aAAaA;AAAA,EAClD;AAAA,EAEA,MAAM,OAAsB;AACtB,IAAA,OAAO,SAAW,OAGtB,MAAM,KAAK,WAAW;AAAA,EAAA;AAE1B;AAGI,OAAO,SAAW,OACJF,EAAA,OAAO,MAAM,MAAM;AAAA,CAElC;AAIH,MAAMG,IAAmB,CAACC,GAAiBC,IAAkB,QACpD;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,MACT,UAAU;AAAA,QACR,EAAE,MAAM,QAAQ,SAASD,EAAQ;AAAA,MACnC;AAAA,MACA,QAAAC;AAAA,IAAA;AAAA,EAEJ;AAAA,EACA,IAAI,KAAK,MAAM,SAAS,EAAE,IAAI,KAAK,OAAS,EAAA,SAAS,EAAE,EAAE,UAAU,CAAC;AACtE,IAIIC,IAAwB,CAACC,OACtB;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,MACT,OAAAA;AAAA,IAAA;AAAA,EAEJ;AAAA,EACA,IAAI,KAAK,MAAM,SAAS,EAAE,IAAI,KAAK,OAAS,EAAA,SAAS,EAAE,EAAE,UAAU,CAAC;AACtE;AAGqB,gBAAAC,GACrBJ,GACAC,IAAkB,IACc;AA1UlC,MAAAI,GAAAC,GAAAC,GAAAC,GAAAC,GAAAC,GAAAC,GAAAC,GAAAC;AA2UM,MAAA;AAEI,UAAAC,IAAoBjD,OAAkB;AAE5C,QAAI,CAAC8B,EAAY,eAAemB,GAAmB,IAAI,GAAK,GAAG;AACvD,YAAA;AAAA,QACJ,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AACA;AAAA,IAAA;AAGF,UAAM7C,IAAUN,EAAU,GAGpBoD,IAAa,IAAI,gBAAgB,GACjCC,IAAY,WAAW,MAAMD,EAAW,MAAA,GAAS,GAAK,GAEtD7C,IAAW,MAAM,MAAM,GAAGD,CAAO,YAAY;AAAA,MACjD,GAAGO,EAAgBP,GAAS;AAAA,QAC1B,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAUgC,IAAS,sBAAsB;AAAA,QAC3C;AAAA,QACA,MAAM,KAAK,UAAUF,EAAiBC,GAASC,CAAM,CAAC;AAAA,MAAA,CACvD;AAAA,MACD,QAAQc,EAAW;AAAA,IAAA,CACpB;AAIG,QAFJ,aAAaC,CAAS,GAElB,CAAC9C,EAAS,IAAI;AACV,YAAAC,IAAY,MAAMD,EAAS,KAAK;AACtC,YAAM,IAAI,MAAM,gCAAgCA,EAAS,MAAM,IAAIC,CAAS,EAAE;AAAA,IAAA;AAGhF,QAAI,CAAC8B,GAAQ;AAEL,YAAA7B,IAAO,MAAMF,EAAS,KAAK;AACjC,UAAIE,EAAK;AACP,cAAM,IAAI,MAAM,cAAcA,EAAK,MAAM,OAAO,EAAE;AAEpD,OAAIoC,KAAAD,KAAAD,KAAAD,IAAAjC,EAAK,WAAL,gBAAAiC,EAAa,WAAb,gBAAAC,EAAqB,aAArB,gBAAAC,EAAgC,OAAhC,QAAAC,EAAoC,YAChC,MAAA;AAAA,QACJ,MAAMpC,EAAK,OAAO,OAAO,SAAS,CAAC,EAAE;AAAA,QACrC,MAAM;AAAA,MACR;AAEF;AAAA,IAAA;AAGI,UAAA6C,KAASR,IAAAvC,EAAS,SAAT,gBAAAuC,EAAe;AAC9B,QAAI,CAACQ,EAAc,OAAA,IAAI,MAAM,qBAAqB;AAE5C,UAAAC,IAAU,IAAI,YAAY;AAChC,QAAIC,IAAS,IACTC,IAAkB,IAClBC,IAAqB;AAErB,QAAA;AACF,iBAAa;AACX,cAAM,EAAE,MAAAC,GAAM,OAAAC,EAAU,IAAA,MAAMN,EAAO,KAAK;AAC1C,YAAIK;AACF;AAGF,cAAME,IAAQN,EAAQ,OAAOK,GAAO,EAAE,QAAQ,IAAM;AAC1C,QAAAJ,KAAAK;AAGV,YAAIC,IAAiB,GACjBC;AAEJ,gBAAQA,IAAeP,EAAO,QAAQ;AAAA,GAAMM,CAAc,OAAO,MAAI;AACnE,gBAAME,IAAOR,EAAO,MAAMM,GAAgBC,CAAY,EAAE,KAAK;AAG7D,cAFAD,IAAiBC,IAAe,GAE5BC,KAAQA,EAAK,WAAW,QAAQ;AAC9B,gBAAA;AACF,oBAAMC,IAAWD,EAAK,MAAM,CAAC,EAAE,KAAK;AAGpC,kBAAIC,MAAa,UAAU;AACzB,sBAAM,EAAE,MAAM,IAAI,MAAM,GAAK;AAC7B;AAAA,cAAA;AAIF,kBAAI,CAACA;AACH;AAGI,oBAAAxD,IAAO,KAAK,MAAMwD,CAAQ;AAGhC,kBAAIxD,EAAK;AACP,sBAAM,IAAI,MAAM,cAAcA,EAAK,MAAM,OAAO,EAAE;AAGpD,kBAAIyD,IAAU,IACVC,IAAS;AAGb,kBAAI1D,EAAK,QAAQ;AACX,oBAAAA,EAAK,OAAO,SAAS;AACvB;oBACSA,EAAK,OAAO,SAAS,WAAWA,EAAK,OAAO;AAC3C,kBAAAyD,IAAAzD,EAAK,OAAO,MAAM;AAAA,yBACnBA,EAAK,OAAO,SAAS,gBAAcuC,KAAAD,IAAAtC,EAAK,OAAO,WAAZ,gBAAAsC,EAAoB,aAApB,QAAAC,EAA+B;AAE3E,sBAAI,CAACU;AACH,oBAAAQ,IAAUzD,EAAK,OAAO,OAAO,SAAS,CAAC,EAAE,SAChC0D,IAAA;AAAA;AAGT;AAAA,cAEJ;AAcF,kBATI,CAACD,KAAW,cAAczD,KAAQ,OAAOA,EAAK,YAAa,aAC7DyD,IAAUzD,EAAK,WAIb,UAAUA,KAAQA,EAAK,SAAS,OACzB0D,IAAA,KAGPD,GAAS;AACL,sBAAAE,IAAUC,EAAeH,GAAST,CAAe;AACvD,gBAAIW,MACiBX,KAAAW,GACEV,IAAA,IACf,MAAA;AAAA,kBACJ,MAAMU;AAAA,kBACN,MAAMD;AAAA,gBACR;AAAA,cACF;AAIF,kBAAIA,GAAQ;AACV,gBAAKT,MAEH,MAAM,EAAE,MAAM,IAAI,MAAM,GAAK;AAE/B;AAAA,cAAA;AAAA,oBAEiB;AAAA,YAAA;AAAA,QAGvB;AAIO,QAAAF,IAAAA,EAAO,MAAMM,CAAc,GAGhCN,EAAO,SAAS,QACTA,IAAAA,EAAO,MAAM,IAAO;AAAA,MAC/B;AAIF,MAAIE,MACF,MAAM,EAAE,MAAM,IAAI,MAAM,GAAK;AAAA,IAC/B,UAEA;AACA,MAAAJ,EAAO,YAAY;AAAA,IAAA;AAIrB,QAAIE,KAAUA,EAAO,WAAW,QAAQ;AAClC,UAAA;AACF,cAAMS,IAAWT,EAAO,MAAM,CAAC,EAAE,KAAK;AAClC,YAAAS,KAAYA,MAAa,UAAU;AAC/B,gBAAAxD,IAAO,KAAK,MAAMwD,CAAQ;AAC5B,eAAAf,KAAAD,IAAAxC,EAAK,WAAL,gBAAAwC,EAAa,UAAb,QAAAC,EAAoB,SAAS;AAC/B,kBAAMkB,IAAUC,EAAe5D,EAAK,OAAO,MAAM,SAASgD,CAAe;AACzE,YAAIW,MACI,MAAA;AAAA,cACJ,MAAMA;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,cAEY;AAAA,MAAA;AAAA,WAKXxD,GAAY;AACf,IAAAA,EAAM,SAAS,eACX,MAAA;AAAA,MACJ,MAAM;AAAA,MACN,MAAM;AAAA,IACR,IACSA,EAAM,SAAS,eAAeA,EAAM,QAAQ,SAAS,iBAAiB,IACzE,MAAA;AAAA,MACJ,MAAM;AAAA,MACN,MAAM;AAAA,IACR,IAEM,MAAA;AAAA,MACJ,MAAM,UAAUA,EAAM,OAAO;AAAA,MAC7B,MAAM;AAAA,IACR;AAAA,EACF;AAEJ;AAGA,SAASyD,EAAeC,GAAsBC,GAA6B;AAErE,SAACA,KAGDD,EAAa,SAASC,EAAY,UAAUD,EAAa,WAAWC,CAAW,IAC1ED,EAAa,MAAMC,EAAY,MAAM,IAJrBD;AAS3B;AAGA,eAAsBE,GAAiBhC,GAAuF;AAC5H,QAAMlC,IAAUN,EAAU,GAEpBO,IAAW,MAAM,MAAM,GAAGD,CAAO,YAAYO,EAAgBP,GAAS;AAAA,IAC1E,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAUiC,EAAsBC,CAAK,CAAC;AAAA,EAAA,CAClD,CAAC;AAEE,MAAA,CAACjC,EAAS,IAAI;AACV,UAAAC,IAAY,MAAMD,EAAS,KAAK;AACtC,UAAM,IAAI,MAAM,gCAAgCA,EAAS,MAAM,IAAIC,CAAS,EAAE;AAAA,EAAA;AAG1E,QAAAC,IAAO,MAAMF,EAAS,KAAK;AACjC,MAAIE,EAAK;AACP,UAAM,IAAI,MAAM,cAAcA,EAAK,MAAM,OAAO,EAAE;AAG7C,SAAAA;AACT;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@schmitech/chatbot-api",
3
3
  "private": false,
4
- "version": "0.4.5",
4
+ "version": "0.5.0",
5
5
  "description": "API client for the ORBIT MCP server",
6
6
  "type": "module",
7
7
  "main": "./dist/api.cjs",