1(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ 2"use strict"; 3var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'identifier\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\' data-ad-format="\'+T.e(c,v,\'format\')+\'" \'',3:'\' \'+T.e(c,v,\'key\')+\':\'+T.e(c,v,\'value\')+\';\''};module.exports=function(c){var c={c:c,p:0};return'<ins '+T.u(c,v,'hook')+' class=" adsbygoogle o-ad__ins '+T.s(s,c,v,'identifier', s[0])+' '+T.s(s,c,v,'class_name', s[1])+'" data-ad-client="'+T.e(c,v,'client_id')+'" data-ad-slot="'+T.e(c,v,'slot_id')+'" '+T.s(s,c,v,'format', s[2])+' style="'+T.s(s,c,v,'style', s[3])+' "></ins> '} 4},{"icebrace-runtime":"icebrace-runtime"}],2:[function(require,module,exports){ 5"use strict"; 6var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' <div class="\'+T.s(s,c,v,\'class_name\', s[0])+\'" style="background-image: url(\\\'\'+T.e(c,v,\'src\')+\'\\\')"></div> \'',2:'\'\'+T.c(\'_name\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class="o-ad" '+T.u(c,v,'hook')+'> '+T.s(s,c,v,'image', s[1])+''+T.s(s,c,v,'component', s[2])+'</div> '} 7},{"icebrace-runtime":"icebrace-runtime"}],3:[function(require,module,exports){ 8"use strict"; 9var T=require("icebrace-runtime"),v,s={0:'\' o-addon--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',3:'\'\'+T.e(c,v,\'text\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<a class=" o-addon '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' "'+T.u(c,v,'hook')+' tabIndex="-1">'+T.s(s,c,v,'icon', s[2])+''+T.s(s,c,v,'text', s[3])+'</a> '} 10},{"icebrace-runtime":"icebrace-runtime"}],4:[function(require,module,exports){ 11"use strict"; 12var T=require("icebrace-runtime"),v,s={0:'\' o-avatar--image \'',1:'\' o-avatar--letter \'',2:'\'\'+T.e(c,v,\'.\')+\'\'',3:'\' o-avatar--\'+T.e(c,v,\'.\')+\' \'',4:'\' style="background-image: url(\\\'\'+T.e(c,v,\'image\')+\'\\\')" \'',5:'\' data-\'+T.e(c,v,\'tag\')+\'="\'+T.e(c,v,\'value\')+\'" \'',6:'\' \'+T.s(s,c,v,\'data\', s[5])+\' \'',7:'\'\'+T.e(c,v,\'letter\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-avatar '+T.s(s,c,v,'image', s[0])+' '+T.i(s,c,v,'image', s[1])+' '+T.s(s,c,v,'class_name', s[2])+' '+T.s(s,c,v,'mod', s[3])+' " '+T.s(s,c,v,'image', s[4])+' '+T.i(s,c,v,'image', s[6])+'>'+T.i(s,c,v,'image', s[7])+'</div> '} 13},{"icebrace-runtime":"icebrace-runtime"}],5:[function(require,module,exports){ 14"use strict"; 15var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',2:'\' <label class="o-dropdown__text">\'+T.e(c,v,\'code\')+\'</label> \''};module.exports=function(c){var c={c:c,p:0};return'<div class="o-dropdown'+T.s(s,c,v,'class_name', s[0])+'" '+T.u(c,v,'hook')+'> '+T.s(s,c,v,'icon', s[1])+''+T.s(s,c,v,'code', s[2])+'</div> '} 16},{"icebrace-runtime":"icebrace-runtime"}],6:[function(require,module,exports){ 17"use strict"; 18var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' name="\'+T.e(c,v,\'name\')+\'"\'',2:'\' type="button"\'',3:'\' type="\'+T.e(c,v,\'type\')+\'"\'',4:'\' value="\'+T.e(c,v,\'value\')+\'"\'',5:'\' disabled="\'+T.e(c,v,\'disabled\')+\'"\'',6:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',7:'\'<span>\'+T.e(c,v,\'text\')+\'</span>\''};module.exports=function(c){var c={c:c,p:0};return'<button '+T.u(c,v,'hook')+' '+T.s(s,c,v,'class_name', s[0])+' '+T.s(s,c,v,'name', s[1])+' '+T.i(s,c,v,'type', s[2])+' '+T.s(s,c,v,'type', s[3])+' '+T.s(s,c,v,'value', s[4])+' '+T.s(s,c,v,'disabled', s[5])+' >'+T.s(s,c,v,'icon', s[6])+''+T.s(s,c,v,'text', s[7])+'</button> '} 19},{"icebrace-runtime":"icebrace-runtime"}],7:[function(require,module,exports){ 20"use strict"; 21var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\'\'',1:'\' type="\'+T.e(c,v,\'type\')+\'"\'',2:'\' accept="\'+T.e(c,v,\'accept\')+\'"\'',3:'\' name="\'+T.e(c,v,\'name\')+\'"\'',4:'\' value="\'+T.e(c,v,\'value\')+\'"\'',5:'\' placeholder="\'+T.e(c,v,\'placeholder\')+\'"\'',6:'\' autocomplete="\'+T.e(c,v,\'autocomplete\')+\'"\'',7:'\' max="\'+T.e(c,v,\'max\')+\'"\'',8:'\' min="\'+T.e(c,v,\'min\')+\'"\'',9:'\' size="\'+T.e(c,v,\'size\')+\'"\'',10:'\' maxlength="\'+T.e(c,v,\'maxlength\')+\'"\'',11:'\' minlength="\'+T.e(c,v,\'minlength\')+\'"\'',12:'\' multiple="\'+T.e(c,v,\'multiple\')+\'"\'',13:'\' readonly="readonly"\'',14:'\' checked="checked"\'',15:'\' disabled="disabled"\'',16:'\' required\''};module.exports=function(c){var c={c:c,p:0};return'<input class="'+T.s(s,c,v,'class_name', s[0])+'" '+T.s(s,c,v,'type', s[1])+' '+T.s(s,c,v,'accept', s[2])+' '+T.s(s,c,v,'name', s[3])+' '+T.s(s,c,v,'value', s[4])+' '+T.s(s,c,v,'placeholder', s[5])+' '+T.s(s,c,v,'autocomplete', s[6])+' '+T.s(s,c,v,'max', s[7])+' '+T.s(s,c,v,'min', s[8])+' '+T.s(s,c,v,'size', s[9])+' '+T.s(s,c,v,'maxlength', s[10])+' '+T.s(s,c,v,'minlength', s[11])+' '+T.s(s,c,v,'multiple', s[12])+' '+T.s(s,c,v,'readonly', s[13])+' '+T.s(s,c,v,'checked', s[14])+' '+T.s(s,c,v,'disabled', s[15])+' '+T.s(s,c,v,'required', s[16])+' '+T.u(c,v,'hook')+' > '} 22},{"icebrace-runtime":"icebrace-runtime"}],8:[function(require,module,exports){ 23"use strict"; 24var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' name="\'+T.e(c,v,\'name\')+\'"\'',2:'\' size="\'+T.e(c,v,\'size\')+\'"\'',3:'\' disabled="disabled"\'',4:'\' readonly="readonly"\'',5:'\' multiple="true"\'',6:'\'\'+T.e(c,v,\'value\')+\'\'',7:'\' label="\'+T.e(c,v,\'label\')+\'"\'',8:'\' selected="selected"\'',9:'\' hidden="hidden"\'',10:'\' disabled="disabled"\'',11:'\' <option value="\'+T.s(s,c,v,\'value\', s[6])+\'" \'+T.s(s,c,v,\'label\', s[7])+\' \'+T.s(s,c,v,\'selected\', s[8])+\' \'+T.s(s,c,v,\'hidden\', s[9])+\' \'+T.s(s,c,v,\'disabled\', s[10])+\' >\'+T.e(c,v,\'text\')+\'</option> \''};module.exports=function(c){var c={c:c,p:0};return'<select '+T.u(c,v,'hook')+' class="'+T.s(s,c,v,'class_name', s[0])+'" '+T.s(s,c,v,'name', s[1])+' '+T.s(s,c,v,'size', s[2])+' '+T.s(s,c,v,'disabled', s[3])+' '+T.s(s,c,v,'readonly', s[4])+' '+T.s(s,c,v,'multiple', s[5])+'> '+T.s(s,c,v,'options', s[11])+'</select> '} 25},{"icebrace-runtime":"icebrace-runtime"}],9:[function(require,module,exports){ 26"use strict"; 27var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' name="\'+T.e(c,v,\'name\')+\'"\'',2:'\' placeholder="\'+T.e(c,v,\'placeholder\')+\'"\'',3:'\' cols="\'+T.e(c,v,\'cols\')+\'"\'',4:'\' rows="\'+T.e(c,v,\'rows\')+\'"\'',5:'\' disabled="disabled"\'',6:'\' readonly="readonly"\'',7:'\' maxlength="\'+T.e(c,v,\'maxlength\')+\'"\'',8:'\' minlength="\'+T.e(c,v,\'minlength\')+\'"\'',9:'\' autocomplete="\'+T.e(c,v,\'autocomplete\')+\'"\'',10:'\' required\'',11:'\'\'+T.e(c,v,\'text\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<textarea class="'+T.s(s,c,v,'class_name', s[0])+'" '+T.s(s,c,v,'name', s[1])+' '+T.s(s,c,v,'placeholder', s[2])+' '+T.s(s,c,v,'cols', s[3])+' '+T.s(s,c,v,'rows', s[4])+' '+T.s(s,c,v,'disabled', s[5])+' '+T.s(s,c,v,'readonly', s[6])+' '+T.s(s,c,v,'maxlength', s[7])+' '+T.s(s,c,v,'minlength', s[8])+' '+T.s(s,c,v,'autocomplete', s[9])+' '+T.s(s,c,v,'required', s[10])+' '+T.u(c,v,'hook')+' >'+T.s(s,c,v,'text', s[11])+'</textarea> '} 28},{"icebrace-runtime":"icebrace-runtime"}],10:[function(require,module,exports){ 29"use strict"; 30var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \''};module.exports=function(c){var c={c:c,p:0};return'<svg '+T.u(c,v,'hook')+' class=" o-icon '+T.s(s,c,v,'class_name', s[0])+' "><use xlink:href="./images/icons/icons.svg?2#'+T.e(c,v,'icon')+'"></use></svg> '} 31},{"icebrace-runtime":"icebrace-runtime"}],11:[function(require,module,exports){ 32"use strict"; 33var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \''};module.exports=function(c){var c={c:c,p:0};return'<img class="'+T.s(s,c,v,'class_name', s[0])+'" src="'+T.e(c,v,'src')+'"> '} 34},{"icebrace-runtime":"icebrace-runtime"}],12:[function(require,module,exports){ 35"use strict"; 36var T=require("icebrace-runtime"),v,s={0:'\' o-info--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.u(c,v,\'text\')+\'\'',3:'\'\'+T.c(\'atoms-link\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<p class=" o-info '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' " '+T.u(c,v,'hook')+'>'+T.s(s,c,v,'text', s[2])+' '+T.s(s,c,v,'link', s[3])+'</p> '} 37},{"icebrace-runtime":"icebrace-runtime"}],13:[function(require,module,exports){ 38"use strict"; 39var T=require("icebrace-runtime"),v,s={0:'\' \'+T.u(c,v,\'hook\')+\'\'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.e(c,v,\'text\')+\'\'',3:'\' - \'+T.e(c,v,\'error\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<span'+T.s(s,c,v,'hook', s[0])+' class=" o-label '+T.s(s,c,v,'class_name', s[1])+' ">'+T.s(s,c,v,'text', s[2])+''+T.s(s,c,v,'error', s[3])+'</span> '} 40},{"icebrace-runtime":"icebrace-runtime"}],14:[function(require,module,exports){ 41"use strict"; 42var T=require("icebrace-runtime"),v,s={0:'\' o-link--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',3:'\'\'+T.e(c,v,\'text\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<a class=" o-link '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' " '+T.u(c,v,'hook')+'>'+T.s(s,c,v,'icon', s[2])+''+T.s(s,c,v,'text', s[3])+'</a> '} 43},{"icebrace-runtime":"icebrace-runtime"}],15:[function(require,module,exports){ 44"use strict"; 45var T=require("icebrace-runtime"),v,s={0:'\' o-loader--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-loader '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' "></div> '} 46},{"icebrace-runtime":"icebrace-runtime"}],16:[function(require,module,exports){ 47"use strict"; 48var T=require("icebrace-runtime"),v,s={0:'\' o-section--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'_name\', c.c
48)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<section class=" o-section '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' " '+T.u(c,v,'hook')+'> '+T.s(s,c,v,'component', s[2])+'</section> '} 49},{"icebrace-runtime":"icebrace-runtime"}],17:[function(require,module,exports){ 50"use strict"; 51var T=require("icebrace-runtime"),v,s={};module.exports=function(c){var c={c:c,p:0};return'<span class="o-form__element" '+T.u(c,v,'hook')+'>'+T.e(c,v,'value')+'</span>'} 52},{"icebrace-runtime":"icebrace-runtime"}],18:[function(require,module,exports){ 53"use strict"; 54var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\'\'+T.c(\'atoms-avatar\', c.c)+\'\'',2:'\'<p class="o-switch__name">\'+T.e(c,v,\'name\')+\'</p>\'',3:'\'<p class="o-switch__email">\'+T.e(c,v,\'email\')+\'</p>\'',4:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',5:'\'\'+T.c(\'atoms-link\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-switch '+T.s(s,c,v,'class_name', s[0])+' " '+T.u(c,v,'hook')+' tabindex="0"> '+T.s(s,c,v,'avatar', s[1])+' <div class="o-switch__text"> '+T.s(s,c,v,'name', s[2])+' '+T.s(s,c,v,'email', s[3])+' </div> '+T.s(s,c,v,'icon', s[4])+''+T.s(s,c,v,'link', s[5])+'</div> '} 55},{"icebrace-runtime":"icebrace-runtime"}],19:[function(require,module,exports){ 56"use strict"; 57var T=require("icebrace-runtime"),v,s={0:'\' data-color="\'+T.e(c,v,\'color\')+\'" \'',1:'\' o-tag--\'+T.e(c,v,\'.\')+\' \'',2:'\' \'+T.e(c,v,\'.\')+\' \'',3:'\'\'+T.e(c,v,\'text\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div '+T.s(s,c,v,'color', s[0])+' class=" o-tag '+T.s(s,c,v,'mod', s[1])+' '+T.s(s,c,v,'class_name', s[2])+' "> '+T.s(s,c,v,'text', s[3])+' <div class="o-tag__close" '+T.u(c,v,'hook')+'><svg class="o-tag__close-icon"><use xlink:href="./images/icons/icons.svg#xmark"></use></svg></div></div> '} 58},{"icebrace-runtime":"icebrace-runtime"}],20:[function(require,module,exports){ 59"use strict"; 60var T=require("icebrace-runtime"),v,s={};module.exports=function(c){var c={c:c,p:0};return'<i class="o-form__tooltip" '+T.u(c,v,'hook')+'>?</i> '} 61},{"icebrace-runtime":"icebrace-runtime"}],21:[function(require,module,exports){ 62"use strict"; 63var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',2:'\' controls\'',3:'\' type="\'+T.e(c,v,\'type\')+\'"\'',4:'\'<source src="\'+T.e(c,v,\'src\')+\'"\'+T.s(s,c,v,\'type\', s[3])+\'>\''};module.exports=function(c){var c={c:c,p:0};return'<div '+T.u(c,v,'hook')+' class=" o-video '+T.s(s,c,v,'class_name', s[0])+' "> '+T.s(s,c,v,'icon', s[1])+' <video '+T.u(c,v,'video-hook')+' '+T.s(s,c,v,'controls', s[2])+'> '+T.s(s,c,v,'source', s[4])+' </video></div> '} 64},{"icebrace-runtime":"icebrace-runtime"}],22:[function(require,module,exports){ 65"use strict"; 66var T=require("icebrace-runtime"),v,s={0:'\' o-well--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\' \'+T.e(c,v,\'.\')+\' \'',3:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',4:'\'<p class="o-well__text u-bold">\'+T.e(c,v,\'title\')+\'</p>\'',5:'\'<p class="o-well__text">\'+T.u(c,v,\'.\')+\'</p>\''};module.exports=function(c){var c={c:c,p:0};return'<div data-hook="well" class=" o-well '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' '+T.s(s,c,v,'wrapper-class', s[2])+' "> '+T.s(s,c,v,'icon', s[3])+' <div class="o-well__content"> '+T.s(s,c,v,'title', s[4])+' '+T.s(s,c,v,'text', s[5])+' </div></div> '} 67},{"icebrace-runtime":"icebrace-runtime"}],23:[function(require,module,exports){ 68"use strict"; 69var T=require("icebrace-runtime"),v,s={0:'\' <!--[if lte IE 11]><meta http-equiv="refresh" content="0;url=\'+T.e(c,v,\'url\')+\'"><![endif]--> \'',1:'\' <noscript><meta http-equiv="refresh" content="0;url=\'+T.e(c,v,\'url\')+\'"></noscript> \'',2:'\'<meta charset="\'+T.e(c,v,\'charset\')+\'">\'',3:'\'<meta http-equiv="X-UA-Compatible" content="\'+T.e(c,v,\'X-UA-Compatible\')+\'" />\'',4:'\'<meta name="viewport" content="\'+T.e(c,v,\'viewport\')+\'" />\'',5:'\'<meta name="google" value="notranslate" />\'',6:'\' <meta name="version" content="\'+T.e(c,v,\'version\')+\'"> \'',7:'\'\'+T.e(c,v,\'name\')+\'="\'+T.e(c,v,\'value\')+\'"\'',8:'\' <meta \'+T.s(s,c,v,\'attributes\', s[7])+\'> \'',9:'\'?version=\'+T.e(c,v,\'version\')+\'\'',10:'\' <link type="text/css" href="\'+T.e(c,v,\'.\')+\'\'+T.s(s,c,v,\'version\', s[9])+\'" rel="stylesheet"> \'',11:'\'?version=\'+T.e(c,v,\'version\')+\'\'',12:'\' <script src="\'+T.e(c,v,\'.\')+\'\'+T.s(s,c,v,\'version\', s[11])+\'"></script> \'',13:'\'?version=\'+T.e(c,v,\'version\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<head><title>'+T.e(c,v,'title')+'</title> {optional base}<base href="{base}"/>{/optional} <link rel="icon" href="./favicon-32.png" sizes="32x32"><link rel="icon" href="./favicon-192.png" sizes="192x192"><link rel="icon" href="{self}{favicon32}" sizes="32x32"><link rel="icon" href="{self}{favicon128}" sizes="128x128"><link rel="icon" href="{self}{favicon180}" sizes="180x180"><link rel="icon" href="{self}{favicon192}" sizes="192x192"><meta id="theme-colors"> '+T.s(s,c,v,'backward-compatibility-redirect', s[0])+''+T.s(s,c,v,'noscript-redirect', s[1])+' '+T.s(s,c,v,'charset', s[2])+' '+T.s(s,c,v,'X-UA-Compatible', s[3])+' '+T.s(s,c,v,'viewport', s[4])+' '+T.s(s,c,v,'google-notranslate', s[5])+' <!-- Turn on IE cleartype --><meta http-equiv="cleartype" content="on"> '+T.s(s,c,v,'version', s[6])+' '+T.s(s,c,v,'custom-meta', s[8])+' '+T.s(s,c,v,'css-files', s[10])+' <script> try { {SentryConfig} } catch (e) {} </script> '+T.s(s,c,v,'script-files', s[12])+' <script> try {window.custom_script} catch (e) {} </script><link type="text/css" href="css/custom.css'+T.s(s,c,v,'version', s[13])+'" rel="stylesheet"></head> '} 70},{"icebrace-runtime":"icebrace-runtime"}],24:[function(require,module,exports){ 71"use strict"; 72var T=require("icebrace-runtime"),v,s={0:'\'\'+T.c(\'meta-head\', c.c)+\'\'',1:'\'\'+T.c(\'atoms-loader\', c.c)+\'\'',2:'\'.min\'',3:'\'.min\''};module.exports=function(c){var c={c:c,p:0};return'<!DOCTYPE html><html> '+T.s(s,c,v,'head', s[0])+' <body><div class="l-loading" id="content"> '+T.s(s,c,v,'loader', s[1])+' </div><script src="framework'+T.s(s,c,v,'min', s[2])+'.js?'+T.e(c,v,'fw_version')+'"></script>
72<script src="bundle'+T.s(s,c,v,'min', s[3])+'.js?'+T.e(c,v,'version')+'"></script></body></html> '} 73},{"icebrace-runtime":"icebrace-runtime"}],25:[function(require,module,exports){ 74"use strict"; 75var T=require("icebrace-runtime"),v,s={0:'\' o-button--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-element-button\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-button o-form__object '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' "> '+T.s(s,c,v,'button', s[2])+'</div> '} 76},{"icebrace-runtime":"icebrace-runtime"}],26:[function(require,module,exports){ 77"use strict"; 78var T=require("icebrace-runtime"),v,s={0:'\'\'+T.c(\'atoms-addon\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class="l-captcha o-form__object"><div class="o-form__element"><div class="o-captcha" '+T.u(c,v,'hook')+'>'+T.c('atoms-loader', c.c)+'</div></div> '+T.s(s,c,v,'addon', s[0])+'</div> '} 79},{"icebrace-runtime":"icebrace-runtime"}],27:[function(require,module,exports){ 80"use strict"; 81var T=require("icebrace-runtime"),v,s={0:'\' o-checkbox--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-element-input\', c.c)+\'\'',3:'\'\'+T.e(c,v,\'label\')+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-checkbox o-checkbox--default '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' "> '+T.s(s,c,v,'input', s[2])+' <i class="o-checkbox__icon"></i><label class="o-checkbox__label">'+T.s(s,c,v,'label', s[3])+'</label></div> '} 82},{"icebrace-runtime":"icebrace-runtime"}],28:[function(require,module,exports){ 83"use strict"; 84var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' o-form__object--\'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-element-input\', c.c)+\'\'',3:'\'\'+T.c(\'atoms-label\', c.c)+\'\'',4:'\'\'+T.c(\'atoms-addon\', c.c)+\'\'',5:'\'\'+T.c(\'atoms-tooltip\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<label class=" o-input o-form__object molecules-input '+T.s(s,c,v,'class_name', s[0])+' '+T.s(s,c,v,'mod', s[1])+' " '+T.u(c,v,'hook')+'> '+T.s(s,c,v,'input', s[2])+''+T.s(s,c,v,'label', s[3])+''+T.s(s,c,v,'addon', s[4])+''+T.s(s,c,v,'tooltip', s[5])+'</label> '} 85},{"icebrace-runtime":"icebrace-runtime"}],29:[function(require,module,exports){ 86"use strict"; 87var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \''};module.exports=function(c){var c={c:c,p:0};return'<li tabindex="0" class=" o-language-picker__item '+T.s(s,c,v,'class_name', s[0])+' " '+T.u(c,v,'# hook')+''+T.u(c,v,'hook')+''+T.u(c,v,'/ hook')+'>'+T.e(c,v,'text')+'</li> '} 88},{"icebrace-runtime":"icebrace-runtime"}],30:[function(require,module,exports){ 89"use strict"; 90var T=require("icebrace-runtime"),v,s={0:'\' o-language-picker--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'molecules-language-picker-item\', c.c)+\'\'',3:'\' <ul class="o-language-picker__column"> \'+T.s(s,c,v,\'item\', s[2])+\' </ul> \''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-language-picker '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' "> '+T.s(s,c,v,'column', s[3])+'</div> '} 91},{"icebrace-runtime":"icebrace-runtime"}],31:[function(require,module,exports){ 92"use strict"; 93var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\'\'+T.c(\'atoms-element-select\', c.c)+\'\'',2:'\'\'+T.c(\'atoms-label\', c.c)+\'\'',3:'\'\'+T.c(\'atoms-tooltip\', c.c)+\'\'',4:'\'\'+T.c(\'atoms-icons\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<label class=" o-select o-form__object '+T.s(s,c,v,'class_name', s[0])+' "> '+T.s(s,c,v,'select', s[1])+''+T.s(s,c,v,'label', s[2])+''+T.s(s,c,v,'tooltip', s[3])+''+T.s(s,c,v,'icon', s[4])+'</label> '} 94},{"icebrace-runtime":"icebrace-runtime"}],32:[function(require,module,exports){ 95"use strict"; 96var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' o-form__object--\'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-static\', c.c)+\'\'',3:'\'\'+T.c(\'atoms-label\', c.c)+\'\'',4:'\'\'+T.c(\'atoms-addon\', c.c)+\'\'',5:'\'\'+T.c(\'atoms-tooltip\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<label class=" o-static o-form__object '+T.s(s,c,v,'class_name', s[0])+' '+T.s(s,c,v,'mod', s[1])+' " '+T.u(c,v,'hook')+'> '+T.s(s,c,v,'static', s[2])+''+T.s(s,c,v,'label', s[3])+''+T.s(s,c,v,'addon', s[4])+''+T.s(s,c,v,'tooltip', s[5])+'</label> '} 97},{"icebrace-runtime":"icebrace-runtime"}],33:[function(require,module,exports){ 98"use strict"; 99var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' o-form__object--\'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-tag\', c.c
99)+\'\'',3:'\'\'+T.c(\'atoms-element-textarea\', c.c)+\'\'',4:'\'\'+T.c(\'atoms-label\', c.c)+\'\'',5:'\'\'+T.c(\'atoms-addon\', c.c)+\'\'',6:'\'\'+T.c(\'atoms-tooltip\', c.c)+\'\'',7:'\'\'+T.c(\'atoms-icons\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<label class=" o-textarea o-form__object '+T.s(s,c,v,'class_name', s[0])+' '+T.s(s,c,v,'mod', s[1])+' " '+T.u(c,v,'hook')+'> '+T.s(s,c,v,'tag', s[2])+''+T.s(s,c,v,'textarea', s[3])+''+T.s(s,c,v,'label', s[4])+''+T.s(s,c,v,'addon', s[5])+''+T.s(s,c,v,'tooltip', s[6])+''+T.s(s,c,v,'icon', s[7])+'</label> '} 100},{"icebrace-runtime":"icebrace-runtime"}],34:[function(require,module,exports){ 101"use strict"; 102var T=require("icebrace-runtime"),v,s={0:'\'\'+T.c(\'_name\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div style=" border-bottom: 1px solid black; height: 40px; width: 100%; /* position: absolute; */ top: 0; background: #fff; z-index: 1;"> '+T.s(s,c,v,'components', s[0])+'</div> '} 103},{"icebrace-runtime":"icebrace-runtime"}],35:[function(require,module,exports){ 104"use strict"; 105var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\' o-bar__section--\'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',3:'\'\'+T.s(s,c,v,\'logo\', s[2])+\' <p class="o-external__copy o-info">\'+T.e(c,v,\'copyright\')+\' © <time datetime="\'+T.e(c,v,\'current_year\')+\'">\'+T.e(c,v,\'current_year\')+\'</time></p> \'',4:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',5:'\' <a class="o-external__social" title="\'+T.e(c,v,\'href\')+\'" href="\'+T.e(c,v,\'href\')+\'" rel="noopener" target="_blank"> \'+T.s(s,c,v,\'icon\', s[4])+\' </a> \'',6:'\' <p class="o-info" title="\'+T.e(c,v,\'version\')+\'">\'+T.u(c,v,\'text\')+\'</p> \'',7:'\'\'+T.s(s,c,v,\'copyright\', s[3])+\' \'+T.s(s,c,v,\'social\', s[5])+\' \'+T.s(s,c,v,\'find-out-more\', s[6])+\'\'',8:'\' <section class=" o-bar__section \'+T.s(s,c,v,\'mod\', s[1])+\' "> \'+T.s(s,c,v,\'footer\', s[7])+\' </section> \''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-bar '+T.s(s,c,v,'class_name', s[0])+' "> '+T.s(s,c,v,'section', s[8])+' </div> '} 106},{"icebrace-runtime":"icebrace-runtime"}],36:[function(require,module,exports){ 107"use strict"; 108var T=require("icebrace-runtime"),v,s={0:'\' o-header--\'+T.e(c,v,\'.\')+\' \'',1:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',2:'\'\'+T.c(\'atoms-avatar\', c.c)+\'\'',3:'\'\'+T.c(\'atoms-image\', c.c)+\'\'',4:'\'\'+T.c(\'atoms-icons\', c.c)+\'\'',5:'\'\'+T.s(s,c,v,\'icon\', s[4])+\'\'',6:'\'\'+T.s(s,c,v,\'logo\', s[3])+\'\'+T.i(s,c,v,\'logo\', s[5])+\'\'',7:'\'\'+T.s(s,c,v,\'avatar\', s[2])+\'\'+T.i(s,c,v,\'avatar\', s[6])+\'\'',8:'\' \'+T.e(c,v,\'.\')+\' \'',9:'\' <h2 class=" o-header__title o-heading o-heading--beta \'+T.s(s,c,v,\'class_name\', s[8])+\' " \'+T.u(c,v,\'hook\')+\'>\'+T.e(c,v,\'.\')+\'</h2> \'',10:'\'\'+T.c(\'atoms-info\', c.c)+\'\'',11:'\'\'+T.c(\'atoms-info\', c.c)+\'\'',12:'\'\'+T.c(\'atoms-well\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-header '+T.s(s,c,v,'mod', s[0])+' "><main class="o-header__main"><div class="o-header__content"> '+T.s(s,c,v,'card-icon', s[1])+''+T.i(s,c,v,'card-icon', s[7])+' '+T.s(s,c,v,'heading', s[9])+' '+T.s(s,c,v,'subtitle', s[10])+''+T.s(s,c,v,'subsubtitle', s[11])+' </div> '+T.s(s,c,v,'well', s[12])+' </main></div> '} 109},{"icebrace-runtime":"icebrace-runtime"}],37:[function(require,module,exports){ 110"use strict"; 111var T=require("icebrace-runtime"),v,s={0:'\' o-card__section--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'_name\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<section class=" o-card__section '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' " '+T.u(c,v,'hook')+'> '+T.s(s,c,v,'component', s[2])+'</section> '} 112},{"icebrace-runtime":"icebrace-runtime"}],38:[function(require,module,exports){ 113"use strict"; 114var T=require("icebrace-runtime"),v,s={0:'\' \'+T.e(c,v,\'.\')+\' \'',1:'\'\'+T.c(\'molecules-window-header\', c.c)+\'\'',2:'\'\'+T.c(\'_name\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class=" o-window '+T.s(s,c,v,'class_name', s[0])+' "> '+T.s(s,c,v,'header', s[1])+' <div class="o-window__main"> '+T.s(s,c,v,'components', s[2])+' </div></div> '} 115},{"icebrace-runtime":"icebrace-runtime"}],39:[function(require,module,exports){ 116"use strict"; 117var T=require("icebrace-runtime"),v,s={0:'\' is-ie \'',1:'\'\'+T.e(c,v,\'background-size\')+\'\'',2:'\'background-color: \'+T.e(c,v,\'background-color\')+\';\'',3:'\'background-image: url(\\\'\'+T.e(c,v,\'background-image\')+\'\\\');\'',4:'\'\'+T.c(\'atoms-ad\', c.c)+\'\'',5:'\'\'+T.c(\'templates-card\', c.c)+\'\'',6:'\'\'+T.c(\'organisms-bar\', c.c
117)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<div class="o-external t-'+T.e(c,v,'theme')+' '+T.s(s,c,v,'ie', s[0])+''+T.s(s,c,v,'background-size', s[1])+'" style=" '+T.s(s,c,v,'background-color', s[2])+' '+T.s(s,c,v,'background-image', s[3])+' " ><main class="o-external__main"> '+T.s(s,c,v,'ad', s[4])+''+T.s(s,c,v,'card', s[5])+' </main> '+T.s(s,c,v,'bar', s[6])+'</div> '} 118},{"icebrace-runtime":"icebrace-runtime"}],40:[function(require,module,exports){ 119"use strict"; 120var T=require("icebrace-runtime"),v,s={0:'\' o-card--\'+T.e(c,v,\'.\')+\' \'',1:'\' \'+T.e(c,v,\'.\')+\' \'',2:'\'\'+T.c(\'_name\', c.c)+\'\'',3:'\'\'+T.c(\'organisms-card-section\', c.c)+\'\''};module.exports=function(c){var c={c:c,p:0};return'<form class=" o-card c-card '+T.s(s,c,v,'mod', s[0])+' '+T.s(s,c,v,'class_name', s[1])+' " '+T.u(c,v,'hook')+' method="POST"><div class="o-card__main"> '+T.s(s,c,v,'component', s[2])+' <div class="o-card__content" data-hook="content"> '+T.s(s,c,v,'content', s[3])+' </div></div></form> '} 121},{"icebrace-runtime":"icebrace-runtime"}],41:[function(require,module,exports){ 122"use strict"; 123require('./middleware/middleware')( 124 polyfills, 125 require('./middleware/i18n'), 126 require('./middleware/setLogLevel'), 127 require('./middleware/initEnvironment'), 128 require('./middleware/loadConfig'), 129 require('./middleware/initDebugger'), 130 setupApp, 131 legacyURL, 132 getServerProperties, 133 getWebmailResources, 134 changeLanguage, 135 startApp 136); 137 138/** 139 * @param {Object} data 140 * @param {Function} next 141 * @returns {undefined} 142 */ 143function polyfills(data, next) { 144 require('classlist-polyfill'); 145 require('svg4everybody')(); 146 require('match-media'); 147 require('es6-object-assign/auto'); 148 SVGElement.prototype.contains = SVGElement.prototype.contains || HTMLDivElement.prototype.contains; 149 150 Element.prototype.matches = Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 151 152 Element.prototype.closest = Element.prototype.closest || function (s) { 153 var el = this; 154 155 do { 156 if (el.matches(s)) { 157 return el; 158 } 159 el = el.parentElement || el.parentNode; 160 } while (el !== null && el.nodeType === 1); 161 return null; 162 }; 163 164 next(); 165} 166 167/** 168 * 169 * @param {Object} data 170 * @param {Function} next 171 * @returns {undefined} 172 */ 173function legacyURL(data, next) { 174 var BaseModel = require('BaseModel'); 175 BaseModel.static('LegacyURL').redirect() || next(); 176} 177 178/** 179 * 180 * @param {Object} data 181 * @param {Function} next 182 * @returns {undefined} 183 */ 184function setupApp(data, next) { 185 var disabled; 186 var Hash = require('@icewarp/hash'); 187 var BaseModel = require('BaseModel'); 188 var BaseController = require('BaseController'); 189 var OldCommunication = require('@icewarp/old-communication'); 190 require('./communication-xml.js'); 191 192 /** 193 * Create new connection to get new request ID 194 * @returns {OldCommunication} 195 */ 196 BaseModel.prototype.createNewConnection = function() { 197 return new OldCommunication(OldCommunication.XHR, Date.now(), { 198 host: (BaseModel.instance('Config').getData('config').icewarpapiUrl || ('//' + location.host + '/icewarpapi')) + '/', 199 xmlns: 'admin:iq:rpc' 200 }); 201 }; 202 203 /** 204 * Call communication command on model 205 * @param {String} command 206 * @param {Object} args 207 * @param {Object} callback 208 * @returns {unresolved} response 209 */ 210 BaseModel.prototype.callCommunication = function (command, args, callback) { 211 return this.com[command].call(this, args, callback); 212 }; 213 214 BaseController.prototype.disable = function () { 215 if (!this.DOMElement) { 216 return this; 217 } 218 this.DOMElement.classList.add('is-loading'); 219 (disabled = this.DOMElement.querySelector(':focus')) && disabled.blur(); 220 return this; 221 }; 222 223 BaseController.prototype.enable = function () { 224 if (!this.DOMElement) { 225 return this; 226 } 227 this.DOMElement.classList.remove('is-loading'); 228 !document.querySelector(':focus') && disabled && disabled.focus(); 229 return this; 230 }; 231 232 // set hashchange listener 233 Hash.update(async function (site, parts, previous_site, previous_parts) { 234 var old_controller; 235 var Template = require('icebrace-runtime'); 236 var name = Template.t(site) ? site : Template.t('sites-' + site) ? 'sites-' + site : false;
237 var content = document.getElementById('content'); 238 if (name) { 239 return new(BaseController.static(name))().execute().then(function (controller) { 240 controller.render(content); 241 }); 242 } 243 old_controller = BaseController.prototype.getInstanceByElement(content); 244 if (!await ((old_controller || {})['onHashChange'] || function () {}).call(old_controller, site, parts, previous_site, previous_parts)) { 245 new(BaseController.static('sites-login'))().execute().then(function (controller) { 246 controller.render(content); 247 }); 248 } 249 }); 250 251 next(); 252} 253 254/** 255 * 256 * @param {Object} data 257 * @param {Function} next 258 * @returns {undefined} 259 */ 260function getServerProperties(data, next) { 261 var BaseModel = require('BaseModel'); 262 var Server = BaseModel.instance('Server'); 263 Server.callCommunication('getServerProperties', { 264 serverpropertylist: ['c_webmail_url', 'c_accounts_policies_login_loginsettings', 'c_niceversion', 'c_version'] 265 }, { 266 success: next, 267 error: error 268 }); 269} 270 271/** 272 * 273 * @param {Object} data 274 * @param {Function} next 275 * @returns {undefined} 276 */ 277function getWebmailResources(data, next) { 278 var BaseModel = require('BaseModel'); 279 var WebClient = BaseModel.instance('WebClient'); 280 WebClient.callCommunication('getWebmailResources', { 281 properties: ['layout_settings', 'restrictions', 'custom_login_fields', 'reset_settings', 'languages', 'signup_domains', 'password_policy', 'banner_options'], 282 selector: document.location.hostname, 283 level: 1 284 }, { 285 success: next, 286 error: error 287 }); 288} 289 290/** 291 * 292 * @param {Object} data 293 * @param {Function} next 294 * @returns {undefined} 295 */ 296function changeLanguage(data, next) { 297 var BaseModel = require('BaseModel'); 298 var WebClient = BaseModel.instance('WebClient'); 299 BaseModel.instance('Login').changeLanguage(WebClient.getData('layout_settings').getDefaultLanguageCode(), { 300 success: next, 301 error: next 302 }); 303} 304 305/** 306 * 307 * @param {Object} data 308 * @param {Function} next 309 * @returns {undefined} 310 */ 311function startApp() { 312 var Hash = require('@icewarp/hash'); 313 var chosen_users; 314 var BaseModel = require('BaseModel'); 315 var BaseController = require('BaseController'); 316 var WebClient = BaseModel.instance('WebClient'); 317 var Login = BaseModel.instance('Login'); 318 var Sentry = require('@sentry/browser'); 319 320 if (window.SentryEnabled) { 321 Sentry.init({ 322 dsn: window.SentryLoginDSN || 'https://[email protected]/3', 323 environment: window.SentryEnvironment || 'production', 324 release: BaseModel.instance('Server').getData('c_version'), 325 sampleRate: 1.0, 326 maxBreadcrumbs: 100, 327 autoSessionTracking: true 328 }); 329 } 330 331 if (BaseModel.instance('Config').getData('config').application === 'webclient' && WebClient.getData('restrictions').getValue('sso_only')) { 332 if (Hash.getParts().eid) { 333 BaseController.new('sites-login', { 334 site: 'unavailable', 335 data: { 336 title: __('error.' + Hash.getParts().eid), 337 retry_link: './' 338 } 339 }).execute().then(function (controller) { 340 var content = document.getElementById('content'); 341 controller.render(content); 342 }); 343 } else { 344 location.href = './sso'; 345 } 346 return; 347 } 348 349 if (Hash.getParts().auth_id) { 350 document.title = __('title.oauth'); 351 } else { 352 document.title = WebClient.getData('layout_settings').getValue('title'); 353 } 354 355 chosen_users = Hash.getParts().username ? [Hash.getParts().username] : Login.getUsers(); 356 chosen_users[0] && Login.setData('chosen_account', chosen_users[0]); 357 358 Hash.update(); 359} 360 361/** 362 * @returns {undefined} 363 */ 364function error() { 365 var BaseModel = require('BaseModel'); 366 var WebClient = BaseModel.instance('WebClient'); 367 BaseModel.instance('Login').changeLanguage(WebClient.getData('layout_settings').getDefaultLanguageCode(), { 368 success: function () { 369 var BaseController = require('BaseController'); 370 BaseController.new('sites-login').execute({ 371 site: 'unavailable' 372 }).then(function (controller) { 373 var content = document.getElementById('content'); 374 controller.render(content); 375 }); 376 } 377 }); 378} 379 380},{"./communication-xml.js":42,"./middleware/i18n":133,"./middleware/initDebugger":134,"./middleware/initEnvironment":135,"./middleware/loadConfig":136,"./middleware/middleware":137,"./middleware/setLogLevel":138,"@icewarp/hash":160,"@icewarp/old-communication":168,"@sentry/browser":223,"BaseController":"BaseController","BaseModel":"BaseModel","classlist-polyfill":356,"es6-object-assign/auto":358,"icebrace-runtime":"icebrace-runtime","match-media":363,"svg4everybody":367}],42:[function(require,module,exports){ 381"use strict"; 382var BaseModel = require('BaseModel'); 383var Login = BaseModel.static('Login'); 384Login.prototype.com= new (require('./communication/xml/Login/LoginPrototype.js'))(); 385var WebClient = BaseModel.static('WebClient'); 386WebClient.prototype.com= new (require('./communication/xml/WebClient/WebClientPrototype.js'))(); 387var Server = BaseModel.static('Server'); 388Server.prototype.com= new (require('./communication/xml/Server/ServerPrototype.js'))(); 389var OAuth = BaseModel.static('OAuth'); 390OAuth.prototype.com= new (require('./communication/xml/OAuth/OAuthPrototype.js'))(); 391 392},{"./communication/xml/Login/LoginPrototype.js":43,"./communication/xml/OAuth/OAuthPrototype.js":44,"./communication/xml/Server/ServerPrototype.js":45,"./communication/xml/WebClient/WebClientPrototype.js":46,"BaseModel":"BaseModel"}],43:[function(require,module,exports){ 393"use strict";
394// var OldCommunication = require('@icewarp/old-communication'); 395var rsa = require('@icewarp/rsa'); 396var Callback = require('Callback'); 397var xhr_connection = require('@icewarp/xhr-connection'); 398 399/** 400 * @param {String} password 401 * @returns {String} 402 */ 403function authPlain(password) { 404 return password; 405} 406 407/** 408 * @param {String} hash 409 * @param {String} timestamp 410 * @returns {String} 411 */ 412function authRSA(hash, timestamp) { 413 return hash ? function (password) { 414 var RSA = new rsa(); 415 RSA.setPublic(hash, '10001'); 416 return RSA.encrypt('p=' + encodeURIComponent(password).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+') + '&t=' + timestamp); 417 } : authPlain; 418} 419 420/** 421 * Communication for Login model 422 * @class LoginPrototype 423 */ 424function LoginPrototype() {} 425 426LoginPrototype.prototype.usernameAvailable = function (params, callback) { 427 var data = { 428 commandname: 'usernameavailable', 429 commandparams: { 430 username: params.username, 431 domain: params.domain, 432 session: params.session 433 } 434 }; 435 436 this.createNewConnection().send(data, { 437 success: callback.success, 438 error: callback.error, 439 context: callback.context 440 }); 441}; 442 443LoginPrototype.prototype.getVerification = function (params, callback) { 444 var data = { 445 commandname: 'sendsignupverification',
446 commandparams: params 447 }; 448 this.createNewConnection().send(data, { 449 success: function (auth) { 450 return Callback(Callback.SUCCESS, callback, auth); 451 }, 452 error: callback.error, 453 context: callback.context 454 }); 455}; 456 457LoginPrototype.prototype.getAuthChallenge = function (callback) { 458 var data; 459 if (!this.getData('useRSA')) { 460 return Callback(Callback.SUCCESS, callback, authPlain); 461 } 462 data = { 463 commandname: 'getauthchallenge', 464 commandparams: { 465 authtype: +this.getData('useRSA') 466 } 467 }; 468 this.createNewConnection().send(data, { 469 success: function (auth) { 470 var rsa; 471 try { 472 rsa = authRSA(auth.hashid, auth.timestamp); 473 return Callback(Callback.SUCCESS, callback, rsa); 474 } catch(error) { 475 return Callback(Callback.ERROR, callback, error); 476 } 477 }, 478 error: callback.error, 479 context: callback.context 480 }); 481}; 482 483LoginPrototype.prototype.logoutTeamChatOnly = function (data, callback) { 484 var XHRConnection = new xhr_connection({ 485 host: data.notifyuri + '?token=' + data.token + '&action=logout', 486 listeners: { 487 onmessage: { 488 func: callback.success, 489 context: callback.context 490 }, 491 onerror: { 492 func: callback.error, 493 context: callback.context 494 } 495 } 496 }); 497 XHRConnection.send('', Date.now()); 498}; 499 500LoginPrototype.prototype.teamchatError = function (data) { 501 var XHRConnection = new xhr_connection({ 502 host: data.notifyuri + '?eid=' + data.eid 503 }); 504 XHRConnection.send('', Date.now()); 505}; 506 507LoginPrototype.prototype.isGuestDomain = function (domain, callback) { 508 var data = { 509 commandname: 'isguestdomain', 510 commandparams: { 511 domainstr: domain 512 } 513 }; 514 515 if (callback.context) { 516 callback.context.DOMShadowElement = callback.context.DOMElement || true; 517 } 518 519 if (!domain) { 520 return Callback(Callback.SUCCESS, callback, false); 521 } 522 523 this.createNewConnection().send(data, { 524 success: function (response) { 525 Callback(Callback.SUCCESS, callback, response); 526 }, 527 error: function () { 528 Callback(Callback.SUCCESS, callback, false); 529 }, 530 context: callback.context 531 }); 532}; 533 534module.exports = LoginPrototype; 535 536},{"@icewarp/rsa":174,"@icewarp/xhr-connection":181,"Callback":"Callback"}],44:[function(require,module,exports){ 537"use strict"; 538var Callback = require('Callback'); 539var OldCommunication = require('@icewarp/old-communication'); 540 541/** 542 * 543 * @description Resolves Admin API props to reasonable format 544 * @param {Object} value 545 * @returns {*} 546 */ 547function resolveAPIItemValue(value) { 548 switch (value.classname) { 549 case 'TAccountName': 550 return [value.name, value.surname].filter(Boolean); 551 case 'TPropertyString': 552 return value.val; 553 case 'TPropertyNoValue': 554 return null; 555 case 'TAccountImage': 556 return { 557 data: value.base64data, 558 mime: value.contenttype, 559 url: 560 'data:' + 561 value.contenttype + 562 ';base64,' + 563 encodeURIComponent(value.base64data) 564 }; 565 default: 566 return false; 567 } 568} 569 570/** 571 * Communication for OAuth model 572 * @class OAuthPrototype 573 */ 574function OAuthPrototype() {} 575 576OAuthPrototype.prototype.login = function (args, callback) { 577 var data = { 578 commandname: 'authenticate', 579 commandparams: { 580 authtype: +args.authtype, 581 email: args.user 582 } 583 }; 584 data.commandparams[args.authtype ? 'digest' : 'password'] = args.password; 585 586 this.createNewConnection().send(data, { 587 success: function (result, attributes) { 588 Callback('success', callback, attributes._attributes.sid); 589 }, 590 error: function (error) { 591 Callback('error', callback, error); 592 }, 593 context: this 594 }); 595}; 596 597OAuthPrototype.prototype.GetOauthClientInfo = function (params, callback) { 598 var data = { 599 commandname: 'getoauthclientinfo', 600 commandparams: { 601 clientid: params.clientid 602 } 603 }; 604 OldCommunication.getConnection('admin-auth').send(data, callback); 605}; 606 607OAuthPrototype.prototype.GetSessionInfo = function (params, callback) { 608 var data = { 609 commandname: 'getsessioninfo' 610 }; 611 return OldCommunication.getConnection('admin-auth').send(data, callback); 612}; 613 614OAuthPrototype.prototype.GetOauthAuthorizationRequest = function ( 615 params, 616 callback 617) { 618 var data = { 619 commandname: 'getoauthauthorizationrequest', 620 commandparams: { 621 requestid: params.requestid 622 } 623 }; 624 OldCommunication.getConnection('admin-auth').send(data, callback); 625}; 626OAuthPrototype.prototype.OauthAuthorizationExists = function ( 627 params, 628 callback 629) { 630 var data = { 631 commandname: 'OauthAuthorizationExists', 632 commandparams: { 633 requestid: params.requestid 634 } 635 }; 636 OldCommunication.getConnection('admin-auth').send(data, callback); 637}; 638 639OAuthPrototype.prototype.GrantOauthAuthorization = function (params, callback) { 640 var data = { 641 commandname: 'grantoauthauthorization',
642 commandparams: { 643 requestid: params.requestid, 644 description: params.description 645 } 646 }; 647 OldCommunication.getConnection('admin-auth').send(data, callback); 648}; 649 650OAuthPrototype.prototype.getAccountDetail = function (args, callback) { 651 var data = { 652 commandname: 'GetAccountProperties', 653 commandparams: { 654 accountemail: args.email, 655 accountpropertyset: 1 656 } 657 }; 658 OldCommunication.getConnection('admin-auth').send(data, { 659 success: function (data) { 660 var admin = { 661 A_Name: [args.email] 662 }; 663 data.item.forEach(function (item) { 664 var value = resolveAPIItemValue(item.propertyval); 665 if (!value) { 666 return; 667 } 668 admin[item.apiproperty.propname] = value; 669 }); 670 callback.success.call(callback.context, admin); 671 }, 672 error: function (error) { 673 Callback('error', callback, error); 674 }, 675 context: this 676 }); 677}; 678 679module.exports = OAuthPrototype; 680 681},{"@icewarp/old-communication":168,"Callback":"Callback"}],45:[function(require,module,exports){ 682"use strict"; 683var Callback = require('Callback'); 684// var OldCommunication = require('@icewarp/old-communication'); 685 686/** 687 * Communication for Server model 688 * @class ServerPrototype 689 */ 690function ServerPrototype() {} 691 692ServerPrototype.prototype.getServerProperties = function (args, callback) { 693 var data = { 694 commandname: 'getserverproperties', 695 commandparams: { 696 serverpropertylist: args.serverpropertylist.map(function (property) { 697 return { 698 item: { 699 propname: property 700 } 701 }; 702 }) 703 } 704 }; 705 this.createNewConnection().send(data, { 706 success: function (response_json) { 707 var items = Array.isArray(response_json.item) ? response_json.item : [response_json.item]; 708 items.forEach(function (item) { 709 this.setData(item.apiproperty.propname, item.propertyval.val); 710 }, this); 711 Callback('success', callback, arguments); 712 }, 713 error: function () { 714 Callback('error', callback, arguments); 715 }, 716 context: this 717 }); 718}; 719 720module.exports = ServerPrototype; 721 722},{"Callback":"Callback"}],46:[function(require,module,exports){ 723"use strict";
724// var OldCommunication = require('@icewarp/old-communication'); 725var BaseModel = require('BaseModel'); 726var Callback = require('Callback'); 727 728/** 729 * Communication for WebClient model 730 * @class WebClientPrototype 731 */ 732function WebClientPrototype() {} 733 734// sign-in-password 735WebClientPrototype.prototype.authenticate = function (args, callback) { 736 var authtype = +BaseModel.instance('Login').getData('useRSA'); 737 var data = { 738 commandname: 'authenticate', 739 commandparams: { 740 email: args.email, 741 authtype: authtype, 742 persistentlogin: args.persistentlogin 743 } 744 }; 745 746 data.commandparams[authtype ? 'digest' : 'password'] = args.password; 747 748 this.createNewConnection().send(data, callback); 749}; 750 751WebClientPrototype.prototype.sendGatewayAuthentication = function (args, callback) { 752 var data = { 753 commandname: 'sendgatewayauthentication', 754 commandparams: { 755 email: args.email, 756 captcharequest: { 757 uid: args.captcharequest.uid, 758 value: args.captcharequest.value 759 } 760 } 761 }; 762 this.createNewConnection().send(data, callback); 763}; 764 765WebClientPrototype.prototype.getAuthToken = function (args, callback) { 766 var authtype = +BaseModel.instance('Login').getData('useRSA'); 767 var data = { 768 commandname: 'getauthtoken', 769 commandparams: { 770 email: args.email, 771 authtype: authtype, 772 persistentlogin: args.persistentlogin 773 } 774 }; 775 776 data.commandparams[authtype ? 'digest' : 'password'] = args.password; 777 args.totpcode && (data.commandparams.totpcode = args.totpcode); 778 779 this.createNewConnection().send(data, callback); 780}; 781 782WebClientPrototype.prototype.confirmPersonality = function (args, callback) { 783 var data = { 784 commandname: 'confirmpersonality', 785 commandparams: { 786 email: args.email, 787 user: args.user, 788 hash: args.hash 789 } 790 }; 791 this.createNewConnection().send(data, callback); 792}; 793 794// create-account -> set-password 795WebClientPrototype.prototype.signupAccount = function (args, callback) { 796 this.createNewConnection().send({ 797 commandname: 'signupaccount', 798 commandparams: args 799 }, callback); 800}; 801 802// forgot-password 803WebClientPrototype.prototype.resetPasswordEmail = function (args, callback) { 804 var data = { 805 commandname: 'resetpasswordemail', 806 commandparams: { 807 email: args.email, 808 langid: BaseModel.instance('WebClient').getData('layout_settings').getUserLanguageCode(), 809 captcharequest: { 810 uid: args.captcharequest.uid, 811 value: args.captcharequest.value 812 } 813 } 814 }; 815 this.createNewConnection().send(data, callback); 816}; 817 818// reset-password 819WebClientPrototype.prototype.resetPassword = function (args, callback) { 820 var Hash = require('@icewarp/hash'); 821 var data = { 822 commandname: 'resetpassword', 823 commandparams: { 824 email: args.user || Hash.getParts().user, 825 newpassword: args.newpassword, 826 resethash: args.resethash || Hash.getParts().hash, 827 authtype: +BaseModel.instance('Login').getData('useRSA') 828 } 829 }; 830 this.createNewConnection().send(data, callback); 831}; 832 833// change-password 834WebClientPrototype.prototype.changePassword = function (args, callback) { 835 var data = { 836 commandname: 'changepassword', 837 commandparams: { 838 email: args.email, 839 oldpassword: args.oldpassword, 840 newpassword: args.newpassword, 841 authtype: +BaseModel.instance('Login').getData('useRSA') 842 } 843 }; 844 this.createNewConnection().send(data, callback); 845}; 846 847WebClientPrototype.prototype.getCaptcha = function (callback) { 848 this.createNewConnection().send({ 849 commandname: 'getcaptcha' 850 }, callback); 851}; 852 853// contact-admin 854WebClientPrototype.prototype.contactAdministrator = function (args, callback) { 855 var data = { 856 commandname: 'contactadministrator', 857 commandparams: { 858 email: args.email, 859 data: args.data, 860 host: location.hostname, 861 captcharequest: { 862 uid: args.captcha.uid, 863 value: args.captcha.value 864 } 865 } 866 }; 867 this.createNewConnection().send(data, callback); 868}; 869 870//tc-join 871WebClientPrototype.prototype.guestConfirm = function (args, callback) { 872 var data = { 873 commandname: 'guestconfirm', 874 commandparams: { 875 email: args.email, 876 password: args.password, 877 fullname: args.fullname, 878 sender: args.sender, 879 hash: args.hash, 880 authtype: +BaseModel.instance('Login').getData('useRSA') 881 } 882 }; 883 this.createNewConnection().send(data, callback); 884}; 885 886WebClientPrototype.prototype.guestVerify = function (args, callback) { 887 var data = { 888 commandname: 'guestverify', 889 commandparams: { 890 email: args.email, 891 hash: args.hash 892 } 893 }; 894 this.createNewConnection().send(data, callback); 895}; 896 897// app start
898WebClientPrototype.prototype.getWebmailResources = function (args, callback) { 899 var data = { 900 commandname: 'getwebmailresources', 901 commandparams: { 902 resources: args.properties.map(function (prop) { 903 return { 904 item: { 905 name: prop 906 } 907 }; 908 }), 909 selector: args.selector, 910 level: args.level 911 } 912 }; 913 this.createNewConnection().send(data, { 914 success: function (response_json) { 915 BaseModel.instance('WebClient').initialize(response_json); 916 Callback('success', callback, response_json); 917 }, 918 error: function () { 919 Callback('error', callback, arguments); 920 }, 921 context: this 922 }); 923}; 924 925module.exports = WebClientPrototype; 926 927},{"@icewarp/hash":160,"BaseModel":"BaseModel","Callback":"Callback"}],47:[function(require,module,exports){ 928"use strict"; 929var BaseController = require('BaseController'); 930var AtomsAdAdsense = BaseController.create('AtomsAdAdsense'); 931 932AtomsAdAdsense.prototype.afterRender = function () { 933 var script; 934 (window.adsbygoogle = window.adsbygoogle || []).push({}); 935 if (!document.getElementById('adsbygoogle')) { 936 script = document.createElement('script'); 937 script.setAttribute('id', 'adsbygoogle'); 938 script.setAttribute('async', true); 939 script.setAttribute('src', '//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'); 940 document.head.appendChild(script); 941 } 942}; 943 944module.exports = AtomsAdAdsense; 945 946},{"BaseController":"BaseController"}],48:[function(require,module,exports){ 947"use strict"; 948var BaseModel = require('BaseModel'); 949var BaseController = require('BaseController'); 950var AtomsAd = BaseController.create('AtomsAd'); 951 952AtomsAd.prototype.afterRender = function () { 953 if (!this.view_data.component && !this.view_data.image) { 954 this.remove(); 955 } 956}; 957 958AtomsAd.prototype.helper = function () { 959 var Restrictions = BaseModel.instance('WebClient').getData('restrictions'); 960 var BannerOptions = BaseModel.instance('WebClient').getData('banner_options'); 961 962 if (!this.data || !this.data.position) { 963 return {}; 964 } 965 966 switch (BannerOptions.getValue(this.data.position + '_type')) { 967 case 'url': 968 if (!BannerOptions.getValue(this.data.position + '_url')) { 969 return {}; 970 } 971 return { 972 image: { 973 src: BannerOptions.getValue(this.data.position + '_url'), 974 class_name: ['o-ad__img'] 975 } 976 }; 977 case 'code': 978 if (Restrictions.getValue('enable_adsense') !== 1 || !BannerOptions.getValue('customer_id') || !BannerOptions.getValue(this.data.position + '_code')) { 979 return {}; 980 } 981 return { 982 component: BaseController.new('atoms-ad-adsense', { 983 slot_id: BannerOptions.getValue(this.data.position + '_code'), 984 client_id: BannerOptions.getValue('customer_id').trim(), 985 identifier: this.data.identifier, 986 style: this.data.style, 987 format: this.data.format || 'auto' 988 }) 989 }; 990 } 991 return {}; 992}; 993 994module.exports = AtomsAd; 995 996},{"BaseController":"BaseController","BaseModel":"BaseModel"}],49:[function(require,module,exports){ 997"use strict"; 998var BaseController = require('BaseController'); 999var AtomsAddon = BaseController.create('AtomsAddon'); 1000 1001AtomsAddon.prototype.helper = function () { 1002 return { 1003 class_name: this.data.class_name, 1004 mod: this.data.mod, 1005 text: this.data.text, 1006 icon: this.data.icon, 1007 hook: this.data.hook 1008 }; 1009}; 1010 1011module.exports = AtomsAddon; 1012 1013},{"BaseController":"BaseController"}],50:[function(require,module,exports){ 1014"use strict"; 1015var BaseController = require('BaseController'); 1016var AtomsAddon = require('./addon'); 1017var AtomsAddon_Show = BaseController.create('AtomsAddon_Show', AtomsAddon); 1018 1019AtomsAddon_Show.prototype.helper = function () { 1020 this.data.icon = BaseController.new('atoms-icons', { 1021 icon: 'eye' 1022 }); 1023 this.data.mod = ['ico', 'floating']; 1024 this.data.hook = this.createHook('show-password'); 1025 return AtomsAddon.prototype.helper.call(this); 1026}; 1027 1028module.exports = AtomsAddon_Show; 1029 1030},{"./addon":49,"BaseController":"BaseController"}],51:[function(require,module,exports){ 1031"use strict"; 1032var BaseModel = require('BaseModel'); 1033var BaseController = require('BaseController'); 1034var AtomsAvatar = BaseController.create('AtomsAvatar'); 1035 1036AtomsAvatar.prototype.helper = function () { 1037 return this.data['email'] ? { 1038 image: this.data['avatar_token'] ? BaseModel.instance('Server').getAvatar({email: this.data['email'], avatarhash: this.data['avatar_token']}) : false, 1039 letter: !this.data['avatar_token'] ? (this.data['name'] || this.data['email'] || '').substr(0, 1) : false, 1040 class_name: this.data.class_name, 1041 mod: this.data['mod'], 1042 data: [ 1043 { 1044 tag: 'color', 1045 value: this.data['color'] 1046 } 1047 ] 1048 } : {}; 1049}; 1050 1051module.exports = AtomsAvatar; 1052 1053},{"BaseController":"BaseController","BaseModel":"BaseModel"}],52:[function(require,module,exports){ 1054"use strict"; 1055var BaseController = require('BaseController'); 1056var AtomsDropdown = BaseController.create('AtomsDropdown'); 1057 1058AtomsDropdown.prototype.helper = function () { 1059 return { 1060 class_name: this.data.class_name, 1061 icon: this.data.icon, 1062 hook: this.data.hook, 1063 code: this.data.code 1064 }; 1065}; 1066 1067module.exports = AtomsDropdown; 1068 1069},{"BaseController":"BaseController"}],53:[function(require,module,exports){ 1070"use strict"; 1071var BaseController = require('BaseController'); 1072var AtomsElementButton = BaseController.create('AtomsElementButton'); 1073 1074AtomsElementButton.prototype.helper = function () { 1075 return { 1076 class_name: this.data.class_name, 1077 name: this.data.name || 'button', 1078 text: this.data.text, 1079 hook: this.data.hook, 1080 disabled: this.data.disabled ? 'disabled' : false, 1081 icon: this.data.icon 1082 }; 1083}; 1084 1085module.exports = AtomsElementButton; 1086 1087},{"BaseController":"BaseController"}],54:[function(require,module,exports){ 1088"use strict"; 1089var BaseController = require('BaseController'); 1090var AtomsElementInput = BaseController.create('AtomsElementInput'); 1091
1092AtomsElementInput.prototype.focus = function () { 1093 this.DOMElement.focus(); 1094}; 1095 1096AtomsElementInput.prototype.helper = function () { 1097 return { 1098 class_name: this.data.class_name, 1099 type: this.data.type || 'text', 1100 accept: this.data.accept, 1101 name: this.data.name || 'input', 1102 value: this.data.value, 1103 placeholder: this.data.placeholder, 1104 autocomplete: this.data.autocomplete, 1105 max: this.data.max, 1106 min: this.data.min, 1107 size: this.data.size, 1108 maxlength: this.data.maxlength, 1109 minlength: this.data.minlength, 1110 multiple: this.data.multiple, 1111 readonly: this.data.readonly, 1112 checked: this.data.checked, 1113 disabled: this.data.disabled, 1114 required: this.data.required, 1115 hook: this.data.hook, 1116 maxDate: this.data.maxDate 1117 }; 1118}; 1119 1120module.exports = AtomsElementInput; 1121 1122},{"BaseController":"BaseController"}],55:[function(require,module,exports){ 1123"use strict"; 1124var Library = require('Library'); 1125var BaseController = require('BaseController'); 1126var AtomsElementInput = require('./element-input.js'); 1127var AtomsElementInput_Date = BaseController.create('AtomsElementInput_Date_Date', AtomsElementInput); 1128 1129AtomsElementInput_Date.prototype.afterRender = function () { 1130 if (this.DOMElement.type === 'date') { 1131 return; 1132 } 1133 Library.get('pikaday', { 1134 success: function (Pikaday) { 1135 new Pikaday({ 1136 field: this.DOMElement, 1137 maxDate: this.data.maxDate, 1138 onSelect: function (date) { 1139 this.date = date; 1140 }.bind(this), 1141 yearRange: [1900, new Date().getFullYear()], 1142 i18n: { 1143 previousMonth: __('calendar.previous_month'), 1144 nextMonth: __('calendar.next_month'), 1145 months: ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'].map(function (month) { 1146 return __('calendar.month.' + month); 1147 }), 1148 weekdays: ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'].map(function (day) { 1149 return __('calendar.day.' + day); 1150 }), 1151 weekdaysShort: ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'].map(function (day) { 1152 return __('calendar.day_short.' + day); 1153 }) 1154 } 1155 }); 1156 }, 1157 error: function () {}, 1158 context: this 1159 }, false, window); 1160}; 1161 1162module.exports = AtomsElementInput_Date; 1163 1164},{"./element-input.js":54,"BaseController":"BaseController","Library":"Library"}],56:[function(require,module,exports){ 1165"use strict"; 1166var BaseController = require('BaseController'); 1167var AtomsElementSelect = BaseController.create('AtomsElementSelect'); 1168 1169AtomsElementSelect.prototype.focus = function () { 1170 this.DOMElement.focus(); 1171}; 1172 1173AtomsElementSelect.prototype.helper = function () { 1174 return { 1175 class_name: this.data.class_name, 1176 label: this.data.label, 1177 name: this.data.name || 'select', 1178 hook: this.data.hook, 1179 readonly: this.data.readonly, 1180 size: this.data.size, 1181 options: (this.data.options || []).map(function(option) { 1182 option.text = option.text === void 0 || option.text === false ? option.value : option.text; 1183 return option; 1184 }) 1185 }; 1186}; 1187 1188module.exports = AtomsElementSelect; 1189 1190},{"BaseController":"BaseController"}],57:[function(require,module,exports){ 1191"use strict"; 1192var BaseController = require('BaseController'); 1193var AtomsElementTextarea = BaseController.create('AtomsElementTextarea'); 1194 1195AtomsElementTextarea.prototype.focus = function () { 1196 this.DOMElement.focus(); 1197}; 1198 1199AtomsElementTextarea.prototype.helper = function () { 1200 return { 1201 rows: this.data.rows || 3, 1202 class_name: this.data.class_name, 1203 placeholder: this.data.placeholder, 1204 name: this.data.name, 1205 autocomplete: this.data.autocomplete || 'off', 1206 required: this.data.required, 1207 text: this.data.text, 1208 hook: this.data.hook 1209 }; 1210}; 1211 1212module.exports = AtomsElementTextarea; 1213 1214},{"BaseController":"BaseController"}],58:[function(require,module,exports){ 1215"use strict"; 1216var BaseController = require('BaseController'); 1217var AtomsInfo = BaseController.create('AtomsInfo'); 1218 1219AtomsInfo.prototype.helper = function () { 1220 return { 1221 text: this.data.text, 1222 class_name: this.data.class_name || ['u-align-center'], 1223 link: this.data.link 1224 }; 1225}; 1226 1227module.exports = AtomsInfo; 1228 1229},{"BaseController":"BaseController"}],59:[function(require,module,exports){ 1230"use strict"; 1231var BaseController = require('BaseController'); 1232var AtomsInfo_HaveAccount = BaseController.create('AtomsInfo_HaveAccount'); 1233 1234AtomsInfo_HaveAccount.prototype.helper = function () { 1235 return { 1236 text: __('generic.have-account'), 1237 class_name: ['u-align-center'], 1238 link: BaseController.new('atoms-link~choose-account') 1239 }; 1240}; 1241 1242module.exports = AtomsInfo_HaveAccount; 1243 1244},{"BaseController":"BaseController"}],60:[function(require,module,exports){ 1245"use strict"; 1246var BaseController = require('BaseController'); 1247var AtomsInfo_ContactAdmin = BaseController.create('AtomsInfo_ContactAdmin'); 1248 1249AtomsInfo_ContactAdmin.prototype.helper = function () { 1250 return { 1251 text: __('contact-admin.having-problems'), 1252 class_name: ['u-align-center'], 1253 link: BaseController.new('atoms-link~contact-admin') 1254 }; 1255}; 1256 1257module.exports = AtomsInfo_ContactAdmin; 1258 1259},{"BaseController":"BaseController"}],61:[function(require,module,exports){ 1260"use strict"; 1261var BaseController = require('BaseController'); 1262var AtomsInfo_DontHaveAccount = BaseController.create('AtomsInfo_DontHaveAccount'); 1263 1264AtomsInfo_DontHaveAccount.prototype.helper = function () { 1265 return { 1266 text: __('generic.dont-have-account'), 1267 class_name: ['u-align-center'], 1268 link: BaseController.new('atoms-link~create-acc') 1269 }; 1270}; 1271 1272module.exports = AtomsInfo_DontHaveAccount; 1273 1274},{"BaseController":"BaseController"}],62:[function(require,module,exports){ 1275"use strict"; 1276var BaseController = require('BaseController'); 1277var AtomsInfo_HaveAccount = BaseController.create('AtomsInfo_HaveAccount'); 1278 1279AtomsInfo_HaveAccount.prototype.helper = function () { 1280 return { 1281 text: __('generic.have-account'), 1282 class_name: ['u-align-center'], 1283 link: BaseController.new('atoms-link~sign-in') 1284 }; 1285}; 1286 1287module.exports = AtomsInfo_HaveAccount; 1288 1289},{"BaseController":"BaseController"}],63:[function(require,module,exports){ 1290"use strict"; 1291var BaseModel = require('BaseModel'); 1292var BaseController = require('BaseController'); 1293var AtomsInfo_NotYou = BaseController.create('AtomsInfo_NotYou'); 1294var Login = BaseModel.instance('Login'); 1295 1296AtomsInfo_NotYou.prototype.helper = function () { 1297 return { 1298 text: __('generic.not-you'), 1299 class_name: ['u-align-center'], 1300 link: BaseController.new('atoms-link~' + (Login.getUsers().length ? 'choose-account' : 'check-account')) 1301 }; 1302}; 1303 1304module.exports = AtomsInfo_NotYou; 1305 1306},{"BaseController":"BaseController","BaseModel":"BaseModel"}],64:[function(require,module,exports){ 1307"use strict"; 1308var BaseController = require('BaseController'); 1309var AtomsInfo_SignWithAnotherAcc = BaseController.create('AtomsInfo_SignWithAnotherAcc'); 1310 1311AtomsInfo_SignWithAnotherAcc.prototype.helper = function () { 1312 return { 1313 // text: __('generic.dont-have-account'), 1314 class_name: ['u-align-center'], 1315 link: BaseController.new('atoms-link~sign-with-another-acc') 1316 }; 1317}; 1318 1319module.exports = AtomsInfo_SignWithAnotherAcc; 1320 1321},{"BaseController":"BaseController"}],65:[function(require,module,exports){ 1322"use strict"; 1323var BaseController = require('BaseController'); 1324var AtomsLabel = BaseController.create('AtomsLabel'); 1325 1326AtomsLabel.prototype.addListeners = function () { 1327 this.addGlobalListener('validation-error', this.handleValidation); 1328 this.addGlobalListener('validation-success', this.handleValidation); 1329}; 1330 1331AtomsLabel.prototype.handleValidation = function (data) { 1332 if (this.getParent(data.controller._name) === data.controller) { 1333 this.data.error = data.message; 1334 this.rerender(); 1335 } 1336}; 1337 1338AtomsLabel.prototype.helper = function () { 1339 return { 1340 hook: this.data.hook, 1341 text: this.data.text,
1342 class_name: this.data.class_name, 1343 error: this.data.error 1344 }; 1345}; 1346 1347module.exports = AtomsLabel; 1348 1349},{"BaseController":"BaseController"}],66:[function(require,module,exports){ 1350"use strict"; 1351var BaseController = require('BaseController'); 1352var AtomsLink_Back = BaseController.create('AtomsLink_Back'); 1353 1354AtomsLink_Back.prototype.helper = function () { 1355 return { 1356 text: __('generic.back'), 1357 class_name: ['u-float-left'].concat(this.data.class_name ? this.data.class_name : []), 1358 hook: this.createHook('back'), 1359 icon: BaseController.new('atoms-icons', { 1360 icon: 'back' 1361 }) 1362 }; 1363}; 1364 1365module.exports = AtomsLink_Back; 1366 1367},{"BaseController":"BaseController"}],67:[function(require,module,exports){ 1368"use strict"; 1369var BaseController = require('BaseController'); 1370var AtomsLink_CheckAccount = BaseController.create('AtomsLink_CheckAccount'); 1371 1372AtomsLink_CheckAccount.prototype.helper = function () { 1373 return { 1374 text: __('generic.check-account'), 1375 hook: this.createHook('back-to-email'), 1376 mod: ['switch'] 1377 }; 1378}; 1379 1380module.exports = AtomsLink_CheckAccount; 1381 1382},{"BaseController":"BaseController"}],68:[function(require,module,exports){ 1383"use strict"; 1384var BaseController = require('BaseController'); 1385var AtomsLink_CheckAccount = BaseController.create('AtomsLink_CheckAccount'); 1386 1387AtomsLink_CheckAccount.prototype.helper = function () { 1388 return { 1389 text: __('generic.choose-different-account'), 1390 hook: this.createHook('choose-account'), 1391 mod: ['switch'] 1392 }; 1393}; 1394 1395module.exports = AtomsLink_CheckAccount; 1396 1397},{"BaseController":"BaseController"}],69:[function(require,module,exports){ 1398"use strict"; 1399var BaseController = require('BaseController'); 1400var AtomsLink_ContactAdmin = BaseController.create('AtomsLink_ContactAdmin'); 1401 1402AtomsLink_ContactAdmin.prototype.helper = function () { 1403 return { 1404 text: __('generic.contact-admin'), 1405 class_name: this.data.class_name, 1406 hook: this.createHook('contact-admin'), 1407 mod: ['switch'] 1408 }; 1409}; 1410 1411module.exports = AtomsLink_ContactAdmin; 1412 1413},{"BaseController":"BaseController"}],70:[function(require,module,exports){ 1414"use strict"; 1415var BaseController = require('BaseController'); 1416var AtomsLink_CreateAcc = BaseController.create('AtomsLink_CreateAcc'); 1417 1418AtomsLink_CreateAcc.prototype.helper = function () { 1419 return { 1420 text: __('generic.create-acc'), 1421 hook: this.createHook('create-acc'), 1422 mod: ['switch'] 1423 }; 1424}; 1425 1426module.exports = AtomsLink_CreateAcc; 1427 1428},{"BaseController":"BaseController"}],71:[function(require,module,exports){ 1429"use strict"; 1430var BaseController = require('BaseController'); 1431var AtomsLink_RemoveFromList = BaseController.create('AtomsLink_RemoveFromList'); 1432 1433AtomsLink_RemoveFromList.prototype.helper = function () { 1434 return { 1435 text: __('choose-account.remove'), 1436 // class_name: ['u-float-left'], 1437 hook: this.createHook('remove-from-list') 1438 }; 1439}; 1440 1441module.exports = AtomsLink_RemoveFromList; 1442 1443},{"BaseController":"BaseController"}],72:[function(require,module,exports){ 1444"use strict"; 1445var BaseController = require('BaseController'); 1446var AtomsLink_Retry = BaseController.create('AtomsLink_Retry'); 1447 1448AtomsLink_Retry.prototype.addListeners = function () { 1449 this.addDOMListener('', 'click', this.retry); 1450}; 1451 1452AtomsLink_Retry.prototype.retry = function (event) { 1453 event.preventDefault(); 1454 if (this.data.link) { 1455 document.location = this.data.link; 1456 } else { 1457 document.location.reload(); 1458 } 1459}; 1460 1461AtomsLink_Retry.prototype.helper = function () { 1462 return { 1463 link: this.data.link, 1464 text: __('generic.retry'), 1465 class_name: ['u-float-center'] 1466 }; 1467}; 1468 1469module.exports = AtomsLink_Retry; 1470 1471},{"BaseController":"BaseController"}],73:[function(require,module,exports){ 1472"use strict"; 1473var BaseController = require('BaseController'); 1474var AtomsLink_SignIn = BaseController.create('AtomsLink_SignIn'); 1475 1476AtomsLink_SignIn.prototype.helper = function () { 1477 return { 1478 text: __('generic.sign-in'), 1479 hook: this.createHook('sign-in'), 1480 mod: ['switch'] 1481 }; 1482}; 1483 1484module.exports = AtomsLink_SignIn; 1485 1486},{"BaseController":"BaseController"}],74:[function(require,module,exports){ 1487"use strict"; 1488var BaseController = require('BaseController'); 1489var AtomsLink_SignWithAnotherAcc = BaseController.create('AtomsLink_SignWithAnotherAcc'); 1490 1491AtomsLink_SignWithAnotherAcc.prototype.helper = function () { 1492 return { 1493 text: __('generic.sign-with-another-acc'), 1494 class_name: ['u-align-center'], 1495 hook: this.createHook('sign-with-another-acc'), 1496 mod: ['switch'] 1497 }; 1498}; 1499 1500module.exports = AtomsLink_SignWithAnotherAcc; 1501 1502},{"BaseController":"BaseController"}],75:[function(require,module,exports){ 1503"use strict"; 1504var BaseController = require('BaseController'); 1505var AtomsLink_WhatIsTeamchat = BaseController.create('AtomsLink_WhatIsTeamchat'); 1506 1507AtomsLink_WhatIsTeamchat.prototype.helper = function () { 1508 return { 1509 text: __('tc-join.what-is-teamchat'), 1510 hook: this.createHook('what-is-teamchat'), 1511 mod: ['switch'] 1512 }; 1513}; 1514 1515module.exports = AtomsLink_WhatIsTeamchat; 1516 1517},{"BaseController":"BaseController"}],76:[function(require,module,exports){ 1518"use strict"; 1519var BaseController = require('BaseController'); 1520var AtomsSwitch = BaseController.create('AtomsSwitch'); 1521 1522AtomsSwitch.prototype.helper = function () { 1523 return { 1524 avatar: BaseController.new('atoms-avatar', Object.assign({}, this.data, { 1525 class_name: ['o-switch__avatar'] 1526 })), 1527 name: this.data['name'] || this.data['email'], 1528 email: this.data['email'], 1529 class_name: this.data.class_name, 1530 hook: this.createHook('switch'), 1531 icon: [ 1532 // BaseController.new('atoms-icons', { 1533 // icon: 'arrow', 1534 // class_name: ['o-switch__ui', 'o-switch__arrow'] 1535 // }), 1536 BaseController.new('atoms-icons', { 1537 icon: 'xmark', 1538 class_name: ['o-switch__ui', 'o-switch__xmark'] 1539 }) 1540 ], 1541 link: { 1542 text: 'Undo', 1543 class_name: ['o-switch__ui', 'o-switch__addon'], 1544 hook: this.createHook('remove-from-list-undo') 1545 } 1546 }; 1547}; 1548 1549module.exports = AtomsSwitch; 1550 1551},{"BaseController":"BaseController"}],77:[function(require,module,exports){ 1552"use strict"; 1553var BaseController = require('BaseController'); 1554var AtomsWell = require('BaseController').create('AtomsWell'); 1555 1556AtomsWell.prototype.helper = function () { 1557 switch (this.data.type) { 1558 case 'success': 1559 this.data.mod = ['success']; 1560 this.data.icon = BaseController.new('atoms-icons', { 1561 icon: 'success', 1562 class_name: 'o-well__icon' 1563 }); 1564 break; 1565 case 'error': 1566 this.data.mod = ['error']; 1567 this.data.icon = BaseController.new('atoms-icons', { 1568 icon: 'error', 1569 class_name: 'o-well__icon' 1570 }); 1571 break; 1572 case 'primary': 1573 default: 1574 this.data.mod = ['secondary']; 1575 this.data.icon = BaseController.new('atoms-icons', { 1576 icon: 'information', 1577 class_name: 'o-well__icon' 1578 }); 1579 } 1580 return this.data; 1581}; 1582 1583module.exports = AtomsWell; 1584 1585},{"BaseController":"BaseController"}],78:[function(require,module,exports){ 1586"use strict"; 1587var BaseController = require('BaseController'); 1588var Validatable = require('./validatable'); 1589 1590var Form = BaseController.create('Form'); 1591 1592Form.prototype.onCreate = function () { 1593 this.inputs = {}; 1594};
1595 1596/** 1597 * Find all validatable children and validate them. 1598 * @param {Function} callback 1599 * @returns {boolean} 1600 */ 1601Form.prototype.validate = function (callback) { 1602 var inputs = this.getChildrenByClass(Validatable), 1603 isValid = true; 1604 1605 this.disable(); 1606 1607 /** 1608 * @returns {Boolean} 1609 */ 1610 function validate() { 1611 var input = inputs.shift(); 1612 if (input) { 1613 input.validate(false, function (valid) { 1614 isValid = isValid && valid; 1615 validate.call(this); 1616 }.bind(this)); 1617 } else { 1618 if (!isValid) { 1619 this.hasError(); 1620 callback && callback(false); 1621 } else { 1622 callback && callback(true); 1623 } 1624 } 1625 } 1626 1627 validate.call(this); 1628}; 1629 1630Form.prototype.saveInputs = function () { 1631 this.selectAll('input').concat(this.selectAll('textarea')).forEach(function (input) { 1632 var value = input.value; 1633 if (input.type === 'checkbox') { 1634 value = input.checked; 1635 } 1636 this.inputs[input.getAttribute('name')] = value; 1637 }, this); 1638}; 1639 1640Form.prototype.loadInputs = function () { 1641 this.selectAll('input').concat(this.selectAll('textarea')).forEach(function (input) { 1642 var value = this.inputs[input.getAttribute('name')]; 1643 if (!value) { 1644 return; 1645 } 1646 input.focus(); 1647 if (input.type === 'checkbox') { 1648 input.checked = value; 1649 } else { 1650 input.value = value; 1651 } 1652 input.blur(); 1653 }, this); 1654}; 1655 1656module.exports = Form; 1657 1658},{"./validatable":127,"BaseController":"BaseController"}],79:[function(require,module,exports){ 1659"use strict"; 1660var BaseController = require('BaseController'); 1661var MoleculesButton = BaseController.create('MoleculesButton'); 1662 1663MoleculesButton.prototype.helper = function () { 1664 return { 1665 mod: this.data['mod'], 1666 class_name: this.data.class_name, 1667 button: BaseController.new('atoms-element-button', this.data.button) 1668 }; 1669}; 1670 1671module.exports = MoleculesButton; 1672 1673},{"BaseController":"BaseController"}],80:[function(require,module,exports){ 1674"use strict"; 1675var BaseModel = require('BaseModel'); 1676var BaseController = require('BaseController'); 1677var MoleculesCaptcha = BaseController.create('MoleculesCaptcha'); 1678 1679MoleculesCaptcha.prototype.addListeners = function () { 1680 this.addHookListener('generate-captcha', 'click', this.rerender); 1681}; 1682 1683MoleculesCaptcha.prototype.afterRender = function () { 1684 this.regenerate(); 1685}; 1686 1687MoleculesCaptcha.prototype.regenerate = function () { 1688 BaseModel.instance('WebClient').getCaptcha({ 1689 success: function (response) { 1690 var parent, style; 1691 this.uid = response.uid; 1692 parent = this.hook('captcha_html'); 1693 while (parent.firstChild) { 1694 parent.removeChild(parent.firstChild); 1695 } 1696 parent.insertAdjacentHTML('afterbegin', response.html); 1697 style = document.createElement('style'); 1698 style.insertAdjacentHTML('afterbegin', response.style); 1699 this.hook('captcha_html').appendChild(style); 1700 }, 1701 error: function () { 1702 console.error(arguments); 1703 }, 1704 context: this 1705 }); 1706}; 1707 1708MoleculesCaptcha.prototype.helper = function () { 1709 var data = this.data || {}; 1710 1711 data.addon = BaseController.new('atoms-addon', { 1712 text: __('generic.captcha-generate'), 1713 mod: ['top'], 1714 hook: this.createHook('generate-captcha') 1715 }); 1716 1717 data.hook = this.createHook('captcha_html'); 1718 return data; 1719}; 1720 1721module.exports = MoleculesCaptcha; 1722 1723},{"BaseController":"BaseController","BaseModel":"BaseModel"}],81:[function(require,module,exports){ 1724"use strict"; 1725var BaseController = require('BaseController'); 1726var MoleculesCheckbox = BaseController.create('MoleculesCheckbox'); 1727 1728MoleculesCheckbox.prototype.onCreate = function () { 1729 this.input = BaseController.new('atoms-element-input', this.data.input); 1730}; 1731 1732MoleculesCheckbox.prototype.addListeners = function() { 1733 this.addDOMListener('input', 'change', this.onChange); 1734}; 1735 1736MoleculesCheckbox.prototype.onChange = function () { 1737 this.DOMElement.classList.toggle('checked', this.input.checked); 1738}; 1739 1740MoleculesCheckbox.prototype.helper = function () { 1741 1742 this.data.input.type = this.data.input.type || 'checkbox'; 1743 this.data.input.class_name = this.data.input.class_name || ['o-checkbox__element']; 1744 this.data.input.name = this.data.input.name; 1745 return { 1746 class_name: this.data.class_name, 1747 input: this.input, 1748 label: this.data.label 1749 }; 1750}; 1751 1752module.exports = MoleculesCheckbox; 1753 1754},{"BaseController":"BaseController"}],82:[function(require,module,exports){ 1755"use strict"; 1756var BaseController = require('BaseController'); 1757var MoleculesInput = BaseController.create('MoleculesInput'); 1758 1759MoleculesInput.prototype.addListeners = function () { 1760 this.addDOMListener('input', 'input keyup blur change', this.checkEmptiness); 1761 if (this.data.input.type === 'password') { 1762 this.addDOMListener('input', 'keyup', this.capsLockCheck); 1763 } 1764 this.addDOMListener('input', 'keyup', this.keyup); 1765}; 1766
1767MoleculesInput.prototype.afterRender = function () { 1768 this.checkEmptiness({target: this.select('input')}); 1769}; 1770 1771MoleculesInput.prototype.capsLockCheck = function (event) { 1772 if (event.getModifierState) { 1773 this.input.DOMElement.setCustomValidity(event.getModifierState('CapsLock') ? __('error.capslock') : ''); 1774 this.input.DOMElement.reportValidity(); 1775 } 1776}; 1777 1778MoleculesInput.prototype.keyup = function (event) { 1779 ~[10, 13].indexOf(event.which || event.keyCode) && (event.form = this.DOMElement.closest('form')) && this.getInstanceByElement(event.form).submitForm(event); 1780}; 1781 1782MoleculesInput.prototype.checkEmptiness = function (event) { 1783 this.DOMElement.classList[event.target.value ? 'remove' : 'add']('is-empty'); 1784 this.data.input.value = event.target.value; 1785}; 1786 1787MoleculesInput.prototype.focus = function () { 1788 this.input.focus(); 1789}; 1790 1791MoleculesInput.prototype.helper = function () { 1792 var label; 1793 1794 this.data.input.class_name = ['o-form__element']; 1795 if (this.data.input.type === 'date') { 1796 this.input = BaseController.new('atoms-element-input~date', this.data.input); 1797 } else { 1798 this.input = BaseController.new('atoms-element-input', this.data.input); 1799 } 1800 1801 if (this.data.label) { 1802 this.data.label.class_name = ['o-form__label', 'o-form__label--main', 'o-form__label--floating']; 1803 label = BaseController.new('atoms-label', this.data.label); 1804 } 1805 1806 return { 1807 class_name: this.data.class_name, 1808 input: this.input, 1809 label: label, 1810 addon: this.data.addon, 1811 tooltip: this.data.tooltip, 1812 mod: this.data.mod, 1813 tag: this.data.tag, 1814 hook: this.data.hook, 1815 icon: this.data.icon, 1816 value: this.data.value 1817 }; 1818}; 1819 1820module.exports = MoleculesInput; 1821 1822},{"BaseController":"BaseController"}],83:[function(require,module,exports){ 1823"use strict"; 1824var BaseModel = require('BaseModel'); 1825var BaseController = require('BaseController'); 1826var MoleculesInput_Password = require('./input~password.js'); 1827var MoleculesInput_PasswordWithPolicy = BaseController.create('MoleculesInput_PasswordWithPolicy', MoleculesInput_Password); 1828 1829MoleculesInput_PasswordWithPolicy.prototype.addListeners = function () { 1830 MoleculesInput_Password.prototype.addListeners.call(this); 1831}; 1832 1833MoleculesInput_PasswordWithPolicy.prototype.helper = function () { 1834 var Login = BaseModel.instance('Login'); 1835 var password_policy = BaseModel.instance('WebClient').getData('password_policy') || {}; 1836 1837 var alias_rule = password_policy.getValue('user_alias') && { 1838 name: 'not_contains', 1839 counterpart_value: Login.getData('create_account').username || Login.getData('chosen_account').username, 1840 parent_hook: 'form', 1841 counterpart_hook: 'username', 1842 message: __('validation.user_alias') 1843 }; 1844 1845 var policies = password_policy.getWorkingDataKeys().filter(function(policy) { 1846 return policy !== 'user_alias'; 1847 }); 1848 1849 this.data.rules = [ 1850 { 1851 name: 'empty', 1852 message: __('validation.empty') 1853 }, 1854 alias_rule 1855 ].concat(policies.map(function (key) { 1856 return password_policy.getValue(key) && { 1857 name: key, 1858 data: password_policy.getValue(key), 1859 message: __('validation.' + key, password_policy.getValue(key)) 1860 }; 1861 })).filter(Boolean); 1862 1863 this.data.addon = Array.isArray(this.data.addon) ? this.data.addon : [this.data.addon]; 1864 if (policies.length) { 1865 if (!this.data.addon.some(function(addon) { 1866 return addon.data.class_name === 'policy'; 1867 })) { 1868 this.data.addon.push(BaseController.new('atoms-addon', { 1869 hook: this.createHook('tooltip'), 1870 class_name: 'policy', 1871 text: __('generic.password-policy') 1872 })); 1873 } 1874 this.data.tooltip_well = this.data.tooltip_well === void 0 ? { 1875 title: __('generic.password-policy'), 1876 text: policies.map(function (key) { 1877 return password_policy.getValue(key) && __('validation.' + key, password_policy.getValue(key)); 1878 }).filter(Boolean), 1879 type: 'primary', 1880 pinned: this.data.tooltip_well_pinned 1881 } : this.data.tooltip_well; 1882 } 1883 1884 return MoleculesInput_Password.prototype.helper.call(this); 1885}; 1886 1887module.exports = MoleculesInput_PasswordWithPolicy; 1888 1889},{"./input~password.js":84,"BaseController":"BaseController","BaseModel":"BaseModel"}],84:[function(require,module,exports){ 1890"use strict"; 1891var BaseController = require('BaseController'); 1892var MoleculesInput_Validatable = require('./input~validatable.js'); 1893var MoleculesInput_Password = BaseController.create('MoleculesInput_Password', MoleculesInput_Validatable); 1894 1895MoleculesInput_Password.prototype.onCreate = function () { 1896 this.show = false; 1897 this.data.input.type = 'password'; 1898 this.data.input.class_name = ['o-form__element--password']; 1899};
1900 1901MoleculesInput_Password.prototype.addListeners = function () { 1902 MoleculesInput_Validatable.prototype.addListeners.call(this); 1903 this.addDelegatedHookListener('show-password', 'click', this.showPassword); 1904}; 1905 1906MoleculesInput_Password.prototype.showPassword = function () { 1907 var icon = (this.data.addon[0] || this.data.addon).data.icon; 1908 this.select('input').setAttribute('type', this.show ? 'password' : 'text'); 1909 icon.data.icon = this.show ? 'eye' : 'eye-crossed'; 1910 this.show = !this.show; 1911 icon.rerender(); 1912}; 1913 1914module.exports = MoleculesInput_Password; 1915 1916},{"./input~validatable.js":86,"BaseController":"BaseController"}],85:[function(require,module,exports){ 1917"use strict"; 1918var BaseModel = require('BaseModel'); 1919var BaseController = require('BaseController'); 1920var MoleculesInput = require('./input'); 1921var MoleculesInput_Search = BaseController.create('MoleculesInput_Search', MoleculesInput); 1922 1923MoleculesInput_Search.prototype.addListeners = function () { 1924 MoleculesInput.prototype.addListeners.call(this); 1925 1926 this.addDOMListener('input', 'submit', this.search); 1927 this.addDOMListener('input', 'keydown', this.keyup); 1928}; 1929 1930MoleculesInput_Search.prototype.keyup = function (event) { 1931 ((event.which || event.keyCode) === 13) && this.search(event); 1932}; 1933 1934MoleculesInput_Search.prototype.search = function (event) { 1935 var WebClient = BaseModel.instance('WebClient'); 1936 var url = WebClient.getData('layout_settings').getValue('search_phrase').replace(/%%query%%/g, event.target.value); 1937 var search = window.open(url); 1938 if (!search) { 1939 window.location = url; 1940 return; 1941 } 1942 search.focus(); 1943 event.target.value = ''; 1944 event.target.blur(); 1945 1946 event.preventDefault(); 1947 event.stopPropagation(); 1948 event.stopImmediatePropagation(); 1949}; 1950 1951module.exports = MoleculesInput_Search; 1952 1953},{"./input":82,"BaseController":"BaseController","BaseModel":"BaseModel"}],86:[function(require,module,exports){ 1954"use strict"; 1955var BaseController = require('BaseController'); 1956var MoleculesInput = require('./input'); 1957var Validatable = require('../../validatable'); 1958var MoleculesInput_Validatable = BaseController.create('MoleculesInput_Validatable', MoleculesInput, Validatable); 1959 1960MoleculesInput_Validatable.prototype.addListeners = function () { 1961 Validatable.prototype.addListeners.call(this); 1962 MoleculesInput.prototype.addListeners.call(this); 1963 1964 this.addDOMListener('input', 'change', this.validate); 1965}; 1966 1967MoleculesInput_Validatable.prototype.helper = function () { 1968 this.data.tooltip && (this.data.tooltip.hook = this.createHook('tooltip')); 1969 return MoleculesInput.prototype.helper.call(this); 1970}; 1971 1972module.exports = MoleculesInput_Validatable; 1973 1974},{"../../validatable":127,"./input":82,"BaseController":"BaseController"}],87:[function(require,module,exports){ 1975"use strict"; 1976var BaseModel = require('BaseModel'); 1977var BaseController = require('BaseController'); 1978var Window = require('../../window.js'); 1979var MoleculesLanguagePicker = BaseController.create('MoleculesLanguagePicker', Window); 1980 1981MoleculesLanguagePicker.prototype.onCreate = function () { 1982 Window.prototype.onCreate.apply(this, arguments); 1983 this.setup({ 1984 move_selector: false, 1985 draggable_border: false 1986 }); 1987}; 1988 1989MoleculesLanguagePicker.prototype.afterRender = function () { 1990 Window.prototype.afterRender.apply(this, arguments); 1991 this.DOMElement.classList.add('c-card'); 1992}; 1993 1994MoleculesLanguagePicker.prototype.addListeners = function () { 1995 Window.prototype.addListeners.apply(this, arguments); 1996 this.addPartialListener('molecules-language-picker-item', 'click', this.changeLanguage); 1997 this.addClickOutsideListener(this.DOMShadowElement, this.onClickOutside); 1998}; 1999 2000MoleculesLanguagePicker.prototype.onClickOutside = function () { 2001 this.invoker.removeChooseLanguage(); 2002}; 2003 2004MoleculesLanguagePicker.prototype.changeLanguage = function (event) { 2005 var controller = this.getInstanceByElement(event.target); 2006 var code = controller.data.model.getValue('code'); 2007 var codes = BaseModel.static('language').codes; 2008 this.disable(); 2009 2010 BaseModel.instance('Login').changeLanguage(codes[code] || code, { 2011 success: function () { 2012 var site = this.getParent('sites'); 2013 site.style && document.head.appendChild(site.style); 2014 this.invoker.removeChooseLanguage.call(this.invoker); 2015 site.getChildren('organisms-bar').forEach(function (bar) { 2016 bar.rerender(); 2017 }); 2018 site.getChildren('templates-card').forEach(function (card) { 2019 card.saveInputs(); 2020 card.rerender().then(function() {
2021 card.loadInputs(); 2022 card.enable(); 2023 }); 2024 }); 2025 }, 2026 error: function (error) { 2027 var site = this.getParent('sites'); 2028 this.enable(); 2029 this.trigger('error-message-show', { 2030 title: __('generic.error'), 2031 text: error || __('error.language-not-found'), 2032 type: 'error' 2033 }); 2034 this.invoker.removeChooseLanguage.call(this.invoker); 2035 site.getChildren('templates-card').forEach(function (card) { 2036 card.enable(); 2037 }); 2038 }, 2039 context: this 2040 }); 2041 2042}; 2043 2044MoleculesLanguagePicker.prototype.helper = function () { 2045 var WebClient = BaseModel.instance('WebClient'); 2046 var languages = WebClient.getData('languages'); 2047 var columns = Math.ceil(languages.length / 13); 2048 var rows = Math.ceil(languages.length / columns); 2049 var column = []; 2050 2051 languages.sort(function (a, b) { 2052 var _a = a.getValue('code'), _b = b.getValue('code'); 2053 if (_a === 'en') { 2054 return -1; 2055 } else if (_b === 'en') { 2056 return 1; 2057 } 2058 return _a < _b ? -1 : _b < _a; 2059 }).map(function (language) { 2060 var code = language.getValue('code'); 2061 return BaseController.new('molecules-language-picker-item', { 2062 text: __('languages.' + code, { useDefaultDictionary: true }), 2063 class_name: WebClient.getData('layout_settings').getUserLanguage().getValue('code') === code ? ['is-active'] : false, 2064 hook: this.createHook('language'), 2065 model: language 2066 }); 2067 }, this).forEach(function (language, i) { 2068 var index = Math.floor(i / rows); 2069 column[index] = column[index] || {item: []}; 2070 column[index].item.push(language); 2071 }); 2072 return { 2073 column: column 2074 }; 2075}; 2076 2077module.exports = MoleculesLanguagePicker; 2078 2079},{"../../window.js":128,"BaseController":"BaseController","BaseModel":"BaseModel"}],88:[function(require,module,exports){ 2080"use strict"; 2081var BaseController = require('BaseController'); 2082var MoleculesSelect = BaseController.create('MoleculesSelect'); 2083 2084MoleculesSelect.prototype.addListeners = function () { 2085 this.addDOMListener('select', 'change', this.checkEmptiness); 2086}; 2087 2088MoleculesSelect.prototype.afterRender = function () { 2089 this.checkEmptiness({target: this.select('select')}); 2090}; 2091 2092MoleculesSelect.prototype.checkEmptiness = function (event) { 2093 this.DOMElement.classList[event.target.value ? 'remove' : 'add']('is-empty'); 2094 this.data.select.value = event.target.value; 2095}; 2096 2097MoleculesSelect.prototype.focus = function () { 2098 this.input.focus(); 2099}; 2100 2101MoleculesSelect.prototype.helper = function () { 2102 var select, label; 2103 this.data.select = this.data.select || {}; 2104 this.data.select.class_name = this.data.select.class_name || []; 2105 this.data.select.class_name.push('o-form__element'); 2106 select = BaseController.new('atoms-element-select', this.data.select); 2107 2108 if (this.data.label) { 2109 this.data.label.class_name = this.data.label.class_name || []; 2110 this.data.label.class_name.push('o-form__label', 'o-form__label--main', 'o-form__label--floating'); 2111 label = BaseController.new('atoms-label', this.data.label); 2112 } 2113 2114 return { 2115 class_name: this.data.class_name, 2116 select: select, 2117 label: label, 2118 icon: BaseController.new('atoms-icons', { 2119 icon: 'arrow', 2120 class_name: ['o-select__arrow'] 2121 }) 2122 }; 2123}; 2124 2125module.exports = MoleculesSelect; 2126 2127},{"BaseController":"BaseController"}],89:[function(require,module,exports){ 2128"use strict"; 2129var BaseController = require('BaseController'); 2130var MoleculesSelect = require('./select'); 2131var Validatable = require('../../validatable'); 2132var MoleculesSelect_Validatable = BaseController.create('MoleculesSelect_Validatable', MoleculesSelect, Validatable); 2133 2134MoleculesSelect_Validatable.prototype.addListeners = function () { 2135 Validatable.prototype.addListeners.call(this); 2136 MoleculesSelect.prototype.addListeners.call(this); 2137 2138 this.addDOMListener('select', 'change', this.validate); 2139}; 2140 2141MoleculesSelect_Validatable.prototype.helper = function () { 2142 this.data.tooltip && (this.data.tooltip.hook = this.createHook('tooltip')); 2143 return MoleculesSelect.prototype.helper.call(this); 2144}; 2145 2146module.exports = MoleculesSelect_Validatable; 2147 2148},{"../../validatable":127,"./select":88,"BaseController":"BaseController"}],90:[function(require,module,exports){ 2149"use strict"; 2150var BaseController = require('BaseController'); 2151var MoleculesStatic = BaseController.create('MoleculesStatic'); 2152 2153MoleculesStatic.prototype.helper = function () { 2154 if (this.data.label) { 2155 this.data.label.class_name = this.data.label.class_name || []; 2156 this.data.label.class_name.push('o-form__label', 'o-form__label--main', 'o-form__label--floating'); 2157 this.data.label = BaseController.new('atoms-label', this.data.label); 2158 } 2159 2160 return this.data; 2161}; 2162 2163module.exports = MoleculesStatic; 2164 2165},{"BaseController":"BaseController"}],91:[function(require,module,exports){ 2166"use strict"; 2167var BaseController = require('BaseController'); 2168var MoleculesTextarea = BaseController.create('MoleculesTextarea'); 2169 2170MoleculesTextarea.prototype.addListeners = function () { 2171 this.addDOMListener('textarea', 'input keyup blur', this.checkEmptiness); 2172}; 2173
2174MoleculesTextarea.prototype.afterRender = function () { 2175 this.checkEmptiness({target: this.select('textarea')}); 2176}; 2177 2178MoleculesTextarea.prototype.checkEmptiness = function (event) { 2179 this.DOMElement.classList[event.target.value ? 'remove' : 'add']('is-empty'); 2180 this.data.textarea.text = event.target.value; 2181}; 2182 2183MoleculesTextarea.prototype.focus = function () { 2184 this.input.focus(); 2185}; 2186 2187MoleculesTextarea.prototype.helper = function () { 2188 var textarea, label; 2189 this.data.textarea = this.data.textarea || {}; 2190 this.data.textarea.class_name = this.data.textarea.class_name || []; 2191 this.data.textarea.class_name.push('o-form__element'); 2192 textarea = BaseController.new('atoms-element-textarea', this.data.textarea); 2193 2194 if (this.data.label) { 2195 this.data.label.class_name = this.data.label.class_name || []; 2196 this.data.label.class_name.push('o-form__label', 'o-form__label--main', 'o-form__label--floating'); 2197 label = BaseController.new('atoms-label', this.data.label); 2198 } 2199 2200 return { 2201 class_name: this.data.class_name, 2202 textarea: textarea, 2203 label: label, 2204 tooltip: this.data.tooltip, 2205 addon: this.data.addon, 2206 mod: this.data.mod, 2207 tag: this.data.tag, 2208 hook: this.data.hook, 2209 icon: this.data.icon 2210 }; 2211}; 2212 2213module.exports = MoleculesTextarea; 2214 2215},{"BaseController":"BaseController"}],92:[function(require,module,exports){ 2216"use strict"; 2217var BaseController = require('BaseController'); 2218var MoleculesTextarea = require('./textarea'); 2219var Validatable = require('../../validatable'); 2220var MoleculesTextarea_Validatable = BaseController.create('MoleculesTextarea_Validatable', MoleculesTextarea, Validatable); 2221 2222MoleculesTextarea_Validatable.prototype.addListeners = function () { 2223 Validatable.prototype.addListeners.call(this); 2224 MoleculesTextarea.prototype.addListeners.call(this); 2225 2226 this.addDOMListener('textarea', 'change', this.validate); 2227}; 2228 2229MoleculesTextarea_Validatable.prototype.helper = function () { 2230 this.data.tooltip && (this.data.tooltip.hook = this.createHook('tooltip')); 2231 return MoleculesTextarea.prototype.helper.call(this); 2232}; 2233 2234module.exports = MoleculesTextarea_Validatable; 2235 2236},{"../../validatable":127,"./textarea":91,"BaseController":"BaseController"}],93:[function(require,module,exports){ 2237"use strict"; 2238var BaseModel = require('BaseModel'); 2239var BaseController = require('BaseController'); 2240var OrganismsBar_Footer = BaseController.create('OrganismsBar_Footer'); 2241 2242OrganismsBar_Footer.prototype.helper = function () { 2243 var WC = BaseModel.instance('WebClient'); 2244 2245 return { 2246 class_name: ['o-external__footer'], 2247 section: [ 2248 { 2249 mod: ['start'], 2250 footer: WC.getData('restrictions').getValue('disable_copyright') ? false : { 2251 current_year: new Date().getFullYear(), 2252 copyright: __('generic.copyright') 2253 } 2254 }, 2255 { 2256 mod: ['center'], 2257 footer: { 2258 social: [ 2259 (WC.getData('restrictions').getValue('website_disabled') || !WC.getData('layout_settings').getValue('website_link')) ? false : { 2260 icon: BaseController.new('atoms-icons', { 2261 icon: 'website', 2262 class_name: ['o-external__icon'] 2263 }), 2264 href: WC.getData('layout_settings').getValue('website_link') 2265 }, 2266 (WC.getData('restrictions').getValue('facebook_disabled') || !WC.getData('layout_settings').getValue('facebook_link')) ? false : { 2267 icon: BaseController.new('atoms-icons', { 2268 icon: 'facebook', 2269 class_name: ['o-external__icon'] 2270 }), 2271 href: WC.getData('layout_settings').getValue('facebook_link') 2272 }, 2273 (WC.getData('restrictions').getValue('twitter_disabled') || !WC.getData('layout_settings').getValue('twitter_link')) ? false : { 2274 icon: BaseController.new('atoms-icons', { 2275 icon: 'twitter', 2276 class_name: ['o-external__icon'] 2277 }), 2278 href: WC.getData('layout_settings').getValue('twitter_link') 2279 }, 2280 (WC.getData('restrictions').getValue('linkedin_disabled') || !WC.getData('layout_settings').getValue('linkedin_link')) ? false : { 2281 icon: BaseController.new('atoms-icons', { 2282 icon: 'linkedin', 2283 class_name: ['o-external__icon'] 2284 }), 2285 href: WC.getData('layout_settings').getValue('linkedin_link') 2286 }
2287 ].filter(Boolean) 2288 } 2289 }, 2290 { 2291 mod: ['end'], 2292 footer: WC.getData('restrictions').getValue('disable_copyright') ? false : { 2293 'find-out-more': { 2294 text: __('generic.find_out_more', { 2295 md: true 2296 }) 2297 }, 2298 version: BaseModel.instance('Server').getData('c_niceversion') 2299 } 2300 } 2301 ] 2302 }; 2303}; 2304 2305module.exports = OrganismsBar_Footer; 2306 2307},{"BaseController":"BaseController","BaseModel":"BaseModel"}],94:[function(require,module,exports){ 2308"use strict"; 2309var BaseModel = require('BaseModel'); 2310var BaseController = require('BaseController'); 2311var OrganismsCardHeader = BaseController.create('OrganismsCardHeader'); 2312var Escape = require('@icewarp/escape-string'); 2313 2314OrganismsCardHeader.prototype.addListeners = function () {}; 2315 2316OrganismsCardHeader.prototype.helper = function () { 2317 var Server = BaseModel.instance('Server'); 2318 var WebClient = BaseModel.instance('WebClient'); 2319 var Login = BaseModel.instance('Login'); 2320 2321 var custom_logo = WebClient.getData('layout_settings').getValue('login_logo'); 2322 2323 var subtitle = this.data.subtitle === void 0 ? Login.getData('chosen_account').name && { 2324 text: Escape(Login.getData('chosen_account').name), 2325 class_name: ['o-header__subtitle'], 2326 mod: ['normal'] 2327 } : this.data.subtitle; 2328 2329 var subsubtitle = this.data.subsubtitle === void 0 ? Login.getData('chosen_account').email && { 2330 text: Escape(Login.getData('chosen_account').email), 2331 class_name: ['o-header__subsubtitle'], 2332 mod: ['normal'] 2333 } : this.data.subsubtitle; 2334 2335 var mod = this.data.mod || []; 2336 if (!Array.isArray(mod)) { 2337 mod = [mod];
2338 } 2339 mod.push('default'); 2340 2341 if (this.data['card-icon']) { 2342 this.data['card-icon'].data.class_name = ['o-header__image', 'o-header__image--default']; 2343 } 2344 2345 this.data.well = this.data.well || {}; 2346 this.data.well.class_name = this.data.well.class_name || []; 2347 this.data.well.class_name.push('o-header__well'); 2348 2349 return { 2350 avatar: this.data.avatar !== void 0 ? this.data.avatar : BaseController.new('atoms-avatar', Object.assign({ class_name: ['o-header__avatar'] }, Login.getData('chosen_account'))), 2351 logo: BaseController.new('atoms-image', { 2352 class_name: ['o-header__image', 'o-header__image--default', custom_logo ? '' : 'o-header__default_logo'], 2353 src: custom_logo ? Server.getLogo() : './images/logo.svg' 2354 }), 2355 icon: this.data.icon || BaseController.new('atoms-icons', { 2356 icon: 'icewarp', 2357 class_name: [ 2358 'o-header__image', 2359 'o-header__image--default' 2360 ] 2361 }), 2362 'card-icon': this.data['card-icon'], 2363 heading: this.data.heading, 2364 hook: this.data.hook, 2365 subtitle: subtitle, 2366 subsubtitle: subsubtitle, 2367 mod: mod, 2368 well: BaseController.new('atoms-well', this.data.well) 2369 }; 2370}; 2371 2372module.exports = OrganismsCardHeader; 2373 2374},{"@icewarp/escape-string":159,"BaseController":"BaseController","BaseModel":"BaseModel"}],95:[function(require,module,exports){ 2375"use strict"; 2376var BaseController = require('BaseController'); 2377var OrganismsCardHeader = require('./card-header.js'); 2378var OrganismsCardHeader_Message = BaseController.create('OrganismsCardHeader_Message', OrganismsCardHeader); 2379 2380OrganismsCardHeader_Message.prototype.helper = function () { 2381 this.data.well && (this.data.well.icon = false); 2382 2383 return OrganismsCardHeader.prototype.helper.call(this); 2384}; 2385 2386module.exports = OrganismsCardHeader_Message; 2387 2388},{"./card-header.js":94,"BaseController":"BaseController"}],96:[function(require,module,exports){ 2389"use strict"; 2390var Window = require('../../window.js'); 2391var BaseController = require('BaseController'); 2392var OrganismsWindow = BaseController.create('OrganismsWindow', Window); 2393 2394OrganismsWindow.prototype.onCreate = function () { 2395 Window.prototype.onCreate.apply(this, arguments); 2396 this.setup({ 2397 //move_selector: ".molecules-window-header", 2398 //draggable_border: 10 2399 }); 2400}; 2401 2402OrganismsWindow.prototype.beforeFullscreenToggle = function () { 2403 this.DOMElement.classList[this.fullscreen ? 'remove' : 'add']('fullscreen'); 2404}; 2405 2406module.exports = OrganismsWindow; 2407 2408},{"../../window.js":128,"BaseController":"BaseController"}],97:[function(require,module,exports){ 2409"use strict"; 2410var BaseController = require('BaseController'); 2411var SitesGeneric = BaseController.create('SitesGeneric'); 2412 2413SitesGeneric.prototype.afterRender = function () { 2414 this.DOMElement.setAttribute('id', 'content'); 2415 this.DOMElement.classList.add('site'); 2416}; 2417 2418module.exports = SitesGeneric; 2419 2420},{"BaseController":"BaseController"}],98:[function(require,module,exports){ 2421"use strict"; 2422var Breakpoint = require('Breakpoint'); 2423var BaseController = require('BaseController'); 2424var GenericSite = require('../generic'); 2425var SitesLogin = BaseController.create('SitesLogin', GenericSite); 2426var Browser = require('@icewarp/utils').browser; 2427var extractColors = require('extract-colors'); 2428var rgbToHsl = require('rgb-to-hsl'); 2429 2430var BaseModel = require('BaseModel'); 2431var Hash = require('@icewarp/hash'); 2432var LocalStorage = require('@icewarp/localstorage'); 2433 2434/** 2435 * 2436 * @param {string} name 2437 * @returns {string|undefined} 2438 */ 2439function getCookie(name) { 2440 var value = '; ' + document.cookie + ';'; 2441 var parts = value.split('; ' + name + '='); 2442 if (parts.length === 2) { 2443 return parts.pop().split(';').shift(); 2444 } 2445} 2446 2447/** 2448 * 2449 * @param {String} hex 2450 * @returns {Object} 2451 */ 2452function hexToRgb(hex) { 2453 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 2454 return result ? { 2455 r: parseInt(result[1], 16), 2456 g: parseInt(result[2], 16), 2457 b: parseInt(result[3], 16) 2458 } : null; 2459} 2460 2461SitesLogin.prototype.addListeners = function () { 2462 this.addDOMListener(document.body, 'keydown', this.keydown); 2463 this.addBreakpointListener([Breakpoint.xs, Breakpoint.sm], this.recompileAd); 2464 this.addBreakpointListener([Breakpoint.md, Breakpoint.lg, Breakpoint.xl], this.recompileAd); 2465}; 2466
2467SitesLogin.prototype.afterRender = function () { 2468 var backgroundImage; 2469 var layoutSettings = BaseModel.instance('WebClient').getData('layout_settings'); 2470 if (!layoutSettings.getValue('login_background_solid') || layoutSettings.getValue('login_background_solid') === 'false') { 2471 backgroundImage = BaseModel.instance('Server').getBackground(); 2472 this.DOMElement.style.backgroundImage = 'url(' + backgroundImage + ')'; 2473 } 2474 GenericSite.prototype.afterRender.call(this); 2475}; 2476 2477SitesLogin.prototype.keydown = function (event) { 2478 if (!document.querySelectorAll('input:focus, textarea:focus, select:focus, button:focus').length && !event.altKey && !event.ctrlKey && !event.metaKey && (!~[8, 9].indexOf(event.which || event.keyCode))) { 2479 this.selectAll('input, textarea').some(function (elem) { 2480 if (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length) { 2481 elem.focus(); 2482 return true; 2483 } 2484 }); 2485 } 2486}; 2487 2488SitesLogin.cards_order = { 2489 unavailable: 0, 2490 'choose-account': 1, 2491 'sign-in': 2, 2492 'sign-in-guest': 3, 2493 'sign-in-password': 3, 2494 'forgot-password': 3, 2495 'create-account': 3, 2496 'join': 3, 2497 'two-factor': 4, 2498 'personal': 4, 2499 'join-username': 4, 2500 'reset-password': 5, 2501 'change-password': 5, 2502 'set-password': 5, 2503 'join-password': 5, 2504 'verification': 6, 2505 'contact-admin': 7, 2506 'tc-join': 101, 2507 'tc-check-email': 102, 2508 'tc-collaboration': 103, 2509 'tc-share': 104, 2510 'tc-actions': 105, 2511 'gateway-login': 301, 2512 'generic-message': 401, 2513 'guest-verify': 500, 2514 'confirm-personality': 501, 2515 'oauth-grant': 601, 2516}; 2517 2518SitesLogin['restriction_sign-in-guest'] = async function () { 2519 var config = BaseModel.instance('Config').getData('config'); 2520 var Login = BaseModel.instance('Login'); 2521 if (config.application !== 'webclient') { 2522 return Login.getDefaultCard(); 2523 } 2524}; 2525SitesLogin['restriction_sign-in-password'] = async function () { 2526 var Login = BaseModel.instance('Login'); 2527 if (!Login.getData('chosen_account').email) { 2528 if (Login.getUsers().length === 1) { 2529 Login.setData('chosen_account', Login.getUsers()[0]); 2530 } else { 2531 return Login.getDefaultCard(); 2532 } 2533 } 2534}; 2535SitesLogin['restriction_two-factor'] = function () { 2536 var Login = BaseModel.instance('Login'); 2537 if (Login.getUsers().length === 1) { 2538 Login.setData('chosen_account', Login.getUsers()[0]); 2539 return 'sign-in-password'; 2540 } else { 2541 return Login.getDefaultCard(); 2542 } 2543}; 2544SitesLogin['restriction_set-password'] = function () { 2545 var Login = BaseModel.instance('Login'); 2546 if (!Login.getData('create_account').username || !Login.getData('chosen_account').email) { 2547 return 'create-account'; 2548 } 2549}; 2550SitesLogin['restriction_generic-message'] = function () { 2551 return !Hash.getParts().tconly && BaseModel.instance('Login').getDefaultCard(); 2552}; 2553SitesLogin.autoChooseAccount = true; 2554SitesLogin['restriction_choose-account'] = function () { 2555 var last_login; 2556 var config = BaseModel.instance('Config').getData('config'); 2557 var Login = BaseModel.instance('Login'); 2558 if (Login.getData('chosen_account').email) { 2559 return 'choose-account'; 2560 } 2561 if (Login.getUsers().length === 1 && SitesLogin.autoChooseAccount) { 2562 SitesLogin.autoChooseAccount = false; 2563 Login.setData('chosen_account', Login.getUsers()[0]); 2564 return 'sign-in-password'; 2565 } else { 2566 last_login = LocalStorage.getItem('last-login-' + config.application); 2567 if (Login.getUsers().length && last_login && Login.getUser(last_login.email)) { 2568 Login.setData('chosen_account', Login.getUser(last_login.email)); 2569 return 'sign-in-password'; 2570 } 2571 } 2572 if (!Login.getUsers().length || BaseModel.instance('WebClient').getData('restrictions').getValue('disable_autofill')) { 2573 return 'sign-in'; 2574 } 2575}; 2576SitesLogin['restriction_forgot-password'] = function () { 2577 if (!BaseModel.instance('WebClient').getData('reset_settings').getValue('enabled') || !BaseModel.instance('Login').getData('chosen_account').email) { 2578 return BaseModel.instance('Login').getDefaultCard(); 2579 } 2580}; 2581SitesLogin['restriction_change-password'] = function () { 2582 if (BaseModel.instance('WebClient').getData('restrictions').getValue('disable_changepass')) { 2583 return BaseModel.instance('Login').getDefaultCard(); 2584 } 2585}; 2586SitesLogin['restriction_contact-admin'] = function () { 2587 if (!BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support')) { 2588 return BaseModel.instance('Login').getDefaultCard(); 2589 } 2590}; 2591SitesLogin['restriction_create-account'] = function () { 2592 var WebClient = BaseModel.instance('WebClient'); 2593 if (WebClient.getData('restrictions').getValue('disable_signup') || WebClient.getData('restrictions').getValue('disable_signup_ip')) { 2594 return BaseModel.instance('Login').getDefaultCard(); 2595 } 2596}; 2597SitesLogin['restriction_personal'] = function () { 2598 var WebClient = BaseModel.instance('WebClient'); 2599 var Login = BaseModel.instance('Login'); 2600 if (WebClient.getData('restrictions').getValue('disable_signup') || WebClient.getData('restrictions').getValue('disable_signup_ip')) { 2601 return Login.getDefaultCard(); 2602 } 2603 if (!Login.getData('create_account').username || !WebClient.getData('custom_login_fields').enabledCustomFields().length) { 2604 return 'create-account'; 2605 } 2606}; 2607SitesLogin['restriction_join'] = function () { 2608 if (!(window.sessionData || {}).domain) {
2609 Hash.change('', { reason: 'signup_invalid_invite_session' }, true, true); 2610 return BaseModel.instance('Login').getDefaultCard(); 2611 } 2612}; 2613SitesLogin['restriction_join-username'] = function () { 2614 var Login = BaseModel.instance('Login'); 2615 if (!(window.sessionData || {}).domain) { 2616 Hash.change('', { reason: 'signup_invalid_invite_session' }, true, true); 2617 return BaseModel.instance('Login').getDefaultCard(); 2618 } 2619 if (!Login.getData('create_account').username) { 2620 return 'join'; 2621 } 2622}; 2623SitesLogin['restriction_join-password'] = function () { 2624 var Login = BaseModel.instance('Login'); 2625 if (!(window.sessionData || {}).domain) { 2626 Hash.change('', { reason: 'signup_invalid_invite_session' }, true, true); 2627 return BaseModel.instance('Login').getDefaultCard(); 2628 } 2629 if (!Login.getData('chosen_account').email) { 2630 return 'join'; 2631 } 2632 if (!Login.getData('create_account').username) { 2633 return 'join'; 2634 } 2635}; 2636SitesLogin['restriction_verification'] = SitesLogin['restriction_personal']; 2637SitesLogin['restriction_guest-verify'] = function () { 2638 if (!Hash.getParts().email || !Hash.getParts().hash) { 2639 return BaseModel.instance('Login').getDefaultCard(); 2640 } 2641}; 2642SitesLogin['restriction_confirm-personality'] = function () { 2643 if (!Hash.getParts().email || !Hash.getParts().user || !Hash.getParts().hash) { 2644 return BaseModel.instance('Login').getDefaultCard(); 2645 } 2646}; 2647SitesLogin['restriction_unavailable'] = function () { 2648 if (BaseModel.instance('WebClient').getData('settings_loaded') && Hash.getParts().error) { 2649 return BaseModel.instance('Login').getDefaultCard(); 2650 } 2651 return 'unavailable'; 2652}; 2653SitesLogin['restriction_tc-*'] = function () { 2654 if (!Hash.getParts().email || !Hash.getParts().sender || !Hash.getParts().hash || !Hash.getParts().room) { 2655 return BaseModel.instance('Login').getDefaultCard(); 2656 } 2657}; 2658SitesLogin['restriction_tc-action'] = SitesLogin['restriction_tc-*']; 2659SitesLogin['restriction_tc-check-emal'] = SitesLogin['restriction_tc-*']; 2660SitesLogin['restriction_tc-collaboration'] = SitesLogin['restriction_tc-*']; 2661SitesLogin['restriction_tc-join'] = SitesLogin['restriction_tc-*']; 2662SitesLogin['restriction_tc-share'] = SitesLogin['restriction_tc-*']; 2663 2664SitesLogin['restriction_oauth-grant'] = function() { 2665 var OAuth, wa_sid_cookie; 2666 if (!Hash.getParts().auth_id) { 2667 return BaseModel.instance('Login').getDefaultCard(); 2668 } 2669 OAuth = BaseModel.instance('OAuth'); 2670 wa_sid_cookie = getCookie('waid'); 2671 if (!wa_sid_cookie){ 2672 return BaseModel.instance('Login').getDefaultCard(); 2673 } 2674 OAuth.createAuthConnection(wa_sid_cookie); 2675}; 2676 2677SitesLogin.restricted = async function (subpage) { 2678 var restriction; 2679 var _subpage = subpage; 2680 var Login = BaseModel.instance('Login'); 2681 var email = (Login.getData('chosen_account') || {}).email || ''; 2682 var domain = ~email.indexOf('@') ? email.split('@').pop() : false; 2683 subpage = SitesLogin.cards_order[subpage] !== void 0 ? subpage : BaseModel.instance('Login').getDefaultCard(); 2684 2685 if (!this['restriction_' + subpage]) { 2686 return subpage; 2687 } 2688 2689 if (email && _subpage !== 'sign-in-password' && subpage === 'sign-in-password') { 2690 return new Promise((resolve) => { 2691 Login.isGuestDomain(domain, { 2692 success: async function(isGuestDomain) { 2693 var subpage = isGuestDomain ? 'choose-account' : 'sign-in-password'; 2694 restriction = await this['restriction_' + subpage]() || subpage; 2695 if (restriction !== subpage) { 2696 Hash.change(restriction, false, false, true); 2697 } 2698 resolve(restriction); 2699 }, 2700 context: this 2701 }); 2702 }); 2703 } 2704 2705 restriction = await this['restriction_' + subpage]() || subpage; 2706 if (restriction !== subpage) { 2707 Hash.change(restriction, false, false, true); 2708 } 2709 return restriction; 2710}; 2711 2712SitesLogin.prototype.recompileAd = function () { 2713 this.getChildren('atoms-ad')[0] && this.getChildren('atoms-ad')[0].rerender({ 2714 position: ~[Breakpoint.md, Breakpoint.lg, Breakpoint.xl].indexOf(Breakpoint.getCurrent()) ? 'desktop' : 'mobile' 2715 }); 2716}; 2717 2718SitesLogin.prototype.onHashChange = async function (site, parts, previous_site) { 2719 var card = await SitesLogin.restricted(site); 2720 var prev_subpage = previous_site || BaseModel.instance('Login').getDefaultCard(); 2721 prev_subpage !== card && this.getInstanceByElement('form').changeCard({card: card, prepend: SitesLogin.cards_order[card] < SitesLogin.cards_order[prev_subpage], change_hash: false}); 2722 return true; 2723}; 2724 2725SitesLogin.prototype.helper = function () { 2726 return new Promise(async function (resolve) { 2727 var backgroundImage, img, themeColor, hsl, hex, rgb, greyColor, lightGreyColor; 2728 var layoutSettings = BaseModel.instance('WebClient').getData('layout_settings'); 2729 if (layoutSettings.getValue('login_background_solid') && layoutSettings.getValue('login_background_solid') !== 'false') { 2730 2731 hex = layoutSettings.getValue('login_interface_color') === 'background' ? layoutSettings.getValue('login_background_color') : layoutSettings.getValue('login_interface_color'); 2732 rgb = hexToRgb(hex); 2733 hsl = rgbToHsl(rgb.r, rgb.g, rgb.b); 2734 themeColor = 'hsl(' + hsl[0] + ', ' + hsl[1] + ', 45%)'; 2735 greyColor = 'hsl(' + hsl[0] + ', 6%, 69%)'; 2736 lightGreyColor = 'hsl(' + hsl[0] + ', 11%, 82%)'; 2737 2738 this.style = this.style || document.createElement('style'); 2739 this.style.textContent = '\ 2740 :root {\ 2741 --theme-color: ' + themeColor + ';\ 2742 --default-color: ' + themeColor + ';\ 2743 --deep-purple-color: ' + themeColor + ';\ 2744 --default-grey-color: ' + greyColor + ';\ 2745 --default-light-grey-color: ' + lightGreyColor + ';\ 2746 }\ 2747 '; 2748 document.head.appendChild(this.style); 2749 2750 resolve({ 2751 card: BaseController.new('templates-card~' + await SitesLogin.restricted(this.data.site || Hash.getSite()), this.data.data), 2752 bar: BaseController.new('organisms-bar~footer', { 2753 class_name: ['footer'] 2754 }), 2755 theme: 'default', 2756 'background-color': layoutSettings.getValue('login_background_color'), 2757 ie: Browser.isIE() || Browser.isEdge(), 2758 ad: BaseController.new('atoms-ad', { 2759 position: ~[Breakpoint.md, Breakpoint.lg, Breakpoint.xl].indexOf(Breakpoint.getCurrent()) ? 'desktop' : 'mobile' 2760 }) 2761 }); 2762 } else if (layoutSettings.getValue('login_interface_color') === 'background') {
2763 backgroundImage = BaseModel.instance('Server').getBackground(1280, 720); 2764 img = new Image(); 2765 img.addEventListener('load', function() { 2766 extractColors.extractColorsFromImage(img).then(async function(swatches) { 2767 var i, hsl, themeColor, greyColor, lightGreyColor; 2768 var mostPopulous = swatches[0]; 2769 for (i in swatches) { 2770 if (swatches[i].area * swatches[i].intensity * swatches[i].saturation * swatches[i].lightness > mostPopulous.area * mostPopulous.intensity * mostPopulous.saturation * mostPopulous.lightness) { 2771 mostPopulous = swatches[i]; 2772 } 2773 } 2774 2775 hsl = rgbToHsl(mostPopulous.red, mostPopulous.green, mostPopulous.blue); 2776 themeColor = 'hsl(' + hsl[0] + ', ' + hsl[1] + ', 45%)'; 2777 greyColor = 'hsl(' + hsl[0] + ', 6%, 69%)'; 2778 lightGreyColor = 'hsl(' + hsl[0] + ', 11%, 82%)'; 2779 2780 this.style = this.style || document.createElement('style'); 2781 this.style.textContent = '\ 2782 :root {\ 2783 --theme-color: ' + themeColor + ';\ 2784 --default-color: ' + themeColor + ';\ 2785 --deep-purple-color: ' + themeColor + ';\ 2786 --default-grey-color: ' + greyColor + ';\ 2787 --default-light-grey-color: ' + lightGreyColor + ';\ 2788 }\ 2789 '; 2790 document.head.appendChild(this.style); 2791 2792 resolve({ 2793 card: BaseController.new('templates-card~' + await SitesLogin.restricted(this.data.site || Hash.getSite()), this.data.data), 2794 bar: BaseController.new('organisms-bar~footer', { 2795 class_name: ['footer'] 2796 }), 2797 theme: 'default', 2798 'background-image': backgroundImage, 2799 'background-color': ~['cover', 'tile'].indexOf(layoutSettings.getValue('login_background_wallpaper_size')) ? themeColor : layoutSettings.getValue('login_background_color'), 2800 'background-size': layoutSettings.getValue('login_background_wallpaper_size'), 2801 ie: Browser.isIE() || Browser.isEdge(), 2802 ad: BaseController.new('atoms-ad', { 2803 position: ~[Breakpoint.md, Breakpoint.lg, Breakpoint.xl].indexOf(Breakpoint.getCurrent()) ? 'desktop' : 'mobile' 2804 }) 2805 }); 2806 }.bind(this)).catch(async function() { 2807 resolve({ 2808 card: BaseController.new('templates-card~' + await SitesLogin.restricted(this.data.site || Hash.getSite()), this.data.data), 2809 bar: BaseController.new('organisms-bar~footer', { 2810 class_name: ['footer'] 2811 }), 2812 theme: layoutSettings.getValue('login_color'), 2813 'background-image': backgroundImage, 2814 'background-color': ~['cover', 'tile'].indexOf(layoutSettings.getValue('login_background_wallpaper_size')) ? themeColor : layoutSettings.getValue('login_background_color'), 2815 'background-size': layoutSettings.getValue('login_background_wallpaper_size'), 2816 ie: Browser.isIE() || Browser.isEdge(), 2817 ad: BaseController.new('atoms-ad', { 2818 position: ~[Breakpoint.md, Breakpoint.lg, Breakpoint.xl].indexOf(Breakpoint.getCurrent()) ? 'desktop' : 'mobile' 2819 }) 2820 }); 2821 }.bind(this)); 2822 }.bind(this)); 2823 2824 img.addEventListener('error', async function() { 2825 resolve({ 2826 card: BaseController.new('templates-card~' + await SitesLogin.restricted(this.data.site || Hash.getSite()), this.data.data), 2827 bar: BaseController.new('organisms-bar~footer', { 2828 class_name: ['footer'] 2829 }), 2830 theme: layoutSettings.getValue('login_color'), 2831 'background-image': backgroundImage, 2832 'background-color': ~['cover', 'tile'].indexOf(layoutSettings.getValue('login_background_wallpaper_size')) ? themeColor : layoutSettings.getValue('login_background_color'), 2833 'background-size': layoutSettings.getValue('login_background_wallpaper_size'), 2834 ie: Browser.isIE() || Browser.isEdge(), 2835 ad: BaseController.new('atoms-ad', { 2836 position: ~[Breakpoint.md, Breakpoint.lg, Breakpoint.xl].indexOf(Breakpoint.getCurrent()) ? 'desktop' : 'mobile' 2837 }) 2838 }); 2839 }.bind(this)); 2840 img.src = backgroundImage; 2841 } else { 2842 backgroundImage = BaseModel.instance('Server').getBackground(1280, 720); 2843 hex = layoutSettings.getValue('login_interface_color'); 2844 rgb = hexToRgb(hex); 2845 hsl = rgbToHsl(rgb.r, rgb.g, rgb.b); 2846 themeColor = 'hsl(' + hsl[0] + ', ' + hsl[1] + ', 45%)'; 2847 greyColor = 'hsl(' + hsl[0] + ', 6%, 69%)'; 2848 lightGreyColor = 'hsl(' + hsl[0] + ', 11%, 82%)'; 2849 2850 this.style = this.style || document.createElement('style'); 2851 this.style.textContent = '\ 2852 :root {\ 2853 --theme-color: ' + themeColor + ';\ 2854 --default-color: ' + themeColor + ';\ 2855 --deep-purple-color: ' + themeColor + ';\ 2856 --default-grey-color: ' + greyColor + ';\ 2857 --default-light-grey-color: ' + lightGreyColor + ';\ 2858 }\ 2859 '; 2860 document.head.appendChild(this.style); 2861 2862 resolve({ 2863 card: BaseController.new('templates-card~' + await SitesLogin.restricted(this.data.site || Hash.getSite()), this.data.data), 2864 bar: BaseController.new('organisms-bar~footer', { 2865 class_name: ['footer'] 2866 }), 2867 theme: 'default', 2868 'background-color': ~['cover', 'tile'].indexOf(layoutSettings.getValue('login_background_wallpaper_size')) ? themeColor : layoutSettings.getValue('login_background_color'), 2869 'background-image': backgroundImage, 2870 'background-size': layoutSettings.getValue('login_background_wallpaper_size'), 2871 ie: Browser.isIE() || Browser.isEdge(), 2872 ad: BaseController.new('atoms-ad', { 2873 position: ~[Breakpoint.md, Breakpoint.lg, Breakpoint.xl].indexOf(Breakpoint.getCurrent()) ? 'desktop' : 'mobile' 2874 }) 2875 }); 2876 } 2877 }.bind(this)); 2878}; 2879 2880module.exports = SitesLogin; 2881 2882},{"../generic":97,"@icewarp/hash":160,"@icewarp/localstorage":167,"@icewarp/utils":180,"BaseController":"BaseController","BaseModel":"BaseModel","Breakpoint":"Breakpoint","extract-colors":360,"rgb-to-hsl":366}],99:[function(require,module,exports){ 2883"use strict"; 2884var BaseModel = require('BaseModel'); 2885var BaseController = require('BaseController'); 2886var Form = require('../../form'); 2887var TemplatesCard = BaseController.create('TemplatesCard', Form); 2888var Validatable = require('../../validatable'); 2889var animationEnd = require('@icewarp/utils').animations.browserEvent('animationend'); 2890var Hash = require('@icewarp/hash'); 2891var delayed = require('delayed'); 2892var MobileDetect = require('mobile-detect'); 2893 2894TemplatesCard.prototype.addListeners = function () { 2895 this.addDelegatedHookListener('sign-with-another-acc', 'click', this.changeCard, {card: 'sign-in', hashData: Hash.getParts()}); 2896 this.addDelegatedHookListener('contact-admin', 'click', this.changeCard, {card: 'contact-admin', hashData: Hash.getParts()}); 2897 this.addDelegatedHookListener('sign-in', 'click', this.changeCard, {hashData: Hash.getParts()}); 2898 this.addDelegatedHookListener('choose-account', 'click', this.changeCard, {card: 'choose-account', hashData: Hash.getParts()}); 2899 this.addDelegatedHookListener('create-acc', 'click', this.changeCard, {card: 'create-account'}); 2900 this.addDelegatedHookListener('back-to-email', 'click', this.backToEmail); 2901 this.addDelegatedHookListener('back', 'click', this.back); 2902 this.addDelegatedHookListener('language', 'click', this.chooseLanguage); 2903 this.addDOMListener('', 'submit', this.submitForm); 2904 2905 this.addGlobalListener('error-message-hide', this.hideMessage); 2906 this.addGlobalListener('error-message-show', this.showMessage); 2907}; 2908 2909TemplatesCard.prototype.onCreate = function () { 2910 Form.prototype.onCreate.call(this); 2911 this.submitted = false; 2912}; 2913
2914TemplatesCard.prototype.afterRender = function () { 2915 var md = new MobileDetect(window.navigator.userAgent); 2916 var parts = Hash.getParts(); 2917 var error = parts.eid || parts.reason; 2918 document.body.scrollTop = document.documentElement.scrollTop = 0; 2919 error && this.showMessage({ 2920 title: __('generic.error'), 2921 text: __('error.' + error, {}, __('error.unspecified', {error: error, md: true})), 2922 type: 'error', 2923 pinned: true 2924 }); 2925 2926 parts.notifyuri && parts.eid && BaseModel.instance('Login').callCommunication('teamchatError', parts); 2927 2928 if (!md.mobile() && !md.tablet()) { 2929 setTimeout(function() { 2930 this.setCaret(); 2931 }.bind(this), 100); 2932 } 2933}; 2934 2935TemplatesCard.prototype.setCaret = function () { 2936 this.selectAll('input, textarea').some(function (elem) { 2937 if (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length) { 2938 elem.focus(); 2939 setTimeout(function() { 2940 var range; 2941 try { 2942 if (typeof elem.selectionStart === 'number') { 2943 elem.selectionStart = elem.selectionEnd = elem.value.length; 2944 } else if (typeof elem.createTextRange !== 'undefined') { 2945 elem.focus(); 2946 range = elem.createTextRange(); 2947 range.collapse(false); 2948 range.select(); 2949 } 2950 } catch (e) { 2951 // ignore 2952 } 2953 }, 0); 2954 return true; 2955 } 2956 }); 2957}; 2958 2959TemplatesCard.prototype.beforeDestroy = function () { 2960 this.autohide_timeout && clearTimeout(this.autohide_timeout); 2961}; 2962 2963TemplatesCard.prototype.chooseLanguage = function (event) { 2964 var rect = event.element.getBoundingClientRect(); 2965 event.stopPropagation(); 2966 this.choose_language = this.choose_language || BaseController.new('molecules-language-picker'); 2967 if (this.choose_language.DOMElement) { 2968 return this.removeChooseLanguage(); 2969 } 2970 this.choose_language.invoker = this; 2971 this.choose_language.execute().then(function(controller) { 2972 controller.render(this.getParent('sites').DOMElement, 'beforeend'); 2973 controller.DOMElement.style.top = rect.bottom + 'px'; 2974 if ((rect.left + rect.right - controller.DOMElement.clientWidth) / 2 + controller.DOMElement.clientWidth <= document.body.clientWidth) { 2975 controller.DOMElement.style.left = (rect.left + rect.right - controller.DOMElement.clientWidth) / 2 + 'px'; 2976 } else { 2977 controller.DOMElement.style.right = 0; 2978 } 2979 event.element.classList.add('is-open'); 2980 }.bind(this)); 2981}; 2982 2983TemplatesCard.prototype.removeChooseLanguage = function () { 2984 if (animationEnd) { 2985 // this.choose_language.DOMElement.classList.add('is-previous'); 2986 // this.choose_language.addDOMListener(this.choose_language.DOMElement, animationEnd, function () { 2987 this.DOMElement && this.hook('language').classList.remove('is-open'); 2988 this.choose_language.remove(); 2989 this.choose_language = null; 2990 // }.bind(this), {}, true); 2991 // this.choose_language.DOMElement.classList.add('on-destroy'); 2992 } else { 2993 this.hook('language').classList.remove('is-open'); 2994 this.choose_language.remove(); 2995 this.choose_language = null; 2996 } 2997}; 2998 2999TemplatesCard.prototype.back = function () { 3000 history.back(); 3001}; 3002 3003TemplatesCard.prototype.backToEmail = function () { 3004 this.changeCard({card: this.data.prev || 'sign-in'}); 3005}; 3006 3007TemplatesCard.prototype.submitForm = function (event) { 3008 event.preventDefault(); 3009 event.stopPropagation(); 3010 event.stopImmediatePropagation(); 3011 if (this.submitted) { 3012 return; 3013 } 3014 this.validateForm && this.disable() && this.validateForm(); 3015}; 3016 3017TemplatesCard.prototype.hasError = function () { 3018 this.enable(); 3019 if (animationEnd) { 3020 this.addDOMListener(this.DOMElement, animationEnd, function () { 3021 this.DOMElement.classList.remove('a-error'); 3022 }.bind(this), {}, true); 3023 this.DOMElement.classList.add('a-error'); 3024 } 3025}; 3026 3027TemplatesCard.prototype.genericError = function (error, type, title) { 3028 var captchas = this.getChildren('molecules-captcha'); 3029 var validatable; 3030 3031 this.hasError(); 3032 if (captchas.length) { 3033 captchas[0].rerender(); 3034 this.hook('captcha').value = ''; 3035 this.hook('captcha').focus(); 3036 } 3037 error && this.showMessage({ 3038 title: title || __('generic.error'), 3039 text: __('error.' + error, {}, __('error.unspecified', {error: error, md: true})), 3040 type: type || 'error' 3041 }); 3042 3043 if (!this.DOMElement.querySelector(':focus')) { 3044 validatable = this.getChildrenByClass(Validatable)[0]; 3045 if (validatable && validatable.focus) { 3046 validatable.focus(); 3047 } 3048 } 3049}; 3050 3051TemplatesCard.prototype.changeCardCallback = function (data) { 3052 if (!this.DOMElement) { 3053 return; 3054 } 3055 BaseController.new('templates-card~' + data.card).execute(data.data || {}).then(function(controller) { 3056 if (!this.DOMElement) { 3057 return; 3058 } 3059 controller.render(this.DOMElement.parentElement, 'beforeend'); 3060 controller.DOMElement.classList.remove(data.prepend ? 'is-previous' : 'is-next'); 3061 this.remove(); 3062 }.bind(this)); 3063}; 3064 3065TemplatesCard.prototype.changeCard = function (event, data) { 3066 if (!this.DOMElement) { 3067 return; 3068 } 3069 data = (arguments.length === 1 ? event : data) || {}; 3070 data.card = data.card || BaseModel.instance('Login').getDefaultCard(); 3071 3072 (data.change_hash === void 0 ? true : data.change_hash) && Hash.change(data.card, data.hashData || {}, true, data.keepHashData); 3073 3074 if (animationEnd) { 3075 this.changeCardCallback(data); 3076 this.DOMElement.classList.add('on-destroy'); 3077 } else { 3078 this.changeCardCallback(data); 3079 } 3080}; 3081 3082TemplatesCard.prototype.hideMessage = function () { 3083 var well = this.getInstanceByElement(this.hook('well')); 3084 if (well.data.pinned) { 3085 return; 3086 } 3087 if (animationEnd) { 3088 well.addDOMListener(well.DOMElement, animationEnd, function () { 3089 well.DOMElement.classList.remove('on-destroy'); 3090 well.DOMElement.classList.remove('is-visible'); 3091 }, {}, true); 3092 well.DOMElement.classList.add('on-destroy'); 3093 } else { 3094 well.DOMElement.classList.remove('is-visible'); 3095 } 3096}; 3097 3098TemplatesCard.prototype.showMessage = function (data) { 3099 var well = this.getInstanceByElement(this.hook('well')); 3100 well.data.title = data.title; 3101 well.data.text = data.text; 3102 well.data.type = data.type; 3103 well.data.pinned = data.pinned; 3104 well.data.class_name = well.data.class_name || []; 3105 well.data.class_name.push('is-visible'); 3106 3107 well.rerender(); 3108 this.autohide_timeout && clearTimeout(this.autohide_timeout);
3109 data.autohide && (this.autohide_timeout = delayed(this.hideMessage, this, data.autohide, this._name + this.id)); 3110}; 3111 3112TemplatesCard.prototype.helper = function (helper_data) { 3113 var WebClient = BaseModel.instance('WebClient'); 3114 var codes = BaseModel.static('language').codes; 3115 var code = WebClient.getData('layout_settings').getUserLanguage().getValue('code'); 3116 var i; 3117 for (i in codes) { 3118 if (codes[i] === code) { 3119 code = i; 3120 break; 3121 } 3122 } 3123 return Object.assign({ 3124 component: [ 3125 (!WebClient.getData('restrictions').getValue('disable_languages') && WebClient.getData('languages').length > 1) && BaseController.new('atoms-dropdown', { 3126 class_name: ['o-card__lang'], 3127 hook: this.createHook('language'), 3128 code: code, 3129 icon: false && BaseController.new('atoms-icons', { 3130 icon: 'planet', 3131 class_name: ['o-dropdown__icon'] 3132 }) 3133 }), 3134 this.data.back && history.length > 2 && BaseController.new('atoms-link~back', { 3135 class_name: ['o-card__back'] 3136 }) 3137 ].filter(Boolean) 3138 }, helper_data); 3139}; 3140 3141module.exports = TemplatesCard; 3142 3143},{"../../form":78,"../../validatable":127,"@icewarp/hash":160,"@icewarp/utils":180,"BaseController":"BaseController","BaseModel":"BaseModel","delayed":"delayed","mobile-detect":364}],100:[function(require,module,exports){ 3144"use strict"; 3145var BaseModel = require('BaseModel'); 3146var BaseController = require('BaseController'); 3147var TemplatesCard = require('./card.js'); 3148var TemplatesCard_ChangePassword = BaseController.create('TemplatesCard_ChangePassword', TemplatesCard); 3149 3150TemplatesCard_ChangePassword.prototype.addListeners = function () { 3151 TemplatesCard.prototype.addListeners.call(this); 3152 this.addHookListener('change-password', 'click', this.submitForm); 3153}; 3154 3155TemplatesCard_ChangePassword.prototype.validateForm = function () { 3156 this.validate(function (isValid) { 3157 if (isValid) { 3158 BaseModel.instance('Login').getAuthChallenge({ 3159 success: this.changePassword, 3160 error: function (error) { 3161 this.genericError(error); 3162 }, 3163 context: this 3164 }); 3165 } 3166 }.bind(this)); 3167}; 3168 3169TemplatesCard_ChangePassword.prototype.changePassword = function (encrypt) { 3170 BaseModel.instance('WebClient').changePassword({ 3171 email: this.hook('username').value, 3172 oldpassword: encrypt(this.hook('current-password').value), 3173 newpassword: encrypt(this.hook('password').value) 3174 }, { 3175 success: function () { 3176 this.changeCard({ 3177 data: { 3178 well: { 3179 title: __('generic.success'), 3180 text: __('change-password.success-message'), 3181 type: 'success', 3182 class_name: ['is-visible'] 3183 } 3184 } 3185 }); 3186 }, 3187 error: function (error) { 3188 this.genericError(error); 3189 }, 3190 context: this 3191 }); 3192}; 3193 3194TemplatesCard_ChangePassword.prototype.helper = function () { 3195 return TemplatesCard.prototype.helper.call(this, { 3196 hook: this.createHook('form'), 3197 content: [ 3198 { 3199 mod: [], 3200 component: BaseController.new('organisms-card-header', { 3201 heading: __('change-password.heading'), 3202 subtitle: '', 3203 well: this.data.well 3204 }) 3205 }, 3206 { 3207 mod: ['form'], 3208 component: BaseController.new('molecules-input~validatable', { 3209 input: { 3210 type: 'text', 3211 name: 'username', 3212 hook: this.createHook('username') 3213 }, 3214 label: { 3215 text: BaseModel.instance('Server').getData('c_accounts_policies_login_loginsettings') ? __('generic.email') : __('generic.username') 3216 }, 3217 rules: [ 3218 { 3219 name: 'empty', 3220 message: __('validation.empty') 3221 } 3222 ] 3223 }) 3224 }, 3225 { 3226 mod: ['form'], 3227 component: BaseController.new('molecules-input~password', { 3228 input: { 3229 hook: this.createHook('current-password'), 3230 name: 'current-password', 3231 autocomplete: 'current-password' 3232 }, 3233 label: { 3234 text: __('generic.password-current') 3235 }, 3236 addon: BaseController.new('atoms-addon~show'), 3237 rules: [ 3238 { 3239 name: 'empty', 3240 message: __('validation.empty') 3241 } 3242 ] 3243 }) 3244 }, 3245 { 3246 mod: ['form'], 3247 component: BaseController.new('molecules-input~password-with-policy', { 3248 input: { 3249 hook: this.createHook('password'), 3250 name: 'new-password', 3251 autocomplete: 'new-password' 3252 }, 3253 label: { 3254 text: __('generic.password-new') 3255 }, 3256 addon: BaseController.new('atoms-addon~show') 3257 }) 3258 }, 3259 { 3260 mod: ['form'], 3261 component: BaseController.new('molecules-input~password', { 3262 input: { 3263 name: 'confirm-password', 3264 autocomplete: 'new-password' 3265 }, 3266 label: { 3267 text: __('generic.password-confirm') 3268 }, 3269 addon: BaseController.new('atoms-addon~show'), 3270 rules: [ 3271 { 3272 name: 'empty', 3273 message: __('validation.empty') 3274 }, 3275 { 3276 name: 'same', 3277 controller: this, 3278 parent_hook: 'form', 3279 counterpart_hook: 'password', 3280 message: __('validation.passwords-no-match') 3281 } 3282 ] 3283 }) 3284 }, 3285 { 3286 mod: ['default', 'space-top'], 3287 component: BaseController.new('molecules-button', { 3288 mod: ['block', 'primary'], 3289 button: { 3290 text: __('generic.save-password'), 3291 hook: this.createHook('change-password'), 3292 name: 'change-password' 3293 } 3294 }) 3295 }, 3296 { 3297 mod: ['footer'], 3298 component: [ 3299 BaseController.new('atoms-info~have-account'), 3300 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin')
3301 ].filter(Boolean) 3302 } 3303 ].filter(Boolean) 3304 }); 3305}; 3306 3307module.exports = TemplatesCard_ChangePassword; 3308 3309},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],101:[function(require,module,exports){ 3310"use strict"; 3311var BaseModel = require('BaseModel'); 3312var BaseController = require('BaseController'); 3313var TemplatesCard = require('./card.js'); 3314var Hash = require('@icewarp/hash'); 3315var TemplatesCard_ChooseAccount = BaseController.create('TemplatesCard_ChooseAccount', TemplatesCard); 3316 3317TemplatesCard_ChooseAccount.prototype.addListeners = function () { 3318 TemplatesCard.prototype.addListeners.call(this); 3319 this.addHookListener('remove-from-list', 'click', this.removeFromListInit); 3320 this.addHookListener('remove-from-list-done', 'click', this.removeFromListDone); 3321 this.addHookListener('switch', 'click', this.chooseAccount); 3322 this.addHookListener('switch', 'keypress', this.chooseAccountEnter); 3323 this.addDelegatedDOMListener('.is-removed', 'click', this.removeFromListUndo); 3324 this.addDelegatedDOMListener('.is-removable', 'click', this.removeFromListRemove); 3325}; 3326 3327TemplatesCard_ChooseAccount.prototype.chooseAccountEnter = function (event, data) { 3328 ((event.which || event.keyCode) === 13) && this.chooseAccount(event, data); 3329}; 3330 3331TemplatesCard_ChooseAccount.prototype.chooseAccount = function (event) { 3332 var Login = BaseModel.instance('Login'); 3333 var email = this.getInstanceByElement(event.element).data.email; 3334 var user = Login.getUser(email); 3335 var config = BaseModel.instance('Config').getData('config'); 3336 3337 event.preventDefault(); 3338 if (event.element.classList.contains('is-removable') || event.element.classList.contains('is-removed')) { 3339 return; 3340 } 3341 3342 if (user.guestLogin) { 3343 if (config.application === 'webclient') { 3344 BaseModel.instance('Login').guestLogin({ 3345 email: email 3346 }); 3347 } else { 3348 this.genericError('invalid_account_app'); 3349 } 3350 return; 3351 } 3352 3353 Login.setData('chosen_account', user); 3354 this.changeCard({ 3355 card: 'sign-in-password', 3356 hashData: Hash.getParts(), 3357 data: { 3358 back: true, 3359 prev: 'choose-account' 3360 } 3361 }); 3362}; 3363 3364TemplatesCard_ChooseAccount.prototype.removeFromListInit = function () { 3365 var heading = this.hook('heading'); 3366 this.hook('remove-from-list-section').classList.add('u-hide'); 3367 this.hook('remove-from-list-done-section').classList.add('on-load'); 3368 this.hook('remove-from-list-done-section').classList.remove('u-hide'); 3369 while (heading.firstChild) { 3370 heading.removeChild(heading.firstChild); 3371 } 3372 heading.insertAdjacentHTML('afterbegin', __('choose-account.remove')); 3373 this.hooks('switch').forEach(function (user) { 3374 user.classList.add('is-removable'); 3375 }); 3376}; 3377 3378TemplatesCard_ChooseAccount.prototype.removeFromListRemove = function (event) { 3379 event.stopPropagation(); 3380 event.stopImmediatePropagation(); 3381 this.closestHook('switch', event.target).classList.add('is-removed'); 3382 this.closestHook('switch', event.target).classList.remove('is-removable'); 3383 this.hook('remove-from-list-done').textContent = this.selectAll('[data-hook="switch"].is-removed').length ? __('choose-account.remove-selected') : __('generic.cancel'); 3384}; 3385 3386TemplatesCard_ChooseAccount.prototype.removeFromListUndo = function (event) { 3387 event.stopPropagation(); 3388 event.stopImmediatePropagation(); 3389 this.closestHook('switch', event.target).classList.add('is-removable'); 3390 this.closestHook('switch', event.target).classList.remove('is-removed'); 3391 this.hook('remove-from-list-done').textContent = this.selectAll('[data-hook="switch"].is-removed').length ? __('choose-account.remove-selected') : __('generic.cancel'); 3392}; 3393 3394TemplatesCard_ChooseAccount.prototype.removeFromListDone = function (event) { 3395 var heading = this.hook('heading'); 3396 event.preventDefault(); 3397 this.hook('remove-from-list-section').classList.add('on-load'); 3398 this.hook('remove-from-list-section').classList.remove('u-hide'); 3399 while (heading.firstChild) { 3400 heading.removeChild(heading.firstChild); 3401 } 3402 heading.insertAdjacentHTML('afterbegin', __('choose-account.heading')); 3403 this.hook('remove-from-list-done-section').classList.add('u-hide'); 3404 this.selectAll('[data-hook="switch"].is-removed').forEach(function (user) { 3405 var user_controller = this.getInstanceByElement(user); 3406 BaseModel.instance('Login').removeUser({email: user_controller.data.email}); 3407 user_controller.remove(); 3408 }, this); 3409 this.selectAll('[data-hook="switch"].is-removable').forEach(function (user) { 3410 user.classList.remove('is-removable'); 3411 }); 3412 if (!BaseModel.instance('Login').getUsers().length) { 3413 this.changeCard({card: 'sign-in'}); 3414 } 3415}; 3416 3417TemplatesCard_ChooseAccount.prototype.helper = function () { 3418 var WebClient = BaseModel.instance('WebClient'); 3419 3420 this.data.back = true; 3421 3422 return TemplatesCard.prototype.helper.call(this, { 3423 hook: this.createHook('form'), 3424 content: [ 3425 { 3426 mod: [], 3427 component: BaseController.new('organisms-card-header', { 3428 heading: __('choose-account.heading'), 3429 hook: this.createHook('heading'), 3430 avatar: false, 3431 subtitle: false, 3432 subsubtitle: false, 3433 well: this.data.well 3434 }) 3435 }, 3436 { 3437 mod: ['form'], 3438 component: BaseModel.instance('Login').getUsers().map(function (user) { 3439 return BaseController.new('atoms-switch', user); 3440 }) 3441 }, 3442 { 3443 mod: ['form'], 3444 hook: this.createHook('remove-from-list-section'), 3445 component: BaseController.new('atoms-link~remove-from-list') 3446 }, 3447 { 3448 mod: ['form'], 3449 class_name: ['u-hide'], 3450 hook: this.createHook('remove-from-list-done-section'), 3451 component: BaseController.new('molecules-button', { 3452 mod: ['block', 'primary', 'small'], 3453 button: { 3454 hook: this.createHook('remove-from-list-done'), 3455 text: __('generic.cancel'), 3456 name: 'done' 3457 } 3458 }) 3459 }, 3460 WebClient.getData('restrictions').getValue('show_search') && { 3461 mod: ['form'], 3462 component: BaseController.new('molecules-input~search', { 3463 input: { 3464 name: 'search' 3465 }, 3466 label: { 3467 text: __('generic.search') 3468 } 3469 }) 3470 }, 3471 { 3472 mod: ['footer', 'space-top'], 3473 component: [ 3474 BaseController.new('atoms-info~sign-with-another-acc'), 3475 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin')
3476 ].filter(Boolean) 3477 } 3478 ].filter(Boolean) 3479 }); 3480}; 3481 3482module.exports = TemplatesCard_ChooseAccount; 3483 3484},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],102:[function(require,module,exports){ 3485"use strict"; 3486var BaseController = require('BaseController'); 3487var TemplatesCard_GenericMessage = require('./card~generic-message.js'); 3488var TemplatesCard_ConfirmPersonality = BaseController.create('TemplatesCard_ConfirmPersonality', TemplatesCard_GenericMessage); 3489var Hash = require('@icewarp/hash'); 3490 3491TemplatesCard_ConfirmPersonality.prototype.addListeners = function () { 3492 TemplatesCard_GenericMessage.prototype.addListeners.call(this); 3493}; 3494 3495TemplatesCard_ConfirmPersonality.prototype.afterRender = function () { 3496 TemplatesCard_GenericMessage.prototype.afterRender.call(this); 3497 3498 !this.hasResponse && this.callCommunication('confirmPersonality', { 3499 user: Hash.getParts().user, 3500 email: Hash.getParts().email, 3501 hash: Hash.getParts().hash 3502 }); 3503}; 3504 3505TemplatesCard_ConfirmPersonality.prototype.helper = function () { 3506 this.data.title = __('confirm-personality.heading'); 3507 this.data.subtitle = this.data.subtitle === void 0 ? { 3508 text: __('confirm-personality.subheading') 3509 } : this.data.subtitle; 3510 this.data.loading = this.data.loading === void 0 ? true : this.data.loading; 3511 this.data.type = this.data.type || 'none'; 3512 return TemplatesCard_GenericMessage.prototype.helper.call(this); 3513}; 3514 3515module.exports = TemplatesCard_ConfirmPersonality; 3516 3517},{"./card~generic-message.js":107,"@icewarp/hash":160,"BaseController":"BaseController"}],103:[function(require,module,exports){ 3518"use strict"; 3519var BaseModel = require('BaseModel'); 3520var BaseController = require('BaseController'); 3521var TemplatesCard = require('./card.js'); 3522var TemplatesCard_ContactAdmin = BaseController.create('TemplatesCard_ContactAdmin', TemplatesCard); 3523 3524TemplatesCard_ContactAdmin.prototype.addListeners = function () { 3525 TemplatesCard.prototype.addListeners.call(this); 3526 this.addHookListener('validate-form', 'click', this.submitForm); 3527 this.addHookListener('validate-form', 'keypress', this.textareaKeypress); 3528}; 3529 3530TemplatesCard_ContactAdmin.prototype.validateForm = function () { 3531 this.validate(function (isValid) { 3532 var data; 3533 if (isValid) { 3534 data = this.hook('describe-problem').value; 3535 if (BaseModel.instance('WebClient').getData('restrictions').getValue('support_require_number')) { 3536 data += '\n\n' + __('personal.mobile-phone') + ': ' + this.hook('tel').value; 3537 } 3538 BaseModel.instance('WebClient').contactAdministrator({ 3539 email: this.hook('email-address').value, 3540 data: data, 3541 captcha: { 3542 uid: this.getChildren('molecules-captcha')[0].uid, 3543 value: this.hook('captcha').value.toUpperCase() 3544 } 3545 }, { 3546 success: function () { 3547 this.changeCard({ 3548 card: 'generic-message', 3549 data: { 3550 type: 'success', 3551 well: { 3552 text: __('contact-admin.success-message') 3553 }, 3554 link: '' 3555 }, 3556 change_hash: false 3557 }); 3558 }, 3559 error: function (error) { 3560 this.genericError(error); 3561 }, 3562 context: this 3563 }); 3564 } 3565 }.bind(this)); 3566}; 3567 3568TemplatesCard_ContactAdmin.prototype.textareaKeypress = function (event) { 3569 (event.ctrlKey || event.metaKey) && ~[10, 13].indexOf(event.which || event.keyCode) && this.submitForm(event); 3570}; 3571 3572TemplatesCard_ContactAdmin.prototype.helper = function () { 3573 var WebClient = BaseModel.instance('WebClient'); 3574 var email = BaseModel.instance('Login').getData('chosen_account').email || ''; 3575 if (!~email.indexOf('@')) { 3576 email = ''; 3577 } 3578 3579 this.data.back = true; 3580 3581 return TemplatesCard.prototype.helper.call(this, { 3582 hook: this.createHook('form'), 3583 content: [ 3584 { 3585 mod: [], 3586 component: BaseController.new('organisms-card-header', { 3587 avatar: false, 3588 heading: __('contact-admin.heading'), 3589 subtitle: false, 3590 subsubtitle: false, 3591 well: this.data.well 3592 }) 3593 }, 3594 { 3595 mod: ['form'], 3596 component: BaseController.new('molecules-input~validatable', { 3597 input: { 3598 hook: this.createHook('email-address'), 3599 type: 'email', 3600 name: 'email-address', 3601 value: email 3602 }, 3603 label: { 3604 text: __('generic.email') 3605 }, 3606 rules: [ 3607 { 3608 name: 'empty', 3609 message: __('validation.empty') 3610 }, 3611 { 3612 name: 'email', 3613 message: __('validation.email') 3614 } 3615 ], 3616 tooltip_well: { 3617 text: [ 3618 __('contact-admin.email-helper') 3619 ], 3620 type: 'primary' 3621 } 3622 }) 3623 }, 3624 BaseModel.instance('WebClient').getData('restrictions').getValue('support_require_number') && { 3625 mod: ['form'], 3626 component: BaseController.new('molecules-input~validatable', { 3627 input: { 3628 hook: this.createHook('tel'), 3629 type: 'tel', 3630 name: 'tel' 3631 }, 3632 label: { 3633 text: __('personal.mobile-phone') 3634 }, 3635 rules: [ 3636 { 3637 name: 'empty', 3638 message: __('validation.empty') 3639 } 3640 ], 3641 tooltip_well: { 3642 text: [ 3643 __('contact-admin.tel') 3644 ], 3645 type: 'primary' 3646 } 3647 }) 3648 }, 3649 { 3650 mod: ['form'], 3651 component: BaseController.new('molecules-textarea~validatable', { 3652 textarea: { 3653 hook: this.createHook('describe-problem'), 3654 name: 'describe-problem' 3655 }, 3656 label: { 3657 text: __('contact-admin.describe-problem') 3658 }, 3659 rules: [ 3660 { 3661 name: 'empty', 3662 message: __('validation.empty') 3663 } 3664 ] 3665 }) 3666 }, 3667 { 3668 mod: ['form'], 3669 component: BaseController.new('molecules-captcha') 3670 }, 3671 { 3672 mod: ['form'], 3673 component: BaseController.new('molecules-input~validatable', { 3674 input: { 3675 hook: this.createHook('captcha'), 3676 type: 'text', 3677 name: 'security-code', 3678 maxlength: 6, 3679 minlength: 6 3680 }, 3681 label: { 3682 text: __('generic.security-code') 3683 }, 3684 rules: [ 3685 { 3686 name: 'empty', 3687 message: __('validation.empty') 3688 }, 3689 { 3690 name: 'length', 3691 data: 6, 3692 message: __('validation.length', 6) 3693 } 3694 ] 3695 }) 3696 }, 3697 { 3698 mod: ['default', 'space-top'], 3699 component: [ 3700 BaseController.new('molecules-button', { 3701 mod: ['block', 'primary'], 3702 button: { 3703 hook: this.createHook('validate-form'), 3704 text: __('contact-admin.submit'), 3705 name: 'send-message' 3706 } 3707 }) 3708 ] 3709 }, 3710 WebClient.getData('restrictions').getValue('show_search') && { 3711 mod: ['form'], 3712 component: BaseController.new('molecules-input~search', { 3713 input: { 3714 name: 'search' 3715 }, 3716 label: { 3717 text: __('generic.search') 3718 } 3719 }) 3720 }
3721 ].filter(Boolean) 3722 }); 3723}; 3724 3725module.exports = TemplatesCard_ContactAdmin; 3726 3727},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],104:[function(require,module,exports){ 3728"use strict"; 3729var punycode = require('punycode'); 3730var BaseModel = require('BaseModel'); 3731var BaseController = require('BaseController'); 3732var TemplatesCard = require('./card.js'); 3733var TemplatesCard_CreateAccount = BaseController.create('TemplatesCard_CreateAccount', TemplatesCard); 3734 3735TemplatesCard_CreateAccount.prototype.addListeners = function () { 3736 TemplatesCard.prototype.addListeners.call(this); 3737 this.addHookListener('save-credentials', 'click', this.submitForm); 3738}; 3739 3740TemplatesCard_CreateAccount.prototype.validateForm = function () { 3741 this.validate(function (isValid) { 3742 var Login = BaseModel.instance('Login'); 3743 var WebClient = BaseModel.instance('WebClient'); 3744 if (isValid) { 3745 Login.setData('chosen_account', { 3746 name: this.hook('full-name').value, 3747 email: this.hook('username').value + '@' + punycode.toUnicode(this.hook('select').value), 3748 avatar_token: false 3749 }); 3750 Login.setData('create_account', { 3751 domain: this.hook('select').value, 3752 username: this.hook('username').value, 3753 fullname: this.hook('full-name').value, 3754 alternativeemail: this.hook('alternate-email').value, 3755 card: {} 3756 }); 3757 this.changeCard({ card: WebClient.getData('custom_login_fields').enabledCustomFields().length || WebClient.getData('custom_login_fields').getValue('login_verification_enabled') ? 'personal' : 'set-password' }); 3758 } 3759 }.bind(this)); 3760}; 3761 3762TemplatesCard_CreateAccount.prototype.helper = function () { 3763 var WebClient = BaseModel.instance('WebClient'); 3764 var Login = BaseModel.instance('Login'); 3765 3766 var signup_domains = WebClient.getData('signup_domains').map(function (domain) { 3767 return { 3768 value: domain.getData('value'), 3769 text: punycode.toUnicode(domain.getData('value')), 3770 selected: Login.getData('create_account').domain === domain.getData('value') 3771 }; 3772 }).sort(function (a, b) { 3773 return b.value > a.value ? -1 : a.value > b.value; 3774 }); 3775 3776 return TemplatesCard.prototype.helper.call(this, { 3777 hook: this.createHook('form'), 3778 content: [ 3779 { 3780 mod: [], 3781 component: BaseController.new('organisms-card-header', { 3782 heading: __('create-account.heading'), 3783 avatar: false, 3784 subtitle: false, 3785 well: this.data.well 3786 }) 3787 }, 3788 { 3789 mod: ['form'], 3790 component: BaseController.new('molecules-input~validatable', { 3791 input: { 3792 type: 'text', 3793 hook: this.createHook('username'), 3794 name: 'username', 3795 value: Login.getData('create_account').username, 3796 autocomplete: 'username' 3797 }, 3798 label: { 3799 text: __('generic.username') 3800 }, 3801 rules: [ 3802 { 3803 name: 'empty', 3804 message: __('validation.empty') 3805 }, 3806 { 3807 name: 'not_contains', 3808 counterpart_value: '@', 3809 message: __('validation.username') 3810 } 3811 ] 3812 }) 3813 }, 3814 { 3815 mod: ['form'], 3816 component: BaseController.new('molecules-select', { 3817 select: { 3818 hook: this.createHook('select'), 3819 name: 'select', 3820 options: signup_domains 3821 }, 3822 label: { 3823 text: __('create-account.domain') 3824 }, 3825 rules: [ 3826 { 3827 name: 'empty', 3828 message: __('validation.empty') 3829 } 3830 ] 3831 }) 3832 }, 3833 { 3834 mod: ['form'], 3835 component: BaseController.new('molecules-input~validatable', { 3836 input: { 3837 type: 'text', 3838 hook: this.createHook('full-name'), 3839 name: 'full-name', 3840 value: Login.getData('create_account').fullname, 3841 autocomplete: 'name' 3842 }, 3843 label: { 3844 text: __('create-account.full-name') 3845 }, 3846 rules: [ 3847 { 3848 name: 'empty', 3849 message: __('validation.empty') 3850 } 3851 ] 3852 }) 3853 }, 3854 { 3855 mod: ['form'], 3856 component: BaseController.new('molecules-input~validatable', { 3857 input: { 3858 type: 'email', 3859 hook: this.createHook('alternate-email'), 3860 name: 'alternate-email', 3861 value: Login.getData('create_account').alternativeemail, 3862 autocomplete: 'email' 3863 }, 3864 label: { 3865 text: __('create-account.alternative-email') 3866 }, 3867 rules: [ 3868 { 3869 name: 'empty', 3870 message: __('validation.empty') 3871 }, 3872 { 3873 name: 'email', 3874 message: __('validation.email') 3875 } 3876 ] 3877 }) 3878 }, 3879 { 3880 mod: ['default', 'space-top'], 3881 component: BaseController.new('molecules-button', { 3882 mod: ['block', 'primary'], 3883 button: { 3884 hook: this.createHook('save-credentials'), 3885 text: WebClient.getData('custom_login_fields').enabledCustomFields().length ? __('create-account.next-step') : __('create-account.last-step'), 3886 name: 'next' 3887 } 3888 }) 3889 }, 3890 { 3891 mod: ['footer'], 3892 component: [ 3893 BaseController.new('atoms-info~have-account'), 3894 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin')
3895 ].filter(Boolean) 3896 } 3897 ].filter(Boolean) 3898 }); 3899}; 3900 3901module.exports = TemplatesCard_CreateAccount; 3902 3903},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel","punycode":355}],105:[function(require,module,exports){ 3904"use strict"; 3905var BaseModel = require('BaseModel'); 3906var BaseController = require('BaseController'); 3907var TemplatesCard = require('./card.js'); 3908var TemplatesCard_ForgotPassword = BaseController.create('TemplatesCard_ForgotPassword', TemplatesCard); 3909 3910TemplatesCard_ForgotPassword.prototype.addListeners = function () { 3911 TemplatesCard.prototype.addListeners.call(this); 3912 this.addHookListener('send-message', 'click', this.submitForm); 3913}; 3914 3915TemplatesCard_ForgotPassword.prototype.validateForm = function () { 3916 this.validate(function (isValid) { 3917 if (isValid) { 3918 BaseModel.instance('WebClient').resetPasswordEmail({ 3919 email: BaseModel.instance('Login').getData('chosen_account').email, 3920 captcharequest: { 3921 uid: this.getChildren('molecules-captcha')[0].uid, 3922 value: this.hook('captcha').value.toUpperCase() 3923 } 3924 }, { 3925 success: function (response) { 3926 if (response == 3) { 3927 this.changeCard({ 3928 card: 'reset-password', 3929 data: { 3930 user: BaseModel.instance('Login').getData('chosen_account').email, 3931 sms: true 3932 }, 3933 change_hash: false 3934 }); 3935 } else { 3936 this.changeCard({ 3937 card: 'generic-message', 3938 data: { 3939 type: 'success', 3940 well: { 3941 text: __('forgot-password.success-message' + (response * 1 === 2 ? '-guest' : '')) 3942 }, 3943 link: '' 3944 }, 3945 change_hash: false 3946 }); 3947 } 3948 }, 3949 error: function (error) { 3950 switch (error) { 3951 case 'account_alternative_email': 3952 this.changeCard({ 3953 card: 'contact-admin', 3954 data: { 3955 well: { 3956 title: __('generic.error'), 3957 text: __('error.' + error), 3958 type: 'error', 3959 class_name: ['is-visible'] 3960 } 3961 } 3962 }); 3963 break; 3964 default: 3965 this.genericError.apply(this, arguments); 3966 } 3967 }, 3968 context: this 3969 }); 3970 } 3971 }.bind(this)); 3972}; 3973 3974TemplatesCard_ForgotPassword.prototype.helper = function () { 3975 return TemplatesCard.prototype.helper.call(this, { 3976 hook: this.createHook('form'), 3977 content: [ 3978 { 3979 mod: [], 3980 component: BaseController.new('organisms-card-header', { 3981 heading: __('forgot-password.heading'), 3982 well: this.data.well 3983 }) 3984 }, 3985 { 3986 mod: ['form'], 3987 component: BaseController.new('molecules-captcha') 3988 }, 3989 { 3990 mod: ['form'], 3991 component: BaseController.new('molecules-input~validatable', { 3992 input: { 3993 hook: this.createHook('captcha'), 3994 type: 'text', 3995 name: 'security-code', 3996 maxlength: 6, 3997 minlength: 6 3998 }, 3999 label: { 4000 text: __('generic.security-code') 4001 }, 4002 rules: [ 4003 { 4004 name: 'empty', 4005 message: __('validation.empty') 4006 }, 4007 { 4008 name: 'length', 4009 data: 6, 4010 message: __('validation.length', 6) 4011 } 4012 ] 4013 }) 4014 }, 4015 { 4016 mod: ['default', 'space-top'], 4017 component: BaseController.new('molecules-button', { 4018 mod: ['block', 'primary'], 4019 button: { 4020 hook: this.createHook('send-message'), 4021 text: __('forgot-password.submit'), 4022 name: 'send-message' 4023 } 4024 }) 4025 }, 4026 { 4027 mod: ['footer'], 4028 component: [ 4029 BaseController.new('atoms-info~not-you'), 4030 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 4031 ].filter(Boolean) 4032 } 4033 ].filter(Boolean) 4034 }); 4035}; 4036 4037module.exports = TemplatesCard_ForgotPassword; 4038 4039},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],106:[function(require,module,exports){ 4040"use strict"; 4041var BaseModel = require('BaseModel'); 4042var BaseController = require('BaseController'); 4043var TemplatesCard = require('./card.js'); 4044var TemplatesCard_GatewayLogin = BaseController.create('TemplatesCard_GatewayLogin', TemplatesCard); 4045 4046TemplatesCard_GatewayLogin.prototype.addListeners = function () { 4047 TemplatesCard.prototype.addListeners.call(this); 4048 this.addHookListener('gateway-sign-in', 'click', this.validateForm); 4049}; 4050 4051TemplatesCard_GatewayLogin.prototype.validateForm = function () { 4052 this.validate(function (isValid) { 4053 if (isValid) { 4054 BaseModel.instance('WebClient').sendGatewayAuthentication({ 4055 email: this.hook('email').value, 4056 captcharequest: { 4057 uid: this.getChildren('molecules-captcha')[0].uid, 4058 value: this.hook('captcha').value.toUpperCase() 4059 } 4060 }, { 4061 success: function () { 4062 this.changeCard({ 4063 card: 'generic-message', 4064 data: { 4065 type: 'success', 4066 well: { 4067 text: __('gateway-login.success-message') 4068 }, 4069 link: '' 4070 }, 4071 change_hash: false 4072 });
4073 }, 4074 error: function (error) { 4075 this.genericError(error); 4076 }, 4077 context: this 4078 }); 4079 } 4080 }.bind(this)); 4081}; 4082 4083TemplatesCard_GatewayLogin.prototype.helper = function () { 4084 var config = BaseModel.instance('Config').getData('config'); 4085 return TemplatesCard.prototype.helper.call(this, { 4086 hook: this.createHook('form'), 4087 content: [ 4088 { 4089 mod: [], 4090 component: BaseController.new('organisms-card-header', { 4091 heading: __('sign-in-generic.heading.' + config.application), 4092 subtitle: { 4093 text: __('gateway-login.subheading') 4094 }, 4095 well: this.data.well 4096 }) 4097 }, 4098 { 4099 mod: ['form'], 4100 component: BaseController.new('molecules-input~validatable', { 4101 input: { 4102 type: 'email', 4103 name: 'email-address', 4104 hook: this.createHook('email') 4105 }, 4106 label: { 4107 text: __('generic.email') 4108 }, 4109 rules: [ 4110 { 4111 name: 'empty', 4112 message: __('validation.empty') 4113 }, 4114 { 4115 name: 'email', 4116 message: __('validation.email') 4117 } 4118 ].filter(Boolean) 4119 }) 4120 }, 4121 { 4122 mod: ['form'], 4123 component: BaseController.new('molecules-captcha') 4124 }, 4125 { 4126 mod: ['form'], 4127 component: BaseController.new('molecules-input~validatable', { 4128 input: { 4129 hook: this.createHook('captcha'), 4130 type: 'text', 4131 name: 'security-code', 4132 maxlength: 6, 4133 minlength: 6 4134 }, 4135 label: { 4136 text: __('generic.security-code') 4137 }, 4138 rules: [ 4139 { 4140 name: 'empty', 4141 message: __('validation.empty') 4142 }, 4143 { 4144 name: 'length', 4145 data: 6, 4146 message: __('validation.length', 6) 4147 } 4148 ] 4149 }) 4150 }, 4151 { 4152 mod: ['default', 'space-top'], 4153 component: BaseController.new('molecules-button', { 4154 mod: ['block', 'primary'], 4155 button: { 4156 text: __('generic.sign-in'), 4157 name: 'gateway-sign-in', 4158 hook: this.createHook('gateway-sign-in') 4159 } 4160 }) 4161 }, 4162 { 4163 mod: ['footer'], 4164 component: BaseController.new('atoms-link~sign-with-another-acc') 4165 } 4166 ].filter(Boolean) 4167 }); 4168}; 4169 4170module.exports = TemplatesCard_GatewayLogin; 4171 4172},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],107:[function(require,module,exports){ 4173"use strict"; 4174var BaseModel = require('BaseModel'); 4175var BaseController = require('BaseController'); 4176var TemplatesCard = require('./card.js'); 4177var TemplatesCard_GenericMessage = BaseController.create('TemplatesCard_GenericMessage', TemplatesCard); 4178var delayed = require('delayed'); 4179var Hash = require('@icewarp/hash'); 4180 4181TemplatesCard_GenericMessage.prototype.addListeners = function () { 4182 TemplatesCard.prototype.addListeners.call(this); 4183 this.addDelegatedHookListener('redirect', 'click', this.changeCard, {card: this.data.link}); 4184}; 4185 4186TemplatesCard_GenericMessage.prototype.onCreate = function () { 4187 this.delayMessage = true; 4188}; 4189 4190TemplatesCard_GenericMessage.prototype.afterRender = function () { 4191 var parts = Hash.getParts(); 4192 TemplatesCard.prototype.afterRender.call(this); 4193 4194 if (parts.tconly) { 4195 if (parts.token && parts.notifyuri) { 4196 this.callCommunication('logoutTeamChatOnly', parts, BaseModel.instance('Login')); 4197 } else { 4198 return this.changeCard({ 4199 card: 'sign-in', 4200 hashData: Hash.getParts() 4201 }); 4202 } 4203 } 4204 4205 delayed(function () { 4206 this.delayMessage = false; 4207 }, this, 400, 'delay' + this._mod); 4208}; 4209 4210TemplatesCard_GenericMessage.prototype.callCommunication = function (method, data, model) { 4211 (model || BaseModel.instance('WebClient'))[method](data, { 4212 success: function () { 4213 this.communicationCallback('success'); 4214 }, 4215 error: function (error) { 4216 this.communicationCallback('error', error); 4217 }, 4218 context: this 4219 }); 4220}; 4221 4222TemplatesCard_GenericMessage.prototype.communicationCallback = function (type, error) { 4223 this.data.type = type; 4224 this.data.well = type === 'error' ? { 4225 text: __('error.' + error, {error: error, md: true}) 4226 } : { 4227 text: __(this._mod + '.success-message') 4228 }; 4229 this.data.subtitle = false; 4230 this.data.link = ''; 4231 this.data.loading = false; 4232 this.hasResponse = true; 4233 Hash.change(false, false, true); 4234 if (this.delayMessage) { 4235 delayed(function () { 4236 this.rerender(); 4237 }, this, 400, 'rerender' + this._mod); 4238 } else { 4239 this.rerender(); 4240 } 4241}; 4242 4243TemplatesCard_GenericMessage.prototype.helper = function () { 4244 if (this.data.well) { 4245 this.data.well.type = this.data.type; 4246 this.data.well.class_name = this.data.class_name || []; 4247 this.data.well.class_name.push('is-visible'); 4248 } 4249 4250 return TemplatesCard.prototype.helper.call(this, { 4251 content: [ 4252 { 4253 mod: [], 4254 component: BaseController.new('organisms-card-header~message', { 4255 mod: this.data.type, 4256 'card-icon': function () { 4257 switch (this.data.type) { 4258 case 'success': 4259 return BaseController.new('atoms-icons', { 4260 icon: 'success' 4261 });
4262 case 'error': 4263 return BaseController.new('atoms-icons', { 4264 icon: 'error' 4265 }); 4266 case 'none': 4267 return false; 4268 default: 4269 return BaseController.new('atoms-icons', { 4270 icon: 'information' 4271 }); 4272 } 4273 }.call(this), 4274 heading: this.data.title === void 0 ? __('generic.' + this.data.type) : this.data.title, 4275 avatar: this.data.avatar, 4276 subtitle: this.data.subtitle, 4277 subsubtitle: this.data.subsubtitle, 4278 well: this.data.well 4279 }) 4280 }, 4281 this.data.loading && { 4282 mod: ['form', 'space-top'], 4283 component: BaseController.new('atoms-loader', { 4284 mod: ['large'] 4285 }) 4286 }, 4287 this.data.link || { 4288 mod: ['form', 'space-top'], 4289 component: BaseController.new('molecules-button', { 4290 mod: ['block', 'primary'], 4291 button: { 4292 text: __('generic.understand'), 4293 name: 'redirect', 4294 hook: this.createHook('redirect') 4295 } 4296 }) 4297 }, 4298 this.data.footer || { 4299 mod: ['footer'], 4300 component: BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 4301 } 4302 ].filter(Boolean) 4303 }); 4304}; 4305 4306module.exports = TemplatesCard_GenericMessage; 4307 4308},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel","delayed":"delayed"}],108:[function(require,module,exports){ 4309"use strict"; 4310var BaseModel = require('BaseModel'); 4311var BaseController = require('BaseController'); 4312var TemplatesCard_GenericMessage = require('./card~generic-message.js'); 4313var TemplatesCard_GuestVerify = BaseController.create('TemplatesCard_GuestVerify', TemplatesCard_GenericMessage); 4314var Hash = require('@icewarp/hash'); 4315 4316TemplatesCard_GuestVerify.prototype.addListeners = function () { 4317 TemplatesCard_GenericMessage.prototype.addListeners.call(this); 4318}; 4319 4320TemplatesCard_GuestVerify.prototype.afterRender = function () { 4321 BaseModel.instance('Login').setData('guestLogin', true); 4322 TemplatesCard_GenericMessage.prototype.afterRender.call(this); 4323 4324 !this.hasResponse && this.callCommunication('guestVerify', { 4325 email: Hash.getParts().email, 4326 hash: Hash.getParts().hash 4327 }); 4328}; 4329 4330TemplatesCard_GuestVerify.prototype.helper = function () { 4331 this.data.avatar = false; 4332 this.data.title = __('guest-verify.heading'); 4333 this.data.subtitle = this.data.subtitle === void 0 ? { 4334 text: __('guest-verify.subheading') 4335 } : this.data.subtitle; 4336 this.data.subsubtitle = { 4337 text: Hash.getParts().email 4338 }; 4339 this.data.loading = this.data.loading === void 0 ? true : this.data.loading; 4340 this.data.type = this.data.type || 'none'; 4341 return TemplatesCard_GenericMessage.prototype.helper.call(this); 4342}; 4343 4344module.exports = TemplatesCard_GuestVerify; 4345 4346},{"./card~generic-message.js":107,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],109:[function(require,module,exports){ 4347"use strict"; 4348var BaseModel = require('BaseModel'); 4349var BaseController = require('BaseController'); 4350var TemplatesCard = require('./card.js'); 4351var AtomsAddon = require('../../atoms/addon/addon'); 4352var TemplatesCard_JoinPassword = BaseController.create('TemplatesCard_JoinPassword', TemplatesCard); 4353 4354TemplatesCard_JoinPassword.prototype.onCreate = function () { 4355 TemplatesCard.prototype.onCreate.call(this); 4356 4357 this.password = BaseController.new('molecules-input~password-with-policy', { 4358 hook: this.createHook('password1'), 4359 input: { 4360 name: 'new-password', 4361 hook: this.createHook('password'), 4362 autocomplete: 'new-password' 4363 }, 4364 label: { 4365 text: __('generic.password-new') 4366 }, 4367 addon: BaseController.new('atoms-addon~show'), 4368 tooltip_well_pinned: true 4369 }); 4370}; 4371 4372TemplatesCard_JoinPassword.prototype.addListeners = function () { 4373 TemplatesCard.prototype.addListeners.call(this); 4374 this.addHookListener('create-account', 'click', this.submitForm); 4375 this.addHookListener('password', 'change', this.crossValidatePasswordCheck); 4376 this.addHookListener('password-check', 'change', this.crossValidatePassword); 4377}; 4378
4379TemplatesCard_JoinPassword.prototype.afterRender = function () { 4380 var addons; 4381 TemplatesCard.prototype.afterRender.call(this); 4382 4383 this.trigger('error-message-show', this.password.data.tooltip_well); 4384 addons = this.password.getChildrenByClass(AtomsAddon); 4385 addons[1] && addons[1].DOMElement.setAttribute('hidden', ''); 4386}; 4387 4388TemplatesCard_JoinPassword.prototype.validateForm = function () { 4389 this.validate(function (isValid) { 4390 var Login = BaseModel.instance('Login'); 4391 if (isValid) { 4392 Login.getData('create_account').password = this.hook('password').value; 4393 Login.getData('create_account').session = window.sessionData.id; 4394 4395 Login.getAuthChallenge({ 4396 success: this.signupAccount, 4397 error: function (error) { 4398 this.genericError(error); 4399 }, 4400 context: this 4401 }); 4402 } 4403 }.bind(this)); 4404}; 4405 4406TemplatesCard_JoinPassword.prototype.signupAccount = function (encrypt) { 4407 BaseModel.instance('WebClient').signupAccount(encrypt, { 4408 success: function () { 4409 this.changeCard({ 4410 data: { 4411 well: { 4412 title: __('generic.success'), 4413 text: __('set-password.success-message'), 4414 type: 'success', 4415 class_name: ['is-visible'] 4416 } 4417 } 4418 }); 4419 }, 4420 error: function (error) { 4421 this.genericError(error); 4422 }, 4423 context: this 4424 }); 4425}; 4426 4427TemplatesCard_JoinPassword.prototype.crossValidatePasswordCheck = function () { 4428 this.hook('password-check').value.trim().length && this.getInstanceByElement(this.hook('password2')).validate(); 4429}; 4430TemplatesCard_JoinPassword.prototype.crossValidatePassword = function () { 4431 this.hook('password').value.trim().length && this.getInstanceByElement(this.hook('password1')).validate(); 4432}; 4433 4434TemplatesCard_JoinPassword.prototype.helper = function () { 4435 var Login = BaseModel.instance('Login'); 4436 4437 this.data.back = true; 4438 4439 return TemplatesCard.prototype.helper.call(this, { 4440 hook: this.createHook('form'), 4441 content: [ 4442 { 4443 mod: [], 4444 component: BaseController.new('organisms-card-header', { 4445 heading: __('set-password.heading'), 4446 avatar: false, 4447 well: this.data.well 4448 }) 4449 }, 4450 { 4451 class_name: ['u-hide'], 4452 component: BaseController.new('molecules-input', { 4453 input: { 4454 type: 'text', 4455 name: 'username', 4456 hook: this.createHook('username'), 4457 value: Login.getData('chosen_account').email, 4458 autocomplete: 'username' 4459 } 4460 }) 4461 }, 4462 { 4463 mod: ['form', 'space-top'], 4464 component: this.password 4465 }, 4466 { 4467 mod: ['form'], 4468 component: BaseController.new('molecules-input~password', { 4469 hook: this.createHook('password2'), 4470 input: { 4471 name: 'password-check', 4472 hook: this.createHook('password-check'), 4473 autocomplete: 'new-password' 4474 }, 4475 label: { 4476 text: __('generic.password-confirm') 4477 }, 4478 rules: [ 4479 { 4480 name: 'empty', 4481 message: __('validation.empty') 4482 }, 4483 { 4484 name: 'same', 4485 controller: this, 4486 parent_hook: 'form', 4487 counterpart_hook: 'password', 4488 message: __('validation.passwords-no-match') 4489 } 4490 ], 4491 addon: BaseController.new('atoms-addon~show') 4492 }) 4493 }, 4494 { 4495 mod: ['default'], 4496 component: BaseController.new('molecules-button', { 4497 mod: ['block', 'primary'], 4498 button: { 4499 text: __('set-password.submit'), 4500 hook: this.createHook('create-account'), 4501 name: 'create-account' 4502 } 4503 }) 4504 } 4505 ] 4506 }); 4507}; 4508 4509module.exports = TemplatesCard_JoinPassword; 4510 4511},{"../../atoms/addon/addon":49,"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],110:[function(require,module,exports){ 4512"use strict"; 4513var punycode = require('punycode'); 4514var delayed = require('delayed'); 4515var BaseModel = require('BaseModel'); 4516var BaseController = require('BaseController'); 4517var TemplatesCard = require('./card.js'); 4518var Validator = BaseModel.instance('Validator'); 4519var TemplatesCard_JoinUsername = BaseController.create('TemplatesCard_JoinUsername', TemplatesCard); 4520 4521TemplatesCard_JoinUsername.prototype.onCreate = function () { 4522 TemplatesCard.prototype.onCreate.call(this); 4523 4524 this.ico = BaseController.new('atoms-icons', { 4525 icon: 'success',
4526 class_name: ['success'] 4527 }); 4528}; 4529 4530TemplatesCard_JoinUsername.prototype.addListeners = function () { 4531 TemplatesCard.prototype.addListeners.call(this); 4532 this.addHookListener('username', 'change keyup', function() { 4533 delayed(this.validateUsername.bind(this, this.hook('username').value), this, 200, 'username_available'); 4534 }); 4535 this.addHookListener('save-credentials', 'click', this.submitForm); 4536}; 4537 4538TemplatesCard_JoinUsername.prototype.validateUsername = function (value, callback) { 4539 var Login = BaseModel.instance('Login'); 4540 4541 this.ico.data.icon = 'hint'; 4542 this.ico.data.class_name = ['hint']; 4543 this.ico.rerender(); 4544 4545 Login.usernameAvailable({ 4546 username: value, 4547 domain: window.sessionData.domain, 4548 session: window.sessionData.id 4549 }, { 4550 success: function() { 4551 this.ico.data.icon = 'success'; 4552 this.ico.data.class_name = ['success']; 4553 this.ico.rerender(); 4554 4555 callback && callback(true); 4556 }, 4557 error: function () { 4558 this.ico.data.icon = 'xmark'; 4559 this.ico.data.class_name = ['error']; 4560 this.ico.rerender(); 4561 4562 callback && callback(false); 4563 }, 4564 context: this 4565 }); 4566}; 4567 4568TemplatesCard_JoinUsername.prototype.validateForm = function () { 4569 var Login = BaseModel.instance('Login'); 4570 this.validate(function (isValid) { 4571 if (isValid) { 4572 Login.setData('chosen_account', Object.assign(Login.getData('chosen_account'), { 4573 email: this.hook('username').value + '@' + punycode.toUnicode(window.sessionData.domain), 4574 })); 4575 Login.setData('create_account', Object.assign(Login.getData('create_account'), { 4576 username: this.hook('username').value, 4577 })); 4578 this.changeCard({ card: 'join-password' }); 4579 } 4580 }.bind(this)); 4581}; 4582 4583TemplatesCard_JoinUsername.prototype.helper = function () { 4584 var Login = BaseModel.instance('Login'); 4585 var domain = punycode.toUnicode(window.sessionData.domain); 4586 4587 this.data.back = true; 4588 4589 return TemplatesCard.prototype.helper.call(this, { 4590 hook: this.createHook('form'), 4591 content: [ 4592 { 4593 mod: [], 4594 component: BaseController.new('organisms-card-header', { 4595 avatar: false, 4596 heading: __('join.heading', { domain: domain }), 4597 subtitle: false, 4598 subsubtitle: { 4599 text: __('create-account.suggestion'), 4600 class_name: ['o-header__subsubtitle'], 4601 mod: ['small'] 4602 }, 4603 well: this.data.well 4604 }) 4605 }, 4606 { 4607 mod: ['form'], 4608 component: BaseController.new('molecules-input~validatable', { 4609 mod: ['wide'], 4610 input: { 4611 type: 'text', 4612 hook: this.createHook('username'), 4613 name: 'username', 4614 value: Login.getData('create_account').username 4615 }, 4616 label: { 4617 text: __('create-account.email-address') 4618 }, 4619 rules: [ 4620 { 4621 name: 'empty', 4622 message: __('validation.empty') 4623 }, 4624 { 4625 name: 'callback', 4626 callback: function(value, callback) { 4627 Validator.email(false, value + '@' + domain, callback); 4628 }, 4629 message: __('validation.email') 4630 }, 4631 { 4632 name: 'callback', 4633 callback: this.validateUsername.bind(this), 4634 message: __('validation.username-taken') 4635 } 4636 ], 4637 addon: [ 4638 { 4639 mod: 'ico', 4640 icon: this.ico 4641 }, 4642 { 4643 mod: 'static', 4644 text: '@' + domain 4645 } 4646 ] 4647 }) 4648 }, 4649 { 4650 mod: ['default', 'space-top'], 4651 component: BaseController.new('molecules-button', { 4652 mod: ['block', 'primary'], 4653 button: { 4654 hook: this.createHook('save-credentials'), 4655 text: __('generic.next') 4656 } 4657 }) 4658 } 4659 ] 4660 }); 4661}; 4662 4663module.exports = TemplatesCard_JoinUsername; 4664 4665},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel","delayed":"delayed","punycode":355}],111:[function(require,module,exports){ 4666"use strict"; 4667var punycode = require('punycode'); 4668var BaseModel = require('BaseModel'); 4669var BaseController = require('BaseController'); 4670var removeAccents = require('@icewarp/utils').string.removeAccents; 4671var TemplatesCard = require('./card.js'); 4672var TemplatesCard_Join = BaseController.create('TemplatesCard_Join', TemplatesCard); 4673 4674TemplatesCard_Join.prototype.addListeners = function () { 4675 TemplatesCard.prototype.addListeners.call(this); 4676 this.addHookListener('save-credentials', 'click', this.submitForm); 4677 this.addHookListener('full-name', 'keyup', this.fullnameHandler); 4678};
4679 4680TemplatesCard_Join.prototype.validateForm = function () { 4681 this.validate(function (isValid) { 4682 if (isValid) { 4683 this.validateUsername(); 4684 } 4685 }.bind(this)); 4686}; 4687 4688TemplatesCard_Join.prototype.validateUsername = function (index) { 4689 var Login = BaseModel.instance('Login'); 4690 var fullname = this.hook('first-name').value + ' ' + this.hook('last-name').value; 4691 var username = removeAccents(fullname.toLowerCase().split(' ').join('.') + (index ? index : '')); 4692 Login.usernameAvailable({ 4693 username: username, 4694 domain: window.sessionData.domain, 4695 session: window.sessionData.id 4696 }, { 4697 success: function() { 4698 Login.setData('chosen_account', { 4699 name: fullname, 4700 email: username + '@' + punycode.toUnicode(window.sessionData.domain), 4701 avatar_token: false 4702 }); 4703 Login.setData('create_account', { 4704 username: username, 4705 domain: window.sessionData.domain, 4706 fullname: fullname, 4707 card: {} 4708 }); 4709 4710 this.changeCard({ card: 'join-username' }); 4711 }, 4712 error: function (error) { 4713 switch(error) { 4714 case 'signup_invalid_invite_domain': 4715 case 'signup_invalid_invite_session': 4716 return this.showMessage({ 4717 title: __('generic.error'), 4718 text: __('error.' + error), 4719 type: 'error' 4720 }); 4721 } 4722 if (index > 9) { 4723 return this.validateUsername(Math.floor(Math.random() * 999999)); 4724 } 4725 this.validateUsername((index || 0) + 1); 4726 }, 4727 context: this 4728 }); 4729}; 4730 4731TemplatesCard_Join.prototype.helper = function () { 4732 var Login = BaseModel.instance('Login'); 4733 4734 var fullname = (Login.getData('create_account').fullname || '').split(' '); 4735 var firstname = fullname[0] || ''; 4736 var lastname = fullname[1] || ''; 4737 4738 return TemplatesCard.prototype.helper.call(this, { 4739 hook: this.createHook('form'), 4740 content: [ 4741 { 4742 mod: [], 4743 component: BaseController.new('organisms-card-header', { 4744 heading: __('join.heading', { domain: window.sessionData.domain }), 4745 avatar: false, 4746 subtitle: false, 4747 subsubtitle: false, 4748 well: this.data.well 4749 }) 4750 }, 4751 { 4752 mod: ['form'], 4753 component: BaseController.new('molecules-input~validatable', { 4754 input: { 4755 type: 'text', 4756 hook: this.createHook('first-name'), 4757 name: 'first-name', 4758 value: firstname, 4759 autocomplete: 'given-name' 4760 }, 4761 label: { 4762 text: firstname ? __('create-account.first-name') : __('create-account.enter-first-name') 4763 }, 4764 rules: [ 4765 { 4766 name: 'empty', 4767 message: __('validation.empty') 4768 } 4769 ] 4770 }) 4771 }, 4772 { 4773 mod: ['form'], 4774 component: BaseController.new('molecules-input~validatable', { 4775 input: { 4776 type: 'text', 4777 hook: this.createHook('last-name'), 4778 name: 'last-name', 4779 value: lastname, 4780 autocomplete: 'family-name' 4781 }, 4782 label: { 4783 text: lastname ? __('create-account.last-name') : __('create-account.enter-last-name') 4784 }, 4785 rules: [ 4786 { 4787 name: 'empty', 4788 message: __('validation.empty') 4789 } 4790 ] 4791 }) 4792 }, 4793 { 4794 mod: ['default', 'space-top'], 4795 component: BaseController.new('molecules-button', { 4796 mod: ['block', 'primary'], 4797 button: { 4798 hook: this.createHook('save-credentials'), 4799 text: __('generic.next') 4800 } 4801 }) 4802 } 4803 ] 4804 }); 4805}; 4806 4807module.exports = TemplatesCard_Join; 4808 4809},{"./card.js":99,"@icewarp/utils":180,"BaseController":"BaseController","BaseModel":"BaseModel","punycode":355}],112:[function(require,module,exports){ 4810"use strict"; 4811var Hash = require('@icewarp/hash'); 4812var BaseModel = require('BaseModel'); 4813var BaseController = require('BaseController'); 4814var TemplatesCard = require('./card.js'); 4815var TemplatesCard_Unavailable = require('./card~unavailable'); 4816var TemplatesCard_OauthGrant = BaseController.create( 4817 'TemplatesCard_OauthGrant', 4818 TemplatesCard 4819); 4820 4821TemplatesCard_OauthGrant.prototype.addListeners = function () { 4822 TemplatesCard.prototype.addListeners.call(this); 4823 this.addHookListener('accept', 'click', this.accept); 4824 this.addHookListener('decline', 'click', this.decline); 4825};
4826 4827TemplatesCard_OauthGrant.prototype.accept = function () { 4828 var OAuth = BaseModel.instance('OAuth'); 4829 OAuth.GrantOauthAuthorization( 4830 this.hook('description') ? this.hook('description').value : '', 4831 { 4832 success: function () { 4833 window.location.replace(OAuth.getRedirectURL()); 4834 }.bind(this), 4835 error: function (error) { 4836 this.genericError(error); 4837 }.bind(this) 4838 } 4839 ); 4840}; 4841TemplatesCard_OauthGrant.prototype.decline = function () { 4842 window.location.replace( 4843 '/oauth/v2/code?auth_id=' + Hash.getParts().auth_id 4844 ); 4845}; 4846 4847TemplatesCard_OauthGrant.prototype.helperDataBuilder = function () { 4848 var OAuth = BaseModel.instance('OAuth'); 4849 var account_data = OAuth.getData('account_data'); 4850 var image = account_data.A_Image; 4851 4852 var client = { 4853 client: OAuth.getData('name') 4854 }; 4855 4856 return TemplatesCard.prototype.helper.call(this, { 4857 hook: this.createHook('form'), 4858 content: [ 4859 { 4860 mod: [], 4861 component: BaseController.new('organisms-card-header', { 4862 heading: __('sign-in-generic.heading.oauth', client), 4863 well: { 4864 title: __('oauth.grant_title', client), 4865 text: 4866 OAuth.getData('scopes').map(function (scope) { 4867 return '- ' + __('oauth.' + scope) + '\n'; 4868 }) + __('oauth.info', client), 4869 class_name: ['is-visible'] 4870 }, 4871 avatar: { 4872 image: image && image.url, 4873 letter: !image && account_data.A_Name[0][0] 4874 } 4875 }) 4876 }, 4877 { 4878 mod: ['form'], 4879 component: BaseController.new('molecules-input', { 4880 input: { 4881 type: 'text', 4882 name: 'description', 4883 hook: this.createHook('description') 4884 }, 4885 label: { 4886 text: __('oauth.description') 4887 } 4888 }) 4889 }, 4890 { 4891 mod: ['default', 'space-top'], 4892 component: [ 4893 BaseController.new('molecules-button', { 4894 mod: ['block', 'primary', 'flex'], 4895 button: { 4896 hook: this.createHook('accept'), 4897 text: __('generic.authorize'), 4898 name: 'next' 4899 } 4900 }), 4901 BaseController.new('molecules-button', { 4902 mod: ['block', 'flex', 'error'], 4903 button: { 4904 hook: this.createHook('decline'), 4905 text: __('generic.decline'), 4906 name: 'next' 4907 } 4908 }) 4909 ] 4910 } 4911 ] 4912 }); 4913}; 4914 4915TemplatesCard_OauthGrant.prototype.checkAlreadyExistingGrant = function ( 4916 callback 4917) { 4918 var OAuth = BaseModel.instance('OAuth'); 4919 OAuth.checkExistingGrant({ 4920 success: function () { 4921 this.accept(); 4922 }.bind(this), 4923 error: function () { 4924 callback.success.call(callback.context || this); 4925 }.bind(this) 4926 }); 4927}; 4928 4929TemplatesCard_OauthGrant.prototype.helper = function () { 4930 var OAuth = BaseModel.instance('OAuth'); 4931 var account_data = OAuth.getData('account_data'); 4932 var controller_this = this; 4933 if (!account_data) { 4934 return new Promise(function (resolve) { 4935 OAuth.initAlreadyLoggedIn({ 4936 success: function () { 4937 controller_this.checkAlreadyExistingGrant({ 4938 success: function () { 4939 resolve(controller_this.helperDataBuilder()); 4940 } 4941 }); 4942 }, 4943 error: function (error) { 4944 controller_this.data.title = error; 4945 resolve( 4946 TemplatesCard_Unavailable.prototype.helper.call( 4947 controller_this 4948 ) 4949 ); 4950 }, 4951 context: this 4952 }); 4953 }); 4954 } 4955 return new Promise(function (resolve) { 4956 controller_this.checkAlreadyExistingGrant({ 4957 success: function () { 4958 resolve(controller_this.helperDataBuilder()); 4959 } 4960 }); 4961 }); 4962 // return this.helperDataBuilder(); 4963}; 4964 4965module.exports = TemplatesCard_OauthGrant; 4966 4967},{"./card.js":99,"./card~unavailable":126,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],113:[function(require,module,exports){ 4968"use strict"; 4969var BaseModel = require('BaseModel'); 4970var BaseController = require('BaseController'); 4971var TemplatesCard = require('./card.js'); 4972var TemplatesCard_Personal = BaseController.create('TemplatesCard_Personal', TemplatesCard); 4973 4974TemplatesCard_Personal.prototype.addListeners = function () { 4975 TemplatesCard.prototype.addListeners.call(this); 4976 this.addHookListener('save-personal', 'click', this.submitForm); 4977}; 4978 4979TemplatesCard_Personal.prototype.validateForm = function () { 4980 this.validate(function (isValid) { 4981 var Login = BaseModel.instance('Login'); 4982 var WebClient = BaseModel.instance('WebClient'); 4983 var CLF = WebClient.getData('custom_login_fields'); 4984 var sms_verification = CLF.getValue('login_verification_type') === 'sms'; 4985 var create_account = Login.getData('create_account'); 4986 var selector; 4987 4988 if (isValid) { 4989 CLF.enabledCustomFields().map(function (field) { 4990 create_account.card[this.hook(field.name).getAttribute('name')] = this.hook(field.name).value; 4991 }, this); 4992 4993 create_account.card.classname = 'taccountcard'; 4994 Login.setData('create_account', create_account); 4995 4996 if (!WebClient.getData('custom_login_fields').getValue('login_verification_enabled')) { 4997 return this.changeCard({ card: 'set-password' }); 4998 } 4999 5000 selector = sms_verification ? create_account.card.mobiletelephonenumber : create_account.alternativeemail; 5001 Login.getVerification({ 5002 verificationtype: +sms_verification, 5003 verificationselector: selector, 5004 captcharequest: { 5005 uid: this.getChildren('molecules-captcha')[0].uid, 5006 value: this.hook('captcha').value.toUpperCase() 5007 } 5008 }, { 5009 success: function () { 5010 this.changeCard({ 5011 card: 'set-password', 5012 data: { 5013 well: { 5014 title: __('generic.success'), 5015 text: __('set-password.code_sent_to', { to: selector }), 5016 type: 'success', 5017 class_name: ['is-visible'] 5018 } 5019 } 5020 });
5021 }, 5022 error: function (error) { 5023 this.genericError(error); 5024 }, 5025 context: this 5026 }); 5027 } 5028 }.bind(this)); 5029}; 5030 5031TemplatesCard_Personal.prototype.customFieldsHelper = function () { 5032 var Login = BaseModel.instance('Login'); 5033 var WebClient = BaseModel.instance('WebClient'); 5034 5035 var autocomplete = { 5036 birthday: 'bday', 5037 company: 'organization', 5038 job: 'organization-title', 5039 mobile_phone: 'tel' 5040 }; 5041 5042 return WebClient.getData('custom_login_fields').enabledCustomFields().map(function (custom_field) { 5043 switch (custom_field.type) { 5044 case 'select': 5045 return { 5046 mod: ['form'], 5047 component: BaseController.new('molecules-select~validatable', { 5048 select: { 5049 hook: this.createHook(custom_field.name), 5050 name: custom_field.name, 5051 options: custom_field.options.map(function (option) { 5052 option.selected = Login.getData('create_account').card[custom_field.name] == option.value; 5053 return option; 5054 }) 5055 }, 5056 label: { 5057 text: custom_field.label 5058 }, 5059 rules: WebClient.getData('custom_login_fields').getValue(custom_field.id + '_required') ? [ 5060 { 5061 name: 'empty', 5062 message: __('validation.empty') 5063 } 5064 ] : false 5065 }) 5066 }; 5067 default: 5068 return { 5069 mod: ['form'], 5070 component: BaseController.new('molecules-input~validatable', { 5071 input: { 5072 type: custom_field.type || 'text', 5073 hook: this.createHook(custom_field.name), 5074 name: custom_field.name, 5075 value: Login.getData('create_account').card[custom_field.name], 5076 maxDate: custom_field.maxDate, 5077 autocomplete: autocomplete[custom_field.name] || custom_field.name 5078 }, 5079 label: { 5080 text: custom_field.label 5081 }, 5082 rules: (WebClient.getData('custom_login_fields').getValue(custom_field.id + '_required') || (custom_field.id === 'mobile_phone' && WebClient.getData('custom_login_fields').getValue('login_verification_enabled') && (WebClient.getData('custom_login_fields').getValue('login_verification_type') === 'sms'))) ? [ 5083 { 5084 name: 'empty', 5085 message: __('validation.empty') 5086 } 5087 ] : false 5088 }) 5089 }; 5090 } 5091 }, this); 5092}; 5093 5094TemplatesCard_Personal.prototype.helper = function () { 5095 var WebClient = BaseModel.instance('WebClient'); 5096 5097 this.data.back = true; 5098 5099 return TemplatesCard.prototype.helper.call(this, { 5100 hook: this.createHook('form'), 5101 content: [ 5102 { 5103 mod: [], 5104 component: BaseController.new('organisms-card-header', { 5105 heading: __('personal.heading'), 5106 avatar: false, 5107 subtitle: false, 5108 well: this.data.well 5109 }) 5110 } 5111 ].concat( 5112 this.customFieldsHelper(), 5113 WebClient.getData('custom_login_fields').getValue('login_verification_enabled') && { 5114 mod: ['form'], 5115 component: BaseController.new('molecules-captcha') 5116 }, 5117 WebClient.getData('custom_login_fields').getValue('login_verification_enabled') && { 5118 mod: ['form'], 5119 component: BaseController.new('molecules-input~validatable', { 5120 input: { 5121 hook: this.createHook('captcha'), 5122 type: 'text', 5123 name: 'security-code', 5124 maxlength: 6, 5125 minlength: 6 5126 }, 5127 label: { 5128 text: __('generic.security-code') 5129 }, 5130 rules: [ 5131 { 5132 name: 'empty', 5133 message: __('validation.empty') 5134 }, 5135 { 5136 name: 'length', 5137 data: 6, 5138 message: __('validation.length', 6) 5139 } 5140 ] 5141 }) 5142 }, 5143 { 5144 mod: ['default', 'space-top'], 5145 component: BaseController.new('molecules-button', { 5146 mod: ['block', 'primary'], 5147 button: { 5148 hook: this.createHook('save-personal'), 5149 text: __('create-account.last-step'), 5150 name: 'next' 5151 } 5152 }) 5153 }, 5154 { 5155 mod: ['footer'], 5156 component: [ 5157 BaseController.new('atoms-info~have-account'), 5158 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 5159 ].filter(Boolean) 5160 } 5161 ).filter(Boolean) 5162 }); 5163}; 5164 5165module.exports = TemplatesCard_Personal; 5166 5167},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],114:[function(require,module,exports){ 5168"use strict"; 5169var BaseModel = require('BaseModel'); 5170var BaseController = require('BaseController'); 5171var TemplatesCard = require('./card.js'); 5172var TemplatesCard_ResetPassword = BaseController.create('TemplatesCard_ResetPassword', TemplatesCard); 5173var Hash = require('@icewarp/hash'); 5174 5175TemplatesCard_ResetPassword.prototype.addListeners = function () { 5176 TemplatesCard.prototype.addListeners.call(this); 5177 this.addHookListener('confirm', 'click', this.submitForm); 5178}; 5179 5180TemplatesCard_ResetPassword.prototype.validateForm = function () { 5181 this.validate(function (isValid) { 5182 if (isValid) { 5183 BaseModel.instance('Login').getAuthChallenge({ 5184 success: this.resetPassword, 5185 error: function (error) { 5186 this.genericError(error); 5187 }, 5188 context: this 5189 }); 5190 } 5191 }.bind(this)); 5192}; 5193 5194TemplatesCard_ResetPassword.prototype.resetPassword = function (encrypt) { 5195 BaseModel.instance('WebClient').resetPassword({ 5196 newpassword: encrypt(this.hook('password').value), 5197 resethash: this.data.sms && this.hook('resethash').value, 5198 user: this.data.user 5199 }, { 5200 success: function () { 5201 this.changeCard({ 5202 card: 'generic-message', 5203 data: { 5204 type: 'success', 5205 well: { 5206 text: __('reset-password.success-message') 5207 }, 5208 link: '' 5209 }, 5210 change_hash: false 5211 }); 5212 }, 5213 error: function (error) { 5214 this.genericError(error); 5215 }, 5216 context: this 5217 }); 5218}; 5219 5220TemplatesCard_ResetPassword.prototype.helper = function () { 5221 var Login = BaseModel.instance('Login'); 5222 Login.setData('chosen_account', Login.getUser(this.data.user || Hash.getParts().user) || {}); 5223 5224 return TemplatesCard.prototype.helper.call(this, { 5225 hook: this.createHook('form'), 5226 content: [ 5227 { 5228 mod: [], 5229 component: BaseController.new('organisms-card-header', { 5230 heading: __('reset-password.heading'), 5231 well: this.data.well 5232 }) 5233 }, 5234 { 5235 class_name: ['u-hide'], 5236 component: BaseController.new('molecules-input', { 5237 input: { 5238 type: 'text', 5239 name: 'username', 5240 hook: this.createHook('username'), 5241 value: (this.data.user || Hash.getParts().user || '').replace(/@.*/, '') 5242 } 5243 }) 5244 }, 5245 { 5246 mod: ['form'], 5247 component: BaseController.new('molecules-input~password-with-policy', { 5248 input: { 5249 name: 'password', 5250 hook: this.createHook('password') 5251 }, 5252 label: { 5253 text: __('generic.password-new') 5254 }, 5255 addon: BaseController.new('atoms-addon~show') 5256 }) 5257 }, 5258 { 5259 mod: ['form'], 5260 component: BaseController.new('molecules-input~password', { 5261 input: { 5262 name: 'confirm-password' 5263 }, 5264 label: { 5265 text: __('generic.password-confirm') 5266 }, 5267 addon: BaseController.new('atoms-addon~show'), 5268 rules: [ 5269 { 5270 name: 'empty', 5271 message: __('validation.empty') 5272 }, 5273 { 5274 name: 'same', 5275 controller: this, 5276 parent_hook: 'form', 5277 counterpart_hook: 'password', 5278 message: __('validation.passwords-no-match') 5279 } 5280 ] 5281 }) 5282 }, 5283 this.data.sms && { 5284 mod: ['form'], 5285 component: BaseController.new('molecules-input', { 5286 input: { 5287 name: 'resethash', 5288 hook: this.createHook('resethash') 5289 }, 5290 label: { 5291 text: __('reset-password.resethash') 5292 }, 5293 rules: [{ 5294 name: 'empty', 5295 message: __('validation.empty') 5296 }] 5297 }) 5298 }, 5299 { 5300 mod: ['default', 'space-top'], 5301 component: BaseController.new('molecules-button', { 5302 mod: ['block', 'primary'], 5303 button: { 5304 text: __('generic.save-password'), 5305 hook: this.createHook('confirm'), 5306 name: 'confirm' 5307 } 5308 }) 5309 }, 5310 { 5311 mod: ['footer'], 5312 component: [ 5313 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin')
5314 ].filter(Boolean) 5315 } 5316 ].filter(Boolean) 5317 }); 5318}; 5319 5320module.exports = TemplatesCard_ResetPassword; 5321 5322},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],115:[function(require,module,exports){ 5323"use strict"; 5324var BaseModel = require('BaseModel'); 5325var BaseController = require('BaseController'); 5326var TemplatesCard = require('./card.js'); 5327var AtomsAddon = require('../../atoms/addon/addon'); 5328var TemplatesCard_SetPassword = BaseController.create('TemplatesCard_SetPassword', TemplatesCard); 5329 5330TemplatesCard_SetPassword.prototype.onCreate = function () { 5331 TemplatesCard.prototype.onCreate.call(this); 5332 5333 this.password = BaseController.new('molecules-input~password-with-policy', { 5334 hook: this.createHook('password1'), 5335 input: { 5336 name: 'password', 5337 hook: this.createHook('password'), 5338 autocomplete: 'new-password' 5339 }, 5340 label: { 5341 text: __('generic.password-new') 5342 }, 5343 addon: BaseController.new('atoms-addon~show'), 5344 tooltip_well_pinned: true 5345 }); 5346}; 5347TemplatesCard_SetPassword.prototype.addListeners = function () { 5348 TemplatesCard.prototype.addListeners.call(this); 5349 this.addHookListener('create-account', 'click', this.submitForm); 5350 this.addHookListener('password', 'change', this.crossValidatePasswordCheck); 5351 this.addHookListener('password-check', 'change', this.crossValidatePassword); 5352}; 5353 5354TemplatesCard_SetPassword.prototype.afterRender = function () { 5355 var addons; 5356 TemplatesCard.prototype.afterRender.call(this); 5357 5358 this.trigger('error-message-show', this.password.data.tooltip_well); 5359 addons = this.password.getChildrenByClass(AtomsAddon); 5360 addons[1] && addons[1].DOMElement.setAttribute('hidden', ''); 5361}; 5362 5363TemplatesCard_SetPassword.prototype.validateForm = function () { 5364 this.validate(function (isValid) { 5365 var WebClient = BaseModel.instance('WebClient'); 5366 var Login = BaseModel.instance('Login'); 5367 5368 if (isValid) { 5369 Login.getData('create_account').password = this.hook('password').value; 5370 5371 if (WebClient.getData('custom_login_fields').getValue('login_verification_enabled')) { 5372 Login.getData('create_account').verificationrequest.code = this.hook('verification_code').value; 5373 } else { 5374 Login.getData('create_account').captcharequest = { 5375 uid: this.getChildren('molecules-captcha')[0].uid, 5376 value: this.hook('captcha').value.toUpperCase() 5377 }; 5378 } 5379 5380 Login.getAuthChallenge({ 5381 success: this.signupAccount, 5382 error: function (error) { 5383 this.genericError(error); 5384 }, 5385 context: this 5386 }); 5387 } 5388 }.bind(this)); 5389}; 5390 5391TemplatesCard_SetPassword.prototype.signupAccount = function (encrypt) { 5392 BaseModel.instance('WebClient').signupAccount(encrypt, { 5393 success: function () { 5394 this.changeCard({ 5395 data: { 5396 well: { 5397 title: __('generic.success'), 5398 text: __('set-password.success-message'), 5399 type: 'success', 5400 class_name: ['is-visible'] 5401 } 5402 } 5403 }); 5404 }, 5405 error: function (error) { 5406 this.genericError(error); 5407 }, 5408 context: this 5409 }); 5410}; 5411 5412TemplatesCard_SetPassword.prototype.crossValidatePasswordCheck = function () { 5413 this.hook('password-check').value.trim().length && this.getInstanceByElement(this.hook('password2')).validate(); 5414}; 5415TemplatesCard_SetPassword.prototype.crossValidatePassword = function () { 5416 this.hook('password').value.trim().length && this.getInstanceByElement(this.hook('password1')).validate(); 5417}; 5418 5419TemplatesCard_SetPassword.prototype.helper = function () { 5420 var Login = BaseModel.instance('Login'); 5421 var WebClient = BaseModel.instance('WebClient'); 5422 5423 this.data.back = true; 5424 5425 return TemplatesCard.prototype.helper.call(this, { 5426 hook: this.createHook('form'), 5427 content: [ 5428 { 5429 mod: [], 5430 component: BaseController.new('organisms-card-header', { 5431 heading: __('set-password.heading'), 5432 well: this.data.well 5433 }) 5434 }, 5435 { 5436 class_name: ['u-hide'], 5437 component: BaseController.new('molecules-input', { 5438 input: { 5439 type: 'text', 5440 name: 'username', 5441 hook: this.createHook('username'), 5442 value: Login.getData('chosen_account').email, 5443 autocomplete: 'username' 5444 } 5445 }) 5446 }, 5447 { 5448 mod: ['form'], 5449 component: this.password 5450 }, 5451 { 5452 mod: ['form'], 5453 component: BaseController.new('molecules-input~password', { 5454 hook: this.createHook('password2'), 5455 input: { 5456 name: 'password-check', 5457 hook: this.createHook('password-check'), 5458 autocomplete: 'new-password' 5459 }, 5460 label: { 5461 text: __('generic.password-confirm') 5462 }, 5463 rules: [ 5464 { 5465 name: 'empty', 5466 message: __('validation.empty') 5467 }, 5468 { 5469 name: 'same', 5470 controller: this, 5471 parent_hook: 'form', 5472 counterpart_hook: 'password', 5473 message: __('validation.passwords-no-match') 5474 } 5475 ], 5476 addon: BaseController.new('atoms-addon~show') 5477 }) 5478 }, 5479 WebClient.getData('custom_login_fields').getValue('login_verification_enabled') ? { 5480 mod: ['form'], 5481 component: BaseController.new('molecules-input~validatable', { 5482 input: { 5483 hook: this.createHook('verification_code'), 5484 type: 'text', 5485 name: 'verification_code', 5486 maxlength: 6, 5487 minlength: 6 5488 }, 5489 label: { 5490 text: __('set-password.verification_code') 5491 }, 5492 rules: [ 5493 { 5494 name: 'empty', 5495 message: __('validation.empty') 5496 }, 5497 { 5498 name: 'length', 5499 data: 6, 5500 message: __('validation.length', 6) 5501 } 5502 ] 5503 }) 5504 } : { 5505 mod: ['form'], 5506 component: BaseController.new('molecules-captcha') 5507 }, 5508 WebClient.getData('custom_login_fields').getValue('login_verification_enabled') ? false : { 5509 mod: ['form'], 5510 component: BaseController.new('molecules-input~validatable', { 5511 input: { 5512 hook: this.createHook('captcha'), 5513 type: 'text', 5514 name: 'security-code', 5515 maxlength: 6, 5516 minlength: 6 5517 }, 5518 label: { 5519 text: __('generic.security-code') 5520 }, 5521 rules: [ 5522 { 5523 name: 'empty', 5524 message: __('validation.empty') 5525 }, 5526 { 5527 name: 'length', 5528 data: 6, 5529 message: __('validation.length', 6) 5530 } 5531 ] 5532 }) 5533 }, 5534 { 5535 mod: ['default', 'space-top'], 5536 component: BaseController.new('molecules-button', { 5537 mod: ['block', 'primary'], 5538 button: { 5539 text: __('set-password.submit'), 5540 hook: this.createHook('create-account'), 5541 name: 'create-account' 5542 } 5543 }) 5544 }, 5545 { 5546 mod: ['footer'], 5547 component: [ 5548 BaseController.new('atoms-info~have-account'), 5549 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin')
5550 ].filter(Boolean) 5551 } 5552 ].filter(Boolean) 5553 }); 5554}; 5555 5556module.exports = TemplatesCard_SetPassword; 5557 5558},{"../../atoms/addon/addon":49,"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],116:[function(require,module,exports){ 5559"use strict"; 5560var BaseModel = require('BaseModel'); 5561var BaseController = require('BaseController'); 5562var TemplatesCard = require('./card.js'); 5563var TemplatesCard_SignInGuest = BaseController.create('TemplatesCard_SignInGuest', TemplatesCard); 5564var Hash = require('@icewarp/hash'); 5565var domainRegEx = /^(((?!-))(xn--|_)?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9][a-z0-9-]{0,60}|[a-z0-9-]{1,30}\.[a-z]{2,})$/; 5566 5567TemplatesCard_SignInGuest.prototype.addListeners = function () { 5568 TemplatesCard.prototype.addListeners.call(this); 5569 this.addHookListener('validate-email', 'click', this.submitForm); 5570}; 5571 5572TemplatesCard_SignInGuest.prototype.validateForm = function () { 5573 this.validate(function (isValid) { 5574 var Login = BaseModel.instance('Login'); 5575 var email = this.hook('email').value.toLowerCase(); 5576 var domain = email.indexOf('@') ? email.split('@').pop() : '..'; 5577 5578 if (!isValid) { 5579 return; 5580 } 5581 5582 if (domain && !domainRegEx.test(domain)) { 5583 return setTimeout(function() { 5584 this.genericError('invalid_domain'); 5585 }.bind(this), 5); 5586 } 5587 5588 Login.isGuestDomain(domain, { 5589 success: function(response) { 5590 if (response) { 5591 Login.setData('chosen_account', { 5592 email: email, 5593 guestLogin: true 5594 }); 5595 BaseModel.instance('Login').guestLogin({ 5596 email: email 5597 }); 5598 } else { 5599 Login.setData('chosen_account', { 5600 email: email 5601 }); 5602 this.changeCard({ card: 'sign-in-password', hashData: Hash.getParts(), data: { back: true }}); 5603 } 5604 }, 5605 context: this 5606 }); 5607 }.bind(this)); 5608}; 5609 5610TemplatesCard_SignInGuest.prototype.helper = function () { 5611 var Login = BaseModel.instance('Login'); 5612 var WebClient = BaseModel.instance('WebClient'); 5613 5614 this.data.back = true; 5615 return TemplatesCard.prototype.helper.call(this, { 5616 hook: this.createHook('form'), 5617 content: [ 5618 { 5619 mod: [], 5620 component: BaseController.new('organisms-card-header', { 5621 heading: __('sign-in.sign-in-as-guest'), 5622 subtitle: { 5623 text: __('sign-in.guest-helper', { 5624 title: WebClient.getData('layout_settings').getValue('title') || 'IceWarp' 5625 }), 5626 class_name: ['o-header__subsubtitle'], 5627 mod: ['normal'] 5628 }, 5629 subsubtitle: false, 5630 avatar: false, 5631 well: this.data.well 5632 }) 5633 }, 5634 { 5635 mod: ['form'], 5636 component: BaseController.new('molecules-input~validatable', { 5637 input: { 5638 type: 'email', 5639 name: 'email-address', 5640 hook: this.createHook('email'), 5641 value: '' 5642 }, 5643 label: { 5644 text: __('generic.email') 5645 }, 5646 rules: [{ 5647 name: 'empty', 5648 message: __('validation.empty') 5649 }, { 5650 name: 'email', 5651 message: __('validation.email') 5652 }] 5653 }) 5654 }, 5655 { 5656 mod: ['default', 'space-bottom'], 5657 component: BaseController.new('molecules-button', { 5658 mod: ['block', 'primary'], 5659 button: { 5660 hook: this.createHook('validate-email'), 5661 text: __('generic.continue'), 5662 name: 'next' 5663 } 5664 }) 5665 }, 5666 { 5667 mod: ['footer'], 5668 component: [ 5669 Login.getUsers().length ? BaseController.new('atoms-info~choose-account') : BaseController.new('atoms-info~have-account'), 5670 WebClient.getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 5671 ].filter(Boolean) 5672 }, 5673 ].filter(Boolean) 5674 }); 5675}; 5676 5677module.exports = TemplatesCard_SignInGuest; 5678 5679},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],117:[function(require,module,exports){ 5680"use strict"; 5681var BaseModel = require('BaseModel'); 5682var BaseController = require('BaseController'); 5683var TemplatesCard = require('./card.js'); 5684var TemplatesCard_SignInPassword = BaseController.create('TemplatesCard_SignInPassword', TemplatesCard); 5685var QueryParams = require('@icewarp/query-params'); 5686var MobileDetect = require('mobile-detect'); 5687var Hash = require('@icewarp/hash'); 5688 5689TemplatesCard_SignInPassword.prototype.loginOauth = function (password) { 5690 var Login = BaseModel.instance('Login'); 5691 var OAuth = BaseModel.instance('OAuth'); 5692 OAuth.login(Login.getData('chosen_account').email, password, Login.getData('useRSA'), { 5693 success: function () { 5694 this.changeCard({ 5695 card: 'oauth-grant', 5696 hashData: Hash.getParts() 5697 }); 5698 }, 5699 error: function (error) { 5700 this.genericError(error); 5701 }, 5702 context: this 5703 }); 5704}; 5705 5706TemplatesCard_SignInPassword.prototype.loginApp = function (response) { 5707 var WebClient = BaseModel.instance('WebClient'); 5708 var Login = BaseModel.instance('Login'); 5709 var i, ctz; 5710 var params = QueryParams.parse(); 5711 var hash_parts = Hash.getParts(); 5712 var user_interface = this.getUserInterface(); 5713 5714 this.submitted = true; 5715 for (i in hash_parts) { 5716 params[i] = hash_parts[i];
5717 } 5718 params.atoken = response.authtoken; 5719 params.language = WebClient.getData('layout_settings').getUserLanguageCode(); 5720 params.remember = this.getPersistentLoginValue(); 5721 ctz = (new Date()).getTimezoneOffset(); 5722 params.ctz = ctz ? -ctz : 0; 5723 this.hook('username').value = Login.getData('chosen_account').email; 5724 5725 if (params.conference) { 5726 params.account = Login.getData('chosen_account'); 5727 return window.parent.postMessage(params, '*'); 5728 } 5729 5730 document.location.href = document.location.protocol + '//' + location.host + (location.pathname + (user_interface ? '/' + user_interface : '') + '/?' + QueryParams.stringify(params)).replace(/\/\//g, '/') + document.location.hash; 5731}; 5732 5733TemplatesCard_SignInPassword.prototype.loginError = function (error, response) { 5734 var phone; 5735 5736 if (!isNaN(response.query.error)) { 5737 phone = +response.query.error; 5738 } 5739 if (error === 'auth_digest_expired') { 5740 return this.validateForm(); 5741 } else if (error === 'auth_two_factor_required' || phone) { 5742 return this.changeCard({ 5743 card: 'two-factor', 5744 hashData: Hash.getParts(), 5745 data: { 5746 password: this.hook('password').value, 5747 persistentLogin: this.getPersistentLoginValue(), 5748 user_interface: this.getUserInterface(), 5749 well: { 5750 title: __('two_step.heading'), 5751 text: __('two_step.subheading' + (phone ? '-phone' : ''), { 5752 phone: phone 5753 }), 5754 type: 'info', 5755 class_name: ['is-visible'] 5756 } 5757 } 5758 }); 5759 } 5760 this.hook('password') && this.hook('password').removeAttribute('readonly'); 5761 this.genericError(error); 5762}; 5763 5764TemplatesCard_SignInPassword.prototype.getPersistentLoginValue = function () { 5765 var WebClient = BaseModel.instance('WebClient'); 5766 return (Hash.getParts().auth_id || WebClient.getData('restrictions').getValue('disable_remember')) ? 0 : +this.hook('persistentlogin').checked; 5767}; 5768 5769TemplatesCard_SignInPassword.prototype.getUserInterface = function () { 5770 var user_interface = this.hook('user_interface') && this.hook('user_interface').value; 5771 return (user_interface || '').replace('desktop', ''); 5772}; 5773 5774TemplatesCard_SignInPassword.prototype.addListeners = function () { 5775 TemplatesCard.prototype.addListeners.call(this); 5776 this.addDelegatedHookListener('forgot-password', 'click', function() { 5777 var Login = BaseModel.instance('Login'); 5778 if (!Login.getData('chosen_account').email || Login.getData('chosen_account').email.indexOf('@') === -1) { 5779 return this.genericError('forgot-missing-domain', '', ' '); 5780 } 5781 this.changeCard({ 5782 card: 'forgot-password', 5783 data: { back: true } 5784 }); 5785 }.bind(this)); 5786 this.addHookListener('validate-password', 'click', this.submitForm); 5787}; 5788 5789TemplatesCard_SignInPassword.prototype.validateForm = function () { 5790 this.hook('password') && this.hook('password').setAttribute('readonly', ''); 5791 this.validate(function (isValid) { 5792 if (isValid) { 5793 BaseModel.instance('Login').getAuthChallenge({ 5794 success: this.authenticate, 5795 error: function (error) { 5796 this.genericError(error); 5797 }, 5798 context: this 5799 }); 5800 } else { 5801 this.hook('password') && this.hook('password').removeAttribute('readonly'); 5802 } 5803 }.bind(this)); 5804}; 5805 5806TemplatesCard_SignInPassword.prototype.authenticate = function (encrypt) { 5807 var password = encrypt(this.hook('password').value); 5808 var WebClient = BaseModel.instance('WebClient'); 5809 var Login = BaseModel.instance('Login'); 5810 5811 if (Hash.getParts().auth_id) { 5812 return this.loginOauth(password); 5813 } 5814 5815 WebClient.getAuthToken({ 5816 email: Login.getData('chosen_account').email, 5817 password: password, 5818 persistentlogin: this.getPersistentLoginValue() 5819 }, { 5820 success: this.loginApp, 5821 error: this.loginError, 5822 context: this 5823 }); 5824}; 5825 5826TemplatesCard_SignInPassword.prototype.helper = function () { 5827 var config = BaseModel.instance('Config').getData('config'); 5828 var WebClient = BaseModel.instance('WebClient'); 5829 var Login = BaseModel.instance('Login'); 5830 5831 var md = new MobileDetect(window.navigator.userAgent); 5832 var interfaces = WebClient.getData('layout_settings').getValue('interfaces') || ''; 5833 var params = QueryParams.parse(); 5834 5835 interfaces = [ 5836 (!interfaces || ~interfaces.indexOf('a')) && { 5837 selected: md.tablet() && md.mobileGrade() === 'A', 5838 text: __('interface.desktop'),
5839 value: 'desktop' 5840 }, 5841 (!interfaces || ~interfaces.indexOf('b')) && { 5842 selected: md.tablet() && md.mobileGrade() !== 'A', 5843 text: __('interface.tablet'), 5844 value: 'basic' 5845 }, 5846 ((params.interface === 'pda') && (!interfaces || ~interfaces.indexOf('p'))) && { 5847 selected: params.interface === 'pda', 5848 text: __('interface.phone'), 5849 value: 'pda' 5850 } 5851 ].filter(Boolean); 5852 5853 return new Promise(function(resolve) { 5854 var remember = !(Hash.getParts().auth_id || WebClient.getData('restrictions').getValue('disable_remember')); 5855 5856 resolve(TemplatesCard.prototype.helper.call(this, { 5857 hook: this.createHook('form'), 5858 content: [ 5859 { 5860 mod: [], 5861 component: BaseController.new('organisms-card-header', { 5862 heading: __('sign-in-generic.heading.' + (params.conference ? 'conference' : config.application)), 5863 well: this.data.well 5864 }) 5865 }, 5866 { 5867 class_name: ['u-hide'], 5868 component: BaseController.new('molecules-input', { 5869 input: { 5870 type: 'text', 5871 name: 'username', 5872 hook: this.createHook('username'), 5873 value: Login.getData('chosen_account').email, 5874 autocomplete: 'username' 5875 } 5876 }) 5877 }, 5878 { 5879 mod: ['form'], 5880 component: BaseController.new('molecules-input~password', { 5881 input: { 5882 name: 'password', 5883 hook: this.createHook('password'), 5884 maxlength: 240, 5885 autocomplete: 'current-password' 5886 }, 5887 label: { 5888 text: __('generic.password') 5889 }, 5890 rules: [{ 5891 name: 'empty', 5892 message: __('validation.empty') 5893 }, 5894 { 5895 name: 'min_length', 5896 data: 1, 5897 message: __('validation.min_length', 1) 5898 } 5899 ], 5900 addon: [ 5901 BaseController.new('atoms-addon~show'), 5902 WebClient.getData('reset_settings').getValue('enabled') && { 5903 text: __('sign-in-password.forgot'), 5904 hook: this.createHook('forgot-password'), 5905 mod: ['floating'] 5906 } 5907 ].filter(Boolean) 5908 }) 5909 }, 5910 (config.application === 'webclient' && (md.mobile() || params.mobile)) ? { 5911 mod: ['form'], 5912 5913 class_name: interfaces.length > 1 ? [] : ['u-hide'], 5914 component: BaseController.new('molecules-select', { 5915 select: { 5916 name: 'user_interface', 5917 hook: this.createHook('user_interface'), 5918 options: interfaces 5919 }, 5920 label: { 5921 text: __('interface.label') 5922 } 5923 }) 5924 } : false, 5925 remember && { 5926 mod: ['form'], 5927 component: BaseController.new('molecules-checkbox', { 5928 label: __('sign-in-password.remember'), 5929 input: { 5930 name: 'remember-me', 5931 hook: this.createHook('persistentlogin') 5932 } 5933 }) 5934 }, 5935 { 5936 mod: ['default', 'space-bottom'], 5937 component: BaseController.new('molecules-button', { 5938 mod: ['block', 'primary'], 5939 button: { 5940 hook: this.createHook('validate-password'), 5941 text: __('generic.sign-in'), 5942 name: 'next' 5943 } 5944 }) 5945 }, 5946 WebClient.getData('restrictions').getValue('show_search') && { 5947 mod: ['form'], 5948 component: BaseController.new('molecules-input~search', { 5949 input: { 5950 name: 'search' 5951 }, 5952 label: { 5953 text: __('generic.search') 5954 } 5955 }) 5956 }, 5957 { 5958 mod: ['footer'], 5959 component: [ 5960 BaseController.new('atoms-info~not-you'), 5961 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 5962 ].filter(Boolean) 5963 } 5964 ].filter(Boolean) 5965 5966 })); 5967 }.bind(this)); 5968 5969}; 5970 5971module.exports = TemplatesCard_SignInPassword; 5972 5973},{"./card.js":99,"@icewarp/hash":160,"@icewarp/query-params":170,"BaseController":"BaseController","BaseModel":"BaseModel","mobile-detect":364}],118:[function(require,module,exports){ 5974"use strict"; 5975var BaseModel = require('BaseModel'); 5976var BaseController = require('BaseController'); 5977var TemplatesCard = require('./card.js'); 5978var TemplatesCard_SignIn = BaseController.create('TemplatesCard_SignIn', TemplatesCard); 5979var Hash = require('@icewarp/hash'); 5980var domainRegEx = /^(((?!-))(xn--|_)?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9][a-z0-9-]{0,60}|[a-z0-9-]{1,30}\.[a-z]{2,})$/; 5981 5982TemplatesCard_SignIn.prototype.addListeners = function () { 5983 TemplatesCard.prototype.addListeners.call(this); 5984 this.addHookListener('validate-email', 'click', this.submitForm); 5985 this.addHookListener('apple', 'click', this.signInAsGuest, { service_provider: 'apple' }); 5986 this.addHookListener('google', 'click', this.signInAsGuest, { service_provider: 'google' }); 5987 this.addHookListener('microsoft', 'click', this.signInAsGuest, { service_provider: 'microsoft' }); 5988 this.addHookListener('mail', 'click', this.signInAsGuestWithEmail, {}, true); 5989}; 5990 5991TemplatesCard_SignIn.prototype.validateForm = function () { 5992 this.validate(function (isValid) { 5993 var Login = BaseModel.instance('Login'); 5994 var email = this.hook('email').value.toLowerCase(); 5995 var domain = ~email.indexOf('@') ? email.split('@').pop() : false; 5996 5997 if (!isValid) { 5998 return; 5999 } 6000 6001 if (domain && !domainRegEx.test(domain)) { 6002 return setTimeout(function() { 6003 this.genericError('invalid_domain'); 6004 }.bind(this), 5); 6005 } 6006 6007 Login.setData('chosen_account', { 6008 email: email 6009 }); 6010 this.changeCard({ card: 'sign-in-password', hashData: Hash.getParts(), data: { back: true }}
6010); 6011 }.bind(this)); 6012}; 6013 6014TemplatesCard_SignIn.prototype.signInAsGuest = function(e, data) { 6015 BaseModel.instance('Login').guestLogin(data); 6016}; 6017 6018TemplatesCard_SignIn.prototype.signInAsGuestWithEmail = function() { 6019 this.changeCard({ card: 'sign-in-guest', hashData: Hash.getParts(), data: { back: true }}); 6020}; 6021 6022TemplatesCard_SignIn.prototype.helper = function () { 6023 var config = BaseModel.instance('Config').getData('config'); 6024 var WebClient = BaseModel.instance('WebClient'); 6025 var Server = BaseModel.instance('Server'); 6026 var Login = BaseModel.instance('Login'); 6027 var guest_signin = config.application === 'webclient' && !WebClient.getData('restrictions').getValue('disable_guest_signin'); 6028 6029 this.data.back = true; 6030 6031 return TemplatesCard.prototype.helper.call(this, { 6032 hook: this.createHook('form'), 6033 content: [ 6034 { 6035 mod: [], 6036 component: BaseController.new('organisms-card-header', { 6037 heading: __('sign-in-generic.heading.' + config.application), 6038 subtitle: { 6039 text: __('sign-in.subtitle', { 6040 title: WebClient.getData('layout_settings').getValue('title') || 'IceWarp' 6041 }), 6042 class_name: ['o-header__subsubtitle'], 6043 mod: ['normal'] 6044 }, 6045 subsubtitle: false, 6046 avatar: false, 6047 well: this.data.well 6048 }) 6049 }, 6050 { 6051 mod: ['form'], 6052 component: BaseController.new('molecules-input~validatable', { 6053 input: { 6054 type: 'email', 6055 name: 'email-address', 6056 hook: this.createHook('email'), 6057 value: Login.getData('chosen_account').email || Hash.getParts().email || Hash.getParts().username 6058 }, 6059 label: { 6060 text: (+Server.getData('c_accounts_policies_login_loginsettings') || Login.getData('guestLogin')) ? __('generic.email') : __('generic.username') 6061 }, 6062 rules: [ 6063 { 6064 name: 'empty', 6065 message: __('validation.empty') 6066 }, 6067 +Server.getData('c_accounts_policies_login_loginsettings') ? { 6068 name: 'email', 6069 message: __('validation.email') 6070 } : false 6071 ].filter(Boolean) 6072 }) 6073 }, 6074 { 6075 mod: ['default', 'space-bottom'], 6076 component: BaseController.new('molecules-button', { 6077 mod: ['block', 'primary'], 6078 button: { 6079 hook: this.createHook('validate-email'), 6080 text: __('generic.continue'), 6081 name: 'next' 6082 } 6083 }) 6084 }, 6085 WebClient.getData('restrictions').getValue('show_search') && { 6086 mod: ['form'], 6087 component: BaseController.new('molecules-input~search', { 6088 input: { 6089 name: 'search' 6090 }, 6091 label: { 6092 text: __('generic.search') 6093 } 6094 }) 6095 }, 6096 { 6097 mod: ['footer', 'form'], 6098 component: [ 6099 (!WebClient.getData('restrictions').getValue('disable_signup') && !WebClient.getData('restrictions').getValue('disable_signup_ip')) && BaseController.new('atoms-info~dont-have-account'), 6100 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 6101 ].filter(Boolean) 6102 }, 6103 guest_signin && { 6104 mod: ['separator', 'form'], 6105 component: BaseController.new('atoms-label', { 6106 text: __('sign-in.sign-in-as-guest'), 6107 }) 6108 }, 6109 guest_signin && { 6110 mod: ['form'], 6111 component: BaseController.new('atoms-label', { 6112 text: __('sign-in.guest-helper', { 6113 title: WebClient.getData('layout_settings').getValue('title') || 'IceWarp' 6114 }), 6115 }) 6116 }, 6117 guest_signin && { 6118 mod: ['default', 'sideBySide'], 6119 component: [ 6120 BaseController.new('molecules-button', { 6121 mod: ['block', 'dark', 'icon', 'wide', 'service'], 6122 button: { 6123 hook: this.createHook('apple'), 6124 name: 'apple', 6125 icon: 'apple' 6126 } 6127 }), 6128 BaseController.new('molecules-button', { 6129 mod: ['block', 'dark', 'icon', 'wide', 'service'], 6130 button: { 6131 hook: this.createHook('google'), 6132 name: 'google', 6133 icon: 'google' 6134 } 6135 }), 6136 BaseController.new('molecules-button', { 6137 mod: ['block', 'dark', 'icon', 'wide', 'service'], 6138 button: { 6139 hook: this.createHook('microsoft'), 6140 name: 'microsoft', 6141 icon: 'microsoft' 6142 } 6143 }), 6144 BaseController.new('molecules-button', { 6145 mod: ['block', 'dark', 'icon', 'wide', 'service'], 6146 button: { 6147 hook: this.createHook('mail'), 6148 name: 'mail', 6149 icon: 'email' 6150 } 6151 }) 6152 ] 6153 }
6154 ].filter(Boolean) 6155 }); 6156}; 6157 6158module.exports = TemplatesCard_SignIn; 6159 6160},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],119:[function(require,module,exports){ 6161"use strict"; 6162var BaseController = require('BaseController'); 6163var TemplatesCard = require('./card.js'); 6164var TemplatesCard_TcActions = BaseController.create('TemplatesCard_TcActions', TemplatesCard); 6165var Hash = require('@icewarp/hash'); 6166 6167TemplatesCard_TcActions.prototype.addListeners = function () { 6168 var hash_data = Hash.getParts(); 6169 TemplatesCard.prototype.addListeners.call(this); 6170 this.addHookListener('next', 'click', this.changeCard, {card: hash_data.return || 'tc-join', hashData: hash_data}); 6171 this.addHookListener('skip', 'click', this.changeCard, {card: hash_data.return || 'tc-join', hashData: hash_data}); 6172}; 6173 6174TemplatesCard_TcActions.prototype.helper = function () { 6175 return TemplatesCard.prototype.helper.call(this, { 6176 content: [ 6177 { 6178 mod: [], 6179 component: BaseController.new('organisms-card-header', { 6180 'card-icon': BaseController.new('atoms-icons', { 6181 icon: 'teamchat' 6182 }), 6183 heading: __('tc-actions.heading'), 6184 subtitle: { 6185 text: __('tc-actions.subheading') 6186 }, 6187 well: this.data.well 6188 }) 6189 }, 6190 { 6191 mod: ['form', 'no-padding'], 6192 component: BaseController.new('AtomsImage', { 6193 class_name: ['u-margin-auto'], 6194 src: './images/teamchat/actions.png' 6195 }) 6196 }, 6197 { 6198 mod: ['default', 'space-top'], 6199 component: [ 6200 BaseController.new('molecules-button', { 6201 mod: ['primary', 'inverted', 'flex'], 6202 button: { 6203 text: __('generic.skip'), 6204 name: 'skip', 6205 hook: this.createHook('skip') 6206 } 6207 }), 6208 BaseController.new('molecules-button', { 6209 mod: ['primary', 'flex'], 6210 button: { 6211 text: __('generic.next'), 6212 name: 'next', 6213 hook: this.createHook('next') 6214 } 6215 }) 6216 ] 6217 }
6218 ].filter(Boolean) 6219 }); 6220}; 6221 6222module.exports = TemplatesCard_TcActions; 6223 6224},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController"}],120:[function(require,module,exports){ 6225"use strict"; 6226var BaseModel = require('BaseModel'); 6227var BaseController = require('BaseController'); 6228var TemplatesCard = require('./card.js'); 6229var TemplatesCard_TcCheckEmail = BaseController.create('TemplatesCard_TcCheckEmail', TemplatesCard); 6230var Hash = require('@icewarp/hash'); 6231 6232TemplatesCard_TcCheckEmail.prototype.addListeners = function () { 6233 TemplatesCard.prototype.addListeners.call(this); 6234 this.addHookListener('what-is-teamchat', 'click', this.changeCard, {card: 'tc-collaboration', hashData: Hash.getParts(), keepHashData: true}); 6235}; 6236 6237TemplatesCard_TcCheckEmail.prototype.helper = function () { 6238 return TemplatesCard.prototype.helper.call(this, { 6239 content: [ 6240 { 6241 mod: [], 6242 component: BaseController.new('organisms-card-header', { 6243 'card-icon': BaseController.new('atoms-icons', { 6244 icon: 'teamchat' 6245 }), 6246 avatar: false, 6247 heading: __('tc-check-email.heading'), 6248 subtitle: { 6249 text: __('tc-check-email.subheading', {md: true, room: this.data.room || (Hash.getParts().room || '').replace(/\+/g, ' ')}), 6250 class_name: 'o-header__subtitle' 6251 }, 6252 subsubtitle: false, 6253 well: this.data.well 6254 }) 6255 }, 6256 { 6257 mod: ['footer', 'space-top'], 6258 component: [ 6259 BaseController.new('atoms-link~what-is-teamchat'), 6260 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 6261 ].filter(Boolean) 6262 } 6263 ].filter(Boolean) 6264 }); 6265}; 6266 6267module.exports = TemplatesCard_TcCheckEmail; 6268 6269},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],121:[function(require,module,exports){ 6270"use strict"; 6271var BaseController = require('BaseController'); 6272var TemplatesCard = require('./card.js'); 6273var TemplatesCard_TcCollaboration = BaseController.create('TemplatesCard_TcCollaboration', TemplatesCard); 6274var Hash = require('@icewarp/hash'); 6275 6276TemplatesCard_TcCollaboration.prototype.addListeners = function () { 6277 var hash_data = Hash.getParts(); 6278 TemplatesCard.prototype.addListeners.call(this); 6279 this.addHookListener('next', 'click', this.changeCard, {card: 'tc-share', hashData: hash_data}); 6280 this.addHookListener('skip', 'click', this.changeCard, {card: hash_data.return || 'tc-join', hashData: hash_data}); 6281}; 6282 6283TemplatesCard_TcCollaboration.prototype.helper = function () { 6284 return TemplatesCard.prototype.helper.call(this, { 6285 content: [ 6286 { 6287 mod: [], 6288 component: BaseController.new('organisms-card-header', { 6289 'card-icon': BaseController.new('atoms-icons', { 6290 icon: 'teamchat' 6291 }), 6292 heading: __('tc-collaboration.heading'), 6293 subtitle: { 6294 text: __('tc-collaboration.subheading') 6295 }, 6296 well: this.data.well 6297 }) 6298 }, 6299 { 6300 mod: ['form', 'no-padding'], 6301 component: BaseController.new('AtomsImage', { 6302 class_name: ['u-margin-auto'], 6303 src: './images/teamchat/collaboration.png' 6304 }) 6305 }, 6306 { 6307 mod: ['default', 'space-top'], 6308 component: [ 6309 BaseController.new('molecules-button', { 6310 mod: ['primary', 'inverted', 'flex'], 6311 button: { 6312 text: __('generic.skip'), 6313 name: 'skip', 6314 hook: this.createHook('skip') 6315 } 6316 }), 6317 BaseController.new('molecules-button', { 6318 mod: ['primary', 'flex'], 6319 button: { 6320 text: __('generic.next'), 6321 name: 'next', 6322 hook: this.createHook('next') 6323 } 6324 }) 6325 ] 6326 }
6327 ].filter(Boolean) 6328 }); 6329}; 6330 6331module.exports = TemplatesCard_TcCollaboration; 6332 6333},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController"}],122:[function(require,module,exports){ 6334"use strict"; 6335var BaseModel = require('BaseModel'); 6336var BaseController = require('BaseController'); 6337var TemplatesCard = require('./card.js'); 6338var TemplatesCard_TcJoin = BaseController.create('TemplatesCard_TcJoin', TemplatesCard); 6339var Hash = require('@icewarp/hash'); 6340 6341TemplatesCard_TcJoin.prototype.addListeners = function () { 6342 TemplatesCard.prototype.addListeners.call(this); 6343 this.addHookListener('verify-email', 'click', this.validateForm); 6344 this.addHookListener('what-is-teamchat', 'click', this.changeCard, { card: 'tc-collaboration', hashData: Hash.getParts(), keepHashData: true }); 6345}; 6346 6347TemplatesCard_TcJoin.prototype.validateForm = function () { 6348 this.validate(function (isValid) { 6349 if (isValid) { 6350 BaseModel.instance('Login').getAuthChallenge({ 6351 success: this.guestConfirm, 6352 error: function (error) { 6353 this.genericError(error); 6354 }, 6355 context: this 6356 }); 6357 } 6358 6359 }.bind(this)); 6360}; 6361 6362TemplatesCard_TcJoin.prototype.guestConfirm = function (encrypt) { 6363 var hash_parts = Hash.getParts(); 6364 hash_parts.room = (hash_parts.room || '').replace(/\+/g, ' '); 6365 BaseModel.instance('WebClient').guestConfirm({ 6366 password: encrypt(this.hook('password').value), 6367 fullname: this.hook('username').value, 6368 email: hash_parts.email, 6369 sender: hash_parts.sender, 6370 hash: hash_parts.hash 6371 }, { 6372 success: function () { 6373 this.changeCard({ 6374 data: { 6375 well: { 6376 title: __('generic.success'), 6377 text: __('tc-join.success-message', { room: hash_parts.room }), 6378 type: 'success', 6379 class_name: ['is-visible'] 6380 }, 6381 room: hash_parts.room 6382 }, 6383 card: 'tc-check-email', 6384 hashData: { 6385 room: hash_parts.room, 6386 return: 'tc-check-email' 6387 } 6388 }); 6389 }, 6390 error: function (error) { 6391 this.genericError(error); 6392 }, 6393 context: this 6394 }); 6395}; 6396 6397TemplatesCard_TcJoin.prototype.helper = function () { 6398 var hash_parts = Hash.getParts(); 6399 hash_parts.room = (hash_parts.room || '').replace(/\+/g, ' '); 6400 return TemplatesCard.prototype.helper.call(this, { 6401 hook: this.createHook('form'), 6402 content: [ 6403 { 6404 mod: [], 6405 component: BaseController.new('organisms-card-header', { 6406 'card-icon': BaseController.new('atoms-icons', { 6407 icon: 'teamchat' 6408 }), 6409 avatar: false, 6410 heading: __('tc-join.heading'), 6411 subtitle: { 6412 text: __('tc-join.subheading', { name: (hash_parts.sendername || '').replace(/\+/g, ' ') || hash_parts.sender, room: hash_parts.room, md: true }) 6413 }, 6414 subsubtitle: false, 6415 well: this.data.well 6416 }) 6417 }, 6418 { 6419 mod: ['form'], 6420 component: BaseController.new('molecules-input~validatable', { 6421 input: { 6422 type: 'text', 6423 name: 'username', 6424 hook: this.createHook('username') 6425 }, 6426 label: { 6427 text: __('tc-join.username') 6428 }, 6429 rules: [ 6430 { 6431 name: 'empty', 6432 message: __('validation.empty') 6433 } 6434 ], 6435 tooltip_well: { 6436 title: __('tc-join.username-helper'), 6437 type: 'primary' 6438 } 6439 }) 6440 }, 6441 { 6442 mod: ['form'], 6443 component: BaseController.new('molecules-input~password-with-policy', { 6444 input: { 6445 name: 'password', 6446 hook: this.createHook('password'), 6447 autocomplete: 'new-password' 6448 }, 6449 label: { 6450 text: __('generic.password-new') 6451 }, 6452 addon: BaseController.new('atoms-addon~show') 6453 }) 6454 }, 6455 { 6456 mod: ['form'], 6457 component: BaseController.new('molecules-input~password', { 6458 input: { 6459 name: 'confirm-password' 6460 }, 6461 label: { 6462 text: __('generic.password-confirm') 6463 }, 6464 addon: BaseController.new('atoms-addon~show'), 6465 rules: [ 6466 { 6467 name: 'empty', 6468 message: __('validation.empty') 6469 }, 6470 { 6471 name: 'same', 6472 controller: this, 6473 parent_hook: 'form', 6474 counterpart_hook: 'password', 6475 message: __('validation.passwords-no-match') 6476 } 6477 ] 6478 }) 6479 }, 6480 { 6481 mod: ['default', 'space-top'], 6482 component: BaseController.new('molecules-button', { 6483 mod: ['block', 'primary'], 6484 button: { 6485 text: __('tc-join.submit'), 6486 name: 'verify-email', 6487 hook: this.createHook('verify-email') 6488 } 6489 }) 6490 }, 6491 { 6492 mod: ['footer'], 6493 component: BaseController.new('atoms-link~what-is-teamchat') 6494 }
6495 ].filter(Boolean) 6496 }); 6497}; 6498 6499module.exports = TemplatesCard_TcJoin; 6500 6501},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController","BaseModel":"BaseModel"}],123:[function(require,module,exports){ 6502"use strict"; 6503var BaseController = require('BaseController'); 6504var TemplatesCard = require('./card.js'); 6505var TemplatesCard_TcShare = BaseController.create('TemplatesCard_TcShare', TemplatesCard); 6506var Hash = require('@icewarp/hash'); 6507 6508TemplatesCard_TcShare.prototype.addListeners = function () { 6509 var hash_data = Hash.getParts(); 6510 TemplatesCard.prototype.addListeners.call(this); 6511 this.addHookListener('next', 'click', this.changeCard, {card: 'tc-actions', hashData: hash_data}); 6512 this.addHookListener('skip', 'click', this.changeCard, {card: hash_data.return || 'tc-join', hashData: hash_data}); 6513}; 6514 6515TemplatesCard_TcShare.prototype.helper = function () { 6516 return TemplatesCard.prototype.helper.call(this, { 6517 content: [ 6518 { 6519 mod: [], 6520 component: BaseController.new('organisms-card-header', { 6521 'card-icon': BaseController.new('atoms-icons', { 6522 icon: 'teamchat' 6523 }), 6524 heading: __('tc-share.heading'), 6525 subtitle: { 6526 text: __('tc-share.subheading') 6527 }, 6528 well: this.data.well 6529 }) 6530 }, 6531 { 6532 mod: ['form', 'no-padding'], 6533 component: BaseController.new('AtomsImage', { 6534 class_name: ['u-margin-auto'], 6535 src: './images/teamchat/share.png' 6536 }) 6537 }, 6538 { 6539 mod: ['default', 'space-top'], 6540 component: [ 6541 BaseController.new('molecules-button', { 6542 mod: ['primary', 'inverted', 'flex'], 6543 button: { 6544 text: __('generic.skip'), 6545 name: 'skip', 6546 hook: this.createHook('skip') 6547 } 6548 }), 6549 BaseController.new('molecules-button', { 6550 mod: ['primary', 'flex'], 6551 button: { 6552 text: __('generic.next'), 6553 name: 'next', 6554 hook: this.createHook('next') 6555 } 6556 }) 6557 ] 6558 }
6559 ].filter(Boolean) 6560 }); 6561}; 6562 6563module.exports = TemplatesCard_TcShare; 6564 6565},{"./card.js":99,"@icewarp/hash":160,"BaseController":"BaseController"}],124:[function(require,module,exports){ 6566"use strict"; 6567var BaseModel = require('BaseModel'); 6568var BaseController = require('BaseController'); 6569var TemplatesCard = require('./card.js'); 6570var TemplatesCard_TouchId = BaseController.create('TemplatesCard_TouchId', TemplatesCard); 6571 6572TemplatesCard_TouchId.prototype.addListeners = function () { 6573 TemplatesCard.prototype.addListeners.call(this); 6574}; 6575 6576TemplatesCard_TouchId.prototype.helper = function () { 6577 return TemplatesCard.prototype.helper.call(this, { 6578 content: [ 6579 { 6580 mod: [], 6581 component: BaseController.new('organisms-card-header', { 6582 heading: __('tc-touch-id.heading'), 6583 well: this.data.well 6584 }) 6585 }, 6586 { 6587 mod: ['form'], 6588 component: { _name: 'atoms-touch-id' } 6589 }, 6590 { 6591 mod: ['footer'], 6592 component: [ 6593 BaseController.new('atoms-link', { 6594 text: __('tc-touch-id.use-password'), 6595 mod: ['switch'], 6596 class_name: ['u-align-center'] 6597 }), 6598 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin') 6599 ].filter(Boolean) 6600 } 6601 ] 6602 }); 6603}; 6604 6605module.exports = TemplatesCard_TouchId; 6606 6607},{"./card.js":99,"BaseController":"BaseController","BaseModel":"BaseModel"}],125:[function(require,module,exports){ 6608"use strict"; 6609var BaseModel = require('BaseModel'); 6610var BaseController = require('BaseController'); 6611var TemplatesCard = require('./card'); 6612var TemplatesCard_SignInPassword = require('./card~sign-in-password'); 6613var TemplatesCard_TwoFactor = BaseController.create('TemplatesCard_TwoFactor', TemplatesCard_SignInPassword); 6614var QueryParams = require('@icewarp/query-params'); 6615var MobileDetect = require('mobile-detect'); 6616var Hash = require('@icewarp/hash'); 6617 6618TemplatesCard_TwoFactor.prototype.addListeners = function () { 6619 TemplatesCard_SignInPassword.prototype.addListeners.call(this); 6620 this.addHookListener('validate-totp', 'click', this.submitForm); 6621}; 6622 6623TemplatesCard_TwoFactor.prototype.authenticate = function (encrypt) { 6624 var password = encrypt(this.data.password); 6625 var WebClient = BaseModel.instance('WebClient'); 6626 var Login = BaseModel.instance('Login'); 6627 6628 if (Hash.getParts().auth_id) { 6629 return this.loginOauth(password); 6630 } 6631 6632 WebClient.getAuthToken({ 6633 email: Login.getData('chosen_account').email, 6634 password: password, 6635 persistentlogin: this.getPersistentLoginValue.call(this), 6636 totpcode: this.hook('totpcode').value 6637 }, { 6638 success: this.loginApp, 6639 error: function(error) { 6640 if (error === 'auth_digest_expired') { 6641 return this.validateForm(); 6642 } 6643 6644 this.genericError(error); 6645 }, 6646 context: this 6647 }); 6648}; 6649 6650TemplatesCard_TwoFactor.prototype.helper = function () { 6651 var config = BaseModel.instance('Config').getData('config'); 6652 var WebClient = BaseModel.instance('WebClient'); 6653 var Login = BaseModel.instance('Login'); 6654 6655 var md = new MobileDetect(window.navigator.userAgent); 6656 var interfaces = WebClient.getData('layout_settings').getValue('interfaces') || ''; 6657 var params = QueryParams.parse(); 6658 6659 interfaces = [ 6660 (!interfaces || ~interfaces.indexOf('a')) ? { 6661 selected: md.tablet() && md.mobileGrade() === 'A', 6662 text: __('interface.desktop'), 6663 value: 'desktop' 6664 } : false, 6665 (!interfaces || ~interfaces.indexOf('b')) ? { 6666 selected: md.tablet() && md.mobileGrade() !== 'A', 6667 text: __('interface.tablet'), 6668 value: 'basic' 6669 } : false, 6670 ((params.interface === 'pda') && (!interfaces || ~interfaces.indexOf('p'))) ? { 6671 selected: params.interface === 'pda', 6672 text: __('interface.phone'), 6673 value: 'pda' 6674 } : false 6675 ].filter(Boolean); 6676 6677 return TemplatesCard.prototype.helper.call(this, { 6678 password: this.data.password, 6679 hook: this.createHook('form'), 6680 content: [ 6681 { 6682 mod: [], 6683 component: BaseController.new('organisms-card-header', { 6684 heading: __('sign-in-generic.heading.' + config.application), 6685 well: this.data.well 6686 }) 6687 }, 6688 { 6689 class_name: ['u-hide'], 6690 component: BaseController.new('molecules-input', { 6691 input: { 6692 type: 'text', 6693 name: 'username', 6694 hook: this.createHook('username'), 6695 value: Login.getData('chosen_account').email 6696 } 6697 }) 6698 }, 6699 { 6700 mod: ['form'], 6701 component: BaseController.new('molecules-input~validatable', { 6702 input: { 6703 name: 'totpcode', 6704 type: 'number', 6705 hook: this.createHook('totpcode'), 6706 maxlength: 6, 6707 autocomplete: 'off' 6708 }, 6709 label: { 6710 text: __('two_step.verification_code') 6711 }, 6712 rules: [ 6713 { 6714 name: 'length', 6715 data: 6, 6716 message: __('validation.length', 6) 6717 } 6718 ] 6719 }) 6720 }, 6721 !WebClient.getData('restrictions').getValue('disable_remember') && { 6722 mod: ['form'], 6723 component: BaseController.new('molecules-checkbox', { 6724 label: __('sign-in-password.remember'), 6725 input: { 6726 name: 'remember-me', 6727 checked: this.data.persistentLogin, 6728 hook: this.createHook('persistentlogin') 6729 } 6730 }) 6731 }, 6732 (config.application === 'webclient' && (md.mobile() || QueryParams.parse().mobile)) && { 6733 mod: ['form'], 6734 class_name: interfaces.length > 1 ? [] : ['u-hide'], 6735 component: BaseController.new('molecules-select', { 6736 select: { 6737 name: 'user_interface', 6738 hook: this.createHook('user_interface'), 6739 options: interfaces 6740 }, 6741 label: { 6742 text: __('interface.label') 6743 } 6744 }) 6745 }, 6746 { 6747 mod: ['default', 'space-top'], 6748 component: BaseController.new('molecules-button', { 6749 mod: ['block', 'primary'], 6750 button: { 6751 hook: this.createHook('validate-totp'), 6752 text: __('generic.sign-in'), 6753 name: 'next' 6754 } 6755 }) 6756 }, 6757 WebClient.getData('restrictions').getValue('show_search') && { 6758 mod: ['form'], 6759 component: BaseController.new('molecules-input~search', { 6760 input: { 6761 name: 'search' 6762 }, 6763 label: { 6764 text: __('generic.search') 6765 } 6766 }) 6767 }, 6768 { 6769 mod: ['footer'], 6770 component: [ 6771 BaseController.new('atoms-info~not-you'), 6772 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin')
6773 ].filter(Boolean) 6774 } 6775 ].filter(Boolean) 6776 }); 6777 6778}; 6779 6780module.exports = TemplatesCard_TwoFactor; 6781 6782},{"./card":99,"./card~sign-in-password":117,"@icewarp/hash":160,"@icewarp/query-params":170,"BaseController":"BaseController","BaseModel":"BaseModel","mobile-detect":364}],126:[function(require,module,exports){ 6783"use strict"; 6784var BaseModel = require('BaseModel'); 6785var BaseController = require('BaseController'); 6786var TemplatesCard_GenericMessage = require('./card~generic-message.js'); 6787var TemplatesCard_Unavailable = BaseController.create('TemplatesCard_Unavailable', TemplatesCard_GenericMessage); 6788 6789TemplatesCard_Unavailable.prototype.addListeners = function () { 6790 TemplatesCard_GenericMessage.prototype.addListeners.call(this); 6791}; 6792 6793TemplatesCard_Unavailable.prototype.helper = function () { 6794 this.data.title = this.data.title || __('error.unavailable'); 6795 this.data.type = this.data.type || 'error'; 6796 this.data.footer = { 6797 mod: ['footer'], 6798 component: [ 6799 BaseController.new('atoms-link~retry', { 6800 link: this.data.retry_link 6801 }), 6802 BaseModel.instance('WebClient').getData('restrictions').getValue('contact_support') && BaseController.new('atoms-info~contact-admin')
6803 ].filter(Boolean) 6804 }; 6805 return TemplatesCard_GenericMessage.prototype.helper.call(this); 6806}; 6807 6808module.exports = TemplatesCard_Unavailable; 6809 6810},{"./card~generic-message.js":107,"BaseController":"BaseController","BaseModel":"BaseModel"}],127:[function(require,module,exports){ 6811"use strict"; 6812var BaseController = require('BaseController'); 6813var Validatable = BaseController.create('Validatable'); 6814var BaseModel = require('BaseModel'); 6815var Validator = BaseModel.instance('Validator'); 6816 6817Validatable.prototype.addListeners = function () { 6818 this.addDelegatedHookListener('tooltip', 'click', this.showMessage); 6819}; 6820 6821Validatable.prototype.validate = function (event, callback) { 6822 var target = event && event.target ? event.target : this.select('input, textarea, select'), 6823 rules = (this.data.rules || []).slice(); 6824 6825 callback = callback instanceof Function ? callback : false, 6826 6827 this.trigger('error-message-hide'); 6828 6829 /** 6830 * @returns {Boolean} 6831 */ 6832 function validate() { 6833 var rule = rules.shift(); 6834 6835 if (rule) { 6836 if (!Validator[rule.name]) { 6837 console.error('missing validation', rule.name); 6838 return validate.call(this); 6839 } 6840 rule.controller = this; 6841 Validator[rule.name](rule, target.value, function(isValid) { 6842 if (!isValid) { 6843 this.trigger('validation-error', rule); 6844 this.DOMElement.classList.add('has-error'); 6845 callback && callback(false); 6846 } else { 6847 validate.call(this); 6848 } 6849 }.bind(this)); 6850 } else { 6851 this.trigger('validation-success', { 6852 controller: this 6853 }); 6854 this.DOMElement.classList.remove('has-error'); 6855 callback && callback(true); 6856 } 6857 } 6858 6859 validate.call(this); 6860}; 6861 6862Validatable.prototype.showMessage = function () { 6863 this.trigger('error-message-show', this.data.tooltip_well); 6864}; 6865 6866module.exports = Validatable; 6867 6868},{"BaseController":"BaseController","BaseModel":"BaseModel"}],128:[function(require,module,exports){ 6869"use strict"; 6870var BaseController = require('BaseController'); 6871var IndexManager = require('@icewarp/index-manager'); 6872 6873var Window = BaseController.create('Window'); 6874 6875/** 6876 * West Bit 6877 * @type Number 6878 */ 6879var W = 1; 6880 6881/** 6882 * East bit 6883 * @type Number 6884 */ 6885var E = 2; 6886/** 6887 * North bit 6888 * @type Number 6889 */ 6890var N = 4; 6891 6892/** 6893 * South bit 6894 * @type Number 6895 */ 6896var S = 8; 6897 6898/** 6899 * 6900 * @param {object} e 6901 * @returns {undefined} 6902 */ 6903function dragStart(e) { 6904 if (this.fullscreen || !this.move_selector) { 6905 return; 6906 } 6907 updateIndex.call(this); 6908 this.drag_start = {x: e.clientX, y: e.clientY}; 6909 if (this.resize) { 6910 e.preventDefault(); 6911 this.resizing = true; 6912 this.start_width = this.DOMElement.offsetWidth; 6913 this.start_height = this.DOMElement.offsetHeight; 6914 this.start_top = this.DOMElement.offsetTop; 6915 this.start_left = this.DOMElement.offsetLeft; 6916 return; 6917 } 6918 if (e.target === this.select(this.move_selector)) { 6919 e.preventDefault(); 6920 this.moving = true; 6921 } 6922} 6923 6924/** 6925 * 6926 * @param {object} e 6927 * @returns {undefined} 6928 */ 6929function stopDrag(e) { 6930 var coords; 6931 if (this.moving) { 6932 coords = calculateCoordinates.call(this, e, true); 6933 this.x = coords.x; 6934 this.y = coords.y; 6935 this.DOMElement.style.transform = 'none'; 6936 this.DOMElement.style.left = this.x + 'px'; 6937 this.DOMElement.style.top = this.y + 'px'; 6938 this.moving = false; 6939 } 6940 if (this.resizing) { 6941 this.resizing = false; 6942 this.x = this.DOMElement.offsetLeft; 6943 this.y = this.DOMElement.offsetTop; 6944 } 6945 6946} 6947 6948/** 6949 * 6950 * @param {object} e 6951 * @returns {undefined} 6952 */ 6953function move(e) { 6954 var coords, width, height, top, left; 6955 if (this.moving) { 6956 coords = calculateCoordinates.call(this, e); 6957 (this.DOMElement.style.transform = 'translateX(' + coords.x + 'px' + ') translateY(' + coords.y + 'px' + ') translateZ(0)'); 6958 } 6959 if (this.resizing) { 6960 width = getWidth.call(this, e); 6961 height = getHeight.call(this, e); 6962 top = getTop.call(this, e); 6963 left = getLeft.call(this, e); 6964 width && (this.resize & W || this.resize & E) && (this.DOMElement.style.width = width + 'px'); 6965 height && (this.resize & N || this.resize & S) && (this.DOMElement.style.height = height + 'px'); 6966 height && (this.resize & N) && (this.DOMElement.style.top = top + 'px'); 6967 width && (this.resize & W) && (this.DOMElement.style.left = left + 'px'); 6968 } 6969} 6970 6971/** 6972 * 6973 * @param {type} e 6974 * @returns {undefined} 6975 */ 6976function resize(e) { 6977 var dir = 0; 6978 if (this.resizing) { 6979 return; 6980 } 6981 this.DOMElement.style.cursor = 'auto'; 6982 (Math.abs(e.clientX - this.x) < this.draggable_border) && (dir = dir | W); 6983 (Math.abs(e.clientX - (this.x + this.DOMElement.offsetWidth)) < this.draggable_border) && (dir = dir | E); 6984 (Math.abs(e.clientY - this.y) < this.draggable_border) && (dir = dir | N); 6985 (Math.abs(e.clientY - (this.y + this.DOMElement.offsetHeight)) < this.draggable_border) && (dir = dir | S); 6986 if (dir & W || dir & E) { 6987 this.DOMElement.style.cursor = 'ew-resize'; 6988 }
6989 if (dir & N || dir & S) { 6990 this.DOMElement.style.cursor = 'ns-resize'; 6991 } 6992 if ((dir & W && dir & S) || (dir & E && dir & N)) { 6993 this.DOMElement.style.cursor = 'nesw-resize'; 6994 } 6995 if ((dir & E && dir & S) || (dir & W && dir & N)) { 6996 this.DOMElement.style.cursor = 'nwse-resize'; 6997 } 6998 this.resize = dir; 6999} 7000 7001/** 7002 * 7003 * @param {object} e 7004 * @param {boolean} fixed 7005 * @returns {nm$_window.Window.prototype.calculateCoordinates.windowAnonym$0} 7006 */ 7007function calculateCoordinates(e, fixed) { 7008 var x_diff = e.clientX - this.drag_start.x; 7009 var y_diff = e.clientY - this.drag_start.y; 7010 var x = x_diff; 7011 var y = y_diff; 7012 if ((this.x + x_diff + this.DOMElement.offsetWidth) > document.body.offsetWidth) { 7013 x = (document.body.offsetWidth - this.DOMElement.offsetWidth - this.x); 7014 } 7015 if ((this.x + x_diff) < 0) { 7016 x = -this.x; 7017 } 7018 if ((this.y + y_diff + this.DOMElement.offsetHeight) > document.body.offsetHeight) { 7019 y = (document.body.offsetHeight - this.DOMElement.offsetHeight - this.y); 7020 } 7021 if ((this.y + y_diff) < 0) { 7022 y = -this.y; 7023 } 7024 return {x: fixed ? this.x + x : x, y: fixed ? this.y + y : y}; 7025} 7026/** 7027 * 7028 * @param {object} e 7029 * @returns {Number} 7030 */ 7031function getTop(e) { 7032 var top = this.start_top + (e.clientY - this.drag_start.y); 7033 return top > 0 ? top : 0; 7034} 7035/** 7036 * 7037 * @param {object} e 7038 * @returns {Number} 7039 */ 7040function getLeft(e) { 7041 var left = this.start_left + (e.clientX - this.drag_start.x); 7042 return left > 0 ? left : 0; 7043} 7044/** 7045 * 7046 * @param {object} e 7047 * @returns {Number} 7048 */ 7049function getWidth(e) { 7050 var width = this.start_width + ((e.clientX - this.drag_start.x) * (this.resize & W ? -1 : 1)); 7051 var space_right = (document.body.offsetWidth - this.DOMElement.offsetLeft); 7052 var space_left = (this.DOMElement.offsetLeft > 0 ? this.DOMElement.offsetLeft : 0) + this.DOMElement.offsetWidth; 7053 if (width < this.min_width) { 7054 return this.min_width; 7055 } 7056 if ((document.body.offsetWidth - this.DOMElement.offsetLeft - this.DOMElement.offsetWidth) < 0) { 7057 return 0; 7058 } 7059 return (this.resize & W) ? (width > space_left ? space_left : width) : (width > space_right ? space_right : width); 7060} 7061/** 7062 * 7063 * @param {object} e 7064 * @returns {Number} 7065 */ 7066function getHeight(e) { 7067 var height = this.start_height + ((e.clientY - this.drag_start.y) * (this.resize & N ? -1 : 1)); 7068 var space_bottom = (document.body.offsetHeight - this.DOMElement.offsetTop); 7069 var space_top = (this.DOMElement.offsetTop < 0 ? 0 : this.DOMElement.offsetTop) + this.DOMElement.offsetHeight; 7070 if (height < this.min_height) { 7071 return this.min_height; 7072 } 7073 if ((space_bottom - this.DOMElement.offsetHeight) < 0 || this.DOMElement.offsetTop < 0) { 7074 return 0; 7075 } 7076 return (this.resize & N) ? (height > space_top ? space_top : height) : (height > space_bottom ? space_bottom : height); 7077} 7078 7079/** 7080 * 7081 * @returns {undefined} 7082 */ 7083function updateIndex() { 7084 this.DOMElement.style.zIndex = IndexManager.add(this) + 200; 7085} 7086 7087/** Generic class_name for floating windows 7088 * 7089 * @returns {Window} 7090 */ 7091Window.prototype.onCreate = function () { 7092 /** 7093 * Border for resizing 7094 * @type Number 7095 */ 7096 this.draggable_border = 0; 7097 7098 /** 7099 * Selector for moving window
7100 * @type String 7101 */ 7102 this.move_selector = false; 7103 7104 /** 7105 * 7106 * @type Number 7107 */ 7108 this.min_width = 100; 7109 7110 /** 7111 * 7112 * @type Number 7113 */ 7114 this.min_height = 100; 7115 7116 this.drag_start = false; 7117 this.x = 0; 7118 this.y = 0; 7119 this.fullscreen = false; 7120}; 7121 7122Window.prototype.addListeners = function () { 7123 if (this.move_selector) { 7124 this.addDOMListener('', 'mousedown', dragStart.bind(this)); 7125 this.addDOMListener(document, 'mouseup', stopDrag.bind(this)); 7126 this.addDOMListener(document, 'mousemove', move.bind(this)); 7127 this.addDelegatedDOMListener(this.move_selector, 'dblclick', this.toggleFullscreen); 7128 } 7129 this.draggable_border && this.addDOMListener('', 'mousemove', resize.bind(this)); 7130}; 7131 7132/** Setup 7133 * 7134 * @param {object} options 7135 * @returns {undefined} 7136 */ 7137Window.prototype.setup = function (options) { 7138 var i; 7139 for (i in (options || {})) { 7140 this[i] = options[i]; 7141 } 7142}; 7143Window.prototype.toggleFullscreen = function (e) { 7144 this.beforeFullScreenToggle && this.beforeFullScreenToggle(e); 7145 if (!this.fullscreen) { 7146 this.beforeFullScreenOn && this.beforeFullScreenOn(e); 7147 this.fullscreen = { 7148 top: this.DOMElement.style.top, 7149 left: this.DOMElement.style.left, 7150 width: this.DOMElement.style.width, 7151 height: this.DOMElement.style.height, 7152 x: this.x, 7153 y: this.y 7154 }; 7155 this.DOMElement.style.top = 0; 7156 this.DOMElement.style.left = 0; 7157 this.DOMElement.style.width = this.DOMElement.style.height = '100%'; 7158 this.x = 0; 7159 this.y = 0; 7160 this.afterFullScreenOn && this.afterFullScreenOn(e); 7161 } else { 7162 this.beforeFullScreenOff(e); 7163 this.DOMElement.style.top = this.fullscreen.top; 7164 this.DOMElement.style.left = this.fullscreen.left; 7165 this.DOMElement.style.width = this.fullscreen.width; 7166 this.DOMElement.style.height = this.fullscreen.height; 7167 this.x = this.fullscreen.x; 7168 this.y = this.fullscreen.y; 7169 this.fullscreen = false; 7170 this.afterFullScreenOff && this.afterFullScreenOff(e); 7171 } 7172 this.afterFullScreenToggle && this.afterFullScreenToggle(e); 7173}; 7174 7175/** 7176 * 7177 * @returns {undefined} 7178 */ 7179Window.prototype.afterRender = function () { 7180 this.DOMElement.classList.add('o-window'); 7181 this.x = this.DOMElement.offsetLeft; 7182 this.y = this.DOMElement.offsetTop; 7183 updateIndex.call(this); 7184}; 7185 7186module.exports = Window; 7187 7188}
7188,{"@icewarp/index-manager":164,"BaseController":"BaseController"}],129:[function(require,module,exports){ 7189"use strict"; 7190module.exports={'form':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/form.js')},'validatable':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/validatable.js')},'window':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/window.js')},'molecules-button':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/button/button.js')},'molecules-captcha':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/captcha/captcha.js')},'molecules-input':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input.js')},'molecules-input~password-with-policy':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~password-with-policy.js')},'molecules-input~password':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~password.js')},'molecules-input~search':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~search.js')},'molecules-input~validatable':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~validatable.js')},'molecules-language-picker':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/language-picker/language-picker.js')},'molecules-select':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/select/select.js')},'molecules-select~validatable':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/select/select~validatable.js')},'molecules-checkbox':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/checkbox/checkbox.js')},'molecules-static':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/static/static.js')},'molecules-textarea':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/textarea/textarea.js')},'molecules-textarea~validatable':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/molecules/textarea/textarea~validatable.js')},'organisms-bar~footer':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/organisms/bar/bar~footer.js')},'organisms-card-header':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/organisms/card-section/card-header.js')},'organisms-card-header~message':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/organisms/card-section/card-header~message.js')},'organisms-window':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/organisms/window/window.js')},'sites-generic':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/sites/generic.js')},'sites-login':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/sites/login/login.js')},'templates-card':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card.js')},'templates-card~change-password':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~change-password.js')},'templates-card~choose-account':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~choose-account.js')},'templates-card~confirm-personality':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~confirm-personality.js')},'templates-card~contact-admin':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~contact-admin.js')},'templates-card~create-account':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~create-account.js')},'templates-card~forgot-password':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~forgot-password.js')},'templates-card~gateway-login':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~gateway-login.js')},'templates-card~generic-message':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~generic-message.js')},'templates-card~guest-verify':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~guest-verify.js')},'templates-card~join-password':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~join-password.js')},'templates-card~join-username':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~join-username.js')},'templates-card~join':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~join.js')},'templates-card~oauth-grant':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~oauth-grant.js')},'templates-card~personal':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~personal.js')},'templates-card~reset-password':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~reset-password.js')},'templates-card~set-password':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~set-password.js')},'templates-card~sign-in-guest':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~sign-in-guest.js')},'templates-card~sign-in-password':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~sign-in-password.js')},'templates-card~sign-in':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~sign-in.js')},'templates-card~tc-actions':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-actions.js')},'templates-card~tc-check-email':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-check-email.js')},'templates-card~tc-collaboration':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-collaboration.js')},'templates-card~tc-join':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-join.js')},'templates-card~tc-share':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-share.js')},'templates-card~touch-id':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~touch-id.js')},'templates-card~two-factor':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~two-factor.js')},'templates-card~unavailable':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~unavailable.js')},'atoms-ad-adsense':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/
7190atoms/ad/ad-adsense.js')},'atoms-ad':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/ad/ad.js')},'atoms-addon':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/addon/addon.js')},'atoms-addon~show':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/addon/addon~show.js')},'atoms-dropdown':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/dropdown/dropdown.js')},'atoms-avatar':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/avatar/avatar.js')},'atoms-element-button':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-button.js')},'atoms-element-input':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-input.js')},'atoms-element-input~date':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-input~date.js')},'atoms-element-select':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-select.js')},'atoms-element-textarea':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-textarea.js')},'atoms-info':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info.js')},'atoms-info~choose-account':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~choose-account.js')},'atoms-info~contact-admin':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~contact-admin.js')},'atoms-info~dont-have-account':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~dont-have-account.js')},'atoms-info~have-account':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~have-account.js')},'atoms-info~not-you':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~not-you.js')},'atoms-info~sign-with-another-acc':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~sign-with-another-acc.js')},'atoms-label':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/label/label.js')},'atoms-link~back':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~back.js')},'atoms-link~check-account':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~check-account.js')},'atoms-link~choose-account':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~choose-account.js')},'atoms-link~contact-admin':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~contact-admin.js')},'atoms-link~create-acc':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~create-acc.js')},'atoms-link~remove-from-list':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~remove-from-list.js')},'atoms-link~retry':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~retry.js')},'atoms-link~sign-in':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~sign-in.js')},'atoms-link~sign-with-another-acc':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~sign-with-another-acc.js')},'atoms-link~what-is-teamchat':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~what-is-teamchat.js')},'atoms-switch':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/switch/switch.js')},'atoms-well':function(){return require('/tc-build/builds/e24a4084e6e20918/merged/components/atoms/well/well.js')}}; 7191}
7191,{"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/ad/ad-adsense.js":47,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/ad/ad.js":48,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/addon/addon.js":49,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/addon/addon~show.js":50,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/avatar/avatar.js":51,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/dropdown/dropdown.js":52,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-button.js":53,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-input.js":54,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-input~date.js":55,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-select.js":56,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/form-elements/element-textarea.js":57,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info.js":58,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~choose-account.js":59,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~contact-admin.js":60,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~dont-have-account.js":61,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~have-account.js":62,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~not-you.js":63,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/info/info~sign-with-another-acc.js":64,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/label/label.js":65,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~back.js":66,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~check-account.js":67,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~choose-account.js":68,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~contact-admin.js":69,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~create-acc.js":70,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~remove-from-list.js":71,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~retry.js":72,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~sign-in.js":73,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~sign-with-another-acc.js":74,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/link/link~what-is-teamchat.js":75,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/switch/switch.js":76,"/tc-build/builds/e24a4084e6e20918/merged/components/atoms/well/well.js":77,"/tc-build/builds/e24a4084e6e20918/merged/components/form.js":78,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/button/button.js":79,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/captcha/captcha.js":80,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/checkbox/checkbox.js":81,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input.js":82,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~password-with-policy.js":83,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~password.js":84,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~search.js":85,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/input/input~validatable.js":86,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/language-picker/language-picker.js":87,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/select/select.js":88,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/select/select~validatable.js":89,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/static/static.js":90,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/textarea/textarea.js":91,"/tc-build/builds/e24a4084e6e20918/merged/components/molecules/textarea/textarea~validatable.js":92,"/tc-build/builds/e24a4084e6e20918/merged/components/organisms/bar/bar~footer.js":93,"/tc-build/builds/e24a4084e6e20918/merged/components/organisms/card-section/card-header.js":94,"/tc-build/builds/e24a4084e6e20918/merged/components/organisms/card-section/card-header~message.js":95,"/tc-build/builds/e24a4084e6e20918/merged/components/organisms/window/window.js":96,"/tc-build/builds/e24a4084e6e20918/merged/components/sites/generic.js":97,"/tc-build/builds/e24a4084e6e20918/merged/components/sites/login/login.js":98,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card.js":99,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~change-password.js":100,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~choose-account.js":101,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~confirm-personality.js":102,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~contact-admin.js":103,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~create-account.js":104,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~forgot-password.js":105,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~gateway-login.js":106,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~generic-message.js":107,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~guest-verify.js":108,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~join-password.js":109,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~join-username.js":110,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~join.js":111,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~oauth-grant.js":112,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~personal.js":113,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~reset-password.js":114,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~set-password.js":115,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~sign-in-guest.js":116,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~sign-in-password.js":117,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~sign-in.js":118,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-actions.js":119,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-check-email.js":120,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-collaboration.js":121,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-join.js":122,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~tc-share.js":123,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~touch-id.js":124,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~two-factor.js":125,"/tc-build/builds/e24a4084e6e20918/merged/components/templates/card/card~unavailable.js":126,"/tc-build/builds/e24a4084e6e20918/merged/components/validatable.js":127,"/tc-build/builds/e24a4084e6e20918/merged/components/window.js":128}],130:[function(require,module,exports){ 7192module.exports={"calendar":{"day":{"monday":"Monday","tuesday":"Tuesday","wednesday":"Wednesday","thursday":"Thursday","friday":"Friday","saturday":"Saturday","
7192sunday":"Sunday"},"day_short":{"mon":"Mon","tue":"Tue","wed":"Wed","thu":"Thu","fri":"Fri","sat":"Sat","sun":"Sun"},"month":{"january":"January","february":"February","march":"March","april":"April","may":"May","june":"June","july":"July","august":"August","september":"September","october":"October","november":"November","december":"December"},"next_month":"Next month","previous_month":"Previous month"},"change-password":{"heading":"Change password","submit":"Change password","success-message":"Password has been changed"},"choose-account":{"heading":"Choose an account","remove":"Manage Accounts","remove-selected":"Remove selected"},"confirm-personality":{"heading":"Confirm personality","subheading":"Please wait while your account is being verified","success-message":"Your account has been verified"},"contact-admin":{"describe-problem":"Describe your problem","email-helper":"The address which will be used to reply to you.","having-problems":"Having problems?","heading":"Contact administrator","submit":"Send message","success-message":"Admin has been notified","tel":"Please leave us here your mobile phone number"},"create-account":{"alternative-email":"Alternative email","domain":"Domain","email-address":"Your email address","enter-first-name":"Enter your first name","enter-last-name":"Enter your last name","first-name":"First name","full-name":"Full name","heading":"Create an account","last-name":"Last name","last-step":"Last step","next-step":"Next step","suggestion":"This is your email address suggested based on the first and last\nname indicated in the previous step. The address is created under\nyour custom domain. Feel free to adjust the name as needed."},"error":{"invalid_login":"Incorrect username or password. Please try again.","expired":"Expired session","connection":"Unable to reach server. Please check your internet connection or contact administrator.","servererror":"Unable to access this service. Please try again later or contact administrator.","overloaded":"The server is currently overloaded. Please try again later or contact administrator.","wc_disabled":"WebClient is disabled.","invalid_rsa":"Unable to create RSA password.","no_db":"Database Connection Error","no_data":"No Data Available","access_error":"Unable to access mailbox folder, please contact administrator.","ip_mismatch":"Your IP has changed, you will be logged out. To prevent this problem in the future, please access WebClient via HTTPS connection.","sso_login_not_allowed":"SSO login not allowed","sso_unable_to_use":"Unable to use SSO","sso_error":"Error when trying to use SSO login","auth_login_invalid":"Invalid login username or password","auth_login_blocked":"Account blocked","account_already_exists":"Account already exists","account_alternative_email":"Account has no alternate email address. Please contact admin","account_disabled_1":"Could not login because of IP Restriction","account_disabled_2":"Could not login because account is disabled","account_disabled_3":"Could not login because password is expired","account_disabled_4":"Could not login because account expired","account_disabled_5":"Could not login because of SMTP access mode","account_disabled_6":"Could not login because of POP/IMAP access mode","account_disabled_7":"Could not login because account is IMAP only","account_disabled_8":"Could not login because account is POP3 only","account_disabled_9":"Could not login because account has no access rights to WebClient","account_disabled_10":"Could not login because of access mode","account_disabled_11":"Could not login because login to this domain is disabled","account_disabled_12":"Could not login because domain expired","account_disabled_13":"Could not login because of license","account_invalid":"Account invalid","account_does_not_exist":"Specified account doesn't exist","account_missing_required_property":"Some of the required properties is missing","account_no_password":"Account password is missing or empty","account_no_username":"Account username is missing or empty","account_no_domain":"Domain is missing","account_password_policy":"Password does not match the password policy","account_signup_disabled":"Self sign-up disabled","account_signup_disabled_ip":"Admin has disabled signup from your IP","auth_digest_expired":"Login expired, please login again","auth_plan_exceeded":"The user count allowed by the license has been exceeded. Only administrators are allowed to sign in until the issue is resolved.","auth_two_factor_invalid":"Invalid verification code","auth_webadmin_session_not_found":"Webadmin session not found","capslock":"Caps Lock on","captcha_confirmation":"Wrong security code","contact_support_no_admin_email":"Administrator has not set up an email address","db_auto_create":"Cannot auto create the database","db_create_sqlitefile":"Cannot create SQLite DB file","db_create_tables":"Cannot create tables","db_invalid_statement":"Invalid statement type","domain_invali
7192d":"Invalid domain","folder_get_list":"Cannot get the list of folders","folder_open":"Cannot open folder","forgot-missing-domain":"Please enter your full email address first to continue with password reset.","group_open":"Cannot open group","groupware_authenticate":"Login to GroupWare failed","groupware_db_connection":"GroupWare is unable to connect to database","groupware_timeout":"GroupWare timeout","groupware_upgrade_task":"GroupWare service update procedure is running. Please try again later.","guest_invalid_hash":"Wrong verification hash","gw_init_error":"GroupWare initialization error","invalid_account_app":"Cannot use this account with this app","invalid_domain":"Invalid domain","language_path_not_found":"Language path not found","language-not-found":"Language file not found","logdir_create":"Cannot create logging directory","login_account_valid":"Invalid account","login_invalid":"Invalid login for user","login_invalid_keypair":"RSA validation failed. Try again.","login_ip_invalid":"Login IP restriction","migration_in_progress":"Migration of account is in progress, please try again later","missing_request_params":"Missing request parameters","no_teamchat_folders":"Unable to login due to missing teamchat folder","password_not_changed":"New password cannot be the same as old password","personality_confirmation_invalid_hashid":"Email address cannot be confirmed: Invalid Hash","personality_confirmation_invalid_user":"Email address cannot be confirmed: Invalid User","reset_disabled":"Reset password has been disabled","reset_password_invalid_hashid":"Invalid hash ID","reset_password_no_hash":"Invalid hash ID","reset_password_uid_file":"UID file doesn't exist","reset_too_old":"Password reset link has expired","rsa_create_key_pair":"Unable to create RSA key pair","server":"Unable to access this service. Please try again later or contact administrator.","session_cookie_mismatch":"Session cookie mismatch","session_expired":"Session expired","session_ip_mismatch":"Session IP mismatch","session_mismatch":"Session mismatch","session_no_user":"Session user object cannot be retrieved","settings_user_set":"Cannot load user settings","setting_file_corrupted":"Webmail server settings are corrupted. Please, contact the administrator.","signup_expired":"Signup session has expired. Contact the sender to invite you again.","signup_invalid_invite_domain":"Invite domain invalid","signup_invalid_invite_session":"Invite session invalid","signup_verification_failed_sms":"Unable to send SMS verification","signup_verification_failed_email":"Unable to send email verification","signup_verification_not_initialized":"Verification not initialized","signup_verification_failed":"Verification failed","storage_get_dom":"Unable to load setting file","unavailable":"Temporary unavailable","unspecified":"Server returned an error **%{error}**","user_settings_global":"Unable to load settings","oauth_not_found":"Invalid OAuth authorization code","oauth_expired":"OAuth authorization code expired"},"forgot-password":{"heading":"Forgot password","submit":"Send me instructions","success-message":"Email has been sent to your alternative email address","success-message-guest":"Email has been sent to your email address"},"gateway-login":{"subheading":"Sign in with an administrator account to manage domains and users","success-message":"We have sent you an e-mail which contains a secure link. Clicking the link will let you access spam management for a limited time."},"generic":{"accept":"Accept","authorize":"Authorize","back":"Back","cancel":"Cancel","captcha-generate":"Generate new","check-account":"Check your account again","choose-different-account":"Choose different account","confirm":"Confirm","contact-admin":"Contact admin","continue":"Continue","copyright":"Powered by IceWarp","create-acc":"Create an account","decline":"Decline","done":"Done","email":"Email address","error":"Something went wrong","female":"Female","find_out_more":"[www.icewarp.com](//www.icewarp.com)","fullscreen-enter":"Enter fullscreen","fullscreen-exit":"Exit fullscreen","have-account":"Already have an account?","dont-have-account":"Don't have an account yet?","hide":"Hide","male":"Male","next":"Next","not-you":"Not you?","password":"Password","password-confirm":"Confirm password","password-current":"Current password","password-new":"New password","password-policy":"Password policy","retry":"Retry","save-password":"Save new password","search":"Search","security-code":"Security code","send":"Send","show":"Show","
7192sign-in":"Sign in","sign-with-another-acc":"Sign in with another account","skip":"Skip","success":"Success","undefined":"Undefined","understand":"OK, I understand","undisclosed_participant":"Undisclosed participant","username":"Username"},"guest-verify":{"heading":"Guest verification","subheading":"Please wait while your account is being verified","success-message":"Your account has been verified"},"interface":{"label":"Interface","desktop":"Desktop","tablet":"Tablet","phone":"Phone"},"join":{"heading":"Join %{domain}"},"oauth":{"grant_title":"Application %{client} needs to access your account and asks for following permissions:","Admin":"Admin API access","User":"WebClient API access","info":"%{client} will be listed among your OAuth applications in WebClient and can be removed any time. You may optionally fill the description below.","description":"Description (optional)"},"personal":{"heading":"Personal Information","nickname":"Nickname","birthday":"Birthday","company":"Company","job":"Job","profession":"Profession","mobile-phone":"Mobile Phone","work-phone":"Work Phone","home-phone":"Home Phone","im":"IM","gender":"Gender","homepage":"Homepage"},"reset-password":{"heading":"Reset password","success-message":"Password has been changed","resethash":"Hash from SMS"},"set-password":{"code_sent_to":"Verification code has been sent to *%{to}*.","verification_code":"Verification code","heading":"You're almost done!","submit":"Create an Account","success-message":"Account has been created"},"sign-in":{"guest-helper":"Use this option if you do not have existing IceWarp account","sign-in-as-guest":"Sign in as guest","subtitle":"Please enter your e-mail address for IceWarp account"},"sign-in-generic":{"heading":{"conference":"Sign in to conference","oauth":"%{client} requires permissions","webclient":"Sign in to WebClient","webadmin":"Sign in to WebAdmin"}},"sign-in-password":{"forgot":"Forgot?","or":"or","remember":"Keep me signed in","
7192sign-in-with-my-service":"Sign in with my service"},"tc-actions":{"heading":"Plus button actions","subheading":"Make it easy to manage all TeamChat actions using the multi action '+' button."},"tc-check-email":{"heading":"Check your email","subheading":"Verify your email address and then use the **combination of your email address and password to join in** and chat with other users in TeamChat room **%{room}**","submit":"Go to sign in page","success-message":"Email has been verified"},"tc-collaboration":{"heading":"Collaboration in teams","subheading":"Exchange ideas, files or other data and discuss in different groups in real-time."},"tc-join":{"heading":"Join our TeamChat","subheading":"%{name} invited you to join TeamChat room _%{room}_","submit":"Verify my email address","success-message":"You have joined %{room}","username":"Name","username-helper":"Add name as it will appear in TeamChat","what-is-teamchat":"What is TeamChat?"},"tc-share":{"heading":"Share everything easily","subheading":"Drag & drop any documents or media - share and edit them right within the app."},"title":{"webadmin":"IceWarp WebAdmin","webclient":"IceWarp WebClient","oauth":"IceWarp OAuth"},"touch-id":{"heading":"Sign in with touch ID","use-password":"Use password instead"},"two_step":{"verification_code":"Verification code","heading":"Two step verification","subheading":"Please enter 6 digit code from IceWarp Authenticator app","subheading-phone":"Please enter 6 digit code sent to your phone number ending -%{phone}"},"validation":{"alpha_chars":"Field has to contain at least %{amount} letter||||Field has to contain at least %{amount} letters","email":"Invalid Email","empty":"Field cannot be empty","length":"Length must be %{amount} characters","min_length":"Minimum length is %{amount} characters","non_alpha_num_chars":"Field has to contain at least %{amount} non-alphanumeric character||||Field has to contain at least %{amount} non-alphanumeric characters","numeric_chars":"Field has to contain at least %{amount} number||||Field has to contain at least %{amount} numbers","passwords-no-match":"Passwords do not match","upper_alpha_chars":"Field has to contain at least %{amount} uppercase letter||||Field has to contain at least %{amount} uppercase letters","user_alias":"Field cannot contain username","username":"Username cannot contain \"@\" character","username-taken":"Username already taken"},"languages":{"ar":"اÙÙØºØ© Ø§ÙØ¹Ø±Ø¨ÙØ©","bg":"бÑлгаÑÑки","cn":"ç®ä½ä¸æ","cs":"ÄeÅ¡tina","de":"Deutsch","dk":"Dansk","el":"Îλληνικά","en":"English","es":"Español","fa":"ÙØ§Ø±Ø³Û","fi":"Suomi","fr":"Français","he":"×¢Ö´×ְרִ×ת","hi":"हिनà¥à¤¦à¥","hr":"Hrvatski","hu":"Magyar","id":"Indonesia","is":"Ãslenska","it":"Italiano","jp":"æ¥æ¬èª","kr":"íêµì´","lv":"LatvieÅ¡u","nl":"Nederlands","no":"Norsk","pl":"Polski","pt":"Português","ru":"PÑÑÑкий","se":"Svenska","sk":"SlovenÄina","th":"à¹à¸à¸¢","tr":"Türkçe","ro":"RomânÄ","ua":"УкÑаÑнÑÑка","vi":"Tiếng Viá»t"}} 7193},{}],131:[function(require,module,exports){ 7194module.exports={"en":{"label":"English","direction":"ltr"},"ar":{"label":"â«Ø§ÙØ¹Ø±Ø¨ÙØ©â¬","direction":"rtl"},"bg":{"label":"бÑлгаÑÑки език","direction":"ltr"},"cs":{"label":"ÄeÅ¡tina","direction":"ltr"},"da":{"label":"dansk","direction":"ltr"},"de":{"label":"Deutsch","direction":"ltr"},"el":{"label":"Îλληνικά","direction":"ltr"},"es":{"label":"español","direction":"ltr"},"fa":{"label":"â«ÙارسÛâ¬","direction":"rtl"},"fi":{"label":"Suomen kieli","direction":"ltr"},"fr":{"label":"français","direction":"ltr"},"he":{"label":"â«×¢×ר×תâ¬","direction":"rtl"},"hi":{"label":"हिनà¥à¤¦à¥","direction":"ltr"},"hr":{"label":"Hrvatski","direction":"ltr"},"hu":{"label":"Magyar","direction":"ltr"},"id":{"label":"Bahasa Indonesia","direction":"ltr"},"is":{"label":"Ãslenska","direction":"ltr"},"it":{"label":"Italiano","direction":"ltr"},"ja":{"label":"æ¥æ¬èª (ã«ã»ãã)","direction":"ltr"},"ko":{"label":"íêµì´ (éåèª)","direction":"ltr"},"la":{"label":"latine","direction":"ltr"},"lv":{"label":"latvieÅ¡u valoda","direction":"ltr"},"nl":{"label":"Nederlands","direction":"ltr"},"no":{"label":"Norsk","direction":"ltr"},"pl":{"label":"Polski","direction":"ltr"},"pt":{"label":"Português","direction":"ltr"},"ro":{"label":"românÄ","direction":"ltr"},"ru":{"label":"ÑÑÑÑкий ÑзÑк","direction":"ltr"},"sk":{"label":"slovenÄina","direction":"ltr"},"sv":{"label":"Svenska","direction":"ltr"},"th":{"label":"à¹à¸à¸¢","direction":"ltr"},"tr":{"label":"Türkçe","direction":"ltr"},"ua":{"label":"ÑкÑаÑнÑÑка мова","direction":"ltr"},"vi":{"label":"Tiếng Viá»t","direction":"ltr"},"zh":{"label":"䏿","direction":"ltr"}} 7195},{}
7195],132:[function(require,module,exports){ 7196"use strict"; 7197/** 7198 * @see {@link https://stackoverflow.com/a/48275932} 7199 * @param {*} target 7200 * @param {*} source 7201 */ 7202function mergeDeep(target, source) { 7203 var key; 7204 if (typeof target == "object" && typeof source == "object") { 7205 for (key in source) { 7206 if (source[key] === null && (target[key] === undefined || target[key] === null)) { 7207 target[key] = null; 7208 } else if (source[key] instanceof Array) { 7209 if (!target[key]) target[key] = []; 7210 //concatenate arrays 7211 target[key] = target[key].concat(source[key]); 7212 } else if (typeof source[key] == "object") { 7213 if (!target[key]) target[key] = {}; 7214 mergeDeep(target[key], source[key]); 7215 } else { 7216 target[key] = source[key]; 7217 } 7218 } 7219 } 7220 return target; 7221} 7222 7223module.exports = mergeDeep; 7224 7225},{}],133:[function(require,module,exports){ 7226"use strict"; 7227var I18n = require('@icewarp/i18n'); 7228var config = require('/tc-build/builds/e24a4084e6e20918/src/_config.json'); 7229 7230/** 7231 * Init translations 7232 * @param {Object} data 7233 * @param {*} next 7234 * @returns {undefined} 7235 */ 7236function i18n(data, next) { 7237 config.i18n = config.i18n || {}; 7238 7239 I18n.init({ 7240 url: config.i18n.url || 'locale/', 7241 map: config.i18n.map || {}, 7242 expose: config.i18n.expose || '__', 7243 default_locale: config.i18n.default_locale || 'en', 7244 default_locale_dictionary: config.i18n.default_locale_dictionary || require('./../locale/en.json'), 7245 supported_languages: config.i18n.supported_languages || require('./../locale/languages.json'), 7246 external_url: config.i18n.external_url, 7247 version: config.i18n.version, 7248 project_name: config.project_name 7249 }); 7250 next(); 7251} 7252 7253module.exports = i18n; 7254 7255},{"./../locale/en.json":130,"./../locale/languages.json":131,"/tc-build/builds/e24a4084e6e20918/src/_config.json":368,"@icewarp/i18n":161}],134:[function(require,module,exports){ 7256"use strict"; 7257var Debugger = require('debugger'); 7258var config = require('/tc-build/builds/e24a4084e6e20918/src/_config.json'); 7259 7260/** 7261 * Init Debugger 7262 * 7263 * @param {*} data 7264 * @param {function} next 7265 * @returns {undefined} 7266 * @ignore 7267 */ 7268function initDebugger(data, next) { 7269 if(config.debugger) { 7270 window.Debugger = Debugger; 7271 } 7272 7273 config.debugger = config.debugger || {}; 7274 7275 Debugger.init({ 7276 level: config.debugger.level || (Debugger.levels.ERROR | Debugger.levels.EVENT | Debugger.levels.HASHCHANGE | Debugger.levels.MOUSE_TRACKING), 7277 log_length: config.debugger.log_length || 10, 7278 mouse_log_length: config.debugger.mouse_log_length || 5000, 7279 dump: { 7280 fn: function (type, data) { 7281 /* eslint-disable no-console*/ 7282 console.log(type, data); 7283 /* eslint-enable no-console*/ 7284 } 7285 } 7286 }); 7287 next(); 7288} 7289module.exports = initDebugger; 7290 7291},{"/tc-build/builds/e24a4084e6e20918/src/_config.json":368,"debugger":"debugger"}],135:[function(require,module,exports){ 7292"use strict"; 7293var BaseModel = require('BaseModel'); 7294var BaseController = require('BaseController'); 7295var Template = require('icebrace-runtime'); 7296 7297/** 7298 * Environment initialization 7299 * set models, controllers, templates 7300 * 7301 * @param {*} data 7302 * @param {function} next 7303 * @returns {undefined} 7304 * @ignore 7305 */ 7306function initEnvironment(data, next) { 7307 BaseModel.setModels(require('./../models-list.js')); 7308 BaseController.setControllers(require('./../controllers-list.js')); 7309 Template.setTemplates(require('./../templates-list.js')); 7310 next(); 7311} 7312 7313module.exports = initEnvironment; 7314 7315},{"./../controllers-list.js":129,"./../models-list.js":139,"./../templates-list.js":157,"BaseController":"BaseController","BaseModel":"BaseModel","icebrace-runtime":"icebrace-runtime"}],136:[function(require,module,exports){ 7316"use strict"; 7317var config = require('/tc-build/builds/e24a4084e6e20918/src/_config.json'); 7318var BaseModel = require('BaseModel'); 7319var Request = require('request'); 7320var mergeDeep = require('./helpers/merge-deep'); 7321 7322/** 7323 * @description Load config from URL, if provided 7324 * @param {string} url 7325 * @param {function} callback 7326 * @returns {undefined} 7327 */ 7328function request(url, callback) { 7329 if (!url) { 7330 return callback(); 7331 } 7332 new Request({ 7333 url: url 7334 }) 7335 .on('load', function(e, xhr) { 7336 try { 7337 mergeDeep(config, JSON.parse(xhr.response || xhr.responseText)); 7338 } catch (e) { 7339 console.info('Error while loading config', url, 'fallback', config); 7340 } 7341 callback(); 7342 }) 7343 .on('error', function() { 7344 console.info('Error while loading config', url, 'fallback', config); 7345 callback(); 7346 }) 7347 .send(); 7348} 7349 7350/** 7351 * Load config from ./_config, extend it by ./external_config.json and config from config.remote_config_url 7352 * 7353 * @param {*} data 7354 * @param {function} next 7355 * @returns {undefined} 7356 * @ignore 7357 */ 7358module.exports = function(data, next) { 7359 var external_config_url = 7360 config.external_config_url || 7361 (location.origin || location.protocol + '//' + location.hostname) + 7362 (location.pathname + '/external_config.json').replace('//', '/'); 7363
7364 BaseModel.instance('Config').setData('config', config); 7365 request(external_config_url, function() { 7366 request(config.remote_config_url, next); 7367 }); 7368}; 7369 7370},{"./helpers/merge-deep":132,"/tc-build/builds/e24a4084e6e20918/src/_config.json":368,"BaseModel":"BaseModel","request":"request"}],137:[function(require,module,exports){ 7371"use strict"; 7372/** 7373 * @returns {undefined} 7374 */ 7375function Middleware() { 7376 if (!arguments[0]) { 7377 throw new Error('No middlewares specified'); 7378 } 7379 7380 runMiddleware(void 0, [].slice.call(arguments)); 7381} 7382 7383/** 7384 * 7385 * @param {*} data 7386 * @param {middleware[]} middlewares 7387 * @returns {undefined} 7388 */ 7389function runMiddleware(data, middlewares) { 7390 if (!middlewares.length) { 7391 return; 7392 } 7393 middlewares.shift()(data, function(data) { 7394 runMiddleware(data, middlewares.slice(0)); 7395 }); 7396} 7397 7398module.exports = Middleware; 7399 7400},{}],138:[function(require,module,exports){ 7401"use strict"; 7402var logger = require('logger'); 7403var config = require('/tc-build/builds/e24a4084e6e20918/src/_config.json'); 7404 7405/** 7406 * Set logger log level 7407 * 7408 * @param {*} data 7409 * @param {function} next 7410 * @returns {undefined} 7411 * @ignore 7412 */ 7413function setLogLevel(data, next) { 7414 logger.setLevel((config.logger || {}).level || (logger.INFO | logger.WARN | logger.ERROR)); 7415 next(); 7416} 7417module.exports = setLogLevel; 7418 7419},{"/tc-build/builds/e24a4084e6e20918/src/_config.json":368,"logger":"logger"}],139:[function(require,module,exports){ 7420"use strict"; 7421module.exports={'Config':function(){return require('./models/Config.js')},'LegacyURL':function(){return require('./models/LegacyURL.js')},'OAuth':function(){return require('./models/OAuth.js')},'Login':function(){return require('./models/Login.js')},'Server':function(){return require('./models/Server.js')},'Validator':function(){return require('./models/Validator.js')},'WebClient':function(){return require('./models/WebClient.js')},'Setting':function(){return require('./models/WebClientSettings/Setting.js')},'Settings':function(){return require('./models/WebClientSettings/Settings.js')},'banner_options':function(){return require('./models/WebClientSettings/banner_options.js')},'custom_login_fields':function(){return require('./models/WebClientSettings/custom_login_fields.js')},'language':function(){return require('./models/WebClientSettings/language.js')},'layout_settings':function(){return require('./models/WebClientSettings/layout_settings.js')},'password_policy':function(){return require('./models/WebClientSettings/password_policy.js')},'restrictions':function(){return require('./models/WebClientSettings/restrictions.js')},'reset_settings':function(){return require('./models/WebClientSettings/reset_settings.js')},'signup_domain':function(){return require('./models/WebClientSettings/signup_domain.js')}}; 7422},{"./models/Config.js":140,"./models/LegacyURL.js":141,"./models/Login.js":142,"./models/OAuth.js":143,"./models/Server.js":144,"./models/Validator.js":145,"./models/WebClient.js":146,"./models/WebClientSettings/Setting.js":147,"./models/WebClientSettings/Settings.js":148,"./models/WebClientSettings/banner_options.js":149,"./models/WebClientSettings/custom_login_fields.js":150,"./models/WebClientSettings/language.js":151,"./models/WebClientSettings/layout_settings.js":152,"./models/WebClientSettings/password_policy.js":153,"./models/WebClientSettings/reset_settings.js":154,"./models/WebClientSettings/restrictions.js":155,"./models/WebClientSettings/signup_domain.js":156}],140:[function(require,module,exports){ 7423"use strict"; 7424var BaseModel = require('BaseModel'); 7425 7426var Config = BaseModel.create('Config'); 7427 7428Config.singleton = true; 7429 7430module.exports = Config; 7431 7432},{"BaseModel":"BaseModel"}],141:[function(require,module,exports){ 7433"use strict"; 7434var BaseModel = require('BaseModel'); 7435var Hash = require('@icewarp/hash'); 7436var LegacyURL = BaseModel.create('LegacyURL'); 7437var QueryParams = require('@icewarp/query-params'); 7438 7439var legacy = function () { 7440 return { 7441 atoken: BaseModel.instance('Login').getDefaultCard(), 7442 resetpwd: 'reset-password', 7443 changePwd: 'change-password', 7444 changepwd: 'change-password', 7445 reset: 'forgot-password', 7446 selfSignUp: 'create-account', 7447 guestSignUp: 'tc-join',
7448 guestVerify: 'guest-verify', 7449 '_s[action]': { 7450 error: BaseModel.instance('Login').getDefaultCard() 7451 }, 7452 action: { 7453 confirm_personality: 'confirm-personality' 7454 }, 7455 view: { 7456 gateway_login: 'gateway-login' 7457 }, 7458 username: 'sign-in', 7459 eid: BaseModel.instance('Login').getDefaultCard(), 7460 tconly: 'generic-message', 7461 auth_id: 'oauth-grant' 7462 }; 7463}; 7464 7465LegacyURL.redirect = function () { 7466 var parts = QueryParams.parse(), 7467 type, 7468 site; 7469 7470 var Legacy = legacy(); 7471 for (type in Legacy) { 7472 site = 7473 typeof Legacy[type] === 'string' && parts[type] 7474 ? Legacy[type] 7475 : (Legacy[type] || {})[parts[type]]; 7476 if (site) { 7477 return Hash.change( 7478 site, 7479 parts, 7480 true, 7481 false, 7482 location.protocol + 7483 '//' + 7484 location.host + 7485 location.pathname + 7486 '?legacy' 7487 ); 7488 } 7489 } 7490}; 7491 7492module.exports = LegacyURL; 7493 7494},{"@icewarp/hash":160,"@icewarp/query-params":170,"BaseModel":"BaseModel"}],142:[function(require,module,exports){ 7495"use strict"; 7496var BaseModel = require('BaseModel'); 7497var Login = BaseModel.create('Login'); 7498var LocalStorage = require('@icewarp/localstorage'); 7499var i18n = require('@icewarp/i18n'); 7500var CssLoader = require('@icewarp/css-loader'); 7501 7502Login.singleton = true; 7503 7504Login.guestLoginURL = 'https://external-users.stage1.k8s.icewarp.com/app/'; 7505Login.prototype.onCreate = function () { 7506 this.setData('guestLogin', false) 7507 .setData('useRSA', true) 7508 .setData('chosen_account', {}) 7509 .setData('create_account', {}); 7510}; 7511 7512Login.prototype.getUser = function (email) { 7513 return this.getUsers().filter(function (user) { 7514 return user.email === email; 7515 })[0]; 7516}; 7517 7518Login.prototype.getUsers = function () { 7519 !LocalStorage.getItem('logins') && LocalStorage.setItem('logins', []); 7520 return LocalStorage.getItem('logins'); 7521}; 7522 7523Login.prototype.removeUser = function (condition) { 7524 LocalStorage.setItem('logins', this.getUsers().filter(function (login) { 7525 return !Object.keys(condition).some(function (key) { 7526 return login[key] === condition[key]; 7527 }); 7528 })); 7529 return this; 7530}; 7531 7532Login.prototype.addUser = function (new_user) { 7533 var logins, i; 7534 if (BaseModel.instance('WebClient').getData('restrictions').getValue('disable_autofill')) { 7535 return this; 7536 } 7537 logins = this.getUsers(); 7538 logins.unshift(new_user); 7539 new_user.color = new_user.color || Math.floor(Math.random() * 6); 7540 LocalStorage.setItem('logins', logins.filter(function (value, index, arr) { 7541 var found = false; 7542 for (i = 0; i <= index; i++) { 7543 if (arr[i].email === value.email) { 7544 found = i; 7545 break; 7546 } 7547 } 7548 return index === found; 7549 })); 7550 return this; 7551}; 7552 7553Login.prototype.getDefaultCard = function () { 7554 return (this.getUsers().length && !BaseModel.instance('WebClient').getData('restrictions').getValue('disable_autofill')) ? ((this.getData('chosen_account') || {}).email ? 'sign-in-password' : 'choose-account') : 'sign-in'; 7555}; 7556 7557Login.prototype.getAuthChallenge = function (callback) { 7558 this.callCommunication('getAuthChallenge', callback); 7559}; 7560 7561Login.prototype.usernameAvailable = function (data, callback) { 7562 this.callCommunication('usernameAvailable', data, callback); 7563}; 7564 7565Login.prototype.getVerification = function (data, callback) { 7566 this.callCommunication('getVerification', data, { 7567 success: function (verification_id) { 7568 this.getData('create_account').verificationrequest = { 7569 id: verification_id 7570 }; 7571 callback.success.call(callback.context); 7572 }, 7573 error: function () { 7574 callback.error.apply(callback.context, arguments); 7575 }, 7576 context: this 7577 }); 7578}; 7579 7580Login.prototype.logoutTeamChatOnly = function (data, callback) { 7581 this.callCommunication('logoutTeamChatOnly', data, callback); 7582}; 7583 7584 7585Login.prototype.isGuestDomain = function (data, callback) { 7586 this.callCommunication('isGuestDomain', data, callback); 7587}; 7588 7589Login.prototype.changeLanguage = function (language, callback) { 7590 var Language = BaseModel.static('language'); 7591 i18n.changeLanguage(Language.codes_reversed[language] || language, changeLanguage.bind(null, callback), changeLanguage.bind(null, callback)); 7592}; 7593 7594Login.prototype.guestLogin = function(data) {
7595 var config = BaseModel.instance('Config').getData('config') || {}; 7596 if (data.email) { 7597 this.addUser({ 7598 email: data.email, 7599 guestLogin: true 7600 }); 7601 data.service_provider = 'email'; 7602 } 7603 document.location = (config.guest_login_url || Login.guestLoginURL) + (data.email || '') + '?service_provider=' + data.service_provider + '&iw_host=' + location.hostname + '&iw_access=standard&autologin=webclient&autologout=1'; 7604}; 7605 7606/** 7607 * 7608 * @param {Object} callback 7609 * @param {String} language_code 7610 * @returns {undefined} 7611 */ 7612function changeLanguage(callback, language_code) { 7613 var WebClient = BaseModel.instance('WebClient'); 7614 var styles = [].map.call(document.head.querySelectorAll('meta[name="stylesheet"]'), function (meta) { 7615 return document.head.querySelector('style[content="' + meta.getAttribute('content') + '"], link[href^="' + meta.getAttribute('content') + '"]'); 7616 }).filter(Boolean); 7617 var codes = BaseModel.static('language').codes; 7618 language_code = codes[language_code] || language_code; 7619 7620 WebClient.getData('layout_settings').setUserLanguageCode(language_code); 7621 7622 document.body.setAttribute('dir', WebClient.getData('layout_settings').getUserLanguage().isRTL() ? 'rtl' : 'ltr'); 7623 CssLoader.setRTL(WebClient.getData('layout_settings').getUserLanguage().isRTL(), function () { 7624 var color, colors = {}; 7625 getComputedStyle(document.getElementById('theme-colors')).getPropertyValue('font-family').replace(/([\w-]+):(#\w+),?/g, function (all, key, value) { 7626 colors[key] = value; 7627 }); 7628 color = WebClient.getData('layout_settings').getValue('login_color'); 7629 7630 CssLoader.load(function () { 7631 styles.forEach(function (style) { 7632 style.parentNode.removeChild(style); 7633 }); 7634 callback.success && callback.success.call(callback.context || this); 7635 }, { 7636 'theme-color': colors[color], 7637 'theme-grey-color': colors[color + '-grey'], 7638 'theme-light-grey-color': colors[color + '-light-grey'] 7639 }); 7640 }); 7641} 7642 7643module.exports = Login; 7644 7645},{"@icewarp/css-loader":158,"@icewarp/i18n":161,"@icewarp/localstorage":167,"BaseModel":"BaseModel"}],143:[function(require,module,exports){ 7646"use strict"; 7647var OldCommunication = require('@icewarp/old-communication'); 7648var Hash = require('@icewarp/hash'); 7649var BaseModel = require('BaseModel'); 7650const Callback = require('Callback'); 7651var OAuth = BaseModel.create('OAuth'); 7652 7653OAuth.singleton = true; 7654 7655/** 7656 * 7657 * 7658 * @param {Callback} callback 7659 * @param {function} sideEffect 7660 * @returns {Callback} 7661 */ 7662function callbackChainBuilder(callback) { 7663 var effects = [].slice.call(arguments, 1); 7664 var context = 7665 typeof effects[effects.length - 1] !== 'function' 7666 ? effects.pop() 7667 : null; 7668 var constructed_callback = callback; 7669 effects.reverse().forEach(function (sideEffect) { 7670 var current_level = constructed_callback; 7671 constructed_callback = { 7672 success: function (result) { 7673 sideEffect.call( 7674 context || null, 7675 { 7676 success: function () { 7677 current_level.success.apply( 7678 current_level.context, 7679 arguments 7680 ); 7681 }, 7682 error: function () { 7683 current_level.error.apply( 7684 current_level.context, 7685 arguments 7686 ); 7687 } 7688 }, 7689 result 7690 ); 7691 }, 7692 error: function () { 7693 current_level.error.apply(current_level.context, arguments); 7694 }, 7695 context: current_level.context 7696 }; 7697 }); 7698 return constructed_callback; 7699} 7700 7701/** 7702 * 7703 * @description Creates new Connection with admin SID 7704 * @param {string} sid - session id 7705 * @returns {undefined} 7706 */ 7707OAuth.prototype.createAuthConnection = function (sid) { 7708 new OldCommunication(OldCommunication.XHR, 'admin-auth', { 7709 host: 7710 (BaseModel.instance('Config').getData('config').icewarpapiUrl || 7711 '//' + location.host + '/icewarpapi') + '/', 7712 xmlns: 'admin:iq:rpc', 7713 session_id: sid 7714 }); 7715}; 7716 7717/** 7718 * @description Set initial data to the model 7719 * @property {string} auth_id - ID of the auth request, used for grant 7720 * @property {string} email - Email of the user that should grant access 7721 * @property {array} scopes - Array of scopes that user should grant to the application 7722 * @returns {undefined} 7723 */ 7724OAuth.prototype.onCreate = function () { 7725 this.setData('account_data', null).initArray('scopes'); 7726}; 7727 7728OAuth.prototype.initAlreadyLoggedIn = function (callback) { 7729 var constructed_callback = callbackChainBuilder( 7730 callback, 7731 function (callback, result) { 7732 this.getAccountDetail(result.email, callback); 7733 }, 7734 function (callback, account) { 7735 this.setData('account_data', account); 7736 this.GetOauthAuthorizationRequest(callback); 7737 }, 7738 function (callback, response) { 7739 var prop; 7740 for (prop in response) { 7741 if (response[prop] && response[prop].item !== void 0) { 7742 this.setData( 7743 prop, 7744 Array.isArray(response[prop].item) 7745 ? response[prop].item 7746 : [response[prop].item] 7747 ); 7748 } else { 7749 this.setData(prop, response[prop]); 7750 } 7751 } 7752 this.GetOauthClientInfo(response.clientid, callback); 7753 }, 7754 function (callback, response) { 7755 var prop; 7756 for (prop in response) { 7757 this.setData(prop, response[prop]); 7758 } 7759 callback.success.call(callback.context); 7760 }, 7761 this 7762 );
7763 this.getSessionInfo(constructed_callback); 7764}; 7765 7766/** 7767 * @param {string} email 7768 * @param {string} password 7769 * @param {Number} authtype 7770 * @param {Callback} callback 7771 * @returns {undefined} 7772 */ 7773OAuth.prototype.login = function (email, password, authtype, callback) { 7774 var constructed_callback = callbackChainBuilder( 7775 callback, 7776 function (callback, sid) { 7777 this.createAuthConnection(sid); 7778 this.getAccountDetail(email, callback); 7779 }, 7780 function (callback, account) { 7781 this.setData('account_data', account); 7782 this.GetOauthAuthorizationRequest(callback); 7783 }, 7784 function (callback, response) { 7785 var prop; 7786 for (prop in response) { 7787 if (response[prop] && response[prop].item !== void 0) { 7788 this.setData( 7789 prop, 7790 Array.isArray(response[prop].item) 7791 ? response[prop].item 7792 : [response[prop].item] 7793 ); 7794 } else { 7795 this.setData(prop, response[prop]); 7796 } 7797 } 7798 this.GetOauthClientInfo(response.clientid, callback); 7799 }, 7800 function (callback, response) { 7801 var prop; 7802 for (prop in response) { 7803 this.setData(prop, response[prop]); 7804 } 7805 callback.success.call(callback.context); 7806 }, 7807 this 7808 ); 7809 this.callCommunication( 7810 'login', 7811 { 7812 user: email, 7813 password: password, 7814 authtype: authtype 7815 }, 7816 constructed_callback 7817 ); 7818}; 7819 7820/** 7821 * @description Gets detail of the logged in account, this data should be used for card heading and avatar 7822 * @param {String} email 7823 * @param {Callback} callback 7824 * @returns {undefined} 7825 */ 7826OAuth.prototype.getAccountDetail = function (email, callback) { 7827 return this.callCommunication( 7828 'getAccountDetail', 7829 { 7830 email: email 7831 }, 7832 callback 7833 ); 7834}; 7835 7836/** 7837 * @description Get information about currently active session 7838 * @param {Callback} callback 7839 * @returns {undefined} 7840 */ 7841OAuth.prototype.getSessionInfo = function (callback) { 7842 return this.callCommunication('GetSessionInfo', {}, callback); 7843}; 7844 7845OAuth.prototype.checkExistingGrant = function (callback) { 7846 var auth_id = Hash.getParts().auth_id; 7847 7848 if (!auth_id) { 7849 return Callback(Callback.SUCCESS, callback, {}); 7850 } 7851 7852 return this.callCommunication( 7853 'OauthAuthorizationExists', 7854 { 7855 requestid: Hash.getParts().auth_id 7856 }, 7857 callback 7858 ); 7859}; 7860 7861OAuth.prototype.GetOauthClientInfo = function (clientid, callback) { 7862 if (!clientid) { 7863 return Callback(Callback.SUCCESS, callback, {}); 7864 } 7865 7866 return this.callCommunication( 7867 'GetOauthClientInfo', 7868 { 7869 clientid: clientid 7870 }, 7871 callback 7872 ); 7873}; 7874 7875OAuth.prototype.GetOauthAuthorizationRequest = function (callback) { 7876 var auth_id = Hash.getParts().auth_id; 7877 7878 if (!auth_id) { 7879 return Callback(Callback.SUCCESS, callback, {}); 7880 } 7881 7882 return this.callCommunication( 7883 'GetOauthAuthorizationRequest', 7884 { 7885 requestid: Hash.getParts().auth_id 7886 }, 7887 callback 7888 ); 7889}; 7890 7891/** 7892 * @description Grant app permissions to access required scopes 7893 * @param {String} description 7894 * @param {Callback} callback 7895 * @returns {undefined} 7896 */ 7897OAuth.prototype.GrantOauthAuthorization = function (description, callback) { 7898 return this.callCommunication( 7899 'GrantOauthAuthorization', 7900 { 7901 requestid: Hash.getParts().auth_id, 7902 description: description 7903 }, 7904 callback 7905 ); 7906}; 7907 7908OAuth.prototype.getRedirectURL = function () { 7909 return '/oauth/v2/code?auth_id=' + Hash.getParts().auth_id; 7910}; 7911 7912module.exports = OAuth; 7913 7914},{"@icewarp/hash":160,"@icewarp/old-communication":168,"BaseModel":"BaseModel","Callback":"Callback"}],144:[function(require,module,exports){ 7915"use strict"; 7916var BaseModel = require('BaseModel'); 7917var Server = BaseModel.create('Server'); 7918 7919Server.singleton = true; 7920 7921Server.prototype.getLogo = function () { 7922 return this.getResource({class: 'logo', fullpath: document.location.hostname, uid: BaseModel.instance('WebClient').getData('layout_settings').getValue('logo_uid')}); 7923}; 7924 7925Server.prototype.getBackground = function (width, height) { 7926 return this.getResource({ 7927 class: 'background', 7928 fullpath: document.location.hostname, 7929 uid: BaseModel.instance('WebClient').getData('layout_settings').getValue('login_background_uid').toString().substring(0, 32), 7930 resize: 1, 7931 width: width || (window.screen.width * window.devicePixelRatio), 7932 height: height || (window.screen.height * window.devicePixelRatio) 7933 }); 7934}; 7935 7936Server.noCacheHash = (0 | Math.random() * 6.04e7).toString(36); 7937Server.prototype.getAvatar = function (data) {
7938 var config = BaseModel.instance('Config').getData('config'); 7939 data.internal = 1; 7940 data.uid = Server.noCacheHash; 7941 return this.getResource(data, config.avatarResourcePath); 7942}; 7943 7944Server.prototype.getResource = function (data, resourcePath) { 7945 var config = BaseModel.instance('Config').getData('config'); 7946 return document.location.origin + (resourcePath || (document.location.pathname + config.resourcePath)) + '?' + Object.keys(data).map(function (key) { 7947 return key + '=' + data[key]; 7948 }).join('&'); 7949}; 7950 7951module.exports = Server; 7952 7953},{"BaseModel":"BaseModel"}],145:[function(require,module,exports){ 7954"use strict"; 7955var BaseModel = require('BaseModel'); 7956var Validator = BaseModel.create('Validator'); 7957 7958/** 7959 * @param {Object} options 7960 * @param {String} value 7961 * @returns {Boolean} 7962 */ 7963function same(options, value) { 7964 return (options.counterpart_value || options.controller.closestHook(options.parent_hook).querySelector('[data-hook="' + options.counterpart_hook + '"]').value) === value; 7965} 7966 7967/** 7968 * @param {Object} options 7969 * @param {String} value 7970 * @returns {Boolean} 7971 */ 7972function contains(options, value) { 7973 return !!(value.match(new RegExp(options.counterpart_value === void 0 ? options.controller.closestHook(options.parent_hook).querySelector('[data-hook="' + options.counterpart_hook + '"]').value : options.counterpart_value, 'gi')) || []).length; 7974} 7975 7976Validator.prototype.empty = function (options, value, callback) { 7977 callback(value.trim().length); 7978}; 7979Validator.prototype.length = function (options, value, callback) { 7980 callback(value.trim().length === +options.data); 7981}; 7982Validator.prototype.min_length = function (options, value, callback) { 7983 callback(value.trim().length >= options.data); 7984}; 7985Validator.prototype.numeric_chars = function (options, value, callback) { 7986 callback((value.match(/\d/g) || []).length >= options.data); 7987}; 7988Validator.prototype.non_alpha_num_chars = function (options, value, callback) { 7989 callback((value.match(/[^A-Za-z0-9]/g) || []).length >= options.data); 7990}; 7991Validator.prototype.alpha_chars = function (options, value, callback) { 7992 callback((value.match(/\w/g) || []).length >= options.data); 7993}; 7994Validator.prototype.upper_alpha_chars = function (options, value, callback) { 7995 callback((value.match(/[A-Z]/g) || []).length >= options.data); 7996}; 7997Validator.prototype.email = function (options, value, callback) { 7998 callback(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(value)); 7999}; 8000Validator.prototype.same = function (options, value, callback) { 8001 callback(same(options, value)); 8002}; 8003Validator.prototype.different = function (options, value, callback) { 8004 callback(!same(options, value)); 8005}; 8006Validator.prototype.contains = function (options, value, callback) { 8007 callback(contains(options, value)); 8008}; 8009Validator.prototype.not_contains = function (options, value, callback) { 8010 callback(!contains(options, value)); 8011}; 8012Validator.prototype.callback = function (options, value, callback) { 8013 options.callback(value, callback); 8014}; 8015module.exports = Validator; 8016 8017},{"BaseModel":"BaseModel"}],146:[function(require,module,exports){ 8018"use strict"; 8019var BaseModel = require('BaseModel'); 8020var WebClient = BaseModel.create('WebClient'); 8021 8022WebClient.singleton = true; 8023 8024WebClient.prototype.onCreate = function () { 8025 this.initArray('languages'); 8026 this.initArray('signup_domains'); 8027 this.setData('custom_login_fields', BaseModel.instance('custom_login_fields')); 8028 this.setData('layout_settings', BaseModel.instance('layout_settings')); 8029 this.setData('password_policy', BaseModel.instance('password_policy')); 8030 this.setData('reset_settings', BaseModel.instance('reset_settings')); 8031 this.setData('restrictions', BaseModel.instance('restrictions')); 8032 this.setData('banner_options', BaseModel.instance('banner_options')); 8033}; 8034 8035WebClient.prototype.initialize = function (data) { 8036 var lvl0 = Array.isArray(data.list.item) ? data.list.item : [data.list.item]; 8037 var lvl2, i, lvl1, j; 8038 for (i in lvl0) { 8039 lvl1 = lvl0[i]; 8040 switch (lvl1.name) { 8041 case 'languages': 8042 lvl2 = Array.isArray(lvl1.list.item) ? lvl1.list.item : [lvl1.list.item]; 8043 for (j in lvl2) { 8044 this.pushData('languages', BaseModel.instance('language').initialize(lvl2[j].list.item)); 8045 } 8046 break; 8047 case 'signup_domains': 8048 if (!lvl1.list.item.list) { 8049 continue; 8050 } 8051 lvl2 = Array.isArray(lvl1.list.item.list.item) ? lvl1.list.item.list.item : [lvl1.list.item.list.item]; 8052 for (j in lvl2) { 8053 this.pushData('signup_domains', BaseModel.instance('signup_domain').initialize(lvl2[j])); 8054 } 8055 break; 8056 default: 8057 if (!lvl1.list || !lvl1.list.item) { 8058 continue; 8059 } 8060 lvl2 = Array.isArray(lvl1.list.item) ? lvl1.list.item : [lvl1.list.item]; 8061 for (j in lvl2) {
8062 lvl2[j].list && lvl2[j].list.item && this.setData(lvl1.name, BaseModel.instance(lvl1.name).initialize(lvl2[j].list.item)); 8063 } 8064 } 8065 } 8066 this.setData('settings_loaded', true); 8067 8068 return this; 8069}; 8070 8071/** 8072 * 8073 * @param {function} encrypt 8074 * @param {@icewarp/callback} callback callback object 8075 * @returns {undefined} 8076 */ 8077WebClient.prototype.signupAccount = function (encrypt, callback) { 8078 var Login = BaseModel.instance('Login'); 8079 var i, data = {}; 8080 for (i in Login.getData('create_account')) { 8081 data[i] = Login.getData('create_account')[i]; 8082 } 8083 8084 data.password = encrypt(Login.getData('create_account').password); 8085 data.authtype = +Login.getData('useRSA'); 8086 this.callCommunication('signupAccount', data, { 8087 success: function() { 8088 Login.addUser(Login.getData('chosen_account')); 8089 Login.setData('create_account', {card: {}}); 8090 callback.success.call(callback.context); 8091 }, 8092 error: function(response) { 8093 callback.error.call(callback.context, response); 8094 }, 8095 context: callback.context 8096 }); 8097}; 8098 8099WebClient.prototype.getAuthToken = function(data, callback) { 8100 this.callCommunication('getAuthToken', data, { 8101 success: function(response) { 8102 var config = BaseModel.instance('Config').getData('config'); 8103 var LocalStorage = require('@icewarp/localstorage'); 8104 var punycode = require('punycode'); 8105 var Login = BaseModel.instance('Login'); 8106 var chosen_account = Login.getData('chosen_account'); 8107 chosen_account.name = [response.name.name || '', response.name.surname || ''].join(' ').trim(); 8108 chosen_account.email = punycode.toUnicode(response.email || ''); 8109 chosen_account.avatar_token = response.avatartoken; 8110 Login.setData('chosen_account', chosen_account); 8111 if (this.getData('restrictions').getValue('remember_login_accounts')) { 8112 Login.addUser(Login.getData('chosen_account')); 8113 LocalStorage.setItem('last-login-' + config.application, response); 8114 } 8115 callback.success.call(callback.context, response); 8116 }, 8117 error: function(error, response) { 8118 callback.error.call(callback.context, error, response); 8119 }, 8120 context: this 8121 }); 8122}; 8123 8124WebClient.prototype.getCaptcha = function(callback) { 8125 this.callCommunication('getCaptcha', callback); 8126}; 8127 8128WebClient.prototype.changePassword = function(data, callback) { 8129 this.callCommunication('changePassword', data, callback); 8130}; 8131 8132WebClient.prototype.resetPassword = function(data, callback) { 8133 this.callCommunication('resetPassword', data, callback); 8134}; 8135 8136WebClient.prototype.confirmPersonality = function(data, callback) { 8137 this.callCommunication('confirmPersonality', data, callback); 8138}; 8139 8140WebClient.prototype.contactAdministrator = function(data, callback) { 8141 this.callCommunication('contactAdministrator', data, callback); 8142}; 8143 8144WebClient.prototype.resetPasswordEmail = function(data, callback) { 8145 this.callCommunication('resetPasswordEmail', data, callback); 8146}; 8147 8148WebClient.prototype.sendGatewayAuthentication = function(data, callback) { 8149 this.callCommunication('sendGatewayAuthentication', data, callback); 8150}; 8151 8152WebClient.prototype.guestConfirm = function(data, callback) { 8153 this.callCommunication('guestConfirm', data, callback); 8154}; 8155 8156WebClient.prototype.guestVerify = function(data, callback) { 8157 this.callCommunication('guestVerify', data, callback); 8158}; 8159 8160module.exports = WebClient; 8161 8162},{"@icewarp/localstorage":167,"BaseModel":"BaseModel","punycode":355}],147:[function(require,module,exports){ 8163"use strict"; 8164var BaseModel = require('BaseModel'); 8165var Setting = BaseModel.create('Setting'); 8166 8167Setting.prototype.onCreate = function () { 8168 this.setData('domainadminaccesslevel', 0) 8169 .setData('useraccesslevel', 0) 8170 .setData('accesslevel', 0) 8171 .setData('name', '') 8172 .setData('value', '') 8173 .setData('setdefault', 0); 8174}; 8175 8176Setting.prototype.initialize = function (data) { 8177 var key; 8178 for (key in data) { 8179 data[key] !== null && data[key] !== void 0 && this.setData(key, parseInt(data[key]) == data[key] ? parseInt(data[key]) : data[key]); 8180 } 8181 8182 return this; 8183}; 8184 8185module.exports = Setting; 8186 8187},{"BaseModel":"BaseModel"}],148:[function(require,module,exports){ 8188"use strict"; 8189var BaseModel = require('BaseModel'); 8190var Settings = BaseModel.create('Settings'); 8191 8192Settings.singleton = true; 8193 8194Settings.prototype.initialize = function (data) { 8195 var j; 8196 data = Array.isArray(data) ? data : [data]; 8197 for (j in data) { 8198 this.setData(data[j].name, BaseModel.instance('Setting', data[j].name).initialize(data[j])); 8199 } 8200 8201 return this; 8202}; 8203 8204Settings.prototype.getValue = function (name) { 8205 return this.getData(name) ? this.getData(name).getData('value') : void 0; 8206}; 8207 8208module.exports = Settings; 8209 8210},{"BaseModel":"BaseModel"}],149:[function(require,module,exports){ 8211"use strict"; 8212var BaseModel = require('BaseModel'); 8213var Settings = require('./Settings'); 8214var banner_options = BaseModel.create('banner_options', Settings); 8215 8216banner_options.prototype.onCreate = function () { 8217 [ 8218 {name: 'top_type', value: 'none'}, 8219 {name: 'top_url', value: ''}, 8220 {name: 'top_code', value: ''}, 8221 {name: 'below_type', value: 'none'}, 8222 {name: 'below_url', value: ''}, 8223 {name: 'below_code', value: ''}, 8224 {name: 'desktop_type', value: 'none'}, 8225 {name: 'desktop_url', value: ''}, 8226 {name: 'desktop_code', value: ''}, 8227 {name: 'mobile_type', value: 'none'}, 8228 {name: 'mobile_url', value: ''}, 8229 {name: 'mobile_code', value: ''}, 8230 {name: 'customer_id', value: ''} 8231 ].forEach(function (setting) { 8232 this.setData(setting.name, BaseModel.instance('Setting', setting.name).initialize(setting)); 8233 }, this); 8234}; 8235 8236module.exports = banner_options; 8237 8238},{"./Settings":148,"BaseModel":"BaseModel"}],150:[function(require,module,exports){ 8239"use strict"; 8240var BaseModel = require('BaseModel'); 8241var Settings = require('./Settings'); 8242var custom_login_fields = BaseModel.create('custom_login_fields', Settings); 8243 8244var available_custom_fields = [ 8245 { 8246 id: 'nickname', 8247 name: 'nickname', 8248 label: __('personal.nickname') 8249 }, { 8250 id: 'birthday', 8251 name: 'birthday', 8252 label: __('personal.birthday'), 8253 type: 'date', 8254 maxDate: new Date() 8255 }, { 8256 id: 'company', 8257 name: 'companyname', 8258 label: __('personal.company') 8259 }, { 8260 id: 'job', 8261 name: 'jobtitle', 8262 label: __('personal.job') 8263 }, { 8264 id: 'profession', 8265 name: 'profession', 8266 label: __('personal.profession') 8267 }, { 8268 id: 'mobile_phone', 8269 name: 'mobiletelephonenumber', 8270 label: __('personal.mobile-phone'), 8271 type: 'tel' 8272 }, { 8273 id: 'work_phone', 8274 name: 'businesstelephonenumber',
8275 label: __('personal.work-phone'), 8276 type: 'tel' 8277 }, { 8278 id: 'home_phone', 8279 name: 'hometelephonenumber', 8280 label: __('personal.home-phone'), 8281 type: 'tel' 8282 }, { 8283 id: 'im', 8284 name: 'imaddress', 8285 label: __('personal.im') 8286 }, { 8287 id: 'gender', 8288 name: 'gender', 8289 label: __('personal.gender'), 8290 type: 'select', 8291 options: [ 8292 { 8293 text: '', 8294 value: 0 8295 }, 8296 { 8297 text: __('generic.male'), 8298 value: 2 8299 }, 8300 { 8301 text: __('generic.female'), 8302 value: 1 8303 } 8304 ] 8305 }, { 8306 id: 'homepage', 8307 name: 'homepage', 8308 label: __('personal.homepage') 8309 } 8310]; 8311 8312custom_login_fields.prototype.onCreate = function () { 8313 [{name: 'login_verification_enabled', value: 0}, 8314 {name: 'login_verification_type', value: 'none'} 8315 ].forEach(function (setting) { 8316 this.setData(setting.name, BaseModel.instance('Setting', setting.name).initialize(setting)); 8317 }, this); 8318}; 8319 8320custom_login_fields.prototype.enabledCustomFields = function () { 8321 var WebClient = BaseModel.instance('WebClient'); 8322 return available_custom_fields.map(function (field) { 8323 if (field.id === 'mobile_phone' && WebClient.getData('custom_login_fields').getValue('login_verification_enabled') && (WebClient.getData('custom_login_fields').getValue('login_verification_type') === 'sms')) { 8324 return field; 8325 } 8326 return this.getValue(field.id + '_enabled') ? field : false; 8327 }, this).filter(Boolean); 8328}; 8329 8330module.exports = custom_login_fields; 8331 8332},{"./Settings":148,"BaseModel":"BaseModel"}],151:[function(require,module,exports){ 8333"use strict"; 8334var BaseModel = require('BaseModel'); 8335var language = BaseModel.create('language'); 8336 8337language.codes = { 8338 zh: 'cn', 8339 da: 'dk', 8340 ja: 'jp', 8341 ko: 'kr', 8342 sv: 'se' 8343}; 8344 8345language.codes_reversed = { 8346 cn: 'zh', 8347 dk: 'da', 8348 jp: 'ja', 8349 kr: 'ko', 8350 se: 'sv' 8351}; 8352 8353language.prototype.initialize = function (data) { 8354 var k; 8355 data = Array.isArray(data) ? data : [data]; 8356 for (k in data) { 8357 if (data[k].name === 'code') { 8358 data[k].value = language.codes[data[k].value] || data[k].value; 8359 } 8360 this.setData(data[k].name, BaseModel.instance('Setting').initialize(data[k])); 8361 } 8362 8363 return this; 8364}; 8365 8366language.prototype.isRTL = function () { 8367 return this.getValue('rtl') === 'true'; 8368}; 8369 8370language.prototype.getValue = function (name) { 8371 return this.getData(name).getData('value'); 8372}; 8373 8374module.exports = language; 8375 8376},{"BaseModel":"BaseModel"}],152:[function(require,module,exports){ 8377"use strict"; 8378var BaseModel = require('BaseModel'); 8379var LocalStorage = require('@icewarp/localstorage'); 8380var Settings = require('./Settings'); 8381var layout_settings = BaseModel.create('layout_settings', Settings); 8382 8383var detected_language; 8384 8385layout_settings.prototype.onCreate = function () { 8386 var config = BaseModel.instance('Config').getData('config'); 8387 [{name: 'language', value: 'en'}, 8388 {name: 'logo_uid', value: ''}, 8389 {name: 'login_background_uid', value: ''}, 8390 {name: 'login_background_color', value: ''}, 8391 {name: 'login_background_solid', value: false}, 8392 {name: 'login_background_wallpaper_size', value: 'cover'}, 8393 {name: 'login_interface_color', value: 'background'}, 8394 {name: 'login_title', value: __('title.' + config.application)}, 8395 {name: 'title', value: __('title.' + config.application)}, 8396 {name: 'skin_style', value: 'blue'}, 8397 {name: 'login_color', value: 'default'}, 8398 {name: 'website_link', value: ''}, 8399 {name: 'facebook_link', value: 'https://www.facebook.com/IceWarpInc'}, 8400 {name: 'twitter_link', value: 'https://twitter.com/icewarp'}, 8401 {name: 'linkedin_link', value: 'https://www.linkedin.com/company/IceWarp'}, 8402 {name: 'disable_copyright', value: false}, 8403 {name: 'search_phrase', value: ''} 8404 ].forEach(function (setting) { 8405 this.setData(setting.name, BaseModel.instance('Setting', setting.name).initialize(setting)); 8406 }, this); 8407}; 8408 8409/** 8410 * @returns {String} 8411 */ 8412function getBrowserLanguageCode() { 8413 var browser_languages, allowed_languages, index, language, 8414 WebClient = BaseModel.instance('WebClient'), 8415 Language = BaseModel.static('language'); 8416 if (detected_language !== void 0) { 8417 return detected_language; 8418 } 8419 browser_languages = (navigator.languages || []).concat([navigator.language || navigator.userLanguage]); 8420 allowed_languages = WebClient.getData('languages').map(function (language) { 8421 return Language.codes_reversed[language.getValue('code')] || language.getValue('code'); 8422 }); 8423 detected_language = false; 8424 for (index in browser_languages) { 8425 language = browser_languages[index].split('-')[0].toLowerCase(); 8426 if (~allowed_languages.indexOf(language)) { 8427 detected_language = language; 8428 break; 8429 } 8430 } 8431 return detected_language; 8432} 8433 8434layout_settings.prototype.getDefaultLanguageCode = function () { 8435 var WebClient = BaseModel.instance('WebClient'); 8436 return WebClient.getData('restrictions').getValue('disable_languages') ? this.getValue('language') : this.getUserLanguageCode(); 8437}; 8438 8439layout_settings.prototype.getUserLanguageCode = function () { 8440 return LocalStorage.getItem('language') || getBrowserLanguageCode() || this.getValue('language') || 'en'; 8441}; 8442 8443layout_settings.prototype.setUserLanguageCode = function (language) { 8444 LocalStorage.setItem('language', language); 8445}; 8446 8447layout_settings.prototype.getUserLanguage = function () { 8448 var i; 8449 var browser_language; 8450 var default_language; 8451 var ulc = this.getUserLanguageCode(); 8452 var blc = getBrowserLanguageCode(); 8453 var languages = BaseModel.instance('WebClient').getData('languages') || []; 8454 var lang_length = languages.length; 8455 for (i = 0; i < lang_length; i++) { 8456 switch (languages[i].getValue('code')) { 8457 case ulc: 8458 return languages[i]; 8459 case blc: 8460 browser_language = browser_language || languages[i]; 8461 break; 8462 case this.getValue('language'): 8463 default_language = default_language || languages[i]; 8464 break; 8465 } 8466 } 8467 8468 return browser_language || default_language || languages.filter(function(language) { 8469 return language.getValue('code') === 'en'; 8470 })[0] || BaseModel.instance('language').initialize([{'name': 'code', value: 'en'}, {name: 'rtl', value: false}]); 8471}; 8472 8473module.exports = layout_settings; 8474 8475},{"./Settings":148,"@icewarp/localstorage":167,"BaseModel":"BaseModel"}],153:[function(require,module,exports){ 8476"use strict"; 8477var BaseModel = require('BaseModel'); 8478var Settings = require('./Settings'); 8479var password_policy = BaseModel.create('password_policy', Settings); 8480 8481module.exports = password_policy; 8482 8483},{"./Settings":148,"BaseModel":"BaseModel"}],154:[function(require,module,exports){ 8484"use strict"; 8485var BaseModel = require('BaseModel'); 8486var Settings = require('./Settings'); 8487var reset_settings = BaseModel.create('reset_settings', Settings); 8488 8489reset_settings.prototype.onCreate = function () { 8490 [ 8491 {name: 'enabled', value: 1} 8492 ].forEach(function (setting) { 8493 this.setData(setting.name, BaseModel.instance('Setting', setting.name).initialize(setting)); 8494 }, this); 8495}; 8496 8497module.exports = reset_settings; 8498 8499},{"./Settings":148,"BaseModel":"BaseModel"}],155:[function(require,module,exports){ 8500"use strict"; 8501var BaseModel = require('BaseModel'); 8502var Settings = require('./Settings'); 8503var restrictions = BaseModel.create('restrictions', Settings); 8504 8505restrictions.prototype.onCreate = function () { 8506 [{name: 'disable_languages', value: false}, 8507 {name: 'disable_guest_signin', value: false}, 8508 {name: 'disable_signup', value: true}, 8509 {name: 'disable_signup_ip', value: false}, 8510 {name: 'disable_remember', value: false}, 8511 {name: 'disable_autofill', value: false}, 8512 {name: 'contact_support', value: true}, 8513 {name: 'disable_changepass', value: false}, 8514 {name: 'website_disabled', value: false}, 8515 {name: 'facebook_disabled', value: false}, 8516 {name: 'twitter_disabled', value: false}, 8517 {name: 'linkedin_disabled', value: false}, 8518 {name: 'show_search', value: false}, 8519 {name: 'remember_login_accounts', value: true}, 8520 ].forEach(function (setting) { 8521 this.setData(setting.name, BaseModel.instance('Setting', setting.name).initialize(setting)); 8522 }, this); 8523}; 8524module.exports = restrictions; 8525 8526},{"./Settings":148,"BaseModel":"BaseModel"}],156:[function(require,module,exports){ 8527"use strict"; 8528var BaseModel = require('BaseModel'); 8529var Setting = require('./Setting'); 8530var signup_domain = BaseModel.create('signup_domain', Setting); 8531 8532signup_domain.prototype.initialize = function (data) { 8533 var key; 8534 for (key in data) { 8535 data[key] !== null && data[key] !== void 0 && this.setData(key, parseInt(data[key]) == data[key] ? parseInt(data[key]) : data[key]); 8536 } 8537 this.setId(this.getData('value')); 8538 8539 return this; 8540}; 8541 8542module.exports = signup_domain; 8543 8544},{"./Setting":147,"BaseModel":"BaseModel"}],157:[function(require,module,exports){ 8545"use strict"; 8546module.exports={'atoms-ad-adsense':function(){return require('./_compiled/atoms-ad-adsense.js')},'atoms-ad':function(){return require('./_compiled/atoms-ad.js')},'atoms-addon':function(){return require('./_compiled/atoms-addon.js')},'atoms-avatar':function(){return require('./_compiled/atoms-avatar.js')},'atoms-element-button':function(){return require('./_compiled/atoms-element-button.js')},'atoms-dropdown':function(){return require('./_compiled/atoms-dropdown.js')},'atoms-element-input':function(){return require('./_compiled/atoms-element-input.js')},'atoms-element-textarea':function(){return require('./_compiled/atoms-element-textarea.js')},'atoms-element-select':function(){return require('./_compiled/atoms-element-select.js')},'atoms-icons':function(){return require('./_compiled/atoms-icons.js')},'atoms-info':function(){return require('./_compiled/atoms-info.js')},'atoms-image':function(){return require('./_compiled/atoms-image.js')},'atoms-label':function(){return require('./_compiled/atoms-label.js')},'atoms-link':function(){return require('./_compiled/atoms-link.js')},'atoms-loader':function(){return require('./_compiled/atoms-loader.js')},'atoms-static':function(){return require('./_compiled/atoms-static.js')},'atoms-section':function(){return require('./_compiled/atoms-section.js')},'atoms-switch':function(){return require('./_compiled/atoms-switch.js')},'atoms-tooltip':function(){return require('./_compiled/atoms-tooltip.js')},'atoms-tag':function(){return require('./_compiled/atoms-tag.js')},'atoms-video':function(){return require('./_compiled/atoms-video.js')},'meta-head':function(){return require('./_compiled/meta-head.js')},'atoms-well':function(){return require('./_compiled/atoms-well.js')},'meta-index':function(){return require('./_compiled/meta-index.js')},'molecules-captcha':function(){return require('./_compiled/molecules-captcha.js')},'molecules-button':function(){return require('./_compiled/molecules-button.js')},'molecules-input':function(){return require('./_compiled/molecules-input.js')},'molecules-checkbox':function(){return require('./_compiled/molecules-checkbox.js')},'molecules-language-picker-item':function(){return require('./_compiled/molecules-language-picker-item.js')},'molecules-language-picker':function(){return require('./_compiled/molecules-language-picker.js')},'molecules-select':function(){return require('./_compiled/molecules-select.js')},'molecules-static':function(){return require('./_compiled/molecules-static.js')},'molecules-textarea':function(){return require('./_compiled/molecules-textarea.js')},'molecules-window-header':function(){return require('./_compiled/molecules-window-header.js')},'organisms-bar':function(){return require('./_compiled/organisms-bar.js')},'organisms-card-header':function(){return require('./_compiled/organisms-card-header.js')},'organisms-card-section':function(){return require('./_compiled/organisms-card-section.js')},'organisms-window':function(){return require('./_compiled/organisms-window.js')},'sites-login':function(){return require('./_compiled/sites-login.js')},'templates-card':function(){return require('./_compiled/templates-card.js')}}; 8547},{"./_compiled/atoms-ad-adsense.js":1,"./_compiled/atoms-ad.js":2,"./_compiled/atoms-addon.js":3,"./_compiled/atoms-avatar.js":4,"./_compiled/atoms-dropdown.js":5,"./_compiled/atoms-element-button.js":6,"./_compiled/atoms-element-input.js":7,"./_compiled/atoms-element-select.js":8,"./_compiled/atoms-element-textarea.js":9,"./_compiled/atoms-icons.js":10,"./_compiled/atoms-image.js":11,"./_compiled/atoms-info.js":12,"./_compiled/atoms-label.js":13,"./_compiled/atoms-link.js":14,"./_compiled/atoms-loader.js":15,"./_compiled/atoms-section.js":16,"./_compiled/atoms-static.js":17,"./_compiled/atoms-switch.js":18,"./_compiled/atoms-tag.js":19,"./_compiled/atoms-tooltip.js":20,"./_compiled/atoms-video.js":21,"./_compiled/atoms-well.js":22,"./_compiled/meta-head.js":23,"./_compiled/meta-index.js":24,"./_compiled/molecules-button.js":25,"./_compiled/molecules-captcha.js":26,"./_compiled/molecules-checkbox.js":27,"./_compiled/molecules-input.js":28,"./_compiled/molecules-language-picker-item.js":29,"./_compiled/molecules-language-picker.js":30,"./_compiled/molecules-select.js":31,"./_compiled/molecules-static.js":32,"./_compiled/molecules-textarea.js":33,"./_compiled/molecules-window-header.js":34,"./_compiled/organisms-bar.js":35,"./_compiled/organisms-card-header.js":36,"./_compiled/organisms-card-section.js":37,"./_compiled/organisms-window.js":38,"./_compiled/sites-login.js":39,"./_compiled/templates-card.js":40}],158:[function(require,module,exports){ 8548var Request = require('request'); 8549/* 8550 * store the number of loaded CSS's 8551 * @type Number 8552 */ 8553var passed; 8554/** 8555 * store the number of CSS's to pass 8556 * @type Number 8557 */ 8558var to_pass; 8559/** 8560 * Flag for browsers supporting css variables 8561 * @type Boolean 8562 */ 8563var supports_css_variables = !!(window.CSS && window.CSS.supports && window.CSS.supports('--v', 0)); 8564 8565/** 8566 * CSS loader class 8567 */ 8568var loader = {}; 8569 8570var forced_definitions = {}; 8571 8572/** 8573 * Loads styles defined in meta name="stylesheet" head tags 8574 * @param {function} callback Callback to call after loading all styles 8575 * @param {Object} custom_definitions object with definitions to use 8576 * @returns {undefined} 8577 */ 8578loader.load = function (callback, custom_definitions) { 8579 forced_definitions = custom_definitions || forced_definitions; 8580 var metas = [].slice.call(document.head.querySelectorAll('meta[name="stylesheet"]')); 8581 passed = 0; 8582 to_pass = metas.length; 8583 if (!to_pass) { 8584 return callback && callback(); 8585 } 8586 metas.forEach(function (meta) { 8587 var uses_variables = meta.getAttribute('variables') && meta.getAttribute('variables') !== "fal
8587se"; 8588 if (!uses_variables || supports_css_variables) { 8589 createTag('link', meta.getAttribute('content'), function () { 8590 runCallback(callback); 8591 }); 8592 } else { 8593 requestCss.call(this, meta, callback); 8594 } 8595 }.bind(this)); 8596}; 8597 8598loader.setRTL = function (isRTL, callback) { 8599 [].forEach.call(document.head.querySelectorAll('meta[name="stylesheet"]'), function (meta) { 8600 var href = meta.getAttribute('content'); 8601 if (isRTL) { 8602 href = href.replace(/(\.rtl)?.css$/, '.rtl.css'); 8603 } else { 8604 href = href.replace(/.rtl.css$/, '.css'); 8605 } 8606 meta.setAttribute('content', href); 8607 }); 8608 callback && callback(); 8609}; 8610 8611/** 8612 * Substitutes css variables for their values 8613 * @param {string} cssText 8614 * @returns {string} parsed text 8615 */ 8616loader.replace = function (cssText) { 8617 cssText = cssText || ''; 8618 var match; 8619 var regExpDefinition = /(?:^|\s+)--(.+?):\s*(.+?);/g; 8620 var regExpSubstitution = /var\(--(.+?)\)/g; 8621 var repeat = true; 8622 8623 while (repeat) { 8624 var definitions = {}; 8625 while ((match = regExpDefinition.exec(cssText)) !== null) { 8626 definitions[match[1]] = match[2]; 8627 } 8628 repeat = false; 8629 cssText = cssText.replace(regExpSubstitution, function (whole, match) { 8630 repeat = true; 8631 return forced_definitions[match] || definitions[match]; 8632 }); 8633 } 8634 return cssText; 8635}; 8636 8637/** 8638 * requests css form the server 8639 * @param {DOMElement} meta meta tag 8640 * @param {function} callback 8641 * @returns {undefined} 8642 */ 8643function requestCss(meta, callback) { 8644 var url = meta.getAttribute('content'); 8645 var base = document.head.getElementsByTagName('base')[0]; 8646 base = base ? base.getAttribute('href') : ''; 8647 base = ~base.indexOf('{') ? '' : base; 8648 var version = document.querySelector('meta[name="version"]'); 8649 if (version) { 8650 version = version.getAttribute('content'); 8651 } 8652 var request = new Request({ 8653 url: base + url + (version ? '?version=' + version : ''), 8654 method: "GET" 8655 }); 8656 request.on('load', function (event, xhr) { 8657 var replace = new RegExp('(\\.\\.[/\\\\]){' + (meta.getAttribute('content').match(/\//g) || []).length + '}', 'g'); 8658 createTag('style', this.replace(xhr.responseText).replace(replace, ''), function (style) { 8659 style.setAttribute('content', url); 8660 runCallback(callback); 8661 }); 8662 }.bind(this)); 8663 request.on('error', console.error); 8664 request.on('abort', console.error); 8665 request.send(); 8666} 8667 8668/** 8669 * Appends "style" or "link" element to head 8670 * @param {string} type "style" or "link" element 8671 * @param {string} src href for "link" element and textContent for "style" element 8672 * @param {function} callback 8673 * @returns {undefined} 8674 */ 8675function createTag(type, src, callback) { 8676 var style = document.createElement(type); 8677 style.setAttribute('type', 'text/css'); 8678 switch (type) { 8679 case 'link': 8680 var version = document.querySelector('meta[name="version"]'); 8681 if (version) { 8682 version = version.getAttribute('content'); 8683 } 8684 style.setAttribute('rel', 'stylesheet'); 8685 style.setAttribute('href', src + (version ? '?version=' + version : '')); 8686 style.onload = callback; 8687 style.onerror = function () { 8688 console.error('Unable to load ' + src); 8689 callback(style); 8690 }; 8691 document.head.appendChild(style); 8692 break; 8693 case 'style': 8694 style.textContent = src; 8695 document.head.appendChild(style); 8696 callback && callback(style); 8697 } 8698} 8699 8700/** 8701 * Removes original meta element from head and calls callback if called last time 8702 * @param {function} callback 8703 * @returns {undefined} 8704 */ 8705function runCallback(callback) { 8706 (++passed === to_pass) && callback && callback(); 8707} 8708 8709module.exports = loader; 8710 8711},{"request":"request"}],159:[function(require,module,exports){ 8712/** 8713 * map of substitutions 8714 */ 8715var entity_map = { 8716 '&': '&', 8717 '<': '<', 8718 '>': '>', 8719 '"': '"', 8720 "'": ''', 8721 '/': '/', 8722 '`': '`', 8723 '=': '=' 8724}; 8725 8726/** 8727 * function to escape &<>"'`=\/ in string 8728 * @param string string to escape 8729 */ 8730var escapeString = function(string) { 8731 return String(string).replace(/[&<>"'`=/]/g, function (match) { 8732 return entity_map[match]; 8733 }); 8734}; 8735 8736/** 8737 * @module escape-string 8738 */ 8739module.exports = escapeString; 8740 8741},{}],160:[function(require,module,exports){ 8742var hashchange = require('hashchange'); 8743var Debugger = require('debugger'); 8744Debugger.addLogLevel("HASHCHANGE"); 8745 8746/** 8747 * Current site
8748 * @type String 8749 */ 8750var _site = ''; 8751 8752/** 8753 * Current hash parts 8754 * @type String[] 8755 */ 8756var _parts = {}; 8757 8758/** 8759 * Previous site 8760 * @type String 8761 */ 8762var _previous_site = ''; 8763 8764/** 8765 * Previous hash parts 8766 * @type String[] 8767 */ 8768var _previous_parts = []; 8769 8770/** 8771 * Flag to skip callback on hash change 8772 * @type Boolean 8773 */ 8774var _skip_callback = false; 8775 8776/** 8777 * @class Hash 8778 */ 8779var Hash = {}; 8780 8781/** 8782 * Set hash change function or trigger hash change event 8783 * @param {function} callback 8784 * @returns {unresolved} 8785 */ 8786Hash.update = function (callback) { 8787 return hashchange.update(callback ? function (hashFragment) { 8788 updateParts(hashFragment); 8789 Debugger.logAction({site: _site, parts: _parts}, Debugger.levels.HASHCHANGE); 8790 !_skip_callback && callback(_site, _parts, _previous_site, _previous_parts); 8791 _skip_callback = false; 8792 _previous_site = _site; 8793 _previous_parts = _parts; 8794 } : void 0); 8795}; 8796 8797/** 8798 * Change browser URL hash 8799 * @param {String} site 8800 * @param {String[]} parts 8801 * @param {Boolean} skip_callback 8802 * @param {Boolean} keep_parts 8803 * @param {String} root 8804 * @returns {Hash} 8805 */ 8806Hash.change = function (site, parts, skip_callback, keep_parts, root) { 8807 _site = site || _site; 8808 _parts = keep_parts ? Hash.getParts() : {}; 8809 if(parts) { 8810 for(var i in parts) { 8811 if(parts[i] === null) { 8812 delete _parts[i]; 8813 } else { 8814 _parts[i] = parts[i]; 8815 } 8816 } 8817 } 8818 var data = []; 8819 for (i in _parts) { 8820 data.push(encodeURIComponent(i) + (_parts[i] !== void 0 ? '=' + encodeURIComponent(_parts[i]) : '')); 8821 } 8822 Debugger.logAction({site: _site, parts: _parts}, Debugger.levels.HASHCHANGE); 8823 _skip_callback = skip_callback; 8824 if(root !== void 0) { 8825 location.replace(root + '#' + _site + (data.length ? '&' + data.join('&') : '')); 8826 } else { 8827 location.hash = _site + (data.length ? '&' + data.join('&') : ''); 8828 } 8829 return this; 8830}; 8831 8832/** 8833 * Returns current site 8834 * @returns {String} 8835 */ 8836Hash.getSite = function () { 8837 return _site; 8838}; 8839 8840/** 8841 * Returns URL hash parts 8842 * @returns {String[]} 8843 */ 8844Hash.getParts = function () { 8845 return _parts; 8846}; 8847 8848function updateParts(hashFragment) { 8849 hashFragment = hashFragment || location.hash; 8850 var parts = hashFragment.replace('#', '').split('&'); 8851 _site = ~parts[0].indexOf('=') ? '' : parts.shift(); 8852 _parts = {}; 8853 parts.forEach(function (part) { 8854 part = part.split('='); 8855 _parts[decodeURIComponent(part.splice(0, 1))] = decodeURIComponent(part.join('=')); 8856 }); 8857} 8858updateParts(); 8859 8860/** 8861 * @module Hash 8862 */ 8863module.exports = Hash; 8864 8865}
8865,{"debugger":"debugger","hashchange":362}],161:[function(require,module,exports){ 8866var Request = require('request'); 8867var logger = require('logger'); 8868var Polyglot = require('./polyglot.js'); 8869var polyglot = null; 8870 8871/** 8872 * object to store loaded languages 8873 */ 8874var language_dictionaries = {}; 8875/** 8876 * object to store supported languages 8877 */ 8878var supported_languages = { 8879 en: { 8880 direction: 'ltr', 8881 label: 'English' 8882 } 8883}; 8884 8885/** 8886 * i18n settings 8887 */ 8888var settings = {}; 8889 8890var default_locale = 'en'; 8891 8892/** 8893 * 8894 * @param {function} fn 8895 * @param {string} language 8896 * @param {Event} event 8897 * @param {XmlHttpRequest} xhr 8898 * @returns {i18n} 8899 */ 8900var loadSuccess = function (fn, language, event, xhr) { 8901 try { 8902 language_dictionaries[language] = JSON.parse(event.target.responseText); 8903 } catch (e) { 8904 // 8905 } 8906 8907 polyglot.extend(language_dictionaries[default_locale]); 8908 polyglot.extend(language_dictionaries[language]); 8909 polyglot.locale(language); 8910 fn(language); 8911 return this; 8912}; 8913 8914/** 8915 * 8916 * @param {string} error_message 8917 * @param {function} fn 8918 * @param {string} language 8919 * @param {XmlHttpRequest} xhr 8920 * @returns {unresolved} 8921 */ 8922var loadError = function (error_message, fn, language, xhr) { 8923 polyglot.locale(language); 8924 return fn ? fn(polyglot.locale()) : logger.error(error_message); 8925}; 8926 8927function compareVersions(a, b) { 8928 return compareVersions.parts(a.split('.'), b.split('.'), 0); 8929} 8930compareVersions.parts = function (a_parts, b_parts, index) { 8931 var diff; 8932 return ((a_parts.length - 1) < index && (b_parts.length - 1) < index) ? 0 : (!(diff = (+a_parts[index] || 0) - (+b_parts[index] || 0)) ? compareVersions.parts(a_parts, b_parts, index + 1) : (diff < 0 ? -1 : 1)); 8933}; 8934 8935/** 8936 * Class for frontend translations 8937 * @class i18n 8938 */ 8939function i18n() {} 8940 8941/** 8942 * Initialize i18n library 8943 * @param {object} options 8944 * @param {string} url - url of local dictionaries 8945 * @param {string} [default_locale] - ISO code of default locale 8946 * @param {string} [external_url] - url of external dictionaries (required for external dictionaries) 8947 * @param {Object} [default_locale_dictionary] - dictionary that is build in application 8948 * @param {string} [version] - version of local dictionaries (required for external dictionaries) 8949 * @param {string} [project_name] - name of project (required for external dictionaries) 8950 * @param {boolean} [options.dynamic] - switches translate function from regular to dynamic 8951 * @param {function} [callback] - callback function called on i18n initialization 8952 * @returns {i18n} 8953 */ 8954i18n.init = function (options, callback) { 8955 settings = options || {}; 8956 polyglot = new Polyglot(settings); 8957 8958 if (settings.default_locale) { 8959 default_locale = settings.default_locale; 8960 if (settings.default_locale_dictionary) { 8961 language_dictionaries[settings.default_locale] = settings.default_locale_dictionary; 8962 } 8963 } 8964 8965 supported_languages = settings.supported_languages || supported_languages; 8966 checkExternalDictionary.call(this, function () { 8967 i18n.changeLanguage(default_locale, callback); 8968 }); 8969 8970 settings.expose && (window[settings.expose] = (settings.dynamic ? i18n.tDynamic : i18n.tRegular).bind(i18n)); 8971}; 8972 8973i18n.getSupportedLanguages = function () { 8974 return supported_languages; 8975}; 8976 8977/** 8978 * @summary Check and download external dictionary, if it's missing or it's old fallback to local 8979 * @description First check if settings necessary for external loading are present. Then create request for remote dictionary version, compare this version with settings.version this property contains version of locale dictionary from app build process. If external version is higher than local download external dictionary and save that external version for that language so it's not checked another time and fallback directly to error handler. Error handler checks if there is dictionary already in memory so there will be no other xhr. 8980 * @param {function} callback 8981 * @returns {undefined} 8982 */ 8983function checkExternalDictionary(callback) { 8984 if (!settings.external_url || !settings.version) { 8985 logger.info('Missing settings for external dictionary'); 8986 return callback(); 8987 } 8988 8989 this.download(settings.external_url + '/version.json', function (event) { 8990 var version; 8991 try { 8992 version = JSON.parse(event.target.responseText).version; 8993 } catch (error) { 8994 return callback(); 8995 } 8996 if (compareVersions(version, settings.version) === 1) { 8997 settings.url = settings.external_url; 8998 this.download(settings.url + '/languages.json', function (event) { 8999 try { 9000 supported_languages = JSON.parse(event.target.responseText); 9001 } catch (e) { 9002 // 9003 } 9004 language_dictionaries = {}; 9005 callback(); 9006 }.bind(this)); 9007 } else { 9008 callback(); 9009 } 9010 }.bind(this), callback); 9011} 9012 9013i18n.download = function (url, success, error) { 9014 var options = { 9015 url: url 9016 };
9017 new Request(options) 9018 .on('load', success) 9019 .on('error', error) 9020 .send(); 9021}; 9022 9023function downloadDictionary(url, language, fn, error_fn) { 9024 fn = fn || function () {}; 9025 error_fn = error_fn || fn; 9026 this.download(url, loadSuccess.bind(this, fn, language), loadError.bind(this, error_fn, language)); 9027} 9028 9029/** 9030 * Change output language. Automatically loads new language file if not loaded yet 9031 * @param {string} language 9032 * @param {function} fn 9033 * @param {function} error_fn 9034 * @returns {i18n} 9035 */ 9036i18n.changeLanguage = function (language, fn, error_fn) { 9037 if (!supported_languages[language]) { 9038 return loadError.call(this, language + ' language not supported', error_fn || fn, language); 9039 } 9040 9041 if (language_dictionaries[language]) { 9042 polyglot.extend(language_dictionaries[default_locale]); 9043 polyglot.extend(language_dictionaries[language]); 9044 polyglot.locale(language); 9045 fn && fn(language); 9046 return; 9047 } 9048 downloadDictionary.call(this, ~settings.url.indexOf('%s') ? settings.url.replace('%s', settings.map ? settings.map[language] || language : language) : (settings.url + '/' + (settings.map ? settings.map[language] || language : language) + '.json'), language, fn, error_fn); 9049 return this; 9050}; 9051 9052/** 9053 * function to translate text 9054 * 9055 * @returns {string} 9056 */ 9057i18n.tRegular = function () { 9058 return polyglot.t.apply(polyglot, arguments); 9059}; 9060 9061/** 9062 * function to translate text, returns new lambda that will return translated string 9063 * 9064 * @returns {function} 9065 */ 9066i18n.tDynamic = function () { 9067 var args = arguments; 9068 return function () { 9069 return polyglot.t.apply(polyglot, args); 9070 }; 9071}; 9072 9073i18n.t = i18n.tRegular; 9074 9075/** 9076 * @module @icewarp/i18n 9077 * @requires @icewarp/request 9078 * @requires @icewarp/logger 9079 * @requires node-polyglot 9080 */ 9081module.exports = i18n; 9082 9083},{"./polyglot.js":163,"logger":"logger","request":"request"}],162:[function(require,module,exports){ 9084/** 9085 * function to parse MD syntax 9086 * @param input input text to parse 9087 */ 9088module.exports = function (input) { 9089 return input.replace(/(\*{1,2}|_{1,2})(.*?)\1/gi, function (match, m1, m2) { 9090 var tag = ['em', 'strong'][m1.length - 1]; 9091 return '<' + tag + '>' + m2 + '</' + tag + '>'; 9092 }).replace(/\[(.*?)\]\((.*?)\)/gi, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'); 9093}; 9094},{}],163:[function(require,module,exports){ 9095var logger = require('logger'); 9096var Escape = require('@icewarp/escape-string'); 9097var markdown = require('./markdown.js'); 9098/** 9099 * Polyglot dictionary 9100 */ 9101var phrases = {}; 9102/** 9103 * Supress errors on missing translation 9104 * @type Boolean 9105 */ 9106var allowMissing = false; 9107/** 9108 * Current locale 9109 * @type String 9110 */ 9111var current_locale = ''; 9112/** 9113 * Current plural type function 9114 * @type function 9115 */ 9116var current_plural_type = null; 9117/** 9118 * Plural forms delimiter 9119 * @type String 9120 */ 9121var delimiter = '||||'; 9122 9123var start_tag = '%{'; 9124 9125var end_tag = '}'; 9126 9127/** 9128 * Types of plural 9129 */ 9130var pluralTypes = { 9131 chinese: function (n) { 9132 return 0; 9133 }, 9134 german: function (n) { 9135 return n !== 1 ? 1 : 0; 9136 }, 9137 french: function (n) { 9138 return n > 1 ? 1 : 0; 9139 }, 9140 russian: function (n) { 9141 return n % 10 === 1 && n % 100 !== 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; 9142 }, 9143 czech: function (n) { 9144 return (n === 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2; 9145 }, 9146 polish: function (n) { 9147 return (n === 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); 9148 }, 9149 icelandic: function (n) { 9150 return (n % 10 !== 1 || n % 100 === 11) ? 1 : 0; 9151 } 9152}; 9153 9154/** 9155 * List of languages for each plural type 9156 */ 9157var pluralTypeToLanguages = { 9158 chinese: ['fa', 'id', 'ja', 'ko', 'lo', 'ms', 'th', 'tr', 'zh'], 9159 german: ['da', 'de', 'en', 'es', 'fi', 'el', 'he', 'hu', 'it', 'nl', 'no', 'pt', 'sv'], 9160 french: ['fr', 'tl', 'pt-br'], 9161 russian: ['hr', 'ru'], 9162 czech: ['cs', 'sk'], 9163 polish: ['pl'], 9164 icelandic: ['is'] 9165}; 9166 9167/** 9168 * Return type of plural for locale 9169 * @param {String} locale 9170 * @returns {String} 9171 */ 9172function pluralType(locale) { 9173 for (var type in pluralTypeToLanguages) { 9174 if (~pluralTypeToLanguages[type].indexOf(locale)) { 9175 return type; 9176 } 9177 } 9178 return 'german'; 9179} 9180 9181/** 9182 * Return index of plural form for count 9183 * @param {Number} count 9184 * @returns {Number} 9185 */ 9186function pluralIndex(count) { 9187 return pluralTypes[current_plural_type](count); 9188} 9189 9190/** 9191 * Return plural translation for text specified by count 9192 * @param {String} text 9193 * @param {Number} count 9194 * @returns {String} 9195 */ 9196function plural(text, count) { 9197 var texts = text.split(delimiter); 9198 return (texts[pluralIndex(count)] || texts[0]).trim(); 9199} 9200 9201/** 9202 * Substitute %{placeholder}'s for options[placeholder]'s 9203 * @param {String} phrase 9204 * @param {Object} options 9205 * @returns {String} 9206 */ 9207function substitute(phrase, options) { 9208 if (Array.isArray(options)) { 9209 var _options = {}; 9210 options.forEach(function (value, index) { 9211 _options[index] = value; 9212 }); 9213 options = _options; 9214 } 9215 phrase = (options.md === void 0 || options.md) ? markdown(phrase) : phrase; 9216 var escape = options.escape === void 0 ? true : options.escape; 9217 delete(options.md); 9218 delete(options.escape); 9219 for (var arg in options) { 9220 phrase = phrase.replace(new RegExp(start_tag + arg + end_tag, 'g'), escape ? Escape(options[arg]) : options[arg]); 9221 } 9222 var substitution_index = 0; 9223 phrase = phrase.replace(/%s/g, function () { 9224 return options[substitution_index++]; 9225 }); 9226 return phrase; 9227} 9228 9229/** 9230 * Polyglot class 9231 * @param {Object} options 9232 * @returns {Polyglot} 9233 */ 9234function Polyglot(options) { 9235 this.options = options || {}; 9236 allowMissing = !!options.allowMissing; 9237 options.delimiter && (delimiter = options.delimiter); 9238 options.start_tag && (start_tag = options.start_tag); 9239 options.end_tag && (end_tag = options.end_tag); 9240 this.locale(options.default_locale || 'en'); 9241 if (options.default_locale_dictionary) { 9242 this.extend(options.default_locale_dictionary); 9243 this.defaultLocaleDictionary = JSON.parse(JSON.stringify(phrases)); 9244 } 9245} 9246 9247/** 9248 * Get and/or set current_locale 9249 * @param {type} new_locale 9250 * @returns {String} current_locale 9251 */ 9252Polyglot.prototype.locale = function (new_locale) { 9253 new_locale && (current_locale = new_locale) && (current_plural_type = pluralType(current_locale)); 9254 return current_locale; 9255}; 9256 9257/** 9258 * Extend polyglot dictionary with morePhrases 9259 * @param {Object} morePhrases 9260 * @returns {Polyglot} 9261 */ 9262Polyglot.prototype.extend = function (morePhrases) { 9263 for (var key in morePhrases) { 9264 var phrase = morePhrases[key]; 9265 var prefixedKey = (arguments[1] || '') + key; 9266 if (typeof phrase === 'object') { 9267 this.extend(phrase, prefixedKey + '.'); 9268 } else { 9269 phrases[prefixedKey] = phrase; 9270 } 9271 } 9272 return this; 9273}; 9274 9275/** 9276 * Translate function 9277 * @param {String} key 9278 * @param {Object} options 9279 * @returns {String} 9280 */ 9281Polyglot.prototype.t = function (key, options, fallback) { 9282 var usedPhrases = phrases; 9283 options = (options === null || options === void 0) ? {} : (typeof options === 'number' ? {amount: options} : options); 9284 if (options.useDefaultDictionary && this.defaultLocaleDictionary) { 9285 usedPhrases = this.defaultLocaleDictionary; 9286 } 9287 if (typeof usedPhrases[key] !== 'string') { 9288 switch (typeof fallback) { 9289 case 'function': 9290 return fallback(key, options); 9291 case 'string': 9292 return fallback; 9293 } 9294 usedPhrases[key] = key; 9295 allowMissing || logger.warning('Missing translation for key: "' + key + '"'); 9296 } 9297 return substitute(plural(usedPhrases[key], options.amount === void 0 ? 1 : (+options.amount || 1)), options); 9298}; 9299 9300/** 9301 * @module Polyglot 9302 */ 9303module.exports = Polyglot; 9304 9305},{"./markdown.js":162,"@icewarp/escape-string":159,"logger":"logger"}],164:[function(require,module,exports){ 9306/** 9307 * array of objects (properties: object, index) to store their indexes 9308 */ 9309var objects = []; 9310 9311/** 9312 * Variable to store max window index 9313 * @type Number|maxIndex 9314 */ 9315var maxIndex = 0; 9316 9317/** 9318 * class to store and assign object indexes 9319 * @returns {IndexManager} 9320 */ 9321function IndexManager() {} 9322 9323/** 9324 * Add object to the storage and return its assigned index. 9325 * Index of a duplicate is overwritten by a new index 9326 * @param {object} object to store 9327 * @returns {Number} maxIndex 9328 */ 9329IndexManager.add = function (object) { 9330 if (!objects.some(function (obj) { 9331 if (obj.object === object && obj.index !== maxIndex) { 9332 obj.index = ++maxIndex; 9333 } 9334 return obj.object === object; 9335 })) { 9336 objects.push({ 9337 object: object, 9338 index: ++maxIndex 9339 }); 9340 }
9341 return maxIndex; 9342}; 9343 9344/** 9345 * Remove object from the storage and return highest index 9346 * @param {object} object to remove 9347 * @returns {Number} maxIndex 9348 */ 9349IndexManager.remove = function (object) { 9350 for (var i in objects) { 9351 if (objects[i].object === object) { 9352 objects.splice(i, 1); 9353 return maxIndex = objects.length ? maxIndex : 0; 9354 } 9355 } 9356}; 9357 9358/** 9359 * @module IndexManager 9360 * @exports IndexManager 9361 */ 9362module.exports = IndexManager; 9363 9364},{}],165:[function(require,module,exports){ 9365/** 9366 * Options for IQ setup. 9367 * @typedef {Object} IQOptions 9368 * @property {array} arguments - array of arguments to be addet to IQ tag (Optional). 9369 * @property {string} id_attr - Custom rename of ID attribute (optional). 9370 * @property {string} format - Change format of response (optional). 9371 */ 9372 9373/** 9374 * Messages ID auto increment 9375 * @type Number 9376 */ 9377var i = 1; 9378/** 9379 * Crate IQ message and handle response for it. 9380 * @class IQ 9381 * @param {IQOptions} options 9382 * @returns {IQ} 9383 */ 9384function IQ(options) { 9385 options = options || {}; 9386 /** 9387 * IQ callbacks storage 9388 * @type object 9389 */ 9390 this.iqs = {}; 9391 /** 9392 * Arguments to add to IQ 9393 * @type Array 9394 */ 9395 this.arguments = options.arguments || []; 9396 /** 9397 * Custom rename of ID attribute 9398 * @type string 9399 */ 9400 this.id_attr = options.id_attr || 'id'; 9401 /** 9402 * Change type of response 9403 * @type string 9404 */ 9405 this.format = options.format || 'text/xml'; 9406 9407 this.id = i++; 9408 9409 this.query = { 9410 arguments: [], 9411 addAttribute: function (name, value) { 9412 this.arguments.push({name: name, value: value}); 9413 return this; 9414 } 9415 }; 9416} 9417/** 9418 * Add attribute to IQ tag 9419 * @param {string} name 9420 * @param {*} value 9421 * @returns {undefined} 9422 */ 9423IQ.prototype.addAttribute = function (name, value) { 9424 this.arguments.push({name: name, value: value}); 9425 return this; 9426}; 9427/** 9428 * Create IQ message, auto increment ID and save callbacks 9429 * @param {string} body 9430 * @param {object} callback 9431 * @returns {String} 9432 */ 9433IQ.prototype.getIQ = function (body, callback) { 9434 this.iqs[this.id] = callback; 9435 return "<iq " + this.id_attr + '="' + this.id + '" ' + (this.arguments.map(function (argument) { 9436 return argument.name + '="' + argument.value + '" '; 9437 }).join(' ')) + " format=\"" + this.format + "\"><query " + (this.query.arguments.map(function (argument) { 9438 return argument.name + '="' + argument.value + '" '; 9439 }).join(' ')) + ">" + body + "</query></iq>"; 9440}; 9441/** 9442 * Process response and return callbacks by ID 9443 * @param {string} response 9444 * @returns {object} 9445 */ 9446IQ.prototype.getCallbacks = function (response, id) { 9447 var xml = new DOMParser().parseFromString(response.replace(/>\s+</g, '><'), "text/xml"); 9448 var iq; 9449 var callback; 9450 if ((iq = xml.getElementsByTagName('iq')).length) { 9451 callback = this.iqs[id || iq[0].getAttribute(this.id_attr)]; 9452 delete this.iqs[id || iq[0].getAttribute(this.id_attr)]; 9453 return {callback: callback, document: xml}; 9454 } 9455 throw new Error("Malformed message"); 9456}; 9457/** 9458 * Get IQ by it's ID 9459 * @param {number} id 9460 * @returns {object} 9461 */ 9462IQ.prototype.getCallbacksById = function (id) { 9463 return this.iqs[id]; 9464}; 9465/** 9466 * Get All pending IQs 9467 * @returns {object} 9468 */ 9469IQ.prototype.getPendingIqs = function () { 9470 return this.iqs; 9471}; 9472 9473module.exports = IQ; 9474 9475},{}],166:[function(require,module,exports){ 9476/** 9477 * @class Json 9478 */ 9479var Json = {}; 9480 9481/** 9482 * Converts JSON object to XML string 9483 * @param {object} json 9484 * @returns {string} XML string 9485 */ 9486Json.toXmlString = function(json) { 9487 if (Array.isArray(json)) { 9488 return json.map(function (item) { 9489 return this.toXmlString(item); 9490 }, this).join(''); 9491 } else if (typeof json === 'object') { 9492 return Object.keys(json).map(function (key) { 9493 return '<' + key + '>' + this.toXmlString(json[key]) + '</' + key + '>'; 9494 }, this).join(''); 9495 } 9496 return json; 9497}; 9498 9499/** 9500 * Converts JSON object to XML object 9501 * @param {object} json 9502 * @returns {object} xml 9503 */ 9504Json.toXml = function(json) { 9505 return this.XmlStringToXml(this.toXmlString(json)); 9506}; 9507 9508/** 9509 * Parses XML string to XML 9510 * @param {string} xml xml string 9511 * @returns {object} XML 9512 */ 9513Json.XmlStringToXml = function(xml) { 9514 return (new DOMParser()).parseFromString(xml, "text/xml"); 9515}; 9516 9517/** 9518 * Converts XML to JSON 9519 * @param {object} xml 9520 * @returns {object} converted json 9521 */ 9522Json.fromXml = function(xml) { 9523 var obj = {}; 9524 9525 if (xml.nodeType === 3 || (!(xml.attributes || []).length && !xml.hasChildNodes())) { 9526 return xml.nodeValue; 9527 } 9528 9529 if ((xml.attributes || []).length > 0) { 9530 obj._attributes = {}; 9531 for (var j = 0; j < xml.attributes.length; j++) { 9532 var attribute = xml.attributes.item(j);
9533 obj._attributes[attribute.nodeName] = attribute.nodeValue; 9534 } 9535 } 9536 9537 for (var i = 0; i < (xml.childNodes || []).length; i++) { 9538 var item = xml.childNodes.item(i); 9539 var nodeName = item.nodeName; 9540 if (nodeName === '#text') { 9541 if(typeof obj === 'string') { 9542 obj += this.fromXml(item); 9543 } else { 9544 obj = this.fromXml(item); 9545 } 9546 } else if (obj[nodeName] === void 0) { 9547 obj[nodeName] = this.fromXml(item); 9548 } else { 9549 if (obj[nodeName].push === void 0) { 9550 var old = obj[nodeName]; 9551 obj[nodeName] = []; 9552 obj[nodeName].push(old); 9553 } 9554 obj[nodeName].push(this.fromXml(item)); 9555 } 9556 } 9557 return obj; 9558}; 9559 9560/** 9561 * Converts XML string to JSON 9562 * @param {type} xml 9563 * @returns {unresolved} 9564 */ 9565Json.fromXmlString = function(xml) { 9566 return this.fromXml(this.XmlStringToXml(xml)); 9567}; 9568 9569/** 9570 * @module Json 9571 */ 9572module.exports = Json; 9573 9574},{}],167:[function(require,module,exports){ 9575function migrate() { 9576 for (var i = 0; i < localStorage.length; i++) { 9577 var key = localStorage.key(i); 9578 fakeEngine.setItem(key, localStorage.getItem(key)); 9579 } 9580} 9581 9582var fakeStorage = {}; 9583var fakeEngine = {}; 9584 9585fakeEngine.getItem = function (key) { 9586 return fakeStorage[key]; 9587}; 9588fakeEngine.setItem = function (key, value) { 9589 fakeStorage[key] = value; 9590}; 9591fakeEngine.removeItem = function (key) { 9592 delete(fakeStorage[key]); 9593}; 9594 9595var LocalStorage = {}; 9596LocalStorage.getItem = function (key) { 9597 var value = _engine.getItem(key); 9598 try { 9599 return JSON.parse(value); 9600 } catch (e) { 9601 return value; 9602 } 9603}; 9604LocalStorage.setItem = function (key, value) { 9605 try { 9606 _engine.setItem(key, JSON.stringify(value)); 9607 } catch (e) { 9608 if (~['QUOTA_EXCEEDED_ERR', 'NS_ERROR_DOM_QUOTA_REACHED'].indexOf(e.name) || ~e.toString().indexOf("QUOTA_EXCEEDED_ERR") || ~e.toString().indexOf("QuotaExceededError")) { 9609 _engine = fakeEngine; 9610 migrate(); 9611 return this.set(key, value); 9612 } 9613 } 9614 return this; 9615}; 9616LocalStorage.removeItem = function (key) { 9617 _engine.removeItem(key); 9618 return this; 9619}; 9620 9621LocalStorage.setEngine = function (engine) { 9622 if(!engine.getItem) { 9623 throw new Error('Engine is missing getItem function'); 9624 } 9625 if(!engine.setItem) { 9626 throw new Error('Engine is missing setItem function'); 9627 } 9628 if(!engine.removeItem) { 9629 throw new Error('Engine is missing removeItem function'); 9630 } 9631 _engine = engine; 9632}; 9633 9634var _engine = fakeEngine; 9635try { 9636 localStorage.setItem('_privateSafari', 'sucks'); 9637 _engine = localStorage; 9638 localStorage.removeItem('_privateSafari'); 9639} catch (e) { 9640 console.log('safari private'); 9641} 9642module.exports = LocalStorage; 9643 9644},{}],168:[function(require,module,exports){ 9645var IQ = require('@icewarp/iq-protocol'); 9646var Json = require('@icewarp/json-xml'); 9647var processResponse = require('./processResponse'); 9648var connections = {}; 9649var main = 'default'; 9650 9651function createConnection(type) { 9652 this.setConnection(new OldCommunication.connections[type](this.getOptions())); 9653} 9654/** 9655 * @class OldCommunication 9656 * @param {number} type type of connection XHR|Scoket 9657 * @param {string} name will be used as ke for storing this instance in global storage 9658 * @param {object} options 9659 * @returns {OldCommunication} 9660 */ 9661function OldCommunication(type, name, options) { 9662 this.host = options.host; 9663 this.email = options.email; 9664 this.subscriptions = options.subscriptions || []; 9665 this.password = options.password; 9666 this.login_type = options.login_type || OldCommunication.PLAIN; 9667 this.send_type = options.send_type || OldCommunication.XML; 9668 options.iq_options = options.iq_options || {}; 9669 options.iq_options.id_attr = options.iq_options.id_attr || 'uid'; 9670 this.iq = new IQ(options.iq_options); 9671 this.iq.query.addAttribute('xmlns', options.xmlns || "admin:iq:rpc"); 9672 options.session_id && this.iq.addAttribute('sid', options.session_id); 9673 createConnection.call(this, type); 9674 connections[name || main] = this; 9675} 9676/** 9677 * @constant 9678 * XHR connection 9679 */ 9680OldCommunication.XHR = 1; 9681/** 9682 * @constant 9683 * Socket connection 9684 */ 9685OldCommunication.SOCKET = 2; 9686/** 9687 * @type {object} 9688 * @static 9689 * @description List of connection libs 9690 */ 9691OldCommunication.connections = {}; 9692OldCommunication.connections[OldCommunication.XHR] = require('@icewarp/xhr-connection'); 9693OldCommunication.connections[OldCommunication.SOCKET] = require('socket'); 9694 9695/** 9696 * @constant 9697 * Plain auth const 9698 */ 9699OldCommunication.PLAIN = 1; 9700/** 9701 * @constant 9702 * Auth via RSA digest 9703 */ 9704OldCommunication.DIGEST = 2; 9705 9706OldCommunication.XML = 'xml'; 9707 9708/** 9709 * @static 9710 * @type {object} 9711 * Error types 9712 */ 9713OldCommunication.ERRORS = { 9714 UNSPECIFIED: 'unspecified', 9715 SERVER: 'server' 9716}; 9717 9718OldCommunication.prototype.callback = require('Callback'); 9719 9720OldCommunication.prototype.getOptions = function () { 9721 return { 9722 protocol: "xmpp", 9723 listeners: { 9724 onopen: { 9725 func: processResponse.onOpen, 9726 context: this 9727 }, 9728 onclose: { 9729 func: processResponse.onClose, 9730 context: this 9731 }, 9732 onerror: { 9733 func: processResponse.onError, 9734 context: this 9735 }, 9736 onmessage: { 9737 func: processResponse.onMessage, 9738 context: this 9739 } 9740 }, 9741 host: this.host 9742 }; 9743}; 9744 9745/** 9746 * 9747 * @param {object} json 9748 * @param {@icewarp/Callback} callback 9749 * @returns {undefined} 9750 */ 9751OldCommunication.prototype.send = function (json, callback) { 9752 this.connection.send(this.iq.getIQ(Json.toXmlString(json), callback), this.iq.id); 9753}; 9754/** 9755 * Set chosen connection instance 9756 * @param {Xhr|Socket} connection 9757 * @returns {Xhr|Socket} 9758 */ 9759OldCommunication.prototype.setConnection = function (connection) { 9760 return this.connection = connection; 9761}; 9762/** 9763 * get OldCommunication from global storage 9764 * @param {string} name 9765 * @returns {OldCommunication} 9766 */ 9767OldCommunication.getConnection = function (name) { 9768 if (!connections[name || main]) {
9769 throw new Error("Missing connection : " + name); 9770 } 9771 return connections[name || main]; 9772}; 9773 9774module.exports = OldCommunication; 9775 9776},{"./processResponse":169,"@icewarp/iq-protocol":165,"@icewarp/json-xml":166,"@icewarp/xhr-connection":181,"Callback":"Callback","socket":"socket"}],169:[function(require,module,exports){ 9777var Json = require('@icewarp/json-xml'); 9778var processResponse = {}; 9779 9780function processData(message) { 9781 var response = Json.fromXml(message.document.querySelector('iq')); 9782 if (response._attributes.type === 'error' || response.query.result === '0') { 9783 var error = message.document.querySelector('error'); 9784 return this.callback( 9785 'error', 9786 message.callback, 9787 error ? error.getAttribute('uid') || error.textContent : this.constructor.ERRORS.UNSPECIFIED, 9788 response 9789 ); 9790 } 9791 this.callback('success', message.callback, response.query.result, response); 9792} 9793 9794processResponse.onMessage = function (data, id) { 9795 processData.call(this, this.iq.getCallbacks(data, id)); 9796}; 9797processResponse.onError = function (id) { 9798 var iqs = []; 9799 if (id) { 9800 iqs = [this.iq.getCallbacksById(id)]; 9801 } else { 9802 var iqs_obj = this.iq.getPendingIqs(); 9803 for (var i in iqs_obj) { 9804 iqs.push(iqs_obj[i]); 9805 } 9806 } 9807 iqs.forEach(function (callback) { 9808 this.callback('error', callback, this.constructor.ERRORS.SERVER); 9809 }, this); 9810}; 9811processResponse.onClose = function () { 9812 9813}; 9814processResponse.onOpen = function () { 9815 9816}; 9817 9818module.exports = processResponse; 9819 9820},{"@icewarp/json-xml":166}],170:[function(require,module,exports){ 9821var QueryParams = {}; 9822QueryParams.parse = function(query) { 9823 var parts = {}; 9824 decodeURIComponent(query || location.search || '').replace(/^\?/, '').split('&').forEach(function (val) { 9825 var part = val.split('='); 9826 if(!part[0]) { 9827 return; 9828 } 9829 parts[part.splice(0, 1)] = part.join('='); 9830 }); 9831 return parts; 9832}; 9833QueryParams.stringify = function(parts) { 9834 return Object.keys(parts).map(function(key) { 9835 return encodeURIComponent(key) + '=' + encodeURIComponent(parts[key]); 9836 }).join('&'); 9837}; 9838module.exports = QueryParams; 9839},{}],171:[function(require,module,exports){ 9840// Copyright (c) 2005 Tom Wu 9841// All Rights Reserved. 9842// See "LICENSE" for details. 9843 9844// Basic JavaScript BN library - subset useful for RSA encryption. 9845 9846// Bits per digit 9847var dbits; 9848 9849// JavaScript engine analysis 9850var canary = 0xdeadbeefcafe; 9851var j_lm = ((canary & 0xffffff) == 0xefcafe); 9852 9853// (public) Constructor 9854function BigInteger(a, b, c) { 9855 if (a != null) 9856 if ("number" == typeof a) this.fromNumber(a, b, c); 9857 else if (b == null && "string" != typeof a) this.fromString(a, 256); 9858 else this.fromString(a, b); 9859} 9860 9861// return new, unset BigInteger 9862function nbi() { return new BigInteger(null); } 9863 9864// am: Compute w_j += (x*this_i), propagate carries, 9865// c is initial carry, returns final carry. 9866// c < 3*dvalue, x < 2*dvalue, this_i < dvalue 9867// We need to select the fastest one that works in this environment. 9868 9869// am1: use a single mult and divide to get the high bits, 9870// max digit bits should be 26 because 9871// max internal value = 2*dvalue^2-2*dvalue (< 2^53) 9872function am1(i, x, w, j, c, n) { 9873 while (--n >= 0) { 9874 var v = x * this[i++] + w[j] + c; 9875 c = Math.floor(v / 0x4000000); 9876 w[j++] = v & 0x3ffffff; 9877 } 9878 return c; 9879} 9880// am2 avoids a big mult-and-extract completely. 9881// Max digit bits should be <= 30 because we do bitwise ops 9882// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) 9883function am2(i, x, w, j, c, n) { 9884 var xl = x & 0x7fff, xh = x >> 15; 9885 while (--n >= 0) { 9886 var l = this[i] & 0x7fff; 9887 var h = this[i++] >> 15; 9888 var m = xh * l + h * xl; 9889 l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); 9890 c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); 9891 w[j++] = l & 0x3fffffff; 9892 } 9893 return c; 9894} 9895// Alternately, set max digit bits to 28 since some 9896// browsers slow down when dealing with 32-bit numbers. 9897function am3(i, x, w, j, c, n) { 9898 var xl = x & 0x3fff, xh = x >> 14; 9899 while (--n >= 0) { 9900 var l = this[i] & 0x3fff; 9901 var h = this[i++] >> 14; 9902 var m = xh * l + h * xl; 9903 l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; 9904 c = (l >> 28) + (m >> 14) + xh * h; 9905 w[j++] = l & 0xfffffff; 9906 } 9907 return c; 9908} 9909if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) { 9910 BigInteger.prototype.am = am2; 9911 dbits = 30; 9912} 9913else if (j_lm && (navigator.appName != "Netscape")) { 9914 BigInteger.prototype.am = am1; 9915 dbits = 26; 9916} 9917else { // Mozilla/Netscape seems to prefer am3 9918 BigInteger.prototype.am = am3; 9919 dbits = 28; 9920} 9921 9922BigInteger.prototype.DB = dbits;
vendor: 14,717 bytes, lines 9923-10416
9923BigInteger.prototype.DM = ((1 << dbits) - 1); 9924BigInteger.prototype.DV = (1 << dbits); 9925 9926var BI_FP = 52; 9927BigInteger.prototype.FV = Math.pow(2, BI_FP); 9928BigInteger.prototype.F1 = BI_FP - dbits; 9929BigInteger.prototype.F2 = 2 * dbits - BI_FP; 9930 9931// Digit conversions 9932var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; 9933var BI_RC = new Array(); 9934var rr, vv; 9935rr = "0".charCodeAt(0); 9936for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; 9937rr = "a".charCodeAt(0); 9938for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; 9939rr = "A".charCodeAt(0); 9940for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; 9941 9942function int2char(n) { return BI_RM.charAt(n); } 9943function intAt(s, i) { 9944 var c = BI_RC[s.charCodeAt(i)]; 9945 return (c == null) ? -1 : c; 9946} 9947 9948// (protected) copy this to r 9949function bnpCopyTo(r) { 9950 for (var i = this.t - 1; i >= 0; --i) r[i] = this[i]; 9951 r.t = this.t; 9952 r.s = this.s; 9953} 9954 9955// (protected) set from integer value x, -DV <= x < DV 9956function bnpFromInt(x) { 9957 this.t = 1; 9958 this.s = (x < 0) ? -1 : 0; 9959 if (x > 0) this[0] = x; 9960 else if (x < -1) this[0] = x + this.DV; 9961 else this.t = 0; 9962} 9963 9964// return bigint initialized to value 9965function nbv(i) { var r = nbi(); r.fromInt(i); return r; } 9966 9967// (protected) set from string and radix 9968function bnpFromString(s, b) { 9969 var k; 9970 if (b == 16) k = 4; 9971 else if (b == 8) k = 3; 9972 else if (b == 256) k = 8; // byte array 9973 else if (b == 2) k = 1; 9974 else if (b == 32) k = 5; 9975 else if (b == 4) k = 2; 9976 else { this.fromRadix(s, b); return; } 9977 this.t = 0; 9978 this.s = 0; 9979 var i = s.length, mi = false, sh = 0; 9980 while (--i >= 0) { 9981 var x = (k == 8) ? s[i] & 0xff : intAt(s, i); 9982 if (x < 0) { 9983 if (s.charAt(i) == "-") mi = true; 9984 continue; 9985 } 9986 mi = false; 9987 if (sh == 0) 9988 this[this.t++] = x; 9989 else if (sh + k > this.DB) { 9990 this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; 9991 this[this.t++] = (x >> (this.DB - sh)); 9992 } 9993 else 9994 this[this.t - 1] |= x << sh; 9995 sh += k; 9996 if (sh >= this.DB) sh -= this.DB; 9997 } 9998 if (k == 8 && (s[0] & 0x80) != 0) { 9999 this.s = -1; 10000 if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh; 10001 } 10002 this.clamp(); 10003 if (mi) BigInteger.ZERO.subTo(this, this); 10004} 10005 10006// (protected) clamp off excess high words 10007function bnpClamp() { 10008 var c = this.s & this.DM; 10009 while (this.t > 0 && this[this.t - 1] == c) --this.t; 10010} 10011 10012// (public) return string representation in given radix 10013function bnToString(b) { 10014 if (this.s < 0) return "-" + this.negate().toString(b); 10015 var k; 10016 if (b == 16) k = 4; 10017 else if (b == 8) k = 3; 10018 else if (b == 2) k = 1; 10019 else if (b == 32) k = 5; 10020 else if (b == 4) k = 2; 10021 else return this.toRadix(b); 10022 var km = (1 << k) - 1, d, m = false, r = "", i = this.t; 10023 var p = this.DB - (i * this.DB) % k; 10024 if (i-- > 0) { 10025 if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d); } 10026 while (i >= 0) { 10027 if (p < k) { 10028 d = (this[i] & ((1 << p) - 1)) << (k - p); 10029 d |= this[--i] >> (p += this.DB - k); 10030 } 10031 else { 10032 d = (this[i] >> (p -= k)) & km; 10033 if (p <= 0) { p += this.DB; --i; } 10034 } 10035 if (d > 0) m = true; 10036 if (m) r += int2char(d); 10037 } 10038 } 10039 return m ? r : "0"; 10040} 10041 10042// (public) -this 10043function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; } 10044 10045// (public) |this| 10046function bnAbs() { return (this.s < 0) ? this.negate() : this; } 10047 10048// (public) return + if this > a, - if this < a, 0 if equal 10049function bnCompareTo(a) { 10050 var r = this.s - a.s; 10051 if (r != 0) return r; 10052 var i = this.t; 10053 r = i - a.t; 10054 if (r != 0) return (this.s < 0) ? -r : r; 10055 while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; 10056 return 0; 10057} 10058 10059// returns bit length of the integer x 10060function nbits(x) { 10061 var r = 1, t; 10062 if ((t = x >>> 16) != 0) { x = t; r += 16; } 10063 if ((t = x >> 8) != 0) { x = t; r += 8; } 10064 if ((t = x >> 4) != 0) { x = t; r += 4; } 10065 if ((t = x >> 2) != 0) { x = t; r += 2; } 10066 if ((t = x >> 1) != 0) { x = t; r += 1; } 10067 return r; 10068} 10069 10070// (public) return the number of bits in "this" 10071function bnBitLength() { 10072 if (this.t <= 0) return 0; 10073 return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)); 10074} 10075 10076// (protected) r = this << n*DB 10077function bnpDLShiftTo(n, r) { 10078 var i; 10079 for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i]; 10080 for (i = n - 1; i >= 0; --i) r[i] = 0; 10081 r.t = this.t + n; 10082 r.s = this.s; 10083} 10084 10085// (protected) r = this >> n*DB 10086function bnpDRShiftTo(n, r) { 10087 for (var i = n; i < this.t; ++i) r[i - n] = this[i]; 10088 r.t = Math.max(this.t - n, 0); 10089 r.s = this.s; 10090} 10091 10092// (protected) r = this << n 10093function bnpLShiftTo(n, r) { 10094 var bs = n % this.DB; 10095 var cbs = this.DB - bs; 10096 var bm = (1 << cbs) - 1; 10097 var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i; 10098 for (i = this.t - 1; i >= 0; --i) { 10099 r[i + ds + 1] = (this[i] >> cbs) | c; 10100 c = (this[i] & bm) << bs; 10101 } 10102 for (i = ds - 1; i >= 0; --i) r[i] = 0; 10103 r[ds] = c; 10104 r.t = this.t + ds + 1; 10105 r.s = this.s; 10106 r.clamp(); 10107} 10108 10109// (protected) r = this >> n 10110function bnpRShiftTo(n, r) { 10111 r.s = this.s; 10112 var ds = Math.floor(n / this.DB); 10113 if (ds >= this.t) { r.t = 0; return; } 10114 var bs = n % this.DB; 10115 var cbs = this.DB - bs; 10116 var bm = (1 << bs) - 1; 10117 r[0] = this[ds] >> bs; 10118 for (var i = ds + 1; i < this.t; ++i) { 10119 r[i - ds - 1] |= (this[i] & bm) << cbs; 10120 r[i - ds] = this[i] >> bs; 10121 } 10122 if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; 10123 r.t = this.t - ds; 10124 r.clamp(); 10125} 10126 10127// (protected) r = this - a 10128function bnpSubTo(a, r) { 10129 var i = 0, c = 0, m = Math.min(a.t, this.t); 10130 while (i < m) { 10131 c += this[i] - a[i]; 10132 r[i++] = c & this.DM; 10133 c >>= this.DB; 10134 } 10135 if (a.t < this.t) { 10136 c -= a.s; 10137 while (i < this.t) { 10138 c += this[i]; 10139 r[i++] = c & this.DM; 10140 c >>= this.DB; 10141 } 10142 c += this.s; 10143 } 10144 else { 10145 c += this.s; 10146 while (i < a.t) { 10147 c -= a[i]; 10148 r[i++] = c & this.DM; 10149 c >>= this.DB; 10150 } 10151 c -= a.s; 10152 } 10153 r.s = (c < 0) ? -1 : 0; 10154 if (c < -1) r[i++] = this.DV + c; 10155 else if (c > 0) r[i++] = c; 10156 r.t = i; 10157 r.clamp(); 10158} 10159 10160// (protected) r = this * a, r != this,a (HAC 14.12) 10161// "this" should be the larger one if appropriate. 10162function bnpMultiplyTo(a, r) { 10163 var x = this.abs(), y = a.abs(); 10164 var i = x.t; 10165 r.t = i + y.t; 10166 while (--i >= 0) r[i] = 0; 10167 for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); 10168 r.s = 0; 10169 r.clamp(); 10170 if (this.s != a.s) BigInteger.ZERO.subTo(r, r); 10171} 10172 10173// (protected) r = this^2, r != this (HAC 14.16) 10174function bnpSquareTo(r) { 10175 var x = this.abs(); 10176 var i = r.t = 2 * x.t; 10177 while (--i >= 0) r[i] = 0; 10178 for (i = 0; i < x.t - 1; ++i) { 10179 var c = x.am(i, x[i], r, 2 * i, 0, 1); 10180 if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { 10181 r[i + x.t] -= x.DV; 10182 r[i + x.t + 1] = 1; 10183 } 10184 } 10185 if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); 10186 r.s = 0; 10187 r.clamp(); 10188} 10189 10190// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) 10191// r != q, this != m. q or r may be null. 10192function bnpDivRemTo(m, q, r) { 10193 var pm = m.abs(); 10194 if (pm.t <= 0) return; 10195 var pt = this.abs(); 10196 if (pt.t < pm.t) { 10197 if (q != null) q.fromInt(0); 10198 if (r != null) this.copyTo(r); 10199 return; 10200 } 10201 if (r == null) r = nbi(); 10202 var y = nbi(), ts = this.s, ms = m.s; 10203 var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus 10204 if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); } 10205 else { pm.copyTo(y); pt.copyTo(r); } 10206 var ys = y.t; 10207 var y0 = y[ys - 1]; 10208 if (y0 == 0) return; 10209 var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0); 10210 var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2; 10211 var i = r.t, j = i - ys, t = (q == null) ? nbi() : q; 10212 y.dlShiftTo(j, t); 10213 if (r.compareTo(t) >= 0) { 10214 r[r.t++] = 1; 10215 r.subTo(t, r); 10216 } 10217 BigInteger.ONE.dlShiftTo(ys, t); 10218 t.subTo(y, y); // "negative" y so we can replace sub with am later 10219 while (y.t < ys) y[y.t++] = 0; 10220 while (--j >= 0) { 10221 // Estimate quotient digit 10222 var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); 10223 if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out 10224 y.dlShiftTo(j, t); 10225 r.subTo(t, r); 10226 while (r[i] < --qd) r.subTo(t, r); 10227 } 10228 } 10229 if (q != null) { 10230 r.drShiftTo(ys, q); 10231 if (ts != ms) BigInteger.ZERO.subTo(q, q); 10232 } 10233 r.t = ys; 10234 r.clamp(); 10235 if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder 10236 if (ts < 0) BigInteger.ZERO.subTo(r, r); 10237} 10238 10239// (public) this mod a 10240function bnMod(a) { 10241 var r = nbi(); 10242 this.abs().divRemTo(a, null, r); 10243 if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); 10244 return r; 10245} 10246 10247// Modular reduction using "classic" algorithm 10248function Classic(m) { this.m = m; } 10249function cConvert(x) { 10250 if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); 10251 else return x; 10252} 10253function cRevert(x) { return x; } 10254function cReduce(x) { x.divRemTo(this.m, null, x); } 10255function cMulTo(x, y, r) { x.multiplyTo(y, r); this.reduce(r); } 10256function cSqrTo(x, r) { x.squareTo(r); this.reduce(r); } 10257 10258Classic.prototype.convert = cConvert; 10259Classic.prototype.revert = cRevert; 10260Classic.prototype.reduce = cReduce; 10261Classic.prototype.mulTo = cMulTo; 10262Classic.prototype.sqrTo = cSqrTo; 10263 10264// (protected) return "-1/this % 2^DB"; useful for Mont. reduction 10265// justification: 10266// xy == 1 (mod m) 10267// xy = 1+km 10268// xy(2-xy) = (1+km)(1-km) 10269// x[y(2-xy)] = 1-k^2m^2 10270// x[y(2-xy)] == 1 (mod m^2) 10271// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 10272// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. 10273// JS multiply "overflows" differently from C/C++, so care is needed here. 10274function bnpInvDigit() { 10275 if (this.t < 1) return 0; 10276 var x = this[0]; 10277 if ((x & 1) == 0) return 0; 10278 var y = x & 3; // y == 1/x mod 2^2 10279 y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4 10280 y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8 10281 y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16 10282 // last step - calculate inverse mod DV directly; 10283 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints 10284 y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits 10285 // we really want the negative inverse, and -DV < y < DV 10286 return (y > 0) ? this.DV - y : -y; 10287} 10288 10289// Montgomery reduction 10290function Montgomery(m) { 10291 this.m = m; 10292 this.mp = m.invDigit(); 10293 this.mpl = this.mp & 0x7fff; 10294 this.mph = this.mp >> 15; 10295 this.um = (1 << (m.DB - 15)) - 1; 10296 this.mt2 = 2 * m.t; 10297} 10298 10299// xR mod m 10300function montConvert(x) { 10301 var r = nbi(); 10302 x.abs().dlShiftTo(this.m.t, r); 10303 r.divRemTo(this.m, null, r); 10304 if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); 10305 return r; 10306} 10307 10308// x/R mod m 10309function montRevert(x) { 10310 var r = nbi(); 10311 x.copyTo(r); 10312 this.reduce(r); 10313 return r; 10314} 10315 10316// x = x/R mod m (HAC 14.32) 10317function montReduce(x) { 10318 while (x.t <= this.mt2) // pad x so am has enough room later 10319 x[x.t++] = 0; 10320 for (var i = 0; i < this.m.t; ++i) { 10321 // faster way of calculating u0 = x[i]*mp mod DV 10322 var j = x[i] & 0x7fff; 10323 var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; 10324 // use am to combine the multiply-shift-add into one call 10325 j = i + this.m.t; 10326 x[j] += this.m.am(0, u0, x, i, 0, this.m.t); 10327 // propagate carry 10328 while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } 10329 } 10330 x.clamp(); 10331 x.drShiftTo(this.m.t, x); 10332 if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); 10333} 10334 10335// r = "x^2/R mod m"; x != r 10336function montSqrTo(x, r) { x.squareTo(r); this.reduce(r); } 10337 10338// r = "xy/R mod m"; x,y != r 10339function montMulTo(x, y, r) { x.multiplyTo(y, r); this.reduce(r); } 10340 10341Montgomery.prototype.convert = montConvert; 10342Montgomery.prototype.revert = montRevert; 10343Montgomery.prototype.reduce = montReduce; 10344Montgomery.prototype.mulTo = montMulTo; 10345Montgomery.prototype.sqrTo = montSqrTo; 10346 10347// (protected) true iff this is even 10348function bnpIsEven() { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; } 10349 10350// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) 10351function bnpExp(e, z) { 10352 if (e > 0xffffffff || e < 1) return BigInteger.ONE; 10353 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1; 10354 g.copyTo(r); 10355 while (--i >= 0) { 10356 z.sqrTo(r, r2); 10357 if ((e & (1 << i)) > 0) z.mulTo(r2, g, r); 10358 else { var t = r; r = r2; r2 = t; } 10359 } 10360 return z.revert(r); 10361} 10362 10363// (public) this^e % m, 0 <= e < 2^32 10364function bnModPowInt(e, m) { 10365 var z; 10366 if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); 10367 return this.exp(e, z); 10368} 10369 10370// protected 10371BigInteger.prototype.copyTo = bnpCopyTo; 10372BigInteger.prototype.fromInt = bnpFromInt; 10373BigInteger.prototype.fromString = bnpFromString; 10374BigInteger.prototype.clamp = bnpClamp; 10375BigInteger.prototype.dlShiftTo = bnpDLShiftTo; 10376BigInteger.prototype.drShiftTo = bnpDRShiftTo; 10377BigInteger.prototype.lShiftTo = bnpLShiftTo; 10378BigInteger.prototype.rShiftTo = bnpRShiftTo; 10379BigInteger.prototype.subTo = bnpSubTo; 10380BigInteger.prototype.multiplyTo = bnpMultiplyTo; 10381BigInteger.prototype.squareTo = bnpSquareTo; 10382BigInteger.prototype.divRemTo = bnpDivRemTo; 10383BigInteger.prototype.invDigit = bnpInvDigit; 10384BigInteger.prototype.isEven = bnpIsEven; 10385BigInteger.prototype.exp = bnpExp; 10386 10387// public 10388BigInteger.prototype.toString = bnToString; 10389BigInteger.prototype.negate = bnNegate; 10390BigInteger.prototype.abs = bnAbs; 10391BigInteger.prototype.compareTo = bnCompareTo; 10392BigInteger.prototype.bitLength = bnBitLength; 10393BigInteger.prototype.mod = bnMod; 10394BigInteger.prototype.modPowInt = bnModPowInt; 10395 10396// "constants" 10397BigInteger.ZERO = nbv(0); 10398BigInteger.ONE = nbv(1); 10399 10400module.exports = BigInteger; 10401},{}],172:[function(require,module,exports){ 10402// prng4.js - uses Arcfour as a PRNG 10403 10404function Arcfour() { 10405 this.i = 0; 10406 this.j = 0; 10407 this.S = new Array(); 10408} 10409 10410// Initialize arcfour context from key, an array of ints, each from [0..255] 10411function ARC4init(key) { 10412 var i, j, t; 10413 for (i = 0; i < 256; ++i) 10414 this.S[i] = i; 10415 j = 0; 10416 for (i = 0; i < 256; ++i) {
10417 j = (j + this.S[i] + key[i % key.length]) & 255; 10418 t = this.S[i]; 10419 this.S[i] = this.S[j]; 10420 this.S[j] = t; 10421 } 10422 this.i = 0; 10423 this.j = 0; 10424} 10425 10426function ARC4next() { 10427 var t; 10428 this.i = (this.i + 1) & 255; 10429 this.j = (this.j + this.S[this.i]) & 255; 10430 t = this.S[this.i]; 10431 this.S[this.i] = this.S[this.j]; 10432 this.S[this.j] = t; 10433 return this.S[(t + this.S[this.i]) & 255]; 10434} 10435 10436Arcfour.prototype.init = ARC4init; 10437Arcfour.prototype.next = ARC4next; 10438 10439// Plug in your RNG constructor here 10440function prng_newstate() { 10441 return new Arcfour(); 10442} 10443 10444// Pool size must be a multiple of 4 and greater than 32. 10445// An array of bytes the size of the pool will be passed to init() 10446var rng_psize = 256; 10447 10448module.exports = { 10449 prng_newstate: prng_newstate, 10450 rng_psize: rng_psize 10451}; 10452},{}],173:[function(require,module,exports){ 10453// Random number generator - requires a PRNG backend, e.g. prng4.js 10454var prng4 = require('./prng4'); 10455var prng_newstate = prng4.prng_newstate; 10456var rng_psize = prng4.rng_psize; 10457 10458// For best results, put code like 10459// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'> 10460// in your main HTML document. 10461 10462var rng_state; 10463var rng_pool; 10464var rng_pptr; 10465 10466// Mix in a 32-bit integer into the pool 10467function rng_seed_int(x) { 10468 rng_pool[rng_pptr++] ^= x & 255; 10469 rng_pool[rng_pptr++] ^= (x >> 8) & 255; 10470 rng_pool[rng_pptr++] ^= (x >> 16) & 255; 10471 rng_pool[rng_pptr++] ^= (x >> 24) & 255; 10472 if (rng_pptr >= rng_psize) rng_pptr -= rng_psize; 10473} 10474 10475// Mix in the current time (w/milliseconds) into the pool 10476function rng_seed_time() { 10477 rng_seed_int(new Date().getTime()); 10478} 10479 10480// Initialize the pool with junk if needed. 10481if (rng_pool == null) { 10482 rng_pool = new Array(); 10483 rng_pptr = 0; 10484 var t; 10485 if (window.crypto && window.crypto.getRandomValues) { 10486 // Use webcrypto if available 10487 var ua = new Uint8Array(32); 10488 window.crypto.getRandomValues(ua); 10489 for (t = 0; t < 32; ++t) 10490 rng_pool[rng_pptr++] = ua[t]; 10491 } 10492 if (navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) { 10493 // Extract entropy (256 bits) from NS4 RNG if available 10494 var z = window.crypto.random(32); 10495 for (t = 0; t < z.length; ++t) 10496 rng_pool[rng_pptr++] = z.charCodeAt(t) & 255; 10497 } 10498 while (rng_pptr < rng_psize) { // extract some randomness from Math.random() 10499 t = Math.floor(65536 * Math.random()); 10500 rng_pool[rng_pptr++] = t >>> 8; 10501 rng_pool[rng_pptr++] = t & 255; 10502 } 10503 rng_pptr = 0; 10504 rng_seed_time(); 10505 //rng_seed_int(window.screenX); 10506 //rng_seed_int(window.screenY); 10507} 10508 10509function rng_get_byte() { 10510 if (rng_state == null) { 10511 rng_seed_time(); 10512 rng_state = prng_newstate(); 10513 rng_state.init(rng_pool); 10514 for (rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) 10515 rng_pool[rng_pptr] = 0; 10516 rng_pptr = 0; 10517 //rng_pool = null; 10518 } 10519 // TODO: allow reseeding after first request 10520 return rng_state.next(); 10521} 10522 10523function rng_get_bytes(ba) { 10524 var i; 10525 for (i = 0; i < ba.length; ++i) ba[i] = rng_get_byte(); 10526} 10527 10528function SecureRandom() { } 10529 10530SecureRandom.prototype.nextBytes = rng_get_bytes; 10531 10532module.exports = SecureRandom; 10533},{"./prng4":172}],174:[function(require,module,exports){ 10534// Depends on jsbn.js and rng.js 10535var BigInteger = require('./jsbn'); 10536var SecureRandom = require('./rng'); 10537 10538// Version 1.1: support utf-8 encoding in pkcs1pad2 10539 10540// convert a (hex) string to a bignum object 10541function parseBigInt(str, r) { 10542 return new BigInteger(str, r); 10543} 10544 10545function linebrk(s, n) { 10546 var ret = ""; 10547 var i = 0; 10548 while (i + n < s.length) { 10549 ret += s.substring(i, i + n) + "\n"; 10550 i += n; 10551 } 10552 return ret + s.substring(i, s.length); 10553} 10554 10555function byte2Hex(b) { 10556 if (b < 0x10) 10557 return "0" + b.toString(16); 10558 else 10559 return b.toString(16); 10560} 10561 10562// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint 10563function pkcs1pad2(s, n) {
10564 if (n < s.length + 11) { // TODO: fix for utf-8 10565 alert("Message too long for RSA"); 10566 return null; 10567 } 10568 var ba = new Array(); 10569 var i = s.length - 1; 10570 while (i >= 0 && n > 0) { 10571 var c = s.charCodeAt(i--); 10572 if (c < 128) { // encode using utf-8 10573 ba[--n] = c; 10574 } 10575 else if ((c > 127) && (c < 2048)) { 10576 ba[--n] = (c & 63) | 128; 10577 ba[--n] = (c >> 6) | 192; 10578 } 10579 else { 10580 ba[--n] = (c & 63) | 128; 10581 ba[--n] = ((c >> 6) & 63) | 128; 10582 ba[--n] = (c >> 12) | 224; 10583 } 10584 } 10585 ba[--n] = 0; 10586 var rng = new SecureRandom(); 10587 var x = new Array(); 10588 while (n > 2) { // random non-zero pad 10589 x[0] = 0; 10590 while (x[0] == 0) rng.nextBytes(x); 10591 ba[--n] = x[0]; 10592 } 10593 ba[--n] = 2; 10594 ba[--n] = 0; 10595 return new BigInteger(ba); 10596} 10597 10598// "empty" RSA key constructor 10599function RSAKey() { 10600 this.n = null; 10601 this.e = 0; 10602 this.d = null; 10603 this.p = null; 10604 this.q = null; 10605 this.dmp1 = null; 10606 this.dmq1 = null; 10607 this.coeff = null; 10608} 10609 10610// Set the public key fields N and e from hex strings 10611function RSASetPublic(N, E) { 10612 if (N != null && E != null && N.length > 0 && E.length > 0) { 10613 this.n = parseBigInt(N, 16); 10614 this.e = parseInt(E, 16); 10615 } 10616 else 10617 alert("Invalid RSA public key"); 10618} 10619 10620// Perform raw public operation on "x": return x^e (mod n) 10621function RSADoPublic(x) { 10622 return x.modPowInt(this.e, this.n); 10623} 10624 10625// Return the PKCS#1 RSA encryption of "text" as an even-length hex string 10626function RSAEncrypt(text) { 10627 var m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3); 10628 if (m == null) return null; 10629 var c = this.doPublic(m); 10630 if (c == null) return null; 10631 var h = c.toString(16); 10632 if ((h.length & 1) == 0) return h; else return "0" + h; 10633} 10634 10635// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string 10636//function RSAEncryptB64(text) { 10637// var h = this.encrypt(text); 10638// if(h) return hex2b64(h); else return null; 10639//} 10640 10641// protected 10642RSAKey.prototype.doPublic = RSADoPublic; 10643 10644// public 10645RSAKey.prototype.setPublic = RSASetPublic; 10646RSAKey.prototype.encrypt = RSAEncrypt; 10647//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; 10648 10649module.exports = RSAKey; 10650},{"./jsbn":171,"./rng":173}],175:[function(require,module,exports){ 10651var StringUtils = require('./string.js'); 10652var Utils = {}; 10653 10654var supress_animations = false; 10655/** 10656 * Supress animations 10657 */ 10658Utils.supress = function () { 10659 document.body.classList.add('no-animation'); 10660 supress_animations = true; 10661}; 10662 10663/** 10664 * Allow animations 10665 */ 10666Utils.allow = function () { 10667 document.body.classList.remove('no-animation'); 10668 supress_animations = false; 10669}; 10670 10671/** 10672 * Returns whether animations are enabled 10673 * @returns {Boolean} 10674 */ 10675Utils.allowed = function () { 10676 return !supress_animations; 10677}; 10678 10679/** 10680 * Return supported browser event type 10681 * @param {String} event 10682 * @returns {String|Boolean} Supported event type or false 10683 */ 10684Utils.browserEvent = function (event) { 10685 if (!this.allowed()) { 10686 return false; 10687 } 10688 if (('on' + event) in window || event.replace(/end|start|update$/, '') in document.body.style) { 10689 return event; 10690 } 10691 if (('onwebkit' + event) in window) { 10692 return 'webkit' + StringUtils.capitalize(event[0]).replace(/(end|start|update)$/, StringUtils.capitalize); 10693 } 10694 return false; 10695}; 10696 10697module.exports = Utils; 10698},{"./string.js":179}],176:[function(require,module,exports){ 10699var Utils = {}; 10700 10701/** 10702 * Detect if the browser is IE 9+ 10703 * @returns {Boolean} 10704 */ 10705Utils.isIE = function () { 10706 return !!(window.ActiveXObject || "ActiveXObject" in window); 10707}; 10708 10709/** 10710 * Detect if the browser is MS Edge 10711 * @returns {Boolean} 10712 */ 10713Utils.isEdge = function () { 10714 return !Utils.isIE() && !!window.StyleMedia; 10715}; 10716 10717module.exports = Utils; 10718},{}],177:[function(require,module,exports){ 10719var Utils = {}; 10720 10721/** 10722 * Push items from arr array to data object 10723 * @param {*} data 10724 * @param {*} arr 10725 * @returns {Utils.push.data} 10726 */ 10727Utils.push = function (data, arr) { 10728 data = data || []; 10729 [].push.apply(data, Array.isArray(arr) ? arr : [arr]); 10730 data = data.filter(function (value, index) { 10731 return value !== void 0 && data.indexOf(value) === index; 10732 }); 10733 return data; 10734}; 10735 10736/** 10737 * Push items from arr array to data property 10738 * @param {Object} data 10739 * @param {String} property 10740 * @param {*} arr 10741 * @returns {Array} 10742 */ 10743Utils.pushToProperty = function (data, property, arr) { 10744 if (data === void 0) { 10745 return data; 10746 } 10747 data[property] = data[property] || []; 10748 [].push.apply(data[property], Array.isArray(arr) ? arr : [arr]); 10749 data[property] = data[property].filter(function (value, index) { 10750 return value !== void 0 && data[property].indexOf(value) === index; 10751 }); 10752 return data; 10753}; 10754 10755Utils.splice = function (array, item) { 10756 if (!Array.isArray(array)) { 10757 return false;
10758 } 10759 if (Array.isArray(item)) { 10760 return item.forEach(function (i) { 10761 Utils.splice(array, i); 10762 }); 10763 } 10764 array.splice(array.indexOf(item), 1); 10765}; 10766 10767module.exports = Utils; 10768},{}],178:[function(require,module,exports){ 10769var Utils = {}; 10770 10771Utils.enabled = function () { 10772 return document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled; 10773}; 10774 10775Utils.element = function () { 10776 return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement; 10777}; 10778 10779Utils.exit = function () { 10780 (document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen || function () {}).bind(document)(); 10781}; 10782 10783Utils.request = function (element) { 10784 (element.requestFullscreen || element.webkitRequestFullscreen || element.mozRequestFullScreen || element.msRequestFullscreen || function () {}).bind(element)(); 10785}; 10786 10787module.exports = Utils; 10788},{}],179:[function(require,module,exports){ 10789var Utils = {}; 10790var accentMap; 10791 10792/** 10793 * Capitalize string 10794 * @param {String} string 10795 * @returns {String} capitalized string 10796 */ 10797Utils.capitalize = function (string) { 10798 return string[0].toUpperCase() + string.slice(1); 10799}; 10800 10801/** 10802 * Escape HTML entities &<>"' 10803 * @param {String} unsafe unescaped string 10804 * @returns {String} escaped string 10805 */ 10806Utils.escapeHtml = function (unsafe) { 10807 return unsafe 10808 .replace(/&/g, "&") 10809 .replace(/</g, "<") 10810 .replace(/>/g, ">") 10811 .replace(/"/g, """) 10812 .replace(/'/g, "'"); 10813}; 10814 10815/** 10816 * Remove accents from input string 10817 * @param {String} input 10818 * @returns String 10819 */ 10820Utils.removeAccents = function (input) { 10821 return input.replace(/[^A-Za-z0-9\s]/g, function (a) { 10822 accentMap = accentMap || buildAccentMap(); 10823 return accentMap[a] || a; 10824 }); 10825}; 10826 10827function buildAccentMap() { 10828 var accentMap = {}; 10829 var map = [ 10830 { base: 'A', letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F' }, 10831 { base: 'AA', letters: '\uA732' }, 10832 { base: 'AE', letters: '\u00C6\u01FC\u01E2' }, 10833 { base: 'AO', letters: '\uA734' }, 10834 { base: 'AU', letters: '\uA736' }, 10835 { base: 'AV', letters: '\uA738\uA73A' }, 10836 { base: 'AY', letters: '\uA73C' }, 10837 { base: 'B', letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181' }, 10838 { base: 'C', letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E' }, 10839 { base: 'D', letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779' }, 10840 { base: 'DZ', letters: '\u01F1\u01C4' }, 10841 { base: 'Dz', letters: '\u01F2\u01C5' }, 10842 { base: 'E', letters: '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E' }, 10843 { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' }, 10844 { base: 'G', letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E' }, 10845 { base: 'H', letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D' }, 10846 { base: 'I', letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197' }, 10847 { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' }, 10848 { base: 'K', letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2' }, 10849 { base: 'L', letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780' }, 10850 { base: 'LJ', letters: '\u01C7' }, 10851 { base: 'Lj', letters: '\u01C8' }, 10852 { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' }, 10853 { base: 'N', letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4' }, 10854 { base: 'NJ', letters: '\u01CA' }, 10855 { base: 'Nj', letters: '\u01CB' }, 10856 { base: 'O', letters: '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C' }, 10857 { base: 'OI', letters: '\u01A2' }, 10858 { base: 'OO', letters: '\uA74E' }, 10859 { base: 'OU', letters: '\u0222' }, 10860 { base: 'P', letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754' }, 10861 { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' }, 10862 { base: 'R', letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782' },
10863 { base: 'S', letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784' }, 10864 { base: 'T', letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786' }, 10865 { base: 'TZ', letters: '\uA728' }, 10866 { base: 'U', letters: '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244' }, 10867 { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' }, 10868 { base: 'VY', letters: '\uA760' }, 10869 { base: 'W', letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72' }, 10870 { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' }, 10871 { base: 'Y', letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE' }, 10872 { base: 'Z', letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762' }, 10873 { base: 'a', letters: '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250' }, 10874 { base: 'aa', letters: '\uA733' }, 10875 { base: 'ae', letters: '\u00E6\u01FD\u01E3' }, 10876 { base: 'ao', letters: '\uA735' }, 10877 { base: 'au', letters: '\uA737' }, 10878 { base: 'av', letters: '\uA739\uA73B' }, 10879 { base: 'ay', letters: '\uA73D' }, 10880 { base: 'b', letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253' }, 10881 { base: 'c', letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184' }, 10882 { base: 'd', letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A' }, 10883 { base: 'dz', letters: '\u01F3\u01C6' }, 10884 { base: 'e', letters: '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD' }, 10885 { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' }, 10886 { base: 'g', letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F' }, 10887 { base: 'h', letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265' }, 10888 { base: 'hv', letters: '\u0195' }, 10889 { base: 'i', letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131' }, 10890 { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' }, 10891 { base: 'k', letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3' }, 10892 { base: 'l', letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747' }, 10893 { base: 'lj', letters: '\u01C9' }, 10894 { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' }, 10895 { base: 'n', letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5' }, 10896 { base: 'nj', letters: '\u01CC' }, 10897 { base: 'o', letters: '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275' }, 10898 { base: 'oi', letters: '\u01A3' }, 10899 { base: 'ou', letters: '\u0223' }, 10900 { base: 'oo', letters: '\uA74F' }, 10901 { base: 'p', letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755' }, 10902 { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' }, 10903 { base: 'r', letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783' }, 10904 { base: 's', letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B' }, 10905 { base: 't', letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787' }, 10906 { base: 'tz', letters: '\uA729' }, 10907 { base: 'u', letters: '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289' }, 10908 { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' }, 10909 { base: 'vy', letters: '\uA761' }, 10910 { base: 'w', letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73' }, 10911 { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' }, 10912 { base: 'y', letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u
109121EF5\u01B4\u024F\u1EFF' }, 10913 { base: 'z', letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763' } 10914 ]; 10915 10916 for (var i = 0; i < map.length; i++) { 10917 var letters = map[i].letters.split(""); 10918 for (var j = 0; j < letters.length; j++) { 10919 accentMap[letters[j]] = map[i].base; 10920 } 10921 } 10922 return accentMap; 10923} 10924 10925module.exports = Utils; 10926},{}],180:[function(require,module,exports){ 10927var Utils = {}; 10928 10929Utils.animations = require('./src/animations.js'); 10930Utils.browser = require('./src/browser.js'); 10931Utils.data = require('./src/data.js'); 10932Utils.fullscreen = require('./src/fullscreen.js'); 10933Utils.string = require('./src/string.js'); 10934 10935module.exports = Utils; 10936},{"./src/animations.js":175,"./src/browser.js":176,"./src/data.js":177,"./src/fullscreen.js":178,"./src/string.js":179}],181:[function(require,module,exports){ 10937var Request = require('request'); 10938 10939function onLoad(id, event, response) { 10940 this.onMessage && this.onMessage.func.call(this.onMessage.context || this, response.response || response.responseText, id); 10941} 10942function onError(id, event, response) { 10943 this.onError && this.onError.func.call(this.onError.context || this, id); 10944} 10945 10946function XHRConnection(options) { 10947 options.listeners = options.listeners || {}; 10948 this.onMessage = options.listeners.onmessage; 10949 this.onError = options.listeners.onerror; 10950 this.host = options.host; 10951} 10952 10953XHRConnection.prototype.send = function (payload, id) { 10954 var request = new Request({ 10955 url: this.host, 10956 method: "POST" 10957 }); 10958 request.on('load', onLoad.bind(this, id)); 10959 request.on('error', onError.bind(this, id)); 10960 request.on('abort', onError.bind(this, id)); 10961 request.send(payload); 10962}; 10963 10964module.exports = XHRConnection; 10965 10966},{"request":"request"}],182:[function(require,module,exports){ 10967Object.defineProperty(exports, '__esModule', { value: true }); 10968 10969const utils = require('@sentry/utils'); 10970const core = require('@sentry/core'); 10971 10972// exporting a separate copy of `WINDOW` rather than exporting the one from `@sentry/browser` 10973// prevents the browser package from being bundled in the CDN bundle, and avoids a 10974// circular dependency between the browser and feedback packages 10975const WINDOW = utils.GLOBAL_OBJ ; 10976 10977const LIGHT_BACKGROUND = '#ffffff'; 10978const INHERIT = 'inherit'; 10979const SUBMIT_COLOR = 'rgba(108, 95, 199, 1)'; 10980const LIGHT_THEME = { 10981 fontFamily: "system-ui, 'Helvetica Neue', Arial, sans-serif", 10982 fontSize: '14px', 10983 10984 background: LIGHT_BACKGROUND, 10985 backgroundHover: '#f6f6f7', 10986 foreground: '#2b2233', 10987 border: '1.5px solid rgba(41, 35, 47, 0.13)', 10988 borderRadius: '12px', 10989 boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', 10990 10991 success: '#268d75', 10992 error: '#df3338', 10993 10994 submitBackground: 'rgba(88, 74, 192, 1)', 10995 submitBackgroundHover: SUBMIT_COLOR, 10996 submitBorder: SUBMIT_COLOR, 10997 submitOutlineFocus: '#29232f', 10998 submitForeground: LIGHT_BACKGROUND, 10999 submitForegroundHover: LIGHT_BACKGROUND, 11000 11001 cancelBackground: 'transparent', 11002 cancelBackgroundHover: 'var(--background-hover)', 11003 cancelBorder: 'var(--border)', 11004 cancelOutlineFocus: 'var(--input-outline-focus)', 11005 cancelForeground: 'var(--foreground)', 11006 cancelForegroundHover: 'var(--foreground)', 11007 11008 inputBackground: INHERIT, 11009 inputForeground: INHERIT, 11010 inputBorder: 'var(--border)', 11011 inputOutlineFocus: SUBMIT_COLOR, 11012 11013 formBorderRadius: '20px', 11014 formContentBorderRadius: '6px', 11015}; 11016 11017const DEFAULT_THEME = { 11018 light: LIGHT_THEME, 11019 dark: { 11020 ...LIGHT_THEME, 11021 11022 background: '#29232f', 11023 backgroundHover: '#352f3b', 11024 foreground: '#ebe6ef', 11025 border: '1.5px solid rgba(235, 230, 239, 0.15)', 11026 11027 success: '#2da98c', 11028 error: '#f55459', 11029 }, 11030}; 11031 11032const ACTOR_LABEL = 'Report a Bug'; 11033const CANCEL_BUTTON_LABEL = 'Cancel'; 11034const SUBMIT_BUTTON_LABEL = 'Send Bug Report'; 11035const FORM_TITLE = 'Report a Bug'; 11036const EMAIL_PLACEHOLDER = '[email protected]'; 11037const EMAIL_LABEL = 'Email'; 11038const MESSAGE_PLACEHOLDER = "What's the bug? What did you expect?"; 11039const MESSAGE_LABEL = 'Description'; 11040const NAME_PLACEHOLDER = 'Your Name'; 11041const NAME_LABEL = 'Name'; 11042const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!'; 11043 11044const FEEDBACK_WIDGET_SOURCE = 'widget'; 11045const FEEDBACK_API_SOURCE = 'api'; 11046 11047/** 11048 * Prepare a feedback event & enrich it with the SDK metadata. 11049 */ 11050async function prepareFeedbackEvent({ 11051 client, 11052 scope, 11053 event, 11054}) { 11055 const eventHint = {}; 11056 if (client.emit) { 11057 client.emit('preprocessEvent', event, eventHint); 11058 } 11059 11060 const preparedEvent = (await core.prepareEvent( 11061 client.getOptions(), 11062 event, 11063 eventHint, 11064 scope, 11065 client, 11066 core.getIsolationScope(), 11067 )) ; 11068 11069 if (preparedEvent === null) { 11070 // Taken from baseclient's `_processEvent` method, where this is handled for errors/transactions
11071 client.recordDroppedEvent('event_processor', 'feedback', event); 11072 return null; 11073 } 11074 11075 // This normally happens in browser client "_prepareEvent" 11076 // but since we do not use this private method from the client, but rather the plain import 11077 // we need to do this manually. 11078 preparedEvent.platform = preparedEvent.platform || 'javascript'; 11079 11080 return preparedEvent; 11081} 11082 11083/** 11084 * Send feedback using transport 11085 */ 11086async function sendFeedbackRequest( 11087 { feedback: { message, email, name, source, url } }, 11088 { includeReplay = true } = {}, 11089) { 11090 const client = core.getClient(); 11091 const transport = client && client.getTransport(); 11092 const dsn = client && client.getDsn(); 11093 11094 if (!client || !transport || !dsn) { 11095 return; 11096 } 11097 11098 const baseEvent = { 11099 contexts: { 11100 feedback: { 11101 contact_email: email, 11102 name, 11103 message, 11104 url, 11105 source, 11106 }, 11107 }, 11108 type: 'feedback', 11109 }; 11110 11111 return core.withScope(async scope => { 11112 // No use for breadcrumbs in feedback 11113 scope.clearBreadcrumbs(); 11114 11115 if ([FEEDBACK_API_SOURCE, FEEDBACK_WIDGET_SOURCE].includes(String(source))) { 11116 scope.setLevel('info'); 11117 } 11118 11119 const feedbackEvent = await prepareFeedbackEvent({ 11120 // eslint-disable-next-line @typescript-eslint/no-explicit-any 11121 scope: scope , 11122 client, 11123 event: baseEvent, 11124 }); 11125 11126 if (!feedbackEvent) { 11127 return; 11128 } 11129 11130 if (client.emit) { 11131 client.emit('beforeSendFeedback', feedbackEvent, { includeReplay: Boolean(includeReplay) }); 11132 } 11133 11134 const envelope = core.createEventEnvelope(feedbackEvent, dsn, client.getOptions()._metadata, client.getOptions().tunnel); 11135 11136 let response; 11137 11138 try { 11139 response = await transport.send(envelope); 11140 } catch (err) { 11141 const error = new Error('Unable to send Feedback'); 11142 11143 try { 11144 // In case browsers don't allow this property to be writable 11145 // @ts-expect-error This needs lib es2022 and newer 11146 error.cause = err; 11147 } catch (e) { 11148 // nothing to do 11149 } 11150 throw error; 11151 } 11152 11153 // TODO (v8): we can remove this guard once transport.send's type signature doesn't include void anymore 11154 if (!response) { 11155 return; 11156 } 11157 11158 // Require valid status codes, otherwise can assume feedback was not sent successfully 11159 if (typeof response.statusCode === 'number' && (response.statusCode < 200 || response.statusCode >= 300)) { 11160 throw new Error('Unable to send Feedback'); 11161 } 11162 11163 return response; 11164 }); 11165} 11166 11167/* 11168 * For reference, the fully built event looks something like this: 11169 * { 11170 * "type": "feedback", 11171 * "event_id": "d2132d31b39445f1938d7e21b6bf0ec4", 11172 * "timestamp": 1597977777.6189718, 11173 * "dist": "1.12", 11174 * "platform": "javascript", 11175 * "environment": "production", 11176 * "release": 42, 11177 * "tags": {"transaction": "/organizations/:orgId/performance/:eventSlug/"}, 11178 * "sdk": {"name": "name", "version": "version"}, 11179 * "user": { 11180 * "id": "123", 11181 * "username": "user", 11182 * "email": "[email protected]", 11183 * "ip_address": "192.168.11.12", 11184 * }, 11185 * "request": { 11186 * "url": None, 11187 * "headers": { 11188 * "user-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15" 11189 * }, 11190 * }, 11191 * "contexts": { 11192 * "feedback": { 11193 * "message": "test message", 11194 * "contact_email": "[email protected]", 11195 * "type": "feedback", 11196 * }, 11197 * "trace": { 11198 * "trace_id": "4C79F60C11214EB38604F4AE0781BFB2", 11199 * "span_id": "FA90FDEAD5F74052", 11200 * "type": "trace", 11201 * }, 11202 * "replay": { 11203 * "replay_id": "e2d42047b1c5431c8cba85ee2a8ab25d", 11204 * }, 11205 * }, 11206 * } 11207 */ 11208 11209/** 11210 * Public API to send a Feedback item to Sentry 11211 */ 11212function sendFeedback( 11213 { name, email, message, source = FEEDBACK_API_SOURCE, url = utils.getLocationHref() }, 11214 options = {}, 11215) { 11216 if (!message) { 11217 throw new Error('Unable to submit feedback with empty message'); 11218 } 11219 11220 return sendFeedbackRequest( 11221 { 11222 feedback: { 11223 name, 11224 email, 11225 message, 11226 url, 11227 source, 11228 }, 11229 }, 11230 options, 11231 ); 11232} 11233 11234/** 11235 * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code. 11236 * 11237 * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking. 11238 */ 11239const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__); 11240 11241/** 11242 * Quick and dirty deep merge for the Feedback integration options 11243 */ 11244function mergeOptions( 11245 defaultOptions, 11246 optionOverrides, 11247) { 11248 return { 11249 ...defaultOptions, 11250 ...optionOverrides, 11251 themeDark: { 11252 ...defaultOptions.themeDark, 11253 ...optionOverrides.themeDark, 11254 }, 11255 themeLight: { 11256 ...defaultOptions.themeLight, 11257 ...optionOverrides.themeLight, 11258 }, 11259 }; 11260} 11261 11262/** 11263 * Creates <style> element for widget actor (button that opens the dialog) 11264 */ 11265function createActorStyles(d) { 11266 const style = d.createElement('style'); 11267 style.textContent = ` 11268.widget__actor { 11269 line-height: 25px; 11270 11271 display: flex; 11272 align-items: center; 11273 gap: 8px; 11274 11275 border-radius: var(--border-radius); 11276 cursor: pointer; 11277 font-size: 14px; 11278 font-weight: 600; 11279 padding: 12px 16px; 11280 text-decoration: none; 11281 z-index: 9000; 11282 11283 color: var(--foreground); 11284 background-color: var(--background); 11285 border: var(--border);
11286 box-shadow: var(--box-shadow); 11287 opacity: 1; 11288 transition: opacity 0.1s ease-in-out; 11289} 11290 11291.widget__actor:hover { 11292 background-color: var(--background-hover); 11293} 11294 11295.widget__actor svg { 11296 width: 16px; 11297 height: 16px; 11298} 11299 11300.widget__actor--hidden { 11301 opacity: 0; 11302 pointer-events: none; 11303 visibility: hidden; 11304} 11305 11306.widget__actor__text { 11307} 11308 11309.feedback-icon path { 11310 fill: var(--foreground); 11311} 11312`; 11313 11314 return style; 11315} 11316 11317/** 11318 * Creates <style> element for widget dialog 11319 */ 11320function createDialogStyles(d) { 11321 const style = d.createElement('style'); 11322 11323 style.textContent = ` 11324.dialog { 11325 line-height: 25px; 11326 background-color: rgba(0, 0, 0, 0.05); 11327 border: none; 11328 position: fixed; 11329 inset: 0; 11330 z-index: 10000; 11331 width: 100vw; 11332 height: 100vh; 11333 display: flex; 11334 align-items: center; 11335 justify-content: center; 11336 opacity: 1; 11337 transition: opacity 0.2s ease-in-out; 11338} 11339 11340.dialog:not([open]) { 11341 opacity: 0; 11342 pointer-events: none; 11343 visibility: hidden; 11344} 11345.dialog:not([open]) .dialog__content { 11346 transform: translate(0, -16px) scale(0.98); 11347} 11348 11349.dialog__content { 11350 position: fixed; 11351 left: var(--left); 11352 right: var(--right); 11353 bottom: var(--bottom); 11354 top: var(--top); 11355 11356 border: var(--border); 11357 border-radius: var(--form-border-radius); 11358 background-color: var(--background); 11359 color: var(--foreground); 11360 11361 width: 320px; 11362 max-width: 100%; 11363 max-height: calc(100% - 2rem); 11364 display: flex; 11365 flex-direction: column;
11366 box-shadow: var(--box-shadow); 11367 transition: transform 0.2s ease-in-out; 11368 transform: translate(0, 0) scale(1); 11369} 11370 11371.dialog__header { 11372 display: flex; 11373 align-items: center; 11374 justify-content: space-between; 11375 font-size: 20px; 11376 font-weight: 600; 11377 padding: 24px 24px 0 24px; 11378 margin: 0; 11379 margin-bottom: 16px; 11380} 11381 11382.brand-link { 11383 display: inline-flex; 11384} 11385 11386.error { 11387 color: var(--error); 11388 margin-bottom: 16px; 11389} 11390 11391.form { 11392 display: grid; 11393 overflow: auto; 11394 flex-direction: column; 11395 gap: 16px; 11396 padding: 0 24px 24px; 11397} 11398 11399.form__error-container { 11400 color: var(--error); 11401} 11402 11403.form__error-container--hidden { 11404 display: none; 11405} 11406 11407.form__label { 11408 display: flex; 11409 flex-direction: column; 11410 gap: 4px; 11411 margin: 0px; 11412} 11413 11414.form__label__text { 11415 display: grid; 11416 gap: 4px; 11417 align-items: center; 11418 grid-auto-flow: column; 11419 grid-auto-columns: max-content; 11420} 11421 11422.form__label__text--required { 11423 font-size: 0.85em; 11424} 11425 11426.form__input { 11427 font-family: inherit; 11428 line-height: inherit; 11429 background-color: var(--input-background); 11430 box-sizing: border-box; 11431 border: var(--input-border); 11432 border-radius: var(--form-content-border-radius); 11433 color: var(--input-foreground); 11434 font-size: 14px; 11435 font-weight: 500; 11436 padding: 6px 12px; 11437} 11438 11439.form__input:focus-visible { 11440 outline: 1px auto var(--input-outline-focus); 11441} 11442 11443.form__input--textarea { 11444 font-family: inherit; 11445 resize: vertical; 11446} 11447 11448.btn-group { 11449 display: grid; 11450 gap: 8px; 11451 margin-top: 8px; 11452} 11453 11454.btn { 11455 line-height: inherit; 11456 border: var(--cancel-border); 11457 border-radius: var(--form-content-border-radius); 11458 cursor: pointer; 11459 font-size: 14px; 11460 font-weight: 600; 11461 padding: 6px 16px; 11462} 11463.btn[disabled] { 11464 opacity: 0.6; 11465 pointer-events: none; 11466} 11467 11468.btn--primary { 11469 background-color: var(--submit-background); 11470 border-color: var(--submit-border); 11471 color: var(--submit-foreground); 11472} 11473.btn--primary:hover { 11474 background-color: var(--submit-background-hover); 11475 color: var(--submit-foreground-hover); 11476} 11477.btn--primary:focus-visible { 11478 outline: 1px auto var(--submit-outline-focus); 11479} 11480 11481.btn--default { 11482 background-color: var(--cancel-background); 11483 color: var(--cancel-foreground); 11484 font-weight: 500; 11485} 11486.btn--default:hover { 11487 background-color: var(--cancel-background-hover); 11488 color: var(--cancel-foreground-hover); 11489} 11490.btn--default:focus-visible { 11491 outline: 1px auto var(--cancel-outline-focus); 11492} 11493 11494.success-message { 11495 background-color: var(--background); 11496 border: var(--border); 11497 border-radius: var(--border-radius);
11498 box-shadow: var(--box-shadow); 11499 font-weight: 600; 11500 color: var(--success); 11501 padding: 12px 24px; 11502 line-height: 25px; 11503 display: grid; 11504 align-items: center; 11505 grid-auto-flow: column; 11506 gap: 6px; 11507 cursor: default; 11508} 11509 11510.success-icon path { 11511 fill: var(--success); 11512} 11513`; 11514 11515 return style; 11516} 11517 11518function getThemedCssVariables(theme) { 11519 return ` 11520 --background: ${theme.background}; 11521 --background-hover: ${theme.backgroundHover}; 11522 --foreground: ${theme.foreground}; 11523 --error: ${theme.error}; 11524 --success: ${theme.success}; 11525 --border: ${theme.border}; 11526 --border-radius: ${theme.borderRadius}; 11527 --box-shadow: ${theme.boxShadow}; 11528 11529 --submit-background: ${theme.submitBackground}; 11530 --submit-background-hover: ${theme.submitBackgroundHover}; 11531 --submit-border: ${theme.submitBorder}; 11532 --submit-outline-focus: ${theme.submitOutlineFocus}; 11533 --submit-foreground: ${theme.submitForeground}; 11534 --submit-foreground-hover: ${theme.submitForegroundHover}; 11535 11536 --cancel-background: ${theme.cancelBackground}; 11537 --cancel-background-hover: ${theme.cancelBackgroundHover}; 11538 --cancel-border: ${theme.cancelBorder}; 11539 --cancel-outline-focus: ${theme.cancelOutlineFocus}; 11540 --cancel-foreground: ${theme.cancelForeground}; 11541 --cancel-foreground-hover: ${theme.cancelForegroundHover}; 11542 11543 --input-background: ${theme.inputBackground}; 11544 --input-foreground: ${theme.inputForeground}; 11545 --input-border: ${theme.inputBorder}; 11546 --input-outline-focus: ${theme.inputOutlineFocus}; 11547 11548 --form-border-radius: ${theme.formBorderRadius}; 11549 --form-content-border-radius: ${theme.formContentBorderRadius}; 11550 `; 11551} 11552 11553/** 11554 * Creates <style> element for widget actor (button that opens the dialog) 11555 */ 11556function createMainStyles( 11557 d, 11558 colorScheme, 11559 themes, 11560) { 11561 const style = d.createElement('style'); 11562 style.textContent = ` 11563:host { 11564 --bottom: 1rem; 11565 --right: 1rem; 11566 --top: auto; 11567 --left: auto; 11568 --z-index: 100000; 11569 --font-family: ${themes.light.fontFamily}; 11570 --font-size: ${themes.light.fontSize}; 11571 11572 position: fixed; 11573 left: var(--left); 11574 right: var(--right); 11575 bottom: var(--bottom); 11576 top: var(--top); 11577 z-index: var(--z-index); 11578 11579 font-family: var(--font-family); 11580 font-size: var(--font-size); 11581 11582 ${getThemedCssVariables(colorScheme === 'dark' ? themes.dark : themes.light)} 11583} 11584 11585${ 11586 colorScheme === 'system' 11587 ? ` 11588@media (prefers-color-scheme: dark) { 11589 :host { 11590 ${getThemedCssVariables(themes.dark)} 11591 } 11592}` 11593 : '' 11594} 11595}`; 11596 11597 return style; 11598} 11599 11600/** 11601 * Creates shadow host 11602 */ 11603function createShadowHost({ id, colorScheme, themeDark, themeLight }) 11604 11605 { 11606 try { 11607 const doc = WINDOW.document; 11608 11609 // Create the host 11610 const host = doc.createElement('div'); 11611 host.id = id; 11612 11613 // Create the shadow root 11614 const shadow = host.attachShadow({ mode: 'open' }); 11615 11616 shadow.appendChild(createMainStyles(doc, colorScheme, { dark: themeDark, light: themeLight })); 11617 shadow.appendChild(createDialogStyles(doc)); 11618 11619 return { shadow, host }; 11620 } catch (e) { 11621 // Shadow DOM probably not supported 11622 utils.logger.warn('[Feedback] Browser does not support shadow DOM API'); 11623 throw new Error('Browser does not support shadow DOM API.'); 11624 } 11625} 11626 11627/** 11628 * Handles UI behavior of dialog when feedback is submitted, calls 11629 * `sendFeedback` to send feedback. 11630 */ 11631async function handleFeedbackSubmit( 11632 dialog, 11633 feedback, 11634 options, 11635) { 11636 if (!dialog) { 11637 // Not sure when this would happen 11638 return; 11639 } 11640 11641 const showFetchError = () => { 11642 if (!dialog) { 11643 return; 11644 } 11645 dialog.showError('There was a problem submitting feedback, please wait and try again.'); 11646 }; 11647 11648 dialog.hideError(); 11649 11650 try { 11651 const resp = await sendFeedback({ ...feedback, source: FEEDBACK_WIDGET_SOURCE }, options); 11652 11653 // Success! 11654 return resp; 11655 } catch (err) { 11656 DEBUG_BUILD && utils.logger.error(err); 11657 showFetchError(); 11658 } 11659} 11660 11661/** 11662 * Helper function to set a dict of attributes on element (w/ specified namespace) 11663 */ 11664function setAttributesNS(el, attributes) { 11665 Object.entries(attributes).forEach(([key, val]) => { 11666 el.setAttributeNS(null, key, val); 11667 }); 11668 return el; 11669} 11670 11671const SIZE = 20; 11672const XMLNS$2 = 'http://www.w3.org/2000/svg'; 11673 11674/** 11675 * Feedback Icon 11676 */ 11677function Icon() { 11678 const createElementNS = (tagName) => 11679 WINDOW.document.createElementNS(XMLNS$2, tagName); 11680 const svg = setAttributesNS(createElementNS('svg'), { 11681 class: 'feedback-icon', 11682 width: `${SIZE}`, 11683 height: `${SIZE}`,
11684 viewBox: `0 0 ${SIZE} ${SIZE}`, 11685 fill: 'none', 11686 }); 11687 11688 const g = setAttributesNS(createElementNS('g'), { 11689 clipPath: 'url(#clip0_57_80)', 11690 }); 11691 11692 const path = setAttributesNS(createElementNS('path'), { 11693 ['fill-rule']: 'evenodd', 11694 ['clip-rule']: 'evenodd', 11695 d: 'M15.6622 15H12.3997C12.2129 14.9959 12.031 14.9396 11.8747 14.8375L8.04965 12.2H7.49956V19.1C7.4875 19.3348 7.3888 19.5568 7.22256 19.723C7.05632 19.8892 6.83435 19.9879 6.59956 20H2.04956C1.80193 19.9968 1.56535 19.8969 1.39023 19.7218C1.21511 19.5467 1.1153 19.3101 1.11206 19.0625V12.2H0.949652C0.824431 12.2017 0.700142 12.1783 0.584123 12.1311C0.468104 12.084 0.362708 12.014 0.274155 11.9255C0.185602 11.8369 0.115689 11.7315 0.0685419 11.6155C0.0213952 11.4995 -0.00202913 11.3752 -0.00034808 11.25V3.75C-0.00900498 3.62067 0.0092504 3.49095 0.0532651 3.36904C0.0972798 3.24712 0.166097 3.13566 0.255372 3.04168C0.344646 2.94771 0.452437 2.87327 0.571937 2.82307C0.691437 2.77286 0.82005 2.74798 0.949652 2.75H8.04965L11.8747 0.1625C12.031 0.0603649 12.2129 0.00407221 12.3997 0H15.6622C15.9098 0.00323746 16.1464 0.103049 16.3215 0.278167C16.4966 0.453286 16.5964 0.689866 16.5997 0.9375V3.25269C17.3969 3.42959 18.1345 3.83026 18.7211 4.41679C19.5322 5.22788 19.9878 6.32796 19.9878 7.47502C19.9878 8.62209 19.5322 9.72217 18.7211 10.5333C18.1345 11.1198 17.3969 11.5205 16.5997 11.6974V14.0125C16.6047 14.1393 16.5842 14.2659 16.5395 14.3847C16.4948 14.5035 16.4268 14.6121 16.3394 14.7042C16.252 14.7962 16.147 14.8698 16.0307 14.9206C15.9144 14.9714 15.7891 14.9984 15.6622 15ZM1.89695 10.325H1.88715V4.625H8.33715C8.52423 4.62301 8.70666 4.56654 8.86215 4.4625L12.6872 1.875H14.7247V13.125H12.6872L8.86215 10.4875C8.70666 10.3835 8.52423 10.327 8.33715 10.325H2.20217C2.15205 10.3167 2.10102 10.3125 2.04956 10.3125C1.9981 10.3125 1.94708 10.3167 1.89695 10.325ZM2.98706 12.2V18.1625H5.66206V12.2H2.98706ZM16.5997 9.93612V5.01393C16.6536 5.02355 16.7072 5.03495 16.7605 5.04814C17.1202 5.13709 17.4556 5.30487 17.7425 5.53934C18.0293 5.77381 18.2605 6.06912 18.4192 6.40389C18.578 6.73866 18.6603 7.10452 18.6603 7.47502C18.6603 7.84552 18.578 8.21139 18.4192 8.54616C18.2605 8.88093 18.0293 9.17624 17.7425 9.41071C17.4556 9.64518 17.1202 9.81296 16.7605 9.90191C16.7072 9.91509 16.6536 9.9265 16.5997 9.93612Z', 11696 }); 11697 svg.appendChild(g).appendChild(path); 11698 11699 const speakerDefs = createElementNS('defs'); 11700 const speakerClipPathDef = setAttributesNS(createElementNS('clipPath'), { 11701 id: 'clip0_57_80', 11702 }); 11703 11704 const speakerRect = setAttributesNS(createElementNS('rect'), { 11705 width: `${SIZE}`, 11706 height: `${SIZE}`, 11707 fill: 'white', 11708 }); 11709 11710 speakerClipPathDef.appendChild(speakerRect); 11711 speakerDefs.appendChild(speakerClipPathDef); 11712 11713 svg.appendChild(speakerDefs).appendChild(speakerClipPathDef).appendChild(speakerRect); 11714 11715 return { 11716 get el() { 11717 return svg; 11718 }, 11719 }; 11720} 11721 11722/** 11723 * Helper function to create an element. Could be used as a JSX factory 11724 * (i.e. React-like syntax). 11725 */ 11726function createElement( 11727 tagName, 11728 attributes, 11729 ...children 11730) { 11731 const doc = WINDOW.document; 11732 const element = doc.createElement(tagName); 11733 11734 if (attributes) { 11735 Object.entries(attributes).forEach(([attribute, attributeValue]) => { 11736 if (attribute === 'className' && typeof attributeValue === 'string') { 11737 // JSX does not allow class as a valid name 11738 element.setAttribute('class', attributeValue); 11739 } else if (typeof attributeValue === 'boolean' && attributeValue) { 11740 element.setAttribute(attribute, ''); 11741 } else if (typeof attributeValue === 'string') { 11742 element.setAttribute(attribute, attributeValue); 11743 } else if (attribute.startsWith('on') && typeof attributeValue === 'function') { 11744 element.addEventListener(attribute.substring(2).toLowerCase(), attributeValue); 11745 } 11746 }); 11747 } 11748 for (const child of children) { 11749 appendChild(element, child); 11750 } 11751 11752 return element; 11753} 11754 11755function appendChild(parent, child) { 11756 const doc = WINDOW.document; 11757 if (typeof child === 'undefined' || child === null) { 11758 return; 11759 } 11760 11761 if (Array.isArray(child)) { 11762 for (const value of child) { 11763 appendChild(parent, value); 11764 } 11765 } else if (child === false) ; else if (typeof child === 'string') { 11766 parent.appendChild(doc.createTextNode(child)); 11767 } else if (child instanceof Node) { 11768 parent.appendChild(child); 11769 } else { 11770 parent.appendChild(doc.createTextNode(String(child))); 11771 } 11772} 11773 11774/** 11775 * 11776 */ 11777function Actor({ buttonLabel, onClick }) { 11778 function _handleClick(e) { 11779 onClick && onClick(e); 11780 } 11781 11782 const el = createElement( 11783 'button', 11784 { 11785 type: 'button', 11786 className: 'widget__actor', 11787 ['aria-label']: buttonLabel, 11788 ['aria-hidden']: 'false', 11789 }, 11790 Icon().el, 11791 buttonLabel 11792 ? createElement( 11793 'span', 11794 { 11795 className: 'widget__actor__text', 11796 }, 11797 buttonLabel, 11798 ) 11799 : null, 11800 ); 11801 11802 el.addEventListener('click', _handleClick); 11803 11804 return { 11805 get el() { 11806 return el; 11807 }, 11808 show: () => { 11809 el.classList.remove('widget__actor--hidden'); 11810 el.setAttribute('aria-hidden', 'false'); 11811 }, 11812 hide: () => { 11813 el.classList.add('widget__actor--hidden'); 11814 el.setAttribute('aria-hidden', 'true'); 11815 }, 11816 }; 11817} 11818 11819/** 11820 * 11821 */ 11822function SubmitButton({ label }) { 11823 const el = createElement( 11824 'button', 11825 { 11826 type: 'submit', 11827 className: 'btn btn--primary', 11828 ['aria-label']: label, 11829 }, 11830 label, 11831 ); 11832 11833 return { 11834 el, 11835 }; 11836} 11837 11838function retrieveStringValue(formData, key) { 11839 const value = formData.get(key); 11840 if (typeof value === 'string') { 11841 return value.trim(); 11842 } 11843 return ''; 11844} 11845 11846/** 11847 * Creates the form element 11848 */ 11849function Form({ 11850 nameLabel, 11851 namePlaceholder, 11852 emailLabel, 11853 emailPlaceholder, 11854 messageLabel, 11855 messagePlaceholder, 11856 cancelButtonLabel, 11857 submitButtonLabel, 11858 11859 showName, 11860 showEmail, 11861 isNameRequired, 11862 isEmailRequired, 11863 11864 defaultName, 11865 defaultEmail, 11866 onCancel, 11867 onSubmit, 11868}) { 11869 const { el: submitEl }
11869 = SubmitButton({ 11870 label: submitButtonLabel, 11871 }); 11872 11873 function handleSubmit(e) { 11874 e.preventDefault(); 11875 11876 if (!(e.target instanceof HTMLFormElement)) { 11877 return; 11878 } 11879 11880 try { 11881 if (onSubmit) { 11882 const formData = new FormData(e.target ); 11883 const feedback = { 11884 name: retrieveStringValue(formData, 'name'), 11885 email: retrieveStringValue(formData, 'email'), 11886 message: retrieveStringValue(formData, 'message'), 11887 }; 11888 11889 onSubmit(feedback); 11890 } 11891 } catch (e2) { 11892 // pass 11893 } 11894 } 11895 11896 const errorEl = createElement('div', { 11897 className: 'form__error-container form__error-container--hidden', 11898 ['aria-hidden']: 'true', 11899 }); 11900 11901 function showError(message) { 11902 errorEl.textContent = message; 11903 errorEl.classList.remove('form__error-container--hidden'); 11904 errorEl.setAttribute('aria-hidden', 'false'); 11905 } 11906 11907 function hideError() { 11908 errorEl.textContent = ''; 11909 errorEl.classList.add('form__error-container--hidden'); 11910 errorEl.setAttribute('aria-hidden', 'true'); 11911 } 11912 11913 const nameEl = createElement('input', { 11914 id: 'name', 11915 type: showName ? 'text' : 'hidden', 11916 ['aria-hidden']: showName ? 'false' : 'true', 11917 name: 'name', 11918 required: isNameRequired, 11919 className: 'form__input', 11920 placeholder: namePlaceholder, 11921 value: defaultName, 11922 }); 11923 11924 const emailEl = createElement('input', { 11925 id: 'email', 11926 type: showEmail ? 'text' : 'hidden', 11927 ['aria-hidden']: showEmail ? 'false' : 'true', 11928 name: 'email', 11929 required: isEmailRequired, 11930 className: 'form__input', 11931 placeholder: emailPlaceholder, 11932 value: defaultEmail, 11933 }); 11934 11935 const messageEl = createElement('textarea', { 11936 id: 'message', 11937 autoFocus: 'true', 11938 rows: '5', 11939 name: 'message', 11940 required: true, 11941 className: 'form__input form__input--textarea', 11942 placeholder: messagePlaceholder, 11943 }); 11944 11945 const cancelEl = createElement( 11946 'button', 11947 { 11948 type: 'button', 11949 className: 'btn btn--default', 11950 ['aria-label']: cancelButtonLabel, 11951 onClick: (e) => { 11952 onCancel && onCancel(e); 11953 }, 11954 }, 11955 cancelButtonLabel, 11956 ); 11957 11958 const formEl = createElement( 11959 'form', 11960 { 11961 className: 'form', 11962 onSubmit: handleSubmit, 11963 }, 11964 [ 11965 errorEl, 11966 11967 showName && 11968 createElement( 11969 'label', 11970 { 11971 htmlFor: 'name', 11972 className: 'form__label', 11973 }, 11974 [ 11975 createElement( 11976 'span', 11977 { className: 'form__label__text' }, 11978 nameLabel, 11979 isNameRequired && createElement('span', { className: 'form__label__text--required' }, ' (required)'), 11980 ), 11981 nameEl, 11982 ], 11983 ), 11984 !showName && nameEl, 11985 11986 showEmail && 11987 createElement( 11988 'label', 11989 { 11990 htmlFor: 'email', 11991 className: 'form__label', 11992 }, 11993 [ 11994 createElement( 11995 'span', 11996 { className: 'form__label__text' }, 11997 emailLabel, 11998 isEmailRequired && createElement('span', { className: 'form__label__text--required' }, ' (required)'), 11999 ), 12000 emailEl, 12001 ], 12002 ), 12003 !showEmail && emailEl, 12004 12005 createElement( 12006 'label', 12007 { 12008 htmlFor: 'message', 12009 className: 'form__label', 12010 }, 12011 [ 12012 createElement( 12013 'span', 12014 { className: 'form__label__text' }, 12015 messageLabel, 12016 createElement('span', { className: 'form__label__text--required' }, ' (required)'), 12017 ), 12018 messageEl, 12019 ], 12020 ), 12021 12022 createElement( 12023 'div', 12024 { 12025 className: 'btn-group', 12026 }, 12027 [submitEl, cancelEl], 12028 ), 12029 ], 12030 ); 12031 12032 return { 12033 get el() { 12034 return formEl; 12035 }, 12036 showError, 12037 hideError, 12038 }; 12039} 12040 12041const XMLNS$1 = 'http://www.w3.org/2000/svg'; 12042 12043/** 12044 * Sentry Logo 12045 */ 12046function Logo({ colorScheme }) { 12047 const createElementNS = (tagName) => 12048 WINDOW.document.createElementNS(XMLNS$1, tagName); 12049 const svg = setAttributesNS(createElementNS('svg'), { 12050 class: 'sentry-logo', 12051 width: '32', 12052 height: '30',
12053 viewBox: '0 0 72 66', 12054 fill: 'none', 12055 }); 12056 12057 const path = setAttributesNS(createElementNS('path'), { 12058 transform: 'translate(11, 11)', 12059 d: 'M29,2.26a4.67,4.67,0,0,0-8,0L14.42,13.53A32.21,32.21,0,0,1,32.17,40.19H27.55A27.68,27.68,0,0,0,12.09,17.47L6,28a15.92,15.92,0,0,1,9.23,12.17H4.62A.76.76,0,0,1,4,39.06l2.94-5a10.74,10.74,0,0,0-3.36-1.9l-2.91,5a4.54,4.54,0,0,0,1.69,6.24A4.66,4.66,0,0,0,4.62,44H19.15a19.4,19.4,0,0,0-8-17.31l2.31-4A23.87,23.87,0,0,1,23.76,44H36.07a35.88,35.88,0,0,0-16.41-31.8l4.67-8a.77.77,0,0,1,1.05-.27c.53.29,20.29,34.77,20.66,35.17a.76.76,0,0,1-.68,1.13H40.6q.09,1.91,0,3.81h4.78A4.59,4.59,0,0,0,50,39.43a4.49,4.49,0,0,0-.62-2.28Z', 12060 }); 12061 svg.append(path); 12062 12063 const defs = createElementNS('defs'); 12064 const style = createElementNS('style'); 12065 12066 style.textContent = ` 12067 path { 12068 fill: ${colorScheme === 'dark' ? '#fff' : '#362d59'}; 12069 }`; 12070 12071 if (colorScheme === 'system') { 12072 style.textContent += ` 12073 @media (prefers-color-scheme: dark) { 12074 path: { 12075 fill: '#fff'; 12076 } 12077 } 12078 `; 12079 } 12080 12081 defs.append(style); 12082 svg.append(defs); 12083 12084 return { 12085 get el() { 12086 return svg; 12087 }, 12088 }; 12089} 12090 12091/** 12092 * Feedback dialog component that has the form 12093 */ 12094function Dialog({ 12095 formTitle, 12096 showBranding, 12097 showName, 12098 showEmail, 12099 isNameRequired, 12100 isEmailRequired, 12101 colorScheme, 12102 defaultName, 12103 defaultEmail, 12104 onClosed, 12105 onCancel, 12106 onSubmit, 12107 ...textLabels 12108}) { 12109 let el = null; 12110 12111 /** 12112 * Handles when the dialog is clicked. In our case, the dialog is the 12113 * semi-transparent bg behind the form. We want clicks outside of the form to 12114 * hide the form. 12115 */ 12116 function handleDialogClick() { 12117 close(); 12118 12119 // Only this should trigger `onClose`, we don't want the `close()` method to 12120 // trigger it, otherwise it can cause cycles. 12121 onClosed && onClosed(); 12122 } 12123 12124 /** 12125 * Close the dialog 12126 */ 12127 function close() { 12128 if (el) { 12129 el.open = false; 12130 } 12131 } 12132 12133 /** 12134 * Opens the dialog 12135 */ 12136 function open() { 12137 if (el) { 12138 el.open = true; 12139 } 12140 } 12141 12142 /** 12143 * Check if dialog is currently opened 12144 */ 12145 function checkIsOpen() { 12146 return (el && el.open === true) || false; 12147 } 12148 12149 const { 12150 el: formEl, 12151 showError, 12152 hideError, 12153 } = Form({ 12154 showEmail, 12155 showName, 12156 isEmailRequired, 12157 isNameRequired, 12158 12159 defaultName, 12160 defaultEmail, 12161 onSubmit, 12162 onCancel, 12163 ...textLabels, 12164 }); 12165 12166 el = createElement( 12167 'dialog', 12168 { 12169 className: 'dialog', 12170 open: true, 12171 onClick: handleDialogClick, 12172 }, 12173 createElement( 12174 'div', 12175 { 12176 className: 'dialog__content', 12177 onClick: e => { 12178 // Stop event propagation so clicks on content modal do not propagate to dialog (which will close dialog) 12179 e.stopPropagation(); 12180 }, 12181 }, 12182 createElement( 12183 'h2', 12184 { className: 'dialog__header' }, 12185 formTitle, 12186 showBranding && 12187 createElement( 12188 'a', 12189 { 12190 className: 'brand-link', 12191 target: '_blank', 12192 href: 'https://sentry.io/welcome/', 12193 title: 'Powered by Sentry', 12194 rel: 'noopener noreferrer', 12195 }, 12196 Logo({ colorScheme }).el, 12197 ), 12198 ), 12199 formEl, 12200 ), 12201 ); 12202 12203 return { 12204 get el() { 12205 return el; 12206 }, 12207 showError, 12208 hideError, 12209 open, 12210 close, 12211 checkIsOpen, 12212 }; 12213} 12214 12215const WIDTH = 16; 12216const HEIGHT = 17; 12217const XMLNS = 'http://www.w3.org/2000/svg'; 12218 12219/** 12220 * Success Icon (checkmark) 12221 */ 12222function SuccessIcon() { 12223 const createElementNS = (tagName) => 12224 WINDOW.document.createElementNS(XMLNS, tagName); 12225 const svg = setAttributesNS(createElementNS('svg'), { 12226 class: 'success-icon', 12227 width: `${WIDTH}`, 12228 height: `${HEIGHT}`, 12229 viewBox: `0 0 ${WIDTH} ${HEIGHT}`, 12230 fill: 'none', 12231 }); 12232 12233 const g = setAttributesNS(createElementNS('g'), { 12234 clipPath: 'url(#clip0_57_156)', 12235 }); 12236 12237 const path2 = setAttributesNS(createElementNS('path'), { 12238 ['fill-rule']: 'evenodd', 12239 ['clip-rule']: 'evenodd', 12240 d: 'M3.55544 15.1518C4.87103 16.0308 6.41775 16.5 8 16.5C10.1217 16.5 12.1566 15.6571 13.6569 14.1569C15.1571 12.6566 16 10.6217 16 8.5C16 6.91775 15.5308 5.37103 14.6518 4.05544C13.7727 2.73985 12.5233 1.71447 11.0615 1.10897C9.59966 0.503466 7.99113 0.34504 6.43928 0.653721C4.88743 0.962403 3.46197 1.72433 2.34315 2.84315C1.22433 3.96197 0.462403 5.38743 0.153721 6.93928C-0.15496 8.49113 0.00346625 10.0997 0.608967 11.5615C1.21447 13.0233 2.23985 14.2727 3.55544 15.1518ZM4.40546 3.1204C5.46945 2.40946 6.72036 2.03 8 2.03C9.71595 2.03 11.3616 2.71166 12.575 3.92502C13.7883 5.13838 14.47 6.78405 14.47 8.5C14.47 9.77965 14.0905 11.0306 13.3796 12.0945C12.6687 13.1585 11.6582 13.9878 10.476 14.4775C9.29373 14.9672 7.99283 15.0953 6.73777 14.8457C5.48271 14.596 4.32987 13.9798 3.42502 13.075C2.52018 12.1701 1.90397 11.0173 1.65432 9.76224C1.40468 8.50718 1.5328 7.20628 2.0225 6.02404C2.5122 4.8418 3.34148 3.83133 4.40546 3.1204Z', 12241 }); 12242 const path = setAttributesNS(createElementNS('path'), { 12243 d: 'M6.68775 12.4297C6.78586 12.4745 6.89218 12.4984 7 12.5C7.11275 12.4955 7.22315 12.4664 7.32337 12.4145C7.4236 12.3627 7.51121 12.2894 7.58 12.2L12 5.63999C12.0848 5.47724 12.1071 5.28902 12.0625 5.11098C12.0178 4.93294 11.9095 4.77744 11.7579 4.67392C11.6064 4.57041 11.4221 4.52608 11.24 4.54931C11.0579 4.57254 10.8907 4.66173
1224310.77 4.79999L6.88 10.57L5.13 8.56999C5.06508 8.49566 4.98613 8.43488 4.89768 8.39111C4.80922 8.34735 4.713 8.32148 4.61453 8.31498C4.51605 8.30847 4.41727 8.32147 4.32382 8.35322C4.23038 8.38497 4.14413 8.43484 4.07 8.49999C3.92511 8.63217 3.83692 8.81523 3.82387 9.01092C3.81083 9.2066 3.87393 9.39976 4 9.54999L6.43 12.24C6.50187 12.3204 6.58964 12.385 6.68775 12.4297Z', 12244 }); 12245 12246 svg.appendChild(g).append(path, path2); 12247 12248 const speakerDefs = createElementNS('defs'); 12249 const speakerClipPathDef = setAttributesNS(createElementNS('clipPath'), { 12250 id: 'clip0_57_156', 12251 }); 12252 12253 const speakerRect = setAttributesNS(createElementNS('rect'), { 12254 width: `${WIDTH}`, 12255 height: `${WIDTH}`, 12256 fill: 'white', 12257 transform: 'translate(0 0.5)', 12258 }); 12259 12260 speakerClipPathDef.appendChild(speakerRect); 12261 speakerDefs.appendChild(speakerClipPathDef); 12262 12263 svg.appendChild(speakerDefs).appendChild(speakerClipPathDef).appendChild(speakerRect); 12264 12265 return { 12266 get el() { 12267 return svg; 12268 }, 12269 }; 12270} 12271 12272/** 12273 * Feedback dialog component that has the form 12274 */ 12275function SuccessMessage({ message, onRemove }) { 12276 function remove() { 12277 if (!el) { 12278 return; 12279 } 12280 12281 el.remove(); 12282 onRemove && onRemove(); 12283 } 12284 12285 const el = createElement( 12286 'div', 12287 { 12288 className: 'success-message', 12289 onClick: remove, 12290 }, 12291 SuccessIcon().el, 12292 message, 12293 ); 12294 12295 return { 12296 el, 12297 remove, 12298 }; 12299} 12300 12301/** 12302 * Creates a new widget. Returns public methods that control widget behavior. 12303 */ 12304function createWidget({ 12305 shadow, 12306 options: { shouldCreateActor = true, ...options }, 12307 attachTo, 12308}) { 12309 let actor; 12310 let dialog; 12311 let isDialogOpen = false; 12312 12313 /** 12314 * Show the success message for 5 seconds 12315 */ 12316 function showSuccessMessage() { 12317 if (!shadow) { 12318 return; 12319 } 12320 12321 try { 12322 const success = SuccessMessage({ 12323 message: options.successMessageText, 12324 onRemove: () => { 12325 if (timeoutId) { 12326 clearTimeout(timeoutId); 12327 } 12328 showActor(); 12329 }, 12330 }); 12331 12332 if (!success.el) { 12333 throw new Error('Unable to show success message'); 12334 } 12335 12336 shadow.appendChild(success.el); 12337 12338 const timeoutId = setTimeout(() => { 12339 if (success) { 12340 success.remove(); 12341 } 12342 }, 5000); 12343 } catch (err) { 12344 // TODO: error handling 12345 utils.logger.error(err); 12346 } 12347 } 12348 12349 /** 12350 * Handler for when the feedback form is completed by the user. This will 12351 * create and send the feedback message as an event. 12352 */ 12353 async function _handleFeedbackSubmit(feedback) { 12354 if (!dialog) { 12355 return; 12356 } 12357 12358 // Simple validation for now, just check for non-empty required fields 12359 const emptyField = []; 12360 if (options.isNameRequired && !feedback.name) { 12361 emptyField.push(options.nameLabel); 12362 } 12363 if (options.isEmailRequired && !feedback.email) { 12364 emptyField.push(options.emailLabel); 12365 } 12366 if (!feedback.message) { 12367 emptyField.push(options.messageLabel); 12368 } 12369 if (emptyField.length > 0) { 12370 dialog.showError(`Please enter in the following required fields: ${emptyField.join(', ')}`); 12371 return; 12372 } 12373 12374 const result = await handleFeedbackSubmit(dialog, feedback); 12375 12376 // Error submitting feedback 12377 if (!result) { 12378 if (options.onSubmitError) { 12379 options.onSubmitError(); 12380 } 12381 12382 return; 12383 } 12384 12385 // Success 12386 removeDialog(); 12387 showSuccessMessage(); 12388 12389 if (options.onSubmitSuccess) { 12390 options.onSubmitSuccess(); 12391 } 12392 } 12393 12394 /** 12395 * Internal handler when dialog is opened 12396 */ 12397 function handleOpenDialog() { 12398 // Flush replay if integration exists 12399 const client = core.getClient(); 12400 const replay = 12401 client && 12402 client.getIntegrationByName && 12403 client.getIntegrationByName('Replay'); 12404 if (!replay) { 12405 return; 12406 } 12407 replay.flush().catch(err => { 12408 DEBUG_BUILD && utils.logger.error(err); 12409 }); 12410 } 12411 12412 /** 12413 * Displays the default actor 12414 */ 12415 function showActor() { 12416 actor && actor.show(); 12417 } 12418 12419 /** 12420 * Hides the default actor 12421 */ 12422 function hideActor() { 12423 actor && actor.hide(); 12424 } 12425 12426 /** 12427 * Removes the default actor element 12428 */ 12429 function removeActor() { 12430 actor && actor.el && actor.el.remove(); 12431 } 12432 12433 /** 12434 * 12435 */ 12436 function openDialog() { 12437 try { 12438 if (dialog) { 12439 dialog.open(); 12440 isDialogOpen = true; 12441 if (options.onFormOpen) { 12442 options.onFormOpen(); 12443 } 12444 handleOpenDialog(); 12445 return; 12446 } 12447 12448 const userKey = options.useSentryUser; 12449 const scope = core.getCurrentScope(); 12450 const user = scope && scope.getUser(); 12451 12452 dialog = Dialog({ 12453 colorScheme: options.colorScheme, 12454 showBranding: options.showBranding, 12455 showName: options.showName || options.isNameRequired,
12456 showEmail: options.showEmail || options.isEmailRequired, 12457 isNameRequired: options.isNameRequired, 12458 isEmailRequired: options.isEmailRequired, 12459 formTitle: options.formTitle, 12460 cancelButtonLabel: options.cancelButtonLabel, 12461 submitButtonLabel: options.submitButtonLabel, 12462 emailLabel: options.emailLabel, 12463 emailPlaceholder: options.emailPlaceholder, 12464 messageLabel: options.messageLabel, 12465 messagePlaceholder: options.messagePlaceholder, 12466 nameLabel: options.nameLabel, 12467 namePlaceholder: options.namePlaceholder, 12468 defaultName: (userKey && user && user[userKey.name]) || '', 12469 defaultEmail: (userKey && user && user[userKey.email]) || '', 12470 onClosed: () => { 12471 showActor(); 12472 isDialogOpen = false; 12473 12474 if (options.onFormClose) { 12475 options.onFormClose(); 12476 } 12477 }, 12478 onCancel: () => { 12479 closeDialog(); 12480 showActor(); 12481 }, 12482 onSubmit: _handleFeedbackSubmit, 12483 }); 12484 12485 if (!dialog.el) { 12486 throw new Error('Unable to open Feedback dialog'); 12487 } 12488 12489 shadow.appendChild(dialog.el); 12490 12491 // Hides the default actor whenever dialog is opened 12492 hideActor(); 12493 12494 if (options.onFormOpen) { 12495 options.onFormOpen(); 12496 } 12497 handleOpenDialog(); 12498 } catch (err) { 12499 // TODO: Error handling? 12500 utils.logger.error(err); 12501 } 12502 } 12503 12504 /** 12505 * Closes the dialog 12506 */ 12507 function closeDialog() { 12508 if (dialog) { 12509 dialog.close(); 12510 isDialogOpen = false; 12511 12512 if (options.onFormClose) { 12513 options.onFormClose(); 12514 } 12515 } 12516 } 12517 12518 /** 12519 * Removes the dialog element from DOM 12520 */ 12521 function removeDialog() { 12522 if (dialog) { 12523 closeDialog(); 12524 const dialogEl = dialog.el; 12525 dialogEl && dialogEl.remove(); 12526 dialog = undefined; 12527 } 12528 } 12529 12530 /** 12531 * 12532 */ 12533 function handleActorClick() { 12534 // Open dialog 12535 if (!isDialogOpen) { 12536 openDialog(); 12537 } 12538 12539 // Hide actor button 12540 hideActor(); 12541 } 12542 12543 if (attachTo) { 12544 attachTo.addEventListener('click', handleActorClick); 12545 } else if (shouldCreateActor) { 12546 actor = Actor({ buttonLabel: options.buttonLabel, onClick: handleActorClick }); 12547 actor.el && shadow.appendChild(actor.el); 12548 } 12549 12550 return { 12551 get actor() { 12552 return actor; 12553 }, 12554 get dialog() { 12555 return dialog; 12556 }, 12557 12558 showActor, 12559 hideActor, 12560 removeActor, 12561 12562 openDialog, 12563 closeDialog, 12564 removeDialog, 12565 }; 12566} 12567 12568const doc = WINDOW.document; 12569 12570const feedbackIntegration = ((options) => { 12571 // eslint-disable-next-line deprecation/deprecation 12572 return new Feedback(options); 12573}) ; 12574 12575/** 12576 * Feedback integration. When added as an integration to the SDK, it will 12577 * inject a button in the bottom-right corner of the window that opens a 12578 * feedback modal when clicked. 12579 * 12580 * @deprecated Use `feedbackIntegration()` instead. 12581 */ 12582class Feedback { 12583 /** 12584 * @inheritDoc 12585 */ 12586 static __initStatic() {this.id = 'Feedback';} 12587 12588 /** 12589 * @inheritDoc 12590 */ 12591 12592 /** 12593 * Feedback configuration options 12594 */ 12595 12596 /** 12597 * Reference to widget element that is created when autoInject is true 12598 */ 12599 12600 /** 12601 * List of all widgets that are created from the integration 12602 */ 12603 12604 /** 12605 * Reference to the host element where widget is inserted 12606 */ 12607 12608 /** 12609 * Refernce to Shadow DOM root 12610 */ 12611 12612 /** 12613 * Tracks if actor styles have ever been inserted into shadow DOM 12614 */ 12615 12616 constructor({ 12617 autoInject = true, 12618 id = 'sentry-feedback', 12619 isEmailRequired = false, 12620 isNameRequired = false, 12621 showBranding = true, 12622 showEmail = true, 12623 showName = true, 12624 useSentryUser = { 12625 email: 'email', 12626 name: 'username', 12627 }, 12628 12629 themeDark, 12630 themeLight, 12631 colorScheme = 'system', 12632 12633 buttonLabel = ACTOR_LABEL, 12634 cancelButtonLabel = CANCEL_BUTTON_LABEL, 12635 submitButtonLabel = SUBMIT_BUTTON_LABEL, 12636 formTitle = FORM_TITLE, 12637 emailPlaceholder = EMAIL_PLACEHOLDER, 12638 emailLabel = EMAIL_LABEL, 12639 messagePlaceholder = MESSAGE_PLACEHOLDER, 12640 messageLabel = MESSAGE_LABEL, 12641 namePlaceholder = NAME_PLACEHOLDER, 12642 nameLabel = NAME_LABEL, 12643 successMessageText = SUCCESS_MESSAGE_TEXT, 12644 12645 onFormClose, 12646 onFormOpen, 12647 onSubmitError, 12648 onSubmitSuccess, 12649 } = {}) { 12650 // eslint-disable-next-line deprecation/deprecation 12651 this.name = Feedback.id; 12652 12653 // tsc fails if these are not initialized explicitly constructor, e.g. can't call `_initialize()` 12654 this._host = null; 12655 this._shadow = null; 12656 this._widget = null; 12657 this._widgets = new Set(); 12658 this._hasInsertedActorStyles = false;
12659 12660 this.options = { 12661 autoInject, 12662 showBranding, 12663 id, 12664 isEmailRequired, 12665 isNameRequired, 12666 showEmail, 12667 showName, 12668 useSentryUser, 12669 12670 colorScheme, 12671 themeDark: { 12672 ...DEFAULT_THEME.dark, 12673 ...themeDark, 12674 }, 12675 themeLight: { 12676 ...DEFAULT_THEME.light, 12677 ...themeLight, 12678 }, 12679 12680 buttonLabel, 12681 cancelButtonLabel, 12682 submitButtonLabel, 12683 formTitle, 12684 emailLabel, 12685 emailPlaceholder, 12686 messageLabel, 12687 messagePlaceholder, 12688 nameLabel, 12689 namePlaceholder, 12690 successMessageText, 12691 12692 onFormClose, 12693 onFormOpen, 12694 onSubmitError, 12695 onSubmitSuccess, 12696 }; 12697 } 12698 12699 /** 12700 * Setup and initialize feedback container 12701 */ 12702 setupOnce() { 12703 if (!utils.isBrowser()) { 12704 return; 12705 } 12706 12707 try { 12708 this._cleanupWidgetIfExists(); 12709 12710 const { autoInject } = this.options; 12711 12712 if (!autoInject) { 12713 // Nothing to do here 12714 return; 12715 } 12716 12717 this._createWidget(this.options); 12718 } catch (err) { 12719 DEBUG_BUILD && utils.logger.error(err); 12720 } 12721 } 12722 12723 /** 12724 * Allows user to open the dialog box. Creates a new widget if 12725 * `autoInject` was false, otherwise re-uses the default widget that was 12726 * created during initialization of the integration. 12727 */ 12728 openDialog() { 12729 if (!this._widget) { 12730 this._createWidget({ ...this.options, shouldCreateActor: false }); 12731 } 12732 12733 if (!this._widget) { 12734 return; 12735 } 12736 12737 this._widget.openDialog(); 12738 } 12739 12740 /** 12741 * Closes the dialog for the default widget, if it exists 12742 */ 12743 closeDialog() { 12744 if (!this._widget) { 12745 // Nothing to do if widget does not exist 12746 return; 12747 } 12748 12749 this._widget.closeDialog(); 12750 } 12751 12752 /** 12753 * Adds click listener to attached element to open a feedback dialog 12754 */ 12755 attachTo(el, optionOverrides) { 12756 try { 12757 const options = mergeOptions(this.options, optionOverrides || {}); 12758 12759 return this._ensureShadowHost(options, ({ shadow }) => { 12760 const targetEl = 12761 typeof el === 'string' ? doc.querySelector(el) : typeof el.addEventListener === 'function' ? el : null; 12762 12763 if (!targetEl) { 12764 DEBUG_BUILD && utils.logger.error('[Feedback] Unable to attach to target element'); 12765 return null; 12766 } 12767 12768 const widget = createWidget({ shadow, options, attachTo: targetEl }); 12769 this._widgets.add(widget); 12770 12771 if (!this._widget) { 12772 this._widget = widget; 12773 } 12774 12775 return widget; 12776 }); 12777 } catch (err) { 12778 DEBUG_BUILD && utils.logger.error(err); 12779 return null; 12780 } 12781 } 12782 12783 /** 12784 * Creates a new widget. Accepts partial options to override any options passed to constructor. 12785 */ 12786 createWidget( 12787 optionOverrides, 12788 ) { 12789 try { 12790 return this._createWidget(mergeOptions(this.options, optionOverrides || {})); 12791 } catch (err) { 12792 DEBUG_BUILD && utils.logger.error(err); 12793 return null; 12794 } 12795 } 12796 12797 /** 12798 * Removes a single widget 12799 */ 12800 removeWidget(widget) { 12801 if (!widget) { 12802 return false; 12803 } 12804 12805 try { 12806 if (this._widgets.has(widget)) { 12807 widget.removeActor(); 12808 widget.removeDialog(); 12809 this._widgets.delete(widget); 12810 12811 if (this._widget === widget) { 12812 // TODO: is more clean-up needed? e.g. call remove() 12813 this._widget = null; 12814 } 12815 12816 return true; 12817 } 12818 } catch (err) { 12819 DEBUG_BUILD && utils.logger.error(err); 12820 } 12821 12822 return false; 12823 } 12824 12825 /** 12826 * Returns the default (first-created) widget 12827 */ 12828 getWidget() { 12829 return this._widget; 12830 } 12831 12832 /** 12833 * Removes the Feedback integration (including host, shadow DOM, and all widgets) 12834 */ 12835 remove() { 12836 if (this._host) { 12837 this._host.remove(); 12838 } 12839 this._initialize(); 12840 } 12841 12842 /** 12843 * Initializes values of protected properties 12844 */ 12845 _initialize() { 12846 this._host = null; 12847 this._shadow = null; 12848 this._widget = null; 12849 this._widgets = new Set(); 12850 this._hasInsertedActorStyles = false; 12851 } 12852 12853 /** 12854 * Clean-up the widget if it already exists in the DOM. This shouldn't happen 12855 * in prod, but can happen in development with hot module reloading. 12856 */ 12857 _cleanupWidgetIfExists() { 12858 if (this._host) { 12859 this.remove(); 12860 } 12861 const existingFeedback = doc.querySelector(`#${this.options.id}`); 12862 if (existingFeedback) { 12863 existingFeedback.remove(); 12864 } 12865 } 12866 12867 /** 12868 * Creates a new widget, after ensuring shadow DOM exists 12869 */ 12870 _createWidget(options) { 12871 return this._ensureShadowHost(options, ({ shadow }) => { 12872 const widget = createWidget({ shadow, options }); 12873 12874 if (!this._hasInsertedActorStyles && widget.actor) { 12875 shadow.appendChild(createActorStyles(doc)); 12876 this._hasInsertedActorStyles = true; 12877 } 12878 12879 this._widgets.add(widget); 12880 12881 if (!this._widget) { 12882 this._widget = widget; 12883 } 12884 12885 return widget; 12886 }); 12887 } 12888 12889 /** 12890 * Ensures that shadow DOM exists and is added to the DOM 12891 */ 12892 _ensureShadowHost( 12893 options, 12894 cb, 12895 ) { 12896 let needsAppendHost = false;
12897 12898 // Don't create if it already exists 12899 if (!this._shadow || !this._host) { 12900 const { id, colorScheme, themeLight, themeDark } = options; 12901 const { shadow, host } = createShadowHost({ 12902 id, 12903 colorScheme, 12904 themeLight, 12905 themeDark, 12906 }); 12907 this._shadow = shadow; 12908 this._host = host; 12909 needsAppendHost = true; 12910 } 12911 12912 // set data attribute on host for different themes 12913 this._host.dataset.sentryFeedbackColorscheme = options.colorScheme; 12914 12915 const result = cb({ shadow: this._shadow, host: this._host }); 12916 12917 if (needsAppendHost) { 12918 doc.body.appendChild(this._host); 12919 } 12920 12921 return result; 12922 } 12923} Feedback.__initStatic(); 12924 12925exports.Feedback = Feedback; 12926exports.feedbackIntegration = feedbackIntegration; 12927exports.sendFeedback = sendFeedback; 12928 12929 12930},{"@sentry/core":250,"@sentry/utils":319}],183:[function(require,module,exports){ 12931var { 12932 _optionalChain 12933} = require('@sentry/utils'); 12934 12935Object.defineProperty(exports, '__esModule', { value: true }); 12936 12937const core = require('@sentry/core'); 12938 12939var NodeType; 12940(function (NodeType) { 12941 NodeType[NodeType["Document"] = 0] = "Document"; 12942 NodeType[NodeType["DocumentType"] = 1] = "DocumentType"; 12943 NodeType[NodeType["Element"] = 2] = "Element"; 12944 NodeType[NodeType["Text"] = 3] = "Text"; 12945 NodeType[NodeType["CDATA"] = 4] = "CDATA"; 12946 NodeType[NodeType["Comment"] = 5] = "Comment"; 12947})(NodeType || (NodeType = {})); 12948function elementClassMatchesRegex(el, regex) { 12949 for (let eIndex = el.classList.length; eIndex--;) { 12950 const className = el.classList[eIndex]; 12951 if (regex.test(className)) { 12952 return true; 12953 } 12954 } 12955 return false; 12956} 12957function distanceToMatch(node, matchPredicate, limit = Infinity, distance = 0) { 12958 if (!node) 12959 return -1; 12960 if (node.nodeType !== node.ELEMENT_NODE) 12961 return -1; 12962 if (distance > limit) 12963 return -1; 12964 if (matchPredicate(node)) 12965 return distance; 12966 return distanceToMatch(node.parentNode, matchPredicate, limit, distance + 1); 12967} 12968function createMatchPredicate(className, selector) { 12969 return (node) => { 12970 const el = node; 12971 if (el === null) 12972 return false; 12973 try { 12974 if (className) { 12975 if (typeof className === 'string') { 12976 if (el.matches(`.${className}`)) 12977 return true; 12978 } 12979 else if (elementClassMatchesRegex(el, className)) { 12980 return true; 12981 } 12982 } 12983 if (selector && el.matches(selector)) 12984 return true; 12985 return false; 12986 } 12987 catch (e2) { 12988 return false; 12989 } 12990 }; 12991} 12992 12993const DEPARTED_MIRROR_ACCESS_WARNING = 'Please stop import mirror directly. Instead of that,' + 12994 '\r\n' + 12995 'now you can use replayer.getMirror() to access the mirror instance of a replayer,' + 12996 '\r\n' + 12997 'or you can use record.mirror to access the mirror instance during recording.'; 12998let _mirror = { 12999 map: {}, 13000 getId() { 13001 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 13002 return -1; 13003 }, 13004 getNode() { 13005 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 13006 return null; 13007 }, 13008 removeNodeFromMap() { 13009 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 13010 }, 13011 has() { 13012 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 13013 return false; 13014 }, 13015 reset() { 13016 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 13017 }, 13018}; 13019if (typeof window !== 'undefined' && window.Proxy && window.Reflect) { 13020 _mirror = new Proxy(_mirror, { 13021 get(target, prop, receiver) { 13022 if (prop === 'map') { 13023 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 13024 } 13025 return Reflect.get(target, prop, receiver); 13026 }, 13027 }); 13028} 13029function hookSetter(target, key, d, isRevoked, win = window) { 13030 const original = win.Object.getOwnPropertyDescriptor(target, key); 13031 win.Object.defineProperty(target, key, isRevoked 13032 ? d 13033 : { 13034 set(value) { 13035 setTimeout(() => { 13036 d.set.call(this, value); 13037 }, 0); 13038 if (original && original.set) { 13039 original.set.call(this, value); 13040 } 13041 }, 13042 }); 13043 return () => hookSetter(target, key, original || {}, true); 13044} 13045function patch(source, name, replacement) { 13046 try { 13047 if (!(name in source)) { 13048 return () => { 13049 }; 13050 } 13051 const original = source[name]; 13052 const wrapped = replacement(original); 13053 if (typeof wrapped === 'function') { 13054 wrapped.prototype = wrapped.prototype || {}; 13055 Object.defineProperties(wrapped, { 13056 __rrweb_original__: { 13057 enumerable: false, 13058 value: original, 13059 }, 13060 }); 13061 } 13062 source[name] = wrapped; 13063 return () => { 13064 source[name] = original; 13065 }; 13066 } 13067 catch (e2) { 13068 return () => { 13069 }; 13070 } 13071} 13072if (!(/[1-9][0-9]{12}/.test(Date.now().toString()))) ; 13073function isBlocked(node, blockClass, blockSelector, unblockSelector, checkAncestors) { 13074 if (!node) { 13075 return false;
vendor: 6,616 bytes, lines 13076-13285
13076 } 13077 const el = node.nodeType === node.ELEMENT_NODE 13078 ? node 13079 : node.parentElement; 13080 if (!el) 13081 return false; 13082 const blockedPredicate = createMatchPredicate(blockClass, blockSelector); 13083 if (!checkAncestors) { 13084 const isUnblocked = unblockSelector && el.matches(unblockSelector); 13085 return blockedPredicate(el) && !isUnblocked; 13086 } 13087 const blockDistance = distanceToMatch(el, blockedPredicate); 13088 let unblockDistance = -1; 13089 if (blockDistance < 0) { 13090 return false; 13091 } 13092 if (unblockSelector) { 13093 unblockDistance = distanceToMatch(el, createMatchPredicate(null, unblockSelector)); 13094 } 13095 if (blockDistance > -1 && unblockDistance < 0) { 13096 return true; 13097 } 13098 return blockDistance < unblockDistance; 13099} 13100let cachedRequestAnimationFrameImplementation; 13101function getRequestAnimationFrameImplementation() { 13102 if (cachedRequestAnimationFrameImplementation) { 13103 return cachedRequestAnimationFrameImplementation; 13104 } 13105 const document = window.document; 13106 let requestAnimationFrameImplementation = window.requestAnimationFrame; 13107 if (document && typeof document.createElement === 'function') { 13108 try { 13109 const sandbox = document.createElement('iframe'); 13110 sandbox.hidden = true; 13111 document.head.appendChild(sandbox); 13112 const contentWindow = sandbox.contentWindow; 13113 if (contentWindow && contentWindow.requestAnimationFrame) { 13114 requestAnimationFrameImplementation = 13115 contentWindow.requestAnimationFrame; 13116 } 13117 document.head.removeChild(sandbox); 13118 } 13119 catch (e) { 13120 } 13121 } 13122 return (cachedRequestAnimationFrameImplementation = 13123 requestAnimationFrameImplementation.bind(window)); 13124} 13125function onRequestAnimationFrame(...rest) { 13126 return getRequestAnimationFrameImplementation()(...rest); 13127} 13128 13129var CanvasContext = /* @__PURE__ */ ((CanvasContext2) => { 13130 CanvasContext2[CanvasContext2["2D"] = 0] = "2D"; 13131 CanvasContext2[CanvasContext2["WebGL"] = 1] = "WebGL"; 13132 CanvasContext2[CanvasContext2["WebGL2"] = 2] = "WebGL2"; 13133 return CanvasContext2; 13134})(CanvasContext || {}); 13135 13136let errorHandler; 13137function registerErrorHandler(handler) { 13138 errorHandler = handler; 13139} 13140const callbackWrapper = (cb) => { 13141 if (!errorHandler) { 13142 return cb; 13143 } 13144 const rrwebWrapped = ((...rest) => { 13145 try { 13146 return cb(...rest); 13147 } 13148 catch (error) { 13149 if (errorHandler && errorHandler(error) === true) { 13150 return () => { 13151 }; 13152 } 13153 throw error; 13154 } 13155 }); 13156 return rrwebWrapped; 13157}; 13158 13159/* 13160 * base64-arraybuffer 1.0.1 <https://github.com/niklasvh/base64-arraybuffer> 13161 * Copyright (c) 2021 Niklas von Hertzen <https://hertzen.com> 13162 * Released under MIT License 13163 */ 13164var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 13165// Use a lookup table to find the index. 13166var lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256); 13167for (var i = 0; i < chars.length; i++) { 13168 lookup[chars.charCodeAt(i)] = i; 13169} 13170var encode = function (arraybuffer) { 13171 var bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = ''; 13172 for (i = 0; i < len; i += 3) { 13173 base64 += chars[bytes[i] >> 2]; 13174 base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; 13175 base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; 13176 base64 += chars[bytes[i + 2] & 63]; 13177 } 13178 if (len % 3 === 2) { 13179 base64 = base64.substring(0, base64.length - 1) + '='; 13180 } 13181 else if (len % 3 === 1) { 13182 base64 = base64.substring(0, base64.length - 2) + '=='; 13183 } 13184 return base64; 13185}; 13186 13187const canvasVarMap = new Map(); 13188function variableListFor(ctx, ctor) { 13189 let contextMap = canvasVarMap.get(ctx); 13190 if (!contextMap) { 13191 contextMap = new Map(); 13192 canvasVarMap.set(ctx, contextMap); 13193 } 13194 if (!contextMap.has(ctor)) { 13195 contextMap.set(ctor, []); 13196 } 13197 return contextMap.get(ctor); 13198} 13199const saveWebGLVar = (value, win, ctx) => { 13200 if (!value || 13201 !(isInstanceOfWebGLObject(value, win) || typeof value === 'object')) 13202 return; 13203 const name = value.constructor.name; 13204 const list = variableListFor(ctx, name); 13205 let index = list.indexOf(value); 13206 if (index === -1) { 13207 index = list.length; 13208 list.push(value); 13209 } 13210 return index; 13211}; 13212function serializeArg(value, win, ctx) { 13213 if (value instanceof Array) { 13214 return value.map((arg) => serializeArg(arg, win, ctx)); 13215 } 13216 else if (value === null) { 13217 return value; 13218 } 13219 else if (value instanceof Float32Array || 13220 value instanceof Float64Array || 13221 value instanceof Int32Array || 13222 value instanceof Uint32Array || 13223 value instanceof Uint8Array || 13224 value instanceof Uint16Array || 13225 value instanceof Int16Array || 13226 value instanceof Int8Array || 13227 value instanceof Uint8ClampedArray) { 13228 const name = value.constructor.name; 13229 return { 13230 rr_type: name, 13231 args: [Object.values(value)], 13232 }; 13233 } 13234 else if (value instanceof ArrayBuffer) { 13235 const name = value.constructor.name; 13236 const base64 = encode(value); 13237 return { 13238 rr_type: name, 13239 base64, 13240 }; 13241 } 13242 else if (value instanceof DataView) { 13243 const name = value.constructor.name; 13244 return { 13245 rr_type: name, 13246 args: [ 13247 serializeArg(value.buffer, win, ctx), 13248 value.byteOffset, 13249 value.byteLength, 13250 ], 13251 }; 13252 } 13253 else if (value instanceof HTMLImageElement) { 13254 const name = value.constructor.name; 13255 const { src } = value; 13256 return { 13257 rr_type: name, 13258 src, 13259 }; 13260 } 13261 else if (value instanceof HTMLCanvasElement) { 13262 const name = 'HTMLImageElement'; 13263 const src = value.toDataURL(); 13264 return { 13265 rr_type: name, 13266 src, 13267 }; 13268 } 13269 else if (value instanceof ImageData) { 13270 const name = value.constructor.name; 13271 return { 13272 rr_type: name, 13273 args: [serializeArg(value.data, win, ctx), value.width, value.height], 13274 }; 13275 } 13276 else if (isInstanceOfWebGLObject(value, win) || typeof value === 'object') { 13277 const name = value.constructor.name; 13278 const index = saveWebGLVar(value, win, ctx); 13279 return { 13280 rr_type: name, 13281 index: index, 13282 }; 13283 } 13284 return value; 13285}
13286const serializeArgs = (args, win, ctx) => { 13287 return args.map((arg) => serializeArg(arg, win, ctx)); 13288}; 13289const isInstanceOfWebGLObject = (value, win) => { 13290 const webGLConstructorNames = [ 13291 'WebGLActiveInfo', 13292 'WebGLBuffer', 13293 'WebGLFramebuffer', 13294 'WebGLProgram', 13295 'WebGLRenderbuffer', 13296 'WebGLShader', 13297 'WebGLShaderPrecisionFormat', 13298 'WebGLTexture', 13299 'WebGLUniformLocation', 13300 'WebGLVertexArrayObject', 13301 'WebGLVertexArrayObjectOES', 13302 ]; 13303 const supportedWebGLConstructorNames = webGLConstructorNames.filter((name) => typeof win[name] === 'function'); 13304 return Boolean(supportedWebGLConstructorNames.find((name) => value instanceof win[name])); 13305}; 13306 13307function initCanvas2DMutationObserver(cb, win, blockClass, blockSelector, unblockSelector) { 13308 const handlers = []; 13309 const props2D = Object.getOwnPropertyNames(win.CanvasRenderingContext2D.prototype); 13310 for (const prop of props2D) { 13311 try { 13312 if (typeof win.CanvasRenderingContext2D.prototype[prop] !== 'function') { 13313 continue; 13314 } 13315 const restoreHandler = patch(win.CanvasRenderingContext2D.prototype, prop, function (original) { 13316 return function (...args) { 13317 if (!isBlocked(this.canvas, blockClass, blockSelector, unblockSelector, true)) { 13318 setTimeout(() => { 13319 const recordArgs = serializeArgs(args, win, this); 13320 cb(this.canvas, { 13321 type: CanvasContext['2D'], 13322 property: prop, 13323 args: recordArgs, 13324 }); 13325 }, 0); 13326 } 13327 return original.apply(this, args); 13328 }; 13329 }); 13330 handlers.push(restoreHandler); 13331 } 13332 catch (e) { 13333 const hookHandler = hookSetter(win.CanvasRenderingContext2D.prototype, prop, { 13334 set(v) { 13335 cb(this.canvas, { 13336 type: CanvasContext['2D'], 13337 property: prop, 13338 args: [v], 13339 setter: true, 13340 }); 13341 }, 13342 }); 13343 handlers.push(hookHandler); 13344 } 13345 } 13346 return () => { 13347 handlers.forEach((h) => h()); 13348 }; 13349} 13350 13351function getNormalizedContextName(contextType) { 13352 return contextType === 'experimental-webgl' ? 'webgl' : contextType; 13353} 13354function initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector, setPreserveDrawingBufferToTrue) { 13355 const handlers = []; 13356 try { 13357 const restoreHandler = patch(win.HTMLCanvasElement.prototype, 'getContext', function (original) { 13358 return function (contextType, ...args) { 13359 if (!isBlocked(this, blockClass, blockSelector, unblockSelector, true)) { 13360 const ctxName = getNormalizedContextName(contextType); 13361 if (!('__context' in this)) 13362 this.__context = ctxName; 13363 if (setPreserveDrawingBufferToTrue && 13364 ['webgl', 'webgl2'].includes(ctxName)) { 13365 if (args[0] && typeof args[0] === 'object') { 13366 const contextAttributes = args[0]; 13367 if (!contextAttributes.preserveDrawingBuffer) { 13368 contextAttributes.preserveDrawingBuffer = true; 13369 } 13370 } 13371 else { 13372 args.splice(0, 1, { 13373 preserveDrawingBuffer: true, 13374 }); 13375 } 13376 } 13377 } 13378 return original.apply(this, [contextType, ...args]); 13379 }; 13380 }); 13381 handlers.push(restoreHandler); 13382 } 13383 catch (e) { 13384 console.error('failed to patch HTMLCanvasElement.prototype.getContext'); 13385 } 13386 return () => {
13387 handlers.forEach((h) => h()); 13388 }; 13389} 13390 13391function patchGLPrototype(prototype, type, cb, blockClass, blockSelector, unblockSelector, mirror, win) { 13392 const handlers = []; 13393 const props = Object.getOwnPropertyNames(prototype); 13394 for (const prop of props) { 13395 if ([ 13396 'isContextLost', 13397 'canvas', 13398 'drawingBufferWidth', 13399 'drawingBufferHeight', 13400 ].includes(prop)) { 13401 continue; 13402 } 13403 try { 13404 if (typeof prototype[prop] !== 'function') { 13405 continue; 13406 } 13407 const restoreHandler = patch(prototype, prop, function (original) { 13408 return function (...args) { 13409 const result = original.apply(this, args); 13410 saveWebGLVar(result, win, this); 13411 if ('tagName' in this.canvas && 13412 !isBlocked(this.canvas, blockClass, blockSelector, unblockSelector, true)) { 13413 const recordArgs = serializeArgs(args, win, this); 13414 const mutation = { 13415 type, 13416 property: prop, 13417 args: recordArgs, 13418 }; 13419 cb(this.canvas, mutation); 13420 } 13421 return result; 13422 }; 13423 }); 13424 handlers.push(restoreHandler); 13425 } 13426 catch (e) { 13427 const hookHandler = hookSetter(prototype, prop, { 13428 set(v) { 13429 cb(this.canvas, { 13430 type, 13431 property: prop, 13432 args: [v], 13433 setter: true, 13434 }); 13435 }, 13436 }); 13437 handlers.push(hookHandler); 13438 } 13439 } 13440 return handlers; 13441} 13442function initCanvasWebGLMutationObserver(cb, win, blockClass, blockSelector, unblockSelector, mirror) { 13443 const handlers = []; 13444 handlers.push(...patchGLPrototype(win.WebGLRenderingContext.prototype, CanvasContext.WebGL, cb, blockClass, blockSelector, unblockSelector, mirror, win)); 13445 if (typeof win.WebGL2RenderingContext !== 'undefined') { 13446 handlers.push(...patchGLPrototype(win.WebGL2RenderingContext.prototype, CanvasContext.WebGL2, cb, blockClass, blockSelector, unblockSelector, mirror, win)); 13447 } 13448 return () => { 13449 handlers.forEach((h) => h()); 13450 }; 13451} 13452 13453var r = `for(var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",e="undefined"==typeof Uint8Array?[]:new Uint8Array(256),n=0;n<64;n++)e[t.charCodeAt(n)]=n;var a=function(e){var n,a=new Uint8Array(e),s=a.length,r="";for(n=0;n<s;n+=3)r+=t[a[n]>>2],r+=t[(3&a[n])<<4|a[n+1]>>4],r+=t[(15&a[n+1])<<2|a[n+2]>>6],r+=t[63&a[n+2]];return s%3==2?r=r.substring(0,r.length-1)+"=":s%3==1&&(r=r.substring(0,r.length-2)+"=="),r};const s=new Map,r=new Map;const i=self;i.onmessage=async function(t){if(!("OffscreenCanvas"in globalThis))return i.postMessage({id:t.data.id});{const{id:e,bitmap:n,width:o,height:f,dataURLOptions:c}=t.data,g=async function(t,e,n){const s=t+"-"+e;if("OffscreenCanvas"in globalThis){if(r.has(s))return r.get(s);const i=new OffscreenCanvas(t,e);i.getContext("2d");const o=await i.convertToBlob(n),f=await o.arrayBuffer(),c=a(f);return r.set(s,c),c}return""}(o,f,c),d=new OffscreenCanvas(o,f);d.getContext("2d").drawImage(n,0,0),n.close();const u=await d.convertToBlob(c),h=u.type,w=await u.arrayBuffer(),l=a(w);if(!s.has(e)&&await g===l)return s.set(e,l),i.postMessage({id:e});if(s.get(e)===l)return i.postMessage({id:e});i.postMessage({id:e,type:h,base64:l,width:o,height:f}),s.set(e,l)}};`; 13454 13455function t(){const t=new Blob([r]);return URL.createObjectURL(t)} 13456 13457class CanvasManager { 13458 reset() { 13459 this.pendingCanvasMutations.clear(); 13460 this.resetObservers && this.resetObservers(); 13461 } 13462 freeze() { 13463 this.frozen = true; 13464 } 13465 unfreeze() { 13466 this.frozen = false; 13467 } 13468 lock() { 13469 this.locked = true; 13470 } 13471 unlock() { 13472 this.locked = false; 13473 } 13474 constructor(options) { 13475 this.pendingCanvasMutations = new Map(); 13476 this.rafStamps = { latestId: 0, invokeId: null }; 13477 this.frozen = false;
13478 this.locked = false; 13479 this.processMutation = (target, mutation) => { 13480 const newFrame = this.rafStamps.invokeId && 13481 this.rafStamps.latestId !== this.rafStamps.invokeId; 13482 if (newFrame || !this.rafStamps.invokeId) 13483 this.rafStamps.invokeId = this.rafStamps.latestId; 13484 if (!this.pendingCanvasMutations.has(target)) { 13485 this.pendingCanvasMutations.set(target, []); 13486 } 13487 this.pendingCanvasMutations.get(target).push(mutation); 13488 }; 13489 const { sampling = 'all', win, blockClass, blockSelector, unblockSelector, recordCanvas, dataURLOptions, errorHandler, } = options; 13490 this.mutationCb = options.mutationCb; 13491 this.mirror = options.mirror; 13492 this.options = options; 13493 if (errorHandler) { 13494 registerErrorHandler(errorHandler); 13495 } 13496 if (options.enableManualSnapshot) { 13497 return; 13498 } 13499 callbackWrapper(() => { 13500 if (recordCanvas && sampling === 'all') 13501 this.initCanvasMutationObserver(win, blockClass, blockSelector, unblockSelector); 13502 if (recordCanvas && typeof sampling === 'number') 13503 this.initCanvasFPSObserver(sampling, win, blockClass, blockSelector, unblockSelector, { 13504 dataURLOptions, 13505 }); 13506 })(); 13507 } 13508 initCanvasFPSObserver(fps, win, blockClass, blockSelector, unblockSelector, options) { 13509 const canvasContextReset = initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector, true); 13510 const rafId = this.takeSnapshot(false, fps, win, blockClass, blockSelector, unblockSelector, options.dataURLOptions); 13511 this.resetObservers = () => { 13512 canvasContextReset(); 13513 cancelAnimationFrame(rafId); 13514 }; 13515 } 13516 initCanvasMutationObserver(win, blockClass, blockSelector, unblockSelector) { 13517 this.startRAFTimestamping(); 13518 this.startPendingCanvasMutationFlusher(); 13519 const canvasContextReset = initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector, false); 13520 const canvas2DReset = initCanvas2DMutationObserver(this.processMutation.bind(this), win, blockClass, blockSelector, unblockSelector); 13521 const canvasWebGL1and2Reset = initCanvasWebGLMutationObserver(this.processMutation.bind(this), win, blockClass, blockSelector, unblockSelector, this.mirror); 13522 this.resetObservers = () => { 13523 canvasContextReset(); 13524 canvas2DReset(); 13525 canvasWebGL1and2Reset(); 13526 }; 13527 } 13528 snapshot(canvasElement) { 13529 const { options } = this; 13530 const rafId = this.takeSnapshot(true, options.sampling === 'all' ? 2 : options.sampling || 2, options.win, options.blockClass, options.blockSelector, options.unblockSelector, options.dataURLOptions, canvasElement); 13531 this.resetObservers = () => { 13532 cancelAnimationFrame(rafId); 13533 }; 13534 } 13535 takeSnapshot(isManualSnapshot, fps, win, blockClass, blockSelector, unblockSelector, dataURLOptions, canvasElement) { 13536 const snapshotInProgressMap = new Map(); 13537 const worker = new Worker(t()); 13538 worker.onmessage = (e) => { 13539 const data = e.data; 13540 const { id } = data; 13541 snapshotInProgressMap.set(id, false); 13542 if (!('base64' in data)) 13543 return; 13544 const { base64, type, width, height } = data; 13545 this.mutationCb({ 13546 id, 13547 type: CanvasContext['2D'], 13548 commands: [ 13549 { 13550 property: 'clearRect', 13551 args: [0, 0, width, height], 13552 }, 13553 { 13554 property: 'drawImage', 13555 args: [ 13556 { 13557 rr_type: 'ImageBitmap', 13558 args: [ 13559 { 13560 rr_type: 'Blob', 13561 data: [{ rr_type: 'ArrayBuffer', base64 }], 13562 type, 13563 }, 13564 ], 13565 }, 13566 0, 13567 0, 13568 ], 13569 }, 13570 ], 13571 }); 13572 }; 13573 const timeBetweenSnapshots = 1000 / fps; 13574 let lastSnapshotTime = 0; 13575 let rafId; 13576 const getCanvas = (canvasElement) => { 13577 if (canvasElement) { 13578 return [canvasElement]; 13579 } 13580 const matchedCanvas = []; 13581 win.document.querySelectorAll('canvas').forEach((canvas) => { 13582 if (!isBlocked(canvas, blockClass, blockSelector, unblockSelector, true)) { 13583 matchedCanvas.push(canvas); 13584 } 13585 }); 13586 return matchedCanvas; 13587 }; 13588 const takeCanvasSnapshots = (timestamp) => { 13589 if (lastSnapshotTime && 13590 timestamp - lastSnapshotTime < timeBetweenSnapshots) { 13591 rafId = onRequestAnimationFrame(takeCanvasSnapshots); 13592 return; 13593 } 13594 lastSnapshotTime = timestamp; 13595 getCanvas(canvasElement).forEach((canvas) => { 13596 const id = this.mirror.getId(canvas); 13597 if (snapshotInProgressMap.get(id)) 13598 return; 13599 snapshotInProgressMap.set(id, true); 13600 if (!isManualSnapshot && 13601 ['webgl', 'webgl2'].includes(canvas.__context)) { 13602 const context = canvas.getContext(canvas.__context); 13603 if (_optionalChain([context, 'optionalAccess', _ => _.getContextAttributes, 'call', _2 => _2(), 'optionalAccess', _3 => _3.preserveDrawingBuffer]) === false) { 13604 context.clear(context.COLOR_BUFFER_BIT); 13605 } 13606 } 13607 createImageBitmap(canvas) 13608 .then((bitmap) => { 13609 worker.postMessage({ 13610 id, 13611 bitmap, 13612 width: canvas.width, 13613 height: canvas.height, 13614 dataURLOptions, 13615 }, [bitmap]); 13616 }) 13617 .catch((error) => { 13618 callbackWrapper(() => { 13619 throw error; 13620 })(); 13621 }); 13622 }); 13623 rafId = onRequestAnimationFrame(takeCanvasSnapshots); 13624 }; 13625 rafId = onRequestAnimationFrame(takeCanvasSnapshots); 13626 return rafId; 13627 } 13628 startPendingCanvasMutationFlusher() { 13629 onRequestAnimationFrame(() => this.flushPendingCanvasMutations()); 13630 } 13631 startRAFTimestamping() {
13632 const setLatestRAFTimestamp = (timestamp) => { 13633 this.rafStamps.latestId = timestamp; 13634 onRequestAnimationFrame(setLatestRAFTimestamp); 13635 }; 13636 onRequestAnimationFrame(setLatestRAFTimestamp); 13637 } 13638 flushPendingCanvasMutations() { 13639 this.pendingCanvasMutations.forEach((values, canvas) => { 13640 const id = this.mirror.getId(canvas); 13641 this.flushPendingCanvasMutationFor(canvas, id); 13642 }); 13643 onRequestAnimationFrame(() => this.flushPendingCanvasMutations()); 13644 } 13645 flushPendingCanvasMutationFor(canvas, id) { 13646 if (this.frozen || this.locked) { 13647 return; 13648 } 13649 const valuesWithType = this.pendingCanvasMutations.get(canvas); 13650 if (!valuesWithType || id === -1) 13651 return; 13652 const values = valuesWithType.map((value) => { 13653 const { type, ...rest } = value; 13654 return rest; 13655 }); 13656 const { type } = valuesWithType[0]; 13657 this.mutationCb({ id, type, commands: values }); 13658 this.pendingCanvasMutations.delete(canvas); 13659 } 13660} 13661 13662const CANVAS_QUALITY = { 13663 low: { 13664 sampling: { 13665 canvas: 1, 13666 }, 13667 dataURLOptions: { 13668 type: 'image/webp', 13669 quality: 0.25, 13670 }, 13671 }, 13672 medium: { 13673 sampling: { 13674 canvas: 2, 13675 }, 13676 dataURLOptions: { 13677 type: 'image/webp', 13678 quality: 0.4, 13679 }, 13680 }, 13681 high: { 13682 sampling: { 13683 canvas: 4, 13684 }, 13685 dataURLOptions: { 13686 type: 'image/webp', 13687 quality: 0.5, 13688 }, 13689 }, 13690}; 13691 13692const INTEGRATION_NAME = 'ReplayCanvas'; 13693 13694/** Exported only for type safe tests. */ 13695const _replayCanvasIntegration = ((options = {}) => { 13696 const _canvasOptions = { 13697 quality: options.quality || 'medium', 13698 enableManualSnapshot: options.enableManualSnapshot, 13699 }; 13700 13701 let canvasManagerResolve; 13702 const _canvasManager = new Promise(resolve => (canvasManagerResolve = resolve)); 13703 13704 return { 13705 name: INTEGRATION_NAME, 13706 // eslint-disable-next-line @typescript-eslint/no-empty-function 13707 setupOnce() {}, 13708 getOptions() { 13709 const { quality, enableManualSnapshot } = _canvasOptions; 13710 13711 return { 13712 enableManualSnapshot, 13713 recordCanvas: true, 13714 getCanvasManager: (options) => { 13715 const manager = new CanvasManager({ 13716 ...options, 13717 enableManualSnapshot, 13718 errorHandler: (err) => { 13719 try { 13720 if (typeof err === 'object') { 13721 (err ).__rrweb__ = true; 13722 } 13723 } catch (error) { 13724 // ignore errors here 13725 // this can happen if the error is frozen or does not allow mutation for other reasons 13726 } 13727 }, 13728 }); 13729 canvasManagerResolve(manager); 13730 return manager; 13731 }, 13732 ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), 13733 }; 13734 }, 13735 async snapshot(canvasElement) { 13736 const canvasManager = await _canvasManager; 13737 canvasManager.snapshot(canvasElement); 13738 }, 13739 }; 13740}) ; 13741 13742/** 13743 * Add this in addition to `replayIntegration()` to enable canvas recording. 13744 */ 13745const replayCanvasIntegration = core.defineIntegration(_replayCanvasIntegration); 13746 13747/** 13748 * @deprecated Use `replayCanvasIntegration()` instead 13749 */ 13750// eslint-disable-next-line deprecation/deprecation 13751const ReplayCanvas = core.convertIntegrationFnToClass(INTEGRATION_NAME, replayCanvasIntegration) 13752 13753; 13754 13755exports.ReplayCanvas = ReplayCanvas; 13756exports.replayCanvasIntegration = replayCanvasIntegration; 13757 13758 13759},{"@sentry/core":250,"@sentry/utils":319}],184:[function(require,module,exports){ 13760Object.defineProperty(exports, '__esModule', { value: true }); 13761 13762const core = require('@sentry/core'); 13763const utils = require('@sentry/utils'); 13764const debugBuild = require('../common/debug-build.js'); 13765const types = require('./types.js'); 13766 13767/** 13768 * Add a listener that cancels and finishes a transaction when the global 13769 * document is hidden. 13770 */ 13771function registerBackgroundTabDetection() { 13772 if (types.WINDOW && types.WINDOW.document) { 13773 types.WINDOW.document.addEventListener('visibilitychange', () => { 13774 // eslint-disable-next-line deprecation/deprecation 13775 const activeTransaction = core.getActiveTransaction() ; 13776 if (types.WINDOW.document.hidden && activeTransaction) { 13777 const statusType = 'cancelled'; 13778 13779 const { op, status } = core.spanToJSON(activeTransaction); 13780 13781 debugBuild.DEBUG_BUILD && 13782 utils.logger.log(`[Tracing] Transaction: ${statusType} -> since tab moved to the background, op: ${op}`); 13783 // We should not set status if it is already set, this prevent important statuses like 13784 // error or data loss from being overwritten on transaction. 13785 if (!status) { 13786 activeTransaction.setStatus(statusType); 13787 } 13788 // TODO: Can we rewrite this to an attribute? 13789 // eslint-disable-next-line deprecation/deprecation 13790 activeTransaction.setTag('visibilitychange', 'document.hidden'); 13791 activeTransaction.end(); 13792 } 13793 }); 13794 } else { 13795 debugBuild.DEBUG_BUILD && utils.logger.warn('[Tracing] Could not set up background tab detection due to lack of global document'); 13796 } 13797} 13798
13799exports.registerBackgroundTabDetection = registerBackgroundTabDetection; 13800 13801 13802},{"../common/debug-build.js":206,"./types.js":192,"@sentry/core":250,"@sentry/utils":319}],185:[function(require,module,exports){ 13803Object.defineProperty(exports, '__esModule', { value: true }); 13804 13805const core = require('@sentry/core'); 13806const utils = require('@sentry/utils'); 13807const debugBuild = require('../common/debug-build.js'); 13808const backgroundtab = require('./backgroundtab.js'); 13809const instrument = require('./instrument.js'); 13810const index = require('./metrics/index.js'); 13811const request = require('./request.js'); 13812const types = require('./types.js'); 13813 13814const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing'; 13815 13816/** Options for Browser Tracing integration */ 13817 13818const DEFAULT_BROWSER_TRACING_OPTIONS = { 13819 ...core.TRACING_DEFAULTS, 13820 instrumentNavigation: true, 13821 instrumentPageLoad: true, 13822 markBackgroundSpan: true, 13823 enableLongTask: true, 13824 enableInp: false, 13825 _experiments: {}, 13826 ...request.defaultRequestInstrumentationOptions, 13827}; 13828 13829/** 13830 * The Browser Tracing integration automatically instruments browser pageload/navigation 13831 * actions as transactions, and captures requests, metrics and errors as spans. 13832 * 13833 * The integration can be configured with a variety of options, and can be extended to use 13834 * any routing library. This integration uses {@see IdleTransaction} to create transactions. 13835 * 13836 * We explicitly export the proper type here, as this has to be extended in some cases. 13837 */ 13838const browserTracingIntegration = ((_options = {}) => { 13839 const _hasSetTracePropagationTargets = debugBuild.DEBUG_BUILD 13840 ? !!( 13841 // eslint-disable-next-line deprecation/deprecation 13842 (_options.tracePropagationTargets || _options.tracingOrigins) 13843 ) 13844 : false; 13845 13846 core.addTracingExtensions(); 13847 13848 // TODO (v8): remove this block after tracingOrigins is removed 13849 // Set tracePropagationTargets to tracingOrigins if specified by the user 13850 // In case both are specified, tracePropagationTargets takes precedence 13851 // eslint-disable-next-line deprecation/deprecation 13852 if (!_options.tracePropagationTargets && _options.tracingOrigins) { 13853 // eslint-disable-next-line deprecation/deprecation 13854 _options.tracePropagationTargets = _options.tracingOrigins; 13855 } 13856 13857 const options = { 13858 ...DEFAULT_BROWSER_TRACING_OPTIONS, 13859 ..._options, 13860 }; 13861 13862 const _collectWebVitals = index.startTrackingWebVitals(); 13863 13864 /** Stores a mapping of interactionIds from PerformanceEventTimings to the origin interaction path */ 13865 const interactionIdtoRouteNameMapping = {}; 13866 if (options.enableInp) { 13867 index.startTrackingINP(interactionIdtoRouteNameMapping); 13868 } 13869 13870 if (options.enableLongTask) { 13871 index.startTrackingLongTasks(); 13872 } 13873 if (options._experiments.enableInteractions) { 13874 index.startTrackingInteractions(); 13875 } 13876 13877 const latestRoute 13878 13879 = { 13880 name: undefined, 13881 context: undefined, 13882 }; 13883 13884 /** Create routing idle transaction. */ 13885 function _createRouteTransaction(context) { 13886 // eslint-disable-next-line deprecation/deprecation 13887 const hub = core.getCurrentHub(); 13888 13889 const { beforeStartSpan, idleTimeout, finalTimeout, heartbeatInterval } = options; 13890 13891 const isPageloadTransaction = context.op === 'pageload'; 13892 13893 let expandedContext; 13894 if (isPageloadTransaction) { 13895 const sentryTrace = isPageloadTransaction ? getMetaContent('sentry-trace') : ''; 13896 const baggage = isPageloadTransaction ? getMetaContent('baggage') : undefined; 13897 const { traceId, dsc, parentSpanId, sampled } = utils.propagationContextFromHeaders(sentryTrace, baggage); 13898 expandedContext = { 13899 traceId, 13900 parentSpanId, 13901 parentSampled: sampled, 13902 ...context, 13903 metadata: { 13904 // eslint-disable-next-line deprecation/deprecation 13905 ...context.metadata, 13906 dynamicSamplingContext: dsc, 13907 }, 13908 trimEnd: true, 13909 }; 13910 } else { 13911 expandedContext = { 13912 trimEnd: true, 13913 ...context, 13914 }; 13915 } 13916 13917 const finalContext = beforeStartSpan ? beforeStartSpan(expandedContext) : expandedContext; 13918 13919 // If `beforeStartSpan` set a custom name, record that fact 13920 // eslint-disable-next-line deprecation/deprecation 13921 finalContext.metadata = 13922 finalContext.name !== expandedContext.name 13923 ? // eslint-disable-next-line deprecation/deprecation 13924 { ...finalContext.metadata, source: 'custom' } 13925 : // eslint-disable-next-line deprecation/deprecation 13926 finalContext.metadata; 13927 13928 latestRoute.name = finalContext.name; 13929 latestRoute.context = finalContext; 13930 13931 if (finalContext.sampled === false) { 13932 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Will not send ${finalContext.op} transaction because of beforeNavigate.`); 13933 } 13934 13935 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Starting ${finalContext.op} transaction on scope`); 13936 13937 const { location } = types.WINDOW; 13938 13939 const idleTransaction = core.startIdleTransaction( 13940 hub, 13941 finalContext, 13942 idleTimeout, 13943 finalTimeout, 13944 true, 13945 { location }, // for use in the tracesSampler 13946 heartbeatInterval, 13947 isPageloadTransaction, // should wait for finish signal if it's a pageload transaction 13948 ); 13949 13950 if (isPageloadTransaction && types.WINDOW.document) { 13951 types.WINDOW.document.addEventListener('readystatechange', () => { 13952 if (['interactive', 'complete'].includes(types.WINDOW.document.readyState)) { 13953 idleTransaction.sendAutoFinishSignal(); 13954 } 13955 }); 13956 13957 if (['interactive', 'complete'].includes(types.WINDOW.document.readyState)) { 13958 idleTransaction.sendAutoFinishSignal(); 13959 } 13960 } 13961 13962 idleTransaction.registerBeforeFinishCallback(transaction => { 13963 _collectWebVitals(); 13964 index.addPerformanceEntries(transaction); 13965 }); 13966 13967 return idleTransaction ; 13968 } 13969 13970 return { 13971 name: BROWSER_TRACING_INTEGRATION_ID, 13972 // eslint-disable-next-line @typescript-eslint/no-empty-function 13973 setupOnce: () => {}, 13974 afterAllSetup(client) { 13975 const clientOptions = client.getOptions(); 13976
13977 const { markBackgroundSpan, traceFetch, traceXHR, shouldCreateSpanForRequest, enableHTTPTimings, _experiments } = 13978 options; 13979 13980 const clientOptionsTracePropagationTargets = clientOptions && clientOptions.tracePropagationTargets; 13981 // There are three ways to configure tracePropagationTargets: 13982 // 1. via top level client option `tracePropagationTargets` 13983 // 2. via BrowserTracing option `tracePropagationTargets` 13984 // 3. via BrowserTracing option `tracingOrigins` (deprecated) 13985 // 13986 // To avoid confusion, favour top level client option `tracePropagationTargets`, and fallback to 13987 // BrowserTracing option `tracePropagationTargets` and then `tracingOrigins` (deprecated). 13988 // This is done as it minimizes bundle size (we don't have to have undefined checks). 13989 // 13990 // If both 1 and either one of 2 or 3 are set (from above), we log out a warning. 13991 // eslint-disable-next-line deprecation/deprecation 13992 const tracePropagationTargets = clientOptionsTracePropagationTargets || options.tracePropagationTargets; 13993 if (debugBuild.DEBUG_BUILD && _hasSetTracePropagationTargets && clientOptionsTracePropagationTargets) { 13994 utils.logger.warn( 13995 '[Tracing] The `tracePropagationTargets` option was set in the BrowserTracing integration and top level `Sentry.init`. The top level `Sentry.init` value is being used.', 13996 ); 13997 } 13998 13999 let activeSpan; 14000 let startingUrl = types.WINDOW.location && types.WINDOW.location.href; 14001 14002 if (client.on) { 14003 client.on('startNavigationSpan', (context) => { 14004 if (activeSpan) { 14005 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Finishing current transaction with op: ${core.spanToJSON(activeSpan).op}`); 14006 // If there's an open transaction on the scope, we need to finish it before creating an new one. 14007 activeSpan.end(); 14008 } 14009 activeSpan = _createRouteTransaction({ 14010 op: 'navigation', 14011 ...context, 14012 }); 14013 }); 14014 14015 client.on('startPageLoadSpan', (context) => { 14016 if (activeSpan) { 14017 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Finishing current transaction with op: ${core.spanToJSON(activeSpan).op}`); 14018 // If there's an open transaction on the scope, we need to finish it before creating an new one. 14019 activeSpan.end(); 14020 } 14021 activeSpan = _createRouteTransaction({ 14022 op: 'pageload', 14023 ...context, 14024 }); 14025 }); 14026 } 14027 14028 if (options.instrumentPageLoad && client.emit && types.WINDOW.location) { 14029 const context = { 14030 name: types.WINDOW.location.pathname, 14031 // pageload should always start at timeOrigin (and needs to be in s, not ms) 14032 startTimestamp: utils.browserPerformanceTimeOrigin ? utils.browserPerformanceTimeOrigin / 1000 : undefined, 14033 origin: 'auto.pageload.browser', 14034 attributes: { 14035 [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', 14036 }, 14037 }; 14038 startBrowserTracingPageLoadSpan(client, context); 14039 } 14040 14041 if (options.instrumentNavigation && client.emit && types.WINDOW.location) { 14042 utils.addHistoryInstrumentationHandler(({ to, from }) => { 14043 /** 14044 * This early return is there to account for some cases where a navigation transaction starts right after 14045 * long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't 14046 * create an uneccessary navigation transaction. 14047 * 14048 * This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also 14049 * only be caused in certain development environments where the usage of a hot module reloader is causing 14050 * errors. 14051 */ 14052 if (from === undefined && startingUrl && startingUrl.indexOf(to) !== -1) { 14053 startingUrl = undefined; 14054 return; 14055 } 14056 14057 if (from !== to) { 14058 startingUrl = undefined; 14059 const context = { 14060 name: types.WINDOW.location.pathname, 14061 origin: 'auto.navigation.browser', 14062 attributes: { 14063 [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', 14064 }, 14065 }; 14066 14067 startBrowserTracingNavigationSpan(client, context); 14068 } 14069 }); 14070 } 14071
14072 if (markBackgroundSpan) { 14073 backgroundtab.registerBackgroundTabDetection(); 14074 } 14075 14076 if (_experiments.enableInteractions) { 14077 registerInteractionListener(options, latestRoute); 14078 } 14079 14080 if (options.enableInp) { 14081 registerInpInteractionListener(interactionIdtoRouteNameMapping, latestRoute); 14082 } 14083 14084 request.instrumentOutgoingRequests({ 14085 traceFetch, 14086 traceXHR, 14087 tracePropagationTargets, 14088 shouldCreateSpanForRequest, 14089 enableHTTPTimings, 14090 }); 14091 }, 14092 // TODO v8: Remove this again 14093 // This is private API that we use to fix converted BrowserTracing integrations in Next.js & SvelteKit 14094 options, 14095 }; 14096}) ; 14097 14098/** 14099 * Manually start a page load span. 14100 * This will only do something if the BrowserTracing integration has been setup. 14101 */ 14102function startBrowserTracingPageLoadSpan(client, spanOptions) { 14103 if (!client.emit) { 14104 return; 14105 } 14106 14107 client.emit('startPageLoadSpan', spanOptions); 14108 14109 const span = core.getActiveSpan(); 14110 const op = span && core.spanToJSON(span).op; 14111 return op === 'pageload' ? span : undefined; 14112} 14113 14114/** 14115 * Manually start a navigation span. 14116 * This will only do something if the BrowserTracing integration has been setup. 14117 */ 14118function startBrowserTracingNavigationSpan(client, spanOptions) { 14119 if (!client.emit) { 14120 return; 14121 } 14122 14123 client.emit('startNavigationSpan', spanOptions); 14124 14125 const span = core.getActiveSpan(); 14126 const op = span && core.spanToJSON(span).op; 14127 return op === 'navigation' ? span : undefined; 14128} 14129 14130/** Returns the value of a meta tag */ 14131function getMetaContent(metaName) { 14132 // Can't specify generic to `getDomElement` because tracing can be used 14133 // in a variety of environments, have to disable `no-unsafe-member-access` 14134 // as a result. 14135 const metaTag = utils.getDomElement(`meta[name=${metaName}]`); 14136 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 14137 return metaTag ? metaTag.getAttribute('content') : undefined; 14138} 14139 14140/** Start listener for interaction transactions */ 14141function registerInteractionListener( 14142 options, 14143 latestRoute 14144 14145, 14146) { 14147 let inflightInteractionTransaction; 14148 const registerInteractionTransaction = () => { 14149 const { idleTimeout, finalTimeout, heartbeatInterval } = options; 14150 const op = 'ui.action.click'; 14151 14152 // eslint-disable-next-line deprecation/deprecation 14153 const currentTransaction = core.getActiveTransaction(); 14154 if (currentTransaction && currentTransaction.op && ['navigation', 'pageload'].includes(currentTransaction.op)) { 14155 debugBuild.DEBUG_BUILD && 14156 utils.logger.warn( 14157 `[Tracing] Did not create ${op} transaction because a pageload or navigation transaction is in progress.`, 14158 ); 14159 return undefined; 14160 } 14161 14162 if (inflightInteractionTransaction) { 14163 inflightInteractionTransaction.setFinishReason('interactionInterrupted'); 14164 inflightInteractionTransaction.end(); 14165 inflightInteractionTransaction = undefined; 14166 } 14167 14168 if (!latestRoute.name) { 14169 debugBuild.DEBUG_BUILD && utils.logger.warn(`[Tracing] Did not create ${op} transaction because _latestRouteName is missing.`); 14170 return undefined; 14171 } 14172 14173 const { location } = types.WINDOW; 14174 14175 const context = { 14176 name: latestRoute.name, 14177 op, 14178 trimEnd: true, 14179 data: { 14180 [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: latestRoute.context ? getSource(latestRoute.context) : 'url', 14181 }, 14182 }; 14183 14184 inflightInteractionTransaction = core.startIdleTransaction( 14185 // eslint-disable-next-line deprecation/deprecation 14186 core.getCurrentHub(), 14187 context, 14188 idleTimeout, 14189 finalTimeout, 14190 true, 14191 { location }, // for use in the tracesSampler 14192 heartbeatInterval, 14193 ); 14194 }; 14195 14196 ['click'].forEach(type => { 14197 addEventListener(type, registerInteractionTransaction, { once: false, capture: true }); 14198 }); 14199} 14200 14201function isPerformanceEventTiming(entry) { 14202 return 'duration' in entry; 14203} 14204 14205/** We store up to 10 interaction candidates max to cap memory usage. This is the same cap as getINP from web-vitals */ 14206const MAX_INTERACTIONS = 10; 14207 14208/** Creates a listener on interaction entries, and maps interactionIds to the origin path of the interaction */ 14209function registerInpInteractionListener( 14210 interactionIdtoRouteNameMapping, 14211 latestRoute 14212 14213, 14214) { 14215 instrument.addPerformanceInstrumentationHandler('event', ({ entries }) => { 14216 const client = core.getClient(); 14217 // We need to get the replay, user, and activeTransaction from the current scope 14218 // so that we can associate replay id, profile id, and a user display to the span 14219 const replay = 14220 client !== undefined && client.getIntegrationByName !== undefined 14221 ? (client.getIntegrationByName('Replay') ) 14222 : undefined; 14223 const replayId = replay !== undefined ? replay.getReplayId() : undefined; 14224 // eslint-disable-next-line deprecation/deprecation 14225 const activeTransaction = core.getActiveTransaction(); 14226 const currentScope = core.getCurrentScope(); 14227 const user = currentScope !== undefined ? currentScope.getUser() : undefined;
14228 for (const entry of entries) { 14229 if (isPerformanceEventTiming(entry)) { 14230 const duration = entry.duration; 14231 const keys = Object.keys(interactionIdtoRouteNameMapping); 14232 const minInteractionId = 14233 keys.length > 0 14234 ? keys.reduce((a, b) => { 14235 return interactionIdtoRouteNameMapping[a].duration < interactionIdtoRouteNameMapping[b].duration 14236 ? a 14237 : b; 14238 }) 14239 : undefined; 14240 if (minInteractionId === undefined || duration > interactionIdtoRouteNameMapping[minInteractionId].duration) { 14241 const interactionId = entry.interactionId; 14242 const routeName = latestRoute.name; 14243 const parentContext = latestRoute.context; 14244 if (interactionId && routeName && parentContext) { 14245 if (minInteractionId && Object.keys(interactionIdtoRouteNameMapping).length >= MAX_INTERACTIONS) { 14246 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 14247 delete interactionIdtoRouteNameMapping[minInteractionId]; 14248 } 14249 interactionIdtoRouteNameMapping[interactionId] = { 14250 routeName, 14251 duration, 14252 parentContext, 14253 user, 14254 activeTransaction, 14255 replayId, 14256 }; 14257 } 14258 } 14259 } 14260 } 14261 }); 14262} 14263 14264function getSource(context) { 14265 const sourceFromAttributes = context.attributes && context.attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]; 14266 // eslint-disable-next-line deprecation/deprecation 14267 const sourceFromData = context.data && context.data[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]; 14268 // eslint-disable-next-line deprecation/deprecation 14269 const sourceFromMetadata = context.metadata && context.metadata.source; 14270 14271 return sourceFromAttributes || sourceFromData || sourceFromMetadata; 14272} 14273 14274exports.BROWSER_TRACING_INTEGRATION_ID = BROWSER_TRACING_INTEGRATION_ID; 14275exports.browserTracingIntegration = browserTracingIntegration; 14276exports.getMetaContent = getMetaContent; 14277exports.startBrowserTracingNavigationSpan = startBrowserTracingNavigationSpan; 14278exports.startBrowserTracingPageLoadSpan = startBrowserTracingPageLoadSpan; 14279 14280 14281},{"../common/debug-build.js":206,"./backgroundtab.js":184,"./instrument.js":187,"./metrics/index.js":188,"./request.js":190,"./types.js":192,"@sentry/core":250,"@sentry/utils":319}],186:[function(require,module,exports){ 14282Object.defineProperty(exports, '__esModule', { value: true }); 14283 14284const core = require('@sentry/core'); 14285const utils = require('@sentry/utils'); 14286const debugBuild = require('../common/debug-build.js'); 14287const backgroundtab = require('./backgroundtab.js'); 14288const instrument = require('./instrument.js'); 14289const index = require('./metrics/index.js'); 14290const request = require('./request.js'); 14291const router = require('./router.js'); 14292const types = require('./types.js'); 14293 14294const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing'; 14295 14296/** Options for Browser Tracing integration */ 14297 14298const DEFAULT_BROWSER_TRACING_OPTIONS = { 14299 ...core.TRACING_DEFAULTS, 14300 markBackgroundTransactions: true, 14301 routingInstrumentation: router.instrumentRoutingWithDefaults, 14302 startTransactionOnLocationChange: true, 14303 startTransactionOnPageLoad: true, 14304 enableLongTask: true, 14305 enableInp: false, 14306 _experiments: {}, 14307 ...request.defaultRequestInstrumentationOptions, 14308}; 14309 14310/** We store up to 10 interaction candidates max to cap memory usage. This is the same cap as getINP from web-vitals */ 14311const MAX_INTERACTIONS = 10; 14312 14313/** 14314 * The Browser Tracing integration automatically instruments browser pageload/navigation 14315 * actions as transactions, and captures requests, metrics and errors as spans. 14316 * 14317 * The integration can be configured with a variety of options, and can be extended to use 14318 * any routing library. This integration uses {@see IdleTransaction} to create transactions. 14319 * 14320 * @deprecated Use `browserTracingIntegration()` instead. 14321 */ 14322class BrowserTracing { 14323 // This class currently doesn't have a static `id` field like the other integration classes, because it prevented 14324 // @sentry/tracing from being treeshaken. Tree shakers do not like static fields, because they behave like side effects. 14325 // TODO: Come up with a better plan, than using static fields on integration classes, and use that plan on all 14326 // integrations. 14327 14328 /** Browser Tracing integration options */ 14329 14330 /** 14331 * @inheritDoc 14332 */ 14333
14334 constructor(_options) { 14335 this.name = BROWSER_TRACING_INTEGRATION_ID; 14336 this._hasSetTracePropagationTargets = false; 14337 14338 core.addTracingExtensions(); 14339 14340 if (debugBuild.DEBUG_BUILD) { 14341 this._hasSetTracePropagationTargets = !!( 14342 _options && 14343 // eslint-disable-next-line deprecation/deprecation 14344 (_options.tracePropagationTargets || _options.tracingOrigins) 14345 ); 14346 } 14347 14348 this.options = { 14349 ...DEFAULT_BROWSER_TRACING_OPTIONS, 14350 ..._options, 14351 }; 14352 14353 // Special case: enableLongTask can be set in _experiments 14354 // TODO (v8): Remove this in v8 14355 if (this.options._experiments.enableLongTask !== undefined) { 14356 this.options.enableLongTask = this.options._experiments.enableLongTask; 14357 } 14358 14359 // TODO (v8): remove this block after tracingOrigins is removed 14360 // Set tracePropagationTargets to tracingOrigins if specified by the user 14361 // In case both are specified, tracePropagationTargets takes precedence 14362 // eslint-disable-next-line deprecation/deprecation 14363 if (_options && !_options.tracePropagationTargets && _options.tracingOrigins) { 14364 // eslint-disable-next-line deprecation/deprecation 14365 this.options.tracePropagationTargets = _options.tracingOrigins; 14366 } 14367 14368 this._collectWebVitals = index.startTrackingWebVitals(); 14369 /** Stores a mapping of interactionIds from PerformanceEventTimings to the origin interaction path */ 14370 this._interactionIdtoRouteNameMapping = {}; 14371 14372 if (this.options.enableInp) { 14373 index.startTrackingINP(this._interactionIdtoRouteNameMapping); 14374 } 14375 if (this.options.enableLongTask) { 14376 index.startTrackingLongTasks(); 14377 } 14378 if (this.options._experiments.enableInteractions) { 14379 index.startTrackingInteractions(); 14380 } 14381 14382 this._latestRoute = { 14383 name: undefined, 14384 context: undefined, 14385 }; 14386 } 14387 14388 /** 14389 * @inheritDoc 14390 */ 14391 setupOnce(_, getCurrentHub) { 14392 this._getCurrentHub = getCurrentHub; 14393 const hub = getCurrentHub(); 14394 // eslint-disable-next-line deprecation/deprecation 14395 const client = hub.getClient(); 14396 const clientOptions = client && client.getOptions(); 14397 14398 const { 14399 routingInstrumentation: instrumentRouting, 14400 startTransactionOnLocationChange, 14401 startTransactionOnPageLoad, 14402 markBackgroundTransactions, 14403 traceFetch, 14404 traceXHR, 14405 shouldCreateSpanForRequest, 14406 enableHTTPTimings, 14407 _experiments, 14408 } = this.options; 14409 14410 const clientOptionsTracePropagationTargets = clientOptions && clientOptions.tracePropagationTargets; 14411 // There are three ways to configure tracePropagationTargets: 14412 // 1. via top level client option `tracePropagationTargets` 14413 // 2. via BrowserTracing option `tracePropagationTargets` 14414 // 3. via BrowserTracing option `tracingOrigins` (deprecated) 14415 // 14416 // To avoid confusion, favour top level client option `tracePropagationTargets`, and fallback to 14417 // BrowserTracing option `tracePropagationTargets` and then `tracingOrigins` (deprecated). 14418 // This is done as it minimizes bundle size (we don't have to have undefined checks). 14419 // 14420 // If both 1 and either one of 2 or 3 are set (from above), we log out a warning. 14421 // eslint-disable-next-line deprecation/deprecation 14422 const tracePropagationTargets = clientOptionsTracePropagationTargets || this.options.tracePropagationTargets; 14423 if (debugBuild.DEBUG_BUILD && this._hasSetTracePropagationTargets && clientOptionsTracePropagationTargets) { 14424 utils.logger.warn( 14425 '[Tracing] The `tracePropagationTargets` option was set in the BrowserTracing integration and top level `Sentry.init`. The top level `Sentry.init` value is being used.', 14426 ); 14427 } 14428 14429 instrumentRouting( 14430 (context) => { 14431 const transaction = this._createRouteTransaction(context); 14432 14433 this.options._experiments.onStartRouteTransaction && 14434 this.options._experiments.onStartRouteTransaction(transaction, context, getCurrentHub); 14435 14436 return transaction; 14437 }, 14438 startTransactionOnPageLoad, 14439 startTransactionOnLocationChange, 14440 ); 14441
14442 if (markBackgroundTransactions) { 14443 backgroundtab.registerBackgroundTabDetection(); 14444 } 14445 14446 if (_experiments.enableInteractions) { 14447 this._registerInteractionListener(); 14448 } 14449 14450 if (this.options.enableInp) { 14451 this._registerInpInteractionListener(); 14452 } 14453 14454 request.instrumentOutgoingRequests({ 14455 traceFetch, 14456 traceXHR, 14457 tracePropagationTargets, 14458 shouldCreateSpanForRequest, 14459 enableHTTPTimings, 14460 }); 14461 } 14462 14463 /** Create routing idle transaction. */ 14464 _createRouteTransaction(context) { 14465 if (!this._getCurrentHub) { 14466 debugBuild.DEBUG_BUILD && 14467 utils.logger.warn(`[Tracing] Did not create ${context.op} transaction because _getCurrentHub is invalid.`); 14468 return undefined; 14469 } 14470 14471 const hub = this._getCurrentHub(); 14472 14473 const { beforeNavigate, idleTimeout, finalTimeout, heartbeatInterval } = this.options; 14474 14475 const isPageloadTransaction = context.op === 'pageload'; 14476 14477 let expandedContext; 14478 if (isPageloadTransaction) { 14479 const sentryTrace = isPageloadTransaction ? getMetaContent('sentry-trace') : ''; 14480 const baggage = isPageloadTransaction ? getMetaContent('baggage') : undefined; 14481 const { traceId, dsc, parentSpanId, sampled } = utils.propagationContextFromHeaders(sentryTrace, baggage); 14482 expandedContext = { 14483 traceId, 14484 parentSpanId, 14485 parentSampled: sampled, 14486 ...context, 14487 metadata: { 14488 // eslint-disable-next-line deprecation/deprecation 14489 ...context.metadata, 14490 dynamicSamplingContext: dsc, 14491 }, 14492 trimEnd: true, 14493 }; 14494 } else { 14495 expandedContext = { 14496 trimEnd: true, 14497 ...context, 14498 }; 14499 } 14500 14501 const modifiedContext = typeof beforeNavigate === 'function' ? beforeNavigate(expandedContext) : expandedContext; 14502 14503 // For backwards compatibility reasons, beforeNavigate can return undefined to "drop" the transaction (prevent it 14504 // from being sent to Sentry). 14505 const finalContext = modifiedContext === undefined ? { ...expandedContext, sampled: false } : modifiedContext; 14506 14507 // If `beforeNavigate` set a custom name, record that fact 14508 // eslint-disable-next-line deprecation/deprecation 14509 finalContext.metadata = 14510 finalContext.name !== expandedContext.name 14511 ? // eslint-disable-next-line deprecation/deprecation 14512 { ...finalContext.metadata, source: 'custom' } 14513 : // eslint-disable-next-line deprecation/deprecation 14514 finalContext.metadata; 14515 14516 this._latestRoute.name = finalContext.name; 14517 this._latestRoute.context = finalContext; 14518 14519 // eslint-disable-next-line deprecation/deprecation 14520 if (finalContext.sampled === false) { 14521 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Will not send ${finalContext.op} transaction because of beforeNavigate.`); 14522 } 14523 14524 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Starting ${finalContext.op} transaction on scope`); 14525 14526 const { location } = types.WINDOW; 14527 14528 const idleTransaction = core.startIdleTransaction( 14529 hub, 14530 finalContext, 14531 idleTimeout, 14532 finalTimeout, 14533 true, 14534 { location }, // for use in the tracesSampler 14535 heartbeatInterval, 14536 isPageloadTransaction, // should wait for finish signal if it's a pageload transaction 14537 ); 14538 14539 if (isPageloadTransaction) { 14540 types.WINDOW.document.addEventListener('readystatechange', () => { 14541 if (['interactive', 'complete'].includes(types.WINDOW.document.readyState)) { 14542 idleTransaction.sendAutoFinishSignal(); 14543 } 14544 }); 14545 14546 if (['interactive', 'complete'].includes(types.WINDOW.document.readyState)) { 14547 idleTransaction.sendAutoFinishSignal(); 14548 } 14549 } 14550 14551 idleTransaction.registerBeforeFinishCallback(transaction => { 14552 this._collectWebVitals(); 14553 index.addPerformanceEntries(transaction); 14554 }); 14555 14556 return idleTransaction ; 14557 } 14558 14559 /** Start listener for interaction transactions */ 14560 _registerInteractionListener() { 14561 let inflightInteractionTransaction; 14562 const registerInteractionTransaction = () => { 14563 const { idleTimeout, finalTimeout, heartbeatInterval } = this.options; 14564 const op = 'ui.action.click'; 14565 14566 // eslint-disable-next-line deprecation/deprecation 14567 const currentTransaction = core.getActiveTransaction(); 14568 if (currentTransaction && currentTransaction.op && ['navigation', 'pageload'].includes(currentTransaction.op)) { 14569 debugBuild.DEBUG_BUILD && 14570 utils.logger.warn( 14571 `[Tracing] Did not create ${op} transaction because a pageload or navigation transaction is in progress.`, 14572 ); 14573 return undefined; 14574 } 14575 14576 if (inflightInteractionTransaction) { 14577 inflightInteractionTransaction.setFinishReason('interactionInterrupted'); 14578 inflightInteractionTransaction.end(); 14579 inflightInteractionTransaction = undefined; 14580 } 14581 14582 if (!this._getCurrentHub) { 14583 debugBuild.DEBUG_BUILD && utils.logger.warn(`[Tracing] Did not create ${op}
14583 transaction because _getCurrentHub is invalid.`); 14584 return undefined; 14585 } 14586 14587 if (!this._latestRoute.name) { 14588 debugBuild.DEBUG_BUILD && utils.logger.warn(`[Tracing] Did not create ${op} transaction because _latestRouteName is missing.`); 14589 return undefined; 14590 } 14591 14592 const hub = this._getCurrentHub(); 14593 const { location } = types.WINDOW; 14594 14595 const context = { 14596 name: this._latestRoute.name, 14597 op, 14598 trimEnd: true, 14599 data: { 14600 [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: this._latestRoute.context 14601 ? getSource(this._latestRoute.context) 14602 : 'url', 14603 }, 14604 }; 14605 14606 inflightInteractionTransaction = core.startIdleTransaction( 14607 hub, 14608 context, 14609 idleTimeout, 14610 finalTimeout, 14611 true, 14612 { location }, // for use in the tracesSampler 14613 heartbeatInterval, 14614 ); 14615 }; 14616 14617 ['click'].forEach(type => { 14618 addEventListener(type, registerInteractionTransaction, { once: false, capture: true }); 14619 }); 14620 } 14621 14622 /** Creates a listener on interaction entries, and maps interactionIds to the origin path of the interaction */ 14623 _registerInpInteractionListener() { 14624 instrument.addPerformanceInstrumentationHandler('event', ({ entries }) => { 14625 const client = core.getClient(); 14626 // We need to get the replay, user, and activeTransaction from the current scope 14627 // so that we can associate replay id, profile id, and a user display to the span 14628 const replay = 14629 client !== undefined && client.getIntegrationByName !== undefined 14630 ? (client.getIntegrationByName('Replay') ) 14631 : undefined; 14632 const replayId = replay !== undefined ? replay.getReplayId() : undefined; 14633 // eslint-disable-next-line deprecation/deprecation 14634 const activeTransaction = core.getActiveTransaction(); 14635 const currentScope = core.getCurrentScope(); 14636 const user = currentScope !== undefined ? currentScope.getUser() : undefined; 14637 for (const entry of entries) { 14638 if (isPerformanceEventTiming(entry)) { 14639 const duration = entry.duration; 14640 const keys = Object.keys(this._interactionIdtoRouteNameMapping); 14641 const minInteractionId = 14642 keys.length > 0 14643 ? keys.reduce((a, b) => { 14644 return this._interactionIdtoRouteNameMapping[a].duration < 14645 this._interactionIdtoRouteNameMapping[b].duration 14646 ? a 14647 : b; 14648 }) 14649 : undefined; 14650 if ( 14651 minInteractionId === undefined || 14652 duration > this._interactionIdtoRouteNameMapping[minInteractionId].duration 14653 ) { 14654 const interactionId = entry.interactionId; 14655 const routeName = this._latestRoute.name; 14656 const parentContext = this._latestRoute.context; 14657 if (interactionId && routeName && parentContext) { 14658 if (minInteractionId && Object.keys(this._interactionIdtoRouteNameMapping).length >= MAX_INTERACTIONS) { 14659 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 14660 delete this._interactionIdtoRouteNameMapping[minInteractionId]; 14661 } 14662 this._interactionIdtoRouteNameMapping[interactionId] = { 14663 routeName, 14664 duration, 14665 parentContext, 14666 user, 14667 activeTransaction, 14668 replayId, 14669 }; 14670 } 14671 } 14672 } 14673 } 14674 }); 14675 } 14676} 14677 14678/** Returns the value of a meta tag */ 14679function getMetaContent(metaName) { 14680 // Can't specify generic to `getDomElement` because tracing can be used 14681 // in a variety of environments, have to disable `no-unsafe-member-access` 14682 // as a result. 14683 const metaTag = utils.getDomElement(`meta[name=${metaName}]`); 14684 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 14685 return metaTag ? metaTag.getAttribute('content') : undefined; 14686} 14687 14688function getSource(context) { 14689 const sourceFromAttributes = context.attributes && context.attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]; 14690 // eslint-disable-next-line deprecation/deprecation 14691 const sourceFromData = context.data && context.data[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]; 14692 // eslint-disable-next-line deprecation/deprecation 14693 const sourceFromMetadata = context.metadata && context.metadata.source; 14694 14695 return sourceFromAttributes || sourceFromData || sourceFromMetadata; 14696} 14697 14698function isPerformanceEventTiming(entry) { 14699 return 'duration' in entry; 14700} 14701 14702exports.BROWSER_TRACING_INTEGRATION_ID = BROWSER_TRACING_INTEGRATION_ID; 14703exports.BrowserTracing = BrowserTracing; 14704exports.getMetaContent = getMetaContent; 14705 14706 14707},{"../common/debug-build.js":206,"./backgroundtab.js":184,"./instrument.js":187,"./metrics/index.js":188,"./request.js":190,"./router.js":191,"./types.js":192,"@sentry/core":250,"@sentry/utils":319}],187:[function(require,module,exports){ 14708Object.defineProperty(exports, '__esModule', { value: true }); 14709 14710const utils = require('@sentry/utils'); 14711const debugBuild = require('../common/debug-build.js'); 14712const getCLS = require('./web-vitals/getCLS.js'); 14713const getFID = require('./web-vitals/getFID.js'); 14714const getINP = require('./web-vitals/getINP.js'); 14715const getLCP = require('./web-vitals/getLCP.js'); 14716const observe = require('./web-vitals/lib/observe.js'); 14717 14718const handlers = {}; 14719const instrumented = {}; 14720 14721let _previousCls; 14722let _previousFid; 14723let _previousLcp; 14724let _previousInp; 14725 14726/** 14727 * Add a callback that will be triggered when a CLS metric is available. 14728 * Returns a cleanup callback which can be called to remove the instrumentation handler. 14729 * 14730 * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called. 14731 * This will lead to the CLS being finalized and frozen. 14732 */ 14733function addClsInstrumentationHandler( 14734 callback, 14735 stopOnCallback = false, 14736) { 14737 return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback); 14738} 14739 14740/** 14741 * Add a callback that will be triggered when a LCP metric is available. 14742 * Returns a cleanup callback which can be called to remove the instrumentation handler. 14743 * 14744 * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called. 14745 * This will lead to the LCP being finalized and frozen. 14746 */ 14747function addLcpInstrumentationHandler( 14748 callback, 14749 stopOnCallback = false, 14750) { 14751 return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback); 14752} 14753 14754/** 14755 * Add a callback that will be triggered when a FID metric is available. 14756 * Returns a cleanup callback which can be called to remove the instrumentation handler. 14757 */ 14758function addFidInstrumentationHandler(callback) { 14759 return addMetricObserver('fid', callback, instrumentFid, _previousFid); 14760} 14761 14762/** 14763 * Add a callback that will be triggered when a INP metric is available. 14764 * Returns a cleanup callback which can be called to remove the instrumentation handler. 14765 */ 14766function addInpInstrumentationHandler( 14767 callback, 14768) { 14769 return addMetricObserver('inp', callback, instrumentInp, _previousInp); 14770} 14771 14772/** 14773 * Add a callback that will be triggered when a performance observer is triggered, 14774 * and receives the entries of the observer. 14775 * Returns a cleanup callback which can be called to remove the instrumentation handler. 14776 */ 14777function addPerformanceInstrumentationHandler( 14778 type, 14779 callback, 14780) { 14781 addHandler(type, callback); 14782 14783 if (!instrumented[type]) { 14784 instrumentPerformanceObserver(type); 14785 instrumented[type] = true; 14786 } 14787 14788 return getCleanupCallback(type, callback); 14789} 14790 14791/** Trigger all handlers of a given type. */ 14792function triggerHandlers(type, data) { 14793 const typeHandlers = handlers[type]; 14794 14795 if (!typeHandlers || !typeHandlers.length) { 14796 return; 14797 } 14798 14799 for (const handler of typeHandlers) { 14800 try { 14801 handler(data); 14802 } catch (e) { 14803 debugBuild.DEBUG_BUILD && 14804 utils.logger.error( 14805 `Error while triggering instrumentation handler.\nType: ${type}\nName: ${utils.getFunctionName(handler)}\nError:`, 14806 e, 14807 ); 14808 } 14809 } 14810} 14811 14812function instrumentCls() { 14813 return getCLS.onCLS(metric => { 14814 triggerHandlers('cls', { 14815 metric, 14816 }); 14817 _previousCls = metric; 14818 }); 14819} 14820 14821function instrumentFid() { 14822 return getFID.onFID(metric => { 14823 triggerHandlers('fid', { 14824 metric, 14825 }); 14826 _previousFid = metric; 14827 }); 14828} 14829 14830function instrumentLcp() { 14831 return getLCP.onLCP(metric => { 14832 triggerHandlers('lcp', { 14833 metric, 14834 }); 14835 _previousLcp = metric; 14836 }); 14837} 14838 14839function instrumentInp() { 14840 return getINP.onINP(metric => { 14841 triggerHandlers('inp', { 14842 metric, 14843 }); 14844 _previousInp = metric; 14845 }); 14846} 14847 14848function addMetricObserver( 14849 type, 14850 callback, 14851 instrumentFn, 14852 previousValue, 14853 stopOnCallback = false, 14854) { 14855 addHandler(type, callback); 14856 14857 let stopListening; 14858 14859 if (!instrumented[type]) { 14860 stopListening = instrumentFn(); 14861 instrumented[type] = true; 14862 } 14863 14864 if (previousValue) { 14865 callback({ metric: previousValue }); 14866 } 14867 14868 return getCleanupCallback(type, callback, stopOnCallback ? stopListening : undefined); 14869} 14870 14871function instrumentPerformanceObserver(type) { 14872 const options = {}; 14873 14874 // Special per-type options we want to use 14875 if (type === 'event') { 14876 options.durationThreshold = 0; 14877 } 14878 14879 observe.observe( 14880 type, 14881 entries => { 14882 triggerHandlers(type, { entries }); 14883 }, 14884 options, 14885 ); 14886} 14887 14888function addHandler(type, handler) { 14889 handlers[type] = handlers[type] || []; 14890 (handlers[type] ).push(handler); 14891} 14892 14893// Get a callback which can be called to remove the instrumentation handler 14894function getCleanupCallback( 14895 type, 14896 callback, 14897 stopListening, 14898) { 14899 return () => { 14900 if (stopListening) { 14901 stopListening(); 14902 } 14903 14904 const typeHandlers = handlers[type]; 14905 14906 if (!typeHandlers) { 14907 return; 14908 } 14909 14910 const index = typeHandlers.indexOf(callback); 14911 if (index !== -1) { 14912 typeHandlers.splice(index, 1); 14913 } 14914 }; 14915} 14916 14917exports.addClsInstrumentationHandler = addClsInstrumentationHandler; 14918exports.addFidInstrumentationHandler = addFidInstrumentationHandler; 14919exports.addInpInstrumentationHandler = addInpInstrumentationHandler; 14920exports.addLcpInstrumentationHandler = addLcpInstrumentationHandler; 14921exports.addPerformanceInstrumentationHandler = addPerformanceInstrumentationHandler; 14922 14923 14924},{"../common/debug-build.js":206,"./web-vitals/getCLS.js":193,"./web-vitals/getFID.js":194,"./web-vitals/getINP.js":195,"./web-vitals/getLCP.js":196,"./web-vitals/lib/observe.js":203,"@sentry/utils":319}],188:[function(require,module,exports){ 14925Object.defineProperty(exports, '__esModule', { value: true }); 14926 14927const core = require('@sentry/core'); 14928const utils = require('@sentry/utils'); 14929const debugBuild = require('../../common/debug-build.js'); 14930const instrument = require('../instrument.js'); 14931const types = require('../types.js'); 14932const getVisibilityWatcher = require('../web-vitals/lib/getVisibilityWatcher.js'); 14933const utils$1 = require('./utils.js'); 14934 14935const MAX_INT_AS_BYTES = 2147483647; 14936 14937/** 14938 * Converts from milliseconds to seconds 14939 * @param time time in ms 14940 */ 14941function msToSec(time) { 14942 return time / 1000; 14943} 14944 14945function getBrowserPerformanceAPI() { 14946 // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are 14947 return types.WINDOW && types.WINDOW.addEventListener && types.WINDOW.performance; 14948} 14949 14950let _performanceCursor = 0; 14951 14952let _measurements = {}; 14953let _lcpEntry; 14954let _clsEntry; 14955 14956/** 14957 * Start tracking web vitals. 14958 * The callback returned by this function can be used to stop tracking & ensure all measurements are final & captured. 14959 * 14960 * @returns A function that forces web vitals collection 14961 */ 14962function startTrackingWebVitals() { 14963 const performance = getBrowserPerformanceAPI(); 14964 if (performance && utils.browserPerformanceTimeOrigin) { 14965 // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are 14966 if (performance.mark) { 14967 types.WINDOW.performance.mark('sentry-tracing-init'); 14968 } 14969 const fidCallback = _trackFID(); 14970 const clsCallback = _trackCLS(); 14971 const lcpCallback = _trackLCP(); 14972 14973 return () => { 14974 fidCallback(); 14975 clsCallback(); 14976 lcpCallback(); 14977 }; 14978 } 14979 14980 return () => undefined; 14981} 14982 14983/** 14984 * Start tracking long tasks. 14985 */ 14986function startTrackingLongTasks() { 14987 instrument.addPerformanceInstrumentationHandler('longtask', ({ entries }) => {
14988 for (const entry of entries) { 14989 // eslint-disable-next-line deprecation/deprecation 14990 const transaction = core.getActiveTransaction() ; 14991 if (!transaction) { 14992 return; 14993 } 14994 const startTime = msToSec((utils.browserPerformanceTimeOrigin ) + entry.startTime); 14995 const duration = msToSec(entry.duration); 14996 14997 // eslint-disable-next-line deprecation/deprecation 14998 transaction.startChild({ 14999 description: 'Main UI thread blocked', 15000 op: 'ui.long-task', 15001 origin: 'auto.ui.browser.metrics', 15002 startTimestamp: startTime, 15003 endTimestamp: startTime + duration, 15004 }); 15005 } 15006 }); 15007} 15008 15009/** 15010 * Start tracking interaction events. 15011 */ 15012function startTrackingInteractions() { 15013 instrument.addPerformanceInstrumentationHandler('event', ({ entries }) => { 15014 for (const entry of entries) { 15015 // eslint-disable-next-line deprecation/deprecation 15016 const transaction = core.getActiveTransaction() ; 15017 if (!transaction) { 15018 return; 15019 } 15020 15021 if (entry.name === 'click') { 15022 const startTime = msToSec((utils.browserPerformanceTimeOrigin ) + entry.startTime); 15023 const duration = msToSec(entry.duration); 15024 15025 const span = { 15026 description: utils.htmlTreeAsString(entry.target), 15027 op: `ui.interaction.${entry.name}`, 15028 origin: 'auto.ui.browser.metrics', 15029 startTimestamp: startTime, 15030 endTimestamp: startTime + duration, 15031 }; 15032 15033 const componentName = utils.getComponentName(entry.target); 15034 if (componentName) { 15035 span.attributes = { 'ui.component_name': componentName }; 15036 } 15037 15038 // eslint-disable-next-line deprecation/deprecation 15039 transaction.startChild(span); 15040 } 15041 } 15042 }); 15043} 15044 15045/** 15046 * Start tracking INP webvital events. 15047 */ 15048function startTrackingINP(interactionIdtoRouteNameMapping) { 15049 const performance = getBrowserPerformanceAPI(); 15050 if (performance && utils.browserPerformanceTimeOrigin) { 15051 const inpCallback = _trackINP(interactionIdtoRouteNameMapping); 15052 15053 return () => { 15054 inpCallback(); 15055 }; 15056 } 15057 15058 return () => undefined; 15059} 15060 15061/** Starts tracking the Cumulative Layout Shift on the current page. */ 15062function _trackCLS() { 15063 return instrument.addClsInstrumentationHandler(({ metric }) => { 15064 const entry = metric.entries[metric.entries.length - 1]; 15065 if (!entry) { 15066 return; 15067 } 15068 15069 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding CLS'); 15070 _measurements['cls'] = { value: metric.value, unit: '' }; 15071 _clsEntry = entry ; 15072 }, true); 15073} 15074 15075/** Starts tracking the Largest Contentful Paint on the current page. */ 15076function _trackLCP() { 15077 return instrument.addLcpInstrumentationHandler(({ metric }) => { 15078 const entry = metric.entries[metric.entries.length - 1]; 15079 if (!entry) { 15080 return; 15081 } 15082 15083 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding LCP'); 15084 _measurements['lcp'] = { value: metric.value, unit: 'millisecond' }; 15085 _lcpEntry = entry ; 15086 }, true); 15087} 15088 15089/** Starts tracking the First Input Delay on the current page. */ 15090function _trackFID() { 15091 return instrument.addFidInstrumentationHandler(({ metric }) => { 15092 const entry = metric.entries[metric.entries.length - 1]; 15093 if (!entry) { 15094 return; 15095 } 15096 15097 const timeOrigin = msToSec(utils.browserPerformanceTimeOrigin ); 15098 const startTime = msToSec(entry.startTime); 15099 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding FID'); 15100 _measurements['fid'] = { value: metric.value, unit: 'millisecond' }; 15101 _measurements['mark.fid'] = { value: timeOrigin + startTime, unit: 'second' }; 15102 }); 15103} 15104 15105/** Starts tracking the Interaction to Next Paint on the current page. */ 15106function _trackINP(interactionIdtoRouteNameMapping) { 15107 return instrument.addInpInstrumentationHandler(({ metric }) => { 15108 const entry = metric.entries.find(e => e.name === 'click' || e.name === 'pointerdown'); 15109 const client = core.getClient(); 15110 if (!entry || !client) { 15111 return; 15112 } 15113 const options = client.getOptions(); 15114 /** Build the INP span, create an envelope from the span, and then send the envelope */ 15115 const startTime = msToSec((utils.browserPerformanceTimeOrigin ) + entry.startTime); 15116 const duration = msToSec(metric.value); 15117 const { routeName, parentContext, activeTransaction, user, replayId } = 15118 entry.interactionId !== undefined 15119 ? interactionIdtoRouteNameMapping[entry.interactionId] 15120 : { 15121 routeName: undefined, 15122 parentContext: undefined, 15123 activeTransaction: undefined, 15124 user: undefined, 15125 replayId: undefined, 15126 }; 15127 const userDisplay = user !== undefined ? user.email || user.id || user.ip_address : undefined; 15128 // eslint-disable-next-line deprecation/deprecation 15129 const profileId = activeTransaction !== undefined ? activeTransaction.getProfileId() : undefined; 15130 const span = new core.Span({ 15131 startTimestamp: startTime, 15132 endTimestamp: startTime + duration, 15133 op: 'ui.interaction.click', 15134 name: utils.htmlTreeAsString(entry.target), 15135 attributes: { 15136 release: options.release, 15137 environment: options.environment, 15138 transaction: routeName, 15139 ...(userDisplay !== undefined && userDisplay !== '' ? { user: userDisplay } : {}), 15140 ...(profileId !== undefined ? { profile_id: profileId } : {}), 15141 ...(replayId !== undefined ? { replay_id: replayId } : {}), 15142 }, 15143 exclusiveTime: metric.value, 15144 measurements: { 15145 inp: { value: metric.value, unit: 'millisecond' }, 15146 }, 15147 }); 15148 15149 /** Check to see if the span should be sampled */ 15150 const sampleRate = getSampleRate(parentContext, options); 15151 if (!sampleRate) { 15152 return; 15153 } 15154 15155 if (Math.random() < (sampleRate )) {
15156 const envelope = span ? core.createSpanEnvelope([span], client.getDsn()) : undefined; 15157 const transport = client && client.getTransport(); 15158 if (transport && envelope) { 15159 transport.send(envelope).then(null, reason => { 15160 debugBuild.DEBUG_BUILD && utils.logger.error('Error while sending interaction:', reason); 15161 }); 15162 } 15163 return; 15164 } 15165 }); 15166} 15167 15168/** Add performance related spans to a transaction */ 15169function addPerformanceEntries(transaction) { 15170 const performance = getBrowserPerformanceAPI(); 15171 if (!performance || !types.WINDOW.performance.getEntries || !utils.browserPerformanceTimeOrigin) { 15172 // Gatekeeper if performance API not available 15173 return; 15174 } 15175 15176 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] Adding & adjusting spans using Performance API'); 15177 const timeOrigin = msToSec(utils.browserPerformanceTimeOrigin); 15178 15179 const performanceEntries = performance.getEntries(); 15180 15181 let responseStartTimestamp; 15182 let requestStartTimestamp; 15183 15184 const { op, start_timestamp: transactionStartTime } = core.spanToJSON(transaction); 15185 15186 // eslint-disable-next-line @typescript-eslint/no-explicit-any 15187 performanceEntries.slice(_performanceCursor).forEach((entry) => { 15188 const startTime = msToSec(entry.startTime); 15189 const duration = msToSec(entry.duration); 15190 15191 // eslint-disable-next-line deprecation/deprecation 15192 if (transaction.op === 'navigation' && transactionStartTime && timeOrigin + startTime < transactionStartTime) { 15193 return; 15194 } 15195 15196 switch (entry.entryType) { 15197 case 'navigation': { 15198 _addNavigationSpans(transaction, entry, timeOrigin); 15199 responseStartTimestamp = timeOrigin + msToSec(entry.responseStart); 15200 requestStartTimestamp = timeOrigin + msToSec(entry.requestStart); 15201 break; 15202 } 15203 case 'mark': 15204 case 'paint': 15205 case 'measure': { 15206 _addMeasureSpans(transaction, entry, startTime, duration, timeOrigin); 15207 15208 // capture web vitals 15209 const firstHidden = getVisibilityWatcher.getVisibilityWatcher(); 15210 // Only report if the page wasn't hidden prior to the web vital. 15211 const shouldRecord = entry.startTime < firstHidden.firstHiddenTime; 15212 15213 if (entry.name === 'first-paint' && shouldRecord) { 15214 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding FP'); 15215 _measurements['fp'] = { value: entry.startTime, unit: 'millisecond' }; 15216 } 15217 if (entry.name === 'first-contentful-paint' && shouldRecord) { 15218 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding FCP'); 15219 _measurements['fcp'] = { value: entry.startTime, unit: 'millisecond' }; 15220 } 15221 break; 15222 } 15223 case 'resource': { 15224 _addResourceSpans(transaction, entry, entry.name , startTime, duration, timeOrigin); 15225 break; 15226 } 15227 // Ignore other entry types. 15228 } 15229 }); 15230 15231 _performanceCursor = Math.max(performanceEntries.length - 1, 0); 15232 15233 _trackNavigator(transaction); 15234 15235 // Measurements are only available for pageload transactions 15236 if (op === 'pageload') { 15237 _addTtfbToMeasurements(_measurements, responseStartTimestamp, requestStartTimestamp, transactionStartTime); 15238 15239 ['fcp', 'fp', 'lcp'].forEach(name => { 15240 if (!_measurements[name] || !transactionStartTime || timeOrigin >= transactionStartTime) { 15241 return; 15242 } 15243 // The web vitals, fcp, fp, lcp, and ttfb, all measure relative to timeOrigin. 15244 // Unfortunately, timeOrigin is not captured within the transaction span data, so these web vitals will need 15245 // to be adjusted to be relative to transaction.startTimestamp. 15246 const oldValue = _measurements[name].value; 15247 const measurementTimestamp = timeOrigin + msToSec(oldValue); 15248 15249 // normalizedValue should be in milliseconds 15250 const normalizedValue = Math.abs((measurementTimestamp - transactionStartTime) * 1000); 15251 const delta = normalizedValue - oldValue; 15252 15253 debugBuild.DEBUG_BUILD && utils.logger.log(`[Measurements] Normalized ${name} from ${oldValue} to ${normalizedValue} (${delta})`); 15254 _measurements[name].value = normalizedValue; 15255 }); 15256 15257 const fidMark = _measurements['mark.fid']; 15258 if (fidMark && _measurements['fid']) { 15259 // create span for FID 15260 utils$1._startChild(transaction, { 15261 description: 'first input delay', 15262 endTimestamp: fidMark.value + msToSec(_measurements['fid'].value), 15263 op: 'ui.action', 15264 origin: 'auto.ui.browser.metrics', 15265 startTimestamp: fidMark.value, 15266 }); 15267 15268 // Delete mark.fid as we don't want it to be part of final payload 15269 delete _measurements['mark.fid']; 15270 } 15271 15272 // If FCP is not recorded we should not record the cls value 15273 // according to the new definition of CLS. 15274 if (!('fcp' in _measurements)) { 15275 delete _measurements.cls; 15276 } 15277
15278 Object.keys(_measurements).forEach(measurementName => { 15279 core.setMeasurement(measurementName, _measurements[measurementName].value, _measurements[measurementName].unit); 15280 }); 15281 15282 _tagMetricInfo(transaction); 15283 } 15284 15285 _lcpEntry = undefined; 15286 _clsEntry = undefined; 15287 _measurements = {}; 15288} 15289 15290/** Create measure related spans */ 15291function _addMeasureSpans( 15292 transaction, 15293 // eslint-disable-next-line @typescript-eslint/no-explicit-any 15294 entry, 15295 startTime, 15296 duration, 15297 timeOrigin, 15298) { 15299 const measureStartTimestamp = timeOrigin + startTime; 15300 const measureEndTimestamp = measureStartTimestamp + duration; 15301 15302 utils$1._startChild(transaction, { 15303 description: entry.name , 15304 endTimestamp: measureEndTimestamp, 15305 op: entry.entryType , 15306 origin: 'auto.resource.browser.metrics', 15307 startTimestamp: measureStartTimestamp, 15308 }); 15309 15310 return measureStartTimestamp; 15311} 15312 15313/** Instrument navigation entries */ 15314// eslint-disable-next-line @typescript-eslint/no-explicit-any 15315function _addNavigationSpans(transaction, entry, timeOrigin) { 15316 ['unloadEvent', 'redirect', 'domContentLoadedEvent', 'loadEvent', 'connect'].forEach(event => { 15317 _addPerformanceNavigationTiming(transaction, entry, event, timeOrigin); 15318 }); 15319 _addPerformanceNavigationTiming(transaction, entry, 'secureConnection', timeOrigin, 'TLS/SSL', 'connectEnd'); 15320 _addPerformanceNavigationTiming(transaction, entry, 'fetch', timeOrigin, 'cache', 'domainLookupStart'); 15321 _addPerformanceNavigationTiming(transaction, entry, 'domainLookup', timeOrigin, 'DNS'); 15322 _addRequest(transaction, entry, timeOrigin); 15323} 15324 15325/** Create performance navigation related spans */ 15326function _addPerformanceNavigationTiming( 15327 transaction, 15328 // eslint-disable-next-line @typescript-eslint/no-explicit-any 15329 entry, 15330 event, 15331 timeOrigin, 15332 description, 15333 eventEnd, 15334) { 15335 const end = eventEnd ? (entry[eventEnd] ) : (entry[`${event}End`] ); 15336 const start = entry[`${event}Start`] ; 15337 if (!start || !end) { 15338 return; 15339 } 15340 utils$1._startChild(transaction, { 15341 op: 'browser', 15342 origin: 'auto.browser.browser.metrics', 15343 description: description || event, 15344 startTimestamp: timeOrigin + msToSec(start), 15345 endTimestamp: timeOrigin + msToSec(end), 15346 }); 15347} 15348 15349/** Create request and response related spans */ 15350// eslint-disable-next-line @typescript-eslint/no-explicit-any 15351function _addRequest(transaction, entry, timeOrigin) { 15352 if (entry.responseEnd) { 15353 // It is possible that we are collecting these metrics when the page hasn't finished loading yet, for example when the HTML slowly streams in. 15354 // In this case, ie. when the document request hasn't finished yet, `entry.responseEnd` will be 0. 15355 // In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect 15356 // these spans when the responseEnd value is available. The backend (Relay) would drop the entire transaction if it contained faulty spans. 15357 utils$1._startChild(transaction, { 15358 op: 'browser', 15359 origin: 'auto.browser.browser.metrics', 15360 description: 'request', 15361 startTimestamp: timeOrigin + msToSec(entry.requestStart ), 15362 endTimestamp: timeOrigin + msToSec(entry.responseEnd ), 15363 }); 15364 15365 utils$1._startChild(transaction, { 15366 op: 'browser', 15367 origin: 'auto.browser.browser.metrics', 15368 description: 'response', 15369 startTimestamp: timeOrigin + msToSec(entry.responseStart ), 15370 endTimestamp: timeOrigin + msToSec(entry.responseEnd ), 15371 }); 15372 } 15373} 15374 15375/** Create resource-related spans */ 15376function _addResourceSpans( 15377 transaction, 15378 entry, 15379 resourceUrl, 15380 startTime, 15381 duration, 15382 timeOrigin, 15383) { 15384 // we already instrument based on fetch and xhr, so we don't need to 15385 // duplicate spans here. 15386 if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') { 15387 return; 15388 } 15389 15390 const parsedUrl = utils.parseUrl(resourceUrl); 15391 15392 // eslint-disable-next-line @typescript-eslint/no-explicit-any 15393 const data = {}; 15394 setResourceEntrySizeData(data, entry, 'transferSize', 'http.response_transfer_size'); 15395 setResourceEntrySizeData(data, entry, 'encodedBodySize', 'http.response_content_length'); 15396 setResourceEntrySizeData(data, entry, 'decodedBodySize', 'http.decoded_response_content_length'); 15397 15398 if ('renderBlockingStatus' in entry) { 15399 data['resource.render_blocking_status'] = entry.renderBlockingStatus; 15400 } 15401 if (parsedUrl.protocol) { 15402 data['url.scheme'] = parsedUrl.protocol.split(':').pop(); // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it. 15403 } 15404 15405 if (parsedUrl.host) {
15406 data['server.address'] = parsedUrl.host; 15407 } 15408 15409 data['url.same_origin'] = resourceUrl.includes(types.WINDOW.location.origin); 15410 15411 const startTimestamp = timeOrigin + startTime; 15412 const endTimestamp = startTimestamp + duration; 15413 15414 utils$1._startChild(transaction, { 15415 description: resourceUrl.replace(types.WINDOW.location.origin, ''), 15416 endTimestamp, 15417 op: entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other', 15418 origin: 'auto.resource.browser.metrics', 15419 startTimestamp, 15420 data, 15421 }); 15422} 15423 15424/** 15425 * Capture the information of the user agent. 15426 */ 15427function _trackNavigator(transaction) { 15428 const navigator = types.WINDOW.navigator ; 15429 if (!navigator) { 15430 return; 15431 } 15432 15433 // track network connectivity 15434 const connection = navigator.connection; 15435 if (connection) { 15436 if (connection.effectiveType) { 15437 // TODO: Can we rewrite this to an attribute? 15438 // eslint-disable-next-line deprecation/deprecation 15439 transaction.setTag('effectiveConnectionType', connection.effectiveType); 15440 } 15441 15442 if (connection.type) { 15443 // TODO: Can we rewrite this to an attribute? 15444 // eslint-disable-next-line deprecation/deprecation 15445 transaction.setTag('connectionType', connection.type); 15446 } 15447 15448 if (utils$1.isMeasurementValue(connection.rtt)) { 15449 _measurements['connection.rtt'] = { value: connection.rtt, unit: 'millisecond' }; 15450 } 15451 } 15452 15453 if (utils$1.isMeasurementValue(navigator.deviceMemory)) { 15454 // TODO: Can we rewrite this to an attribute? 15455 // eslint-disable-next-line deprecation/deprecation 15456 transaction.setTag('deviceMemory', `${navigator.deviceMemory} GB`); 15457 } 15458 15459 if (utils$1.isMeasurementValue(navigator.hardwareConcurrency)) { 15460 // TODO: Can we rewrite this to an attribute? 15461 // eslint-disable-next-line deprecation/deprecation 15462 transaction.setTag('hardwareConcurrency', String(navigator.hardwareConcurrency)); 15463 } 15464} 15465 15466/** Add LCP / CLS data to transaction to allow debugging */ 15467function _tagMetricInfo(transaction) { 15468 if (_lcpEntry) { 15469 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding LCP Data'); 15470 15471 // Capture Properties of the LCP element that contributes to the LCP. 15472 15473 if (_lcpEntry.element) { 15474 // TODO: Can we rewrite this to an attribute? 15475 // eslint-disable-next-line deprecation/deprecation 15476 transaction.setTag('lcp.element', utils.htmlTreeAsString(_lcpEntry.element)); 15477 } 15478 15479 if (_lcpEntry.id) { 15480 // TODO: Can we rewrite this to an attribute? 15481 // eslint-disable-next-line deprecation/deprecation 15482 transaction.setTag('lcp.id', _lcpEntry.id); 15483 } 15484 15485 if (_lcpEntry.url) { 15486 // Trim URL to the first 200 characters. 15487 // TODO: Can we rewrite this to an attribute? 15488 // eslint-disable-next-line deprecation/deprecation 15489 transaction.setTag('lcp.url', _lcpEntry.url.trim().slice(0, 200)); 15490 } 15491 15492 // TODO: Can we rewrite this to an attribute? 15493 // eslint-disable-next-line deprecation/deprecation 15494 transaction.setTag('lcp.size', _lcpEntry.size); 15495 } 15496 15497 // See: https://developer.mozilla.org/en-US/docs/Web/API/LayoutShift 15498 if (_clsEntry && _clsEntry.sources) { 15499 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding CLS Data'); 15500 _clsEntry.sources.forEach((source, index) => 15501 // TODO: Can we rewrite this to an attribute? 15502 // eslint-disable-next-line deprecation/deprecation 15503 transaction.setTag(`cls.source.${index + 1}`, utils.htmlTreeAsString(source.node)), 15504 ); 15505 } 15506} 15507 15508function setResourceEntrySizeData( 15509 data, 15510 entry, 15511 key, 15512 dataKey, 15513) { 15514 const entryVal = entry[key]; 15515 if (entryVal != null && entryVal < MAX_INT_AS_BYTES) { 15516 data[dataKey] = entryVal; 15517 } 15518} 15519 15520/** 15521 * Add ttfb information to measurements 15522 * 15523 * Exported for tests 15524 */ 15525function _addTtfbToMeasurements( 15526 _measurements, 15527 responseStartTimestamp, 15528 requestStartTimestamp, 15529 transactionStartTime, 15530) { 15531 // Generate TTFB (Time to First Byte), which measured as the time between the beginning of the transaction and the 15532 // start of the response in milliseconds 15533 if (typeof responseStartTimestamp === 'number' && transactionStartTime) { 15534 debugBuild.DEBUG_BUILD && utils.logger.log('[Measurements] Adding TTFB'); 15535 _measurements['ttfb'] = { 15536 // As per https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStart, 15537 // responseStart can be 0 if the request is coming straight from the cache. 15538 // This might lead us to calculate a negative ttfb if we don't use Math.max here. 15539 // 15540 // This logic is the same as what is in the web-vitals library to calculate ttfb 15541 // https://github.com/GoogleChrome/web-vitals/blob/2301de5015e82b09925238a228a0893635854587/src/onTTFB.ts#L92 15542 // TODO(abhi): We should use the web-vitals library instead of this custom calculation. 15543 value: Math.max(responseStartTimestamp - transactionStartTime, 0) * 1000, 15544 unit: 'millisecond', 15545 }; 15546 15547 if (typeof requestStartTimestamp === 'number' && requestStartTimestamp <= responseStartTimestamp) { 15548 // Capture the time spent making the request and receiving the first byte of the response. 15549 // This is the time between the start of the request and the start of the response in milliseconds. 15550 _measurements['ttfb.requestTime'] = { 15551 value: (responseStartTimestamp - requestStartTimestamp) * 1000, 15552 unit: 'millisecond', 15553 }; 15554 } 15555 } 15556} 15557 15558/** Taken from @sentry/core sampling.ts */ 15559function getSampleRate(transactionContext, options) { 15560 if (!core.hasTracingEnabled(options)) { 15561 return false;
15562 } 15563 let sampleRate; 15564 if (transactionContext !== undefined && typeof options.tracesSampler === 'function') { 15565 sampleRate = options.tracesSampler({ 15566 transactionContext, 15567 name: transactionContext.name, 15568 parentSampled: transactionContext.parentSampled, 15569 attributes: { 15570 // eslint-disable-next-line deprecation/deprecation 15571 ...transactionContext.data, 15572 ...transactionContext.attributes, 15573 }, 15574 location: types.WINDOW.location, 15575 }); 15576 } else if (transactionContext !== undefined && transactionContext.sampled !== undefined) { 15577 sampleRate = transactionContext.sampled; 15578 } else if (typeof options.tracesSampleRate !== 'undefined') { 15579 sampleRate = options.tracesSampleRate; 15580 } else { 15581 sampleRate = 1; 15582 } 15583 if (!core.isValidSampleRate(sampleRate)) { 15584 debugBuild.DEBUG_BUILD && utils.logger.warn('[Tracing] Discarding transaction because of invalid sample rate.'); 15585 return false; 15586 } 15587 return sampleRate; 15588} 15589 15590exports._addMeasureSpans = _addMeasureSpans; 15591exports._addResourceSpans = _addResourceSpans; 15592exports._addTtfbToMeasurements = _addTtfbToMeasurements; 15593exports.addPerformanceEntries = addPerformanceEntries; 15594exports.startTrackingINP = startTrackingINP; 15595exports.startTrackingInteractions = startTrackingInteractions; 15596exports.startTrackingLongTasks = startTrackingLongTasks; 15597exports.startTrackingWebVitals = startTrackingWebVitals; 15598 15599 15600},{"../../common/debug-build.js":206,"../instrument.js":187,"../types.js":192,"../web-vitals/lib/getVisibilityWatcher.js":201,"./utils.js":189,"@sentry/core":250,"@sentry/utils":319}],189:[function(require,module,exports){ 15601Object.defineProperty(exports, '__esModule', { value: true }); 15602 15603/** 15604 * Checks if a given value is a valid measurement value. 15605 */ 15606function isMeasurementValue(value) { 15607 return typeof value === 'number' && isFinite(value); 15608} 15609 15610/** 15611 * Helper function to start child on transactions. This function will make sure that the transaction will 15612 * use the start timestamp of the created child span if it is earlier than the transactions actual 15613 * start timestamp. 15614 * 15615 * Note: this will not be possible anymore in v8, 15616 * unless we do some special handling for browser here... 15617 */ 15618function _startChild(transaction, { startTimestamp, ...ctx }) { 15619 // eslint-disable-next-line deprecation/deprecation 15620 if (startTimestamp && transaction.startTimestamp > startTimestamp) { 15621 // eslint-disable-next-line deprecation/deprecation 15622 transaction.startTimestamp = startTimestamp; 15623 } 15624 15625 // eslint-disable-next-line deprecation/deprecation 15626 return transaction.startChild({ 15627 startTimestamp, 15628 ...ctx, 15629 }); 15630} 15631 15632exports._startChild = _startChild; 15633exports.isMeasurementValue = isMeasurementValue; 15634 15635 15636},{}],190:[function(require,module,exports){ 15637Object.defineProperty(exports, '__esModule', { value: true }); 15638 15639const core = require('@sentry/core'); 15640const utils = require('@sentry/utils'); 15641const fetch = require('../common/fetch.js'); 15642const instrument = require('./instrument.js'); 15643 15644/* eslint-disable max-lines */ 15645 15646const DEFAULT_TRACE_PROPAGATION_TARGETS = ['localhost', /^\/(?!\/)/]; 15647 15648/** Options for Request Instrumentation */ 15649 15650const defaultRequestInstrumentationOptions = { 15651 traceFetch: true, 15652 traceXHR: true, 15653 enableHTTPTimings: true, 15654 // TODO (v8): Remove this property 15655 tracingOrigins: DEFAULT_TRACE_PROPAGATION_TARGETS, 15656 tracePropagationTargets: DEFAULT_TRACE_PROPAGATION_TARGETS, 15657}; 15658 15659/** Registers span creators for xhr and fetch requests */ 15660function instrumentOutgoingRequests(_options) { 15661 const { 15662 traceFetch, 15663 traceXHR, 15664 // eslint-disable-next-line deprecation/deprecation 15665 tracePropagationTargets, 15666 // eslint-disable-next-line deprecation/deprecation 15667 tracingOrigins, 15668 shouldCreateSpanForRequest, 15669 enableHTTPTimings, 15670 } = { 15671 traceFetch: defaultRequestInstrumentationOptions.traceFetch, 15672 traceXHR: defaultRequestInstrumentationOptions.traceXHR, 15673 ..._options, 15674 }; 15675 15676 const shouldCreateSpan = 15677 typeof shouldCreateSpanForRequest === 'function' ? shouldCreateSpanForRequest : (_) => true; 15678 15679 // TODO(v8) Remove tracingOrigins here 15680 // The only reason we're passing it in here is because this instrumentOutgoingRequests function is publicly exported 15681 // and we don't want to break the API. We can remove it in v8. 15682 const shouldAttachHeadersWithTargets = (url) => 15683 shouldAttachHeaders(url, tracePropagationTargets || tracingOrigins); 15684 15685 const spans = {}; 15686 15687 if (traceFetch) { 15688 utils.addFetchInstrumentationHandler(handlerData => { 15689 const createdSpan = fetch.instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans); 15690 if (enableHTTPTimings && createdSpan) { 15691 addHTTPTimings(createdSpan); 15692 } 15693 }); 15694 } 15695 15696 if (traceXHR) { 15697 utils.addXhrInstrumentationHandler(handlerData => { 15698 const createdSpan = xhrCallback(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans); 15699 if (enableHTTPTimings && createdSpan) { 15700 addHTTPTimings(createdSpan); 15701 } 15702 }); 15703 } 15704} 15705 15706function isPerformanceResourceTiming(entry) { 15707 return ( 15708 entry.entryType === 'resource' && 15709 'initiatorType' in entry && 15710 typeof (entry ).nextHopProtocol === 'string' && 15711 (entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest') 15712 ); 15713} 15714 15715/** 15716 * Creates a temporary observer to listen to the next fetch/xhr resourcing timings, 15717 * so that when timings hit their per-browser limit they don't need to be removed. 15718 * 15719 * @param span A span that has yet to be finished, must contain `url` on data. 15720 */ 15721function addHTTPTimings(span) { 15722 const { url } = core.spanToJSON(span).data || {}; 15723 15724 if (!url || typeof url !== 'string') { 15725 return; 15726 } 15727 15728 const cleanup = instrument.addPerformanceInstrumentationHandler('resource', ({ entries }) => {
15729 entries.forEach(entry => { 15730 if (isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) { 15731 const spanData = resourceTimingEntryToSpanData(entry); 15732 spanData.forEach(data => span.setAttribute(...data)); 15733 // In the next tick, clean this handler up 15734 // We have to wait here because otherwise this cleans itself up before it is fully done 15735 setTimeout(cleanup); 15736 } 15737 }); 15738 }); 15739} 15740 15741/** 15742 * Converts ALPN protocol ids to name and version. 15743 * 15744 * (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids) 15745 * @param nextHopProtocol PerformanceResourceTiming.nextHopProtocol 15746 */ 15747function extractNetworkProtocol(nextHopProtocol) { 15748 let name = 'unknown'; 15749 let version = 'unknown'; 15750 let _name = ''; 15751 for (const char of nextHopProtocol) { 15752 // http/1.1 etc. 15753 if (char === '/') { 15754 [name, version] = nextHopProtocol.split('/'); 15755 break; 15756 } 15757 // h2, h3 etc. 15758 if (!isNaN(Number(char))) { 15759 name = _name === 'h' ? 'http' : _name; 15760 version = nextHopProtocol.split(_name)[1]; 15761 break; 15762 } 15763 _name += char; 15764 } 15765 if (_name === nextHopProtocol) { 15766 // webrtc, ftp, etc. 15767 name = _name; 15768 } 15769 return { name, version }; 15770} 15771 15772function getAbsoluteTime(time = 0) { 15773 return ((utils.browserPerformanceTimeOrigin || performance.timeOrigin) + time) / 1000; 15774} 15775 15776function resourceTimingEntryToSpanData(resourceTiming) { 15777 const { name, version } = extractNetworkProtocol(resourceTiming.nextHopProtocol); 15778 15779 const timingSpanData = []; 15780 15781 timingSpanData.push(['network.protocol.version', version], ['network.protocol.name', name]); 15782 15783 if (!utils.browserPerformanceTimeOrigin) { 15784 return timingSpanData; 15785 } 15786 return [ 15787 ...timingSpanData, 15788 ['http.request.redirect_start', getAbsoluteTime(resourceTiming.redirectStart)], 15789 ['http.request.fetch_start', getAbsoluteTime(resourceTiming.fetchStart)], 15790 ['http.request.domain_lookup_start', getAbsoluteTime(resourceTiming.domainLookupStart)], 15791 ['http.request.domain_lookup_end', getAbsoluteTime(resourceTiming.domainLookupEnd)], 15792 ['http.request.connect_start', getAbsoluteTime(resourceTiming.connectStart)], 15793 ['http.request.secure_connection_start', getAbsoluteTime(resourceTiming.secureConnectionStart)], 15794 ['http.request.connection_end', getAbsoluteTime(resourceTiming.connectEnd)], 15795 ['http.request.request_start', getAbsoluteTime(resourceTiming.requestStart)], 15796 ['http.request.response_start', getAbsoluteTime(resourceTiming.responseStart)], 15797 ['http.request.response_end', getAbsoluteTime(resourceTiming.responseEnd)], 15798 ]; 15799} 15800 15801/** 15802 * A function that determines whether to attach tracing headers to a request. 15803 * This was extracted from `instrumentOutgoingRequests` to make it easier to test shouldAttachHeaders. 15804 * We only export this fuction for testing purposes. 15805 */ 15806function shouldAttachHeaders(url, tracePropagationTargets) { 15807 return utils.stringMatchesSomePattern(url, tracePropagationTargets || DEFAULT_TRACE_PROPAGATION_TARGETS); 15808} 15809 15810/** 15811 * Create and track xhr request spans 15812 * 15813 * @returns Span if a span was created, otherwise void. 15814 */ 15815// eslint-disable-next-line complexity 15816function xhrCallback( 15817 handlerData, 15818 shouldCreateSpan, 15819 shouldAttachHeaders, 15820 spans, 15821) { 15822 const xhr = handlerData.xhr; 15823 const sentryXhrData = xhr && xhr[utils.SENTRY_XHR_DATA_KEY]; 15824 15825 if (!core.hasTracingEnabled() || !xhr || xhr.__sentry_own_request__ || !sentryXhrData) { 15826 return undefined; 15827 } 15828 15829 const shouldCreateSpanResult = shouldCreateSpan(sentryXhrData.url); 15830 15831 // check first if the request has finished and is tracked by an existing span which should now end 15832 if (handlerData.endTimestamp && shouldCreateSpanResult) { 15833 const spanId = xhr.__sentry_xhr_span_id__; 15834 if (!spanId) return; 15835 15836 const span = spans[spanId]; 15837 if (span && sentryXhrData.status_code !== undefined) { 15838 core.setHttpStatus(span, sentryXhrData.status_code); 15839 span.end(); 15840 15841 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 15842 delete spans[spanId]; 15843 } 15844 return undefined; 15845 } 15846 15847 const scope = core.getCurrentScope(); 15848 const isolationScope = core.getIsolationScope(); 15849 15850 const span = shouldCreateSpanResult 15851 ? core.startInactiveSpan({ 15852 name: `${sentryXhrData.method} ${sentryXhrData.url}`, 15853 onlyIfParent: true, 15854 attributes: { 15855 type: 'xhr', 15856 'http.method': sentryXhrData.method, 15857 url: sentryXhrData.url, 15858 [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser', 15859 }, 15860 op: 'http.client', 15861 }) 15862 : undefined; 15863
15864 if (span) { 15865 xhr.__sentry_xhr_span_id__ = span.spanContext().spanId; 15866 spans[xhr.__sentry_xhr_span_id__] = span; 15867 } 15868 15869 const client = core.getClient(); 15870 15871 if (xhr.setRequestHeader && shouldAttachHeaders(sentryXhrData.url) && client) { 15872 const { traceId, spanId, sampled, dsc } = { 15873 ...isolationScope.getPropagationContext(), 15874 ...scope.getPropagationContext(), 15875 }; 15876 15877 const sentryTraceHeader = span ? core.spanToTraceHeader(span) : utils.generateSentryTraceHeader(traceId, spanId, sampled); 15878 15879 const sentryBaggageHeader = utils.dynamicSamplingContextToSentryBaggageHeader( 15880 dsc || 15881 (span ? core.getDynamicSamplingContextFromSpan(span) : core.getDynamicSamplingContextFromClient(traceId, client, scope)), 15882 ); 15883 15884 setHeaderOnXhr(xhr, sentryTraceHeader, sentryBaggageHeader); 15885 } 15886 15887 return span; 15888} 15889 15890function setHeaderOnXhr( 15891 xhr, 15892 sentryTraceHeader, 15893 sentryBaggageHeader, 15894) { 15895 try { 15896 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 15897 xhr.setRequestHeader('sentry-trace', sentryTraceHeader); 15898 if (sentryBaggageHeader) { 15899 // From MDN: "If this method is called several times with the same header, the values are merged into one single request header." 15900 // We can therefore simply set a baggage header without checking what was there before 15901 // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader 15902 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 15903 xhr.setRequestHeader(utils.BAGGAGE_HEADER_NAME, sentryBaggageHeader); 15904 } 15905 } catch (_) { 15906 // Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED. 15907 } 15908} 15909 15910exports.DEFAULT_TRACE_PROPAGATION_TARGETS = DEFAULT_TRACE_PROPAGATION_TARGETS; 15911exports.defaultRequestInstrumentationOptions = defaultRequestInstrumentationOptions; 15912exports.extractNetworkProtocol = extractNetworkProtocol; 15913exports.instrumentOutgoingRequests = instrumentOutgoingRequests; 15914exports.shouldAttachHeaders = shouldAttachHeaders; 15915exports.xhrCallback = xhrCallback; 15916 15917 15918},{"../common/fetch.js":207,"./instrument.js":187,"@sentry/core":250,"@sentry/utils":319}],191:[function(require,module,exports){ 15919Object.defineProperty(exports, '__esModule', { value: true }); 15920 15921const utils = require('@sentry/utils'); 15922const debugBuild = require('../common/debug-build.js'); 15923const types = require('./types.js'); 15924 15925/** 15926 * Default function implementing pageload and navigation transactions 15927 */ 15928function instrumentRoutingWithDefaults( 15929 customStartTransaction, 15930 startTransactionOnPageLoad = true, 15931 startTransactionOnLocationChange = true, 15932) { 15933 if (!types.WINDOW || !types.WINDOW.location) { 15934 debugBuild.DEBUG_BUILD && utils.logger.warn('Could not initialize routing instrumentation due to invalid location'); 15935 return; 15936 } 15937 15938 let startingUrl = types.WINDOW.location.href; 15939 15940 let activeTransaction; 15941 if (startTransactionOnPageLoad) { 15942 activeTransaction = customStartTransaction({ 15943 name: types.WINDOW.location.pathname, 15944 // pageload should always start at timeOrigin (and needs to be in s, not ms) 15945 startTimestamp: utils.browserPerformanceTimeOrigin ? utils.browserPerformanceTimeOrigin / 1000 : undefined, 15946 op: 'pageload', 15947 origin: 'auto.pageload.browser', 15948 metadata: { source: 'url' }, 15949 }); 15950 } 15951 15952 if (startTransactionOnLocationChange) { 15953 utils.addHistoryInstrumentationHandler(({ to, from }) => { 15954 /** 15955 * This early return is there to account for some cases where a navigation transaction starts right after 15956 * long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't 15957 * create an uneccessary navigation transaction. 15958 * 15959 * This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also 15960 * only be caused in certain development environments where the usage of a hot module reloader is causing 15961 * errors. 15962 */ 15963 if (from === undefined && startingUrl && startingUrl.indexOf(to) !== -1) { 15964 startingUrl = undefined; 15965 return; 15966 } 15967 15968 if (from !== to) { 15969 startingUrl = undefined; 15970 if (activeTransaction) { 15971 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Finishing current transaction with op: ${activeTransaction.op}`); 15972 // If there's an open transaction on the scope, we need to finish it before creating an new one. 15973 activeTransaction.end(); 15974 } 15975 activeTransaction = customStartTransaction({ 15976 name: types.WINDOW.location.pathname, 15977 op: 'navigation', 15978 origin: 'auto.navigation.browser', 15979 metadata: { source: 'url' }, 15980 }); 15981 } 15982 }); 15983 } 15984} 15985 15986exports.instrumentRoutingWithDefaults = instrumentRoutingWithDefaults; 15987 15988 15989},{"../common/debug-build.js":206,"./types.js":192,"@sentry/utils":319}],192:[function(require,module,exports){ 15990Object.defineProperty(exports, '__esModule', { value: true }); 15991 15992const utils = require('@sentry/utils'); 15993 15994const WINDOW = utils.GLOBAL_OBJ ; 15995 15996exports.WINDOW = WINDOW; 15997 15998 15999},{"@sentry/utils":319}],193:[function(require,module,exports){ 16000Object.defineProperty(exports, '__esModule', { value: true }); 16001 16002const bindReporter = require('./lib/bindReporter.js'); 16003const initMetric = require('./lib/initMetric.js'); 16004const observe = require('./lib/observe.js'); 16005const onHidden = require('./lib/onHidden.js'); 16006 16007/* 16008 * Copyright 2020 Google LLC 16009 * 16010 * Licensed under the Apache License, Version 2.0 (the "License");
16011 * you may not use this file except in compliance with the License. 16012 * You may obtain a copy of the License at 16013 * 16014 * https://www.apache.org/licenses/LICENSE-2.0 16015 * 16016 * Unless required by applicable law or agreed to in writing, software 16017 * distributed under the License is distributed on an "AS IS" BASIS, 16018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16019 * See the License for the specific language governing permissions and 16020 * limitations under the License. 16021 */ 16022 16023/** 16024 * Calculates the [CLS](https://web.dev/cls/) value for the current page and 16025 * calls the `callback` function once the value is ready to be reported, along 16026 * with all `layout-shift` performance entries that were used in the metric 16027 * value calculation. The reported value is a `double` (corresponding to a 16028 * [layout shift score](https://web.dev/cls/#layout-shift-score)). 16029 * 16030 * If the `reportAllChanges` configuration option is set to `true`, the 16031 * `callback` function will be called as soon as the value is initially 16032 * determined as well as any time the value changes throughout the page 16033 * lifespan. 16034 * 16035 * _**Important:** CLS should be continually monitored for changes throughout 16036 * the entire lifespan of a pageâincluding if the user returns to the page after 16037 * it's been hidden/backgrounded. However, since browsers often [will not fire 16038 * additional callbacks once the user has backgrounded a 16039 * page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden), 16040 * `callback` is always called when the page's visibility state changes to 16041 * hidden. As a result, the `callback` function might be called multiple times 16042 * during the same page load._ 16043 */ 16044const onCLS = (onReport) => { 16045 const metric = initMetric.initMetric('CLS', 0); 16046 let report; 16047 16048 let sessionValue = 0; 16049 let sessionEntries = []; 16050 16051 // const handleEntries = (entries: Metric['entries']) => { 16052 const handleEntries = (entries) => { 16053 entries.forEach(entry => { 16054 // Only count layout shifts without recent user input. 16055 if (!entry.hadRecentInput) { 16056 const firstSessionEntry = sessionEntries[0]; 16057 const lastSessionEntry = sessionEntries[sessionEntries.length - 1]; 16058 16059 // If the entry occurred less than 1 second after the previous entry and 16060 // less than 5 seconds after the first entry in the session, include the 16061 // entry in the current session. Otherwise, start a new session. 16062 if ( 16063 sessionValue && 16064 sessionEntries.length !== 0 && 16065 entry.startTime - lastSessionEntry.startTime < 1000 && 16066 entry.startTime - firstSessionEntry.startTime < 5000 16067 ) { 16068 sessionValue += entry.value; 16069 sessionEntries.push(entry); 16070 } else { 16071 sessionValue = entry.value; 16072 sessionEntries = [entry]; 16073 } 16074 16075 // If the current session value is larger than the current CLS value, 16076 // update CLS and the entries contributing to it. 16077 if (sessionValue > metric.value) { 16078 metric.value = sessionValue; 16079 metric.entries = sessionEntries; 16080 if (report) { 16081 report(); 16082 } 16083 } 16084 } 16085 }); 16086 }; 16087 16088 const po = observe.observe('layout-shift', handleEntries); 16089 if (po) { 16090 report = bindReporter.bindReporter(onReport, metric); 16091 16092 const stopListening = () => { 16093 handleEntries(po.takeRecords() ); 16094 report(true); 16095 }; 16096 16097 onHidden.onHidden(stopListening); 16098 16099 return stopListening; 16100 } 16101 16102 return; 16103}; 16104 16105exports.onCLS = onCLS; 16106 16107 16108},{"./lib/bindReporter.js":197,"./lib/initMetric.js":202,"./lib/observe.js":203,"./lib/onHidden.js":204}],194:[function(require,module,exports){ 16109Object.defineProperty(exports, '__esModule', { value: true }); 16110 16111const bindReporter = require('./lib/bindReporter.js'); 16112const getVisibilityWatcher = require('./lib/getVisibilityWatcher.js'); 16113const initMetric = require('./lib/initMetric.js'); 16114const observe = require('./lib/observe.js'); 16115const onHidden = require('./lib/onHidden.js'); 16116 16117/* 16118 * Copyright 2020 Google LLC 16119 * 16120 * Licensed under the Apache License, Version 2.0 (the "License");
16121 * you may not use this file except in compliance with the License. 16122 * You may obtain a copy of the License at 16123 * 16124 * https://www.apache.org/licenses/LICENSE-2.0 16125 * 16126 * Unless required by applicable law or agreed to in writing, software 16127 * distributed under the License is distributed on an "AS IS" BASIS, 16128 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16129 * See the License for the specific language governing permissions and 16130 * limitations under the License. 16131 */ 16132 16133/** 16134 * Calculates the [FID](https://web.dev/fid/) value for the current page and 16135 * calls the `callback` function once the value is ready, along with the 16136 * relevant `first-input` performance entry used to determine the value. The 16137 * reported value is a `DOMHighResTimeStamp`. 16138 * 16139 * _**Important:** since FID is only reported after the user interacts with the 16140 * page, it's possible that it will not be reported for some page loads._ 16141 */ 16142const onFID = (onReport) => { 16143 const visibilityWatcher = getVisibilityWatcher.getVisibilityWatcher(); 16144 const metric = initMetric.initMetric('FID'); 16145 // eslint-disable-next-line prefer-const 16146 let report; 16147 16148 const handleEntry = (entry) => { 16149 // Only report if the page wasn't hidden prior to the first input. 16150 if (entry.startTime < visibilityWatcher.firstHiddenTime) { 16151 metric.value = entry.processingStart - entry.startTime; 16152 metric.entries.push(entry); 16153 report(true); 16154 } 16155 }; 16156 16157 const handleEntries = (entries) => { 16158 (entries ).forEach(handleEntry); 16159 }; 16160 16161 const po = observe.observe('first-input', handleEntries); 16162 report = bindReporter.bindReporter(onReport, metric); 16163 16164 if (po) { 16165 onHidden.onHidden(() => { 16166 handleEntries(po.takeRecords() ); 16167 po.disconnect(); 16168 }, true); 16169 } 16170}; 16171 16172exports.onFID = onFID; 16173 16174 16175},{"./lib/bindReporter.js":197,"./lib/getVisibilityWatcher.js":201,"./lib/initMetric.js":202,"./lib/observe.js":203,"./lib/onHidden.js":204}],195:[function(require,module,exports){ 16176Object.defineProperty(exports, '__esModule', { value: true }); 16177 16178const bindReporter = require('./lib/bindReporter.js'); 16179const initMetric = require('./lib/initMetric.js'); 16180const observe = require('./lib/observe.js'); 16181const onHidden = require('./lib/onHidden.js'); 16182const interactionCountPolyfill = require('./lib/polyfills/interactionCountPolyfill.js'); 16183 16184/* 16185 * Copyright 2022 Google LLC 16186 * 16187 * Licensed under the Apache License, Version 2.0 (the "License"); 16188 * you may not use this file except in compliance with the License. 16189 * You may obtain a copy of the License at 16190 * 16191 * https://www.apache.org/licenses/LICENSE-2.0 16192 * 16193 * Unless required by applicable law or agreed to in writing, software 16194 * distributed under the License is distributed on an "AS IS" BASIS, 16195 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16196 * See the License for the specific language governing permissions and 16197 * limitations under the License. 16198 */ 16199 16200/** 16201 * Returns the interaction count since the last bfcache restore (or for the 16202 * full page lifecycle if there were no bfcache restores). 16203 */ 16204const getInteractionCountForNavigation = () => { 16205 return interactionCountPolyfill.getInteractionCount(); 16206}; 16207 16208// To prevent unnecessary memory usage on pages with lots of interactions, 16209// store at most 10 of the longest interactions to consider as INP candidates. 16210const MAX_INTERACTIONS_TO_CONSIDER = 10; 16211 16212// A list of longest interactions on the page (by latency) sorted so the 16213// longest one is first. The list is as most MAX_INTERACTIONS_TO_CONSIDER long. 16214const longestInteractionList = []; 16215 16216// A mapping of longest interactions by their interaction ID. 16217// This is used for faster lookup. 16218const longestInteractionMap = {}; 16219 16220/** 16221 * Takes a performance entry and adds it to the list of worst interactions 16222 * if its duration is long enough to make it among the worst. If the 16223 * entry is part of an existing interaction, it is merged and the latency 16224 * and entries list is updated as needed. 16225 */ 16226const processEntry = (entry) => { 16227 // The least-long of the 10 longest interactions. 16228 const minLongestInteraction = longestInteractionList[longestInteractionList.length - 1]; 16229 16230 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 16231 const existingInteraction = longestInteractionMap[entry.interactionId]; 16232 16233 // Only process the entry if it's possibly one of the ten longest, 16234 // or if it's part of an existing interaction. 16235 if ( 16236 existingInteraction || 16237 longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER || 16238 entry.duration > minLongestInteraction.latency 16239 ) { 16240 // If the interaction already exists, update it. Otherwise create one. 16241 if (existingInteraction) { 16242 existingInteraction.entries.push(entry); 16243 existingInteraction.latency = Math.max(existingInteraction.latency, entry.duration); 16244 } else { 16245 const interaction = { 16246 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 16247 id: entry.interactionId, 16248 latency: entry.duration,
16249 entries: [entry], 16250 }; 16251 longestInteractionMap[interaction.id] = interaction; 16252 longestInteractionList.push(interaction); 16253 } 16254 16255 // Sort the entries by latency (descending) and keep only the top ten. 16256 longestInteractionList.sort((a, b) => b.latency - a.latency); 16257 longestInteractionList.splice(MAX_INTERACTIONS_TO_CONSIDER).forEach(i => { 16258 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 16259 delete longestInteractionMap[i.id]; 16260 }); 16261 } 16262}; 16263 16264/** 16265 * Returns the estimated p98 longest interaction based on the stored 16266 * interaction candidates and the interaction count for the current page. 16267 */ 16268const estimateP98LongestInteraction = () => { 16269 const candidateInteractionIndex = Math.min( 16270 longestInteractionList.length - 1, 16271 Math.floor(getInteractionCountForNavigation() / 50), 16272 ); 16273 16274 return longestInteractionList[candidateInteractionIndex]; 16275}; 16276 16277/** 16278 * Calculates the [INP](https://web.dev/responsiveness/) value for the current 16279 * page and calls the `callback` function once the value is ready, along with 16280 * the `event` performance entries reported for that interaction. The reported 16281 * value is a `DOMHighResTimeStamp`. 16282 * 16283 * A custom `durationThreshold` configuration option can optionally be passed to 16284 * control what `event-timing` entries are considered for INP reporting. The 16285 * default threshold is `40`, which means INP scores of less than 40 are 16286 * reported as 0. Note that this will not affect your 75th percentile INP value 16287 * unless that value is also less than 40 (well below the recommended 16288 * [good](https://web.dev/inp/#what-is-a-good-inp-score) threshold). 16289 * 16290 * If the `reportAllChanges` configuration option is set to `true`, the 16291 * `callback` function will be called as soon as the value is initially 16292 * determined as well as any time the value changes throughout the page 16293 * lifespan. 16294 * 16295 * _**Important:** INP should be continually monitored for changes throughout 16296 * the entire lifespan of a pageâincluding if the user returns to the page after 16297 * it's been hidden/backgrounded. However, since browsers often [will not fire 16298 * additional callbacks once the user has backgrounded a 16299 * page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden), 16300 * `callback` is always called when the page's visibility state changes to 16301 * hidden. As a result, the `callback` function might be called multiple times 16302 * during the same page load._ 16303 */ 16304const onINP = (onReport, opts) => { 16305 // Set defaults 16306 // eslint-disable-next-line no-param-reassign 16307 opts = opts || {}; 16308 16309 // https://web.dev/inp/#what's-a-%22good%22-inp-value 16310 // const thresholds = [200, 500]; 16311 16312 // TODO(philipwalton): remove once the polyfill is no longer needed. 16313 interactionCountPolyfill.initInteractionCountPolyfill(); 16314 16315 const metric = initMetric.initMetric('INP'); 16316 // eslint-disable-next-line prefer-const 16317 let report; 16318 16319 const handleEntries = (entries) => { 16320 entries.forEach(entry => { 16321 if (entry.interactionId) { 16322 processEntry(entry); 16323 } 16324 16325 // Entries of type `first-input` don't currently have an `interactionId`, 16326 // so to consider them in INP we have to first check that an existing 16327 // entry doesn't match the `duration` and `startTime`. 16328 // Note that this logic assumes that `event` entries are dispatched 16329 // before `first-input` entries. This is true in Chrome but it is not 16330 // true in Firefox; however, Firefox doesn't support interactionId, so 16331 // it's not an issue at the moment. 16332 // TODO(philipwalton): remove once crbug.com/1325826 is fixed. 16333 if (entry.entryType === 'first-input') { 16334 const noMatchingEntry = !longestInteractionList.some(interaction => { 16335 return interaction.entries.some(prevEntry => { 16336 return entry.duration === prevEntry.duration && entry.startTime === prevEntry.startTime; 16337 }); 16338 }); 16339 if (noMatchingEntry) { 16340 processEntry(entry); 16341 } 16342 } 16343 }); 16344 16345 const inp = estimateP98LongestInteraction(); 16346 16347 if (inp && inp.latency !== metric.value) { 16348 metric.value = inp.latency; 16349 metric.entries = inp.entries; 16350 report(); 16351 } 16352 }; 16353 16354 const po = observe.observe('event', handleEntries, { 16355 // Event Timing entries have their durations rounded to the nearest 8ms, 16356 // so a duration of 40ms would be any event that spans 2.5 or more frames
16357 // at 60Hz. This threshold is chosen to strike a balance between usefulness 16358 // and performance. Running this callback for any interaction that spans 16359 // just one or two frames is likely not worth the insight that could be 16360 // gained. 16361 durationThreshold: opts.durationThreshold || 40, 16362 } ); 16363 16364 report = bindReporter.bindReporter(onReport, metric, opts.reportAllChanges); 16365 16366 if (po) { 16367 // Also observe entries of type `first-input`. This is useful in cases 16368 // where the first interaction is less than the `durationThreshold`. 16369 po.observe({ type: 'first-input', buffered: true }); 16370 16371 onHidden.onHidden(() => { 16372 handleEntries(po.takeRecords() ); 16373 16374 // If the interaction count shows that there were interactions but 16375 // none were captured by the PerformanceObserver, report a latency of 0. 16376 if (metric.value < 0 && getInteractionCountForNavigation() > 0) { 16377 metric.value = 0; 16378 metric.entries = []; 16379 } 16380 16381 report(true); 16382 }); 16383 } 16384}; 16385 16386exports.onINP = onINP; 16387 16388 16389},{"./lib/bindReporter.js":197,"./lib/initMetric.js":202,"./lib/observe.js":203,"./lib/onHidden.js":204,"./lib/polyfills/interactionCountPolyfill.js":205}],196:[function(require,module,exports){ 16390Object.defineProperty(exports, '__esModule', { value: true }); 16391 16392const bindReporter = require('./lib/bindReporter.js'); 16393const getActivationStart = require('./lib/getActivationStart.js'); 16394const getVisibilityWatcher = require('./lib/getVisibilityWatcher.js'); 16395const initMetric = require('./lib/initMetric.js'); 16396const observe = require('./lib/observe.js'); 16397const onHidden = require('./lib/onHidden.js'); 16398 16399/* 16400 * Copyright 2020 Google LLC 16401 * 16402 * Licensed under the Apache License, Version 2.0 (the "License"); 16403 * you may not use this file except in compliance with the License. 16404 * You may obtain a copy of the License at 16405 * 16406 * https://www.apache.org/licenses/LICENSE-2.0 16407 * 16408 * Unless required by applicable law or agreed to in writing, software 16409 * distributed under the License is distributed on an "AS IS" BASIS, 16410 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16411 * See the License for the specific language governing permissions and 16412 * limitations under the License. 16413 */ 16414 16415const reportedMetricIDs = {}; 16416 16417/** 16418 * Calculates the [LCP](https://web.dev/lcp/) value for the current page and 16419 * calls the `callback` function once the value is ready (along with the 16420 * relevant `largest-contentful-paint` performance entry used to determine the 16421 * value). The reported value is a `DOMHighResTimeStamp`. 16422 */ 16423const onLCP = (onReport) => { 16424 const visibilityWatcher = getVisibilityWatcher.getVisibilityWatcher(); 16425 const metric = initMetric.initMetric('LCP'); 16426 let report; 16427 16428 const handleEntries = (entries) => { 16429 const lastEntry = entries[entries.length - 1] ; 16430 if (lastEntry) { 16431 // The startTime attribute returns the value of the renderTime if it is 16432 // not 0, and the value of the loadTime otherwise. The activationStart 16433 // reference is used because LCP should be relative to page activation 16434 // rather than navigation start if the page was prerendered. 16435 const value = Math.max(lastEntry.startTime - getActivationStart.getActivationStart(), 0); 16436 16437 // Only report if the page wasn't hidden prior to LCP. 16438 if (value < visibilityWatcher.firstHiddenTime) { 16439 metric.value = value; 16440 metric.entries = [lastEntry]; 16441 report(); 16442 } 16443 } 16444 }; 16445 16446 const po = observe.observe('largest-contentful-paint', handleEntries); 16447 16448 if (po) { 16449 report = bindReporter.bindReporter(onReport, metric); 16450 16451 const stopListening = () => { 16452 if (!reportedMetricIDs[metric.id]) { 16453 handleEntries(po.takeRecords() ); 16454 po.disconnect(); 16455 reportedMetricIDs[metric.id] = true; 16456 report(true); 16457 } 16458 }; 16459 16460 // Stop listening after input. Note: while scrolling is an input that 16461 // stop LCP observation, it's unreliable since it can be programmatically 16462 // generated. See: https://github.com/GoogleChrome/web-vitals/issues/75 16463 ['keydown', 'click'].forEach(type => { 16464 addEventListener(type, stopListening, { once: true, capture: true }); 16465 }); 16466 16467 onHidden.onHidden(stopListening, true); 16468 16469 return stopListening; 16470 } 16471 16472 return; 16473}; 16474 16475exports.onLCP = onLCP; 16476 16477 16478},{"./lib/bindReporter.js":197,"./lib/getActivationStart.js":199,"./lib/getVisibilityWatcher.js":201,"./lib/initMetric.js":202,"./lib/observe.js":203,"./lib/onHidden.js":204}],197:[function(require,module,exports){ 16479Object.defineProperty(exports, '__esModule', { value: true }); 16480 16481const bindReporter = ( 16482 callback, 16483 metric, 16484 reportAllChanges, 16485) => { 16486 let prevValue; 16487 let delta; 16488 return (forceReport) => { 16489 if (metric.value >= 0) { 16490 if (forceReport || reportAllChanges) {
16491 delta = metric.value - (prevValue || 0); 16492 16493 // Report the metric if there's a non-zero delta or if no previous 16494 // value exists (which can happen in the case of the document becoming 16495 // hidden when the metric value is 0). 16496 // See: https://github.com/GoogleChrome/web-vitals/issues/14 16497 if (delta || prevValue === undefined) { 16498 prevValue = metric.value; 16499 metric.delta = delta; 16500 callback(metric); 16501 } 16502 } 16503 } 16504 }; 16505}; 16506 16507exports.bindReporter = bindReporter; 16508 16509 16510},{}],198:[function(require,module,exports){ 16511Object.defineProperty(exports, '__esModule', { value: true }); 16512 16513/* 16514 * Copyright 2020 Google LLC 16515 * 16516 * Licensed under the Apache License, Version 2.0 (the "License"); 16517 * you may not use this file except in compliance with the License. 16518 * You may obtain a copy of the License at 16519 * 16520 * https://www.apache.org/licenses/LICENSE-2.0 16521 * 16522 * Unless required by applicable law or agreed to in writing, software 16523 * distributed under the License is distributed on an "AS IS" BASIS, 16524 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16525 * See the License for the specific language governing permissions and 16526 * limitations under the License. 16527 */ 16528 16529/** 16530 * Performantly generate a unique, 30-char string by combining a version 16531 * number, the current timestamp with a 13-digit number integer. 16532 * @return {string} 16533 */ 16534const generateUniqueID = () => { 16535 return `v3-${Date.now()}-${Math.floor(Math.random() * (9e12 - 1)) + 1e12}`; 16536}; 16537 16538exports.generateUniqueID = generateUniqueID; 16539 16540 16541},{}],199:[function(require,module,exports){ 16542Object.defineProperty(exports, '__esModule', { value: true }); 16543 16544const getNavigationEntry = require('./getNavigationEntry.js'); 16545 16546/* 16547 * Copyright 2022 Google LLC 16548 * 16549 * Licensed under the Apache License, Version 2.0 (the "License"); 16550 * you may not use this file except in compliance with the License. 16551 * You may obtain a copy of the License at 16552 * 16553 * https://www.apache.org/licenses/LICENSE-2.0 16554 * 16555 * Unless required by applicable law or agreed to in writing, software 16556 * distributed under the License is distributed on an "AS IS" BASIS, 16557 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16558 * See the License for the specific language governing permissions and 16559 * limitations under the License. 16560 */ 16561 16562const getActivationStart = () => { 16563 const navEntry = getNavigationEntry.getNavigationEntry(); 16564 return (navEntry && navEntry.activationStart) || 0; 16565}; 16566 16567exports.getActivationStart = getActivationStart; 16568 16569 16570},{"./getNavigationEntry.js":200}],200:[function(require,module,exports){ 16571Object.defineProperty(exports, '__esModule', { value: true }); 16572 16573const types = require('../../types.js'); 16574 16575/* 16576 * Copyright 2022 Google LLC 16577 * 16578 * Licensed under the Apache License, Version 2.0 (the "License"); 16579 * you may not use this file except in compliance with the License. 16580 * You may obtain a copy of the License at 16581 * 16582 * https://www.apache.org/licenses/LICENSE-2.0 16583 * 16584 * Unless required by applicable law or agreed to in writing, software 16585 * distributed under the License is distributed on an "AS IS" BASIS, 16586 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16587 * See the License for the specific language governing permissions and 16588 * limitations under the License. 16589 */ 16590 16591const getNavigationEntryFromPerformanceTiming = () => { 16592 // eslint-disable-next-line deprecation/deprecation 16593 const timing = types.WINDOW.performance.timing; 16594 // eslint-disable-next-line deprecation/deprecation 16595 const type = types.WINDOW.performance.navigation.type; 16596 16597 const navigationEntry = { 16598 entryType: 'navigation', 16599 startTime: 0, 16600 type: type == 2 ? 'back_forward' : type === 1 ? 'reload' : 'navigate', 16601 }; 16602 16603 for (const key in timing) { 16604 if (key !== 'navigationStart' && key !== 'toJSON') { 16605 // eslint-disable-next-line deprecation/deprecation 16606 navigationEntry[key] = Math.max((timing[key ] ) - timing.navigationStart, 0); 16607 } 16608 } 16609 return navigationEntry ; 16610}; 16611 16612const getNavigationEntry = () => { 16613 if (types.WINDOW.__WEB_VITALS_POLYFILL__) { 16614 return ( 16615 types.WINDOW.performance && 16616 ((performance.getEntriesByType && performance.getEntriesByType('navigation')[0]) || 16617 getNavigationEntryFromPerformanceTiming()) 16618 ); 16619 } else { 16620 return types.WINDOW.performance && performance.getEntriesByType && performance.getEntriesByType('navigation')[0]; 16621 } 16622}; 16623 16624exports.getNavigationEntry = getNavigationEntry; 16625 16626 16627},{"../../types.js":192}],201:[function(require,module,exports){ 16628Object.defineProperty(exports, '__esModule', { value: true }); 16629 16630const types = require('../../types.js'); 16631const onHidden = require('./onHidden.js'); 16632 16633/* 16634 * Copyright 2020 Google LLC 16635 * 16636 * Licensed under the Apache License, Version 2.0 (the "License");
16637 * you may not use this file except in compliance with the License. 16638 * You may obtain a copy of the License at 16639 * 16640 * https://www.apache.org/licenses/LICENSE-2.0 16641 * 16642 * Unless required by applicable law or agreed to in writing, software 16643 * distributed under the License is distributed on an "AS IS" BASIS, 16644 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16645 * See the License for the specific language governing permissions and 16646 * limitations under the License. 16647 */ 16648 16649let firstHiddenTime = -1; 16650 16651const initHiddenTime = () => { 16652 // If the document is hidden and not prerendering, assume it was always 16653 // hidden and the page was loaded in the background. 16654 return types.WINDOW.document.visibilityState === 'hidden' && !types.WINDOW.document.prerendering ? 0 : Infinity; 16655}; 16656 16657const trackChanges = () => { 16658 // Update the time if/when the document becomes hidden. 16659 onHidden.onHidden(({ timeStamp }) => { 16660 firstHiddenTime = timeStamp; 16661 }, true); 16662}; 16663 16664const getVisibilityWatcher = ( 16665 16666) => { 16667 if (firstHiddenTime < 0) { 16668 // If the document is hidden when this code runs, assume it was hidden 16669 // since navigation start. This isn't a perfect heuristic, but it's the 16670 // best we can do until an API is available to support querying past 16671 // visibilityState. 16672 firstHiddenTime = initHiddenTime(); 16673 trackChanges(); 16674 } 16675 return { 16676 get firstHiddenTime() { 16677 return firstHiddenTime; 16678 }, 16679 }; 16680}; 16681 16682exports.getVisibilityWatcher = getVisibilityWatcher; 16683 16684 16685},{"../../types.js":192,"./onHidden.js":204}],202:[function(require,module,exports){ 16686Object.defineProperty(exports, '__esModule', { value: true }); 16687 16688const types = require('../../types.js'); 16689const generateUniqueID = require('./generateUniqueID.js'); 16690const getActivationStart = require('./getActivationStart.js'); 16691const getNavigationEntry = require('./getNavigationEntry.js'); 16692 16693/* 16694 * Copyright 2020 Google LLC 16695 * 16696 * Licensed under the Apache License, Version 2.0 (the "License"); 16697 * you may not use this file except in compliance with the License. 16698 * You may obtain a copy of the License at 16699 * 16700 * https://www.apache.org/licenses/LICENSE-2.0 16701 * 16702 * Unless required by applicable law or agreed to in writing, software 16703 * distributed under the License is distributed on an "AS IS" BASIS, 16704 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16705 * See the License for the specific language governing permissions and 16706 * limitations under the License. 16707 */ 16708 16709const initMetric = (name, value) => { 16710 const navEntry = getNavigationEntry.getNavigationEntry(); 16711 let navigationType = 'navigate'; 16712 16713 if (navEntry) { 16714 if (types.WINDOW.document.prerendering || getActivationStart.getActivationStart() > 0) { 16715 navigationType = 'prerender'; 16716 } else { 16717 navigationType = navEntry.type.replace(/_/g, '-') ; 16718 } 16719 } 16720 16721 return { 16722 name, 16723 value: typeof value === 'undefined' ? -1 : value, 16724 rating: 'good', // Will be updated if the value changes. 16725 delta: 0, 16726 entries: [], 16727 id: generateUniqueID.generateUniqueID(), 16728 navigationType, 16729 }; 16730}; 16731 16732exports.initMetric = initMetric; 16733 16734 16735},{"../../types.js":192,"./generateUniqueID.js":198,"./getActivationStart.js":199,"./getNavigationEntry.js":200}],203:[function(require,module,exports){ 16736Object.defineProperty(exports, '__esModule', { value: true }); 16737 16738/** 16739 * Takes a performance entry type and a callback function, and creates a 16740 * `PerformanceObserver` instance that will observe the specified entry type 16741 * with buffering enabled and call the callback _for each entry_. 16742 * 16743 * This function also feature-detects entry support and wraps the logic in a 16744 * try/catch to avoid errors in unsupporting browsers. 16745 */ 16746const observe = ( 16747 type, 16748 callback, 16749 opts, 16750) => { 16751 try { 16752 if (PerformanceObserver.supportedEntryTypes.includes(type)) { 16753 const po = new PerformanceObserver(list => { 16754 callback(list.getEntries() ); 16755 }); 16756 po.observe( 16757 Object.assign( 16758 { 16759 type, 16760 buffered: true, 16761 }, 16762 opts || {}, 16763 ) , 16764 ); 16765 return po; 16766 } 16767 } catch (e) {
16768 // Do nothing. 16769 } 16770 return; 16771}; 16772 16773exports.observe = observe; 16774 16775 16776},{}],204:[function(require,module,exports){ 16777Object.defineProperty(exports, '__esModule', { value: true }); 16778 16779const types = require('../../types.js'); 16780 16781/* 16782 * Copyright 2020 Google LLC 16783 * 16784 * Licensed under the Apache License, Version 2.0 (the "License"); 16785 * you may not use this file except in compliance with the License. 16786 * You may obtain a copy of the License at 16787 * 16788 * https://www.apache.org/licenses/LICENSE-2.0 16789 * 16790 * Unless required by applicable law or agreed to in writing, software 16791 * distributed under the License is distributed on an "AS IS" BASIS, 16792 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16793 * See the License for the specific language governing permissions and 16794 * limitations under the License. 16795 */ 16796 16797const onHidden = (cb, once) => { 16798 const onHiddenOrPageHide = (event) => { 16799 if (event.type === 'pagehide' || types.WINDOW.document.visibilityState === 'hidden') { 16800 cb(event); 16801 if (once) { 16802 removeEventListener('visibilitychange', onHiddenOrPageHide, true); 16803 removeEventListener('pagehide', onHiddenOrPageHide, true); 16804 } 16805 } 16806 }; 16807 addEventListener('visibilitychange', onHiddenOrPageHide, true); 16808 // Some browsers have buggy implementations of visibilitychange, 16809 // so we use pagehide in addition, just to be safe. 16810 addEventListener('pagehide', onHiddenOrPageHide, true); 16811}; 16812 16813exports.onHidden = onHidden; 16814 16815 16816},{"../../types.js":192}],205:[function(require,module,exports){ 16817Object.defineProperty(exports, '__esModule', { value: true }); 16818 16819const observe = require('../observe.js'); 16820 16821let interactionCountEstimate = 0; 16822let minKnownInteractionId = Infinity; 16823let maxKnownInteractionId = 0; 16824 16825const updateEstimate = (entries) => { 16826 (entries ).forEach(e => { 16827 if (e.interactionId) { 16828 minKnownInteractionId = Math.min(minKnownInteractionId, e.interactionId); 16829 maxKnownInteractionId = Math.max(maxKnownInteractionId, e.interactionId); 16830 16831 interactionCountEstimate = maxKnownInteractionId ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1 : 0; 16832 } 16833 }); 16834}; 16835 16836let po; 16837 16838/** 16839 * Returns the `interactionCount` value using the native API (if available) 16840 * or the polyfill estimate in this module. 16841 */ 16842const getInteractionCount = () => { 16843 return po ? interactionCountEstimate : performance.interactionCount || 0; 16844}; 16845 16846/** 16847 * Feature detects native support or initializes the polyfill if needed. 16848 */ 16849const initInteractionCountPolyfill = () => { 16850 if ('interactionCount' in performance || po) return; 16851 16852 po = observe.observe('event', updateEstimate, { 16853 type: 'event', 16854 buffered: true, 16855 durationThreshold: 0, 16856 } ); 16857}; 16858 16859exports.getInteractionCount = getInteractionCount; 16860exports.initInteractionCountPolyfill = initInteractionCountPolyfill; 16861 16862 16863},{"../observe.js":203}],206:[function(require,module,exports){ 16864Object.defineProperty(exports, '__esModule', { value: true }); 16865 16866/** 16867 * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code. 16868 * 16869 * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking. 16870 */ 16871const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__); 16872 16873exports.DEBUG_BUILD = DEBUG_BUILD; 16874 16875 16876},{}],207:[function(require,module,exports){ 16877Object.defineProperty(exports, '__esModule', { value: true }); 16878 16879const core = require('@sentry/core'); 16880const utils = require('@sentry/utils'); 16881 16882/** 16883 * Create and track fetch request spans for usage in combination with `addInstrumentationHandler`. 16884 * 16885 * @returns Span if a span was created, otherwise void. 16886 */ 16887function instrumentFetchRequest( 16888 handlerData, 16889 shouldCreateSpan, 16890 shouldAttachHeaders, 16891 spans, 16892 spanOrigin = 'auto.http.browser', 16893) { 16894 if (!core.hasTracingEnabled() || !handlerData.fetchData) { 16895 return undefined; 16896 } 16897 16898 const shouldCreateSpanResult = shouldCreateSpan(handlerData.fetchData.url); 16899 16900 if (handlerData.endTimestamp && shouldCreateSpanResult) { 16901 const spanId = handlerData.fetchData.__span; 16902 if (!spanId) return; 16903 16904 const span = spans[spanId]; 16905 if (span) { 16906 if (handlerData.response) { 16907 core.setHttpStatus(span, handlerData.response.status); 16908 16909 const contentLength = 16910 handlerData.response && handlerData.response.headers && handlerData.response.headers.get('content-length'); 16911 16912 if (contentLength) { 16913 const contentLengthNum = parseInt(contentLength); 16914 if (contentLengthNum > 0) { 16915 span.setAttribute('http.response_content_length', contentLengthNum); 16916 } 16917 } 16918 } else if (handlerData.error) { 16919 span.setStatus('internal_error'); 16920 } 16921 span.end(); 16922 16923 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 16924 delete spans[spanId]; 16925 } 16926 return undefined; 16927 } 16928 16929 const scope = core.getCurrentScope(); 16930 const client = core.getClient(); 16931 16932 const { method, url } = handlerData.fetchData; 16933 16934 const span = shouldCreateSpanResult 16935 ? core.startInactiveSpan({ 16936 name: `${method} ${url}`, 16937 onlyIfParent: true, 16938 attributes: { 16939 url, 16940 type: 'fetch', 16941 'http.method': method, 16942 [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin, 16943 }, 16944 op: 'http.client', 16945 }) 16946 : undefined; 16947
16948 if (span) { 16949 handlerData.fetchData.__span = span.spanContext().spanId; 16950 spans[span.spanContext().spanId] = span; 16951 } 16952 16953 if (shouldAttachHeaders(handlerData.fetchData.url) && client) { 16954 const request = handlerData.args[0]; 16955 16956 // In case the user hasn't set the second argument of a fetch call we default it to `{}`. 16957 handlerData.args[1] = handlerData.args[1] || {}; 16958 16959 // eslint-disable-next-line @typescript-eslint/no-explicit-any 16960 const options = handlerData.args[1]; 16961 16962 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access 16963 options.headers = addTracingHeadersToFetchRequest(request, client, scope, options, span); 16964 } 16965 16966 return span; 16967} 16968 16969/** 16970 * Adds sentry-trace and baggage headers to the various forms of fetch headers 16971 */ 16972function addTracingHeadersToFetchRequest( 16973 request, // unknown is actually type Request but we can't export DOM types from this package, 16974 client, 16975 scope, 16976 options 16977 16978, 16979 requestSpan, 16980) { 16981 // eslint-disable-next-line deprecation/deprecation 16982 const span = requestSpan || scope.getSpan(); 16983 16984 const isolationScope = core.getIsolationScope(); 16985 16986 const { traceId, spanId, sampled, dsc } = { 16987 ...isolationScope.getPropagationContext(), 16988 ...scope.getPropagationContext(), 16989 }; 16990 16991 const sentryTraceHeader = span ? core.spanToTraceHeader(span) : utils.generateSentryTraceHeader(traceId, spanId, sampled); 16992 16993 const sentryBaggageHeader = utils.dynamicSamplingContextToSentryBaggageHeader( 16994 dsc || 16995 (span ? core.getDynamicSamplingContextFromSpan(span) : core.getDynamicSamplingContextFromClient(traceId, client, scope)), 16996 ); 16997 16998 const headers = 16999 options.headers || 17000 (typeof Request !== 'undefined' && utils.isInstanceOf(request, Request) ? (request ).headers : undefined); 17001 17002 if (!headers) { 17003 return { 'sentry-trace': sentryTraceHeader, baggage: sentryBaggageHeader }; 17004 } else if (typeof Headers !== 'undefined' && utils.isInstanceOf(headers, Headers)) { 17005 const newHeaders = new Headers(headers ); 17006 17007 newHeaders.append('sentry-trace', sentryTraceHeader); 17008 17009 if (sentryBaggageHeader) { 17010 // If the same header is appended multiple times the browser will merge the values into a single request header. 17011 // Its therefore safe to simply push a "baggage" entry, even though there might already be another baggage header. 17012 newHeaders.append(utils.BAGGAGE_HEADER_NAME, sentryBaggageHeader); 17013 } 17014 17015 return newHeaders ; 17016 } else if (Array.isArray(headers)) { 17017 const newHeaders = [...headers, ['sentry-trace', sentryTraceHeader]]; 17018 17019 if (sentryBaggageHeader) { 17020 // If there are multiple entries with the same key, the browser will merge the values into a single request header. 17021 // Its therefore safe to simply push a "baggage" entry, even though there might already be another baggage header. 17022 newHeaders.push([utils.BAGGAGE_HEADER_NAME, sentryBaggageHeader]); 17023 } 17024 17025 return newHeaders ; 17026 } else { 17027 const existingBaggageHeader = 'baggage' in headers ? headers.baggage : undefined; 17028 const newBaggageHeaders = []; 17029 17030 if (Array.isArray(existingBaggageHeader)) { 17031 newBaggageHeaders.push(...existingBaggageHeader); 17032 } else if (existingBaggageHeader) { 17033 newBaggageHeaders.push(existingBaggageHeader); 17034 } 17035 17036 if (sentryBaggageHeader) { 17037 newBaggageHeaders.push(sentryBaggageHeader); 17038 } 17039 17040 return { 17041 ...(headers ), 17042 'sentry-trace': sentryTraceHeader, 17043 baggage: newBaggageHeaders.length > 0 ? newBaggageHeaders.join(',') : undefined, 17044 }; 17045 } 17046} 17047 17048exports.addTracingHeadersToFetchRequest = addTracingHeadersToFetchRequest; 17049exports.instrumentFetchRequest = instrumentFetchRequest; 17050 17051 17052},{"@sentry/core":250,"@sentry/utils":319}],208:[function(require,module,exports){ 17053Object.defineProperty(exports, '__esModule', { value: true }); 17054 17055const core = require('@sentry/core'); 17056const utils = require('@sentry/utils'); 17057 17058/** 17059 * @private 17060 */ 17061function _autoloadDatabaseIntegrations() { 17062 const carrier = core.getMainCarrier(); 17063 if (!carrier.__SENTRY__) { 17064 return; 17065 } 17066 17067 const packageToIntegrationMapping = { 17068 mongodb() { 17069 const integration = utils.dynamicRequire(module, './node/integrations/mongo') 17070 17071; 17072 return new integration.Mongo(); 17073 }, 17074 mongoose() { 17075 const integration = utils.dynamicRequire(module, './node/integrations/mongo') 17076 17077; 17078 return new integration.Mongo(); 17079 }, 17080 mysql() { 17081 const integration = utils.dynamicRequire(module, './node/integrations/mysql') 17082 17083; 17084 return new integration.Mysql(); 17085 }, 17086 pg() { 17087 const integration = utils.dynamicRequire(module, './node/integrations/postgres') 17088 17089; 17090 return new integration.Postgres(); 17091 }, 17092 }; 17093 17094 const mappedPackages = Object.keys(packageToIntegrationMapping) 17095 .filter(moduleName =>
17095 !!utils.loadModule(moduleName)) 17096 .map(pkg => { 17097 try { 17098 return packageToIntegrationMapping[pkg](); 17099 } catch (e) { 17100 return undefined; 17101 } 17102 }) 17103 .filter(p => p) ; 17104 17105 if (mappedPackages.length > 0) { 17106 carrier.__SENTRY__.integrations = [...(carrier.__SENTRY__.integrations || []), ...mappedPackages]; 17107 } 17108} 17109 17110/** 17111 * This patches the global object and injects the Tracing extensions methods 17112 */ 17113function addExtensionMethods() { 17114 core.addTracingExtensions(); 17115 17116 // Detect and automatically load specified integrations. 17117 if (utils.isNodeEnv()) { 17118 _autoloadDatabaseIntegrations(); 17119 } 17120} 17121 17122exports.addExtensionMethods = addExtensionMethods; 17123 17124 17125},{"@sentry/core":250,"@sentry/utils":319}],209:[function(require,module,exports){ 17126Object.defineProperty(exports, '__esModule', { value: true }); 17127 17128const core = require('@sentry/core'); 17129const utils = require('@sentry/utils'); 17130const express = require('./node/integrations/express.js'); 17131const postgres = require('./node/integrations/postgres.js'); 17132const mysql = require('./node/integrations/mysql.js'); 17133const mongo = require('./node/integrations/mongo.js'); 17134const prisma = require('./node/integrations/prisma.js'); 17135const graphql = require('./node/integrations/graphql.js'); 17136const apollo = require('./node/integrations/apollo.js'); 17137const lazy = require('./node/integrations/lazy.js'); 17138const browsertracing = require('./browser/browsertracing.js'); 17139const browserTracingIntegration = require('./browser/browserTracingIntegration.js'); 17140const request = require('./browser/request.js'); 17141const instrument = require('./browser/instrument.js'); 17142const fetch = require('./common/fetch.js'); 17143const extensions = require('./extensions.js'); 17144 17145 17146 17147exports.IdleTransaction = core.IdleTransaction; 17148exports.Span = core.Span; 17149exports.SpanStatus = core.SpanStatus; 17150exports.Transaction = core.Transaction; 17151exports.extractTraceparentData = core.extractTraceparentData; 17152exports.getActiveTransaction = core.getActiveTransaction; 17153exports.hasTracingEnabled = core.hasTracingEnabled; 17154exports.spanStatusfromHttpCode = core.spanStatusfromHttpCode; 17155exports.startIdleTransaction = core.startIdleTransaction; 17156exports.TRACEPARENT_REGEXP = utils.TRACEPARENT_REGEXP; 17157exports.stripUrlQueryAndFragment = utils.stripUrlQueryAndFragment; 17158exports.Express = express.Express; 17159exports.Postgres = postgres.Postgres; 17160exports.Mysql = mysql.Mysql; 17161exports.Mongo = mongo.Mongo; 17162exports.Prisma = prisma.Prisma; 17163exports.GraphQL = graphql.GraphQL; 17164exports.Apollo = apollo.Apollo; 17165exports.lazyLoadedNodePerformanceMonitoringIntegrations = lazy.lazyLoadedNodePerformanceMonitoringIntegrations; 17166exports.BROWSER_TRACING_INTEGRATION_ID = browsertracing.BROWSER_TRACING_INTEGRATION_ID; 17167exports.BrowserTracing = browsertracing.BrowserTracing; 17168exports.browserTracingIntegration = browserTracingIntegration.browserTracingIntegration; 17169exports.startBrowserTracingNavigationSpan = browserTracingIntegration.startBrowserTracingNavigationSpan; 17170exports.startBrowserTracingPageLoadSpan = browserTracingIntegration.startBrowserTracingPageLoadSpan; 17171exports.defaultRequestInstrumentationOptions = request.defaultRequestInstrumentationOptions; 17172exports.instrumentOutgoingRequests = request.instrumentOutgoingRequests; 17173exports.addClsInstrumentationHandler = instrument.addClsInstrumentationHandler; 17174exports.addFidInstrumentationHandler = instrument.addFidInstrumentationHandler; 17175exports.addLcpInstrumentationHandler = instrument.addLcpInstrumentationHandler; 17176exports.addPerformanceInstrumentationHandler = instrument.addPerformanceInstrumentationHandler; 17177exports.addTracingHeadersToFetchRequest = fetch.addTracingHeadersToFetchRequest; 17178exports.instrumentFetchRequest = fetch.instrumentFetchRequest; 17179exports.addExtensionMethods = extensions.addExtensionMethods; 17180 17181 17182},{"./browser/browserTracingIntegration.js":185,"./browser/browsertracing.js":186,"./browser/instrument.js":187,"./browser/request.js":190,"./common/fetch.js":207,"./extensions.js":208,"./node/integrations/apollo.js":210,"./node/integrations/express.js":211,"./node/integrations/graphql.js":212,"./node/integrations/lazy.js":213,"./node/integrations/mongo.js":214,"./node/integrations/mysql.js":215,"./node/integrations/postgres.js":216,"./node/integrations/prisma.js":217,"@sentry/core":250,"@sentry/utils":319}],210:[function(require,module,exports){ 17183var { 17184 _optionalChain 17185} = require('@sentry/utils'); 17186 17187Object.defineProperty(exports, '__esModule', { value: true }); 17188 17189const utils = require('@sentry/utils'); 17190const debugBuild = require('../../common/debug-build.js');
17191const nodeUtils = require('./utils/node-utils.js'); 17192 17193/** Tracing integration for Apollo */ 17194class Apollo { 17195 /** 17196 * @inheritDoc 17197 */ 17198 static __initStatic() {this.id = 'Apollo';} 17199 17200 /** 17201 * @inheritDoc 17202 */ 17203 17204 /** 17205 * @inheritDoc 17206 */ 17207 constructor( 17208 options = { 17209 useNestjs: false, 17210 }, 17211 ) { 17212 this.name = Apollo.id; 17213 this._useNest = !!options.useNestjs; 17214 } 17215 17216 /** @inheritdoc */ 17217 loadDependency() { 17218 if (this._useNest) { 17219 this._module = this._module || utils.loadModule('@nestjs/graphql'); 17220 } else { 17221 this._module = this._module || utils.loadModule('apollo-server-core'); 17222 } 17223 17224 return this._module; 17225 } 17226 17227 /** 17228 * @inheritDoc 17229 */ 17230 setupOnce(_, getCurrentHub) { 17231 if (nodeUtils.shouldDisableAutoInstrumentation(getCurrentHub)) { 17232 debugBuild.DEBUG_BUILD && utils.logger.log('Apollo Integration is skipped because of instrumenter configuration.'); 17233 return; 17234 } 17235 17236 if (this._useNest) { 17237 const pkg = this.loadDependency(); 17238 17239 if (!pkg) { 17240 debugBuild.DEBUG_BUILD && utils.logger.error('Apollo-NestJS Integration was unable to require @nestjs/graphql package.'); 17241 return; 17242 } 17243 17244 /** 17245 * Iterate over resolvers of NestJS ResolversExplorerService before schemas are constructed. 17246 */ 17247 utils.fill( 17248 pkg.GraphQLFactory.prototype, 17249 'mergeWithSchema', 17250 function (orig) { 17251 return function ( 17252 17253 ...args 17254 ) { 17255 utils.fill(this.resolversExplorerService, 'explore', function (orig) { 17256 return function () { 17257 const resolvers = utils.arrayify(orig.call(this)); 17258 17259 const instrumentedResolvers = instrumentResolvers(resolvers, getCurrentHub); 17260 17261 return instrumentedResolvers; 17262 }; 17263 }); 17264 17265 return orig.call(this, ...args); 17266 }; 17267 }, 17268 ); 17269 } else { 17270 const pkg = this.loadDependency(); 17271 17272 if (!pkg) { 17273 debugBuild.DEBUG_BUILD && utils.logger.error('Apollo Integration was unable to require apollo-server-core package.'); 17274 return; 17275 } 17276 17277 /** 17278 * Iterate over resolvers of the ApolloServer instance before schemas are constructed. 17279 */ 17280 utils.fill(pkg.ApolloServerBase.prototype, 'constructSchema', function (orig) { 17281 return function ( 17282 17283) { 17284 if (!this.config.resolvers) { 17285 if (debugBuild.DEBUG_BUILD) { 17286 if (this.config.schema) { 17287 utils.logger.warn( 17288 'Apollo integration is not able to trace `ApolloServer` instances constructed via `schema` property.' + 17289 'If you are using NestJS with Apollo, please use `Sentry.Integrations.Apollo({ useNestjs: true })` instead.', 17290 ); 17291 utils.logger.warn(); 17292 } else if (this.config.modules) { 17293 utils.logger.warn( 17294 'Apollo integration is not able to trace `ApolloServer` instances constructed via `modules` property.', 17295 ); 17296 } 17297 17298 utils.logger.error('Skipping tracing as no resolvers found on the `ApolloServer` instance.'); 17299 } 17300 17301 return orig.call(this); 17302 } 17303 17304 const resolvers = utils.arrayify(this.config.resolvers); 17305 17306 this.config.resolvers = instrumentResolvers(resolvers, getCurrentHub); 17307 17308 return orig.call(this); 17309 }; 17310 }); 17311 } 17312 } 17313}Apollo.__initStatic(); 17314 17315function instrumentResolvers(resolvers, getCurrentHub) { 17316 return resolvers.map(model => { 17317 Object.keys(model).forEach(resolverGroupName => { 17318 Object.keys(model[resolverGroupName]).forEach(resolverName => { 17319 if (typeof model[resolverGroupName][resolverName] !== 'function') { 17320 return; 17321 } 17322 17323 wrapResolver(model, resolverGroupName, resolverName, getCurrentHub); 17324 }); 17325 }); 17326 17327 return model; 17328 }); 17329} 17330 17331/** 17332 * Wrap a single resolver which can be a parent of other resolvers and/or db operations. 17333 */ 17334function wrapResolver( 17335 model, 17336 resolverGroupName, 17337 resolverName, 17338 getCurrentHub, 17339) { 17340 utils.fill(model[resolverGroupName], resolverName, function (orig) { 17341 return function ( ...args) { 17342 // eslint-disable-next-line deprecation/deprecation 17343 const scope = getCurrentHub().getScope(); 17344 // eslint-disable-next-line deprecation/deprecation 17345 const parentSpan = scope.getSpan(); 17346 // eslint-disable-next-line deprecation/deprecation 17347 const span = _optionalChain([parentSpan, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({ 17348 description: `${resolverGroupName}.${resolverName}`, 17349 op: 'graphql.resolve', 17350 origin: 'auto.graphql.apollo', 17351 })]); 17352 17353 const rv = orig.call(this, ...args); 17354 17355 if (utils.isThenable(rv)) { 17356 return rv.then((res) => { 17357 _optionalChain([span, 'optionalAccess', _4 => _4.end, 'call', _5 => _5()]); 17358 return res; 17359 }); 17360 } 17361 17362 _optionalChain([span, 'optionalAccess', _6 => _6.end, 'call', _7 => _7()]); 17363 17364 return rv; 17365 }; 17366 }); 17367} 17368 17369exports.Apollo = Apollo; 17370 17371 17372}
17372,{"../../common/debug-build.js":206,"./utils/node-utils.js":218,"@sentry/utils":319}],211:[function(require,module,exports){ 17373var { 17374 _optionalChain 17375} = require('@sentry/utils'); 17376 17377Object.defineProperty(exports, '__esModule', { value: true }); 17378 17379const core = require('@sentry/core'); 17380const utils = require('@sentry/utils'); 17381const debugBuild = require('../../common/debug-build.js'); 17382const nodeUtils = require('./utils/node-utils.js'); 17383 17384/* eslint-disable max-lines */ 17385 17386/** 17387 * Express integration 17388 * 17389 * Provides an request and error handler for Express framework as well as tracing capabilities 17390 */ 17391class Express { 17392 /** 17393 * @inheritDoc 17394 */ 17395 static __initStatic() {this.id = 'Express';} 17396 17397 /** 17398 * @inheritDoc 17399 */ 17400 17401 /** 17402 * Express App instance 17403 */ 17404 17405 /** 17406 * @inheritDoc 17407 */ 17408 constructor(options = {}) { 17409 this.name = Express.id; 17410 this._router = options.router || options.app; 17411 this._methods = (Array.isArray(options.methods) ? options.methods : []).concat('use'); 17412 } 17413 17414 /** 17415 * @inheritDoc 17416 */ 17417 setupOnce(_, getCurrentHub) { 17418 if (!this._router) { 17419 debugBuild.DEBUG_BUILD && utils.logger.error('ExpressIntegration is missing an Express instance'); 17420 return; 17421 } 17422 17423 if (nodeUtils.shouldDisableAutoInstrumentation(getCurrentHub)) { 17424 debugBuild.DEBUG_BUILD && utils.logger.log('Express Integration is skipped because of instrumenter configuration.'); 17425 return; 17426 } 17427 17428 instrumentMiddlewares(this._router, this._methods); 17429 instrumentRouter(this._router ); 17430 } 17431}Express.__initStatic(); 17432 17433/** 17434 * Wraps original middleware function in a tracing call, which stores the info about the call as a span, 17435 * and finishes it once the middleware is done invoking. 17436 * 17437 * Express middlewares have 3 various forms, thus we have to take care of all of them: 17438 * // sync 17439 * app.use(function (req, res) { ... }) 17440 * // async 17441 * app.use(function (req, res, next) { ... }) 17442 * // error handler 17443 * app.use(function (err, req, res, next) { ... }) 17444 * 17445 * They all internally delegate to the `router[method]` of the given application instance. 17446 */ 17447// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any 17448function wrap(fn, method) { 17449 const arity = fn.length; 17450 17451 switch (arity) { 17452 case 2: { 17453 return function ( req, res) { 17454 const transaction = res.__sentry_transaction; 17455 if (transaction) { 17456 // eslint-disable-next-line deprecation/deprecation 17457 const span = transaction.startChild({ 17458 description: fn.name, 17459 op: `middleware.express.${method}`, 17460 origin: 'auto.middleware.express', 17461 }); 17462 res.once('finish', () => { 17463 span.end(); 17464 }); 17465 } 17466 return fn.call(this, req, res); 17467 }; 17468 } 17469 case 3: { 17470 return function ( 17471 17472 req, 17473 res, 17474 next, 17475 ) { 17476 const transaction = res.__sentry_transaction; 17477 // eslint-disable-next-line deprecation/deprecation 17478 const span = _optionalChain([transaction, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({ 17479 description: fn.name, 17480 op: `middleware.express.${method}`, 17481 origin: 'auto.middleware.express', 17482 })]); 17483 fn.call(this, req, res, function ( ...args) { 17484 _optionalChain([span, 'optionalAccess', _4 => _4.end, 'call', _5 => _5()]); 17485 next.call(this, ...args); 17486 }); 17487 }; 17488 } 17489 case 4: { 17490 return function ( 17491 17492 err, 17493 req, 17494 res, 17495 next, 17496 ) { 17497 const transaction = res.__sentry_transaction; 17498 // eslint-disable-next-line deprecation/deprecation 17499 const span = _optionalChain([transaction, 'optionalAccess', _6 => _6.startChild, 'call', _7 => _7({ 17500 description: fn.name, 17501 op: `middleware.express.${method}`, 17502 origin: 'auto.middleware.express', 17503 })]); 17504 fn.call(this, err, req, res, function ( ...args) { 17505 _optionalChain([span, 'optionalAccess', _8 => _8.end, 'call', _9 => _9()]); 17506 next.call(this, ...args); 17507 }); 17508 }; 17509 } 17510 default: { 17511 throw new Error(`Express middleware takes 2-4 arguments. Got: ${arity}`); 17512 } 17513 } 17514} 17515 17516/** 17517 * Takes all the function arguments passed to the original `app` or `router` method, eg. `app.use` or `router.use` 17518 * and wraps every function, as well as array of functions with a call to our `wrap` method. 17519 * We have to take care of the arrays as well as iterate over all of the arguments, 17520 * as `app.use` can accept middlewares in few various forms. 17521 * 17522 * app.use([<path>], <fn>) 17523 * app.use([<path>], <fn>, ...<fn>) 17524 * app.use([<path>], ...<fn>[]) 17525 */ 17526function wrapMiddlewareArgs(args, method) { 17527 return args.map((arg) => { 17528 if (typeof arg === 'function') { 17529 return wrap(arg, method); 17530 } 17531 17532 if (Array.isArray(arg)) { 17533 return arg.map((a) => { 17534 if (typeof a === 'function') { 17535 return wrap(a, method); 17536 } 17537 return a; 17538 }); 17539 } 17540 17541 return arg; 17542 }); 17543} 17544 17545/** 17546 * Patches original router to utilize our tracing functionality 17547 */ 17548function patchMiddleware(router, method) { 17549 const originalCallback = router[method]; 17550 17551 router[method] = function (...args) { 17552 return originalCallback.call(this, ...wrapMiddlewareArgs(args, method)); 17553 }; 17554 17555 return router; 17556} 17557 17558/** 17559 * Patches original router methods 17560 */ 17561function instrumentMiddlewares(router, methods = []) { 17562 methods.forEach((method) => patchMiddleware(router, method)); 17563} 17564 17565/** 17566 * Patches the prototype of Express.Router to accumulate the resolved route 17567 * if a layer instance's `match` function was called and it returned a successful match. 17568 * 17569 * @see https://github.com/expressjs/express/blob/master/lib/router/index.js 17570 * 17571 * @param appOrRouter the router instance which can either be an app (i.e. top-level) or a (nested) router. 17572 */ 17573function instrumentRouter(appOrRouter) {
17574 // This is how we can distinguish between app and routers 17575 const isApp = 'settings' in appOrRouter; 17576 17577 // In case the app's top-level router hasn't been initialized yet, we have to do it now 17578 if (isApp && appOrRouter._router === undefined && appOrRouter.lazyrouter) { 17579 appOrRouter.lazyrouter(); 17580 } 17581 17582 const router = isApp ? appOrRouter._router : appOrRouter; 17583 17584 if (!router) { 17585 /* 17586 If we end up here, this means likely that this integration is used with Express 3 or Express 5. 17587 For now, we don't support these versions (3 is very old and 5 is still in beta). To support Express 5, 17588 we'd need to make more changes to the routing instrumentation because the router is no longer part of 17589 the Express core package but maintained in its own package. The new router has different function 17590 signatures and works slightly differently, demanding more changes than just taking the router from 17591 `app.router` instead of `app._router`. 17592 @see https://github.com/pillarjs/router 17593 17594 TODO: Proper Express 5 support 17595 */ 17596 debugBuild.DEBUG_BUILD && utils.logger.debug('Cannot instrument router for URL Parameterization (did not find a valid router).'); 17597 debugBuild.DEBUG_BUILD && utils.logger.debug('Routing instrumentation is currently only supported in Express 4.'); 17598 return; 17599 } 17600 17601 const routerProto = Object.getPrototypeOf(router) ; 17602 17603 const originalProcessParams = routerProto.process_params; 17604 routerProto.process_params = function process_params( 17605 layer, 17606 called, 17607 req, 17608 res, 17609 done, 17610 ) { 17611 // Base case: We're in the first part of the URL (thus we start with the root '/') 17612 if (!req._reconstructedRoute) { 17613 req._reconstructedRoute = ''; 17614 } 17615 17616 // If the layer's partial route has params, is a regex or an array, the route is stored in layer.route. 17617 const { layerRoutePath, isRegex, isArray, numExtraSegments } = getLayerRoutePathInfo(layer); 17618 17619 if (layerRoutePath || isRegex || isArray) { 17620 req._hasParameters = true; 17621 } 17622 17623 // Otherwise, the hardcoded path (i.e. a partial route without params) is stored in layer.path 17624 let partialRoute; 17625 17626 if (layerRoutePath) { 17627 partialRoute = layerRoutePath; 17628 } else { 17629 /** 17630 * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path 17631 * example: 17632 * original url: /api/v1/1234 17633 * prevent: /api/api/v1/:userId 17634 * router structure 17635 * /api -> middleware 17636 * /api/v1 -> middleware 17637 * /1234 -> endpoint with param :userId 17638 * final _reconstructedRoute is /api/v1/:userId 17639 */ 17640 partialRoute = preventDuplicateSegments(req.originalUrl, req._reconstructedRoute, layer.path) || ''; 17641 } 17642 17643 // Normalize the partial route so that it doesn't contain leading or trailing slashes 17644 // and exclude empty or '*' wildcard routes. 17645 // The exclusion of '*' routes is our best effort to not "pollute" the transaction name 17646 // with interim handlers (e.g. ones that check authentication or do other middleware stuff). 17647 // We want to end up with the parameterized URL of the incoming request without any extraneous path segments. 17648 const finalPartialRoute = partialRoute 17649 .split('/') 17650 .filter(segment => segment.length > 0 && (isRegex || isArray || !segment.includes('*'))) 17651 .join('/'); 17652 17653 // If we found a valid partial URL, we append it to the reconstructed route 17654 if (finalPartialRoute && finalPartialRoute.length > 0) { 17655 // If the partial route is from a regex route, we append a '/' to close the regex 17656 req._reconstructedRoute += `/${finalPartialRoute}${isRegex ? '/' : ''}`; 17657 } 17658 17659 // Now we check if we are in the "last" part of the route. We determine this by comparing the 17660 // number of URL segments from the original URL to that of our reconstructed parameterized URL. 17661 // If we've reached our final destination, we update the transaction name. 17662 const urlLength = utils.getNumberOfUrlSegments(utils.stripUrlQueryAndFragment(req.originalUrl || '')) + numExtraSegments; 17663 const routeLength = utils.getNumberOfUrlSegments(req._reconstructedRoute); 17664 17665 if (urlLength === routeLength) { 17666 if (!req._hasParameters) { 17667 if (req._reconstructedRoute !== req.originalUrl) { 17668 req._reconstructedRoute = req.originalUrl ? utils.stripUrlQueryAndFragment(req.originalUrl) : req.originalUrl; 17669 } 17670 } 17671 17672 const transaction = res.__sentry_transaction; 17673 const attributes = (transaction && core.spanToJSON(transaction).data) || {}; 17674 if (transaction && attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] !== 'custom') { 17675 // If the request URL is '/' or empty, the reconstructed route will be empty. 17676 // Therefore, we fall back to setting the final route to '/' in this case. 17677 const finalRoute = req._reconstructedRoute || '/'; 17678 17679 const [name, source] = utils.extractPathForTransaction(req, { path: true, method: true, customRoute: finalRoute }); 17680 transaction.updateName(name); 17681 transaction.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source); 17682 } 17683 } 17684 17685 return originalProcessParams.call(this, layer, called, req, res, done); 17686 }; 17687} 17688 17689/** 17690 * Recreate layer.route.path from layer.regexp and layer.keys. 17691 * Works until express.js used package [email protected] 17692 * or until layer.keys contain offset attribute 17693 * 17694 * @param layer the layer to extract the stringified route from 17695 * 17696 * @returns string in layer.route.path structure 'router/:pathParam' or undefined 17697 */ 17698const extractOriginalRoute = ( 17699 path, 17700 regexp, 17701 keys, 17702) => { 17703 if (!path || !regexp || !keys || Object.keys(keys).length === 0 || !_optionalChain([
vendor: 2,216 bytes, lines 17703-17773
17703keys, 'access', _10 => _10[0], 'optionalAccess', _11 => _11.offset])) { 17704 return undefined; 17705 } 17706 17707 const orderedKeys = keys.sort((a, b) => a.offset - b.offset); 17708 17709 // add d flag for getting indices from regexp result 17710 // eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor -- regexp comes from express.js 17711 const pathRegex = new RegExp(regexp, `${regexp.flags}d`); 17712 /** 17713 * use custom type cause of TS error with missing indices in RegExpExecArray 17714 */ 17715 const execResult = pathRegex.exec(path) ; 17716 17717 if (!execResult || !execResult.indices) { 17718 return undefined; 17719 } 17720 /** 17721 * remove first match from regex cause contain whole layer.path 17722 */ 17723 const [, ...paramIndices] = execResult.indices; 17724 17725 if (paramIndices.length !== orderedKeys.length) { 17726 return undefined; 17727 } 17728 let resultPath = path; 17729 let indexShift = 0; 17730 17731 /** 17732 * iterate param matches from regexp.exec 17733 */ 17734 paramIndices.forEach((item, index) => { 17735 /** check if offsets is define because in some cases regex d flag returns undefined */ 17736 if (item) { 17737 const [startOffset, endOffset] = item; 17738 /** 17739 * isolate part before param 17740 */ 17741 const substr1 = resultPath.substring(0, startOffset - indexShift); 17742 /** 17743 * define paramName as replacement in format :pathParam 17744 */ 17745 const replacement = `:${orderedKeys[index].name}`; 17746 17747 /** 17748 * isolate part after param 17749 */ 17750 const substr2 = resultPath.substring(endOffset - indexShift); 17751 17752 /** 17753 * recreate original path but with param replacement 17754 */ 17755 resultPath = substr1 + replacement + substr2; 17756 17757 /** 17758 * calculate new index shift after resultPath was modified 17759 */ 17760 indexShift = indexShift + (endOffset - startOffset - replacement.length); 17761 } 17762 }); 17763 17764 return resultPath; 17765}; 17766 17767/** 17768 * Extracts and stringifies the layer's route which can either be a string with parameters (`users/:id`), 17769 * a RegEx (`/test/`) or an array of strings and regexes (`['/path1', /\/path[2-5]/, /path/:id]`). Additionally 17770 * returns extra information about the route, such as if the route is defined as regex or as an array. 17771 * 17772 * @param layer the layer to extract the stringified route from 17773 *
17774 * @returns an object containing the stringified route, a flag determining if the route was a regex 17775 * and the number of extra segments to the matched path that are additionally in the route, 17776 * if the route was an array (defaults to 0). 17777 */ 17778function getLayerRoutePathInfo(layer) { 17779 let lrp = _optionalChain([layer, 'access', _12 => _12.route, 'optionalAccess', _13 => _13.path]); 17780 17781 const isRegex = utils.isRegExp(lrp); 17782 const isArray = Array.isArray(lrp); 17783 17784 if (!lrp) { 17785 // parse node.js major version 17786 // Next.js will complain if we directly use `proces.versions` here because of edge runtime. 17787 const [major] = (utils.GLOBAL_OBJ ).process.versions.node.split('.').map(Number); 17788 17789 // allow call extractOriginalRoute only if node version support Regex d flag, node 16+ 17790 if (major >= 16) { 17791 /** 17792 * If lrp does not exist try to recreate original layer path from route regexp 17793 */ 17794 lrp = extractOriginalRoute(layer.path, layer.regexp, layer.keys); 17795 } 17796 } 17797 17798 if (!lrp) { 17799 return { isRegex, isArray, numExtraSegments: 0 }; 17800 } 17801 17802 const numExtraSegments = isArray 17803 ? Math.max(getNumberOfArrayUrlSegments(lrp ) - utils.getNumberOfUrlSegments(layer.path || ''), 0) 17804 : 0; 17805 17806 const layerRoutePath = getLayerRoutePathString(isArray, lrp); 17807 17808 return { layerRoutePath, isRegex, isArray, numExtraSegments }; 17809} 17810 17811/** 17812 * Returns the number of URL segments in an array of routes 17813 * 17814 * Example: ['/api/test', /\/api\/post[0-9]/, '/users/:id/details`] -> 7 17815 */ 17816function getNumberOfArrayUrlSegments(routesArray) { 17817 return routesArray.reduce((accNumSegments, currentRoute) => { 17818 // array members can be a RegEx -> convert them toString 17819 return accNumSegments + utils.getNumberOfUrlSegments(currentRoute.toString()); 17820 }, 0); 17821} 17822 17823/** 17824 * Extracts and returns the stringified version of the layers route path 17825 * Handles route arrays (by joining the paths together) as well as RegExp and normal 17826 * string values (in the latter case the toString conversion is technically unnecessary but 17827 * it doesn't hurt us either). 17828 */ 17829function getLayerRoutePathString(isArray, lrp) { 17830 if (isArray) { 17831 return (lrp ).map(r => r.toString()).join(','); 17832 } 17833 return lrp && lrp.toString(); 17834} 17835 17836/** 17837 * remove duplicate segment contain in layerPath against reconstructedRoute, 17838 * and return only unique segment that can be added into reconstructedRoute 17839 */ 17840function preventDuplicateSegments( 17841 originalUrl, 17842 reconstructedRoute, 17843 layerPath, 17844) {
17845 // filter query params 17846 const normalizeURL = utils.stripUrlQueryAndFragment(originalUrl || ''); 17847 const originalUrlSplit = _optionalChain([normalizeURL, 'optionalAccess', _14 => _14.split, 'call', _15 => _15('/'), 'access', _16 => _16.filter, 'call', _17 => _17(v => !!v)]); 17848 let tempCounter = 0; 17849 const currentOffset = _optionalChain([reconstructedRoute, 'optionalAccess', _18 => _18.split, 'call', _19 => _19('/'), 'access', _20 => _20.filter, 'call', _21 => _21(v => !!v), 'access', _22 => _22.length]) || 0; 17850 const result = _optionalChain([layerPath 17851, 'optionalAccess', _23 => _23.split, 'call', _24 => _24('/') 17852, 'access', _25 => _25.filter, 'call', _26 => _26(segment => { 17853 if (_optionalChain([originalUrlSplit, 'optionalAccess', _27 => _27[currentOffset + tempCounter]]) === segment) { 17854 tempCounter += 1; 17855 return true; 17856 } 17857 return false; 17858 }) 17859, 'access', _28 => _28.join, 'call', _29 => _29('/')]); 17860 return result; 17861} 17862 17863exports.Express = Express; 17864exports.extractOriginalRoute = extractOriginalRoute; 17865exports.preventDuplicateSegments = preventDuplicateSegments; 17866 17867 17868},{"../../common/debug-build.js":206,"./utils/node-utils.js":218,"@sentry/core":250,"@sentry/utils":319}],212:[function(require,module,exports){ 17869var { 17870 _optionalChain 17871} = require('@sentry/utils'); 17872 17873Object.defineProperty(exports, '__esModule', { value: true }); 17874 17875const utils = require('@sentry/utils'); 17876const debugBuild = require('../../common/debug-build.js'); 17877const nodeUtils = require('./utils/node-utils.js'); 17878 17879/** Tracing integration for graphql package */ 17880class GraphQL { 17881 /** 17882 * @inheritDoc 17883 */ 17884 static __initStatic() {this.id = 'GraphQL';} 17885 17886 /** 17887 * @inheritDoc 17888 */ 17889 17890 constructor() { 17891 this.name = GraphQL.id; 17892 } 17893 17894 /** @inheritdoc */ 17895 loadDependency() { 17896 return (this._module = this._module || utils.loadModule('graphql/execution/execute.js')); 17897 } 17898 17899 /** 17900 * @inheritDoc 17901 */ 17902 setupOnce(_, getCurrentHub) { 17903 if (nodeUtils.shouldDisableAutoInstrumentation(getCurrentHub)) { 17904 debugBuild.DEBUG_BUILD && utils.logger.log('GraphQL Integration is skipped because of instrumenter configuration.'); 17905 return; 17906 } 17907 17908 const pkg = this.loadDependency(); 17909 17910 if (!pkg) { 17911 debugBuild.DEBUG_BUILD && utils.logger.error('GraphQL Integration was unable to require graphql/execution package.'); 17912 return; 17913 } 17914 17915 utils.fill(pkg, 'execute', function (orig) { 17916 return function ( ...args) { 17917 // eslint-disable-next-line deprecation/deprecation 17918 const scope = getCurrentHub().getScope(); 17919 // eslint-disable-next-line deprecation/deprecation 17920 const parentSpan = scope.getSpan(); 17921 17922 // eslint-disable-next-line deprecation/deprecation 17923 const span = _optionalChain([parentSpan, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({ 17924 description: 'execute', 17925 op: 'graphql.execute', 17926 origin: 'auto.graphql.graphql', 17927 })]); 17928 17929 // eslint-disable-next-line deprecation/deprecation 17930 _optionalChain([scope, 'optionalAccess', _4 => _4.setSpan, 'call', _5 => _5(span)]); 17931 17932 const rv = orig.call(this, ...args); 17933 17934 if (utils.isThenable(rv)) { 17935 return rv.then((res) => { 17936 _optionalChain([span, 'optionalAccess', _6 => _6.end, 'call', _7 => _7()]); 17937 // eslint-disable-next-line deprecation/deprecation 17938 _optionalChain([scope, 'optionalAccess', _8 => _8.setSpan, 'call', _9 => _9(parentSpan)]); 17939 17940 return res; 17941 }); 17942 } 17943 17944 _optionalChain([span, 'optionalAccess', _10 => _10.end, 'call', _11 => _11()]); 17945 // eslint-disable-next-line deprecation/deprecation 17946 _optionalChain([scope, 'optionalAccess', _12 => _12.setSpan, 'call', _13 => _13(parentSpan)]); 17947 return rv; 17948 }; 17949 }); 17950 } 17951}GraphQL.__initStatic(); 17952 17953exports.GraphQL = GraphQL; 17954 17955 17956},{"../../common/debug-build.js":206,"./utils/node-utils.js":218,"@sentry/utils":319}],213:[function(require,module,exports){ 17957Object.defineProperty(exports, '__esModule', { value: true }); 17958 17959const utils = require('@sentry/utils'); 17960 17961const lazyLoadedNodePerformanceMonitoringIntegrations = [ 17962 () => { 17963 const integration = utils.dynamicRequire(module, './apollo') 17964 17965; 17966 return new integration.Apollo(); 17967 }, 17968 () => { 17969 const integration = utils.dynamicRequire(module, './apollo') 17970 17971; 17972 return new integration.Apollo({ useNestjs: true }); 17973 }, 17974 () => { 17975 const integration = utils.dynamicRequire(module, './graphql') 17976 17977; 17978 return new integration.GraphQL(); 17979 }, 17980 () => { 17981 const integration = utils.dynamicRequire(module, './mongo') 17982 17983; 17984 return new integration.Mongo(); 17985 }, 17986 () => { 17987 const integration = utils.dynamicRequire(module, './mongo') 17988 17989; 17990 return new integration.Mongo({ mongoose: true }); 17991 }, 17992 () => { 17993 const integration = utils.dynamicRequire(module, './mysql') 17994 17995; 17996 return new integration.Mysql(); 17997 }, 17998 () => { 17999 const integration = utils.dynamicRequire(module, './postgres') 18000 18001; 18002 return new integration.Postgres(); 18003 }, 18004]; 18005 18006exports.lazyLoadedNodePerformanceMonitoringIntegrations = lazyLoadedNodePerformanceMonitoringIntegrations; 18007 18008 18009},{"@sentry/utils":319}],214:[function(require,module,exports){ 18010var { 18011 _optionalChain 18012} = require('@sentry/utils'); 18013 18014Object.defineProperty(exports, '__esModule', { value: true }); 18015 18016const utils = require('@sentry/utils'); 18017const debugBuild = require('../../common/debug-build.js');
vendor: 4,128 bytes, lines 18018-18118
18018const nodeUtils = require('./utils/node-utils.js'); 18019 18020// This allows us to use the same array for both defaults options and the type itself. 18021// (note `as const` at the end to make it a union of string literal types (i.e. "a" | "b" | ... ) 18022// and not just a string[]) 18023 18024const OPERATIONS = [ 18025 'aggregate', // aggregate(pipeline, options, callback) 18026 'bulkWrite', // bulkWrite(operations, options, callback) 18027 'countDocuments', // countDocuments(query, options, callback) 18028 'createIndex', // createIndex(fieldOrSpec, options, callback) 18029 'createIndexes', // createIndexes(indexSpecs, options, callback) 18030 'deleteMany', // deleteMany(filter, options, callback) 18031 'deleteOne', // deleteOne(filter, options, callback) 18032 'distinct', // distinct(key, query, options, callback) 18033 'drop', // drop(options, callback) 18034 'dropIndex', // dropIndex(indexName, options, callback) 18035 'dropIndexes', // dropIndexes(options, callback) 18036 'estimatedDocumentCount', // estimatedDocumentCount(options, callback) 18037 'find', // find(query, options, callback) 18038 'findOne', // findOne(query, options, callback) 18039 'findOneAndDelete', // findOneAndDelete(filter, options, callback) 18040 'findOneAndReplace', // findOneAndReplace(filter, replacement, options, callback) 18041 'findOneAndUpdate', // findOneAndUpdate(filter, update, options, callback) 18042 'indexes', // indexes(options, callback) 18043 'indexExists', // indexExists(indexes, options, callback) 18044 'indexInformation', // indexInformation(options, callback) 18045 'initializeOrderedBulkOp', // initializeOrderedBulkOp(options, callback) 18046 'insertMany', // insertMany(docs, options, callback) 18047 'insertOne', // insertOne(doc, options, callback) 18048 'isCapped', // isCapped(options, callback) 18049 'mapReduce', // mapReduce(map, reduce, options, callback) 18050 'options', // options(options, callback) 18051 'parallelCollectionScan', // parallelCollectionScan(options, callback) 18052 'rename', // rename(newName, options, callback) 18053 'replaceOne', // replaceOne(filter, doc, options, callback) 18054 'stats', // stats(options, callback) 18055 'updateMany', // updateMany(filter, update, options, callback) 18056 'updateOne', // updateOne(filter, update, options, callback) 18057] ; 18058 18059// All of the operations above take `options` and `callback` as their final parameters, but some of them 18060// take additional parameters as well. For those operations, this is a map of 18061// { <operation name>: [<names of additional parameters>] }, as a way to know what to call the operation's 18062// positional arguments when we add them to the span's `data` object later 18063const OPERATION_SIGNATURES 18064 18065 = { 18066 // aggregate intentionally not included because `pipeline` arguments are too complex to serialize well 18067 // see https://github.com/getsentry/sentry-javascript/pull/3102 18068 bulkWrite: ['operations'], 18069 countDocuments: ['query'], 18070 createIndex: ['fieldOrSpec'], 18071 createIndexes: ['indexSpecs'], 18072 deleteMany: ['filter'], 18073 deleteOne: ['filter'], 18074 distinct: ['key', 'query'], 18075 dropIndex: ['indexName'], 18076 find: ['query'], 18077 findOne: ['query'], 18078 findOneAndDelete: ['filter'], 18079 findOneAndReplace: ['filter', 'replacement'], 18080 findOneAndUpdate: ['filter', 'update'], 18081 indexExists: ['indexes'], 18082 insertMany: ['docs'], 18083 insertOne: ['doc'], 18084 mapReduce: ['map', 'reduce'], 18085 rename: ['newName'], 18086 replaceOne: ['filter', 'doc'], 18087 updateMany: ['filter', 'update'], 18088 updateOne: ['filter', 'update'], 18089}; 18090 18091function isCursor(maybeCursor) { 18092 return maybeCursor && typeof maybeCursor === 'object' && maybeCursor.once && typeof maybeCursor.once === 'function'; 18093} 18094 18095/** Tracing integration for mongo package */ 18096class Mongo { 18097 /** 18098 * @inheritDoc 18099 */ 18100 static __initStatic() {this.id = 'Mongo';} 18101 18102 /** 18103 * @inheritDoc 18104 */ 18105 18106 /** 18107 * @inheritDoc 18108 */ 18109 constructor(options = {}) { 18110 this.name = Mongo.id; 18111 this._operations = Array.isArray(options.operations) ? options.operations : (OPERATIONS ); 18112 this._describeOperations = 'describeOperations' in options ? options.describeOperations : true; 18113 this._useMongoose = !!options.useMongoose; 18114 } 18115 18116 /** @inheritdoc */ 18117 loadDependency() { 18118 const moduleName = this._useMongoose ? 'mongoose' : 'mongodb';
18119 return (this._module = this._module || utils.loadModule(moduleName)); 18120 } 18121 18122 /** 18123 * @inheritDoc 18124 */ 18125 setupOnce(_, getCurrentHub) { 18126 if (nodeUtils.shouldDisableAutoInstrumentation(getCurrentHub)) { 18127 debugBuild.DEBUG_BUILD && utils.logger.log('Mongo Integration is skipped because of instrumenter configuration.'); 18128 return; 18129 } 18130 18131 const pkg = this.loadDependency(); 18132 18133 if (!pkg) { 18134 const moduleName = this._useMongoose ? 'mongoose' : 'mongodb'; 18135 debugBuild.DEBUG_BUILD && utils.logger.error(`Mongo Integration was unable to require \`${moduleName}\` package.`); 18136 return; 18137 } 18138 18139 this._instrumentOperations(pkg.Collection, this._operations, getCurrentHub); 18140 } 18141 18142 /** 18143 * Patches original collection methods 18144 */ 18145 _instrumentOperations(collection, operations, getCurrentHub) { 18146 operations.forEach((operation) => this._patchOperation(collection, operation, getCurrentHub)); 18147 } 18148 18149 /** 18150 * Patches original collection to utilize our tracing functionality 18151 */ 18152 _patchOperation(collection, operation, getCurrentHub) { 18153 if (!(operation in collection.prototype)) return; 18154 18155 const getSpanContext = this._getSpanContextFromOperationArguments.bind(this); 18156 18157 utils.fill(collection.prototype, operation, function (orig) { 18158 return function ( ...args) { 18159 const lastArg = args[args.length - 1]; 18160 // eslint-disable-next-line deprecation/deprecation 18161 const hub = getCurrentHub(); 18162 // eslint-disable-next-line deprecation/deprecation 18163 const scope = hub.getScope(); 18164 // eslint-disable-next-line deprecation/deprecation 18165 const client = hub.getClient(); 18166 // eslint-disable-next-line deprecation/deprecation 18167 const parentSpan = scope.getSpan(); 18168 18169 const sendDefaultPii = _optionalChain([client, 'optionalAccess', _2 => _2.getOptions, 'call', _3 => _3(), 'access', _4 => _4.sendDefaultPii]); 18170 18171 // Check if the operation was passed a callback. (mapReduce requires a different check, as 18172 // its (non-callback) arguments can also be functions.) 18173 if (typeof lastArg !== 'function' || (operation === 'mapReduce' && args.length === 2)) { 18174 // eslint-disable-next-line deprecation/deprecation 18175 const span = _optionalChain([parentSpan, 'optionalAccess', _5 => _5.startChild, 'call', _6 => _6(getSpanContext(this, operation, args, sendDefaultPii))]); 18176 const maybePromiseOrCursor = orig.call(this, ...args); 18177 18178 if (utils.isThenable(maybePromiseOrCursor)) { 18179 return maybePromiseOrCursor.then((res) => { 18180 _optionalChain([span, 'optionalAccess', _7 => _7.end, 'call', _8 => _8()]); 18181 return res; 18182 }); 18183 } 18184 // If the operation returns a Cursor 18185 // we need to attach a listener to it to finish the span when the cursor is closed. 18186 else if (isCursor(maybePromiseOrCursor)) { 18187 const cursor = maybePromiseOrCursor ; 18188 18189 try { 18190 cursor.once('close', () => { 18191 _optionalChain([span, 'optionalAccess', _9 => _9.end, 'call', _10 => _10()]); 18192 }); 18193 } catch (e) { 18194 // If the cursor is already closed, `once` will throw an error. In that case, we can 18195 // finish the span immediately. 18196 _optionalChain([span, 'optionalAccess', _11 => _11.end, 'call', _12 => _12()]); 18197 } 18198 18199 return cursor; 18200 } else { 18201 _optionalChain([span, 'optionalAccess', _13 => _13.end, 'call', _14 => _14()]); 18202 return maybePromiseOrCursor; 18203 } 18204 } 18205 18206 // eslint-disable-next-line deprecation/deprecation 18207 const span = _optionalChain([parentSpan, 'optionalAccess', _15 => _15.startChild, 'call', _16 => _16(getSpanContext(this, operation, args.slice(0, -1)))]); 18208 18209 return orig.call(this, ...args.slice(0, -1), function (err, result) { 18210 _optionalChain([span, 'optionalAccess', _17 => _17.end, 'call', _18 => _18()]); 18211 lastArg(err, result); 18212 }); 18213 }; 18214 }); 18215 } 18216 18217 /** 18218 * Form a SpanContext based on the user input to a given operation. 18219 */ 18220 _getSpanContextFromOperationArguments( 18221 collection, 18222 operation, 18223 args, 18224 sendDefaultPii = false, 18225 ) { 18226 const data = { 18227 'db.system': 'mongodb', 18228 'db.name': collection.dbName, 18229 'db.operation': operation, 18230 'db.mongodb.collection': collection.collectionName, 18231 }; 18232 const spanContext = { 18233 op: 'db', 18234 // TODO v8: Use `${collection.collectionName}.${operation}` 18235 origin: 'auto.db.mongo', 18236 description: operation, 18237 data, 18238 }; 18239 18240 // If the operation takes no arguments besides `options` and `callback`, or if argument 18241 // collection is disabled for this operation, just return early.
18242 const signature = OPERATION_SIGNATURES[operation]; 18243 const shouldDescribe = Array.isArray(this._describeOperations) 18244 ? this._describeOperations.includes(operation) 18245 : this._describeOperations; 18246 18247 if (!signature || !shouldDescribe || !sendDefaultPii) { 18248 return spanContext; 18249 } 18250 18251 try { 18252 // Special case for `mapReduce`, as the only one accepting functions as arguments. 18253 if (operation === 'mapReduce') { 18254 const [map, reduce] = args ; 18255 data[signature[0]] = typeof map === 'string' ? map : map.name || '<anonymous>'; 18256 data[signature[1]] = typeof reduce === 'string' ? reduce : reduce.name || '<anonymous>'; 18257 } else { 18258 for (let i = 0; i < signature.length; i++) { 18259 data[`db.mongodb.${signature[i]}`] = JSON.stringify(args[i]); 18260 } 18261 } 18262 } catch (_oO) { 18263 // no-empty 18264 } 18265 18266 return spanContext; 18267 } 18268}Mongo.__initStatic(); 18269 18270exports.Mongo = Mongo; 18271 18272 18273},{"../../common/debug-build.js":206,"./utils/node-utils.js":218,"@sentry/utils":319}],215:[function(require,module,exports){ 18274var { 18275 _optionalChain 18276} = require('@sentry/utils'); 18277 18278Object.defineProperty(exports, '__esModule', { value: true }); 18279 18280const utils = require('@sentry/utils'); 18281const debugBuild = require('../../common/debug-build.js'); 18282const nodeUtils = require('./utils/node-utils.js'); 18283 18284/** Tracing integration for node-mysql package */ 18285class Mysql { 18286 /** 18287 * @inheritDoc 18288 */ 18289 static __initStatic() {this.id = 'Mysql';} 18290 18291 /** 18292 * @inheritDoc 18293 */ 18294 18295 constructor() { 18296 this.name = Mysql.id; 18297 } 18298 18299 /** @inheritdoc */ 18300 loadDependency() { 18301 return (this._module = this._module || utils.loadModule('mysql/lib/Connection.js')); 18302 } 18303 18304 /** 18305 * @inheritDoc 18306 */ 18307 setupOnce(_, getCurrentHub) { 18308 if (nodeUtils.shouldDisableAutoInstrumentation(getCurrentHub)) { 18309 debugBuild.DEBUG_BUILD && utils.logger.log('Mysql Integration is skipped because of instrumenter configuration.'); 18310 return; 18311 } 18312 18313 const pkg = this.loadDependency(); 18314 18315 if (!pkg) { 18316 debugBuild.DEBUG_BUILD && utils.logger.error('Mysql Integration was unable to require `mysql` package.'); 18317 return; 18318 } 18319 18320 let mySqlConfig = undefined; 18321 18322 try { 18323 pkg.prototype.connect = new Proxy(pkg.prototype.connect, { 18324 apply(wrappingTarget, thisArg, args) { 18325 if (!mySqlConfig) { 18326 mySqlConfig = thisArg.config; 18327 } 18328 return wrappingTarget.apply(thisArg, args); 18329 }, 18330 }); 18331 } catch (e) { 18332 debugBuild.DEBUG_BUILD && utils.logger.error('Mysql Integration was unable to instrument `mysql` config.'); 18333 } 18334 18335 function spanDataFromConfig() { 18336 if (!mySqlConfig) { 18337 return {}; 18338 } 18339 return { 18340 'server.address': mySqlConfig.host, 18341 'server.port': mySqlConfig.port, 18342 'db.user': mySqlConfig.user, 18343 }; 18344 } 18345 18346 function finishSpan(span) { 18347 if (!span) { 18348 return; 18349 } 18350 18351 const data = spanDataFromConfig(); 18352 Object.keys(data).forEach(key => { 18353 span.setAttribute(key, data[key]); 18354 }); 18355 18356 span.end(); 18357 } 18358 18359 // The original function will have one of these signatures: 18360 // function (callback) => void 18361 // function (options, callback) => void 18362 // function (options, values, callback) => void 18363 utils.fill(pkg, 'createQuery', function (orig) { 18364 return function ( options, values, callback) { 18365 // eslint-disable-next-line deprecation/deprecation 18366 const scope = getCurrentHub().getScope(); 18367 // eslint-disable-next-line deprecation/deprecation 18368 const parentSpan = scope.getSpan(); 18369 18370 // eslint-disable-next-line deprecation/deprecation 18371 const span = _optionalChain([parentSpan, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({ 18372 description: typeof options === 'string' ? options : (options ).sql, 18373 op: 'db', 18374 origin: 'auto.db.mysql', 18375 data: { 18376 'db.system': 'mysql', 18377 }, 18378 })]); 18379 18380 if (typeof callback === 'function') { 18381 return orig.call(this, options, values, function (err, result, fields) { 18382 finishSpan(span); 18383 callback(err, result, fields); 18384 }); 18385 } 18386 18387 if (typeof values === 'function') { 18388 return orig.call(this, options, function (err, result, fields) { 18389 finishSpan(span); 18390 values(err, result, fields); 18391 }); 18392 } 18393 18394 // streaming, no callback! 18395 const query = orig.call(this, options, values) ; 18396 18397 query.on('end', () => { 18398 finishSpan(span); 18399 }); 18400 18401 return query; 18402 }; 18403 }); 18404 } 18405}Mysql.__initStatic(); 18406 18407exports.Mysql = Mysql; 18408 18409 18410}
18410,{"../../common/debug-build.js":206,"./utils/node-utils.js":218,"@sentry/utils":319}],216:[function(require,module,exports){ 18411var { 18412 _optionalChain 18413} = require('@sentry/utils'); 18414 18415Object.defineProperty(exports, '__esModule', { value: true }); 18416 18417const utils = require('@sentry/utils'); 18418const debugBuild = require('../../common/debug-build.js'); 18419const nodeUtils = require('./utils/node-utils.js'); 18420 18421/** Tracing integration for node-postgres package */ 18422class Postgres { 18423 /** 18424 * @inheritDoc 18425 */ 18426 static __initStatic() {this.id = 'Postgres';} 18427 18428 /** 18429 * @inheritDoc 18430 */ 18431 18432 constructor(options = {}) { 18433 this.name = Postgres.id; 18434 this._usePgNative = !!options.usePgNative; 18435 this._module = options.module; 18436 } 18437 18438 /** @inheritdoc */ 18439 loadDependency() { 18440 return (this._module = this._module || utils.loadModule('pg')); 18441 } 18442 18443 /** 18444 * @inheritDoc 18445 */ 18446 setupOnce(_, getCurrentHub) { 18447 if (nodeUtils.shouldDisableAutoInstrumentation(getCurrentHub)) { 18448 debugBuild.DEBUG_BUILD && utils.logger.log('Postgres Integration is skipped because of instrumenter configuration.'); 18449 return; 18450 } 18451 18452 const pkg = this.loadDependency(); 18453 18454 if (!pkg) { 18455 debugBuild.DEBUG_BUILD && utils.logger.error('Postgres Integration was unable to require `pg` package.'); 18456 return; 18457 } 18458 18459 const Client = this._usePgNative ? _optionalChain([pkg, 'access', _2 => _2.native, 'optionalAccess', _3 => _3.Client]) : pkg.Client; 18460 18461 if (!Client) { 18462 debugBuild.DEBUG_BUILD && utils.logger.error("Postgres Integration was unable to access 'pg-native' bindings."); 18463 return; 18464 } 18465 18466 /** 18467 * function (query, callback) => void 18468 * function (query, params, callback) => void 18469 * function (query) => Promise 18470 * function (query, params) => Promise 18471 * function (pg.Cursor) => pg.Cursor 18472 */ 18473 utils.fill(Client.prototype, 'query', function (orig) { 18474 return function ( config, values, callback) { 18475 // eslint-disable-next-line deprecation/deprecation 18476 const scope = getCurrentHub().getScope(); 18477 // eslint-disable-next-line deprecation/deprecation 18478 const parentSpan = scope.getSpan(); 18479 18480 const data = { 18481 'db.system': 'postgresql', 18482 }; 18483 18484 try { 18485 if (this.database) { 18486 data['db.name'] = this.database; 18487 } 18488 if (this.host) { 18489 data['server.address'] = this.host; 18490 } 18491 if (this.port) { 18492 data['server.port'] = this.port; 18493 } 18494 if (this.user) { 18495 data['db.user'] = this.user; 18496 } 18497 } catch (e) { 18498 // ignore 18499 } 18500 18501 // eslint-disable-next-line deprecation/deprecation 18502 const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({ 18503 description: typeof config === 'string' ? config : (config ).text, 18504 op: 'db', 18505 origin: 'auto.db.postgres', 18506 data, 18507 })]); 18508 18509 if (typeof callback === 'function') { 18510 return orig.call(this, config, values, function (err, result) { 18511 _optionalChain([span, 'optionalAccess', _6 => _6.end, 'call', _7 => _7()]); 18512 callback(err, result); 18513 }); 18514 } 18515 18516 if (typeof values === 'function') { 18517 return orig.call(this, config, function (err, result) { 18518 _optionalChain([span, 'optionalAccess', _8 => _8.end, 'call', _9 => _9()]); 18519 values(err, result); 18520 }); 18521 } 18522 18523 const rv = typeof values !== 'undefined' ? orig.call(this, config, values) : orig.call(this, config); 18524 18525 if (utils.isThenable(rv)) { 18526 return rv.then((res) => { 18527 _optionalChain([span, 'optionalAccess', _10 => _10.end, 'call', _11 => _11()]); 18528 return res; 18529 }); 18530 } 18531 18532 _optionalChain([span, 'optionalAccess', _12 => _12.end, 'call', _13 => _13()]); 18533 return rv; 18534 }; 18535 }); 18536 } 18537}Postgres.__initStatic(); 18538 18539exports.Postgres = Postgres; 18540 18541 18542},{"../../common/debug-build.js":206,"./utils/node-utils.js":218,"@sentry/utils":319}],217:[function(require,module,exports){ 18543Object.defineProperty(exports, '__esModule', { value: true }); 18544 18545const core = require('@sentry/core'); 18546const utils = require('@sentry/utils'); 18547const debugBuild = require('../../common/debug-build.js');
18548const nodeUtils = require('./utils/node-utils.js'); 18549 18550function isValidPrismaClient(possibleClient) { 18551 return !!possibleClient && !!(possibleClient )['$use']; 18552} 18553 18554/** Tracing integration for @prisma/client package */ 18555class Prisma { 18556 /** 18557 * @inheritDoc 18558 */ 18559 static __initStatic() {this.id = 'Prisma';} 18560 18561 /** 18562 * @inheritDoc 18563 */ 18564 18565 /** 18566 * @inheritDoc 18567 */ 18568 constructor(options = {}) { 18569 this.name = Prisma.id; 18570 18571 // We instrument the PrismaClient inside the constructor and not inside `setupOnce` because in some cases of server-side 18572 // bundling (Next.js) multiple Prisma clients can be instantiated, even though users don't intend to. When instrumenting 18573 // in setupOnce we can only ever instrument one client. 18574 // https://github.com/getsentry/sentry-javascript/issues/7216#issuecomment-1602375012 18575 // In the future we might explore providing a dedicated PrismaClient middleware instead of this hack. 18576 if (isValidPrismaClient(options.client) && !options.client._sentryInstrumented) { 18577 // eslint-disable-next-line @typescript-eslint/no-explicit-any 18578 utils.addNonEnumerableProperty(options.client , '_sentryInstrumented', true); 18579 18580 const clientData = {}; 18581 try { 18582 const engineConfig = (options.client )._engineConfig; 18583 if (engineConfig) { 18584 const { activeProvider, clientVersion } = engineConfig; 18585 if (activeProvider) { 18586 clientData['db.system'] = activeProvider; 18587 } 18588 if (clientVersion) { 18589 clientData['db.prisma.version'] = clientVersion; 18590 } 18591 } 18592 } catch (e) { 18593 // ignore 18594 } 18595 18596 options.client.$use((params, next) => { 18597 // eslint-disable-next-line deprecation/deprecation 18598 if (nodeUtils.shouldDisableAutoInstrumentation(core.getCurrentHub)) { 18599 return next(params); 18600 } 18601 18602 const action = params.action; 18603 const model = params.model; 18604 18605 return core.startSpan( 18606 { 18607 name: model ? `${model} ${action}` : action, 18608 onlyIfParent: true, 18609 op: 'db.prisma', 18610 attributes: { 18611 [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.prisma', 18612 }, 18613 data: { ...clientData, 'db.operation': action }, 18614 }, 18615 () => next(params), 18616 ); 18617 }); 18618 } else { 18619 debugBuild.DEBUG_BUILD && 18620 utils.logger.warn('Unsupported Prisma client provided to PrismaIntegration. Provided client:', options.client); 18621 } 18622 } 18623 18624 /** 18625 * @inheritDoc 18626 */ 18627 setupOnce() { 18628 // Noop - here for backwards compatibility 18629 } 18630} Prisma.__initStatic(); 18631 18632exports.Prisma = Prisma; 18633 18634 18635},{"../../common/debug-build.js":206,"./utils/node-utils.js":218,"@sentry/core":250,"@sentry/utils":319}],218:[function(require,module,exports){ 18636var { 18637 _optionalChain 18638} = require('@sentry/utils'); 18639 18640Object.defineProperty(exports, '__esModule', { value: true }); 18641 18642/** 18643 * Check if Sentry auto-instrumentation should be disabled. 18644 * 18645 * @param getCurrentHub A method to fetch the current hub 18646 * @returns boolean 18647 */ 18648function shouldDisableAutoInstrumentation(getCurrentHub) { 18649 // eslint-disable-next-line deprecation/deprecation 18650 const clientOptions = _optionalChain([getCurrentHub, 'call', _ => _(), 'access', _2 => _2.getClient, 'call', _3 => _3(), 'optionalAccess', _4 => _4.getOptions, 'call', _5 => _5()]); 18651 const instrumenter = _optionalChain([clientOptions, 'optionalAccess', _6 => _6.instrumenter]) || 'sentry'; 18652 18653 return instrumenter !== 'sentry'; 18654} 18655 18656exports.shouldDisableAutoInstrumentation = shouldDisableAutoInstrumentation; 18657 18658 18659},{"@sentry/utils":319}],219:[function(require,module,exports){ 18660Object.defineProperty(exports, '__esModule', { value: true }); 18661 18662const core = require('@sentry/core'); 18663const utils = require('@sentry/utils'); 18664const debugBuild = require('./debug-build.js'); 18665const eventbuilder = require('./eventbuilder.js'); 18666const helpers = require('./helpers.js'); 18667const userfeedback = require('./userfeedback.js'); 18668 18669/** 18670 * Configuration options for the Sentry Browser SDK. 18671 * @see @sentry/types Options for more information. 18672 */ 18673 18674/** 18675 * The Sentry Browser SDK Client. 18676 * 18677 * @see BrowserOptions for documentation on configuration options. 18678 * @see SentryClient for usage documentation. 18679 */ 18680class BrowserClient extends core.BaseClient { 18681 /** 18682 * Creates a new Browser SDK instance. 18683 * 18684 * @param options Configuration options for this SDK. 18685 */ 18686 constructor(options) { 18687 const sdkSource = helpers.WINDOW.SENTRY_SDK_SOURCE || utils.getSDKSource(); 18688 core.applySdkMetadata(options, 'browser', ['browser'], sdkSource); 18689 18690 super(options); 18691 18692 if (options.sendClientReports && helpers.WINDOW.document) { 18693 helpers.WINDOW.document.addEventListener('visibilitychange', () => { 18694 if (helpers.WINDOW.document.visibilityState === 'hidden') { 18695 this._flushOutcomes(); 18696 } 18697 }); 18698 } 18699 } 18700 18701 /** 18702 * @inheritDoc 18703 */ 18704 eventFromException(exception, hint) { 18705 return eventbuilder.eventFromException(this._options.stackParser, exception, hint, this._options.attachStacktrace); 18706 } 18707 18708 /** 18709 * @inheritDoc 18710 */ 18711 eventFromMessage( 18712 message, 18713 // eslint-disable-next-line deprecation/deprecation 18714 level = 'info', 18715 hint, 18716 ) { 18717 return eventbuilder.eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace); 18718 } 18719 18720 /** 18721 * Sends user feedback to Sentry. 18722 */ 18723 captureUserFeedback(feedback) { 18724 if (!this._isEnabled()) { 18725 debugBuild.DEBUG_BUILD && utils.logger.warn('SDK not enabled, will not capture user feedback.'); 18726 return; 18727 } 18728 18729 const envelope = userfeedback.createUserFeedbackEnvelope(feedback, {
18730 metadata: this.getSdkMetadata(), 18731 dsn: this.getDsn(), 18732 tunnel: this.getOptions().tunnel, 18733 }); 18734 18735 // _sendEnvelope should not throw 18736 // eslint-disable-next-line @typescript-eslint/no-floating-promises 18737 this._sendEnvelope(envelope); 18738 } 18739 18740 /** 18741 * @inheritDoc 18742 */ 18743 _prepareEvent(event, hint, scope) { 18744 event.platform = event.platform || 'javascript'; 18745 return super._prepareEvent(event, hint, scope); 18746 } 18747 18748 /** 18749 * Sends client reports as an envelope. 18750 */ 18751 _flushOutcomes() { 18752 const outcomes = this._clearOutcomes(); 18753 18754 if (outcomes.length === 0) { 18755 debugBuild.DEBUG_BUILD && utils.logger.log('No outcomes to send'); 18756 return; 18757 } 18758 18759 // This is really the only place where we want to check for a DSN and only send outcomes then 18760 if (!this._dsn) { 18761 debugBuild.DEBUG_BUILD && utils.logger.log('No dsn provided, will not send outcomes'); 18762 return; 18763 } 18764 18765 debugBuild.DEBUG_BUILD && utils.logger.log('Sending outcomes:', outcomes); 18766 18767 const envelope = utils.createClientReportEnvelope(outcomes, this._options.tunnel && utils.dsnToString(this._dsn)); 18768 18769 // _sendEnvelope should not throw 18770 // eslint-disable-next-line @typescript-eslint/no-floating-promises 18771 this._sendEnvelope(envelope); 18772 } 18773} 18774 18775exports.BrowserClient = BrowserClient; 18776 18777 18778},{"./debug-build.js":220,"./eventbuilder.js":221,"./helpers.js":222,"./userfeedback.js":240,"@sentry/core":250,"@sentry/utils":319}],220:[function(require,module,exports){ 18779arguments[4][206][0].apply(exports,arguments) 18780},{"dup":206}],221:[function(require,module,exports){ 18781Object.defineProperty(exports, '__esModule', { value: true }); 18782 18783const core = require('@sentry/core'); 18784const utils = require('@sentry/utils'); 18785 18786/** 18787 * This function creates an exception from a JavaScript Error 18788 */ 18789function exceptionFromError(stackParser, ex) { 18790 // Get the frames first since Opera can lose the stack if we touch anything else first 18791 const frames = parseStackFrames(stackParser, ex); 18792 18793 const exception = { 18794 type: ex && ex.name, 18795 value: extractMessage(ex), 18796 }; 18797 18798 if (frames.length) { 18799 exception.stacktrace = { frames }; 18800 } 18801 18802 if (exception.type === undefined && exception.value === '') { 18803 exception.value = 'Unrecoverable error caught'; 18804 } 18805 18806 return exception; 18807} 18808 18809/** 18810 * @hidden 18811 */ 18812function eventFromPlainObject( 18813 stackParser, 18814 exception, 18815 syntheticException, 18816 isUnhandledRejection, 18817) { 18818 const client = core.getClient(); 18819 const normalizeDepth = client && client.getOptions().normalizeDepth; 18820 18821 const event = { 18822 exception: { 18823 values: [ 18824 { 18825 type: utils.isEvent(exception) ? exception.constructor.name : isUnhandledRejection ? 'UnhandledRejection' : 'Error', 18826 value: getNonErrorObjectExceptionValue(exception, { isUnhandledRejection }), 18827 }, 18828 ], 18829 }, 18830 extra: { 18831 __serialized__: utils.normalizeToSize(exception, normalizeDepth), 18832 }, 18833 }; 18834 18835 if (syntheticException) { 18836 const frames = parseStackFrames(stackParser, syntheticException); 18837 if (frames.length) { 18838 // event.exception.values[0] has been set above 18839 (event.exception ).values[0].stacktrace = { frames }; 18840 } 18841 } 18842 18843 return event; 18844} 18845 18846/** 18847 * @hidden 18848 */ 18849function eventFromError(stackParser, ex) { 18850 return { 18851 exception: { 18852 values: [exceptionFromError(stackParser, ex)], 18853 }, 18854 }; 18855} 18856 18857/** Parses stack frames from an error */ 18858function parseStackFrames( 18859 stackParser, 18860 ex, 18861) { 18862 // Access and store the stacktrace property before doing ANYTHING 18863 // else to it because Opera is not very good at providing it 18864 // reliably in other circumstances. 18865 const stacktrace = ex.stacktrace || ex.stack || ''; 18866 18867 const popSize = getPopSize(ex); 18868 18869 try { 18870 return stackParser(stacktrace, popSize); 18871 } catch (e) { 18872 // no-empty 18873 } 18874 18875 return []; 18876} 18877 18878// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108 18879const reactMinifiedRegexp = /Minified React error #\d+;/i; 18880 18881function getPopSize(ex) { 18882 if (ex) { 18883 if (typeof ex.framesToPop === 'number') { 18884 return ex.framesToPop; 18885 } 18886 18887 if (reactMinifiedRegexp.test(ex.message)) { 18888 return 1; 18889 } 18890 } 18891 18892 return 0; 18893} 18894 18895/** 18896 * There are cases where stacktrace.message is an Event object 18897 * https://github.com/getsentry/sentry-javascript/issues/1949 18898 * In this specific case we try to extract stacktrace.message.error.message 18899 */ 18900function extractMessage(ex) { 18901 const message = ex && ex.message; 18902 if (!message) { 18903 return 'No error message';
18904 } 18905 if (message.error && typeof message.error.message === 'string') { 18906 return message.error.message; 18907 } 18908 return message; 18909} 18910 18911/** 18912 * Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. 18913 * @hidden 18914 */ 18915function eventFromException( 18916 stackParser, 18917 exception, 18918 hint, 18919 attachStacktrace, 18920) { 18921 const syntheticException = (hint && hint.syntheticException) || undefined; 18922 const event = eventFromUnknownInput(stackParser, exception, syntheticException, attachStacktrace); 18923 utils.addExceptionMechanism(event); // defaults to { type: 'generic', handled: true } 18924 event.level = 'error'; 18925 if (hint && hint.event_id) { 18926 event.event_id = hint.event_id; 18927 } 18928 return utils.resolvedSyncPromise(event); 18929} 18930 18931/** 18932 * Builds and Event from a Message 18933 * @hidden 18934 */ 18935function eventFromMessage( 18936 stackParser, 18937 message, 18938 // eslint-disable-next-line deprecation/deprecation 18939 level = 'info', 18940 hint, 18941 attachStacktrace, 18942) { 18943 const syntheticException = (hint && hint.syntheticException) || undefined; 18944 const event = eventFromString(stackParser, message, syntheticException, attachStacktrace); 18945 event.level = level; 18946 if (hint && hint.event_id) { 18947 event.event_id = hint.event_id; 18948 } 18949 return utils.resolvedSyncPromise(event); 18950} 18951 18952/** 18953 * @hidden 18954 */ 18955function eventFromUnknownInput( 18956 stackParser, 18957 exception, 18958 syntheticException, 18959 attachStacktrace, 18960 isUnhandledRejection, 18961) { 18962 let event; 18963 18964 if (utils.isErrorEvent(exception ) && (exception ).error) { 18965 // If it is an ErrorEvent with `error` property, extract it to get actual Error 18966 const errorEvent = exception ; 18967 return eventFromError(stackParser, errorEvent.error ); 18968 } 18969 18970 // If it is a `DOMError` (which is a legacy API, but still supported in some browsers) then we just extract the name 18971 // and message, as it doesn't provide anything else. According to the spec, all `DOMExceptions` should also be 18972 // `Error`s, but that's not the case in IE11, so in that case we treat it the same as we do a `DOMError`. 18973 // 18974 // https://developer.mozilla.org/en-US/docs/Web/API/DOMError 18975 // https://developer.mozilla.org/en-US/docs/Web/API/DOMException 18976 // https://webidl.spec.whatwg.org/#es-DOMException-specialness 18977 if (utils.isDOMError(exception) || utils.isDOMException(exception )) { 18978 const domException = exception ; 18979 18980 if ('stack' in (exception )) { 18981 event = eventFromError(stackParser, exception ); 18982 } else { 18983 const name = domException.name || (utils.isDOMError(domException) ? 'DOMError' : 'DOMException'); 18984 const message = domException.message ? `${name}: ${domException.message}` : name; 18985 event = eventFromString(stackParser, message, syntheticException, attachStacktrace); 18986 utils.addExceptionTypeValue(event, message); 18987 } 18988 if ('code' in domException) { 18989 // eslint-disable-next-line deprecation/deprecation 18990 event.tags = { ...event.tags, 'DOMException.code': `${domException.code}` }; 18991 } 18992 18993 return event; 18994 } 18995 if (utils.isError(exception)) { 18996 // we have a real Error object, do nothing 18997 return eventFromError(stackParser, exception); 18998 } 18999 if (utils.isPlainObject(exception) || utils.isEvent(exception)) { 19000 // If it's a plain object or an instance of `Event` (the built-in JS kind, not this SDK's `Event` type), serialize 19001 // it manually. This will allow us to group events based on top-level keys which is much better than creating a new 19002 // group on any key/value change. 19003 const objectException = exception ; 19004 event = eventFromPlainObject(stackParser, objectException, syntheticException, isUnhandledRejection); 19005 utils.addExceptionMechanism(event, { 19006 synthetic: true, 19007 }); 19008 return event; 19009 } 19010 19011 // If none of previous checks were valid, then it means that it's not: 19012 // - an instance of DOMError 19013 // - an instance of DOMException 19014 // - an instance of Event 19015 // - an instance of Error 19016 // - a valid ErrorEvent (one with an error property) 19017 // - a plain Object 19018 // 19019 // So bail out and capture it as a simple message: 19020 event = eventFromString(stackParser, exception , syntheticException, attachStacktrace); 19021 utils.addExceptionTypeValue(event, `${exception}`, undefined); 19022 utils.addExceptionMechanism(event, { 19023 synthetic: true, 19024 }); 19025 19026 return event; 19027} 19028
19029/** 19030 * @hidden 19031 */ 19032function eventFromString( 19033 stackParser, 19034 message, 19035 syntheticException, 19036 attachStacktrace, 19037) { 19038 const event = {}; 19039 19040 if (attachStacktrace && syntheticException) { 19041 const frames = parseStackFrames(stackParser, syntheticException); 19042 if (frames.length) { 19043 event.exception = { 19044 values: [{ value: message, stacktrace: { frames } }], 19045 }; 19046 } 19047 } 19048 19049 if (utils.isParameterizedString(message)) { 19050 const { __sentry_template_string__, __sentry_template_values__ } = message; 19051 19052 event.logentry = { 19053 message: __sentry_template_string__, 19054 params: __sentry_template_values__, 19055 }; 19056 return event; 19057 } 19058 19059 event.message = message; 19060 return event; 19061} 19062 19063function getNonErrorObjectExceptionValue( 19064 exception, 19065 { isUnhandledRejection }, 19066) { 19067 const keys = utils.extractExceptionKeysForMessage(exception); 19068 const captureType = isUnhandledRejection ? 'promise rejection' : 'exception'; 19069 19070 // Some ErrorEvent instances do not have an `error` property, which is why they are not handled before 19071 // We still want to try to get a decent message for these cases 19072 if (utils.isErrorEvent(exception)) { 19073 return `Event \`ErrorEvent\` captured as ${captureType} with message \`${exception.message}\``; 19074 } 19075 19076 if (utils.isEvent(exception)) { 19077 const className = getObjectClassName(exception); 19078 return `Event \`${className}\` (type=${exception.type}) captured as ${captureType}`; 19079 } 19080 19081 return `Object captured as ${captureType} with keys: ${keys}`; 19082} 19083 19084function getObjectClassName(obj) { 19085 try { 19086 const prototype = Object.getPrototypeOf(obj); 19087 return prototype ? prototype.constructor.name : undefined; 19088 } catch (e) { 19089 // ignore errors here 19090 } 19091} 19092 19093exports.eventFromError = eventFromError; 19094exports.eventFromException = eventFromException; 19095exports.eventFromMessage = eventFromMessage; 19096exports.eventFromPlainObject = eventFromPlainObject; 19097exports.eventFromString = eventFromString; 19098exports.eventFromUnknownInput = eventFromUnknownInput; 19099exports.exceptionFromError = exceptionFromError; 19100exports.parseStackFrames = parseStackFrames; 19101 19102 19103},{"@sentry/core":250,"@sentry/utils":319}],222:[function(require,module,exports){ 19104Object.defineProperty(exports, '__esModule', { value: true }); 19105 19106require('@sentry-internal/tracing'); 19107const core = require('@sentry/core'); 19108const utils = require('@sentry/utils'); 19109 19110const WINDOW = utils.GLOBAL_OBJ ; 19111 19112let ignoreOnError = 0; 19113 19114/** 19115 * @hidden 19116 */ 19117function shouldIgnoreOnError() { 19118 return ignoreOnError > 0; 19119} 19120 19121/** 19122 * @hidden 19123 */ 19124function ignoreNextOnError() { 19125 // onerror should trigger before setTimeout 19126 ignoreOnError++; 19127 setTimeout(() => { 19128 ignoreOnError--; 19129 }); 19130} 19131 19132/** 19133 * Instruments the given function and sends an event to Sentry every time the 19134 * function throws an exception. 19135 * 19136 * @param fn A function to wrap. It is generally safe to pass an unbound function, because the returned wrapper always 19137 * has a correct `this` context. 19138 * @returns The wrapped function. 19139 * @hidden 19140 */ 19141function wrap( 19142 fn, 19143 options 19144 19145 = {}, 19146 before, 19147 // eslint-disable-next-line @typescript-eslint/no-explicit-any 19148) { 19149 // for future readers what this does is wrap a function and then create 19150 // a bi-directional wrapping between them. 19151 // 19152 // example: wrapped = wrap(original); 19153 // original.__sentry_wrapped__ -> wrapped 19154 // wrapped.__sentry_original__ -> original 19155 19156 if (typeof fn !== 'function') { 19157 return fn; 19158 } 19159 19160 try { 19161 // if we're dealing with a function that was previously wrapped, return 19162 // the original wrapper. 19163 const wrapper = fn.__sentry_wrapped__; 19164 if (wrapper) { 19165 return wrapper; 19166 } 19167 19168 // We don't wanna wrap it twice 19169 if (utils.getOriginalFunction(fn)) { 19170 return fn; 19171 } 19172 } catch (e) { 19173 // Just accessing custom props in some Selenium environments 19174 // can cause a "Permission denied" exception (see raven-js#495). 19175 // Bail on wrapping and return the function as-is (defers to window.onerror). 19176 return fn; 19177 } 19178 19179 /* eslint-disable prefer-rest-params */ 19180 // It is important that `sentryWrapped` is not an arrow function to preserve the context of `this` 19181 const sentryWrapped = function () { 19182 const args = Array.prototype.slice.call(arguments); 19183 19184 try { 19185 if (before && typeof before === 'function') { 19186 before.apply(this, arguments); 19187 } 19188 19189 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access 19190 const wrappedArguments = args.map((arg) => wrap(arg, options)); 19191 19192 // Attempt to invoke user-land function 19193 // NOTE: If you are a Sentry user, and you are seeing this stack frame, it 19194 // means the sentry.javascript SDK caught an error invoking your application code. This 19195 // is expected behavior and NOT indicative of a bug with sentry.javascript. 19196 return fn.apply(this, wrappedArguments); 19197 } catch (ex) { 19198 ignoreNextOnError(); 19199 19200 core.withScope(scope => { 19201 scope.addEventProcessor(event => { 19202 if (options.mechanism) { 19203 utils.addExceptionTypeValue(event, undefined, undefined); 19204 utils.addExceptionMechanism(event, options.mechanism); 19205 } 19206 19207 event.extra = { 19208 ...event.extra, 19209 arguments: args, 19210 }; 19211 19212 return event; 19213 }); 19214 19215 core.captureException(ex); 19216 }); 19217 19218 throw ex; 19219 } 19220 }; 19221 /* eslint-enable prefer-rest-params */ 19222 19223 // Accessing some objects may throw 19224 // ref: https://github.com/getsentry/sentry-javascript/issues/1168 19225 try { 19226 for (const property in fn) { 19227 if (Object.prototype.hasOwnProperty.call(fn, property)) { 19228 sentryWrapped[property] = fn[property]; 19229 } 19230 } 19231 } catch (_oO) {} // eslint-disable-line no-empty 19232 19233 // Signal that this function has been wrapped/filled already 19234 // for both debugging and to prevent it to being wrapped/filled twice 19235 utils.markFunctionWrapped(sentryWrapped, fn); 19236 19237 utils.addNonEnumerableProperty(fn, '__sentry_wrapped__', sentryWrapped); 19238 19239 // Restore original function name (not all browsers allow that) 19240 try { 19241 const descriptor = Object.getOwnPropertyDescriptor(sentryWrapped, 'name') ; 19242 if (descriptor.configurable) { 19243 Object.defineProperty(sentryWrapped, 'name', { 19244 get() { 19245 return fn.name; 19246 }, 19247 }); 19248 } 19249 // eslint-disable-next-line no-empty 19250 } catch (_oO) {} 19251 19252 return sentryWrapped; 19253} 19254 19255exports.WINDOW = WINDOW; 19256exports.ignoreNextOnError = ignoreNextOnError; 19257exports.shouldIgnoreOnError = shouldIgnoreOnError; 19258exports.wrap = wrap; 19259 19260 19261},{"@sentry-internal/tracing":209,"@sentry/core":250,"@sentry/utils":319}],223:[function(require,module,exports){ 19262Object.defineProperty(exports, '__esModule', { value: true }); 19263 19264const core = require('@sentry/core'); 19265const helpers = require('./helpers.js'); 19266const client = require('./client.js'); 19267const fetch = require('./transports/fetch.js'); 19268const xhr = require('./transports/xhr.js'); 19269const stackParsers = require('./stack-parsers.js'); 19270const eventbuilder = require('./eventbuilder.js'); 19271const userfeedback = require('./userfeedback.js'); 19272const sdk = require('./sdk.js'); 19273const breadcrumbs = require('./integrations/breadcrumbs.js'); 19274const dedupe = require('./integrations/dedupe.js'); 19275const globalhandlers = require('./integrations/globalhandlers.js'); 19276const httpcontext = require('./integrations/httpcontext.js'); 19277const linkederrors = require('./integrations/linkederrors.js'); 19278const trycatch = require('./integrations/trycatch.js'); 19279const index = require('./integrations/index.js'); 19280const replay = require('@sentry/replay'); 19281const replayCanvas = require('@sentry-internal/replay-canvas'); 19282const feedback = require('@sentry-internal/feedback'); 19283const tracing = require('@sentry-internal/tracing'); 19284const offline = require('./transports/offline.js'); 19285const hubextensions = require('./profiling/hubextensions.js'); 19286const integration = require('./profiling/integration.js'); 19287 19288let windowIntegrations = {}; 19289 19290// This block is needed to add compatibility with the integrations packages when used with a C
19290DN 19291if (helpers.WINDOW.Sentry && helpers.WINDOW.Sentry.Integrations) { 19292 windowIntegrations = helpers.WINDOW.Sentry.Integrations; 19293} 19294 19295/** @deprecated Import the integration function directly, e.g. `inboundFiltersIntegration()` instead of `new Integrations.InboundFilter(). */ 19296const INTEGRATIONS = { 19297 ...windowIntegrations, 19298 // eslint-disable-next-line deprecation/deprecation 19299 ...core.Integrations, 19300 ...index, 19301}; 19302 19303exports.FunctionToString = core.FunctionToString; 19304exports.Hub = core.Hub; 19305exports.InboundFilters = core.InboundFilters; 19306exports.ModuleMetadata = core.ModuleMetadata; 19307exports.SDK_VERSION = core.SDK_VERSION; 19308exports.SEMANTIC_ATTRIBUTE_SENTRY_OP = core.SEMANTIC_ATTRIBUTE_SENTRY_OP; 19309exports.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN; 19310exports.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE; 19311exports.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE; 19312exports.Scope = core.Scope; 19313exports.addBreadcrumb = core.addBreadcrumb; 19314exports.addEventProcessor = core.addEventProcessor; 19315exports.addGlobalEventProcessor = core.addGlobalEventProcessor; 19316exports.addIntegration = core.addIntegration; 19317exports.addTracingExtensions = core.addTracingExtensions; 19318exports.captureEvent = core.captureEvent; 19319exports.captureException = core.captureException; 19320exports.captureMessage = core.captureMessage; 19321exports.captureSession = core.captureSession; 19322exports.close = core.close; 19323exports.configureScope = core.configureScope; 19324exports.continueTrace = core.continueTrace; 19325exports.createTransport = core.createTransport; 19326exports.endSession = core.endSession; 19327exports.extractTraceparentData = core.extractTraceparentData; 19328exports.flush = core.flush; 19329exports.functionToStringIntegration = core.functionToStringIntegration; 19330exports.getActiveSpan = core.getActiveSpan; 19331exports.getActiveTransaction = core.getActiveTransaction; 19332exports.getClient = core.getClient; 19333exports.getCurrentHub = core.getCurrentHub; 19334exports.getCurrentScope = core.getCurrentScope; 19335exports.getHubFromCarrier = core.getHubFromCarrier; 19336exports.getSpanStatusFromHttpCode = core.getSpanStatusFromHttpCode; 19337exports.inboundFiltersIntegration = core.inboundFiltersIntegration; 19338exports.isInitialized = core.isInitialized; 19339exports.lastEventId = core.lastEventId; 19340exports.makeMain = core.makeMain; 19341exports.makeMultiplexedTransport = core.makeMultiplexedTransport; 19342exports.metrics = core.metrics; 19343exports.moduleMetadataIntegration = core.moduleMetadataIntegration; 19344exports.parameterize = core.parameterize; 19345exports.setContext = core.setContext; 19346exports.setCurrentClient = core.setCurrentClient; 19347exports.setExtra = core.setExtra; 19348exports.setExtras = core.setExtras;
19349exports.setHttpStatus = core.setHttpStatus; 19350exports.setMeasurement = core.setMeasurement; 19351exports.setTag = core.setTag; 19352exports.setTags = core.setTags; 19353exports.setUser = core.setUser; 19354exports.spanStatusfromHttpCode = core.spanStatusfromHttpCode; 19355exports.startInactiveSpan = core.startInactiveSpan; 19356exports.startSession = core.startSession; 19357exports.startSpan = core.startSpan; 19358exports.startSpanManual = core.startSpanManual; 19359exports.startTransaction = core.startTransaction; 19360exports.trace = core.trace; 19361exports.withActiveSpan = core.withActiveSpan; 19362exports.withIsolationScope = core.withIsolationScope; 19363exports.withScope = core.withScope; 19364exports.WINDOW = helpers.WINDOW; 19365exports.BrowserClient = client.BrowserClient; 19366exports.makeFetchTransport = fetch.makeFetchTransport; 19367exports.makeXHRTransport = xhr.makeXHRTransport; 19368exports.chromeStackLineParser = stackParsers.chromeStackLineParser; 19369exports.defaultStackLineParsers = stackParsers.defaultStackLineParsers; 19370exports.defaultStackParser = stackParsers.defaultStackParser; 19371exports.geckoStackLineParser = stackParsers.geckoStackLineParser; 19372exports.opera10StackLineParser = stackParsers.opera10StackLineParser; 19373exports.opera11StackLineParser = stackParsers.opera11StackLineParser; 19374exports.winjsStackLineParser = stackParsers.winjsStackLineParser; 19375exports.eventFromException = eventbuilder.eventFromException; 19376exports.eventFromMessage = eventbuilder.eventFromMessage; 19377exports.exceptionFromError = eventbuilder.exceptionFromError; 19378exports.createUserFeedbackEnvelope = userfeedback.createUserFeedbackEnvelope; 19379exports.captureUserFeedback = sdk.captureUserFeedback; 19380exports.defaultIntegrations = sdk.defaultIntegrations; 19381exports.forceLoad = sdk.forceLoad; 19382exports.getDefaultIntegrations = sdk.getDefaultIntegrations; 19383exports.init = sdk.init; 19384exports.onLoad = sdk.onLoad; 19385exports.showReportDialog = sdk.showReportDialog; 19386exports.wrap = sdk.wrap; 19387exports.Breadcrumbs = breadcrumbs.Breadcrumbs; 19388exports.breadcrumbsIntegration = breadcrumbs.breadcrumbsIntegration; 19389exports.Dedupe = dedupe.Dedupe; 19390exports.dedupeIntegration = dedupe.dedupeIntegration; 19391exports.GlobalHandlers = globalhandlers.GlobalHandlers; 19392exports.globalHandlersIntegration = globalhandlers.globalHandlersIntegration; 19393exports.HttpContext = httpcontext.HttpContext; 19394exports.httpContextIntegration = httpcontext.httpContextIntegration; 19395exports.LinkedErrors = linkederrors.LinkedErrors; 19396exports.linkedErrorsIntegration = linkederrors.linkedErrorsIntegration; 19397exports.TryCatch = trycatch.TryCatch; 19398exports.browserApiErrorsIntegration = trycatch.browserApiErrorsIntegration; 19399exports.Replay = replay.Replay; 19400exports.getReplay = replay.getReplay; 19401exports.replayIntegration = replay.replayIntegration; 19402exports.ReplayCanvas = replayCanvas.ReplayCanvas; 19403exports.replayCanvasIntegration = replayCanvas.replayCanvasIntegration; 19404exports.Feedback = feedback.Feedback; 19405exports.feedbackIntegration = feedback.feedbackIntegration; 19406exports.sendFeedback = feedback.sendFeedback; 19407exports.BrowserTracing = tracing.BrowserTracing; 19408exports.browserTracingIntegration = tracing.browserTracingIntegration; 19409exports.defaultRequestInstrumentationOptions = tracing.defaultRequestInstrumentationOptions; 19410exports.instrumentOutgoingRequests = tracing.instrumentOutgoingRequests; 19411exports.startBrowserTracingNavigationSpan = tracing.startBrowserTracingNavigationSpan; 19412exports.startBrowserTracingPageLoadSpan = tracing.startBrowserTracingPageLoadSpan; 19413exports.makeBrowserOfflineTransport = offline.makeBrowserOfflineTransport; 19414exports.onProfilingStartRouteTransaction = hubextensions.onProfilingStartRouteTransaction; 19415exports.BrowserProfilingIntegration = integration.BrowserProfilingIntegration; 19416exports.browserProfilingIntegration = integration.browserProfilingIntegration; 19417exports.Integrations = INTEGRATIONS; 19418 19419 19420},{"./client.js":219,"./eventbuilder.js":221,"./helpers.js":222,"./integrations/breadcrumbs.js":224,"./integrations/dedupe.js":225,"./integrations/globalhandlers.js":226,"./integrations/httpcontext.js":227,"./integrations/index.js":228,"./integrations/linkederrors.js":229,"./integrations/trycatch.js":230,"./profiling/hubextensions.js":231,"./profiling/integration.js":232,"./sdk.js":234,"./stack-parsers.js":235,"./transports/fetch.js":236,"./transports/offline.js":237,"./transports/xhr.js":239,"./userfeedback.js":240,"@sentry-internal/feedback":182,"@sentry-internal/replay-canvas":183,"@sentry-internal/tracing":209,"@sentry/core":250,"@sentry/replay":299}],224:[function(require,module,exports){ 19421Object.defineProperty(exports, '__esModule', { value: true }); 19422 19423const core = require('@sentry/core'); 19424const utils = require('@sentry/utils'); 19425const debugBuild = require('../debug-build.js'); 19426const helpers = require('../helpers.js'); 19427 19428/* eslint-disable max-lines */ 19429 19430/** maxStringLength gets capped to prevent 100 breadcrumbs exceeding 1MB event payload size */ 19431const MAX_ALLOWED_STRING_LENGTH = 1024; 19432 19433const INTEGRATION_NAME = 'Breadcrumbs'; 19434 19435const _breadcrumbsIntegration = ((options = {}) => { 19436 const _options = { 19437 console: true, 19438 dom: true, 19439 fetch: true, 19440 history: true, 19441 sentry: true, 19442 xhr: true, 19443 ...options, 19444 }; 19445 19446 return { 19447 name: INTEGRATION_NAME, 19448 // TODO v8: Remove this 19449 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 19450 setup(client) { 19451 if (_options.console) { 19452 utils.addConsoleInstrumentationHandler(_getConsoleBreadcrumbHandler(client)); 19453 } 19454 if (_options.dom) { 19455 utils.addClickKeypressInstrumentationHandler(_getDomBreadcrumbHandler(client, _options.dom)); 19456 } 19457 if (_options.xhr) { 19458 utils.addXhrInstrumentationHandler(_getXhrBreadcrumbHandler(client)); 19459 } 19460 if (_options.fetch) { 19461 utils.addFetchInstrumentationHandler(_getFetchBreadcrumbHandler(client)); 19462 } 19463 if (_options.history) { 19464 utils.addHistoryInstrumentationHandler(_getHistoryBreadcrumbHandler(client)); 19465 } 19466 if (_options.sentry && client.on) { 19467 client.on('beforeSendEvent', _getSentryBreadcrumbHandler(client)); 19468 } 19469 }, 19470 }; 19471}) ; 19472 19473const breadcrumbsIntegration = core.defineIntegration(_breadcrumbsIntegration); 19474 19475/** 19476 * Default Breadcrumbs instrumentations 19477 * 19478 * @deprecated Use `breadcrumbsIntegration()` instead. 19479 */ 19480// eslint-disable-next-line deprecation/deprecation 19481const Breadcrumbs = core.convertIntegrationFnToClass(INTEGRATION_NAME, breadcrumbsIntegration) 19482 19483; 19484 19485/** 19486 * Adds a breadcrumb for Sentry events or transactions if this option is enabled. 19487 */ 19488function _getSentryBreadcrumbHandler(client) { 19489 return function addSentryBreadcrumb(event) { 19490 if (core.getClient() !== client) { 19491 return; 19492 } 19493 19494 core.addBreadcrumb( 19495 { 19496 category: `sentry.${event.type === 'transaction' ? 'transaction' : 'event'}`, 19497 event_id: event.event_id, 19498 level: event.level, 19499 message: utils.getEventDescription(event), 19500 }, 19501 { 19502 event, 19503 }, 19504 ); 19505 }; 19506} 19507 19508/** 19509 * A HOC that creaes a function that creates breadcrumbs from DOM API calls. 19510 * This is a HOC so that we get access to dom options in the closure. 19511 */ 19512function _getDomBreadcrumbHandler( 19513 client, 19514 dom, 19515) { 19516 return function _innerDomBreadcrumb(handlerData) { 19517 if (core.getClient() !== client) { 19518 return; 19519 } 19520 19521 let target;
19522 let componentName; 19523 let keyAttrs = typeof dom === 'object' ? dom.serializeAttribute : undefined; 19524 19525 let maxStringLength = 19526 typeof dom === 'object' && typeof dom.maxStringLength === 'number' ? dom.maxStringLength : undefined; 19527 if (maxStringLength && maxStringLength > MAX_ALLOWED_STRING_LENGTH) { 19528 debugBuild.DEBUG_BUILD && 19529 utils.logger.warn( 19530 `\`dom.maxStringLength\` cannot exceed ${MAX_ALLOWED_STRING_LENGTH}, but a value of ${maxStringLength} was configured. Sentry will use ${MAX_ALLOWED_STRING_LENGTH} instead.`, 19531 ); 19532 maxStringLength = MAX_ALLOWED_STRING_LENGTH; 19533 } 19534 19535 if (typeof keyAttrs === 'string') { 19536 keyAttrs = [keyAttrs]; 19537 } 19538 19539 // Accessing event.target can throw (see getsentry/raven-js#838, #768) 19540 try { 19541 const event = handlerData.event ; 19542 const element = _isEvent(event) ? event.target : event; 19543 19544 target = utils.htmlTreeAsString(element, { keyAttrs, maxStringLength }); 19545 componentName = utils.getComponentName(element); 19546 } catch (e) { 19547 target = '<unknown>'; 19548 } 19549 19550 if (target.length === 0) { 19551 return; 19552 } 19553 19554 const breadcrumb = { 19555 category: `ui.${handlerData.name}`, 19556 message: target, 19557 }; 19558 19559 if (componentName) { 19560 breadcrumb.data = { 'ui.component_name': componentName }; 19561 } 19562 19563 core.addBreadcrumb(breadcrumb, { 19564 event: handlerData.event, 19565 name: handlerData.name, 19566 global: handlerData.global, 19567 }); 19568 }; 19569} 19570 19571/** 19572 * Creates breadcrumbs from console API calls 19573 */ 19574function _getConsoleBreadcrumbHandler(client) { 19575 return function _consoleBreadcrumb(handlerData) { 19576 if (core.getClient() !== client) { 19577 return; 19578 } 19579 19580 const breadcrumb = { 19581 category: 'console', 19582 data: { 19583 arguments: handlerData.args, 19584 logger: 'console', 19585 }, 19586 level: utils.severityLevelFromString(handlerData.level), 19587 message: utils.safeJoin(handlerData.args, ' '), 19588 }; 19589 19590 if (handlerData.level === 'assert') { 19591 if (handlerData.args[0] === false) { 19592 breadcrumb.message = `Assertion failed: ${utils.safeJoin(handlerData.args.slice(1), ' ') || 'console.assert'}`; 19593 breadcrumb.data.arguments = handlerData.args.slice(1); 19594 } else { 19595 // Don't capture a breadcrumb for passed assertions 19596 return; 19597 } 19598 } 19599 19600 core.addBreadcrumb(breadcrumb, { 19601 input: handlerData.args, 19602 level: handlerData.level, 19603 }); 19604 }; 19605} 19606 19607/** 19608 * Creates breadcrumbs from XHR API calls 19609 */ 19610function _getXhrBreadcrumbHandler(client) { 19611 return function _xhrBreadcrumb(handlerData) { 19612 if (core.getClient() !== client) { 19613 return; 19614 } 19615 19616 const { startTimestamp, endTimestamp } = handlerData; 19617 19618 const sentryXhrData = handlerData.xhr[utils.SENTRY_XHR_DATA_KEY]; 19619 19620 // We only capture complete, non-sentry requests 19621 if (!startTimestamp || !endTimestamp || !sentryXhrData) { 19622 return; 19623 } 19624 19625 const { method, url, status_code, body } = sentryXhrData; 19626 19627 const data = { 19628 method, 19629 url, 19630 status_code, 19631 }; 19632 19633 const hint = { 19634 xhr: handlerData.xhr, 19635 input: body, 19636 startTimestamp, 19637 endTimestamp, 19638 }; 19639 19640 core.addBreadcrumb( 19641 { 19642 category: 'xhr', 19643 data, 19644 type: 'http', 19645 }, 19646 hint, 19647 ); 19648 }; 19649} 19650 19651/** 19652 * Creates breadcrumbs from fetch API calls 19653 */ 19654function _getFetchBreadcrumbHandler(client) { 19655 return function _fetchBreadcrumb(handlerData) { 19656 if (core.getClient() !== client) { 19657 return; 19658 } 19659 19660 const { startTimestamp, endTimestamp } = handlerData; 19661 19662 // We only capture complete fetch requests 19663 if (!endTimestamp) { 19664 return; 19665 } 19666 19667 if (handlerData.fetchData.url.match(/sentry_key/) && handlerData.fetchData.method === 'POST') { 19668 // We will not create breadcrumbs for fetch requests that contain `sentry_key` (internal sentry requests) 19669 return; 19670 } 19671 19672 if (handlerData.error) { 19673 const data = handlerData.fetchData; 19674 const hint = { 19675 data: handlerData.error, 19676 input: handlerData.args, 19677 startTimestamp, 19678 endTimestamp, 19679 }; 19680 19681 core.addBreadcrumb( 19682 { 19683 category: 'fetch', 19684 data, 19685 level: 'error', 19686 type: 'http', 19687 }, 19688 hint, 19689 ); 19690 } else { 19691 const response = handlerData.response ; 19692 const data = { 19693 ...handlerData.fetchData, 19694 status_code: response && response.status, 19695 }; 19696 const hint = { 19697 input: handlerData.args, 19698 response, 19699 startTimestamp, 19700 endTimestamp, 19701 }; 19702 core.addBreadcrumb( 19703 { 19704 category: 'fetch', 19705 data, 19706 type: 'http', 19707 }, 19708 hint, 19709 ); 19710 } 19711 }; 19712} 19713 19714/** 19715 * Creates breadcrumbs from history API calls 19716 */ 19717function _getHistoryBreadcrumbHandler(client) { 19718 return function _historyBreadcrumb(handlerData) { 19719 if (core.getClient() !== client) { 19720 return; 19721 } 19722 19723 let from = handlerData.from; 19724 let to = handlerData.to; 19725 const parsedLoc = utils.parseUrl(helpers.WINDOW.location.href); 19726 let parsedFrom = from ? utils.parseUrl(from) : undefined; 19727 const parsedTo = utils.parseUrl(to); 19728 19729 // Initial pushState doesn't provide `from` information 19730 if (!parsedFrom || !parsedFrom.path) { 19731 parsedFrom = parsedLoc; 19732 } 19733 19734 // Use only the path component of the URL if the URL matches the current 19735 // document (almost all the time when using pushState) 19736 if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host) { 19737 to = parsedTo.relative; 19738 } 19739 if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host) { 19740 from = parsedFrom.relative; 19741 } 19742 19743 core.addBreadcrumb({ 19744 category: 'navigation', 19745 data: { 19746 from, 19747 to, 19748 }, 19749 }); 19750 }; 19751} 19752 19753function _isEvent(event) { 19754 return !!event && !!(event ).target; 19755} 19756 19757exports.Breadcrumbs = Breadcrumbs; 19758exports.breadcrumbsIntegration = breadcrumbsIntegration; 19759 19760 19761},{"../debug-build.js":220,"../helpers.js":222,"@sentry/core":250,"@sentry/utils":319}],225:[function(require,module,exports){ 19762Object.defineProperty(exports, '__esModule', { value: true }); 19763 19764const core = require('@sentry/core'); 19765const utils = require('@sentry/utils'); 19766const debugBuild = require('../debug-build.js'); 19767 19768const INTEGRATION_NAME = 'Dedupe'; 19769 19770const _dedupeIntegration = (() => { 19771 let previousEvent; 19772 19773 return { 19774 name: INTEGRATION_NAME, 19775 // TODO v8: Remove this 19776 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 19777 processEvent(currentEvent) { 19778 // We want to ignore any non-error type events, e.g. transactions or replays 19779 // These should never be deduped, and also not be compared against as _previousEvent. 19780 if (currentEvent.type) { 19781 return currentEvent; 19782 } 19783 19784 // Juuust in case something goes wrong
vendor: 4,137 bytes, lines 19785-19937
19785 try { 19786 if (_shouldDropEvent(currentEvent, previousEvent)) { 19787 debugBuild.DEBUG_BUILD && utils.logger.warn('Event dropped due to being a duplicate of previously captured event.'); 19788 return null; 19789 } 19790 } catch (_oO) {} // eslint-disable-line no-empty 19791 19792 return (previousEvent = currentEvent); 19793 }, 19794 }; 19795}) ; 19796 19797const dedupeIntegration = core.defineIntegration(_dedupeIntegration); 19798 19799/** 19800 * Deduplication filter. 19801 * @deprecated Use `dedupeIntegration()` instead. 19802 */ 19803// eslint-disable-next-line deprecation/deprecation 19804const Dedupe = core.convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration) 19805 19806; 19807 19808function _shouldDropEvent(currentEvent, previousEvent) { 19809 if (!previousEvent) { 19810 return false; 19811 } 19812 19813 if (_isSameMessageEvent(currentEvent, previousEvent)) { 19814 return true; 19815 } 19816 19817 if (_isSameExceptionEvent(currentEvent, previousEvent)) { 19818 return true; 19819 } 19820 19821 return false; 19822} 19823 19824function _isSameMessageEvent(currentEvent, previousEvent) { 19825 const currentMessage = currentEvent.message; 19826 const previousMessage = previousEvent.message; 19827 19828 // If neither event has a message property, they were both exceptions, so bail out 19829 if (!currentMessage && !previousMessage) { 19830 return false; 19831 } 19832 19833 // If only one event has a stacktrace, but not the other one, they are not the same 19834 if ((currentMessage && !previousMessage) || (!currentMessage && previousMessage)) { 19835 return false; 19836 } 19837 19838 if (currentMessage !== previousMessage) { 19839 return false; 19840 } 19841 19842 if (!_isSameFingerprint(currentEvent, previousEvent)) { 19843 return false; 19844 } 19845 19846 if (!_isSameStacktrace(currentEvent, previousEvent)) { 19847 return false; 19848 } 19849 19850 return true; 19851} 19852 19853function _isSameExceptionEvent(currentEvent, previousEvent) { 19854 const previousException = _getExceptionFromEvent(previousEvent); 19855 const currentException = _getExceptionFromEvent(currentEvent); 19856 19857 if (!previousException || !currentException) { 19858 return false; 19859 } 19860 19861 if (previousException.type !== currentException.type || previousException.value !== currentException.value) { 19862 return false; 19863 } 19864 19865 if (!_isSameFingerprint(currentEvent, previousEvent)) { 19866 return false; 19867 } 19868 19869 if (!_isSameStacktrace(currentEvent, previousEvent)) { 19870 return false; 19871 } 19872 19873 return true; 19874} 19875 19876function _isSameStacktrace(currentEvent, previousEvent) { 19877 let currentFrames = _getFramesFromEvent(currentEvent); 19878 let previousFrames = _getFramesFromEvent(previousEvent); 19879 19880 // If neither event has a stacktrace, they are assumed to be the same 19881 if (!currentFrames && !previousFrames) { 19882 return true; 19883 } 19884 19885 // If only one event has a stacktrace, but not the other one, they are not the same 19886 if ((currentFrames && !previousFrames) || (!currentFrames && previousFrames)) { 19887 return false; 19888 } 19889 19890 currentFrames = currentFrames ; 19891 previousFrames = previousFrames ; 19892 19893 // If number of frames differ, they are not the same 19894 if (previousFrames.length !== currentFrames.length) { 19895 return false; 19896 } 19897 19898 // Otherwise, compare the two 19899 for (let i = 0; i < previousFrames.length; i++) { 19900 const frameA = previousFrames[i]; 19901 const frameB = currentFrames[i]; 19902 19903 if ( 19904 frameA.filename !== frameB.filename || 19905 frameA.lineno !== frameB.lineno || 19906 frameA.colno !== frameB.colno || 19907 frameA.function !== frameB.function 19908 ) { 19909 return false; 19910 } 19911 } 19912 19913 return true; 19914} 19915 19916function _isSameFingerprint(currentEvent, previousEvent) { 19917 let currentFingerprint = currentEvent.fingerprint; 19918 let previousFingerprint = previousEvent.fingerprint; 19919 19920 // If neither event has a fingerprint, they are assumed to be the same 19921 if (!currentFingerprint && !previousFingerprint) { 19922 return true; 19923 } 19924 19925 // If only one event has a fingerprint, but not the other one, they are not the same 19926 if ((currentFingerprint && !previousFingerprint) || (!currentFingerprint && previousFingerprint)) { 19927 return false; 19928 } 19929 19930 currentFingerprint = currentFingerprint ; 19931 previousFingerprint = previousFingerprint ; 19932 19933 // Otherwise, compare the two 19934 try { 19935 return !!(currentFingerprint.join('') === previousFingerprint.join('')); 19936 } catch (_oO) { 19937 return false;
19938 } 19939} 19940 19941function _getExceptionFromEvent(event) { 19942 return event.exception && event.exception.values && event.exception.values[0]; 19943} 19944 19945function _getFramesFromEvent(event) { 19946 const exception = event.exception; 19947 19948 if (exception) { 19949 try { 19950 // @ts-expect-error Object could be undefined 19951 return exception.values[0].stacktrace.frames; 19952 } catch (_oO) { 19953 return undefined; 19954 } 19955 } 19956 return undefined; 19957} 19958 19959exports.Dedupe = Dedupe; 19960exports.dedupeIntegration = dedupeIntegration; 19961 19962 19963},{"../debug-build.js":220,"@sentry/core":250,"@sentry/utils":319}],226:[function(require,module,exports){ 19964Object.defineProperty(exports, '__esModule', { value: true }); 19965 19966const core = require('@sentry/core'); 19967const utils = require('@sentry/utils'); 19968const debugBuild = require('../debug-build.js'); 19969const eventbuilder = require('../eventbuilder.js'); 19970const helpers = require('../helpers.js'); 19971 19972/* eslint-disable @typescript-eslint/no-unsafe-member-access */ 19973 19974const INTEGRATION_NAME = 'GlobalHandlers'; 19975 19976const _globalHandlersIntegration = ((options = {}) => { 19977 const _options = { 19978 onerror: true, 19979 onunhandledrejection: true, 19980 ...options, 19981 }; 19982 19983 return { 19984 name: INTEGRATION_NAME, 19985 setupOnce() { 19986 Error.stackTraceLimit = 50; 19987 }, 19988 setup(client) { 19989 if (_options.onerror) { 19990 _installGlobalOnErrorHandler(client); 19991 globalHandlerLog('onerror'); 19992 } 19993 if (_options.onunhandledrejection) { 19994 _installGlobalOnUnhandledRejectionHandler(client); 19995 globalHandlerLog('onunhandledrejection'); 19996 } 19997 }, 19998 }; 19999}) ; 20000 20001const globalHandlersIntegration = core.defineIntegration(_globalHandlersIntegration); 20002 20003/** 20004 * Global handlers. 20005 * @deprecated Use `globalHandlersIntegration()` instead. 20006 */ 20007// eslint-disable-next-line deprecation/deprecation 20008const GlobalHandlers = core.convertIntegrationFnToClass( 20009 INTEGRATION_NAME, 20010 globalHandlersIntegration, 20011) 20012 20013; 20014 20015function _installGlobalOnErrorHandler(client) { 20016 utils.addGlobalErrorInstrumentationHandler(data => { 20017 const { stackParser, attachStacktrace } = getOptions(); 20018 20019 if (core.getClient() !== client || helpers.shouldIgnoreOnError()) { 20020 return; 20021 } 20022 20023 const { msg, url, line, column, error } = data; 20024 20025 const event = 20026 error === undefined && utils.isString(msg) 20027 ? _eventFromIncompleteOnError(msg, url, line, column) 20028 : _enhanceEventWithInitialFrame( 20029 eventbuilder.eventFromUnknownInput(stackParser, error || msg, undefined, attachStacktrace, false), 20030 url, 20031 line, 20032 column, 20033 ); 20034 20035 event.level = 'error'; 20036 20037 core.captureEvent(event, { 20038 originalException: error, 20039 mechanism: { 20040 handled: false, 20041 type: 'onerror', 20042 }, 20043 }); 20044 }); 20045} 20046 20047function _installGlobalOnUnhandledRejectionHandler(client) { 20048 utils.addGlobalUnhandledRejectionInstrumentationHandler(e => { 20049 const { stackParser, attachStacktrace } = getOptions(); 20050 20051 if (core.getClient() !== client || helpers.shouldIgnoreOnError()) { 20052 return; 20053 } 20054 20055 const error = _getUnhandledRejectionError(e ); 20056 20057 const event = utils.isPrimitive(error) 20058 ? _eventFromRejectionWithPrimitive(error) 20059 : eventbuilder.eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true); 20060 20061 event.level = 'error'; 20062 20063 core.captureEvent(event, { 20064 originalException: error, 20065 mechanism: { 20066 handled: false, 20067 type: 'onunhandledrejection', 20068 }, 20069 }); 20070 }); 20071} 20072 20073function _getUnhandledRejectionError(error) { 20074 if (utils.isPrimitive(error)) { 20075 return error; 20076 } 20077 20078 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20079 const e = error ; 20080 20081 // dig the object of the rejection out of known event types 20082 try { 20083 // PromiseRejectionEvents store the object of the rejection under 'reason' 20084 // see https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent 20085 if ('reason' in e) { 20086 return e.reason; 20087 } 20088 20089 // something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents 20090 // to CustomEvents, moving the `promise` and `reason` attributes of the PRE into 20091 // the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec 20092 // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and 20093 // https://github.com/getsentry/sentry-javascript/issues/2380 20094 else if ('detail' in e && 'reason' in e.detail) { 20095 return e.detail.reason; 20096 } 20097 } catch (e2) {} // eslint-disable-line no-empty 20098 20099 return error; 20100} 20101
20102/** 20103 * Create an event from a promise rejection where the `reason` is a primitive. 20104 * 20105 * @param reason: The `reason` property of the promise rejection 20106 * @returns An Event object with an appropriate `exception` value 20107 */ 20108function _eventFromRejectionWithPrimitive(reason) { 20109 return { 20110 exception: { 20111 values: [ 20112 { 20113 type: 'UnhandledRejection', 20114 // String() is needed because the Primitive type includes symbols (which can't be automatically stringified) 20115 value: `Non-Error promise rejection captured with value: ${String(reason)}`, 20116 }, 20117 ], 20118 }, 20119 }; 20120} 20121 20122/** 20123 * This function creates a stack from an old, error-less onerror handler. 20124 */ 20125// eslint-disable-next-line @typescript-eslint/no-explicit-any 20126function _eventFromIncompleteOnError(msg, url, line, column) { 20127 const ERROR_TYPES_RE = 20128 /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i; 20129 20130 // If 'message' is ErrorEvent, get real message from inside 20131 let message = utils.isErrorEvent(msg) ? msg.message : msg; 20132 let name = 'Error'; 20133 20134 const groups = message.match(ERROR_TYPES_RE); 20135 if (groups) { 20136 name = groups[1]; 20137 message = groups[2]; 20138 } 20139 20140 const event = { 20141 exception: { 20142 values: [ 20143 { 20144 type: name, 20145 value: message, 20146 }, 20147 ], 20148 }, 20149 }; 20150 20151 return _enhanceEventWithInitialFrame(event, url, line, column); 20152} 20153 20154// eslint-disable-next-line @typescript-eslint/no-explicit-any 20155function _enhanceEventWithInitialFrame(event, url, line, column) { 20156 // event.exception 20157 const e = (event.exception = event.exception || {}); 20158 // event.exception.values 20159 const ev = (e.values = e.values || []); 20160 // event.exception.values[0] 20161 const ev0 = (ev[0] = ev[0] || {}); 20162 // event.exception.values[0].stacktrace 20163 const ev0s = (ev0.stacktrace = ev0.stacktrace || {}); 20164 // event.exception.values[0].stacktrace.frames 20165 const ev0sf = (ev0s.frames = ev0s.frames || []); 20166 20167 const colno = isNaN(parseInt(column, 10)) ? undefined : column; 20168 const lineno = isNaN(parseInt(line, 10)) ? undefined : line; 20169 const filename = utils.isString(url) && url.length > 0 ? url : utils.getLocationHref(); 20170 20171 // event.exception.values[0].stacktrace.frames 20172 if (ev0sf.length === 0) { 20173 ev0sf.push({ 20174 colno, 20175 filename, 20176 function: '?', 20177 in_app: true, 20178 lineno, 20179 }); 20180 } 20181 20182 return event; 20183} 20184 20185function globalHandlerLog(type) { 20186 debugBuild.DEBUG_BUILD && utils.logger.log(`Global Handler attached: ${type}`); 20187} 20188 20189function getOptions() { 20190 const client = core.getClient(); 20191 const options = (client && client.getOptions()) || { 20192 stackParser: () => [], 20193 attachStacktrace: false, 20194 }; 20195 return options; 20196} 20197 20198exports.GlobalHandlers = GlobalHandlers; 20199exports.globalHandlersIntegration = globalHandlersIntegration; 20200 20201 20202},{"../debug-build.js":220,"../eventbuilder.js":221,"../helpers.js":222,"@sentry/core":250,"@sentry/utils":319}],227:[function(require,module,exports){ 20203Object.defineProperty(exports, '__esModule', { value: true }); 20204 20205const core = require('@sentry/core'); 20206const helpers = require('../helpers.js'); 20207 20208const INTEGRATION_NAME = 'HttpContext'; 20209 20210const _httpContextIntegration = (() => { 20211 return { 20212 name: INTEGRATION_NAME, 20213 // TODO v8: Remove this 20214 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 20215 preprocessEvent(event) { 20216 // if none of the information we want exists, don't bother 20217 if (!helpers.WINDOW.navigator && !helpers.WINDOW.location && !helpers.WINDOW.document) { 20218 return; 20219 } 20220 20221 // grab as much info as exists and add it to the event 20222 const url = (event.request && event.request.url) || (helpers.WINDOW.location && helpers.WINDOW.location.href); 20223 const { referrer } = helpers.WINDOW.document || {}; 20224 const { userAgent } = helpers.WINDOW.navigator || {}; 20225 20226 const headers = { 20227 ...(event.request && event.request.headers), 20228 ...(referrer && { Referer: referrer }), 20229 ...(userAgent && { 'User-Agent': userAgent }), 20230 }; 20231 const request = { ...event.request, ...(url && { url }), headers }; 20232 20233 event.request = request; 20234 }, 20235 }; 20236}) ; 20237 20238const httpContextIntegration = core.defineIntegration(_httpContextIntegration); 20239 20240/** 20241 * HttpContext integration collects information about HTTP request headers. 20242 * @deprecated Use `httpContextIntegration()` instead. 20243 */ 20244// eslint-disable-next-line deprecation/deprecation 20245const HttpContext = core.convertIntegrationFnToClass(INTEGRATION_NAME, httpContextIntegration) 20246 20247; 20248 20249exports.HttpContext = HttpContext; 20250exports.httpContextIntegration = httpContextIntegration; 20251 20252 20253},{"../helpers.js":222,"@sentry/core":250}],228:[function(require,module,exports){ 20254Object.defineProperty(exports, '__esModule', { value: true }); 20255 20256const globalhandlers = require('./globalhandlers.js'); 20257const trycatch = require('./trycatch.js'); 20258const breadcrumbs = require('./breadcrumbs.js'); 20259const linkederrors = require('./linkederrors.js'); 20260const httpcontext = require('./httpcontext.js'); 20261const dedupe = require('./dedupe.js'); 20262 20263/* eslint-disable deprecation/deprecation */ 20264 20265exports.GlobalHandlers = globalhandlers.GlobalHandlers; 20266exports.TryCatch = trycatch.TryCatch; 20267exports.Breadcrumbs = breadcrumbs.Breadcrumbs; 20268exports.LinkedErrors = linkederrors.LinkedErrors; 20269exports.HttpContext = httpcontext.HttpContext; 20270exports.Dedupe = dedupe.Dedupe; 20271 20272 20273},{"./breadcrumbs.js":224,"./dedupe.js":225,"./globalhandlers.js":226,"./httpcontext.js":227,"./linkederrors.js":229,"./trycatch.js":230}],229:[function(require,module,exports){ 20274Object.defineProperty(exports, '__esModule', { value: true }); 20275 20276const core = require('@sentry/core'); 20277const utils = require('@sentry/utils'); 20278const eventbuilder = require('../eventbuilder.js'); 20279 20280const DEFAULT_KEY = 'cause'; 20281const DEFAULT_LIMIT = 5; 20282 20283const INTEGRATION_NAME = 'LinkedErrors'; 20284 20285const _linkedErrorsIntegration = ((options = {}) => { 20286 const limit = options.limit || DEFAULT_LIMIT; 20287 const key = options.key || DEFAULT_KEY; 20288 20289 return { 20290 name: INTEGRATION_NAME, 20291 // TODO v8: Remove this 20292 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 20293 preprocessEvent(event, hint, client) { 20294 const options = client.getOptions(); 20295 20296 utils.applyAggregateErrorsToEvent( 20297 // This differs from the LinkedErrors integration in core by using a different exceptionFromError function 20298 eventbuilder.exceptionFromError, 20299 options.stackParser, 20300 options.maxValueLength, 20301 key, 20302 limit, 20303 event, 20304 hint, 20305 ); 20306 }, 20307 }; 20308}) ; 20309 20310const linkedErrorsIntegration = core.defineIntegration(_linkedErrorsIntegration); 20311 20312/** 20313 * Aggregrate linked errors in an event. 20314 * @deprecated Use `linkedErrorsIntegration()` instead. 20315 */ 20316// eslint-disable-next-line deprecation/deprecation 20317const LinkedErrors = core.convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration) 20318 20319; 20320 20321exports.LinkedErrors = LinkedErrors; 20322exports.linkedErrorsIntegration = linkedErrorsIntegration; 20323 20324 20325},{"../eventbuilder.js":221,"@sentry/core":250,"@sentry/utils":319}],230:[function(require,module,exports){ 20326Object.defineProperty(exports, '__esModule', { value: true }); 20327 20328const core = require('@sentry/core'); 20329const utils = require('@sentry/utils'); 20330const helpers = require('../helpers.js'); 20331 20332const DEFAULT_EVENT_TARGET = [ 20333 'EventTarget', 20334 'Window', 20335 'Node', 20336 'ApplicationCache', 20337 'AudioTrackList', 20338 'BroadcastChannel', 20339 'ChannelMergerNode', 20340 'CryptoOperation', 20341 'EventSource', 20342 'FileReader', 20343 'HTMLUnknownElement', 20344 'IDBDatabase', 20345 'IDBRequest', 20346 'IDBTransaction', 20347 'KeyOperation', 20348 'MediaController',
20349 'MessagePort', 20350 'ModalWindow', 20351 'Notification', 20352 'SVGElementInstance', 20353 'Screen', 20354 'SharedWorker', 20355 'TextTrack', 20356 'TextTrackCue', 20357 'TextTrackList', 20358 'WebSocket', 20359 'WebSocketWorker', 20360 'Worker', 20361 'XMLHttpRequest', 20362 'XMLHttpRequestEventTarget', 20363 'XMLHttpRequestUpload', 20364]; 20365 20366const INTEGRATION_NAME = 'TryCatch'; 20367 20368const _browserApiErrorsIntegration = ((options = {}) => { 20369 const _options = { 20370 XMLHttpRequest: true, 20371 eventTarget: true, 20372 requestAnimationFrame: true, 20373 setInterval: true, 20374 setTimeout: true, 20375 ...options, 20376 }; 20377 20378 return { 20379 name: INTEGRATION_NAME, 20380 // TODO: This currently only works for the first client this is setup 20381 // We may want to adjust this to check for client etc. 20382 setupOnce() { 20383 if (_options.setTimeout) { 20384 utils.fill(helpers.WINDOW, 'setTimeout', _wrapTimeFunction); 20385 } 20386 20387 if (_options.setInterval) { 20388 utils.fill(helpers.WINDOW, 'setInterval', _wrapTimeFunction); 20389 } 20390 20391 if (_options.requestAnimationFrame) { 20392 utils.fill(helpers.WINDOW, 'requestAnimationFrame', _wrapRAF); 20393 } 20394 20395 if (_options.XMLHttpRequest && 'XMLHttpRequest' in helpers.WINDOW) { 20396 utils.fill(XMLHttpRequest.prototype, 'send', _wrapXHR); 20397 } 20398 20399 const eventTargetOption = _options.eventTarget; 20400 if (eventTargetOption) { 20401 const eventTarget = Array.isArray(eventTargetOption) ? eventTargetOption : DEFAULT_EVENT_TARGET; 20402 eventTarget.forEach(_wrapEventTarget); 20403 } 20404 }, 20405 }; 20406}) ; 20407 20408const browserApiErrorsIntegration = core.defineIntegration(_browserApiErrorsIntegration); 20409 20410/** 20411 * Wrap timer functions and event targets to catch errors and provide better meta data. 20412 * @deprecated Use `browserApiErrorsIntegration()` instead. 20413 */ 20414// eslint-disable-next-line deprecation/deprecation 20415const TryCatch = core.convertIntegrationFnToClass( 20416 INTEGRATION_NAME, 20417 browserApiErrorsIntegration, 20418) 20419 20420; 20421 20422function _wrapTimeFunction(original) { 20423 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20424 return function ( ...args) { 20425 const originalCallback = args[0]; 20426 args[0] = helpers.wrap(originalCallback, { 20427 mechanism: { 20428 data: { function: utils.getFunctionName(original) }, 20429 handled: false, 20430 type: 'instrument', 20431 }, 20432 }); 20433 return original.apply(this, args); 20434 }; 20435} 20436 20437// eslint-disable-next-line @typescript-eslint/no-explicit-any 20438function _wrapRAF(original) { 20439 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20440 return function ( callback) { 20441 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 20442 return original.apply(this, [ 20443 helpers.wrap(callback, { 20444 mechanism: { 20445 data: { 20446 function: 'requestAnimationFrame', 20447 handler: utils.getFunctionName(original), 20448 }, 20449 handled: false, 20450 type: 'instrument', 20451 }, 20452 }), 20453 ]); 20454 }; 20455} 20456 20457function _wrapXHR(originalSend) { 20458 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20459 return function ( ...args) { 20460 // eslint-disable-next-line @typescript-eslint/no-this-alias 20461 const xhr = this; 20462 const xmlHttpRequestProps = ['onload', 'onerror', 'onprogress', 'onreadystatechange']; 20463 20464 xmlHttpRequestProps.forEach(prop => { 20465 if (prop in xhr && typeof xhr[prop] === 'function') { 20466 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20467 utils.fill(xhr, prop, function (original) { 20468 const wrapOptions = { 20469 mechanism: { 20470 data: { 20471 function: prop, 20472 handler: utils.getFunctionName(original), 20473 }, 20474 handled: false, 20475 type: 'instrument', 20476 }, 20477 }; 20478 20479 // If Instrument integration has been called before TryCatch, get the name of original function 20480 const originalFunction = utils.getOriginalFunction(original); 20481 if (originalFunction) { 20482 wrapOptions.mechanism.data.handler = utils.getFunctionName(originalFunction); 20483 } 20484 20485 // Otherwise wrap directly 20486 return helpers.wrap(original, wrapOptions); 20487 }); 20488 } 20489 }); 20490 20491 return originalSend.apply(this, args); 20492 }; 20493} 20494 20495function _wrapEventTarget(target) { 20496 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20497 const globalObject = helpers.WINDOW ; 20498 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 20499 const proto = globalObject[target] && globalObject[target].prototype; 20500 20501 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins 20502 if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) { 20503 return; 20504 } 20505 20506 utils.fill(proto, 'addEventListener', function (original,) 20507 20508 { 20509 return function ( 20510 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20511 20512 eventName, 20513 fn, 20514 options, 20515 ) {
20516 try { 20517 if (typeof fn.handleEvent === 'function') { 20518 // ESlint disable explanation: 20519 // First, it is generally safe to call `wrap` with an unbound function. Furthermore, using `.bind()` would 20520 // introduce a bug here, because bind returns a new function that doesn't have our 20521 // flags(like __sentry_original__) attached. `wrap` checks for those flags to avoid unnecessary wrapping. 20522 // Without those flags, every call to addEventListener wraps the function again, causing a memory leak. 20523 // eslint-disable-next-line @typescript-eslint/unbound-method 20524 fn.handleEvent = helpers.wrap(fn.handleEvent, { 20525 mechanism: { 20526 data: { 20527 function: 'handleEvent', 20528 handler: utils.getFunctionName(fn), 20529 target, 20530 }, 20531 handled: false, 20532 type: 'instrument', 20533 }, 20534 }); 20535 } 20536 } catch (err) { 20537 // can sometimes get 'Permission denied to access property "handle Event' 20538 } 20539 20540 return original.apply(this, [ 20541 eventName, 20542 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20543 helpers.wrap(fn , { 20544 mechanism: { 20545 data: { 20546 function: 'addEventListener', 20547 handler: utils.getFunctionName(fn), 20548 target, 20549 }, 20550 handled: false, 20551 type: 'instrument', 20552 }, 20553 }), 20554 options, 20555 ]); 20556 }; 20557 }); 20558 20559 utils.fill( 20560 proto, 20561 'removeEventListener', 20562 function ( 20563 originalRemoveEventListener, 20564 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20565 ) { 20566 return function ( 20567 // eslint-disable-next-line @typescript-eslint/no-explicit-any 20568 20569 eventName, 20570 fn, 20571 options, 20572 ) { 20573 /** 20574 * There are 2 possible scenarios here: 20575 * 20576 * 1. Someone passes a callback, which was attached prior to Sentry initialization, or by using unmodified 20577 * method, eg. `document.addEventListener.call(el, name, handler). In this case, we treat this function 20578 * as a pass-through, and call original `removeEventListener` with it. 20579 * 20580 * 2. Someone passes a callback, which was attached after Sentry was initialized, which means that it was using 20581 * our wrapped version of `addEventListener`, which internally calls `wrap` helper. 20582 * This helper "wraps" whole callback inside a try/catch statement, and attached appropriate metadata to it, 20583 * in order for us to make a distinction between wrapped/non-wrapped functions possible. 20584 * If a function was wrapped, it has additional property of `__sentry_wrapped__`, holding the handler. 20585 * 20586 * When someone adds a handler prior to initialization, and then do it again, but after, 20587 * then we have to detach both of them. Otherwise, if we'd detach only wrapped one, it'd be impossible 20588 * to get rid of the initial handler and it'd stick there forever. 20589 */ 20590 const wrappedEventHandler = fn ; 20591 try { 20592 const originalEventHandler = wrappedEventHandler && wrappedEventHandler.__sentry_wrapped__; 20593 if (originalEventHandler) { 20594 originalRemoveEventListener.call(this, eventName, originalEventHandler, options); 20595 } 20596 } catch (e) { 20597 // ignore, accessing __sentry_wrapped__ will throw in some Selenium environments 20598 } 20599 return originalRemoveEventListener.call(this, eventName, wrappedEventHandler, options); 20600 }; 20601 }, 20602 ); 20603} 20604 20605exports.TryCatch = TryCatch; 20606exports.browserApiErrorsIntegration = browserApiErrorsIntegration; 20607 20608 20609},{"../helpers.js":222,"@sentry/core":250,"@sentry/utils":319}],231:[function(require,module,exports){ 20610Object.defineProperty(exports, '__esModule', { value: true }); 20611 20612const core = require('@sentry/core'); 20613const utils = require('@sentry/utils'); 20614const debugBuild = require('../debug-build.js'); 20615const helpers = require('../helpers.js'); 20616const utils$1 = require('./utils.js'); 20617 20618/* eslint-disable complexity */ 20619 20620/** 20621 * Safety wrapper for startTransaction for the unlikely case that transaction starts before tracing is imported - 20622 * if that happens we want to avoid throwing an error from profiling code. 20623 * see https://github.com/getsentry/sentry-javascript/issues/4731. 20624 * 20625 * @experimental 20626 */ 20627function onProfilingStartRouteTransaction(transaction) { 20628 if (!transaction) { 20629 if (debugBuild.DEBUG_BUILD) { 20630 utils.logger.log('[Profiling] Transaction is undefined, skipping profiling'); 20631 } 20632 return transaction; 20633 } 20634 20635 if (utils$1.shouldProfileTransaction(transaction)) { 20636 return startProfileForTransaction(transaction); 20637 } 20638 20639 return transaction; 20640} 20641 20642/** 20643 * Wraps startTransaction and stopTransaction with profiling related logic. 20644 * startProfileForTransaction is called after the call to startTransaction in order to avoid our own code from 20645 * being profiled. Because of that same reason, stopProfiling is called before the call to stopTransaction. 20646 */ 20647function startProfileForTransaction(transaction) { 20648 // Start the profiler and get the profiler instance. 20649 let startTimestamp; 20650 if (utils$1.isAutomatedPageLoadTransaction(transaction)) { 20651 startTimestamp = utils.timestampInSeconds() * 1000; 20652 } 20653 20654 const profiler = utils$1.startJSSelfProfile(); 20655 20656 // We failed to construct the profiler, fallback to original transaction. 20657 // No need to log anything as this has already been logged in startProfile. 20658 if (!profiler) { 20659 return transaction; 20660 } 20661 20662 if (debugBuild.DEBUG_BUILD) { 20663 utils.logger.log(`[Profiling] started profiling transaction: ${core.spanToJSON(transaction).description}`); 20664 } 20665 20666 // We create "unique" transaction names to avoid concurrent transactions with same names 20667 // from being ignored by the profiler. From here on, only this transaction name should be used when 20668 // calling the profiler methods. Note: we log the original name to the user to avoid confusion. 20669 const profileId = utils.uuid4(); 20670 20671 /** 20672 * Idempotent handler for profile stop 20673 */ 20674 async function onProfileHandler() { 20675 // Check if the profile exists and return it the behavior has to be idempotent as users may call transaction.finish multiple times. 20676 if (!transaction) { 20677 return null; 20678 } 20679 // Satisfy the type checker, but profiler will always be defined here. 20680 if (!profiler) { 20681 return null; 20682 } 20683 20684 return profiler 20685 .stop() 20686 .then((profile) => { 20687 if (maxDurationTimeoutID) { 20688 helpers.WINDOW.clearTimeout(maxDurationTimeoutID); 20689 maxDurationTimeoutID = undefined; 20690 } 20691 20692 if (debugBuild.DEBUG_BUILD) { 20693 utils.logger.log(`[Profiling] stopped profiling of transaction: ${core.spanToJSON(transaction).description}`); 20694 } 20695 20696 // In case of an overlapping transaction, stopProfiling may return null and silently ignore the overlapping profile. 20697 if (!profile) { 20698 if (debugBuild.DEBUG_BUILD) { 20699 utils.logger.log( 20700 `[Profiling] profiler returned null profile for: ${core.spanToJSON(transaction).description}`, 20701 'this may indicate an overlapping transaction or a call to stopProfiling with a profile title that was never started', 20702 ); 20703 } 20704 return null; 20705 } 20706 20707 utils$1.addProfileToGlobalCache(profileId, profile); 20708 return null; 20709 }) 20710 .catch(error => { 20711 if (debugBuild.DEBUG_BUILD) { 20712 utils.logger.log('[Profiling] error while stopping profiler:', error); 20713 } 20714 return null; 20715 }); 20716 } 20717 20718 // Enqueue a timeout to prevent profiles from running over max duration. 20719 let maxDurationTimeoutID = helpers.WINDOW.setTimeout(() => { 20720 if (debugBuild.DEBUG_BUILD) { 20721 utils.logger.log( 20722 '[Profiling] max profile duration elapsed, stopping profiling for:', 20723 core.spanToJSON(transaction).description, 20724 ); 20725 } 20726 // If the timeout exceeds, we want to stop profiling, but not finish the transaction 20727 // eslint-disable-next-line @typescript-eslint/no-floating-promises 20728 onProfileHandler(); 20729 }, utils$1.MAX_PROFILE_DURATION_MS); 20730 20731 // We need to reference the original end call to avoid creating an infinite loop 20732 const originalEnd = transaction.end.bind(transaction); 20733 20734 /** 20735 * Wraps startTransaction and stopTransaction with profiling related logic. 20736 * startProfiling is called after the call to startTransaction in order to avoid our own code from 20737 * being profiled. Because of that same reason, stopProfiling is called before the call to stopTransaction. 20738 */ 20739 function profilingWrappedTransactionEnd() { 20740 if (!transaction) { 20741 return originalEnd(); 20742 } 20743 // onProfileHandler should always return the same profile even if this is called multiple times. 20744 // Always call onProfileHandler to ensure stopProfiling is called and the timeout is cleared. 20745 void onProfileHandler().then( 20746 () => { 20747 // TODO: Can we rewrite this to use attributes? 20748 // eslint-disable-next-line deprecation/deprecation 20749 transaction.setContext('profile', { profile_id: profileId, start_timestamp: startTimestamp }); 20750 originalEnd(); 20751 }, 20752 () => { 20753 // If onProfileHandler fails, we still want to call the original finish method. 20754 originalEnd(); 20755 }, 20756 ); 20757 20758 return transaction; 20759 } 20760 20761 transaction.end = profilingWrappedTransactionEnd; 20762 return transaction; 20763} 20764 20765exports.onProfilingStartRouteTransaction = onProfilingStartRouteTransaction; 20766exports.startProfileForTransaction = startProfileForTransaction; 20767 20768 20769}
20769,{"../debug-build.js":220,"../helpers.js":222,"./utils.js":233,"@sentry/core":250,"@sentry/utils":319}],232:[function(require,module,exports){ 20770Object.defineProperty(exports, '__esModule', { value: true }); 20771 20772const core = require('@sentry/core'); 20773const utils$1 = require('@sentry/utils'); 20774const debugBuild = require('../debug-build.js'); 20775const hubextensions = require('./hubextensions.js'); 20776const utils = require('./utils.js'); 20777 20778const INTEGRATION_NAME = 'BrowserProfiling'; 20779 20780const _browserProfilingIntegration = (() => { 20781 return { 20782 name: INTEGRATION_NAME, 20783 // TODO v8: Remove this 20784 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 20785 setup(client) { 20786 const scope = core.getCurrentScope(); 20787 20788 // eslint-disable-next-line deprecation/deprecation 20789 const transaction = scope.getTransaction(); 20790 20791 if (transaction && utils.isAutomatedPageLoadTransaction(transaction)) { 20792 if (utils.shouldProfileTransaction(transaction)) { 20793 hubextensions.startProfileForTransaction(transaction); 20794 } 20795 } 20796 20797 if (typeof client.on !== 'function') { 20798 utils$1.logger.warn('[Profiling] Client does not support hooks, profiling will be disabled'); 20799 return; 20800 } 20801 20802 client.on('startTransaction', (transaction) => { 20803 if (utils.shouldProfileTransaction(transaction)) { 20804 hubextensions.startProfileForTransaction(transaction); 20805 } 20806 }); 20807 20808 client.on('beforeEnvelope', (envelope) => { 20809 // if not profiles are in queue, there is nothing to add to the envelope. 20810 if (!utils.getActiveProfilesCount()) { 20811 return; 20812 } 20813 20814 const profiledTransactionEvents = utils.findProfiledTransactionsFromEnvelope(envelope); 20815 if (!profiledTransactionEvents.length) { 20816 return; 20817 } 20818 20819 const profilesToAddToEnvelope = []; 20820 20821 for (const profiledTransaction of profiledTransactionEvents) { 20822 const context = profiledTransaction && profiledTransaction.contexts; 20823 const profile_id = context && context['profile'] && context['profile']['profile_id']; 20824 const start_timestamp = context && context['profile'] && context['profile']['start_timestamp']; 20825 20826 if (typeof profile_id !== 'string') { 20827 debugBuild.DEBUG_BUILD && utils$1.logger.log('[Profiling] cannot find profile for a transaction without a profile context'); 20828 continue; 20829 } 20830 20831 if (!profile_id) { 20832 debugBuild.DEBUG_BUILD && utils$1.logger.log('[Profiling] cannot find profile for a transaction without a profile context'); 20833 continue; 20834 } 20835 20836 // Remove the profile from the transaction context before sending, relay will take care of the rest. 20837 if (context && context['profile']) { 20838 delete context.profile; 20839 } 20840 20841 const profile = utils.takeProfileFromGlobalCache(profile_id); 20842 if (!profile) { 20843 debugBuild.DEBUG_BUILD && utils$1.logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`); 20844 continue; 20845 } 20846 20847 const profileEvent = utils.createProfilingEvent( 20848 profile_id, 20849 start_timestamp , 20850 profile, 20851 profiledTransaction , 20852 ); 20853 if (profileEvent) { 20854 profilesToAddToEnvelope.push(profileEvent); 20855 } 20856 } 20857 20858 utils.addProfilesToEnvelope(envelope , profilesToAddToEnvelope); 20859 }); 20860 }, 20861 }; 20862}) ; 20863 20864const browserProfilingIntegration = core.defineIntegration(_browserProfilingIntegration); 20865 20866/** 20867 * Browser profiling integration. Stores any event that has contexts["profile"]["profile_id"] 20868 * This exists because we do not want to await async profiler.stop calls as transaction.finish is called 20869 * in a synchronous context. Instead, we handle sending the profile async from the promise callback and 20870 * rely on being able to pull the event from the cache when we need to construct the envelope. This makes the 20871 * integration less reliable as we might be dropping profiles when the cache is full. 20872 * 20873 * @experimental 20874 * @deprecated Use `browserProfilingIntegration()` instead. 20875 */ 20876// eslint-disable-next-line deprecation/deprecation 20877const BrowserProfilingIntegration = core.convertIntegrationFnToClass( 20878 INTEGRATION_NAME, 20879 browserProfilingIntegration, 20880) ;
20881 20882// eslint-disable-next-line deprecation/deprecation 20883 20884exports.BrowserProfilingIntegration = BrowserProfilingIntegration; 20885exports.browserProfilingIntegration = browserProfilingIntegration; 20886 20887 20888},{"../debug-build.js":220,"./hubextensions.js":231,"./utils.js":233,"@sentry/core":250,"@sentry/utils":319}],233:[function(require,module,exports){ 20889Object.defineProperty(exports, '__esModule', { value: true }); 20890 20891const core = require('@sentry/core'); 20892const utils = require('@sentry/utils'); 20893const debugBuild = require('../debug-build.js'); 20894const helpers = require('../helpers.js'); 20895 20896/* eslint-disable max-lines */ 20897 20898const MS_TO_NS = 1e6; 20899// Use 0 as main thread id which is identical to threadId in node:worker_threads 20900// where main logs 0 and workers seem to log in increments of 1 20901const THREAD_ID_STRING = String(0); 20902const THREAD_NAME = 'main'; 20903 20904// Machine properties (eval only once) 20905let OS_PLATFORM = ''; 20906let OS_PLATFORM_VERSION = ''; 20907let OS_ARCH = ''; 20908let OS_BROWSER = (helpers.WINDOW.navigator && helpers.WINDOW.navigator.userAgent) || ''; 20909let OS_MODEL = ''; 20910const OS_LOCALE = 20911 (helpers.WINDOW.navigator && helpers.WINDOW.navigator.language) || 20912 (helpers.WINDOW.navigator && helpers.WINDOW.navigator.languages && helpers.WINDOW.navigator.languages[0]) || 20913 ''; 20914 20915function isUserAgentData(data) { 20916 return typeof data === 'object' && data !== null && 'getHighEntropyValues' in data; 20917} 20918 20919// @ts-expect-error userAgentData is not part of the navigator interface yet 20920const userAgentData = helpers.WINDOW.navigator && helpers.WINDOW.navigator.userAgentData; 20921 20922if (isUserAgentData(userAgentData)) { 20923 userAgentData 20924 .getHighEntropyValues(['architecture', 'model', 'platform', 'platformVersion', 'fullVersionList']) 20925 .then((ua) => { 20926 OS_PLATFORM = ua.platform || ''; 20927 OS_ARCH = ua.architecture || ''; 20928 OS_MODEL = ua.model || ''; 20929 OS_PLATFORM_VERSION = ua.platformVersion || ''; 20930 20931 if (ua.fullVersionList && ua.fullVersionList.length > 0) { 20932 const firstUa = ua.fullVersionList[ua.fullVersionList.length - 1]; 20933 OS_BROWSER = `${firstUa.brand} ${firstUa.version}`; 20934 } 20935 }) 20936 .catch(e => void e); 20937} 20938 20939function isProcessedJSSelfProfile(profile) { 20940 return !('thread_metadata' in profile); 20941} 20942 20943// Enriches the profile with threadId of the current thread. 20944// This is done in node as we seem to not be able to get the info from C native code. 20945/** 20946 * 20947 */ 20948function enrichWithThreadInformation(profile) { 20949 if (!isProcessedJSSelfProfile(profile)) { 20950 return profile; 20951 } 20952 20953 return convertJSSelfProfileToSampledFormat(profile); 20954} 20955 20956// Profile is marked as optional because it is deleted from the metadata 20957// by the integration before the event is processed by other integrations. 20958 20959function getTraceId(event) { 20960 const traceId = event && event.contexts && event.contexts['trace'] && event.contexts['trace']['trace_id']; 20961 // Log a warning if the profile has an invalid traceId (should be uuidv4). 20962 // All profiles and transactions are rejected if this is the case and we want to 20963 // warn users that this is happening if they enable debug flag 20964 if (typeof traceId === 'string' && traceId.length !== 32) { 20965 if (debugBuild.DEBUG_BUILD) { 20966 utils.logger.log(`[Profiling] Invalid traceId: ${traceId} on profiled event`); 20967 } 20968 } 20969 if (typeof traceId !== 'string') { 20970 return ''; 20971 } 20972 20973 return traceId; 20974} 20975/** 20976 * Creates a profiling event envelope from a Sentry event. If profile does not pass 20977 * validation, returns null. 20978 * @param event 20979 * @param dsn 20980 * @param metadata 20981 * @param tunnel 20982 * @returns {EventEnvelope | null} 20983 */ 20984 20985/** 20986 * Creates a profiling event envelope from a Sentry event. 20987 */ 20988function createProfilePayload( 20989 profile_id, 20990 start_timestamp, 20991 processed_profile, 20992 event, 20993) { 20994 if (event.type !== 'transaction') { 20995 // createProfilingEventEnvelope should only be called for transactions, 20996 // we type guard this behavior with isProfiledTransactionEvent. 20997 throw new TypeError('Profiling events may only be attached to transactions, this should never occur.'); 20998 } 20999 21000 if (processed_profile === undefined || processed_profile === null) { 21001 throw new TypeError( 21002 `Cannot construct profiling event envelope without a valid profile. Got ${processed_profile} instead.`, 21003 ); 21004 } 21005 21006 const traceId = getTraceId(event); 21007 const enrichedThreadProfile = enrichWithThreadInformation(processed_profile); 21008 const transactionStartMs = start_timestamp 21009 ? start_timestamp 21010 : typeof event.start_timestamp === 'number' 21011 ? event.start_timestamp * 1000 21012 : Date.now(); 21013 const transactionEndMs = typeof event.timestamp === 'number' ? event.timestamp * 1000 : Date.now(); 21014 21015 const profile = { 21016 event_id: profile_id, 21017 timestamp: new Date(transactionStartMs).toISOString(), 21018 platform: 'javascript', 21019 version: '1', 21020 release: event.release || '', 21021 environment: event.environment || core.DEFAULT_ENVIRONMENT, 21022 runtime: { 21023 name: 'javascript', 21024 version: helpers.WINDOW.navigator.userAgent, 21025 }, 21026 os: { 21027 name: OS_PLATFORM, 21028 version: OS_PLATFORM_VERSION, 21029 build_number: OS_BROWSER, 21030 }, 21031 device: { 21032 locale: OS_LOCALE,
21033 model: OS_MODEL, 21034 manufacturer: OS_BROWSER, 21035 architecture: OS_ARCH, 21036 is_emulator: false, 21037 }, 21038 debug_meta: { 21039 images: applyDebugMetadata(processed_profile.resources), 21040 }, 21041 profile: enrichedThreadProfile, 21042 transactions: [ 21043 { 21044 name: event.transaction || '', 21045 id: event.event_id || utils.uuid4(), 21046 trace_id: traceId, 21047 active_thread_id: THREAD_ID_STRING, 21048 relative_start_ns: '0', 21049 relative_end_ns: ((transactionEndMs - transactionStartMs) * 1e6).toFixed(0), 21050 }, 21051 ], 21052 }; 21053 21054 return profile; 21055} 21056 21057/* 21058 See packages/tracing-internal/src/browser/router.ts 21059*/ 21060/** 21061 * 21062 */ 21063function isAutomatedPageLoadTransaction(transaction) { 21064 return transaction.op === 'pageload'; 21065} 21066 21067/** 21068 * Converts a JSSelfProfile to a our sampled format. 21069 * Does not currently perform stack indexing. 21070 */ 21071function convertJSSelfProfileToSampledFormat(input) { 21072 let EMPTY_STACK_ID = undefined; 21073 let STACK_ID = 0; 21074 21075 // Initialize the profile that we will fill with data 21076 const profile = { 21077 samples: [], 21078 stacks: [], 21079 frames: [], 21080 thread_metadata: { 21081 [THREAD_ID_STRING]: { name: THREAD_NAME }, 21082 }, 21083 }; 21084 21085 if (!input.samples.length) { 21086 return profile; 21087 } 21088 21089 // We assert samples.length > 0 above and timestamp should always be present 21090 const start = input.samples[0].timestamp; 21091 // The JS SDK might change it's time origin based on some heuristic (see See packages/utils/src/time.ts) 21092 // when that happens, we need to ensure we are correcting the profile timings so the two timelines stay in sync. 21093 // Since JS self profiling time origin is always initialized to performance.timeOrigin, we need to adjust for 21094 // the drift between the SDK selected value and our profile time origin. 21095 const origin = 21096 typeof performance.timeOrigin === 'number' ? performance.timeOrigin : utils.browserPerformanceTimeOrigin || 0; 21097 const adjustForOriginChange = origin - (utils.browserPerformanceTimeOrigin || origin); 21098 21099 for (let i = 0; i < input.samples.length; i++) { 21100 const jsSample = input.samples[i]; 21101 21102 // If sample has no stack, add an empty sample 21103 if (jsSample.stackId === undefined) { 21104 if (EMPTY_STACK_ID === undefined) { 21105 EMPTY_STACK_ID = STACK_ID; 21106 profile.stacks[EMPTY_STACK_ID] = []; 21107 STACK_ID++; 21108 } 21109 21110 profile['samples'][i] = { 21111 // convert ms timestamp to ns 21112 elapsed_since_start_ns: ((jsSample.timestamp + adjustForOriginChange - start) * MS_TO_NS).toFixed(0), 21113 stack_id: EMPTY_STACK_ID, 21114 thread_id: THREAD_ID_STRING, 21115 }; 21116 continue; 21117 } 21118 21119 let stackTop = input.stacks[jsSample.stackId]; 21120 21121 // Functions in top->down order (root is last) 21122 // We follow the stackTop.parentId trail and collect each visited frameId 21123 const stack = []; 21124 21125 while (stackTop) { 21126 stack.push(stackTop.frameId); 21127 21128 const frame = input.frames[stackTop.frameId]; 21129 21130 // If our frame has not been indexed yet, index it 21131 if (profile.frames[stackTop.frameId] === undefined) { 21132 profile.frames[stackTop.frameId] = { 21133 function: frame.name, 21134 abs_path: typeof frame.resourceId === 'number' ? input.resources[frame.resourceId] : undefined, 21135 lineno: frame.line, 21136 colno: frame.column, 21137 }; 21138 } 21139 21140 stackTop = stackTop.parentId === undefined ? undefined : input.stacks[stackTop.parentId]; 21141 } 21142 21143 const sample = { 21144 // convert ms timestamp to ns 21145 elapsed_since_start_ns: ((jsSample.timestamp + adjustForOriginChange - start) * MS_TO_NS).toFixed(0), 21146 stack_id: STACK_ID, 21147 thread_id: THREAD_ID_STRING, 21148 }; 21149 21150 profile['stacks'][STACK_ID] = stack; 21151 profile['samples'][i] = sample; 21152 STACK_ID++; 21153 } 21154 21155 return profile; 21156} 21157 21158/** 21159 * Adds items to envelope if they are not already present - mutates the envelope. 21160 * @param envelope 21161 */ 21162function addProfilesToEnvelope(envelope, profiles) { 21163 if (!profiles.length) { 21164 return envelope; 21165 } 21166 21167 for (const profile of profiles) { 21168 envelope[1].push([{ type: 'profile' }, profile]); 21169 } 21170 return envelope; 21171} 21172 21173/** 21174 * Finds transactions with profile_id context in the envelope 21175 * @param envelope 21176 * @returns 21177 */ 21178function findProfiledTransactionsFromEnvelope(envelope) { 21179 const events = []; 21180
21181 utils.forEachEnvelopeItem(envelope, (item, type) => { 21182 if (type !== 'transaction') { 21183 return; 21184 } 21185 21186 for (let j = 1; j < item.length; j++) { 21187 const event = item[j] ; 21188 21189 if (event && event.contexts && event.contexts['profile'] && event.contexts['profile']['profile_id']) { 21190 events.push(item[j] ); 21191 } 21192 } 21193 }); 21194 21195 return events; 21196} 21197 21198const debugIdStackParserCache = new WeakMap(); 21199/** 21200 * Applies debug meta data to an event from a list of paths to resources (sourcemaps) 21201 */ 21202function applyDebugMetadata(resource_paths) { 21203 const debugIdMap = utils.GLOBAL_OBJ._sentryDebugIds; 21204 21205 if (!debugIdMap) { 21206 return []; 21207 } 21208 21209 const client = core.getClient(); 21210 const options = client && client.getOptions(); 21211 const stackParser = options && options.stackParser; 21212 21213 if (!stackParser) { 21214 return []; 21215 } 21216 21217 let debugIdStackFramesCache; 21218 const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser); 21219 if (cachedDebugIdStackFrameCache) { 21220 debugIdStackFramesCache = cachedDebugIdStackFrameCache; 21221 } else { 21222 debugIdStackFramesCache = new Map(); 21223 debugIdStackParserCache.set(stackParser, debugIdStackFramesCache); 21224 } 21225 21226 // Build a map of filename -> debug_id 21227 const filenameDebugIdMap = Object.keys(debugIdMap).reduce((acc, debugIdStackTrace) => { 21228 let parsedStack; 21229 21230 const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace); 21231 if (cachedParsedStack) { 21232 parsedStack = cachedParsedStack; 21233 } else { 21234 parsedStack = stackParser(debugIdStackTrace); 21235 debugIdStackFramesCache.set(debugIdStackTrace, parsedStack); 21236 } 21237 21238 for (let i = parsedStack.length - 1; i >= 0; i--) { 21239 const stackFrame = parsedStack[i]; 21240 const file = stackFrame && stackFrame.filename; 21241 21242 if (stackFrame && file) { 21243 acc[file] = debugIdMap[debugIdStackTrace] ; 21244 break; 21245 } 21246 } 21247 return acc; 21248 }, {}); 21249 21250 const images = []; 21251 for (const path of resource_paths) { 21252 if (path && filenameDebugIdMap[path]) { 21253 images.push({ 21254 type: 'sourcemap', 21255 code_file: path, 21256 debug_id: filenameDebugIdMap[path] , 21257 }); 21258 } 21259 } 21260 21261 return images; 21262} 21263 21264/** 21265 * Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1). 21266 */ 21267function isValidSampleRate(rate) { 21268 // we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck 21269 if ((typeof rate !== 'number' && typeof rate !== 'boolean') || (typeof rate === 'number' && isNaN(rate))) { 21270 debugBuild.DEBUG_BUILD && 21271 utils.logger.warn( 21272 `[Profiling] Invalid sample rate. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify( 21273 rate, 21274 )} of type ${JSON.stringify(typeof rate)}.`, 21275 ); 21276 return false; 21277 } 21278 21279 // Boolean sample rates are always valid 21280 if (rate === true || rate === false) { 21281 return true; 21282 } 21283 21284 // in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false 21285 if (rate < 0 || rate > 1) { 21286 debugBuild.DEBUG_BUILD && utils.logger.warn(`[Profiling] Invalid sample rate. Sample rate must be between 0 and 1. Got ${rate}.`); 21287 return false; 21288 } 21289 return true; 21290} 21291 21292function isValidProfile(profile) { 21293 if (profile.samples.length < 2) { 21294 if (debugBuild.DEBUG_BUILD) { 21295 // Log a warning if the profile has less than 2 samples so users can know why 21296 // they are not seeing any profiling data and we cant avoid the back and forth 21297 // of asking them to provide us with a dump of the profile data. 21298 utils.logger.log('[Profiling] Discarding profile because it contains less than 2 samples'); 21299 } 21300 return false; 21301 } 21302 21303 if (!profile.frames.length) { 21304 if (debugBuild.DEBUG_BUILD) { 21305 utils.logger.log('[Profiling] Discarding profile because it contains no frames'); 21306 } 21307 return false; 21308 } 21309 21310 return true; 21311} 21312 21313// Keep a flag value to avoid re-initializing the profiler constructor. If it fails 21314// once, it will always fail and this allows us to early return. 21315let PROFILING_CONSTRUCTOR_FAILED = false;
21316const MAX_PROFILE_DURATION_MS = 30000; 21317 21318/** 21319 * Check if profiler constructor is available. 21320 * @param maybeProfiler 21321 */ 21322function isJSProfilerSupported(maybeProfiler) { 21323 return typeof maybeProfiler === 'function'; 21324} 21325 21326/** 21327 * Starts the profiler and returns the profiler instance. 21328 */ 21329function startJSSelfProfile() { 21330 // Feature support check first 21331 const JSProfilerConstructor = helpers.WINDOW.Profiler; 21332 21333 if (!isJSProfilerSupported(JSProfilerConstructor)) { 21334 if (debugBuild.DEBUG_BUILD) { 21335 utils.logger.log( 21336 '[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.', 21337 ); 21338 } 21339 return; 21340 } 21341 21342 // From initial testing, it seems that the minimum value for sampleInterval is 10ms. 21343 const samplingIntervalMS = 10; 21344 // Start the profiler 21345 const maxSamples = Math.floor(MAX_PROFILE_DURATION_MS / samplingIntervalMS); 21346 21347 // Attempt to initialize the profiler constructor, if it fails, we disable profiling for the current user session. 21348 // This is likely due to a missing 'Document-Policy': 'js-profiling' header. We do not want to throw an error if this happens 21349 // as we risk breaking the user's application, so just disable profiling and log an error. 21350 try { 21351 return new JSProfilerConstructor({ sampleInterval: samplingIntervalMS, maxBufferSize: maxSamples }); 21352 } catch (e) { 21353 if (debugBuild.DEBUG_BUILD) { 21354 utils.logger.log( 21355 "[Profiling] Failed to initialize the Profiling constructor, this is likely due to a missing 'Document-Policy': 'js-profiling' header.", 21356 ); 21357 utils.logger.log('[Profiling] Disabling profiling for current user session.'); 21358 } 21359 PROFILING_CONSTRUCTOR_FAILED = true; 21360 } 21361 21362 return; 21363} 21364 21365/** 21366 * Determine if a profile should be profiled. 21367 */ 21368function shouldProfileTransaction(transaction) { 21369 // If constructor failed once, it will always fail, so we can early return. 21370 if (PROFILING_CONSTRUCTOR_FAILED) { 21371 if (debugBuild.DEBUG_BUILD) { 21372 utils.logger.log('[Profiling] Profiling has been disabled for the duration of the current user session.'); 21373 } 21374 return false; 21375 } 21376 21377 if (!transaction.isRecording()) { 21378 if (debugBuild.DEBUG_BUILD) { 21379 utils.logger.log('[Profiling] Discarding profile because transaction was not sampled.'); 21380 } 21381 return false; 21382 } 21383 21384 const client = core.getClient(); 21385 const options = client && client.getOptions(); 21386 if (!options) { 21387 debugBuild.DEBUG_BUILD && utils.logger.log('[Profiling] Profiling disabled, no options found.'); 21388 return false; 21389 } 21390 21391 // @ts-expect-error profilesSampleRate is not part of the browser options yet 21392 const profilesSampleRate = options.profilesSampleRate; 21393 21394 // Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The 21395 // only valid values are booleans or numbers between 0 and 1.) 21396 if (!isValidSampleRate(profilesSampleRate)) { 21397 debugBuild.DEBUG_BUILD && utils.logger.warn('[Profiling] Discarding profile because of invalid sample rate.'); 21398 return false; 21399 } 21400 21401 // if the function returned 0 (or false), or if `profileSampleRate` is 0, it's a sign the profile should be dropped 21402 if (!profilesSampleRate) { 21403 debugBuild.DEBUG_BUILD && 21404 utils.logger.log( 21405 '[Profiling] Discarding profile because a negative sampling decision was inherited or profileSampleRate is set to 0', 21406 ); 21407 return false; 21408 } 21409 21410 // Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is 21411 // a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false. 21412 const sampled = profilesSampleRate === true ? true : Math.random() < profilesSampleRate; 21413 // Check if we should sample this profile 21414 if (!sampled) { 21415 debugBuild.DEBUG_BUILD && 21416 utils.logger.log( 21417 `[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number( 21418 profilesSampleRate, 21419 )})`, 21420 ); 21421 return false; 21422 } 21423 21424 return true; 21425} 21426 21427/** 21428 * Creates a profiling envelope item, if the profile does not pass validation, returns null. 21429 * @param event 21430 * @returns {Profile | null} 21431 */ 21432function createProfilingEvent( 21433 profile_id, 21434 start_timestamp, 21435 profile, 21436 event, 21437) { 21438 if (!isValidProfile(profile)) { 21439 return null; 21440 } 21441 21442 return createProfilePayload(profile_id, start_timestamp, profile, event); 21443} 21444 21445// TODO (v8): We need to obtain profile ids in @sentry-internal/tracing, 21446// but we don't have access to this map because importing this map would 21447// cause a circular dependancy. We need to resolve this in v8. 21448const PROFILE_MAP = new Map(); 21449/** 21450 * 21451 */ 21452function getActiveProfilesCount() { 21453 return PROFILE_MAP.size; 21454} 21455 21456/** 21457 * Retrieves profile from global cache and removes it. 21458 */ 21459function takeProfileFromGlobalCache(profile_id) { 21460 const profile = PROFILE_MAP.get(profile_id); 21461 if (profile) { 21462 PROFILE_MAP.delete(profile_id); 21463 } 21464 return profile; 21465} 21466/** 21467 * Adds profile to global cache and evicts the oldest profile if the cache is full. 21468 */ 21469function addProfileToGlobalCache(profile_id, profile) { 21470 PROFILE_MAP.set(profile_id, profile); 21471 21472 if (PROFILE_MAP.size > 30) { 21473 const last = PROFILE_MAP.keys().next().value; 21474 PROFILE_MAP.delete(last); 21475 } 21476} 21477 21478exports.MAX_PROFILE_DURATION_MS = MAX_PROFILE_DURATION_MS; 21479exports.addProfileToGlobalCache = addProfileToGlobalCache; 21480exports.addProfilesToEnvelope = addProfilesToEnvelope; 21481exports.applyDebugMetadata = applyDebugMetadata; 21482exports.convertJSSelfProfileToSampledFormat = convertJSSelfProfileToSampledFormat; 21483exports.createProfilePayload = createProfilePayload; 21484exports.createProfilingEvent = createProfilingEvent; 21485exports.enrichWithThreadInformation = enrichWithThreadInformation; 21486exports.findProfiledTransactionsFromEnvelope = findProfiledTransactionsFromEnvelope; 21487exports.getActiveProfilesCount = getActiveProfilesCount; 21488exports.isAutomatedPageLoadTransaction = isAutomatedPageLoadTransaction; 21489exports.isValidSampleRate = isValidSampleRate; 21490exports.shouldProfileTransaction = shouldProfileTransaction; 21491exports.startJSSelfProfile = startJSSelfProfile; 21492exports.takeProfileFromGlobalCache = takeProfileFromGlobalCache; 21493 21494 21495},{"../debug-build.js":220,"../helpers.js":222,"@sentry/core":250,"@sentry/utils":319}],234:[function(require,module,exports){ 21496Object.defineProperty(exports, '__esModule', { value: true }); 21497 21498const core = require('@sentry/core'); 21499const utils = require('@sentry/utils'); 21500const client = require('./client.js'); 21501const debugBuild = require('./debug-build.js'); 21502const helpers = require('./helpers.js'); 21503const breadcrumbs = require('./integrations/breadcrumbs.js'); 21504const dedupe = require('./integrations/dedupe.js'); 21505const globalhandlers = require('./integrations/globalhandlers.js'); 21506const httpcontext = require('./integrations/httpcontext.js'); 21507const linkederrors = require('./integrations/linkederrors.js'); 21508const trycatch = require('./integrations/trycatch.js'); 21509const stackParsers = require('./stack-parsers.js'); 21510const fetch = require('./transports/fetch.js'); 21511const xhr = require('./transports/xhr.js'); 21512 21513/** @deprecated Use `getDefaultIntegrations(options)` instead. */ 21514const defaultIntegrations = [ 21515 core.inboundFiltersIntegration(), 21516 core.functionToStringIntegration(), 21517 trycatch.browserApiErrorsIntegration(), 21518 breadcrumbs.breadcrumbsIntegration(), 21519 globalhandlers.globalHandlersIntegration(), 21520 linkederrors.linkedErrorsIntegration(), 21521 dedupe.dedupeIntegration(), 21522 httpcontext.httpContextIntegration(), 21523]; 21524 21525/** Get the default integrations for the browser SDK. */ 21526function getDefaultIntegrations(_options) { 21527 // We return a copy of the defaultIntegrations here to avoid mutating this 21528 return [ 21529 // eslint-disable-next-line deprecation/deprecation 21530 ...defaultIntegrations, 21531 ]; 21532} 21533 21534/** 21535 * A magic string that build tooling can leverage in order to inject a release value into the SDK. 21536 */ 21537 21538/** 21539 * The Sentry Browser SDK Client. 21540 * 21541 * To use this SDK, call the {@link init} function as early as possible when 21542 * loading the web page. To set context information or send manual events, use 21543 * the provided methods. 21544 * 21545 * @example 21546 * 21547 * ``` 21548 * 21549 * import { init } from '@sentry/browser'; 21550 * 21551 * init({ 21552 * dsn: '__DSN__', 21553 * // ... 21554 * }); 21555 * ``` 21556 * 21557 * @example 21558 * ``` 21559 * 21560 * import { configureScope } from '@sentry/browser'; 21561 * configureScope((scope: Scope) => { 21562 * scope.setExtra({ battery: 0.7 }); 21563 * scope.setTag({ user_mode: 'admin' }); 21564 * scope.setUser({ id: '4711' }); 21565 * }); 21566 * ``` 21567 * 21568 * @example 21569 * ``` 21570 * 21571 * import { addBreadcrumb } from '@sentry/browser'; 21572 * addBreadcrumb({ 21573 * message: 'My Breadcrumb', 21574 * // ... 21575 * }); 21576 * ``` 21577 * 21578 * @example 21579 * 21580 * ``` 21581 * 21582 * import * as Sentry from '@sentry/browser'; 21583 * Sentry.captureMessage('Hello, world!'); 21584 * Sentry.captureException(new Error('Good bye')); 21585 * Sentry.captureEvent({ 21586 * message: 'Manual', 21587 * stacktrace: [ 21588 * // ... 21589 * ], 21590 * }); 21591 * ``` 21592 * 21593 * @see {@link BrowserOptions} for documentation on configuration options. 21594 */ 21595function init(options = {}) { 21596 if (options.defaultIntegrations === undefined) { 21597 options.defaultIntegrations = getDefaultIntegrations(); 21598 } 21599 if (options.release === undefined) { 21600 // This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value 21601 if (typeof __SENTRY_RELEASE__ === 'string') { 21602 options.release = __SENTRY_RELEASE__; 21603 } 21604 21605 // This supports the variable that sentry-webpack-plugin injects 21606 if (helpers.WINDOW.SENTRY_RELEASE && helpers.WINDOW.SENTRY_RELEASE.id) { 21607 options.release = helpers.WINDOW.SENTRY_RELEASE.id; 21608 } 21609 } 21610 if (options.autoSessionTracking === undefined) { 21611 options.autoSessionTracking = true; 21612 } 21613 if (options.sendClientReports === undefined) { 21614 options.sendClientReports = true; 21615 } 21616 21617 const clientOptions = { 21618 ...options, 21619 stackParser: utils.stackParserFromStackParserOptions(options.stackParser || stackParsers.defaultStackParser), 21620 integrations: core.getIntegrationsToSetup(options), 21621 transport: options.transport || (utils.supportsFetch() ? fetch.makeFetchTransport : xhr.makeXHRTransport), 21622 }; 21623 21624 core.initAndBind(client.BrowserClient, clientOptions); 21625 21626 if (options.autoSessionTracking) { 21627 startSessionTracking(); 21628 } 21629} 21630 21631const showReportDialog = ( 21632 // eslint-disable-next-line deprecation/deprecation 21633 options = {}, 21634 // eslint-disable-next-line deprecation/deprecation 21635 hub = core.getCurrentHub(), 21636) => { 21637 // doesn't work without a document (React Native) 21638 if (!helpers.WINDOW.document) { 21639 debugBuild.DEBUG_BUILD && utils.logger.error('Global document not defined in showReportDialog call'); 21640 return; 21641 } 21642 21643 // eslint-disable-next-line deprecation/deprecation 21644 const { client, scope } = hub.getStackTop();
21645 const dsn = options.dsn || (client && client.getDsn()); 21646 if (!dsn) { 21647 debugBuild.DEBUG_BUILD && utils.logger.error('DSN not configured for showReportDialog call'); 21648 return; 21649 } 21650 21651 if (scope) { 21652 options.user = { 21653 ...scope.getUser(), 21654 ...options.user, 21655 }; 21656 } 21657 21658 // TODO(v8): Remove this entire if statement. `eventId` will be a required option. 21659 // eslint-disable-next-line deprecation/deprecation 21660 if (!options.eventId) { 21661 // eslint-disable-next-line deprecation/deprecation 21662 options.eventId = hub.lastEventId(); 21663 } 21664 21665 const script = helpers.WINDOW.document.createElement('script'); 21666 script.async = true; 21667 script.crossOrigin = 'anonymous'; 21668 script.src = core.getReportDialogEndpoint(dsn, options); 21669 21670 if (options.onLoad) { 21671 script.onload = options.onLoad; 21672 } 21673 21674 const { onClose } = options; 21675 if (onClose) { 21676 const reportDialogClosedMessageHandler = (event) => { 21677 if (event.data === '__sentry_reportdialog_closed__') { 21678 try { 21679 onClose(); 21680 } finally { 21681 helpers.WINDOW.removeEventListener('message', reportDialogClosedMessageHandler); 21682 } 21683 } 21684 }; 21685 helpers.WINDOW.addEventListener('message', reportDialogClosedMessageHandler); 21686 } 21687 21688 const injectionPoint = helpers.WINDOW.document.head || helpers.WINDOW.document.body; 21689 if (injectionPoint) { 21690 injectionPoint.appendChild(script); 21691 } else { 21692 debugBuild.DEBUG_BUILD && utils.logger.error('Not injecting report dialog. No injection point found in HTML'); 21693 } 21694}; 21695 21696/** 21697 * This function is here to be API compatible with the loader. 21698 * @hidden 21699 */ 21700function forceLoad() { 21701 // Noop 21702} 21703 21704/** 21705 * This function is here to be API compatible with the loader. 21706 * @hidden 21707 */ 21708function onLoad(callback) { 21709 callback(); 21710} 21711 21712/** 21713 * Wrap code within a try/catch block so the SDK is able to capture errors. 21714 * 21715 * @deprecated This function will be removed in v8. 21716 * It is not part of Sentry's official API and it's easily replaceable by using a try/catch block 21717 * and calling Sentry.captureException. 21718 * 21719 * @param fn A function to wrap. 21720 * 21721 * @returns The result of wrapped function call. 21722 */ 21723// TODO(v8): Remove this function 21724// eslint-disable-next-line @typescript-eslint/no-explicit-any 21725function wrap(fn) { 21726 return helpers.wrap(fn)(); 21727} 21728 21729/** 21730 * Enable automatic Session Tracking for the initial page load. 21731 */ 21732function startSessionTracking() { 21733 if (typeof helpers.WINDOW.document === 'undefined') { 21734 debugBuild.DEBUG_BUILD && utils.logger.warn('Session tracking in non-browser environment with @sentry/browser is not supported.'); 21735 return; 21736 } 21737 21738 // The session duration for browser sessions does not track a meaningful 21739 // concept that can be used as a metric. 21740 // Automatically captured sessions are akin to page views, and thus we 21741 // discard their duration. 21742 core.startSession({ ignoreDuration: true }); 21743 core.captureSession(); 21744 21745 // We want to create a session for every navigation as well 21746 utils.addHistoryInstrumentationHandler(({ from, to }) => { 21747 // Don't create an additional session for the initial route or if the location did not change 21748 if (from !== undefined && from !== to) { 21749 core.startSession({ ignoreDuration: true }); 21750 core.captureSession(); 21751 } 21752 }); 21753} 21754 21755/** 21756 * Captures user feedback and sends it to Sentry. 21757 */ 21758function captureUserFeedback(feedback) { 21759 const client = core.getClient(); 21760 if (client) { 21761 client.captureUserFeedback(feedback); 21762 } 21763} 21764 21765exports.captureUserFeedback = captureUserFeedback; 21766exports.defaultIntegrations = defaultIntegrations; 21767exports.forceLoad = forceLoad; 21768exports.getDefaultIntegrations = getDefaultIntegrations; 21769exports.init = init; 21770exports.onLoad = onLoad; 21771exports.showReportDialog = showReportDialog; 21772exports.wrap = wrap; 21773 21774 21775},{"./client.js":219,"./debug-build.js":220,"./helpers.js":222,"./integrations/breadcrumbs.js":224,"./integrations/dedupe.js":225,"./integrations/globalhandlers.js":226,"./integrations/httpcontext.js":227,"./integrations/linkederrors.js":229,"./integrations/trycatch.js":230,"./stack-parsers.js":235,"./transports/fetch.js":236,"./transports/xhr.js":239,"@sentry/core":250,"@sentry/utils":319}],235:[function(require,module,exports){ 21776Object.defineProperty(exports, '__esModule', { value: true }); 21777 21778const utils = require('@sentry/utils'); 21779 21780// global reference to slice 21781const UNKNOWN_FUNCTION = '?'; 21782 21783const OPERA10_PRIORITY = 10; 21784const OPERA11_PRIORITY = 20; 21785const CHROME_PRIORITY = 30; 21786const WINJS_PRIORITY = 40; 21787const GECKO_PRIORITY = 50; 21788 21789function createFrame(filename, func, lineno, colno) { 21790 const frame = { 21791 filename, 21792 function: func, 21793 in_app: true, // All browser frames are considered in_app 21794 }; 21795 21796 if (lineno !== undefined) { 21797 frame.lineno = lineno; 21798 } 21799 21800 if (colno !== undefined) { 21801 frame.colno = colno; 21802 } 21803 21804 return frame; 21805} 21806 21807// Chromium based browsers: Chrome, Brave, new Opera, new Edge 21808const chromeRegex = 21809 /^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; 21810const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/; 21811 21812// We cannot call this variable `chrome` because it can conflict with global `chrome` variable in certain environments 21813// See: https://github.com/getsentry/sentry-javascript/issues/6880 21814const chromeStackParserFn = line => { 21815 const parts = chromeRegex.exec(line); 21816 21817 if (parts) { 21818 const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line 21819 21820 if (isEval) { 21821 const subMatch = chromeEvalRegex.exec(parts[2]); 21822 21823 if (subMatch) { 21824 // throw out eval line/column and use top-most line/column number 21825 parts[2] = subMatch[1]; // url 21826 parts[3] = subMatch[2]; // line 21827 parts[4] = subMatch[3]; // column 21828 } 21829 } 21830 21831 // Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now 21832 // would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable)
21833 const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]); 21834 21835 return createFrame(filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined); 21836 } 21837 21838 return; 21839}; 21840 21841const chromeStackLineParser = [CHROME_PRIORITY, chromeStackParserFn]; 21842 21843// gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it 21844// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js 21845// We need this specific case for now because we want no other regex to match. 21846const geckoREgex = 21847 /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i; 21848const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i; 21849 21850const gecko = line => { 21851 const parts = geckoREgex.exec(line); 21852 21853 if (parts) { 21854 const isEval = parts[3] && parts[3].indexOf(' > eval') > -1; 21855 if (isEval) { 21856 const subMatch = geckoEvalRegex.exec(parts[3]); 21857 21858 if (subMatch) { 21859 // throw out eval line/column and use top-most line number 21860 parts[1] = parts[1] || 'eval'; 21861 parts[3] = subMatch[1]; 21862 parts[4] = subMatch[2]; 21863 parts[5] = ''; // no column when eval 21864 } 21865 } 21866 21867 let filename = parts[3]; 21868 let func = parts[1] || UNKNOWN_FUNCTION; 21869 [func, filename] = extractSafariExtensionDetails(func, filename); 21870 21871 return createFrame(filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined); 21872 } 21873 21874 return; 21875}; 21876 21877const geckoStackLineParser = [GECKO_PRIORITY, gecko]; 21878 21879const winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i; 21880 21881const winjs = line => { 21882 const parts = winjsRegex.exec(line); 21883 21884 return parts 21885 ? createFrame(parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined) 21886 : undefined; 21887}; 21888 21889const winjsStackLineParser = [WINJS_PRIORITY, winjs]; 21890 21891const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i; 21892 21893const opera10 = line => { 21894 const parts = opera10Regex.exec(line); 21895 return parts ? createFrame(parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined; 21896}; 21897 21898const opera10StackLineParser = [OPERA10_PRIORITY, opera10]; 21899 21900const opera11Regex = 21901 / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i; 21902 21903const opera11 = line => { 21904 const parts = opera11Regex.exec(line); 21905 return parts ? createFrame(parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined; 21906}; 21907 21908const opera11StackLineParser = [OPERA11_PRIORITY, opera11]; 21909 21910const defaultStackLineParsers = [chromeStackLineParser, geckoStackLineParser, winjsStackLineParser]; 21911 21912const defaultStackParser = utils.createStackParser(...defaultStackLineParsers); 21913 21914/** 21915 * Safari web extensions, starting version unknown, can produce "frames-only" stacktraces. 21916 * What it means, is that instead of format like: 21917 * 21918 * Error: wat 21919 * at function@url:row:col 21920 * at function@url:row:col 21921 * at function@url:row:col 21922 * 21923 * it produces something like: 21924 * 21925 * function@url:row:col 21926 * function@url:row:col 21927 * function@url:row:col 21928 * 21929 * Because of that, it won't be captured by `chrome` RegExp and will fall into `Gecko` branch. 21930 * This function is extracted so that we can use it in both places without duplicating the logic. 21931 * Unfortunately "just" changing RegExp is too complicated now and making it pass all tests 21932 * and fix this case seems like an impossible, or at least way too time-consuming task. 21933 */ 21934const extractSafariExtensionDetails = (func, filename) => { 21935 const isSafariExtension = func.indexOf('safari-extension') !== -1; 21936 const isSafariWebExtension = func.indexOf('safari-web-extension') !== -1; 21937 21938 return isSafariExtension || isSafariWebExtension 21939 ? [ 21940 func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION, 21941 isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`, 21942 ] 21943 : [func, filename]; 21944}; 21945 21946exports.chromeStackLineParser = chromeStackLineParser; 21947exports.defaultStackLineParsers = defaultStackLineParsers; 21948exports.defaultStackParser = defaultStackParser; 21949exports.geckoStackLineParser = geckoStackLineParser; 21950exports.opera10StackLineParser = opera10StackLineParser; 21951exports.opera11StackLineParser = opera11StackLineParser; 21952exports.winjsStackLineParser = winjsStackLineParser; 21953 21954 21955},{"@sentry/utils":319}],236:[function(require,module,exports){ 21956Object.defineProperty(exports, '__esModule', { value: true }); 21957 21958const core = require('@sentry/core'); 21959const utils$1 = require('@sentry/utils'); 21960const utils = require('./utils.js'); 21961 21962/** 21963 * Creates a Transport that uses the Fetch API to send events to Sentry. 21964 */ 21965function makeFetchTransport( 21966 options, 21967 nativeFetch = utils.getNativeFetchImplementation(), 21968) { 21969 let pendingBodySize = 0; 21970 let pendingCount = 0; 21971
21972 function makeRequest(request) { 21973 const requestSize = request.body.length; 21974 pendingBodySize += requestSize; 21975 pendingCount++; 21976 21977 const requestOptions = { 21978 body: request.body, 21979 method: 'POST', 21980 referrerPolicy: 'origin', 21981 headers: options.headers, 21982 // Outgoing requests are usually cancelled when navigating to a different page, causing a "TypeError: Failed to 21983 // fetch" error and sending a "network_error" client-outcome - in Chrome, the request status shows "(cancelled)". 21984 // The `keepalive` flag keeps outgoing requests alive, even when switching pages. We want this since we're 21985 // frequently sending events right before the user is switching pages (eg. whenfinishing navigation transactions). 21986 // Gotchas: 21987 // - `keepalive` isn't supported by Firefox 21988 // - As per spec (https://fetch.spec.whatwg.org/#http-network-or-cache-fetch): 21989 // If the sum of contentLength and inflightKeepaliveBytes is greater than 64 kibibytes, then return a network error. 21990 // We will therefore only activate the flag when we're below that limit. 21991 // There is also a limit of requests that can be open at the same time, so we also limit this to 15 21992 // See https://github.com/getsentry/sentry-javascript/pull/7553 for details 21993 keepalive: pendingBodySize <= 60000 && pendingCount < 15, 21994 ...options.fetchOptions, 21995 }; 21996 21997 try { 21998 return nativeFetch(options.url, requestOptions).then(response => { 21999 pendingBodySize -= requestSize; 22000 pendingCount--; 22001 return { 22002 statusCode: response.status, 22003 headers: {
22004 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'), 22005 'retry-after': response.headers.get('Retry-After'), 22006 }, 22007 }; 22008 }); 22009 } catch (e) { 22010 utils.clearCachedFetchImplementation(); 22011 pendingBodySize -= requestSize; 22012 pendingCount--; 22013 return utils$1.rejectedSyncPromise(e); 22014 } 22015 } 22016 22017 return core.createTransport(options, makeRequest); 22018} 22019 22020exports.makeFetchTransport = makeFetchTransport; 22021 22022 22023},{"./utils.js":238,"@sentry/core":250,"@sentry/utils":319}],237:[function(require,module,exports){ 22024Object.defineProperty(exports, '__esModule', { value: true }); 22025 22026const core = require('@sentry/core'); 22027const utils = require('@sentry/utils'); 22028 22029// 'Store', 'promisifyRequest' and 'createStore' were originally copied from the 'idb-keyval' package before being 22030// modified and simplified: https://github.com/jakearchibald/idb-keyval 22031// 22032// At commit: 0420a704fd6cbb4225429c536b1f61112d012fca 22033// Original licence: 22034 22035// Copyright 2016, Jake Archibald 22036// 22037// Licensed under the Apache License, Version 2.0 (the "License"); 22038// you may not use this file except in compliance with the License. 22039// You may obtain a copy of the License at 22040// 22041// http://www.apache.org/licenses/LICENSE-2.0 22042// 22043// Unless required by applicable law or agreed to in writing, software 22044// distributed under the License is distributed on an "AS IS" BASIS, 22045// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22046// See the License for the specific language governing permissions and 22047// limitations under the License. 22048 22049function promisifyRequest(request) { 22050 return new Promise((resolve, reject) => { 22051 // @ts-expect-error - file size hacks 22052 request.oncomplete = request.onsuccess = () => resolve(request.result); 22053 // @ts-expect-error - file size hacks 22054 request.onabort = request.onerror = () => reject(request.error); 22055 }); 22056} 22057 22058/** Create or open an IndexedDb store */ 22059function createStore(dbName, storeName) { 22060 const request = indexedDB.open(dbName); 22061 request.onupgradeneeded = () => request.result.createObjectStore(storeName); 22062 const dbp = promisifyRequest(request); 22063 22064 return callback => dbp.then(db => callback(db.transaction(storeName, 'readwrite').objectStore(storeName))); 22065} 22066 22067function keys(store) { 22068 return promisifyRequest(store.getAllKeys() ); 22069} 22070 22071/** Insert into the store */ 22072function insert(store, value, maxQueueSize) { 22073 return store(store => { 22074 return keys(store).then(keys => { 22075 if (keys.length >= maxQueueSize) { 22076 return; 22077 } 22078 22079 // We insert with an incremented key so that the entries are popped in order 22080 store.put(value, Math.max(...keys, 0) + 1); 22081 return promisifyRequest(store.transaction); 22082 }); 22083 }); 22084} 22085 22086/** Pop the oldest value from the store */ 22087function pop(store) { 22088 return store(store => { 22089 return keys(store).then(keys => { 22090 if (keys.length === 0) { 22091 return undefined; 22092 } 22093 22094 return promisifyRequest(store.get(keys[0])).then(value => { 22095 store.delete(keys[0]); 22096 return promisifyRequest(store.transaction).then(() => value); 22097 }); 22098 }); 22099 }); 22100} 22101 22102function createIndexedDbStore(options) { 22103 let store; 22104 22105 // Lazily create the store only when it's needed 22106 function getStore() { 22107 if (store == undefined) { 22108 store = createStore(options.dbName || 'sentry-offline', options.storeName || 'queue'); 22109 } 22110 22111 return store; 22112 } 22113 22114 return { 22115 insert: async (env) => { 22116 try { 22117 const serialized = await utils.serializeEnvelope(env, options.textEncoder); 22118 await insert(getStore(), serialized, options.maxQueueSize || 30); 22119 } catch (_) { 22120 // 22121 } 22122 }, 22123 pop: async () => { 22124 try { 22125 const deserialized = await pop(getStore()); 22126 if (deserialized) { 22127 return utils.parseEnvelope( 22128 deserialized, 22129 options.textEncoder || new TextEncoder(), 22130 options.textDecoder || new TextDecoder(), 22131 ); 22132 } 22133 } catch (_) { 22134 // 22135 } 22136 22137 return undefined; 22138 }, 22139 }; 22140} 22141 22142function makeIndexedDbOfflineTransport( 22143 createTransport, 22144) { 22145 return options => createTransport({ ...options, createStore: createIndexedDbStore }); 22146} 22147 22148/** 22149 * Creates a transport that uses IndexedDb to store events when offline. 22150 */ 22151function makeBrowserOfflineTransport( 22152 createTransport, 22153) { 22154 return makeIndexedDbOfflineTransport(core.makeOfflineTransport(createTransport)); 22155} 22156 22157exports.createStore = createStore; 22158exports.insert = insert; 22159exports.makeBrowserOfflineTransport = makeBrowserOfflineTransport; 22160exports.pop = pop; 22161 22162 22163},{"@sentry/core":250,"@sentry/utils":319}],238:[function(require,module,exports){ 22164Object.defineProperty(exports, '__esModule', { value: true }); 22165 22166const utils = require('@sentry/utils'); 22167const debugBuild = require('../debug-build.js'); 22168const helpers = require('../helpers.js'); 22169 22170let cachedFetchImpl = undefined; 22171 22172/** 22173 * A special usecase for incorrectly wrapped Fetch APIs in conjunction with ad-blockers. 22174 * Whenever someone wraps the Fetch API and returns the wrong promise chain, 22175 * this chain becomes orphaned and there is no possible way to capture it's rejections 22176 * other than allowing it bubble up to this very handler. eg. 22177 * 22178 * const f = window.fetch; 22179 * window.fetch = function () { 22180 * const p = f.apply(this, arguments); 22181 * 22182 * p.then(function() { 22183 * console.log('hi.'); 22184 * }); 22185 * 22186 * return p; 22187 * } 22188 * 22189 * `p.then(function () { ... })` is producing a completely separate promise chain, 22190 * however, what's returned is `p` - the result of original `fetch` call. 22191 * 22192 * This mean, that whenever we use the Fetch API to send our own requests, _and_ 22193 * some ad-blocker blocks it, this orphaned chain will _always_ reject, 22194 * effectively causing another event to be captured. 22195 * This makes a whole process become an infinite loop, which we need to somehow 22196 * deal with, and break it in one way or another. 22197 * 22198 * To deal with this issue, we are making sure that we _always_ use the real 22199 * browser Fetch API, instead of relying on what `window.fetch` exposes. 22200 * The only downside to this would be missing our own requests as breadcrumbs, 22201 * but because we are already not doing this, it should be just fine. 22202 * 22203 * Possible failed fetch error messages per-browser: 22204 * 22205 * Chrome: Failed to fetch 22206 * Edge: Failed to Fetch 22207 * Firefox: NetworkError when attempting to fetch resource 22208 * Safari: resource blocked by content blocker 22209 */ 22210function getNativeFetchImplementation() { 22211 if (cachedFetchImpl) { 22212 return cachedFetchImpl; 22213 } 22214
22215 /* eslint-disable @typescript-eslint/unbound-method */ 22216 22217 // Fast path to avoid DOM I/O 22218 if (utils.isNativeFetch(helpers.WINDOW.fetch)) { 22219 return (cachedFetchImpl = helpers.WINDOW.fetch.bind(helpers.WINDOW)); 22220 } 22221 22222 const document = helpers.WINDOW.document; 22223 let fetchImpl = helpers.WINDOW.fetch; 22224 // eslint-disable-next-line deprecation/deprecation 22225 if (document && typeof document.createElement === 'function') { 22226 try { 22227 const sandbox = document.createElement('iframe'); 22228 sandbox.hidden = true; 22229 document.head.appendChild(sandbox); 22230 const contentWindow = sandbox.contentWindow; 22231 if (contentWindow && contentWindow.fetch) { 22232 fetchImpl = contentWindow.fetch; 22233 } 22234 document.head.removeChild(sandbox); 22235 } catch (e) { 22236 debugBuild.DEBUG_BUILD && utils.logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', e); 22237 } 22238 } 22239 22240 return (cachedFetchImpl = fetchImpl.bind(helpers.WINDOW)); 22241 /* eslint-enable @typescript-eslint/unbound-method */ 22242} 22243 22244/** Clears cached fetch impl */ 22245function clearCachedFetchImplementation() { 22246 cachedFetchImpl = undefined; 22247} 22248 22249exports.clearCachedFetchImplementation = clearCachedFetchImplementation; 22250exports.getNativeFetchImplementation = getNativeFetchImplementation; 22251 22252 22253},{"../debug-build.js":220,"../helpers.js":222,"@sentry/utils":319}],239:[function(require,module,exports){ 22254Object.defineProperty(exports, '__esModule', { value: true }); 22255 22256const core = require('@sentry/core'); 22257const utils = require('@sentry/utils'); 22258 22259/** 22260 * The DONE ready state for XmlHttpRequest 22261 * 22262 * Defining it here as a constant b/c XMLHttpRequest.DONE is not always defined 22263 * (e.g. during testing, it is `undefined`) 22264 * 22265 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState} 22266 */ 22267const XHR_READYSTATE_DONE = 4; 22268 22269/** 22270 * Creates a Transport that uses the XMLHttpRequest API to send events to Sentry. 22271 */ 22272function makeXHRTransport(options) { 22273 function makeRequest(request) { 22274 return new utils.SyncPromise((resolve, reject) => { 22275 const xhr = new XMLHttpRequest(); 22276 22277 xhr.onerror = reject; 22278 22279 xhr.onreadystatechange = () => { 22280 if (xhr.readyState === XHR_READYSTATE_DONE) { 22281 resolve({ 22282 statusCode: xhr.status, 22283 headers: {
22284 'x-sentry-rate-limits': xhr.getResponseHeader('X-Sentry-Rate-Limits'), 22285 'retry-after': xhr.getResponseHeader('Retry-After'), 22286 }, 22287 }); 22288 } 22289 }; 22290 22291 xhr.open('POST', options.url); 22292 22293 for (const header in options.headers) { 22294 if (Object.prototype.hasOwnProperty.call(options.headers, header)) { 22295 xhr.setRequestHeader(header, options.headers[header]); 22296 } 22297 } 22298 22299 xhr.send(request.body); 22300 }); 22301 } 22302 22303 return core.createTransport(options, makeRequest); 22304} 22305 22306exports.makeXHRTransport = makeXHRTransport; 22307 22308 22309},{"@sentry/core":250,"@sentry/utils":319}],240:[function(require,module,exports){ 22310Object.defineProperty(exports, '__esModule', { value: true }); 22311 22312const utils = require('@sentry/utils'); 22313 22314/** 22315 * Creates an envelope from a user feedback. 22316 */ 22317function createUserFeedbackEnvelope( 22318 feedback, 22319 { 22320 metadata, 22321 tunnel, 22322 dsn, 22323 } 22324 22325, 22326) { 22327 const headers = { 22328 event_id: feedback.event_id, 22329 sent_at: new Date().toISOString(), 22330 ...(metadata && 22331 metadata.sdk && { 22332 sdk: { 22333 name: metadata.sdk.name, 22334 version: metadata.sdk.version, 22335 }, 22336 }), 22337 ...(!!tunnel && !!dsn && { dsn: utils.dsnToString(dsn) }), 22338 }; 22339 const item = createUserFeedbackEnvelopeItem(feedback); 22340 22341 return utils.createEnvelope(headers, [item]); 22342} 22343 22344function createUserFeedbackEnvelopeItem(feedback) { 22345 const feedbackHeaders = { 22346 type: 'user_report', 22347 }; 22348 return [feedbackHeaders, feedback]; 22349} 22350 22351exports.createUserFeedbackEnvelope = createUserFeedbackEnvelope; 22352 22353 22354},{"@sentry/utils":319}],241:[function(require,module,exports){ 22355Object.defineProperty(exports, '__esModule', { value: true }); 22356 22357const utils = require('@sentry/utils'); 22358 22359const SENTRY_API_VERSION = '7'; 22360 22361/** Returns the prefix to construct Sentry ingestion API endpoints. */ 22362function getBaseApiEndpoint(dsn) { 22363 const protocol = dsn.protocol ? `${dsn.protocol}:` : ''; 22364 const port = dsn.port ? `:${dsn.port}` : ''; 22365 return `${protocol}//${dsn.host}${port}${dsn.path ? `/${dsn.path}` : ''}/api/`; 22366} 22367 22368/** Returns the ingest API endpoint for target. */ 22369function _getIngestEndpoint(dsn) { 22370 return `${getBaseApiEndpoint(dsn)}${dsn.projectId}/envelope/`; 22371} 22372 22373/** Returns a URL-encoded string with auth config suitable for a query string. */ 22374function _encodedAuth(dsn, sdkInfo) { 22375 return utils.urlEncode({ 22376 // We send only the minimum set of required information. See 22377 // https://github.com/getsentry/sentry-javascript/issues/2572. 22378 sentry_key: dsn.publicKey, 22379 sentry_version: SENTRY_API_VERSION, 22380 ...(sdkInfo && { sentry_client: `${sdkInfo.name}/${sdkInfo.version}` }), 22381 }); 22382} 22383 22384/** 22385 * Returns the envelope endpoint URL with auth in the query string. 22386 * 22387 * Sending auth as part of the query string and not as custom HTTP headers avoids CORS preflight requests. 22388 */ 22389function getEnvelopeEndpointWithUrlEncodedAuth( 22390 dsn, 22391 // TODO (v8): Remove `tunnelOrOptions` in favor of `options`, and use the substitute code below 22392 // options: ClientOptions = {} as ClientOptions, 22393 tunnelOrOptions = {} , 22394) { 22395 // TODO (v8): Use this code instead 22396 // const { tunnel, _metadata = {} } = options; 22397 // return tunnel ? tunnel : `${_getIngestEndpoint(dsn)}?${_encodedAuth(dsn, _metadata.sdk)}`; 22398 22399 const tunnel = typeof tunnelOrOptions === 'string' ? tunnelOrOptions : tunnelOrOptions.tunnel; 22400 const sdkInfo = 22401 typeof tunnelOrOptions === 'string' || !tunnelOrOptions._metadata ? undefined : tunnelOrOptions._metadata.sdk; 22402 22403 return tunnel ? tunnel : `${_getIngestEndpoint(dsn)}?${_encodedAuth(dsn, sdkInfo)}`; 22404} 22405 22406/** Returns the url to the report dialog endpoint. */ 22407function getReportDialogEndpoint( 22408 dsnLike, 22409 dialogOptions 22410 22411, 22412) { 22413 const dsn = utils.makeDsn(dsnLike); 22414 if (!dsn) { 22415 return ''; 22416 } 22417 22418 const endpoint = `${getBaseApiEndpoint(dsn)}embed/error-page/`; 22419 22420 let encodedOptions = `dsn=${utils.dsnToString(dsn)}`; 22421 for (const key in dialogOptions) { 22422 if (key === 'dsn') { 22423 continue; 22424 } 22425 22426 if (key === 'onClose') { 22427 continue; 22428 } 22429 22430 if (key === 'user') { 22431 const user = dialogOptions.user; 22432 if (!user) { 22433 continue; 22434 } 22435 if (user.name) { 22436 encodedOptions += `&name=${encodeURIComponent(user.name)}
22436`; 22437 } 22438 if (user.email) { 22439 encodedOptions += `&email=${encodeURIComponent(user.email)}`; 22440 } 22441 } else { 22442 encodedOptions += `&${encodeURIComponent(key)}=${encodeURIComponent(dialogOptions[key] )}`; 22443 } 22444 } 22445 22446 return `${endpoint}?${encodedOptions}`; 22447} 22448 22449exports.getEnvelopeEndpointWithUrlEncodedAuth = getEnvelopeEndpointWithUrlEncodedAuth; 22450exports.getReportDialogEndpoint = getReportDialogEndpoint; 22451 22452 22453},{"@sentry/utils":319}],242:[function(require,module,exports){ 22454Object.defineProperty(exports, '__esModule', { value: true }); 22455 22456const utils = require('@sentry/utils'); 22457const api = require('./api.js'); 22458const debugBuild = require('./debug-build.js'); 22459const envelope = require('./envelope.js'); 22460const exports$1 = require('./exports.js'); 22461const hub = require('./hub.js'); 22462const integration = require('./integration.js'); 22463const envelope$1 = require('./metrics/envelope.js'); 22464const session = require('./session.js'); 22465const dynamicSamplingContext = require('./tracing/dynamicSamplingContext.js'); 22466const prepareEvent = require('./utils/prepareEvent.js'); 22467 22468const ALREADY_SEEN_ERROR = "Not capturing exception because it's already been captured."; 22469 22470/** 22471 * Base implementation for all JavaScript SDK clients. 22472 * 22473 * Call the constructor with the corresponding options 22474 * specific to the client subclass. To access these options later, use 22475 * {@link Client.getOptions}. 22476 * 22477 * If a Dsn is specified in the options, it will be parsed and stored. Use 22478 * {@link Client.getDsn} to retrieve the Dsn at any moment. In case the Dsn is 22479 * invalid, the constructor will throw a {@link SentryException}. Note that 22480 * without a valid Dsn, the SDK will not send any events to Sentry. 22481 * 22482 * Before sending an event, it is passed through 22483 * {@link BaseClient._prepareEvent} to add SDK information and scope data 22484 * (breadcrumbs and context). To add more custom information, override this 22485 * method and extend the resulting prepared event. 22486 * 22487 * To issue automatically created events (e.g. via instrumentation), use 22488 * {@link Client.captureEvent}. It will prepare the event and pass it through 22489 * the callback lifecycle. To issue auto-breadcrumbs, use 22490 * {@link Client.addBreadcrumb}. 22491 * 22492 * @example 22493 * class NodeClient extends BaseClient<NodeOptions> { 22494 * public constructor(options: NodeOptions) { 22495 * super(options); 22496 * } 22497 * 22498 * // ... 22499 * } 22500 */ 22501class BaseClient { 22502 /** 22503 * A reference to a metrics aggregator 22504 * 22505 * @experimental Note this is alpha API. It may experience breaking changes in the future. 22506 */ 22507 22508 /** Options passed to the SDK. */ 22509 22510 /** The client Dsn, if specified in options. Without this Dsn, the SDK will be disabled. */ 22511 22512 /** Array of set up integrations. */ 22513 22514 /** Indicates whether this client's integrations have been set up. */ 22515 22516 /** Number of calls being processed */ 22517 22518 /** Holds flushable */ 22519 22520 // eslint-disable-next-line @typescript-eslint/ban-types 22521 22522 /** 22523 * Initializes this client instance. 22524 * 22525 * @param options Options for the client. 22526 */ 22527 constructor(options) { 22528 this._options = options; 22529 this._integrations = {}; 22530 this._integrationsInitialized = false; 22531 this._numProcessing = 0; 22532 this._outcomes = {}; 22533 this._hooks = {}; 22534 this._eventProcessors = []; 22535 22536 if (options.dsn) { 22537 this._dsn = utils.makeDsn(options.dsn); 22538 } else { 22539 debugBuild.DEBUG_BUILD && utils.logger.warn('No DSN provided, client will not send events.'); 22540 } 22541 22542 if (this._dsn) { 22543 const url = api.getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, options); 22544 this._transport = options.transport({ 22545 recordDroppedEvent: this.recordDroppedEvent.bind(this), 22546 ...options.transportOptions, 22547 url, 22548 }); 22549 } 22550 } 22551 22552 /** 22553 * @inheritDoc 22554 */ 22555 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types 22556 captureException(exception, hint, scope) { 22557 // ensure we haven't captured this very object before 22558 if (utils.checkOrSetAlreadyCaught(exception)) { 22559 debugBuild.DEBUG_BUILD && utils.logger.log(ALREADY_SEEN_ERROR); 22560 return; 22561 } 22562 22563 let eventId = hint && hint.event_id; 22564 22565 this._process( 22566 this.eventFromException(exception, hint) 22567 .then(event => this._captureEvent(event, hint, scope)) 22568 .then(result => { 22569 eventId = result; 22570 }), 22571 ); 22572 22573 return eventId; 22574 } 22575 22576 /** 22577 * @inheritDoc 22578 */ 22579 captureMessage( 22580 message, 22581 // eslint-disable-next-line deprecation/deprecation 22582 level, 22583 hint, 22584 scope, 22585 ) { 22586 let eventId = hint && hint.event_id; 22587 22588 const eventMessage = utils.isParameterizedString(message) ? message :
22588String(message); 22589 22590 const promisedEvent = utils.isPrimitive(message) 22591 ? this.eventFromMessage(eventMessage, level, hint) 22592 : this.eventFromException(message, hint); 22593 22594 this._process( 22595 promisedEvent 22596 .then(event => this._captureEvent(event, hint, scope)) 22597 .then(result => { 22598 eventId = result; 22599 }), 22600 ); 22601 22602 return eventId; 22603 } 22604 22605 /** 22606 * @inheritDoc 22607 */ 22608 captureEvent(event, hint, scope) { 22609 // ensure we haven't captured this very object before 22610 if (hint && hint.originalException && utils.checkOrSetAlreadyCaught(hint.originalException)) { 22611 debugBuild.DEBUG_BUILD && utils.logger.log(ALREADY_SEEN_ERROR); 22612 return; 22613 } 22614 22615 let eventId = hint && hint.event_id; 22616 22617 const sdkProcessingMetadata = event.sdkProcessingMetadata || {}; 22618 const capturedSpanScope = sdkProcessingMetadata.capturedSpanScope; 22619 22620 this._process( 22621 this._captureEvent(event, hint, capturedSpanScope || scope).then(result => { 22622 eventId = result; 22623 }), 22624 ); 22625 22626 return eventId; 22627 } 22628 22629 /** 22630 * @inheritDoc 22631 */ 22632 captureSession(session$1) { 22633 if (!(typeof session$1.release === 'string')) { 22634 debugBuild.DEBUG_BUILD && utils.logger.warn('Discarded session because of missing or non-string release'); 22635 } else { 22636 this.sendSession(session$1); 22637 // After sending, we set init false to indicate it's not the first occurrence 22638 session.updateSession(session$1, { init: false }); 22639 } 22640 } 22641 22642 /** 22643 * @inheritDoc 22644 */ 22645 getDsn() { 22646 return this._dsn; 22647 } 22648 22649 /** 22650 * @inheritDoc 22651 */ 22652 getOptions() { 22653 return this._options; 22654 } 22655 22656 /** 22657 * @see SdkMetadata in @sentry/types 22658 * 22659 * @return The metadata of the SDK 22660 */ 22661 getSdkMetadata() { 22662 return this._options._metadata; 22663 } 22664 22665 /** 22666 * @inheritDoc 22667 */ 22668 getTransport() { 22669 return this._transport; 22670 } 22671 22672 /** 22673 * @inheritDoc 22674 */ 22675 flush(timeout) { 22676 const transport = this._transport; 22677 if (transport) { 22678 if (this.metricsAggregator) { 22679 this.metricsAggregator.flush(); 22680 } 22681 return this._isClientDoneProcessing(timeout).then(clientFinished => { 22682 return transport.flush(timeout).then(transportFlushed => clientFinished && transportFlushed); 22683 }); 22684 } else { 22685 return utils.resolvedSyncPromise(true); 22686 } 22687 } 22688 22689 /** 22690 * @inheritDoc 22691 */ 22692 close(timeout) { 22693 return this.flush(timeout).then(result => { 22694 this.getOptions().enabled = false; 22695 if (this.metricsAggregator) { 22696 this.metricsAggregator.close(); 22697 } 22698 return result; 22699 }); 22700 } 22701 22702 /** Get all installed event processors. */ 22703 getEventProcessors() { 22704 return this._eventProcessors; 22705 } 22706 22707 /** @inheritDoc */ 22708 addEventProcessor(eventProcessor) { 22709 this._eventProcessors.push(eventProcessor); 22710 } 22711 22712 /** 22713 * This is an internal function to setup all integrations that should run on the client. 22714 * @deprecated Use `client.init()` instead. 22715 */ 22716 setupIntegrations(forceInitialize) { 22717 if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) { 22718 this._setupIntegrations(); 22719 } 22720 } 22721 22722 /** @inheritdoc */ 22723 init() { 22724 if (this._isEnabled()) { 22725 this._setupIntegrations(); 22726 } 22727 } 22728 22729 /** 22730 * Gets an installed integration by its `id`. 22731 * 22732 * @returns The installed integration or `undefined` if no integration with that `id` was installed. 22733 * @deprecated Use `getIntegrationByName()` instead. 22734 */ 22735 getIntegrationById(integrationId) { 22736 return this.getIntegrationByName(integrationId); 22737 } 22738 22739 /** 22740 * Gets an installed integration by its name. 22741 * 22742 * @returns The installed integration or `undefined` if no integration with that `name` was installed. 22743 */ 22744 getIntegrationByName(integrationName) { 22745 return this._integrations[integrationName] ; 22746 } 22747 22748 /** 22749 * Returns the client's instance of the given integration class, it any. 22750 * @deprecated Use `getIntegrationByName()` instead. 22751 */ 22752 getIntegration(integration) { 22753 try { 22754 return (this._integrations[integration.id] ) || null; 22755 } catch (_oO) { 22756 debugBuild.DEBUG_BUILD && utils.logger.warn(`Cannot retrieve integration ${integration.id} from the current Client`); 22757 return null; 22758 } 22759 } 22760 22761 /** 22762 * @inheritDoc 22763 */ 22764 addIntegration(integration$1) { 22765 const isAlreadyInstalled = this._integrations[integration$1.name]; 22766 22767 // This hook takes care of only installing if not already installed 22768 integration.setupIntegration(this, integration$1, this._integrations); 22769 // Here we need to check manually to make sure to not run this multiple times 22770 if (!isAlreadyInstalled) { 22771 integration.afterSetupIntegrations(this, [integration$1]); 22772 } 22773 } 22774 22775 /** 22776 * @inheritDoc 22777 */ 22778 sendEvent(event, hint = {}) {
22779 this.emit('beforeSendEvent', event, hint); 22780 22781 let env = envelope.createEventEnvelope(event, this._dsn, this._options._metadata, this._options.tunnel); 22782 22783 for (const attachment of hint.attachments || []) { 22784 env = utils.addItemToEnvelope( 22785 env, 22786 utils.createAttachmentEnvelopeItem( 22787 attachment, 22788 this._options.transportOptions && this._options.transportOptions.textEncoder, 22789 ), 22790 ); 22791 } 22792 22793 const promise = this._sendEnvelope(env); 22794 if (promise) { 22795 promise.then(sendResponse => this.emit('afterSendEvent', event, sendResponse), null); 22796 } 22797 } 22798 22799 /** 22800 * @inheritDoc 22801 */ 22802 sendSession(session) { 22803 const env = envelope.createSessionEnvelope(session, this._dsn, this._options._metadata, this._options.tunnel); 22804 22805 // _sendEnvelope should not throw 22806 // eslint-disable-next-line @typescript-eslint/no-floating-promises 22807 this._sendEnvelope(env); 22808 } 22809 22810 /** 22811 * @inheritDoc 22812 */ 22813 recordDroppedEvent(reason, category, _event) { 22814 // Note: we use `event` in replay, where we overwrite this hook. 22815 22816 if (this._options.sendClientReports) { 22817 // We want to track each category (error, transaction, session, replay_event) separately 22818 // but still keep the distinction between different type of outcomes. 22819 // We could use nested maps, but it's much easier to read and type this way. 22820 // A correct type for map-based implementation if we want to go that route 22821 // would be `Partial<Record<SentryRequestType, Partial<Record<Outcome, number>>>>` 22822 // With typescript 4.1 we could even use template literal types 22823 const key = `${reason}:${category}`; 22824 debugBuild.DEBUG_BUILD && utils.logger.log(`Adding outcome: "${
22824key}"`); 22825 22826 // The following works because undefined + 1 === NaN and NaN is falsy 22827 this._outcomes[key] = this._outcomes[key] + 1 || 1; 22828 } 22829 } 22830 22831 /** 22832 * @inheritDoc 22833 */ 22834 captureAggregateMetrics(metricBucketItems) { 22835 debugBuild.DEBUG_BUILD && utils.logger.log(`Flushing aggregated metrics, number of metrics: ${metricBucketItems.length}`); 22836 const metricsEnvelope = envelope$1.createMetricEnvelope( 22837 metricBucketItems, 22838 this._dsn, 22839 this._options._metadata, 22840 this._options.tunnel, 22841 ); 22842 22843 // _sendEnvelope should not throw 22844 // eslint-disable-next-line @typescript-eslint/no-floating-promises 22845 this._sendEnvelope(metricsEnvelope); 22846 } 22847 22848 // Keep on() & emit() signatures in sync with types' client.ts interface 22849 /* eslint-disable @typescript-eslint/unified-signatures */ 22850 22851 /** @inheritdoc */ 22852 22853 /** @inheritdoc */ 22854 on(hook, callback) { 22855 if (!this._hooks[hook]) { 22856 this._hooks[hook] = []; 22857 } 22858 22859 // @ts-expect-error We assue the types are correct 22860 this._hooks[hook].push(callback); 22861 } 22862 22863 /** @inheritdoc */ 22864 22865 /** @inheritdoc */ 22866 emit(hook, ...rest) { 22867 if (this._hooks[hook]) { 22868 this._hooks[hook].forEach(callback => callback(...rest)); 22869 } 22870 } 22871 22872 /* eslint-enable @typescript-eslint/unified-signatures */ 22873 22874 /** Setup integrations for this client. */ 22875 _setupIntegrations() { 22876 const { integrations } = this._options; 22877 this._integrations = integration.setupIntegrations(this, integrations); 22878 integration.afterSetupIntegrations(this, integrations); 22879 22880 // TODO v8: We don't need this flag anymore 22881 this._integrationsInitialized = true; 22882 } 22883 22884 /** Updates existing session based on the provided event */ 22885 _updateSessionFromEvent(session$1, event) { 22886 let crashed = false; 22887 let errored = false; 22888 const exceptions = event.exception && event.exception.values; 22889 22890 if (exceptions) { 22891 errored = true; 22892 22893 for (const ex of exceptions) { 22894 const mechanism = ex.mechanism; 22895 if (mechanism && mechanism.handled === false) { 22896 crashed = true; 22897 break; 22898 } 22899 } 22900 } 22901 22902 // A session is updated and that session update is sent in only one of the two following scenarios: 22903 // 1. Session with non terminal status and 0 errors + an error occurred -> Will set error count to 1 and send update 22904 // 2. Session with non terminal status and 1 error + a crash occurred -> Will set status crashed and send update 22905 const sessionNonTerminal = session$1.status === 'ok'; 22906 const shouldUpdateAndSend = (sessionNonTerminal && session$1.errors === 0) || (sessionNonTerminal && crashed); 22907 22908 if (shouldUpdateAndSend) { 22909 session.updateSession(session$1, { 22910 ...(crashed && { status: 'crashed' }), 22911 errors: session$1.errors || Number(errored || crashed), 22912 }); 22913 this.captureSession(session$1); 22914 } 22915 } 22916 22917 /** 22918 * Determine if the client is finished processing. Returns a promise because it will wait `timeout` ms before saying 22919 * "no" (resolving to `false`) in order to give the client a chance to potentially finish first. 22920 * 22921 * @param timeout The time, in ms, after which to resolve to `false` if the client is still busy. Passing `0` (or not 22922 * passing anything) will make the promise wait as long as it takes for processing to finish before resolving to 22923 * `true`. 22924 * @returns A promise which will resolve to `true` if processing is already done or finishes before the timeout, and 22925 * `false` otherwise 22926 */ 22927 _isClientDoneProcessing(timeout) { 22928 return new utils.SyncPromise(resolve => { 22929 let ticked = 0; 22930 const tick = 1; 22931 22932 const interval = setInterval(() => { 22933 if (this._numProcessing == 0) { 22934 clearInterval(interval); 22935 resolve(true); 22936 } else { 22937 ticked += tick; 22938 if (timeout && ticked >= timeout) { 22939 clearInterval(interval); 22940 resolve(false); 22941 } 22942 } 22943 }, tick); 22944 }); 22945 } 22946 22947 /** Determines whether this SDK is enabled and a transport is present. */ 22948 _isEnabled() { 22949 return this.getOptions().enabled !== false && this._transport !== undefined; 22950 } 22951 22952 /** 22953 * Adds common information to events. 22954 * 22955 * The information includes release and environment from `options`, 22956 * breadcrumbs and context (extra, tags and user) from the scope. 22957 * 22958 * Information that is already present in the event is never overwritten. For 22959 * nested objects, such as the context, keys are merged. 22960 * 22961 * @param event The original event. 22962 * @param hint May contain additional information about the original exception. 22963 * @param scope A scope containing event metadata. 22964 * @returns A new event with more information. 22965 */ 22966 _prepareEvent( 22967 event, 22968 hint, 22969 scope, 22970 isolationScope = hub.getIsolationScope(), 22971 ) { 22972 const options = this.getOptions(); 22973 const integrations = Object.keys(this._integrations); 22974 if (!hint.integrations && integrations.length > 0) { 22975 hint.integrations = integrations; 22976 } 22977
22978 this.emit('preprocessEvent', event, hint); 22979 22980 return prepareEvent.prepareEvent(options, event, hint, scope, this, isolationScope).then(evt => { 22981 if (evt === null) { 22982 return evt; 22983 } 22984 22985 const propagationContext = { 22986 ...isolationScope.getPropagationContext(), 22987 ...(scope ? scope.getPropagationContext() : undefined), 22988 }; 22989 22990 const trace = evt.contexts && evt.contexts.trace; 22991 if (!trace && propagationContext) { 22992 const { traceId: trace_id, spanId, parentSpanId, dsc } = propagationContext; 22993 evt.contexts = { 22994 trace: { 22995 trace_id, 22996 span_id: spanId, 22997 parent_span_id: parentSpanId, 22998 }, 22999 ...evt.contexts, 23000 }; 23001 23002 const dynamicSamplingContext$1 = dsc ? dsc : dynamicSamplingContext.getDynamicSamplingContextFromClient(trace_id, this, scope); 23003 23004 evt.sdkProcessingMetadata = { 23005 dynamicSamplingContext: dynamicSamplingContext$1, 23006 ...evt.sdkProcessingMetadata, 23007 }; 23008 } 23009 return evt; 23010 }); 23011 } 23012 23013 /** 23014 * Processes the event and logs an error in case of rejection 23015 * @param event 23016 * @param hint 23017 * @param scope 23018 */ 23019 _captureEvent(event, hint = {}, scope) { 23020 return this._processEvent(event, hint, scope).then( 23021 finalEvent => { 23022 return finalEvent.event_id; 23023 }, 23024 reason => { 23025 if (debugBuild.DEBUG_BUILD) { 23026 // If something's gone wrong, log the error as a warning. If it's just us having used a `SentryError` for 23027 // control flow, log just the message (no stack) as a log-level log. 23028 const sentryError = reason ; 23029 if (sentryError.logLevel === 'log') { 23030 utils.logger.log(sentryError.message); 23031 } else { 23032 utils.logger.warn(sentryError); 23033 } 23034 } 23035 return undefined; 23036 }, 23037 ); 23038 } 23039 23040 /** 23041 * Processes an event (either error or message) and sends it to Sentry. 23042 * 23043 * This also adds breadcrumbs and context information to the event. However, 23044 * platform specific meta data (such as the User's IP address) must be added 23045 * by the SDK implementor. 23046 * 23047 * 23048 * @param event The event to send to Sentry. 23049 * @param hint May contain additional information about the original exception. 23050 * @param scope A scope containing event metadata. 23051 * @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send. 23052 */ 23053 _processEvent(event, hint, scope) { 23054 const options = this.getOptions(); 23055 const { sampleRate } = options; 23056 23057 const isTransaction = isTransactionEvent(event); 23058 const isError = isErrorEvent(event); 23059 const eventType = event.type || 'error'; 23060 const beforeSendLabel = `before send for type \`${eventType}\``; 23061 23062 // 1.0 === 100% events are sent 23063 // 0.0 === 0% events are sent 23064 // Sampling for transaction happens somewhere else 23065 if (isError && typeof sampleRate === 'number' && Math.random() > sampleRate) { 23066 this.recordDroppedEvent('sample_rate', 'error', event); 23067 return utils.rejectedSyncPromise( 23068 new utils.SentryError( 23069 `Discarding event because it's not included in the random sample (sampling rate = ${sampleRate})`, 23070 'log', 23071 ), 23072 ); 23073 } 23074 23075 const dataCategory = eventType === 'replay_event' ? 'replay' : eventType; 23076 23077 const sdkProcessingMetadata = event.sdkProcessingMetadata || {}; 23078 const capturedSpanIsolationScope = sdkProcessingMetadata.capturedSpanIsolationScope; 23079 23080 return this._prepareEvent(event, hint, scope, capturedSpanIsolationScope) 23081 .then(prepared => { 23082 if (prepared === null) { 23083 this.recordDroppedEvent('event_processor', dataCategory, event); 23084 throw new utils.SentryError('An event processor returned `null`, will not send event.', 'log'); 23085 } 23086 23087 const isInternalException = hint.data && (hint.data ).__sentry__ === true; 23088 if (isInternalException) { 23089 return prepared; 23090 } 23091 23092 const result = processBeforeSend(options, prepared, hint); 23093 return _validateBeforeSendResult(result, beforeSendLabel); 23094 }) 23095 .then(processedEvent => { 23096 if (processedEvent === null) { 23097 this.recordDroppedEvent('before_send', dataCategory, event); 23098 throw new utils.SentryError(`${beforeSendLabel} returned \`null\`, will not send event.`, 'log'); 23099 } 23100 23101 const session = scope && scope.getSession(); 23102 if (!isTransaction && session) { 23103 this._updateSessionFromEvent(session, processedEvent); 23104 } 23105 23106 // None of the Sentry built event processor will update transaction name, 23107 // so if the transaction name has been changed by an event processor, we know 23108 // it has to come from custom event processor added by a user 23109 const transactionInfo = processedEvent.transaction_info; 23110 if (isTransaction && transactionInfo && processedEvent.transaction !== event.transaction) { 23111 const source = 'custom'; 23112 processedEvent.transaction_info = { 23113 ...transactionInfo, 23114 source, 23115 }; 23116 } 23117 23118 this.sendEvent(processedEvent, hint); 23119 return processedEvent; 23120 }) 23121 .then(null, reason => { 23122 if (reason instanceof utils.SentryError) { 23123 throw reason; 23124 } 23125 23126 this.captureException(reason, { 23127 data: { 23128 __sentry__: true, 23129 }, 23130 originalException: reason, 23131 }); 23132 throw new utils.SentryError( 23133 `Event processing pipeline threw an error, original event will not be sent. Details have been sent as a new event.\nReason: ${reason}`, 23134 ); 23135 }); 23136 } 23137 23138 /** 23139 * Occupies the client with processing and event 23140 */ 23141 _process(promise) { 23142 this._numProcessing++; 23143 void promise.then( 23144 value => { 23145 this._numProcessing--; 23146 return value; 23147 }, 23148 reason => { 23149 this._numProcessing--; 23150 return reason; 23151 }, 23152 ); 23153 } 23154 23155 /** 23156 * @inheritdoc 23157 */ 23158 _sendEnvelope(envelope) {
23159 this.emit('beforeEnvelope', envelope); 23160 23161 if (this._isEnabled() && this._transport) { 23162 return this._transport.send(envelope).then(null, reason => { 23163 debugBuild.DEBUG_BUILD && utils.logger.error('Error while sending event:', reason); 23164 }); 23165 } else { 23166 debugBuild.DEBUG_BUILD && utils.logger.error('Transport disabled'); 23167 } 23168 } 23169 23170 /** 23171 * Clears outcomes on this client and returns them. 23172 */ 23173 _clearOutcomes() { 23174 const outcomes = this._outcomes; 23175 this._outcomes = {}; 23176 return Object.keys(outcomes).map(key => { 23177 const [reason, category] = key.split(':') ; 23178 return { 23179 reason, 23180 category, 23181 quantity: outcomes[key], 23182 }; 23183 }); 23184 } 23185 23186 /** 23187 * @inheritDoc 23188 */ 23189 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types 23190 23191} 23192 23193/** 23194 * Verifies that return value of configured `beforeSend` or `beforeSendTransaction` is of expected type, and returns the value if so. 23195 */ 23196function _validateBeforeSendResult( 23197 beforeSendResult, 23198 beforeSendLabel, 23199) { 23200 const invalidValueError = `${beforeSendLabel} must return \`null\` or a valid event.`; 23201 if (utils.isThenable(beforeSendResult)) { 23202 return beforeSendResult.then( 23203 event => { 23204 if (!utils.isPlainObject(event) && event !== null) { 23205 throw new utils.SentryError(invalidValueError); 23206 } 23207 return event; 23208 }, 23209 e => { 23210 throw new utils.SentryError(`${beforeSendLabel} rejected with ${e}`); 23211 }, 23212 ); 23213 } else if (!utils.isPlainObject(beforeSendResult) && beforeSendResult !== null) { 23214 throw new utils.SentryError(invalidValueError); 23215 } 23216 return beforeSendResult; 23217} 23218 23219/** 23220 * Process the matching `beforeSendXXX` callback. 23221 */ 23222function processBeforeSend( 23223 options, 23224 event, 23225 hint, 23226) { 23227 const { beforeSend, beforeSendTransaction } = options; 23228 23229 if (isErrorEvent(event) && beforeSend) { 23230 return beforeSend(event, hint); 23231 } 23232 23233 if (isTransactionEvent(event) && beforeSendTransaction) { 23234 return beforeSendTransaction(event, hint); 23235 } 23236 23237 return event; 23238} 23239 23240function isErrorEvent(event) { 23241 return event.type === undefined; 23242} 23243 23244function isTransactionEvent(event) { 23245 return event.type === 'transaction'; 23246} 23247 23248/** 23249 * Add an event processor to the current client. 23250 * This event processor will run for all events processed by this client. 23251 */ 23252function addEventProcessor(callback) { 23253 const client = exports$1.getClient(); 23254 23255 if (!client || !client.addEventProcessor) { 23256 return; 23257 } 23258 23259 client.addEventProcessor(callback); 23260} 23261 23262exports.BaseClient = BaseClient; 23263exports.addEventProcessor = addEventProcessor; 23264 23265 23266},{"./api.js":241,"./debug-build.js":245,"./envelope.js":246,"./exports.js":248,"./hub.js":249,"./integration.js":251,"./metrics/envelope.js":262,"./session.js":272,"./tracing/dynamicSamplingContext.js":275,"./utils/prepareEvent.js":295,"@sentry/utils":319}],243:[function(require,module,exports){ 23267Object.defineProperty(exports, '__esModule', { value: true }); 23268 23269const utils = require('@sentry/utils'); 23270 23271/** 23272 * Create envelope from check in item. 23273 */ 23274function createCheckInEnvelope( 23275 checkIn, 23276 dynamicSamplingContext, 23277 metadata, 23278 tunnel, 23279 dsn, 23280) { 23281 const headers = { 23282 sent_at: new Date().toISOString(), 23283 }; 23284 23285 if (metadata && metadata.sdk) { 23286 headers.sdk = { 23287 name: metadata.sdk.name, 23288 version: metadata.sdk.version, 23289 }; 23290 } 23291 23292 if (!!tunnel && !!dsn) { 23293 headers.dsn = utils.dsnToString(dsn); 23294 } 23295 23296 if (dynamicSamplingContext) { 23297 headers.trace = utils.dropUndefinedKeys(dynamicSamplingContext) ; 23298 } 23299 23300 const item = createCheckInEnvelopeItem(checkIn); 23301 return utils.createEnvelope(headers, [item]); 23302} 23303 23304function createCheckInEnvelopeItem(checkIn) { 23305 const checkInHeaders = { 23306 type: 'check_in', 23307 }; 23308 return [checkInHeaders, checkIn]; 23309} 23310 23311exports.createCheckInEnvelope = createCheckInEnvelope; 23312 23313 23314},{"@sentry/utils":319}],244:[function(require,module,exports){ 23315Object.defineProperty(exports, '__esModule', { value: true }); 23316 23317const DEFAULT_ENVIRONMENT = 'production'; 23318 23319exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT; 23320 23321 23322},{}],245:[function(require,module,exports){ 23323arguments[4][206][0].apply(exports,arguments) 23324},{"dup":206}],246:[function(require,module,exports){ 23325Object.defineProperty(exports, '__esModule', { value: true }); 23326 23327const utils = require('@sentry/utils'); 23328 23329/** 23330 * Apply SdkInfo (name, version, packages, integrations) to the corresponding event key. 23331 * Merge with existing data if any. 23332 **/ 23333function enhanceEventWithSdkInfo(event, sdkInfo) { 23334 if (!sdkInfo) { 23335 return event; 23336 } 23337 event.sdk = event.sdk || {}; 23338 event.sdk.name = event.sdk.name || sdkInfo.name; 23339 event.sdk.version = event.sdk.version || sdkInfo.version; 23340 event.sdk.integrations = [...(event.sdk.integrations || []), ...(sdkInfo.integrations || [])]; 23341 event.sdk.packages = [...(event.sdk.packages || []), ...(sdkInfo.packages || [])]; 23342 return event; 23343} 23344
23345/** Creates an envelope from a Session */ 23346function createSessionEnvelope( 23347 session, 23348 dsn, 23349 metadata, 23350 tunnel, 23351) { 23352 const sdkInfo = utils.getSdkMetadataForEnvelopeHeader(metadata); 23353 const envelopeHeaders = { 23354 sent_at: new Date().toISOString(), 23355 ...(sdkInfo && { sdk: sdkInfo }), 23356 ...(!!tunnel && dsn && { dsn: utils.dsnToString(dsn) }), 23357 }; 23358 23359 const envelopeItem = 23360 'aggregates' in session ? [{ type: 'sessions' }, session] : [{ type: 'session' }, session.toJSON()]; 23361 23362 return utils.createEnvelope(envelopeHeaders, [envelopeItem]); 23363} 23364 23365/** 23366 * Create an Envelope from an event. 23367 */ 23368function createEventEnvelope( 23369 event, 23370 dsn, 23371 metadata, 23372 tunnel, 23373) { 23374 const sdkInfo = utils.getSdkMetadataForEnvelopeHeader(metadata); 23375 23376 /* 23377 Note: Due to TS, event.type may be `replay_event`, theoretically. 23378 In practice, we never call `createEventEnvelope` with `replay_event` type, 23379 and we'd have to adjut a looot of types to make this work properly. 23380 We want to avoid casting this around, as that could lead to bugs (e.g. when we add another type) 23381 So the safe choice is to really guard against the replay_event type here. 23382 */ 23383 const eventType = event.type && event.type !== 'replay_event' ? event.type : 'event'; 23384 23385 enhanceEventWithSdkInfo(event, metadata && metadata.sdk); 23386 23387 const envelopeHeaders = utils.createEventEnvelopeHeaders(event, sdkInfo, tunnel, dsn); 23388 23389 // Prevent this data (which, if it exists, was used in earlier steps in the processing pipeline) from being sent to 23390 // sentry. (Note: Our use of this property comes and goes with whatever we might be debugging, whatever hacks we may 23391 // have temporarily added, etc. Even if we don't happen to be using it at some point in the future, let's not get rid 23392 // of this `delete`, lest we miss putting it back in the next time the property is in use.) 23393 delete event.sdkProcessingMetadata; 23394 23395 const eventItem = [{ type: eventType }, event]; 23396 return utils.createEnvelope(envelopeHeaders, [eventItem]); 23397} 23398 23399exports.createEventEnvelope = createEventEnvelope; 23400exports.createSessionEnvelope = createSessionEnvelope; 23401 23402 23403},{"@sentry/utils":319}],247:[function(require,module,exports){ 23404Object.defineProperty(exports, '__esModule', { value: true }); 23405 23406const utils = require('@sentry/utils'); 23407const debugBuild = require('./debug-build.js'); 23408 23409/** 23410 * Returns the global event processors. 23411 * @deprecated Global event processors will be removed in v8. 23412 */ 23413function getGlobalEventProcessors() { 23414 return utils.getGlobalSingleton('globalEventProcessors', () => []); 23415} 23416 23417/** 23418 * Add a EventProcessor to be kept globally. 23419 * @deprecated Use `addEventProcessor` instead. Global event processors will be removed in v8. 23420 */ 23421function addGlobalEventProcessor(callback) { 23422 // eslint-disable-next-line deprecation/deprecation 23423 getGlobalEventProcessors().push(callback); 23424} 23425 23426/** 23427 * Process an array of event processors, returning the processed event (or `null` if the event was dropped). 23428 */ 23429function notifyEventProcessors( 23430 processors, 23431 event, 23432 hint, 23433 index = 0, 23434) { 23435 return new utils.SyncPromise((resolve, reject) => { 23436 const processor = processors[index]; 23437 if (event === null || typeof processor !== 'function') { 23438 resolve(event); 23439 } else { 23440 const result = processor({ ...event }, hint) ; 23441 23442 debugBuild.DEBUG_BUILD && processor.id && result === null && utils.logger.log(`Event processor "${processor.id}" dropped event`); 23443 23444 if (utils.isThenable(result)) { 23445 void result 23446 .then(final => notifyEventProcessors(processors, final, hint, index + 1).then(resolve)) 23447 .then(null, reject); 23448 } else { 23449 void notifyEventProcessors(processors, result, hint, index + 1) 23450 .then(resolve) 23451 .then(null, reject); 23452 } 23453 } 23454 }); 23455} 23456 23457exports.addGlobalEventProcessor = addGlobalEventProcessor; 23458exports.getGlobalEventProcessors = getGlobalEventProcessors; 23459exports.notifyEventProcessors = notifyEventProcessors; 23460 23461 23462},{"./debug-build.js":245,"@sentry/utils":319}],248:[function(require,module,exports){ 23463Object.defineProperty(exports, '__esModule', { value: true }); 23464 23465const utils = require('@sentry/utils'); 23466const constants = require('./constants.js'); 23467const debugBuild = require('./debug-build.js'); 23468const hub = require('./hub.js'); 23469const session = require('./session.js'); 23470const prepareEvent = require('./utils/prepareEvent.js'); 23471 23472/** 23473 * Captures an exception event and sends it to Sentry. 23474 * 23475 * @param exception The exception to capture. 23476 * @param hint Optional additional data to attach to the Sentry event. 23477 * @returns the id of the captured Sentry event. 23478 */ 23479function captureException( 23480 // eslint-disable-next-line @typescript-eslint/no-explicit-any 23481 exception, 23482 hint, 23483) { 23484 // eslint-disable-next-line deprecation/deprecation 23485 return hub.getCurrentHub().captureException(exception, prepareEvent.parseEventHintOrCaptureContext(hint)); 23486} 23487 23488/** 23489 * Captures a message event and sends it to Sentry. 23490 * 23491 * @param exception The exception to capture. 23492 * @param captureContext Define the level of the message or pass in additional data to attach to the message. 23493 * @returns the id of the captured message. 23494 */ 23495function captureMessage( 23496 message, 23497 // eslint-disable-next-line deprecation/deprecation 23498 captureContext, 23499) { 23500 // This is necessary to provide explicit scopes upgrade, without changing the original 23501 // arity of the `captureMessage(message, level)` method. 23502 const level = typeof captureContext === 'string' ? captureContext : undefined; 23503 const context = typeof captureContext !== 'string' ? { captureContext } : undefined; 23504 // eslint-disable-next-line deprecation/deprecation 23505 return hub.getCurrentHub().captureMessage(message, level, context); 23506} 23507 23508/** 23509 * Captures a manually created event and sends it to Sentry. 23510 * 23511 * @param exception The event to send to Sentry. 23512 * @param hint Optional additional data to attach to the Sentry event. 23513 * @returns the id of the captured event. 23514 */ 23515function captureEvent(event, hint) { 23516 // eslint-disable-next-line deprecation/deprecation 23517 return hub.getCurrentHub().captureEvent(event, hint); 23518} 23519 23520/** 23521 * Callback to set context information onto the scope. 23522 * @param callback Callback function that receives Scope. 23523 * 23524 * @deprecated Use getCurrentScope() directly. 23525 */ 23526function configureScope(callback) { 23527 // eslint-disable-next-line deprecation/deprecation 23528 hub.getCurrentHub().configureScope(callback); 23529} 23530 23531/** 23532 * Records a new breadcrumb which will be attached to future events. 23533 * 23534 * Breadcrumbs will be added to subsequent events to provide more context on 23535 * user's actions prior to an error or crash. 23536 * 23537 * @param breadcrumb The breadcrumb to record. 23538 */ 23539function addBreadcrumb(breadcrumb, hint) { 23540 // eslint-disable-next-line deprecation/deprecation 23541 hub.getCurrentHub().addBreadcrumb(breadcrumb, hint); 23542} 23543 23544/** 23545 * Sets context data with the given name. 23546 * @param name of the context 23547 * @param context Any kind of data. This data will be normalized. 23548 */ 23549// eslint-disable-next-line @typescript-eslint/no-explicit-any 23550function setContext(name, context) { 23551 // eslint-disable-next-line deprecation/deprecation 23552 hub.getCurrentHub().setContext(name, context); 23553} 23554 23555/** 23556 * Set an object that will be merged sent as extra data with the event. 23557 * @param extras Extras object to merge into current context. 23558 */ 23559function setExtras(extras) { 23560 // eslint-disable-next-line deprecation/deprecation 23561 hub.getCurrentHub().setExtras(extras); 23562} 23563 23564/** 23565 * Set key:value that will be sent as extra data with the event. 23566 * @param key String of extra 23567 * @param extra Any kind of data. This data will be normalized. 23568 */ 23569function setExtra(key, extra) { 23570 // eslint-disable-next-line deprecation/deprecation 23571 hub.getCurrentHub().setExtra(key, extra); 23572} 23573 23574/** 23575 * Set an object that will be merged sent as tags data with the event. 23576 * @param tags Tags context object to merge into current context. 23577 */ 23578function setTags(tags) { 23579 // eslint-disable-next-line deprecation/deprecation 23580 hub.getCurrentHub().setTags(tags); 23581} 23582 23583/** 23584 * Set key:value that will be sent as tags data with the event. 23585 * 23586 * Can also be used to unset a tag, by passing `undefined`. 23587 * 23588 * @param key String key of tag 23589 * @param value Value of tag 23590 */ 23591function setTag(key, value) { 23592 // eslint-disable-next-line deprecation/deprecation 23593 hub.getCurrentHub().setTag(key, value); 23594} 23595 23596/** 23597 * Updates user context information for future events. 23598 * 23599 * @param user User context object to be set in the current context. Pass `null` to unset the user. 23600 */ 23601function setUser(user) { 23602 // eslint-disable-next-line deprecation/deprecation 23603 hub.getCurrentHub().setUser(user); 23604} 23605 23606/** 23607 * Creates a new scope with and executes the given operation within. 23608 * The scope is automatically removed once the operation 23609 * finishes or throws. 23610 * 23611 * This is essentially a convenience function for: 23612 * 23613 * pushScope(); 23614 * callback(); 23615 * popScope(); 23616 */ 23617 23618/** 23619 * Either creates a new active scope, or sets the given scope as active scope in the given callback. 23620 */ 23621function withScope( 23622 ...rest 23623) { 23624 // eslint-disable-next-line deprecation/deprecation 23625 const hub$1 = hub.getCurrentHub(); 23626 23627 // If a scope is defined, we want to make this the active scope instead of the default one 23628 if (rest.length === 2) { 23629 const [scope, callback] = rest; 23630 if (!scope) { 23631 // eslint-disable-next-line deprecation/deprecation 23632 return hub$1.withScope(callback); 23633 } 23634 23635 // eslint-disable-next-line deprecation/deprecation 23636 return hub$1.withScope(() => { 23637 // eslint-disable-next-line deprecation/deprecation 23638 hub$1.getStackTop().scope = scope ; 23639 return callback(scope ); 23640 }); 23641 } 23642 23643 // eslint-disable-next-line deprecation/deprecation 23644 return hub$1.withScope(rest[0]); 23645} 23646 23647/** 23648 * Attempts to fork the current isolation scope and the current scope based on the current async context strategy. If no 23649 * async context strategy is set, the isolation scope and the current scope will not be forked (this is currently the 23650 * case, for example, in the browser). 23651 * 23652 * Usage of this function in environments without async context strategy is discouraged and may lead to unexpected behaviour. 23653 * 23654 * This function is intended for Sentry SDK and SDK integration development. It is not recommended to be used in "normal"
23655 * applications directly because it comes with pitfalls. Use at your own risk! 23656 * 23657 * @param callback The callback in which the passed isolation scope is active. (Note: In environments without async 23658 * context strategy, the currently active isolation scope may change within execution of the callback.) 23659 * @returns The same value that `callback` returns. 23660 */ 23661function withIsolationScope(callback) { 23662 return hub.runWithAsyncContext(() => { 23663 return callback(hub.getIsolationScope()); 23664 }); 23665} 23666 23667/** 23668 * Forks the current scope and sets the provided span as active span in the context of the provided callback. 23669 * 23670 * @param span Spans started in the context of the provided callback will be children of this span. 23671 * @param callback Execution context in which the provided span will be active. Is passed the newly forked scope. 23672 * @returns the value returned from the provided callback function. 23673 */ 23674function withActiveSpan(span, callback) { 23675 return withScope(scope => { 23676 // eslint-disable-next-line deprecation/deprecation 23677 scope.setSpan(span); 23678 return callback(scope); 23679 }); 23680} 23681 23682/** 23683 * Starts a new `Transaction` and returns it. This is the entry point to manual tracing instrumentation. 23684 * 23685 * A tree structure can be built by adding child spans to the transaction, and child spans to other spans. To start a 23686 * new child span within the transaction or any span, call the respective `.startChild()` method. 23687 * 23688 * Every child span must be finished before the transaction is finished, otherwise the unfinished spans are discarded. 23689 * 23690 * The transaction must be finished with a call to its `.end()` method, at which point the transaction with all its 23691 * finished child spans will be sent to Sentry. 23692 * 23693 * NOTE: This function should only be used for *manual* instrumentation. Auto-instrumentation should call 23694 * `startTransaction` directly on the hub. 23695 * 23696 * @param context Properties of the new `Transaction`. 23697 * @param customSamplingContext Information given to the transaction sampling function (along with context-dependent 23698 * default values). See {@link Options.tracesSampler}. 23699 * 23700 * @returns The transaction which was just started 23701 * 23702 * @deprecated Use `startSpan()`, `startSpanManual()` or `startInactiveSpan()` instead. 23703 */ 23704function startTransaction( 23705 context, 23706 customSamplingContext, 23707) { 23708 // eslint-disable-next-line deprecation/deprecation 23709 return hub.getCurrentHub().startTransaction({ ...context }, customSamplingContext); 23710} 23711 23712/** 23713 * Create a cron monitor check in and send it to Sentry. 23714 * 23715 * @param checkIn An object that describes a check in. 23716 * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want 23717 * to create a monitor automatically when sending a check in. 23718 */ 23719function captureCheckIn(checkIn, upsertMonitorConfig) { 23720 const scope = getCurrentScope(); 23721 const client = getClient(); 23722 if (!client) { 23723 debugBuild.DEBUG_BUILD && utils.logger.warn('Cannot capture check-in. No client defined.'); 23724 } else if (!client.captureCheckIn) { 23725 debugBuild.DEBUG_BUILD && utils.logger.warn('Cannot capture check-in. Client does not support sending check-ins.'); 23726 } else { 23727 return client.captureCheckIn(checkIn, upsertMonitorConfig, scope); 23728 } 23729 23730 return utils.uuid4(); 23731} 23732 23733/** 23734 * Wraps a callback with a cron monitor check in. The check in will be sent to Sentry when the callback finishes. 23735 * 23736 * @param monitorSlug The distinct slug of the monitor. 23737 * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want 23738 * to create a monitor automatically when sending a check in. 23739 */ 23740function withMonitor( 23741 monitorSlug, 23742 callback, 23743 upsertMonitorConfig, 23744) { 23745 const checkInId = captureCheckIn({ monitorSlug, status: 'in_progress' }, upsertMonitorConfig); 23746 const now = utils.timestampInSeconds(); 23747 23748 function finishCheckIn(status) { 23749 captureCheckIn({ monitorSlug, status, checkInId, duration: utils.timestampInSeconds() - now }); 23750 } 23751 23752 let maybePromiseResult; 23753 try { 23754 maybePromiseResult = callback(); 23755 } catch (e) { 23756 finishCheckIn('error'); 23757 throw e; 23758 } 23759 23760 if (utils.isThenable(maybePromiseResult)) { 23761 Promise.resolve(maybePromiseResult).then( 23762 () => { 23763 finishCheckIn('ok'); 23764 }, 23765 () => { 23766 finishCheckIn('error'); 23767 }, 23768 ); 23769 } else { 23770 finishCheckIn('ok'); 23771 } 23772 23773 return maybePromiseResult; 23774} 23775 23776/** 23777 * Call `flush()` on the current client, if there is one. See {@link Client.flush}. 23778 * 23779 * @param timeout Maximum time in ms the client should wait to flush its event queue. Omitting this parameter will cause 23780 * the client to wait until all events are sent before resolving the promise. 23781 * @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it 23782 * doesn't (or if there's no client defined). 23783 */ 23784async function flush(timeout) { 23785 const client = getClient(); 23786 if (client) { 23787 return client.flush(timeout); 23788 } 23789 debugBuild.DEBUG_BUILD && utils.logger.warn('Cannot flush events. No client defined.'); 23790 return Promise.resolve(false); 23791} 23792 23793/** 23794 * Call `close()` on the current client, if there is one. See {@link Client.close}. 23795 * 23796 * @param timeout Maximum time in ms the client should wait to flush its event queue before shutting down. Omitting this 23797 * parameter will cause the client to wait until all events are sent before disabling itself. 23798 * @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it 23799 * doesn't (or if there's no client defined). 23800 */ 23801async function close(timeout) { 23802 const client = getClient(); 23803 if (client) { 23804 return client.close(timeout); 23805 } 23806 debugBuild.DEBUG_BUILD && utils.logger.warn('Cannot flush events and disable SDK. No client defined.'); 23807 return Promise.resolve(false); 23808} 23809 23810/** 23811 * This is the getter for lastEventId. 23812 * 23813 * @returns The last event id of a captured event. 23814 * @deprecated This function will be removed in the next major version of the Sentry SDK. 23815 */ 23816function lastEventId() { 23817 // eslint-disable-next-line deprecation/deprecation 23818 return hub.getCurrentHub().lastEventId(); 23819} 23820 23821/** 23822 * Get the currently active client. 23823 */ 23824function getClient() { 23825 // eslint-disable-next-line deprecation/deprecation 23826 return hub.getCurrentHub().getClient(); 23827} 23828 23829/** 23830 * Returns true if Sentry has been properly initialized. 23831 */ 23832function isInitialized() { 23833 return !!getClient(); 23834} 23835 23836/** 23837 * Get the currently active scope. 23838 */ 23839function getCurrentScope() { 23840 // eslint-disable-next-line deprecation/deprecation 23841 return hub.getCurrentHub().getScope(); 23842} 23843 23844/** 23845 * Start a session on the current isolation scope. 23846 * 23847 * @param context (optional) additional properties to be applied to the returned session object 23848 * 23849 * @returns the new active session 23850 */ 23851function startSession(context) { 23852 const client = getClient(); 23853 const isolationScope = hub.getIsolationScope(); 23854 const currentScope = getCurrentScope(); 23855 23856 const { release, environment = constants.DEFAULT_ENVIRONMENT } = (client && client.getOptions()) || {}; 23857 23858 // Will fetch userAgent if called from browser sdk 23859 const { userAgent } = utils.GLOBAL_OBJ.navigator || {}; 23860 23861 const session$1 = session.makeSession({ 23862 release, 23863 environment, 23864 user: currentScope.getUser() || isolationScope.getUser(), 23865 ...(userAgent && { userAgent }), 23866 ...context, 23867 }); 23868 23869 // End existing session if there's one 23870 const currentSession = isolationScope.getSession(); 23871 if (currentSession && currentSession.status === 'ok') { 23872 session.updateSession(currentSession, { status: 'exited' }); 23873 } 23874 23875 endSession(); 23876 23877 // Afterwards we set the new session on the scope 23878 isolationScope.setSession(session$1); 23879 23880 // TODO (v8): Remove this and only use the isolation scope(?). 23881 // For v7 though, we can't "soft-break" people using getCurrentHub().getScope().setSession() 23882 currentScope.setSession(session$1); 23883 23884 return session$1; 23885} 23886 23887/** 23888 * End the session on the current isolation scope. 23889 */ 23890function endSession() { 23891 const isolationScope = hub.getIsolationScope(); 23892 const currentScope = getCurrentScope(); 23893 23894 const session$1 = currentScope.getSession() || isolationScope.getSession(); 23895 if (session$1) { 23896 session.closeSession(session$1); 23897 } 23898 _sendSessionUpdate(); 23899 23900 // the session is over; take it off of the scope 23901 isolationScope.setSession(); 23902 23903 // TODO (v8): Remove this and only use the isolation scope(?). 23904 // For v7 though, we can't "soft-break" people using getCurrentHub().getScope().setSession() 23905 currentScope.setSession(); 23906} 23907 23908/** 23909 * Sends the current Session on the scope 23910 */ 23911function _sendSessionUpdate() { 23912 const isolationScope = hub.getIsolationScope(); 23913 const currentScope = getCurrentScope(); 23914 const client = getClient(); 23915 // TODO (v8): Remove currentScope and only use the isolation scope(?). 23916 // For v7 though, we can't "soft-break" people using getCurrentHub().getScope().setSession() 23917 const session = currentScope.getSession() || isolationScope.getSession(); 23918 if (session && client && client.captureSession) { 23919 client.captureSession(session); 23920 } 23921} 23922 23923/** 23924 * Sends the current session on the scope to Sentry 23925 * 23926 * @param end If set the session will be marked as exited and removed from the scope. 23927 * Defaults to `false`. 23928 */ 23929function captureSession(end = false) { 23930 // both send the update and pull the session from the scope 23931 if (end) { 23932 endSession(); 23933 return; 23934 } 23935 23936 // only send the update 23937 _sendSessionUpdate(); 23938} 23939 23940exports.addBreadcrumb = addBreadcrumb; 23941exports.captureCheckIn = captureCheckIn; 23942exports.captureEvent = captureEvent; 23943exports.captureException = captureException; 23944exports.captureMessage = captureMessage; 23945exports.captureSession = captureSession; 23946exports.close = close; 23947exports.configureScope = configureScope; 23948exports.endSession = endSession; 23949exports.flush = flush; 23950exports.getClient = getClient; 23951exports.getCurrentScope = getCurrentScope; 23952exports.isInitialized = isInitialized; 23953exports.lastEventId = lastEventId; 23954exports.setContext = setContext; 23955exports.setExtra = setExtra;
23956exports.setExtras = setExtras; 23957exports.setTag = setTag; 23958exports.setTags = setTags; 23959exports.setUser = setUser; 23960exports.startSession = startSession; 23961exports.startTransaction = startTransaction; 23962exports.withActiveSpan = withActiveSpan; 23963exports.withIsolationScope = withIsolationScope; 23964exports.withMonitor = withMonitor; 23965exports.withScope = withScope; 23966 23967 23968},{"./constants.js":244,"./debug-build.js":245,"./hub.js":249,"./session.js":272,"./utils/prepareEvent.js":295,"@sentry/utils":319}],249:[function(require,module,exports){ 23969Object.defineProperty(exports, '__esModule', { value: true }); 23970 23971const utils = require('@sentry/utils'); 23972const constants = require('./constants.js'); 23973const debugBuild = require('./debug-build.js'); 23974const scope = require('./scope.js'); 23975const session = require('./session.js'); 23976const version = require('./version.js'); 23977 23978/** 23979 * API compatibility version of this hub. 23980 * 23981 * WARNING: This number should only be increased when the global interface 23982 * changes and new methods are introduced. 23983 * 23984 * @hidden 23985 */ 23986const API_VERSION = parseFloat(version.SDK_VERSION); 23987 23988/** 23989 * Default maximum number of breadcrumbs added to an event. Can be overwritten 23990 * with {@link Options.maxBreadcrumbs}. 23991 */ 23992const DEFAULT_BREADCRUMBS = 100; 23993 23994/** 23995 * @inheritDoc 23996 */ 23997class Hub { 23998 /** Is a {@link Layer}[] containing the client and scope */ 23999 24000 /** Contains the last event id of a captured event. */ 24001 24002 /** 24003 * Creates a new instance of the hub, will push one {@link Layer} into the 24004 * internal stack on creation. 24005 * 24006 * @param client bound to the hub. 24007 * @param scope bound to the hub. 24008 * @param version number, higher number means higher priority. 24009 * 24010 * @deprecated Instantiation of Hub objects is deprecated and the constructor will be removed in version 8 of the SDK. 24011 * 24012 * If you are currently using the Hub for multi-client use like so: 24013 * 24014 * ``` 24015 * // OLD 24016 * const hub = new Hub(); 24017 * hub.bindClient(client); 24018 * makeMain(hub) 24019 * ``` 24020 * 24021 * instead initialize the client as follows: 24022 * 24023 * ``` 24024 * // NEW 24025 * Sentry.withIsolationScope(() => { 24026 * Sentry.setCurrentClient(client); 24027 * client.init(); 24028 * }); 24029 * ``` 24030 * 24031 * If you are using the Hub to capture events like so: 24032 * 24033 * ``` 24034 * // OLD 24035 * const client = new Client(); 24036 * const hub = new Hub(client); 24037 * hub.captureException() 24038 * ``` 24039 * 24040 * instead capture isolated events as follows: 24041 * 24042 * ``` 24043 * // NEW 24044 * const client = new Client(); 24045 * const scope = new Scope(); 24046 * scope.setClient(client); 24047 * scope.captureException(); 24048 * ``` 24049 */ 24050 constructor( 24051 client, 24052 scope$1, 24053 isolationScope, 24054 _version = API_VERSION, 24055 ) {this._version = _version; 24056 let assignedScope; 24057 if (!scope$1) { 24058 assignedScope = new scope.Scope(); 24059 assignedScope.setClient(client); 24060 } else { 24061 assignedScope = scope$1; 24062 } 24063 24064 let assignedIsolationScope; 24065 if (!isolationScope) { 24066 assignedIsolationScope = new scope.Scope(); 24067 assignedIsolationScope.setClient(client); 24068 } else { 24069 assignedIsolationScope = isolationScope; 24070 } 24071 24072 this._stack = [{ scope: assignedScope }]; 24073 24074 if (client) { 24075 // eslint-disable-next-line deprecation/deprecation 24076 this.bindClient(client); 24077 } 24078 24079 this._isolationScope = assignedIsolationScope; 24080 } 24081 24082 /** 24083 * Checks if this hub's version is older than the given version. 24084 * 24085 * @param version A version number to compare to. 24086 * @return True if the given version is newer; otherwise false. 24087 * 24088 * @deprecated This will be removed in v8. 24089 */ 24090 isOlderThan(version) { 24091 return this._version < version; 24092 } 24093 24094 /** 24095 * This binds the given client to the current scope. 24096 * @param client An SDK client (client) instance. 24097 * 24098 * @deprecated Use `initAndBind()` directly, or `setCurrentClient()` and/or `client.init()` instead. 24099 */ 24100 bindClient(client) { 24101 // eslint-disable-next-line deprecation/deprecation 24102 const top = this.getStackTop(); 24103 top.client = client; 24104 top.scope.setClient(client); 24105 // eslint-disable-next-line deprecation/deprecation 24106 if (client && client.setupIntegrations) { 24107 // eslint-disable-next-line deprecation/deprecation 24108 client.setupIntegrations(); 24109 } 24110 } 24111 24112 /** 24113 * @inheritDoc 24114 * 24115 * @deprecated Use `withScope` instead. 24116 */ 24117 pushScope() { 24118 // We want to clone the content of prev scope 24119 // eslint-disable-next-line deprecation/deprecation
24120 const scope = this.getScope().clone(); 24121 // eslint-disable-next-line deprecation/deprecation 24122 this.getStack().push({ 24123 // eslint-disable-next-line deprecation/deprecation 24124 client: this.getClient(), 24125 scope, 24126 }); 24127 return scope; 24128 } 24129 24130 /** 24131 * @inheritDoc 24132 * 24133 * @deprecated Use `withScope` instead. 24134 */ 24135 popScope() { 24136 // eslint-disable-next-line deprecation/deprecation 24137 if (this.getStack().length <= 1) return false; 24138 // eslint-disable-next-line deprecation/deprecation 24139 return !!this.getStack().pop(); 24140 } 24141 24142 /** 24143 * @inheritDoc 24144 * 24145 * @deprecated Use `Sentry.withScope()` instead. 24146 */ 24147 withScope(callback) { 24148 // eslint-disable-next-line deprecation/deprecation 24149 const scope = this.pushScope(); 24150 24151 let maybePromiseResult; 24152 try { 24153 maybePromiseResult = callback(scope); 24154 } catch (e) { 24155 // eslint-disable-next-line deprecation/deprecation 24156 this.popScope(); 24157 throw e; 24158 } 24159 24160 if (utils.isThenable(maybePromiseResult)) { 24161 // @ts-expect-error - isThenable returns the wrong type 24162 return maybePromiseResult.then( 24163 res => { 24164 // eslint-disable-next-line deprecation/deprecation 24165 this.popScope(); 24166 return res; 24167 }, 24168 e => { 24169 // eslint-disable-next-line deprecation/deprecation 24170 this.popScope(); 24171 throw e; 24172 }, 24173 ); 24174 } 24175 24176 // eslint-disable-next-line deprecation/deprecation 24177 this.popScope(); 24178 return maybePromiseResult; 24179 } 24180 24181 /** 24182 * @inheritDoc 24183 * 24184 * @deprecated Use `Sentry.getClient()` instead. 24185 */ 24186 getClient() { 24187 // eslint-disable-next-line deprecation/deprecation 24188 return this.getStackTop().client ; 24189 } 24190 24191 /** 24192 * Returns the scope of the top stack. 24193 * 24194 * @deprecated Use `Sentry.getCurrentScope()` instead. 24195 */ 24196 getScope() { 24197 // eslint-disable-next-line deprecation/deprecation 24198 return this.getStackTop().scope; 24199 } 24200 24201 /** 24202 * @deprecated Use `Sentry.getIsolationScope()` instead. 24203 */ 24204 getIsolationScope() { 24205 return this._isolationScope; 24206 } 24207 24208 /** 24209 * Returns the scope stack for domains or the process. 24210 * @deprecated This will be removed in v8. 24211 */ 24212 getStack() { 24213 return this._stack; 24214 } 24215 24216 /** 24217 * Returns the topmost scope layer in the order domain > local > process. 24218 * @deprecated This will be removed in v8. 24219 */ 24220 getStackTop() { 24221 return this._stack[this._stack.length - 1]; 24222 } 24223 24224 /** 24225 * @inheritDoc 24226 * 24227 * @deprecated Use `Sentry.captureException()` instead. 24228 */ 24229 captureException(exception, hint) { 24230 const eventId = (this._lastEventId = hint && hint.event_id ? hint.event_id : utils.uuid4()); 24231 const syntheticException = new Error('Sentry syntheticException'); 24232 // eslint-disable-next-line deprecation/deprecation 24233 this.getScope().captureException(exception, { 24234 originalException: exception, 24235 syntheticException, 24236 ...hint, 24237 event_id: eventId, 24238 }); 24239 24240 return eventId; 24241 } 24242 24243 /** 24244 * @inheritDoc 24245 * 24246 * @deprecated Use `Sentry.captureMessage()` instead. 24247 */ 24248 captureMessage( 24249 message, 24250 // eslint-disable-next-line deprecation/deprecation 24251 level, 24252 hint, 24253 ) { 24254 const eventId = (this._lastEventId = hint && hint.event_id ? hint.event_id : utils.uuid4()); 24255 const syntheticException = new Error(message); 24256 // eslint-disable-next-line deprecation/deprecation 24257 this.getScope().captureMessage(message, level, { 24258 originalException: message, 24259 syntheticException, 24260 ...hint, 24261 event_id: eventId, 24262 }); 24263 24264 return eventId; 24265 } 24266 24267 /** 24268 * @inheritDoc 24269 * 24270 * @deprecated Use `Sentry.captureEvent()` instead. 24271 */ 24272 captureEvent(event, hint) { 24273 const eventId = hint && hint.event_id ? hint.event_id : utils.uuid4(); 24274 if (!event.type) { 24275 this._lastEventId = eventId; 24276 } 24277 // eslint-disable-next-line deprecation/deprecation 24278 this.getScope().captureEvent(event, { ...hint, event_id: eventId }); 24279 return eventId; 24280 } 24281 24282 /** 24283 * @inheritDoc 24284 * 24285 * @deprecated This will be removed in v8. 24286 */ 24287 lastEventId() { 24288 return this._lastEventId; 24289 } 24290 24291 /** 24292 * @inheritDoc 24293 * 24294 * @deprecated Use `Sentry.addBreadcrumb()` instead. 24295 */ 24296 addBreadcrumb(breadcrumb, hint) { 24297 // eslint-disable-next-line deprecation/deprecation 24298 const { scope, client }
24298 = this.getStackTop(); 24299 24300 if (!client) return; 24301 24302 const { beforeBreadcrumb = null, maxBreadcrumbs = DEFAULT_BREADCRUMBS } = 24303 (client.getOptions && client.getOptions()) || {}; 24304 24305 if (maxBreadcrumbs <= 0) return; 24306 24307 const timestamp = utils.dateTimestampInSeconds(); 24308 const mergedBreadcrumb = { timestamp, ...breadcrumb }; 24309 const finalBreadcrumb = beforeBreadcrumb 24310 ? (utils.consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint)) ) 24311 : mergedBreadcrumb; 24312 24313 if (finalBreadcrumb === null) return; 24314 24315 if (client.emit) { 24316 client.emit('beforeAddBreadcrumb', finalBreadcrumb, hint); 24317 } 24318 24319 // TODO(v8): I know this comment doesn't make much sense because the hub will be deprecated but I still wanted to 24320 // write it down. In theory, we would have to add the breadcrumbs to the isolation scope here, however, that would 24321 // duplicate all of the breadcrumbs. There was the possibility of adding breadcrumbs to both, the isolation scope 24322 // and the normal scope, and deduplicating it down the line in the event processing pipeline. However, that would 24323 // have been very fragile, because the breadcrumb objects would have needed to keep their identity all throughout 24324 // the event processing pipeline. 24325 // In the new implementation, the top level `Sentry.addBreadcrumb()` should ONLY write to the isolation scope. 24326 24327 scope.addBreadcrumb(finalBreadcrumb, maxBreadcrumbs); 24328 } 24329 24330 /** 24331 * @inheritDoc 24332 * @deprecated Use `Sentry.setUser()` instead. 24333 */ 24334 setUser(user) { 24335 // TODO(v8): The top level `Sentry.setUser()` function should write ONLY to the isolation scope. 24336 // eslint-disable-next-line deprecation/deprecation 24337 this.getScope().setUser(user); 24338 // eslint-disable-next-line deprecation/deprecation 24339 this.getIsolationScope().setUser(user); 24340 } 24341 24342 /** 24343 * @inheritDoc 24344 * @deprecated Use `Sentry.setTags()` instead. 24345 */ 24346 setTags(tags) { 24347 // TODO(v8): The top level `Sentry.setTags()` function should write ONLY to the isolation scope. 24348 // eslint-disable-next-line deprecation/deprecation 24349 this.getScope().setTags(tags); 24350 // eslint-disable-next-line deprecation/deprecation 24351 this.getIsolationScope().setTags(tags); 24352 } 24353 24354 /** 24355 * @inheritDoc 24356 * @deprecated Use `Sentry.setExtras()` instead. 24357 */ 24358 setExtras(extras) { 24359 // TODO(v8): The top level `Sentry.setExtras()` function should write ONLY to the isolation scope. 24360 // eslint-disable-next-line deprecation/deprecation 24361 this.getScope().setExtras(extras); 24362 // eslint-disable-next-line deprecation/deprecation 24363 this.getIsolationScope().setExtras(extras); 24364 } 24365 24366 /** 24367 * @inheritDoc 24368 * @deprecated Use `Sentry.setTag()` instead. 24369 */ 24370 setTag(key, value) { 24371 // TODO(v8): The top level `Sentry.setTag()` function should write ONLY to the isolation scope. 24372 // eslint-disable-next-line deprecation/deprecation 24373 this.getScope().setTag(key, value); 24374 // eslint-disable-next-line deprecation/deprecation 24375 this.getIsolationScope().setTag(key, value); 24376 } 24377 24378 /** 24379 * @inheritDoc 24380 * @deprecated Use `Sentry.setExtra()` instead. 24381 */ 24382 setExtra(key, extra) { 24383 // TODO(v8): The top level `Sentry.setExtra()` function should write ONLY to the isolation scope. 24384 // eslint-disable-next-line deprecation/deprecation 24385 this.getScope().setExtra(key, extra); 24386 // eslint-disable-next-line deprecation/deprecation 24387 this.getIsolationScope().setExtra(key, extra); 24388 } 24389 24390 /** 24391 * @inheritDoc 24392 * @deprecated Use `Sentry.setContext()` instead. 24393 */ 24394 // eslint-disable-next-line @typescript-eslint/no-explicit-any 24395 setContext(name, context) { 24396 // TODO(v8): The top level `Sentry.setContext()` function should write ONLY to the isolation scope. 24397 // eslint-disable-next-line deprecation/deprecation 24398 this.getScope().setContext(name, context); 24399 // eslint-disable-next-line deprecation/deprecation 24400 this.getIsolationScope().setContext(name, context); 24401 } 24402 24403 /** 24404 * @inheritDoc 24405 * 24406 * @deprecated Use `getScope()` directly. 24407 */ 24408 configureScope(callback) { 24409 // eslint-disable-next-line deprecation/deprecation 24410 const { scope, client }
vendor: 9,493 bytes, lines 24410-24708
24410 = this.getStackTop(); 24411 if (client) { 24412 callback(scope); 24413 } 24414 } 24415 24416 /** 24417 * @inheritDoc 24418 */ 24419 run(callback) { 24420 // eslint-disable-next-line deprecation/deprecation 24421 const oldHub = makeMain(this); 24422 try { 24423 callback(this); 24424 } finally { 24425 // eslint-disable-next-line deprecation/deprecation 24426 makeMain(oldHub); 24427 } 24428 } 24429 24430 /** 24431 * @inheritDoc 24432 * @deprecated Use `Sentry.getClient().getIntegrationByName()` instead. 24433 */ 24434 getIntegration(integration) { 24435 // eslint-disable-next-line deprecation/deprecation 24436 const client = this.getClient(); 24437 if (!client) return null; 24438 try { 24439 // eslint-disable-next-line deprecation/deprecation 24440 return client.getIntegration(integration); 24441 } catch (_oO) { 24442 debugBuild.DEBUG_BUILD && utils.logger.warn(`Cannot retrieve integration ${integration.id} from the current Hub`); 24443 return null; 24444 } 24445 } 24446 24447 /** 24448 * Starts a new `Transaction` and returns it. This is the entry point to manual tracing instrumentation. 24449 * 24450 * A tree structure can be built by adding child spans to the transaction, and child spans to other spans. To start a 24451 * new child span within the transaction or any span, call the respective `.startChild()` method. 24452 * 24453 * Every child span must be finished before the transaction is finished, otherwise the unfinished spans are discarded. 24454 * 24455 * The transaction must be finished with a call to its `.end()` method, at which point the transaction with all its 24456 * finished child spans will be sent to Sentry. 24457 * 24458 * @param context Properties of the new `Transaction`. 24459 * @param customSamplingContext Information given to the transaction sampling function (along with context-dependent 24460 * default values). See {@link Options.tracesSampler}. 24461 * 24462 * @returns The transaction which was just started 24463 * 24464 * @deprecated Use `startSpan()`, `startSpanManual()` or `startInactiveSpan()` instead. 24465 */ 24466 startTransaction(context, customSamplingContext) { 24467 const result = this._callExtensionMethod('startTransaction', context, customSamplingContext); 24468 24469 if (debugBuild.DEBUG_BUILD && !result) { 24470 // eslint-disable-next-line deprecation/deprecation 24471 const client = this.getClient(); 24472 if (!client) { 24473 utils.logger.warn( 24474 "Tracing extension 'startTransaction' is missing. You should 'init' the SDK before calling 'startTransaction'", 24475 ); 24476 } else { 24477 utils.logger.warn(`Tracing extension 'startTransaction' has not been added. Call 'addTracingExtensions' before calling 'init': 24478Sentry.addTracingExtensions(); 24479Sentry.init({...}); 24480`); 24481 } 24482 } 24483 24484 return result; 24485 } 24486 24487 /** 24488 * @inheritDoc 24489 * @deprecated Use `spanToTraceHeader()` instead. 24490 */ 24491 traceHeaders() { 24492 return this._callExtensionMethod('traceHeaders'); 24493 } 24494 24495 /** 24496 * @inheritDoc 24497 * 24498 * @deprecated Use top level `captureSession` instead. 24499 */ 24500 captureSession(endSession = false) { 24501 // both send the update and pull the session from the scope 24502 if (endSession) { 24503 // eslint-disable-next-line deprecation/deprecation 24504 return this.endSession(); 24505 } 24506 24507 // only send the update 24508 this._sendSessionUpdate(); 24509 } 24510 24511 /** 24512 * @inheritDoc 24513 * @deprecated Use top level `endSession` instead. 24514 */ 24515 endSession() { 24516 // eslint-disable-next-line deprecation/deprecation 24517 const layer = this.getStackTop(); 24518 const scope = layer.scope; 24519 const session$1 = scope.getSession(); 24520 if (session$1) { 24521 session.closeSession(session$1); 24522 } 24523 this._sendSessionUpdate(); 24524 24525 // the session is over; take it off of the scope 24526 scope.setSession(); 24527 } 24528 24529 /** 24530 * @inheritDoc 24531 * @deprecated Use top level `startSession` instead. 24532 */ 24533 startSession(context) { 24534 // eslint-disable-next-line deprecation/deprecation 24535 const { scope, client } = this.getStackTop(); 24536 const { release, environment = constants.DEFAULT_ENVIRONMENT } = (client && client.getOptions()) || {}; 24537 24538 // Will fetch userAgent if called from browser sdk 24539 const { userAgent } = utils.GLOBAL_OBJ.navigator || {}; 24540 24541 const session$1 = session.makeSession({ 24542 release, 24543 environment, 24544 user: scope.getUser(), 24545 ...(userAgent && { userAgent }), 24546 ...context, 24547 }); 24548 24549 // End existing session if there's one 24550 const currentSession = scope.getSession && scope.getSession(); 24551 if (currentSession && currentSession.status === 'ok') { 24552 session.updateSession(currentSession, { status: 'exited' }); 24553 } 24554 // eslint-disable-next-line deprecation/deprecation 24555 this.endSession(); 24556 24557 // Afterwards we set the new session on the scope 24558 scope.setSession(session$1); 24559 24560 return session$1; 24561 } 24562 24563 /** 24564 * Returns if default PII should be sent to Sentry and propagated in ourgoing requests 24565 * when Tracing is used. 24566 * 24567 * @deprecated Use top-level `getClient().getOptions().sendDefaultPii` instead. This function 24568 * only unnecessarily increased API surface but only wrapped accessing the option. 24569 */ 24570 shouldSendDefaultPii() { 24571 // eslint-disable-next-line deprecation/deprecation 24572 const client = this.getClient(); 24573 const options = client && client.getOptions(); 24574 return Boolean(options && options.sendDefaultPii); 24575 } 24576 24577 /** 24578 * Sends the current Session on the scope 24579 */ 24580 _sendSessionUpdate() { 24581 // eslint-disable-next-line deprecation/deprecation 24582 const { scope, client } = this.getStackTop(); 24583 24584 const session = scope.getSession(); 24585 if (session && client && client.captureSession) { 24586 client.captureSession(session); 24587 } 24588 } 24589 24590 /** 24591 * Calls global extension method and binding current instance to the function call 24592 */ 24593 // @ts-expect-error Function lacks ending return statement and return type does not include 'undefined'. ts(2366) 24594 // eslint-disable-next-line @typescript-eslint/no-explicit-any 24595 _callExtensionMethod(method, ...args) { 24596 const carrier = getMainCarrier(); 24597 const sentry = carrier.__SENTRY__; 24598 if (sentry && sentry.extensions && typeof sentry.extensions[method] === 'function') { 24599 return sentry.extensions[method].apply(this, args); 24600 } 24601 debugBuild.DEBUG_BUILD && utils.logger.warn(`Extension method ${method} couldn't be found, doing nothing.`); 24602 } 24603} 24604 24605/** 24606 * Returns the global shim registry. 24607 * 24608 * FIXME: This function is problematic, because despite always returning a valid Carrier, 24609 * it has an optional `__SENTRY__` property, which then in turn requires us to always perform an unnecessary check 24610 * at the call-site. We always access the carrier through this function, so we can guarantee that `__SENTRY__` is there. 24611 **/ 24612function getMainCarrier() { 24613 utils.GLOBAL_OBJ.__SENTRY__ = utils.GLOBAL_OBJ.__SENTRY__ || { 24614 extensions: {}, 24615 hub: undefined, 24616 }; 24617 return utils.GLOBAL_OBJ; 24618} 24619 24620/** 24621 * Replaces the current main hub with the passed one on the global object 24622 * 24623 * @returns The old replaced hub 24624 * 24625 * @deprecated Use `setCurrentClient()` instead. 24626 */ 24627function makeMain(hub) { 24628 const registry = getMainCarrier(); 24629 const oldHub = getHubFromCarrier(registry); 24630 setHubOnCarrier(registry, hub); 24631 return oldHub; 24632} 24633 24634/** 24635 * Returns the default hub instance. 24636 * 24637 * If a hub is already registered in the global carrier but this module 24638 * contains a more recent version, it replaces the registered version. 24639 * Otherwise, the currently registered hub will be returned. 24640 * 24641 * @deprecated Use the respective replacement method directly instead. 24642 */ 24643function getCurrentHub() { 24644 // Get main carrier (global for every environment) 24645 const registry = getMainCarrier(); 24646 24647 if (registry.__SENTRY__ && registry.__SENTRY__.acs) { 24648 const hub = registry.__SENTRY__.acs.getCurrentHub(); 24649 24650 if (hub) { 24651 return hub; 24652 } 24653 } 24654 24655 // Return hub that lives on a global object 24656 return getGlobalHub(registry); 24657} 24658 24659/** 24660 * Get the currently active isolation scope. 24661 * The isolation scope is active for the current exection context, 24662 * meaning that it will remain stable for the same Hub. 24663 */ 24664function getIsolationScope() { 24665 // eslint-disable-next-line deprecation/deprecation 24666 return getCurrentHub().getIsolationScope(); 24667} 24668 24669function getGlobalHub(registry = getMainCarrier()) { 24670 // If there's no hub, or its an old API, assign a new one 24671 24672 if ( 24673 !hasHubOnCarrier(registry) || 24674 // eslint-disable-next-line deprecation/deprecation 24675 getHubFromCarrier(registry).isOlderThan(API_VERSION) 24676 ) { 24677 // eslint-disable-next-line deprecation/deprecation 24678 setHubOnCarrier(registry, new Hub()); 24679 } 24680 24681 // Return hub that lives on a global object 24682 return getHubFromCarrier(registry); 24683} 24684 24685/** 24686 * @private Private API with no semver guarantees! 24687 * 24688 * If the carrier does not contain a hub, a new hub is created with the global hub client and scope. 24689 */ 24690function ensureHubOnCarrier(carrier, parent = getGlobalHub()) { 24691 // If there's no hub on current domain, or it's an old API, assign a new one 24692 if ( 24693 !hasHubOnCarrier(carrier) || 24694 // eslint-disable-next-line deprecation/deprecation 24695 getHubFromCarrier(carrier).isOlderThan(API_VERSION) 24696 ) { 24697 // eslint-disable-next-line deprecation/deprecation 24698 const client = parent.getClient(); 24699 // eslint-disable-next-line deprecation/deprecation 24700 const scope = parent.getScope(); 24701 // eslint-disable-next-line deprecation/deprecation 24702 const isolationScope = parent.getIsolationScope(); 24703 // eslint-disable-next-line deprecation/deprecation 24704 setHubOnCarrier(carrier, new Hub(client, scope.clone(), isolationScope.clone())); 24705 } 24706} 24707 24708/**
24709 * @private Private API with no semver guarantees! 24710 * 24711 * Sets the global async context strategy 24712 */ 24713function setAsyncContextStrategy(strategy) { 24714 // Get main carrier (global for every environment) 24715 const registry = getMainCarrier(); 24716 registry.__SENTRY__ = registry.__SENTRY__ || {}; 24717 registry.__SENTRY__.acs = strategy; 24718} 24719 24720/** 24721 * Runs the supplied callback in its own async context. Async Context strategies are defined per SDK. 24722 * 24723 * @param callback The callback to run in its own async context 24724 * @param options Options to pass to the async context strategy 24725 * @returns The result of the callback 24726 */ 24727function runWithAsyncContext(callback, options = {}) { 24728 const registry = getMainCarrier(); 24729 24730 if (registry.__SENTRY__ && registry.__SENTRY__.acs) { 24731 return registry.__SENTRY__.acs.runWithAsyncContext(callback, options); 24732 } 24733 24734 // if there was no strategy, fallback to just calling the callback 24735 return callback(); 24736} 24737 24738/** 24739 * This will tell whether a carrier has a hub on it or not 24740 * @param carrier object 24741 */ 24742function hasHubOnCarrier(carrier) { 24743 return !!(carrier && carrier.__SENTRY__ && carrier.__SENTRY__.hub); 24744} 24745 24746/** 24747 * This will create a new {@link Hub} and add to the passed object on 24748 * __SENTRY__.hub. 24749 * @param carrier object 24750 * @hidden 24751 */ 24752function getHubFromCarrier(carrier) { 24753 // eslint-disable-next-line deprecation/deprecation 24754 return utils.getGlobalSingleton('hub', () => new Hub(), carrier); 24755} 24756 24757/** 24758 * This will set passed {@link Hub} on the passed object's __SENTRY__.hub attribute 24759 * @param carrier object 24760 * @param hub Hub 24761 * @returns A boolean indicating success or failure 24762 */ 24763function setHubOnCarrier(carrier, hub) { 24764 if (!carrier) return false; 24765 const __SENTRY__ = (carrier.__SENTRY__ = carrier.__SENTRY__ || {}); 24766 __SENTRY__.hub = hub; 24767 return true; 24768} 24769 24770exports.API_VERSION = API_VERSION; 24771exports.Hub = Hub; 24772exports.ensureHubOnCarrier = ensureHubOnCarrier; 24773exports.getCurrentHub = getCurrentHub; 24774exports.getHubFromCarrier = getHubFromCarrier; 24775exports.getIsolationScope = getIsolationScope; 24776exports.getMainCarrier = getMainCarrier; 24777exports.makeMain = makeMain; 24778exports.runWithAsyncContext = runWithAsyncContext; 24779exports.setAsyncContextStrategy = setAsyncContextStrategy; 24780exports.setHubOnCarrier = setHubOnCarrier; 24781 24782 24783},{"./constants.js":244,"./debug-build.js":245,"./scope.js":268,"./session.js":272,"./version.js":298,"@sentry/utils":319}],250:[function(require,module,exports){ 24784Object.defineProperty(exports, '__esModule', { value: true }); 24785 24786const hubextensions = require('./tracing/hubextensions.js'); 24787const idletransaction = require('./tracing/idletransaction.js'); 24788const span$1 = require('./tracing/span.js'); 24789const transaction = require('./tracing/transaction.js'); 24790const utils = require('./tracing/utils.js'); 24791const spanstatus = require('./tracing/spanstatus.js'); 24792const trace = require('./tracing/trace.js'); 24793const dynamicSamplingContext = require('./tracing/dynamicSamplingContext.js'); 24794const measurement = require('./tracing/measurement.js'); 24795const sampling = require('./tracing/sampling.js'); 24796const semanticAttributes = require('./semanticAttributes.js'); 24797const envelope = require('./envelope.js'); 24798const exports$1 = require('./exports.js'); 24799const hub = require('./hub.js'); 24800const session = require('./session.js'); 24801const sessionflusher = require('./sessionflusher.js'); 24802const scope = require('./scope.js'); 24803const eventProcessors = require('./eventProcessors.js'); 24804const api = require('./api.js'); 24805const baseclient = require('./baseclient.js'); 24806const serverRuntimeClient = require('./server-runtime-client.js'); 24807const sdk = require('./sdk.js'); 24808const base = require('./transports/base.js'); 24809const offline = require('./transports/offline.js'); 24810const multiplexed = require('./transports/multiplexed.js'); 24811const version = require('./version.js'); 24812const integration = require('./integration.js'); 24813const applyScopeDataToEvent = require('./utils/applyScopeDataToEvent.js'); 24814const prepareEvent = require('./utils/prepareEvent.js'); 24815const checkin = require('./checkin.js'); 24816const span = require('./span.js'); 24817const hasTracingEnabled = require('./utils/hasTracingEnabled.js'); 24818const isSentryRequestUrl = require('./utils/isSentryRequestUrl.js'); 24819const handleCallbackErrors = require('./utils/handleCallbackErrors.js'); 24820const parameterize = require('./utils/parameterize.js'); 24821const spanUtils = require('./utils/spanUtils.js'); 24822const getRootSpan = require('./utils/getRootSpan.js'); 24823const sdkMetadata = require('./utils/sdkMetadata.js'); 24824const constants = require('./constants.js'); 24825const metadata = require('./integrations/metadata.js'); 24826const requestdata = require('./integrations/requestdata.js'); 24827const inboundfilters = require('./integrations/inboundfilters.js'); 24828const functiontostring = require('./integrations/functiontostring.js'); 24829const linkederrors = require('./integrations/linkederrors.js'); 24830const index = require('./integrations/index.js'); 24831const exports$2 = require('./metrics/exports.js'); 24832 24833/** @deprecated Import the integration function directly, e.g. `inboundFiltersIntegration()` instead of `new Integrations.InboundFilter(). */ 24834const Integrations = index; 24835 24836exports.addTracingExtensions = hubextensions.addTracingExtensions; 24837exports.startIdleTransaction = hubextensions.startIdleTransaction; 24838exports.IdleTransaction = idletransaction.IdleTransaction; 24839exports.TRACING_DEFAULTS = idletransaction.TRACING_DEFAULTS; 24840exports.Span = span$1.Span; 24841exports.Transaction = transaction.Transaction; 24842exports.extractTraceparentData = utils.extractTraceparentData; 24843exports.getActiveTransaction = utils.getActiveTransaction; 24844Object.defineProperty(exports, 'SpanStatus', { 24845 enumerable: true, 24846 get: () => spanstatus.SpanStatus 24847}); 24848exports.getSpanStatusFromHttpCode = spanstatus.getSpanStatusFromHttpCode; 24849exports.setHttpStatus = spanstatus.setHttpStatus; 24850exports.spanStatusfromHttpCode = spanstatus.spanStatusfromHttpCode; 24851exports.continueTrace = trace.continueTrace; 24852exports.getActiveSpan = trace.getActiveSpan; 24853exports.startActiveSpan = trace.startActiveSpan; 24854exports.startInactiveSpan = trace.startInactiveSpan; 24855exports.startSpan = trace.startSpan; 24856exports.startSpanManual = trace.startSpanManual; 24857exports.trace = trace.trace; 24858exports.getDynamicSamplingContextFromClient = dynamicSamplingContext.getDynamicSamplingContextFromClient; 24859exports.getDynamicSamplingContextFromSpan = dynamicSamplingContext.getDynamicSamplingContextFromSpan; 24860exports.setMeasurement = measurement.setMeasurement; 24861exports.isValidSampleRate = sampling.isValidSampleRate; 24862exports.SEMANTIC_ATTRIBUTE_PROFILE_ID = semanticAttributes.SEMANTIC_ATTRIBUTE_PROFILE_ID; 24863exports.SEMANTIC_ATTRIBUTE_SENTRY_OP = semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_OP; 24864exports.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN; 24865exports.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE; 24866exports.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE;
24867exports.createEventEnvelope = envelope.createEventEnvelope; 24868exports.createSessionEnvelope = envelope.createSessionEnvelope; 24869exports.addBreadcrumb = exports$1.addBreadcrumb; 24870exports.captureCheckIn = exports$1.captureCheckIn; 24871exports.captureEvent = exports$1.captureEvent; 24872exports.captureException = exports$1.captureException; 24873exports.captureMessage = exports$1.captureMessage; 24874exports.captureSession = exports$1.captureSession; 24875exports.close = exports$1.close; 24876exports.configureScope = exports$1.configureScope; 24877exports.endSession = exports$1.endSession; 24878exports.flush = exports$1.flush; 24879exports.getClient = exports$1.getClient; 24880exports.getCurrentScope = exports$1.getCurrentScope; 24881exports.isInitialized = exports$1.isInitialized; 24882exports.lastEventId = exports$1.lastEventId; 24883exports.setContext = exports$1.setContext; 24884exports.setExtra = exports$1.setExtra; 24885exports.setExtras = exports$1.setExtras; 24886exports.setTag = exports$1.setTag; 24887exports.setTags = exports$1.setTags; 24888exports.setUser = exports$1.setUser; 24889exports.startSession = exports$1.startSession; 24890exports.startTransaction = exports$1.startTransaction; 24891exports.withActiveSpan = exports$1.withActiveSpan; 24892exports.withIsolationScope = exports$1.withIsolationScope; 24893exports.withMonitor = exports$1.withMonitor; 24894exports.withScope = exports$1.withScope; 24895exports.Hub = hub.Hub; 24896exports.ensureHubOnCarrier = hub.ensureHubOnCarrier; 24897exports.getCurrentHub = hub.getCurrentHub; 24898exports.getHubFromCarrier = hub.getHubFromCarrier; 24899exports.getIsolationScope = hub.getIsolationScope; 24900exports.getMainCarrier = hub.getMainCarrier; 24901exports.makeMain = hub.makeMain; 24902exports.runWithAsyncContext = hub.runWithAsyncContext; 24903exports.setAsyncContextStrategy = hub.setAsyncContextStrategy; 24904exports.setHubOnCarrier = hub.setHubOnCarrier; 24905exports.closeSession = session.closeSession; 24906exports.makeSession = session.makeSession; 24907exports.updateSession = session.updateSession; 24908exports.SessionFlusher = sessionflusher.SessionFlusher; 24909exports.Scope = scope.Scope; 24910exports.getGlobalScope = scope.getGlobalScope; 24911exports.setGlobalScope = scope.setGlobalScope; 24912exports.addGlobalEventProcessor = eventProcessors.addGlobalEventProcessor; 24913exports.notifyEventProcessors = eventProcessors.notifyEventProcessors; 24914exports.getEnvelopeEndpointWithUrlEncodedAuth = api.getEnvelopeEndpointWithUrlEncodedAuth; 24915exports.getReportDialogEndpoint = api.getReportDialogEndpoint; 24916exports.BaseClient = baseclient.BaseClient; 24917exports.addEventProcessor = baseclient.addEventProcessor; 24918exports.ServerRuntimeClient = serverRuntimeClient.ServerRuntimeClient; 24919exports.initAndBind = sdk.initAndBind; 24920exports.setCurrentClient = sdk.setCurrentClient; 24921exports.createTransport = base.createTransport; 24922exports.makeOfflineTransport = offline.makeOfflineTransport; 24923exports.makeMultiplexedTransport = multiplexed.makeMultiplexedTransport; 24924exports.SDK_VERSION = version.SDK_VERSION; 24925exports.addIntegration = integration.addIntegration; 24926exports.convertIntegrationFnToClass = integration.convertIntegrationFnToClass;
24927exports.defineIntegration = integration.defineIntegration; 24928exports.getIntegrationsToSetup = integration.getIntegrationsToSetup; 24929exports.applyScopeDataToEvent = applyScopeDataToEvent.applyScopeDataToEvent; 24930exports.mergeScopeData = applyScopeDataToEvent.mergeScopeData; 24931exports.prepareEvent = prepareEvent.prepareEvent; 24932exports.createCheckInEnvelope = checkin.createCheckInEnvelope; 24933exports.createSpanEnvelope = span.createSpanEnvelope; 24934exports.hasTracingEnabled = hasTracingEnabled.hasTracingEnabled; 24935exports.isSentryRequestUrl = isSentryRequestUrl.isSentryRequestUrl; 24936exports.handleCallbackErrors = handleCallbackErrors.handleCallbackErrors; 24937exports.parameterize = parameterize.parameterize; 24938exports.spanIsSampled = spanUtils.spanIsSampled; 24939exports.spanToJSON = spanUtils.spanToJSON; 24940exports.spanToTraceContext = spanUtils.spanToTraceContext; 24941exports.spanToTraceHeader = spanUtils.spanToTraceHeader; 24942exports.getRootSpan = getRootSpan.getRootSpan; 24943exports.applySdkMetadata = sdkMetadata.applySdkMetadata; 24944exports.DEFAULT_ENVIRONMENT = constants.DEFAULT_ENVIRONMENT; 24945exports.ModuleMetadata = metadata.ModuleMetadata; 24946exports.moduleMetadataIntegration = metadata.moduleMetadataIntegration; 24947exports.RequestData = requestdata.RequestData; 24948exports.requestDataIntegration = requestdata.requestDataIntegration; 24949exports.InboundFilters = inboundfilters.InboundFilters; 24950exports.inboundFiltersIntegration = inboundfilters.inboundFiltersIntegration; 24951exports.FunctionToString = functiontostring.FunctionToString; 24952exports.functionToStringIntegration = functiontostring.functionToStringIntegration; 24953exports.LinkedErrors = linkederrors.LinkedErrors; 24954exports.linkedErrorsIntegration = linkederrors.linkedErrorsIntegration; 24955exports.metrics = exports$2.metrics; 24956exports.Integrations = Integrations; 24957 24958 24959},{"./api.js":241,"./baseclient.js":242,"./checkin.js":243,"./constants.js":244,"./envelope.js":246,"./eventProcessors.js":247,"./exports.js":248,"./hub.js":249,"./integration.js":251,"./integrations/functiontostring.js":252,"./integrations/inboundfilters.js":253,"./integrations/index.js":254,"./integrations/linkederrors.js":255,"./integrations/metadata.js":256,"./integrations/requestdata.js":257,"./metrics/exports.js":263,"./scope.js":268,"./sdk.js":269,"./semanticAttributes.js":270,"./server-runtime-client.js":271,"./session.js":272,"./sessionflusher.js":273,"./span.js":274,"./tracing/dynamicSamplingContext.js":275,"./tracing/hubextensions.js":277,"./tracing/idletransaction.js":278,"./tracing/measurement.js":279,"./tracing/sampling.js":280,"./tracing/span.js":281,"./tracing/spanstatus.js":282,"./tracing/trace.js":283,"./tracing/transaction.js":284,"./tracing/utils.js":285,"./transports/base.js":286,"./transports/multiplexed.js":287,"./transports/offline.js":288,"./utils/applyScopeDataToEvent.js":289,"./utils/getRootSpan.js":290,"./utils/handleCallbackErrors.js":291,"./utils/hasTracingEnabled.js":292,"./utils/isSentryRequestUrl.js":293,"./utils/parameterize.js":294,"./ut
24959ils/prepareEvent.js":295,"./utils/sdkMetadata.js":296,"./utils/spanUtils.js":297,"./version.js":298}],251:[function(require,module,exports){ 24960Object.defineProperty(exports, '__esModule', { value: true }); 24961 24962const utils = require('@sentry/utils'); 24963const debugBuild = require('./debug-build.js'); 24964const eventProcessors = require('./eventProcessors.js'); 24965const exports$1 = require('./exports.js'); 24966const hub = require('./hub.js'); 24967 24968const installedIntegrations = []; 24969 24970/** Map of integrations assigned to a client */ 24971 24972/** 24973 * Remove duplicates from the given array, preferring the last instance of any duplicate. Not guaranteed to 24974 * preseve the order of integrations in the array. 24975 * 24976 * @private 24977 */ 24978function filterDuplicates(integrations) { 24979 const integrationsByName = {}; 24980 24981 integrations.forEach(currentInstance => { 24982 const { name } = currentInstance; 24983 24984 const existingInstance = integrationsByName[name]; 24985 24986 // We want integrations later in the array to overwrite earlier ones of the same type, except that we never want a 24987 // default instance to overwrite an existing user instance 24988 if (existingInstance && !existingInstance.isDefaultInstance && currentInstance.isDefaultInstance) { 24989 return; 24990 } 24991 24992 integrationsByName[name] = currentInstance; 24993 }); 24994 24995 return Object.keys(integrationsByName).map(k => integrationsByName[k]); 24996} 24997 24998/** Gets integrations to install */ 24999function getIntegrationsToSetup(options) { 25000 const defaultIntegrations = options.defaultIntegrations || []; 25001 const userIntegrations = options.integrations; 25002 25003 // We flag default instances, so that later we can tell them apart from any user-created instances of the same class 25004 defaultIntegrations.forEach(integration => { 25005 integration.isDefaultInstance = true; 25006 }); 25007 25008 let integrations; 25009 25010 if (Array.isArray(userIntegrations)) { 25011 integrations = [...defaultIntegrations, ...userIntegrations]; 25012 } else if (typeof userIntegrations === 'function') { 25013 integrations = utils.arrayify(userIntegrations(defaultIntegrations)); 25014 } else { 25015 integrations = defaultIntegrations; 25016 } 25017 25018 const finalIntegrations = filterDuplicates(integrations); 25019 25020 // The `Debug` integration prints copies of the `event` and `hint` which will be passed to `beforeSend` or 25021 // `beforeSendTransaction`. It therefore has to run after all other integrations, so that the changes of all event 25022 // processors will be reflected in the printed values. For lack of a more elegant way to guarantee that, we therefore 25023 // locate it and, assuming it exists, pop it out of its current spot and shove it onto the end of the array. 25024 const debugIndex = findIndex(finalIntegrations, integration => integration.name === 'Debug'); 25025 if (debugIndex !== -1) { 25026 const [debugInstance] = finalIntegrations.splice(debugIndex, 1); 25027 finalIntegrations.push(debugInstance); 25028 } 25029 25030 return finalIntegrations; 25031} 25032 25033/** 25034 * Given a list of integration instances this installs them all. When `withDefaults` is set to `true` then all default 25035 * integrations are added unless they were already provided before. 25036 * @param integrations array of integration instances 25037 * @param withDefault should enable default integrations 25038 */ 25039function setupIntegrations(client, integrations) { 25040 const integrationIndex = {}; 25041 25042 integrations.forEach(integration => { 25043 // guard against empty provided integrations 25044 if (integration) { 25045 setupIntegration(client, integration, integrationIndex); 25046 } 25047 }); 25048 25049 return integrationIndex; 25050} 25051 25052/** 25053 * Execute the `afterAllSetup` hooks of the given integrations. 25054 */ 25055function afterSetupIntegrations(client, integrations) { 25056 for (const integration of integrations) { 25057 // guard against empty provided integrations 25058 if (integration && integration.afterAllSetup) { 25059 integration.afterAllSetup(client); 25060 } 25061 } 25062} 25063 25064/** Setup a single integration. */ 25065function setupIntegration(client, integration, integrationIndex) { 25066 if (integrationIndex[integration.name]) { 25067 debugBuild.DEBUG_BUILD && utils.logger.log(`Integration skipped because it was already installed: ${integration.name}`); 25068 return; 25069 } 25070 integrationIndex[integration.name] = integration; 25071 25072 // `setupOnce` is only called the first time 25073 if (installedIntegrations.indexOf(integration.name) === -1) { 25074 // eslint-disable-next-line deprecation/deprecation 25075 integration.setupOnce(eventProcessors.addGlobalEventProcessor, hub.getCurrentHub); 25076 installedIntegrations.push(integration.name); 25077 } 25078 25079 // `setup` is run for each client 25080 if (integration.setup && typeof integration.setup === 'function') { 25081 integration.setup(client); 25082 } 25083 25084 if (client.on && typeof integration.preprocessEvent === 'function') { 25085 const callback = integration.preprocessEvent.bind(integration) ; 25086 client.on('preprocessEvent', (event, hint) => callback(event, hint, client)); 25087 } 25088 25089 if (client.addEventProcessor && typeof integration.processEvent === 'function') { 25090 const callback = integration.processEvent.bind(integration) ; 25091 25092 const processor = Object.assign((event, hint) => callback(event, hint, client), { 25093 id: integration.name, 25094 }); 25095 25096 client.addEventProcessor(processor); 25097 } 25098 25099 debugBuild.DEBUG_BUILD && utils.logger.log(`Integration installed: ${integration.name}`); 25100} 25101 25102/** Add an integration to the current hub's client. */ 25103function addIntegration(integration) { 25104 const client = exports$1.getClient(); 25105 25106 if (!client || !client.addIntegration) { 25107 debugBuild.DEBUG_BUILD && utils.logger.warn(`Cannot add integration "${integration.name}" because no SDK Client is available.`); 25108 return; 25109 } 25110 25111 client.addIntegration(integration); 25112} 25113 25114// Polyfill for Array.findIndex(), which is not supported in ES5 25115function findIndex(arr, callback) { 25116 for (let i = 0; i < arr.length; i++) { 25117 if (callback(arr[i]) === true) { 25118 return i; 25119 } 25120 } 25121 25122 return -1; 25123} 25124 25125/** 25126 * Convert a new integration function to the legacy class syntax. 25127 * In v8, we can remove this and instead export the integration functions directly. 25128 * 25129 * @deprecated This will be removed in v8! 25130 */ 25131function convertIntegrationFnToClass( 25132 name, 25133 fn, 25134) { 25135 return Object.assign( 25136 function ConvertedIntegration(...args) { 25137 return fn(...args); 25138 }, 25139 { id: name }, 25140 ) ; 25141} 25142 25143/** 25144 * Define an integration function that can be used to create an integration instance. 25145 * Note that this by design hides the implementation details of the integration, as they are considered internal. 25146 */ 25147function defineIntegration(fn) { 25148 return fn; 25149} 25150 25151exports.addIntegration = addIntegration; 25152exports.afterSetupIntegrations = afterSetupIntegrations; 25153exports.convertIntegrationFnToClass = convertIntegrationFnToClass;
25154exports.defineIntegration = defineIntegration; 25155exports.getIntegrationsToSetup = getIntegrationsToSetup; 25156exports.installedIntegrations = installedIntegrations; 25157exports.setupIntegration = setupIntegration; 25158exports.setupIntegrations = setupIntegrations; 25159 25160 25161},{"./debug-build.js":245,"./eventProcessors.js":247,"./exports.js":248,"./hub.js":249,"@sentry/utils":319}],252:[function(require,module,exports){ 25162Object.defineProperty(exports, '__esModule', { value: true }); 25163 25164const utils = require('@sentry/utils'); 25165const exports$1 = require('../exports.js'); 25166const integration = require('../integration.js'); 25167 25168let originalFunctionToString; 25169 25170const INTEGRATION_NAME = 'FunctionToString'; 25171 25172const SETUP_CLIENTS = new WeakMap(); 25173 25174const _functionToStringIntegration = (() => { 25175 return { 25176 name: INTEGRATION_NAME, 25177 setupOnce() { 25178 // eslint-disable-next-line @typescript-eslint/unbound-method 25179 originalFunctionToString = Function.prototype.toString; 25180 25181 // intrinsics (like Function.prototype) might be immutable in some environments 25182 // e.g. Node with --frozen-intrinsics, XS (an embedded JavaScript engine) or SES (a JavaScript proposal) 25183 try { 25184 // eslint-disable-next-line @typescript-eslint/no-explicit-any 25185 Function.prototype.toString = function ( ...args) { 25186 const originalFunction = utils.getOriginalFunction(this); 25187 const context = 25188 SETUP_CLIENTS.has(exports$1.getClient() ) && originalFunction !== undefined ? originalFunction : this; 25189 return originalFunctionToString.apply(context, args); 25190 }; 25191 } catch (e) { 25192 // ignore errors here, just don't patch this 25193 } 25194 }, 25195 setup(client) { 25196 SETUP_CLIENTS.set(client, true); 25197 }, 25198 }; 25199}) ; 25200 25201/** 25202 * Patch toString calls to return proper name for wrapped functions. 25203 * 25204 * ```js 25205 * Sentry.init({ 25206 * integrations: [ 25207 * functionToStringIntegration(), 25208 * ], 25209 * }); 25210 * ``` 25211 */ 25212const functionToStringIntegration = integration.defineIntegration(_functionToStringIntegration); 25213 25214/** 25215 * Patch toString calls to return proper name for wrapped functions. 25216 * 25217 * @deprecated Use `functionToStringIntegration()` instead. 25218 */ 25219// eslint-disable-next-line deprecation/deprecation 25220const FunctionToString = integration.convertIntegrationFnToClass( 25221 INTEGRATION_NAME, 25222 functionToStringIntegration, 25223) ; 25224 25225// eslint-disable-next-line deprecation/deprecation 25226 25227exports.FunctionToString = FunctionToString; 25228exports.functionToStringIntegration = functionToStringIntegration; 25229 25230 25231},{"../exports.js":248,"../integration.js":251,"@sentry/utils":319}],253:[function(require,module,exports){ 25232Object.defineProperty(exports, '__esModule', { value: true }); 25233 25234const utils = require('@sentry/utils'); 25235const debugBuild = require('../debug-build.js'); 25236const integration = require('../integration.js'); 25237 25238// "Script error." is hard coded into browsers for errors that it can't read. 25239// this is the result of a script being pulled in from an external domain and CORS. 25240const DEFAULT_IGNORE_ERRORS = [/^Script error\.?$/, /^Javascript error: Script error\.? on line 0$/]; 25241 25242const DEFAULT_IGNORE_TRANSACTIONS = [ 25243 /^.*\/healthcheck$/, 25244 /^.*\/healthy$/, 25245 /^.*\/live$/, 25246 /^.*\/ready$/, 25247 /^.*\/heartbeat$/, 25248 /^.*\/health$/, 25249 /^.*\/healthz$/, 25250]; 25251 25252/** Options for the InboundFilters integration */ 25253 25254const INTEGRATION_NAME = 'InboundFilters'; 25255const _inboundFiltersIntegration = ((options = {}) => { 25256 return { 25257 name: INTEGRATION_NAME, 25258 // TODO v8: Remove this 25259 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 25260 processEvent(event, _hint, client) { 25261 const clientOptions = client.getOptions(); 25262 const mergedOptions = _mergeOptions(options, clientOptions); 25263 return _shouldDropEvent(event, mergedOptions) ? null : event; 25264 }, 25265 }; 25266}) ; 25267 25268const inboundFiltersIntegration = integration.defineIntegration(_inboundFiltersIntegration); 25269 25270/** 25271 * Inbound filters configurable by the user. 25272 * @deprecated Use `inboundFiltersIntegration()` instead. 25273 */ 25274// eslint-disable-next-line deprecation/deprecation 25275const InboundFilters = integration.convertIntegrationFnToClass( 25276 INTEGRATION_NAME, 25277 inboundFiltersIntegration, 25278) 25279 25280; 25281 25282function _mergeOptions( 25283 internalOptions = {},
vendor: 4,472 bytes, lines 25284-25420
25284 clientOptions = {}, 25285) { 25286 return { 25287 allowUrls: [...(internalOptions.allowUrls || []), ...(clientOptions.allowUrls || [])], 25288 denyUrls: [...(internalOptions.denyUrls || []), ...(clientOptions.denyUrls || [])], 25289 ignoreErrors: [ 25290 ...(internalOptions.ignoreErrors || []), 25291 ...(clientOptions.ignoreErrors || []), 25292 ...(internalOptions.disableErrorDefaults ? [] : DEFAULT_IGNORE_ERRORS), 25293 ], 25294 ignoreTransactions: [ 25295 ...(internalOptions.ignoreTransactions || []), 25296 ...(clientOptions.ignoreTransactions || []), 25297 ...(internalOptions.disableTransactionDefaults ? [] : DEFAULT_IGNORE_TRANSACTIONS), 25298 ], 25299 ignoreInternal: internalOptions.ignoreInternal !== undefined ? internalOptions.ignoreInternal : true, 25300 }; 25301} 25302 25303function _shouldDropEvent(event, options) { 25304 if (options.ignoreInternal && _isSentryError(event)) { 25305 debugBuild.DEBUG_BUILD && 25306 utils.logger.warn(`Event dropped due to being internal Sentry Error.\nEvent: ${utils.getEventDescription(event)}`); 25307 return true; 25308 } 25309 if (_isIgnoredError(event, options.ignoreErrors)) { 25310 debugBuild.DEBUG_BUILD && 25311 utils.logger.warn( 25312 `Event dropped due to being matched by \`ignoreErrors\` option.\nEvent: ${utils.getEventDescription(event)}`, 25313 ); 25314 return true; 25315 } 25316 if (_isIgnoredTransaction(event, options.ignoreTransactions)) { 25317 debugBuild.DEBUG_BUILD && 25318 utils.logger.warn( 25319 `Event dropped due to being matched by \`ignoreTransactions\` option.\nEvent: ${utils.getEventDescription(event)}`, 25320 ); 25321 return true; 25322 } 25323 if (_isDeniedUrl(event, options.denyUrls)) { 25324 debugBuild.DEBUG_BUILD && 25325 utils.logger.warn( 25326 `Event dropped due to being matched by \`denyUrls\` option.\nEvent: ${utils.getEventDescription( 25327 event, 25328 )}.\nUrl: ${_getEventFilterUrl(event)}`, 25329 ); 25330 return true; 25331 } 25332 if (!_isAllowedUrl(event, options.allowUrls)) { 25333 debugBuild.DEBUG_BUILD && 25334 utils.logger.warn( 25335 `Event dropped due to not being matched by \`allowUrls\` option.\nEvent: ${utils.getEventDescription( 25336 event, 25337 )}.\nUrl: ${_getEventFilterUrl(event)}`, 25338 ); 25339 return true; 25340 } 25341 return false; 25342} 25343 25344function _isIgnoredError(event, ignoreErrors) { 25345 // If event.type, this is not an error 25346 if (event.type || !ignoreErrors || !ignoreErrors.length) { 25347 return false; 25348 } 25349 25350 return _getPossibleEventMessages(event).some(message => utils.stringMatchesSomePattern(message, ignoreErrors)); 25351} 25352 25353function _isIgnoredTransaction(event, ignoreTransactions) { 25354 if (event.type !== 'transaction' || !ignoreTransactions || !ignoreTransactions.length) { 25355 return false; 25356 } 25357 25358 const name = event.transaction; 25359 return name ? utils.stringMatchesSomePattern(name, ignoreTransactions) : false; 25360} 25361 25362function _isDeniedUrl(event, denyUrls) { 25363 // TODO: Use Glob instead? 25364 if (!denyUrls || !denyUrls.length) { 25365 return false; 25366 } 25367 const url = _getEventFilterUrl(event); 25368 return !url ? false : utils.stringMatchesSomePattern(url, denyUrls); 25369} 25370 25371function _isAllowedUrl(event, allowUrls) { 25372 // TODO: Use Glob instead? 25373 if (!allowUrls || !allowUrls.length) { 25374 return true; 25375 } 25376 const url = _getEventFilterUrl(event); 25377 return !url ? true : utils.stringMatchesSomePattern(url, allowUrls); 25378} 25379 25380function _getPossibleEventMessages(event) { 25381 const possibleMessages = []; 25382 25383 if (event.message) { 25384 possibleMessages.push(event.message); 25385 } 25386 25387 let lastException; 25388 try { 25389 // @ts-expect-error Try catching to save bundle size 25390 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 25391 lastException = event.exception.values[event.exception.values.length - 1]; 25392 } catch (e) { 25393 // try catching to save bundle size checking existence of variables 25394 } 25395 25396 if (lastException) { 25397 if (lastException.value) { 25398 possibleMessages.push(lastException.value); 25399 if (lastException.type) { 25400 possibleMessages.push(`${lastException.type}: ${lastException.value}`); 25401 } 25402 } 25403 } 25404 25405 if (debugBuild.DEBUG_BUILD && possibleMessages.length === 0) { 25406 utils.logger.error(`Could not extract message for event ${utils.getEventDescription(event)}`); 25407 } 25408 25409 return possibleMessages; 25410} 25411 25412function _isSentryError(event) { 25413 try { 25414 // @ts-expect-error can't be a sentry error if undefined 25415 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 25416 return event.exception.values[0].type === 'SentryError'; 25417 } catch (e) { 25418 // ignore 25419 } 25420 return false;
25421} 25422 25423function _getLastValidUrl(frames = []) { 25424 for (let i = frames.length - 1; i >= 0; i--) { 25425 const frame = frames[i]; 25426 25427 if (frame && frame.filename !== '<anonymous>' && frame.filename !== '[native code]') { 25428 return frame.filename || null; 25429 } 25430 } 25431 25432 return null; 25433} 25434 25435function _getEventFilterUrl(event) { 25436 try { 25437 let frames; 25438 try { 25439 // @ts-expect-error we only care about frames if the whole thing here is defined 25440 frames = event.exception.values[0].stacktrace.frames; 25441 } catch (e) { 25442 // ignore 25443 } 25444 return frames ? _getLastValidUrl(frames) : null; 25445 } catch (oO) { 25446 debugBuild.DEBUG_BUILD && utils.logger.error(`Cannot extract url for event ${utils.getEventDescription(event)}`); 25447 return null; 25448 } 25449} 25450 25451exports.InboundFilters = InboundFilters; 25452exports.inboundFiltersIntegration = inboundFiltersIntegration; 25453 25454 25455},{"../debug-build.js":245,"../integration.js":251,"@sentry/utils":319}],254:[function(require,module,exports){ 25456Object.defineProperty(exports, '__esModule', { value: true }); 25457 25458const functiontostring = require('./functiontostring.js'); 25459const inboundfilters = require('./inboundfilters.js'); 25460const linkederrors = require('./linkederrors.js'); 25461 25462/* eslint-disable deprecation/deprecation */ 25463 25464exports.FunctionToString = functiontostring.FunctionToString; 25465exports.InboundFilters = inboundfilters.InboundFilters; 25466exports.LinkedErrors = linkederrors.LinkedErrors; 25467 25468 25469},{"./functiontostring.js":252,"./inboundfilters.js":253,"./linkederrors.js":255}],255:[function(require,module,exports){ 25470Object.defineProperty(exports, '__esModule', { value: true }); 25471 25472const utils = require('@sentry/utils'); 25473const integration = require('../integration.js'); 25474 25475const DEFAULT_KEY = 'cause'; 25476const DEFAULT_LIMIT = 5; 25477 25478const INTEGRATION_NAME = 'LinkedErrors'; 25479 25480const _linkedErrorsIntegration = ((options = {}) => { 25481 const limit = options.limit || DEFAULT_LIMIT; 25482 const key = options.key || DEFAULT_KEY; 25483 25484 return { 25485 name: INTEGRATION_NAME, 25486 // TODO v8: Remove this 25487 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 25488 preprocessEvent(event, hint, client) { 25489 const options = client.getOptions(); 25490 25491 utils.applyAggregateErrorsToEvent( 25492 utils.exceptionFromError, 25493 options.stackParser, 25494 options.maxValueLength, 25495 key, 25496 limit, 25497 event, 25498 hint, 25499 ); 25500 }, 25501 }; 25502}) ; 25503 25504const linkedErrorsIntegration = integration.defineIntegration(_linkedErrorsIntegration); 25505 25506/** 25507 * Adds SDK info to an event. 25508 * @deprecated Use `linkedErrorsIntegration()` instead. 25509 */ 25510// eslint-disable-next-line deprecation/deprecation 25511const LinkedErrors = integration.convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration) 25512 25513; 25514 25515exports.LinkedErrors = LinkedErrors; 25516exports.linkedErrorsIntegration = linkedErrorsIntegration; 25517 25518 25519},{"../integration.js":251,"@sentry/utils":319}],256:[function(require,module,exports){ 25520Object.defineProperty(exports, '__esModule', { value: true }); 25521 25522const utils = require('@sentry/utils'); 25523const integration = require('../integration.js'); 25524const metadata = require('../metadata.js'); 25525 25526const INTEGRATION_NAME = 'ModuleMetadata'; 25527 25528const _moduleMetadataIntegration = (() => { 25529 return { 25530 name: INTEGRATION_NAME, 25531 // TODO v8: Remove this 25532 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 25533 setup(client) { 25534 if (typeof client.on !== 'function') { 25535 return; 25536 } 25537 25538 // We need to strip metadata from stack frames before sending them to Sentry since these are client side only. 25539 client.on('beforeEnvelope', envelope => { 25540 utils.forEachEnvelopeItem(envelope, (item, type) => { 25541 if (type === 'event') { 25542 const event = Array.isArray(item) ? (item )[1] : undefined; 25543 25544 if (event) { 25545 metadata.stripMetadataFromStackFrames(event); 25546 item[1] = event; 25547 } 25548 } 25549 }); 25550 }); 25551 }, 25552 25553 processEvent(event, _hint, client) { 25554 const stackParser = client.getOptions().stackParser; 25555 metadata.addMetadataToStackFrames(stackParser, event); 25556 return event; 25557 }, 25558 }; 25559}) ; 25560 25561const moduleMetadataIntegration = integration.defineIntegration(_moduleMetadataIntegration); 25562 25563/** 25564 * Adds module metadata to stack frames. 25565 * 25566 * Metadata can be injected by the Sentry bundler plugins using the `_experiments.moduleMetadata` config option. 25567 * 25568 * When this integration is added, the metadata passed to the bundler plugin is added to the stack frames of all events 25569 * under the `module_metadata` property. This can be used to help in tagging or routing of events from different teams 25570 * our sources 25571 * 25572 * @deprecated Use `moduleMetadataIntegration()` instead. 25573 */ 25574// eslint-disable-next-line deprecation/deprecation 25575const ModuleMetadata = integration.convertIntegrationFnToClass( 25576 INTEGRATION_NAME, 25577 moduleMetadataIntegration, 25578) 25579 25580; 25581 25582exports.ModuleMetadata = ModuleMetadata; 25583exports.moduleMetadataIntegration = moduleMetadataIntegration; 25584 25585 25586},{"../integration.js":251,"../metadata.js":258,"@sentry/utils":319}],257:[function(require,module,exports){ 25587Object.defineProperty(exports, '__esModule', { value: true }); 25588 25589const utils = require('@sentry/utils'); 25590const integration = require('../integration.js'); 25591const spanUtils = require('../utils/spanUtils.js'); 25592 25593const DEFAULT_OPTIONS = { 25594 include: { 25595 cookies: true, 25596 data: true, 25597 headers: true, 25598 ip: false, 25599 query_string: true, 25600 url: true, 25601 user: { 25602 id: true, 25603 username: true, 25604 email: true, 25605 }, 25606 }, 25607 transactionNamingScheme: 'methodPath', 25608}; 25609 25610const INTEGRATION_NAME = 'RequestData'; 25611 25612const _requestDataIntegration = ((options = {}) => { 25613 const _addRequestData = utils.addRequestDataToEvent; 25614 const _options = { 25615 ...DEFAULT_OPTIONS, 25616 ...options, 25617 include: { 25618 // @ts-expect-error It's mad because `method` isn't a known `include` key. (It's only here and not set by default in 25619 // `addRequestDataToEvent` for legacy reasons. TODO (v8): Change that.) 25620 method: true, 25621 ...DEFAULT_OPTIONS.include, 25622 ...options.include, 25623 user: 25624 options.include && typeof options.include.user === 'boolean' 25625 ? options.include.user 25626 : { 25627 ...DEFAULT_OPTIONS.include.user, 25628 // Unclear why TS still thinks `options.include.user` could be a boolean at this point 25629 ...((options.include || {}).user ), 25630 }, 25631 }, 25632 }; 25633 25634 return { 25635 name: INTEGRATION_NAME, 25636 // TODO v8: Remove this 25637 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 25638 processEvent(event, _hint, client) { 25639 // Note: In the long run, most of the logic here should probably move into the request data utility functions. For 25640 // the moment it lives here, though, until https://github.com/getsentry/sentry-javascript/issues/5718 is addressed. 25641 // (TL;DR: Those functions touch many parts of the repo in many different ways, and need to be clened up. Once 25642 // that's happened, it will be easier to add this logic in without worrying about unexpected side effects.) 25643 const { transactionNamingScheme } = _options; 25644 25645 const { sdkProcessingMetadata = {} } = event; 25646 const req = sdkProcessingMetadata.request; 25647 25648 if (!req) { 25649 return event; 25650 } 25651 25652 // The Express request handler takes a similar `include` option to that which can be passed to this integration. 25653 // If passed there, we store it in `sdkProcessingMetadata`. TODO(v8): Force express and GCP people to use this 25654 // integration, so that all of this passing and conversion isn't necessary 25655 const addRequestDataOptions = 25656 sdkProcessingMetadata.requestDataOptionsFromExpressHandler || 25657 sdkProcessingMetadata.requestDataOptionsFromGCPWrapper || 25658 convertReqDataIntegrationOptsToAddReqDataOpts(_options); 25659 25660 const processedEvent = _addRequestData(event, req, addRequestDataOptions); 25661 25662 // Transaction events already have the right `transaction` value 25663 if (event.type === 'transaction' || transactionNamingScheme === 'handler') { 25664 return processedEvent; 25665 } 25666 25667 // In all other cases, use the request's associated transaction (if any) to overwrite the event's `transaction` 25668 // value with a high-quality one 25669 const reqWithTransaction = req ; 25670 const transaction = reqWithTransaction._sentryTransaction; 25671 if (transaction) { 25672 const name = spanUtils.spanToJSON(transaction).description || ''; 25673 25674 // TODO (v8): Remove the nextjs check and just base it on `transactionNamingScheme` for all SDKs. (We have to 25675 // keep it the way it is for the moment, because changing the names of transactions in Sentry has the potential 25676 // to break things like alert rules.) 25677 const shouldIncludeMethodInTransactionName = 25678 getSDKName(client) === 'sentry.javascript.nextjs' 25679 ? name.startsWith('/api') 25680 : transactionNamingScheme !== 'path'; 25681 25682 const [transactionValue] = utils.extractPathForTransaction(req, { 25683 path: true, 25684 method: shouldIncludeMethodInTransactionName, 25685 customRoute: name, 25686 }); 25687 25688 processedEvent.transaction = transactionValue; 25689 } 25690 25691 return processedEvent; 25692 }, 25693 }; 25694}) ; 25695 25696const requestDataIntegration = integration.defineIntegration(_requestDataIntegration); 25697 25698/** 25699 * Add data about a request to an event. Primarily for use in Node-based SDKs, but included in `@sentry/integrations` 25700 * so it can be used in cross-platform SDKs like `@sentry/nextjs`. 25701 * @deprecated Use `requestDataIntegration()` instead. 25702 */ 25703// eslint-disable-next-line deprecation/deprecation 25704const RequestData = integration.convertIntegrationFnToClass(INTEGRATION_NAME, requestDataIntegration) 25705 25706; 25707 25708/** Convert this integration's options to match what `addRequestDataToEvent` expects */ 25709/** TODO: Can possibly be deleted once https://github.com/getsentry/sentry-javascript/issues/5718 is fixed */ 25710function convertReqDataIntegrationOptsToAddReqDataOpts( 25711 integrationOptions, 25712) { 25713 const { 25714 transactionNamingScheme, 25715 include: { ip, user, ...requestOptions }, 25716 } = integrationOptions; 25717 25718 const requestIncludeKeys = []; 25719 for (const [key, value] of Object.entries(requestOptions)) { 25720 if (value) { 25721 requestIncludeKeys.push(key); 25722 } 25723 } 25724 25725 let addReqDataUserOpt; 25726 if (user === undefined) { 25727 addReqDataUserOpt = true; 25728 } else if (typeof user === 'boolean') { 25729 addReqDataUserOpt = user; 25730 } else { 25731 const userIncludeKeys = []; 25732 for (const [key, value] of Object.entries(user)) { 25733 if (value) { 25734 userIncludeKeys.push(key); 25735 } 25736 } 25737 addReqDataUserOpt = userIncludeKeys; 25738 } 25739 25740 return { 25741 include: { 25742 ip, 25743 user: addReqDataUserOpt, 25744 request: requestIncludeKeys.length !== 0 ? requestIncludeKeys : undefined, 25745 transaction: transactionNamingScheme, 25746 }, 25747 }; 25748} 25749 25750function getSDKName(client) { 25751 try { 25752 // For a long chain like this, it's fewer bytes to combine a try-catch with assuming everything is there than to 25753 // write out a long chain of `a && a.b && a.b.c && ...` 25754 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 25755 return client.getOptions()._metadata.sdk.name; 25756 } catch (err) { 25757 // In theory we should never get here
25758 return undefined; 25759 } 25760} 25761 25762exports.RequestData = RequestData; 25763exports.requestDataIntegration = requestDataIntegration; 25764 25765 25766},{"../integration.js":251,"../utils/spanUtils.js":297,"@sentry/utils":319}],258:[function(require,module,exports){ 25767Object.defineProperty(exports, '__esModule', { value: true }); 25768 25769const utils = require('@sentry/utils'); 25770 25771/** Keys are source filename/url, values are metadata objects. */ 25772// eslint-disable-next-line @typescript-eslint/no-explicit-any 25773const filenameMetadataMap = new Map(); 25774/** Set of stack strings that have already been parsed. */ 25775const parsedStacks = new Set(); 25776 25777function ensureMetadataStacksAreParsed(parser) { 25778 if (!utils.GLOBAL_OBJ._sentryModuleMetadata) { 25779 return; 25780 } 25781 25782 for (const stack of Object.keys(utils.GLOBAL_OBJ._sentryModuleMetadata)) { 25783 const metadata = utils.GLOBAL_OBJ._sentryModuleMetadata[stack]; 25784 25785 if (parsedStacks.has(stack)) { 25786 continue; 25787 } 25788 25789 // Ensure this stack doesn't get parsed again 25790 parsedStacks.add(stack); 25791 25792 const frames = parser(stack); 25793 25794 // Go through the frames starting from the top of the stack and find the first one with a filename 25795 for (const frame of frames.reverse()) { 25796 if (frame.filename) { 25797 // Save the metadata for this filename 25798 filenameMetadataMap.set(frame.filename, metadata); 25799 break; 25800 } 25801 } 25802 } 25803} 25804 25805/** 25806 * Retrieve metadata for a specific JavaScript file URL. 25807 * 25808 * Metadata is injected by the Sentry bundler plugins using the `_experiments.moduleMetadata` config option. 25809 */ 25810// eslint-disable-next-line @typescript-eslint/no-explicit-any 25811function getMetadataForUrl(parser, filename) { 25812 ensureMetadataStacksAreParsed(parser); 25813 return filenameMetadataMap.get(filename); 25814} 25815 25816/** 25817 * Adds metadata to stack frames. 25818 * 25819 * Metadata is injected by the Sentry bundler plugins using the `_experiments.moduleMetadata` config option. 25820 */ 25821function addMetadataToStackFrames(parser, event) { 25822 try { 25823 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 25824 event.exception.values.forEach(exception => { 25825 if (!exception.stacktrace) { 25826 return; 25827 } 25828 25829 for (const frame of exception.stacktrace.frames || []) { 25830 if (!frame.filename) { 25831 continue; 25832 } 25833 25834 const metadata = getMetadataForUrl(parser, frame.filename); 25835 25836 if (metadata) { 25837 frame.module_metadata = metadata; 25838 } 25839 } 25840 }); 25841 } catch (_) { 25842 // To save bundle size we're just try catching here instead of checking for the existence of all the different objects. 25843 } 25844} 25845 25846/** 25847 * Strips metadata from stack frames. 25848 */ 25849function stripMetadataFromStackFrames(event) { 25850 try { 25851 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 25852 event.exception.values.forEach(exception => { 25853 if (!exception.stacktrace) { 25854 return; 25855 } 25856 25857 for (const frame of exception.stacktrace.frames || []) { 25858 delete frame.module_metadata; 25859 } 25860 }); 25861 } catch (_) { 25862 // To save bundle size we're just try catching here instead of checking for the existence of all the different objects. 25863 } 25864} 25865 25866exports.addMetadataToStackFrames = addMetadataToStackFrames; 25867exports.getMetadataForUrl = getMetadataForUrl; 25868exports.stripMetadataFromStackFrames = stripMetadataFromStackFrames; 25869 25870 25871},{"@sentry/utils":319}],259:[function(require,module,exports){ 25872Object.defineProperty(exports, '__esModule', { value: true }); 25873 25874const utils$1 = require('@sentry/utils'); 25875const constants = require('./constants.js'); 25876const instance = require('./instance.js'); 25877const metricSummary = require('./metric-summary.js'); 25878const utils = require('./utils.js'); 25879 25880/** 25881 * A metrics aggregator that aggregates metrics in memory and flushes them periodically. 25882 */ 25883class MetricsAggregator { 25884 // TODO(@anonrig): Use FinalizationRegistry to have a proper way of flushing the buckets 25885 // when the aggregator is garbage collected. 25886 // Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry 25887 25888 // Different metrics have different weights. We use this to limit the number of metrics 25889 // that we store in memory. 25890 25891 // SDKs are required to shift the flush interval by random() * rollup_in_seconds. 25892 // That shift is determined once per startup to create jittering. 25893 25894 // An SDK is required to perform force flushing ahead of scheduled time if the memory 25895 // pressure is too high. There is no rule for this other than that SDKs should be tracking 25896 // abstract aggregation complexity (eg: a counter only carries a single float, whereas a 25897 // distribution is a float per emission). 25898 // 25899 // Force flush is used on either shutdown, flush() or when we exceed the max weight. 25900 25901 constructor( _client) {this._client = _client; 25902 this._buckets = new Map(); 25903 this._bucketsTotalWeight = 0; 25904 this._interval = setInterval(() => this._flush(), constants.DEFAULT_FLUSH_INTERVAL); 25905 this._flushShift = Math.floor((Math.random() * constants.DEFAULT_FLUSH_INTERVAL) / 1000); 25906 this._forceFlush = false;
25907 } 25908 25909 /** 25910 * @inheritDoc 25911 */ 25912 add( 25913 metricType, 25914 unsanitizedName, 25915 value, 25916 unit = 'none', 25917 unsanitizedTags = {}, 25918 maybeFloatTimestamp = utils$1.timestampInSeconds(), 25919 ) { 25920 const timestamp = Math.floor(maybeFloatTimestamp); 25921 const name = unsanitizedName.replace(constants.NAME_AND_TAG_KEY_NORMALIZATION_REGEX, '_'); 25922 const tags = utils.sanitizeTags(unsanitizedTags); 25923 25924 const bucketKey = utils.getBucketKey(metricType, name, unit, tags); 25925 25926 let bucketItem = this._buckets.get(bucketKey); 25927 // If this is a set metric, we need to calculate the delta from the previous weight. 25928 const previousWeight = bucketItem && metricType === constants.SET_METRIC_TYPE ? bucketItem.metric.weight : 0; 25929 25930 if (bucketItem) { 25931 bucketItem.metric.add(value); 25932 // TODO(abhi): Do we need this check? 25933 if (bucketItem.timestamp < timestamp) { 25934 bucketItem.timestamp = timestamp; 25935 } 25936 } else { 25937 bucketItem = { 25938 // @ts-expect-error we don't need to narrow down the type of value here, saves bundle size. 25939 metric: new instance.METRIC_MAP[metricType](value), 25940 timestamp, 25941 metricType, 25942 name, 25943 unit, 25944 tags, 25945 }; 25946 this._buckets.set(bucketKey, bucketItem); 25947 } 25948 25949 // If value is a string, it's a set metric so calculate the delta from the previous weight. 25950 const val = typeof value === 'string' ? bucketItem.metric.weight - previousWeight : value; 25951 metricSummary.updateMetricSummaryOnActiveSpan(metricType, name, val, unit, unsanitizedTags, bucketKey); 25952 25953 // We need to keep track of the total weight of the buckets so that we can 25954 // flush them when we exceed the max weight. 25955 this._bucketsTotalWeight += bucketItem.metric.weight; 25956 25957 if (this._bucketsTotalWeight >= constants.MAX_WEIGHT) { 25958 this.flush(); 25959 } 25960 } 25961 25962 /** 25963 * Flushes the current metrics to the transport via the transport. 25964 */ 25965 flush() { 25966 this._forceFlush = true; 25967 this._flush(); 25968 } 25969 25970 /** 25971 * Shuts down metrics aggregator and clears all metrics. 25972 */ 25973 close() { 25974 this._forceFlush = true; 25975 clearInterval(this._interval); 25976 this._flush(); 25977 } 25978 25979 /** 25980 * Flushes the buckets according to the internal state of the aggregator. 25981 * If it is a force flush, which happens on shutdown, it will flush all buckets. 25982 * Otherwise, it will only flush buckets that are older than the flush interval, 25983 * and according to the flush shift. 25984 * 25985 * This function mutates `_forceFlush` and `_bucketsTotalWeight` properties. 25986 */ 25987 _flush() { 25988 // TODO(@anonrig): Add Atomics for locking to avoid having force flush and regular flush 25989 // running at the same time. 25990 // Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics 25991 25992 // This path eliminates the need for checking for timestamps since we're forcing a flush. 25993 // Remember to reset the flag, or it will always flush all metrics. 25994 if (this._forceFlush) { 25995 this._forceFlush = false; 25996 this._bucketsTotalWeight = 0; 25997 this._captureMetrics(this._buckets); 25998 this._buckets.clear(); 25999 return; 26000 } 26001 const cutoffSeconds = Math.floor(utils$1.timestampInSeconds()) - constants.DEFAULT_FLUSH_INTERVAL / 1000 - this._flushShift; 26002 // TODO(@anonrig): Optimization opportunity. 26003 // Convert this map to an array and store key in the bucketItem. 26004 const flushedBuckets = new Map(); 26005 for (const [key, bucket] of this._buckets) { 26006 if (bucket.timestamp <= cutoffSeconds) { 26007 flushedBuckets.set(key, bucket); 26008 this._bucketsTotalWeight -= bucket.metric.weight; 26009 } 26010 } 26011 26012 for (const [key] of flushedBuckets) { 26013 this._buckets.delete(key); 26014 } 26015 26016 this._captureMetrics(flushedBuckets); 26017 } 26018 26019 /** 26020 * Only captures a subset of the buckets passed to this function. 26021 * @param flushedBuckets 26022 */ 26023 _captureMetrics(flushedBuckets) { 26024 if (flushedBuckets.size > 0 && this._client.captureAggregateMetrics) { 26025 // TODO(@anonrig): Optimization opportunity. 26026 // This copy operation can be avoided if we store the key in the bucketItem. 26027 const buckets = Array.from(flushedBuckets).map(([, bucketItem]) => bucketItem); 26028 this._client.captureAggregateMetrics(buckets); 26029 } 26030 } 26031} 26032 26033exports.MetricsAggregator = MetricsAggregator; 26034 26035 26036},{"./constants.js":261,"./instance.js":264,"./metric-summary.js":266,"./utils.js":267,"@sentry/utils":319}],260:[function(require,module,exports){ 26037Object.defineProperty(exports, '__esModule', { value: true }); 26038 26039const utils$1 = require('@sentry/utils'); 26040const constants = require('./constants.js'); 26041const instance = require('./instance.js'); 26042const metricSummary = require('./metric-summary.js'); 26043const utils = require('./utils.js'); 26044 26045/** 26046 * A simple metrics aggregator that aggregates metrics in memory and flushes them periodically. 26047 * Default flush interval is 5 seconds. 26048 * 26049 * @experimental This API is experimental and might change in the future. 26050 */ 26051class BrowserMetricsAggregator { 26052 // TODO(@anonrig): Use FinalizationRegistry to have a proper way of flushing the buckets 26053 // when the aggregator is garbage collected. 26054 // Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry 26055 26056 constructor( _client) {this._client = _client; 26057 this._buckets = new Map(); 26058 this._interval = setInterval(() => this.flush(), constants.DEFAULT_BROWSER_FLUSH_INTERVAL); 26059 } 26060 26061 /** 26062 * @inheritDoc 26063 */ 26064 add( 26065 metricType, 26066 unsanitizedName, 26067 value, 26068 unit = 'none', 26069 unsanitizedTags = {}, 26070 maybeFloatTimestamp = utils$1.timestampInSeconds(), 26071 ) { 26072 const timestamp = Math.floor(maybeFloatTimestamp); 26073 const name = unsanitizedName.replace(constants.NAME_AND_TAG_KEY_NORMALIZATION_REGEX, '_'); 26074 const tags = utils.sanitizeTags(unsanitizedTags); 26075 26076 const bucketKey = utils.getBucketKey(metricType, name, unit, tags); 26077 26078 let bucketItem = this._buckets.get(bucketKey); 26079 // If this is a set metric, we need to calculate the delta from the previous weight. 26080 const previousWeight = bucketItem && metricType === constants.SET_METRIC_TYPE ? bucketItem.metric.weight : 0; 26081 26082 if (bucketItem) { 26083 bucketItem.metric.add(value); 26084 // TODO(abhi): Do we need this check? 26085 if (bucketItem.timestamp < timestamp) { 26086 bucketItem.timestamp = timestamp; 26087 } 26088 } else { 26089 bucketItem = { 26090 // @ts-expect-error we don't need to narrow down the type of value here, saves bundle size. 26091 metric: new instance.METRIC_MAP[metricType](value),
26092 timestamp, 26093 metricType, 26094 name, 26095 unit, 26096 tags, 26097 }; 26098 this._buckets.set(bucketKey, bucketItem); 26099 } 26100 26101 // If value is a string, it's a set metric so calculate the delta from the previous weight. 26102 const val = typeof value === 'string' ? bucketItem.metric.weight - previousWeight : value; 26103 metricSummary.updateMetricSummaryOnActiveSpan(metricType, name, val, unit, unsanitizedTags, bucketKey); 26104 } 26105 26106 /** 26107 * @inheritDoc 26108 */ 26109 flush() { 26110 // short circuit if buckets are empty. 26111 if (this._buckets.size === 0) { 26112 return; 26113 } 26114 if (this._client.captureAggregateMetrics) { 26115 // TODO(@anonrig): Use Object.values() when we support ES6+ 26116 const metricBuckets = Array.from(this._buckets).map(([, bucketItem]) => bucketItem); 26117 this._client.captureAggregateMetrics(metricBuckets); 26118 } 26119 this._buckets.clear(); 26120 } 26121 26122 /** 26123 * @inheritDoc 26124 */ 26125 close() { 26126 clearInterval(this._interval); 26127 this.flush(); 26128 } 26129} 26130 26131exports.BrowserMetricsAggregator = BrowserMetricsAggregator; 26132 26133 26134},{"./constants.js":261,"./instance.js":264,"./metric-summary.js":266,"./utils.js":267,"@sentry/utils":319}],261:[function(require,module,exports){ 26135Object.defineProperty(exports, '__esModule', { value: true }); 26136 26137const COUNTER_METRIC_TYPE = 'c' ; 26138const GAUGE_METRIC_TYPE = 'g' ; 26139const SET_METRIC_TYPE = 's' ; 26140const DISTRIBUTION_METRIC_TYPE = 'd' ; 26141 26142/** 26143 * Normalization regex for metric names and metric tag names. 26144 * 26145 * This enforces that names and tag keys only contain alphanumeric characters, 26146 * underscores, forward slashes, periods, and dashes. 26147 * 26148 * See: https://develop.sentry.dev/sdk/metrics/#normalization 26149 */ 26150const NAME_AND_TAG_KEY_NORMALIZATION_REGEX = /[^a-zA-Z0-9_/.-]+/g; 26151 26152/** 26153 * Normalization regex for metric tag values. 26154 * 26155 * This enforces that values only contain words, digits, or the following 26156 * special characters: _:/@.{}[\]$- 26157 * 26158 * See: https://develop.sentry.dev/sdk/metrics/#normalization 26159 */ 26160const TAG_VALUE_NORMALIZATION_REGEX = /[^\w\d\s_:/@.{}[\]$-]+/g; 26161 26162/** 26163 * This does not match spec in https://develop.sentry.dev/sdk/metrics 26164 * but was chosen to optimize for the most common case in browser environments. 26165 */ 26166const DEFAULT_BROWSER_FLUSH_INTERVAL = 5000; 26167 26168/** 26169 * SDKs are required to bucket into 10 second intervals (rollup in seconds) 26170 * which is the current lower bound of metric accuracy. 26171 */ 26172const DEFAULT_FLUSH_INTERVAL = 10000; 26173 26174/** 26175 * The maximum number of metrics that should be stored in memory. 26176 */ 26177const MAX_WEIGHT = 10000; 26178 26179exports.COUNTER_METRIC_TYPE = COUNTER_METRIC_TYPE; 26180exports.DEFAULT_BROWSER_FLUSH_INTERVAL = DEFAULT_BROWSER_FLUSH_INTERVAL; 26181exports.DEFAULT_FLUSH_INTERVAL = DEFAULT_FLUSH_INTERVAL; 26182exports.DISTRIBUTION_METRIC_TYPE = DISTRIBUTION_METRIC_TYPE; 26183exports.GAUGE_METRIC_TYPE = GAUGE_METRIC_TYPE; 26184exports.MAX_WEIGHT = MAX_WEIGHT; 26185exports.NAME_AND_TAG_KEY_NORMALIZATION_REGEX = NAME_AND_TAG_KEY_NORMALIZATION_REGEX; 26186exports.SET_METRIC_TYPE = SET_METRIC_TYPE; 26187exports.TAG_VALUE_NORMALIZATION_REGEX = TAG_VALUE_NORMALIZATION_REGEX; 26188 26189 26190},{}],262:[function(require,module,exports){ 26191Object.defineProperty(exports, '__esModule', { value: true }); 26192 26193const utils = require('@sentry/utils'); 26194const utils$1 = require('./utils.js'); 26195 26196/** 26197 * Create envelope from a metric aggregate. 26198 */ 26199function createMetricEnvelope( 26200 metricBucketItems, 26201 dsn, 26202 metadata, 26203 tunnel, 26204) { 26205 const headers = { 26206 sent_at: new Date().toISOString(), 26207 }; 26208 26209 if (metadata && metadata.sdk) { 26210 headers.sdk = { 26211 name: metadata.sdk.name, 26212 version: metadata.sdk.version, 26213 }; 26214 } 26215 26216 if (!!tunnel && dsn) { 26217 headers.dsn = utils.dsnToString(dsn); 26218 } 26219 26220 const item = createMetricEnvelopeItem(metricBucketItems); 26221 return utils.createEnvelope(headers, [item]); 26222} 26223 26224function createMetricEnvelopeItem(metricBucketItems) { 26225 const payload = utils$1.serializeMetricBuckets(metricBucketItems); 26226 const metricHeaders = { 26227 type: 'statsd', 26228 length: payload.length, 26229 }; 26230 return [metricHeaders, payload]; 26231} 26232 26233exports.createMetricEnvelope = createMetricEnvelope; 26234 26235 26236},{"./utils.js":267,"@sentry/utils":319}],263:[function(require,module,exports){ 26237Object.defineProperty(exports, '__esModule', { value: true }); 26238 26239const utils = require('@sentry/utils'); 26240const debugBuild = require('../debug-build.js'); 26241const exports$1 = require('../exports.js'); 26242const spanUtils = require('../utils/spanUtils.js'); 26243const constants = require('./constants.js'); 26244const integration = require('./integration.js'); 26245 26246function addToMetricsAggregator( 26247 metricType, 26248 name, 26249 value, 26250 data = {}, 26251) { 26252 const client = exports$1.getClient(); 26253 const scope = exports$1.getCurrentScope(); 26254 if (client) { 26255 if (!client.metricsAggregator) { 26256 debugBuild.DEBUG_BUILD && 26257 utils.logger.warn('No metrics aggregator enabled. Please add the MetricsAggregator integration to use metrics APIs'); 26258 return; 26259 } 26260 const { unit, tags, timestamp } = data; 26261 const { release, environment } = client.getOptions(); 26262 // eslint-disable-next-line deprecation/deprecation 26263 const transaction = scope.getTransaction(); 26264 const metricTags = {}; 26265 if (release) { 26266 metricTags.release = release; 26267 } 26268 if (environment) { 26269 metricTags.environment = environment; 26270 } 26271 if (transaction) { 26272 metricTags.transaction = spanUtils.spanToJSON(transaction).description || ''; 26273 } 26274 26275 debugBuild.DEBUG_BUILD && utils.logger.log(`Adding value of ${value} to ${metricType} metric ${name}`); 26276 client.metricsAggregator.add(metricType, name, value, unit, { ...metricTags, ...tags }, timestamp); 26277 } 26278} 26279 26280/** 26281 * Adds a value to a counter metric 26282 * 26283 * @experimental This API is experimental and might have breaking changes in the future. 26284 */ 26285function increment(name, value = 1, data) { 26286 addToMetricsAggregator(constants.COUNTER_METRIC_TYPE, name, value, data); 26287} 26288 26289/** 26290 * Adds a value to a distribution metric 26291 * 26292 * @experimental This API is experimental and might have breaking changes in the future. 26293 */ 26294function distribution(name, value, data) { 26295 addToMetricsAggregator(constants.DISTRIBUTION_METRIC_TYPE, name, value, data); 26296} 26297 26298/** 26299 * Adds a value to a set metric. Value must be a string or integer. 26300 * 26301 * @experimental This API is experimental and might have breaking changes in the future. 26302 */ 26303function set(name, value, data) { 26304 addToMetricsAggregator(constants.SET_METRIC_TYPE, name, value, data); 26305} 26306 26307/** 26308 * Adds a value to a gauge metric 26309 * 26310 * @experimental This API is experimental and might have breaking changes in the future. 26311 */ 26312function gauge(name, value, data) { 26313 addToMetricsAggregator(constants.GAUGE_METRIC_TYPE, name, value, data); 26314} 26315 26316const metrics = { 26317 increment, 26318 distribution, 26319 set, 26320 gauge, 26321 /** @deprecated Use `metrics.metricsAggregratorIntegration()` instead. */ 26322 // eslint-disable-next-line deprecation/deprecation 26323 MetricsAggregator: integration.MetricsAggregator, 26324 metricsAggregatorIntegration: integration.metricsAggregatorIntegration, 26325}; 26326 26327exports.distribution = distribution; 26328exports.gauge = gauge; 26329exports.increment = increment; 26330exports.metrics = metrics;
26331exports.set = set; 26332 26333 26334},{"../debug-build.js":245,"../exports.js":248,"../utils/spanUtils.js":297,"./constants.js":261,"./integration.js":265,"@sentry/utils":319}],264:[function(require,module,exports){ 26335Object.defineProperty(exports, '__esModule', { value: true }); 26336 26337const constants = require('./constants.js'); 26338const utils = require('./utils.js'); 26339 26340/** 26341 * A metric instance representing a counter. 26342 */ 26343class CounterMetric { 26344 constructor( _value) {this._value = _value;} 26345 26346 /** @inheritDoc */ 26347 get weight() { 26348 return 1; 26349 } 26350 26351 /** @inheritdoc */ 26352 add(value) { 26353 this._value += value; 26354 } 26355 26356 /** @inheritdoc */ 26357 toString() { 26358 return `${this._value}`; 26359 } 26360} 26361 26362/** 26363 * A metric instance representing a gauge. 26364 */ 26365class GaugeMetric { 26366 26367 constructor(value) { 26368 this._last = value; 26369 this._min = value; 26370 this._max = value; 26371 this._sum = value; 26372 this._count = 1; 26373 } 26374 26375 /** @inheritDoc */ 26376 get weight() { 26377 return 5; 26378 } 26379 26380 /** @inheritdoc */ 26381 add(value) { 26382 this._last = value; 26383 if (value < this._min) { 26384 this._min = value; 26385 } 26386 if (value > this._max) { 26387 this._max = value; 26388 } 26389 this._sum += value; 26390 this._count++; 26391 } 26392 26393 /** @inheritdoc */ 26394 toString() { 26395 return `${this._last}:${this._min}:${this._max}:${this._sum}:${this._count}`; 26396 } 26397} 26398 26399/** 26400 * A metric instance representing a distribution. 26401 */ 26402class DistributionMetric { 26403 26404 constructor(first) { 26405 this._value = [first]; 26406 } 26407 26408 /** @inheritDoc */ 26409 get weight() { 26410 return this._value.length; 26411 } 26412 26413 /** @inheritdoc */ 26414 add(value) { 26415 this._value.push(value); 26416 } 26417 26418 /** @inheritdoc */ 26419 toString() { 26420 return this._value.join(':'); 26421 } 26422} 26423 26424/** 26425 * A metric instance representing a set. 26426 */ 26427class SetMetric { 26428 26429 constructor( first) {this.first = first; 26430 this._value = new Set([first]); 26431 } 26432 26433 /** @inheritDoc */ 26434 get weight() { 26435 return this._value.size; 26436 } 26437 26438 /** @inheritdoc */ 26439 add(value) { 26440 this._value.add(value); 26441 } 26442 26443 /** @inheritdoc */ 26444 toString() { 26445 return Array.from(this._value) 26446 .map(val => (typeof val === 'string' ? utils.simpleHash(val) : val)) 26447 .join(':'); 26448 } 26449} 26450 26451const METRIC_MAP = { 26452 [constants.COUNTER_METRIC_TYPE]: CounterMetric, 26453 [constants.GAUGE_METRIC_TYPE]: GaugeMetric, 26454 [constants.DISTRIBUTION_METRIC_TYPE]: DistributionMetric, 26455 [constants.SET_METRIC_TYPE]: SetMetric, 26456}; 26457 26458exports.CounterMetric = CounterMetric; 26459exports.DistributionMetric = DistributionMetric; 26460exports.GaugeMetric = GaugeMetric; 26461exports.METRIC_MAP = METRIC_MAP; 26462exports.SetMetric = SetMetric; 26463 26464 26465},{"./constants.js":261,"./utils.js":267}],265:[function(require,module,exports){ 26466Object.defineProperty(exports, '__esModule', { value: true }); 26467 26468const integration = require('../integration.js'); 26469const browserAggregator = require('./browser-aggregator.js'); 26470 26471const INTEGRATION_NAME = 'MetricsAggregator'; 26472 26473const _metricsAggregatorIntegration = (() => { 26474 return { 26475 name: INTEGRATION_NAME, 26476 // TODO v8: Remove this 26477 setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function 26478 setup(client) { 26479 client.metricsAggregator = new browserAggregator.BrowserMetricsAggregator(client); 26480 }, 26481 }; 26482}) ; 26483 26484const metricsAggregatorIntegration = integration.defineIntegration(_metricsAggregatorIntegration); 26485 26486/** 26487 * Enables Sentry metrics monitoring. 26488 * 26489 * @experimental This API is experimental and might having breaking changes in the future. 26490 * @deprecated Use `metricsAggegratorIntegration()` instead. 26491 */ 26492// eslint-disable-next-line deprecation/deprecation 26493const MetricsAggregator = integration.convertIntegrationFnToClass( 26494 INTEGRATION_NAME, 26495 metricsAggregatorIntegration, 26496) ; 26497 26498exports.MetricsAggregator = MetricsAggregator; 26499exports.metricsAggregatorIntegration = metricsAggregatorIntegration; 26500 26501 26502},{"../integration.js":251,"./browser-aggregator.js":260}],266:[function(require,module,exports){ 26503Object.defineProperty(exports, '__esModule', { value: true }); 26504 26505const utils = require('@sentry/utils'); 26506require('../debug-build.js'); 26507require('../tracing/errors.js'); 26508require('../tracing/spanstatus.js'); 26509const trace = require('../tracing/trace.js'); 26510 26511/** 26512 * key: bucketKey 26513 * value: [exportKey, MetricSummary] 26514 */ 26515 26516let SPAN_METRIC_SUMMARY; 26517 26518function getMetricStorageForSpan(span) { 26519 return SPAN_METRIC_SUMMARY ? SPAN_METRIC_SUMMARY.get(span) : undefined; 26520} 26521 26522/** 26523 * Fetches the metric summary if it exists for the passed span 26524 */ 26525function getMetricSummaryJsonForSpan(span) { 26526 const storage = getMetricStorageForSpan(span); 26527 26528 if (!storage) { 26529 return undefined; 26530 } 26531 const output = {}; 26532 26533 for (const [, [exportKey, summary]] of storage) { 26534 if (!output[exportKey]) { 26535 output[exportKey] = []; 26536 } 26537 26538 output[exportKey].push(utils.dropUndefinedKeys(summary)); 26539 } 26540 26541 return output; 26542} 26543 26544/** 26545 * Updates the metric summary on the currently active span 26546 */ 26547function updateMetricSummaryOnActiveSpan( 26548 metricType, 26549 sanitizedName, 26550 value, 26551 unit, 26552 tags, 26553 bucketKey, 26554) { 26555 const span = trace.getActiveSpan();
26556 if (span) { 26557 const storage = getMetricStorageForSpan(span) || new Map(); 26558 26559 const exportKey = `${metricType}:${sanitizedName}@${unit}`; 26560 const bucketItem = storage.get(bucketKey); 26561 26562 if (bucketItem) { 26563 const [, summary] = bucketItem; 26564 storage.set(bucketKey, [ 26565 exportKey, 26566 { 26567 min: Math.min(summary.min, value), 26568 max: Math.max(summary.max, value), 26569 count: (summary.count += 1), 26570 sum: (summary.sum += value), 26571 tags: summary.tags, 26572 }, 26573 ]); 26574 } else { 26575 storage.set(bucketKey, [ 26576 exportKey, 26577 { 26578 min: value, 26579 max: value, 26580 count: 1, 26581 sum: value, 26582 tags, 26583 }, 26584 ]); 26585 } 26586 26587 if (!SPAN_METRIC_SUMMARY) { 26588 SPAN_METRIC_SUMMARY = new WeakMap(); 26589 } 26590 26591 SPAN_METRIC_SUMMARY.set(span, storage); 26592 } 26593} 26594 26595exports.getMetricSummaryJsonForSpan = getMetricSummaryJsonForSpan; 26596exports.updateMetricSummaryOnActiveSpan = updateMetricSummaryOnActiveSpan; 26597 26598 26599},{"../debug-build.js":245,"../tracing/errors.js":276,"../tracing/spanstatus.js":282,"../tracing/trace.js":283,"@sentry/utils":319}],267:[function(require,module,exports){ 26600Object.defineProperty(exports, '__esModule', { value: true }); 26601 26602const utils = require('@sentry/utils'); 26603const constants = require('./constants.js'); 26604 26605/** 26606 * Generate bucket key from metric properties. 26607 */ 26608function getBucketKey( 26609 metricType, 26610 name, 26611 unit, 26612 tags, 26613) { 26614 const stringifiedTags = Object.entries(utils.dropUndefinedKeys(tags)).sort((a, b) => a[0].localeCompare(b[0])); 26615 return `${metricType}${name}${unit}${stringifiedTags}`; 26616} 26617 26618/* eslint-disable no-bitwise */ 26619/** 26620 * Simple hash function for strings. 26621 */ 26622function simpleHash(s) { 26623 let rv = 0; 26624 for (let i = 0; i < s.length; i++) { 26625 const c = s.charCodeAt(i); 26626 rv = (rv << 5) - rv + c; 26627 rv &= rv; 26628 } 26629 return rv >>> 0; 26630} 26631/* eslint-enable no-bitwise */ 26632 26633/** 26634 * Serialize metrics buckets into a string based on statsd format. 26635 * 26636 * Example of format: 26637 * metric.name@second:1:1.2|d|#a:value,b:anothervalue|T12345677 26638 * Segments: 26639 * name: metric.name 26640 * unit: second 26641 * value: [1, 1.2] 26642 * type of metric: d (distribution) 26643 * tags: { a: value, b: anothervalue } 26644 * timestamp: 12345677 26645 */ 26646function serializeMetricBuckets(metricBucketItems) { 26647 let out = ''; 26648 for (const item of metricBucketItems) { 26649 const tagEntries = Object.entries(item.tags); 26650 const maybeTags = tagEntries.length > 0 ? `|#${tagEntries.map(([key, value]) => `${key}:${value}`).join(',')}` : ''; 26651 out += `${item.name}@${item.unit}:${item.metric}|${item.metricType}${maybeTags}|T${item.timestamp}\n`; 26652 } 26653 return out; 26654} 26655 26656/** 26657 * Sanitizes tags. 26658 */ 26659function sanitizeTags(unsanitizedTags) { 26660 const tags = {}; 26661 for (const key in unsanitizedTags) { 26662 if (Object.prototype.hasOwnProperty.call(unsanitizedTags, key)) { 26663 const sanitizedKey = key.replace(constants.NAME_AND_TAG_KEY_NORMALIZATION_REGEX, '_'); 26664 tags[sanitizedKey] = String(unsanitizedTags[key]).replace(constants.TAG_VALUE_NORMALIZATION_REGEX, ''); 26665 } 26666 } 26667 return tags; 26668} 26669 26670exports.getBucketKey = getBucketKey; 26671exports.sanitizeTags = sanitizeTags; 26672exports.serializeMetricBuckets = serializeMetricBuckets; 26673exports.simpleHash = simpleHash; 26674 26675 26676},{"./constants.js":261,"@sentry/utils":319}],268:[function(require,module,exports){ 26677Object.defineProperty(exports, '__esModule', { value: true }); 26678 26679const utils = require('@sentry/utils'); 26680const eventProcessors = require('./eventProcessors.js'); 26681const session = require('./session.js'); 26682const applyScopeDataToEvent = require('./utils/applyScopeDataToEvent.js'); 26683 26684/** 26685 * Default value for maximum number of breadcrumbs added to an event. 26686 */ 26687const DEFAULT_MAX_BREADCRUMBS = 100; 26688 26689/** 26690 * The global scope is kept in this module. 26691 * When accessing this via `getGlobalScope()` we'll make sure to set one if none is currently present. 26692 */ 26693let globalScope; 26694 26695/** 26696 * Holds additional event information. {@link Scope.applyToEvent} will be 26697 * called by the client before an event will be sent. 26698 */ 26699class Scope { 26700 /** Flag if notifying is happening. */ 26701 26702 /** Callback for client to receive scope changes. */ 26703 26704 /** Callback list that will be called after {@link applyToEvent}. */ 26705 26706 /** Array of breadcrumbs. */ 26707 26708 /** User */ 26709 26710 /** Tags */ 26711 26712 /** Extra */ 26713 26714 /** Contexts */ 26715 26716 /** Attachments */ 26717 26718 /** Propagation Context for distributed tracing */ 26719 26720 /** 26721 * A place to stash data which is needed at some point in the SDK's event processing pipeline but which shouldn't get 26722 * sent to Sentry 26723 */ 26724 26725 /** Fingerprint */ 26726 26727 /** Severity */ 26728 // eslint-disable-next-line deprecation/deprecation 26729 26730 /** 26731 * Transaction Name 26732 */ 26733 26734 /** Span */ 26735 26736 /** Session */ 26737 26738 /** Request Mode Session Status */ 26739 26740 /** The client on this scope */ 26741 26742 // NOTE: Any field which gets added here should get added not only to the constructor but also to the `clone` method. 26743 26744 constructor() { 26745 this._notifyingListeners = false;
vendor: 9,158 bytes, lines 26746-27135
26746 this._scopeListeners = []; 26747 this._eventProcessors = []; 26748 this._breadcrumbs = []; 26749 this._attachments = []; 26750 this._user = {}; 26751 this._tags = {}; 26752 this._extra = {}; 26753 this._contexts = {}; 26754 this._sdkProcessingMetadata = {}; 26755 this._propagationContext = generatePropagationContext(); 26756 } 26757 26758 /** 26759 * Inherit values from the parent scope. 26760 * @deprecated Use `scope.clone()` and `new Scope()` instead. 26761 */ 26762 static clone(scope) { 26763 return scope ? scope.clone() : new Scope(); 26764 } 26765 26766 /** 26767 * Clone this scope instance. 26768 */ 26769 clone() { 26770 const newScope = new Scope(); 26771 newScope._breadcrumbs = [...this._breadcrumbs]; 26772 newScope._tags = { ...this._tags }; 26773 newScope._extra = { ...this._extra }; 26774 newScope._contexts = { ...this._contexts }; 26775 newScope._user = this._user; 26776 newScope._level = this._level; 26777 newScope._span = this._span; 26778 newScope._session = this._session; 26779 newScope._transactionName = this._transactionName; 26780 newScope._fingerprint = this._fingerprint; 26781 newScope._eventProcessors = [...this._eventProcessors]; 26782 newScope._requestSession = this._requestSession; 26783 newScope._attachments = [...this._attachments]; 26784 newScope._sdkProcessingMetadata = { ...this._sdkProcessingMetadata }; 26785 newScope._propagationContext = { ...this._propagationContext }; 26786 newScope._client = this._client; 26787 26788 return newScope; 26789 } 26790 26791 /** Update the client on the scope. */ 26792 setClient(client) { 26793 this._client = client; 26794 } 26795 26796 /** 26797 * Get the client assigned to this scope. 26798 * 26799 * It is generally recommended to use the global function `Sentry.getClient()` instead, unless you know what you are doing. 26800 */ 26801 getClient() { 26802 return this._client; 26803 } 26804 26805 /** 26806 * Add internal on change listener. Used for sub SDKs that need to store the scope. 26807 * @hidden 26808 */ 26809 addScopeListener(callback) { 26810 this._scopeListeners.push(callback); 26811 } 26812 26813 /** 26814 * @inheritDoc 26815 */ 26816 addEventProcessor(callback) { 26817 this._eventProcessors.push(callback); 26818 return this; 26819 } 26820 26821 /** 26822 * @inheritDoc 26823 */ 26824 setUser(user) { 26825 // If null is passed we want to unset everything, but still define keys, 26826 // so that later down in the pipeline any existing values are cleared. 26827 this._user = user || { 26828 email: undefined, 26829 id: undefined, 26830 ip_address: undefined, 26831 segment: undefined, 26832 username: undefined, 26833 }; 26834 26835 if (this._session) { 26836 session.updateSession(this._session, { user }); 26837 } 26838 26839 this._notifyScopeListeners(); 26840 return this; 26841 } 26842 26843 /** 26844 * @inheritDoc 26845 */ 26846 getUser() { 26847 return this._user; 26848 } 26849 26850 /** 26851 * @inheritDoc 26852 */ 26853 getRequestSession() { 26854 return this._requestSession; 26855 } 26856 26857 /** 26858 * @inheritDoc 26859 */ 26860 setRequestSession(requestSession) { 26861 this._requestSession = requestSession; 26862 return this; 26863 } 26864 26865 /** 26866 * @inheritDoc 26867 */ 26868 setTags(tags) { 26869 this._tags = { 26870 ...this._tags, 26871 ...tags, 26872 }; 26873 this._notifyScopeListeners(); 26874 return this; 26875 } 26876 26877 /** 26878 * @inheritDoc 26879 */ 26880 setTag(key, value) { 26881 this._tags = { ...this._tags, [key]: value }; 26882 this._notifyScopeListeners(); 26883 return this; 26884 } 26885 26886 /** 26887 * @inheritDoc 26888 */ 26889 setExtras(extras) { 26890 this._extra = { 26891 ...this._extra, 26892 ...extras, 26893 }; 26894 this._notifyScopeListeners(); 26895 return this; 26896 } 26897 26898 /** 26899 * @inheritDoc 26900 */ 26901 setExtra(key, extra) { 26902 this._extra = { ...this._extra, [key]: extra }; 26903 this._notifyScopeListeners(); 26904 return this; 26905 } 26906 26907 /** 26908 * @inheritDoc 26909 */ 26910 setFingerprint(fingerprint) { 26911 this._fingerprint = fingerprint; 26912 this._notifyScopeListeners(); 26913 return this; 26914 } 26915 26916 /** 26917 * @inheritDoc 26918 */ 26919 setLevel( 26920 // eslint-disable-next-line deprecation/deprecation 26921 level, 26922 ) { 26923 this._level = level; 26924 this._notifyScopeListeners(); 26925 return this; 26926 } 26927 26928 /** 26929 * Sets the transaction name on the scope for future events. 26930 */ 26931 setTransactionName(name) { 26932 this._transactionName = name; 26933 this._notifyScopeListeners(); 26934 return this; 26935 } 26936 26937 /** 26938 * @inheritDoc 26939 */ 26940 setContext(key, context) { 26941 if (context === null) { 26942 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 26943 delete this._contexts[key]; 26944 } else { 26945 this._contexts[key] = context; 26946 } 26947 26948 this._notifyScopeListeners(); 26949 return this; 26950 } 26951 26952 /** 26953 * Sets the Span on the scope. 26954 * @param span Span 26955 * @deprecated Instead of setting a span on a scope, use `startSpan()`/`startSpanManual()` instead. 26956 */ 26957 setSpan(span) { 26958 this._span = span; 26959 this._notifyScopeListeners(); 26960 return this; 26961 } 26962 26963 /** 26964 * Returns the `Span` if there is one. 26965 * @deprecated Use `getActiveSpan()` instead. 26966 */ 26967 getSpan() { 26968 return this._span; 26969 } 26970 26971 /** 26972 * Returns the `Transaction` attached to the scope (if there is one). 26973 * @deprecated You should not rely on the transaction, but just use `startSpan()` APIs instead. 26974 */ 26975 getTransaction() { 26976 // Often, this span (if it exists at all) will be a transaction, but it's not guaranteed to be. Regardless, it will 26977 // have a pointer to the currently-active transaction. 26978 const span = this._span; 26979 // Cannot replace with getRootSpan because getRootSpan returns a span, not a transaction 26980 // Also, this method will be removed anyway. 26981 // eslint-disable-next-line deprecation/deprecation 26982 return span && span.transaction; 26983 } 26984 26985 /** 26986 * @inheritDoc 26987 */ 26988 setSession(session) { 26989 if (!session) { 26990 delete this._session; 26991 } else { 26992 this._session = session; 26993 } 26994 this._notifyScopeListeners(); 26995 return this; 26996 } 26997 26998 /** 26999 * @inheritDoc 27000 */ 27001 getSession() { 27002 return this._session; 27003 } 27004 27005 /** 27006 * @inheritDoc 27007 */ 27008 update(captureContext) { 27009 if (!captureContext) { 27010 return this; 27011 } 27012 27013 const scopeToMerge = typeof captureContext === 'function' ? captureContext(this) : captureContext; 27014 27015 if (scopeToMerge instanceof Scope) { 27016 const scopeData = scopeToMerge.getScopeData(); 27017 27018 this._tags = { ...this._tags, ...scopeData.tags }; 27019 this._extra = { ...this._extra, ...scopeData.extra }; 27020 this._contexts = { ...this._contexts, ...scopeData.contexts }; 27021 if (scopeData.user && Object.keys(scopeData.user).length) { 27022 this._user = scopeData.user; 27023 } 27024 if (scopeData.level) { 27025 this._level = scopeData.level; 27026 } 27027 if (scopeData.fingerprint.length) { 27028 this._fingerprint = scopeData.fingerprint; 27029 } 27030 if (scopeToMerge.getRequestSession()) { 27031 this._requestSession = scopeToMerge.getRequestSession(); 27032 } 27033 if (scopeData.propagationContext) { 27034 this._propagationContext = scopeData.propagationContext; 27035 } 27036 } else if (utils.isPlainObject(scopeToMerge)) { 27037 const scopeContext = captureContext ; 27038 this._tags = { ...this._tags, ...scopeContext.tags }; 27039 this._extra = { ...this._extra, ...scopeContext.extra }; 27040 this._contexts = { ...this._contexts, ...scopeContext.contexts }; 27041 if (scopeContext.user) { 27042 this._user = scopeContext.user; 27043 } 27044 if (scopeContext.level) { 27045 this._level = scopeContext.level; 27046 } 27047 if (scopeContext.fingerprint) { 27048 this._fingerprint = scopeContext.fingerprint; 27049 } 27050 if (scopeContext.requestSession) { 27051 this._requestSession = scopeContext.requestSession; 27052 } 27053 if (scopeContext.propagationContext) { 27054 this._propagationContext = scopeContext.propagationContext; 27055 } 27056 } 27057 27058 return this; 27059 } 27060 27061 /** 27062 * @inheritDoc 27063 */ 27064 clear() { 27065 this._breadcrumbs = []; 27066 this._tags = {}; 27067 this._extra = {}; 27068 this._user = {}; 27069 this._contexts = {}; 27070 this._level = undefined; 27071 this._transactionName = undefined; 27072 this._fingerprint = undefined; 27073 this._requestSession = undefined; 27074 this._span = undefined; 27075 this._session = undefined; 27076 this._notifyScopeListeners(); 27077 this._attachments = []; 27078 this._propagationContext = generatePropagationContext(); 27079 return this; 27080 } 27081 27082 /** 27083 * @inheritDoc 27084 */ 27085 addBreadcrumb(breadcrumb, maxBreadcrumbs) { 27086 const maxCrumbs = typeof maxBreadcrumbs === 'number' ? maxBreadcrumbs : DEFAULT_MAX_BREADCRUMBS; 27087 27088 // No data has been changed, so don't notify scope listeners 27089 if (maxCrumbs <= 0) { 27090 return this; 27091 } 27092 27093 const mergedBreadcrumb = { 27094 timestamp: utils.dateTimestampInSeconds(), 27095 ...breadcrumb, 27096 }; 27097 27098 const breadcrumbs = this._breadcrumbs; 27099 breadcrumbs.push(mergedBreadcrumb); 27100 this._breadcrumbs = breadcrumbs.length > maxCrumbs ? breadcrumbs.slice(-maxCrumbs) : breadcrumbs; 27101 27102 this._notifyScopeListeners(); 27103 27104 return this; 27105 } 27106 27107 /** 27108 * @inheritDoc 27109 */ 27110 getLastBreadcrumb() { 27111 return this._breadcrumbs[this._breadcrumbs.length - 1]; 27112 } 27113 27114 /** 27115 * @inheritDoc 27116 */ 27117 clearBreadcrumbs() { 27118 this._breadcrumbs = []; 27119 this._notifyScopeListeners(); 27120 return this; 27121 } 27122 27123 /** 27124 * @inheritDoc 27125 */ 27126 addAttachment(attachment) { 27127 this._attachments.push(attachment); 27128 return this; 27129 } 27130 27131 /** 27132 * @inheritDoc 27133 * @deprecated Use `getScopeData()` instead. 27134 */ 27135 getAttachments() {
27136 const data = this.getScopeData(); 27137 27138 return data.attachments; 27139 } 27140 27141 /** 27142 * @inheritDoc 27143 */ 27144 clearAttachments() { 27145 this._attachments = []; 27146 return this; 27147 } 27148 27149 /** @inheritDoc */ 27150 getScopeData() { 27151 const { 27152 _breadcrumbs, 27153 _attachments, 27154 _contexts, 27155 _tags, 27156 _extra, 27157 _user, 27158 _level, 27159 _fingerprint, 27160 _eventProcessors, 27161 _propagationContext, 27162 _sdkProcessingMetadata, 27163 _transactionName, 27164 _span, 27165 } = this; 27166 27167 return { 27168 breadcrumbs: _breadcrumbs, 27169 attachments: _attachments, 27170 contexts: _contexts, 27171 tags: _tags, 27172 extra: _extra, 27173 user: _user, 27174 level: _level, 27175 fingerprint: _fingerprint || [], 27176 eventProcessors: _eventProcessors, 27177 propagationContext: _propagationContext, 27178 sdkProcessingMetadata: _sdkProcessingMetadata, 27179 transactionName: _transactionName, 27180 span: _span, 27181 }; 27182 } 27183 27184 /** 27185 * Applies data from the scope to the event and runs all event processors on it. 27186 * 27187 * @param event Event 27188 * @param hint Object containing additional information about the original exception, for use by the event processors. 27189 * @hidden 27190 * @deprecated Use `applyScopeDataToEvent()` directly 27191 */ 27192 applyToEvent( 27193 event, 27194 hint = {}, 27195 additionalEventProcessors = [], 27196 ) { 27197 applyScopeDataToEvent.applyScopeDataToEvent(event, this.getScopeData()); 27198 27199 // TODO (v8): Update this order to be: Global > Client > Scope 27200 const eventProcessors$1 = [ 27201 ...additionalEventProcessors, 27202 // eslint-disable-next-line deprecation/deprecation 27203 ...eventProcessors.getGlobalEventProcessors(), 27204 ...this._eventProcessors, 27205 ]; 27206 27207 return eventProcessors.notifyEventProcessors(eventProcessors$1, event, hint); 27208 } 27209 27210 /** 27211 * Add data which will be accessible during event processing but won't get sent to Sentry 27212 */ 27213 setSDKProcessingMetadata(newData) { 27214 this._sdkProcessingMetadata = { ...this._sdkProcessingMetadata, ...newData }; 27215 27216 return this; 27217 } 27218 27219 /** 27220 * @inheritDoc 27221 */ 27222 setPropagationContext(context) { 27223 this._propagationContext = context; 27224 return this; 27225 } 27226 27227 /** 27228 * @inheritDoc 27229 */ 27230 getPropagationContext() { 27231 return this._propagationContext; 27232 } 27233 27234 /** 27235 * Capture an exception for this scope. 27236 * 27237 * @param exception The exception to capture. 27238 * @param hint Optinal additional data to attach to the Sentry event. 27239 * @returns the id of the captured Sentry event. 27240 */ 27241 captureException(exception, hint) { 27242 const eventId = hint && hint.event_id ? hint.event_id : utils.uuid4(); 27243 27244 if (!this._client) { 27245 utils.logger.warn('No client configured on scope - will not capture exception!'); 27246 return eventId; 27247 } 27248 27249 const syntheticException = new Error('Sentry syntheticException'); 27250 27251 this._client.captureException( 27252 exception, 27253 { 27254 originalException: exception, 27255 syntheticException, 27256 ...hint, 27257 event_id: eventId, 27258 }, 27259 this, 27260 ); 27261 27262 return eventId; 27263 } 27264 27265 /** 27266 * Capture a message for this scope. 27267 * 27268 * @param message The message to capture. 27269 * @param level An optional severity level to report the message with. 27270 * @param hint Optional additional data to attach to the Sentry event. 27271 * @returns the id of the captured message. 27272 */ 27273 captureMessage(message, level, hint) { 27274 const eventId = hint && hint.event_id ? hint.event_id : utils.uuid4(); 27275 27276 if (!this._client) { 27277 utils.logger.warn('No client configured on scope - will not capture message!'); 27278 return eventId; 27279 } 27280 27281 const syntheticException = new Error(message); 27282 27283 this._client.captureMessage( 27284 message, 27285 level, 27286 { 27287 originalException: message, 27288 syntheticException, 27289 ...hint, 27290 event_id: eventId, 27291 }, 27292 this, 27293 ); 27294 27295 return eventId; 27296 } 27297 27298 /** 27299 * Captures a manually created event for this scope and sends it to Sentry. 27300 * 27301 * @param exception The event to capture. 27302 * @param hint Optional additional data to attach to the Sentry event. 27303 * @returns the id of the captured event. 27304 */ 27305 captureEvent(event, hint) { 27306 const eventId = hint && hint.event_id ? hint.event_id : utils.uuid4(); 27307 27308 if (!this._client) { 27309 utils.logger.warn('No client configured on scope - will not capture event!'); 27310 return eventId; 27311 } 27312 27313 this._client.captureEvent(event, { ...hint, event_id: eventId }, this); 27314 27315 return eventId; 27316 } 27317 27318 /** 27319 * This will be called on every set call. 27320 */ 27321 _notifyScopeListeners() { 27322 // We need this check for this._notifyingListeners to be able to work on scope during updates 27323 // If this check is not here we'll produce endless recursion when something is done with the scope 27324 // during the callback. 27325 if (!this._notifyingListeners) { 27326 this._notifyingListeners = true;
27327 this._scopeListeners.forEach(callback => { 27328 callback(this); 27329 }); 27330 this._notifyingListeners = false; 27331 } 27332 } 27333} 27334 27335/** 27336 * Get the global scope. 27337 * This scope is applied to _all_ events. 27338 */ 27339function getGlobalScope() { 27340 if (!globalScope) { 27341 globalScope = new Scope(); 27342 } 27343 27344 return globalScope; 27345} 27346 27347/** 27348 * This is mainly needed for tests. 27349 * DO NOT USE this, as this is an internal API and subject to change. 27350 * @hidden 27351 */ 27352function setGlobalScope(scope) { 27353 globalScope = scope; 27354} 27355 27356function generatePropagationContext() { 27357 return { 27358 traceId: utils.uuid4(), 27359 spanId: utils.uuid4().substring(16), 27360 }; 27361} 27362 27363exports.Scope = Scope; 27364exports.getGlobalScope = getGlobalScope; 27365exports.setGlobalScope = setGlobalScope; 27366 27367 27368},{"./eventProcessors.js":247,"./session.js":272,"./utils/applyScopeDataToEvent.js":289,"@sentry/utils":319}],269:[function(require,module,exports){ 27369Object.defineProperty(exports, '__esModule', { value: true }); 27370 27371const utils = require('@sentry/utils'); 27372const debugBuild = require('./debug-build.js'); 27373const exports$1 = require('./exports.js'); 27374const hub = require('./hub.js'); 27375 27376/** A class object that can instantiate Client objects. */ 27377 27378/** 27379 * Internal function to create a new SDK client instance. The client is 27380 * installed and then bound to the current scope. 27381 * 27382 * @param clientClass The client class to instantiate. 27383 * @param options Options to pass to the client. 27384 */ 27385function initAndBind( 27386 clientClass, 27387 options, 27388) { 27389 if (options.debug === true) { 27390 if (debugBuild.DEBUG_BUILD) { 27391 utils.logger.enable(); 27392 } else { 27393 // use `console.warn` rather than `logger.warn` since by non-debug bundles have all `logger.x` statements stripped 27394 utils.consoleSandbox(() => { 27395 // eslint-disable-next-line no-console 27396 console.warn('[Sentry] Cannot initialize SDK with `debug` option using a non-debug bundle.'); 27397 }); 27398 } 27399 } 27400 const scope = exports$1.getCurrentScope(); 27401 scope.update(options.initialScope); 27402 27403 const client = new clientClass(options); 27404 setCurrentClient(client); 27405 initializeClient(client); 27406} 27407 27408/** 27409 * Make the given client the current client. 27410 */ 27411function setCurrentClient(client) { 27412 // eslint-disable-next-line deprecation/deprecation 27413 const hub$1 = hub.getCurrentHub(); 27414 // eslint-disable-next-line deprecation/deprecation 27415 const top = hub$1.getStackTop(); 27416 top.client = client; 27417 top.scope.setClient(client); 27418} 27419 27420/** 27421 * Initialize the client for the current scope. 27422 * Make sure to call this after `setCurrentClient()`. 27423 */ 27424function initializeClient(client) { 27425 if (client.init) { 27426 client.init(); 27427 // TODO v8: Remove this fallback 27428 // eslint-disable-next-line deprecation/deprecation 27429 } else if (client.setupIntegrations) { 27430 // eslint-disable-next-line deprecation/deprecation 27431 client.setupIntegrations(); 27432 } 27433} 27434 27435exports.initAndBind = initAndBind; 27436exports.setCurrentClient = setCurrentClient; 27437 27438 27439},{"./debug-build.js":245,"./exports.js":248,"./hub.js":249,"@sentry/utils":319}],270:[function(require,module,exports){ 27440Object.defineProperty(exports, '__esModule', { value: true }); 27441 27442/** 27443 * Use this attribute to represent the source of a span. 27444 * Should be one of: custom, url, route, view, component, task, unknown 27445 * 27446 */ 27447const SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = 'sentry.source'; 27448 27449/** 27450 * Use this attribute to represent the sample rate used for a span. 27451 */ 27452const SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = 'sentry.sample_rate'; 27453 27454/** 27455 * Use this attribute to represent the operation of a span. 27456 */ 27457const SEMANTIC_ATTRIBUTE_SENTRY_OP = 'sentry.op'; 27458 27459/** 27460 * Use this attribute to represent the origin of a span. 27461 */ 27462const SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = 'sentry.origin'; 27463 27464/** 27465 * The id of the profile that this span occured in. 27466 */ 27467const SEMANTIC_ATTRIBUTE_PROFILE_ID = 'profile_id'; 27468 27469exports.SEMANTIC_ATTRIBUTE_PROFILE_ID = SEMANTIC_ATTRIBUTE_PROFILE_ID; 27470exports.SEMANTIC_ATTRIBUTE_SENTRY_OP = SEMANTIC_ATTRIBUTE_SENTRY_OP; 27471exports.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN; 27472exports.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE; 27473exports.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = SEMANTIC_ATTRIBUTE_SENTRY_SOURCE; 27474 27475 27476},{}],271:[function(require,module,exports){ 27477Object.defineProperty(exports, '__esModule', { value: true }); 27478 27479const utils = require('@sentry/utils'); 27480const baseclient = require('./baseclient.js'); 27481const checkin = require('./checkin.js'); 27482const debugBuild = require('./debug-build.js'); 27483const exports$1 = require('./exports.js'); 27484const aggregator = require('./metrics/aggregator.js'); 27485const sessionflusher = require('./sessionflusher.js'); 27486const hubextensions = require('./tracing/hubextensions.js'); 27487const spanUtils = require('./utils/spanUtils.js'); 27488const getRootSpan = require('./utils/getRootSpan.js'); 27489require('./tracing/spanstatus.js'); 27490const dynamicSamplingContext = require('./tracing/dynamicSamplingContext.js'); 27491 27492/** 27493 * The Sentry Server Runtime Client SDK. 27494 */ 27495class ServerRuntimeClient 27496 27497 extends baseclient.BaseClient { 27498 27499 /** 27500 * Creates a new Edge SDK instance. 27501 * @param options Configuration options for this SDK. 27502 */ 27503 constructor(options) {
27504 // Server clients always support tracing 27505 hubextensions.addTracingExtensions(); 27506 27507 super(options); 27508 27509 if (options._experiments && options._experiments['metricsAggregator']) { 27510 this.metricsAggregator = new aggregator.MetricsAggregator(this); 27511 } 27512 } 27513 27514 /** 27515 * @inheritDoc 27516 */ 27517 eventFromException(exception, hint) { 27518 return utils.resolvedSyncPromise(utils.eventFromUnknownInput(exports$1.getClient(), this._options.stackParser, exception, hint)); 27519 } 27520 27521 /** 27522 * @inheritDoc 27523 */ 27524 eventFromMessage( 27525 message, 27526 // eslint-disable-next-line deprecation/deprecation 27527 level = 'info', 27528 hint, 27529 ) { 27530 return utils.resolvedSyncPromise( 27531 utils.eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace), 27532 ); 27533 } 27534 27535 /** 27536 * @inheritDoc 27537 */ 27538 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types 27539 captureException(exception, hint, scope) { 27540 // Check if the flag `autoSessionTracking` is enabled, and if `_sessionFlusher` exists because it is initialised only 27541 // when the `requestHandler` middleware is used, and hence the expectation is to have SessionAggregates payload 27542 // sent to the Server only when the `requestHandler` middleware is used 27543 if (this._options.autoSessionTracking && this._sessionFlusher && scope) { 27544 const requestSession = scope.getRequestSession(); 27545 27546 // Necessary checks to ensure this is code block is executed only within a request 27547 // Should override the status only if `requestSession.status` is `Ok`, which is its initial stage 27548 if (requestSession && requestSession.status === 'ok') { 27549 requestSession.status = 'errored'; 27550 } 27551 } 27552 27553 return super.captureException(exception, hint, scope); 27554 } 27555 27556 /** 27557 * @inheritDoc 27558 */ 27559 captureEvent(event, hint, scope) { 27560 // Check if the flag `autoSessionTracking` is enabled, and if `_sessionFlusher` exists because it is initialised only 27561 // when the `requestHandler` middleware is used, and hence the expectation is to have SessionAggregates payload 27562 // sent to the Server only when the `requestHandler` middleware is used 27563 if (this._options.autoSessionTracking && this._sessionFlusher && scope) { 27564 const eventType = event.type || 'exception'; 27565 const isException = 27566 eventType === 'exception' && event.exception && event.exception.values && event.exception.values.length > 0; 27567 27568 // If the event is of type Exception, then a request session should be captured 27569 if (isException) { 27570 const requestSession = scope.getRequestSession(); 27571 27572 // Ensure that this is happening within the bounds of a request, and make sure not to override 27573 // Session Status if Errored / Crashed 27574 if (requestSession && requestSession.status === 'ok') { 27575 requestSession.status = 'errored'; 27576 } 27577 } 27578 } 27579 27580 return super.captureEvent(event, hint, scope); 27581 } 27582 27583 /** 27584 * 27585 * @inheritdoc 27586 */ 27587 close(timeout) { 27588 if (this._sessionFlusher) { 27589 this._sessionFlusher.close(); 27590 } 27591 return super.close(timeout); 27592 } 27593 27594 /** Method that initialises an instance of SessionFlusher on Client */ 27595 initSessionFlusher() { 27596 const { release, environment } = this._options; 27597 if (!release) { 27598 debugBuild.DEBUG_BUILD && utils.logger.warn('Cannot initialise an instance of SessionFlusher if no release is provided!'); 27599 } else { 27600 this._sessionFlusher = new sessionflusher.SessionFlusher(this, { 27601 release, 27602 environment, 27603 }); 27604 } 27605 } 27606 27607 /** 27608 * Create a cron monitor check in and send it to Sentry. 27609 * 27610 * @param checkIn An object that describes a check in. 27611 * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want 27612 * to create a monitor automatically when sending a check in. 27613 */ 27614 captureCheckIn(checkIn, monitorConfig, scope) { 27615 const id = 'checkInId' in checkIn && checkIn.checkInId ? checkIn.checkInId : utils.uuid4(); 27616 if (!this._isEnabled()) { 27617 debugBuild.DEBUG_BUILD && utils.logger.warn('SDK not enabled, will not capture checkin.'); 27618 return id; 27619 } 27620 27621 const options = this.getOptions(); 27622 const { release, environment, tunnel } = options; 27623 27624 const serializedCheckIn = { 27625 check_in_id: id, 27626 monitor_slug: checkIn.monitorSlug, 27627 status: checkIn.status, 27628 release, 27629 environment, 27630 }; 27631 27632 if ('duration' in checkIn) { 27633 serializedCheckIn.duration = checkIn.duration; 27634 } 27635 27636 if (monitorConfig) { 27637 serializedCheckIn.monitor_config = { 27638 schedule: monitorConfig.schedule, 27639 checkin_margin: monitorConfig.checkinMargin, 27640 max_runtime: monitorConfig.maxRuntime, 27641 timezone: monitorConfig.timezone, 27642 }; 27643 } 27644 27645 const [dynamicSamplingContext, traceContext] = this._getTraceInfoFromScope(scope); 27646 if (traceContext) { 27647 serializedCheckIn.contexts = { 27648 trace: traceContext, 27649 }; 27650 } 27651 27652 const envelope = checkin.createCheckInEnvelope( 27653 serializedCheckIn, 27654 dynamicSamplingContext,
27655 this.getSdkMetadata(), 27656 tunnel, 27657 this.getDsn(), 27658 ); 27659 27660 debugBuild.DEBUG_BUILD && utils.logger.info('Sending checkin:', checkIn.monitorSlug, checkIn.status); 27661 27662 // _sendEnvelope should not throw 27663 // eslint-disable-next-line @typescript-eslint/no-floating-promises 27664 this._sendEnvelope(envelope); 27665 27666 return id; 27667 } 27668 27669 /** 27670 * Method responsible for capturing/ending a request session by calling `incrementSessionStatusCount` to increment 27671 * appropriate session aggregates bucket 27672 */ 27673 _captureRequestSession() { 27674 if (!this._sessionFlusher) { 27675 debugBuild.DEBUG_BUILD && utils.logger.warn('Discarded request mode session because autoSessionTracking option was disabled'); 27676 } else { 27677 this._sessionFlusher.incrementSessionStatusCount(); 27678 } 27679 } 27680 27681 /** 27682 * @inheritDoc 27683 */ 27684 _prepareEvent( 27685 event, 27686 hint, 27687 scope, 27688 isolationScope, 27689 ) { 27690 if (this._options.platform) { 27691 event.platform = event.platform || this._options.platform; 27692 } 27693 27694 if (this._options.runtime) { 27695 event.contexts = { 27696 ...event.contexts, 27697 runtime: (event.contexts || {}).runtime || this._options.runtime, 27698 }; 27699 } 27700 27701 if (this._options.serverName) { 27702 event.server_name = event.server_name || this._options.serverName; 27703 } 27704 27705 return super._prepareEvent(event, hint, scope, isolationScope); 27706 } 27707 27708 /** Extract trace information from scope */ 27709 _getTraceInfoFromScope( 27710 scope, 27711 ) { 27712 if (!scope) { 27713 return [undefined, undefined]; 27714 } 27715 27716 // eslint-disable-next-line deprecation/deprecation 27717 const span = scope.getSpan(); 27718 if (span) { 27719 const samplingContext = getRootSpan.getRootSpan(span) ? dynamicSamplingContext.getDynamicSamplingContextFromSpan(span) : undefined; 27720 return [samplingContext, spanUtils.spanToTraceContext(span)]; 27721 } 27722 27723 const { traceId, spanId, parentSpanId, dsc } = scope.getPropagationContext(); 27724 const traceContext = { 27725 trace_id: traceId, 27726 span_id: spanId, 27727 parent_span_id: parentSpanId, 27728 }; 27729 if (dsc) { 27730 return [dsc, traceContext]; 27731 } 27732 27733 return [dynamicSamplingContext.getDynamicSamplingContextFromClient(traceId, this, scope), traceContext]; 27734 } 27735} 27736 27737exports.ServerRuntimeClient = ServerRuntimeClient; 27738 27739 27740},{"./baseclient.js":242,"./checkin.js":243,"./debug-build.js":245,"./exports.js":248,"./metrics/aggregator.js":259,"./sessionflusher.js":273,"./tracing/dynamicSamplingContext.js":275,"./tracing/hubextensions.js":277,"./tracing/spanstatus.js":282,"./utils/getRootSpan.js":290,"./utils/spanUtils.js":297,"@sentry/utils":319}],272:[function(require,module,exports){ 27741Object.defineProperty(exports, '__esModule', { value: true }); 27742 27743const utils = require('@sentry/utils'); 27744 27745/** 27746 * Creates a new `Session` object by setting certain default parameters. If optional @param context 27747 * is passed, the passed properties are applied to the session object. 27748 * 27749 * @param context (optional) additional properties to be applied to the returned session object 27750 * 27751 * @returns a new `Session` object 27752 */ 27753function makeSession(context) { 27754 // Both timestamp and started are in seconds since the UNIX epoch. 27755 const startingTime = utils.timestampInSeconds(); 27756 27757 const session = { 27758 sid: utils.uuid4(), 27759 init: true, 27760 timestamp: startingTime, 27761 started: startingTime, 27762 duration: 0, 27763 status: 'ok', 27764 errors: 0, 27765 ignoreDuration: false, 27766 toJSON: () => sessionToJSON(session), 27767 }; 27768 27769 if (context) { 27770 updateSession(session, context); 27771 } 27772 27773 return session; 27774} 27775 27776/** 27777 * Updates a session object with the properties passed in the context. 27778 * 27779 * Note that this function mutates the passed object and returns void. 27780 * (Had to do this instead of returning a new and updated session because closing and sending a session 27781 * makes an update to the session after it was passed to the sending logic. 27782 * @see BaseClient.captureSession ) 27783 * 27784 * @param session the `Session` to update 27785 * @param context the `SessionContext` holding the properties that should be updated in @param session 27786 */ 27787// eslint-disable-next-line complexity 27788function updateSession(session, context = {}) { 27789 if (context.user) { 27790 if (!session.ipAddress && context.user.ip_address) { 27791 session.ipAddress = context.user.ip_address; 27792 } 27793 27794 if (!session.did && !context.did) { 27795 session.did = context.user.id || context.user.email || context.user.username; 27796 } 27797 } 27798 27799 session.timestamp = context.timestamp || utils.timestampInSeconds(); 27800 27801 if (context.abnormal_mechanism) { 27802 session.abnormal_mechanism = context.abnormal_mechanism; 27803 } 27804 27805 if (context.ignoreDuration) {
27806 session.ignoreDuration = context.ignoreDuration; 27807 } 27808 if (context.sid) { 27809 // Good enough uuid validation. â Kamil 27810 session.sid = context.sid.length === 32 ? context.sid : utils.uuid4(); 27811 } 27812 if (context.init !== undefined) { 27813 session.init = context.init; 27814 } 27815 if (!session.did && context.did) { 27816 session.did = `${context.did}`; 27817 } 27818 if (typeof context.started === 'number') { 27819 session.started = context.started; 27820 } 27821 if (session.ignoreDuration) { 27822 session.duration = undefined; 27823 } else if (typeof context.duration === 'number') { 27824 session.duration = context.duration; 27825 } else { 27826 const duration = session.timestamp - session.started; 27827 session.duration = duration >= 0 ? duration : 0; 27828 } 27829 if (context.release) { 27830 session.release = context.release; 27831 } 27832 if (context.environment) { 27833 session.environment = context.environment; 27834 } 27835 if (!session.ipAddress && context.ipAddress) { 27836 session.ipAddress = context.ipAddress; 27837 } 27838 if (!session.userAgent && context.userAgent) { 27839 session.userAgent = context.userAgent; 27840 } 27841 if (typeof context.errors === 'number') { 27842 session.errors = context.errors; 27843 } 27844 if (context.status) { 27845 session.status = context.status; 27846 } 27847} 27848 27849/** 27850 * Closes a session by setting its status and updating the session object with it. 27851 * Internally calls `updateSession` to update the passed session object. 27852 * 27853 * Note that this function mutates the passed session (@see updateSession for explanation). 27854 * 27855 * @param session the `Session` object to be closed 27856 * @param status the `SessionStatus` with which the session was closed. If you don't pass a status, 27857 * this function will keep the previously set status, unless it was `'ok'` in which case 27858 * it is changed to `'exited'`. 27859 */ 27860function closeSession(session, status) { 27861 let context = {}; 27862 if (status) { 27863 context = { status }; 27864 } else if (session.status === 'ok') { 27865 context = { status: 'exited' }; 27866 } 27867 27868 updateSession(session, context); 27869} 27870 27871/** 27872 * Serializes a passed session object to a JSON object with a slightly different structure. 27873 * This is necessary because the Sentry backend requires a slightly different schema of a session 27874 * than the one the JS SDKs use internally. 27875 * 27876 * @param session the session to be converted 27877 * 27878 * @returns a JSON object of the passed session 27879 */ 27880function sessionToJSON(session) { 27881 return utils.dropUndefinedKeys({ 27882 sid: `${session.sid}`, 27883 init: session.init, 27884 // Make sure that sec is converted to ms for date constructor 27885 started: new Date(session.started * 1000).toISOString(), 27886 timestamp: new Date(session.timestamp * 1000).toISOString(), 27887 status: session.status, 27888 errors: session.errors, 27889 did: typeof session.did === 'number' || typeof session.did === 'string' ? `${session.did}` : undefined, 27890 duration: session.duration, 27891 abnormal_mechanism: session.abnormal_mechanism, 27892 attrs: { 27893 release: session.release, 27894 environment: session.environment, 27895 ip_address: session.ipAddress, 27896 user_agent: session.userAgent, 27897 }, 27898 }); 27899} 27900 27901exports.closeSession = closeSession; 27902exports.makeSession = makeSession; 27903exports.updateSession = updateSession; 27904 27905 27906},{"@sentry/utils":319}],273:[function(require,module,exports){ 27907Object.defineProperty(exports, '__esModule', { value: true }); 27908 27909const utils = require('@sentry/utils'); 27910const exports$1 = require('./exports.js'); 27911 27912/** 27913 * @inheritdoc 27914 */ 27915class SessionFlusher { 27916 27917 constructor(client, attrs) { 27918 this._client = client; 27919 this.flushTimeout = 60; 27920 this._pendingAggregates = {}; 27921 this._isEnabled = true; 27922 27923 // Call to setInterval, so that flush is called every 60 seconds 27924 this._intervalId = setInterval(() => this.flush(), this.flushTimeout * 1000); 27925 this._sessionAttrs = attrs; 27926 } 27927 27928 /** Checks if `pendingAggregates` has entries, and if it does flushes them by calling `sendSession` */ 27929 flush() { 27930 const sessionAggregates = this.getSessionAggregates(); 27931 if (sessionAggregates.aggregates.length === 0) { 27932 return; 27933 } 27934 this._pendingAggregates = {}; 27935 this._client.sendSession(sessionAggregates); 27936 } 27937 27938 /** Massages the entries in `pendingAggregates` and returns aggregated sessions */ 27939 getSessionAggregates() {
27940 const aggregates = Object.keys(this._pendingAggregates).map((key) => { 27941 return this._pendingAggregates[parseInt(key)]; 27942 }); 27943 27944 const sessionAggregates = { 27945 attrs: this._sessionAttrs, 27946 aggregates, 27947 }; 27948 return utils.dropUndefinedKeys(sessionAggregates); 27949 } 27950 27951 /** JSDoc */ 27952 close() { 27953 clearInterval(this._intervalId); 27954 this._isEnabled = false; 27955 this.flush(); 27956 } 27957 27958 /** 27959 * Wrapper function for _incrementSessionStatusCount that checks if the instance of SessionFlusher is enabled then 27960 * fetches the session status of the request from `Scope.getRequestSession().status` on the scope and passes them to 27961 * `_incrementSessionStatusCount` along with the start date 27962 */ 27963 incrementSessionStatusCount() { 27964 if (!this._isEnabled) { 27965 return; 27966 } 27967 const scope = exports$1.getCurrentScope(); 27968 const requestSession = scope.getRequestSession(); 27969 27970 if (requestSession && requestSession.status) { 27971 this._incrementSessionStatusCount(requestSession.status, new Date()); 27972 // This is not entirely necessarily but is added as a safe guard to indicate the bounds of a request and so in 27973 // case captureRequestSession is called more than once to prevent double count 27974 scope.setRequestSession(undefined); 27975 /* eslint-enable @typescript-eslint/no-unsafe-member-access */ 27976 } 27977 } 27978 27979 /** 27980 * Increments status bucket in pendingAggregates buffer (internal state) corresponding to status of 27981 * the session received 27982 */ 27983 _incrementSessionStatusCount(status, date) { 27984 // Truncate minutes and seconds on Session Started attribute to have one minute bucket keys 27985 const sessionStartedTrunc = new Date(date).setSeconds(0, 0); 27986 this._pendingAggregates[sessionStartedTrunc] = this._pendingAggregates[sessionStartedTrunc] || {}; 27987 27988 // corresponds to aggregated sessions in one specific minute bucket 27989 // for example, {"started":"2021-03-16T08:00:00.000Z","exited":4, "errored": 1} 27990 const aggregationCounts = this._pendingAggregates[sessionStartedTrunc]; 27991 if (!aggregationCounts.started) { 27992 aggregationCounts.started = new Date(sessionStartedTrunc).toISOString(); 27993 } 27994 27995 switch (status) { 27996 case 'errored': 27997 aggregationCounts.errored = (aggregationCounts.errored || 0) + 1; 27998 return aggregationCounts.errored; 27999 case 'ok': 28000 aggregationCounts.exited = (aggregationCounts.exited || 0) + 1; 28001 return aggregationCounts.exited; 28002 default: 28003 aggregationCounts.crashed = (aggregationCounts.crashed || 0) + 1; 28004 return aggregationCounts.crashed; 28005 } 28006 } 28007} 28008 28009exports.SessionFlusher = SessionFlusher; 28010 28011 28012},{"./exports.js":248,"@sentry/utils":319}],274:[function(require,module,exports){ 28013Object.defineProperty(exports, '__esModule', { value: true }); 28014 28015const utils = require('@sentry/utils'); 28016 28017/** 28018 * Create envelope from Span item. 28019 */ 28020function createSpanEnvelope(spans, dsn) { 28021 const headers = { 28022 sent_at: new Date().toISOString(), 28023 }; 28024 28025 if (dsn) { 28026 headers.dsn = utils.dsnToString(dsn); 28027 } 28028 28029 const items = spans.map(createSpanItem); 28030 return utils.createEnvelope(headers, items); 28031} 28032 28033function createSpanItem(span) { 28034 const spanHeaders = { 28035 type: 'span', 28036 }; 28037 return [spanHeaders, span]; 28038} 28039 28040exports.createSpanEnvelope = createSpanEnvelope; 28041 28042 28043},{"@sentry/utils":319}],275:[function(require,module,exports){ 28044Object.defineProperty(exports, '__esModule', { value: true }); 28045 28046const utils = require('@sentry/utils'); 28047const constants = require('../constants.js'); 28048const exports$1 = require('../exports.js'); 28049const getRootSpan = require('../utils/getRootSpan.js'); 28050const spanUtils = require('../utils/spanUtils.js'); 28051 28052/** 28053 * Creates a dynamic sampling context from a client. 28054 * 28055 * Dispatches the `createDsc` lifecycle hook as a side effect. 28056 */ 28057function getDynamicSamplingContextFromClient( 28058 trace_id, 28059 client, 28060 scope, 28061) { 28062 const options = client.getOptions(); 28063 28064 const { publicKey: public_key } = client.getDsn() || {}; 28065 // TODO(v8): Remove segment from User 28066 // eslint-disable-next-line deprecation/deprecation 28067 const { segment: user_segment } = (scope && scope.getUser()) || {}; 28068 28069 const dsc = utils.dropUndefinedKeys({ 28070 environment: options.environment || constants.DEFAULT_ENVIRONMENT, 28071 release: options.release, 28072 user_segment, 28073 public_key, 28074 trace_id, 28075 }) ; 28076 28077 client.emit && client.emit('createDsc', dsc); 28078 28079 return dsc; 28080} 28081 28082/** 28083 * A Span with a frozen dynamic sampling context. 28084 */ 28085 28086/** 28087 * Creates a dynamic sampling context from a span (and client and scope) 28088 * 28089 * @param span the span from which a few values like the root span name and sample rate are extracted. 28090 * 28091 * @returns a dynamic sampling context 28092 */ 28093function getDynamicSamplingContextFromSpan(span) { 28094 const client = exports$1.getClient(); 28095 if (!client) { 28096 return {}; 28097 } 28098 28099 // passing emit=false here to only emit later once the DSC is actually populated 28100 const dsc = getDynamicSamplingContextFromClient(spanUtils.spanToJSON(span).trace_id || '', client, exports$1.getCurrentScope()); 28101 28102 // TODO (v8): Remove v7FrozenDsc as a Transaction will no longer have _frozenDynamicSamplingContext 28103 const txn = getRootSpan.getRootSpan(span) ; 28104 if (!txn) { 28105 return dsc; 28106 } 28107 28108 // TODO (v8): Remove v7FrozenDsc as a Transaction will no longer have _frozenDynamicSamplingContext 28109 // For now we need to avoid breaking users who directly created a txn with a DSC, where this field is still set. 28110 // @see Transaction class constructor 28111 const v7FrozenDsc = txn && txn._frozenDynamicSamplingContext; 28112 if (v7FrozenDsc) { 28113 return v7FrozenDsc; 28114 } 28115 28116 // TODO (v8): Replace txn.metadata with txn.attributes[] 28117 // We can't do this yet because attributes aren't always set yet. 28118 // eslint-disable-next-line deprecation/deprecation 28119 const { sampleRate: maybeSampleRate, source }
28119 = txn.metadata; 28120 if (maybeSampleRate != null) { 28121 dsc.sample_rate = `${maybeSampleRate}`; 28122 } 28123 28124 // We don't want to have a transaction name in the DSC if the source is "url" because URLs might contain PII 28125 const jsonSpan = spanUtils.spanToJSON(txn); 28126 28127 // after JSON conversion, txn.name becomes jsonSpan.description 28128 if (source && source !== 'url') { 28129 dsc.transaction = jsonSpan.description; 28130 } 28131 28132 dsc.sampled = String(spanUtils.spanIsSampled(txn)); 28133 28134 client.emit && client.emit('createDsc', dsc); 28135 28136 return dsc; 28137} 28138 28139exports.getDynamicSamplingContextFromClient = getDynamicSamplingContextFromClient; 28140exports.getDynamicSamplingContextFromSpan = getDynamicSamplingContextFromSpan; 28141 28142 28143},{"../constants.js":244,"../exports.js":248,"../utils/getRootSpan.js":290,"../utils/spanUtils.js":297,"@sentry/utils":319}],276:[function(require,module,exports){ 28144Object.defineProperty(exports, '__esModule', { value: true }); 28145 28146const utils = require('@sentry/utils'); 28147const debugBuild = require('../debug-build.js'); 28148const utils$1 = require('./utils.js'); 28149 28150let errorsInstrumented = false; 28151 28152/** 28153 * Configures global error listeners 28154 */ 28155function registerErrorInstrumentation() { 28156 if (errorsInstrumented) { 28157 return; 28158 } 28159 28160 errorsInstrumented = true; 28161 utils.addGlobalErrorInstrumentationHandler(errorCallback); 28162 utils.addGlobalUnhandledRejectionInstrumentationHandler(errorCallback); 28163} 28164 28165/** 28166 * If an error or unhandled promise occurs, we mark the active transaction as failed 28167 */ 28168function errorCallback() { 28169 // eslint-disable-next-line deprecation/deprecation 28170 const activeTransaction = utils$1.getActiveTransaction(); 28171 if (activeTransaction) { 28172 const status = 'internal_error'; 28173 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Transaction: ${status} -> Global error occured`); 28174 activeTransaction.setStatus(status); 28175 } 28176} 28177 28178// The function name will be lost when bundling but we need to be able to identify this listener later to maintain the 28179// node.js default exit behaviour 28180errorCallback.tag = 'sentry_tracingErrorCallback'; 28181 28182exports.registerErrorInstrumentation = registerErrorInstrumentation; 28183 28184 28185},{"../debug-build.js":245,"./utils.js":285,"@sentry/utils":319}],277:[function(require,module,exports){ 28186Object.defineProperty(exports, '__esModule', { value: true }); 28187 28188const utils = require('@sentry/utils'); 28189const debugBuild = require('../debug-build.js'); 28190const hub = require('../hub.js'); 28191const spanUtils = require('../utils/spanUtils.js'); 28192const errors = require('./errors.js'); 28193const idletransaction = require('./idletransaction.js'); 28194const sampling = require('./sampling.js'); 28195const transaction = require('./transaction.js'); 28196 28197/** Returns all trace headers that are currently on the top scope. */ 28198function traceHeaders() { 28199 // eslint-disable-next-line deprecation/deprecation 28200 const scope = this.getScope(); 28201 // eslint-disable-next-line deprecation/deprecation 28202 const span = scope.getSpan(); 28203 28204 return span 28205 ? { 28206 'sentry-trace': spanUtils.spanToTraceHeader(span), 28207 } 28208 : {}; 28209} 28210 28211/** 28212 * Creates a new transaction and adds a sampling decision if it doesn't yet have one. 28213 * 28214 * The Hub.startTransaction method delegates to this method to do its work, passing the Hub instance in as `this`, as if 28215 * it had been called on the hub directly. Exists as a separate function so that it can be injected into the class as an 28216 * "extension method." 28217 * 28218 * @param this: The Hub starting the transaction 28219 * @param transactionContext: Data used to configure the transaction 28220 * @param CustomSamplingContext: Optional data to be provided to the `tracesSampler` function (if any) 28221 * 28222 * @returns The new transaction 28223 * 28224 * @see {@link Hub.startTransaction} 28225 */ 28226function _startTransaction( 28227 28228 transactionContext, 28229 customSamplingContext, 28230) { 28231 // eslint-disable-next-line deprecation/deprecation 28232 const client = this.getClient(); 28233 const options = (client && client.getOptions()) || {}; 28234 28235 const configInstrumenter = options.instrumenter || 'sentry'; 28236 const transactionInstrumenter = transactionContext.instrumenter || 'sentry'; 28237 28238 if (configInstrumenter !== transactionInstrumenter) { 28239 debugBuild.DEBUG_BUILD && 28240 utils.logger.error( 28241 `A transaction was started with instrumenter=\`${transactionInstrumenter}\`, but the SDK is configured with the \`${configInstrumenter}\` instrumenter. 28242The transaction will not be sampled. Please use the ${configInstrumenter} instrumentation to start transactions.`, 28243 ); 28244 28245 // eslint-disable-next-line deprecation/deprecation 28246 transactionContext.sampled = false;
28247 } 28248 28249 // eslint-disable-next-line deprecation/deprecation 28250 let transaction$1 = new transaction.Transaction(transactionContext, this); 28251 transaction$1 = sampling.sampleTransaction(transaction$1, options, { 28252 name: transactionContext.name, 28253 parentSampled: transactionContext.parentSampled, 28254 transactionContext, 28255 attributes: { 28256 // eslint-disable-next-line deprecation/deprecation 28257 ...transactionContext.data, 28258 ...transactionContext.attributes, 28259 }, 28260 ...customSamplingContext, 28261 }); 28262 if (transaction$1.isRecording()) { 28263 transaction$1.initSpanRecorder(options._experiments && (options._experiments.maxSpans )); 28264 } 28265 if (client && client.emit) { 28266 client.emit('startTransaction', transaction$1); 28267 } 28268 return transaction$1; 28269} 28270 28271/** 28272 * Create new idle transaction. 28273 */ 28274function startIdleTransaction( 28275 hub, 28276 transactionContext, 28277 idleTimeout, 28278 finalTimeout, 28279 onScope, 28280 customSamplingContext, 28281 heartbeatInterval, 28282 delayAutoFinishUntilSignal = false, 28283) { 28284 // eslint-disable-next-line deprecation/deprecation 28285 const client = hub.getClient(); 28286 const options = (client && client.getOptions()) || {}; 28287 28288 // eslint-disable-next-line deprecation/deprecation 28289 let transaction = new idletransaction.IdleTransaction( 28290 transactionContext, 28291 hub, 28292 idleTimeout, 28293 finalTimeout, 28294 heartbeatInterval, 28295 onScope, 28296 delayAutoFinishUntilSignal, 28297 ); 28298 transaction = sampling.sampleTransaction(transaction, options, { 28299 name: transactionContext.name, 28300 parentSampled: transactionContext.parentSampled, 28301 transactionContext, 28302 attributes: { 28303 // eslint-disable-next-line deprecation/deprecation 28304 ...transactionContext.data, 28305 ...transactionContext.attributes, 28306 }, 28307 ...customSamplingContext, 28308 }); 28309 if (transaction.isRecording()) { 28310 transaction.initSpanRecorder(options._experiments && (options._experiments.maxSpans )); 28311 } 28312 if (client && client.emit) { 28313 client.emit('startTransaction', transaction); 28314 } 28315 return transaction; 28316} 28317 28318/** 28319 * Adds tracing extensions to the global hub. 28320 */ 28321function addTracingExtensions() { 28322 const carrier = hub.getMainCarrier(); 28323 if (!carrier.__SENTRY__) { 28324 return; 28325 } 28326 carrier.__SENTRY__.extensions = carrier.__SENTRY__.extensions || {}; 28327 if (!carrier.__SENTRY__.extensions.startTransaction) { 28328 carrier.__SENTRY__.extensions.startTransaction = _startTransaction; 28329 } 28330 if (!carrier.__SENTRY__.extensions.traceHeaders) { 28331 carrier.__SENTRY__.extensions.traceHeaders = traceHeaders; 28332 } 28333 28334 errors.registerErrorInstrumentation(); 28335} 28336 28337exports.addTracingExtensions = addTracingExtensions; 28338exports.startIdleTransaction = startIdleTransaction; 28339 28340 28341},{"../debug-build.js":245,"../hub.js":249,"../utils/spanUtils.js":297,"./errors.js":276,"./idletransaction.js":278,"./sampling.js":280,"./transaction.js":284,"@sentry/utils":319}],278:[function(require,module,exports){ 28342Object.defineProperty(exports, '__esModule', { value: true }); 28343 28344const utils = require('@sentry/utils'); 28345const debugBuild = require('../debug-build.js'); 28346const spanUtils = require('../utils/spanUtils.js'); 28347const span = require('./span.js'); 28348const transaction = require('./transaction.js'); 28349 28350const TRACING_DEFAULTS = { 28351 idleTimeout: 1000, 28352 finalTimeout: 30000, 28353 heartbeatInterval: 5000, 28354}; 28355 28356const FINISH_REASON_TAG = 'finishReason'; 28357 28358const IDLE_TRANSACTION_FINISH_REASONS = [ 28359 'heartbeatFailed', 28360 'idleTimeout', 28361 'documentHidden', 28362 'finalTimeout', 28363 'externalFinish', 28364 'cancelled', 28365]; 28366 28367/** 28368 * @inheritDoc 28369 */ 28370class IdleTransactionSpanRecorder extends span.SpanRecorder { 28371 constructor( 28372 _pushActivity, 28373 _popActivity, 28374 transactionSpanId, 28375 maxlen, 28376 ) { 28377 super(maxlen);this._pushActivity = _pushActivity;this._popActivity = _popActivity;this.transactionSpanId = transactionSpanId; } 28378 28379 /** 28380 * @inheritDoc 28381 */ 28382 add(span) { 28383 // We should make sure we do not push and pop activities for 28384 // the transaction that this span recorder belongs to. 28385 if (span.spanContext().spanId !== this.transactionSpanId) { 28386 // We patch span.end() to pop an activity after setting an endTimestamp.
28387 // eslint-disable-next-line @typescript-eslint/unbound-method 28388 const originalEnd = span.end; 28389 span.end = (...rest) => { 28390 this._popActivity(span.spanContext().spanId); 28391 return originalEnd.apply(span, rest); 28392 }; 28393 28394 // We should only push new activities if the span does not have an end timestamp. 28395 if (spanUtils.spanToJSON(span).timestamp === undefined) { 28396 this._pushActivity(span.spanContext().spanId); 28397 } 28398 } 28399 28400 super.add(span); 28401 } 28402} 28403 28404/** 28405 * An IdleTransaction is a transaction that automatically finishes. It does this by tracking child spans as activities. 28406 * You can have multiple IdleTransactions active, but if the `onScope` option is specified, the idle transaction will 28407 * put itself on the scope on creation. 28408 */ 28409class IdleTransaction extends transaction.Transaction { 28410 // Activities store a list of active spans 28411 28412 // Track state of activities in previous heartbeat 28413 28414 // Amount of times heartbeat has counted. Will cause transaction to finish after 3 beats. 28415 28416 // We should not use heartbeat if we finished a transaction 28417 28418 // Idle timeout was canceled and we should finish the transaction with the last span end. 28419 28420 /** 28421 * Timer that tracks Transaction idleTimeout 28422 */ 28423 28424 /** 28425 * @deprecated Transactions will be removed in v8. Use spans instead. 28426 */ 28427 constructor( 28428 transactionContext, 28429 _idleHub, 28430 /** 28431 * The time to wait in ms until the idle transaction will be finished. This timer is started each time 28432 * there are no active spans on this transaction. 28433 */ 28434 _idleTimeout = TRACING_DEFAULTS.idleTimeout, 28435 /** 28436 * The final value in ms that a transaction cannot exceed 28437 */ 28438 _finalTimeout = TRACING_DEFAULTS.finalTimeout, 28439 _heartbeatInterval = TRACING_DEFAULTS.heartbeatInterval, 28440 // Whether or not the transaction should put itself on the scope when it starts and pop itself off when it ends 28441 _onScope = false, 28442 /** 28443 * When set to `true`, will disable the idle timeout (`_idleTimeout` option) and heartbeat mechanisms (`_heartbeatInterval` 28444 * option) until the `sendAutoFinishSignal()` method is called. The final timeout mechanism (`_finalTimeout` option) 28445 * will not be affected by this option, meaning the transaction will definitely be finished when the final timeout is 28446 * reached, no matter what this option is configured to. 28447 * 28448 * Defaults to `false`. 28449 */ 28450 delayAutoFinishUntilSignal = false, 28451 ) { 28452 super(transactionContext, _idleHub);this._idleHub = _idleHub;this._idleTimeout = _idleTimeout;this._finalTimeout = _finalTimeout;this._heartbeatInterval = _heartbeatInterval;this._onScope = _onScope; 28453 this.activities = {}; 28454 this._heartbeatCounter = 0; 28455 this._finished = false; 28456 this._idleTimeoutCanceledPermanently = false; 28457 this._beforeFinishCallbacks = []; 28458 this._finishReason = IDLE_TRANSACTION_FINISH_REASONS[4]; 28459 this._autoFinishAllowed = !delayAutoFinishUntilSignal; 28460 28461 if (_onScope) { 28462 // We set the transaction here on the scope so error events pick up the trace 28463 // context and attach it to the error. 28464 debugBuild.DEBUG_BUILD && utils.logger.log(`Setting idle transaction on scope. Span ID: ${this.spanContext().spanId}`); 28465 // eslint-disable-next-line deprecation/deprecation 28466 _idleHub.getScope().setSpan(this); 28467 } 28468 28469 if (!delayAutoFinishUntilSignal) { 28470 this._restartIdleTimeout(); 28471 } 28472 28473 setTimeout(() => { 28474 if (!this._finished) { 28475 this.setStatus('deadline_exceeded'); 28476 this._finishReason = IDLE_TRANSACTION_FINISH_REASONS[3]; 28477 this.end(); 28478 } 28479 }, this._finalTimeout); 28480 } 28481 28482 /** {@inheritDoc} */ 28483 end(endTimestamp) { 28484 const endTimestampInS = spanUtils.spanTimeInputToSeconds(endTimestamp); 28485 28486 this._finished = true; 28487 this.activities = {}; 28488 28489 // eslint-disable-next-line deprecation/deprecation 28490 if (this.op === 'ui.action.click') { 28491 this.setAttribute(FINISH_REASON_TAG, this._finishReason); 28492 } 28493 28494 // eslint-disable-next-line deprecation/deprecation 28495 if (this.spanRecorder) { 28496 debugBuild.DEBUG_BUILD && 28497 // eslint-disable-next-line deprecation/deprecation 28498 utils.logger.log('[Tracing] finishing IdleTransaction', new Date(endTimestampInS * 1000).toISOString(), this.op); 28499 28500 for (const callback of this._beforeFinishCallbacks) { 28501 callback(this, endTimestampInS); 28502 } 28503 28504 // eslint-disable-next-line deprecation/deprecation 28505 this.spanRecorder.spans = this.spanRecorder.spans.filter((span) => { 28506 // If we are dealing with the transaction itself, we just return it 28507 if (span.spanContext().spanId === this.spanContext().spanId) { 28508 return true; 28509 } 28510 28511 // We cancel all pending spans with status "cancelled" to indicate the idle transaction was finished early 28512 if (!spanUtils.spanToJSON(span).timestamp) { 28513 span.setStatus('cancelled');
28514 span.end(endTimestampInS); 28515 debugBuild.DEBUG_BUILD && 28516 utils.logger.log('[Tracing] cancelling span since transaction ended early', JSON.stringify(span, undefined, 2)); 28517 } 28518 28519 const { start_timestamp: startTime, timestamp: endTime } = spanUtils.spanToJSON(span); 28520 const spanStartedBeforeTransactionFinish = startTime && startTime < endTimestampInS; 28521 28522 // Add a delta with idle timeout so that we prevent false positives 28523 const timeoutWithMarginOfError = (this._finalTimeout + this._idleTimeout) / 1000; 28524 const spanEndedBeforeFinalTimeout = endTime && startTime && endTime - startTime < timeoutWithMarginOfError; 28525 28526 if (debugBuild.DEBUG_BUILD) { 28527 const stringifiedSpan = JSON.stringify(span, undefined, 2); 28528 if (!spanStartedBeforeTransactionFinish) { 28529 utils.logger.log('[Tracing] discarding Span since it happened after Transaction was finished', stringifiedSpan); 28530 } else if (!spanEndedBeforeFinalTimeout) { 28531 utils.logger.log('[Tracing] discarding Span since it finished after Transaction final timeout', stringifiedSpan); 28532 } 28533 } 28534 28535 return spanStartedBeforeTransactionFinish && spanEndedBeforeFinalTimeout; 28536 }); 28537 28538 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] flushing IdleTransaction'); 28539 } else { 28540 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] No active IdleTransaction'); 28541 } 28542 28543 // if `this._onScope` is `true`, the transaction put itself on the scope when it started 28544 if (this._onScope) { 28545 // eslint-disable-next-line deprecation/deprecation 28546 const scope = this._idleHub.getScope(); 28547 // eslint-disable-next-line deprecation/deprecation 28548 if (scope.getTransaction() === this) { 28549 // eslint-disable-next-line deprecation/deprecation 28550 scope.setSpan(undefined); 28551 } 28552 } 28553 28554 return super.end(endTimestamp); 28555 } 28556 28557 /** 28558 * Register a callback function that gets executed before the transaction finishes. 28559 * Useful for cleanup or if you want to add any additional spans based on current context. 28560 * 28561 * This is exposed because users have no other way of running something before an idle transaction 28562 * finishes. 28563 */ 28564 registerBeforeFinishCallback(callback) { 28565 this._beforeFinishCallbacks.push(callback); 28566 } 28567 28568 /** 28569 * @inheritDoc 28570 */ 28571 initSpanRecorder(maxlen) { 28572 // eslint-disable-next-line deprecation/deprecation 28573 if (!this.spanRecorder) { 28574 const pushActivity = (id) => { 28575 if (this._finished) { 28576 return; 28577 } 28578 this._pushActivity(id); 28579 }; 28580 const popActivity = (id) => { 28581 if (this._finished) { 28582 return; 28583 } 28584 this._popActivity(id); 28585 }; 28586 28587 // eslint-disable-next-line deprecation/deprecation 28588 this.spanRecorder = new IdleTransactionSpanRecorder(pushActivity, popActivity, this.spanContext().spanId, maxlen); 28589 28590 // Start heartbeat so that transactions do not run forever. 28591 debugBuild.DEBUG_BUILD && utils.logger.log('Starting heartbeat'); 28592 this._pingHeartbeat(); 28593 } 28594 // eslint-disable-next-line deprecation/deprecation 28595 this.spanRecorder.add(this); 28596 } 28597 28598 /** 28599 * Cancels the existing idle timeout, if there is one. 28600 * @param restartOnChildSpanChange Default is `true`. 28601 * If set to false the transaction will end 28602 * with the last child span. 28603 */ 28604 cancelIdleTimeout( 28605 endTimestamp, 28606 { 28607 restartOnChildSpanChange, 28608 } 28609 28610 = { 28611 restartOnChildSpanChange: true, 28612 }, 28613 ) { 28614 this._idleTimeoutCanceledPermanently = restartOnChildSpanChange === false; 28615 if (this._idleTimeoutID) { 28616 clearTimeout(this._idleTimeoutID); 28617 this._idleTimeoutID = undefined; 28618 28619 if (Object.keys(this.activities).length === 0 && this._idleTimeoutCanceledPermanently) { 28620 this._finishReason = IDLE_TRANSACTION_FINISH_REASONS[5]; 28621 this.end(endTimestamp); 28622 } 28623 } 28624 } 28625 28626 /** 28627 * Temporary method used to externally set the transaction's `finishReason` 28628 * 28629 * ** WARNING** 28630 * This is for the purpose of experimentation only and will be removed in the near future, do not use! 28631 * 28632 * @internal 28633 * 28634 */ 28635 setFinishReason(reason) { 28636 this._finishReason = reason; 28637 } 28638 28639 /** 28640 * Permits the IdleTransaction to automatically end itself via the idle timeout and heartbeat mechanisms when the `delayAutoFinishUntilSignal` option was set to `true`. 28641 */ 28642 sendAutoFinishSignal() { 28643 if (!this._autoFinishAllowed) { 28644 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] Received finish signal for idle transaction.'); 28645 this._restartIdleTimeout(); 28646 this._autoFinishAllowed = true; 28647 } 28648 } 28649 28650 /** 28651 * Restarts idle timeout, if there is no running idle timeout it will start one. 28652 */ 28653 _restartIdleTimeout(endTimestamp) { 28654 this.cancelIdleTimeout(); 28655 this._idleTimeoutID = setTimeout(() => { 28656 if (!this._finished && Object.keys(this.activities).length === 0) { 28657 this._finishReason = IDLE_TRANSACTION_FINISH_REASONS[1]; 28658 this.end(endTimestamp); 28659 } 28660 }, this._idleTimeout); 28661 } 28662 28663 /** 28664 * Start tracking a specific activity. 28665 * @param spanId The span id that represents the activity 28666 */ 28667 _pushActivity(spanId) { 28668 this.cancelIdleTimeout(undefined, { restartOnChildSpanChange: !this._idleTimeoutCanceledPermanently }); 28669 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] pushActivity: ${spanId}`); 28670 this.activities[spanId] = true; 28671 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] new activities count', Object.keys(this.activities).length); 28672 } 28673 28674 /** 28675 * Remove an activity from usage 28676 * @param spanId The span id that represents the activity 28677 */ 28678 _popActivity(spanId) { 28679 if (this.activities[spanId]) { 28680 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] popActivity ${spanId}`); 28681 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 28682 delete this.activities[spanId]; 28683 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] new activities count', Object.keys(this.activities).length); 28684 } 28685 28686 if (Object.keys(this.activities).length === 0) { 28687 const endTimestamp = utils.timestampInSeconds(); 28688 if (this._idleTimeoutCanceledPermanently) { 28689 if (this._autoFinishAllowed) { 28690 this._finishReason = IDLE_TRANSACTION_FINISH_REASONS[5]; 28691 this.end(endTimestamp); 28692 } 28693 } else { 28694 // We need to add the timeout here to have the real endtimestamp of the transaction 28695 // Remember timestampInSeconds is in seconds, timeout is in ms 28696 this._restartIdleTimeout(endTimestamp + this._idleTimeout / 1000); 28697 } 28698 } 28699 } 28700 28701 /** 28702 * Checks when entries of this.activities are not changing for 3 beats. 28703 * If this occurs we finish the transaction. 28704 */ 28705 _beat() { 28706 // We should not be running heartbeat if the idle transaction is finished. 28707 if (this._finished) { 28708 return; 28709 } 28710 28711 const heartbeatString = Object.keys(this.activities).join(''); 28712 28713 if (heartbeatString === this._prevHeartbeatString) { 28714 this._heartbeatCounter++; 28715 } else { 28716 this._heartbeatCounter = 1; 28717 } 28718 28719 this._prevHeartbeatString = heartbeatString; 28720 28721 if (this._heartbeatCounter >= 3) { 28722 if (this._autoFinishAllowed) { 28723 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] Transaction finished because of no change for 3 heart beats'); 28724 this.setStatus('deadline_exceeded'); 28725 this._finishReason = IDLE_TRANSACTION_FINISH_REASONS[0]; 28726 this.end(); 28727 } 28728 } else { 28729 this._pingHeartbeat(); 28730 } 28731 } 28732 28733 /** 28734 * Pings the heartbeat 28735 */ 28736 _pingHeartbeat() { 28737 debugBuild.DEBUG_BUILD && utils.logger.log(`pinging Heartbeat -> current counter: ${this._heartbeatCounter}`); 28738 setTimeout(() => { 28739 this._beat(); 28740 }, this._heartbeatInterval); 28741 } 28742} 28743 28744exports.IdleTransaction = IdleTransaction; 28745exports.IdleTransactionSpanRecorder = IdleTransactionSpanRecorder; 28746exports.TRACING_DEFAULTS = TRACING_DEFAULTS; 28747 28748 28749},{"../debug-build.js":245,"../utils/spanUtils.js":297,"./span.js":281,"./transaction.js":284,"@sentry/utils":319}],279:[function(require,module,exports){ 28750Object.defineProperty(exports, '__esModule', { value: true }); 28751 28752const utils = require('./utils.js'); 28753 28754/** 28755 * Adds a measurement to the current active transaction. 28756 */ 28757function setMeasurement(name, value, unit) { 28758 // eslint-disable-next-line deprecation/deprecation 28759 const transaction = utils.getActiveTransaction(); 28760 if (transaction) { 28761 // eslint-disable-next-line deprecation/deprecation 28762 transaction.setMeasurement(name, value, unit); 28763 } 28764} 28765 28766exports.setMeasurement = setMeasurement; 28767 28768 28769},{"./utils.js":285}],280:[function(require,module,exports){ 28770Object.defineProperty(exports, '__esModule', { value: true }); 28771 28772const utils = require('@sentry/utils'); 28773const debugBuild = require('../debug-build.js'); 28774const semanticAttributes = require('../semanticAttributes.js'); 28775const hasTracingEnabled = require('../utils/hasTracingEnabled.js'); 28776const spanUtils = require('../utils/spanUtils.js'); 28777 28778/** 28779 * Makes a sampling decision for the given transaction and stores it on the transaction. 28780 * 28781 * Called every time a transaction is created. Only transactions which emerge with a `sampled` value of `true` will be 28782 * sent to Sentry. 28783 * 28784 * This method muttes the given `transaction` and will set the `sampled` value on it. 28785 * It returns the same transaction, for convenience. 28786 */ 28787function sampleTransaction( 28788 transaction, 28789 options, 28790 samplingContext, 28791) { 28792 // nothing to do if tracing is not enabled 28793 if (!hasTracingEnabled.hasTracingEnabled(options)) { 28794 // eslint-disable-next-line deprecation/deprecation 28795 transaction.sampled = false;
28796 return transaction; 28797 } 28798 28799 // if the user has forced a sampling decision by passing a `sampled` value in their transaction context, go with that 28800 // eslint-disable-next-line deprecation/deprecation 28801 if (transaction.sampled !== undefined) { 28802 // eslint-disable-next-line deprecation/deprecation 28803 transaction.setAttribute(semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(transaction.sampled)); 28804 return transaction; 28805 } 28806 28807 // we would have bailed already if neither `tracesSampler` nor `tracesSampleRate` nor `enableTracing` were defined, so one of these should 28808 // work; prefer the hook if so 28809 let sampleRate; 28810 if (typeof options.tracesSampler === 'function') { 28811 sampleRate = options.tracesSampler(samplingContext); 28812 transaction.setAttribute(semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(sampleRate)); 28813 } else if (samplingContext.parentSampled !== undefined) { 28814 sampleRate = samplingContext.parentSampled; 28815 } else if (typeof options.tracesSampleRate !== 'undefined') { 28816 sampleRate = options.tracesSampleRate; 28817 transaction.setAttribute(semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(sampleRate)); 28818 } else { 28819 // When `enableTracing === true`, we use a sample rate of 100% 28820 sampleRate = 1; 28821 transaction.setAttribute(semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, sampleRate); 28822 } 28823 28824 // Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The 28825 // only valid values are booleans or numbers between 0 and 1.) 28826 if (!isValidSampleRate(sampleRate)) { 28827 debugBuild.DEBUG_BUILD && utils.logger.warn('[Tracing] Discarding transaction because of invalid sample rate.'); 28828 // eslint-disable-next-line deprecation/deprecation 28829 transaction.sampled = false; 28830 return transaction; 28831 } 28832 28833 // if the function returned 0 (or false), or if `tracesSampleRate` is 0, it's a sign the transaction should be dropped 28834 if (!sampleRate) { 28835 debugBuild.DEBUG_BUILD && 28836 utils.logger.log( 28837 `[Tracing] Discarding transaction because ${ 28838 typeof options.tracesSampler === 'function' 28839 ? 'tracesSampler returned 0 or false' 28840 : 'a negative sampling decision was inherited or tracesSampleRate is set to 0' 28841 }`, 28842 ); 28843 // eslint-disable-next-line deprecation/deprecation 28844 transaction.sampled = false; 28845 return transaction; 28846 } 28847 28848 // Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is 28849 // a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false. 28850 // eslint-disable-next-line deprecation/deprecation 28851 transaction.sampled = Math.random() < (sampleRate ); 28852 28853 // if we're not going to keep it, we're done 28854 // eslint-disable-next-line deprecation/deprecation 28855 if (!transaction.sampled) { 28856 debugBuild.DEBUG_BUILD && 28857 utils.logger.log( 28858 `[Tracing] Discarding transaction because it's not included in the random sample (sampling rate = ${Number( 28859 sampleRate, 28860 )})`, 28861 ); 28862 return transaction; 28863 } 28864 28865 debugBuild.DEBUG_BUILD && 28866 // eslint-disable-next-line deprecation/deprecation 28867 utils.logger.log(`[Tracing] starting ${transaction.op} transaction - ${spanUtils.spanToJSON(transaction).description}`); 28868 return transaction; 28869} 28870 28871/** 28872 * Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1). 28873 */ 28874function isValidSampleRate(rate) { 28875 // we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck 28876 // eslint-disable-next-line @typescript-eslint/no-explicit-any 28877 if (utils.isNaN(rate) || !(typeof rate === 'number' || typeof rate === 'boolean')) { 28878 debugBuild.DEBUG_BUILD && 28879 utils.logger.warn( 28880 `[Tracing] Given sample rate is invalid. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify( 28881 rate, 28882 )} of type ${JSON.stringify(typeof rate)}.`, 28883 ); 28884 return false; 28885 } 28886 28887 // in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false 28888 if (rate < 0 || rate > 1) { 28889 debugBuild.DEBUG_BUILD &&
28890 utils.logger.warn(`[Tracing] Given sample rate is invalid. Sample rate must be between 0 and 1. Got ${rate}.`); 28891 return false; 28892 } 28893 return true; 28894} 28895 28896exports.isValidSampleRate = isValidSampleRate; 28897exports.sampleTransaction = sampleTransaction; 28898 28899 28900},{"../debug-build.js":245,"../semanticAttributes.js":270,"../utils/hasTracingEnabled.js":292,"../utils/spanUtils.js":297,"@sentry/utils":319}],281:[function(require,module,exports){ 28901Object.defineProperty(exports, '__esModule', { value: true }); 28902 28903const utils = require('@sentry/utils'); 28904const debugBuild = require('../debug-build.js'); 28905const metricSummary = require('../metrics/metric-summary.js'); 28906const semanticAttributes = require('../semanticAttributes.js'); 28907const getRootSpan = require('../utils/getRootSpan.js'); 28908const spanUtils = require('../utils/spanUtils.js'); 28909const spanstatus = require('./spanstatus.js'); 28910 28911/** 28912 * Keeps track of finished spans for a given transaction 28913 * @internal 28914 * @hideconstructor 28915 * @hidden 28916 */ 28917class SpanRecorder { 28918 28919 constructor(maxlen = 1000) { 28920 this._maxlen = maxlen; 28921 this.spans = []; 28922 } 28923 28924 /** 28925 * This is just so that we don't run out of memory while recording a lot 28926 * of spans. At some point we just stop and flush out the start of the 28927 * trace tree (i.e.the first n spans with the smallest 28928 * start_timestamp). 28929 */ 28930 add(span) { 28931 if (this.spans.length > this._maxlen) { 28932 // eslint-disable-next-line deprecation/deprecation 28933 span.spanRecorder = undefined; 28934 } else { 28935 this.spans.push(span); 28936 } 28937 } 28938} 28939 28940/** 28941 * Span contains all data about a span 28942 */ 28943class Span { 28944 /** 28945 * Tags for the span. 28946 * @deprecated Use `spanToJSON(span).atttributes` instead. 28947 */ 28948 28949 /** 28950 * Data for the span. 28951 * @deprecated Use `spanToJSON(span).atttributes` instead. 28952 */ 28953 // eslint-disable-next-line @typescript-eslint/no-explicit-any 28954 28955 /** 28956 * List of spans that were finalized 28957 * 28958 * @deprecated This property will no longer be public. Span recording will be handled internally. 28959 */ 28960 28961 /** 28962 * @inheritDoc 28963 * @deprecated Use top level `Sentry.getRootSpan()` instead 28964 */ 28965 28966 /** 28967 * The instrumenter that created this span. 28968 * 28969 * TODO (v8): This can probably be replaced by an `instanceOf` check of the span class. 28970 * the instrumenter can only be sentry or otel so we can check the span instance 28971 * to verify which one it is and remove this field entirely. 28972 * 28973 * @deprecated This field will be removed. 28974 */ 28975 28976 /** Epoch timestamp in seconds when the span started. */ 28977 28978 /** Epoch timestamp in seconds when the span ended. */ 28979 28980 /** Internal keeper of the status */ 28981 28982 /** 28983 * You should never call the constructor manually, always use `Sentry.startTransaction()` 28984 * or call `startChild()` on an existing span. 28985 * @internal 28986 * @hideconstructor 28987 * @hidden 28988 */ 28989 constructor(spanContext = {}) { 28990 this._traceId = spanContext.traceId || utils.uuid4(); 28991 this._spanId = spanContext.spanId || utils.uuid4().substring(16); 28992 this._startTime = spanContext.startTimestamp || utils.timestampInSeconds(); 28993 // eslint-disable-next-line deprecation/deprecation 28994 this.tags = spanContext.tags ? { ...spanContext.tags } : {}; 28995 // eslint-disable-next-line deprecation/deprecation 28996 this.data = spanContext.data ? { ...spanContext.data } : {}; 28997 // eslint-disable-next-line deprecation/deprecation 28998 this.instrumenter = spanContext.instrumenter || 'sentry'; 28999 29000 this._attributes = {}; 29001 this.setAttributes({ 29002 [semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanContext.origin || 'manual', 29003 [semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_OP]: spanContext.op, 29004 ...spanContext.attributes, 29005 }); 29006 29007 // eslint-disable-next-line deprecation/deprecation 29008 this._name = spanContext.name || spanContext.description; 29009 29010 if (spanContext.parentSpanId) { 29011 this._parentSpanId = spanContext.parentSpanId; 29012 } 29013 // We want to include booleans as well here 29014 if ('sampled' in spanContext) { 29015 this._sampled = spanContext.sampled; 29016 } 29017 if (spanContext.status) { 29018 this._status = spanContext.status; 29019 } 29020 if (spanContext.endTimestamp) { 29021 this._endTime = spanContext.endTimestamp; 29022 } 29023 if (spanContext.exclusiveTime) { 29024 this._exclusiveTime = spanContext.exclusiveTime; 29025 } 29026 this._measurements = spanContext.measurements ? { ...spanContext.measurements } : {}; 29027 } 29028 29029 // This rule conflicts with another eslint rule :( 29030 /* eslint-disable @typescript-eslint/member-ordering */ 29031 29032 /** 29033 * An alias for `description` of the Span. 29034 * @deprecated Use `spanToJSON(span).description` instead. 29035 */ 29036 get name() { 29037 return this._name || ''; 29038 } 29039 29040 /** 29041 * Update the name of the span. 29042 * @deprecated Use `spanToJSON(span).description` instead. 29043 */ 29044 set name(name) { 29045 this.updateName(name); 29046 } 29047 29048 /** 29049 * Get the description of the Span. 29050 * @deprecated Use `spanToJSON(span).description` instead. 29051 */ 29052 get description() { 29053 return this._name; 29054 } 29055 29056 /** 29057 * Get the description of the Span. 29058 * @deprecated Use `spanToJSON(span).description` instead. 29059 */ 29060 set description(description) { 29061 this._name = description; 29062 } 29063 29064 /** 29065 * The ID of the trace. 29066 * @deprecated Use `spanContext().traceId` instead. 29067 */ 29068 get traceId() { 29069 return this._traceId; 29070 } 29071 29072 /** 29073 * The ID of the trace. 29074 * @deprecated You cannot update the traceId of a span after span creation. 29075 */ 29076 set traceId(traceId) { 29077 this._traceId = traceId; 29078 } 29079 29080 /** 29081 * The ID of the span. 29082 * @deprecated Use `spanContext().spanId` instead. 29083 */ 29084 get spanId() { 29085 return this._spanId; 29086 } 29087 29088 /** 29089 * The ID of the span. 29090 * @deprecated You cannot update the spanId of a span after span creation. 29091 */ 29092 set spanId(spanId) { 29093 this._spanId = spanId; 29094 } 29095 29096 /** 29097 * @inheritDoc 29098 * 29099 * @deprecated Use `startSpan` functions instead. 29100 */ 29101 set parentSpanId(string) { 29102 this._parentSpanId = string; 29103 } 29104 29105 /** 29106 * @inheritDoc 29107 * 29108 * @deprecated Use `spanToJSON(span).parent_span_id` instead. 29109 */ 29110 get parentSpanId() { 29111 return this._parentSpanId; 29112 } 29113 29114 /** 29115 * Was this span chosen to be sent as part of the sample? 29116 * @deprecated Use `isRecording()` instead. 29117 */ 29118 get sampled() { 29119 return this._sampled; 29120 } 29121 29122 /** 29123 * Was this span chosen to be sent as part of the sample? 29124 * @deprecated You cannot update the sampling decision of a span after span creation. 29125 */ 29126 set sampled(sampled) { 29127 this._sampled = sampled; 29128 } 29129 29130 /** 29131 * Attributes for the span. 29132 * @deprecated Use `spanToJSON(span).atttributes` instead. 29133 */ 29134 get attributes() { 29135 return this._attributes; 29136 } 29137 29138 /** 29139 * Attributes for the span. 29140 * @deprecated Use `setAttributes()` instead. 29141 */ 29142 set attributes(attributes) { 29143 this._attributes = attributes; 29144 } 29145 29146 /** 29147 * Timestamp in seconds (epoch time) indicating when the span started. 29148 * @deprecated Use `spanToJSON()` instead. 29149 */ 29150 get startTimestamp() { 29151 return this._startTime; 29152 } 29153 29154 /** 29155 * Timestamp in seconds (epoch time) indicating when the span started. 29156 * @deprecated In v8, you will not be able to update the span start time after creation. 29157 */ 29158 set startTimestamp(startTime) { 29159 this._startTime = startTime; 29160 } 29161 29162 /** 29163 * Timestamp in seconds when the span ended. 29164 * @deprecated Use `spanToJSON()` instead. 29165 */ 29166 get endTimestamp() { 29167 return this._endTime; 29168 } 29169 29170 /** 29171 * Timestamp in seconds when the span ended. 29172 * @deprecated Set the end time via `span.end()` instead. 29173 */ 29174 set endTimestamp(endTime) { 29175 this._endTime = endTime; 29176 } 29177 29178 /** 29179 * The status of the span. 29180 * 29181 * @deprecated Use `spanToJSON().status` instead to get the status. 29182 */ 29183 get status() { 29184 return this._status; 29185 } 29186 29187 /** 29188 * The status of the span. 29189 * 29190 * @deprecated Use `.setStatus()` instead to set or update the status. 29191 */ 29192 set status(status) { 29193 this._status = status; 29194 } 29195 29196 /** 29197 * Operation of the span 29198 * 29199 * @deprecated Use `spanToJSON().op` to read the op instead. 29200 */ 29201 get op() { 29202 return this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_OP] ; 29203 } 29204 29205 /** 29206 * Operation of the span 29207 * 29208 * @deprecated Use `startSpan()` functions to set or `span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'op') 29209 * to update the span instead. 29210 */ 29211 set op(op) { 29212 this.setAttribute(semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_OP, op); 29213 } 29214 29215 /** 29216 * The origin of the span, giving context about what created the span. 29217 *
29218 * @deprecated Use `spanToJSON().origin` to read the origin instead. 29219 */ 29220 get origin() { 29221 return this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] ; 29222 } 29223 29224 /** 29225 * The origin of the span, giving context about what created the span. 29226 * 29227 * @deprecated Use `startSpan()` functions to set the origin instead. 29228 */ 29229 set origin(origin) { 29230 this.setAttribute(semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, origin); 29231 } 29232 29233 /* eslint-enable @typescript-eslint/member-ordering */ 29234 29235 /** @inheritdoc */ 29236 spanContext() { 29237 const { _spanId: spanId, _traceId: traceId, _sampled: sampled } = this; 29238 return { 29239 spanId, 29240 traceId, 29241 traceFlags: sampled ? spanUtils.TRACE_FLAG_SAMPLED : spanUtils.TRACE_FLAG_NONE, 29242 }; 29243 } 29244 29245 /** 29246 * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`. 29247 * Also the `sampled` decision will be inherited. 29248 * 29249 * @deprecated Use `startSpan()`, `startSpanManual()` or `startInactiveSpan()` instead. 29250 */ 29251 startChild( 29252 spanContext, 29253 ) { 29254 const childSpan = new Span({ 29255 ...spanContext, 29256 parentSpanId: this._spanId, 29257 sampled: this._sampled, 29258 traceId: this._traceId, 29259 }); 29260 29261 // eslint-disable-next-line deprecation/deprecation 29262 childSpan.spanRecorder = this.spanRecorder; 29263 // eslint-disable-next-line deprecation/deprecation 29264 if (childSpan.spanRecorder) { 29265 // eslint-disable-next-line deprecation/deprecation 29266 childSpan.spanRecorder.add(childSpan); 29267 } 29268 29269 const rootSpan = getRootSpan.getRootSpan(this); 29270 // TODO: still set span.transaction here until we have a more permanent solution 29271 // Probably similarly to the weakmap we hold in node-experimental 29272 // eslint-disable-next-line deprecation/deprecation 29273 childSpan.transaction = rootSpan ; 29274 29275 if (debugBuild.DEBUG_BUILD && rootSpan) { 29276 const opStr = (spanContext && spanContext.op) || '< unknown op >'; 29277 const nameStr = spanUtils.spanToJSON(childSpan).description || '< unknown name >'; 29278 const idStr = rootSpan.spanContext().spanId; 29279 29280 const logMessage = `[Tracing] Starting '${opStr}' span on transaction '${nameStr}' (${idStr}).`; 29281 utils.logger.log(logMessage); 29282 this._logMessage = logMessage; 29283 } 29284 29285 return childSpan; 29286 } 29287 29288 /** 29289 * Sets the tag attribute on the current span. 29290 * 29291 * Can also be used to unset a tag, by passing `undefined`. 29292 * 29293 * @param key Tag key 29294 * @param value Tag value 29295 * @deprecated Use `setAttribute()` instead. 29296 */ 29297 setTag(key, value) { 29298 // eslint-disable-next-line deprecation/deprecation 29299 this.tags = { ...this.tags, [key]: value }; 29300 return this; 29301 } 29302 29303 /** 29304 * Sets the data attribute on the current span 29305 * @param key Data key 29306 * @param value Data value 29307 * @deprecated Use `setAttribute()` instead. 29308 */ 29309 // eslint-disable-next-line @typescript-eslint/no-explicit-any 29310 setData(key, value) { 29311 // eslint-disable-next-line deprecation/deprecation 29312 this.data = { ...this.data, [key]: value }; 29313 return this; 29314 } 29315 29316 /** @inheritdoc */ 29317 setAttribute(key, value) { 29318 if (value === undefined) { 29319 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 29320 delete this._attributes[key]; 29321 } else { 29322 this._attributes[key] = value; 29323 } 29324 } 29325 29326 /** @inheritdoc */ 29327 setAttributes(attributes) { 29328 Object.keys(attributes).forEach(key => this.setAttribute(key, attributes[key])); 29329 } 29330 29331 /** 29332 * @inheritDoc 29333 */ 29334 setStatus(value) { 29335 this._status = value; 29336 return this; 29337 } 29338 29339 /** 29340 * @inheritDoc 29341 * @deprecated Use top-level `setHttpStatus()` instead. 29342 */ 29343 setHttpStatus(httpStatus) { 29344 spanstatus.setHttpStatus(this, httpStatus); 29345 return this; 29346 } 29347 29348 /** 29349 * @inheritdoc 29350 * 29351 * @deprecated Use `.updateName()` instead. 29352 */ 29353 setName(name) { 29354 this.updateName(name); 29355 } 29356 29357 /** 29358 * @inheritDoc 29359 */ 29360 updateName(name) { 29361 this._name = name; 29362 return this; 29363 } 29364 29365 /** 29366 * @inheritDoc 29367 * 29368 * @deprecated Use `spanToJSON(span).status === 'ok'` instead. 29369 */ 29370 isSuccess() { 29371 return this._status === 'ok'; 29372 } 29373 29374 /** 29375 * @inheritDoc 29376 * 29377 * @deprecated Use `.end()` instead. 29378 */ 29379 finish(endTimestamp) { 29380 return this.end(endTimestamp); 29381 } 29382 29383 /** @inheritdoc */ 29384 end(endTimestamp) { 29385 // If already ended, skip 29386 if (this._endTime) { 29387 return; 29388 } 29389 const rootSpan = getRootSpan.getRootSpan(this); 29390 if ( 29391 debugBuild.DEBUG_BUILD && 29392 // Don't call this for transactions 29393 rootSpan && 29394 rootSpan.spanContext().spanId !== this._spanId 29395 ) { 29396 const logMessage = this._logMessage; 29397 if (logMessage) { 29398 utils.logger.log((logMessage ).replace('Starting', 'Finis
29398hing')); 29399 } 29400 } 29401 29402 this._endTime = spanUtils.spanTimeInputToSeconds(endTimestamp); 29403 } 29404 29405 /** 29406 * @inheritDoc 29407 * 29408 * @deprecated Use `spanToTraceHeader()` instead. 29409 */ 29410 toTraceparent() { 29411 return spanUtils.spanToTraceHeader(this); 29412 } 29413 29414 /** 29415 * @inheritDoc 29416 * 29417 * @deprecated Use `spanToJSON()` or access the fields directly instead. 29418 */ 29419 toContext() { 29420 return utils.dropUndefinedKeys({ 29421 data: this._getData(), 29422 description: this._name, 29423 endTimestamp: this._endTime, 29424 // eslint-disable-next-line deprecation/deprecation 29425 op: this.op, 29426 parentSpanId: this._parentSpanId, 29427 sampled: this._sampled, 29428 spanId: this._spanId, 29429 startTimestamp: this._startTime, 29430 status: this._status, 29431 // eslint-disable-next-line deprecation/deprecation 29432 tags: this.tags, 29433 traceId: this._traceId, 29434 }); 29435 } 29436 29437 /** 29438 * @inheritDoc 29439 * 29440 * @deprecated Update the fields directly instead. 29441 */ 29442 updateWithContext(spanContext) { 29443 // eslint-disable-next-line deprecation/deprecation 29444 this.data = spanContext.data || {}; 29445 // eslint-disable-next-line deprecation/deprecation 29446 this._name = spanContext.name || spanContext.description; 29447 this._endTime = spanContext.endTimestamp; 29448 // eslint-disable-next-line deprecation/deprecation 29449 this.op = spanContext.op; 29450 this._parentSpanId = spanContext.parentSpanId; 29451 this._sampled = spanContext.sampled; 29452 this._spanId = spanContext.spanId || this._spanId; 29453 this._startTime = spanContext.startTimestamp || this._startTime; 29454 this._status = spanContext.status; 29455 // eslint-disable-next-line deprecation/deprecation 29456 this.tags = spanContext.tags || {}; 29457 this._traceId = spanContext.traceId || this._traceId; 29458 29459 return this; 29460 } 29461 29462 /** 29463 * @inheritDoc 29464 * 29465 * @deprecated Use `spanToTraceContext()` util function instead. 29466 */ 29467 getTraceContext() { 29468 return spanUtils.spanToTraceContext(this); 29469 } 29470 29471 /** 29472 * Get JSON representation of this span. 29473 * 29474 * @hidden 29475 * @internal This method is purely for internal purposes and should not be used outside 29476 * of SDK code. If you need to get a JSON representation of a span, 29477 * use `spanToJSON(span)` instead. 29478 */ 29479 getSpanJSON() { 29480 return utils.dropUndefinedKeys({ 29481 data: this._getData(), 29482 description: this._name, 29483 op: this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_OP] , 29484 parent_span_id: this._parentSpanId, 29485 span_id: this._spanId, 29486 start_timestamp: this._startTime, 29487 status: this._status, 29488 // eslint-disable-next-line deprecation/deprecation 29489 tags: Object.keys(this.tags).length > 0 ? this.tags : undefined, 29490 timestamp: this._endTime, 29491 trace_id: this._traceId, 29492 origin: this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] , 29493 _metrics_summary: metricSummary.getMetricSummaryJsonForSpan(this), 29494 profile_id: this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_PROFILE_ID] , 29495 exclusive_time: this._exclusiveTime, 29496 measurements: Object.keys(this._measurements).length > 0 ? this._measurements : undefined, 29497 }); 29498 } 29499 29500 /** @inheritdoc */ 29501 isRecording() { 29502 return !this._endTime && !!this._sampled; 29503 } 29504 29505 /** 29506 * Convert the object to JSON. 29507 * @deprecated Use `spanToJSON(span)` instead. 29508 */ 29509 toJSON() { 29510 return this.getSpanJSON(); 29511 } 29512 29513 /** 29514 * Get the merged data for this span. 29515 * For now, this combines `data` and `attributes` together, 29516 * until eventually we can ingest `attributes` directly. 29517 */ 29518 _getData() 29519 29520 { 29521 // eslint-disable-next-line deprecation/deprecation 29522 const { data, _attributes: attributes } = this; 29523 29524 const hasData = Object.keys(data).length > 0; 29525 const hasAttributes = Object.keys(attributes).length > 0; 29526 29527 if (!hasData && !hasAttributes) { 29528 return undefined; 29529 } 29530 29531 if (hasData && hasAttributes) { 29532 return { 29533 ...data, 29534 ...attributes, 29535 }; 29536 } 29537 29538 return hasData ? data : attributes; 29539 } 29540} 29541 29542exports.Span = Span; 29543exports.SpanRecorder = SpanRecorder; 29544 29545 29546},{"../debug-build.js":245,"../metrics/metric-summary.js":266,"../semanticAttributes.js":270,"../utils/getRootSpan.js":290,"../utils/spanUtils.js":297,"./spanstatus.js":282,"@sentry/utils":319}],282:[function(require,module,exports){ 29547Object.defineProperty(exports, '__esModule', { value: true }); 29548 29549/** The status of an Span. 29550 * 29551 * @deprecated Use string literals - if you require type casting, cast to SpanStatusType type 29552 */ 29553exports.SpanStatus = void 0; (function (SpanStatus) { 29554 /** The operation completed successfully. */ 29555 const Ok = 'ok'; SpanStatus["Ok"] = Ok; 29556 /** Deadline expired before operation could complete. */ 29557 const DeadlineExceeded = 'deadline_exceeded'; SpanStatus["DeadlineExceeded"] = DeadlineExceeded; 29558 /** 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) */ 29559 const Unauthenticated = 'unauthenticated'; SpanStatus["Unauthenticated"] = Unauthenticated; 29560 /** 403 Forbidden */ 29561 const PermissionDenied = 'permission_denied'; SpanStatus["PermissionDenied"] = PermissionDenied; 29562 /** 404 Not Found. Some requested entity (file or directory) was not found. */ 29563 const NotFound = 'not_found'; SpanStatus["NotFound"] = NotFound; 29564 /** 429 Too Many Requests */ 29565 const ResourceExhausted = 'resource_exhausted'; SpanStatus["ResourceExhausted"] = ResourceExhausted;
29566 /** Client specified an invalid argument. 4xx. */ 29567 const InvalidArgument = 'invalid_argument'; SpanStatus["InvalidArgument"] = InvalidArgument; 29568 /** 501 Not Implemented */ 29569 const Unimplemented = 'unimplemented'; SpanStatus["Unimplemented"] = Unimplemented; 29570 /** 503 Service Unavailable */ 29571 const Unavailable = 'unavailable'; SpanStatus["Unavailable"] = Unavailable; 29572 /** Other/generic 5xx. */ 29573 const InternalError = 'internal_error'; SpanStatus["InternalError"] = InternalError; 29574 /** Unknown. Any non-standard HTTP status code. */ 29575 const UnknownError = 'unknown_error'; SpanStatus["UnknownError"] = UnknownError; 29576 /** The operation was cancelled (typically by the user). */ 29577 const Cancelled = 'cancelled'; SpanStatus["Cancelled"] = Cancelled; 29578 /** Already exists (409) */ 29579 const AlreadyExists = 'already_exists'; SpanStatus["AlreadyExists"] = AlreadyExists; 29580 /** Operation was rejected because the system is not in a state required for the operation's */ 29581 const FailedPrecondition = 'failed_precondition'; SpanStatus["FailedPrecondition"] = FailedPrecondition; 29582 /** The operation was aborted, typically due to a concurrency issue. */ 29583 const Aborted = 'aborted'; SpanStatus["Aborted"] = Aborted; 29584 /** Operation was attempted past the valid range. */ 29585 const OutOfRange = 'out_of_range'; SpanStatus["OutOfRange"] = OutOfRange; 29586 /** Unrecoverable data loss or corruption */ 29587 const DataLoss = 'data_loss'; SpanStatus["DataLoss"] = DataLoss; 29588})(exports.SpanStatus || (exports.SpanStatus = {})); 29589 29590/** 29591 * Converts a HTTP status code into a {@link SpanStatusType}. 29592 * 29593 * @param httpStatus The HTTP response status code. 29594 * @returns The span status or unknown_error. 29595 */ 29596function getSpanStatusFromHttpCode(httpStatus) { 29597 if (httpStatus < 400 && httpStatus >= 100) { 29598 return 'ok'; 29599 } 29600 29601 if (httpStatus >= 400 && httpStatus < 500) { 29602 switch (httpStatus) { 29603 case 401: 29604 return 'unauthenticated'; 29605 case 403: 29606 return 'permission_denied'; 29607 case 404: 29608 return 'not_found'; 29609 case 409: 29610 return 'already_exists'; 29611 case 413: 29612 return 'failed_precondition'; 29613 case 429: 29614 return 'resource_exhausted'; 29615 default: 29616 return 'invalid_argument'; 29617 } 29618 } 29619 29620 if (httpStatus >= 500 && httpStatus < 600) { 29621 switch (httpStatus) { 29622 case 501: 29623 return 'unimplemented'; 29624 case 503: 29625 return 'unavailable'; 29626 case 504: 29627 return 'deadline_exceeded'; 29628 default: 29629 return 'internal_error'; 29630 } 29631 } 29632 29633 return 'unknown_error'; 29634} 29635 29636/** 29637 * Converts a HTTP status code into a {@link SpanStatusType}. 29638 * 29639 * @deprecated Use {@link spanStatusFromHttpCode} instead. 29640 * This export will be removed in v8 as the signature contains a typo. 29641 * 29642 * @param httpStatus The HTTP response status code. 29643 * @returns The span status or unknown_error. 29644 */ 29645const spanStatusfromHttpCode = getSpanStatusFromHttpCode; 29646 29647/** 29648 * Sets the Http status attributes on the current span based on the http code. 29649 * Additionally, the span's status is updated, depending on the http code. 29650 */ 29651function setHttpStatus(span, httpStatus) { 29652 // TODO (v8): Remove these calls 29653 // Relay does not require us to send the status code as a tag 29654 // For now, just because users might expect it to land as a tag we keep sending it. 29655 // Same with data. 29656 // In v8, we replace both, simply with 29657 // span.setAttribute('http.response.status_code', httpStatus); 29658 29659 // eslint-disable-next-line deprecation/deprecation 29660 span.setTag('http.status_code', String(httpStatus)); 29661 // eslint-disable-next-line deprecation/deprecation 29662 span.setData('http.response.status_code', httpStatus); 29663 29664 const spanStatus = getSpanStatusFromHttpCode(httpStatus); 29665 if (spanStatus !== 'unknown_error') { 29666 span.setStatus(spanStatus); 29667 } 29668} 29669 29670exports.getSpanStatusFromHttpCode = getSpanStatusFromHttpCode; 29671exports.setHttpStatus = setHttpStatus; 29672exports.spanStatusfromHttpCode = spanStatusfromHttpCode; 29673 29674 29675},{}],283:[function(require,module,exports){ 29676Object.defineProperty(exports, '__esModule', { value: true }); 29677 29678const utils = require('@sentry/utils'); 29679const debugBuild = require('../debug-build.js'); 29680const hub = require('../hub.js'); 29681const spanUtils = require('../utils/spanUtils.js'); 29682require('./errors.js'); 29683require('./spanstatus.js'); 29684const dynamicSamplingContext = require('./dynamicSamplingContext.js'); 29685const exports$1 = require('../exports.js'); 29686const handleCallbackErrors = require('../utils/handleCallbackErrors.js'); 29687const hasTracingEnabled = require('../utils/hasTracingEnabled.js'); 29688 29689/** 29690 * Wraps a function with a transaction/span and finishes the span after the function is done. 29691 *
29692 * Note that if you have not enabled tracing extensions via `addTracingExtensions` 29693 * or you didn't set `tracesSampleRate`, this function will not generate spans 29694 * and the `span` returned from the callback will be undefined. 29695 * 29696 * This function is meant to be used internally and may break at any time. Use at your own risk. 29697 * 29698 * @internal 29699 * @private 29700 * 29701 * @deprecated Use `startSpan` instead. 29702 */ 29703function trace( 29704 context, 29705 callback, 29706 // eslint-disable-next-line @typescript-eslint/no-empty-function 29707 onError = () => {}, 29708 // eslint-disable-next-line @typescript-eslint/no-empty-function 29709 afterFinish = () => {}, 29710) { 29711 // eslint-disable-next-line deprecation/deprecation 29712 const hub$1 = hub.getCurrentHub(); 29713 const scope = exports$1.getCurrentScope(); 29714 // eslint-disable-next-line deprecation/deprecation 29715 const parentSpan = scope.getSpan(); 29716 29717 const spanContext = normalizeContext(context); 29718 const activeSpan = createChildSpanOrTransaction(hub$1, { 29719 parentSpan, 29720 spanContext, 29721 forceTransaction: false, 29722 scope, 29723 }); 29724 29725 // eslint-disable-next-line deprecation/deprecation 29726 scope.setSpan(activeSpan); 29727 29728 return handleCallbackErrors.handleCallbackErrors( 29729 () => callback(activeSpan), 29730 error => { 29731 activeSpan && activeSpan.setStatus('internal_error'); 29732 onError(error, activeSpan); 29733 }, 29734 () => { 29735 activeSpan && activeSpan.end(); 29736 // eslint-disable-next-line deprecation/deprecation 29737 scope.setSpan(parentSpan); 29738 afterFinish(); 29739 }, 29740 ); 29741} 29742 29743/** 29744 * Wraps a function with a transaction/span and finishes the span after the function is done. 29745 * The created span is the active span and will be used as parent by other spans created inside the function 29746 * and can be accessed via `Sentry.getSpan()`, as long as the function is executed while the scope is active. 29747 * 29748 * If you want to create a span that is not set as active, use {@link startInactiveSpan}. 29749 * 29750 * Note that if you have not enabled tracing extensions via `addTracingExtensions` 29751 * or you didn't set `tracesSampleRate`, this function will not generate spans 29752 * and the `span` returned from the callback will be undefined. 29753 */ 29754function startSpan(context, callback) { 29755 const spanContext = normalizeContext(context); 29756 29757 return hub.runWithAsyncContext(() => { 29758 return exports$1.withScope(context.scope, scope => { 29759 // eslint-disable-next-line deprecation/deprecation 29760 const hub$1 = hub.getCurrentHub(); 29761 // eslint-disable-next-line deprecation/deprecation 29762 const parentSpan = scope.getSpan(); 29763 29764 const shouldSkipSpan = context.onlyIfParent && !parentSpan; 29765 const activeSpan = shouldSkipSpan 29766 ? undefined 29767 : createChildSpanOrTransaction(hub$1, { 29768 parentSpan, 29769 spanContext, 29770 forceTransaction: context.forceTransaction, 29771 scope, 29772 }); 29773 29774 return handleCallbackErrors.handleCallbackErrors( 29775 () => callback(activeSpan), 29776 () => { 29777 // Only update the span status if it hasn't been changed yet 29778 if (activeSpan) { 29779 const { status } = spanUtils.spanToJSON(activeSpan); 29780 if (!status || status === 'ok') { 29781 activeSpan.setStatus('internal_error'); 29782 } 29783 } 29784 }, 29785 () => activeSpan && activeSpan.end(), 29786 ); 29787 }); 29788 }); 29789} 29790 29791/** 29792 * @deprecated Use {@link startSpan} instead. 29793 */ 29794const startActiveSpan = startSpan; 29795 29796/** 29797 * Similar to `Sentry.startSpan`. Wraps a function with a transaction/span, but does not finish the span 29798 * after the function is done automatically. You'll have to call `span.end()` manually. 29799 * 29800 * The created span is the active span and will be used as parent by other spans created inside the function 29801 * and can be accessed via `Sentry.getActiveSpan()`, as long as the function is executed while the scope is active. 29802 * 29803 * Note that if you have not enabled tracing extensions via `addTracingExtensions` 29804 * or you didn't set `tracesSampleRate`, this function will not generate spans 29805 * and the `span` returned from the callback will be undefined. 29806 */ 29807function startSpanManual( 29808 context, 29809 callback, 29810) { 29811 const spanContext = normalizeContext(context); 29812 29813 return hub.runWithAsyncContext(() => { 29814 return exports$1.withScope(context.scope, scope => { 29815 // eslint-disable-next-line deprecation/deprecation 29816 const hub$1 = hub.getCurrentHub(); 29817 // eslint-disable-next-line deprecation/deprecation 29818 const parentSpan = scope.getSpan(); 29819 29820 const shouldSkipSpan = context.onlyIfParent && !parentSpan; 29821 const activeSpan = shouldSkipSpan 29822 ? undefined 29823 : createChildSpanOrTransaction(hub$1, { 29824 parentSpan, 29825 spanContext, 29826 forceTransaction: context.forceTransaction, 29827 scope, 29828 }); 29829 29830 function finishAndSetSpan() { 29831 activeSpan && activeSpan.end(); 29832 } 29833 29834 return handleCallbackErrors.handleCallbackErrors( 29835 () => callback(activeSpan, finishAndSetSpan), 29836 () => { 29837 // Only update the span status if it hasn't been changed yet, and the span is not yet finished 29838 if (activeSpan && activeSpan.isRecording()) { 29839 const { status } = spanUtils.spanToJSON(activeSpan); 29840 if (!status || status === 'ok') { 29841 activeSpan.setStatus('internal_error'); 29842 } 29843 } 29844 }, 29845 ); 29846 }); 29847 }); 29848} 29849 29850/** 29851 * Creates a span. This span is not set as active, so will not get automatic instrumentation spans 29852 * as children or be able to be accessed via `Sentry.getSpan()`. 29853 * 29854 * If you want to create a span that is set as active, use {@link startSpan}. 29855 *
29856 * Note that if you have not enabled tracing extensions via `addTracingExtensions` 29857 * or you didn't set `tracesSampleRate` or `tracesSampler`, this function will not generate spans 29858 * and the `span` returned from the callback will be undefined. 29859 */ 29860function startInactiveSpan(context) { 29861 if (!hasTracingEnabled.hasTracingEnabled()) { 29862 return undefined; 29863 } 29864 29865 const spanContext = normalizeContext(context); 29866 // eslint-disable-next-line deprecation/deprecation 29867 const hub$1 = hub.getCurrentHub(); 29868 const parentSpan = context.scope 29869 ? // eslint-disable-next-line deprecation/deprecation 29870 context.scope.getSpan() 29871 : getActiveSpan(); 29872 29873 const shouldSkipSpan = context.onlyIfParent && !parentSpan; 29874 29875 if (shouldSkipSpan) { 29876 return undefined; 29877 } 29878 29879 const scope = context.scope || exports$1.getCurrentScope(); 29880 29881 // Even though we don't actually want to make this span active on the current scope, 29882 // we need to make it active on a temporary scope that we use for event processing 29883 // as otherwise, it won't pick the correct span for the event when processing it 29884 const temporaryScope = (scope ).clone(); 29885 29886 return createChildSpanOrTransaction(hub$1, { 29887 parentSpan, 29888 spanContext, 29889 forceTransaction: context.forceTransaction, 29890 scope: temporaryScope, 29891 }); 29892} 29893 29894/** 29895 * Returns the currently active span. 29896 */ 29897function getActiveSpan() { 29898 // eslint-disable-next-line deprecation/deprecation 29899 return exports$1.getCurrentScope().getSpan(); 29900} 29901 29902const continueTrace = ( 29903 { 29904 sentryTrace, 29905 baggage, 29906 } 29907 29908, 29909 callback, 29910) => { 29911 // TODO(v8): Change this function so it doesn't do anything besides setting the propagation context on the current scope: 29912 /* 29913 return withScope((scope) => { 29914 const propagationContext = propagationContextFromHeaders(sentryTrace, baggage); 29915 scope.setPropagationContext(propagationContext); 29916 return callback(); 29917 }) 29918 */ 29919 29920 const currentScope = exports$1.getCurrentScope(); 29921 29922 // eslint-disable-next-line deprecation/deprecation 29923 const { traceparentData, dynamicSamplingContext, propagationContext } = utils.tracingContextFromHeaders( 29924 sentryTrace, 29925 baggage, 29926 ); 29927 29928 currentScope.setPropagationContext(propagationContext); 29929 29930 if (debugBuild.DEBUG_BUILD && traceparentData) { 29931 utils.logger.log(`[Tracing] Continuing trace ${traceparentData.traceId}.`); 29932 } 29933 29934 const transactionContext = { 29935 ...traceparentData, 29936 metadata: utils.dropUndefinedKeys({ 29937 dynamicSamplingContext, 29938 }), 29939 }; 29940 29941 if (!callback) { 29942 return transactionContext; 29943 } 29944 29945 return hub.runWithAsyncContext(() => { 29946 return callback(transactionContext); 29947 }); 29948}; 29949 29950function createChildSpanOrTransaction( 29951 hub$1, 29952 { 29953 parentSpan, 29954 spanContext, 29955 forceTransaction, 29956 scope, 29957 } 29958 29959, 29960) { 29961 if (!hasTracingEnabled.hasTracingEnabled()) { 29962 return undefined; 29963 } 29964 29965 const isolationScope = hub.getIsolationScope(); 29966 29967 let span; 29968 if (parentSpan && !forceTransaction) { 29969 // eslint-disable-next-line deprecation/deprecation 29970 span = parentSpan.startChild(spanContext); 29971 } else if (parentSpan) { 29972 // If we forced a transaction but have a parent span, make sure to continue from the parent span, not the scope 29973 const dsc = dynamicSamplingContext.getDynamicSamplingContextFromSpan(parentSpan); 29974 const { traceId, spanId: parentSpanId } = parentSpan.spanContext(); 29975 const sampled = spanUtils.spanIsSampled(parentSpan); 29976 29977 // eslint-disable-next-line deprecation/deprecation 29978 span = hub$1.startTransaction({ 29979 traceId, 29980 parentSpanId, 29981 parentSampled: sampled, 29982 ...spanContext, 29983 metadata: { 29984 dynamicSamplingContext: dsc, 29985 // eslint-disable-next-line deprecation/deprecation 29986 ...spanContext.metadata, 29987 }, 29988 }); 29989 } else { 29990 const { traceId, dsc, parentSpanId, sampled } = { 29991 ...isolationScope.getPropagationContext(), 29992 ...scope.getPropagationContext(), 29993 }; 29994 29995 // eslint-disable-next-line deprecation/deprecation 29996 span = hub$1.startTransaction({ 29997 traceId, 29998 parentSpanId, 29999 parentSampled: sampled, 30000 ...spanContext, 30001 metadata: { 30002 dynamicSamplingContext: dsc, 30003 // eslint-disable-next-line deprecation/deprecation 30004 ...spanContext.metadata, 30005 }, 30006 }); 30007 } 30008 30009 // We always set this as active span on the scope 30010 // In the case of this being an inactive span, we ensure to pass a detached scope in here in the first place 30011 // But by having this here, we can ensure that the lookup through `getCapturedScopesOnSpan` results in the correct scope & span combo 30012 // eslint-disable-next-line deprecation/deprecation 30013 scope.setSpan(span); 30014 30015 setCapturedScopesOnSpan(span, scope, isolationScope); 30016 30017 return span; 30018} 30019 30020/** 30021 * This converts StartSpanOptions to TransactionContext. 30022 * For the most part (for now) we accept the same options, 30023 * but some of them need to be transformed. 30024 * 30025 * Eventually the StartSpanOptions will be more aligned with OpenTelemetry. 30026 */ 30027function normalizeContext(context) { 30028 if (context.startTime) { 30029 const ctx = { ...context }; 30030 ctx.startTimestamp = spanUtils.spanTimeInputToSeconds(context.startTime); 30031 delete ctx.startTime; 30032 return ctx; 30033 } 30034 30035 return context; 30036} 30037 30038const SCOPE_ON_START_SPAN_FIELD = '_sentryScope'; 30039const ISOLATION_SCOPE_ON_START_SPAN_FIELD = '_sentryIsolationScope'; 30040 30041function setCapturedScopesOnSpan(span, scope, isolationScope) {
30042 if (span) { 30043 utils.addNonEnumerableProperty(span, ISOLATION_SCOPE_ON_START_SPAN_FIELD, isolationScope); 30044 utils.addNonEnumerableProperty(span, SCOPE_ON_START_SPAN_FIELD, scope); 30045 } 30046} 30047 30048/** 30049 * Grabs the scope and isolation scope off a span that were active when the span was started. 30050 */ 30051function getCapturedScopesOnSpan(span) { 30052 return { 30053 scope: (span )[SCOPE_ON_START_SPAN_FIELD], 30054 isolationScope: (span )[ISOLATION_SCOPE_ON_START_SPAN_FIELD], 30055 }; 30056} 30057 30058exports.continueTrace = continueTrace; 30059exports.getActiveSpan = getActiveSpan; 30060exports.getCapturedScopesOnSpan = getCapturedScopesOnSpan; 30061exports.startActiveSpan = startActiveSpan; 30062exports.startInactiveSpan = startInactiveSpan; 30063exports.startSpan = startSpan; 30064exports.startSpanManual = startSpanManual; 30065exports.trace = trace; 30066 30067 30068},{"../debug-build.js":245,"../exports.js":248,"../hub.js":249,"../utils/handleCallbackErrors.js":291,"../utils/hasTracingEnabled.js":292,"../utils/spanUtils.js":297,"./dynamicSamplingContext.js":275,"./errors.js":276,"./spanstatus.js":282,"@sentry/utils":319}],284:[function(require,module,exports){ 30069Object.defineProperty(exports, '__esModule', { value: true }); 30070 30071const utils = require('@sentry/utils'); 30072const debugBuild = require('../debug-build.js'); 30073const hub = require('../hub.js'); 30074const metricSummary = require('../metrics/metric-summary.js'); 30075const semanticAttributes = require('../semanticAttributes.js'); 30076const spanUtils = require('../utils/spanUtils.js'); 30077const dynamicSamplingContext = require('./dynamicSamplingContext.js'); 30078const span = require('./span.js'); 30079const trace = require('./trace.js'); 30080 30081/** JSDoc */ 30082class Transaction extends span.Span { 30083 /** 30084 * The reference to the current hub. 30085 */ 30086 30087 // DO NOT yet remove this property, it is used in a hack for v7 backwards compatibility. 30088 30089 /** 30090 * This constructor should never be called manually. Those instrumenting tracing should use 30091 * `Sentry.startTransaction()`, and internal methods should use `hub.startTransaction()`. 30092 * @internal 30093 * @hideconstructor 30094 * @hidden 30095 * 30096 * @deprecated Transactions will be removed in v8. Use spans instead. 30097 */ 30098 constructor(transactionContext, hub$1) { 30099 super(transactionContext); 30100 this._contexts = {}; 30101 30102 // eslint-disable-next-line deprecation/deprecation 30103 this._hub = hub$1 || hub.getCurrentHub(); 30104 30105 this._name = transactionContext.name || ''; 30106 30107 this._metadata = { 30108 // eslint-disable-next-line deprecation/deprecation 30109 ...transactionContext.metadata, 30110 }; 30111 30112 this._trimEnd = transactionContext.trimEnd; 30113 30114 // this is because transactions are also spans, and spans have a transaction pointer 30115 // TODO (v8): Replace this with another way to set the root span 30116 // eslint-disable-next-line deprecation/deprecation 30117 this.transaction = this; 30118 30119 // If Dynamic Sampling Context is provided during the creation of the transaction, we freeze it as it usually means 30120 // there is incoming Dynamic Sampling Context. (Either through an incoming request, a baggage meta-tag, or other means) 30121 const incomingDynamicSamplingContext = this._metadata.dynamicSamplingContext; 30122 if (incomingDynamicSamplingContext) { 30123 // We shallow copy this in case anything writes to the original reference of the passed in `dynamicSamplingContext` 30124 this._frozenDynamicSamplingContext = { ...incomingDynamicSamplingContext }; 30125 } 30126 } 30127 30128 // This sadly conflicts with the getter/setter ordering :( 30129 /* eslint-disable @typescript-eslint/member-ordering */ 30130 30131 /** 30132 * Getter for `name` property. 30133 * @deprecated Use `spanToJSON(span).description` instead. 30134 */ 30135 get name() { 30136 return this._name; 30137 } 30138 30139 /** 30140 * Setter for `name` property, which also sets `source` as custom. 30141 * @deprecated Use `updateName()` and `setMetadata()` instead. 30142 */ 30143 set name(newName) { 30144 // eslint-disable-next-line deprecation/deprecation 30145 this.setName(newName); 30146 } 30147 30148 /** 30149 * Get the metadata for this transaction. 30150 * @deprecated Use `spanGetMetadata(transaction)` instead. 30151 */ 30152 get metadata() { 30153 // We merge attributes in for backwards compatibility 30154 return { 30155 // Defaults 30156 // eslint-disable-next-line deprecation/deprecation 30157 source: 'custom', 30158 spanMetadata: {}, 30159 30160 // Legacy metadata 30161 ...this._metadata, 30162 30163 // From attributes 30164 ...(this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] && { 30165 source: this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] , 30166 }), 30167 ...(this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] && { 30168 sampleRate: this._attributes[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] , 30169 }), 30170 }; 30171 } 30172 30173 /** 30174 * Update the metadata for this transaction. 30175 * @deprecated Use `spanGetMetadata(transaction)` instead. 30176 */ 30177 set metadata(metadata) { 30178 this._metadata = metadata; 30179 } 30180 30181 /* eslint-enable @typescript-eslint/member-ordering */ 30182 30183 /** 30184 * Setter for `name` property, which also sets `source` on the metadata. 30185 * 30186 * @deprecated Use `.updateName()` and `.setAttribute()` instead. 30187 */ 30188 setName(name, source = 'custom') { 30189 this._name = name; 30190 this.setAttribute(semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source); 30191 } 30192 30193 /** @inheritdoc */ 30194 updateName(name) { 30195 this._name = name; 30196 return this; 30197 } 30198 30199 /** 30200 * Attaches SpanRecorder to the span itself 30201 * @param maxlen maximum number of spans that can be recorded 30202 */ 30203 initSpanRecorder(maxlen = 1000) { 30204 // eslint-disable-next-line deprecation/deprecation 30205 if (!this.spanRecorder) { 30206 // eslint-disable-next-line deprecation/deprecation 30207 this.spanRecorder = new span.SpanRecorder(maxlen); 30208 } 30209 // eslint-disable-next-line deprecation/deprecation 30210 this.spanRecorder.add(this); 30211 } 30212 30213 /** 30214 * Set the context of a transaction event. 30215 * @deprecated Use either `.setAttribute()`, or set the context on the scope before creating the transaction. 30216 */ 30217 setContext(key, context) { 30218 if (context === null) { 30219 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 30220 delete this._contexts[key]; 30221 } else { 30222 this._contexts[key] = context; 30223 } 30224 } 30225 30226 /** 30227 * @inheritDoc 30228 * 30229 * @deprecated Use top-level `setMeasurement()` instead. 30230 */ 30231 setMeasurement(name, value, unit = '') { 30232 this._measurements[name] = { value, unit }; 30233 } 30234 30235 /** 30236 * Store metadata on this transaction. 30237 * @deprecated Use attributes or store data on the scope instead. 30238 */ 30239 setMetadata(newMetadata) { 30240 this._metadata = { ...this._metadata, ...newMetadata }; 30241 } 30242 30243 /** 30244 * @inheritDoc 30245 */ 30246 end(endTimestamp) { 30247 const timestampInS = spanUtils.spanTimeInputToSeconds(endTimestamp); 30248 const transaction = this._finishTransaction(timestampInS); 30249 if (!transaction) { 30250 return undefined; 30251 } 30252 // eslint-disable-next-line deprecation/deprecation 30253 return this._hub.captureEvent(transaction); 30254 } 30255 30256 /** 30257 * @inheritDoc 30258 */ 30259 toContext() { 30260 // eslint-disable-next-line deprecation/deprecation 30261 const spanContext = super.toContext(); 30262 30263 return utils.dropUndefinedKeys({ 30264 ...spanContext, 30265 name: this._name, 30266 trimEnd: this._trimEnd, 30267 }); 30268 } 30269 30270 /** 30271 * @inheritDoc 30272 */ 30273 updateWithContext(transactionContext) { 30274 // eslint-disable-next-line deprecation/deprecation 30275 super.updateWithContext(transactionContext); 30276 30277 this._name = transactionContext.name || ''; 30278 this._trimEnd = transactionContext.trimEnd; 30279 30280 return this; 30281 } 30282 30283 /** 30284 * @inheritdoc 30285 * 30286 * @experimental 30287 * 30288 * @deprecated Use top-level `getDynamicSamplingContextFromSpan` instead. 30289 */ 30290 getDynamicSamplingContext() { 30291 return dynamicSamplingContext.getDynamicSamplingContextFromSpan(this); 30292 } 30293 30294 /** 30295 * Override the current hub with a new one. 30296 * Used if you want another hub to finish the transaction. 30297 * 30298 * @internal 30299 */ 30300 setHub(hub) { 30301 this._hub = hub; 30302 } 30303 30304 /** 30305 * Get the profile id of the transaction. 30306 */ 30307 getProfileId() { 30308 if (this._contexts !== undefined && this._contexts['profile'] !== undefined) { 30309 return this._contexts['profile'].profile_id ; 30310 } 30311 return undefined; 30312 } 30313 30314 /** 30315 * Finish the transaction & prepare the event to send to Sentry. 30316 */
30317 _finishTransaction(endTimestamp) { 30318 // This transaction is already finished, so we should not flush it again. 30319 if (this._endTime !== undefined) { 30320 return undefined; 30321 } 30322 30323 if (!this._name) { 30324 debugBuild.DEBUG_BUILD && utils.logger.warn('Transaction has no name, falling back to `<unlabeled transaction>`.'); 30325 this._name = '<unlabeled transaction>'; 30326 } 30327 30328 // just sets the end timestamp 30329 super.end(endTimestamp); 30330 30331 // eslint-disable-next-line deprecation/deprecation 30332 const client = this._hub.getClient(); 30333 if (client && client.emit) { 30334 client.emit('finishTransaction', this); 30335 } 30336 30337 if (this._sampled !== true) { 30338 // At this point if `sampled !== true` we want to discard the transaction. 30339 debugBuild.DEBUG_BUILD && utils.logger.log('[Tracing] Discarding transaction because its trace was not chosen to be sampled.'); 30340 30341 if (client) { 30342 client.recordDroppedEvent('sample_rate', 'transaction'); 30343 } 30344 30345 return undefined; 30346 } 30347 30348 // eslint-disable-next-line deprecation/deprecation 30349 const finishedSpans = this.spanRecorder 30350 ? // eslint-disable-next-line deprecation/deprecation 30351 this.spanRecorder.spans.filter(span => span !== this && spanUtils.spanToJSON(span).timestamp) 30352 : []; 30353 30354 if (this._trimEnd && finishedSpans.length > 0) { 30355 const endTimes = finishedSpans.map(span => spanUtils.spanToJSON(span).timestamp).filter(Boolean) ; 30356 this._endTime = endTimes.reduce((prev, current) => { 30357 return prev > current ? prev : current; 30358 }); 30359 } 30360 30361 const { scope: capturedSpanScope, isolationScope: capturedSpanIsolationScope } = trace.getCapturedScopesOnSpan(this); 30362 30363 // eslint-disable-next-line deprecation/deprecation 30364 const { metadata } = this; 30365 // eslint-disable-next-line deprecation/deprecation 30366 const { source } = metadata; 30367 30368 const transaction = { 30369 contexts: { 30370 ...this._contexts, 30371 // We don't want to override trace context 30372 trace: spanUtils.spanToTraceContext(this), 30373 }, 30374 // TODO: Pass spans serialized via `spanToJSON()` here instead in v8. 30375 spans: finishedSpans, 30376 start_timestamp: this._startTime, 30377 // eslint-disable-next-line deprecation/deprecation 30378 tags: this.tags, 30379 timestamp: this._endTime, 30380 transaction: this._name, 30381 type: 'transaction', 30382 sdkProcessingMetadata: { 30383 ...metadata, 30384 capturedSpanScope, 30385 capturedSpanIsolationScope, 30386 ...utils.dropUndefinedKeys({ 30387 dynamicSamplingContext: dynamicSamplingContext.getDynamicSamplingContextFromSpan(this), 30388 }), 30389 }, 30390 _metrics_summary: metricSummary.getMetricSummaryJsonForSpan(this), 30391 ...(source && { 30392 transaction_info: { 30393 source, 30394 }, 30395 }), 30396 }; 30397 30398 const hasMeasurements = Object.keys(this._measurements).length > 0; 30399 30400 if (hasMeasurements) { 30401 debugBuild.DEBUG_BUILD && 30402 utils.logger.log( 30403 '[Measurements] Adding measurements to transaction', 30404 JSON.stringify(this._measurements, undefined, 2), 30405 ); 30406 transaction.measurements = this._measurements; 30407 } 30408 30409 // eslint-disable-next-line deprecation/deprecation 30410 debugBuild.DEBUG_BUILD && utils.logger.log(`[Tracing] Finishing ${this.op} transaction: ${this._name}.`); 30411 30412 return transaction; 30413 } 30414} 30415 30416exports.Transaction = Transaction; 30417 30418 30419},{"../debug-build.js":245,"../hub.js":249,"../metrics/metric-summary.js":266,"../semanticAttributes.js":270,"../utils/spanUtils.js":297,"./dynamicSamplingContext.js":275,"./span.js":281,"./trace.js":283,"@sentry/utils":319}],285:[function(require,module,exports){ 30420Object.defineProperty(exports, '__esModule', { value: true }); 30421 30422const utils = require('@sentry/utils'); 30423const hub = require('../hub.js'); 30424 30425/** 30426 * Grabs active transaction off scope. 30427 * 30428 * @deprecated You should not rely on the transaction, but just use `startSpan()` APIs instead. 30429 */ 30430function getActiveTransaction(maybeHub) { 30431 // eslint-disable-next-line deprecation/deprecation 30432 const hub$1 = maybeHub || hub.getCurrentHub(); 30433 // eslint-disable-next-line deprecation/deprecation 30434 const scope = hub$1.getScope(); 30435 // eslint-disable-next-line deprecation/deprecation 30436 return scope.getTransaction() ; 30437} 30438 30439/** 30440 * The `extractTraceparentData` function and `TRACEPARENT_REGEXP` constant used 30441 * to be declared in this file. It was later moved into `@sentry/utils` as part of a 30442 * move to remove `@sentry/tracing` dependencies from `@sentry/node` (`extractTraceparentData` 30443 * is the only tracing function used by `@sentry/node`). 30444 * 30445 * These exports are kept here for backwards compatability's sake. 30446 * 30447 * See https://github.com/getsentry/sentry-javascript/issues/4642 for more details. 30448 * 30449 * @deprecated Import this function from `@sentry/utils` instead 30450 */ 30451const extractTraceparentData = utils.extractTraceparentData; 30452 30453exports.stripUrlQueryAndFragment = utils.stripUrlQueryAndFragment; 30454exports.extractTraceparentData = extractTraceparentData; 30455exports.getActiveTransaction = getActiveTransaction; 30456 30457 30458},{"../hub.js":249,"@sentry/utils":319}],286:[function(require,module,exports){ 30459Object.defineProperty(exports, '__esModule', { value: true }); 30460 30461const utils = require('@sentry/utils'); 30462const debugBuild = require('../debug-build.js'); 30463 30464const DEFAULT_TRANSPORT_BUFFER_SIZE = 30; 30465 30466/**
30467 * Creates an instance of a Sentry `Transport` 30468 * 30469 * @param options 30470 * @param makeRequest 30471 */ 30472function createTransport( 30473 options, 30474 makeRequest, 30475 buffer = utils.makePromiseBuffer( 30476 options.bufferSize || DEFAULT_TRANSPORT_BUFFER_SIZE, 30477 ), 30478) { 30479 let rateLimits = {}; 30480 const flush = (timeout) => buffer.drain(timeout); 30481 30482 function send(envelope) { 30483 const filteredEnvelopeItems = []; 30484 30485 // Drop rate limited items from envelope 30486 utils.forEachEnvelopeItem(envelope, (item, type) => { 30487 const envelopeItemDataCategory = utils.envelopeItemTypeToDataCategory(type); 30488 if (utils.isRateLimited(rateLimits, envelopeItemDataCategory)) { 30489 const event = getEventForEnvelopeItem(item, type); 30490 options.recordDroppedEvent('ratelimit_backoff', envelopeItemDataCategory, event); 30491 } else { 30492 filteredEnvelopeItems.push(item); 30493 } 30494 }); 30495 30496 // Skip sending if envelope is empty after filtering out rate limited events 30497 if (filteredEnvelopeItems.length === 0) { 30498 return utils.resolvedSyncPromise(); 30499 } 30500 30501 // eslint-disable-next-line @typescript-eslint/no-explicit-any 30502 const filteredEnvelope = utils.createEnvelope(envelope[0], filteredEnvelopeItems ); 30503 30504 // Creates client report for each item in an envelope 30505 const recordEnvelopeLoss = (reason) => { 30506 utils.forEachEnvelopeItem(filteredEnvelope, (item, type) => { 30507 const event = getEventForEnvelopeItem(item, type); 30508 options.recordDroppedEvent(reason, utils.envelopeItemTypeToDataCategory(type), event); 30509 }); 30510 }; 30511 30512 const requestTask = () => 30513 makeRequest({ body: utils.serializeEnvelope(filteredEnvelope, options.textEncoder) }).then( 30514 response => { 30515 // We don't want to throw on NOK responses, but we want to at least log them 30516 if (response.statusCode !== undefined && (response.statusCode < 200 || response.statusCode >= 300)) { 30517 debugBuild.DEBUG_BUILD && utils.logger.warn(`Sentry responded with status code ${response.statusCode} to sent event.`); 30518 } 30519 30520 rateLimits = utils.updateRateLimits(rateLimits, response); 30521 return response; 30522 }, 30523 error => { 30524 recordEnvelopeLoss('network_error'); 30525 throw error; 30526 }, 30527 ); 30528 30529 return buffer.add(requestTask).then( 30530 result => result, 30531 error => { 30532 if (error instanceof utils.SentryError) { 30533 debugBuild.DEBUG_BUILD && utils.logger.error('Skipped sending event because buffer is full.'); 30534 recordEnvelopeLoss('queue_overflow'); 30535 return utils.resolvedSyncPromise(); 30536 } else { 30537 throw error; 30538 } 30539 }, 30540 ); 30541 } 30542 30543 // We use this to identifify if the transport is the base transport 30544 // TODO (v8): Remove this again as we'll no longer need it 30545 send.__sentry__baseTransport__ = true; 30546 30547 return { 30548 send, 30549 flush, 30550 }; 30551} 30552 30553function getEventForEnvelopeItem(item, type) { 30554 if (type !== 'event' && type !== 'transaction') { 30555 return undefined; 30556 } 30557 30558 return Array.isArray(item) ? (item )[1] : undefined; 30559} 30560 30561exports.DEFAULT_TRANSPORT_BUFFER_SIZE = DEFAULT_TRANSPORT_BUFFER_SIZE; 30562exports.createTransport = createTransport; 30563 30564 30565},{"../debug-build.js":245,"@sentry/utils":319}],287:[function(require,module,exports){ 30566Object.defineProperty(exports, '__esModule', { value: true }); 30567 30568const utils = require('@sentry/utils'); 30569const api = require('../api.js'); 30570 30571/** 30572 * Gets an event from an envelope. 30573 * 30574 * This is only exported for use in the tests 30575 */ 30576function eventFromEnvelope(env, types) { 30577 let event; 30578 30579 utils.forEachEnvelopeItem(env, (item, type) => { 30580 if (types.includes(type)) { 30581 event = Array.isArray(item) ? (item )[1] : undefined; 30582 } 30583 // bail out if we found an event 30584 return !!event; 30585 }); 30586 30587 return event; 30588} 30589 30590/** 30591 * Creates a transport that overrides the release on all events. 30592 */ 30593function makeOverrideReleaseTransport( 30594 createTransport, 30595 release, 30596) { 30597 return options => { 30598 const transport = createTransport(options); 30599 30600 return { 30601 send: async (envelope) => { 30602 const event = eventFromEnvelope(envelope, ['event', 'transaction', 'profile', 'replay_event']); 30603 30604 if (event) { 30605 event.release = release; 30606 } 30607 return transport.send(envelope); 30608 }, 30609 flush: timeout => transport.flush(timeout), 30610 }; 30611 }; 30612} 30613 30614/** 30615 * Creates a transport that can send events to different DSNs depending on the envelope contents. 30616 */ 30617function makeMultiplexedTransport( 30618 createTransport, 30619 matcher, 30620) { 30621 return options => { 30622 const fallbackTransport = createTransport(options); 30623 const otherTransports = {}; 30624 30625 function getTransport(dsn, release) { 30626 // We create a transport for every unique dsn/release combination as there may be code from multiple releases in 30627 // use at the same time
30628 const key = release ? `${dsn}:${release}` : dsn; 30629 30630 if (!otherTransports[key]) { 30631 const validatedDsn = utils.dsnFromString(dsn); 30632 if (!validatedDsn) { 30633 return undefined; 30634 } 30635 const url = api.getEnvelopeEndpointWithUrlEncodedAuth(validatedDsn); 30636 30637 otherTransports[key] = release 30638 ? makeOverrideReleaseTransport(createTransport, release)({ ...options, url }) 30639 : createTransport({ ...options, url }); 30640 } 30641 30642 return otherTransports[key]; 30643 } 30644 30645 async function send(envelope) { 30646 function getEvent(types) { 30647 const eventTypes = types && types.length ? types : ['event']; 30648 return eventFromEnvelope(envelope, eventTypes); 30649 } 30650 30651 const transports = matcher({ envelope, getEvent }) 30652 .map(result => { 30653 if (typeof result === 'string') { 30654 return getTransport(result, undefined); 30655 } else { 30656 return getTransport(result.dsn, result.release); 30657 } 30658 }) 30659 .filter((t) => !!t); 30660 30661 // If we have no transports to send to, use the fallback transport 30662 if (transports.length === 0) { 30663 transports.push(fallbackTransport); 30664 } 30665 30666 const results = await Promise.all(transports.map(transport => transport.send(envelope))); 30667 30668 return results[0]; 30669 } 30670 30671 async function flush(timeout) { 30672 const allTransports = [...Object.keys(otherTransports).map(dsn => otherTransports[dsn]), fallbackTransport]; 30673 const results = await Promise.all(allTransports.map(transport => transport.flush(timeout))); 30674 return results.every(r => r); 30675 } 30676 30677 return { 30678 send, 30679 flush, 30680 }; 30681 }; 30682} 30683 30684exports.eventFromEnvelope = eventFromEnvelope; 30685exports.makeMultiplexedTransport = makeMultiplexedTransport; 30686 30687 30688},{"../api.js":241,"@sentry/utils":319}],288:[function(require,module,exports){ 30689Object.defineProperty(exports, '__esModule', { value: true }); 30690 30691const utils = require('@sentry/utils'); 30692const debugBuild = require('../debug-build.js'); 30693 30694const MIN_DELAY = 100; // 100 ms 30695const START_DELAY = 5000; // 5 seconds 30696const MAX_DELAY = 3.6e6; // 1 hour 30697 30698function log(msg, error) { 30699 debugBuild.DEBUG_BUILD && utils.logger.info(`[Offline]: ${msg}`, error); 30700} 30701 30702/** 30703 * Wraps a transport and stores and retries events when they fail to send. 30704 * 30705 * @param createTransport The transport to wrap. 30706 */ 30707function makeOfflineTransport( 30708 createTransport, 30709) { 30710 return options => { 30711 const transport = createTransport(options); 30712 const store = options.createStore ? options.createStore(options) : undefined; 30713 30714 let retryDelay = START_DELAY; 30715 let flushTimer; 30716 30717 function shouldQueue(env, error, retryDelay) { 30718 // We don't queue Session Replay envelopes because they are: 30719 // - Ordered and Replay relies on the response status to know when they're successfully sent. 30720 // - Likely to fill the queue quickly and block other events from being sent. 30721 // We also want to drop client reports because they can be generated when we retry sending events while offline. 30722 if (utils.envelopeContainsItemType(env, ['replay_event', 'replay_recording', 'client_report'])) { 30723 return false; 30724 } 30725 30726 if (options.shouldStore) { 30727 return options.shouldStore(env, error, retryDelay); 30728 } 30729 30730 return true; 30731 } 30732 30733 function flushIn(delay) { 30734 if (!store) { 30735 return; 30736 } 30737 30738 if (flushTimer) { 30739 clearTimeout(flushTimer ); 30740 } 30741 30742 flushTimer = setTimeout(async () => { 30743 flushTimer = undefined; 30744 30745 const found = await store.pop(); 30746 if (found) { 30747 log('Attempting to send previously queued event'); 30748 void send(found).catch(e => { 30749 log('Failed to retry sending', e); 30750 }); 30751 } 30752 }, delay) ; 30753 30754 // We need to unref the timer in node.js, otherwise the node process never exit. 30755 if (typeof flushTimer !== 'number' && flushTimer.unref) { 30756 flushTimer.unref(); 30757 } 30758 } 30759 30760 function flushWithBackOff() { 30761 if (flushTimer) { 30762 return; 30763 } 30764 30765 flushIn(retryDelay); 30766 30767 retryDelay = Math.min(retryDelay * 2, MAX_DELAY); 30768 } 30769 30770 async function send(envelope) {
30771 try { 30772 const result = await transport.send(envelope); 30773 30774 let delay = MIN_DELAY; 30775 30776 if (result) { 30777 // If there's a retry-after header, use that as the next delay. 30778 if (result.headers && result.headers['retry-after']) { 30779 delay = utils.parseRetryAfterHeader(result.headers['retry-after']); 30780 } // If we have a server error, return now so we don't flush the queue. 30781 else if ((result.statusCode || 0) >= 400) { 30782 return result; 30783 } 30784 } 30785 30786 flushIn(delay); 30787 retryDelay = START_DELAY; 30788 return result; 30789 } catch (e) { 30790 if (store && (await shouldQueue(envelope, e , retryDelay))) { 30791 await store.insert(envelope); 30792 flushWithBackOff(); 30793 log('Error sending. Event queued', e ); 30794 return {}; 30795 } else { 30796 throw e; 30797 } 30798 } 30799 } 30800 30801 if (options.flushAtStartup) { 30802 flushWithBackOff(); 30803 } 30804 30805 return { 30806 send, 30807 flush: t => transport.flush(t), 30808 }; 30809 }; 30810} 30811 30812exports.MIN_DELAY = MIN_DELAY; 30813exports.START_DELAY = START_DELAY; 30814exports.makeOfflineTransport = makeOfflineTransport; 30815 30816 30817},{"../debug-build.js":245,"@sentry/utils":319}],289:[function(require,module,exports){ 30818Object.defineProperty(exports, '__esModule', { value: true }); 30819 30820const utils = require('@sentry/utils'); 30821const dynamicSamplingContext = require('../tracing/dynamicSamplingContext.js'); 30822const getRootSpan = require('./getRootSpan.js'); 30823const spanUtils = require('./spanUtils.js'); 30824 30825/** 30826 * Applies data from the scope to the event and runs all event processors on it. 30827 */ 30828function applyScopeDataToEvent(event, data) { 30829 const { fingerprint, span, breadcrumbs, sdkProcessingMetadata } = data; 30830 30831 // Apply general data 30832 applyDataToEvent(event, data); 30833 30834 // We want to set the trace context for normal events only if there isn't already 30835 // a trace context on the event. There is a product feature in place where we link 30836 // errors with transaction and it relies on that. 30837 if (span) { 30838 applySpanToEvent(event, span); 30839 } 30840 30841 applyFingerprintToEvent(event, fingerprint); 30842 applyBreadcrumbsToEvent(event, breadcrumbs); 30843 applySdkMetadataToEvent(event, sdkProcessingMetadata); 30844} 30845 30846/** Merge data of two scopes together. */ 30847function mergeScopeData(data, mergeData) { 30848 const { 30849 extra, 30850 tags, 30851 user, 30852 contexts, 30853 level, 30854 sdkProcessingMetadata, 30855 breadcrumbs, 30856 fingerprint, 30857 eventProcessors, 30858 attachments, 30859 propagationContext, 30860 // eslint-disable-next-line deprecation/deprecation 30861 transactionName, 30862 span, 30863 } = mergeData; 30864 30865 mergeAndOverwriteScopeData(data, 'extra', extra); 30866 mergeAndOverwriteScopeData(data, 'tags', tags); 30867 mergeAndOverwriteScopeData(data, 'user', user); 30868 mergeAndOverwriteScopeData(data, 'contexts', contexts); 30869 mergeAndOverwriteScopeData(data, 'sdkProcessingMetadata', sdkProcessingMetadata); 30870 30871 if (level) { 30872 data.level = level; 30873 } 30874 30875 if (transactionName) { 30876 // eslint-disable-next-line deprecation/deprecation 30877 data.transactionName = transactionName; 30878 } 30879 30880 if (span) { 30881 data.span = span; 30882 } 30883 30884 if (breadcrumbs.length) { 30885 data.breadcrumbs = [...data.breadcrumbs, ...breadcrumbs]; 30886 } 30887 30888 if (fingerprint.length) { 30889 data.fingerprint = [...data.fingerprint, ...fingerprint]; 30890 } 30891 30892 if (eventProcessors.length) { 30893 data.eventProcessors = [...data.eventProcessors, ...eventProcessors]; 30894 } 30895 30896 if (attachments.length) { 30897 data.attachments = [...data.attachments, ...attachments]; 30898 } 30899 30900 data.propagationContext = { ...data.propagationContext, ...propagationContext }; 30901} 30902 30903/** 30904 * Merges certain scope data. Undefined values will overwrite any existing values. 30905 * Exported only for tests. 30906 */ 30907function mergeAndOverwriteScopeData 30908 30909(data, prop, mergeVal) { 30910 if (mergeVal && Object.keys(mergeVal).length) { 30911 // Clone object 30912 data[prop] = { ...data[prop] }; 30913 for (const key in mergeVal) { 30914 if (Object.prototype.hasOwnProperty.call(mergeVal, key)) { 30915 data[prop][key] = mergeVal[key]; 30916 } 30917 } 30918 } 30919} 30920 30921function applyDataToEvent(event, data) { 30922 const { 30923 extra, 30924 tags, 30925 user, 30926 contexts, 30927 level, 30928 // eslint-disable-next-line deprecation/deprecation 30929 transactionName, 30930 } = data; 30931 30932 const cleanedExtra = utils.dropUndefinedKeys(extra); 30933 if (cleanedExtra && Object.keys(cleanedExtra).length) { 30934 event.extra = { ...cleanedExtra, ...event.extra }; 30935 } 30936 30937 const cleanedTags = utils.dropUndefinedKeys(tags); 30938 if (cleanedTags && Object.keys(cleanedTags).length) { 30939 event.tags = { ...cleanedTags, ...event.tags }; 30940 } 30941 30942 const cleanedUser = utils.dropUndefinedKeys(user); 30943 if (cleanedUser && Object.keys(cleanedUser).length) { 30944 event.user = { ...cleanedUser, ...event.user }; 30945 } 30946 30947 const cleanedContexts = utils.dropUndefinedKeys(contexts); 30948 if (cleanedContexts && Object.keys(cleanedContexts).length) { 30949 event.contexts = { ...cleanedContexts, ...event.contexts }; 30950 } 30951 30952 if (level) { 30953 event.level = level; 30954 } 30955 30956 if (transactionName) { 30957 event.transaction = transactionName; 30958 } 30959} 30960 30961function applyBreadcrumbsToEvent(event, breadcrumbs) { 30962 const mergedBreadcrumbs = [...(event.breadcrumbs || []), ...breadcrumbs]; 30963 event.breadcrumbs = mergedBreadcrumbs.length ? mergedBreadcrumbs : undefined; 30964} 30965 30966function applySdkMetadataToEvent(event, sdkProcessingMetadata) { 30967 event.sdkProcessingMetadata = { 30968 ...event.sdkProcessingMetadata, 30969 ...sdkProcessingMetadata, 30970 }; 30971} 30972 30973function applySpanToEvent(event, span) { 30974 event.contexts = { trace: spanUtils.spanToTraceContext(span), ...event.contexts }; 30975 const rootSpan = getRootSpan.getRootSpan(span); 30976 if (rootSpan) { 30977 event.sdkProcessingMetadata = { 30978 dynamicSamplingContext: dynamicSamplingContext.getDynamicSamplingContextFromSpan(span), 30979 ...event.sdkProcessingMetadata, 30980 }; 30981 const transactionName = spanUtils.spanToJSON(rootSpan).description; 30982 if (transactionName) { 30983 event.tags = { transaction: transactionName, ...event.tags }; 30984 } 30985 } 30986} 30987 30988/** 30989 * Applies fingerprint from the scope to the event if there's one, 30990 * uses message if there's one instead or get rid of empty fingerprint 30991 */ 30992function applyFingerprintToEvent(event, fingerprint) { 30993 // Make sure it's an array first and we actually have something in place 30994 event.fingerprint = event.fingerprint ? utils.arrayify(event.fingerprint) : []; 30995 30996 // If we have something on the scope, then merge it with event 30997 if (fingerprint) { 30998 event.fingerprint = event.fingerprint.concat(fingerprint); 30999 } 31000 31001 // If we have no data at all, remove empty array default 31002 if (event.fingerprint && !event.fingerprint.length) { 31003 delete event.fingerprint; 31004 } 31005} 31006 31007exports.applyScopeDataToEvent = applyScopeDataToEvent; 31008exports.mergeAndOverwriteScopeData = mergeAndOverwriteScopeData; 31009exports.mergeScopeData = mergeScopeData; 31010 31011 31012},{"../tracing/dynamicSamplingContext.js":275,"./getRootSpan.js":290,"./spanUtils.js":297,"@sentry/utils":319}],290:[function(require,module,exports){ 31013Object.defineProperty(exports, '__esModule', { value: true }); 31014 31015/** 31016 * Returns the root span of a given span. 31017 * 31018 * As long as we use `Transaction`s internally, the returned root span 31019 * will be a `Transaction` but be aware that this might change in the future. 31020 * 31021 * If the given span has no root span or transaction, `undefined` is returned. 31022 */ 31023function getRootSpan(span) { 31024 // TODO (v8): Remove this check and just return span 31025 // eslint-disable-next-line deprecation/deprecation 31026 return span.transaction; 31027} 31028 31029exports.getRootSpan = getRootSpan; 31030 31031 31032},{}],291:[function(require,module,exports){ 31033Object.defineProperty(exports, '__esModule', { value: true }); 31034 31035const utils = require('@sentry/utils'); 31036 31037/** 31038 * Wrap a callback function with error handling. 31039 * If an error is thrown, it will be passed to the `onError` callback and re-thrown. 31040 * 31041 * If the return value of the function is a promise, it will be handled with `maybeHandlePromiseRejection`. 31042 * 31043 * If an `onFinally` callback is provided, this will be called when the callback has finished 31044 * - so if it returns a promise, once the promise resolved/rejected, 31045 * else once the callback has finished executing. 31046 * The `onFinally` callback will _always_ be called, no matter if an error was thrown or not. 31047 */ 31048function handleCallbackErrors 31049 31050( 31051 fn, 31052 onError, 31053 // eslint-disable-next-line @typescript-eslint/no-empty-function 31054 onFinally = () => {}, 31055) { 31056 let maybePromiseResult; 31057 try { 31058 maybePromiseResult = fn(); 31059 } catch (e) { 31060 onError(e); 31061 onFinally(); 31062 throw e; 31063 } 31064 31065 return maybeHandlePromiseRejection(maybePromiseResult, onError, onFinally); 31066} 31067 31068/** 31069 * Maybe handle a promise rejection. 31070 * This expects to be given a value that _may_ be a promise, or any other value. 31071 * If it is a promise, and it rejects, it will call the `onError` callback. 31072 * Other than this, it will generally return the given value as-is. 31073 */ 31074function maybeHandlePromiseRejection( 31075 value, 31076 onError, 31077 onFinally, 31078) { 31079 if (utils.isThenable(value)) { 31080 // @ts-expect-error - the isThenable check returns the "wrong" type here
31081 return value.then( 31082 res => { 31083 onFinally(); 31084 return res; 31085 }, 31086 e => { 31087 onError(e); 31088 onFinally(); 31089 throw e; 31090 }, 31091 ); 31092 } 31093 31094 onFinally(); 31095 return value; 31096} 31097 31098exports.handleCallbackErrors = handleCallbackErrors; 31099 31100 31101},{"@sentry/utils":319}],292:[function(require,module,exports){ 31102Object.defineProperty(exports, '__esModule', { value: true }); 31103 31104const exports$1 = require('../exports.js'); 31105 31106// Treeshakable guard to remove all code related to tracing 31107 31108/** 31109 * Determines if tracing is currently enabled. 31110 * 31111 * Tracing is enabled when at least one of `tracesSampleRate` and `tracesSampler` is defined in the SDK config. 31112 */ 31113function hasTracingEnabled( 31114 maybeOptions, 31115) { 31116 if (typeof __SENTRY_TRACING__ === 'boolean' && !__SENTRY_TRACING__) { 31117 return false; 31118 } 31119 31120 const client = exports$1.getClient(); 31121 const options = maybeOptions || (client && client.getOptions()); 31122 return !!options && (options.enableTracing || 'tracesSampleRate' in options || 'tracesSampler' in options); 31123} 31124 31125exports.hasTracingEnabled = hasTracingEnabled; 31126 31127 31128},{"../exports.js":248}],293:[function(require,module,exports){ 31129Object.defineProperty(exports, '__esModule', { value: true }); 31130 31131/** 31132 * Checks whether given url points to Sentry server 31133 * @param url url to verify 31134 * 31135 * TODO(v8): Remove Hub fallback type 31136 */ 31137function isSentryRequestUrl(url, hubOrClient) { 31138 const client = 31139 hubOrClient && isHub(hubOrClient) 31140 ? // eslint-disable-next-line deprecation/deprecation 31141 hubOrClient.getClient() 31142 : hubOrClient; 31143 const dsn = client && client.getDsn(); 31144 const tunnel = client && client.getOptions().tunnel; 31145 31146 return checkDsn(url, dsn) || checkTunnel(url, tunnel); 31147} 31148 31149function checkTunnel(url, tunnel) { 31150 if (!tunnel) { 31151 return false; 31152 } 31153 31154 return removeTrailingSlash(url) === removeTrailingSlash(tunnel); 31155} 31156 31157function checkDsn(url, dsn) { 31158 return dsn ? url.includes(dsn.host) : false; 31159} 31160 31161function removeTrailingSlash(str) { 31162 return str[str.length - 1] === '/' ? str.slice(0, -1) : str; 31163} 31164 31165function isHub(hubOrClient) { 31166 // eslint-disable-next-line deprecation/deprecation 31167 return (hubOrClient ).getClient !== undefined; 31168} 31169 31170exports.isSentryRequestUrl = isSentryRequestUrl; 31171 31172 31173},{}],294:[function(require,module,exports){ 31174Object.defineProperty(exports, '__esModule', { value: true }); 31175 31176/** 31177 * Tagged template function which returns paramaterized representation of the message 31178 * For example: parameterize`This is a log statement with ${x} and ${y} params`, would return: 31179 * "__sentry_template_string__": 'This is a log statement with %s and %s params', 31180 * "__sentry_template_values__": ['first', 'second'] 31181 * @param strings An array of string values splitted between expressions 31182 * @param values Expressions extracted from template string 31183 * @returns String with template information in __sentry_template_string__ and __sentry_template_values__ properties 31184 */ 31185function parameterize(strings, ...values) { 31186 const formatted = new String(String.raw(strings, ...values)) ; 31187 formatted.__sentry_template_string__ = strings.join('\x00').replace(/%/g, '%%').replace(/\0/g, '%s'); 31188 formatted.__sentry_template_values__ = values; 31189 return formatted; 31190} 31191 31192exports.parameterize = parameterize; 31193 31194 31195},{}],295:[function(require,module,exports){ 31196Object.defineProperty(exports, '__esModule', { value: true }); 31197 31198const utils = require('@sentry/utils'); 31199const constants = require('../constants.js'); 31200const eventProcessors = require('../eventProcessors.js'); 31201const scope = require('../scope.js'); 31202const applyScopeDataToEvent = require('./applyScopeDataToEvent.js'); 31203const spanUtils = require('./spanUtils.js'); 31204 31205/** 31206 * This type makes sure that we get either a CaptureContext, OR an EventHint. 31207 * It does not allow mixing them, which could lead to unexpected outcomes, e.g. this is disallowed: 31208 * { user: { id: '123' }, mechanism: { handled: false } } 31209 */ 31210 31211/** 31212 * Adds common information to events. 31213 * 31214 * The information includes release and environment from `options`, 31215 * breadcrumbs and context (extra, tags and user) from the scope. 31216 * 31217 * Information that is already present in the event is never overwritten. For 31218 * nested objects, such as the context, keys are merged. 31219 *
31220 * Note: This also triggers callbacks for `addGlobalEventProcessor`, but not `beforeSend`. 31221 * 31222 * @param event The original event. 31223 * @param hint May contain additional information about the original exception. 31224 * @param scope A scope containing event metadata. 31225 * @returns A new event with more information. 31226 * @hidden 31227 */ 31228function prepareEvent( 31229 options, 31230 event, 31231 hint, 31232 scope$1, 31233 client, 31234 isolationScope, 31235) { 31236 const { normalizeDepth = 3, normalizeMaxBreadth = 1000 } = options; 31237 const prepared = { 31238 ...event, 31239 event_id: event.event_id || hint.event_id || utils.uuid4(), 31240 timestamp: event.timestamp || utils.dateTimestampInSeconds(), 31241 }; 31242 const integrations = hint.integrations || options.integrations.map(i => i.name); 31243 31244 applyClientOptions(prepared, options); 31245 applyIntegrationsMetadata(prepared, integrations); 31246 31247 // Only put debug IDs onto frames for error events. 31248 if (event.type === undefined) { 31249 applyDebugIds(prepared, options.stackParser); 31250 } 31251 31252 // If we have scope given to us, use it as the base for further modifications. 31253 // This allows us to prevent unnecessary copying of data if `captureContext` is not provided. 31254 const finalScope = getFinalScope(scope$1, hint.captureContext); 31255 31256 if (hint.mechanism) { 31257 utils.addExceptionMechanism(prepared, hint.mechanism); 31258 } 31259 31260 const clientEventProcessors = client && client.getEventProcessors ? client.getEventProcessors() : []; 31261 31262 // This should be the last thing called, since we want that 31263 // {@link Hub.addEventProcessor} gets the finished prepared event. 31264 // Merge scope data together 31265 const data = scope.getGlobalScope().getScopeData(); 31266 31267 if (isolationScope) { 31268 const isolationData = isolationScope.getScopeData(); 31269 applyScopeDataToEvent.mergeScopeData(data, isolationData); 31270 } 31271 31272 if (finalScope) { 31273 const finalScopeData = finalScope.getScopeData(); 31274 applyScopeDataToEvent.mergeScopeData(data, finalScopeData); 31275 } 31276 31277 const attachments = [...(hint.attachments || []), ...data.attachments]; 31278 if (attachments.length) { 31279 hint.attachments = attachments; 31280 } 31281 31282 applyScopeDataToEvent.applyScopeDataToEvent(prepared, data); 31283 31284 // TODO (v8): Update this order to be: Global > Client > Scope 31285 const eventProcessors$1 = [ 31286 ...clientEventProcessors, 31287 // eslint-disable-next-line deprecation/deprecation 31288 ...eventProcessors.getGlobalEventProcessors(), 31289 // Run scope event processors _after_ all other processors 31290 ...data.eventProcessors, 31291 ]; 31292 31293 const result = eventProcessors.notifyEventProcessors(eventProcessors$1, prepared, hint); 31294 31295 return result.then(evt => { 31296 if (evt) { 31297 // We apply the debug_meta field only after all event processors have ran, so that if any event processors modified 31298 // file names (e.g.the RewriteFrames integration) the filename -> debug ID relationship isn't destroyed. 31299 // This should not cause any PII issues, since we're only moving data that is already on the event and not adding 31300 // any new data 31301 applyDebugMeta(evt); 31302 } 31303 31304 if (typeof normalizeDepth === 'number' && normalizeDepth > 0) { 31305 return normalizeEvent(evt, normalizeDepth, normalizeMaxBreadth); 31306 } 31307 return evt; 31308 }); 31309} 31310 31311/** 31312 * Enhances event using the client configuration. 31313 * It takes care of all "static" values like environment, release and `dist`, 31314 * as well as truncating overly long values. 31315 * @param event event instance to be enhanced 31316 */ 31317function applyClientOptions(event, options) { 31318 const { environment, release, dist, maxValueLength = 250 } = options; 31319 31320 if (!('environment' in event)) { 31321 event.environment = 'environment' in options ? environment : constants.DEFAULT_ENVIRONMENT; 31322 } 31323 31324 if (event.release === undefined && release !== undefined) { 31325 event.release = release; 31326 } 31327 31328 if (event.dist === undefined && dist !== undefined) { 31329 event.dist = dist; 31330 } 31331 31332 if (event.message) { 31333 event.message = utils.truncate(event.message, maxValueLength); 31334 } 31335 31336 const exception = event.exception && event.exception.values && event.exception.values[0]; 31337 if (exception && exception.value) { 31338 exception.value = utils.truncate(exception.value, maxValueLength); 31339 } 31340 31341 const request = event.request; 31342 if (request && request.url) { 31343 request.url = utils.truncate(request.url, maxValueLength); 31344 } 31345} 31346 31347const debugIdStackParserCache = new WeakMap(); 31348 31349/** 31350 * Puts debug IDs into the stack frames of an error event. 31351 */ 31352function applyDebugIds(event, stackParser) { 31353 const debugIdMap = utils.GLOBAL_OBJ._sentryDebugIds; 31354 31355 if (!debugIdMap) { 31356 return; 31357 } 31358 31359 let debugIdStackFramesCache; 31360 const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser); 31361 if (cachedDebugIdStackFrameCache) { 31362 debugIdStackFramesCache = cachedDebugIdStackFrameCache; 31363 } else { 31364 debugIdStackFramesCache = new Map(); 31365 debugIdStackParserCache.set(stackParser, debugIdStackFramesCache); 31366 } 31367 31368 // Build a map of filename -> debug_id 31369 const filenameDebugIdMap = Object.keys(debugIdMap).reduce((acc, debugIdStackTrace) => { 31370 let parsedStack; 31371 const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace); 31372 if (cachedParsedStack) { 31373 parsedStack = cachedParsedStack; 31374 } else { 31375 parsedStack = stackParser(debugIdStackTrace); 31376 debugIdStackFramesCache.set(debugIdStackTrace, parsedStack); 31377 } 31378 31379 for (let i = parsedStack.length - 1; i >= 0; i--) { 31380 const stackFrame = parsedStack[i]; 31381 if (stackFrame.filename) { 31382 acc[stackFrame.filename] = debugIdMap[debugIdStackTrace]; 31383 break; 31384 } 31385 } 31386 return acc; 31387 }, {}); 31388 31389 try { 31390 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
vendor: 3,304 bytes, lines 31391-31495
31391 event.exception.values.forEach(exception => { 31392 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 31393 exception.stacktrace.frames.forEach(frame => { 31394 if (frame.filename) { 31395 frame.debug_id = filenameDebugIdMap[frame.filename]; 31396 } 31397 }); 31398 }); 31399 } catch (e) { 31400 // To save bundle size we're just try catching here instead of checking for the existence of all the different objects. 31401 } 31402} 31403 31404/** 31405 * Moves debug IDs from the stack frames of an error event into the debug_meta field. 31406 */ 31407function applyDebugMeta(event) { 31408 // Extract debug IDs and filenames from the stack frames on the event. 31409 const filenameDebugIdMap = {}; 31410 try { 31411 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 31412 event.exception.values.forEach(exception => { 31413 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 31414 exception.stacktrace.frames.forEach(frame => { 31415 if (frame.debug_id) { 31416 if (frame.abs_path) { 31417 filenameDebugIdMap[frame.abs_path] = frame.debug_id; 31418 } else if (frame.filename) { 31419 filenameDebugIdMap[frame.filename] = frame.debug_id; 31420 } 31421 delete frame.debug_id; 31422 } 31423 }); 31424 }); 31425 } catch (e) { 31426 // To save bundle size we're just try catching here instead of checking for the existence of all the different objects. 31427 } 31428 31429 if (Object.keys(filenameDebugIdMap).length === 0) { 31430 return; 31431 } 31432 31433 // Fill debug_meta information 31434 event.debug_meta = event.debug_meta || {}; 31435 event.debug_meta.images = event.debug_meta.images || []; 31436 const images = event.debug_meta.images; 31437 Object.keys(filenameDebugIdMap).forEach(filename => { 31438 images.push({ 31439 type: 'sourcemap', 31440 code_file: filename, 31441 debug_id: filenameDebugIdMap[filename], 31442 }); 31443 }); 31444} 31445 31446/** 31447 * This function adds all used integrations to the SDK info in the event. 31448 * @param event The event that will be filled with all integrations. 31449 */ 31450function applyIntegrationsMetadata(event, integrationNames) { 31451 if (integrationNames.length > 0) { 31452 event.sdk = event.sdk || {}; 31453 event.sdk.integrations = [...(event.sdk.integrations || []), ...integrationNames]; 31454 } 31455} 31456 31457/** 31458 * Applies `normalize` function on necessary `Event` attributes to make them safe for serialization. 31459 * Normalized keys: 31460 * - `breadcrumbs.data` 31461 * - `user` 31462 * - `contexts` 31463 * - `extra` 31464 * @param event Event 31465 * @returns Normalized event 31466 */ 31467function normalizeEvent(event, depth, maxBreadth) { 31468 if (!event) { 31469 return null; 31470 } 31471 31472 const normalized = { 31473 ...event, 31474 ...(event.breadcrumbs && { 31475 breadcrumbs: event.breadcrumbs.map(b => ({ 31476 ...b, 31477 ...(b.data && { 31478 data: utils.normalize(b.data, depth, maxBreadth), 31479 }), 31480 })), 31481 }), 31482 ...(event.user && { 31483 user: utils.normalize(event.user, depth, maxBreadth), 31484 }), 31485 ...(event.contexts && { 31486 contexts: utils.normalize(event.contexts, depth, maxBreadth), 31487 }), 31488 ...(event.extra && { 31489 extra: utils.normalize(event.extra, depth, maxBreadth), 31490 }), 31491 }; 31492 31493 // event.contexts.trace stores information about a Transaction. Similarly, 31494 // event.spans[] stores information about child Spans. Given that a 31495 // Transaction is conceptually a Span, normalization should apply to both
31496 // Transactions and Spans consistently. 31497 // For now the decision is to skip normalization of Transactions and Spans, 31498 // so this block overwrites the normalized event to add back the original 31499 // Transaction information prior to normalization. 31500 if (event.contexts && event.contexts.trace && normalized.contexts) { 31501 normalized.contexts.trace = event.contexts.trace; 31502 31503 // event.contexts.trace.data may contain circular/dangerous data so we need to normalize it 31504 if (event.contexts.trace.data) { 31505 normalized.contexts.trace.data = utils.normalize(event.contexts.trace.data, depth, maxBreadth); 31506 } 31507 } 31508 31509 // event.spans[].data may contain circular/dangerous data so we need to normalize it 31510 if (event.spans) { 31511 normalized.spans = event.spans.map(span => { 31512 const data = spanUtils.spanToJSON(span).data; 31513 31514 if (data) { 31515 // This is a bit weird, as we generally have `Span` instances here, but to be safe we do not assume so 31516 // eslint-disable-next-line deprecation/deprecation 31517 span.data = utils.normalize(data, depth, maxBreadth); 31518 } 31519 31520 return span; 31521 }); 31522 } 31523 31524 return normalized; 31525} 31526 31527function getFinalScope(scope$1, captureContext) { 31528 if (!captureContext) { 31529 return scope$1; 31530 } 31531 31532 const finalScope = scope$1 ? scope$1.clone() : new scope.Scope(); 31533 finalScope.update(captureContext); 31534 return finalScope; 31535} 31536 31537/** 31538 * Parse either an `EventHint` directly, or convert a `CaptureContext` to an `EventHint`. 31539 * This is used to allow to update method signatures that used to accept a `CaptureContext` but should now accept an `EventHint`. 31540 */ 31541function parseEventHintOrCaptureContext( 31542 hint, 31543) { 31544 if (!hint) { 31545 return undefined; 31546 } 31547 31548 // If you pass a Scope or `() => Scope` as CaptureContext, we just return this as captureContext 31549 if (hintIsScopeOrFunction(hint)) { 31550 return { captureContext: hint }; 31551 } 31552 31553 if (hintIsScopeContext(hint)) { 31554 return { 31555 captureContext: hint, 31556 }; 31557 } 31558 31559 return hint; 31560} 31561 31562function hintIsScopeOrFunction( 31563 hint, 31564) { 31565 return hint instanceof scope.Scope || typeof hint === 'function'; 31566} 31567 31568const captureContextKeys = [ 31569 'user', 31570 'level', 31571 'extra', 31572 'contexts', 31573 'tags', 31574 'fingerprint', 31575 'requestSession', 31576 'propagationContext', 31577] ; 31578 31579function hintIsScopeContext(hint) { 31580 return Object.keys(hint).some(key => captureContextKeys.includes(key )); 31581} 31582 31583exports.applyDebugIds = applyDebugIds; 31584exports.applyDebugMeta = applyDebugMeta; 31585exports.parseEventHintOrCaptureContext = parseEventHintOrCaptureContext; 31586exports.prepareEvent = prepareEvent; 31587 31588 31589},{"../constants.js":244,"../eventProcessors.js":247,"../scope.js":268,"./applyScopeDataToEvent.js":289,"./spanUtils.js":297,"@sentry/utils":319}],296:[function(require,module,exports){ 31590Object.defineProperty(exports, '__esModule', { value: true }); 31591 31592const version = require('../version.js'); 31593 31594/** 31595 * A builder for the SDK metadata in the options for the SDK initialization. 31596 * 31597 * Note: This function is identical to `buildMetadata` in Remix and NextJS and SvelteKit. 31598 * We don't extract it for bundle size reasons. 31599 * @see https://github.com/getsentry/sentry-javascript/pull/7404 31600 * @see https://github.com/getsentry/sentry-javascript/pull/4196 31601 * 31602 * If you make changes to this function consider updating the others as well. 31603 * 31604 * @param options SDK options object that gets mutated 31605 * @param names list of package names 31606 */ 31607function applySdkMetadata(options, name, names = [name], source = 'npm') { 31608 const metadata = options._metadata || {}; 31609 31610 if (!metadata.sdk) { 31611 metadata.sdk = { 31612 name: `sentry.javascript.${name}`, 31613 packages: names.map(name => ({ 31614 name: `${source}:@sentry/${name}`, 31615 version: version.SDK_VERSION, 31616 })), 31617 version: version.SDK_VERSION, 31618 }; 31619 } 31620 31621 options._metadata = metadata; 31622} 31623 31624exports.applySdkMetadata = applySdkMetadata; 31625 31626 31627},{"../version.js":298}],297:[function(require,module,exports){ 31628Object.defineProperty(exports, '__esModule', { value: true }); 31629 31630const utils = require('@sentry/utils'); 31631 31632// These are aligned with OpenTelemetry trace flags 31633const TRACE_FLAG_NONE = 0x0; 31634const TRACE_FLAG_SAMPLED = 0x1; 31635 31636/** 31637 * Convert a span to a trace context, which can be sent as the `trace` context in an event. 31638 */ 31639function spanToTraceContext(span) { 31640 const { spanId: span_id, traceId: trace_id } = span.spanContext(); 31641 const { data, op, parent_span_id, status, tags, origin } = spanToJSON(span); 31642 31643 return utils.dropUndefinedKeys({ 31644 data, 31645 op, 31646 parent_span_id, 31647 span_id, 31648 status, 31649 tags, 31650 trace_id, 31651 origin, 31652 }); 31653} 31654 31655/** 31656 * Convert a Span to a Sentry trace header. 31657 */ 31658function spanToTraceHeader(span) { 31659 const { traceId, spanId } = span.spanContext(); 31660 const sampled = spanIsSampled(span); 31661 return utils.generateSentryTraceHeader(traceId, spanId, sampled); 31662} 31663 31664/** 31665 * Convert a span time input intp a timestamp in seconds. 31666 */ 31667function spanTimeInputToSeconds(input) { 31668 if (typeof input === 'number') { 31669 return ensureTimestampInSeconds(input); 31670 } 31671 31672 if (Array.isArray(input)) { 31673 // See {@link HrTime} for the array-based time format 31674 return input[0] + input[1] / 1e9; 31675 } 31676 31677 if (input instanceof Date) { 31678 return ensureTimestampInSeconds(input.getTime()); 31679 } 31680 31681 return utils.timestampInSeconds(); 31682} 31683 31684/** 31685 * Converts a timestamp to second, if it was in milliseconds, or keeps it as second. 31686 */ 31687function ensureTimestampInSeconds(timestamp) { 31688 const isMs = timestamp > 9999999999; 31689 return isMs ? timestamp / 1000 : timestamp; 31690} 31691 31692/** 31693 * Convert a span to a JSON representation. 31694 * Note that all fields returned here are optional and need to be guarded against. 31695 *
31696 * Note: Because of this, we currently have a circular type dependency (which we opted out of in package.json). 31697 * This is not avoidable as we need `spanToJSON` in `spanUtils.ts`, which in turn is needed by `span.ts` for backwards compatibility. 31698 * And `spanToJSON` needs the Span class from `span.ts` to check here. 31699 * TODO v8: When we remove the deprecated stuff from `span.ts`, we can remove the circular dependency again. 31700 */ 31701function spanToJSON(span) { 31702 if (spanIsSpanClass(span)) { 31703 return span.getSpanJSON(); 31704 } 31705 31706 // Fallback: We also check for `.toJSON()` here... 31707 // eslint-disable-next-line deprecation/deprecation 31708 if (typeof span.toJSON === 'function') { 31709 // eslint-disable-next-line deprecation/deprecation 31710 return span.toJSON(); 31711 } 31712 31713 return {}; 31714} 31715 31716/** 31717 * Sadly, due to circular dependency checks we cannot actually import the Span class here and check for instanceof. 31718 * :( So instead we approximate this by checking if it has the `getSpanJSON` method. 31719 */ 31720function spanIsSpanClass(span) { 31721 return typeof (span ).getSpanJSON === 'function'; 31722} 31723 31724/** 31725 * Returns true if a span is sampled. 31726 * In most cases, you should just use `span.isRecording()` instead. 31727 * However, this has a slightly different semantic, as it also returns false if the span is finished. 31728 * So in the case where this distinction is important, use this method. 31729 */ 31730function spanIsSampled(span) { 31731 // We align our trace flags with the ones OpenTelemetry use 31732 // So we also check for sampled the same way they do. 31733 const { traceFlags } = span.spanContext(); 31734 // eslint-disable-next-line no-bitwise 31735 return Boolean(traceFlags & TRACE_FLAG_SAMPLED); 31736} 31737 31738exports.TRACE_FLAG_NONE = TRACE_FLAG_NONE; 31739exports.TRACE_FLAG_SAMPLED = TRACE_FLAG_SAMPLED; 31740exports.spanIsSampled = spanIsSampled; 31741exports.spanTimeInputToSeconds = spanTimeInputToSeconds; 31742exports.spanToJSON = spanToJSON; 31743exports.spanToTraceContext = spanToTraceContext; 31744exports.spanToTraceHeader = spanToTraceHeader; 31745 31746 31747},{"@sentry/utils":319}],298:[function(require,module,exports){ 31748Object.defineProperty(exports, '__esModule', { value: true }); 31749 31750const SDK_VERSION = '7.107.0'; 31751 31752exports.SDK_VERSION = SDK_VERSION; 31753 31754 31755},{}],299:[function(require,module,exports){ 31756var { 31757 _nullishCoalesce, 31758 _optionalChain 31759} = require('@sentry/utils'); 31760 31761Object.defineProperty(exports, '__esModule', { value: true }); 31762 31763const core = require('@sentry/core'); 31764const utils = require('@sentry/utils'); 31765const tracing = require('@sentry-internal/tracing'); 31766 31767// exporting a separate copy of `WINDOW` rather than exporting the one from `@sentry/browser` 31768// prevents the browser package from being bundled in the CDN bundle, and avoids a 31769// circular dependency between the browser and replay packages should `@sentry/browser` import 31770// from `@sentry/replay` in the future 31771const WINDOW = utils.GLOBAL_OBJ ; 31772 31773const REPLAY_SESSION_KEY = 'sentryReplaySession'; 31774const REPLAY_EVENT_NAME = 'replay_event'; 31775const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay'; 31776 31777// The idle limit for a session after which recording is paused. 31778const SESSION_IDLE_PAUSE_DURATION = 300000; // 5 minutes in ms 31779 31780// The idle limit for a session after which the session expires. 31781const SESSION_IDLE_EXPIRE_DURATION = 900000; // 15 minutes in ms 31782 31783/** Default flush delays */ 31784const DEFAULT_FLUSH_MIN_DELAY = 5000; 31785// XXX: Temp fix for our debounce logic where `maxWait` would never occur if it 31786// was the same as `wait` 31787const DEFAULT_FLUSH_MAX_DELAY = 5500; 31788 31789/* How long to wait for error checkouts */ 31790const BUFFER_CHECKOUT_TIME = 60000; 31791 31792const RETRY_BASE_INTERVAL = 5000; 31793const RETRY_MAX_COUNT = 3; 31794 31795/* The max (uncompressed) size in bytes of a network body. Any body larger than this will be truncated. */ 31796const NETWORK_BODY_MAX_SIZE = 150000; 31797 31798/* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */ 31799const CONSOLE_ARG_MAX_SIZE = 5000; 31800 31801/* Min. time to wait before we consider something a slow click. */ 31802const SLOW_CLICK_THRESHOLD = 3000; 31803/* For scroll actions after a click, we only look for a very short time period to detect programmatic scrolling. */ 31804const SLOW_CLICK_SCROLL_TIMEOUT = 300; 31805 31806/** When encountering a total segment size exceeding this size, stop the replay (as we cannot properly ingest it). */ 31807const REPLAY_MAX_EVENT_BUFFER_SIZE = 20000000; // ~20MB 31808 31809/** Replays must be min. 5s long before we send them. */ 31810const MIN_REPLAY_DURATION = 4999; 31811/* The max. allowed value that the minReplayDuration can be set to. */ 31812const MIN_REPLAY_DURATION_LIMIT = 15000; 31813 31814/** The max. length of a replay. */ 31815const MAX_REPLAY_DURATION = 3600000; // 60 minutes in ms; 31816 31817function _nullishCoalesce$1(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var NodeType$1; 31818(function (NodeType) { 31819 NodeType[NodeType["Document"] = 0] = "Document"; 31820 NodeType[NodeType["DocumentType"] = 1] = "DocumentType"; 31821 NodeType[NodeType["Element"] = 2] = "Element"; 31822 NodeType[NodeType["Text"] = 3] = "Text"; 31823 NodeType[NodeType["CDATA"] = 4] = "CDATA"; 31824 NodeType[NodeType["Comment"] = 5] = "Comment"; 31825})(NodeType$1 || (NodeType$1 = {})); 31826 31827function isElement$1(n) { 31828 return n.nodeType === n.ELEMENT_NODE; 31829} 31830function isShadowRoot(n) { 31831 const host = _optionalChain$5([n, 'optionalAccess', _ => _.host]); 31832 return Boolean(_optionalChain$5([host, 'optionalAccess', _2 => _2.shadowRoot]) === n); 31833} 31834function isNativeShadowDom(shadowRoot) { 31835 return Object.prototype.toString.call(shadowRoot) === '[object ShadowRoot]'; 31836} 31837function fixBrowserCompatibilityIssuesInCSS(cssText) { 31838 if (cssText.includes(' background-clip: text;') && 31839 !cssText.includes(' -webkit-background-clip: text;')) { 31840 cssText = cssText.replace(' background-clip: text;', ' -webkit-background-clip: text; background-clip: text;'); 31841 } 31842 return cssText; 31843}
31844function escapeImportStatement(rule) { 31845 const { cssText } = rule; 31846 if (cssText.split('"').length < 3) 31847 return cssText; 31848 const statement = ['@import', `url(${JSON.stringify(rule.href)})`]; 31849 if (rule.layerName === '') { 31850 statement.push(`layer`); 31851 } 31852 else if (rule.layerName) { 31853 statement.push(`layer(${rule.layerName})`); 31854 } 31855 if (rule.supportsText) { 31856 statement.push(`supports(${rule.supportsText})`); 31857 } 31858 if (rule.media.length) { 31859 statement.push(rule.media.mediaText); 31860 } 31861 return statement.join(' ') + ';'; 31862} 31863function stringifyStylesheet(s) { 31864 try { 31865 const rules = s.rules || s.cssRules; 31866 return rules 31867 ? fixBrowserCompatibilityIssuesInCSS(Array.from(rules, stringifyRule).join('')) 31868 : null; 31869 } 31870 catch (error) { 31871 return null; 31872 } 31873} 31874function stringifyRule(rule) { 31875 let importStringified; 31876 if (isCSSImportRule(rule)) { 31877 try { 31878 importStringified = 31879 stringifyStylesheet(rule.styleSheet) || 31880 escapeImportStatement(rule); 31881 } 31882 catch (error) { 31883 } 31884 } 31885 else if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) { 31886 return fixSafariColons(rule.cssText); 31887 } 31888 return importStringified || rule.cssText; 31889} 31890function fixSafariColons(cssStringified) { 31891 const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm; 31892 return cssStringified.replace(regex, '$1\\$2'); 31893} 31894function isCSSImportRule(rule) { 31895 return 'styleSheet' in rule; 31896} 31897function isCSSStyleRule(rule) { 31898 return 'selectorText' in rule; 31899} 31900class Mirror { 31901 constructor() { 31902 this.idNodeMap = new Map(); 31903 this.nodeMetaMap = new WeakMap(); 31904 } 31905 getId(n) { 31906 if (!n) 31907 return -1; 31908 const id = _optionalChain$5([this, 'access', _3 => _3.getMeta, 'call', _4 => _4(n), 'optionalAccess', _5 => _5.id]); 31909 return _nullishCoalesce$1(id, () => ( -1)); 31910 } 31911 getNode(id) { 31912 return this.idNodeMap.get(id) || null; 31913 } 31914 getIds() { 31915 return Array.from(this.idNodeMap.keys()); 31916 } 31917 getMeta(n) { 31918 return this.nodeMetaMap.get(n) || null; 31919 } 31920 removeNodeFromMap(n) { 31921 const id = this.getId(n); 31922 this.idNodeMap.delete(id); 31923 if (n.childNodes) { 31924 n.childNodes.forEach((childNode) => this.removeNodeFromMap(childNode)); 31925 } 31926 } 31927 has(id) { 31928 return this.idNodeMap.has(id); 31929 } 31930 hasNode(node) { 31931 return this.nodeMetaMap.has(node); 31932 } 31933 add(n, meta) { 31934 const id = meta.id; 31935 this.idNodeMap.set(id, n); 31936 this.nodeMetaMap.set(n, meta); 31937 } 31938 replace(id, n) { 31939 const oldNode = this.getNode(id); 31940 if (oldNode) { 31941 const meta = this.nodeMetaMap.get(oldNode); 31942 if (meta) 31943 this.nodeMetaMap.set(n, meta); 31944 } 31945 this.idNodeMap.set(id, n); 31946 } 31947 reset() { 31948 this.idNodeMap = new Map(); 31949 this.nodeMetaMap = new WeakMap(); 31950 } 31951} 31952function createMirror() { 31953 return new Mirror(); 31954} 31955function shouldMaskInput({ maskInputOptions, tagName, type, }) { 31956 if (tagName === 'OPTION') { 31957 tagName = 'SELECT'; 31958 } 31959 return Boolean(maskInputOptions[tagName.toLowerCase()] || 31960 (type && maskInputOptions[type]) || 31961 type === 'password' || 31962 (tagName === 'INPUT' && !type && maskInputOptions['text'])); 31963} 31964function maskInputValue({ isMasked, element, value, maskInputFn, }) { 31965 let text = value || ''; 31966 if (!isMasked) { 31967 return text; 31968 } 31969 if (maskInputFn) { 31970 text = maskInputFn(text, element); 31971 } 31972 return '*'.repeat(text.length); 31973} 31974function toLowerCase(str) { 31975 return str.toLowerCase(); 31976} 31977function toUpperCase(str) { 31978 return str.toUpperCase(); 31979} 31980const ORIGINAL_ATTRIBUTE_NAME = '__rrweb_original__'; 31981function is2DCanvasBlank(canvas) { 31982 const ctx = canvas.getContext('2d'); 31983 if (!ctx) 31984 return true; 31985 const chunkSize = 50; 31986 for (let x = 0; x < canvas.width; x += chunkSize) { 31987 for (let y = 0; y < canvas.height; y += chunkSize) { 31988 const getImageData = ctx.getImageData; 31989 const originalGetImageData = ORIGINAL_ATTRIBUTE_NAME in getImageData 31990 ? getImageData[ORIGINAL_ATTRIBUTE_NAME] 31991 : getImageData; 31992 const pixelBuffer = new Uint32Array(originalGetImageData.call(ctx, x, y, Math.min(chunkSize, canvas.width - x), Math.min(chunkSize, canvas.height - y)).data.buffer); 31993 if (pixelBuffer.some((pixel) => pixel !== 0)) 31994 return false;
vendor: 4,204 bytes, lines 31995-32131
31995 } 31996 } 31997 return true; 31998} 31999function getInputType(element) { 32000 const type = element.type; 32001 return element.hasAttribute('data-rr-is-password') 32002 ? 'password' 32003 : type 32004 ? 32005 toLowerCase(type) 32006 : null; 32007} 32008function getInputValue(el, tagName, type) { 32009 if (tagName === 'INPUT' && (type === 'radio' || type === 'checkbox')) { 32010 return el.getAttribute('value') || ''; 32011 } 32012 return el.value; 32013} 32014 32015let _id = 1; 32016const tagNameRegex = new RegExp('[^a-z0-9-_:]'); 32017const IGNORED_NODE = -2; 32018function genId() { 32019 return _id++; 32020} 32021function getValidTagName(element) { 32022 if (element instanceof HTMLFormElement) { 32023 return 'form'; 32024 } 32025 const processedTagName = toLowerCase(element.tagName); 32026 if (tagNameRegex.test(processedTagName)) { 32027 return 'div'; 32028 } 32029 return processedTagName; 32030} 32031function extractOrigin(url) { 32032 let origin = ''; 32033 if (url.indexOf('//') > -1) { 32034 origin = url.split('/').slice(0, 3).join('/'); 32035 } 32036 else { 32037 origin = url.split('/')[0]; 32038 } 32039 origin = origin.split('?')[0]; 32040 return origin; 32041} 32042let canvasService; 32043let canvasCtx; 32044const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm; 32045const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i; 32046const URL_WWW_MATCH = /^www\..*/i; 32047const DATA_URI = /^(data:)([^,]*),(.*)/i; 32048function absoluteToStylesheet(cssText, href) { 32049 return (cssText || '').replace(URL_IN_CSS_REF, (origin, quote1, path1, quote2, path2, path3) => { 32050 const filePath = path1 || path2 || path3; 32051 const maybeQuote = quote1 || quote2 || ''; 32052 if (!filePath) { 32053 return origin; 32054 } 32055 if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) { 32056 return `url(${maybeQuote}${filePath}${maybeQuote})`; 32057 } 32058 if (DATA_URI.test(filePath)) { 32059 return `url(${maybeQuote}${filePath}${maybeQuote})`; 32060 } 32061 if (filePath[0] === '/') { 32062 return `url(${maybeQuote}${extractOrigin(href) + filePath}${maybeQuote})`; 32063 } 32064 const stack = href.split('/'); 32065 const parts = filePath.split('/'); 32066 stack.pop(); 32067 for (const part of parts) { 32068 if (part === '.') { 32069 continue; 32070 } 32071 else if (part === '..') { 32072 stack.pop(); 32073 } 32074 else { 32075 stack.push(part); 32076 } 32077 } 32078 return `url(${maybeQuote}${stack.join('/')}${maybeQuote})`; 32079 }); 32080} 32081const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/; 32082const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/; 32083function getAbsoluteSrcsetString(doc, attributeValue) { 32084 if (attributeValue.trim() === '') { 32085 return attributeValue; 32086 } 32087 let pos = 0; 32088 function collectCharacters(regEx) { 32089 let chars; 32090 const match = regEx.exec(attributeValue.substring(pos)); 32091 if (match) { 32092 chars = match[0]; 32093 pos += chars.length; 32094 return chars; 32095 } 32096 return ''; 32097 } 32098 const output = []; 32099 while (true) { 32100 collectCharacters(SRCSET_COMMAS_OR_SPACES); 32101 if (pos >= attributeValue.length) { 32102 break; 32103 } 32104 let url = collectCharacters(SRCSET_NOT_SPACES); 32105 if (url.slice(-1) === ',') { 32106 url = absoluteToDoc(doc, url.substring(0, url.length - 1)); 32107 output.push(url); 32108 } 32109 else { 32110 let descriptorsStr = ''; 32111 url = absoluteToDoc(doc, url); 32112 let inParens = false; 32113 while (true) { 32114 const c = attributeValue.charAt(pos); 32115 if (c === '') { 32116 output.push((url + descriptorsStr).trim()); 32117 break; 32118 } 32119 else if (!inParens) { 32120 if (c === ',') { 32121 pos += 1; 32122 output.push((url + descriptorsStr).trim()); 32123 break; 32124 } 32125 else if (c === '(') { 32126 inParens = true; 32127 } 32128 } 32129 else { 32130 if (c === ')') { 32131 inParens = false;
32132 } 32133 } 32134 descriptorsStr += c; 32135 pos += 1; 32136 } 32137 } 32138 } 32139 return output.join(', '); 32140} 32141function absoluteToDoc(doc, attributeValue) { 32142 if (!attributeValue || attributeValue.trim() === '') { 32143 return attributeValue; 32144 } 32145 const a = doc.createElement('a'); 32146 a.href = attributeValue; 32147 return a.href; 32148} 32149function isSVGElement(el) { 32150 return Boolean(el.tagName === 'svg' || el.ownerSVGElement); 32151} 32152function getHref() { 32153 const a = document.createElement('a'); 32154 a.href = ''; 32155 return a.href; 32156} 32157function transformAttribute(doc, tagName, name, value, element, maskAttributeFn) { 32158 if (!value) { 32159 return value; 32160 } 32161 if (name === 'src' || 32162 (name === 'href' && !(tagName === 'use' && value[0] === '#'))) { 32163 return absoluteToDoc(doc, value); 32164 } 32165 else if (name === 'xlink:href' && value[0] !== '#') { 32166 return absoluteToDoc(doc, value); 32167 } 32168 else if (name === 'background' && 32169 (tagName === 'table' || tagName === 'td' || tagName === 'th')) { 32170 return absoluteToDoc(doc, value); 32171 } 32172 else if (name === 'srcset') { 32173 return getAbsoluteSrcsetString(doc, value); 32174 } 32175 else if (name === 'style') { 32176 return absoluteToStylesheet(value, getHref()); 32177 } 32178 else if (tagName === 'object' && name === 'data') { 32179 return absoluteToDoc(doc, value); 32180 } 32181 if (typeof maskAttributeFn === 'function') { 32182 return maskAttributeFn(name, value, element); 32183 } 32184 return value; 32185} 32186function ignoreAttribute(tagName, name, _value) { 32187 return (tagName === 'video' || tagName === 'audio') && name === 'autoplay'; 32188} 32189function _isBlockedElement(element, blockClass, blockSelector, unblockSelector) { 32190 try { 32191 if (unblockSelector && element.matches(unblockSelector)) { 32192 return false; 32193 } 32194 if (typeof blockClass === 'string') { 32195 if (element.classList.contains(blockClass)) { 32196 return true; 32197 } 32198 } 32199 else { 32200 for (let eIndex = element.classList.length; eIndex--;) { 32201 const className = element.classList[eIndex]; 32202 if (blockClass.test(className)) { 32203 return true; 32204 } 32205 } 32206 } 32207 if (blockSelector) { 32208 return element.matches(blockSelector); 32209 } 32210 } 32211 catch (e) { 32212 } 32213 return false; 32214} 32215function elementClassMatchesRegex(el, regex) { 32216 for (let eIndex = el.classList.length; eIndex--;) { 32217 const className = el.classList[eIndex]; 32218 if (regex.test(className)) { 32219 return true; 32220 } 32221 } 32222 return false; 32223} 32224function distanceToMatch(node, matchPredicate, limit = Infinity, distance = 0) { 32225 if (!node) 32226 return -1; 32227 if (node.nodeType !== node.ELEMENT_NODE) 32228 return -1; 32229 if (distance > limit) 32230 return -1; 32231 if (matchPredicate(node)) 32232 return distance; 32233 return distanceToMatch(node.parentNode, matchPredicate, limit, distance + 1); 32234} 32235function createMatchPredicate(className, selector) { 32236 return (node) => { 32237 const el = node; 32238 if (el === null) 32239 return false; 32240 try { 32241 if (className) { 32242 if (typeof className === 'string') { 32243 if (el.matches(`.${className}`)) 32244 return true; 32245 } 32246 else if (elementClassMatchesRegex(el, className)) { 32247 return true; 32248 } 32249 } 32250 if (selector && el.matches(selector)) 32251 return true; 32252 return false; 32253 } 32254 catch (e2) { 32255 return false; 32256 } 32257 }; 32258} 32259function needMaskingText(node, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, maskAllText) { 32260 try { 32261 const el = node.nodeType === node.ELEMENT_NODE 32262 ? node 32263 : node.parentElement; 32264 if (el === null) 32265 return false; 32266 if (el.tagName === 'INPUT') { 32267 const autocomplete = el.getAttribute('autocomplete'); 32268 const disallowedAutocompleteValues = [ 32269 'current-password', 32270 'new-password', 32271 'cc-number', 32272 'cc-exp', 32273 'cc-exp-month', 32274 'cc-exp-year', 32275 'cc-csc', 32276 ]; 32277 if (disallowedAutocompleteValues.includes(autocomplete)) { 32278 return true; 32279 } 32280 } 32281 let maskDistance = -1; 32282 let unmaskDistance = -1; 32283 if (maskAllText) { 32284 unmaskDistance = distanceToMatch(el, createMatchPredicate(unmaskTextClass, unmaskTextSelector)); 32285 if (unmaskDistance < 0) { 32286 return true; 32287 } 32288 maskDistance = distanceToMatch(el, createMatchPredicate(maskTextClass, maskTextSelector), unmaskDistance >= 0 ? unmaskDistance : Infinity); 32289 } 32290 else { 32291 maskDistance = distanceToMatch(el, createMatchPredicate(maskTextClass, maskTextSelector)); 32292 if (maskDistance < 0) { 32293 return false;
32294 } 32295 unmaskDistance = distanceToMatch(el, createMatchPredicate(unmaskTextClass, unmaskTextSelector), maskDistance >= 0 ? maskDistance : Infinity); 32296 } 32297 return maskDistance >= 0 32298 ? unmaskDistance >= 0 32299 ? maskDistance <= unmaskDistance 32300 : true 32301 : unmaskDistance >= 0 32302 ? false 32303 : !!maskAllText; 32304 } 32305 catch (e) { 32306 } 32307 return !!maskAllText; 32308} 32309function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) { 32310 const win = iframeEl.contentWindow; 32311 if (!win) { 32312 return; 32313 } 32314 let fired = false; 32315 let readyState; 32316 try { 32317 readyState = win.document.readyState; 32318 } 32319 catch (error) { 32320 return; 32321 } 32322 if (readyState !== 'complete') { 32323 const timer = setTimeout(() => { 32324 if (!fired) { 32325 listener(); 32326 fired = true; 32327 } 32328 }, iframeLoadTimeout); 32329 iframeEl.addEventListener('load', () => { 32330 clearTimeout(timer); 32331 fired = true; 32332 listener(); 32333 }); 32334 return; 32335 } 32336 const blankUrl = 'about:blank'; 32337 if (win.location.href !== blankUrl || 32338 iframeEl.src === blankUrl || 32339 iframeEl.src === '') { 32340 setTimeout(listener, 0); 32341 return iframeEl.addEventListener('load', listener); 32342 } 32343 iframeEl.addEventListener('load', listener); 32344} 32345function onceStylesheetLoaded(link, listener, styleSheetLoadTimeout) { 32346 let fired = false; 32347 let styleSheetLoaded; 32348 try { 32349 styleSheetLoaded = link.sheet; 32350 } 32351 catch (error) { 32352 return; 32353 } 32354 if (styleSheetLoaded) 32355 return; 32356 const timer = setTimeout(() => { 32357 if (!fired) { 32358 listener(); 32359 fired = true; 32360 } 32361 }, styleSheetLoadTimeout); 32362 link.addEventListener('load', () => { 32363 clearTimeout(timer); 32364 fired = true; 32365 listener(); 32366 }); 32367} 32368function serializeNode(n, options) { 32369 const { doc, mirror, blockClass, blockSelector, unblockSelector, maskAllText, maskAttributeFn, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, inlineStylesheet, maskInputOptions = {}, maskTextFn, maskInputFn, dataURLOptions = {}, inlineImages, recordCanvas, keepIframeSrcFn, newlyAddedElement = false, } = options; 32370 const rootId = getRootId(doc, mirror); 32371 switch (n.nodeType) { 32372 case n.DOCUMENT_NODE: 32373 if (n.compatMode !== 'CSS1Compat') { 32374 return { 32375 type: NodeType$1.Document, 32376 childNodes: [], 32377 compatMode: n.compatMode, 32378 }; 32379 } 32380 else { 32381 return { 32382 type: NodeType$1.Document, 32383 childNodes: [], 32384 }; 32385 } 32386 case n.DOCUMENT_TYPE_NODE: 32387 return { 32388 type: NodeType$1.DocumentType, 32389 name: n.name, 32390 publicId: n.publicId, 32391 systemId: n.systemId, 32392 rootId, 32393 }; 32394 case n.ELEMENT_NODE: 32395 return serializeElementNode(n, { 32396 doc, 32397 blockClass, 32398 blockSelector, 32399 unblockSelector, 32400 inlineStylesheet, 32401 maskAttributeFn, 32402 maskInputOptions, 32403 maskInputFn, 32404 dataURLOptions, 32405 inlineImages, 32406 recordCanvas, 32407 keepIframeSrcFn, 32408 newlyAddedElement, 32409 rootId, 32410 maskAllText, 32411 maskTextClass, 32412 unmaskTextClass, 32413 maskTextSelector, 32414 unmaskTextSelector, 32415 }); 32416 case n.TEXT_NODE: 32417 return serializeTextNode(n, { 32418 maskAllText, 32419 maskTextClass, 32420 unmaskTextClass, 32421 maskTextSelector, 32422 unmaskTextSelector, 32423 maskTextFn, 32424 maskInputOptions, 32425 maskInputFn, 32426 rootId, 32427 }); 32428 case n.CDATA_SECTION_NODE: 32429 return { 32430 type: NodeType$1.CDATA, 32431 textContent: '', 32432 rootId, 32433 }; 32434 case n.COMMENT_NODE: 32435 return { 32436 type: NodeType$1.Comment, 32437 textContent: n.textContent || '', 32438 rootId, 32439 }; 32440 default: 32441 return false;
32442 } 32443} 32444function getRootId(doc, mirror) { 32445 if (!mirror.hasNode(doc)) 32446 return undefined; 32447 const docId = mirror.getId(doc); 32448 return docId === 1 ? undefined : docId; 32449} 32450function serializeTextNode(n, options) { 32451 const { maskAllText, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, maskTextFn, maskInputOptions, maskInputFn, rootId, } = options; 32452 const parentTagName = n.parentNode && n.parentNode.tagName; 32453 let textContent = n.textContent; 32454 const isStyle = parentTagName === 'STYLE' ? true : undefined; 32455 const isScript = parentTagName === 'SCRIPT' ? true : undefined; 32456 const isTextarea = parentTagName === 'TEXTAREA' ? true : undefined; 32457 if (isStyle && textContent) { 32458 try { 32459 if (n.nextSibling || n.previousSibling) { 32460 } 32461 else if (_optionalChain$5([n, 'access', _6 => _6.parentNode, 'access', _7 => _7.sheet, 'optionalAccess', _8 => _8.cssRules])) { 32462 textContent = stringifyStylesheet(n.parentNode.sheet); 32463 } 32464 } 32465 catch (err) { 32466 console.warn(`Cannot get CSS styles from text's parentNode. Error: ${err}`, n); 32467 } 32468 textContent = absoluteToStylesheet(textContent, getHref()); 32469 } 32470 if (isScript) { 32471 textContent = 'SCRIPT_PLACEHOLDER'; 32472 } 32473 const forceMask = needMaskingText(n, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, maskAllText); 32474 if (!isStyle && !isScript && !isTextarea && textContent && forceMask) { 32475 textContent = maskTextFn 32476 ? maskTextFn(textContent) 32477 : textContent.replace(/[\S]/g, '*'); 32478 } 32479 if (isTextarea && textContent && (maskInputOptions.textarea || forceMask)) { 32480 textContent = maskInputFn 32481 ? maskInputFn(textContent, n.parentNode) 32482 : textContent.replace(/[\S]/g, '*'); 32483 } 32484 if (parentTagName === 'OPTION' && textContent) { 32485 const isInputMasked = shouldMaskInput({ 32486 type: null, 32487 tagName: parentTagName, 32488 maskInputOptions, 32489 }); 32490 textContent = maskInputValue({ 32491 isMasked: needMaskingText(n, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, isInputMasked), 32492 element: n, 32493 value: textContent, 32494 maskInputFn, 32495 }); 32496 } 32497 return { 32498 type: NodeType$1.Text, 32499 textContent: textContent || '', 32500 isStyle, 32501 rootId, 32502 }; 32503} 32504function serializeElementNode(n, options) { 32505 const { doc, blockClass, blockSelector, unblockSelector, inlineStylesheet, maskInputOptions = {}, maskAttributeFn, maskInputFn, dataURLOptions = {}, inlineImages, recordCanvas, keepIframeSrcFn, newlyAddedElement = false, rootId, maskAllText, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, } = options; 32506 const needBlock = _isBlockedElement(n, blockClass, blockSelector, unblockSelector); 32507 const tagName = getValidTagName(n); 32508 let attributes = {}; 32509 const len = n.attributes.length; 32510 for (let i = 0; i < len; i++) { 32511 const attr = n.attributes[i]; 32512 if (attr.name && !ignoreAttribute(tagName, attr.name, attr.value)) { 32513 attributes[attr.name] = transformAttribute(doc, tagName, toLowerCase(attr.name), attr.value, n, maskAttributeFn); 32514 } 32515 } 32516 if (tagName === 'link' && inlineStylesheet) { 32517 const stylesheet = Array.from(doc.styleSheets).find((s) => { 32518 return s.href === n.href; 32519 }); 32520 let cssText = null; 32521 if (stylesheet) { 32522 cssText = stringifyStylesheet(stylesheet); 32523 } 32524 if (cssText) { 32525 delete attributes.rel; 32526 delete attributes.href; 32527 attributes._cssText = absoluteToStylesheet(cssText, stylesheet.href); 32528 } 32529 } 32530 if (tagName === 'style' && 32531 n.sheet && 32532 !(n.innerText || n.textContent || '').trim().length) { 32533 const cssText = stringifyStylesheet(n.sheet); 32534 if (cssText) { 32535 attributes._cssText = absoluteToStylesheet(cssText, getHref()); 32536 } 32537 } 32538 if (tagName === 'input' || 32539 tagName === 'textarea' || 32540 tagName === 'select' || 32541 tagName === 'option') { 32542 const el = n; 32543 const type = getInputType(el); 32544 const value = getInputValue(el, toUpperCase(tagName), type); 32545 const checked = el.checked; 32546 if (type !== 'submit' && type !== 'button' && value) { 32547 const forceMask = needMaskingText(el, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, shouldMaskInput({ 32548 type, 32549 tagName: toUpperCase(tagName), 32550 maskInputOptions, 32551 })); 32552 attributes.value = maskInputValue({ 32553 isMasked: forceMask, 32554 element: el, 32555 value, 32556 maskInputFn, 32557 }); 32558 } 32559 if (checked) { 32560 attributes.checked = checked; 32561 } 32562 } 32563 if (tagName === 'option') { 32564 if (n.selected && !maskInputOptions['select']) { 32565 attributes.selected = true; 32566 } 32567 else { 32568 delete attributes.selected; 32569 } 32570 } 32571 if (tagName === 'canvas' && recordCanvas) { 32572 if (n.__context === '2d') { 32573 if (!is2DCanvasBlank(n)) { 32574 attributes.rr_dataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality); 32575 } 32576 } 32577 else if (!('__context' in n)) { 32578 const canvasDataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality); 32579 const blankCanvas = document.createElement('canvas'); 32580 blankCanvas.width = n.width; 32581 blankCanvas.height = n.height; 32582 const blankCanvasDataURL = blankCanvas.toDataURL(dataURLOptions.type, dataURLOptions.quality); 32583 if (canvasDataURL !== blankCanvasDataURL) { 32584 attributes.rr_dataURL = canvasDataURL; 32585 } 32586 } 32587 } 32588 if (tagName === 'img' && inlineImages) { 32589 if (!canvasService) { 32590 canvasService = doc.createElement('canvas'); 32591 canvasCtx = canvasService.getContext('2d'); 32592 } 32593 const image = n; 32594 const oldValue = image.crossOrigin; 32595 image.crossOrigin = 'anonymous'; 32596 const recordInlineImage = () => { 32597 image.removeEventListener('load', recordInlineImage); 32598 try {
32599 canvasService.width = image.naturalWidth; 32600 canvasService.height = image.naturalHeight; 32601 canvasCtx.drawImage(image, 0, 0); 32602 attributes.rr_dataURL = canvasService.toDataURL(dataURLOptions.type, dataURLOptions.quality); 32603 } 32604 catch (err) { 32605 console.warn(`Cannot inline img src=${image.currentSrc}! Error: ${err}`); 32606 } 32607 oldValue 32608 ? (attributes.crossOrigin = oldValue) 32609 : image.removeAttribute('crossorigin'); 32610 }; 32611 if (image.complete && image.naturalWidth !== 0) 32612 recordInlineImage(); 32613 else 32614 image.addEventListener('load', recordInlineImage); 32615 } 32616 if (tagName === 'audio' || tagName === 'video') { 32617 attributes.rr_mediaState = n.paused 32618 ? 'paused' 32619 : 'played'; 32620 attributes.rr_mediaCurrentTime = n.currentTime; 32621 } 32622 if (!newlyAddedElement) { 32623 if (n.scrollLeft) { 32624 attributes.rr_scrollLeft = n.scrollLeft; 32625 } 32626 if (n.scrollTop) { 32627 attributes.rr_scrollTop = n.scrollTop; 32628 } 32629 } 32630 if (needBlock) { 32631 const { width, height } = n.getBoundingClientRect(); 32632 attributes = { 32633 class: attributes.class, 32634 rr_width: `${width}px`, 32635 rr_height: `${height}px`, 32636 }; 32637 } 32638 if (tagName === 'iframe' && !keepIframeSrcFn(attributes.src)) { 32639 if (!n.contentDocument) { 32640 attributes.rr_src = attributes.src; 32641 } 32642 delete attributes.src; 32643 } 32644 let isCustomElement; 32645 try { 32646 if (customElements.get(tagName)) 32647 isCustomElement = true; 32648 } 32649 catch (e) { 32650 } 32651 return { 32652 type: NodeType$1.Element, 32653 tagName, 32654 attributes, 32655 childNodes: [], 32656 isSVG: isSVGElement(n) || undefined, 32657 needBlock, 32658 rootId, 32659 isCustom: isCustomElement, 32660 }; 32661} 32662function lowerIfExists(maybeAttr) { 32663 if (maybeAttr === undefined || maybeAttr === null) { 32664 return ''; 32665 } 32666 else { 32667 return maybeAttr.toLowerCase(); 32668 } 32669} 32670function slimDOMExcluded(sn, slimDOMOptions) { 32671 if (slimDOMOptions.comment && sn.type === NodeType$1.Comment) { 32672 return true; 32673 } 32674 else if (sn.type === NodeType$1.Element) { 32675 if (slimDOMOptions.script && 32676 (sn.tagName === 'script' || 32677 (sn.tagName === 'link' && 32678 (sn.attributes.rel === 'preload' || 32679 sn.attributes.rel === 'modulepreload') && 32680 sn.attributes.as === 'script') || 32681 (sn.tagName === 'link' && 32682 sn.attributes.rel === 'prefetch' && 32683 typeof sn.attributes.href === 'string' && 32684 sn.attributes.href.endsWith('.js')))) { 32685 return true; 32686 } 32687 else if (slimDOMOptions.headFavicon && 32688 ((sn.tagName === 'link' && sn.attributes.rel === 'shortcut icon') || 32689 (sn.tagName === 'meta' && 32690 (lowerIfExists(sn.attributes.name).match(/^msapplication-tile(image|color)$/) || 32691 lowerIfExists(sn.attributes.name) === 'application-name' || 32692 lowerIfExists(sn.attributes.rel) === 'icon' || 32693 lowerIfExists(sn.attributes.rel) === 'apple-touch-icon' || 32694 lowerIfExists(sn.attributes.rel) === 'shortcut icon')))) { 32695 return true; 32696 } 32697 else if (sn.tagName === 'meta') { 32698 if (slimDOMOptions.headMetaDescKeywords && 32699 lowerIfExists(sn.attributes.name).match(/^description|keywords$/)) { 32700 return true; 32701 } 32702 else if (slimDOMOptions.headMetaSocial && 32703 (lowerIfExists(sn.attributes.property).match(/^(og|twitter|fb):/) || 32704 lowerIfExists(sn.attributes.name).match(/^(og|twitter):/) || 32705 lowerIfExists(sn.attributes.name) === 'pinterest')) { 32706 return true; 32707 } 32708 else if (slimDOMOptions.headMetaRobots && 32709 (lowerIfExists(sn.attributes.name) === 'robots' || 32710 lowerIfExists(sn.attributes.name) === 'googlebot' || 32711 lowerIfExists(sn.attributes.name) === 'bingbot')) { 32712 return true; 32713 } 32714 else if (slimDOMOptions.headMetaHttpEquiv && 32715 sn.attributes['http-equiv'] !== undefined) { 32716 return true; 32717 } 32718 else if (slimDOMOptions.headMetaAuthorship && 32719 (lowerIfExists(sn.attributes.name) === 'author' || 32720 lowerIfExists(sn.attributes.name) === 'generator' || 32721 lowerIfExists(sn.attributes.name) === 'framework' || 32722 lowerIfExists(sn.attributes.name) === 'publisher' || 32723 lowerIfExists(sn.attributes.name) === 'progid' || 32724 lowerIfExists(sn.attributes.property).match(/^article:/) || 32725 lowerIfExists(sn.attributes.property).match(/^product:/))) { 32726 return true; 32727 } 32728 else if (slimDOMOptions.headMetaVerification && 32729 (lowerIfExists(sn.attributes.name) === 'google-site-verification' || 32730 lowerIfExists(sn.attributes.name) === 'yandex-verification' || 32731 lowerIfExists(sn.attributes.name) === 'csrf-token' || 32732 lowerIfExists(sn.attributes.name) === 'p:domain_verify' || 32733 lowerIfExists(sn.attributes.name) === 'verify-v1' || 32734 lowerIfExists(sn.attributes.name) === 'verification' || 32735 lowerIfExists(sn.attributes.name) === 'shopify-checkout-api-token')) { 32736 return true; 32737 } 32738 } 32739 } 32740 return false;
32741} 32742function serializeNodeWithId(n, options) { 32743 const { doc, mirror, blockClass, blockSelector, unblockSelector, maskAllText, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, skipChild = false, inlineStylesheet = true, maskInputOptions = {}, maskAttributeFn, maskTextFn, maskInputFn, slimDOMOptions, dataURLOptions = {}, inlineImages = false, recordCanvas = false, onSerialize, onIframeLoad, iframeLoadTimeout = 5000, onStylesheetLoad, stylesheetLoadTimeout = 5000, keepIframeSrcFn = () => false, newlyAddedElement = false, } = options; 32744 let { preserveWhiteSpace = true } = options; 32745 const _serializedNode = serializeNode(n, { 32746 doc, 32747 mirror, 32748 blockClass, 32749 blockSelector, 32750 maskAllText, 32751 unblockSelector, 32752 maskTextClass, 32753 unmaskTextClass, 32754 maskTextSelector, 32755 unmaskTextSelector, 32756 inlineStylesheet, 32757 maskInputOptions, 32758 maskAttributeFn, 32759 maskTextFn, 32760 maskInputFn, 32761 dataURLOptions, 32762 inlineImages, 32763 recordCanvas, 32764 keepIframeSrcFn, 32765 newlyAddedElement, 32766 }); 32767 if (!_serializedNode) { 32768 console.warn(n, 'not serialized'); 32769 return null; 32770 } 32771 let id; 32772 if (mirror.hasNode(n)) { 32773 id = mirror.getId(n); 32774 } 32775 else if (slimDOMExcluded(_serializedNode, slimDOMOptions) || 32776 (!preserveWhiteSpace && 32777 _serializedNode.type === NodeType$1.Text && 32778 !_serializedNode.isStyle && 32779 !_serializedNode.textContent.replace(/^\s+|\s+$/gm, '').length)) { 32780 id = IGNORED_NODE; 32781 } 32782 else { 32783 id = genId(); 32784 } 32785 const serializedNode = Object.assign(_serializedNode, { id }); 32786 mirror.add(n, serializedNode); 32787 if (id === IGNORED_NODE) { 32788 return null; 32789 } 32790 if (onSerialize) { 32791 onSerialize(n); 32792 } 32793 let recordChild = !skipChild; 32794 if (serializedNode.type === NodeType$1.Element) { 32795 recordChild = recordChild && !serializedNode.needBlock; 32796 delete serializedNode.needBlock; 32797 const shadowRoot = n.shadowRoot; 32798 if (shadowRoot && isNativeShadowDom(shadowRoot)) 32799 serializedNode.isShadowHost = true; 32800 } 32801 if ((serializedNode.type === NodeType$1.Document || 32802 serializedNode.type === NodeType$1.Element) && 32803 recordChild) { 32804 if (slimDOMOptions.headWhitespace && 32805 serializedNode.type === NodeType$1.Element && 32806 serializedNode.tagName === 'head') { 32807 preserveWhiteSpace = false; 32808 } 32809 const bypassOptions = { 32810 doc, 32811 mirror, 32812 blockClass, 32813 blockSelector, 32814 maskAllText, 32815 unblockSelector, 32816 maskTextClass, 32817 unmaskTextClass, 32818 maskTextSelector, 32819 unmaskTextSelector, 32820 skipChild, 32821 inlineStylesheet, 32822 maskInputOptions, 32823 maskAttributeFn, 32824 maskTextFn, 32825 maskInputFn, 32826 slimDOMOptions, 32827 dataURLOptions, 32828 inlineImages, 32829 recordCanvas, 32830 preserveWhiteSpace, 32831 onSerialize, 32832 onIframeLoad, 32833 iframeLoadTimeout, 32834 onStylesheetLoad, 32835 stylesheetLoadTimeout, 32836 keepIframeSrcFn, 32837 }; 32838 for (const childN of Array.from(n.childNodes)) { 32839 const serializedChildNode = serializeNodeWithId(childN, bypassOptions); 32840 if (serializedChildNode) { 32841 serializedNode.childNodes.push(serializedChildNode); 32842 } 32843 } 32844 if (isElement$1(n) && n.shadowRoot) { 32845 for (const childN of Array.from(n.shadowRoot.childNodes)) { 32846 const serializedChildNode = serializeNodeWithId(childN, bypassOptions); 32847 if (serializedChildNode) { 32848 isNativeShadowDom(n.shadowRoot) && 32849 (serializedChildNode.isShadow = true); 32850 serializedNode.childNodes.push(serializedChildNode); 32851 } 32852 } 32853 } 32854 } 32855 if (n.parentNode && 32856 isShadowRoot(n.parentNode) && 32857 isNativeShadowDom(n.parentNode)) { 32858 serializedNode.isShadow = true; 32859 } 32860 if (serializedNode.type === NodeType$1.Element && 32861 serializedNode.tagName === 'iframe') { 32862 onceIframeLoaded(n, () => { 32863 const iframeDoc = n.contentDocument; 32864 if (iframeDoc && onIframeLoad) { 32865 const serializedIframeNode = serializeNodeWithId(iframeDoc, { 32866 doc: iframeDoc, 32867 mirror, 32868 blockClass, 32869 blockSelector, 32870 unblockSelector, 32871 maskAllText, 32872 maskTextClass, 32873 unmaskTextClass, 32874 maskTextSelector, 32875 unmaskTextSelector,
32876 skipChild: false, 32877 inlineStylesheet, 32878 maskInputOptions, 32879 maskAttributeFn, 32880 maskTextFn, 32881 maskInputFn, 32882 slimDOMOptions, 32883 dataURLOptions, 32884 inlineImages, 32885 recordCanvas, 32886 preserveWhiteSpace, 32887 onSerialize, 32888 onIframeLoad, 32889 iframeLoadTimeout, 32890 onStylesheetLoad, 32891 stylesheetLoadTimeout, 32892 keepIframeSrcFn, 32893 }); 32894 if (serializedIframeNode) { 32895 onIframeLoad(n, serializedIframeNode); 32896 } 32897 } 32898 }, iframeLoadTimeout); 32899 } 32900 if (serializedNode.type === NodeType$1.Element && 32901 serializedNode.tagName === 'link' && 32902 serializedNode.attributes.rel === 'stylesheet') { 32903 onceStylesheetLoaded(n, () => { 32904 if (onStylesheetLoad) { 32905 const serializedLinkNode = serializeNodeWithId(n, { 32906 doc, 32907 mirror, 32908 blockClass, 32909 blockSelector, 32910 unblockSelector, 32911 maskAllText, 32912 maskTextClass, 32913 unmaskTextClass, 32914 maskTextSelector, 32915 unmaskTextSelector, 32916 skipChild: false, 32917 inlineStylesheet, 32918 maskInputOptions, 32919 maskAttributeFn, 32920 maskTextFn, 32921 maskInputFn, 32922 slimDOMOptions, 32923 dataURLOptions, 32924 inlineImages, 32925 recordCanvas, 32926 preserveWhiteSpace, 32927 onSerialize, 32928 onIframeLoad, 32929 iframeLoadTimeout, 32930 onStylesheetLoad, 32931 stylesheetLoadTimeout, 32932 keepIframeSrcFn, 32933 }); 32934 if (serializedLinkNode) { 32935 onStylesheetLoad(n, serializedLinkNode); 32936 } 32937 } 32938 }, stylesheetLoadTimeout); 32939 } 32940 return serializedNode; 32941} 32942function snapshot(n, options) { 32943 const { mirror = new Mirror(), blockClass = 'rr-block', blockSelector = null, unblockSelector = null, maskAllText = false, maskTextClass = 'rr-mask', unmaskTextClass = null, maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, inlineImages = false, recordCanvas = false, maskAllInputs = false, maskAttributeFn, maskTextFn, maskInputFn, slimDOM = false, dataURLOptions, preserveWhiteSpace, onSerialize, onIframeLoad, iframeLoadTimeout, onStylesheetLoad, stylesheetLoadTimeout, keepIframeSrcFn = () => false, } = options || {}; 32944 const maskInputOptions = maskAllInputs === true 32945 ? { 32946 color: true, 32947 date: true, 32948 'datetime-local': true, 32949 email: true, 32950 month: true, 32951 number: true, 32952 range: true, 32953 search: true, 32954 tel: true, 32955 text: true, 32956 time: true, 32957 url: true, 32958 week: true, 32959 textarea: true, 32960 select: true, 32961 } 32962 : maskAllInputs === false 32963 ? {} 32964 : maskAllInputs; 32965 const slimDOMOptions = slimDOM === true || slimDOM === 'all' 32966 ? 32967 { 32968 script: true, 32969 comment: true, 32970 headFavicon: true, 32971 headWhitespace: true, 32972 headMetaDescKeywords: slimDOM === 'all', 32973 headMetaSocial: true, 32974 headMetaRobots: true, 32975 headMetaHttpEquiv: true, 32976 headMetaAuthorship: true, 32977 headMetaVerification: true, 32978 } 32979 : slimDOM === false 32980 ? {} 32981 : slimDOM; 32982 return serializeNodeWithId(n, { 32983 doc: n, 32984 mirror, 32985 blockClass, 32986 blockSelector, 32987 unblockSelector, 32988 maskAllText, 32989 maskTextClass, 32990 unmaskTextClass, 32991 maskTextSelector, 32992 unmaskTextSelector,
32993 skipChild: false, 32994 inlineStylesheet, 32995 maskInputOptions, 32996 maskAttributeFn, 32997 maskTextFn, 32998 maskInputFn, 32999 slimDOMOptions, 33000 dataURLOptions, 33001 inlineImages, 33002 recordCanvas, 33003 preserveWhiteSpace, 33004 onSerialize, 33005 onIframeLoad, 33006 iframeLoadTimeout, 33007 onStylesheetLoad, 33008 stylesheetLoadTimeout, 33009 keepIframeSrcFn, 33010 newlyAddedElement: false, 33011 }); 33012} 33013 33014function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } 33015function on(type, fn, target = document) { 33016 const options = { capture: true, passive: true }; 33017 target.addEventListener(type, fn, options); 33018 return () => target.removeEventListener(type, fn, options); 33019} 33020const DEPARTED_MIRROR_ACCESS_WARNING = 'Please stop import mirror directly. Instead of that,' + 33021 '\r\n' + 33022 'now you can use replayer.getMirror() to access the mirror instance of a replayer,' + 33023 '\r\n' + 33024 'or you can use record.mirror to access the mirror instance during recording.'; 33025let _mirror = { 33026 map: {}, 33027 getId() { 33028 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 33029 return -1; 33030 }, 33031 getNode() { 33032 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 33033 return null; 33034 }, 33035 removeNodeFromMap() { 33036 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 33037 }, 33038 has() { 33039 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 33040 return false; 33041 }, 33042 reset() { 33043 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 33044 }, 33045}; 33046if (typeof window !== 'undefined' && window.Proxy && window.Reflect) { 33047 _mirror = new Proxy(_mirror, { 33048 get(target, prop, receiver) { 33049 if (prop === 'map') { 33050 console.error(DEPARTED_MIRROR_ACCESS_WARNING); 33051 } 33052 return Reflect.get(target, prop, receiver); 33053 }, 33054 }); 33055} 33056function throttle$1(func, wait, options = {}) { 33057 let timeout = null; 33058 let previous = 0; 33059 return function (...args) { 33060 const now = Date.now(); 33061 if (!previous && options.leading === false) { 33062 previous = now; 33063 } 33064 const remaining = wait - (now - previous); 33065 const context = this; 33066 if (remaining <= 0 || remaining > wait) { 33067 if (timeout) { 33068 clearTimeout(timeout); 33069 timeout = null; 33070 } 33071 previous = now; 33072 func.apply(context, args); 33073 } 33074 else if (!timeout && options.trailing !== false) { 33075 timeout = setTimeout(() => { 33076 previous = options.leading === false ? 0 : Date.now(); 33077 timeout = null; 33078 func.apply(context, args); 33079 }, remaining); 33080 } 33081 }; 33082} 33083function hookSetter(target, key, d, isRevoked, win = window) { 33084 const original = win.Object.getOwnPropertyDescriptor(target, key); 33085 win.Object.defineProperty(target, key, isRevoked 33086 ? d 33087 : { 33088 set(value) { 33089 setTimeout(() => { 33090 d.set.call(this, value); 33091 }, 0); 33092 if (original && original.set) { 33093 original.set.call(this, value); 33094 } 33095 }, 33096 }); 33097 return () => hookSetter(target, key, original || {}, true); 33098} 33099function patch(source, name, replacement) { 33100 try { 33101 if (!(name in source)) { 33102 return () => { 33103 }; 33104 } 33105 const original = source[name]; 33106 const wrapped = replacement(original); 33107 if (typeof wrapped === 'function') { 33108 wrapped.prototype = wrapped.prototype || {}; 33109 Object.defineProperties(wrapped, { 33110 __rrweb_original__: { 33111 enumerable: false, 33112 value: original, 33113 }, 33114 }); 33115 } 33116 source[name] = wrapped; 33117 return () => { 33118 source[name] = original; 33119 }; 33120 } 33121 catch (e2) { 33122 return () => { 33123 }; 33124 } 33125} 33126let nowTimestamp = Date.now; 33127if (!(/[1-9][0-9]{12}/.test(Date.now().toString()))) { 33128 nowTimestamp = () => new Date().getTime(); 33129} 33130function getWindowScroll(win) { 33131 const doc = win.document; 33132 return { 33133 left: doc.scrollingElement 33134 ? doc.scrollingElement.scrollLeft 33135 : win.pageXOffset !== undefined 33136 ? win.pageXOffset 33137 : _optionalChain$4([doc, 'optionalAccess', _ => _.documentElement, 'access', _2 => _2.scrollLeft]) || 33138 _optionalChain$4([doc, 'optionalAccess', _3 => _3.body, 'optionalAccess', _4 => _4.parentElement, 'optionalAccess', _5 => _5.scrollLeft]) || 33139 _optionalChain$4([doc, 'optionalAccess', _6 => _6.body, 'optionalAccess', _7 => _7.scrollLeft]) || 33140 0, 33141 top: doc.scrollingElement 33142 ? doc.scrollingElement.scrollTop 33143 : win.pageYOffset !== undefined 33144 ? win.pageYOffset 33145 : _optionalChain$4([doc, 'optionalAccess', _8 => _8.documentElement, 'access', _9 => _9.scrollTop]) || 33146 _optionalChain$4([doc, 'optionalAccess', _10 => _10.body, 'optionalAccess', _11 => _11.parentElement, 'optionalAccess', _12 => _12.scrollTop]) || 33147 _optionalChain$4([doc, 'optionalAccess', _13 => _13.body, 'optionalAccess', _14 => _14.scrollTop]) || 33148 0, 33149 }; 33150} 33151function getWindowHeight() { 33152 return (window.innerHeight || 33153 (document.documentElement && document.documentElement.clientHeight) || 33154 (document.body && document.body.clientHeight)); 33155} 33156function getWindowWidth() { 33157 return (window.innerWidth || 33158 (document.documentElement && document.documentElement.clientWidth) || 33159 (document.body && document.body.clientWidth)); 33160} 33161function isBlocked(node, blockClass, blockSelector, unblockSelector, checkAncestors) { 33162 if (!node) { 33163 return false;
33164 } 33165 const el = node.nodeType === node.ELEMENT_NODE 33166 ? node 33167 : node.parentElement; 33168 if (!el) 33169 return false; 33170 const blockedPredicate = createMatchPredicate(blockClass, blockSelector); 33171 if (!checkAncestors) { 33172 const isUnblocked = unblockSelector && el.matches(unblockSelector); 33173 return blockedPredicate(el) && !isUnblocked; 33174 } 33175 const blockDistance = distanceToMatch(el, blockedPredicate); 33176 let unblockDistance = -1; 33177 if (blockDistance < 0) { 33178 return false; 33179 } 33180 if (unblockSelector) { 33181 unblockDistance = distanceToMatch(el, createMatchPredicate(null, unblockSelector)); 33182 } 33183 if (blockDistance > -1 && unblockDistance < 0) { 33184 return true; 33185 } 33186 return blockDistance < unblockDistance; 33187} 33188function isSerialized(n, mirror) { 33189 return mirror.getId(n) !== -1; 33190} 33191function isIgnored(n, mirror) { 33192 return mirror.getId(n) === IGNORED_NODE; 33193} 33194function isAncestorRemoved(target, mirror) { 33195 if (isShadowRoot(target)) { 33196 return false; 33197 } 33198 const id = mirror.getId(target); 33199 if (!mirror.has(id)) { 33200 return true; 33201 } 33202 if (target.parentNode && 33203 target.parentNode.nodeType === target.DOCUMENT_NODE) { 33204 return false; 33205 } 33206 if (!target.parentNode) { 33207 return true; 33208 } 33209 return isAncestorRemoved(target.parentNode, mirror); 33210} 33211function legacy_isTouchEvent(event) { 33212 return Boolean(event.changedTouches); 33213} 33214function polyfill(win = window) { 33215 if ('NodeList' in win && !win.NodeList.prototype.forEach) { 33216 win.NodeList.prototype.forEach = Array.prototype 33217 .forEach; 33218 } 33219 if ('DOMTokenList' in win && !win.DOMTokenList.prototype.forEach) { 33220 win.DOMTokenList.prototype.forEach = Array.prototype 33221 .forEach; 33222 } 33223 if (!Node.prototype.contains) { 33224 Node.prototype.contains = (...args) => { 33225 let node = args[0]; 33226 if (!(0 in args)) { 33227 throw new TypeError('1 argument is required'); 33228 } 33229 do { 33230 if (this === node) { 33231 return true; 33232 } 33233 } while ((node = node && node.parentNode)); 33234 return false; 33235 }; 33236 } 33237} 33238function isSerializedIframe(n, mirror) { 33239 return Boolean(n.nodeName === 'IFRAME' && mirror.getMeta(n)); 33240} 33241function isSerializedStylesheet(n, mirror) { 33242 return Boolean(n.nodeName === 'LINK' && 33243 n.nodeType === n.ELEMENT_NODE && 33244 n.getAttribute && 33245 n.getAttribute('rel') === 'stylesheet' && 33246 mirror.getMeta(n)); 33247} 33248function hasShadowRoot(n) { 33249 return Boolean(_optionalChain$4([n, 'optionalAccess', _18 => _18.shadowRoot])); 33250} 33251class StyleSheetMirror { 33252 constructor() { 33253 this.id = 1; 33254 this.styleIDMap = new WeakMap(); 33255 this.idStyleMap = new Map(); 33256 } 33257 getId(stylesheet) { 33258 return _nullishCoalesce(this.styleIDMap.get(stylesheet), () => ( -1)); 33259 } 33260 has(stylesheet) { 33261 return this.styleIDMap.has(stylesheet); 33262 } 33263 add(stylesheet, id) { 33264 if (this.has(stylesheet)) 33265 return this.getId(stylesheet); 33266 let newId; 33267 if (id === undefined) { 33268 newId = this.id++; 33269 } 33270 else 33271 newId = id; 33272 this.styleIDMap.set(stylesheet, newId); 33273 this.idStyleMap.set(newId, stylesheet); 33274 return newId; 33275 } 33276 getStyle(id) { 33277 return this.idStyleMap.get(id) || null; 33278 } 33279 reset() { 33280 this.styleIDMap = new WeakMap(); 33281 this.idStyleMap = new Map(); 33282 this.id = 1; 33283 } 33284 generateId() { 33285 return this.id++; 33286 } 33287} 33288function getShadowHost(n) { 33289 let shadowHost = null; 33290 if (_optionalChain$4([n, 'access', _19 => _19.getRootNode, 'optionalCall', _20 => _20(), 'optionalAccess', _21 => _21.nodeType]) === Node.DOCUMENT_FRAGMENT_NODE && 33291 n.getRootNode().host) 33292 shadowHost = n.getRootNode().host; 33293 return shadowHost; 33294} 33295function getRootShadowHost(n) { 33296 let rootShadowHost = n; 33297 let shadowHost; 33298 while ((shadowHost = getShadowHost(rootShadowHost))) 33299 rootShadowHost = shadowHost; 33300 return rootShadowHost; 33301} 33302function shadowHostInDom(n) { 33303 const doc = n.ownerDocument; 33304 if (!doc) 33305 return false;
33306 const shadowHost = getRootShadowHost(n); 33307 return doc.contains(shadowHost); 33308} 33309function inDom(n) { 33310 const doc = n.ownerDocument; 33311 if (!doc) 33312 return false; 33313 return doc.contains(n) || shadowHostInDom(n); 33314} 33315let cachedRequestAnimationFrameImplementation; 33316function getRequestAnimationFrameImplementation() { 33317 if (cachedRequestAnimationFrameImplementation) { 33318 return cachedRequestAnimationFrameImplementation; 33319 } 33320 const document = window.document; 33321 let requestAnimationFrameImplementation = window.requestAnimationFrame; 33322 if (document && typeof document.createElement === 'function') { 33323 try { 33324 const sandbox = document.createElement('iframe'); 33325 sandbox.hidden = true; 33326 document.head.appendChild(sandbox); 33327 const contentWindow = sandbox.contentWindow; 33328 if (contentWindow && contentWindow.requestAnimationFrame) { 33329 requestAnimationFrameImplementation = 33330 contentWindow.requestAnimationFrame; 33331 } 33332 document.head.removeChild(sandbox); 33333 } 33334 catch (e) { 33335 } 33336 } 33337 return (cachedRequestAnimationFrameImplementation = 33338 requestAnimationFrameImplementation.bind(window)); 33339} 33340function onRequestAnimationFrame(...rest) { 33341 return getRequestAnimationFrameImplementation()(...rest); 33342} 33343 33344var EventType = /* @__PURE__ */ ((EventType2) => { 33345 EventType2[EventType2["DomContentLoaded"] = 0] = "DomContentLoaded"; 33346 EventType2[EventType2["Load"] = 1] = "Load"; 33347 EventType2[EventType2["FullSnapshot"] = 2] = "FullSnapshot"; 33348 EventType2[EventType2["IncrementalSnapshot"] = 3] = "IncrementalSnapshot"; 33349 EventType2[EventType2["Meta"] = 4] = "Meta"; 33350 EventType2[EventType2["Custom"] = 5] = "Custom"; 33351 EventType2[EventType2["Plugin"] = 6] = "Plugin"; 33352 return EventType2; 33353})(EventType || {}); 33354var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => { 33355 IncrementalSource2[IncrementalSource2["Mutation"] = 0] = "Mutation"; 33356 IncrementalSource2[IncrementalSource2["MouseMove"] = 1] = "MouseMove"; 33357 IncrementalSource2[IncrementalSource2["MouseInteraction"] = 2] = "MouseInteraction"; 33358 IncrementalSource2[IncrementalSource2["Scroll"] = 3] = "Scroll"; 33359 IncrementalSource2[IncrementalSource2["ViewportResize"] = 4] = "ViewportResize"; 33360 IncrementalSource2[IncrementalSource2["Input"] = 5] = "Input"; 33361 IncrementalSource2[IncrementalSource2["TouchMove"] = 6] = "TouchMove"; 33362 IncrementalSource2[IncrementalSource2["MediaInteraction"] = 7] = "MediaInteraction"; 33363 IncrementalSource2[IncrementalSource2["StyleSheetRule"] = 8] = "StyleSheetRule"; 33364 IncrementalSource2[IncrementalSource2["CanvasMutation"] = 9] = "CanvasMutation"; 33365 IncrementalSource2[IncrementalSource2["Font"] = 10] = "Font"; 33366 IncrementalSource2[IncrementalSource2["Log"] = 11] = "Log"; 33367 IncrementalSource2[IncrementalSource2["Drag"] = 12] = "Drag"; 33368 IncrementalSource2[IncrementalSource2["StyleDeclaration"] = 13] = "StyleDeclaration"; 33369 IncrementalSource2[IncrementalSource2["Selection"] = 14] = "Selection"; 33370 IncrementalSource2[IncrementalSource2["AdoptedStyleSheet"] = 15] = "AdoptedStyleSheet"; 33371 IncrementalSource2[IncrementalSource2["CustomElement"] = 16] = "CustomElement"; 33372 return IncrementalSource2; 33373})(IncrementalSource || {}); 33374var MouseInteractions = /* @__PURE__ */ ((MouseInteractions2) => { 33375 MouseInteractions2[MouseInteractions2["MouseUp"] = 0] = "MouseUp"; 33376 MouseInteractions2[MouseInteractions2["MouseDown"] = 1] = "MouseDown"; 33377 MouseInteractions2[MouseInteractions2["Click"] = 2] = "Click"; 33378 MouseInteractions2[MouseInteractions2["ContextMenu"] = 3] = "ContextMenu"; 33379 MouseInteractions2[MouseInteractions2["DblClick"] = 4] = "DblClick"; 33380 MouseInteractions2[MouseInteractions2["Focus"] = 5] = "Focus"; 33381 MouseInteractions2[MouseInteractions2["Blur"] = 6] = "Blur"; 33382 MouseInteractions2[MouseInteractions2["TouchStart"] = 7] = "TouchStart"; 33383 MouseInteractions2[MouseInteractions2["TouchMove_Departed"] = 8] = "TouchMove_Departed"; 33384 MouseInteractions2[MouseInteractions2["TouchEnd"] = 9] = "TouchEnd"; 33385 MouseInteractions2[MouseInteractions2["TouchCancel"] = 10] = "TouchCancel"; 33386 return MouseInteractions2; 33387})(MouseInteractions || {}); 33388var PointerTypes = /* @__PURE__ */ ((PointerTypes2) => { 33389 PointerTypes2[PointerTypes2["Mouse"] = 0] = "Mouse"; 33390 PointerTypes2[PointerTypes2["Pen"] = 1] = "Pen"; 33391 PointerTypes2[PointerTypes2["Touch"] = 2] = "Touch"; 33392 return PointerTypes2; 33393})(PointerTypes || {}); 33394 33395function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } 33396function isNodeInLinkedList(n) { 33397 return '__ln' in n; 33398} 33399class DoubleLinkedList { 33400 constructor() { 33401 this.length = 0; 33402 this.head = null; 33403 this.tail = null; 33404 } 33405 get(position) { 33406 if (position >= this.length) { 33407 throw new Error('Position outside of list range'); 33408 } 33409 let current = this.head; 33410 for (let index = 0; index < position; index++) { 33411 current = _optionalChain$3([current, 'optionalAccess', _ => _.next]) || null; 33412 } 33413 return current; 33414 } 33415 addNode(n) { 33416 const node = { 33417 value: n, 33418 previous: null, 33419 next: null, 33420 }; 33421 n.__ln = node; 33422 if (n.previousSibling && isNodeInLinkedList(n.previousSibling)) { 33423 const current = n.previousSibling.__ln.next; 33424 node.next = current; 33425 node.previous = n.previousSibling.__ln; 33426 n.previousSibling.__ln.next = node; 33427 if (current) { 33428 current.previous = node; 33429 } 33430 } 33431 else if (n.nextSibling && 33432 isNodeInLinkedList(n.nextSibling) && 33433 n.nextSibling.__ln.previous) { 33434 const current = n.nextSibling.__ln.previous; 33435 node.previous = current; 33436 node.next = n.nextSibling.__ln; 33437 n.nextSibling.__ln.previous = node; 33438 if (current) { 33439 current.next = node; 33440 } 33441 } 33442 else { 33443 if (this.head) { 33444 this.head.previous = node; 33445 } 33446 node.next = this.head; 33447 this.head = node; 33448 } 33449 if (node.next === null) { 33450 this.tail = node; 33451 } 33452 this.length++; 33453 } 33454 removeNode(n) { 33455 const current = n.__ln; 33456 if (!this.head) { 33457 return; 33458 } 33459 if (!current.previous) { 33460 this.head = current.next; 33461 if (this.head) { 33462 this.head.previous = null; 33463 } 33464 else { 33465 this.tail = null; 33466 } 33467 } 33468 else { 33469 current.previous.next = current.next; 33470 if (current.next) { 33471 current.next.previous = current.previous; 33472 } 33473 else { 33474 this.tail = current.previous; 33475 } 33476 } 33477 if (n.__ln) { 33478 delete n.__ln; 33479 } 33480 this.length--; 33481 } 33482} 33483const moveKey = (id, parentId) => `${id}@${parentId}`; 33484class MutationBuffer { 33485 constructor() { 33486 this.frozen = false;
vendor: 5,440 bytes, lines 33487-33615
33487 this.locked = false; 33488 this.texts = []; 33489 this.attributes = []; 33490 this.removes = []; 33491 this.mapRemoves = []; 33492 this.movedMap = {}; 33493 this.addedSet = new Set(); 33494 this.movedSet = new Set(); 33495 this.droppedSet = new Set(); 33496 this.processMutations = (mutations) => { 33497 mutations.forEach(this.processMutation); 33498 this.emit(); 33499 }; 33500 this.emit = () => { 33501 if (this.frozen || this.locked) { 33502 return; 33503 } 33504 const adds = []; 33505 const addedIds = new Set(); 33506 const addList = new DoubleLinkedList(); 33507 const getNextId = (n) => { 33508 let ns = n; 33509 let nextId = IGNORED_NODE; 33510 while (nextId === IGNORED_NODE) { 33511 ns = ns && ns.nextSibling; 33512 nextId = ns && this.mirror.getId(ns); 33513 } 33514 return nextId; 33515 }; 33516 const pushAdd = (n) => { 33517 if (!n.parentNode || !inDom(n)) { 33518 return; 33519 } 33520 const parentId = isShadowRoot(n.parentNode) 33521 ? this.mirror.getId(getShadowHost(n)) 33522 : this.mirror.getId(n.parentNode); 33523 const nextId = getNextId(n); 33524 if (parentId === -1 || nextId === -1) { 33525 return addList.addNode(n); 33526 } 33527 const sn = serializeNodeWithId(n, { 33528 doc: this.doc, 33529 mirror: this.mirror, 33530 blockClass: this.blockClass, 33531 blockSelector: this.blockSelector, 33532 maskAllText: this.maskAllText, 33533 unblockSelector: this.unblockSelector, 33534 maskTextClass: this.maskTextClass, 33535 unmaskTextClass: this.unmaskTextClass, 33536 maskTextSelector: this.maskTextSelector, 33537 unmaskTextSelector: this.unmaskTextSelector, 33538 skipChild: true, 33539 newlyAddedElement: true, 33540 inlineStylesheet: this.inlineStylesheet, 33541 maskInputOptions: this.maskInputOptions, 33542 maskAttributeFn: this.maskAttributeFn, 33543 maskTextFn: this.maskTextFn, 33544 maskInputFn: this.maskInputFn, 33545 slimDOMOptions: this.slimDOMOptions, 33546 dataURLOptions: this.dataURLOptions, 33547 recordCanvas: this.recordCanvas, 33548 inlineImages: this.inlineImages, 33549 onSerialize: (currentN) => { 33550 if (isSerializedIframe(currentN, this.mirror)) { 33551 this.iframeManager.addIframe(currentN); 33552 } 33553 if (isSerializedStylesheet(currentN, this.mirror)) { 33554 this.stylesheetManager.trackLinkElement(currentN); 33555 } 33556 if (hasShadowRoot(n)) { 33557 this.shadowDomManager.addShadowRoot(n.shadowRoot, this.doc); 33558 } 33559 }, 33560 onIframeLoad: (iframe, childSn) => { 33561 this.iframeManager.attachIframe(iframe, childSn); 33562 this.shadowDomManager.observeAttachShadow(iframe); 33563 }, 33564 onStylesheetLoad: (link, childSn) => { 33565 this.stylesheetManager.attachLinkElement(link, childSn); 33566 }, 33567 }); 33568 if (sn) { 33569 adds.push({ 33570 parentId, 33571 nextId, 33572 node: sn, 33573 }); 33574 addedIds.add(sn.id); 33575 } 33576 }; 33577 while (this.mapRemoves.length) { 33578 this.mirror.removeNodeFromMap(this.mapRemoves.shift()); 33579 } 33580 for (const n of this.movedSet) { 33581 if (isParentRemoved(this.removes, n, this.mirror) && 33582 !this.movedSet.has(n.parentNode)) { 33583 continue; 33584 } 33585 pushAdd(n); 33586 } 33587 for (const n of this.addedSet) { 33588 if (!isAncestorInSet(this.droppedSet, n) && 33589 !isParentRemoved(this.removes, n, this.mirror)) { 33590 pushAdd(n); 33591 } 33592 else if (isAncestorInSet(this.movedSet, n)) { 33593 pushAdd(n); 33594 } 33595 else { 33596 this.droppedSet.add(n); 33597 } 33598 } 33599 let candidate = null; 33600 while (addList.length) { 33601 let node = null; 33602 if (candidate) { 33603 const parentId = this.mirror.getId(candidate.value.parentNode); 33604 const nextId = getNextId(candidate.value); 33605 if (parentId !== -1 && nextId !== -1) { 33606 node = candidate; 33607 } 33608 } 33609 if (!node) { 33610 let tailNode = addList.tail; 33611 while (tailNode) { 33612 const _node = tailNode; 33613 tailNode = tailNode.previous; 33614 if (_node) { 33615 const parentId = this.mirror.getId(_no
33615de.value.parentNode); 33616 const nextId = getNextId(_node.value); 33617 if (nextId === -1) 33618 continue; 33619 else if (parentId !== -1) { 33620 node = _node; 33621 break; 33622 } 33623 else { 33624 const unhandledNode = _node.value; 33625 if (unhandledNode.parentNode && 33626 unhandledNode.parentNode.nodeType === 33627 Node.DOCUMENT_FRAGMENT_NODE) { 33628 const shadowHost = unhandledNode.parentNode 33629 .host; 33630 const parentId = this.mirror.getId(shadowHost); 33631 if (parentId !== -1) { 33632 node = _node; 33633 break; 33634 } 33635 } 33636 } 33637 } 33638 } 33639 } 33640 if (!node) { 33641 while (addList.head) { 33642 addList.removeNode(addList.head.value); 33643 } 33644 break; 33645 } 33646 candidate = node.previous; 33647 addList.removeNode(node.value); 33648 pushAdd(node.value); 33649 } 33650 const payload = { 33651 texts: this.texts 33652 .map((text) => ({ 33653 id: this.mirror.getId(text.node), 33654 value: text.value, 33655 })) 33656 .filter((text) => !addedIds.has(text.id)) 33657 .filter((text) => this.mirror.has(text.id)), 33658 attributes: this.attributes 33659 .map((attribute) => { 33660 const { attributes } = attribute; 33661 if (typeof attributes.style === 'string') { 33662 const diffAsStr = JSON.stringify(attribute.styleDiff); 33663 const unchangedAsStr = JSON.stringify(attribute._unchangedStyles); 33664 if (diffAsStr.length < attributes.style.length) { 33665 if ((diffAsStr + unchangedAsStr).split('var(').length === 33666 attributes.style.split('var(').length) { 33667 attributes.style = attribute.styleDiff; 33668 } 33669 } 33670 } 33671 return { 33672 id: this.mirror.getId(attribute.node), 33673 attributes: attributes, 33674 }; 33675 }) 33676 .filter((attribute) => !addedIds.has(attribute.id)) 33677 .filter((attribute) => this.mirror.has(attribute.id)), 33678 removes: this.removes, 33679 adds, 33680 }; 33681 if (!payload.texts.length && 33682 !payload.attributes.length && 33683 !payload.removes.length && 33684 !payload.adds.length) { 33685 return; 33686 } 33687 this.texts = []; 33688 this.attributes = []; 33689 this.removes = []; 33690 this.addedSet = new Set(); 33691 this.movedSet = new Set(); 33692 this.droppedSet = new Set(); 33693 this.movedMap = {}; 33694 this.mutationCb(payload); 33695 }; 33696 this.processMutation = (m) => { 33697 if (isIgnored(m.target, this.mirror)) { 33698 return; 33699 } 33700 let unattachedDoc; 33701 try { 33702 unattachedDoc = document.implementation.createHTMLDocument(); 33703 } 33704 catch (e) { 33705 unattachedDoc = this.doc; 33706 } 33707 switch (m.type) { 33708 case 'characterData': { 33709 const value = m.target.textContent; 33710 if (!isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, false) && 33711 value !== m.oldValue) { 33712 this.texts.push({ 33713 value: needMaskingText(m.target, this.maskTextClass, this.maskTextSelector, this.unmaskTextClass, this.unmaskTextSelector, this.maskAllText) && value 33714 ? this.maskTextFn 33715 ? this.maskTextFn(value) 33716 : value.replace(/[\S]/g, '*') 33717 : value, 33718 node: m.target, 33719 }); 33720 } 33721 break; 33722 } 33723 case 'attributes': { 33724 const target = m.target; 33725 let attributeName = m.attributeName; 33726 let value = m.target.getAttribute(attributeName); 33727 if (attributeName === 'value') { 33728 const type = getInputType(target); 33729 const tagName = target.tagName; 33730 value = getInputValue(target, tagName, type); 33731 const isInputMasked = shouldMaskInput({ 33732 maskInputOptions: this.maskInputOptions, 33733 tagName, 33734 type, 33735 }); 33736 const forceMask = needMaskingText(m.target, this.maskTextClass, this.maskTextSelector, this.unmaskTextClass, this.unmaskTextSelector, isInputMasked); 33737 value = maskInputValue({ 33738 isMasked: forceMask, 33739 element: target, 33740 value, 33741 maskInputFn: this.maskInputFn, 33742 }); 33743 } 33744 if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, false) || 33745 value === m.oldValue) { 33746 return; 33747 } 33748 let item = this.attributes.find((a) => a.node === m.target); 33749 if (target.tagName === 'IFRAME' && 33750 attributeName === 'src' && 33751 !this.keepIframeSrcFn(value)) { 33752 if (!target.contentDocument) { 33753 attributeName = 'rr_src'; 33754 } 33755 else { 33756 return; 33757 } 33758 } 33759 if (!item) { 33760 item = { 33761 node: m.target, 33762 attributes: {}, 33763 styleDiff: {}, 33764 _unchangedStyles: {}, 33765 }; 33766 this.attributes.push(item); 33767 } 33768 if (attributeName === 'type' && 33769 target.tagName === 'INPUT' && 33770 (m.oldValue || '').toLowerCase() === 'password') { 33771 target.setAttribute('data-rr-is-password', 'true'); 33772 } 33773 if (!ignoreAttribute(target.tagName, attributeName)) { 33774 item.attributes[attributeName] = transformAttribute(this.doc, toLowerCase(target.tagName), toLowerCase(attributeName), value, target, this.maskAttributeFn); 33775 if (attributeName === 'style') { 33776 const old = unattachedDoc.createElement('span'); 33777 if (m.oldValue) { 33778 old.setAttribute('style', m.oldValue); 33779 } 33780 for (const pname of Array.from(target.style)) { 33781 const newValue = target.style.getPropertyValue(pname); 33782 const newPriority = target.style.getPropertyPriority(pname); 33783 if (newValue !== old.style.getPropertyValue(pname) || 33784 newPriority !== old.style.getPropertyPriority(pname)) { 33785 if (newPriority === '') { 33786 item.styleDiff[pname] = newValue; 33787 } 33788 else { 33789 item.styleDiff[pname] = [newValue, newPriority]; 33790 } 33791 } 33792 else { 33793 item._unchangedStyles[pname] = [newValue, newPriority]; 33794 } 33795 } 33796 for (const pname of Array.from(old.style)) { 33797 if (target.style.getPropertyValue(pname) === '') { 33798 item.styleDiff[pname] = false;
33799 } 33800 } 33801 } 33802 } 33803 break; 33804 } 33805 case 'childList': { 33806 if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, true)) { 33807 return; 33808 } 33809 m.addedNodes.forEach((n) => this.genAdds(n, m.target)); 33810 m.removedNodes.forEach((n) => { 33811 const nodeId = this.mirror.getId(n); 33812 const parentId = isShadowRoot(m.target) 33813 ? this.mirror.getId(m.target.host) 33814 : this.mirror.getId(m.target); 33815 if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, false) || 33816 isIgnored(n, this.mirror) || 33817 !isSerialized(n, this.mirror)) { 33818 return; 33819 } 33820 if (this.addedSet.has(n)) { 33821 deepDelete(this.addedSet, n); 33822 this.droppedSet.add(n); 33823 } 33824 else if (this.addedSet.has(m.target) && nodeId === -1) ; 33825 else if (isAncestorRemoved(m.target, this.mirror)) ; 33826 else if (this.movedSet.has(n) && 33827 this.movedMap[moveKey(nodeId, parentId)]) { 33828 deepDelete(this.movedSet, n); 33829 } 33830 else { 33831 this.removes.push({ 33832 parentId, 33833 id: nodeId, 33834 isShadow: isShadowRoot(m.target) && isNativeShadowDom(m.target) 33835 ? true 33836 : undefined, 33837 }); 33838 } 33839 this.mapRemoves.push(n); 33840 }); 33841 break; 33842 } 33843 } 33844 }; 33845 this.genAdds = (n, target) => { 33846 if (this.processedNodeManager.inOtherBuffer(n, this)) 33847 return; 33848 if (this.addedSet.has(n) || this.movedSet.has(n)) 33849 return; 33850 if (this.mirror.hasNode(n)) { 33851 if (isIgnored(n, this.mirror)) { 33852 return; 33853 } 33854 this.movedSet.add(n); 33855 let targetId = null; 33856 if (target && this.mirror.hasNode(target)) { 33857 targetId = this.mirror.getId(target); 33858 } 33859 if (targetId && targetId !== -1) { 33860 this.movedMap[moveKey(this.mirror.getId(n), targetId)] = true; 33861 } 33862 } 33863 else { 33864 this.addedSet.add(n); 33865 this.droppedSet.delete(n); 33866 } 33867 if (!isBlocked(n, this.blockClass, this.blockSelector, this.unblockSelector, false)) { 33868 n.childNodes.forEach((childN) => this.genAdds(childN)); 33869 if (hasShadowRoot(n)) { 33870 n.shadowRoot.childNodes.forEach((childN) => { 33871 this.processedNodeManager.add(childN, this); 33872 this.genAdds(childN, n); 33873 }); 33874 } 33875 } 33876 }; 33877 } 33878 init(options) { 33879 [ 33880 'mutationCb', 33881 'blockClass', 33882 'blockSelector', 33883 'unblockSelector', 33884 'maskAllText', 33885 'maskTextClass', 33886 'unmaskTextClass', 33887 'maskTextSelector', 33888 'unmaskTextSelector', 33889 'inlineStylesheet', 33890 'maskInputOptions', 33891 'maskAttributeFn', 33892 'maskTextFn', 33893 'maskInputFn', 33894 'keepIframeSrcFn', 33895 'recordCanvas', 33896 'inlineImages', 33897 'slimDOMOptions', 33898 'dataURLOptions', 33899 'doc', 33900 'mirror', 33901 'iframeManager', 33902 'stylesheetManager', 33903 'shadowDomManager', 33904 'canvasManager', 33905 'processedNodeManager', 33906 ].forEach((key) => { 33907 this[key] = options[key]; 33908 }); 33909 } 33910 freeze() { 33911 this.frozen = true; 33912 this.canvasManager.freeze(); 33913 } 33914 unfreeze() { 33915 this.frozen = false;
33916 this.canvasManager.unfreeze(); 33917 this.emit(); 33918 } 33919 isFrozen() { 33920 return this.frozen; 33921 } 33922 lock() { 33923 this.locked = true; 33924 this.canvasManager.lock(); 33925 } 33926 unlock() { 33927 this.locked = false; 33928 this.canvasManager.unlock(); 33929 this.emit(); 33930 } 33931 reset() { 33932 this.shadowDomManager.reset(); 33933 this.canvasManager.reset(); 33934 } 33935} 33936function deepDelete(addsSet, n) { 33937 addsSet.delete(n); 33938 n.childNodes.forEach((childN) => deepDelete(addsSet, childN)); 33939} 33940function isParentRemoved(removes, n, mirror) { 33941 if (removes.length === 0) 33942 return false; 33943 return _isParentRemoved(removes, n, mirror); 33944} 33945function _isParentRemoved(removes, n, mirror) { 33946 const { parentNode } = n; 33947 if (!parentNode) { 33948 return false; 33949 } 33950 const parentId = mirror.getId(parentNode); 33951 if (removes.some((r) => r.id === parentId)) { 33952 return true; 33953 } 33954 return _isParentRemoved(removes, parentNode, mirror); 33955} 33956function isAncestorInSet(set, n) { 33957 if (set.size === 0) 33958 return false; 33959 return _isAncestorInSet(set, n); 33960} 33961function _isAncestorInSet(set, n) { 33962 const { parentNode } = n; 33963 if (!parentNode) { 33964 return false; 33965 } 33966 if (set.has(parentNode)) { 33967 return true; 33968 } 33969 return _isAncestorInSet(set, parentNode); 33970} 33971 33972let errorHandler; 33973function registerErrorHandler(handler) { 33974 errorHandler = handler; 33975} 33976function unregisterErrorHandler() { 33977 errorHandler = undefined; 33978} 33979const callbackWrapper = (cb) => { 33980 if (!errorHandler) { 33981 return cb; 33982 } 33983 const rrwebWrapped = ((...rest) => { 33984 try { 33985 return cb(...rest); 33986 } 33987 catch (error) { 33988 if (errorHandler && errorHandler(error) === true) { 33989 return () => { 33990 }; 33991 } 33992 throw error; 33993 } 33994 }); 33995 return rrwebWrapped; 33996}; 33997 33998function _optionalChain$2(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } 33999const mutationBuffers = []; 34000function getEventTarget(event) { 34001 try { 34002 if ('composedPath' in event) { 34003 const path = event.composedPath(); 34004 if (path.length) { 34005 return path[0]; 34006 } 34007 } 34008 else if ('path' in event && event.path.length) { 34009 return event.path[0]; 34010 } 34011 } 34012 catch (e2) { 34013 } 34014 return event && event.target; 34015} 34016function initMutationObserver(options, rootEl) { 34017 const mutationBuffer = new MutationBuffer(); 34018 mutationBuffers.push(mutationBuffer); 34019 mutationBuffer.init(options); 34020 let mutationObserverCtor = window.MutationObserver || 34021 window.__rrMutationObserver; 34022 const angularZoneSymbol = _optionalChain$2([window, 'optionalAccess', _ => _.Zone, 'optionalAccess', _2 => _2.__symbol__, 'optionalCall', _3 => _3('MutationObserver')]); 34023 if (angularZoneSymbol && 34024 window[angularZoneSymbol]) { 34025 mutationObserverCtor = window[angularZoneSymbol]; 34026 } 34027 const observer = new mutationObserverCtor(callbackWrapper((mutations) => { 34028 if (options.onMutation && options.onMutation(mutations) === false) { 34029 return; 34030 } 34031 mutationBuffer.processMutations.bind(mutationBuffer)(mutations); 34032 })); 34033 observer.observe(rootEl, { 34034 attributes: true, 34035 attributeOldValue: true, 34036 characterData: true, 34037 characterDataOldValue: true, 34038 childList: true, 34039 subtree: true, 34040 }); 34041 return observer; 34042} 34043function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) { 34044 if (sampling.mousemove === false) { 34045 return () => { 34046 }; 34047 } 34048 const threshold = typeof sampling.mousemove === 'number' ? sampling.mousemove : 50; 34049 const callbackThreshold = typeof sampling.mousemoveCallback === 'number' 34050 ? sampling.mousemoveCallback 34051 : 500; 34052 let positions = []; 34053 let timeBaseline; 34054 const wrappedCb = throttle$1(callbackWrapper((source) => { 34055 const totalOffset = Date.now() - timeBaseline; 34056 mousemoveCb(positions.map((p) => { 34057 p.timeOffset -= totalOffset; 34058 return p; 34059 }), source); 34060 positions = []; 34061 timeBaseline = null; 34062 }), callbackThreshold); 34063 const updatePosition = callbackWrapper(throttle$1(callbackWrapper((evt) => { 34064 const target = getEventTarget(evt); 34065 const { clientX, clientY } = legacy_isTouchEvent(evt) 34066 ? evt.changedTouches[0] 34067 : evt; 34068 if (!timeBaseline) { 34069 timeBaseline = nowTimestamp(); 34070 } 34071 positions.push({ 34072 x: clientX, 34073 y: clientY, 34074 id: mirror.getId(target), 34075 timeOffset: nowTimestamp() - timeBaseline, 34076 }); 34077 wrappedCb(typeof DragEvent !== 'undefined' && evt instanceof DragEvent 34078 ? IncrementalSource.Drag 34079 : evt instanceof MouseEvent 34080 ? IncrementalSource.MouseMove 34081 : IncrementalSource.TouchMove); 34082 }), threshold, { 34083 trailing: false, 34084 })); 34085 const handlers = [ 34086 on('mousemove', updatePosition, doc), 34087 on('touchmove', updatePosition, doc), 34088 on('drag', updatePosition, doc), 34089 ]; 34090 return callbackWrapper(() => {
34091 handlers.forEach((h) => h()); 34092 }); 34093} 34094function initMouseInteractionObserver({ mouseInteractionCb, doc, mirror, blockClass, blockSelector, unblockSelector, sampling, }) { 34095 if (sampling.mouseInteraction === false) { 34096 return () => { 34097 }; 34098 } 34099 const disableMap = sampling.mouseInteraction === true || 34100 sampling.mouseInteraction === undefined 34101 ? {} 34102 : sampling.mouseInteraction; 34103 const handlers = []; 34104 let currentPointerType = null; 34105 const getHandler = (eventKey) => { 34106 return (event) => { 34107 const target = getEventTarget(event); 34108 if (isBlocked(target, blockClass, blockSelector, unblockSelector, true)) { 34109 return; 34110 } 34111 let pointerType = null; 34112 let thisEventKey = eventKey; 34113 if ('pointerType' in event) { 34114 switch (event.pointerType) { 34115 case 'mouse': 34116 pointerType = PointerTypes.Mouse; 34117 break; 34118 case 'touch': 34119 pointerType = PointerTypes.Touch; 34120 break; 34121 case 'pen': 34122 pointerType = PointerTypes.Pen; 34123 break; 34124 } 34125 if (pointerType === PointerTypes.Touch) { 34126 if (MouseInteractions[eventKey] === MouseInteractions.MouseDown) { 34127 thisEventKey = 'TouchStart'; 34128 } 34129 else if (MouseInteractions[eventKey] === MouseInteractions.MouseUp) { 34130 thisEventKey = 'TouchEnd'; 34131 } 34132 } 34133 else if (pointerType === PointerTypes.Pen) ; 34134 } 34135 else if (legacy_isTouchEvent(event)) { 34136 pointerType = PointerTypes.Touch; 34137 } 34138 if (pointerType !== null) { 34139 currentPointerType = pointerType; 34140 if ((thisEventKey.startsWith('Touch') && 34141 pointerType === PointerTypes.Touch) || 34142 (thisEventKey.startsWith('Mouse') && 34143 pointerType === PointerTypes.Mouse)) { 34144 pointerType = null; 34145 } 34146 } 34147 else if (MouseInteractions[eventKey] === MouseInteractions.Click) { 34148 pointerType = currentPointerType; 34149 currentPointerType = null; 34150 } 34151 const e = legacy_isTouchEvent(event) ? event.changedTouches[0] : event; 34152 if (!e) { 34153 return; 34154 } 34155 const id = mirror.getId(target); 34156 const { clientX, clientY } = e; 34157 callbackWrapper(mouseInteractionCb)({ 34158 type: MouseInteractions[thisEventKey], 34159 id, 34160 x: clientX, 34161 y: clientY, 34162 ...(pointerType !== null && { pointerType }), 34163 }); 34164 }; 34165 }; 34166 Object.keys(MouseInteractions) 34167 .filter((key) => Number.isNaN(Number(key)) && 34168 !key.endsWith('_Departed') && 34169 disableMap[key] !== false) 34170 .forEach((eventKey) => { 34171 let eventName = toLowerCase(eventKey); 34172 const handler = getHandler(eventKey); 34173 if (window.PointerEvent) { 34174 switch (MouseInteractions[eventKey]) { 34175 case MouseInteractions.MouseDown: 34176 case MouseInteractions.MouseUp: 34177 eventName = eventName.replace('mouse', 'pointer'); 34178 break; 34179 case MouseInteractions.TouchStart: 34180 case MouseInteractions.TouchEnd: 34181 return; 34182 } 34183 } 34184 handlers.push(on(eventName, handler, doc)); 34185 }); 34186 return callbackWrapper(() => { 34187 handlers.forEach((h) => h()); 34188 }); 34189} 34190function initScrollObserver({ scrollCb, doc, mirror, blockClass, blockSelector, unblockSelector, sampling, }) { 34191 const updatePosition = callbackWrapper(throttle$1(callbackWrapper((evt) => { 34192 const target = getEventTarget(evt); 34193 if (!target || 34194 isBlocked(target, blockClass, blockSelector, unblockSelector, true)) { 34195 return; 34196 } 34197 const id = mirror.getId(target); 34198 if (target === doc && doc.defaultView) { 34199 const scrollLeftTop = getWindowScroll(doc.defaultView); 34200 scrollCb({ 34201 id, 34202 x: scrollLeftTop.left, 34203 y: scrollLeftTop.top, 34204 }); 34205 } 34206 else { 34207 scrollCb({ 34208 id, 34209 x: target.scrollLeft, 34210 y: target.scrollTop, 34211 }); 34212 } 34213 }), sampling.scroll || 100)); 34214 return on('scroll', updatePosition, doc); 34215} 34216function initViewportResizeObserver({ viewportResizeCb }, { win }) { 34217 let lastH = -1; 34218 let lastW = -1; 34219 const updateDimension = callbackWrapper(throttle$1(callbackWrapper(() => { 34220 const height = getWindowHeight(); 34221 const width = getWindowWidth(); 34222 if (lastH !== height || lastW !== width) { 34223 viewportResizeCb({ 34224 width: Number(width), 34225 height: Number(height),
34226 }); 34227 lastH = height; 34228 lastW = width; 34229 } 34230 }), 200)); 34231 return on('resize', updateDimension, win); 34232} 34233const INPUT_TAGS = ['INPUT', 'TEXTAREA', 'SELECT']; 34234const lastInputValueMap = new WeakMap(); 34235function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, unblockSelector, ignoreClass, ignoreSelector, maskInputOptions, maskInputFn, sampling, userTriggeredOnInput, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, }) { 34236 function eventHandler(event) { 34237 let target = getEventTarget(event); 34238 const userTriggered = event.isTrusted; 34239 const tagName = target && toUpperCase(target.tagName); 34240 if (tagName === 'OPTION') 34241 target = target.parentElement; 34242 if (!target || 34243 !tagName || 34244 INPUT_TAGS.indexOf(tagName) < 0 || 34245 isBlocked(target, blockClass, blockSelector, unblockSelector, true)) { 34246 return; 34247 } 34248 const el = target; 34249 if (el.classList.contains(ignoreClass) || 34250 (ignoreSelector && el.matches(ignoreSelector))) { 34251 return; 34252 } 34253 const type = getInputType(target); 34254 let text = getInputValue(el, tagName, type); 34255 let isChecked = false; 34256 const isInputMasked = shouldMaskInput({ 34257 maskInputOptions, 34258 tagName, 34259 type, 34260 }); 34261 const forceMask = needMaskingText(target, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, isInputMasked); 34262 if (type === 'radio' || type === 'checkbox') { 34263 isChecked = target.checked; 34264 } 34265 text = maskInputValue({ 34266 isMasked: forceMask, 34267 element: target, 34268 value: text, 34269 maskInputFn, 34270 }); 34271 cbWithDedup(target, userTriggeredOnInput 34272 ? { text, isChecked, userTriggered } 34273 : { text, isChecked }); 34274 const name = target.name; 34275 if (type === 'radio' && name && isChecked) { 34276 doc 34277 .querySelectorAll(`input[type="radio"][name="${name}"]`) 34278 .forEach((el) => { 34279 if (el !== target) { 34280 const text = maskInputValue({ 34281 isMasked: forceMask, 34282 element: el, 34283 value: getInputValue(el, tagName, type), 34284 maskInputFn, 34285 }); 34286 cbWithDedup(el, userTriggeredOnInput 34287 ? { text, isChecked: !isChecked, userTriggered: false } 34288 : { text, isChecked: !isChecked }); 34289 } 34290 }); 34291 } 34292 } 34293 function cbWithDedup(target, v) { 34294 const lastInputValue = lastInputValueMap.get(target); 34295 if (!lastInputValue || 34296 lastInputValue.text !== v.text || 34297 lastInputValue.isChecked !== v.isChecked) { 34298 lastInputValueMap.set(target, v); 34299 const id = mirror.getId(target); 34300 callbackWrapper(inputCb)({ 34301 ...v, 34302 id, 34303 }); 34304 } 34305 } 34306 const events = sampling.input === 'last' ? ['change'] : ['input', 'change']; 34307 const handlers = events.map((eventName) => on(eventName, callbackWrapper(eventHandler), doc)); 34308 const currentWindow = doc.defaultView; 34309 if (!currentWindow) { 34310 return () => { 34311 handlers.forEach((h) => h()); 34312 }; 34313 } 34314 const propertyDescriptor = currentWindow.Object.getOwnPropertyDescriptor(currentWindow.HTMLInputElement.prototype, 'value'); 34315 const hookProperties = [ 34316 [currentWindow.HTMLInputElement.prototype, 'value'], 34317 [currentWindow.HTMLInputElement.prototype, 'checked'], 34318 [currentWindow.HTMLSelectElement.prototype, 'value'], 34319 [currentWindow.HTMLTextAreaElement.prototype, 'value'], 34320 [currentWindow.HTMLSelectElement.prototype, 'selectedIndex'], 34321 [currentWindow.HTMLOptionElement.prototype, 'selected'], 34322 ]; 34323 if (propertyDescriptor && propertyDescriptor.set) { 34324 handlers.push(...hookProperties.map((p) => hookSetter(p[0], p[1], { 34325 set() { 34326 callbackWrapper(eventHandler)({ 34327 target: this, 34328 isTrusted: false, 34329 }); 34330 }, 34331 }, false, currentWindow))); 34332 } 34333 return callbackWrapper(() => {
34334 handlers.forEach((h) => h()); 34335 }); 34336} 34337function getNestedCSSRulePositions(rule) { 34338 const positions = []; 34339 function recurse(childRule, pos) { 34340 if ((hasNestedCSSRule('CSSGroupingRule') && 34341 childRule.parentRule instanceof CSSGroupingRule) || 34342 (hasNestedCSSRule('CSSMediaRule') && 34343 childRule.parentRule instanceof CSSMediaRule) || 34344 (hasNestedCSSRule('CSSSupportsRule') && 34345 childRule.parentRule instanceof CSSSupportsRule) || 34346 (hasNestedCSSRule('CSSConditionRule') && 34347 childRule.parentRule instanceof CSSConditionRule)) { 34348 const rules = Array.from(childRule.parentRule.cssRules); 34349 const index = rules.indexOf(childRule); 34350 pos.unshift(index); 34351 } 34352 else if (childRule.parentStyleSheet) { 34353 const rules = Array.from(childRule.parentStyleSheet.cssRules); 34354 const index = rules.indexOf(childRule); 34355 pos.unshift(index); 34356 } 34357 return pos; 34358 } 34359 return recurse(rule, positions); 34360} 34361function getIdAndStyleId(sheet, mirror, styleMirror) { 34362 let id, styleId; 34363 if (!sheet) 34364 return {}; 34365 if (sheet.ownerNode) 34366 id = mirror.getId(sheet.ownerNode); 34367 else 34368 styleId = styleMirror.getId(sheet); 34369 return { 34370 styleId, 34371 id, 34372 }; 34373} 34374function initStyleSheetObserver({ styleSheetRuleCb, mirror, stylesheetManager }, { win }) { 34375 if (!win.CSSStyleSheet || !win.CSSStyleSheet.prototype) { 34376 return () => { 34377 }; 34378 } 34379 const insertRule = win.CSSStyleSheet.prototype.insertRule; 34380 win.CSSStyleSheet.prototype.insertRule = new Proxy(insertRule, { 34381 apply: callbackWrapper((target, thisArg, argumentsList) => { 34382 const [rule, index] = argumentsList; 34383 const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror); 34384 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34385 styleSheetRuleCb({ 34386 id, 34387 styleId, 34388 adds: [{ rule, index }], 34389 }); 34390 } 34391 return target.apply(thisArg, argumentsList); 34392 }), 34393 }); 34394 const deleteRule = win.CSSStyleSheet.prototype.deleteRule; 34395 win.CSSStyleSheet.prototype.deleteRule = new Proxy(deleteRule, { 34396 apply: callbackWrapper((target, thisArg, argumentsList) => { 34397 const [index] = argumentsList; 34398 const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror); 34399 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34400 styleSheetRuleCb({ 34401 id, 34402 styleId, 34403 removes: [{ index }], 34404 }); 34405 } 34406 return target.apply(thisArg, argumentsList); 34407 }), 34408 }); 34409 let replace; 34410 if (win.CSSStyleSheet.prototype.replace) { 34411 replace = win.CSSStyleSheet.prototype.replace; 34412 win.CSSStyleSheet.prototype.replace = new Proxy(replace, { 34413 apply: callbackWrapper((target, thisArg, argumentsList) => { 34414 const [text] = argumentsList; 34415 const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror); 34416 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34417 styleSheetRuleCb({ 34418 id, 34419 styleId, 34420 replace: text, 34421 }); 34422 } 34423 return target.apply(thisArg, argumentsList); 34424 }), 34425 }); 34426 } 34427 let replaceSync; 34428 if (win.CSSStyleSheet.prototype.replaceSync) { 34429 replaceSync = win.CSSStyleSheet.prototype.replaceSync; 34430 win.CSSStyleSheet.prototype.replaceSync = new Proxy(replaceSync, { 34431 apply: callbackWrapper((target, thisArg, argumentsList) => { 34432 const [text] = argumentsList; 34433 const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror); 34434 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34435 styleSheetRuleCb({ 34436 id, 34437 styleId, 34438 replaceSync: text, 34439 }); 34440 } 34441 return target.apply(thisArg, argumentsList); 34442 }), 34443 }); 34444 } 34445 const supportedNestedCSSRuleTypes = {}; 34446 if (canMonkeyPatchNestedCSSRule('CSSGroupingRule')) { 34447 supportedNestedCSSRuleTypes.CSSGroupingRule = win.CSSGroupingRule; 34448 } 34449 else { 34450 if (canMonkeyPatchNestedCSSRule('CSSMediaRule')) { 34451 supportedNestedCSSRuleTypes.CSSMediaRule = win.CSSMediaRule; 34452 } 34453 if (canMonkeyPatchNestedCSSRule('CSSConditionRule')) { 34454 supportedNestedCSSRuleTypes.CSSConditionRule = win.CSSConditionRule; 34455 } 34456 if (canMonkeyPatchNestedCSSRule('CSSSupportsRule')) { 34457 supportedNestedCSSRuleTypes.CSSSupportsRule = win.CSSSupportsRule; 34458 } 34459 } 34460 const unmodifiedFunctions = {};
34461 Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => { 34462 unmodifiedFunctions[typeKey] = { 34463 insertRule: type.prototype.insertRule, 34464 deleteRule: type.prototype.deleteRule, 34465 }; 34466 type.prototype.insertRule = new Proxy(unmodifiedFunctions[typeKey].insertRule, { 34467 apply: callbackWrapper((target, thisArg, argumentsList) => { 34468 const [rule, index] = argumentsList; 34469 const { id, styleId } = getIdAndStyleId(thisArg.parentStyleSheet, mirror, stylesheetManager.styleMirror); 34470 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34471 styleSheetRuleCb({ 34472 id, 34473 styleId, 34474 adds: [ 34475 { 34476 rule, 34477 index: [ 34478 ...getNestedCSSRulePositions(thisArg), 34479 index || 0, 34480 ], 34481 }, 34482 ], 34483 }); 34484 } 34485 return target.apply(thisArg, argumentsList); 34486 }), 34487 }); 34488 type.prototype.deleteRule = new Proxy(unmodifiedFunctions[typeKey].deleteRule, { 34489 apply: callbackWrapper((target, thisArg, argumentsList) => { 34490 const [index] = argumentsList; 34491 const { id, styleId } = getIdAndStyleId(thisArg.parentStyleSheet, mirror, stylesheetManager.styleMirror); 34492 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34493 styleSheetRuleCb({ 34494 id, 34495 styleId, 34496 removes: [ 34497 { index: [...getNestedCSSRulePositions(thisArg), index] }, 34498 ], 34499 }); 34500 } 34501 return target.apply(thisArg, argumentsList); 34502 }), 34503 }); 34504 }); 34505 return callbackWrapper(() => { 34506 win.CSSStyleSheet.prototype.insertRule = insertRule; 34507 win.CSSStyleSheet.prototype.deleteRule = deleteRule; 34508 replace && (win.CSSStyleSheet.prototype.replace = replace); 34509 replaceSync && (win.CSSStyleSheet.prototype.replaceSync = replaceSync); 34510 Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => { 34511 type.prototype.insertRule = unmodifiedFunctions[typeKey].insertRule; 34512 type.prototype.deleteRule = unmodifiedFunctions[typeKey].deleteRule; 34513 }); 34514 }); 34515} 34516function initAdoptedStyleSheetObserver({ mirror, stylesheetManager, }, host) { 34517 let hostId = null; 34518 if (host.nodeName === '#document') 34519 hostId = mirror.getId(host); 34520 else 34521 hostId = mirror.getId(host.host); 34522 const patchTarget = host.nodeName === '#document' 34523 ? _optionalChain$2([host, 'access', _4 => _4.defaultView, 'optionalAccess', _5 => _5.Document]) 34524 : _optionalChain$2([host, 'access', _6 => _6.ownerDocument, 'optionalAccess', _7 => _7.defaultView, 'optionalAccess', _8 => _8.ShadowRoot]); 34525 const originalPropertyDescriptor = _optionalChain$2([patchTarget, 'optionalAccess', _9 => _9.prototype]) 34526 ? Object.getOwnPropertyDescriptor(_optionalChain$2([patchTarget, 'optionalAccess', _10 => _10.prototype]), 'adoptedStyleSheets') 34527 : undefined; 34528 if (hostId === null || 34529 hostId === -1 || 34530 !patchTarget || 34531 !originalPropertyDescriptor) 34532 return () => { 34533 }; 34534 Object.defineProperty(host, 'adoptedStyleSheets', { 34535 configurable: originalPropertyDescriptor.configurable, 34536 enumerable: originalPropertyDescriptor.enumerable, 34537 get() { 34538 return _optionalChain$2([originalPropertyDescriptor, 'access', _11 => _11.get, 'optionalAccess', _12 => _12.call, 'call', _13 => _13(this)]); 34539 }, 34540 set(sheets) { 34541 const result = _optionalChain$2([originalPropertyDescriptor, 'access', _14 => _14.set, 'optionalAccess', _15 => _15.call, 'call', _16 => _16(this, sheets)]); 34542 if (hostId !== null && hostId !== -1) { 34543 try { 34544 stylesheetManager.adoptStyleSheets(sheets, hostId); 34545 } 34546 catch (e) { 34547 } 34548 } 34549 return result; 34550 }, 34551 }); 34552 return callbackWrapper(() => { 34553 Object.defineProperty(host, 'adoptedStyleSheets', { 34554 configurable: originalPropertyDescriptor.configurable, 34555 enumerable: originalPropertyDescriptor.enumerable, 34556 get: originalPropertyDescriptor.get, 34557 set: originalPropertyDescriptor.set, 34558 }); 34559 }); 34560} 34561function initStyleDeclarationObserver({ styleDeclarationCb, mirror, ignoreCSSAttributes, stylesheetManager, }, { win }) { 34562 const setProperty = win.CSSStyleDeclaration.prototype.setProperty; 34563 win.CSSStyleDeclaration.prototype.setProperty = new Proxy(setProperty, { 34564 apply: callbackWrapper((target, thisArg, argumentsList) => { 34565 const [property, value, priority] = argumentsList; 34566 if (ignoreCSSAttributes.has(property)) { 34567 return setProperty.apply(thisArg, [property, value, priority]); 34568 } 34569 const { id, styleId } = getIdAndStyleId(_optionalChain$2([thisArg, 'access', _17 => _17.parentRule, 'optionalAccess', _18 => _18.parentStyleSheet]), mirror, stylesheetManager.styleMirror); 34570 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34571 styleDeclarationCb({ 34572 id, 34573 styleId, 34574 set: { 34575 property, 34576 value, 34577 priority, 34578 }, 34579 index: getNestedCSSRulePositions(thisArg.parentRule), 34580 }); 34581 } 34582 return target.apply(thisArg, argumentsList); 34583 }), 34584 }); 34585 const removeProperty = win.CSSStyleDeclaration.prototype.removeProperty; 34586 win.CSSStyleDeclaration.prototype.removeProperty = new Proxy(removeProperty, { 34587 apply: callbackWrapper((target, thisArg, argumentsList) => { 34588 const [property] = argumentsList; 34589 if (ignoreCSSAttributes.has(property)) { 34590 return removeProperty.apply(thisArg, [property]); 34591 } 34592 const { id, styleId } = getIdAndStyleId(_optionalChain$2([thisArg, 'access', _19 => _19.parentRule, 'optionalAccess', _20 => _20.parentStyleSheet]), mirror, stylesheetManager.styleMirror); 34593 if ((id && id !== -1) || (styleId && styleId !== -1)) { 34594 styleDeclarationCb({ 34595 id, 34596 styleId, 34597 remove: { 34598 property, 34599 }, 34600 index: getNestedCSSRulePositions(thisArg.parentRule), 34601 }); 34602 } 34603 return target.apply(thisArg, argumentsList); 34604 }), 34605 }); 34606 return callbackWrapper(() => { 34607 win.CSSStyleDeclaration.prototype.setProperty = setProperty; 34608 win.CSSStyleDeclaration.prototype.removeProperty = removeProperty; 34609 }); 34610} 34611function initMediaInteractionObserver({ mediaInteractionCb, blockClass, blockSelector, unblockSelector, mirror, sampling, doc, }) { 34612 const handler = callbackWrapper((type) => throttle$1(callbackWrapper((event) => { 34613 const target = getEventTarget(event); 34614 if (!target || 34615 isBlocked(target, blockClass, blockSelector, unblockSelector, true)) { 34616 return; 34617 } 34618 const { currentTime, volume, muted, playbackRate } = target; 34619 mediaInteractionCb({ 34620 type, 34621 id: mirror.getId(target), 34622 currentTime, 34623 volume, 34624 muted, 34625 playbackRate, 34626 }); 34627 }), sampling.media || 500)); 34628 const handlers = [ 34629 on('play', handler(0), doc), 34630 on('pause', handler(1), doc), 34631 on('seeked', handler(2), doc), 34632 on('volumechange', handler(3), doc), 34633 on('ratechange', handler(4), doc), 34634 ]; 34635 return callbackWrapper(() => {
34636 handlers.forEach((h) => h()); 34637 }); 34638} 34639function initFontObserver({ fontCb, doc }) { 34640 const win = doc.defaultView; 34641 if (!win) { 34642 return () => { 34643 }; 34644 } 34645 const handlers = []; 34646 const fontMap = new WeakMap(); 34647 const originalFontFace = win.FontFace; 34648 win.FontFace = function FontFace(family, source, descriptors) { 34649 const fontFace = new originalFontFace(family, source, descriptors); 34650 fontMap.set(fontFace, { 34651 family, 34652 buffer: typeof source !== 'string', 34653 descriptors, 34654 fontSource: typeof source === 'string' 34655 ? source 34656 : JSON.stringify(Array.from(new Uint8Array(source))), 34657 }); 34658 return fontFace; 34659 }; 34660 const restoreHandler = patch(doc.fonts, 'add', function (original) { 34661 return function (fontFace) { 34662 setTimeout(callbackWrapper(() => { 34663 const p = fontMap.get(fontFace); 34664 if (p) { 34665 fontCb(p); 34666 fontMap.delete(fontFace); 34667 } 34668 }), 0); 34669 return original.apply(this, [fontFace]); 34670 }; 34671 }); 34672 handlers.push(() => { 34673 win.FontFace = originalFontFace; 34674 }); 34675 handlers.push(restoreHandler); 34676 return callbackWrapper(() => { 34677 handlers.forEach((h) => h()); 34678 }); 34679} 34680function initSelectionObserver(param) { 34681 const { doc, mirror, blockClass, blockSelector, unblockSelector, selectionCb, } = param; 34682 let collapsed = true; 34683 const updateSelection = callbackWrapper(() => { 34684 const selection = doc.getSelection(); 34685 if (!selection || (collapsed && _optionalChain$2([selection, 'optionalAccess', _21 => _21.isCollapsed]))) 34686 return; 34687 collapsed = selection.isCollapsed || false; 34688 const ranges = []; 34689 const count = selection.rangeCount || 0; 34690 for (let i = 0; i < count; i++) { 34691 const range = selection.getRangeAt(i); 34692 const { startContainer, startOffset, endContainer, endOffset } = range; 34693 const blocked = isBlocked(startContainer, blockClass, blockSelector, unblockSelector, true) || 34694 isBlocked(endContainer, blockClass, blockSelector, unblockSelector, true); 34695 if (blocked) 34696 continue; 34697 ranges.push({ 34698 start: mirror.getId(startContainer), 34699 startOffset, 34700 end: mirror.getId(endContainer), 34701 endOffset, 34702 }); 34703 } 34704 selectionCb({ ranges }); 34705 }); 34706 updateSelection(); 34707 return on('selectionchange', updateSelection); 34708} 34709function initCustomElementObserver({ doc, customElementCb, }) { 34710 const win = doc.defaultView; 34711 if (!win || !win.customElements) 34712 return () => { }; 34713 const restoreHandler = patch(win.customElements, 'define', function (original) { 34714 return function (name, constructor, options) { 34715 try { 34716 customElementCb({ 34717 define: { 34718 name, 34719 }, 34720 }); 34721 } 34722 catch (e) { 34723 } 34724 return original.apply(this, [name, constructor, options]); 34725 }; 34726 }); 34727 return restoreHandler; 34728} 34729function initObservers(o, _hooks = {}) { 34730 const currentWindow = o.doc.defaultView; 34731 if (!currentWindow) { 34732 return () => { 34733 }; 34734 } 34735 const mutationObserver = initMutationObserver(o, o.doc); 34736 const mousemoveHandler = initMoveObserver(o); 34737 const mouseInteractionHandler = initMouseInteractionObserver(o); 34738 const scrollHandler = initScrollObserver(o); 34739 const viewportResizeHandler = initViewportResizeObserver(o, { 34740 win: currentWindow, 34741 }); 34742 const inputHandler = initInputObserver(o); 34743 const mediaInteractionHandler = initMediaInteractionObserver(o); 34744 const styleSheetObserver = initStyleSheetObserver(o, { win: currentWindow }); 34745 const adoptedStyleSheetObserver = initAdoptedStyleSheetObserver(o, o.doc); 34746 const styleDeclarationObserver = initStyleDeclarationObserver(o, { 34747 win: currentWindow, 34748 }); 34749 const fontObserver = o.collectFonts 34750 ? initFontObserver(o) 34751 : () => { 34752 }; 34753 const selectionObserver = initSelectionObserver(o); 34754 const customElementObserver = initCustomElementObserver(o); 34755 const pluginHandlers = []; 34756 for (const plugin of o.plugins) { 34757 pluginHandlers.push(plugin.observer(plugin.callback, currentWindow, plugin.options)); 34758 } 34759 return callbackWrapper(() => {
34760 mutationBuffers.forEach((b) => b.reset()); 34761 mutationObserver.disconnect(); 34762 mousemoveHandler(); 34763 mouseInteractionHandler(); 34764 scrollHandler(); 34765 viewportResizeHandler(); 34766 inputHandler(); 34767 mediaInteractionHandler(); 34768 styleSheetObserver(); 34769 adoptedStyleSheetObserver(); 34770 styleDeclarationObserver(); 34771 fontObserver(); 34772 selectionObserver(); 34773 customElementObserver(); 34774 pluginHandlers.forEach((h) => h()); 34775 }); 34776} 34777function hasNestedCSSRule(prop) { 34778 return typeof window[prop] !== 'undefined'; 34779} 34780function canMonkeyPatchNestedCSSRule(prop) { 34781 return Boolean(typeof window[prop] !== 'undefined' && 34782 window[prop].prototype && 34783 'insertRule' in window[prop].prototype && 34784 'deleteRule' in window[prop].prototype); 34785} 34786 34787class CrossOriginIframeMirror { 34788 constructor(generateIdFn) { 34789 this.generateIdFn = generateIdFn; 34790 this.iframeIdToRemoteIdMap = new WeakMap(); 34791 this.iframeRemoteIdToIdMap = new WeakMap(); 34792 } 34793 getId(iframe, remoteId, idToRemoteMap, remoteToIdMap) { 34794 const idToRemoteIdMap = idToRemoteMap || this.getIdToRemoteIdMap(iframe); 34795 const remoteIdToIdMap = remoteToIdMap || this.getRemoteIdToIdMap(iframe); 34796 let id = idToRemoteIdMap.get(remoteId); 34797 if (!id) { 34798 id = this.generateIdFn(); 34799 idToRemoteIdMap.set(remoteId, id); 34800 remoteIdToIdMap.set(id, remoteId); 34801 } 34802 return id; 34803 } 34804 getIds(iframe, remoteId) { 34805 const idToRemoteIdMap = this.getIdToRemoteIdMap(iframe); 34806 const remoteIdToIdMap = this.getRemoteIdToIdMap(iframe); 34807 return remoteId.map((id) => this.getId(iframe, id, idToRemoteIdMap, remoteIdToIdMap)); 34808 } 34809 getRemoteId(iframe, id, map) { 34810 const remoteIdToIdMap = map || this.getRemoteIdToIdMap(iframe); 34811 if (typeof id !== 'number') 34812 return id; 34813 const remoteId = remoteIdToIdMap.get(id); 34814 if (!remoteId) 34815 return -1; 34816 return remoteId; 34817 } 34818 getRemoteIds(iframe, ids) { 34819 const remoteIdToIdMap = this.getRemoteIdToIdMap(iframe); 34820 return ids.map((id) => this.getRemoteId(iframe, id, remoteIdToIdMap)); 34821 } 34822 reset(iframe) { 34823 if (!iframe) { 34824 this.iframeIdToRemoteIdMap = new WeakMap(); 34825 this.iframeRemoteIdToIdMap = new WeakMap(); 34826 return; 34827 } 34828 this.iframeIdToRemoteIdMap.delete(iframe); 34829 this.iframeRemoteIdToIdMap.delete(iframe); 34830 } 34831 getIdToRemoteIdMap(iframe) { 34832 let idToRemoteIdMap = this.iframeIdToRemoteIdMap.get(iframe); 34833 if (!idToRemoteIdMap) { 34834 idToRemoteIdMap = new Map(); 34835 this.iframeIdToRemoteIdMap.set(iframe, idToRemoteIdMap); 34836 } 34837 return idToRemoteIdMap; 34838 } 34839 getRemoteIdToIdMap(iframe) { 34840 let remoteIdToIdMap = this.iframeRemoteIdToIdMap.get(iframe); 34841 if (!remoteIdToIdMap) { 34842 remoteIdToIdMap = new Map(); 34843 this.iframeRemoteIdToIdMap.set(iframe, remoteIdToIdMap); 34844 } 34845 return remoteIdToIdMap; 34846 } 34847} 34848 34849function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } 34850class IframeManagerNoop { 34851 constructor() { 34852 this.crossOriginIframeMirror = new CrossOriginIframeMirror(genId); 34853 this.crossOriginIframeRootIdMap = new WeakMap(); 34854 } 34855 addIframe() { 34856 } 34857 addLoadListener() { 34858 } 34859 attachIframe() { 34860 } 34861} 34862class IframeManager { 34863 constructor(options) { 34864 this.iframes = new WeakMap(); 34865 this.crossOriginIframeMap = new WeakMap(); 34866 this.crossOriginIframeMirror = new CrossOriginIframeMirror(genId); 34867 this.crossOriginIframeRootIdMap = new WeakMap(); 34868 this.mutationCb = options.mutationCb; 34869 this.wrappedEmit = options.wrappedEmit; 34870 this.stylesheetManager = options.stylesheetManager; 34871 this.recordCrossOriginIframes = options.recordCrossOriginIframes; 34872 this.crossOriginIframeStyleMirror = new CrossOriginIframeMirror(this.stylesheetManager.styleMirror.generateId.bind(this.stylesheetManager.styleMirror)); 34873 this.mirror = options.mirror; 34874 if (this.recordCrossOriginIframes) { 34875 window.addEventListener('message', this.handleMessage.bind(this)); 34876 } 34877 } 34878 addIframe(iframeEl) { 34879 this.iframes.set(iframeEl, true); 34880 if (iframeEl.contentWindow) 34881 this.crossOriginIframeMap.set(iframeEl.contentWindow, iframeEl); 34882 } 34883 addLoadListener(cb) { 34884 this.loadListener = cb; 34885 } 34886 attachIframe(iframeEl, childSn) { 34887 this.mutationCb({ 34888 adds: [ 34889 { 34890 parentId: this.mirror.getId(iframeEl), 34891 nextId: null, 34892 node: childSn, 34893 }, 34894 ], 34895 removes: [], 34896 texts: [], 34897 attributes: [], 34898 isAttachIframe: true, 34899 }); 34900 _optionalChain$1([this, 'access', _ => _.loadListener, 'optionalCall', _2 => _2(iframeEl)]); 34901 if (iframeEl.contentDocument && 34902 iframeEl.contentDocument.adoptedStyleSheets && 34903 iframeEl.contentDocument.adoptedStyleSheets.length > 0) 34904 this.stylesheetManager.adoptStyleSheets(iframeEl.contentDocument.adoptedStyleSheets, this.mirror.getId(iframeEl.contentDocument)); 34905 } 34906 handleMessage(message) { 34907 const crossOriginMessageEvent = message; 34908 if (crossOriginMessageEvent.data.type !== 'rrweb' || 34909 crossOriginMessageEvent.origin !== crossOriginMessageEvent.data.origin) 34910 return; 34911 const iframeSourceWindow = message.source; 34912 if (!iframeSourceWindow) 34913 return; 34914 const iframeEl = this.crossOriginIframeMap.get(message.source); 34915 if (!iframeEl) 34916 return; 34917 const transformedEvent = this.transformCrossOriginEvent(iframeEl, crossOriginMessageEvent.data.event); 34918 if (transformedEvent) 34919 this.wrappedEmit(transformedEvent, crossOriginMessageEvent.data.isCheckout); 34920 } 34921 transformCrossOriginEvent(iframeEl, e) { 34922 switch (e.type) { 34923 case EventType.FullSnapshot: { 34924 this.crossOriginIframeMirror.reset(iframeEl); 34925 this.crossOriginIframeStyleMirror.reset(iframeEl); 34926 this.replaceIdOnNode(e.data.node, iframeEl); 34927 const rootId = e.data.node.id; 34928 this.crossOriginIframeRootIdMap.set(iframeEl, rootId); 34929 this.patchRootIdOnNode(e.data.node, rootId); 34930 return { 34931 timestamp: e.timestamp, 34932 type: EventType.IncrementalSnapshot, 34933 data: { 34934 source: IncrementalSource.Mutation, 34935 adds: [ 34936 { 34937 parentId: this.mirror.getId(iframeEl), 34938 nextId: null, 34939 node: e.data.node, 34940 }, 34941 ], 34942 removes: [], 34943 texts: [], 34944 attributes: [], 34945 isAttachIframe: true, 34946 }, 34947 }; 34948 } 34949 case EventType.Meta: 34950 case EventType.Load: 34951 case EventType.DomContentLoaded: { 34952 return false;
34953 } 34954 case EventType.Plugin: { 34955 return e; 34956 } 34957 case EventType.Custom: { 34958 this.replaceIds(e.data.payload, iframeEl, ['id', 'parentId', 'previousId', 'nextId']); 34959 return e; 34960 } 34961 case EventType.IncrementalSnapshot: { 34962 switch (e.data.source) { 34963 case IncrementalSource.Mutation: { 34964 e.data.adds.forEach((n) => { 34965 this.replaceIds(n, iframeEl, [ 34966 'parentId', 34967 'nextId', 34968 'previousId', 34969 ]); 34970 this.replaceIdOnNode(n.node, iframeEl); 34971 const rootId = this.crossOriginIframeRootIdMap.get(iframeEl); 34972 rootId && this.patchRootIdOnNode(n.node, rootId); 34973 }); 34974 e.data.removes.forEach((n) => { 34975 this.replaceIds(n, iframeEl, ['parentId', 'id']); 34976 }); 34977 e.data.attributes.forEach((n) => { 34978 this.replaceIds(n, iframeEl, ['id']); 34979 }); 34980 e.data.texts.forEach((n) => { 34981 this.replaceIds(n, iframeEl, ['id']); 34982 }); 34983 return e; 34984 } 34985 case IncrementalSource.Drag: 34986 case IncrementalSource.TouchMove: 34987 case IncrementalSource.MouseMove: { 34988 e.data.positions.forEach((p) => { 34989 this.replaceIds(p, iframeEl, ['id']); 34990 }); 34991 return e; 34992 } 34993 case IncrementalSource.ViewportResize: { 34994 return false; 34995 } 34996 case IncrementalSource.MediaInteraction: 34997 case IncrementalSource.MouseInteraction: 34998 case IncrementalSource.Scroll: 34999 case IncrementalSource.CanvasMutation: 35000 case IncrementalSource.Input: { 35001 this.replaceIds(e.data, iframeEl, ['id']); 35002 return e; 35003 } 35004 case IncrementalSource.StyleSheetRule: 35005 case IncrementalSource.StyleDeclaration: { 35006 this.replaceIds(e.data, iframeEl, ['id']); 35007 this.replaceStyleIds(e.data, iframeEl, ['styleId']); 35008 return e; 35009 } 35010 case IncrementalSource.Font: { 35011 return e; 35012 } 35013 case IncrementalSource.Selection: { 35014 e.data.ranges.forEach((range) => { 35015 this.replaceIds(range, iframeEl, ['start', 'end']); 35016 }); 35017 return e; 35018 } 35019 case IncrementalSource.AdoptedStyleSheet: { 35020 this.replaceIds(e.data, iframeEl, ['id']); 35021 this.replaceStyleIds(e.data, iframeEl, ['styleIds']); 35022 _optionalChain$1([e, 'access', _3 => _3.data, 'access', _4 => _4.styles, 'optionalAccess', _5 => _5.forEach, 'call', _6 => _6((style) => { 35023 this.replaceStyleIds(style, iframeEl, ['styleId']); 35024 })]); 35025 return e; 35026 } 35027 } 35028 } 35029 } 35030 return false; 35031 } 35032 replace(iframeMirror, obj, iframeEl, keys) { 35033 for (const key of keys) { 35034 if (!Array.isArray(obj[key]) && typeof obj[key] !== 'number') 35035 continue; 35036 if (Array.isArray(obj[key])) { 35037 obj[key] = iframeMirror.getIds(iframeEl, obj[key]); 35038 } 35039 else { 35040 obj[key] = iframeMirror.getId(iframeEl, obj[key]); 35041 } 35042 } 35043 return obj; 35044 } 35045 replaceIds(obj, iframeEl, keys) { 35046 return this.replace(this.crossOriginIframeMirror, obj, iframeEl, keys); 35047 } 35048 replaceStyleIds(obj, iframeEl, keys) { 35049 return this.replace(this.crossOriginIframeStyleMirror, obj, iframeEl, keys); 35050 } 35051 replaceIdOnNode(node, iframeEl) { 35052 this.replaceIds(node, iframeEl, ['id', 'rootId']);
35053 if ('childNodes' in node) { 35054 node.childNodes.forEach((child) => { 35055 this.replaceIdOnNode(child, iframeEl); 35056 }); 35057 } 35058 } 35059 patchRootIdOnNode(node, rootId) { 35060 if (node.type !== NodeType$1.Document && !node.rootId) 35061 node.rootId = rootId; 35062 if ('childNodes' in node) { 35063 node.childNodes.forEach((child) => { 35064 this.patchRootIdOnNode(child, rootId); 35065 }); 35066 } 35067 } 35068} 35069 35070class ShadowDomManagerNoop { 35071 init() { 35072 } 35073 addShadowRoot() { 35074 } 35075 observeAttachShadow() { 35076 } 35077 reset() { 35078 } 35079} 35080class ShadowDomManager { 35081 constructor(options) { 35082 this.shadowDoms = new WeakSet(); 35083 this.restoreHandlers = []; 35084 this.mutationCb = options.mutationCb; 35085 this.scrollCb = options.scrollCb; 35086 this.bypassOptions = options.bypassOptions; 35087 this.mirror = options.mirror; 35088 this.init(); 35089 } 35090 init() { 35091 this.reset(); 35092 this.patchAttachShadow(Element, document); 35093 } 35094 addShadowRoot(shadowRoot, doc) { 35095 if (!isNativeShadowDom(shadowRoot)) 35096 return; 35097 if (this.shadowDoms.has(shadowRoot)) 35098 return; 35099 this.shadowDoms.add(shadowRoot); 35100 const observer = initMutationObserver({ 35101 ...this.bypassOptions, 35102 doc, 35103 mutationCb: this.mutationCb, 35104 mirror: this.mirror, 35105 shadowDomManager: this, 35106 }, shadowRoot); 35107 this.restoreHandlers.push(() => observer.disconnect()); 35108 this.restoreHandlers.push(initScrollObserver({ 35109 ...this.bypassOptions, 35110 scrollCb: this.scrollCb, 35111 doc: shadowRoot, 35112 mirror: this.mirror, 35113 })); 35114 setTimeout(() => { 35115 if (shadowRoot.adoptedStyleSheets && 35116 shadowRoot.adoptedStyleSheets.length > 0) 35117 this.bypassOptions.stylesheetManager.adoptStyleSheets(shadowRoot.adoptedStyleSheets, this.mirror.getId(shadowRoot.host)); 35118 this.restoreHandlers.push(initAdoptedStyleSheetObserver({ 35119 mirror: this.mirror, 35120 stylesheetManager: this.bypassOptions.stylesheetManager, 35121 }, shadowRoot)); 35122 }, 0); 35123 } 35124 observeAttachShadow(iframeElement) { 35125 if (!iframeElement.contentWindow || !iframeElement.contentDocument) 35126 return; 35127 this.patchAttachShadow(iframeElement.contentWindow.Element, iframeElement.contentDocument); 35128 } 35129 patchAttachShadow(element, doc) { 35130 const manager = this; 35131 this.restoreHandlers.push(patch(element.prototype, 'attachShadow', function (original) { 35132 return function (option) { 35133 const shadowRoot = original.call(this, option); 35134 if (this.shadowRoot && inDom(this)) 35135 manager.addShadowRoot(this.shadowRoot, doc); 35136 return shadowRoot; 35137 }; 35138 })); 35139 } 35140 reset() { 35141 this.restoreHandlers.forEach((handler) => { 35142 try { 35143 handler(); 35144 } 35145 catch (e) { 35146 } 35147 }); 35148 this.restoreHandlers = []; 35149 this.shadowDoms = new WeakSet(); 35150 } 35151} 35152 35153class CanvasManagerNoop { 35154 reset() { 35155 } 35156 freeze() { 35157 } 35158 unfreeze() { 35159 } 35160 lock() { 35161 } 35162 unlock() { 35163 } 35164 snapshot() { 35165 } 35166} 35167 35168class StylesheetManager { 35169 constructor(options) { 35170 this.trackedLinkElements = new WeakSet(); 35171 this.styleMirror = new StyleSheetMirror(); 35172 this.mutationCb = options.mutationCb; 35173 this.adoptedStyleSheetCb = options.adoptedStyleSheetCb; 35174 } 35175 attachLinkElement(linkEl, childSn) { 35176 if ('_cssText' in childSn.attributes) 35177 this.mutationCb({ 35178 adds: [], 35179 removes: [], 35180 texts: [], 35181 attributes: [ 35182 { 35183 id: childSn.id, 35184 attributes: childSn 35185 .attributes, 35186 }, 35187 ], 35188 }); 35189 this.trackLinkElement(linkEl); 35190 } 35191 trackLinkElement(linkEl) { 35192 if (this.trackedLinkElements.has(linkEl)) 35193 return; 35194 this.trackedLinkElements.add(linkEl); 35195 this.trackStylesheetInLinkElement(linkEl); 35196 } 35197 adoptStyleSheets(sheets, hostId) { 35198 if (sheets.length === 0) 35199 return; 35200 const adoptedStyleSheetData = { 35201 id: hostId, 35202 styleIds: [], 35203 }; 35204 const styles = []; 35205 for (const sheet of sheets) { 35206 let styleId; 35207 if (!this.styleMirror.has(sheet)) { 35208 styleId = this.styleMirror.add(sheet); 35209 styles.push({ 35210 styleId, 35211 rules: Array.from(sheet.rules || CSSRule, (r, index) => ({ 35212 rule: stringifyRule(r), 35213 index, 35214 })), 35215 }); 35216 } 35217 else 35218 styleId = this.styleMirror.getId(sheet); 35219 adoptedStyleSheetData.styleIds.push(styleId); 35220 } 35221 if (styles.length > 0) 35222 adoptedStyleSheetData.styles = styles; 35223 this.adoptedStyleSheetCb(adoptedStyleSheetData); 35224 } 35225 reset() { 35226 this.styleMirror.reset(); 35227 this.trackedLinkElements = new WeakSet(); 35228 } 35229 trackStylesheetInLinkElement(linkEl) { 35230 } 35231} 35232 35233class ProcessedNodeManager { 35234 constructor() { 35235 this.nodeMap = new WeakMap(); 35236 this.loop = true; 35237 this.periodicallyClear(); 35238 } 35239 periodicallyClear() { 35240 onRequestAnimationFrame(() => { 35241 this.clear(); 35242 if (this.loop) 35243 this.periodicallyClear(); 35244 }); 35245 } 35246 inOtherBuffer(node, thisBuffer) { 35247 const buffers = this.nodeMap.get(node); 35248 return (buffers && Array.from(buffers).some((buffer) =>
35248 buffer !== thisBuffer)); 35249 } 35250 add(node, buffer) { 35251 this.nodeMap.set(node, (this.nodeMap.get(node) || new Set()).add(buffer)); 35252 } 35253 clear() { 35254 this.nodeMap = new WeakMap(); 35255 } 35256 destroy() { 35257 this.loop = false; 35258 } 35259} 35260 35261function wrapEvent(e) { 35262 const eWithTime = e; 35263 eWithTime.timestamp = nowTimestamp(); 35264 return eWithTime; 35265} 35266let _takeFullSnapshot; 35267const mirror = createMirror(); 35268function record(options = {}) { 35269 const { emit, checkoutEveryNms, checkoutEveryNth, blockClass = 'rr-block', blockSelector = null, unblockSelector = null, ignoreClass = 'rr-ignore', ignoreSelector = null, maskAllText = false, maskTextClass = 'rr-mask', unmaskTextClass = null, maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, maskAllInputs, maskInputOptions: _maskInputOptions, slimDOMOptions: _slimDOMOptions, maskAttributeFn, maskInputFn, maskTextFn, packFn, sampling = {}, dataURLOptions = {}, mousemoveWait, recordCanvas = false, recordCrossOriginIframes = false, recordAfter = options.recordAfter === 'DOMContentLoaded' 35270 ? options.recordAfter 35271 : 'load', userTriggeredOnInput = false, collectFonts = false, inlineImages = false, plugins, keepIframeSrcFn = () => false, ignoreCSSAttributes = new Set([]), errorHandler, onMutation, getCanvasManager, } = options; 35272 registerErrorHandler(errorHandler); 35273 const inEmittingFrame = recordCrossOriginIframes 35274 ? window.parent === window 35275 : true; 35276 let passEmitsToParent = false; 35277 if (!inEmittingFrame) { 35278 try { 35279 if (window.parent.document) { 35280 passEmitsToParent = false; 35281 } 35282 } 35283 catch (e) { 35284 passEmitsToParent = true; 35285 } 35286 } 35287 if (inEmittingFrame && !emit) { 35288 throw new Error('emit function is required'); 35289 } 35290 if (mousemoveWait !== undefined && sampling.mousemove === undefined) { 35291 sampling.mousemove = mousemoveWait; 35292 } 35293 mirror.reset(); 35294 const maskInputOptions = maskAllInputs === true 35295 ? { 35296 color: true, 35297 date: true, 35298 'datetime-local': true, 35299 email: true, 35300 month: true, 35301 number: true, 35302 range: true, 35303 search: true, 35304 tel: true, 35305 text: true, 35306 time: true, 35307 url: true, 35308 week: true, 35309 textarea: true, 35310 select: true, 35311 radio: true, 35312 checkbox: true, 35313 } 35314 : _maskInputOptions !== undefined 35315 ? _maskInputOptions 35316 : {}; 35317 const slimDOMOptions = _slimDOMOptions === true || _slimDOMOptions === 'all' 35318 ? { 35319 script: true, 35320 comment: true, 35321 headFavicon: true, 35322 headWhitespace: true, 35323 headMetaSocial: true, 35324 headMetaRobots: true, 35325 headMetaHttpEquiv: true, 35326 headMetaVerification: true, 35327 headMetaAuthorship: _slimDOMOptions === 'all', 35328 headMetaDescKeywords: _slimDOMOptions === 'all', 35329 } 35330 : _slimDOMOptions 35331 ? _slimDOMOptions 35332 : {}; 35333 polyfill(); 35334 let lastFullSnapshotEvent; 35335 let incrementalSnapshotCount = 0; 35336 const eventProcessor = (e) => { 35337 for (const plugin of plugins || []) { 35338 if (plugin.eventProcessor) { 35339 e = plugin.eventProcessor(e); 35340 } 35341 } 35342 if (packFn && 35343 !passEmitsToParent) { 35344 e = packFn(e); 35345 } 35346 return e; 35347 }; 35348 const wrappedEmit = (e, isCheckout) => { 35349 if (_optionalChain([mutationBuffers, 'access', _ => _[0], 'optionalAccess', _2 => _2.isFrozen, 'call', _3 => _3()]) && 35350 e.type !== EventType.FullSnapshot && 35351 !(e.type === EventType.IncrementalSnapshot && 35352 e.data.source === IncrementalSource.Mutation)) { 35353 mutationBuffers.forEach((buf) => buf.unfreeze()); 35354 } 35355 if (inEmittingFrame) { 35356 _optionalChain([emit, 'optionalCall', _4 => _4(eventProcessor(e), isCheckout)]); 35357 } 35358 else if (passEmitsToParent) { 35359 const message = { 35360 type: 'rrweb', 35361 event: eventProcessor(e), 35362 origin: window.location.origin, 35363 isCheckout, 35364 }; 35365 window.parent.postMessage(message, '*'); 35366 } 35367 if (e.type === EventType.FullSnapshot) { 35368 lastFullSnapshotEvent = e; 35369 incrementalSnapshotCount = 0; 35370 } 35371 else if (e.type === EventType.IncrementalSnapshot) { 35372 if (e.data.source === IncrementalSource.Mutation && 35373 e.data.isAttachIframe) { 35374 return; 35375 } 35376 incrementalSnapshotCount++; 35377 const exceedCount = checkoutEveryNth && incrementalSnapshotCount >= checkoutEveryNth; 35378 const exceedTime = checkoutEveryNms && 35379 e.timestamp - lastFullSnapshotEvent.timestamp > checkoutEveryNms; 35380 if (exceedCount || exceedTime) { 35381 takeFullSnapshot(true); 35382 } 35383 } 35384 }; 35385 const wrappedMutationEmit = (m) => { 35386 wrappedEmit(wrapEvent({ 35387 type: EventType.IncrementalSnapshot, 35388 data: { 35389 source: IncrementalSource.Mutation, 35390 ...m, 35391 }, 35392 })); 35393 }; 35394 const wrappedScrollEmit = (p) => wrappedEmit(wrapEvent({ 35395 type: EventType.IncrementalSnapshot, 35396 data: { 35397 source: IncrementalSource.Scroll, 35398 ...p, 35399 }, 35400 })); 35401 const wrappedCanvasMutationEmit = (p) => wrappedEmit(wrapEvent({ 35402 type: EventType.IncrementalSnapshot, 35403 data: { 35404 source: IncrementalSource.CanvasMutation, 35405 ...p, 35406 }, 35407 })); 35408 const wrappedAdoptedStyleSheetEmit = (a) => wrappedEmit(wrapEvent({ 35409 type: EventType.IncrementalSnapshot, 35410 data: { 35411 source: IncrementalSource.AdoptedStyleSheet, 35412 ...a, 35413 }, 35414 })); 35415 const stylesheetManager = new StylesheetManager({ 35416 mutationCb: wrappedMutationEmit, 35417 adoptedStyleSheetCb: wrappedAdoptedStyleSheetEmit, 35418 }); 35419 const iframeManager = typeof __RRWEB_EXCLUDE_IFRAME__ === 'boolean' && __RRWEB_EXCLUDE_IFRAME__ 35420 ? new IframeManagerNoop() 35421 : new IframeManager({ 35422 mirror, 35423 mutationCb: wrappedMutationEmit, 35424 stylesheetManager: stylesheetManager, 35425 recordCrossOriginIframes, 35426 wrappedEmit, 35427 }); 35428 for (const plugin of plugins || []) { 35429 if (plugin.getMirror) 35430 plugin.getMirror({ 35431 nodeMirror: mirror, 35432 crossOriginIframeMirror: iframeManager.crossOriginIframeMirror, 35433 crossOriginIframeStyleMirror: iframeManager.crossOriginIframeStyleMirror, 35434 }); 35435 } 35436 const processedNodeManager = new ProcessedNodeManager(); 35437 const canvasManager = _getCanvasManager(getCanvasManager, { 35438 mirror, 35439 win: window, 35440 mutationCb: (p) => wrappedEmit(wrapEvent({ 35441 type: EventType.IncrementalSnapshot, 35442 data: { 35443 source: IncrementalSource.CanvasMutation, 35444 ...p, 35445 }, 35446 })), 35447 recordCanvas, 35448 blockClass, 35449 blockSelector, 35450 unblockSelector, 35451 sampling: sampling['canvas'], 35452 dataURLOptions, 35453 errorHandler, 35454 }); 35455 const shadowDomManager = typeof __RRWEB_EXCLUDE_SHADOW_DOM__ === 'boolean' && 35456 __RRWEB_EXCLUDE_SHADOW_DOM__ 35457 ? new ShadowDomManagerNoop() 35458 : new ShadowDomManager({ 35459 mutationCb: wrappedMutationEmit, 35460 scrollCb: wrappedScrollEmit, 35461 bypassOptions: { 35462 onMutation, 35463 blockClass, 35464 blockSelector, 35465 unblockSelector, 35466 maskAllText, 35467 maskTextClass, 35468 unmaskTextClass, 35469 maskTextSelector, 35470 unmaskTextSelector, 35471 inlineStylesheet, 35472 maskInputOptions, 35473 dataURLOptions, 35474 maskAttributeFn, 35475 maskTextFn, 35476 maskInputFn, 35477 recordCanvas, 35478 inlineImages, 35479 sampling, 35480 slimDOMOptions, 35481 iframeManager, 35482 stylesheetManager, 35483 canvasManager, 35484 keepIframeSrcFn,
35485 processedNodeManager, 35486 }, 35487 mirror, 35488 }); 35489 const takeFullSnapshot = (isCheckout = false) => { 35490 wrappedEmit(wrapEvent({ 35491 type: EventType.Meta, 35492 data: { 35493 href: window.location.href, 35494 width: getWindowWidth(), 35495 height: getWindowHeight(), 35496 }, 35497 }), isCheckout); 35498 stylesheetManager.reset(); 35499 shadowDomManager.init(); 35500 mutationBuffers.forEach((buf) => buf.lock()); 35501 const node = snapshot(document, { 35502 mirror, 35503 blockClass, 35504 blockSelector, 35505 unblockSelector, 35506 maskAllText, 35507 maskTextClass, 35508 unmaskTextClass, 35509 maskTextSelector, 35510 unmaskTextSelector, 35511 inlineStylesheet, 35512 maskAllInputs: maskInputOptions, 35513 maskAttributeFn, 35514 maskInputFn, 35515 maskTextFn, 35516 slimDOM: slimDOMOptions, 35517 dataURLOptions, 35518 recordCanvas, 35519 inlineImages, 35520 onSerialize: (n) => { 35521 if (isSerializedIframe(n, mirror)) { 35522 iframeManager.addIframe(n); 35523 } 35524 if (isSerializedStylesheet(n, mirror)) { 35525 stylesheetManager.trackLinkElement(n); 35526 } 35527 if (hasShadowRoot(n)) { 35528 shadowDomManager.addShadowRoot(n.shadowRoot, document); 35529 } 35530 }, 35531 onIframeLoad: (iframe, childSn) => { 35532 iframeManager.attachIframe(iframe, childSn); 35533 shadowDomManager.observeAttachShadow(iframe); 35534 }, 35535 onStylesheetLoad: (linkEl, childSn) => { 35536 stylesheetManager.attachLinkElement(linkEl, childSn); 35537 }, 35538 keepIframeSrcFn, 35539 }); 35540 if (!node) { 35541 return console.warn('Failed to snapshot the document'); 35542 } 35543 wrappedEmit(wrapEvent({ 35544 type: EventType.FullSnapshot, 35545 data: { 35546 node, 35547 initialOffset: getWindowScroll(window), 35548 }, 35549 })); 35550 mutationBuffers.forEach((buf) => buf.unlock()); 35551 if (document.adoptedStyleSheets && document.adoptedStyleSheets.length > 0) 35552 stylesheetManager.adoptStyleSheets(document.adoptedStyleSheets, mirror.getId(document)); 35553 }; 35554 _takeFullSnapshot = takeFullSnapshot; 35555 try { 35556 const handlers = []; 35557 const observe = (doc) => { 35558 return callbackWrapper(initObservers)({ 35559 onMutation, 35560 mutationCb: wrappedMutationEmit, 35561 mousemoveCb: (positions, source) => wrappedEmit(wrapEvent({ 35562 type: EventType.IncrementalSnapshot, 35563 data: { 35564 source, 35565 positions, 35566 }, 35567 })), 35568 mouseInteractionCb: (d) => wrappedEmit(wrapEvent({ 35569 type: EventType.IncrementalSnapshot, 35570 data: { 35571 source: IncrementalSource.MouseInteraction, 35572 ...d, 35573 }, 35574 })), 35575 scrollCb: wrappedScrollEmit, 35576 viewportResizeCb: (d) => wrappedEmit(wrapEvent({ 35577 type: EventType.IncrementalSnapshot, 35578 data: { 35579 source: IncrementalSource.ViewportResize, 35580 ...d, 35581 }, 35582 })), 35583 inputCb: (v) => wrappedEmit(wrapEvent({ 35584 type: EventType.IncrementalSnapshot, 35585 data: { 35586 source: IncrementalSource.Input, 35587 ...v, 35588 }, 35589 })), 35590 mediaInteractionCb: (p) => wrappedEmit(wrapEvent({ 35591 type: EventType.IncrementalSnapshot, 35592 data: { 35593 source: IncrementalSource.MediaInteraction, 35594 ...p, 35595 }, 35596 })), 35597 styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({ 35598 type: EventType.IncrementalSnapshot, 35599 data: { 35600 source: IncrementalSource.StyleSheetRule, 35601 ...r, 35602 }, 35603 })), 35604 styleDeclarationCb: (r) => wrappedEmit(wrapEvent({ 35605 type: EventType.IncrementalSnapshot, 35606 data: { 35607 source: IncrementalSource.StyleDeclaration, 35608 ...r, 35609 }, 35610 })), 35611 canvasMutationCb: wrappedCanvasMutationEmit, 35612 fontCb: (p) => wrappedEmit(wrapEvent({ 35613 type: EventType.IncrementalSnapshot, 35614 data: { 35615 source: IncrementalSource.Font, 35616 ...p, 35617 }, 35618 })), 35619 selectionCb: (p) => { 35620 wrappedEmit(wrapEvent({ 35621 type: EventType.IncrementalSnapshot, 35622 data: { 35623 source: IncrementalSource.Selection, 35624 ...p, 35625 }, 35626 })); 35627 }, 35628 customElementCb: (c) => { 35629 wrappedEmit(wrapEvent({ 35630 type: EventType.IncrementalSnapshot, 35631 data: { 35632 source: IncrementalSource.CustomElement, 35633 ...c, 35634 }, 35635 })); 35636 }, 35637 blockClass, 35638 ignoreClass, 35639 ignoreSelector, 35640 maskAllText, 35641 maskTextClass, 35642 unmaskTextClass, 35643 maskTextSelector, 35644 unmaskTextSelector, 35645 maskInputOptions, 35646 inlineStylesheet, 35647 sampling, 35648 recordCanvas, 35649 inlineImages,
35650 userTriggeredOnInput, 35651 collectFonts, 35652 doc, 35653 maskAttributeFn, 35654 maskInputFn, 35655 maskTextFn, 35656 keepIframeSrcFn, 35657 blockSelector, 35658 unblockSelector, 35659 slimDOMOptions, 35660 dataURLOptions, 35661 mirror, 35662 iframeManager, 35663 stylesheetManager, 35664 shadowDomManager, 35665 processedNodeManager, 35666 canvasManager, 35667 ignoreCSSAttributes, 35668 plugins: _optionalChain([plugins 35669, 'optionalAccess', _5 => _5.filter, 'call', _6 => _6((p) => p.observer) 35670, 'optionalAccess', _7 => _7.map, 'call', _8 => _8((p) => ({ 35671 observer: p.observer, 35672 options: p.options, 35673 callback: (payload) => wrappedEmit(wrapEvent({ 35674 type: EventType.Plugin, 35675 data: { 35676 plugin: p.name, 35677 payload, 35678 }, 35679 })), 35680 }))]) || [], 35681 }, {}); 35682 }; 35683 iframeManager.addLoadListener((iframeEl) => { 35684 try { 35685 handlers.push(observe(iframeEl.contentDocument)); 35686 } 35687 catch (error) { 35688 console.warn(error); 35689 } 35690 }); 35691 const init = () => { 35692 takeFullSnapshot(); 35693 handlers.push(observe(document)); 35694 }; 35695 if (document.readyState === 'interactive' || 35696 document.readyState === 'complete') { 35697 init(); 35698 } 35699 else { 35700 handlers.push(on('DOMContentLoaded', () => { 35701 wrappedEmit(wrapEvent({ 35702 type: EventType.DomContentLoaded, 35703 data: {}, 35704 })); 35705 if (recordAfter === 'DOMContentLoaded') 35706 init(); 35707 })); 35708 handlers.push(on('load', () => { 35709 wrappedEmit(wrapEvent({ 35710 type: EventType.Load, 35711 data: {}, 35712 })); 35713 if (recordAfter === 'load') 35714 init(); 35715 }, window)); 35716 } 35717 return () => { 35718 handlers.forEach((h) => h()); 35719 processedNodeManager.destroy(); 35720 _takeFullSnapshot = undefined; 35721 unregisterErrorHandler(); 35722 }; 35723 } 35724 catch (error) { 35725 console.warn(error); 35726 } 35727} 35728function takeFullSnapshot(isCheckout) { 35729 if (!_takeFullSnapshot) { 35730 throw new Error('please take full snapshot after start recording'); 35731 } 35732 _takeFullSnapshot(isCheckout); 35733} 35734record.mirror = mirror; 35735record.takeFullSnapshot = takeFullSnapshot; 35736function _getCanvasManager(getCanvasManagerFn, options) { 35737 try { 35738 return getCanvasManagerFn 35739 ? getCanvasManagerFn(options) 35740 : new CanvasManagerNoop(); 35741 } 35742 catch (e2) { 35743 console.warn('Unable to initialize CanvasManager'); 35744 return new CanvasManagerNoop(); 35745 } 35746} 35747 35748const ReplayEventTypeIncrementalSnapshot = 3; 35749const ReplayEventTypeCustom = 5; 35750 35751/** 35752 * Converts a timestamp to ms, if it was in s, or keeps it as ms. 35753 */ 35754function timestampToMs(timestamp) { 35755 const isMs = timestamp > 9999999999; 35756 return isMs ? timestamp : timestamp * 1000; 35757} 35758 35759/** 35760 * Converts a timestamp to s, if it was in ms, or keeps it as s. 35761 */ 35762function timestampToS(timestamp) { 35763 const isMs = timestamp > 9999999999; 35764 return isMs ? timestamp / 1000 : timestamp; 35765} 35766 35767/** 35768 * Add a breadcrumb event to replay. 35769 */ 35770function addBreadcrumbEvent(replay, breadcrumb) { 35771 if (breadcrumb.category === 'sentry.transaction') { 35772 return; 35773 } 35774 35775 if (['ui.click', 'ui.input'].includes(breadcrumb.category )) { 35776 replay.triggerUserActivity(); 35777 } else { 35778 replay.checkAndHandleExpiredSession(); 35779 } 35780 35781 replay.addUpdate(() => { 35782 // This should never reject 35783 // eslint-disable-next-line @typescript-eslint/no-floating-promises 35784 replay.throttledAddEvent({ 35785 type: EventType.Custom, 35786 // TODO: We were converting from ms to seconds for breadcrumbs, spans, 35787 // but maybe we should just keep them as milliseconds 35788 timestamp: (breadcrumb.timestamp || 0) * 1000, 35789 data: { 35790 tag: 'breadcrumb', 35791 // normalize to max. 10 depth and 1_000 properties per object 35792 payload: utils.normalize(breadcrumb, 10, 1000), 35793 }, 35794 }); 35795
35796 // Do not flush after console log messages 35797 return breadcrumb.category === 'console'; 35798 }); 35799} 35800 35801const INTERACTIVE_SELECTOR = 'button,a'; 35802 35803/** Get the closest interactive parent element, or else return the given element. */ 35804function getClosestInteractive(element) { 35805 const closestInteractive = element.closest(INTERACTIVE_SELECTOR); 35806 return closestInteractive || element; 35807} 35808 35809/** 35810 * For clicks, we check if the target is inside of a button or link 35811 * If so, we use this as the target instead 35812 * This is useful because if you click on the image in <button><img></button>, 35813 * The target will be the image, not the button, which we don't want here 35814 */ 35815function getClickTargetNode(event) { 35816 const target = getTargetNode(event); 35817 35818 if (!target || !(target instanceof Element)) { 35819 return target; 35820 } 35821 35822 return getClosestInteractive(target); 35823} 35824 35825/** Get the event target node. */ 35826function getTargetNode(event) { 35827 if (isEventWithTarget(event)) { 35828 return event.target ; 35829 } 35830 35831 return event; 35832} 35833 35834function isEventWithTarget(event) { 35835 return typeof event === 'object' && !!event && 'target' in event; 35836} 35837 35838let handlers; 35839 35840/** 35841 * Register a handler to be called when `window.open()` is called. 35842 * Returns a cleanup function. 35843 */ 35844function onWindowOpen(cb) { 35845 // Ensure to only register this once 35846 if (!handlers) { 35847 handlers = []; 35848 monkeyPatchWindowOpen(); 35849 } 35850 35851 handlers.push(cb); 35852 35853 return () => { 35854 const pos = handlers ? handlers.indexOf(cb) : -1; 35855 if (pos > -1) { 35856 (handlers ).splice(pos, 1); 35857 } 35858 }; 35859} 35860 35861function monkeyPatchWindowOpen() { 35862 utils.fill(WINDOW, 'open', function (originalWindowOpen) { 35863 return function (...args) { 35864 if (handlers) { 35865 try { 35866 handlers.forEach(handler => handler()); 35867 } catch (e) { 35868 // ignore errors in here 35869 } 35870 } 35871 35872 return originalWindowOpen.apply(WINDOW, args); 35873 }; 35874 }); 35875} 35876 35877/** Handle a click. */ 35878function handleClick(clickDetector, clickBreadcrumb, node) { 35879 clickDetector.handleClick(clickBreadcrumb, node); 35880} 35881 35882/** A click detector class that can be used to detect slow or rage clicks on elements. */ 35883class ClickDetector { 35884 // protected for testing 35885 35886 constructor( 35887 replay, 35888 slowClickConfig, 35889 // Just for easier testing 35890 _addBreadcrumbEvent = addBreadcrumbEvent, 35891 ) { 35892 this._lastMutation = 0; 35893 this._lastScroll = 0; 35894 this._clicks = []; 35895 35896 // We want everything in s, but options are in ms 35897 this._timeout = slowClickConfig.timeout / 1000; 35898 this._threshold = slowClickConfig.threshold / 1000; 35899 this._scollTimeout = slowClickConfig.scrollTimeout / 1000; 35900 this._replay = replay; 35901 this._ignoreSelector = slowClickConfig.ignoreSelector; 35902 this._addBreadcrumbEvent = _addBreadcrumbEvent; 35903 } 35904 35905 /** Register click detection handlers on mutation or scroll. */ 35906 addListeners() { 35907 const cleanupWindowOpen = onWindowOpen(() => { 35908 // Treat window.open as mutation 35909 this._lastMutation = nowInSeconds(); 35910 }); 35911 35912 this._teardown = () => { 35913 cleanupWindowOpen(); 35914 35915 this._clicks = []; 35916 this._lastMutation = 0; 35917 this._lastScroll = 0; 35918 }; 35919 } 35920 35921 /** Clean up listeners. */ 35922 removeListeners() { 35923 if (this._teardown) { 35924 this._teardown(); 35925 } 35926 35927 if (this._checkClickTimeout) { 35928 clearTimeout(this._checkClickTimeout); 35929 } 35930 } 35931 35932 /** @inheritDoc */ 35933 handleClick(breadcrumb, node) { 35934 if (ignoreElement(node, this._ignoreSelector) || !isClickBreadcrumb(breadcrumb)) { 35935 return; 35936 } 35937 35938 const newClick = { 35939 timestamp: timestampToS(breadcrumb.timestamp), 35940 clickBreadcrumb: breadcrumb, 35941 // Set this to 0 so we know it originates from the click breadcrumb 35942 clickCount: 0, 35943 node, 35944 }; 35945 35946 // If there was a click in the last 1s on the same element, ignore it - only keep a single reference per second 35947 if ( 35948 this._clicks.some(click => click.node === newClick.node && Math.abs(click.timestamp - newClick.timestamp) < 1) 35949 ) { 35950 return; 35951 } 35952 35953 this._clicks.push(newClick); 35954 35955 // If this is the first new click, set a timeout to check for multi clicks 35956 if (this._clicks.length === 1) { 35957 this._scheduleCheckClicks(); 35958 } 35959 } 35960 35961 /** @inheritDoc */ 35962 registerMutation(timestamp = Date.now()) { 35963 this._lastMutation = timestampToS(timestamp); 35964 } 35965 35966 /** @inheritDoc */ 35967 registerScroll(timestamp = Date.now()) { 35968 this._lastScroll = timestampToS(timestamp); 35969 } 35970 35971 /** @inheritDoc */ 35972 registerClick(element) { 35973 const node = getClosestInteractive(element); 35974 this._handleMultiClick(node ); 35975 } 35976 35977 /** Count multiple clicks on elements. */ 35978 _handleMultiClick(node) { 35979 this._getClicks(node).forEach(click => { 35980 click.clickCount++; 35981 }); 35982 } 35983 35984 /** Get all pending clicks for a given node. */ 35985 _getClicks(node) { 35986 return this._clicks.filter(click => click.node === node); 35987 } 35988 35989 /** Check the clicks that happened. */ 35990 _checkClicks() { 35991 const timedOutClicks = []; 35992 35993 const now = nowInSeconds(); 35994 35995 this._clicks.forEach(click => { 35996 if (!click.mutationAfter && this._lastMutation) { 35997 click.mutationAfter = click.timestamp <= this._lastMutation ? this._lastMutation - click.timestamp : undefined; 35998 } 35999 if (!click.scrollAfter && this._lastScroll) { 36000 click.scrollAfter = click.timestamp <= this._lastScroll ? this._lastScroll - click.timestamp : undefined; 36001 } 36002 36003 // All of these are in seconds! 36004 if (click.timestamp + this._timeout <= now) { 36005 timedOutClicks.push(click); 36006 } 36007 }); 36008 36009 // Remove "old" clicks 36010 for (const click of timedOutClicks) { 36011 const pos = this._clicks.indexOf(click); 36012 36013 if (pos > -1) { 36014 this._generateBreadcrumbs(click); 36015 this._clicks.splice(pos, 1); 36016 } 36017 } 36018 36019 // Trigger new check, unless no clicks left 36020 if (this._clicks.length) { 36021 this._scheduleCheckClicks(); 36022 } 36023 } 36024 36025 /** Generate matching breadcrumb(s) for the click. */ 36026 _generateBreadcrumbs(click) { 36027 const replay = this._replay; 36028 const hadScroll = click.scrollAfter && click.scrollAfter <= this._scollTimeout; 36029 const hadMutation = click.mutationAfter && click.mutationAfter <= this._threshold; 36030 36031 const isSlowClick = !hadScroll && !hadMutation; 36032 const { clickCount, clickBreadcrumb }
36032 = click; 36033 36034 // Slow click 36035 if (isSlowClick) { 36036 // If `mutationAfter` is set, it means a mutation happened after the threshold, but before the timeout 36037 // If not, it means we just timed out without scroll & mutation 36038 const timeAfterClickMs = Math.min(click.mutationAfter || this._timeout, this._timeout) * 1000; 36039 const endReason = timeAfterClickMs < this._timeout * 1000 ? 'mutation' : 'timeout'; 36040 36041 const breadcrumb = { 36042 type: 'default', 36043 message: clickBreadcrumb.message, 36044 timestamp: clickBreadcrumb.timestamp, 36045 category: 'ui.slowClickDetected', 36046 data: { 36047 ...clickBreadcrumb.data, 36048 url: WINDOW.location.href, 36049 route: replay.getCurrentRoute(), 36050 timeAfterClickMs, 36051 endReason, 36052 // If clickCount === 0, it means multiClick was not correctly captured here 36053 // - we still want to send 1 in this case 36054 clickCount: clickCount || 1, 36055 }, 36056 }; 36057 36058 this._addBreadcrumbEvent(replay, breadcrumb); 36059 return; 36060 } 36061 36062 // Multi click 36063 if (clickCount > 1) { 36064 const breadcrumb = { 36065 type: 'default', 36066 message: clickBreadcrumb.message, 36067 timestamp: clickBreadcrumb.timestamp, 36068 category: 'ui.multiClick', 36069 data: { 36070 ...clickBreadcrumb.data, 36071 url: WINDOW.location.href, 36072 route: replay.getCurrentRoute(), 36073 clickCount, 36074 metric: true, 36075 }, 36076 }; 36077 36078 this._addBreadcrumbEvent(replay, breadcrumb); 36079 } 36080 } 36081 36082 /** Schedule to check current clicks. */ 36083 _scheduleCheckClicks() { 36084 if (this._checkClickTimeout) { 36085 clearTimeout(this._checkClickTimeout); 36086 } 36087 36088 this._checkClickTimeout = setTimeout(() => this._checkClicks(), 1000); 36089 } 36090} 36091 36092const SLOW_CLICK_TAGS = ['A', 'BUTTON', 'INPUT']; 36093 36094/** exported for tests only */ 36095function ignoreElement(node, ignoreSelector) { 36096 if (!SLOW_CLICK_TAGS.includes(node.tagName)) { 36097 return true; 36098 } 36099 36100 // If <input> tag, we only want to consider input[type='submit'] & input[type='button'] 36101 if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) { 36102 return true; 36103 } 36104 36105 // If <a> tag, detect special variants that may not lead to an action 36106 // If target !== _self, we may open the link somewhere else, which would lead to no action 36107 // Also, when downloading a file, we may not leave the page, but still not trigger an action 36108 if ( 36109 node.tagName === 'A' && 36110 (node.hasAttribute('download') || (node.hasAttribute('target') && node.getAttribute('target') !== '_self')) 36111 ) { 36112 return true; 36113 } 36114 36115 if (ignoreSelector && node.matches(ignoreSelector)) { 36116 return true; 36117 } 36118 36119 return false; 36120} 36121 36122function isClickBreadcrumb(breadcrumb) { 36123 return !!(breadcrumb.data && typeof breadcrumb.data.nodeId === 'number' && breadcrumb.timestamp); 36124} 36125 36126// This is good enough for us, and is easier to test/mock than `timestampInSeconds` 36127function nowInSeconds() { 36128 return Date.now() / 1000; 36129} 36130 36131/** Update the click detector based on a recording event of rrweb. */ 36132function updateClickDetectorForRecordingEvent(clickDetector, event) { 36133 try { 36134 // note: We only consider incremental snapshots here 36135 // This means that any full snapshot is ignored for mutation detection - the reason is that we simply cannot know if a mutation happened here. 36136 // E.g. think that we are buffering, an error happens and we take a full snapshot because we switched to session mode - 36137 // in this scenario, we would not know if a dead click happened because of the error, which is a key dead click scenario. 36138 // Instead, by ignoring full snapshots, we have the risk that we generate a false positive 36139 // (if a mutation _did_ happen but was "swallowed" by the full snapshot) 36140 // But this should be more unlikely as we'd generally capture the incremental snapshot right away 36141 36142 if (!isIncrementalEvent(event)) { 36143 return; 36144 } 36145 36146 const { source } = event.data; 36147 if (source === IncrementalSource.Mutation) { 36148 clickDetector.registerMutation(event.timestamp); 36149 } 36150 36151 if (source === IncrementalSource.Scroll) { 36152 clickDetector.registerScroll(event.timestamp); 36153 } 36154 36155 if (isIncrementalMouseInteraction(event)) { 36156 const { type, id } = event.data; 36157 const node = record.mirror.getNode(id); 36158 36159 if (node instanceof HTMLElement && type === MouseInteractions.Click) { 36160 clickDetector.registerClick(node); 36161 } 36162 } 36163 } catch (e) { 36164 // ignore errors here, e.g. if accessing something that does not exist 36165 } 36166} 36167 36168function isIncrementalEvent(event) { 36169 return event.type === ReplayEventTypeIncrementalSnapshot; 36170} 36171 36172function isIncrementalMouseInteraction( 36173 event, 36174) { 36175 return event.data.source === IncrementalSource.MouseInteraction; 36176} 36177 36178/** 36179 * Create a breadcrumb for a replay. 36180 */ 36181function createBreadcrumb( 36182 breadcrumb, 36183) { 36184 return { 36185 timestamp: Date.now() / 1000, 36186 type: 'default', 36187 ...breadcrumb, 36188 }; 36189} 36190 36191var NodeType; 36192(function (NodeType) { 36193 NodeType[NodeType["Document"] = 0] = "Document"; 36194 NodeType[NodeType["DocumentType"] = 1] = "DocumentType"; 36195 NodeType[NodeType["Element"] = 2] = "Element"; 36196 NodeType[NodeType["Text"] = 3] = "Text"; 36197 NodeType[NodeType["CDATA"] = 4] = "CDATA"; 36198 NodeType[NodeType["Comment"] = 5] = "Comment"; 36199})(NodeType || (NodeType = {})); 36200 36201// Note that these are the serialized attributes and not attributes directly on 36202// the DOM Node. Attributes we are interested in: 36203const ATTRIBUTES_TO_RECORD = new Set([ 36204 'id', 36205 'class', 36206 'aria-label', 36207 'role', 36208 'name', 36209 'alt', 36210 'title', 36211 'data-test-id', 36212 'data-testid', 36213 'disabled', 36214 'aria-disabled', 36215 'data-sentry-component', 36216]); 36217 36218/**
36219 * Inclusion list of attributes that we want to record from the DOM element 36220 */ 36221function getAttributesToRecord(attributes) { 36222 const obj = {}; 36223 for (const key in attributes) { 36224 if (ATTRIBUTES_TO_RECORD.has(key)) { 36225 let normalizedKey = key; 36226 36227 if (key === 'data-testid' || key === 'data-test-id') { 36228 normalizedKey = 'testId'; 36229 } 36230 36231 obj[normalizedKey] = attributes[key]; 36232 } 36233 } 36234 36235 return obj; 36236} 36237 36238const handleDomListener = ( 36239 replay, 36240) => { 36241 return (handlerData) => { 36242 if (!replay.isEnabled()) { 36243 return; 36244 } 36245 36246 const result = handleDom(handlerData); 36247 36248 if (!result) { 36249 return; 36250 } 36251 36252 const isClick = handlerData.name === 'click'; 36253 const event = isClick ? (handlerData.event ) : undefined; 36254 // Ignore clicks if ctrl/alt/meta/shift keys are held down as they alter behavior of clicks (e.g. open in new tab) 36255 if ( 36256 isClick && 36257 replay.clickDetector && 36258 event && 36259 event.target && 36260 !event.altKey && 36261 !event.metaKey && 36262 !event.ctrlKey && 36263 !event.shiftKey 36264 ) { 36265 handleClick( 36266 replay.clickDetector, 36267 result , 36268 getClickTargetNode(handlerData.event ) , 36269 ); 36270 } 36271 36272 addBreadcrumbEvent(replay, result); 36273 }; 36274}; 36275 36276/** Get the base DOM breadcrumb. */ 36277function getBaseDomBreadcrumb(target, message) { 36278 const nodeId = record.mirror.getId(target); 36279 const node = nodeId && record.mirror.getNode(nodeId); 36280 const meta = node && record.mirror.getMeta(node); 36281 const element = meta && isElement(meta) ? meta : null; 36282 36283 return { 36284 message, 36285 data: element 36286 ? { 36287 nodeId, 36288 node: { 36289 id: nodeId, 36290 tagName: element.tagName, 36291 textContent: Array.from(element.childNodes) 36292 .map((node) => node.type === NodeType.Text && node.textContent) 36293 .filter(Boolean) // filter out empty values 36294 .map(text => (text ).trim()) 36295 .join(''), 36296 attributes: getAttributesToRecord(element.attributes), 36297 }, 36298 } 36299 : {}, 36300 }; 36301} 36302 36303/** 36304 * An event handler to react to DOM events. 36305 * Exported for tests. 36306 */ 36307function handleDom(handlerData) { 36308 const { target, message } = getDomTarget(handlerData); 36309 36310 return createBreadcrumb({ 36311 category: `ui.${handlerData.name}`, 36312 ...getBaseDomBreadcrumb(target, message), 36313 }); 36314} 36315 36316function getDomTarget(handlerData) { 36317 const isClick = handlerData.name === 'click'; 36318 36319 let message; 36320 let target = null; 36321 36322 // Accessing event.target can throw (see getsentry/raven-js#838, #768) 36323 try { 36324 target = isClick ? getClickTargetNode(handlerData.event ) : getTargetNode(handlerData.event ); 36325 message = utils.htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>'; 36326 } catch (e) { 36327 message = '<unknown>'; 36328 } 36329 36330 return { target, message }; 36331} 36332 36333function isElement(node) { 36334 return node.type === NodeType.Element; 36335} 36336 36337/** Handle keyboard events & create breadcrumbs. */ 36338function handleKeyboardEvent(replay, event) { 36339 if (!replay.isEnabled()) { 36340 return; 36341 } 36342 36343 // Update user activity, but do not restart recording as it can create 36344 // noisy/low-value replays (e.g. user comes back from idle, hits alt-tab, new 36345 // session with a single "keydown" breadcrumb is created) 36346 replay.updateUserActivity(); 36347 36348 const breadcrumb = getKeyboardBreadcrumb(event); 36349 36350 if (!breadcrumb) { 36351 return; 36352 } 36353 36354 addBreadcrumbEvent(replay, breadcrumb); 36355} 36356 36357/** exported only for tests */ 36358function getKeyboardBreadcrumb(event) { 36359 const { metaKey, shiftKey, ctrlKey, altKey, key, target } = event; 36360 36361 // never capture for input fields 36362 if (!target || isInputElement(target ) || !key) { 36363 return null; 36364 } 36365 36366 // Note: We do not consider shift here, as that means "uppercase" 36367 const hasModifierKey = metaKey || ctrlKey || altKey; 36368 const isCharacterKey = key.length === 1; // other keys like Escape, Tab, etc have a longer length 36369 36370 // Do not capture breadcrumb if only a word key is pressed 36371 // This could leak e.g. user input 36372 if (!hasModifierKey && isCharacterKey) { 36373 return null; 36374 } 36375 36376 const message = utils.htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>'; 36377 const baseBreadcrumb = getBaseDomBreadcrumb(target , message); 36378 36379 return createBreadcrumb({ 36380 category: 'ui.keyDown', 36381 message, 36382 data: { 36383 ...baseBreadcrumb.data, 36384 metaKey,
36385 shiftKey, 36386 ctrlKey, 36387 altKey, 36388 key, 36389 }, 36390 }); 36391} 36392 36393function isInputElement(target) { 36394 return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable; 36395} 36396 36397// Map entryType -> function to normalize data for event 36398const ENTRY_TYPES 36399 36400 = { 36401 // @ts-expect-error TODO: entry type does not fit the create* functions entry type 36402 resource: createResourceEntry, 36403 paint: createPaintEntry, 36404 // @ts-expect-error TODO: entry type does not fit the create* functions entry type 36405 navigation: createNavigationEntry, 36406}; 36407 36408/** 36409 * Create replay performance entries from the browser performance entries. 36410 */ 36411function createPerformanceEntries( 36412 entries, 36413) { 36414 return entries.map(createPerformanceEntry).filter(Boolean) ; 36415} 36416 36417function createPerformanceEntry(entry) { 36418 if (!ENTRY_TYPES[entry.entryType]) { 36419 return null; 36420 } 36421 36422 return ENTRY_TYPES[entry.entryType](entry); 36423} 36424 36425function getAbsoluteTime(time) { 36426 // browserPerformanceTimeOrigin can be undefined if `performance` or 36427 // `performance.now` doesn't exist, but this is already checked by this integration 36428 return ((utils.browserPerformanceTimeOrigin || WINDOW.performance.timeOrigin) + time) / 1000; 36429} 36430 36431function createPaintEntry(entry) { 36432 const { duration, entryType, name, startTime } = entry; 36433 36434 const start = getAbsoluteTime(startTime); 36435 return { 36436 type: entryType, 36437 name, 36438 start, 36439 end: start + duration, 36440 data: undefined, 36441 }; 36442} 36443 36444function createNavigationEntry(entry) { 36445 const { 36446 entryType, 36447 name, 36448 decodedBodySize, 36449 duration, 36450 domComplete, 36451 encodedBodySize, 36452 domContentLoadedEventStart, 36453 domContentLoadedEventEnd, 36454 domInteractive, 36455 loadEventStart, 36456 loadEventEnd, 36457 redirectCount, 36458 startTime, 36459 transferSize, 36460 type, 36461 } = entry; 36462
36463 // Ignore entries with no duration, they do not seem to be useful and cause dupes 36464 if (duration === 0) { 36465 return null; 36466 } 36467 36468 return { 36469 type: `${entryType}.${type}`, 36470 start: getAbsoluteTime(startTime), 36471 end: getAbsoluteTime(domComplete), 36472 name, 36473 data: { 36474 size: transferSize, 36475 decodedBodySize, 36476 encodedBodySize, 36477 duration, 36478 domInteractive, 36479 domContentLoadedEventStart, 36480 domContentLoadedEventEnd, 36481 loadEventStart, 36482 loadEventEnd, 36483 domComplete, 36484 redirectCount, 36485 }, 36486 }; 36487} 36488 36489function createResourceEntry( 36490 entry, 36491) { 36492 const { 36493 entryType, 36494 initiatorType, 36495 name, 36496 responseEnd, 36497 startTime, 36498 decodedBodySize, 36499 encodedBodySize, 36500 responseStatus, 36501 transferSize, 36502 } = entry; 36503 36504 // Core SDK handles these 36505 if (['fetch', 'xmlhttprequest'].includes(initiatorType)) { 36506 return null; 36507 } 36508 36509 return { 36510 type: `${entryType}.${initiatorType}`, 36511 start: getAbsoluteTime(startTime), 36512 end: getAbsoluteTime(responseEnd), 36513 name, 36514 data: { 36515 size: transferSize, 36516 statusCode: responseStatus, 36517 decodedBodySize, 36518 encodedBodySize, 36519 }, 36520 }; 36521} 36522 36523/** 36524 * Add a LCP event to the replay based on an LCP metric. 36525 */ 36526function getLargestContentfulPaint(metric 36527 36528) { 36529 const entries = metric.entries; 36530 const lastEntry = entries[entries.length - 1] ; 36531 const element = lastEntry ? lastEntry.element : undefined; 36532 36533 const value = metric.value; 36534 36535 const end = getAbsoluteTime(value); 36536 36537 const data = { 36538 type: 'largest-contentful-paint', 36539 name: 'largest-contentful-paint', 36540 start: end, 36541 end, 36542 data: { 36543 value, 36544 size: value, 36545 nodeId: element ? record.mirror.getId(element) : undefined, 36546 }, 36547 }; 36548 36549 return data; 36550} 36551 36552/** 36553 * Sets up a PerformanceObserver to listen to all performance entry types. 36554 * Returns a callback to stop observing. 36555 */ 36556function setupPerformanceObserver(replay) { 36557 function addPerformanceEntry(entry) { 36558 // It is possible for entries to come up multiple times 36559 if (!replay.performanceEntries.includes(entry)) { 36560 replay.performanceEntries.push(entry); 36561 } 36562 } 36563 36564 function onEntries({ entries }) { 36565 entries.forEach(addPerformanceEntry); 36566 } 36567 36568 const clearCallbacks = []; 36569 36570 (['navigation', 'paint', 'resource'] ).forEach(type => { 36571 clearCallbacks.push(tracing.addPerformanceInstrumentationHandler(type, onEntries)); 36572 }); 36573 36574 clearCallbacks.push( 36575 tracing.addLcpInstrumentationHandler(({ metric }) => { 36576 replay.replayPerformanceEntries.push(getLargestContentfulPaint(metric)); 36577 }), 36578 ); 36579 36580 // A callback to cleanup all handlers 36581 return () => { 36582 clearCallbacks.forEach(clearCallback => clearCallback()); 36583 }; 36584} 36585 36586/** 36587 * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code. 36588 * 36589 * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking. 36590 */ 36591const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__); 36592 36593const r = `var t=Uint8Array,n=Uint16Array,r=Int32Array,e=new t([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),i=new t([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),a=new t([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),s=function(t,e){for(var i=new n(31),a=0;a<31;++a)i[a]=e+=1<<t[a-1];var s=new r(i[30]);for(a=1;a<30;++a)for(var o=i[a];o<i[a+1];++o)s[o]=o-i[a]<<5|a;return{b:i,r:s}},o=s(e,2),f=o.b,h=o.r;f[28]=258,h[258]=28;for(var l=s(i,0).r,u=new n(32768),c=0;c<32768;++c){var v=(43690&c)>>1|(21845&c)<<1;v=(61680&(v=(52428&v)>>2|(13107&v)<<2))>>4|(3855&v)<<4,u[c]=((65280&v)>>8|(255&v)<<8)>>1}var d=function(t,r,e){for(var i=t.length,a=0,s=new n(r);a<i;++a)t[a]&&++s[t[a]-1];var o,f=new n(r);for(a=1;a<r;++a)f[a]=f[a-1]+s[a-1]<<1;if(e){o=new n(1<<r);var h=15-r;for(a=0;a<i;++a)if(t[a])for(var l=a<<4|t[a],c=r-t[a],v=f[t[a]-1]++<<c,d=v|(1<<c)-1;v<=d;++v)o[u[v]>>h]=l}else for(o=new n(i),a=0;a<i;++a)t[a]&&(o[a]=u[f[t[a]-1]++]>>15-t[a]);return o},g=new t(288);for(c=0;c<144;++c)g[c]=8;for(c=144;c<256;++c)g[c]=9;for(c=256;c<280;++c)g[c]=7;for(c=280;c<288;++c)g[c]=8;var w=new t(32);for(c=0;c<32;++c)w[c]=5;var p=d(g,9,0),y=d(w,5,0),m=function(t){return(t+7)/8|0},b=function(n,r,e){return(null==r||r<0)&&(r=0),(null==e||e>n.length)&&(e=n.length),new t(n.subarray(r,e))}
vendor: 4,465 bytes, line 36593
36593,M=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],E=function(t,n,r){var e=new Error(n||M[t]);if(e.code=t,Error.captureStackTrace&&Error.captureStackTrace(e,E),!r)throw e;return e},z=function(t,n,r){r<<=7&n;var e=n/8|0;t[e]|=r,t[e+1]|=r>>8},A=function(t,n,r){r<<=7&n;var e=n/8|0;t[e]|=r,t[e+1]|=r>>8,t[e+2]|=r>>16},_=function(r,e){for(var i=[],a=0;a<r.length;++a)r[a]&&i.push({s:a,f:r[a]});var s=i.length,o=i.slice();if(!s)return{t:F,l:0};if(1==s){var f=new t(i[0].s+1);return f[i[0].s]=1,{t:f,l:1}}i.sort((function(t,n){return t.f-n.f})),i.push({s:-1,f:25001});var h=i[0],l=i[1],u=0,c=1,v=2;for(i[0]={s:-1,f:h.f+l.f,l:h,r:l};c!=s-1;)h=i[i[u].f<i[v].f?u++:v++],l=i[u!=c&&i[u].f<i[v].f?u++:v++],i[c++]={s:-1,f:h.f+l.f,l:h,r:l};var d=o[0].s;for(a=1;a<s;++a)o[a].s>d&&(d=o[a].s);var g=new n(d+1),w=x(i[c-1],g,0);if(w>e){a=0;var p=0,y=w-e,m=1<<y;for(o.sort((function(t,n){return g[n.s]-g[t.s]||t.f-n.f}));a<s;++a){var b=o[a].s;if(!(g[b]>e))break;p+=m-(1<<w-g[b]),g[b]=e}for(p>>=y;p>0;){var M=o[a].s;g[M]<e?p-=1<<e-g[M]++-1:++a}for(;a>=0&&p;--a){var E=o[a].s;g[E]==e&&(--g[E],++p)}w=e}return{t:new t(g),l:w}},x=function(t,n,r){return-1==t.s?Math.max(x(t.l,n,r+1),x(t.r,n,r+1)):n[t.s]=r},D=function(t){for(var r=t.length;r&&!t[--r];);for(var e=new n(++r),i=0,a=t[0],s=1,o=function(t){e[i++]=t},f=1;f<=r;++f)if(t[f]==a&&f!=r)++s;else{if(!a&&s>2){for(;s>138;s-=138)o(32754);s>2&&(o(s>10?s-11<<5|28690:s-3<<5|12305),s=0)}else if(s>3){for(o(a),--s;s>6;s-=6)o(8304);s>2&&(o(s-3<<5|8208),s=0)}for(;s--;)o(a);s=1,a=t[f]}return{c:e.subarray(0,i),n:r}},T=function(t,n){for(var r=0,e=0;e<n.length;++e)r+=t[e]*n[e];return r},k=function(t,n,r){var e=r.length,i=m(n+2);t[i]=255&e,t[i+1]=e>>8,t[i+2]=255^t[i],t[i+3]=255^t[i+1];for(var a=0;a<e;++a)t[i+a+4]=r[a];return 8*(i+4+e)},C=function(t,r,s,o,f,h,l,u,c,v,m){z(r,m++,s),++f[256];for(var b=_(f,15),M=b.t,E=b.l,x=_(h,15),C=x.t,U=x.l,F=D(M),I=F.c,S=F.n,L=D(C),O=L.c,j=L.n,q=new n(19),B=0;B<I.length;++B)++q[31&I[B]];for(B=0;B<O.length;++B)++q[31&O[B]];for(var G=_(q,7),H=G.t,J=G.l,K=19;K>4&&!H[a[K-1]];--K);var N,P,Q,R,V=v+5<<3,W=T(f,g)+T(h,w)+l,X=T(f,M)+T(h,C)+l+14+3*K+T(q,H)+2*q[16]+3*q[17]+7*q[18];if(c>=0&&V<=W&&V<=X)return k(r,m,t.subarray(c,c+v));if(z(r,m,1+(X<W)),m+=2,X<W){N=d(M,E,0),P=M,Q=d(C,U,0),R=C;var Y=d(H,J,0);z(r,m,S-257),z(r,m+5,j-1),z(r,m+10,K-4),m+=14;for(B=0;B<K;++B)z(r,m+3*B,H[a[B]]);m+=3*K;for(var Z=[I,O],$=0;$<2;++$){var tt=Z[$];for(B=0;B<tt.length;++B){var nt=31&tt[B];z(r,m,Y[nt]),m+=H[nt],nt>15&&(z(r,m,tt[B]>>5&127),m+=tt[B]>>12)}}}else N=p,P=g,Q=y,R=w;for(B=0;B<u;++B){var rt=o[B];if(rt>255){A(r,m,N[(nt=rt>>18&31)+257]),m+=P[nt+257],nt>7&&(z(r,m,rt>>23&31),m+=e[nt]);var et=31&rt;A(r,m,Q[et]),m+=R[et],et>3&&(A(r,m,rt>>5&8191),m+=i[et])}else A(r,m,N[rt]),m+=P[rt]}return A(r,m,N[256]),m+P[256]},U=new r([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),F=new t(0),I=function(){for(var t=new Int32Array(256),n=0;n<256;++n){for(var r=n,e=9;--e;)r=(1&r&&-306674912)^r>>>1;t[n]=r}return t}(),S=function(){var t=1,n=0;return{p:function(r){for(var e=t,i=n,a=0|r.length,s=0;s!=a;){for(var o=Math.min(s+2655,a);s<o;++s)i+=e+=r[s];e=(65535&e)+15*(e>>16),i=(65535&i)+15*(i>>16)}t=e,n=i},d:function(){return(255&(t%=65521))<<24|(65280&t)<<8|(255&(n%=65521))<<8|n>>8}}},L=function(a,s,o,f,u){if(!u&&(u={l:1},s.dictionary)){var c=s.dictionary.subarray(-32768),v=new t(c.length+a.length);v.set(c),v.set(a,c.length),a=v,u.w=c.length}return function(a,s,o,f,u,c){var v=c.z||a.length,d=new t(f+v+5*(1+Math.ceil(v/7e3))+u),g=d.subarray(f,d.length-u),w=c.l,p=7&(c.r||0);if(s){p&&(g[0]=c.r>>3);for(var y=U[s-1],M=y>>13,E=8191&y,z=(1<<o)-1,A=c.p||new n(32768),_=c.h||new n(z+1),x=Math.ceil(o/3),D=2*x,T=function(t){return(a[t]^a[t+1]<<x^a[t+2]<<D)&z},F=new r(25e3),I=new n(288),S=new n(32),L=0,O=0,j=c.i||0,q=0,B=c.w||0,G=0;j+2<v;++j){var H=T(j),J=32767&j,K=_[H];if(A[J]=K,_[H]=J,B<=j){var N=v-j;if((L>7e3||q>24576)&&(N>423||!w)){p=C(a,g,0,F,I,S,O,q,G,j-G,p),q=L=O=0,G=j;for(var P=0;P<286;++P)I[P]=0;for(P=0;P<30;++P)S[P]=0}var Q=2,R=0,V=E,W=J-K&32767;if(N>2&&H==T(j-W))for(var X=Math.min(M,N)-1,Y=Math.min(32767,j),Z=Math.min(258,N);W<=Y&&--V&&J!=K;){if(a[j+Q]==a[j+Q-W]){for(var $=0;$<Z&&a[j+$]==a[j+$-W];++$);if($>Q){if(Q=$,R=W,$>X)break;var tt=Math.min(W,$-2),nt=0;for(P=0;P<tt;
36593++P){var rt=j-W+P&32767,et=rt-A[rt]&32767;et>nt&&(nt=et,K=rt)}}}W+=(J=K)-(K=A[J])&32767}if(R){F[q++]=268435456|h[Q]<<18|l[R];var it=31&h[Q],at=31&l[R];O+=e[it]+i[at],++I[257+it],++S[at],B=j+Q,++L}else F[q++]=a[j],++I[a[j]]}}for(j=Math.max(j,B);j<v;++j)F[q++]=a[j],++I[a[j]];p=C(a,g,w,F,I,S,O,q,G,j-G,p),w||(c.r=7&p|g[p/8|0]<<3,p-=7,c.h=_,c.p=A,c.i=j,c.w=B)}else{for(j=c.w||0;j<v+w;j+=65535){var st=j+65535;st>=v&&(g[p/8|0]=w,st=v),p=k(g,p+1,a.subarray(j,st))}c.i=v}return b(d,0,f+m(p)+u)}(a,null==s.level?6:s.level,null==s.mem?Math.ceil(1.5*Math.max(8,Math.min(13,Math.log(a.length)))):12+s.mem,o,f,u)},O=function(t,n,r){for(;r;++n)t[n]=r,r>>>=8},j=function(){function n(n,r){if("function"==typeof n&&(r=n,n={}),this.ondata=r,this.o=n||{},this.s={l:0,i:32768,w:32768,z:32768},this.b=new t(98304),this.o.dictionary){var e=this.o.dictionary.subarray(-32768);this.b.set(e,32768-e.length),this.s.i=32768-e.length}}return n.prototype.p=function(t,n){this.ondata(L(t,this.o,0,0,this.s),n)},n.prototype.push=function(n,r){this.ondata||E(5),this.s.l&&E(4);var e=n.length+this.s.z;if(e>this.b.length){if(e>2*this.b.length-32768){var i=new t(-32768&e);i.set(this.b.subarray(0,this.s.z)),this.b=i}var a=this.b.length-this.s.z;a&&(this.b.set(n.subarray(0,a),this.s.z),this.s.z=this.b.length,this.p(this.b,!1)),this.b.set(this.b.subarray(-32768)),this.b.set(n.subarray(a),32768),this.s.z=n.length-a+32768,this.s.i=32766,this.s.w=32768}else this.b.set(n,this.s.z),this.s.z+=n.length;this.s.l=1&r,(this.s.z>this.s.w+8191||r)&&(this.p(this.b,r||!1),this.s.w=this.s.i,this.s.i-=2)},n}();function q(t,n){n||(n={});var r=function(){var t=-1;return{p:function(n){for(var r=t,e=0;e<n.length;++e)r=I[255&r^n[e]]^r>>>8;t=r},d:function(){return~t}}}(),e=t.length;r.p(t);var i,a=L(t,n,10+((i=n).filename?i.filename.length+1:0),8),s=a.length;return function(t,n){var r=n.filename;if(t[0]=31,t[1]=139,t[2]=8,t[8]=n.level<2?4:9==n.level?2:0,t[9]=3,0!=n.mtime&&O(t,4,Math.floor(new Date(n.mtime||Date.now())/1e3)),r){t[3]=8;for(var e=0;e<=r.length;++e)t[e+10]=r.charCodeAt(e)}}(a,n),O(a,s-8,r.d()),O(a,s-4,e),a}var B=function(){function t(t,n){this.c=S(),this.v=1,j.call(this,t,n)}return t.prototype.push=function(t,n){this.c.p(t),j.prototype.push.call(this,t,n)},t.prototype.p=function(t,n){var r=L(t,this.o,this.v&&(this.o.dictionary?6:2),n&&4,this.s);this.v&&(function(t,n){var r=n.level,e=0==r?0:r<6?1:9==r?3:2;if(t[0]=120,t[1]=e<<6|(n.dictionary&&32),t[1]|=31-(t[0]<<8|t[1])%31,n.dictionary){var i=S();i.p(n.dictionary),O(t,2,i.d())}}(r,this.o),this.v=0),n&&O(r,r.length-4,this.c.d()),this.ondata(r,n)},t}(),G="undefined"!=typeof TextEncoder&&new TextEncoder,H="undefined"!=typeof TextDecoder&&new TextDecoder;try{H.decode(F,{stream:!0})}catch(t){}var J=function(){function t(t){this.ondata=t}return t.prototype.push=function(t,n){this.ondata||E(5),this.d&&E(4),this.ondata(K(t),this.d=n||!1)},t}();function K(n,r){if(r){for(var e=new t(n.length),i=0;i<n.length;++i)e[i]=n.charCodeAt(i);return e}if(G)return G.encode(n);var a=n.length,s=new t(n.length+(n.length>>1)),o=0,f=function(t){s[o++]=t};for(i=0;i<a;++i){if(o+5>s.length){var h=new t(o+8+(a-i<<1));h.set(s),s=h}var l=n.charCodeAt(i);l<128||r?f(l):l<2048?(f(192|l>>6),f(128|63&l)):l>55295&&l<57344?(f(240|(l=65536+(1047552&l)|1023&n.charCodeAt(++i))>>18),f(128|l>>12&63),f(128|l>>6&63),f(128|63&l)):(f(224|l>>12),f(128|l>>6&63),f(128|63&l))}return b(s,0,o)}const N=new class{constructor(){this._init()}clear(){this._init()}addEvent(t){if(!t)throw new Error("Adding invalid event");const n=this._hasEvents?",":"";this.stream.push(n+t),this._hasEvents=!0}finish(){this.stream.push("]",!0);const t=function(t){let n=0;for(let r=0,e=t.length;r<e;r++)n+=t[r].length;const r=new Uint8Array(n);for(let n=0,e=0,i=t.length;n<i;n++){const i=t[n];r.set(i,e),e+=i.length}return r}(this._deflatedData);return this._init(),t}_init(){this._hasEvents=!1,this._deflatedData=[],this.deflate=new B,this.deflate.ondata=(t,n)=>{this._deflatedData.push(t)},this.stream=new J(((t,n)=>{this.deflate.push(t,n)})),this.stream.push("[")}},P={clear:()=>{N.clear()},addEvent:t=>N.addEvent(t),finish:()=>N.finish(),compress:t=>function(t){return q(K(t))}(t)};addEventListener("message",(function(t){const n=t.data.method,r=t.data.id,e=t.data.arg;if(n in P&&"function"==typeof P[n])try{const t=P[n](e);postMessage({id:r,method:n,success:!0,response:t})}catch(t){postMessage({id:r,method:n,success:!1,response:t.message}),console.error(t)}})),postMessage({id:void 0,method:"init",success:!0,response:void 0});`; 36594 36595function e(){const e=new Blob([r]);return URL.createObjectURL(e)} 36596 36597/** 36598 * Log a message in debug mode, and add a breadcrumb when _experiment.traceInternals is enabled. 36599 */ 36600function logInfo(message, shouldAddBreadcrumb) { 36601 if (!DEBUG_BUILD) { 36602 return; 36603 } 36604 36605 utils.logger.info(message); 36606 36607 if (shouldAddBreadcrumb) { 36608 addLogBreadcrumb(message); 36609 } 36610} 36611 36612/** 36613 * Log a message, and add a breadcrumb in the next tick. 36614 * This is necessary when the breadcrumb may be added before the replay is initialized. 36615 */ 36616function logInfoNextTick(message, shouldAddBreadcrumb) { 36617 if (!DEBUG_BUILD) { 36618 return; 36619 } 36620 36621 utils.logger.info(message); 36622 36623 if (shouldAddBreadcrumb) { 36624 // Wait a tick here to avoid race conditions for some initial logs 36625 // which may be added before replay is initialized 36626 setTimeout(() => { 36627 addLogBreadcrumb(message); 36628 }, 0); 36629 } 36630} 36631 36632function addLogBreadcrumb(message) { 36633 core.addBreadcrumb( 36634 { 36635 category: 'console', 36636 data: { 36637 logger: 'replay', 36638 }, 36639 level: 'info', 36640 message, 36641 }, 36642 { level: 'info' }, 36643 ); 36644} 36645 36646/** This error indicates that the event buffer size exceeded the limit.. */
36647class EventBufferSizeExceededError extends Error { 36648 constructor() { 36649 super(`Event buffer exceeded maximum size of ${REPLAY_MAX_EVENT_BUFFER_SIZE}.`); 36650 } 36651} 36652 36653/** 36654 * A basic event buffer that does not do any compression. 36655 * Used as fallback if the compression worker cannot be loaded or is disabled. 36656 */ 36657class EventBufferArray { 36658 /** All the events that are buffered to be sent. */ 36659 36660 /** @inheritdoc */ 36661 36662 constructor() { 36663 this.events = []; 36664 this._totalSize = 0; 36665 this.hasCheckout = false; 36666 } 36667 36668 /** @inheritdoc */ 36669 get hasEvents() { 36670 return this.events.length > 0; 36671 } 36672 36673 /** @inheritdoc */ 36674 get type() { 36675 return 'sync'; 36676 } 36677 36678 /** @inheritdoc */ 36679 destroy() { 36680 this.events = []; 36681 } 36682 36683 /** @inheritdoc */ 36684 async addEvent(event) { 36685 const eventSize = JSON.stringify(event).length; 36686 this._totalSize += eventSize; 36687 if (this._totalSize > REPLAY_MAX_EVENT_BUFFER_SIZE) { 36688 throw new EventBufferSizeExceededError(); 36689 } 36690 36691 this.events.push(event); 36692 } 36693 36694 /** @inheritdoc */ 36695 finish() { 36696 return new Promise(resolve => { 36697 // Make a copy of the events array reference and immediately clear the 36698 // events member so that we do not lose new events while uploading 36699 // attachment. 36700 const eventsRet = this.events; 36701 this.clear(); 36702 resolve(JSON.stringify(eventsRet)); 36703 }); 36704 } 36705 36706 /** @inheritdoc */ 36707 clear() { 36708 this.events = []; 36709 this._totalSize = 0; 36710 this.hasCheckout = false; 36711 } 36712 36713 /** @inheritdoc */ 36714 getEarliestTimestamp() { 36715 const timestamp = this.events.map(event => event.timestamp).sort()[0]; 36716 36717 if (!timestamp) { 36718 return null; 36719 } 36720 36721 return timestampToMs(timestamp); 36722 } 36723} 36724 36725/** 36726 * Event buffer that uses a web worker to compress events. 36727 * Exported only for testing. 36728 */ 36729class WorkerHandler { 36730 36731 constructor(worker) { 36732 this._worker = worker; 36733 this._id = 0; 36734 } 36735 36736 /** 36737 * Ensure the worker is ready (or not). 36738 * This will either resolve when the worker is ready, or reject if an error occured. 36739 */ 36740 ensureReady() { 36741 // Ensure we only check once 36742 if (this._ensureReadyPromise) { 36743 return this._ensureReadyPromise; 36744 } 36745 36746 this._ensureReadyPromise = new Promise((resolve, reject) => { 36747 this._worker.addEventListener( 36748 'message', 36749 ({ data }) => { 36750 if ((data ).success) { 36751 resolve(); 36752 } else { 36753 reject(); 36754 } 36755 }, 36756 { once: true }, 36757 ); 36758 36759 this._worker.addEventListener( 36760 'error', 36761 error => { 36762 reject(error); 36763 }, 36764 { once: true }, 36765 ); 36766 }); 36767 36768 return this._ensureReadyPromise; 36769 } 36770 36771 /** 36772 * Destroy the worker. 36773 */ 36774 destroy() { 36775 logInfo('[Replay] Destroying compression worker'); 36776 this._worker.terminate(); 36777 } 36778 36779 /** 36780 * Post message to worker and wait for response before resolving promise. 36781 */ 36782 postMessage(method, arg) { 36783 const id = this._getAndIncrementId(); 36784 36785 return new Promise((resolve, reject) => { 36786 const listener = ({ data }) => { 36787 const response = data ; 36788 if (response.method !== method) { 36789 return; 36790 } 36791 36792 // There can be multiple listeners for a single method, the id ensures 36793 // that the response matches the caller. 36794 if (response.id !== id) { 36795 return; 36796 } 36797 36798 // At this point, we'll always want to remove listener regardless of result status 36799 this._worker.removeEventListener('message', listener); 36800 36801 if (!response.success) { 36802 // TODO: Do some error handling, not sure what 36803 DEBUG_BUILD && utils.logger.error('[Replay]', response.response); 36804 36805 reject(new Error('Error in compression worker')); 36806 return; 36807 } 36808 36809 resolve(response.response ); 36810 }; 36811 36812 // Note: we can't use `once` option because it's possible it needs to 36813 // listen to multiple messages 36814 this._worker.addEventListener('message', listener); 36815 this._worker.postMessage({ id, method, arg }); 36816 }); 36817 } 36818 36819 /** Get the current ID and increment it for the next call. */ 36820 _getAndIncrementId() { 36821 return this._id++; 36822 } 36823} 36824 36825/** 36826 * Event buffer that uses a web worker to compress events. 36827 * Exported only for testing. 36828 */ 36829class EventBufferCompressionWorker { 36830 /** @inheritdoc */ 36831
vendor: 3,385 bytes, lines 36832-36982
36832 constructor(worker) { 36833 this._worker = new WorkerHandler(worker); 36834 this._earliestTimestamp = null; 36835 this._totalSize = 0; 36836 this.hasCheckout = false; 36837 } 36838 36839 /** @inheritdoc */ 36840 get hasEvents() { 36841 return !!this._earliestTimestamp; 36842 } 36843 36844 /** @inheritdoc */ 36845 get type() { 36846 return 'worker'; 36847 } 36848 36849 /** 36850 * Ensure the worker is ready (or not). 36851 * This will either resolve when the worker is ready, or reject if an error occured. 36852 */ 36853 ensureReady() { 36854 return this._worker.ensureReady(); 36855 } 36856 36857 /** 36858 * Destroy the event buffer. 36859 */ 36860 destroy() { 36861 this._worker.destroy(); 36862 } 36863 36864 /** 36865 * Add an event to the event buffer. 36866 * 36867 * Returns true if event was successfuly received and processed by worker. 36868 */ 36869 addEvent(event) { 36870 const timestamp = timestampToMs(event.timestamp); 36871 if (!this._earliestTimestamp || timestamp < this._earliestTimestamp) { 36872 this._earliestTimestamp = timestamp; 36873 } 36874 36875 const data = JSON.stringify(event); 36876 this._totalSize += data.length; 36877 36878 if (this._totalSize > REPLAY_MAX_EVENT_BUFFER_SIZE) { 36879 return Promise.reject(new EventBufferSizeExceededError()); 36880 } 36881 36882 return this._sendEventToWorker(data); 36883 } 36884 36885 /** 36886 * Finish the event buffer and return the compressed data. 36887 */ 36888 finish() { 36889 return this._finishRequest(); 36890 } 36891 36892 /** @inheritdoc */ 36893 clear() { 36894 this._earliestTimestamp = null; 36895 this._totalSize = 0; 36896 this.hasCheckout = false; 36897 36898 // We do not wait on this, as we assume the order of messages is consistent for the worker 36899 this._worker.postMessage('clear').then(null, e => { 36900 DEBUG_BUILD && utils.logger.warn('[Replay] Sending "clear" message to worker failed', e); 36901 }); 36902 } 36903 36904 /** @inheritdoc */ 36905 getEarliestTimestamp() { 36906 return this._earliestTimestamp; 36907 } 36908 36909 /** 36910 * Send the event to the worker. 36911 */ 36912 _sendEventToWorker(data) { 36913 return this._worker.postMessage('addEvent', data); 36914 } 36915 36916 /** 36917 * Finish the request and return the compressed data from the worker. 36918 */ 36919 async _finishRequest() { 36920 const response = await this._worker.postMessage('finish'); 36921 36922 this._earliestTimestamp = null; 36923 this._totalSize = 0; 36924 36925 return response; 36926 } 36927} 36928 36929/** 36930 * This proxy will try to use the compression worker, and fall back to use the simple buffer if an error occurs there. 36931 * This can happen e.g. if the worker cannot be loaded. 36932 * Exported only for testing. 36933 */ 36934class EventBufferProxy { 36935 36936 constructor(worker) { 36937 this._fallback = new EventBufferArray(); 36938 this._compression = new EventBufferCompressionWorker(worker); 36939 this._used = this._fallback; 36940 36941 this._ensureWorkerIsLoadedPromise = this._ensureWorkerIsLoaded(); 36942 } 36943 36944 /** @inheritdoc */ 36945 get type() { 36946 return this._used.type; 36947 } 36948 36949 /** @inheritDoc */ 36950 get hasEvents() { 36951 return this._used.hasEvents; 36952 } 36953 36954 /** @inheritdoc */ 36955 get hasCheckout() { 36956 return this._used.hasCheckout; 36957 } 36958 /** @inheritdoc */ 36959 set hasCheckout(value) { 36960 this._used.hasCheckout = value; 36961 } 36962 36963 /** @inheritDoc */ 36964 destroy() { 36965 this._fallback.destroy(); 36966 this._compression.destroy(); 36967 } 36968 36969 /** @inheritdoc */ 36970 clear() { 36971 return this._used.clear(); 36972 } 36973 36974 /** @inheritdoc */ 36975 getEarliestTimestamp() { 36976 return this._used.getEarliestTimestamp(); 36977 } 36978 36979 /** 36980 * Add an event to the event buffer. 36981 * 36982 * Returns true if event was successfully added.
36983 */ 36984 addEvent(event) { 36985 return this._used.addEvent(event); 36986 } 36987 36988 /** @inheritDoc */ 36989 async finish() { 36990 // Ensure the worker is loaded, so the sent event is compressed 36991 await this.ensureWorkerIsLoaded(); 36992 36993 return this._used.finish(); 36994 } 36995 36996 /** Ensure the worker has loaded. */ 36997 ensureWorkerIsLoaded() { 36998 return this._ensureWorkerIsLoadedPromise; 36999 } 37000 37001 /** Actually check if the worker has been loaded. */ 37002 async _ensureWorkerIsLoaded() { 37003 try { 37004 await this._compression.ensureReady(); 37005 } catch (error) { 37006 // If the worker fails to load, we fall back to the simple buffer. 37007 // Nothing more to do from our side here 37008 logInfo('[Replay] Failed to load the compression worker, falling back to simple buffer'); 37009 return; 37010 } 37011 37012 // Now we need to switch over the array buffer to the compression worker 37013 await this._switchToCompressionWorker(); 37014 } 37015 37016 /** Switch the used buffer to the compression worker. */ 37017 async _switchToCompressionWorker() { 37018 const { events, hasCheckout } = this._fallback; 37019 37020 const addEventPromises = []; 37021 for (const event of events) { 37022 addEventPromises.push(this._compression.addEvent(event)); 37023 } 37024 37025 this._compression.hasCheckout = hasCheckout; 37026 37027 // We switch over to the new buffer immediately - any further events will be added
37028 // after the previously buffered ones 37029 this._used = this._compression; 37030 37031 // Wait for original events to be re-added before resolving 37032 try { 37033 await Promise.all(addEventPromises); 37034 } catch (error) { 37035 DEBUG_BUILD && utils.logger.warn('[Replay] Failed to add events when switching buffers.', error); 37036 } 37037 } 37038} 37039 37040/** 37041 * Create an event buffer for replays. 37042 */ 37043function createEventBuffer({ 37044 useCompression, 37045 workerUrl: customWorkerUrl, 37046}) { 37047 if ( 37048 useCompression && 37049 // eslint-disable-next-line no-restricted-globals 37050 window.Worker 37051 ) { 37052 const worker = _loadWorker(customWorkerUrl); 37053 37054 if (worker) { 37055 return worker; 37056 } 37057 } 37058 37059 logInfo('[Replay] Using simple buffer'); 37060 return new EventBufferArray(); 37061} 37062 37063function _loadWorker(customWorkerUrl) { 37064 try { 37065 const workerUrl = customWorkerUrl || _getWorkerUrl(); 37066 37067 if (!workerUrl) { 37068 return; 37069 } 37070 37071 logInfo(`[Replay] Using compression worker${customWorkerUrl ? ` from ${customWorkerUrl}` : ''}`); 37072 const worker = new Worker(workerUrl); 37073 return new EventBufferProxy(worker); 37074 } catch (error) { 37075 logInfo('[Replay] Failed to create compression worker'); 37076 // Fall back to use simple event buffer array 37077 } 37078} 37079 37080function _getWorkerUrl() { 37081 if (typeof __SENTRY_EXCLUDE_REPLAY_WORKER__ === 'undefined' || !__SENTRY_EXCLUDE_REPLAY_WORKER__) { 37082 return e(); 37083 } 37084 37085 return ''; 37086} 37087 37088/** If sessionStorage is available. */ 37089function hasSessionStorage() { 37090 try { 37091 // This can throw, e.g. when being accessed in a sandboxed iframe 37092 return 'sessionStorage' in WINDOW && !!WINDOW.sessionStorage; 37093 } catch (e) { 37094 return false; 37095 } 37096} 37097 37098/** 37099 * Removes the session from Session Storage and unsets session in replay instance 37100 */ 37101function clearSession(replay) { 37102 deleteSession(); 37103 replay.session = undefined; 37104} 37105 37106/** 37107 * Deletes a session from storage 37108 */ 37109function deleteSession() { 37110 if (!hasSessionStorage()) { 37111 return; 37112 } 37113 37114 try { 37115 WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY); 37116 } catch (e) { 37117 // Ignore potential SecurityError exceptions 37118 } 37119} 37120 37121/** 37122 * Given a sample rate, returns true if replay should be sampled. 37123 * 37124 * 1.0 = 100% sampling 37125 * 0.0 = 0% sampling 37126 */ 37127function isSampled(sampleRate) { 37128 if (sampleRate === undefined) { 37129 return false; 37130 } 37131 37132 // Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1) 37133 return Math.random() < sampleRate; 37134} 37135 37136/** 37137 * Get a session with defaults & applied sampling. 37138 */ 37139function makeSession(session) { 37140 const now = Date.now(); 37141 const id = session.id || utils.uuid4(); 37142 // Note that this means we cannot set a started/lastActivity of `0`, but this should not be relevant outside of tests. 37143 const started = session.started || now; 37144 const lastActivity = session.lastActivity || now; 37145 const segmentId = session.segmentId || 0; 37146 const sampled = session.sampled; 37147 const previousSessionId = session.previousSessionId; 37148 37149 return { 37150 id, 37151 started, 37152 lastActivity, 37153 segmentId, 37154 sampled, 37155 previousSessionId, 37156 }; 37157} 37158 37159/** 37160 * Save a session to session storage. 37161 */ 37162function saveSession(session) { 37163 if (!hasSessionStorage()) { 37164 return; 37165 } 37166 37167 try { 37168 WINDOW.sessionStorage.setItem(REPLAY_SESSION_KEY, JSON.stringify(session)); 37169 } catch (e) { 37170 // Ignore potential SecurityError exceptions 37171 } 37172} 37173 37174/** 37175 * Get the sampled status for a session based on sample rates & current sampled status. 37176 */ 37177function getSessionSampleType(sessionSampleRate, allowBuffering) { 37178 return isSampled(sessionSampleRate) ? 'session' : allowBuffering ? 'buffer' : false; 37179} 37180 37181/** 37182 * Create a new session, which in its current implementation is a Sentry event 37183 * that all replays will be saved to as attachments. Currently, we only expect 37184 * one of these Sentry events per "replay session". 37185 */ 37186function createSession( 37187 { sessionSampleRate, allowBuffering, stickySession = false }, 37188 { previousSessionId } = {}, 37189) { 37190 const sampled = getSessionSampleType(sessionSampleRate, allowBuffering); 37191 const session = makeSession({ 37192 sampled, 37193 previousSessionId, 37194 }); 37195 37196 if (stickySession) { 37197 saveSession(session); 37198 } 37199 37200 return session; 37201} 37202 37203/** 37204 * Fetches a session from storage 37205 */ 37206function fetchSession(traceInternals) { 37207 if (!hasSessionStorage()) { 37208 return null; 37209 } 37210 37211 try { 37212 // This can throw if cookies are disabled 37213 const sessionStringFromStorage = WINDOW.sessionStorage.getItem(REPLAY_SESSION_KEY); 37214 37215 if (!sessionStringFromStorage) { 37216 return null; 37217 } 37218 37219 const sessionObj = JSON.parse(sessionStringFromStorage) ; 37220 37221 logInfoNextTick('[Replay] Loading existing session', traceInternals); 37222 37223 return makeSession(sessionObj); 37224 } catch (e) { 37225 return null; 37226 } 37227} 37228 37229/** 37230 * Given an initial timestamp and an expiry duration, checks to see if current 37231 * time should be considered as expired. 37232 */ 37233function isExpired( 37234 initialTime, 37235 expiry, 37236 targetTime = +new Date(), 37237) { 37238 // Always expired if < 0 37239 if (initialTime === null || expiry === undefined || expiry < 0) { 37240 return true; 37241 } 37242 37243 // Never expires if == 0 37244 if (expiry === 0) { 37245 return false;
37246 } 37247 37248 return initialTime + expiry <= targetTime; 37249} 37250 37251/** 37252 * Checks to see if session is expired 37253 */ 37254function isSessionExpired( 37255 session, 37256 { 37257 maxReplayDuration, 37258 sessionIdleExpire, 37259 targetTime = Date.now(), 37260 }, 37261) { 37262 return ( 37263 // First, check that maximum session length has not been exceeded 37264 isExpired(session.started, maxReplayDuration, targetTime) || 37265 // check that the idle timeout has not been exceeded (i.e. user has 37266 // performed an action within the last `sessionIdleExpire` ms) 37267 isExpired(session.lastActivity, sessionIdleExpire, targetTime) 37268 ); 37269} 37270 37271/** If the session should be refreshed or not. */ 37272function shouldRefreshSession( 37273 session, 37274 { sessionIdleExpire, maxReplayDuration }, 37275) { 37276 // If not expired, all good, just keep the session 37277 if (!isSessionExpired(session, { sessionIdleExpire, maxReplayDuration })) { 37278 return false; 37279 } 37280 37281 // If we are buffering & haven't ever flushed yet, always continue 37282 if (session.sampled === 'buffer' && session.segmentId === 0) { 37283 return false; 37284 } 37285 37286 return true; 37287} 37288 37289/** 37290 * Get or create a session, when initializing the replay. 37291 * Returns a session that may be unsampled. 37292 */ 37293function loadOrCreateSession( 37294 { 37295 traceInternals, 37296 sessionIdleExpire, 37297 maxReplayDuration, 37298 previousSessionId, 37299 } 37300 37301, 37302 sessionOptions, 37303) { 37304 const existingSession = sessionOptions.stickySession && fetchSession(traceInternals); 37305 37306 // No session exists yet, just create a new one 37307 if (!existingSession) { 37308 logInfoNextTick('[Replay] Creating new session', traceInternals); 37309 return createSession(sessionOptions, { previousSessionId }); 37310 } 37311 37312 if (!shouldRefreshSession(existingSession, { sessionIdleExpire, maxReplayDuration })) { 37313 return existingSession; 37314 } 37315 37316 logInfoNextTick('[Replay] Session in sessionStorage is expired, creating new one...'); 37317 return createSession(sessionOptions, { previousSessionId: existingSession.id }); 37318} 37319 37320function isCustomEvent(event) { 37321 return event.type === EventType.Custom; 37322} 37323 37324/** 37325 * Add an event to the event buffer. 37326 * In contrast to `addEvent`, this does not return a promise & does not wait for the adding of the event to succeed/fail. 37327 * Instead this returns `true` if we tried to add the event, else false. 37328 * It returns `false` e.g. if we are paused, disabled, or out of the max replay duration. 37329 * 37330 * `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`. 37331 */ 37332function addEventSync(replay, event, isCheckout) { 37333 if (!shouldAddEvent(replay, event)) { 37334 return false; 37335 } 37336 37337 // This should never reject 37338 // eslint-disable-next-line @typescript-eslint/no-floating-promises 37339 _addEvent(replay, event, isCheckout); 37340 37341 return true; 37342} 37343 37344/** 37345 * Add an event to the event buffer. 37346 * Resolves to `null` if no event was added, else to `void`. 37347 * 37348 * `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`. 37349 */ 37350function addEvent( 37351 replay, 37352 event, 37353 isCheckout, 37354) { 37355 if (!shouldAddEvent(replay, event)) { 37356 return Promise.resolve(null); 37357 } 37358 37359 return _addEvent(replay, event, isCheckout); 37360} 37361 37362async function _addEvent( 37363 replay, 37364 event, 37365 isCheckout, 37366) { 37367 if (!replay.eventBuffer) { 37368 return null; 37369 } 37370 37371 try { 37372 if (isCheckout && replay.recordingMode === 'buffer') { 37373 replay.eventBuffer.clear(); 37374 } 37375 37376 if (isCheckout) { 37377 replay.eventBuffer.hasCheckout = true; 37378 } 37379 37380 const replayOptions = replay.getOptions(); 37381 37382 const eventAfterPossibleCallback = maybeApplyCallback(event, replayOptions.beforeAddRecordingEvent); 37383 37384 if (!eventAfterPossibleCallback) { 37385 return; 37386 } 37387 37388 return await replay.eventBuffer.addEvent(eventAfterPossibleCallback); 37389 } catch (error) { 37390 const reason = error && error instanceof EventBufferSizeExceededError ? 'addEventSizeExceeded' : 'addEvent'; 37391 37392 DEBUG_BUILD && utils.logger.error(error); 37393 await replay.stop({ reason }); 37394 37395 const client = core.getClient(); 37396 37397 if (client) { 37398 client.recordDroppedEvent('internal_sdk_error', 'replay'); 37399 } 37400 } 37401} 37402 37403/** Exported only for tests. */ 37404function shouldAddEvent(replay, event) { 37405 if (!replay.eventBuffer || replay.isPaused() || !replay.isEnabled()) { 37406 return false;
37407 } 37408 37409 const timestampInMs = timestampToMs(event.timestamp); 37410 37411 // Throw out events that happen more than 5 minutes ago. This can happen if 37412 // page has been left open and idle for a long period of time and user 37413 // comes back to trigger a new session. The performance entries rely on 37414 // `performance.timeOrigin`, which is when the page first opened. 37415 if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) { 37416 return false; 37417 } 37418 37419 // Throw out events that are +60min from the initial timestamp 37420 if (timestampInMs > replay.getContext().initialTimestamp + replay.getOptions().maxReplayDuration) { 37421 logInfo( 37422 `[Replay] Skipping event with timestamp ${timestampInMs} because it is after maxReplayDuration`, 37423 replay.getOptions()._experiments.traceInternals, 37424 ); 37425 return false; 37426 } 37427 37428 return true; 37429} 37430 37431function maybeApplyCallback( 37432 event, 37433 callback, 37434) { 37435 try { 37436 if (typeof callback === 'function' && isCustomEvent(event)) { 37437 return callback(event); 37438 } 37439 } catch (error) { 37440 DEBUG_BUILD && 37441 utils.logger.error('[Replay] An error occured in the `beforeAddRecordingEvent` callback, skipping the event...', error); 37442 return null; 37443 } 37444 37445 return event; 37446} 37447 37448/** If the event is an error event */ 37449function isErrorEvent(event) { 37450 return !event.type; 37451} 37452 37453/** If the event is a transaction event */ 37454function isTransactionEvent(event) { 37455 return event.type === 'transaction'; 37456} 37457 37458/** If the event is an replay event */ 37459function isReplayEvent(event) { 37460 return event.type === 'replay_event'; 37461} 37462 37463/** If the event is a feedback event */ 37464function isFeedbackEvent(event) { 37465 return event.type === 'feedback'; 37466} 37467 37468/** 37469 * Returns a listener to be added to `client.on('afterSendErrorEvent, listener)`. 37470 */ 37471function handleAfterSendEvent(replay) { 37472 // Custom transports may still be returning `Promise<void>`, which means we cannot expect the status code to be available there 37473 // TODO (v8): remove this check as it will no longer be necessary 37474 const enforceStatusCode = isBaseTransportSend(); 37475 37476 return (event, sendResponse) => { 37477 if (!replay.isEnabled() || (!isErrorEvent(event) && !isTransactionEvent(event))) { 37478 return; 37479 } 37480 37481 const statusCode = sendResponse && sendResponse.statusCode; 37482 37483 // We only want to do stuff on successful error sending, otherwise you get error replays without errors attached 37484 // If not using the base transport, we allow `undefined` response (as a custom transport may not implement this correctly yet) 37485 // If we do use the base transport, we skip if we encountered an non-OK status code 37486 if (enforceStatusCode && (!statusCode || statusCode < 200 || statusCode >= 300)) { 37487 return; 37488 } 37489 37490 if (isTransactionEvent(event)) { 37491 handleTransactionEvent(replay, event); 37492 return; 37493 } 37494 37495 handleErrorEvent(replay, event); 37496 }; 37497} 37498 37499function handleTransactionEvent(replay, event) { 37500 const replayContext = replay.getContext(); 37501 37502 // Collect traceIds in _context regardless of `recordingMode` 37503 // In error mode, _context gets cleared on every checkout 37504 // We limit to max. 100 transactions linked 37505 if (event.contexts && event.contexts.trace && event.contexts.trace.trace_id && replayContext.traceIds.size < 100) { 37506 replayContext.traceIds.add(event.contexts.trace.trace_id ); 37507 } 37508} 37509 37510function handleErrorEvent(replay, event) { 37511 const replayContext = replay.getContext(); 37512 37513 // Add error to list of errorIds of replay. This is ok to do even if not 37514 // sampled because context will get reset at next checkout. 37515 // XXX: There is also a race condition where it's possible to capture an 37516 // error to Sentry before Replay SDK has loaded, but response returns after 37517 // it was loaded, and this gets called. 37518 // We limit to max. 100 errors linked 37519 if (event.event_id && replayContext.errorIds.size < 100) { 37520 replayContext.errorIds.add(event.event_id); 37521 } 37522 37523 // If error event is tagged with replay id it means it was sampled (when in buffer mode) 37524 // Need to be very careful that this does not cause an infinite loop 37525 if (replay.recordingMode !== 'buffer' || !event.tags || !event.tags.replayId) { 37526 return; 37527 } 37528 37529 const { beforeErrorSampling } = replay.getOptions(); 37530 if (typeof beforeErrorSampling === 'function' && !beforeErrorSampling(event)) { 37531 return; 37532 } 37533 37534 setTimeout(() => { 37535 // Capture current event buffer as new replay 37536 // This should never reject 37537 // eslint-disable-next-line @typescript-eslint/no-floating-promises 37538 replay.sendBufferedReplayOrFlush(); 37539 }); 37540} 37541 37542function isBaseTransportSend() { 37543 const client = core.getClient(); 37544 if (!client) { 37545 return false;
37546 } 37547 37548 const transport = client.getTransport(); 37549 if (!transport) { 37550 return false; 37551 } 37552 37553 return ( 37554 (transport.send ).__sentry__baseTransport__ || false 37555 ); 37556} 37557 37558/** 37559 * Returns a listener to be added to `client.on('afterSendErrorEvent, listener)`. 37560 */ 37561function handleBeforeSendEvent(replay) { 37562 return (event) => { 37563 if (!replay.isEnabled() || !isErrorEvent(event)) { 37564 return; 37565 } 37566 37567 handleHydrationError(replay, event); 37568 }; 37569} 37570 37571function handleHydrationError(replay, event) { 37572 const exceptionValue = event.exception && event.exception.values && event.exception.values[0].value; 37573 if (typeof exceptionValue !== 'string') { 37574 return; 37575 } 37576 37577 if ( 37578 // Only matches errors in production builds of react-dom 37579 // Example https://reactjs.org/docs/error-decoder.html?invariant=423 37580 exceptionValue.match(/reactjs\.org\/docs\/error-decoder\.html\?invariant=(418|419|422|423|425)/) || 37581 // Development builds of react-dom 37582 // Error 1: Hydration failed because the initial UI does not match what was rendered on the server. 37583 // Error 2: Text content does not match server-rendered HTML. Warning: Text content did not match. 37584 exceptionValue.match(/(does not match server-rendered HTML|Hydration failed because)/i) 37585 ) { 37586 const breadcrumb = createBreadcrumb({ 37587 category: 'replay.hydrate-error', 37588 }); 37589 addBreadcrumbEvent(replay, breadcrumb); 37590 } 37591} 37592 37593/** 37594 * Returns true if we think the given event is an error originating inside of rrweb. 37595 */ 37596function isRrwebError(event, hint) { 37597 if (event.type || !event.exception || !event.exception.values || !event.exception.values.length) { 37598 return false; 37599 } 37600 37601 // @ts-expect-error this may be set by rrweb when it finds errors 37602 if (hint.originalException && hint.originalException.__rrweb__) { 37603 return true; 37604 } 37605 37606 return false; 37607} 37608 37609/** 37610 * Add a feedback breadcrumb event to replay. 37611 */ 37612function addFeedbackBreadcrumb(replay, event) { 37613 replay.triggerUserActivity(); 37614 replay.addUpdate(() => { 37615 if (!event.timestamp) { 37616 // Ignore events that don't have timestamps (this shouldn't happen, more of a typing issue) 37617 // Return true here so that we don't flush 37618 return true; 37619 } 37620 37621 // This should never reject 37622 // eslint-disable-next-line @typescript-eslint/no-floating-promises 37623 replay.throttledAddEvent({ 37624 type: EventType.Custom, 37625 timestamp: event.timestamp * 1000, 37626 data: { 37627 tag: 'breadcrumb', 37628 payload: { 37629 timestamp: event.timestamp, 37630 type: 'default', 37631 category: 'sentry.feedback', 37632 data: { 37633 feedbackId: event.event_id, 37634 }, 37635 }, 37636 }, 37637 } ); 37638 37639 return false; 37640 }); 37641} 37642 37643/** 37644 * Determine if event should be sampled (only applies in buffer mode). 37645 * When an event is captured by `hanldleGlobalEvent`, when in buffer mode 37646 * we determine if we want to sample the error or not. 37647 */ 37648function shouldSampleForBufferEvent(replay, event) { 37649 if (replay.recordingMode !== 'buffer') { 37650 return false; 37651 } 37652 37653 // ignore this error because otherwise we could loop indefinitely with 37654 // trying to capture replay and failing 37655 if (event.message === UNABLE_TO_SEND_REPLAY) { 37656 return false; 37657 } 37658 37659 // Require the event to be an error event & to have an exception 37660 if (!event.exception || event.type) { 37661 return false; 37662 } 37663 37664 return isSampled(replay.getOptions().errorSampleRate); 37665} 37666 37667/** 37668 * Returns a listener to be added to `addEventProcessor(listener)`. 37669 */ 37670function handleGlobalEventListener( 37671 replay, 37672 includeAfterSendEventHandling = false, 37673) { 37674 const afterSendHandler = includeAfterSendEventHandling ? handleAfterSendEvent(replay) : undefined; 37675 37676 return Object.assign( 37677 (event, hint) => { 37678 // Do nothing if replay has been disabled 37679 if (!replay.isEnabled()) { 37680 return event; 37681 } 37682 37683 if (isReplayEvent(event)) { 37684 // Replays have separate set of breadcrumbs, do not include breadcrumbs 37685 // from core SDK 37686 delete event.breadcrumbs; 37687 return event; 37688 } 37689 37690 // We only want to handle errors, transactions, and feedbacks, nothing else 37691 if (!isErrorEvent(event) && !isTransactionEvent(event) && !isFeedbackEvent(event)) { 37692 return event; 37693 } 37694 37695 // Ensure we do not add replay_id if the session is expired
37696 const isSessionActive = replay.checkAndHandleExpiredSession(); 37697 if (!isSessionActive) { 37698 return event; 37699 } 37700 37701 if (isFeedbackEvent(event)) { 37702 // This should never reject 37703 // eslint-disable-next-line @typescript-eslint/no-floating-promises 37704 replay.flush(); 37705 event.contexts.feedback.replay_id = replay.getSessionId(); 37706 // Add a replay breadcrumb for this piece of feedback 37707 addFeedbackBreadcrumb(replay, event); 37708 return event; 37709 } 37710 37711 // Unless `captureExceptions` is enabled, we want to ignore errors coming from rrweb 37712 // As there can be a bunch of stuff going wrong in internals there, that we don't want to bubble up to users 37713 if (isRrwebError(event, hint) && !replay.getOptions()._experiments.captureExceptions) { 37714 DEBUG_BUILD && utils.logger.log('[Replay] Ignoring error from rrweb internals', event); 37715 return null; 37716 } 37717 37718 // When in buffer mode, we decide to sample here. 37719 // Later, in `handleAfterSendEvent`, if the replayId is set, we know that we sampled 37720 // And convert the buffer session to a full session 37721 const isErrorEventSampled = shouldSampleForBufferEvent(replay, event); 37722 37723 // Tag errors if it has been sampled in buffer mode, or if it is session mode 37724 // Only tag transactions if in session mode 37725 const shouldTagReplayId = isErrorEventSampled || replay.recordingMode === 'session'; 37726 37727 if (shouldTagReplayId) { 37728 event.tags = { ...event.tags, replayId: replay.getSessionId() }; 37729 } 37730 37731 // In cases where a custom client is used that does not support the new hooks (yet), 37732 // we manually call this hook method here 37733 if (afterSendHandler) { 37734 // Pretend the error had a 200 response so we always capture it 37735 afterSendHandler(event, { statusCode: 200 }); 37736 } 37737 37738 return event; 37739 }, 37740 { id: 'Replay' }, 37741 ); 37742} 37743 37744/** 37745 * Create a "span" for each performance entry. 37746 */ 37747function createPerformanceSpans( 37748 replay, 37749 entries, 37750) { 37751 return entries.map(({ type, start, end, name, data }) => { 37752 const response = replay.throttledAddEvent({ 37753 type: EventType.Custom, 37754 timestamp: start, 37755 data: { 37756 tag: 'performanceSpan', 37757 payload: { 37758 op: type, 37759 description: name, 37760 startTimestamp: start, 37761 endTimestamp: end, 37762 data, 37763 }, 37764 }, 37765 }); 37766 37767 // If response is a string, it means its either THROTTLED or SKIPPED 37768 return typeof response === 'string' ? Promise.resolve(null) : response; 37769 }); 37770} 37771 37772function handleHistory(handlerData) { 37773 const { from, to } = handlerData; 37774 37775 const now = Date.now() / 1000; 37776 37777 return { 37778 type: 'navigation.push', 37779 start: now, 37780 end: now, 37781 name: to, 37782 data: { 37783 previous: from, 37784 }, 37785 }; 37786} 37787 37788/** 37789 * Returns a listener to be added to `addHistoryInstrumentationHandler(listener)`. 37790 */ 37791function handleHistorySpanListener(replay) { 37792 return (handlerData) => { 37793 if (!replay.isEnabled()) { 37794 return; 37795 } 37796 37797 const result = handleHistory(handlerData); 37798 37799 if (result === null) { 37800 return; 37801 } 37802 37803 // Need to collect visited URLs 37804 replay.getContext().urls.push(result.name); 37805 replay.triggerUserActivity(); 37806 37807 replay.addUpdate(() => { 37808 createPerformanceSpans(replay, [result]); 37809 // Returning false to flush 37810 return false; 37811 }); 37812 }; 37813} 37814 37815/** 37816 * Check whether a given request URL should be filtered out. This is so we 37817 * don't log Sentry ingest requests. 37818 */ 37819function shouldFilterRequest(replay, url) { 37820 // If we enabled the `traceInternals` experiment, we want to trace everything 37821 if (DEBUG_BUILD && replay.getOptions()._experiments.traceInternals) { 37822 return false; 37823 } 37824 37825 return core.isSentryRequestUrl(url, core.getClient()); 37826} 37827 37828/** Add a performance entry breadcrumb */ 37829function addNetworkBreadcrumb( 37830 replay, 37831 result, 37832) { 37833 if (!replay.isEnabled()) { 37834 return; 37835 } 37836 37837 if (result === null) { 37838 return; 37839 } 37840 37841 if (shouldFilterRequest(replay, result.name)) { 37842 return; 37843 } 37844 37845 replay.addUpdate(() => { 37846 createPerformanceSpans(replay, [result]); 37847 // Returning true will cause `addUpdate` to not flush 37848 // We do not want network requests to cause a flush. This will prevent 37849 // recurring/polling requests from keeping the replay session alive. 37850 return true; 37851 }); 37852} 37853 37854/** only exported for tests */ 37855function handleFetch(handlerData) { 37856 const { startTimestamp, endTimestamp, fetchData, response } = handlerData; 37857 37858 if (!endTimestamp) { 37859 return null; 37860 } 37861 37862 // This is only used as a fallback, so we know the body sizes are never set here 37863 const { method, url } = fetchData; 37864 37865 return { 37866 type: 'resource.fetch', 37867 start: startTimestamp / 1000, 37868 end: endTimestamp / 1000, 37869 name: url, 37870 data: { 37871 method, 37872 statusCode: response ? (response ).status : undefined, 37873 }, 37874 }; 37875} 37876 37877/** 37878 * Returns a listener to be added to `addFetchInstrumentationHandler(listener)`. 37879 */ 37880function handleFetchSpanListener(replay) { 37881 return (handlerData) => { 37882 if (!replay.isEnabled()) { 37883 return; 37884 } 37885 37886 const result = handleFetch(handlerData); 37887 37888 addNetworkBreadcrumb(replay, result); 37889 }; 37890} 37891 37892/** only exported for tests */ 37893function handleXhr(handlerData) { 37894 const { startTimestamp, endTimestamp, xhr } = handlerData; 37895 37896 const sentryXhrData = xhr[utils.SENTRY_XHR_DATA_KEY]; 37897 37898 if (!startTimestamp || !endTimestamp || !sentryXhrData) { 37899 return null; 37900 } 37901 37902 // This is only used as a fallback, so we know the body sizes are never set here 37903 const { method, url, status_code: statusCode } = sentryXhrData; 37904 37905 if (url === undefined) { 37906 return null; 37907 } 37908 37909 return { 37910 type: 'resource.xhr', 37911 name: url, 37912 start: startTimestamp / 1000, 37913 end: endTimestamp / 1000, 37914 data: { 37915 method, 37916 statusCode, 37917 }, 37918 }; 37919} 37920 37921/** 37922 * Returns a listener to be added to `addXhrInstrumentationHandler(listener)`. 37923 */ 37924function handleXhrSpanListener(replay) { 37925 return (handlerData) => { 37926 if (!replay.isEnabled()) { 37927 return; 37928 } 37929
37930 const result = handleXhr(handlerData); 37931 37932 addNetworkBreadcrumb(replay, result); 37933 }; 37934} 37935 37936/** Get the size of a body. */ 37937function getBodySize( 37938 body, 37939 textEncoder, 37940) { 37941 if (!body) { 37942 return undefined; 37943 } 37944 37945 try { 37946 if (typeof body === 'string') { 37947 return textEncoder.encode(body).length; 37948 } 37949 37950 if (body instanceof URLSearchParams) { 37951 return textEncoder.encode(body.toString()).length; 37952 } 37953 37954 if (body instanceof FormData) { 37955 const formDataStr = _serializeFormData(body); 37956 return textEncoder.encode(formDataStr).length; 37957 } 37958 37959 if (body instanceof Blob) { 37960 return body.size; 37961 } 37962 37963 if (body instanceof ArrayBuffer) { 37964 return body.byteLength; 37965 } 37966 37967 // Currently unhandled types: ArrayBufferView, ReadableStream 37968 } catch (e) { 37969 // just return undefined 37970 } 37971 37972 return undefined; 37973} 37974 37975/** Convert a Content-Length header to number/undefined. */ 37976function parseContentLengthHeader(header) { 37977 if (!header) { 37978 return undefined; 37979 } 37980 37981 const size = parseInt(header, 10); 37982 return isNaN(size) ? undefined : size; 37983} 37984 37985/** Get the string representation of a body. */ 37986function getBodyString(body) { 37987 try { 37988 if (typeof body === 'string') { 37989 return [body]; 37990 } 37991 37992 if (body instanceof URLSearchParams) { 37993 return [body.toString()]; 37994 } 37995 37996 if (body instanceof FormData) { 37997 return [_serializeFormData(body)]; 37998 } 37999 38000 if (!body) { 38001 return [undefined]; 38002 } 38003 } catch (e2) { 38004 DEBUG_BUILD && utils.logger.warn('[Replay] Failed to serialize body', body); 38005 return [undefined, 'BODY_PARSE_ERROR']; 38006 } 38007 38008 DEBUG_BUILD && utils.logger.info('[Replay] Skipping network body because of body type', body); 38009 38010 return [undefined, 'UNPARSEABLE_BODY_TYPE']; 38011} 38012 38013/** Merge a warning into an existing network request/response. */ 38014function mergeWarning( 38015 info, 38016 warning, 38017) { 38018 if (!info) { 38019 return { 38020 headers: {}, 38021 size: undefined, 38022 _meta: { 38023 warnings: [warning], 38024 }, 38025 }; 38026 } 38027 38028 const newMeta = { ...info._meta }; 38029 const existingWarnings = newMeta.warnings || []; 38030 newMeta.warnings = [...existingWarnings, warning]; 38031 38032 info._meta = newMeta; 38033 return info; 38034} 38035
38036/** Convert ReplayNetworkRequestData to a PerformanceEntry. */ 38037function makeNetworkReplayBreadcrumb( 38038 type, 38039 data, 38040) { 38041 if (!data) { 38042 return null; 38043 } 38044 38045 const { startTimestamp, endTimestamp, url, method, statusCode, request, response } = data; 38046 38047 const result = { 38048 type, 38049 start: startTimestamp / 1000, 38050 end: endTimestamp / 1000, 38051 name: url, 38052 data: utils.dropUndefinedKeys({ 38053 method, 38054 statusCode, 38055 request, 38056 response, 38057 }), 38058 }; 38059 38060 return result; 38061} 38062 38063/** Build the request or response part of a replay network breadcrumb that was skipped. */ 38064function buildSkippedNetworkRequestOrResponse(bodySize) { 38065 return { 38066 headers: {}, 38067 size: bodySize, 38068 _meta: { 38069 warnings: ['URL_SKIPPED'], 38070 }, 38071 }; 38072} 38073 38074/** Build the request or response part of a replay network breadcrumb. */ 38075function buildNetworkRequestOrResponse( 38076 headers, 38077 bodySize, 38078 body, 38079) { 38080 if (!bodySize && Object.keys(headers).length === 0) { 38081 return undefined; 38082 } 38083 38084 if (!bodySize) { 38085 return { 38086 headers, 38087 }; 38088 } 38089 38090 if (!body) { 38091 return { 38092 headers, 38093 size: bodySize, 38094 }; 38095 } 38096 38097 const info = { 38098 headers, 38099 size: bodySize, 38100 }; 38101 38102 const { body: normalizedBody, warnings } = normalizeNetworkBody(body); 38103 info.body = normalizedBody; 38104 if (warnings && warnings.length > 0) { 38105 info._meta = { 38106 warnings, 38107 }; 38108 } 38109 38110 return info; 38111} 38112 38113/** Filter a set of headers */ 38114function getAllowedHeaders(headers, allowedHeaders) { 38115 return Object.keys(headers).reduce((filteredHeaders, key) => { 38116 const normalizedKey = key.toLowerCase(); 38117 // Avoid putting empty strings into the headers 38118 if (allowedHeaders.includes(normalizedKey) && headers[key]) { 38119 filteredHeaders[normalizedKey] = headers[key]; 38120 } 38121 return filteredHeaders; 38122 }, {}); 38123} 38124 38125function _serializeFormData(formData) { 38126 // This is a bit simplified, but gives us a decent estimate 38127 // This converts e.g. { name: 'Anne Smith', age: 13 } to 'name=Anne+Smith&age=13' 38128 // @ts-expect-error passing FormData to URLSearchParams actually works 38129 return new URLSearchParams(formData).toString(); 38130} 38131 38132function normalizeNetworkBody(body) 38133 38134 { 38135 if (!body || typeof body !== 'string') { 38136 return { 38137 body, 38138 }; 38139 } 38140 38141 const exceedsSizeLimit = body.length > NETWORK_BODY_MAX_SIZE; 38142 const isProbablyJson = _strIsProbablyJson(body); 38143 38144 if (exceedsSizeLimit) { 38145 const truncatedBody = body.slice(0, NETWORK_BODY_MAX_SIZE); 38146 38147 if (isProbablyJson) { 38148 return { 38149 body: truncatedBody, 38150 warnings: ['MAYBE_JSON_TRUNCATED'], 38151 }; 38152 } 38153 38154 return { 38155 body: `${truncatedBody}â¦`, 38156 warnings: ['TEXT_TRUNCATED'], 38157 }; 38158 } 38159 38160 if (isProbablyJson) { 38161 try { 38162 const jsonBody = JSON.parse(body); 38163 return { 38164 body: jsonBody, 38165 }; 38166 } catch (e3) { 38167 // fall back to just send the body as string 38168 } 38169 } 38170 38171 return { 38172 body, 38173 }; 38174} 38175 38176function _strIsProbablyJson(str) { 38177 const first = str[0]; 38178 const last = str[str.length - 1]; 38179 38180 // Simple check: If this does not start & end with {} or [], it's not JSON 38181 return (first === '[' && last === ']') || (first === '{' && last === '}'); 38182} 38183 38184/** Match an URL against a list of strings/Regex. */ 38185function urlMatches(url, urls) { 38186 const fullUrl = getFullUrl(url); 38187 38188 return utils.stringMatchesSomePattern(fullUrl, urls); 38189} 38190 38191/** exported for tests */ 38192function getFullUrl(url, baseURI = WINDOW.document.baseURI) { 38193 // Short circuit for common cases: 38194 if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith(WINDOW.location.origin)) { 38195 return url; 38196 } 38197 const fixedUrl = new URL(url, baseURI); 38198 38199 // If these do not match, we are not dealing with a relative URL, so just return it 38200 if (fixedUrl.origin !== new URL(baseURI).origin) { 38201 return url; 38202 } 38203 38204 const fullUrl = fixedUrl.href; 38205 38206 // Remove trailing slashes, if they don't match the original URL 38207 if (!url.endsWith('/') && fullUrl.endsWith('/')) { 38208 return fullUrl.slice(0, -1); 38209 } 38210 38211 return fullUrl; 38212} 38213 38214/** 38215 * Capture a fetch breadcrumb to a replay. 38216 * This adds additional data (where approriate). 38217 */ 38218async function captureFetchBreadcrumbToReplay( 38219 breadcrumb, 38220 hint, 38221 options 38222 38223, 38224) { 38225 try { 38226 const data = await _prepareFetchData(breadcrumb, hint, options); 38227 38228 // Create a replay performance entry from this breadcrumb 38229 const result = makeNetworkReplayBreadcrumb('resource.fetch', data); 38230 addNetworkBreadcrumb(options.replay, result); 38231 } catch (error) { 38232 DEBUG_BUILD && utils.logger.error('[Replay] Failed to capture fetch breadcrumb', error); 38233 } 38234} 38235 38236/** 38237 * Enrich a breadcrumb with additional data. 38238 * This has to be sync & mutate the given breadcrumb, 38239 * as the breadcrumb is afterwards consumed by other handlers. 38240 */ 38241function enrichFetchBreadcrumb( 38242 breadcrumb, 38243 hint, 38244 options, 38245) { 38246 const { input, response } = hint; 38247 38248 const body = input ? _getFetchRequestArgBody(input) : undefined; 38249 const reqSize = getBodySize(body, options.textEncoder); 38250 38251 const resSize = response ? parseContentLengthHeader(response.headers.get('content-length')) : undefined; 38252 38253 if (reqSize !== undefined) { 38254 breadcrumb.data.request_body_size = reqSize; 38255 } 38256 if (resSize !== undefined) { 38257 breadcrumb.data.response_body_size = resSize; 38258 } 38259} 38260 38261async function _prepareFetchData( 38262 breadcrumb, 38263 hint, 38264 options 38265 38266, 38267) { 38268 const now = Date.now(); 38269 const { startTimestamp = now, endTimestamp = now } = hint; 38270 38271 const { 38272 url, 38273 method, 38274 status_code: statusCode = 0, 38275 request_body_size: requestBodySize, 38276 response_body_size: responseBodySize, 38277 } = breadcrumb.data; 38278 38279 const captureDetails = 38280 urlMatches(url, options.networkDetailAllowUrls) && !urlMatches(url, options.networkDetailDenyUrls); 38281 38282 const request = captureDetails 38283 ? _getRequestInfo(options, hint.input, requestBodySize)
38284 : buildSkippedNetworkRequestOrResponse(requestBodySize); 38285 const response = await _getResponseInfo(captureDetails, options, hint.response, responseBodySize); 38286 38287 return { 38288 startTimestamp, 38289 endTimestamp, 38290 url, 38291 method, 38292 statusCode, 38293 request, 38294 response, 38295 }; 38296} 38297 38298function _getRequestInfo( 38299 { networkCaptureBodies, networkRequestHeaders }, 38300 input, 38301 requestBodySize, 38302) { 38303 const headers = input ? getRequestHeaders(input, networkRequestHeaders) : {}; 38304 38305 if (!networkCaptureBodies) { 38306 return buildNetworkRequestOrResponse(headers, requestBodySize, undefined); 38307 } 38308 38309 // We only want to transmit string or string-like bodies 38310 const requestBody = _getFetchRequestArgBody(input); 38311 const [bodyStr, warning] = getBodyString(requestBody); 38312 const data = buildNetworkRequestOrResponse(headers, requestBodySize, bodyStr); 38313 38314 if (warning) { 38315 return mergeWarning(data, warning); 38316 } 38317 38318 return data; 38319} 38320 38321/** Exported only for tests. */ 38322async function _getResponseInfo( 38323 captureDetails, 38324 { 38325 networkCaptureBodies, 38326 textEncoder, 38327 networkResponseHeaders, 38328 } 38329 38330, 38331 response, 38332 responseBodySize, 38333) { 38334 if (!captureDetails && responseBodySize !== undefined) { 38335 return buildSkippedNetworkRequestOrResponse(responseBodySize); 38336 } 38337 38338 const headers = response ? getAllHeaders(response.headers, networkResponseHeaders) : {}; 38339 38340 if (!response || (!networkCaptureBodies && responseBodySize !== undefined)) { 38341 return buildNetworkRequestOrResponse(headers, responseBodySize, undefined); 38342 } 38343 38344 const [bodyText, warning] = await _parseFetchResponseBody(response); 38345 const result = getResponseData(bodyText, { 38346 networkCaptureBodies, 38347 textEncoder, 38348 responseBodySize, 38349 captureDetails, 38350 headers, 38351 }); 38352 38353 if (warning) { 38354 return mergeWarning(result, warning); 38355 } 38356 38357 return result; 38358} 38359 38360function getResponseData( 38361 bodyText, 38362 { 38363 networkCaptureBodies, 38364 textEncoder, 38365 responseBodySize, 38366 captureDetails, 38367 headers, 38368 } 38369 38370, 38371) { 38372 try { 38373 const size = 38374 bodyText && bodyText.length && responseBodySize === undefined 38375 ? getBodySize(bodyText, textEncoder) 38376 : responseBodySize; 38377 38378 if (!captureDetails) { 38379 return buildSkippedNetworkRequestOrResponse(size); 38380 } 38381 38382 if (networkCaptureBodies) { 38383 return buildNetworkRequestOrResponse(headers, size, bodyText); 38384 } 38385 38386 return buildNetworkRequestOrResponse(headers, size, undefined); 38387 } catch (error) { 38388 DEBUG_BUILD && utils.logger.warn('[Replay] Failed to serialize response body', error); 38389 // fallback 38390 return buildNetworkRequestOrResponse(headers, responseBodySize, undefined); 38391 } 38392} 38393 38394async function _parseFetchResponseBody(response) { 38395 const res = _tryCloneResponse(response); 38396 38397 if (!res) { 38398 return [undefined, 'BODY_PARSE_ERROR']; 38399 } 38400 38401 try { 38402 const text = await _tryGetResponseText(res); 38403 return [text]; 38404 } catch (error) { 38405 DEBUG_BUILD && utils.logger.warn('[Replay] Failed to get text body from response', error); 38406 return [undefined, 'BODY_PARSE_ERROR']; 38407 } 38408} 38409 38410function _getFetchRequestArgBody(fetchArgs = []) { 38411 // We only support getting the body from the fetch options 38412 if (fetchArgs.length !== 2 || typeof fetchArgs[1] !== 'object') { 38413 return undefined; 38414 } 38415 38416 return (fetchArgs[1] ).body; 38417} 38418 38419function getAllHeaders(headers, allowedHeaders) { 38420 const allHeaders = {}; 38421 38422 allowedHeaders.forEach(header => { 38423 if (headers.get(header)) { 38424 allHeaders[header] = headers.get(header) ; 38425 } 38426 }); 38427 38428 return allHeaders; 38429} 38430 38431function getRequestHeaders(fetchArgs, allowedHeaders) { 38432 if (fetchArgs.length === 1 && typeof fetchArgs[0] !== 'string') { 38433 return getHeadersFromOptions(fetchArgs[0] , allowedHeaders); 38434 } 38435 38436 if (fetchArgs.length === 2) { 38437 return getHeadersFromOptions(fetchArgs[1] , allowedHeaders); 38438 } 38439 38440 return {}; 38441} 38442 38443function getHeadersFromOptions( 38444 input, 38445 allowedHeaders, 38446) { 38447 if (!input) { 38448 return {}; 38449 } 38450 38451 const headers = input.headers; 38452 38453 if (!headers) { 38454 return {}; 38455 } 38456 38457 if (headers instanceof Headers) { 38458 return getAllHeaders(headers, allowedHeaders); 38459 } 38460 38461 // We do not support this, as it is not really documented (anymore?) 38462 if (Array.isArray(headers)) { 38463 return {}; 38464 } 38465 38466 return getAllowedHeaders(headers, allowedHeaders); 38467} 38468 38469function _tryCloneResponse(response) { 38470 try { 38471 // We have to clone this, as the body can only be read once 38472 return response.clone(); 38473 } catch (error) { 38474 // this can throw if the response was already consumed before 38475 DEBUG_BUILD && utils.logger.warn('[Replay] Failed to clone response body', error); 38476 } 38477} 38478 38479/** 38480 * Get the response body of a fetch request, or timeout after 500ms. 38481 * Fetch can return a streaming body, that may not resolve (or not for a long time). 38482 * If that happens, we rather abort after a short time than keep waiting for this. 38483 */ 38484function _tryGetResponseText(response) { 38485 return new Promise((resolve, reject) => { 38486 const timeout = setTimeout(() => reject(new Error('Timeout while trying to read response body')), 500); 38487 38488 _getResponseText(response) 38489 .then( 38490 txt => resolve(txt), 38491 reason => reject(reason), 38492 ) 38493 .finally(() => clearTimeout(timeout)); 38494 }); 38495} 38496 38497async function _getResponseText(response) { 38498 // Force this to be a promise, just to be safe 38499 // eslint-disable-next-line no-return-await 38500 return await response.text(); 38501} 38502 38503/** 38504 * Capture an XHR breadcrumb to a replay. 38505 * This adds additional data (where approriate). 38506 */ 38507async function captureXhrBreadcrumbToReplay( 38508 breadcrumb, 38509 hint, 38510 options, 38511) { 38512 try { 38513 const data = _prepareXhrData(breadcrumb, hint, options); 38514 38515 // Create a replay performance entry from this breadcrumb 38516 const result = makeNetworkReplayBreadcrumb('resource.xhr', data); 38517 addNetworkBreadcrumb(options.replay, result); 38518 } catch (error) { 38519 DEBUG_BUILD && utils.logger.error('[Replay] Failed to capture xhr breadcrumb', error); 38520 } 38521} 38522 38523/** 38524 * Enrich a breadcrumb with additional data. 38525 * This has to be sync & mutate the given breadcrumb, 38526 * as the breadcrumb is afterwards consumed by other handlers. 38527 */ 38528function enrichXhrBreadcrumb( 38529 breadcrumb, 38530 hint, 38531 options, 38532) { 38533 const { xhr, input } = hint; 38534 38535 if (!xhr) { 38536 return; 38537 } 38538 38539 const reqSize = getBodySize(input, options.textEncoder); 38540 const resSize = xhr.getResponseHeader('content-length') 38541 ? parseContentLengthHeader(xhr.getResponseHeader('content-length')) 38542 : _getBodySize(xhr.response, xhr.responseType, options.textEncoder); 38543 38544 if (reqSize !== undefined) { 38545 breadcrumb.data.request_body_size = reqSize; 38546 } 38547 if (resSize !== undefined) { 38548 breadcrumb.data.response_body_size = resSize; 38549 } 38550} 38551 38552function _prepareXhrData( 38553 breadcrumb, 38554 hint, 38555 options, 38556) { 38557 const now = Date.now(); 38558 const { startTimestamp = now, endTimestamp = now, input, xhr } = hint; 38559 38560 const { 38561 url, 38562 method, 38563 status_code: statusCode = 0, 38564 request_body_size: requestBodySize, 38565 response_body_size: responseBodySize, 38566 } = breadcrumb.data; 38567 38568 if (!url) { 38569 return null; 38570 } 38571 38572 if (!xhr || !urlMatches(url, options.networkDetailAllowUrls) || urlMatches(url, options.networkDetailDenyUrls)) {
38573 const request = buildSkippedNetworkRequestOrResponse(requestBodySize); 38574 const response = buildSkippedNetworkRequestOrResponse(responseBodySize); 38575 return { 38576 startTimestamp, 38577 endTimestamp, 38578 url, 38579 method, 38580 statusCode, 38581 request, 38582 response, 38583 }; 38584 } 38585 38586 const xhrInfo = xhr[utils.SENTRY_XHR_DATA_KEY]; 38587 const networkRequestHeaders = xhrInfo 38588 ? getAllowedHeaders(xhrInfo.request_headers, options.networkRequestHeaders) 38589 : {}; 38590 const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders); 38591 38592 const [requestBody, requestWarning] = options.networkCaptureBodies ? getBodyString(input) : [undefined]; 38593 const [responseBody, responseWarning] = options.networkCaptureBodies ? _getXhrResponseBody(xhr) : [undefined]; 38594 38595 const request = buildNetworkRequestOrResponse(networkRequestHeaders, requestBodySize, requestBody); 38596 const response = buildNetworkRequestOrResponse(networkResponseHeaders, responseBodySize, responseBody); 38597 38598 return { 38599 startTimestamp, 38600 endTimestamp, 38601 url, 38602 method, 38603 statusCode, 38604 request: requestWarning ? mergeWarning(request, requestWarning) : request, 38605 response: responseWarning ? mergeWarning(response, responseWarning) : response, 38606 }; 38607} 38608 38609function getResponseHeaders(xhr) { 38610 const headers = xhr.getAllResponseHeaders(); 38611 38612 if (!headers) { 38613 return {}; 38614 } 38615 38616 return headers.split('\r\n').reduce((acc, line) => { 38617 const [key, value] = line.split(': '); 38618 acc[key.toLowerCase()] = value; 38619 return acc; 38620 }, {}); 38621} 38622 38623function _getXhrResponseBody(xhr) { 38624 // We collect errors that happen, but only log them if we can't get any response body 38625 const errors = []; 38626 38627 try { 38628 return [xhr.responseText]; 38629 } catch (e) { 38630 errors.push(e); 38631 } 38632 38633 // Try to manually parse the response body, if responseText fails 38634 try { 38635 return _parseXhrResponse(xhr.response, xhr.responseType); 38636 } catch (e) { 38637 errors.push(e); 38638 } 38639 38640 DEBUG_BUILD && utils.logger.warn('[Replay] Failed to get xhr response body', ...errors); 38641 38642 return [undefined]; 38643} 38644 38645/** 38646 * Get the string representation of the XHR response. 38647 * Based on MDN, these are the possible types of the response: 38648 * string 38649 * ArrayBuffer 38650 * Blob 38651 * Document 38652 * POJO 38653 * 38654 * Exported only for tests. 38655 */ 38656function _parseXhrResponse( 38657 body, 38658 responseType, 38659) { 38660 try { 38661 if (typeof body === 'string') { 38662 return [body]; 38663 } 38664 38665 if (body instanceof Document) { 38666 return [body.body.outerHTML]; 38667 } 38668 38669 if (responseType === 'json' && body && typeof body === 'object') { 38670 return [JSON.stringify(body)]; 38671 } 38672 38673 if (!body) { 38674 return [undefined]; 38675 } 38676 } catch (e2) { 38677 DEBUG_BUILD && utils.logger.warn('[Replay] Failed to serialize body', body); 38678 return [undefined, 'BODY_PARSE_ERROR']; 38679 } 38680 38681 DEBUG_BUILD && utils.logger.info('[Replay] Skipping network body because of body type', body); 38682 38683 return [undefined, 'UNPARSEABLE_BODY_TYPE']; 38684} 38685 38686function _getBodySize( 38687 body, 38688 responseType, 38689 textEncoder, 38690) { 38691 try { 38692 const bodyStr = responseType === 'json' && body && typeof body === 'object' ? JSON.stringify(body) : body; 38693 return getBodySize(bodyStr, textEncoder); 38694 } catch (e3) { 38695 return undefined; 38696 } 38697} 38698 38699/** 38700 * This method does two things: 38701 * - It enriches the regular XHR/fetch breadcrumbs with request/response size data 38702 * - It captures the XHR/fetch breadcrumbs to the replay 38703 * (enriching it with further data that is _not_ added to the regular breadcrumbs) 38704 */ 38705function handleNetworkBreadcrumbs(replay) { 38706 const client = core.getClient(); 38707 38708 try { 38709 const textEncoder = new TextEncoder(); 38710 38711 const { 38712 networkDetailAllowUrls, 38713 networkDetailDenyUrls, 38714 networkCaptureBodies, 38715 networkRequestHeaders, 38716 networkResponseHeaders, 38717 } = replay.getOptions(); 38718 38719 const options = { 38720 replay, 38721 textEncoder, 38722 networkDetailAllowUrls, 38723 networkDetailDenyUrls, 38724 networkCaptureBodies, 38725 networkRequestHeaders, 38726 networkResponseHeaders, 38727 }; 38728 38729 if (client && client.on) { 38730 client.on('beforeAddBreadcrumb', (breadcrumb, hint) => beforeAddNetworkBreadcrumb(options, breadcrumb, hint)); 38731 } else { 38732 // Fallback behavior 38733 utils.addFetchInstrumentationHandler(handleFetchSpanListener(replay)); 38734 utils.addXhrInstrumentationHandler(handleXhrSpanListener(replay)); 38735 } 38736 } catch (e2) {
38737 // Do nothing 38738 } 38739} 38740 38741/** just exported for tests */ 38742function beforeAddNetworkBreadcrumb( 38743 options, 38744 breadcrumb, 38745 hint, 38746) { 38747 if (!breadcrumb.data) { 38748 return; 38749 } 38750 38751 try { 38752 if (_isXhrBreadcrumb(breadcrumb) && _isXhrHint(hint)) { 38753 // This has to be sync, as we need to ensure the breadcrumb is enriched in the same tick 38754 // Because the hook runs synchronously, and the breadcrumb is afterwards passed on 38755 // So any async mutations to it will not be reflected in the final breadcrumb 38756 enrichXhrBreadcrumb(breadcrumb, hint, options); 38757 38758 // This call should not reject 38759 // eslint-disable-next-line @typescript-eslint/no-floating-promises 38760 captureXhrBreadcrumbToReplay(breadcrumb, hint, options); 38761 } 38762 38763 if (_isFetchBreadcrumb(breadcrumb) && _isFetchHint(hint)) { 38764 // This has to be sync, as we need to ensure the breadcrumb is enriched in the same tick 38765 // Because the hook runs synchronously, and the breadcrumb is afterwards passed on 38766 // So any async mutations to it will not be reflected in the final breadcrumb 38767 enrichFetchBreadcrumb(breadcrumb, hint, options); 38768 38769 // This call should not reject 38770 // eslint-disable-next-line @typescript-eslint/no-floating-promises 38771 captureFetchBreadcrumbToReplay(breadcrumb, hint, options); 38772 } 38773 } catch (e) { 38774 DEBUG_BUILD && utils.logger.warn('Error when enriching network breadcrumb'); 38775 } 38776} 38777 38778function _isXhrBreadcrumb(breadcrumb) { 38779 return breadcrumb.category === 'xhr'; 38780} 38781 38782function _isFetchBreadcrumb(breadcrumb) { 38783 return breadcrumb.category === 'fetch'; 38784} 38785 38786function _isXhrHint(hint) { 38787 return hint && hint.xhr; 38788} 38789 38790function _isFetchHint(hint) { 38791 return hint && hint.response; 38792} 38793 38794let _LAST_BREADCRUMB = null; 38795 38796function isBreadcrumbWithCategory(breadcrumb) { 38797 return !!breadcrumb.category; 38798} 38799 38800const handleScopeListener = 38801 (replay) => 38802 (scope) => { 38803 if (!replay.isEnabled()) { 38804 return; 38805 } 38806 38807 const result = handleScope(scope); 38808 38809 if (!result) { 38810 return; 38811 } 38812 38813 addBreadcrumbEvent(replay, result); 38814 }; 38815 38816/** 38817 * An event handler to handle scope changes. 38818 */ 38819function handleScope(scope) { 38820 // TODO (v8): Remove this guard. This was put in place because we introduced 38821 // Scope.getLastBreadcrumb mid-v7 which caused incompatibilities with older SDKs. 38822 // For now, we'll just return null if the method doesn't exist but we should eventually 38823 // get rid of this guard. 38824 const newBreadcrumb = scope.getLastBreadcrumb && scope.getLastBreadcrumb(); 38825 38826 // Listener can be called when breadcrumbs have not changed, so we store the 38827 // reference to the last crumb and only return a crumb if it has changed 38828 if (_LAST_BREADCRUMB === newBreadcrumb || !newBreadcrumb) { 38829 return null; 38830 } 38831 38832 _LAST_BREADCRUMB = newBreadcrumb; 38833 38834 if ( 38835 !isBreadcrumbWithCategory(newBreadcrumb) || 38836 ['fetch', 'xhr', 'sentry.event', 'sentry.transaction'].includes(newBreadcrumb.category) || 38837 newBreadcrumb.category.startsWith('ui.') 38838 ) { 38839 return null; 38840 } 38841 38842 if (newBreadcrumb.category === 'console') { 38843 return normalizeConsoleBreadcrumb(newBreadcrumb); 38844 } 38845 38846 return createBreadcrumb(newBreadcrumb); 38847} 38848 38849/** exported for tests only */ 38850function normalizeConsoleBreadcrumb( 38851 breadcrumb, 38852) { 38853 const args = breadcrumb.data && breadcrumb.data.arguments; 38854 38855 if (!Array.isArray(args) || args.length === 0) { 38856 return createBreadcrumb(breadcrumb); 38857 } 38858 38859 let isTruncated = false; 38860 38861 // Avoid giant args captures 38862 const normalizedArgs = args.map(arg => { 38863 if (!arg) { 38864 return arg; 38865 } 38866 if (typeof arg === 'string') { 38867 if (arg.length > CONSOLE_ARG_MAX_SIZE) { 38868 isTruncated = true; 38869 return `${arg.slice(0, CONSOLE_ARG_MAX_SIZE)}â¦`; 38870 } 38871 38872 return arg; 38873 } 38874 if (typeof arg === 'object') { 38875 try { 38876 const normalizedArg = utils.normalize(arg, 7); 38877 const stringified = JSON.stringify(normalizedArg); 38878 if (stringified.length > CONSOLE_ARG_MAX_SIZE) { 38879 isTruncated = true; 38880 // We use the pretty printed JSON string here as a base 38881 return `${JSON.stringify(normalizedArg, null, 2).slice(0, CONSOLE_ARG_MAX_SIZE)}â¦`; 38882 } 38883 return normalizedArg; 38884 } catch (e) { 38885 // fall back to default 38886 } 38887 } 38888 38889 return arg; 38890 }); 38891 38892 return createBreadcrumb({ 38893 ...breadcrumb, 38894 data: { 38895 ...breadcrumb.data, 38896 arguments: normalizedArgs, 38897 ...(isTruncated ? { _meta: { warnings: ['CONSOLE_ARG_TRUNCATED'] } } : {}), 38898 }, 38899 }); 38900} 38901 38902/** 38903 * Add global listeners that cannot be removed. 38904 */ 38905function addGlobalListeners(replay) { 38906 // Listeners from core SDK // 38907 const scope = core.getCurrentScope(); 38908 const client = core.getClient(); 38909 38910 scope.addScopeListener(handleScopeListener(replay)); 38911 utils.addClickKeypressInstrumentationHandler(handleDomListener(replay)); 38912 utils.addHistoryInstrumentationHandler(handleHistorySpanListener(replay)); 38913 handleNetworkBreadcrumbs(replay); 38914 38915 // Tag all (non replay) events that get sent to Sentry with the current 38916 // replay ID so that we can reference them later in the UI 38917 const eventProcessor = handleGlobalEventListener(replay, !hasHooks(client)); 38918 if (client && client.addEventProcessor) { 38919 client.addEventProcessor(eventProcessor); 38920 } else { 38921 core.addEventProcessor(eventProcessor); 38922 } 38923 38924 // If a custom client has no hooks yet, we continue to use the "old" implementation 38925 if (hasHooks(client)) { 38926 client.on('beforeSendEvent', handleBeforeSendEvent(replay)); 38927 client.on('afterSendEvent', handleAfterSendEvent(replay)); 38928 client.on('createDsc', (dsc) => { 38929 const replayId = replay.getSessionId(); 38930 // We do not want to set the DSC when in buffer mode, as that means the replay has not been sent (yet) 38931 if (replayId && replay.isEnabled() && replay.recordingMode === 'session') { 38932 // Ensure to check that the session is still active - it could have expired in the meanwhile
38933 const isSessionActive = replay.checkAndHandleExpiredSession(); 38934 if (isSessionActive) { 38935 dsc.replay_id = replayId; 38936 } 38937 } 38938 }); 38939 38940 client.on('startTransaction', transaction => { 38941 replay.lastTransaction = transaction; 38942 }); 38943 38944 // We may be missing the initial startTransaction due to timing issues, 38945 // so we capture it on finish again. 38946 client.on('finishTransaction', transaction => { 38947 replay.lastTransaction = transaction; 38948 }); 38949 38950 // We want to flush replay 38951 client.on('beforeSendFeedback', (feedbackEvent, options) => { 38952 const replayId = replay.getSessionId(); 38953 if (options && options.includeReplay && replay.isEnabled() && replayId) { 38954 // This should never reject 38955 if (feedbackEvent.contexts && feedbackEvent.contexts.feedback) { 38956 feedbackEvent.contexts.feedback.replay_id = replayId; 38957 } 38958 } 38959 }); 38960 } 38961} 38962 38963// eslint-disable-next-line @typescript-eslint/no-explicit-any 38964function hasHooks(client) { 38965 return !!(client && client.on); 38966} 38967 38968/** 38969 * Create a "span" for the total amount of memory being used by JS objects 38970 * (including v8 internal objects). 38971 */ 38972async function addMemoryEntry(replay) { 38973 // window.performance.memory is a non-standard API and doesn't work on all browsers, so we try-catch this 38974 try { 38975 return Promise.all( 38976 createPerformanceSpans(replay, [ 38977 // @ts-expect-error memory doesn't exist on type Performance as the API is non-standard (we check that it exists above) 38978 createMemoryEntry(WINDOW.performance.memory), 38979 ]), 38980 ); 38981 } catch (error) { 38982 // Do nothing 38983 return []; 38984 } 38985} 38986 38987function createMemoryEntry(memoryEntry) { 38988 const { jsHeapSizeLimit, totalJSHeapSize, usedJSHeapSize } = memoryEntry; 38989 // we don't want to use `getAbsoluteTime` because it adds the event time to the 38990 // time origin, so we get the current timestamp instead 38991 const time = Date.now() / 1000; 38992 return { 38993 type: 'memory', 38994 name: 'memory', 38995 start: time, 38996 end: time, 38997 data: { 38998 memory: { 38999 jsHeapSizeLimit, 39000 totalJSHeapSize, 39001 usedJSHeapSize, 39002 }, 39003 }, 39004 }; 39005} 39006 39007/** 39008 * Heavily simplified debounce function based on lodash.debounce. 39009 * 39010 * This function takes a callback function (@param fun) and delays its invocation 39011 * by @param wait milliseconds. Optionally, a maxWait can be specified in @param options, 39012 * which ensures that the callback is invoked at least once after the specified max. wait time. 39013 * 39014 * @param func the function whose invocation is to be debounced 39015 * @param wait the minimum time until the function is invoked after it was called once 39016 * @param options the options object, which can contain the `maxWait` property 39017 * 39018 * @returns the debounced version of the function, which needs to be called at least once to start the 39019 * debouncing process. Subsequent calls will reset the debouncing timer and, in case @paramfunc 39020 * was already invoked in the meantime, return @param func's return value. 39021 * The debounced function has two additional properties: 39022 * - `flush`: Invokes the debounced function immediately and returns its return value 39023 * - `cancel`: Cancels the debouncing process and resets the debouncing timer 39024 */ 39025function debounce(func, wait, options) { 39026 let callbackReturnValue; 39027 39028 let timerId; 39029 let maxTimerId; 39030 39031 const maxWait = options && options.maxWait ? Math.max(options.maxWait, wait) : 0; 39032 39033 function invokeFunc() { 39034 cancelTimers(); 39035 callbackReturnValue = func(); 39036 return callbackReturnValue; 39037 } 39038 39039 function cancelTimers() { 39040 timerId !== undefined && clearTimeout(timerId); 39041 maxTimerId !== undefined && clearTimeout(maxTimerId); 39042 timerId = maxTimerId = undefined; 39043 } 39044 39045 function flush() { 39046 if (timerId !== undefined || maxTimerId !== undefined) { 39047 return invokeFunc(); 39048 } 39049 return callbackReturnValue; 39050 } 39051 39052 function debounced() { 39053 if (timerId) { 39054 clearTimeout(timerId); 39055 } 39056 timerId = setTimeout(invokeFunc, wait); 39057 39058 if (maxWait && maxTimerId === undefined) { 39059 maxTimerId = setTimeout(invokeFunc, maxWait); 39060 } 39061 39062 return callbackReturnValue; 39063 } 39064 39065 debounced.cancel = cancelTimers; 39066 debounced.flush = flush; 39067 return debounced; 39068} 39069 39070/** 39071 * Handler for recording events. 39072 * 39073 * Adds to event buffer, and has varying flushing behaviors if the event was a checkout. 39074 */ 39075function getHandleRecordingEmit(replay) { 39076 let hadFirstEvent = false;
39077 39078 return (event, _isCheckout) => { 39079 // If this is false, it means session is expired, create and a new session and wait for checkout 39080 if (!replay.checkAndHandleExpiredSession()) { 39081 DEBUG_BUILD && utils.logger.warn('[Replay] Received replay event after session expired.'); 39082 39083 return; 39084 } 39085 39086 // `_isCheckout` is only set when the checkout is due to `checkoutEveryNms` 39087 // We also want to treat the first event as a checkout, so we handle this specifically here 39088 const isCheckout = _isCheckout || !hadFirstEvent; 39089 hadFirstEvent = true; 39090 39091 if (replay.clickDetector) { 39092 updateClickDetectorForRecordingEvent(replay.clickDetector, event); 39093 } 39094 39095 // The handler returns `true` if we do not want to trigger debounced flush, `false` if we want to debounce flush. 39096 replay.addUpdate(() => { 39097 // The session is always started immediately on pageload/init, but for 39098 // error-only replays, it should reflect the most recent checkout 39099 // when an error occurs. Clear any state that happens before this current
39100 // checkout. This needs to happen before `addEvent()` which updates state 39101 // dependent on this reset. 39102 if (replay.recordingMode === 'buffer' && isCheckout) { 39103 replay.setInitialState(); 39104 } 39105 39106 // If the event is not added (e.g. due to being paused, disabled, or out of the max replay duration), 39107 // Skip all further steps 39108 if (!addEventSync(replay, event, isCheckout)) { 39109 // Return true to skip scheduling a debounced flush 39110 return true; 39111 } 39112 39113 // Different behavior for full snapshots (type=2), ignore other event types 39114 // See https://github.com/rrweb-io/rrweb/blob/d8f9290ca496712aa1e7d472549480c4e7876594/packages/rrweb/src/types.ts#L16 39115 if (!isCheckout) { 39116 return false; 39117 } 39118 39119 // Additionally, create a meta event that will capture certain SDK settings. 39120 // In order to handle buffer mode, this needs to either be done when we 39121 // receive checkout events or at flush time. 39122 // 39123 // `isCheckout` is always true, but want to be explicit that it should 39124 // only be added for checkouts 39125 addSettingsEvent(replay, isCheckout); 39126 39127 // If there is a previousSessionId after a full snapshot occurs, then 39128 // the replay session was started due to session expiration. The new session 39129 // is started before triggering a new checkout and contains the id 39130 // of the previous session. Do not immediately flush in this case 39131 // to avoid capturing only the checkout and instead the replay will 39132 // be captured if they perform any follow-up actions. 39133 if (replay.session && replay.session.previousSessionId) { 39134 return true; 39135 } 39136 39137 // When in buffer mode, make sure we adjust the session started date to the current earliest event of the buffer 39138 // this should usually be the timestamp of the checkout event, but to be safe... 39139 if (replay.recordingMode === 'buffer' && replay.session && replay.eventBuffer) { 39140 const earliestEvent = replay.eventBuffer.getEarliestTimestamp(); 39141 if (earliestEvent) { 39142 logInfo( 39143 `[Replay] Updating session start time to earliest event in buffer to ${new Date(earliestEvent)}`, 39144 replay.getOptions()._experiments.traceInternals, 39145 ); 39146 39147 replay.session.started = earliestEvent; 39148 39149 if (replay.getOptions().stickySession) { 39150 saveSession(replay.session); 39151 } 39152 } 39153 } 39154 39155 if (replay.recordingMode === 'session') { 39156 // If the full snapshot is due to an initial load, we will not have 39157 // a previous session ID. In this case, we want to buffer events 39158 // for a set amount of time before flushing. This can help avoid 39159 // capturing replays of users that immediately close the window. 39160 39161 // This should never reject 39162 // eslint-disable-next-line @typescript-eslint/no-floating-promises 39163 void replay.flush(); 39164 } 39165 39166 return true; 39167 }); 39168 }; 39169} 39170 39171/** 39172 * Exported for tests 39173 */ 39174function createOptionsEvent(replay) { 39175 const options = replay.getOptions(); 39176 return { 39177 type: EventType.Custom, 39178 timestamp: Date.now(), 39179 data: { 39180 tag: 'options', 39181 payload: { 39182 shouldRecordCanvas: replay.isRecordingCanvas(), 39183 sessionSampleRate: options.sessionSampleRate, 39184 errorSampleRate: options.errorSampleRate, 39185 useCompressionOption: options.useCompression, 39186 blockAllMedia: options.blockAllMedia, 39187 maskAllText: options.maskAllText, 39188 maskAllInputs: options.maskAllInputs, 39189 useCompression: replay.eventBuffer ? replay.eventBuffer.type === 'worker' : false, 39190 networkDetailHasUrls: options.networkDetailAllowUrls.length > 0, 39191 networkCaptureBodies: options.networkCaptureBodies, 39192 networkRequestHasHeaders: options.networkRequestHeaders.length > 0, 39193 networkResponseHasHeaders: options.networkResponseHeaders.length > 0, 39194 }, 39195 }, 39196 }; 39197} 39198 39199/** 39200 * Add a "meta" event that contains a simplified view on current configuration 39201 * options. This should only be included on the first segment of a recording. 39202 */ 39203function addSettingsEvent(replay, isCheckout) { 39204 // Only need to add this event when sending the first segment 39205 if (!isCheckout || !replay.session || replay.session.segmentId !== 0) { 39206 return; 39207 } 39208 39209 addEventSync(replay, createOptionsEvent(replay), false); 39210} 39211 39212/** 39213 * Create a replay envelope ready to be sent. 39214 * This includes both the replay event, as well as the recording data. 39215 */ 39216function createReplayEnvelope( 39217 replayEvent, 39218 recordingData, 39219 dsn, 39220 tunnel, 39221) { 39222 return utils.createEnvelope( 39223 utils.createEventEnvelopeHeaders(replayEvent, utils.getSdkMetadataForEnvelopeHeader(replayEvent), tunnel, dsn), 39224 [ 39225 [{ type: 'replay_event' }, replayEvent], 39226 [ 39227 { 39228 type: 'replay_recording',
39229 // If string then we need to encode to UTF8, otherwise will have 39230 // wrong size. TextEncoder has similar browser support to 39231 // MutationObserver, although it does not accept IE11. 39232 length: 39233 typeof recordingData === 'string' ? new TextEncoder().encode(recordingData).length : recordingData.length, 39234 }, 39235 recordingData, 39236 ], 39237 ], 39238 ); 39239} 39240 39241/** 39242 * Prepare the recording data ready to be sent. 39243 */ 39244function prepareRecordingData({ 39245 recordingData, 39246 headers, 39247} 39248 39249) { 39250 let payloadWithSequence; 39251 39252 // XXX: newline is needed to separate sequence id from events 39253 const replayHeaders = `${JSON.stringify(headers)} 39254`; 39255 39256 if (typeof recordingData === 'string') { 39257 payloadWithSequence = `${replayHeaders}${recordingData}`; 39258 } else { 39259 const enc = new TextEncoder(); 39260 // XXX: newline is needed to separate sequence id from events 39261 const sequence = enc.encode(replayHeaders); 39262 // Merge the two Uint8Arrays 39263 payloadWithSequence = new Uint8Array(sequence.length + recordingData.length); 39264 payloadWithSequence.set(sequence); 39265 payloadWithSequence.set(recordingData, sequence.length); 39266 } 39267 39268 return payloadWithSequence; 39269} 39270 39271/** 39272 * Prepare a replay event & enrich it with the SDK metadata. 39273 */ 39274async function prepareReplayEvent({ 39275 client, 39276 scope, 39277 replayId: event_id, 39278 event, 39279} 39280 39281) { 39282 const integrations = 39283 typeof client._integrations === 'object' && client._integrations !== null && !Array.isArray(client._integrations) 39284 ? Object.keys(client._integrations) 39285 : undefined; 39286 39287 const eventHint = { event_id, integrations }; 39288 39289 if (client.emit) { 39290 client.emit('preprocessEvent', event, eventHint); 39291 } 39292 39293 const preparedEvent = (await core.prepareEvent( 39294 client.getOptions(), 39295 event, 39296 eventHint, 39297 scope, 39298 client, 39299 core.getIsolationScope(), 39300 )) ; 39301 39302 // If e.g. a global event processor returned null 39303 if (!preparedEvent) { 39304 return null; 39305 } 39306 39307 // This normally happens in browser client "_prepareEvent" 39308 // but since we do not use this private method from the client, but rather the plain import 39309 // we need to do this manually. 39310 preparedEvent.platform = preparedEvent.platform || 'javascript'; 39311 39312 // extract the SDK name because `client._prepareEvent` doesn't add it to the event 39313 const metadata = client.getSdkMetadata && client.getSdkMetadata(); 39314 const { name, version } = (metadata && metadata.sdk) || {}; 39315 39316 preparedEvent.sdk = { 39317 ...preparedEvent.sdk, 39318 name: name || 'sentry.javascript.unknown', 39319 version: version || '0.0.0', 39320 }; 39321 39322 return preparedEvent; 39323} 39324 39325/** 39326 * Send replay attachment using `fetch()` 39327 */ 39328async function sendReplayRequest({ 39329 recordingData, 39330 replayId, 39331 segmentId: segment_id, 39332 eventContext, 39333 timestamp, 39334 session, 39335}) { 39336 const preparedRecordingData = prepareRecordingData({ 39337 recordingData, 39338 headers: { 39339 segment_id, 39340 }, 39341 }); 39342 39343 const { urls, errorIds, traceIds, initialTimestamp } = eventContext; 39344 39345 const client = core.getClient(); 39346 const scope = core.getCurrentScope(); 39347 const transport = client && client.getTransport(); 39348 const dsn = client && client.getDsn(); 39349 39350 if (!client || !transport || !dsn || !session.sampled) { 39351 return; 39352 } 39353 39354 const baseEvent = { 39355 type: REPLAY_EVENT_NAME, 39356 replay_start_timestamp: initialTimestamp / 1000, 39357 timestamp: timestamp / 1000, 39358 error_ids: errorIds, 39359 trace_ids: traceIds, 39360 urls, 39361 replay_id: replayId, 39362 segment_id, 39363 replay_type: session.sampled, 39364 }; 39365 39366 const replayEvent = await prepareReplayEvent({ scope, client, replayId, event: baseEvent }); 39367 39368 if (!replayEvent) { 39369 // Taken from baseclient's `_processEvent` method, where this is handled for errors/transactions 39370 client.recordDroppedEvent('event_processor', 'replay', baseEvent); 39371 logInfo('An event processor returned `null`, will not send event.'); 39372 return; 39373 } 39374 39375 /* 39376 For reference, the fully built event looks something like this: 39377 { 39378 "type": "replay_event", 39379 "timestamp": 1670837008.634, 39380 "error_ids": [ 39381 "errorId" 39382 ], 39383 "trace_ids": [ 39384 "traceId" 39385 ], 39386 "urls": [ 39387 "https://example.com" 39388 ], 39389 "replay_id": "eventId", 39390 "segment_id": 3, 39391 "replay_type": "error", 39392 "platform": "javascript", 39393 "event_id": "eventId", 39394 "environment": "production", 39395 "sdk": { 39396 "integrations": [ 39397 "BrowserTracing", 39398 "Replay" 39399 ], 39400 "name": "sentry.javascript.browser", 39401 "version": "7.25.0" 39402 }, 39403 "sdkProcessingMetadata": {}, 39404 "contexts": { 39405 }, 39406 } 39407 */ 39408 39409 // Prevent this data (which, if it exists, was used in earlier steps in the processing pipeline) from being sent to 39410 // sentry. (Note: Our use of this property comes and goes with whatever we might be debugging, whatever hacks we may 39411 // have temporarily added, etc. Even if we don't happen to be using it at some point in the future, let's not get rid 39412 // of this `delete`, lest we miss putting it back in the next time the property is in use.) 39413 delete replayEvent.sdkProcessingMetadata; 39414 39415 const envelope = createReplayEnvelope(replayEvent, preparedRecordingData, dsn, client.getOptions().tunnel); 39416 39417 let response; 39418 39419 try { 39420 response = await transport.send(envelope); 39421 } catch (err) { 39422 const error = new Error(UNABLE_TO_SEND_REPLAY); 39423 39424 try { 39425 // In case browsers don't allow this property to be writable 39426 // @ts-expect-error This needs lib es2022 and newer 39427 error.cause = err;
39428 } catch (e) { 39429 // nothing to do 39430 } 39431 throw error; 39432 } 39433 39434 // TODO (v8): we can remove this guard once transport.send's type signature doesn't include void anymore 39435 if (!response) { 39436 return response; 39437 } 39438 39439 // If the status code is invalid, we want to immediately stop & not retry 39440 if (typeof response.statusCode === 'number' && (response.statusCode < 200 || response.statusCode >= 300)) { 39441 throw new TransportStatusCodeError(response.statusCode); 39442 } 39443 39444 const rateLimits = utils.updateRateLimits({}, response); 39445 if (utils.isRateLimited(rateLimits, 'replay')) { 39446 throw new RateLimitError(rateLimits); 39447 } 39448 39449 return response; 39450} 39451 39452/** 39453 * This error indicates that the transport returned an invalid status code. 39454 */ 39455class TransportStatusCodeError extends Error { 39456 constructor(statusCode) { 39457 super(`Transport returned status code ${statusCode}`); 39458 } 39459} 39460 39461/** 39462 * This error indicates that we hit a rate limit API error. 39463 */ 39464class RateLimitError extends Error { 39465 39466 constructor(rateLimits) { 39467 super('Rate limit hit'); 39468 this.rateLimits = rateLimits; 39469 } 39470} 39471 39472/** 39473 * Finalize and send the current replay event to Sentry 39474 */ 39475async function sendReplay( 39476 replayData, 39477 retryConfig = { 39478 count: 0, 39479 interval: RETRY_BASE_INTERVAL, 39480 }, 39481) { 39482 const { recordingData, options } = replayData; 39483 39484 // short circuit if there's no events to upload (this shouldn't happen as _runFlush makes this check) 39485 if (!recordingData.length) { 39486 return; 39487 } 39488 39489 try { 39490 await sendReplayRequest(replayData); 39491 return true; 39492 } catch (err) { 39493 if (err instanceof TransportStatusCodeError || err instanceof RateLimitError) { 39494 throw err; 39495 } 39496 39497 // Capture error for every failed replay 39498 core.setContext('Replays', { 39499 _retryCount: retryConfig.count, 39500 }); 39501 39502 if (DEBUG_BUILD && options._experiments && options._experiments.captureExceptions) { 39503 core.captureException(err); 39504 } 39505 39506 // If an error happened here, it's likely that uploading the attachment 39507 // failed, we'll can retry with the same events payload 39508 if (retryConfig.count >= RETRY_MAX_COUNT) { 39509 const error = new Error(`${UNABLE_TO_SEND_REPLAY} - max retries exceeded`); 39510 39511 try { 39512 // In case browsers don't allow this property to be writable 39513 // @ts-expect-error This needs lib es2022 and newer 39514 error.cause = err; 39515 } catch (e) { 39516 // nothing to do 39517 } 39518 39519 throw error; 39520 } 39521 39522 // will retry in intervals of 5, 10, 30 39523 retryConfig.interval *= ++retryConfig.count; 39524 39525 return new Promise((resolve, reject) => { 39526 setTimeout(async () => { 39527 try { 39528 await sendReplay(replayData, retryConfig); 39529 resolve(true); 39530 } catch (err) { 39531 reject(err); 39532 } 39533 }, retryConfig.interval); 39534 }); 39535 } 39536} 39537 39538const THROTTLED = '__THROTTLED'; 39539const SKIPPED = '__SKIPPED'; 39540 39541/** 39542 * Create a throttled function off a given function. 39543 * When calling the throttled function, it will call the original function only 39544 * if it hasn't been called more than `maxCount` times in the last `durationSeconds`. 39545 * 39546 * Returns `THROTTLED` if throttled for the first time, after that `SKIPPED`, 39547 * or else the return value of the original function. 39548 */ 39549// eslint-disable-next-line @typescript-eslint/no-explicit-any 39550function throttle( 39551 fn, 39552 maxCount, 39553 durationSeconds, 39554) { 39555 const counter = new Map(); 39556 39557 const _cleanup = (now) => { 39558 const threshold = now - durationSeconds; 39559 counter.forEach((_value, key) => { 39560 if (key < threshold) { 39561 counter.delete(key); 39562 } 39563 }); 39564 }; 39565 39566 const _getTotalCount = () => { 39567 return [...counter.values()].reduce((a, b) => a + b, 0); 39568 }; 39569 39570 let isThrottled = false; 39571 39572 return (...rest) => { 39573 // Date in second-precision, which we use as basis for the throttling 39574 const now = Math.floor(Date.now() / 1000); 39575 39576 // First, make sure to delete any old entries 39577 _cleanup(now); 39578 39579 // If already over limit, do nothing 39580 if (_getTotalCount() >= maxCount) { 39581 const wasThrottled = isThrottled; 39582 isThrottled = true; 39583 return wasThrottled ? SKIPPED : THROTTLED; 39584 } 39585 39586 isThrottled = false;
39587 const count = counter.get(now) || 0; 39588 counter.set(now, count + 1); 39589 39590 return fn(...rest); 39591 }; 39592} 39593 39594/* eslint-disable max-lines */ // TODO: We might want to split this file up 39595 39596/** 39597 * The main replay container class, which holds all the state and methods for recording and sending replays. 39598 */ 39599class ReplayContainer { 39600 39601 /** 39602 * Recording can happen in one of three modes: 39603 * - session: Record the whole session, sending it continuously 39604 * - buffer: Always keep the last 60s of recording, requires: 39605 * - having replaysOnErrorSampleRate > 0 to capture replay when an error occurs 39606 * - or calling `flush()` to send the replay 39607 */ 39608 39609 /** 39610 * The current or last active transcation. 39611 * This is only available when performance is enabled. 39612 */ 39613 39614 /** 39615 * These are here so we can overwrite them in tests etc. 39616 * @hidden 39617 */ 39618 39619 /** 39620 * Options to pass to `rrweb.record()` 39621 */ 39622 39623 /** 39624 * Timestamp of the last user activity. This lives across sessions. 39625 */ 39626 39627 /** 39628 * Is the integration currently active? 39629 */ 39630 39631 /** 39632 * Paused is a state where: 39633 * - DOM Recording is not listening at all 39634 * - Nothing will be added to event buffer (e.g. core SDK events) 39635 */ 39636 39637 /** 39638 * Have we attached listeners to the core SDK? 39639 * Note we have to track this as there is no way to remove instrumentation handlers. 39640 */ 39641 39642 /** 39643 * Function to stop recording 39644 */ 39645 39646 /** 39647 * Internal use for canvas recording options 39648 */ 39649 39650 constructor({ 39651 options, 39652 recordingOptions, 39653 } 39654 39655) {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); 39656 this.eventBuffer = null; 39657 this.performanceEntries = []; 39658 this.replayPerformanceEntries = []; 39659 this.recordingMode = 'session'; 39660 this.timeouts = { 39661 sessionIdlePause: SESSION_IDLE_PAUSE_DURATION, 39662 sessionIdleExpire: SESSION_IDLE_EXPIRE_DURATION, 39663 } ; 39664 this._lastActivity = Date.now(); 39665 this._isEnabled = false; 39666 this._isPaused = false; 39667 this._hasInitializedCoreListeners = false; 39668 this._context = { 39669 errorIds: new Set(), 39670 traceIds: new Set(), 39671 urls: [], 39672 initialTimestamp: Date.now(), 39673 initialUrl: '', 39674 }; 39675 39676 this._recordingOptions = recordingOptions; 39677 this._options = options; 39678 39679 this._debouncedFlush = debounce(() => this._flush(), this._options.flushMinDelay, { 39680 maxWait: this._options.flushMaxDelay, 39681 }); 39682 39683 this._throttledAddEvent = throttle( 39684 (event, isCheckout) => addEvent(this, event, isCheckout), 39685 // Max 300 events... 39686 300, 39687 // ... per 5s 39688 5, 39689 ); 39690 39691 const { slowClickTimeout, slowClickIgnoreSelectors } = this.getOptions(); 39692 39693 const slowClickConfig = slowClickTimeout 39694 ? { 39695 threshold: Math.min(SLOW_CLICK_THRESHOLD, slowClickTimeout), 39696 timeout: slowClickTimeout, 39697 scrollTimeout: SLOW_CLICK_SCROLL_TIMEOUT, 39698 ignoreSelector: slowClickIgnoreSelectors ? slowClickIgnoreSelectors.join(',') : '', 39699 } 39700 : undefined; 39701 39702 if (slowClickConfig) { 39703 this.clickDetector = new ClickDetector(this, slowClickConfig); 39704 } 39705 } 39706 39707 /** Get the event context. */ 39708 getContext() { 39709 return this._context; 39710 } 39711 39712 /** If recording is currently enabled. */ 39713 isEnabled() { 39714 return this._isEnabled; 39715 } 39716 39717 /** If recording is currently paused. */ 39718 isPaused() { 39719 return this._isPaused; 39720 } 39721 39722 /** 39723 * Determine if canvas recording is enabled 39724 */ 39725 isRecordingCanvas() { 39726 return Boolean(this._canvas); 39727 } 39728 39729 /** Get the replay integration options. */ 39730 getOptions() { 39731 return this._options; 39732 } 39733 39734 /** 39735 * Initializes the plugin based on sampling configuration. Should not be 39736 * called outside of constructor. 39737 */ 39738 initializeSampling(previousSessionId) { 39739 const { errorSampleRate, sessionSampleRate } = this._options; 39740 39741 // If neither sample rate is > 0, then do nothing - user will need to call one of
39742 // `start()` or `startBuffering` themselves. 39743 if (errorSampleRate <= 0 && sessionSampleRate <= 0) { 39744 return; 39745 } 39746 39747 // Otherwise if there is _any_ sample rate set, try to load an existing 39748 // session, or create a new one. 39749 this._initializeSessionForSampling(previousSessionId); 39750 39751 if (!this.session) { 39752 // This should not happen, something wrong has occurred 39753 this._handleException(new Error('Unable to initialize and create session')); 39754 return; 39755 } 39756 39757 if (this.session.sampled === false) { 39758 // This should only occur if `errorSampleRate` is 0 and was unsampled for 39759 // session-based replay. In this case there is nothing to do. 39760 return; 39761 } 39762 39763 // If segmentId > 0, it means we've previously already captured this session 39764 // In this case, we still want to continue in `session` recording mode 39765 this.recordingMode = this.session.sampled === 'buffer' && this.session.segmentId === 0 ? 'buffer' : 'session'; 39766 39767 logInfoNextTick( 39768 `[Replay] Starting replay in ${this.recordingMode} mode`, 39769 this._options._experiments.traceInternals, 39770 ); 39771 39772 this._initializeRecording(); 39773 } 39774 39775 /** 39776 * Start a replay regardless of sampling rate. Calling this will always 39777 * create a new session. Will throw an error if replay is already in progress. 39778 * 39779 * Creates or loads a session, attaches listeners to varying events (DOM, 39780 * _performanceObserver, Recording, Sentry SDK, etc) 39781 */ 39782 start() { 39783 if (this._isEnabled && this.recordingMode === 'session') { 39784 throw new Error('Replay recording is already in progress'); 39785 } 39786 39787 if (this._isEnabled && this.recordingMode === 'buffer') { 39788 throw new Error('Replay buffering is in progress, call `flush()` to save the replay'); 39789 } 39790 39791 logInfoNextTick('[Replay] Starting replay in session mode', this._options._experiments.traceInternals); 39792 39793 const session = loadOrCreateSession( 39794 { 39795 maxReplayDuration: this._options.maxReplayDuration, 39796 sessionIdleExpire: this.timeouts.sessionIdleExpire, 39797 traceInternals: this._options._experiments.traceInternals, 39798 }, 39799 { 39800 stickySession: this._options.stickySession, 39801 // This is intentional: create a new session-based replay when calling `start()` 39802 sessionSampleRate: 1, 39803 allowBuffering: false, 39804 }, 39805 ); 39806 39807 this.session = session; 39808 39809 this._initializeRecording(); 39810 } 39811 39812 /** 39813 * Start replay buffering. Buffers until `flush()` is called or, if 39814 * `replaysOnErrorSampleRate` > 0, an error occurs. 39815 */ 39816 startBuffering() { 39817 if (this._isEnabled) { 39818 throw new Error('Replay recording is already in progress'); 39819 } 39820 39821 logInfoNextTick('[Replay] Starting replay in buffer mode', this._options._experiments.traceInternals); 39822 39823 const session = loadOrCreateSession( 39824 { 39825 sessionIdleExpire: this.timeouts.sessionIdleExpire, 39826 maxReplayDuration: this._options.maxReplayDuration, 39827 traceInternals: this._options._experiments.traceInternals, 39828 }, 39829 { 39830 stickySession: this._options.stickySession, 39831 sessionSampleRate: 0, 39832 allowBuffering: true, 39833 }, 39834 ); 39835 39836 this.session = session; 39837 39838 this.recordingMode = 'buffer'; 39839 this._initializeRecording(); 39840 } 39841 39842 /** 39843 * Start recording. 39844 * 39845 * Note that this will cause a new DOM checkout 39846 */ 39847 startRecording() { 39848 try { 39849 const canvasOptions = this._canvas; 39850 39851 this._stopRecording = record({ 39852 ...this._recordingOptions, 39853 // When running in error sampling mode, we need to overwrite `checkoutEveryNms` 39854 // Without this, it would record forever, until an error happens, which we don't want 39855 // instead, we'll always keep the last 60 seconds of replay before an error happened 39856 ...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }), 39857 emit: getHandleRecordingEmit(this), 39858 onMutation: this._onMutationHandler, 39859 ...(canvasOptions 39860 ? { 39861 recordCanvas: canvasOptions.recordCanvas, 39862 getCanvasManager: canvasOptions.getCanvasManager, 39863 sampling: canvasOptions.sampling, 39864 dataURLOptions: canvasOptions.dataURLOptions, 39865 } 39866 : {}), 39867 }); 39868 } catch (err) { 39869 this._handleException(err); 39870 } 39871 } 39872 39873 /** 39874 * Stops the recording, if it was running. 39875 * 39876 * Returns true if it was previously stopped, or is now stopped, 39877 * otherwise false. 39878 */ 39879 stopRecording() { 39880 try { 39881 if (this._stopRecording) { 39882 this._stopRecording(); 39883 this._stopRecording = undefined; 39884 } 39885 39886 return true; 39887 } catch (err) { 39888 this._handleException(err); 39889 return false;
39890 } 39891 } 39892 39893 /** 39894 * Currently, this needs to be manually called (e.g. for tests). Sentry SDK 39895 * does not support a teardown 39896 */ 39897 async stop({ forceFlush = false, reason } = {}) { 39898 if (!this._isEnabled) { 39899 return; 39900 } 39901 39902 // We can't move `_isEnabled` after awaiting a flush, otherwise we can 39903 // enter into an infinite loop when `stop()` is called while flushing. 39904 this._isEnabled = false; 39905 39906 try { 39907 logInfo( 39908 `[Replay] Stopping Replay${reason ? ` triggered by ${reason}` : ''}`, 39909 this._options._experiments.traceInternals, 39910 ); 39911 39912 this._removeListeners(); 39913 this.stopRecording(); 39914 39915 this._debouncedFlush.cancel(); 39916 // See comment above re: `_isEnabled`, we "force" a flush, ignoring the 39917 // `_isEnabled` state of the plugin since it was disabled above. 39918 if (forceFlush) { 39919 await this._flush({ force: true }); 39920 } 39921 39922 // After flush, destroy event buffer 39923 this.eventBuffer && this.eventBuffer.destroy(); 39924 this.eventBuffer = null; 39925 39926 // Clear session from session storage, note this means if a new session 39927 // is started after, it will not have `previousSessionId` 39928 clearSession(this); 39929 } catch (err) { 39930 this._handleException(err); 39931 } 39932 } 39933 39934 /** 39935 * Pause some replay functionality. See comments for `_isPaused`. 39936 * This differs from stop as this only stops DOM recording, it is 39937 * not as thorough of a shutdown as `stop()`. 39938 */ 39939 pause() { 39940 if (this._isPaused) { 39941 return; 39942 } 39943 39944 this._isPaused = true; 39945 this.stopRecording(); 39946 39947 logInfo('[Replay] Pausing replay', this._options._experiments.traceInternals); 39948 } 39949 39950 /** 39951 * Resumes recording, see notes for `pause(). 39952 * 39953 * Note that calling `startRecording()` here will cause a 39954 * new DOM checkout.` 39955 */ 39956 resume() { 39957 if (!this._isPaused || !this._checkSession()) { 39958 return; 39959 } 39960 39961 this._isPaused = false; 39962 this.startRecording(); 39963 39964 logInfo('[Replay] Resuming replay', this._options._experiments.traceInternals); 39965 } 39966 39967 /** 39968 * If not in "session" recording mode, flush event buffer which will create a new replay. 39969 * Unless `continueRecording` is false, the replay will continue to record and 39970 * behave as a "session"-based replay. 39971 * 39972 * Otherwise, queue up a flush. 39973 */ 39974 async sendBufferedReplayOrFlush({ continueRecording = true } = {}) { 39975 if (this.recordingMode === 'session') { 39976 return this.flushImmediate(); 39977 } 39978 39979 const activityTime = Date.now(); 39980 39981 logInfo('[Replay] Converting buffer to session', this._options._experiments.traceInternals); 39982 39983 // Allow flush to complete before resuming as a session recording, otherwise 39984 // the checkout from `startRecording` may be included in the payload. 39985 // Prefer to keep the error replay as a separate (and smaller) segment 39986 // than the session replay. 39987 await this.flushImmediate(); 39988 39989 const hasStoppedRecording = this.stopRecording(); 39990 39991 if (!continueRecording || !hasStoppedRecording) { 39992 return; 39993 } 39994 39995 // To avoid race conditions where this is called multiple times, we check here again that we are still buffering 39996 if ((this.recordingMode ) === 'session') { 39997 return; 39998 } 39999 40000 // Re-start recording in session-mode 40001 this.recordingMode = 'session'; 40002 40003 // Once this session ends, we do not want to refresh it 40004 if (this.session) { 40005 this._updateUserActivity(activityTime); 40006 this._updateSessionActivity(activityTime); 40007 this._maybeSaveSession(); 40008 } 40009 40010 this.startRecording(); 40011 } 40012 40013 /** 40014 * We want to batch uploads of replay events. Save events only if 40015 * `<flushMinDelay>` milliseconds have elapsed since the last event 40016 * *OR* if `<flushMaxDelay>` milliseconds have elapsed. 40017 * 40018 * Accepts a callback to perform side-effects and returns true to stop batch 40019 * processing and hand back control to caller. 40020 */ 40021 addUpdate(cb) { 40022 // We need to always run `cb` (e.g. in the case of `this.recordingMode == 'buffer'`) 40023 const cbResult = cb(); 40024 40025 // If this option is turned on then we will only want to call `flush` 40026 // explicitly 40027 if (this.recordingMode === 'buffer') { 40028 return; 40029 } 40030 40031 // If callback is true, we do not want to continue with flushing -- the 40032 // caller will need to handle it. 40033 if (cbResult === true) { 40034 return; 40035 } 40036 40037 // addUpdate is called quite frequently - use _debouncedFlush so that it 40038 // respects the flush delays and does not flush immediately 40039 this._debouncedFlush(); 40040 } 40041 40042 /** 40043 * Updates the user activity timestamp and resumes recording. This should be
40044 * called in an event handler for a user action that we consider as the user 40045 * being "active" (e.g. a mouse click). 40046 */ 40047 triggerUserActivity() { 40048 this._updateUserActivity(); 40049 40050 // This case means that recording was once stopped due to inactivity. 40051 // Ensure that recording is resumed. 40052 if (!this._stopRecording) { 40053 // Create a new session, otherwise when the user action is flushed, it 40054 // will get rejected due to an expired session. 40055 if (!this._checkSession()) { 40056 return; 40057 } 40058 40059 // Note: This will cause a new DOM checkout 40060 this.resume(); 40061 return; 40062 } 40063 40064 // Otherwise... recording was never suspended, continue as normalish 40065 this.checkAndHandleExpiredSession(); 40066 40067 this._updateSessionActivity(); 40068 } 40069 40070 /** 40071 * Updates the user activity timestamp *without* resuming 40072 * recording. Some user events (e.g. keydown) can be create 40073 * low-value replays that only contain the keypress as a 40074 * breadcrumb. Instead this would require other events to 40075 * create a new replay after a session has expired. 40076 */ 40077 updateUserActivity() { 40078 this._updateUserActivity(); 40079 this._updateSessionActivity(); 40080 } 40081 40082 /** 40083 * Only flush if `this.recordingMode === 'session'` 40084 */ 40085 conditionalFlush() { 40086 if (this.recordingMode === 'buffer') { 40087 return Promise.resolve(); 40088 } 40089 40090 return this.flushImmediate(); 40091 } 40092 40093 /** 40094 * Flush using debounce flush 40095 */ 40096 flush() { 40097 return this._debouncedFlush() ; 40098 } 40099 40100 /** 40101 * Always flush via `_debouncedFlush` so that we do not have flushes triggered 40102 * from calling both `flush` and `_debouncedFlush`. Otherwise, there could be 40103 * cases of mulitple flushes happening closely together. 40104 */ 40105 flushImmediate() { 40106 this._debouncedFlush(); 40107 // `.flush` is provided by the debounced function, analogously to lodash.debounce 40108 return this._debouncedFlush.flush() ; 40109 } 40110 40111 /** 40112 * Cancels queued up flushes. 40113 */ 40114 cancelFlush() { 40115 this._debouncedFlush.cancel(); 40116 } 40117 40118 /** Get the current sesion (=replay) ID */ 40119 getSessionId() { 40120 return this.session && this.session.id; 40121 } 40122 40123 /** 40124 * Checks if recording should be stopped due to user inactivity. Otherwise 40125 * check if session is expired and create a new session if so. Triggers a new 40126 * full snapshot on new session. 40127 * 40128 * Returns true if session is not expired, false otherwise. 40129 * @hidden 40130 */ 40131 checkAndHandleExpiredSession() { 40132 // Prevent starting a new session if the last user activity is older than 40133 // SESSION_IDLE_PAUSE_DURATION. Otherwise non-user activity can trigger a new 40134 // session+recording. This creates noisy replays that do not have much 40135 // content in them. 40136 if ( 40137 this._lastActivity && 40138 isExpired(this._lastActivity, this.timeouts.sessionIdlePause) && 40139 this.session && 40140 this.session.sampled === 'session' 40141 ) { 40142 // Pause recording only for session-based replays. Otherwise, resuming 40143 // will create a new replay and will conflict with users who only choose 40144 // to record error-based replays only. (e.g. the resumed replay will not 40145 // contain a reference to an error) 40146 this.pause(); 40147 return; 40148 } 40149 40150 // --- There is recent user activity --- // 40151 // This will create a new session if expired, based on expiry length 40152 if (!this._checkSession()) { 40153 // Check session handles the refreshing itself 40154 return false; 40155 } 40156 40157 return true; 40158 } 40159 40160 /** 40161 * Capture some initial state that can change throughout the lifespan of the 40162 * replay. This is required because otherwise they would be captured at the 40163 * first flush. 40164 */ 40165 setInitialState() { 40166 const urlPath = `${WINDOW.location.pathname}${WINDOW.location.hash}${WINDOW.location.search}`; 40167 const url = `${WINDOW.location.origin}${urlPath}`; 40168 40169 this.performanceEntries = []; 40170 this.replayPerformanceEntries = []; 40171 40172 // Reset _context as well 40173 this._clearContext(); 40174 40175 this._context.initialUrl = url; 40176 this._context.initialTimestamp = Date.now(); 40177 this._context.urls.push(url); 40178 } 40179 40180 /** 40181 * Add a breadcrumb event, that may be throttled. 40182 * If it was throttled, we add a custom breadcrumb to indicate that. 40183 */ 40184 throttledAddEvent( 40185 event, 40186 isCheckout, 40187 ) { 40188 const res = this._throttledAddEvent(event, isCheckout); 40189 40190 // If this is THROTTLED, it means we have throttled the event for the first time 40191 // In this case, we want to add a breadcrumb indicating that something was skipped 40192 if (res === THROTTLED) { 40193 const breadcrumb = createBreadcrumb({ 40194 category: 'replay.throttled', 40195 }); 40196 40197 this.addUpdate(() => { 40198 // Return `false` if the event _was_ added, as that means we schedule a flush 40199 return !addEventSync(this, { 40200 type: ReplayEventTypeCustom, 40201 timestamp: breadcrumb.timestamp || 0, 40202 data: { 40203 tag: 'breadcrumb', 40204 payload: breadcrumb, 40205 metric: true, 40206 }, 40207 }); 40208 }); 40209 } 40210 40211 return res; 40212 } 40213 40214 /** 40215 * This will get the parametrized route name of the current page. 40216 * This is only available if performance is enabled, and if an instrumented router is used. 40217 */ 40218 getCurrentRoute() { 40219 // eslint-disable-next-line deprecation/deprecation 40220 const lastTransaction = this.lastTransaction || core.getCurrentScope().getTransaction(); 40221 40222 const attributes = (lastTransaction && core.spanToJSON(lastTransaction).data) || {}; 40223 const source = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]; 40224 if (!lastTransaction || !source || !['route', 'custom'].includes(source)) { 40225 return undefined; 40226 } 40227 40228 return core.spanToJSON(lastTransaction).description; 40229 } 40230 40231 /** 40232 * Initialize and start all listeners to varying events (DOM, 40233 * Performance Observer, Recording, Sentry SDK, etc) 40234 */ 40235 _initializeRecording() { 40236 this.setInitialState(); 40237 40238 // this method is generally called on page load or manually - in both cases 40239 // we should treat it as an activity 40240 this._updateSessionActivity(); 40241 40242 this.eventBuffer = createEventBuffer({ 40243 useCompression: this._options.useCompression, 40244 workerUrl: this._options.workerUrl, 40245 }); 40246 40247 this._removeListeners(); 40248 this._addListeners(); 40249 40250 // Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout 40251 this._isEnabled = true; 40252 this._isPaused = false;
40253 40254 this.startRecording(); 40255 } 40256 40257 /** A wrapper to conditionally capture exceptions. */ 40258 _handleException(error) { 40259 DEBUG_BUILD && utils.logger.error('[Replay]', error); 40260 40261 if (DEBUG_BUILD && this._options._experiments && this._options._experiments.captureExceptions) { 40262 core.captureException(error); 40263 } 40264 } 40265 40266 /** 40267 * Loads (or refreshes) the current session. 40268 */ 40269 _initializeSessionForSampling(previousSessionId) { 40270 // Whenever there is _any_ error sample rate, we always allow buffering 40271 // Because we decide on sampling when an error occurs, we need to buffer at all times if sampling for errors 40272 const allowBuffering = this._options.errorSampleRate > 0; 40273 40274 const session = loadOrCreateSession( 40275 { 40276 sessionIdleExpire: this.timeouts.sessionIdleExpire, 40277 maxReplayDuration: this._options.maxReplayDuration, 40278 traceInternals: this._options._experiments.traceInternals, 40279 previousSessionId, 40280 }, 40281 { 40282 stickySession: this._options.stickySession, 40283 sessionSampleRate: this._options.sessionSampleRate, 40284 allowBuffering, 40285 }, 40286 ); 40287 40288 this.session = session; 40289 } 40290 40291 /** 40292 * Checks and potentially refreshes the current session. 40293 * Returns false if session is not recorded. 40294 */ 40295 _checkSession() { 40296 // If there is no session yet, we do not want to refresh anything 40297 // This should generally not happen, but to be safe.... 40298 if (!this.session) { 40299 return false; 40300 } 40301 40302 const currentSession = this.session; 40303 40304 if ( 40305 shouldRefreshSession(currentSession, { 40306 sessionIdleExpire: this.timeouts.sessionIdleExpire, 40307 maxReplayDuration: this._options.maxReplayDuration, 40308 }) 40309 ) { 40310 // This should never reject 40311 // eslint-disable-next-line @typescript-eslint/no-floating-promises 40312 this._refreshSession(currentSession); 40313 return false; 40314 } 40315 40316 return true; 40317 } 40318 40319 /** 40320 * Refresh a session with a new one. 40321 * This stops the current session (without forcing a flush, as that would never work since we are expired), 40322 * and then does a new sampling based on the refreshed session. 40323 */ 40324 async _refreshSession(session) { 40325 if (!this._isEnabled) { 40326 return; 40327 } 40328 await this.stop({ reason: 'refresh session' }); 40329 this.initializeSampling(session.id); 40330 } 40331 40332 /** 40333 * Adds listeners to record events for the replay 40334 */ 40335 _addListeners() { 40336 try { 40337 WINDOW.document.addEventListener('visibilitychange', this._handleVisibilityChange); 40338 WINDOW.addEventListener('blur', this._handleWindowBlur); 40339 WINDOW.addEventListener('focus', this._handleWindowFocus); 40340 WINDOW.addEventListener('keydown', this._handleKeyboardEvent); 40341 40342 if (this.clickDetector) { 40343 this.clickDetector.addListeners(); 40344 } 40345 40346 // There is no way to remove these listeners, so ensure they are only added once 40347 if (!this._hasInitializedCoreListeners) { 40348 addGlobalListeners(this); 40349 40350 this._hasInitializedCoreListeners = true; 40351 } 40352 } catch (err) { 40353 this._handleException(err); 40354 } 40355 40356 this._performanceCleanupCallback = setupPerformanceObserver(this); 40357 } 40358 40359 /** 40360 * Cleans up listeners that were created in `_addListeners` 40361 */ 40362 _removeListeners() { 40363 try { 40364 WINDOW.document.removeEventListener('visibilitychange', this._handleVisibilityChange); 40365 40366 WINDOW.removeEventListener('blur', this._handleWindowBlur); 40367 WINDOW.removeEventListener('focus', this._handleWindowFocus); 40368 WINDOW.removeEventListener('keydown', this._handleKeyboardEvent); 40369 40370 if (this.clickDetector) { 40371 this.clickDetector.removeListeners(); 40372 } 40373 40374 if (this._performanceCleanupCallback) { 40375 this._performanceCleanupCallback(); 40376 } 40377 } catch (err) { 40378 this._handleException(err); 40379 } 40380 } 40381 40382 /** 40383 * Handle when visibility of the page content changes. Opening a new tab will 40384 * cause the state to change to hidden because of content of current page will 40385 * be hidden. Likewise, moving a different window to cover the contents of the 40386 * page will also trigger a change to a hidden state. 40387 */ 40388 __init() {this._handleVisibilityChange = () => { 40389 if (WINDOW.document.visibilityState === 'visible') { 40390 this._doChangeToForegroundTasks(); 40391 } else {
40392 this._doChangeToBackgroundTasks(); 40393 } 40394 };} 40395 40396 /** 40397 * Handle when page is blurred 40398 */ 40399 __init2() {this._handleWindowBlur = () => { 40400 const breadcrumb = createBreadcrumb({ 40401 category: 'ui.blur', 40402 }); 40403 40404 // Do not count blur as a user action -- it's part of the process of them 40405 // leaving the page 40406 this._doChangeToBackgroundTasks(breadcrumb); 40407 };} 40408 40409 /** 40410 * Handle when page is focused 40411 */ 40412 __init3() {this._handleWindowFocus = () => { 40413 const breadcrumb = createBreadcrumb({ 40414 category: 'ui.focus', 40415 }); 40416 40417 // Do not count focus as a user action -- instead wait until they focus and 40418 // interactive with page 40419 this._doChangeToForegroundTasks(breadcrumb); 40420 };} 40421 40422 /** Ensure page remains active when a key is pressed. */ 40423 __init4() {this._handleKeyboardEvent = (event) => { 40424 handleKeyboardEvent(this, event); 40425 };} 40426 40427 /** 40428 * Tasks to run when we consider a page to be hidden (via blurring and/or visibility) 40429 */ 40430 _doChangeToBackgroundTasks(breadcrumb) { 40431 if (!this.session) { 40432 return; 40433 } 40434 40435 const expired = isSessionExpired(this.session, { 40436 maxReplayDuration: this._options.maxReplayDuration, 40437 sessionIdleExpire: this.timeouts.sessionIdleExpire, 40438 }); 40439 40440 if (expired) { 40441 return; 40442 } 40443 40444 if (breadcrumb) { 40445 this._createCustomBreadcrumb(breadcrumb); 40446 } 40447 40448 // Send replay when the page/tab becomes hidden. There is no reason to send 40449 // replay if it becomes visible, since no actions we care about were done 40450 // while it was hidden 40451 // This should never reject 40452 // eslint-disable-next-line @typescript-eslint/no-floating-promises 40453 void this.conditionalFlush(); 40454 } 40455 40456 /** 40457 * Tasks to run when we consider a page to be visible (via focus and/or visibility) 40458 */ 40459 _doChangeToForegroundTasks(breadcrumb) { 40460 if (!this.session) { 40461 return; 40462 } 40463 40464 const isSessionActive = this.checkAndHandleExpiredSession(); 40465 40466 if (!isSessionActive) { 40467 // If the user has come back to the page within SESSION_IDLE_PAUSE_DURATION 40468 // ms, we will re-use the existing session, otherwise create a new 40469 // session 40470 logInfo('[Replay] Document has become active, but session has expired'); 40471 return; 40472 } 40473 40474 if (breadcrumb) { 40475 this._createCustomBreadcrumb(breadcrumb); 40476 } 40477 } 40478 40479 /** 40480 * Update user activity (across session lifespans) 40481 */ 40482 _updateUserActivity(_lastActivity = Date.now()) { 40483 this._lastActivity = _lastActivity; 40484 } 40485 40486 /** 40487 * Updates the session's last activity timestamp 40488 */ 40489 _updateSessionActivity(_lastActivity = Date.now()) { 40490 if (this.session) { 40491 this.session.lastActivity = _lastActivity; 40492 this._maybeSaveSession(); 40493 } 40494 } 40495 40496 /** 40497 * Helper to create (and buffer) a replay breadcrumb from a core SDK breadcrumb 40498 */ 40499 _createCustomBreadcrumb(breadcrumb) { 40500 this.addUpdate(() => { 40501 // This should never reject 40502 // eslint-disable-next-line @typescript-eslint/no-floating-promises 40503 this.throttledAddEvent({ 40504 type: EventType.Custom, 40505 timestamp: breadcrumb.timestamp || 0, 40506 data: { 40507 tag: 'breadcrumb', 40508 payload: breadcrumb, 40509 }, 40510 }); 40511 }); 40512 } 40513 40514 /** 40515 * Observed performance events are added to `this.performanceEntries`. These 40516 * are included in the replay event before it is finished and sent to Sentry. 40517 */ 40518 _addPerformanceEntries() { 40519 const performanceEntries = createPerformanceEntries(this.performanceEntries).concat(this.replayPerformanceEntries); 40520 40521 this.performanceEntries = []; 40522 this.replayPerformanceEntries = []; 40523 40524 return Promise.all(createPerformanceSpans(this, performanceEntries)); 40525 } 40526 40527 /** 40528 * Clear _context 40529 */ 40530 _clearContext() { 40531 // XXX: `initialTimestamp` and `initialUrl` do not get cleared 40532 this._context.errorIds.clear(); 40533 this._context.traceIds.clear(); 40534 this._context.urls = []; 40535 } 40536 40537 /** Update the initial timestamp based on the buffer content. */ 40538 _updateInitialTimestampFromEventBuffer() { 40539 const { session, eventBuffer } = this; 40540 if (!session || !eventBuffer) { 40541 return; 40542 } 40543 40544 // we only ever update this on the initial segment 40545 if (session.segmentId) { 40546 return; 40547 } 40548 40549 const earliestEvent = eventBuffer.getEarliestTimestamp();
40550 if (earliestEvent && earliestEvent < this._context.initialTimestamp) { 40551 this._context.initialTimestamp = earliestEvent; 40552 } 40553 } 40554 40555 /** 40556 * Return and clear _context 40557 */ 40558 _popEventContext() { 40559 const _context = { 40560 initialTimestamp: this._context.initialTimestamp, 40561 initialUrl: this._context.initialUrl, 40562 errorIds: Array.from(this._context.errorIds), 40563 traceIds: Array.from(this._context.traceIds), 40564 urls: this._context.urls, 40565 }; 40566 40567 this._clearContext(); 40568 40569 return _context; 40570 } 40571 40572 /** 40573 * Flushes replay event buffer to Sentry. 40574 * 40575 * Performance events are only added right before flushing - this is 40576 * due to the buffered performance observer events. 40577 * 40578 * Should never be called directly, only by `flush` 40579 */ 40580 async _runFlush() { 40581 const replayId = this.getSessionId(); 40582 40583 if (!this.session || !this.eventBuffer || !replayId) { 40584 DEBUG_BUILD && utils.logger.error('[Replay] No session or eventBuffer found to flush.'); 40585 return; 40586 } 40587 40588 await this._addPerformanceEntries(); 40589 40590 // Check eventBuffer again, as it could have been stopped in the meanwhile 40591 if (!this.eventBuffer || !this.eventBuffer.hasEvents) { 40592 return; 40593 } 40594 40595 // Only attach memory event if eventBuffer is not empty 40596 await addMemoryEntry(this); 40597 40598 // Check eventBuffer again, as it could have been stopped in the meanwhile 40599 if (!this.eventBuffer) { 40600 return; 40601 } 40602 40603 // if this changed in the meanwhile, e.g. because the session was refreshed or similar, we abort here 40604 if (replayId !== this.getSessionId()) { 40605 return; 40606 } 40607 40608 try { 40609 // This uses the data from the eventBuffer, so we need to call this before `finish() 40610 this._updateInitialTimestampFromEventBuffer(); 40611 40612 const timestamp = Date.now(); 40613 40614 // Check total duration again, to avoid sending outdated stuff 40615 // We leave 30s wiggle room to accomodate late flushing etc. 40616 // This _could_ happen when the browser is suspended during flushing, in which case we just want to stop 40617 if (timestamp - this._context.initialTimestamp > this._options.maxReplayDuration + 30000) { 40618 throw new Error('Session is too long, not sending replay'); 40619 } 40620 40621 const eventContext = this._popEventContext(); 40622 // Always increment segmentId regardless of outcome of sending replay 40623 const segmentId = this.session.segmentId++; 40624 this._maybeSaveSession(); 40625 40626 // Note this empties the event buffer regardless of outcome of sending replay 40627 const recordingData = await this.eventBuffer.finish(); 40628 40629 await sendReplay({ 40630 replayId, 40631 recordingData, 40632 segmentId, 40633 eventContext, 40634 session: this.session, 40635 options: this.getOptions(), 40636 timestamp, 40637 }); 40638 } catch (err) { 40639 this._handleException(err); 40640 40641 // This means we retried 3 times and all of them failed, 40642 // or we ran into a problem we don't want to retry, like rate limiting. 40643 // In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments 40644 // This should never reject 40645 // eslint-disable-next-line @typescript-eslint/no-floating-promises 40646 this.stop({ reason: 'sendReplay' }); 40647 40648 const client = core.getClient(); 40649 40650 if (client) { 40651 client.recordDroppedEvent('send_error', 'replay'); 40652 } 40653 } 40654 } 40655 40656 /** 40657 * Flush recording data to Sentry. Creates a lock so that only a single flush 40658 * can be active at a time. Do not call this directly. 40659 */ 40660 __init5() {this._flush = async ({ 40661 force = false, 40662 } 40663 40664 = {}) => { 40665 if (!this._isEnabled && !force) { 40666 // This can happen if e.g. the replay was stopped because of exceeding the retry limit 40667 return; 40668 } 40669 40670 if (!this.checkAndHandleExpiredSession()) { 40671 DEBUG_BUILD && utils.logger.error('[Replay] Attempting to finish replay event after session expired.'); 40672 return; 40673 } 40674 40675 if (!this.session) { 40676 // should never happen, as we would have bailed out before 40677 return; 40678 } 40679 40680 const start = this.session.started; 40681 const now = Date.now(); 40682 const duration = now - start; 40683 40684 // A flush is about to happen, cancel any queued flushes 40685 this._debouncedFlush.cancel(); 40686 40687 // If session is too short, or too long (allow some wiggle room over maxReplayDuration), do not send it 40688 // This _should_ not happen, but it may happen if flush is triggered due to a page activity change or similar 40689 const tooShort = duration < this._options.minReplayDuration; 40690 const tooLong = duration > this._options.maxReplayDuration + 5000; 40691 if (tooShort || tooLong) { 40692 logInfo( 40693 `[Replay] Session duration (${Math.floor(duration / 1000)}s) is too ${ 40694 tooShort ? 'short' : 'long' 40695 }, not sending replay.`, 40696 this._options._experiments.traceInternals, 40697 ); 40698 40699 if (tooShort) { 40700 this._debouncedFlush(); 40701 } 40702 return; 40703 } 40704 40705 const eventBuffer = this.eventBuffer; 40706 if (eventBuffer && this.session.segmentId === 0 && !eventBuffer.hasCheckout) { 40707 logInfo('[Replay] Flushing initial segment without checkout.', this._options._experiments.traceInternals); 40708 // TODO FN: Evaluate if we want to stop here, or remove this again? 40709 } 40710 40711 // this._flushLock acts as a lock so that future calls to `_flush()` 40712 // will be blocked until this promise resolves 40713 if (!this._flushLock) { 40714 this._flushLock = this._runFlush(); 40715 await this._flushLock; 40716 this._flushLock = undefined; 40717 return; 40718 } 40719 40720 // Wait for previous flush to finish, then call the debounced `_flush()`. 40721 // It's possible there are other flush requests queued and waiting for it 40722 // to resolve. We want to reduce all outstanding requests (as well as any 40723 // new flush requests that occur within a second of the locked flush 40724 // completing) into a single flush. 40725 40726 try { 40727 await this._flushLock; 40728 } catch (err) { 40729 DEBUG_BUILD && utils.logger.error(err); 40730 } finally { 40731 this._debouncedFlush(); 40732 } 40733 };} 40734 40735 /** Save the session, if it is sticky */ 40736 _maybeSaveSession() { 40737 if (this.session && this._options.stickySession) { 40738 saveSession(this.session); 40739 } 40740 } 40741 40742 /** Handler for rrweb.record.onMutation */ 40743 __init6() {this._onMutationHandler = (mutations) => { 40744 const count = mutations.length; 40745 40746 const mutationLimit = this._options.mutationLimit; 40747 const mutationBreadcrumbLimit = this._options.mutationBreadcrumbLimit; 40748 const overMutationLimit = mutationLimit && count > mutationLimit; 40749 40750 // Create a breadcrumb if a lot of mutations happen at the same time 40751 // We can show this in the UI as an information with potential performance improvements 40752 if (count > mutationBreadcrumbLimit || overMutationLimit) { 40753 const breadcrumb = createBreadcrumb({ 40754 category: 'replay.mutations', 40755 data: { 40756 count, 40757 limit: overMutationLimit, 40758 }, 40759 }); 40760 this._createCustomBreadcrumb(breadcrumb); 40761 } 40762 40763 // Stop replay if over the mutation limit 40764 if (overMutationLimit) { 40765 // This should never reject 40766 // eslint-disable-next-line @typescript-eslint/no-floating-promises 40767 this.stop({ reason: 'mutationLimit', forceFlush: this.recordingMode === 'session' }); 40768 return false;
40769 } 40770 40771 // `true` means we use the regular mutation handling by rrweb 40772 return true; 40773 };} 40774} 40775 40776function getOption( 40777 selectors, 40778 defaultSelectors, 40779 deprecatedClassOption, 40780 deprecatedSelectorOption, 40781) { 40782 const deprecatedSelectors = typeof deprecatedSelectorOption === 'string' ? deprecatedSelectorOption.split(',') : []; 40783 40784 const allSelectors = [ 40785 ...selectors, 40786 // @deprecated 40787 ...deprecatedSelectors, 40788 40789 // sentry defaults 40790 ...defaultSelectors, 40791 ]; 40792 40793 // @deprecated 40794 if (typeof deprecatedClassOption !== 'undefined') { 40795 // NOTE: No support for RegExp 40796 if (typeof deprecatedClassOption === 'string') { 40797 allSelectors.push(`.${deprecatedClassOption}`); 40798 } 40799 40800 utils.consoleSandbox(() => { 40801 // eslint-disable-next-line no-console 40802 console.warn( 40803 '[Replay] You are using a deprecated configuration item for privacy. Read the documentation on how to use the new privacy configuration.', 40804 ); 40805 }); 40806 } 40807 40808 return allSelectors.join(','); 40809} 40810 40811/** 40812 * Returns privacy related configuration for use in rrweb 40813 */ 40814function getPrivacyOptions({ 40815 mask, 40816 unmask, 40817 block, 40818 unblock, 40819 ignore, 40820 40821 // eslint-disable-next-line deprecation/deprecation 40822 blockClass, 40823 // eslint-disable-next-line deprecation/deprecation 40824 blockSelector, 40825 // eslint-disable-next-line deprecation/deprecation 40826 maskTextClass, 40827 // eslint-disable-next-line deprecation/deprecation 40828 maskTextSelector, 40829 // eslint-disable-next-line deprecation/deprecation 40830 ignoreClass, 40831}) { 40832 const defaultBlockedElements = ['base[href="/"]']; 40833 40834 const maskSelector = getOption(mask, ['.sentry-mask', '[data-sentry-mask]'], maskTextClass, maskTextSelector); 40835 const unmaskSelector = getOption(unmask, ['.sentry-unmask', '[data-sentry-unmask]']); 40836 40837 const options = { 40838 // We are making the decision to make text and input selectors the same 40839 maskTextSelector: maskSelector, 40840 unmaskTextSelector: unmaskSelector, 40841 40842 blockSelector: getOption( 40843 block, 40844 ['.sentry-block', '[data-sentry-block]', ...defaultBlockedElements], 40845 blockClass, 40846 blockSelector, 40847 ), 40848 unblockSelector: getOption(unblock, ['.sentry-unblock', '[data-sentry-unblock]']), 40849 ignoreSelector: getOption(ignore, ['.sentry-ignore', '[data-sentry-ignore]', 'input[type="file"]'], ignoreClass), 40850 }; 40851 40852 if (blockClass instanceof RegExp) { 40853 options.blockClass = blockClass; 40854 } 40855 40856 if (maskTextClass instanceof RegExp) { 40857 options.maskTextClass = maskTextClass; 40858 } 40859 40860 return options; 40861} 40862 40863/** 40864 * Masks an attribute if necessary, otherwise return attribute value as-is. 40865 */ 40866function maskAttribute({ 40867 el, 40868 key, 40869 maskAttributes, 40870 maskAllText, 40871 privacyOptions, 40872 value, 40873}) { 40874 // We only mask attributes if `maskAllText` is true 40875 if (!maskAllText) { 40876 return value; 40877 } 40878 40879 // unmaskTextSelector takes precendence 40880 if (privacyOptions.unmaskTextSelector && el.matches(privacyOptions.unmaskTextSelector)) { 40881 return value; 40882 } 40883 40884 if ( 40885 maskAttributes.includes(key) || 40886 // Need to mask `value` attribute for `<input>` if it's a button-like 40887 // type 40888 (key === 'value' && el.tagName === 'INPUT' && ['submit', 'button'].includes(el.getAttribute('type') || '')) 40889 ) { 40890 return value.replace(/[\S]/g, '*'); 40891 } 40892 40893 return value; 40894} 40895 40896const MEDIA_SELECTORS = 40897 'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]'; 40898 40899const DEFAULT_NETWORK_HEADERS = ['content-length', 'content-type', 'accept']; 40900 40901let _initialized = false; 40902 40903const replayIntegration = ((options) => { 40904 // eslint-disable-next-line deprecation/deprecation 40905 return new Replay(options); 40906}) ; 40907 40908/** 40909 * The main replay integration class, to be passed to `init({ integrations: [] })`. 40910 * @deprecated Use `replayIntegration()` instead. 40911 */ 40912class Replay { 40913 /** 40914 * @inheritDoc 40915 */ 40916 static __initStatic() {this.id = 'Replay';} 40917 40918 /** 40919 * @inheritDoc 40920 */ 40921 40922 /** 40923 * Options to pass to `rrweb.record()` 40924 */ 40925 40926 /** 40927 * Initial options passed to the replay integration, merged with default values. 40928 * Note: `sessionSampleRate` and `errorSampleRate` are not required here, as they 40929 * can only be finally set when setupOnce() is called. 40930 * 40931 * @private 40932 */ 40933
40934 constructor({ 40935 flushMinDelay = DEFAULT_FLUSH_MIN_DELAY, 40936 flushMaxDelay = DEFAULT_FLUSH_MAX_DELAY, 40937 minReplayDuration = MIN_REPLAY_DURATION, 40938 maxReplayDuration = MAX_REPLAY_DURATION, 40939 stickySession = true, 40940 useCompression = true, 40941 workerUrl, 40942 _experiments = {}, 40943 sessionSampleRate, 40944 errorSampleRate, 40945 maskAllText = true, 40946 maskAllInputs = true, 40947 blockAllMedia = true, 40948 40949 mutationBreadcrumbLimit = 750, 40950 mutationLimit = 10000, 40951 40952 slowClickTimeout = 7000, 40953 slowClickIgnoreSelectors = [], 40954 40955 networkDetailAllowUrls = [], 40956 networkDetailDenyUrls = [], 40957 networkCaptureBodies = true, 40958 networkRequestHeaders = [], 40959 networkResponseHeaders = [], 40960 40961 mask = [], 40962 maskAttributes = ['title', 'placeholder'], 40963 unmask = [], 40964 block = [], 40965 unblock = [], 40966 ignore = [], 40967 maskFn, 40968 40969 beforeAddRecordingEvent, 40970 beforeErrorSampling, 40971 40972 // eslint-disable-next-line deprecation/deprecation 40973 blockClass, 40974 // eslint-disable-next-line deprecation/deprecation 40975 blockSelector, 40976 // eslint-disable-next-line deprecation/deprecation 40977 maskInputOptions, 40978 // eslint-disable-next-line deprecation/deprecation 40979 maskTextClass, 40980 // eslint-disable-next-line deprecation/deprecation 40981 maskTextSelector, 40982 // eslint-disable-next-line deprecation/deprecation 40983 ignoreClass, 40984 } = {}) { 40985 // eslint-disable-next-line deprecation/deprecation 40986 this.name = Replay.id; 40987 40988 const privacyOptions = getPrivacyOptions({ 40989 mask, 40990 unmask, 40991 block, 40992 unblock, 40993 ignore, 40994 blockClass, 40995 blockSelector, 40996 maskTextClass, 40997 maskTextSelector, 40998 ignoreClass, 40999 }); 41000 41001 this._recordingOptions = { 41002 maskAllInputs, 41003 maskAllText, 41004 maskInputOptions: { ...(maskInputOptions || {}), password: true }, 41005 maskTextFn: maskFn, 41006 maskInputFn: maskFn, 41007 maskAttributeFn: (key, value, el) => 41008 maskAttribute({ 41009 maskAttributes, 41010 maskAllText, 41011 privacyOptions, 41012 key, 41013 value, 41014 el, 41015 }), 41016 41017 ...privacyOptions, 41018 41019 // Our defaults 41020 slimDOMOptions: 'all', 41021 inlineStylesheet: true, 41022 // Disable inline images as it will increase segment/replay size 41023 inlineImages: false, 41024 // collect fonts, but be aware that `sentry.io` needs to be an allowed 41025 // origin for playback 41026 collectFonts: true, 41027 errorHandler: (err) => { 41028 try { 41029 err.__rrweb__ = true; 41030 } catch (error) { 41031 // ignore errors here 41032 // this can happen if the error is frozen or does not allow mutation for other reasons 41033 } 41034 }, 41035 }; 41036 41037 this._initialOptions = { 41038 flushMinDelay, 41039 flushMaxDelay, 41040 minReplayDuration: Math.min(minReplayDuration, MIN_REPLAY_DURATION_LIMIT), 41041 maxReplayDuration: Math.min(maxReplayDuration, MAX_REPLAY_DURATION), 41042 stickySession, 41043 sessionSampleRate, 41044 errorSampleRate, 41045 useCompression, 41046 workerUrl, 41047 blockAllMedia, 41048 maskAllInputs, 41049 maskAllText, 41050 mutationBreadcrumbLimit, 41051 mutationLimit, 41052 slowClickTimeout, 41053 slowClickIgnoreSelectors, 41054 networkDetailAllowUrls, 41055 networkDetailDenyUrls, 41056 networkCaptureBodies, 41057 networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders), 41058 networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders), 41059 beforeAddRecordingEvent, 41060 beforeErrorSampling, 41061 41062 _experiments, 41063 }; 41064 41065 if (typeof sessionSampleRate === 'number') { 41066 // eslint-disable-next-line 41067 console.warn( 41068 `[Replay] You are passing \`sessionSampleRate\` to the Replay integration. 41069This option is deprecated and will be removed soon. 41070Instead, configure \`replaysSessionSampleRate\` directly in the SDK init options, e.g.: 41071Sentry.init({ replaysSessionSampleRate: ${sessionSampleRate} })`, 41072 ); 41073 41074 this._initialOptions.sessionSampleRate = sessionSampleRate; 41075 } 41076 41077 if (typeof errorSampleRate === 'number') { 41078 // eslint-disable-next-line 41079 console.warn( 41080 `[Replay] You are passing \`errorSampleRate\` to the Replay integration. 41081This option is deprecated and will be removed soon. 41082Instead, configure \`replaysOnErrorSampleRate\` directly in the SDK init options, e.g.: 41083Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, 41084 ); 41085 41086 this._initialOptions.errorSampleRate = errorSampleRate; 41087 } 41088 41089 if (this._initialOptions.blockAllMedia) { 41090 // `blockAllMedia` is a more user friendly option to configure blocking 41091 // embedded media elements 41092 this._recordingOptions.blockSelector = !this._recordingOptions.blockSelector 41093 ? MEDIA_SELECTORS 41094 : `${this._recordingOptions.blockSelector},${MEDIA_SELECTORS}`; 41095 } 41096 41097 if (this._isInitialized && utils.isBrowser()) { 41098 throw new Error('Multiple Sentry Session Replay instances are not supported'); 41099 } 41100 41101 this._isInitialized = true; 41102 } 41103 41104 /** If replay has already been initialized */ 41105 get _isInitialized() { 41106 return _initialized; 41107 } 41108 41109 /** Update _isInitialized */ 41110 set _isInitialized(value) { 41111 _initialized = value; 41112 } 41113 41114 /** 41115 * Setup and initialize replay container 41116 */ 41117 setupOnce() { 41118 if (!utils.isBrowser()) { 41119 return; 41120 } 41121 41122 this._setup(); 41123 41124 // Once upon a time, we tried to create a transaction in `setupOnce` and it would 41125 // potentially create a transaction before some native SDK integrations have run 41126 // and applied their own global event processor. An example is: 41127 // https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts 41128 // 41129 // So we call `this._initialize()` in next event loop as a workaround to wait for other 41130 // global event processors to finish. This is no longer needed, but keeping it 41131 // here to avoid any future issues. 41132 setTimeout(() => this._initialize()); 41133 } 41134 41135 /** 41136 * Start a replay regardless of sampling rate. Calling this will always 41137 * create a new session. Will throw an error if replay is already in progress. 41138 * 41139 * Creates or loads a session, attaches listeners to varying events (DOM, 41140 * PerformanceObserver, Recording, Sentry SDK, etc) 41141 */ 41142 start() { 41143 if (!this._replay) { 41144 return; 41145 } 41146 41147 this._replay.start(); 41148 } 41149 41150 /** 41151 * Start replay buffering. Buffers until `flush()` is called or, if 41152 * `replaysOnErrorSampleRate` > 0, until an error occurs. 41153 */
41154 startBuffering() { 41155 if (!this._replay) { 41156 return; 41157 } 41158 41159 this._replay.startBuffering(); 41160 } 41161 41162 /** 41163 * Currently, this needs to be manually called (e.g. for tests). Sentry SDK 41164 * does not support a teardown 41165 */ 41166 stop() { 41167 if (!this._replay) { 41168 return Promise.resolve(); 41169 } 41170 41171 return this._replay.stop({ forceFlush: this._replay.recordingMode === 'session' }); 41172 } 41173 41174 /** 41175 * If not in "session" recording mode, flush event buffer which will create a new replay. 41176 * Unless `continueRecording` is false, the replay will continue to record and 41177 * behave as a "session"-based replay. 41178 * 41179 * Otherwise, queue up a flush. 41180 */ 41181 flush(options) { 41182 if (!this._replay || !this._replay.isEnabled()) { 41183 return Promise.resolve(); 41184 } 41185 41186 return this._replay.sendBufferedReplayOrFlush(options); 41187 } 41188 41189 /** 41190 * Get the current session ID. 41191 */ 41192 getReplayId() { 41193 if (!this._replay || !this._replay.isEnabled()) { 41194 return; 41195 } 41196 41197 return this._replay.getSessionId(); 41198 } 41199 41200 /** 41201 * Initializes replay. 41202 */ 41203 _initialize() { 41204 if (!this._replay) { 41205 return; 41206 } 41207 41208 // We have to run this in _initialize, because this runs in setTimeout 41209 // So when this runs all integrations have been added 41210 // Before this, we cannot access integrations on the client, 41211 // so we need to mutate the options here 41212 this._maybeLoadFromReplayCanvasIntegration(); 41213 41214 this._replay.initializeSampling(); 41215 } 41216 41217 /** Setup the integration. */ 41218 _setup() { 41219 // Client is not available in constructor, so we need to wait until setupOnce 41220 const finalOptions = loadReplayOptionsFromClient(this._initialOptions); 41221 41222 this._replay = new ReplayContainer({ 41223 options: finalOptions, 41224 recordingOptions: this._recordingOptions, 41225 }); 41226 } 41227 41228 /** Get canvas options from ReplayCanvas integration, if it is also added. */ 41229 _maybeLoadFromReplayCanvasIntegration() { 41230 // To save bundle size, we skip checking for stuff here 41231 // and instead just try-catch everything - as generally this should all be defined 41232 /* eslint-disable @typescript-eslint/no-non-null-assertion */ 41233 try { 41234 const client = core.getClient(); 41235 const canvasIntegration = client.getIntegrationByName('ReplayCanvas') 41236 41237; 41238 if (!canvasIntegration) { 41239 return; 41240 } 41241 41242 this._replay['_canvas'] = canvasIntegration.getOptions(); 41243 } catch (e) { 41244 // ignore errors here 41245 } 41246 /* eslint-enable @typescript-eslint/no-non-null-assertion */ 41247 } 41248}Replay.__initStatic(); 41249 41250/** Parse Replay-related options from SDK options */ 41251function loadReplayOptionsFromClient(initialOptions) { 41252 const client = core.getClient(); 41253 const opt = client && (client.getOptions() ); 41254 41255 const finalOptions = { sessionSampleRate: 0, errorSampleRate: 0, ...utils.dropUndefinedKeys(initialOptions) }; 41256 41257 if (!opt) { 41258 utils.consoleSandbox(() => { 41259 // eslint-disable-next-line no-console 41260 console.warn('SDK client is not available.'); 41261 }); 41262 return finalOptions; 41263 } 41264 41265 if ( 41266 initialOptions.sessionSampleRate == null && // TODO remove once deprecated rates are removed 41267 initialOptions.errorSampleRate == null && // TODO remove once deprecated rates are removed 41268 opt.replaysSessionSampleRate == null && 41269 opt.replaysOnErrorSampleRate == null 41270 ) { 41271 utils.consoleSandbox(() => { 41272 // eslint-disable-next-line no-console 41273 console.warn( 41274 'Replay is disabled because neither `replaysSessionSampleRate` nor `replaysOnErrorSampleRate` are set.', 41275 ); 41276 }); 41277 } 41278 41279 if (typeof opt.replaysSessionSampleRate === 'number') { 41280 finalOptions.sessionSampleRate = opt.replaysSessionSampleRate; 41281 } 41282 41283 if (typeof opt.replaysOnErrorSampleRate === 'number') { 41284 finalOptions.errorSampleRate = opt.replaysOnErrorSampleRate; 41285 } 41286 41287 return finalOptions; 41288} 41289 41290function _getMergedNetworkHeaders(headers) { 41291 return [...DEFAULT_NETWORK_HEADERS, ...headers.map(header => header.toLowerCase())]; 41292} 41293 41294/** 41295 * This is a small utility to get a type-safe instance of the Replay integration. 41296 */ 41297// eslint-disable-next-line deprecation/deprecation 41298function getReplay() { 41299 const client = core.getClient(); 41300 return ( 41301 client && client.getIntegrationByName && client.getIntegrationByName('Replay') 41302 ); 41303} 41304 41305exports.Replay = Replay; 41306exports.getReplay = getReplay; 41307exports.replayIntegration = replayIntegration; 41308 41309 41310},{"@sentry-internal/tracing":209,"@sentry/core":250,"@sentry/utils":319}],300:[function(require,module,exports){ 41311Object.defineProperty(exports, '__esModule', { value: true }); 41312 41313const is = require('./is.js'); 41314const string = require('./string.js'); 41315 41316/** 41317 * Creates exceptions inside `event.exception.values` for errors that are nested on properties based on the `key` parameter. 41318 */ 41319function applyAggregateErrorsToEvent( 41320 exceptionFromErrorImplementation, 41321 parser, 41322 maxValueLimit = 250, 41323 key, 41324 limit, 41325 event, 41326 hint, 41327) { 41328 if (!event.exception || !event.exception.values || !hint || !is.isInstanceOf(hint.originalException, Error)) { 41329 return; 41330 } 41331 41332 // Generally speaking the last item in `event.exception.values` is the exception originating from the original Error 41333 const originalException = 41334 event.exception.values.length > 0 ? event.exception.values[event.exception.values.length - 1] : undefined; 41335 41336 // We only create exception grouping if there is an exception in the event. 41337 if (originalException) { 41338 event.exception.values = truncateAggregateExceptions( 41339 aggregateExceptionsFromError( 41340 exceptionFromErrorImplementation, 41341 parser, 41342 limit, 41343 hint.originalException , 41344 key, 41345 event.exception.values, 41346 originalException, 41347 0, 41348 ), 41349 maxValueLimit, 41350 ); 41351 } 41352} 41353 41354function aggregateExceptionsFromError( 41355 exceptionFromErrorImplementation, 41356 parser, 41357 limit, 41358 error, 41359 key, 41360 prevExceptions, 41361 exception, 41362 exceptionId, 41363) { 41364 if (prevExceptions.length >= limit + 1) { 41365 return prevExceptions; 41366 } 41367 41368 let newExceptions = [...prevExceptions]; 41369 41370 // Recursively call this function in order to walk down a chain of errors 41371 if (is.isInstanceOf(error[key], Error)) { 41372 applyExceptionGroupFieldsForParentException(exception, exceptionId); 41373 const newException = exceptionFromErrorImplementation(parser, error[key]); 41374 const newExceptionId = newExceptions.length; 41375 applyExceptionGroupFieldsForChildException(newException, key, newExceptionId, exceptionId); 41376 newExceptions = aggregateExceptionsFromError( 41377 exceptionFromErrorImplementation, 41378 parser, 41379 limit, 41380 error[key], 41381 key, 41382 [newException, ...newExceptions], 41383 newException, 41384 newExceptionId, 41385 ); 41386 } 41387 41388 // This will create exception grouping for AggregateErrors 41389 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError 41390 if (Array.isArray(error.errors)) {
41391 error.errors.forEach((childError, i) => { 41392 if (is.isInstanceOf(childError, Error)) { 41393 applyExceptionGroupFieldsForParentException(exception, exceptionId); 41394 const newException = exceptionFromErrorImplementation(parser, childError); 41395 const newExceptionId = newExceptions.length; 41396 applyExceptionGroupFieldsForChildException(newException, `errors[${i}]`, newExceptionId, exceptionId); 41397 newExceptions = aggregateExceptionsFromError( 41398 exceptionFromErrorImplementation, 41399 parser, 41400 limit, 41401 childError, 41402 key, 41403 [newException, ...newExceptions], 41404 newException, 41405 newExceptionId, 41406 ); 41407 } 41408 }); 41409 } 41410 41411 return newExceptions; 41412} 41413 41414function applyExceptionGroupFieldsForParentException(exception, exceptionId) { 41415 // Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default. 41416 exception.mechanism = exception.mechanism || { type: 'generic', handled: true }; 41417 41418 exception.mechanism = { 41419 ...exception.mechanism, 41420 ...(exception.type === 'AggregateError' && { is_exception_group: true }), 41421 exception_id: exceptionId, 41422 }; 41423} 41424 41425function applyExceptionGroupFieldsForChildException( 41426 exception, 41427 source, 41428 exceptionId, 41429 parentId, 41430) { 41431 // Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default. 41432 exception.mechanism = exception.mechanism || { type: 'generic', handled: true }; 41433 41434 exception.mechanism = { 41435 ...exception.mechanism, 41436 type: 'chained', 41437 source, 41438 exception_id: exceptionId, 41439 parent_id: parentId, 41440 }; 41441} 41442 41443/** 41444 * Truncate the message (exception.value) of all exceptions in the event. 41445 * Because this event processor is ran after `applyClientOptions`, 41446 * we need to truncate the message of the added exceptions here. 41447 */ 41448function truncateAggregateExceptions(exceptions, maxValueLength) { 41449 return exceptions.map(exception => { 41450 if (exception.value) { 41451 exception.value = string.truncate(exception.value, maxValueLength); 41452 } 41453 return exception; 41454 }); 41455} 41456 41457exports.applyAggregateErrorsToEvent = applyAggregateErrorsToEvent; 41458 41459 41460},{"./is.js":329,"./string.js":345}],301:[function(require,module,exports){ 41461Object.defineProperty(exports, '__esModule', { value: true }); 41462 41463const object = require('./object.js'); 41464const nodeStackTrace = require('./node-stack-trace.js'); 41465 41466/** 41467 * A node.js watchdog timer 41468 * @param pollInterval The interval that we expect to get polled at 41469 * @param anrThreshold The threshold for when we consider ANR 41470 * @param callback The callback to call for ANR 41471 * @returns An object with `poll` and `enabled` functions {@link WatchdogReturn} 41472 */ 41473function watchdogTimer( 41474 createTimer, 41475 pollInterval, 41476 anrThreshold, 41477 callback, 41478) { 41479 const timer = createTimer(); 41480 let triggered = false; 41481 let enabled = true; 41482 41483 setInterval(() => { 41484 const diffMs = timer.getTimeMs(); 41485 41486 if (triggered === false && diffMs > pollInterval + anrThreshold) { 41487 triggered = true; 41488 if (enabled) { 41489 callback(); 41490 } 41491 } 41492 41493 if (diffMs < pollInterval + anrThreshold) { 41494 triggered = false; 41495 } 41496 }, 20); 41497 41498 return { 41499 poll: () => { 41500 timer.reset(); 41501 }, 41502 enabled: (state) => { 41503 enabled = state; 41504 }, 41505 }; 41506} 41507 41508// types copied from inspector.d.ts 41509 41510/** 41511 * Converts Debugger.CallFrame to Sentry StackFrame 41512 */ 41513function callFrameToStackFrame( 41514 frame, 41515 url, 41516 getModuleFromFilename, 41517) { 41518 const filename = url ? url.replace(/^file:\/\//, '') : undefined; 41519 41520 // CallFrame row/col are 0 based, whereas StackFrame are 1 based 41521 const colno = frame.location.columnNumber ? frame.location.columnNumber + 1 : undefined; 41522 const lineno = frame.location.lineNumber ? frame.location.lineNumber + 1 : undefined; 41523 41524 return object.dropUndefinedKeys({ 41525 filename, 41526 module: getModuleFromFilename(filename), 41527 function: frame.functionName || '?', 41528 colno, 41529 lineno, 41530 in_app: filename ? nodeStackTrace.filenameIsInApp(filename) : undefined, 41531 }); 41532} 41533 41534exports.callFrameToStackFrame = callFrameToStackFrame; 41535exports.watchdogTimer = watchdogTimer; 41536 41537 41538},{"./node-stack-trace.js":335,"./object.js":338}],302:[function(require,module,exports){ 41539Object.defineProperty(exports, '__esModule', { value: true }); 41540 41541const debugBuild = require('./debug-build.js'); 41542const is = require('./is.js'); 41543const logger = require('./logger.js'); 41544 41545const BAGGAGE_HEADER_NAME = 'baggage'; 41546 41547const SENTRY_BAGGAGE_KEY_PREFIX = 'sentry-'; 41548 41549const SENTRY_BAGGAGE_KEY_PREFIX_REGEX = /^sentry-/; 41550 41551/**
vendor: 5,343 bytes, lines 41552-41690
41552 * Max length of a serialized baggage string 41553 * 41554 * https://www.w3.org/TR/baggage/#limits 41555 */ 41556const MAX_BAGGAGE_STRING_LENGTH = 8192; 41557 41558/** 41559 * Takes a baggage header and turns it into Dynamic Sampling Context, by extracting all the "sentry-" prefixed values 41560 * from it. 41561 * 41562 * @param baggageHeader A very bread definition of a baggage header as it might appear in various frameworks. 41563 * @returns The Dynamic Sampling Context that was found on `baggageHeader`, if there was any, `undefined` otherwise. 41564 */ 41565function baggageHeaderToDynamicSamplingContext( 41566 // Very liberal definition of what any incoming header might look like 41567 baggageHeader, 41568) { 41569 if (!is.isString(baggageHeader) && !Array.isArray(baggageHeader)) { 41570 return undefined; 41571 } 41572 41573 // Intermediary object to store baggage key value pairs of incoming baggage headers on. 41574 // It is later used to read Sentry-DSC-values from. 41575 let baggageObject = {}; 41576 41577 if (Array.isArray(baggageHeader)) { 41578 // Combine all baggage headers into one object containing the baggage values so we can later read the Sentry-DSC-values from it 41579 baggageObject = baggageHeader.reduce((acc, curr) => { 41580 const currBaggageObject = baggageHeaderToObject(curr); 41581 for (const key of Object.keys(currBaggageObject)) { 41582 acc[key] = currBaggageObject[key]; 41583 } 41584 return acc; 41585 }, {}); 41586 } else { 41587 // Return undefined if baggage header is an empty string (technically an empty baggage header is not spec conform but 41588 // this is how we choose to handle it) 41589 if (!baggageHeader) { 41590 return undefined; 41591 } 41592 41593 baggageObject = baggageHeaderToObject(baggageHeader); 41594 } 41595 41596 // Read all "sentry-" prefixed values out of the baggage object and put it onto a dynamic sampling context object. 41597 const dynamicSamplingContext = Object.entries(baggageObject).reduce((acc, [key, value]) => { 41598 if (key.match(SENTRY_BAGGAGE_KEY_PREFIX_REGEX)) { 41599 const nonPrefixedKey = key.slice(SENTRY_BAGGAGE_KEY_PREFIX.length); 41600 acc[nonPrefixedKey] = value; 41601 } 41602 return acc; 41603 }, {}); 41604 41605 // Only return a dynamic sampling context object if there are keys in it. 41606 // A keyless object means there were no sentry values on the header, which means that there is no DSC. 41607 if (Object.keys(dynamicSamplingContext).length > 0) { 41608 return dynamicSamplingContext ; 41609 } else { 41610 return undefined; 41611 } 41612} 41613 41614/** 41615 * Turns a Dynamic Sampling Object into a baggage header by prefixing all the keys on the object with "sentry-". 41616 * 41617 * @param dynamicSamplingContext The Dynamic Sampling Context to turn into a header. For convenience and compatibility 41618 * with the `getDynamicSamplingContext` method on the Transaction class ,this argument can also be `undefined`. If it is 41619 * `undefined` the function will return `undefined`. 41620 * @returns a baggage header, created from `dynamicSamplingContext`, or `undefined` either if `dynamicSamplingContext` 41621 * was `undefined`, or if `dynamicSamplingContext` didn't contain any values. 41622 */ 41623function dynamicSamplingContextToSentryBaggageHeader( 41624 // this also takes undefined for convenience and bundle size in other places 41625 dynamicSamplingContext, 41626) { 41627 if (!dynamicSamplingContext) { 41628 return undefined; 41629 } 41630 41631 // Prefix all DSC keys with "sentry-" and put them into a new object 41632 const sentryPrefixedDSC = Object.entries(dynamicSamplingContext).reduce( 41633 (acc, [dscKey, dscValue]) => { 41634 if (dscValue) { 41635 acc[`${SENTRY_BAGGAGE_KEY_PREFIX}${dscKey}`] = dscValue; 41636 } 41637 return acc; 41638 }, 41639 {}, 41640 ); 41641 41642 return objectToBaggageHeader(sentryPrefixedDSC); 41643} 41644 41645/** 41646 * Will parse a baggage header, which is a simple key-value map, into a flat object. 41647 * 41648 * @param baggageHeader The baggage header to parse. 41649 * @returns a flat object containing all the key-value pairs from `baggageHeader`. 41650 */ 41651function baggageHeaderToObject(baggageHeader) { 41652 return baggageHeader 41653 .split(',') 41654 .map(baggageEntry => baggageEntry.split('=').map(keyOrValue => decodeURIComponent(keyOrValue.trim()))) 41655 .reduce((acc, [key, value]) => { 41656 acc[key] = value; 41657 return acc; 41658 }, {}); 41659} 41660 41661/** 41662 * Turns a flat object (key-value pairs) into a baggage header, which is also just key-value pairs. 41663 * 41664 * @param object The object to turn into a baggage header. 41665 * @returns a baggage header string, or `undefined` if the object didn't have any values, since an empty baggage header 41666 * is not spec compliant. 41667 */ 41668function objectToBaggageHeader(object) { 41669 if (Object.keys(object).length === 0) { 41670 // An empty baggage header is not spec compliant: We return undefined. 41671 return undefined; 41672 } 41673 41674 return Object.entries(object).reduce((baggageHeader, [objectKey, objectValue], currentIndex) => { 41675 const baggageEntry = `${encodeURIComponent(objectKey)}=${encodeURIComponent(objectValue)}`; 41676 const newBaggageHeader = currentIndex === 0 ? baggageEntry : `${baggageHeader},${baggageEntry}`; 41677 if (newBaggageHeader.length > MAX_BAGGAGE_STRING_LENGTH) { 41678 debugBuild.DEBUG_BUILD && 41679 logger.logger.warn( 41680 `Not adding key: ${objectKey} with val: ${objectValue} to baggage header due to exceeding baggage size limits.`, 41681 ); 41682 return baggageHeader; 41683 } else { 41684 return newBaggageHeader; 41685 } 41686 }, ''); 41687} 41688 41689exports.BAGGAGE_HEADER_NAME = BAGGAGE_HEADER_NAME; 41690exports.MAX_BAGGAGE_STRING_LENGTH = MAX_BAGGAGE_STRING_LENGTH;
41691exports.SENTRY_BAGGAGE_KEY_PREFIX = SENTRY_BAGGAGE_KEY_PREFIX; 41692exports.SENTRY_BAGGAGE_KEY_PREFIX_REGEX = SENTRY_BAGGAGE_KEY_PREFIX_REGEX; 41693exports.baggageHeaderToDynamicSamplingContext = baggageHeaderToDynamicSamplingContext; 41694exports.dynamicSamplingContextToSentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader; 41695 41696 41697},{"./debug-build.js":313,"./is.js":329,"./logger.js":331}],303:[function(require,module,exports){ 41698Object.defineProperty(exports, '__esModule', { value: true }); 41699 41700const is = require('./is.js'); 41701const worldwide = require('./worldwide.js'); 41702 41703// eslint-disable-next-line deprecation/deprecation 41704const WINDOW = worldwide.getGlobalObject(); 41705 41706const DEFAULT_MAX_STRING_LENGTH = 80; 41707 41708/** 41709 * Given a child DOM element, returns a query-selector statement describing that 41710 * and its ancestors 41711 * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz] 41712 * @returns generated DOM path 41713 */ 41714function htmlTreeAsString( 41715 elem, 41716 options = {}, 41717) { 41718 if (!elem) { 41719 return '<unknown>'; 41720 } 41721 41722 // try/catch both: 41723 // - accessing event.target (see getsentry/raven-js#838, #768) 41724 // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly 41725 // - can throw an exception in some circumstances. 41726 try {
vendor: 5,405 bytes, lines 41727-41907
41727 let currentElem = elem ; 41728 const MAX_TRAVERSE_HEIGHT = 5; 41729 const out = []; 41730 let height = 0; 41731 let len = 0; 41732 const separator = ' > '; 41733 const sepLength = separator.length; 41734 let nextStr; 41735 const keyAttrs = Array.isArray(options) ? options : options.keyAttrs; 41736 const maxStringLength = (!Array.isArray(options) && options.maxStringLength) || DEFAULT_MAX_STRING_LENGTH; 41737 41738 while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) { 41739 nextStr = _htmlElementAsString(currentElem, keyAttrs); 41740 // bail out if 41741 // - nextStr is the 'html' element 41742 // - the length of the string that would be created exceeds maxStringLength 41743 // (ignore this limit if we are on the first iteration) 41744 if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= maxStringLength)) { 41745 break; 41746 } 41747 41748 out.push(nextStr); 41749 41750 len += nextStr.length; 41751 currentElem = currentElem.parentNode; 41752 } 41753 41754 return out.reverse().join(separator); 41755 } catch (_oO) { 41756 return '<unknown>'; 41757 } 41758} 41759 41760/** 41761 * Returns a simple, query-selector representation of a DOM element 41762 * e.g. [HTMLElement] => input#foo.btn[name=baz] 41763 * @returns generated DOM path 41764 */ 41765function _htmlElementAsString(el, keyAttrs) { 41766 const elem = el 41767 41768; 41769 41770 const out = []; 41771 let className; 41772 let classes; 41773 let key; 41774 let attr; 41775 let i; 41776 41777 if (!elem || !elem.tagName) { 41778 return ''; 41779 } 41780 41781 // @ts-expect-error WINDOW has HTMLElement 41782 if (WINDOW.HTMLElement) { 41783 // If using the component name annotation plugin, this value may be available on the DOM node 41784 if (elem instanceof HTMLElement && elem.dataset && elem.dataset['sentryComponent']) { 41785 return elem.dataset['sentryComponent']; 41786 } 41787 } 41788 41789 out.push(elem.tagName.toLowerCase()); 41790 41791 // Pairs of attribute keys defined in `serializeAttribute` and their values on element. 41792 const keyAttrPairs = 41793 keyAttrs && keyAttrs.length 41794 ? keyAttrs.filter(keyAttr => elem.getAttribute(keyAttr)).map(keyAttr => [keyAttr, elem.getAttribute(keyAttr)]) 41795 : null; 41796 41797 if (keyAttrPairs && keyAttrPairs.length) { 41798 keyAttrPairs.forEach(keyAttrPair => { 41799 out.push(`[${keyAttrPair[0]}="${keyAttrPair[1]}"]`); 41800 }); 41801 } else { 41802 if (elem.id) { 41803 out.push(`#${elem.id}`); 41804 } 41805 41806 // eslint-disable-next-line prefer-const 41807 className = elem.className; 41808 if (className && is.isString(className)) { 41809 classes = className.split(/\s+/); 41810 for (i = 0; i < classes.length; i++) { 41811 out.push(`.${classes[i]}`); 41812 } 41813 } 41814 } 41815 const allowedAttrs = ['aria-label', 'type', 'name', 'title', 'alt']; 41816 for (i = 0; i < allowedAttrs.length; i++) { 41817 key = allowedAttrs[i]; 41818 attr = elem.getAttribute(key); 41819 if (attr) { 41820 out.push(`[${key}="${attr}"]`); 41821 } 41822 } 41823 return out.join(''); 41824} 41825 41826/** 41827 * A safe form of location.href 41828 */ 41829function getLocationHref() { 41830 try { 41831 return WINDOW.document.location.href; 41832 } catch (oO) { 41833 return ''; 41834 } 41835} 41836 41837/** 41838 * Gets a DOM element by using document.querySelector. 41839 * 41840 * This wrapper will first check for the existance of the function before 41841 * actually calling it so that we don't have to take care of this check, 41842 * every time we want to access the DOM. 41843 * 41844 * Reason: DOM/querySelector is not available in all environments. 41845 * 41846 * We have to cast to any because utils can be consumed by a variety of environments, 41847 * and we don't want to break TS users. If you know what element will be selected by 41848 * `document.querySelector`, specify it as part of the generic call. For example, 41849 * `const element = getDomElement<Element>('selector');` 41850 * 41851 * @param selector the selector string passed on to document.querySelector 41852 */ 41853// eslint-disable-next-line @typescript-eslint/no-explicit-any 41854function getDomElement(selector) { 41855 if (WINDOW.document && WINDOW.document.querySelector) { 41856 return WINDOW.document.querySelector(selector) ; 41857 } 41858 return null; 41859} 41860 41861/** 41862 * Given a DOM element, traverses up the tree until it finds the first ancestor node 41863 * that has the `data-sentry-component` attribute. This attribute is added at build-time 41864 * by projects that have the component name annotation plugin installed. 41865 * 41866 * @returns a string representation of the component for the provided DOM element, or `null` if not found 41867 */ 41868function getComponentName(elem) { 41869 // @ts-expect-error WINDOW has HTMLElement 41870 if (!WINDOW.HTMLElement) { 41871 return null; 41872 } 41873 41874 let currentElem = elem ; 41875 const MAX_TRAVERSE_HEIGHT = 5; 41876 for (let i = 0; i < MAX_TRAVERSE_HEIGHT; i++) { 41877 if (!currentElem) { 41878 return null; 41879 } 41880 41881 if (currentElem instanceof HTMLElement && currentElem.dataset['sentryComponent']) { 41882 return currentElem.dataset['sentryComponent']; 41883 } 41884 41885 currentElem = currentElem.parentNode; 41886 } 41887 41888 return null; 41889} 41890 41891exports.getComponentName = getComponentName; 41892exports.getDomElement = getDomElement; 41893exports.getLocationHref = getLocationHref; 41894exports.htmlTreeAsString = htmlTreeAsString; 41895 41896 41897},{"./is.js":329,"./worldwide.js":354}],304:[function(require,module,exports){ 41898Object.defineProperty(exports, '__esModule', { value: true }); 41899 41900const _nullishCoalesce = require('./_nullishCoalesce.js'); 41901 41902// https://github.com/alangpierce/sucrase/tree/265887868966917f3b924ce38dfad01fbab1329f 41903 41904/** 41905 * Polyfill for the nullish coalescing operator (`??`), when used in situations where at least one of the values is the 41906 * result of an async operation. 41907 *
41908 * Note that the RHS is wrapped in a function so that if it's a computed value, that evaluation won't happen unless the 41909 * LHS evaluates to a nullish value, to mimic the operator's short-circuiting behavior. 41910 * 41911 * Adapted from Sucrase (https://github.com/alangpierce/sucrase) 41912 * 41913 * @param lhs The value of the expression to the left of the `??` 41914 * @param rhsFn A function returning the value of the expression to the right of the `??` 41915 * @returns The LHS value, unless it's `null` or `undefined`, in which case, the RHS value 41916 */ 41917async function _asyncNullishCoalesce(lhs, rhsFn) { 41918 return _nullishCoalesce._nullishCoalesce(lhs, rhsFn); 41919} 41920 41921// Sucrase version: 41922// async function _asyncNullishCoalesce(lhs, rhsFn) { 41923// if (lhs != null) { 41924// return lhs; 41925// } else { 41926// return await rhsFn(); 41927// } 41928// } 41929 41930exports._asyncNullishCoalesce = _asyncNullishCoalesce; 41931 41932 41933},{"./_nullishCoalesce.js":307}],305:[function(require,module,exports){ 41934Object.defineProperty(exports, '__esModule', { value: true }); 41935 41936/** 41937 * Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values, 41938 * descriptors, and functions, for situations in which at least one part of the expression is async. 41939 * 41940 * Adapted from Sucrase (https://github.com/alangpierce/sucrase) See 41941 * https://github.com/alangpierce/sucrase/blob/265887868966917f3b924ce38dfad01fbab1329f/src/transformers/OptionalChainingNullishTransformer.ts#L15 41942 * 41943 * @param ops Array result of expression conversion 41944 * @returns The value of the expression 41945 */ 41946async function _asyncOptionalChain(ops) { 41947 let lastAccessLHS = undefined; 41948 let value = ops[0]; 41949 let i = 1; 41950 while (i < ops.length) { 41951 const op = ops[i] ; 41952 const fn = ops[i + 1] ; 41953 i += 2; 41954 // by checking for loose equality to `null`, we catch both `null` and `undefined` 41955 if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { 41956 // really we're meaning to return `undefined` as an actual value here, but it saves bytes not to write it 41957 return; 41958 } 41959 if (op === 'access' || op === 'optionalAccess') { 41960 lastAccessLHS = value; 41961 value = await fn(value); 41962 } else if (op === 'call' || op === 'optionalCall') { 41963 value = await fn((...args) => (value ).call(lastAccessLHS, ...args)); 41964 lastAccessLHS = undefined; 41965 } 41966 } 41967 return value; 41968} 41969 41970// Sucrase version: 41971// async function _asyncOptionalChain(ops) { 41972// let lastAccessLHS = undefined; 41973// let value = ops[0]; 41974// let i = 1; 41975// while (i < ops.length) { 41976// const op = ops[i]; 41977// const fn = ops[i + 1]; 41978// i += 2; 41979// if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { 41980// return undefined; 41981// } 41982// if (op === 'access' || op === 'optionalAccess') { 41983// lastAccessLHS = value; 41984// value = await fn(value); 41985// } else if (op === 'call' || op === 'optionalCall') { 41986// value = await fn((...args) => value.call(lastAccessLHS, ...args)); 41987// lastAccessLHS = undefined; 41988// } 41989// } 41990// return value; 41991// } 41992 41993exports._asyncOptionalChain = _asyncOptionalChain; 41994 41995 41996},{}],306:[function(require,module,exports){ 41997Object.defineProperty(exports, '__esModule', { value: true }); 41998 41999const _asyncOptionalChain = require('./_asyncOptionalChain.js'); 42000 42001// https://github.com/alangpierce/sucrase/tree/265887868966917f3b924ce38dfad01fbab1329f 42002 42003/** 42004 * Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values, 42005 * descriptors, and functions, in cases where the value of the expression is to be deleted. 42006 * 42007 * Adapted from Sucrase (https://github.com/alangpierce/sucrase) See 42008 * https://github.com/alangpierce/sucrase/blob/265887868966917f3b924ce38dfad01fbab1329f/src/transformers/OptionalChainingNullishTransformer.ts#L15 42009 * 42010 * @param ops Array result of expression conversion 42011 * @returns The return value of the `delete` operator: `true`, unless the deletion target is an own, non-configurable 42012 * property (one which can't be deleted or turned into an accessor, and whose enumerability can't be changed), in which 42013 * case `false`. 42014 */ 42015async function _asyncOptionalChainDelete(ops) { 42016 const result = (await _asyncOptionalChain._asyncOptionalChain(ops)) ; 42017 // If `result` is `null`, it means we didn't get to the end of the chain and so nothing was deleted (in which case, 42018 // return `true` since that's what `delete` does when it no-ops). If it's non-null, we know the delete happened, in 42019 // which case we return whatever the `delete` returned, which will be a boolean. 42020 return result == null ? true : (result ); 42021} 42022 42023// Sucrase version: 42024// async function asyncOptionalChainDelete(ops) { 42025// const result = await ASYNC_OPTIONAL_CHAIN_NAME(ops); 42026// return result == null ? true : result; 42027// } 42028 42029exports._asyncOptionalChainDelete = _asyncOptionalChainDelete; 42030 42031 42032},{"./_asyncOptionalChain.js":305}],307:[function(require,module,exports){ 42033Object.defineProperty(exports, '__esModule', { value: true }); 42034 42035// https://github.com/alangpierce/sucrase/tree/265887868966917f3b924ce38dfad01fbab1329f 42036// 42037// The MIT License (MIT) 42038// 42039// Copyright (c) 2012-2018 various contributors (see AUTHORS) 42040// 42041// Permission is hereby granted, free of charge, to any person obtaining a copy 42042// of this software and associated documentation files (the "Software"), to deal 42043// in the Software without restriction, including without limitation the rights 42044// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 42045// copies of the Software, and to permit persons to whom the Software is 42046// furnished to do so, subject to the following conditions: 42047// 42048// The above copyright notice and this permission notice shall be included in all 42049// copies or substantial portions of the Software. 42050// 42051// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42052// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42053// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 42054// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42055// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42056// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 42057// SOFTWARE. 42058 42059/** 42060 * Polyfill for the nullish coalescing operator (`??`). 42061 * 42062 * Note that the RHS is wrapped in a function so that if it's a computed value, that evaluation won't happen unless the 42063 * LHS evaluates to a nullish value, to mimic the operator's short-circuiting behavior. 42064 * 42065 * Adapted from Sucrase (https://github.com/alangpierce/sucrase) 42066 * 42067 * @param lhs The value of the expression to the left of the `??` 42068 * @param rhsFn A function returning the value of the expression to the right of the `??` 42069 * @returns The LHS value, unless it's `null` or `undefined`, in which case, the RHS value 42070 */ 42071function _nullishCoalesce(lhs, rhsFn) { 42072 // by checking for loose equality to `null`, we catch both `null` and `undefined` 42073 return lhs != null ? lhs : rhsFn(); 42074} 42075 42076// Sucrase version: 42077// function _nullishCoalesce(lhs, rhsFn) { 42078// if (lhs != null) { 42079// return lhs; 42080// } else { 42081// return rhsFn(); 42082// } 42083// } 42084 42085exports._nullishCoalesce = _nullishCoalesce; 42086 42087 42088},{}],308:[function(require,module,exports){ 42089Object.defineProperty(exports, '__esModule', { value: true }); 42090 42091/** 42092 * Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values, 42093 * descriptors, and functions. 42094 * 42095 * Adapted from Sucrase (https://github.com/alangpierce/sucrase) 42096 * See https://github.com/alangpierce/sucrase/blob/265887868966917f3b924ce38dfad01fbab1329f/src/transformers/OptionalChainingNullishTransformer.ts#L15 42097 * 42098 * @param ops Array result of expression conversion 42099 * @returns The value of the expression 42100 */ 42101function _optionalChain(ops) { 42102 let lastAccessLHS = undefined; 42103 let value = ops[0]; 42104 let i = 1; 42105 while (i < ops.length) { 42106 const op = ops[i] ; 42107 const fn = ops[i + 1] ; 42108 i += 2; 42109 // by checking for loose equality to `null`, we catch both `null` and `undefined` 42110 if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { 42111 // really we're meaning to return `undefined` as an actual value here, but it saves bytes not to write it 42112 return; 42113 } 42114 if (op === 'access' || op === 'optionalAccess') { 42115 lastAccessLHS = value; 42116 value = fn(value); 42117 } else if (op === 'call' || op === 'optionalCall') { 42118 value = fn((...args) => (value ).call(lastAccessLHS, ...args)); 42119 lastAccessLHS = undefined; 42120 } 42121 } 42122 return value; 42123} 42124 42125// Sucrase version 42126// function _optionalChain(ops) { 42127// let lastAccessLHS = undefined; 42128// let value = ops[0]; 42129// let i = 1; 42130// while (i < ops.length) { 42131// const op = ops[i]; 42132// const fn = ops[i + 1]; 42133// i += 2; 42134// if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { 42135// return undefined; 42136// } 42137// if (op === 'access' || op === 'optionalAccess') { 42138// lastAccessLHS = value; 42139// value = fn(value); 42140// } else if (op === 'call' || op === 'optionalCall') { 42141// value = fn((...args) => value.call(lastAccessLHS, ...args)); 42142// lastAccessLHS = undefined; 42143// } 42144// } 42145// return value; 42146// } 42147 42148exports._optionalChain = _optionalChain; 42149 42150 42151},{}],309:[function(require,module,exports){ 42152Object.defineProperty(exports, '__esModule', { value: true }); 42153 42154const _optionalChain = require('./_optionalChain.js'); 42155 42156// https://github.com/alangpierce/sucrase/tree/265887868966917f3b924ce38dfad01fbab1329f 42157 42158/** 42159 * Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values, 42160 * descriptors, and functions, in cases where the value of the expression is to be deleted. 42161 * 42162 * Adapted from Sucrase (https://github.com/alangpierce/sucrase) See 42163 * https://github.com/alangpierce/sucrase/blob/265887868966917f3b924ce38dfad01fbab1329f/src/transformers/OptionalChainingNullishTransformer.ts#L15 42164 * 42165 * @param ops Array result of expression conversion 42166 * @returns The return value of the `delete` operator: `true`, unless the deletion target is an own, non-configurable 42167 * property (one which can't be deleted or turned into an accessor, and whose enumerability can't be changed), in which 42168 * case `false`. 42169 */ 42170function _optionalChainDelete(ops) { 42171 const result = _optionalChain._optionalChain(ops) ; 42172 // If `result` is `null`, it means we didn't get to the end of the chain and so nothing was deleted (in which case, 42173 // return `true` since that's what `delete` does when it no-ops). If it's non-null, we know the delete happened, in 42174 // which case we return whatever the `delete` returned, which will be a boolean. 42175 return result == null ? true : result; 42176} 42177 42178// Sucrase version: 42179// function _optionalChainDelete(ops) { 42180// const result = _optionalChain(ops); 42181// // by checking for loose equality to `null`, we catch both `null` and `undefined` 42182// return result == null ? true : result; 42183// } 42184 42185exports._optionalChainDelete = _optionalChainDelete; 42186 42187 42188},{"./_optionalChain.js":308}],310:[function(require,module,exports){ 42189Object.defineProperty(exports, '__esModule', { value: true }); 42190 42191/** 42192 * Creates a cache that evicts keys in fifo order 42193 * @param size {Number} 42194 */ 42195function makeFifoCache( 42196 size, 42197) 42198 42199 { 42200 // Maintain a fifo queue of keys, we cannot rely on Object.keys as the browser may not support it. 42201 let evictionOrder = []; 42202 let cache = {}; 42203 42204 return { 42205 add(key, value) { 42206 while (evictionOrder.length >= size) { 42207 // shift is O(n) but this is small size and only happens if we are 42208 // exceeding the cache size so it should be fine. 42209 const evictCandidate = evictionOrder.shift(); 42210 42211 if (evictCandidate !== undefined) { 42212 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 42213 delete cache[evictCandidate]; 42214 } 42215 } 42216 42217 // in case we have a collision, delete the old key. 42218 if (cache[key]) { 42219 this.delete(key); 42220 } 42221 42222 evictionOrder.push(key); 42223 cache[key] = value; 42224 }, 42225 clear() { 42226 cache = {}; 42227 evictionOrder = []; 42228 }, 42229 get(key) { 42230 return cache[key]; 42231 }, 42232 size() { 42233 return evictionOrder.length; 42234 }, 42235 // Delete cache key and return true if it existed, false otherwise. 42236 delete(key) { 42237 if (!cache[key]) { 42238 return false;
42239 } 42240 42241 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete 42242 delete cache[key]; 42243 42244 for (let i = 0; i < evictionOrder.length; i++) { 42245 if (evictionOrder[i] === key) { 42246 evictionOrder.splice(i, 1); 42247 break; 42248 } 42249 } 42250 42251 return true; 42252 }, 42253 }; 42254} 42255 42256exports.makeFifoCache = makeFifoCache; 42257 42258 42259},{}],311:[function(require,module,exports){ 42260Object.defineProperty(exports, '__esModule', { value: true }); 42261 42262const envelope = require('./envelope.js'); 42263const time = require('./time.js'); 42264 42265/** 42266 * Creates client report envelope 42267 * @param discarded_events An array of discard events 42268 * @param dsn A DSN that can be set on the header. Optional. 42269 */ 42270function createClientReportEnvelope( 42271 discarded_events, 42272 dsn, 42273 timestamp, 42274) { 42275 const clientReportItem = [ 42276 { type: 'client_report' }, 42277 { 42278 timestamp: timestamp || time.dateTimestampInSeconds(), 42279 discarded_events, 42280 }, 42281 ]; 42282 return envelope.createEnvelope(dsn ? { dsn } : {}, [clientReportItem]); 42283} 42284 42285exports.createClientReportEnvelope = createClientReportEnvelope; 42286 42287 42288},{"./envelope.js":316,"./time.js":348}],312:[function(require,module,exports){ 42289Object.defineProperty(exports, '__esModule', { value: true }); 42290 42291/** 42292 * This code was originally copied from the 'cookie` module at v0.5.0 and was simplified for our use case. 42293 * https://github.com/jshttp/cookie/blob/a0c84147aab6266bdb3996cf4062e93907c0b0fc/index.js 42294 * It had the following license: 42295 * 42296 * (The MIT License) 42297 * 42298 * Copyright (c) 2012-2014 Roman Shtylman <[email protected]> 42299 * Copyright (c) 2015 Douglas Christopher Wilson <[email protected]> 42300 * 42301 * Permission is hereby granted, free of charge, to any person obtaining 42302 * a copy of this software and associated documentation files (the 42303 * 'Software'), to deal in the Software without restriction, including 42304 * without limitation the rights to use, copy, modify, merge, publish, 42305 * distribute, sublicense, and/or sell copies of the Software, and to 42306 * permit persons to whom the Software is furnished to do so, subject to 42307 * the following conditions: 42308 * 42309 * The above copyright notice and this permission notice shall be 42310 * included in all copies or substantial portions of the Software. 42311 * 42312 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 42313 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 42314 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 42315 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 42316 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 42317 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 42318 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 42319 */ 42320 42321/** 42322 * Parses a cookie string 42323 */ 42324function parseCookie(str) { 42325 const obj = {}; 42326 let index = 0; 42327 42328 while (index < str.length) { 42329 const eqIdx = str.indexOf('=', index); 42330 42331 // no more cookie pairs 42332 if (eqIdx === -1) { 42333 break; 42334 } 42335 42336 let endIdx = str.indexOf(';', index); 42337 42338 if (endIdx === -1) { 42339 endIdx = str.length; 42340 } else if (endIdx < eqIdx) { 42341 // backtrack on prior semicolon 42342 index = str.lastIndexOf(';', eqIdx - 1) + 1; 42343 continue; 42344 } 42345 42346 const key = str.slice(index, eqIdx).trim(); 42347 42348 // only assign once 42349 if (undefined === obj[key]) { 42350 let val = str.slice(eqIdx + 1, endIdx).trim(); 42351 42352 // quoted values 42353 if (val.charCodeAt(0) === 0x22) { 42354 val = val.slice(1, -1); 42355 } 42356 42357 try { 42358 obj[key] = val.indexOf('%') !== -1 ? decodeURIComponent(val) : val; 42359 } catch (e) { 42360 obj[key] = val; 42361 } 42362 } 42363 42364 index = endIdx + 1; 42365 } 42366 42367 return obj; 42368} 42369 42370exports.parseCookie = parseCookie; 42371 42372 42373},{}],313:[function(require,module,exports){ 42374arguments[4][206][0].apply(exports,arguments) 42375},{"dup":206}],314:[function(require,module,exports){ 42376Object.defineProperty(exports, '__esModule', { value: true }); 42377 42378const debugBuild = require('./debug-build.js'); 42379const logger = require('./logger.js'); 42380 42381/** Regular expression used to parse a Dsn. */ 42382const DSN_REGEX = /^(?:(\w+):)\/\/(?:(\w+)(?::(\w+)?)?@)([\w.-]+)(?::(\d+))?\/(.+)/; 42383 42384function isValidProtocol(protocol) { 42385 return protocol === 'http' || protocol === 'https'; 42386} 42387 42388/** 42389 * Renders the string representation of this Dsn. 42390 * 42391 * By default, this will render the public representation without the password 42392 * component. To get the deprecated private representation, set `withPassword` 42393 * to true. 42394 * 42395 * @param withPassword When set to true, the password will be included. 42396 */ 42397function dsnToString(dsn, withPassword = false) { 42398 const { host, path, pass, port, projectId, protocol, publicKey } = dsn; 42399 return ( 42400 `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ''}` + 42401 `@${host}${port ? `:${port}` : ''}/${path ? `${path}/` : path}${projectId}` 42402 ); 42403} 42404 42405/** 42406 * Parses a Dsn from a given string. 42407 * 42408 * @param str A Dsn as string 42409 * @returns Dsn as DsnComponents or undefined if @param str is not a valid DSN string 42410 */ 42411function dsnFromString(str) { 42412 const match = DSN_REGEX.exec(str); 42413 42414 if (!match) { 42415 // This should be logged to the console 42416 logger.consoleSandbox(() => { 42417 // eslint-disable-next-line no-console 42418 console.error(`Invalid Sentry Dsn: ${str}`); 42419 }); 42420 return undefined; 42421 } 42422 42423 const [protocol, publicKey, pass = '', host, port = '', lastPath] = match.slice(1); 42424 let path = ''; 42425 let projectId = lastPath; 42426 42427 const split = projectId.split('/'); 42428 if (split.length > 1) { 42429 path = split.slice(0, -1).join('/'); 42430 projectId = split.pop() ; 42431 } 42432 42433 if (projectId) { 42434 const projectMatch = projectId.match(/^\d+/); 42435 if (projectMatch) { 42436 projectId = projectMatch[0]; 42437 } 42438 } 42439 42440 return dsnFromComponents({ host, pass, path, projectId, port, protocol: protocol , publicKey }); 42441} 42442 42443function dsnFromComponents(components) { 42444 return { 42445 protocol: components.protocol, 42446 publicKey: components.publicKey || '', 42447 pass: components.pass || '', 42448 host: components.host, 42449 port: components.port || '', 42450 path: components.path || '', 42451 projectId: components.projectId, 42452 }; 42453} 42454 42455function validateDsn(dsn) { 42456 if (!debugBuild.DEBUG_BUILD) { 42457 return true; 42458 } 42459 42460 const { port, projectId, protocol }
42460 = dsn; 42461 42462 const requiredComponents = ['protocol', 'publicKey', 'host', 'projectId']; 42463 const hasMissingRequiredComponent = requiredComponents.find(component => { 42464 if (!dsn[component]) { 42465 logger.logger.error(`Invalid Sentry Dsn: ${component} missing`); 42466 return true; 42467 } 42468 return false; 42469 }); 42470 42471 if (hasMissingRequiredComponent) { 42472 return false; 42473 } 42474 42475 if (!projectId.match(/^\d+$/)) { 42476 logger.logger.error(`Invalid Sentry Dsn: Invalid projectId ${projectId}`); 42477 return false; 42478 } 42479 42480 if (!isValidProtocol(protocol)) { 42481 logger.logger.error(`Invalid Sentry Dsn: Invalid protocol ${protocol}`); 42482 return false; 42483 } 42484 42485 if (port && isNaN(parseInt(port, 10))) { 42486 logger.logger.error(`Invalid Sentry Dsn: Invalid port ${port}`); 42487 return false; 42488 } 42489 42490 return true; 42491} 42492 42493/** 42494 * Creates a valid Sentry Dsn object, identifying a Sentry instance and project. 42495 * @returns a valid DsnComponents object or `undefined` if @param from is an invalid DSN source 42496 */ 42497function makeDsn(from) { 42498 const components = typeof from === 'string' ? dsnFromString(from) : dsnFromComponents(from); 42499 if (!components || !validateDsn(components)) { 42500 return undefined; 42501 } 42502 return components; 42503} 42504 42505exports.dsnFromString = dsnFromString; 42506exports.dsnToString = dsnToString; 42507exports.makeDsn = makeDsn; 42508 42509 42510},{"./debug-build.js":313,"./logger.js":331}],315:[function(require,module,exports){ 42511Object.defineProperty(exports, '__esModule', { value: true }); 42512 42513/* 42514 * This module exists for optimizations in the build process through rollup and terser. We define some global 42515 * constants, which can be overridden during build. By guarding certain pieces of code with functions that return these 42516 * constants, we can control whether or not they appear in the final bundle. (Any code guarded by a false condition will 42517 * never run, and will hence be dropped during treeshaking.) The two primary uses for this are stripping out calls to 42518 * `logger` and preventing node-related code from appearing in browser bundles. 42519 * 42520 * Attention: 42521 * This file should not be used to define constants/flags that are intended to be used for tree-shaking conducted by 42522 * users. These flags should live in their respective packages, as we identified user tooling (specifically webpack) 42523 * having issues tree-shaking these constants across package boundaries. 42524 * An example for this is the __SENTRY_DEBUG__ constant. It is declared in each package individually because we want 42525 * users to be able to shake away expressions that it guards. 42526 */ 42527 42528/** 42529 * Figures out if we're building a browser bundle. 42530 * 42531 * @returns true if this is a browser bundle build. 42532 */ 42533function isBrowserBundle() { 42534 return typeof __SENTRY_BROWSER_BUNDLE__ !== 'undefined' && !!__SENTRY_BROWSER_BUNDLE__; 42535} 42536 42537/** 42538 * Get source of SDK. 42539 */ 42540function getSDKSource() { 42541 // @ts-expect-error "npm" is injected by rollup during build process 42542 return "npm"; 42543} 42544 42545exports.getSDKSource = getSDKSource; 42546exports.isBrowserBundle = isBrowserBundle; 42547 42548 42549},{}],316:[function(require,module,exports){ 42550Object.defineProperty(exports, '__esModule', { value: true }); 42551 42552const dsn = require('./dsn.js'); 42553const normalize = require('./normalize.js'); 42554const object = require('./object.js'); 42555 42556/** 42557 * Creates an envelope. 42558 * Make sure to always explicitly provide the generic to this function 42559 * so that the envelope types resolve correctly. 42560 */ 42561function createEnvelope(headers, items = []) { 42562 return [headers, items] ; 42563} 42564 42565/** 42566 * Add an item to an envelope. 42567 * Make sure to always explicitly provide the generic to this function 42568 * so that the envelope types resolve correctly. 42569 */ 42570function addItemToEnvelope(envelope, newItem) { 42571 const [headers, items] = envelope; 42572 return [headers, [...items, newItem]] ; 42573} 42574 42575/** 42576 * Convenience function to loop through the items and item types of an envelope. 42577 * (This function was mostly created because working with envelope types is painful at the moment) 42578 * 42579 * If the callback returns true, the rest of the items will be skipped. 42580 */ 42581function forEachEnvelopeItem( 42582 envelope, 42583 callback, 42584) { 42585 const envelopeItems = envelope[1]; 42586 42587 for (const envelopeItem of envelopeItems) { 42588 const envelopeItemType = envelopeItem[0].type; 42589 const result = callback(envelopeItem, envelopeItemType); 42590 42591 if (result) { 42592 return true; 42593 } 42594 } 42595 42596 return false;
vendor: 4,200 bytes, lines 42597-42751
42597} 42598 42599/** 42600 * Returns true if the envelope contains any of the given envelope item types 42601 */ 42602function envelopeContainsItemType(envelope, types) { 42603 return forEachEnvelopeItem(envelope, (_, type) => types.includes(type)); 42604} 42605 42606/** 42607 * Encode a string to UTF8. 42608 */ 42609function encodeUTF8(input, textEncoder) { 42610 const utf8 = textEncoder || new TextEncoder(); 42611 return utf8.encode(input); 42612} 42613 42614/** 42615 * Serializes an envelope. 42616 */ 42617function serializeEnvelope(envelope, textEncoder) { 42618 const [envHeaders, items] = envelope; 42619 42620 // Initially we construct our envelope as a string and only convert to binary chunks if we encounter binary data 42621 let parts = JSON.stringify(envHeaders); 42622 42623 function append(next) { 42624 if (typeof parts === 'string') { 42625 parts = typeof next === 'string' ? parts + next : [encodeUTF8(parts, textEncoder), next]; 42626 } else { 42627 parts.push(typeof next === 'string' ? encodeUTF8(next, textEncoder) : next); 42628 } 42629 } 42630 42631 for (const item of items) { 42632 const [itemHeaders, payload] = item; 42633 42634 append(`\n${JSON.stringify(itemHeaders)}\n`); 42635 42636 if (typeof payload === 'string' || payload instanceof Uint8Array) { 42637 append(payload); 42638 } else { 42639 let stringifiedPayload; 42640 try { 42641 stringifiedPayload = JSON.stringify(payload); 42642 } catch (e) { 42643 // In case, despite all our efforts to keep `payload` circular-dependency-free, `JSON.strinify()` still 42644 // fails, we try again after normalizing it again with infinite normalization depth. This of course has a 42645 // performance impact but in this case a performance hit is better than throwing. 42646 stringifiedPayload = JSON.stringify(normalize.normalize(payload)); 42647 } 42648 append(stringifiedPayload); 42649 } 42650 } 42651 42652 return typeof parts === 'string' ? parts : concatBuffers(parts); 42653} 42654 42655function concatBuffers(buffers) { 42656 const totalLength = buffers.reduce((acc, buf) => acc + buf.length, 0); 42657 42658 const merged = new Uint8Array(totalLength); 42659 let offset = 0; 42660 for (const buffer of buffers) { 42661 merged.set(buffer, offset); 42662 offset += buffer.length; 42663 } 42664 42665 return merged; 42666} 42667 42668/** 42669 * Parses an envelope 42670 */ 42671function parseEnvelope( 42672 env, 42673 textEncoder, 42674 textDecoder, 42675) { 42676 let buffer = typeof env === 'string' ? textEncoder.encode(env) : env; 42677 42678 function readBinary(length) { 42679 const bin = buffer.subarray(0, length); 42680 // Replace the buffer with the remaining data excluding trailing newline 42681 buffer = buffer.subarray(length + 1); 42682 return bin; 42683 } 42684 42685 function readJson() { 42686 let i = buffer.indexOf(0xa); 42687 // If we couldn't find a newline, we must have found the end of the buffer 42688 if (i < 0) { 42689 i = buffer.length; 42690 } 42691 42692 return JSON.parse(textDecoder.decode(readBinary(i))) ; 42693 } 42694 42695 const envelopeHeader = readJson(); 42696 // eslint-disable-next-line @typescript-eslint/no-explicit-any 42697 const items = []; 42698 42699 while (buffer.length) { 42700 const itemHeader = readJson(); 42701 const binaryLength = typeof itemHeader.length === 'number' ? itemHeader.length : undefined; 42702 42703 items.push([itemHeader, binaryLength ? readBinary(binaryLength) : readJson()]); 42704 } 42705 42706 return [envelopeHeader, items]; 42707} 42708 42709/** 42710 * Creates attachment envelope items 42711 */ 42712function createAttachmentEnvelopeItem( 42713 attachment, 42714 textEncoder, 42715) { 42716 const buffer = typeof attachment.data === 'string' ? encodeUTF8(attachment.data, textEncoder) : attachment.data; 42717 42718 return [ 42719 object.dropUndefinedKeys({ 42720 type: 'attachment', 42721 length: buffer.length, 42722 filename: attachment.filename, 42723 content_type: attachment.contentType, 42724 attachment_type: attachment.attachmentType, 42725 }), 42726 buffer, 42727 ]; 42728} 42729 42730const ITEM_TYPE_TO_DATA_CATEGORY_MAP = { 42731 session: 'session', 42732 sessions: 'session', 42733 attachment: 'attachment', 42734 transaction: 'transaction', 42735 event: 'error', 42736 client_report: 'internal', 42737 user_report: 'default', 42738 profile: 'profile', 42739 replay_event: 'replay', 42740 replay_recording: 'replay', 42741 check_in: 'monitor', 42742 feedback: 'feedback', 42743 span: 'span', 42744 // TODO: This is a temporary workaround until we have a proper data category for metrics 42745 statsd: 'unknown', 42746}; 42747 42748/** 42749 * Maps the type of an envelope item to a data category. 42750 */ 42751function envelopeItemTypeToDataCategory(type) {
42752 return ITEM_TYPE_TO_DATA_CATEGORY_MAP[type]; 42753} 42754 42755/** Extracts the minimal SDK info from from the metadata or an events */ 42756function getSdkMetadataForEnvelopeHeader(metadataOrEvent) { 42757 if (!metadataOrEvent || !metadataOrEvent.sdk) { 42758 return; 42759 } 42760 const { name, version } = metadataOrEvent.sdk; 42761 return { name, version }; 42762} 42763 42764/** 42765 * Creates event envelope headers, based on event, sdk info and tunnel 42766 * Note: This function was extracted from the core package to make it available in Replay 42767 */ 42768function createEventEnvelopeHeaders( 42769 event, 42770 sdkInfo, 42771 tunnel, 42772 dsn$1, 42773) { 42774 const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext; 42775 return { 42776 event_id: event.event_id , 42777 sent_at: new Date().toISOString(), 42778 ...(sdkInfo && { sdk: sdkInfo }), 42779 ...(!!tunnel && dsn$1 && { dsn: dsn.dsnToString(dsn$1) }), 42780 ...(dynamicSamplingContext && { 42781 trace: object.dropUndefinedKeys({ ...dynamicSamplingContext }), 42782 }), 42783 }; 42784} 42785 42786exports.addItemToEnvelope = addItemToEnvelope; 42787exports.createAttachmentEnvelopeItem = createAttachmentEnvelopeItem; 42788exports.createEnvelope = createEnvelope; 42789exports.createEventEnvelopeHeaders = createEventEnvelopeHeaders; 42790exports.envelopeContainsItemType = envelopeContainsItemType; 42791exports.envelopeItemTypeToDataCategory = envelopeItemTypeToDataCategory; 42792exports.forEachEnvelopeItem = forEachEnvelopeItem; 42793exports.getSdkMetadataForEnvelopeHeader = getSdkMetadataForEnvelopeHeader; 42794exports.parseEnvelope = parseEnvelope; 42795exports.serializeEnvelope = serializeEnvelope; 42796 42797 42798},{"./dsn.js":314,"./normalize.js":337,"./object.js":338}],317:[function(require,module,exports){ 42799Object.defineProperty(exports, '__esModule', { value: true }); 42800 42801/** An error emitted by Sentry SDKs and related utilities. */ 42802class SentryError extends Error { 42803 /** Display name of this error instance. */ 42804 42805 constructor( message, logLevel = 'warn') { 42806 super(message);this.message = message; 42807 this.name = new.target.prototype.constructor.name; 42808 // This sets the prototype to be `Error`, not `SentryError`. It's unclear why we do this, but commenting this line 42809 // out causes various (seemingly totally unrelated) playwright tests consistently time out. FYI, this makes 42810 // instances of `SentryError` fail `obj instanceof SentryError` checks. 42811 Object.setPrototypeOf(this, new.target.prototype); 42812 this.logLevel = logLevel; 42813 } 42814} 42815 42816exports.SentryError = SentryError; 42817 42818 42819},{}],318:[function(require,module,exports){ 42820Object.defineProperty(exports, '__esModule', { value: true }); 42821 42822const is = require('./is.js'); 42823const misc = require('./misc.js'); 42824const normalize = require('./normalize.js'); 42825const object = require('./object.js'); 42826 42827/** 42828 * Extracts stack frames from the error.stack string 42829 */ 42830function parseStackFrames(stackParser, error) { 42831 return stackParser(error.stack || '', 1); 42832} 42833 42834/** 42835 * Extracts stack frames from the error and builds a Sentry Exception 42836 */ 42837function exceptionFromError(stackParser, error) { 42838 const exception = { 42839 type: error.name || error.constructor.name, 42840 value: error.message, 42841 }; 42842 42843 const frames = parseStackFrames(stackParser, error); 42844 if (frames.length) { 42845 exception.stacktrace = { frames }; 42846 } 42847 42848 return exception; 42849} 42850 42851function getMessageForObject(exception) { 42852 if ('name' in exception && typeof exception.name === 'string') { 42853 let message = `'${exception.name}' captured as exception`; 42854 42855 if ('message' in exception && typeof exception.message === 'string') { 42856 message += ` with message '${exception.message}'`; 42857 } 42858 42859 return message; 42860 } else if ('message' in exception && typeof exception.message === 'string') { 42861 return exception.message; 42862 } else { 42863 // This will allow us to group events based on top-level keys 42864 // which is much better than creating new group when any key/value change 42865 return `Object captured as exception with keys: ${object.extractExceptionKeysForMessage( 42866 exception , 42867 )}`; 42868 } 42869} 42870 42871/** 42872 * Builds and Event from a Exception 42873 * 42874 * TODO(v8): Remove getHub fallback 42875 * @hidden 42876 */ 42877function eventFromUnknownInput( 42878 getHubOrClient, 42879 stackParser, 42880 exception, 42881 hint, 42882) { 42883 const client = 42884 typeof getHubOrClient === 'function' 42885 ? // eslint-disable-next-line deprecation/deprecation 42886 getHubOrClient().getClient() 42887 : getHubOrClient; 42888 42889 let ex = exception; 42890 const providedMechanism = 42891 hint && hint.data && (hint.data ).mechanism; 42892 const mechanism = providedMechanism || { 42893 handled: true, 42894 type: 'generic', 42895 }; 42896 42897 let extras; 42898 42899 if (!is.isError(exception)) { 42900 if (is.isPlainObject(exception)) { 42901 const normalizeDepth = client && client.getOptions().normalizeDepth; 42902 extras = { ['__serialized__']: normalize.normalizeToSize(exception , normalizeDepth) }; 42903 42904 const message = getMessageForObject(exception); 42905 ex = (hint && hint.syntheticException) || new Error(message); 42906 (ex ).message = message; 42907 } else { 42908 // This handles when someone does: `throw "something awesome";` 42909 // We use synthesized Error here so we can extract a (rough) stack trace. 42910 ex = (hint && hint.syntheticException) || new Error(exception ); 42911 (ex ).message = exception ; 42912 } 42913 mechanism.synthetic = true; 42914 } 42915 42916 const event = { 42917 exception: { 42918 values: [exceptionFromError(stackParser, ex )], 42919 }, 42920 }; 42921 42922 if (extras) { 42923 event.extra = extras; 42924 } 42925 42926 misc.addExceptionTypeValue(event, undefined, undefined); 42927 misc.addExceptionMechanism(event, mechanism); 42928 42929 return { 42930 ...event, 42931 event_id: hint && hint.event_id, 42932 }; 42933} 42934 42935/**
42936 * Builds and Event from a Message 42937 * @hidden 42938 */ 42939function eventFromMessage( 42940 stackParser, 42941 message, 42942 // eslint-disable-next-line deprecation/deprecation 42943 level = 'info', 42944 hint, 42945 attachStacktrace, 42946) { 42947 const event = { 42948 event_id: hint && hint.event_id, 42949 level, 42950 }; 42951 42952 if (attachStacktrace && hint && hint.syntheticException) { 42953 const frames = parseStackFrames(stackParser, hint.syntheticException); 42954 if (frames.length) { 42955 event.exception = { 42956 values: [ 42957 { 42958 value: message, 42959 stacktrace: { frames }, 42960 }, 42961 ], 42962 }; 42963 } 42964 } 42965 42966 if (is.isParameterizedString(message)) { 42967 const { __sentry_template_string__, __sentry_template_values__ } = message; 42968 42969 event.logentry = { 42970 message: __sentry_template_string__, 42971 params: __sentry_template_values__, 42972 }; 42973 return event; 42974 } 42975 42976 event.message = message; 42977 return event; 42978} 42979 42980exports.eventFromMessage = eventFromMessage; 42981exports.eventFromUnknownInput = eventFromUnknownInput; 42982exports.exceptionFromError = exceptionFromError; 42983exports.parseStackFrames = parseStackFrames; 42984 42985 42986},{"./is.js":329,"./misc.js":334,"./normalize.js":337,"./object.js":338}],319:[function(require,module,exports){ 42987Object.defineProperty(exports, '__esModule', { value: true }); 42988 42989const aggregateErrors = require('./aggregate-errors.js'); 42990const browser = require('./browser.js'); 42991const dsn = require('./dsn.js'); 42992const error = require('./error.js'); 42993const worldwide = require('./worldwide.js'); 42994const index = require('./instrument/index.js'); 42995const is = require('./is.js'); 42996const isBrowser = require('./isBrowser.js'); 42997const logger = require('./logger.js'); 42998const memo = require('./memo.js'); 42999const misc = require('./misc.js'); 43000const node = require('./node.js'); 43001const normalize = require('./normalize.js'); 43002const object = require('./object.js'); 43003const path = require('./path.js'); 43004const promisebuffer = require('./promisebuffer.js'); 43005const requestdata = require('./requestdata.js'); 43006const severity = require('./severity.js'); 43007const stacktrace = require('./stacktrace.js'); 43008const string = require('./string.js'); 43009const supports = require('./supports.js'); 43010const syncpromise = require('./syncpromise.js'); 43011const time = require('./time.js'); 43012const tracing = require('./tracing.js'); 43013const env = require('./env.js'); 43014const envelope = require('./envelope.js'); 43015const clientreport = require('./clientreport.js'); 43016const ratelimit = require('./ratelimit.js'); 43017const baggage = require('./baggage.js'); 43018const url = require('./url.js'); 43019const userIntegrations = require('./userIntegrations.js'); 43020const cache = require('./cache.js'); 43021const eventbuilder = require('./eventbuilder.js'); 43022const anr = require('./anr.js'); 43023const lru = require('./lru.js'); 43024const _asyncNullishCoalesce = require('./buildPolyfills/_asyncNullishCoalesce.js'); 43025const _asyncOptionalChain = require('./buildPolyfills/_asyncOptionalChain.js'); 43026const _asyncOptionalChainDelete = require('./buildPolyfills/_asyncOptionalChainDelete.js'); 43027const _nullishCoalesce = require('./buildPolyfills/_nullishCoalesce.js'); 43028const _optionalChain = require('./buildPolyfills/_optionalChain.js'); 43029const _optionalChainDelete = require('./buildPolyfills/_optionalChainDelete.js'); 43030const console = require('./instrument/console.js'); 43031const dom = require('./instrument/dom.js'); 43032const xhr = require('./instrument/xhr.js'); 43033const fetch = require('./instrument/fetch.js'); 43034const history = require('./instrument/history.js'); 43035const globalError = require('./instrument/globalError.js'); 43036const globalUnhandledRejection = require('./instrument/globalUnhandledRejection.js'); 43037const _handlers = require('./instrument/_handlers.js'); 43038const nodeStackTrace = require('./node-stack-trace.js'); 43039const escapeStringForRegex = require('./vendor/escapeStringForRegex.js'); 43040const supportsHistory = require('./vendor/supportsHistory.js'); 43041 43042 43043 43044exports.applyAggregateErrorsToEvent = aggregateErrors.applyAggregateErrorsToEvent; 43045exports.getComponentName = browser.getComponentName; 43046exports.getDomElement = browser.getDomElement; 43047exports.getLocationHref = browser.getLocationHref; 43048exports.htmlTreeAsString = browser.htmlTreeAsString; 43049exports.dsnFromString = dsn.dsnFromString; 43050exports.dsnToString = dsn.dsnToString; 43051exports.makeDsn = dsn.makeDsn;
43052exports.SentryError = error.SentryError; 43053exports.GLOBAL_OBJ = worldwide.GLOBAL_OBJ; 43054exports.getGlobalObject = worldwide.getGlobalObject; 43055exports.getGlobalSingleton = worldwide.getGlobalSingleton; 43056exports.addInstrumentationHandler = index.addInstrumentationHandler; 43057exports.isDOMError = is.isDOMError; 43058exports.isDOMException = is.isDOMException; 43059exports.isElement = is.isElement; 43060exports.isError = is.isError; 43061exports.isErrorEvent = is.isErrorEvent; 43062exports.isEvent = is.isEvent; 43063exports.isInstanceOf = is.isInstanceOf; 43064exports.isNaN = is.isNaN; 43065exports.isParameterizedString = is.isParameterizedString; 43066exports.isPlainObject = is.isPlainObject; 43067exports.isPrimitive = is.isPrimitive; 43068exports.isRegExp = is.isRegExp; 43069exports.isString = is.isString; 43070exports.isSyntheticEvent = is.isSyntheticEvent; 43071exports.isThenable = is.isThenable; 43072exports.isVueViewModel = is.isVueViewModel; 43073exports.isBrowser = isBrowser.isBrowser; 43074exports.CONSOLE_LEVELS = logger.CONSOLE_LEVELS; 43075exports.consoleSandbox = logger.consoleSandbox; 43076exports.logger = logger.logger; 43077exports.originalConsoleMethods = logger.originalConsoleMethods; 43078exports.memoBuilder = memo.memoBuilder; 43079exports.addContextToFrame = misc.addContextToFrame; 43080exports.addExceptionMechanism = misc.addExceptionMechanism; 43081exports.addExceptionTypeValue = misc.addExceptionTypeValue; 43082exports.arrayify = misc.arrayify; 43083exports.checkOrSetAlreadyCaught = misc.checkOrSetAlreadyCaught; 43084exports.getEventDescription = misc.getEventDescription; 43085exports.parseSemver = misc.parseSemver; 43086exports.uuid4 = misc.uuid4; 43087exports.dynamicRequire = node.dynamicRequire; 43088exports.isNodeEnv = node.isNodeEnv; 43089exports.loadModule = node.loadModule; 43090exports.normalize = normalize.normalize; 43091exports.normalizeToSize = normalize.normalizeToSize; 43092exports.normalizeUrlToBase = normalize.normalizeUrlToBase; 43093exports.walk = normalize.walk; 43094exports.addNonEnumerableProperty = object.addNonEnumerableProperty; 43095exports.convertToPlainObject = object.convertToPlainObject; 43096exports.dropUndefinedKeys = object.dropUndefinedKeys; 43097exports.extractExceptionKeysForMessage = object.extractExceptionKeysForMessage; 43098exports.fill = object.fill; 43099exports.getOriginalFunction = object.getOriginalFunction; 43100exports.markFunctionWrapped = object.markFunctionWrapped; 43101exports.objectify = object.objectify; 43102exports.urlEncode = object.urlEncode; 43103exports.basename = path.basename; 43104exports.dirname = path.dirname; 43105exports.isAbsolute = path.isAbsolute; 43106exports.join = path.join; 43107exports.normalizePath = path.normalizePath; 43108exports.relative = path.relative; 43109exports.resolve = path.resolve; 43110exports.makePromiseBuffer = promisebuffer.makePromiseBuffer; 43111exports.DEFAULT_USER_INCLUDES = requestdata.DEFAULT_USER_INCLUDES; 43112exports.addRequestDataToEvent = requestdata.addRequestDataToEvent; 43113exports.addRequestDataToTransaction = requestdata.addRequestDataToTransaction; 43114exports.extractPathForTransaction = requestdata.extractPathForTransaction; 43115exports.extractRequestData = requestdata.extractRequestData; 43116exports.winterCGHeadersToDict = requestdata.winterCGHeadersToDict; 43117exports.winterCGRequestToRequestData = requestdata.winterCGRequestToRequestData; 43118exports.severityFromString = severity.severityFromString; 43119exports.severityLevelFromString = severity.severityLevelFromString; 43120exports.validSeverityLevels = severity.validSeverityLevels; 43121exports.createStackParser = stacktrace.createStackParser; 43122exports.getFunctionName = stacktrace.getFunctionName; 43123exports.nodeStackLineParser = stacktrace.nodeStackLineParser; 43124exports.stackParserFromStackParserOptions = stacktrace.stackParserFromStackParserOptions; 43125exports.stripSentryFramesAndReverse = stacktrace.stripSentryFramesAndReverse;
43126exports.isMatchingPattern = string.isMatchingPattern; 43127exports.safeJoin = string.safeJoin; 43128exports.snipLine = string.snipLine; 43129exports.stringMatchesSomePattern = string.stringMatchesSomePattern; 43130exports.truncate = string.truncate; 43131exports.isNativeFetch = supports.isNativeFetch; 43132exports.supportsDOMError = supports.supportsDOMError; 43133exports.supportsDOMException = supports.supportsDOMException; 43134exports.supportsErrorEvent = supports.supportsErrorEvent; 43135exports.supportsFetch = supports.supportsFetch; 43136exports.supportsNativeFetch = supports.supportsNativeFetch; 43137exports.supportsReferrerPolicy = supports.supportsReferrerPolicy; 43138exports.supportsReportingObserver = supports.supportsReportingObserver; 43139exports.SyncPromise = syncpromise.SyncPromise; 43140exports.rejectedSyncPromise = syncpromise.rejectedSyncPromise; 43141exports.resolvedSyncPromise = syncpromise.resolvedSyncPromise; 43142Object.defineProperty(exports, '_browserPerformanceTimeOriginMode', { 43143 enumerable: true, 43144 get: () => time._browserPerformanceTimeOriginMode 43145}); 43146exports.browserPerformanceTimeOrigin = time.browserPerformanceTimeOrigin; 43147exports.dateTimestampInSeconds = time.dateTimestampInSeconds; 43148exports.timestampInSeconds = time.timestampInSeconds; 43149exports.timestampWithMs = time.timestampWithMs; 43150exports.TRACEPARENT_REGEXP = tracing.TRACEPARENT_REGEXP; 43151exports.extractTraceparentData = tracing.extractTraceparentData; 43152exports.generateSentryTraceHeader = tracing.generateSentryTraceHeader; 43153exports.propagationContextFromHeaders = tracing.propagationContextFromHeaders; 43154exports.tracingContextFromHeaders = tracing.tracingContextFromHeaders; 43155exports.getSDKSource = env.getSDKSource; 43156exports.isBrowserBundle = env.isBrowserBundle; 43157exports.addItemToEnvelope = envelope.addItemToEnvelope; 43158exports.createAttachmentEnvelopeItem = envelope.createAttachmentEnvelopeItem; 43159exports.createEnvelope = envelope.createEnvelope; 43160exports.createEventEnvelopeHeaders = envelope.createEventEnvelopeHeaders; 43161exports.envelopeContainsItemType = envelope.envelopeContainsItemType; 43162exports.envelopeItemTypeToDataCategory = envelope.envelopeItemTypeToDataCategory; 43163exports.forEachEnvelopeItem = envelope.forEachEnvelopeItem; 43164exports.getSdkMetadataForEnvelopeHeader = envelope.getSdkMetadataForEnvelopeHeader; 43165exports.parseEnvelope = envelope.parseEnvelope; 43166exports.serializeEnvelope = envelope.serializeEnvelope; 43167exports.createClientReportEnvelope = clientreport.createClientReportEnvelope; 43168exports.DEFAULT_RETRY_AFTER = ratelimit.DEFAULT_RETRY_AFTER; 43169exports.disabledUntil = ratelimit.disabledUntil; 43170exports.isRateLimited = ratelimit.isRateLimited; 43171exports.parseRetryAfterHeader = ratelimit.parseRetryAfterHeader; 43172exports.updateRateLimits = ratelimit.updateRateLimits; 43173exports.BAGGAGE_HEADER_NAME = baggage.BAGGAGE_HEADER_NAME; 43174exports.MAX_BAGGAGE_STRING_LENGTH = baggage.MAX_BAGGAGE_STRING_LENGTH; 43175exports.SENTRY_BAGGAGE_KEY_PREFIX = baggage.SENTRY_BAGGAGE_KEY_PREFIX; 43176exports.SENTRY_BAGGAGE_KEY_PREFIX_REGEX = baggage.SENTRY_BAGGAGE_KEY_PREFIX_REGEX; 43177exports.baggageHeaderToDynamicSamplingContext = baggage.baggageHeaderToDynamicSamplingContext; 43178exports.dynamicSamplingContextToSentryBaggageHeader = baggage.dynamicSamplingContextToSentryBaggageHeader; 43179exports.getNumberOfUrlSegments = url.getNumberOfUrlSegments; 43180exports.getSanitizedUrlString = url.getSanitizedUrlString; 43181exports.parseUrl = url.parseUrl; 43182exports.stripUrlQueryAndFragment = url.stripUrlQueryAndFragment; 43183exports.addOrUpdateIntegration = userIntegrations.addOrUpdateIntegration; 43184exports.makeFifoCache = cache.makeFifoCache; 43185exports.eventFromMessage = eventbuilder.eventFromMessage; 43186exports.eventFromUnknownInput = eventbuilder.eventFromUnknownInput; 43187exports.exceptionFromError = eventbuilder.exceptionFromError; 43188exports.parseStackFrames = eventbuilder.parseStackFrames; 43189exports.callFrameToStackFrame = anr.callFrameToStackFrame; 43190exports.watchdogTimer = anr.watchdogTimer; 43191exports.LRUMap = lru.LRUMap; 43192exports._asyncNullishCoalesce = _asyncNullishCoalesce._asyncNullishCoalesce; 43193exports._asyncOptionalChain = _asyncOptionalChain._asyncOptionalChain; 43194exports._asyncOptionalChainDelete = _asyncOptionalChainDelete._asyncOptionalChainDelete; 43195exports._nullishCoalesce = _nullishCoalesce._nullishCoalesce; 43196exports._optionalChain = _optionalChain._optionalChain; 43197exports._optionalChainDelete = _optionalChainDelete._optionalChainDelete; 43198exports.addConsoleInstrumentationHandler = console.addConsoleInstrumentationHandler; 43199exports.addClickKeypressInstrumentationHandler = dom.addClickKeypressInstrumentationHandler; 43200exports.SENTRY_XHR_DATA_KEY = xhr.SENTRY_XHR_DATA_KEY;
43201exports.addXhrInstrumentationHandler = xhr.addXhrInstrumentationHandler; 43202exports.addFetchInstrumentationHandler = fetch.addFetchInstrumentationHandler; 43203exports.addHistoryInstrumentationHandler = history.addHistoryInstrumentationHandler; 43204exports.addGlobalErrorInstrumentationHandler = globalError.addGlobalErrorInstrumentationHandler; 43205exports.addGlobalUnhandledRejectionInstrumentationHandler = globalUnhandledRejection.addGlobalUnhandledRejectionInstrumentationHandler; 43206exports.resetInstrumentationHandlers = _handlers.resetInstrumentationHandlers; 43207exports.filenameIsInApp = nodeStackTrace.filenameIsInApp; 43208exports.escapeStringForRegex = escapeStringForRegex.escapeStringForRegex; 43209exports.supportsHistory = supportsHistory.supportsHistory; 43210 43211 43212},{"./aggregate-errors.js":300,"./anr.js":301,"./baggage.js":302,"./browser.js":303,"./buildPolyfills/_asyncNullishCoalesce.js":304,"./buildPolyfills/_asyncOptionalChain.js":305,"./buildPolyfills/_asyncOptionalChainDelete.js":306,"./buildPolyfills/_nullishCoalesce.js":307,"./buildPolyfills/_optionalChain.js":308,"./buildPolyfills/_optionalChainDelete.js":309,"./cache.js":310,"./clientreport.js":311,"./dsn.js":314,"./env.js":315,"./envelope.js":316,"./error.js":317,"./eventbuilder.js":318,"./instrument/_handlers.js":320,"./instrument/console.js":321,"./instrument/dom.js":322,"./instrument/fetch.js":323,"./instrument/globalError.js":324,"./instrument/globalUnhandledRejection.js":325,"./instrument/history.js":326,"./instrument/index.js":327,"./instrument/xhr.js":328,"./is.js":329,"./isBrowser.js":330,"./logger.js":331,"./lru.js":332,"./memo.js":333,"./misc.js":334,"./node-stack-trace.js":335,"./node.js":336,"./normalize.js":337,"./object.js":338,"./path.js":339,"./promisebuffer.js":340,"./ratelimit.js":341,"./requestdata.js":342,"./severity.js":343,"./stacktrace.js":344,"./string.js":345,"./supports.js":346,"./syncpromise.js":347,"./time.js":348,"./tracing.js":349,"./url.js":350,"./userIntegrations.js":351,"./vendor/escapeStringForRegex.js":352,"./vendor/supportsHistory.js":353,"./worldwide.js":354}],320:[function(require,module,exports){ 43213Object.defineProperty(exports, '__esModule', { value: true }); 43214 43215const debugBuild = require('../debug-build.js'); 43216const logger = require('../logger.js'); 43217const stacktrace = require('../stacktrace.js'); 43218 43219// We keep the handlers globally 43220const handlers = {}; 43221const instrumented = {}; 43222 43223/** Add a handler function. */ 43224function addHandler(type, handler) { 43225 handlers[type] = handlers[type] || []; 43226 (handlers[type] ).push(handler); 43227} 43228 43229/** 43230 * Reset all instrumentation handlers. 43231 * This can be used by tests to ensure we have a clean slate of instrumentation handlers. 43232 */ 43233function resetInstrumentationHandlers() { 43234 Object.keys(handlers).forEach(key => { 43235 handlers[key ] = undefined; 43236 }); 43237} 43238 43239/** Maybe run an instrumentation function, unless it was already called. */ 43240function maybeInstrument(type, instrumentFn) { 43241 if (!instrumented[type]) { 43242 instrumentFn(); 43243 instrumented[type] = true; 43244 } 43245} 43246 43247/** Trigger handlers for a given instrumentation type. */ 43248function triggerHandlers(type, data) { 43249 const typeHandlers = type && handlers[type]; 43250 if (!typeHandlers) { 43251 return; 43252 } 43253 43254 for (const handler of typeHandlers) { 43255 try { 43256 handler(data); 43257 } catch (e) { 43258 debugBuild.DEBUG_BUILD && 43259 logger.logger.error( 43260 `Error while triggering instrumentation handler.\nType: ${type}\nName: ${stacktrace.getFunctionName(handler)}\nError:`, 43261 e, 43262 ); 43263 } 43264 } 43265} 43266 43267exports.addHandler = addHandler; 43268exports.maybeInstrument = maybeInstrument; 43269exports.resetInstrumentationHandlers = resetInstrumentationHandlers; 43270exports.triggerHandlers = triggerHandlers; 43271 43272 43273},{"../debug-build.js":313,"../logger.js":331,"../stacktrace.js":344}],321:[function(require,module,exports){ 43274Object.defineProperty(exports, '__esModule', { value: true }); 43275 43276const logger = require('../logger.js'); 43277const object = require('../object.js'); 43278const worldwide = require('../worldwide.js'); 43279const _handlers = require('./_handlers.js'); 43280 43281/** 43282 * Add an instrumentation handler for when a console.xxx method is called. 43283 * 43284 * Use at your own risk, this might break without changelog notice, only used internally. 43285 * @hidden 43286 */ 43287function addConsoleInstrumentationHandler(handler) { 43288 const type = 'console'; 43289 _handlers.addHandler(type, handler); 43290 _handlers.maybeInstrument(type, instrumentConsole); 43291} 43292 43293function instrumentConsole() { 43294 if (!('console' in worldwide.GLOBAL_OBJ)) { 43295 return; 43296 } 43297 43298 logger.CONSOLE_LEVELS.forEach(function (level) { 43299 if (!(level in worldwide.GLOBAL_OBJ.console)) { 43300 return; 43301 } 43302 43303 object.fill(worldwide.GLOBAL_OBJ.console, level, function (originalConsoleMethod) { 43304 logger.originalConsoleMethods[level] = originalConsoleMethod; 43305 43306 return function (...args) { 43307 const handlerData = { args, level }; 43308 _handlers.triggerHandlers('console', handlerData); 43309 43310 const log = logger.originalConsoleMethods[level]; 43311 log && log.apply(worldwide.GLOBAL_OBJ.console, args); 43312 }; 43313 }); 43314 }); 43315} 43316 43317exports.addConsoleInstrumentationHandler = addConsoleInstrumentationHandler; 43318 43319 43320},{"../logger.js":331,"../object.js":338,"../worldwide.js":354,"./_handlers.js":320}],322:[function(require,module,exports){ 43321Object.defineProperty(exports, '__esModule', { value: true }); 43322 43323const misc = require('../misc.js'); 43324const object = require('../object.js'); 43325const worldwide = require('../worldwide.js'); 43326const _handlers = require('./_handlers.js'); 43327 43328const WINDOW = worldwide.GLOBAL_OBJ ; 43329const DEBOUNCE_DURATION = 1000; 43330 43331let debounceTimerID; 43332let lastCapturedEventType; 43333let lastCapturedEventTargetId; 43334 43335/** 43336 * Add an instrumentation handler for when a click or a keypress happens. 43337 * 43338 * Use at your own risk, this might break without changelog notice, only used internally. 43339 * @hidden 43340 */ 43341function addClickKeypressInstrumentationHandler(handler) { 43342 const type = 'dom'; 43343 _handlers.addHandler(type, handler); 43344 _handlers.maybeInstrument(type, instrumentDOM); 43345} 43346 43347/** Exported for tests only. */ 43348function instrumentDOM() { 43349 if (!WINDOW.document) { 43350 return; 43351 } 43352 43353 // Make it so that any click or keypress that is unhandled / bubbled up all the way to the document triggers our dom 43354 // handlers. (Normally we have only one, which captures a breadcrumb for each click or keypress.) Do this before 43355 // we instrument `addEventListener` so that we don't end up attaching this handler twice. 43356 const triggerDOMHandler = _handlers.triggerHandlers.bind(null, 'dom'); 43357 const globalDOMEventHandler = makeDOMEventHandler(triggerDOMHandler, true); 43358 WINDOW.document.addEventListener('click', globalDOMEventHandler, false); 43359 WINDOW.document.addEventListener('keypress', globalDOMEventHandler, false); 43360 43361 // After hooking into click and keypress events bubbled up to `document`, we also hook into user-handled 43362 // clicks & keypresses, by adding an event listener of our own to any element to which they add a listener. That 43363 // way, whenever one of their handlers is triggered, ours will be, too. (This is needed because their handler 43364 // could potentially prevent the event from bubbling up to our global listeners. This way, our handler are still 43365 // guaranteed to fire at least once.) 43366 ['EventTarget', 'Node'].forEach((target) => { 43367 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 43368 const proto = (WINDOW )[target] && (WINDOW )[target].prototype; 43369 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins 43370 if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) { 43371 return; 43372 } 43373 43374 object.fill(proto, 'addEventListener', function (originalAddEventListener) { 43375 return function ( 43376 43377 type, 43378 listener, 43379 options, 43380 ) { 43381 if (type === 'click' || type == 'keypress') { 43382 try { 43383 const el = this ; 43384 const handlers = (el.__sentry_instrumentation_handlers__ = el.__sentry_instrumentation_handlers__ || {}); 43385 const handlerForType = (handlers[type] = handlers[type] || { refCount: 0 }); 43386 43387 if (!handlerForType.handler) { 43388 const handler = makeDOMEventHandler(triggerDOMHandler); 43389 handlerForType.handler = handler; 43390 originalAddEventListener.call(this, type, handler, options); 43391 } 43392 43393 handlerForType.refCount++; 43394 } catch (e) { 43395 // Accessing dom properties is always fragile. 43396 // Also allows us to skip `addEventListenrs` calls with no proper `this` context. 43397 } 43398 } 43399 43400 return originalAddEventListener.call(this, type, listener, options); 43401 }; 43402 }); 43403 43404 object.fill( 43405 proto, 43406 'removeEventListener', 43407 function (originalRemoveEventListener) { 43408 return function ( 43409 43410 type, 43411 listener, 43412 options, 43413 ) { 43414 if (type === 'click' || type == 'keypress') { 43415 try { 43416 const el = this ; 43417 const handlers = el.__sentry_instrumentation_handlers__ || {}; 43418 const handlerForType = handlers[type]; 43419 43420 if (handlerForType) { 43421 handlerForType.refCount--; 43422 // If there are no longer any custom handlers of the current type on this element, we can remove ours, too. 43423 if (handlerForType.refCount <= 0) { 43424 originalRemoveEventListener.call(this, type, handlerForType.handler, options); 43425 handlerForType.handler = undefined; 43426 delete handlers[type]; // eslint-disable-line @typescript-eslint/no-dynamic-delete 43427 } 43428 43429 // If there are no longer any custom handlers of any type on this element, cleanup everything. 43430 if (Object.keys(handlers).length === 0) { 43431 delete el.__sentry_instrumentation_handlers__; 43432 } 43433 } 43434 } catch (e) { 43435 // Accessing dom properties is always fragile. 43436 // Also allows us to skip `addEventListenrs` calls with no proper `this` context. 43437 } 43438 } 43439 43440 return originalRemoveEventListener.call(this, type, listener, options); 43441 }; 43442 }, 43443 ); 43444 }); 43445} 43446 43447/** 43448 * Check whether the event is similar to the last captured one. For example, two click events on the same button. 43449 */ 43450function isSimilarToLastCapturedEvent(event) { 43451 // If both events have different type, then user definitely performed two separate actions. e.g. click + keypress. 43452 if (event.type !== lastCapturedEventType) { 43453 return false;
43454 } 43455 43456 try { 43457 // If both events have the same type, it's still possible that actions were performed on different targets. 43458 // e.g. 2 clicks on different buttons. 43459 if (!event.target || (event.target )._sentryId !== lastCapturedEventTargetId) { 43460 return false; 43461 } 43462 } catch (e) { 43463 // just accessing `target` property can throw an exception in some rare circumstances 43464 // see: https://github.com/getsentry/sentry-javascript/issues/838 43465 } 43466 43467 // If both events have the same type _and_ same `target` (an element which triggered an event, _not necessarily_ 43468 // to which an event listener was attached), we treat them as the same action, as we want to capture 43469 // only one breadcrumb. e.g. multiple clicks on the same button, or typing inside a user input box. 43470 return true; 43471} 43472 43473/** 43474 * Decide whether an event should be captured. 43475 * @param event event to be captured 43476 */ 43477function shouldSkipDOMEvent(eventType, target) { 43478 // We are only interested in filtering `keypress` events for now. 43479 if (eventType !== 'keypress') { 43480 return false; 43481 } 43482 43483 if (!target || !target.tagName) { 43484 return true; 43485 } 43486 43487 // Only consider keypress events on actual input elements. This will disregard keypresses targeting body 43488 // e.g.tabbing through elements, hotkeys, etc. 43489 if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) { 43490 return false; 43491 } 43492 43493 return true; 43494} 43495 43496/** 43497 * Wraps addEventListener to capture UI breadcrumbs 43498 */ 43499function makeDOMEventHandler( 43500 handler, 43501 globalListener = false, 43502) { 43503 return (event) => { 43504 // It's possible this handler might trigger multiple times for the same 43505 // event (e.g. event propagation through node ancestors). 43506 // Ignore if we've already captured that event. 43507 if (!event || event['_sentryCaptured']) { 43508 return; 43509 } 43510 43511 const target = getEventTarget(event); 43512 43513 // We always want to skip _some_ events. 43514 if (shouldSkipDOMEvent(event.type, target)) { 43515 return; 43516 } 43517 43518 // Mark event as "seen" 43519 object.addNonEnumerableProperty(event, '_sentryCaptured', true); 43520 43521 if (target && !target._sentryId) { 43522 // Add UUID to event target so we can identify if 43523 object.addNonEnumerableProperty(target, '_sentryId', misc.uuid4()); 43524 } 43525 43526 const name = event.type === 'keypress' ? 'input' : event.type; 43527 43528 // If there is no last captured event, it means that we can safely capture the new event and store it for future comparisons. 43529 // If there is a last captured event, see if the new event is different enough to treat it as a unique one. 43530 // If that's the case, emit the previous event and store locally the newly-captured DOM event. 43531 if (!isSimilarToLastCapturedEvent(event)) { 43532 const handlerData = { event, name, global: globalListener }; 43533 handler(handlerData); 43534 lastCapturedEventType = event.type; 43535 lastCapturedEventTargetId = target ? target._sentryId : undefined; 43536 } 43537 43538 // Start a new debounce timer that will prevent us from capturing multiple events that should be grouped together. 43539 clearTimeout(debounceTimerID); 43540 debounceTimerID = WINDOW.setTimeout(() => { 43541 lastCapturedEventTargetId = undefined; 43542 lastCapturedEventType = undefined; 43543 }, DEBOUNCE_DURATION); 43544 }; 43545} 43546 43547function getEventTarget(event) { 43548 try { 43549 return event.target ; 43550 } catch (e) { 43551 // just accessing `target` property can throw an exception in some rare circumstances 43552 // see: https://github.com/getsentry/sentry-javascript/issues/838 43553 return null; 43554 } 43555} 43556 43557exports.addClickKeypressInstrumentationHandler = addClickKeypressInstrumentationHandler; 43558exports.instrumentDOM = instrumentDOM; 43559 43560 43561},{"../misc.js":334,"../object.js":338,"../worldwide.js":354,"./_handlers.js":320}],323:[function(require,module,exports){ 43562Object.defineProperty(exports, '__esModule', { value: true }); 43563 43564const object = require('../object.js'); 43565const supports = require('../supports.js'); 43566const worldwide = require('../worldwide.js'); 43567const _handlers = require('./_handlers.js'); 43568 43569/** 43570 * Add an instrumentation handler for when a fetch request happens. 43571 * The handler function is called once when the request starts and once when it ends, 43572 * which can be identified by checking if it has an `endTimestamp`. 43573 * 43574 * Use at your own risk, this might break without changelog notice, only used internally. 43575 * @hidden 43576 */ 43577function addFetchInstrumentationHandler(handler) { 43578 const type = 'fetch'; 43579 _handlers.addHandler(type, handler); 43580 _handlers.maybeInstrument(type, instrumentFetch); 43581} 43582 43583function instrumentFetch() { 43584 if (!supports.supportsNativeFetch()) { 43585 return; 43586 } 43587 43588 object.fill(worldwide.GLOBAL_OBJ, 'fetch', function (originalFetch) { 43589 return function (...args) { 43590 const { method, url } = parseFetchArgs(args); 43591 43592 const handlerData = { 43593 args, 43594 fetchData: { 43595 method, 43596 url, 43597 }, 43598 startTimestamp: Date.now(), 43599 }; 43600 43601 _handlers.triggerHandlers('fetch', { 43602 ...handlerData, 43603 }); 43604 43605 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 43606 return originalFetch.apply(worldwide.GLOBAL_OBJ, args).then( 43607 (response) => { 43608 const finishedHandlerData = { 43609 ...handlerData, 43610 endTimestamp: Date.now(), 43611 response, 43612 }; 43613 43614 _handlers.triggerHandlers('fetch', finishedHandlerData); 43615 return response; 43616 }, 43617 (error) => { 43618 const erroredHandlerData = { 43619 ...handlerData, 43620 endTimestamp: Date.now(), 43621 error, 43622 }; 43623 43624 _handlers.triggerHandlers('fetch', erroredHandlerData); 43625 // NOTE: If you are a Sentry user, and you are seeing this stack frame, 43626 // it means the sentry.javascript SDK caught an error invoking your application code. 43627 // This is expected behavior and NOT indicative of a bug with sentry.javascript. 43628 throw error; 43629 }, 43630 ); 43631 }; 43632 }); 43633} 43634 43635function hasProp(obj, prop) { 43636 return !!obj && typeof obj === 'object' && !!(obj )[prop]; 43637} 43638 43639function getUrlFromResource(resource) { 43640 if (typeof resource === 'string') { 43641 return resource; 43642 } 43643 43644 if (!resource) { 43645 return ''; 43646 } 43647 43648 if (hasProp(resource, 'url')) { 43649 return resource.url; 43650 } 43651 43652 if (resource.toString) { 43653 return resource.toString(); 43654 } 43655 43656 return ''; 43657} 43658 43659/** 43660 * Parses the fetch arguments to find the used Http method and the url of the request. 43661 * Exported for tests only. 43662 */ 43663function parseFetchArgs(fetchArgs) { 43664 if (fetchArgs.length === 0) { 43665 return { method: 'GET', url: '' }; 43666 } 43667 43668 if (fetchArgs.length === 2) { 43669 const [url, options] = fetchArgs ;
43670 43671 return { 43672 url: getUrlFromResource(url), 43673 method: hasProp(options, 'method') ? String(options.method).toUpperCase() : 'GET', 43674 }; 43675 } 43676 43677 const arg = fetchArgs[0]; 43678 return { 43679 url: getUrlFromResource(arg ), 43680 method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET', 43681 }; 43682} 43683 43684exports.addFetchInstrumentationHandler = addFetchInstrumentationHandler; 43685exports.parseFetchArgs = parseFetchArgs; 43686 43687 43688},{"../object.js":338,"../supports.js":346,"../worldwide.js":354,"./_handlers.js":320}],324:[function(require,module,exports){ 43689Object.defineProperty(exports, '__esModule', { value: true }); 43690 43691const worldwide = require('../worldwide.js'); 43692const _handlers = require('./_handlers.js'); 43693 43694let _oldOnErrorHandler = null; 43695 43696/** 43697 * Add an instrumentation handler for when an error is captured by the global error handler. 43698 * 43699 * Use at your own risk, this might break without changelog notice, only used internally. 43700 * @hidden 43701 */ 43702function addGlobalErrorInstrumentationHandler(handler) { 43703 const type = 'error'; 43704 _handlers.addHandler(type, handler); 43705 _handlers.maybeInstrument(type, instrumentError); 43706} 43707 43708function instrumentError() { 43709 _oldOnErrorHandler = worldwide.GLOBAL_OBJ.onerror; 43710 43711 worldwide.GLOBAL_OBJ.onerror = function ( 43712 msg, 43713 url, 43714 line, 43715 column, 43716 error, 43717 ) { 43718 const handlerData = { 43719 column, 43720 error, 43721 line, 43722 msg, 43723 url, 43724 }; 43725 _handlers.triggerHandlers('error', handlerData); 43726 43727 if (_oldOnErrorHandler && !_oldOnErrorHandler.__SENTRY_LOADER__) { 43728 // eslint-disable-next-line prefer-rest-params 43729 return _oldOnErrorHandler.apply(this, arguments); 43730 } 43731 43732 return false; 43733 }; 43734 43735 worldwide.GLOBAL_OBJ.onerror.__SENTRY_INSTRUMENTED__ = true; 43736} 43737 43738exports.addGlobalErrorInstrumentationHandler = addGlobalErrorInstrumentationHandler; 43739 43740 43741},{"../worldwide.js":354,"./_handlers.js":320}],325:[function(require,module,exports){ 43742Object.defineProperty(exports, '__esModule', { value: true }); 43743 43744const worldwide = require('../worldwide.js'); 43745const _handlers = require('./_handlers.js'); 43746 43747let _oldOnUnhandledRejectionHandler = null; 43748 43749/** 43750 * Add an instrumentation handler for when an unhandled promise rejection is captured. 43751 * 43752 * Use at your own risk, this might break without changelog notice, only used internally. 43753 * @hidden 43754 */ 43755function addGlobalUnhandledRejectionInstrumentationHandler( 43756 handler, 43757) { 43758 const type = 'unhandledrejection'; 43759 _handlers.addHandler(type, handler); 43760 _handlers.maybeInstrument(type, instrumentUnhandledRejection); 43761} 43762 43763function instrumentUnhandledRejection() { 43764 _oldOnUnhandledRejectionHandler = worldwide.GLOBAL_OBJ.onunhandledrejection; 43765 43766 worldwide.GLOBAL_OBJ.onunhandledrejection = function (e) { 43767 const handlerData = e; 43768 _handlers.triggerHandlers('unhandledrejection', handlerData); 43769 43770 if (_oldOnUnhandledRejectionHandler && !_oldOnUnhandledRejectionHandler.__SENTRY_LOADER__) { 43771 // eslint-disable-next-line prefer-rest-params 43772 return _oldOnUnhandledRejectionHandler.apply(this, arguments); 43773 } 43774 43775 return true; 43776 }; 43777 43778 worldwide.GLOBAL_OBJ.onunhandledrejection.__SENTRY_INSTRUMENTED__ = true; 43779} 43780 43781exports.addGlobalUnhandledRejectionInstrumentationHandler = addGlobalUnhandledRejectionInstrumentationHandler; 43782 43783 43784},{"../worldwide.js":354,"./_handlers.js":320}],326:[function(require,module,exports){ 43785Object.defineProperty(exports, '__esModule', { value: true }); 43786 43787const object = require('../object.js'); 43788require('../debug-build.js'); 43789require('../logger.js'); 43790const worldwide = require('../worldwide.js'); 43791const supportsHistory = require('../vendor/supportsHistory.js'); 43792const _handlers = require('./_handlers.js'); 43793 43794const WINDOW = worldwide.GLOBAL_OBJ ; 43795 43796let lastHref; 43797 43798/** 43799 * Add an instrumentation handler for when a fetch request happens. 43800 * The handler function is called once when the request starts and once when it ends, 43801 * which can be identified by checking if it has an `endTimestamp`. 43802 * 43803 * Use at your own risk, this might break without changelog notice, only used internally. 43804 * @hidden 43805 */ 43806function addHistoryInstrumentationHandler(handler) { 43807 const type = 'history'; 43808 _handlers.addHandler(type, handler); 43809 _handlers.maybeInstrument(type, instrumentHistory); 43810} 43811 43812function instrumentHistory() { 43813 if (!supportsHistory.supportsHistory()) { 43814 return; 43815 } 43816 43817 const oldOnPopState = WINDOW.onpopstate; 43818 WINDOW.onpopstate = function ( ...args) { 43819 const to = WINDOW.location.href;
43820 // keep track of the current URL state, as we always receive only the updated state 43821 const from = lastHref; 43822 lastHref = to; 43823 const handlerData = { from, to }; 43824 _handlers.triggerHandlers('history', handlerData); 43825 if (oldOnPopState) { 43826 // Apparently this can throw in Firefox when incorrectly implemented plugin is installed. 43827 // https://github.com/getsentry/sentry-javascript/issues/3344 43828 // https://github.com/bugsnag/bugsnag-js/issues/469 43829 try { 43830 return oldOnPopState.apply(this, args); 43831 } catch (_oO) { 43832 // no-empty 43833 } 43834 } 43835 }; 43836 43837 function historyReplacementFunction(originalHistoryFunction) { 43838 return function ( ...args) { 43839 const url = args.length > 2 ? args[2] : undefined; 43840 if (url) { 43841 // coerce to string (this is what pushState does) 43842 const from = lastHref; 43843 const to = String(url); 43844 // keep track of the current URL state, as we always receive only the updated state 43845 lastHref = to; 43846 const handlerData = { from, to }; 43847 _handlers.triggerHandlers('history', handlerData); 43848 } 43849 return originalHistoryFunction.apply(this, args); 43850 }; 43851 } 43852 43853 object.fill(WINDOW.history, 'pushState', historyReplacementFunction); 43854 object.fill(WINDOW.history, 'replaceState', historyReplacementFunction); 43855} 43856 43857exports.addHistoryInstrumentationHandler = addHistoryInstrumentationHandler; 43858 43859 43860},{"../debug-build.js":313,"../logger.js":331,"../object.js":338,"../vendor/supportsHistory.js":353,"../worldwide.js":354,"./_handlers.js":320}],327:[function(require,module,exports){ 43861Object.defineProperty(exports, '__esModule', { value: true }); 43862 43863const debugBuild = require('../debug-build.js'); 43864const logger = require('../logger.js'); 43865const console = require('./console.js'); 43866const dom = require('./dom.js'); 43867const fetch = require('./fetch.js'); 43868const globalError = require('./globalError.js'); 43869const globalUnhandledRejection = require('./globalUnhandledRejection.js'); 43870const history = require('./history.js'); 43871const xhr = require('./xhr.js'); 43872 43873// TODO(v8): Consider moving this file (or at least parts of it) into the browser package. The registered handlers are mostly non-generic and we risk leaking runtime specific code into generic packages. 43874 43875/** 43876 * Add handler that will be called when given type of instrumentation triggers. 43877 * Use at your own risk, this might break without changelog notice, only used internally. 43878 * @hidden 43879 * @deprecated Use the proper function per instrumentation type instead! 43880 */ 43881function addInstrumentationHandler(type, callback) { 43882 switch (type) { 43883 case 'console': 43884 return console.addConsoleInstrumentationHandler(callback); 43885 case 'dom': 43886 return dom.addClickKeypressInstrumentationHandler(callback); 43887 case 'xhr': 43888 return xhr.addXhrInstrumentationHandler(callback); 43889 case 'fetch': 43890 return fetch.addFetchInstrumentationHandler(callback); 43891 case 'history': 43892 return history.addHistoryInstrumentationHandler(callback); 43893 case 'error': 43894 return globalError.addGlobalErrorInstrumentationHandler(callback); 43895 case 'unhandledrejection': 43896 return globalUnhandledRejection.addGlobalUnhandledRejectionInstrumentationHandler(callback); 43897 default: 43898 debugBuild.DEBUG_BUILD && logger.logger.warn('unknown instrumentation type:', type); 43899 } 43900} 43901 43902exports.addConsoleInstrumentationHandler = console.addConsoleInstrumentationHandler; 43903exports.addClickKeypressInstrumentationHandler = dom.addClickKeypressInstrumentationHandler; 43904exports.addFetchInstrumentationHandler = fetch.addFetchInstrumentationHandler; 43905exports.addGlobalErrorInstrumentationHandler = globalError.addGlobalErrorInstrumentationHandler; 43906exports.addGlobalUnhandledRejectionInstrumentationHandler = globalUnhandledRejection.addGlobalUnhandledRejectionInstrumentationHandler; 43907exports.addHistoryInstrumentationHandler = history.addHistoryInstrumentationHandler; 43908exports.SENTRY_XHR_DATA_KEY = xhr.SENTRY_XHR_DATA_KEY; 43909exports.addXhrInstrumentationHandler = xhr.addXhrInstrumentationHandler; 43910exports.addInstrumentationHandler = addInstrumentationHandler; 43911 43912 43913},{"../debug-build.js":313,"../logger.js":331,"./console.js":321,"./dom.js":322,"./fetch.js":323,"./globalError.js":324,"./globalUnhandledRejection.js":325,"./history.js":326,"./xhr.js":328}],328:[function(require,module,exports){ 43914Object.defineProperty(exports, '__esModule', { value: true }); 43915 43916const is = require('../is.js'); 43917const object = require('../object.js'); 43918const worldwide = require('../worldwide.js'); 43919const _handlers = require('./_handlers.js'); 43920 43921const WINDOW = worldwide.GLOBAL_OBJ ; 43922 43923const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v3__'; 43924 43925/** 43926 * Add an instrumentation handler for when an XHR request happens. 43927 * The handler function is called once when the request starts and once when it ends, 43928 * which can be identified by checking if it has an `endTimestamp`. 43929 * 43930 * Use at your own risk, this might break without changelog notice, only used internally. 43931 * @hidden 43932 */ 43933function addXhrInstrumentationHandler(handler) { 43934 const type = 'xhr'; 43935 _handlers.addHandler(type, handler); 43936 _handlers.maybeInstrument(type, instrumentXHR); 43937} 43938 43939/** Exported only for tests. */ 43940function instrumentXHR() { 43941 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 43942 if (!(WINDOW ).XMLHttpRequest) { 43943 return; 43944 } 43945 43946 const xhrproto = XMLHttpRequest.prototype; 43947 43948 object.fill(xhrproto, 'open', function (originalOpen) { 43949 return function ( ...args) { 43950 const startTimestamp = Date.now(); 43951 43952 // open() should always be called with two or more arguments 43953 // But to be on the safe side, we actually validate this and bail out if we don't have a method & url 43954 const method = is.isString(args[0]) ? args[0].toUpperCase() : undefined; 43955 const url = parseUrl(args[1]); 43956 43957 if (!method || !url) { 43958 return originalOpen.apply(this, args); 43959 } 43960 43961 this[SENTRY_XHR_DATA_KEY] = { 43962 method, 43963 url, 43964 request_headers: {}, 43965 }; 43966 43967 // if Sentry key appears in URL, don't capture it as a request
43968 if (method === 'POST' && url.match(/sentry_key/)) { 43969 this.__sentry_own_request__ = true; 43970 } 43971 43972 const onreadystatechangeHandler = () => { 43973 // For whatever reason, this is not the same instance here as from the outer method 43974 const xhrInfo = this[SENTRY_XHR_DATA_KEY]; 43975 43976 if (!xhrInfo) { 43977 return; 43978 } 43979 43980 if (this.readyState === 4) { 43981 try { 43982 // touching statusCode in some platforms throws 43983 // an exception 43984 xhrInfo.status_code = this.status; 43985 } catch (e) { 43986 /* do nothing */ 43987 } 43988 43989 const handlerData = { 43990 args: [method, url], 43991 endTimestamp: Date.now(), 43992 startTimestamp, 43993 xhr: this, 43994 }; 43995 _handlers.triggerHandlers('xhr', handlerData); 43996 } 43997 }; 43998 43999 if ('onreadystatechange' in this && typeof this.onreadystatechange === 'function') { 44000 object.fill(this, 'onreadystatechange', function (original) { 44001 return function ( ...readyStateArgs) { 44002 onreadystatechangeHandler(); 44003 return original.apply(this, readyStateArgs); 44004 }; 44005 }); 44006 } else { 44007 this.addEventListener('readystatechange', onreadystatechangeHandler); 44008 } 44009 44010 // Intercepting `setRequestHeader` to access the request headers of XHR instance. 44011 // This will only work for user/library defined headers, not for the default/browser-assigned headers. 44012 // Request cookies are also unavailable for XHR, as `Cookie` header can't be defined by `setRequestHeader`. 44013 object.fill(this, 'setRequestHeader', function (original) { 44014 return function ( ...setRequestHeaderArgs) { 44015 const [header, value] = setRequestHeaderArgs; 44016 44017 const xhrInfo = this[SENTRY_XHR_DATA_KEY]; 44018 44019 if (xhrInfo && is.isString(header) && is.isString(value)) { 44020 xhrInfo.request_headers[header.toLowerCase()] = value; 44021 } 44022 44023 return original.apply(this, setRequestHeaderArgs); 44024 }; 44025 }); 44026 44027 return originalOpen.apply(this, args); 44028 }; 44029 }); 44030 44031 object.fill(xhrproto, 'send', function (originalSend) { 44032 return function ( ...args) { 44033 const sentryXhrData = this[SENTRY_XHR_DATA_KEY]; 44034 44035 if (!sentryXhrData) { 44036 return originalSend.apply(this, args); 44037 } 44038 44039 if (args[0] !== undefined) { 44040 sentryXhrData.body = args[0]; 44041 } 44042 44043 const handlerData = { 44044 args: [sentryXhrData.method, sentryXhrData.url], 44045 startTimestamp: Date.now(), 44046 xhr: this, 44047 }; 44048 _handlers.triggerHandlers('xhr', handlerData); 44049 44050 return originalSend.apply(this, args); 44051 }; 44052 }); 44053} 44054 44055function parseUrl(url) { 44056 if (is.isString(url)) { 44057 return url; 44058 } 44059 44060 try { 44061 // url can be a string or URL 44062 // but since URL is not available in IE11, we do not check for it, 44063 // but simply assume it is an URL and return `toString()` from it (which returns the full URL) 44064 // If that fails, we just return undefined 44065 return (url ).toString(); 44066 } catch (e2) {} // eslint-disable-line no-empty 44067 44068 return undefined; 44069} 44070 44071exports.SENTRY_XHR_DATA_KEY = SENTRY_XHR_DATA_KEY; 44072exports.addXhrInstrumentationHandler = addXhrInstrumentationHandler; 44073exports.instrumentXHR = instrumentXHR; 44074 44075 44076},{"../is.js":329,"../object.js":338,"../worldwide.js":354,"./_handlers.js":320}],329:[function(require,module,exports){ 44077Object.defineProperty(exports, '__esModule', { value: true }); 44078 44079// eslint-disable-next-line @typescript-eslint/unbound-method 44080const objectToString = Object.prototype.toString; 44081 44082/** 44083 * Checks whether given value's type is one of a few Error or Error-like 44084 * {@link isError}. 44085 * 44086 * @param wat A value to be checked. 44087 * @returns A boolean representing the result. 44088 */ 44089function isError(wat) { 44090 switch (objectToString.call(wat)) { 44091 case '[object Error]': 44092 case '[object Exception]': 44093 case '[object DOMException]': 44094 return true; 44095 default: 44096 return isInstanceOf(wat, Error); 44097 } 44098} 44099/** 44100 * Checks whether given value is an instance of the given built-in class. 44101 * 44102 * @param wat The value to be checked 44103 * @param className 44104 * @returns A boolean representing the result. 44105 */ 44106function isBuiltin(wat, className) { 44107 return objectToString.call(wat) === `[object ${className}]`; 44108} 44109 44110/** 44111 * Checks whether given value's type is ErrorEvent 44112 * {@link isErrorEvent}. 44113 * 44114 * @param wat A value to be checked. 44115 * @returns A boolean representing the result. 44116 */ 44117function isErrorEvent(wat) { 44118 return isBuiltin(wat, 'ErrorEvent'); 44119} 44120 44121/** 44122 * Checks whether given value's type is DOMError 44123 * {@link isDOMError}. 44124 * 44125 * @param wat A value to be checked. 44126 * @returns A boolean representing the result. 44127 */ 44128function isDOMError(wat) { 44129 return isBuiltin(wat, 'DOMError'); 44130} 44131 44132/** 44133 * Checks whether given value's type is DOMException 44134 * {@link isDOMException}. 44135 * 44136 * @param wat A value to be checked. 44137 * @returns A boolean representing the result. 44138 */ 44139function isDOMException(wat) { 44140 return isBuiltin(wat, 'DOMException'); 44141} 44142 44143/** 44144 * Checks whether given value's type is a string 44145 * {@link isString}. 44146 * 44147 * @param wat A value to be checked. 44148 * @returns A boolean representing the result. 44149 */ 44150function isString(wat) { 44151 return isBuiltin(wat, 'String'); 44152} 44153 44154/** 44155 * Checks whether given string is parameterized 44156 * {@link isParameterizedString}. 44157 * 44158 * @param wat A value to be checked. 44159 * @returns A boolean representing the result. 44160 */ 44161function isParameterizedString(wat) { 44162 return ( 44163 typeof wat === 'object' && 44164 wat !== null &&
44165 '__sentry_template_string__' in wat && 44166 '__sentry_template_values__' in wat 44167 ); 44168} 44169 44170/** 44171 * Checks whether given value is a primitive (undefined, null, number, boolean, string, bigint, symbol) 44172 * {@link isPrimitive}. 44173 * 44174 * @param wat A value to be checked. 44175 * @returns A boolean representing the result. 44176 */ 44177function isPrimitive(wat) { 44178 return wat === null || isParameterizedString(wat) || (typeof wat !== 'object' && typeof wat !== 'function'); 44179} 44180 44181/** 44182 * Checks whether given value's type is an object literal, or a class instance. 44183 * {@link isPlainObject}. 44184 * 44185 * @param wat A value to be checked. 44186 * @returns A boolean representing the result. 44187 */ 44188function isPlainObject(wat) { 44189 return isBuiltin(wat, 'Object'); 44190} 44191 44192/** 44193 * Checks whether given value's type is an Event instance 44194 * {@link isEvent}. 44195 * 44196 * @param wat A value to be checked. 44197 * @returns A boolean representing the result. 44198 */ 44199function isEvent(wat) { 44200 return typeof Event !== 'undefined' && isInstanceOf(wat, Event); 44201} 44202 44203/** 44204 * Checks whether given value's type is an Element instance 44205 * {@link isElement}. 44206 * 44207 * @param wat A value to be checked. 44208 * @returns A boolean representing the result. 44209 */ 44210function isElement(wat) { 44211 return typeof Element !== 'undefined' && isInstanceOf(wat, Element); 44212} 44213 44214/** 44215 * Checks whether given value's type is an regexp 44216 * {@link isRegExp}. 44217 * 44218 * @param wat A value to be checked. 44219 * @returns A boolean representing the result. 44220 */ 44221function isRegExp(wat) { 44222 return isBuiltin(wat, 'RegExp'); 44223} 44224 44225/** 44226 * Checks whether given value has a then function. 44227 * @param wat A value to be checked. 44228 */ 44229function isThenable(wat) { 44230 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 44231 return Boolean(wat && wat.then && typeof wat.then === 'function'); 44232} 44233 44234/** 44235 * Checks whether given value's type is a SyntheticEvent 44236 * {@link isSyntheticEvent}. 44237 * 44238 * @param wat A value to be checked. 44239 * @returns A boolean representing the result. 44240 */ 44241function isSyntheticEvent(wat) { 44242 return isPlainObject(wat) && 'nativeEvent' in wat && 'preventDefault' in wat && 'stopPropagation' in wat; 44243} 44244 44245/** 44246 * Checks whether given value is NaN 44247 * {@link isNaN}. 44248 * 44249 * @param wat A value to be checked. 44250 * @returns A boolean representing the result. 44251 */ 44252function isNaN(wat) { 44253 return typeof wat === 'number' && wat !== wat; 44254} 44255 44256/** 44257 * Checks whether given value's type is an instance of provided constructor. 44258 * {@link isInstanceOf}. 44259 * 44260 * @param wat A value to be checked. 44261 * @param base A constructor to be used in a check. 44262 * @returns A boolean representing the result. 44263 */ 44264function isInstanceOf(wat, base) { 44265 try { 44266 return wat instanceof base; 44267 } catch (_e) { 44268 return false; 44269 } 44270} 44271 44272/** 44273 * Checks whether given value's type is a Vue ViewModel. 44274 * 44275 * @param wat A value to be checked. 44276 * @returns A boolean representing the result. 44277 */ 44278function isVueViewModel(wat) { 44279 // Not using Object.prototype.toString because in Vue 3 it would read the instance's Symbol(Symbol.toStringTag) property. 44280 return !!(typeof wat === 'object' && wat !== null && ((wat ).__isVue || (wat )._isVue)); 44281} 44282 44283exports.isDOMError = isDOMError; 44284exports.isDOMException = isDOMException; 44285exports.isElement = isElement; 44286exports.isError = isError; 44287exports.isErrorEvent = isErrorEvent; 44288exports.isEvent = isEvent; 44289exports.isInstanceOf = isInstanceOf; 44290exports.isNaN = isNaN; 44291exports.isParameterizedString = isParameterizedString; 44292exports.isPlainObject = isPlainObject; 44293exports.isPrimitive = isPrimitive; 44294exports.isRegExp = isRegExp; 44295exports.isString = isString; 44296exports.isSyntheticEvent = isSyntheticEvent; 44297exports.isThenable = isThenable; 44298exports.isVueViewModel = isVueViewModel; 44299 44300 44301},{}],330:[function(require,module,exports){ 44302Object.defineProperty(exports, '__esModule', { value: true }); 44303 44304const node = require('./node.js'); 44305const worldwide = require('./worldwide.js'); 44306 44307/** 44308 * Returns true if we are in the browser. 44309 */ 44310function isBrowser() { 44311 // eslint-disable-next-line no-restricted-globals 44312 return typeof window !== 'undefined' && (!node.isNodeEnv() || isElectronNodeRenderer()); 44313} 44314 44315// Electron renderers with nodeIntegration enabled are detected as Node.js so we specifically test for them 44316function isElectronNodeRenderer() { 44317 return ( 44318 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any 44319 (worldwide.GLOBAL_OBJ ).process !== undefined && ((worldwide.GLOBAL_OBJ ).process ).t
44319ype === 'renderer' 44320 ); 44321} 44322 44323exports.isBrowser = isBrowser; 44324 44325 44326},{"./node.js":336,"./worldwide.js":354}],331:[function(require,module,exports){ 44327Object.defineProperty(exports, '__esModule', { value: true }); 44328 44329const debugBuild = require('./debug-build.js'); 44330const worldwide = require('./worldwide.js'); 44331 44332/** Prefix for logging strings */ 44333const PREFIX = 'Sentry Logger '; 44334 44335const CONSOLE_LEVELS = [ 44336 'debug', 44337 'info', 44338 'warn', 44339 'error', 44340 'log', 44341 'assert', 44342 'trace', 44343] ; 44344 44345/** This may be mutated by the console instrumentation. */ 44346const originalConsoleMethods 44347 44348 = {}; 44349 44350/** JSDoc */ 44351 44352/** 44353 * Temporarily disable sentry console instrumentations. 44354 * 44355 * @param callback The function to run against the original `console` messages 44356 * @returns The results of the callback 44357 */ 44358function consoleSandbox(callback) { 44359 if (!('console' in worldwide.GLOBAL_OBJ)) { 44360 return callback(); 44361 } 44362 44363 const console = worldwide.GLOBAL_OBJ.console ; 44364 const wrappedFuncs = {}; 44365 44366 const wrappedLevels = Object.keys(originalConsoleMethods) ; 44367 44368 // Restore all wrapped console methods
44369 wrappedLevels.forEach(level => { 44370 const originalConsoleMethod = originalConsoleMethods[level] ; 44371 wrappedFuncs[level] = console[level] ; 44372 console[level] = originalConsoleMethod; 44373 }); 44374 44375 try { 44376 return callback(); 44377 } finally { 44378 // Revert restoration to wrapped state 44379 wrappedLevels.forEach(level => { 44380 console[level] = wrappedFuncs[level] ; 44381 }); 44382 } 44383} 44384 44385function makeLogger() { 44386 let enabled = false; 44387 const logger = { 44388 enable: () => { 44389 enabled = true; 44390 }, 44391 disable: () => { 44392 enabled = false; 44393 }, 44394 isEnabled: () => enabled, 44395 }; 44396 44397 if (debugBuild.DEBUG_BUILD) { 44398 CONSOLE_LEVELS.forEach(name => { 44399 // eslint-disable-next-line @typescript-eslint/no-explicit-any 44400 logger[name] = (...args) => { 44401 if (enabled) { 44402 consoleSandbox(() => { 44403 worldwide.GLOBAL_OBJ.console[name](`${PREFIX}[${name}]:`, ...args); 44404 }); 44405 } 44406 }; 44407 }); 44408 } else { 44409 CONSOLE_LEVELS.forEach(name => { 44410 logger[name] = () => undefined; 44411 }); 44412 } 44413 44414 return logger ; 44415} 44416 44417const logger = makeLogger(); 44418 44419exports.CONSOLE_LEVELS = CONSOLE_LEVELS; 44420exports.consoleSandbox = consoleSandbox; 44421exports.logger = logger; 44422exports.originalConsoleMethods = originalConsoleMethods; 44423 44424 44425},{"./debug-build.js":313,"./worldwide.js":354}],332:[function(require,module,exports){ 44426Object.defineProperty(exports, '__esModule', { value: true }); 44427 44428/** A simple Least Recently Used map */ 44429class LRUMap { 44430 44431 constructor( _maxSize) {this._maxSize = _maxSize; 44432 this._cache = new Map(); 44433 } 44434 44435 /** Get the current size of the cache */ 44436 get size() { 44437 return this._cache.size; 44438 } 44439 44440 /** Get an entry or undefined if it was not in the cache. Re-inserts to update the recently used order */ 44441 get(key) { 44442 const value = this._cache.get(key); 44443 if (value === undefined) { 44444 return undefined; 44445 } 44446 // Remove and re-insert to update the order 44447 this._cache.delete(key); 44448 this._cache.set(key, value); 44449 return value; 44450 } 44451 44452 /** Insert an entry and evict an older entry if we've reached maxSize */ 44453 set(key, value) { 44454 if (this._cache.size >= this._maxSize) { 44455 // keys() returns an iterator in insertion order so keys().next() gives us the oldest key 44456 this._cache.delete(this._cache.keys().next().value); 44457 } 44458 this._cache.set(key, value); 44459 } 44460 44461 /** Remove an entry and return the entry if it was in the cache */ 44462 remove(key) { 44463 const value = this._cache.get(key); 44464 if (value) { 44465 this._cache.delete(key); 44466 } 44467 return value; 44468 } 44469 44470 /** Clear all entries */ 44471 clear() { 44472 this._cache.clear(); 44473 } 44474 44475 /** Get all the keys */ 44476 keys() { 44477 return Array.from(this._cache.keys()); 44478 } 44479 44480 /** Get all the values */ 44481 values() { 44482 const values = []; 44483 this._cache.forEach(value => values.push(value)); 44484 return values; 44485 } 44486} 44487 44488exports.LRUMap = LRUMap; 44489 44490 44491},{}],333:[function(require,module,exports){ 44492Object.defineProperty(exports, '__esModule', { value: true }); 44493 44494/* eslint-disable @typescript-eslint/no-unsafe-member-access */ 44495/* eslint-disable @typescript-eslint/no-explicit-any */ 44496 44497/** 44498 * Helper to decycle json objects 44499 */ 44500function memoBuilder() { 44501 const hasWeakSet = typeof WeakSet === 'function'; 44502 const inner = hasWeakSet ? new WeakSet() : []; 44503 function memoize(obj) { 44504 if (hasWeakSet) { 44505 if (inner.has(obj)) { 44506 return true; 44507 } 44508 inner.add(obj); 44509 return false; 44510 } 44511 // eslint-disable-next-line @typescript-eslint/prefer-for-of 44512 for (let i = 0; i < inner.length; i++) { 44513 const value = inner[i]; 44514 if (value === obj) { 44515 return true; 44516 } 44517 } 44518 inner.push(obj); 44519 return false; 44520 } 44521 44522 function unmemoize(obj) { 44523 if (hasWeakSet) { 44524 inner.delete(obj); 44525 } else { 44526 for (let i = 0; i < inner.length; i++) { 44527 if (inner[i] === obj) { 44528 inner.splice(i, 1); 44529 break; 44530 } 44531 } 44532 } 44533 } 44534 return [memoize, unmemoize]; 44535} 44536 44537exports.memoBuilder = memoBuilder; 44538 44539 44540},{}],334:[function(require,module,exports){ 44541Object.defineProperty(exports, '__esModule', { value: true }); 44542 44543const object = require('./object.js'); 44544const string = require('./string.js'); 44545const worldwide = require('./worldwide.js'); 44546 44547/** 44548 * UUID4 generator 44549 * 44550 * @returns string Generated UUID4. 44551 */ 44552function uuid4() { 44553 const gbl = worldwide.GLOBAL_OBJ ; 44554 const crypto = gbl.crypto || gbl.msCrypto; 44555 44556 let getRandomByte = () => Math.random() * 16; 44557 try { 44558 if (crypto && crypto.randomUUID) { 44559 return crypto.randomUUID().replace(/-/g, ''); 44560 } 44561 if (crypto && crypto.getRandomValues) { 44562 getRandomByte = () => { 44563 // crypto.getRandomValues might return undefined instead of the typed array 44564 // in old Chromium versions (e.g. 23.0.1235.0 (151422))
vendor: 5,656 bytes, lines 44565-44715
44565 // However, `typedArray` is still filled in-place. 44566 // @see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#typedarray 44567 const typedArray = new Uint8Array(1); 44568 crypto.getRandomValues(typedArray); 44569 return typedArray[0]; 44570 }; 44571 } 44572 } catch (_) { 44573 // some runtimes can crash invoking crypto 44574 // https://github.com/getsentry/sentry-javascript/issues/8935 44575 } 44576 44577 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 44578 // Concatenating the following numbers as strings results in '10000000100040008000100000000000' 44579 return (([1e7] ) + 1e3 + 4e3 + 8e3 + 1e11).replace(/[018]/g, c => 44580 // eslint-disable-next-line no-bitwise 44581 ((c ) ^ ((getRandomByte() & 15) >> ((c ) / 4))).toString(16), 44582 ); 44583} 44584 44585function getFirstException(event) { 44586 return event.exception && event.exception.values ? event.exception.values[0] : undefined; 44587} 44588 44589/** 44590 * Extracts either message or type+value from an event that can be used for user-facing logs 44591 * @returns event's description 44592 */ 44593function getEventDescription(event) { 44594 const { message, event_id: eventId } = event; 44595 if (message) { 44596 return message; 44597 } 44598 44599 const firstException = getFirstException(event); 44600 if (firstException) { 44601 if (firstException.type && firstException.value) { 44602 return `${firstException.type}: ${firstException.value}`; 44603 } 44604 return firstException.type || firstException.value || eventId || '<unknown>'; 44605 } 44606 return eventId || '<unknown>'; 44607} 44608 44609/** 44610 * Adds exception values, type and value to an synthetic Exception. 44611 * @param event The event to modify. 44612 * @param value Value of the exception. 44613 * @param type Type of the exception. 44614 * @hidden 44615 */ 44616function addExceptionTypeValue(event, value, type) { 44617 const exception = (event.exception = event.exception || {}); 44618 const values = (exception.values = exception.values || []); 44619 const firstException = (values[0] = values[0] || {}); 44620 if (!firstException.value) { 44621 firstException.value = value || ''; 44622 } 44623 if (!firstException.type) { 44624 firstException.type = type || 'Error'; 44625 } 44626} 44627 44628/** 44629 * Adds exception mechanism data to a given event. Uses defaults if the second parameter is not passed. 44630 * 44631 * @param event The event to modify. 44632 * @param newMechanism Mechanism data to add to the event. 44633 * @hidden 44634 */ 44635function addExceptionMechanism(event, newMechanism) { 44636 const firstException = getFirstException(event); 44637 if (!firstException) { 44638 return; 44639 } 44640 44641 const defaultMechanism = { type: 'generic', handled: true }; 44642 const currentMechanism = firstException.mechanism; 44643 firstException.mechanism = { ...defaultMechanism, ...currentMechanism, ...newMechanism }; 44644 44645 if (newMechanism && 'data' in newMechanism) { 44646 const mergedData = { ...(currentMechanism && currentMechanism.data), ...newMechanism.data }; 44647 firstException.mechanism.data = mergedData; 44648 } 44649} 44650 44651// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string 44652const SEMVER_REGEXP = 44653 /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/; 44654 44655/** 44656 * Represents Semantic Versioning object 44657 */ 44658 44659/** 44660 * Parses input into a SemVer interface 44661 * @param input string representation of a semver version 44662 */ 44663function parseSemver(input) { 44664 const match = input.match(SEMVER_REGEXP) || []; 44665 const major = parseInt(match[1], 10); 44666 const minor = parseInt(match[2], 10); 44667 const patch = parseInt(match[3], 10); 44668 return { 44669 buildmetadata: match[5], 44670 major: isNaN(major) ? undefined : major, 44671 minor: isNaN(minor) ? undefined : minor, 44672 patch: isNaN(patch) ? undefined : patch, 44673 prerelease: match[4], 44674 }; 44675} 44676 44677/** 44678 * This function adds context (pre/post/line) lines to the provided frame 44679 * 44680 * @param lines string[] containing all lines 44681 * @param frame StackFrame that will be mutated 44682 * @param linesOfContext number of context lines we want to add pre/post 44683 */ 44684function addContextToFrame(lines, frame, linesOfContext = 5) { 44685 // When there is no line number in the frame, attaching context is nonsensical and will even break grouping 44686 if (frame.lineno === undefined) { 44687 return; 44688 } 44689 44690 const maxLines = lines.length; 44691 const sourceLine = Math.max(Math.min(maxLines - 1, frame.lineno - 1), 0); 44692 44693 frame.pre_context = lines 44694 .slice(Math.max(0, sourceLine - linesOfContext), sourceLine) 44695 .map((line) => string.snipLine(line, 0)); 44696 44697 frame.context_line = string.snipLine(lines[Math.min(maxLines - 1, sourceLine)], frame.colno || 0); 44698 44699 frame.post_context = lines 44700 .slice(Math.min(sourceLine + 1, maxLines), sourceLine + 1 + linesOfContext) 44701 .map((line) => string.snipLine(line, 0)); 44702} 44703 44704/** 44705 * Checks whether or not we've already captured the given exception (note: not an identical exception - the very object 44706 * in question), and marks it captured if not. 44707 * 44708 * This is useful because it's possible for an error to get captured by more than one mechanism. After we intercept and 44709 * record an error, we rethrow it (assuming we've intercepted it before it's reached the top-level global handlers), so 44710 * that we don't interfere with whatever effects the error might have had were the SDK not there. At that point, because 44711 * the error has been rethrown, it's possible for it to bubble up to some other code we've instrumented. If it's not 44712 * caught after that, it will bubble all the way up to the global handlers (which of course we also instrument). This 44713 * function helps us ensure that even if we encounter the same error more than once, we only record it the first time we 44714 * see it. 44715 *
44716 * Note: It will ignore primitives (always return `false` and not mark them as seen), as properties can't be set on 44717 * them. {@link: Object.objectify} can be used on exceptions to convert any that are primitives into their equivalent 44718 * object wrapper forms so that this check will always work. However, because we need to flag the exact object which 44719 * will get rethrown, and because that rethrowing happens outside of the event processing pipeline, the objectification 44720 * must be done before the exception captured. 44721 * 44722 * @param A thrown exception to check or flag as having been seen 44723 * @returns `true` if the exception has already been captured, `false` if not (with the side effect of marking it seen) 44724 */ 44725function checkOrSetAlreadyCaught(exception) { 44726 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 44727 if (exception && (exception ).__sentry_captured__) { 44728 return true; 44729 } 44730 44731 try { 44732 // set it this way rather than by assignment so that it's not ennumerable and therefore isn't recorded by the 44733 // `ExtraErrorData` integration 44734 object.addNonEnumerableProperty(exception , '__sentry_captured__', true); 44735 } catch (err) { 44736 // `exception` is a primitive, so we can't mark it seen 44737 } 44738 44739 return false; 44740} 44741 44742/** 44743 * Checks whether the given input is already an array, and if it isn't, wraps it in one. 44744 * 44745 * @param maybeArray Input to turn into an array, if necessary 44746 * @returns The input, if already an array, or an array with the input as the only element, if not 44747 */ 44748function arrayify(maybeArray) { 44749 return Array.isArray(maybeArray) ? maybeArray : [maybeArray]; 44750} 44751 44752exports.addContextToFrame = addContextToFrame; 44753exports.addExceptionMechanism = addExceptionMechanism; 44754exports.addExceptionTypeValue = addExceptionTypeValue; 44755exports.arrayify = arrayify; 44756exports.checkOrSetAlreadyCaught = checkOrSetAlreadyCaught; 44757exports.getEventDescription = getEventDescription; 44758exports.parseSemver = parseSemver; 44759exports.uuid4 = uuid4; 44760 44761 44762},{"./object.js":338,"./string.js":345,"./worldwide.js":354}],335:[function(require,module,exports){ 44763Object.defineProperty(exports, '__esModule', { value: true }); 44764 44765/** 44766 * Does this filename look like it's part of the app code? 44767 */ 44768function filenameIsInApp(filename, isNative = false) { 44769 const isInternal = 44770 isNative || 44771 (filename && 44772 // It's not internal if it's an absolute linux path 44773 !filename.startsWith('/') && 44774 // It's not internal if it's an absolute windows path 44775 !filename.match(/^[A-Z]:/) && 44776 // It's not internal if the path is starting with a dot 44777 !filename.startsWith('.') && 44778 // It's not internal if the frame has a protocol. In node, this is usually the case if the file got pre-processed with a bundler like webpack 44779 !filename.match(/^[a-zA-Z]([a-zA-Z0-9.\-+])*:\/\//)); // Schema from: https://stackoverflow.com/a/3641782 44780 44781 // in_app is all that's not an internal Node function or a module within node_modules 44782 // note that isNative appears to return true even for node core libraries 44783 // see https://github.com/getsentry/raven-node/issues/176 44784 44785 return !isInternal && filename !== undefined && !filename.includes('node_modules/'); 44786} 44787 44788/** Node Stack line parser */ 44789// eslint-disable-next-line complexity 44790function node(getModule) { 44791 const FILENAME_MATCH = /^\s*[-]{4,}$/; 44792 const FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+):(\d+):(\d+)?|([^)]+))\)?/; 44793 44794 // eslint-disable-next-line complexity 44795 return (line) => { 44796 const lineMatch = line.match(FULL_MATCH); 44797 44798 if (lineMatch) { 44799 let object; 44800 let method; 44801 let functionName; 44802 let typeName; 44803 let methodName; 44804 44805 if (lineMatch[1]) { 44806 functionName = lineMatch[1]; 44807 44808 let methodStart = functionName.lastIndexOf('.'); 44809 if (functionName[methodStart - 1] === '.') { 44810 methodStart--; 44811 } 44812 44813 if (methodStart > 0) { 44814 object = functionName.slice(0, methodStart); 44815 method = functionName.slice(methodStart + 1); 44816 const objectEnd = object.indexOf('.Module'); 44817 if (objectEnd > 0) { 44818 functionName = functionName.slice(objectEnd + 1); 44819 object = object.slice(0, objectEnd); 44820 } 44821 } 44822 typeName = undefined; 44823 } 44824 44825 if (method) { 44826 typeName = object; 44827 methodName = method; 44828 } 44829 44830 if (method === '<anonymous>') { 44831 methodName = undefined; 44832 functionName = undefined; 44833 } 44834 44835 if (functionName === undefined) { 44836 methodName = methodName || '<anonymous>'; 44837 functionName = typeName ? `${typeName}.${methodName}` : methodName; 44838 } 44839 44840 let filename = lineMatch[2] && lineMatch[2].startsWith('file://') ? lineMatch[2].slice(7) : lineMatch[2]; 44841 const isNative = lineMatch[5] === 'native'; 44842 44843 // If it's a Windows path, trim the leading slash so that `/C:/foo` becomes `C:/foo` 44844 if (filename && filename.match(/\/[A-Z]:/)) { 44845 filename = filename.slice(1); 44846 } 44847 44848 if (!filename && lineMatch[5] && !isNative) { 44849 filename = lineMatch[5]; 44850 } 44851 44852 return { 44853 filename, 44854 module: getModule ? getModule(filename) : undefined, 44855 function: functionName, 44856 lineno: parseInt(lineMatch[3], 10) || undefined, 44857 colno: parseInt(lineMatch[4], 10) || undefined, 44858 in_app: filenameIsInApp(filename, isNative), 44859 }; 44860 } 44861 44862 if (line.match(FILENAME_MATCH)) { 44863 return { 44864 filename: line, 44865 }; 44866 } 44867 44868 return undefined; 44869 }; 44870} 44871 44872exports.filenameIsInApp = filenameIsInApp; 44873exports.node = node; 44874 44875 44876},{}],336:[function(require,module,exports){ 44877(function (process){(function (){ 44878Object.defineProperty(exports, '__esModule', { value: true }); 44879 44880const env = require('./env.js'); 44881 44882/** 44883 * NOTE: In order to avoid circular dependencies, if you add a function to this module and it needs to print something, 44884 * you must either a) use `console.log` rather than the logger, or b) put your function elsewhere. 44885 */ 44886 44887/** 44888 * Checks whether we're in the Node.js or Browser environment 44889 * 44890 * @returns Answer to given question 44891 */ 44892function isNodeEnv() { 44893 // explicitly check for browser bundles as those can be optimized statically 44894 // by terser/rollup. 44895 return (
44896 !env.isBrowserBundle() && 44897 Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]' 44898 ); 44899} 44900 44901/** 44902 * Requires a module which is protected against bundler minification. 44903 * 44904 * @param request The module path to resolve 44905 */ 44906// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any 44907function dynamicRequire(mod, request) { 44908 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 44909 return mod.require(request); 44910} 44911 44912/** 44913 * Helper for dynamically loading module that should work with linked dependencies. 44914 * The problem is that we _should_ be using `require(require.resolve(moduleName, { paths: [cwd()] }))` 44915 * However it's _not possible_ to do that with Webpack, as it has to know all the dependencies during 44916 * build time. `require.resolve` is also not available in any other way, so we cannot create, 44917 * a fake helper like we do with `dynamicRequire`. 44918 * 44919 * We always prefer to use local package, thus the value is not returned early from each `try/catch` block. 44920 * That is to mimic the behavior of `require.resolve` exactly. 44921 * 44922 * @param moduleName module name to require 44923 * @returns possibly required module 44924 */ 44925function loadModule(moduleName) { 44926 let mod; 44927 44928 try { 44929 mod = dynamicRequire(module, moduleName); 44930 } catch (e) { 44931 // no-empty 44932 } 44933 44934 try { 44935 const { cwd } = dynamicRequire(module, 'process'); 44936 mod = dynamicRequire(module, `${cwd()}/node_modules/${moduleName}`) ; 44937 } catch (e) { 44938 // no-empty 44939 } 44940 44941 return mod; 44942} 44943 44944exports.dynamicRequire = dynamicRequire; 44945exports.isNodeEnv = isNodeEnv; 44946exports.loadModule = loadModule; 44947 44948 44949}).call(this)}).call(this,require('_process')) 44950},{"./env.js":315,"_process":365}],337:[function(require,module,exports){ 44951(function (global){(function (){ 44952Object.defineProperty(exports, '__esModule', { value: true }); 44953 44954const is = require('./is.js'); 44955const memo = require('./memo.js'); 44956const object = require('./object.js'); 44957const stacktrace = require('./stacktrace.js'); 44958 44959/** 44960 * Recursively normalizes the given object. 44961 * 44962 * - Creates a copy to prevent original input mutation 44963 * - Skips non-enumerable properties 44964 * - When stringifying, calls `toJSON` if implemented 44965 * - Removes circular references 44966 * - Translates non-serializable values (`undefined`/`NaN`/functions) to serializable format 44967 * - Translates known global objects/classes to a string representations 44968 * - Takes care of `Error` object serialization 44969 * - Optionally limits depth of final output 44970 * - Optionally limits number of properties/elements included in any single object/array 44971 * 44972 * @param input The object to be normalized. 44973 * @param depth The max depth to which to normalize the object. (Anything deeper stringified whole.) 44974 * @param maxProperties The max number of elements or properties to be included in any single array or 44975 * object in the normallized output. 44976 * @returns A normalized version of the object, or `"**non-serializable**"` if any errors are thrown during normalization. 44977 */ 44978// eslint-disable-next-line @typescript-eslint/no-explicit-any 44979function normalize(input, depth = 100, maxProperties = +Infinity) { 44980 try { 44981 // since we're at the outermost level, we don't provide a key 44982 return visit('', input, depth, maxProperties); 44983 } catch (err) { 44984 return { ERROR: `**non-serializable** (${err})` }; 44985 } 44986} 44987 44988/** JSDoc */ 44989function normalizeToSize( 44990 // eslint-disable-next-line @typescript-eslint/no-explicit-any 44991 object, 44992 // Default Node.js REPL depth 44993 depth = 3, 44994 // 100kB, as 200kB is max payload size, so half sounds reasonable 44995 maxSize = 100 * 1024, 44996) { 44997 const normalized = normalize(object, depth); 44998 44999 if (jsonSize(normalized) > maxSize) { 45000 return normalizeToSize(object, depth - 1, maxSize); 45001 } 45002 45003 return normalized ; 45004} 45005 45006/** 45007 * Visits a node to perform normalization on it 45008 * 45009 * @param key The key corresponding to the given node 45010 * @param value The node to be visited 45011 * @param depth Optional number indicating the maximum recursion depth 45012 * @param maxProperties Optional maximum number of properties/elements included in any single object/array 45013 * @param memo Optional Memo class handling decycling 45014 */ 45015function visit( 45016 key, 45017 value, 45018 depth = +Infinity, 45019 maxProperties = +Infinity, 45020 memo$1 = memo.memoBuilder(), 45021) { 45022 const [memoize, unmemoize] = memo$1; 45023 45024 // Get the simple cases out of the way first 45025 if ( 45026 value == null || // this matches null and undefined -> eqeq not eqeqeq 45027 (['number', 'boolean', 'string'].includes(typeof value) && !is.isNaN(value)) 45028 ) { 45029 return value ; 45030 } 45031 45032 const stringified = stringifyValue(key, value); 45033 45034 // Anything we could potentially dig into more (objects or arrays) will have come back as `"[object XXXX]"`. 45035 // Everything else will have already been serialized, so if we don't see that pattern, we're done. 45036 if (!stringified.startsWith('[object ')) { 45037 return stringified; 45038 } 45039 45040 // From here on, we can assert that `value` is either an object or an array.
vendor: 6,568 bytes, lines 45041-45224
45041 45042 // Do not normalize objects that we know have already been normalized. As a general rule, the 45043 // "__sentry_skip_normalization__" property should only be used sparingly and only should only be set on objects that 45044 // have already been normalized. 45045 if ((value )['__sentry_skip_normalization__']) { 45046 return value ; 45047 } 45048 45049 // We can set `__sentry_override_normalization_depth__` on an object to ensure that from there 45050 // We keep a certain amount of depth. 45051 // This should be used sparingly, e.g. we use it for the redux integration to ensure we get a certain amount of state. 45052 const remainingDepth = 45053 typeof (value )['__sentry_override_normalization_depth__'] === 'number' 45054 ? ((value )['__sentry_override_normalization_depth__'] ) 45055 : depth; 45056 45057 // We're also done if we've reached the max depth 45058 if (remainingDepth === 0) { 45059 // At this point we know `serialized` is a string of the form `"[object XXXX]"`. Clean it up so it's just `"[XXXX]"`. 45060 return stringified.replace('object ', ''); 45061 } 45062 45063 // If we've already visited this branch, bail out, as it's circular reference. If not, note that we're seeing it now. 45064 if (memoize(value)) { 45065 return '[Circular ~]'; 45066 } 45067 45068 // If the value has a `toJSON` method, we call it to extract more information 45069 const valueWithToJSON = value ; 45070 if (valueWithToJSON && typeof valueWithToJSON.toJSON === 'function') { 45071 try { 45072 const jsonValue = valueWithToJSON.toJSON(); 45073 // We need to normalize the return value of `.toJSON()` in case it has circular references 45074 return visit('', jsonValue, remainingDepth - 1, maxProperties, memo$1); 45075 } catch (err) { 45076 // pass (The built-in `toJSON` failed, but we can still try to do it ourselves) 45077 } 45078 } 45079 45080 // At this point we know we either have an object or an array, we haven't seen it before, and we're going to recurse 45081 // because we haven't yet reached the max depth. Create an accumulator to hold the results of visiting each 45082 // property/entry, and keep track of the number of items we add to it. 45083 const normalized = (Array.isArray(value) ? [] : {}) ; 45084 let numAdded = 0; 45085 45086 // Before we begin, convert`Error` and`Event` instances into plain objects, since some of each of their relevant 45087 // properties are non-enumerable and otherwise would get missed. 45088 const visitable = object.convertToPlainObject(value ); 45089 45090 for (const visitKey in visitable) { 45091 // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration. 45092 if (!Object.prototype.hasOwnProperty.call(visitable, visitKey)) { 45093 continue; 45094 } 45095 45096 if (numAdded >= maxProperties) { 45097 normalized[visitKey] = '[MaxProperties ~]'; 45098 break; 45099 } 45100 45101 // Recursively visit all the child nodes 45102 const visitValue = visitable[visitKey]; 45103 normalized[visitKey] = visit(visitKey, visitValue, remainingDepth - 1, maxProperties, memo$1); 45104 45105 numAdded++; 45106 } 45107 45108 // Once we've visited all the branches, remove the parent from memo storage 45109 unmemoize(value); 45110 45111 // Return accumulated values 45112 return normalized; 45113} 45114 45115/* eslint-disable complexity */ 45116/** 45117 * Stringify the given value. Handles various known special values and types. 45118 * 45119 * Not meant to be used on simple primitives which already have a string representation, as it will, for example, turn 45120 * the number 1231 into "[Object Number]", nor on `null`, as it will throw. 45121 * 45122 * @param value The value to stringify 45123 * @returns A stringified representation of the given value 45124 */ 45125function stringifyValue( 45126 key, 45127 // this type is a tiny bit of a cheat, since this function does handle NaN (which is technically a number), but for 45128 // our internal use, it'll do 45129 value, 45130) { 45131 try { 45132 if (key === 'domain' && value && typeof value === 'object' && (value )._events) { 45133 return '[Domain]'; 45134 } 45135 45136 if (key === 'domainEmitter') { 45137 return '[DomainEmitter]'; 45138 } 45139 45140 // It's safe to use `global`, `window`, and `document` here in this manner, as we are asserting using `typeof` first 45141 // which won't throw if they are not present. 45142 45143 if (typeof global !== 'undefined' && value === global) { 45144 return '[Global]'; 45145 } 45146 45147 // eslint-disable-next-line no-restricted-globals 45148 if (typeof window !== 'undefined' && value === window) { 45149 return '[Window]'; 45150 } 45151 45152 // eslint-disable-next-line no-restricted-globals 45153 if (typeof document !== 'undefined' && value === document) { 45154 return '[Document]'; 45155 } 45156 45157 if (is.isVueViewModel(value)) { 45158 return '[VueViewModel]'; 45159 } 45160 45161 // React's SyntheticEvent thingy 45162 if (is.isSyntheticEvent(value)) { 45163 return '[SyntheticEvent]'; 45164 } 45165 45166 if (typeof value === 'number' && value !== value) { 45167 return '[NaN]'; 45168 } 45169 45170 if (typeof value === 'function') { 45171 return `[Function: ${stacktrace.getFunctionName(value)}]`; 45172 } 45173 45174 if (typeof value === 'symbol') { 45175 return `[${String(value)}]`; 45176 } 45177 45178 // stringified BigInts are indistinguishable from regular numbers, so we need to label them to avoid confusion 45179 if (typeof value === 'bigint') { 45180 return `[BigInt: ${String(value)}]`; 45181 } 45182 45183 // Now that we've knocked out all the special cases and the primitives, all we have left are objects. Simply casting 45184 // them to strings means that instances of classes which haven't defined their `toStringTag` will just come out as 45185 // `"[object Object]"`. If we instead look at the constructor's name (which is the same as the name of the class), 45186 // we can make sure that only plain objects come out that way. 45187 const objName = getConstructorName(value); 45188 45189 // Handle HTML Elements 45190 if (/^HTML(\w*)Element$/.test(objName)) { 45191 return `[HTMLElement: ${objName}]`; 45192 } 45193 45194 return `[object ${objName}]`; 45195 } catch (err) { 45196 return `**non-serializable** (${err})`; 45197 } 45198} 45199/* eslint-enable complexity */ 45200 45201function getConstructorName(value) { 45202 const prototype = Object.getPrototypeOf(value); 45203 45204 return prototype ? prototype.constructor.name : 'null prototype'; 45205} 45206 45207/** Calculates bytes size of input string */ 45208function utf8Length(value) { 45209 // eslint-disable-next-line no-bitwise 45210 return ~-encodeURI(value).split(/%..|./).length; 45211} 45212 45213/** Calculates bytes size of input object */ 45214// eslint-disable-next-line @typescript-eslint/no-explicit-any 45215function jsonSize(value) { 45216 return utf8Length(JSON.stringify(value)); 45217} 45218 45219/** 45220 * Normalizes URLs in exceptions and stacktraces to a base path so Sentry can fingerprint 45221 * across platforms and working directory. 45222 * 45223 * @param url The URL to be normalized. 45224 * @param basePath The application base path.
45225 * @returns The normalized URL. 45226 */ 45227function normalizeUrlToBase(url, basePath) { 45228 const escapedBase = basePath 45229 // Backslash to forward 45230 .replace(/\\/g, '/') 45231 // Escape RegExp special characters 45232 .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); 45233 45234 let newUrl = url; 45235 try { 45236 newUrl = decodeURI(url); 45237 } catch (_Oo) { 45238 // Sometime this breaks 45239 } 45240 return ( 45241 newUrl 45242 .replace(/\\/g, '/') 45243 .replace(/webpack:\/?/g, '') // Remove intermediate base path 45244 // eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor 45245 .replace(new RegExp(`(file://)?/*${escapedBase}/*`, 'ig'), 'app:///') 45246 ); 45247} 45248 45249exports.normalize = normalize; 45250exports.normalizeToSize = normalizeToSize; 45251exports.normalizeUrlToBase = normalizeUrlToBase; 45252exports.walk = visit; 45253 45254 45255}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 45256},{"./is.js":329,"./memo.js":333,"./object.js":338,"./stacktrace.js":344}],338:[function(require,module,exports){ 45257Object.defineProperty(exports, '__esModule', { value: true }); 45258 45259const browser = require('./browser.js'); 45260const debugBuild = require('./debug-build.js'); 45261const is = require('./is.js'); 45262const logger = require('./logger.js'); 45263const string = require('./string.js'); 45264 45265/** 45266 * Replace a method in an object with a wrapped version of itself. 45267 * 45268 * @param source An object that contains a method to be wrapped. 45269 * @param name The name of the method to be wrapped. 45270 * @param replacementFactory A higher-order function that takes the original version of the given method and returns a 45271 * wrapped version. Note: The function returned by `replacementFactory` needs to be a non-arrow function, in order to 45272 * preserve the correct value of `this`, and the original method must be called using `origMethod.call(this, <other 45273 * args>)` or `origMethod.apply(this, [<other args>])` (rather than being called directly), again to preserve `this`. 45274 * @returns void 45275 */ 45276function fill(source, name, replacementFactory) { 45277 if (!(name in source)) { 45278 return; 45279 } 45280 45281 const original = source[name] ; 45282 const wrapped = replacementFactory(original) ; 45283 45284 // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work 45285 // otherwise it'll throw "TypeError: Object.defineProperties called on non-object" 45286 if (typeof wrapped === 'function') { 45287 markFunctionWrapped(wrapped, original); 45288 } 45289 45290 source[name] = wrapped; 45291} 45292 45293/** 45294 * Defines a non-enumerable property on the given object. 45295 * 45296 * @param obj The object on which to set the property 45297 * @param name The name of the property to be set 45298 * @param value The value to which to set the property 45299 */ 45300function addNonEnumerableProperty(obj, name, value) { 45301 try { 45302 Object.defineProperty(obj, name, { 45303 // enumerable: false, // the default, so we can save on bundle size by not explicitly setting it 45304 value: value, 45305 writable: true, 45306 configurable: true, 45307 }); 45308 } catch (o_O) { 45309 debugBuild.DEBUG_BUILD && logger.logger.log(`Failed to add non-enumerable property "${name}" to object`, obj); 45310 } 45311} 45312 45313/** 45314 * Remembers the original function on the wrapped function and 45315 * patches up the prototype. 45316 * 45317 * @param wrapped the wrapper function 45318 * @param original the original function that gets wrapped 45319 */ 45320function markFunctionWrapped(wrapped, original) { 45321 try { 45322 const proto = original.prototype || {}; 45323 wrapped.prototype = original.prototype = proto; 45324 addNonEnumerableProperty(wrapped, '__sentry_original__', original); 45325 } catch (o_O) {} // eslint-disable-line no-empty 45326} 45327 45328/** 45329 * This extracts the original function if available. See 45330 * `markFunctionWrapped` for more information. 45331 * 45332 * @param func the function to unwrap 45333 * @returns the unwrapped version of the function if available. 45334 */ 45335function getOriginalFunction(func) { 45336 return func.__sentry_original__; 45337} 45338 45339/** 45340 * Encodes given object into url-friendly format 45341 * 45342 * @param object An object that contains serializable values 45343 * @returns string Encoded 45344 */ 45345function urlEncode(object) { 45346 return Object.keys(object) 45347 .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(object[key])}`) 45348 .join('&'); 45349} 45350 45351/** 45352 * Transforms any `Error` or `Event` into a plain object with all of their enumerable properties, and some of their 45353 * non-enumerable properties attached.
45354 * 45355 * @param value Initial source that we have to transform in order for it to be usable by the serializer 45356 * @returns An Event or Error turned into an object - or the value argurment itself, when value is neither an Event nor 45357 * an Error. 45358 */ 45359function convertToPlainObject( 45360 value, 45361) 45362 45363 { 45364 if (is.isError(value)) { 45365 return { 45366 message: value.message, 45367 name: value.name, 45368 stack: value.stack, 45369 ...getOwnProperties(value), 45370 }; 45371 } else if (is.isEvent(value)) { 45372 const newObj 45373 45374 = { 45375 type: value.type, 45376 target: serializeEventTarget(value.target), 45377 currentTarget: serializeEventTarget(value.currentTarget), 45378 ...getOwnProperties(value), 45379 }; 45380 45381 if (typeof CustomEvent !== 'undefined' && is.isInstanceOf(value, CustomEvent)) { 45382 newObj.detail = value.detail; 45383 } 45384 45385 return newObj; 45386 } else { 45387 return value; 45388 } 45389} 45390 45391/** Creates a string representation of the target of an `Event` object */ 45392function serializeEventTarget(target) { 45393 try { 45394 return is.isElement(target) ? browser.htmlTreeAsString(target) : Object.prototype.toString.call(target); 45395 } catch (_oO) { 45396 return '<unknown>'; 45397 } 45398} 45399 45400/** Filters out all but an object's own properties */ 45401function getOwnProperties(obj) { 45402 if (typeof obj === 'object' && obj !== null) { 45403 const extractedProps = {}; 45404 for (const property in obj) { 45405 if (Object.prototype.hasOwnProperty.call(obj, property)) { 45406 extractedProps[property] = (obj )[property]; 45407 } 45408 } 45409 return extractedProps; 45410 } else { 45411 return {}; 45412 } 45413} 45414 45415/** 45416 * Given any captured exception, extract its keys and create a sorted 45417 * and truncated list that will be used inside the event message. 45418 * eg. `Non-error exception captured with keys: foo, bar, baz` 45419 */ 45420function extractExceptionKeysForMessage(exception, maxLength = 40) { 45421 const keys = Object.keys(convertToPlainObject(exception)); 45422 keys.sort(); 45423 45424 if (!keys.length) { 45425 return '[object has no keys]'; 45426 } 45427 45428 if (keys[0].length >= maxLength) { 45429 return string.truncate(keys[0], maxLength); 45430 } 45431 45432 for (let includedKeys = keys.length; includedKeys > 0; includedKeys--) { 45433 const serialized = keys.slice(0, includedKeys).join(', '); 45434 if (serialized.length > maxLength) { 45435 continue; 45436 } 45437 if (includedKeys === keys.length) { 45438 return serialized; 45439 } 45440 return string.truncate(serialized, maxLength); 45441 } 45442 45443 return ''; 45444} 45445 45446/** 45447 * Given any object, return a new object having removed all fields whose value was `undefined`. 45448 * Works recursively on objects and arrays. 45449 * 45450 * Attention: This function keeps circular references in the returned object. 45451 */ 45452function dropUndefinedKeys(inputValue) { 45453 // This map keeps track of what already visited nodes map to. 45454 // Our Set - based memoBuilder doesn't work here because we want to the output object to have the same circular 45455 // references as the input object. 45456 const memoizationMap = new Map(); 45457 45458 // This function just proxies `_dropUndefinedKeys` to keep the `memoBuilder` out of this function's API 45459 return _dropUndefinedKeys(inputValue, memoizationMap); 45460} 45461 45462function _dropUndefinedKeys(inputValue, memoizationMap) { 45463 if (isPojo(inputValue)) { 45464 // If this node has already been visited due to a circular reference, return the object it was mapped to in the new object 45465 const memoVal = memoizationMap.get(inputValue); 45466 if (memoVal !== undefined) { 45467 return memoVal ; 45468 } 45469 45470 const returnValue = {}; 45471 // Store the mapping of this value in case we visit it again, in case of circular data 45472 memoizationMap.set(inputValue, returnValue); 45473 45474 for (const key of Object.keys(inputValue)) { 45475 if (typeof inputValue[key] !== 'undefined') { 45476 returnValue[key] = _dropUndefinedKeys(inputValue[key], memoizationMap); 45477 } 45478 } 45479 45480 return returnValue ; 45481 } 45482 45483 if (Array.isArray(inputValue)) { 45484 // If this node has already been visited due to a circular reference, return the array it was mapped to in the new object 45485 const memoVal = memoizationMap.get(inputValue); 45486 if (memoVal !== undefined) { 45487 return memoVal ; 45488 } 45489 45490 const returnValue = []; 45491 // Store the mapping of this value in case we visit it again, in case of circular data 45492 memoizationMap.set(inputValue, returnValue); 45493 45494 inputValue.forEach((item) => { 45495 returnValue.push(_dropUndefinedKeys(item, memoizationMap)); 45496 }); 45497 45498 return returnValue ; 45499 } 45500 45501 return inputValue; 45502} 45503 45504function isPojo(input) { 45505 if (!is.isPlainObject(input)) { 45506 return false;
45507 } 45508 45509 try { 45510 const name = (Object.getPrototypeOf(input) ).constructor.name; 45511 return !name || name === 'Object'; 45512 } catch (e) { 45513 return true; 45514 } 45515} 45516 45517/** 45518 * Ensure that something is an object. 45519 * 45520 * Turns `undefined` and `null` into `String`s and all other primitives into instances of their respective wrapper 45521 * classes (String, Boolean, Number, etc.). Acts as the identity function on non-primitives. 45522 * 45523 * @param wat The subject of the objectification 45524 * @returns A version of `wat` which can safely be used with `Object` class methods 45525 */ 45526function objectify(wat) { 45527 let objectified; 45528 switch (true) { 45529 case wat === undefined || wat === null: 45530 objectified = new String(wat); 45531 break; 45532 45533 // Though symbols and bigints do have wrapper classes (`Symbol` and `BigInt`, respectively), for whatever reason 45534 // those classes don't have constructors which can be used with the `new` keyword. We therefore need to cast each as 45535 // an object in order to wrap it. 45536 case typeof wat === 'symbol' || typeof wat === 'bigint': 45537 objectified = Object(wat); 45538 break; 45539 45540 // this will catch the remaining primitives: `String`, `Number`, and `Boolean` 45541 case is.isPrimitive(wat): 45542 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 45543 objectified = new (wat ).constructor(wat); 45544 break; 45545 45546 // by process of elimination, at this point we know that `wat` must already be an object 45547 default: 45548 objectified = wat; 45549 break; 45550 } 45551 return objectified; 45552} 45553 45554exports.addNonEnumerableProperty = addNonEnumerableProperty; 45555exports.convertToPlainObject = convertToPlainObject; 45556exports.dropUndefinedKeys = dropUndefinedKeys; 45557exports.extractExceptionKeysForMessage = extractExceptionKeysForMessage; 45558exports.fill = fill; 45559exports.getOriginalFunction = getOriginalFunction; 45560exports.markFunctionWrapped = markFunctionWrapped; 45561exports.objectify = objectify; 45562exports.urlEncode = urlEncode; 45563 45564 45565},{"./browser.js":303,"./debug-build.js":313,"./is.js":329,"./logger.js":331,"./string.js":345}],339:[function(require,module,exports){ 45566Object.defineProperty(exports, '__esModule', { value: true }); 45567 45568// Slightly modified (no IE8 support, ES6) and transcribed to TypeScript 45569// https://github.com/calvinmetcalf/rollup-plugin-node-builtins/blob/63ab8aacd013767445ca299e468d9a60a95328d7/src/es6/path.js 45570// 45571// Copyright Joyent, Inc.and other Node contributors. 45572// 45573// Permission is hereby granted, free of charge, to any person obtaining a 45574// copy of this software and associated documentation files (the 45575// "Software"), to deal in the Software without restriction, including 45576// without limitation the rights to use, copy, modify, merge, publish, 45577// distribute, sublicense, and/or sell copies of the Software, and to permit 45578// persons to whom the Software is furnished to do so, subject to the 45579// following conditions: 45580// 45581// The above copyright notice and this permission notice shall be included 45582// in all copies or substantial portions of the Software. 45583// 45584// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 45585// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 45586// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 45587// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 45588// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 45589// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 45590// USE OR OTHER DEALINGS IN THE SOFTWARE. 45591 45592/** JSDoc */ 45593function normalizeArray(parts, allowAboveRoot) { 45594 // if the path tries to go above the root, `up` ends up > 0 45595 let up = 0; 45596 for (let i = parts.length - 1; i >= 0; i--) { 45597 const last = parts[i]; 45598 if (last === '.') { 45599 parts.splice(i, 1); 45600 } else if (last === '..') { 45601 parts.splice(i, 1); 45602 up++; 45603 } else if (up) { 45604 parts.splice(i, 1); 45605 up--; 45606 } 45607 } 45608 45609 // if the path is allowed to go above the root, restore leading ..s 45610 if (allowAboveRoot) { 45611 for (; up--; up) { 45612 parts.unshift('..'); 45613 } 45614 } 45615 45616 return parts; 45617} 45618 45619// Split a filename into [root, dir, basename, ext], unix version 45620// 'root' is just a slash, or nothing. 45621const splitPathRe = /^(\S+:\\|\/?)([\s\S]*?)((?:\.{1,2}|[^/\\]+?|)(\.[^./\\]*|))(?:[/\\]*)$/; 45622/** JSDoc */ 45623function splitPath(filename) { 45624 // Truncate files names greater than 1024 characters to avoid regex dos 45625 // https://github.com/getsentry/sentry-javascript/pull/8737#discussion_r1285719172 45626 const truncated = filename.length > 1024 ? `<truncated>${filename.slice(-1024)}` : filename; 45627 const parts = splitPathRe.exec(truncated); 45628 return parts ? parts.slice(1) : []; 45629} 45630 45631// path.resolve([from ...], to) 45632// posix version 45633/** JSDoc */ 45634function resolve(...args) { 45635 let resolvedPath = ''; 45636 let resolvedAbsolute = false;
vendor: 5,354 bytes, lines 45637-45841
45637 45638 for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { 45639 const path = i >= 0 ? args[i] : '/'; 45640 45641 // Skip empty entries 45642 if (!path) { 45643 continue; 45644 } 45645 45646 resolvedPath = `${path}/${resolvedPath}`; 45647 resolvedAbsolute = path.charAt(0) === '/'; 45648 } 45649 45650 // At this point the path should be resolved to a full absolute path, but 45651 // handle relative paths to be safe (might happen when process.cwd() fails) 45652 45653 // Normalize the path 45654 resolvedPath = normalizeArray( 45655 resolvedPath.split('/').filter(p => !!p), 45656 !resolvedAbsolute, 45657 ).join('/'); 45658 45659 return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'; 45660} 45661 45662/** JSDoc */ 45663function trim(arr) { 45664 let start = 0; 45665 for (; start < arr.length; start++) { 45666 if (arr[start] !== '') { 45667 break; 45668 } 45669 } 45670 45671 let end = arr.length - 1; 45672 for (; end >= 0; end--) { 45673 if (arr[end] !== '') { 45674 break; 45675 } 45676 } 45677 45678 if (start > end) { 45679 return []; 45680 } 45681 return arr.slice(start, end - start + 1); 45682} 45683 45684// path.relative(from, to) 45685// posix version 45686/** JSDoc */ 45687function relative(from, to) { 45688 /* eslint-disable no-param-reassign */ 45689 from = resolve(from).slice(1); 45690 to = resolve(to).slice(1); 45691 /* eslint-enable no-param-reassign */ 45692 45693 const fromParts = trim(from.split('/')); 45694 const toParts = trim(to.split('/')); 45695 45696 const length = Math.min(fromParts.length, toParts.length); 45697 let samePartsLength = length; 45698 for (let i = 0; i < length; i++) { 45699 if (fromParts[i] !== toParts[i]) { 45700 samePartsLength = i; 45701 break; 45702 } 45703 } 45704 45705 let outputParts = []; 45706 for (let i = samePartsLength; i < fromParts.length; i++) { 45707 outputParts.push('..'); 45708 } 45709 45710 outputParts = outputParts.concat(toParts.slice(samePartsLength)); 45711 45712 return outputParts.join('/'); 45713} 45714 45715// path.normalize(path) 45716// posix version 45717/** JSDoc */ 45718function normalizePath(path) { 45719 const isPathAbsolute = isAbsolute(path); 45720 const trailingSlash = path.slice(-1) === '/'; 45721 45722 // Normalize the path 45723 let normalizedPath = normalizeArray( 45724 path.split('/').filter(p => !!p), 45725 !isPathAbsolute, 45726 ).join('/'); 45727 45728 if (!normalizedPath && !isPathAbsolute) { 45729 normalizedPath = '.'; 45730 } 45731 if (normalizedPath && trailingSlash) { 45732 normalizedPath += '/'; 45733 } 45734 45735 return (isPathAbsolute ? '/' : '') + normalizedPath; 45736} 45737 45738// posix version 45739/** JSDoc */ 45740function isAbsolute(path) { 45741 return path.charAt(0) === '/'; 45742} 45743 45744// posix version 45745/** JSDoc */ 45746function join(...args) { 45747 return normalizePath(args.join('/')); 45748} 45749 45750/** JSDoc */ 45751function dirname(path) { 45752 const result = splitPath(path); 45753 const root = result[0]; 45754 let dir = result[1]; 45755 45756 if (!root && !dir) { 45757 // No dirname whatsoever 45758 return '.'; 45759 } 45760 45761 if (dir) { 45762 // It has a dirname, strip trailing slash 45763 dir = dir.slice(0, dir.length - 1); 45764 } 45765 45766 return root + dir; 45767} 45768 45769/** JSDoc */ 45770function basename(path, ext) { 45771 let f = splitPath(path)[2]; 45772 if (ext && f.slice(ext.length * -1) === ext) { 45773 f = f.slice(0, f.length - ext.length); 45774 } 45775 return f; 45776} 45777 45778exports.basename = basename; 45779exports.dirname = dirname; 45780exports.isAbsolute = isAbsolute; 45781exports.join = join; 45782exports.normalizePath = normalizePath; 45783exports.relative = relative; 45784exports.resolve = resolve; 45785 45786 45787},{}],340:[function(require,module,exports){ 45788Object.defineProperty(exports, '__esModule', { value: true }); 45789 45790const error = require('./error.js'); 45791const syncpromise = require('./syncpromise.js'); 45792 45793/** 45794 * Creates an new PromiseBuffer object with the specified limit 45795 * @param limit max number of promises that can be stored in the buffer 45796 */ 45797function makePromiseBuffer(limit) { 45798 const buffer = []; 45799 45800 function isReady() { 45801 return limit === undefined || buffer.length < limit; 45802 } 45803 45804 /** 45805 * Remove a promise from the queue. 45806 * 45807 * @param task Can be any PromiseLike<T> 45808 * @returns Removed promise. 45809 */ 45810 function remove(task) { 45811 return buffer.splice(buffer.indexOf(task), 1)[0]; 45812 } 45813 45814 /** 45815 * Add a promise (representing an in-flight action) to the queue, and set it to remove itself on fulfillment. 45816 * 45817 * @param taskProducer A function producing any PromiseLike<T>; In previous versions this used to be `task: 45818 * PromiseLike<T>`, but under that model, Promises were instantly created on the call-site and their executor 45819 * functions therefore ran immediately. Thus, even if the buffer was full, the action still happened. By 45820 * requiring the promise to be wrapped in a function, we can defer promise creation until after the buffer 45821 * limit check. 45822 * @returns The original promise. 45823 */ 45824 function add(taskProducer) { 45825 if (!isReady()) { 45826 return syncpromise.rejectedSyncPromise(new error.SentryError('Not adding Promise because buffer limit was reached.')); 45827 } 45828 45829 // start the task and add its promise to the queue 45830 const task = taskProducer(); 45831 if (buffer.indexOf(task) === -1) { 45832 buffer.push(task); 45833 } 45834 void task 45835 .then(() => remove(task)) 45836 // Use `then(null, rejectionHandler)` rather than `catch(rejectionHandler)` so that we can use `PromiseLike` 45837 // rather than `Promise`. `PromiseLike` doesn't have a `.catch` method, making its polyfill smaller. (ES5 didn't 45838 // have promises, so TS has to polyfill when down-compiling.) 45839 .then(null, () => 45840 remove(task).then(null, () => { 45841 // We have to add another catch here because `remove()` starts a new promise chain.
45842 }), 45843 ); 45844 return task; 45845 } 45846 45847 /** 45848 * Wait for all promises in the queue to resolve or for timeout to expire, whichever comes first. 45849 * 45850 * @param timeout The time, in ms, after which to resolve to `false` if the queue is still non-empty. Passing `0` (or 45851 * not passing anything) will make the promise wait as long as it takes for the queue to drain before resolving to 45852 * `true`. 45853 * @returns A promise which will resolve to `true` if the queue is already empty or drains before the timeout, and 45854 * `false` otherwise 45855 */ 45856 function drain(timeout) { 45857 return new syncpromise.SyncPromise((resolve, reject) => { 45858 let counter = buffer.length; 45859 45860 if (!counter) { 45861 return resolve(true); 45862 } 45863 45864 // wait for `timeout` ms and then resolve to `false` (if not cancelled first) 45865 const capturedSetTimeout = setTimeout(() => { 45866 if (timeout && timeout > 0) { 45867 resolve(false); 45868 } 45869 }, timeout); 45870 45871 // if all promises resolve in time, cancel the timer and resolve to `true` 45872 buffer.forEach(item => { 45873 void syncpromise.resolvedSyncPromise(item).then(() => { 45874 if (!--counter) { 45875 clearTimeout(capturedSetTimeout); 45876 resolve(true); 45877 } 45878 }, reject); 45879 }); 45880 }); 45881 } 45882 45883 return { 45884 $: buffer, 45885 add, 45886 drain, 45887 }; 45888} 45889 45890exports.makePromiseBuffer = makePromiseBuffer; 45891 45892 45893},{"./error.js":317,"./syncpromise.js":347}],341:[function(require,module,exports){ 45894Object.defineProperty(exports, '__esModule', { value: true }); 45895 45896// Intentionally keeping the key broad, as we don't know for sure what rate limit headers get returned from backend 45897 45898const DEFAULT_RETRY_AFTER = 60 * 1000; // 60 seconds 45899 45900/** 45901 * Extracts Retry-After value from the request header or returns default value 45902 * @param header string representation of 'Retry-After' header 45903 * @param now current unix timestamp 45904 * 45905 */ 45906function parseRetryAfterHeader(header, now = Date.now()) { 45907 const headerDelay = parseInt(`${header}`, 10); 45908 if (!isNaN(headerDelay)) { 45909 return headerDelay * 1000; 45910 } 45911 45912 const headerDate = Date.parse(`${header}`); 45913 if (!isNaN(headerDate)) { 45914 return headerDate - now; 45915 } 45916 45917 return DEFAULT_RETRY_AFTER; 45918} 45919 45920/** 45921 * Gets the time that the given category is disabled until for rate limiting. 45922 * In case no category-specific limit is set but a general rate limit across all categories is active, 45923 * that time is returned. 45924 * 45925 * @return the time in ms that the category is disabled until or 0 if there's no active rate limit. 45926 */ 45927function disabledUntil(limits, category) { 45928 return limits[category] || limits.all || 0; 45929} 45930 45931/** 45932 * Checks if a category is rate limited 45933 */ 45934function isRateLimited(limits, category, now = Date.now()) { 45935 return disabledUntil(limits, category) > now; 45936} 45937 45938/** 45939 * Update ratelimits from incoming headers. 45940 * 45941 * @return the updated RateLimits object. 45942 */ 45943function updateRateLimits( 45944 limits, 45945 { statusCode, headers }, 45946 now = Date.now(), 45947) { 45948 const updatedRateLimits = { 45949 ...limits, 45950 }; 45951 45952 // "The name is case-insensitive." 45953 // https://developer.mozilla.org/en-US/docs/Web/API/Headers/get 45954 const rateLimitHeader = headers && headers['x-sentry-rate-limits']; 45955 const retryAfterHeader = headers && headers['retry-after']; 45956 45957 if (rateLimitHeader) { 45958 /** 45959 * rate limit headers are of the form 45960 * <header>,<header>,.. 45961 * where each <header> is of the form 45962 * <retry_after>: <categories>: <scope>: <reason_code> 45963 * where 45964 * <retry_after> is a delay in seconds 45965 * <categories> is the event type(s) (error, transaction, etc) being rate limited and is of the form 45966 * <category>;<category>;... 45967 * <scope> is what's being limited (org, project, or key) - ignored by SDK 45968 * <reason_code> is an arbitrary string like "org_quota" - ignored by SDK 45969 */ 45970 for (const limit of rateLimitHeader.trim().split(',')) { 45971 const [retryAfter, categories] = limit.split(':', 2); 45972 const headerDelay = parseInt(retryAfter, 10); 45973 const delay = (!isNaN(headerDelay) ? headerDelay : 60) * 1000; // 60sec default 45974 if (!categories) { 45975 updatedRateLimits.all = now + delay; 45976 } else { 45977 for (const category of categories.split(';')) { 45978 updatedRateLimits[category] = now + delay; 45979 } 45980 } 45981 } 45982 } else if (retryAfterHeader) { 45983 updatedRateLimits.all = now + parseRetryAfterHeader(retryAfterHeader, now); 45984 } else if (statusCode === 429) { 45985 updatedRateLimits.all = now + 60 * 1000; 45986 } 45987 45988 return updatedRateLimits; 45989} 45990 45991exports.DEFAULT_RETRY_AFTER = DEFAULT_RETRY_AFTER; 45992exports.disabledUntil = disabledUntil; 45993exports.isRateLimited = isRateLimited; 45994exports.parseRetryAfterHeader = parseRetryAfterHeader; 45995exports.updateRateLimits = updateRateLimits; 45996 45997 45998},{}],342:[function(require,module,exports){ 45999Object.defineProperty(exports, '__esModule', { value: true }); 46000 46001const cookie = require('./cookie.js'); 46002const debugBuild = require('./debug-build.js'); 46003const is = require('./is.js'); 46004const logger = require('./logger.js'); 46005const normalize = require('./normalize.js'); 46006const url = require('./url.js'); 46007 46008const DEFAULT_INCLUDES = { 46009 ip: false, 46010 request: true, 46011 transaction: true, 46012 user: true, 46013}; 46014const DEFAULT_REQUEST_INCLUDES = ['cookies', 'data', 'headers', 'method', 'query_string', 'url']; 46015const DEFAULT_USER_INCLUDES = ['id', 'username', 'email']; 46016 46017/** 46018 * Sets parameterized route as transaction name e.g.: `GET /users/:id` 46019 * Also adds more context data on the transaction from the request 46020 */ 46021function addRequestDataToTransaction( 46022 transaction, 46023 req, 46024 deps, 46025) { 46026 if (!transaction) return; 46027 // eslint-disable-next-line deprecation/deprecation 46028 if (!transaction.metadata.source || transaction.metadata.source === 'url') { 46029 // Attempt to grab a parameterized route off of the request 46030 const [name, source] = extractPathForTransaction(req, { path: true, method: true }); 46031 transaction.updateName(name); 46032 // TODO: SEMANTIC_ATTRIBUTE_SENTRY_SOURCE is in core, align this once we merge utils & core 46033 // eslint-disable-next-line deprecation/deprecation 46034 transaction.setMetadata({ source }); 46035 } 46036 transaction.setAttribute('url', req.originalUrl || req.url); 46037 if (req.baseUrl) { 46038 transaction.setAttribute('baseUrl', req.baseUrl); 46039 } 46040 // TODO: We need to rewrite this to a flat format? 46041 // eslint-disable-next-line deprecation/deprecation 46042 transaction.setData('query', extractQueryParams(req, deps)); 46043} 46044 46045/** 46046 * Extracts a complete and parameterized path from the request object and uses it to construct transaction name. 46047 * If the parameterized transaction name cannot be extracted, we fall back to the raw URL. 46048 * 46049 * Additionally, this function determines and returns the transaction name source 46050 *
vendor: 7,800 bytes, lines 46051-46315
46051 * eg. GET /mountpoint/user/:id 46052 * 46053 * @param req A request object 46054 * @param options What to include in the transaction name (method, path, or a custom route name to be 46055 * used instead of the request's route) 46056 * 46057 * @returns A tuple of the fully constructed transaction name [0] and its source [1] (can be either 'route' or 'url') 46058 */ 46059function extractPathForTransaction( 46060 req, 46061 options = {}, 46062) { 46063 const method = req.method && req.method.toUpperCase(); 46064 46065 let path = ''; 46066 let source = 'url'; 46067 46068 // Check to see if there's a parameterized route we can use (as there is in Express) 46069 if (options.customRoute || req.route) { 46070 path = options.customRoute || `${req.baseUrl || ''}${req.route && req.route.path}`; 46071 source = 'route'; 46072 } 46073 46074 // Otherwise, just take the original URL 46075 else if (req.originalUrl || req.url) { 46076 path = url.stripUrlQueryAndFragment(req.originalUrl || req.url || ''); 46077 } 46078 46079 let name = ''; 46080 if (options.method && method) { 46081 name += method; 46082 } 46083 if (options.method && options.path) { 46084 name += ' '; 46085 } 46086 if (options.path && path) { 46087 name += path; 46088 } 46089 46090 return [name, source]; 46091} 46092 46093/** JSDoc */ 46094function extractTransaction(req, type) { 46095 switch (type) { 46096 case 'path': { 46097 return extractPathForTransaction(req, { path: true })[0]; 46098 } 46099 case 'handler': { 46100 return (req.route && req.route.stack && req.route.stack[0] && req.route.stack[0].name) || '<anonymous>'; 46101 } 46102 case 'methodPath': 46103 default: { 46104 // if exist _reconstructedRoute return that path instead of route.path 46105 const customRoute = req._reconstructedRoute ? req._reconstructedRoute : undefined; 46106 return extractPathForTransaction(req, { path: true, method: true, customRoute })[0]; 46107 } 46108 } 46109} 46110 46111/** JSDoc */ 46112function extractUserData( 46113 user 46114 46115, 46116 keys, 46117) { 46118 const extractedUser = {}; 46119 const attributes = Array.isArray(keys) ? keys : DEFAULT_USER_INCLUDES; 46120 46121 attributes.forEach(key => { 46122 if (user && key in user) { 46123 extractedUser[key] = user[key]; 46124 } 46125 }); 46126 46127 return extractedUser; 46128} 46129 46130/** 46131 * Normalize data from the request object, accounting for framework differences. 46132 * 46133 * @param req The request object from which to extract data 46134 * @param options.include An optional array of keys to include in the normalized data. Defaults to 46135 * DEFAULT_REQUEST_INCLUDES if not provided. 46136 * @param options.deps Injected, platform-specific dependencies 46137 * @returns An object containing normalized request data 46138 */ 46139function extractRequestData( 46140 req, 46141 options 46142 46143, 46144) { 46145 const { include = DEFAULT_REQUEST_INCLUDES, deps } = options || {}; 46146 // eslint-disable-next-line @typescript-eslint/no-explicit-any 46147 const requestData = {}; 46148 46149 // headers: 46150 // node, express, koa, nextjs: req.headers 46151 const headers = (req.headers || {}) 46152 46153; 46154 // method: 46155 // node, express, koa, nextjs: req.method 46156 const method = req.method; 46157 // host: 46158 // express: req.hostname in > 4 and req.host in < 4 46159 // koa: req.host 46160 // node, nextjs: req.headers.host 46161 // Express 4 mistakenly strips off port number from req.host / req.hostname so we can't rely on them 46162 // See: https://github.com/expressjs/express/issues/3047#issuecomment-236653223 46163 // Also: https://github.com/getsentry/sentry-javascript/issues/1917 46164 const host = headers.host || req.hostname || req.host || '<no host>'; 46165 // protocol: 46166 // node, nextjs: <n/a> 46167 // express, koa: req.protocol 46168 const protocol = req.protocol === 'https' || (req.socket && req.socket.encrypted) ? 'https' : 'http'; 46169 // url (including path and query string): 46170 // node, express: req.originalUrl 46171 // koa, nextjs: req.url 46172 const originalUrl = req.originalUrl || req.url || ''; 46173 // absolute url 46174 const absoluteUrl = originalUrl.startsWith(protocol) ? originalUrl : `${protocol}://${host}${originalUrl}`; 46175 include.forEach(key => { 46176 switch (key) { 46177 case 'headers': { 46178 requestData.headers = headers; 46179 46180 // Remove the Cookie header in case cookie data should not be included in the event 46181 if (!include.includes('cookies')) { 46182 delete (requestData.headers ).cookie; 46183 } 46184 46185 break; 46186 } 46187 case 'method': { 46188 requestData.method = method; 46189 break; 46190 } 46191 case 'url': { 46192 requestData.url = absoluteUrl; 46193 break; 46194 } 46195 case 'cookies': { 46196 // cookies: 46197 // node, express, koa: req.headers.cookie 46198 // vercel, sails.js, express (w/ cookie middleware), nextjs: req.cookies 46199 requestData.cookies = 46200 // TODO (v8 / #5257): We're only sending the empty object for backwards compatibility, so the last bit can 46201 // come off in v8 46202 req.cookies || (headers.cookie && cookie.parseCookie(headers.cookie)) || {}; 46203 break; 46204 } 46205 case 'query_string': { 46206 // query string: 46207 // node: req.url (raw) 46208 // express, koa, nextjs: req.query 46209 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 46210 requestData.query_string = extractQueryParams(req, deps); 46211 break; 46212 } 46213 case 'data': { 46214 if (method === 'GET' || method === 'HEAD') { 46215 break; 46216 } 46217 // body data: 46218 // express, koa, nextjs: req.body 46219 // 46220 // when using node by itself, you have to read the incoming stream(see 46221 // https://nodejs.dev/learn/get-http-request-body-data-using-nodejs); if a user is doing that, we can't know 46222 // where they're going to store the final result, so they'll have to capture this data themselves 46223 if (req.body !== undefined) { 46224 requestData.data = is.isString(req.body) ? req.body : JSON.stringify(normalize.normalize(req.body)); 46225 } 46226 break; 46227 } 46228 default: { 46229 if ({}.hasOwnProperty.call(req, key)) { 46230 requestData[key] = (req )[key]; 46231 } 46232 } 46233 } 46234 }); 46235 46236 return requestData; 46237} 46238 46239/** 46240 * Add data from the given request to the given event 46241 * 46242 * @param event The event to which the request data will be added 46243 * @param req Request object 46244 * @param options.include Flags to control what data is included 46245 * @param options.deps Injected platform-specific dependencies 46246 * @returns The mutated `Event` object 46247 */ 46248function addRequestDataToEvent( 46249 event, 46250 req, 46251 options, 46252) { 46253 const include = { 46254 ...DEFAULT_INCLUDES, 46255 ...(options && options.include), 46256 }; 46257 46258 if (include.request) { 46259 const extractedRequestData = Array.isArray(include.request) 46260 ? extractRequestData(req, { include: include.request, deps: options && options.deps }) 46261 : extractRequestData(req, { deps: options && options.deps }); 46262 46263 event.request = { 46264 ...event.request, 46265 ...extractedRequestData, 46266 }; 46267 } 46268 46269 if (include.user) { 46270 const extractedUser = req.user && is.isPlainObject(req.user) ? extractUserData(req.user, include.user) : {}; 46271 46272 if (Object.keys(extractedUser).length) { 46273 event.user = { 46274 ...event.user, 46275 ...extractedUser, 46276 }; 46277 } 46278 } 46279 46280 // client ip: 46281 // node, nextjs: req.socket.remoteAddress 46282 // express, koa: req.ip 46283 if (include.ip) { 46284 const ip = req.ip || (req.socket && req.socket.remoteAddress); 46285 if (ip) { 46286 event.user = { 46287 ...event.user, 46288 ip_address: ip, 46289 }; 46290 } 46291 } 46292 46293 if (include.transaction && !event.transaction) { 46294 // TODO do we even need this anymore? 46295 // TODO make this work for nextjs 46296 event.transaction = extractTransaction(req, include.transaction); 46297 } 46298 46299 return event; 46300} 46301 46302function extractQueryParams( 46303 req, 46304 deps, 46305) { 46306 // url (including path and query string): 46307 // node, express: req.originalUrl 46308 // koa, nextjs: req.url 46309 let originalUrl = req.originalUrl || req.url || ''; 46310 46311 if (!originalUrl) { 46312 return; 46313 } 46314 46315 // The `URL` constructor can't handle internal URLs of the form `/some/p
46315ath/here`, so stick a dummy protocol and 46316 // hostname on the beginning. Since the point here is just to grab the query string, it doesn't matter what we use. 46317 if (originalUrl.startsWith('/')) { 46318 originalUrl = `http://dogs.are.great${originalUrl}`; 46319 } 46320 46321 try { 46322 return ( 46323 req.query || 46324 (typeof URL !== 'undefined' && new URL(originalUrl).search.slice(1)) || 46325 // In Node 8, `URL` isn't in the global scope, so we have to use the built-in module from Node 46326 (deps && deps.url && deps.url.parse(originalUrl).query) || 46327 undefined 46328 ); 46329 } catch (e2) { 46330 return undefined; 46331 } 46332} 46333 46334/** 46335 * Transforms a `Headers` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into a simple key-value dict. 46336 * The header keys will be lower case: e.g. A "Content-Type" header will be stored as "content-type". 46337 */ 46338// TODO(v8): Make this function return undefined when the extraction fails. 46339function winterCGHeadersToDict(winterCGHeaders) { 46340 const headers = {}; 46341 try { 46342 winterCGHeaders.forEach((value, key) => { 46343 if (typeof value === 'string') { 46344 // We check that value is a string even though it might be redundant to make sure prototype pollution is not possible. 46345 headers[key] = value; 46346 } 46347 }); 46348 } catch (e) { 46349 debugBuild.DEBUG_BUILD && 46350 logger.logger.warn('Sentry failed extracting headers from a request object. If you see this, please file an issue.'); 46351 } 46352 46353 return headers; 46354} 46355 46356/** 46357 * Converts a `Request` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into the format that the `RequestData` integration understands. 46358 */ 46359function winterCGRequestToRequestData(req) { 46360 const headers = winterCGHeadersToDict(req.headers); 46361 return { 46362 method: req.method, 46363 url: req.url, 46364 headers, 46365 }; 46366} 46367 46368exports.DEFAULT_USER_INCLUDES = DEFAULT_USER_INCLUDES; 46369exports.addRequestDataToEvent = addRequestDataToEvent; 46370exports.addRequestDataToTransaction = addRequestDataToTransaction; 46371exports.extractPathForTransaction = extractPathForTransaction; 46372exports.extractRequestData = extractRequestData; 46373exports.winterCGHeadersToDict = winterCGHeadersToDict; 46374exports.winterCGRequestToRequestData = winterCGRequestToRequestData; 46375 46376 46377},{"./cookie.js":312,"./debug-build.js":313,"./is.js":329,"./logger.js":331,"./normalize.js":337,"./url.js":350}],343:[function(require,module,exports){ 46378Object.defineProperty(exports, '__esModule', { value: true }); 46379 46380// Note: Ideally the `SeverityLevel` type would be derived from `validSeverityLevels`, but that would mean either 46381// 46382// a) moving `validSeverityLevels` to `@sentry/types`, 46383// b) moving the`SeverityLevel` type here, or 46384// c) importing `validSeverityLevels` from here into `@sentry/types`. 46385// 46386// Option A would make `@sentry/types` a runtime dependency of `@sentry/utils` (not good), and options B and C would 46387// create a circular dependency between `@sentry/types` and `@sentry/utils` (also not good). So a TODO accompanying the 46388// type, reminding anyone who changes it to change this list also, will have to do. 46389 46390const validSeverityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug']; 46391 46392/** 46393 * Converts a string-based level into a member of the deprecated {@link Severity} enum. 46394 * 46395 * @deprecated `severityFromString` is deprecated. Please use `severityLevelFromString` instead. 46396 * 46397 * @param level String representation of Severity 46398 * @returns Severity 46399 */ 46400function severityFromString(level) { 46401 return severityLevelFromString(level) ; 46402} 46403 46404/** 46405 * Converts a string-based level into a `SeverityLevel`, normalizing it along the way. 46406 * 46407 * @param level String representation of desired `SeverityLevel`. 46408 * @returns The `SeverityLevel` corresponding to the given string, or 'log' if the string isn't a valid level. 46409 */ 46410function severityLevelFromString(level) { 46411 return (level === 'warn' ? 'warning' : validSeverityLevels.includes(level) ? level : 'log') ; 46412} 46413 46414exports.severityFromString = severityFromString; 46415exports.severityLevelFromString = severityLevelFromString; 46416exports.validSeverityLevels = validSeverityLevels; 46417 46418 46419},{}],344:[function(require,module,exports){ 46420Object.defineProperty(exports, '__esModule', { value: true }); 46421 46422const nodeStackTrace = require('./node-stack-trace.js'); 46423 46424const STACKTRACE_FRAME_LIMIT = 50; 46425// Used to sanitize webpack (error: *) wrapped stack errors 46426const WEBPACK_ERROR_REGEXP = /\(error: (.*)\)/; 46427const STRIP_FRAME_REGEXP = /captureMessage|captureException/; 46428 46429/** 46430 * Creates a stack parser with the supplied line parsers 46431 * 46432 * StackFrames are returned in the correct order for Sentry Exception
46433 * frames and with Sentry SDK internal frames removed from the top and bottom 46434 * 46435 */ 46436function createStackParser(...parsers) { 46437 const sortedParsers = parsers.sort((a, b) => a[0] - b[0]).map(p => p[1]); 46438 46439 return (stack, skipFirst = 0) => { 46440 const frames = []; 46441 const lines = stack.split('\n'); 46442 46443 for (let i = skipFirst; i < lines.length; i++) { 46444 const line = lines[i]; 46445 // Ignore lines over 1kb as they are unlikely to be stack frames. 46446 // Many of the regular expressions use backtracking which results in run time that increases exponentially with 46447 // input size. Huge strings can result in hangs/Denial of Service: 46448 // https://github.com/getsentry/sentry-javascript/issues/2286 46449 if (line.length > 1024) { 46450 continue; 46451 } 46452 46453 // https://github.com/getsentry/sentry-javascript/issues/5459 46454 // Remove webpack (error: *) wrappers 46455 const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, '$1') : line; 46456 46457 // https://github.com/getsentry/sentry-javascript/issues/7813 46458 // Skip Error: lines 46459 if (cleanedLine.match(/\S*Error: /)) { 46460 continue; 46461 } 46462 46463 for (const parser of sortedParsers) { 46464 const frame = parser(cleanedLine); 46465 46466 if (frame) { 46467 frames.push(frame); 46468 break; 46469 } 46470 } 46471 46472 if (frames.length >= STACKTRACE_FRAME_LIMIT) { 46473 break; 46474 } 46475 } 46476 46477 return stripSentryFramesAndReverse(frames); 46478 }; 46479} 46480 46481/** 46482 * Gets a stack parser implementation from Options.stackParser 46483 * @see Options 46484 * 46485 * If options contains an array of line parsers, it is converted into a parser 46486 */ 46487function stackParserFromStackParserOptions(stackParser) { 46488 if (Array.isArray(stackParser)) { 46489 return createStackParser(...stackParser); 46490 } 46491 return stackParser; 46492} 46493 46494/** 46495 * Removes Sentry frames from the top and bottom of the stack if present and enforces a limit of max number of frames. 46496 * Assumes stack input is ordered from top to bottom and returns the reverse representation so call site of the 46497 * function that caused the crash is the last frame in the array. 46498 * @hidden 46499 */ 46500function stripSentryFramesAndReverse(stack) { 46501 if (!stack.length) { 46502 return []; 46503 } 46504 46505 const localStack = Array.from(stack); 46506 46507 // If stack starts with one of our API calls, remove it (starts, meaning it's the top of the stack - aka last call) 46508 if (/sentryWrapped/.test(localStack[localStack.length - 1].function || '')) { 46509 localStack.pop(); 46510 } 46511 46512 // Reversing in the middle of the procedure allows us to just pop the values off the stack 46513 localStack.reverse(); 46514 46515 // If stack ends with one of our internal API calls, remove it (ends, meaning it's the bottom of the stack - aka top-most call) 46516 if (STRIP_FRAME_REGEXP.test(localStack[localStack.length - 1].function || '')) { 46517 localStack.pop(); 46518 46519 // When using synthetic events, we will have a 2 levels deep stack, as `new Error('Sentry syntheticException')` 46520 // is produced within the hub itself, making it: 46521 // 46522 // Sentry.captureException() 46523 // getCurrentHub().captureException() 46524 // 46525 // instead of just the top `Sentry` call itself. 46526 // This forces us to possibly strip an additional frame in the exact same was as above. 46527 if (STRIP_FRAME_REGEXP.test(localStack[localStack.length - 1].function || '')) { 46528 localStack.pop(); 46529 } 46530 } 46531 46532 return localStack.slice(0, STACKTRACE_FRAME_LIMIT).map(frame => ({ 46533 ...frame, 46534 filename: frame.filename || localStack[localStack.length - 1].filename, 46535 function: frame.function || '?', 46536 })); 46537} 46538 46539const defaultFunctionName = '<anonymous>'; 46540 46541/** 46542 * Safely extract function name from itself 46543 */ 46544function getFunctionName(fn) { 46545 try { 46546 if (!fn || typeof fn !== 'function') { 46547 return defaultFunctionName; 46548 } 46549 return fn.name || defaultFunctionName; 46550 } catch (e) { 46551 // Just accessing custom props in some Selenium environments 46552 // can cause a "Permission denied" exception (see raven-js#495). 46553 return defaultFunctionName; 46554 } 46555} 46556 46557/** 46558 * Node.js stack line parser 46559 * 46560 * This is in @sentry/utils so it can be used from the Electron SDK in the browser for when `nodeIntegration == true`. 46561 * This allows it to be used without referencing or importing any node specific code which causes bundlers to complain 46562 */ 46563function nodeStackLineParser(getModule) { 46564 return [90, nodeStackTrace.node(getModule)]; 46565} 46566 46567exports.filenameIsInApp = nodeStackTrace.filenameIsInApp; 46568exports.createStackParser = createStackParser; 46569exports.getFunctionName = getFunctionName; 46570exports.nodeStackLineParser = nodeStackLineParser; 46571exports.stackParserFromStackParserOptions = stackParserFromStackParserOptions; 46572exports.stripSentryFramesAndReverse = stripSentryFramesAndReverse;
46573 46574 46575},{"./node-stack-trace.js":335}],345:[function(require,module,exports){ 46576Object.defineProperty(exports, '__esModule', { value: true }); 46577 46578const is = require('./is.js'); 46579 46580/** 46581 * Truncates given string to the maximum characters count 46582 * 46583 * @param str An object that contains serializable values 46584 * @param max Maximum number of characters in truncated string (0 = unlimited) 46585 * @returns string Encoded 46586 */ 46587function truncate(str, max = 0) { 46588 if (typeof str !== 'string' || max === 0) { 46589 return str; 46590 } 46591 return str.length <= max ? str : `${str.slice(0, max)}...`; 46592} 46593 46594/** 46595 * This is basically just `trim_line` from 46596 * https://github.com/getsentry/sentry/blob/master/src/sentry/lang/javascript/processor.py#L67 46597 * 46598 * @param str An object that contains serializable values 46599 * @param max Maximum number of characters in truncated string 46600 * @returns string Encoded 46601 */ 46602function snipLine(line, colno) { 46603 let newLine = line; 46604 const lineLength = newLine.length; 46605 if (lineLength <= 150) { 46606 return newLine; 46607 } 46608 if (colno > lineLength) { 46609 // eslint-disable-next-line no-param-reassign 46610 colno = lineLength; 46611 } 46612 46613 let start = Math.max(colno - 60, 0); 46614 if (start < 5) { 46615 start = 0; 46616 } 46617 46618 let end = Math.min(start + 140, lineLength); 46619 if (end > lineLength - 5) { 46620 end = lineLength; 46621 } 46622 if (end === lineLength) { 46623 start = Math.max(end - 140, 0); 46624 } 46625 46626 newLine = newLine.slice(start, end); 46627 if (start > 0) { 46628 newLine = `'{snip} ${newLine}`; 46629 } 46630 if (end < lineLength) { 46631 newLine += ' {snip}'; 46632 } 46633 46634 return newLine; 46635} 46636 46637/** 46638 * Join values in array 46639 * @param input array of values to be joined together 46640 * @param delimiter string to be placed in-between values 46641 * @returns Joined values 46642 */ 46643// eslint-disable-next-line @typescript-eslint/no-explicit-any 46644function safeJoin(input, delimiter) { 46645 if (!Array.isArray(input)) { 46646 return ''; 46647 } 46648 46649 const output = []; 46650 // eslint-disable-next-line @typescript-eslint/prefer-for-of 46651 for (let i = 0; i < input.length; i++) { 46652 const value = input[i]; 46653 try { 46654 // This is a hack to fix a Vue3-specific bug that causes an infinite loop of 46655 // console warnings. This happens when a Vue template is rendered with 46656 // an undeclared variable, which we try to stringify, ultimately causing 46657 // Vue to issue another warning which repeats indefinitely. 46658 // see: https://github.com/getsentry/sentry-javascript/pull/8981 46659 if (is.isVueViewModel(value)) { 46660 output.push('[VueViewModel]'); 46661 } else { 46662 output.push(String(value)); 46663 } 46664 } catch (e) { 46665 output.push('[value cannot be serialized]'); 46666 } 46667 } 46668 46669 return output.join(delimiter); 46670} 46671 46672/** 46673 * Checks if the given value matches a regex or string 46674 * 46675 * @param value The string to test 46676 * @param pattern Either a regex or a string against which `value` will be matched 46677 * @param requireExactStringMatch If true, `value` must match `pattern` exactly. If false, `value` will match 46678 * `pattern` if it contains `pattern`. Only applies to string-type patterns. 46679 */ 46680function isMatchingPattern( 46681 value, 46682 pattern, 46683 requireExactStringMatch = false, 46684) { 46685 if (!is.isString(value)) { 46686 return false; 46687 } 46688 46689 if (is.isRegExp(pattern)) { 46690 return pattern.test(value); 46691 } 46692 if (is.isString(pattern)) { 46693 return requireExactStringMatch ? value === pattern : value.includes(pattern); 46694 } 46695 46696 return false; 46697} 46698 46699/** 46700 * Test the given string against an array of strings and regexes. By default, string matching is done on a 46701 * substring-inclusion basis rather than a strict equality basis 46702 * 46703 * @param testString The string to test 46704 * @param patterns The patterns against which to test the string 46705 * @param requireExactStringMatch If true, `testString` must match one of the given string patterns exactly in order to 46706 * count. If false, `testString` will match a string pattern if it contains that pattern. 46707 * @returns 46708 */ 46709function stringMatchesSomePattern( 46710 testString, 46711 patterns = [], 46712 requireExactStringMatch = false, 46713) { 46714 return patterns.some(pattern => isMatchingPattern(testString, pattern, requireExactStringMatch)); 46715} 46716 46717exports.isMatchingPattern = isMatchingPattern; 46718exports.safeJoin = safeJoin; 46719exports.snipLine = snipLine; 46720exports.stringMatchesSomePattern = stringMatchesSomePattern; 46721exports.truncate = truncate; 46722 46723 46724},{"./is.js":329}],346:[function(require,module,exports){ 46725Object.defineProperty(exports, '__esModule', { value: true }); 46726 46727const debugBuild = require('./debug-build.js'); 46728const logger = require('./logger.js'); 46729const worldwide = require('./worldwide.js'); 46730 46731// eslint-disable-next-line deprecation/deprecation 46732const WINDOW = worldwide.getGlobalObject
vendor: 2,843 bytes, lines 46732-46847
46732(); 46733 46734/** 46735 * Tells whether current environment supports ErrorEvent objects 46736 * {@link supportsErrorEvent}. 46737 * 46738 * @returns Answer to the given question. 46739 */ 46740function supportsErrorEvent() { 46741 try { 46742 new ErrorEvent(''); 46743 return true; 46744 } catch (e) { 46745 return false; 46746 } 46747} 46748 46749/** 46750 * Tells whether current environment supports DOMError objects 46751 * {@link supportsDOMError}. 46752 * 46753 * @returns Answer to the given question. 46754 */ 46755function supportsDOMError() { 46756 try { 46757 // Chrome: VM89:1 Uncaught TypeError: Failed to construct 'DOMError': 46758 // 1 argument required, but only 0 present. 46759 // @ts-expect-error It really needs 1 argument, not 0. 46760 new DOMError(''); 46761 return true; 46762 } catch (e) { 46763 return false; 46764 } 46765} 46766 46767/** 46768 * Tells whether current environment supports DOMException objects 46769 * {@link supportsDOMException}. 46770 * 46771 * @returns Answer to the given question. 46772 */ 46773function supportsDOMException() { 46774 try { 46775 new DOMException(''); 46776 return true; 46777 } catch (e) { 46778 return false; 46779 } 46780} 46781 46782/** 46783 * Tells whether current environment supports Fetch API 46784 * {@link supportsFetch}. 46785 * 46786 * @returns Answer to the given question. 46787 */ 46788function supportsFetch() { 46789 if (!('fetch' in WINDOW)) { 46790 return false; 46791 } 46792 46793 try { 46794 new Headers(); 46795 new Request('http://www.example.com'); 46796 new Response(); 46797 return true; 46798 } catch (e) { 46799 return false; 46800 } 46801} 46802/** 46803 * isNativeFetch checks if the given function is a native implementation of fetch() 46804 */ 46805// eslint-disable-next-line @typescript-eslint/ban-types 46806function isNativeFetch(func) { 46807 return func && /^function fetch\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString()); 46808} 46809 46810/** 46811 * Tells whether current environment supports Fetch API natively 46812 * {@link supportsNativeFetch}. 46813 * 46814 * @returns true if `window.fetch` is natively implemented, false otherwise 46815 */ 46816function supportsNativeFetch() { 46817 if (typeof EdgeRuntime === 'string') { 46818 return true; 46819 } 46820 46821 if (!supportsFetch()) { 46822 return false; 46823 } 46824 46825 // Fast path to avoid DOM I/O 46826 // eslint-disable-next-line @typescript-eslint/unbound-method 46827 if (isNativeFetch(WINDOW.fetch)) { 46828 return true; 46829 } 46830 46831 // window.fetch is implemented, but is polyfilled or already wrapped (e.g: by a chrome extension) 46832 // so create a "pure" iframe to see if that has native fetch 46833 let result = false; 46834 const doc = WINDOW.document; 46835 // eslint-disable-next-line deprecation/deprecation 46836 if (doc && typeof (doc.createElement ) === 'function') { 46837 try { 46838 const sandbox = doc.createElement('iframe'); 46839 sandbox.hidden = true; 46840 doc.head.appendChild(sandbox); 46841 if (sandbox.contentWindow && sandbox.contentWindow.fetch) { 46842 // eslint-disable-next-line @typescript-eslint/unbound-method 46843 result = isNativeFetch(sandbox.contentWindow.fetch); 46844 } 46845 doc.head.removeChild(sandbox); 46846 } catch (err) { 46847
vendor: 4,300 bytes, lines 46847-47015
46847debugBuild.DEBUG_BUILD && 46848 logger.logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err); 46849 } 46850 } 46851 46852 return result; 46853} 46854 46855/** 46856 * Tells whether current environment supports ReportingObserver API 46857 * {@link supportsReportingObserver}. 46858 * 46859 * @returns Answer to the given question. 46860 */ 46861function supportsReportingObserver() { 46862 return 'ReportingObserver' in WINDOW; 46863} 46864 46865/** 46866 * Tells whether current environment supports Referrer Policy API 46867 * {@link supportsReferrerPolicy}. 46868 * 46869 * @returns Answer to the given question. 46870 */ 46871function supportsReferrerPolicy() { 46872 // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default' 46873 // (see https://caniuse.com/#feat=referrer-policy), 46874 // it doesn't. And it throws an exception instead of ignoring this parameter... 46875 // REF: https://github.com/getsentry/raven-js/issues/1233 46876 46877 if (!supportsFetch()) { 46878 return false; 46879 } 46880 46881 try { 46882 new Request('_', { 46883 referrerPolicy: 'origin' , 46884 }); 46885 return true; 46886 } catch (e) { 46887 return false; 46888 } 46889} 46890 46891exports.isNativeFetch = isNativeFetch; 46892exports.supportsDOMError = supportsDOMError; 46893exports.supportsDOMException = supportsDOMException; 46894exports.supportsErrorEvent = supportsErrorEvent; 46895exports.supportsFetch = supportsFetch; 46896exports.supportsNativeFetch = supportsNativeFetch; 46897exports.supportsReferrerPolicy = supportsReferrerPolicy; 46898exports.supportsReportingObserver = supportsReportingObserver; 46899 46900 46901},{"./debug-build.js":313,"./logger.js":331,"./worldwide.js":354}],347:[function(require,module,exports){ 46902Object.defineProperty(exports, '__esModule', { value: true }); 46903 46904const is = require('./is.js'); 46905 46906/* eslint-disable @typescript-eslint/explicit-function-return-type */ 46907 46908/** SyncPromise internal states */ 46909var States; (function (States) { 46910 /** Pending */ 46911 const PENDING = 0; States[States["PENDING"] = PENDING] = "PENDING"; 46912 /** Resolved / OK */ 46913 const RESOLVED = 1; States[States["RESOLVED"] = RESOLVED] = "RESOLVED"; 46914 /** Rejected / Error */ 46915 const REJECTED = 2; States[States["REJECTED"] = REJECTED] = "REJECTED"; 46916})(States || (States = {})); 46917 46918// Overloads so we can call resolvedSyncPromise without arguments and generic argument 46919 46920/** 46921 * Creates a resolved sync promise. 46922 * 46923 * @param value the value to resolve the promise with 46924 * @returns the resolved sync promise 46925 */ 46926function resolvedSyncPromise(value) { 46927 return new SyncPromise(resolve => { 46928 resolve(value); 46929 }); 46930} 46931 46932/** 46933 * Creates a rejected sync promise. 46934 * 46935 * @param value the value to reject the promise with 46936 * @returns the rejected sync promise 46937 */ 46938function rejectedSyncPromise(reason) { 46939 return new SyncPromise((_, reject) => { 46940 reject(reason); 46941 }); 46942} 46943 46944/** 46945 * Thenable class that behaves like a Promise and follows it's interface 46946 * but is not async internally 46947 */ 46948class SyncPromise { 46949 46950 constructor( 46951 executor, 46952 ) {SyncPromise.prototype.__init.call(this);SyncPromise.prototype.__init2.call(this);SyncPromise.prototype.__init3.call(this);SyncPromise.prototype.__init4.call(this); 46953 this._state = States.PENDING; 46954 this._handlers = []; 46955 46956 try { 46957 executor(this._resolve, this._reject); 46958 } catch (e) { 46959 this._reject(e); 46960 } 46961 } 46962 46963 /** JSDoc */ 46964 then( 46965 onfulfilled, 46966 onrejected, 46967 ) { 46968 return new SyncPromise((resolve, reject) => { 46969 this._handlers.push([ 46970 false, 46971 result => { 46972 if (!onfulfilled) { 46973 // TODO: ¯\_(ã)_/¯ 46974 // TODO: FIXME 46975 resolve(result ); 46976 } else { 46977 try { 46978 resolve(onfulfilled(result)); 46979 } catch (e) { 46980 reject(e); 46981 } 46982 } 46983 }, 46984 reason => { 46985 if (!onrejected) { 46986 reject(reason); 46987 } else { 46988 try { 46989 resolve(onrejected(reason)); 46990 } catch (e) { 46991 reject(e); 46992 } 46993 } 46994 }, 46995 ]); 46996 this._executeHandlers(); 46997 }); 46998 } 46999 47000 /** JSDoc */ 47001 catch( 47002 onrejected, 47003 ) { 47004 return this.then(val => val, onrejected); 47005 } 47006 47007 /** JSDoc */ 47008 finally(onfinally) { 47009 return new SyncPromise((resolve, reject) => { 47010 let val; 47011 let isRejected; 47012 47013 return this.then( 47014 value => { 47015 isRejected = false;
47016 val = value; 47017 if (onfinally) { 47018 onfinally(); 47019 } 47020 }, 47021 reason => { 47022 isRejected = true; 47023 val = reason; 47024 if (onfinally) { 47025 onfinally(); 47026 } 47027 }, 47028 ).then(() => { 47029 if (isRejected) { 47030 reject(val); 47031 return; 47032 } 47033 47034 resolve(val ); 47035 }); 47036 }); 47037 } 47038 47039 /** JSDoc */ 47040 __init() {this._resolve = (value) => { 47041 this._setResult(States.RESOLVED, value); 47042 };} 47043 47044 /** JSDoc */ 47045 __init2() {this._reject = (reason) => { 47046 this._setResult(States.REJECTED, reason); 47047 };} 47048 47049 /** JSDoc */ 47050 __init3() {this._setResult = (state, value) => { 47051 if (this._state !== States.PENDING) { 47052 return; 47053 } 47054 47055 if (is.isThenable(value)) { 47056 void (value ).then(this._resolve, this._reject); 47057 return; 47058 } 47059 47060 this._state = state; 47061 this._value = value; 47062 47063 this._executeHandlers(); 47064 };} 47065 47066 /** JSDoc */ 47067 __init4() {this._executeHandlers = () => { 47068 if (this._state === States.PENDING) { 47069 return; 47070 } 47071 47072 const cachedHandlers = this._handlers.slice(); 47073 this._handlers = []; 47074 47075 cachedHandlers.forEach(handler => { 47076 if (handler[0]) { 47077 return; 47078 } 47079 47080 if (this._state === States.RESOLVED) { 47081 // eslint-disable-next-line @typescript-eslint/no-floating-promises 47082 handler[1](this._value ); 47083 } 47084 47085 if (this._state === States.REJECTED) { 47086 handler[2](this._value); 47087 } 47088 47089 handler[0] = true; 47090 }); 47091 };} 47092} 47093 47094exports.SyncPromise = SyncPromise; 47095exports.rejectedSyncPromise = rejectedSyncPromise; 47096exports.resolvedSyncPromise = resolvedSyncPromise; 47097 47098 47099},{"./is.js":329}],348:[function(require,module,exports){ 47100Object.defineProperty(exports, '__esModule', { value: true }); 47101 47102const worldwide = require('./worldwide.js'); 47103 47104const ONE_SECOND_IN_MS = 1000; 47105 47106/** 47107 * A partial definition of the [Performance Web API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Performance} 47108 * for accessing a high-resolution monotonic clock. 47109 */ 47110 47111/** 47112 * Returns a timestamp in seconds since the UNIX epoch using the Date API. 47113 * 47114 * TODO(v8): Return type should be rounded. 47115 */ 47116function dateTimestampInSeconds() { 47117 return Date.now() / ONE_SECOND_IN_MS; 47118} 47119 47120/** 47121 * Returns a wrapper around the native Performance API browser implementation, or undefined for browsers that do not 47122 * support the API. 47123 * 47124 * Wrapping the native API works around differences in behavior from different browsers. 47125 */ 47126function createUnixTimestampInSecondsFunc() { 47127 const { performance } = worldwide.GLOBAL_OBJ ; 47128 if (!performance || !performance.now) { 47129 return dateTimestampInSeconds; 47130 } 47131 47132 // Some browser and environments don't have a timeOrigin, so we fallback to 47133 // using Date.now() to compute the starting time. 47134 const approxStartingTimeOrigin = Date.now() - performance.now(); 47135 const timeOrigin = performance.timeOrigin == undefined ? approxStartingTimeOrigin : performance.timeOrigin; 47136 47137 // performance.now() is a monotonic clock, which means it starts at 0 when the process begins. To get the current 47138 // wall clock time (actual UNIX timestamp), we need to add the starting time origin and the current time elapsed. 47139 // 47140 // TODO: This does not account for the case where the monotonic clock that powers performance.now() drifts from the 47141 // wall clock time, which causes the returned timestamp to be inaccurate. We should investigate how to detect and 47142 // correct for this. 47143 // See: https://github.com/getsentry/sentry-javascript/issues/2590 47144 // See: https://github.com/mdn/content/issues/4713 47145 // See: https://dev.to/noamr/when-a-millisecond-is-not-a-millisecond-3h6 47146 return () => { 47147 return (timeOrigin + performance.now()) / ONE_SECOND_IN_MS; 47148 }; 47149} 47150 47151/** 47152 * Returns a timestamp in seconds since the UNIX epoch using either the Performance or Date APIs, depending on the 47153 * availability of the Performance API. 47154 * 47155 * BUG: Note that because of how browsers implement the Performance API, the clock might stop when the computer is 47156 * asleep. This creates a skew between `dateTimestampInSeconds` and `timestampInSeconds`. The 47157 * skew can grow to arbitrary amounts like days, weeks or months. 47158 * See https://github.com/getsentry/sentry-javascript/issues/2590. 47159 */ 47160const timestampInSeconds = createUnixTimestampInSecondsFunc(); 47161 47162/** 47163 * Re-exported with an old name for backwards-compatibility. 47164 * TODO (v8): Remove this 47165 * 47166 * @deprecated Use `timestampInSeconds` instead. 47167 */ 47168const timestampWithMs = timestampInSeconds; 47169 47170/** 47171 * Internal helper to store what is the source of browserPerformanceTimeOrigin below. For debugging only. 47172 */ 47173exports._browserPerformanceTimeOriginMode = void 0; 47174 47175/** 47176 * The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the 47177 * performance API is available. 47178 */ 47179const browserPerformanceTimeOrigin = (() => { 47180 // Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or 47181 // performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin 47182 // data as reliable if they are within a reasonable threshold of the current time. 47183 47184 const { performance } = worldwide.GLOBAL_OBJ ; 47185 if (!performance || !performance.now) { 47186 exports._browserPerformanceTimeOriginMode = 'none'; 47187 return undefined; 47188 } 47189 47190 const threshold = 3600 * 1000; 47191 const performanceNow = performance.now(); 47192 const dateNow = Date.now(); 47193 47194 // if timeOrigin isn't available set delta to threshold so it isn't used 47195 const timeOriginDelta = performance.timeOrigin 47196 ? Math.abs(performance.timeOrigin + performanceNow - dateNow) 47197 : threshold; 47198 const timeOriginIsReliable = timeOriginDelta < threshold; 47199
47200 // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin 47201 // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing. 47202 // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always 47203 // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the 47204 // Date API. 47205 // eslint-disable-next-line deprecation/deprecation 47206 const navigationStart = performance.timing && performance.timing.navigationStart; 47207 const hasNavigationStart = typeof navigationStart === 'number'; 47208 // if navigationStart isn't available set delta to threshold so it isn't used 47209 const navigationStartDelta = hasNavigationStart ? Math.abs(navigationStart + performanceNow - dateNow) : threshold; 47210 const navigationStartIsReliable = navigationStartDelta < threshold; 47211 47212 if (timeOriginIsReliable || navigationStartIsReliable) { 47213 // Use the more reliable time origin 47214 if (timeOriginDelta <= navigationStartDelta) { 47215 exports._browserPerformanceTimeOriginMode = 'timeOrigin'; 47216 return performance.timeOrigin; 47217 } else { 47218 exports._browserPerformanceTimeOriginMode = 'navigationStart'; 47219 return navigationStart; 47220 } 47221 } 47222 47223 // Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date. 47224 exports._browserPerformanceTimeOriginMode = 'dateNow'; 47225 return dateNow; 47226})(); 47227 47228exports.browserPerformanceTimeOrigin = browserPerformanceTimeOrigin; 47229exports.dateTimestampInSeconds = dateTimestampInSeconds; 47230exports.timestampInSeconds = timestampInSeconds; 47231exports.timestampWithMs = timestampWithMs; 47232 47233 47234},{"./worldwide.js":354}],349:[function(require,module,exports){ 47235Object.defineProperty(exports, '__esModule', { value: true }); 47236 47237const baggage = require('./baggage.js'); 47238const misc = require('./misc.js'); 47239 47240// eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor -- RegExp is used for readability here 47241const TRACEPARENT_REGEXP = new RegExp( 47242 '^[ \\t]*' + // whitespace 47243 '([0-9a-f]{32})?' + // trace_id 47244 '-?([0-9a-f]{16})?' + // span_id 47245 '-?([01])?' + // sampled 47246 '[ \\t]*$', // whitespace 47247); 47248 47249/** 47250 * Extract transaction context data from a `sentry-trace` header. 47251 * 47252 * @param traceparent Traceparent string 47253 * 47254 * @returns Object containing data from the header, or undefined if traceparent string is malformed 47255 */ 47256function extractTraceparentData(traceparent) { 47257 if (!traceparent) { 47258 return undefined; 47259 } 47260 47261 const matches = traceparent.match(TRACEPARENT_REGEXP); 47262 if (!matches) { 47263 return undefined; 47264 } 47265 47266 let parentSampled; 47267 if (matches[3] === '1') { 47268 parentSampled = true; 47269 } else if (matches[3] === '0') { 47270 parentSampled = false; 47271 } 47272 47273 return { 47274 traceId: matches[1], 47275 parentSampled, 47276 parentSpanId: matches[2], 47277 }; 47278} 47279 47280/** 47281 * Create tracing context from incoming headers. 47282 * 47283 * @deprecated Use `propagationContextFromHeaders` instead. 47284 */ 47285// TODO(v8): Remove this function 47286function tracingContextFromHeaders( 47287 sentryTrace, 47288 baggage$1, 47289) 47290 47291 { 47292 const traceparentData = extractTraceparentData(sentryTrace); 47293 const dynamicSamplingContext = baggage.baggageHeaderToDynamicSamplingContext(baggage$1); 47294 47295 const { traceId, parentSpanId, parentSampled } = traceparentData || {}; 47296 47297 if (!traceparentData) { 47298 return { 47299 traceparentData, 47300 dynamicSamplingContext: undefined, 47301 propagationContext: { 47302 traceId: traceId || misc.uuid4(), 47303 spanId: misc.uuid4().substring(16), 47304 }, 47305 }; 47306 } else { 47307 return { 47308 traceparentData, 47309 dynamicSamplingContext: dynamicSamplingContext || {}, // If we have traceparent data but no DSC it means we are not head of trace and we must freeze it 47310 propagationContext: { 47311 traceId: traceId || misc.uuid4(), 47312 parentSpanId: parentSpanId || misc.uuid4().substring(16), 47313 spanId: misc.uuid4().substring(16), 47314 sampled: parentSampled, 47315 dsc: dynamicSamplingContext || {}, // If we have traceparent data but no DSC it means we are not head of trace and we must freeze it 47316 }, 47317 }; 47318 } 47319} 47320 47321/** 47322 * Create a propagation context from incoming headers. 47323 */ 47324function propagationContextFromHeaders( 47325 sentryTrace, 47326 baggage$1, 47327) { 47328 const traceparentData = extractTraceparentData(sentryTrace); 47329 const dynamicSamplingContext = baggage.baggageHeaderToDynamicSamplingContext(baggage$1); 47330 47331 const { traceId, parentSpanId, parentSampled } = traceparentData || {}; 47332 47333 if (!traceparentData) { 47334 return { 47335 traceId: traceId || misc.uuid4(), 47336 spanId: misc.uuid4().substring(16), 47337 }; 47338 } else { 47339 return { 47340 traceId: traceId || misc.uuid4(), 47341 parentSpanId: parentSpanId || misc.uuid4().substring(16), 47342 spanId: misc.uuid4().substring(16), 47343 sampled: parentSampled, 47344 dsc: dynamicSamplingContext || {}, // If we have traceparent data but no DSC it means we are not head of trace and we must freeze it 47345 }; 47346 } 47347} 47348 47349/** 47350 * Create sentry-trace header from span context values. 47351 */ 47352function generateSentryTraceHeader( 47353 traceId = misc.uuid4(), 47354 spanId = misc.uuid4().substring(16), 47355 sampled, 47356) { 47357 let sampledString = ''; 47358 if (sampled !== undefined) { 47359 sampledString = sampled ? '-1' : '-0'; 47360 } 47361 return `${traceId}-${spanId}${sampledString}`; 47362} 47363 47364exports.TRACEPARENT_REGEXP = TRACEPARENT_REGEXP; 47365exports.extractTraceparentData = extractTraceparentData; 47366exports.generateSentryTraceHeader = generateSentryTraceHeader; 47367exports.propagationContextFromHeaders = propagationContextFromHeaders; 47368exports.tracingContextFromHeaders = tracingContextFromHeaders; 47369 47370 47371},{"./baggage.js":302,"./misc.js":334}],350:[function(require,module,exports){ 47372Object.defineProperty(exports, '__esModule', { value: true }); 47373 47374/** 47375 * Parses string form of URL into an object 47376 * // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B 47377 * // intentionally using regex and not <a/> href parsing trick because React Native and other 47378 * // environments where DOM might not be available 47379 * @returns parsed URL object 47380 */ 47381function parseUrl(url) { 47382 if (!url) { 47383 return {}; 47384 } 47385 47386 const match = url.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/); 47387 47388 if (!match) { 47389 return {}; 47390 } 47391 47392 // coerce to undefined values to empty string so we don't get 'undefined' 47393 const query = match[6] || ''; 47394 const fragment = match[8] || ''; 47395 return { 47396 host: match[4], 47397 path: match[5], 47398 protocol: match[2], 47399 search: query, 47400 hash: fragment, 47401 relative: match[5] + query + fragment, // everything minus origin 47402 }; 47403} 47404 47405/** 47406 * Strip the query string and fragment off of a given URL or path (if present) 47407 * 47408 * @param urlPath Full URL or path, including possible query string and/or fragment 47409 * @returns URL or path without query string or fragment 47410 */ 47411function stripUrlQueryAndFragment(urlPath) { 47412 // eslint-disable-next-line no-useless-escape 47413 return urlPath.split(/[\?#]/, 1)[0]; 47414} 47415 47416/** 47417 * Returns number of URL segments of a passed string URL. 47418 */ 47419function getNumberOfUrlSegments(url) { 47420 // split at '/' or at '\/' to split regex urls correctly 47421 return url.split(/\\?\//).filter(s => s.length > 0 && s !== ',').length; 47422} 47423 47424/** 47425 * Takes a URL object and returns a sanitized string which is safe to use as span description 47426 * see: https://develop.sentry.dev/sdk/data-handling/#structuring-d
47426ata 47427 */ 47428function getSanitizedUrlString(url) { 47429 const { protocol, host, path } = url; 47430 47431 const filteredHost = 47432 (host && 47433 host 47434 // Always filter out authority 47435 .replace(/^.*@/, '[filtered]:[filtered]@') 47436 // Don't show standard :80 (http) and :443 (https) ports to reduce the noise 47437 // TODO: Use new URL global if it exists 47438 .replace(/(:80)$/, '') 47439 .replace(/(:443)$/, '')) || 47440 ''; 47441 47442 return `${protocol ? `${protocol}://` : ''}${filteredHost}${path}`; 47443} 47444 47445exports.getNumberOfUrlSegments = getNumberOfUrlSegments; 47446exports.getSanitizedUrlString = getSanitizedUrlString; 47447exports.parseUrl = parseUrl; 47448exports.stripUrlQueryAndFragment = stripUrlQueryAndFragment; 47449 47450 47451},{}],351:[function(require,module,exports){ 47452Object.defineProperty(exports, '__esModule', { value: true }); 47453 47454/** 47455 * Recursively traverses an object to update an existing nested key. 47456 * Note: The provided key path must include existing properties, 47457 * the function will not create objects while traversing. 47458 * 47459 * @param obj An object to update 47460 * @param value The value to update the nested key with 47461 * @param keyPath The path to the key to update ex. fizz.buzz.foo 47462 */ 47463// eslint-disable-next-line @typescript-eslint/no-explicit-any 47464function setNestedKey(obj, keyPath, value) { 47465 // Ex. foo.bar.zoop will extract foo and bar.zoop 47466 const match = keyPath.match(/([a-z_]+)\.(.*)/i); 47467 // The match will be null when there's no more recursing to do, i.e., when we've reached the right level of the object 47468 if (match === null) { 47469 obj[keyPath] = value; 47470 } else { 47471 // `match[1]` is the initial segment of the path, and `match[2]` is the remainder of the path 47472 const innerObj = obj[match[1]]; 47473 setNestedKey(innerObj, match[2], value); 47474 } 47475} 47476 47477/** 47478 * Enforces inclusion of a given integration with specified options in an integration array originally determined by the 47479 * user, by either including the given default instance or by patching an existing user instance with the given options. 47480 * 47481 * Ideally this would happen when integrations are set up, but there isn't currently a mechanism there for merging 47482 * options from a default integration instance with those from a user-provided instance of the same integration, only 47483 * for allowing the user to override a default instance entirely. (TODO: Fix that.) 47484 * 47485 * @param defaultIntegrationInstance An instance of the integration with the correct options already set 47486 * @param userIntegrations Integrations defined by the user. 47487 * @param forcedOptions Options with which to patch an existing user-derived instance on the integration. 47488 * @returns A final integrations array. 47489 * 47490 * @deprecated This will be removed in v8. 47491 */ 47492function addOrUpdateIntegration( 47493 defaultIntegrationInstance, 47494 userIntegrations, 47495 forcedOptions = {}, 47496) { 47497 return ( 47498 Array.isArray(userIntegrations) 47499 ? addOrUpdateIntegrationInArray(defaultIntegrationInstance, userIntegrations, forcedOptions) 47500 : addOrUpdateIntegrationInFunction( 47501 defaultIntegrationInstance, 47502 // Somehow TS can't figure out that not being an array makes this necessarily a function 47503 userIntegrations , 47504 forcedOptions, 47505 ) 47506 ) ; 47507} 47508 47509function addOrUpdateIntegrationInArray( 47510 defaultIntegrationInstance, 47511 userIntegrations, 47512 forcedOptions, 47513) { 47514 const userInstance = userIntegrations.find(integration => integration.name === defaultIntegrationInstance.name); 47515 47516 if (userInstance) { 47517 for (const [keyPath, value] of Object.entries(forcedOptions)) { 47518 setNestedKey(userInstance, keyPath, value); 47519 } 47520 47521 return userIntegrations; 47522 } 47523 47524 return [...userIntegrations, defaultIntegrationInstance]; 47525} 47526 47527function addOrUpdateIntegrationInFunction( 47528 defaultIntegrationInstance, 47529 userIntegrationsFunc, 47530 forcedOptions, 47531) { 47532 const wrapper = defaultIntegrations => { 47533 const userFinalIntegrations = userIntegrationsFunc(defaultIntegrations); 47534 47535 // There are instances where we want the user to be able to prevent an integration from appearing at all, which they 47536 // would do by providing a function which filters out the integration in question. If that's happened in one of 47537 // those cases, don't add our default back in. 47538 if (defaultIntegrationInstance.allowExclusionByUser) { 47539 const userFinalInstance = userFinalIntegrations.find( 47540 integration => integration.name === defaultIntegrationInstance.name, 47541 ); 47542 if (!userFinalInstance) { 47543 return userFinalIntegrations; 47544 } 47545 } 47546 47547 return addOrUpdateIntegrationInArray(defaultIntegrationInstance, userFinalIntegrations, forcedOptions); 47548 }; 47549 47550 return wrapper; 47551} 47552 47553exports.addOrUpdateIntegration = addOrUpdateIntegration; 47554 47555 47556},{}],352:[function(require,module,exports){ 47557Object.defineProperty(exports, '__esModule', { value: true }); 47558 47559// Based on https://github.com/sindresorhus/escape-string-regexp but with modifications to: 47560// a) reduce the size by skipping the runtime type - checking 47561// b) ensure it gets down - compiled for old versions of Node(the published package only supports Node 12+). 47562// 47563// MIT License 47564// 47565// Copyright (c) Sindre Sorhus <[email protected]> (https://sindresorhus.com) 47566// 47567// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 47568// documentation files(the "Software"), to deal in the Software without restriction, including without limitation 47569// the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and 47570// to permit persons to whom the Software is furnished to do so, subject to the following conditions: 47571// 47572// The above copyright notice and this permission notice shall be included in all copies or substantial portions of 47573// the Software. 47574// 47575// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 47576// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 47577// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 47578// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 47579// IN THE SOFTWARE. 47580 47581/** 47582 * Given a string, escape characters which have meaning in the regex grammar, such that the result is safe to feed to 47583 * `new RegExp()`. 47584 * 47585 * @param regexString The string to escape 47586 * @returns An version of the string with all special regex characters escaped 47587 */ 47588function escapeStringForRegex(regexString) { 47589 // escape the hyphen separately so we can also replace it with a unicode literal hyphen, to avoid the problems 47590 // discussed in https://github.com/sindresorhus/escape-string-regexp/issues/20. 47591 return regexString.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d'); 47592} 47593 47594exports.escapeStringForRegex = escapeStringForRegex; 47595 47596 47597},{}],353:[function(require,module,exports){ 47598Object.defineProperty(exports, '__esModule', { value: true }); 47599 47600const worldwide = require('../worldwide.js'); 47601 47602// Based on https://github.com/angular/angular.js/pull/13945/files 47603 47604// eslint-disable-next-line deprecation/deprecation 47605const WINDOW = worldwide.getGlobalObject(); 47606 47607/** 47608 * Tells whether current environment supports History API 47609 * {@link supportsHistory}. 47610 * 47611 * @returns Answer to the given question. 47612 */ 47613function supportsHistory() { 47614 // NOTE: in Chrome App environment, touching history.pushState, *even inside 47615 // a try/catch block*, will cause Chrome to output an error to console.error 47616 // borrowed from: https://github.com/angular/angular.js/pull/13945/files 47617 /* eslint-disable @typescript-eslint/no-unsafe-member-access */ 47618 // eslint-disable-next-line @typescript-eslint/no-explicit-any 47619 const chromeVar = (WINDOW ).chrome; 47620 const isChromePackagedApp = chromeVar && chromeVar.app && chromeVar.app.runtime; 47621 /* eslint-enable @typescript-eslint/no-unsafe-member-access */ 47622 const hasHistoryApi = 'history' in WINDOW && !!WINDOW.history.pushState && !!WINDOW.history.replaceState; 47623 47624 return !isChromePackagedApp && hasHistoryApi; 47625} 47626 47627exports.supportsHistory = supportsHistory; 47628 47629 47630},{"../worldwide.js":354}],354:[function(require,module,exports){ 47631(function (global){(function (){ 47632Object.defineProperty(exports, '__esModule', { value: true }); 47633 47634/** Internal global with common properties and Sentry extensions */ 47635 47636// The code below for 'isGlobalObj' and 'GLOBAL_OBJ' was copied from core-js before modification 47637// https://github.com/zloirock/core-js/blob/1b944df55282cdc99c90db5f49eb0b6eda2cc0a3/packages/core-js/internals/global.js 47638// core-js has the following licence: 47639// 47640// Copyright (c) 2014-2022 Denis Pushkarev 47641// 47642// Permission is hereby granted, free of charge, to any person obtaining a copy 47643// of this software and associated documentation files (the "Software"), to deal 47644// in the Software without restriction, including without limitation the rights 47645// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 47646// copies of the Software, and to permit persons to whom the Software is 47647// furnished to do so, subject to the following conditions: 47648// 47649// The above copyright notice and this permission notice shall be included in 47650// all copies or substantial portions of the Software. 47651// 47652// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47653// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47654// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47655// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47656// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47657// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47658// THE SOFTWARE. 47659 47660/** Returns 'obj' if it's the global object, otherwise returns undefined */ 47661function isGlobalObj(obj) { 47662 return obj && obj.Math == Math ? obj : undefined; 47663} 47664 47665/** Get's the global object for the current JavaScript runtime */ 47666const GLOBAL_OBJ = 47667 (typeof globalThis == 'object' && isGlobalObj(globalThis)) || 47668 // eslint-disable-next-line no-restricted-globals 47669 (typeof window == 'object' && isGlobalObj(window)) || 47670 (typeof self == 'object' && isGlobalObj(self)) || 47671 (typeof global == 'object' && isGlobalObj(global)) || 47672 (function () { 47673 return this; 47674 })() || 47675 {}; 47676 47677/** 47678 * @deprecated Use GLOBAL_OBJ instead or WINDOW from @sentry/browser. This will be removed in v8 47679 */ 47680function getGlobalObject() { 47681 return GLOBAL_OBJ ; 47682} 47683 47684/** 47685 * Returns a global singleton contained in the global `__SENTRY__` object. 47686 * 47687 * If the singleton doesn't already exist in `__SENTRY__`, it will be created using the given factory 47688 * function and added to the `__SENTRY__` object. 47689 * 47690 * @param name name of the global singleton on __SENTRY__ 47691 * @param creator creator Factory function to create the singleton if it doesn't already exist on `__SENTRY__` 47692 * @param obj (Optional) The global object on which to look for `__SENTRY__`, if not `GLOBAL_OBJ`'s return value 47693 * @returns the singleton 47694 */ 47695function getGlobalSingleton(name, creator, obj) { 47696 const gbl = (obj || GLOBAL_OBJ) ; 47697 const __SENTRY__ = (gbl.__SENTRY__ = gbl.__SENTRY__ || {}); 47698 const singleton = __SENTRY__[name] || (__SENTRY__[name] = creator()); 47699 return singleton; 47700} 47701 47702exports.GLOBAL_OBJ = GLOBAL_OBJ; 47703exports.getGlobalObject = getGlobalObject; 47704exports.getGlobalSingleton = getGlobalSingleton; 47705 47706 47707}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 47708},{}],355:[function(require,module,exports){ 47709(function (global){(function (){
vendor: 14,672 bytes, lines 47709-48243
47709 47710/*! https://mths.be/punycode v1.4.1 by @mathias */ 47711;(function(root) { 47712 47713 /** Detect free variables */ 47714 var freeExports = typeof exports == 'object' && exports && 47715 !exports.nodeType && exports; 47716 var freeModule = typeof module == 'object' && module && 47717 !module.nodeType && module; 47718 var freeGlobal = typeof global == 'object' && global; 47719 if ( 47720 freeGlobal.global === freeGlobal || 47721 freeGlobal.window === freeGlobal || 47722 freeGlobal.self === freeGlobal 47723 ) { 47724 root = freeGlobal; 47725 } 47726 47727 /** 47728 * The `punycode` object. 47729 * @name punycode 47730 * @type Object 47731 */ 47732 var punycode, 47733 47734 /** Highest positive signed 32-bit float value */ 47735 maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 47736 47737 /** Bootstring parameters */ 47738 base = 36, 47739 tMin = 1, 47740 tMax = 26, 47741 skew = 38, 47742 damp = 700, 47743 initialBias = 72, 47744 initialN = 128, // 0x80 47745 delimiter = '-', // '\x2D' 47746 47747 /** Regular expressions */ 47748 regexPunycode = /^xn--/, 47749 regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars 47750 regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators 47751 47752 /** Error messages */ 47753 errors = { 47754 'overflow': 'Overflow: input needs wider integers to process', 47755 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', 47756 'invalid-input': 'Invalid input' 47757 }, 47758 47759 /** Convenience shortcuts */ 47760 baseMinusTMin = base - tMin, 47761 floor = Math.floor, 47762 stringFromCharCode = String.fromCharCode, 47763 47764 /** Temporary variable */ 47765 key; 47766 47767 /*--------------------------------------------------------------------------*/ 47768 47769 /** 47770 * A generic error utility function. 47771 * @private 47772 * @param {String} type The error type. 47773 * @returns {Error} Throws a `RangeError` with the applicable error message. 47774 */ 47775 function error(type) { 47776 throw new RangeError(errors[type]); 47777 } 47778 47779 /** 47780 * A generic `Array#map` utility function. 47781 * @private 47782 * @param {Array} array The array to iterate over. 47783 * @param {Function} callback The function that gets called for every array 47784 * item. 47785 * @returns {Array} A new array of values returned by the callback function. 47786 */ 47787 function map(array, fn) { 47788 var length = array.length; 47789 var result = []; 47790 while (length--) { 47791 result[length] = fn(array[length]); 47792 } 47793 return result; 47794 } 47795 47796 /** 47797 * A simple `Array#map`-like wrapper to work with domain name strings or email 47798 * addresses. 47799 * @private 47800 * @param {String} domain The domain name or email address. 47801 * @param {Function} callback The function that gets called for every 47802 * character. 47803 * @returns {Array} A new string of characters returned by the callback 47804 * function. 47805 */ 47806 function mapDomain(string, fn) { 47807 var parts = string.split('@'); 47808 var result = ''; 47809 if (parts.length > 1) { 47810 // In email addresses, only the domain name should be punycoded. Leave 47811 // the local part (i.e. everything up to `@`) intact. 47812 result = parts[0] + '@'; 47813 string = parts[1]; 47814 } 47815 // Avoid `split(regex)` for IE8 compatibility. See #17. 47816 string = string.replace(regexSeparators, '\x2E'); 47817 var labels = string.split('.'); 47818 var encoded = map(labels, fn).join('.'); 47819 return result + encoded; 47820 } 47821 47822 /** 47823 * Creates an array containing the numeric code points of each Unicode 47824 * character in the string. While JavaScript uses UCS-2 internally, 47825 * this function will convert a pair of surrogate halves (each of which 47826 * UCS-2 exposes as separate characters) into a single code point, 47827 * matching UTF-16. 47828 * @see `punycode.ucs2.encode` 47829 * @see <https://mathiasbynens.be/notes/javascript-encoding> 47830 * @memberOf punycode.ucs2 47831 * @name decode 47832 * @param {String} string The Unicode input string (UCS-2). 47833 * @returns {Array} The new array of code points. 47834 */ 47835 function ucs2decode(string) { 47836 var output = [], 47837 counter = 0, 47838 length = string.length, 47839 value, 47840 extra; 47841 while (counter < length) { 47842 value = string.charCodeAt(counter++); 47843 if (value >= 0xD800 && value <= 0xDBFF && counter < length) { 47844 // high surrogate, and there is a next character 47845 extra = string.charCodeAt(counter++); 47846 if ((extra & 0xFC00) == 0xDC00) { // low surrogate 47847 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); 47848 } else { 47849 // unmatched surrogate; only append this code unit, in case the next 47850 // code unit is the high surrogate of a surrogate pair 47851 output.push(value); 47852 counter--; 47853 } 47854 } else { 47855 output.push(value); 47856 } 47857 } 47858 return output; 47859 } 47860 47861 /** 47862 * Creates a string based on an array of numeric code points. 47863 * @see `punycode.ucs2.decode` 47864 * @memberOf punycode.ucs2 47865 * @name encode 47866 * @param {Array} codePoints The array of numeric code points. 47867 * @returns {String} The new Unicode string (UCS-2). 47868 */ 47869 function ucs2encode(array) { 47870 return map(array, function(value) { 47871 var output = ''; 47872 if (value > 0xFFFF) { 47873 value -= 0x10000; 47874 output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); 47875 value = 0xDC00 | value & 0x3FF; 47876 } 47877 output += stringFromCharCode(value); 47878 return output; 47879 }).join(''); 47880 } 47881 47882 /** 47883 * Converts a basic code point into a digit/integer. 47884 * @see `digitToBasic()` 47885 * @private 47886 * @param {Number} codePoint The basic numeric code point value. 47887 * @returns {Number} The numeric value of a basic code point (for use in 47888 * representing integers) in the range `0` to `base - 1`, or `base` if 47889 * the code point does not represent a value. 47890 */ 47891 function basicToDigit(codePoint) { 47892 if (codePoint - 48 < 10) { 47893 return codePoint - 22; 47894 } 47895 if (codePoint - 65 < 26) { 47896 return codePoint - 65; 47897 } 47898 if (codePoint - 97 < 26) { 47899 return codePoint - 97; 47900 } 47901 return base; 47902 } 47903 47904 /** 47905 * Converts a digit/integer into a basic code point. 47906 * @see `basicToDigit()` 47907 * @private 47908 * @param {Number} digit The numeric value of a basic code point. 47909 * @returns {Number} The basic code point whose value (when used for 47910 * representing integers) is `digit`, which needs to be in the range 47911 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is 47912 * used; else, the lowercase form is used. The behavior is undefined 47913 * if `flag` is non-zero and `digit` has no uppercase form. 47914 */ 47915 function digitToBasic(digit, flag) { 47916 // 0..25 map to ASCII a..z or A..Z 47917 // 26..35 map to ASCII 0..9 47918 return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); 47919 } 47920 47921 /** 47922 * Bias adaptation function as per section 3.4 of RFC 3492. 47923 * https://tools.ietf.org/html/rfc3492#section-3.4 47924 * @private 47925 */ 47926 function adapt(delta, numPoints, firstTime) { 47927 var k = 0; 47928 delta = firstTime ? floor(delta / damp) : delta >> 1; 47929 delta += floor(delta / numPoints); 47930 for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { 47931 delta = floor(delta / baseMinusTMin); 47932 } 47933 return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); 47934 } 47935 47936 /** 47937 * Converts a Punycode string of ASCII-only symbols to a string of Unicode 47938 * symbols. 47939 * @memberOf punycode 47940 * @param {String} input The Punycode string of ASCII-only symbols. 47941 * @returns {String} The resulting string of Unicode symbols. 47942 */ 47943 function decode(input) { 47944 // Don't use UCS-2 47945 var output = [], 47946 inputLength = input.length, 47947 out, 47948 i = 0, 47949 n = initialN, 47950 bias = initialBias, 47951 basic, 47952 j, 47953 index, 47954 oldi, 47955 w, 47956 k, 47957 digit, 47958 t, 47959 /** Cached calculation results */ 47960 baseMinusT; 47961 47962 // Handle the basic code points: let `basic` be the number of input code 47963 // points before the last delimiter, or `0` if there is none, then copy 47964 // the first basic code points to the output. 47965 47966 basic = input.lastIndexOf(delimiter); 47967 if (basic < 0) { 47968 basic = 0; 47969 } 47970 47971 for (j = 0; j < basic; ++j) { 47972 // if it's not a basic code point 47973 if (input.charCodeAt(j) >= 0x80) { 47974 error('not-basic'); 47975 } 47976 output.push(input.charCodeAt(j)); 47977 } 47978 47979 // Main decoding loop: start just after the last delimiter if any basic code 47980 // points were copied; start at the beginning otherwise. 47981 47982 for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { 47983 47984 // `index` is the index of the next character to be consumed. 47985 // Decode a generalized variable-length integer into `delta`, 47986 // which gets added to `i`. The overflow checking is easier 47987 // if we increase `i` as we go, then subtract off its starting 47988 // value at the end to obtain `delta`. 47989 for (oldi = i, w = 1, k = base; /* no condition */; k += base) { 47990 47991 if (index >= inputLength) { 47992 error('invalid-input'); 47993 } 47994 47995 digit = basicToDigit(input.charCodeAt(index++)); 47996 47997 if (digit >= base || digit > floor((maxInt - i) / w)) { 47998 error('overflow'); 47999 } 48000 48001 i += digit * w; 48002 t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); 48003 48004 if (digit < t) { 48005 break; 48006 } 48007 48008 baseMinusT = base - t; 48009 if (w > floor(maxInt / baseMinusT)) { 48010 error('overflow'); 48011 } 48012 48013 w *= baseMinusT; 48014 48015 } 48016 48017 out = output.length + 1; 48018 bias = adapt(i - oldi, out, oldi == 0); 48019 48020 // `i` was supposed to wrap around from `out` to `0`, 48021 // incrementing `n` each time, so we'll fix that now: 48022 if (floor(i / out) > maxInt - n) { 48023 error('overflow'); 48024 } 48025 48026 n += floor(i / out); 48027 i %= out; 48028 48029 // Insert `n` at position `i` of the output 48030 output.splice(i++, 0, n); 48031 48032 } 48033 48034 return ucs2encode(output); 48035 } 48036 48037 /** 48038 * Converts a string of Unicode symbols (e.g. a domain name label) to a 48039 * Punycode string of ASCII-only symbols. 48040 * @memberOf punycode 48041 * @param {String} input The string of Unicode symbols. 48042 * @returns {String} The resulting Punycode string of ASCII-only symbols. 48043 */ 48044 function encode(input) { 48045 var n, 48046 delta, 48047 handledCPCount, 48048 basicLength, 48049 bias, 48050 j, 48051 m, 48052 q, 48053 k, 48054 t, 48055 currentValue, 48056 output = [], 48057 /** `inputLength` will hold the number of code points in `input`. */ 48058 inputLength, 48059 /** Cached calculation results */ 48060 handledCPCountPlusOne, 48061 baseMinusT, 48062 qMinusT; 48063 48064 // Convert the input in UCS-2 to Unicode 48065 input = ucs2decode(input); 48066 48067 // Cache the length 48068 inputLength = input.length; 48069 48070 // Initialize the state 48071 n = initialN; 48072 delta = 0; 48073 bias = initialBias; 48074 48075 // Handle the basic code points 48076 for (j = 0; j < inputLength; ++j) { 48077 currentValue = input[j]; 48078 if (currentValue < 0x80) { 48079 output.push(stringFromCharCode(currentValue)); 48080 } 48081 } 48082 48083 handledCPCount = basicLength = output.length; 48084 48085 // `handledCPCount` is the number of code points that have been handled; 48086 // `basicLength` is the number of basic code points. 48087 48088 // Finish the basic string - if it is not empty - with a delimiter 48089 if (basicLength) { 48090 output.push(delimiter); 48091 } 48092 48093 // Main encoding loop: 48094 while (handledCPCount < inputLength) { 48095 48096 // All non-basic code points < n have been handled already. Find the next 48097 // larger one: 48098 for (m = maxInt, j = 0; j < inputLength; ++j) { 48099 currentValue = input[j]; 48100 if (currentValue >= n && currentValue < m) { 48101 m = currentValue; 48102 } 48103 } 48104 48105 // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, 48106 // but guard against overflow 48107 handledCPCountPlusOne = handledCPCount + 1; 48108 if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { 48109 error('overflow'); 48110 } 48111 48112 delta += (m - n) * handledCPCountPlusOne; 48113 n = m; 48114 48115 for (j = 0; j < inputLength; ++j) { 48116 currentValue = input[j]; 48117 48118 if (currentValue < n && ++delta > maxInt) { 48119 error('overflow'); 48120 } 48121 48122 if (currentValue == n) { 48123 // Represent delta as a generalized variable-length integer 48124 for (q = delta, k = base; /* no condition */; k += base) { 48125 t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); 48126 if (q < t) { 48127 break; 48128 } 48129 qMinusT = q - t; 48130 baseMinusT = base - t; 48131 output.push( 48132 stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) 48133 ); 48134 q = floor(qMinusT / baseMinusT); 48135 } 48136 48137 output.push(stringFromCharCode(digitToBasic(q, 0))); 48138 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); 48139 delta = 0; 48140 ++handledCPCount; 48141 } 48142 } 48143 48144 ++delta; 48145 ++n; 48146 48147 } 48148 return output.join(''); 48149 } 48150 48151 /** 48152 * Converts a Punycode string representing a domain name or an email address 48153 * to Unicode. Only the Punycoded parts of the input will be converted, i.e. 48154 * it doesn't matter if you call it on a string that has already been 48155 * converted to Unicode. 48156 * @memberOf punycode 48157 * @param {String} input The Punycoded domain name or email address to 48158 * convert to Unicode. 48159 * @returns {String} The Unicode representation of the given Punycode 48160 * string. 48161 */ 48162 function toUnicode(input) { 48163 return mapDomain(input, function(string) { 48164 return regexPunycode.test(string) 48165 ? decode(string.slice(4).toLowerCase()) 48166 : string; 48167 }); 48168 } 48169 48170 /** 48171 * Converts a Unicode string representing a domain name or an email address to 48172 * Punycode. Only the non-ASCII parts of the domain name will be converted, 48173 * i.e. it doesn't matter if you call it with a domain that's already in 48174 * ASCII. 48175 * @memberOf punycode 48176 * @param {String} input The domain name or email address to convert, as a 48177 * Unicode string. 48178 * @returns {String} The Punycode representation of the given domain name or 48179 * email address. 48180 */ 48181 function toASCII(input) { 48182 return mapDomain(input, function(string) { 48183 return regexNonASCII.test(string) 48184 ? 'xn--' + encode(string) 48185 : string; 48186 }); 48187 } 48188 48189 /*--------------------------------------------------------------------------*/ 48190 48191 /** Define the public API */ 48192 punycode = { 48193 /** 48194 * A string representing the current Punycode.js version number. 48195 * @memberOf punycode 48196 * @type String 48197 */ 48198 'version': '1.4.1', 48199 /** 48200 * An object of methods to convert from JavaScript's internal character 48201 * representation (UCS-2) to Unicode code points, and back. 48202 * @see <https://mathiasbynens.be/notes/javascript-encoding> 48203 * @memberOf punycode 48204 * @type Object 48205 */ 48206 'ucs2': { 48207 'decode': ucs2decode, 48208 'encode': ucs2encode 48209 }, 48210 'decode': decode, 48211 'encode': encode, 48212 'toASCII': toASCII, 48213 'toUnicode': toUnicode 48214 }; 48215 48216 /** Expose `punycode` */ 48217 // Some AMD build optimizers, like r.js, check for specific condition patterns 48218 // like the following: 48219 if ( 48220 typeof define == 'function' && 48221 typeof define.amd == 'object' && 48222 define.amd 48223 ) { 48224 define('punycode', function() { 48225 return punycode; 48226 }); 48227 } else if (freeExports && freeModule) { 48228 if (module.exports == freeExports) { 48229 // in Node.js, io.js, or RingoJS v0.8.0+ 48230 freeModule.exports = punycode; 48231 } else { 48232 // in Narwhal or RingoJS v0.7.0- 48233 for (key in punycode) { 48234 punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); 48235 } 48236 } 48237 } else { 48238 // in Rhino or a web browser 48239 root.punycode = punycode; 48240 } 48241 48242}(this)); 48243
vendor: 4,425 bytes, lines 48244-48424
48244}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 48245},{}],356:[function(require,module,exports){ 48246/* 48247 * classList.js: Cross-browser full element.classList implementation. 48248 * 1.1.20170427 48249 * 48250 * By Eli Grey, http://eligrey.com 48251 * License: Dedicated to the public domain. 48252 * See https://github.com/eligrey/classList.js/blob/master/LICENSE.md 48253 */ 48254 48255/*global self, document, DOMException */ 48256 48257/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */ 48258 48259if ("document" in window.self) { 48260 48261// Full polyfill for browsers with no classList support 48262// Including IE < Edge missing SVGElement.classList 48263if (!("classList" in document.createElement("_")) 48264 || document.createElementNS && !("classList" in document.createElementNS("http://www.w3.org/2000/svg","g"))) { 48265 48266(function (view) { 48267 48268"use strict"; 48269 48270if (!('Element' in view)) return; 48271 48272var 48273 classListProp = "classList" 48274 , protoProp = "prototype" 48275 , elemCtrProto = view.Element[protoProp] 48276 , objCtr = Object 48277 , strTrim = String[protoProp].trim || function () { 48278 return this.replace(/^\s+|\s+$/g, ""); 48279 } 48280 , arrIndexOf = Array[protoProp].indexOf || function (item) { 48281 var 48282 i = 0 48283 , len = this.length 48284 ; 48285 for (; i < len; i++) { 48286 if (i in this && this[i] === item) { 48287 return i; 48288 } 48289 } 48290 return -1; 48291 } 48292 // Vendors: please allow content code to instantiate DOMExceptions 48293 , DOMEx = function (type, message) { 48294 this.name = type; 48295 this.code = DOMException[type]; 48296 this.message = message; 48297 } 48298 , checkTokenAndGetIndex = function (classList, token) { 48299 if (token === "") { 48300 throw new DOMEx( 48301 "SYNTAX_ERR" 48302 , "An invalid or illegal string was specified" 48303 ); 48304 } 48305 if (/\s/.test(token)) { 48306 throw new DOMEx( 48307 "INVALID_CHARACTER_ERR" 48308 , "String contains an invalid character" 48309 ); 48310 } 48311 return arrIndexOf.call(classList, token); 48312 } 48313 , ClassList = function (elem) { 48314 var 48315 trimmedClasses = strTrim.call(elem.getAttribute("class") || "") 48316 , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] 48317 , i = 0 48318 , len = classes.length 48319 ; 48320 for (; i < len; i++) { 48321 this.push(classes[i]); 48322 } 48323 this._updateClassName = function () { 48324 elem.setAttribute("class", this.toString()); 48325 }; 48326 } 48327 , classListProto = ClassList[protoProp] = [] 48328 , classListGetter = function () { 48329 return new ClassList(this); 48330 } 48331; 48332// Most DOMException implementations don't allow calling DOMException's toString() 48333// on non-DOMExceptions. Error's toString() is sufficient here. 48334DOMEx[protoProp] = Error[protoProp]; 48335classListProto.item = function (i) { 48336 return this[i] || null; 48337}; 48338classListProto.contains = function (token) { 48339 token += ""; 48340 return checkTokenAndGetIndex(this, token) !== -1; 48341}; 48342classListProto.add = function () { 48343 var 48344 tokens = arguments 48345 , i = 0 48346 , l = tokens.length 48347 , token 48348 , updated = false 48349 ; 48350 do { 48351 token = tokens[i] + ""; 48352 if (checkTokenAndGetIndex(this, token) === -1) { 48353 this.push(token); 48354 updated = true; 48355 } 48356 } 48357 while (++i < l); 48358 48359 if (updated) { 48360 this._updateClassName(); 48361 } 48362}; 48363classListProto.remove = function () { 48364 var 48365 tokens = arguments 48366 , i = 0 48367 , l = tokens.length 48368 , token 48369 , updated = false 48370 , index 48371 ; 48372 do { 48373 token = tokens[i] + ""; 48374 index = checkTokenAndGetIndex(this, token); 48375 while (index !== -1) { 48376 this.splice(index, 1); 48377 updated = true; 48378 index = checkTokenAndGetIndex(this, token); 48379 } 48380 } 48381 while (++i < l); 48382 48383 if (updated) { 48384 this._updateClassName(); 48385 } 48386}; 48387classListProto.toggle = function (token, force) { 48388 token += ""; 48389 48390 var 48391 result = this.contains(token) 48392 , method = result ? 48393 force !== true && "remove" 48394 : 48395 force !== false && "add" 48396 ; 48397 48398 if (method) { 48399 this[method](token); 48400 } 48401 48402 if (force === true || force === false) { 48403 return force; 48404 } else { 48405 return !result; 48406 } 48407}; 48408classListProto.toString = function () { 48409 return this.join(" "); 48410}; 48411 48412if (objCtr.defineProperty) { 48413 var classListPropDesc = { 48414 get: classListGetter 48415 , enumerable: true 48416 , configurable: true 48417 }; 48418 try { 48419 objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); 48420 } catch (ex) { // IE 8 doesn't support enumerable:true 48421 // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36 48422 // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected 48423 if (ex.number === undefined || ex.number === -0x7FF5EC54) { 48424 classListPropDesc.enumerable = false;
48425 objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); 48426 } 48427 } 48428} else if (objCtr[protoProp].__defineGetter__) { 48429 elemCtrProto.__defineGetter__(classListProp, classListGetter); 48430} 48431 48432}(window.self)); 48433 48434} 48435 48436// There is full or partial native classList support, so just check if we need 48437// to normalize the add/remove and toggle APIs. 48438 48439(function () { 48440 "use strict"; 48441 48442 var testElement = document.createElement("_"); 48443 48444 testElement.classList.add("c1", "c2"); 48445 48446 // Polyfill for IE 10/11 and Firefox <26, where classList.add and 48447 // classList.remove exist but support only one argument at a time. 48448 if (!testElement.classList.contains("c2")) { 48449 var createMethod = function(method) { 48450 var original = DOMTokenList.prototype[method]; 48451 48452 DOMTokenList.prototype[method] = function(token) { 48453 var i, len = arguments.length; 48454 48455 for (i = 0; i < len; i++) { 48456 token = arguments[i]; 48457 original.call(this, token); 48458 } 48459 }; 48460 }; 48461 createMethod('add'); 48462 createMethod('remove'); 48463 } 48464 48465 testElement.classList.toggle("c3", false); 48466 48467 // Polyfill for IE 10 and Firefox <24, where classList.toggle does not 48468 // support the second argument. 48469 if (testElement.classList.contains("c3")) { 48470 var _toggle = DOMTokenList.prototype.toggle; 48471 48472 DOMTokenList.prototype.toggle = function(token, force) { 48473 if (1 in arguments && !this.contains(token) === !force) { 48474 return force; 48475 } else { 48476 return _toggle.call(this, token); 48477 } 48478 }; 48479 48480 } 48481 48482 testElement = null; 48483}()); 48484 48485} 48486 48487},{}],357:[function(require,module,exports){ 48488module.exports = function(arr, obj){ 48489 if (arr.indexOf) return arr.indexOf(obj); 48490 for (var i = 0; i < arr.length; ++i) { 48491 if (arr[i] === obj) return i; 48492 } 48493 return -1; 48494}; 48495},{}],358:[function(require,module,exports){ 48496'use strict'; 48497 48498require('./index').polyfill(); 48499 48500},{"./index":359}],359:[function(require,module,exports){ 48501/** 48502 * Code refactored from Mozilla Developer Network: 48503 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 48504 */ 48505 48506'use strict'; 48507 48508function assign(target, firstSource) { 48509 if (target === undefined || target === null) { 48510 throw new TypeError('Cannot convert first argument to object'); 48511 } 48512 48513 var to = Object(target); 48514 for (var i = 1; i < arguments.length; i++) { 48515 var nextSource = arguments[i]; 48516 if (nextSource === undefined || nextSource === null) { 48517 continue; 48518 } 48519 48520 var keysArray = Object.keys(Object(nextSource)); 48521 for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { 48522 var nextKey = keysArray[nextIndex]; 48523 var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey); 48524 if (desc !== undefined && desc.enumerable) { 48525 to[nextKey] = nextSource[nextKey]; 48526 } 48527 } 48528 } 48529 return to; 48530} 48531 48532function polyfill() { 48533 if (!Object.assign) { 48534 Object.defineProperty(Object, 'assign', { 48535 enumerable: false, 48536 configurable: true, 48537 writable: true, 48538 value: assign 48539 }); 48540 } 48541} 48542 48543module.exports = { 48544 assign: assign, 48545 polyfill: polyfill 48546}; 48547 48548},{}],360:[function(require,module,exports){ 48549(function (process){(function (){ 48550"use strict";Object.defineProperties(exports,{t:{value:!0},[Symbol.toStringTag]:{value:"Module"}});class t{constructor(t,s,e,r=t<<16|s<<8|e){this.i=1,this.o=-1,this.h=-1,this.u=-1,this.l=-1,this.M=t,this.g=s,this.p=e,this.m=r}static distance(t,s){return(Math.abs(s.M-t.M)+Math.abs(s.g-t.g)+Math.abs(s.p-t.p))/765}clone(){const s=new t(this.M,this.g,this.p,this.m);return s.i=this.i,s}$(){const t=this.M/255,s=this.g/255,e=this.p/255,r=Math.max(t,s,e),n=Math.min(t,s,e);if(this.u=(r+n)/2,r===n)this.h=0,this.o=0,this.l=0;else{const i=r-n;switch(this.o=this.u>.5?i/(2-r-n):i/(r+n),this.l=this.o*(2*(.5-Math.abs(.5-this.u))),r){case t:this.h=((s-e)/i+(s<e?6:0))/6;break;case s:this.h=((e-t)/i+2)/6;break;case e:this.h=((t-s)/i+4)/6}}}get C(){return-1===this.h&&this.$(),this.h}get v(){return-1===this.o&&this.$(),this.o}get j(){return-1===this.u&&this.$(),this.u}get D(){return-1===this.l&&this.$(),this.l}}const s=(t,s)=>Math.abs(t-s);class e{constructor(){this.N=[],this.S=null}I(t){this.N.push(t),this.S=null}O(t,e,r,n){for(let h=0;h<this.N.length;h++){const a=this.N[h];if(!(i=a.C,o=t.C,Math.min(s(i,o),s((i+.5)%1,(o+.5)%1))<e&&s(a.v,t.v)<r&&s(a.j,t.j)<n))return!1}var i,o;return!0}get _(){if(!this.S){const{r:s,L:e,b:r}=this.N.reduce(((t,s)=>(t.r+=s.M,t.L+=s.g,t.b+=s.p,t)),{r:0,L:0,b:0}),n=this.N.reduce(((t,s)=>t+s.i),0);this.S=new t(Math.round(s/this.N.length),Math.round(e/this.N.length),Math.round(r/this.N.length)),this.S.i=n}return this.S}}
48550class r{constructor(t,s,e){this.P=[],this.C=t,this.v=s,this.j=e}I(t){const s=this.P.find((s=>s.O(t,this.C,this.v,this.j)));if(s)s.I(t);else{const s=new e;s.I(t),this.P.push(s)}}F(){return this.P.map((t=>t._))}}var n=({pixels:t=64e3,distance:s=.22,colorValidator:e=((t,s,e,r)=>(null!=r?r:255)>250),hueDistance:r=.08333333333333333,saturationDistance:n=.2,lightnessDistance:i=.2,crossOrigin:o=null}={})=>{if("production"!==process.env.NODE_ENV){const o=(t,s,e=0,r=Number.MAX_VALUE)=>{if(Number(s)!==s)throw new Error(`${t} is not a valid number (${s})`);return s<e&&console.warn(`${t} can not be less than ${e} (it's ${s})`),s>r&&console.warn(`${t} can not be more than ${r} (it's ${s})`),Math.min(Math.max(s,e),r)},h=(t,s)=>{if(!s||"[object Function]"!=={}.toString.call(s))throw new Error(`${t} is not a function (${s})`);return s};((t,s,e=0,r=Number.MAX_SAFE_INTEGER)=>{if(!Number.isInteger(s))throw new Error(`${t} is not a valid number (${s})`);return s<e&&console.warn(`${t} can not be less than ${e} (it's ${s})`),s>r&&console.warn(`${t} can not be more than ${r} (it's ${s})`),Math.min(Math.max(s,e),r)})("pixels",t||0,1),o("distance",s,0,1),h("colorValidator",e),o("hueDistance",r,0,1),o("saturationDistance",n,0,1),o("lightnessDistance",i,0,1)}return[Math.max(t,1),Math.min(Math.max(s,0),1),e,Math.min(Math.max(r,0),1),Math.min(Math.max(n,0),1),Math.min(Math.max(i,0),1),o]};class i{constructor(){this.i=0,this.k={}}I(s,e,r,n){return this.i++,this.k[s]?this.k[s].i++:this.k[s]=new t(e,r,n,s),this.k[s]}G(){return Object.keys(this.k).map((t=>this.k[t]))}H(){const t=this.G().reduce(((t,s)=>t.i>=s.i?t:s)).clone();return t.i=this.i,t}}class o{constructor(){this.i=0,this.k={}}G(){return Object.keys(this.k).map((t=>this.k[t]))}I(t,s,e){const r=t<<16|s<<8|e,n=(t>>4&15)<<8|(s>>4&15)<<4|e>>4&15;return this.i++,this.V(n).I(r,t,s,e)}V(t){return this.k[t]||(this.k[t]=new i),this.k[t]}T(s){const e=this.G().map((t=>t.H()));e.sort(((t,s)=>s.i-t.i));const r=[];for(;e.length;){const n=e.shift();e.filter((e=>t.distance(n,e)<s)).forEach((t=>{n.i+=t.i;const s=e.findIndex((s=>s===t));e.splice(s,1)})),r.push(n)}return r}}var h=({data:t,width:s,height:e},r,n,i)=>{const h=new o,a=s&&e&&Math.floor(s*e/r)||1;let c=0;for(let o=0;o<t.length;o+=4*a){const s=t[o],e=t[o+1],r=t[o+2];i(s,e,r,t[o+3])?h.I(s,e,r):c++}return{N:h.T(n),count:h.i+c}};const a=()=>"undefined"!=typeof window,c=(t,s,e,n,i)=>{const o=((t,s,e,n,i)=>{const o=new r(e,n,i);t.forEach((t=>o.I(t)));const h=o.F();return h.sort(((t,e)=>(e.D+.1)*(.9-e.i/s)-(t.D+.1)*(.9-t.i/s))),h})(t,s,e,n,i);return o.map((t=>((t,s)=>({hex:`#${"0".repeat(6-t.m.toString(16).length)}${t.m.toString(16)}`,red:t.M,green:t.g,blue:t.p,area:t.i/s,hue:t.C,saturation:t.v,lightness:t.j,intensity:t.D}))(t,s)))},u=(t,s={})=>{const[e,r,i,o,a,u]=n(s),{N:l,count:d}=h(t,e,r,i);return c(l,d,o,a,u)},l=(t,s={})=>{if(a()){const[e,r,i,o,a,u,l]=n(s);return t.crossOrigin=l,new Promise((s=>{const n=t=>{const n=((t,s)=>{const e=t.width*t.height,r=e<s?t.width:Math.round(t.width*Math.sqrt(s/e)),n=e<s?t.height:Math.round(t.height*Math.sqrt(s/e)),i=document.createElement("canvas");i.width=r,i.height=n;const o=i.getContext("2d");return o.drawImage(t,0,0,t.width,t.height,0,0,r,n),o.getImageData(0,0,r,n)})(t,e),{N:l,count:d}=h(n,e,r,i);s(c(l,d,o,a,u))};if(t.complete)n(t);else{const s=()=>{t.removeEventListener("load",s),n(t)};t.addEventListener("load",s)}}))}if("production"!==process.env.NODE_ENV)throw new Error("Can not use extractColorsFromImage for Node.js")},d=(t,s={})=>{if(a()){const e=new Image;return e.src=t,l(e,s)}if("production"!==process.env.NODE_ENV)throw new Error("Can not use extractColorsFromSrc for Node.js")};exports.extractColors=(t,s)=>{if(!a()){if("production"!==process.env.NODE_ENV){if(t instanceof String)throw new Error("Send imageData to extractColors (Image src or HTMLImageElement not supported in Nodejs)");if(!t.data)throw new Error("Send imageData to extractColors");(null==s?void 0:s.crossOrigin)&&console.warn("options.crossOrigin not supported in Node.js")}return new Promise((e=>{e(u(t,s))}))}if(t instanceof Image)return l(t,s);if(t instanceof ImageData||t instanceof Object&&t.data)return new Promise((e=>{e(u(t,s))}));if("string"==typeof t)return d(t,s);throw new Error("Can not analyse picture")},exports.extractColorsFromImage=l,exports.extractColorsFromImageData=u,exports.extractColorsFromSrc=d; 48551 48552 48553}
48553).call(this)}).call(this,require('_process')) 48554},{"_process":365}],361:[function(require,module,exports){ 48555 48556var hasOwn = Object.prototype.hasOwnProperty; 48557var toString = Object.prototype.toString; 48558 48559module.exports = function forEach (obj, fn, ctx) { 48560 if (toString.call(fn) !== '[object Function]') { 48561 throw new TypeError('iterator must be a function'); 48562 } 48563 var l = obj.length; 48564 if (l === +l) { 48565 for (var i = 0; i < l; i++) { 48566 fn.call(ctx, obj[i], i, obj); 48567 } 48568 } else { 48569 for (var k in obj) { 48570 if (hasOwn.call(obj, k)) { 48571 fn.call(ctx, obj[k], k, obj); 48572 } 48573 } 48574 } 48575}; 48576 48577 48578},{}],362:[function(require,module,exports){ 48579var each = require('each'), 48580 indexOf = require('indexof'); 48581 48582var getFragment = function( url ){ 48583 48584 var url = url || window.location.href; 48585 return url.replace( /^[^#]*#?(.*)$/, '$1' ); 48586 48587}; 48588 48589var HashChange = function(){ 48590 48591 var self = this; 48592 48593 this.onChangeCallbacks = []; 48594 48595 window.addEventListener("hashchange", function(e){ 48596 48597 self.hashChanged( getFragment(e.newURL) ); 48598 48599 }, false); 48600 48601 return this; 48602 48603}; 48604 48605HashChange.prototype = { 48606 48607 update : function( callback ){ 48608 48609 if(callback){ 48610 48611 this.onChangeCallbacks.push( callback ); 48612 return this; 48613 48614 } else { 48615 48616 this.hashChanged( getFragment() ); 48617 48618 } 48619 48620 }, 48621 48622 unbind : function( callback ){ 48623 48624 var i = indexOf( this.onChangeCallbacks , callback); 48625 48626 if(i !== -1){ 48627 48628 this.onChangeCallbacks.splice(i - 1, 1); 48629 48630 } 48631 48632 return this; 48633 48634 }, 48635 48636 updateHash : function( hash ){ 48637 48638 this.currentHash = hash; 48639 48640 window.location.href = window.location.href.replace( /#.*/, '') + '#' + hash; 48641 48642 }, 48643 48644 hashChanged : function( frag ){ 48645 48646 if(this.onChangeCallbacks.length){ 48647 48648 each(this.onChangeCallbacks, function( callback ){ 48649 48650 callback( frag ); 48651 48652 return true; 48653 48654 }); 48655 48656 } 48657 48658 return this; 48659 48660 }, 48661 48662 48663} 48664 48665hashChange = new HashChange(); 48666 48667module.exports = hashChange; 48668 48669},{"each":361,"indexof":357}],363:[function(require,module,exports){ 48670/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ 48671 48672window.matchMedia || (window.matchMedia = function() { 48673 "use strict"; 48674 48675 // For browsers that support matchMedium api such as IE 9 and webkit 48676 var styleMedia = (window.styleMedia || window.media); 48677 48678 // For those that don't support matchMedium 48679 if (!styleMedia) { 48680 var style = document.createElement('style'), 48681 script = document.getElementsByTagName('script')[0], 48682 info = null; 48683 48684 style.type = 'text/css'; 48685 style.id = 'matchmediajs-test'; 48686 48687 script.parentNode.insertBefore(style, script); 48688 48689 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers 48690 info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; 48691 48692 styleMedia = { 48693 matchMedium: function(media) { 48694 var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; 48695 48696 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers 48697 if (style.styleSheet) { 48698 style.styleSheet.cssText = text; 48699 } else { 48700 style.textContent = text; 48701 } 48702 48703 // Test if media query is true or false 48704 return info.width === '1px'; 48705 } 48706 }; 48707 } 48708 48709 return function(media) { 48710 return { 48711 matches: styleMedia.matchMedium(media || 'all'), 48712 media: media || 'all' 48713 }; 48714 }; 48715}()); 48716 48717},{}],364:[function(require,module,exports){ 48718// THIS FILE IS GENERATED - DO NOT EDIT! 48719/*!mobile-detect v1.4.5 2021-03-13*/ 48720/*global module:false, define:false*/ 48721/*jshint latedef:false*/ 48722/*!@license Copyright 2013, Heinrich Goebl, License: MIT, see https://github.com/hgoebl/mobile-detect.js*/ 48723(function (define, undefined) { 48724define(function () { 48725 'use strict'; 48726 48727 var impl = {}; 48728 48729 impl.mobileDetectRules = { 48730 "phones": { 48731 "iPhone": "\\biPhone\\b|\\biPod\\b", 48732 "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+|\\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\\b-[0-9]+", 48733 "Pixel": "; \\bPixel\\b", 48734 "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel", 48735 "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 5X|Nexus 6", 48736 "Dell": "Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", 48737 "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b|XT1068|XT1092|XT1052", 48738 "Samsung":
vendor: 4,913 bytes, line 48738
48738"\\bSamsung\\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-
vendor: 63,412 bytes, lines 48738-49728
48738I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F|SM-G610F|SM-G981B|SM-G892A|SM-A530F", 48739 "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)|LM-G710", 48740 "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533|SOV34|601SO|F8332", 48741 "Asus": "Asus.*Galaxy|PadFone.*Mobile", 48742 "Xiaomi": "^(?!.*\\bx11\\b).*xiaomi.*$|POCOPHONE F1|MI 8|Redmi Note 9S|Redmi Note 5A Prime|N2G47H|M2001J2G|M2001J2I|M1805E10A|M2004J11G|M1902F1G|M2002J9G|M2004J19G|M2003J6A1G", 48743 "NokiaLumia": "Lumia [0-9]{3,4}", 48744 "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", 48745 "Palm": "PalmSource|Palm", 48746 "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", 48747 "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", 48748 "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", 48749 "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", 48750 "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", 48751 "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", 48752 "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", 48753 "Alcatel": "Alcatel", 48754 "Nintendo": "Nintendo (3DS|Switch)", 48755 "Amoi": "Amoi", 48756 "INQ": "INQ", 48757 "OnePlus": "ONEPLUS", 48758 "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" 48759 }, 48760 "tablets": { 48761 "iPad": "iPad|iPad.*Mobile", 48762 "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", 48763 "GoogleTablet": "Android.*Pixel C", 48764 "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615|SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860", 48765 "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\\b|Android.*Silk\/[0-9.]+ like Chrome\/[0-9.]+ (?!Mobile)", 48766 "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", 48767 "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", 48768 "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\\bP027\\b|\\bP024\\b|\\bP00C\\b", 48769 "BlackBerryTablet": "PlayBook|RIM Tablet", 48770 "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", 48771 "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", 48772 "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", 48773 "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20\\b|\\bA3-A30|A3-A40", 48774 "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", 48775 "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", 48776 "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", 48777 "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", 48778 "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F|YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F|TB-X704L", 48779 "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", 48780 "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", 48781 "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", 48782 "ArnovaTablet": "97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", 48783 "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", 48784 "IRUTablet": "M702pro", 48785 "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", 48786 "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", 48787 "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", 48788 "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", 48789 "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", 48790 "NokiaLumiaTablet": "Lumia 2520", 48791 "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712", 48792 "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", 48793 "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", 48794 "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", 48795 "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", 48796 "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", 48797 "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", 48798 "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", 48799 "FlyTablet": "IQ310|Fly Vision", 48800 "bqTablet": "Android.*(bq)?.*\\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\\b|Maxwell.*Lite|Maxwell.*Plus", 48801 "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19", 48802 "NecTablet": "\\bN-06D|\\bN-08D", 48803 "PantechTablet": "Pantech.*P4100", 48804 "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", 48805 "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", 48806 "ZyncTablet": "z1000|Z99 2G|z930|z990|z909|Z919|z900", 48807 "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", 48808 "NabiTablet": "Android.*\\bNabi", 48809 "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", 48810 "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", 48811 "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", 48812 "PlaystationTablet": "Playstation.*(Portable|Vita)", 48813 "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", 48814 "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", 48815 "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", 48816 "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", 48817 "GalapadTablet": "Android [0-9.]+; [a-z-]+; \\bG1\\b", 48818 "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", 48819 "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", 48820 "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", 48821 "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", 48822 "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", 48823 "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", 48824 "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", 48825 "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", 48826 "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027", 48827 "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", 48828 "DPSTablet": "DPS Dream 9|DPS Dual 7", 48829 "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", 48830 "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", 48831 "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", 48832 "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", 48833 "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", 48834 "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", 48835 "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", 48836 "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", 48837 "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", 48838 "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400", 48839 "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", 48840 "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", 48841 "iMobileTablet": "i-mobile i-note", 48842 "TolinoTablet": "tolino tab [0-9.]+|tolino shine", 48843 "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", 48844 "AMPETablet": "Android.* A78 ", 48845 "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", 48846 "TecnoTablet": "TECNO P9|TECNO DP8D", 48847 "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", 48848 "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", 48849 "FX2Tablet": "FX2 PAD7|FX2 PAD10", 48850 "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", 48851 "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", 48852 "VerizonTablet": "QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1", 48853 "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", 48854 "CaptivaTablet": "CAPTIVA PAD", 48855 "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", 48856 "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", 48857 "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+|V10 \\b4G\\b", 48858 "JaytechTablet": "TPC-PA762", 48859 "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", 48860 "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", 48861 "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", 48862 "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", 48863 "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", 48864 "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", 48865 "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", 48866 "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", 48867 "MediacomTablet": "M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA", 48868 "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", 48869 "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", 48870 "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", 48871 "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", 48872 "UbislateTablet": "UbiSlate[\\s]?7C", 48873 "PocketBookTablet": "Pocketbook", 48874 "KocasoTablet": "\\b(TB-1207)\\b", 48875 "HisenseTablet": "\\b(F5281|E2371)\\b", 48876 "Hudl": "Hudl HT7S3|Hudl 2", 48877 "TelstraTablet": "T-Hub2", 48878 "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bTP750\\b|\\bQTAQZ3\\b|WVT101|TM1088|KT107" 48879 }, 48880 "oss": { 48881 "AndroidOS": "Android", 48882 "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", 48883 "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", 48884 "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", 48885 "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;", 48886 "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", 48887 "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad|AppleCoreMedia", 48888 "iPadOS": "CPU OS 13", 48889 "SailfishOS": "Sailfish", 48890 "MeeGoOS": "MeeGo", 48891 "MaemoOS": "Maemo", 48892 "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", 48893 "webOS": "webOS|hpwOS", 48894 "badaOS": "\\bBada\\b", 48895 "BREWOS": "BREW" 48896 }, 48897 "uas": { 48898 "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", 48899 "Dolfin": "\\bDolfin\\b", 48900 "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+$|Coast\/[0-9.]+", 48901 "Skyfire": "Skyfire", 48902 "Edge": "\\bEdgiOS\\b|Mobile Safari\/[.0-9]* Edge", 48903 "IE": "IEMobile|MSIEMobile", 48904 "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS", 48905 "Bolt": "bolt", 48906 "TeaShark": "teashark", 48907 "Blazer": "Blazer", 48908 "Safari": "Version((?!\\bEdgiOS\\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari", 48909 "WeChat": "\\bMicroMessenger\\b", 48910 "UCBrowser": "UC.*Browser|UCWEB", 48911 "baiduboxapp": "baiduboxapp", 48912 "baidubrowser": "baidubrowser", 48913 "DiigoBrowser": "DiigoBrowser", 48914 "Mercury": "\\bMercury\\b", 48915 "ObigoBrowser": "Obigo", 48916 "NetFront": "NF-Browser", 48917 "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", 48918 "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" 48919 }, 48920 "props": { 48921 "Mobile": "Mobile\/[VER]", 48922 "Build": "Build\/[VER]", 48923 "Version": "Version\/[VER]", 48924 "VendorID": "VendorID\/[VER]", 48925 "iPad": "iPad.*CPU[a-z ]+[VER]", 48926 "iPhone": "iPhone.*CPU[a-z ]+[VER]", 48927 "iPod": "iPod.*CPU[a-z ]+[VER]", 48928 "Kindle": "Kindle\/[VER]", 48929 "Chrome": [ 48930 "Chrome\/[VER]", 48931 "CriOS\/[VER]", 48932 "CrMo\/[VER]" 48933 ], 48934 "Coast": [ 48935 "Coast\/[VER]" 48936 ], 48937 "Dolfin": "Dolfin\/[VER]", 48938 "Firefox": [ 48939 "Firefox\/[VER]", 48940 "FxiOS\/[VER]" 48941 ], 48942 "Fennec": "Fennec\/[VER]", 48943 "Edge": "Edge\/[VER]", 48944 "IE": [ 48945 "IEMobile\/[VER];", 48946 "IEMobile [VER]", 48947 "MSIE [VER];", 48948 "Trident\/[0-9.]+;.*rv:[VER]" 48949 ], 48950 "NetFront": "NetFront\/[VER]", 48951 "NokiaBrowser": "NokiaBrowser\/[VER]", 48952 "Opera": [ 48953 " OPR\/[VER]", 48954 "Opera Mini\/[VER]", 48955 "Version\/[VER]" 48956 ], 48957 "Opera Mini": "Opera Mini\/[VER]", 48958 "Opera Mobi": "Version\/[VER]", 48959 "UCBrowser": [ 48960 "UCWEB[VER]", 48961 "UC.*Browser\/[VER]" 48962 ], 48963 "MQQBrowser": "MQQBrowser\/[VER]", 48964 "MicroMessenger": "MicroMessenger\/[VER]", 48965 "baiduboxapp": "baiduboxapp\/[VER]", 48966 "baidubrowser": "baidubrowser\/[VER]", 48967 "SamsungBrowser": "SamsungBrowser\/[VER]", 48968 "Iron": "Iron\/[VER]", 48969 "Safari": [ 48970 "Version\/[VER]", 48971 "Safari\/[VER]" 48972 ], 48973 "Skyfire": "Skyfire\/[VER]", 48974 "Tizen": "Tizen\/[VER]", 48975 "Webkit": "webkit[ \/][VER]", 48976 "PaleMoon": "PaleMoon\/[VER]", 48977 "SailfishBrowser": "SailfishBrowser\/[VER]", 48978 "Gecko": "Gecko\/[VER]", 48979 "Trident": "Trident\/[VER]", 48980 "Presto": "Presto\/[VER]", 48981 "Goanna": "Goanna\/[VER]", 48982 "iOS": " \\bi?OS\\b [VER][ ;]{1}", 48983 "Android": "Android [VER]", 48984 "Sailfish": "Sailfish [VER]", 48985 "BlackBerry": [ 48986 "BlackBerry[\\w]+\/[VER]", 48987 "BlackBerry.*Version\/[VER]", 48988 "Version\/[VER]" 48989 ], 48990 "BREW": "BREW [VER]", 48991 "Java": "Java\/[VER]", 48992 "Windows Phone OS": [ 48993 "Windows Phone OS [VER]", 48994 "Windows Phone [VER]" 48995 ], 48996 "Windows Phone": "Windows Phone [VER]", 48997 "Windows CE": "Windows CE\/[VER]", 48998 "Windows NT": "Windows NT [VER]", 48999 "Symbian": [ 49000 "SymbianOS\/[VER]", 49001 "Symbian\/[VER]" 49002 ], 49003 "webOS": [ 49004 "webOS\/[VER]", 49005 "hpwOS\/[VER];" 49006 ] 49007 }, 49008 "utils": { 49009 "Bot": "Googlebot|facebookexternalhit|Google-AMPHTML|s~amp-validator|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom|contentkingapp|AspiegelBot", 49010 "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", 49011 "DesktopMode": "WPDesktop", 49012 "TV": "SonyDTV|HbbTV", 49013 "WebKit": "(webkit)[ \/]([\\w.]+)", 49014 "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\\b", 49015 "Watch": "SM-V700" 49016 } 49017}; 49018 49019 // following patterns come from http://detectmobilebrowsers.com/ 49020 impl.detectMobileBrowsers = { 49021 fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, 49022 shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, 49023 tabletPattern: /android|ipad|playbook|silk/i 49024 }; 49025 49026 var hasOwnProp = Object.prototype.hasOwnProperty, 49027 isArray; 49028 49029 impl.FALLBACK_PHONE = 'UnknownPhone'; 49030 impl.FALLBACK_TABLET = 'UnknownTablet'; 49031 impl.FALLBACK_MOBILE = 'UnknownMobile'; 49032 49033 isArray = ('isArray' in Array) ? 49034 Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; 49035 49036 function equalIC(a, b) { 49037 return a != null && b != null && a.toLowerCase() === b.toLowerCase(); 49038 } 49039 49040 function containsIC(array, value) { 49041 var valueLC, i, len = array.length; 49042 if (!len || !value) { 49043 return false; 49044 } 49045 valueLC = value.toLowerCase(); 49046 for (i = 0; i < len; ++i) { 49047 if (valueLC === array[i].toLowerCase()) { 49048 return true; 49049 } 49050 } 49051 return false; 49052 } 49053 49054 function convertPropsToRegExp(object) { 49055 for (var key in object) { 49056 if (hasOwnProp.call(object, key)) { 49057 object[key] = new RegExp(object[key], 'i'); 49058 } 49059 } 49060 } 49061 49062 function prepareUserAgent(userAgent) { 49063 return (userAgent || '').substr(0, 500); // mitigate vulnerable to ReDoS 49064 } 49065 49066 (function init() { 49067 var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; 49068 for (key in mobileDetectRules.props) { 49069 if (hasOwnProp.call(mobileDetectRules.props, key)) { 49070 values = mobileDetectRules.props[key]; 49071 if (!isArray(values)) { 49072 values = [values]; 49073 } 49074 len = values.length; 49075 for (i = 0; i < len; ++i) { 49076 value = values[i]; 49077 verPos = value.indexOf('[VER]'); 49078 if (verPos >= 0) { 49079 value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); 49080 } 49081 values[i] = new RegExp(value, 'i'); 49082 } 49083 mobileDetectRules.props[key] = values; 49084 } 49085 } 49086 convertPropsToRegExp(mobileDetectRules.oss); 49087 convertPropsToRegExp(mobileDetectRules.phones); 49088 convertPropsToRegExp(mobileDetectRules.tablets); 49089 convertPropsToRegExp(mobileDetectRules.uas); 49090 convertPropsToRegExp(mobileDetectRules.utils); 49091 49092 // copy some patterns to oss0 which are tested first (see issue#15) 49093 mobileDetectRules.oss0 = { 49094 WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, 49095 WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS 49096 }; 49097 }()); 49098 49099 /** 49100 * Test userAgent string against a set of rules and find the first matched key. 49101 * @param {Object} rules (key is String, value is RegExp) 49102 * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). 49103 * @returns {String|null} the matched key if found, otherwise <tt>null</tt> 49104 * @private 49105 */ 49106 impl.findMatch = function(rules, userAgent) { 49107 for (var key in rules) { 49108 if (hasOwnProp.call(rules, key)) { 49109 if (rules[key].test(userAgent)) { 49110 return key; 49111 } 49112 } 49113 } 49114 return null; 49115 }; 49116 49117 /** 49118 * Test userAgent string against a set of rules and return an array of matched keys. 49119 * @param {Object} rules (key is String, value is RegExp) 49120 * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). 49121 * @returns {Array} an array of matched keys, may be empty when there is no match, but not <tt>null</tt> 49122 * @private 49123 */ 49124 impl.findMatches = function(rules, userAgent) { 49125 var result = []; 49126 for (var key in rules) { 49127 if (hasOwnProp.call(rules, key)) { 49128 if (rules[key].test(userAgent)) { 49129 result.push(key); 49130 } 49131 } 49132 } 49133 return result; 49134 }; 49135 49136 /** 49137 * Check the version of the given property in the User-Agent. 49138 * 49139 * @param {String} propertyName 49140 * @param {String} userAgent 49141 * @return {String} version or <tt>null</tt> if version not found 49142 * @private 49143 */ 49144 impl.getVersionStr = function (propertyName, userAgent) { 49145 var props = impl.mobileDetectRules.props, patterns, i, len, match; 49146 if (hasOwnProp.call(props, propertyName)) { 49147 patterns = props[propertyName]; 49148 len = patterns.length; 49149 for (i = 0; i < len; ++i) { 49150 match = patterns[i].exec(userAgent); 49151 if (match !== null) { 49152 return match[1]; 49153 } 49154 } 49155 } 49156 return null; 49157 }; 49158 49159 /** 49160 * Check the version of the given property in the User-Agent. 49161 * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) 49162 * 49163 * @param {String} propertyName 49164 * @param {String} userAgent 49165 * @return {Number} version or <tt>NaN</tt> if version not found 49166 * @private 49167 */ 49168 impl.getVersion = function (propertyName, userAgent) { 49169 var version = impl.getVersionStr(propertyName, userAgent); 49170 return version ? impl.prepareVersionNo(version) : NaN; 49171 }; 49172 49173 /** 49174 * Prepare the version number. 49175 * 49176 * @param {String} version 49177 * @return {Number} the version number as a floating number 49178 * @private 49179 */ 49180 impl.prepareVersionNo = function (version) { 49181 var numbers; 49182 49183 numbers = version.split(/[a-z._ \/\-]/i); 49184 if (numbers.length === 1) { 49185 version = numbers[0]; 49186 } 49187 if (numbers.length > 1) { 49188 version = numbers[0] + '.'; 49189 numbers.shift(); 49190 version += numbers.join(''); 49191 } 49192 return Number(version); 49193 }; 49194 49195 impl.isMobileFallback = function (userAgent) { 49196 return impl.detectMobileBrowsers.fullPattern.test(userAgent) || 49197 impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); 49198 }; 49199 49200 impl.isTabletFallback = function (userAgent) { 49201 return impl.detectMobileBrowsers.tabletPattern.test(userAgent); 49202 }; 49203 49204 impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { 49205 if (cache.mobile !== undefined) { 49206 return; 49207 } 49208 var phone, tablet, phoneSized; 49209 49210 // first check for stronger tablet rules, then phone (see issue#5) 49211 tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); 49212 if (tablet) { 49213 cache.mobile = cache.tablet = tablet; 49214 cache.phone = null; 49215 return; // unambiguously identified as tablet 49216 } 49217 49218 phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); 49219 if (phone) { 49220 cache.mobile = cache.phone = phone; 49221 cache.tablet = null; 49222 return; // unambiguously identified as phone 49223 } 49224 49225 // our rules haven't found a match -> try more general fallback rules 49226 if (impl.isMobileFallback(userAgent)) { 49227 phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); 49228 if (phoneSized === undefined) { 49229 cache.mobile = impl.FALLBACK_MOBILE; 49230 cache.tablet = cache.phone = null; 49231 } else if (phoneSized) { 49232 cache.mobile = cache.phone = impl.FALLBACK_PHONE; 49233 cache.tablet = null; 49234 } else { 49235 cache.mobile = cache.tablet = impl.FALLBACK_TABLET; 49236 cache.phone = null; 49237 } 49238 } else if (impl.isTabletFallback(userAgent)) { 49239 cache.mobile = cache.tablet = impl.FALLBACK_TABLET; 49240 cache.phone = null; 49241 } else { 49242 // not mobile at all! 49243 cache.mobile = cache.tablet = cache.phone = null; 49244 } 49245 }; 49246 49247 // t is a reference to a MobileDetect instance 49248 impl.mobileGrade = function (t) { 49249 // impl note: 49250 // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. 49251 // When changes are made in Mobile_Detect.php, copy this method and replace: 49252 // $this-> / t. 49253 // self::MOBILE_GRADE_(.) / '$1' 49254 // , self::VERSION_TYPE_FLOAT / (nothing) 49255 // isIOS() / os('iOS') 49256 // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE 49257 var $isMobile = t.mobile() !== null; 49258 49259 if ( 49260 // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) 49261 t.os('iOS') && t.version('iPad')>=4.3 || 49262 t.os('iOS') && t.version('iPhone')>=3.1 || 49263 t.os('iOS') && t.version('iPod')>=3.1 || 49264 49265 // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) 49266 // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM 49267 // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices 49268 // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 49269 ( t.version('Android')>2.1 && t.is('Webkit') ) || 49270 49271 // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 49272 t.version('Windows Phone OS')>=7.0 || 49273 49274 // Blackberry 7 - Tested on BlackBerry Torch 9810 49275 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 49276 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || 49277 // Blackberry Playbook (1.0-2.0) - Tested on PlayBook 49278 t.match('Playbook.*Tablet') || 49279 49280 // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) 49281 ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || 49282 // Palm WebOS 3.0 - Tested on HP TouchPad 49283 t.match('hp.*TouchPad') || 49284 49285 // Firefox Mobile (12 Beta) - Tested on Android 2.3 device 49286 ( t.is('Firefox') && t.version('Firefox')>=12 ) || 49287 49288 // Chrome for Android - Tested on Android 4.0, 4.1 device 49289 ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || 49290 49291 // Skyfire 4.1 - Tested on Android 2.3 device 49292 ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || 49293 49294 // Opera Mobile 11.5-12: Tested on Android 2.3 49295 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || 49296 49297 // Meego 1.2 - Tested on Nokia 950 and N9 49298 t.is('MeeGoOS') || 49299 49300 // Tizen (pre-release) - Tested on early hardware 49301 t.is('Tizen') || 49302 49303 // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser 49304 // @todo: more tests here! 49305 t.is('Dolfin') && t.version('Bada')>=2.0 || 49306 49307 // UC Browser - Tested on Android 2.3 device 49308 ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || 49309 49310 // Kindle 3 and Fire - Tested on the built-in WebKit browser for each 49311 ( t.match('Kindle Fire') || 49312 t.is('Kindle') && t.version('Kindle')>=3.0 ) || 49313 49314 // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet 49315 t.is('AndroidOS') && t.is('NookTablet') || 49316 49317 // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 49318 t.version('Chrome')>=11 && !$isMobile || 49319 49320 // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 49321 t.version('Safari')>=5.0 && !$isMobile || 49322 49323 // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 49324 t.version('Firefox')>=4.0 && !$isMobile || 49325 49326 // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 49327 t.version('MSIE')>=7.0 && !$isMobile || 49328 49329 // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 49330 // @reference: http://my.opera.com/community/openweb/idopera/ 49331 t.version('Opera')>=10 && !$isMobile 49332 49333 ){ 49334 return 'A'; 49335 } 49336 49337 if ( 49338 t.os('iOS') && t.version('iPad')<4.3 || 49339 t.os('iOS') && t.version('iPhone')<3.1 || 49340 t.os('iOS') && t.version('iPod')<3.1 || 49341 49342 // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 49343 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || 49344 49345 //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 49346 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && 49347 (t.version('Android')>=2.3 || t.is('iOS')) ) || 49348 49349 // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) 49350 t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || 49351 49352 // @todo: report this (tested on Nokia N71) 49353 t.version('Opera Mobi')>=11 && t.is('SymbianOS') 49354 ){ 49355 return 'B'; 49356 } 49357 49358 if ( 49359 // Blackberry 4.x - Tested on the Curve 8330 49360 t.version('BlackBerry')<5.0 || 49361 // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) 49362 t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 49363 49364 ){ 49365 return 'C'; 49366 } 49367 49368 //All older smartphone platforms and featurephones - Any device that doesn't support media queries 49369 //will receive the basic, C grade experience. 49370 return 'C'; 49371 }; 49372 49373 impl.detectOS = function (ua) { 49374 return impl.findMatch(impl.mobileDetectRules.oss0, ua) || 49375 impl.findMatch(impl.mobileDetectRules.oss, ua); 49376 }; 49377 49378 impl.getDeviceSmallerSide = function () { 49379 return window.screen.width < window.screen.height ? 49380 window.screen.width : 49381 window.screen.height; 49382 }; 49383 49384 /** 49385 * Constructor for MobileDetect object. 49386 * <br> 49387 * Such an object will keep a reference to the given user-agent string and cache most of the detect queries.<br> 49388 * <div style="background-color: #d9edf7; border: 1px solid #bce8f1; color: #3a87ad; padding: 14px; border-radius: 2px; margin-top: 20px"> 49389 * <strong>Find information how to download and install:</strong> 49390 * <a href="https://github.com/hgoebl/mobile-detect.js/">github.com/hgoebl/mobile-detect.js/</a> 49391 * </div> 49392 * 49393 * @example <pre> 49394 * var md = new MobileDetect(window.navigator.userAgent); 49395 * if (md.mobile()) { 49396 * location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/'; 49397 * } 49398 * </pre> 49399 * 49400 * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] 49401 * @param {number} [maxPhoneWidth=600] <strong>only for browsers</strong> specify a value for the maximum 49402 * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled 49403 * as phone. 49404 * This is only used in cases where the device cannot be classified as phone or tablet.<br> 49405 * See <a href="http://developer.android.com/guide/practices/screens_support.html">Declaring Tablet Layouts 49406 * for Android</a>.<br> 49407 * If you provide a value < 0, then this "fuzzy" check is disabled. 49408 * @constructor 49409 * @global 49410 */ 49411 function MobileDetect(userAgent, maxPhoneWidth) { 49412 this.ua = prepareUserAgent(userAgent); 49413 this._cache = {}; 49414 //600dp is typical 7" tablet minimum width 49415 this.maxPhoneWidth = maxPhoneWidth || 600; 49416 } 49417 49418 MobileDetect.prototype = { 49419 constructor: MobileDetect, 49420 49421 /** 49422 * Returns the detected phone or tablet type or <tt>null</tt> if it is not a mobile device. 49423 * <br> 49424 * For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.<br> 49425 * <br> 49426 * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against 49427 * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test 49428 * is positive, a value of <code>UnknownPhone</code>, <code>UnknownTablet</code> or 49429 * <code>UnknownMobile</code> is returned.<br> 49430 * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br> 49431 * <br> 49432 * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code> 49433 * and <code>UnknownMobile</code>, so you will get <code>UnknownMobile</code> here.<br> 49434 * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for: 49435 * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. 49436 * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use. 49437 * <br> 49438 * In most cases you will use the return value just as a boolean. 49439 * 49440 * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". 49441 * @function MobileDetect#mobile 49442 */ 49443 mobile: function () { 49444 impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); 49445 return this._cache.mobile; 49446 }, 49447 49448 /** 49449 * Returns the detected phone type/family string or <tt>null</tt>. 49450 * <br> 49451 * The returned tablet (family or producer) is one of following keys:<br> 49452 * <br><tt>iPhone, BlackBerry, Pixel, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, 49453 * Xiaomi, NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, 49454 * SimValley, Wolfgang, Alcatel, Nintendo, Amoi, INQ, OnePlus, GenericPhone</tt><br> 49455 * <br> 49456 * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against 49457 * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test 49458 * is positive, a value of <code>UnknownPhone</code> or <code>UnknownMobile</code> is returned.<br> 49459 * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br> 49460 * <br> 49461 * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code> 49462 * and <code>UnknownMobile</code>, so you will get <code>null</code> here, while {@link MobileDetect#mobile} 49463 * will return <code>UnknownMobile</code>.<br> 49464 * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for: 49465 * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. 49466 * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use. 49467 * <br> 49468 * In most cases you will use the return value just as a boolean. 49469 * 49470 * @returns {String} the key of the phone family or producer, e.g. "iPhone" 49471 * @function MobileDetect#phone 49472 */ 49473 phone: function () { 49474 impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); 49475 return this._cache.phone; 49476 }, 49477 49478 /** 49479 * Returns the detected tablet type/family string or <tt>null</tt>. 49480 * <br> 49481 * The returned tablet (family or producer) is one of following keys:<br> 49482 * <br><tt>iPad, NexusTablet, GoogleTablet, SamsungTablet, Kindle, SurfaceTablet, 49483 * HPTablet, AsusTablet, BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, 49484 * AcerTablet, ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, 49485 * LenovoTablet, DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, 49486 * IntensoTablet, IRUTablet, MegafonTablet, EbodaTablet, AllViewTablet, 49487 * ArchosTablet, AinolTablet, NokiaLumiaTablet, SonyTablet, PhilipsTablet, 49488 * CubeTablet, CobyTablet, MIDTablet, MSITablet, SMiTTablet, RockChipTablet, 49489 * FlyTablet, bqTablet, HuaweiTablet, NecTablet, PantechTablet, BronchoTablet, 49490 * VersusTablet, ZyncTablet, PositivoTablet, NabiTablet, KoboTablet, DanewTablet, 49491 * TexetTablet, PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, 49492 * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, 49493 * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, 49494 * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, 49495 * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, 49496 * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, 49497 * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, 49498 * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, 49499 * VerizonTablet, OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, 49500 * OndaTablet, JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, 49501 * LavaTablet, AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MediacomTablet, 49502 * MiTablet, NibiruTablet, NexoTablet, LeaderTablet, UbislateTablet, 49503 * PocketBookTablet, KocasoTablet, HisenseTablet, Hudl, TelstraTablet, 49504 * GenericTablet</tt><br> 49505 * <br> 49506 * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against 49507 * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test 49508 * is positive, a value of <code>UnknownTablet</code> or <code>UnknownMobile</code> is returned.<br> 49509 * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br> 49510 * <br> 49511 * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code> 49512 * and <code>UnknownMobile</code>, so you will get <code>null</code> here, while {@link MobileDetect#mobile} 49513 * will return <code>UnknownMobile</code>.<br> 49514 * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for: 49515 * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. 49516 * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use. 49517 * <br> 49518 * In most cases you will use the return value just as a boolean. 49519 * 49520 * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" 49521 * @function MobileDetect#tablet 49522 */ 49523 tablet: function () { 49524 impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); 49525 return this._cache.tablet; 49526 }, 49527 49528 /** 49529 * Returns the (first) detected user-agent string or <tt>null</tt>. 49530 * <br> 49531 * The returned user-agent is one of following keys:<br> 49532 * <br><tt>Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, Blazer, 49533 * Safari, WeChat, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, Mercury, 49534 * ObigoBrowser, NetFront, GenericBrowser, PaleMoon</tt><br> 49535 * <br> 49536 * In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare 49537 * cases where a mobile device pretends to be more than one particular browser. You can get the 49538 * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by 49539 * providing one of the defined keys as first argument to {@link MobileDetect#is}. 49540 * 49541 * @returns {String} the key for the detected user-agent or <tt>null</tt> 49542 * @function MobileDetect#userAgent 49543 */ 49544 userAgent: function () { 49545 if (this._cache.userAgent === undefined) { 49546 this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); 49547 } 49548 return this._cache.userAgent; 49549 }, 49550 49551 /** 49552 * Returns all detected user-agent strings. 49553 * <br> 49554 * The array is empty or contains one or more of following keys:<br> 49555 * <br><tt>Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, Blazer, 49556 * Safari, WeChat, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, Mercury, 49557 * ObigoBrowser, NetFront, GenericBrowser, PaleMoon</tt><br> 49558 * <br> 49559 * In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare 49560 * cases where a mobile device pretends to be more than one particular browser. You can get the 49561 * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by 49562 * providing one of the defined keys as first argument to {@link MobileDetect#is}. 49563 * 49564 * @returns {Array} the array of detected user-agent keys or <tt>[]</tt> 49565 * @function MobileDetect#userAgents 49566 */ 49567 userAgents: function () { 49568 if (this._cache.userAgents === undefined) { 49569 this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); 49570 } 49571 return this._cache.userAgents; 49572 }, 49573 49574 /** 49575 * Returns the detected operating system string or <tt>null</tt>. 49576 * <br> 49577 * The operating system is one of following keys:<br> 49578 * <br><tt>AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, 49579 * iOS, iPadOS, SailfishOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS</tt><br> 49580 * 49581 * @returns {String} the key for the detected operating system. 49582 * @function MobileDetect#os 49583 */ 49584 os: function () { 49585 if (this._cache.os === undefined) { 49586 this._cache.os = impl.detectOS(this.ua); 49587 } 49588 return this._cache.os; 49589 }, 49590 49591 /** 49592 * Get the version (as Number) of the given property in the User-Agent. 49593 * <br> 49594 * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) 49595 * 49596 * @param {String} key a key defining a thing which has a version.<br> 49597 * You can use one of following keys:<br> 49598 * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, 49599 * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, 49600 * Opera Mobi, UCBrowser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, 49601 * SamsungBrowser, Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, 49602 * SailfishBrowser, Gecko, Trident, Presto, Goanna, iOS, Android, Sailfish, 49603 * BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows CE, Windows 49604 * NT, Symbian, webOS</tt><br> 49605 * 49606 * @returns {Number} the version as float or <tt>NaN</tt> if User-Agent doesn't contain this version. 49607 * Be careful when comparing this value with '==' operator! 49608 * @function MobileDetect#version 49609 */ 49610 version: function (key) { 49611 return impl.getVersion(key, this.ua); 49612 }, 49613 49614 /** 49615 * Get the version (as String) of the given property in the User-Agent. 49616 * <br> 49617 * 49618 * @param {String} key a key defining a thing which has a version.<br> 49619 * You can use one of following keys:<br> 49620 * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, 49621 * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, 49622 * Opera Mobi, UCBrowser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, 49623 * SamsungBrowser, Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, 49624 * SailfishBrowser, Gecko, Trident, Presto, Goanna, iOS, Android, Sailfish, 49625 * BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows CE, Windows 49626 * NT, Symbian, webOS</tt><br> 49627 * 49628 * @returns {String} the "raw" version as String or <tt>null</tt> if User-Agent doesn't contain this version. 49629 * 49630 * @function MobileDetect#versionStr 49631 */ 49632 versionStr: function (key) { 49633 return impl.getVersionStr(key, this.ua); 49634 }, 49635 49636 /** 49637 * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. 49638 * 49639 * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or 49640 * tablet family.<br> 49641 * For a complete list of possible values, see {@link MobileDetect#userAgent}, 49642 * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.<br> 49643 * Additionally you have following keys:<br> 49644 * <br><tt>Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch</tt><br> 49645 * 49646 * @returns {boolean} <tt>true</tt> when the given key is one of the defined keys of userAgent, os, phone, 49647 * tablet or one of the listed additional keys, otherwise <tt>false</tt> 49648 * @function MobileDetect#is 49649 */ 49650 is: function (key) { 49651 return containsIC(this.userAgents(), key) || 49652 equalIC(key, this.os()) || 49653 equalIC(key, this.phone()) || 49654 equalIC(key, this.tablet()) || 49655 containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); 49656 }, 49657 49658 /** 49659 * Do a quick test against navigator::userAgent. 49660 * 49661 * @param {String|RegExp} pattern the pattern, either as String or RegExp 49662 * (a string will be converted to a case-insensitive RegExp). 49663 * @returns {boolean} <tt>true</tt> when the pattern matches, otherwise <tt>false</tt> 49664 * @function MobileDetect#match 49665 */ 49666 match: function (pattern) { 49667 if (!(pattern instanceof RegExp)) { 49668 pattern = new RegExp(pattern, 'i'); 49669 } 49670 return pattern.test(this.ua); 49671 }, 49672 49673 /** 49674 * Checks whether the mobile device can be considered as phone regarding <code>screen.width</code>. 49675 * <br> 49676 * Obviously this method makes sense in browser environments only (not for Node.js)! 49677 * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.<br> 49678 * The argument is optional and if not present or falsy, the value of the constructor is taken. 49679 * @returns {boolean|undefined} <code>undefined</code> if screen size wasn't detectable, else <code>true</code> 49680 * when screen.width is less or equal to maxPhoneWidth, otherwise <code>false</code>.<br> 49681 * Will always return <code>undefined</code> server-side. 49682 */ 49683 isPhoneSized: function (maxPhoneWidth) { 49684 return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); 49685 }, 49686 49687 /** 49688 * Returns the mobile grade ('A', 'B', 'C'). 49689 * 49690 * @returns {String} one of the mobile grades ('A', 'B', 'C'). 49691 * @function MobileDetect#mobileGrade 49692 */ 49693 mobileGrade: function () { 49694 if (this._cache.grade === undefined) { 49695 this._cache.grade = impl.mobileGrade(this); 49696 } 49697 return this._cache.grade; 49698 } 49699 }; 49700 49701 // environment-dependent 49702 if (typeof window !== 'undefined' && window.screen) { 49703 MobileDetect.isPhoneSized = function (maxPhoneWidth) { 49704 return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; 49705 }; 49706 } else { 49707 MobileDetect.isPhoneSized = function () {}; 49708 } 49709 49710 // should not be replaced by a completely new object - just overwrite existing methods 49711 MobileDetect._impl = impl; 49712 49713 MobileDetect.version = '1.4.5 2021-03-13'; 49714 49715 return MobileDetect; 49716}); // end of call of define() 49717})((function (undefined) { 49718 if (typeof module !== 'undefined' && module.exports) { 49719 return function (factory) { module.exports = factory(); }; 49720 } else if (typeof define === 'function' && define.amd) { 49721 return define; 49722 } else if (typeof window !== 'undefined') { 49723 return function (factory) { window.MobileDetect = factory(); }; 49724 } else { 49725 // please file a bug if you get this error! 49726 throw new Error('unknown environment'); 49727 } 49728})());
49728 49729},{}],365
vendor: 5,461 bytes, lines 49729-49915
49729:[function(require,module,exports){ 49730// shim for using process in browser 49731var process = module.exports = {}; 49732 49733// cached from whatever global is present so that test runners that stub it 49734// don't break things. But we need to wrap it in a try catch in case it is 49735// wrapped in strict mode code which doesn't define any globals. It's inside a 49736// function because try/catches deoptimize in certain engines. 49737 49738var cachedSetTimeout; 49739var cachedClearTimeout; 49740 49741function defaultSetTimout() { 49742 throw new Error('setTimeout has not been defined'); 49743} 49744function defaultClearTimeout () { 49745 throw new Error('clearTimeout has not been defined'); 49746} 49747(function () { 49748 try { 49749 if (typeof setTimeout === 'function') { 49750 cachedSetTimeout = setTimeout; 49751 } else { 49752 cachedSetTimeout = defaultSetTimout; 49753 } 49754 } catch (e) { 49755 cachedSetTimeout = defaultSetTimout; 49756 } 49757 try { 49758 if (typeof clearTimeout === 'function') { 49759 cachedClearTimeout = clearTimeout; 49760 } else { 49761 cachedClearTimeout = defaultClearTimeout; 49762 } 49763 } catch (e) { 49764 cachedClearTimeout = defaultClearTimeout; 49765 } 49766} ()) 49767function runTimeout(fun) { 49768 if (cachedSetTimeout === setTimeout) { 49769 //normal enviroments in sane situations 49770 return setTimeout(fun, 0); 49771 } 49772 // if setTimeout wasn't available but was latter defined 49773 if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { 49774 cachedSetTimeout = setTimeout; 49775 return setTimeout(fun, 0); 49776 } 49777 try { 49778 // when when somebody has screwed with setTimeout but no I.E. maddness 49779 return cachedSetTimeout(fun, 0); 49780 } catch(e){ 49781 try { 49782 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 49783 return cachedSetTimeout.call(null, fun, 0); 49784 } catch(e){ 49785 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error 49786 return cachedSetTimeout.call(this, fun, 0); 49787 } 49788 } 49789 49790 49791} 49792function runClearTimeout(marker) { 49793 if (cachedClearTimeout === clearTimeout) { 49794 //normal enviroments in sane situations 49795 return clearTimeout(marker); 49796 } 49797 // if clearTimeout wasn't available but was latter defined 49798 if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { 49799 cachedClearTimeout = clearTimeout; 49800 return clearTimeout(marker); 49801 } 49802 try { 49803 // when when somebody has screwed with setTimeout but no I.E. maddness 49804 return cachedClearTimeout(marker); 49805 } catch (e){ 49806 try { 49807 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 49808 return cachedClearTimeout.call(null, marker); 49809 } catch (e){ 49810 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. 49811 // Some versions of I.E. have different rules for clearTimeout vs setTimeout 49812 return cachedClearTimeout.call(this, marker); 49813 } 49814 } 49815 49816 49817 49818} 49819var queue = []; 49820var draining = false; 49821var currentQueue; 49822var queueIndex = -1; 49823 49824function cleanUpNextTick() { 49825 if (!draining || !currentQueue) { 49826 return; 49827 } 49828 draining = false; 49829 if (currentQueue.length) { 49830 queue = currentQueue.concat(queue); 49831 } else { 49832 queueIndex = -1; 49833 } 49834 if (queue.length) { 49835 drainQueue(); 49836 } 49837} 49838 49839function drainQueue() { 49840 if (draining) { 49841 return; 49842 } 49843 var timeout = runTimeout(cleanUpNextTick); 49844 draining = true; 49845 49846 var len = queue.length; 49847 while(len) { 49848 currentQueue = queue; 49849 queue = []; 49850 while (++queueIndex < len) { 49851 if (currentQueue) { 49852 currentQueue[queueIndex].run(); 49853 } 49854 } 49855 queueIndex = -1; 49856 len = queue.length; 49857 } 49858 currentQueue = null; 49859 draining = false; 49860 runClearTimeout(timeout); 49861} 49862 49863process.nextTick = function (fun) { 49864 var args = new Array(arguments.length - 1); 49865 if (arguments.length > 1) { 49866 for (var i = 1; i < arguments.length; i++) { 49867 args[i - 1] = arguments[i]; 49868 } 49869 } 49870 queue.push(new Item(fun, args)); 49871 if (queue.length === 1 && !draining) { 49872 runTimeout(drainQueue); 49873 } 49874}; 49875 49876// v8 likes predictible objects 49877function Item(fun, array) { 49878 this.fun = fun; 49879 this.array = array; 49880} 49881Item.prototype.run = function () { 49882 this.fun.apply(null, this.array); 49883}; 49884process.title = 'browser'; 49885process.browser = true; 49886process.env = {}; 49887process.argv = []; 49888process.version = ''; // empty string to avoid regexp issues 49889process.versions = {}; 49890 49891function noop() {} 49892 49893process.on = noop; 49894process.addListener = noop; 49895process.once = noop; 49896process.off = noop; 49897process.removeListener = noop; 49898process.removeAllListeners = noop; 49899process.emit = noop; 49900process.prependListener = noop; 49901process.prependOnceListener = noop; 49902 49903process.listeners = function (name) { return [] } 49904 49905process.binding = function (name) { 49906 throw new Error('process.binding is not supported'); 49907}; 49908 49909process.cwd = function () { return '/' }; 49910process.chdir = function (dir) { 49911 throw new Error('process.chdir is not supported'); 49912}; 49913process.umask = function() { return 0; }; 49914 49915},{}],
49915366:[function(require,module,exports){ 49916(function() { 49917 module.exports = function(r, g, b) { 49918 var d, h, l, max, min, s; 49919 r /= 255; 49920 g /= 255; 49921 b /= 255; 49922 max = Math.max(r, g, b); 49923 min = Math.min(r, g, b); 49924 h = 0; 49925 s = 0; 49926 l = (max + min) / 2; 49927 if (max === min) { 49928 h = s = 0; 49929 } else { 49930 d = max - min; 49931 s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 49932 switch (max) { 49933 case r: 49934 h = (g - b) / d + (g < b ? 6 : 0); 49935 break; 49936 case g: 49937 h = (b - r) / d + 2; 49938 break; 49939 case b: 49940 h = (r - g) / d + 4; 49941 } 49942 h /= 6; 49943 } 49944 h = h * 360; 49945 s = (s * 100) + "%"; 49946 l = (l * 100) + "%"; 49947 return [h, s, l]; 49948 }; 49949 49950}).call(this); 49951 49952},{}],367:[function(require,module,exports){ 49953!function(root, factory) { 49954 "function" == typeof define && define.amd ? // AMD. Register as an anonymous module unless amdModuleId is set 49955 define([], function() { 49956 return root.svg4everybody = factory(); 49957 }) : "object" == typeof module && module.exports ? // Node. Does not work with strict CommonJS, but 49958 // only CommonJS-like environments that support module.exports, 49959 // like Node. 49960 module.exports = factory() : root.svg4everybody = factory(); 49961}(this, function() { 49962 /*! svg4everybody v2.1.9 | github.com/jonathantneal/svg4everybody */ 49963 function embed(parent, svg, target) { 49964 // if the target exists 49965 if (target) { 49966 // create a document fragment to hold the contents of the target 49967 var fragment = document.createDocumentFragment(), viewBox = !svg.hasAttribute("viewBox") && target.getAttribute("viewBox"); 49968 // conditionally set the viewBox on the svg
vendor: 5,596 bytes, lines 49969-50077
49969 viewBox && svg.setAttribute("viewBox", viewBox); 49970 // copy the contents of the clone into the fragment 49971 for (// clone the target 49972 var clone = target.cloneNode(!0); clone.childNodes.length; ) { 49973 fragment.appendChild(clone.firstChild); 49974 } 49975 // append the fragment into the svg 49976 parent.appendChild(fragment); 49977 } 49978 } 49979 function loadreadystatechange(xhr) { 49980 // listen to changes in the request 49981 xhr.onreadystatechange = function() { 49982 // if the request is ready 49983 if (4 === xhr.readyState) { 49984 // get the cached html document 49985 var cachedDocument = xhr._cachedDocument; 49986 // ensure the cached html document based on the xhr response 49987 cachedDocument || (cachedDocument = xhr._cachedDocument = document.implementation.createHTMLDocument(""), 49988 cachedDocument.body.innerHTML = xhr.responseText, xhr._cachedTarget = {}), // clear the xhr embeds list and embed each item 49989 xhr._embeds.splice(0).map(function(item) { 49990 // get the cached target 49991 var target = xhr._cachedTarget[item.id]; 49992 // ensure the cached target 49993 target || (target = xhr._cachedTarget[item.id] = cachedDocument.getElementById(item.id)), 49994 // embed the target into the svg 49995 embed(item.parent, item.svg, target); 49996 }); 49997 } 49998 }, // test the ready state change immediately 49999 xhr.onreadystatechange(); 50000 } 50001 function svg4everybody(rawopts) { 50002 function oninterval() { 50003 // while the index exists in the live <use> collection 50004 for (// get the cached <use> index 50005 var index = 0; index < uses.length; ) { 50006 // get the current <use> 50007 var use = uses[index], parent = use.parentNode, svg = getSVGAncestor(parent), src = use.getAttribute("xlink:href") || use.getAttribute("href"); 50008 if (!src && opts.attributeName && (src = use.getAttribute(opts.attributeName)), 50009 svg && src) { 50010 if (polyfill) { 50011 if (!opts.validate || opts.validate(src, svg, use)) { 50012 // remove the <use> element 50013 parent.removeChild(use); 50014 // parse the src and get the url and id 50015 var srcSplit = src.split("#"), url = srcSplit.shift(), id = srcSplit.join("#"); 50016 // if the link is external 50017 if (url.length) { 50018 // get the cached xhr request 50019 var xhr = requests[url]; 50020 // ensure the xhr request exists 50021 xhr || (xhr = requests[url] = new XMLHttpRequest(), xhr.open("GET", url), xhr.send(), 50022 xhr._embeds = []), // add the svg and id as an item to the xhr embeds list 50023 xhr._embeds.push({ 50024 parent: parent, 50025 svg: svg, 50026 id: id 50027 }), // prepare the xhr ready state change event 50028 loadreadystatechange(xhr); 50029 } else { 50030 // embed the local id into the svg 50031 embed(parent, svg, document.getElementById(id)); 50032 } 50033 } else { 50034 // increase the index when the previous value was not "valid" 50035 ++index, ++numberOfSvgUseElementsToBypass; 50036 } 50037 } 50038 } else { 50039 // increase the index when the previous value was not "valid" 50040 ++index; 50041 } 50042 } 50043 // continue the interval 50044 (!uses.length || uses.length - numberOfSvgUseElementsToBypass > 0) && requestAnimationFrame(oninterval, 67); 50045 } 50046 var polyfill, opts = Object(rawopts), newerIEUA = /\bTrident\/[567]\b|\bMSIE (?:9|10)\.0\b/, webkitUA = /\bAppleWebKit\/(\d+)\b/, olderEdgeUA = /\bEdge\/12\.(\d+)\b/, edgeUA = /\bEdge\/.(\d+)\b/, inIframe = window.top !== window.self; 50047 polyfill = "polyfill" in opts ? opts.polyfill : newerIEUA.test(navigator.userAgent) || (navigator.userAgent.match(olderEdgeUA) || [])[1] < 10547 || (navigator.userAgent.match(webkitUA) || [])[1] < 537 || edgeUA.test(navigator.userAgent) && inIframe; 50048 // create xhr requests object 50049 var requests = {}, requestAnimationFrame = window.requestAnimationFrame || setTimeout, uses = document.getElementsByTagName("use"), numberOfSvgUseElementsToBypass = 0; 50050 // conditionally start the interval if the polyfill is active 50051 polyfill && oninterval(); 50052 } 50053 function getSVGAncestor(node) { 50054 for (var svg = node; "svg" !== svg.nodeName.toLowerCase() && (svg = svg.parentNode); ) {} 50055 return svg; 50056 } 50057 return svg4everybody; 50058}); 50059},{}],368:[function(require,module,exports){ 50060module.exports={ 50061 "resourcePath": "./server/download.php", 50062 "avatarResourcePath": "/teamchatapi/files.avatar", 50063 "icewarpapiUrl": "", 50064 "i18n": { 50065 "url": "locale/%s/data.json", 50066 "map": { 50067 "zh": "cn", 50068 "da": "dk", 50069 "ja": "jp", 50070 "ko": "kr", 50071 "sv": "se" 50072 } 50073 }, 50074 "sentry": false 50075} 50076 50077},{}]},{},[41]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.