@reticlehq/browser 3.6.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.
- package/dist/actions/action-report.d.ts +64 -0
- package/dist/actions/action-report.js +87 -0
- package/dist/actions/actions-dom.d.ts +5 -0
- package/dist/actions/actions-dom.js +32 -4
- package/dist/actions/actions-press.d.ts +1 -0
- package/dist/actions/actions-press.js +25 -1
- package/dist/actions/actions.d.ts +2 -37
- package/dist/actions/actions.js +56 -80
- package/dist/actions/appeared-text.js +5 -2
- package/dist/actions/click-target.d.ts +1 -0
- package/dist/actions/click-target.js +14 -0
- package/dist/actions/danger-context.d.ts +4 -1
- package/dist/actions/danger-context.js +45 -4
- package/dist/actions/value-input.d.ts +1 -0
- package/dist/actions/value-input.js +11 -0
- package/dist/activate.d.ts +14 -0
- package/dist/activate.js +43 -0
- package/dist/busy.d.ts +3 -0
- package/dist/busy.js +42 -0
- package/dist/commands/commands.js +49 -17
- package/dist/connect-options.d.ts +12 -1
- package/dist/connect-options.js +18 -1
- package/dist/dom/a11y.d.ts +2 -0
- package/dist/dom/a11y.js +353 -80
- package/dist/dom/addressing/coverage-markers.d.ts +6 -0
- package/dist/dom/addressing/coverage-markers.js +13 -0
- package/dist/dom/chart.d.ts +3 -2
- package/dist/dom/chart.js +3 -2
- package/dist/dom/dom-ignore.d.ts +8 -0
- package/dist/dom/dom-ignore.js +57 -2
- package/dist/dom/layout-audit.d.ts +15 -0
- package/dist/dom/layout-audit.js +208 -0
- package/dist/dom/paint-context.d.ts +15 -0
- package/dist/dom/paint-context.js +78 -0
- package/dist/dom/query.d.ts +2 -1
- package/dist/dom/query.js +163 -38
- package/dist/dom/render-page.d.ts +12 -0
- package/dist/dom/render-page.js +135 -0
- package/dist/dom/shadow-registry.d.ts +1 -0
- package/dist/dom/shadow-registry.js +27 -0
- package/dist/dom/snapshot.d.ts +5 -0
- package/dist/dom/snapshot.js +135 -36
- package/dist/dom/stable-selector.d.ts +1 -0
- package/dist/dom/stable-selector.js +19 -0
- package/dist/dom/text-match.d.ts +12 -0
- package/dist/dom/text-match.js +115 -0
- package/dist/dom/theme.d.ts +1 -0
- package/dist/dom/theme.js +21 -9
- package/dist/dom/virtualized.js +5 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -0
- package/dist/observers/blind-spots.js +3 -2
- package/dist/observers/canvas.d.ts +18 -0
- package/dist/observers/canvas.js +76 -0
- package/dist/observers/dom.js +96 -32
- package/dist/observers/field.d.ts +11 -0
- package/dist/observers/field.js +116 -30
- package/dist/observers/install-all.js +4 -0
- package/dist/observers/media.d.ts +2 -0
- package/dist/observers/media.js +32 -0
- package/dist/observers/net-detail/network-body.d.ts +2 -0
- package/dist/observers/net-detail/network-body.js +8 -1
- package/dist/observers/network.js +82 -13
- package/dist/observers/perf.js +53 -1
- package/dist/observers/route.d.ts +2 -0
- package/dist/observers/route.js +39 -9
- package/dist/presenter/carousel/carousel.js +2 -7
- package/dist/presenter/carousel/panel-slides.d.ts +2 -4
- package/dist/presenter/carousel/panel-slides.js +17 -15
- package/dist/presenter/chrome/log-memory.d.ts +1 -0
- package/dist/presenter/chrome/presenter-log.d.ts +7 -0
- package/dist/presenter/chrome/presenter-log.js +48 -8
- package/dist/presenter/chrome/presenter-morph.d.ts +1 -0
- package/dist/presenter/chrome/presenter-morph.js +34 -0
- package/dist/presenter/chrome/presenter-report-copy.d.ts +12 -4
- package/dist/presenter/chrome/presenter-report-copy.js +12 -4
- package/dist/presenter/hud-telemetry.js +55 -4
- package/dist/presenter/presenter-account-styles.js +3 -3
- package/dist/presenter/presenter-account.d.ts +27 -5
- package/dist/presenter/presenter-account.js +83 -6
- package/dist/presenter/presenter-agent-link.d.ts +9 -0
- package/dist/presenter/presenter-agent-link.js +62 -0
- package/dist/presenter/presenter-chat-views.d.ts +25 -4
- package/dist/presenter/presenter-chat-views.js +339 -72
- package/dist/presenter/presenter-config.d.ts +3 -0
- package/dist/presenter/presenter-config.js +2 -0
- package/dist/presenter/presenter-controls.d.ts +0 -1
- package/dist/presenter/presenter-controls.js +13 -91
- package/dist/presenter/presenter-design-tokens.js +1 -1
- package/dist/presenter/presenter-frame.d.ts +3 -2
- package/dist/presenter/presenter-frame.js +31 -24
- package/dist/presenter/presenter-harness-row.d.ts +56 -0
- package/dist/presenter/presenter-harness-row.js +170 -0
- package/dist/presenter/presenter-personas.d.ts +35 -0
- package/dist/presenter/presenter-personas.js +95 -0
- package/dist/presenter/presenter-plan.js +25 -24
- package/dist/presenter/presenter-report-styles.js +23 -22
- package/dist/presenter/presenter-report.js +29 -13
- package/dist/presenter/presenter-run-state.js +2 -1
- package/dist/presenter/presenter-settings-styles.js +8 -4
- package/dist/presenter/presenter-settings.d.ts +4 -4
- package/dist/presenter/presenter-settings.js +66 -28
- package/dist/presenter/presenter-shell-styles.js +12 -3
- package/dist/presenter/presenter-shell.d.ts +11 -3
- package/dist/presenter/presenter-shell.js +60 -22
- package/dist/presenter/presenter-styles.js +0 -2
- package/dist/presenter/presenter-workspace.js +10 -3
- package/dist/presenter/presenter.d.ts +3 -2
- package/dist/presenter/presenter.js +107 -25
- package/dist/registry/declared-platform.js +2 -0
- package/dist/registry/store-adapters.d.ts +5 -2
- package/dist/registry/store-adapters.js +40 -10
- package/dist/reticle-inject.js +771 -703
- package/dist/reticle.d.ts +4 -2
- package/dist/reticle.js +72 -8
- package/dist/security/page-location.d.ts +2 -0
- package/dist/security/page-location.js +7 -0
- package/dist/security/serialization.js +1 -1
- package/dist/storage-keys.d.ts +4 -2
- package/dist/storage-keys.js +8 -3
- package/dist/timers/native/native-timers.d.ts +1 -0
- package/dist/timers/native/native-timers.js +5 -0
- package/dist/transport/transport.d.ts +1 -0
- package/dist/transport/transport.js +23 -3
- package/dist/transport/unreachable-message.d.ts +1 -1
- package/dist/transport/unreachable-message.js +3 -5
- package/package.json +6 -2
- package/dist/presenter/carousel/offer-card.d.ts +0 -21
- package/dist/presenter/carousel/offer-card.js +0 -56
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isDangerousActionText } from '@reticlehq/core';
|
|
2
|
-
import { getAccessibleName } from '../dom/a11y.js';
|
|
1
|
+
import { OutwardAction, isDangerousActionText, isInertHref, isDangerousNavigation, isPaymentField, outwardActionOf, outwardRefusal, } from '@reticlehq/core';
|
|
2
|
+
import { getAccessibleName, getRole } from '../dom/a11y.js';
|
|
3
3
|
import { isHtmlElement } from '../dom/realm.js';
|
|
4
4
|
const LABEL_VALUED_INPUT_TYPES = new Set([
|
|
5
5
|
'submit',
|
|
@@ -16,7 +16,17 @@ function holdsUserText(el) {
|
|
|
16
16
|
return !LABEL_VALUED_INPUT_TYPES.has(el.type.toLowerCase());
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
+
const ANCHOR_TAG = 'A';
|
|
20
|
+
function navigatingHref(el) {
|
|
21
|
+
if (ANCHOR_TAG !== el.tagName)
|
|
22
|
+
return undefined;
|
|
23
|
+
const href = el.getAttribute('href');
|
|
24
|
+
return null === href || isInertHref(href) ? undefined : href;
|
|
25
|
+
}
|
|
19
26
|
export function dangerousActionContext(el) {
|
|
27
|
+
const href = navigatingHref(el);
|
|
28
|
+
if (href !== undefined)
|
|
29
|
+
return href;
|
|
20
30
|
const form = el.closest('form');
|
|
21
31
|
const ownText = holdsUserText(el)
|
|
22
32
|
? ['', '']
|
|
@@ -35,6 +45,37 @@ export function submitControlFor(el) {
|
|
|
35
45
|
const found = el.closest('form')?.querySelector(SUBMIT_CONTROL_SELECTOR);
|
|
36
46
|
return isHtmlElement(found) ? found : null;
|
|
37
47
|
}
|
|
38
|
-
export function requiresDangerousConfirmation(
|
|
39
|
-
|
|
48
|
+
export function requiresDangerousConfirmation(el) {
|
|
49
|
+
const href = navigatingHref(el);
|
|
50
|
+
if (href !== undefined)
|
|
51
|
+
return isDangerousNavigation(href);
|
|
52
|
+
return isDangerousActionText(dangerousActionContext(el), getRole(el));
|
|
53
|
+
}
|
|
54
|
+
let outwardAllowed;
|
|
55
|
+
export function setOutwardPolicy(allowed) {
|
|
56
|
+
outwardAllowed = allowed;
|
|
57
|
+
}
|
|
58
|
+
export function assertOutwardAllowed(targets) {
|
|
59
|
+
if (outwardAllowed === undefined)
|
|
60
|
+
return;
|
|
61
|
+
for (const el of targets) {
|
|
62
|
+
if (null === el)
|
|
63
|
+
continue;
|
|
64
|
+
const kind = outwardActionOf(dangerousActionContext(el), getRole(el));
|
|
65
|
+
if (kind !== undefined && !outwardAllowed.includes(kind))
|
|
66
|
+
throw new Error(outwardRefusal(kind));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function assertPaymentEntryAllowed(el) {
|
|
70
|
+
if (outwardAllowed === undefined || outwardAllowed.includes(OutwardAction.PAY))
|
|
71
|
+
return;
|
|
72
|
+
const facts = {
|
|
73
|
+
autocomplete: el.getAttribute('autocomplete') ?? undefined,
|
|
74
|
+
name: el.getAttribute('name') ?? undefined,
|
|
75
|
+
id: el.getAttribute('id') ?? undefined,
|
|
76
|
+
inputMode: el.getAttribute('inputmode') ?? undefined,
|
|
77
|
+
label: `${getAccessibleName(el)} ${el.getAttribute('placeholder') ?? ''}`,
|
|
78
|
+
};
|
|
79
|
+
if (isPaymentField(facts))
|
|
80
|
+
throw new Error(outwardRefusal(OutwardAction.PAY));
|
|
40
81
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ActionTarget } from '../dom/realm.js';
|
|
2
|
+
export declare function isAutofillSafeTarget(el: Element, ua?: string): boolean;
|
|
2
3
|
export declare function setNativeValue(el: HTMLInputElement | HTMLTextAreaElement, value: string): boolean;
|
|
3
4
|
export declare function assertNotRichText(el: ActionTarget, action: string): void;
|
|
4
5
|
export declare function assertEditable(el: HTMLInputElement | HTMLTextAreaElement, action: string): void;
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { captureValueSetter } from '../patching/capture-method.js';
|
|
2
2
|
import { isHtmlElement, valuePrototypeOf } from '../dom/realm.js';
|
|
3
|
+
const PASSWORD_AUTOCOMPLETE = /\b(current|new)-password\b/;
|
|
4
|
+
const NOT_WEBKIT = /Chrome|Chromium|Edg\/|Firefox|Gecko\//;
|
|
5
|
+
export function isAutofillSafeTarget(el, ua = navigator.userAgent) {
|
|
6
|
+
if (!(el instanceof HTMLInputElement))
|
|
7
|
+
return false;
|
|
8
|
+
const password = 'password' === el.type.toLowerCase() ||
|
|
9
|
+
PASSWORD_AUTOCOMPLETE.test(el.getAttribute('autocomplete') ?? '');
|
|
10
|
+
if (!password || NOT_WEBKIT.test(ua))
|
|
11
|
+
return false;
|
|
12
|
+
return 600 <= Number(/AppleWebKit\/(\d+)/.exec(ua)?.[1] ?? 0);
|
|
13
|
+
}
|
|
3
14
|
export function setNativeValue(el, value) {
|
|
4
15
|
const proto = valuePrototypeOf(el);
|
|
5
16
|
const setter = proto === undefined ? undefined : captureValueSetter(proto);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReticleConnectOptions } from './connect-options.js';
|
|
2
|
+
export interface ActivateOptions {
|
|
3
|
+
publicKey: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ActivateHost {
|
|
6
|
+
location: Pick<Location, 'href' | 'origin'>;
|
|
7
|
+
history: Pick<History, 'replaceState' | 'state'>;
|
|
8
|
+
now: () => number;
|
|
9
|
+
connect: () => Promise<{
|
|
10
|
+
connect: (options: ReticleConnectOptions) => void;
|
|
11
|
+
}>;
|
|
12
|
+
warn: (message: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function activate(options: ActivateOptions, host?: ActivateHost | undefined): Promise<boolean>;
|
package/dist/activate.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { HelloEnv, PRODUCTION_ACTIVATE_PARAM, verifyActivationTicket, } from '@reticlehq/core/activation';
|
|
2
|
+
const REFUSED_PREFIX = '[Reticle] activation refused: ';
|
|
3
|
+
function pageHost() {
|
|
4
|
+
if ('undefined' === typeof location || 'undefined' === typeof history)
|
|
5
|
+
return undefined;
|
|
6
|
+
return {
|
|
7
|
+
location,
|
|
8
|
+
history,
|
|
9
|
+
now: () => Date.now(),
|
|
10
|
+
connect: () => import('./reticle-singleton.js').then((sdk) => sdk.reticle),
|
|
11
|
+
warn: (message) => console.warn(message),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export async function activate(options, host = pageHost()) {
|
|
15
|
+
if (host === undefined)
|
|
16
|
+
return false;
|
|
17
|
+
const url = new URL(host.location.href);
|
|
18
|
+
const ticket = url.searchParams.get(PRODUCTION_ACTIVATE_PARAM);
|
|
19
|
+
if (null === ticket)
|
|
20
|
+
return false;
|
|
21
|
+
url.searchParams.delete(PRODUCTION_ACTIVATE_PARAM);
|
|
22
|
+
host.history.replaceState(host.history.state, '', url.toString());
|
|
23
|
+
const verdict = await verifyActivationTicket(ticket, {
|
|
24
|
+
publicKey: options.publicKey,
|
|
25
|
+
origin: host.location.origin,
|
|
26
|
+
now: host.now(),
|
|
27
|
+
});
|
|
28
|
+
if (!verdict.ok) {
|
|
29
|
+
host.warn(`${REFUSED_PREFIX}${verdict.reason}`);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const { payload } = verdict;
|
|
33
|
+
const sdk = await host.connect();
|
|
34
|
+
sdk.connect({
|
|
35
|
+
url: payload.bridge,
|
|
36
|
+
token: payload.nonce,
|
|
37
|
+
env: HelloEnv.PRODUCTION,
|
|
38
|
+
scope: payload.scope,
|
|
39
|
+
allowInProduction: true,
|
|
40
|
+
allowNonLocalhost: true,
|
|
41
|
+
});
|
|
42
|
+
return true;
|
|
43
|
+
}
|
package/dist/busy.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function trackBusy<T>(work: Promise<T>, signal: (name: string, data: Record<string, unknown>) => void): Promise<T>;
|
|
2
|
+
export declare const SHORT_TIMER_MS = 1000;
|
|
3
|
+
export declare function trackShortTimers(signal: (name: string, data: Record<string, unknown>) => void, maxMs?: number): () => void;
|
package/dist/busy.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { RETICLE_BUSY_SIGNAL } from '@reticlehq/core';
|
|
2
|
+
import { captureMethod } from './patching/capture-method.js';
|
|
3
|
+
export function trackBusy(work, signal) {
|
|
4
|
+
signal(RETICLE_BUSY_SIGNAL, { delta: 1 });
|
|
5
|
+
const done = () => {
|
|
6
|
+
signal(RETICLE_BUSY_SIGNAL, { delta: -1 });
|
|
7
|
+
};
|
|
8
|
+
work.then(done, done);
|
|
9
|
+
return work;
|
|
10
|
+
}
|
|
11
|
+
export const SHORT_TIMER_MS = 1000;
|
|
12
|
+
export function trackShortTimers(signal, maxMs = SHORT_TIMER_MS) {
|
|
13
|
+
const realSet = captureMethod(window, 'setTimeout');
|
|
14
|
+
const realClear = captureMethod(window, 'clearTimeout');
|
|
15
|
+
const callSet = realSet.bind(window);
|
|
16
|
+
const callClear = realClear.bind(window);
|
|
17
|
+
const pending = new Set();
|
|
18
|
+
const end = (id) => {
|
|
19
|
+
if (pending.delete(id))
|
|
20
|
+
signal(RETICLE_BUSY_SIGNAL, { delta: -1 });
|
|
21
|
+
};
|
|
22
|
+
window.setTimeout = ((cb, delay = 0, ...args) => {
|
|
23
|
+
if ('function' !== typeof cb || delay > maxMs)
|
|
24
|
+
return Reflect.apply(realSet, window, [cb, delay, ...args]);
|
|
25
|
+
signal(RETICLE_BUSY_SIGNAL, { delta: 1 });
|
|
26
|
+
const id = callSet(() => {
|
|
27
|
+
end(id);
|
|
28
|
+
cb(...args);
|
|
29
|
+
}, delay);
|
|
30
|
+
pending.add(id);
|
|
31
|
+
return id;
|
|
32
|
+
});
|
|
33
|
+
window.clearTimeout = ((id) => {
|
|
34
|
+
if (id !== undefined)
|
|
35
|
+
end(id);
|
|
36
|
+
callClear(id);
|
|
37
|
+
});
|
|
38
|
+
return () => {
|
|
39
|
+
window.setTimeout = realSet;
|
|
40
|
+
window.clearTimeout = realClear;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -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,
|
|
@@ -122,6 +135,9 @@ function readState(ref, store, path, depth) {
|
|
|
122
135
|
const names = storeNames();
|
|
123
136
|
if (path !== undefined || depth !== undefined) {
|
|
124
137
|
const rawStores = readStoresRaw(store);
|
|
138
|
+
if (store !== undefined && !Object.hasOwn(rawStores, store)) {
|
|
139
|
+
return { store, path, found: false, value: null, storeNames: names };
|
|
140
|
+
}
|
|
125
141
|
const base = store !== undefined ? rawStores[store] : { stores: rawStores, storeNames: names };
|
|
126
142
|
const selection = path !== undefined ? selectPath(base, path) : { found: true, value: base };
|
|
127
143
|
const selected = selection.found && depth !== undefined ? capDepth(selection.value, depth) : selection.value;
|
|
@@ -142,8 +158,9 @@ function readState(ref, store, path, depth) {
|
|
|
142
158
|
stores,
|
|
143
159
|
storeNames: names,
|
|
144
160
|
};
|
|
145
|
-
if (truncation !== undefined)
|
|
161
|
+
if (truncation !== undefined) {
|
|
146
162
|
result.truncation = truncation;
|
|
163
|
+
}
|
|
147
164
|
if (ref !== undefined && ref.length > 0) {
|
|
148
165
|
const el = refs.resolve(ref);
|
|
149
166
|
if (null === el) {
|
|
@@ -158,8 +175,9 @@ function readState(ref, store, path, depth) {
|
|
|
158
175
|
}
|
|
159
176
|
function listAnimations() {
|
|
160
177
|
const doc = document;
|
|
161
|
-
if (typeof doc.getAnimations !== 'function')
|
|
178
|
+
if (typeof doc.getAnimations !== 'function') {
|
|
162
179
|
return { animations: [] };
|
|
180
|
+
}
|
|
163
181
|
const animations = doc.getAnimations().map((a) => {
|
|
164
182
|
const effect = a.effect;
|
|
165
183
|
const timing = effect?.getTiming();
|
|
@@ -174,8 +192,9 @@ function listAnimations() {
|
|
|
174
192
|
return { animations };
|
|
175
193
|
}
|
|
176
194
|
export function resolveNavigationUrl(rawUrl, baseUrl) {
|
|
177
|
-
if (0 === rawUrl.length || rawUrl.length > TRANSPORT_LIMITS.MAX_URL_LENGTH)
|
|
195
|
+
if (0 === rawUrl.length || rawUrl.length > TRANSPORT_LIMITS.MAX_URL_LENGTH) {
|
|
178
196
|
return null;
|
|
197
|
+
}
|
|
179
198
|
try {
|
|
180
199
|
const url = new URL(rawUrl, baseUrl);
|
|
181
200
|
return 'http:' === url.protocol || 'https:' === url.protocol ? url.toString() : null;
|
|
@@ -190,29 +209,39 @@ export function createCommandRegistry() {
|
|
|
190
209
|
scope: str(args['scope']),
|
|
191
210
|
mode: str(args['mode']) ?? SnapshotMode.FULL,
|
|
192
211
|
includeRoot: true === args['includeRoot'],
|
|
212
|
+
ids: true === args['ids'],
|
|
213
|
+
audit: true === args['audit'],
|
|
193
214
|
}));
|
|
194
215
|
reg.set(ReticleCommand.QUERY, (args) => {
|
|
195
216
|
const limit = args['limit'];
|
|
196
217
|
return runQuery(queryFromArgs(args), 'number' === typeof limit ? limit : undefined);
|
|
197
218
|
});
|
|
198
|
-
reg.set(ReticleCommand.MATCH, (args) => matchQuery(ElementQuerySchema.parse(record(args['query'])), str(args['state'])));
|
|
199
|
-
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) => {
|
|
200
221
|
const action = str(args['action']) ?? '';
|
|
201
|
-
|
|
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;
|
|
202
230
|
});
|
|
203
|
-
reg.set(ReticleCommand.
|
|
204
|
-
reg.set(ReticleCommand.INSPECT, (args) => inspect(str(args['ref']) ?? ''));
|
|
231
|
+
reg.set(ReticleCommand.INSPECT, (args) => inspect(str(args['ref']) ?? '', true === args[INSPECT_REVEAL_ARG]));
|
|
205
232
|
reg.set(ReticleCommand.ANIMATIONS, () => listAnimations());
|
|
206
233
|
reg.set(ReticleCommand.CLOCK, (args) => {
|
|
207
234
|
if (true === args['reset']) {
|
|
208
235
|
resetClock();
|
|
209
236
|
}
|
|
210
237
|
else {
|
|
211
|
-
if (true === args['freeze'])
|
|
238
|
+
if (true === args['freeze']) {
|
|
212
239
|
freezeClock();
|
|
240
|
+
}
|
|
213
241
|
const adv = args['advanceMs'];
|
|
214
|
-
if ('number' === typeof adv)
|
|
242
|
+
if ('number' === typeof adv) {
|
|
215
243
|
advanceClock(adv);
|
|
244
|
+
}
|
|
216
245
|
}
|
|
217
246
|
return { frozen: isClockFrozen() };
|
|
218
247
|
});
|
|
@@ -220,6 +249,7 @@ export function createCommandRegistry() {
|
|
|
220
249
|
reg.set(ReticleCommand.STORAGE_READ, (args) => readStorage(str(args['area'])));
|
|
221
250
|
reg.set(ReticleCommand.CAPABILITIES, () => getCapabilities());
|
|
222
251
|
reg.set(ReticleCommand.CAPTURE, (args) => captureDesktopWindow(true === args['fullPage']));
|
|
252
|
+
reg.set(ReticleCommand.RENDER, () => import('../dom/render-page.js').then((m) => m.renderPage()));
|
|
223
253
|
reg.set(ReticleCommand.SCROLL, (args) => {
|
|
224
254
|
const dy = args['dy'];
|
|
225
255
|
const fraction = args['fraction'];
|
|
@@ -227,11 +257,13 @@ export function createCommandRegistry() {
|
|
|
227
257
|
});
|
|
228
258
|
reg.set(ReticleCommand.NAVIGATE, (args) => {
|
|
229
259
|
const rawUrl = str(args['url']);
|
|
230
|
-
if (rawUrl === undefined || 0 === rawUrl.length)
|
|
260
|
+
if (rawUrl === undefined || 0 === rawUrl.length) {
|
|
231
261
|
return { ok: false, reason: 'url required' };
|
|
262
|
+
}
|
|
232
263
|
const url = resolveNavigationUrl(rawUrl, window.location.href);
|
|
233
|
-
if (null === url)
|
|
264
|
+
if (null === url) {
|
|
234
265
|
return { ok: false, reason: 'only http(s) navigation is allowed' };
|
|
266
|
+
}
|
|
235
267
|
window.location.assign(url);
|
|
236
268
|
return { ok: true, url };
|
|
237
269
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
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;
|
package/dist/connect-options.js
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
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
|
+
}
|
package/dist/dom/a11y.d.ts
CHANGED
|
@@ -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;
|