@reticlehq/browser 3.7.0 → 3.8.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 (92) hide show
  1. package/dist/actions/action-report.d.ts +10 -0
  2. package/dist/actions/action-report.js +29 -2
  3. package/dist/actions/actions-dom.d.ts +4 -0
  4. package/dist/actions/actions-dom.js +20 -4
  5. package/dist/actions/actions.d.ts +1 -0
  6. package/dist/actions/actions.js +35 -17
  7. package/dist/actions/appeared-text.js +2 -2
  8. package/dist/actions/click-target.d.ts +1 -0
  9. package/dist/actions/click-target.js +14 -0
  10. package/dist/actions/danger-context.d.ts +2 -1
  11. package/dist/actions/danger-context.js +20 -5
  12. package/dist/activate.d.ts +14 -0
  13. package/dist/activate.js +43 -0
  14. package/dist/busy.d.ts +3 -0
  15. package/dist/busy.js +42 -0
  16. package/dist/commands/commands.js +45 -17
  17. package/dist/connect-options.d.ts +12 -1
  18. package/dist/connect-options.js +18 -1
  19. package/dist/dom/a11y.d.ts +2 -0
  20. package/dist/dom/a11y.js +191 -159
  21. package/dist/dom/chart.d.ts +3 -2
  22. package/dist/dom/chart.js +3 -2
  23. package/dist/dom/dom-ignore.d.ts +6 -0
  24. package/dist/dom/dom-ignore.js +43 -1
  25. package/dist/dom/layout-audit.d.ts +15 -0
  26. package/dist/dom/layout-audit.js +208 -0
  27. package/dist/dom/paint-context.d.ts +15 -0
  28. package/dist/dom/paint-context.js +78 -0
  29. package/dist/dom/query.d.ts +2 -1
  30. package/dist/dom/query.js +97 -34
  31. package/dist/dom/shadow-registry.d.ts +1 -0
  32. package/dist/dom/shadow-registry.js +27 -0
  33. package/dist/dom/snapshot.d.ts +5 -0
  34. package/dist/dom/snapshot.js +85 -34
  35. package/dist/dom/stable-selector.d.ts +1 -0
  36. package/dist/dom/stable-selector.js +19 -0
  37. package/dist/dom/text-match.d.ts +12 -0
  38. package/dist/dom/text-match.js +115 -0
  39. package/dist/dom/theme.d.ts +1 -0
  40. package/dist/dom/theme.js +21 -9
  41. package/dist/dom/virtualized.js +5 -1
  42. package/dist/index.d.ts +2 -1
  43. package/dist/index.js +5 -0
  44. package/dist/observers/blind-spots.js +3 -2
  45. package/dist/observers/canvas.d.ts +18 -0
  46. package/dist/observers/canvas.js +76 -0
  47. package/dist/observers/dom.js +66 -18
  48. package/dist/observers/field.d.ts +11 -0
  49. package/dist/observers/field.js +117 -13
  50. package/dist/observers/install-all.js +4 -0
  51. package/dist/observers/media.d.ts +2 -0
  52. package/dist/observers/media.js +32 -0
  53. package/dist/observers/net-detail/network-body.d.ts +2 -0
  54. package/dist/observers/net-detail/network-body.js +8 -1
  55. package/dist/observers/network.js +26 -6
  56. package/dist/observers/route.d.ts +2 -0
  57. package/dist/observers/route.js +33 -4
  58. package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -5
  59. package/dist/presenter/chrome/presenter-report-copy.js +0 -14
  60. package/dist/presenter/hud-telemetry.js +1 -1
  61. package/dist/presenter/presenter-chat-views.d.ts +3 -4
  62. package/dist/presenter/presenter-chat-views.js +47 -20
  63. package/dist/presenter/presenter-config.d.ts +1 -0
  64. package/dist/presenter/presenter-config.js +1 -0
  65. package/dist/presenter/presenter-frame.d.ts +3 -2
  66. package/dist/presenter/presenter-frame.js +24 -15
  67. package/dist/presenter/presenter-harness-row.d.ts +4 -15
  68. package/dist/presenter/presenter-harness-row.js +11 -50
  69. package/dist/presenter/presenter-report-styles.js +0 -17
  70. package/dist/presenter/presenter-report.d.ts +1 -2
  71. package/dist/presenter/presenter-report.js +4 -54
  72. package/dist/presenter/presenter-run-state.js +2 -1
  73. package/dist/presenter/presenter-settings.d.ts +2 -3
  74. package/dist/presenter/presenter-settings.js +14 -17
  75. package/dist/presenter/presenter-shell.d.ts +6 -4
  76. package/dist/presenter/presenter-shell.js +37 -7
  77. package/dist/presenter/presenter.js +32 -11
  78. package/dist/registry/store-adapters.d.ts +5 -2
  79. package/dist/registry/store-adapters.js +40 -10
  80. package/dist/reticle-inject.js +602 -611
  81. package/dist/reticle.d.ts +4 -2
  82. package/dist/reticle.js +36 -6
  83. package/dist/security/page-location.d.ts +2 -0
  84. package/dist/security/page-location.js +7 -0
  85. package/dist/security/serialization.js +1 -1
  86. package/dist/storage-keys.d.ts +1 -0
  87. package/dist/storage-keys.js +1 -0
  88. package/dist/timers/native/native-timers.d.ts +1 -0
  89. package/dist/timers/native/native-timers.js +5 -0
  90. package/dist/transport/transport.d.ts +1 -0
  91. package/dist/transport/transport.js +18 -0
  92. package/package.json +6 -2
@@ -1,4 +1,4 @@
1
- import { ComponentStateReason, ElementQuerySchema, ReticleCommand, SnapshotMode, TRANSPORT_LIMITS, selectPath, capDepth, } from '@reticlehq/core';
1
+ import { ComponentStateReason, ElementQuerySchema, INSPECT_IN_VIEWPORT_FIELD, INSPECT_REVEAL_ARG, ReticleCommand, SnapshotMode, TRANSPORT_LIMITS, selectPath, capDepth, } from '@reticlehq/core';
2
2
  import { buildSnapshot } from '../dom/snapshot.js';
3
3
  import { paintContextOf } from '../dom/paint-context.js';
4
4
  import { matchQuery, runQuery } from '../dom/query.js';
@@ -11,6 +11,7 @@ import { editEpoch } from '../edit-epoch.js';
11
11
  import { isButton, isInput } from '../dom/realm.js';
12
12
  import { hitTestOccluder } from '../dom/occlusion.js';
13
13
  import { readStorage } from '../observers/storage.js';
14
+ import { canvasAfterAct } from '../observers/canvas.js';
14
15
  import { captureDesktopWindow } from '../dom/desktop-capture.js';
15
16
  import { identifyComponent, readComponentState } from '../registry/stores/adapters.js';
16
17
  import { readStoresWithTruncation, readStoresRaw, storeNames } from '../registry/stores.js';
@@ -18,6 +19,7 @@ import { sanitizeWithReport } from '../security/serialization.js';
18
19
  import { getCapabilities } from '../registry/capabilities.js';
19
20
  import { freezeClock, advanceClock, resetClock, isClockFrozen } from '../timers/clock.js';
20
21
  import { scrollContainer } from '../actions/scroll.js';
22
+ import { isOffViewport } from '../actions/actions-dom.js';
21
23
  export const RELOAD_CACHE_BUST_PARAM = '_reticle_reload';
22
24
  function str(value) {
23
25
  return 'string' === typeof value ? value : undefined;
@@ -29,11 +31,13 @@ function record(value) {
29
31
  return 'object' === typeof value && value !== null ? value : {};
30
32
  }
31
33
  function sourceLocation(value) {
32
- if (typeof value !== 'object' || null === value)
34
+ if (typeof value !== 'object' || null === value) {
33
35
  return undefined;
36
+ }
34
37
  const obj = value;
35
- if (typeof obj['file'] !== 'string' || typeof obj['line'] !== 'number')
38
+ if (typeof obj['file'] !== 'string' || typeof obj['line'] !== 'number') {
36
39
  return undefined;
40
+ }
37
41
  return { file: obj['file'], line: obj['line'], column: num(obj['column']) };
38
42
  }
39
43
  function queryFromArgs(args) {
@@ -56,10 +60,17 @@ function queryFromArgs(args) {
56
60
  source: sourceLocation(args['source']),
57
61
  };
58
62
  }
59
- function inspect(ref) {
63
+ function inspect(ref, reveal = false) {
60
64
  const el = refs.resolve(ref);
61
- if (null === el)
65
+ if (null === el) {
62
66
  throw new Error(editEpoch.staleRefMessage(ref));
67
+ }
68
+ const scrolledIntoView = reveal &&
69
+ 'function' === typeof el.scrollIntoView &&
70
+ isOffViewport(el, el.getBoundingClientRect());
71
+ if (scrolledIntoView) {
72
+ el.scrollIntoView({ block: 'center', inline: 'center' });
73
+ }
63
74
  const rect = el.getBoundingClientRect();
64
75
  const component = identifyComponent(el);
65
76
  const view = el.ownerDocument.defaultView;
@@ -101,6 +112,8 @@ function inspect(ref) {
101
112
  formAction: isButton(el) || isInput(el) ? (el.form?.getAttribute('action') ?? undefined) : undefined,
102
113
  formText: isButton(el) || isInput(el) ? (el.form?.textContent ?? undefined) : undefined,
103
114
  box: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
115
+ ...(scrolledIntoView ? { scrolledIntoView: true } : {}),
116
+ ...(reveal ? { [INSPECT_IN_VIEWPORT_FIELD]: !isOffViewport(el, rect) } : {}),
104
117
  occluded: isOccluded(el, rect),
105
118
  styles,
106
119
  scroll,
@@ -145,8 +158,9 @@ function readState(ref, store, path, depth) {
145
158
  stores,
146
159
  storeNames: names,
147
160
  };
148
- if (truncation !== undefined)
161
+ if (truncation !== undefined) {
149
162
  result.truncation = truncation;
163
+ }
150
164
  if (ref !== undefined && ref.length > 0) {
151
165
  const el = refs.resolve(ref);
152
166
  if (null === el) {
@@ -161,8 +175,9 @@ function readState(ref, store, path, depth) {
161
175
  }
162
176
  function listAnimations() {
163
177
  const doc = document;
164
- if (typeof doc.getAnimations !== 'function')
178
+ if (typeof doc.getAnimations !== 'function') {
165
179
  return { animations: [] };
180
+ }
166
181
  const animations = doc.getAnimations().map((a) => {
167
182
  const effect = a.effect;
168
183
  const timing = effect?.getTiming();
@@ -177,8 +192,9 @@ function listAnimations() {
177
192
  return { animations };
178
193
  }
179
194
  export function resolveNavigationUrl(rawUrl, baseUrl) {
180
- if (0 === rawUrl.length || rawUrl.length > TRANSPORT_LIMITS.MAX_URL_LENGTH)
195
+ if (0 === rawUrl.length || rawUrl.length > TRANSPORT_LIMITS.MAX_URL_LENGTH) {
181
196
  return null;
197
+ }
182
198
  try {
183
199
  const url = new URL(rawUrl, baseUrl);
184
200
  return 'http:' === url.protocol || 'https:' === url.protocol ? url.toString() : null;
@@ -193,29 +209,39 @@ export function createCommandRegistry() {
193
209
  scope: str(args['scope']),
194
210
  mode: str(args['mode']) ?? SnapshotMode.FULL,
195
211
  includeRoot: true === args['includeRoot'],
212
+ ids: true === args['ids'],
213
+ audit: true === args['audit'],
196
214
  }));
197
215
  reg.set(ReticleCommand.QUERY, (args) => {
198
216
  const limit = args['limit'];
199
217
  return runQuery(queryFromArgs(args), 'number' === typeof limit ? limit : undefined);
200
218
  });
201
- reg.set(ReticleCommand.MATCH, (args) => matchQuery(ElementQuerySchema.parse(record(args['query'])), str(args['state'])));
202
- reg.set(ReticleCommand.ACT, (args) => {
219
+ reg.set(ReticleCommand.MATCH, (args) => matchQuery(ElementQuerySchema.parse(record(args['query'])), str(args['state']), undefined, undefined, true === args['diagnose']));
220
+ reg.set(ReticleCommand.ACT, async (args) => {
203
221
  const action = str(args['action']) ?? '';
204
- return executeAction(str(args['ref']) ?? '', action, record(args['args']));
222
+ const result = await executeAction(str(args['ref']) ?? '', action, record(args['args']));
223
+ canvasAfterAct();
224
+ return result;
225
+ });
226
+ reg.set(ReticleCommand.ACT_SEQUENCE, async (args) => {
227
+ const result = await executeSequence((Array.isArray(args['steps']) ? args['steps'] : []));
228
+ canvasAfterAct();
229
+ return result;
205
230
  });
206
- reg.set(ReticleCommand.ACT_SEQUENCE, (args) => executeSequence((Array.isArray(args['steps']) ? args['steps'] : [])));
207
- reg.set(ReticleCommand.INSPECT, (args) => inspect(str(args['ref']) ?? ''));
231
+ reg.set(ReticleCommand.INSPECT, (args) => inspect(str(args['ref']) ?? '', true === args[INSPECT_REVEAL_ARG]));
208
232
  reg.set(ReticleCommand.ANIMATIONS, () => listAnimations());
209
233
  reg.set(ReticleCommand.CLOCK, (args) => {
210
234
  if (true === args['reset']) {
211
235
  resetClock();
212
236
  }
213
237
  else {
214
- if (true === args['freeze'])
238
+ if (true === args['freeze']) {
215
239
  freezeClock();
240
+ }
216
241
  const adv = args['advanceMs'];
217
- if ('number' === typeof adv)
242
+ if ('number' === typeof adv) {
218
243
  advanceClock(adv);
244
+ }
219
245
  }
220
246
  return { frozen: isClockFrozen() };
221
247
  });
@@ -231,11 +257,13 @@ export function createCommandRegistry() {
231
257
  });
232
258
  reg.set(ReticleCommand.NAVIGATE, (args) => {
233
259
  const rawUrl = str(args['url']);
234
- if (rawUrl === undefined || 0 === rawUrl.length)
260
+ if (rawUrl === undefined || 0 === rawUrl.length) {
235
261
  return { ok: false, reason: 'url required' };
262
+ }
236
263
  const url = resolveNavigationUrl(rawUrl, window.location.href);
237
- if (null === url)
264
+ if (null === url) {
238
265
  return { ok: false, reason: 'only http(s) navigation is allowed' };
266
+ }
239
267
  window.location.assign(url);
240
268
  return { ok: true, url };
241
269
  });
@@ -1,4 +1,4 @@
1
- import type { RedactionConfig } from '@reticlehq/core';
1
+ import { HelloInstrumentation, type HelloEnv, type HelloScope, type RedactionConfig } from '@reticlehq/core';
2
2
  export interface ReticleConnectOptions {
3
3
  url?: string;
4
4
  session?: string;
@@ -6,6 +6,10 @@ export interface ReticleConnectOptions {
6
6
  token?: string;
7
7
  allowNonLocalhost?: boolean;
8
8
  allowInProduction?: boolean;
9
+ env?: HelloEnv;
10
+ scope?: HelloScope;
11
+ injected?: boolean;
12
+ lease?: boolean;
9
13
  testIdAttribute?: string;
10
14
  overlay?: boolean;
11
15
  captureNetworkBodies?: boolean;
@@ -26,3 +30,10 @@ export interface ReticleConnectOptions {
26
30
  idleEndMs?: number;
27
31
  redact?: RedactionConfig;
28
32
  }
33
+ export declare function helloMode(options: Pick<ReticleConnectOptions, 'env' | 'scope' | 'injected'>): {
34
+ env?: HelloEnv;
35
+ scope?: HelloScope;
36
+ instrumentation?: HelloInstrumentation;
37
+ };
38
+ export declare function shouldBlockProduction(nodeEnv: string | undefined, allowInProduction: boolean): boolean;
39
+ export declare function leaseToken(options: ReticleConnectOptions, current: string | undefined): string | undefined;
@@ -1 +1,18 @@
1
- export {};
1
+ import { HelloInstrumentation, } from '@reticlehq/core';
2
+ export function helloMode(options) {
3
+ return {
4
+ ...(options.env === undefined ? {} : { env: options.env }),
5
+ ...(options.scope === undefined ? {} : { scope: options.scope }),
6
+ ...(true === options.injected ? { instrumentation: HelloInstrumentation.INJECTED } : {}),
7
+ };
8
+ }
9
+ export function shouldBlockProduction(nodeEnv, allowInProduction) {
10
+ return 'production' === nodeEnv && !allowInProduction;
11
+ }
12
+ export function leaseToken(options, current) {
13
+ const token = options.token;
14
+ if (true !== options.lease || token === undefined || 0 === token.length || token === current) {
15
+ return undefined;
16
+ }
17
+ return token;
18
+ }
@@ -4,6 +4,8 @@ export declare function getAccessibleName(el: Element): string;
4
4
  export declare function getStates(el: Element, visible?: boolean): ElementState[];
5
5
  export declare function isSensitiveField(el: Element): boolean;
6
6
  export declare function getValue(el: Element): string | undefined;
7
+ export declare function isHiddenByAriaOnly(el: Element): boolean;
8
+ export declare function isRenderedOutsideAriaHidden(el: Element): boolean;
7
9
  export declare function isInViewport(el: Element, memo?: Map<Element, boolean>): boolean;
8
10
  export declare function isVisible(el: Element, memo?: Map<Element, boolean>): boolean;
9
11
  export declare function describe(el: Element, memo?: Map<Element, boolean>): ElementDescriptor;