@makemore/agent-frontend 1.7.1 → 1.8.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 +122 -0
- package/dist/chat-widget.js +212 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -175,6 +175,124 @@ See `django-tts-example.py` for the complete Django backend implementation.
|
|
|
175
175
|
| `showVoiceSettings` | boolean | `true` | Show voice settings button in header (works with proxy and direct API) |
|
|
176
176
|
| `showExpandButton` | boolean | `true` | Show expand/minimize button in header |
|
|
177
177
|
| `onEvent` | function | `null` | Callback for SSE events: `(eventType, payload) => void` |
|
|
178
|
+
| `authStrategy` | string | `null` | Auth strategy: `'token'`, `'jwt'`, `'session'`, `'anonymous'`, `'none'` (auto-detected if null) |
|
|
179
|
+
| `authToken` | string | `null` | Token value for `'token'` or `'jwt'` strategies |
|
|
180
|
+
| `authHeader` | string | `null` | Custom header name (defaults based on strategy) |
|
|
181
|
+
| `authTokenPrefix` | string | `null` | Custom token prefix (defaults based on strategy) |
|
|
182
|
+
| `anonymousSessionEndpoint` | string | `null` | Endpoint for anonymous session (defaults to `apiPaths.anonymousSession`) |
|
|
183
|
+
| `anonymousTokenKey` | string | `'chat_widget_anonymous_token'` | localStorage key for anonymous token |
|
|
184
|
+
| `onAuthError` | function | `null` | Callback for auth errors: `(error) => void` |
|
|
185
|
+
|
|
186
|
+
### Authentication
|
|
187
|
+
|
|
188
|
+
The widget supports multiple authentication strategies with sensible defaults:
|
|
189
|
+
|
|
190
|
+
#### Token Authentication (Django REST Framework)
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
ChatWidget.init({
|
|
194
|
+
backendUrl: 'https://api.example.com',
|
|
195
|
+
agentKey: 'my-agent',
|
|
196
|
+
authStrategy: 'token',
|
|
197
|
+
authToken: 'abc123...',
|
|
198
|
+
// Sends: Authorization: Token abc123...
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### JWT/Bearer Authentication
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
ChatWidget.init({
|
|
206
|
+
backendUrl: 'https://api.example.com',
|
|
207
|
+
agentKey: 'my-agent',
|
|
208
|
+
authStrategy: 'jwt',
|
|
209
|
+
authToken: 'eyJ...',
|
|
210
|
+
// Sends: Authorization: Bearer eyJ...
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Session-Based Authentication (Cookies)
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
ChatWidget.init({
|
|
218
|
+
backendUrl: 'https://api.example.com',
|
|
219
|
+
agentKey: 'my-agent',
|
|
220
|
+
authStrategy: 'session',
|
|
221
|
+
// Sends requests with credentials: 'include'
|
|
222
|
+
// No auth header, relies on session cookie
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### Anonymous Session Tokens
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
ChatWidget.init({
|
|
230
|
+
backendUrl: 'https://api.example.com',
|
|
231
|
+
agentKey: 'my-agent',
|
|
232
|
+
authStrategy: 'anonymous',
|
|
233
|
+
anonymousSessionEndpoint: '/api/accounts/anonymous-session/',
|
|
234
|
+
// On first request: fetches anonymous token from endpoint
|
|
235
|
+
// Persists token to localStorage
|
|
236
|
+
// Sends: X-Anonymous-Token: {token}
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### No Authentication (Public Endpoints)
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
ChatWidget.init({
|
|
244
|
+
backendUrl: 'https://api.example.com',
|
|
245
|
+
agentKey: 'my-agent',
|
|
246
|
+
authStrategy: 'none',
|
|
247
|
+
// No auth headers sent
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### Custom Headers and Prefixes
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
ChatWidget.init({
|
|
255
|
+
authStrategy: 'token',
|
|
256
|
+
authToken: 'mytoken123',
|
|
257
|
+
authHeader: 'X-API-Key', // Custom header name
|
|
258
|
+
authTokenPrefix: '', // No prefix (just the token)
|
|
259
|
+
// Sends: X-API-Key: mytoken123
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### Dynamic Token Updates
|
|
264
|
+
|
|
265
|
+
Update authentication after initialization (e.g., after user login):
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
// After user logs in
|
|
269
|
+
ChatWidget.setAuth({
|
|
270
|
+
strategy: 'jwt',
|
|
271
|
+
token: 'new-jwt-token-after-login'
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// After user logs out
|
|
275
|
+
ChatWidget.clearAuth();
|
|
276
|
+
|
|
277
|
+
// Handle token refresh on auth errors
|
|
278
|
+
ChatWidget.init({
|
|
279
|
+
authStrategy: 'jwt',
|
|
280
|
+
authToken: initialToken,
|
|
281
|
+
onAuthError: async (error) => {
|
|
282
|
+
if (error.status === 401) {
|
|
283
|
+
const newToken = await refreshToken();
|
|
284
|
+
ChatWidget.setAuth({ token: newToken });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### Auto-Detection
|
|
291
|
+
|
|
292
|
+
If no `authStrategy` is specified, the widget auto-detects based on config:
|
|
293
|
+
- If `authToken` is provided → uses `'token'` strategy
|
|
294
|
+
- If `anonymousSessionEndpoint` or `apiPaths.anonymousSession` is configured → uses `'anonymous'` strategy
|
|
295
|
+
- Otherwise → uses `'none'`
|
|
178
296
|
|
|
179
297
|
### Event Callback
|
|
180
298
|
|
|
@@ -477,6 +595,10 @@ ChatWidget.setAutoRunMode('automatic'); // 'automatic', 'confirm', or 'manual'
|
|
|
477
595
|
// Change auto-run delay (in milliseconds)
|
|
478
596
|
ChatWidget.setAutoRunDelay(2000);
|
|
479
597
|
|
|
598
|
+
// Authentication methods
|
|
599
|
+
ChatWidget.setAuth({ strategy: 'jwt', token: 'new-token' }); // Update auth
|
|
600
|
+
ChatWidget.clearAuth(); // Clear authentication
|
|
601
|
+
|
|
480
602
|
// Remove the widget from the page
|
|
481
603
|
ChatWidget.destroy();
|
|
482
604
|
|
package/dist/chat-widget.js
CHANGED
|
@@ -33,9 +33,18 @@
|
|
|
33
33
|
placeholder: 'Type your message...',
|
|
34
34
|
emptyStateTitle: 'Start a Conversation',
|
|
35
35
|
emptyStateMessage: 'Send a message to get started.',
|
|
36
|
+
// Authentication configuration
|
|
37
|
+
authStrategy: null, // 'token' | 'jwt' | 'session' | 'anonymous' | 'none' (auto-detected if null)
|
|
38
|
+
authToken: null, // Token value for 'token' or 'jwt' strategies
|
|
39
|
+
authHeader: null, // Custom header name (defaults based on strategy)
|
|
40
|
+
authTokenPrefix: null, // Custom token prefix (defaults based on strategy)
|
|
41
|
+
anonymousSessionEndpoint: null, // Endpoint for anonymous session (defaults to apiPaths.anonymousSession)
|
|
42
|
+
anonymousTokenKey: 'chat_widget_anonymous_token', // Storage key for anonymous token
|
|
43
|
+
onAuthError: null, // Callback for auth errors: (error) => void
|
|
44
|
+
// Legacy config (deprecated but still supported)
|
|
36
45
|
anonymousTokenHeader: 'X-Anonymous-Token',
|
|
37
46
|
conversationIdKey: 'chat_widget_conversation_id',
|
|
38
|
-
sessionTokenKey: 'chat_widget_session_token',
|
|
47
|
+
sessionTokenKey: 'chat_widget_session_token', // Deprecated: use anonymousTokenKey
|
|
39
48
|
// API endpoint paths (can be customized for different backend setups)
|
|
40
49
|
apiPaths: {
|
|
41
50
|
anonymousSession: '/api/accounts/anonymous-session/',
|
|
@@ -87,7 +96,8 @@
|
|
|
87
96
|
journeyType: 'general',
|
|
88
97
|
messages: [],
|
|
89
98
|
conversationId: null,
|
|
90
|
-
sessionToken: null,
|
|
99
|
+
sessionToken: null, // Deprecated: use authToken
|
|
100
|
+
authToken: null, // Current auth token (for token/jwt/anonymous strategies)
|
|
91
101
|
error: null,
|
|
92
102
|
eventSource: null,
|
|
93
103
|
currentAudio: null,
|
|
@@ -219,17 +229,16 @@
|
|
|
219
229
|
|
|
220
230
|
if (config.ttsProxyUrl) {
|
|
221
231
|
// Use Django proxy
|
|
222
|
-
response = await fetch(config.ttsProxyUrl, {
|
|
232
|
+
response = await fetch(config.ttsProxyUrl, getFetchOptions({
|
|
223
233
|
method: 'POST',
|
|
224
234
|
headers: {
|
|
225
235
|
'Content-Type': 'application/json',
|
|
226
|
-
...(state.sessionToken ? { [config.anonymousTokenHeader]: state.sessionToken } : {}),
|
|
227
236
|
},
|
|
228
237
|
body: JSON.stringify({
|
|
229
238
|
text: text,
|
|
230
239
|
role: role,
|
|
231
240
|
}),
|
|
232
|
-
});
|
|
241
|
+
}));
|
|
233
242
|
} else {
|
|
234
243
|
// Direct ElevenLabs API call
|
|
235
244
|
const voiceId = role === 'assistant' ? config.ttsVoices.assistant : config.ttsVoices.user;
|
|
@@ -308,19 +317,15 @@
|
|
|
308
317
|
// If using proxy, notify backend of voice change
|
|
309
318
|
if (config.ttsProxyUrl) {
|
|
310
319
|
try {
|
|
311
|
-
|
|
312
|
-
const headers = {
|
|
313
|
-
'Content-Type': 'application/json',
|
|
314
|
-
};
|
|
315
|
-
if (token) {
|
|
316
|
-
headers[config.anonymousTokenHeader] = token;
|
|
317
|
-
}
|
|
320
|
+
await getOrCreateSession();
|
|
318
321
|
|
|
319
|
-
await fetch(`${config.backendUrl}${config.apiPaths.ttsSetVoice}`, {
|
|
322
|
+
await fetch(`${config.backendUrl}${config.apiPaths.ttsSetVoice}`, getFetchOptions({
|
|
320
323
|
method: 'POST',
|
|
321
|
-
headers
|
|
324
|
+
headers: {
|
|
325
|
+
'Content-Type': 'application/json',
|
|
326
|
+
},
|
|
322
327
|
body: JSON.stringify({ role, voice_id: voiceId }),
|
|
323
|
-
});
|
|
328
|
+
}));
|
|
324
329
|
} catch (err) {
|
|
325
330
|
console.error('[ChatWidget] Failed to set voice on backend:', err);
|
|
326
331
|
}
|
|
@@ -335,15 +340,9 @@
|
|
|
335
340
|
|
|
336
341
|
if (config.ttsProxyUrl) {
|
|
337
342
|
// Fetch voices from Django backend
|
|
338
|
-
|
|
339
|
-
const headers = {};
|
|
340
|
-
if (token) {
|
|
341
|
-
headers[config.anonymousTokenHeader] = token;
|
|
342
|
-
}
|
|
343
|
+
await getOrCreateSession();
|
|
343
344
|
|
|
344
|
-
const response = await fetch(`${config.backendUrl}${config.apiPaths.ttsVoices}`,
|
|
345
|
-
headers,
|
|
346
|
-
});
|
|
345
|
+
const response = await fetch(`${config.backendUrl}${config.apiPaths.ttsVoices}`, getFetchOptions());
|
|
347
346
|
|
|
348
347
|
if (response.ok) {
|
|
349
348
|
const data = await response.json();
|
|
@@ -370,34 +369,162 @@
|
|
|
370
369
|
}
|
|
371
370
|
}
|
|
372
371
|
|
|
372
|
+
// ============================================================================
|
|
373
|
+
// Authentication
|
|
374
|
+
// ============================================================================
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Determine the effective auth strategy based on config
|
|
378
|
+
*/
|
|
379
|
+
function getAuthStrategy() {
|
|
380
|
+
if (config.authStrategy) {
|
|
381
|
+
return config.authStrategy;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Auto-detect strategy based on config
|
|
385
|
+
if (config.authToken) {
|
|
386
|
+
return 'token'; // Default to token auth if token provided
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Check for legacy anonymous session config
|
|
390
|
+
if (config.apiPaths.anonymousSession || config.anonymousSessionEndpoint) {
|
|
391
|
+
return 'anonymous';
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return 'none';
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Get auth headers based on current strategy
|
|
399
|
+
*/
|
|
400
|
+
function getAuthHeaders() {
|
|
401
|
+
const strategy = getAuthStrategy();
|
|
402
|
+
const headers = {};
|
|
403
|
+
|
|
404
|
+
switch (strategy) {
|
|
405
|
+
case 'token': {
|
|
406
|
+
const token = config.authToken || state.authToken;
|
|
407
|
+
if (token) {
|
|
408
|
+
const headerName = config.authHeader || 'Authorization';
|
|
409
|
+
const prefix = config.authTokenPrefix !== undefined ? config.authTokenPrefix : 'Token';
|
|
410
|
+
headers[headerName] = prefix ? `${prefix} ${token}` : token;
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
case 'jwt': {
|
|
416
|
+
const token = config.authToken || state.authToken;
|
|
417
|
+
if (token) {
|
|
418
|
+
const headerName = config.authHeader || 'Authorization';
|
|
419
|
+
const prefix = config.authTokenPrefix !== undefined ? config.authTokenPrefix : 'Bearer';
|
|
420
|
+
headers[headerName] = prefix ? `${prefix} ${token}` : token;
|
|
421
|
+
}
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
case 'anonymous': {
|
|
426
|
+
const token = state.authToken || state.sessionToken; // Support legacy sessionToken
|
|
427
|
+
if (token) {
|
|
428
|
+
const headerName = config.authHeader || config.anonymousTokenHeader || 'X-Anonymous-Token';
|
|
429
|
+
headers[headerName] = token;
|
|
430
|
+
}
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
case 'session':
|
|
435
|
+
// Session auth uses cookies, no headers needed
|
|
436
|
+
break;
|
|
437
|
+
|
|
438
|
+
case 'none':
|
|
439
|
+
// No auth
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return headers;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Get fetch options including auth credentials
|
|
448
|
+
*/
|
|
449
|
+
function getFetchOptions(options = {}) {
|
|
450
|
+
const strategy = getAuthStrategy();
|
|
451
|
+
const fetchOptions = { ...options };
|
|
452
|
+
|
|
453
|
+
// Add auth headers
|
|
454
|
+
fetchOptions.headers = {
|
|
455
|
+
...fetchOptions.headers,
|
|
456
|
+
...getAuthHeaders(),
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// For session auth, include credentials
|
|
460
|
+
if (strategy === 'session') {
|
|
461
|
+
fetchOptions.credentials = 'include';
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return fetchOptions;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Handle auth errors (401, 403)
|
|
469
|
+
*/
|
|
470
|
+
function handleAuthError(error, response) {
|
|
471
|
+
if (config.onAuthError && typeof config.onAuthError === 'function') {
|
|
472
|
+
const authError = new Error(error.message || 'Authentication failed');
|
|
473
|
+
authError.status = response?.status;
|
|
474
|
+
authError.response = response;
|
|
475
|
+
config.onAuthError(authError);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
373
479
|
// ============================================================================
|
|
374
480
|
// Session Management
|
|
375
481
|
// ============================================================================
|
|
376
482
|
|
|
377
483
|
async function getOrCreateSession() {
|
|
484
|
+
const strategy = getAuthStrategy();
|
|
485
|
+
|
|
486
|
+
// For non-anonymous strategies, return the configured token
|
|
487
|
+
if (strategy !== 'anonymous') {
|
|
488
|
+
return config.authToken || state.authToken;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Anonymous strategy: get or create anonymous token
|
|
492
|
+
if (state.authToken) {
|
|
493
|
+
return state.authToken;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Support legacy sessionToken
|
|
378
497
|
if (state.sessionToken) {
|
|
379
|
-
|
|
498
|
+
state.authToken = state.sessionToken;
|
|
499
|
+
return state.authToken;
|
|
380
500
|
}
|
|
381
501
|
|
|
382
502
|
// Try to restore from storage
|
|
383
|
-
const
|
|
503
|
+
const storageKey = config.anonymousTokenKey || config.sessionTokenKey;
|
|
504
|
+
const stored = getStoredValue(storageKey);
|
|
384
505
|
if (stored) {
|
|
385
|
-
state.
|
|
506
|
+
state.authToken = stored;
|
|
507
|
+
state.sessionToken = stored; // Keep legacy field in sync
|
|
386
508
|
return stored;
|
|
387
509
|
}
|
|
388
510
|
|
|
389
511
|
// Create new anonymous session
|
|
390
512
|
try {
|
|
391
|
-
const
|
|
513
|
+
const endpoint = config.anonymousSessionEndpoint || config.apiPaths.anonymousSession;
|
|
514
|
+
const response = await fetch(`${config.backendUrl}${endpoint}`, {
|
|
392
515
|
method: 'POST',
|
|
393
516
|
headers: { 'Content-Type': 'application/json' },
|
|
394
517
|
});
|
|
395
518
|
|
|
396
519
|
if (response.ok) {
|
|
397
520
|
const data = await response.json();
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
521
|
+
const token = data.token;
|
|
522
|
+
state.authToken = token;
|
|
523
|
+
state.sessionToken = token; // Keep legacy field in sync
|
|
524
|
+
setStoredValue(storageKey, token);
|
|
525
|
+
return token;
|
|
526
|
+
} else if (response.status === 401 || response.status === 403) {
|
|
527
|
+
handleAuthError(new Error('Failed to create anonymous session'), response);
|
|
401
528
|
}
|
|
402
529
|
} catch (e) {
|
|
403
530
|
console.warn('[ChatWidget] Failed to create session:', e);
|
|
@@ -428,31 +555,35 @@
|
|
|
428
555
|
render();
|
|
429
556
|
|
|
430
557
|
try {
|
|
558
|
+
// Get auth token (if using anonymous strategy)
|
|
431
559
|
const token = await getOrCreateSession();
|
|
432
|
-
const headers = { 'Content-Type': 'application/json' };
|
|
433
|
-
if (token) {
|
|
434
|
-
headers[config.anonymousTokenHeader] = token;
|
|
435
|
-
}
|
|
436
560
|
|
|
437
561
|
// Restore conversation ID from storage if not set
|
|
438
562
|
if (!state.conversationId) {
|
|
439
563
|
state.conversationId = getStoredValue(config.conversationIdKey);
|
|
440
564
|
}
|
|
441
565
|
|
|
442
|
-
const response = await fetch(`${config.backendUrl}${config.apiPaths.runs}`, {
|
|
566
|
+
const response = await fetch(`${config.backendUrl}${config.apiPaths.runs}`, getFetchOptions({
|
|
443
567
|
method: 'POST',
|
|
444
|
-
headers,
|
|
568
|
+
headers: { 'Content-Type': 'application/json' },
|
|
445
569
|
body: JSON.stringify({
|
|
446
570
|
agentKey: config.agentKey,
|
|
447
571
|
conversationId: state.conversationId,
|
|
448
572
|
messages: [{ role: 'user', content: content.trim() }],
|
|
449
573
|
metadata: { journey_type: state.journeyType },
|
|
450
574
|
}),
|
|
451
|
-
});
|
|
575
|
+
}));
|
|
452
576
|
|
|
453
577
|
if (!response.ok) {
|
|
454
578
|
const errorData = await response.json().catch(() => ({}));
|
|
455
|
-
|
|
579
|
+
const error = new Error(errorData.error || `HTTP ${response.status}`);
|
|
580
|
+
|
|
581
|
+
// Handle auth errors
|
|
582
|
+
if (response.status === 401 || response.status === 403) {
|
|
583
|
+
handleAuthError(error, response);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
throw error;
|
|
456
587
|
}
|
|
457
588
|
|
|
458
589
|
const run = await response.json();
|
|
@@ -1148,6 +1279,11 @@
|
|
|
1148
1279
|
};
|
|
1149
1280
|
state.journeyType = config.defaultJourneyType;
|
|
1150
1281
|
|
|
1282
|
+
// Initialize auth token from config
|
|
1283
|
+
if (config.authToken) {
|
|
1284
|
+
state.authToken = config.authToken;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1151
1287
|
// Restore conversation ID
|
|
1152
1288
|
state.conversationId = getStoredValue(config.conversationIdKey);
|
|
1153
1289
|
|
|
@@ -1193,6 +1329,42 @@
|
|
|
1193
1329
|
sendMessage(message);
|
|
1194
1330
|
}
|
|
1195
1331
|
|
|
1332
|
+
/**
|
|
1333
|
+
* Update authentication configuration
|
|
1334
|
+
* @param {Object} authConfig - { strategy?: string, token?: string }
|
|
1335
|
+
*/
|
|
1336
|
+
function setAuth(authConfig = {}) {
|
|
1337
|
+
if (authConfig.strategy) {
|
|
1338
|
+
config.authStrategy = authConfig.strategy;
|
|
1339
|
+
}
|
|
1340
|
+
if (authConfig.token !== undefined) {
|
|
1341
|
+
config.authToken = authConfig.token;
|
|
1342
|
+
state.authToken = authConfig.token;
|
|
1343
|
+
|
|
1344
|
+
// For anonymous strategy, also persist to storage
|
|
1345
|
+
if (getAuthStrategy() === 'anonymous' && authConfig.token) {
|
|
1346
|
+
const storageKey = config.anonymousTokenKey || config.sessionTokenKey;
|
|
1347
|
+
setStoredValue(storageKey, authConfig.token);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
console.log('[ChatWidget] Auth updated:', { strategy: getAuthStrategy(), hasToken: !!state.authToken });
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
/**
|
|
1354
|
+
* Clear authentication
|
|
1355
|
+
*/
|
|
1356
|
+
function clearAuth() {
|
|
1357
|
+
config.authToken = null;
|
|
1358
|
+
state.authToken = null;
|
|
1359
|
+
state.sessionToken = null;
|
|
1360
|
+
|
|
1361
|
+
// Clear from storage
|
|
1362
|
+
const storageKey = config.anonymousTokenKey || config.sessionTokenKey;
|
|
1363
|
+
setStoredValue(storageKey, null);
|
|
1364
|
+
|
|
1365
|
+
console.log('[ChatWidget] Auth cleared');
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1196
1368
|
// Export public API
|
|
1197
1369
|
global.ChatWidget = {
|
|
1198
1370
|
init,
|
|
@@ -1209,6 +1381,8 @@
|
|
|
1209
1381
|
toggleTTS,
|
|
1210
1382
|
stopSpeech,
|
|
1211
1383
|
setVoice,
|
|
1384
|
+
setAuth,
|
|
1385
|
+
clearAuth,
|
|
1212
1386
|
getState: () => ({ ...state }),
|
|
1213
1387
|
getConfig: () => ({ ...config }),
|
|
1214
1388
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makemore/agent-frontend",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "A standalone, zero-dependency chat widget for AI agents. Embed conversational AI into any website with a single script tag.",
|
|
5
5
|
"main": "dist/chat-widget.js",
|
|
6
6
|
"files": [
|