@mrrocket/sdk 0.15.0 → 0.17.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/CHANGELOG.md +29 -0
- package/README.md +47 -3
- package/dist/api-client.d.ts +12 -5
- package/dist/api-client.js +12 -8
- package/dist/api-client.js.map +1 -1
- package/dist/api.d.ts +4 -1
- package/dist/api.js +2 -1
- package/dist/api.js.map +1 -1
- package/dist/batch.d.ts +6 -4
- package/dist/batch.js +3 -3
- package/dist/batch.js.map +1 -1
- package/dist/browser/mrrocket-flows.js +9 -2
- package/dist/browser/mrrocket-forms.js +1 -1
- package/dist/browser/mrrocket-messenger.js +42 -43
- package/dist/browser/mrrocket-push.js +1 -1
- package/dist/browser/mrrocket-replay.js +3 -3
- package/dist/browser/mrrocket.js +1 -1
- package/dist/client.d.ts +10 -2
- package/dist/client.js +36 -15
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +5 -1
- package/dist/context.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/errors.d.ts +5 -1
- package/dist/errors.js +8 -2
- package/dist/errors.js.map +1 -1
- package/dist/flows-ui.d.ts +1 -1
- package/dist/flows-ui.js +64 -14
- package/dist/flows-ui.js.map +1 -1
- package/dist/flows-web.d.ts +2 -0
- package/dist/flows-web.js +4 -1
- package/dist/flows-web.js.map +1 -1
- package/dist/flows.d.ts +59 -3
- package/dist/flows.js +88 -7
- package/dist/flows.js.map +1 -1
- package/dist/forms.d.ts +4 -0
- package/dist/forms.js +4 -1
- package/dist/forms.js.map +1 -1
- package/dist/identity.d.ts +42 -0
- package/dist/identity.js +24 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/messenger-ui.d.ts +12 -2
- package/dist/messenger-ui.js +58 -47
- package/dist/messenger-ui.js.map +1 -1
- package/dist/messenger.js +3 -2
- package/dist/messenger.js.map +1 -1
- package/dist/push-web.d.ts +2 -13
- package/dist/push-web.js +4 -2
- package/dist/push-web.js.map +1 -1
- package/dist/react-native/index.d.cts +105 -14
- package/dist/react-native/index.d.ts +105 -14
- package/dist/react-native/index.js +238 -55
- package/dist/react-native/index.js.map +1 -1
- package/dist/replay.d.ts +4 -1
- package/dist/replay.js +8 -2
- package/dist/replay.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/dist/styles-css.d.ts +1 -1
- package/dist/styles-css.js +40 -41
- package/dist/styles-css.js.map +1 -1
- package/dist/user-hash.d.ts +27 -0
- package/dist/user-hash.js +24 -0
- package/dist/user-hash.js.map +1 -0
- package/package.json +5 -1
package/dist/messenger-ui.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The web messenger, after Crisp's: a round launcher (
|
|
2
|
+
* The web messenger, after Crisp's: a round launcher (a click opens it, no card on hover) and a panel
|
|
3
3
|
* with a bar on top (Home, a "Chat · Help" switch while there are both, a ⋮ menu to minimize or widen it). Home shows the greeting,
|
|
4
4
|
* the latest chat and the help search; Chat is the chat with the team, answered in MRRocket › Support by the owner or
|
|
5
5
|
* the Customer experience agent; Help lists the product's published help articles by collection, searchable, read in
|
|
@@ -23,6 +23,8 @@ export interface MessengerUiOptions {
|
|
|
23
23
|
name?: string;
|
|
24
24
|
email?: string;
|
|
25
25
|
} | undefined;
|
|
26
|
+
/** The identity hash of the visitor id now (0.16.0), when the site gave one to identify. */
|
|
27
|
+
userHash?: () => string | undefined;
|
|
26
28
|
/** Show the round launcher (default true). Without it the panel opens only through `open()`. */
|
|
27
29
|
launcher?: boolean;
|
|
28
30
|
/** Where the launcher sits (default bottom right); the panel and the cards open from there. */
|
|
@@ -55,8 +57,14 @@ export interface MessengerUiOptions {
|
|
|
55
57
|
header?: "plain" | "color";
|
|
56
58
|
/** "Powered by MRRocket" at the bottom; MRRocket's server says whether the plan may hide it. */
|
|
57
59
|
branding?: boolean;
|
|
58
|
-
/** The
|
|
60
|
+
/** The logo at the top left of Home (MRRocket sends the uploaded logo, else the favicon); without it the title's first letter. */
|
|
59
61
|
logo?: string;
|
|
62
|
+
/** The round mark in the chat's head (MRRocket sends the favicon); without it the title's first letter. */
|
|
63
|
+
icon?: string;
|
|
64
|
+
/** The AI agent's name on its answers (default "AI agent"). */
|
|
65
|
+
agentName?: string;
|
|
66
|
+
/** The AI agent's picture beside its answers. */
|
|
67
|
+
agentPhoto?: string;
|
|
60
68
|
/** MRRocket's own preview: mount inside this element (positioned) instead of the page. */
|
|
61
69
|
container?: HTMLElement;
|
|
62
70
|
/** MRRocket's own preview: answers from here instead of the server. */
|
|
@@ -80,5 +88,7 @@ export interface MessengerHandle {
|
|
|
80
88
|
/**
|
|
81
89
|
* Mounts the messenger with its look from MRRocket (Support › Messenger) underneath what the code passes: an option the
|
|
82
90
|
* code sets wins, one it leaves out comes from MRRocket, then the default. Calls made before the look arrived wait.
|
|
91
|
+
* A repeat visit starts with the look this browser saw last; a look that arrives later than that (changed, or slower
|
|
92
|
+
* than LOOK_WAIT_MS) replaces the launcher while the panel is closed, or once it closes.
|
|
83
93
|
*/
|
|
84
94
|
export declare const mountMessenger: (o: MessengerUiOptions) => MessengerHandle;
|
package/dist/messenger-ui.js
CHANGED
|
@@ -15,7 +15,6 @@ var POLL_IDLE_MS = 3e4;
|
|
|
15
15
|
var WAITING_FOR_MS = 10 * 6e4;
|
|
16
16
|
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
|
|
17
17
|
var SEEN_KEY = "ckw_msgr_seen";
|
|
18
|
-
var whoLabel = { visitor: "You", team: "Team", ai: "AI agent", auto: "Team" };
|
|
19
18
|
var readSeen = () => {
|
|
20
19
|
try {
|
|
21
20
|
return window.localStorage.getItem(SEEN_KEY) ?? "";
|
|
@@ -167,20 +166,52 @@ var blockOf = (b) => {
|
|
|
167
166
|
}
|
|
168
167
|
};
|
|
169
168
|
var LOOK_WAIT_MS = 2500;
|
|
169
|
+
var LOOK_KEY = "ckw_msgr_look:";
|
|
170
|
+
var readCachedLook = (apiKey) => {
|
|
171
|
+
try {
|
|
172
|
+
const raw = window.localStorage.getItem(LOOK_KEY + apiKey);
|
|
173
|
+
return raw ? JSON.parse(raw) : null;
|
|
174
|
+
} catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var writeCachedLook = (apiKey, look) => {
|
|
179
|
+
try {
|
|
180
|
+
window.localStorage.setItem(LOOK_KEY + apiKey, JSON.stringify(look));
|
|
181
|
+
} catch {
|
|
182
|
+
}
|
|
183
|
+
};
|
|
170
184
|
var mountMessenger = (o) => {
|
|
171
185
|
let real = null;
|
|
186
|
+
let shown = "";
|
|
172
187
|
let gone = false;
|
|
173
188
|
const queued = [];
|
|
174
189
|
const later = (fn) => real ? fn(real) : queued.push(fn);
|
|
175
190
|
const ctrl = new AbortController();
|
|
191
|
+
const caching = !o.client && !!o.apiKey;
|
|
176
192
|
const start = (look) => {
|
|
177
|
-
if (
|
|
193
|
+
if (gone) return;
|
|
194
|
+
const key = JSON.stringify(look ?? {});
|
|
195
|
+
if (real && key === shown) return;
|
|
196
|
+
if (real?.isOpen()) {
|
|
197
|
+
real.onClose(() => start(look));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
real?.destroy();
|
|
201
|
+
shown = key;
|
|
178
202
|
const defined = Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
179
203
|
real = build({ ...look ?? {}, ...defined, accent: o.accent ?? look?.accent, theme: o.theme ?? look?.theme, branding: look?.branding ?? true });
|
|
180
204
|
for (const fn of queued.splice(0)) fn(real);
|
|
181
205
|
};
|
|
182
|
-
const
|
|
183
|
-
|
|
206
|
+
const cached = caching ? readCachedLook(o.apiKey) : null;
|
|
207
|
+
if (cached) start(cached);
|
|
208
|
+
const timer = cached ? void 0 : setTimeout(() => start(null), LOOK_WAIT_MS);
|
|
209
|
+
(o.client ?? createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user(), userHash: o.userHash?.() })).messengerLook(ctrl.signal).then((look) => {
|
|
210
|
+
if (caching && look) writeCachedLook(o.apiKey, look);
|
|
211
|
+
start(look);
|
|
212
|
+
}).catch(() => {
|
|
213
|
+
if (!real) start(null);
|
|
214
|
+
}).finally(() => clearTimeout(timer));
|
|
184
215
|
return {
|
|
185
216
|
open: (v) => later((h) => h.open(v)),
|
|
186
217
|
close: () => real?.close(),
|
|
@@ -203,11 +234,12 @@ var build = (o) => {
|
|
|
203
234
|
const label = o.label ?? "";
|
|
204
235
|
const reply = replyLine(o.replyTime);
|
|
205
236
|
const initial = (title.trim()[0] ?? "?").toUpperCase();
|
|
237
|
+
const whoLabel = { visitor: "You", team: "Team", ai: o.agentName?.trim() || "AI agent", auto: "Team" };
|
|
206
238
|
const launcherOn = o.launcher ?? true;
|
|
207
239
|
const helpOn = o.help ?? true;
|
|
208
240
|
const soundOn = o.sound ?? true;
|
|
209
241
|
const previewOn = o.preview ?? true;
|
|
210
|
-
const api = () => o.client ?? createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user() });
|
|
242
|
+
const api = () => o.client ?? createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user(), userHash: o.userHash?.() });
|
|
211
243
|
const root = el("div", {
|
|
212
244
|
class: "ckw-root",
|
|
213
245
|
"data-theme": o.theme ?? "auto",
|
|
@@ -223,6 +255,7 @@ var build = (o) => {
|
|
|
223
255
|
o.glow?.slice(0, 2).forEach((c, i) => /^#[0-9a-f]{6}$/i.test(c) && root.style.setProperty(`--ckw-glow${i + 2}`, c));
|
|
224
256
|
(o.container ?? document.body).appendChild(root);
|
|
225
257
|
let open = false;
|
|
258
|
+
let afterClose = null;
|
|
226
259
|
let view = "home";
|
|
227
260
|
let thread = null;
|
|
228
261
|
let loaded = false;
|
|
@@ -268,13 +301,22 @@ var build = (o) => {
|
|
|
268
301
|
const id = lastTeamId(thread);
|
|
269
302
|
if (id) writeSeen(id);
|
|
270
303
|
};
|
|
271
|
-
const
|
|
304
|
+
const letter = (size) => el("span", { class: `ckw-msgr-av${size ? " ckw-msgr-av-sm" : ""}`, "aria-hidden": "true" }, initial);
|
|
305
|
+
const avatar = (size) => {
|
|
306
|
+
if (!o.icon) return letter(size);
|
|
307
|
+
const av = el("span", { class: `ckw-msgr-av ckw-msgr-av-img${size ? " ckw-msgr-av-sm" : ""}`, "aria-hidden": "true" });
|
|
308
|
+
const img = el("img", { src: o.icon, alt: "" });
|
|
309
|
+
img.addEventListener("error", () => av.replaceWith(letter(size)));
|
|
310
|
+
av.append(img);
|
|
311
|
+
return av;
|
|
312
|
+
};
|
|
272
313
|
const logo = el("span", { class: "ckw-msgr-logo", "aria-hidden": "true" });
|
|
273
314
|
if (o.logo) {
|
|
274
315
|
const img = el("img", { src: o.logo, alt: "" });
|
|
275
316
|
img.addEventListener("error", () => logo.replaceChildren(avatar("sm")));
|
|
276
317
|
logo.append(img);
|
|
277
318
|
} else logo.append(avatar("sm"));
|
|
319
|
+
const agentFace = () => o.agentPhoto ? el("img", { class: "ckw-msg-face", src: o.agentPhoto, alt: "" }) : null;
|
|
278
320
|
const sky = el("div", { class: "ckw-msgr-sky", "aria-hidden": "true" });
|
|
279
321
|
const leaving = /* @__PURE__ */ new Map();
|
|
280
322
|
const enter = (node, parent = root) => {
|
|
@@ -326,7 +368,6 @@ var build = (o) => {
|
|
|
326
368
|
const drawPreview = () => {
|
|
327
369
|
const m = unseen.at(-1);
|
|
328
370
|
if (!previewShown() || !m) return leave(prev);
|
|
329
|
-
hideTeaser(true);
|
|
330
371
|
const x = el("button", { type: "button", class: "ckw-msgr-preview-x", "aria-label": "Dismiss" }, icon(I.cross, 14));
|
|
331
372
|
x.addEventListener("click", (e) => {
|
|
332
373
|
e.stopPropagation();
|
|
@@ -347,43 +388,8 @@ var build = (o) => {
|
|
|
347
388
|
prev.replaceChildren(card, x);
|
|
348
389
|
enter(prev);
|
|
349
390
|
};
|
|
350
|
-
const teaser = el("div", { class: "ckw-msgr-teaser", "data-pos": position });
|
|
351
|
-
let teaserTimer;
|
|
352
|
-
const showTeaser = () => {
|
|
353
|
-
clearTimeout(teaserTimer);
|
|
354
|
-
if (open || previewShown() || !launcherOn) return;
|
|
355
|
-
const chat = el("button", { type: "button", class: "ckw-msgr-teaser-b", "data-main": "" }, icon(I.chat), el("span", {}, "Chat"));
|
|
356
|
-
chat.addEventListener("click", () => show("messages"));
|
|
357
|
-
const buttons = [chat];
|
|
358
|
-
if (helpOn && hasArticles) {
|
|
359
|
-
const search = el("button", { type: "button", class: "ckw-msgr-teaser-b" }, icon(I.search), el("span", {}, "Search"));
|
|
360
|
-
search.addEventListener("click", () => show("help"));
|
|
361
|
-
buttons.push(search);
|
|
362
|
-
}
|
|
363
|
-
teaser.replaceChildren(
|
|
364
|
-
el(
|
|
365
|
-
"div",
|
|
366
|
-
{ class: "ckw-msgr-teaser-top" },
|
|
367
|
-
el("span", { class: "ckw-msgr-teaser-t" }, el("b", {}, greeting), el("span", { class: "ckw-msgr-online" }, reply)),
|
|
368
|
-
avatar()
|
|
369
|
-
),
|
|
370
|
-
el("div", { class: "ckw-msgr-teaser-row" }, ...buttons)
|
|
371
|
-
);
|
|
372
|
-
enter(teaser);
|
|
373
|
-
};
|
|
374
|
-
function hideTeaser(now = false) {
|
|
375
|
-
clearTimeout(teaserTimer);
|
|
376
|
-
if (now) return leave(teaser, 140);
|
|
377
|
-
teaserTimer = setTimeout(() => leave(teaser, 140), 260);
|
|
378
|
-
}
|
|
379
|
-
const hoverable = (e) => e.pointerType === "mouse";
|
|
380
|
-
for (const node of [fab, teaser]) {
|
|
381
|
-
node.addEventListener("pointerenter", (e) => hoverable(e) && (node === fab ? showTeaser() : clearTimeout(teaserTimer)));
|
|
382
|
-
node.addEventListener("pointerleave", (e) => hoverable(e) && hideTeaser());
|
|
383
|
-
}
|
|
384
391
|
fab.addEventListener("click", () => {
|
|
385
392
|
chime.unlock();
|
|
386
|
-
hideTeaser(true);
|
|
387
393
|
if (open) close();
|
|
388
394
|
else show(unseen.length ? "messages" : "home");
|
|
389
395
|
});
|
|
@@ -477,7 +483,7 @@ var build = (o) => {
|
|
|
477
483
|
};
|
|
478
484
|
const form = el("form", { class: "ckw-msgr-compose" });
|
|
479
485
|
const err = el("p", { class: "ckw-msgr-error", role: "alert" });
|
|
480
|
-
const email = el("input", { class: "ckw-input", type: "email", inputmode: "email", autocomplete: "email", placeholder: "
|
|
486
|
+
const email = el("input", { class: "ckw-input ckw-msgr-email", type: "email", inputmode: "email", autocomplete: "email", placeholder: "Email for our reply (optional)", "aria-label": "Your email (optional)", maxlength: "200", "data-1p-ignore": "", "data-lpignore": "true", "data-bwignore": "", "data-form-type": "other" });
|
|
481
487
|
const row = el("div", { class: "ckw-msgr-box" });
|
|
482
488
|
const text = el("textarea", { class: "ckw-textarea ckw-msgr-input", rows: "1", placeholder: "Write your message\u2026", "aria-label": "Message", maxlength: "4000" });
|
|
483
489
|
const send = el("button", { type: "submit", class: "ckw-msgr-send", "aria-label": "Send" }, icon(I.up));
|
|
@@ -677,7 +683,7 @@ var build = (o) => {
|
|
|
677
683
|
chip.addEventListener("click", () => go({ article: a.id }));
|
|
678
684
|
li.append(chip);
|
|
679
685
|
}
|
|
680
|
-
li.append(el("span", { class: "ckw-msg-meta" }, `${m.from !== "visitor" ? `${whoLabel[m.from]} \xB7 ` : ""}${isPending ? "Sending\u2026" : timeAgo(m.at)}`));
|
|
686
|
+
li.append(el("span", { class: "ckw-msg-meta" }, m.from === "ai" ? agentFace() : null, `${m.from !== "visitor" ? `${whoLabel[m.from]} \xB7 ` : ""}${isPending ? "Sending\u2026" : timeAgo(m.at)}`));
|
|
681
687
|
return li;
|
|
682
688
|
};
|
|
683
689
|
const articleRow = (a) => {
|
|
@@ -916,7 +922,7 @@ var build = (o) => {
|
|
|
916
922
|
if (needEmail()) {
|
|
917
923
|
if (emailOk()) email.removeAttribute("aria-invalid");
|
|
918
924
|
else email.setAttribute("aria-invalid", "true");
|
|
919
|
-
if (!email.isConnected)
|
|
925
|
+
if (!email.isConnected) row.insertBefore(email, text);
|
|
920
926
|
} else email.remove();
|
|
921
927
|
drawTray();
|
|
922
928
|
send.disabled = !canSend();
|
|
@@ -1046,7 +1052,6 @@ var build = (o) => {
|
|
|
1046
1052
|
view = v === "help" && !helpOn ? "home" : v;
|
|
1047
1053
|
drawn = -1;
|
|
1048
1054
|
previewGone = true;
|
|
1049
|
-
hideTeaser(true);
|
|
1050
1055
|
pop.toggleAttribute("data-still", still);
|
|
1051
1056
|
enter(pop);
|
|
1052
1057
|
if (was) replay(body, "ckw-msgr-enter");
|
|
@@ -1067,6 +1072,9 @@ var build = (o) => {
|
|
|
1067
1072
|
drawFab();
|
|
1068
1073
|
schedule();
|
|
1069
1074
|
if (launcherOn) fab.focus();
|
|
1075
|
+
const fn = afterClose;
|
|
1076
|
+
afterClose = null;
|
|
1077
|
+
if (fn) setTimeout(fn, 220);
|
|
1070
1078
|
}
|
|
1071
1079
|
pop.addEventListener("click", () => amenuOpen() && closeAmenu());
|
|
1072
1080
|
const onKey = (e) => {
|
|
@@ -1088,9 +1096,12 @@ var build = (o) => {
|
|
|
1088
1096
|
open: (v) => show(v ?? "home"),
|
|
1089
1097
|
close,
|
|
1090
1098
|
toggle: () => open ? close() : show(),
|
|
1099
|
+
isOpen: () => open,
|
|
1100
|
+
onClose: (fn) => {
|
|
1101
|
+
afterClose = fn;
|
|
1102
|
+
},
|
|
1091
1103
|
destroy: () => {
|
|
1092
1104
|
clearTimeout(poll);
|
|
1093
|
-
clearTimeout(teaserTimer);
|
|
1094
1105
|
for (const t of leaving.values()) clearTimeout(t);
|
|
1095
1106
|
ctrl?.abort();
|
|
1096
1107
|
for (const p of picked) forget(p);
|