@aisuai/chat-widget 0.1.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 +85 -0
- package/dist/index.d.mts +320 -0
- package/dist/index.d.ts +320 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +14 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @aisuai/chat-widget
|
|
2
|
+
|
|
3
|
+
Embeddable chat widget for integrating AiSU AI assistant into any React application.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @aisuai/chat-widget
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @aisuai/chat-widget
|
|
11
|
+
# or
|
|
12
|
+
yarn add @aisuai/chat-widget
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { ChatWidget } from "@aisuai/chat-widget";
|
|
19
|
+
|
|
20
|
+
function App() {
|
|
21
|
+
return (
|
|
22
|
+
<ChatWidget
|
|
23
|
+
apiKey="pk_live_xxx"
|
|
24
|
+
theme="auto"
|
|
25
|
+
position="bottom-right"
|
|
26
|
+
greeting="Hello! How can I help you today?"
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Next.js App Router
|
|
33
|
+
|
|
34
|
+
When using with Next.js App Router, add `"use client"` at the top of your component file:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
"use client";
|
|
38
|
+
|
|
39
|
+
import { ChatWidget } from "@aisuai/chat-widget";
|
|
40
|
+
|
|
41
|
+
export function Chat() {
|
|
42
|
+
return <ChatWidget apiKey="pk_live_xxx" />;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
| Property | Type | Default | Description |
|
|
49
|
+
| -------------- | --------------------------------- | --------------------- | ------------------------- |
|
|
50
|
+
| `apiKey` | `string` | required | Your AiSU API key |
|
|
51
|
+
| `apiEndpoint` | `string` | AiSU API | Custom API endpoint |
|
|
52
|
+
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Color theme |
|
|
53
|
+
| `primaryColor` | `string` | `'#0066FF'` | Primary accent color |
|
|
54
|
+
| `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Widget position |
|
|
55
|
+
| `greeting` | `string` | - | Initial greeting message |
|
|
56
|
+
| `placeholder` | `string` | `'Type a message...'` | Input placeholder |
|
|
57
|
+
| `onOpen` | `() => void` | - | Called when widget opens |
|
|
58
|
+
| `onClose` | `() => void` | - | Called when widget closes |
|
|
59
|
+
| `onMessage` | `(message: Message) => void` | - | Called on new message |
|
|
60
|
+
| `onError` | `(error: Error) => void` | - | Called on error |
|
|
61
|
+
|
|
62
|
+
## API Key Types
|
|
63
|
+
|
|
64
|
+
- **Public keys** (`pk_live_*`): For client-side use, only accesses public documents
|
|
65
|
+
- **Private keys** (`sk_live_*`): For server-side use, accesses all documents
|
|
66
|
+
|
|
67
|
+
## Development
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Install dependencies
|
|
71
|
+
pnpm install
|
|
72
|
+
|
|
73
|
+
# Build the package
|
|
74
|
+
pnpm build
|
|
75
|
+
|
|
76
|
+
# Watch mode
|
|
77
|
+
pnpm dev
|
|
78
|
+
|
|
79
|
+
# Type check
|
|
80
|
+
pnpm type-check
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authentication Types
|
|
5
|
+
*
|
|
6
|
+
* Supports API key, session, public (anonymous), and custom authentication.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* API Key authentication config
|
|
10
|
+
* For external customers embedding the widget on their sites
|
|
11
|
+
*/
|
|
12
|
+
interface ApiKeyAuthConfig {
|
|
13
|
+
type: "api-key";
|
|
14
|
+
apiKey: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* OAuth/Session authentication config
|
|
18
|
+
* Uses cookies/session - no explicit token needed
|
|
19
|
+
*/
|
|
20
|
+
interface SessionAuthConfig {
|
|
21
|
+
type: "session";
|
|
22
|
+
/**
|
|
23
|
+
* Optional user ID for analytics/tracking
|
|
24
|
+
*/
|
|
25
|
+
userId?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Public/Anonymous authentication config
|
|
29
|
+
* For unauthenticated users on public websites
|
|
30
|
+
*/
|
|
31
|
+
interface PublicAuthConfig {
|
|
32
|
+
type: "public";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Assistant-based authentication config
|
|
36
|
+
* Uses an assistant ID to configure the widget with curated document access
|
|
37
|
+
*/
|
|
38
|
+
interface AssistantAuthConfig {
|
|
39
|
+
type: "assistant";
|
|
40
|
+
/**
|
|
41
|
+
* The assistant ID (e.g., "ast_xxx")
|
|
42
|
+
*/
|
|
43
|
+
assistantId: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Custom authentication config
|
|
47
|
+
* Allows full control over auth headers
|
|
48
|
+
*/
|
|
49
|
+
interface CustomAuthConfig {
|
|
50
|
+
type: "custom";
|
|
51
|
+
/**
|
|
52
|
+
* Function that returns headers for authentication
|
|
53
|
+
*/
|
|
54
|
+
getAuthHeaders: () => Record<string, string> | Promise<Record<string, string>>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Union of all auth configurations
|
|
58
|
+
*/
|
|
59
|
+
type AuthConfig = ApiKeyAuthConfig | SessionAuthConfig | PublicAuthConfig | AssistantAuthConfig | CustomAuthConfig;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Chat Widget Configuration Types
|
|
63
|
+
*
|
|
64
|
+
* Core type definitions for configuring the embeddable chat widget.
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Message in the chat conversation
|
|
69
|
+
*/
|
|
70
|
+
interface Message {
|
|
71
|
+
id: string;
|
|
72
|
+
role: "user" | "assistant";
|
|
73
|
+
content: string;
|
|
74
|
+
timestamp: Date;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Configuration options for the chat widget
|
|
78
|
+
*/
|
|
79
|
+
interface ChatWidgetConfig {
|
|
80
|
+
/**
|
|
81
|
+
* Authentication configuration
|
|
82
|
+
* Supports API key, session (OAuth), or custom auth
|
|
83
|
+
*
|
|
84
|
+
* @example API Key auth (external customers):
|
|
85
|
+
* ```
|
|
86
|
+
* auth: { type: 'api-key', apiKey: 'pk_live_xxx' }
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @example Session auth (web app):
|
|
90
|
+
* ```
|
|
91
|
+
* auth: { type: 'session', userId: 'user-123' }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
auth: AuthConfig;
|
|
95
|
+
/**
|
|
96
|
+
* API endpoint URL (optional)
|
|
97
|
+
* Defaults to '/api/chat' for session auth or production API for API key auth
|
|
98
|
+
*/
|
|
99
|
+
apiEndpoint?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Color theme for the widget
|
|
102
|
+
* @default 'auto'
|
|
103
|
+
*/
|
|
104
|
+
theme?: "light" | "dark" | "auto";
|
|
105
|
+
/**
|
|
106
|
+
* Primary accent color (hex or CSS color)
|
|
107
|
+
* @default '#0066FF'
|
|
108
|
+
*/
|
|
109
|
+
primaryColor?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Widget position on the page
|
|
112
|
+
* @default 'bottom-right'
|
|
113
|
+
*/
|
|
114
|
+
position?: "bottom-right" | "bottom-left";
|
|
115
|
+
/**
|
|
116
|
+
* Initial greeting message shown to users
|
|
117
|
+
*/
|
|
118
|
+
greeting?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Placeholder text for the input field
|
|
121
|
+
* @default 'Type a message...'
|
|
122
|
+
*/
|
|
123
|
+
placeholder?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Callback when widget is opened
|
|
126
|
+
*/
|
|
127
|
+
onOpen?: () => void;
|
|
128
|
+
/**
|
|
129
|
+
* Callback when widget is closed
|
|
130
|
+
*/
|
|
131
|
+
onClose?: () => void;
|
|
132
|
+
/**
|
|
133
|
+
* Callback when a message is sent or received
|
|
134
|
+
*/
|
|
135
|
+
onMessage?: (message: Message) => void;
|
|
136
|
+
/**
|
|
137
|
+
* Callback when an error occurs
|
|
138
|
+
* If provided, you can handle errors yourself (e.g., show custom UI)
|
|
139
|
+
* If not provided, a default friendly message is shown to the user
|
|
140
|
+
*/
|
|
141
|
+
onError?: (error: Error) => void;
|
|
142
|
+
/**
|
|
143
|
+
* Custom error message to display when chat fails
|
|
144
|
+
* Only used when onError is not provided
|
|
145
|
+
* @default 'Sorry, I encountered an error. Please try again.'
|
|
146
|
+
*/
|
|
147
|
+
errorMessage?: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Internal widget state
|
|
151
|
+
*/
|
|
152
|
+
interface ChatWidgetState {
|
|
153
|
+
isOpen: boolean;
|
|
154
|
+
isLoading: boolean;
|
|
155
|
+
messages: Message[];
|
|
156
|
+
error: Error | null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Widget display variant
|
|
160
|
+
*/
|
|
161
|
+
type ChatWidgetVariant = "floating" | "inline" | "fullpage";
|
|
162
|
+
/**
|
|
163
|
+
* Props for the ChatWidget component
|
|
164
|
+
*/
|
|
165
|
+
interface ChatWidgetProps extends ChatWidgetConfig {
|
|
166
|
+
/**
|
|
167
|
+
* Display variant for the widget
|
|
168
|
+
* - 'floating': Bubble in corner that expands to a panel (default)
|
|
169
|
+
* - 'inline': Embedded chat interface for placing within a page section
|
|
170
|
+
* - 'fullpage': Full viewport chat experience
|
|
171
|
+
* @default 'floating'
|
|
172
|
+
*/
|
|
173
|
+
variant?: ChatWidgetVariant;
|
|
174
|
+
/**
|
|
175
|
+
* Whether the widget starts in open state (only applies to 'floating' variant)
|
|
176
|
+
* @default false
|
|
177
|
+
*/
|
|
178
|
+
defaultOpen?: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Additional CSS class name
|
|
181
|
+
*/
|
|
182
|
+
className?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Custom title for the chat header
|
|
185
|
+
*/
|
|
186
|
+
title?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Style exports for @aisuai/chat-widget
|
|
191
|
+
*
|
|
192
|
+
* Styles will be added in subsequent tasks:
|
|
193
|
+
* - CSS variables for theming
|
|
194
|
+
* - Base component styles
|
|
195
|
+
* - Animation keyframes
|
|
196
|
+
*/
|
|
197
|
+
declare const DEFAULT_THEME: {
|
|
198
|
+
readonly primaryColor: "#0066FF";
|
|
199
|
+
readonly backgroundColor: "#FFFFFF";
|
|
200
|
+
readonly textColor: "#1A1A1A";
|
|
201
|
+
readonly borderColor: "#E5E5E5";
|
|
202
|
+
readonly inputBackground: "#F5F5F5";
|
|
203
|
+
};
|
|
204
|
+
declare const DARK_THEME: {
|
|
205
|
+
readonly primaryColor: "#3B82F6";
|
|
206
|
+
readonly backgroundColor: "#1A1A1A";
|
|
207
|
+
readonly textColor: "#FFFFFF";
|
|
208
|
+
readonly borderColor: "#333333";
|
|
209
|
+
readonly inputBackground: "#2A2A2A";
|
|
210
|
+
};
|
|
211
|
+
type ThemeColors = typeof DEFAULT_THEME;
|
|
212
|
+
|
|
213
|
+
declare function ChatWidget({ auth, apiEndpoint, theme, primaryColor, position, greeting, placeholder, defaultOpen, variant, className, title: customTitle, onOpen, onClose, onMessage, onError, }: ChatWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
214
|
+
/**
|
|
215
|
+
* Helper to create API key auth config
|
|
216
|
+
* For external customers embedding the widget on their sites
|
|
217
|
+
*/
|
|
218
|
+
declare function apiKeyAuth(apiKey: string): AuthConfig;
|
|
219
|
+
/**
|
|
220
|
+
* Helper to create session auth config
|
|
221
|
+
* For authenticated users in web apps
|
|
222
|
+
*/
|
|
223
|
+
declare function sessionAuth(userId?: string): AuthConfig;
|
|
224
|
+
/**
|
|
225
|
+
* Helper to create public/anonymous auth config
|
|
226
|
+
* For unauthenticated users on public websites
|
|
227
|
+
*/
|
|
228
|
+
declare function publicAuth(): AuthConfig;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* ChatBubble Component
|
|
232
|
+
*
|
|
233
|
+
* Floating trigger button that opens the chat widget.
|
|
234
|
+
*/
|
|
235
|
+
interface ChatBubbleProps {
|
|
236
|
+
onClick: () => void;
|
|
237
|
+
isOpen: boolean;
|
|
238
|
+
primaryColor?: string;
|
|
239
|
+
position?: "bottom-right" | "bottom-left";
|
|
240
|
+
}
|
|
241
|
+
declare function ChatBubble({ onClick, isOpen, primaryColor, position, }: ChatBubbleProps): react_jsx_runtime.JSX.Element | null;
|
|
242
|
+
|
|
243
|
+
interface ChatWindowProps {
|
|
244
|
+
messages: Message[];
|
|
245
|
+
isLoading: boolean;
|
|
246
|
+
onSendMessage: (message: string) => void;
|
|
247
|
+
onClose: () => void;
|
|
248
|
+
title?: string;
|
|
249
|
+
placeholder?: string;
|
|
250
|
+
primaryColor?: string;
|
|
251
|
+
position?: "bottom-right" | "bottom-left";
|
|
252
|
+
}
|
|
253
|
+
declare function ChatWindow({ messages, isLoading, onSendMessage, onClose, title, placeholder, primaryColor, position, }: ChatWindowProps): react_jsx_runtime.JSX.Element;
|
|
254
|
+
|
|
255
|
+
interface MessageListProps {
|
|
256
|
+
messages: Message[];
|
|
257
|
+
isLoading?: boolean;
|
|
258
|
+
primaryColor?: string;
|
|
259
|
+
}
|
|
260
|
+
declare function MessageList({ messages, isLoading, primaryColor, }: MessageListProps): react_jsx_runtime.JSX.Element;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* ChatInput Component
|
|
264
|
+
*
|
|
265
|
+
* Text input with send button for the chat widget.
|
|
266
|
+
*/
|
|
267
|
+
interface ChatInputProps {
|
|
268
|
+
onSubmit: (message: string) => void;
|
|
269
|
+
isLoading?: boolean;
|
|
270
|
+
placeholder?: string;
|
|
271
|
+
primaryColor?: string;
|
|
272
|
+
}
|
|
273
|
+
declare function ChatInput({ onSubmit, isLoading, placeholder, primaryColor, }: ChatInputProps): react_jsx_runtime.JSX.Element;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* useChat Hook
|
|
277
|
+
*
|
|
278
|
+
* Core hook for chat API communication.
|
|
279
|
+
* Handles streaming responses and message management.
|
|
280
|
+
* Supports both API key and session/OAuth authentication.
|
|
281
|
+
*/
|
|
282
|
+
|
|
283
|
+
interface UseChatOptions {
|
|
284
|
+
/**
|
|
285
|
+
* Authentication configuration
|
|
286
|
+
*/
|
|
287
|
+
auth: AuthConfig;
|
|
288
|
+
/**
|
|
289
|
+
* API endpoint URL
|
|
290
|
+
* Defaults based on auth type:
|
|
291
|
+
* - API key: production API
|
|
292
|
+
* - Session: /api/chat or /api/authenticated-chat
|
|
293
|
+
*/
|
|
294
|
+
apiEndpoint?: string;
|
|
295
|
+
/**
|
|
296
|
+
* Callback when a message is sent or received
|
|
297
|
+
*/
|
|
298
|
+
onMessage?: (message: Message) => void;
|
|
299
|
+
/**
|
|
300
|
+
* Callback when an error occurs
|
|
301
|
+
* If provided, no default error message is shown - you handle it yourself
|
|
302
|
+
*/
|
|
303
|
+
onError?: (error: Error) => void;
|
|
304
|
+
/**
|
|
305
|
+
* Custom error message to display when chat fails
|
|
306
|
+
* Only used when onError is not provided
|
|
307
|
+
* @default 'Sorry, I encountered an error. Please try again.'
|
|
308
|
+
*/
|
|
309
|
+
errorMessage?: string;
|
|
310
|
+
}
|
|
311
|
+
interface UseChatReturn {
|
|
312
|
+
messages: Message[];
|
|
313
|
+
isLoading: boolean;
|
|
314
|
+
error: Error | null;
|
|
315
|
+
sendMessage: (content: string) => Promise<void>;
|
|
316
|
+
clearMessages: () => void;
|
|
317
|
+
}
|
|
318
|
+
declare function useChat({ auth, apiEndpoint, onMessage, onError, errorMessage, }: UseChatOptions): UseChatReturn;
|
|
319
|
+
|
|
320
|
+
export { type ApiKeyAuthConfig, type AuthConfig, ChatBubble, ChatInput, ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type ChatWidgetState, type ChatWidgetVariant, ChatWindow, type CustomAuthConfig, DARK_THEME, DEFAULT_THEME, type Message, MessageList, type PublicAuthConfig, type SessionAuthConfig, type ThemeColors, apiKeyAuth, publicAuth, sessionAuth, useChat };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authentication Types
|
|
5
|
+
*
|
|
6
|
+
* Supports API key, session, public (anonymous), and custom authentication.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* API Key authentication config
|
|
10
|
+
* For external customers embedding the widget on their sites
|
|
11
|
+
*/
|
|
12
|
+
interface ApiKeyAuthConfig {
|
|
13
|
+
type: "api-key";
|
|
14
|
+
apiKey: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* OAuth/Session authentication config
|
|
18
|
+
* Uses cookies/session - no explicit token needed
|
|
19
|
+
*/
|
|
20
|
+
interface SessionAuthConfig {
|
|
21
|
+
type: "session";
|
|
22
|
+
/**
|
|
23
|
+
* Optional user ID for analytics/tracking
|
|
24
|
+
*/
|
|
25
|
+
userId?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Public/Anonymous authentication config
|
|
29
|
+
* For unauthenticated users on public websites
|
|
30
|
+
*/
|
|
31
|
+
interface PublicAuthConfig {
|
|
32
|
+
type: "public";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Assistant-based authentication config
|
|
36
|
+
* Uses an assistant ID to configure the widget with curated document access
|
|
37
|
+
*/
|
|
38
|
+
interface AssistantAuthConfig {
|
|
39
|
+
type: "assistant";
|
|
40
|
+
/**
|
|
41
|
+
* The assistant ID (e.g., "ast_xxx")
|
|
42
|
+
*/
|
|
43
|
+
assistantId: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Custom authentication config
|
|
47
|
+
* Allows full control over auth headers
|
|
48
|
+
*/
|
|
49
|
+
interface CustomAuthConfig {
|
|
50
|
+
type: "custom";
|
|
51
|
+
/**
|
|
52
|
+
* Function that returns headers for authentication
|
|
53
|
+
*/
|
|
54
|
+
getAuthHeaders: () => Record<string, string> | Promise<Record<string, string>>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Union of all auth configurations
|
|
58
|
+
*/
|
|
59
|
+
type AuthConfig = ApiKeyAuthConfig | SessionAuthConfig | PublicAuthConfig | AssistantAuthConfig | CustomAuthConfig;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Chat Widget Configuration Types
|
|
63
|
+
*
|
|
64
|
+
* Core type definitions for configuring the embeddable chat widget.
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Message in the chat conversation
|
|
69
|
+
*/
|
|
70
|
+
interface Message {
|
|
71
|
+
id: string;
|
|
72
|
+
role: "user" | "assistant";
|
|
73
|
+
content: string;
|
|
74
|
+
timestamp: Date;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Configuration options for the chat widget
|
|
78
|
+
*/
|
|
79
|
+
interface ChatWidgetConfig {
|
|
80
|
+
/**
|
|
81
|
+
* Authentication configuration
|
|
82
|
+
* Supports API key, session (OAuth), or custom auth
|
|
83
|
+
*
|
|
84
|
+
* @example API Key auth (external customers):
|
|
85
|
+
* ```
|
|
86
|
+
* auth: { type: 'api-key', apiKey: 'pk_live_xxx' }
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @example Session auth (web app):
|
|
90
|
+
* ```
|
|
91
|
+
* auth: { type: 'session', userId: 'user-123' }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
auth: AuthConfig;
|
|
95
|
+
/**
|
|
96
|
+
* API endpoint URL (optional)
|
|
97
|
+
* Defaults to '/api/chat' for session auth or production API for API key auth
|
|
98
|
+
*/
|
|
99
|
+
apiEndpoint?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Color theme for the widget
|
|
102
|
+
* @default 'auto'
|
|
103
|
+
*/
|
|
104
|
+
theme?: "light" | "dark" | "auto";
|
|
105
|
+
/**
|
|
106
|
+
* Primary accent color (hex or CSS color)
|
|
107
|
+
* @default '#0066FF'
|
|
108
|
+
*/
|
|
109
|
+
primaryColor?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Widget position on the page
|
|
112
|
+
* @default 'bottom-right'
|
|
113
|
+
*/
|
|
114
|
+
position?: "bottom-right" | "bottom-left";
|
|
115
|
+
/**
|
|
116
|
+
* Initial greeting message shown to users
|
|
117
|
+
*/
|
|
118
|
+
greeting?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Placeholder text for the input field
|
|
121
|
+
* @default 'Type a message...'
|
|
122
|
+
*/
|
|
123
|
+
placeholder?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Callback when widget is opened
|
|
126
|
+
*/
|
|
127
|
+
onOpen?: () => void;
|
|
128
|
+
/**
|
|
129
|
+
* Callback when widget is closed
|
|
130
|
+
*/
|
|
131
|
+
onClose?: () => void;
|
|
132
|
+
/**
|
|
133
|
+
* Callback when a message is sent or received
|
|
134
|
+
*/
|
|
135
|
+
onMessage?: (message: Message) => void;
|
|
136
|
+
/**
|
|
137
|
+
* Callback when an error occurs
|
|
138
|
+
* If provided, you can handle errors yourself (e.g., show custom UI)
|
|
139
|
+
* If not provided, a default friendly message is shown to the user
|
|
140
|
+
*/
|
|
141
|
+
onError?: (error: Error) => void;
|
|
142
|
+
/**
|
|
143
|
+
* Custom error message to display when chat fails
|
|
144
|
+
* Only used when onError is not provided
|
|
145
|
+
* @default 'Sorry, I encountered an error. Please try again.'
|
|
146
|
+
*/
|
|
147
|
+
errorMessage?: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Internal widget state
|
|
151
|
+
*/
|
|
152
|
+
interface ChatWidgetState {
|
|
153
|
+
isOpen: boolean;
|
|
154
|
+
isLoading: boolean;
|
|
155
|
+
messages: Message[];
|
|
156
|
+
error: Error | null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Widget display variant
|
|
160
|
+
*/
|
|
161
|
+
type ChatWidgetVariant = "floating" | "inline" | "fullpage";
|
|
162
|
+
/**
|
|
163
|
+
* Props for the ChatWidget component
|
|
164
|
+
*/
|
|
165
|
+
interface ChatWidgetProps extends ChatWidgetConfig {
|
|
166
|
+
/**
|
|
167
|
+
* Display variant for the widget
|
|
168
|
+
* - 'floating': Bubble in corner that expands to a panel (default)
|
|
169
|
+
* - 'inline': Embedded chat interface for placing within a page section
|
|
170
|
+
* - 'fullpage': Full viewport chat experience
|
|
171
|
+
* @default 'floating'
|
|
172
|
+
*/
|
|
173
|
+
variant?: ChatWidgetVariant;
|
|
174
|
+
/**
|
|
175
|
+
* Whether the widget starts in open state (only applies to 'floating' variant)
|
|
176
|
+
* @default false
|
|
177
|
+
*/
|
|
178
|
+
defaultOpen?: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Additional CSS class name
|
|
181
|
+
*/
|
|
182
|
+
className?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Custom title for the chat header
|
|
185
|
+
*/
|
|
186
|
+
title?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Style exports for @aisuai/chat-widget
|
|
191
|
+
*
|
|
192
|
+
* Styles will be added in subsequent tasks:
|
|
193
|
+
* - CSS variables for theming
|
|
194
|
+
* - Base component styles
|
|
195
|
+
* - Animation keyframes
|
|
196
|
+
*/
|
|
197
|
+
declare const DEFAULT_THEME: {
|
|
198
|
+
readonly primaryColor: "#0066FF";
|
|
199
|
+
readonly backgroundColor: "#FFFFFF";
|
|
200
|
+
readonly textColor: "#1A1A1A";
|
|
201
|
+
readonly borderColor: "#E5E5E5";
|
|
202
|
+
readonly inputBackground: "#F5F5F5";
|
|
203
|
+
};
|
|
204
|
+
declare const DARK_THEME: {
|
|
205
|
+
readonly primaryColor: "#3B82F6";
|
|
206
|
+
readonly backgroundColor: "#1A1A1A";
|
|
207
|
+
readonly textColor: "#FFFFFF";
|
|
208
|
+
readonly borderColor: "#333333";
|
|
209
|
+
readonly inputBackground: "#2A2A2A";
|
|
210
|
+
};
|
|
211
|
+
type ThemeColors = typeof DEFAULT_THEME;
|
|
212
|
+
|
|
213
|
+
declare function ChatWidget({ auth, apiEndpoint, theme, primaryColor, position, greeting, placeholder, defaultOpen, variant, className, title: customTitle, onOpen, onClose, onMessage, onError, }: ChatWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
214
|
+
/**
|
|
215
|
+
* Helper to create API key auth config
|
|
216
|
+
* For external customers embedding the widget on their sites
|
|
217
|
+
*/
|
|
218
|
+
declare function apiKeyAuth(apiKey: string): AuthConfig;
|
|
219
|
+
/**
|
|
220
|
+
* Helper to create session auth config
|
|
221
|
+
* For authenticated users in web apps
|
|
222
|
+
*/
|
|
223
|
+
declare function sessionAuth(userId?: string): AuthConfig;
|
|
224
|
+
/**
|
|
225
|
+
* Helper to create public/anonymous auth config
|
|
226
|
+
* For unauthenticated users on public websites
|
|
227
|
+
*/
|
|
228
|
+
declare function publicAuth(): AuthConfig;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* ChatBubble Component
|
|
232
|
+
*
|
|
233
|
+
* Floating trigger button that opens the chat widget.
|
|
234
|
+
*/
|
|
235
|
+
interface ChatBubbleProps {
|
|
236
|
+
onClick: () => void;
|
|
237
|
+
isOpen: boolean;
|
|
238
|
+
primaryColor?: string;
|
|
239
|
+
position?: "bottom-right" | "bottom-left";
|
|
240
|
+
}
|
|
241
|
+
declare function ChatBubble({ onClick, isOpen, primaryColor, position, }: ChatBubbleProps): react_jsx_runtime.JSX.Element | null;
|
|
242
|
+
|
|
243
|
+
interface ChatWindowProps {
|
|
244
|
+
messages: Message[];
|
|
245
|
+
isLoading: boolean;
|
|
246
|
+
onSendMessage: (message: string) => void;
|
|
247
|
+
onClose: () => void;
|
|
248
|
+
title?: string;
|
|
249
|
+
placeholder?: string;
|
|
250
|
+
primaryColor?: string;
|
|
251
|
+
position?: "bottom-right" | "bottom-left";
|
|
252
|
+
}
|
|
253
|
+
declare function ChatWindow({ messages, isLoading, onSendMessage, onClose, title, placeholder, primaryColor, position, }: ChatWindowProps): react_jsx_runtime.JSX.Element;
|
|
254
|
+
|
|
255
|
+
interface MessageListProps {
|
|
256
|
+
messages: Message[];
|
|
257
|
+
isLoading?: boolean;
|
|
258
|
+
primaryColor?: string;
|
|
259
|
+
}
|
|
260
|
+
declare function MessageList({ messages, isLoading, primaryColor, }: MessageListProps): react_jsx_runtime.JSX.Element;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* ChatInput Component
|
|
264
|
+
*
|
|
265
|
+
* Text input with send button for the chat widget.
|
|
266
|
+
*/
|
|
267
|
+
interface ChatInputProps {
|
|
268
|
+
onSubmit: (message: string) => void;
|
|
269
|
+
isLoading?: boolean;
|
|
270
|
+
placeholder?: string;
|
|
271
|
+
primaryColor?: string;
|
|
272
|
+
}
|
|
273
|
+
declare function ChatInput({ onSubmit, isLoading, placeholder, primaryColor, }: ChatInputProps): react_jsx_runtime.JSX.Element;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* useChat Hook
|
|
277
|
+
*
|
|
278
|
+
* Core hook for chat API communication.
|
|
279
|
+
* Handles streaming responses and message management.
|
|
280
|
+
* Supports both API key and session/OAuth authentication.
|
|
281
|
+
*/
|
|
282
|
+
|
|
283
|
+
interface UseChatOptions {
|
|
284
|
+
/**
|
|
285
|
+
* Authentication configuration
|
|
286
|
+
*/
|
|
287
|
+
auth: AuthConfig;
|
|
288
|
+
/**
|
|
289
|
+
* API endpoint URL
|
|
290
|
+
* Defaults based on auth type:
|
|
291
|
+
* - API key: production API
|
|
292
|
+
* - Session: /api/chat or /api/authenticated-chat
|
|
293
|
+
*/
|
|
294
|
+
apiEndpoint?: string;
|
|
295
|
+
/**
|
|
296
|
+
* Callback when a message is sent or received
|
|
297
|
+
*/
|
|
298
|
+
onMessage?: (message: Message) => void;
|
|
299
|
+
/**
|
|
300
|
+
* Callback when an error occurs
|
|
301
|
+
* If provided, no default error message is shown - you handle it yourself
|
|
302
|
+
*/
|
|
303
|
+
onError?: (error: Error) => void;
|
|
304
|
+
/**
|
|
305
|
+
* Custom error message to display when chat fails
|
|
306
|
+
* Only used when onError is not provided
|
|
307
|
+
* @default 'Sorry, I encountered an error. Please try again.'
|
|
308
|
+
*/
|
|
309
|
+
errorMessage?: string;
|
|
310
|
+
}
|
|
311
|
+
interface UseChatReturn {
|
|
312
|
+
messages: Message[];
|
|
313
|
+
isLoading: boolean;
|
|
314
|
+
error: Error | null;
|
|
315
|
+
sendMessage: (content: string) => Promise<void>;
|
|
316
|
+
clearMessages: () => void;
|
|
317
|
+
}
|
|
318
|
+
declare function useChat({ auth, apiEndpoint, onMessage, onError, errorMessage, }: UseChatOptions): UseChatReturn;
|
|
319
|
+
|
|
320
|
+
export { type ApiKeyAuthConfig, type AuthConfig, ChatBubble, ChatInput, ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type ChatWidgetState, type ChatWidgetVariant, ChatWindow, type CustomAuthConfig, DARK_THEME, DEFAULT_THEME, type Message, MessageList, type PublicAuthConfig, type SessionAuthConfig, type ThemeColors, apiKeyAuth, publicAuth, sessionAuth, useChat };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var ne={primaryColor:"#0066FF",backgroundColor:"#FFFFFF",textColor:"#1A1A1A",borderColor:"#E5E5E5",inputBackground:"#F5F5F5"},ie={primaryColor:"#3B82F6",backgroundColor:"#1A1A1A",textColor:"#FFFFFF",borderColor:"#333333",inputBackground:"#2A2A2A"};function K({onClick:e,isOpen:n,primaryColor:u="#0066FF",position:o="bottom-right"}){return n?null:jsxRuntime.jsx("button",{type:"button",onClick:e,"aria-label":"Open chat",style:{position:"fixed",bottom:"24px",...o==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"56px",height:"56px",borderRadius:"50%",backgroundColor:u,border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)",transition:"transform 0.2s ease, box-shadow 0.2s ease",zIndex:9999},onMouseEnter:i=>{i.currentTarget.style.transform="scale(1.05)",i.currentTarget.style.boxShadow="0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)";},onMouseLeave:i=>{i.currentTarget.style.transform="scale(1)",i.currentTarget.style.boxShadow="0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)";},children:jsxRuntime.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})})}function k({messages:e,isLoading:n=false,primaryColor:u="#0066FF"}){let o=react.useRef(null);return react.useEffect(()=>{o.current?.scrollIntoView({behavior:"smooth"});},[e]),e.length===0&&!n?jsxRuntime.jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:"24px",color:"#666",textAlign:"center"},children:jsxRuntime.jsx("p",{style:{margin:0,fontSize:"14px"},children:"Start a conversation by typing a message below."})}):jsxRuntime.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"16px",display:"flex",flexDirection:"column",gap:"12px"},children:[e.map(r=>jsxRuntime.jsx("div",{style:{display:"flex",justifyContent:r.role==="user"?"flex-end":"flex-start"},children:jsxRuntime.jsx("div",{style:{maxWidth:"80%",padding:"12px 16px",borderRadius:"12px",backgroundColor:r.role==="user"?u:"#F3F4F6",color:r.role==="user"?"#FFFFFF":"#1F2937",fontSize:"14px",lineHeight:"1.5",wordBreak:"break-word",whiteSpace:"pre-wrap"},children:r.content})},r.id)),n&&e[e.length-1]?.role==="user"&&jsxRuntime.jsx("div",{style:{display:"flex",justifyContent:"flex-start"},children:jsxRuntime.jsxs("div",{style:{padding:"12px 16px",borderRadius:"12px",backgroundColor:"#F3F4F6",display:"flex",alignItems:"center",gap:"4px"},children:[jsxRuntime.jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite"}}),jsxRuntime.jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.2s"}}),jsxRuntime.jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.4s"}})]})}),jsxRuntime.jsx("div",{ref:o}),jsxRuntime.jsx("style",{children:`
|
|
2
|
+
@keyframes pulse {
|
|
3
|
+
0%, 100% { opacity: 0.4; transform: scale(0.8); }
|
|
4
|
+
50% { opacity: 1; transform: scale(1); }
|
|
5
|
+
}
|
|
6
|
+
`})]})}function M({onSubmit:e,isLoading:n=false,placeholder:u="Type a message...",primaryColor:o="#0066FF"}){let[r,i]=react.useState(""),s=react.useRef(null);react.useEffect(()=>{let t=s.current;t&&(t.style.height="auto",t.style.height=`${Math.min(t.scrollHeight,120)}px`);},[r]);let g=react.useCallback(()=>{let t=r.trim();!t||n||(e(t),i(""),s.current&&(s.current.style.height="auto"));},[r,n,e]),d=react.useCallback(t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),g());},[g]),a=r.trim().length>0&&!n;return jsxRuntime.jsxs("div",{style:{padding:"12px 16px",borderTop:"1px solid #E5E7EB",backgroundColor:"#FFFFFF"},children:[jsxRuntime.jsxs("div",{style:{display:"flex",alignItems:"flex-end",gap:"8px"},children:[jsxRuntime.jsx("textarea",{ref:s,value:r,onChange:t=>i(t.target.value),onKeyDown:d,placeholder:u,disabled:n,rows:1,style:{flex:1,padding:"10px 12px",borderRadius:"8px",border:"1px solid #E5E7EB",backgroundColor:"#F9FAFB",fontSize:"14px",lineHeight:"1.5",resize:"none",outline:"none",fontFamily:"inherit",minHeight:"42px",maxHeight:"120px"},onFocus:t=>{t.currentTarget.style.borderColor=o,t.currentTarget.style.boxShadow=`0 0 0 2px ${o}20`;},onBlur:t=>{t.currentTarget.style.borderColor="#E5E7EB",t.currentTarget.style.boxShadow="none";}}),jsxRuntime.jsx("button",{type:"button",onClick:g,disabled:!a,"aria-label":"Send message",style:{width:"42px",height:"42px",borderRadius:"8px",border:"none",backgroundColor:a?o:"#E5E7EB",cursor:a?"pointer":"not-allowed",display:"flex",alignItems:"center",justifyContent:"center",transition:"background-color 0.2s ease, transform 0.1s ease",flexShrink:0},onMouseEnter:t=>{a&&(t.currentTarget.style.transform="scale(1.05)");},onMouseLeave:t=>{t.currentTarget.style.transform="scale(1)";},children:n?jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",style:{animation:"spin 1s linear infinite"},children:jsxRuntime.jsx("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})}):jsxRuntime.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:a?"white":"#9CA3AF",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),jsxRuntime.jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]}),jsxRuntime.jsx("style",{children:`
|
|
7
|
+
@keyframes spin {
|
|
8
|
+
from { transform: rotate(0deg); }
|
|
9
|
+
to { transform: rotate(360deg); }
|
|
10
|
+
}
|
|
11
|
+
`})]})}function O({messages:e,isLoading:n,onSendMessage:u,onClose:o,title:r="Chat",placeholder:i="Type a message...",primaryColor:s="#0066FF",position:g="bottom-right"}){return jsxRuntime.jsxs("div",{style:{position:"fixed",bottom:"24px",...g==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"380px",height:"520px",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)",display:"flex",flexDirection:"column",overflow:"hidden",zIndex:9999,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsxRuntime.jsxs("div",{style:{padding:"16px",backgroundColor:s,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsxRuntime.jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:r}),jsxRuntime.jsx("button",{type:"button",onClick:o,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"4px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px",transition:"background-color 0.2s ease"},onMouseEnter:a=>{a.currentTarget.style.backgroundColor="rgba(255, 255, 255, 0.2)";},onMouseLeave:a=>{a.currentTarget.style.backgroundColor="transparent";},children:jsxRuntime.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsxRuntime.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsxRuntime.jsx(k,{messages:e,isLoading:n,primaryColor:s}),jsxRuntime.jsx(M,{onSubmit:u,isLoading:n,placeholder:i,primaryColor:s})]})}async function J(e){switch(e.type){case "api-key":return {"x-api-key":e.apiKey};case "session":return {};case "public":return {};case "assistant":return {};case "custom":return e.getAuthHeaders();default:return {}}}var ge="Sorry, I encountered an error. Please try again.";function fe(e){switch(e.type){case "api-key":return "/api/chat";case "session":return "/api/authenticated-chat";case "public":return "/api/public-chat";case "assistant":return `/api/public/assistant/${e.assistantId}/chat`;case "custom":return "/api/authenticated-chat";default:return "/api/public-chat"}}function U({auth:e,apiEndpoint:n,onMessage:u,onError:o,errorMessage:r=ge}){let[i,s]=react.useState([]),[g,d]=react.useState(false),[a,t]=react.useState(null),h=react.useRef(null),S=n??fe(e),z=react.useCallback(async C=>{if(!C.trim()||g)return;h.current&&h.current.abort(),h.current=new AbortController;let R={id:`user-${Date.now()}`,role:"user",content:C.trim(),timestamp:new Date};s(c=>[...c,R]),u?.(R),d(true),t(null);try{let c=await J(e),l=await fetch(S,{method:"POST",headers:{"Content-Type":"application/json",...c},credentials:e.type==="session"?"include":"same-origin",body:JSON.stringify({messages:[...i,R].map(y=>({role:y.role,content:y.content})),...e.type==="session"&&e.userId?{userId:e.userId}:{}}),signal:h.current.signal});if(!l.ok){let y=await l.json().catch(()=>({}));throw new Error(y.error??`Request failed with status ${l.status}`)}let F=l.body?.getReader(),W=new TextDecoder,A="",w=`assistant-${Date.now()}`;if(F){let y={id:w,role:"assistant",content:"",timestamp:new Date};for(s(b=>[...b,y]);;){let{done:b,value:B}=await F.read();if(b)break;let se=W.decode(B,{stream:!0}).split(`
|
|
12
|
+
`),Y="";for(let H of se)if(H.startsWith("event:"))Y=H.slice(6).trim();else if(H.startsWith("data:")){let L=H.slice(5).trim();if(!L||L==="[DONE]")continue;try{let f=JSON.parse(L);if(Y==="text-delta"||f.type==="text-delta"){let N=f.delta??f.value??"";A+=N,s(v=>{let x=[...v],P=x.length-1;return P>=0&&x[P]?.role==="assistant"&&(x[P]={...x[P],content:A}),x});}}catch{if(L.startsWith("0:")){let f=L.slice(2);f.startsWith('"')&&f.endsWith('"')&&(f=f.slice(1,-1)),f=f.replace(/\\n/g,`
|
|
13
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\"),A+=f,s(N=>{let v=[...N],x=v.length-1;return x>=0&&v[x]?.role==="assistant"&&(v[x]={...v[x],content:A}),v});}}}}u?.({id:w,role:"assistant",content:A,timestamp:new Date});}}catch(c){if(c instanceof Error&&c.name==="AbortError")return;let l=c instanceof Error?c:new Error("An error occurred");if(t(l),o)o(l);else {let F={id:`error-${Date.now()}`,role:"assistant",content:r,timestamp:new Date};s(W=>[...W,F]);}}finally{d(false),h.current=null;}},[e,S,i,g,u,o,r]),j=react.useCallback(()=>{h.current&&h.current.abort(),s([]),t(null),d(false);},[]);return {messages:i,isLoading:g,error:a,sendMessage:z,clearMessages:j}}function ee({auth:e,apiEndpoint:n,theme:u="light",primaryColor:o="#0066FF",position:r="bottom-right",greeting:i,placeholder:s="Type a message...",defaultOpen:g=false,variant:d="floating",className:a,title:t,onOpen:h,onClose:S,onMessage:z,onError:j}){let[C,R]=react.useState(g),{messages:c,isLoading:l,sendMessage:F,clearMessages:W}=U({auth:e,apiEndpoint:n,onMessage:z,onError:j}),A=react.useCallback(()=>{R(true),h?.();},[h]),w=react.useCallback(()=>{R(false),S?.();},[S]);react.useEffect(()=>{if(d!=="floating")return;let b=B=>{B.key==="Escape"&&C&&(B.preventDefault(),w());};return window.addEventListener("keydown",b),()=>window.removeEventListener("keydown",b)},[C,d,w]);let y=react.useCallback(b=>{F(b);},[F]),D=t??(e.type==="api-key"?"Chat":"AiSU Assistant");return d==="floating"?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(K,{onClick:A,isOpen:C,primaryColor:o,position:r}),C&&jsxRuntime.jsx(O,{messages:c,isLoading:l,onSendMessage:y,onClose:w,title:D,placeholder:s,primaryColor:o,position:r})]}):d==="inline"?jsxRuntime.jsxs("div",{className:a,style:{display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",overflow:"hidden",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsxRuntime.jsx("div",{style:{padding:"16px",backgroundColor:o,color:"#FFFFFF"},children:jsxRuntime.jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:D})}),jsxRuntime.jsx(k,{messages:c,isLoading:l,primaryColor:o}),jsxRuntime.jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):d==="fullpage"?jsxRuntime.jsxs("div",{className:a,style:{position:"fixed",inset:0,display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',zIndex:9999},children:[jsxRuntime.jsxs("div",{style:{padding:"20px 24px",backgroundColor:o,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsxRuntime.jsx("h2",{style:{margin:0,fontSize:"20px",fontWeight:600},children:D}),S&&jsxRuntime.jsx("button",{type:"button",onClick:w,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"8px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px"},children:jsxRuntime.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsxRuntime.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsxRuntime.jsx("div",{style:{flex:1,overflow:"hidden"},children:jsxRuntime.jsx(k,{messages:c,isLoading:l,primaryColor:o})}),jsxRuntime.jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):null}function te(e){return {type:"api-key",apiKey:e}}function oe(e){return {type:"session",userId:e}}function re(){return {type:"public"}}exports.ChatBubble=K;exports.ChatInput=M;exports.ChatWidget=ee;exports.ChatWindow=O;exports.DARK_THEME=ie;exports.DEFAULT_THEME=ne;exports.MessageList=k;exports.apiKeyAuth=te;exports.publicAuth=re;exports.sessionAuth=oe;exports.useChat=U;//# sourceMappingURL=index.js.map
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/styles/index.ts","../src/components/ChatBubble.tsx","../src/components/MessageList.tsx","../src/components/ChatInput.tsx","../src/components/ChatWindow.tsx","../src/types/auth.ts","../src/hooks/useChat.ts","../src/components/ChatWidget.tsx"],"names":["DEFAULT_THEME","DARK_THEME","ChatBubble","onClick","isOpen","primaryColor","position","jsx","e","MessageList","messages","isLoading","messagesEndRef","useRef","useEffect","jsxs","message","ChatInput","onSubmit","placeholder","value","setValue","useState","textareaRef","textarea","handleSubmit","useCallback","trimmed","handleKeyDown","canSubmit","ChatWindow","onSendMessage","onClose","title","getAuthHeaders","config","DEFAULT_ERROR_MESSAGE","getDefaultEndpoint","auth","useChat","apiEndpoint","onMessage","onError","errorMessage","setMessages","setIsLoading","error","setError","abortControllerRef","endpoint","sendMessage","content","userMessage","prev","authHeaders","response","m","errorData","reader","decoder","assistantContent","assistantMessageId","initialAssistantMessage","done","lines","currentEvent","line","dataStr","data","text","newMessages","lastIdx","err","chatError","errorMsg","clearMessages","ChatWidget","theme","greeting","defaultOpen","variant","className","customTitle","onOpen","setIsOpen","handleOpen","handleClose","handleSendMessage","Fragment","apiKeyAuth","apiKey","sessionAuth","userId","publicAuth"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Style exports for @aisuai/chat-widget\n *\n * Styles will be added in subsequent tasks:\n * - CSS variables for theming\n * - Base component styles\n * - Animation keyframes\n */\n\n// Default theme colors\nexport const DEFAULT_THEME = {\n primaryColor: \"#0066FF\",\n backgroundColor: \"#FFFFFF\",\n textColor: \"#1A1A1A\",\n borderColor: \"#E5E5E5\",\n inputBackground: \"#F5F5F5\",\n} as const;\n\n// Dark theme colors\nexport const DARK_THEME = {\n primaryColor: \"#3B82F6\",\n backgroundColor: \"#1A1A1A\",\n textColor: \"#FFFFFF\",\n borderColor: \"#333333\",\n inputBackground: \"#2A2A2A\",\n} as const;\n\nexport type ThemeColors = typeof DEFAULT_THEME;\n","/**\n * ChatBubble Component\n *\n * Floating trigger button that opens the chat widget.\n */\n\nimport React from \"react\";\n\ninterface ChatBubbleProps {\n onClick: () => void;\n isOpen: boolean;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatBubble({\n onClick,\n isOpen,\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatBubbleProps) {\n if (isOpen) return null;\n\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Open chat\"\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n backgroundColor: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.2s ease, box-shadow 0.2s ease\",\n zIndex: 9999,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n e.currentTarget.style.boxShadow =\n \"0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n e.currentTarget.style.boxShadow =\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\";\n }}\n >\n {/* Chat icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </button>\n );\n}\n","/**\n * MessageList Component\n *\n * Displays chat messages with proper styling for user and assistant roles.\n */\n\nimport React, { useEffect, useRef } from \"react\";\nimport type { Message } from \"../types\";\n\ninterface MessageListProps {\n messages: Message[];\n isLoading?: boolean;\n primaryColor?: string;\n}\n\nexport function MessageList({\n messages,\n isLoading = false,\n primaryColor = \"#0066FF\",\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n if (messages.length === 0 && !isLoading) {\n return (\n <div\n style={{\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"24px\",\n color: \"#666\",\n textAlign: \"center\",\n }}\n >\n <p style={{ margin: 0, fontSize: \"14px\" }}>\n Start a conversation by typing a message below.\n </p>\n </div>\n );\n }\n\n return (\n <div\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: \"16px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {messages.map((message) => (\n <div\n key={message.id}\n style={{\n display: \"flex\",\n justifyContent: message.role === \"user\" ? \"flex-end\" : \"flex-start\",\n }}\n >\n <div\n style={{\n maxWidth: \"80%\",\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor:\n message.role === \"user\" ? primaryColor : \"#F3F4F6\",\n color: message.role === \"user\" ? \"#FFFFFF\" : \"#1F2937\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n wordBreak: \"break-word\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {message.content}\n </div>\n </div>\n ))}\n\n {/* Loading indicator */}\n {isLoading && messages[messages.length - 1]?.role === \"user\" && (\n <div style={{ display: \"flex\", justifyContent: \"flex-start\" }}>\n <div\n style={{\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor: \"#F3F4F6\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"4px\",\n }}\n >\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.2s\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.4s\",\n }}\n />\n </div>\n </div>\n )}\n\n {/* Auto-scroll anchor */}\n <div ref={messagesEndRef} />\n\n {/* Keyframe animation for loading dots */}\n <style>{`\n @keyframes pulse {\n 0%, 100% { opacity: 0.4; transform: scale(0.8); }\n 50% { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatInput Component\n *\n * Text input with send button for the chat widget.\n */\n\nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\n\ninterface ChatInputProps {\n onSubmit: (message: string) => void;\n isLoading?: boolean;\n placeholder?: string;\n primaryColor?: string;\n}\n\nexport function ChatInput({\n onSubmit,\n isLoading = false,\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n}: ChatInputProps) {\n const [value, setValue] = useState(\"\");\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-resize textarea\n useEffect(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n }\n }, [value]);\n\n const handleSubmit = useCallback(() => {\n const trimmed = value.trim();\n if (!trimmed || isLoading) return;\n\n onSubmit(trimmed);\n setValue(\"\");\n\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n }\n }, [value, isLoading, onSubmit]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n },\n [handleSubmit],\n );\n\n const canSubmit = value.trim().length > 0 && !isLoading;\n\n return (\n <div\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid #E5E7EB\",\n backgroundColor: \"#FFFFFF\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-end\",\n gap: \"8px\",\n }}\n >\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={isLoading}\n rows={1}\n style={{\n flex: 1,\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: \"1px solid #E5E7EB\",\n backgroundColor: \"#F9FAFB\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n resize: \"none\",\n outline: \"none\",\n fontFamily: \"inherit\",\n minHeight: \"42px\",\n maxHeight: \"120px\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.borderColor = primaryColor;\n e.currentTarget.style.boxShadow = `0 0 0 2px ${primaryColor}20`;\n }}\n onBlur={(e) => {\n e.currentTarget.style.borderColor = \"#E5E7EB\";\n e.currentTarget.style.boxShadow = \"none\";\n }}\n />\n\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n aria-label=\"Send message\"\n style={{\n width: \"42px\",\n height: \"42px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: canSubmit ? primaryColor : \"#E5E7EB\",\n cursor: canSubmit ? \"pointer\" : \"not-allowed\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n transition: \"background-color 0.2s ease, transform 0.1s ease\",\n flexShrink: 0,\n }}\n onMouseEnter={(e) => {\n if (canSubmit) {\n e.currentTarget.style.transform = \"scale(1.05)\";\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n }}\n >\n {isLoading ? (\n // Loading spinner\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n style={{\n animation: \"spin 1s linear infinite\",\n }}\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n ) : (\n // Send icon\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={canSubmit ? \"white\" : \"#9CA3AF\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n )}\n </button>\n </div>\n\n {/* Keyframe animation for spinner */}\n <style>{`\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatWindow Component\n *\n * The expandable chat panel containing messages and input.\n */\n\nimport React from \"react\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport type { Message } from \"../types\";\n\ninterface ChatWindowProps {\n messages: Message[];\n isLoading: boolean;\n onSendMessage: (message: string) => void;\n onClose: () => void;\n title?: string;\n placeholder?: string;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatWindow({\n messages,\n isLoading,\n onSendMessage,\n onClose,\n title = \"Chat\",\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatWindowProps) {\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <div\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"380px\",\n height: \"520px\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow:\n \"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)\",\n display: \"flex\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n zIndex: 9999,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n transition: \"background-color 0.2s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255, 255, 255, 0.2)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"transparent\";\n }}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={onSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n}\n","/**\n * Authentication Types\n *\n * Supports API key, session, public (anonymous), and custom authentication.\n */\n\n/**\n * API Key authentication config\n * For external customers embedding the widget on their sites\n */\nexport interface ApiKeyAuthConfig {\n type: \"api-key\";\n apiKey: string;\n}\n\n/**\n * OAuth/Session authentication config\n * Uses cookies/session - no explicit token needed\n */\nexport interface SessionAuthConfig {\n type: \"session\";\n /**\n * Optional user ID for analytics/tracking\n */\n userId?: string;\n}\n\n/**\n * Public/Anonymous authentication config\n * For unauthenticated users on public websites\n */\nexport interface PublicAuthConfig {\n type: \"public\";\n}\n\n/**\n * Assistant-based authentication config\n * Uses an assistant ID to configure the widget with curated document access\n */\nexport interface AssistantAuthConfig {\n type: \"assistant\";\n /**\n * The assistant ID (e.g., \"ast_xxx\")\n */\n assistantId: string;\n}\n\n/**\n * Custom authentication config\n * Allows full control over auth headers\n */\nexport interface CustomAuthConfig {\n type: \"custom\";\n /**\n * Function that returns headers for authentication\n */\n getAuthHeaders: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n}\n\n/**\n * Union of all auth configurations\n */\nexport type AuthConfig =\n | ApiKeyAuthConfig\n | SessionAuthConfig\n | PublicAuthConfig\n | AssistantAuthConfig\n | CustomAuthConfig;\n\n/**\n * Helper to build auth headers from config\n */\nexport async function getAuthHeaders(\n config: AuthConfig,\n): Promise<Record<string, string>> {\n switch (config.type) {\n case \"api-key\":\n return { \"x-api-key\": config.apiKey };\n case \"session\":\n // Session auth uses cookies, no explicit headers needed\n return {};\n case \"public\":\n // Public auth - no headers needed\n return {};\n case \"assistant\":\n // Assistant auth - no special headers, ID is in URL\n return {};\n case \"custom\":\n return config.getAuthHeaders();\n default:\n return {};\n }\n}\n","/**\n * useChat Hook\n *\n * Core hook for chat API communication.\n * Handles streaming responses and message management.\n * Supports both API key and session/OAuth authentication.\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Message, AuthConfig } from \"../types\";\nimport { getAuthHeaders } from \"../types\";\n\nconst DEFAULT_ERROR_MESSAGE =\n \"Sorry, I encountered an error. Please try again.\";\n\ninterface UseChatOptions {\n /**\n * Authentication configuration\n */\n auth: AuthConfig;\n\n /**\n * API endpoint URL\n * Defaults based on auth type:\n * - API key: production API\n * - Session: /api/chat or /api/authenticated-chat\n */\n apiEndpoint?: string;\n\n /**\n * Callback when a message is sent or received\n */\n onMessage?: (message: Message) => void;\n\n /**\n * Callback when an error occurs\n * If provided, no default error message is shown - you handle it yourself\n */\n onError?: (error: Error) => void;\n\n /**\n * Custom error message to display when chat fails\n * Only used when onError is not provided\n * @default 'Sorry, I encountered an error. Please try again.'\n */\n errorMessage?: string;\n}\n\ninterface UseChatReturn {\n messages: Message[];\n isLoading: boolean;\n error: Error | null;\n sendMessage: (content: string) => Promise<void>;\n clearMessages: () => void;\n}\n\n/**\n * Get default API endpoint based on auth type\n */\nfunction getDefaultEndpoint(auth: AuthConfig): string {\n switch (auth.type) {\n case \"api-key\":\n // External customers use the API key chat endpoint\n return \"/api/chat\";\n case \"session\":\n // Session auth uses authenticated chat\n return \"/api/authenticated-chat\";\n case \"public\":\n // Anonymous public users\n return \"/api/public-chat\";\n case \"assistant\":\n // Assistant-based public access\n return `/api/public/assistant/${auth.assistantId}/chat`;\n case \"custom\":\n // Custom auth - default to authenticated endpoint\n return \"/api/authenticated-chat\";\n default:\n return \"/api/public-chat\";\n }\n}\n\nexport function useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n errorMessage = DEFAULT_ERROR_MESSAGE,\n}: UseChatOptions): UseChatReturn {\n const [messages, setMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const endpoint = apiEndpoint ?? getDefaultEndpoint(auth);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim() || isLoading) return;\n\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n abortControllerRef.current = new AbortController();\n\n const userMessage: Message = {\n id: `user-${Date.now()}`,\n role: \"user\",\n content: content.trim(),\n timestamp: new Date(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessage?.(userMessage);\n setIsLoading(true);\n setError(null);\n\n try {\n // Get auth headers based on auth type\n const authHeaders = await getAuthHeaders(auth);\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...authHeaders,\n },\n // Include credentials for session auth (cookies)\n credentials: auth.type === \"session\" ? \"include\" : \"same-origin\",\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n // Include userId for session auth if provided\n ...(auth.type === \"session\" && auth.userId\n ? { userId: auth.userId }\n : {}),\n }),\n signal: abortControllerRef.current.signal,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error ?? `Request failed with status ${response.status}`,\n );\n }\n\n const reader = response.body?.getReader();\n const decoder = new TextDecoder();\n let assistantContent = \"\";\n const assistantMessageId = `assistant-${Date.now()}`;\n\n if (reader) {\n // Add initial assistant message\n const initialAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: \"\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, initialAssistantMessage]);\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n\n // Parse SSE format (AI SDK v6 UIMessageStream)\n const lines = chunk.split(\"\\n\");\n let currentEvent = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n currentEvent = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const dataStr = line.slice(5).trim();\n if (!dataStr || dataStr === \"[DONE]\") continue;\n\n try {\n const data = JSON.parse(dataStr) as {\n type?: string;\n delta?: string;\n value?: string;\n };\n\n // Handle text-delta events\n if (\n currentEvent === \"text-delta\" ||\n data.type === \"text-delta\"\n ) {\n const text = data.delta ?? data.value ?? \"\";\n assistantContent += text;\n\n // Update assistant message\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n } catch {\n // Try legacy format (0: prefix)\n if (dataStr.startsWith(\"0:\")) {\n let text = dataStr.slice(2);\n if (text.startsWith('\"') && text.endsWith('\"')) {\n text = text.slice(1, -1);\n }\n text = text\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\r/g, \"\\r\")\n .replace(/\\\\t/g, \"\\t\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n assistantContent += text;\n\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n }\n }\n }\n }\n\n // Notify about completed assistant message\n const finalAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: assistantContent,\n timestamp: new Date(),\n };\n onMessage?.(finalAssistantMessage);\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n // Request was cancelled, ignore\n return;\n }\n\n const chatError =\n err instanceof Error ? err : new Error(\"An error occurred\");\n setError(chatError);\n\n if (onError) {\n // User handles errors themselves\n onError(chatError);\n } else {\n // Show default friendly error message\n const errorMsg: Message = {\n id: `error-${Date.now()}`,\n role: \"assistant\",\n content: errorMessage,\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMsg]);\n }\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n },\n [auth, endpoint, messages, isLoading, onMessage, onError, errorMessage],\n );\n\n const clearMessages = useCallback(() => {\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n setMessages([]);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return {\n messages,\n isLoading,\n error,\n sendMessage,\n clearMessages,\n };\n}\n","/**\n * ChatWidget Component\n *\n * Main embeddable chat widget with multiple display variants:\n * - floating: Bubble trigger with expandable panel (default)\n * - inline: Embedded chat interface for page sections\n * - fullpage: Full viewport chat experience\n *\n * Supports both API key and session authentication.\n *\n * @example Floating widget (default)\n * ```tsx\n * <ChatWidget auth={sessionAuth()} />\n * ```\n *\n * @example Inline embed\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"inline\" className=\"h-[500px]\" />\n * ```\n *\n * @example Full page\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"fullpage\" />\n * ```\n */\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport { ChatBubble } from \"./ChatBubble\";\nimport { ChatWindow } from \"./ChatWindow\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport { useChat } from \"../hooks/useChat\";\nimport type { ChatWidgetProps, AuthConfig } from \"../types\";\n\nexport function ChatWidget({\n auth,\n apiEndpoint,\n theme = \"light\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n greeting,\n placeholder = \"Type a message...\",\n defaultOpen = false,\n variant = \"floating\",\n className,\n title: customTitle,\n onOpen,\n onClose,\n onMessage,\n onError,\n}: ChatWidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n const { messages, isLoading, sendMessage, clearMessages } = useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n });\n\n const handleOpen = useCallback(() => {\n setIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n // Handle keyboard shortcut (Escape to close) - only for floating variant\n useEffect(() => {\n if (variant !== \"floating\") return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && isOpen) {\n e.preventDefault();\n handleClose();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, variant, handleClose]);\n\n const handleSendMessage = useCallback(\n (content: string) => {\n void sendMessage(content);\n },\n [sendMessage],\n );\n\n // Determine title based on auth type or use custom title\n const title =\n customTitle ?? (auth.type === \"api-key\" ? \"Chat\" : \"AiSU Assistant\");\n\n // Floating variant: bubble + expandable window\n if (variant === \"floating\") {\n return (\n <>\n <ChatBubble\n onClick={handleOpen}\n isOpen={isOpen}\n primaryColor={primaryColor}\n position={position}\n />\n {isOpen && (\n <ChatWindow\n messages={messages}\n isLoading={isLoading}\n onSendMessage={handleSendMessage}\n onClose={handleClose}\n title={title}\n placeholder={placeholder}\n primaryColor={primaryColor}\n position={position}\n />\n )}\n </>\n );\n }\n\n // Inline variant: embedded chat interface\n if (variant === \"inline\") {\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow: \"0 2px 8px rgba(0, 0, 0, 0.1)\",\n overflow: \"hidden\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n // Fullpage variant: takes full viewport\n if (variant === \"fullpage\") {\n return (\n <div\n className={className}\n style={{\n position: \"fixed\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n zIndex: 9999,\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"20px 24px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h2\n style={{\n margin: 0,\n fontSize: \"20px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h2>\n {onClose && (\n <button\n type=\"button\"\n onClick={handleClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"8px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n\n {/* Messages - flex grow to fill space */}\n <div style={{ flex: 1, overflow: \"hidden\" }}>\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n </div>\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n return null;\n}\n\n/**\n * Helper to create API key auth config\n * For external customers embedding the widget on their sites\n */\nexport function apiKeyAuth(apiKey: string): AuthConfig {\n return { type: \"api-key\", apiKey };\n}\n\n/**\n * Helper to create session auth config\n * For authenticated users in web apps\n */\nexport function sessionAuth(userId?: string): AuthConfig {\n return { type: \"session\", userId };\n}\n\n/**\n * Helper to create public/anonymous auth config\n * For unauthenticated users on public websites\n */\nexport function publicAuth(): AuthConfig {\n return { type: \"public\" };\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {useRef,useEffect,useState,useCallback}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var ne={primaryColor:"#0066FF",backgroundColor:"#FFFFFF",textColor:"#1A1A1A",borderColor:"#E5E5E5",inputBackground:"#F5F5F5"},ie={primaryColor:"#3B82F6",backgroundColor:"#1A1A1A",textColor:"#FFFFFF",borderColor:"#333333",inputBackground:"#2A2A2A"};function K({onClick:e,isOpen:n,primaryColor:u="#0066FF",position:o="bottom-right"}){return n?null:jsx("button",{type:"button",onClick:e,"aria-label":"Open chat",style:{position:"fixed",bottom:"24px",...o==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"56px",height:"56px",borderRadius:"50%",backgroundColor:u,border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)",transition:"transform 0.2s ease, box-shadow 0.2s ease",zIndex:9999},onMouseEnter:i=>{i.currentTarget.style.transform="scale(1.05)",i.currentTarget.style.boxShadow="0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)";},onMouseLeave:i=>{i.currentTarget.style.transform="scale(1)",i.currentTarget.style.boxShadow="0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)";},children:jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})})}function k({messages:e,isLoading:n=false,primaryColor:u="#0066FF"}){let o=useRef(null);return useEffect(()=>{o.current?.scrollIntoView({behavior:"smooth"});},[e]),e.length===0&&!n?jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:"24px",color:"#666",textAlign:"center"},children:jsx("p",{style:{margin:0,fontSize:"14px"},children:"Start a conversation by typing a message below."})}):jsxs("div",{style:{flex:1,overflowY:"auto",padding:"16px",display:"flex",flexDirection:"column",gap:"12px"},children:[e.map(r=>jsx("div",{style:{display:"flex",justifyContent:r.role==="user"?"flex-end":"flex-start"},children:jsx("div",{style:{maxWidth:"80%",padding:"12px 16px",borderRadius:"12px",backgroundColor:r.role==="user"?u:"#F3F4F6",color:r.role==="user"?"#FFFFFF":"#1F2937",fontSize:"14px",lineHeight:"1.5",wordBreak:"break-word",whiteSpace:"pre-wrap"},children:r.content})},r.id)),n&&e[e.length-1]?.role==="user"&&jsx("div",{style:{display:"flex",justifyContent:"flex-start"},children:jsxs("div",{style:{padding:"12px 16px",borderRadius:"12px",backgroundColor:"#F3F4F6",display:"flex",alignItems:"center",gap:"4px"},children:[jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite"}}),jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.2s"}}),jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.4s"}})]})}),jsx("div",{ref:o}),jsx("style",{children:`
|
|
2
|
+
@keyframes pulse {
|
|
3
|
+
0%, 100% { opacity: 0.4; transform: scale(0.8); }
|
|
4
|
+
50% { opacity: 1; transform: scale(1); }
|
|
5
|
+
}
|
|
6
|
+
`})]})}function M({onSubmit:e,isLoading:n=false,placeholder:u="Type a message...",primaryColor:o="#0066FF"}){let[r,i]=useState(""),s=useRef(null);useEffect(()=>{let t=s.current;t&&(t.style.height="auto",t.style.height=`${Math.min(t.scrollHeight,120)}px`);},[r]);let g=useCallback(()=>{let t=r.trim();!t||n||(e(t),i(""),s.current&&(s.current.style.height="auto"));},[r,n,e]),d=useCallback(t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),g());},[g]),a=r.trim().length>0&&!n;return jsxs("div",{style:{padding:"12px 16px",borderTop:"1px solid #E5E7EB",backgroundColor:"#FFFFFF"},children:[jsxs("div",{style:{display:"flex",alignItems:"flex-end",gap:"8px"},children:[jsx("textarea",{ref:s,value:r,onChange:t=>i(t.target.value),onKeyDown:d,placeholder:u,disabled:n,rows:1,style:{flex:1,padding:"10px 12px",borderRadius:"8px",border:"1px solid #E5E7EB",backgroundColor:"#F9FAFB",fontSize:"14px",lineHeight:"1.5",resize:"none",outline:"none",fontFamily:"inherit",minHeight:"42px",maxHeight:"120px"},onFocus:t=>{t.currentTarget.style.borderColor=o,t.currentTarget.style.boxShadow=`0 0 0 2px ${o}20`;},onBlur:t=>{t.currentTarget.style.borderColor="#E5E7EB",t.currentTarget.style.boxShadow="none";}}),jsx("button",{type:"button",onClick:g,disabled:!a,"aria-label":"Send message",style:{width:"42px",height:"42px",borderRadius:"8px",border:"none",backgroundColor:a?o:"#E5E7EB",cursor:a?"pointer":"not-allowed",display:"flex",alignItems:"center",justifyContent:"center",transition:"background-color 0.2s ease, transform 0.1s ease",flexShrink:0},onMouseEnter:t=>{a&&(t.currentTarget.style.transform="scale(1.05)");},onMouseLeave:t=>{t.currentTarget.style.transform="scale(1)";},children:n?jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",style:{animation:"spin 1s linear infinite"},children:jsx("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})}):jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:a?"white":"#9CA3AF",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]}),jsx("style",{children:`
|
|
7
|
+
@keyframes spin {
|
|
8
|
+
from { transform: rotate(0deg); }
|
|
9
|
+
to { transform: rotate(360deg); }
|
|
10
|
+
}
|
|
11
|
+
`})]})}function O({messages:e,isLoading:n,onSendMessage:u,onClose:o,title:r="Chat",placeholder:i="Type a message...",primaryColor:s="#0066FF",position:g="bottom-right"}){return jsxs("div",{style:{position:"fixed",bottom:"24px",...g==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"380px",height:"520px",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)",display:"flex",flexDirection:"column",overflow:"hidden",zIndex:9999,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsxs("div",{style:{padding:"16px",backgroundColor:s,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:r}),jsx("button",{type:"button",onClick:o,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"4px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px",transition:"background-color 0.2s ease"},onMouseEnter:a=>{a.currentTarget.style.backgroundColor="rgba(255, 255, 255, 0.2)";},onMouseLeave:a=>{a.currentTarget.style.backgroundColor="transparent";},children:jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsx(k,{messages:e,isLoading:n,primaryColor:s}),jsx(M,{onSubmit:u,isLoading:n,placeholder:i,primaryColor:s})]})}async function J(e){switch(e.type){case "api-key":return {"x-api-key":e.apiKey};case "session":return {};case "public":return {};case "assistant":return {};case "custom":return e.getAuthHeaders();default:return {}}}var ge="Sorry, I encountered an error. Please try again.";function fe(e){switch(e.type){case "api-key":return "/api/chat";case "session":return "/api/authenticated-chat";case "public":return "/api/public-chat";case "assistant":return `/api/public/assistant/${e.assistantId}/chat`;case "custom":return "/api/authenticated-chat";default:return "/api/public-chat"}}function U({auth:e,apiEndpoint:n,onMessage:u,onError:o,errorMessage:r=ge}){let[i,s]=useState([]),[g,d]=useState(false),[a,t]=useState(null),h=useRef(null),S=n??fe(e),z=useCallback(async C=>{if(!C.trim()||g)return;h.current&&h.current.abort(),h.current=new AbortController;let R={id:`user-${Date.now()}`,role:"user",content:C.trim(),timestamp:new Date};s(c=>[...c,R]),u?.(R),d(true),t(null);try{let c=await J(e),l=await fetch(S,{method:"POST",headers:{"Content-Type":"application/json",...c},credentials:e.type==="session"?"include":"same-origin",body:JSON.stringify({messages:[...i,R].map(y=>({role:y.role,content:y.content})),...e.type==="session"&&e.userId?{userId:e.userId}:{}}),signal:h.current.signal});if(!l.ok){let y=await l.json().catch(()=>({}));throw new Error(y.error??`Request failed with status ${l.status}`)}let F=l.body?.getReader(),W=new TextDecoder,A="",w=`assistant-${Date.now()}`;if(F){let y={id:w,role:"assistant",content:"",timestamp:new Date};for(s(b=>[...b,y]);;){let{done:b,value:B}=await F.read();if(b)break;let se=W.decode(B,{stream:!0}).split(`
|
|
12
|
+
`),Y="";for(let H of se)if(H.startsWith("event:"))Y=H.slice(6).trim();else if(H.startsWith("data:")){let L=H.slice(5).trim();if(!L||L==="[DONE]")continue;try{let f=JSON.parse(L);if(Y==="text-delta"||f.type==="text-delta"){let N=f.delta??f.value??"";A+=N,s(v=>{let x=[...v],P=x.length-1;return P>=0&&x[P]?.role==="assistant"&&(x[P]={...x[P],content:A}),x});}}catch{if(L.startsWith("0:")){let f=L.slice(2);f.startsWith('"')&&f.endsWith('"')&&(f=f.slice(1,-1)),f=f.replace(/\\n/g,`
|
|
13
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\"),A+=f,s(N=>{let v=[...N],x=v.length-1;return x>=0&&v[x]?.role==="assistant"&&(v[x]={...v[x],content:A}),v});}}}}u?.({id:w,role:"assistant",content:A,timestamp:new Date});}}catch(c){if(c instanceof Error&&c.name==="AbortError")return;let l=c instanceof Error?c:new Error("An error occurred");if(t(l),o)o(l);else {let F={id:`error-${Date.now()}`,role:"assistant",content:r,timestamp:new Date};s(W=>[...W,F]);}}finally{d(false),h.current=null;}},[e,S,i,g,u,o,r]),j=useCallback(()=>{h.current&&h.current.abort(),s([]),t(null),d(false);},[]);return {messages:i,isLoading:g,error:a,sendMessage:z,clearMessages:j}}function ee({auth:e,apiEndpoint:n,theme:u="light",primaryColor:o="#0066FF",position:r="bottom-right",greeting:i,placeholder:s="Type a message...",defaultOpen:g=false,variant:d="floating",className:a,title:t,onOpen:h,onClose:S,onMessage:z,onError:j}){let[C,R]=useState(g),{messages:c,isLoading:l,sendMessage:F,clearMessages:W}=U({auth:e,apiEndpoint:n,onMessage:z,onError:j}),A=useCallback(()=>{R(true),h?.();},[h]),w=useCallback(()=>{R(false),S?.();},[S]);useEffect(()=>{if(d!=="floating")return;let b=B=>{B.key==="Escape"&&C&&(B.preventDefault(),w());};return window.addEventListener("keydown",b),()=>window.removeEventListener("keydown",b)},[C,d,w]);let y=useCallback(b=>{F(b);},[F]),D=t??(e.type==="api-key"?"Chat":"AiSU Assistant");return d==="floating"?jsxs(Fragment,{children:[jsx(K,{onClick:A,isOpen:C,primaryColor:o,position:r}),C&&jsx(O,{messages:c,isLoading:l,onSendMessage:y,onClose:w,title:D,placeholder:s,primaryColor:o,position:r})]}):d==="inline"?jsxs("div",{className:a,style:{display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",overflow:"hidden",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsx("div",{style:{padding:"16px",backgroundColor:o,color:"#FFFFFF"},children:jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:D})}),jsx(k,{messages:c,isLoading:l,primaryColor:o}),jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):d==="fullpage"?jsxs("div",{className:a,style:{position:"fixed",inset:0,display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',zIndex:9999},children:[jsxs("div",{style:{padding:"20px 24px",backgroundColor:o,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsx("h2",{style:{margin:0,fontSize:"20px",fontWeight:600},children:D}),S&&jsx("button",{type:"button",onClick:w,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"8px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px"},children:jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsx("div",{style:{flex:1,overflow:"hidden"},children:jsx(k,{messages:c,isLoading:l,primaryColor:o})}),jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):null}function te(e){return {type:"api-key",apiKey:e}}function oe(e){return {type:"session",userId:e}}function re(){return {type:"public"}}export{K as ChatBubble,M as ChatInput,ee as ChatWidget,O as ChatWindow,ie as DARK_THEME,ne as DEFAULT_THEME,k as MessageList,te as apiKeyAuth,re as publicAuth,oe as sessionAuth,U as useChat};//# sourceMappingURL=index.mjs.map
|
|
14
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/styles/index.ts","../src/components/ChatBubble.tsx","../src/components/MessageList.tsx","../src/components/ChatInput.tsx","../src/components/ChatWindow.tsx","../src/types/auth.ts","../src/hooks/useChat.ts","../src/components/ChatWidget.tsx"],"names":["DEFAULT_THEME","DARK_THEME","ChatBubble","onClick","isOpen","primaryColor","position","jsx","e","MessageList","messages","isLoading","messagesEndRef","useRef","useEffect","jsxs","message","ChatInput","onSubmit","placeholder","value","setValue","useState","textareaRef","textarea","handleSubmit","useCallback","trimmed","handleKeyDown","canSubmit","ChatWindow","onSendMessage","onClose","title","getAuthHeaders","config","DEFAULT_ERROR_MESSAGE","getDefaultEndpoint","auth","useChat","apiEndpoint","onMessage","onError","errorMessage","setMessages","setIsLoading","error","setError","abortControllerRef","endpoint","sendMessage","content","userMessage","prev","authHeaders","response","m","errorData","reader","decoder","assistantContent","assistantMessageId","initialAssistantMessage","done","lines","currentEvent","line","dataStr","data","text","newMessages","lastIdx","err","chatError","errorMsg","clearMessages","ChatWidget","theme","greeting","defaultOpen","variant","className","customTitle","onOpen","setIsOpen","handleOpen","handleClose","handleSendMessage","Fragment","apiKeyAuth","apiKey","sessionAuth","userId","publicAuth"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Style exports for @aisuai/chat-widget\n *\n * Styles will be added in subsequent tasks:\n * - CSS variables for theming\n * - Base component styles\n * - Animation keyframes\n */\n\n// Default theme colors\nexport const DEFAULT_THEME = {\n primaryColor: \"#0066FF\",\n backgroundColor: \"#FFFFFF\",\n textColor: \"#1A1A1A\",\n borderColor: \"#E5E5E5\",\n inputBackground: \"#F5F5F5\",\n} as const;\n\n// Dark theme colors\nexport const DARK_THEME = {\n primaryColor: \"#3B82F6\",\n backgroundColor: \"#1A1A1A\",\n textColor: \"#FFFFFF\",\n borderColor: \"#333333\",\n inputBackground: \"#2A2A2A\",\n} as const;\n\nexport type ThemeColors = typeof DEFAULT_THEME;\n","/**\n * ChatBubble Component\n *\n * Floating trigger button that opens the chat widget.\n */\n\nimport React from \"react\";\n\ninterface ChatBubbleProps {\n onClick: () => void;\n isOpen: boolean;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatBubble({\n onClick,\n isOpen,\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatBubbleProps) {\n if (isOpen) return null;\n\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Open chat\"\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n backgroundColor: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.2s ease, box-shadow 0.2s ease\",\n zIndex: 9999,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n e.currentTarget.style.boxShadow =\n \"0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n e.currentTarget.style.boxShadow =\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\";\n }}\n >\n {/* Chat icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </button>\n );\n}\n","/**\n * MessageList Component\n *\n * Displays chat messages with proper styling for user and assistant roles.\n */\n\nimport React, { useEffect, useRef } from \"react\";\nimport type { Message } from \"../types\";\n\ninterface MessageListProps {\n messages: Message[];\n isLoading?: boolean;\n primaryColor?: string;\n}\n\nexport function MessageList({\n messages,\n isLoading = false,\n primaryColor = \"#0066FF\",\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n if (messages.length === 0 && !isLoading) {\n return (\n <div\n style={{\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"24px\",\n color: \"#666\",\n textAlign: \"center\",\n }}\n >\n <p style={{ margin: 0, fontSize: \"14px\" }}>\n Start a conversation by typing a message below.\n </p>\n </div>\n );\n }\n\n return (\n <div\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: \"16px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {messages.map((message) => (\n <div\n key={message.id}\n style={{\n display: \"flex\",\n justifyContent: message.role === \"user\" ? \"flex-end\" : \"flex-start\",\n }}\n >\n <div\n style={{\n maxWidth: \"80%\",\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor:\n message.role === \"user\" ? primaryColor : \"#F3F4F6\",\n color: message.role === \"user\" ? \"#FFFFFF\" : \"#1F2937\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n wordBreak: \"break-word\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {message.content}\n </div>\n </div>\n ))}\n\n {/* Loading indicator */}\n {isLoading && messages[messages.length - 1]?.role === \"user\" && (\n <div style={{ display: \"flex\", justifyContent: \"flex-start\" }}>\n <div\n style={{\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor: \"#F3F4F6\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"4px\",\n }}\n >\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.2s\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.4s\",\n }}\n />\n </div>\n </div>\n )}\n\n {/* Auto-scroll anchor */}\n <div ref={messagesEndRef} />\n\n {/* Keyframe animation for loading dots */}\n <style>{`\n @keyframes pulse {\n 0%, 100% { opacity: 0.4; transform: scale(0.8); }\n 50% { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatInput Component\n *\n * Text input with send button for the chat widget.\n */\n\nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\n\ninterface ChatInputProps {\n onSubmit: (message: string) => void;\n isLoading?: boolean;\n placeholder?: string;\n primaryColor?: string;\n}\n\nexport function ChatInput({\n onSubmit,\n isLoading = false,\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n}: ChatInputProps) {\n const [value, setValue] = useState(\"\");\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-resize textarea\n useEffect(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n }\n }, [value]);\n\n const handleSubmit = useCallback(() => {\n const trimmed = value.trim();\n if (!trimmed || isLoading) return;\n\n onSubmit(trimmed);\n setValue(\"\");\n\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n }\n }, [value, isLoading, onSubmit]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n },\n [handleSubmit],\n );\n\n const canSubmit = value.trim().length > 0 && !isLoading;\n\n return (\n <div\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid #E5E7EB\",\n backgroundColor: \"#FFFFFF\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-end\",\n gap: \"8px\",\n }}\n >\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={isLoading}\n rows={1}\n style={{\n flex: 1,\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: \"1px solid #E5E7EB\",\n backgroundColor: \"#F9FAFB\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n resize: \"none\",\n outline: \"none\",\n fontFamily: \"inherit\",\n minHeight: \"42px\",\n maxHeight: \"120px\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.borderColor = primaryColor;\n e.currentTarget.style.boxShadow = `0 0 0 2px ${primaryColor}20`;\n }}\n onBlur={(e) => {\n e.currentTarget.style.borderColor = \"#E5E7EB\";\n e.currentTarget.style.boxShadow = \"none\";\n }}\n />\n\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n aria-label=\"Send message\"\n style={{\n width: \"42px\",\n height: \"42px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: canSubmit ? primaryColor : \"#E5E7EB\",\n cursor: canSubmit ? \"pointer\" : \"not-allowed\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n transition: \"background-color 0.2s ease, transform 0.1s ease\",\n flexShrink: 0,\n }}\n onMouseEnter={(e) => {\n if (canSubmit) {\n e.currentTarget.style.transform = \"scale(1.05)\";\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n }}\n >\n {isLoading ? (\n // Loading spinner\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n style={{\n animation: \"spin 1s linear infinite\",\n }}\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n ) : (\n // Send icon\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={canSubmit ? \"white\" : \"#9CA3AF\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n )}\n </button>\n </div>\n\n {/* Keyframe animation for spinner */}\n <style>{`\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatWindow Component\n *\n * The expandable chat panel containing messages and input.\n */\n\nimport React from \"react\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport type { Message } from \"../types\";\n\ninterface ChatWindowProps {\n messages: Message[];\n isLoading: boolean;\n onSendMessage: (message: string) => void;\n onClose: () => void;\n title?: string;\n placeholder?: string;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatWindow({\n messages,\n isLoading,\n onSendMessage,\n onClose,\n title = \"Chat\",\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatWindowProps) {\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <div\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"380px\",\n height: \"520px\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow:\n \"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)\",\n display: \"flex\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n zIndex: 9999,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n transition: \"background-color 0.2s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255, 255, 255, 0.2)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"transparent\";\n }}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={onSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n}\n","/**\n * Authentication Types\n *\n * Supports API key, session, public (anonymous), and custom authentication.\n */\n\n/**\n * API Key authentication config\n * For external customers embedding the widget on their sites\n */\nexport interface ApiKeyAuthConfig {\n type: \"api-key\";\n apiKey: string;\n}\n\n/**\n * OAuth/Session authentication config\n * Uses cookies/session - no explicit token needed\n */\nexport interface SessionAuthConfig {\n type: \"session\";\n /**\n * Optional user ID for analytics/tracking\n */\n userId?: string;\n}\n\n/**\n * Public/Anonymous authentication config\n * For unauthenticated users on public websites\n */\nexport interface PublicAuthConfig {\n type: \"public\";\n}\n\n/**\n * Assistant-based authentication config\n * Uses an assistant ID to configure the widget with curated document access\n */\nexport interface AssistantAuthConfig {\n type: \"assistant\";\n /**\n * The assistant ID (e.g., \"ast_xxx\")\n */\n assistantId: string;\n}\n\n/**\n * Custom authentication config\n * Allows full control over auth headers\n */\nexport interface CustomAuthConfig {\n type: \"custom\";\n /**\n * Function that returns headers for authentication\n */\n getAuthHeaders: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n}\n\n/**\n * Union of all auth configurations\n */\nexport type AuthConfig =\n | ApiKeyAuthConfig\n | SessionAuthConfig\n | PublicAuthConfig\n | AssistantAuthConfig\n | CustomAuthConfig;\n\n/**\n * Helper to build auth headers from config\n */\nexport async function getAuthHeaders(\n config: AuthConfig,\n): Promise<Record<string, string>> {\n switch (config.type) {\n case \"api-key\":\n return { \"x-api-key\": config.apiKey };\n case \"session\":\n // Session auth uses cookies, no explicit headers needed\n return {};\n case \"public\":\n // Public auth - no headers needed\n return {};\n case \"assistant\":\n // Assistant auth - no special headers, ID is in URL\n return {};\n case \"custom\":\n return config.getAuthHeaders();\n default:\n return {};\n }\n}\n","/**\n * useChat Hook\n *\n * Core hook for chat API communication.\n * Handles streaming responses and message management.\n * Supports both API key and session/OAuth authentication.\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Message, AuthConfig } from \"../types\";\nimport { getAuthHeaders } from \"../types\";\n\nconst DEFAULT_ERROR_MESSAGE =\n \"Sorry, I encountered an error. Please try again.\";\n\ninterface UseChatOptions {\n /**\n * Authentication configuration\n */\n auth: AuthConfig;\n\n /**\n * API endpoint URL\n * Defaults based on auth type:\n * - API key: production API\n * - Session: /api/chat or /api/authenticated-chat\n */\n apiEndpoint?: string;\n\n /**\n * Callback when a message is sent or received\n */\n onMessage?: (message: Message) => void;\n\n /**\n * Callback when an error occurs\n * If provided, no default error message is shown - you handle it yourself\n */\n onError?: (error: Error) => void;\n\n /**\n * Custom error message to display when chat fails\n * Only used when onError is not provided\n * @default 'Sorry, I encountered an error. Please try again.'\n */\n errorMessage?: string;\n}\n\ninterface UseChatReturn {\n messages: Message[];\n isLoading: boolean;\n error: Error | null;\n sendMessage: (content: string) => Promise<void>;\n clearMessages: () => void;\n}\n\n/**\n * Get default API endpoint based on auth type\n */\nfunction getDefaultEndpoint(auth: AuthConfig): string {\n switch (auth.type) {\n case \"api-key\":\n // External customers use the API key chat endpoint\n return \"/api/chat\";\n case \"session\":\n // Session auth uses authenticated chat\n return \"/api/authenticated-chat\";\n case \"public\":\n // Anonymous public users\n return \"/api/public-chat\";\n case \"assistant\":\n // Assistant-based public access\n return `/api/public/assistant/${auth.assistantId}/chat`;\n case \"custom\":\n // Custom auth - default to authenticated endpoint\n return \"/api/authenticated-chat\";\n default:\n return \"/api/public-chat\";\n }\n}\n\nexport function useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n errorMessage = DEFAULT_ERROR_MESSAGE,\n}: UseChatOptions): UseChatReturn {\n const [messages, setMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const endpoint = apiEndpoint ?? getDefaultEndpoint(auth);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim() || isLoading) return;\n\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n abortControllerRef.current = new AbortController();\n\n const userMessage: Message = {\n id: `user-${Date.now()}`,\n role: \"user\",\n content: content.trim(),\n timestamp: new Date(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessage?.(userMessage);\n setIsLoading(true);\n setError(null);\n\n try {\n // Get auth headers based on auth type\n const authHeaders = await getAuthHeaders(auth);\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...authHeaders,\n },\n // Include credentials for session auth (cookies)\n credentials: auth.type === \"session\" ? \"include\" : \"same-origin\",\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n // Include userId for session auth if provided\n ...(auth.type === \"session\" && auth.userId\n ? { userId: auth.userId }\n : {}),\n }),\n signal: abortControllerRef.current.signal,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error ?? `Request failed with status ${response.status}`,\n );\n }\n\n const reader = response.body?.getReader();\n const decoder = new TextDecoder();\n let assistantContent = \"\";\n const assistantMessageId = `assistant-${Date.now()}`;\n\n if (reader) {\n // Add initial assistant message\n const initialAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: \"\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, initialAssistantMessage]);\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n\n // Parse SSE format (AI SDK v6 UIMessageStream)\n const lines = chunk.split(\"\\n\");\n let currentEvent = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n currentEvent = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const dataStr = line.slice(5).trim();\n if (!dataStr || dataStr === \"[DONE]\") continue;\n\n try {\n const data = JSON.parse(dataStr) as {\n type?: string;\n delta?: string;\n value?: string;\n };\n\n // Handle text-delta events\n if (\n currentEvent === \"text-delta\" ||\n data.type === \"text-delta\"\n ) {\n const text = data.delta ?? data.value ?? \"\";\n assistantContent += text;\n\n // Update assistant message\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n } catch {\n // Try legacy format (0: prefix)\n if (dataStr.startsWith(\"0:\")) {\n let text = dataStr.slice(2);\n if (text.startsWith('\"') && text.endsWith('\"')) {\n text = text.slice(1, -1);\n }\n text = text\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\r/g, \"\\r\")\n .replace(/\\\\t/g, \"\\t\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n assistantContent += text;\n\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n }\n }\n }\n }\n\n // Notify about completed assistant message\n const finalAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: assistantContent,\n timestamp: new Date(),\n };\n onMessage?.(finalAssistantMessage);\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n // Request was cancelled, ignore\n return;\n }\n\n const chatError =\n err instanceof Error ? err : new Error(\"An error occurred\");\n setError(chatError);\n\n if (onError) {\n // User handles errors themselves\n onError(chatError);\n } else {\n // Show default friendly error message\n const errorMsg: Message = {\n id: `error-${Date.now()}`,\n role: \"assistant\",\n content: errorMessage,\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMsg]);\n }\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n },\n [auth, endpoint, messages, isLoading, onMessage, onError, errorMessage],\n );\n\n const clearMessages = useCallback(() => {\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n setMessages([]);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return {\n messages,\n isLoading,\n error,\n sendMessage,\n clearMessages,\n };\n}\n","/**\n * ChatWidget Component\n *\n * Main embeddable chat widget with multiple display variants:\n * - floating: Bubble trigger with expandable panel (default)\n * - inline: Embedded chat interface for page sections\n * - fullpage: Full viewport chat experience\n *\n * Supports both API key and session authentication.\n *\n * @example Floating widget (default)\n * ```tsx\n * <ChatWidget auth={sessionAuth()} />\n * ```\n *\n * @example Inline embed\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"inline\" className=\"h-[500px]\" />\n * ```\n *\n * @example Full page\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"fullpage\" />\n * ```\n */\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport { ChatBubble } from \"./ChatBubble\";\nimport { ChatWindow } from \"./ChatWindow\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport { useChat } from \"../hooks/useChat\";\nimport type { ChatWidgetProps, AuthConfig } from \"../types\";\n\nexport function ChatWidget({\n auth,\n apiEndpoint,\n theme = \"light\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n greeting,\n placeholder = \"Type a message...\",\n defaultOpen = false,\n variant = \"floating\",\n className,\n title: customTitle,\n onOpen,\n onClose,\n onMessage,\n onError,\n}: ChatWidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n const { messages, isLoading, sendMessage, clearMessages } = useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n });\n\n const handleOpen = useCallback(() => {\n setIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n // Handle keyboard shortcut (Escape to close) - only for floating variant\n useEffect(() => {\n if (variant !== \"floating\") return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && isOpen) {\n e.preventDefault();\n handleClose();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, variant, handleClose]);\n\n const handleSendMessage = useCallback(\n (content: string) => {\n void sendMessage(content);\n },\n [sendMessage],\n );\n\n // Determine title based on auth type or use custom title\n const title =\n customTitle ?? (auth.type === \"api-key\" ? \"Chat\" : \"AiSU Assistant\");\n\n // Floating variant: bubble + expandable window\n if (variant === \"floating\") {\n return (\n <>\n <ChatBubble\n onClick={handleOpen}\n isOpen={isOpen}\n primaryColor={primaryColor}\n position={position}\n />\n {isOpen && (\n <ChatWindow\n messages={messages}\n isLoading={isLoading}\n onSendMessage={handleSendMessage}\n onClose={handleClose}\n title={title}\n placeholder={placeholder}\n primaryColor={primaryColor}\n position={position}\n />\n )}\n </>\n );\n }\n\n // Inline variant: embedded chat interface\n if (variant === \"inline\") {\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow: \"0 2px 8px rgba(0, 0, 0, 0.1)\",\n overflow: \"hidden\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n // Fullpage variant: takes full viewport\n if (variant === \"fullpage\") {\n return (\n <div\n className={className}\n style={{\n position: \"fixed\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n zIndex: 9999,\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"20px 24px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h2\n style={{\n margin: 0,\n fontSize: \"20px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h2>\n {onClose && (\n <button\n type=\"button\"\n onClick={handleClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"8px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n\n {/* Messages - flex grow to fill space */}\n <div style={{ flex: 1, overflow: \"hidden\" }}>\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n </div>\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n return null;\n}\n\n/**\n * Helper to create API key auth config\n * For external customers embedding the widget on their sites\n */\nexport function apiKeyAuth(apiKey: string): AuthConfig {\n return { type: \"api-key\", apiKey };\n}\n\n/**\n * Helper to create session auth config\n * For authenticated users in web apps\n */\nexport function sessionAuth(userId?: string): AuthConfig {\n return { type: \"session\", userId };\n}\n\n/**\n * Helper to create public/anonymous auth config\n * For unauthenticated users on public websites\n */\nexport function publicAuth(): AuthConfig {\n return { type: \"public\" };\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aisuai/chat-widget",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Embeddable chat widget for AiSU",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public",
|
|
22
|
+
"provenance": true
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"type-check": "tsc --noEmit",
|
|
28
|
+
"clean": "rm -rf dist",
|
|
29
|
+
"prepublishOnly": "pnpm build"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=18.0.0",
|
|
33
|
+
"react-dom": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/react": "^18.2.0",
|
|
37
|
+
"@types/react-dom": "^18.2.0",
|
|
38
|
+
"react": "^18.2.0",
|
|
39
|
+
"react-dom": "^18.2.0",
|
|
40
|
+
"tsup": "^8.0.0",
|
|
41
|
+
"typescript": "^5.0.0"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"chat",
|
|
45
|
+
"widget",
|
|
46
|
+
"react",
|
|
47
|
+
"ai",
|
|
48
|
+
"aisu"
|
|
49
|
+
],
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://github.com/AiSU-AI/Company-Site.git",
|
|
54
|
+
"directory": "packages/chat-widget"
|
|
55
|
+
}
|
|
56
|
+
}
|