@amplitude/session-replay-browser 1.36.2 → 1.37.0-sr-3176-rc2.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 (43) hide show
  1. package/lib/cjs/config/joined-config.d.ts.map +1 -1
  2. package/lib/cjs/config/joined-config.js +13 -12
  3. package/lib/cjs/config/joined-config.js.map +1 -1
  4. package/lib/cjs/config/types.d.ts +16 -0
  5. package/lib/cjs/config/types.d.ts.map +1 -1
  6. package/lib/cjs/config/types.js.map +1 -1
  7. package/lib/cjs/helpers.d.ts +9 -4
  8. package/lib/cjs/helpers.d.ts.map +1 -1
  9. package/lib/cjs/helpers.js +83 -21
  10. package/lib/cjs/helpers.js.map +1 -1
  11. package/lib/cjs/session-replay.d.ts +6 -3
  12. package/lib/cjs/session-replay.d.ts.map +1 -1
  13. package/lib/cjs/session-replay.js +62 -37
  14. package/lib/cjs/session-replay.js.map +1 -1
  15. package/lib/cjs/version.d.ts +1 -1
  16. package/lib/cjs/version.d.ts.map +1 -1
  17. package/lib/cjs/version.js +1 -1
  18. package/lib/cjs/version.js.map +1 -1
  19. package/lib/esm/config/joined-config.d.ts.map +1 -1
  20. package/lib/esm/config/joined-config.js +13 -12
  21. package/lib/esm/config/joined-config.js.map +1 -1
  22. package/lib/esm/config/types.d.ts +16 -0
  23. package/lib/esm/config/types.d.ts.map +1 -1
  24. package/lib/esm/config/types.js.map +1 -1
  25. package/lib/esm/helpers.d.ts +9 -4
  26. package/lib/esm/helpers.d.ts.map +1 -1
  27. package/lib/esm/helpers.js +81 -20
  28. package/lib/esm/helpers.js.map +1 -1
  29. package/lib/esm/session-replay.d.ts +6 -3
  30. package/lib/esm/session-replay.d.ts.map +1 -1
  31. package/lib/esm/session-replay.js +63 -38
  32. package/lib/esm/session-replay.js.map +1 -1
  33. package/lib/esm/version.d.ts +1 -1
  34. package/lib/esm/version.d.ts.map +1 -1
  35. package/lib/esm/version.js +1 -1
  36. package/lib/esm/version.js.map +1 -1
  37. package/lib/scripts/index-min.js +1 -1
  38. package/lib/scripts/index-min.js.gz +0 -0
  39. package/lib/scripts/index-min.js.map +1 -1
  40. package/lib/scripts/session-replay-browser-min.js +1 -1
  41. package/lib/scripts/session-replay-browser-min.js.gz +0 -0
  42. package/lib/scripts/session-replay-browser-min.js.map +1 -1
  43. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"joined-config.d.ts","sourceRoot":"","sources":["../../../src/config/joined-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAA4C,MAAM,2BAA2B,CAAC;AAEnH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EACL,wBAAwB,IAAI,yBAAyB,EACrD,aAAa,EACb,oBAAoB,EAGrB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,uCAAuC,kBAAmB,aAAa,kBAAkB,OAAO,kBA0B5G,CAAC;AACF,qBAAa,kCAAkC;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4B;IACxD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;gBAE7C,kBAAkB,EAAE,mBAAmB,EAAE,WAAW,EAAE,yBAAyB;IAKrF,oBAAoB,IAAI,OAAO,CAAC,oBAAoB,CAAC;CAuL5D;AAED,eAAO,MAAM,wCAAwC,WAAkB,MAAM,WAAW,oBAAoB,gDAW3G,CAAC"}
1
+ {"version":3,"file":"joined-config.d.ts","sourceRoot":"","sources":["../../../src/config/joined-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAA4C,MAAM,2BAA2B,CAAC;AAEnH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EACL,wBAAwB,IAAI,yBAAyB,EACrD,aAAa,EACb,oBAAoB,EAGrB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,uCAAuC,kBAAmB,aAAa,kBAAkB,OAAO,kBA0B5G,CAAC;AACF,qBAAa,kCAAkC;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4B;IACxD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;gBAE7C,kBAAkB,EAAE,mBAAmB,EAAE,WAAW,EAAE,yBAAyB;IAKrF,oBAAoB,IAAI,OAAO,CAAC,oBAAoB,CAAC;CAwL5D;AAED,eAAO,MAAM,wCAAwC,WAAkB,MAAM,WAAW,oBAAoB,gDAW3G,CAAC"}
@@ -40,13 +40,13 @@ var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
40
40
  this.remoteConfigClient = remoteConfigClient;
41
41
  }
42
42
  SessionReplayJoinedConfigGenerator.prototype.generateJoinedConfig = function () {
43
- var _a, _b, _c, _d, _e;
43
+ var _a, _b, _c, _d, _e, _f, _g;
44
44
  return tslib_1.__awaiter(this, void 0, void 0, function () {
45
- var config, sessionReplayRemoteConfig, error_1, samplingConfig, remotePrivacyConfig, targetingConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _f, _g, _h, selector, selectorType;
46
- var e_1, _j;
45
+ var config, sessionReplayRemoteConfig, error_1, samplingConfig, remotePrivacyConfig, targetingConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _h, _j, _k, selector, selectorType;
46
+ var e_1, _l;
47
47
  var _this = this;
48
- return tslib_1.__generator(this, function (_k) {
49
- switch (_k.label) {
48
+ return tslib_1.__generator(this, function (_m) {
49
+ switch (_m.label) {
50
50
  case 0:
51
51
  config = tslib_1.__assign({}, this.localConfig);
52
52
  // Special case here as optOut is implemented via getter/setter
@@ -54,9 +54,9 @@ var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
54
54
  // We always want captureEnabled to be true, unless there's an override
55
55
  // in the remote config.
56
56
  config.captureEnabled = true;
57
- _k.label = 1;
57
+ _m.label = 1;
58
58
  case 1:
59
- _k.trys.push([1, 3, , 4]);
59
+ _m.trys.push([1, 3, , 4]);
60
60
  // Subscribe to remote config client to get the config (uses cache if available)
61
61
  return [4 /*yield*/, new Promise(function (resolve, reject) {
62
62
  _this.remoteConfigClient.subscribe('configs.sessionReplay', 'all', function (remoteConfig, source) {
@@ -97,10 +97,10 @@ var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
97
97
  })];
98
98
  case 2:
99
99
  // Subscribe to remote config client to get the config (uses cache if available)
100
- _k.sent();
100
+ _m.sent();
101
101
  return [3 /*break*/, 4];
102
102
  case 3:
103
- error_1 = _k.sent();
103
+ error_1 = _m.sent();
104
104
  this.localConfig.loggerProvider.error('Failed to generate joined config: ', error_1);
105
105
  config.captureEnabled = false;
106
106
  return [2 /*return*/, {
@@ -156,6 +156,7 @@ var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
156
156
  maskSelector: [],
157
157
  unmaskSelector: [],
158
158
  maskAttributes: tslib_1.__spreadArray([], tslib_1.__read(new Set(tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(((_d = localPrivacyConfig.maskAttributes) !== null && _d !== void 0 ? _d : [])), false), tslib_1.__read(((_e = remotePrivacyConfig.maskAttributes) !== null && _e !== void 0 ? _e : [])), false))), false),
159
+ urlMaskLevels: tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(((_f = remotePrivacyConfig.urlMaskLevels) !== null && _f !== void 0 ? _f : [])), false), tslib_1.__read(((_g = localPrivacyConfig.urlMaskLevels) !== null && _g !== void 0 ? _g : [])), false),
159
160
  };
160
161
  privacyConfigSelectorMap = function (privacyConfig) {
161
162
  var e_2, _a, e_3, _b, e_4, _c;
@@ -207,8 +208,8 @@ var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
207
208
  };
208
209
  selectorMap = tslib_1.__assign(tslib_1.__assign({}, privacyConfigSelectorMap(localPrivacyConfig)), privacyConfigSelectorMap(remotePrivacyConfig));
209
210
  try {
210
- for (_f = tslib_1.__values(Object.entries(selectorMap)), _g = _f.next(); !_g.done; _g = _f.next()) {
211
- _h = tslib_1.__read(_g.value, 2), selector = _h[0], selectorType = _h[1];
211
+ for (_h = tslib_1.__values(Object.entries(selectorMap)), _j = _h.next(); !_j.done; _j = _h.next()) {
212
+ _k = tslib_1.__read(_j.value, 2), selector = _k[0], selectorType = _k[1];
212
213
  if (selectorType === 'mask') {
213
214
  joinedPrivacyConfig.maskSelector.push(selector);
214
215
  }
@@ -223,7 +224,7 @@ var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
223
224
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
224
225
  finally {
225
226
  try {
226
- if (_g && !_g.done && (_j = _f.return)) _j.call(_f);
227
+ if (_j && !_j.done && (_l = _h.return)) _l.call(_h);
227
228
  }
228
229
  finally { if (e_1) throw e_1.error; }
229
230
  }
@@ -1 +1 @@
1
- {"version":3,"file":"joined-config.js","sourceRoot":"","sources":["../../../src/config/joined-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { ILogger, IRemoteConfigClient, RemoteConfigClient, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport { getDebugConfig } from '../helpers';\nimport { SessionReplayOptions } from '../typings/session-replay';\nimport { SessionReplayLocalConfig } from './local-config';\nimport {\n SessionReplayLocalConfig as ISessionReplayLocalConfig,\n PrivacyConfig,\n SessionReplayConfigs,\n SessionReplayJoinedConfig,\n SessionReplayRemoteConfig,\n} from './types';\n\nexport const removeInvalidSelectorsFromPrivacyConfig = (privacyConfig: PrivacyConfig, loggerProvider: ILogger) => {\n // This allows us to not search the DOM.\n const fragment = document.createDocumentFragment();\n\n const dropInvalidSelectors = (selectors: string[] | string = []): string[] | undefined => {\n if (typeof selectors === 'string') {\n selectors = [selectors];\n }\n selectors = selectors.filter((selector: string) => {\n try {\n fragment.querySelector(selector);\n } catch {\n loggerProvider.warn(`[session-replay-browser] omitting selector \"${selector}\" because it is invalid`);\n return false;\n }\n return true;\n });\n if (selectors.length === 0) {\n return undefined;\n }\n return selectors;\n };\n privacyConfig.blockSelector = dropInvalidSelectors(privacyConfig.blockSelector);\n privacyConfig.maskSelector = dropInvalidSelectors(privacyConfig.maskSelector);\n privacyConfig.unmaskSelector = dropInvalidSelectors(privacyConfig.unmaskSelector);\n return privacyConfig;\n};\nexport class SessionReplayJoinedConfigGenerator {\n private readonly localConfig: ISessionReplayLocalConfig;\n private readonly remoteConfigClient: IRemoteConfigClient;\n\n constructor(remoteConfigClient: IRemoteConfigClient, localConfig: ISessionReplayLocalConfig) {\n this.localConfig = localConfig;\n this.remoteConfigClient = remoteConfigClient;\n }\n\n async generateJoinedConfig(): Promise<SessionReplayConfigs> {\n const config: SessionReplayJoinedConfig = { ...this.localConfig };\n // Special case here as optOut is implemented via getter/setter\n config.optOut = this.localConfig.optOut;\n // We always want captureEnabled to be true, unless there's an override\n // in the remote config.\n config.captureEnabled = true;\n let sessionReplayRemoteConfig: SessionReplayRemoteConfig | undefined;\n\n try {\n // Subscribe to remote config client to get the config (uses cache if available)\n await new Promise<void>((resolve, reject) => {\n this.remoteConfigClient.subscribe(\n 'configs.sessionReplay',\n 'all',\n (remoteConfig: RemoteConfig | null, source: Source) => {\n this.localConfig.loggerProvider.debug(\n `Session Replay remote configuration received from ${source}:`,\n JSON.stringify(remoteConfig, null, 2),\n );\n\n if (!remoteConfig) {\n reject(new Error('No remote config received'));\n return;\n }\n\n // remoteConfig is already filtered to 'configs.sessionReplay' namespace\n const namespaceConfig = remoteConfig as SessionReplayRemoteConfig;\n const samplingConfig = namespaceConfig.sr_sampling_config;\n const privacyConfig = namespaceConfig.sr_privacy_config;\n const targetingConfig = namespaceConfig.sr_targeting_config;\n\n const ugcFilterRules = config.interactionConfig?.ugcFilterRules;\n // This is intentionally forced to only be set through the remote config.\n config.interactionConfig = namespaceConfig.sr_interaction_config;\n if (config.interactionConfig && ugcFilterRules) {\n config.interactionConfig.ugcFilterRules = ugcFilterRules;\n }\n\n // This is intentionally forced to only be set through the remote config.\n config.loggingConfig = namespaceConfig.sr_logging_config;\n\n if (samplingConfig || privacyConfig || targetingConfig) {\n sessionReplayRemoteConfig = {};\n if (samplingConfig) {\n sessionReplayRemoteConfig.sr_sampling_config = samplingConfig;\n }\n if (privacyConfig) {\n sessionReplayRemoteConfig.sr_privacy_config = privacyConfig;\n }\n if (targetingConfig) {\n sessionReplayRemoteConfig.sr_targeting_config = targetingConfig;\n }\n }\n\n // Resolve on first callback\n resolve();\n },\n );\n });\n } catch (error) {\n this.localConfig.loggerProvider.error('Failed to generate joined config: ', error);\n config.captureEnabled = false;\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: undefined,\n };\n }\n\n if (!sessionReplayRemoteConfig) {\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n\n const {\n sr_sampling_config: samplingConfig,\n sr_privacy_config: remotePrivacyConfig,\n sr_targeting_config: targetingConfig,\n } = sessionReplayRemoteConfig;\n if (samplingConfig && Object.keys(samplingConfig).length > 0) {\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) {\n config.captureEnabled = samplingConfig.capture_enabled;\n } else {\n config.captureEnabled = false;\n }\n\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'sample_rate')) {\n config.sampleRate = samplingConfig.sample_rate;\n }\n } else {\n // If config API response was valid (ie 200), but no config returned, assume that\n // customer has not yet set up config, and use sample rate from SDK options,\n // allowing for immediate replay capture\n config.captureEnabled = true;\n this.localConfig.loggerProvider.debug(\n 'Remote config successfully fetched, but no values set for project, Session Replay capture enabled.',\n );\n }\n\n // Remote config join acts somewhat like a left join between the remote and the local\n // config. That is, remote config has precedence over local values as with sampling.\n // However, non conflicting values will be added to the lists.\n // Here's an example to illustrate:\n //\n // Remote config: {'.selector1': 'MASK', '.selector2': 'UNMASK'}\n // Local config: {'.selector1': 'UNMASK', '.selector3': 'MASK'}\n //\n // Resolved config: {'.selector1': 'MASK', '.selector2': 'UNMASK', '.selector3': 'MASK'}\n // config.privacyConfig = {\n // ...(config.privacyConfig ?? {}),\n // ...remotePrivacyConfig,\n // };\n\n if (remotePrivacyConfig) {\n const localPrivacyConfig: PrivacyConfig = config.privacyConfig ?? {};\n\n const joinedPrivacyConfig: Required<PrivacyConfig> & { blockSelector: string[] } = {\n defaultMaskLevel: remotePrivacyConfig.defaultMaskLevel ?? localPrivacyConfig.defaultMaskLevel ?? 'medium',\n blockSelector: [],\n maskSelector: [],\n unmaskSelector: [],\n maskAttributes: [\n ...new Set([...(localPrivacyConfig.maskAttributes ?? []), ...(remotePrivacyConfig.maskAttributes ?? [])]),\n ],\n };\n\n const privacyConfigSelectorMap = (privacyConfig: PrivacyConfig): Record<string, 'mask' | 'unmask' | 'block'> => {\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {};\n if (typeof privacyConfig.blockSelector === 'string') {\n privacyConfig.blockSelector = [privacyConfig.blockSelector];\n }\n\n for (const selector of privacyConfig.blockSelector ?? []) {\n selectorMap[selector] = 'block';\n }\n for (const selector of privacyConfig.maskSelector ?? []) {\n selectorMap[selector] = 'mask';\n }\n for (const selector of privacyConfig.unmaskSelector ?? []) {\n selectorMap[selector] = 'unmask';\n }\n return selectorMap;\n };\n\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {\n ...privacyConfigSelectorMap(localPrivacyConfig),\n ...privacyConfigSelectorMap(remotePrivacyConfig),\n };\n\n for (const [selector, selectorType] of Object.entries(selectorMap)) {\n if (selectorType === 'mask') {\n joinedPrivacyConfig.maskSelector.push(selector);\n } else if (selectorType === 'block') {\n joinedPrivacyConfig.blockSelector.push(selector);\n } else if (selectorType === 'unmask') {\n joinedPrivacyConfig.unmaskSelector.push(selector);\n }\n }\n\n config.privacyConfig = removeInvalidSelectorsFromPrivacyConfig(\n joinedPrivacyConfig,\n this.localConfig.loggerProvider,\n );\n }\n\n if (targetingConfig && Object.keys(targetingConfig).length > 0) {\n config.targetingConfig = targetingConfig;\n }\n\n this.localConfig.loggerProvider.debug(\n JSON.stringify({ name: 'session replay joined config', config: getDebugConfig(config) }, null, 2),\n );\n\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n}\n\nexport const createSessionReplayJoinedConfigGenerator = async (apiKey: string, options: SessionReplayOptions) => {\n const localConfig = new SessionReplayLocalConfig(apiKey, options);\n\n const remoteConfigClient = new RemoteConfigClient(\n apiKey,\n localConfig.loggerProvider,\n localConfig.serverZone,\n options.configServerUrl,\n );\n\n return new SessionReplayJoinedConfigGenerator(remoteConfigClient, localConfig);\n};\n"]}
1
+ {"version":3,"file":"joined-config.js","sourceRoot":"","sources":["../../../src/config/joined-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { ILogger, IRemoteConfigClient, RemoteConfigClient, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport { getDebugConfig } from '../helpers';\nimport { SessionReplayOptions } from '../typings/session-replay';\nimport { SessionReplayLocalConfig } from './local-config';\nimport {\n SessionReplayLocalConfig as ISessionReplayLocalConfig,\n PrivacyConfig,\n SessionReplayConfigs,\n SessionReplayJoinedConfig,\n SessionReplayRemoteConfig,\n} from './types';\n\nexport const removeInvalidSelectorsFromPrivacyConfig = (privacyConfig: PrivacyConfig, loggerProvider: ILogger) => {\n // This allows us to not search the DOM.\n const fragment = document.createDocumentFragment();\n\n const dropInvalidSelectors = (selectors: string[] | string = []): string[] | undefined => {\n if (typeof selectors === 'string') {\n selectors = [selectors];\n }\n selectors = selectors.filter((selector: string) => {\n try {\n fragment.querySelector(selector);\n } catch {\n loggerProvider.warn(`[session-replay-browser] omitting selector \"${selector}\" because it is invalid`);\n return false;\n }\n return true;\n });\n if (selectors.length === 0) {\n return undefined;\n }\n return selectors;\n };\n privacyConfig.blockSelector = dropInvalidSelectors(privacyConfig.blockSelector);\n privacyConfig.maskSelector = dropInvalidSelectors(privacyConfig.maskSelector);\n privacyConfig.unmaskSelector = dropInvalidSelectors(privacyConfig.unmaskSelector);\n return privacyConfig;\n};\nexport class SessionReplayJoinedConfigGenerator {\n private readonly localConfig: ISessionReplayLocalConfig;\n private readonly remoteConfigClient: IRemoteConfigClient;\n\n constructor(remoteConfigClient: IRemoteConfigClient, localConfig: ISessionReplayLocalConfig) {\n this.localConfig = localConfig;\n this.remoteConfigClient = remoteConfigClient;\n }\n\n async generateJoinedConfig(): Promise<SessionReplayConfigs> {\n const config: SessionReplayJoinedConfig = { ...this.localConfig };\n // Special case here as optOut is implemented via getter/setter\n config.optOut = this.localConfig.optOut;\n // We always want captureEnabled to be true, unless there's an override\n // in the remote config.\n config.captureEnabled = true;\n let sessionReplayRemoteConfig: SessionReplayRemoteConfig | undefined;\n\n try {\n // Subscribe to remote config client to get the config (uses cache if available)\n await new Promise<void>((resolve, reject) => {\n this.remoteConfigClient.subscribe(\n 'configs.sessionReplay',\n 'all',\n (remoteConfig: RemoteConfig | null, source: Source) => {\n this.localConfig.loggerProvider.debug(\n `Session Replay remote configuration received from ${source}:`,\n JSON.stringify(remoteConfig, null, 2),\n );\n\n if (!remoteConfig) {\n reject(new Error('No remote config received'));\n return;\n }\n\n // remoteConfig is already filtered to 'configs.sessionReplay' namespace\n const namespaceConfig = remoteConfig as SessionReplayRemoteConfig;\n const samplingConfig = namespaceConfig.sr_sampling_config;\n const privacyConfig = namespaceConfig.sr_privacy_config;\n const targetingConfig = namespaceConfig.sr_targeting_config;\n\n const ugcFilterRules = config.interactionConfig?.ugcFilterRules;\n // This is intentionally forced to only be set through the remote config.\n config.interactionConfig = namespaceConfig.sr_interaction_config;\n if (config.interactionConfig && ugcFilterRules) {\n config.interactionConfig.ugcFilterRules = ugcFilterRules;\n }\n\n // This is intentionally forced to only be set through the remote config.\n config.loggingConfig = namespaceConfig.sr_logging_config;\n\n if (samplingConfig || privacyConfig || targetingConfig) {\n sessionReplayRemoteConfig = {};\n if (samplingConfig) {\n sessionReplayRemoteConfig.sr_sampling_config = samplingConfig;\n }\n if (privacyConfig) {\n sessionReplayRemoteConfig.sr_privacy_config = privacyConfig;\n }\n if (targetingConfig) {\n sessionReplayRemoteConfig.sr_targeting_config = targetingConfig;\n }\n }\n\n // Resolve on first callback\n resolve();\n },\n );\n });\n } catch (error) {\n this.localConfig.loggerProvider.error('Failed to generate joined config: ', error);\n config.captureEnabled = false;\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: undefined,\n };\n }\n\n if (!sessionReplayRemoteConfig) {\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n\n const {\n sr_sampling_config: samplingConfig,\n sr_privacy_config: remotePrivacyConfig,\n sr_targeting_config: targetingConfig,\n } = sessionReplayRemoteConfig;\n if (samplingConfig && Object.keys(samplingConfig).length > 0) {\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) {\n config.captureEnabled = samplingConfig.capture_enabled;\n } else {\n config.captureEnabled = false;\n }\n\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'sample_rate')) {\n config.sampleRate = samplingConfig.sample_rate;\n }\n } else {\n // If config API response was valid (ie 200), but no config returned, assume that\n // customer has not yet set up config, and use sample rate from SDK options,\n // allowing for immediate replay capture\n config.captureEnabled = true;\n this.localConfig.loggerProvider.debug(\n 'Remote config successfully fetched, but no values set for project, Session Replay capture enabled.',\n );\n }\n\n // Remote config join acts somewhat like a left join between the remote and the local\n // config. That is, remote config has precedence over local values as with sampling.\n // However, non conflicting values will be added to the lists.\n // Here's an example to illustrate:\n //\n // Remote config: {'.selector1': 'MASK', '.selector2': 'UNMASK'}\n // Local config: {'.selector1': 'UNMASK', '.selector3': 'MASK'}\n //\n // Resolved config: {'.selector1': 'MASK', '.selector2': 'UNMASK', '.selector3': 'MASK'}\n // config.privacyConfig = {\n // ...(config.privacyConfig ?? {}),\n // ...remotePrivacyConfig,\n // };\n\n if (remotePrivacyConfig) {\n const localPrivacyConfig: PrivacyConfig = config.privacyConfig ?? {};\n\n const joinedPrivacyConfig: Required<PrivacyConfig> & { blockSelector: string[] } = {\n defaultMaskLevel: remotePrivacyConfig.defaultMaskLevel ?? localPrivacyConfig.defaultMaskLevel ?? 'medium',\n blockSelector: [],\n maskSelector: [],\n unmaskSelector: [],\n maskAttributes: [\n ...new Set([...(localPrivacyConfig.maskAttributes ?? []), ...(remotePrivacyConfig.maskAttributes ?? [])]),\n ],\n urlMaskLevels: [...(remotePrivacyConfig.urlMaskLevels ?? []), ...(localPrivacyConfig.urlMaskLevels ?? [])],\n };\n\n const privacyConfigSelectorMap = (privacyConfig: PrivacyConfig): Record<string, 'mask' | 'unmask' | 'block'> => {\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {};\n if (typeof privacyConfig.blockSelector === 'string') {\n privacyConfig.blockSelector = [privacyConfig.blockSelector];\n }\n\n for (const selector of privacyConfig.blockSelector ?? []) {\n selectorMap[selector] = 'block';\n }\n for (const selector of privacyConfig.maskSelector ?? []) {\n selectorMap[selector] = 'mask';\n }\n for (const selector of privacyConfig.unmaskSelector ?? []) {\n selectorMap[selector] = 'unmask';\n }\n return selectorMap;\n };\n\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {\n ...privacyConfigSelectorMap(localPrivacyConfig),\n ...privacyConfigSelectorMap(remotePrivacyConfig),\n };\n\n for (const [selector, selectorType] of Object.entries(selectorMap)) {\n if (selectorType === 'mask') {\n joinedPrivacyConfig.maskSelector.push(selector);\n } else if (selectorType === 'block') {\n joinedPrivacyConfig.blockSelector.push(selector);\n } else if (selectorType === 'unmask') {\n joinedPrivacyConfig.unmaskSelector.push(selector);\n }\n }\n\n config.privacyConfig = removeInvalidSelectorsFromPrivacyConfig(\n joinedPrivacyConfig,\n this.localConfig.loggerProvider,\n );\n }\n\n if (targetingConfig && Object.keys(targetingConfig).length > 0) {\n config.targetingConfig = targetingConfig;\n }\n\n this.localConfig.loggerProvider.debug(\n JSON.stringify({ name: 'session replay joined config', config: getDebugConfig(config) }, null, 2),\n );\n\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n}\n\nexport const createSessionReplayJoinedConfigGenerator = async (apiKey: string, options: SessionReplayOptions) => {\n const localConfig = new SessionReplayLocalConfig(apiKey, options);\n\n const remoteConfigClient = new RemoteConfigClient(\n apiKey,\n localConfig.loggerProvider,\n localConfig.serverZone,\n options.configServerUrl,\n );\n\n return new SessionReplayJoinedConfigGenerator(remoteConfigClient, localConfig);\n};\n"]}
@@ -49,6 +49,22 @@ export type PrivacyConfig = {
49
49
  maskSelector?: string[];
50
50
  unmaskSelector?: string[];
51
51
  maskAttributes?: string[];
52
+ /**
53
+ * Per-URL overrides for `defaultMaskLevel`. Each entry contains a glob pattern (`match`)
54
+ * and a `maskLevel` to apply when the current page URL matches that pattern.
55
+ * Rules are evaluated in order; the first match wins. Remote rules take precedence
56
+ * over local rules (remote entries are prepended before local entries).
57
+ *
58
+ * @example
59
+ * urlMaskLevels: [
60
+ * { match: 'https://example.com/checkout/*', maskLevel: 'conservative' },
61
+ * { match: 'https://example.com/public/*', maskLevel: 'light' },
62
+ * ]
63
+ */
64
+ urlMaskLevels?: Array<{
65
+ match: string;
66
+ maskLevel: MaskLevel;
67
+ }>;
52
68
  };
53
69
  /**
54
70
  * UGC filter rule.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,eAAe,EAAE,CAAC;KAC3B,CAAC;IACF,OAAO,CAAC,EAAE;QACR,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE;YACL,OAAO,CAAC,EAAE,OAAO,CAAC;YAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;YACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,CAAC;KACH,CAAC;CACH;AAED,MAAM,MAAM,eAAe,GAAG,aAAa,CAAC;AAE5C,MAAM,MAAM,yBAAyB,GAAG;IACtC,kBAAkB,CAAC,EAAE,cAAc,CAAC;IACpC,iBAAiB,CAAC,EAAE,aAAa,CAAC;IAClC,qBAAqB,CAAC,EAAE,iBAAiB,CAAC;IAC1C,iBAAiB,CAAC,EAAE,aAAa,CAAC;IAClC,mBAAmB,CAAC,EAAE,eAAe,CAAC;CACvC,CAAC;AAEF,MAAM,WAAW,oCAAoC;IACnD,OAAO,EAAE;QACP,aAAa,EAAE,yBAAyB,CAAC;KAC1C,CAAC;CACH;AAED,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,QAAQ,GACR,cAAc,CAAC;AAEnB,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAG3C,MAAM,MAAM,aAAa,GAAG;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,wBAAyB,SAAQ,OAAO;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,EAAE,QAAQ,CAAC;IACnB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,8BAA8B,CAAC;IACnD;;;;OAIG;IACH,SAAS,EAAE,SAAS,CAAC;IAErB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,cAAc,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAExC;;OAEG;IACH,eAAe,CAAC,EAAE;QAChB;;WAEG;QACH,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB;;WAEG;QACH,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IAEF;;;OAGG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAED,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,wBAAwB,CAAC;IACtC,YAAY,EAAE,yBAAyB,CAAC;IACxC,YAAY,EAAE,yBAAyB,GAAG,SAAS,CAAC;CACrD;AACD,MAAM,WAAW,kCAAkC;IACjD,oBAAoB,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,yBAAyB,GAAG,SAAS,CAAC;IACpD,WAAW,EAAE,wBAAwB,CAAC;IACtC,YAAY,EAAE,yBAAyB,CAAC;IACxC,SAAS,CAAC,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,4BAA4B,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":";;;AAuDa,QAAA,kBAAkB,GAAG,QAAQ,CAAC","sourcesContent":["import { IConfig, LogLevel, ILogger } from '@amplitude/analytics-core';\nimport { StoreType, ConsoleLogLevel } from '../typings/session-replay';\nimport { TargetingFlag } from '@amplitude/targeting';\n\nexport interface SamplingConfig {\n sample_rate: number;\n capture_enabled: boolean;\n}\n\nexport interface InteractionConfig {\n trackEveryNms?: number;\n enabled: boolean; // defaults to false\n batch: boolean; // defaults to false\n /**\n * UGC filter rules.\n */\n ugcFilterRules?: UGCFilterRule[];\n}\n\nexport interface LoggingConfig {\n console: {\n enabled: boolean;\n levels: ConsoleLogLevel[];\n };\n network?: {\n enabled: boolean;\n body?: {\n request?: boolean;\n response?: boolean;\n maxBodySizeBytes?: number;\n };\n };\n}\n\nexport type TargetingConfig = TargetingFlag;\n\nexport type SessionReplayRemoteConfig = {\n sr_sampling_config?: SamplingConfig;\n sr_privacy_config?: PrivacyConfig;\n sr_interaction_config?: InteractionConfig;\n sr_logging_config?: LoggingConfig;\n sr_targeting_config?: TargetingConfig;\n};\n\nexport interface SessionReplayRemoteConfigAPIResponse {\n configs: {\n sessionReplay: SessionReplayRemoteConfig;\n };\n}\n\nexport type MaskLevel =\n | 'light' // only mask a subset of inputs that's deemed sensitive - password, credit card, telephone #, email. These are information we never want to capture.\n | 'medium' // mask all inputs\n | 'conservative'; // mask all inputs and all texts\n\nexport const DEFAULT_MASK_LEVEL = 'medium';\n\n// err on the side of excluding more\nexport type PrivacyConfig = {\n blockSelector?: string | string[]; // exclude in the UI\n defaultMaskLevel?: MaskLevel;\n maskSelector?: string[];\n unmaskSelector?: string[];\n maskAttributes?: string[]; // HTML attribute names to mask (e.g. [\"placeholder\", \"aria-label\"])\n};\n\n/**\n * UGC filter rule.\n */\nexport type UGCFilterRule = {\n /**\n * The selector of the UGC element.\n */\n selector: string;\n /**\n * The replacement text for the UGC element.\n */\n replacement: string;\n};\n\nexport interface SessionReplayLocalConfig extends IConfig {\n apiKey: string;\n loggerProvider: ILogger;\n /**\n * LogLevel.None or LogLevel.Error or LogLevel.Warn or LogLevel.Verbose or LogLevel.Debug.\n * Sets the log level.\n *\n * @defaultValue LogLevel.Warn\n */\n logLevel: LogLevel;\n /**\n * The maximum number of retries allowed for sending replay events.\n * Once this limit is reached, failed events will no longer be sent.\n *\n * @defaultValue 2\n */\n flushMaxRetries: number;\n /**\n * Use this option to control how many sessions to select for replay collection.\n * The number should be a decimal between 0 and 1, for example 0.4, representing\n * the fraction of sessions to have randomly selected for replay collection.\n * Over a large number of sessions, 0.4 would select 40% of those sessions.\n * Sample rates as small as six decimal places (0.000001) are supported.\n *\n * @defaultValue 0\n */\n sampleRate: number;\n privacyConfig?: PrivacyConfig;\n /**\n * Adds additional debug event property to help debug instrumentation issues\n * (such as mismatching apps). Only recommended for debugging initial setup,\n * and not recommended for production.\n */\n debugMode?: boolean;\n /**\n * Specifies the endpoint URL to fetch remote configuration.\n * If provided, it overrides the default server zone configuration.\n */\n configServerUrl?: string;\n /**\n * Specifies the endpoint URL for sending session replay data.\n * If provided, it overrides the default server zone configuration.\n */\n trackServerUrl?: string;\n /**\n * If stylesheets are inlined, the contents of the stylesheet will be stored.\n * During replay, the stored stylesheet will be used instead of attempting to fetch it remotely.\n * This prevents replays from appearing broken due to missing stylesheets.\n * Note: Inlining stylesheets may not work in all cases.\n */\n shouldInlineStylesheet?: boolean;\n version?: SessionReplayVersion;\n /**\n * Performance configuration config. If enabled, we will defer compression\n * to be done during the browser's idle periods.\n */\n performanceConfig?: SessionReplayPerformanceConfig;\n /**\n * Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events\n * when all events cannot be sent during capture. `memory` stores replay events only in memory,\n * meaning events are lost when the page is closed. If IndexedDB is unavailable, the system falls back to `memory`.\n */\n storeType: StoreType;\n\n /**\n * If true, the SDK will compress replay events using a web worker.\n * This offloads compression to a separate thread, improving performance on the main thread.\n *\n * @defaultValue false\n */\n useWebWorker?: boolean;\n\n userProperties?: { [key: string]: any };\n\n /**\n * Remove certain parts of the DOM from being captured. These are typically ignored when blocking by selectors.\n */\n omitElementTags?: {\n /**\n * If true, removes script tags from the DOM, but not noscript tags.\n */\n script?: boolean;\n /**\n * If true, removes comment tags from the DOM.\n */\n comment?: boolean;\n };\n\n /**\n * If true, applies a background color to blocked elements in the replay.\n * This helps visualize which elements are blocked from being captured.\n */\n applyBackgroundColorToBlockedElements?: boolean;\n /**\n * Enables URL change polling as a fallback for SPA route tracking.\n * When enabled, the SDK will periodically check for URL changes every second\n * in addition to patching the History API. This is useful for edge cases where\n * route changes might bypass the standard History API methods.\n *\n * @defaultValue false\n */\n enableUrlChangePolling?: boolean;\n /**\n * Specifies the interval in milliseconds for URL change polling when enableUrlChangePolling is true.\n * The SDK will check for URL changes at this interval as a fallback for SPA route tracking.\n *\n * @defaultValue 1000\n */\n urlChangePollingInterval?: number;\n /**\n * Whether to capture document title in URL change events.\n * When disabled, the title field will be empty in URL change events.\n *\n * @defaultValue false\n */\n captureDocumentTitle?: boolean;\n interactionConfig?: InteractionConfig;\n}\n\nexport interface SessionReplayJoinedConfig extends SessionReplayLocalConfig {\n captureEnabled?: boolean;\n interactionConfig?: InteractionConfig;\n loggingConfig?: LoggingConfig;\n targetingConfig?: TargetingConfig;\n}\n\nexport interface SessionReplayConfigs {\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n remoteConfig: SessionReplayRemoteConfig | undefined;\n}\nexport interface SessionReplayJoinedConfigGenerator {\n generateJoinedConfig: () => Promise<SessionReplayConfigs>;\n}\n\nexport interface SessionReplayMetadata {\n remoteConfig: SessionReplayRemoteConfig | undefined;\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n framework?: {\n name: string;\n version: string;\n };\n sessionId: string | number | undefined;\n hashValue?: number;\n sampleRate: number;\n replaySDKType: string | null;\n replaySDKVersion: string | undefined;\n standaloneSDKType: string;\n standaloneSDKVersion: string | undefined;\n}\n\nexport interface SessionReplayVersion {\n version: string;\n type: SessionReplayType;\n}\n\n/**\n * Configuration options for session replay performance.\n */\nexport interface SessionReplayPerformanceConfig {\n /**\n * If enabled, event compression will be deferred to occur during the browser's idle periods.\n */\n enabled: boolean;\n /**\n * Optional timeout in milliseconds for the `requestIdleCallback` API.\n * If specified, this value will be used to set a maximum time for the browser to wait\n * before executing the deferred compression task, even if the browser is not idle.\n */\n timeout?: number;\n /**\n * Performance configuration for interaction tracking (clicks, scrolls).\n */\n interaction?: InteractionPerformanceConfig;\n}\n\n/**\n * Performance configuration for interaction tracking, specifically for CSS selector generation.\n */\nexport interface InteractionPerformanceConfig {\n /**\n * Maximum time in milliseconds allowed for CSS selector generation.\n * If selector generation takes longer than this, it will throw a timeout error.\n * Default: undefined (no timeout limit)\n */\n timeoutMs?: number;\n /**\n * Maximum number of attempts to optimize/simplify the CSS selector path.\n * Higher values may produce shorter selectors but take longer to compute.\n * Default: 10000\n */\n maxNumberOfTries?: number;\n /**\n * Maximum number of CSS selector combinations to test for uniqueness.\n * If more combinations would be generated, falls back to a simpler strategy.\n * Default: 1000\n */\n threshold?: number;\n}\n\nexport type SessionReplayType = 'standalone' | 'plugin' | 'segment';\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":";;;AAuDa,QAAA,kBAAkB,GAAG,QAAQ,CAAC","sourcesContent":["import { IConfig, LogLevel, ILogger } from '@amplitude/analytics-core';\nimport { StoreType, ConsoleLogLevel } from '../typings/session-replay';\nimport { TargetingFlag } from '@amplitude/targeting';\n\nexport interface SamplingConfig {\n sample_rate: number;\n capture_enabled: boolean;\n}\n\nexport interface InteractionConfig {\n trackEveryNms?: number;\n enabled: boolean; // defaults to false\n batch: boolean; // defaults to false\n /**\n * UGC filter rules.\n */\n ugcFilterRules?: UGCFilterRule[];\n}\n\nexport interface LoggingConfig {\n console: {\n enabled: boolean;\n levels: ConsoleLogLevel[];\n };\n network?: {\n enabled: boolean;\n body?: {\n request?: boolean;\n response?: boolean;\n maxBodySizeBytes?: number;\n };\n };\n}\n\nexport type TargetingConfig = TargetingFlag;\n\nexport type SessionReplayRemoteConfig = {\n sr_sampling_config?: SamplingConfig;\n sr_privacy_config?: PrivacyConfig;\n sr_interaction_config?: InteractionConfig;\n sr_logging_config?: LoggingConfig;\n sr_targeting_config?: TargetingConfig;\n};\n\nexport interface SessionReplayRemoteConfigAPIResponse {\n configs: {\n sessionReplay: SessionReplayRemoteConfig;\n };\n}\n\nexport type MaskLevel =\n | 'light' // only mask a subset of inputs that's deemed sensitive - password, credit card, telephone #, email. These are information we never want to capture.\n | 'medium' // mask all inputs\n | 'conservative'; // mask all inputs and all texts\n\nexport const DEFAULT_MASK_LEVEL = 'medium';\n\n// err on the side of excluding more\nexport type PrivacyConfig = {\n blockSelector?: string | string[]; // exclude in the UI\n defaultMaskLevel?: MaskLevel;\n maskSelector?: string[];\n unmaskSelector?: string[];\n maskAttributes?: string[]; // HTML attribute names to mask (e.g. [\"placeholder\", \"aria-label\"])\n /**\n * Per-URL overrides for `defaultMaskLevel`. Each entry contains a glob pattern (`match`)\n * and a `maskLevel` to apply when the current page URL matches that pattern.\n * Rules are evaluated in order; the first match wins. Remote rules take precedence\n * over local rules (remote entries are prepended before local entries).\n *\n * @example\n * urlMaskLevels: [\n * { match: 'https://example.com/checkout/*', maskLevel: 'conservative' },\n * { match: 'https://example.com/public/*', maskLevel: 'light' },\n * ]\n */\n urlMaskLevels?: Array<{ match: string; maskLevel: MaskLevel }>;\n};\n\n/**\n * UGC filter rule.\n */\nexport type UGCFilterRule = {\n /**\n * The selector of the UGC element.\n */\n selector: string;\n /**\n * The replacement text for the UGC element.\n */\n replacement: string;\n};\n\nexport interface SessionReplayLocalConfig extends IConfig {\n apiKey: string;\n loggerProvider: ILogger;\n /**\n * LogLevel.None or LogLevel.Error or LogLevel.Warn or LogLevel.Verbose or LogLevel.Debug.\n * Sets the log level.\n *\n * @defaultValue LogLevel.Warn\n */\n logLevel: LogLevel;\n /**\n * The maximum number of retries allowed for sending replay events.\n * Once this limit is reached, failed events will no longer be sent.\n *\n * @defaultValue 2\n */\n flushMaxRetries: number;\n /**\n * Use this option to control how many sessions to select for replay collection.\n * The number should be a decimal between 0 and 1, for example 0.4, representing\n * the fraction of sessions to have randomly selected for replay collection.\n * Over a large number of sessions, 0.4 would select 40% of those sessions.\n * Sample rates as small as six decimal places (0.000001) are supported.\n *\n * @defaultValue 0\n */\n sampleRate: number;\n privacyConfig?: PrivacyConfig;\n /**\n * Adds additional debug event property to help debug instrumentation issues\n * (such as mismatching apps). Only recommended for debugging initial setup,\n * and not recommended for production.\n */\n debugMode?: boolean;\n /**\n * Specifies the endpoint URL to fetch remote configuration.\n * If provided, it overrides the default server zone configuration.\n */\n configServerUrl?: string;\n /**\n * Specifies the endpoint URL for sending session replay data.\n * If provided, it overrides the default server zone configuration.\n */\n trackServerUrl?: string;\n /**\n * If stylesheets are inlined, the contents of the stylesheet will be stored.\n * During replay, the stored stylesheet will be used instead of attempting to fetch it remotely.\n * This prevents replays from appearing broken due to missing stylesheets.\n * Note: Inlining stylesheets may not work in all cases.\n */\n shouldInlineStylesheet?: boolean;\n version?: SessionReplayVersion;\n /**\n * Performance configuration config. If enabled, we will defer compression\n * to be done during the browser's idle periods.\n */\n performanceConfig?: SessionReplayPerformanceConfig;\n /**\n * Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events\n * when all events cannot be sent during capture. `memory` stores replay events only in memory,\n * meaning events are lost when the page is closed. If IndexedDB is unavailable, the system falls back to `memory`.\n */\n storeType: StoreType;\n\n /**\n * If true, the SDK will compress replay events using a web worker.\n * This offloads compression to a separate thread, improving performance on the main thread.\n *\n * @defaultValue false\n */\n useWebWorker?: boolean;\n\n userProperties?: { [key: string]: any };\n\n /**\n * Remove certain parts of the DOM from being captured. These are typically ignored when blocking by selectors.\n */\n omitElementTags?: {\n /**\n * If true, removes script tags from the DOM, but not noscript tags.\n */\n script?: boolean;\n /**\n * If true, removes comment tags from the DOM.\n */\n comment?: boolean;\n };\n\n /**\n * If true, applies a background color to blocked elements in the replay.\n * This helps visualize which elements are blocked from being captured.\n */\n applyBackgroundColorToBlockedElements?: boolean;\n /**\n * Enables URL change polling as a fallback for SPA route tracking.\n * When enabled, the SDK will periodically check for URL changes every second\n * in addition to patching the History API. This is useful for edge cases where\n * route changes might bypass the standard History API methods.\n *\n * @defaultValue false\n */\n enableUrlChangePolling?: boolean;\n /**\n * Specifies the interval in milliseconds for URL change polling when enableUrlChangePolling is true.\n * The SDK will check for URL changes at this interval as a fallback for SPA route tracking.\n *\n * @defaultValue 1000\n */\n urlChangePollingInterval?: number;\n /**\n * Whether to capture document title in URL change events.\n * When disabled, the title field will be empty in URL change events.\n *\n * @defaultValue false\n */\n captureDocumentTitle?: boolean;\n interactionConfig?: InteractionConfig;\n}\n\nexport interface SessionReplayJoinedConfig extends SessionReplayLocalConfig {\n captureEnabled?: boolean;\n interactionConfig?: InteractionConfig;\n loggingConfig?: LoggingConfig;\n targetingConfig?: TargetingConfig;\n}\n\nexport interface SessionReplayConfigs {\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n remoteConfig: SessionReplayRemoteConfig | undefined;\n}\nexport interface SessionReplayJoinedConfigGenerator {\n generateJoinedConfig: () => Promise<SessionReplayConfigs>;\n}\n\nexport interface SessionReplayMetadata {\n remoteConfig: SessionReplayRemoteConfig | undefined;\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n framework?: {\n name: string;\n version: string;\n };\n sessionId: string | number | undefined;\n hashValue?: number;\n sampleRate: number;\n replaySDKType: string | null;\n replaySDKVersion: string | undefined;\n standaloneSDKType: string;\n standaloneSDKVersion: string | undefined;\n}\n\nexport interface SessionReplayVersion {\n version: string;\n type: SessionReplayType;\n}\n\n/**\n * Configuration options for session replay performance.\n */\nexport interface SessionReplayPerformanceConfig {\n /**\n * If enabled, event compression will be deferred to occur during the browser's idle periods.\n */\n enabled: boolean;\n /**\n * Optional timeout in milliseconds for the `requestIdleCallback` API.\n * If specified, this value will be used to set a maximum time for the browser to wait\n * before executing the deferred compression task, even if the browser is not idle.\n */\n timeout?: number;\n /**\n * Performance configuration for interaction tracking (clicks, scrolls).\n */\n interaction?: InteractionPerformanceConfig;\n}\n\n/**\n * Performance configuration for interaction tracking, specifically for CSS selector generation.\n */\nexport interface InteractionPerformanceConfig {\n /**\n * Maximum time in milliseconds allowed for CSS selector generation.\n * If selector generation takes longer than this, it will throw a timeout error.\n * Default: undefined (no timeout limit)\n */\n timeoutMs?: number;\n /**\n * Maximum number of attempts to optimize/simplify the CSS selector path.\n * Higher values may produce shorter selectors but take longer to compute.\n * Default: 10000\n */\n maxNumberOfTries?: number;\n /**\n * Maximum number of CSS selector combinations to test for uniqueness.\n * If more combinations would be generated, falls back to a simpler strategy.\n * Default: 1000\n */\n threshold?: number;\n}\n\nexport type SessionReplayType = 'standalone' | 'plugin' | 'segment';\n"]}
@@ -1,6 +1,11 @@
1
- import { PrivacyConfig, SessionReplayJoinedConfig, UGCFilterRule } from './config/types';
1
+ import { MaskLevel, PrivacyConfig, SessionReplayJoinedConfig, UGCFilterRule } from './config/types';
2
2
  import { StorageData } from './typings/session-replay';
3
3
  export { getServerUrl } from './utils/server-url';
4
+ /**
5
+ * Returns the effective mask level for a given URL by checking `urlMaskLevels`
6
+ * (first match wins) and falling back to `defaultMaskLevel`.
7
+ */
8
+ export declare const getEffectiveMaskLevel: (url: string | undefined, config: PrivacyConfig) => MaskLevel;
4
9
  /**
5
10
  * Checks if the given element set to be masked by rrweb
6
11
  *
@@ -8,9 +13,9 @@ export { getServerUrl } from './utils/server-url';
8
13
  * 1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking
9
14
  * 2. Use app defaults
10
15
  */
11
- export declare const isMasked: (elementType: 'input' | 'text', config: PrivacyConfig | undefined, element: HTMLElement | null) => boolean;
12
- export declare const maskFn: (elementType: 'text' | 'input', config?: PrivacyConfig) => (text: string, element: HTMLElement | null) => string;
13
- export declare const maskAttributeFn: (config?: PrivacyConfig) => (key: string, value: string, element: HTMLElement) => string;
16
+ export declare const isMasked: (elementType: 'input' | 'text', config: PrivacyConfig | undefined, element: HTMLElement | null, currentUrl?: string) => boolean;
17
+ export declare const maskFn: (elementType: 'text' | 'input', config?: PrivacyConfig, getCurrentUrl?: () => string) => (text: string, element: HTMLElement | null) => string;
18
+ export declare const maskAttributeFn: (config?: PrivacyConfig, getCurrentUrl?: () => string) => (key: string, value: string, element: HTMLElement) => string;
14
19
  export declare const getCurrentUrl: () => string;
15
20
  export declare const generateSessionReplayId: (sessionId: string | number, deviceId: string) => string;
16
21
  export declare const validateUGCFilterRules: (ugcFilterRules: UGCFilterRule[]) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,aAAa,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAExH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA4ClD;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,gBACN,OAAO,GAAG,MAAM,8CAEpB,WAAW,GAAG,IAAI,KAC1B,OA2BF,CAAC;AAEF,eAAO,MAAM,MAAM,gBACH,MAAM,GAAG,OAAO,WAAW,aAAa,YAC/C,MAAM,WAAW,WAAW,GAAG,IAAI,KAAG,MAE5C,CAAC;AAEJ,eAAO,MAAM,eAAe,YAAa,aAAa,WACvC,MAAM,SAAS,MAAM,WAAW,WAAW,KAAG,MAY5D,CAAC;AAEF,eAAO,MAAM,aAAa,cAGzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,cAAe,MAAM,GAAG,MAAM,YAAY,MAAM,KAAG,MAEtF,CAAC;AAmBF,eAAO,MAAM,sBAAsB,mBAAoB,aAAa,EAAE,SAUrE,CAAC;AAEF,eAAO,MAAM,UAAU,YAAa,MAAM,kBAAkB,aAAa,EAAE,WAW1E,CAAC;AAEF,eAAO,MAAM,cAAc,QAAa,QAAQ,WAAW,CAa1D,CAAC;AAEF,eAAO,MAAM,cAAc,WAAY,yBAAyB,KAAG,yBAOlE,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,SAAS,EAAE,aAAa,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAExH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA8ClD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAS,MAAM,GAAG,SAAS,UAAU,aAAa,KAAG,SAStF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,gBACN,OAAO,GAAG,MAAM,8CAEpB,WAAW,GAAG,IAAI,eACd,MAAM,KAClB,OA2BF,CAAC;AAEF,eAAO,MAAM,MAAM,gBACH,MAAM,GAAG,OAAO,WAAW,aAAa,kBAAkB,MAAM,MAAM,YAC7E,MAAM,WAAW,WAAW,GAAG,IAAI,KAAG,MAE5C,CAAC;AAEJ,eAAO,MAAM,eAAe,YAAa,aAAa,kBAAkB,MAAM,MAAM,WACrE,MAAM,SAAS,MAAM,WAAW,WAAW,KAAG,MAa5D,CAAC;AAEF,eAAO,MAAM,aAAa,cAGzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,cAAe,MAAM,GAAG,MAAM,YAAY,MAAM,KAAG,MAEtF,CAAC;AAuDF,eAAO,MAAM,sBAAsB,mBAAoB,aAAa,EAAE,SAUrE,CAAC;AAEF,eAAO,MAAM,UAAU,YAAa,MAAM,kBAAkB,aAAa,EAAE,WAW1E,CAAC;AAEF,eAAO,MAAM,cAAc,QAAa,QAAQ,WAAW,CAa1D,CAAC;AAEF,eAAO,MAAM,cAAc,WAAY,yBAAyB,KAAG,yBAOlE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDebugConfig = exports.getStorageSize = exports.getPageUrl = exports.validateUGCFilterRules = exports.generateSessionReplayId = exports.getCurrentUrl = exports.maskAttributeFn = exports.maskFn = exports.isMasked = exports.getServerUrl = void 0;
3
+ exports.getDebugConfig = exports.getStorageSize = exports.getPageUrl = exports.validateUGCFilterRules = exports.generateSessionReplayId = exports.getCurrentUrl = exports.maskAttributeFn = exports.maskFn = exports.isMasked = exports.getEffectiveMaskLevel = exports.getServerUrl = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var analytics_core_1 = require("@amplitude/analytics-core");
6
6
  var types_1 = require("./config/types");
@@ -9,7 +9,7 @@ var get_input_type_1 = require("./utils/get-input-type");
9
9
  var server_url_1 = require("./utils/server-url");
10
10
  Object.defineProperty(exports, "getServerUrl", { enumerable: true, get: function () { return server_url_1.getServerUrl; } });
11
11
  /**
12
- * Light: Subset of inputs
12
+ * Light: Subset of inputs (sensitive types only — password, hidden, email, tel, cc-*)
13
13
  * Medium: All inputs
14
14
  * Conservative: All inputs and all texts
15
15
  */
@@ -17,7 +17,8 @@ var isMaskedForLevel = function (elementType, level, element) {
17
17
  switch (level) {
18
18
  case 'light': {
19
19
  if (elementType !== 'input') {
20
- return true;
20
+ // light only masks a subset of inputs; text nodes are not masked at this level.
21
+ return false;
21
22
  }
22
23
  var inputType = element ? (0, get_input_type_1.getInputType)(element) : '';
23
24
  /* istanbul ignore if */ // TODO(lew): For some reason it's impossible to test this.
@@ -33,12 +34,40 @@ var isMaskedForLevel = function (elementType, level, element) {
33
34
  return false;
34
35
  }
35
36
  case 'medium':
37
+ return elementType === 'input';
36
38
  case 'conservative':
37
39
  return true;
38
40
  default:
39
41
  return isMaskedForLevel(elementType, types_1.DEFAULT_MASK_LEVEL, element);
40
42
  }
41
43
  };
44
+ /**
45
+ * Returns the effective mask level for a given URL by checking `urlMaskLevels`
46
+ * (first match wins) and falling back to `defaultMaskLevel`.
47
+ */
48
+ var getEffectiveMaskLevel = function (url, config) {
49
+ var e_1, _a;
50
+ var _b;
51
+ if (url && config.urlMaskLevels) {
52
+ try {
53
+ for (var _c = tslib_1.__values(config.urlMaskLevels), _d = _c.next(); !_d.done; _d = _c.next()) {
54
+ var rule = _d.value;
55
+ if (globToRegex(rule.match).test(url)) {
56
+ return rule.maskLevel;
57
+ }
58
+ }
59
+ }
60
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
61
+ finally {
62
+ try {
63
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
64
+ }
65
+ finally { if (e_1) throw e_1.error; }
66
+ }
67
+ }
68
+ return (_b = config.defaultMaskLevel) !== null && _b !== void 0 ? _b : types_1.DEFAULT_MASK_LEVEL;
69
+ };
70
+ exports.getEffectiveMaskLevel = getEffectiveMaskLevel;
42
71
  /**
43
72
  * Checks if the given element set to be masked by rrweb
44
73
  *
@@ -46,8 +75,8 @@ var isMaskedForLevel = function (elementType, level, element) {
46
75
  * 1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking
47
76
  * 2. Use app defaults
48
77
  */
49
- var isMasked = function (elementType, config, element) {
50
- var _a, _b, _c;
78
+ var isMasked = function (elementType, config, element, currentUrl) {
79
+ var _a, _b;
51
80
  if (config === void 0) { config = { defaultMaskLevel: types_1.DEFAULT_MASK_LEVEL }; }
52
81
  if (element) {
53
82
  // Element or parent is explicitly instrumented in code to mask
@@ -70,16 +99,16 @@ var isMasked = function (elementType, config, element) {
70
99
  return false;
71
100
  }
72
101
  }
73
- return isMaskedForLevel(elementType, (_c = config.defaultMaskLevel) !== null && _c !== void 0 ? _c : types_1.DEFAULT_MASK_LEVEL, element);
102
+ return isMaskedForLevel(elementType, (0, exports.getEffectiveMaskLevel)(currentUrl, config), element);
74
103
  };
75
104
  exports.isMasked = isMasked;
76
- var maskFn = function (elementType, config) {
105
+ var maskFn = function (elementType, config, getCurrentUrl) {
77
106
  return function (text, element) {
78
- return (0, exports.isMasked)(elementType, config, element) ? text.replace(/[^\s]/g, '*') : text;
107
+ return (0, exports.isMasked)(elementType, config, element, getCurrentUrl === null || getCurrentUrl === void 0 ? void 0 : getCurrentUrl()) ? text.replace(/[^\s]/g, '*') : text;
79
108
  };
80
109
  };
81
110
  exports.maskFn = maskFn;
82
- var maskAttributeFn = function (config) {
111
+ var maskAttributeFn = function (config, getCurrentUrl) {
83
112
  return function (key, value, element) {
84
113
  var _a;
85
114
  // Never mask style — rrweb has a separate styleDiff path for attribute mutations
@@ -91,7 +120,8 @@ var maskAttributeFn = function (config) {
91
120
  return value;
92
121
  // Recompute masking every call so class/ancestor mutations do not stale-cache
93
122
  // the decision for later attribute mutations on the same element.
94
- return (0, exports.isMasked)('text', config, element) ? value.replace(/[^\s]/g, '*') : value;
123
+ var elementType = ['INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) ? 'input' : 'text';
124
+ return (0, exports.isMasked)(elementType, config, element, getCurrentUrl === null || getCurrentUrl === void 0 ? void 0 : getCurrentUrl()) ? value.replace(/[^\s]/g, '*') : value;
95
125
  };
96
126
  };
97
127
  exports.maskAttributeFn = maskAttributeFn;
@@ -112,13 +142,45 @@ var isValidGlobUrl = function (globUrl) {
112
142
  return false;
113
143
  return true;
114
144
  };
145
+ var globRegexCache = new Map();
115
146
  var globToRegex = function (glob) {
116
- // Escape special regex characters, then convert globs
117
- var escaped = glob
118
- .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex specials
119
- .replace(/\*/g, '.*') // Convert * to .*
120
- .replace(/\?/g, '.'); // Convert ? to .
121
- return new RegExp("^".concat(escaped, "$"));
147
+ var cached = globRegexCache.get(glob);
148
+ if (cached)
149
+ return cached;
150
+ // Glob → regex conversion. Glob substitution must happen BEFORE regex escaping so that
151
+ // the escaper does not corrupt the glob characters (e.g. turning `/**` into `/\*\*`).
152
+ // Placeholder tokens use null bytes, which are illegal in HTTP URLs and therefore can
153
+ // never collide with real pattern content.
154
+ //
155
+ // Substitution order (most-specific first):
156
+ // trailing /** → (/.*)? — path with or without a trailing slash/subpath
157
+ // middle /**/ → /(.*\/)? — zero-or-more path segments (including zero)
158
+ // bare ** → .* — graceful fallback for ** not adjacent to /
159
+ // single * → .* — any characters (preserves existing behaviour)
160
+ // ? → . — single character wildcard
161
+ var T_TRAILING = '\x00TRAIL\x00';
162
+ var T_MIDDLE = '\x00MID\x00';
163
+ var T_DSTAR = '\x00DS\x00';
164
+ var T_STAR = '\x00ST\x00';
165
+ var T_QUEST = '\x00QU\x00';
166
+ var s = glob;
167
+ s = s.replace(/\/\*\*$/, T_TRAILING); // trailing /**
168
+ s = s.replace(/\/\*\*\//g, T_MIDDLE); // /**/ in the middle
169
+ s = s.replace(/\*\*/g, T_DSTAR); // bare ** (e.g. **.example.com)
170
+ s = s.replace(/\*/g, T_STAR); // single *
171
+ s = s.replace(/\?/g, T_QUEST); // ?
172
+ // Escape all remaining regex special characters.
173
+ s = s.replace(/[.+^${}()|[\]\\]/g, '\\$&');
174
+ // Expand tokens into their regex equivalents.
175
+ // Use split/join (not regex) to avoid the no-control-regex lint rule on the token strings.
176
+ s = s.split(T_TRAILING).join('(/.*)?'); // /** → optional /anything
177
+ s = s.split(T_MIDDLE).join('/(.*\\/)?'); // /**/ → /zero-or-more-segments/
178
+ s = s.split(T_DSTAR).join('.*'); // bare ** → .*
179
+ s = s.split(T_STAR).join('.*'); // * → .*
180
+ s = s.split(T_QUEST).join('.'); // ? → .
181
+ var regex = new RegExp("^".concat(s, "$"));
182
+ globRegexCache.set(glob, regex);
183
+ return regex;
122
184
  };
123
185
  var validateUGCFilterRules = function (ugcFilterRules) {
124
186
  // validate ugcFilterRules
@@ -132,7 +194,7 @@ var validateUGCFilterRules = function (ugcFilterRules) {
132
194
  };
133
195
  exports.validateUGCFilterRules = validateUGCFilterRules;
134
196
  var getPageUrl = function (pageUrl, ugcFilterRules) {
135
- var e_1, _a;
197
+ var e_2, _a;
136
198
  try {
137
199
  // apply ugcFilterRules, order is important, first rule wins
138
200
  for (var ugcFilterRules_1 = tslib_1.__values(ugcFilterRules), ugcFilterRules_1_1 = ugcFilterRules_1.next(); !ugcFilterRules_1_1.done; ugcFilterRules_1_1 = ugcFilterRules_1.next()) {
@@ -143,18 +205,18 @@ var getPageUrl = function (pageUrl, ugcFilterRules) {
143
205
  }
144
206
  }
145
207
  }
146
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
208
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
147
209
  finally {
148
210
  try {
149
211
  if (ugcFilterRules_1_1 && !ugcFilterRules_1_1.done && (_a = ugcFilterRules_1.return)) _a.call(ugcFilterRules_1);
150
212
  }
151
- finally { if (e_1) throw e_1.error; }
213
+ finally { if (e_2) throw e_2.error; }
152
214
  }
153
215
  return pageUrl;
154
216
  };
155
217
  exports.getPageUrl = getPageUrl;
156
218
  var getStorageSize = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
157
- var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota, e_2;
219
+ var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota, e_3;
158
220
  return tslib_1.__generator(this, function (_b) {
159
221
  switch (_b.label) {
160
222
  case 0:
@@ -169,7 +231,7 @@ var getStorageSize = function () { return tslib_1.__awaiter(void 0, void 0, void
169
231
  return [2 /*return*/, { totalStorageSize: totalStorageSize, percentOfQuota: percentOfQuota, usageDetails: JSON.stringify(usageDetails) }];
170
232
  case 2: return [3 /*break*/, 4];
171
233
  case 3:
172
- e_2 = _b.sent();
234
+ e_3 = _b.sent();
173
235
  return [3 /*break*/, 4];
174
236
  case 4: return [2 /*return*/, { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' }];
175
237
  }
@@ -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\n * Medium: All inputs\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 true;\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 case 'conservative':\n return true;\n default:\n return isMaskedForLevel(elementType, DEFAULT_MASK_LEVEL, element);\n }\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): 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, config.defaultMaskLevel ?? DEFAULT_MASK_LEVEL, element);\n};\n\nexport const maskFn =\n (elementType: 'text' | 'input', config?: PrivacyConfig) =>\n (text: string, element: HTMLElement | null): string => {\n return isMasked(elementType, config, element) ? text.replace(/[^\\s]/g, '*') : text;\n };\n\nexport const maskAttributeFn = (config?: PrivacyConfig) => {\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 // Recompute masking every call so class/ancestor mutations do not stale-cache\n // the decision for later attribute mutations on the same element.\n return isMasked('text', config, element) ? 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 globToRegex = (glob: string): RegExp => {\n // Escape special regex characters, then convert globs\n const escaped = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex specials\n .replace(/\\*/g, '.*') // Convert * to .*\n .replace(/\\?/g, '.'); // Convert ? to .\n\n return new RegExp(`^${escaped}$`);\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 { 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\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 // light only masks a subset of inputs; text nodes are not masked at this level.\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 // Recompute masking every call so class/ancestor mutations do not stale-cache\n // the decision for later attribute mutations on the same element.\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"]}
@@ -24,6 +24,8 @@ export declare class SessionReplay implements AmplitudeSessionReplay {
24
24
  private networkObservers?;
25
25
  private metadata;
26
26
  private recordFunction;
27
+ /** Current page URL, kept in sync with SPA navigations for URL-based masking */
28
+ private currentPageUrl;
27
29
  /** Cleanup for URL change listener used to re-evaluate targeting on SPA route changes */
28
30
  private urlChangeCleanup;
29
31
  /** Monotonic counter to ignore stale URL-change targeting results */
@@ -32,10 +34,11 @@ export declare class SessionReplay implements AmplitudeSessionReplay {
32
34
  init(apiKey: string, options: SessionReplayOptions): import("@amplitude/analytics-core").AmplitudeReturn<void>;
33
35
  private teardownEventListeners;
34
36
  /**
35
- * Subscribes to SPA URL changes via the URL tracking plugin and re-evaluates targeting so we
36
- * can start/stop recording when the user navigates to a page that matches or no longer matches.
37
+ * Subscribes to SPA URL changes via the URL tracking plugin. Always keeps
38
+ * `currentPageUrl` in sync (needed for URL-based masking). When a targeting
39
+ * config is present it also re-evaluates targeting on every navigation.
37
40
  */
38
- private setupUrlChangeListenerForTargeting;
41
+ private setupUrlChangeListener;
39
42
  private getCurrentPageForTargeting;
40
43
  protected _init(apiKey: string, options: SessionReplayOptions): Promise<void>;
41
44
  setSessionId(sessionId: string | number, deviceId?: string): import("@amplitude/analytics-core").AmplitudeReturn<void>;
@@ -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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"}