@reticlehq/browser 2.0.1 → 2.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.
Files changed (85) hide show
  1. package/dist/actions/actions-dom.d.ts.map +1 -1
  2. package/dist/actions/actions-dom.js +3 -20
  3. package/dist/actions/actions-dom.js.map +1 -1
  4. package/dist/commands/commands.d.ts.map +1 -1
  5. package/dist/commands/commands.js +14 -29
  6. package/dist/commands/commands.js.map +1 -1
  7. package/dist/dom/a11y.d.ts +1 -1
  8. package/dist/dom/a11y.d.ts.map +1 -1
  9. package/dist/dom/a11y.js +1 -1
  10. package/dist/dom/a11y.js.map +1 -1
  11. package/dist/dom/dom-ignore.d.ts +2 -0
  12. package/dist/dom/dom-ignore.d.ts.map +1 -1
  13. package/dist/dom/dom-ignore.js +10 -0
  14. package/dist/dom/dom-ignore.js.map +1 -1
  15. package/dist/dom/occlusion.d.ts +9 -0
  16. package/dist/dom/occlusion.d.ts.map +1 -0
  17. package/dist/dom/occlusion.js +21 -0
  18. package/dist/dom/occlusion.js.map +1 -0
  19. package/dist/dom/query.d.ts +1 -1
  20. package/dist/dom/query.d.ts.map +1 -1
  21. package/dist/dom/query.js +1 -1
  22. package/dist/dom/query.js.map +1 -1
  23. package/dist/dom/refs.d.ts +1 -1
  24. package/dist/dom/refs.js +1 -1
  25. package/dist/dom/snapshot.d.ts +1 -1
  26. package/dist/dom/snapshot.d.ts.map +1 -1
  27. package/dist/dom/snapshot.js +37 -15
  28. package/dist/dom/snapshot.js.map +1 -1
  29. package/dist/observers/animation.d.ts +1 -1
  30. package/dist/observers/animation.d.ts.map +1 -1
  31. package/dist/observers/animation.js +1 -1
  32. package/dist/observers/animation.js.map +1 -1
  33. package/dist/observers/dom.d.ts +1 -1
  34. package/dist/observers/dom.d.ts.map +1 -1
  35. package/dist/observers/dom.js +1 -1
  36. package/dist/observers/dom.js.map +1 -1
  37. package/dist/observers/network.d.ts +10 -5
  38. package/dist/observers/network.d.ts.map +1 -1
  39. package/dist/observers/network.js +289 -29
  40. package/dist/observers/network.js.map +1 -1
  41. package/dist/observers/perf.d.ts +13 -0
  42. package/dist/observers/perf.d.ts.map +1 -0
  43. package/dist/observers/perf.js +62 -0
  44. package/dist/observers/perf.js.map +1 -0
  45. package/dist/observers/route.d.ts.map +1 -1
  46. package/dist/observers/route.js +5 -2
  47. package/dist/observers/route.js.map +1 -1
  48. package/dist/observers/scroll.d.ts +1 -1
  49. package/dist/observers/scroll.d.ts.map +1 -1
  50. package/dist/observers/scroll.js +1 -1
  51. package/dist/observers/scroll.js.map +1 -1
  52. package/dist/observers/storage.d.ts +14 -0
  53. package/dist/observers/storage.d.ts.map +1 -0
  54. package/dist/observers/storage.js +75 -0
  55. package/dist/observers/storage.js.map +1 -0
  56. package/dist/presenter/presenter-test-helpers.d.ts +16 -0
  57. package/dist/presenter/presenter-test-helpers.d.ts.map +1 -0
  58. package/dist/presenter/presenter-test-helpers.js +42 -0
  59. package/dist/presenter/presenter-test-helpers.js.map +1 -0
  60. package/dist/presenter/presenter.d.ts +0 -2
  61. package/dist/presenter/presenter.d.ts.map +1 -1
  62. package/dist/presenter/presenter.js +0 -4
  63. package/dist/presenter/presenter.js.map +1 -1
  64. package/dist/recorder/recorder.d.ts.map +1 -1
  65. package/dist/recorder/recorder.js +13 -0
  66. package/dist/recorder/recorder.js.map +1 -1
  67. package/dist/registry/stores.d.ts +7 -1
  68. package/dist/registry/stores.d.ts.map +1 -1
  69. package/dist/registry/stores.js +15 -3
  70. package/dist/registry/stores.js.map +1 -1
  71. package/dist/reticle.d.ts +6 -1
  72. package/dist/reticle.d.ts.map +1 -1
  73. package/dist/reticle.js +4 -2
  74. package/dist/reticle.js.map +1 -1
  75. package/dist/review/annotator.d.ts.map +1 -1
  76. package/dist/review/annotator.js +3 -1
  77. package/dist/review/annotator.js.map +1 -1
  78. package/dist/security/serialization.d.ts +2 -0
  79. package/dist/security/serialization.d.ts.map +1 -1
  80. package/dist/security/serialization.js +13 -2
  81. package/dist/security/serialization.js.map +1 -1
  82. package/dist/transport/transport.d.ts.map +1 -1
  83. package/dist/transport/transport.js +7 -4
  84. package/dist/transport/transport.js.map +1 -1
  85. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
1
  import type { Emit, Teardown } from './types.js';
2
- /** Observe CSS animations + transitions and emit anim.start / anim.end (plan/03 §6). */
2
+ /** Observe CSS animations + transitions and emit anim.start / anim.end. */
3
3
  export declare function installAnimation(emit: Emit): Teardown;
4
4
  //# sourceMappingURL=animation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"animation.d.ts","sourceRoot":"","sources":["../../src/observers/animation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjD,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAmCrD"}
1
+ {"version":3,"file":"animation.d.ts","sourceRoot":"","sources":["../../src/observers/animation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjD,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAmCrD"}
@@ -1,7 +1,7 @@
1
1
  import { EventType } from '@reticlehq/core';
2
2
  import { refs } from '../dom/refs.js';
3
3
  import { isReticleOverlay } from '../dom/dom-ignore.js';
4
- /** Observe CSS animations + transitions and emit anim.start / anim.end (plan/03 §6). */
4
+ /** Observe CSS animations + transitions and emit anim.start / anim.end. */
5
5
  export function installAnimation(emit) {
6
6
  const onStart = (event) => {
7
7
  const target = event.target;
@@ -1 +1 @@
1
- {"version":3,"file":"animation.js","sourceRoot":"","sources":["../../src/observers/animation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,IAAU;IACzC,MAAM,OAAO,GAAG,CAAC,KAAqB,EAAQ,EAAE;QAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,6FAA6F;QAC7F,wFAAwF;QACxF,IAAI,MAAM,YAAY,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACjF,CAAC;IACH,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,CAAC,KAAqB,EAAQ,EAAE;QAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,IAAI,MAAM,YAAY,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC,CAAC;IACF,MAAM,eAAe,GAAG,CAAC,KAAsB,EAAQ,EAAE;QACvD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,IAAI,MAAM,YAAY,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,IAAI,CACF,SAAS,CAAC,QAAQ,EAClB,EAAE,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,EAChD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CACpB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;IAEF,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3D,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACvD,QAAQ,CAAC,gBAAgB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;IAElE,OAAO,GAAG,EAAE;QACV,QAAQ,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC9D,QAAQ,CAAC,mBAAmB,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1D,QAAQ,CAAC,mBAAmB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;IACvE,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"animation.js","sourceRoot":"","sources":["../../src/observers/animation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAAC,IAAU;IACzC,MAAM,OAAO,GAAG,CAAC,KAAqB,EAAQ,EAAE;QAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,6FAA6F;QAC7F,wFAAwF;QACxF,IAAI,MAAM,YAAY,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACjF,CAAC;IACH,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,CAAC,KAAqB,EAAQ,EAAE;QAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,IAAI,MAAM,YAAY,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC,CAAC;IACF,MAAM,eAAe,GAAG,CAAC,KAAsB,EAAQ,EAAE;QACvD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,IAAI,MAAM,YAAY,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,IAAI,CACF,SAAS,CAAC,QAAQ,EAClB,EAAE,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,EAChD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CACpB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;IAEF,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3D,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACvD,QAAQ,CAAC,gBAAgB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;IAElE,OAAO,GAAG,EAAE;QACV,QAAQ,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC9D,QAAQ,CAAC,mBAAmB,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1D,QAAQ,CAAC,mBAAmB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;IACvE,CAAC,CAAC;AACJ,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import type { Emit, Teardown } from './types.js';
2
- /** Observe DOM mutations and emit semantic (not raw) events. See plan/03 §1. */
2
+ /** Observe DOM mutations and emit semantic (not raw) events. */
3
3
  export declare function installDom(emit: Emit): Teardown;
4
4
  //# sourceMappingURL=dom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAwBjD,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA0E/C"}
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAwBjD,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA0E/C"}
@@ -20,7 +20,7 @@ const MAX_PER_BATCH = 40;
20
20
  function isMeaningful(role, name) {
21
21
  return role !== 'generic' || name.length > 0;
22
22
  }
23
- /** Observe DOM mutations and emit semantic (not raw) events. See plan/03 §1. */
23
+ /** Observe DOM mutations and emit semantic (not raw) events. */
24
24
  export function installDom(emit) {
25
25
  const observer = new MutationObserver((records) => {
26
26
  let added = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,16 @@
1
1
  import type { Emit, Teardown } from './types.js';
2
+ /** Config for the network observer. Body capture is OFF by default and dev-only opt-in. */
3
+ export interface NetworkOptions {
4
+ /** Capture request/response bodies (text-like content only, redacted, per-body capped). */
5
+ captureBodies?: boolean;
6
+ }
2
7
  /**
3
- * Redact credential-bearing query params (`?access_token=…`, signed-URL keys, magic-link tokens) so
4
- * they don't leak into the agent transcript / flow / run artifacts. Only the query string is rewritten
5
- * — the path (relative or absolute) and any hash are preserved — and only when something actually
6
- * matched, so non-sensitive URLs pass through byte-for-byte. Uses the shared `isSensitiveKey` regex.
8
+ * Redact credential-bearing values so they don't leak into the agent transcript / flow / run
9
+ * artifacts: query params (`?access_token=…`, signed-URL keys) via the shared `isSensitiveKey` regex,
10
+ * AND path-embedded tokens (`/reset/<token>`, `/invite/<token>`) that live in the path, not the query.
11
+ * The hash is preserved and the URL is returned byte-for-byte when nothing matched.
7
12
  */
8
13
  export declare function redactUrl(raw: string): string;
9
14
  /** Patch fetch + XMLHttpRequest to emit net.request events. Fully reversible. */
10
- export declare function installNetwork(emit: Emit): Teardown;
15
+ export declare function installNetwork(emit: Emit, opts?: NetworkOptions): Teardown;
11
16
  //# sourceMappingURL=network.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/observers/network.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAiB7C;AAqBD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAiGnD"}
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/observers/network.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjD,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,2FAA2F;IAC3F,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AA+HD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA0D7C;AAyCD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAE,cAAmB,GAAG,QAAQ,CAoM9E"}
@@ -1,29 +1,192 @@
1
1
  import { EventType, REDACTED_VALUE } from '@reticlehq/core';
2
- import { isSensitiveKey } from '../security/serialization.js';
2
+ import { isSensitiveKey, sanitizeForTransport, safeStringify, scrubKnownSecrets, } from '../security/serialization.js';
3
3
  /**
4
- * Redact credential-bearing query params (`?access_token=…`, signed-URL keys, magic-link tokens) so
5
- * they don't leak into the agent transcript / flow / run artifacts. Only the query string is rewritten
6
- * — the path (relative or absolute) and any hash are preserved — and only when something actually
7
- * matched, so non-sensitive URLs pass through byte-for-byte. Uses the shared `isSensitiveKey` regex.
4
+ * Per-body character cap. Bodies ride the same ring buffer as the DOM/route/console timeline, so an
5
+ * uncapped body could evict the whole behavioral history; the small cap keeps a few large responses
6
+ * from starving the timeline (the separate-budget concern in the scalability audit).
7
+ */
8
+ const MAX_BODY_CHARS = 8192;
9
+ /** Only text-like bodies are worth capturing; binary (images/fonts/octet-stream) is skipped. */
10
+ const CAPTURABLE_CONTENT = /application\/json|text\/|application\/xml|x-www-form-urlencoded|graphql/i;
11
+ function isCapturableType(contentType) {
12
+ return contentType !== null && CAPTURABLE_CONTENT.test(contentType);
13
+ }
14
+ /**
15
+ * An `Authorization: Bearer …` / `Basic …` credential. The token side requires credential shape — 16+
16
+ * chars AND at least one digit or symbol — so ordinary prose ("Basic subscription includes…", "Bearer
17
+ * capacity exceeded") is NOT mangled, only actual opaque tokens are.
18
+ */
19
+ const AUTH_SCHEME_TOKEN = /\b(Bearer|Basic)\s+(?=[A-Za-z0-9._~+/=-]{16,})(?=[A-Za-z0-9._~+/=-]*[\d._~+/=-])[A-Za-z0-9._~+/=-]+/gi;
20
+ /**
21
+ * Redact credentials in ANY text body (form-urlencoded, text/plain, xml, or JSON that failed to parse).
22
+ * sanitizeForTransport only redacts KEYS inside a parsed object, so a `password=secret` form post or a
23
+ * `Bearer <token>` string would otherwise ship verbatim. Redacts the value of any `key=value` / `key: value`
24
+ * pair whose key is sensitive, plus credential-shaped auth-scheme tokens.
25
+ */
26
+ function redactText(text) {
27
+ return (text
28
+ // Auth-scheme tokens FIRST: `Authorization: Bearer <token>` — the key/value rule below would
29
+ // otherwise consume just "Bearer" as Authorization's value (it stops at whitespace) and leave the
30
+ // token behind, so the scheme rule must run before it.
31
+ .replace(AUTH_SCHEME_TOKEN, (_m, scheme) => `${scheme} ${REDACTED_VALUE}`)
32
+ .replace(/([A-Za-z0-9_.-]+)(\s*[=:]\s*"?)([^&\s,;"}]+)/g, (match, key, sep) => isSensitiveKey(key) ? `${key}${sep}${REDACTED_VALUE}` : match));
33
+ }
34
+ /**
35
+ * Redact + cap a body for the agent transcript. JSON is parsed and run through the same
36
+ * sanitizeForTransport redaction used for state (sensitive keys -> [REDACTED]); every other text body
37
+ * (and JSON that didn't parse) goes through redactText so form/plain-text credentials can't leak.
38
+ * Returns the (possibly truncated) body plus whether it was cut.
39
+ */
40
+ function projectBody(text, contentType) {
41
+ let out;
42
+ if (contentType !== null && /json|graphql/i.test(contentType)) {
43
+ try {
44
+ out = safeStringify(sanitizeForTransport(JSON.parse(text)));
45
+ }
46
+ catch {
47
+ out = redactText(text); // looked like JSON but wasn't — still redact key/value + auth tokens
48
+ }
49
+ }
50
+ else {
51
+ out = redactText(text);
52
+ }
53
+ // Key-based redaction can't see a secret sitting in a VALUE under a benign key — scan the projected
54
+ // text for high-confidence secret shapes (JWTs, provider keys) as a backstop, JSON or not.
55
+ out = scrubKnownSecrets(out);
56
+ const truncated = out.length > MAX_BODY_CHARS;
57
+ return { body: truncated ? out.slice(0, MAX_BODY_CHARS) : out, truncated };
58
+ }
59
+ /** The byte size of a binary frame (ArrayBuffer / Blob / typed-array view), or undefined if unknown. */
60
+ function binaryFrameBytes(data) {
61
+ if (data instanceof ArrayBuffer)
62
+ return data.byteLength;
63
+ if (typeof Blob !== 'undefined' && data instanceof Blob)
64
+ return data.size;
65
+ if (ArrayBuffer.isView(data))
66
+ return data.byteLength;
67
+ return undefined;
68
+ }
69
+ /** Project one SSE/WebSocket frame: byte size + shape; the (capped, redacted) payload only when body
70
+ * capture is on and it is a string frame. Binary frames report their byte size, not just a bare type. */
71
+ function frameFields(data, captureBodies) {
72
+ if (typeof data !== 'string') {
73
+ const bytes = binaryFrameBytes(data);
74
+ return bytes === undefined
75
+ ? { frameType: typeof data }
76
+ : { frameType: 'binary', frameBytes: bytes };
77
+ }
78
+ const out = { frameBytes: data.length };
79
+ if (captureBodies) {
80
+ const { body, truncated } = projectBody(data, 'application/json');
81
+ out['frame'] = body;
82
+ if (truncated)
83
+ out['frameTruncated'] = true;
84
+ }
85
+ return out;
86
+ }
87
+ /**
88
+ * The request body for the transcript. Plain strings and URLSearchParams are captured (redacted, capped);
89
+ * FormData/Blob/ArrayBuffer/stream aren't text so they get a `requestBodyType` marker (the agent still
90
+ * learns a body existed) rather than being silently dropped. Shared by the fetch and XHR paths.
91
+ */
92
+ function projectRequestBody(body, captureBodies) {
93
+ if (!captureBodies)
94
+ return {};
95
+ let text;
96
+ let contentType = 'application/json';
97
+ if (typeof body === 'string') {
98
+ text = body;
99
+ }
100
+ else if (typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams) {
101
+ text = body.toString();
102
+ contentType = 'application/x-www-form-urlencoded';
103
+ }
104
+ else if (body !== undefined && body !== null) {
105
+ const shape = body.constructor?.name ?? typeof body;
106
+ return { requestBodyType: shape };
107
+ }
108
+ if (text === undefined || text.length === 0)
109
+ return {};
110
+ const { body: out, truncated } = projectBody(text, contentType);
111
+ return truncated ? { requestBody: out, requestBodyTruncated: true } : { requestBody: out };
112
+ }
113
+ /** A path segment name that is typically followed by a single-use secret token in the NEXT segment. */
114
+ const SENSITIVE_PATH_SEGMENT = /^(reset|verify|verification|confirm|activate|invite|magic|magiclink|token|key|oauth|unsubscribe|password)$/i;
115
+ /** Only mask a following segment that looks token-like — short ids/words (`reset/form`) are left alone. */
116
+ const PATH_TOKEN_MIN_LENGTH = 12;
117
+ /**
118
+ * Redact credential-bearing values so they don't leak into the agent transcript / flow / run
119
+ * artifacts: query params (`?access_token=…`, signed-URL keys) via the shared `isSensitiveKey` regex,
120
+ * AND path-embedded tokens (`/reset/<token>`, `/invite/<token>`) that live in the path, not the query.
121
+ * The hash is preserved and the URL is returned byte-for-byte when nothing matched.
8
122
  */
9
123
  export function redactUrl(raw) {
10
- const queryStart = raw.indexOf('?');
11
- if (queryStart === -1)
12
- return raw;
13
- const base = raw.slice(0, queryStart);
14
- const rest = raw.slice(queryStart + 1);
15
- const hashStart = rest.indexOf('#');
16
- const query = hashStart === -1 ? rest : rest.slice(0, hashStart);
17
- const hash = hashStart === -1 ? '' : rest.slice(hashStart);
18
- const params = new URLSearchParams(query);
124
+ const hashStart = raw.indexOf('#');
125
+ const hash = hashStart === -1 ? '' : raw.slice(hashStart);
126
+ const beforeHash = hashStart === -1 ? raw : raw.slice(0, hashStart);
127
+ const queryStart = beforeHash.indexOf('?');
128
+ const pathPart = queryStart === -1 ? beforeHash : beforeHash.slice(0, queryStart);
129
+ const query = queryStart === -1 ? '' : beforeHash.slice(queryStart + 1);
19
130
  let changed = false;
20
- for (const key of [...params.keys()]) {
21
- if (isSensitiveKey(key)) {
22
- params.set(key, REDACTED_VALUE);
131
+ // Credentials in the authority (`scheme://user:pass@host`) never belong in a transcript.
132
+ let authority = pathPart;
133
+ const userinfo = /^([a-z][a-z0-9+.-]*:\/\/)[^/@]+@/i.exec(pathPart);
134
+ if (userinfo !== null) {
135
+ authority = `${userinfo[1] ?? ''}${REDACTED_VALUE}@${pathPart.slice(userinfo[0].length)}`;
136
+ changed = true;
137
+ }
138
+ let newQuery = query;
139
+ if (query !== '') {
140
+ const params = new URLSearchParams(query);
141
+ for (const key of [...params.keys()]) {
142
+ if (isSensitiveKey(key)) {
143
+ params.set(key, REDACTED_VALUE);
144
+ changed = true;
145
+ }
146
+ }
147
+ newQuery = params.toString();
148
+ }
149
+ const segments = authority.split('/');
150
+ for (let i = 0; i + 1 < segments.length; i++) {
151
+ const name = segments[i];
152
+ const next = segments[i + 1];
153
+ if (name !== undefined &&
154
+ next !== undefined &&
155
+ next.length >= PATH_TOKEN_MIN_LENGTH &&
156
+ SENSITIVE_PATH_SEGMENT.test(name)) {
157
+ segments[i + 1] = REDACTED_VALUE;
23
158
  changed = true;
24
159
  }
25
160
  }
26
- return changed ? `${base}?${params.toString()}${hash}` : raw;
161
+ // OAuth implicit flow puts the access_token in the FRAGMENT (`#access_token=…`), and hash-routers carry
162
+ // `?token=…` in the hash — redact sensitive params there too, leaving plain anchors (`#section`) alone.
163
+ let newHash = hash;
164
+ if (hash.length > 1) {
165
+ newHash = hash.replace(/([A-Za-z0-9_.-]+)=([^&\s]+)/g, (m, key) => isSensitiveKey(key) ? `${key}=${REDACTED_VALUE}` : m);
166
+ if (newHash !== hash)
167
+ changed = true;
168
+ }
169
+ if (!changed)
170
+ return raw;
171
+ const queryOut = queryStart === -1 ? '' : `?${newQuery}`;
172
+ return `${segments.join('/')}${queryOut}${newHash}`;
173
+ }
174
+ /**
175
+ * Response metadata that needs no body capture: HTTP status text, content-type, and byte size (from
176
+ * content-length when the server sent it). Lets an agent tell an HTML error page served as 200 from
177
+ * real JSON, and spot empty/oversized responses. Fields are omitted when absent so a clean call stays
178
+ * token-flat.
179
+ */
180
+ function netResponseMeta(statusText, contentType, contentLength) {
181
+ const out = {};
182
+ if (statusText !== '')
183
+ out['statusText'] = statusText;
184
+ if (contentType !== null && contentType !== '')
185
+ out['contentType'] = contentType;
186
+ const size = contentLength !== null ? Number.parseInt(contentLength, 10) : Number.NaN;
187
+ if (Number.isFinite(size))
188
+ out['responseSize'] = size;
189
+ return out;
27
190
  }
28
191
  function urlOf(input) {
29
192
  if (typeof input === 'string')
@@ -40,7 +203,8 @@ function methodOf(input, init) {
40
203
  return 'GET';
41
204
  }
42
205
  /** Patch fetch + XMLHttpRequest to emit net.request events. Fully reversible. */
43
- export function installNetwork(emit) {
206
+ export function installNetwork(emit, opts = {}) {
207
+ const captureBodies = opts.captureBodies === true;
44
208
  // Keep the true original for teardown identity, plus a window-bound copy to invoke
45
209
  // (fetch throws "Illegal invocation" if called with the wrong `this`).
46
210
  const origFetch = window.fetch;
@@ -59,6 +223,21 @@ export function installNetwork(emit) {
59
223
  emit(EventType.NET_PENDING, { id, method, url, initiator: 'fetch' });
60
224
  try {
61
225
  const res = await callFetch(input, init);
226
+ const contentType = res.headers.get('content-type');
227
+ // Read a CLONE so the app's response stream stays untouched. Dev-only opt-in; only text-like
228
+ // bodies; a read failure never breaks the observation.
229
+ let responseBodyFields = {};
230
+ if (captureBodies && isCapturableType(contentType)) {
231
+ try {
232
+ const { body, truncated } = projectBody(await res.clone().text(), contentType);
233
+ responseBodyFields = truncated
234
+ ? { responseBody: body, responseBodyTruncated: true }
235
+ : { responseBody: body };
236
+ }
237
+ catch {
238
+ /* body not readable (already locked/consumed) — skip, keep the envelope */
239
+ }
240
+ }
62
241
  emit(EventType.NET_REQUEST, {
63
242
  id,
64
243
  method,
@@ -67,6 +246,9 @@ export function installNetwork(emit) {
67
246
  ok: res.ok,
68
247
  durationMs: Math.round(performance.now() - start),
69
248
  initiator: 'fetch',
249
+ ...netResponseMeta(res.statusText, contentType, res.headers.get('content-length')),
250
+ ...projectRequestBody(init?.body, captureBodies),
251
+ ...responseBodyFields,
70
252
  });
71
253
  return res;
72
254
  }
@@ -100,29 +282,107 @@ export function installNetwork(emit) {
100
282
  });
101
283
  callOpen.call(this, method, url, ...rest);
102
284
  };
285
+ // A reused XHR calls send() repeatedly; attach the completion listener ONCE per instance and read the
286
+ // request identity from `meta` at fire time. Adding a fresh closure each send() would leave stale
287
+ // listeners that re-fire on later completions, emitting duplicate, mislabeled events.
288
+ const listenerAttached = new WeakSet();
103
289
  proto.send = function (body) {
104
290
  const m = meta.get(this);
105
291
  if (m !== undefined) {
106
292
  m.start = performance.now();
293
+ m.reqBody = body ?? null;
107
294
  emit(EventType.NET_PENDING, { id: m.id, method: m.method, url: m.url, initiator: 'xhr' });
108
- this.addEventListener('loadend', () => {
109
- emit(EventType.NET_REQUEST, {
110
- id: m.id,
111
- method: m.method,
112
- url: m.url,
113
- status: this.status,
114
- ok: this.status >= 200 && this.status < 400,
115
- durationMs: Math.round(performance.now() - m.start),
116
- initiator: 'xhr',
295
+ if (!listenerAttached.has(this)) {
296
+ listenerAttached.add(this);
297
+ this.addEventListener('loadend', () => {
298
+ const cur = meta.get(this);
299
+ if (cur === undefined)
300
+ return;
301
+ const xhrContentType = this.getResponseHeader('content-type');
302
+ let responseBodyFields = {};
303
+ // responseText throws unless responseType is '' or 'text' — guard before reading.
304
+ const textReadable = this.responseType === '' || this.responseType === 'text';
305
+ if (captureBodies && textReadable && isCapturableType(xhrContentType)) {
306
+ try {
307
+ const { body: rb, truncated } = projectBody(this.responseText, xhrContentType);
308
+ responseBodyFields = truncated
309
+ ? { responseBody: rb, responseBodyTruncated: true }
310
+ : { responseBody: rb };
311
+ }
312
+ catch {
313
+ /* unreadable body — skip */
314
+ }
315
+ }
316
+ emit(EventType.NET_REQUEST, {
317
+ id: cur.id,
318
+ method: cur.method,
319
+ url: cur.url,
320
+ status: this.status,
321
+ ok: this.status >= 200 && this.status < 400,
322
+ durationMs: Math.round(performance.now() - cur.start),
323
+ initiator: 'xhr',
324
+ ...netResponseMeta(this.statusText, xhrContentType, this.getResponseHeader('content-length')),
325
+ ...projectRequestBody(cur.reqBody, captureBodies),
326
+ ...responseBodyFields,
327
+ });
117
328
  });
118
- });
329
+ }
119
330
  }
120
331
  origSend.call(this, body ?? null);
121
332
  };
333
+ // SSE + WebSocket frame capture — gated behind body capture, since a chatty stream is the
334
+ // high-volume case. Subclass the native constructors so the app's own usage is unchanged.
335
+ const origEventSource = window.EventSource;
336
+ const origWebSocket = window.WebSocket;
337
+ if (captureBodies && typeof origEventSource === 'function') {
338
+ window.EventSource = class extends origEventSource {
339
+ constructor(u, init) {
340
+ super(u, init);
341
+ const url = redactUrl(String(u));
342
+ emit(EventType.NET_STREAM, { transport: 'sse', direction: 'open', url });
343
+ this.addEventListener('message', (ev) => {
344
+ emit(EventType.NET_STREAM, {
345
+ transport: 'sse',
346
+ direction: 'in',
347
+ url,
348
+ ...frameFields(ev.data, captureBodies),
349
+ });
350
+ });
351
+ }
352
+ };
353
+ }
354
+ if (captureBodies && typeof origWebSocket === 'function') {
355
+ window.WebSocket = class extends origWebSocket {
356
+ constructor(u, protocols) {
357
+ super(u, protocols);
358
+ const url = redactUrl(String(u));
359
+ emit(EventType.NET_STREAM, { transport: 'ws', direction: 'open', url });
360
+ this.addEventListener('message', (ev) => {
361
+ emit(EventType.NET_STREAM, {
362
+ transport: 'ws',
363
+ direction: 'in',
364
+ url,
365
+ ...frameFields(ev.data, captureBodies),
366
+ });
367
+ });
368
+ }
369
+ send(data) {
370
+ emit(EventType.NET_STREAM, {
371
+ transport: 'ws',
372
+ direction: 'out',
373
+ url: redactUrl(this.url),
374
+ ...frameFields(data, captureBodies),
375
+ });
376
+ super.send(data);
377
+ }
378
+ };
379
+ }
122
380
  return () => {
123
381
  window.fetch = origFetch;
124
382
  proto.open = origOpen;
125
383
  proto.send = origSend;
384
+ window.EventSource = origEventSource;
385
+ window.WebSocket = origWebSocket;
126
386
  };
127
387
  }
128
388
  //# sourceMappingURL=network.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/observers/network.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/observers/network.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Emit, Teardown } from './types.js';
2
+ /**
3
+ * Observe the web-perf signals a screenshot tool fundamentally cannot verify — largest-contentful-paint
4
+ * (LCP), cumulative layout shift (CLS), and long tasks — and emit them into the ring buffer so an agent
5
+ * can assert "no layout shift on load" or "LCP under 2.5s". No-ops when PerformanceObserver or a given
6
+ * entry type is unavailable (jsdom / older browsers), so it never throws in an unsupported context.
7
+ *
8
+ * Each event carries `at` (the entry's own startTime) so a consumer can reason about WHEN the metric
9
+ * occurred rather than when it was flushed — buffered:true replays pre-install entries, whose emit time
10
+ * would otherwise be install time.
11
+ */
12
+ export declare function installPerf(emit: Emit): Teardown;
13
+ //# sourceMappingURL=perf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../../src/observers/perf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAQjD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA8ChD"}
@@ -0,0 +1,62 @@
1
+ import { EventType, PerfMetric } from '@reticlehq/core';
2
+ /**
3
+ * Observe the web-perf signals a screenshot tool fundamentally cannot verify — largest-contentful-paint
4
+ * (LCP), cumulative layout shift (CLS), and long tasks — and emit them into the ring buffer so an agent
5
+ * can assert "no layout shift on load" or "LCP under 2.5s". No-ops when PerformanceObserver or a given
6
+ * entry type is unavailable (jsdom / older browsers), so it never throws in an unsupported context.
7
+ *
8
+ * Each event carries `at` (the entry's own startTime) so a consumer can reason about WHEN the metric
9
+ * occurred rather than when it was flushed — buffered:true replays pre-install entries, whose emit time
10
+ * would otherwise be install time.
11
+ */
12
+ export function installPerf(emit) {
13
+ if (typeof PerformanceObserver !== 'function')
14
+ return () => undefined;
15
+ const observers = [];
16
+ const observe = (type, handle) => {
17
+ try {
18
+ const po = new PerformanceObserver((list) => {
19
+ for (const entry of list.getEntries())
20
+ handle(entry);
21
+ });
22
+ po.observe({ type, buffered: true });
23
+ observers.push(po);
24
+ }
25
+ catch {
26
+ /* entry type unsupported in this browser — skip it, leave the others installed */
27
+ }
28
+ };
29
+ // CLS is CUMULATIVE: sum qualifying shifts and report the running total, not each isolated shift.
30
+ // ponytail: naive running sum — no session-windowing (5s window / 1s gap); enough for
31
+ // "no layout shift on load" and trend, upgrade to windowed sessions if a CWV-exact number is needed.
32
+ let cls = 0;
33
+ // LCP only grows across candidates — surface a value only when it exceeds the last, not every candidate.
34
+ let lcp = 0;
35
+ observe('largest-contentful-paint', (e) => {
36
+ const value = Math.round(e.startTime);
37
+ if (value <= lcp)
38
+ return;
39
+ lcp = value;
40
+ emit(EventType.PERF, { metric: PerfMetric.LCP, value, at: value });
41
+ });
42
+ observe('layout-shift', (e) => {
43
+ const ls = e;
44
+ // Shifts within 500ms of a user input are expected (not CLS) — the spec's hadRecentInput flag.
45
+ if (ls.hadRecentInput === true)
46
+ return;
47
+ cls += ls.value ?? 0;
48
+ emit(EventType.PERF, { metric: PerfMetric.CLS, value: cls, at: Math.round(e.startTime) });
49
+ });
50
+ observe('longtask', (e) => {
51
+ emit(EventType.PERF, {
52
+ metric: PerfMetric.LONGTASK,
53
+ value: Math.round(e.duration),
54
+ at: Math.round(e.startTime),
55
+ });
56
+ });
57
+ return () => {
58
+ for (const po of observers)
59
+ po.disconnect();
60
+ };
61
+ }
62
+ //# sourceMappingURL=perf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf.js","sourceRoot":"","sources":["../../src/observers/perf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AASxD;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,IAAU;IACpC,IAAI,OAAO,mBAAmB,KAAK,UAAU;QAAE,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC;IACtE,MAAM,SAAS,GAA0B,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,MAAyC,EAAQ,EAAE;QAChF,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,mBAAmB,CAAC,CAAC,IAAI,EAAE,EAAE;gBAC1C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE;oBAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACvD,CAAC,CAAC,CAAC;YACH,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACrC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,kFAAkF;QACpF,CAAC;IACH,CAAC,CAAC;IAEF,kGAAkG;IAClG,sFAAsF;IACtF,qGAAqG;IACrG,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,yGAAyG;IACzG,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAC,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,KAAK,IAAI,GAAG;YAAE,OAAO;QACzB,GAAG,GAAG,KAAK,CAAC;QACZ,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;QAC5B,MAAM,EAAE,GAAG,CAAqB,CAAC;QACjC,+FAA+F;QAC/F,IAAI,EAAE,CAAC,cAAc,KAAK,IAAI;YAAE,OAAO;QACvC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE;QACxB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;YACnB,MAAM,EAAE,UAAU,CAAC,QAAQ;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC7B,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,EAAE;QACV,KAAK,MAAM,EAAE,IAAI,SAAS;YAAE,EAAE,CAAC,UAAU,EAAE,CAAC;IAC9C,CAAC,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/observers/route.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAWjD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA+CjD"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/observers/route.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAWjD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAmDjD"}
@@ -17,10 +17,15 @@ export function installRoute(emit) {
17
17
  /* eslint-enable @typescript-eslint/unbound-method */
18
18
  const callPush = origPush.bind(history);
19
19
  const callReplace = origReplace.bind(history);
20
+ // The `from` baseline for the NEXT popstate/hashchange. Updated in fire() on every emitted change
21
+ // — including pushState/replaceState — so a later Back nav isn't compared against a stale href
22
+ // (which made `to === from` trip and silently drop the back navigation).
23
+ let lastHref = location.href;
20
24
  const fire = (from) => {
21
25
  const to = snapshotLocation();
22
26
  if (to.href === from)
23
27
  return;
28
+ lastHref = to.href;
24
29
  emit(EventType.ROUTE_CHANGE, {
25
30
  from,
26
31
  to: to.href,
@@ -39,10 +44,8 @@ export function installRoute(emit) {
39
44
  callReplace(data, unused, url ?? null);
40
45
  fire(from);
41
46
  };
42
- let lastHref = location.href;
43
47
  const onNav = () => {
44
48
  fire(lastHref);
45
- lastHref = location.href;
46
49
  };
47
50
  window.addEventListener('popstate', onNav);
48
51
  window.addEventListener('hashchange', onNav);