@chatwidgetai/chat-widget 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +3 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/hooks/useChat.d.ts.map +1 -1
- package/dist/index.esm.js +99 -23
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +99 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/ai-chat-widget.umd.js +0 -65776
- package/dist/ai-chat-widget.umd.js.map +0 -1
package/dist/api/client.d.ts
CHANGED
|
@@ -19,7 +19,10 @@ export declare class ApiError extends Error {
|
|
|
19
19
|
}
|
|
20
20
|
export declare class WidgetApiClient {
|
|
21
21
|
private config;
|
|
22
|
+
private detectedTimeZone;
|
|
22
23
|
constructor(config: ApiClientConfig);
|
|
24
|
+
private static detectTimeZone;
|
|
25
|
+
private getTimeZone;
|
|
23
26
|
/**
|
|
24
27
|
* Get widget configuration
|
|
25
28
|
*/
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;CAOpG;AAwDD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;CAOpG;AAwDD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,gBAAgB,CAAS;gBAErB,MAAM,EAAE,eAAe;IAKnC,OAAO,CAAC,MAAM,CAAC,cAAc;IAS7B,OAAO,CAAC,WAAW;IAInB;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAoBlC,uBAAuB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAA;KAAE,CAAC;IA6BhH;;OAEG;IACG,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAwB7G;;;OAGG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAyB9G;;OAEG;IACG,gBAAgB,CACpB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,GAAG,CAAC;IA4Cf;;OAEG;IACG,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,UAAU,GAAG,UAAU,GAChC,OAAO,CAAC,IAAI,CAAC;IA4BhB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAsBzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/hooks/useChat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAa,MAAM,UAAU,CAAC;AAKxE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzF;AAkED,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/hooks/useChat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAa,MAAM,UAAU,CAAC;AAKxE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzF;AAkED,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAiW9D"}
|
package/dist/index.esm.js
CHANGED
|
@@ -67,6 +67,19 @@ async function buildApiError(response, defaultMessage) {
|
|
|
67
67
|
class WidgetApiClient {
|
|
68
68
|
constructor(config) {
|
|
69
69
|
this.config = config;
|
|
70
|
+
this.detectedTimeZone = WidgetApiClient.detectTimeZone();
|
|
71
|
+
}
|
|
72
|
+
static detectTimeZone() {
|
|
73
|
+
try {
|
|
74
|
+
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
75
|
+
return tz && tz.trim().length > 0 ? tz : "UTC";
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return "UTC";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
getTimeZone() {
|
|
82
|
+
return this.detectedTimeZone;
|
|
70
83
|
}
|
|
71
84
|
/**
|
|
72
85
|
* Get widget configuration
|
|
@@ -87,7 +100,15 @@ class WidgetApiClient {
|
|
|
87
100
|
}
|
|
88
101
|
async getOrCreateConversation(conversationId) {
|
|
89
102
|
const baseUrl = `${this.config.apiUrl}/api/widget/${this.config.widgetId}/conversation`;
|
|
90
|
-
const
|
|
103
|
+
const params = new URLSearchParams();
|
|
104
|
+
if (conversationId) {
|
|
105
|
+
params.set('conversationId', conversationId);
|
|
106
|
+
}
|
|
107
|
+
const timeZone = this.getTimeZone();
|
|
108
|
+
if (timeZone) {
|
|
109
|
+
params.set('timeZone', timeZone);
|
|
110
|
+
}
|
|
111
|
+
const query = params.toString() ? `?${params.toString()}` : '';
|
|
91
112
|
const response = await fetch(`${baseUrl}${query}`, {
|
|
92
113
|
method: 'GET',
|
|
93
114
|
headers: {
|
|
@@ -134,6 +155,7 @@ class WidgetApiClient {
|
|
|
134
155
|
conversationId: conversationId,
|
|
135
156
|
message,
|
|
136
157
|
fileIds,
|
|
158
|
+
timeZone: this.getTimeZone(),
|
|
137
159
|
}),
|
|
138
160
|
});
|
|
139
161
|
if (!response.ok) {
|
|
@@ -156,6 +178,7 @@ class WidgetApiClient {
|
|
|
156
178
|
conversationId: conversationId,
|
|
157
179
|
message,
|
|
158
180
|
fileIds,
|
|
181
|
+
timeZone: this.getTimeZone(),
|
|
159
182
|
}),
|
|
160
183
|
});
|
|
161
184
|
if (!response.ok) {
|
|
@@ -232,11 +255,6 @@ class WidgetApiClient {
|
|
|
232
255
|
/**
|
|
233
256
|
* Generate a unique session ID
|
|
234
257
|
*/
|
|
235
|
-
function generateSessionId() {
|
|
236
|
-
const timestamp = Date.now().toString(36);
|
|
237
|
-
const randomStr = Math.random().toString(36).substring(2, 15);
|
|
238
|
-
return `session_${timestamp}_${randomStr}`;
|
|
239
|
-
}
|
|
240
258
|
/**
|
|
241
259
|
* Generate a unique message ID
|
|
242
260
|
*/
|
|
@@ -291,6 +309,18 @@ function loadConversation(widgetId) {
|
|
|
291
309
|
return null;
|
|
292
310
|
}
|
|
293
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Clear conversation from localStorage
|
|
314
|
+
*/
|
|
315
|
+
function clearConversation(widgetId) {
|
|
316
|
+
try {
|
|
317
|
+
const key = getStorageKey(widgetId);
|
|
318
|
+
localStorage.removeItem(key);
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
console.error('Failed to clear conversation:', error);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
294
324
|
/**
|
|
295
325
|
* Check if localStorage is available
|
|
296
326
|
*/
|
|
@@ -383,29 +413,43 @@ function useChat(options) {
|
|
|
383
413
|
config: null,
|
|
384
414
|
});
|
|
385
415
|
const apiClient = useRef(new WidgetApiClient({ widgetId, apiKey, apiUrl }));
|
|
386
|
-
// Load configuration and conversation
|
|
416
|
+
// Load configuration on mount and hydrate with existing conversation if available
|
|
387
417
|
useEffect(() => {
|
|
418
|
+
let isMounted = true;
|
|
388
419
|
const initialize = async () => {
|
|
389
420
|
try {
|
|
390
|
-
// Load config
|
|
391
421
|
const config = await apiClient.current.getConfig();
|
|
392
|
-
// Get or create conversation
|
|
393
422
|
const persistConversation = config.behavior.persistConversation ?? true;
|
|
394
|
-
let conversationId;
|
|
423
|
+
let conversationId = '';
|
|
424
|
+
let messages = [];
|
|
395
425
|
if (persistConversation && isStorageAvailable()) {
|
|
396
426
|
const stored = loadConversation(widgetId);
|
|
397
|
-
|
|
427
|
+
const storedId = stored?.conversationId || stored?.sessionId;
|
|
428
|
+
if (storedId) {
|
|
429
|
+
try {
|
|
430
|
+
const conversation = await apiClient.current.getOrCreateConversation(storedId);
|
|
431
|
+
conversationId = conversation.id;
|
|
432
|
+
messages = conversation.messages;
|
|
433
|
+
}
|
|
434
|
+
catch (conversationError) {
|
|
435
|
+
console.warn('Failed to load existing conversation:', conversationError);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (!isMounted) {
|
|
440
|
+
return;
|
|
398
441
|
}
|
|
399
|
-
// Get conversation from backend
|
|
400
|
-
const conversation = await apiClient.current.getOrCreateConversation(conversationId);
|
|
401
442
|
setState(prev => ({
|
|
402
443
|
...prev,
|
|
403
444
|
config,
|
|
404
|
-
conversationId
|
|
405
|
-
messages
|
|
445
|
+
conversationId,
|
|
446
|
+
messages,
|
|
406
447
|
}));
|
|
407
448
|
}
|
|
408
449
|
catch (error) {
|
|
450
|
+
if (!isMounted) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
409
453
|
const errorInfo = deriveErrorInfo(error);
|
|
410
454
|
const err = error instanceof Error ? error : new Error(errorInfo.message);
|
|
411
455
|
setState(prev => ({ ...prev, error: errorInfo.message }));
|
|
@@ -413,11 +457,17 @@ function useChat(options) {
|
|
|
413
457
|
}
|
|
414
458
|
};
|
|
415
459
|
initialize();
|
|
460
|
+
return () => {
|
|
461
|
+
isMounted = false;
|
|
462
|
+
};
|
|
416
463
|
}, [widgetId, apiKey, apiUrl, onError]);
|
|
417
464
|
// Save conversation when messages change
|
|
418
465
|
useEffect(() => {
|
|
419
466
|
const persistConversation = state.config?.behavior.persistConversation ?? true;
|
|
420
|
-
if (persistConversation &&
|
|
467
|
+
if (persistConversation &&
|
|
468
|
+
isStorageAvailable() &&
|
|
469
|
+
state.messages.length > 0 &&
|
|
470
|
+
state.conversationId) {
|
|
421
471
|
saveConversation(widgetId, state.conversationId, state.messages);
|
|
422
472
|
}
|
|
423
473
|
}, [widgetId, state.messages, state.conversationId, state.config?.behavior.persistConversation]);
|
|
@@ -425,13 +475,15 @@ function useChat(options) {
|
|
|
425
475
|
* Send a message
|
|
426
476
|
*/
|
|
427
477
|
const sendMessage = useCallback(async (content, files) => {
|
|
428
|
-
|
|
478
|
+
const trimmedContent = content.trim();
|
|
479
|
+
const hasFiles = !!files && files.length > 0;
|
|
480
|
+
if (!trimmedContent && !hasFiles)
|
|
429
481
|
return;
|
|
430
482
|
const userMessage = {
|
|
431
483
|
id: generateMessageId(),
|
|
432
484
|
message: {
|
|
433
485
|
type: 'human',
|
|
434
|
-
content:
|
|
486
|
+
content: trimmedContent,
|
|
435
487
|
},
|
|
436
488
|
timestamp: new Date().toISOString(),
|
|
437
489
|
sources: [],
|
|
@@ -446,13 +498,37 @@ function useChat(options) {
|
|
|
446
498
|
}));
|
|
447
499
|
onMessage?.(userMessage);
|
|
448
500
|
try {
|
|
501
|
+
let conversationId = state.conversationId;
|
|
502
|
+
if (!conversationId) {
|
|
503
|
+
const conversation = await apiClient.current.getOrCreateConversation();
|
|
504
|
+
conversationId = conversation.id;
|
|
505
|
+
setState(prev => {
|
|
506
|
+
const serverMessages = conversation.messages ?? [];
|
|
507
|
+
if (serverMessages.length === 0) {
|
|
508
|
+
return {
|
|
509
|
+
...prev,
|
|
510
|
+
conversationId,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
const serverIds = new Set(serverMessages.map(msg => msg.id));
|
|
514
|
+
const mergedMessages = [
|
|
515
|
+
...serverMessages,
|
|
516
|
+
...prev.messages.filter(msg => !serverIds.has(msg.id)),
|
|
517
|
+
];
|
|
518
|
+
return {
|
|
519
|
+
...prev,
|
|
520
|
+
conversationId,
|
|
521
|
+
messages: mergedMessages,
|
|
522
|
+
};
|
|
523
|
+
});
|
|
524
|
+
}
|
|
449
525
|
// Upload files if provided
|
|
450
526
|
let fileIds;
|
|
451
527
|
if (files && files.length > 0) {
|
|
452
528
|
fileIds = [];
|
|
453
529
|
for (const file of files) {
|
|
454
530
|
try {
|
|
455
|
-
const uploadedFile = await apiClient.current.uploadFile(
|
|
531
|
+
const uploadedFile = await apiClient.current.uploadFile(conversationId, file);
|
|
456
532
|
fileIds.push(uploadedFile.id);
|
|
457
533
|
}
|
|
458
534
|
catch (uploadError) {
|
|
@@ -466,11 +542,11 @@ function useChat(options) {
|
|
|
466
542
|
let response;
|
|
467
543
|
if (useAgent) {
|
|
468
544
|
// Use agent endpoint - returns ConversationMessage[]
|
|
469
|
-
response = await apiClient.current.sendAgentMessage(
|
|
545
|
+
response = await apiClient.current.sendAgentMessage(conversationId, trimmedContent, fileIds);
|
|
470
546
|
}
|
|
471
547
|
else {
|
|
472
548
|
// Use standard chat endpoint
|
|
473
|
-
response = await apiClient.current.sendMessage(
|
|
549
|
+
response = await apiClient.current.sendMessage(conversationId, trimmedContent, fileIds);
|
|
474
550
|
}
|
|
475
551
|
// Both endpoints now return ConversationMessage[] array (FULL conversation)
|
|
476
552
|
if (Array.isArray(response)) {
|
|
@@ -582,12 +658,12 @@ function useChat(options) {
|
|
|
582
658
|
setState(prev => ({
|
|
583
659
|
...prev,
|
|
584
660
|
messages: [],
|
|
585
|
-
conversationId:
|
|
661
|
+
conversationId: '',
|
|
586
662
|
error: null,
|
|
587
663
|
}));
|
|
588
664
|
const persistConversation = state.config?.behavior.persistConversation ?? true;
|
|
589
665
|
if (persistConversation && isStorageAvailable()) {
|
|
590
|
-
|
|
666
|
+
clearConversation(widgetId);
|
|
591
667
|
}
|
|
592
668
|
}, [widgetId, state.config?.behavior.persistConversation]);
|
|
593
669
|
/**
|