@sentry/browser 11.0.0-beta.2 → 11.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/npm/cjs/dev/index.js +1 -1
- package/build/npm/cjs/dev/integrations/breadcrumbs.js +0 -32
- package/build/npm/cjs/dev/integrations/breadcrumbs.js.map +1 -1
- package/build/npm/cjs/dev/integrations/contextlines.js +1 -1
- package/build/npm/cjs/dev/integrations/contextlines.js.map +1 -1
- package/build/npm/cjs/dev/integrations/httpclient.js +3 -9
- package/build/npm/cjs/dev/integrations/httpclient.js.map +1 -1
- package/build/npm/cjs/dev/integrations/httpcontext.js +2 -1
- package/build/npm/cjs/dev/integrations/httpcontext.js.map +1 -1
- package/build/npm/cjs/dev/integrations/webVitals.js +15 -4
- package/build/npm/cjs/dev/integrations/webVitals.js.map +1 -1
- package/build/npm/cjs/dev/sdk.js +1 -0
- package/build/npm/cjs/dev/sdk.js.map +1 -1
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js +51 -7
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/cjs/prod/index.js +1 -1
- package/build/npm/cjs/prod/integrations/breadcrumbs.js +0 -32
- package/build/npm/cjs/prod/integrations/breadcrumbs.js.map +1 -1
- package/build/npm/cjs/prod/integrations/contextlines.js +1 -1
- package/build/npm/cjs/prod/integrations/contextlines.js.map +1 -1
- package/build/npm/cjs/prod/integrations/httpclient.js +3 -9
- package/build/npm/cjs/prod/integrations/httpclient.js.map +1 -1
- package/build/npm/cjs/prod/integrations/httpcontext.js +2 -1
- package/build/npm/cjs/prod/integrations/httpcontext.js.map +1 -1
- package/build/npm/cjs/prod/integrations/webVitals.js +15 -4
- package/build/npm/cjs/prod/integrations/webVitals.js.map +1 -1
- package/build/npm/cjs/prod/sdk.js +1 -0
- package/build/npm/cjs/prod/sdk.js.map +1 -1
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js +51 -7
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/dev/index.js +1 -1
- package/build/npm/esm/dev/integrations/breadcrumbs.js +1 -33
- package/build/npm/esm/dev/integrations/breadcrumbs.js.map +1 -1
- package/build/npm/esm/dev/integrations/contextlines.js +1 -1
- package/build/npm/esm/dev/integrations/contextlines.js.map +1 -1
- package/build/npm/esm/dev/integrations/httpclient.js +3 -9
- package/build/npm/esm/dev/integrations/httpclient.js.map +1 -1
- package/build/npm/esm/dev/integrations/httpcontext.js +2 -1
- package/build/npm/esm/dev/integrations/httpcontext.js.map +1 -1
- package/build/npm/esm/dev/integrations/webVitals.js +16 -5
- package/build/npm/esm/dev/integrations/webVitals.js.map +1 -1
- package/build/npm/esm/dev/package.json +1 -1
- package/build/npm/esm/dev/sdk.js +2 -1
- package/build/npm/esm/dev/sdk.js.map +1 -1
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js +53 -9
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/prod/index.js +1 -1
- package/build/npm/esm/prod/integrations/breadcrumbs.js +1 -33
- package/build/npm/esm/prod/integrations/breadcrumbs.js.map +1 -1
- package/build/npm/esm/prod/integrations/contextlines.js +1 -1
- package/build/npm/esm/prod/integrations/contextlines.js.map +1 -1
- package/build/npm/esm/prod/integrations/httpclient.js +3 -9
- package/build/npm/esm/prod/integrations/httpclient.js.map +1 -1
- package/build/npm/esm/prod/integrations/httpcontext.js +2 -1
- package/build/npm/esm/prod/integrations/httpcontext.js.map +1 -1
- package/build/npm/esm/prod/integrations/webVitals.js +16 -5
- package/build/npm/esm/prod/integrations/webVitals.js.map +1 -1
- package/build/npm/esm/prod/package.json +1 -1
- package/build/npm/esm/prod/sdk.js +2 -1
- package/build/npm/esm/prod/sdk.js.map +1 -1
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js +53 -9
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/types/exports.d.ts +2 -2
- package/build/npm/types/exports.d.ts.map +1 -1
- package/build/npm/types/integrations/breadcrumbs.d.ts +0 -1
- package/build/npm/types/integrations/breadcrumbs.d.ts.map +1 -1
- package/build/npm/types/integrations/contextlines.d.ts +1 -1
- package/build/npm/types/integrations/contextlines.d.ts.map +1 -1
- package/build/npm/types/integrations/httpcontext.d.ts.map +1 -1
- package/build/npm/types/integrations/webVitals.d.ts +35 -0
- package/build/npm/types/integrations/webVitals.d.ts.map +1 -1
- package/build/npm/types/sdk.d.ts.map +1 -1
- package/build/npm/types/tracing/browserTracingIntegration.d.ts +20 -0
- package/build/npm/types/tracing/browserTracingIntegration.d.ts.map +1 -1
- package/build/npm/types/tracing/linkedTraces.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpclient.js","sources":["../../../../../src/integrations/httpclient.ts"],"sourcesContent":["import type { Client, Event as SentryEvent, IntegrationFn } from '@sentry/core';\nimport {\n _INTERNAL_filterCookies,\n _INTERNAL_filterKeyValueData,\n addExceptionMechanism,\n addFetchInstrumentationHandler,\n captureEvent,\n debug,\n defineIntegration,\n getClient,\n GLOBAL_OBJ,\n isSentryRequestUrl,\n} from '@sentry/core';\nimport type { SentryWrappedXMLHttpRequest } from '@sentry/browser-utils';\nimport { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { DEBUG_BUILD } from '../debug-build';\n\nexport type HttpStatusCodeRange = [number, number] | number;\nexport type HttpRequestTarget = string | RegExp;\n\nconst INTEGRATION_NAME = 'HttpClient' as const;\n\ninterface HttpClientOptions {\n /**\n * HTTP status codes that should be considered failed.\n * This array can contain tuples of `[begin, end]` (both inclusive),\n * single status codes, or a combinations of both\n *\n * Example: [[500, 505], 507]\n * Default: [[500, 599]]\n */\n failedRequestStatusCodes: HttpStatusCodeRange[];\n\n /**\n * Targets to track for failed requests.\n * This array can contain strings or regular expressions.\n *\n * Example: ['http://localhost', /api\\/.*\\/]\n * Default: [/.*\\/]\n */\n failedRequestTargets: HttpRequestTarget[];\n}\n\nconst _httpClientIntegration = ((options: Partial<HttpClientOptions> = {}) => {\n const _options: HttpClientOptions = {\n failedRequestStatusCodes: [[500, 599]],\n failedRequestTargets: [/.*/],\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n setup(client): void {\n _wrapFetch(client, _options);\n _wrapXHR(client, _options);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Create events for failed client side HTTP requests.\n */\nexport const httpClientIntegration = defineIntegration(_httpClientIntegration);\n\n/**\n * Interceptor function for fetch requests\n *\n * @param requestInfo The Fetch API request info\n * @param response The Fetch API response\n * @param requestInit The request init object\n */\nfunction _fetchResponseHandler(\n options: HttpClientOptions,\n requestInfo: RequestInfo,\n response: Response,\n requestInit?: RequestInit,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, response.status, response.url)) {\n const request = _getRequest(requestInfo, requestInit);\n\n let requestHeaders, responseHeaders, requestCookies, responseCookies;\n\n const dc = _getDataCollectionSettings();\n\n if (dc.requestHeaders !== false) {\n requestHeaders = _INTERNAL_filterKeyValueData(_extractFetchHeaders(request.headers), dc.requestHeaders);\n }\n if (dc.responseHeaders !== false) {\n responseHeaders = _INTERNAL_filterKeyValueData(_extractFetchHeaders(response.headers), dc.responseHeaders);\n }\n if (dc.cookies !== false) {\n const reqCookieStr = request.headers.get('Cookie') || undefined;\n if (reqCookieStr) {\n const filtered = _INTERNAL_filterCookies(reqCookieStr, dc.cookies);\n if (typeof filtered === 'object') {\n requestCookies = filtered;\n }\n }\n const resCookieStr = response.headers.get('Set-Cookie') || undefined;\n if (resCookieStr) {\n const filtered = _INTERNAL_filterCookies(resCookieStr, dc.cookies);\n if (typeof filtered === 'object') {\n responseCookies = filtered;\n }\n }\n }\n\n const event = _createEvent({\n url: request.url,\n method: request.method,\n status: response.status,\n requestHeaders,\n responseHeaders,\n requestCookies,\n responseCookies,\n error,\n type: 'fetch',\n });\n\n captureEvent(event);\n }\n}\n\n/**\n * Interceptor function for XHR requests\n *\n * @param xhr The XHR request\n * @param method The HTTP method\n * @param headers The HTTP headers\n */\nfunction _xhrResponseHandler(\n options: HttpClientOptions,\n xhr: XMLHttpRequest,\n method: string,\n headers: Record<string, string>,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, xhr.status, xhr.responseURL)) {\n let requestHeaders, responseCookies, responseHeaders;\n\n const dc = _getDataCollectionSettings();\n\n if (dc.cookies !== false) {\n try {\n const cookieString = xhr.getResponseHeader('Set-Cookie') || xhr.getResponseHeader('set-cookie') || undefined;\n if (cookieString) {\n const filtered = _INTERNAL_filterCookies(cookieString, dc.cookies);\n if (typeof filtered === 'object') {\n responseCookies = filtered;\n }\n }\n } catch {\n // ignore it if parsing fails\n }\n }\n\n if (dc.responseHeaders !== false) {\n try {\n responseHeaders = _INTERNAL_filterKeyValueData(_getXHRResponseHeaders(xhr), dc.responseHeaders);\n } catch {\n // ignore it if parsing fails\n }\n }\n\n if (dc.requestHeaders !== false) {\n requestHeaders = _INTERNAL_filterKeyValueData(headers, dc.requestHeaders);\n }\n\n const event = _createEvent({\n url: xhr.responseURL,\n method,\n status: xhr.status,\n requestHeaders,\n // Can't access request cookies from XHR\n responseHeaders,\n responseCookies,\n error,\n type: 'xhr',\n });\n\n captureEvent(event);\n }\n}\n\n/**\n * Extracts response size from `Content-Length` header when possible\n *\n * @param headers\n * @returns The response size in bytes or undefined\n */\nfunction _getResponseSizeFromHeaders(headers?: Record<string, string>): number | undefined {\n if (headers) {\n const contentLength = headers['Content-Length'] || headers['content-length'];\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n }\n }\n\n return undefined;\n}\n\n/**\n * Extracts the headers as an object from the given Fetch API request or response object\n *\n * @param headers The headers to extract\n * @returns The extracted headers as an object\n */\nfunction _extractFetchHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n\n headers.forEach((value, key) => {\n result[key] = value;\n });\n\n return result;\n}\n\n/**\n * Extracts the response headers as an object from the given XHR object\n *\n * @param xhr The XHR object to extract the response headers from\n * @returns The response headers as an object\n */\nfunction _getXHRResponseHeaders(xhr: XMLHttpRequest): Record<string, string> {\n const headers = xhr.getAllResponseHeaders();\n\n if (!headers) {\n return {};\n }\n\n return headers.split('\\r\\n').reduce((acc: Record<string, string>, line: string) => {\n const [key, value] = line.split(': ');\n if (key && value) {\n acc[key] = value;\n }\n return acc;\n }, {});\n}\n\n/**\n * Checks if the given target url is in the given list of targets\n *\n * @param target The target url to check\n * @returns true if the target url is in the given list of targets, false otherwise\n */\nfunction _isInGivenRequestTargets(\n failedRequestTargets: HttpClientOptions['failedRequestTargets'],\n target: string,\n): boolean {\n return failedRequestTargets.some((givenRequestTarget: HttpRequestTarget) => {\n if (typeof givenRequestTarget === 'string') {\n return target.includes(givenRequestTarget);\n }\n\n return givenRequestTarget.test(target);\n });\n}\n\n/**\n * Checks if the given status code is in the given range\n *\n * @param status The status code to check\n * @returns true if the status code is in the given range, false otherwise\n */\nfunction _isInGivenStatusRanges(\n failedRequestStatusCodes: HttpClientOptions['failedRequestStatusCodes'],\n status: number,\n): boolean {\n return failedRequestStatusCodes.some((range: HttpStatusCodeRange) => {\n if (typeof range === 'number') {\n return range === status;\n }\n\n return status >= range[0] && status <= range[1];\n });\n}\n\n/**\n * Wraps `fetch` function to capture request and response data\n */\nfunction _wrapFetch(client: Client, options: HttpClientOptions): void {\n addFetchInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { response, args, error, virtualError } = handlerData;\n const [requestInfo, requestInit] = args as [RequestInfo, RequestInit | undefined];\n\n if (!response) {\n return;\n }\n\n _fetchResponseHandler(options, requestInfo, response as Response, requestInit, error || virtualError);\n });\n}\n\n/**\n * Wraps XMLHttpRequest to capture request and response data\n */\nfunction _wrapXHR(client: Client, options: HttpClientOptions): void {\n if (!('XMLHttpRequest' in GLOBAL_OBJ)) {\n return;\n }\n\n addXhrInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { error, virtualError } = handlerData;\n\n const xhr = handlerData.xhr as SentryWrappedXMLHttpRequest & XMLHttpRequest;\n\n const sentryXhrData = xhr[SENTRY_XHR_DATA_KEY];\n\n if (!sentryXhrData) {\n return;\n }\n\n const { method, request_headers: headers } = sentryXhrData;\n\n try {\n _xhrResponseHandler(options, xhr, method, headers, error || virtualError);\n } catch (e) {\n DEBUG_BUILD && debug.warn('Error while extracting response event form XHR response', e);\n }\n });\n}\n\n/**\n * Checks whether to capture given response as an event\n *\n * @param status response status code\n * @param url response url\n */\nfunction _shouldCaptureResponse(options: HttpClientOptions, status: number, url: string): boolean {\n return (\n _isInGivenStatusRanges(options.failedRequestStatusCodes, status) &&\n _isInGivenRequestTargets(options.failedRequestTargets, url) &&\n !isSentryRequestUrl(url, getClient())\n );\n}\n\n/**\n * Creates a synthetic Sentry event from given response data\n *\n * @param data response data\n * @returns event\n */\nfunction _createEvent(data: {\n url: string;\n method: string;\n status: number;\n type: 'fetch' | 'xhr';\n responseHeaders?: Record<string, string>;\n responseCookies?: Record<string, string>;\n requestHeaders?: Record<string, string>;\n requestCookies?: Record<string, string>;\n error?: unknown;\n}): SentryEvent {\n const client = getClient();\n const virtualStackTrace = client && data.error && data.error instanceof Error ? data.error.stack : undefined;\n // Remove the first frame from the stack as it's the HttpClient call\n const stack = virtualStackTrace && client ? client.getOptions().stackParser(virtualStackTrace, 0, 1) : undefined;\n const message = `HTTP Client Error with status code: ${data.status}`;\n\n const event: SentryEvent = {\n message,\n exception: {\n values: [\n {\n type: 'Error',\n value: message,\n stacktrace: stack ? { frames: stack } : undefined,\n },\n ],\n },\n request: {\n url: data.url,\n method: data.method,\n headers: data.requestHeaders,\n cookies: data.requestCookies,\n },\n contexts: {\n response: {\n status_code: data.status,\n headers: data.responseHeaders,\n cookies: data.responseCookies,\n body_size: _getResponseSizeFromHeaders(data.responseHeaders),\n },\n },\n };\n\n addExceptionMechanism(event, {\n type: `auto.http.client.${data.type}`,\n handled: false,\n });\n\n return event;\n}\n\nfunction _getRequest(requestInfo: RequestInfo, requestInit?: RequestInit): Request {\n if (!requestInit && requestInfo instanceof Request) {\n return requestInfo;\n }\n\n // If both are set, we try to construct a new Request with the given arguments\n // However, if e.g. the original request has a `body`, this will throw an error because it was already accessed\n // In this case, as a fallback, we just use the original request - using both is rather an edge case\n if (requestInfo instanceof Request && requestInfo.bodyUsed) {\n return requestInfo;\n }\n\n return new Request(requestInfo, requestInit);\n}\n\nfunction _getDataCollectionSettings() {\n const client = getClient();\n if (!client) {\n return { cookies: false, requestHeaders: false, responseHeaders: false };\n }\n\n const { cookies, httpHeaders } = client.getDataCollectionOptions();\n return { cookies, requestHeaders: httpHeaders.request, responseHeaders: httpHeaders.response };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"httpclient.js","sources":["../../../../../src/integrations/httpclient.ts"],"sourcesContent":["import type { Client, Event as SentryEvent, IntegrationFn } from '@sentry/core';\nimport {\n _INTERNAL_filterCookies,\n _INTERNAL_filterKeyValueData,\n addExceptionMechanism,\n addFetchInstrumentationHandler,\n captureEvent,\n debug,\n defineIntegration,\n getClient,\n GLOBAL_OBJ,\n isSentryRequestUrl,\n} from '@sentry/core';\nimport type { SentryWrappedXMLHttpRequest } from '@sentry/browser-utils';\nimport { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { DEBUG_BUILD } from '../debug-build';\n\nexport type HttpStatusCodeRange = [number, number] | number;\nexport type HttpRequestTarget = string | RegExp;\n\nconst INTEGRATION_NAME = 'HttpClient' as const;\n\ninterface HttpClientOptions {\n /**\n * HTTP status codes that should be considered failed.\n * This array can contain tuples of `[begin, end]` (both inclusive),\n * single status codes, or a combinations of both\n *\n * Example: [[500, 505], 507]\n * Default: [[500, 599]]\n */\n failedRequestStatusCodes: HttpStatusCodeRange[];\n\n /**\n * Targets to track for failed requests.\n * This array can contain strings or regular expressions.\n *\n * Example: ['http://localhost', /api\\/.*\\/]\n * Default: [/.*\\/]\n */\n failedRequestTargets: HttpRequestTarget[];\n}\n\nconst _httpClientIntegration = ((options: Partial<HttpClientOptions> = {}) => {\n const _options: HttpClientOptions = {\n failedRequestStatusCodes: [[500, 599]],\n failedRequestTargets: [/.*/],\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n setup(client): void {\n _wrapFetch(client, _options);\n _wrapXHR(client, _options);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Create events for failed client side HTTP requests.\n */\nexport const httpClientIntegration = defineIntegration(_httpClientIntegration);\n\n/**\n * Interceptor function for fetch requests\n *\n * @param requestInfo The Fetch API request info\n * @param response The Fetch API response\n * @param requestInit The request init object\n */\nfunction _fetchResponseHandler(\n options: HttpClientOptions,\n requestInfo: RequestInfo,\n response: Response,\n requestInit?: RequestInit,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, response.status, response.url)) {\n const request = _getRequest(requestInfo, requestInit);\n\n let requestHeaders, responseHeaders, requestCookies, responseCookies;\n\n const dc = _getDataCollectionSettings();\n\n if (dc.requestHeaders !== false) {\n requestHeaders = _INTERNAL_filterKeyValueData(_extractFetchHeaders(request.headers), dc.requestHeaders);\n }\n if (dc.responseHeaders !== false) {\n responseHeaders = _INTERNAL_filterKeyValueData(_extractFetchHeaders(response.headers), dc.responseHeaders);\n }\n if (dc.cookies !== false) {\n const reqCookieStr = request.headers.get('Cookie') || undefined;\n if (reqCookieStr) {\n const filtered = _INTERNAL_filterCookies(reqCookieStr, dc.cookies);\n requestCookies = typeof filtered === 'string' ? { cookie: filtered } : filtered;\n }\n const resCookieStr = response.headers.get('Set-Cookie') || undefined;\n if (resCookieStr) {\n const filtered = _INTERNAL_filterCookies(resCookieStr, dc.cookies);\n responseCookies = typeof filtered === 'string' ? { 'set-cookie': filtered } : filtered;\n }\n }\n\n const event = _createEvent({\n url: request.url,\n method: request.method,\n status: response.status,\n requestHeaders,\n responseHeaders,\n requestCookies,\n responseCookies,\n error,\n type: 'fetch',\n });\n\n captureEvent(event);\n }\n}\n\n/**\n * Interceptor function for XHR requests\n *\n * @param xhr The XHR request\n * @param method The HTTP method\n * @param headers The HTTP headers\n */\nfunction _xhrResponseHandler(\n options: HttpClientOptions,\n xhr: XMLHttpRequest,\n method: string,\n headers: Record<string, string>,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, xhr.status, xhr.responseURL)) {\n let requestHeaders, responseCookies, responseHeaders;\n\n const dc = _getDataCollectionSettings();\n\n if (dc.cookies !== false) {\n try {\n const cookieString = xhr.getResponseHeader('Set-Cookie') || xhr.getResponseHeader('set-cookie') || undefined;\n if (cookieString) {\n const filtered = _INTERNAL_filterCookies(cookieString, dc.cookies);\n responseCookies = typeof filtered === 'string' ? { 'set-cookie': filtered } : filtered;\n }\n } catch {\n // ignore it if parsing fails\n }\n }\n\n if (dc.responseHeaders !== false) {\n try {\n responseHeaders = _INTERNAL_filterKeyValueData(_getXHRResponseHeaders(xhr), dc.responseHeaders);\n } catch {\n // ignore it if parsing fails\n }\n }\n\n if (dc.requestHeaders !== false) {\n requestHeaders = _INTERNAL_filterKeyValueData(headers, dc.requestHeaders);\n }\n\n const event = _createEvent({\n url: xhr.responseURL,\n method,\n status: xhr.status,\n requestHeaders,\n // Can't access request cookies from XHR\n responseHeaders,\n responseCookies,\n error,\n type: 'xhr',\n });\n\n captureEvent(event);\n }\n}\n\n/**\n * Extracts response size from `Content-Length` header when possible\n *\n * @param headers\n * @returns The response size in bytes or undefined\n */\nfunction _getResponseSizeFromHeaders(headers?: Record<string, string>): number | undefined {\n if (headers) {\n const contentLength = headers['Content-Length'] || headers['content-length'];\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n }\n }\n\n return undefined;\n}\n\n/**\n * Extracts the headers as an object from the given Fetch API request or response object\n *\n * @param headers The headers to extract\n * @returns The extracted headers as an object\n */\nfunction _extractFetchHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n\n headers.forEach((value, key) => {\n result[key] = value;\n });\n\n return result;\n}\n\n/**\n * Extracts the response headers as an object from the given XHR object\n *\n * @param xhr The XHR object to extract the response headers from\n * @returns The response headers as an object\n */\nfunction _getXHRResponseHeaders(xhr: XMLHttpRequest): Record<string, string> {\n const headers = xhr.getAllResponseHeaders();\n\n if (!headers) {\n return {};\n }\n\n return headers.split('\\r\\n').reduce((acc: Record<string, string>, line: string) => {\n const [key, value] = line.split(': ');\n if (key && value) {\n acc[key] = value;\n }\n return acc;\n }, {});\n}\n\n/**\n * Checks if the given target url is in the given list of targets\n *\n * @param target The target url to check\n * @returns true if the target url is in the given list of targets, false otherwise\n */\nfunction _isInGivenRequestTargets(\n failedRequestTargets: HttpClientOptions['failedRequestTargets'],\n target: string,\n): boolean {\n return failedRequestTargets.some((givenRequestTarget: HttpRequestTarget) => {\n if (typeof givenRequestTarget === 'string') {\n return target.includes(givenRequestTarget);\n }\n\n return givenRequestTarget.test(target);\n });\n}\n\n/**\n * Checks if the given status code is in the given range\n *\n * @param status The status code to check\n * @returns true if the status code is in the given range, false otherwise\n */\nfunction _isInGivenStatusRanges(\n failedRequestStatusCodes: HttpClientOptions['failedRequestStatusCodes'],\n status: number,\n): boolean {\n return failedRequestStatusCodes.some((range: HttpStatusCodeRange) => {\n if (typeof range === 'number') {\n return range === status;\n }\n\n return status >= range[0] && status <= range[1];\n });\n}\n\n/**\n * Wraps `fetch` function to capture request and response data\n */\nfunction _wrapFetch(client: Client, options: HttpClientOptions): void {\n addFetchInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { response, args, error, virtualError } = handlerData;\n const [requestInfo, requestInit] = args as [RequestInfo, RequestInit | undefined];\n\n if (!response) {\n return;\n }\n\n _fetchResponseHandler(options, requestInfo, response as Response, requestInit, error || virtualError);\n });\n}\n\n/**\n * Wraps XMLHttpRequest to capture request and response data\n */\nfunction _wrapXHR(client: Client, options: HttpClientOptions): void {\n if (!('XMLHttpRequest' in GLOBAL_OBJ)) {\n return;\n }\n\n addXhrInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { error, virtualError } = handlerData;\n\n const xhr = handlerData.xhr as SentryWrappedXMLHttpRequest & XMLHttpRequest;\n\n const sentryXhrData = xhr[SENTRY_XHR_DATA_KEY];\n\n if (!sentryXhrData) {\n return;\n }\n\n const { method, request_headers: headers } = sentryXhrData;\n\n try {\n _xhrResponseHandler(options, xhr, method, headers, error || virtualError);\n } catch (e) {\n DEBUG_BUILD && debug.warn('Error while extracting response event form XHR response', e);\n }\n });\n}\n\n/**\n * Checks whether to capture given response as an event\n *\n * @param status response status code\n * @param url response url\n */\nfunction _shouldCaptureResponse(options: HttpClientOptions, status: number, url: string): boolean {\n return (\n _isInGivenStatusRanges(options.failedRequestStatusCodes, status) &&\n _isInGivenRequestTargets(options.failedRequestTargets, url) &&\n !isSentryRequestUrl(url, getClient())\n );\n}\n\n/**\n * Creates a synthetic Sentry event from given response data\n *\n * @param data response data\n * @returns event\n */\nfunction _createEvent(data: {\n url: string;\n method: string;\n status: number;\n type: 'fetch' | 'xhr';\n responseHeaders?: Record<string, string>;\n responseCookies?: Record<string, string>;\n requestHeaders?: Record<string, string>;\n requestCookies?: Record<string, string>;\n error?: unknown;\n}): SentryEvent {\n const client = getClient();\n const virtualStackTrace = client && data.error && data.error instanceof Error ? data.error.stack : undefined;\n // Remove the first frame from the stack as it's the HttpClient call\n const stack = virtualStackTrace && client ? client.getOptions().stackParser(virtualStackTrace, 0, 1) : undefined;\n const message = `HTTP Client Error with status code: ${data.status}`;\n\n const event: SentryEvent = {\n message,\n exception: {\n values: [\n {\n type: 'Error',\n value: message,\n stacktrace: stack ? { frames: stack } : undefined,\n },\n ],\n },\n request: {\n url: data.url,\n method: data.method,\n headers: data.requestHeaders,\n cookies: data.requestCookies,\n },\n contexts: {\n response: {\n status_code: data.status,\n headers: data.responseHeaders,\n cookies: data.responseCookies,\n body_size: _getResponseSizeFromHeaders(data.responseHeaders),\n },\n },\n };\n\n addExceptionMechanism(event, {\n type: `auto.http.client.${data.type}`,\n handled: false,\n });\n\n return event;\n}\n\nfunction _getRequest(requestInfo: RequestInfo, requestInit?: RequestInit): Request {\n if (!requestInit && requestInfo instanceof Request) {\n return requestInfo;\n }\n\n // If both are set, we try to construct a new Request with the given arguments\n // However, if e.g. the original request has a `body`, this will throw an error because it was already accessed\n // In this case, as a fallback, we just use the original request - using both is rather an edge case\n if (requestInfo instanceof Request && requestInfo.bodyUsed) {\n return requestInfo;\n }\n\n return new Request(requestInfo, requestInit);\n}\n\nfunction _getDataCollectionSettings() {\n const client = getClient();\n if (!client) {\n return { cookies: false, requestHeaders: false, responseHeaders: false };\n }\n\n const { cookies, httpHeaders } = client.getDataCollectionOptions();\n return { cookies, requestHeaders: httpHeaders.request, responseHeaders: httpHeaders.response };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,7 @@ const httpContextIntegration = defineIntegration(() => {
|
|
|
32
32
|
reqData.headers,
|
|
33
33
|
client.getDataCollectionOptions().httpHeaders.request
|
|
34
34
|
);
|
|
35
|
+
const referer = headers["Referer"];
|
|
35
36
|
safeSetSpanJSONAttributes(span, {
|
|
36
37
|
// This attribute is used by the "Filter out events from legacy browsers and crawlers" features on the Sentry backend.
|
|
37
38
|
// Therefore, it's set on every span.
|
|
@@ -41,7 +42,7 @@ const httpContextIntegration = defineIntegration(() => {
|
|
|
41
42
|
// Coerce empty string to undefined so the helper's nullish check drops it,
|
|
42
43
|
// rather than writing an empty `url.full` attribute onto the span.
|
|
43
44
|
[URL_FULL]: span.attributes?.[SENTRY_OP] !== "http.client" ? filterCollectedUrl(reqData.url) : void 0,
|
|
44
|
-
[`${HTTP_REQUEST_HEADER_KEY_BASE}.referer`]:
|
|
45
|
+
[`${HTTP_REQUEST_HEADER_KEY_BASE}.referer`]: referer ? [referer] : void 0
|
|
45
46
|
}
|
|
46
47
|
});
|
|
47
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpcontext.js","sources":["../../../../../src/integrations/httpcontext.ts"],"sourcesContent":["import { _INTERNAL_filterKeyValueData, defineIntegration, safeSetSpanJSONAttributes } from '@sentry/core';\nimport { getHttpRequestData, WINDOW } from '../helpers';\nimport { filterCollectedUrl } from '@sentry/core';\nimport { HTTP_REQUEST_HEADER_KEY_BASE, SENTRY_OP, URL_FULL, USER_AGENT_ORIGINAL } from '@sentry/conventions/attributes';\n\n/**\n * Collects information about HTTP request headers and\n * attaches them to the event.\n */\nexport const httpContextIntegration = defineIntegration(() => {\n return {\n name: 'HttpContext' as const,\n preprocessEvent(event, _hint, client) {\n // if none of the information we want exists, don't bother\n if (!WINDOW.navigator && !WINDOW.location && !WINDOW.document) {\n return;\n }\n\n const { url, headers: collectedHeaders } = getHttpRequestData();\n\n // We only filter the headers we collected ourselves, so headers the user set are left alone. Going by key\n // means we also catch these headers when `browserTracingIntegration` already put them on the event.\n const behavior = client.getDataCollectionOptions().httpHeaders.request;\n const userHeaders = Object.entries(event.request?.headers ?? {}).filter(([key]) => !(key in collectedHeaders));\n\n const headers = {\n ..._INTERNAL_filterKeyValueData(collectedHeaders, behavior),\n ...Object.fromEntries(userHeaders),\n };\n\n event.request = {\n // The URL isn't gated by `dataCollection`, same as on the server.\n url,\n ...event.request,\n ...(Object.keys(headers).length > 0 ? { headers } : { headers: undefined }),\n };\n },\n\n processSpan(span, client) {\n // if none of the information we want exists, don't bother\n if (!WINDOW.navigator && !WINDOW.location && !WINDOW.document) {\n return;\n }\n\n const reqData = getHttpRequestData();\n\n // `httpHeadersToSpanAttributes` would also work here, but its cookie and array handling never runs for these\n // two headers and costs every browser bundle ~400B gzip.\n const headers = _INTERNAL_filterKeyValueData(\n reqData.headers,\n client.getDataCollectionOptions().httpHeaders.request,\n );\n\n safeSetSpanJSONAttributes(span, {\n // This attribute is used by the \"Filter out events from legacy browsers and crawlers\" features on the Sentry backend.\n // Therefore, it's set on every span.\n [USER_AGENT_ORIGINAL]: headers['User-Agent'],\n\n // These attributes, we only need on the segment span (analogous to the `request` context for events)\n ...(span.is_segment && {\n // Coerce empty string to undefined so the helper's nullish check drops it,\n // rather than writing an empty `url.full` attribute onto the span.\n [URL_FULL]: span.attributes?.[SENTRY_OP] !== 'http.client' ? filterCollectedUrl(reqData.url) : undefined,\n [`${HTTP_REQUEST_HEADER_KEY_BASE}.referer`]:
|
|
1
|
+
{"version":3,"file":"httpcontext.js","sources":["../../../../../src/integrations/httpcontext.ts"],"sourcesContent":["import { _INTERNAL_filterKeyValueData, defineIntegration, safeSetSpanJSONAttributes } from '@sentry/core';\nimport { getHttpRequestData, WINDOW } from '../helpers';\nimport { filterCollectedUrl } from '@sentry/core';\nimport { HTTP_REQUEST_HEADER_KEY_BASE, SENTRY_OP, URL_FULL, USER_AGENT_ORIGINAL } from '@sentry/conventions/attributes';\n\n/**\n * Collects information about HTTP request headers and\n * attaches them to the event.\n */\nexport const httpContextIntegration = defineIntegration(() => {\n return {\n name: 'HttpContext' as const,\n preprocessEvent(event, _hint, client) {\n // if none of the information we want exists, don't bother\n if (!WINDOW.navigator && !WINDOW.location && !WINDOW.document) {\n return;\n }\n\n const { url, headers: collectedHeaders } = getHttpRequestData();\n\n // We only filter the headers we collected ourselves, so headers the user set are left alone. Going by key\n // means we also catch these headers when `browserTracingIntegration` already put them on the event.\n const behavior = client.getDataCollectionOptions().httpHeaders.request;\n const userHeaders = Object.entries(event.request?.headers ?? {}).filter(([key]) => !(key in collectedHeaders));\n\n const headers = {\n ..._INTERNAL_filterKeyValueData(collectedHeaders, behavior),\n ...Object.fromEntries(userHeaders),\n };\n\n event.request = {\n // The URL isn't gated by `dataCollection`, same as on the server.\n url,\n ...event.request,\n ...(Object.keys(headers).length > 0 ? { headers } : { headers: undefined }),\n };\n },\n\n processSpan(span, client) {\n // if none of the information we want exists, don't bother\n if (!WINDOW.navigator && !WINDOW.location && !WINDOW.document) {\n return;\n }\n\n const reqData = getHttpRequestData();\n\n // `httpHeadersToSpanAttributes` would also work here, but its cookie and array handling never runs for these\n // two headers and costs every browser bundle ~400B gzip.\n const headers = _INTERNAL_filterKeyValueData(\n reqData.headers,\n client.getDataCollectionOptions().httpHeaders.request,\n );\n const referer = headers['Referer'];\n\n safeSetSpanJSONAttributes(span, {\n // This attribute is used by the \"Filter out events from legacy browsers and crawlers\" features on the Sentry backend.\n // Therefore, it's set on every span.\n [USER_AGENT_ORIGINAL]: headers['User-Agent'],\n\n // These attributes, we only need on the segment span (analogous to the `request` context for events)\n ...(span.is_segment && {\n // Coerce empty string to undefined so the helper's nullish check drops it,\n // rather than writing an empty `url.full` attribute onto the span.\n [URL_FULL]: span.attributes?.[SENTRY_OP] !== 'http.client' ? filterCollectedUrl(reqData.url) : undefined,\n [`${HTTP_REQUEST_HEADER_KEY_BASE}.referer`]: referer ? [referer] : undefined,\n }),\n });\n },\n };\n});\n"],"names":[],"mappings":";;;;AASO,MAAM,sBAAA,GAAyB,kBAAkB,MAAM;AAC5D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,aAAA;AAAA,IACN,eAAA,CAAgB,KAAA,EAAO,KAAA,EAAO,MAAA,EAAQ;AAEpC,MAAA,IAAI,CAAC,OAAO,SAAA,IAAa,CAAC,OAAO,QAAA,IAAY,CAAC,OAAO,QAAA,EAAU;AAC7D,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,EAAE,GAAA,EAAK,OAAA,EAAS,gBAAA,KAAqB,kBAAA,EAAmB;AAI9D,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,wBAAA,EAAyB,CAAE,WAAA,CAAY,OAAA;AAC/D,MAAA,MAAM,cAAc,MAAA,CAAO,OAAA,CAAQ,KAAA,CAAM,OAAA,EAAS,WAAW,EAAE,CAAA,CAAE,MAAA,CAAO,CAAC,CAAC,GAAG,CAAA,KAAM,EAAE,OAAO,gBAAA,CAAiB,CAAA;AAE7G,MAAA,MAAM,OAAA,GAAU;AAAA,QACd,GAAG,4BAAA,CAA6B,gBAAA,EAAkB,QAAQ,CAAA;AAAA,QAC1D,GAAG,MAAA,CAAO,WAAA,CAAY,WAAW;AAAA,OACnC;AAEA,MAAA,KAAA,CAAM,OAAA,GAAU;AAAA;AAAA,QAEd,GAAA;AAAA,QACA,GAAG,KAAA,CAAM,OAAA;AAAA,QACT,GAAI,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,MAAA,GAAS,CAAA,GAAI,EAAE,OAAA,EAAQ,GAAI,EAAE,OAAA,EAAS,MAAA;AAAU,OAC3E;AAAA,IACF,CAAA;AAAA,IAEA,WAAA,CAAY,MAAM,MAAA,EAAQ;AAExB,MAAA,IAAI,CAAC,OAAO,SAAA,IAAa,CAAC,OAAO,QAAA,IAAY,CAAC,OAAO,QAAA,EAAU;AAC7D,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,UAAU,kBAAA,EAAmB;AAInC,MAAA,MAAM,OAAA,GAAU,4BAAA;AAAA,QACd,OAAA,CAAQ,OAAA;AAAA,QACR,MAAA,CAAO,wBAAA,EAAyB,CAAE,WAAA,CAAY;AAAA,OAChD;AACA,MAAA,MAAM,OAAA,GAAU,QAAQ,SAAS,CAAA;AAEjC,MAAA,yBAAA,CAA0B,IAAA,EAAM;AAAA;AAAA;AAAA,QAG9B,CAAC,mBAAmB,GAAG,OAAA,CAAQ,YAAY,CAAA;AAAA;AAAA,QAG3C,GAAI,KAAK,UAAA,IAAc;AAAA;AAAA;AAAA,UAGrB,CAAC,QAAQ,GAAG,IAAA,CAAK,UAAA,GAAa,SAAS,CAAA,KAAM,aAAA,GAAgB,kBAAA,CAAmB,OAAA,CAAQ,GAAG,CAAA,GAAI,MAAA;AAAA,UAC/F,CAAC,GAAG,4BAA4B,CAAA,QAAA,CAAU,GAAG,OAAA,GAAU,CAAC,OAAO,CAAA,GAAI;AAAA;AACrE,OACD,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAC;;;;"}
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { defineIntegration, hasSpanStreamingEnabled } from '@sentry/core';
|
|
2
|
-
import { registerInpInteractionListener, startTrackingWebVitals, addWebVitalsToSpan, trackLcpAsSpan, trackClsAsSpan, trackInpAsSpan } from '@sentry/browser-utils';
|
|
2
|
+
import { registerInpInteractionListener, supportsSoftNavigations, enableSoftNavigationReporting, startSoftNavigationCorrelation, enableBfcacheReporting, startTrackingWebVitals, addWebVitalsToSpan, trackLcpAsSpan, trackClsAsSpan, trackInpAsSpan } from '@sentry/browser-utils';
|
|
3
3
|
|
|
4
4
|
const WEB_VITALS_INTEGRATION_NAME = "WebVitals";
|
|
5
5
|
const webVitalsIntegration = defineIntegration((options = {}) => {
|
|
6
|
-
const
|
|
6
|
+
const { ignore = [], softNavigations = true, bfcacheNavigations = true } = options;
|
|
7
|
+
const ignored = new Set(ignore);
|
|
7
8
|
return {
|
|
8
9
|
name: WEB_VITALS_INTEGRATION_NAME,
|
|
9
10
|
setup(client) {
|
|
10
11
|
const spanStreamingEnabled = hasSpanStreamingEnabled(client);
|
|
12
|
+
const reportSoftNavs = softNavigations && spanStreamingEnabled && supportsSoftNavigations();
|
|
13
|
+
const reportBfcache = bfcacheNavigations && spanStreamingEnabled;
|
|
14
|
+
const perNavigation = reportSoftNavs || reportBfcache;
|
|
15
|
+
if (reportSoftNavs) {
|
|
16
|
+
enableSoftNavigationReporting();
|
|
17
|
+
startSoftNavigationCorrelation(client);
|
|
18
|
+
}
|
|
19
|
+
if (reportBfcache) {
|
|
20
|
+
enableBfcacheReporting();
|
|
21
|
+
}
|
|
11
22
|
const trackClsOnPageloadSpan = !spanStreamingEnabled && !ignored.has("cls");
|
|
12
23
|
const trackLcpOnPageloadSpan = !spanStreamingEnabled && !ignored.has("lcp");
|
|
13
24
|
const finalizeWebVitals = startTrackingWebVitals({
|
|
@@ -32,14 +43,14 @@ const webVitalsIntegration = defineIntegration((options = {}) => {
|
|
|
32
43
|
});
|
|
33
44
|
if (spanStreamingEnabled) {
|
|
34
45
|
if (!ignored.has("lcp")) {
|
|
35
|
-
trackLcpAsSpan(client);
|
|
46
|
+
trackLcpAsSpan(client, perNavigation);
|
|
36
47
|
}
|
|
37
48
|
if (!ignored.has("cls")) {
|
|
38
|
-
trackClsAsSpan(client);
|
|
49
|
+
trackClsAsSpan(client, perNavigation);
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
if (!ignored.has("inp")) {
|
|
42
|
-
trackInpAsSpan(client);
|
|
53
|
+
trackInpAsSpan(client, perNavigation);
|
|
43
54
|
}
|
|
44
55
|
},
|
|
45
56
|
afterAllSetup() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webVitals.js","sources":["../../../../../src/integrations/webVitals.ts"],"sourcesContent":["import type { IntegrationFn, Span } from '@sentry/core';\nimport { defineIntegration, hasSpanStreamingEnabled } from '@sentry/core';\nimport {\n addWebVitalsToSpan,\n registerInpInteractionListener,\n startTrackingWebVitals,\n trackClsAsSpan,\n trackInpAsSpan,\n trackLcpAsSpan,\n} from '@sentry/browser-utils';\n\nexport const WEB_VITALS_INTEGRATION_NAME = 'WebVitals' as const;\n\nexport type WebVitalName = 'cls' | 'inp' | 'lcp';\n\nexport interface WebVitalsOptions {\n /**\n * Web vitals to skip.\n */\n ignore?: WebVitalName[];\n}\n\n/**\n * Captures Core Web Vitals (LCP, CLS, INP) and related pageload vitals.\n *\n * `browserTracingIntegration` auto-registers this integration if no\n * `webVitalsIntegration` is already present, so explicit registration is only\n * needed to customize options or to use it without `browserTracingIntegration`.\n */\nexport const webVitalsIntegration = defineIntegration((options: WebVitalsOptions = {}) => {\n const ignored = new Set(
|
|
1
|
+
{"version":3,"file":"webVitals.js","sources":["../../../../../src/integrations/webVitals.ts"],"sourcesContent":["import type { IntegrationFn, Span } from '@sentry/core';\nimport { defineIntegration, hasSpanStreamingEnabled } from '@sentry/core';\nimport {\n addWebVitalsToSpan,\n enableBfcacheReporting,\n enableSoftNavigationReporting,\n registerInpInteractionListener,\n startSoftNavigationCorrelation,\n startTrackingWebVitals,\n supportsSoftNavigations,\n trackClsAsSpan,\n trackInpAsSpan,\n trackLcpAsSpan,\n} from '@sentry/browser-utils';\n\nexport const WEB_VITALS_INTEGRATION_NAME = 'WebVitals' as const;\n\nexport type WebVitalName = 'cls' | 'inp' | 'lcp';\n\nexport interface WebVitalsOptions {\n /**\n * Web vitals to skip.\n */\n ignore?: WebVitalName[];\n\n /**\n * Give each soft navigation its own set of LCP, CLS and INP, detected through the browser's\n * [Soft Navigations API](https://developer.chrome.com/docs/web-platform/soft-navigations-experiment)\n * (Chromium 151+).\n *\n * Each soft navigation's vitals are reported against the navigation span they belong to. This\n * also changes how the initial page load is measured: its vitals are finalized at the first soft\n * navigation rather than accumulating over the page's lifetime.\n *\n * Soft navigations the browser doesn't detect (programmatic navigations, navigations that never\n * paint) report no vitals at all, so coverage is lower than for page loads. Set this to `false`\n * to report a single set of vitals for the whole page lifetime instead.\n *\n * Requires span streaming (`traceLifecycle: 'stream'`, the default), since soft navigation vitals\n * are finalized long after the navigation span they belong to has ended. Ignored in browsers\n * without support for the Soft Navigations API.\n *\n * Default: `true`\n */\n softNavigations?: boolean;\n\n /**\n * Give each back/forward-cache restore its own set of LCP, CLS and INP.\n *\n * A restore is a new page view measured against a document that was never reloaded, so its vitals\n * are reported against the navigation span `browserTracingIntegration` starts for the restore,\n * and tagged `browser.navigation.type: back-forward-cache`. A restore is near-instant by construction, so\n * these are a distinct population from page load vitals and are meant to be read through that\n * attribute rather than pooled with them. Set this to `false` to leave restores unmeasured.\n *\n * Requires span streaming (`traceLifecycle: 'stream'`, the default) and\n * `browserTracingIntegration`, which supplies the navigation span these attach to.\n *\n * Default: `true`\n */\n bfcacheNavigations?: boolean;\n}\n\n/**\n * Captures Core Web Vitals (LCP, CLS, INP) and related pageload vitals.\n *\n * `browserTracingIntegration` auto-registers this integration if no\n * `webVitalsIntegration` is already present, so explicit registration is only\n * needed to customize options or to use it without `browserTracingIntegration`.\n */\nexport const webVitalsIntegration = defineIntegration((options: WebVitalsOptions = {}) => {\n const { ignore = [], softNavigations = true, bfcacheNavigations = true } = options;\n const ignored = new Set(ignore);\n\n return {\n name: WEB_VITALS_INTEGRATION_NAME,\n setup(client) {\n const spanStreamingEnabled = hasSpanStreamingEnabled(client);\n\n // Soft navigation vitals are finalized at the next soft navigation or on pagehide, long after\n // the navigation span they belong to has ended. Only span streaming can still send them.\n const reportSoftNavs = softNavigations && spanStreamingEnabled && supportsSoftNavigations();\n const reportBfcache = bfcacheNavigations && spanStreamingEnabled;\n\n // Both attribute a vital to the page view it was measured on rather than to the page load, so\n // either one puts the trackers on the per-navigation path.\n const perNavigation = reportSoftNavs || reportBfcache;\n\n // These have to run before any web vital observer is instrumented, since web-vitals only\n // reads its options when the observer is set up.\n if (reportSoftNavs) {\n enableSoftNavigationReporting();\n startSoftNavigationCorrelation(client);\n }\n\n if (reportBfcache) {\n enableBfcacheReporting();\n }\n\n // With span streaming enabled, CLS and LCP are tracked as standalone v2 spans (like INP).\n // Otherwise, they're recorded as measurements on the pageload span.\n const trackClsOnPageloadSpan = !spanStreamingEnabled && !ignored.has('cls');\n const trackLcpOnPageloadSpan = !spanStreamingEnabled && !ignored.has('lcp');\n\n const finalizeWebVitals = startTrackingWebVitals({\n trackCls: trackClsOnPageloadSpan,\n trackLcp: trackLcpOnPageloadSpan,\n client,\n });\n\n const pageloadSpans = new WeakSet<Span>();\n\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpans.add(span);\n });\n\n client.on('spanEnd', span => {\n if (!pageloadSpans.delete(span)) {\n return;\n }\n\n finalizeWebVitals();\n addWebVitalsToSpan(span, {\n recordClsOnPageloadSpan: trackClsOnPageloadSpan,\n recordLcpOnPageloadSpan: trackLcpOnPageloadSpan,\n spanStreamingEnabled,\n });\n });\n\n if (spanStreamingEnabled) {\n if (!ignored.has('lcp')) {\n trackLcpAsSpan(client, perNavigation);\n }\n if (!ignored.has('cls')) {\n trackClsAsSpan(client, perNavigation);\n }\n }\n\n // INP is always sent as a streamed web vital span. When span streaming is disabled, INP still\n // streams (it overrides the static trace lifecycle for INP only), see `trackInpAsSpan`.\n if (!ignored.has('inp')) {\n trackInpAsSpan(client, perNavigation);\n }\n },\n afterAllSetup() {\n if (!ignored.has('inp')) {\n registerInpInteractionListener();\n }\n },\n };\n}) satisfies IntegrationFn;\n"],"names":[],"mappings":";;;AAeO,MAAM,2BAAA,GAA8B;AAuDpC,MAAM,oBAAA,GAAuB,iBAAA,CAAkB,CAAC,OAAA,GAA4B,EAAC,KAAM;AACxF,EAAA,MAAM,EAAE,SAAS,EAAC,EAAG,kBAAkB,IAAA,EAAM,kBAAA,GAAqB,MAAK,GAAI,OAAA;AAC3E,EAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,MAAM,CAAA;AAE9B,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,2BAAA;AAAA,IACN,MAAM,MAAA,EAAQ;AACZ,MAAA,MAAM,oBAAA,GAAuB,wBAAwB,MAAM,CAAA;AAI3D,MAAA,MAAM,cAAA,GAAiB,eAAA,IAAmB,oBAAA,IAAwB,uBAAA,EAAwB;AAC1F,MAAA,MAAM,gBAAgB,kBAAA,IAAsB,oBAAA;AAI5C,MAAA,MAAM,gBAAgB,cAAA,IAAkB,aAAA;AAIxC,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,6BAAA,EAA8B;AAC9B,QAAA,8BAAA,CAA+B,MAAM,CAAA;AAAA,MACvC;AAEA,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,sBAAA,EAAuB;AAAA,MACzB;AAIA,MAAA,MAAM,yBAAyB,CAAC,oBAAA,IAAwB,CAAC,OAAA,CAAQ,IAAI,KAAK,CAAA;AAC1E,MAAA,MAAM,yBAAyB,CAAC,oBAAA,IAAwB,CAAC,OAAA,CAAQ,IAAI,KAAK,CAAA;AAE1E,MAAA,MAAM,oBAAoB,sBAAA,CAAuB;AAAA,QAC/C,QAAA,EAAU,sBAAA;AAAA,QACV,QAAA,EAAU,sBAAA;AAAA,QACV;AAAA,OACD,CAAA;AAED,MAAA,MAAM,aAAA,uBAAoB,OAAA,EAAc;AAExC,MAAA,MAAA,CAAO,EAAA,CAAG,0BAA0B,CAAA,IAAA,KAAQ;AAC1C,QAAA,aAAA,CAAc,IAAI,IAAI,CAAA;AAAA,MACxB,CAAC,CAAA;AAED,MAAA,MAAA,CAAO,EAAA,CAAG,WAAW,CAAA,IAAA,KAAQ;AAC3B,QAAA,IAAI,CAAC,aAAA,CAAc,MAAA,CAAO,IAAI,CAAA,EAAG;AAC/B,UAAA;AAAA,QACF;AAEA,QAAA,iBAAA,EAAkB;AAClB,QAAA,kBAAA,CAAmB,IAAA,EAAM;AAAA,UACvB,uBAAA,EAAyB,sBAAA;AAAA,UACzB,uBAAA,EAAyB,sBAAA;AAAA,UACzB;AAAA,SACD,CAAA;AAAA,MACH,CAAC,CAAA;AAED,MAAA,IAAI,oBAAA,EAAsB;AACxB,QAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,UAAA,cAAA,CAAe,QAAQ,aAAa,CAAA;AAAA,QACtC;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,UAAA,cAAA,CAAe,QAAQ,aAAa,CAAA;AAAA,QACtC;AAAA,MACF;AAIA,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,QAAA,cAAA,CAAe,QAAQ,aAAa,CAAA;AAAA,MACtC;AAAA,IACF,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,QAAA,8BAAA,EAA+B;AAAA,MACjC;AAAA,IACF;AAAA,GACF;AACF,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"11.0.0-
|
|
1
|
+
{"type":"module","version":"11.0.0-rc.1","sideEffects":false}
|
package/build/npm/esm/dev/sdk.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { eventFiltersIntegration, functionToStringIntegration, conversationIdIntegration, dedupeIntegration, getIntegrationsToSetup, stackParserFromStackParserOptions, setNormalizeStringifier, initAndBind } from '@sentry/core';
|
|
1
|
+
import { eventFiltersIntegration, functionToStringIntegration, conversationIdIntegration, consoleIntegration, dedupeIntegration, getIntegrationsToSetup, stackParserFromStackParserOptions, setNormalizeStringifier, initAndBind } from '@sentry/core';
|
|
2
2
|
import { BrowserClient } from './client.js';
|
|
3
3
|
import { breadcrumbsIntegration } from './integrations/breadcrumbs.js';
|
|
4
4
|
import { browserApiErrorsIntegration } from './integrations/browserapierrors.js';
|
|
@@ -20,6 +20,7 @@ function getDefaultIntegrations(_options) {
|
|
|
20
20
|
conversationIdIntegration(),
|
|
21
21
|
browserApiErrorsIntegration(),
|
|
22
22
|
breadcrumbsIntegration(),
|
|
23
|
+
consoleIntegration(),
|
|
23
24
|
globalHandlersIntegration(),
|
|
24
25
|
linkedErrorsIntegration(),
|
|
25
26
|
dedupeIntegration(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../../src/sdk.ts"],"sourcesContent":["import type { Client, Integration, Options } from '@sentry/core';\nimport {\n conversationIdIntegration,\n dedupeIntegration,\n eventFiltersIntegration,\n functionToStringIntegration,\n getIntegrationsToSetup,\n initAndBind,\n setNormalizeStringifier,\n stackParserFromStackParserOptions,\n} from '@sentry/core';\nimport type { BrowserClientOptions, BrowserOptions } from './client';\nimport { BrowserClient } from './client';\nimport { breadcrumbsIntegration } from './integrations/breadcrumbs';\nimport { browserApiErrorsIntegration } from './integrations/browserapierrors';\nimport { browserSessionIntegration } from './integrations/browsersession';\nimport { cultureContextIntegration } from './integrations/culturecontext';\nimport { globalHandlersIntegration } from './integrations/globalhandlers';\nimport { httpContextIntegration } from './integrations/httpcontext';\nimport { linkedErrorsIntegration } from './integrations/linkederrors';\nimport { spotlightBrowserIntegration } from './integrations/spotlight';\nimport { defaultStackParser } from './stack-parsers';\nimport { makeFetchTransport } from './transports/fetch';\nimport { normalizeStringifyValue } from './normalizeStringifyValue';\nimport { checkAndWarnIfIsEmbeddedBrowserExtension } from './utils/detectBrowserExtension';\n\n/** Get the default integrations for the browser SDK. */\nexport function getDefaultIntegrations(_options: Options): Integration[] {\n /**\n * Note: Please make sure this stays in sync with Angular SDK, which re-exports\n * `getDefaultIntegrations` but with an adjusted set of integrations.\n */\n return [\n eventFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n browserApiErrorsIntegration(),\n breadcrumbsIntegration(),\n globalHandlersIntegration(),\n linkedErrorsIntegration(),\n dedupeIntegration(),\n httpContextIntegration(),\n cultureContextIntegration(),\n browserSessionIntegration(),\n ];\n}\n\n/**\n * The Sentry Browser SDK Client.\n *\n * To use this SDK, call the {@link init} function as early as possible when\n * loading the web page. To set context information or send manual events, use\n * the provided methods.\n *\n * @example\n *\n * ```\n *\n * import { init } from '@sentry/browser';\n *\n * init({\n * dsn: '__DSN__',\n * // ...\n * });\n * ```\n *\n * @example\n * ```\n *\n * import { addBreadcrumb } from '@sentry/browser';\n * addBreadcrumb({\n * message: 'My Breadcrumb',\n * // ...\n * });\n * ```\n *\n * @example\n *\n * ```\n *\n * import * as Sentry from '@sentry/browser';\n * Sentry.captureMessage('Hello, world!');\n * Sentry.captureException(new Error('Good bye'));\n * Sentry.captureEvent({\n * message: 'Manual',\n * stacktrace: [\n * // ...\n * ],\n * });\n * ```\n *\n * @see {@link BrowserOptions} for documentation on configuration options.\n */\nexport function init(options: BrowserOptions = {}): Client | undefined {\n const shouldDisableBecauseIsBrowserExtenstion =\n !options.skipBrowserExtensionCheck && checkAndWarnIfIsEmbeddedBrowserExtension();\n\n let defaultIntegrations =\n options.defaultIntegrations == null ? getDefaultIntegrations(options) : options.defaultIntegrations;\n\n /*! rollup-include-development-only */\n if (options.spotlight) {\n if (!defaultIntegrations) {\n defaultIntegrations = [];\n }\n const args = typeof options.spotlight === 'string' ? { sidecarUrl: options.spotlight } : undefined;\n defaultIntegrations.push(spotlightBrowserIntegration(args));\n }\n /*! rollup-include-development-only-end */\n\n const integrations = getIntegrationsToSetup({\n integrations: options.integrations,\n defaultIntegrations,\n });\n\n const clientOptions: BrowserClientOptions = {\n ...options,\n enabled: shouldDisableBecauseIsBrowserExtenstion ? false : options.enabled,\n stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),\n integrations,\n transport: options.transport || makeFetchTransport,\n };\n\n setNormalizeStringifier(normalizeStringifyValue);\n\n return initAndBind(BrowserClient, clientOptions);\n}\n\n/**\n * This function is here to be API compatible with the loader.\n * @hidden\n */\nexport function forceLoad(): void {\n // Noop\n}\n\n/**\n * This function is here to be API compatible with the loader.\n * @hidden\n */\nexport function onLoad(callback: () => void): void {\n callback();\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../../src/sdk.ts"],"sourcesContent":["import type { Client, Integration, Options } from '@sentry/core';\nimport {\n consoleIntegration,\n conversationIdIntegration,\n dedupeIntegration,\n eventFiltersIntegration,\n functionToStringIntegration,\n getIntegrationsToSetup,\n initAndBind,\n setNormalizeStringifier,\n stackParserFromStackParserOptions,\n} from '@sentry/core';\nimport type { BrowserClientOptions, BrowserOptions } from './client';\nimport { BrowserClient } from './client';\nimport { breadcrumbsIntegration } from './integrations/breadcrumbs';\nimport { browserApiErrorsIntegration } from './integrations/browserapierrors';\nimport { browserSessionIntegration } from './integrations/browsersession';\nimport { cultureContextIntegration } from './integrations/culturecontext';\nimport { globalHandlersIntegration } from './integrations/globalhandlers';\nimport { httpContextIntegration } from './integrations/httpcontext';\nimport { linkedErrorsIntegration } from './integrations/linkederrors';\nimport { spotlightBrowserIntegration } from './integrations/spotlight';\nimport { defaultStackParser } from './stack-parsers';\nimport { makeFetchTransport } from './transports/fetch';\nimport { normalizeStringifyValue } from './normalizeStringifyValue';\nimport { checkAndWarnIfIsEmbeddedBrowserExtension } from './utils/detectBrowserExtension';\n\n/** Get the default integrations for the browser SDK. */\nexport function getDefaultIntegrations(_options: Options): Integration[] {\n /**\n * Note: Please make sure this stays in sync with Angular SDK, which re-exports\n * `getDefaultIntegrations` but with an adjusted set of integrations.\n */\n return [\n eventFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n browserApiErrorsIntegration(),\n breadcrumbsIntegration(),\n consoleIntegration(),\n globalHandlersIntegration(),\n linkedErrorsIntegration(),\n dedupeIntegration(),\n httpContextIntegration(),\n cultureContextIntegration(),\n browserSessionIntegration(),\n ];\n}\n\n/**\n * The Sentry Browser SDK Client.\n *\n * To use this SDK, call the {@link init} function as early as possible when\n * loading the web page. To set context information or send manual events, use\n * the provided methods.\n *\n * @example\n *\n * ```\n *\n * import { init } from '@sentry/browser';\n *\n * init({\n * dsn: '__DSN__',\n * // ...\n * });\n * ```\n *\n * @example\n * ```\n *\n * import { addBreadcrumb } from '@sentry/browser';\n * addBreadcrumb({\n * message: 'My Breadcrumb',\n * // ...\n * });\n * ```\n *\n * @example\n *\n * ```\n *\n * import * as Sentry from '@sentry/browser';\n * Sentry.captureMessage('Hello, world!');\n * Sentry.captureException(new Error('Good bye'));\n * Sentry.captureEvent({\n * message: 'Manual',\n * stacktrace: [\n * // ...\n * ],\n * });\n * ```\n *\n * @see {@link BrowserOptions} for documentation on configuration options.\n */\nexport function init(options: BrowserOptions = {}): Client | undefined {\n const shouldDisableBecauseIsBrowserExtenstion =\n !options.skipBrowserExtensionCheck && checkAndWarnIfIsEmbeddedBrowserExtension();\n\n let defaultIntegrations =\n options.defaultIntegrations == null ? getDefaultIntegrations(options) : options.defaultIntegrations;\n\n /*! rollup-include-development-only */\n if (options.spotlight) {\n if (!defaultIntegrations) {\n defaultIntegrations = [];\n }\n const args = typeof options.spotlight === 'string' ? { sidecarUrl: options.spotlight } : undefined;\n defaultIntegrations.push(spotlightBrowserIntegration(args));\n }\n /*! rollup-include-development-only-end */\n\n const integrations = getIntegrationsToSetup({\n integrations: options.integrations,\n defaultIntegrations,\n });\n\n const clientOptions: BrowserClientOptions = {\n ...options,\n enabled: shouldDisableBecauseIsBrowserExtenstion ? false : options.enabled,\n stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),\n integrations,\n transport: options.transport || makeFetchTransport,\n };\n\n setNormalizeStringifier(normalizeStringifyValue);\n\n return initAndBind(BrowserClient, clientOptions);\n}\n\n/**\n * This function is here to be API compatible with the loader.\n * @hidden\n */\nexport function forceLoad(): void {\n // Noop\n}\n\n/**\n * This function is here to be API compatible with the loader.\n * @hidden\n */\nexport function onLoad(callback: () => void): void {\n callback();\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AA4BO,SAAS,uBAAuB,QAAA,EAAkC;AAKvE,EAAA,OAAO;AAAA,IACL,uBAAA,EAAwB;AAAA,IACxB,2BAAA,EAA4B;AAAA,IAC5B,yBAAA,EAA0B;AAAA,IAC1B,2BAAA,EAA4B;AAAA,IAC5B,sBAAA,EAAuB;AAAA,IACvB,kBAAA,EAAmB;AAAA,IACnB,yBAAA,EAA0B;AAAA,IAC1B,uBAAA,EAAwB;AAAA,IACxB,iBAAA,EAAkB;AAAA,IAClB,sBAAA,EAAuB;AAAA,IACvB,yBAAA,EAA0B;AAAA,IAC1B,yBAAA;AAA0B,GAC5B;AACF;AAgDO,SAAS,IAAA,CAAK,OAAA,GAA0B,EAAC,EAAuB;AACrE,EAAA,MAAM,uCAAA,GACJ,CAAC,OAAA,CAAQ,yBAAA,IAA6B,wCAAA,EAAyC;AAEjF,EAAA,IAAI,sBACF,OAAA,CAAQ,mBAAA,IAAuB,OAAO,sBAAA,CAA8B,IAAI,OAAA,CAAQ,mBAAA;AAAA;AAGlF,EAAA,IAAI,QAAQ,SAAA,EAAW;AACrB,IAAA,IAAI,CAAC,mBAAA,EAAqB;AACxB,MAAA,mBAAA,GAAsB,EAAC;AAAA,IACzB;AACA,IAAA,MAAM,IAAA,GAAO,OAAO,OAAA,CAAQ,SAAA,KAAc,WAAW,EAAE,UAAA,EAAY,OAAA,CAAQ,SAAA,EAAU,GAAI,MAAA;AACzF,IAAA,mBAAA,CAAoB,IAAA,CAAK,2BAAA,CAA4B,IAAI,CAAC,CAAA;AAAA,EAC5D;AAAA;AAGA,EAAA,MAAM,eAAe,sBAAA,CAAuB;AAAA,IAC1C,cAAc,OAAA,CAAQ,YAAA;AAAA,IACtB;AAAA,GACD,CAAA;AAED,EAAA,MAAM,aAAA,GAAsC;AAAA,IAC1C,GAAG,OAAA;AAAA,IACH,OAAA,EAAS,uCAAA,GAA0C,KAAA,GAAQ,OAAA,CAAQ,OAAA;AAAA,IACnE,WAAA,EAAa,iCAAA,CAAkC,OAAA,CAAQ,WAAA,IAAe,kBAAkB,CAAA;AAAA,IACxF,YAAA;AAAA,IACA,SAAA,EAAW,QAAQ,SAAA,IAAa;AAAA,GAClC;AAEA,EAAA,uBAAA,CAAwB,uBAAuB,CAAA;AAE/C,EAAA,OAAO,WAAA,CAAY,eAAe,aAAa,CAAA;AACjD;AAMO,SAAS,SAAA,GAAkB;AAElC;AAMO,SAAS,OAAO,QAAA,EAA4B;AACjD,EAAA,QAAA,EAAS;AACX;;;;"}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import { TRACING_DEFAULTS, consoleSandbox, hasSpanStreamingEnabled, PAGELOAD_SPAN_NAME_FALLBACK, parseStringToURLObject, NAVIGATION_SPAN_NAME_FALLBACK, debug, registerSpanErrorInstrumentation, GLOBAL_OBJ, getCurrentScope, getDynamicSamplingContextFromSpan, spanIsSampled, getClient, hasSpansEnabled, generateSpanId, generateTraceId, propagationContextFromHeaders,
|
|
1
|
+
import { TRACING_DEFAULTS, consoleSandbox, hasSpanStreamingEnabled, PAGELOAD_SPAN_NAME_FALLBACK, parseStringToURLObject, NAVIGATION_SPAN_NAME_FALLBACK, debug, registerSpanErrorInstrumentation, GLOBAL_OBJ, getCurrentScope, getDynamicSamplingContextFromSpan, spanIsSampled, getClient, hasSpansEnabled, generateSpanId, generateTraceId, propagationContextFromHeaders, spanToJSON, browserPerformanceTimeOrigin, dateTimestampInSeconds, timestampInSeconds, addNonEnumerableProperty, isURLObjectRelative, filterCollectedUrl } from '@sentry/core';
|
|
2
2
|
import { _INTERNAL_ensureBrowserSpanStreaming, startInactiveSpan, startIdleSpan } from '@sentry/core/browser';
|
|
3
3
|
import { isBotUserAgent, getLocationHref, addHistoryInstrumentationHandler, startTrackingLongAnimationFrames, startTrackingLongTasks, addPerformanceEntries } from '@sentry/browser-utils';
|
|
4
|
+
import { SENTRY_IDLE_SPAN_FINISH_REASON, URL_FULL, URL_PATH, SENTRY_OP, SENTRY_SEGMENT_NAME_SOURCE, SENTRY_ORIGIN, BROWSER_NAVIGATION_TYPE } from '@sentry/conventions/attributes';
|
|
4
5
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
5
6
|
import { WINDOW, getHttpRequestData } from '../helpers.js';
|
|
6
7
|
import { WEB_VITALS_INTEGRATION_NAME, webVitalsIntegration } from '../integrations/webVitals.js';
|
|
7
8
|
import { registerBackgroundTabDetection } from './backgroundtab.js';
|
|
8
9
|
import { linkTraces } from './linkedTraces.js';
|
|
9
|
-
import {
|
|
10
|
-
import { URL_FULL, URL_PATH, SENTRY_OP, SENTRY_SEGMENT_NAME_SOURCE } from '@sentry/conventions/attributes';
|
|
10
|
+
import { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './request.js';
|
|
11
11
|
import { NAVIGATION_REDIRECT, NAVIGATION, PAGELOAD } from '@sentry/conventions/op';
|
|
12
12
|
|
|
13
13
|
const BROWSER_TRACING_INTEGRATION_ID = "BrowserTracing";
|
|
14
14
|
const DEFAULT_BROWSER_TRACING_OPTIONS = {
|
|
15
15
|
...TRACING_DEFAULTS,
|
|
16
16
|
instrumentNavigation: true,
|
|
17
|
+
instrumentBfcacheRestore: true,
|
|
17
18
|
instrumentPageLoad: true,
|
|
18
19
|
markBackgroundSpan: true,
|
|
19
20
|
enableLongTask: true,
|
|
20
21
|
enableLongAnimationFrame: true,
|
|
22
|
+
// oxlint-disable-next-line typescript/no-deprecated -- still honoured until it is removed
|
|
21
23
|
enableInp: true,
|
|
22
24
|
ignoreResourceSpans: [],
|
|
23
25
|
detectRedirects: true,
|
|
@@ -36,9 +38,11 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
36
38
|
}
|
|
37
39
|
const optionalWindowDocument = WINDOW.document;
|
|
38
40
|
const {
|
|
41
|
+
// oxlint-disable-next-line typescript/no-deprecated -- still honoured until it is removed
|
|
39
42
|
enableInp,
|
|
40
43
|
enableLongTask,
|
|
41
44
|
enableLongAnimationFrame,
|
|
45
|
+
webVitals,
|
|
42
46
|
beforeStartSpan,
|
|
43
47
|
idleTimeout,
|
|
44
48
|
finalTimeout,
|
|
@@ -51,6 +55,7 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
51
55
|
ignoreResourceSpans,
|
|
52
56
|
instrumentPageLoad,
|
|
53
57
|
instrumentNavigation,
|
|
58
|
+
instrumentBfcacheRestore,
|
|
54
59
|
detectRedirects,
|
|
55
60
|
linkPreviousTrace,
|
|
56
61
|
consistentTraceSampling,
|
|
@@ -135,7 +140,7 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
135
140
|
DEBUG_BUILD && debug.log(
|
|
136
141
|
`[Tracing] Finishing current active span with op: ${spanToJSON(activeSpan).attributes[SENTRY_OP]}`
|
|
137
142
|
);
|
|
138
|
-
activeSpan.setAttribute(
|
|
143
|
+
activeSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, "cancelled");
|
|
139
144
|
activeSpan.end();
|
|
140
145
|
}
|
|
141
146
|
}
|
|
@@ -223,10 +228,18 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
223
228
|
});
|
|
224
229
|
client.on("endPageloadSpan", () => {
|
|
225
230
|
if (enableReportPageLoaded && _pageloadSpan) {
|
|
226
|
-
_pageloadSpan.setAttribute(
|
|
231
|
+
_pageloadSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, "reportPageLoaded");
|
|
227
232
|
_pageloadSpan.end();
|
|
228
233
|
}
|
|
229
234
|
});
|
|
235
|
+
WINDOW.addEventListener?.("pagehide", () => {
|
|
236
|
+
const activeSpan = getActiveIdleSpan(client);
|
|
237
|
+
if (activeSpan && !spanToJSON(activeSpan).end_timestamp) {
|
|
238
|
+
activeSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, "documentHidden");
|
|
239
|
+
activeSpan.end();
|
|
240
|
+
}
|
|
241
|
+
void client.flush();
|
|
242
|
+
});
|
|
230
243
|
},
|
|
231
244
|
afterAllSetup(client) {
|
|
232
245
|
if (_isBot) {
|
|
@@ -234,9 +247,11 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
234
247
|
}
|
|
235
248
|
_INTERNAL_ensureBrowserSpanStreaming(client);
|
|
236
249
|
if (client.addIntegration && !client.getIntegrationByName?.(WEB_VITALS_INTEGRATION_NAME)) {
|
|
250
|
+
const ignore = webVitals?.ignore ?? [];
|
|
237
251
|
client.addIntegration(
|
|
238
252
|
webVitalsIntegration({
|
|
239
|
-
|
|
253
|
+
...webVitals,
|
|
254
|
+
ignore: enableInp || ignore.includes("inp") ? ignore : [...ignore, "inp"]
|
|
240
255
|
})
|
|
241
256
|
);
|
|
242
257
|
}
|
|
@@ -252,13 +267,13 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
252
267
|
name: hasSpanStreamingEnabled(client) ? PAGELOAD_SPAN_NAME_FALLBACK : WINDOW.location.pathname,
|
|
253
268
|
attributes: {
|
|
254
269
|
[SENTRY_SEGMENT_NAME_SOURCE]: "url",
|
|
255
|
-
[
|
|
270
|
+
[SENTRY_ORIGIN]: "auto.pageload.browser"
|
|
256
271
|
}
|
|
257
272
|
});
|
|
258
273
|
}
|
|
259
274
|
if (instrumentNavigation) {
|
|
260
275
|
addHistoryInstrumentationHandler(({ to, from }) => {
|
|
261
|
-
if (from === void 0 && startingUrl
|
|
276
|
+
if (from === void 0 && startingUrl !== void 0 && startingUrl.indexOf(to) !== -1) {
|
|
262
277
|
startingUrl = void 0;
|
|
263
278
|
return;
|
|
264
279
|
}
|
|
@@ -274,13 +289,42 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
274
289
|
name: hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : parsed?.pathname || WINDOW.location.pathname,
|
|
275
290
|
attributes: {
|
|
276
291
|
[SENTRY_SEGMENT_NAME_SOURCE]: "url",
|
|
277
|
-
[
|
|
292
|
+
[SENTRY_ORIGIN]: "auto.navigation.browser"
|
|
278
293
|
}
|
|
279
294
|
},
|
|
280
295
|
{ url: to, isRedirect: navigationIsRedirect }
|
|
281
296
|
);
|
|
282
297
|
});
|
|
283
298
|
}
|
|
299
|
+
if (instrumentBfcacheRestore) {
|
|
300
|
+
WINDOW.addEventListener?.("pageshow", (event) => {
|
|
301
|
+
if (!event.persisted) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
startingUrl = void 0;
|
|
305
|
+
startBrowserTracingNavigationSpan(
|
|
306
|
+
client,
|
|
307
|
+
{
|
|
308
|
+
// Deliberately no `startTime`: the span starts now, at the restore. The
|
|
309
|
+
// `PerformanceNavigationTiming` entry still describes the original document load and
|
|
310
|
+
// would date the span to before the page was frozen.
|
|
311
|
+
//
|
|
312
|
+
// TODO(routing): resolve the parameterized route via the route provider (#23551) and set
|
|
313
|
+
// the source from it. No router event fires on a restore, so in a framework app this is
|
|
314
|
+
// the only navigation span still named from a raw pathname.
|
|
315
|
+
name: hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : WINDOW.location?.pathname || "/",
|
|
316
|
+
attributes: {
|
|
317
|
+
[SENTRY_SEGMENT_NAME_SOURCE]: "url",
|
|
318
|
+
[SENTRY_ORIGIN]: "auto.navigation.browser.bfcache",
|
|
319
|
+
// A bfcache restore is near-instant, so these spans would otherwise drag
|
|
320
|
+
// navigation duration percentiles down with no way to tell them apart.
|
|
321
|
+
[BROWSER_NAVIGATION_TYPE]: "back-forward-cache"
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
{ url: WINDOW.location?.href }
|
|
325
|
+
);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
284
328
|
}
|
|
285
329
|
if (markBackgroundSpan) {
|
|
286
330
|
registerBackgroundTabDetection();
|