@developer.notchatbot/webchat 1.7.1 → 2.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 +2 -0
- package/dist/components/ChatBot.d.ts +3 -4
- package/dist/components/ContactCapture.d.ts +7 -0
- package/dist/components/MessageActions.d.ts +8 -0
- package/dist/components/MessageAlertSettings.d.ts +5 -0
- package/dist/components/MessageSelectionActions.d.ts +4 -0
- package/dist/components/ReplyQuote.d.ts +8 -0
- package/dist/components/UnreadMessagePreview.d.ts +15 -0
- package/dist/components/embedchat/EmbedChat.d.ts +6 -2
- package/dist/config/endpoints.d.ts +0 -5
- package/dist/hooks/useMessageAlerts.d.ts +11 -0
- package/dist/hooks/useMessageGesture.d.ts +14 -0
- package/dist/hooks/useTeamAvailability.d.ts +2 -0
- package/dist/hooks/useVisitorChat.d.ts +48 -0
- package/dist/types.d.ts +86 -14
- package/dist/utils/cart-model.d.ts +23 -0
- package/dist/utils/contact-link.d.ts +2 -0
- package/dist/utils/convex.d.ts +2 -3
- package/dist/utils/markdown.d.ts +2 -0
- package/dist/utils/message-alerts.d.ts +15 -0
- package/dist/utils/message-colors.d.ts +3 -0
- package/dist/utils/message-id.d.ts +2 -0
- package/dist/utils/phone.d.ts +16 -0
- package/dist/utils/shopify-attribution.d.ts +12 -0
- package/dist/utils/storefront-cart.d.ts +6 -0
- package/dist/utils/storefront-identity.d.ts +23 -0
- package/dist/utils/tiendanube-attribution.d.ts +8 -0
- package/dist/utils/transcript.d.ts +23 -0
- package/dist/utils/visitor-presence.d.ts +30 -0
- package/dist/utils/visitor-session.d.ts +31 -0
- package/dist/utils/vtex-attribution.d.ts +13 -0
- package/dist/webchat-bundle.min.js +8707 -5192
- package/dist/webchat-bundle.min.umd.cjs +81 -55
- package/package.json +8 -4
- package/dist/components/ConversationRating.d.ts +0 -7
- package/dist/utils/notchatbot-cookie.d.ts +0 -32
- package/dist/utils/survey.d.ts +0 -30
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 🔷 WebChat - Embedded Chat
|
|
2
2
|
|
|
3
|
+
Webchat 2.0.0 uses origin-bound visitor credentials and requires the matching NotChatbot backend and Cloudflare presence service. See [the rollout guide](../next/apps/next/docs/webchat-v2-rollout.md) before upgrading an existing install.
|
|
4
|
+
|
|
3
5
|
## 📦 Quick Start
|
|
4
6
|
|
|
5
7
|
### 1. Add the widget to your website
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { default as React } from 'react';
|
|
2
1
|
import { ChatBotProps } from '../types';
|
|
3
|
-
declare const ChatBot:
|
|
4
|
-
exposeControl?: (api:
|
|
5
|
-
}
|
|
2
|
+
declare const ChatBot: ({ config, exposeControl }: ChatBotProps & {
|
|
3
|
+
exposeControl?: (api: Record<string, unknown>) => void;
|
|
4
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
6
5
|
export default ChatBot;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
uid: string;
|
|
3
|
+
conversationId?: string;
|
|
4
|
+
}
|
|
5
|
+
/** Save intentional contact edits after a pause; passive identity hints never authorize follow-up. */
|
|
6
|
+
export declare function ContactCapture({ uid, conversationId }: Props): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export default function MessageActions({ anchor, selectionMode, reaction, onReact, onReply, onClose }: {
|
|
2
|
+
selectionMode?: boolean;
|
|
3
|
+
anchor: HTMLElement;
|
|
4
|
+
reaction?: string | null;
|
|
5
|
+
onReact?: (emoji: string | null) => void;
|
|
6
|
+
onReply?: () => void;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
}): import('react').ReactPortal;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MessageAlertControls } from '../hooks/useMessageAlerts';
|
|
2
|
+
/** Customer-controlled alert preferences. Opening this menu never requests browser permission. */
|
|
3
|
+
export default function MessageAlertSettings({ controls }: {
|
|
4
|
+
controls: MessageAlertControls;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Message } from '../types';
|
|
2
|
+
export declare const quoteName: (message: Message) => string;
|
|
3
|
+
export declare const quoteText: (message: Pick<Message, "type" | "text">) => string;
|
|
4
|
+
export default function ReplyQuote({ message, onClick, textColor }: {
|
|
5
|
+
message: Message;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
textColor?: string;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Message } from '../types';
|
|
2
|
+
interface Props {
|
|
3
|
+
messages: Message[];
|
|
4
|
+
isStaffTyping?: boolean;
|
|
5
|
+
staffTypingAuthor?: Message["author"];
|
|
6
|
+
title: string;
|
|
7
|
+
avatar?: string;
|
|
8
|
+
position: 'bottom-left' | 'bottom-right';
|
|
9
|
+
marginBottom: number;
|
|
10
|
+
marginSide: number;
|
|
11
|
+
onOpen: () => void;
|
|
12
|
+
}
|
|
13
|
+
/** Real unread replies in transcript order. Previewing or dismissing never sends viewed receipts. */
|
|
14
|
+
export default function UnreadMessagePreview({ messages, isStaffTyping, staffTypingAuthor, title, avatar, position, marginBottom, marginSide, onOpen }: Props): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
+
export {};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { default as React } from 'react';
|
|
2
1
|
import { EmbedChatProps } from '../../types';
|
|
3
|
-
declare const EmbedChat:
|
|
2
|
+
declare const EmbedChat: ({ config, exposeControl }: EmbedChatProps & {
|
|
3
|
+
exposeControl?: (api: {
|
|
4
|
+
restart: () => void;
|
|
5
|
+
identify: (hint: import('../../utils/storefront-identity').CustomerHint) => void;
|
|
6
|
+
}) => void;
|
|
7
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
4
8
|
export default EmbedChat;
|
|
@@ -2,7 +2,6 @@ export interface EndpointConfig {
|
|
|
2
2
|
baseUrl: string;
|
|
3
3
|
chatEndpoint: string;
|
|
4
4
|
uploadEndpoint: string;
|
|
5
|
-
rateEndpoint: string;
|
|
6
5
|
realtimeUrl: string;
|
|
7
6
|
}
|
|
8
7
|
/**
|
|
@@ -30,10 +29,6 @@ export declare function getChatEndpoint(): string;
|
|
|
30
29
|
* Obtiene el endpoint de upload
|
|
31
30
|
*/
|
|
32
31
|
export declare function getUploadEndpoint(): string;
|
|
33
|
-
/**
|
|
34
|
-
* Obtiene el endpoint de rating
|
|
35
|
-
*/
|
|
36
|
-
export declare function getRateEndpoint(): string;
|
|
37
32
|
/**
|
|
38
33
|
* Obtiene la URL base según el ambiente
|
|
39
34
|
*/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Message } from '../types';
|
|
2
|
+
export interface MessageAlertControls {
|
|
3
|
+
soundEnabled: boolean;
|
|
4
|
+
toggleSound: () => void;
|
|
5
|
+
notificationsEnabled: boolean;
|
|
6
|
+
notificationsSupported: boolean;
|
|
7
|
+
permission: NotificationPermission | 'unsupported';
|
|
8
|
+
toggleNotifications: () => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/** Alerts use the existing unread feed; old history, typing and duplicate snapshots remain silent. */
|
|
11
|
+
export declare function useMessageAlerts(uid: string, conversationId: string | undefined, messages: Message[], unreadCount: number, isOpen: boolean, title: string, onOpen: () => void): MessageAlertControls;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export declare function useMessageGesture(enabled: boolean, onReply: () => void, onHold: (touch: boolean) => void): {
|
|
3
|
+
offset: number;
|
|
4
|
+
gestures: {
|
|
5
|
+
onPointerDown: (event: React.PointerEvent<HTMLDivElement>) => void;
|
|
6
|
+
onPointerMove: (event: React.PointerEvent) => void;
|
|
7
|
+
onPointerUp: (event: React.PointerEvent) => void;
|
|
8
|
+
onPointerCancel: () => void;
|
|
9
|
+
onLostPointerCapture: () => void;
|
|
10
|
+
onClickCapture: (event: React.MouseEvent) => void;
|
|
11
|
+
onKeyDown: (event: React.KeyboardEvent) => void;
|
|
12
|
+
onContextMenu: (event: React.MouseEvent) => void;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { VisitorSession } from '../utils/visitor-session';
|
|
2
|
+
import { Transcript } from '../utils/transcript';
|
|
3
|
+
import { FileWithBlobUrl, Message, WebChatConfig } from '../types';
|
|
4
|
+
import { CustomerHint } from '../utils/storefront-identity';
|
|
5
|
+
interface PendingSend {
|
|
6
|
+
createdAt?: string;
|
|
7
|
+
requestId: string;
|
|
8
|
+
conversationId: string;
|
|
9
|
+
chatbotUid: string;
|
|
10
|
+
newMessages: Array<{
|
|
11
|
+
id: string;
|
|
12
|
+
role: 'user';
|
|
13
|
+
content: string;
|
|
14
|
+
type: string;
|
|
15
|
+
metaContent?: string;
|
|
16
|
+
replyToId?: string;
|
|
17
|
+
}>;
|
|
18
|
+
currentUrl: string;
|
|
19
|
+
}
|
|
20
|
+
/** Owns the visitor lifecycle shared by floating and embedded chat surfaces. */
|
|
21
|
+
export declare function useVisitorChat(config: WebChatConfig, isOpen: boolean): {
|
|
22
|
+
react: (messageId: string, emoji: string | null) => Promise<boolean>;
|
|
23
|
+
teamOnline: boolean;
|
|
24
|
+
staffTypingAuthor: {
|
|
25
|
+
name: string;
|
|
26
|
+
avatarUrl?: string;
|
|
27
|
+
} | undefined;
|
|
28
|
+
staffTyping: boolean;
|
|
29
|
+
unreadMessages: Message[];
|
|
30
|
+
unreadMessage: Message;
|
|
31
|
+
session: VisitorSession | null;
|
|
32
|
+
draftRevision: number;
|
|
33
|
+
messages: Message[];
|
|
34
|
+
sending: boolean;
|
|
35
|
+
error: string;
|
|
36
|
+
unread: boolean;
|
|
37
|
+
unreadCount: number;
|
|
38
|
+
state: Partial<Transcript>;
|
|
39
|
+
connected: boolean;
|
|
40
|
+
pending: PendingSend;
|
|
41
|
+
send: (text: string, files?: FileWithBlobUrl[], replyTo?: Message) => false | Promise<boolean | undefined>;
|
|
42
|
+
restart: (forgetContact?: boolean) => void;
|
|
43
|
+
viewed: (ids: string[]) => void;
|
|
44
|
+
typing: (active: boolean) => void | undefined;
|
|
45
|
+
identify: (hint: CustomerHint) => void;
|
|
46
|
+
retry: () => void;
|
|
47
|
+
};
|
|
48
|
+
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export interface WebChatPositionConfig {
|
|
|
5
5
|
showPopup?: boolean;
|
|
6
6
|
}
|
|
7
7
|
export interface WebChatConfig {
|
|
8
|
+
active?: boolean;
|
|
9
|
+
quickReplies?: string[];
|
|
10
|
+
contactCapture?: boolean;
|
|
11
|
+
identityEndpoint?: string;
|
|
8
12
|
elementId: string;
|
|
9
13
|
title?: string;
|
|
10
14
|
placeholder?: string;
|
|
@@ -58,6 +62,11 @@ export interface EmbedChatInputConfig {
|
|
|
58
62
|
iconColor?: string;
|
|
59
63
|
}
|
|
60
64
|
export interface EmbedChatConfig {
|
|
65
|
+
apiBaseUrl?: string;
|
|
66
|
+
realtimeUrl?: string;
|
|
67
|
+
contactCapture?: boolean;
|
|
68
|
+
quickReplies?: string[];
|
|
69
|
+
identityEndpoint?: string;
|
|
61
70
|
elementId: string;
|
|
62
71
|
title?: string;
|
|
63
72
|
placeholder?: string;
|
|
@@ -95,14 +104,28 @@ export interface EmbedChatProps {
|
|
|
95
104
|
config: EmbedChatConfig;
|
|
96
105
|
}
|
|
97
106
|
export interface EmbedChatWindowProps {
|
|
107
|
+
onReact?: (messageId: string, emoji: string | null) => Promise<boolean>;
|
|
108
|
+
alertSettings?: React.ReactNode;
|
|
109
|
+
onTyping?: (active: boolean) => void;
|
|
110
|
+
contactMessage?: React.ReactNode;
|
|
111
|
+
children?: React.ReactNode;
|
|
112
|
+
onViewed?: (ids: string[]) => void;
|
|
113
|
+
sending?: boolean;
|
|
114
|
+
draftRevision?: number;
|
|
98
115
|
config: EmbedChatConfig;
|
|
99
116
|
messages: Message[];
|
|
100
|
-
onSendMessage: (message: string, files?: FileWithBlobUrl[]) => void
|
|
117
|
+
onSendMessage: (message: string, files?: FileWithBlobUrl[], replyTo?: Message) => void | boolean | Promise<void | boolean>;
|
|
101
118
|
isLoading?: boolean;
|
|
102
119
|
isAiTyping?: boolean;
|
|
120
|
+
teamOnline?: boolean;
|
|
121
|
+
isStaffTyping?: boolean;
|
|
122
|
+
staffTypingAuthor?: Message["author"];
|
|
103
123
|
chatbotActivated?: boolean;
|
|
104
124
|
}
|
|
105
125
|
export interface EmbedChatHeaderProps {
|
|
126
|
+
selectionActions?: React.ReactNode;
|
|
127
|
+
teamOnline?: boolean;
|
|
128
|
+
alertSettings?: React.ReactNode;
|
|
106
129
|
title: string;
|
|
107
130
|
primaryColor?: string;
|
|
108
131
|
avatar?: string;
|
|
@@ -113,12 +136,29 @@ export interface EmbedChatFooterProps {
|
|
|
113
136
|
footerColor?: string;
|
|
114
137
|
}
|
|
115
138
|
export interface EmbedChatInstance {
|
|
139
|
+
logout?: () => void;
|
|
140
|
+
setCart: (cart: Omit<import('./utils/cart-model').WebchatCart, 'itemCount' | 'truncated'> | null) => void;
|
|
141
|
+
identify?: (hint: import('./utils/storefront-identity').CustomerHint) => void;
|
|
116
142
|
destroy: () => void;
|
|
117
143
|
updateConfig?: (newConfig: Partial<EmbedChatConfig>) => void;
|
|
118
144
|
injectCSS?: (css: string) => void;
|
|
119
145
|
removeCustomCSS?: () => void;
|
|
120
146
|
}
|
|
121
147
|
export interface Message {
|
|
148
|
+
reaction?: string;
|
|
149
|
+
replyToId?: string;
|
|
150
|
+
replyTo?: {
|
|
151
|
+
id: string;
|
|
152
|
+
content: string;
|
|
153
|
+
role: string;
|
|
154
|
+
type: string;
|
|
155
|
+
};
|
|
156
|
+
author?: {
|
|
157
|
+
name: string;
|
|
158
|
+
avatarUrl?: string;
|
|
159
|
+
};
|
|
160
|
+
contactPromptAfter?: boolean;
|
|
161
|
+
delivery?: 'sending' | 'accepted' | 'failed';
|
|
122
162
|
id: string;
|
|
123
163
|
text: string;
|
|
124
164
|
sender: 'user' | 'bot';
|
|
@@ -138,37 +178,44 @@ export interface ChatButtonProps {
|
|
|
138
178
|
marginBottom?: number;
|
|
139
179
|
marginSide?: number;
|
|
140
180
|
hasNewMessages?: boolean;
|
|
181
|
+
unreadCount?: number;
|
|
141
182
|
isMobile?: boolean;
|
|
142
183
|
isMenuOpen?: boolean;
|
|
143
184
|
hasWhatsAppMenu?: boolean;
|
|
144
185
|
}
|
|
145
186
|
export interface ChatWindowProps {
|
|
187
|
+
onReact?: (messageId: string, emoji: string | null) => Promise<boolean>;
|
|
188
|
+
alertSettings?: React.ReactNode;
|
|
189
|
+
onTyping?: (active: boolean) => void;
|
|
190
|
+
draftRevision?: number;
|
|
191
|
+
onViewed?: (ids: string[]) => void;
|
|
192
|
+
sendError?: string;
|
|
193
|
+
onRetry?: () => void;
|
|
194
|
+
sending?: boolean;
|
|
195
|
+
contactCaptured?: boolean;
|
|
196
|
+
handoffRequested?: boolean;
|
|
197
|
+
engaged?: boolean;
|
|
146
198
|
isOpen: boolean;
|
|
147
199
|
onClose: () => void;
|
|
148
200
|
config: WebChatConfig;
|
|
149
201
|
messages: Message[];
|
|
150
|
-
onSendMessage: (message: string, files?: FileWithBlobUrl[]) => void
|
|
202
|
+
onSendMessage: (message: string, files?: FileWithBlobUrl[], replyTo?: Message) => void | boolean | Promise<void | boolean>;
|
|
151
203
|
isLoading?: boolean;
|
|
152
204
|
isAiTyping?: boolean;
|
|
205
|
+
teamOnline?: boolean;
|
|
206
|
+
isStaffTyping?: boolean;
|
|
207
|
+
staffTypingAuthor?: Message["author"];
|
|
153
208
|
position?: 'bottom-right' | 'bottom-left';
|
|
154
209
|
marginBottom?: number;
|
|
155
210
|
marginSide?: number;
|
|
156
211
|
isMobile?: boolean;
|
|
157
212
|
chatbotActivated?: boolean;
|
|
158
|
-
isRated?: boolean;
|
|
159
|
-
onRatingChange?: (isRated: boolean) => void;
|
|
160
213
|
conversationId?: string;
|
|
161
|
-
/** Configurable auto-survey threshold from the backend; undefined = legacy default (2). */
|
|
162
|
-
surveyAfterUserMessages?: number;
|
|
163
|
-
/** Timestamp of the last manual survey request from Livechat; undefined = never requested. */
|
|
164
|
-
webchatSurveyRequestedAt?: number;
|
|
165
|
-
}
|
|
166
|
-
/** Survey-related conversation state forwarded from the Convex realtime subscription. */
|
|
167
|
-
export interface ConversationSurveyState {
|
|
168
|
-
surveyAfterUserMessages?: number;
|
|
169
|
-
webchatSurveyRequestedAt?: number;
|
|
170
214
|
}
|
|
171
215
|
export interface ChatHeaderProps {
|
|
216
|
+
selectionActions?: React.ReactNode;
|
|
217
|
+
teamOnline?: boolean;
|
|
218
|
+
alertSettings?: React.ReactNode;
|
|
172
219
|
title: string;
|
|
173
220
|
onClose: () => void;
|
|
174
221
|
primaryColor?: string;
|
|
@@ -178,21 +225,40 @@ export interface ChatHeaderProps {
|
|
|
178
225
|
closeButtonCustomIcon?: string;
|
|
179
226
|
}
|
|
180
227
|
export interface MessageListProps {
|
|
228
|
+
selectedMessageId?: string;
|
|
229
|
+
onSelectMessage?: (message: Message | undefined) => void;
|
|
230
|
+
onReact?: (messageId: string, emoji: string | null) => Promise<boolean>;
|
|
231
|
+
onReply?: (message: Message) => void;
|
|
232
|
+
contactMessage?: React.ReactNode;
|
|
233
|
+
onViewed?: (ids: string[]) => void;
|
|
181
234
|
messages: Message[];
|
|
182
235
|
isTyping: boolean;
|
|
236
|
+
teamOnline?: boolean;
|
|
237
|
+
isStaffTyping?: boolean;
|
|
238
|
+
staffTypingAuthor?: Message["author"];
|
|
183
239
|
avatar?: string;
|
|
184
240
|
textColor?: string;
|
|
185
241
|
bubbleUserColor?: string;
|
|
186
242
|
chatbotActivated?: boolean;
|
|
187
243
|
}
|
|
188
244
|
export interface MessageProps {
|
|
245
|
+
selectedMessageId?: string;
|
|
246
|
+
onSelectMessage?: (message: Message | undefined) => void;
|
|
247
|
+
onReact?: (messageId: string, emoji: string | null) => Promise<boolean>;
|
|
248
|
+
onReply?: (message: Message) => void;
|
|
249
|
+
referencedMessage?: Message;
|
|
250
|
+
onJump?: (id: string) => void;
|
|
189
251
|
message: Message;
|
|
190
252
|
avatar?: string;
|
|
191
253
|
textColor?: string;
|
|
192
254
|
bubbleUserColor?: string;
|
|
193
255
|
}
|
|
194
256
|
export interface MessageInputProps {
|
|
195
|
-
|
|
257
|
+
replyTo?: Message;
|
|
258
|
+
onCancelReply?: () => void;
|
|
259
|
+
onTyping?: (active: boolean) => void;
|
|
260
|
+
draftScope?: string;
|
|
261
|
+
onSendMessage: (message: string, files?: FileWithBlobUrl[], replyTo?: Message) => void | boolean | Promise<void | boolean>;
|
|
196
262
|
placeholder?: string;
|
|
197
263
|
primaryColor?: string;
|
|
198
264
|
disabled?: boolean;
|
|
@@ -201,6 +267,9 @@ export interface MessageInputProps {
|
|
|
201
267
|
}
|
|
202
268
|
export interface TypingIndicatorProps {
|
|
203
269
|
avatar?: string;
|
|
270
|
+
author?: Message["author"];
|
|
271
|
+
human?: boolean;
|
|
272
|
+
compact?: boolean;
|
|
204
273
|
}
|
|
205
274
|
export interface ChatBubblePopoverProps {
|
|
206
275
|
initialMessage?: string;
|
|
@@ -214,6 +283,9 @@ export interface ChatBubblePopoverProps {
|
|
|
214
283
|
onPopoverClick: () => void;
|
|
215
284
|
}
|
|
216
285
|
export interface WebChatInstance {
|
|
286
|
+
logout?: () => void;
|
|
287
|
+
setCart: (cart: Omit<import('./utils/cart-model').WebchatCart, 'itemCount' | 'truncated'> | null) => void;
|
|
288
|
+
identify?: (hint: import('./utils/storefront-identity').CustomerHint) => void;
|
|
217
289
|
root: any;
|
|
218
290
|
destroy: () => void;
|
|
219
291
|
getConversationId: () => string | null;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Cart amounts are integer minor currency units. Storefront hints never authorize orders or prices. */
|
|
2
|
+
export interface WebchatCartItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
quantity: number;
|
|
6
|
+
unitPrice: number;
|
|
7
|
+
variant?: string;
|
|
8
|
+
imageUrl?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface WebchatCart {
|
|
12
|
+
currency: string;
|
|
13
|
+
total: number;
|
|
14
|
+
itemCount: number;
|
|
15
|
+
items: WebchatCartItem[];
|
|
16
|
+
truncated: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface WebchatCartSnapshot {
|
|
19
|
+
cart: WebchatCart | null;
|
|
20
|
+
updatedAt: number;
|
|
21
|
+
}
|
|
22
|
+
/** Allowlist and bound storefront context before sending it to staff or edge storage. */
|
|
23
|
+
export declare function sanitizeWebchatCart(value: unknown, origin: string): WebchatCart | null;
|
package/dist/utils/convex.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConvexReactClient } from 'convex/react';
|
|
2
|
-
import {
|
|
2
|
+
import { Message } from '../types';
|
|
3
3
|
export interface ConvexConnectionData {
|
|
4
4
|
client: ConvexReactClient;
|
|
5
5
|
unsubscribe: (() => void) | null;
|
|
@@ -11,10 +11,9 @@ export interface ConvexConnectionData {
|
|
|
11
11
|
* @param conversationId Conversation ID
|
|
12
12
|
* @param onMessage Callback for new messages
|
|
13
13
|
* @param onChatbotToggle Callback for chatbot activation changes
|
|
14
|
-
* @param onSurveyStateChange Callback for survey state changes (threshold + manual trigger)
|
|
15
14
|
* @returns Promise that resolves to Convex connection data
|
|
16
15
|
*/
|
|
17
|
-
export declare const initializeConvexConnection: (realtimeEndpoint: string, _chatbotUid: string, conversationId: string, onMessage: (message: Message) => void, onChatbotToggle?: (chatbotActivated: boolean) => void
|
|
16
|
+
export declare const initializeConvexConnection: (realtimeEndpoint: string, _chatbotUid: string, conversationId: string, onMessage: (message: Message) => void, onChatbotToggle?: (chatbotActivated: boolean) => void) => Promise<ConvexConnectionData>;
|
|
18
17
|
/**
|
|
19
18
|
* Fetches initial conversation data with messages from Convex
|
|
20
19
|
* @param realtimeEndpoint Realtime service deployment URL
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Keep notification counters out of the page metadata sent to Livechat. */
|
|
2
|
+
export declare const getStorefrontTitle: () => string;
|
|
3
|
+
/** Preserve storefront title changes, including client-side navigation, while showing unread replies. */
|
|
4
|
+
export declare function createUnreadTitle(): {
|
|
5
|
+
update(next: number): void;
|
|
6
|
+
close(): void;
|
|
7
|
+
};
|
|
8
|
+
/** Share a bounded receipt ledger between storefront tabs; Web Locks prevent simultaneous alerts. */
|
|
9
|
+
export declare function claimMessageAlert(uid: string, conversationId: string, ids: string[]): Promise<any>;
|
|
10
|
+
/** Unlock audio only on customer interaction; unsupported/autoplay-blocked browsers remain silent. */
|
|
11
|
+
export declare function createMessageSound(): {
|
|
12
|
+
unlock: () => void;
|
|
13
|
+
play(): void;
|
|
14
|
+
close(): void;
|
|
15
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Store theme colors are opaque hex colors; keep a custom text color only when legible. */
|
|
2
|
+
export declare function messageTextColor(background: string, preferred?: string): string;
|
|
3
|
+
export declare function messageMetaColor(background: string, foreground: string): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getCountryCallingCode, CountryCode } from 'libphonenumber-js/min';
|
|
2
|
+
export { getCountryCallingCode, type CountryCode };
|
|
3
|
+
export declare const phoneCountries: CountryCode[];
|
|
4
|
+
export declare const isPhoneCountry: (value: unknown) => value is CountryCode;
|
|
5
|
+
export declare const countryFlag: (country: CountryCode) => string;
|
|
6
|
+
/** Browser hints are a convenience, not geolocation. No request or permission prompt is needed. */
|
|
7
|
+
export declare function suggestPhoneCountry(languages: readonly string[], timeZone: string): CountryCode;
|
|
8
|
+
/** Split pasted/saved international numbers without duplicating their country calling code. */
|
|
9
|
+
export declare function splitPhone(value: string, fallback: CountryCode): {
|
|
10
|
+
value: string;
|
|
11
|
+
country: CountryCode;
|
|
12
|
+
};
|
|
13
|
+
/** Normalize national input (including trunk prefixes) for the existing E.164 contact endpoint. */
|
|
14
|
+
export declare function normalizePhone(value: string, country: CountryCode): string | null;
|
|
15
|
+
export declare const countryName: (country: CountryCode) => string;
|
|
16
|
+
export declare const sortedPhoneCountries: CountryCode[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ShopifyAttributionReference {
|
|
2
|
+
conversationId: string;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
}
|
|
5
|
+
/** Cart API bridge. Only runs network work after engagement or for cleanup of our saved reference. */
|
|
6
|
+
export declare function observeShopifyAttribution(doc: Document, readReference: () => ShopifyAttributionReference | null, storage: {
|
|
7
|
+
read(): string | null;
|
|
8
|
+
write(value: string): void;
|
|
9
|
+
}, request?: typeof fetch): {
|
|
10
|
+
refresh: () => Promise<void>;
|
|
11
|
+
dispose: () => void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { WebchatCart } from './cart-model';
|
|
2
|
+
export type { WebchatCart } from './cart-model';
|
|
3
|
+
/** Commerce adapters call this on initial load and cart changes. No network until chat engagement. */
|
|
4
|
+
export declare function setStorefrontCart(uid: string, input: unknown): void;
|
|
5
|
+
export declare const getStorefrontCart: (uid: string) => WebchatCart | null | undefined;
|
|
6
|
+
export declare function subscribeStorefrontCart(uid: string, listener: () => void): () => void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { VisitorSession } from './visitor-session';
|
|
2
|
+
export interface CustomerHint {
|
|
3
|
+
platform?: 'tiendanube' | 'shopify' | 'vtex' | 'custom';
|
|
4
|
+
subject?: string;
|
|
5
|
+
email?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
phone?: string;
|
|
8
|
+
}
|
|
9
|
+
interface VerifiedIdentity extends CustomerHint {
|
|
10
|
+
verified: boolean;
|
|
11
|
+
expiresAt: number;
|
|
12
|
+
}
|
|
13
|
+
/** Hints only prefill the form; they do not authenticate or link customer records. */
|
|
14
|
+
export declare function saveCustomerHint(uid: string, hint: CustomerHint): void;
|
|
15
|
+
/** The configured same-origin merchant route must validate its own login before signing. */
|
|
16
|
+
export declare function refreshStorefrontIdentity(session: VisitorSession, endpoint: string): Promise<{
|
|
17
|
+
changed: boolean;
|
|
18
|
+
identity: null;
|
|
19
|
+
} | {
|
|
20
|
+
changed: boolean;
|
|
21
|
+
identity: VerifiedIdentity;
|
|
22
|
+
}>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface AttributionReference {
|
|
2
|
+
token: string;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
}
|
|
5
|
+
/** Attach only to same-origin Tiendanube purchase forms; unrelated forms remain untouched. */
|
|
6
|
+
export declare function attachTiendanubeAttribution(doc: Document, token: string): number;
|
|
7
|
+
/** Owns field lifecycle across cart rendering; never intercepts payment or blocks navigation. */
|
|
8
|
+
export declare function observeTiendanubeAttribution(doc: Document, reference: AttributionReference, storeId: string, readPlatform: () => unknown, onRetired?: () => void): () => void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { VisitorSession } from './visitor-session';
|
|
2
|
+
import { Message } from '../types';
|
|
3
|
+
export interface Transcript {
|
|
4
|
+
messages: Array<{
|
|
5
|
+
reaction?: string;
|
|
6
|
+
replyToId?: string;
|
|
7
|
+
replyTo?: Message["replyTo"];
|
|
8
|
+
id: string;
|
|
9
|
+
role: string;
|
|
10
|
+
content: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
type?: string;
|
|
13
|
+
metaContent?: string;
|
|
14
|
+
contactPromptAfter?: boolean;
|
|
15
|
+
author?: Message['author'];
|
|
16
|
+
}>;
|
|
17
|
+
chatbotActivated: boolean;
|
|
18
|
+
contactCaptured?: boolean;
|
|
19
|
+
handoffRequested?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare const transcriptMessages: (data: Transcript) => Message[];
|
|
22
|
+
/** One bounded subscription supplies both initial history and live replies, avoiding snapshot races. */
|
|
23
|
+
export declare function subscribeTranscript(session: VisitorSession, onData: (data: Transcript) => void, onError: () => void): () => void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { VisitorSession } from './visitor-session';
|
|
2
|
+
export interface EdgeReply {
|
|
3
|
+
id: string;
|
|
4
|
+
at: number;
|
|
5
|
+
receipt: 'available' | 'delivered' | 'viewed';
|
|
6
|
+
}
|
|
7
|
+
export interface EdgeState {
|
|
8
|
+
staffTyping?: {
|
|
9
|
+
name: string;
|
|
10
|
+
avatarUrl?: string;
|
|
11
|
+
} | null;
|
|
12
|
+
staffTypingUntil?: number;
|
|
13
|
+
typingUntil?: number;
|
|
14
|
+
page?: {
|
|
15
|
+
url: string;
|
|
16
|
+
title: string;
|
|
17
|
+
} | null;
|
|
18
|
+
type: 'state';
|
|
19
|
+
presence: string;
|
|
20
|
+
replies: EdgeReply[];
|
|
21
|
+
observedAt: number;
|
|
22
|
+
}
|
|
23
|
+
/** Reconnectable metadata channel. Transcript content is only loaded while the chat is open. */
|
|
24
|
+
export declare function connectVisitorPresence(session: VisitorSession, onState: (state: EdgeState) => void, onConnection: (connected: boolean) => void, onTeamAvailability?: (online: boolean) => void): {
|
|
25
|
+
setTyping: (active: boolean) => void;
|
|
26
|
+
setOpen(value: boolean): void;
|
|
27
|
+
delivered(ids: string[]): void;
|
|
28
|
+
viewed(ids: string[]): void;
|
|
29
|
+
close(): void;
|
|
30
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface VisitorSession {
|
|
2
|
+
chatbotUid: string;
|
|
3
|
+
conversationId: string;
|
|
4
|
+
visitorId: string;
|
|
5
|
+
token: string;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
presenceUrl?: string | null;
|
|
8
|
+
started?: boolean;
|
|
9
|
+
contactConversationId?: string;
|
|
10
|
+
contactSession?: {
|
|
11
|
+
token: string;
|
|
12
|
+
expiresAt: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare const visitorStorageKey: (uid: string, item: string) => string;
|
|
16
|
+
/** Tenant/site-scoped storage with a stable in-memory fallback for blocked browser storage. */
|
|
17
|
+
export declare function readVisitorData(uid: string, item: string): string | null;
|
|
18
|
+
export declare function writeVisitorData(uid: string, item: string, value: string | null): void;
|
|
19
|
+
export declare function getVisitorSession(uid: string): VisitorSession | null;
|
|
20
|
+
export declare function getContactSession(uid: string): {
|
|
21
|
+
token: string;
|
|
22
|
+
expiresAt: number;
|
|
23
|
+
} | null;
|
|
24
|
+
export declare function saveVisitorSession(session: VisitorSession): void;
|
|
25
|
+
/** Called on first send/upload, never on page load or merely opening the launcher. */
|
|
26
|
+
export declare function ensureVisitorSession(uid: string): Promise<VisitorSession>;
|
|
27
|
+
export declare function resetVisitorSession(uid: string, forgetContact?: boolean): void;
|
|
28
|
+
export declare function visitorHeaders(session: VisitorSession): {
|
|
29
|
+
'Content-Type': string;
|
|
30
|
+
Authorization: string;
|
|
31
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface Reference {
|
|
2
|
+
conversationId: string;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
}
|
|
5
|
+
/** Uses the store's existing vtexjs checkout transport. Configure its shared queue at integration time. */
|
|
6
|
+
export declare function observeVtexAttribution(doc: Document, readReference: () => Reference | null, storage: {
|
|
7
|
+
read(): string | null;
|
|
8
|
+
write(value: string): void;
|
|
9
|
+
}): {
|
|
10
|
+
refresh: () => Promise<void>;
|
|
11
|
+
dispose: () => void;
|
|
12
|
+
};
|
|
13
|
+
export {};
|