@guidelytech/sdk-core 0.9.0 → 0.10.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.
Files changed (48) hide show
  1. package/README.md +15 -4
  2. package/dist/{capture-C3faAYb7.d.cts → capture-369s4YYT.d.ts} +2 -1
  3. package/dist/{capture-Dqd7up2n.d.ts → capture-DVJyQ2JZ.d.cts} +2 -1
  4. package/dist/capture.cjs +2 -0
  5. package/dist/capture.cjs.map +1 -1
  6. package/dist/capture.d.cts +3 -2
  7. package/dist/capture.d.ts +3 -2
  8. package/dist/capture.js +4 -6
  9. package/dist/capture.js.map +1 -1
  10. package/dist/chunk-C4WWSF67.js +374 -0
  11. package/dist/chunk-C4WWSF67.js.map +1 -0
  12. package/dist/{chunk-544KSOC3.js → chunk-GDJB466J.js} +115 -18
  13. package/dist/chunk-GDJB466J.js.map +1 -0
  14. package/dist/headless.cjs +275 -40
  15. package/dist/headless.cjs.map +1 -1
  16. package/dist/headless.d.cts +43 -3
  17. package/dist/headless.d.ts +43 -3
  18. package/dist/headless.js +14 -8
  19. package/dist/health-DFHUstWd.d.cts +88 -0
  20. package/dist/health-DFHUstWd.d.ts +88 -0
  21. package/dist/{http-47tiAlOM.d.ts → http-D0dCcpLN.d.cts} +10 -35
  22. package/dist/{http-47tiAlOM.d.cts → http-DJd8jRhK.d.ts} +10 -35
  23. package/dist/index.cjs +342 -77
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +10 -5
  26. package/dist/index.d.ts +10 -5
  27. package/dist/index.js +71 -32
  28. package/dist/index.js.map +1 -1
  29. package/dist/recorder.cjs +70 -9
  30. package/dist/recorder.cjs.map +1 -1
  31. package/dist/recorder.d.cts +9 -0
  32. package/dist/recorder.d.ts +9 -0
  33. package/dist/recorder.js +57 -11
  34. package/dist/recorder.js.map +1 -1
  35. package/dist/{types-DnJW_4ck.d.ts → types-B5ecgHUV.d.cts} +10 -3
  36. package/dist/{types-zM5e3loY.d.cts → types-BtPovimB.d.ts} +10 -3
  37. package/package.json +4 -4
  38. package/dist/chunk-544KSOC3.js.map +0 -1
  39. package/dist/chunk-AKNE7D5M.js +0 -160
  40. package/dist/chunk-AKNE7D5M.js.map +0 -1
  41. package/dist/chunk-CYAG6ZYX.js +0 -85
  42. package/dist/chunk-CYAG6ZYX.js.map +0 -1
  43. package/dist/chunk-GDF6RCHQ.js +0 -209
  44. package/dist/chunk-GDF6RCHQ.js.map +0 -1
  45. package/dist/types-DbKQPvFt.d.cts +0 -238
  46. package/dist/types-DqhNl5Am.d.ts +0 -238
  47. package/dist/types-RyeRQd9f.d.ts +0 -226
  48. package/dist/types-d4eOerxi.d.cts +0 -226
package/dist/index.d.cts CHANGED
@@ -4,14 +4,15 @@ export { AppSnapshot, AutocaptureSettings, ExceptionProperties, GuideConfig, Gui
4
4
  import { FlagsClient, JsonValue, FlagValue, FlagDetails } from '@guidelytech/flags';
5
5
  export { Attributes, EvaluationResult, FlagDetails, FlagsBootstrap, FlagsClient, FlagsClientOptions, FlagsPayload, JsonValue } from '@guidelytech/flags';
6
6
  import { MessengerTab } from '@guidelytech/guide-runtime/messenger';
7
- import { k as GuidelyOptions, c as GuidelyAccount, a as ConsentState, C as ChecklistProgressState, l as GuidelyEvents, e as GuidelyUser, G as GuideLocalState, S as SessionState } from './types-zM5e3loY.cjs';
8
- export { E as EventQueue, b as EventQueueOptions, m as GuideStepInfo, d as GuidelyEnvironment, n as GuidelyEventName, P as PersistedState, f as areMutuallyExclusive, i as isExclusiveGuide, h as isFrequencyEligible, j as isWithinSchedule } from './types-zM5e3loY.cjs';
9
- export { K as KEYS, b as KeyValueStore, S as StorageKind, d as createStorage } from './http-47tiAlOM.cjs';
10
- export { C as CaptureMarker, a as CaptureOutgoingMessage } from './capture-C3faAYb7.cjs';
7
+ import { k as GuidelyOptions, c as GuidelyAccount, a as ConsentState, C as ChecklistProgressState, l as GuidelyEvents, e as GuidelyUser, G as GuideLocalState, S as SessionState } from './types-B5ecgHUV.cjs';
8
+ export { E as EventQueue, b as EventQueueOptions, m as GuideStepInfo, d as GuidelyEnvironment, n as GuidelyEventName, P as PersistedState, f as areMutuallyExclusive, i as isExclusiveGuide, h as isFrequencyEligible, j as isWithinSchedule } from './types-B5ecgHUV.cjs';
9
+ export { a as KEYS, K as KeyValueStore, c as StorageKind, d as createStorage } from './health-DFHUstWd.cjs';
10
+ export { C as CaptureMarker, a as CaptureOutgoingMessage } from './capture-DVJyQ2JZ.cjs';
11
11
  export { CAPTURE_PARAM } from '@guidelytech/shared/runtime';
12
+ import './http-D0dCcpLN.cjs';
12
13
 
13
14
  declare const SDK_NAME = "@guidelytech/sdk-core";
14
- declare const SDK_VERSION = "0.9.0";
15
+ declare const SDK_VERSION = "0.10.0";
15
16
  declare const DEFAULT_API_URL = "https://api.guidely.app";
16
17
  /**
17
18
  * Framework-independent Guidely client. Create one per page with {@link createGuidely} or
@@ -24,6 +25,8 @@ declare class GuidelyClient {
24
25
  private readonly sessionStore;
25
26
  private readonly emitter;
26
27
  private readonly queue;
28
+ /** Survey answers and guide/checklist progress, kept until the server accepts them. */
29
+ private readonly outbox;
27
30
  private config;
28
31
  private etag;
29
32
  private anonymousId;
@@ -85,6 +88,8 @@ declare class GuidelyClient {
85
88
  private wireErrorListeners;
86
89
  /** Re-fetches the published config and re-evaluates triggers. */
87
90
  refresh(): Promise<void>;
91
+ /** Re-renders after a config change (refresh, or a config that arrived after start). */
92
+ private applyConfigChange;
88
93
  /** Tears everything down: guides, widgets, listeners, timers, host element. Re-init is allowed via a new client. */
89
94
  destroy(): void;
90
95
  /** Identifies the end user and loads server-held state (audiences, guide history, checklist progress). */
package/dist/index.d.ts CHANGED
@@ -4,14 +4,15 @@ export { AppSnapshot, AutocaptureSettings, ExceptionProperties, GuideConfig, Gui
4
4
  import { FlagsClient, JsonValue, FlagValue, FlagDetails } from '@guidelytech/flags';
5
5
  export { Attributes, EvaluationResult, FlagDetails, FlagsBootstrap, FlagsClient, FlagsClientOptions, FlagsPayload, JsonValue } from '@guidelytech/flags';
6
6
  import { MessengerTab } from '@guidelytech/guide-runtime/messenger';
7
- import { k as GuidelyOptions, c as GuidelyAccount, a as ConsentState, C as ChecklistProgressState, l as GuidelyEvents, e as GuidelyUser, G as GuideLocalState, S as SessionState } from './types-DnJW_4ck.js';
8
- export { E as EventQueue, b as EventQueueOptions, m as GuideStepInfo, d as GuidelyEnvironment, n as GuidelyEventName, P as PersistedState, f as areMutuallyExclusive, i as isExclusiveGuide, h as isFrequencyEligible, j as isWithinSchedule } from './types-DnJW_4ck.js';
9
- export { K as KEYS, b as KeyValueStore, S as StorageKind, d as createStorage } from './http-47tiAlOM.js';
10
- export { C as CaptureMarker, a as CaptureOutgoingMessage } from './capture-Dqd7up2n.js';
7
+ import { k as GuidelyOptions, c as GuidelyAccount, a as ConsentState, C as ChecklistProgressState, l as GuidelyEvents, e as GuidelyUser, G as GuideLocalState, S as SessionState } from './types-BtPovimB.js';
8
+ export { E as EventQueue, b as EventQueueOptions, m as GuideStepInfo, d as GuidelyEnvironment, n as GuidelyEventName, P as PersistedState, f as areMutuallyExclusive, i as isExclusiveGuide, h as isFrequencyEligible, j as isWithinSchedule } from './types-BtPovimB.js';
9
+ export { a as KEYS, K as KeyValueStore, c as StorageKind, d as createStorage } from './health-DFHUstWd.js';
10
+ export { C as CaptureMarker, a as CaptureOutgoingMessage } from './capture-369s4YYT.js';
11
11
  export { CAPTURE_PARAM } from '@guidelytech/shared/runtime';
12
+ import './http-DJd8jRhK.js';
12
13
 
13
14
  declare const SDK_NAME = "@guidelytech/sdk-core";
14
- declare const SDK_VERSION = "0.9.0";
15
+ declare const SDK_VERSION = "0.10.0";
15
16
  declare const DEFAULT_API_URL = "https://api.guidely.app";
16
17
  /**
17
18
  * Framework-independent Guidely client. Create one per page with {@link createGuidely} or
@@ -24,6 +25,8 @@ declare class GuidelyClient {
24
25
  private readonly sessionStore;
25
26
  private readonly emitter;
26
27
  private readonly queue;
28
+ /** Survey answers and guide/checklist progress, kept until the server accepts them. */
29
+ private readonly outbox;
27
30
  private config;
28
31
  private etag;
29
32
  private anonymousId;
@@ -85,6 +88,8 @@ declare class GuidelyClient {
85
88
  private wireErrorListeners;
86
89
  /** Re-fetches the published config and re-evaluates triggers. */
87
90
  refresh(): Promise<void>;
91
+ /** Re-renders after a config change (refresh, or a config that arrived after start). */
92
+ private applyConfigChange;
88
93
  /** Tears everything down: guides, widgets, listeners, timers, host element. Re-init is allowed via a new client. */
89
94
  destroy(): void;
90
95
  /** Identifies the end user and loads server-held state (audiences, guide history, checklist progress). */
package/dist/index.js CHANGED
@@ -1,27 +1,28 @@
1
1
  import {
2
2
  Emitter,
3
3
  EventQueue,
4
+ Outbox,
4
5
  areMutuallyExclusive,
5
6
  dismissedAfterMerge,
6
7
  isExclusiveGuide,
7
8
  isFrequencyEligible,
8
9
  isWithinSchedule
9
- } from "./chunk-544KSOC3.js";
10
+ } from "./chunk-GDJB466J.js";
10
11
  import {
12
+ Api,
11
13
  KEYS,
14
+ __publicField,
12
15
  createStorage,
16
+ postWithRetry,
13
17
  readJson,
14
18
  writeJson
15
- } from "./chunk-CYAG6ZYX.js";
16
- import {
17
- Api,
18
- __publicField,
19
- postWithRetry
20
- } from "./chunk-AKNE7D5M.js";
19
+ } from "./chunk-C4WWSF67.js";
21
20
 
22
21
  // src/client.ts
23
22
  import { evaluateRules, randomId, rolloutBucket, sanitizeProperties, supportsPlatform } from "@guidelytech/shared/runtime";
24
23
  import {
24
+ closestComposed as closestComposed3,
25
+ composedTarget,
25
26
  destroyHost,
26
27
  isChecklistComplete,
27
28
  renderChecklist,
@@ -35,7 +36,7 @@ import { createScope } from "@guidelytech/guide-runtime";
35
36
  import { createFlagsClient } from "@guidelytech/flags";
36
37
 
37
38
  // src/authoring.ts
38
- import { highlightSelectors, previewStep, runGuide, startAuthoring } from "@guidelytech/guide-runtime";
39
+ import { closestComposed, highlightSelectors, previewStep, runGuide, startAuthoring } from "@guidelytech/guide-runtime";
39
40
 
40
41
  // src/snapshot.ts
41
42
  var MAX_SNAPSHOT_BYTES = 6 * 1024 * 1024;
@@ -199,7 +200,7 @@ var AuthoringBridge = class {
199
200
  masked(el) {
200
201
  return this.opts.maskSelectors.some((sel) => {
201
202
  try {
202
- return !!el.closest(sel);
203
+ return !!closestComposed(el, sel);
203
204
  } catch {
204
205
  return false;
205
206
  }
@@ -380,7 +381,7 @@ function takeCaptureToken(sessionStore) {
380
381
  var loadCapture = async () => (await import("./capture.js")).capture;
381
382
 
382
383
  // src/autocapture.ts
383
- import { isGuidelyElement, isStableId } from "@guidelytech/guide-runtime";
384
+ import { closestComposed as closestComposed2, isGuidelyElement, isStableId, SHADOW_SEPARATOR, shadowHostChain } from "@guidelytech/guide-runtime";
384
385
  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]";
385
386
  var DEFAULT_MASK_SELECTORS = ["[data-guidely-mask]", ".guidely-mask"];
386
387
  var PREFERRED_ATTRS = ["data-testid", "data-test-id", "data-test", "data-cy", "data-qa", "data-guidely-track", "data-tour"];
@@ -400,11 +401,11 @@ function validSelectors(list) {
400
401
  return out;
401
402
  }
402
403
  function isIgnoredElement(el) {
403
- return isGuidelyElement(el) || !!el.closest("[data-guidely-ignore]");
404
+ return isGuidelyElement(el) || !!closestComposed2(el, "[data-guidely-ignore]");
404
405
  }
405
406
  function interactiveElement(target) {
406
407
  try {
407
- return target.closest(INTERACTIVE_SELECTOR);
408
+ return closestComposed2(target, INTERACTIVE_SELECTOR);
408
409
  } catch {
409
410
  return null;
410
411
  }
@@ -415,14 +416,19 @@ function esc(value) {
415
416
  }
416
417
  var attr = (tag, name, value) => value ? `${tag}[${name}="${value.replace(/["\\]/g, "\\$&")}"]` : `${tag}[${name}]`;
417
418
  function elementSelector(el) {
419
+ const own = ownSelector(el);
420
+ const chain = shadowHostChain(el);
421
+ return (chain ? chain + SHADOW_SEPARATOR + own : own).slice(0, 300);
422
+ }
423
+ function ownSelector(el) {
418
424
  const tag = el.tagName.toLowerCase();
419
425
  if (el.id && isStableId(el.id)) return `#${esc(el.id)}`;
420
- for (const name of PREFERRED_ATTRS) if (el.hasAttribute(name)) return attr(tag, name, el.getAttribute(name) || "").slice(0, 300);
426
+ for (const name of PREFERRED_ATTRS) if (el.hasAttribute(name)) return attr(tag, name, el.getAttribute(name) || "");
421
427
  for (const a of Array.from(el.attributes)) {
422
- if (a.name.startsWith("data-") && !NOISY_DATA_ATTR.test(a.name) && a.value && a.value.length <= 60) return attr(tag, a.name, a.value).slice(0, 300);
428
+ if (a.name.startsWith("data-") && !NOISY_DATA_ATTR.test(a.name) && a.value && a.value.length <= 60) return attr(tag, a.name, a.value);
423
429
  }
424
430
  const label = el.getAttribute("aria-label");
425
- if (label && label.length <= 80) return attr(tag, "aria-label", label).slice(0, 300);
431
+ if (label && label.length <= 80) return attr(tag, "aria-label", label);
426
432
  const parts = [];
427
433
  let cur = el;
428
434
  while (cur && parts.length < 4) {
@@ -438,12 +444,12 @@ function elementSelector(el) {
438
444
  parts.unshift(same.length > 1 ? `${t}:nth-of-type(${same.indexOf(node) + 1})` : t);
439
445
  cur = parent;
440
446
  }
441
- return (parts.join(" > ") || tag).slice(0, 300);
447
+ return parts.join(" > ") || tag;
442
448
  }
443
449
  function matches(el, selector, deep) {
444
450
  if (!selector) return false;
445
451
  try {
446
- return !!el.closest(selector) || deep && !!el.querySelector(selector);
452
+ return !!closestComposed2(el, selector) || deep && !!el.querySelector(selector);
447
453
  } catch {
448
454
  return false;
449
455
  }
@@ -461,7 +467,7 @@ function elementText(el, mask, maskAll) {
461
467
  return text ? text.slice(0, 100) : void 0;
462
468
  }
463
469
  function linkHref(el) {
464
- const a = el.closest("a[href]");
470
+ const a = closestComposed2(el, "a[href]");
465
471
  if (!a) return void 0;
466
472
  try {
467
473
  const u = new URL(a.getAttribute("href") || "", location.href);
@@ -1028,11 +1034,22 @@ var loadRecorder = async () => (await import("./recorder.js")).recorder;
1028
1034
 
1029
1035
  // src/client.ts
1030
1036
  var SDK_NAME = "@guidelytech/sdk-core";
1031
- var SDK_VERSION = "0.9.0";
1037
+ var SDK_VERSION = "0.10.0";
1032
1038
  var DEFAULT_API_URL = "https://api.guidely.app";
1033
1039
  var PAGE_SCOPED = /* @__PURE__ */ new Set(["page_load", "url_match", "element_click", "element_visible", "delay"]);
1034
1040
  var DAY_MS = 24 * 60 * 60 * 1e3;
1035
1041
  var MAX_SESSION_EXCEPTIONS = 100;
1042
+ var CACHED_START_MS = 1500;
1043
+ function settlesWithin(promise, ms) {
1044
+ return new Promise((resolve) => {
1045
+ const timer = setTimeout(() => resolve(false), ms);
1046
+ const done = () => {
1047
+ clearTimeout(timer);
1048
+ resolve(true);
1049
+ };
1050
+ promise.then(done, done);
1051
+ });
1052
+ }
1036
1053
  function isBrowser() {
1037
1054
  return typeof window !== "undefined" && typeof document !== "undefined";
1038
1055
  }
@@ -1053,6 +1070,8 @@ var GuidelyClient = class _GuidelyClient {
1053
1070
  __publicField(this, "sessionStore");
1054
1071
  __publicField(this, "emitter");
1055
1072
  __publicField(this, "queue");
1073
+ /** Survey answers and guide/checklist progress, kept until the server accepts them. */
1074
+ __publicField(this, "outbox");
1056
1075
  __publicField(this, "config", null);
1057
1076
  __publicField(this, "etag", null);
1058
1077
  __publicField(this, "anonymousId");
@@ -1152,6 +1171,7 @@ var GuidelyClient = class _GuidelyClient {
1152
1171
  store: this.store,
1153
1172
  storageKey: KEYS.queue(this.options.projectId),
1154
1173
  enabled: () => this.analyticsEnabled(),
1174
+ health: this.api.health,
1155
1175
  send: async (events) => {
1156
1176
  const res = await this.api.post("/events", { events, sentAt: nowIso(), sdk: { name: SDK_NAME, version: SDK_VERSION } }, { keepalive: true });
1157
1177
  return { ok: res.ok, retry: !(res.status >= 400 && res.status < 500 && res.status !== 429) };
@@ -1159,6 +1179,7 @@ var GuidelyClient = class _GuidelyClient {
1159
1179
  beacon: (events) => this.api.beacon("/events", { events, sentAt: nowIso(), sdk: { name: SDK_NAME, version: SDK_VERSION } }),
1160
1180
  onError: (err) => this.reportError(err)
1161
1181
  });
1182
+ this.outbox = new Outbox({ api: this.api, store: this.store, storageKey: KEYS.outbox(this.options.projectId), health: this.api.health });
1162
1183
  if (options.user) this.user = { ...options.user };
1163
1184
  this.flags = this.createFlags(options.flags);
1164
1185
  }
@@ -1216,12 +1237,15 @@ var GuidelyClient = class _GuidelyClient {
1216
1237
  const cached = readJson(this.store, KEYS.config(this.options.projectId), null);
1217
1238
  this.etag = this.store.get(KEYS.etag(this.options.projectId));
1218
1239
  if (cached && cached.guides) this.config = webOnly(cached);
1219
- await this.fetchConfig();
1240
+ const before = this.config?.configVersion;
1241
+ const fresh = this.fetchConfig();
1242
+ if (!this.config) await fresh;
1243
+ else if (!await settlesWithin(fresh, CACHED_START_MS)) void fresh.then(() => this.applyConfigChange(before));
1220
1244
  if (this.destroyed) return;
1221
1245
  this.wireListeners();
1222
1246
  if (!this.identitySettled) {
1223
- if (this.options.user) await this.identify(this.options.user.id, this.options.user.traits, this.options.user.account);
1224
- else if (this.user?.id) await this.identify(this.user.id, this.user.traits, this.user.account);
1247
+ const known = this.options.user ?? (this.user?.id ? this.user : null);
1248
+ if (known) await settlesWithin(this.identify(known.id, known.traits, known.account), CACHED_START_MS);
1225
1249
  }
1226
1250
  if (this.destroyed) return;
1227
1251
  this.isReady = true;
@@ -1326,7 +1350,12 @@ var GuidelyClient = class _GuidelyClient {
1326
1350
  win.removeEventListener("scroll", onScroll);
1327
1351
  doc.removeEventListener("keydown", onKey, true);
1328
1352
  });
1329
- const refresh = setInterval(() => void this.refresh(), this.options.configRefreshMs);
1353
+ const refresh = setInterval(() => {
1354
+ if (this.api.health.canSend()) void this.refresh();
1355
+ }, this.options.configRefreshMs);
1356
+ const onOnline = () => this.api.health.online();
1357
+ win.addEventListener("online", onOnline);
1358
+ this.cleanups.push(() => win.removeEventListener("online", onOnline));
1330
1359
  this.cleanups.push(() => clearInterval(refresh));
1331
1360
  const poll = setInterval(() => {
1332
1361
  if (!this.isReady || !this.config || this.editing() || doc.visibilityState === "hidden") return;
@@ -1359,6 +1388,11 @@ var GuidelyClient = class _GuidelyClient {
1359
1388
  if (this.destroyed) return;
1360
1389
  const before = this.config?.configVersion;
1361
1390
  await this.fetchConfig();
1391
+ this.applyConfigChange(before);
1392
+ }
1393
+ /** Re-renders after a config change (refresh, or a config that arrived after start). */
1394
+ applyConfigChange(before) {
1395
+ if (this.destroyed || !this.isReady) return;
1362
1396
  if (this.config && this.config.configVersion !== before) {
1363
1397
  this.renderPersistentWidgets();
1364
1398
  this.evaluate("ready");
@@ -1393,6 +1427,7 @@ var GuidelyClient = class _GuidelyClient {
1393
1427
  this.replay = null;
1394
1428
  this.queue.flushSync();
1395
1429
  this.queue.destroy();
1430
+ this.outbox.destroy();
1396
1431
  this.flags.destroy();
1397
1432
  this.emitter.clear();
1398
1433
  destroyHost();
@@ -1595,7 +1630,7 @@ var GuidelyClient = class _GuidelyClient {
1595
1630
  if (changed) void this.queue.flush();
1596
1631
  }
1597
1632
  handleDocumentClick(e) {
1598
- const target = e.target;
1633
+ const target = composedTarget(e);
1599
1634
  if (!target || typeof target.closest !== "function") return;
1600
1635
  this.autocaptureClick(e, target);
1601
1636
  this.completeChecklistTasksBy("click", target);
@@ -1690,7 +1725,7 @@ var GuidelyClient = class _GuidelyClient {
1690
1725
  }
1691
1726
  /** Bins one pointer sample into the heatmap buffer. Not session activity. */
1692
1727
  sampleMove(e) {
1693
- const target = e.target;
1728
+ const target = composedTarget(e);
1694
1729
  if (document.visibilityState === "hidden" || !target?.closest || !this.autocaptureOn("mouseMovement") || isIgnoredElement(target)) return;
1695
1730
  const url = location.href;
1696
1731
  if (this.heatmap.url !== url) this.flushHeatmap();
@@ -1815,7 +1850,9 @@ var GuidelyClient = class _GuidelyClient {
1815
1850
  this.persistSession();
1816
1851
  this.replay?.stop({ discard: true });
1817
1852
  },
1818
- onError: (err) => this.reportError(err)
1853
+ onError: (err) => this.reportError(err),
1854
+ health: this.api.health,
1855
+ stash: this.sessionStore
1819
1856
  });
1820
1857
  this.syncReplay();
1821
1858
  },
@@ -1905,7 +1942,7 @@ var GuidelyClient = class _GuidelyClient {
1905
1942
  case "element_click":
1906
1943
  if (reason !== "click" || !t.value || !detail.target) return false;
1907
1944
  try {
1908
- return !!detail.target.closest(t.value);
1945
+ return !!closestComposed3(detail.target, t.value);
1909
1946
  } catch {
1910
1947
  return false;
1911
1948
  }
@@ -2056,7 +2093,9 @@ var GuidelyClient = class _GuidelyClient {
2056
2093
  if (reason === "completed") this.completeChecklistTasksBy("guide_completed", guide);
2057
2094
  }
2058
2095
  syncGuideState(guideId, update) {
2059
- void postWithRetry(this.api, "/guide-state", { anonymousId: this.anonymousId, userId: this.user?.id || null, updates: [{ guideId, ...update }] });
2096
+ const body = { anonymousId: this.anonymousId, userId: this.user?.id || null, updates: [{ guideId, ...update }] };
2097
+ if (update.impression) void postWithRetry(this.api, "/guide-state", body);
2098
+ else this.outbox.add(`guide:${guideId}:${update.completed ? "completed" : "dismissed"}:${this.anonymousId}`, "/guide-state", body);
2060
2099
  }
2061
2100
  show(guide, manual, stepId) {
2062
2101
  try {
@@ -2184,7 +2223,7 @@ var GuidelyClient = class _GuidelyClient {
2184
2223
  this.persistState();
2185
2224
  this.recordEnd(guide, "completed");
2186
2225
  this.enqueue("survey_submitted", { guideId: guide.id, guideVersion: guide.version, properties: { responseId } });
2187
- void postWithRetry(this.api, `/surveys/${encodeURIComponent(guide.id)}/responses`, { anonymousId: this.anonymousId, userId: this.user?.id || null, accountId: this.user?.account?.id || null, guideVersion: guide.version, answers, responseId });
2226
+ this.outbox.add(`survey:${responseId}`, `/surveys/${encodeURIComponent(guide.id)}/responses`, { anonymousId: this.anonymousId, userId: this.user?.id || null, accountId: this.user?.account?.id || null, guideVersion: guide.version, answers, responseId });
2188
2227
  this.emitter.emit("survey:submit", { guide, answers, responseId });
2189
2228
  this.emitter.emit("guide:complete", guide);
2190
2229
  widget.showThankYou();
@@ -2373,7 +2412,7 @@ var GuidelyClient = class _GuidelyClient {
2373
2412
  }
2374
2413
  this.persistState();
2375
2414
  this.widgets.get(guide.id)?.checklist?.setProgress(this.getChecklistProgress(guide.id));
2376
- void postWithRetry(this.api, `/checklists/${encodeURIComponent(guide.id)}/progress`, { anonymousId: this.anonymousId, userId: this.user?.id || null, guideVersion: guide.version, completedTaskIds: progress.completedTaskIds, completed: !!progress.completedAt });
2415
+ this.outbox.add(`checklist:${guide.id}:progress:${this.anonymousId}`, `/checklists/${encodeURIComponent(guide.id)}/progress`, { anonymousId: this.anonymousId, userId: this.user?.id || null, guideVersion: guide.version, completedTaskIds: progress.completedTaskIds, completed: !!progress.completedAt });
2377
2416
  this.emitter.emit("checklist:task", { guide, task, progress: this.getChecklistProgress(guide.id) });
2378
2417
  if (complete) {
2379
2418
  this.emitter.emit("checklist:complete", guide);
@@ -2393,7 +2432,7 @@ var GuidelyClient = class _GuidelyClient {
2393
2432
  else if (kind === "guide_completed") hit = value.id === task.completionValue || value.key === task.completionValue;
2394
2433
  else if (kind === "click") {
2395
2434
  try {
2396
- hit = !!value.closest(task.completionValue);
2435
+ hit = !!closestComposed3(value, task.completionValue);
2397
2436
  } catch {
2398
2437
  hit = false;
2399
2438
  }
@@ -2413,7 +2452,7 @@ var GuidelyClient = class _GuidelyClient {
2413
2452
  progress.dismissedAt = nowIso();
2414
2453
  this.persistState();
2415
2454
  this.enqueue("checklist_dismissed", { guideId: guide.id, guideVersion: guide.version });
2416
- void postWithRetry(this.api, `/checklists/${encodeURIComponent(guide.id)}/progress`, { anonymousId: this.anonymousId, userId: this.user?.id || null, guideVersion: guide.version, completedTaskIds: progress.completedTaskIds, dismissed: true });
2455
+ this.outbox.add(`checklist:${guide.id}:dismissed:${this.anonymousId}`, `/checklists/${encodeURIComponent(guide.id)}/progress`, { anonymousId: this.anonymousId, userId: this.user?.id || null, guideVersion: guide.version, completedTaskIds: progress.completedTaskIds, dismissed: true });
2417
2456
  this.widgets.get(guide.id)?.destroy();
2418
2457
  this.widgets.delete(guide.id);
2419
2458
  }