@guidelytech/sdk-core 0.5.0 → 0.6.1

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 CHANGED
@@ -33,6 +33,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
33
33
  var index_exports = {};
34
34
  __export(index_exports, {
35
35
  AUTHORING_PARAM: () => AUTHORING_PARAM,
36
+ CAPTURE_PARAM: () => import_runtime2.CAPTURE_PARAM,
36
37
  DEFAULT_API_URL: () => DEFAULT_API_URL,
37
38
  EventQueue: () => EventQueue,
38
39
  Guidely: () => Guidely,
@@ -56,9 +57,9 @@ __export(index_exports, {
56
57
  module.exports = __toCommonJS(index_exports);
57
58
 
58
59
  // src/client.ts
59
- var import_runtime11 = require("@guidelytech/shared/runtime");
60
- var import_guide_runtime3 = require("@guidelytech/guide-runtime");
60
+ var import_runtime13 = require("@guidelytech/shared/runtime");
61
61
  var import_guide_runtime4 = require("@guidelytech/guide-runtime");
62
+ var import_guide_runtime5 = require("@guidelytech/guide-runtime");
62
63
 
63
64
  // src/authoring.ts
64
65
  var import_guide_runtime = require("@guidelytech/guide-runtime");
@@ -207,8 +208,13 @@ var KEYS = {
207
208
  session: "guidely:session",
208
209
  active: "guidely:active",
209
210
  authoring: "guidely:authoring",
211
+ /** How-to capture session marker ({ token, … }) and its not-yet-uploaded steps. */
212
+ capture: "guidely:capture",
213
+ capturePending: "guidely:capture:pending",
210
214
  /** Messenger conversations this browser can read: [{ id, token }]. */
211
- conversations: (key) => `guidely:conversations:${key}`
215
+ conversations: (key) => `guidely:conversations:${key}`,
216
+ /** Announcement ids opened in the messenger's News tab. */
217
+ newsSeen: (key) => `guidely:news:${key}`
212
218
  };
213
219
 
214
220
  // src/authoring.ts
@@ -440,6 +446,43 @@ var AuthoringBridge = class {
440
446
  }
441
447
  };
442
448
 
449
+ // src/capture-token.ts
450
+ var import_runtime2 = require("@guidelytech/shared/runtime");
451
+ function takeCaptureToken(sessionStore) {
452
+ if (typeof window === "undefined") return null;
453
+ let token = null;
454
+ let authoringLink = false;
455
+ try {
456
+ const url = new URL(window.location.href);
457
+ token = url.searchParams.get(import_runtime2.CAPTURE_PARAM);
458
+ authoringLink = url.searchParams.has(AUTHORING_PARAM);
459
+ if (token) {
460
+ url.searchParams.delete(import_runtime2.CAPTURE_PARAM);
461
+ window.history.replaceState(window.history.state, "", url.toString());
462
+ }
463
+ } catch {
464
+ token = null;
465
+ }
466
+ const saved = readJson(sessionStore, KEYS.capture, null);
467
+ let marker = null;
468
+ if (token) marker = saved?.token === token ? saved : { token };
469
+ else if (saved?.token && !authoringLink) marker = saved;
470
+ if (!marker) {
471
+ if (saved) {
472
+ sessionStore.remove(KEYS.capture);
473
+ sessionStore.remove(KEYS.capturePending);
474
+ }
475
+ return null;
476
+ }
477
+ if (token && saved?.token !== token) sessionStore.remove(KEYS.capturePending);
478
+ writeJson(sessionStore, KEYS.capture, marker);
479
+ sessionStore.remove(KEYS.authoring);
480
+ return marker;
481
+ }
482
+
483
+ // src/load-capture.ts
484
+ var loadCapture = async () => (await import("./capture.cjs")).capture;
485
+
443
486
  // src/autocapture.ts
444
487
  var import_guide_runtime2 = require("@guidelytech/guide-runtime");
445
488
  var INTERACTIVE_SELECTOR = "a,button,input[type=button],input[type=submit],input[type=reset],input[type=checkbox],input[type=radio],select,summary,label,[role=button],[role=link],[role=tab],[role=menuitem],[role=checkbox],[role=switch],[role=option],[onclick],[data-guidely-track]";
@@ -701,7 +744,7 @@ var HeatmapBuffer = class {
701
744
  };
702
745
 
703
746
  // src/errors.ts
704
- var import_runtime4 = require("@guidelytech/shared/runtime");
747
+ var import_runtime5 = require("@guidelytech/shared/runtime");
705
748
  var MAX_FRAMES_BYTES = 6e3;
706
749
  function fitFrames(frames) {
707
750
  const out = frames.slice(0, 30);
@@ -722,7 +765,7 @@ function exceptionFromError(error, source, handled, fallbackType = "Error") {
722
765
  return {
723
766
  type: isError && e.name || fallbackType,
724
767
  message: (isError ? e.message : describe(error)).slice(0, 1e3),
725
- frames: isError ? fitFrames((0, import_runtime4.parseStack)(e.stack)) : [],
768
+ frames: isError ? fitFrames((0, import_runtime5.parseStack)(e.stack)) : [],
726
769
  source,
727
770
  handled
728
771
  };
@@ -869,7 +912,8 @@ var Api = class {
869
912
  const f = this.fetcher;
870
913
  if (!f) throw new Error("fetch is not available");
871
914
  const headers = { ...options.headers, "X-Guidely-Key": this.key, Accept: "application/json" };
872
- if (options.body !== void 0) headers["Content-Type"] = "application/json";
915
+ const form = typeof FormData !== "undefined" && options.body instanceof FormData;
916
+ if (options.body !== void 0 && !form) headers["Content-Type"] = "application/json";
873
917
  if (options.etag) headers["If-None-Match"] = options.etag;
874
918
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
875
919
  const timer = ac ? setTimeout(() => ac.abort(), options.timeoutMs ?? 1e4) : null;
@@ -877,7 +921,7 @@ var Api = class {
877
921
  const res = await f(this.url(path, options.params), {
878
922
  method,
879
923
  headers,
880
- body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
924
+ body: options.body === void 0 ? void 0 : form ? options.body : JSON.stringify(options.body),
881
925
  keepalive: options.keepalive,
882
926
  signal: ac?.signal,
883
927
  credentials: "omit",
@@ -902,6 +946,10 @@ var Api = class {
902
946
  post(path, body, options) {
903
947
  return this.request("POST", path, { body, ...options });
904
948
  }
949
+ /** Multipart POST (file uploads). No Content-Type header: the browser adds it with the boundary. */
950
+ postForm(path, form, options) {
951
+ return this.request("POST", path, { body: form, ...options });
952
+ }
905
953
  /**
906
954
  * POST that may answer with server-sent events. Each event is passed to `onEvent`; a JSON answer is
907
955
  * returned instead. No timeout: Scout replies can take a while and the server keeps the stream alive.
@@ -944,10 +992,10 @@ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
944
992
  function backoffMs(attempt, baseMs = 1e3, maxMs = 3e4) {
945
993
  return Math.min(maxMs, baseMs * 2 ** Math.max(0, attempt));
946
994
  }
947
- async function postWithRetry(api, path, body, attempts = 3, baseMs = 500) {
995
+ async function withRetry(send, attempts = 3, baseMs = 500) {
948
996
  for (let i = 0; i < attempts; i++) {
949
997
  try {
950
- const res = await api.post(path, body);
998
+ const res = await send();
951
999
  if (res.ok || res.status >= 400 && res.status < 500 && res.status !== 429) return res;
952
1000
  } catch {
953
1001
  }
@@ -955,6 +1003,9 @@ async function postWithRetry(api, path, body, attempts = 3, baseMs = 500) {
955
1003
  }
956
1004
  return null;
957
1005
  }
1006
+ function postWithRetry(api, path, body, attempts = 3, baseMs = 500) {
1007
+ return withRetry(() => api.post(path, body), attempts, baseMs);
1008
+ }
958
1009
  async function readEventStream(body, onEvent) {
959
1010
  const reader = body.getReader();
960
1011
  const decoder = new TextDecoder();
@@ -992,6 +1043,15 @@ async function readEventStream(body, onEvent) {
992
1043
  // src/messenger-api.ts
993
1044
  var MAX_STORED = 50;
994
1045
  var TOKEN_HEADER = "X-Guidely-Conversation";
1046
+ function pagePath(url) {
1047
+ if (!url) return void 0;
1048
+ try {
1049
+ const u = new URL(url);
1050
+ return (u.pathname + (/^#!?\//.test(u.hash) ? u.hash.split("?")[0] : "")).slice(0, 2e3);
1051
+ } catch {
1052
+ return void 0;
1053
+ }
1054
+ }
995
1055
  function storedConversations(store, projectId) {
996
1056
  const list = readJson(store, KEYS.conversations(projectId), []);
997
1057
  return Array.isArray(list) ? list.filter((c) => c && typeof c.id === "string" && typeof c.token === "string") : [];
@@ -1066,7 +1126,7 @@ function createMessengerTransport(opts) {
1066
1126
  return exchange("/conversations", { anonymousId: opts.anonymousId(), userId: opts.userId(), message: text, pageUrl: opts.pageUrl() }, {}, h, (r) => remember(r.conversation.id, r.token));
1067
1127
  },
1068
1128
  send(id, text, h) {
1069
- return exchange(`/conversations/${encodeURIComponent(id)}/messages`, { message: text }, { [TOKEN_HEADER]: tokenFor(id) }, h);
1129
+ return exchange(`/conversations/${encodeURIComponent(id)}/messages`, { message: text, pageUrl: opts.pageUrl() }, { [TOKEN_HEADER]: tokenFor(id) }, h);
1070
1130
  },
1071
1131
  async handoff(id) {
1072
1132
  const res = await api.post(`/conversations/${encodeURIComponent(id)}/handoff`, {}, { headers: { [TOKEN_HEADER]: tokenFor(id) } });
@@ -1086,13 +1146,98 @@ function createMessengerTransport(opts) {
1086
1146
  const res = await api.get(`/articles/${encodeURIComponent(id)}`);
1087
1147
  return res.ok && res.data ? res.data.article : null;
1088
1148
  },
1149
+ async pageContent(path) {
1150
+ const res = await api.post("/messenger/page", { anonymousId: opts.anonymousId(), userId: opts.userId(), path: path.split(/[?#]/)[0] || "/" });
1151
+ if (!res.ok || !res.data) throw new HttpError(res.status);
1152
+ return res.data;
1153
+ },
1089
1154
  async searchArticles(q) {
1090
1155
  const res = await api.get("/resource-center/search", { params: { q } });
1091
1156
  return res.ok && res.data ? res.data.articles : [];
1157
+ },
1158
+ async listHowTos() {
1159
+ const res = await api.get("/how-tos", { params: { url: pagePath(opts.pageUrl()) } });
1160
+ if (!res.ok || !res.data) throw new HttpError(res.status);
1161
+ return res.data;
1162
+ },
1163
+ async getHowTo(id) {
1164
+ const res = await api.get(`/how-tos/${encodeURIComponent(id)}`);
1165
+ return res.ok && res.data ? res.data.howTo : null;
1092
1166
  }
1093
1167
  };
1094
1168
  }
1095
1169
 
1170
+ // src/messenger-visitor.ts
1171
+ var import_runtime10 = require("@guidelytech/shared/runtime");
1172
+ var import_guide_runtime3 = require("@guidelytech/guide-runtime");
1173
+ var PAGE_GUIDE_KINDS = /* @__PURE__ */ new Set(["flow", "tooltip", "modal"]);
1174
+ var CATCH_ALL = /* @__PURE__ */ new Set(["", "*", "**", "/*", "/**", "/"]);
1175
+ var RESUME_WITHIN_MS = 14 * 864e5;
1176
+ var NEWS_WITHIN_MS = 90 * 864e5;
1177
+ var MAX_NEWS = 10;
1178
+ function pathOf(url) {
1179
+ try {
1180
+ return new URL(url, "http://x.invalid").pathname || "/";
1181
+ } catch {
1182
+ return null;
1183
+ }
1184
+ }
1185
+ function targetsPage(guide, url) {
1186
+ const c = guide.config;
1187
+ const checks = [...c.urlPatterns, ...c.trigger.urlPattern ? [c.trigger.urlPattern] : [], ...c.trigger.type === "url_match" && c.trigger.value ? [c.trigger.value] : [], ...c.steps[0]?.url ? [c.steps[0].url] : []];
1188
+ const specific = checks.filter((p) => !CATCH_ALL.has(p.trim()));
1189
+ return specific.length > 0 && checks.every((p) => (0, import_guide_runtime3.urlMatches)(p, url));
1190
+ }
1191
+ function plainText(html, max = 280) {
1192
+ const text = html.replace(/<(br|\/p|\/div|\/li|\/h[1-6])\s*\/?>/gi, " ").replace(/<[^>]*>/g, "").replace(/&nbsp;/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&").replace(/\s+/g, " ").trim();
1193
+ return text.length > max ? `${text.slice(0, max - 1).trimEnd()}\u2026` : text;
1194
+ }
1195
+ function buildMessengerVisitor(input) {
1196
+ const now = input.now ?? Date.now();
1197
+ const { guides, state } = input;
1198
+ const done = (g) => !!state.guides[g.id]?.completedAt;
1199
+ const pageGuides = guides.filter((g) => PAGE_GUIDE_KINDS.has(g.kind) && g.config.steps.length > 0 && !done(g) && targetsPage(g, input.url) && input.isTargeted(g)).slice(0, 3).map((g) => ({ id: g.id, key: g.key, name: g.name, kind: g.kind }));
1200
+ let resumeGuide = null;
1201
+ let resumeAt = 0;
1202
+ for (const g of guides) {
1203
+ const s = state.guides[g.id];
1204
+ if (g.kind !== "flow" || !s?.lastStepId || s.completedAt || g.config.steps.length < 2) continue;
1205
+ const at = Date.parse(s.lastShownAt ?? "");
1206
+ if (!Number.isFinite(at) || now - at > RESUME_WITHIN_MS || at <= resumeAt) continue;
1207
+ const stepIndex = g.config.steps.findIndex((st) => st.id === s.lastStepId);
1208
+ if (stepIndex < 1 || !isWithinSchedule(g)) continue;
1209
+ resumeGuide = { id: g.id, name: g.name, stepId: s.lastStepId, stepIndex, stepCount: g.config.steps.length };
1210
+ resumeAt = at;
1211
+ }
1212
+ let checklist = null;
1213
+ for (const g of guides) {
1214
+ const tasks = g.config.checklist?.tasks;
1215
+ if (g.kind !== "checklist" || !tasks?.length) continue;
1216
+ const p = state.checklists[g.id];
1217
+ if (p?.completedAt || p?.dismissedAt || !input.isAudienceTargeted(g)) continue;
1218
+ const completed = new Set(p?.completedTaskIds ?? []);
1219
+ const doneCount = tasks.filter((t) => completed.has(t.id)).length;
1220
+ if (doneCount >= tasks.length) continue;
1221
+ checklist = { id: g.id, name: g.name, done: doneCount, total: tasks.length, nextTask: tasks.find((t) => !completed.has(t.id))?.title ?? null };
1222
+ break;
1223
+ }
1224
+ const seen = new Set(input.newsSeen);
1225
+ const news = guides.filter((g) => g.kind === "announcement" && g.config.steps.length > 0 && now - Date.parse(g.publishedAt) <= NEWS_WITHIN_MS && input.isAudienceTargeted(g)).sort((a, b) => b.publishedAt.localeCompare(a.publishedAt)).slice(0, MAX_NEWS).map((g) => {
1226
+ const step = g.config.steps[0];
1227
+ return {
1228
+ id: g.id,
1229
+ key: g.key,
1230
+ title: step.title || g.name,
1231
+ body: plainText(step.body ?? ""),
1232
+ imageUrl: step.imageUrl || null,
1233
+ publishedAt: g.publishedAt,
1234
+ // Read once opened in the News tab, or once the announcement itself was shown.
1235
+ unread: !seen.has(g.id) && !(state.guides[g.id]?.impressions ?? 0)
1236
+ };
1237
+ });
1238
+ return { firstName: (0, import_runtime10.firstNameFromTraits)(input.traits), path: pathOf(input.url), pageGuides, resumeGuide, checklist, news };
1239
+ }
1240
+
1096
1241
  // src/navigation.ts
1097
1242
  function watchNavigation(listener, debounceMs = 50) {
1098
1243
  if (typeof window === "undefined") return () => {
@@ -1311,7 +1456,7 @@ var loadRecorder = async () => (await import("./recorder.cjs")).recorder;
1311
1456
 
1312
1457
  // src/client.ts
1313
1458
  var SDK_NAME = "@guidelytech/sdk-core";
1314
- var SDK_VERSION = "0.5.0";
1459
+ var SDK_VERSION = "0.6.1";
1315
1460
  var DEFAULT_API_URL = "https://api.guidely.app";
1316
1461
  var PAGE_SCOPED = /* @__PURE__ */ new Set(["page_load", "url_match", "element_click", "element_visible", "delay"]);
1317
1462
  var DAY_MS = 24 * 60 * 60 * 1e3;
@@ -1326,7 +1471,7 @@ function emptyState() {
1326
1471
  return { guides: {}, checklists: {}, surveysSubmitted: [], audienceIds: [] };
1327
1472
  }
1328
1473
  function newSession(now = Date.now()) {
1329
- return { id: `s_${(0, import_runtime11.randomId)(16)}`, startedAt: new Date(now).toISOString(), shownGuides: [], events: [], lastActivityAt: now };
1474
+ return { id: `s_${(0, import_runtime13.randomId)(16)}`, startedAt: new Date(now).toISOString(), shownGuides: [], events: [], lastActivityAt: now };
1330
1475
  }
1331
1476
  var GuidelyClient = class _GuidelyClient {
1332
1477
  constructor(options) {
@@ -1362,6 +1507,9 @@ var GuidelyClient = class _GuidelyClient {
1362
1507
  __publicField(this, "firstVisit");
1363
1508
  __publicField(this, "lastUrl");
1364
1509
  __publicField(this, "authoring", null);
1510
+ __publicField(this, "capture", null);
1511
+ /** A capture token was found and the (lazily loaded) capture bridge is starting. */
1512
+ __publicField(this, "captureStarting", false);
1365
1513
  __publicField(this, "lastAudiences", /* @__PURE__ */ new Set());
1366
1514
  /** Set once the app calls identify()/reset(); bootstrap then leaves identity alone instead of re-identifying. */
1367
1515
  __publicField(this, "identitySettled", false);
@@ -1412,7 +1560,7 @@ var GuidelyClient = class _GuidelyClient {
1412
1560
  this.sessionStore = this.options.storage === "memory" ? this.store : createStorage("session");
1413
1561
  this.anonymousId = this.store.get(KEYS.anon) || "";
1414
1562
  if (!this.anonymousId) {
1415
- this.anonymousId = `anon_${(0, import_runtime11.randomId)(20)}`;
1563
+ this.anonymousId = `anon_${(0, import_runtime13.randomId)(20)}`;
1416
1564
  this.store.set(KEYS.anon, this.anonymousId);
1417
1565
  }
1418
1566
  this.firstVisit = !this.store.get(KEYS.seen);
@@ -1470,10 +1618,11 @@ var GuidelyClient = class _GuidelyClient {
1470
1618
  this.isReady = true;
1471
1619
  if (this.config) this.emitter.emit("ready", this.config);
1472
1620
  this.resolveReady?.();
1621
+ const capturing = !this.options.disableAuthoring && this.maybeStartCapture();
1473
1622
  this.renderPersistentWidgets();
1474
1623
  this.resumeActiveGuide();
1475
1624
  this.evaluate("ready");
1476
- if (!this.options.disableAuthoring) this.maybeStartAuthoring();
1625
+ if (!this.options.disableAuthoring && !capturing) this.maybeStartAuthoring();
1477
1626
  this.pageTracker.start(location.href);
1478
1627
  this.touchSession();
1479
1628
  this.syncCapture();
@@ -1571,7 +1720,7 @@ var GuidelyClient = class _GuidelyClient {
1571
1720
  const refresh = setInterval(() => void this.refresh(), this.options.configRefreshMs);
1572
1721
  this.cleanups.push(() => clearInterval(refresh));
1573
1722
  const poll = setInterval(() => {
1574
- if (!this.isReady || !this.config || this.authoring?.isActive() || doc.visibilityState === "hidden") return;
1723
+ if (!this.isReady || !this.config || this.editing() || doc.visibilityState === "hidden") return;
1575
1724
  const url = location.href;
1576
1725
  const ctx = this.getContext();
1577
1726
  for (const guide of this.config.guides) {
@@ -1629,12 +1778,14 @@ var GuidelyClient = class _GuidelyClient {
1629
1778
  this.cleanups.splice(0).forEach((fn) => fn());
1630
1779
  this.authoring?.stop();
1631
1780
  this.authoring = null;
1781
+ this.capture?.destroy();
1782
+ this.capture = null;
1632
1783
  this.replay?.destroy();
1633
1784
  this.replay = null;
1634
1785
  this.queue.flushSync();
1635
1786
  this.queue.destroy();
1636
1787
  this.emitter.clear();
1637
- (0, import_guide_runtime3.destroyHost)();
1788
+ (0, import_guide_runtime4.destroyHost)();
1638
1789
  if (current === this) current = null;
1639
1790
  }
1640
1791
  // ---------------------------------------------------------------------------
@@ -1646,7 +1797,7 @@ var GuidelyClient = class _GuidelyClient {
1646
1797
  this.identitySettled = true;
1647
1798
  this.user = { id: String(userId), traits: { ...this.user?.id === String(userId) ? this.user.traits : {}, ...traits || {} }, account: account ?? (this.user?.id === String(userId) ? this.user.account : void 0) };
1648
1799
  writeJson(this.store, KEYS.user(this.options.projectId), this.user);
1649
- this.enqueue("identify", { properties: { traits: (0, import_runtime11.sanitizeProperties)(this.user.traits) } });
1800
+ this.enqueue("identify", { properties: { traits: (0, import_runtime13.sanitizeProperties)(this.user.traits) } });
1650
1801
  await this.syncIdentify();
1651
1802
  this.emitter.emit("identify", { userId: this.user.id, anonymousId: this.anonymousId });
1652
1803
  if (this.isReady) this.evaluate("identify");
@@ -1661,6 +1812,7 @@ var GuidelyClient = class _GuidelyClient {
1661
1812
  for (const [id, s] of Object.entries(data.guideState || {})) {
1662
1813
  const local = guides[id];
1663
1814
  guides[id] = {
1815
+ ...local,
1664
1816
  impressions: Math.max(local?.impressions ?? 0, s.impressions ?? 0),
1665
1817
  completedAt: local?.completedAt ?? s.completedAt ?? null,
1666
1818
  dismissedAt: local?.dismissedAt ?? s.dismissedAt ?? null,
@@ -1689,6 +1841,7 @@ var GuidelyClient = class _GuidelyClient {
1689
1841
  const g = this.findGuide(id);
1690
1842
  if (w.checklist && g) w.checklist.setProgress(this.getChecklistProgress(g.id));
1691
1843
  });
1844
+ this.messenger?.refresh();
1692
1845
  }
1693
1846
  /** Sets or replaces the account (company/organisation) for the current user. */
1694
1847
  async setAccount(account) {
@@ -1713,7 +1866,7 @@ var GuidelyClient = class _GuidelyClient {
1713
1866
  this.stopGuide();
1714
1867
  this.user = null;
1715
1868
  this.store.remove(KEYS.user(this.options.projectId));
1716
- this.anonymousId = `anon_${(0, import_runtime11.randomId)(20)}`;
1869
+ this.anonymousId = `anon_${(0, import_runtime13.randomId)(20)}`;
1717
1870
  this.store.set(KEYS.anon, this.anonymousId);
1718
1871
  this.state = emptyState();
1719
1872
  this.persistState();
@@ -1755,7 +1908,7 @@ var GuidelyClient = class _GuidelyClient {
1755
1908
  if (this.consent === "denied" || !this.options.analytics) return null;
1756
1909
  if (name !== "page_leave" && name !== "heatmap") this.touchSession();
1757
1910
  const event = {
1758
- eventId: (0, import_runtime11.randomId)(24),
1911
+ eventId: (0, import_runtime13.randomId)(24),
1759
1912
  name,
1760
1913
  occurredAt: nowIso(),
1761
1914
  anonymousId: this.anonymousId,
@@ -1765,7 +1918,7 @@ var GuidelyClient = class _GuidelyClient {
1765
1918
  url: this.collectUrls() ? location.href : void 0,
1766
1919
  ...extra
1767
1920
  };
1768
- if (extra.properties) event.properties = (0, import_runtime11.sanitizeProperties)(extra.properties);
1921
+ if (extra.properties) event.properties = (0, import_runtime13.sanitizeProperties)(extra.properties);
1769
1922
  this.queue.enqueue(event);
1770
1923
  this.replay?.addCustomEvent("guidely", { name, customName: event.customName, guideId: event.guideId });
1771
1924
  this.emitter.emit("track", event);
@@ -1810,16 +1963,17 @@ var GuidelyClient = class _GuidelyClient {
1810
1963
  const st = this.active.controller.getState();
1811
1964
  if (st.status === "running" && !this.active.manual) {
1812
1965
  const g = this.active.guide;
1813
- if (g.config.urlPatterns.length && !g.config.urlPatterns.some((p) => (0, import_guide_runtime3.urlMatches)(p, url))) this.active.controller.destroy();
1966
+ if (g.config.urlPatterns.length && !g.config.urlPatterns.some((p) => (0, import_guide_runtime4.urlMatches)(p, url))) this.active.controller.destroy();
1814
1967
  }
1815
1968
  }
1816
1969
  this.widgets.forEach((w, id) => {
1817
1970
  if (!w.controller || w.manual) return;
1818
1971
  const g = this.findGuide(id);
1819
- if (g?.config.urlPatterns.length && !g.config.urlPatterns.some((p) => (0, import_guide_runtime3.urlMatches)(p, url))) w.controller.destroy();
1972
+ if (g?.config.urlPatterns.length && !g.config.urlPatterns.some((p) => (0, import_guide_runtime4.urlMatches)(p, url))) w.controller.destroy();
1820
1973
  });
1821
1974
  this.firedDelays.clear();
1822
1975
  if (this.isReady) this.evaluate("navigation");
1976
+ if (changed) this.messenger?.refresh();
1823
1977
  if (changed) void this.queue.flush();
1824
1978
  }
1825
1979
  handleDocumentClick(e) {
@@ -1850,9 +2004,13 @@ var GuidelyClient = class _GuidelyClient {
1850
2004
  if (this.replay?.activeSessionId) this.replay.stop();
1851
2005
  this.syncReplay();
1852
2006
  }
1853
- /** Autocapture, error tracking and replay need analytics on, consent granted and no authoring session. */
2007
+ /** Autocapture, error tracking and replay need analytics on, consent granted and no authoring or how-to capture session. */
1854
2008
  captureAllowed() {
1855
- return !this.destroyed && this.analyticsEnabled() && !this.authoring?.isActive();
2009
+ return !this.destroyed && this.analyticsEnabled() && !this.editing();
2010
+ }
2011
+ /** Authoring or how-to capture is running: no guides, widgets, replay or autocapture. */
2012
+ editing() {
2013
+ return !!this.authoring?.isActive() || this.captureStarting || !!this.capture?.isActive();
1856
2014
  }
1857
2015
  /** A capability is on when the project enables it (absent on old servers → off) and no option turns it off. */
1858
2016
  autocaptureOn(key) {
@@ -1862,7 +2020,7 @@ var GuidelyClient = class _GuidelyClient {
1862
2020
  /** Page views on SPA navigation predate autocapture: only an explicit opt-out stops them. */
1863
2021
  pageviewsOn() {
1864
2022
  const o = this.options.autocapture;
1865
- return this.config?.settings?.autocapture?.pageviews !== false && o !== false && !(typeof o === "object" && o.pageviews === false) && !this.authoring?.isActive();
2023
+ return this.config?.settings?.autocapture?.pageviews !== false && o !== false && !(typeof o === "object" && o.pageviews === false) && !this.editing();
1866
2024
  }
1867
2025
  trackPageView(url) {
1868
2026
  if (url === this.pageViewUrl || !this.pageviewsOn()) return;
@@ -1872,7 +2030,7 @@ var GuidelyClient = class _GuidelyClient {
1872
2030
  const device = detectDevice(navigator.userAgent, window.innerWidth);
1873
2031
  const props = { deviceType: device.type, browser: device.browser, os: device.os, screenWidth: window.screen?.width, viewportWidth: window.innerWidth };
1874
2032
  if (collect) {
1875
- props.path = pathOf(url);
2033
+ props.path = pathOf2(url);
1876
2034
  props.title = (document.title || "").slice(0, 200);
1877
2035
  const ref = !this.session.pageViews ? externalReferrer() : void 0;
1878
2036
  if (ref) props.referrer = ref;
@@ -1889,7 +2047,7 @@ var GuidelyClient = class _GuidelyClient {
1889
2047
  if (!this.pageLeft && this.autocaptureOn("pageLeave")) {
1890
2048
  const info = t.leave();
1891
2049
  const collect = this.collectUrls();
1892
- this.enqueue("page_leave", { url: collect ? info.url : void 0, properties: { ...collect ? { path: pathOf(info.url) } : {}, durationMs: info.durationMs, scrollDepth: info.scrollDepth } });
2050
+ this.enqueue("page_leave", { url: collect ? info.url : void 0, properties: { ...collect ? { path: pathOf2(info.url) } : {}, durationMs: info.durationMs, scrollDepth: info.scrollDepth } });
1893
2051
  }
1894
2052
  if (nextUrl !== null) {
1895
2053
  t.start(nextUrl);
@@ -1926,7 +2084,7 @@ var GuidelyClient = class _GuidelyClient {
1926
2084
  if (!batch || !this.captureAllowed()) return;
1927
2085
  const collect = this.collectUrls();
1928
2086
  const de = document.documentElement;
1929
- const properties = { path: collect ? pathOf(batch.url) : void 0, viewportWidth: window.innerWidth, viewportHeight: window.innerHeight, pageHeight: Math.max(de.scrollHeight, document.body?.scrollHeight || 0), points: batch.points };
2087
+ const properties = { path: collect ? pathOf2(batch.url) : void 0, viewportWidth: window.innerWidth, viewportHeight: window.innerHeight, pageHeight: Math.max(de.scrollHeight, document.body?.scrollHeight || 0), points: batch.points };
1930
2088
  if (!collect) delete properties.path;
1931
2089
  this.enqueue("heatmap", { url: collect ? batch.url : void 0, properties });
1932
2090
  }
@@ -2005,7 +2163,7 @@ var GuidelyClient = class _GuidelyClient {
2005
2163
  syncReplay() {
2006
2164
  const cfg = this.isReady && this.captureAllowed() ? this.replayConfig() : null;
2007
2165
  if (cfg && this.session.replay === void 0) {
2008
- this.session.replay = (0, import_runtime11.rolloutBucket)(this.session.id, "replay") < cfg.sampleRate;
2166
+ this.session.replay = (0, import_runtime13.rolloutBucket)(this.session.id, "replay") < cfg.sampleRate;
2009
2167
  this.persistSession();
2010
2168
  }
2011
2169
  if (!cfg || !this.session.replay) {
@@ -2100,12 +2258,12 @@ var GuidelyClient = class _GuidelyClient {
2100
2258
  }
2101
2259
  isTargeted(guide, ctx, url) {
2102
2260
  const c = guide.config;
2103
- if (c.urlPatterns.length && !c.urlPatterns.some((p) => (0, import_guide_runtime3.urlMatches)(p, url))) return false;
2104
- if (c.trigger.urlPattern && !(0, import_guide_runtime3.urlMatches)(c.trigger.urlPattern, url)) return false;
2261
+ if (c.urlPatterns.length && !c.urlPatterns.some((p) => (0, import_guide_runtime4.urlMatches)(p, url))) return false;
2262
+ if (c.trigger.urlPattern && !(0, import_guide_runtime4.urlMatches)(c.trigger.urlPattern, url)) return false;
2105
2263
  if (!isWithinSchedule(guide)) return false;
2106
2264
  if (guide.kind === "survey" && (this.state.surveysSubmitted.includes(guide.id) || this.state.surveysSubmitted.includes(guide.key))) return false;
2107
2265
  ctx.rolloutSalt = guide.id;
2108
- return (0, import_runtime11.evaluateRules)(c.targeting, ctx);
2266
+ return (0, import_runtime13.evaluateRules)(c.targeting, ctx);
2109
2267
  }
2110
2268
  isEligible(guide, ctx, url) {
2111
2269
  if (!this.isTargeted(guide, ctx, url)) return false;
@@ -2123,7 +2281,7 @@ var GuidelyClient = class _GuidelyClient {
2123
2281
  if (t.delayMs > 0) return reason === "timer" && detail.guideId === guide.id;
2124
2282
  return reason === "ready" || reason === "navigation" || reason === "identify";
2125
2283
  case "url_match":
2126
- return (reason === "ready" || reason === "navigation" || reason === "identify") && (0, import_guide_runtime3.urlMatches)(t.value, location.href);
2284
+ return (reason === "ready" || reason === "navigation" || reason === "identify") && (0, import_guide_runtime4.urlMatches)(t.value, location.href);
2127
2285
  case "event":
2128
2286
  return reason === "event" && !!t.value && detail.eventName === t.value;
2129
2287
  case "element_click":
@@ -2147,7 +2305,7 @@ var GuidelyClient = class _GuidelyClient {
2147
2305
  }
2148
2306
  }
2149
2307
  evaluate(reason, detail = {}) {
2150
- if (!this.config || this.destroyed || this.authoring?.isActive()) return;
2308
+ if (!this.config || this.destroyed || this.editing()) return;
2151
2309
  const url = location.href;
2152
2310
  const ctx = this.getContext();
2153
2311
  if (reason === "identify") {
@@ -2199,7 +2357,7 @@ var GuidelyClient = class _GuidelyClient {
2199
2357
  this.visibilityObservers.delete(guide.id);
2200
2358
  };
2201
2359
  this.visibilityObservers.set(guide.id, stop);
2202
- (0, import_guide_runtime3.waitForTarget)([{ kind: "css", value: selector }], { timeoutMs: 0, signal: ac.signal }).then((el) => {
2360
+ (0, import_guide_runtime4.waitForTarget)([{ kind: "css", value: selector }], { timeoutMs: 0, signal: ac.signal }).then((el) => {
2203
2361
  if (ac.signal.aborted) return;
2204
2362
  const fire = () => {
2205
2363
  stop();
@@ -2292,10 +2450,10 @@ var GuidelyClient = class _GuidelyClient {
2292
2450
  }
2293
2451
  }
2294
2452
  showFlow(guide, manual, stepId) {
2295
- if (this.authoring?.isActive()) return;
2453
+ if (this.editing()) return;
2296
2454
  const exclusive = isExclusiveGuide(guide);
2297
2455
  const entry = { guide, manual, startUrl: location.href };
2298
- const controller = (0, import_guide_runtime3.runGuide)(guide, {
2456
+ const controller = (0, import_guide_runtime4.runGuide)(guide, {
2299
2457
  theme: this.theme(),
2300
2458
  ctx: () => this.getContext(),
2301
2459
  startAtStep: stepId,
@@ -2310,6 +2468,10 @@ var GuidelyClient = class _GuidelyClient {
2310
2468
  }
2311
2469
  if (e.name === "step_viewed" && step) {
2312
2470
  if (exclusive) writeJson(this.sessionStore, KEYS.active, { guideId: guide.id, stepId: step.id, manual });
2471
+ if (guide.kind === "flow" && guide.config.steps.length > 1) {
2472
+ this.guideState(guide.id).lastStepId = step.id;
2473
+ this.persistState();
2474
+ }
2313
2475
  this.emitter.emit("guide:step", { guide, stepId: step.id, stepIndex: e.stepIndex ?? 0 });
2314
2476
  }
2315
2477
  if (e.name === "guide_completed") {
@@ -2349,13 +2511,13 @@ var GuidelyClient = class _GuidelyClient {
2349
2511
  }
2350
2512
  }
2351
2513
  showChecklist(guide) {
2352
- if (this.authoring?.isActive()) return;
2514
+ if (this.editing()) return;
2353
2515
  const config = guide.config.checklist;
2354
2516
  if (!config || this.widgets.has(guide.id)) return;
2355
- const scope = (0, import_guide_runtime4.createScope)(this.theme(), guide.config.appearance);
2517
+ const scope = (0, import_guide_runtime5.createScope)(this.theme(), guide.config.appearance);
2356
2518
  const progress = this.getChecklistProgress(guide.id);
2357
2519
  const first = !this.state.guides[guide.id]?.impressions;
2358
- const widget = (0, import_guide_runtime3.renderChecklist)({
2520
+ const widget = (0, import_guide_runtime4.renderChecklist)({
2359
2521
  scope: scope.el,
2360
2522
  config,
2361
2523
  progress,
@@ -2371,10 +2533,10 @@ var GuidelyClient = class _GuidelyClient {
2371
2533
  if (first) this.recordImpression(guide);
2372
2534
  }
2373
2535
  showSurvey(guide, manual) {
2374
- if (this.authoring?.isActive()) return;
2536
+ if (this.editing()) return;
2375
2537
  const config = guide.config.survey;
2376
2538
  if (!config) return;
2377
- const scope = (0, import_guide_runtime4.createScope)(this.theme(), guide.config.appearance);
2539
+ const scope = (0, import_guide_runtime5.createScope)(this.theme(), guide.config.appearance);
2378
2540
  const entry = { guide, manual, startUrl: location.href, scope };
2379
2541
  const finish = (reason) => {
2380
2542
  widget.destroy();
@@ -2387,13 +2549,13 @@ var GuidelyClient = class _GuidelyClient {
2387
2549
  }
2388
2550
  this.setTimer(() => this.evaluate("after_guide", { endedGuide: guide }), 0);
2389
2551
  };
2390
- const widget = (0, import_guide_runtime3.renderSurvey)({
2552
+ const widget = (0, import_guide_runtime4.renderSurvey)({
2391
2553
  scope: scope.el,
2392
2554
  config,
2393
2555
  title: guide.name,
2394
2556
  onDismiss: () => finish(this.state.surveysSubmitted.includes(guide.id) ? "submitted" : "dismissed"),
2395
2557
  onSubmit: (answers) => {
2396
- const responseId = (0, import_runtime11.randomId)(24);
2558
+ const responseId = (0, import_runtime13.randomId)(24);
2397
2559
  this.state.surveysSubmitted.push(guide.id);
2398
2560
  this.persistState();
2399
2561
  this.recordEnd(guide, "completed");
@@ -2422,7 +2584,7 @@ var GuidelyClient = class _GuidelyClient {
2422
2584
  }
2423
2585
  }
2424
2586
  renderPersistentWidgets() {
2425
- if (!this.config) return;
2587
+ if (!this.config || this.captureStarting || this.capture?.isActive()) return;
2426
2588
  const rc = this.config.resourceCenter;
2427
2589
  if (this.config.messenger?.enabled) {
2428
2590
  if (this.resourceCenter) {
@@ -2435,9 +2597,9 @@ var GuidelyClient = class _GuidelyClient {
2435
2597
  }
2436
2598
  this.destroyMessenger();
2437
2599
  if (rc && rc.enabled && !this.resourceCenter) {
2438
- const scope = (0, import_guide_runtime4.createScope)(this.theme());
2600
+ const scope = (0, import_guide_runtime5.createScope)(this.theme());
2439
2601
  this.resourceCenterScope = scope;
2440
- this.resourceCenter = (0, import_guide_runtime3.renderResourceCenter)({
2602
+ this.resourceCenter = (0, import_guide_runtime4.renderResourceCenter)({
2441
2603
  scope: scope.el,
2442
2604
  config: rc,
2443
2605
  guides: this.config.guides.map((g) => ({ id: g.id, key: g.key, name: g.name, kind: g.kind })),
@@ -2473,7 +2635,7 @@ var GuidelyClient = class _GuidelyClient {
2473
2635
  this.messengerLoading = import("@guidelytech/guide-runtime/messenger").then(({ renderMessenger }) => {
2474
2636
  const cfg = this.config?.messenger;
2475
2637
  if (this.destroyed || !this.config || !cfg?.enabled || this.messenger) return this.messenger;
2476
- const scope = (0, import_guide_runtime4.createScope)(this.theme());
2638
+ const scope = (0, import_guide_runtime5.createScope)(this.theme());
2477
2639
  this.messengerScope = scope;
2478
2640
  this.messenger = renderMessenger({
2479
2641
  scope: scope.el,
@@ -2486,6 +2648,13 @@ var GuidelyClient = class _GuidelyClient {
2486
2648
  userId: () => this.user?.id || null,
2487
2649
  pageUrl: () => this.collectUrls() ? location.href : void 0
2488
2650
  }),
2651
+ visitor: () => this.messengerVisitor(),
2652
+ brand: { logoUrl: this.theme().logoUrl ?? null, name: this.theme().brandName ?? null },
2653
+ onResumeGuide: (guideId, stepId) => this.startGuide(guideId, { stepId }),
2654
+ onNewsSeen: (ids) => {
2655
+ const seen = readJson(this.store, KEYS.newsSeen(this.options.projectId), []);
2656
+ writeJson(this.store, KEYS.newsSeen(this.options.projectId), Array.from(/* @__PURE__ */ new Set([...ids, ...Array.isArray(seen) ? seen : []])).slice(0, 200));
2657
+ },
2489
2658
  resourceCenter: this.config.resourceCenter,
2490
2659
  audienceIds: () => this.state.audienceIds,
2491
2660
  guides: this.config.guides.map((g) => ({ id: g.id, key: g.key, name: g.name, kind: g.kind })),
@@ -2507,6 +2676,25 @@ var GuidelyClient = class _GuidelyClient {
2507
2676
  });
2508
2677
  return this.messengerLoading;
2509
2678
  }
2679
+ /** What the messenger personalises from, computed fresh on every render. */
2680
+ messengerVisitor() {
2681
+ const ctx = this.getContext();
2682
+ const url = location.href;
2683
+ const seen = readJson(this.store, KEYS.newsSeen(this.options.projectId), []);
2684
+ return buildMessengerVisitor({
2685
+ guides: this.config?.guides ?? [],
2686
+ state: this.state,
2687
+ traits: this.user?.traits,
2688
+ url,
2689
+ isTargeted: (g) => this.isTargeted(g, ctx, url),
2690
+ isAudienceTargeted: (g) => {
2691
+ if (!isWithinSchedule(g)) return false;
2692
+ ctx.rolloutSalt = g.id;
2693
+ return (0, import_runtime13.evaluateRules)(g.config.targeting, ctx);
2694
+ },
2695
+ newsSeen: Array.isArray(seen) ? seen : []
2696
+ });
2697
+ }
2510
2698
  destroyMessenger() {
2511
2699
  this.messenger?.destroy();
2512
2700
  this.messengerScope?.destroy();
@@ -2553,7 +2741,7 @@ var GuidelyClient = class _GuidelyClient {
2553
2741
  if (progress.completedTaskIds.includes(task.id)) return;
2554
2742
  progress.completedTaskIds.push(task.id);
2555
2743
  this.enqueue("checklist_task_completed", { guideId: guide.id, guideVersion: guide.version, properties: { taskId: task.id } });
2556
- const complete = (0, import_guide_runtime3.isChecklistComplete)(config, progress) && !progress.completedAt;
2744
+ const complete = (0, import_guide_runtime4.isChecklistComplete)(config, progress) && !progress.completedAt;
2557
2745
  if (complete) {
2558
2746
  progress.completedAt = nowIso();
2559
2747
  this.enqueue("checklist_completed", { guideId: guide.id, guideVersion: guide.version });
@@ -2576,7 +2764,7 @@ var GuidelyClient = class _GuidelyClient {
2576
2764
  if (task.completion !== kind || !task.completionValue) continue;
2577
2765
  let hit = false;
2578
2766
  if (kind === "event") hit = value === task.completionValue;
2579
- else if (kind === "url_visited") hit = (0, import_guide_runtime3.urlMatches)(task.completionValue, value);
2767
+ else if (kind === "url_visited") hit = (0, import_guide_runtime4.urlMatches)(task.completionValue, value);
2580
2768
  else if (kind === "guide_completed") hit = value.id === task.completionValue || value.key === task.completionValue;
2581
2769
  else if (kind === "click") {
2582
2770
  try {
@@ -2720,7 +2908,8 @@ var GuidelyClient = class _GuidelyClient {
2720
2908
  audienceIds: this.state.audienceIds,
2721
2909
  session: this.session,
2722
2910
  pendingEvents: this.queue.size,
2723
- authoring: !!this.authoring?.isActive()
2911
+ authoring: !!this.authoring?.isActive(),
2912
+ capture: !!this.capture?.isActive()
2724
2913
  };
2725
2914
  }
2726
2915
  // ---------------------------------------------------------------------------
@@ -2735,22 +2924,78 @@ var GuidelyClient = class _GuidelyClient {
2735
2924
  ctx: () => this.getContext(),
2736
2925
  maskSelectors: [...this.options.maskSelectors || [], ...this.config?.settings?.maskSelectors || []],
2737
2926
  onError: (err) => this.reportError(err),
2738
- onActive: (active) => {
2739
- this.emitter.emit("authoring", { active });
2740
- if (active) this.replay?.stop({ discard: true });
2741
- else this.syncCapture();
2742
- if (active) {
2743
- this.stopGuide();
2744
- this.widgets.forEach((w) => w.destroy());
2745
- this.widgets.clear();
2746
- } else this.evaluate("ready");
2747
- }
2927
+ onActive: (active) => this.setEditing("authoring", active)
2748
2928
  });
2749
2929
  if (bridge.detect()) this.authoring = bridge;
2750
2930
  } catch (err) {
2751
2931
  this.reportError(err);
2752
2932
  }
2753
2933
  }
2934
+ /** Authoring or capture started / ended: pause everything a visitor would see or be recorded by. */
2935
+ setEditing(kind, active) {
2936
+ this.emitter.emit(kind, { active });
2937
+ if (active) {
2938
+ this.replay?.stop({ discard: true });
2939
+ this.stopGuide();
2940
+ this.widgets.forEach((w) => w.destroy());
2941
+ this.widgets.clear();
2942
+ if (kind === "capture") this.hidePersistentWidgets();
2943
+ } else {
2944
+ this.syncCapture();
2945
+ this.renderPersistentWidgets();
2946
+ this.evaluate("ready");
2947
+ }
2948
+ }
2949
+ hidePersistentWidgets() {
2950
+ this.resourceCenter?.destroy();
2951
+ this.resourceCenterScope?.destroy();
2952
+ this.resourceCenter = null;
2953
+ this.resourceCenterScope = null;
2954
+ this.destroyMessenger();
2955
+ }
2956
+ // ---------------------------------------------------------------------------
2957
+ // How-to capture
2958
+ // ---------------------------------------------------------------------------
2959
+ /**
2960
+ * Starts how-to capture when the URL carries `guidely_capture` (or this tab is mid-recording).
2961
+ * The bridge, toolbar and screenshot code are a separate chunk loaded only then.
2962
+ */
2963
+ maybeStartCapture() {
2964
+ let marker = null;
2965
+ try {
2966
+ marker = takeCaptureToken(this.sessionStore);
2967
+ } catch (err) {
2968
+ this.reportError(err);
2969
+ }
2970
+ if (!marker) return false;
2971
+ const found = marker;
2972
+ this.captureStarting = true;
2973
+ this.replay?.stop({ discard: true });
2974
+ loadCapture().then(async (capture) => {
2975
+ if (this.destroyed) return;
2976
+ const bridge = capture.createBridge({
2977
+ api: this.api,
2978
+ sessionStore: this.sessionStore,
2979
+ marker: found,
2980
+ maskSelector: this.maskSelector(),
2981
+ onError: (err) => this.reportError(err),
2982
+ onActive: (active) => {
2983
+ this.captureStarting = false;
2984
+ this.setEditing("capture", active);
2985
+ }
2986
+ });
2987
+ this.capture = bridge;
2988
+ await bridge.start();
2989
+ }).catch((err) => this.reportError(err)).finally(() => {
2990
+ if (!this.captureStarting) return;
2991
+ this.captureStarting = false;
2992
+ if (this.destroyed) return;
2993
+ this.syncCapture();
2994
+ this.renderPersistentWidgets();
2995
+ this.evaluate("ready");
2996
+ });
2997
+ return true;
2998
+ }
2754
2999
  // ---------------------------------------------------------------------------
2755
3000
  // Internals
2756
3001
  // ---------------------------------------------------------------------------
@@ -2790,9 +3035,9 @@ var GuidelyClient = class _GuidelyClient {
2790
3035
  };
2791
3036
  var current = null;
2792
3037
  function webOnly(config) {
2793
- return config.guides.every((g) => (0, import_runtime11.supportsPlatform)(g.config, "web")) ? config : { ...config, guides: config.guides.filter((g) => (0, import_runtime11.supportsPlatform)(g.config, "web")) };
3038
+ return config.guides.every((g) => (0, import_runtime13.supportsPlatform)(g.config, "web")) ? config : { ...config, guides: config.guides.filter((g) => (0, import_runtime13.supportsPlatform)(g.config, "web")) };
2794
3039
  }
2795
- function pathOf(url) {
3040
+ function pathOf2(url) {
2796
3041
  try {
2797
3042
  return new URL(url, "http://localhost").pathname;
2798
3043
  } catch {
@@ -2826,6 +3071,7 @@ var index_default = Guidely;
2826
3071
  // Annotate the CommonJS export names for ESM import in node:
2827
3072
  0 && (module.exports = {
2828
3073
  AUTHORING_PARAM,
3074
+ CAPTURE_PARAM,
2829
3075
  DEFAULT_API_URL,
2830
3076
  EventQueue,
2831
3077
  Guidely,