@mrrocket/sdk 0.16.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.
@@ -51,7 +51,7 @@ module.exports = __toCommonJS(native_exports);
51
51
  var import_react3 = require("react");
52
52
 
53
53
  // src/core.ts
54
- var SDK_VERSION = "0.16.0";
54
+ var SDK_VERSION = "0.17.0";
55
55
  var propOf = (person, name) => {
56
56
  const want = name.trim().toLowerCase();
57
57
  for (const [k, v] of Object.entries(person)) if (k.toLowerCase() === want) return v;
@@ -242,9 +242,9 @@ var call = async (url, init, signal) => {
242
242
  };
243
243
  var createApi = (c) => {
244
244
  const base = `${c.host}/api/sdk`;
245
- const who = { key: c.apiKey, distinctId: c.distinctId, user: c.user, userHash: c.userHash };
245
+ const who2 = { key: c.apiKey, distinctId: c.distinctId, user: c.user, userHash: c.userHash };
246
246
  const me = { key: c.apiKey, distinctId: c.distinctId, userHash: c.userHash };
247
- const post = (path, body, signal) => call(`${base}${path}`, { method: "POST", body: JSON.stringify({ ...who, ...body }) }, signal);
247
+ const post = (path, body, signal) => call(`${base}${path}`, { method: "POST", body: JSON.stringify({ ...who2, ...body }) }, signal);
248
248
  return {
249
249
  list: (o, signal) => call(`${base}/feedback?${qs({ ...me, board: o.board, sort: o.sort, q: o.q })}`, void 0, signal),
250
250
  post: (id, signal) => call(`${base}/feedback/${encodeURIComponent(id)}?${qs(me)}`, void 0, signal),
@@ -358,6 +358,25 @@ var matchesTrigger = (trigger, event) => {
358
358
  return t === e || SIGNUP.has(t) && SIGNUP.has(e);
359
359
  };
360
360
  var startsOnLoad = (trigger) => /^(first (launch|visit|open|session|login|sign ?in|app open)|app (opened|launched)|on load|every visit|always)?$/i.test(trigger.trim());
361
+ var isPageTrigger = (trigger) => trigger.trim().startsWith("/");
362
+ var manual = (trigger) => eventSlug(trigger) === "from_a_checklist";
363
+ var videoEmbed = (url) => {
364
+ const u = (url ?? "").trim();
365
+ if (!/^https?:\/\//i.test(u)) return null;
366
+ let m = u.match(/^https?:\/\/(?:www\.|m\.)?(?:youtube\.com\/(?:watch\?(?:.*&)?v=|embed\/|shorts\/|live\/)|youtu\.be\/|youtube-nocookie\.com\/embed\/)([\w-]{6,20})/i);
367
+ if (m) return { kind: "iframe", src: `https://www.youtube-nocookie.com/embed/${m[1]}?rel=0` };
368
+ m = u.match(/^https?:\/\/(?:www\.|player\.)?vimeo\.com\/(?:video\/)?(\d{4,12})/i);
369
+ if (m) return { kind: "iframe", src: `https://player.vimeo.com/video/${m[1]}?dnt=1` };
370
+ m = u.match(/^https?:\/\/(?:www\.)?loom\.com\/(?:share|embed)\/([\w-]{8,64})/i);
371
+ if (m) return { kind: "iframe", src: `https://www.loom.com/embed/${m[1]}` };
372
+ if (/\.(mp4|webm|mov|m4v)(\?|#|$)/i.test(u) || /\/media\/uploads\//.test(u)) return { kind: "file", src: u };
373
+ return null;
374
+ };
375
+ var mediaOf = (step) => {
376
+ const m = step.media;
377
+ if (!m || m.kind !== "image" && m.kind !== "video" || !/^https?:\/\//i.test(m.url ?? "")) return void 0;
378
+ return m.kind === "video" && !videoEmbed(m.url) ? void 0 : m;
379
+ };
361
380
  var runId = () => `cf_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
362
381
  var discounted = (amount, percent) => Math.round(amount * (1 - percent / 100) * 100) / 100;
363
382
  var money = (amount, currency) => {
@@ -405,6 +424,7 @@ var createFlows = (env) => {
405
424
  const seenEvents = /* @__PURE__ */ new Set();
406
425
  const now = () => env.now?.() ?? Date.now();
407
426
  let timer = null;
427
+ let returnTo = null;
408
428
  const flows = () => config?.onboarding ?? [];
409
429
  const flowById = (id) => id ? flows().find((f) => f.id === id) : void 0;
410
430
  const prog = (id) => {
@@ -542,7 +562,14 @@ var createFlows = (env) => {
542
562
  shown.add(`s:${i.id}`);
543
563
  env.track(ONBOARDING_EVENT, { flow: flow.id, step: i.id, kind: "checklist", action: "shown" });
544
564
  }
545
- return { type: "checklist", flow, items: items.map((s) => ({ step: s, done: p.done.has(s.id) })) };
565
+ return {
566
+ type: "checklist",
567
+ flow,
568
+ items: items.map((s) => {
569
+ const tour = s.startsTour && s.startsTour !== flow.id ? flowById(s.startsTour) : void 0;
570
+ return { step: s, done: p.done.has(s.id), ...tour && nodesOf(tour).length ? { tour } : {} };
571
+ })
572
+ };
546
573
  }
547
574
  if (!shown.has(`s:${step.id}`)) {
548
575
  shown.add(`s:${step.id}`);
@@ -576,7 +603,28 @@ var createFlows = (env) => {
576
603
  }
577
604
  const ob = onboardingView();
578
605
  if (ob) return ob;
579
- if (active && !holding) active = null;
606
+ if (active && !holding) {
607
+ const back = returnTo;
608
+ const ended = active;
609
+ returnTo = null;
610
+ active = null;
611
+ const list = back ? flowById(back.flow) : void 0;
612
+ if (back && list) {
613
+ const item = stepsIn(nodesOf(list)).find((s) => s.id === back.step);
614
+ const p = prog(list.id);
615
+ if (item && !item.event && !progress.get(ended)?.dismissed && !p.done.has(item.id)) {
616
+ markDone(p, item.id);
617
+ record({ flow: list.id, step: item.id, kind: "checklist", action: "completed" });
618
+ }
619
+ active = list.id;
620
+ const again = onboardingView();
621
+ if (again) return again;
622
+ if (!holding) active = null;
623
+ } else if (known) {
624
+ const after = flowById(ended)?.trigger;
625
+ Promise.resolve().then(() => autoStart(after));
626
+ }
627
+ }
580
628
  const m = messages.find((x) => !handled.has(x.id));
581
629
  return m ? { type: "message", message: m } : null;
582
630
  };
@@ -601,10 +649,15 @@ var createFlows = (env) => {
601
649
  emit();
602
650
  return true;
603
651
  };
604
- const autoStart = () => {
652
+ const allowed = (f) => f.audience !== "signed_in" || !!env.personId();
653
+ const autoStart = (after) => {
605
654
  if (!auto || active || !known) return;
606
655
  if (!env.personId() && !env.storage?.()) return;
607
- const next = flows().find((f) => startsOnLoad(f.trigger) && nodesOf(f).length && !finished(f));
656
+ const path = env.path?.();
657
+ const same2 = after && !manual(after) ? eventSlug(after) : "";
658
+ const next = flows().find(
659
+ (f) => (isPageTrigger(f.trigger) ? path !== void 0 && pageMatches(f.trigger, path) : startsOnLoad(f.trigger) || !!same2 && eventSlug(f.trigger) === same2) && allowed(f) && nodesOf(f).length && !finished(f)
660
+ );
608
661
  if (next) start(next);
609
662
  };
610
663
  const refresh = () => {
@@ -614,6 +667,7 @@ var createFlows = (env) => {
614
667
  seenEvents.clear();
615
668
  handled.clear();
616
669
  active = null;
670
+ returnTo = null;
617
671
  loadedFor = void 0;
618
672
  }
619
673
  progressFor = pid;
@@ -652,9 +706,9 @@ var createFlows = (env) => {
652
706
  };
653
707
  const offerAt = (c) => c.round > 1 ? { round: 2 } : c.rule >= 0 ? { rule: c.rule } : {};
654
708
  const toOffer = (c) => {
655
- const who = { answer: c.answer, plan: c.options.plan, months: monthsSince(c.options.customerSince, env.now?.()) };
709
+ const who2 = { answer: c.answer, plan: c.options.plan, months: monthsSince(c.options.customerSince, env.now?.()) };
656
710
  const rules = c.flow.rules?.[c.reason] ?? [];
657
- c.rule = rules.findIndex((r) => ruleMatches(r, who));
711
+ c.rule = rules.findIndex((r) => ruleMatches(r, who2));
658
712
  c.offer = c.rule < 0 ? c.flow.offers[c.reason] : rules[c.rule].offer ?? void 0;
659
713
  c.round = 1;
660
714
  c.screen = c.offer ? "offer" : "confirm";
@@ -723,6 +777,7 @@ var createFlows = (env) => {
723
777
  },
724
778
  refresh,
725
779
  onEvent: (name) => {
780
+ if (name === "$pageview") autoStart();
726
781
  if (!name || name.startsWith("$")) return;
727
782
  const slug = eventSlug(name);
728
783
  const fresh = !!slug && !seenEvents.has(slug);
@@ -743,12 +798,12 @@ var createFlows = (env) => {
743
798
  emit();
744
799
  } else if (fresh) save();
745
800
  if (!auto || !env.personId() && !env.storage?.()) return;
746
- const next = flows().find((f) => nodesOf(f).length && matchesTrigger(f.trigger, name) && !finished(f));
801
+ const next = flows().find((f) => nodesOf(f).length && !manual(f.trigger) && matchesTrigger(f.trigger, name) && allowed(f) && !finished(f));
747
802
  if (next) start(next);
748
803
  },
749
804
  openCancelFlow,
750
805
  startOnboarding: (id) => {
751
- const f = id ? flowById(id) : flows().find((x) => nodesOf(x).length && !finished(x));
806
+ const f = id ? flowById(id) : flows().find((x) => nodesOf(x).length && !manual(x.trigger) && !finished(x));
752
807
  if (!f || !nodesOf(f).length) return false;
753
808
  const p = prog(f.id);
754
809
  p.dismissed = false;
@@ -844,6 +899,8 @@ var createFlows = (env) => {
844
899
  env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: v.step.id, kind: v.step.kind, action: "completed" });
845
900
  save();
846
901
  emit();
902
+ const url = v.step.kind === "modal" ? safeUrl(v.step.url) : void 0;
903
+ if (url) env.openUrl?.(url);
847
904
  },
848
905
  check: (stepId) => {
849
906
  const v = onboardingView();
@@ -860,9 +917,26 @@ var createFlows = (env) => {
860
917
  if (!v || v.type !== "step" && v.type !== "checklist") return;
861
918
  prog(v.flow.id).dismissed = true;
862
919
  env.track(ONBOARDING_EVENT, { flow: v.flow.id, ...v.type === "step" ? { step: v.step.id } : {}, action: "dismissed" });
863
- active = null;
920
+ active = returnTo && returnTo.flow !== v.flow.id && flowById(returnTo.flow) ? returnTo.flow : null;
921
+ returnTo = null;
922
+ save();
923
+ emit();
924
+ },
925
+ startTour: (stepId) => {
926
+ const v = onboardingView();
927
+ if (v?.type !== "checklist") return false;
928
+ const tour = v.items.find((i) => i.step.id === stepId)?.tour;
929
+ if (!tour) return false;
930
+ const p = prog(tour.id);
931
+ p.done.clear();
932
+ p.at.clear();
933
+ p.dismissed = false;
934
+ returnTo = { flow: v.flow.id, step: stepId };
935
+ active = tour.id;
936
+ env.track(ONBOARDING_EVENT, { flow: tour.id, action: "started", from: v.flow.id });
864
937
  save();
865
938
  emit();
939
+ return true;
866
940
  }
867
941
  },
868
942
  message: {
@@ -1474,7 +1548,7 @@ var createClient = (options, deps) => {
1474
1548
  if (errorsSeen.has(mark)) return;
1475
1549
  errorsSeen.add(mark);
1476
1550
  errorsSent++;
1477
- const who = sendId();
1551
+ const who2 = sendId();
1478
1552
  errorQueue.push({
1479
1553
  ...d,
1480
1554
  mechanism,
@@ -1483,7 +1557,7 @@ var createClient = (options, deps) => {
1483
1557
  ts: now(),
1484
1558
  crumbs: crumbs.slice(),
1485
1559
  ...release ? { release } : {},
1486
- ...who ? { distinctId: who } : {},
1560
+ ...who2 ? { distinctId: who2 } : {},
1487
1561
  ...session ? { sessionId: session.id } : {}
1488
1562
  });
1489
1563
  recorder?.mark({ kind: "error", path: currentScreen ?? "/", label: clip2(d.message, 120) });
@@ -1598,20 +1672,20 @@ var createClient = (options, deps) => {
1598
1672
  await loadedNow();
1599
1673
  if (!apiKey || consent === "off") return { status: "error", reason: !apiKey ? "No public key." : "The consent is off." };
1600
1674
  if (!identified) return { status: "not-signed-in" };
1601
- const who = identified;
1602
- const userHash = hashOf(who);
1675
+ const who2 = identified;
1676
+ const userHash = hashOf(who2);
1603
1677
  try {
1604
1678
  const permission = await deps.push.permission(o.ask !== false);
1605
1679
  if (permission !== "granted") return { status: permission === "denied" ? "denied" : "not-asked" };
1606
1680
  const token = await deps.push.token(o.projectId);
1607
1681
  if (!token) return { status: "unavailable", reason: "This device has no push token (a simulator, or no EAS project id)." };
1608
- const status = await post("/api/sdk/push", JSON.stringify({ key: apiKey, distinctId: who, userHash, platform: "expo", token, app: context }));
1682
+ const status = await post("/api/sdk/push", JSON.stringify({ key: apiKey, distinctId: who2, userHash, platform: "expo", token, app: context }));
1609
1683
  if (status < 200 || status >= 300) {
1610
1684
  warn(`Push registration was rejected with ${status || "no answer"}. Check the public key and the host.`);
1611
1685
  return { status: "error", reason: `MRRocket answered ${status || "nothing"}.` };
1612
1686
  }
1613
1687
  pushToken = token;
1614
- pushFor = who;
1688
+ pushFor = who2;
1615
1689
  pushHash = userHash;
1616
1690
  listenForOpens();
1617
1691
  debug("Registered for push.");
@@ -2165,6 +2239,22 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
2165
2239
  ];
2166
2240
  return sheet([top, ...body, error], flows.cancel.close);
2167
2241
  }
2242
+ const media = (s) => {
2243
+ const m2 = mediaOf(s);
2244
+ if (!m2) return null;
2245
+ if (m2.kind === "image")
2246
+ return RN.Image ? (0, import_react.createElement)(RN.Image, {
2247
+ key: "media",
2248
+ source: { uri: m2.url },
2249
+ accessibilityLabel: m2.alt,
2250
+ resizeMode: "cover",
2251
+ style: { width: "100%", aspectRatio: 16 / 9, borderRadius: 10, backgroundColor: p.soft }
2252
+ }) : null;
2253
+ const v2 = videoEmbed(m2.url);
2254
+ const open = v2?.kind === "file" ? v2.src : m2.url;
2255
+ return RN.Linking ? btn("\u25B6 Watch the video", "secondary", () => void RN.Linking?.openURL(open).catch(() => {
2256
+ })) : null;
2257
+ };
2168
2258
  if (v.type === "step")
2169
2259
  return sheet(
2170
2260
  [
@@ -2174,6 +2264,7 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
2174
2264
  v.total > 1 ? muted(`Step ${v.index + 1} of ${v.total}`) : null,
2175
2265
  close("Close the tour", flows.onboarding.dismiss)
2176
2266
  ),
2267
+ media(v.step),
2177
2268
  title(v.step.title),
2178
2269
  v.step.body ? muted(v.step.body, { fontSize: 15 }) : null,
2179
2270
  btn(v.step.button || (v.last ? "Done" : "Next"), "primary", flows.onboarding.next)
@@ -2194,13 +2285,14 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
2194
2285
  ),
2195
2286
  muted(`${done} of ${v.items.length} done`),
2196
2287
  ...v.items.map(
2197
- ({ step, done: d }) => (0, import_react.createElement)(
2288
+ ({ step, done: d, tour }) => (0, import_react.createElement)(
2198
2289
  RN.Pressable,
2199
2290
  {
2200
2291
  key: step.id,
2201
- disabled: d || !!step.event,
2202
- onPress: () => flows.onboarding.check(step.id),
2203
- accessibilityRole: "checkbox",
2292
+ // 0.17.0: an item that starts a tour opens it; finishing the tour ticks it.
2293
+ disabled: d || !!step.event && !tour,
2294
+ onPress: () => tour ? flows.onboarding.startTour(step.id) : flows.onboarding.check(step.id),
2295
+ accessibilityRole: tour && !d ? "button" : "checkbox",
2204
2296
  accessibilityState: { checked: d },
2205
2297
  style: { flexDirection: "row", gap: 10, alignItems: "flex-start", paddingVertical: 6 }
2206
2298
  },
@@ -2672,7 +2764,7 @@ var SurveySheet = ({ survey, api, p, onDone }) => {
2672
2764
  var MRRocketSurveys = ({ client, appearance }) => {
2673
2765
  const p = usePalette(appearance);
2674
2766
  const [survey, setSurvey] = (0, import_react2.useState)(null);
2675
- const [who, setWho] = (0, import_react2.useState)(() => client.getDistinctId());
2767
+ const [who2, setWho] = (0, import_react2.useState)(() => client.getDistinctId());
2676
2768
  (0, import_react2.useEffect)(() => client.subscribe(() => setWho(client.getDistinctId())), [client]);
2677
2769
  (0, import_react2.useEffect)(() => {
2678
2770
  let stop = false;
@@ -2693,7 +2785,7 @@ var MRRocketSurveys = ({ client, appearance }) => {
2693
2785
  clearTimeout(timer);
2694
2786
  ctrl.abort();
2695
2787
  };
2696
- }, [client, who]);
2788
+ }, [client, who2]);
2697
2789
  const done = (0, import_react2.useCallback)(() => {
2698
2790
  setSurvey((cur) => {
2699
2791
  if (cur) client.markSurveyDone(cur.s.id);
@@ -2815,6 +2907,7 @@ var POLL_IDLE_MS = 3e4;
2815
2907
  var WAITING_FOR_MS = 10 * 6e4;
2816
2908
  var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
2817
2909
  var whoLabel = { visitor: "You", team: "Team", ai: "AI agent", auto: "Team" };
2910
+ var who = (from, agentName) => from === "ai" && agentName?.trim() || whoLabel[from];
2818
2911
  var msgView = "home";
2819
2912
  var messengerOpen = opener();
2820
2913
  var openAt = (v = "home") => {
@@ -3199,7 +3292,7 @@ var MessengerSheet = ({
3199
3292
  k.text(`\u{1F4C4} ${a.title}`, { fontSize: 13 })
3200
3293
  )
3201
3294
  ),
3202
- m.at ? k.muted(`${mine ? "" : `${whoLabel[m.from]} \xB7 `}${isPending ? "Sending\u2026" : timeAgo(m.at)}`, { fontSize: 11, textAlign: mine ? "right" : "left", paddingHorizontal: 6 }) : null
3295
+ m.at ? k.muted(`${mine ? "" : `${who(m.from, o.agentName)} \xB7 `}${isPending ? "Sending\u2026" : timeAgo(m.at)}`, { fontSize: 11, textAlign: mine ? "right" : "left", paddingHorizontal: 6 }) : null
3203
3296
  );
3204
3297
  };
3205
3298
  const row = (a) => (0, import_react2.createElement)(
@@ -3257,7 +3350,7 @@ var MessengerSheet = ({
3257
3350
  RN3.View,
3258
3351
  { key: "r", style: { flexDirection: "row", alignItems: "center", gap: 10 } },
3259
3352
  title ? teamMark(title, alpha(p.accent, 0.16), p.accent, 26) : null,
3260
- (0, import_react2.createElement)(RN3.View, { style: { flex: 1, gap: 1 } }, (0, import_react2.createElement)(RN3.Text, { numberOfLines: 1, style: { color: hu.fg, fontSize: 14, fontWeight: "500" } }, last.body || (last.attachments?.length ? `Sent ${last.attachments.length === 1 ? last.attachments[0].name : `${last.attachments.length} files`}` : "")), k.muted(`${last.from === "visitor" ? "You" : whoLabel[last.from]} \xB7 ${timeAgo(last.at)}`, { fontSize: 11.5 })),
3353
+ (0, import_react2.createElement)(RN3.View, { style: { flex: 1, gap: 1 } }, (0, import_react2.createElement)(RN3.Text, { numberOfLines: 1, style: { color: hu.fg, fontSize: 14, fontWeight: "500" } }, last.body || (last.attachments?.length ? `Sent ${last.attachments.length === 1 ? last.attachments[0].name : `${last.attachments.length} files`}` : "")), k.muted(`${last.from === "visitor" ? "You" : who(last.from, o.agentName)} \xB7 ${timeAgo(last.at)}`, { fontSize: 11.5 })),
3261
3354
  chat.unseen.length ? (0, import_react2.createElement)(RN3.View, { style: { width: 8, height: 8, borderRadius: 4, backgroundColor: p.danger } }) : glyph("next", p.muted, 14)
3262
3355
  )
3263
3356
  ], { paddingVertical: 10, paddingHorizontal: 12 })
@@ -3292,7 +3385,6 @@ var MessengerSheet = ({
3292
3385
  RN3.View,
3293
3386
  { style: { paddingHorizontal: 12, paddingTop: 8, paddingBottom: 6, gap: 8 } },
3294
3387
  chat.error ? k.text(chat.error, { color: p.danger, fontSize: 12 }) : null,
3295
- needEmail ? k.field({ value: email, onChange: setEmail, placeholder: "Your email (optional), so we can follow up", email: true, max: 200, style: { borderWidth: emailOk ? 0 : 1, borderColor: p.danger, borderRadius: r.field, paddingHorizontal: 16, backgroundColor: hu.surface, ...surf } }) : null,
3296
3388
  // Photos picked for the next message, each with a way to take it out again.
3297
3389
  photos.length ? (0, import_react2.createElement)(
3298
3390
  RN3.View,
@@ -3320,6 +3412,15 @@ var MessengerSheet = ({
3320
3412
  (0, import_react2.createElement)(
3321
3413
  RN3.View,
3322
3414
  { style: { gap: 2, borderRadius: 20, paddingTop: 10, paddingBottom: 6, paddingRight: 6, paddingLeft: 16, backgroundColor: hu.surface, ...surf } },
3415
+ // The optional email: the box's first line, under a hairline the message follows.
3416
+ needEmail ? k.field({
3417
+ value: email,
3418
+ onChange: setEmail,
3419
+ placeholder: "Email for our reply (optional)",
3420
+ email: true,
3421
+ max: 200,
3422
+ style: { minHeight: 0, marginRight: 10, marginBottom: 4, paddingHorizontal: 0, paddingTop: 0, paddingBottom: 8, borderWidth: 0, borderRadius: 0, borderBottomWidth: 1, borderBottomColor: emailOk ? p.line : p.danger, backgroundColor: "transparent", fontSize: 13.5 }
3423
+ }) : null,
3323
3424
  k.field({ value: body, onChange: setBody, placeholder: "Write a message\u2026", multiline: true, max: 4e3, style: { minHeight: 28, maxHeight: 120, borderWidth: 0, paddingHorizontal: 0, paddingVertical: 4, backgroundColor: "transparent" } }),
3324
3425
  (0, import_react2.createElement)(
3325
3426
  RN3.View,
@@ -3371,11 +3472,13 @@ var MessengerSheet = ({
3371
3472
  key: v,
3372
3473
  onPress: () => setView(v),
3373
3474
  accessibilityRole: "tab",
3475
+ accessibilityLabel: name,
3374
3476
  accessibilityState: { selected: on },
3375
- style: { flex: 1, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6, height: 36, borderRadius: 18, ...on ? { backgroundColor: hu.segment, ...segLift } : {} }
3477
+ // Only the open tab carries its name; the others are icons, so the bar fits a narrow phone.
3478
+ style: { ...on ? { flex: 1 } : { width: 48 }, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6, height: 36, borderRadius: 18, ...on ? { backgroundColor: hu.segment, ...segLift } : {} }
3376
3479
  },
3377
3480
  glyph(icon, on ? hu.fg : hu.muted, 17),
3378
- k.text(name, { fontSize: 13.5, fontWeight: "500", color: on ? hu.fg : hu.muted }),
3481
+ on ? k.text(name, { fontSize: 13.5, fontWeight: "500", color: hu.fg }) : null,
3379
3482
  badge ? (0, import_react2.createElement)(RN3.View, { style: { position: "absolute", top: 7, right: 12, width: 8, height: 8, borderRadius: 4, backgroundColor: p.danger } }) : null
3380
3483
  );
3381
3484
  };
@@ -3389,7 +3492,7 @@ var MessengerSheet = ({
3389
3492
  const head = (0, import_react2.createElement)(
3390
3493
  RN3.View,
3391
3494
  { key: "head", style: { flexDirection: "row", alignItems: "center", gap: 8, paddingLeft: 12, paddingRight: 12, paddingTop: 12, paddingBottom: 6, backgroundColor: ground } },
3392
- typeof view !== "string" ? back("help", "All articles") : view === "messages" ? back("home", "Back to home") : view === "home" && (o.logo || title) ? o.logo ? (0, import_react2.createElement)(RN3.Image, { key: "logo", source: { uri: o.logo }, accessibilityIgnoresInvertColors: true, style: { width: 28, height: 28, borderRadius: 8, marginLeft: 4 } }) : teamMark(title, alpha(p.accent, 0.16), p.accent, 28) : null,
3495
+ typeof view !== "string" ? back("help", "All articles") : view === "messages" ? back("home", "Back to home") : view === "home" && (o.logo || title) ? o.logo ? (0, import_react2.createElement)(RN3.Image, { key: "logo", source: { uri: o.logo }, accessibilityIgnoresInvertColors: true, resizeMode: "contain", style: { height: 28, aspectRatio: 1, maxWidth: 132, borderRadius: 8, marginLeft: 4 } }) : teamMark(title, alpha(p.accent, 0.16), p.accent, 28) : null,
3393
3496
  // In the chat: who answers, in the middle.
3394
3497
  view === "messages" && title ? (0, import_react2.createElement)(
3395
3498
  RN3.View,
@@ -3453,6 +3556,7 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
3453
3556
  corners: look.corners,
3454
3557
  header: look.header,
3455
3558
  logo: look.logo,
3559
+ agentName: look.agentName,
3456
3560
  ...defined
3457
3561
  } : given;
3458
3562
  const p = usePalette({ theme: appearance?.theme ?? look?.theme, accent: appearance?.accent ?? look?.accent });
@@ -3542,7 +3646,7 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
3542
3646
  elevation: 6
3543
3647
  }
3544
3648
  },
3545
- k.muted(`${whoLabel[banner.from]}${unseen > 1 ? ` \xB7 ${unseen} new` : ""}`, { fontWeight: "600", fontSize: 12 }),
3649
+ k.muted(`${who(banner.from, options.agentName)}${unseen > 1 ? ` \xB7 ${unseen} new` : ""}`, { fontWeight: "600", fontSize: 12 }),
3546
3650
  (0, import_react2.createElement)(RN3.Text, { numberOfLines: 3, style: { color: p.fg, fontSize: 15, lineHeight: 20 } }, banner.body)
3547
3651
  ) : null;
3548
3652
  if (!launcher && !toast && !open) return null;