@bootdesk/js-web-adapter-core 0.1.0 → 0.3.4

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/index.d.ts CHANGED
@@ -1,6 +1,54 @@
1
1
  import Pusher from 'pusher-js';
2
2
  import Echo from 'laravel-echo';
3
3
 
4
+ interface HttpClientConfig {
5
+ apiUrl: string;
6
+ headers?: Record<string, string>;
7
+ timeout?: number;
8
+ verifyToken?: string;
9
+ }
10
+ interface ChatResponse {
11
+ id: string;
12
+ role: "assistant" | "user";
13
+ text: string;
14
+ attachments?: Array<{
15
+ type: string;
16
+ url: string;
17
+ name?: string;
18
+ mime_type?: string;
19
+ size?: number;
20
+ }>;
21
+ events?: Array<Record<string, unknown>>;
22
+ }
23
+ declare class HttpClient {
24
+ private config;
25
+ constructor(config: HttpClientConfig);
26
+ get(url: string, signal?: AbortSignal): Promise<unknown>;
27
+ post(url: string, body: unknown, signal?: AbortSignal): Promise<unknown>;
28
+ delete(url: string, signal?: AbortSignal): Promise<unknown>;
29
+ sendMessage(messages: Array<{
30
+ id: string;
31
+ role: string;
32
+ text: string;
33
+ attachments?: Array<{
34
+ url: string;
35
+ name?: string;
36
+ mime_type?: string;
37
+ size?: number;
38
+ }>;
39
+ }>, endpoint?: string, conversationId?: string): Promise<ChatResponse>;
40
+ sendAction(actionId: string, value: string, messageId: string, conversationId: string, endpoint?: string): Promise<Record<string, unknown>>;
41
+ editMessage(messageId: string, newText: string, endpointTemplate?: string): Promise<void>;
42
+ deleteMessage(messageId: string, endpointTemplate?: string): Promise<void>;
43
+ addReaction(messageId: string, emoji: string, endpointTemplate?: string): Promise<void>;
44
+ removeReaction(messageId: string, emoji: string, endpointTemplate?: string): Promise<void>;
45
+ postFormData(url: string, formData: FormData, signal?: AbortSignal): Promise<unknown>;
46
+ setHeader(name: string, value: string): void;
47
+ removeHeader(name: string): void;
48
+ private resolve;
49
+ private expandTemplate;
50
+ }
51
+
4
52
  declare abstract class ChatEvent {
5
53
  readonly type: string;
6
54
  readonly threadId: string;
@@ -13,7 +61,7 @@ declare class UnknownEvent extends ChatEvent {
13
61
  constructor(type: string, threadId: string, data: Record<string, unknown>, timestamp: number);
14
62
  }
15
63
 
16
- declare class TypingStartedEvent extends ChatEvent {
64
+ declare class DMRequestedEvent extends ChatEvent {
17
65
  readonly userId: string;
18
66
  constructor(threadId: string, userId: string, timestamp?: number);
19
67
  }
@@ -25,6 +73,11 @@ declare class StreamingChunkEvent extends ChatEvent {
25
73
  constructor(threadId: string, messageId: string, chunk: string, isFinal: boolean, timestamp?: number);
26
74
  }
27
75
 
76
+ declare class TypingStartedEvent extends ChatEvent {
77
+ readonly userId: string;
78
+ constructor(threadId: string, userId: string, timestamp?: number);
79
+ }
80
+
28
81
  interface BaseCard {
29
82
  type: string;
30
83
  }
@@ -143,77 +196,6 @@ interface Attachment {
143
196
  mimeType?: string;
144
197
  }
145
198
 
146
- declare class MessagePostedEvent extends ChatEvent {
147
- readonly messageId: string;
148
- readonly text: string;
149
- readonly author: User;
150
- readonly card?: Card;
151
- readonly attachments?: Array<{
152
- type: string;
153
- url?: string;
154
- name?: string;
155
- mimeType?: string;
156
- size?: number | null;
157
- }>;
158
- constructor(threadId: string, messageId: string, text: string, author: User, card?: Card, attachments?: Array<{
159
- type: string;
160
- url?: string;
161
- name?: string;
162
- mimeType?: string;
163
- size?: number | null;
164
- }>, timestamp?: number);
165
- }
166
-
167
- interface HttpClientConfig {
168
- apiUrl: string;
169
- headers?: Record<string, string>;
170
- timeout?: number;
171
- verifyToken?: string;
172
- }
173
- interface ChatResponse {
174
- id: string;
175
- role: "assistant" | "user";
176
- text: string;
177
- attachments?: Array<{
178
- type: string;
179
- url: string;
180
- name?: string;
181
- mime_type?: string;
182
- size?: number;
183
- }>;
184
- events?: Array<Record<string, unknown>>;
185
- }
186
- declare class HttpClient {
187
- private config;
188
- constructor(config: HttpClientConfig);
189
- get(url: string, signal?: AbortSignal): Promise<unknown>;
190
- post(url: string, body: unknown, signal?: AbortSignal): Promise<unknown>;
191
- delete(url: string, signal?: AbortSignal): Promise<unknown>;
192
- sendMessage(messages: Array<{
193
- id: string;
194
- role: string;
195
- text: string;
196
- attachments?: Array<{
197
- url: string;
198
- name?: string;
199
- mime_type?: string;
200
- size?: number;
201
- }>;
202
- }>, endpoint?: string, conversationId?: string): Promise<ChatResponse>;
203
- sendAction(actionId: string, value: string, messageId: string, conversationId: string, endpoint?: string): Promise<Record<string, unknown>>;
204
- editMessage(messageId: string, newText: string, endpointTemplate?: string): Promise<void>;
205
- deleteMessage(messageId: string, endpointTemplate?: string): Promise<void>;
206
- addReaction(messageId: string, emoji: string, endpointTemplate?: string): Promise<void>;
207
- removeReaction(messageId: string, emoji: string, endpointTemplate?: string): Promise<void>;
208
- private resolve;
209
- private expandTemplate;
210
- }
211
-
212
- declare class DMRequestedEvent extends ChatEvent {
213
- readonly userId: string;
214
- constructor(threadId: string, userId: string, timestamp?: number);
215
- }
216
-
217
199
  declare class ReactionRemovedEvent extends ChatEvent {
218
200
  readonly messageId: string;
219
201
  readonly emoji: string;
@@ -240,6 +222,27 @@ declare class MessageEditedEvent extends ChatEvent {
240
222
  constructor(threadId: string, messageId: string, newText: string, card?: Card, timestamp?: number);
241
223
  }
242
224
 
225
+ declare class MessagePostedEvent extends ChatEvent {
226
+ readonly messageId: string;
227
+ readonly text: string;
228
+ readonly author: User;
229
+ readonly card?: Card;
230
+ readonly attachments?: Array<{
231
+ type: string;
232
+ url?: string;
233
+ name?: string;
234
+ mimeType?: string;
235
+ size?: number | null;
236
+ }>;
237
+ constructor(threadId: string, messageId: string, text: string, author: User, card?: Card, attachments?: Array<{
238
+ type: string;
239
+ url?: string;
240
+ name?: string;
241
+ mimeType?: string;
242
+ size?: number | null;
243
+ }>, timestamp?: number);
244
+ }
245
+
243
246
  interface EventHandlers {
244
247
  onMessagePosted?: (event: MessagePostedEvent) => void;
245
248
  onMessageEdited?: (event: MessageEditedEvent) => void;
@@ -263,6 +266,13 @@ interface BroadcastClient {
263
266
  isConnected(): boolean;
264
267
  }
265
268
 
269
+ interface ReconfigureConfig {
270
+ userId?: string;
271
+ userName?: string;
272
+ verifyToken?: string;
273
+ conversationId?: string;
274
+ headers?: Record<string, string>;
275
+ }
266
276
  interface WebChatClientConfig {
267
277
  apiUrl: string;
268
278
  userId: string;
@@ -285,6 +295,12 @@ interface WebChatClientConfig {
285
295
  reactions?: boolean;
286
296
  };
287
297
  }
298
+ interface AttachmentInput {
299
+ url: string;
300
+ name?: string;
301
+ mimeType?: string;
302
+ size?: number;
303
+ }
288
304
  interface LoadMessagesOptions {
289
305
  limit?: number;
290
306
  before?: number;
@@ -310,16 +326,22 @@ declare class WebChatClient {
310
326
  private subscribers;
311
327
  private unsubscribeUserChannel?;
312
328
  constructor(config: WebChatClientConfig);
329
+ reconfigure(config: ReconfigureConfig): void;
330
+ setLocaleHeader(locale: string): void;
313
331
  connect(): Promise<void>;
314
332
  disconnect(): void;
315
333
  loadMessages(options?: LoadMessagesOptions, signal?: AbortSignal): Promise<LoadMessagesResult>;
316
- sendMessage(text: string, attachments?: any[]): Promise<void>;
334
+ sendMessage(text: string, attachments?: AttachmentInput[]): Promise<void>;
317
335
  sendAction(messageId: string, actionId: string, value: string): Promise<void>;
318
336
  editMessage(messageId: string, newText: string): Promise<void>;
319
337
  deleteMessage(messageId: string): Promise<void>;
320
338
  addReaction(messageId: string, emoji: string): Promise<void>;
321
339
  removeReaction(messageId: string, emoji: string): Promise<void>;
322
340
  onMessagePosted(handler: (event: MessagePostedEvent) => void): Unsubscribe;
341
+ onMessageEdited(handler: (event: MessageEditedEvent) => void): Unsubscribe;
342
+ onMessageDeleted(handler: (event: MessageDeletedEvent) => void): Unsubscribe;
343
+ onReactionAdded(handler: (event: ReactionAddedEvent) => void): Unsubscribe;
344
+ onReactionRemoved(handler: (event: ReactionRemovedEvent) => void): Unsubscribe;
323
345
  onStreamingChunk(handler: (event: StreamingChunkEvent) => void): Unsubscribe;
324
346
  onTypingStarted(handler: (event: TypingStartedEvent) => void): Unsubscribe;
325
347
  getConversationId(): string;
@@ -329,7 +351,7 @@ declare class WebChatClient {
329
351
  getFeatures(): NonNullable<WebChatClientConfig["features"]>;
330
352
  getEndpoints(): NonNullable<WebChatClientConfig["endpoints"]>;
331
353
  getHttpClient(): HttpClient;
332
- addEventListener(eventType: string, handler: (event: any) => void): Unsubscribe;
354
+ addEventListener<T = unknown>(eventType: string, handler: (event: T) => void): Unsubscribe;
333
355
  private handleMessagePosted;
334
356
  private handleMessageEdited;
335
357
  private handleMessageDeleted;
@@ -392,6 +414,7 @@ interface PushConfig {
392
414
  getVapidPublicKey: () => Promise<string>;
393
415
  serviceWorkerUrl?: string;
394
416
  serviceWorkerScope?: string;
417
+ serviceWorkerType?: "classic" | "module";
395
418
  onSubscribe: (subscription: PushSubscriptionJSON) => Promise<void>;
396
419
  onUnsubscribe: (subscription: PushSubscriptionJSON) => Promise<void>;
397
420
  notificationOptions?: {
@@ -430,4 +453,4 @@ declare class PushManager {
430
453
 
431
454
  declare function createPushSubscriptionHandlers(httpClient: HttpClient, userId: string): Pick<PushConfig, "onSubscribe" | "onUnsubscribe">;
432
455
 
433
- export { type Attachment, type BaseCard, type BroadcastClient, type Card, type CardAction, type CardElement, type CardField, type CardSection, type ChannelTypeConfig, ChatEvent, type ChatResponse, type CustomCard, DMRequestedEvent, type DividerElement, type EventHandlers, type FileCard, HttpClient, type HttpClientConfig, type ImageCard, type ImageElement, LaravelEchoBroadcastClient, type LinkButtonElement, type LinkElement, type LoadMessagesOptions, type LoadMessagesResult, type Message, type MessageContent, MessageDeletedEvent, MessageEditedEvent, MessagePostedEvent, type PHPCard, type PushConfig, type PushEventData, PushManager, type PushSubscriptionStatus, PusherBroadcastClient, type PusherConfig, type Reaction, ReactionAddedEvent, ReactionRemovedEvent, StreamingChunkEvent, type TableElement, type TextElement, TypingStartedEvent, UnknownEvent, type Unsubscribe, type User, WebChatClient, type WebChatClientConfig, createPushSubscriptionHandlers, generateConversationId, generateId, parseChatEvent };
456
+ export { type Attachment, type BaseCard, type BroadcastClient, type Card, type CardAction, type CardElement, type CardField, type CardSection, type ChannelTypeConfig, ChatEvent, type ChatResponse, type CustomCard, DMRequestedEvent, type DividerElement, type EventHandlers, type FileCard, HttpClient, type HttpClientConfig, type ImageCard, type ImageElement, LaravelEchoBroadcastClient, type LinkButtonElement, type LinkElement, type LoadMessagesOptions, type LoadMessagesResult, type Message, type MessageContent, MessageDeletedEvent, MessageEditedEvent, MessagePostedEvent, type PHPCard, type PushConfig, type PushEventData, PushManager, type PushSubscriptionStatus, PusherBroadcastClient, type PusherConfig, type Reaction, ReactionAddedEvent, ReactionRemovedEvent, type ReconfigureConfig, StreamingChunkEvent, type TableElement, type TextElement, TypingStartedEvent, UnknownEvent, type Unsubscribe, type User, WebChatClient, type WebChatClientConfig, createPushSubscriptionHandlers, generateConversationId, generateId, parseChatEvent };
package/dist/index.js CHANGED
@@ -85,6 +85,30 @@ var HttpClient = class {
85
85
  const url = this.expandTemplate(endpointTemplate, { id: messageId, emoji });
86
86
  await this.delete(url);
87
87
  }
88
+ async postFormData(url, formData, signal) {
89
+ const controller = new AbortController();
90
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
91
+ try {
92
+ const fullUrl = this.resolve(url);
93
+ const combined = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;
94
+ const response = await fetch(fullUrl, {
95
+ method: "POST",
96
+ headers: this.config.headers,
97
+ signal: combined,
98
+ body: formData
99
+ });
100
+ if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
101
+ return response.json();
102
+ } finally {
103
+ clearTimeout(timeoutId);
104
+ }
105
+ }
106
+ setHeader(name, value) {
107
+ this.config.headers[name] = value;
108
+ }
109
+ removeHeader(name) {
110
+ delete this.config.headers[name];
111
+ }
88
112
  resolve(url) {
89
113
  return /^https?:\/\//.test(url) ? url : `${this.config.apiUrl}${url}`;
90
114
  }
@@ -285,6 +309,31 @@ var WebChatClient = class {
285
309
  this.conversationId = config.conversationId ?? generateConversationId();
286
310
  this.currentUserId = config.userId;
287
311
  }
312
+ reconfigure(config) {
313
+ if (config.userId) {
314
+ this.currentUserId = config.userId;
315
+ this.httpClient.setHeader("X-User-Id", config.userId);
316
+ }
317
+ if (config.userName) {
318
+ this.config = { ...this.config, userName: config.userName };
319
+ this.httpClient.setHeader("X-User-Name", config.userName);
320
+ }
321
+ if (config.verifyToken) {
322
+ this.config = { ...this.config, verifyToken: config.verifyToken };
323
+ this.httpClient.setHeader("X-Verify-Token", config.verifyToken);
324
+ }
325
+ if (config.conversationId) {
326
+ this.conversationId = config.conversationId;
327
+ }
328
+ if (config.headers) {
329
+ Object.entries(config.headers).forEach(([key, value]) => {
330
+ this.httpClient.setHeader(key, value);
331
+ });
332
+ }
333
+ }
334
+ setLocaleHeader(locale) {
335
+ this.httpClient.setHeader("X-Locale", locale);
336
+ }
288
337
  async connect() {
289
338
  if (this.broadcastClient) {
290
339
  this.broadcastClient.connect();
@@ -333,10 +382,14 @@ var WebChatClient = class {
333
382
  `${endpoint}?${params.toString()}`,
334
383
  signal
335
384
  );
336
- const messages = (response.messages || []).map((msg) => ({
385
+ const rawMessages = response.messages ?? [];
386
+ const messages = rawMessages.map((msg) => ({
337
387
  id: msg.id,
338
388
  threadId,
339
- content: { text: msg.text, cards: msg.card ? [msg.card] : void 0 },
389
+ content: {
390
+ text: msg.text,
391
+ cards: msg.card ? [msg.card] : void 0
392
+ },
340
393
  author: {
341
394
  id: msg.author.id,
342
395
  name: msg.author.name,
@@ -375,7 +428,7 @@ var WebChatClient = class {
375
428
  timestamp: Date.now(),
376
429
  attachments: attachments.length > 0 ? attachments.map((a, i) => ({
377
430
  id: `att-${messageId}-${i}`,
378
- name: a.name || "",
431
+ name: a.name ?? "",
379
432
  url: a.url,
380
433
  size: a.size,
381
434
  mimeType: a.mimeType
@@ -390,7 +443,7 @@ var WebChatClient = class {
390
443
  id: messageId,
391
444
  role: "user",
392
445
  text,
393
- attachments: attachments?.map((a) => ({
446
+ attachments: attachments.map((a) => ({
394
447
  url: a.url,
395
448
  name: a.name,
396
449
  mime_type: a.mimeType,
@@ -409,15 +462,15 @@ var WebChatClient = class {
409
462
  }
410
463
  if (response.text && !response.events?.some((e) => e.type === "message.posted")) {
411
464
  const assistantMessage = {
412
- id: response.id || generateId(),
465
+ id: response.id ?? generateId(),
413
466
  threadId: this.getThreadId(),
414
467
  content: { text: response.text },
415
468
  author: { id: "assistant", name: "Assistant", isBot: true },
416
469
  timestamp: Date.now(),
417
470
  attachments: response.attachments?.map((a, i) => ({
418
- id: `att-${response.id || "msg"}-${i}`,
419
- name: a.name || "",
420
- url: a.url || "",
471
+ id: `att-${response.id ?? "msg"}-${i}`,
472
+ name: a.name ?? "",
473
+ url: a.url ?? "",
421
474
  type: a.type,
422
475
  mimeType: a.mime_type,
423
476
  size: a.size
@@ -474,11 +527,23 @@ var WebChatClient = class {
474
527
  onMessagePosted(handler) {
475
528
  return this.addEventListener("message.posted", handler);
476
529
  }
530
+ onMessageEdited(handler) {
531
+ return this.addEventListener("message:edited", handler);
532
+ }
533
+ onMessageDeleted(handler) {
534
+ return this.addEventListener("message:deleted", handler);
535
+ }
536
+ onReactionAdded(handler) {
537
+ return this.addEventListener("reaction:added", handler);
538
+ }
539
+ onReactionRemoved(handler) {
540
+ return this.addEventListener("reaction:removed", handler);
541
+ }
477
542
  onStreamingChunk(handler) {
478
- return this.addEventListener("streaming.chunk", handler);
543
+ return this.addEventListener("streaming:chunk", handler);
479
544
  }
480
545
  onTypingStarted(handler) {
481
- return this.addEventListener("typing.started", handler);
546
+ return this.addEventListener("typing:started", handler);
482
547
  }
483
548
  getConversationId() {
484
549
  return this.conversationId;
@@ -523,11 +588,11 @@ var WebChatClient = class {
523
588
  timestamp: event.timestamp,
524
589
  attachments: event.attachments?.map((a) => ({
525
590
  id: `att-${event.messageId}-${Math.random().toString(36).slice(2, 8)}`,
526
- name: a.name || "",
527
- url: a.url || "",
591
+ name: a.name ?? "",
592
+ url: a.url ?? "",
528
593
  type: a.type,
529
594
  mimeType: a.mimeType,
530
- size: a.size
595
+ size: a.size ?? void 0
531
596
  }))
532
597
  };
533
598
  this.messages.push(message);
@@ -538,17 +603,14 @@ var WebChatClient = class {
538
603
  const message = this.messages.find((m) => m.id === event.messageId);
539
604
  if (message?.content) {
540
605
  message.content.text = event.newText;
541
- this.notifySubscribers("message:edited", {
542
- messageId: event.messageId,
543
- newText: event.newText
544
- });
606
+ this.notifySubscribers("message:edited", event);
545
607
  }
546
608
  }
547
609
  handleMessageDeleted(event) {
548
610
  const index = this.messages.findIndex((m) => m.id === event.messageId);
549
611
  if (index !== -1) {
550
612
  this.messages.splice(index, 1);
551
- this.notifySubscribers("message:deleted", { messageId: event.messageId });
613
+ this.notifySubscribers("message:deleted", event);
552
614
  }
553
615
  }
554
616
  handleReactionAdded(event) {
@@ -562,7 +624,7 @@ var WebChatClient = class {
562
624
  } else {
563
625
  message.reactions.push({ emoji: event.emoji, count: 1, users: [event.user.id] });
564
626
  }
565
- this.notifySubscribers("reaction:added", { messageId: event.messageId, emoji: event.emoji });
627
+ this.notifySubscribers("reaction:added", event);
566
628
  }
567
629
  handleReactionRemoved(event) {
568
630
  const message = this.messages.find((m) => m.id === event.messageId);
@@ -574,13 +636,13 @@ var WebChatClient = class {
574
636
  reaction.users = reaction.users.filter((id) => id !== event.user.id);
575
637
  if (reaction.count === 0) message.reactions.splice(index, 1);
576
638
  }
577
- this.notifySubscribers("reaction:removed", { messageId: event.messageId, emoji: event.emoji });
639
+ this.notifySubscribers("reaction:removed", event);
578
640
  }
579
641
  handleStreamingChunk(event) {
580
642
  const { messageId, chunk, isFinal } = event;
581
643
  if (!this.streamingMessages.has(messageId)) {
582
644
  this.streamingMessages.set(messageId, { messageId, accumulatedText: "", isComplete: false });
583
- this.notifySubscribers("streaming:started", { messageId });
645
+ this.notifySubscribers("streaming:started", event);
584
646
  }
585
647
  const state = this.streamingMessages.get(messageId);
586
648
  state.accumulatedText += chunk;
@@ -600,24 +662,18 @@ var WebChatClient = class {
600
662
  this.streamingMessages.delete(messageId);
601
663
  this.notifySubscribers("streaming:complete", { messageId, text: state.accumulatedText });
602
664
  } else {
603
- this.notifySubscribers("streaming:chunk", {
604
- messageId,
605
- chunk,
606
- fullText: state.accumulatedText
607
- });
665
+ this.notifySubscribers("streaming:chunk", event);
608
666
  }
609
- this.notifySubscribers("streaming.chunk", event);
610
667
  }
611
668
  handleTypingStarted(event) {
612
669
  if (this.pendingTyping) clearTimeout(this.pendingTyping);
613
- this.notifySubscribers("typing:started", { userId: event.userId });
670
+ this.notifySubscribers("typing:started", event);
614
671
  this.pendingTyping = setTimeout(() => {
615
672
  this.notifySubscribers("typing:stopped", { userId: event.userId });
616
673
  }, 3e3);
617
- this.notifySubscribers("typing.started", event);
618
674
  }
619
675
  handleDMRequested(event) {
620
- this.notifySubscribers("dm.requested", { userId: event.userId, threadId: event.threadId });
676
+ this.notifySubscribers("dm.requested", event);
621
677
  }
622
678
  notifySubscribers(eventType, data) {
623
679
  this.subscribers.get(eventType)?.forEach((handler) => handler(data));
@@ -895,9 +951,19 @@ var PushManager = class _PushManager {
895
951
  try {
896
952
  this.registration = await navigator.serviceWorker.register(
897
953
  this.config.serviceWorkerUrl || "/chat-service-worker.js",
898
- { scope: this.config.serviceWorkerScope || "/" }
954
+ {
955
+ scope: this.config.serviceWorkerScope || "/",
956
+ type: this.config.serviceWorkerType
957
+ }
899
958
  );
900
959
  await navigator.serviceWorker.ready;
960
+ navigator.serviceWorker.addEventListener("message", (event) => {
961
+ const msg = event.data;
962
+ if (msg?.type === "chat-widget:push-data") {
963
+ const pushData = msg.data;
964
+ this.messageListeners.forEach((listener) => listener(pushData));
965
+ }
966
+ });
901
967
  const subscription = await this.registration.pushManager.getSubscription();
902
968
  this.setStatus(subscription ? "subscribed" : "default");
903
969
  } catch {