@reticlehq/browser 2.1.0 → 2.2.1
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/NOTICE +5 -0
- package/dist/actions/actions.d.ts +1 -1
- package/dist/actions/actions.d.ts.map +1 -1
- package/dist/actions/actions.js +37 -19
- package/dist/actions/actions.js.map +1 -1
- package/dist/commands/commands.d.ts +2 -0
- package/dist/commands/commands.d.ts.map +1 -1
- package/dist/commands/commands.js +20 -6
- package/dist/commands/commands.js.map +1 -1
- package/dist/dom/a11y.d.ts +17 -6
- package/dist/dom/a11y.d.ts.map +1 -1
- package/dist/dom/a11y.js +68 -32
- package/dist/dom/a11y.js.map +1 -1
- package/dist/dom/auto-anchor.d.ts +10 -10
- package/dist/dom/auto-anchor.js +10 -10
- package/dist/dom/blind-spots.d.ts +14 -0
- package/dist/dom/blind-spots.d.ts.map +1 -0
- package/dist/dom/blind-spots.js +30 -0
- package/dist/dom/blind-spots.js.map +1 -0
- package/dist/dom/chart.d.ts +93 -0
- package/dist/dom/chart.d.ts.map +1 -0
- package/dist/dom/chart.js +119 -0
- package/dist/dom/chart.js.map +1 -0
- package/dist/dom/dom-ignore.d.ts.map +1 -1
- package/dist/dom/dom-ignore.js +7 -2
- package/dist/dom/dom-ignore.js.map +1 -1
- package/dist/dom/query.d.ts +17 -4
- package/dist/dom/query.d.ts.map +1 -1
- package/dist/dom/query.js +185 -30
- package/dist/dom/query.js.map +1 -1
- package/dist/dom/refs.d.ts +25 -2
- package/dist/dom/refs.d.ts.map +1 -1
- package/dist/dom/refs.js +78 -3
- package/dist/dom/refs.js.map +1 -1
- package/dist/dom/snapshot.d.ts +6 -0
- package/dist/dom/snapshot.d.ts.map +1 -1
- package/dist/dom/snapshot.js +6 -1
- package/dist/dom/snapshot.js.map +1 -1
- package/dist/dom/source.d.ts +40 -0
- package/dist/dom/source.d.ts.map +1 -0
- package/dist/dom/source.js +59 -0
- package/dist/dom/source.js.map +1 -0
- package/dist/dom/theme.js +2 -2
- package/dist/dom/theme.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/observers/blind-spots.d.ts +19 -0
- package/dist/observers/blind-spots.d.ts.map +1 -0
- package/dist/observers/blind-spots.js +89 -0
- package/dist/observers/blind-spots.js.map +1 -0
- package/dist/observers/console.d.ts.map +1 -1
- package/dist/observers/console.js +39 -6
- package/dist/observers/console.js.map +1 -1
- package/dist/observers/dom.d.ts.map +1 -1
- package/dist/observers/dom.js +68 -9
- package/dist/observers/dom.js.map +1 -1
- package/dist/observers/focus.d.ts +10 -0
- package/dist/observers/focus.d.ts.map +1 -0
- package/dist/observers/focus.js +49 -0
- package/dist/observers/focus.js.map +1 -0
- package/dist/observers/network-body.d.ts +19 -0
- package/dist/observers/network-body.d.ts.map +1 -0
- package/dist/observers/network-body.js +143 -0
- package/dist/observers/network-body.js.map +1 -0
- package/dist/observers/network-redact.d.ts +8 -0
- package/dist/observers/network-redact.d.ts.map +1 -0
- package/dist/observers/network-redact.js +66 -0
- package/dist/observers/network-redact.js.map +1 -0
- package/dist/observers/network.d.ts +13 -6
- package/dist/observers/network.d.ts.map +1 -1
- package/dist/observers/network.js +288 -162
- package/dist/observers/network.js.map +1 -1
- package/dist/observers/route.d.ts.map +1 -1
- package/dist/observers/route.js +15 -9
- package/dist/observers/route.js.map +1 -1
- package/dist/observers/scroll.d.ts.map +1 -1
- package/dist/observers/scroll.js +35 -8
- package/dist/observers/scroll.js.map +1 -1
- package/dist/observers/state.d.ts +20 -0
- package/dist/observers/state.d.ts.map +1 -0
- package/dist/observers/state.js +87 -0
- package/dist/observers/state.js.map +1 -0
- package/dist/observers/storage.d.ts +9 -0
- package/dist/observers/storage.d.ts.map +1 -1
- package/dist/observers/storage.js +105 -3
- package/dist/observers/storage.js.map +1 -1
- package/dist/observers/types.d.ts +15 -0
- package/dist/observers/types.d.ts.map +1 -1
- package/dist/observers/types.js +29 -1
- package/dist/observers/types.js.map +1 -1
- package/dist/patching/capture-method.d.ts +27 -0
- package/dist/patching/capture-method.d.ts.map +1 -0
- package/dist/patching/capture-method.js +37 -0
- package/dist/patching/capture-method.js.map +1 -0
- package/dist/presenter/presenter-config.d.ts +3 -3
- package/dist/presenter/presenter-config.d.ts.map +1 -1
- package/dist/presenter/presenter-config.js +3 -3
- package/dist/presenter/presenter-config.js.map +1 -1
- package/dist/presenter/presenter-controls.d.ts +1 -1
- package/dist/presenter/presenter-controls.d.ts.map +1 -1
- package/dist/presenter/presenter-controls.js +3 -3
- package/dist/presenter/presenter-controls.js.map +1 -1
- package/dist/presenter/presenter-glow.d.ts +1 -1
- package/dist/presenter/presenter-glow.js +1 -1
- package/dist/presenter/presenter-styles.d.ts +1 -1
- package/dist/presenter/presenter-styles.d.ts.map +1 -1
- package/dist/presenter/presenter-styles.js +12 -3
- package/dist/presenter/presenter-styles.js.map +1 -1
- package/dist/presenter/presenter.d.ts +4 -4
- package/dist/presenter/presenter.d.ts.map +1 -1
- package/dist/presenter/presenter.js +5 -5
- package/dist/presenter/presenter.js.map +1 -1
- package/dist/recorder/recorder.d.ts +8 -8
- package/dist/recorder/recorder.d.ts.map +1 -1
- package/dist/recorder/recorder.js +9 -9
- package/dist/recorder/recorder.js.map +1 -1
- package/dist/registry/capabilities.d.ts +2 -2
- package/dist/registry/capabilities.d.ts.map +1 -1
- package/dist/registry/capabilities.js +1 -1
- package/dist/registry/capabilities.js.map +1 -1
- package/dist/registry/domains.d.ts +1 -1
- package/dist/registry/domains.js +1 -1
- package/dist/registry/emitter.d.ts +2 -2
- package/dist/registry/emitter.js +2 -2
- package/dist/registry/store-adapters.d.ts +128 -0
- package/dist/registry/store-adapters.d.ts.map +1 -0
- package/dist/registry/store-adapters.js +135 -0
- package/dist/registry/store-adapters.js.map +1 -0
- package/dist/registry/stores.d.ts +38 -2
- package/dist/registry/stores.d.ts.map +1 -1
- package/dist/registry/stores.js +110 -8
- package/dist/registry/stores.js.map +1 -1
- package/dist/reticle.d.ts +22 -3
- package/dist/reticle.d.ts.map +1 -1
- package/dist/reticle.js +81 -14
- package/dist/reticle.js.map +1 -1
- package/dist/review/annotator.js +1 -1
- package/dist/review/annotator.js.map +1 -1
- package/dist/review/mark-anchor.d.ts.map +1 -1
- package/dist/review/mark-anchor.js +1 -21
- package/dist/review/mark-anchor.js.map +1 -1
- package/dist/security/serialization.d.ts +29 -3
- package/dist/security/serialization.d.ts.map +1 -1
- package/dist/security/serialization.js +169 -28
- package/dist/security/serialization.js.map +1 -1
- package/dist/timers/clock.d.ts +13 -0
- package/dist/timers/clock.d.ts.map +1 -1
- package/dist/timers/clock.js +76 -6
- package/dist/timers/clock.js.map +1 -1
- package/dist/timers/native-console.d.ts +2 -0
- package/dist/timers/native-console.d.ts.map +1 -0
- package/dist/timers/native-console.js +10 -0
- package/dist/timers/native-console.js.map +1 -0
- package/dist/transport/transport.d.ts +1 -1
- package/dist/transport/transport.d.ts.map +1 -1
- package/dist/transport/transport.js +43 -4
- package/dist/transport/transport.js.map +1 -1
- package/package.json +7 -3
package/dist/observers/route.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EventType } from '@reticlehq/core';
|
|
2
|
+
import { captureMethod } from '../patching/capture-method.js';
|
|
2
3
|
function snapshotLocation() {
|
|
3
4
|
return {
|
|
4
5
|
pathname: location.pathname,
|
|
@@ -11,13 +12,11 @@ function snapshotLocation() {
|
|
|
11
12
|
export function installRoute(emit) {
|
|
12
13
|
// Keep the true originals for teardown identity; bound copies are used for invocation
|
|
13
14
|
// (History methods throw "Illegal invocation" if called with the wrong `this`).
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const origReplace = history.replaceState;
|
|
17
|
-
/* eslint-enable @typescript-eslint/unbound-method */
|
|
15
|
+
const origPush = captureMethod(history, 'pushState');
|
|
16
|
+
const origReplace = captureMethod(history, 'replaceState');
|
|
18
17
|
const callPush = origPush.bind(history);
|
|
19
18
|
const callReplace = origReplace.bind(history);
|
|
20
|
-
// The `from` baseline for the NEXT popstate/hashchange. Updated in fire
|
|
19
|
+
// The `from` baseline for the NEXT popstate/hashchange. Updated in fire on every emitted change
|
|
21
20
|
// — including pushState/replaceState — so a later Back nav isn't compared against a stale href
|
|
22
21
|
// (which made `to === from` trip and silently drop the back navigation).
|
|
23
22
|
let lastHref = location.href;
|
|
@@ -34,24 +33,31 @@ export function installRoute(emit) {
|
|
|
34
33
|
hash: to.hash,
|
|
35
34
|
});
|
|
36
35
|
};
|
|
37
|
-
|
|
36
|
+
const patchedPush = (data, unused, url) => {
|
|
38
37
|
const from = location.href;
|
|
39
38
|
callPush(data, unused, url ?? null);
|
|
40
39
|
fire(from);
|
|
41
40
|
};
|
|
42
|
-
|
|
41
|
+
const patchedReplace = (data, unused, url) => {
|
|
43
42
|
const from = location.href;
|
|
44
43
|
callReplace(data, unused, url ?? null);
|
|
45
44
|
fire(from);
|
|
46
45
|
};
|
|
46
|
+
history.pushState = patchedPush;
|
|
47
|
+
history.replaceState = patchedReplace;
|
|
47
48
|
const onNav = () => {
|
|
48
49
|
fire(lastHref);
|
|
49
50
|
};
|
|
50
51
|
window.addEventListener('popstate', onNav);
|
|
51
52
|
window.addEventListener('hashchange', onNav);
|
|
52
53
|
return () => {
|
|
53
|
-
|
|
54
|
-
history.
|
|
54
|
+
// Restore ONLY if the slot still holds our wrapper. If a router/analytics SDK wrapped
|
|
55
|
+
// history.pushState AFTER connect(), unconditionally writing origPush back would silently
|
|
56
|
+
// uninstall THEIR instrumentation too — the SDK harming the app it only meant to observe.
|
|
57
|
+
if (history.pushState === patchedPush)
|
|
58
|
+
history.pushState = origPush;
|
|
59
|
+
if (history.replaceState === patchedReplace)
|
|
60
|
+
history.replaceState = origReplace;
|
|
55
61
|
window.removeEventListener('popstate', onNav);
|
|
56
62
|
window.removeEventListener('hashchange', onNav);
|
|
57
63
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/observers/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/observers/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,SAAS,gBAAgB;IACvB,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,sFAAsF;IACtF,gFAAgF;IAChF,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE9C,gGAAgG;IAChG,+FAA+F;IAC/F,yEAAyE;IACzE,IAAI,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;IAE7B,MAAM,IAAI,GAAG,CAAC,IAAY,EAAQ,EAAE;QAClC,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;QAC9B,IAAI,EAAE,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO;QAC7B,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE;YAC3B,IAAI;YACJ,EAAE,EAAE,EAAE,CAAC,IAAI;YACX,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,IAAI,EAAE,EAAE,CAAC,IAAI;SACd,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,IAAa,EAAE,MAAc,EAAE,GAAyB,EAAQ,EAAE;QACrF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,CAAC,CAAC;IACF,MAAM,cAAc,GAAG,CAAC,IAAa,EAAE,MAAc,EAAE,GAAyB,EAAQ,EAAE;QACxF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,CAAC,CAAC;IACF,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC;IAChC,OAAO,CAAC,YAAY,GAAG,cAAc,CAAC;IAEtC,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjB,CAAC,CAAC;IACF,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAE7C,OAAO,GAAG,EAAE;QACV,sFAAsF;QACtF,0FAA0F;QAC1F,0FAA0F;QAC1F,IAAI,OAAO,CAAC,SAAS,KAAK,WAAW;YAAE,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC;QACpE,IAAI,OAAO,CAAC,YAAY,KAAK,cAAc;YAAE,OAAO,CAAC,YAAY,GAAG,WAAW,CAAC;QAChF,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll.d.ts","sourceRoot":"","sources":["../../src/observers/scroll.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scroll.d.ts","sourceRoot":"","sources":["../../src/observers/scroll.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKjD,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAsElD"}
|
package/dist/observers/scroll.js
CHANGED
|
@@ -1,26 +1,44 @@
|
|
|
1
|
-
import { EventType } from '@reticlehq/core';
|
|
1
|
+
import { EventType, ScrollDirection } from '@reticlehq/core';
|
|
2
2
|
import { refs } from '../dom/refs.js';
|
|
3
|
+
import { nativeSetTimeout, nativeClearTimeout } from '../timers/native-timers.js';
|
|
3
4
|
const THROTTLE_MS = 100;
|
|
4
5
|
const REVEAL_SELECTOR = '[data-reticle-reveal], [data-reveal], section';
|
|
5
6
|
/** Observe scroll position + reveal-on-scroll for modern scroll-reactive UIs. */
|
|
6
7
|
export function installScroll(emit) {
|
|
7
8
|
let lastEmit = 0;
|
|
8
9
|
let lastY = 0;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return;
|
|
13
|
-
lastEmit = now;
|
|
10
|
+
let trailingTimer;
|
|
11
|
+
const emitPosition = () => {
|
|
12
|
+
lastEmit = performance.now();
|
|
14
13
|
const y = window.scrollY;
|
|
15
14
|
const max = Math.max(1, document.documentElement.scrollHeight - window.innerHeight);
|
|
16
15
|
emit(EventType.SCROLL_POSITION, {
|
|
17
16
|
x: window.scrollX,
|
|
18
17
|
y,
|
|
19
18
|
percent: Math.round((y / max) * 100),
|
|
20
|
-
direction: y >= lastY ?
|
|
19
|
+
direction: y >= lastY ? ScrollDirection.DOWN : ScrollDirection.UP,
|
|
21
20
|
});
|
|
22
21
|
lastY = y;
|
|
23
22
|
};
|
|
23
|
+
const onScroll = () => {
|
|
24
|
+
const elapsed = performance.now() - lastEmit;
|
|
25
|
+
if (elapsed >= THROTTLE_MS) {
|
|
26
|
+
if (trailingTimer !== undefined) {
|
|
27
|
+
nativeClearTimeout(trailingTimer);
|
|
28
|
+
trailingTimer = undefined;
|
|
29
|
+
}
|
|
30
|
+
emitPosition();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Leading-edge only dropped the FINAL, resting position — an agent asserting "scrolled to the
|
|
34
|
+
// footer" saw the last mid-scroll sample, not where the page settled. Schedule a trailing emit.
|
|
35
|
+
if (trailingTimer === undefined) {
|
|
36
|
+
trailingTimer = nativeSetTimeout(() => {
|
|
37
|
+
trailingTimer = undefined;
|
|
38
|
+
emitPosition();
|
|
39
|
+
}, THROTTLE_MS - elapsed);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
24
42
|
window.addEventListener('scroll', onScroll, { passive: true });
|
|
25
43
|
let io;
|
|
26
44
|
if (typeof IntersectionObserver === 'function') {
|
|
@@ -31,11 +49,20 @@ export function installScroll(emit) {
|
|
|
31
49
|
}
|
|
32
50
|
}
|
|
33
51
|
}, { threshold: 0.25 });
|
|
52
|
+
const observer = io;
|
|
53
|
+
// Observe reveal targets present at install. Reveal-on-scroll sections are in the initial DOM by
|
|
54
|
+
// design (they exist hidden and animate in on scroll), so this covers the real case. Watching the
|
|
55
|
+
// whole body subtree for LATE-mounted reveal targets was tried and reverted: a second body-wide
|
|
56
|
+
// MutationObserver on EVERY app — running querySelectorAll(section,...) per mutation batch — is
|
|
57
|
+
// disproportionate overhead for a niche signal. Dynamically-mounted reveal targets are simply not
|
|
58
|
+
// tracked (an honest blind spot, consistent with the rest of the SDK).
|
|
34
59
|
for (const el of document.querySelectorAll(REVEAL_SELECTOR))
|
|
35
|
-
|
|
60
|
+
observer.observe(el);
|
|
36
61
|
}
|
|
37
62
|
return () => {
|
|
38
63
|
window.removeEventListener('scroll', onScroll);
|
|
64
|
+
if (trailingTimer !== undefined)
|
|
65
|
+
nativeClearTimeout(trailingTimer);
|
|
39
66
|
io?.disconnect();
|
|
40
67
|
};
|
|
41
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll.js","sourceRoot":"","sources":["../../src/observers/scroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"scroll.js","sourceRoot":"","sources":["../../src/observers/scroll.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Emit, Teardown } from './types.js';
|
|
2
|
+
interface StateChange {
|
|
3
|
+
path: string;
|
|
4
|
+
old: unknown;
|
|
5
|
+
new: unknown;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Shallow top-level diff of two store states — the keys whose value changed. Immutable updates
|
|
9
|
+
* (Zustand/Redux) replace the changed key's reference, so `Object.is` catches them. Pure; deep-nested
|
|
10
|
+
* diffing behind an unchanged top-level reference is a v2 concern.
|
|
11
|
+
*/
|
|
12
|
+
export declare function diffState(prev: unknown, next: unknown): StateChange[];
|
|
13
|
+
/**
|
|
14
|
+
* Subscribe to every registered store that exposed a subscribe method, emitting a STATE_CHANGE per
|
|
15
|
+
* changed top-level path with {name, path, old, new} — automatic diffs, not pull-only readings. Stores
|
|
16
|
+
* without a subscribe fall back to the pull path (reticle_state). Fully reversible.
|
|
17
|
+
*/
|
|
18
|
+
export declare function installStoreState(emit: Emit): Teardown;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/observers/state.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd;AAMD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE,CAUrE;AAeD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA8CtD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { EventType, REDACTED_VALUE } from '@reticlehq/core';
|
|
2
|
+
import { subscribableStores, onStoreRegistered, } from '../registry/stores.js';
|
|
3
|
+
import { isSensitiveKey, sanitizeForTransport } from '../security/serialization.js';
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Shallow top-level diff of two store states — the keys whose value changed. Immutable updates
|
|
9
|
+
* (Zustand/Redux) replace the changed key's reference, so `Object.is` catches them. Pure; deep-nested
|
|
10
|
+
* diffing behind an unchanged top-level reference is a v2 concern.
|
|
11
|
+
*/
|
|
12
|
+
export function diffState(prev, next) {
|
|
13
|
+
if (!isRecord(prev) || !isRecord(next)) {
|
|
14
|
+
return Object.is(prev, next) ? [] : [{ path: '', old: prev, new: next }];
|
|
15
|
+
}
|
|
16
|
+
const changes = [];
|
|
17
|
+
for (const key of new Set([...Object.keys(prev), ...Object.keys(next)])) {
|
|
18
|
+
if (!Object.is(prev[key], next[key]))
|
|
19
|
+
changes.push({ path: key, old: prev[key], new: next[key] });
|
|
20
|
+
}
|
|
21
|
+
return changes;
|
|
22
|
+
}
|
|
23
|
+
/** Redact a changed value when its path is credential-bearing, else cap it for transport. */
|
|
24
|
+
function project(path, value) {
|
|
25
|
+
return isSensitiveKey(path) ? REDACTED_VALUE : sanitizeForTransport(value);
|
|
26
|
+
}
|
|
27
|
+
function safeRead(getter) {
|
|
28
|
+
try {
|
|
29
|
+
return getter();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Subscribe to every registered store that exposed a subscribe method, emitting a STATE_CHANGE per
|
|
37
|
+
* changed top-level path with {name, path, old, new} — automatic diffs, not pull-only readings. Stores
|
|
38
|
+
* without a subscribe fall back to the pull path (reticle_state). Fully reversible.
|
|
39
|
+
*/
|
|
40
|
+
export function installStoreState(emit) {
|
|
41
|
+
const active = new Map();
|
|
42
|
+
const watch = ([name, getter, subscribe]) => {
|
|
43
|
+
// A re-registration under the same name is the HMR cycle: the store INSTANCE is replaced (new
|
|
44
|
+
// getter + new subscribe). Skipping it (the old `seen` guard) left the subscription bound to the
|
|
45
|
+
// DEAD getter forever and the live store invisible until a full reload. Rebind: drop the previous
|
|
46
|
+
// subscription for this name, then subscribe the new tuple. Guard the old unsubscribe — if it throws
|
|
47
|
+
// (a misbehaving store), the rebind must still proceed, or the live store stays invisible.
|
|
48
|
+
try {
|
|
49
|
+
active.get(name)?.();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
/* a faulty unsubscribe must not block re-binding to the new instance */
|
|
53
|
+
}
|
|
54
|
+
let last = safeRead(getter);
|
|
55
|
+
active.set(name, subscribe(() => {
|
|
56
|
+
const next = safeRead(getter);
|
|
57
|
+
for (const change of diffState(last, next)) {
|
|
58
|
+
emit(EventType.STATE_CHANGE, {
|
|
59
|
+
name,
|
|
60
|
+
path: change.path,
|
|
61
|
+
value: project(change.path, change.new),
|
|
62
|
+
old: project(change.path, change.old),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
last = next;
|
|
66
|
+
}));
|
|
67
|
+
};
|
|
68
|
+
// Stores already registered...
|
|
69
|
+
for (const entry of subscribableStores())
|
|
70
|
+
watch(entry);
|
|
71
|
+
//...and any registered LATER. The SDK installs observers during connect, but apps call
|
|
72
|
+
// registerStore after that, so without this the common case subscribes to nothing.
|
|
73
|
+
const offRegistered = onStoreRegistered(watch);
|
|
74
|
+
return () => {
|
|
75
|
+
offRegistered();
|
|
76
|
+
for (const unsubscribe of active.values()) {
|
|
77
|
+
try {
|
|
78
|
+
unsubscribe();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
/* one faulty store unsubscribe must not abort tearing the rest down */
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
active.clear();
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/observers/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Emit, type Teardown } from './types.js';
|
|
1
2
|
/** The three readable client-side storage areas. httpOnly cookies are invisible to JS by design. */
|
|
2
3
|
export interface StorageSnapshot {
|
|
3
4
|
local: Record<string, string>;
|
|
@@ -11,4 +12,12 @@ export interface StorageSnapshot {
|
|
|
11
12
|
* for all three. Sensitive keys are redacted; httpOnly cookies are unreadable by design (documented).
|
|
12
13
|
*/
|
|
13
14
|
export declare function readStorage(area?: string): StorageSnapshot | Record<string, string>;
|
|
15
|
+
/**
|
|
16
|
+
* Observe storage WRITES (not just reads): patch Storage.setItem/removeItem so a token persisted, a
|
|
17
|
+
* cart updated, or a session cleared emits a STORAGE_CHANGE {area, key, old?, new?} diff — the "before"
|
|
18
|
+
* the pull path can never see. localStorage and sessionStorage share one prototype, so `this` inside the
|
|
19
|
+
* patch identifies the area. The native originals are read off the prototype descriptor (not a bare
|
|
20
|
+
* method access) and re-dispatched via `.call(this)`. Fully reversible; values redacted like the reads.
|
|
21
|
+
*/
|
|
22
|
+
export declare function installStorage(emit: Emit): Teardown;
|
|
14
23
|
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/observers/storage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/observers/storage.ts"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnF,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAmDD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASnF;AAYD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAwFnD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { REDACTED_VALUE } from '@reticlehq/core';
|
|
1
|
+
import { EventType, REDACTED_VALUE, StorageArea } from '@reticlehq/core';
|
|
2
2
|
import { isSensitiveKey } from '../security/serialization.js';
|
|
3
|
+
import { observeSafely, observeValue } from './types.js';
|
|
3
4
|
/** Accessing localStorage/sessionStorage throws in a sandboxed iframe / disabled-storage context. */
|
|
4
5
|
function safeArea(get) {
|
|
5
6
|
try {
|
|
@@ -60,9 +61,9 @@ function readCookies() {
|
|
|
60
61
|
* for all three. Sensitive keys are redacted; httpOnly cookies are unreadable by design (documented).
|
|
61
62
|
*/
|
|
62
63
|
export function readStorage(area) {
|
|
63
|
-
if (area ===
|
|
64
|
+
if (area === StorageArea.LOCAL)
|
|
64
65
|
return readArea(safeArea(() => window.localStorage));
|
|
65
|
-
if (area ===
|
|
66
|
+
if (area === StorageArea.SESSION)
|
|
66
67
|
return readArea(safeArea(() => window.sessionStorage));
|
|
67
68
|
if (area === 'cookies')
|
|
68
69
|
return readCookies();
|
|
@@ -72,4 +73,105 @@ export function readStorage(area) {
|
|
|
72
73
|
cookies: readCookies(),
|
|
73
74
|
};
|
|
74
75
|
}
|
|
76
|
+
/** Redact a value when its key is credential-bearing — the same rule the pull path applies. */
|
|
77
|
+
function redactFor(key, value) {
|
|
78
|
+
if (value === null)
|
|
79
|
+
return undefined;
|
|
80
|
+
return isSensitiveKey(key) ? REDACTED_VALUE : value;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Observe storage WRITES (not just reads): patch Storage.setItem/removeItem so a token persisted, a
|
|
84
|
+
* cart updated, or a session cleared emits a STORAGE_CHANGE {area, key, old?, new?} diff — the "before"
|
|
85
|
+
* the pull path can never see. localStorage and sessionStorage share one prototype, so `this` inside the
|
|
86
|
+
* patch identifies the area. The native originals are read off the prototype descriptor (not a bare
|
|
87
|
+
* method access) and re-dispatched via `.call(this)`. Fully reversible; values redacted like the reads.
|
|
88
|
+
*/
|
|
89
|
+
export function installStorage(emit) {
|
|
90
|
+
if (typeof Storage === 'undefined')
|
|
91
|
+
return () => undefined;
|
|
92
|
+
const proto = Storage.prototype;
|
|
93
|
+
const origSet = Object.getOwnPropertyDescriptor(proto, 'setItem')?.value;
|
|
94
|
+
const origRemove = Object.getOwnPropertyDescriptor(proto, 'removeItem')?.value;
|
|
95
|
+
const origClear = Object.getOwnPropertyDescriptor(proto, 'clear')?.value;
|
|
96
|
+
if (origSet === undefined || origRemove === undefined || origClear === undefined) {
|
|
97
|
+
return () => undefined;
|
|
98
|
+
}
|
|
99
|
+
// Resolve sessionStorage at CALL time, not once at install. If the property threw during install
|
|
100
|
+
// (a transient sandbox state) the captured reference would be null and every session write would be
|
|
101
|
+
// misreported as `local` for the life of the page. Reads are cheap and safeArea swallows throws.
|
|
102
|
+
const areaOf = (storage) => storage === safeArea(() => window.sessionStorage) ? StorageArea.SESSION : StorageArea.LOCAL;
|
|
103
|
+
const readOld = (storage, key) => {
|
|
104
|
+
try {
|
|
105
|
+
return storage.getItem(key);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const patchedSetItem = function (key, value) {
|
|
112
|
+
// The app's write happens FIRST and outside the guard — it must succeed or fail on its own terms.
|
|
113
|
+
const old = observeValue(() => readOld(this, key)) ?? null;
|
|
114
|
+
origSet.call(this, key, value);
|
|
115
|
+
observeSafely(() => {
|
|
116
|
+
emit(EventType.STORAGE_CHANGE, {
|
|
117
|
+
area: areaOf(this),
|
|
118
|
+
key,
|
|
119
|
+
...(redactFor(key, old) === undefined ? {} : { old: redactFor(key, old) }),
|
|
120
|
+
new: redactFor(key, value) ?? REDACTED_VALUE,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
proto.setItem = patchedSetItem;
|
|
125
|
+
const patchedRemoveItem = function (key) {
|
|
126
|
+
const old = observeValue(() => readOld(this, key)) ?? null;
|
|
127
|
+
origRemove.call(this, key);
|
|
128
|
+
observeSafely(() => {
|
|
129
|
+
// No `new` field ⇒ the key was removed.
|
|
130
|
+
emit(EventType.STORAGE_CHANGE, {
|
|
131
|
+
area: areaOf(this),
|
|
132
|
+
key,
|
|
133
|
+
...(redactFor(key, old) === undefined ? {} : { old: redactFor(key, old) }),
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
proto.removeItem = patchedRemoveItem;
|
|
138
|
+
const patchedClear = function () {
|
|
139
|
+
// localStorage.clear() is the most common logout — but it emitted NOTHING, so "logout cleared the
|
|
140
|
+
// session" was unverifiable from the write path. Snapshot the keys BEFORE clearing (the values are
|
|
141
|
+
// gone after), then report each as a removal, reusing the {area, key, old} shape removeItem emits.
|
|
142
|
+
const area = areaOf(this);
|
|
143
|
+
const removed = [];
|
|
144
|
+
try {
|
|
145
|
+
for (let i = 0; i < this.length; i += 1) {
|
|
146
|
+
const key = this.key(i);
|
|
147
|
+
if (key !== null)
|
|
148
|
+
removed.push({ key, old: readOld(this, key) });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Enumerating keys can throw in a locked-down context; clear anyway, just without the diff.
|
|
153
|
+
}
|
|
154
|
+
origClear.call(this);
|
|
155
|
+
for (const { key, old } of removed) {
|
|
156
|
+
observeSafely(() => {
|
|
157
|
+
emit(EventType.STORAGE_CHANGE, {
|
|
158
|
+
area,
|
|
159
|
+
key,
|
|
160
|
+
...(redactFor(key, old) === undefined ? {} : { old: redactFor(key, old) }),
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
proto.clear = patchedClear;
|
|
166
|
+
return () => {
|
|
167
|
+
// Restore only if the slot still holds our wrapper — never uninstall a wrapper the app layered
|
|
168
|
+
// on top of ours after connect().
|
|
169
|
+
if (proto.setItem === patchedSetItem)
|
|
170
|
+
proto.setItem = origSet;
|
|
171
|
+
if (proto.removeItem === patchedRemoveItem)
|
|
172
|
+
proto.removeItem = origRemove;
|
|
173
|
+
if (proto.clear === patchedClear)
|
|
174
|
+
proto.clear = origClear;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
75
177
|
//# sourceMappingURL=storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/observers/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/observers/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,4 +3,19 @@ import type { EventType } from '@reticlehq/core';
|
|
|
3
3
|
export type Emit = (type: EventType, data: Record<string, unknown>, ref?: string) => void;
|
|
4
4
|
/** Every observer returns a teardown that fully restores any patched globals. */
|
|
5
5
|
export type Teardown = () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Run an observation so it can never escape into the app's call stack.
|
|
8
|
+
*
|
|
9
|
+
* Every monkey-patch calls its observation INSIDE the function it replaced, so a throw does not surface
|
|
10
|
+
* as an SDK error — it propagates out of `localStorage.setItem` after the write already succeeded, out
|
|
11
|
+
* of `history.pushState` (crashing a router's navigate), or out of `console.log` before the message
|
|
12
|
+
* reaches the console. Guarding the transport hop alone is not enough: the payload is BUILT here too
|
|
13
|
+
* (reading the old value, resolving the area, redacting), and any of that can throw on a hostile or
|
|
14
|
+
* exotic object.
|
|
15
|
+
*
|
|
16
|
+
* A dev-only observability SDK must never be able to break the app it is observing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function observeSafely(observation: () => void): void;
|
|
19
|
+
/** Like observeSafely, but for reading a value the observation needs; undefined if the read throws. */
|
|
20
|
+
export declare function observeValue<T>(read: () => T): T | undefined;
|
|
6
21
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/observers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,yFAAyF;AACzF,MAAM,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAE1F,iFAAiF;AACjF,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/observers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,yFAAyF;AACzF,MAAM,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAE1F,iFAAiF;AACjF,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,IAAI,GAAG,IAAI,CAM3D;AAED,uGAAuG;AACvG,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAM5D"}
|
package/dist/observers/types.js
CHANGED
|
@@ -1,2 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Run an observation so it can never escape into the app's call stack.
|
|
3
|
+
*
|
|
4
|
+
* Every monkey-patch calls its observation INSIDE the function it replaced, so a throw does not surface
|
|
5
|
+
* as an SDK error — it propagates out of `localStorage.setItem` after the write already succeeded, out
|
|
6
|
+
* of `history.pushState` (crashing a router's navigate), or out of `console.log` before the message
|
|
7
|
+
* reaches the console. Guarding the transport hop alone is not enough: the payload is BUILT here too
|
|
8
|
+
* (reading the old value, resolving the area, redacting), and any of that can throw on a hostile or
|
|
9
|
+
* exotic object.
|
|
10
|
+
*
|
|
11
|
+
* A dev-only observability SDK must never be able to break the app it is observing.
|
|
12
|
+
*/
|
|
13
|
+
export function observeSafely(observation) {
|
|
14
|
+
try {
|
|
15
|
+
observation();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
/* observation is best-effort; the host app's control flow is not */
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Like observeSafely, but for reading a value the observation needs; undefined if the read throws. */
|
|
22
|
+
export function observeValue(read) {
|
|
23
|
+
try {
|
|
24
|
+
return read();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
2
30
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/observers/types.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/observers/types.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,WAAuB;IACnD,IAAI,CAAC;QACH,WAAW,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;IACtE,CAAC;AACH,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,YAAY,CAAI,IAAa;IAC3C,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture a method off an object so it can be restored — or re-invoked via `.call` — later.
|
|
3
|
+
*
|
|
4
|
+
* Monkeypatching is unavoidable in this SDK: observing history, console, fetch and XHR means
|
|
5
|
+
* replacing a method and putting the original back on teardown. Putting it back requires holding the
|
|
6
|
+
* UNBOUND original, because identity is what teardown compares — a bound copy is a different function
|
|
7
|
+
* and would leave the patch installed forever.
|
|
8
|
+
*
|
|
9
|
+
* `@typescript-eslint/unbound-method` exists to catch the common mistake this pattern deliberately
|
|
10
|
+
* makes, so every such site used to carry an eslint-disable. Disabling a rule seven times to express
|
|
11
|
+
* one intention is worse than naming the intention once: those disables also suppressed the rule for
|
|
12
|
+
* any OTHER unbound access on the same lines, which is exactly what the rule is for.
|
|
13
|
+
*
|
|
14
|
+
* The generic index access here is not something the rule flags, so callers stay clean and the
|
|
15
|
+
* "I meant to do this" is stated in one place instead of seven.
|
|
16
|
+
*/
|
|
17
|
+
export declare function captureMethod<T, K extends keyof T>(target: T, key: K): T[K];
|
|
18
|
+
/**
|
|
19
|
+
* The `value` setter defined on a prototype, for inputs whose value must be set the way the browser
|
|
20
|
+
* does it — React installs its own descriptor, and assigning `el.value` directly skips the tracker it
|
|
21
|
+
* relies on to notice a change.
|
|
22
|
+
*
|
|
23
|
+
* Same reason as `captureMethod` for existing separately from its call site: a property descriptor's
|
|
24
|
+
* `set` is an unbound function, and naming that intention once beats disabling the rule at each use.
|
|
25
|
+
*/
|
|
26
|
+
export declare function captureValueSetter(proto: object): ((this: HTMLElement, value: string) => void) | undefined;
|
|
27
|
+
//# sourceMappingURL=capture-method.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-method.d.ts","sourceRoot":"","sources":["../../src/patching/capture-method.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAE3E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,GACZ,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAO1D"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture a method off an object so it can be restored — or re-invoked via `.call` — later.
|
|
3
|
+
*
|
|
4
|
+
* Monkeypatching is unavoidable in this SDK: observing history, console, fetch and XHR means
|
|
5
|
+
* replacing a method and putting the original back on teardown. Putting it back requires holding the
|
|
6
|
+
* UNBOUND original, because identity is what teardown compares — a bound copy is a different function
|
|
7
|
+
* and would leave the patch installed forever.
|
|
8
|
+
*
|
|
9
|
+
* `@typescript-eslint/unbound-method` exists to catch the common mistake this pattern deliberately
|
|
10
|
+
* makes, so every such site used to carry an eslint-disable. Disabling a rule seven times to express
|
|
11
|
+
* one intention is worse than naming the intention once: those disables also suppressed the rule for
|
|
12
|
+
* any OTHER unbound access on the same lines, which is exactly what the rule is for.
|
|
13
|
+
*
|
|
14
|
+
* The generic index access here is not something the rule flags, so callers stay clean and the
|
|
15
|
+
* "I meant to do this" is stated in one place instead of seven.
|
|
16
|
+
*/
|
|
17
|
+
export function captureMethod(target, key) {
|
|
18
|
+
return target[key];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The `value` setter defined on a prototype, for inputs whose value must be set the way the browser
|
|
22
|
+
* does it — React installs its own descriptor, and assigning `el.value` directly skips the tracker it
|
|
23
|
+
* relies on to notice a change.
|
|
24
|
+
*
|
|
25
|
+
* Same reason as `captureMethod` for existing separately from its call site: a property descriptor's
|
|
26
|
+
* `set` is an unbound function, and naming that intention once beats disabling the rule at each use.
|
|
27
|
+
*/
|
|
28
|
+
export function captureValueSetter(proto) {
|
|
29
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, 'value');
|
|
30
|
+
if (descriptor === undefined)
|
|
31
|
+
return undefined;
|
|
32
|
+
// Read through the same generic index access `captureMethod` uses: reaching for `.set` directly is
|
|
33
|
+
// what the rule flags, and it is right to in general — this is the one place that means it.
|
|
34
|
+
const setter = captureMethod(descriptor, 'set');
|
|
35
|
+
return setter;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=capture-method.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-method.js","sourceRoot":"","sources":["../../src/patching/capture-method.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAuB,MAAS,EAAE,GAAM;IACnE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAa;IAEb,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnE,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,mGAAmG;IACnG,4FAA4F;IAC5F,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAChD,OAAO,MAAkE,CAAC;AAC5E,CAAC"}
|
|
@@ -50,7 +50,7 @@ export interface PresenterOptions {
|
|
|
50
50
|
}
|
|
51
51
|
export declare const DEFAULT_PACE = 450;
|
|
52
52
|
/**
|
|
53
|
-
* Glow state machine phases (exposed via glowPhase
|
|
53
|
+
* Glow state machine phases (exposed via glowPhase for tests). A burst of activity flips the
|
|
54
54
|
* border IN once on the first activity, holds steady (the slow reticle-pulse breathing keeps running
|
|
55
55
|
* uninterrupted — no per-action restart/strobe), then fades OUT once after a quiet window.
|
|
56
56
|
*/
|
|
@@ -71,11 +71,11 @@ export declare const HEARTBEAT_MS = 1000;
|
|
|
71
71
|
*/
|
|
72
72
|
export declare const IDLE_NOTICE_MS = 4000;
|
|
73
73
|
/** Default session-idle-end: after this much quiet the session auto-ends (glow off, panel persists
|
|
74
|
-
*
|
|
74
|
+
* for analysis). Agent-tweakable via reticle_session { idleEndMs } for the app's needs. */
|
|
75
75
|
export declare const IDLE_END_MS = 300000;
|
|
76
76
|
/** Floor for a tweaked idle-end so the agent can't set a uselessly tiny window. */
|
|
77
77
|
export declare const IDLE_END_MIN_MS = 5000;
|
|
78
|
-
/** Must match the glow CSS opacity transition
|
|
78
|
+
/** Must match the glow CSS opacity transition.25s) so phase reaches idle after the fade paints. */
|
|
79
79
|
export declare const GLOW_FADE_MS = 250;
|
|
80
80
|
export declare const GLOW_ON = "1";
|
|
81
81
|
export declare const GLOW_OFF = "0";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presenter-config.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D;;;;GAIG;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAgD,CAAC;AACxE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AACtE,eAAO,MAAM,mBAAmB,EAAE,UAA+B,CAAC;AAClE,eAAO,MAAM,SAAS,cAAc,CAAC;AACrC,eAAO,MAAM,OAAO,MAAM,CAAC;AAC3B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wGAAwG;IACxG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEnE,0CAA0C;AAC1C,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,2FAA2F;AAC3F,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC;;;;GAIG;AACH,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC;
|
|
1
|
+
{"version":3,"file":"presenter-config.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D;;;;GAIG;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAgD,CAAC;AACxE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AACtE,eAAO,MAAM,mBAAmB,EAAE,UAA+B,CAAC;AAClE,eAAO,MAAM,SAAS,cAAc,CAAC;AACrC,eAAO,MAAM,OAAO,MAAM,CAAC;AAC3B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wGAAwG;IACxG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEnE,0CAA0C;AAC1C,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,2FAA2F;AAC3F,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC;;;;GAIG;AACH,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC;2FAC2F;AAC3F,eAAO,MAAM,WAAW,SAAU,CAAC;AACnC,mFAAmF;AACnF,eAAO,MAAM,eAAe,OAAQ,CAAC;AACrC,mGAAmG;AACnG,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,OAAO,MAAM,CAAC;AAC3B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAC5B,eAAO,MAAM,OAAO,YAAY,CAAC;AACjC,2EAA2E;AAC3E,eAAO,MAAM,QAAQ,qBAAqB,CAAC;AAC3C,eAAO,MAAM,cAAc,2BAA2B,CAAC"}
|