@reticlehq/browser 2.13.1 → 3.1.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/actions-dom.d.ts +8 -20
- package/dist/actions/actions-dom.js +70 -69
- package/dist/actions/actions-press.d.ts +14 -0
- package/dist/actions/actions-press.js +123 -0
- package/dist/actions/actions.d.ts +1 -89
- package/dist/actions/actions.js +64 -365
- package/dist/actions/appeared-text.d.ts +0 -20
- package/dist/actions/appeared-text.js +6 -36
- package/dist/actions/danger-context.d.ts +3 -0
- package/dist/actions/danger-context.js +39 -0
- package/dist/actions/scroll.d.ts +8 -10
- package/dist/actions/scroll.js +28 -17
- package/dist/actions/synthetic/synthetic-input.d.ts +2 -0
- package/dist/actions/synthetic/synthetic-input.js +13 -0
- package/dist/actions/value-input.d.ts +0 -30
- package/dist/actions/value-input.js +0 -33
- package/dist/commands/commands.d.ts +0 -2
- package/dist/commands/commands.js +10 -70
- package/dist/connect-options.d.ts +2 -96
- package/dist/dom/a11y.d.ts +0 -29
- package/dist/dom/a11y.js +3 -90
- package/dist/dom/addressing/auto-anchor.d.ts +25 -0
- package/dist/dom/addressing/auto-anchor.js +41 -0
- package/dist/dom/addressing/refs.d.ts +14 -0
- package/dist/dom/addressing/refs.js +114 -0
- package/dist/dom/addressing/source.d.ts +9 -0
- package/dist/dom/addressing/source.js +29 -0
- package/dist/dom/chart.d.ts +0 -61
- package/dist/dom/chart.js +0 -60
- package/dist/dom/desktop-capture.d.ts +0 -30
- package/dist/dom/desktop-capture.js +1 -73
- package/dist/dom/dom-ignore.d.ts +0 -30
- package/dist/dom/dom-ignore.js +1 -48
- package/dist/dom/occlusion.d.ts +0 -7
- package/dist/dom/occlusion.js +31 -12
- package/dist/dom/paint-context.d.ts +6 -0
- package/dist/dom/paint-context.js +38 -0
- package/dist/dom/query.d.ts +0 -14
- package/dist/dom/query.js +50 -216
- package/dist/dom/realm.d.ts +0 -20
- package/dist/dom/realm.js +0 -28
- package/dist/dom/shadow-registry.d.ts +0 -33
- package/dist/dom/shadow-registry.js +2 -72
- package/dist/dom/snapshot.d.ts +2 -43
- package/dist/dom/snapshot.js +27 -152
- package/dist/dom/theme.d.ts +0 -37
- package/dist/dom/theme.js +2 -52
- package/dist/dom/virtualized.d.ts +0 -17
- package/dist/dom/virtualized.js +0 -27
- package/dist/edit-epoch.d.ts +1 -23
- package/dist/edit-epoch.js +1 -53
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -28
- package/dist/observers/animation.d.ts +0 -1
- package/dist/observers/animation.js +1 -4
- package/dist/observers/blind-spots.d.ts +0 -26
- package/dist/observers/blind-spots.js +3 -62
- package/dist/observers/console.d.ts +1 -2
- package/dist/observers/console.js +41 -30
- package/dist/observers/context-open.d.ts +1 -11
- package/dist/observers/context-open.js +10 -14
- package/dist/observers/departure.d.ts +3 -0
- package/dist/observers/departure.js +52 -0
- package/dist/observers/dialogs.d.ts +2 -0
- package/dist/observers/dialogs.js +39 -0
- package/dist/observers/dom.js +28 -52
- package/dist/observers/download.d.ts +1 -2
- package/dist/observers/download.js +39 -56
- package/dist/observers/focus.d.ts +0 -6
- package/dist/observers/focus.js +0 -7
- package/dist/observers/frames.d.ts +0 -9
- package/dist/observers/frames.js +1 -28
- package/dist/observers/health.d.ts +0 -5
- package/dist/observers/health.js +2 -34
- package/dist/observers/install-all.d.ts +2 -0
- package/dist/observers/install-all.js +26 -27
- package/dist/observers/ipc.d.ts +0 -25
- package/dist/observers/ipc.js +0 -65
- package/dist/observers/navigation.d.ts +2 -0
- package/dist/observers/navigation.js +33 -0
- package/dist/observers/net-detail/network-body.d.ts +12 -0
- package/dist/observers/net-detail/network-body.js +71 -0
- package/dist/observers/net-detail/network-redact.d.ts +1 -0
- package/dist/observers/net-detail/network-redact.js +1 -0
- package/dist/observers/network-stream.d.ts +0 -21
- package/dist/observers/network-stream.js +3 -46
- package/dist/observers/network.d.ts +3 -27
- package/dist/observers/network.js +178 -295
- package/dist/observers/perf.d.ts +0 -10
- package/dist/observers/perf.js +0 -16
- package/dist/observers/route.d.ts +1 -2
- package/dist/observers/route.js +13 -19
- package/dist/observers/scroll.d.ts +0 -1
- package/dist/observers/scroll.js +2 -11
- package/dist/observers/sdk-failure.d.ts +1 -9
- package/dist/observers/sdk-failure.js +1 -30
- package/dist/observers/state.d.ts +1 -11
- package/dist/observers/state.js +13 -41
- package/dist/observers/storage.d.ts +0 -14
- package/dist/observers/storage.js +10 -34
- package/dist/observers/types.d.ts +0 -15
- package/dist/observers/types.js +0 -14
- package/dist/patching/capture-method.d.ts +0 -24
- package/dist/patching/capture-method.js +0 -26
- package/dist/presenter/chrome/layers.d.ts +2 -0
- package/dist/presenter/chrome/layers.js +2 -0
- package/dist/presenter/chrome/log-kinds.d.ts +12 -0
- package/dist/presenter/chrome/log-kinds.js +7 -0
- package/dist/presenter/{overlay.d.ts → chrome/overlay.d.ts} +0 -1
- package/dist/presenter/{overlay.js → chrome/overlay.js} +0 -1
- package/dist/presenter/chrome/presenter-brand.d.ts +3 -0
- package/dist/presenter/{presenter-brand.js → chrome/presenter-brand.js} +0 -21
- package/dist/presenter/chrome/presenter-effects.d.ts +4 -0
- package/dist/presenter/{presenter-effects.js → chrome/presenter-effects.js} +1 -10
- package/dist/presenter/chrome/presenter-hud-chrome.d.ts +7 -0
- package/dist/presenter/{presenter-hud-chrome.js → chrome/presenter-hud-chrome.js} +0 -10
- package/dist/presenter/chrome/presenter-log.d.ts +17 -0
- package/dist/presenter/{presenter-log.js → chrome/presenter-log.js} +5 -54
- package/dist/presenter/chrome/presenter-report-copy.d.ts +51 -0
- package/dist/presenter/chrome/presenter-report-copy.js +95 -0
- package/dist/presenter/chrome/presenter-safe-html.d.ts +2 -0
- package/dist/presenter/chrome/presenter-safe-html.js +16 -0
- package/dist/presenter/{presenter-tally.d.ts → chrome/presenter-tally.d.ts} +0 -5
- package/dist/presenter/{presenter-tally.js → chrome/presenter-tally.js} +1 -5
- package/dist/presenter/{presenter-verbs.js → chrome/presenter-verbs.js} +0 -7
- package/dist/presenter/{presenter-heroicons-data.d.ts → icons/presenter-heroicons-data.d.ts} +1 -8
- package/dist/presenter/{presenter-heroicons-data.js → icons/presenter-heroicons-data.js} +1 -8
- package/dist/presenter/{presenter-icons.d.ts → icons/presenter-icons.d.ts} +1 -6
- package/dist/presenter/{presenter-icons.js → icons/presenter-icons.js} +1 -6
- package/dist/presenter/presenter-account-styles.d.ts +1 -0
- package/dist/presenter/presenter-account-styles.js +99 -0
- package/dist/presenter/presenter-account.d.ts +40 -0
- package/dist/presenter/presenter-account.js +178 -0
- package/dist/presenter/presenter-config.d.ts +10 -107
- package/dist/presenter/presenter-config.js +5 -92
- package/dist/presenter/presenter-controls.d.ts +1 -35
- package/dist/presenter/presenter-controls.js +10 -133
- package/dist/presenter/presenter-dock-layout.d.ts +0 -3
- package/dist/presenter/presenter-dock-layout.js +1 -5
- package/dist/presenter/presenter-drag.d.ts +2 -42
- package/dist/presenter/presenter-drag.js +3 -76
- package/dist/presenter/presenter-glow.d.ts +0 -21
- package/dist/presenter/presenter-glow.js +2 -28
- package/dist/presenter/presenter-hud-position.d.ts +18 -0
- package/dist/presenter/presenter-hud-position.js +50 -0
- package/dist/presenter/presenter-report-styles.d.ts +0 -6
- package/dist/presenter/presenter-report-styles.js +22 -7
- package/dist/presenter/presenter-report.d.ts +5 -7
- package/dist/presenter/presenter-report.js +44 -95
- package/dist/presenter/presenter-run-state.d.ts +1 -8
- package/dist/presenter/presenter-run-state.js +1 -6
- package/dist/presenter/presenter-settings-styles.d.ts +0 -1
- package/dist/presenter/presenter-settings-styles.js +2 -2
- package/dist/presenter/presenter-settings.d.ts +5 -23
- package/dist/presenter/presenter-settings.js +21 -33
- package/dist/presenter/presenter-shell-styles.js +23 -20
- package/dist/presenter/presenter-shell.d.ts +6 -18
- package/dist/presenter/presenter-shell.js +26 -77
- package/dist/presenter/presenter-styles.d.ts +2 -10
- package/dist/presenter/presenter-styles.js +6 -12
- package/dist/presenter/presenter-workspace.d.ts +4 -4
- package/dist/presenter/presenter-workspace.js +30 -10
- package/dist/presenter/presenter.d.ts +3 -63
- package/dist/presenter/presenter.js +29 -132
- package/dist/presenter/tour/tour-view.d.ts +33 -0
- package/dist/presenter/tour/tour-view.js +188 -0
- package/dist/presenter/tour/tour.d.ts +25 -0
- package/dist/presenter/tour/tour.js +245 -0
- package/dist/recorder/recorder-styles.d.ts +0 -6
- package/dist/recorder/recorder-styles.js +0 -6
- package/dist/recorder/recorder.d.ts +0 -34
- package/dist/recorder/recorder.js +6 -49
- package/dist/registry/auto-testids.d.ts +0 -19
- package/dist/registry/auto-testids.js +1 -21
- package/dist/registry/capabilities.d.ts +0 -31
- package/dist/registry/capabilities.js +1 -46
- package/dist/registry/commit-and-signal.d.ts +0 -6
- package/dist/registry/commit-and-signal.js +1 -7
- package/dist/registry/declared-channels.d.ts +2 -0
- package/dist/registry/declared-channels.js +14 -0
- package/dist/registry/declared-platform.d.ts +4 -0
- package/dist/registry/declared-platform.js +34 -0
- package/dist/registry/domains.d.ts +0 -8
- package/dist/registry/domains.js +0 -7
- package/dist/registry/emitter.d.ts +0 -14
- package/dist/registry/emitter.js +1 -11
- package/dist/registry/store-adapters.d.ts +0 -186
- package/dist/registry/store-adapters.js +1 -164
- package/dist/registry/{adapters.d.ts → stores/adapters.d.ts} +0 -10
- package/dist/registry/{adapters.js → stores/adapters.js} +0 -10
- package/dist/registry/stores.d.ts +0 -33
- package/dist/registry/stores.js +1 -60
- package/dist/reticle-presenter-helpers.d.ts +0 -13
- package/dist/reticle-presenter-helpers.js +10 -20
- package/dist/reticle-singleton.d.ts +2 -0
- package/dist/reticle-singleton.js +3 -0
- package/dist/reticle.d.ts +1 -52
- package/dist/reticle.js +115 -180
- package/dist/review/annotator-styles.js +1 -8
- package/dist/review/annotator.d.ts +2 -13
- package/dist/review/annotator.js +2 -42
- package/dist/review/mark-anchor.d.ts +0 -11
- package/dist/review/mark-anchor.js +3 -11
- package/dist/security/serialization.d.ts +0 -20
- package/dist/security/serialization.js +1 -66
- package/dist/session-continuity.d.ts +0 -16
- package/dist/session-continuity.js +1 -20
- package/dist/timers/clock.d.ts +1 -14
- package/dist/timers/clock.js +59 -60
- package/dist/timers/console/native-console.js +5 -0
- package/dist/timers/native/native-timers.d.ts +11 -0
- package/dist/timers/native/native-timers.js +48 -0
- package/dist/transport/transport.d.ts +0 -51
- package/dist/transport/transport.js +5 -131
- package/dist/transport/unreachable-message.d.ts +0 -17
- package/dist/transport/unreachable-message.js +0 -17
- package/dist/util/captured-method.d.ts +0 -35
- package/dist/util/captured-method.js +0 -35
- package/package.json +5 -4
- package/dist/actions/synthetic-input.d.ts +0 -9
- package/dist/actions/synthetic-input.js +0 -40
- package/dist/dom/auto-anchor.d.ts +0 -65
- package/dist/dom/auto-anchor.js +0 -74
- package/dist/dom/refs.d.ts +0 -90
- package/dist/dom/refs.js +0 -245
- package/dist/dom/source.d.ts +0 -53
- package/dist/dom/source.js +0 -74
- package/dist/observers/network-body.d.ts +0 -35
- package/dist/observers/network-body.js +0 -168
- package/dist/observers/network-redact.d.ts +0 -20
- package/dist/observers/network-redact.js +0 -80
- package/dist/presenter/presenter-brand.d.ts +0 -22
- package/dist/presenter/presenter-effects.d.ts +0 -13
- package/dist/presenter/presenter-hud-chrome.d.ts +0 -17
- package/dist/presenter/presenter-log.d.ts +0 -64
- package/dist/presenter/presenter-report-copy.d.ts +0 -112
- package/dist/presenter/presenter-report-copy.js +0 -156
- package/dist/presenter/presenter-test-helpers.d.ts +0 -16
- package/dist/presenter/presenter-test-helpers.js +0 -41
- package/dist/timers/native-console.js +0 -9
- package/dist/timers/native-timers.d.ts +0 -36
- package/dist/timers/native-timers.js +0 -78
- /package/dist/presenter/{presenter-verbs.d.ts → chrome/presenter-verbs.d.ts} +0 -0
- /package/dist/timers/{native-console.d.ts → console/native-console.d.ts} +0 -0
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import { Z_OVERLAY } from '../presenter/
|
|
2
|
-
/** Markup + CSS for the in-page annotation HUD (markers, hover box, composer). */
|
|
1
|
+
import { Z_OVERLAY } from '../presenter/chrome/layers.js';
|
|
3
2
|
const MARK_ATTR = 'data-reticle-mark';
|
|
4
3
|
const sel = (role) => `[${MARK_ATTR}="${role}"]`;
|
|
5
4
|
export const MARK_PLACEHOLDER = 'What should change?';
|
|
6
5
|
export const MARK_SUBMIT = 'Add';
|
|
7
6
|
export const MARK_CANCEL = 'Cancel';
|
|
8
7
|
export const MARK_PENDING_GLYPH = '+';
|
|
9
|
-
/**
|
|
10
|
-
* ABOVE the presenter overlay, because the overlay contains the page blocker annotate mode raises.
|
|
11
|
-
* One below it, the shield painted over the composer: every click on Cancel or Add landed on the
|
|
12
|
-
* blocker instead of the button, so the note could be neither saved nor dismissed. The root here is
|
|
13
|
-
* pointer-events:none, so only the marks and the composer sit above the HUD - not a new shield.
|
|
14
|
-
*/
|
|
15
8
|
const Z_MARK = Z_OVERLAY + 1;
|
|
16
9
|
export const ANNOTATOR_CSS = `
|
|
17
10
|
${sel('root')}{position:fixed;inset:0;pointer-events:none;z-index:${String(Z_MARK)};}
|
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
import { EventType } from '@reticlehq/core';
|
|
2
|
-
|
|
3
|
-
* What the HUD is told about a mark the moment it is placed.
|
|
4
|
-
*
|
|
5
|
-
* The row used to get the note and the anchor's label - "generic: my feedback" - which names
|
|
6
|
-
* neither the element nor which of several marks it is. The pin on the page is numbered, so the
|
|
7
|
-
* row carries the same number, plus the source the anchor already resolved.
|
|
8
|
-
*/
|
|
9
|
-
export interface MarkReport {
|
|
2
|
+
interface MarkReport {
|
|
10
3
|
note: string;
|
|
11
|
-
/** The anchor the agent will look the element up by, e.g. `[data-testid="deploy-submit"]`. */
|
|
12
4
|
anchor: string;
|
|
13
5
|
label: string;
|
|
14
|
-
/** 1-based, matching the number drawn in the pin. */
|
|
15
6
|
index: number;
|
|
16
|
-
/** file:line, when the app is source-stamped. */
|
|
17
7
|
source?: string;
|
|
18
8
|
}
|
|
19
9
|
export interface AnnotatorDeps {
|
|
@@ -34,9 +24,7 @@ export declare class Annotator {
|
|
|
34
24
|
get active(): boolean;
|
|
35
25
|
get markCount(): number;
|
|
36
26
|
mount(): void;
|
|
37
|
-
/** Drive marker/highlight chrome from the HUD accent swatch. */
|
|
38
27
|
setAccent(hex: string): void;
|
|
39
|
-
/** @deprecated HUD expand/collapse owns annotate mode; chrome buttons are hide/clear. */
|
|
40
28
|
attachFlagButton(btn: HTMLElement): void;
|
|
41
29
|
attachChrome(chrome: AnnotatorChrome): void;
|
|
42
30
|
destroy(): void;
|
|
@@ -45,3 +33,4 @@ export declare class Annotator {
|
|
|
45
33
|
syncAnchors(): void;
|
|
46
34
|
}
|
|
47
35
|
export declare function installAnnotator(deps: AnnotatorDeps): Annotator;
|
|
36
|
+
export {};
|
package/dist/review/annotator.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { isSyntheticInput } from '../actions/synthetic-input.js';
|
|
1
|
+
import { isSyntheticInput } from '../actions/synthetic/synthetic-input.js';
|
|
2
2
|
import { EventType } from '@reticlehq/core';
|
|
3
3
|
import { isReticleUi, isReticleOverlay } from '../dom/dom-ignore.js';
|
|
4
4
|
import { resolveMarkAnchor } from './mark-anchor.js';
|
|
5
|
-
import { nativeSetTimeout, nativeClearTimeout } from '../timers/native-timers.js';
|
|
5
|
+
import { nativeSetTimeout, nativeClearTimeout } from '../timers/native/native-timers.js';
|
|
6
6
|
import { ANNOTATOR_CSS, ANNOTATOR_ROOT_HTML, MARK_CANCEL, MARK_PENDING_GLYPH, MARK_PLACEHOLDER, MARK_SUBMIT, } from './annotator-styles.js';
|
|
7
|
-
/** The cursor must rest this long before the outline boxes the element under it - calm, not jumpy. */
|
|
8
7
|
const HIGHLIGHT_REST_MS = 130;
|
|
9
8
|
const SHAKE_MS = 250;
|
|
10
9
|
const POP_W = 280;
|
|
@@ -85,12 +84,10 @@ export class Annotator {
|
|
|
85
84
|
if (undefined !== this.#accent)
|
|
86
85
|
this.setAccent(this.#accent);
|
|
87
86
|
}
|
|
88
|
-
/** Drive marker/highlight chrome from the HUD accent swatch. */
|
|
89
87
|
setAccent(hex) {
|
|
90
88
|
this.#accent = hex;
|
|
91
89
|
this.#root?.style.setProperty('--reticle-mark-accent', hex);
|
|
92
90
|
}
|
|
93
|
-
/** @deprecated HUD expand/collapse owns annotate mode; chrome buttons are hide/clear. */
|
|
94
91
|
attachFlagButton(btn) {
|
|
95
92
|
this.attachChrome({ markersBtn: btn });
|
|
96
93
|
}
|
|
@@ -211,18 +208,11 @@ export class Annotator {
|
|
|
211
208
|
#handleClick(ev) {
|
|
212
209
|
if (!this.#active)
|
|
213
210
|
return;
|
|
214
|
-
// A click Reticle dispatched is the agent driving the app, not a person placing a mark. Without
|
|
215
|
-
// this, expanding the HUD silently disabled every `reticle_act` click while the action still
|
|
216
|
-
// reported success — a false green in our own UI. See synthetic-input.ts.
|
|
217
211
|
if (isSyntheticInput())
|
|
218
212
|
return;
|
|
219
213
|
const raw = ev.target;
|
|
220
214
|
if (!(raw instanceof Element))
|
|
221
215
|
return;
|
|
222
|
-
// The page blocker is a full-viewport shield Reticle puts up WHILE annotating, so with it on
|
|
223
|
-
// every click lands on Reticle's own UI and was discarded as such — annotate mode looked
|
|
224
|
-
// completely dead, because the one thing standing between the user and the page is the thing
|
|
225
|
-
// annotate mode turns on. Resolve what is underneath instead of giving up on the click.
|
|
226
216
|
const target = raw.hasAttribute(BLOCKER_ATTR_NAME)
|
|
227
217
|
? pageElementAt(ev.clientX, ev.clientY)
|
|
228
218
|
: raw;
|
|
@@ -274,9 +264,6 @@ export class Annotator {
|
|
|
274
264
|
if (this.#hi === undefined)
|
|
275
265
|
return;
|
|
276
266
|
const raw = ev.target;
|
|
277
|
-
// Same shield as in #handleClick: while annotating, a full-viewport blocker sits over the page,
|
|
278
|
-
// so EVERY mousemove reports it as the target. Resolving only there left the outline suppressed
|
|
279
|
-
// on every element - a crosshair with no indication of what it was on. See #handleClick.
|
|
280
267
|
const target = raw instanceof Element && raw.hasAttribute(BLOCKER_ATTR_NAME)
|
|
281
268
|
? pageElementAt(ev.clientX, ev.clientY)
|
|
282
269
|
: raw;
|
|
@@ -315,22 +302,11 @@ export class Annotator {
|
|
|
315
302
|
this.#pendingKey = mark.anchor;
|
|
316
303
|
this.#pendingTarget = mark.target;
|
|
317
304
|
this.#hideHighlight();
|
|
318
|
-
// Where the element is NOW, not where it was when the mark was made. The popover is
|
|
319
|
-
// position:fixed, so it is placed in viewport coordinates, and the stored clientX/clientY are
|
|
320
|
-
// viewport coordinates from an earlier scroll position. Reopening a mark after scrolling put the
|
|
321
|
-
// note somewhere unrelated to the thing it annotates — further away the further you had scrolled.
|
|
322
305
|
const at = this.#currentPoint(mark);
|
|
323
306
|
this.#mountPopover(mark.label, at.x, at.y, mark.note);
|
|
324
307
|
this.#dropPending(at.x, at.y);
|
|
325
308
|
this.#paintSelection();
|
|
326
309
|
}
|
|
327
|
-
/**
|
|
328
|
-
* The viewport point a mark's popover should open at.
|
|
329
|
-
*
|
|
330
|
-
* Prefers the element's live box, because that is what the note is ABOUT. Falls back to the stored
|
|
331
|
-
* coordinates only when the element is gone, where there is nothing better and the mark is already
|
|
332
|
-
* shown as stale.
|
|
333
|
-
*/
|
|
334
310
|
#currentPoint(mark) {
|
|
335
311
|
const el = mark.target;
|
|
336
312
|
if (el !== undefined && el.isConnected) {
|
|
@@ -471,7 +447,6 @@ export class Annotator {
|
|
|
471
447
|
this.#dropPin(resolved, note, x, y);
|
|
472
448
|
this.#report(note, resolved.anchor, resolved.label, this.#marks.length, sourceLabel(resolved));
|
|
473
449
|
}
|
|
474
|
-
/** Hand the HUD everything it needs to name this mark in one row. */
|
|
475
450
|
#report(note, anchor, label, index, source) {
|
|
476
451
|
const mark = { note, anchor, label, index };
|
|
477
452
|
if (source !== undefined)
|
|
@@ -560,12 +535,6 @@ export class Annotator {
|
|
|
560
535
|
this.#repositionPopover();
|
|
561
536
|
this.#paintSelection();
|
|
562
537
|
}
|
|
563
|
-
/**
|
|
564
|
-
* Keep an OPEN popover attached to its element while the page scrolls.
|
|
565
|
-
*
|
|
566
|
-
* The pins were repositioned here and the popover was not, so scrolling with a note open slid the
|
|
567
|
-
* note off its target and left it floating over unrelated content.
|
|
568
|
-
*/
|
|
569
538
|
#repositionPopover() {
|
|
570
539
|
const pop = this.#pop;
|
|
571
540
|
const mark = this.#editing;
|
|
@@ -589,7 +558,6 @@ export class Annotator {
|
|
|
589
558
|
this.#selBox.hidden = true;
|
|
590
559
|
}
|
|
591
560
|
}
|
|
592
|
-
/** "file:line" for a resolved anchor, when the app carries source stamps. */
|
|
593
561
|
function sourceLabel(resolved) {
|
|
594
562
|
return resolved.source === undefined
|
|
595
563
|
? undefined
|
|
@@ -607,15 +575,7 @@ function isElementFixed(el) {
|
|
|
607
575
|
const pos = getComputedStyle(el).position;
|
|
608
576
|
return 'fixed' === pos || 'sticky' === pos;
|
|
609
577
|
}
|
|
610
|
-
/** The blocker Reticle raises over the page while annotating; see the click handler. */
|
|
611
578
|
const BLOCKER_ATTR_NAME = 'data-reticle-blocker';
|
|
612
|
-
/**
|
|
613
|
-
* The topmost element of the HOST PAGE at a point, seeing past Reticle's own overlays.
|
|
614
|
-
*
|
|
615
|
-
* `elementsFromPoint` returns the whole stack topmost-first, so the page element is simply the first
|
|
616
|
-
* entry that is not ours. Returns undefined where the API is unavailable (jsdom) or nothing but
|
|
617
|
-
* Reticle UI is there, and the caller drops the click rather than guessing at a target.
|
|
618
|
-
*/
|
|
619
579
|
function pageElementAt(x, y) {
|
|
620
580
|
const from = document.elementsFromPoint.bind(document);
|
|
621
581
|
if (from === undefined)
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import { MarkAnchorStrategy } from '@reticlehq/core';
|
|
2
|
-
/**
|
|
3
|
-
* The element address carried by a human review mark: a re-resolvable anchor (auto-anchor's most
|
|
4
|
-
* durable tier for this element), its durability strategy, a human-legible label, and — crucially —
|
|
5
|
-
* the source file:line the agent should open. Source is reported INDEPENDENTLY of the anchor tier:
|
|
6
|
-
* a role-anchored element still carries its babel-stamped source so the agent can jump to the code.
|
|
7
|
-
*/
|
|
8
2
|
export interface MarkAnchor {
|
|
9
3
|
anchor: string;
|
|
10
4
|
strategy: MarkAnchorStrategy;
|
|
@@ -14,9 +8,4 @@ export interface MarkAnchor {
|
|
|
14
8
|
line: number;
|
|
15
9
|
};
|
|
16
10
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Resolve a clicked element into the address a human review mark carries. Reuses the same
|
|
19
|
-
* auto-anchor machinery a recorded flow uses, so a mark pins to the element the way Reticle addresses
|
|
20
|
-
* it everywhere else — and always reports the source file:line when one is available.
|
|
21
|
-
*/
|
|
22
11
|
export declare function resolveMarkAnchor(el: Element): MarkAnchor;
|
|
@@ -1,28 +1,20 @@
|
|
|
1
1
|
import { MarkAnchorStrategy } from '@reticlehq/core';
|
|
2
|
-
import { AnchorStrategy, synthesizeAnchor } from '../dom/auto-anchor.js';
|
|
2
|
+
import { AnchorStrategy, synthesizeAnchor, } from '../dom/addressing/auto-anchor.js';
|
|
3
3
|
import { getAccessibleName, getRole } from '../dom/a11y.js';
|
|
4
|
-
import { identifyComponent } from '../registry/adapters.js';
|
|
5
|
-
import { sourceFor } from '../dom/source.js';
|
|
6
|
-
/** Attribute names — defined locally per the recorder/query convention (no shared free string). */
|
|
4
|
+
import { identifyComponent } from '../registry/stores/adapters.js';
|
|
5
|
+
import { sourceFor } from '../dom/addressing/source.js';
|
|
7
6
|
const TESTID_ATTR = 'data-testid';
|
|
8
|
-
/** AnchorStrategy and MarkAnchorStrategy share string values; map explicitly (no cross-cast). */
|
|
9
7
|
const STRATEGY = {
|
|
10
8
|
[AnchorStrategy.TESTID]: MarkAnchorStrategy.TESTID,
|
|
11
9
|
[AnchorStrategy.COMPONENT]: MarkAnchorStrategy.COMPONENT,
|
|
12
10
|
[AnchorStrategy.ROLE]: MarkAnchorStrategy.ROLE,
|
|
13
11
|
[AnchorStrategy.POSITION]: MarkAnchorStrategy.POSITION,
|
|
14
12
|
};
|
|
15
|
-
/** A short, human-legible label for the element: `role "name"`, falling back to role / tag name. */
|
|
16
13
|
function labelFor(el, role, name) {
|
|
17
14
|
if (name.length > 0)
|
|
18
15
|
return role.length > 0 ? `${role} "${name}"` : `"${name}"`;
|
|
19
16
|
return role.length > 0 ? role : el.tagName.toLowerCase();
|
|
20
17
|
}
|
|
21
|
-
/**
|
|
22
|
-
* Resolve a clicked element into the address a human review mark carries. Reuses the same
|
|
23
|
-
* auto-anchor machinery a recorded flow uses, so a mark pins to the element the way Reticle addresses
|
|
24
|
-
* it everywhere else — and always reports the source file:line when one is available.
|
|
25
|
-
*/
|
|
26
18
|
export function resolveMarkAnchor(el) {
|
|
27
19
|
const testid = el.getAttribute(TESTID_ATTR) ?? undefined;
|
|
28
20
|
const info = identifyComponent(el);
|
|
@@ -1,33 +1,13 @@
|
|
|
1
1
|
import { isSensitiveKey, scrubKnownSecrets } from '@reticlehq/core';
|
|
2
|
-
/**
|
|
3
|
-
* What the transport caps removed from a value, if anything.
|
|
4
|
-
*
|
|
5
|
-
* Truncation used to be entirely silent: a 1,000-entity store came back as ~142 entities with no
|
|
6
|
-
* marker and no count, and a caller comparing it against expected data would conclude the app had
|
|
7
|
-
* lost the rest. A partial answer that cannot be distinguished from a complete one is the precise
|
|
8
|
-
* shape of a false green — the failure this project exists to prevent — so the caps now report.
|
|
9
|
-
*/
|
|
10
2
|
export interface TruncationReport {
|
|
11
|
-
/** Whole collection items not included, either past the item cap or past the node budget. */
|
|
12
3
|
droppedItems: number;
|
|
13
|
-
/** Values replaced by the `[TRUNCATED]` placeholder because a cap was hit inside them. */
|
|
14
4
|
truncatedValues: number;
|
|
15
|
-
/** Human-and-agent readable summary. Present so a consumer never has to compose one. */
|
|
16
5
|
note: string;
|
|
17
6
|
}
|
|
18
|
-
/** Convert arbitrary app state into a bounded, redacted JSON-compatible value. */
|
|
19
7
|
export declare function sanitizeForTransport(value: unknown): unknown;
|
|
20
|
-
/**
|
|
21
|
-
* As `sanitizeForTransport`, but also reports what the caps removed.
|
|
22
|
-
*
|
|
23
|
-
* Returned as a separate field rather than embedded in the value: the value has to keep the exact
|
|
24
|
-
* shape the consumer's schema declares, so a marker spliced inside it would break validation on the
|
|
25
|
-
* very payloads that are already under pressure.
|
|
26
|
-
*/
|
|
27
8
|
export declare function sanitizeWithReport(value: unknown): {
|
|
28
9
|
value: unknown;
|
|
29
10
|
truncation?: TruncationReport;
|
|
30
11
|
};
|
|
31
|
-
/** Serialize without allowing cycles, BigInt, getters, or secrets to break the transport. */
|
|
32
12
|
export declare function safeStringify(value: unknown): string;
|
|
33
13
|
export { isSensitiveKey, scrubKnownSecrets };
|
|
@@ -3,8 +3,6 @@ const TRUNCATED_VALUE = '[TRUNCATED]';
|
|
|
3
3
|
const UNSERIALIZABLE_VALUE = '[UNSERIALIZABLE]';
|
|
4
4
|
const OMIT_VALUE = Symbol('omit');
|
|
5
5
|
const MAX_KEY_LENGTH = 256;
|
|
6
|
-
// UTF-8 encodes at most ~3 bytes per JS (UTF-16) code unit, so /4 is a provably-safe bound that never
|
|
7
|
-
// exceeds the byte budget — /8 was ~1/8 of the real 1MiB wire budget and truncated legitimate state.
|
|
8
6
|
const MAX_TOTAL_CHARACTERS = Math.floor(TRANSPORT_LIMITS.MAX_MESSAGE_BYTES / 4);
|
|
9
7
|
const MAX_TOTAL_NODES = TRANSPORT_LIMITS.MAX_COLLECTION_ITEMS * 5;
|
|
10
8
|
function boundedString(value, state, max) {
|
|
@@ -13,9 +11,6 @@ function boundedString(value, state, max) {
|
|
|
13
11
|
state.remainingCharacters -= value.length;
|
|
14
12
|
return value;
|
|
15
13
|
}
|
|
16
|
-
// Count the cut. A silently shortened string is the same false green the collection caps were made
|
|
17
|
-
// to report: a caller comparing a 500k-char value against expected data sees 65k and concludes the
|
|
18
|
-
// app dropped the rest, with no marker saying WE did. The report interface exists for exactly this.
|
|
19
14
|
state.truncatedValues += 1;
|
|
20
15
|
const truncated = allowed <= TRUNCATED_VALUE.length
|
|
21
16
|
? TRUNCATED_VALUE.slice(0, allowed)
|
|
@@ -45,23 +40,13 @@ function sanitize(value, state, depth, key) {
|
|
|
45
40
|
if ('undefined' === typeof value || 'function' === typeof value || 'symbol' === typeof value) {
|
|
46
41
|
return OMIT_VALUE;
|
|
47
42
|
}
|
|
48
|
-
// An invalid Date (`new Date(NaN)` / `new Date(undefined)`, easy to land in app state) throws
|
|
49
|
-
// RangeError on toISOString — and only safeStringify catches it, so a direct sanitize caller
|
|
50
|
-
// (readStoresWithTruncation, the state observer) crashed the WHOLE state read over one bad Date.
|
|
51
|
-
// Degrade to null, the same way a non-finite number does two branches up.
|
|
52
43
|
if (value instanceof Date)
|
|
53
44
|
return Number.isNaN(value.getTime()) ? null : value.toISOString();
|
|
54
|
-
// Map and Set are common enough in app state (a normalized store keyed by id, a set of selected
|
|
55
|
-
// ids) that serializing them to `{}` — which is what the plain-object branch below does, since they
|
|
56
|
-
// have no enumerable own keys — is a false green: an agent reads empty and concludes the state is
|
|
57
|
-
// empty, when really it was unrepresentable. Convert to a readable shape, bounded by the same caps.
|
|
58
45
|
if (value instanceof Map) {
|
|
59
46
|
const out = Object.create(null);
|
|
60
47
|
let n = 0;
|
|
61
48
|
for (const [k, v] of value) {
|
|
62
49
|
if (state.nodes >= MAX_TOTAL_NODES || n >= TRANSPORT_LIMITS.MAX_COLLECTION_ITEMS) {
|
|
63
|
-
// Budget spent — STOP. `continue` iterated a million-entry Map to the end just to count drops
|
|
64
|
-
// one at a time; size-n records the remainder in one shot (like the typed-array branch).
|
|
65
50
|
state.droppedItems += value.size - n;
|
|
66
51
|
break;
|
|
67
52
|
}
|
|
@@ -78,7 +63,7 @@ function sanitize(value, state, depth, key) {
|
|
|
78
63
|
let n = 0;
|
|
79
64
|
for (const item of value) {
|
|
80
65
|
if (state.nodes >= MAX_TOTAL_NODES || n >= TRANSPORT_LIMITS.MAX_COLLECTION_ITEMS) {
|
|
81
|
-
state.droppedItems += value.size - n;
|
|
66
|
+
state.droppedItems += value.size - n;
|
|
82
67
|
break;
|
|
83
68
|
}
|
|
84
69
|
const sv = sanitize(item, state, depth + 1);
|
|
@@ -87,10 +72,6 @@ function sanitize(value, state, depth, key) {
|
|
|
87
72
|
}
|
|
88
73
|
return out;
|
|
89
74
|
}
|
|
90
|
-
// A typed array (Uint8Array, Float32Array, …) is array-like DATA, not a plain object. The
|
|
91
|
-
// plain-object branch below turned it into index-keyed keys ({"0":1,"1":2,…}) — a shape lie: an
|
|
92
|
-
// agent reading a tensor/binary field saw an object where an array lives, and a big one blew the key
|
|
93
|
-
// cap silently. Emit its numbers as a bounded array like a Set. DataView is opaque bytes — leave it.
|
|
94
75
|
if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
|
|
95
76
|
const len = value.length;
|
|
96
77
|
const out = [];
|
|
@@ -117,35 +98,15 @@ function sanitize(value, state, depth, key) {
|
|
|
117
98
|
state.seen.add(value);
|
|
118
99
|
try {
|
|
119
100
|
if (Array.isArray(value)) {
|
|
120
|
-
// Truncate by dropping whole ITEMS, never by corrupting them.
|
|
121
|
-
//
|
|
122
|
-
// The node budget used to run out mid-collection, so later items kept their shape while
|
|
123
|
-
// individual fields became the string "[TRUNCATED]" — an array field turned into a string, a
|
|
124
|
-
// boolean into a string. Consumers declare output schemas over these payloads, so that was not
|
|
125
|
-
// a degraded answer: validation rejected the whole message and the caller received NOTHING. On
|
|
126
|
-
// a page with thousands of matches that is a total loss of the query tool, in exactly the
|
|
127
|
-
// conditions where it matters most.
|
|
128
|
-
//
|
|
129
|
-
// Stopping BEFORE an item that will not fit keeps every survivor whole and type-correct. The
|
|
130
|
-
// collection's true size travels separately as a scalar (serialized first), so "how many" stays
|
|
131
|
-
// exact while the sample shrinks.
|
|
132
101
|
const out = [];
|
|
133
102
|
const considered = value.slice(0, TRANSPORT_LIMITS.MAX_COLLECTION_ITEMS);
|
|
134
|
-
// Items beyond the collection cap are dropped before the loop even sees them; count them here
|
|
135
|
-
// so the report covers BOTH reasons a caller is holding a short list.
|
|
136
103
|
state.droppedItems += Math.max(0, value.length - considered.length);
|
|
137
104
|
for (const item of considered) {
|
|
138
105
|
if (state.nodes >= MAX_TOTAL_NODES) {
|
|
139
106
|
state.droppedItems += 1;
|
|
140
107
|
continue;
|
|
141
108
|
}
|
|
142
|
-
// Checking only BEFORE the item is not enough: one that starts under the budget can cross it
|
|
143
|
-
// partway through and come back with its tail replaced by placeholders. Serialize, then keep
|
|
144
|
-
// it only if it fitted — otherwise discard it and stop, so what ships is always whole.
|
|
145
109
|
const sanitized = sanitize(item, state, depth + 1);
|
|
146
|
-
// `>=`, not `>`: sanitize stops AT the ceiling rather than passing it, so the budget never
|
|
147
|
-
// reads as exceeded. Reaching it during this item means some field inside was replaced by a
|
|
148
|
-
// placeholder, which makes the item schema-invalid — drop it and stop.
|
|
149
110
|
if (state.nodes >= MAX_TOTAL_NODES) {
|
|
150
111
|
state.droppedItems += 1;
|
|
151
112
|
continue;
|
|
@@ -155,24 +116,9 @@ function sanitize(value, state, depth, key) {
|
|
|
155
116
|
return out;
|
|
156
117
|
}
|
|
157
118
|
const out = Object.create(null);
|
|
158
|
-
// Scalars first, collections second. The node budget is spent in iteration order, so a large
|
|
159
|
-
// array sitting earlier in the object would consume the whole budget and turn the scalars after
|
|
160
|
-
// it into "[TRUNCATED]". Those scalars are the summary fields — a match `count`, a `total`, a
|
|
161
|
-
// status — and a summary that degrades to a placeholder while its own sample survives is the
|
|
162
|
-
// worst trade available: the caller keeps a partial list and loses the number that says the list
|
|
163
|
-
// is partial. Ordering by cost makes that impossible regardless of how a producer writes its
|
|
164
|
-
// object literal, so no caller has to know this rule to stay correct.
|
|
165
119
|
const allKeys = Object.keys(value);
|
|
166
120
|
const keys = allKeys.slice(0, TRANSPORT_LIMITS.MAX_OBJECT_KEYS);
|
|
167
|
-
// Keys past the cap are dropped — count them, like the array/Map/Set paths do, so a 5,000-key
|
|
168
|
-
// store reported as 200 keys carries a droppedItems marker instead of reading as complete.
|
|
169
121
|
state.droppedItems += Math.max(0, allKeys.length - keys.length);
|
|
170
|
-
// Read each key's value ONCE, inside the guard. A property getter can throw — MobX strict mode,
|
|
171
|
-
// a Vue reactive trap read outside a reactive context, any hostile Proxy — and that throw must
|
|
172
|
-
// cost only its own key, not the whole object read. The earlier code dereferenced the getter in
|
|
173
|
-
// an unguarded `isScalar` (and again in the sanitize call: two invocations, doubling side
|
|
174
|
-
// effects), so one bad property lost the entire STATE_READ — the exact silent-loss shape the Date
|
|
175
|
-
// guard above was written to prevent. Snapshot first, then partition scalars-before-collections.
|
|
176
122
|
const read = keys.map((key) => {
|
|
177
123
|
try {
|
|
178
124
|
const v = value[key];
|
|
@@ -203,17 +149,9 @@ function sanitize(value, state, depth, key) {
|
|
|
203
149
|
state.seen.delete(value);
|
|
204
150
|
}
|
|
205
151
|
}
|
|
206
|
-
/** Convert arbitrary app state into a bounded, redacted JSON-compatible value. */
|
|
207
152
|
export function sanitizeForTransport(value) {
|
|
208
153
|
return sanitizeWithReport(value).value;
|
|
209
154
|
}
|
|
210
|
-
/**
|
|
211
|
-
* As `sanitizeForTransport`, but also reports what the caps removed.
|
|
212
|
-
*
|
|
213
|
-
* Returned as a separate field rather than embedded in the value: the value has to keep the exact
|
|
214
|
-
* shape the consumer's schema declares, so a marker spliced inside it would break validation on the
|
|
215
|
-
* very payloads that are already under pressure.
|
|
216
|
-
*/
|
|
217
155
|
export function sanitizeWithReport(value) {
|
|
218
156
|
const state = {
|
|
219
157
|
seen: new WeakSet(),
|
|
@@ -240,7 +178,6 @@ export function sanitizeWithReport(value) {
|
|
|
240
178
|
},
|
|
241
179
|
};
|
|
242
180
|
}
|
|
243
|
-
/** Serialize without allowing cycles, BigInt, getters, or secrets to break the transport. */
|
|
244
181
|
export function safeStringify(value) {
|
|
245
182
|
try {
|
|
246
183
|
return JSON.stringify(sanitizeForTransport(value));
|
|
@@ -249,6 +186,4 @@ export function safeStringify(value) {
|
|
|
249
186
|
return JSON.stringify(UNSERIALIZABLE_VALUE);
|
|
250
187
|
}
|
|
251
188
|
}
|
|
252
|
-
// Re-exported: these moved to @reticlehq/core (they are wire rules, not DOM rules).
|
|
253
|
-
// Kept on this module's surface so every existing importer inside the SDK is unaffected.
|
|
254
189
|
export { isSensitiveKey, scrubKnownSecrets };
|
|
@@ -1,17 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Keep a tab's session id across a reload.
|
|
3
|
-
*
|
|
4
|
-
* The id was minted fresh on every `connect()`. A reload is a new document, so the page came back as
|
|
5
|
-
* a NEW session while the agent still held the old id — and every call after
|
|
6
|
-
* `reticle_navigate { reload: true }` was refused with "no browser session connected". Reported on 6
|
|
7
|
-
* of 6 apps; a reload is the most ordinary thing an agent does.
|
|
8
|
-
*
|
|
9
|
-
* `sessionStorage` is exactly the right scope: it survives reloads and same-tab navigations, and is
|
|
10
|
-
* NOT shared with another tab of the same app — so two tabs stay two sessions, which is what the
|
|
11
|
-
* multi-session tooling assumes.
|
|
12
|
-
*
|
|
13
|
-
* An explicit id still wins. `connect({ session })` and the `__reticle_session` URL param a lease
|
|
14
|
-
* stamps are callers ASSERTING an identity, not asking for one; they are also remembered, so a
|
|
15
|
-
* leased tab that reloads rejoins its own lease.
|
|
16
|
-
*/
|
|
17
1
|
export declare function rememberSessionLabel(explicit: string | undefined, store: Storage | undefined, generate: () => string): string;
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Keep a tab's session id across a reload.
|
|
3
|
-
*
|
|
4
|
-
* The id was minted fresh on every `connect()`. A reload is a new document, so the page came back as
|
|
5
|
-
* a NEW session while the agent still held the old id — and every call after
|
|
6
|
-
* `reticle_navigate { reload: true }` was refused with "no browser session connected". Reported on 6
|
|
7
|
-
* of 6 apps; a reload is the most ordinary thing an agent does.
|
|
8
|
-
*
|
|
9
|
-
* `sessionStorage` is exactly the right scope: it survives reloads and same-tab navigations, and is
|
|
10
|
-
* NOT shared with another tab of the same app — so two tabs stay two sessions, which is what the
|
|
11
|
-
* multi-session tooling assumes.
|
|
12
|
-
*
|
|
13
|
-
* An explicit id still wins. `connect({ session })` and the `__reticle_session` URL param a lease
|
|
14
|
-
* stamps are callers ASSERTING an identity, not asking for one; they are also remembered, so a
|
|
15
|
-
* leased tab that reloads rejoins its own lease.
|
|
16
|
-
*/
|
|
17
|
-
/** Where the id lives. Namespaced like the URL param it mirrors. */
|
|
18
1
|
const STORAGE_KEY = '__reticle_session';
|
|
19
2
|
export function rememberSessionLabel(explicit, store, generate) {
|
|
20
3
|
const read = () => {
|
|
@@ -23,7 +6,7 @@ export function rememberSessionLabel(explicit, store, generate) {
|
|
|
23
6
|
return value !== null && value !== undefined && value.length > 0 ? value : undefined;
|
|
24
7
|
}
|
|
25
8
|
catch {
|
|
26
|
-
return undefined;
|
|
9
|
+
return undefined;
|
|
27
10
|
}
|
|
28
11
|
};
|
|
29
12
|
const write = (value) => {
|
|
@@ -31,10 +14,8 @@ export function rememberSessionLabel(explicit, store, generate) {
|
|
|
31
14
|
store?.setItem(STORAGE_KEY, value);
|
|
32
15
|
}
|
|
33
16
|
catch {
|
|
34
|
-
/* same: never block connect on storage */
|
|
35
17
|
}
|
|
36
18
|
};
|
|
37
|
-
// `explicit` may be '' — resolveSessionLabel yields that for "none given" — and `??` would take it.
|
|
38
19
|
const asked = explicit !== undefined && explicit.length > 0 ? explicit : undefined;
|
|
39
20
|
const chosen = asked ?? read() ?? generate();
|
|
40
21
|
write(chosen);
|
package/dist/timers/clock.d.ts
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
|
+
export declare const FREEZE_WATCHDOG_MS = 120000;
|
|
1
2
|
export declare function isClockFrozen(): boolean;
|
|
2
3
|
export declare function freezeClock(): void;
|
|
3
|
-
/** Run all timers due within the next `ms` of virtual time, in order. */
|
|
4
4
|
export declare function advanceClock(ms: number): void;
|
|
5
|
-
/**
|
|
6
|
-
* Restore the real timers AND hand back everything the app queued while frozen.
|
|
7
|
-
*
|
|
8
|
-
* The queue used to be discarded (`tasks = []`). Restoring the native functions is only half the job:
|
|
9
|
-
* the callbacks the app scheduled during the freeze live in the virtual queue, and dropping them leaves
|
|
10
|
-
* the app quietly broken in a new way — a toast that never dismisses, a retry that never fires, a
|
|
11
|
-
* session-expiry check that never runs. `Date.now()` and future timers look healthy, so nothing points
|
|
12
|
-
* at the cause. That matters most on the path this is called from: an agent freezes the clock, the
|
|
13
|
-
* bridge dies, and the developer is left with an app that was never un-frozen deliberately.
|
|
14
|
-
*
|
|
15
|
-
* Pending work is re-scheduled onto REAL timers with its remaining virtual delay (a 5s toast frozen 2s
|
|
16
|
-
* in still has ~3s to go), and the ids the app is holding keep working — see the translation note.
|
|
17
|
-
*/
|
|
18
5
|
export declare function resetClock(): void;
|