@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 +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/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('
|
|
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
|
|
514
|
+
const type = getInputType(el);
|
|
515
|
+
const value = getInputValue(el, tagName.toUpperCase(), type);
|
|
493
516
|
const checked = n.checked;
|
|
494
|
-
if (
|
|
495
|
-
|
|
517
|
+
if (type !== 'submit' &&
|
|
518
|
+
type !== 'button' &&
|
|
496
519
|
value) {
|
|
497
520
|
attributes.value = maskInputValue({
|
|
498
521
|
input: el,
|
|
499
|
-
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
|
-
|
|
1620
|
+
target.tagName === 'INPUT' &&
|
|
1605
1621
|
(m.oldValue || '').toLowerCase() === 'password') {
|
|
1606
|
-
|
|
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
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
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 =
|
|
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
|
-
|
|
2030
|
+
if (hasInputMaskOptions({
|
|
2017
2031
|
maskInputOptions,
|
|
2018
2032
|
maskInputSelector,
|
|
2019
2033
|
tagName,
|
|
2020
2034
|
type,
|
|
2021
2035
|
})) {
|
|
2022
2036
|
text = maskInputValue({
|
|
2023
|
-
input:
|
|
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
|
|
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
|
-
//
|
|
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(
|
|
4236
|
-
if (isEventWithTarget(
|
|
4237
|
-
return
|
|
4273
|
+
function getTargetNode(event) {
|
|
4274
|
+
if (isEventWithTarget(event)) {
|
|
4275
|
+
return event.target;
|
|
4238
4276
|
}
|
|
4239
4277
|
|
|
4240
|
-
return
|
|
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
|
-
//
|
|
4300
|
-
if
|
|
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
|
-
|
|
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
|
-
|
|
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),
|