@amplitude/session-replay-browser 1.50.4 → 1.51.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.
Files changed (103) hide show
  1. package/README.md +15 -0
  2. package/lib/cjs/config/joined-config.d.ts.map +1 -1
  3. package/lib/cjs/config/joined-config.js +6 -25
  4. package/lib/cjs/config/joined-config.js.map +1 -1
  5. package/lib/cjs/config/types.d.ts +2 -25
  6. package/lib/cjs/config/types.d.ts.map +1 -1
  7. package/lib/cjs/config/types.js +0 -2
  8. package/lib/cjs/config/types.js.map +1 -1
  9. package/lib/cjs/events/base-events-store.d.ts +8 -5
  10. package/lib/cjs/events/base-events-store.d.ts.map +1 -1
  11. package/lib/cjs/events/base-events-store.js +51 -55
  12. package/lib/cjs/events/base-events-store.js.map +1 -1
  13. package/lib/cjs/events/event-compressor.d.ts.map +1 -1
  14. package/lib/cjs/events/event-compressor.js +4 -2
  15. package/lib/cjs/events/event-compressor.js.map +1 -1
  16. package/lib/cjs/events/events-idb-store.d.ts.map +1 -1
  17. package/lib/cjs/events/events-idb-store.js +23 -8
  18. package/lib/cjs/events/events-idb-store.js.map +1 -1
  19. package/lib/cjs/events/events-manager.d.ts.map +1 -1
  20. package/lib/cjs/events/events-manager.js +18 -6
  21. package/lib/cjs/events/events-manager.js.map +1 -1
  22. package/lib/cjs/helpers.d.ts +1 -16
  23. package/lib/cjs/helpers.d.ts.map +1 -1
  24. package/lib/cjs/helpers.js +8 -166
  25. package/lib/cjs/helpers.js.map +1 -1
  26. package/lib/cjs/observers.d.ts.map +1 -1
  27. package/lib/cjs/observers.js +2 -22
  28. package/lib/cjs/observers.js.map +1 -1
  29. package/lib/cjs/session-replay.d.ts.map +1 -1
  30. package/lib/cjs/session-replay.js +6 -35
  31. package/lib/cjs/session-replay.js.map +1 -1
  32. package/lib/cjs/track-destination.d.ts.map +1 -1
  33. package/lib/cjs/track-destination.js +6 -5
  34. package/lib/cjs/track-destination.js.map +1 -1
  35. package/lib/cjs/utils/utf8-byte-length.d.ts +17 -0
  36. package/lib/cjs/utils/utf8-byte-length.d.ts.map +1 -0
  37. package/lib/cjs/utils/utf8-byte-length.js +104 -0
  38. package/lib/cjs/utils/utf8-byte-length.js.map +1 -0
  39. package/lib/cjs/version.d.ts +1 -1
  40. package/lib/cjs/version.js +1 -1
  41. package/lib/cjs/version.js.map +1 -1
  42. package/lib/cjs/worker/index.js +1 -1
  43. package/lib/esm/config/joined-config.d.ts.map +1 -1
  44. package/lib/esm/config/joined-config.js +6 -25
  45. package/lib/esm/config/joined-config.js.map +1 -1
  46. package/lib/esm/config/types.d.ts +2 -25
  47. package/lib/esm/config/types.d.ts.map +1 -1
  48. package/lib/esm/config/types.js +1 -1
  49. package/lib/esm/config/types.js.map +1 -1
  50. package/lib/esm/events/base-events-store.d.ts +8 -5
  51. package/lib/esm/events/base-events-store.d.ts.map +1 -1
  52. package/lib/esm/events/base-events-store.js +51 -55
  53. package/lib/esm/events/base-events-store.js.map +1 -1
  54. package/lib/esm/events/event-compressor.d.ts.map +1 -1
  55. package/lib/esm/events/event-compressor.js +4 -2
  56. package/lib/esm/events/event-compressor.js.map +1 -1
  57. package/lib/esm/events/events-idb-store.d.ts.map +1 -1
  58. package/lib/esm/events/events-idb-store.js +23 -8
  59. package/lib/esm/events/events-idb-store.js.map +1 -1
  60. package/lib/esm/events/events-manager.d.ts.map +1 -1
  61. package/lib/esm/events/events-manager.js +18 -6
  62. package/lib/esm/events/events-manager.js.map +1 -1
  63. package/lib/esm/helpers.d.ts +1 -16
  64. package/lib/esm/helpers.d.ts.map +1 -1
  65. package/lib/esm/helpers.js +7 -161
  66. package/lib/esm/helpers.js.map +1 -1
  67. package/lib/esm/observers.d.ts.map +1 -1
  68. package/lib/esm/observers.js +2 -22
  69. package/lib/esm/observers.js.map +1 -1
  70. package/lib/esm/session-replay.d.ts.map +1 -1
  71. package/lib/esm/session-replay.js +8 -37
  72. package/lib/esm/session-replay.js.map +1 -1
  73. package/lib/esm/track-destination.d.ts.map +1 -1
  74. package/lib/esm/track-destination.js +6 -5
  75. package/lib/esm/track-destination.js.map +1 -1
  76. package/lib/esm/utils/utf8-byte-length.d.ts +17 -0
  77. package/lib/esm/utils/utf8-byte-length.d.ts.map +1 -0
  78. package/lib/esm/utils/utf8-byte-length.js +97 -0
  79. package/lib/esm/utils/utf8-byte-length.js.map +1 -0
  80. package/lib/esm/version.d.ts +1 -1
  81. package/lib/esm/version.js +1 -1
  82. package/lib/esm/version.js.map +1 -1
  83. package/lib/esm/worker/index.js +1 -1
  84. package/lib/scripts/index-min.js +1 -1
  85. package/lib/scripts/index-min.js.gz +0 -0
  86. package/lib/scripts/index-min.js.map +1 -1
  87. package/lib/scripts/observers-min.js +1 -1
  88. package/lib/scripts/observers-min.js.gz +0 -0
  89. package/lib/scripts/observers-min.js.map +1 -1
  90. package/lib/scripts/session-replay-browser-min.js +1 -1
  91. package/lib/scripts/session-replay-browser-min.js.gz +0 -0
  92. package/lib/scripts/session-replay-browser-min.js.map +1 -1
  93. package/lib/scripts/worker-min.js +1 -1
  94. package/lib/scripts/worker-min.js.gz +0 -0
  95. package/package.json +3 -2
  96. package/lib/cjs/utils/get-input-type.d.ts +0 -9
  97. package/lib/cjs/utils/get-input-type.d.ts.map +0 -1
  98. package/lib/cjs/utils/get-input-type.js +0 -25
  99. package/lib/cjs/utils/get-input-type.js.map +0 -1
  100. package/lib/esm/utils/get-input-type.d.ts +0 -9
  101. package/lib/esm/utils/get-input-type.d.ts.map +0 -1
  102. package/lib/esm/utils/get-input-type.js +0 -20
  103. package/lib/esm/utils/get-input-type.js.map +0 -1
@@ -1,122 +1,8 @@
1
1
  import { __assign, __awaiter, __generator, __values } from "tslib";
2
2
  import { getGlobalScope } from '@amplitude/analytics-core';
3
- import { DEFAULT_MASK_LEVEL } from './config/types';
4
- import { KB_SIZE, MASK_TEXT_CLASS, UNMASK_TEXT_CLASS } from './constants';
5
- import { getInputType } from './utils/get-input-type';
3
+ import { KB_SIZE } from './constants';
4
+ import { globToRegex } from '@amplitude/session-replay-dom-privacy';
6
5
  export { getServerUrl } from './utils/server-url';
7
- /**
8
- * Light: Subset of inputs (sensitive types only — password, hidden, email, tel, cc-*)
9
- * Medium: All inputs (form fields), text is NOT masked
10
- * Conservative: All inputs and all texts
11
- */
12
- var isMaskedForLevel = function (elementType, level, element) {
13
- switch (level) {
14
- case 'light': {
15
- if (elementType !== 'input') {
16
- return false;
17
- }
18
- var inputType = element ? getInputType(element) : '';
19
- /* istanbul ignore if */ // TODO(lew): For some reason it's impossible to test this.
20
- if (!inputType) {
21
- return false;
22
- }
23
- if (['password', 'hidden', 'email', 'tel'].includes(inputType)) {
24
- return true;
25
- }
26
- if (element.autocomplete.startsWith('cc-')) {
27
- return true;
28
- }
29
- return false;
30
- }
31
- case 'medium':
32
- return elementType === 'input';
33
- case 'conservative':
34
- return true;
35
- default:
36
- return isMaskedForLevel(elementType, DEFAULT_MASK_LEVEL, element);
37
- }
38
- };
39
- /**
40
- * Returns the effective mask level for a given URL by checking `urlMaskLevels`
41
- * (first match wins) and falling back to `defaultMaskLevel`.
42
- */
43
- export var getEffectiveMaskLevel = function (url, config) {
44
- var e_1, _a;
45
- var _b;
46
- if (url && config.urlMaskLevels) {
47
- try {
48
- for (var _c = __values(config.urlMaskLevels), _d = _c.next(); !_d.done; _d = _c.next()) {
49
- var rule = _d.value;
50
- if (globToRegex(rule.match).test(url)) {
51
- return rule.maskLevel;
52
- }
53
- }
54
- }
55
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
56
- finally {
57
- try {
58
- if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
59
- }
60
- finally { if (e_1) throw e_1.error; }
61
- }
62
- }
63
- return (_b = config.defaultMaskLevel) !== null && _b !== void 0 ? _b : DEFAULT_MASK_LEVEL;
64
- };
65
- /**
66
- * Checks if the given element set to be masked by rrweb
67
- *
68
- * Priority is:
69
- * 1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking
70
- * 2. Use app defaults
71
- */
72
- export var isMasked = function (elementType, config, element, currentUrl) {
73
- var _a, _b;
74
- if (config === void 0) { config = { defaultMaskLevel: DEFAULT_MASK_LEVEL }; }
75
- if (element) {
76
- // Element or parent is explicitly instrumented in code to mask
77
- if (element.closest('.' + MASK_TEXT_CLASS)) {
78
- return true;
79
- }
80
- // Config has override for mask
81
- var shouldMask = ((_a = config.maskSelector) !== null && _a !== void 0 ? _a : []).some(function (selector) { return element.closest(selector); });
82
- if (shouldMask) {
83
- return true;
84
- }
85
- // Code or config has override to unmask
86
- if (element.closest('.' + UNMASK_TEXT_CLASS)) {
87
- return false;
88
- }
89
- // Here we are probably sent an element, but we want to match if they have a
90
- // parent with an unmask selector.
91
- var shouldUnmask = ((_b = config.unmaskSelector) !== null && _b !== void 0 ? _b : []).some(function (selector) { return element.closest(selector); });
92
- if (shouldUnmask) {
93
- return false;
94
- }
95
- }
96
- return isMaskedForLevel(elementType, getEffectiveMaskLevel(currentUrl, config), element);
97
- };
98
- export var maskFn = function (elementType, config, getCurrentUrl) {
99
- return function (text, element) {
100
- return isMasked(elementType, config, element, getCurrentUrl === null || getCurrentUrl === void 0 ? void 0 : getCurrentUrl()) ? text.replace(/[^\s]/g, '*') : text;
101
- };
102
- };
103
- export var maskAttributeFn = function (config, getCurrentUrl) {
104
- return function (key, value, element) {
105
- var _a;
106
- // Never mask style — rrweb has a separate styleDiff path for attribute mutations
107
- // that reads directly from the DOM, bypassing maskAttributeFn.
108
- if (key === 'style')
109
- return value;
110
- // Short-circuit: only proceed if this attribute is in the allowlist.
111
- if (!((_a = config === null || config === void 0 ? void 0 : config.maskAttributes) !== null && _a !== void 0 ? _a : []).includes(key))
112
- return value;
113
- // Use 'input' for form elements so that `medium` (which masks inputs but not text)
114
- // still masks attributes on inputs/selects/textareas. For non-form elements, use
115
- // 'text' so medium leaves them visible.
116
- var elementType = ['INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) ? 'input' : 'text';
117
- return isMasked(elementType, config, element, getCurrentUrl === null || getCurrentUrl === void 0 ? void 0 : getCurrentUrl()) ? value.replace(/[^\s]/g, '*') : value;
118
- };
119
- };
120
6
  export var getCurrentUrl = function () {
121
7
  var globalScope = getGlobalScope();
122
8
  return (globalScope === null || globalScope === void 0 ? void 0 : globalScope.location) ? globalScope.location.href : '';
@@ -132,46 +18,6 @@ var isValidGlobUrl = function (globUrl) {
132
18
  return false;
133
19
  return true;
134
20
  };
135
- var globRegexCache = new Map();
136
- var globToRegex = function (glob) {
137
- var cached = globRegexCache.get(glob);
138
- if (cached)
139
- return cached;
140
- // Glob → regex conversion. Glob substitution must happen BEFORE regex escaping so that
141
- // the escaper does not corrupt the glob characters (e.g. turning `/**` into `/\*\*`).
142
- // Placeholder tokens use null bytes, which are illegal in HTTP URLs and therefore can
143
- // never collide with real pattern content.
144
- //
145
- // Substitution order (most-specific first):
146
- // trailing /** → (/.*)? — path with or without a trailing slash/subpath
147
- // middle /**/ → /(.*\/)? — zero-or-more path segments (including zero)
148
- // bare ** → .* — graceful fallback for ** not adjacent to /
149
- // single * → .* — any characters (preserves existing behaviour)
150
- // ? → . — single character wildcard
151
- var T_TRAILING = '\x00TRAIL\x00';
152
- var T_MIDDLE = '\x00MID\x00';
153
- var T_DSTAR = '\x00DS\x00';
154
- var T_STAR = '\x00ST\x00';
155
- var T_QUEST = '\x00QU\x00';
156
- var s = glob;
157
- s = s.replace(/\/\*\*$/, T_TRAILING); // trailing /**
158
- s = s.replace(/\/\*\*\//g, T_MIDDLE); // /**/ in the middle
159
- s = s.replace(/\*\*/g, T_DSTAR); // bare ** (e.g. **.example.com)
160
- s = s.replace(/\*/g, T_STAR); // single *
161
- s = s.replace(/\?/g, T_QUEST); // ?
162
- // Escape all remaining regex special characters.
163
- s = s.replace(/[.+^${}()|[\]\\]/g, '\\$&');
164
- // Expand tokens into their regex equivalents.
165
- // Use split/join (not regex) to avoid the no-control-regex lint rule on the token strings.
166
- s = s.split(T_TRAILING).join('(/.*)?'); // /** → optional /anything
167
- s = s.split(T_MIDDLE).join('/(.*\\/)?'); // /**/ → /zero-or-more-segments/
168
- s = s.split(T_DSTAR).join('.*'); // bare ** → .*
169
- s = s.split(T_STAR).join('.*'); // * → .*
170
- s = s.split(T_QUEST).join('.'); // ? → .
171
- var regex = new RegExp("^".concat(s, "$"));
172
- globRegexCache.set(glob, regex);
173
- return regex;
174
- };
175
21
  export var validateUGCFilterRules = function (ugcFilterRules) {
176
22
  // validate ugcFilterRules
177
23
  if (!ugcFilterRules.every(function (rule) { return typeof rule.selector === 'string' && typeof rule.replacement === 'string'; })) {
@@ -183,7 +29,7 @@ export var validateUGCFilterRules = function (ugcFilterRules) {
183
29
  }
184
30
  };
185
31
  export var getPageUrl = function (pageUrl, ugcFilterRules) {
186
- var e_2, _a;
32
+ var e_1, _a;
187
33
  try {
188
34
  // apply ugcFilterRules, order is important, first rule wins
189
35
  for (var ugcFilterRules_1 = __values(ugcFilterRules), ugcFilterRules_1_1 = ugcFilterRules_1.next(); !ugcFilterRules_1_1.done; ugcFilterRules_1_1 = ugcFilterRules_1.next()) {
@@ -194,17 +40,17 @@ export var getPageUrl = function (pageUrl, ugcFilterRules) {
194
40
  }
195
41
  }
196
42
  }
197
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
43
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
198
44
  finally {
199
45
  try {
200
46
  if (ugcFilterRules_1_1 && !ugcFilterRules_1_1.done && (_a = ugcFilterRules_1.return)) _a.call(ugcFilterRules_1);
201
47
  }
202
- finally { if (e_2) throw e_2.error; }
48
+ finally { if (e_1) throw e_1.error; }
203
49
  }
204
50
  return pageUrl;
205
51
  };
206
52
  export var getStorageSize = function () { return __awaiter(void 0, void 0, void 0, function () {
207
- var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota, e_3;
53
+ var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota, e_2;
208
54
  return __generator(this, function (_b) {
209
55
  switch (_b.label) {
210
56
  case 0:
@@ -219,7 +65,7 @@ export var getStorageSize = function () { return __awaiter(void 0, void 0, void
219
65
  return [2 /*return*/, { totalStorageSize: totalStorageSize, percentOfQuota: percentOfQuota, usageDetails: JSON.stringify(usageDetails) }];
220
66
  case 2: return [3 /*break*/, 4];
221
67
  case 3:
222
- e_3 = _b.sent();
68
+ e_2 = _b.sent();
223
69
  return [3 /*break*/, 4];
224
70
  case 4: return [2 /*return*/, { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' }];
225
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\nimport { DEFAULT_MASK_LEVEL, MaskLevel, PrivacyConfig, SessionReplayJoinedConfig, UGCFilterRule } from './config/types';\nimport { KB_SIZE, MASK_TEXT_CLASS, UNMASK_TEXT_CLASS } from './constants';\nimport { StorageData } from './typings/session-replay';\nimport { getInputType } from './utils/get-input-type';\nexport { getServerUrl } from './utils/server-url';\n\ntype ChromeStorageEstimate = {\n quota?: number;\n usage?: number;\n usageDetails?: { [key: string]: number };\n};\n\n/**\n * Light: Subset of inputs (sensitive types only — password, hidden, email, tel, cc-*)\n * Medium: All inputs (form fields), text is NOT masked\n * Conservative: All inputs and all texts\n */\nconst isMaskedForLevel = (elementType: 'input' | 'text', level: MaskLevel, element: HTMLElement | null): boolean => {\n switch (level) {\n case 'light': {\n if (elementType !== 'input') {\n return false;\n }\n\n const inputType = element ? getInputType(element) : '';\n /* istanbul ignore if */ // TODO(lew): For some reason it's impossible to test this.\n if (!inputType) {\n return false;\n }\n\n if (['password', 'hidden', 'email', 'tel'].includes(inputType)) {\n return true;\n }\n\n if ((element as HTMLInputElement).autocomplete.startsWith('cc-')) {\n return true;\n }\n\n return false;\n }\n case 'medium':\n return elementType === 'input';\n case 'conservative':\n return true;\n default:\n return isMaskedForLevel(elementType, DEFAULT_MASK_LEVEL, element);\n }\n};\n\n/**\n * Returns the effective mask level for a given URL by checking `urlMaskLevels`\n * (first match wins) and falling back to `defaultMaskLevel`.\n */\nexport const getEffectiveMaskLevel = (url: string | undefined, config: PrivacyConfig): MaskLevel => {\n if (url && config.urlMaskLevels) {\n for (const rule of config.urlMaskLevels) {\n if (globToRegex(rule.match).test(url)) {\n return rule.maskLevel;\n }\n }\n }\n return config.defaultMaskLevel ?? DEFAULT_MASK_LEVEL;\n};\n\n/**\n * Checks if the given element set to be masked by rrweb\n *\n * Priority is:\n * 1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking\n * 2. Use app defaults\n */\nexport const isMasked = (\n elementType: 'input' | 'text',\n config: PrivacyConfig = { defaultMaskLevel: DEFAULT_MASK_LEVEL },\n element: HTMLElement | null,\n currentUrl?: string,\n): boolean => {\n if (element) {\n // Element or parent is explicitly instrumented in code to mask\n if (element.closest('.' + MASK_TEXT_CLASS)) {\n return true;\n }\n\n // Config has override for mask\n const shouldMask = (config.maskSelector ?? []).some((selector) => element.closest(selector));\n if (shouldMask) {\n return true;\n }\n\n // Code or config has override to unmask\n if (element.closest('.' + UNMASK_TEXT_CLASS)) {\n return false;\n }\n\n // Here we are probably sent an element, but we want to match if they have a\n // parent with an unmask selector.\n const shouldUnmask = (config.unmaskSelector ?? []).some((selector) => element.closest(selector));\n if (shouldUnmask) {\n return false;\n }\n }\n\n return isMaskedForLevel(elementType, getEffectiveMaskLevel(currentUrl, config), element);\n};\n\nexport const maskFn =\n (elementType: 'text' | 'input', config?: PrivacyConfig, getCurrentUrl?: () => string) =>\n (text: string, element: HTMLElement | null): string => {\n return isMasked(elementType, config, element, getCurrentUrl?.()) ? text.replace(/[^\\s]/g, '*') : text;\n };\n\nexport const maskAttributeFn = (config?: PrivacyConfig, getCurrentUrl?: () => string) => {\n return (key: string, value: string, element: HTMLElement): string => {\n // Never mask style — rrweb has a separate styleDiff path for attribute mutations\n // that reads directly from the DOM, bypassing maskAttributeFn.\n if (key === 'style') return value;\n\n // Short-circuit: only proceed if this attribute is in the allowlist.\n if (!(config?.maskAttributes ?? []).includes(key)) return value;\n\n // Use 'input' for form elements so that `medium` (which masks inputs but not text)\n // still masks attributes on inputs/selects/textareas. For non-form elements, use\n // 'text' so medium leaves them visible.\n const elementType = ['INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) ? 'input' : 'text';\n return isMasked(elementType, config, element, getCurrentUrl?.()) ? value.replace(/[^\\s]/g, '*') : value;\n };\n};\n\nexport const getCurrentUrl = () => {\n const globalScope = getGlobalScope();\n return globalScope?.location ? globalScope.location.href : '';\n};\n\nexport const generateSessionReplayId = (sessionId: string | number, deviceId: string): string => {\n return `${deviceId}/${sessionId}`;\n};\n\nconst isValidGlobUrl = (globUrl: string): boolean => {\n if (typeof globUrl !== 'string' || globUrl.trim() === '') return false;\n const urlPattern = /^\\/|^https?:\\/\\/[^\\s]+$/;\n if (!urlPattern.test(globUrl)) return false;\n return true;\n};\n\nconst globRegexCache = new Map<string, RegExp>();\n\nconst globToRegex = (glob: string): RegExp => {\n const cached = globRegexCache.get(glob);\n if (cached) return cached;\n\n // Glob → regex conversion. Glob substitution must happen BEFORE regex escaping so that\n // the escaper does not corrupt the glob characters (e.g. turning `/**` into `/\\*\\*`).\n // Placeholder tokens use null bytes, which are illegal in HTTP URLs and therefore can\n // never collide with real pattern content.\n //\n // Substitution order (most-specific first):\n // trailing /** → (/.*)? — path with or without a trailing slash/subpath\n // middle /**/ → /(.*\\/)? — zero-or-more path segments (including zero)\n // bare ** → .* — graceful fallback for ** not adjacent to /\n // single * → .* — any characters (preserves existing behaviour)\n // ? → . — single character wildcard\n const T_TRAILING = '\\x00TRAIL\\x00';\n const T_MIDDLE = '\\x00MID\\x00';\n const T_DSTAR = '\\x00DS\\x00';\n const T_STAR = '\\x00ST\\x00';\n const T_QUEST = '\\x00QU\\x00';\n\n let s = glob;\n s = s.replace(/\\/\\*\\*$/, T_TRAILING); // trailing /**\n s = s.replace(/\\/\\*\\*\\//g, T_MIDDLE); // /**/ in the middle\n s = s.replace(/\\*\\*/g, T_DSTAR); // bare ** (e.g. **.example.com)\n s = s.replace(/\\*/g, T_STAR); // single *\n s = s.replace(/\\?/g, T_QUEST); // ?\n\n // Escape all remaining regex special characters.\n s = s.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Expand tokens into their regex equivalents.\n // Use split/join (not regex) to avoid the no-control-regex lint rule on the token strings.\n s = s.split(T_TRAILING).join('(/.*)?'); // /** → optional /anything\n s = s.split(T_MIDDLE).join('/(.*\\\\/)?'); // /**/ → /zero-or-more-segments/\n s = s.split(T_DSTAR).join('.*'); // bare ** → .*\n s = s.split(T_STAR).join('.*'); // * → .*\n s = s.split(T_QUEST).join('.'); // ? → .\n\n const regex = new RegExp(`^${s}$`);\n globRegexCache.set(glob, regex);\n return regex;\n};\n\nexport const validateUGCFilterRules = (ugcFilterRules: UGCFilterRule[]) => {\n // validate ugcFilterRules\n if (!ugcFilterRules.every((rule) => typeof rule.selector === 'string' && typeof rule.replacement === 'string')) {\n throw new Error('ugcFilterRules must be an array of objects with selector and replacement properties');\n }\n\n // validate ugcFilterRules are valid globs\n if (!ugcFilterRules.every((rule) => isValidGlobUrl(rule.selector))) {\n throw new Error('ugcFilterRules must be an array of objects with valid globs');\n }\n};\n\nexport const getPageUrl = (pageUrl: string, ugcFilterRules: UGCFilterRule[]) => {\n // apply ugcFilterRules, order is important, first rule wins\n for (const rule of ugcFilterRules) {\n const regex = globToRegex(rule.selector);\n\n if (regex.test(pageUrl)) {\n return pageUrl.replace(regex, rule.replacement);\n }\n }\n\n return pageUrl;\n};\n\nexport const getStorageSize = async (): Promise<StorageData> => {\n try {\n const globalScope = getGlobalScope();\n if (globalScope) {\n const { usage, quota, usageDetails }: ChromeStorageEstimate = await globalScope.navigator.storage.estimate();\n const totalStorageSize = usage ? Math.round(usage / KB_SIZE) : 0;\n const percentOfQuota = usage && quota ? Math.round((usage / quota + Number.EPSILON) * 1000) / 1000 : 0;\n return { totalStorageSize, percentOfQuota, usageDetails: JSON.stringify(usageDetails) };\n }\n } catch (e) {\n // swallow\n }\n return { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' };\n};\n\nexport const getDebugConfig = (config: SessionReplayJoinedConfig): SessionReplayJoinedConfig => {\n const debugConfig = {\n ...config,\n };\n const { apiKey } = debugConfig;\n debugConfig.apiKey = `****${apiKey.substring(apiKey.length - 4)}`;\n return debugConfig;\n};\n"]}
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig, UGCFilterRule } from './config/types';\nimport { KB_SIZE } from './constants';\nimport { StorageData } from './typings/session-replay';\nimport { globToRegex } from '@amplitude/session-replay-dom-privacy';\nexport { getServerUrl } from './utils/server-url';\n\ntype ChromeStorageEstimate = {\n quota?: number;\n usage?: number;\n usageDetails?: { [key: string]: number };\n};\n\nexport const getCurrentUrl = () => {\n const globalScope = getGlobalScope();\n return globalScope?.location ? globalScope.location.href : '';\n};\n\nexport const generateSessionReplayId = (sessionId: string | number, deviceId: string): string => {\n return `${deviceId}/${sessionId}`;\n};\n\nconst isValidGlobUrl = (globUrl: string): boolean => {\n if (typeof globUrl !== 'string' || globUrl.trim() === '') return false;\n const urlPattern = /^\\/|^https?:\\/\\/[^\\s]+$/;\n if (!urlPattern.test(globUrl)) return false;\n return true;\n};\n\nexport const validateUGCFilterRules = (ugcFilterRules: UGCFilterRule[]) => {\n // validate ugcFilterRules\n if (!ugcFilterRules.every((rule) => typeof rule.selector === 'string' && typeof rule.replacement === 'string')) {\n throw new Error('ugcFilterRules must be an array of objects with selector and replacement properties');\n }\n\n // validate ugcFilterRules are valid globs\n if (!ugcFilterRules.every((rule) => isValidGlobUrl(rule.selector))) {\n throw new Error('ugcFilterRules must be an array of objects with valid globs');\n }\n};\n\nexport const getPageUrl = (pageUrl: string, ugcFilterRules: UGCFilterRule[]) => {\n // apply ugcFilterRules, order is important, first rule wins\n for (const rule of ugcFilterRules) {\n const regex = globToRegex(rule.selector);\n\n if (regex.test(pageUrl)) {\n return pageUrl.replace(regex, rule.replacement);\n }\n }\n\n return pageUrl;\n};\n\nexport const getStorageSize = async (): Promise<StorageData> => {\n try {\n const globalScope = getGlobalScope();\n if (globalScope) {\n const { usage, quota, usageDetails }: ChromeStorageEstimate = await globalScope.navigator.storage.estimate();\n const totalStorageSize = usage ? Math.round(usage / KB_SIZE) : 0;\n const percentOfQuota = usage && quota ? Math.round((usage / quota + Number.EPSILON) * 1000) / 1000 : 0;\n return { totalStorageSize, percentOfQuota, usageDetails: JSON.stringify(usageDetails) };\n }\n } catch (e) {\n // swallow\n }\n return { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' };\n};\n\nexport const getDebugConfig = (config: SessionReplayJoinedConfig): SessionReplayJoinedConfig => {\n const debugConfig = {\n ...config,\n };\n const { apiKey } = debugConfig;\n debugConfig.apiKey = `****${apiKey.substring(apiKey.length - 4)}`;\n return debugConfig;\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"observers.d.ts","sourceRoot":"","sources":["../../src/observers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,qBAAqB,EAA+C,MAAM,wBAAwB,CAAC;AAEjH,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,WAAW,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAEvF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AAkDD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,aAAa,CAAC,CAAuB;IAC7C,OAAO,CAAC,aAAa,CAAC,CAAgB;IAEtC,KAAK,CAAC,aAAa,EAAE,oBAAoB,EAAE,aAAa,CAAC,EAAE,aAAa;IAMxE,IAAI;IAOJ,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,mBAAmB;IAIhD,OAAO,CAAC,YAAY;CAkGrB"}
1
+ {"version":3,"file":"observers.d.ts","sourceRoot":"","sources":["../../src/observers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,qBAAqB,EAA+C,MAAM,wBAAwB,CAAC;AAGjH,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,WAAW,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAEvF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AA8BD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,aAAa,CAAC,CAAuB;IAC7C,OAAO,CAAC,aAAa,CAAC,CAAgB;IAEtC,KAAK,CAAC,aAAa,EAAE,oBAAoB,EAAE,aAAa,CAAC,EAAE,aAAa;IAMxE,IAAI;IAOJ,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,mBAAmB;IAIhD,OAAO,CAAC,YAAY;CAkGrB"}
@@ -1,6 +1,7 @@
1
1
  import { __awaiter, __generator } from "tslib";
2
2
  import { getGlobalScope } from '@amplitude/analytics-core';
3
3
  import { captureSerializedBody, isBodyCaptureEnabled } from './network-body-capture';
4
+ import { truncateUtf8 } from './utils/utf8-byte-length';
4
5
  var DEFAULT_MAX_BODY_SIZE_BYTES = 10240; // 10KB
5
6
  var BINARY_CONTENT_TYPE_PREFIXES = ['image/', 'audio/', 'video/', 'application/octet-stream', 'font/'];
6
7
  function isBinaryContentType(contentType) {
@@ -26,28 +27,7 @@ function serializeRequestBody(body) {
26
27
  return undefined;
27
28
  }
28
29
  function truncateToByteLimit(str, maxBytes) {
29
- if (new Blob([str]).size <= maxBytes) {
30
- return { value: str, truncated: false };
31
- }
32
- // Binary search for the longest prefix whose UTF-8 byte length fits within maxBytes.
33
- // Cap hi at maxBytes since each UTF-8 character is at least 1 byte, so no more than
34
- // maxBytes characters can ever fit — this avoids large intermediate Blob allocations.
35
- var lo = 0;
36
- var hi = Math.min(str.length, maxBytes);
37
- while (lo < hi) {
38
- var mid = Math.ceil((lo + hi) / 2);
39
- if (new Blob([str.slice(0, mid)]).size <= maxBytes) {
40
- lo = mid;
41
- }
42
- else {
43
- hi = mid - 1;
44
- }
45
- }
46
- // Avoid splitting a surrogate pair: if lo landed after a high surrogate, back up one position
47
- if (lo > 0 && str.charCodeAt(lo - 1) >= 0xd800 && str.charCodeAt(lo - 1) <= 0xdbff) {
48
- lo -= 1;
49
- }
50
- return { value: str.slice(0, lo), truncated: true };
30
+ return truncateUtf8(str, maxBytes);
51
31
  }
52
32
  var NetworkObservers = /** @class */ (function () {
53
33
  function NetworkObservers() {
@@ -1 +1 @@
1
- {"version":3,"file":"observers.js","sourceRoot":"","sources":["../../src/observers.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\n\nimport { type BodyCaptureRuleConfig, captureSerializedBody, isBodyCaptureEnabled } from './network-body-capture';\n\nexport type ResponseBodyStatus = 'captured' | 'truncated' | 'skipped_binary' | 'error';\n\nexport interface NetworkRequestEvent {\n timestamp: number;\n type: 'fetch';\n method: string;\n url: string;\n status?: number;\n duration?: number;\n requestHeaders?: Record<string, string>;\n responseHeaders?: Record<string, string>;\n requestBody?: string;\n responseBody?: string;\n responseBodyStatus?: ResponseBodyStatus;\n error?: {\n name: string;\n message: string;\n };\n}\n\nexport type NetworkEventCallback = (event: NetworkRequestEvent) => void;\n\nexport interface NetworkBodyConfig {\n request?: BodyCaptureRuleConfig;\n response?: BodyCaptureRuleConfig;\n maxBodySizeBytes?: number;\n}\n\nexport interface NetworkConfig {\n enabled: boolean;\n body?: NetworkBodyConfig;\n}\n\nconst DEFAULT_MAX_BODY_SIZE_BYTES = 10240; // 10KB\n\nconst BINARY_CONTENT_TYPE_PREFIXES = ['image/', 'audio/', 'video/', 'application/octet-stream', 'font/'];\n\nfunction isBinaryContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n return BINARY_CONTENT_TYPE_PREFIXES.some((prefix) => contentType.toLowerCase().startsWith(prefix));\n}\n\nfunction serializeRequestBody(body: BodyInit | null | undefined): string | undefined {\n if (body === null || body === undefined) return undefined;\n if (typeof body === 'string') return body;\n if (body instanceof URLSearchParams) return body.toString();\n if (body instanceof FormData) {\n const parts: string[] = [];\n body.forEach((value, key) => {\n parts.push(`${key}=${typeof value === 'string' ? value : '[File]'}`);\n });\n return parts.join('&');\n }\n // Blob, ArrayBuffer, ArrayBufferView, ReadableStream — skip\n return undefined;\n}\n\nfunction truncateToByteLimit(str: string, maxBytes: number): { value: string; truncated: boolean } {\n if (new Blob([str]).size <= maxBytes) {\n return { value: str, truncated: false };\n }\n // Binary search for the longest prefix whose UTF-8 byte length fits within maxBytes.\n // Cap hi at maxBytes since each UTF-8 character is at least 1 byte, so no more than\n // maxBytes characters can ever fit — this avoids large intermediate Blob allocations.\n let lo = 0;\n let hi = Math.min(str.length, maxBytes);\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (new Blob([str.slice(0, mid)]).size <= maxBytes) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n // Avoid splitting a surrogate pair: if lo landed after a high surrogate, back up one position\n if (lo > 0 && str.charCodeAt(lo - 1) >= 0xd800 && str.charCodeAt(lo - 1) <= 0xdbff) {\n lo -= 1;\n }\n return { value: str.slice(0, lo), truncated: true };\n}\n\nexport class NetworkObservers {\n private fetchObserver: (() => void) | null = null;\n private eventCallback?: NetworkEventCallback;\n private networkConfig?: NetworkConfig;\n\n start(eventCallback: NetworkEventCallback, networkConfig?: NetworkConfig) {\n this.eventCallback = eventCallback;\n this.networkConfig = networkConfig;\n this.observeFetch();\n }\n\n stop() {\n this.fetchObserver?.();\n this.fetchObserver = null;\n this.eventCallback = undefined;\n this.networkConfig = undefined;\n }\n\n protected notifyEvent(event: NetworkRequestEvent) {\n this.eventCallback?.(event);\n }\n\n private observeFetch() {\n const globalScope = getGlobalScope();\n if (!globalScope) return;\n\n const originalFetch = globalScope.fetch;\n if (!originalFetch) return;\n\n globalScope.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n const startTime = Date.now();\n const requestEvent: NetworkRequestEvent = {\n timestamp: startTime,\n type: 'fetch',\n method: init?.method || 'GET', // Fetch API defaulted to GET when no method is provided\n url: input.toString(),\n requestHeaders: init?.headers as Record<string, string>,\n };\n\n // Capture request body if configured\n const bodyConfig = this.networkConfig?.body;\n if (bodyConfig && isBodyCaptureEnabled(bodyConfig.request)) {\n const serialized = serializeRequestBody(init?.body);\n if (serialized !== undefined) {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n requestEvent.requestBody = captureSerializedBody(\n serialized,\n bodyConfig.request,\n maxBytes,\n truncateToByteLimit,\n ).value;\n }\n }\n\n try {\n const response = await originalFetch(input, init);\n const endTime = Date.now();\n\n requestEvent.status = response.status;\n requestEvent.duration = endTime - startTime;\n\n // Convert Headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n requestEvent.responseHeaders = headers;\n\n if (bodyConfig && isBodyCaptureEnabled(bodyConfig.response)) {\n const contentType = headers['content-type'] || null;\n if (isBinaryContentType(contentType)) {\n requestEvent.responseBodyStatus = 'skipped_binary';\n this.notifyEvent(requestEvent);\n } else {\n const cloned = response.clone();\n // Read body without blocking the response return to the caller\n cloned.text().then(\n (text) => {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n const { value, truncated } = captureSerializedBody(\n text,\n bodyConfig.response,\n maxBytes,\n truncateToByteLimit,\n );\n requestEvent.responseBody = value;\n requestEvent.responseBodyStatus = truncated ? 'truncated' : 'captured';\n this.notifyEvent(requestEvent);\n },\n () => {\n requestEvent.responseBodyStatus = 'error';\n this.notifyEvent(requestEvent);\n },\n );\n }\n } else {\n this.notifyEvent(requestEvent);\n }\n\n return response;\n } catch (error) {\n const endTime = Date.now();\n requestEvent.duration = endTime - startTime;\n\n // Capture error information\n const typedError = error as Error;\n requestEvent.error = {\n name: typedError.name || 'UnknownError',\n message: typedError.message || 'An unknown error occurred',\n };\n\n this.notifyEvent(requestEvent);\n throw error;\n }\n };\n\n this.fetchObserver = () => {\n globalScope.fetch = originalFetch;\n };\n }\n}\n"]}
1
+ {"version":3,"file":"observers.js","sourceRoot":"","sources":["../../src/observers.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\n\nimport { type BodyCaptureRuleConfig, captureSerializedBody, isBodyCaptureEnabled } from './network-body-capture';\nimport { truncateUtf8 } from './utils/utf8-byte-length';\n\nexport type ResponseBodyStatus = 'captured' | 'truncated' | 'skipped_binary' | 'error';\n\nexport interface NetworkRequestEvent {\n timestamp: number;\n type: 'fetch';\n method: string;\n url: string;\n status?: number;\n duration?: number;\n requestHeaders?: Record<string, string>;\n responseHeaders?: Record<string, string>;\n requestBody?: string;\n responseBody?: string;\n responseBodyStatus?: ResponseBodyStatus;\n error?: {\n name: string;\n message: string;\n };\n}\n\nexport type NetworkEventCallback = (event: NetworkRequestEvent) => void;\n\nexport interface NetworkBodyConfig {\n request?: BodyCaptureRuleConfig;\n response?: BodyCaptureRuleConfig;\n maxBodySizeBytes?: number;\n}\n\nexport interface NetworkConfig {\n enabled: boolean;\n body?: NetworkBodyConfig;\n}\n\nconst DEFAULT_MAX_BODY_SIZE_BYTES = 10240; // 10KB\n\nconst BINARY_CONTENT_TYPE_PREFIXES = ['image/', 'audio/', 'video/', 'application/octet-stream', 'font/'];\n\nfunction isBinaryContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n return BINARY_CONTENT_TYPE_PREFIXES.some((prefix) => contentType.toLowerCase().startsWith(prefix));\n}\n\nfunction serializeRequestBody(body: BodyInit | null | undefined): string | undefined {\n if (body === null || body === undefined) return undefined;\n if (typeof body === 'string') return body;\n if (body instanceof URLSearchParams) return body.toString();\n if (body instanceof FormData) {\n const parts: string[] = [];\n body.forEach((value, key) => {\n parts.push(`${key}=${typeof value === 'string' ? value : '[File]'}`);\n });\n return parts.join('&');\n }\n // Blob, ArrayBuffer, ArrayBufferView, ReadableStream — skip\n return undefined;\n}\n\nfunction truncateToByteLimit(str: string, maxBytes: number): { value: string; truncated: boolean } {\n return truncateUtf8(str, maxBytes);\n}\n\nexport class NetworkObservers {\n private fetchObserver: (() => void) | null = null;\n private eventCallback?: NetworkEventCallback;\n private networkConfig?: NetworkConfig;\n\n start(eventCallback: NetworkEventCallback, networkConfig?: NetworkConfig) {\n this.eventCallback = eventCallback;\n this.networkConfig = networkConfig;\n this.observeFetch();\n }\n\n stop() {\n this.fetchObserver?.();\n this.fetchObserver = null;\n this.eventCallback = undefined;\n this.networkConfig = undefined;\n }\n\n protected notifyEvent(event: NetworkRequestEvent) {\n this.eventCallback?.(event);\n }\n\n private observeFetch() {\n const globalScope = getGlobalScope();\n if (!globalScope) return;\n\n const originalFetch = globalScope.fetch;\n if (!originalFetch) return;\n\n globalScope.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n const startTime = Date.now();\n const requestEvent: NetworkRequestEvent = {\n timestamp: startTime,\n type: 'fetch',\n method: init?.method || 'GET', // Fetch API defaulted to GET when no method is provided\n url: input.toString(),\n requestHeaders: init?.headers as Record<string, string>,\n };\n\n // Capture request body if configured\n const bodyConfig = this.networkConfig?.body;\n if (bodyConfig && isBodyCaptureEnabled(bodyConfig.request)) {\n const serialized = serializeRequestBody(init?.body);\n if (serialized !== undefined) {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n requestEvent.requestBody = captureSerializedBody(\n serialized,\n bodyConfig.request,\n maxBytes,\n truncateToByteLimit,\n ).value;\n }\n }\n\n try {\n const response = await originalFetch(input, init);\n const endTime = Date.now();\n\n requestEvent.status = response.status;\n requestEvent.duration = endTime - startTime;\n\n // Convert Headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n requestEvent.responseHeaders = headers;\n\n if (bodyConfig && isBodyCaptureEnabled(bodyConfig.response)) {\n const contentType = headers['content-type'] || null;\n if (isBinaryContentType(contentType)) {\n requestEvent.responseBodyStatus = 'skipped_binary';\n this.notifyEvent(requestEvent);\n } else {\n const cloned = response.clone();\n // Read body without blocking the response return to the caller\n cloned.text().then(\n (text) => {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n const { value, truncated } = captureSerializedBody(\n text,\n bodyConfig.response,\n maxBytes,\n truncateToByteLimit,\n );\n requestEvent.responseBody = value;\n requestEvent.responseBodyStatus = truncated ? 'truncated' : 'captured';\n this.notifyEvent(requestEvent);\n },\n () => {\n requestEvent.responseBodyStatus = 'error';\n this.notifyEvent(requestEvent);\n },\n );\n }\n } else {\n this.notifyEvent(requestEvent);\n }\n\n return response;\n } catch (error) {\n const endTime = Date.now();\n requestEvent.duration = endTime - startTime;\n\n // Capture error information\n const typedError = error as Error;\n requestEvent.error = {\n name: typedError.name || 'UnknownError',\n message: typedError.message || 'An unknown error occurred',\n };\n\n this.notifyEvent(requestEvent);\n throw error;\n }\n };\n\n this.fetchObserver = () => {\n globalScope.fetch = originalFetch;\n };\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,11 @@
1
1
  import { __assign, __awaiter, __generator, __read, __spreadArray, __values } from "tslib";
2
+ import { createPrivacyRecorderOptions, getBlockSelectors, getMaskTextSelectors, } from '@amplitude/session-replay-dom-privacy';
2
3
  import { getAnalyticsConnector, getGlobalScope, Logger, returnWrapper, SpecialEventType, generateHashCode, getOrCreateWindowMessenger, enableBackgroundCapture, AMPLITUDE_ORIGINS_MAP, } from '@amplitude/analytics-core';
3
4
  // Import only specific types to avoid pulling in the entire rrweb-types package
4
5
  import { EventType as RRWebEventType } from '@amplitude/rrweb-types';
5
6
  import { createSessionReplayJoinedConfigGenerator } from './config/joined-config';
6
- import { BLOCK_CLASS, CustomRRwebEvent, DEFAULT_SESSION_REPLAY_PROPERTY, INTERACTION_MAX_INTERVAL, INTERACTION_MIN_INTERVAL, MASK_TEXT_CLASS, SESSION_REPLAY_DEBUG_PROPERTY, SESSION_REPLAY_EU_URL, SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_STAGING_URL, } from './constants';
7
- import { getServerUrl, getDebugConfig, getEffectiveMaskLevel, getPageUrl, getStorageSize, getCurrentUrl, maskFn, maskAttributeFn, } from './helpers';
7
+ import { CustomRRwebEvent, DEFAULT_SESSION_REPLAY_PROPERTY, INTERACTION_MAX_INTERVAL, INTERACTION_MIN_INTERVAL, SESSION_REPLAY_DEBUG_PROPERTY, SESSION_REPLAY_EU_URL, SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_STAGING_URL, } from './constants';
8
+ import { getServerUrl, getDebugConfig, getPageUrl, getStorageSize, getCurrentUrl } from './helpers';
8
9
  import { EventCompressor } from './events/event-compressor';
9
10
  import { createEventsManager } from './events/events-manager';
10
11
  import { MultiEventManager } from './events/multi-manager';
@@ -774,42 +775,12 @@ var SessionReplay = /** @class */ (function () {
774
775
  return shouldRecord;
775
776
  };
776
777
  SessionReplay.prototype.getBlockSelectors = function () {
777
- var _a, _b, _c;
778
- // For some reason, this defaults to empty array ([]) if undefined in the compiled script.
779
- // Empty arrays cause errors when being evaluated in Safari.
780
- // Force the selector to be undefined if it's an empty array.
781
- var blockSelector = (_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.privacyConfig) === null || _b === void 0 ? void 0 : _b.blockSelector) !== null && _c !== void 0 ? _c : [];
782
- if (blockSelector.length === 0) {
783
- return undefined;
784
- }
785
- return blockSelector;
778
+ var _a;
779
+ return getBlockSelectors((_a = this.config) === null || _a === void 0 ? void 0 : _a.privacyConfig);
786
780
  };
787
781
  SessionReplay.prototype.getMaskTextSelectors = function () {
788
- var _a, _b;
789
- var privacyConfig = (_a = this.config) === null || _a === void 0 ? void 0 : _a.privacyConfig;
790
- var effectiveLevel = privacyConfig ? getEffectiveMaskLevel(this.currentPageUrl, privacyConfig) : undefined;
791
- if (effectiveLevel === 'conservative') {
792
- return '*';
793
- }
794
- // If any urlMaskLevels rule uses 'conservative', always route all text nodes
795
- // through maskTextFn so the dynamic URL getter can decide at call time.
796
- // Without this, rrweb's static maskTextSelector would miss text nodes when
797
- // the user navigates from a non-conservative page to a conservative one.
798
- if ((_b = privacyConfig === null || privacyConfig === void 0 ? void 0 : privacyConfig.urlMaskLevels) === null || _b === void 0 ? void 0 : _b.some(function (rule) { return rule.maskLevel === 'conservative'; })) {
799
- return '*';
800
- }
801
- // If defaultMaskLevel is 'conservative' and URL rules exist, always route text through
802
- // maskTextFn — a page matching no rule falls back to the conservative default, and
803
- // rrweb must be set up at start to call maskTextFn for those text nodes.
804
- var urlMaskLevels = privacyConfig === null || privacyConfig === void 0 ? void 0 : privacyConfig.urlMaskLevels;
805
- if ((privacyConfig === null || privacyConfig === void 0 ? void 0 : privacyConfig.defaultMaskLevel) === 'conservative' && urlMaskLevels && urlMaskLevels.length > 0) {
806
- return '*';
807
- }
808
- var maskSelector = privacyConfig === null || privacyConfig === void 0 ? void 0 : privacyConfig.maskSelector;
809
- if (!maskSelector) {
810
- return;
811
- }
812
- return maskSelector;
782
+ var _a;
783
+ return getMaskTextSelectors((_a = this.config) === null || _a === void 0 ? void 0 : _a.privacyConfig, this.currentPageUrl);
813
784
  };
814
785
  SessionReplay.prototype.getRecordingPlugins = function (loggingConfig) {
815
786
  var _a, _b, _c, _d, _e, _f;
@@ -1061,7 +1032,7 @@ var SessionReplay = /** @class */ (function () {
1061
1032
  SessionReplay.prototype.buildRRWebRecordOptions = function (config, hooks, emit, errorLogPrefix) {
1062
1033
  var _this = this;
1063
1034
  var privacyConfig = config.privacyConfig;
1064
- return __assign(__assign({ emit: emit, inlineStylesheet: config.shouldInlineStylesheet, inlineImages: config.inlineImages, hooks: hooks, maskAllInputs: true, maskTextClass: MASK_TEXT_CLASS, blockClass: BLOCK_CLASS, blockSelector: this.getBlockSelectors(), applyBackgroundColorToBlockedElements: config.applyBackgroundColorToBlockedElements, maskInputFn: maskFn('input', privacyConfig, function () { return _this.currentPageUrl; }), maskTextFn: maskFn('text', privacyConfig, function () { return _this.currentPageUrl; }), maskAttributeFn: maskAttributeFn(privacyConfig, function () { return _this.currentPageUrl; }), maskTextSelector: this.getMaskTextSelectors() }, (config.fullSnapshotIntervalMs !== undefined && { checkoutEveryNms: config.fullSnapshotIntervalMs })), { recordCanvas: false, captureAdoptedStyleSheets: config.captureAdoptedStyleSheets,
1035
+ return __assign(__assign(__assign(__assign({ emit: emit, inlineStylesheet: config.shouldInlineStylesheet, inlineImages: config.inlineImages, hooks: hooks }, createPrivacyRecorderOptions(privacyConfig, function () { return _this.currentPageUrl; })), { applyBackgroundColorToBlockedElements: config.applyBackgroundColorToBlockedElements }), (config.fullSnapshotIntervalMs !== undefined && { checkoutEveryNms: config.fullSnapshotIntervalMs })), { recordCanvas: false, captureAdoptedStyleSheets: config.captureAdoptedStyleSheets,
1065
1036
  // Strip nodes that are never rendered by the rrweb replay player.
1066
1037
  // None of these affect visual fidelity; omitting them reduces snapshot size.
1067
1038
  slimDOMOptions: {