@reticlehq/browser 3.2.0 → 3.4.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 (83) hide show
  1. package/dist/actions/actions-dom.d.ts +6 -5
  2. package/dist/actions/actions-dom.js +5 -4
  3. package/dist/actions/actions-press.d.ts +3 -3
  4. package/dist/actions/actions-press.js +0 -3
  5. package/dist/actions/actions.d.ts +0 -1
  6. package/dist/actions/actions.js +17 -13
  7. package/dist/actions/check-state.d.ts +5 -0
  8. package/dist/actions/check-state.js +24 -0
  9. package/dist/actions/danger-context.d.ts +3 -2
  10. package/dist/actions/danger-context.js +2 -1
  11. package/dist/actions/value-input.d.ts +2 -1
  12. package/dist/actions/value-input.js +15 -6
  13. package/dist/connect-options.d.ts +1 -0
  14. package/dist/dom/a11y.js +43 -3
  15. package/dist/dom/addressing/source.d.ts +2 -1
  16. package/dist/dom/dom-ignore.d.ts +1 -0
  17. package/dist/dom/dom-ignore.js +13 -0
  18. package/dist/dom/query.js +6 -4
  19. package/dist/dom/realm.d.ts +6 -0
  20. package/dist/dom/realm.js +5 -0
  21. package/dist/dom/snapshot.d.ts +1 -1
  22. package/dist/dom/snapshot.js +8 -2
  23. package/dist/observers/console.js +38 -13
  24. package/dist/observers/dom.js +3 -1
  25. package/dist/observers/download.js +3 -2
  26. package/dist/observers/error-repeats.d.ts +18 -0
  27. package/dist/observers/error-repeats.js +41 -0
  28. package/dist/observers/field.d.ts +2 -0
  29. package/dist/observers/field.js +86 -0
  30. package/dist/observers/frames.js +3 -4
  31. package/dist/observers/install-all.js +2 -0
  32. package/dist/observers/net-detail/network-body.d.ts +2 -0
  33. package/dist/observers/net-detail/network-body.js +24 -7
  34. package/dist/observers/network.js +14 -1
  35. package/dist/observers/route.js +4 -4
  36. package/dist/observers/state.js +21 -8
  37. package/dist/presenter/carousel/carousel.d.ts +13 -0
  38. package/dist/presenter/carousel/carousel.js +126 -0
  39. package/dist/presenter/carousel/offer-card.d.ts +21 -0
  40. package/dist/presenter/carousel/offer-card.js +55 -0
  41. package/dist/presenter/carousel/panel-slides.d.ts +7 -0
  42. package/dist/presenter/carousel/panel-slides.js +10 -0
  43. package/dist/presenter/carousel/talk-card.d.ts +8 -0
  44. package/dist/presenter/carousel/talk-card.js +20 -0
  45. package/dist/presenter/chrome/presenter-log.d.ts +2 -1
  46. package/dist/presenter/chrome/presenter-log.js +14 -3
  47. package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -1
  48. package/dist/presenter/chrome/presenter-report-copy.js +1 -1
  49. package/dist/presenter/hud-telemetry.d.ts +3 -0
  50. package/dist/presenter/hud-telemetry.js +87 -0
  51. package/dist/presenter/presenter-account.js +1 -1
  52. package/dist/presenter/presenter-config.d.ts +5 -1
  53. package/dist/presenter/presenter-config.js +4 -1
  54. package/dist/presenter/presenter-controls.d.ts +1 -0
  55. package/dist/presenter/presenter-controls.js +12 -1
  56. package/dist/presenter/presenter-report.js +6 -6
  57. package/dist/presenter/presenter-settings-styles.js +2 -1
  58. package/dist/presenter/presenter-settings.d.ts +2 -4
  59. package/dist/presenter/presenter-settings.js +13 -4
  60. package/dist/presenter/presenter-shell-styles.js +4 -0
  61. package/dist/presenter/presenter-shell.d.ts +4 -1
  62. package/dist/presenter/presenter-shell.js +49 -11
  63. package/dist/presenter/presenter-styles.js +5 -1
  64. package/dist/presenter/presenter-workspace.d.ts +0 -7
  65. package/dist/presenter/presenter-workspace.js +7 -7
  66. package/dist/presenter/presenter.js +43 -10
  67. package/dist/presenter/tour/tour.d.ts +3 -0
  68. package/dist/presenter/tour/tour.js +5 -0
  69. package/dist/recorder/recorder.js +25 -22
  70. package/dist/registry/store-adapters.js +32 -2
  71. package/dist/registry/stores/adapters.js +8 -2
  72. package/dist/reticle-inject.d.ts +2 -0
  73. package/dist/reticle-inject.js +1337 -0
  74. package/dist/reticle.js +6 -0
  75. package/dist/review/annotator.d.ts +3 -1
  76. package/dist/review/annotator.js +37 -40
  77. package/dist/review/marks-for-agent.d.ts +9 -0
  78. package/dist/review/marks-for-agent.js +12 -0
  79. package/dist/util/captured-method.d.ts +0 -1
  80. package/dist/util/captured-method.js +1 -1
  81. package/package.json +15 -11
  82. package/dist/presenter/presenter-offer.d.ts +0 -25
  83. package/dist/presenter/presenter-offer.js +0 -87
@@ -14,7 +14,7 @@ const PROJECT_LABEL = 'Project';
14
14
  const COPY_PATH_LABEL = 'Copy path';
15
15
  const COPIED_PATH_LABEL = 'Copied';
16
16
  const WORKSPACE_FALLBACK = 'This page';
17
- export function readWorkspaceRoot() {
17
+ function readWorkspaceRoot() {
18
18
  const value = globalThis[RETICLE_ROOT_GLOBAL];
19
19
  return 'string' === typeof value && value.length > 0 ? value : undefined;
20
20
  }
@@ -24,13 +24,13 @@ export function workspaceFolderLabel(root) {
24
24
  const last = parts[parts.length - 1];
25
25
  return last !== undefined && last.length > 0 ? last : WORKSPACE_FALLBACK;
26
26
  }
27
- export function readProjectIdFromUrl() {
27
+ function readProjectIdFromUrl() {
28
28
  if ('undefined' === typeof window)
29
29
  return undefined;
30
30
  const id = new URLSearchParams(window.location.search).get(RETICLE_URL_PARAM.PROJECT);
31
31
  return id !== null && id.length > 0 ? id : undefined;
32
32
  }
33
- export function workspaceSummary() {
33
+ function workspaceSummary() {
34
34
  const root = readWorkspaceRoot();
35
35
  const projectId = readProjectIdFromUrl();
36
36
  const folder = root !== undefined ? workspaceFolderLabel(root) : WORKSPACE_FALLBACK;
@@ -106,6 +106,7 @@ export function paintWorkspace(root) {
106
106
  }
107
107
  }
108
108
  export function mountWorkspaceSelector(root) {
109
+ const ac = new AbortController();
109
110
  paintWorkspace(root);
110
111
  const btn = root.querySelector(`[${WORKSPACE_BTN_ATTR}]`);
111
112
  const menu = root.querySelector(`[${WORKSPACE_MENU_ATTR}]`);
@@ -183,13 +184,12 @@ export function mountWorkspaceSelector(root) {
183
184
  btn.addEventListener('click', onBtnClick);
184
185
  menu.addEventListener('pointerdown', (e) => e.stopPropagation());
185
186
  copyBtn?.addEventListener('click', onCopy);
186
- document.addEventListener('pointerdown', onDocPointer);
187
- document.addEventListener('keydown', onKeyDown);
187
+ document.addEventListener('pointerdown', onDocPointer, { signal: ac.signal });
188
+ document.addEventListener('keydown', onKeyDown, { signal: ac.signal });
188
189
  return () => {
189
190
  btn.removeEventListener('click', onBtnClick);
190
191
  copyBtn?.removeEventListener('click', onCopy);
191
- document.removeEventListener('pointerdown', onDocPointer);
192
- document.removeEventListener('keydown', onKeyDown);
192
+ ac.abort();
193
193
  };
194
194
  }
195
195
  export function paintToolbarAccount(root, account, dashboardUrl, details = {}) {
@@ -3,19 +3,22 @@ import { refs } from '../dom/addressing/refs.js';
3
3
  import { unreachableStripText } from '../transport/unreachable-message.js';
4
4
  import { actionVerb } from './chrome/presenter-verbs.js';
5
5
  import { nativeSetTimeout, nativeClearTimeout, nativeNow } from '../timers/native/native-timers.js';
6
- import { LOG_KIND, CHIP_LABEL, DATA_RETICLE_LOG, clampLogMax, formatElapsed, humanDuration, appendLogRow, } from './chrome/presenter-log.js';
6
+ import { LOG_KIND, CHIP_LABEL, DATA_RETICLE_LOG, clampLogMax, formatElapsed, humanDuration, appendLogRow, clearLogRows, trimLogRows, } from './chrome/presenter-log.js';
7
7
  import { PRESENTER_CSS } from './presenter-styles.js';
8
8
  import { HudShell } from './presenter-shell.js';
9
9
  import { parseImpactSnapshot } from './chrome/presenter-report-copy.js';
10
- import { BorderMode, DEFAULT_BORDER_MODE, DATA_BUSY, BUSY_OFF, effectivePaceMs, IDLE_AFTER_MS, HEARTBEAT_MS, IDLE_NOTICE_MS, IDLE_END_MS, IDLE_END_MIN_MS, ACT_STRIP, STATE_ATTR, UNREACHABLE_STATE, GLOW_FADE_MS, GLOW_ON, GLOW_OFF, DATA_ON, THROTTLED_ATTR, LIVENESS_ATTR, MARKERS_BTN_ATTR, CLEAR_MARKS_ATTR, MARK_COUNT_ATTR, } from './presenter-config.js';
10
+ import { BorderMode, DEFAULT_BORDER_MODE, DATA_BUSY, BUSY_OFF, effectivePaceMs, IDLE_AFTER_MS, HEARTBEAT_MS, IDLE_NOTICE_MS, IDLE_END_MS, IDLE_END_MIN_MS, ACT_STRIP, STATE_ATTR, UNREACHABLE_STATE, GLOW_FADE_MS, GLOW_ON, GLOW_OFF, DATA_ON, THROTTLED_ATTR, LIVENESS_ATTR, MARKERS_BTN_ATTR, CLEAR_MARKS_ATTR, COPY_MARKS_ATTR, MARKS_ROW_ATTR, MARK_COUNT_ATTR, } from './presenter-config.js';
11
11
  import { buildRunState } from './presenter-run-state.js';
12
12
  import { moveCursor, ringAround, spawnRipple, pace } from './chrome/presenter-effects.js';
13
13
  import { GlowController } from './presenter-glow.js';
14
14
  import { PresenterIcon, PRESENTER_ICON_SIZE, hiIcon } from './icons/presenter-icons.js';
15
15
  import { renderTally } from './chrome/presenter-tally.js';
16
- import { CONTROLS_BANNER_HTML, CONTROLS_FLOWS_HTML, CONTROLS_FOOT_HTML, ENDED_FADE_MS, ControlPanel, } from './presenter-controls.js';
16
+ import { CONTROLS_BANNER_HTML, CONTROLS_FLOWS_HTML, CONTROLS_MARKS_HTML, CONTROLS_FOOT_HTML, ENDED_FADE_MS, ControlPanel, } from './presenter-controls.js';
17
17
  import { statusTheme, blockerHtml, getPresenterSettings, OutputDetail, syncPageBlocker, } from './presenter-settings.js';
18
18
  import { Annotator } from '../review/annotator.js';
19
+ import { shouldAutoOpenChat } from './presenter-shell.js';
20
+ import { installHudTelemetry } from './hud-telemetry.js';
21
+ const COPIED_FLASH_MS = 1600;
19
22
  export { GlowPhase } from './presenter-config.js';
20
23
  export { LOG_KIND, LOG_RESULT } from './chrome/presenter-log.js';
21
24
  export class Presenter {
@@ -50,6 +53,8 @@ export class Presenter {
50
53
  #log;
51
54
  #logBaseMs;
52
55
  #onControl;
56
+ #onHudUse;
57
+ #hudTelemetryTeardown;
53
58
  #panel;
54
59
  #shell;
55
60
  #annotator;
@@ -70,6 +75,7 @@ export class Presenter {
70
75
  });
71
76
  this.#logMax = clampLogMax(options.logMax);
72
77
  this.#onControl = options.onControl;
78
+ this.#onHudUse = options.onHudUse;
73
79
  this.#panel = new ControlPanel({
74
80
  emit: (kind, text) => this.#onControl?.(text !== undefined ? { kind, text } : { kind }),
75
81
  logHuman: (text) => {
@@ -159,7 +165,7 @@ export class Presenter {
159
165
  <div data-reticle-glow></div>
160
166
  <div data-reticle-cursor></div>
161
167
  <div data-reticle-ring></div>
162
- ${HudShell.dockHtml(actStrip, CONTROLS_BANNER_HTML, DATA_RETICLE_LOG, CONTROLS_FLOWS_HTML, CONTROLS_FOOT_HTML)}`;
168
+ ${HudShell.dockHtml(actStrip, CONTROLS_BANNER_HTML, DATA_RETICLE_LOG, CONTROLS_MARKS_HTML + CONTROLS_FLOWS_HTML, CONTROLS_FOOT_HTML)}`;
163
169
  document.body.appendChild(root);
164
170
  this.#root = root;
165
171
  this.#glow = root.querySelector('[data-reticle-glow]') ?? undefined;
@@ -179,6 +185,9 @@ export class Presenter {
179
185
  syncPageBlocker(root, getPresenterSettings(), false);
180
186
  this.#glowCtl.setElements(this.#glow, this.#cursor);
181
187
  this.#panel.mount(root, this.#glow);
188
+ if (this.#onHudUse !== undefined) {
189
+ this.#hudTelemetryTeardown = installHudTelemetry(document, root, this.#onHudUse);
190
+ }
182
191
  this.setMode(this.#mode);
183
192
  this.#renderTally();
184
193
  }
@@ -190,7 +199,23 @@ export class Presenter {
190
199
  const markers = root.querySelector(`[${MARKERS_BTN_ATTR}]`);
191
200
  const clear = root.querySelector(`[${CLEAR_MARKS_ATTR}]`);
192
201
  const count = root.querySelector(`[${MARK_COUNT_ATTR}]`);
202
+ const copy = root.querySelector(`[${COPY_MARKS_ATTR}]`);
203
+ const row = root.querySelector(`[${MARKS_ROW_ATTR}]`);
193
204
  const chrome = {};
205
+ if (row instanceof HTMLElement)
206
+ chrome.copyRow = row;
207
+ let marks = annotator.markCount;
208
+ chrome.onCount = (n) => {
209
+ if (0 === marks && n > 0)
210
+ this.#shell.openChat();
211
+ marks = n;
212
+ };
213
+ if (copy instanceof HTMLElement) {
214
+ copy.addEventListener('click', (e) => {
215
+ e.stopPropagation();
216
+ this.#copyMarks(annotator, copy);
217
+ });
218
+ }
194
219
  if (markers instanceof HTMLElement)
195
220
  chrome.markersBtn = markers;
196
221
  if (clear instanceof HTMLElement)
@@ -201,6 +226,14 @@ export class Presenter {
201
226
  annotator.setAccent(statusTheme(getPresenterSettings().statusThemeId).active);
202
227
  this.#syncAnnotator();
203
228
  }
229
+ #copyMarks(annotator, btn) {
230
+ const text = annotator.agentPrompt(window.location.href);
231
+ void navigator.clipboard?.writeText(text).catch(() => undefined);
232
+ btn.setAttribute('data-copied', '1');
233
+ nativeSetTimeout(() => btn.removeAttribute('data-copied'), COPIED_FLASH_MS);
234
+ if (getPresenterSettings().clearOnCopy)
235
+ annotator.clearAll();
236
+ }
204
237
  #syncAnnotator() {
205
238
  const live = !this.#shell.isCollapsed() && this.#shell.isAnnotateOn();
206
239
  this.#annotator?.toggle(live);
@@ -213,6 +246,8 @@ export class Presenter {
213
246
  if (this.#heartbeatTimer !== undefined)
214
247
  nativeClearTimeout(this.#heartbeatTimer);
215
248
  this.#heartbeatTimer = undefined;
249
+ this.#hudTelemetryTeardown?.();
250
+ this.#hudTelemetryTeardown = undefined;
216
251
  this.#shell.teardown();
217
252
  this.#panel.teardown();
218
253
  this.#sessionActive = false;
@@ -237,7 +272,7 @@ export class Presenter {
237
272
  this.#showSession();
238
273
  this.#glowCtl.resetActivity(this.#now());
239
274
  this.#startHeartbeat();
240
- if (getPresenterSettings().autoOpenChat) {
275
+ if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat)) {
241
276
  this.#shell.openChat();
242
277
  }
243
278
  }
@@ -250,7 +285,7 @@ export class Presenter {
250
285
  this.#hud?.setAttribute(DATA_ON, GLOW_ON);
251
286
  this.#lastActionText = unreachableStripText(url, attempts);
252
287
  this.#paintActStrip(this.#lastActionText, true);
253
- if (getPresenterSettings().autoOpenChat)
288
+ if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat))
254
289
  this.#shell.openChat();
255
290
  }
256
291
  #showSession() {
@@ -413,7 +448,7 @@ export class Presenter {
413
448
  this.#runLog = [];
414
449
  this.#tallied = { passes: 0, fails: 0 };
415
450
  if (this.#log !== undefined)
416
- this.#log.replaceChildren();
451
+ clearLogRows(this.#log);
417
452
  this.#renderTally();
418
453
  }
419
454
  #applyHideUntilRestart() {
@@ -477,9 +512,7 @@ export class Presenter {
477
512
  #pruneLog() {
478
513
  if (this.#log === undefined)
479
514
  return;
480
- while (this.#log.childElementCount > this.#logMax) {
481
- this.#log.firstElementChild?.remove();
482
- }
515
+ trimLogRows(this.#log, this.#logMax);
483
516
  }
484
517
  setThrottled(throttled) {
485
518
  this.#root?.setAttribute(THROTTLED_ATTR, throttled ? '1' : '0');
@@ -11,6 +11,9 @@ export interface TourDeps {
11
11
  readonly projectId: string;
12
12
  readonly isDriving: () => boolean;
13
13
  readonly search?: string;
14
+ readonly navigator?: {
15
+ readonly webdriver?: boolean;
16
+ };
14
17
  readonly copy?: (text: string) => Promise<boolean> | boolean;
15
18
  readonly select?: (element: Element) => void;
16
19
  }
@@ -1,6 +1,7 @@
1
1
  import { COPIED_LABEL, COPY_FLASH_MS, COPY_LABEL, COPY_MANUAL_LABEL, TOUR_ATTR, TOUR_CSS, TOUR_PROMPT_ATTR, TOUR_TARGET_ATTR, holeRects, isInteractive, isLastSlide, nextIndex, slideHtml, tourSlides, } from './tour-view.js';
2
2
  import { TourAnchor } from '@reticlehq/core/tour';
3
3
  import { RETICLE_URL_PARAM } from '@reticlehq/core';
4
+ import { appModalOpen } from '../../dom/dom-ignore.js';
4
5
  export const TOUR_SEEN_KEY_PREFIX = 'reticle.tour.seen.';
5
6
  const APP_SELECTORS = ['main', '#root', '#app'];
6
7
  const HUD_PARTS = ['[data-reticle-hud]', '[data-reticle-chat-panel]'];
@@ -79,6 +80,8 @@ export function mountTour(deps) {
79
80
  return undefined;
80
81
  if (openedByReticle(deps.search))
81
82
  return undefined;
83
+ if (true === deps.navigator?.webdriver)
84
+ return undefined;
82
85
  if (tourAlreadySeen(deps.storage, deps.projectId))
83
86
  return undefined;
84
87
  const doc = deps.document;
@@ -220,6 +223,8 @@ export function mountTour(deps) {
220
223
  const onKey = (event) => {
221
224
  if (!open)
222
225
  return;
226
+ if (appModalOpen(doc))
227
+ return;
223
228
  const step = 'ArrowRight' === event.key ? 1 : 'ArrowLeft' === event.key ? -1 : 0;
224
229
  if ('Escape' === event.key) {
225
230
  event.preventDefault();
@@ -1,4 +1,4 @@
1
- import { ActionType, AnchorKind, AnnotationKind, DEGRADED_ANCHOR_ROLE, EventType, FLOW_FILE_VERSION, FlowStepTool, RecorderPhase, } from '@reticlehq/core';
1
+ import { ActionType, AnchorKind, AnnotationKind, DEGRADED_ANCHOR_ROLE, EventType, FLOW_FILE_VERSION, FlowStepTool, RecorderPhase, PredicateKind, } from '@reticlehq/core';
2
2
  import { REDACTED_VALUE } from '@reticlehq/core';
3
3
  import { sourceFromDom } from '../dom/addressing/source.js';
4
4
  import { getAccessibleName, getRole, isSensitiveField } from '../dom/a11y.js';
@@ -83,17 +83,20 @@ export function compileRecording(name, steps, annotations, createdAt, startPath)
83
83
  }
84
84
  if (ann.kind === AnnotationKind.SUCCESS_STATE) {
85
85
  if (ann.signal !== undefined)
86
- success = { signal: ann.signal };
86
+ success = { kind: PredicateKind.SIGNAL, name: ann.signal };
87
87
  continue;
88
88
  }
89
89
  const target = out.at(-1);
90
90
  if (target === undefined)
91
91
  continue;
92
92
  if (ann.kind === AnnotationKind.ASSERT_SIGNAL && ann.signal !== undefined) {
93
- target.expect = { ...target.expect, signal: ann.signal };
93
+ target.expect = alsoAssert(target.expect, { kind: PredicateKind.SIGNAL, name: ann.signal });
94
94
  }
95
95
  else if (ann.kind === AnnotationKind.ASSERT_VISIBLE) {
96
- target.expect = { ...target.expect, element: anchorToElement(ann.anchor) };
96
+ target.expect = alsoAssert(target.expect, {
97
+ kind: PredicateKind.ELEMENT,
98
+ query: anchorToElement(ann.anchor),
99
+ });
97
100
  }
98
101
  }
99
102
  const flow = { version: FLOW_FILE_VERSION, name, createdAt, steps: out };
@@ -105,6 +108,14 @@ export function compileRecording(name, steps, annotations, createdAt, startPath)
105
108
  flow.success = success;
106
109
  return flow;
107
110
  }
111
+ function alsoAssert(existing, clause) {
112
+ if (existing === undefined)
113
+ return clause;
114
+ if (existing.kind === PredicateKind.ALL_OF) {
115
+ return { kind: PredicateKind.ALL_OF, predicates: [...existing.predicates, clause] };
116
+ }
117
+ return { kind: PredicateKind.ALL_OF, predicates: [existing, clause] };
118
+ }
108
119
  function anchorToElement(anchor) {
109
120
  if (anchor.kind === AnchorKind.TESTID)
110
121
  return { testid: anchor.value };
@@ -122,7 +133,7 @@ class Recorder {
122
133
  #startPath;
123
134
  #annotations = [];
124
135
  #pendingFill;
125
- #teardowns = [];
136
+ #captureAbort;
126
137
  #root;
127
138
  #statusEl;
128
139
  #menuEl;
@@ -145,9 +156,8 @@ class Recorder {
145
156
  this.#installCapture();
146
157
  }
147
158
  destroy() {
148
- for (const t of this.#teardowns)
149
- t();
150
- this.#teardowns = [];
159
+ this.#captureAbort?.abort();
160
+ this.#captureAbort = undefined;
151
161
  this.#root?.remove();
152
162
  this.#root = undefined;
153
163
  this.#statusEl = undefined;
@@ -159,20 +169,13 @@ class Recorder {
159
169
  this.#pendingFill = undefined;
160
170
  }
161
171
  #installCapture() {
162
- const onClick = (ev) => this.#onClick(ev);
163
- const onInput = (ev) => this.#onInput(ev);
164
- const onChange = (ev) => this.#onChange(ev);
165
- const onSubmit = (ev) => this.#onSubmit(ev);
166
- document.addEventListener('click', onClick, true);
167
- document.addEventListener('input', onInput, true);
168
- document.addEventListener('change', onChange, true);
169
- document.addEventListener('submit', onSubmit, true);
170
- this.#teardowns.push(() => {
171
- document.removeEventListener('click', onClick, true);
172
- document.removeEventListener('input', onInput, true);
173
- document.removeEventListener('change', onChange, true);
174
- document.removeEventListener('submit', onSubmit, true);
175
- });
172
+ const ac = new AbortController();
173
+ this.#captureAbort = ac;
174
+ const opts = { capture: true, signal: ac.signal };
175
+ document.addEventListener('click', (ev) => this.#onClick(ev), opts);
176
+ document.addEventListener('input', (ev) => this.#onInput(ev), opts);
177
+ document.addEventListener('change', (ev) => this.#onChange(ev), opts);
178
+ document.addEventListener('submit', (ev) => this.#onSubmit(ev), opts);
176
179
  }
177
180
  #ignore(ev) {
178
181
  const target = ev.target;
@@ -1,5 +1,35 @@
1
1
  import { nativeWarn } from '../timers/console/native-console.js';
2
2
  import { markAdapterSource } from './stores.js';
3
+ function snapshotLive(value) {
4
+ try {
5
+ return copyPlain(value, new WeakMap());
6
+ }
7
+ catch {
8
+ return value;
9
+ }
10
+ }
11
+ function copyPlain(value, seen) {
12
+ if ('object' !== typeof value || null === value)
13
+ return value;
14
+ const done = seen.get(value);
15
+ if (done !== undefined)
16
+ return done;
17
+ if (Array.isArray(value)) {
18
+ const out = [];
19
+ seen.set(value, out);
20
+ for (const item of value)
21
+ out.push(copyPlain(item, seen));
22
+ return out;
23
+ }
24
+ const proto = Object.getPrototypeOf(value);
25
+ if (proto !== Object.prototype && proto !== null)
26
+ return value;
27
+ const out = {};
28
+ seen.set(value, out);
29
+ for (const [key, item] of Object.entries(value))
30
+ out[key] = copyPlain(item, seen);
31
+ return out;
32
+ }
3
33
  export function tanstackQueryStore(client) {
4
34
  const store = {
5
35
  getState: () => {
@@ -106,7 +136,7 @@ export function svelteStore(readable, warn = nativeWarn) {
106
136
  let value;
107
137
  let called = false;
108
138
  stopSubscription(readable.subscribe((next) => {
109
- value = next;
139
+ value = snapshotLive(next);
110
140
  called = true;
111
141
  }));
112
142
  if (!called && !warnedAboutLazyStore) {
@@ -132,7 +162,7 @@ export function svelteStore(readable, warn = nativeWarn) {
132
162
  const PINIA_SUBSCRIBE_OPTIONS = { detached: true, flush: 'sync' };
133
163
  export function piniaStore(store) {
134
164
  return {
135
- getState: () => store.$state,
165
+ getState: () => snapshotLive(store.$state),
136
166
  subscribe: (listener) => store.$subscribe(() => listener(), { ...PINIA_SUBSCRIBE_OPTIONS }),
137
167
  };
138
168
  }
@@ -6,8 +6,14 @@ export function registerAdapter(adapter) {
6
6
  }
7
7
  export function identifyComponent(el) {
8
8
  for (const adapter of adapters) {
9
- const info = adapter.identify(el);
10
- if (info !== null)
9
+ let info;
10
+ try {
11
+ info = adapter.identify(el);
12
+ }
13
+ catch {
14
+ continue;
15
+ }
16
+ if (info !== null && info !== undefined)
11
17
  return info;
12
18
  }
13
19
  return null;
@@ -0,0 +1,2 @@
1
+ // A script evaluated in the page, read by the daemon as text. Nothing here is importable.
2
+ export {};