@customerhero/js 2.1.0 → 2.2.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/dist/index.cjs +111 -3
- package/dist/index.d.cts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +111 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -75,6 +75,8 @@ var en = {
|
|
|
75
75
|
attach_menu_open: "Add attachment",
|
|
76
76
|
attach_photo: "Choose file",
|
|
77
77
|
drop_files_here: "Drop files here",
|
|
78
|
+
incident_dismiss: "Dismiss",
|
|
79
|
+
incident_default_link_label: "Learn more",
|
|
78
80
|
attachment_unsupported_type: "Unsupported file type"
|
|
79
81
|
};
|
|
80
82
|
|
|
@@ -104,6 +106,8 @@ var es = {
|
|
|
104
106
|
attach_menu_open: "A\xF1adir adjunto",
|
|
105
107
|
attach_photo: "Elegir archivo",
|
|
106
108
|
drop_files_here: "Suelta los archivos aqu\xED",
|
|
109
|
+
incident_dismiss: "Descartar",
|
|
110
|
+
incident_default_link_label: "M\xE1s informaci\xF3n",
|
|
107
111
|
attachment_unsupported_type: "Tipo de archivo no admitido"
|
|
108
112
|
};
|
|
109
113
|
|
|
@@ -133,6 +137,8 @@ var ptBR = {
|
|
|
133
137
|
attach_menu_open: "Adicionar anexo",
|
|
134
138
|
attach_photo: "Escolher arquivo",
|
|
135
139
|
drop_files_here: "Solte os arquivos aqui",
|
|
140
|
+
incident_dismiss: "Dispensar",
|
|
141
|
+
incident_default_link_label: "Saiba mais",
|
|
136
142
|
attachment_unsupported_type: "Tipo de arquivo n\xE3o suportado"
|
|
137
143
|
};
|
|
138
144
|
|
|
@@ -162,6 +168,8 @@ var ptPT = {
|
|
|
162
168
|
attach_menu_open: "Adicionar anexo",
|
|
163
169
|
attach_photo: "Escolher ficheiro",
|
|
164
170
|
drop_files_here: "Largue os ficheiros aqui",
|
|
171
|
+
incident_dismiss: "Dispensar",
|
|
172
|
+
incident_default_link_label: "Saiba mais",
|
|
165
173
|
attachment_unsupported_type: "Tipo de ficheiro n\xE3o suportado"
|
|
166
174
|
};
|
|
167
175
|
|
|
@@ -191,6 +199,8 @@ var fr = {
|
|
|
191
199
|
attach_menu_open: "Ajouter une pi\xE8ce jointe",
|
|
192
200
|
attach_photo: "Choisir un fichier",
|
|
193
201
|
drop_files_here: "D\xE9posez les fichiers ici",
|
|
202
|
+
incident_dismiss: "Ignorer",
|
|
203
|
+
incident_default_link_label: "En savoir plus",
|
|
194
204
|
attachment_unsupported_type: "Type de fichier non pris en charge"
|
|
195
205
|
};
|
|
196
206
|
|
|
@@ -220,6 +230,8 @@ var de = {
|
|
|
220
230
|
attach_menu_open: "Anhang hinzuf\xFCgen",
|
|
221
231
|
attach_photo: "Datei ausw\xE4hlen",
|
|
222
232
|
drop_files_here: "Dateien hier ablegen",
|
|
233
|
+
incident_dismiss: "Schlie\xDFen",
|
|
234
|
+
incident_default_link_label: "Mehr erfahren",
|
|
223
235
|
attachment_unsupported_type: "Dateityp nicht unterst\xFCtzt"
|
|
224
236
|
};
|
|
225
237
|
|
|
@@ -249,6 +261,8 @@ var it = {
|
|
|
249
261
|
attach_menu_open: "Aggiungi allegato",
|
|
250
262
|
attach_photo: "Scegli file",
|
|
251
263
|
drop_files_here: "Trascina qui i file",
|
|
264
|
+
incident_dismiss: "Chiudi",
|
|
265
|
+
incident_default_link_label: "Scopri di pi\xF9",
|
|
252
266
|
attachment_unsupported_type: "Tipo di file non supportato"
|
|
253
267
|
};
|
|
254
268
|
|
|
@@ -278,6 +292,8 @@ var nl = {
|
|
|
278
292
|
attach_menu_open: "Bijlage toevoegen",
|
|
279
293
|
attach_photo: "Bestand kiezen",
|
|
280
294
|
drop_files_here: "Sleep bestanden hier",
|
|
295
|
+
incident_dismiss: "Sluiten",
|
|
296
|
+
incident_default_link_label: "Meer informatie",
|
|
281
297
|
attachment_unsupported_type: "Bestandstype niet ondersteund"
|
|
282
298
|
};
|
|
283
299
|
|
|
@@ -307,6 +323,8 @@ var pl = {
|
|
|
307
323
|
attach_menu_open: "Dodaj za\u0142\u0105cznik",
|
|
308
324
|
attach_photo: "Wybierz plik",
|
|
309
325
|
drop_files_here: "Upu\u015B\u0107 pliki tutaj",
|
|
326
|
+
incident_dismiss: "Zamknij",
|
|
327
|
+
incident_default_link_label: "Dowiedz si\u0119 wi\u0119cej",
|
|
310
328
|
attachment_unsupported_type: "Nieobs\u0142ugiwany typ pliku"
|
|
311
329
|
};
|
|
312
330
|
|
|
@@ -336,6 +354,8 @@ var tr = {
|
|
|
336
354
|
attach_menu_open: "Ek ekle",
|
|
337
355
|
attach_photo: "Dosya se\xE7",
|
|
338
356
|
drop_files_here: "Dosyalar\u0131 buraya b\u0131rak",
|
|
357
|
+
incident_dismiss: "Kapat",
|
|
358
|
+
incident_default_link_label: "Daha fazla bilgi",
|
|
339
359
|
attachment_unsupported_type: "Desteklenmeyen dosya t\xFCr\xFC"
|
|
340
360
|
};
|
|
341
361
|
|
|
@@ -365,6 +385,8 @@ var ar = {
|
|
|
365
385
|
attach_menu_open: "\u0625\u0636\u0627\u0641\u0629 \u0645\u0631\u0641\u0642",
|
|
366
386
|
attach_photo: "\u0627\u062E\u062A\u0631 \u0645\u0644\u0641\u064B\u0627",
|
|
367
387
|
drop_files_here: "\u0623\u0641\u0644\u062A \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0647\u0646\u0627",
|
|
388
|
+
incident_dismiss: "\u0625\u063A\u0644\u0627\u0642",
|
|
389
|
+
incident_default_link_label: "\u0627\u0639\u0631\u0641 \u0627\u0644\u0645\u0632\u064A\u062F",
|
|
368
390
|
attachment_unsupported_type: "\u0646\u0648\u0639 \u0627\u0644\u0645\u0644\u0641 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645"
|
|
369
391
|
};
|
|
370
392
|
|
|
@@ -394,6 +416,8 @@ var ja = {
|
|
|
394
416
|
attach_menu_open: "\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u3092\u8FFD\u52A0",
|
|
395
417
|
attach_photo: "\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E",
|
|
396
418
|
drop_files_here: "\u30D5\u30A1\u30A4\u30EB\u3092\u3053\u3053\u306B\u30C9\u30ED\u30C3\u30D7",
|
|
419
|
+
incident_dismiss: "\u9589\u3058\u308B",
|
|
420
|
+
incident_default_link_label: "\u8A73\u7D30\u3092\u898B\u308B",
|
|
397
421
|
attachment_unsupported_type: "\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u306A\u3044\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F"
|
|
398
422
|
};
|
|
399
423
|
|
|
@@ -423,6 +447,8 @@ var ko = {
|
|
|
423
447
|
attach_menu_open: "\uCCA8\uBD80 \uD30C\uC77C \uCD94\uAC00",
|
|
424
448
|
attach_photo: "\uD30C\uC77C \uC120\uD0DD",
|
|
425
449
|
drop_files_here: "\uD30C\uC77C\uC744 \uC5EC\uAE30\uC5D0 \uB193\uAE30",
|
|
450
|
+
incident_dismiss: "\uB2EB\uAE30",
|
|
451
|
+
incident_default_link_label: "\uC790\uC138\uD788 \uC54C\uC544\uBCF4\uAE30",
|
|
426
452
|
attachment_unsupported_type: "\uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD"
|
|
427
453
|
};
|
|
428
454
|
|
|
@@ -452,6 +478,8 @@ var zhCN = {
|
|
|
452
478
|
attach_menu_open: "\u6DFB\u52A0\u9644\u4EF6",
|
|
453
479
|
attach_photo: "\u9009\u62E9\u6587\u4EF6",
|
|
454
480
|
drop_files_here: "\u5C06\u6587\u4EF6\u62D6\u653E\u5230\u6B64\u5904",
|
|
481
|
+
incident_dismiss: "\u5173\u95ED",
|
|
482
|
+
incident_default_link_label: "\u4E86\u89E3\u66F4\u591A",
|
|
455
483
|
attachment_unsupported_type: "\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B"
|
|
456
484
|
};
|
|
457
485
|
|
|
@@ -481,6 +509,8 @@ var zhTW = {
|
|
|
481
509
|
attach_menu_open: "\u65B0\u589E\u9644\u4EF6",
|
|
482
510
|
attach_photo: "\u9078\u64C7\u6A94\u6848",
|
|
483
511
|
drop_files_here: "\u5C07\u6A94\u6848\u62D6\u653E\u5230\u6B64\u8655",
|
|
512
|
+
incident_dismiss: "\u95DC\u9589",
|
|
513
|
+
incident_default_link_label: "\u77AD\u89E3\u66F4\u591A",
|
|
484
514
|
attachment_unsupported_type: "\u4E0D\u652F\u63F4\u7684\u6A94\u6848\u985E\u578B"
|
|
485
515
|
};
|
|
486
516
|
|
|
@@ -1000,9 +1030,50 @@ function resolveConfig(userConfig, fetched) {
|
|
|
1000
1030
|
stringOverrides: fetched?.stringOverrides
|
|
1001
1031
|
};
|
|
1002
1032
|
}
|
|
1033
|
+
function sanitizeIncidentBanner(input) {
|
|
1034
|
+
if (!input || typeof input !== "object") return null;
|
|
1035
|
+
const raw = input;
|
|
1036
|
+
const sev = raw.severity;
|
|
1037
|
+
if (sev !== "info" && sev !== "warning" && sev !== "outage") return null;
|
|
1038
|
+
if (typeof raw.title !== "string" || raw.title.length === 0) return null;
|
|
1039
|
+
if (typeof raw.expiresAt === "string") {
|
|
1040
|
+
const t = Date.parse(raw.expiresAt);
|
|
1041
|
+
if (!Number.isNaN(t) && t <= Date.now()) return null;
|
|
1042
|
+
}
|
|
1043
|
+
const out = { severity: sev, title: raw.title };
|
|
1044
|
+
if (typeof raw.body === "string") out.body = raw.body;
|
|
1045
|
+
if (typeof raw.eta === "string") out.eta = raw.eta;
|
|
1046
|
+
if (raw.link && typeof raw.link === "object") {
|
|
1047
|
+
const link = raw.link;
|
|
1048
|
+
if (typeof link.url === "string") {
|
|
1049
|
+
out.link = { url: link.url };
|
|
1050
|
+
if (typeof link.label === "string") out.link.label = link.label;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (typeof raw.expiresAt === "string") out.expiresAt = raw.expiresAt;
|
|
1054
|
+
return out;
|
|
1055
|
+
}
|
|
1056
|
+
function bannerKey(banner) {
|
|
1057
|
+
if (!banner) return null;
|
|
1058
|
+
return JSON.stringify([
|
|
1059
|
+
banner.severity,
|
|
1060
|
+
banner.title,
|
|
1061
|
+
banner.body ?? "",
|
|
1062
|
+
banner.eta ?? "",
|
|
1063
|
+
banner.link?.url ?? "",
|
|
1064
|
+
banner.link?.label ?? "",
|
|
1065
|
+
banner.expiresAt ?? ""
|
|
1066
|
+
]);
|
|
1067
|
+
}
|
|
1003
1068
|
function getStorage() {
|
|
1004
1069
|
try {
|
|
1005
|
-
|
|
1070
|
+
if (typeof window !== "undefined" && window.localStorage)
|
|
1071
|
+
return window.localStorage;
|
|
1072
|
+
if (typeof globalThis !== "undefined") {
|
|
1073
|
+
const ls = globalThis.localStorage;
|
|
1074
|
+
if (ls) return ls;
|
|
1075
|
+
}
|
|
1076
|
+
return null;
|
|
1006
1077
|
} catch {
|
|
1007
1078
|
return null;
|
|
1008
1079
|
}
|
|
@@ -1044,7 +1115,9 @@ var CustomerHeroChat = class {
|
|
|
1044
1115
|
preChatSubmission: null,
|
|
1045
1116
|
consent: this.readStoredConsent(),
|
|
1046
1117
|
pendingTriggerId: null,
|
|
1047
|
-
pendingPrefill: null
|
|
1118
|
+
pendingPrefill: null,
|
|
1119
|
+
incidentBanner: null,
|
|
1120
|
+
incidentBannerDismissed: false
|
|
1048
1121
|
};
|
|
1049
1122
|
}
|
|
1050
1123
|
// ── Proactive engagement state ─────────────────────────────────────
|
|
@@ -1123,11 +1196,18 @@ var CustomerHeroChat = class {
|
|
|
1123
1196
|
const resolved = resolveConfig(this.userConfig, fetched);
|
|
1124
1197
|
const triggers = Array.isArray(fetched.triggers) ? fetched.triggers : [];
|
|
1125
1198
|
const preChatForm = fetched.preChatForm ?? null;
|
|
1199
|
+
const incidentBanner = sanitizeIncidentBanner(fetched.incidentBanner);
|
|
1200
|
+
const prevBannerKey = bannerKey(this.state.incidentBanner);
|
|
1201
|
+
const nextBannerKey = bannerKey(incidentBanner);
|
|
1202
|
+
const dismissedFromStorage = nextBannerKey && nextBannerKey === this.readStoredBannerDismissal();
|
|
1203
|
+
const incidentBannerDismissed = nextBannerKey === prevBannerKey ? this.state.incidentBannerDismissed || !!dismissedFromStorage : !!dismissedFromStorage;
|
|
1126
1204
|
this.setState({
|
|
1127
1205
|
config: resolved,
|
|
1128
1206
|
configLoaded: true,
|
|
1129
1207
|
triggers,
|
|
1130
|
-
preChatForm
|
|
1208
|
+
preChatForm,
|
|
1209
|
+
incidentBanner,
|
|
1210
|
+
incidentBannerDismissed
|
|
1131
1211
|
});
|
|
1132
1212
|
if (resolved.stringOverrides) this.rebuildTranslator();
|
|
1133
1213
|
this.startTriggersRuntimeIfPossible();
|
|
@@ -1552,6 +1632,34 @@ var CustomerHeroChat = class {
|
|
|
1552
1632
|
setTraits(traits) {
|
|
1553
1633
|
this.triggersRuntime?.setTraits(traits);
|
|
1554
1634
|
}
|
|
1635
|
+
/** Hide the active incident banner for this visitor. Persisted in
|
|
1636
|
+
* localStorage so a refresh keeps it dismissed; resets automatically
|
|
1637
|
+
* when the operator changes the banner content. No-op when no banner
|
|
1638
|
+
* is showing. */
|
|
1639
|
+
dismissIncidentBanner() {
|
|
1640
|
+
const key = bannerKey(this.state.incidentBanner);
|
|
1641
|
+
if (!key) return;
|
|
1642
|
+
this.writeStoredBannerDismissal(key);
|
|
1643
|
+
this.setState({ incidentBannerDismissed: true });
|
|
1644
|
+
}
|
|
1645
|
+
readStoredBannerDismissal() {
|
|
1646
|
+
try {
|
|
1647
|
+
return this.storage?.getItem(
|
|
1648
|
+
`ch_incident_dismissed_${this.userConfig.chatbotId}`
|
|
1649
|
+
) ?? null;
|
|
1650
|
+
} catch {
|
|
1651
|
+
return null;
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
writeStoredBannerDismissal(key) {
|
|
1655
|
+
try {
|
|
1656
|
+
this.storage?.setItem(
|
|
1657
|
+
`ch_incident_dismissed_${this.userConfig.chatbotId}`,
|
|
1658
|
+
key
|
|
1659
|
+
);
|
|
1660
|
+
} catch {
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1555
1663
|
/** Submit pre-chat form answers. Synthesizes a customer record server-side
|
|
1556
1664
|
* on the next sendMessage. Resumes any pending message that was deferred
|
|
1557
1665
|
* while the form was open. */
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type TranslationKey = "online" | "typing" | "unable_to_load" | "powered_by" | "new_conversation" | "open_chat" | "close_chat" | "send_message" | "helpful" | "not_helpful" | "menu" | "action_approve" | "action_cancel" | "action_what_will_happen" | "action_already_resolved" | "action_failed" | "status_sending" | "status_sent" | "status_failed" | "screenshot_capture" | "attachment_remove" | "attach_menu_open" | "attach_photo" | "drop_files_here" | "attachment_unsupported_type";
|
|
1
|
+
type TranslationKey = "online" | "typing" | "unable_to_load" | "powered_by" | "new_conversation" | "open_chat" | "close_chat" | "send_message" | "helpful" | "not_helpful" | "menu" | "action_approve" | "action_cancel" | "action_what_will_happen" | "action_already_resolved" | "action_failed" | "status_sending" | "status_sent" | "status_failed" | "screenshot_capture" | "attachment_remove" | "attach_menu_open" | "attach_photo" | "drop_files_here" | "attachment_unsupported_type" | "incident_dismiss" | "incident_default_link_label";
|
|
2
2
|
type Translations = Record<TranslationKey, string>;
|
|
3
3
|
|
|
4
4
|
declare const SUPPORTED_LOCALES: readonly ["en", "es", "pt-BR", "pt-PT", "fr", "de", "it", "nl", "pl", "tr", "ar", "ja", "ko", "zh-CN", "zh-TW"];
|
|
@@ -244,6 +244,20 @@ interface PreChatSubmission {
|
|
|
244
244
|
/** Keyed answers from text/textarea/select/consent fields. */
|
|
245
245
|
properties?: Record<string, string | number | boolean>;
|
|
246
246
|
}
|
|
247
|
+
interface IncidentBanner {
|
|
248
|
+
severity: "info" | "warning" | "outage";
|
|
249
|
+
title: string;
|
|
250
|
+
body?: string;
|
|
251
|
+
/** Free-text human ETA, e.g. "Back online by 14:00 UTC". */
|
|
252
|
+
eta?: string;
|
|
253
|
+
/** Optional CTA — typically a status-page incident URL. */
|
|
254
|
+
link?: {
|
|
255
|
+
url: string;
|
|
256
|
+
label?: string;
|
|
257
|
+
};
|
|
258
|
+
/** ISO 8601 UTC. After this time the widget hides the banner. */
|
|
259
|
+
expiresAt?: string;
|
|
260
|
+
}
|
|
247
261
|
interface ConsentSettings {
|
|
248
262
|
/** When true, all condition kinds are evaluated. When false (default), only
|
|
249
263
|
* direct launcher clicks fire — URL/time/scroll/exit-intent/trait
|
|
@@ -284,6 +298,11 @@ interface ChatState {
|
|
|
284
298
|
/** When set, the host should preload this text into the input. Cleared
|
|
285
299
|
* once the host consumes it (or when the conversation starts). */
|
|
286
300
|
pendingPrefill: string | null;
|
|
301
|
+
/** Operator-controlled incident banner. `null` when none is active. */
|
|
302
|
+
incidentBanner: IncidentBanner | null;
|
|
303
|
+
/** True when the visitor has dismissed the active banner this session.
|
|
304
|
+
* Reset whenever a new banner (different content) lands. */
|
|
305
|
+
incidentBannerDismissed: boolean;
|
|
287
306
|
}
|
|
288
307
|
|
|
289
308
|
type Listener = (state: ChatState) => void;
|
|
@@ -339,6 +358,13 @@ declare class CustomerHeroChat {
|
|
|
339
358
|
* values are kept in memory (not persisted) so the integrator decides
|
|
340
359
|
* the source of truth. */
|
|
341
360
|
setTraits(traits: Record<string, string | number | boolean>): void;
|
|
361
|
+
/** Hide the active incident banner for this visitor. Persisted in
|
|
362
|
+
* localStorage so a refresh keeps it dismissed; resets automatically
|
|
363
|
+
* when the operator changes the banner content. No-op when no banner
|
|
364
|
+
* is showing. */
|
|
365
|
+
dismissIncidentBanner(): void;
|
|
366
|
+
private readStoredBannerDismissal;
|
|
367
|
+
private writeStoredBannerDismissal;
|
|
342
368
|
/** Submit pre-chat form answers. Synthesizes a customer record server-side
|
|
343
369
|
* on the next sendMessage. Resumes any pending message that was deferred
|
|
344
370
|
* while the form was open. */
|
|
@@ -438,4 +464,4 @@ interface StartTriggersRuntimeOptions {
|
|
|
438
464
|
}
|
|
439
465
|
declare function startTriggersRuntime(options: StartTriggersRuntimeOptions): TriggersRuntimeHandle;
|
|
440
466
|
|
|
441
|
-
export { type ActionConfirmationBlock, type ChatMessage, type ChatState, type ConsentSettings, CustomerHeroChat, type CustomerHeroChatConfig, DEFAULTS, type IdentifyPayload, type IdentityData, type MessageBlock, type MessageRating, type MessageSource, type MessageStatus, type PreChatField, type PreChatFieldKind, type PreChatFormConfig, type PreChatSubmission, type QuickRepliesBlock, type ResolvedConfig, SUPPORTED_LOCALES, ScreenshotCancelled, ScreenshotUnavailable, type StringOverrides, type SupportedLocale, type TranslateFn, type TranslationKey, type Translations, type TriggerAction, type TriggerConditionLeaf, type TriggerConditionNode, type TriggerDefinition, type TriggerFrequency, type TriggersRuntimeHandle, type VisitorContext, canCaptureScreenshot, captureScreenshot, createTranslator, detectLocale, evaluate, isRtlLocale, pickFire, resolveLocale, startTriggersRuntime };
|
|
467
|
+
export { type ActionConfirmationBlock, type ChatMessage, type ChatState, type ConsentSettings, CustomerHeroChat, type CustomerHeroChatConfig, DEFAULTS, type IdentifyPayload, type IdentityData, type IncidentBanner, type MessageBlock, type MessageRating, type MessageSource, type MessageStatus, type PreChatField, type PreChatFieldKind, type PreChatFormConfig, type PreChatSubmission, type QuickRepliesBlock, type ResolvedConfig, SUPPORTED_LOCALES, ScreenshotCancelled, ScreenshotUnavailable, type StringOverrides, type SupportedLocale, type TranslateFn, type TranslationKey, type Translations, type TriggerAction, type TriggerConditionLeaf, type TriggerConditionNode, type TriggerDefinition, type TriggerFrequency, type TriggersRuntimeHandle, type VisitorContext, canCaptureScreenshot, captureScreenshot, createTranslator, detectLocale, evaluate, isRtlLocale, pickFire, resolveLocale, startTriggersRuntime };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type TranslationKey = "online" | "typing" | "unable_to_load" | "powered_by" | "new_conversation" | "open_chat" | "close_chat" | "send_message" | "helpful" | "not_helpful" | "menu" | "action_approve" | "action_cancel" | "action_what_will_happen" | "action_already_resolved" | "action_failed" | "status_sending" | "status_sent" | "status_failed" | "screenshot_capture" | "attachment_remove" | "attach_menu_open" | "attach_photo" | "drop_files_here" | "attachment_unsupported_type";
|
|
1
|
+
type TranslationKey = "online" | "typing" | "unable_to_load" | "powered_by" | "new_conversation" | "open_chat" | "close_chat" | "send_message" | "helpful" | "not_helpful" | "menu" | "action_approve" | "action_cancel" | "action_what_will_happen" | "action_already_resolved" | "action_failed" | "status_sending" | "status_sent" | "status_failed" | "screenshot_capture" | "attachment_remove" | "attach_menu_open" | "attach_photo" | "drop_files_here" | "attachment_unsupported_type" | "incident_dismiss" | "incident_default_link_label";
|
|
2
2
|
type Translations = Record<TranslationKey, string>;
|
|
3
3
|
|
|
4
4
|
declare const SUPPORTED_LOCALES: readonly ["en", "es", "pt-BR", "pt-PT", "fr", "de", "it", "nl", "pl", "tr", "ar", "ja", "ko", "zh-CN", "zh-TW"];
|
|
@@ -244,6 +244,20 @@ interface PreChatSubmission {
|
|
|
244
244
|
/** Keyed answers from text/textarea/select/consent fields. */
|
|
245
245
|
properties?: Record<string, string | number | boolean>;
|
|
246
246
|
}
|
|
247
|
+
interface IncidentBanner {
|
|
248
|
+
severity: "info" | "warning" | "outage";
|
|
249
|
+
title: string;
|
|
250
|
+
body?: string;
|
|
251
|
+
/** Free-text human ETA, e.g. "Back online by 14:00 UTC". */
|
|
252
|
+
eta?: string;
|
|
253
|
+
/** Optional CTA — typically a status-page incident URL. */
|
|
254
|
+
link?: {
|
|
255
|
+
url: string;
|
|
256
|
+
label?: string;
|
|
257
|
+
};
|
|
258
|
+
/** ISO 8601 UTC. After this time the widget hides the banner. */
|
|
259
|
+
expiresAt?: string;
|
|
260
|
+
}
|
|
247
261
|
interface ConsentSettings {
|
|
248
262
|
/** When true, all condition kinds are evaluated. When false (default), only
|
|
249
263
|
* direct launcher clicks fire — URL/time/scroll/exit-intent/trait
|
|
@@ -284,6 +298,11 @@ interface ChatState {
|
|
|
284
298
|
/** When set, the host should preload this text into the input. Cleared
|
|
285
299
|
* once the host consumes it (or when the conversation starts). */
|
|
286
300
|
pendingPrefill: string | null;
|
|
301
|
+
/** Operator-controlled incident banner. `null` when none is active. */
|
|
302
|
+
incidentBanner: IncidentBanner | null;
|
|
303
|
+
/** True when the visitor has dismissed the active banner this session.
|
|
304
|
+
* Reset whenever a new banner (different content) lands. */
|
|
305
|
+
incidentBannerDismissed: boolean;
|
|
287
306
|
}
|
|
288
307
|
|
|
289
308
|
type Listener = (state: ChatState) => void;
|
|
@@ -339,6 +358,13 @@ declare class CustomerHeroChat {
|
|
|
339
358
|
* values are kept in memory (not persisted) so the integrator decides
|
|
340
359
|
* the source of truth. */
|
|
341
360
|
setTraits(traits: Record<string, string | number | boolean>): void;
|
|
361
|
+
/** Hide the active incident banner for this visitor. Persisted in
|
|
362
|
+
* localStorage so a refresh keeps it dismissed; resets automatically
|
|
363
|
+
* when the operator changes the banner content. No-op when no banner
|
|
364
|
+
* is showing. */
|
|
365
|
+
dismissIncidentBanner(): void;
|
|
366
|
+
private readStoredBannerDismissal;
|
|
367
|
+
private writeStoredBannerDismissal;
|
|
342
368
|
/** Submit pre-chat form answers. Synthesizes a customer record server-side
|
|
343
369
|
* on the next sendMessage. Resumes any pending message that was deferred
|
|
344
370
|
* while the form was open. */
|
|
@@ -438,4 +464,4 @@ interface StartTriggersRuntimeOptions {
|
|
|
438
464
|
}
|
|
439
465
|
declare function startTriggersRuntime(options: StartTriggersRuntimeOptions): TriggersRuntimeHandle;
|
|
440
466
|
|
|
441
|
-
export { type ActionConfirmationBlock, type ChatMessage, type ChatState, type ConsentSettings, CustomerHeroChat, type CustomerHeroChatConfig, DEFAULTS, type IdentifyPayload, type IdentityData, type MessageBlock, type MessageRating, type MessageSource, type MessageStatus, type PreChatField, type PreChatFieldKind, type PreChatFormConfig, type PreChatSubmission, type QuickRepliesBlock, type ResolvedConfig, SUPPORTED_LOCALES, ScreenshotCancelled, ScreenshotUnavailable, type StringOverrides, type SupportedLocale, type TranslateFn, type TranslationKey, type Translations, type TriggerAction, type TriggerConditionLeaf, type TriggerConditionNode, type TriggerDefinition, type TriggerFrequency, type TriggersRuntimeHandle, type VisitorContext, canCaptureScreenshot, captureScreenshot, createTranslator, detectLocale, evaluate, isRtlLocale, pickFire, resolveLocale, startTriggersRuntime };
|
|
467
|
+
export { type ActionConfirmationBlock, type ChatMessage, type ChatState, type ConsentSettings, CustomerHeroChat, type CustomerHeroChatConfig, DEFAULTS, type IdentifyPayload, type IdentityData, type IncidentBanner, type MessageBlock, type MessageRating, type MessageSource, type MessageStatus, type PreChatField, type PreChatFieldKind, type PreChatFormConfig, type PreChatSubmission, type QuickRepliesBlock, type ResolvedConfig, SUPPORTED_LOCALES, ScreenshotCancelled, ScreenshotUnavailable, type StringOverrides, type SupportedLocale, type TranslateFn, type TranslationKey, type Translations, type TriggerAction, type TriggerConditionLeaf, type TriggerConditionNode, type TriggerDefinition, type TriggerFrequency, type TriggersRuntimeHandle, type VisitorContext, canCaptureScreenshot, captureScreenshot, createTranslator, detectLocale, evaluate, isRtlLocale, pickFire, resolveLocale, startTriggersRuntime };
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,8 @@ var en = {
|
|
|
36
36
|
attach_menu_open: "Add attachment",
|
|
37
37
|
attach_photo: "Choose file",
|
|
38
38
|
drop_files_here: "Drop files here",
|
|
39
|
+
incident_dismiss: "Dismiss",
|
|
40
|
+
incident_default_link_label: "Learn more",
|
|
39
41
|
attachment_unsupported_type: "Unsupported file type"
|
|
40
42
|
};
|
|
41
43
|
|
|
@@ -65,6 +67,8 @@ var es = {
|
|
|
65
67
|
attach_menu_open: "A\xF1adir adjunto",
|
|
66
68
|
attach_photo: "Elegir archivo",
|
|
67
69
|
drop_files_here: "Suelta los archivos aqu\xED",
|
|
70
|
+
incident_dismiss: "Descartar",
|
|
71
|
+
incident_default_link_label: "M\xE1s informaci\xF3n",
|
|
68
72
|
attachment_unsupported_type: "Tipo de archivo no admitido"
|
|
69
73
|
};
|
|
70
74
|
|
|
@@ -94,6 +98,8 @@ var ptBR = {
|
|
|
94
98
|
attach_menu_open: "Adicionar anexo",
|
|
95
99
|
attach_photo: "Escolher arquivo",
|
|
96
100
|
drop_files_here: "Solte os arquivos aqui",
|
|
101
|
+
incident_dismiss: "Dispensar",
|
|
102
|
+
incident_default_link_label: "Saiba mais",
|
|
97
103
|
attachment_unsupported_type: "Tipo de arquivo n\xE3o suportado"
|
|
98
104
|
};
|
|
99
105
|
|
|
@@ -123,6 +129,8 @@ var ptPT = {
|
|
|
123
129
|
attach_menu_open: "Adicionar anexo",
|
|
124
130
|
attach_photo: "Escolher ficheiro",
|
|
125
131
|
drop_files_here: "Largue os ficheiros aqui",
|
|
132
|
+
incident_dismiss: "Dispensar",
|
|
133
|
+
incident_default_link_label: "Saiba mais",
|
|
126
134
|
attachment_unsupported_type: "Tipo de ficheiro n\xE3o suportado"
|
|
127
135
|
};
|
|
128
136
|
|
|
@@ -152,6 +160,8 @@ var fr = {
|
|
|
152
160
|
attach_menu_open: "Ajouter une pi\xE8ce jointe",
|
|
153
161
|
attach_photo: "Choisir un fichier",
|
|
154
162
|
drop_files_here: "D\xE9posez les fichiers ici",
|
|
163
|
+
incident_dismiss: "Ignorer",
|
|
164
|
+
incident_default_link_label: "En savoir plus",
|
|
155
165
|
attachment_unsupported_type: "Type de fichier non pris en charge"
|
|
156
166
|
};
|
|
157
167
|
|
|
@@ -181,6 +191,8 @@ var de = {
|
|
|
181
191
|
attach_menu_open: "Anhang hinzuf\xFCgen",
|
|
182
192
|
attach_photo: "Datei ausw\xE4hlen",
|
|
183
193
|
drop_files_here: "Dateien hier ablegen",
|
|
194
|
+
incident_dismiss: "Schlie\xDFen",
|
|
195
|
+
incident_default_link_label: "Mehr erfahren",
|
|
184
196
|
attachment_unsupported_type: "Dateityp nicht unterst\xFCtzt"
|
|
185
197
|
};
|
|
186
198
|
|
|
@@ -210,6 +222,8 @@ var it = {
|
|
|
210
222
|
attach_menu_open: "Aggiungi allegato",
|
|
211
223
|
attach_photo: "Scegli file",
|
|
212
224
|
drop_files_here: "Trascina qui i file",
|
|
225
|
+
incident_dismiss: "Chiudi",
|
|
226
|
+
incident_default_link_label: "Scopri di pi\xF9",
|
|
213
227
|
attachment_unsupported_type: "Tipo di file non supportato"
|
|
214
228
|
};
|
|
215
229
|
|
|
@@ -239,6 +253,8 @@ var nl = {
|
|
|
239
253
|
attach_menu_open: "Bijlage toevoegen",
|
|
240
254
|
attach_photo: "Bestand kiezen",
|
|
241
255
|
drop_files_here: "Sleep bestanden hier",
|
|
256
|
+
incident_dismiss: "Sluiten",
|
|
257
|
+
incident_default_link_label: "Meer informatie",
|
|
242
258
|
attachment_unsupported_type: "Bestandstype niet ondersteund"
|
|
243
259
|
};
|
|
244
260
|
|
|
@@ -268,6 +284,8 @@ var pl = {
|
|
|
268
284
|
attach_menu_open: "Dodaj za\u0142\u0105cznik",
|
|
269
285
|
attach_photo: "Wybierz plik",
|
|
270
286
|
drop_files_here: "Upu\u015B\u0107 pliki tutaj",
|
|
287
|
+
incident_dismiss: "Zamknij",
|
|
288
|
+
incident_default_link_label: "Dowiedz si\u0119 wi\u0119cej",
|
|
271
289
|
attachment_unsupported_type: "Nieobs\u0142ugiwany typ pliku"
|
|
272
290
|
};
|
|
273
291
|
|
|
@@ -297,6 +315,8 @@ var tr = {
|
|
|
297
315
|
attach_menu_open: "Ek ekle",
|
|
298
316
|
attach_photo: "Dosya se\xE7",
|
|
299
317
|
drop_files_here: "Dosyalar\u0131 buraya b\u0131rak",
|
|
318
|
+
incident_dismiss: "Kapat",
|
|
319
|
+
incident_default_link_label: "Daha fazla bilgi",
|
|
300
320
|
attachment_unsupported_type: "Desteklenmeyen dosya t\xFCr\xFC"
|
|
301
321
|
};
|
|
302
322
|
|
|
@@ -326,6 +346,8 @@ var ar = {
|
|
|
326
346
|
attach_menu_open: "\u0625\u0636\u0627\u0641\u0629 \u0645\u0631\u0641\u0642",
|
|
327
347
|
attach_photo: "\u0627\u062E\u062A\u0631 \u0645\u0644\u0641\u064B\u0627",
|
|
328
348
|
drop_files_here: "\u0623\u0641\u0644\u062A \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0647\u0646\u0627",
|
|
349
|
+
incident_dismiss: "\u0625\u063A\u0644\u0627\u0642",
|
|
350
|
+
incident_default_link_label: "\u0627\u0639\u0631\u0641 \u0627\u0644\u0645\u0632\u064A\u062F",
|
|
329
351
|
attachment_unsupported_type: "\u0646\u0648\u0639 \u0627\u0644\u0645\u0644\u0641 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645"
|
|
330
352
|
};
|
|
331
353
|
|
|
@@ -355,6 +377,8 @@ var ja = {
|
|
|
355
377
|
attach_menu_open: "\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u3092\u8FFD\u52A0",
|
|
356
378
|
attach_photo: "\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E",
|
|
357
379
|
drop_files_here: "\u30D5\u30A1\u30A4\u30EB\u3092\u3053\u3053\u306B\u30C9\u30ED\u30C3\u30D7",
|
|
380
|
+
incident_dismiss: "\u9589\u3058\u308B",
|
|
381
|
+
incident_default_link_label: "\u8A73\u7D30\u3092\u898B\u308B",
|
|
358
382
|
attachment_unsupported_type: "\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u306A\u3044\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F"
|
|
359
383
|
};
|
|
360
384
|
|
|
@@ -384,6 +408,8 @@ var ko = {
|
|
|
384
408
|
attach_menu_open: "\uCCA8\uBD80 \uD30C\uC77C \uCD94\uAC00",
|
|
385
409
|
attach_photo: "\uD30C\uC77C \uC120\uD0DD",
|
|
386
410
|
drop_files_here: "\uD30C\uC77C\uC744 \uC5EC\uAE30\uC5D0 \uB193\uAE30",
|
|
411
|
+
incident_dismiss: "\uB2EB\uAE30",
|
|
412
|
+
incident_default_link_label: "\uC790\uC138\uD788 \uC54C\uC544\uBCF4\uAE30",
|
|
387
413
|
attachment_unsupported_type: "\uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD"
|
|
388
414
|
};
|
|
389
415
|
|
|
@@ -413,6 +439,8 @@ var zhCN = {
|
|
|
413
439
|
attach_menu_open: "\u6DFB\u52A0\u9644\u4EF6",
|
|
414
440
|
attach_photo: "\u9009\u62E9\u6587\u4EF6",
|
|
415
441
|
drop_files_here: "\u5C06\u6587\u4EF6\u62D6\u653E\u5230\u6B64\u5904",
|
|
442
|
+
incident_dismiss: "\u5173\u95ED",
|
|
443
|
+
incident_default_link_label: "\u4E86\u89E3\u66F4\u591A",
|
|
416
444
|
attachment_unsupported_type: "\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B"
|
|
417
445
|
};
|
|
418
446
|
|
|
@@ -442,6 +470,8 @@ var zhTW = {
|
|
|
442
470
|
attach_menu_open: "\u65B0\u589E\u9644\u4EF6",
|
|
443
471
|
attach_photo: "\u9078\u64C7\u6A94\u6848",
|
|
444
472
|
drop_files_here: "\u5C07\u6A94\u6848\u62D6\u653E\u5230\u6B64\u8655",
|
|
473
|
+
incident_dismiss: "\u95DC\u9589",
|
|
474
|
+
incident_default_link_label: "\u77AD\u89E3\u66F4\u591A",
|
|
445
475
|
attachment_unsupported_type: "\u4E0D\u652F\u63F4\u7684\u6A94\u6848\u985E\u578B"
|
|
446
476
|
};
|
|
447
477
|
|
|
@@ -961,9 +991,50 @@ function resolveConfig(userConfig, fetched) {
|
|
|
961
991
|
stringOverrides: fetched?.stringOverrides
|
|
962
992
|
};
|
|
963
993
|
}
|
|
994
|
+
function sanitizeIncidentBanner(input) {
|
|
995
|
+
if (!input || typeof input !== "object") return null;
|
|
996
|
+
const raw = input;
|
|
997
|
+
const sev = raw.severity;
|
|
998
|
+
if (sev !== "info" && sev !== "warning" && sev !== "outage") return null;
|
|
999
|
+
if (typeof raw.title !== "string" || raw.title.length === 0) return null;
|
|
1000
|
+
if (typeof raw.expiresAt === "string") {
|
|
1001
|
+
const t = Date.parse(raw.expiresAt);
|
|
1002
|
+
if (!Number.isNaN(t) && t <= Date.now()) return null;
|
|
1003
|
+
}
|
|
1004
|
+
const out = { severity: sev, title: raw.title };
|
|
1005
|
+
if (typeof raw.body === "string") out.body = raw.body;
|
|
1006
|
+
if (typeof raw.eta === "string") out.eta = raw.eta;
|
|
1007
|
+
if (raw.link && typeof raw.link === "object") {
|
|
1008
|
+
const link = raw.link;
|
|
1009
|
+
if (typeof link.url === "string") {
|
|
1010
|
+
out.link = { url: link.url };
|
|
1011
|
+
if (typeof link.label === "string") out.link.label = link.label;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (typeof raw.expiresAt === "string") out.expiresAt = raw.expiresAt;
|
|
1015
|
+
return out;
|
|
1016
|
+
}
|
|
1017
|
+
function bannerKey(banner) {
|
|
1018
|
+
if (!banner) return null;
|
|
1019
|
+
return JSON.stringify([
|
|
1020
|
+
banner.severity,
|
|
1021
|
+
banner.title,
|
|
1022
|
+
banner.body ?? "",
|
|
1023
|
+
banner.eta ?? "",
|
|
1024
|
+
banner.link?.url ?? "",
|
|
1025
|
+
banner.link?.label ?? "",
|
|
1026
|
+
banner.expiresAt ?? ""
|
|
1027
|
+
]);
|
|
1028
|
+
}
|
|
964
1029
|
function getStorage() {
|
|
965
1030
|
try {
|
|
966
|
-
|
|
1031
|
+
if (typeof window !== "undefined" && window.localStorage)
|
|
1032
|
+
return window.localStorage;
|
|
1033
|
+
if (typeof globalThis !== "undefined") {
|
|
1034
|
+
const ls = globalThis.localStorage;
|
|
1035
|
+
if (ls) return ls;
|
|
1036
|
+
}
|
|
1037
|
+
return null;
|
|
967
1038
|
} catch {
|
|
968
1039
|
return null;
|
|
969
1040
|
}
|
|
@@ -1005,7 +1076,9 @@ var CustomerHeroChat = class {
|
|
|
1005
1076
|
preChatSubmission: null,
|
|
1006
1077
|
consent: this.readStoredConsent(),
|
|
1007
1078
|
pendingTriggerId: null,
|
|
1008
|
-
pendingPrefill: null
|
|
1079
|
+
pendingPrefill: null,
|
|
1080
|
+
incidentBanner: null,
|
|
1081
|
+
incidentBannerDismissed: false
|
|
1009
1082
|
};
|
|
1010
1083
|
}
|
|
1011
1084
|
// ── Proactive engagement state ─────────────────────────────────────
|
|
@@ -1084,11 +1157,18 @@ var CustomerHeroChat = class {
|
|
|
1084
1157
|
const resolved = resolveConfig(this.userConfig, fetched);
|
|
1085
1158
|
const triggers = Array.isArray(fetched.triggers) ? fetched.triggers : [];
|
|
1086
1159
|
const preChatForm = fetched.preChatForm ?? null;
|
|
1160
|
+
const incidentBanner = sanitizeIncidentBanner(fetched.incidentBanner);
|
|
1161
|
+
const prevBannerKey = bannerKey(this.state.incidentBanner);
|
|
1162
|
+
const nextBannerKey = bannerKey(incidentBanner);
|
|
1163
|
+
const dismissedFromStorage = nextBannerKey && nextBannerKey === this.readStoredBannerDismissal();
|
|
1164
|
+
const incidentBannerDismissed = nextBannerKey === prevBannerKey ? this.state.incidentBannerDismissed || !!dismissedFromStorage : !!dismissedFromStorage;
|
|
1087
1165
|
this.setState({
|
|
1088
1166
|
config: resolved,
|
|
1089
1167
|
configLoaded: true,
|
|
1090
1168
|
triggers,
|
|
1091
|
-
preChatForm
|
|
1169
|
+
preChatForm,
|
|
1170
|
+
incidentBanner,
|
|
1171
|
+
incidentBannerDismissed
|
|
1092
1172
|
});
|
|
1093
1173
|
if (resolved.stringOverrides) this.rebuildTranslator();
|
|
1094
1174
|
this.startTriggersRuntimeIfPossible();
|
|
@@ -1513,6 +1593,34 @@ var CustomerHeroChat = class {
|
|
|
1513
1593
|
setTraits(traits) {
|
|
1514
1594
|
this.triggersRuntime?.setTraits(traits);
|
|
1515
1595
|
}
|
|
1596
|
+
/** Hide the active incident banner for this visitor. Persisted in
|
|
1597
|
+
* localStorage so a refresh keeps it dismissed; resets automatically
|
|
1598
|
+
* when the operator changes the banner content. No-op when no banner
|
|
1599
|
+
* is showing. */
|
|
1600
|
+
dismissIncidentBanner() {
|
|
1601
|
+
const key = bannerKey(this.state.incidentBanner);
|
|
1602
|
+
if (!key) return;
|
|
1603
|
+
this.writeStoredBannerDismissal(key);
|
|
1604
|
+
this.setState({ incidentBannerDismissed: true });
|
|
1605
|
+
}
|
|
1606
|
+
readStoredBannerDismissal() {
|
|
1607
|
+
try {
|
|
1608
|
+
return this.storage?.getItem(
|
|
1609
|
+
`ch_incident_dismissed_${this.userConfig.chatbotId}`
|
|
1610
|
+
) ?? null;
|
|
1611
|
+
} catch {
|
|
1612
|
+
return null;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
writeStoredBannerDismissal(key) {
|
|
1616
|
+
try {
|
|
1617
|
+
this.storage?.setItem(
|
|
1618
|
+
`ch_incident_dismissed_${this.userConfig.chatbotId}`,
|
|
1619
|
+
key
|
|
1620
|
+
);
|
|
1621
|
+
} catch {
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1516
1624
|
/** Submit pre-chat form answers. Synthesizes a customer record server-side
|
|
1517
1625
|
* on the next sendMessage. Resumes any pending message that was deferred
|
|
1518
1626
|
* while the form was open. */
|