@schmitech/chatbot-api 0.5.0 → 0.5.2

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 secure API key authentication, temporary key exchange, and session tracking.
3
+ A TypeScript/JavaScript client for seamless interaction with the ORBIT server, supporting API key authentication 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, initializeChatbot } from '@schmitech/chatbot-api';
18
+ import { configureApi, streamChat } from '@schmitech/chatbot-api';
19
19
 
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');
20
+ configureApi({
21
+ apiUrl: 'https://your-api-server.com',
22
+ apiKey: 'your-api-key',
23
+ sessionId: 'optional-session-id' // Optional, for conversation tracking
24
+ });
25
25
  ```
26
26
 
27
27
  ### Streaming Chat Example
@@ -36,33 +36,73 @@ async function chat() {
36
36
  }
37
37
  }
38
38
  ```
39
+ ### Local test in Node.js environment
40
+
41
+ First, verify you have `Node.js` and its package manager, `npm`, installed. Then create a new folder.
42
+
43
+ ```bash
44
+ node -v
45
+ npm -v
46
+ ```
47
+
48
+ Initialize a `Node.js` Project
49
+
50
+ ```bash
51
+ npm init -y
52
+ ```
53
+
54
+ Modify `package.json`
55
+
56
+ ```json
57
+ {
58
+ "name": "orbit-node",
59
+ "version": "1.0.0",
60
+ "main": "index.js",
61
+ "type": "module",
62
+ "scripts": {
63
+ "test": "echo \"Error: no test specified\" && exit 1"
64
+ },
65
+ "keywords": [],
66
+ "author": "",
67
+ "license": "ISC",
68
+ "description": "",
69
+ "dependencies": {
70
+ "@schmitech/chatbot-api": "^0.5.0"
71
+ }
72
+ }
73
+ ```
74
+
75
+ Install chatbot api
76
+
77
+ ```bash
78
+ npm install @schmitech/chatbot-api
79
+ ```
80
+
81
+ Run this test
82
+
83
+ ```bash
84
+ node test/test-npm-package.js "how many r are in a strawberry?" "http://localhost:3000" "my-session-123"
85
+ ```
39
86
 
40
87
  ## ⚛️ React Integration
41
88
 
42
89
  Here's how to use the API in a React component:
43
90
 
44
91
  ```tsx
45
- import React, { useState, useEffect } from 'react';
46
- import { configureApi, streamChat, initializeChatbot } from '@schmitech/chatbot-api';
92
+ import React, { useState } from 'react';
93
+ import { configureApi, streamChat } from '@schmitech/chatbot-api';
94
+
95
+ // Configure once at app startup
96
+ configureApi({
97
+ apiUrl: 'https://your-api-server.com',
98
+ apiKey: 'your-api-key',
99
+ sessionId: 'user_123_session_456' // Optional
100
+ });
47
101
 
48
102
  function ChatComponent() {
49
103
  const [messages, setMessages] = useState<Array<{ text: string; isUser: boolean }>>([]);
50
104
  const [input, setInput] = useState('');
51
105
 
52
- useEffect(() => {
53
- // Configure API and initialize secure key exchange
54
- const setupApi = async () => {
55
- try {
56
- configureApi('https://your-api-server.com', 'your-api-key');
57
- await initializeChatbot('your-api-key', window.location.origin);
58
- } catch (error) {
59
- console.error('Failed to initialize secure API:', error);
60
- }
61
- };
62
-
63
- setupApi();
64
- }, []);
65
-
66
106
  const handleSubmit = async (e: React.FormEvent) => {
67
107
  e.preventDefault();
68
108
  setMessages(prev => [...prev, { text: input, isUser: true }]);
@@ -94,17 +134,14 @@ function ChatComponent() {
94
134
  ### React Native Example
95
135
 
96
136
  ```typescript
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
- };
137
+ import { configureApi, streamChat } from '@schmitech/chatbot-api';
138
+
139
+ // Configure once at app startup
140
+ configureApi({
141
+ apiUrl: 'https://your-api-server.com',
142
+ apiKey: 'your-api-key',
143
+ sessionId: 'user_123_session_456' // Optional
144
+ });
108
145
 
109
146
  async function handleChat(message: string) {
110
147
  for await (const response of streamChat(message, true)) {
@@ -123,17 +160,13 @@ You can also use the API directly in the browser via CDN:
123
160
 
124
161
  ```html
125
162
  <script type="module">
126
- import { configureApi, streamChat, initializeChatbot } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api/dist/api.mjs';
127
-
128
- // Configure API and initialize secure key exchange
129
- const setupApi = async () => {
130
- try {
131
- configureApi('https://your-api-server.com', 'your-api-key');
132
- await initializeChatbot('your-api-key', window.location.origin);
133
- } catch (error) {
134
- console.error('Failed to initialize secure API:', error);
135
- }
136
- };
163
+ import { configureApi, streamChat } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api/dist/api.mjs';
164
+
165
+ configureApi({
166
+ apiUrl: 'https://your-api-server.com',
167
+ apiKey: 'your-api-key',
168
+ sessionId: 'your-session-id' // Optional
169
+ });
137
170
 
138
171
  async function handleChat() {
139
172
  for await (const response of streamChat('Hello', true)) {
@@ -145,25 +178,16 @@ You can also use the API directly in the browser via CDN:
145
178
 
146
179
  ## 📚 API Reference
147
180
 
148
- ### `configureApi(apiUrl: string, apiKey?: string, sessionId?: string)`
181
+ ### `configureApi(config)`
149
182
 
150
183
  Configure the API client with server details.
151
184
 
152
185
  | Parameter | Type | Required | Description |
153
186
  |-----------|------|----------|-------------|
154
187
  | `apiUrl` | string | Yes | Chatbot API server URL |
155
- | `apiKey` | string | No | API key for authentication |
188
+ | `apiKey` | string | Yes | API key for authentication |
156
189
  | `sessionId` | string | No | Session ID for conversation tracking |
157
190
 
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
-
167
191
  ### `streamChat(message: string, stream: boolean = true)`
168
192
 
169
193
  Stream chat responses from the server.
@@ -182,19 +206,8 @@ interface StreamResponse {
182
206
  }
183
207
  ```
184
208
 
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
209
+ ## 🔒 Security
195
210
 
196
211
  - Always use HTTPS for your API URL
197
212
  - Keep your API key secure and never expose it in client-side code
198
- - Use environment variables for sensitive configuration
199
- - Implement proper error handling for authentication failures
200
- - Monitor for security events using the `chatbot:auth:failed` event
213
+ - Consider using environment variables for sensitive configuration
package/dist/api.cjs CHANGED
@@ -1,3 +1,3 @@
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;
1
+ "use strict";var S=Object.create;var p=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty;var K=(t,e,r)=>e in t?p(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var U=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of O(e))!T.call(t,s)&&s!==r&&p(t,s,{get:()=>e[s],enumerable:!(n=x(e,s))||n.enumerable});return t};var I=(t,e,r)=>(r=t!=null?S(P(t)):{},U(e||!t||!t.__esModule?p(r,"default",{value:t,enumerable:!0}):r,t));var h=(t,e,r)=>K(t,typeof e!="symbol"?e+"":e,r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let A=null,m=null;typeof window>"u"&&Promise.all([import("http").catch(()=>null),import("https").catch(()=>null)]).then(([t,e])=>{var r,n;(r=t==null?void 0:t.default)!=null&&r.Agent?A=new t.default.Agent({keepAlive:!0}):t!=null&&t.Agent&&(A=new t.Agent({keepAlive:!0})),(n=e==null?void 0:e.default)!=null&&n.Agent?m=new e.default.Agent({keepAlive:!0}):e!=null&&e.Agent&&(m=new e.Agent({keepAlive:!0}))}).catch(t=>{console.warn("Failed to initialize HTTP agents:",t.message)});class b{constructor(e){h(this,"apiUrl");h(this,"apiKey");h(this,"sessionId");if(!e.apiUrl||typeof e.apiUrl!="string")throw new Error("API URL must be a valid string");if(e.apiKey!==void 0&&e.apiKey!==null&&typeof e.apiKey!="string")throw new Error("API key must be a valid string or null");if(e.sessionId!==void 0&&e.sessionId!==null&&typeof e.sessionId!="string")throw new Error("Session ID must be a valid string or null");this.apiUrl=e.apiUrl,this.apiKey=e.apiKey??null,this.sessionId=e.sessionId??null}setSessionId(e){if(e!==null&&typeof e!="string")throw new Error("Session ID must be a valid string or null");this.sessionId=e}getSessionId(){return this.sessionId}getFetchOptions(e={}){const r={};if(typeof window>"u"){const d=this.apiUrl.startsWith("https:")?m:A;d&&(r.agent=d)}else r.headers={Connection:"keep-alive"};const n={"X-Request-ID":Date.now().toString(36)+Math.random().toString(36).substring(2)};return r.headers&&Object.assign(n,r.headers),e.headers&&Object.assign(n,e.headers),this.apiKey&&(n["X-API-Key"]=this.apiKey),this.sessionId&&(n["X-Session-ID"]=this.sessionId),{...e,...r,headers:n}}createChatRequest(e,r=!0){return{messages:[{role:"user",content:e}],stream:r}}async*streamChat(e,r=!0){var n;try{const s=new AbortController,d=setTimeout(()=>s.abort(),6e4),l=await fetch(`${this.apiUrl}/v1/chat`,{...this.getFetchOptions({method:"POST",headers:{"Content-Type":"application/json",Accept:r?"text/event-stream":"application/json"},body:JSON.stringify(this.createChatRequest(e,r))}),signal:s.signal});if(clearTimeout(d),!l.ok){const a=await l.text();throw new Error(`Network response was not ok: ${l.status} ${a}`)}if(!r){const a=await l.json();a.response&&(yield{text:a.response,done:!0});return}const w=(n=l.body)==null?void 0:n.getReader();if(!w)throw new Error("No reader available");const k=new TextDecoder;let i="",g=!1;try{for(;;){const{done:a,value:C}=await w.read();if(a)break;const E=k.decode(C,{stream:!0});i+=E;let c=0,y;for(;(y=i.indexOf(`
2
+ `,c))!==-1;){const u=i.slice(c,y).trim();if(c=y+1,u&&u.startsWith("data: ")){const f=u.slice(6).trim();if(!f||f==="[DONE]"){yield{text:"",done:!0};return}try{const o=JSON.parse(f);if(o.error)throw new Error(`Server Error: ${o.error.message}`);if(o.response&&(g=!0,yield{text:o.response,done:o.done||!1}),o.done){yield{text:"",done:!0};return}}catch(o){console.warn("Error parsing JSON chunk:",o,"Chunk:",f)}}else u&&(g=!0,yield{text:u,done:!1})}i=i.slice(c),i.length>1e6&&(console.warn("Buffer too large, truncating..."),i=i.slice(-5e5))}g&&(yield{text:"",done:!0})}finally{w.releaseLock()}}catch(s){throw s.name==="AbortError"?new Error("Connection timed out. Please check if the server is running."):s.name==="TypeError"&&s.message.includes("Failed to fetch")?new Error("Could not connect to the server. Please check if the server is running."):s}}}let v=null;const j=(t,e=null,r=null)=>{v=new b({apiUrl:t,apiKey:e,sessionId:r})};async function*D(t,e=!0){if(!v)throw new Error("API not configured. Please call configureApi() with your server URL before using any API functions.");yield*v.streamChat(t,e)}exports.ApiClient=b;exports.configureApi=j;exports.streamChat=D;
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// Temporary key management\nlet sessionId: string | null = null;\nlet keyRefreshTimer: number | null = null;\n\n// Key Exchange Response interface\ninterface KeyExchangeResponse {\n temporaryKey: string;\n sessionId: string;\n expiresIn: number; // seconds\n expiresAt: number; // timestamp\n}\n\n// Configure the API with a custom URL, API key (optional), and session ID (optional)\nexport const configureApi = (apiUrl: string, apiKey: string | null = null, sessionId: string | null = null): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (apiKey !== null && typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n configuredSessionId = sessionId;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or return null if not configured\nconst getApiKey = (): string | null => {\n return configuredApiKey;\n};\n\n// Get the configured session ID or return null if not configured\nconst getSessionId = (): string | null => {\n return configuredSessionId;\n};\n\n// Initialize chatbot with temporary key exchange\nexport const initializeChatbot = async (permanentApiKey: string, customOrigin?: string): Promise<void> => {\n try {\n const API_URL = getApiUrl();\n \n // Exchange permanent key for temporary session key\n const response = await fetch(`${API_URL}/api/v1/exchange-key`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n apiKey: permanentApiKey,\n origin: customOrigin || (typeof window !== 'undefined' ? window.location.origin : 'node-client')\n })\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to exchange API key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Store only the temporary key and session\n sessionId = data.sessionId;\n configuredApiKey = data.temporaryKey; // Use temporary key as the main API key\n configuredSessionId = data.sessionId;\n \n // Clear permanent key from memory (security measure)\n permanentApiKey = '';\n \n // Set up auto-refresh (90% of expiry time)\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any; \n } catch (error) {\n throw error;\n }\n};\n\n// Refresh temporary key before it expires\nconst refreshTemporaryKey = async (): Promise<void> => {\n if (!sessionId) return;\n \n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/api/v1/refresh-key`, {\n method: 'POST',\n headers: { \n 'Content-Type': 'application/json',\n 'X-Session-ID': sessionId,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : 'node-client'\n }\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to refresh key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Update keys\n configuredApiKey = data.temporaryKey;\n \n // Reset timer\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any;\n } catch (error) {\n // Emit event for handling by consumer\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent('chatbot:auth:failed', { detail: error }));\n }\n }\n};\n\n// Helper to get fetch options with connection pooling and enhanced security\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment with enhanced security headers\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n const timestamp = Date.now();\n \n // Enhanced security headers\n const headers: Record<string, string> = {\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId,\n 'X-Timestamp': timestamp.toString()\n };\n \n // Add origin and referrer for security validation\n if (typeof window !== 'undefined') {\n headers['X-Origin'] = window.location.origin;\n headers['X-Referrer'] = document.referrer || 'direct';\n }\n \n // Add API key to headers only if it exists\n const apiKey = getApiKey();\n if (apiKey) {\n headers['X-API-Key'] = apiKey;\n \n // Add request signature for enhanced security\n if (typeof window !== 'undefined') {\n headers['X-Signature'] = generateRequestSignature(\n requestId,\n timestamp,\n options.body\n );\n }\n }\n \n // Add session ID to headers only if it exists\n const sessionId = getSessionId();\n if (sessionId) {\n headers['X-Session-ID'] = sessionId;\n }\n \n return {\n ...options,\n headers: {\n ...options.headers,\n ...headers\n }\n };\n};\n\n// Generate request signature for enhanced security\nconst generateRequestSignature = (\n requestId: string, \n timestamp: number, \n body?: any\n): string => {\n const payload = `${requestId}:${timestamp}:${body ? JSON.stringify(body) : ''}`;\n // Simple base64 encoding - in production, you should use HMAC\n return btoa(payload).substring(0, 16);\n};\n\n// Rate limiter implementation\nclass RateLimiter {\n private requests: Map<string, number[]> = new Map();\n \n canMakeRequest(\n identifier: string, \n maxRequests: number = 20, \n windowMs: number = 60000\n ): boolean {\n const now = Date.now();\n const userRequests = this.requests.get(identifier) || [];\n const recentRequests = userRequests.filter(time => now - time < windowMs);\n \n if (recentRequests.length >= maxRequests) {\n return false;\n }\n \n recentRequests.push(now);\n this.requests.set(identifier, recentRequests);\n \n // Cleanup old entries\n if (this.requests.size > 1000) {\n this.cleanup(windowMs);\n }\n \n return true;\n }\n \n private cleanup(windowMs: number): void {\n const now = Date.now();\n for (const [key, requests] of this.requests.entries()) {\n const recent = requests.filter(time => now - time < windowMs);\n if (recent.length === 0) {\n this.requests.delete(key);\n } else {\n this.requests.set(key, recent);\n }\n }\n }\n}\n\n// Global rate limiter instance\nconst rateLimiter = new RateLimiter();\n\n// Security monitoring (client-side)\nconst securityMonitor = {\n config: {\n monitoring: {\n enabled: true\n }\n },\n\n async loadConfig(): Promise<void> {\n try {\n const API_URL = getApiUrl();\n const response = await fetch(`${API_URL}/api/v1/security/config`);\n if (response.ok) {\n const config = await response.json();\n if (config.monitoring) {\n this.config.monitoring = {\n ...this.config.monitoring,\n ...config.monitoring\n };\n }\n }\n } catch (e) {\n // Fail silently, use default config\n }\n },\n\n detectDevTools(): boolean {\n if (typeof window === 'undefined') return false;\n const threshold = 160;\n return (window.outerHeight - window.innerHeight > threshold) || \n (window.outerWidth - window.innerWidth > threshold);\n },\n \n async init(): Promise<void> {\n if (typeof window === 'undefined') return;\n \n // Load configuration first\n await this.loadConfig();\n }\n};\n\n// Initialize security monitoring if in browser\nif (typeof window !== 'undefined') {\n securityMonitor.init().catch(() => {\n // Fail silently, security monitoring will use default config\n });\n}\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n // Check rate limiting\n const sessionIdentifier = getSessionId() || 'anonymous';\n \n if (!rateLimiter.canMakeRequest(sessionIdentifier, 20, 60000)) {\n yield { \n text: 'Rate limit exceeded. Please wait a moment before sending more messages.', \n done: true \n };\n return;\n }\n \n const API_URL = getApiUrl();\n \n // Add timeout to the fetch request\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 second timeout\n\n const response = await fetch(`${API_URL}/v1/chat`, {\n ...getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n let hasReceivedContent = false;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n \n // Process complete lines immediately as they arrive\n let lineStartIndex = 0;\n let newlineIndex;\n \n while ((newlineIndex = buffer.indexOf('\\n', lineStartIndex)) !== -1) {\n const line = buffer.slice(lineStartIndex, newlineIndex).trim();\n lineStartIndex = newlineIndex + 1;\n \n if (line && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n \n // Check for [DONE] message (legacy format)\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n return;\n }\n\n // Skip empty data lines\n if (!jsonText) {\n continue;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n // Handle errors\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n \n let content = '';\n let isDone = false;\n \n // Handle MCP protocol format\n if (data.result) {\n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n // For complete messages, only yield if we haven't received any content yet\n if (!hasReceivedContent) {\n content = data.result.output.messages[0].content;\n isDone = true;\n } else {\n // Skip the complete message if we've already received chunks\n continue;\n }\n }\n }\n \n // Handle direct server response format (from LLM clients)\n // This is what the server actually sends: { \"response\": \"...\", \"done\": false/true }\n if (!content && 'response' in data && typeof data.response === 'string') {\n content = data.response;\n }\n \n // Check for done signal in the data\n if ('done' in data && data.done === true) {\n isDone = true;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n hasReceivedContent = true;\n yield {\n text: newText,\n done: isDone\n };\n }\n }\n \n // If we received a done signal, exit\n if (isDone) {\n if (!hasReceivedContent) {\n // Yield empty response to indicate completion\n yield { text: '', done: true };\n }\n return;\n }\n } catch (parseError) {\n // Don't throw, just continue processing\n }\n }\n }\n \n // Keep remaining incomplete line in buffer\n buffer = buffer.slice(lineStartIndex);\n \n // Prevent buffer from growing too large\n if (buffer.length > 1000000) { // 1MB limit\n buffer = buffer.slice(-500000); // Keep last 500KB\n }\n }\n \n // If we exit the while loop naturally, ensure we send a done signal\n if (hasReceivedContent) {\n yield { text: '', done: true };\n }\n \n } finally {\n reader.releaseLock();\n }\n\n // Handle any remaining buffer (fallback)\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText && jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: true\n };\n }\n }\n }\n } catch (error) {\n // Fail silently for final buffer parsing\n }\n }\n \n } catch (error: any) {\n if (error.name === 'AbortError') {\n yield { \n text: 'Connection timed out. Please check if the server is running.', \n done: true \n };\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n yield { \n text: 'Could not connect to the server. Please check if the server is running.', \n done: true \n };\n } else {\n yield { \n text: `Error: ${error.message}`, \n done: true \n };\n }\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n // Simplified version - just check if we have new content at the end\n if (!currentText) return incomingText;\n \n // If incoming text is longer and starts with current text, return the new part\n if (incomingText.length > currentText.length && incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n // Otherwise return the full incoming text (fallback)\n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configuredSessionId","sessionId","keyRefreshTimer","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getSessionId","initializeChatbot","permanentApiKey","customOrigin","API_URL","response","errorText","data","refreshInterval","refreshTemporaryKey","error","getFetchOptions","options","requestId","timestamp","headers","generateRequestSignature","body","payload","RateLimiter","__publicField","identifier","maxRequests","windowMs","now","recentRequests","time","key","requests","recent","rateLimiter","securityMonitor","config","threshold","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","sessionIdentifier","controller","timeoutId","_d","_c","_b","_a","reader","_e","decoder","buffer","currentFullText","hasReceivedContent","done","value","chunk","lineStartIndex","newlineIndex","line","jsonText","content","isDone","_g","_f","newText","extractNewText","_i","_h","incomingText","currentText","sendToolsRequest"],"mappings":"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"}
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// Initialize agents for connection pooling in Node.js environments\nif (typeof window === 'undefined') {\n // Lazy load to avoid including 'http' in browser bundles\n Promise.all([\n import('http').catch(() => null),\n import('https').catch(() => null)\n ]).then(([http, https]) => {\n if (http?.default?.Agent) {\n httpAgent = new http.default.Agent({ keepAlive: true });\n } else if (http?.Agent) {\n httpAgent = new http.Agent({ keepAlive: true });\n }\n \n if (https?.default?.Agent) {\n httpsAgent = new https.default.Agent({ keepAlive: true });\n } else if (https?.Agent) {\n httpsAgent = new https.Agent({ keepAlive: true });\n }\n }).catch(err => {\n // Silently fail - connection pooling is optional\n console.warn('Failed to initialize HTTP agents:', err.message);\n });\n}\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\n// The server now returns this directly for non-streaming chat\nexport interface ChatResponse {\n response: string;\n sources?: any[];\n}\n\n// The request body for the /v1/chat endpoint\ninterface ChatRequest {\n messages: Array<{ role: string; content: string; }>;\n stream: boolean;\n}\n\nexport class ApiClient {\n private readonly apiUrl: string;\n private readonly apiKey: string | null;\n private sessionId: string | null; // Session ID can be mutable\n\n constructor(config: { apiUrl: string; apiKey?: string | null; sessionId?: string | null }) {\n if (!config.apiUrl || typeof config.apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (config.apiKey !== undefined && config.apiKey !== null && typeof config.apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (config.sessionId !== undefined && config.sessionId !== null && typeof config.sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n \n this.apiUrl = config.apiUrl;\n this.apiKey = config.apiKey ?? null;\n this.sessionId = config.sessionId ?? null;\n }\n\n public setSessionId(sessionId: string | null): void {\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n this.sessionId = sessionId;\n }\n\n public getSessionId(): string | null {\n return this.sessionId;\n }\n\n // Helper to get fetch options with connection pooling if available\n private getFetchOptions(options: RequestInit = {}): RequestInit {\n const baseOptions: RequestInit = {};\n \n // Environment-specific options\n if (typeof window === 'undefined') {\n // Node.js: Use connection pooling agent\n const isHttps = this.apiUrl.startsWith('https:');\n const agent = isHttps ? httpsAgent : httpAgent;\n if (agent) {\n (baseOptions as any).agent = agent;\n }\n } else {\n // Browser: Use keep-alive header\n baseOptions.headers = { 'Connection': 'keep-alive' };\n }\n\n // Common headers\n const headers: Record<string, string> = {\n 'X-Request-ID': Date.now().toString(36) + Math.random().toString(36).substring(2),\n };\n\n // Merge base options headers (for browser keep-alive)\n if (baseOptions.headers) {\n Object.assign(headers, baseOptions.headers);\n }\n\n // Merge original request headers\n if (options.headers) {\n Object.assign(headers, options.headers);\n }\n\n if (this.apiKey) {\n headers['X-API-Key'] = this.apiKey;\n }\n\n if (this.sessionId) {\n headers['X-Session-ID'] = this.sessionId;\n }\n\n return {\n ...options,\n ...baseOptions,\n headers,\n };\n }\n\n // Create Chat request\n private createChatRequest(message: string, stream: boolean = true): ChatRequest {\n return {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n };\n }\n\n public async *streamChat(\n message: string,\n stream: boolean = true\n ): AsyncGenerator<StreamResponse> {\n try {\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(`${this.apiUrl}/v1/chat`, {\n ...this.getFetchOptions({\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(this.createChatRequest(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 ChatResponse;\n if (data.response) {\n yield {\n text: data.response,\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 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 const jsonText = line.slice(6).trim();\n \n if (!jsonText || jsonText === '[DONE]') {\n yield { text: '', done: true };\n return;\n }\n\n try {\n const data = JSON.parse(jsonText);\n \n if (data.error) {\n throw new Error(`Server Error: ${data.error.message}`);\n }\n \n if (data.response) {\n hasReceivedContent = true;\n yield { text: data.response, done: data.done || false };\n }\n\n if (data.done) {\n yield { text: '', done: true };\n return;\n }\n \n } catch (parseError) {\n console.warn('Error parsing JSON chunk:', parseError, 'Chunk:', jsonText);\n }\n } else if (line) {\n // Handle raw text chunks that are not in SSE format\n hasReceivedContent = true;\n yield { text: line, done: false };\n }\n }\n \n buffer = buffer.slice(lineStartIndex);\n \n if (buffer.length > 1000000) { // 1MB limit\n console.warn('Buffer too large, truncating...');\n buffer = buffer.slice(-500000); // Keep last 500KB\n }\n }\n \n if (hasReceivedContent) {\n yield { text: '', done: true };\n }\n \n } finally {\n reader.releaseLock();\n }\n \n } catch (error: any) {\n if (error.name === 'AbortError') {\n throw new Error('Connection timed out. Please check if the server is running.');\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n throw new Error('Could not connect to the server. Please check if the server is running.');\n } else {\n throw error;\n }\n }\n }\n}\n\n// Legacy compatibility functions - these create a default client instance\n// These are kept for backward compatibility but should be deprecated in favor of the class-based approach\n\nlet defaultClient: ApiClient | 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 defaultClient = new ApiClient({ apiUrl, apiKey, sessionId });\n}\n\n// Legacy streamChat function that uses the default client\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n if (!defaultClient) {\n throw new Error('API not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n \n yield* defaultClient.streamChat(message, stream);\n}\n"],"names":["httpAgent","httpsAgent","http","https","_a","_b","err","ApiClient","config","__publicField","sessionId","options","baseOptions","agent","headers","message","stream","controller","timeoutId","response","errorText","data","reader","decoder","buffer","hasReceivedContent","done","value","chunk","lineStartIndex","newlineIndex","line","jsonText","parseError","error","defaultClient","configureApi","apiUrl","apiKey","streamChat"],"mappings":"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"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ export interface StreamResponse {
2
+ text: string;
3
+ done: boolean;
4
+ }
5
+ export interface ChatResponse {
6
+ response: string;
7
+ sources?: any[];
8
+ }
9
+ export declare class ApiClient {
10
+ private readonly apiUrl;
11
+ private readonly apiKey;
12
+ private sessionId;
13
+ constructor(config: {
14
+ apiUrl: string;
15
+ apiKey?: string | null;
16
+ sessionId?: string | null;
17
+ });
18
+ setSessionId(sessionId: string | null): void;
19
+ getSessionId(): string | null;
20
+ private getFetchOptions;
21
+ private createChatRequest;
22
+ streamChat(message: string, stream?: boolean): AsyncGenerator<StreamResponse>;
23
+ }
24
+ export declare const configureApi: (apiUrl: string, apiKey?: string | null, sessionId?: string | null) => void;
25
+ export declare function streamChat(message: string, stream?: boolean): AsyncGenerator<StreamResponse>;
package/dist/api.mjs CHANGED
@@ -1,305 +1,147 @@
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) => {
6
- if (!t || typeof t != "string")
7
- throw new Error("API URL must be a valid string");
8
- if (e !== null && typeof e != "string")
9
- throw new Error("API key must be a valid string or null");
10
- if (n !== null && typeof n != "string")
11
- throw new Error("Session ID must be a valid string or null");
12
- v = t, S = e, q = n;
13
- }, w = () => {
14
- if (!v)
15
- throw new Error("API URL not configured. Please call configureApi() with your server URL before using any API functions.");
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 = {}) => {
61
- t.startsWith("https:");
62
- const n = Date.now().toString(36) + Math.random().toString(36).substring(2), r = Date.now(), o = {
63
- Connection: "keep-alive",
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), {
76
- ...e,
77
- headers: {
78
- ...e.headers,
79
- ...o
80
- }
81
- };
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());
1
+ var k = Object.defineProperty;
2
+ var E = (t, e, r) => e in t ? k(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r;
3
+ var w = (t, e, r) => E(t, typeof e != "symbol" ? e + "" : e, r);
4
+ let p = null, A = null;
5
+ typeof window > "u" && Promise.all([
6
+ import("http").catch(() => null),
7
+ import("https").catch(() => null)
8
+ ]).then(([t, e]) => {
9
+ var r, n;
10
+ (r = t == null ? void 0 : t.default) != null && r.Agent ? p = new t.default.Agent({ keepAlive: !0 }) : t != null && t.Agent && (p = new t.Agent({ keepAlive: !0 })), (n = e == null ? void 0 : e.default) != null && n.Agent ? A = new e.default.Agent({ keepAlive: !0 }) : e != null && e.Agent && (A = new e.Agent({ keepAlive: !0 }));
11
+ }).catch((t) => {
12
+ console.warn("Failed to initialize HTTP agents:", t.message);
13
+ });
14
+ class x {
15
+ // Session ID can be mutable
16
+ constructor(e) {
17
+ w(this, "apiUrl");
18
+ w(this, "apiKey");
19
+ w(this, "sessionId");
20
+ if (!e.apiUrl || typeof e.apiUrl != "string")
21
+ throw new Error("API URL must be a valid string");
22
+ if (e.apiKey !== void 0 && e.apiKey !== null && typeof e.apiKey != "string")
23
+ throw new Error("API key must be a valid string or null");
24
+ if (e.sessionId !== void 0 && e.sessionId !== null && typeof e.sessionId != "string")
25
+ throw new Error("Session ID must be a valid string or null");
26
+ this.apiUrl = e.apiUrl, this.apiKey = e.apiKey ?? null, this.sessionId = e.sessionId ?? null;
89
27
  }
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);
28
+ setSessionId(e) {
29
+ if (e !== null && typeof e != "string")
30
+ throw new Error("Session ID must be a valid string or null");
31
+ this.sessionId = e;
93
32
  }
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
- }
33
+ getSessionId() {
34
+ return this.sessionId;
100
35
  }
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();
36
+ // Helper to get fetch options with connection pooling if available
37
+ getFetchOptions(e = {}) {
38
+ const r = {};
39
+ if (typeof window > "u") {
40
+ const u = this.apiUrl.startsWith("https:") ? A : p;
41
+ u && (r.agent = u);
42
+ } else
43
+ r.headers = { Connection: "keep-alive" };
44
+ const n = {
45
+ "X-Request-ID": Date.now().toString(36) + Math.random().toString(36).substring(2)
46
+ };
47
+ return r.headers && Object.assign(n, r.headers), e.headers && Object.assign(n, e.headers), this.apiKey && (n["X-API-Key"] = this.apiKey), this.sessionId && (n["X-Session-ID"] = this.sessionId), {
48
+ ...e,
49
+ ...r,
50
+ headers: n
51
+ };
128
52
  }
129
- };
130
- typeof window < "u" && G.init().catch(() => {
131
- });
132
- const Q = (t, e = !0) => ({
133
- jsonrpc: "2.0",
134
- method: "tools/call",
135
- params: {
136
- name: "chat",
137
- arguments: {
53
+ // Create Chat request
54
+ createChatRequest(e, r = !0) {
55
+ return {
138
56
  messages: [
139
- { role: "user", content: t }
57
+ { role: "user", content: e }
140
58
  ],
141
- stream: e
142
- }
143
- },
144
- id: Date.now().toString(36) + Math.random().toString(36).substring(2)
145
- }), V = (t) => ({
146
- jsonrpc: "2.0",
147
- method: "tools/call",
148
- params: {
149
- name: "tools",
150
- arguments: {
151
- tools: t
152
- }
153
- },
154
- id: Date.now().toString(36) + Math.random().toString(36).substring(2)
155
- });
156
- async function* te(t, e = !0) {
157
- var n, r, o, c, i, g, A, C, O;
158
- try {
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, {
169
- method: "POST",
170
- headers: {
171
- "Content-Type": "application/json",
172
- Accept: e ? "text/event-stream" : "application/json"
173
- },
174
- body: JSON.stringify(Q(t, e))
175
- }),
176
- signal: j.signal
177
- });
178
- if (clearTimeout(J), !h.ok) {
179
- const a = await h.text();
180
- throw new Error(`Network response was not ok: ${h.status} ${a}`);
181
- }
182
- if (!e) {
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,
188
- done: !0
189
- });
190
- return;
191
- }
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;
59
+ stream: r
60
+ };
61
+ }
62
+ async *streamChat(e, r = !0) {
63
+ var n;
196
64
  try {
197
- for (; ; ) {
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: "))
208
- try {
209
- const x = b.slice(6).trim();
210
- if (x === "[DONE]") {
65
+ const s = new AbortController(), u = setTimeout(() => s.abort(), 6e4), l = await fetch(`${this.apiUrl}/v1/chat`, {
66
+ ...this.getFetchOptions({
67
+ method: "POST",
68
+ headers: {
69
+ "Content-Type": "application/json",
70
+ Accept: r ? "text/event-stream" : "application/json"
71
+ },
72
+ body: JSON.stringify(this.createChatRequest(e, r))
73
+ }),
74
+ signal: s.signal
75
+ });
76
+ if (clearTimeout(u), !l.ok) {
77
+ const a = await l.text();
78
+ throw new Error(`Network response was not ok: ${l.status} ${a}`);
79
+ }
80
+ if (!r) {
81
+ const a = await l.json();
82
+ a.response && (yield {
83
+ text: a.response,
84
+ done: !0
85
+ });
86
+ return;
87
+ }
88
+ const h = (n = l.body) == null ? void 0 : n.getReader();
89
+ if (!h) throw new Error("No reader available");
90
+ const I = new TextDecoder();
91
+ let i = "", g = !1;
92
+ try {
93
+ for (; ; ) {
94
+ const { done: a, value: v } = await h.read();
95
+ if (a)
96
+ break;
97
+ const b = I.decode(v, { stream: !0 });
98
+ i += b;
99
+ let c = 0, y;
100
+ for (; (y = i.indexOf(`
101
+ `, c)) !== -1; ) {
102
+ const d = i.slice(c, y).trim();
103
+ if (c = y + 1, d && d.startsWith("data: ")) {
104
+ const f = d.slice(6).trim();
105
+ if (!f || f === "[DONE]") {
211
106
  yield { text: "", done: !0 };
212
107
  return;
213
108
  }
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;
220
- if (s.result) {
221
- if (s.result.type === "start")
222
- continue;
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;
230
- }
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
- });
109
+ try {
110
+ const o = JSON.parse(f);
111
+ if (o.error)
112
+ throw new Error(`Server Error: ${o.error.message}`);
113
+ if (o.response && (g = !0, yield { text: o.response, done: o.done || !1 }), o.done) {
114
+ yield { text: "", done: !0 };
115
+ return;
116
+ }
117
+ } catch (o) {
118
+ console.warn("Error parsing JSON chunk:", o, "Chunk:", f);
237
119
  }
238
- if (I) {
239
- p || (yield { text: "", done: !0 });
240
- return;
241
- }
242
- } catch {
243
- }
244
- }
245
- u = u.slice(k), u.length > 1e6 && (u = u.slice(-5e5));
246
- }
247
- p && (yield { text: "", done: !0 });
248
- } finally {
249
- T.releaseLock();
250
- }
251
- if (u && u.startsWith("data: "))
252
- try {
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
261
- });
120
+ } else d && (g = !0, yield { text: d, done: !1 });
262
121
  }
122
+ i = i.slice(c), i.length > 1e6 && (console.warn("Buffer too large, truncating..."), i = i.slice(-5e5));
263
123
  }
264
- } catch {
124
+ g && (yield { text: "", done: !0 });
125
+ } finally {
126
+ h.releaseLock();
265
127
  }
266
- } catch (l) {
267
- l.name === "AbortError" ? yield {
268
- text: "Connection timed out. Please check if the server is running.",
269
- done: !0
270
- } : l.name === "TypeError" && l.message.includes("Failed to fetch") ? yield {
271
- text: "Could not connect to the server. Please check if the server is running.",
272
- done: !0
273
- } : yield {
274
- text: `Error: ${l.message}`,
275
- done: !0
276
- };
128
+ } catch (s) {
129
+ throw s.name === "AbortError" ? new Error("Connection timed out. Please check if the server is running.") : s.name === "TypeError" && s.message.includes("Failed to fetch") ? new Error("Could not connect to the server. Please check if the server is running.") : s;
130
+ }
277
131
  }
278
132
  }
279
- function L(t, e) {
280
- return e && t.length > e.length && t.startsWith(e) ? t.slice(e.length) : t;
281
- }
282
- async function ne(t) {
283
- const e = w(), n = await fetch(`${e}/v1/chat`, X(e, {
284
- method: "POST",
285
- headers: {
286
- "Content-Type": "application/json"
287
- },
288
- body: JSON.stringify(V(t))
289
- }));
290
- if (!n.ok) {
291
- const o = await n.text();
292
- throw new Error(`Network response was not ok: ${n.status} ${o}`);
293
- }
294
- const r = await n.json();
295
- if (r.error)
296
- throw new Error(`MCP Error: ${r.error.message}`);
297
- return r;
133
+ let m = null;
134
+ const S = (t, e = null, r = null) => {
135
+ m = new x({ apiUrl: t, apiKey: e, sessionId: r });
136
+ };
137
+ async function* O(t, e = !0) {
138
+ if (!m)
139
+ throw new Error("API not configured. Please call configureApi() with your server URL before using any API functions.");
140
+ yield* m.streamChat(t, e);
298
141
  }
299
142
  export {
300
- Z as configureApi,
301
- ee as initializeChatbot,
302
- ne as sendToolsRequest,
303
- te as streamChat
143
+ x as ApiClient,
144
+ S as configureApi,
145
+ O as streamChat
304
146
  };
305
147
  //# 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// Temporary key management\nlet sessionId: string | null = null;\nlet keyRefreshTimer: number | null = null;\n\n// Key Exchange Response interface\ninterface KeyExchangeResponse {\n temporaryKey: string;\n sessionId: string;\n expiresIn: number; // seconds\n expiresAt: number; // timestamp\n}\n\n// Configure the API with a custom URL, API key (optional), and session ID (optional)\nexport const configureApi = (apiUrl: string, apiKey: string | null = null, sessionId: string | null = null): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (apiKey !== null && typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n configuredSessionId = sessionId;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or return null if not configured\nconst getApiKey = (): string | null => {\n return configuredApiKey;\n};\n\n// Get the configured session ID or return null if not configured\nconst getSessionId = (): string | null => {\n return configuredSessionId;\n};\n\n// Initialize chatbot with temporary key exchange\nexport const initializeChatbot = async (permanentApiKey: string, customOrigin?: string): Promise<void> => {\n try {\n const API_URL = getApiUrl();\n \n // Exchange permanent key for temporary session key\n const response = await fetch(`${API_URL}/api/v1/exchange-key`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n apiKey: permanentApiKey,\n origin: customOrigin || (typeof window !== 'undefined' ? window.location.origin : 'node-client')\n })\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to exchange API key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Store only the temporary key and session\n sessionId = data.sessionId;\n configuredApiKey = data.temporaryKey; // Use temporary key as the main API key\n configuredSessionId = data.sessionId;\n \n // Clear permanent key from memory (security measure)\n permanentApiKey = '';\n \n // Set up auto-refresh (90% of expiry time)\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any; \n } catch (error) {\n throw error;\n }\n};\n\n// Refresh temporary key before it expires\nconst refreshTemporaryKey = async (): Promise<void> => {\n if (!sessionId) return;\n \n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/api/v1/refresh-key`, {\n method: 'POST',\n headers: { \n 'Content-Type': 'application/json',\n 'X-Session-ID': sessionId,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : 'node-client'\n }\n });\n \n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to refresh key: ${response.status} ${errorText}`);\n }\n \n const data: KeyExchangeResponse = await response.json();\n \n // Update keys\n configuredApiKey = data.temporaryKey;\n \n // Reset timer\n if (keyRefreshTimer) {\n clearTimeout(keyRefreshTimer);\n }\n const refreshInterval = data.expiresIn * 0.9 * 1000;\n keyRefreshTimer = setTimeout(() => refreshTemporaryKey(), refreshInterval) as any;\n } catch (error) {\n // Emit event for handling by consumer\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent('chatbot:auth:failed', { detail: error }));\n }\n }\n};\n\n// Helper to get fetch options with connection pooling and enhanced security\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment with enhanced security headers\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n const timestamp = Date.now();\n \n // Enhanced security headers\n const headers: Record<string, string> = {\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId,\n 'X-Timestamp': timestamp.toString()\n };\n \n // Add origin and referrer for security validation\n if (typeof window !== 'undefined') {\n headers['X-Origin'] = window.location.origin;\n headers['X-Referrer'] = document.referrer || 'direct';\n }\n \n // Add API key to headers only if it exists\n const apiKey = getApiKey();\n if (apiKey) {\n headers['X-API-Key'] = apiKey;\n \n // Add request signature for enhanced security\n if (typeof window !== 'undefined') {\n headers['X-Signature'] = generateRequestSignature(\n requestId,\n timestamp,\n options.body\n );\n }\n }\n \n // Add session ID to headers only if it exists\n const sessionId = getSessionId();\n if (sessionId) {\n headers['X-Session-ID'] = sessionId;\n }\n \n return {\n ...options,\n headers: {\n ...options.headers,\n ...headers\n }\n };\n};\n\n// Generate request signature for enhanced security\nconst generateRequestSignature = (\n requestId: string, \n timestamp: number, \n body?: any\n): string => {\n const payload = `${requestId}:${timestamp}:${body ? JSON.stringify(body) : ''}`;\n // Simple base64 encoding - in production, you should use HMAC\n return btoa(payload).substring(0, 16);\n};\n\n// Rate limiter implementation\nclass RateLimiter {\n private requests: Map<string, number[]> = new Map();\n \n canMakeRequest(\n identifier: string, \n maxRequests: number = 20, \n windowMs: number = 60000\n ): boolean {\n const now = Date.now();\n const userRequests = this.requests.get(identifier) || [];\n const recentRequests = userRequests.filter(time => now - time < windowMs);\n \n if (recentRequests.length >= maxRequests) {\n return false;\n }\n \n recentRequests.push(now);\n this.requests.set(identifier, recentRequests);\n \n // Cleanup old entries\n if (this.requests.size > 1000) {\n this.cleanup(windowMs);\n }\n \n return true;\n }\n \n private cleanup(windowMs: number): void {\n const now = Date.now();\n for (const [key, requests] of this.requests.entries()) {\n const recent = requests.filter(time => now - time < windowMs);\n if (recent.length === 0) {\n this.requests.delete(key);\n } else {\n this.requests.set(key, recent);\n }\n }\n }\n}\n\n// Global rate limiter instance\nconst rateLimiter = new RateLimiter();\n\n// Security monitoring (client-side)\nconst securityMonitor = {\n config: {\n monitoring: {\n enabled: true\n }\n },\n\n async loadConfig(): Promise<void> {\n try {\n const API_URL = getApiUrl();\n const response = await fetch(`${API_URL}/api/v1/security/config`);\n if (response.ok) {\n const config = await response.json();\n if (config.monitoring) {\n this.config.monitoring = {\n ...this.config.monitoring,\n ...config.monitoring\n };\n }\n }\n } catch (e) {\n // Fail silently, use default config\n }\n },\n\n detectDevTools(): boolean {\n if (typeof window === 'undefined') return false;\n const threshold = 160;\n return (window.outerHeight - window.innerHeight > threshold) || \n (window.outerWidth - window.innerWidth > threshold);\n },\n \n async init(): Promise<void> {\n if (typeof window === 'undefined') return;\n \n // Load configuration first\n await this.loadConfig();\n }\n};\n\n// Initialize security monitoring if in browser\nif (typeof window !== 'undefined') {\n securityMonitor.init().catch(() => {\n // Fail silently, security monitoring will use default config\n });\n}\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n // Check rate limiting\n const sessionIdentifier = getSessionId() || 'anonymous';\n \n if (!rateLimiter.canMakeRequest(sessionIdentifier, 20, 60000)) {\n yield { \n text: 'Rate limit exceeded. Please wait a moment before sending more messages.', \n done: true \n };\n return;\n }\n \n const API_URL = getApiUrl();\n \n // Add timeout to the fetch request\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 second timeout\n\n const response = await fetch(`${API_URL}/v1/chat`, {\n ...getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n let hasReceivedContent = false;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n \n // Process complete lines immediately as they arrive\n let lineStartIndex = 0;\n let newlineIndex;\n \n while ((newlineIndex = buffer.indexOf('\\n', lineStartIndex)) !== -1) {\n const line = buffer.slice(lineStartIndex, newlineIndex).trim();\n lineStartIndex = newlineIndex + 1;\n \n if (line && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n \n // Check for [DONE] message (legacy format)\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n return;\n }\n\n // Skip empty data lines\n if (!jsonText) {\n continue;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n // Handle errors\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n \n let content = '';\n let isDone = false;\n \n // Handle MCP protocol format\n if (data.result) {\n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n // For complete messages, only yield if we haven't received any content yet\n if (!hasReceivedContent) {\n content = data.result.output.messages[0].content;\n isDone = true;\n } else {\n // Skip the complete message if we've already received chunks\n continue;\n }\n }\n }\n \n // Handle direct server response format (from LLM clients)\n // This is what the server actually sends: { \"response\": \"...\", \"done\": false/true }\n if (!content && 'response' in data && typeof data.response === 'string') {\n content = data.response;\n }\n \n // Check for done signal in the data\n if ('done' in data && data.done === true) {\n isDone = true;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n hasReceivedContent = true;\n yield {\n text: newText,\n done: isDone\n };\n }\n }\n \n // If we received a done signal, exit\n if (isDone) {\n if (!hasReceivedContent) {\n // Yield empty response to indicate completion\n yield { text: '', done: true };\n }\n return;\n }\n } catch (parseError) {\n // Don't throw, just continue processing\n }\n }\n }\n \n // Keep remaining incomplete line in buffer\n buffer = buffer.slice(lineStartIndex);\n \n // Prevent buffer from growing too large\n if (buffer.length > 1000000) { // 1MB limit\n buffer = buffer.slice(-500000); // Keep last 500KB\n }\n }\n \n // If we exit the while loop naturally, ensure we send a done signal\n if (hasReceivedContent) {\n yield { text: '', done: true };\n }\n \n } finally {\n reader.releaseLock();\n }\n\n // Handle any remaining buffer (fallback)\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText && jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: true\n };\n }\n }\n }\n } catch (error) {\n // Fail silently for final buffer parsing\n }\n }\n \n } catch (error: any) {\n if (error.name === 'AbortError') {\n yield { \n text: 'Connection timed out. Please check if the server is running.', \n done: true \n };\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n yield { \n text: 'Could not connect to the server. Please check if the server is running.', \n done: true \n };\n } else {\n yield { \n text: `Error: ${error.message}`, \n done: true \n };\n }\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n // Simplified version - just check if we have new content at the end\n if (!currentText) return incomingText;\n \n // If incoming text is longer and starts with current text, return the new part\n if (incomingText.length > currentText.length && incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n // Otherwise return the full incoming text (fallback)\n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configuredSessionId","sessionId","keyRefreshTimer","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getSessionId","initializeChatbot","permanentApiKey","customOrigin","API_URL","response","errorText","data","refreshInterval","refreshTemporaryKey","error","getFetchOptions","options","requestId","timestamp","headers","generateRequestSignature","body","payload","RateLimiter","__publicField","identifier","maxRequests","windowMs","now","recentRequests","time","key","requests","recent","rateLimiter","securityMonitor","config","threshold","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","_a","_b","_c","_d","_e","_f","_g","_h","_i","sessionIdentifier","controller","timeoutId","reader","decoder","buffer","currentFullText","hasReceivedContent","done","value","chunk","lineStartIndex","newlineIndex","line","jsonText","content","isDone","newText","extractNewText","incomingText","currentText","sendToolsRequest"],"mappings":"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"}
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// Initialize agents for connection pooling in Node.js environments\nif (typeof window === 'undefined') {\n // Lazy load to avoid including 'http' in browser bundles\n Promise.all([\n import('http').catch(() => null),\n import('https').catch(() => null)\n ]).then(([http, https]) => {\n if (http?.default?.Agent) {\n httpAgent = new http.default.Agent({ keepAlive: true });\n } else if (http?.Agent) {\n httpAgent = new http.Agent({ keepAlive: true });\n }\n \n if (https?.default?.Agent) {\n httpsAgent = new https.default.Agent({ keepAlive: true });\n } else if (https?.Agent) {\n httpsAgent = new https.Agent({ keepAlive: true });\n }\n }).catch(err => {\n // Silently fail - connection pooling is optional\n console.warn('Failed to initialize HTTP agents:', err.message);\n });\n}\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\n// The server now returns this directly for non-streaming chat\nexport interface ChatResponse {\n response: string;\n sources?: any[];\n}\n\n// The request body for the /v1/chat endpoint\ninterface ChatRequest {\n messages: Array<{ role: string; content: string; }>;\n stream: boolean;\n}\n\nexport class ApiClient {\n private readonly apiUrl: string;\n private readonly apiKey: string | null;\n private sessionId: string | null; // Session ID can be mutable\n\n constructor(config: { apiUrl: string; apiKey?: string | null; sessionId?: string | null }) {\n if (!config.apiUrl || typeof config.apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (config.apiKey !== undefined && config.apiKey !== null && typeof config.apiKey !== 'string') {\n throw new Error('API key must be a valid string or null');\n }\n if (config.sessionId !== undefined && config.sessionId !== null && typeof config.sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n \n this.apiUrl = config.apiUrl;\n this.apiKey = config.apiKey ?? null;\n this.sessionId = config.sessionId ?? null;\n }\n\n public setSessionId(sessionId: string | null): void {\n if (sessionId !== null && typeof sessionId !== 'string') {\n throw new Error('Session ID must be a valid string or null');\n }\n this.sessionId = sessionId;\n }\n\n public getSessionId(): string | null {\n return this.sessionId;\n }\n\n // Helper to get fetch options with connection pooling if available\n private getFetchOptions(options: RequestInit = {}): RequestInit {\n const baseOptions: RequestInit = {};\n \n // Environment-specific options\n if (typeof window === 'undefined') {\n // Node.js: Use connection pooling agent\n const isHttps = this.apiUrl.startsWith('https:');\n const agent = isHttps ? httpsAgent : httpAgent;\n if (agent) {\n (baseOptions as any).agent = agent;\n }\n } else {\n // Browser: Use keep-alive header\n baseOptions.headers = { 'Connection': 'keep-alive' };\n }\n\n // Common headers\n const headers: Record<string, string> = {\n 'X-Request-ID': Date.now().toString(36) + Math.random().toString(36).substring(2),\n };\n\n // Merge base options headers (for browser keep-alive)\n if (baseOptions.headers) {\n Object.assign(headers, baseOptions.headers);\n }\n\n // Merge original request headers\n if (options.headers) {\n Object.assign(headers, options.headers);\n }\n\n if (this.apiKey) {\n headers['X-API-Key'] = this.apiKey;\n }\n\n if (this.sessionId) {\n headers['X-Session-ID'] = this.sessionId;\n }\n\n return {\n ...options,\n ...baseOptions,\n headers,\n };\n }\n\n // Create Chat request\n private createChatRequest(message: string, stream: boolean = true): ChatRequest {\n return {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n };\n }\n\n public async *streamChat(\n message: string,\n stream: boolean = true\n ): AsyncGenerator<StreamResponse> {\n try {\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(`${this.apiUrl}/v1/chat`, {\n ...this.getFetchOptions({\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(this.createChatRequest(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 ChatResponse;\n if (data.response) {\n yield {\n text: data.response,\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 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 const jsonText = line.slice(6).trim();\n \n if (!jsonText || jsonText === '[DONE]') {\n yield { text: '', done: true };\n return;\n }\n\n try {\n const data = JSON.parse(jsonText);\n \n if (data.error) {\n throw new Error(`Server Error: ${data.error.message}`);\n }\n \n if (data.response) {\n hasReceivedContent = true;\n yield { text: data.response, done: data.done || false };\n }\n\n if (data.done) {\n yield { text: '', done: true };\n return;\n }\n \n } catch (parseError) {\n console.warn('Error parsing JSON chunk:', parseError, 'Chunk:', jsonText);\n }\n } else if (line) {\n // Handle raw text chunks that are not in SSE format\n hasReceivedContent = true;\n yield { text: line, done: false };\n }\n }\n \n buffer = buffer.slice(lineStartIndex);\n \n if (buffer.length > 1000000) { // 1MB limit\n console.warn('Buffer too large, truncating...');\n buffer = buffer.slice(-500000); // Keep last 500KB\n }\n }\n \n if (hasReceivedContent) {\n yield { text: '', done: true };\n }\n \n } finally {\n reader.releaseLock();\n }\n \n } catch (error: any) {\n if (error.name === 'AbortError') {\n throw new Error('Connection timed out. Please check if the server is running.');\n } else if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {\n throw new Error('Could not connect to the server. Please check if the server is running.');\n } else {\n throw error;\n }\n }\n }\n}\n\n// Legacy compatibility functions - these create a default client instance\n// These are kept for backward compatibility but should be deprecated in favor of the class-based approach\n\nlet defaultClient: ApiClient | 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 defaultClient = new ApiClient({ apiUrl, apiKey, sessionId });\n}\n\n// Legacy streamChat function that uses the default client\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n if (!defaultClient) {\n throw new Error('API not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n \n yield* defaultClient.streamChat(message, stream);\n}\n"],"names":["httpAgent","httpsAgent","http","https","_a","_b","err","ApiClient","config","__publicField","sessionId","options","baseOptions","agent","headers","message","stream","controller","timeoutId","response","errorText","data","reader","decoder","buffer","hasReceivedContent","done","value","chunk","lineStartIndex","newlineIndex","line","jsonText","parseError","error","defaultClient","configureApi","apiUrl","apiKey","streamChat"],"mappings":"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"}
package/package.json CHANGED
@@ -1,26 +1,30 @@
1
1
  {
2
2
  "name": "@schmitech/chatbot-api",
3
3
  "private": false,
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "description": "API client for the ORBIT MCP server",
6
6
  "type": "module",
7
7
  "main": "./dist/api.cjs",
8
8
  "module": "./dist/api.mjs",
9
- "types": "./api.d.ts",
9
+ "types": "./dist/api.d.ts",
10
10
  "exports": {
11
11
  ".": {
12
- "import": "./dist/api.mjs",
13
- "require": "./dist/api.cjs",
14
- "types": "./api.d.ts"
12
+ "import": {
13
+ "types": "./dist/api.d.ts",
14
+ "default": "./dist/api.mjs"
15
+ },
16
+ "require": {
17
+ "types": "./dist/api.d.ts",
18
+ "default": "./dist/api.cjs"
19
+ }
15
20
  }
16
21
  },
17
22
  "files": [
18
- "dist",
19
- "api.d.ts"
23
+ "dist"
20
24
  ],
21
25
  "scripts": {
22
26
  "dev": "vite",
23
- "build": "tsc --emitDeclarationOnly && vite build",
27
+ "build": "vite build",
24
28
  "lint": "eslint .",
25
29
  "preview": "vite preview",
26
30
  "test": "vitest",
@@ -28,15 +32,9 @@
28
32
  "test-query": "node --import 'data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));' ./test/run-query.js",
29
33
  "test-query-from-pairs": "node --import 'data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));' ./test/run-query-from-pairs.js"
30
34
  },
31
- "dependencies": {
32
- "cors": "^2.8.5",
33
- "express": "^4.18.3",
34
- "node-fetch": "^3.3.2"
35
- },
35
+ "dependencies": {},
36
36
  "devDependencies": {
37
37
  "@eslint/js": "^9.9.1",
38
- "@types/cors": "^2.8.17",
39
- "@types/express": "^4.17.21",
40
38
  "@types/node": "^20.11.24",
41
39
  "eslint": "^9.9.1",
42
40
  "globals": "^15.9.0",
@@ -45,6 +43,7 @@
45
43
  "typescript": "^5.5.3",
46
44
  "typescript-eslint": "^8.3.0",
47
45
  "vite": "^5.4.2",
46
+ "vite-plugin-dts": "^4.3.0",
48
47
  "vitest": "^0.34.6"
49
48
  },
50
49
  "peerDependencies": {
package/api.d.ts DELETED
@@ -1,35 +0,0 @@
1
- export interface StreamResponse {
2
- text: string;
3
- done: boolean;
4
- }
5
- export interface ChatResponse {
6
- response: string;
7
- }
8
- interface MCPResponse {
9
- jsonrpc: "2.0";
10
- id: string;
11
- result?: {
12
- type?: "start" | "chunk" | "complete";
13
- chunk?: {
14
- content: string;
15
- };
16
- output?: {
17
- messages: Array<{
18
- role: string;
19
- content: string;
20
- }>;
21
- };
22
- };
23
- error?: {
24
- code: number;
25
- message: string;
26
- };
27
- }
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>;
30
- export declare function streamChat(message: string, stream?: boolean): AsyncGenerator<StreamResponse>;
31
- export declare function sendToolsRequest(tools: Array<{
32
- name: string;
33
- parameters: Record<string, any>;
34
- }>): Promise<MCPResponse>;
35
- export {};
package/dist/api.mjs.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "../api.d.ts";