@sentry/browser 11.0.0-alpha.0 → 11.0.0-alpha.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 -0
- package/build/npm/cjs/dev/index.js.map +1 -1
- package/build/npm/cjs/dev/integrations/graphqlClient.js +3 -3
- package/build/npm/cjs/dev/integrations/graphqlClient.js.map +1 -1
- package/build/npm/cjs/dev/profiling/index.js.map +1 -1
- package/build/npm/cjs/dev/profiling/integration.js +21 -91
- package/build/npm/cjs/dev/profiling/integration.js.map +1 -1
- package/build/npm/cjs/dev/profiling/utils.js +0 -283
- package/build/npm/cjs/dev/profiling/utils.js.map +1 -1
- package/build/npm/cjs/dev/tracing/backgroundtab.js +5 -1
- package/build/npm/cjs/dev/tracing/backgroundtab.js.map +1 -1
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js +5 -9
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/dev/tracing/linkedTraces.js +3 -2
- package/build/npm/cjs/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/cjs/dev/tracing/request.js +2 -4
- package/build/npm/cjs/dev/tracing/request.js.map +1 -1
- package/build/npm/cjs/prod/index.js +1 -0
- package/build/npm/cjs/prod/index.js.map +1 -1
- package/build/npm/cjs/prod/integrations/graphqlClient.js +3 -3
- package/build/npm/cjs/prod/integrations/graphqlClient.js.map +1 -1
- package/build/npm/cjs/prod/profiling/index.js.map +1 -1
- package/build/npm/cjs/prod/profiling/integration.js +21 -91
- package/build/npm/cjs/prod/profiling/integration.js.map +1 -1
- package/build/npm/cjs/prod/profiling/utils.js +0 -283
- package/build/npm/cjs/prod/profiling/utils.js.map +1 -1
- package/build/npm/cjs/prod/tracing/backgroundtab.js +5 -1
- package/build/npm/cjs/prod/tracing/backgroundtab.js.map +1 -1
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js +5 -9
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/prod/tracing/linkedTraces.js +3 -2
- package/build/npm/cjs/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/cjs/prod/tracing/request.js +2 -4
- package/build/npm/cjs/prod/tracing/request.js.map +1 -1
- package/build/npm/esm/dev/index.js +1 -1
- package/build/npm/esm/dev/integrations/graphqlClient.js +5 -5
- package/build/npm/esm/dev/integrations/graphqlClient.js.map +1 -1
- package/build/npm/esm/dev/package.json +1 -1
- package/build/npm/esm/dev/profiling/index.js.map +1 -1
- package/build/npm/esm/dev/profiling/integration.js +22 -92
- package/build/npm/esm/dev/profiling/integration.js.map +1 -1
- package/build/npm/esm/dev/profiling/utils.js +2 -272
- package/build/npm/esm/dev/profiling/utils.js.map +1 -1
- package/build/npm/esm/dev/tracing/backgroundtab.js +5 -1
- package/build/npm/esm/dev/tracing/backgroundtab.js.map +1 -1
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js +6 -10
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/dev/tracing/linkedTraces.js +3 -2
- package/build/npm/esm/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/dev/tracing/request.js +2 -4
- package/build/npm/esm/dev/tracing/request.js.map +1 -1
- package/build/npm/esm/prod/index.js +1 -1
- package/build/npm/esm/prod/integrations/graphqlClient.js +5 -5
- package/build/npm/esm/prod/integrations/graphqlClient.js.map +1 -1
- package/build/npm/esm/prod/package.json +1 -1
- package/build/npm/esm/prod/profiling/index.js.map +1 -1
- package/build/npm/esm/prod/profiling/integration.js +22 -92
- package/build/npm/esm/prod/profiling/integration.js.map +1 -1
- package/build/npm/esm/prod/profiling/utils.js +2 -272
- package/build/npm/esm/prod/profiling/utils.js.map +1 -1
- package/build/npm/esm/prod/tracing/backgroundtab.js +5 -1
- package/build/npm/esm/prod/tracing/backgroundtab.js.map +1 -1
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js +6 -10
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/prod/tracing/linkedTraces.js +3 -2
- package/build/npm/esm/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/prod/tracing/request.js +2 -4
- package/build/npm/esm/prod/tracing/request.js.map +1 -1
- package/build/npm/types/exports.d.ts +1 -1
- package/build/npm/types/exports.d.ts.map +1 -1
- package/build/npm/types/index.bundle.d.ts +2 -2
- package/build/npm/types/index.bundle.d.ts.map +1 -1
- package/build/npm/types/index.bundle.feedback.d.ts +2 -2
- package/build/npm/types/index.bundle.feedback.d.ts.map +1 -1
- package/build/npm/types/index.bundle.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.replay.d.ts +2 -2
- package/build/npm/types/index.bundle.replay.d.ts.map +1 -1
- package/build/npm/types/index.bundle.replay.feedback.d.ts +2 -2
- package/build/npm/types/index.bundle.replay.feedback.d.ts.map +1 -1
- package/build/npm/types/index.bundle.replay.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.replay.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.d.ts +2 -2
- package/build/npm/types/index.bundle.tracing.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.d.ts +2 -2
- package/build/npm/types/index.bundle.tracing.replay.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.d.ts +2 -2
- package/build/npm/types/index.bundle.tracing.replay.feedback.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.replay.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.d.ts +1 -2
- package/build/npm/types/index.d.ts.map +1 -1
- package/build/npm/types/integrations/graphqlClient.d.ts.map +1 -1
- package/build/npm/types/profiling/index.d.ts.map +1 -1
- package/build/npm/types/profiling/integration.d.ts.map +1 -1
- package/build/npm/types/profiling/utils.d.ts +1 -74
- package/build/npm/types/profiling/utils.d.ts.map +1 -1
- package/build/npm/types/tracing/backgroundtab.d.ts.map +1 -1
- package/build/npm/types/tracing/browserTracingIntegration.d.ts +0 -10
- package/build/npm/types/tracing/browserTracingIntegration.d.ts.map +1 -1
- package/build/npm/types/tracing/linkedTraces.d.ts.map +1 -1
- package/build/npm/types/tracing/request.d.ts +0 -13
- package/build/npm/types/tracing/request.d.ts.map +1 -1
- package/package.json +8 -8
- package/build/npm/cjs/dev/profiling/startProfileForSpan.js +0 -91
- package/build/npm/cjs/dev/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/cjs/prod/profiling/startProfileForSpan.js +0 -91
- package/build/npm/cjs/prod/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/esm/dev/profiling/startProfileForSpan.js +0 -89
- package/build/npm/esm/dev/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/esm/prod/profiling/startProfileForSpan.js +0 -89
- package/build/npm/esm/prod/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/types/profiling/startProfileForSpan.d.ts +0 -8
- package/build/npm/types/profiling/startProfileForSpan.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT, URL_FULL } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n const httpUrl = spanAttributes[URL_FULL];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":[],"mappings":";;;;AA6CA,MAAM,gBAAA,GAAmB,eAAA;AAEzB,MAAM,yBAAA,IAA6B,CAAC,OAAA,KAAkC;AACpE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAgB;AACpB,MAAA,0BAAA,CAA2B,QAAQ,OAAO,CAAA;AAC1C,MAAA,gCAAA,CAAiC,QAAQ,OAAO,CAAA;AAAA,IAClD;AAAA,GACF;AACF,CAAA,CAAA;AAEA,SAAS,0BAAA,CAA2B,QAAgB,OAAA,EAAqC;AACvF,EAAA,MAAA,CAAO,EAAA,CAAG,2BAAA,EAA6B,CAAC,IAAA,EAAM,IAAA,KAAS;AACrD,IAAA,MAAM,QAAA,GAAW,WAAW,IAAI,CAAA;AAEhC,IAAA,MAAM,cAAA,GAAiB,QAAA,CAAS,IAAA,IAAQ,EAAC;AACzC,IAAA,MAAM,MAAA,GAAS,eAAe,4BAA4B,CAAA;AAE1D,IAAA,MAAM,mBAAmB,MAAA,KAAW,aAAA;AAEpC,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAU,eAAe,QAAQ,CAAA;AACvC,IAAA,MAAM,UAAA,GAAa,cAAA,CAAe,sCAAsC,CAAA,IAAK,eAAe,aAAa,CAAA;AAEzG,IAAA,IAAI,CAAC,QAAA,CAAS,OAAO,KAAK,CAAC,QAAA,CAAS,UAAU,CAAA,EAAG;AAC/C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,WAAU,GAAI,OAAA;AACtB,IAAA,MAAM,uBAAA,GAA0B,wBAAA,CAAyB,OAAA,EAAS,SAAS,CAAA;AAC3E,IAAA,MAAM,OAAA,GAAU,4BAA4B,IAA2B,CAAA;AAEvE,IAAA,IAAI,2BAA2B,OAAA,EAAS;AACtC,MAAA,MAAM,WAAA,GAAc,yBAAyB,OAAO,CAAA;AAEpD,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,MAAM,aAAA,GAAgB,qBAAqB,WAAW,CAAA;AACtD,QAAA,IAAA,CAAK,WAAW,CAAA,EAAG,UAAU,IAAI,OAAO,CAAA,EAAA,EAAK,aAAa,CAAA,CAAA,CAAG,CAAA;AAG7D,QAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,IAAK,MAAA,CAAO,0BAAyB,CAAE,OAAA,CAAQ,aAAa,IAAA,EAAM;AACjG,UAAA,IAAA,CAAK,YAAA,CAAa,gBAAA,EAAkB,WAAA,CAAY,KAAK,CAAA;AAAA,QACvD;AAGA,QAAA,IAAI,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACnC,UAAA,IAAA,CAAK,YAAA,CAAa,qCAAA,EAAuC,WAAA,CAAY,UAAA,CAAW,eAAe,UAAU,CAAA;AACzG,UAAA,IAAA,CAAK,YAAA,CAAa,iCAAA,EAAmC,WAAA,CAAY,UAAA,CAAW,eAAe,OAAO,CAAA;AAAA,QACpG;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;AAEA,SAAS,gCAAA,CAAiC,QAAgB,OAAA,EAAqC;AAC7F,EAAA,MAAA,CAAO,EAAA,CAAG,iCAAA,EAAmC,CAAC,UAAA,EAAY,WAAA,KAAgB;AACxE,IAAA,MAAM,EAAE,QAAA,EAAU,IAAA,EAAM,IAAA,EAAK,GAAI,UAAA;AAEjC,IAAA,MAAM,UAAU,QAAA,KAAa,OAAA;AAC7B,IAAA,MAAM,QAAQ,QAAA,KAAa,KAAA;AAC3B,IAAA,MAAM,mBAAmB,IAAA,KAAS,MAAA;AAElC,IAAA,IAAI,gBAAA,KAAqB,WAAW,KAAA,CAAA,EAAQ;AAC1C,MAAA,MAAM,UAAU,IAAA,EAAM,GAAA;AACtB,MAAA,MAAM,EAAE,WAAU,GAAI,OAAA;AAEtB,MAAA,MAAM,uBAAA,GAA0B,wBAAA,CAAyB,OAAA,EAAS,SAAS,CAAA;AAC3E,MAAA,MAAM,OAAA,GAAU,4BAA4B,WAAkC,CAAA;AAE9E,MAAA,IAAI,uBAAA,IAA2B,QAAQ,OAAA,EAAS;AAC9C,QAAA,MAAM,WAAA,GAAc,yBAAyB,OAAO,CAAA;AAEpD,QAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,WAAA,EAAa;AAChC,UAAA,MAAM,aAAA,GAAgB,qBAAqB,WAAW,CAAA;AAEtD,UAAA,IAAA,CAAK,mBAAmB,CAAA,GAAI,aAAA;AAE5B,UAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,IAAK,MAAA,CAAO,0BAAyB,CAAE,OAAA,CAAQ,aAAa,IAAA,EAAM;AACjG,YAAA,IAAA,CAAK,gBAAgB,IAAI,WAAA,CAAY,KAAA;AAAA,UACvC;AAEA,UAAA,IAAI,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACnC,YAAA,IAAA,CAAK,qCAAqC,CAAA,GAAI,WAAA,CAAY,UAAA,CAAW,cAAA,CAAe,UAAA;AACpF,YAAA,IAAA,CAAK,iCAAiC,CAAA,GAAI,WAAA,CAAY,UAAA,CAAW,cAAA,CAAe,OAAA;AAAA,UAClF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;AAMO,SAAS,qBAAqB,WAAA,EAA4C;AAE/E,EAAA,IAAI,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACnC,IAAA,OAAO,CAAA,UAAA,EAAa,YAAY,aAAa,CAAA,CAAA;AAAA,EAC/C;AAGA,EAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,EAAG;AAClC,IAAA,MAAM,EAAE,KAAA,EAAO,YAAA,EAAc,aAAA,EAAe,sBAAqB,GAAI,WAAA;AACrE,IAAA,MAAM,EAAE,aAAA,GAAgB,oBAAA,EAAsB,aAAA,EAAc,GAAI,kBAAkB,YAAY,CAAA;AAC9F,IAAA,MAAM,aAAA,GAAgB,gBAAgB,CAAA,EAAG,aAAa,IAAI,aAAa,CAAA,CAAA,GAAK,GAAG,aAAa,CAAA,CAAA;AAC5F,IAAA,OAAO,aAAA;AAAA,EACT;AAGA,EAAA,OAAO,SAAA;AACT;AAOO,SAAS,4BAA4B,IAAA,EAA+C;AACzF,EAAA,MAAM,QAAQ,KAAA,IAAS,IAAA;AAEvB,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,mBAAmB,CAAA;AAClD,IAAA,IAAA,GAAO,aAAA,IAAiB,aAAA,CAAc,aAAA,CAAc,IAAI,EAAE,CAAC,CAAA;AAAA,EAC7D,CAAA,MAAO;AACL,IAAA,MAAM,eAAA,GAAkB,sBAAA,CAAuB,IAAA,CAAK,KAAK,CAAA;AACzD,IAAA,IAAA,GAAO,aAAA,CAAc,eAAe,CAAA,CAAE,CAAC,CAAA;AAAA,EACzC;AAEA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,kBAAkB,KAAA,EAAiC;AACjE,EAAA,MAAM,YAAA,GAAe,8DAAA;AACrB,EAAA,MAAM,cAAA,GAAiB,kDAAA;AAEvB,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAA,CAAM,YAAY,CAAA;AAC3C,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,OAAO;AAAA,MACL,aAAA,EAAe,WAAW,CAAC,CAAA;AAAA,MAC3B,aAAA,EAAe,WAAW,CAAC;AAAA,KAC7B;AAAA,EACF;AAEA,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,cAAc,CAAA;AAC/C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,OAAO;AAAA,MACL,aAAA,EAAe,aAAa,CAAC,CAAA;AAAA,MAC7B,aAAA,EAAe;AAAA,KACjB;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,aAAA,EAAe,MAAA;AAAA,IACf,aAAA,EAAe;AAAA,GACjB;AACF;AASA,SAAS,kBAAkB,OAAA,EAAqD;AAC9E,EAAA,OAAO,YAAA,CAAa,OAAO,CAAA,IAAK,OAAO,QAAQ,KAAA,KAAU,QAAA;AAC3D;AAKA,SAAS,mBAAmB,OAAA,EAAsD;AAChF,EAAA,OACE,YAAA,CAAa,OAAO,CAAA,IACpB,OAAO,OAAA,CAAQ,aAAA,KAAkB,QAAA,IACjC,YAAA,CAAa,OAAA,CAAQ,UAAU,CAAA,IAC/B,YAAA,CAAa,OAAA,CAAQ,WAAW,cAAc,CAAA,IAC9C,OAAO,OAAA,CAAQ,UAAA,CAAW,cAAA,CAAe,UAAA,KAAe,QAAA,IACxD,OAAO,OAAA,CAAQ,UAAA,CAAW,cAAA,CAAe,OAAA,KAAY,QAAA;AAEzD;AAQO,SAAS,yBAAyB,OAAA,EAAoD;AAC3F,EAAA,IAAI;AACF,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAGtC,IAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,IAAK,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACrE,MAAA,OAAO,WAAA;AAAA,IACT;AAGA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAMO,MAAM,wBAAA,GAA2B,kBAAkB,yBAAyB;;;;"}
|
|
1
|
+
{"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT, HTTP_METHOD, SENTRY_OP, URL_FULL } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.attributes;\n const spanOp = spanAttributes[SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n const httpUrl = spanAttributes[URL_FULL];\n // oxlint-disable-next-line typescript/no-deprecated\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes[HTTP_METHOD];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":[],"mappings":";;;;AA4CA,MAAM,gBAAA,GAAmB,eAAA;AAEzB,MAAM,yBAAA,IAA6B,CAAC,OAAA,KAAkC;AACpE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAgB;AACpB,MAAA,0BAAA,CAA2B,QAAQ,OAAO,CAAA;AAC1C,MAAA,gCAAA,CAAiC,QAAQ,OAAO,CAAA;AAAA,IAClD;AAAA,GACF;AACF,CAAA,CAAA;AAEA,SAAS,0BAAA,CAA2B,QAAgB,OAAA,EAAqC;AACvF,EAAA,MAAA,CAAO,EAAA,CAAG,2BAAA,EAA6B,CAAC,IAAA,EAAM,IAAA,KAAS;AACrD,IAAA,MAAM,QAAA,GAAW,WAAW,IAAI,CAAA;AAEhC,IAAA,MAAM,iBAAiB,QAAA,CAAS,UAAA;AAChC,IAAA,MAAM,MAAA,GAAS,eAAe,SAAS,CAAA;AAEvC,IAAA,MAAM,mBAAmB,MAAA,KAAW,aAAA;AAEpC,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAU,eAAe,QAAQ,CAAA;AAEvC,IAAA,MAAM,UAAA,GAAa,cAAA,CAAe,sCAAsC,CAAA,IAAK,eAAe,WAAW,CAAA;AAEvG,IAAA,IAAI,CAAC,QAAA,CAAS,OAAO,KAAK,CAAC,QAAA,CAAS,UAAU,CAAA,EAAG;AAC/C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,WAAU,GAAI,OAAA;AACtB,IAAA,MAAM,uBAAA,GAA0B,wBAAA,CAAyB,OAAA,EAAS,SAAS,CAAA;AAC3E,IAAA,MAAM,OAAA,GAAU,4BAA4B,IAA2B,CAAA;AAEvE,IAAA,IAAI,2BAA2B,OAAA,EAAS;AACtC,MAAA,MAAM,WAAA,GAAc,yBAAyB,OAAO,CAAA;AAEpD,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,MAAM,aAAA,GAAgB,qBAAqB,WAAW,CAAA;AACtD,QAAA,IAAA,CAAK,WAAW,CAAA,EAAG,UAAU,IAAI,OAAO,CAAA,EAAA,EAAK,aAAa,CAAA,CAAA,CAAG,CAAA;AAG7D,QAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,IAAK,MAAA,CAAO,0BAAyB,CAAE,OAAA,CAAQ,aAAa,IAAA,EAAM;AACjG,UAAA,IAAA,CAAK,YAAA,CAAa,gBAAA,EAAkB,WAAA,CAAY,KAAK,CAAA;AAAA,QACvD;AAGA,QAAA,IAAI,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACnC,UAAA,IAAA,CAAK,YAAA,CAAa,qCAAA,EAAuC,WAAA,CAAY,UAAA,CAAW,eAAe,UAAU,CAAA;AACzG,UAAA,IAAA,CAAK,YAAA,CAAa,iCAAA,EAAmC,WAAA,CAAY,UAAA,CAAW,eAAe,OAAO,CAAA;AAAA,QACpG;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;AAEA,SAAS,gCAAA,CAAiC,QAAgB,OAAA,EAAqC;AAC7F,EAAA,MAAA,CAAO,EAAA,CAAG,iCAAA,EAAmC,CAAC,UAAA,EAAY,WAAA,KAAgB;AACxE,IAAA,MAAM,EAAE,QAAA,EAAU,IAAA,EAAM,IAAA,EAAK,GAAI,UAAA;AAEjC,IAAA,MAAM,UAAU,QAAA,KAAa,OAAA;AAC7B,IAAA,MAAM,QAAQ,QAAA,KAAa,KAAA;AAC3B,IAAA,MAAM,mBAAmB,IAAA,KAAS,MAAA;AAElC,IAAA,IAAI,gBAAA,KAAqB,WAAW,KAAA,CAAA,EAAQ;AAC1C,MAAA,MAAM,UAAU,IAAA,EAAM,GAAA;AACtB,MAAA,MAAM,EAAE,WAAU,GAAI,OAAA;AAEtB,MAAA,MAAM,uBAAA,GAA0B,wBAAA,CAAyB,OAAA,EAAS,SAAS,CAAA;AAC3E,MAAA,MAAM,OAAA,GAAU,4BAA4B,WAAkC,CAAA;AAE9E,MAAA,IAAI,uBAAA,IAA2B,QAAQ,OAAA,EAAS;AAC9C,QAAA,MAAM,WAAA,GAAc,yBAAyB,OAAO,CAAA;AAEpD,QAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,WAAA,EAAa;AAChC,UAAA,MAAM,aAAA,GAAgB,qBAAqB,WAAW,CAAA;AAEtD,UAAA,IAAA,CAAK,mBAAmB,CAAA,GAAI,aAAA;AAE5B,UAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,IAAK,MAAA,CAAO,0BAAyB,CAAE,OAAA,CAAQ,aAAa,IAAA,EAAM;AACjG,YAAA,IAAA,CAAK,gBAAgB,IAAI,WAAA,CAAY,KAAA;AAAA,UACvC;AAEA,UAAA,IAAI,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACnC,YAAA,IAAA,CAAK,qCAAqC,CAAA,GAAI,WAAA,CAAY,UAAA,CAAW,cAAA,CAAe,UAAA;AACpF,YAAA,IAAA,CAAK,iCAAiC,CAAA,GAAI,WAAA,CAAY,UAAA,CAAW,cAAA,CAAe,OAAA;AAAA,UAClF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;AAMO,SAAS,qBAAqB,WAAA,EAA4C;AAE/E,EAAA,IAAI,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACnC,IAAA,OAAO,CAAA,UAAA,EAAa,YAAY,aAAa,CAAA,CAAA;AAAA,EAC/C;AAGA,EAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,EAAG;AAClC,IAAA,MAAM,EAAE,KAAA,EAAO,YAAA,EAAc,aAAA,EAAe,sBAAqB,GAAI,WAAA;AACrE,IAAA,MAAM,EAAE,aAAA,GAAgB,oBAAA,EAAsB,aAAA,EAAc,GAAI,kBAAkB,YAAY,CAAA;AAC9F,IAAA,MAAM,aAAA,GAAgB,gBAAgB,CAAA,EAAG,aAAa,IAAI,aAAa,CAAA,CAAA,GAAK,GAAG,aAAa,CAAA,CAAA;AAC5F,IAAA,OAAO,aAAA;AAAA,EACT;AAGA,EAAA,OAAO,SAAA;AACT;AAOO,SAAS,4BAA4B,IAAA,EAA+C;AACzF,EAAA,MAAM,QAAQ,KAAA,IAAS,IAAA;AAEvB,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,mBAAmB,CAAA;AAClD,IAAA,IAAA,GAAO,aAAA,IAAiB,aAAA,CAAc,aAAA,CAAc,IAAI,EAAE,CAAC,CAAA;AAAA,EAC7D,CAAA,MAAO;AACL,IAAA,MAAM,eAAA,GAAkB,sBAAA,CAAuB,IAAA,CAAK,KAAK,CAAA;AACzD,IAAA,IAAA,GAAO,aAAA,CAAc,eAAe,CAAA,CAAE,CAAC,CAAA;AAAA,EACzC;AAEA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,kBAAkB,KAAA,EAAiC;AACjE,EAAA,MAAM,YAAA,GAAe,8DAAA;AACrB,EAAA,MAAM,cAAA,GAAiB,kDAAA;AAEvB,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAA,CAAM,YAAY,CAAA;AAC3C,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,OAAO;AAAA,MACL,aAAA,EAAe,WAAW,CAAC,CAAA;AAAA,MAC3B,aAAA,EAAe,WAAW,CAAC;AAAA,KAC7B;AAAA,EACF;AAEA,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,cAAc,CAAA;AAC/C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,OAAO;AAAA,MACL,aAAA,EAAe,aAAa,CAAC,CAAA;AAAA,MAC7B,aAAA,EAAe;AAAA,KACjB;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,aAAA,EAAe,MAAA;AAAA,IACf,aAAA,EAAe;AAAA,GACjB;AACF;AASA,SAAS,kBAAkB,OAAA,EAAqD;AAC9E,EAAA,OAAO,YAAA,CAAa,OAAO,CAAA,IAAK,OAAO,QAAQ,KAAA,KAAU,QAAA;AAC3D;AAKA,SAAS,mBAAmB,OAAA,EAAsD;AAChF,EAAA,OACE,YAAA,CAAa,OAAO,CAAA,IACpB,OAAO,OAAA,CAAQ,aAAA,KAAkB,QAAA,IACjC,YAAA,CAAa,OAAA,CAAQ,UAAU,CAAA,IAC/B,YAAA,CAAa,OAAA,CAAQ,WAAW,cAAc,CAAA,IAC9C,OAAO,OAAA,CAAQ,UAAA,CAAW,cAAA,CAAe,UAAA,KAAe,QAAA,IACxD,OAAO,OAAA,CAAQ,UAAA,CAAW,cAAA,CAAe,OAAA,KAAY,QAAA;AAEzD;AAQO,SAAS,yBAAyB,OAAA,EAAoD;AAC3F,EAAA,IAAI;AACF,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAGtC,IAAA,IAAI,iBAAA,CAAkB,WAAW,CAAA,IAAK,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACrE,MAAA,OAAO,WAAA;AAAA,IACT;AAGA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAMO,MAAM,wBAAA,GAA2B,kBAAkB,yBAAyB;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"11.0.0-alpha.
|
|
1
|
+
{"type":"module","version":"11.0.0-alpha.1","sideEffects":false}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../src/profiling/index.ts"],"sourcesContent":["import type { Profiler } from '@sentry/core/browser';\nimport { debug, getClient } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Starts
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/profiling/index.ts"],"sourcesContent":["import type { Profiler } from '@sentry/core/browser';\nimport { debug, getClient } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Starts a manually controlled Sentry UI profiling session.\n *\n * Profiling starts only when the integration sampled the current session and `profileLifecycle` is `manual`.\n * While running, the profiler periodically sends profile chunks to Sentry until `stopProfiler()` is called.\n */\nfunction startProfiler(): void {\n const client = getClient();\n if (!client) {\n DEBUG_BUILD && debug.warn('No Sentry client available, profiling is not started');\n return;\n }\n\n const integration = client.getIntegrationByName('BrowserProfiling');\n\n if (!integration) {\n DEBUG_BUILD && debug.warn('BrowserProfiling integration is not available');\n return;\n }\n\n client.emit('startUIProfiler');\n}\n\n/**\n * Stops a manually controlled Sentry UI profiling session.\n *\n * Calls to stop will stop the profiler and flush the currently collected profile data to Sentry.\n */\nfunction stopProfiler(): void {\n const client = getClient();\n if (!client) {\n DEBUG_BUILD && debug.warn('No Sentry client available, profiling is not started');\n return;\n }\n\n const integration = client.getIntegrationByName('BrowserProfiling');\n if (!integration) {\n DEBUG_BUILD && debug.warn('ProfilingIntegration is not available');\n return;\n }\n\n client.emit('stopUIProfiler');\n}\n\n/**\n * Profiler namespace for controlling the JS profiler in 'manual' mode.\n *\n * Requires the `browserProfilingIntegration` from the `@sentry/browser` package.\n */\nexport const uiProfiler: Profiler = {\n startProfiler,\n stopProfiler,\n};\n"],"names":[],"mappings":";;;AAUA,SAAS,aAAA,GAAsB;AAC7B,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,WAAA,IAAe,KAAA,CAAM,KAAK,sDAAsD,CAAA;AAChF,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,oBAAA,CAAqB,kBAAkB,CAAA;AAElE,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,WAAA,IAAe,KAAA,CAAM,KAAK,+CAA+C,CAAA;AACzE,IAAA;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,KAAK,iBAAiB,CAAA;AAC/B;AAOA,SAAS,YAAA,GAAqB;AAC5B,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,WAAA,IAAe,KAAA,CAAM,KAAK,sDAAsD,CAAA;AAChF,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,oBAAA,CAAqB,kBAAkB,CAAA;AAClE,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,WAAA,IAAe,KAAA,CAAM,KAAK,uCAAuC,CAAA;AACjE,IAAA;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,KAAK,gBAAgB,CAAA;AAC9B;AAOO,MAAM,UAAA,GAAuB;AAAA,EAClC,aAAA;AAAA,EACA;AACF;;;;"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { defineIntegration,
|
|
1
|
+
import { defineIntegration, getActiveSpan, getRootSpan, hasSpansEnabled, debug } from '@sentry/core/browser';
|
|
2
2
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
3
|
import { WINDOW } from '../helpers.js';
|
|
4
|
-
import { startProfileForSpan } from './startProfileForSpan.js';
|
|
5
4
|
import { UIProfiler } from './UIProfiler.js';
|
|
6
|
-
import { hasLegacyProfiling, isAutomatedPageLoadSpan, shouldProfileSpanLegacy, PROFILED_ROOT_SPANS, setThreadAttributes, getActiveProfilesCount, findProfiledTransactionsFromEnvelope, takeProfileFromGlobalCache, createProfilingEvent, addProfilesToEnvelope } from './utils.js';
|
|
7
5
|
|
|
8
6
|
const INTEGRATION_NAME = "BrowserProfiling";
|
|
9
7
|
const _browserProfilingIntegration = (() => {
|
|
@@ -12,102 +10,34 @@ const _browserProfilingIntegration = (() => {
|
|
|
12
10
|
setup(client) {
|
|
13
11
|
const options = client.getOptions();
|
|
14
12
|
const profiler = new UIProfiler();
|
|
15
|
-
if (!
|
|
13
|
+
if (!options.profileLifecycle) {
|
|
16
14
|
options.profileLifecycle = "manual";
|
|
17
15
|
}
|
|
18
|
-
if (hasLegacyProfiling(options) && !options.profilesSampleRate) {
|
|
19
|
-
DEBUG_BUILD && debug.log("[Profiling] Profiling disabled, no profiling options found.");
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
16
|
const activeSpan = getActiveSpan();
|
|
23
17
|
const rootSpan = activeSpan && getRootSpan(activeSpan);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} else if (lifecycleMode === "trace") {
|
|
36
|
-
if (!hasSpansEnabled(options)) {
|
|
37
|
-
DEBUG_BUILD && debug.warn(
|
|
38
|
-
"[Profiling] `profileLifecycle` is 'trace' but tracing is disabled. Set a `tracesSampleRate` or `tracesSampler` to enable span tracing."
|
|
39
|
-
);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
profiler.initialize(client);
|
|
43
|
-
if (rootSpan) {
|
|
44
|
-
profiler.notifyRootSpanActive(rootSpan);
|
|
45
|
-
}
|
|
46
|
-
WINDOW.setTimeout(() => {
|
|
47
|
-
const laterActiveSpan = getActiveSpan();
|
|
48
|
-
const laterRootSpan = laterActiveSpan && getRootSpan(laterActiveSpan);
|
|
49
|
-
if (laterRootSpan) {
|
|
50
|
-
profiler.notifyRootSpanActive(laterRootSpan);
|
|
51
|
-
}
|
|
52
|
-
}, 0);
|
|
18
|
+
const lifecycleMode = options.profileLifecycle;
|
|
19
|
+
client.on("startUIProfiler", () => profiler.start());
|
|
20
|
+
client.on("stopUIProfiler", () => profiler.stop());
|
|
21
|
+
if (lifecycleMode === "manual") {
|
|
22
|
+
profiler.initialize(client);
|
|
23
|
+
} else if (lifecycleMode === "trace") {
|
|
24
|
+
if (!hasSpansEnabled(options)) {
|
|
25
|
+
DEBUG_BUILD && debug.warn(
|
|
26
|
+
"[Profiling] `profileLifecycle` is 'trace' but tracing is disabled. Set a `tracesSampleRate` or `tracesSampler` to enable span tracing."
|
|
27
|
+
);
|
|
28
|
+
return;
|
|
53
29
|
}
|
|
54
|
-
|
|
55
|
-
if (rootSpan
|
|
56
|
-
|
|
57
|
-
startProfileForSpan(rootSpan);
|
|
58
|
-
}
|
|
30
|
+
profiler.initialize(client);
|
|
31
|
+
if (rootSpan) {
|
|
32
|
+
profiler.notifyRootSpanActive(rootSpan);
|
|
59
33
|
}
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
} else if (PROFILED_ROOT_SPANS.has(rootSpan2)) {
|
|
67
|
-
setThreadAttributes(span);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
client.on("beforeEnvelope", (envelope) => {
|
|
71
|
-
if (!getActiveProfilesCount()) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);
|
|
75
|
-
if (!profiledTransactionEvents.length) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const profilesToAddToEnvelope = [];
|
|
79
|
-
for (const profiledTransaction of profiledTransactionEvents) {
|
|
80
|
-
const context = profiledTransaction?.contexts;
|
|
81
|
-
const profile_id = context?.profile?.["profile_id"];
|
|
82
|
-
const start_timestamp = context?.profile?.["start_timestamp"];
|
|
83
|
-
if (typeof profile_id !== "string") {
|
|
84
|
-
DEBUG_BUILD && debug.log("[Profiling] cannot find profile for a span without a profile context");
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (!profile_id) {
|
|
88
|
-
DEBUG_BUILD && debug.log("[Profiling] cannot find profile for a span without a profile context");
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (context?.profile) {
|
|
92
|
-
delete context.profile;
|
|
93
|
-
}
|
|
94
|
-
const profile = takeProfileFromGlobalCache(profile_id);
|
|
95
|
-
if (!profile) {
|
|
96
|
-
DEBUG_BUILD && debug.log(`[Profiling] Could not retrieve profile for span: ${profile_id}`);
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
const profileEvent = createProfilingEvent(
|
|
100
|
-
profile_id,
|
|
101
|
-
start_timestamp,
|
|
102
|
-
profile,
|
|
103
|
-
profiledTransaction
|
|
104
|
-
);
|
|
105
|
-
if (profileEvent) {
|
|
106
|
-
profilesToAddToEnvelope.push(profileEvent);
|
|
107
|
-
}
|
|
34
|
+
WINDOW.setTimeout(() => {
|
|
35
|
+
const laterActiveSpan = getActiveSpan();
|
|
36
|
+
const laterRootSpan = laterActiveSpan && getRootSpan(laterActiveSpan);
|
|
37
|
+
if (laterRootSpan) {
|
|
38
|
+
profiler.notifyRootSpanActive(laterRootSpan);
|
|
108
39
|
}
|
|
109
|
-
|
|
110
|
-
});
|
|
40
|
+
}, 0);
|
|
111
41
|
}
|
|
112
42
|
}
|
|
113
43
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.js","sources":["../../../../../src/profiling/integration.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"integration.js","sources":["../../../../../src/profiling/integration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core/browser';\nimport { debug, defineIntegration, getActiveSpan, getRootSpan, hasSpansEnabled } from '@sentry/core/browser';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport { UIProfiler } from './UIProfiler';\n\nconst INTEGRATION_NAME = 'BrowserProfiling' as const;\n\nconst _browserProfilingIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const options = client.getOptions() as BrowserOptions;\n const profiler = new UIProfiler();\n\n if (!options.profileLifecycle) {\n // Set default lifecycle mode\n options.profileLifecycle = 'manual';\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n const lifecycleMode = options.profileLifecycle;\n\n // Registering hooks in all lifecycle modes to be able to notify users in case they want to start/stop the profiler manually in `trace` mode\n client.on('startUIProfiler', () => profiler.start());\n client.on('stopUIProfiler', () => profiler.stop());\n\n if (lifecycleMode === 'manual') {\n profiler.initialize(client);\n } else if (lifecycleMode === 'trace') {\n if (!hasSpansEnabled(options)) {\n DEBUG_BUILD &&\n debug.warn(\n \"[Profiling] `profileLifecycle` is 'trace' but tracing is disabled. Set a `tracesSampleRate` or `tracesSampler` to enable span tracing.\",\n );\n return;\n }\n\n profiler.initialize(client);\n\n // If there is an active, sampled root span already, notify the profiler\n if (rootSpan) {\n profiler.notifyRootSpanActive(rootSpan);\n }\n\n // In case rootSpan is created slightly after setup -> schedule microtask to re-check and notify.\n WINDOW.setTimeout(() => {\n const laterActiveSpan = getActiveSpan();\n const laterRootSpan = laterActiveSpan && getRootSpan(laterActiveSpan);\n if (laterRootSpan) {\n profiler.notifyRootSpanActive(laterRootSpan);\n }\n }, 0);\n }\n },\n };\n}) satisfies IntegrationFn;\n\nexport const browserProfilingIntegration = defineIntegration(_browserProfilingIntegration);\n"],"names":[],"mappings":";;;;;AAOA,MAAM,gBAAA,GAAmB,kBAAA;AAEzB,MAAM,gCAAgC,MAAM;AAC1C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAQ;AACZ,MAAA,MAAM,OAAA,GAAU,OAAO,UAAA,EAAW;AAClC,MAAA,MAAM,QAAA,GAAW,IAAI,UAAA,EAAW;AAEhC,MAAA,IAAI,CAAC,QAAQ,gBAAA,EAAkB;AAE7B,QAAA,OAAA,CAAQ,gBAAA,GAAmB,QAAA;AAAA,MAC7B;AAEA,MAAA,MAAM,aAAa,aAAA,EAAc;AACjC,MAAA,MAAM,QAAA,GAAW,UAAA,IAAc,WAAA,CAAY,UAAU,CAAA;AACrD,MAAA,MAAM,gBAAgB,OAAA,CAAQ,gBAAA;AAG9B,MAAA,MAAA,CAAO,EAAA,CAAG,iBAAA,EAAmB,MAAM,QAAA,CAAS,OAAO,CAAA;AACnD,MAAA,MAAA,CAAO,EAAA,CAAG,gBAAA,EAAkB,MAAM,QAAA,CAAS,MAAM,CAAA;AAEjD,MAAA,IAAI,kBAAkB,QAAA,EAAU;AAC9B,QAAA,QAAA,CAAS,WAAW,MAAM,CAAA;AAAA,MAC5B,CAAA,MAAA,IAAW,kBAAkB,OAAA,EAAS;AACpC,QAAA,IAAI,CAAC,eAAA,CAAgB,OAAO,CAAA,EAAG;AAC7B,UAAA,WAAA,IACE,KAAA,CAAM,IAAA;AAAA,YACJ;AAAA,WACF;AACF,UAAA;AAAA,QACF;AAEA,QAAA,QAAA,CAAS,WAAW,MAAM,CAAA;AAG1B,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,QAAA,CAAS,qBAAqB,QAAQ,CAAA;AAAA,QACxC;AAGA,QAAA,MAAA,CAAO,WAAW,MAAM;AACtB,UAAA,MAAM,kBAAkB,aAAA,EAAc;AACtC,UAAA,MAAM,aAAA,GAAgB,eAAA,IAAmB,WAAA,CAAY,eAAe,CAAA;AACpE,UAAA,IAAI,aAAA,EAAe;AACjB,YAAA,QAAA,CAAS,qBAAqB,aAAa,CAAA;AAAA,UAC7C;AAAA,QACF,GAAG,CAAC,CAAA;AAAA,MACN;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;AAEO,MAAM,2BAAA,GAA8B,kBAAkB,4BAA4B;;;;"}
|
|
@@ -1,108 +1,10 @@
|
|
|
1
|
-
import { GLOBAL_OBJ,
|
|
1
|
+
import { GLOBAL_OBJ, debug, uuid4, browserPerformanceTimeOrigin, getClient, getDebugImagesForResources } from '@sentry/core/browser';
|
|
2
2
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
3
|
import { WINDOW } from '../helpers.js';
|
|
4
4
|
|
|
5
|
-
const MS_TO_NS = 1e6;
|
|
6
5
|
const isMainThread = "window" in GLOBAL_OBJ && GLOBAL_OBJ.window === GLOBAL_OBJ && typeof importScripts === "undefined";
|
|
7
6
|
const PROFILER_THREAD_ID_STRING = String(0);
|
|
8
7
|
const PROFILER_THREAD_NAME = isMainThread ? "main" : "worker";
|
|
9
|
-
const navigator = WINDOW.navigator;
|
|
10
|
-
let OS_PLATFORM = "";
|
|
11
|
-
let OS_PLATFORM_VERSION = "";
|
|
12
|
-
let OS_ARCH = "";
|
|
13
|
-
let OS_BROWSER = navigator?.userAgent || "";
|
|
14
|
-
let OS_MODEL = "";
|
|
15
|
-
const OS_LOCALE = navigator?.language || navigator?.languages?.[0] || "";
|
|
16
|
-
function isUserAgentData(data) {
|
|
17
|
-
return typeof data === "object" && data !== null && "getHighEntropyValues" in data;
|
|
18
|
-
}
|
|
19
|
-
const userAgentData = navigator?.userAgentData;
|
|
20
|
-
if (isUserAgentData(userAgentData)) {
|
|
21
|
-
userAgentData.getHighEntropyValues(["architecture", "model", "platform", "platformVersion", "fullVersionList"]).then((ua) => {
|
|
22
|
-
OS_PLATFORM = ua.platform || "";
|
|
23
|
-
OS_ARCH = ua.architecture || "";
|
|
24
|
-
OS_MODEL = ua.model || "";
|
|
25
|
-
OS_PLATFORM_VERSION = ua.platformVersion || "";
|
|
26
|
-
if (ua.fullVersionList?.length) {
|
|
27
|
-
const firstUa = ua.fullVersionList[ua.fullVersionList.length - 1];
|
|
28
|
-
OS_BROWSER = `${firstUa.brand} ${firstUa.version}`;
|
|
29
|
-
}
|
|
30
|
-
}).catch((e) => void 0);
|
|
31
|
-
}
|
|
32
|
-
function isProcessedJSSelfProfile(profile) {
|
|
33
|
-
return !("thread_metadata" in profile);
|
|
34
|
-
}
|
|
35
|
-
function enrichWithThreadInformation(profile) {
|
|
36
|
-
if (!isProcessedJSSelfProfile(profile)) {
|
|
37
|
-
return profile;
|
|
38
|
-
}
|
|
39
|
-
return convertJSSelfProfileToSampledFormat(profile);
|
|
40
|
-
}
|
|
41
|
-
function getTraceId(event) {
|
|
42
|
-
const traceId = event.contexts?.trace?.trace_id;
|
|
43
|
-
if (typeof traceId === "string" && traceId.length !== 32) {
|
|
44
|
-
if (DEBUG_BUILD) {
|
|
45
|
-
debug.log(`[Profiling] Invalid traceId: ${traceId} on profiled event`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (typeof traceId !== "string") {
|
|
49
|
-
return "";
|
|
50
|
-
}
|
|
51
|
-
return traceId;
|
|
52
|
-
}
|
|
53
|
-
function createProfilePayload(profile_id, start_timestamp, processed_profile, event) {
|
|
54
|
-
if (event.type !== "transaction") {
|
|
55
|
-
throw new TypeError("Profiling events may only be attached to transactions, this should never occur.");
|
|
56
|
-
}
|
|
57
|
-
if (processed_profile === void 0 || processed_profile === null) {
|
|
58
|
-
throw new TypeError(
|
|
59
|
-
`Cannot construct profiling event envelope without a valid profile. Got ${processed_profile} instead.`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
const traceId = getTraceId(event);
|
|
63
|
-
const enrichedThreadProfile = enrichWithThreadInformation(processed_profile);
|
|
64
|
-
const transactionStartMs = start_timestamp ? start_timestamp : typeof event.start_timestamp === "number" ? event.start_timestamp * 1e3 : timestampInSeconds() * 1e3;
|
|
65
|
-
const transactionEndMs = typeof event.timestamp === "number" ? event.timestamp * 1e3 : timestampInSeconds() * 1e3;
|
|
66
|
-
const profile = {
|
|
67
|
-
event_id: profile_id,
|
|
68
|
-
timestamp: new Date(transactionStartMs).toISOString(),
|
|
69
|
-
platform: "javascript",
|
|
70
|
-
version: "1",
|
|
71
|
-
release: event.release || "",
|
|
72
|
-
environment: event.environment || DEFAULT_ENVIRONMENT,
|
|
73
|
-
runtime: {
|
|
74
|
-
name: "javascript",
|
|
75
|
-
version: WINDOW.navigator.userAgent
|
|
76
|
-
},
|
|
77
|
-
os: {
|
|
78
|
-
name: OS_PLATFORM,
|
|
79
|
-
version: OS_PLATFORM_VERSION,
|
|
80
|
-
build_number: OS_BROWSER
|
|
81
|
-
},
|
|
82
|
-
device: {
|
|
83
|
-
locale: OS_LOCALE,
|
|
84
|
-
model: OS_MODEL,
|
|
85
|
-
manufacturer: OS_BROWSER,
|
|
86
|
-
architecture: OS_ARCH,
|
|
87
|
-
is_emulator: false
|
|
88
|
-
},
|
|
89
|
-
debug_meta: {
|
|
90
|
-
images: applyDebugMetadata(processed_profile.resources)
|
|
91
|
-
},
|
|
92
|
-
profile: enrichedThreadProfile,
|
|
93
|
-
transactions: [
|
|
94
|
-
{
|
|
95
|
-
name: event.transaction || "",
|
|
96
|
-
id: event.event_id || uuid4(),
|
|
97
|
-
trace_id: traceId,
|
|
98
|
-
active_thread_id: PROFILER_THREAD_ID_STRING,
|
|
99
|
-
relative_start_ns: "0",
|
|
100
|
-
relative_end_ns: ((transactionEndMs - transactionStartMs) * 1e6).toFixed(0)
|
|
101
|
-
}
|
|
102
|
-
]
|
|
103
|
-
};
|
|
104
|
-
return profile;
|
|
105
|
-
}
|
|
106
8
|
function createProfileChunkPayload(jsSelfProfile, client, profilerId) {
|
|
107
9
|
if (jsSelfProfile == null) {
|
|
108
10
|
throw new TypeError(
|
|
@@ -214,94 +116,6 @@ function convertToContinuousProfile(input) {
|
|
|
214
116
|
thread_metadata: { [PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME } }
|
|
215
117
|
};
|
|
216
118
|
}
|
|
217
|
-
function isAutomatedPageLoadSpan(span) {
|
|
218
|
-
return spanToJSON(span).op === "pageload";
|
|
219
|
-
}
|
|
220
|
-
function convertJSSelfProfileToSampledFormat(input) {
|
|
221
|
-
let EMPTY_STACK_ID = void 0;
|
|
222
|
-
let STACK_ID = 0;
|
|
223
|
-
const profile = {
|
|
224
|
-
samples: [],
|
|
225
|
-
stacks: [],
|
|
226
|
-
frames: [],
|
|
227
|
-
thread_metadata: {
|
|
228
|
-
[PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME }
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
const firstSample = input.samples[0];
|
|
232
|
-
if (!firstSample) {
|
|
233
|
-
return profile;
|
|
234
|
-
}
|
|
235
|
-
const start = firstSample.timestamp;
|
|
236
|
-
const perfOrigin = browserPerformanceTimeOrigin();
|
|
237
|
-
const origin = typeof performance.timeOrigin === "number" ? performance.timeOrigin : perfOrigin || 0;
|
|
238
|
-
const adjustForOriginChange = origin - (perfOrigin || origin);
|
|
239
|
-
input.samples.forEach((jsSample, i) => {
|
|
240
|
-
if (jsSample.stackId === void 0) {
|
|
241
|
-
if (EMPTY_STACK_ID === void 0) {
|
|
242
|
-
EMPTY_STACK_ID = STACK_ID;
|
|
243
|
-
profile.stacks[EMPTY_STACK_ID] = [];
|
|
244
|
-
STACK_ID++;
|
|
245
|
-
}
|
|
246
|
-
profile["samples"][i] = {
|
|
247
|
-
// convert ms timestamp to ns
|
|
248
|
-
elapsed_since_start_ns: ((jsSample.timestamp + adjustForOriginChange - start) * MS_TO_NS).toFixed(0),
|
|
249
|
-
stack_id: EMPTY_STACK_ID,
|
|
250
|
-
thread_id: PROFILER_THREAD_ID_STRING
|
|
251
|
-
};
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
let stackTop = input.stacks[jsSample.stackId];
|
|
255
|
-
const stack = [];
|
|
256
|
-
while (stackTop) {
|
|
257
|
-
stack.push(stackTop.frameId);
|
|
258
|
-
const frame = input.frames[stackTop.frameId];
|
|
259
|
-
if (frame && profile.frames[stackTop.frameId] === void 0) {
|
|
260
|
-
profile.frames[stackTop.frameId] = {
|
|
261
|
-
function: frame.name,
|
|
262
|
-
abs_path: typeof frame.resourceId === "number" ? input.resources[frame.resourceId] : void 0,
|
|
263
|
-
lineno: frame.line,
|
|
264
|
-
colno: frame.column
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
stackTop = stackTop.parentId === void 0 ? void 0 : input.stacks[stackTop.parentId];
|
|
268
|
-
}
|
|
269
|
-
const sample = {
|
|
270
|
-
// convert ms timestamp to ns
|
|
271
|
-
elapsed_since_start_ns: ((jsSample.timestamp + adjustForOriginChange - start) * MS_TO_NS).toFixed(0),
|
|
272
|
-
stack_id: STACK_ID,
|
|
273
|
-
thread_id: PROFILER_THREAD_ID_STRING
|
|
274
|
-
};
|
|
275
|
-
profile["stacks"][STACK_ID] = stack;
|
|
276
|
-
profile["samples"][i] = sample;
|
|
277
|
-
STACK_ID++;
|
|
278
|
-
});
|
|
279
|
-
return profile;
|
|
280
|
-
}
|
|
281
|
-
function addProfilesToEnvelope(envelope, profiles) {
|
|
282
|
-
if (!profiles.length) {
|
|
283
|
-
return envelope;
|
|
284
|
-
}
|
|
285
|
-
for (const profile of profiles) {
|
|
286
|
-
envelope[1].push([{ type: "profile" }, profile]);
|
|
287
|
-
}
|
|
288
|
-
return envelope;
|
|
289
|
-
}
|
|
290
|
-
function findProfiledTransactionsFromEnvelope(envelope) {
|
|
291
|
-
const events = [];
|
|
292
|
-
forEachEnvelopeItem(envelope, (item, type) => {
|
|
293
|
-
if (type !== "transaction") {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
for (let j = 1; j < item.length; j++) {
|
|
297
|
-
const event = item[j];
|
|
298
|
-
if (event?.contexts?.profile?.profile_id) {
|
|
299
|
-
events.push(item[j]);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
return events;
|
|
304
|
-
}
|
|
305
119
|
function applyDebugMetadata(resource_paths) {
|
|
306
120
|
const client = getClient();
|
|
307
121
|
const options = client?.getOptions();
|
|
@@ -329,21 +143,6 @@ function isValidSampleRate(rate) {
|
|
|
329
143
|
}
|
|
330
144
|
return true;
|
|
331
145
|
}
|
|
332
|
-
function isValidProfile(profile) {
|
|
333
|
-
if (profile.samples.length < 2) {
|
|
334
|
-
if (DEBUG_BUILD) {
|
|
335
|
-
debug.log("[Profiling] Discarding profile because it contains less than 2 samples");
|
|
336
|
-
}
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
if (!profile.frames.length) {
|
|
340
|
-
if (DEBUG_BUILD) {
|
|
341
|
-
debug.log("[Profiling] Discarding profile because it contains no frames");
|
|
342
|
-
}
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
return true;
|
|
346
|
-
}
|
|
347
146
|
let PROFILING_CONSTRUCTOR_FAILED = false;
|
|
348
147
|
const MAX_PROFILE_DURATION_MS = 3e4;
|
|
349
148
|
function isJSProfilerSupported(maybeProfiler) {
|
|
@@ -372,45 +171,6 @@ function startJSSelfProfile() {
|
|
|
372
171
|
}
|
|
373
172
|
return;
|
|
374
173
|
}
|
|
375
|
-
function shouldProfileSpanLegacy(span) {
|
|
376
|
-
if (PROFILING_CONSTRUCTOR_FAILED) {
|
|
377
|
-
if (DEBUG_BUILD) {
|
|
378
|
-
debug.log("[Profiling] Profiling has been disabled for the duration of the current user session.");
|
|
379
|
-
}
|
|
380
|
-
return false;
|
|
381
|
-
}
|
|
382
|
-
if (!span.isRecording()) {
|
|
383
|
-
DEBUG_BUILD && debug.log("[Profiling] Discarding profile because root span was not sampled.");
|
|
384
|
-
return false;
|
|
385
|
-
}
|
|
386
|
-
const client = getClient();
|
|
387
|
-
const options = client?.getOptions();
|
|
388
|
-
if (!options) {
|
|
389
|
-
DEBUG_BUILD && debug.log("[Profiling] Profiling disabled, no options found.");
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
const profilesSampleRate = options.profilesSampleRate;
|
|
393
|
-
if (!isValidSampleRate(profilesSampleRate)) {
|
|
394
|
-
DEBUG_BUILD && debug.warn("[Profiling] Discarding profile because of invalid sample rate.");
|
|
395
|
-
return false;
|
|
396
|
-
}
|
|
397
|
-
if (!profilesSampleRate) {
|
|
398
|
-
DEBUG_BUILD && debug.log(
|
|
399
|
-
"[Profiling] Discarding profile because a negative sampling decision was inherited or profileSampleRate is set to 0"
|
|
400
|
-
);
|
|
401
|
-
return false;
|
|
402
|
-
}
|
|
403
|
-
const sampled = profilesSampleRate === true ? true : Math.random() < profilesSampleRate;
|
|
404
|
-
if (!sampled) {
|
|
405
|
-
DEBUG_BUILD && debug.log(
|
|
406
|
-
`[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number(
|
|
407
|
-
profilesSampleRate
|
|
408
|
-
)})`
|
|
409
|
-
);
|
|
410
|
-
return false;
|
|
411
|
-
}
|
|
412
|
-
return true;
|
|
413
|
-
}
|
|
414
174
|
function shouldProfileSession(options) {
|
|
415
175
|
if (PROFILING_CONSTRUCTOR_FAILED) {
|
|
416
176
|
if (DEBUG_BUILD) {
|
|
@@ -435,40 +195,10 @@ function shouldProfileSession(options) {
|
|
|
435
195
|
}
|
|
436
196
|
return Math.random() <= profileSessionSampleRate;
|
|
437
197
|
}
|
|
438
|
-
function hasLegacyProfiling(options) {
|
|
439
|
-
return typeof options.profilesSampleRate !== "undefined";
|
|
440
|
-
}
|
|
441
|
-
function createProfilingEvent(profile_id, start_timestamp, profile, event) {
|
|
442
|
-
if (!isValidProfile(profile)) {
|
|
443
|
-
return null;
|
|
444
|
-
}
|
|
445
|
-
return createProfilePayload(profile_id, start_timestamp, profile, event);
|
|
446
|
-
}
|
|
447
|
-
const PROFILE_MAP = /* @__PURE__ */ new Map();
|
|
448
|
-
function getActiveProfilesCount() {
|
|
449
|
-
return PROFILE_MAP.size;
|
|
450
|
-
}
|
|
451
|
-
function takeProfileFromGlobalCache(profile_id) {
|
|
452
|
-
const profile = PROFILE_MAP.get(profile_id);
|
|
453
|
-
if (profile) {
|
|
454
|
-
PROFILE_MAP.delete(profile_id);
|
|
455
|
-
}
|
|
456
|
-
return profile;
|
|
457
|
-
}
|
|
458
|
-
function addProfileToGlobalCache(profile_id, profile) {
|
|
459
|
-
PROFILE_MAP.set(profile_id, profile);
|
|
460
|
-
if (PROFILE_MAP.size > 30) {
|
|
461
|
-
const last = PROFILE_MAP.keys().next().value;
|
|
462
|
-
if (last !== void 0) {
|
|
463
|
-
PROFILE_MAP.delete(last);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
const PROFILED_ROOT_SPANS = /* @__PURE__ */ new WeakSet();
|
|
468
198
|
function setThreadAttributes(span) {
|
|
469
199
|
span.setAttribute("thread.id", PROFILER_THREAD_ID_STRING);
|
|
470
200
|
span.setAttribute("thread.name", PROFILER_THREAD_NAME);
|
|
471
201
|
}
|
|
472
202
|
|
|
473
|
-
export { MAX_PROFILE_DURATION_MS,
|
|
203
|
+
export { MAX_PROFILE_DURATION_MS, PROFILER_THREAD_ID_STRING, PROFILER_THREAD_NAME, applyDebugMetadata, createProfileChunkPayload, isValidSampleRate, setThreadAttributes, shouldProfileSession, startJSSelfProfile, validateProfileChunk };
|
|
474
204
|
//# sourceMappingURL=utils.js.map
|