@sentry/browser 5.24.2 → 5.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /*! @sentry/browser 5.24.2 (8096d02) | https://github.com/getsentry/sentry-javascript */
1
+ /*! @sentry/browser 5.25.0 (bca2c59) | https://github.com/getsentry/sentry-javascript */
2
2
  var Sentry = (function (exports) {
3
3
  /** Console logging verbosity for the SDK. */
4
4
  var LogLevel;
@@ -874,13 +874,6 @@ var Sentry = (function (exports) {
874
874
  ? self
875
875
  : fallbackGlobalObject);
876
876
  }
877
- /**
878
- * Determines if running in react native
879
- */
880
- function isReactNative() {
881
- var _a;
882
- return ((_a = getGlobalObject().navigator) === null || _a === void 0 ? void 0 : _a.product) === 'ReactNative';
883
- }
884
877
  /**
885
878
  * UUID4 generator
886
879
  *
@@ -1032,73 +1025,6 @@ var Sentry = (function (exports) {
1032
1025
  return '';
1033
1026
  }
1034
1027
  }
1035
- const INITIAL_TIME = Date.now();
1036
- let prevNow = 0;
1037
- const performanceFallback = {
1038
- now() {
1039
- let now = Date.now() - INITIAL_TIME;
1040
- if (now < prevNow) {
1041
- now = prevNow;
1042
- }
1043
- prevNow = now;
1044
- return now;
1045
- },
1046
- timeOrigin: INITIAL_TIME,
1047
- };
1048
- /**
1049
- * Performance wrapper for react native as performance.now() has been found to start off with an unusual offset.
1050
- */
1051
- function getReactNativePerformanceWrapper() {
1052
- // Performance only available >= RN 0.63
1053
- const { performance } = getGlobalObject();
1054
- if (performance && typeof performance.now === 'function') {
1055
- const INITIAL_OFFSET = performance.now();
1056
- return {
1057
- now() {
1058
- return performance.now() - INITIAL_OFFSET;
1059
- },
1060
- timeOrigin: INITIAL_TIME,
1061
- };
1062
- }
1063
- return performanceFallback;
1064
- }
1065
- const crossPlatformPerformance = (() => {
1066
- // React Native's performance.now() starts with a gigantic offset, so we need to wrap it.
1067
- if (isReactNative()) {
1068
- return getReactNativePerformanceWrapper();
1069
- }
1070
- if (isNodeEnv()) {
1071
- try {
1072
- const perfHooks = dynamicRequire(module, 'perf_hooks');
1073
- return perfHooks.performance;
1074
- }
1075
- catch (_) {
1076
- return performanceFallback;
1077
- }
1078
- }
1079
- const { performance } = getGlobalObject();
1080
- if (!performance || !performance.now) {
1081
- return performanceFallback;
1082
- }
1083
- // Polyfill for performance.timeOrigin.
1084
- //
1085
- // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin
1086
- // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing.
1087
- if (performance.timeOrigin === undefined) {
1088
- // As of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always a
1089
- // valid fallback. In the absence of a initial time provided by the browser, fallback to INITIAL_TIME.
1090
- // @ts-ignore ignored because timeOrigin is a readonly property but we want to override
1091
- // eslint-disable-next-line deprecation/deprecation
1092
- performance.timeOrigin = (performance.timing && performance.timing.navigationStart) || INITIAL_TIME;
1093
- }
1094
- return performance;
1095
- })();
1096
- /**
1097
- * Returns a timestamp in seconds with milliseconds precision since the UNIX epoch calculated with the monotonic clock.
1098
- */
1099
- function timestampWithMs() {
1100
- return (crossPlatformPerformance.timeOrigin + crossPlatformPerformance.now()) / 1000;
1101
- }
1102
1028
  const defaultRetryAfter = 60 * 1000; // 60 seconds
1103
1029
  /**
1104
1030
  * Extracts Retry-After value from the request header or returns default value
@@ -1171,359 +1097,93 @@ var Sentry = (function (exports) {
1171
1097
  global$1.__SENTRY__ = global$1.__SENTRY__ || {};
1172
1098
  const logger = global$1.__SENTRY__.logger || (global$1.__SENTRY__.logger = new Logger());
1173
1099
 
1174
- /* eslint-disable @typescript-eslint/explicit-function-return-type */
1175
- /** SyncPromise internal states */
1176
- var States;
1177
- (function (States) {
1178
- /** Pending */
1179
- States["PENDING"] = "PENDING";
1180
- /** Resolved / OK */
1181
- States["RESOLVED"] = "RESOLVED";
1182
- /** Rejected / Error */
1183
- States["REJECTED"] = "REJECTED";
1184
- })(States || (States = {}));
1185
1100
  /**
1186
- * Thenable class that behaves like a Promise and follows it's interface
1187
- * but is not async internally
1101
+ * Tells whether current environment supports Fetch API
1102
+ * {@link supportsFetch}.
1103
+ *
1104
+ * @returns Answer to the given question.
1188
1105
  */
1189
- class SyncPromise {
1190
- constructor(executor) {
1191
- this._state = States.PENDING;
1192
- this._handlers = [];
1193
- /** JSDoc */
1194
- this._resolve = (value) => {
1195
- this._setResult(States.RESOLVED, value);
1196
- };
1197
- /** JSDoc */
1198
- this._reject = (reason) => {
1199
- this._setResult(States.REJECTED, reason);
1200
- };
1201
- /** JSDoc */
1202
- this._setResult = (state, value) => {
1203
- if (this._state !== States.PENDING) {
1204
- return;
1205
- }
1206
- if (isThenable(value)) {
1207
- value.then(this._resolve, this._reject);
1208
- return;
1209
- }
1210
- this._state = state;
1211
- this._value = value;
1212
- this._executeHandlers();
1213
- };
1214
- // TODO: FIXME
1215
- /** JSDoc */
1216
- this._attachHandler = (handler) => {
1217
- this._handlers = this._handlers.concat(handler);
1218
- this._executeHandlers();
1219
- };
1220
- /** JSDoc */
1221
- this._executeHandlers = () => {
1222
- if (this._state === States.PENDING) {
1223
- return;
1224
- }
1225
- const cachedHandlers = this._handlers.slice();
1226
- this._handlers = [];
1227
- cachedHandlers.forEach(handler => {
1228
- if (handler.done) {
1229
- return;
1230
- }
1231
- if (this._state === States.RESOLVED) {
1232
- if (handler.onfulfilled) {
1233
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
1234
- handler.onfulfilled(this._value);
1235
- }
1236
- }
1237
- if (this._state === States.REJECTED) {
1238
- if (handler.onrejected) {
1239
- handler.onrejected(this._value);
1240
- }
1241
- }
1242
- handler.done = true;
1243
- });
1244
- };
1245
- try {
1246
- executor(this._resolve, this._reject);
1247
- }
1248
- catch (e) {
1249
- this._reject(e);
1250
- }
1106
+ function supportsFetch() {
1107
+ if (!('fetch' in getGlobalObject())) {
1108
+ return false;
1251
1109
  }
1252
- /** JSDoc */
1253
- static resolve(value) {
1254
- return new SyncPromise(resolve => {
1255
- resolve(value);
1256
- });
1110
+ try {
1111
+ new Headers();
1112
+ new Request('');
1113
+ new Response();
1114
+ return true;
1257
1115
  }
1258
- /** JSDoc */
1259
- static reject(reason) {
1260
- return new SyncPromise((_, reject) => {
1261
- reject(reason);
1262
- });
1116
+ catch (e) {
1117
+ return false;
1263
1118
  }
1264
- /** JSDoc */
1265
- static all(collection) {
1266
- return new SyncPromise((resolve, reject) => {
1267
- if (!Array.isArray(collection)) {
1268
- reject(new TypeError(`Promise.all requires an array as input.`));
1269
- return;
1270
- }
1271
- if (collection.length === 0) {
1272
- resolve([]);
1273
- return;
1119
+ }
1120
+ /**
1121
+ * isNativeFetch checks if the given function is a native implementation of fetch()
1122
+ */
1123
+ // eslint-disable-next-line @typescript-eslint/ban-types
1124
+ function isNativeFetch(func) {
1125
+ return func && /^function fetch\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString());
1126
+ }
1127
+ /**
1128
+ * Tells whether current environment supports Fetch API natively
1129
+ * {@link supportsNativeFetch}.
1130
+ *
1131
+ * @returns true if `window.fetch` is natively implemented, false otherwise
1132
+ */
1133
+ function supportsNativeFetch() {
1134
+ if (!supportsFetch()) {
1135
+ return false;
1136
+ }
1137
+ const global = getGlobalObject();
1138
+ // Fast path to avoid DOM I/O
1139
+ // eslint-disable-next-line @typescript-eslint/unbound-method
1140
+ if (isNativeFetch(global.fetch)) {
1141
+ return true;
1142
+ }
1143
+ // window.fetch is implemented, but is polyfilled or already wrapped (e.g: by a chrome extension)
1144
+ // so create a "pure" iframe to see if that has native fetch
1145
+ let result = false;
1146
+ const doc = global.document;
1147
+ // eslint-disable-next-line deprecation/deprecation
1148
+ if (doc && typeof doc.createElement === `function`) {
1149
+ try {
1150
+ const sandbox = doc.createElement('iframe');
1151
+ sandbox.hidden = true;
1152
+ doc.head.appendChild(sandbox);
1153
+ if (sandbox.contentWindow && sandbox.contentWindow.fetch) {
1154
+ // eslint-disable-next-line @typescript-eslint/unbound-method
1155
+ result = isNativeFetch(sandbox.contentWindow.fetch);
1274
1156
  }
1275
- let counter = collection.length;
1276
- const resolvedCollection = [];
1277
- collection.forEach((item, index) => {
1278
- SyncPromise.resolve(item)
1279
- .then(value => {
1280
- resolvedCollection[index] = value;
1281
- counter -= 1;
1282
- if (counter !== 0) {
1283
- return;
1284
- }
1285
- resolve(resolvedCollection);
1286
- })
1287
- .then(null, reject);
1288
- });
1289
- });
1157
+ doc.head.removeChild(sandbox);
1158
+ }
1159
+ catch (err) {
1160
+ logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err);
1161
+ }
1290
1162
  }
1291
- /** JSDoc */
1292
- then(onfulfilled, onrejected) {
1293
- return new SyncPromise((resolve, reject) => {
1294
- this._attachHandler({
1295
- done: false,
1296
- onfulfilled: result => {
1297
- if (!onfulfilled) {
1298
- // TODO: ¯\_(ツ)_/¯
1299
- // TODO: FIXME
1300
- resolve(result);
1301
- return;
1302
- }
1303
- try {
1304
- resolve(onfulfilled(result));
1305
- return;
1306
- }
1307
- catch (e) {
1308
- reject(e);
1309
- return;
1310
- }
1311
- },
1312
- onrejected: reason => {
1313
- if (!onrejected) {
1314
- reject(reason);
1315
- return;
1316
- }
1317
- try {
1318
- resolve(onrejected(reason));
1319
- return;
1320
- }
1321
- catch (e) {
1322
- reject(e);
1323
- return;
1324
- }
1325
- },
1326
- });
1163
+ return result;
1164
+ }
1165
+ /**
1166
+ * Tells whether current environment supports Referrer Policy API
1167
+ * {@link supportsReferrerPolicy}.
1168
+ *
1169
+ * @returns Answer to the given question.
1170
+ */
1171
+ function supportsReferrerPolicy() {
1172
+ // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default
1173
+ // https://caniuse.com/#feat=referrer-policy
1174
+ // It doesn't. And it throw exception instead of ignoring this parameter...
1175
+ // REF: https://github.com/getsentry/raven-js/issues/1233
1176
+ if (!supportsFetch()) {
1177
+ return false;
1178
+ }
1179
+ try {
1180
+ new Request('_', {
1181
+ referrerPolicy: 'origin',
1327
1182
  });
1183
+ return true;
1328
1184
  }
1329
- /** JSDoc */
1330
- catch(onrejected) {
1331
- return this.then(val => val, onrejected);
1332
- }
1333
- /** JSDoc */
1334
- finally(onfinally) {
1335
- return new SyncPromise((resolve, reject) => {
1336
- let val;
1337
- let isRejected;
1338
- return this.then(value => {
1339
- isRejected = false;
1340
- val = value;
1341
- if (onfinally) {
1342
- onfinally();
1343
- }
1344
- }, reason => {
1345
- isRejected = true;
1346
- val = reason;
1347
- if (onfinally) {
1348
- onfinally();
1349
- }
1350
- }).then(() => {
1351
- if (isRejected) {
1352
- reject(val);
1353
- return;
1354
- }
1355
- resolve(val);
1356
- });
1357
- });
1358
- }
1359
- /** JSDoc */
1360
- toString() {
1361
- return '[object SyncPromise]';
1362
- }
1363
- }
1364
-
1365
- /** A simple queue that holds promises. */
1366
- class PromiseBuffer {
1367
- constructor(_limit) {
1368
- this._limit = _limit;
1369
- /** Internal set of queued Promises */
1370
- this._buffer = [];
1371
- }
1372
- /**
1373
- * Says if the buffer is ready to take more requests
1374
- */
1375
- isReady() {
1376
- return this._limit === undefined || this.length() < this._limit;
1377
- }
1378
- /**
1379
- * Add a promise to the queue.
1380
- *
1381
- * @param task Can be any PromiseLike<T>
1382
- * @returns The original promise.
1383
- */
1384
- add(task) {
1385
- if (!this.isReady()) {
1386
- return SyncPromise.reject(new SentryError('Not adding Promise due to buffer limit reached.'));
1387
- }
1388
- if (this._buffer.indexOf(task) === -1) {
1389
- this._buffer.push(task);
1390
- }
1391
- task
1392
- .then(() => this.remove(task))
1393
- .then(null, () => this.remove(task).then(null, () => {
1394
- // We have to add this catch here otherwise we have an unhandledPromiseRejection
1395
- // because it's a new Promise chain.
1396
- }));
1397
- return task;
1398
- }
1399
- /**
1400
- * Remove a promise to the queue.
1401
- *
1402
- * @param task Can be any PromiseLike<T>
1403
- * @returns Removed promise.
1404
- */
1405
- remove(task) {
1406
- const removedTask = this._buffer.splice(this._buffer.indexOf(task), 1)[0];
1407
- return removedTask;
1408
- }
1409
- /**
1410
- * This function returns the number of unresolved promises in the queue.
1411
- */
1412
- length() {
1413
- return this._buffer.length;
1414
- }
1415
- /**
1416
- * This will drain the whole queue, returns true if queue is empty or drained.
1417
- * If timeout is provided and the queue takes longer to drain, the promise still resolves but with false.
1418
- *
1419
- * @param timeout Number in ms to wait until it resolves with false.
1420
- */
1421
- drain(timeout) {
1422
- return new SyncPromise(resolve => {
1423
- const capturedSetTimeout = setTimeout(() => {
1424
- if (timeout && timeout > 0) {
1425
- resolve(false);
1426
- }
1427
- }, timeout);
1428
- SyncPromise.all(this._buffer)
1429
- .then(() => {
1430
- clearTimeout(capturedSetTimeout);
1431
- resolve(true);
1432
- })
1433
- .then(null, () => {
1434
- resolve(true);
1435
- });
1436
- });
1437
- }
1438
- }
1439
-
1440
- /**
1441
- * Tells whether current environment supports Fetch API
1442
- * {@link supportsFetch}.
1443
- *
1444
- * @returns Answer to the given question.
1445
- */
1446
- function supportsFetch() {
1447
- if (!('fetch' in getGlobalObject())) {
1448
- return false;
1449
- }
1450
- try {
1451
- new Headers();
1452
- new Request('');
1453
- new Response();
1454
- return true;
1455
- }
1456
- catch (e) {
1457
- return false;
1458
- }
1459
- }
1460
- /**
1461
- * isNativeFetch checks if the given function is a native implementation of fetch()
1462
- */
1463
- // eslint-disable-next-line @typescript-eslint/ban-types
1464
- function isNativeFetch(func) {
1465
- return func && /^function fetch\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString());
1466
- }
1467
- /**
1468
- * Tells whether current environment supports Fetch API natively
1469
- * {@link supportsNativeFetch}.
1470
- *
1471
- * @returns true if `window.fetch` is natively implemented, false otherwise
1472
- */
1473
- function supportsNativeFetch() {
1474
- if (!supportsFetch()) {
1475
- return false;
1476
- }
1477
- const global = getGlobalObject();
1478
- // Fast path to avoid DOM I/O
1479
- // eslint-disable-next-line @typescript-eslint/unbound-method
1480
- if (isNativeFetch(global.fetch)) {
1481
- return true;
1482
- }
1483
- // window.fetch is implemented, but is polyfilled or already wrapped (e.g: by a chrome extension)
1484
- // so create a "pure" iframe to see if that has native fetch
1485
- let result = false;
1486
- const doc = global.document;
1487
- // eslint-disable-next-line deprecation/deprecation
1488
- if (doc && typeof doc.createElement === `function`) {
1489
- try {
1490
- const sandbox = doc.createElement('iframe');
1491
- sandbox.hidden = true;
1492
- doc.head.appendChild(sandbox);
1493
- if (sandbox.contentWindow && sandbox.contentWindow.fetch) {
1494
- // eslint-disable-next-line @typescript-eslint/unbound-method
1495
- result = isNativeFetch(sandbox.contentWindow.fetch);
1496
- }
1497
- doc.head.removeChild(sandbox);
1498
- }
1499
- catch (err) {
1500
- logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err);
1501
- }
1502
- }
1503
- return result;
1504
- }
1505
- /**
1506
- * Tells whether current environment supports Referrer Policy API
1507
- * {@link supportsReferrerPolicy}.
1508
- *
1509
- * @returns Answer to the given question.
1510
- */
1511
- function supportsReferrerPolicy() {
1512
- // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default
1513
- // https://caniuse.com/#feat=referrer-policy
1514
- // It doesn't. And it throw exception instead of ignoring this parameter...
1515
- // REF: https://github.com/getsentry/raven-js/issues/1233
1516
- if (!supportsFetch()) {
1517
- return false;
1518
- }
1519
- try {
1520
- new Request('_', {
1521
- referrerPolicy: 'origin',
1522
- });
1523
- return true;
1524
- }
1525
- catch (e) {
1526
- return false;
1185
+ catch (e) {
1186
+ return false;
1527
1187
  }
1528
1188
  }
1529
1189
  /**
@@ -1645,7 +1305,7 @@ var Sentry = (function (exports) {
1645
1305
  }
1646
1306
  fill(global$2, 'fetch', function (originalFetch) {
1647
1307
  return function (...args) {
1648
- const commonHandlerData = {
1308
+ const handlerData = {
1649
1309
  args,
1650
1310
  fetchData: {
1651
1311
  method: getFetchMethod(args),
@@ -1653,13 +1313,13 @@ var Sentry = (function (exports) {
1653
1313
  },
1654
1314
  startTimestamp: Date.now(),
1655
1315
  };
1656
- triggerHandlers('fetch', Object.assign({}, commonHandlerData));
1316
+ triggerHandlers('fetch', Object.assign({}, handlerData));
1657
1317
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1658
1318
  return originalFetch.apply(global$2, args).then((response) => {
1659
- triggerHandlers('fetch', Object.assign(Object.assign({}, commonHandlerData), { endTimestamp: Date.now(), response }));
1319
+ triggerHandlers('fetch', Object.assign(Object.assign({}, handlerData), { endTimestamp: Date.now(), response }));
1660
1320
  return response;
1661
1321
  }, (error) => {
1662
- triggerHandlers('fetch', Object.assign(Object.assign({}, commonHandlerData), { endTimestamp: Date.now(), error }));
1322
+ triggerHandlers('fetch', Object.assign(Object.assign({}, handlerData), { endTimestamp: Date.now(), error }));
1663
1323
  // NOTE: If you are a Sentry user, and you are seeing this stack frame,
1664
1324
  // it means the sentry.javascript SDK caught an error invoking your application code.
1665
1325
  // This is expected behavior and NOT indicative of a bug with sentry.javascript.
@@ -1695,7 +1355,7 @@ var Sentry = (function (exports) {
1695
1355
  if (!('XMLHttpRequest' in global$2)) {
1696
1356
  return;
1697
1357
  }
1698
- // Poor man implementation of ES6 `Map` by tracking and keeping in sync key and value separately.
1358
+ // Poor man's implementation of ES6 `Map`, tracking and keeping in sync key and value separately.
1699
1359
  const requestKeys = [];
1700
1360
  const requestValues = [];
1701
1361
  const xhrproto = XMLHttpRequest.prototype;
@@ -1729,7 +1389,7 @@ var Sentry = (function (exports) {
1729
1389
  try {
1730
1390
  const requestPos = requestKeys.indexOf(xhr);
1731
1391
  if (requestPos !== -1) {
1732
- // Make sure to pop both, key and value to keep it in sync.
1392
+ // Make sure to pop both key and value to keep it in sync.
1733
1393
  requestKeys.splice(requestPos);
1734
1394
  const args = requestValues.splice(requestPos)[0];
1735
1395
  if (xhr.__sentry_xhr__ && args[0] !== undefined) {
@@ -1987,56 +1647,427 @@ var Sentry = (function (exports) {
1987
1647
  };
1988
1648
  }
1989
1649
 
1650
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
1651
+ /** SyncPromise internal states */
1652
+ var States;
1653
+ (function (States) {
1654
+ /** Pending */
1655
+ States["PENDING"] = "PENDING";
1656
+ /** Resolved / OK */
1657
+ States["RESOLVED"] = "RESOLVED";
1658
+ /** Rejected / Error */
1659
+ States["REJECTED"] = "REJECTED";
1660
+ })(States || (States = {}));
1990
1661
  /**
1991
- * Holds additional event information. {@link Scope.applyToEvent} will be
1992
- * called by the client before an event will be sent.
1662
+ * Thenable class that behaves like a Promise and follows it's interface
1663
+ * but is not async internally
1993
1664
  */
1994
- class Scope {
1995
- constructor() {
1996
- /** Flag if notifiying is happening. */
1997
- this._notifyingListeners = false;
1998
- /** Callback for client to receive scope changes. */
1999
- this._scopeListeners = [];
2000
- /** Callback list that will be called after {@link applyToEvent}. */
2001
- this._eventProcessors = [];
2002
- /** Array of breadcrumbs. */
2003
- this._breadcrumbs = [];
2004
- /** User */
2005
- this._user = {};
2006
- /** Tags */
2007
- this._tags = {};
2008
- /** Extra */
2009
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2010
- this._extra = {};
2011
- /** Contexts */
2012
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2013
- this._contexts = {};
2014
- }
2015
- /**
2016
- * Inherit values from the parent scope.
2017
- * @param scope to clone.
2018
- */
2019
- static clone(scope) {
2020
- const newScope = new Scope();
2021
- if (scope) {
2022
- newScope._breadcrumbs = [...scope._breadcrumbs];
2023
- newScope._tags = Object.assign({}, scope._tags);
2024
- newScope._extra = Object.assign({}, scope._extra);
2025
- newScope._contexts = Object.assign({}, scope._contexts);
2026
- newScope._user = scope._user;
2027
- newScope._level = scope._level;
2028
- newScope._span = scope._span;
2029
- newScope._transactionName = scope._transactionName;
2030
- newScope._fingerprint = scope._fingerprint;
2031
- newScope._eventProcessors = [...scope._eventProcessors];
2032
- }
2033
- return newScope;
2034
- }
2035
- /**
2036
- * Add internal on change listener. Used for sub SDKs that need to store the scope.
2037
- * @hidden
2038
- */
2039
- addScopeListener(callback) {
1665
+ class SyncPromise {
1666
+ constructor(executor) {
1667
+ this._state = States.PENDING;
1668
+ this._handlers = [];
1669
+ /** JSDoc */
1670
+ this._resolve = (value) => {
1671
+ this._setResult(States.RESOLVED, value);
1672
+ };
1673
+ /** JSDoc */
1674
+ this._reject = (reason) => {
1675
+ this._setResult(States.REJECTED, reason);
1676
+ };
1677
+ /** JSDoc */
1678
+ this._setResult = (state, value) => {
1679
+ if (this._state !== States.PENDING) {
1680
+ return;
1681
+ }
1682
+ if (isThenable(value)) {
1683
+ value.then(this._resolve, this._reject);
1684
+ return;
1685
+ }
1686
+ this._state = state;
1687
+ this._value = value;
1688
+ this._executeHandlers();
1689
+ };
1690
+ // TODO: FIXME
1691
+ /** JSDoc */
1692
+ this._attachHandler = (handler) => {
1693
+ this._handlers = this._handlers.concat(handler);
1694
+ this._executeHandlers();
1695
+ };
1696
+ /** JSDoc */
1697
+ this._executeHandlers = () => {
1698
+ if (this._state === States.PENDING) {
1699
+ return;
1700
+ }
1701
+ const cachedHandlers = this._handlers.slice();
1702
+ this._handlers = [];
1703
+ cachedHandlers.forEach(handler => {
1704
+ if (handler.done) {
1705
+ return;
1706
+ }
1707
+ if (this._state === States.RESOLVED) {
1708
+ if (handler.onfulfilled) {
1709
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
1710
+ handler.onfulfilled(this._value);
1711
+ }
1712
+ }
1713
+ if (this._state === States.REJECTED) {
1714
+ if (handler.onrejected) {
1715
+ handler.onrejected(this._value);
1716
+ }
1717
+ }
1718
+ handler.done = true;
1719
+ });
1720
+ };
1721
+ try {
1722
+ executor(this._resolve, this._reject);
1723
+ }
1724
+ catch (e) {
1725
+ this._reject(e);
1726
+ }
1727
+ }
1728
+ /** JSDoc */
1729
+ static resolve(value) {
1730
+ return new SyncPromise(resolve => {
1731
+ resolve(value);
1732
+ });
1733
+ }
1734
+ /** JSDoc */
1735
+ static reject(reason) {
1736
+ return new SyncPromise((_, reject) => {
1737
+ reject(reason);
1738
+ });
1739
+ }
1740
+ /** JSDoc */
1741
+ static all(collection) {
1742
+ return new SyncPromise((resolve, reject) => {
1743
+ if (!Array.isArray(collection)) {
1744
+ reject(new TypeError(`Promise.all requires an array as input.`));
1745
+ return;
1746
+ }
1747
+ if (collection.length === 0) {
1748
+ resolve([]);
1749
+ return;
1750
+ }
1751
+ let counter = collection.length;
1752
+ const resolvedCollection = [];
1753
+ collection.forEach((item, index) => {
1754
+ SyncPromise.resolve(item)
1755
+ .then(value => {
1756
+ resolvedCollection[index] = value;
1757
+ counter -= 1;
1758
+ if (counter !== 0) {
1759
+ return;
1760
+ }
1761
+ resolve(resolvedCollection);
1762
+ })
1763
+ .then(null, reject);
1764
+ });
1765
+ });
1766
+ }
1767
+ /** JSDoc */
1768
+ then(onfulfilled, onrejected) {
1769
+ return new SyncPromise((resolve, reject) => {
1770
+ this._attachHandler({
1771
+ done: false,
1772
+ onfulfilled: result => {
1773
+ if (!onfulfilled) {
1774
+ // TODO: ¯\_(ツ)_/¯
1775
+ // TODO: FIXME
1776
+ resolve(result);
1777
+ return;
1778
+ }
1779
+ try {
1780
+ resolve(onfulfilled(result));
1781
+ return;
1782
+ }
1783
+ catch (e) {
1784
+ reject(e);
1785
+ return;
1786
+ }
1787
+ },
1788
+ onrejected: reason => {
1789
+ if (!onrejected) {
1790
+ reject(reason);
1791
+ return;
1792
+ }
1793
+ try {
1794
+ resolve(onrejected(reason));
1795
+ return;
1796
+ }
1797
+ catch (e) {
1798
+ reject(e);
1799
+ return;
1800
+ }
1801
+ },
1802
+ });
1803
+ });
1804
+ }
1805
+ /** JSDoc */
1806
+ catch(onrejected) {
1807
+ return this.then(val => val, onrejected);
1808
+ }
1809
+ /** JSDoc */
1810
+ finally(onfinally) {
1811
+ return new SyncPromise((resolve, reject) => {
1812
+ let val;
1813
+ let isRejected;
1814
+ return this.then(value => {
1815
+ isRejected = false;
1816
+ val = value;
1817
+ if (onfinally) {
1818
+ onfinally();
1819
+ }
1820
+ }, reason => {
1821
+ isRejected = true;
1822
+ val = reason;
1823
+ if (onfinally) {
1824
+ onfinally();
1825
+ }
1826
+ }).then(() => {
1827
+ if (isRejected) {
1828
+ reject(val);
1829
+ return;
1830
+ }
1831
+ resolve(val);
1832
+ });
1833
+ });
1834
+ }
1835
+ /** JSDoc */
1836
+ toString() {
1837
+ return '[object SyncPromise]';
1838
+ }
1839
+ }
1840
+
1841
+ /** A simple queue that holds promises. */
1842
+ class PromiseBuffer {
1843
+ constructor(_limit) {
1844
+ this._limit = _limit;
1845
+ /** Internal set of queued Promises */
1846
+ this._buffer = [];
1847
+ }
1848
+ /**
1849
+ * Says if the buffer is ready to take more requests
1850
+ */
1851
+ isReady() {
1852
+ return this._limit === undefined || this.length() < this._limit;
1853
+ }
1854
+ /**
1855
+ * Add a promise to the queue.
1856
+ *
1857
+ * @param task Can be any PromiseLike<T>
1858
+ * @returns The original promise.
1859
+ */
1860
+ add(task) {
1861
+ if (!this.isReady()) {
1862
+ return SyncPromise.reject(new SentryError('Not adding Promise due to buffer limit reached.'));
1863
+ }
1864
+ if (this._buffer.indexOf(task) === -1) {
1865
+ this._buffer.push(task);
1866
+ }
1867
+ task
1868
+ .then(() => this.remove(task))
1869
+ .then(null, () => this.remove(task).then(null, () => {
1870
+ // We have to add this catch here otherwise we have an unhandledPromiseRejection
1871
+ // because it's a new Promise chain.
1872
+ }));
1873
+ return task;
1874
+ }
1875
+ /**
1876
+ * Remove a promise to the queue.
1877
+ *
1878
+ * @param task Can be any PromiseLike<T>
1879
+ * @returns Removed promise.
1880
+ */
1881
+ remove(task) {
1882
+ const removedTask = this._buffer.splice(this._buffer.indexOf(task), 1)[0];
1883
+ return removedTask;
1884
+ }
1885
+ /**
1886
+ * This function returns the number of unresolved promises in the queue.
1887
+ */
1888
+ length() {
1889
+ return this._buffer.length;
1890
+ }
1891
+ /**
1892
+ * This will drain the whole queue, returns true if queue is empty or drained.
1893
+ * If timeout is provided and the queue takes longer to drain, the promise still resolves but with false.
1894
+ *
1895
+ * @param timeout Number in ms to wait until it resolves with false.
1896
+ */
1897
+ drain(timeout) {
1898
+ return new SyncPromise(resolve => {
1899
+ const capturedSetTimeout = setTimeout(() => {
1900
+ if (timeout && timeout > 0) {
1901
+ resolve(false);
1902
+ }
1903
+ }, timeout);
1904
+ SyncPromise.all(this._buffer)
1905
+ .then(() => {
1906
+ clearTimeout(capturedSetTimeout);
1907
+ resolve(true);
1908
+ })
1909
+ .then(null, () => {
1910
+ resolve(true);
1911
+ });
1912
+ });
1913
+ }
1914
+ }
1915
+
1916
+ /**
1917
+ * A TimestampSource implementation for environments that do not support the Performance Web API natively.
1918
+ *
1919
+ * Note that this TimestampSource does not use a monotonic clock. A call to `nowSeconds` may return a timestamp earlier
1920
+ * than a previously returned value. We do not try to emulate a monotonic behavior in order to facilitate debugging. It
1921
+ * is more obvious to explain "why does my span have negative duration" than "why my spans have zero duration".
1922
+ */
1923
+ const dateTimestampSource = {
1924
+ nowSeconds: () => Date.now() / 1000,
1925
+ };
1926
+ /**
1927
+ * Returns a wrapper around the native Performance API browser implementation, or undefined for browsers that do not
1928
+ * support the API.
1929
+ *
1930
+ * Wrapping the native API works around differences in behavior from different browsers.
1931
+ */
1932
+ function getBrowserPerformance() {
1933
+ const { performance } = getGlobalObject();
1934
+ if (!performance || !performance.now) {
1935
+ return undefined;
1936
+ }
1937
+ // Replace performance.timeOrigin with our own timeOrigin based on Date.now().
1938
+ //
1939
+ // This is a partial workaround for browsers reporting performance.timeOrigin such that performance.timeOrigin +
1940
+ // performance.now() gives a date arbitrarily in the past.
1941
+ //
1942
+ // Additionally, computing timeOrigin in this way fills the gap for browsers where performance.timeOrigin is
1943
+ // undefined.
1944
+ //
1945
+ // The assumption that performance.timeOrigin + performance.now() ~= Date.now() is flawed, but we depend on it to
1946
+ // interact with data coming out of performance entries.
1947
+ //
1948
+ // Note that despite recommendations against it in the spec, browsers implement the Performance API with a clock that
1949
+ // might stop when the computer is asleep (and perhaps under other circumstances). Such behavior causes
1950
+ // performance.timeOrigin + performance.now() to have an arbitrary skew over Date.now(). In laptop computers, we have
1951
+ // observed skews that can be as long as days, weeks or months.
1952
+ //
1953
+ // See https://github.com/getsentry/sentry-javascript/issues/2590.
1954
+ //
1955
+ // BUG: despite our best intentions, this workaround has its limitations. It mostly addresses timings of pageload
1956
+ // transactions, but ignores the skew built up over time that can aversely affect timestamps of navigation
1957
+ // transactions of long-lived web pages.
1958
+ const timeOrigin = Date.now() - performance.now();
1959
+ return {
1960
+ now: () => performance.now(),
1961
+ timeOrigin,
1962
+ };
1963
+ }
1964
+ /**
1965
+ * Returns the native Performance API implementation from Node.js. Returns undefined in old Node.js versions that don't
1966
+ * implement the API.
1967
+ */
1968
+ function getNodePerformance() {
1969
+ try {
1970
+ const perfHooks = dynamicRequire(module, 'perf_hooks');
1971
+ return perfHooks.performance;
1972
+ }
1973
+ catch (_) {
1974
+ return undefined;
1975
+ }
1976
+ }
1977
+ /**
1978
+ * The Performance API implementation for the current platform, if available.
1979
+ */
1980
+ const platformPerformance = isNodeEnv() ? getNodePerformance() : getBrowserPerformance();
1981
+ const timestampSource = platformPerformance === undefined
1982
+ ? dateTimestampSource
1983
+ : {
1984
+ nowSeconds: () => (platformPerformance.timeOrigin + platformPerformance.now()) / 1000,
1985
+ };
1986
+ /**
1987
+ * Returns a timestamp in seconds since the UNIX epoch using the Date API.
1988
+ */
1989
+ const dateTimestampInSeconds = dateTimestampSource.nowSeconds.bind(dateTimestampSource);
1990
+ /**
1991
+ * Returns a timestamp in seconds since the UNIX epoch using either the Performance or Date APIs, depending on the
1992
+ * availability of the Performance API.
1993
+ *
1994
+ * See `usingPerformanceAPI` to test whether the Performance API is used.
1995
+ *
1996
+ * BUG: Note that because of how browsers implement the Performance API, the clock might stop when the computer is
1997
+ * asleep. This creates a skew between `dateTimestampInSeconds` and `timestampInSeconds`. The
1998
+ * skew can grow to arbitrary amounts like days, weeks or months.
1999
+ * See https://github.com/getsentry/sentry-javascript/issues/2590.
2000
+ */
2001
+ const timestampInSeconds = timestampSource.nowSeconds.bind(timestampSource);
2002
+ /**
2003
+ * The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the
2004
+ * performance API is available.
2005
+ */
2006
+ const browserPerformanceTimeOrigin = (() => {
2007
+ const { performance } = getGlobalObject();
2008
+ if (!performance) {
2009
+ return undefined;
2010
+ }
2011
+ if (performance.timeOrigin) {
2012
+ return performance.timeOrigin;
2013
+ }
2014
+ // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin
2015
+ // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing.
2016
+ // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always
2017
+ // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the
2018
+ // Date API.
2019
+ // eslint-disable-next-line deprecation/deprecation
2020
+ return (performance.timing && performance.timing.navigationStart) || Date.now();
2021
+ })();
2022
+
2023
+ /**
2024
+ * Holds additional event information. {@link Scope.applyToEvent} will be
2025
+ * called by the client before an event will be sent.
2026
+ */
2027
+ class Scope {
2028
+ constructor() {
2029
+ /** Flag if notifiying is happening. */
2030
+ this._notifyingListeners = false;
2031
+ /** Callback for client to receive scope changes. */
2032
+ this._scopeListeners = [];
2033
+ /** Callback list that will be called after {@link applyToEvent}. */
2034
+ this._eventProcessors = [];
2035
+ /** Array of breadcrumbs. */
2036
+ this._breadcrumbs = [];
2037
+ /** User */
2038
+ this._user = {};
2039
+ /** Tags */
2040
+ this._tags = {};
2041
+ /** Extra */
2042
+ this._extra = {};
2043
+ /** Contexts */
2044
+ this._contexts = {};
2045
+ }
2046
+ /**
2047
+ * Inherit values from the parent scope.
2048
+ * @param scope to clone.
2049
+ */
2050
+ static clone(scope) {
2051
+ const newScope = new Scope();
2052
+ if (scope) {
2053
+ newScope._breadcrumbs = [...scope._breadcrumbs];
2054
+ newScope._tags = Object.assign({}, scope._tags);
2055
+ newScope._extra = Object.assign({}, scope._extra);
2056
+ newScope._contexts = Object.assign({}, scope._contexts);
2057
+ newScope._user = scope._user;
2058
+ newScope._level = scope._level;
2059
+ newScope._span = scope._span;
2060
+ newScope._transactionName = scope._transactionName;
2061
+ newScope._fingerprint = scope._fingerprint;
2062
+ newScope._eventProcessors = [...scope._eventProcessors];
2063
+ }
2064
+ return newScope;
2065
+ }
2066
+ /**
2067
+ * Add internal on change listener. Used for sub SDKs that need to store the scope.
2068
+ * @hidden
2069
+ */
2070
+ addScopeListener(callback) {
2040
2071
  this._scopeListeners.push(callback);
2041
2072
  }
2042
2073
  /**
@@ -2120,9 +2151,14 @@ var Sentry = (function (exports) {
2120
2151
  /**
2121
2152
  * @inheritDoc
2122
2153
  */
2123
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2124
2154
  setContext(key, context) {
2125
- this._contexts = Object.assign(Object.assign({}, this._contexts), { [key]: context });
2155
+ if (context === null) {
2156
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
2157
+ delete this._contexts[key];
2158
+ }
2159
+ else {
2160
+ this._contexts = Object.assign(Object.assign({}, this._contexts), { [key]: context });
2161
+ }
2126
2162
  this._notifyScopeListeners();
2127
2163
  return this;
2128
2164
  }
@@ -2144,10 +2180,18 @@ var Sentry = (function (exports) {
2144
2180
  * @inheritDoc
2145
2181
  */
2146
2182
  getTransaction() {
2183
+ var _a, _b, _c, _d;
2184
+ // often, this span will be a transaction, but it's not guaranteed to be
2147
2185
  const span = this.getSpan();
2148
- if (span && span.spanRecorder && span.spanRecorder.spans[0]) {
2186
+ // try it the new way first
2187
+ if ((_a = span) === null || _a === void 0 ? void 0 : _a.transaction) {
2188
+ return (_b = span) === null || _b === void 0 ? void 0 : _b.transaction;
2189
+ }
2190
+ // fallback to the old way (known bug: this only finds transactions with sampled = true)
2191
+ if ((_d = (_c = span) === null || _c === void 0 ? void 0 : _c.spanRecorder) === null || _d === void 0 ? void 0 : _d.spans[0]) {
2149
2192
  return span.spanRecorder.spans[0];
2150
2193
  }
2194
+ // neither way found a transaction
2151
2195
  return undefined;
2152
2196
  }
2153
2197
  /**
@@ -2213,7 +2257,7 @@ var Sentry = (function (exports) {
2213
2257
  * @inheritDoc
2214
2258
  */
2215
2259
  addBreadcrumb(breadcrumb, maxBreadcrumbs) {
2216
- const mergedBreadcrumb = Object.assign({ timestamp: timestampWithMs() }, breadcrumb);
2260
+ const mergedBreadcrumb = Object.assign({ timestamp: dateTimestampInSeconds() }, breadcrumb);
2217
2261
  this._breadcrumbs =
2218
2262
  maxBreadcrumbs !== undefined && maxBreadcrumbs >= 0
2219
2263
  ? [...this._breadcrumbs, mergedBreadcrumb].slice(-maxBreadcrumbs)
@@ -2527,7 +2571,7 @@ var Sentry = (function (exports) {
2527
2571
  if (maxBreadcrumbs <= 0) {
2528
2572
  return;
2529
2573
  }
2530
- const timestamp = timestampWithMs();
2574
+ const timestamp = dateTimestampInSeconds();
2531
2575
  const mergedBreadcrumb = Object.assign({ timestamp }, breadcrumb);
2532
2576
  const finalBreadcrumb = beforeBreadcrumb
2533
2577
  ? consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint))
@@ -3337,7 +3381,7 @@ var Sentry = (function (exports) {
3337
3381
  */
3338
3382
  _prepareEvent(event, scope, hint) {
3339
3383
  const { normalizeDepth = 3 } = this.getOptions();
3340
- const prepared = Object.assign(Object.assign({}, event), { event_id: event.event_id || (hint && hint.event_id ? hint.event_id : uuid4()), timestamp: event.timestamp || timestampWithMs() });
3384
+ const prepared = Object.assign(Object.assign({}, event), { event_id: event.event_id || (hint && hint.event_id ? hint.event_id : uuid4()), timestamp: event.timestamp || dateTimestampInSeconds() });
3341
3385
  this._applyClientOptions(prepared);
3342
3386
  this._applyIntegrationsMetadata(prepared);
3343
3387
  // If we have scope given to us, use it as the base for further modifications.
@@ -3621,7 +3665,7 @@ var Sentry = (function (exports) {
3621
3665
  event_id: event.event_id,
3622
3666
  // We need to add * 1000 since we divide it by 1000 by default but JS works with ms precision
3623
3667
  // The reason we use timestampWithMs here is that all clocks across the SDK use the same clock
3624
- sent_at: new Date(timestampWithMs() * 1000).toISOString(),
3668
+ sent_at: new Date().toISOString(),
3625
3669
  });
3626
3670
  const itemHeaders = JSON.stringify({
3627
3671
  type: event.type,
@@ -5342,7 +5386,7 @@ var Sentry = (function (exports) {
5342
5386
  });
5343
5387
 
5344
5388
  const SDK_NAME = 'sentry.javascript.browser';
5345
- const SDK_VERSION = '5.24.2';
5389
+ const SDK_VERSION = '5.25.0';
5346
5390
 
5347
5391
  /**
5348
5392
  * The Sentry Browser SDK Client.