@cubenest/rrweb-core 0.1.0-alpha.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 (135) hide show
  1. package/NOTICE +15 -0
  2. package/README.md +26 -0
  3. package/dist/compat/index.d.ts +37 -0
  4. package/dist/compat/index.d.ts.map +1 -0
  5. package/dist/compat/index.js +97 -0
  6. package/dist/compat/index.js.map +1 -0
  7. package/dist/compression/index.d.ts +24 -0
  8. package/dist/compression/index.d.ts.map +1 -0
  9. package/dist/compression/index.js +61 -0
  10. package/dist/compression/index.js.map +1 -0
  11. package/dist/console/buffer.d.ts +99 -0
  12. package/dist/console/buffer.d.ts.map +1 -0
  13. package/dist/console/buffer.js +169 -0
  14. package/dist/console/buffer.js.map +1 -0
  15. package/dist/console/index.d.ts +3 -0
  16. package/dist/console/index.d.ts.map +1 -0
  17. package/dist/console/index.js +16 -0
  18. package/dist/console/index.js.map +1 -0
  19. package/dist/console/types.d.ts +61 -0
  20. package/dist/console/types.d.ts.map +1 -0
  21. package/dist/console/types.js +11 -0
  22. package/dist/console/types.js.map +1 -0
  23. package/dist/index.d.ts +17 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +18 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/masking/body.d.ts +30 -0
  28. package/dist/masking/body.d.ts.map +1 -0
  29. package/dist/masking/body.js +33 -0
  30. package/dist/masking/body.js.map +1 -0
  31. package/dist/masking/headers.d.ts +16 -0
  32. package/dist/masking/headers.d.ts.map +1 -0
  33. package/dist/masking/headers.js +46 -0
  34. package/dist/masking/headers.js.map +1 -0
  35. package/dist/masking/index.d.ts +8 -0
  36. package/dist/masking/index.d.ts.map +1 -0
  37. package/dist/masking/index.js +11 -0
  38. package/dist/masking/index.js.map +1 -0
  39. package/dist/masking/inputs.d.ts +15 -0
  40. package/dist/masking/inputs.d.ts.map +1 -0
  41. package/dist/masking/inputs.js +36 -0
  42. package/dist/masking/inputs.js.map +1 -0
  43. package/dist/masking/regex.d.ts +96 -0
  44. package/dist/masking/regex.d.ts.map +1 -0
  45. package/dist/masking/regex.js +182 -0
  46. package/dist/masking/regex.js.map +1 -0
  47. package/dist/masking/selectors.d.ts +67 -0
  48. package/dist/masking/selectors.d.ts.map +1 -0
  49. package/dist/masking/selectors.js +137 -0
  50. package/dist/masking/selectors.js.map +1 -0
  51. package/dist/masking/text.d.ts +9 -0
  52. package/dist/masking/text.d.ts.map +1 -0
  53. package/dist/masking/text.js +15 -0
  54. package/dist/masking/text.js.map +1 -0
  55. package/dist/network/cdp.d.ts +54 -0
  56. package/dist/network/cdp.d.ts.map +1 -0
  57. package/dist/network/cdp.js +282 -0
  58. package/dist/network/cdp.js.map +1 -0
  59. package/dist/network/index.d.ts +4 -0
  60. package/dist/network/index.d.ts.map +1 -0
  61. package/dist/network/index.js +14 -0
  62. package/dist/network/index.js.map +1 -0
  63. package/dist/network/types.d.ts +133 -0
  64. package/dist/network/types.d.ts.map +1 -0
  65. package/dist/network/types.js +35 -0
  66. package/dist/network/types.js.map +1 -0
  67. package/dist/network/web-request.d.ts +76 -0
  68. package/dist/network/web-request.d.ts.map +1 -0
  69. package/dist/network/web-request.js +294 -0
  70. package/dist/network/web-request.js.map +1 -0
  71. package/dist/persistence/index.d.ts +3 -0
  72. package/dist/persistence/index.d.ts.map +1 -0
  73. package/dist/persistence/index.js +11 -0
  74. package/dist/persistence/index.js.map +1 -0
  75. package/dist/persistence/store.d.ts +18 -0
  76. package/dist/persistence/store.d.ts.map +1 -0
  77. package/dist/persistence/store.js +327 -0
  78. package/dist/persistence/store.js.map +1 -0
  79. package/dist/persistence/types.d.ts +76 -0
  80. package/dist/persistence/types.d.ts.map +1 -0
  81. package/dist/persistence/types.js +21 -0
  82. package/dist/persistence/types.js.map +1 -0
  83. package/dist/rrweb.d.ts +5 -0
  84. package/dist/rrweb.d.ts.map +1 -0
  85. package/dist/rrweb.js +13 -0
  86. package/dist/rrweb.js.map +1 -0
  87. package/dist/screenshot/base64.d.ts +8 -0
  88. package/dist/screenshot/base64.d.ts.map +1 -0
  89. package/dist/screenshot/base64.js +21 -0
  90. package/dist/screenshot/base64.js.map +1 -0
  91. package/dist/screenshot/cdp.d.ts +50 -0
  92. package/dist/screenshot/cdp.d.ts.map +1 -0
  93. package/dist/screenshot/cdp.js +65 -0
  94. package/dist/screenshot/cdp.js.map +1 -0
  95. package/dist/screenshot/index.d.ts +4 -0
  96. package/dist/screenshot/index.d.ts.map +1 -0
  97. package/dist/screenshot/index.js +10 -0
  98. package/dist/screenshot/index.js.map +1 -0
  99. package/dist/screenshot/tabs.d.ts +44 -0
  100. package/dist/screenshot/tabs.d.ts.map +1 -0
  101. package/dist/screenshot/tabs.js +63 -0
  102. package/dist/screenshot/tabs.js.map +1 -0
  103. package/dist/screenshot/types.d.ts +27 -0
  104. package/dist/screenshot/types.d.ts.map +1 -0
  105. package/dist/screenshot/types.js +18 -0
  106. package/dist/screenshot/types.js.map +1 -0
  107. package/dist/shadow-dom/index.d.ts +3 -0
  108. package/dist/shadow-dom/index.d.ts.map +1 -0
  109. package/dist/shadow-dom/index.js +8 -0
  110. package/dist/shadow-dom/index.js.map +1 -0
  111. package/dist/shadow-dom/traverse.d.ts +54 -0
  112. package/dist/shadow-dom/traverse.d.ts.map +1 -0
  113. package/dist/shadow-dom/traverse.js +209 -0
  114. package/dist/shadow-dom/traverse.js.map +1 -0
  115. package/dist/shadow-dom/types.d.ts +43 -0
  116. package/dist/shadow-dom/types.d.ts.map +1 -0
  117. package/dist/shadow-dom/types.js +25 -0
  118. package/dist/shadow-dom/types.js.map +1 -0
  119. package/dist/throttling/apply.d.ts +59 -0
  120. package/dist/throttling/apply.d.ts.map +1 -0
  121. package/dist/throttling/apply.js +101 -0
  122. package/dist/throttling/apply.js.map +1 -0
  123. package/dist/throttling/defaults.d.ts +60 -0
  124. package/dist/throttling/defaults.d.ts.map +1 -0
  125. package/dist/throttling/defaults.js +81 -0
  126. package/dist/throttling/defaults.js.map +1 -0
  127. package/dist/throttling/guards.d.ts +69 -0
  128. package/dist/throttling/guards.d.ts.map +1 -0
  129. package/dist/throttling/guards.js +212 -0
  130. package/dist/throttling/guards.js.map +1 -0
  131. package/dist/throttling/index.d.ts +5 -0
  132. package/dist/throttling/index.d.ts.map +1 -0
  133. package/dist/throttling/index.js +11 -0
  134. package/dist/throttling/index.js.map +1 -0
  135. package/package.json +35 -0
@@ -0,0 +1,101 @@
1
+ // Public throttling entrypoint — Task 1.4.
2
+ //
3
+ // `applyLargeDomGuards` is the only function the substrate exports from this
4
+ // module (alongside `LARGE_DOM_DEFAULTS`). It composes the three guards from
5
+ // `guards.ts` into a single `recordOptions` transform:
6
+ //
7
+ // 1. Pull recordOptions-shaped defaults (mousemoveWait/sampling/etc.) onto
8
+ // the consumer's options, with the consumer winning on conflicts.
9
+ // 2. Replace the consumer's `emit` with a guarded wrapper that runs every
10
+ // event through dataUrl → eventSize → mutation, in that order. The
11
+ // ordering matters: the data-URL guard shrinks oversized snapshot
12
+ // payloads BEFORE the event-size guard measures them, otherwise an
13
+ // oversize data URL would always trip the size cap and silently drop
14
+ // the whole snapshot.
15
+ //
16
+ // The guards never reach into rrweb's subscription, so this function can't
17
+ // truly stop the recorder on its own. The hard-mutation-limit semantics are:
18
+ // further events are dropped at the wrapper, AND the consumer's `onLimit`
19
+ // callback fires once (consumers wire this to rrweb's teardown if they want
20
+ // a true stop).
21
+ import { LARGE_DOM_DEFAULTS } from './defaults';
22
+ import { applyDataUrlGuard, applyEventSizeGuard, applyMutationGuard, } from './guards';
23
+ /**
24
+ * Compose the throttling defaults and guard chain onto an rrweb
25
+ * `recordOptions` object.
26
+ *
27
+ * Returns a new `recordOptions` with:
28
+ * - the first six `LARGE_DOM_DEFAULTS` (mousemoveWait, sampling,
29
+ * inlineImages, collectFonts, recordCanvas, plus the
30
+ * `checkoutEveryNms` mapped from `defaults.checkoutEveryMs`) merged in
31
+ * where the caller didn't already set them; and
32
+ * - an `emit` wrapper that runs dataUrl → eventSize → mutation in order.
33
+ *
34
+ * Note on semantics: because `applyLargeDomGuards` does not own the rrweb
35
+ * subscription, the hard mutation limit can only stop events from being
36
+ * forwarded from this wrapper onward — it cannot tear down the rrweb
37
+ * `record()` subscription on its own. Wire your own teardown via `onLimit`
38
+ * if you need the recorder itself to stop.
39
+ *
40
+ * @example
41
+ * const stop = record(
42
+ * applyLargeDomGuards(
43
+ * { emit: forwardToTransport },
44
+ * {
45
+ * onWarn: (e) => forwardToTransport(e),
46
+ * onLimit: () => stop?.(),
47
+ * },
48
+ * ),
49
+ * );
50
+ */
51
+ export function applyLargeDomGuards(recordOpts, options = {}) {
52
+ const defaults = options.defaults ?? LARGE_DOM_DEFAULTS;
53
+ const onWarn = options.onWarn ?? noop;
54
+ const callerEmit = recordOpts.emit ?? noopEmit;
55
+ // Build the guard chain. Order is significant — see file header.
56
+ // Note: `onLimit` is spread conditionally because tsconfig
57
+ // `exactOptionalPropertyTypes: true` disallows `undefined` on an optional
58
+ // field — the property either exists with a function value or is absent.
59
+ const mutationHooks = {
60
+ softWarnAt: defaults.mutationSoftWarnAt,
61
+ hardLimit: defaults.mutationLimit,
62
+ emitWarn: onWarn,
63
+ emitLimit: onWarn,
64
+ ...(options.onLimit !== undefined ? { onLimit: options.onLimit } : {}),
65
+ };
66
+ const guardedEmit = applyMutationGuard((event, isCheckout) => {
67
+ const post = applyEventSizeGuard(event, defaults.singleEventMaxBytes, onWarn);
68
+ if (post === null)
69
+ return;
70
+ callerEmit(post, isCheckout);
71
+ }, mutationHooks);
72
+ const composedEmit = (event, isCheckout) => {
73
+ const post = applyDataUrlGuard(event, defaults.dataUrlMaxBytes);
74
+ guardedEmit(post, isCheckout);
75
+ };
76
+ // Merge — caller wins on every key that's explicitly set.
77
+ const merged = {
78
+ mousemoveWait: defaults.mousemoveWait,
79
+ sampling: { ...defaults.sampling },
80
+ inlineImages: defaults.inlineImages,
81
+ collectFonts: defaults.collectFonts,
82
+ recordCanvas: defaults.recordCanvas,
83
+ checkoutEveryNms: defaults.checkoutEveryMs,
84
+ ...recordOpts,
85
+ // emit is always the composed wrapper; the caller's emit has been captured
86
+ // by `callerEmit` above.
87
+ emit: composedEmit,
88
+ };
89
+ // `sampling` is a nested object — re-merge so caller-provided keys win.
90
+ if (recordOpts.sampling !== undefined) {
91
+ merged.sampling = { ...defaults.sampling, ...recordOpts.sampling };
92
+ }
93
+ return merged;
94
+ }
95
+ function noop() {
96
+ /* intentionally empty — default onWarn / onLimit */
97
+ }
98
+ function noopEmit(_event, _isCheckout) {
99
+ /* intentionally empty — fallback when caller didn't provide an emit */
100
+ }
101
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/throttling/apply.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,uDAAuD;AACvD,EAAE;AACF,6EAA6E;AAC7E,uEAAuE;AACvE,4EAA4E;AAC5E,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,0EAA0E;AAC1E,2BAA2B;AAC3B,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,0EAA0E;AAC1E,4EAA4E;AAC5E,gBAAgB;AAGhB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAEL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,UAAU,CAAC;AA4BlB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,mBAAmB,CACjC,UAAwC,EACxC,UAAsC,EAAE;IAExC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,kBAAkB,CAAC;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC;IAEtC,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,IAAI,QAAQ,CAAC;IAE/C,iEAAiE;IACjE,2DAA2D;IAC3D,0EAA0E;IAC1E,yEAAyE;IACzE,MAAM,aAAa,GAAuB;QACxC,UAAU,EAAE,QAAQ,CAAC,kBAAkB;QACvC,SAAS,EAAE,QAAQ,CAAC,aAAa;QACjC,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,MAAM;QACjB,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvE,CAAC;IAEF,MAAM,WAAW,GAAG,kBAAkB,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;QAC3D,MAAM,IAAI,GAAG,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAC9E,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO;QAC1B,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC/B,CAAC,EAAE,aAAa,CAAC,CAAC;IAElB,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAE,UAAoB,EAAQ,EAAE;QACxE,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;QAChE,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAChC,CAAC,CAAC;IAEF,0DAA0D;IAC1D,MAAM,MAAM,GAAiC;QAC3C,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,QAAQ,EAAE,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE;QAClC,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,gBAAgB,EAAE,QAAQ,CAAC,eAAe;QAC1C,GAAG,UAAU;QACb,2EAA2E;QAC3E,yBAAyB;QACzB,IAAI,EAAE,YAAY;KACnB,CAAC;IAEF,wEAAwE;IACxE,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,CAAC,QAAQ,GAAG,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;IACrE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,IAAI;IACX,oDAAoD;AACtD,CAAC;AAED,SAAS,QAAQ,CAAC,MAAqB,EAAE,WAAqB;IAC5D,uEAAuE;AACzE,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Default throttling configuration for the substrate.
3
+ *
4
+ * The first six properties land directly on rrweb's `recordOptions`; the
5
+ * remaining five are interpreted by `applyLargeDomGuards`. Values match the
6
+ * shared-preamble §2 numbers verbatim — tune only on the back of real-world
7
+ * session data.
8
+ */
9
+ export declare const LARGE_DOM_DEFAULTS: Readonly<{
10
+ /** Throttle window for mousemove sampling, in milliseconds. */
11
+ mousemoveWait: 50;
12
+ /**
13
+ * Frozen rrweb sampling strategy. `scroll: 100` throttles scroll events;
14
+ * `input: 'last'` only emits the final input value rather than every
15
+ * keystroke (mirrors PostHog's session-replay default).
16
+ */
17
+ sampling: Readonly<{
18
+ scroll: 100;
19
+ input: "last";
20
+ }>;
21
+ /** Disable base64-inlined images — too expensive on rich pages. */
22
+ inlineImages: false;
23
+ /** Disable font sniffing — produces enormous events on font-heavy sites. */
24
+ collectFonts: false;
25
+ /** Disable canvas recording — canvas streams alone can dwarf a session. */
26
+ recordCanvas: false;
27
+ /**
28
+ * Hard mutation cap (cumulative across the recording). When exceeded,
29
+ * `applyLargeDomGuards` stops forwarding events and invokes the consumer's
30
+ * `onLimit` callback (the consumer can then call rrweb's teardown).
31
+ */
32
+ mutationLimit: 10000;
33
+ /**
34
+ * Per-batch soft warning threshold. When a single mutation batch exceeds
35
+ * this, the guard emits one `tracelane.mutation.warn` custom event per
36
+ * batch — never spammed.
37
+ */
38
+ mutationSoftWarnAt: 750;
39
+ /**
40
+ * Maximum size for a single `data:` URL value (in `src`/`href` attributes).
41
+ * Larger values are replaced with the SVG placeholder declared in
42
+ * `guards.ts`. 5 MB matches PostHog's session-replay tuning.
43
+ */
44
+ dataUrlMaxBytes: number;
45
+ /**
46
+ * Maximum JSON-stringified size for a single event. Anything larger is
47
+ * dropped (replaced with a `tracelane.event.dropped` breadcrumb) — we
48
+ * don't try to truncate inside an event because the result is rarely
49
+ * replayable.
50
+ */
51
+ singleEventMaxBytes: number;
52
+ /**
53
+ * Buffer roll-over cadence in milliseconds. rrweb re-emits a full
54
+ * snapshot on this interval. 30s avoids the documented PostHog
55
+ * single-page-app missing-recording bug.
56
+ */
57
+ checkoutEveryMs: 30000;
58
+ }>;
59
+ export type LargeDomDefaults = typeof LARGE_DOM_DEFAULTS;
60
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/throttling/defaults.ts"],"names":[],"mappings":"AAuBA;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB;IAC7B,+DAA+D;;IAG/D;;;;OAIG;;;;;IAMH,mEAAmE;;IAGnE,4EAA4E;;IAG5E,2EAA2E;;IAG3E;;;;OAIG;;IAGH;;;;OAIG;;IAGH;;;;OAIG;;IAGH;;;;;OAKG;;IAGH;;;;OAIG;;EAEH,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,OAAO,kBAAkB,CAAC"}
@@ -0,0 +1,81 @@
1
+ // Large-DOM throttling defaults — Task 1.4.
2
+ //
3
+ // The first six values (mousemoveWait / sampling.scroll / sampling.input /
4
+ // inlineImages / collectFonts / recordCanvas) are pass-through rrweb config
5
+ // inherited from the PostHog fork's session-replay tuning. They prevent
6
+ // recordings from exploding on heavy SPAs.
7
+ //
8
+ // The last five values are tracelane-specific guard thresholds applied via
9
+ // `applyLargeDomGuards`:
10
+ // - mutationLimit / mutationSoftWarnAt — Sentry-parity mutation guard
11
+ // - dataUrlMaxBytes — PostHog-parity data-URL guard
12
+ // - singleEventMaxBytes — Kafka-class ingest realism cap
13
+ // - checkoutEveryMs — re-snapshot cadence to dodge the
14
+ // documented PostHog SPA
15
+ // missing-recording bug
16
+ //
17
+ // All values are frozen at module load so neither the substrate nor consumers
18
+ // can mutate them at runtime; consumers needing different thresholds pass a
19
+ // fresh `defaults` object into `applyLargeDomGuards`.
20
+ //
21
+ // See shared-preamble §2 ("Large-DOM throttling defaults") and ADR-0002 for
22
+ // the rationale and source links.
23
+ /**
24
+ * Default throttling configuration for the substrate.
25
+ *
26
+ * The first six properties land directly on rrweb's `recordOptions`; the
27
+ * remaining five are interpreted by `applyLargeDomGuards`. Values match the
28
+ * shared-preamble §2 numbers verbatim — tune only on the back of real-world
29
+ * session data.
30
+ */
31
+ export const LARGE_DOM_DEFAULTS = Object.freeze({
32
+ /** Throttle window for mousemove sampling, in milliseconds. */
33
+ mousemoveWait: 50,
34
+ /**
35
+ * Frozen rrweb sampling strategy. `scroll: 100` throttles scroll events;
36
+ * `input: 'last'` only emits the final input value rather than every
37
+ * keystroke (mirrors PostHog's session-replay default).
38
+ */
39
+ sampling: Object.freeze({
40
+ scroll: 100,
41
+ input: 'last',
42
+ }),
43
+ /** Disable base64-inlined images — too expensive on rich pages. */
44
+ inlineImages: false,
45
+ /** Disable font sniffing — produces enormous events on font-heavy sites. */
46
+ collectFonts: false,
47
+ /** Disable canvas recording — canvas streams alone can dwarf a session. */
48
+ recordCanvas: false,
49
+ /**
50
+ * Hard mutation cap (cumulative across the recording). When exceeded,
51
+ * `applyLargeDomGuards` stops forwarding events and invokes the consumer's
52
+ * `onLimit` callback (the consumer can then call rrweb's teardown).
53
+ */
54
+ mutationLimit: 10000,
55
+ /**
56
+ * Per-batch soft warning threshold. When a single mutation batch exceeds
57
+ * this, the guard emits one `tracelane.mutation.warn` custom event per
58
+ * batch — never spammed.
59
+ */
60
+ mutationSoftWarnAt: 750,
61
+ /**
62
+ * Maximum size for a single `data:` URL value (in `src`/`href` attributes).
63
+ * Larger values are replaced with the SVG placeholder declared in
64
+ * `guards.ts`. 5 MB matches PostHog's session-replay tuning.
65
+ */
66
+ dataUrlMaxBytes: 5 * 1024 * 1024, // 5 MB
67
+ /**
68
+ * Maximum JSON-stringified size for a single event. Anything larger is
69
+ * dropped (replaced with a `tracelane.event.dropped` breadcrumb) — we
70
+ * don't try to truncate inside an event because the result is rarely
71
+ * replayable.
72
+ */
73
+ singleEventMaxBytes: 1024 * 1024, // 1 MB
74
+ /**
75
+ * Buffer roll-over cadence in milliseconds. rrweb re-emits a full
76
+ * snapshot on this interval. 30s avoids the documented PostHog
77
+ * single-page-app missing-recording bug.
78
+ */
79
+ checkoutEveryMs: 30_000,
80
+ });
81
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/throttling/defaults.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,wEAAwE;AACxE,2CAA2C;AAC3C,EAAE;AACF,2EAA2E;AAC3E,yBAAyB;AACzB,wEAAwE;AACxE,yEAAyE;AACzE,0EAA0E;AAC1E,4EAA4E;AAC5E,kEAAkE;AAClE,iEAAiE;AACjE,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,sDAAsD;AACtD,EAAE;AACF,4EAA4E;AAC5E,kCAAkC;AAElC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9C,+DAA+D;IAC/D,aAAa,EAAE,EAAE;IAEjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC;QACtB,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,MAAe;KACvB,CAAC;IAEF,mEAAmE;IACnE,YAAY,EAAE,KAAK;IAEnB,4EAA4E;IAC5E,YAAY,EAAE,KAAK;IAEnB,2EAA2E;IAC3E,YAAY,EAAE,KAAK;IAEnB;;;;OAIG;IACH,aAAa,EAAE,KAAK;IAEpB;;;;OAIG;IACH,kBAAkB,EAAE,GAAG;IAEvB;;;;OAIG;IACH,eAAe,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;IAEzC;;;;;OAKG;IACH,mBAAmB,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO;IAEzC;;;;OAIG;IACH,eAAe,EAAE,MAAM;CACxB,CAAC,CAAC"}
@@ -0,0 +1,69 @@
1
+ import type { customEvent, eventWithTime } from '../rrweb';
2
+ /**
3
+ * 1×1 transparent SVG carrying the text marker `CUBENEST-DATA-URL-OVERSIZE`.
4
+ * Base64-encoded so the resulting `data:image/svg+xml;base64,...` URL is
5
+ * compact and replays without parse warnings in modern browsers.
6
+ *
7
+ * Source SVG (pre-base64):
8
+ * <svg xmlns="http://www.w3.org/2000/svg" width="1" height="1">
9
+ * <text>CUBENEST-DATA-URL-OVERSIZE</text>
10
+ * </svg>
11
+ *
12
+ * Substituted by `applyDataUrlGuard` when a data: URL exceeds the configured
13
+ * `dataUrlMaxBytes`. Kept here as a frozen constant so test fixtures and
14
+ * downstream tooling can identify oversize hits by exact-match.
15
+ */
16
+ export declare const DATA_URL_PLACEHOLDER = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxIiBoZWlnaHQ9IjEiPjx0ZXh0PkNVQkVORVNULURBVEEtVVJMLU9WRVJTSVpFPC90ZXh0Pjwvc3ZnPg==";
17
+ /**
18
+ * Replaces oversized data: URLs in either:
19
+ * - a FullSnapshot event's tree (`data.node`), or
20
+ * - an IncrementalSnapshot.Mutation event's `adds` array (each `node`).
21
+ *
22
+ * Non-snapshot events are returned unchanged. Small data URLs and non-data
23
+ * URLs are preserved verbatim. The original event is never mutated.
24
+ */
25
+ export declare function applyDataUrlGuard(event: eventWithTime, maxBytes: number): eventWithTime;
26
+ /**
27
+ * Drops events whose JSON-stringified size exceeds `maxBytes`.
28
+ *
29
+ * When dropping, the guard emits a sibling `tracelane.event.dropped` custom
30
+ * event via `onDrop` (so the consumer can forward it). The dropped breadcrumb
31
+ * carries `{ type, ts, size }` — enough for postmortem reasoning without
32
+ * leaking the dropped event's payload. Returns `null` when the input is
33
+ * dropped, otherwise returns the input unchanged.
34
+ *
35
+ * Size is measured via `JSON.stringify().length` (UTF-16 code units), which
36
+ * is a close-enough proxy for transport bytes at this layer.
37
+ */
38
+ export declare function applyEventSizeGuard(event: eventWithTime, maxBytes: number, onDrop: (breadcrumb: customEvent<{
39
+ type: number;
40
+ ts: number;
41
+ size: number;
42
+ }> & {
43
+ timestamp: number;
44
+ }) => void): eventWithTime | null;
45
+ /**
46
+ * Hooks supplied to `applyMutationGuard`. The guard fires `onWarn` at most
47
+ * once per batch (when batch count > soft threshold), and `onLimit` at most
48
+ * once per recording (when cumulative count > hard limit). After `onLimit`,
49
+ * the wrapped emit is a no-op — consumers should call rrweb's teardown from
50
+ * `onLimit` to truly stop the recorder.
51
+ */
52
+ export interface MutationGuardHooks {
53
+ softWarnAt: number;
54
+ hardLimit: number;
55
+ emitWarn: (event: customEvent & {
56
+ timestamp: number;
57
+ }) => void;
58
+ emitLimit: (event: customEvent & {
59
+ timestamp: number;
60
+ }) => void;
61
+ onLimit?: () => void;
62
+ }
63
+ /**
64
+ * Wraps an `emit` callback with the cumulative + per-batch mutation counters.
65
+ * Returns a new emit function with the same signature; the wrapper is
66
+ * stateful (closure-captured counters).
67
+ */
68
+ export declare function applyMutationGuard(emit: (event: eventWithTime, isCheckout?: boolean) => void, hooks: MutationGuardHooks): (event: eventWithTime, isCheckout?: boolean) => void;
69
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/throttling/guards.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAM3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,+KAC6I,CAAC;AAsD/K;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CA8BvF;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,CACN,UAAU,EAAE,WAAW,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB,KACE,IAAI,GACR,aAAa,GAAG,IAAI,CA4BtB;AA4BD;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/D,SAAS,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE,OAAO,KAAK,IAAI,EAC1D,KAAK,EAAE,kBAAkB,GACxB,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE,OAAO,KAAK,IAAI,CA0CtD"}
@@ -0,0 +1,212 @@
1
+ // Guard implementations — Task 1.4.
2
+ //
3
+ // Three pure-ish guards, applied in this order by `applyLargeDomGuards`:
4
+ //
5
+ // 1. `applyDataUrlGuard` — substitutes oversized data:URL attributes
6
+ // 2. `applyEventSizeGuard` — drops events whose JSON payload exceeds the
7
+ // configured cap
8
+ // 3. `applyMutationGuard` — stateful counter wrapping the emit callback;
9
+ // warns above the soft threshold, halts above
10
+ // the hard limit
11
+ //
12
+ // Guards 1 and 2 are pure transforms (return a new event or null). Guard 3
13
+ // is a higher-order function that returns a wrapped emitter — the only
14
+ // stateful guard, because per-batch + cumulative counters need persistence
15
+ // across calls.
16
+ //
17
+ // None of the guards mutate their input events; they return new objects
18
+ // (shallow + relevant nested clone) so the caller's references stay clean.
19
+ import { EventType, IncrementalSource } from '../rrweb';
20
+ // ────────────────────────────────────────────────────────────────────────────
21
+ // Data-URL placeholder
22
+ // ────────────────────────────────────────────────────────────────────────────
23
+ /**
24
+ * 1×1 transparent SVG carrying the text marker `CUBENEST-DATA-URL-OVERSIZE`.
25
+ * Base64-encoded so the resulting `data:image/svg+xml;base64,...` URL is
26
+ * compact and replays without parse warnings in modern browsers.
27
+ *
28
+ * Source SVG (pre-base64):
29
+ * <svg xmlns="http://www.w3.org/2000/svg" width="1" height="1">
30
+ * <text>CUBENEST-DATA-URL-OVERSIZE</text>
31
+ * </svg>
32
+ *
33
+ * Substituted by `applyDataUrlGuard` when a data: URL exceeds the configured
34
+ * `dataUrlMaxBytes`. Kept here as a frozen constant so test fixtures and
35
+ * downstream tooling can identify oversize hits by exact-match.
36
+ */
37
+ export const DATA_URL_PLACEHOLDER = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxIiBoZWlnaHQ9IjEiPjx0ZXh0PkNVQkVORVNULURBVEEtVVJMLU9WRVJTSVpFPC90ZXh0Pjwvc3ZnPg==';
38
+ const DATA_URL_PREFIX = /^data:/;
39
+ function isObject(v) {
40
+ return typeof v === 'object' && v !== null;
41
+ }
42
+ /**
43
+ * Walks a serialized node and its `childNodes` recursively, replacing any
44
+ * `src`/`href` attribute whose value is a data: URL longer than `maxBytes`
45
+ * with the SVG placeholder. Returns a deeply-cloned node — input is not
46
+ * mutated.
47
+ */
48
+ function walkAndGuardNode(node, maxBytes) {
49
+ const clone = { ...node };
50
+ if (isObject(node.attributes)) {
51
+ const attrs = { ...node.attributes };
52
+ for (const key of ['src', 'href']) {
53
+ const value = attrs[key];
54
+ if (typeof value === 'string' && DATA_URL_PREFIX.test(value) && value.length > maxBytes) {
55
+ attrs[key] = DATA_URL_PLACEHOLDER;
56
+ }
57
+ }
58
+ clone.attributes = attrs;
59
+ }
60
+ if (Array.isArray(node.childNodes)) {
61
+ clone.childNodes = node.childNodes.map((child) => isObject(child) ? walkAndGuardNode(child, maxBytes) : child);
62
+ }
63
+ return clone;
64
+ }
65
+ // ────────────────────────────────────────────────────────────────────────────
66
+ // Data-URL guard
67
+ // ────────────────────────────────────────────────────────────────────────────
68
+ /**
69
+ * Replaces oversized data: URLs in either:
70
+ * - a FullSnapshot event's tree (`data.node`), or
71
+ * - an IncrementalSnapshot.Mutation event's `adds` array (each `node`).
72
+ *
73
+ * Non-snapshot events are returned unchanged. Small data URLs and non-data
74
+ * URLs are preserved verbatim. The original event is never mutated.
75
+ */
76
+ export function applyDataUrlGuard(event, maxBytes) {
77
+ if (event.type === EventType.FullSnapshot) {
78
+ const data = event.data;
79
+ if (!isObject(data) || !isObject(data.node))
80
+ return event;
81
+ return {
82
+ ...event,
83
+ data: {
84
+ ...data,
85
+ node: walkAndGuardNode(data.node, maxBytes),
86
+ },
87
+ };
88
+ }
89
+ if (event.type === EventType.IncrementalSnapshot) {
90
+ const data = event.data;
91
+ if (!isObject(data) || data.source !== IncrementalSource.Mutation)
92
+ return event;
93
+ if (!Array.isArray(data.adds) || data.adds.length === 0)
94
+ return event;
95
+ const adds = data.adds.map((entry) => {
96
+ if (!isObject(entry) || !isObject(entry.node))
97
+ return entry;
98
+ return { ...entry, node: walkAndGuardNode(entry.node, maxBytes) };
99
+ });
100
+ return {
101
+ ...event,
102
+ data: { ...data, adds },
103
+ };
104
+ }
105
+ return event;
106
+ }
107
+ // ────────────────────────────────────────────────────────────────────────────
108
+ // Event-size guard
109
+ // ────────────────────────────────────────────────────────────────────────────
110
+ /**
111
+ * Drops events whose JSON-stringified size exceeds `maxBytes`.
112
+ *
113
+ * When dropping, the guard emits a sibling `tracelane.event.dropped` custom
114
+ * event via `onDrop` (so the consumer can forward it). The dropped breadcrumb
115
+ * carries `{ type, ts, size }` — enough for postmortem reasoning without
116
+ * leaking the dropped event's payload. Returns `null` when the input is
117
+ * dropped, otherwise returns the input unchanged.
118
+ *
119
+ * Size is measured via `JSON.stringify().length` (UTF-16 code units), which
120
+ * is a close-enough proxy for transport bytes at this layer.
121
+ */
122
+ export function applyEventSizeGuard(event, maxBytes, onDrop) {
123
+ let serialized;
124
+ try {
125
+ serialized = JSON.stringify(event);
126
+ }
127
+ catch {
128
+ // Circular reference or BigInt — defensively drop. Same breadcrumb shape.
129
+ onDrop({
130
+ type: EventType.Custom,
131
+ data: {
132
+ tag: 'tracelane.event.dropped',
133
+ payload: { type: event.type, ts: event.timestamp, size: -1 },
134
+ },
135
+ timestamp: event.timestamp,
136
+ });
137
+ return null;
138
+ }
139
+ if (serialized.length <= maxBytes)
140
+ return event;
141
+ onDrop({
142
+ type: EventType.Custom,
143
+ data: {
144
+ tag: 'tracelane.event.dropped',
145
+ payload: { type: event.type, ts: event.timestamp, size: serialized.length },
146
+ },
147
+ timestamp: event.timestamp,
148
+ });
149
+ return null;
150
+ }
151
+ // ────────────────────────────────────────────────────────────────────────────
152
+ // Mutation guard
153
+ // ────────────────────────────────────────────────────────────────────────────
154
+ /**
155
+ * Counts the mutations in an IncrementalSnapshot.Mutation batch. Sums
156
+ * texts + attributes + removes + adds. Non-mutation events return 0.
157
+ */
158
+ function countMutationsInEvent(event) {
159
+ if (event.type !== EventType.IncrementalSnapshot)
160
+ return 0;
161
+ const data = event.data;
162
+ if (!isObject(data) || data.source !== IncrementalSource.Mutation)
163
+ return 0;
164
+ return ((Array.isArray(data.texts) ? data.texts.length : 0) +
165
+ (Array.isArray(data.attributes) ? data.attributes.length : 0) +
166
+ (Array.isArray(data.removes) ? data.removes.length : 0) +
167
+ (Array.isArray(data.adds) ? data.adds.length : 0));
168
+ }
169
+ /**
170
+ * Wraps an `emit` callback with the cumulative + per-batch mutation counters.
171
+ * Returns a new emit function with the same signature; the wrapper is
172
+ * stateful (closure-captured counters).
173
+ */
174
+ export function applyMutationGuard(emit, hooks) {
175
+ let cumulative = 0;
176
+ let limitReached = false;
177
+ return (event, isCheckout) => {
178
+ if (limitReached)
179
+ return;
180
+ const batchCount = countMutationsInEvent(event);
181
+ if (batchCount > hooks.softWarnAt) {
182
+ const warn = {
183
+ type: EventType.Custom,
184
+ data: {
185
+ tag: 'tracelane.mutation.warn',
186
+ payload: { count: batchCount, batchTs: event.timestamp },
187
+ },
188
+ timestamp: event.timestamp,
189
+ };
190
+ hooks.emitWarn(warn);
191
+ }
192
+ cumulative += batchCount;
193
+ if (cumulative > hooks.hardLimit) {
194
+ limitReached = true;
195
+ const limitEvent = {
196
+ type: EventType.Custom,
197
+ data: {
198
+ tag: 'tracelane.mutation.limit',
199
+ payload: { totalCount: cumulative },
200
+ },
201
+ timestamp: event.timestamp,
202
+ };
203
+ hooks.emitLimit(limitEvent);
204
+ hooks.onLimit?.();
205
+ // Drop the offending event itself — the limit breadcrumb is the final
206
+ // signal forwarded for this recording.
207
+ return;
208
+ }
209
+ emit(event, isCheckout);
210
+ };
211
+ }
212
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/throttling/guards.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { LARGE_DOM_DEFAULTS } from './defaults';
2
+ export type { LargeDomDefaults } from './defaults';
3
+ export { applyLargeDomGuards } from './apply';
4
+ export type { ApplyLargeDomGuardsOptions } from './apply';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/throttling/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC9C,YAAY,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,11 @@
1
+ // Public barrel for the throttling module.
2
+ //
3
+ // Locked surface per IMPLEMENTATION_PLAN.md Public API contract
4
+ // (lines 695-696): the `LARGE_DOM_DEFAULTS` constant plus the
5
+ // `applyLargeDomGuards` function. The guard implementations
6
+ // (`applyDataUrlGuard`, `applyEventSizeGuard`, `applyMutationGuard`) and the
7
+ // SVG placeholder constant stay internal — they're composed by
8
+ // `applyLargeDomGuards` and not intended for direct consumption.
9
+ export { LARGE_DOM_DEFAULTS } from './defaults';
10
+ export { applyLargeDomGuards } from './apply';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/throttling/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,gEAAgE;AAChE,8DAA8D;AAC9D,4DAA4D;AAC5D,6EAA6E;AAC7E,+DAA+D;AAC/D,iEAAiE;AAEjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@cubenest/rrweb-core",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Shared rrweb-based capture substrate for tracelane and peek.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" }
11
+ },
12
+ "files": ["dist", "NOTICE", "README.md"],
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.json",
15
+ "typecheck": "tsc -p tsconfig.json --noEmit",
16
+ "test": "vitest run --passWithNoTests"
17
+ },
18
+ "dependencies": {
19
+ "@posthog/rrweb": "0.0.34",
20
+ "@posthog/rrweb-types": "0.0.24",
21
+ "@rrweb/rrweb-plugin-console-record": "2.0.0-alpha.20",
22
+ "fflate": "^0.8.2"
23
+ },
24
+ "devDependencies": {
25
+ "jsdom": "^25.0.1",
26
+ "fake-indexeddb": "^6.0.0"
27
+ },
28
+ "publishConfig": { "access": "public", "provenance": false },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/Cubenest/rrweb-stack.git",
32
+ "directory": "packages/rrweb-core"
33
+ },
34
+ "homepage": "https://github.com/Cubenest/rrweb-stack/tree/main/packages/rrweb-core#readme"
35
+ }