@scalebun/web 1.3.1 → 1.5.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 (51) hide show
  1. package/dist/core/pageContext.d.ts.map +1 -1
  2. package/dist/core/pageContext.js +2 -1
  3. package/dist/core/pageContext.js.map +1 -1
  4. package/dist/core/version.generated.d.ts +9 -0
  5. package/dist/core/version.generated.d.ts.map +1 -0
  6. package/dist/core/version.generated.js +9 -0
  7. package/dist/core/version.generated.js.map +1 -0
  8. package/dist/features/bugreport/widget.d.ts.map +1 -1
  9. package/dist/features/bugreport/widget.js +1 -0
  10. package/dist/features/bugreport/widget.js.map +1 -1
  11. package/dist/features/coach/overlay.d.ts.map +1 -1
  12. package/dist/features/coach/overlay.js +1 -0
  13. package/dist/features/coach/overlay.js.map +1 -1
  14. package/dist/features/engage/widget/InAppWidget.d.ts.map +1 -1
  15. package/dist/features/engage/widget/InAppWidget.js +1 -0
  16. package/dist/features/engage/widget/InAppWidget.js.map +1 -1
  17. package/dist/features/engage/widget/SurveyWidget.d.ts.map +1 -1
  18. package/dist/features/engage/widget/SurveyWidget.js +1 -0
  19. package/dist/features/engage/widget/SurveyWidget.js.map +1 -1
  20. package/dist/features/inbox/widget/InboxWidget.d.ts.map +1 -1
  21. package/dist/features/inbox/widget/InboxWidget.js +1 -0
  22. package/dist/features/inbox/widget/InboxWidget.js.map +1 -1
  23. package/dist/features/journey/InteractionTracker.d.ts +31 -1
  24. package/dist/features/journey/InteractionTracker.d.ts.map +1 -1
  25. package/dist/features/journey/InteractionTracker.js +190 -54
  26. package/dist/features/journey/InteractionTracker.js.map +1 -1
  27. package/dist/features/journey/JourneyFeature.d.ts +1 -1
  28. package/dist/features/journey/JourneyFeature.d.ts.map +1 -1
  29. package/dist/features/journey/JourneyFeature.js +6 -4
  30. package/dist/features/journey/JourneyFeature.js.map +1 -1
  31. package/dist/features/journey/friction.d.ts +3 -4
  32. package/dist/features/journey/friction.d.ts.map +1 -1
  33. package/dist/features/journey/friction.js +7 -8
  34. package/dist/features/journey/friction.js.map +1 -1
  35. package/dist/features/journey/uiState.d.ts +50 -0
  36. package/dist/features/journey/uiState.d.ts.map +1 -0
  37. package/dist/features/journey/uiState.js +97 -0
  38. package/dist/features/journey/uiState.js.map +1 -0
  39. package/dist/features/push/softAsk.d.ts.map +1 -1
  40. package/dist/features/push/softAsk.js +1 -0
  41. package/dist/features/push/softAsk.js.map +1 -1
  42. package/dist/features/replay/engine/interactions.d.ts.map +1 -1
  43. package/dist/features/replay/engine/interactions.js +26 -7
  44. package/dist/features/replay/engine/interactions.js.map +1 -1
  45. package/dist/public/ScaleBunFacade.d.ts +22 -0
  46. package/dist/public/ScaleBunFacade.d.ts.map +1 -1
  47. package/dist/public/ScaleBunFacade.js +27 -0
  48. package/dist/public/ScaleBunFacade.js.map +1 -1
  49. package/dist/scalebun.min.js +23 -23
  50. package/dist/scalebun.min.js.map +4 -4
  51. package/package.json +6 -5
@@ -11,6 +11,8 @@
11
11
  */
12
12
  import { RageDetector, DeadClickWatcher } from './friction.js';
13
13
  import { getPositionContext } from './positionContext.js';
14
+ import { uiStateSignature } from './uiState.js';
15
+ import { getReplayCoord, uuid } from '../../core/index.js';
14
16
  export class InteractionTracker {
15
17
  constructor(emit, opts = {},
16
18
  /** Raise a capture signal ('rage'|'dead') onto the bus — arms friction-triggered features
@@ -18,6 +20,7 @@ export class InteractionTracker {
18
20
  signal) {
19
21
  this.emit = emit;
20
22
  this.signal = signal;
23
+ this.pending = new Map();
21
24
  this.rage = new RageDetector(opts.rageWindowMs ?? 800, opts.rageRadius ?? 30, opts.rageMin ?? 3);
22
25
  this.dead = new DeadClickWatcher(opts.deadMs ?? 700);
23
26
  this.maskText = opts.maskText ?? false;
@@ -26,42 +29,159 @@ export class InteractionTracker {
26
29
  if (typeof document === 'undefined')
27
30
  return;
28
31
  this.dead.observe(document);
32
+ this.onPointerDownFn = (e) => {
33
+ const pe = e;
34
+ if (pe.isPrimary === false || (typeof pe.button === 'number' && pe.button !== 0))
35
+ return;
36
+ const target = eventTarget(e);
37
+ if (!target)
38
+ return;
39
+ this.pointerDown = capture(target, pe, Date.now(), this.maskText);
40
+ };
29
41
  this.onClickFn = (e) => {
30
42
  const me = e;
31
- const t = Date.now();
32
- const target = e.target;
33
- if (!target || !target.tagName)
43
+ const target = eventTarget(e);
44
+ if (!target)
34
45
  return;
35
- const label = describe(target, this.maskText);
36
- const selector = selectorOf(target);
37
- // Viewport + scroll at click time the dashboard normalizes click positions across screen
38
- // sizes (heatmaps). Compact keys keep the event small.
39
- const p = pointer(me);
40
- // H7 — element anchoring + component identity. The target's bounding rect lets the dashboard re-project
41
- // a hotspot onto the element at any viewport (responsive), and `component` (opt-in data-scalebun-component,
42
- // walked up ancestors) groups clicks BY reusable component across every route it appears on.
43
- const el = anchor(target);
44
- const rage = this.rage.push(me.clientX, me.clientY, t);
45
- const data = { action: 'click', ...p, selector, ...el };
46
+ const down = this.pointerDown;
47
+ this.pointerDown = undefined;
48
+ // A real pointer click reuses the evidence captured when the finger/button landed. Keyboard
49
+ // and programmatic clicks have no pointerdown and are measured honestly at click time.
50
+ const captured = me.detail !== 0 && down && down.target === target && Date.now() - down.timestamp < 5000
51
+ ? down
52
+ : capture(target, me, Date.now(), this.maskText);
53
+ const rage = this.rage.push(captured.x, captured.y, captured.timestamp);
46
54
  if (rage)
47
- data.rage = true;
48
- this.emit('USER_ACTION', data, label);
55
+ captured.data.rage = true;
49
56
  if (rage)
50
57
  this.signal?.('rage'); // RageDetector coalesces → one signal per cluster
51
- this.dead.onClick(t, () => {
52
- this.emit('USER_ACTION', { action: 'click', ...p, selector, ...el, dead: true }, label);
53
- this.signal?.('dead'); // resolved async (no follow-up DOM change within deadMs)
58
+ this.pending.set(captured.interactionId, captured);
59
+ this.dead.onClick((dead) => {
60
+ this.finish(captured.interactionId, dead);
61
+ if (dead)
62
+ this.signal?.('dead');
54
63
  });
55
64
  };
65
+ this.onPageHideFn = () => this.flushPending();
66
+ document.addEventListener('pointerdown', this.onPointerDownFn, true);
56
67
  document.addEventListener('click', this.onClickFn, true);
68
+ if (typeof window !== 'undefined')
69
+ window.addEventListener('pagehide', this.onPageHideFn, true);
57
70
  }
58
71
  stop() {
72
+ this.flushPending();
59
73
  this.dead.disconnect();
60
- if (this.onClickFn && typeof document !== 'undefined') {
61
- document.removeEventListener('click', this.onClickFn, true);
74
+ if (typeof document !== 'undefined') {
75
+ if (this.onPointerDownFn)
76
+ document.removeEventListener('pointerdown', this.onPointerDownFn, true);
77
+ if (this.onClickFn)
78
+ document.removeEventListener('click', this.onClickFn, true);
62
79
  }
80
+ if (this.onPageHideFn && typeof window !== 'undefined') {
81
+ window.removeEventListener('pagehide', this.onPageHideFn, true);
82
+ }
83
+ this.pointerDown = undefined;
84
+ }
85
+ /**
86
+ * Emit the one row for this interaction.
87
+ *
88
+ * `dead` is THREE-VALUED here, and that is the point. `true` and `false` are verdicts the watcher
89
+ * actually reached; `undefined` means the page went away before the observation window closed, so
90
+ * nobody looked. Writing `dead: false` in that case asserts a measurement never taken — "this click
91
+ * DID cause a change" — and a dead-click rate computed from it is wrong in exactly the situation
92
+ * where dead clicks matter most: the visitor left immediately after clicking.
93
+ *
94
+ * So the key is omitted rather than defaulted, the same rule the rest of this pipeline follows:
95
+ * absent means unknown, never zero. `deadUnknown` records WHY it is absent, so a consumer can tell
96
+ * "not dead" from "we never found out".
97
+ */
98
+ finish(interactionId, dead) {
99
+ const captured = this.pending.get(interactionId);
100
+ if (!captured)
101
+ return;
102
+ this.pending.delete(interactionId);
103
+ if (dead === true)
104
+ captured.data.dead = true;
105
+ else if (dead === undefined)
106
+ captured.data.deadUnknown = true;
107
+ this.emit('USER_ACTION', captured.data, captured.label, {
108
+ interactionId,
109
+ timestamp: captured.timestamp,
110
+ });
111
+ }
112
+ /**
113
+ * Flush every interaction still awaiting its dead-click verdict.
114
+ *
115
+ * Runs on `pagehide` and on `stop()`. Without it a click followed immediately by a navigation is
116
+ * never emitted at all — the whole row is lost, which is strictly worse than an unknown flag. The
117
+ * verdict is passed as `undefined` because none was reached; see finish().
118
+ */
119
+ flushPending() {
120
+ for (const interactionId of [...this.pending.keys()])
121
+ this.finish(interactionId, undefined);
63
122
  }
64
123
  }
124
+ function eventTarget(e) {
125
+ // SHADOW DOM — see the note below. `e.target` is retargeted to the host, so the composed
126
+ // path is what identifies the control. Our own surfaces stay reported as their host, which
127
+ // is what keeps the query-side exclusion matching them.
128
+ let target = e.target;
129
+ if (!target || !target.tagName)
130
+ return null;
131
+ if (!target.hasAttribute('data-scalebun')) {
132
+ const deep = e.composedPath?.()[0];
133
+ if (deep && deep.tagName)
134
+ target = deep;
135
+ }
136
+ return target;
137
+ }
138
+ function capture(target, pointerEvent, timestamp, maskText) {
139
+ const ui = uiStateSignature();
140
+ const data = {
141
+ action: 'click',
142
+ ...pointer(pointerEvent),
143
+ selector: selectorOf(target),
144
+ ...anchor(target),
145
+ state_status: ui ? 'captured_nonempty' : 'captured_empty',
146
+ };
147
+ if (ui)
148
+ data.ui = ui;
149
+ const replay = getReplayCoord();
150
+ if (replay)
151
+ data.replayCoord = replay;
152
+ return {
153
+ target,
154
+ x: pointerEvent.clientX,
155
+ y: pointerEvent.clientY,
156
+ data,
157
+ label: describe(target, maskText),
158
+ interactionId: `ixw-${uuid()}`,
159
+ timestamp,
160
+ };
161
+ }
162
+ /**
163
+ * The element the visitor actually clicked, not the wrapper the browser reports.
164
+ *
165
+ * `event.target` is RETARGETED at a shadow boundary: a click on a button inside a web component is
166
+ * reported as a click on the component's host, so every control inside it collapses onto one
167
+ * element and neither the selector nor the path describes what was hit. `composedPath()[0]` is the
168
+ * real node, and both of the SDK's other capture lanes already use it — the replay engine says so
169
+ * outright ("composedPath()[0] beats e.target, which is the host"). This lane was the one that
170
+ * never got the fix, and it is the lane heatmaps read.
171
+ *
172
+ * OUR OWN WIDGETS ARE DELIBERATELY NOT UNWRAPPED. Every ScaleBun surface — in-app, inbox, survey,
173
+ * coachmark, soft-ask, bug report — is mounted in a shadow root too, and the query layer keeps
174
+ * those clicks out of customer heatmaps by matching the HOST's selector. Resolving through them
175
+ * would produce an inner control the filter does not recognise, so clicks on ScaleBun's own UI
176
+ * would start being reported as clicks on the customer's page. Reporting the host for our surfaces
177
+ * is therefore not a limitation, it is what keeps the existing exclusion working — and it keeps
178
+ * that decision in one place rather than splitting it across two repos.
179
+ *
180
+ * Falls back to `event.target` whenever the composed path is unavailable or its first entry is not
181
+ * an element (text nodes, the document, a closed root's boundary), so nothing is lost when the
182
+ * answer cannot be improved.
183
+ */
184
+ /* resolution happens inline in the click handler — see the note above. */
65
185
  /** Click position + viewport + scroll + document height, so the dashboard can place clicks in
66
186
  * viewport-% or DOCUMENT space across different screen sizes. `x`/`y` are viewport-relative (clientX/Y).
67
187
  *
@@ -86,6 +206,44 @@ function pointer(me) {
86
206
  dpr: w?.devicePixelRatio ?? 1,
87
207
  };
88
208
  }
209
+ /**
210
+ * A CONTRADICTION SIGNAL, NOT A LOCATOR — one independent fact about what was clicked.
211
+ *
212
+ * `path` resolves uniquely on real markup (measured 30/30 on the reported site) but is FRAGILE: one
213
+ * inserted sibling shifts an `nth-of-type` segment onto a different control, and the reader has no
214
+ * way to notice. This field exists so it can notice. When the element a stored path resolves to
215
+ * contradicts this, the reader refuses to anchor.
216
+ *
217
+ * IT MAY ONLY EVER REFUSE. Agreement is not evidence of identity: a duplicate sibling carrying the
218
+ * same href satisfies it exactly, which is why promoting on agreement was measured and rejected —
219
+ * it raised silent mis-anchors from 12 to 14 across 156 adversarial trials while looking like an
220
+ * improvement. Refusal-only took them from 12 to 2 and cannot, by construction, add an anchor.
221
+ *
222
+ * PRIVACY. Only the three signals below, in this order, and nothing derived from user text:
223
+ * · href PATHNAME — query string and fragment stripped, so tokens, emails and ids never travel.
224
+ * · aria-label — author-written UI wording, capped at 32 chars and rejected outright if it carries
225
+ * an address or a long digit run, which is what a personalised label looks like.
226
+ * · type — a build-time constant on form controls.
227
+ * Deliberately excluded: visible text, input values, full URLs, class lists.
228
+ *
229
+ * One optional field, absent when nothing safe is available, so the common case adds no bytes and an
230
+ * old reader that ignores it behaves exactly as before.
231
+ */
232
+ function constraintOf(el) {
233
+ // Same normalisation as `stripQuery` in core/breadcrumbs and performance/resources — one regex,
234
+ // and it drops the fragment as well, so `#anchor` links reduce to their path.
235
+ const h = (el.getAttribute('href') || '').replace(/[?#].*$/, '');
236
+ // No `javascript:` guard: this is a comparison token, not a URL to follow, so an odd scheme is
237
+ // harmless and the check cost more bytes than the case is worth.
238
+ if (h)
239
+ return 'h' + h;
240
+ const a = (el.getAttribute('aria-label') || '').trim();
241
+ // A long digit run or an address is what a personalised label looks like — refuse those.
242
+ if (a && a.length < 33 && !/@|\d{4,}/.test(a))
243
+ return 'a' + a;
244
+ const t = el.getAttribute('type');
245
+ return t ? 'y' + t : undefined;
246
+ }
89
247
  /** H7 — element bounding rect (for responsive re-anchoring) + opt-in component name (for component heatmaps). */
90
248
  function anchor(el) {
91
249
  const r = el.getBoundingClientRect();
@@ -110,43 +268,14 @@ function anchor(el) {
110
268
  if (pc)
111
269
  out.fx = pc;
112
270
  out.path = structuralPath(el);
113
- const ui = openOverlays();
114
- if (ui)
115
- out.ui = ui;
271
+ const cx = constraintOf(el);
272
+ if (cx)
273
+ out.cx = cx;
116
274
  const comp = el.closest('[data-scalebun-component]')?.getAttribute('data-scalebun-component');
117
275
  if (comp)
118
276
  out.component = comp;
119
277
  return out;
120
278
  }
121
- /**
122
- * S1 — WHICH OVERLAYS WERE OPEN when this click happened.
123
- *
124
- * A click on a menu item only means something if the menu was open. Nothing stored today says so, and
125
- * it is not derivable afterwards from anything else on the event — the same lesson as `fx` and
126
- * `path`: capture has to lead use, and history cannot be backfilled. Without this the dashboard can
127
- * SHOW a state (the viewer can open and close the reconstruction) but cannot COUNT one, because every
128
- * click on the route is aggregated into a single picture regardless of what was on screen.
129
- *
130
- * PLATFORM-DEFINED STATE ONLY: `aria-expanded="true"` and `<dialog open>`. Deliberately no guessing at
131
- * `.menu-open` or `.is-active` — a class heuristic is right on some sites and silently wrong on
132
- * others, and a wrong state key partitions clicks into buckets that do not correspond to anything.
133
- *
134
- * SORTED, so the same set of open overlays produces the same key whatever order the DOM happens to
135
- * return them in — otherwise one state would fragment into several and the counts would be
136
- * meaningless.
137
- *
138
- * Emitted ONLY when something is open, exactly as `fx` is. The overwhelming majority of clicks happen
139
- * with nothing open and pay nothing at all; the length cap bounds the rest.
140
- */
141
- function openOverlays() {
142
- const out = [];
143
- document.querySelectorAll('[aria-expanded="true"],dialog[open]').forEach((e) => {
144
- const k = e.getAttribute('aria-controls') || e.getAttribute('aria-label') || e.id;
145
- if (k)
146
- out.push(k);
147
- });
148
- return out.length ? out.sort().join('|').slice(0, 64) : undefined;
149
- }
150
279
  /**
151
280
  * True when this click landed on a VIEWPORT-anchored element — one that does not move as the page
152
281
  * scrolls, because it or an ancestor computes to `position: fixed`.
@@ -253,7 +382,14 @@ export function describe(el, maskText = false) {
253
382
  return tag;
254
383
  return `${tag}: ${maskText ? mask(text) : text}`;
255
384
  }
256
- /** A compact CSS-ish selector (tag#id.class) — structure only, no text/PII. */
385
+ /**
386
+ * A compact CSS-ish selector (tag#id.class) — structure only, no text/PII.
387
+ *
388
+ * Byte-identical to autocapture's copy, and DELIBERATELY left duplicated. Sharing it through a
389
+ * `core/` module was tried and measured: the eager bundle grew 136 B rather than shrinking, because
390
+ * gzip already collapses the second copy to almost nothing while a new module boundary costs real
391
+ * bytes. Deduplicate this only if the two lanes ever need to agree on the value, not to save space.
392
+ */
257
393
  function selectorOf(el) {
258
394
  let s = el.tagName.toLowerCase();
259
395
  if (el.id)
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionTracker.js","sourceRoot":"","sources":["../../../src/features/journey/InteractionTracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"InteractionTracker.js","sourceRoot":"","sources":["../../../src/features/journey/InteractionTracker.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * F-JRN — journey + navigation. Emits SCREEN_VIEW (route changes) and USER_ACTION (clicks + rage/dead
2
+ * F-JRN — journey + navigation. Emits SCREEN_VIEW (route changes) and USER_ACTION (clicks enriched with rage/dead
3
3
  * friction) as `kind:'event'` items → the existing funnels / flows / friction analytics. Always-on,
4
4
  * decoupled from replay.
5
5
  */
@@ -1 +1 @@
1
- {"version":3,"file":"JourneyFeature.d.ts","sourceRoot":"","sources":["../../../src/features/journey/JourneyFeature.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAMxE,qBAAa,cAAe,YAAW,QAAQ;IAC7C,QAAQ,CAAC,IAAI,aAAa;IAC1B,OAAO,CAAC,GAAG,CAA+B;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,GAAG,CAAC,CAAoB;IAChC,OAAO,CAAC,YAAY,CAAC,CAAqB;IAE1C,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,KAAK,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI;IAmBhC,OAAO,CAAC,IAAI;IAkBZ,QAAQ,IAAI,IAAI;CAKjB"}
1
+ {"version":3,"file":"JourneyFeature.d.ts","sourceRoot":"","sources":["../../../src/features/journey/JourneyFeature.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAMxE,qBAAa,cAAe,YAAW,QAAQ;IAC7C,QAAQ,CAAC,IAAI,aAAa;IAC1B,OAAO,CAAC,GAAG,CAA+B;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,GAAG,CAAC,CAAoB;IAChC,OAAO,CAAC,YAAY,CAAC,CAAqB;IAE1C,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,KAAK,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI;IAoBhC,OAAO,CAAC,IAAI;IA0BZ,QAAQ,IAAI,IAAI;CAKjB"}
@@ -15,7 +15,7 @@ export class JourneyFeature {
15
15
  if (typeof window === 'undefined' || typeof document === 'undefined')
16
16
  return;
17
17
  this.nav = new NavigationTracker((from, to) => this.emit('SCREEN_VIEW', { from, to }, undefined, to));
18
- this.interactions = new InteractionTracker((name, data, label) => this.emit(name, data, label, currentPath()),
18
+ this.interactions = new InteractionTracker((name, data, label, interaction) => this.emit(name, data, label, currentPath(), interaction),
19
19
  // Label masking is opt-IN (`privacy.maskEventText`). Off by default so USER_ACTION rows carry the
20
20
  // real element text and group per element instead of collapsing by text shape.
21
21
  { maskText: ctx.maskEventText === true }, (reason) => this.ctx?.signal(reason));
@@ -23,12 +23,12 @@ export class JourneyFeature {
23
23
  this.interactions.start();
24
24
  this.active = true;
25
25
  }
26
- emit(name, props, label, screenName) {
26
+ emit(name, props, label, screenName, interaction) {
27
27
  // Heatmaps 2.0 (H5) — stamp WHERE the replay was when this happened, so a heatmap hotspot (or friction
28
28
  // click) deep-links to the EXACT replay frame, not just the session. Cheap (a getter + spread); only
29
29
  // present when replay is producing frames (undefined otherwise). Closes the journey↔replay gap that
30
30
  // left the richest heatmap signal (clicks + rage/dead) without a frame coordinate.
31
- const replay = getReplayCoord();
31
+ const replay = props.replayCoord ? undefined : getReplayCoord();
32
32
  const item = {
33
33
  kind: 'event',
34
34
  name,
@@ -36,7 +36,9 @@ export class JourneyFeature {
36
36
  label,
37
37
  screenName: screenName ?? currentPath(),
38
38
  eventId: `evt_${uuid()}`,
39
- timestamp: now(),
39
+ timestamp: interaction?.timestamp ?? now(),
40
+ interactionId: interaction?.interactionId,
41
+ interactionProtocol: interaction ? 1 : undefined,
40
42
  };
41
43
  this.ctx?.emit(item);
42
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"JourneyFeature.js","sourceRoot":"","sources":["../../../src/features/journey/JourneyFeature.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,OAAO,cAAc;IAA3B;QACW,SAAI,GAAG,SAAS,CAAC;QAClB,QAAG,GAA0B,IAAI,CAAC;QAClC,WAAM,GAAG,KAAK,CAAC;IAkDzB,CAAC;IA9CC,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,GAAmB;QACvB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW;YAAE,OAAO;QAE7E,IAAI,CAAC,GAAG,GAAG,IAAI,iBAAiB,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAC5C,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,CACtD,CAAC;QACF,IAAI,CAAC,YAAY,GAAG,IAAI,kBAAkB,CACxC,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;QAClE,kGAAkG;QAClG,+EAA+E;QAC/E,EAAE,QAAQ,EAAE,GAAG,CAAC,aAAa,KAAK,IAAI,EAAE,EACxC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CACrC,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACjB,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;IAEO,IAAI,CAAC,IAAY,EAAE,KAA8B,EAAE,KAAc,EAAE,UAAmB;QAC5F,uGAAuG;QACvG,qGAAqG;QACrG,oGAAoG;QACpG,mFAAmF;QACnF,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,OAAO;YACb,IAAI;YACJ,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK;YACzD,KAAK;YACL,UAAU,EAAE,UAAU,IAAI,WAAW,EAAE;YACvC,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE;YACxB,SAAS,EAAE,GAAG,EAAE;SACJ,CAAC;QACf,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QACjB,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;CACF;AAED,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,OAAO,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"JourneyFeature.js","sourceRoot":"","sources":["../../../src/features/journey/JourneyFeature.ts"],"names":[],"mappings":"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"}
@@ -16,14 +16,13 @@ export declare class RageDetector {
16
16
  /** Fires a callback when a click had NO DOM change and NO navigation within `deadMs`. */
17
17
  export declare class DeadClickWatcher {
18
18
  private readonly deadMs;
19
- private lastChangeT;
19
+ private changeVersion;
20
20
  private observer;
21
21
  private timers;
22
- private startHref;
23
22
  constructor(deadMs?: number);
24
23
  observe(target: Node): void;
25
- /** Call on each click. `onDead` runs later iff the click produced no DOM change + no navigation. */
26
- onClick(at: number, onDead: () => void): void;
24
+ /** Resolve exactly once after the observation window. `true` means no DOM change + no navigation. */
25
+ onClick(onResult: (dead: boolean) => void): void;
27
26
  disconnect(): void;
28
27
  }
29
28
  //# sourceMappingURL=friction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"friction.d.ts","sourceRoot":"","sources":["../../../src/features/journey/friction.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,yGAAyG;AACzG,qBAAa,YAAY;IAGrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJtB,OAAO,CAAC,OAAO,CAAkD;gBAE9C,QAAQ,SAAM,EACd,MAAM,SAAK,EACX,GAAG,SAAI;IAG1B,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;CAM/C;AAED,yFAAyF;AACzF,qBAAa,gBAAgB;IAMf,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,SAAS,CAAM;gBAEM,MAAM,SAAM;IAEzC,OAAO,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI;IAS3B,oGAAoG;IACpG,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI;IAQ7C,UAAU,IAAI,IAAI;CAMnB"}
1
+ {"version":3,"file":"friction.d.ts","sourceRoot":"","sources":["../../../src/features/journey/friction.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,yGAAyG;AACzG,qBAAa,YAAY;IAGrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJtB,OAAO,CAAC,OAAO,CAAkD;gBAE9C,QAAQ,SAAM,EACd,MAAM,SAAK,EACX,GAAG,SAAI;IAG1B,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;CAM/C;AAED,yFAAyF;AACzF,qBAAa,gBAAgB;IAKf,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,MAAM,CAA4C;gBAE7B,MAAM,SAAM;IAEzC,OAAO,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI;IAQ3B,qGAAqG;IACrG,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAUhD,UAAU,IAAI,IAAI;CAMnB"}
@@ -23,26 +23,25 @@ export class RageDetector {
23
23
  export class DeadClickWatcher {
24
24
  constructor(deadMs = 700) {
25
25
  this.deadMs = deadMs;
26
- this.lastChangeT = 0;
26
+ this.changeVersion = 0;
27
27
  this.observer = null;
28
28
  this.timers = new Set();
29
- this.startHref = '';
30
29
  }
31
30
  observe(target) {
32
31
  if (typeof MutationObserver === 'undefined')
33
32
  return;
34
- this.startHref = href();
35
33
  this.observer = new MutationObserver(() => {
36
- this.lastChangeT = Date.now();
34
+ this.changeVersion++;
37
35
  });
38
36
  this.observer.observe(target, { subtree: true, childList: true, attributes: true, characterData: true });
39
37
  }
40
- /** Call on each click. `onDead` runs later iff the click produced no DOM change + no navigation. */
41
- onClick(at, onDead) {
38
+ /** Resolve exactly once after the observation window. `true` means no DOM change + no navigation. */
39
+ onClick(onResult) {
40
+ const version = this.changeVersion;
41
+ const startHref = href();
42
42
  const timer = setTimeout(() => {
43
43
  this.timers.delete(timer);
44
- if (this.lastChangeT < at && href() === this.startHref)
45
- onDead();
44
+ onResult(this.changeVersion === version && href() === startHref);
46
45
  }, this.deadMs);
47
46
  this.timers.add(timer);
48
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"friction.js","sourceRoot":"","sources":["../../../src/features/journey/friction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"friction.js","sourceRoot":"","sources":["../../../src/features/journey/friction.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,yGAAyG;AACzG,MAAM,OAAO,YAAY;IAEvB,YACmB,WAAW,GAAG,EACd,SAAS,EAAE,EACX,MAAM,CAAC;QAFP,aAAQ,GAAR,QAAQ,CAAM;QACd,WAAM,GAAN,MAAM,CAAK;QACX,QAAG,GAAH,GAAG,CAAI;QAJlB,YAAO,GAA+C,EAAE,CAAC;IAK9D,CAAC;IAEJ,IAAI,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS;QAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC;QACrF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC;IACrC,CAAC;CACF;AAED,yFAAyF;AACzF,MAAM,OAAO,gBAAgB;IAK3B,YAA6B,SAAS,GAAG;QAAZ,WAAM,GAAN,MAAM,CAAM;QAJjC,kBAAa,GAAG,CAAC,CAAC;QAClB,aAAQ,GAA4B,IAAI,CAAC;QACzC,WAAM,GAAG,IAAI,GAAG,EAAiC,CAAC;IAEd,CAAC;IAE7C,OAAO,CAAC,MAAY;QAClB,IAAI,OAAO,gBAAgB,KAAK,WAAW;YAAE,OAAO;QACpD,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE;YACxC,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,qGAAqG;IACrG,OAAO,CAAC,QAAiC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,aAAa,KAAK,OAAO,IAAI,IAAI,EAAE,KAAK,SAAS,CAAC,CAAC;QACnE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,UAAU;QACR,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF;AAED,SAAS,IAAI;IACX,IAAI,CAAC;QACH,OAAO,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * UI STATE AT INTERACTION TIME — which visual surface the visitor was actually looking at.
3
+ *
4
+ * A page is not just `/products`. It is `/products` with the cart drawer shut, or with it open, or
5
+ * with the reviews tab selected. Those are different interaction surfaces, and a click on one must
6
+ * never be counted on another: heat from the open drawer painted over the closed layout is a picture
7
+ * of something that never existed.
8
+ *
9
+ * WHAT WAS WRONG WITH THE PREVIOUS SHAPE. State was captured as an opaque set of the things that
10
+ * happened to be OPEN — `menu|dialog`, sorted and joined. Two consequences:
11
+ *
12
+ * 1. `sidebar = closed` was not representable. Absence meant "nothing open", which conflates a shut
13
+ * sidebar with a page that has no sidebar. But the click that OPENS a drawer belongs to the
14
+ * closed state — that is what the visitor saw when they reached for it — so the closed value has
15
+ * to exist to receive it.
16
+ * 2. It could not be queried by dimension. Asking for `sidebar=open` meant matching the whole
17
+ * signature, so every unrelated dimension had to match too and the buckets fragmented
18
+ * combinatorially.
19
+ *
20
+ * THE SHAPE NOW: `name:value` pairs, sorted, joined with `;`. Still ONE short string on the wire — no
21
+ * new field — but the backend can split it and match one dimension without constraining the others.
22
+ *
23
+ * DELIBERATELY NARROW, because every byte here is eager. Only `aria-expanded` (read in BOTH states,
24
+ * which is what makes "closed" a value rather than an absence) and `dialog` (likewise). No
25
+ * `aria-selected`, no `aria-current`, no `details` — those were measured at ~90 B of bundle for
26
+ * dimensions the host can declare explicitly for free. No class-name guessing at any price: `.is-open`
27
+ * is right on some sites and silently wrong on others, and a wrong state key partitions clicks into
28
+ * buckets that correspond to nothing.
29
+ *
30
+ * Anything the platform does not express is `setUiState`'s job, and an explicit dimension WINS for the
31
+ * same name — a heuristic that silently overrode a declaration would make the API pointless.
32
+ */
33
+ /** Declare a UI state dimension the DOM does not express. */
34
+ export declare function setUiState(name: string, value: string): void;
35
+ /**
36
+ * Stop reporting a dimension — or, with no name, every declared dimension.
37
+ *
38
+ * Later interactions carry no value for it, which is not the same as carrying a value. Clearing all is
39
+ * what a single-page app wants on route change: declarations from the previous screen would otherwise
40
+ * follow the visitor onto a surface where they mean nothing.
41
+ */
42
+ export declare function clearUiState(name?: string): void;
43
+ /**
44
+ * The state signature for the interaction happening RIGHT NOW.
45
+ *
46
+ * Read synchronously inside the event handler, never reconstructed afterwards: by the time a menu has
47
+ * closed, the DOM no longer knows it was open when the click landed.
48
+ */
49
+ export declare function uiStateSignature(): string | undefined;
50
+ //# sourceMappingURL=uiState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uiState.d.ts","sourceRoot":"","sources":["../../../src/features/journey/uiState.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAaH,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI5D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAGhD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CA2BrD"}