summaryrefslogtreecommitdiff
path: root/shared/logger/node_modules/@sentry/browser/esm/transports
diff options
context:
space:
mode:
Diffstat (limited to 'shared/logger/node_modules/@sentry/browser/esm/transports')
-rw-r--r--shared/logger/node_modules/@sentry/browser/esm/transports/fetch.js64
-rw-r--r--shared/logger/node_modules/@sentry/browser/esm/transports/offline.js133
-rw-r--r--shared/logger/node_modules/@sentry/browser/esm/transports/utils.js85
-rw-r--r--shared/logger/node_modules/@sentry/browser/esm/transports/xhr.js52
4 files changed, 334 insertions, 0 deletions
diff --git a/shared/logger/node_modules/@sentry/browser/esm/transports/fetch.js b/shared/logger/node_modules/@sentry/browser/esm/transports/fetch.js
new file mode 100644
index 0000000..bb836e3
--- /dev/null
+++ b/shared/logger/node_modules/@sentry/browser/esm/transports/fetch.js
@@ -0,0 +1,64 @@
+import { createTransport } from '@sentry/core';
+import { rejectedSyncPromise } from '@sentry/utils';
+import { getNativeFetchImplementation, clearCachedFetchImplementation } from './utils.js';
+
+/**
+ * Creates a Transport that uses the Fetch API to send events to Sentry.
+ */
+function makeFetchTransport(
+ options,
+ nativeFetch = getNativeFetchImplementation(),
+) {
+ let pendingBodySize = 0;
+ let pendingCount = 0;
+
+ function makeRequest(request) {
+ const requestSize = request.body.length;
+ pendingBodySize += requestSize;
+ pendingCount++;
+
+ const requestOptions = {
+ body: request.body,
+ method: 'POST',
+ referrerPolicy: 'origin',
+ headers: options.headers,
+ // Outgoing requests are usually cancelled when navigating to a different page, causing a "TypeError: Failed to
+ // fetch" error and sending a "network_error" client-outcome - in Chrome, the request status shows "(cancelled)".
+ // The `keepalive` flag keeps outgoing requests alive, even when switching pages. We want this since we're
+ // frequently sending events right before the user is switching pages (eg. whenfinishing navigation transactions).
+ // Gotchas:
+ // - `keepalive` isn't supported by Firefox
+ // - As per spec (https://fetch.spec.whatwg.org/#http-network-or-cache-fetch):
+ // If the sum of contentLength and inflightKeepaliveBytes is greater than 64 kibibytes, then return a network error.
+ // We will therefore only activate the flag when we're below that limit.
+ // There is also a limit of requests that can be open at the same time, so we also limit this to 15
+ // See https://github.com/getsentry/sentry-javascript/pull/7553 for details
+ keepalive: pendingBodySize <= 60000 && pendingCount < 15,
+ ...options.fetchOptions,
+ };
+
+ try {
+ return nativeFetch(options.url, requestOptions).then(response => {
+ pendingBodySize -= requestSize;
+ pendingCount--;
+ return {
+ statusCode: response.status,
+ headers: {
+ 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
+ 'retry-after': response.headers.get('Retry-After'),
+ },
+ };
+ });
+ } catch (e) {
+ clearCachedFetchImplementation();
+ pendingBodySize -= requestSize;
+ pendingCount--;
+ return rejectedSyncPromise(e);
+ }
+ }
+
+ return createTransport(options, makeRequest);
+}
+
+export { makeFetchTransport };
+//# sourceMappingURL=fetch.js.map
diff --git a/shared/logger/node_modules/@sentry/browser/esm/transports/offline.js b/shared/logger/node_modules/@sentry/browser/esm/transports/offline.js
new file mode 100644
index 0000000..c60a02d
--- /dev/null
+++ b/shared/logger/node_modules/@sentry/browser/esm/transports/offline.js
@@ -0,0 +1,133 @@
+import { makeOfflineTransport } from '@sentry/core';
+import { serializeEnvelope, parseEnvelope } from '@sentry/utils';
+
+// 'Store', 'promisifyRequest' and 'createStore' were originally copied from the 'idb-keyval' package before being
+// modified and simplified: https://github.com/jakearchibald/idb-keyval
+//
+// At commit: 0420a704fd6cbb4225429c536b1f61112d012fca
+// Original licence:
+
+// Copyright 2016, Jake Archibald
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+function promisifyRequest(request) {
+ return new Promise((resolve, reject) => {
+ // @ts-ignore - file size hacks
+ request.oncomplete = request.onsuccess = () => resolve(request.result);
+ // @ts-ignore - file size hacks
+ request.onabort = request.onerror = () => reject(request.error);
+ });
+}
+
+/** Create or open an IndexedDb store */
+function createStore(dbName, storeName) {
+ const request = indexedDB.open(dbName);
+ request.onupgradeneeded = () => request.result.createObjectStore(storeName);
+ const dbp = promisifyRequest(request);
+
+ return callback => dbp.then(db => callback(db.transaction(storeName, 'readwrite').objectStore(storeName)));
+}
+
+function keys(store) {
+ return promisifyRequest(store.getAllKeys() );
+}
+
+/** Insert into the store */
+function insert(store, value, maxQueueSize) {
+ return store(store => {
+ return keys(store).then(keys => {
+ if (keys.length >= maxQueueSize) {
+ return;
+ }
+
+ // We insert with an incremented key so that the entries are popped in order
+ store.put(value, Math.max(...keys, 0) + 1);
+ return promisifyRequest(store.transaction);
+ });
+ });
+}
+
+/** Pop the oldest value from the store */
+function pop(store) {
+ return store(store => {
+ return keys(store).then(keys => {
+ if (keys.length === 0) {
+ return undefined;
+ }
+
+ return promisifyRequest(store.get(keys[0])).then(value => {
+ store.delete(keys[0]);
+ return promisifyRequest(store.transaction).then(() => value);
+ });
+ });
+ });
+}
+
+function createIndexedDbStore(options) {
+ let store;
+
+ // Lazily create the store only when it's needed
+ function getStore() {
+ if (store == undefined) {
+ store = createStore(options.dbName || 'sentry-offline', options.storeName || 'queue');
+ }
+
+ return store;
+ }
+
+ return {
+ insert: async (env) => {
+ try {
+ const serialized = await serializeEnvelope(env, options.textEncoder);
+ await insert(getStore(), serialized, options.maxQueueSize || 30);
+ } catch (_) {
+ //
+ }
+ },
+ pop: async () => {
+ try {
+ const deserialized = await pop(getStore());
+ if (deserialized) {
+ return parseEnvelope(
+ deserialized,
+ options.textEncoder || new TextEncoder(),
+ options.textDecoder || new TextDecoder(),
+ );
+ }
+ } catch (_) {
+ //
+ }
+
+ return undefined;
+ },
+ };
+}
+
+function makeIndexedDbOfflineTransport(
+ createTransport,
+) {
+ return options => createTransport({ ...options, createStore: createIndexedDbStore });
+}
+
+/**
+ * Creates a transport that uses IndexedDb to store events when offline.
+ */
+function makeBrowserOfflineTransport(
+ createTransport,
+) {
+ return makeIndexedDbOfflineTransport(makeOfflineTransport(createTransport));
+}
+
+export { createStore, insert, makeBrowserOfflineTransport, pop };
+//# sourceMappingURL=offline.js.map
diff --git a/shared/logger/node_modules/@sentry/browser/esm/transports/utils.js b/shared/logger/node_modules/@sentry/browser/esm/transports/utils.js
new file mode 100644
index 0000000..bc50f0c
--- /dev/null
+++ b/shared/logger/node_modules/@sentry/browser/esm/transports/utils.js
@@ -0,0 +1,85 @@
+import { isNativeFetch, logger } from '@sentry/utils';
+import { WINDOW } from '../helpers.js';
+
+let cachedFetchImpl = undefined;
+
+/**
+ * A special usecase for incorrectly wrapped Fetch APIs in conjunction with ad-blockers.
+ * Whenever someone wraps the Fetch API and returns the wrong promise chain,
+ * this chain becomes orphaned and there is no possible way to capture it's rejections
+ * other than allowing it bubble up to this very handler. eg.
+ *
+ * const f = window.fetch;
+ * window.fetch = function () {
+ * const p = f.apply(this, arguments);
+ *
+ * p.then(function() {
+ * console.log('hi.');
+ * });
+ *
+ * return p;
+ * }
+ *
+ * `p.then(function () { ... })` is producing a completely separate promise chain,
+ * however, what's returned is `p` - the result of original `fetch` call.
+ *
+ * This mean, that whenever we use the Fetch API to send our own requests, _and_
+ * some ad-blocker blocks it, this orphaned chain will _always_ reject,
+ * effectively causing another event to be captured.
+ * This makes a whole process become an infinite loop, which we need to somehow
+ * deal with, and break it in one way or another.
+ *
+ * To deal with this issue, we are making sure that we _always_ use the real
+ * browser Fetch API, instead of relying on what `window.fetch` exposes.
+ * The only downside to this would be missing our own requests as breadcrumbs,
+ * but because we are already not doing this, it should be just fine.
+ *
+ * Possible failed fetch error messages per-browser:
+ *
+ * Chrome: Failed to fetch
+ * Edge: Failed to Fetch
+ * Firefox: NetworkError when attempting to fetch resource
+ * Safari: resource blocked by content blocker
+ */
+function getNativeFetchImplementation() {
+ if (cachedFetchImpl) {
+ return cachedFetchImpl;
+ }
+
+ /* eslint-disable @typescript-eslint/unbound-method */
+
+ // Fast path to avoid DOM I/O
+ if (isNativeFetch(WINDOW.fetch)) {
+ return (cachedFetchImpl = WINDOW.fetch.bind(WINDOW));
+ }
+
+ const document = WINDOW.document;
+ let fetchImpl = WINDOW.fetch;
+ // eslint-disable-next-line deprecation/deprecation
+ if (document && typeof document.createElement === 'function') {
+ try {
+ const sandbox = document.createElement('iframe');
+ sandbox.hidden = true;
+ document.head.appendChild(sandbox);
+ const contentWindow = sandbox.contentWindow;
+ if (contentWindow && contentWindow.fetch) {
+ fetchImpl = contentWindow.fetch;
+ }
+ document.head.removeChild(sandbox);
+ } catch (e) {
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
+ logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', e);
+ }
+ }
+
+ return (cachedFetchImpl = fetchImpl.bind(WINDOW));
+ /* eslint-enable @typescript-eslint/unbound-method */
+}
+
+/** Clears cached fetch impl */
+function clearCachedFetchImplementation() {
+ cachedFetchImpl = undefined;
+}
+
+export { clearCachedFetchImplementation, getNativeFetchImplementation };
+//# sourceMappingURL=utils.js.map
diff --git a/shared/logger/node_modules/@sentry/browser/esm/transports/xhr.js b/shared/logger/node_modules/@sentry/browser/esm/transports/xhr.js
new file mode 100644
index 0000000..4cb34a0
--- /dev/null
+++ b/shared/logger/node_modules/@sentry/browser/esm/transports/xhr.js
@@ -0,0 +1,52 @@
+import { createTransport } from '@sentry/core';
+import { SyncPromise } from '@sentry/utils';
+
+/**
+ * The DONE ready state for XmlHttpRequest
+ *
+ * Defining it here as a constant b/c XMLHttpRequest.DONE is not always defined
+ * (e.g. during testing, it is `undefined`)
+ *
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState}
+ */
+const XHR_READYSTATE_DONE = 4;
+
+/**
+ * Creates a Transport that uses the XMLHttpRequest API to send events to Sentry.
+ */
+function makeXHRTransport(options) {
+ function makeRequest(request) {
+ return new SyncPromise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+
+ xhr.onerror = reject;
+
+ xhr.onreadystatechange = () => {
+ if (xhr.readyState === XHR_READYSTATE_DONE) {
+ resolve({
+ statusCode: xhr.status,
+ headers: {
+ 'x-sentry-rate-limits': xhr.getResponseHeader('X-Sentry-Rate-Limits'),
+ 'retry-after': xhr.getResponseHeader('Retry-After'),
+ },
+ });
+ }
+ };
+
+ xhr.open('POST', options.url);
+
+ for (const header in options.headers) {
+ if (Object.prototype.hasOwnProperty.call(options.headers, header)) {
+ xhr.setRequestHeader(header, options.headers[header]);
+ }
+ }
+
+ xhr.send(request.body);
+ });
+ }
+
+ return createTransport(options, makeRequest);
+}
+
+export { makeXHRTransport };
+//# sourceMappingURL=xhr.js.map