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