@sentry/replay 7.51.0 → 7.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.
package/cjs/index.js CHANGED
@@ -75,7 +75,7 @@ function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInp
75
75
  if (unmaskInputSelector && input.matches(unmaskInputSelector)) {
76
76
  return text;
77
77
  }
78
- if (input.hasAttribute('rr_is_password')) {
78
+ if (input.hasAttribute('data-rr-is-password')) {
79
79
  type = 'password';
80
80
  }
81
81
  if (isInputTypeMasked({ maskInputOptions, tagName, type }) ||
@@ -108,6 +108,21 @@ function is2DCanvasBlank(canvas) {
108
108
  }
109
109
  return true;
110
110
  }
111
+ function getInputType(element) {
112
+ const type = element.type;
113
+ return element.hasAttribute('data-rr-is-password')
114
+ ? 'password'
115
+ : type
116
+ ? type.toLowerCase()
117
+ : null;
118
+ }
119
+ function getInputValue(el, tagName, type) {
120
+ typeof type === 'string' ? type.toLowerCase() : '';
121
+ if (tagName === 'INPUT' && (type === 'radio' || type === 'checkbox')) {
122
+ return el.getAttribute('value') || '';
123
+ }
124
+ return el.value;
125
+ }
111
126
 
112
127
  let _id = 1;
113
128
  const tagNameRegex = new RegExp('[^a-z0-9-_:]');
@@ -146,6 +161,13 @@ function getCssRuleString(rule) {
146
161
  catch (_a) {
147
162
  }
148
163
  }
164
+ return validateStringifiedCssRule(cssStringified);
165
+ }
166
+ function validateStringifiedCssRule(cssStringified) {
167
+ if (cssStringified.indexOf(':') > -1) {
168
+ const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
169
+ return cssStringified.replace(regex, '$1\\$2');
170
+ }
149
171
  return cssStringified;
150
172
  }
151
173
  function isCSSImportRule(rule) {
@@ -154,7 +176,7 @@ function isCSSImportRule(rule) {
154
176
  function stringifyStyleSheet(sheet) {
155
177
  return sheet.cssRules
156
178
  ? Array.from(sheet.cssRules)
157
- .map((rule) => rule.cssText || '')
179
+ .map((rule) => rule.cssText ? validateStringifiedCssRule(rule.cssText) : '')
158
180
  .join('')
159
181
  : '';
160
182
  }
@@ -489,14 +511,15 @@ function serializeNode(n, options) {
489
511
  tagName === 'select' ||
490
512
  tagName === 'option') {
491
513
  const el = n;
492
- const value = getInputValue(tagName, el, attributes);
514
+ const type = getInputType(el);
515
+ const value = getInputValue(el, tagName.toUpperCase(), type);
493
516
  const checked = n.checked;
494
- if (attributes.type !== 'submit' &&
495
- attributes.type !== 'button' &&
517
+ if (type !== 'submit' &&
518
+ type !== 'button' &&
496
519
  value) {
497
520
  attributes.value = maskInputValue({
498
521
  input: el,
499
- type: attributes.type,
522
+ type,
500
523
  tagName,
501
524
  value,
502
525
  maskInputSelector,
@@ -969,15 +992,8 @@ function snapshot(n, options) {
969
992
  function skipAttribute(tagName, attributeName, value) {
970
993
  return ((tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay');
971
994
  }
972
- function getInputValue(tagName, el, attributes) {
973
- if (tagName === 'input' &&
974
- (attributes.type === 'radio' || attributes.type === 'checkbox')) {
975
- return el.getAttribute('value') || '';
976
- }
977
- return el.value;
978
- }
979
995
 
980
- var EventType;
996
+ var EventType$1;
981
997
  (function (EventType) {
982
998
  EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
983
999
  EventType[EventType["Load"] = 1] = "Load";
@@ -986,7 +1002,7 @@ var EventType;
986
1002
  EventType[EventType["Meta"] = 4] = "Meta";
987
1003
  EventType[EventType["Custom"] = 5] = "Custom";
988
1004
  EventType[EventType["Plugin"] = 6] = "Plugin";
989
- })(EventType || (EventType = {}));
1005
+ })(EventType$1 || (EventType$1 = {}));
990
1006
  var IncrementalSource;
991
1007
  (function (IncrementalSource) {
992
1008
  IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
@@ -1601,9 +1617,9 @@ class MutationBuffer {
1601
1617
  this.attributes.push(item);
1602
1618
  }
1603
1619
  if (m.attributeName === 'type' &&
1604
- m.target.tagName === 'INPUT' &&
1620
+ target.tagName === 'INPUT' &&
1605
1621
  (m.oldValue || '').toLowerCase() === 'password') {
1606
- m.target.setAttribute('rr_is_password', 'true');
1622
+ target.setAttribute('data-rr-is-password', 'true');
1607
1623
  }
1608
1624
  if (m.attributeName === 'style') {
1609
1625
  const old = this.doc.createElement('span');
@@ -2000,27 +2016,25 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
2000
2016
  isBlocked(target, blockClass, blockSelector, unblockSelector)) {
2001
2017
  return;
2002
2018
  }
2003
- let type = target.type;
2004
- if (target.classList.contains(ignoreClass) ||
2005
- (ignoreSelector && target.matches(ignoreSelector))) {
2019
+ const el = target;
2020
+ const type = getInputType(el);
2021
+ if (el.classList.contains(ignoreClass) ||
2022
+ (ignoreSelector && el.matches(ignoreSelector))) {
2006
2023
  return;
2007
2024
  }
2008
- let text = target.value;
2025
+ let text = getInputValue(el, tagName, type);
2009
2026
  let isChecked = false;
2010
- if (target.hasAttribute('rr_is_password')) {
2011
- type = 'password';
2012
- }
2013
2027
  if (type === 'radio' || type === 'checkbox') {
2014
2028
  isChecked = target.checked;
2015
2029
  }
2016
- else if (hasInputMaskOptions({
2030
+ if (hasInputMaskOptions({
2017
2031
  maskInputOptions,
2018
2032
  maskInputSelector,
2019
2033
  tagName,
2020
2034
  type,
2021
2035
  })) {
2022
2036
  text = maskInputValue({
2023
- input: target,
2037
+ input: el,
2024
2038
  maskInputOptions,
2025
2039
  maskInputSelector,
2026
2040
  unmaskInputSelector,
@@ -2037,8 +2051,18 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
2037
2051
  .querySelectorAll(`input[type="radio"][name="${name}"]`)
2038
2052
  .forEach((el) => {
2039
2053
  if (el !== target) {
2054
+ const text = maskInputValue({
2055
+ input: el,
2056
+ maskInputOptions,
2057
+ maskInputSelector,
2058
+ unmaskInputSelector,
2059
+ tagName,
2060
+ type,
2061
+ value: getInputValue(el, tagName, type),
2062
+ maskInputFn,
2063
+ });
2040
2064
  cbWithDedup(el, callbackWrapper(wrapEventWithUserTriggeredFlag)({
2041
- text: el.value,
2065
+ text,
2042
2066
  isChecked: !isChecked,
2043
2067
  userTriggered: false,
2044
2068
  }, userTriggeredOnInput));
@@ -2951,17 +2975,17 @@ function record(options = {}) {
2951
2975
  wrappedEmit = (e, isCheckout) => {
2952
2976
  var _a;
2953
2977
  if (((_a = mutationBuffers[0]) === null || _a === void 0 ? void 0 : _a.isFrozen()) &&
2954
- e.type !== EventType.FullSnapshot &&
2955
- !(e.type === EventType.IncrementalSnapshot &&
2978
+ e.type !== EventType$1.FullSnapshot &&
2979
+ !(e.type === EventType$1.IncrementalSnapshot &&
2956
2980
  e.data.source === IncrementalSource.Mutation)) {
2957
2981
  mutationBuffers.forEach((buf) => buf.unfreeze());
2958
2982
  }
2959
2983
  emit(eventProcessor(e), isCheckout);
2960
- if (e.type === EventType.FullSnapshot) {
2984
+ if (e.type === EventType$1.FullSnapshot) {
2961
2985
  lastFullSnapshotEvent = e;
2962
2986
  incrementalSnapshotCount = 0;
2963
2987
  }
2964
- else if (e.type === EventType.IncrementalSnapshot) {
2988
+ else if (e.type === EventType$1.IncrementalSnapshot) {
2965
2989
  if (e.data.source === IncrementalSource.Mutation &&
2966
2990
  e.data.isAttachIframe) {
2967
2991
  return;
@@ -2977,16 +3001,16 @@ function record(options = {}) {
2977
3001
  };
2978
3002
  const wrappedMutationEmit = (m) => {
2979
3003
  wrappedEmit(wrapEvent({
2980
- type: EventType.IncrementalSnapshot,
3004
+ type: EventType$1.IncrementalSnapshot,
2981
3005
  data: Object.assign({ source: IncrementalSource.Mutation }, m),
2982
3006
  }));
2983
3007
  };
2984
3008
  const wrappedScrollEmit = (p) => wrappedEmit(wrapEvent({
2985
- type: EventType.IncrementalSnapshot,
3009
+ type: EventType$1.IncrementalSnapshot,
2986
3010
  data: Object.assign({ source: IncrementalSource.Scroll }, p),
2987
3011
  }));
2988
3012
  const wrappedCanvasMutationEmit = (p) => wrappedEmit(wrapEvent({
2989
- type: EventType.IncrementalSnapshot,
3013
+ type: EventType$1.IncrementalSnapshot,
2990
3014
  data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
2991
3015
  }));
2992
3016
  const iframeManager = new IframeManager({
@@ -3031,7 +3055,7 @@ function record(options = {}) {
3031
3055
  takeFullSnapshot = (isCheckout = false) => {
3032
3056
  var _a, _b, _c, _d;
3033
3057
  wrappedEmit(wrapEvent({
3034
- type: EventType.Meta,
3058
+ type: EventType$1.Meta,
3035
3059
  data: {
3036
3060
  href: window.location.href,
3037
3061
  width: getWindowWidth(),
@@ -3074,7 +3098,7 @@ function record(options = {}) {
3074
3098
  }
3075
3099
  mirror.map = idNodeMap;
3076
3100
  wrappedEmit(wrapEvent({
3077
- type: EventType.FullSnapshot,
3101
+ type: EventType$1.FullSnapshot,
3078
3102
  data: {
3079
3103
  node,
3080
3104
  initialOffset: {
@@ -3099,7 +3123,7 @@ function record(options = {}) {
3099
3123
  const handlers = [];
3100
3124
  handlers.push(on('DOMContentLoaded', () => {
3101
3125
  wrappedEmit(wrapEvent({
3102
- type: EventType.DomContentLoaded,
3126
+ type: EventType$1.DomContentLoaded,
3103
3127
  data: {},
3104
3128
  }));
3105
3129
  }));
@@ -3109,40 +3133,40 @@ function record(options = {}) {
3109
3133
  onMutation,
3110
3134
  mutationCb: wrappedMutationEmit,
3111
3135
  mousemoveCb: (positions, source) => wrappedEmit(wrapEvent({
3112
- type: EventType.IncrementalSnapshot,
3136
+ type: EventType$1.IncrementalSnapshot,
3113
3137
  data: {
3114
3138
  source,
3115
3139
  positions,
3116
3140
  },
3117
3141
  })),
3118
3142
  mouseInteractionCb: (d) => wrappedEmit(wrapEvent({
3119
- type: EventType.IncrementalSnapshot,
3143
+ type: EventType$1.IncrementalSnapshot,
3120
3144
  data: Object.assign({ source: IncrementalSource.MouseInteraction }, d),
3121
3145
  })),
3122
3146
  scrollCb: wrappedScrollEmit,
3123
3147
  viewportResizeCb: (d) => wrappedEmit(wrapEvent({
3124
- type: EventType.IncrementalSnapshot,
3148
+ type: EventType$1.IncrementalSnapshot,
3125
3149
  data: Object.assign({ source: IncrementalSource.ViewportResize }, d),
3126
3150
  })),
3127
3151
  inputCb: (v) => wrappedEmit(wrapEvent({
3128
- type: EventType.IncrementalSnapshot,
3152
+ type: EventType$1.IncrementalSnapshot,
3129
3153
  data: Object.assign({ source: IncrementalSource.Input }, v),
3130
3154
  })),
3131
3155
  mediaInteractionCb: (p) => wrappedEmit(wrapEvent({
3132
- type: EventType.IncrementalSnapshot,
3156
+ type: EventType$1.IncrementalSnapshot,
3133
3157
  data: Object.assign({ source: IncrementalSource.MediaInteraction }, p),
3134
3158
  })),
3135
3159
  styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({
3136
- type: EventType.IncrementalSnapshot,
3160
+ type: EventType$1.IncrementalSnapshot,
3137
3161
  data: Object.assign({ source: IncrementalSource.StyleSheetRule }, r),
3138
3162
  })),
3139
3163
  styleDeclarationCb: (r) => wrappedEmit(wrapEvent({
3140
- type: EventType.IncrementalSnapshot,
3164
+ type: EventType$1.IncrementalSnapshot,
3141
3165
  data: Object.assign({ source: IncrementalSource.StyleDeclaration }, r),
3142
3166
  })),
3143
3167
  canvasMutationCb: wrappedCanvasMutationEmit,
3144
3168
  fontCb: (p) => wrappedEmit(wrapEvent({
3145
- type: EventType.IncrementalSnapshot,
3169
+ type: EventType$1.IncrementalSnapshot,
3146
3170
  data: Object.assign({ source: IncrementalSource.Font }, p),
3147
3171
  })),
3148
3172
  blockClass,
@@ -3175,7 +3199,7 @@ function record(options = {}) {
3175
3199
  observer: p.observer,
3176
3200
  options: p.options,
3177
3201
  callback: (payload) => wrappedEmit(wrapEvent({
3178
- type: EventType.Plugin,
3202
+ type: EventType$1.Plugin,
3179
3203
  data: {
3180
3204
  plugin: p.name,
3181
3205
  payload,
@@ -3203,7 +3227,7 @@ function record(options = {}) {
3203
3227
  else {
3204
3228
  handlers.push(on('load', () => {
3205
3229
  wrappedEmit(wrapEvent({
3206
- type: EventType.Load,
3230
+ type: EventType$1.Load,
3207
3231
  data: {},
3208
3232
  }));
3209
3233
  init();
@@ -3222,7 +3246,7 @@ record.addCustomEvent = (tag, payload) => {
3222
3246
  throw new Error('please add custom event after start recording');
3223
3247
  }
3224
3248
  wrappedEmit(wrapEvent({
3225
- type: EventType.Custom,
3249
+ type: EventType$1.Custom,
3226
3250
  data: {
3227
3251
  tag,
3228
3252
  payload,
@@ -3401,6 +3425,11 @@ class EventBufferArray {
3401
3425
  return this.events.length > 0;
3402
3426
  }
3403
3427
 
3428
+ /** @inheritdoc */
3429
+ get type() {
3430
+ return 'sync';
3431
+ }
3432
+
3404
3433
  /** @inheritdoc */
3405
3434
  destroy() {
3406
3435
  this.events = [];
@@ -3556,6 +3585,11 @@ class EventBufferCompressionWorker {
3556
3585
  return !!this._earliestTimestamp;
3557
3586
  }
3558
3587
 
3588
+ /** @inheritdoc */
3589
+ get type() {
3590
+ return 'worker';
3591
+ }
3592
+
3559
3593
  /**
3560
3594
  * Ensure the worker is ready (or not).
3561
3595
  * This will either resolve when the worker is ready, or reject if an error occured.
@@ -3638,6 +3672,11 @@ class EventBufferProxy {
3638
3672
  this._ensureWorkerIsLoadedPromise = this._ensureWorkerIsLoaded();
3639
3673
  }
3640
3674
 
3675
+ /** @inheritdoc */
3676
+ get type() {
3677
+ return this._used.type;
3678
+ }
3679
+
3641
3680
  /** @inheritDoc */
3642
3681
  get hasEvents() {
3643
3682
  return this._used.hasEvents;
@@ -4043,22 +4082,18 @@ function handleAfterSendEvent(replay) {
4043
4082
  return;
4044
4083
  }
4045
4084
 
4046
- // Add error to list of errorIds of replay
4085
+ // Add error to list of errorIds of replay. This is ok to do even if not
4086
+ // sampled because context will get reset at next checkout.
4087
+ // XXX: There is also a race condition where it's possible to capture an
4088
+ // error to Sentry before Replay SDK has loaded, but response returns after
4089
+ // it was loaded, and this gets called.
4047
4090
  if (event.event_id) {
4048
4091
  replay.getContext().errorIds.add(event.event_id);
4049
4092
  }
4050
4093
 
4051
- // Trigger error recording
4094
+ // If error event is tagged with replay id it means it was sampled (when in buffer mode)
4052
4095
  // Need to be very careful that this does not cause an infinite loop
4053
- if (
4054
- replay.recordingMode === 'buffer' &&
4055
- event.exception &&
4056
- event.message !== UNABLE_TO_SEND_REPLAY // ignore this error because otherwise we could loop indefinitely with trying to capture replay and failing
4057
- ) {
4058
- if (!isSampled(replay.getOptions().errorSampleRate)) {
4059
- return;
4060
- }
4061
-
4096
+ if (replay.recordingMode === 'buffer' && event.tags && event.tags.replayId) {
4062
4097
  setTimeout(() => {
4063
4098
  // Capture current event buffer as new replay
4064
4099
  void replay.sendBufferedReplayOrFlush();
@@ -4122,7 +4157,7 @@ function addBreadcrumbEvent(replay, breadcrumb) {
4122
4157
 
4123
4158
  replay.addUpdate(() => {
4124
4159
  void addEvent(replay, {
4125
- type: EventType.Custom,
4160
+ type: EventType$1.Custom,
4126
4161
  // TODO: We were converting from ms to seconds for breadcrumbs, spans,
4127
4162
  // but maybe we should just keep them as milliseconds
4128
4163
  timestamp: (breadcrumb.timestamp || 0) * 1000,
@@ -4190,15 +4225,18 @@ const handleDomListener =
4190
4225
 
4191
4226
  /**
4192
4227
  * An event handler to react to DOM events.
4228
+ * Exported for tests only.
4193
4229
  */
4194
4230
  function handleDom(handlerData) {
4195
4231
  let target;
4196
4232
  let targetNode;
4197
4233
 
4234
+ const isClick = handlerData.name === 'click';
4235
+
4198
4236
  // Accessing event.target can throw (see getsentry/raven-js#838, #768)
4199
4237
  try {
4200
- targetNode = getTargetNode(handlerData);
4201
- target = utils.htmlTreeAsString(targetNode);
4238
+ targetNode = isClick ? getClickTargetNode(handlerData.event) : getTargetNode(handlerData.event);
4239
+ target = utils.htmlTreeAsString(targetNode, { maxStringLength: 200 });
4202
4240
  } catch (e) {
4203
4241
  target = '<unknown>';
4204
4242
  }
@@ -4232,12 +4270,29 @@ function handleDom(handlerData) {
4232
4270
  });
4233
4271
  }
4234
4272
 
4235
- function getTargetNode(handlerData) {
4236
- if (isEventWithTarget(handlerData.event)) {
4237
- return handlerData.event.target;
4273
+ function getTargetNode(event) {
4274
+ if (isEventWithTarget(event)) {
4275
+ return event.target;
4238
4276
  }
4239
4277
 
4240
- return handlerData.event;
4278
+ return event;
4279
+ }
4280
+
4281
+ const INTERACTIVE_SELECTOR = 'button,a';
4282
+
4283
+ // For clicks, we check if the target is inside of a button or link
4284
+ // If so, we use this as the target instead
4285
+ // This is useful because if you click on the image in <button><img></button>,
4286
+ // The target will be the image, not the button, which we don't want here
4287
+ function getClickTargetNode(event) {
4288
+ const target = getTargetNode(event);
4289
+
4290
+ if (!target || !(target instanceof Element)) {
4291
+ return target;
4292
+ }
4293
+
4294
+ const closestInteractive = target.closest(INTERACTIVE_SELECTOR);
4295
+ return closestInteractive || target;
4241
4296
  }
4242
4297
 
4243
4298
  function isEventWithTarget(event) {
@@ -4267,6 +4322,30 @@ function isRrwebError(event, hint) {
4267
4322
  });
4268
4323
  }
4269
4324
 
4325
+ /**
4326
+ * Determine if event should be sampled (only applies in buffer mode).
4327
+ * When an event is captured by `hanldleGlobalEvent`, when in buffer mode
4328
+ * we determine if we want to sample the error or not.
4329
+ */
4330
+ function shouldSampleForBufferEvent(replay, event) {
4331
+ if (replay.recordingMode !== 'buffer') {
4332
+ return false;
4333
+ }
4334
+
4335
+ // ignore this error because otherwise we could loop indefinitely with
4336
+ // trying to capture replay and failing
4337
+ if (event.message === UNABLE_TO_SEND_REPLAY) {
4338
+ return false;
4339
+ }
4340
+
4341
+ // Require the event to be an error event & to have an exception
4342
+ if (!event.exception || event.type) {
4343
+ return false;
4344
+ }
4345
+
4346
+ return isSampled(replay.getOptions().errorSampleRate);
4347
+ }
4348
+
4270
4349
  /**
4271
4350
  * Returns a listener to be added to `addGlobalEventProcessor(listener)`.
4272
4351
  */
@@ -4296,8 +4375,16 @@ function handleGlobalEventListener(
4296
4375
  return null;
4297
4376
  }
4298
4377
 
4299
- // Only tag transactions with replayId if not waiting for an error
4300
- if (isErrorEvent(event) || (isTransactionEvent(event) && replay.recordingMode === 'session')) {
4378
+ // When in buffer mode, we decide to sample here.
4379
+ // Later, in `handleAfterSendEvent`, if the replayId is set, we know that we sampled
4380
+ // And convert the buffer session to a full session
4381
+ const isErrorEventSampled = shouldSampleForBufferEvent(replay, event);
4382
+
4383
+ // Tag errors if it has been sampled in buffer mode, or if it is session mode
4384
+ // Only tag transactions if in session mode
4385
+ const shouldTagReplayId = isErrorEventSampled || replay.recordingMode === 'session';
4386
+
4387
+ if (shouldTagReplayId) {
4301
4388
  event.tags = { ...event.tags, replayId: replay.getSessionId() };
4302
4389
  }
4303
4390
 
@@ -4347,7 +4434,7 @@ function createPerformanceSpans(
4347
4434
  ) {
4348
4435
  return entries.map(({ type, start, end, name, data }) =>
4349
4436
  addEvent(replay, {
4350
- type: EventType.Custom,
4437
+ type: EventType$1.Custom,
4351
4438
  timestamp: start,
4352
4439
  data: {
4353
4440
  tag: 'performanceSpan',
@@ -5960,6 +6047,23 @@ function debounce(func, wait, options) {
5960
6047
  return debounced;
5961
6048
  }
5962
6049
 
6050
+ /* eslint-disable @typescript-eslint/naming-convention */
6051
+
6052
+ var EventType; (function (EventType) {
6053
+ const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
6054
+ const Load = 1; EventType[EventType["Load"] = Load] = "Load";
6055
+ const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
6056
+ const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
6057
+ const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
6058
+ const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
6059
+ const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
6060
+ })(EventType || (EventType = {}));
6061
+
6062
+ /**
6063
+ * This is a partial copy of rrweb's eventWithTime type which only contains the properties
6064
+ * we specifcally need in the SDK.
6065
+ */
6066
+
5963
6067
  /**
5964
6068
  * Handler for recording events.
5965
6069
  *
@@ -6002,6 +6106,14 @@ function getHandleRecordingEmit(replay) {
6002
6106
  return false;
6003
6107
  }
6004
6108
 
6109
+ // Additionally, create a meta event that will capture certain SDK settings.
6110
+ // In order to handle buffer mode, this needs to either be done when we
6111
+ // receive checkout events or at flush time.
6112
+ //
6113
+ // `isCheckout` is always true, but want to be explicit that it should
6114
+ // only be added for checkouts
6115
+ void addSettingsEvent(replay, isCheckout);
6116
+
6005
6117
  // If there is a previousSessionId after a full snapshot occurs, then
6006
6118
  // the replay session was started due to session expiration. The new session
6007
6119
  // is started before triggering a new checkout and contains the id
@@ -6039,6 +6151,46 @@ function getHandleRecordingEmit(replay) {
6039
6151
  };
6040
6152
  }
6041
6153
 
6154
+ /**
6155
+ * Exported for tests
6156
+ */
6157
+ function createOptionsEvent(replay) {
6158
+ const options = replay.getOptions();
6159
+ return {
6160
+ type: EventType.Custom,
6161
+ timestamp: Date.now(),
6162
+ data: {
6163
+ tag: 'options',
6164
+ payload: {
6165
+ sessionSampleRate: options.sessionSampleRate,
6166
+ errorSampleRate: options.errorSampleRate,
6167
+ useCompressionOption: options.useCompression,
6168
+ blockAllMedia: options.blockAllMedia,
6169
+ maskAllText: options.maskAllText,
6170
+ maskAllInputs: options.maskAllInputs,
6171
+ useCompression: replay.eventBuffer ? replay.eventBuffer.type === 'worker' : false,
6172
+ networkDetailHasUrls: options.networkDetailAllowUrls.length > 0,
6173
+ networkCaptureBodies: options.networkCaptureBodies,
6174
+ networkRequestHasHeaders: options.networkRequestHeaders.length > 0,
6175
+ networkResponseHasHeaders: options.networkResponseHeaders.length > 0,
6176
+ },
6177
+ },
6178
+ };
6179
+ }
6180
+
6181
+ /**
6182
+ * Add a "meta" event that contains a simplified view on current configuration
6183
+ * options. This should only be included on the first segment of a recording.
6184
+ */
6185
+ function addSettingsEvent(replay, isCheckout) {
6186
+ // Only need to add this event when sending the first segment
6187
+ if (!isCheckout || !replay.session || replay.session.segmentId !== 0) {
6188
+ return Promise.resolve(null);
6189
+ }
6190
+
6191
+ return addEvent(replay, createOptionsEvent(replay), false);
6192
+ }
6193
+
6042
6194
  /**
6043
6195
  * Create a replay envelope ready to be sent.
6044
6196
  * This includes both the replay event, as well as the recording data.
@@ -6153,7 +6305,6 @@ async function sendReplayRequest({
6153
6305
  eventContext,
6154
6306
  timestamp,
6155
6307
  session,
6156
- options,
6157
6308
  }) {
6158
6309
  const preparedRecordingData = prepareRecordingData({
6159
6310
  recordingData,
@@ -6195,15 +6346,6 @@ async function sendReplayRequest({
6195
6346
  return;
6196
6347
  }
6197
6348
 
6198
- replayEvent.contexts = {
6199
- ...replayEvent.contexts,
6200
- replay: {
6201
- ...(replayEvent.contexts && replayEvent.contexts.replay),
6202
- session_sample_rate: options.sessionSampleRate,
6203
- error_sample_rate: options.errorSampleRate,
6204
- },
6205
- };
6206
-
6207
6349
  /*
6208
6350
  For reference, the fully built event looks something like this:
6209
6351
  {
@@ -6234,10 +6376,6 @@ async function sendReplayRequest({
6234
6376
  },
6235
6377
  "sdkProcessingMetadata": {},
6236
6378
  "contexts": {
6237
- "replay": {
6238
- "session_sample_rate": 1,
6239
- "error_sample_rate": 0,
6240
- },
6241
6379
  },
6242
6380
  }
6243
6381
  */
@@ -6430,7 +6568,7 @@ class ReplayContainer {
6430
6568
  recordingOptions,
6431
6569
  }
6432
6570
 
6433
- ) {ReplayContainer.prototype.__init.call(this);ReplayContainer.prototype.__init2.call(this);ReplayContainer.prototype.__init3.call(this);ReplayContainer.prototype.__init4.call(this);ReplayContainer.prototype.__init5.call(this);ReplayContainer.prototype.__init6.call(this);ReplayContainer.prototype.__init7.call(this);ReplayContainer.prototype.__init8.call(this);ReplayContainer.prototype.__init9.call(this);ReplayContainer.prototype.__init10.call(this);ReplayContainer.prototype.__init11.call(this);ReplayContainer.prototype.__init12.call(this);ReplayContainer.prototype.__init13.call(this);ReplayContainer.prototype.__init14.call(this);ReplayContainer.prototype.__init15.call(this);ReplayContainer.prototype.__init16.call(this);ReplayContainer.prototype.__init17.call(this);
6571
+ ) {ReplayContainer.prototype.__init.call(this);ReplayContainer.prototype.__init2.call(this);ReplayContainer.prototype.__init3.call(this);ReplayContainer.prototype.__init4.call(this);ReplayContainer.prototype.__init5.call(this);ReplayContainer.prototype.__init6.call(this);ReplayContainer.prototype.__init7.call(this);ReplayContainer.prototype.__init8.call(this);ReplayContainer.prototype.__init9.call(this);ReplayContainer.prototype.__init10.call(this);ReplayContainer.prototype.__init11.call(this);ReplayContainer.prototype.__init12.call(this);ReplayContainer.prototype.__init13.call(this);ReplayContainer.prototype.__init14.call(this);ReplayContainer.prototype.__init15.call(this);ReplayContainer.prototype.__init16.call(this);ReplayContainer.prototype.__init17.call(this);ReplayContainer.prototype.__init18.call(this);
6434
6572
  this._recordingOptions = recordingOptions;
6435
6573
  this._options = options;
6436
6574
 
@@ -6922,6 +7060,7 @@ class ReplayContainer {
6922
7060
  WINDOW.document.addEventListener('visibilitychange', this._handleVisibilityChange);
6923
7061
  WINDOW.addEventListener('blur', this._handleWindowBlur);
6924
7062
  WINDOW.addEventListener('focus', this._handleWindowFocus);
7063
+ WINDOW.addEventListener('keydown', this._handleKeyboardEvent);
6925
7064
 
6926
7065
  // There is no way to remove these listeners, so ensure they are only added once
6927
7066
  if (!this._hasInitializedCoreListeners) {
@@ -6950,6 +7089,7 @@ class ReplayContainer {
6950
7089
 
6951
7090
  WINDOW.removeEventListener('blur', this._handleWindowBlur);
6952
7091
  WINDOW.removeEventListener('focus', this._handleWindowFocus);
7092
+ WINDOW.removeEventListener('keydown', this._handleKeyboardEvent);
6953
7093
 
6954
7094
  if (this._performanceObserver) {
6955
7095
  this._performanceObserver.disconnect();
@@ -7000,6 +7140,11 @@ class ReplayContainer {
7000
7140
  this._doChangeToForegroundTasks(breadcrumb);
7001
7141
  };}
7002
7142
 
7143
+ /** Ensure page remains active when a key is pressed. */
7144
+ __init16() {this._handleKeyboardEvent = () => {
7145
+ this.triggerUserActivity();
7146
+ };}
7147
+
7003
7148
  /**
7004
7149
  * Tasks to run when we consider a page to be hidden (via blurring and/or visibility)
7005
7150
  */
@@ -7079,7 +7224,7 @@ class ReplayContainer {
7079
7224
  _createCustomBreadcrumb(breadcrumb) {
7080
7225
  this.addUpdate(() => {
7081
7226
  void addEvent(this, {
7082
- type: EventType.Custom,
7227
+ type: EventType$1.Custom,
7083
7228
  timestamp: breadcrumb.timestamp || 0,
7084
7229
  data: {
7085
7230
  tag: 'breadcrumb',
@@ -7230,7 +7375,7 @@ class ReplayContainer {
7230
7375
  * Flush recording data to Sentry. Creates a lock so that only a single flush
7231
7376
  * can be active at a time. Do not call this directly.
7232
7377
  */
7233
- __init16() {this._flush = async ({
7378
+ __init17() {this._flush = async ({
7234
7379
  force = false,
7235
7380
  }
7236
7381
 
@@ -7285,7 +7430,7 @@ class ReplayContainer {
7285
7430
  }
7286
7431
 
7287
7432
  /** Handler for rrweb.record.onMutation */
7288
- __init17() {this._onMutationHandler = (mutations) => {
7433
+ __init18() {this._onMutationHandler = (mutations) => {
7289
7434
  const count = mutations.length;
7290
7435
 
7291
7436
  const mutationLimit = this._options._experiments.mutationLimit || 0;
@@ -7524,6 +7669,8 @@ class Replay {
7524
7669
  errorSampleRate,
7525
7670
  useCompression,
7526
7671
  blockAllMedia,
7672
+ maskAllInputs,
7673
+ maskAllText,
7527
7674
  networkDetailAllowUrls,
7528
7675
  networkCaptureBodies,
7529
7676
  networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),