From 128ab44c58da6796425a491a5e516594789bef0a Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 3 Sep 2024 10:12:46 +0200 Subject: [PATCH 01/25] test(browser): Add integration test for `httpContextIntegration` (#13553) Add a test to our browser integration tests where we explicitly check that httpContextIntegration sets all its supported properties: url, user-agent and (previously untested) referer. --- .../suites/integrations/httpContext/init.js | 20 ++++++++++++++ .../integrations/httpContext/subject.js | 1 + .../suites/integrations/httpContext/test.ts | 26 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 dev-packages/browser-integration-tests/suites/integrations/httpContext/init.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/httpContext/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/httpContext/test.ts diff --git a/dev-packages/browser-integration-tests/suites/integrations/httpContext/init.js b/dev-packages/browser-integration-tests/suites/integrations/httpContext/init.js new file mode 100644 index 000000000000..984534454ac7 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/httpContext/init.js @@ -0,0 +1,20 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +const integrations = Sentry.getDefaultIntegrations({}).filter( + defaultIntegration => defaultIntegration.name === 'HttpContext', +); + +const client = new Sentry.BrowserClient({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + transport: Sentry.makeFetchTransport, + stackParser: Sentry.defaultStackParser, + integrations: integrations, +}); + +const scope = new Sentry.Scope(); +scope.setClient(client); +client.init(); + +window._sentryScope = scope; diff --git a/dev-packages/browser-integration-tests/suites/integrations/httpContext/subject.js b/dev-packages/browser-integration-tests/suites/integrations/httpContext/subject.js new file mode 100644 index 000000000000..62ce205e2ffc --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/httpContext/subject.js @@ -0,0 +1 @@ +window._sentryScope.captureException(new Error('client init')); diff --git a/dev-packages/browser-integration-tests/suites/integrations/httpContext/test.ts b/dev-packages/browser-integration-tests/suites/integrations/httpContext/test.ts new file mode 100644 index 000000000000..02a62142e02b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/httpContext/test.ts @@ -0,0 +1,26 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/types'; + +import { sentryTest } from '../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../utils/helpers'; + +sentryTest('httpContextIntegration captures user-agent and referrer', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const errorEventPromise = getFirstSentryEnvelopeRequest(page); + + // Simulate document.referrer being set to test full functionality of the integration + await page.goto(url, { referer: 'https://sentry.io/' }); + + const errorEvent = await errorEventPromise; + + expect(errorEvent.exception?.values).toHaveLength(1); + + expect(errorEvent.request).toEqual({ + headers: { + 'User-Agent': expect.any(String), + Referer: 'https://sentry.io/', + }, + url: expect.any(String), + }); +}); From 47743990e3e2249e5c48ec3639bb849deda5db50 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein <83657429+Zen-cronic@users.noreply.github.com> Date: Tue, 3 Sep 2024 08:04:47 -0400 Subject: [PATCH 02/25] feat(node): Add `generic-pool` integration (#13465) Resolves #13308 Implement genericPool OTL instrumentation in `packages/node` - [x] If you've added code that should be tested, please add tests. - [x] Ensure your code lints and the test suite passes (`yarn lint`) & (`yarn test`). --------- Signed-off-by: Kaung Zin Hein --- .../node-integration-tests/package.json | 1 + .../suites/tracing/genericPool/scenario.js | 71 +++++++++++++++++++ .../suites/tracing/genericPool/test.ts | 34 +++++++++ packages/astro/src/index.server.ts | 1 + packages/aws-serverless/src/index.ts | 1 + packages/bun/src/index.ts | 1 + packages/google-cloud-serverless/src/index.ts | 1 + packages/node/package.json | 1 + packages/node/src/index.ts | 1 + .../src/integrations/tracing/genericPool.ts | 40 +++++++++++ .../node/src/integrations/tracing/index.ts | 3 + packages/remix/src/index.server.ts | 1 + packages/solidstart/src/server/index.ts | 1 + packages/sveltekit/src/server/index.ts | 1 + yarn.lock | 9 ++- 15 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js create mode 100644 dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts create mode 100644 packages/node/src/integrations/tracing/genericPool.ts diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index 9243a1512884..0ac7fdbf0aa2 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -44,6 +44,7 @@ "cors": "^2.8.5", "cron": "^3.1.6", "express": "^4.17.3", + "generic-pool": "^3.9.0", "graphql": "^16.3.0", "http-terminator": "^3.2.0", "ioredis": "^5.4.1", diff --git a/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js b/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js new file mode 100644 index 000000000000..74d5f73693f5 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js @@ -0,0 +1,71 @@ +const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +const Sentry = require('@sentry/node'); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); + +// Stop the process from exiting before the transaction is sent +setInterval(() => {}, 1000); + +const mysql = require('mysql'); +const genericPool = require('generic-pool'); + +const factory = { + create: function () { + return mysql.createConnection({ + user: 'root', + password: 'docker', + }); + }, + destroy: function (client) { + client.end(err => { + if (err) { + // eslint-disable-next-line no-console + console.error('Error while disconnecting MySQL:', err); + } + }); + }, +}; + +const opts = { + max: 10, + min: 2, +}; + +const myPool = genericPool.createPool(factory, opts); + +async function run() { + await Sentry.startSpan( + { + op: 'transaction', + name: 'Test Transaction', + }, + async () => { + try { + const client1 = await myPool.acquire(); + const client2 = await myPool.acquire(); + + client1.query('SELECT NOW()', function () { + myPool.release(client1); + }); + + client2.query('SELECT 1 + 1 AS solution', function () { + myPool.release(client2); + }); + } catch (err) { + // eslint-disable-next-line no-console + console.error('Error while pooling MySQL:', err); + } finally { + await myPool.drain(); + await myPool.clear(); + } + }, + ); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts new file mode 100644 index 000000000000..a61782ae0fe5 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts @@ -0,0 +1,34 @@ +import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; + +describe('genericPool auto instrumentation', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + test('should auto-instrument `genericPool` package when calling pool.require()', done => { + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + description: expect.stringMatching(/^generic-pool\.ac?quire/), + origin: 'auto.db.otel.generic-pool', + data: { + 'sentry.origin': 'auto.db.otel.generic-pool', + }, + status: 'ok', + }), + + expect.objectContaining({ + description: expect.stringMatching(/^generic-pool\.ac?quire/), + origin: 'auto.db.otel.generic-pool', + data: { + 'sentry.origin': 'auto.db.otel.generic-pool', + }, + status: 'ok', + }), + ]), + }; + + createRunner(__dirname, 'scenario.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done); + }); +}); diff --git a/packages/astro/src/index.server.ts b/packages/astro/src/index.server.ts index 0895eb86e364..747870da3014 100644 --- a/packages/astro/src/index.server.ts +++ b/packages/astro/src/index.server.ts @@ -43,6 +43,7 @@ export { fsIntegration, functionToStringIntegration, generateInstrumentOnce, + genericPoolIntegration, getActiveSpan, getAutoPerformanceIntegrations, getClient, diff --git a/packages/aws-serverless/src/index.ts b/packages/aws-serverless/src/index.ts index 27f48c2da0db..f648dba045ec 100644 --- a/packages/aws-serverless/src/index.ts +++ b/packages/aws-serverless/src/index.ts @@ -87,6 +87,7 @@ export { setupConnectErrorHandler, fastifyIntegration, fsIntegration, + genericPoolIntegration, graphqlIntegration, mongoIntegration, mongooseIntegration, diff --git a/packages/bun/src/index.ts b/packages/bun/src/index.ts index d4ca06f85584..1d8b02c33568 100644 --- a/packages/bun/src/index.ts +++ b/packages/bun/src/index.ts @@ -108,6 +108,7 @@ export { setupKoaErrorHandler, connectIntegration, setupConnectErrorHandler, + genericPoolIntegration, graphqlIntegration, mongoIntegration, mongooseIntegration, diff --git a/packages/google-cloud-serverless/src/index.ts b/packages/google-cloud-serverless/src/index.ts index f58305c64f6c..463a0c5c1246 100644 --- a/packages/google-cloud-serverless/src/index.ts +++ b/packages/google-cloud-serverless/src/index.ts @@ -87,6 +87,7 @@ export { connectIntegration, setupConnectErrorHandler, fastifyIntegration, + genericPoolIntegration, graphqlIntegration, mongoIntegration, mongooseIntegration, diff --git a/packages/node/package.json b/packages/node/package.json index f17c37541f63..6a64f646f64c 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -73,6 +73,7 @@ "@opentelemetry/instrumentation-express": "0.41.1", "@opentelemetry/instrumentation-fastify": "0.38.0", "@opentelemetry/instrumentation-fs": "0.14.0", + "@opentelemetry/instrumentation-generic-pool": "0.38.0", "@opentelemetry/instrumentation-graphql": "0.42.0", "@opentelemetry/instrumentation-hapi": "0.40.0", "@opentelemetry/instrumentation-http": "0.52.1", diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 5f4adf315fd5..6ce3c325e3ff 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -26,6 +26,7 @@ export { hapiIntegration, setupHapiErrorHandler } from './integrations/tracing/h export { koaIntegration, setupKoaErrorHandler } from './integrations/tracing/koa'; export { connectIntegration, setupConnectErrorHandler } from './integrations/tracing/connect'; export { spotlightIntegration } from './integrations/spotlight'; +export { genericPoolIntegration } from './integrations/tracing/genericPool'; export { SentryContextManager } from './otel/contextManager'; export { generateInstrumentOnce } from './otel/instrument'; diff --git a/packages/node/src/integrations/tracing/genericPool.ts b/packages/node/src/integrations/tracing/genericPool.ts new file mode 100644 index 000000000000..55b8b6095f64 --- /dev/null +++ b/packages/node/src/integrations/tracing/genericPool.ts @@ -0,0 +1,40 @@ +import { GenericPoolInstrumentation } from '@opentelemetry/instrumentation-generic-pool'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core'; +import type { IntegrationFn } from '@sentry/types'; +import { generateInstrumentOnce } from '../../otel/instrument'; + +const INTEGRATION_NAME = 'GenericPool'; + +export const instrumentGenericPool = generateInstrumentOnce(INTEGRATION_NAME, () => new GenericPoolInstrumentation({})); + +const _genericPoolIntegration = (() => { + return { + name: INTEGRATION_NAME, + setupOnce() { + instrumentGenericPool(); + }, + + setup(client) { + client.on('spanStart', span => { + const spanJSON = spanToJSON(span); + + const spanDescription = spanJSON.description; + + // typo in emitted span for version <= 0.38.0 of @opentelemetry/instrumentation-generic-pool + const isGenericPoolSpan = + spanDescription === 'generic-pool.aquire' || spanDescription === 'generic-pool.acquire'; + + if (isGenericPoolSpan) { + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.generic-pool'); + } + }); + }, + }; +}) satisfies IntegrationFn; + +/** + * GenericPool integration + * + * Capture tracing data for GenericPool. + */ +export const genericPoolIntegration = defineIntegration(_genericPoolIntegration); diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 886c11683674..46a9f79e4caa 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -4,6 +4,7 @@ import { instrumentHttp } from '../http'; import { connectIntegration, instrumentConnect } from './connect'; import { expressIntegration, instrumentExpress } from './express'; import { fastifyIntegration, instrumentFastify } from './fastify'; +import { genericPoolIntegration, instrumentGenericPool } from './genericPool'; import { graphqlIntegration, instrumentGraphql } from './graphql'; import { hapiIntegration, instrumentHapi } from './hapi'; import { instrumentKoa, koaIntegration } from './koa'; @@ -37,6 +38,7 @@ export function getAutoPerformanceIntegrations(): Integration[] { hapiIntegration(), koaIntegration(), connectIntegration(), + genericPoolIntegration(), ]; } @@ -61,5 +63,6 @@ export function getOpenTelemetryInstrumentationToPreload(): (((options?: any) => instrumentHapi, instrumentGraphql, instrumentRedis, + instrumentGenericPool, ]; } diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts index 7ab6efb15827..457dcb9f8685 100644 --- a/packages/remix/src/index.server.ts +++ b/packages/remix/src/index.server.ts @@ -47,6 +47,7 @@ export { flush, functionToStringIntegration, generateInstrumentOnce, + genericPoolIntegration, getActiveSpan, getAutoPerformanceIntegrations, getClient, diff --git a/packages/solidstart/src/server/index.ts b/packages/solidstart/src/server/index.ts index c3499a82459a..995f58d057e3 100644 --- a/packages/solidstart/src/server/index.ts +++ b/packages/solidstart/src/server/index.ts @@ -38,6 +38,7 @@ export { flush, functionToStringIntegration, generateInstrumentOnce, + genericPoolIntegration, getActiveSpan, getAutoPerformanceIntegrations, getClient, diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts index 32dd6627d7a6..d57ec35bd7cc 100644 --- a/packages/sveltekit/src/server/index.ts +++ b/packages/sveltekit/src/server/index.ts @@ -37,6 +37,7 @@ export { fastifyIntegration, flush, functionToStringIntegration, + genericPoolIntegration, generateInstrumentOnce, getActiveSpan, getAutoPerformanceIntegrations, diff --git a/yarn.lock b/yarn.lock index 6f2432d7054a..1acd7e11fbd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7113,6 +7113,13 @@ "@opentelemetry/core" "^1.8.0" "@opentelemetry/instrumentation" "^0.52.0" +"@opentelemetry/instrumentation-generic-pool@0.38.0": + version "0.38.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.38.0.tgz#9ea4d82da23541cda613d553bd405b2cbc0da184" + integrity sha512-0/ULi6pIco1fEnDPmmAul8ZoudFL7St0hjgBbWZlZPBCSyslDll1J7DFeEbjiRSSyUd+0tu73ae0DOKVKNd7VA== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation-graphql@0.42.0": version "0.42.0" resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.42.0.tgz#588a18c39e3b3f655bc09243566172ab0b638d35" @@ -19084,7 +19091,7 @@ generate-function@^2.3.1: dependencies: is-property "^1.0.2" -generic-pool@3.9.0: +generic-pool@3.9.0, generic-pool@^3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4" integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g== From b7d154440fc8d40f1154c67129dc80cc8723d184 Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:34:55 +0200 Subject: [PATCH 03/25] feat(vue): Only start UI spans if parent is available (#13568) UI spans make sense if they are a child of e.g. a pageload root span. This change ensures UI spans are not created as root spans. ref https://github.com/getsentry/sentry-javascript/issues/13546 --- packages/vue/src/tracing.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vue/src/tracing.ts b/packages/vue/src/tracing.ts index 70f662559adf..135b7fa8c9cc 100644 --- a/packages/vue/src/tracing.ts +++ b/packages/vue/src/tracing.ts @@ -114,6 +114,8 @@ export const createTracingMixins = (options: TracingOptions): Mixins => { attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.vue', }, + // UI spans should only be created if there is an active root span (transaction) + onlyIfParent: true, }); } } else { From 3180113e7a62fb283298fa47364d2d6bef6d37b0 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 3 Sep 2024 16:50:28 +0200 Subject: [PATCH 04/25] ci: Show what size limit jobs exceeded the limit (#13532) Noticed that it was a bit annoying, when we exceeded the size limit, to find out why/what has failed. Now, it should show in the GH comment which specific check has failed, and what the current limit is: ![image](https://github.com/user-attachments/assets/13495922-ac91-42bf-a398-18bb7b0e9e72) While I was at this, I also streamlined the code a bit, extracted it a bit into utils to de-clutter stuff, and fixed/improved some debug logging issues (e.g. the log group was not correctly closed before, ...) --- .../size-limit-gh-action/.eslintrc.cjs | 2 +- dev-packages/size-limit-gh-action/index.mjs | 319 +++--------------- .../utils/SizeLimitFormatter.mjs | 137 ++++++++ .../getArtifactsForBranchAndWorkflow.mjs | 128 +++++++ 4 files changed, 312 insertions(+), 274 deletions(-) create mode 100644 dev-packages/size-limit-gh-action/utils/SizeLimitFormatter.mjs create mode 100644 dev-packages/size-limit-gh-action/utils/getArtifactsForBranchAndWorkflow.mjs diff --git a/dev-packages/size-limit-gh-action/.eslintrc.cjs b/dev-packages/size-limit-gh-action/.eslintrc.cjs index 8c67e0037908..4a92730d3b0b 100644 --- a/dev-packages/size-limit-gh-action/.eslintrc.cjs +++ b/dev-packages/size-limit-gh-action/.eslintrc.cjs @@ -7,7 +7,7 @@ module.exports = { overrides: [ { - files: ['*.mjs'], + files: ['**/*.mjs'], extends: ['@sentry-internal/sdk/src/base'], }, ], diff --git a/dev-packages/size-limit-gh-action/index.mjs b/dev-packages/size-limit-gh-action/index.mjs index 3dbb8aa22127..680d12237bf5 100644 --- a/dev-packages/size-limit-gh-action/index.mjs +++ b/dev-packages/size-limit-gh-action/index.mjs @@ -1,4 +1,3 @@ -/* eslint-disable max-lines */ import { promises as fs } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -9,13 +8,22 @@ import { exec } from '@actions/exec'; import { context, getOctokit } from '@actions/github'; import * as glob from '@actions/glob'; import * as io from '@actions/io'; -import bytes from 'bytes'; import { markdownTable } from 'markdown-table'; +import { SizeLimitFormatter } from './utils/SizeLimitFormatter.mjs'; +import { getArtifactsForBranchAndWorkflow } from './utils/getArtifactsForBranchAndWorkflow.mjs'; + const SIZE_LIMIT_HEADING = '## size-limit report 📦 '; const ARTIFACT_NAME = 'size-limit-action'; const RESULTS_FILE = 'size-limit-results.json'; +function getResultsFilePath() { + const __dirname = path.dirname(fileURLToPath(import.meta.url)); + return path.resolve(__dirname, RESULTS_FILE); +} + +const { getInput, setFailed } = core; + async function fetchPreviousComment(octokit, repo, pr) { const { data: commentList } = await octokit.rest.issues.listComments({ ...repo, @@ -26,114 +34,6 @@ async function fetchPreviousComment(octokit, repo, pr) { return !sizeLimitComment ? null : sizeLimitComment; } -class SizeLimit { - formatBytes(size) { - return bytes.format(size, { unitSeparator: ' ' }); - } - - formatPercentageChange(base = 0, current = 0) { - if (base === 0) { - return 'added'; - } - - if (current === 0) { - return 'removed'; - } - - const value = ((current - base) / base) * 100; - const formatted = (Math.sign(value) * Math.ceil(Math.abs(value) * 100)) / 100; - - if (value > 0) { - return `+${formatted}%`; - } - - if (value === 0) { - return '-'; - } - - return `${formatted}%`; - } - - formatChange(base = 0, current = 0) { - if (base === 0) { - return 'added'; - } - - if (current === 0) { - return 'removed'; - } - - const value = current - base; - const formatted = this.formatBytes(value); - - if (value > 0) { - return `+${formatted} 🔺`; - } - - if (value === 0) { - return '-'; - } - - return `${formatted} 🔽`; - } - - formatLine(value, change) { - return `${value} (${change})`; - } - - formatSizeResult(name, base, current) { - return [ - name, - this.formatBytes(current.size), - this.formatPercentageChange(base.size, current.size), - this.formatChange(base.size, current.size), - ]; - } - - parseResults(output) { - const results = JSON.parse(output); - - return results.reduce((current, result) => { - return { - // biome-ignore lint/performance/noAccumulatingSpread: - ...current, - [result.name]: { - name: result.name, - size: +result.size, - }, - }; - }, {}); - } - - hasSizeChanges(base, current, threshold = 0) { - const names = [...new Set([...(base ? Object.keys(base) : []), ...Object.keys(current)])]; - - return !!names.find(name => { - const baseResult = base?.[name] || EmptyResult; - const currentResult = current[name] || EmptyResult; - - if (baseResult.size === 0 && currentResult.size === 0) { - return true; - } - - return Math.abs((currentResult.size - baseResult.size) / baseResult.size) * 100 > threshold; - }); - } - - formatResults(base, current) { - const names = [...new Set([...(base ? Object.keys(base) : []), ...Object.keys(current)])]; - const header = SIZE_RESULTS_HEADER; - const fields = names.map(name => { - const baseResult = base?.[name] || EmptyResult; - const currentResult = current[name] || EmptyResult; - - return this.formatSizeResult(name, baseResult, currentResult); - }); - - return [header, ...fields]; - } -} - async function execSizeLimit() { let output = ''; @@ -151,15 +51,8 @@ async function execSizeLimit() { return { status, output }; } -const SIZE_RESULTS_HEADER = ['Path', 'Size', '% Change', 'Change']; - -const EmptyResult = { - name: '-', - size: 0, -}; - async function run() { - const { getInput, setFailed } = core; + const __dirname = path.dirname(fileURLToPath(import.meta.url)); try { const { payload, repo } = context; @@ -174,36 +67,12 @@ async function run() { } const octokit = getOctokit(githubToken); - const limit = new SizeLimit(); - const artifactClient = artifact.create(); - const __dirname = path.dirname(fileURLToPath(import.meta.url)); - const resultsFilePath = path.resolve(__dirname, RESULTS_FILE); + const limit = new SizeLimitFormatter(); + const resultsFilePath = getResultsFilePath(); // If we have no comparison branch, we just run size limit & store the result as artifact if (!comparisonBranch) { - let base; - const { output: baseOutput } = await execSizeLimit(); - - try { - base = limit.parseResults(baseOutput); - } catch (error) { - core.error('Error parsing size-limit output. The output should be a json.'); - throw error; - } - - try { - await fs.writeFile(resultsFilePath, JSON.stringify(base), 'utf8'); - } catch (err) { - core.error(err); - } - const globber = await glob.create(resultsFilePath, { - followSymbolicLinks: false, - }); - const files = await globber.glob(); - - await artifactClient.uploadArtifact(ARTIFACT_NAME, files, __dirname); - - return; + return runSizeLimitOnComparisonBranch(); } // Else, we run size limit for the current branch, AND fetch it for the comparison branch @@ -213,12 +82,15 @@ async function run() { let baseWorkflowRun; try { + const workflowName = `${process.env.GITHUB_WORKFLOW || ''}`; + core.startGroup(`getArtifactsForBranchAndWorkflow - workflow:"${workflowName}", branch:"${comparisonBranch}"`); const artifacts = await getArtifactsForBranchAndWorkflow(octokit, { ...repo, artifactName: ARTIFACT_NAME, branch: comparisonBranch, - workflowName: `${process.env.GITHUB_WORKFLOW || ''}`, + workflowName, }); + core.endGroup(); if (!artifacts) { throw new Error('No artifacts found'); @@ -255,9 +127,12 @@ async function run() { const thresholdNumber = Number(threshold); - // @ts-ignore const sizeLimitComment = await fetchPreviousComment(octokit, repo, pr); + if (sizeLimitComment) { + core.debug('Found existing size limit comment, udpating it instead of creating a new one...'); + } + const shouldComment = isNaN(thresholdNumber) || limit.hasSizeChanges(base, current, thresholdNumber) || sizeLimitComment; @@ -269,8 +144,12 @@ async function run() { '⚠️ **Warning:** Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.', ); } - - bodyParts.push(markdownTable(limit.formatResults(base, current))); + try { + bodyParts.push(markdownTable(limit.formatResults(base, current))); + } catch (error) { + core.error('Error generating markdown table'); + core.error(error); + } if (baseWorkflowRun) { bodyParts.push(''); @@ -298,6 +177,8 @@ async function run() { "Error updating comment. This can happen for PR's originating from a fork without write permissions.", ); } + } else { + core.debug('Skipping comment because there are no changes.'); } if (status > 0) { @@ -309,136 +190,28 @@ async function run() { } } -// max pages of workflows to pagination through -const DEFAULT_MAX_PAGES = 50; -// max results per page -const DEFAULT_PAGE_LIMIT = 10; - -/** - * Fetch artifacts from a workflow run from a branch - * - * This is a bit hacky since GitHub Actions currently does not directly - * support downloading artifacts from other workflows - */ -/** - * Fetch artifacts from a workflow run from a branch - * - * This is a bit hacky since GitHub Actions currently does not directly - * support downloading artifacts from other workflows - */ -async function getArtifactsForBranchAndWorkflow(octokit, { owner, repo, workflowName, branch, artifactName }) { - core.startGroup(`getArtifactsForBranchAndWorkflow - workflow:"${workflowName}", branch:"${branch}"`); - - let repositoryWorkflow = null; +async function runSizeLimitOnComparisonBranch() { + const resultsFilePath = getResultsFilePath(); - // For debugging - const allWorkflows = []; - - // - // Find workflow id from `workflowName` - // - for await (const response of octokit.paginate.iterator(octokit.rest.actions.listRepoWorkflows, { - owner, - repo, - })) { - const targetWorkflow = response.data.find(({ name }) => name === workflowName); + const limit = new SizeLimitFormatter(); + const artifactClient = artifact.create(); - allWorkflows.push(...response.data.map(({ name }) => name)); + const { output: baseOutput } = await execSizeLimit(); - // If not found in responses, continue to search on next page - if (!targetWorkflow) { - continue; - } - - repositoryWorkflow = targetWorkflow; - break; - } - - if (!repositoryWorkflow) { - core.info( - `Unable to find workflow with name "${workflowName}" in the repository. Found workflows: ${allWorkflows.join( - ', ', - )}`, - ); - core.endGroup(); - return null; + try { + const base = limit.parseResults(baseOutput); + await fs.writeFile(resultsFilePath, JSON.stringify(base), 'utf8'); + } catch (error) { + core.error('Error parsing size-limit output. The output should be a json.'); + throw error; } - const workflow_id = repositoryWorkflow.id; - - let currentPage = 0; - let latestWorkflowRun = null; - - for await (const response of octokit.paginate.iterator(octokit.rest.actions.listWorkflowRuns, { - owner, - repo, - workflow_id, - branch, - per_page: DEFAULT_PAGE_LIMIT, - event: 'push', - })) { - if (!response.data.length) { - core.warning(`Workflow ${workflow_id} not found in branch ${branch}`); - core.endGroup(); - return null; - } - - // Do not allow downloading artifacts from a fork. - const filtered = response.data.filter(workflowRun => workflowRun.head_repository.full_name === `${owner}/${repo}`); - - // Sort to ensure the latest workflow run is the first - filtered.sort((a, b) => { - return new Date(b.created_at).getTime() - new Date(a.created_at).getTime(); - }); - - // Store the first workflow run, to determine if this is the latest one... - if (!latestWorkflowRun) { - latestWorkflowRun = filtered[0]; - } - - // Search through workflow artifacts until we find a workflow run w/ artifact name that we are looking for - for (const workflowRun of filtered) { - core.info(`Checking artifacts for workflow run: ${workflowRun.html_url}`); - - const { - data: { artifacts }, - } = await octokit.rest.actions.listWorkflowRunArtifacts({ - owner, - repo, - run_id: workflowRun.id, - }); - - if (!artifacts) { - core.warning( - `Unable to fetch artifacts for branch: ${branch}, workflow: ${workflow_id}, workflowRunId: ${workflowRun.id}`, - ); - } else { - const foundArtifact = artifacts.find(({ name }) => name === artifactName); - if (foundArtifact) { - core.info(`Found suitable artifact: ${foundArtifact.url}`); - return { - artifact: foundArtifact, - workflowRun, - isLatest: latestWorkflowRun.id === workflowRun.id, - }; - } else { - core.info(`No artifact found for ${artifactName}, trying next workflow run...`); - } - } - } - - if (currentPage > DEFAULT_MAX_PAGES) { - core.warning(`Workflow ${workflow_id} not found in branch: ${branch}`); - core.endGroup(); - return null; - } - - currentPage++; - } + const globber = await glob.create(resultsFilePath, { + followSymbolicLinks: false, + }); + const files = await globber.glob(); - core.warning(`Artifact not found: ${artifactName}`); - core.endGroup(); - return null; + await artifactClient.uploadArtifact(ARTIFACT_NAME, files, __dirname); } run(); diff --git a/dev-packages/size-limit-gh-action/utils/SizeLimitFormatter.mjs b/dev-packages/size-limit-gh-action/utils/SizeLimitFormatter.mjs new file mode 100644 index 000000000000..034281b38224 --- /dev/null +++ b/dev-packages/size-limit-gh-action/utils/SizeLimitFormatter.mjs @@ -0,0 +1,137 @@ +import * as core from '@actions/core'; +import bytes from 'bytes'; + +const SIZE_RESULTS_HEADER = ['Path', 'Size', '% Change', 'Change']; + +const EmptyResult = { + name: '-', + size: 0, +}; + +export class SizeLimitFormatter { + formatBytes(size) { + return bytes.format(size, { unitSeparator: ' ' }); + } + + formatName(name, sizeLimit, passed) { + if (passed) { + return name; + } + + return `⛔️ ${name} (max: ${this.formatBytes(sizeLimit)})`; + } + + formatPercentageChange(base = 0, current = 0) { + if (base === 0) { + return 'added'; + } + + if (current === 0) { + return 'removed'; + } + + const value = ((current - base) / base) * 100; + const formatted = (Math.sign(value) * Math.ceil(Math.abs(value) * 100)) / 100; + + if (value > 0) { + return `+${formatted}%`; + } + + if (value === 0) { + return '-'; + } + + return `${formatted}%`; + } + + formatChange(base = 0, current = 0) { + if (base === 0) { + return 'added'; + } + + if (current === 0) { + return 'removed'; + } + + const value = current - base; + const formatted = this.formatBytes(value); + + if (value > 0) { + return `+${formatted} 🔺`; + } + + if (value === 0) { + return '-'; + } + + return `${formatted} 🔽`; + } + + formatLine(value, change) { + return `${value} (${change})`; + } + + formatSizeResult(name, base, current) { + if (!current.passed) { + core.debug( + `Size limit exceeded for ${name} - ${this.formatBytes(current.size)} > ${this.formatBytes(current.sizeLimit)}`, + ); + } + + return [ + this.formatName(name, current.sizeLimit, current.passed), + this.formatBytes(current.size), + this.formatPercentageChange(base.size, current.size), + this.formatChange(base.size, current.size), + ]; + } + + parseResults(output) { + const results = JSON.parse(output); + + return results.reduce((current, result) => { + return { + // biome-ignore lint/performance/noAccumulatingSpread: + ...current, + [result.name]: { + name: result.name, + size: +result.size, + sizeLimit: +result.sizeLimit, + passed: result.passed || false, + }, + }; + }, {}); + } + + hasSizeChanges(base, current, threshold = 0) { + if (!base || !current) { + return true; + } + + const names = [...new Set([...Object.keys(base), ...Object.keys(current)])]; + + return names.some(name => { + const baseResult = base[name] || EmptyResult; + const currentResult = current[name] || EmptyResult; + + if (!baseResult.size || !currentResult.size) { + return true; + } + + return Math.abs((currentResult.size - baseResult.size) / baseResult.size) * 100 > threshold; + }); + } + + formatResults(base, current) { + const names = [...new Set([...(base ? Object.keys(base) : []), ...Object.keys(current)])]; + const header = SIZE_RESULTS_HEADER; + const fields = names.map(name => { + const baseResult = base?.[name] || EmptyResult; + const currentResult = current[name] || EmptyResult; + + return this.formatSizeResult(name, baseResult, currentResult); + }); + + return [header, ...fields]; + } +} diff --git a/dev-packages/size-limit-gh-action/utils/getArtifactsForBranchAndWorkflow.mjs b/dev-packages/size-limit-gh-action/utils/getArtifactsForBranchAndWorkflow.mjs new file mode 100644 index 000000000000..6d512b46afe1 --- /dev/null +++ b/dev-packages/size-limit-gh-action/utils/getArtifactsForBranchAndWorkflow.mjs @@ -0,0 +1,128 @@ +import * as core from '@actions/core'; + +// max pages of workflows to pagination through +const DEFAULT_MAX_PAGES = 50; +// max results per page +const DEFAULT_PAGE_LIMIT = 10; + +/** + * Fetch artifacts from a workflow run from a branch + * + * This is a bit hacky since GitHub Actions currently does not directly + * support downloading artifacts from other workflows + */ +/** + * Fetch artifacts from a workflow run from a branch + * + * This is a bit hacky since GitHub Actions currently does not directly + * support downloading artifacts from other workflows + */ +export async function getArtifactsForBranchAndWorkflow(octokit, { owner, repo, workflowName, branch, artifactName }) { + let repositoryWorkflow = null; + + // For debugging + const allWorkflows = []; + + // + // Find workflow id from `workflowName` + // + for await (const response of octokit.paginate.iterator(octokit.rest.actions.listRepoWorkflows, { + owner, + repo, + })) { + const targetWorkflow = response.data.find(({ name }) => name === workflowName); + + allWorkflows.push(...response.data.map(({ name }) => name)); + + // If not found in responses, continue to search on next page + if (!targetWorkflow) { + continue; + } + + repositoryWorkflow = targetWorkflow; + break; + } + + if (!repositoryWorkflow) { + core.info( + `Unable to find workflow with name "${workflowName}" in the repository. Found workflows: ${allWorkflows.join( + ', ', + )}`, + ); + return null; + } + + const workflow_id = repositoryWorkflow.id; + + let currentPage = 0; + let latestWorkflowRun = null; + + for await (const response of octokit.paginate.iterator(octokit.rest.actions.listWorkflowRuns, { + owner, + repo, + workflow_id, + branch, + per_page: DEFAULT_PAGE_LIMIT, + event: 'push', + })) { + if (!response.data.length) { + core.warning(`Workflow ${workflow_id} not found in branch ${branch}`); + return null; + } + + // Do not allow downloading artifacts from a fork. + const filtered = response.data.filter(workflowRun => workflowRun.head_repository.full_name === `${owner}/${repo}`); + + // Sort to ensure the latest workflow run is the first + filtered.sort((a, b) => { + return new Date(b.created_at).getTime() - new Date(a.created_at).getTime(); + }); + + // Store the first workflow run, to determine if this is the latest one... + if (!latestWorkflowRun) { + latestWorkflowRun = filtered[0]; + } + + // Search through workflow artifacts until we find a workflow run w/ artifact name that we are looking for + for (const workflowRun of filtered) { + core.info(`Checking artifacts for workflow run: ${workflowRun.html_url}`); + + const { + data: { artifacts }, + } = await octokit.rest.actions.listWorkflowRunArtifacts({ + owner, + repo, + run_id: workflowRun.id, + }); + + if (!artifacts) { + core.warning( + `Unable to fetch artifacts for branch: ${branch}, workflow: ${workflow_id}, workflowRunId: ${workflowRun.id}`, + ); + } else { + const foundArtifact = artifacts.find(({ name }) => name === artifactName); + if (foundArtifact) { + core.info(`Found suitable artifact: ${foundArtifact.url}`); + return { + artifact: foundArtifact, + workflowRun, + isLatest: latestWorkflowRun.id === workflowRun.id, + }; + } else { + core.info(`No artifact found for ${artifactName}, trying next workflow run...`); + } + } + } + + if (currentPage > DEFAULT_MAX_PAGES) { + core.warning(`Workflow ${workflow_id} not found in branch: ${branch}`); + return null; + } + + currentPage++; + } + + core.warning(`Artifact not found: ${artifactName}`); + core.endGroup(); + return null; +} From f5ef4705d513d18f5b1e68932d9d704ea322c708 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:06:21 +0000 Subject: [PATCH 05/25] ref: Add external contributor to CHANGELOG.md (#13569) This PR adds the external contributor to the CHANGELOG.md file, so that they are credited for their contribution. See #13465 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 015c5370a75a..234c9e5704a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +Work in this release was contributed by @Zen-cronic. Thank you for your contribution! + ## 8.28.0 ### Important Changes From d5f9f9da8d6dd1bd203a95ccbae2bfe4559553a0 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:04:51 -0400 Subject: [PATCH 06/25] fix(replay): Fix types in WebVitalData (#13573) Fixes attribution type: when adding an attribution in CLS we add {`value`, `nodeIds`} not {`value`, `sources`} --- packages/replay-internal/src/types/performance.ts | 2 +- packages/replay-internal/src/util/createPerformanceEntries.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/replay-internal/src/types/performance.ts b/packages/replay-internal/src/types/performance.ts index 7a60e51684f3..b3dcab0e7dd7 100644 --- a/packages/replay-internal/src/types/performance.ts +++ b/packages/replay-internal/src/types/performance.ts @@ -114,7 +114,7 @@ export interface WebVitalData { /** * The layout shifts of a CLS metric */ - attributions?: { value: number; sources?: number[] }[]; + attributions?: { value: number; nodeIds?: number[] }[]; } /** diff --git a/packages/replay-internal/src/util/createPerformanceEntries.ts b/packages/replay-internal/src/util/createPerformanceEntries.ts index 830f878dc8ea..0c22ba73163a 100644 --- a/packages/replay-internal/src/util/createPerformanceEntries.ts +++ b/packages/replay-internal/src/util/createPerformanceEntries.ts @@ -198,7 +198,7 @@ export function getLargestContentfulPaint(metric: Metric): ReplayPerformanceEntr return getWebVital(metric, 'largest-contentful-paint', node); } -function isLayoutShift(entry: PerformanceEntry | LayoutShift): entry is LayoutShift { +function isLayoutShift(entry: PerformanceEntry): entry is LayoutShift { return (entry as LayoutShift).sources !== undefined; } From 2393064cce4ae9335296c1a4e2d3131473b6feee Mon Sep 17 00:00:00 2001 From: Andrei <168741329+andreiborza@users.noreply.github.com> Date: Wed, 4 Sep 2024 00:39:28 +0200 Subject: [PATCH 07/25] chore(ci): Retain and upload traces on e2e-tests failures (#13562) --- .github/workflows/build.yml | 9 +++++++++ dev-packages/test-utils/src/playwright-config.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f06228f3a7e..77ddae4705b6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1003,6 +1003,15 @@ jobs: working-directory: dev-packages/e2e-tests/test-applications/${{ matrix.test-application }} timeout-minutes: 5 run: pnpm test:assert + + - name: Upload Playwright Traces + uses: actions/upload-artifact@v4 + if: failure() + with: + name: playwright-traces-job_e2e_playwright_tests-${{ matrix.test-application}} + path: dev-packages/e2e-tests/test-applications/${{ matrix.test-application}}/test-results + overwrite: true + retention-days: 7 job_optional_e2e_tests: name: E2E ${{ matrix.label || matrix.test-application }} Test diff --git a/dev-packages/test-utils/src/playwright-config.ts b/dev-packages/test-utils/src/playwright-config.ts index da2a10d0b477..d30c8cad4475 100644 --- a/dev-packages/test-utils/src/playwright-config.ts +++ b/dev-packages/test-utils/src/playwright-config.ts @@ -46,7 +46,7 @@ export function getPlaywrightConfig( baseURL: `http://localhost:${appPort}`, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: 'retain-on-failure', }, /* Configure projects for major browsers */ From d929462e250120796097ed7a802e1dd14858a882 Mon Sep 17 00:00:00 2001 From: Andrei <168741329+andreiborza@users.noreply.github.com> Date: Wed, 4 Sep 2024 00:40:19 +0200 Subject: [PATCH 08/25] feat(solidstart): Add `browserTracingIntegration` by default (#13561) Closes: #13352 --- packages/solidstart/src/client/sdk.ts | 29 ++++++++++++- packages/solidstart/test/client/sdk.test.ts | 45 +++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/packages/solidstart/src/client/sdk.ts b/packages/solidstart/src/client/sdk.ts index f44a2134ce50..8b1b6f7f39d5 100644 --- a/packages/solidstart/src/client/sdk.ts +++ b/packages/solidstart/src/client/sdk.ts @@ -1,13 +1,21 @@ import { applySdkMetadata } from '@sentry/core'; import type { BrowserOptions } from '@sentry/solid'; -import { init as initSolidSDK } from '@sentry/solid'; -import type { Client } from '@sentry/types'; +import { + browserTracingIntegration, + getDefaultIntegrations as getDefaultSolidIntegrations, + init as initSolidSDK, +} from '@sentry/solid'; +import type { Client, Integration } from '@sentry/types'; + +// Treeshakable guard to remove all code related to tracing +declare const __SENTRY_TRACING__: boolean; /** * Initializes the client side of the Solid Start SDK. */ export function init(options: BrowserOptions): Client | undefined { const opts = { + defaultIntegrations: getDefaultIntegrations(options), ...options, }; @@ -15,3 +23,20 @@ export function init(options: BrowserOptions): Client | undefined { return initSolidSDK(opts); } + +function getDefaultIntegrations(options: BrowserOptions): Integration[] { + const integrations = getDefaultSolidIntegrations(options); + + // This evaluates to true unless __SENTRY_TRACING__ is text-replaced with "false", + // in which case everything inside will get tree-shaken away + if (typeof __SENTRY_TRACING__ === 'undefined' || __SENTRY_TRACING__) { + // We add the default BrowserTracingIntegration here always. + // We can do this, even if `solidRouterBrowserTracingIntegration` is + // supplied as integration in `init` by users because it will win + // over the default integration by virtue of having the same + // `BrowserTracing` integration name and being added later. + integrations.push(browserTracingIntegration()); + } + + return integrations; +} diff --git a/packages/solidstart/test/client/sdk.test.ts b/packages/solidstart/test/client/sdk.test.ts index 886bb29b515d..b242e03ceb70 100644 --- a/packages/solidstart/test/client/sdk.test.ts +++ b/packages/solidstart/test/client/sdk.test.ts @@ -3,6 +3,7 @@ import * as SentrySolid from '@sentry/solid'; import { vi } from 'vitest'; import { init as solidStartInit } from '../../src/client'; +import { solidRouterBrowserTracingIntegration } from '../../src/client/solidrouter'; const browserInit = vi.spyOn(SentrySolid, 'init'); @@ -34,3 +35,47 @@ describe('Initialize Solid Start SDK', () => { expect(browserInit).toHaveBeenLastCalledWith(expect.objectContaining(expectedMetadata)); }); }); + +describe('browserTracingIntegration', () => { + it('adds the `browserTracingIntegration` when `__SENTRY_TRACING__` is not set', () => { + const client = solidStartInit({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + }); + + const browserTracingIntegration = client + ?.getOptions() + .integrations.find(integration => integration.name === 'BrowserTracing'); + expect(browserTracingIntegration).toBeDefined(); + expect(browserTracingIntegration!.isDefaultInstance).toEqual(true); + }); + + it("doesn't add the `browserTracingIntegration` if `__SENTRY_TRACING__` is false", () => { + // @ts-expect-error Test setup for build-time flag + globalThis.__SENTRY_TRACING__ = false; + + const client = solidStartInit({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + }); + + const browserTracingIntegration = client + ?.getOptions() + .integrations.find(integration => integration.name === 'BrowserTracing'); + expect(browserTracingIntegration).toBeUndefined(); + + // @ts-expect-error Test setup for build-time flag + delete globalThis.__SENTRY_TRACING__; + }); + + it("doesn't add the default `browserTracingIntegration` if `solidBrowserTracingIntegration` was already passed in", () => { + const client = solidStartInit({ + integrations: [solidRouterBrowserTracingIntegration()], + dsn: 'https://public@dsn.ingest.sentry.io/1337', + }); + + const browserTracingIntegration = client + ?.getOptions() + .integrations.find(integration => integration.name === 'BrowserTracing'); + expect(browserTracingIntegration).toBeDefined(); + expect(browserTracingIntegration!.isDefaultInstance).toBeUndefined(); + }); +}); From 5c05bd829f9b118ad5b2477ec149f489088e68f2 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 4 Sep 2024 09:57:09 +0200 Subject: [PATCH 09/25] fix(utils): Keep logger on carrier (#13570) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today, if you have a pluggable integration, it will incorrectly use it's own logger, which will generally be disabled. This is because we inline all the logger code into the bundle, but the logger is never enabled. Now, the logger is kept as a singleton on the carrier, ensuring that we always use the same logger. I added browser integration tests to cover this - especially one in feedback which failed before. NOTE: This is still not really ideal, because we still include the whole `makeLogger` code in each pluggable integration that uses the logger 🤔 but we can look into this later - now, at least logging should work for pluggable integrations. --- .../suites/feedback/attachTo/init.js | 17 ++++ .../suites/feedback/attachTo/template.html | 9 ++ .../suites/feedback/attachTo/test.ts | 82 +++++++++++++++++++ .../suites/feedback/logger/init.js | 19 +++++ .../suites/feedback/logger/test.ts | 36 ++++++++ .../httpclient/httpClientIntegration/init.js | 11 --- .../httpClientIntegration/subject.js | 8 -- .../httpclient/httpClientIntegration/test.ts | 64 --------------- .../suites/replay/logger/init.js | 18 ++++ .../suites/replay/logger/test.ts | 36 ++++++++ .../utils/generatePlugin.ts | 1 - packages/utils/src/logger.ts | 8 +- packages/utils/src/worldwide.ts | 2 + 13 files changed, 225 insertions(+), 86 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/feedback/attachTo/init.js create mode 100644 dev-packages/browser-integration-tests/suites/feedback/attachTo/template.html create mode 100644 dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/feedback/logger/init.js create mode 100644 dev-packages/browser-integration-tests/suites/feedback/logger/test.ts delete mode 100644 dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/init.js delete mode 100644 dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/subject.js delete mode 100644 dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/replay/logger/init.js create mode 100644 dev-packages/browser-integration-tests/suites/replay/logger/test.ts diff --git a/dev-packages/browser-integration-tests/suites/feedback/attachTo/init.js b/dev-packages/browser-integration-tests/suites/feedback/attachTo/init.js new file mode 100644 index 000000000000..5eb27143fdc7 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/attachTo/init.js @@ -0,0 +1,17 @@ +import * as Sentry from '@sentry/browser'; +// Import this separately so that generatePlugin can handle it for CDN scenarios +import { feedbackIntegration } from '@sentry/browser'; + +const feedback = feedbackIntegration({ + autoInject: false, +}); + +window.Sentry = Sentry; +window.feedback = feedback; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [feedback], +}); + +feedback.attachTo('#custom-feedback-buttom'); diff --git a/dev-packages/browser-integration-tests/suites/feedback/attachTo/template.html b/dev-packages/browser-integration-tests/suites/feedback/attachTo/template.html new file mode 100644 index 000000000000..ae36b0c69c7b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/attachTo/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts b/dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts new file mode 100644 index 000000000000..507b08685092 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts @@ -0,0 +1,82 @@ +import { expect } from '@playwright/test'; + +import { TEST_HOST, sentryTest } from '../../../utils/fixtures'; +import { envelopeRequestParser, getEnvelopeType, shouldSkipFeedbackTest } from '../../../utils/helpers'; + +sentryTest('should capture feedback with custom button', async ({ getLocalTestUrl, page }) => { + if (shouldSkipFeedbackTest()) { + sentryTest.skip(); + } + + const feedbackRequestPromise = page.waitForResponse(res => { + const req = res.request(); + + const postData = req.postData(); + if (!postData) { + return false; + } + + try { + return getEnvelopeType(req) === 'feedback'; + } catch (err) { + return false; + } + }); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + await page.locator('#custom-feedback-buttom').click(); + await page.waitForSelector(':visible:text-is("Report a Bug")'); + + expect(await page.locator(':visible:text-is("Report a Bug")').count()).toEqual(1); + await page.locator('[name="name"]').fill('Jane Doe'); + await page.locator('[name="email"]').fill('janedoe@example.org'); + await page.locator('[name="message"]').fill('my example feedback'); + await page.locator('[data-sentry-feedback] .btn--primary').click(); + + const feedbackEvent = envelopeRequestParser((await feedbackRequestPromise).request()); + expect(feedbackEvent).toEqual({ + type: 'feedback', + breadcrumbs: expect.any(Array), + contexts: { + feedback: { + contact_email: 'janedoe@example.org', + message: 'my example feedback', + name: 'Jane Doe', + source: 'widget', + url: `${TEST_HOST}/index.html`, + }, + trace: { + trace_id: expect.stringMatching(/\w{32}/), + span_id: expect.stringMatching(/\w{16}/), + }, + }, + level: 'info', + timestamp: expect.any(Number), + event_id: expect.stringMatching(/\w{32}/), + environment: 'production', + tags: {}, + sdk: { + integrations: expect.arrayContaining(['Feedback']), + version: expect.any(String), + name: 'sentry.javascript.browser', + packages: expect.anything(), + }, + request: { + url: `${TEST_HOST}/index.html`, + headers: { + 'User-Agent': expect.stringContaining(''), + }, + }, + platform: 'javascript', + }); +}); diff --git a/dev-packages/browser-integration-tests/suites/feedback/logger/init.js b/dev-packages/browser-integration-tests/suites/feedback/logger/init.js new file mode 100644 index 000000000000..3251bd6c7a4c --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/logger/init.js @@ -0,0 +1,19 @@ +import * as Sentry from '@sentry/browser'; +// Import this separately so that generatePlugin can handle it for CDN scenarios +import { feedbackIntegration } from '@sentry/browser'; + +const feedback = feedbackIntegration({ + autoInject: false, +}); + +window.Sentry = Sentry; +window.feedback = feedback; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + debug: true, + integrations: [feedback], +}); + +// This should log an error! +feedback.attachTo('#does-not-exist'); diff --git a/dev-packages/browser-integration-tests/suites/feedback/logger/test.ts b/dev-packages/browser-integration-tests/suites/feedback/logger/test.ts new file mode 100644 index 000000000000..34fadfc2503b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/logger/test.ts @@ -0,0 +1,36 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../utils/fixtures'; +import { shouldSkipFeedbackTest } from '../../../utils/helpers'; + +/** + * This test is mostly relevant for ensuring that the logger works in all combinations of CDN bundles. + * Even if feedback is included via the CDN, this test ensures that the logger is working correctly. + */ +sentryTest('should log error correctly', async ({ getLocalTestUrl, page }) => { + // In minified bundles we do not have logger messages, so we skip the test + if (shouldSkipFeedbackTest() || (process.env.PW_BUNDLE || '').includes('_min')) { + sentryTest.skip(); + } + + const messages: string[] = []; + + page.on('console', message => { + messages.push(message.text()); + }); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + expect(messages).toContain('Sentry Logger [log]: Integration installed: Feedback'); + expect(messages).toContain('Sentry Logger [error]: [Feedback] Unable to attach to target element'); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/init.js b/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/init.js deleted file mode 100644 index 8540ab176c38..000000000000 --- a/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/init.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as Sentry from '@sentry/browser'; -import { httpClientIntegration } from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [httpClientIntegration()], - tracesSampleRate: 1, - sendDefaultPii: true, -}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/subject.js b/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/subject.js deleted file mode 100644 index 563b069e66cc..000000000000 --- a/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/subject.js +++ /dev/null @@ -1,8 +0,0 @@ -const xhr = new XMLHttpRequest(); - -xhr.open('GET', 'http://sentry-test.io/foo', true); -xhr.withCredentials = true; -xhr.setRequestHeader('Accept', 'application/json'); -xhr.setRequestHeader('Content-Type', 'application/json'); -xhr.setRequestHeader('Cache', 'no-cache'); -xhr.send(); diff --git a/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/test.ts b/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/test.ts deleted file mode 100644 index f064a8652b48..000000000000 --- a/dev-packages/browser-integration-tests/suites/integrations/httpclient/httpClientIntegration/test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { expect } from '@playwright/test'; -import type { Event } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; - -sentryTest('works with httpClientIntegration', async ({ getLocalTestPath, page }) => { - const url = await getLocalTestPath({ testDir: __dirname }); - - await page.route('**/foo', route => { - return route.fulfill({ - status: 500, - body: JSON.stringify({ - error: { - message: 'Internal Server Error', - }, - }), - headers: { - 'Content-Type': 'text/html', - }, - }); - }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - - expect(eventData.exception?.values).toHaveLength(1); - - // Not able to get the cookies from the request/response because of Playwright bug - // https://github.com/microsoft/playwright/issues/11035 - expect(eventData).toMatchObject({ - message: 'HTTP Client Error with status code: 500', - exception: { - values: [ - { - type: 'Error', - value: 'HTTP Client Error with status code: 500', - mechanism: { - type: 'http.client', - handled: false, - }, - }, - ], - }, - request: { - url: 'http://sentry-test.io/foo', - method: 'GET', - headers: { - accept: 'application/json', - cache: 'no-cache', - 'content-type': 'application/json', - }, - }, - contexts: { - response: { - status_code: 500, - body_size: 45, - headers: { - 'content-type': 'text/html', - 'content-length': '45', - }, - }, - }, - }); -}); diff --git a/dev-packages/browser-integration-tests/suites/replay/logger/init.js b/dev-packages/browser-integration-tests/suites/replay/logger/init.js new file mode 100644 index 000000000000..195be16ddad3 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/replay/logger/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = Sentry.replayIntegration({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay], +}); diff --git a/dev-packages/browser-integration-tests/suites/replay/logger/test.ts b/dev-packages/browser-integration-tests/suites/replay/logger/test.ts new file mode 100644 index 000000000000..fa034a12b003 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/replay/logger/test.ts @@ -0,0 +1,36 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../utils/fixtures'; +import { shouldSkipReplayTest, waitForReplayRequest } from '../../../utils/replayHelpers'; + +sentryTest('should output logger messages', async ({ getLocalTestPath, page }) => { + // In minified bundles we do not have logger messages, so we skip the test + if (shouldSkipReplayTest() || (process.env.PW_BUNDLE || '').includes('_min')) { + sentryTest.skip(); + } + + const messages: string[] = []; + + page.on('console', message => { + messages.push(message.text()); + }); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const reqPromise0 = waitForReplayRequest(page, 0); + + const url = await getLocalTestPath({ testDir: __dirname }); + + await Promise.all([page.goto(url), reqPromise0]); + + expect(messages).toContain('Sentry Logger [log]: Integration installed: Replay'); + expect(messages).toContain('Sentry Logger [info]: [Replay] Creating new session'); + expect(messages).toContain('Sentry Logger [info]: [Replay] Starting replay in session mode'); + expect(messages).toContain('Sentry Logger [info]: [Replay] Using compression worker'); +}); diff --git a/dev-packages/browser-integration-tests/utils/generatePlugin.ts b/dev-packages/browser-integration-tests/utils/generatePlugin.ts index 9189ce63812f..acc583506df4 100644 --- a/dev-packages/browser-integration-tests/utils/generatePlugin.ts +++ b/dev-packages/browser-integration-tests/utils/generatePlugin.ts @@ -30,7 +30,6 @@ const useLoader = bundleKey.startsWith('loader'); const IMPORTED_INTEGRATION_CDN_BUNDLE_PATHS: Record = { httpClientIntegration: 'httpclient', captureConsoleIntegration: 'captureconsole', - CaptureConsole: 'captureconsole', debugIntegration: 'debug', rewriteFramesIntegration: 'rewriteframes', contextLinesIntegration: 'contextlines', diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index e996d87202b2..533b59fd5882 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -1,7 +1,7 @@ import type { ConsoleLevel } from '@sentry/types'; import { DEBUG_BUILD } from './debug-build'; -import { GLOBAL_OBJ } from './worldwide'; +import { GLOBAL_OBJ, getGlobalSingleton } from './worldwide'; /** Prefix for logging strings */ const PREFIX = 'Sentry Logger '; @@ -97,4 +97,8 @@ function makeLogger(): Logger { return logger as Logger; } -export const logger = makeLogger(); +/** + * This is a logger singleton which either logs things or no-ops if logging is not enabled. + * The logger is a singleton on the carrier, to ensure that a consistent logger is used throughout the SDK. + */ +export const logger = getGlobalSingleton('logger', makeLogger); diff --git a/packages/utils/src/worldwide.ts b/packages/utils/src/worldwide.ts index e323f12034a2..2a1ca7b958d8 100644 --- a/packages/utils/src/worldwide.ts +++ b/packages/utils/src/worldwide.ts @@ -15,6 +15,7 @@ import type { Client, MetricsAggregator, Scope } from '@sentry/types'; import type { SdkSource } from './env'; +import type { logger } from './logger'; import { SDK_VERSION } from './version'; interface SentryCarrier { @@ -25,6 +26,7 @@ interface SentryCarrier { defaultIsolationScope?: Scope; defaultCurrentScope?: Scope; globalMetricsAggregators?: WeakMap | undefined; + logger?: typeof logger; /** Overwrites TextEncoder used in `@sentry/utils`, need for `react-native@0.73` and older */ encodePolyfill?: (input: string) => Uint8Array; From ec7d9e3d632fc7b805771f6e8d08c0cb9a2c0349 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 4 Sep 2024 11:08:08 +0200 Subject: [PATCH 10/25] ci: Update size-limit to ensure bundle size optimization (#13571) I wanted to add a new entry for size limit with sentry browser with max. tree shaking. While doing this, I noticed that bundle size did not shrink as much as I would have expected it. After playing around some, I noticed that it was not actually shaking out the constant changes, for whatever reason. Probably some size-limit internal default config. Now, i actually add terser to ensure it fully minimizes & tree shakes stuff for us. --- .size-limit.js | 37 ++++ .../browser-integration-tests/package.json | 2 +- .../bundle-analyzer-scenarios/package.json | 2 +- packages/ember/package.json | 2 +- packages/nextjs/package.json | 2 +- yarn.lock | 197 ++---------------- 6 files changed, 56 insertions(+), 186 deletions(-) diff --git a/.size-limit.js b/.size-limit.js index d2211d91d5b0..5da293511976 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -10,6 +10,31 @@ module.exports = [ gzip: true, limit: '24 KB', }, + { + name: '@sentry/browser - with treeshaking flags', + path: 'packages/browser/build/npm/esm/index.js', + import: createImport('init'), + gzip: true, + limit: '24 KB', + modifyWebpackConfig: function (config) { + const webpack = require('webpack'); + const TerserPlugin = require('terser-webpack-plugin'); + + config.plugins.push( + new webpack.DefinePlugin({ + __SENTRY_DEBUG__: false, + __RRWEB_EXCLUDE_SHADOW_DOM__: true, + __RRWEB_EXCLUDE_IFRAME__: true, + __SENTRY_EXCLUDE_REPLAY_WORKER__: true, + }), + ); + + config.optimization.minimize = true; + config.optimization.minimizer = [new TerserPlugin()]; + + return config; + }, + }, { name: '@sentry/browser (incl. Tracing)', path: 'packages/browser/build/npm/esm/index.js', @@ -32,6 +57,8 @@ module.exports = [ limit: '68 KB', modifyWebpackConfig: function (config) { const webpack = require('webpack'); + const TerserPlugin = require('terser-webpack-plugin'); + config.plugins.push( new webpack.DefinePlugin({ __SENTRY_DEBUG__: false, @@ -40,6 +67,10 @@ module.exports = [ __SENTRY_EXCLUDE_REPLAY_WORKER__: true, }), ); + + config.optimization.minimize = true; + config.optimization.minimizer = [new TerserPlugin()]; + return config; }, }, @@ -222,11 +253,17 @@ module.exports = [ ignore: [...builtinModules, ...nodePrefixedBuiltinModules], modifyWebpackConfig: function (config) { const webpack = require('webpack'); + const TerserPlugin = require('terser-webpack-plugin'); + config.plugins.push( new webpack.DefinePlugin({ __SENTRY_TRACING__: false, }), ); + + config.optimization.minimize = true; + config.optimization.minimizer = [new TerserPlugin()]; + return config; }, }, diff --git a/dev-packages/browser-integration-tests/package.json b/dev-packages/browser-integration-tests/package.json index 886f91d328fb..d012484a4e0b 100644 --- a/dev-packages/browser-integration-tests/package.json +++ b/dev-packages/browser-integration-tests/package.json @@ -48,7 +48,7 @@ "babel-loader": "^8.2.2", "html-webpack-plugin": "^5.5.0", "pako": "^2.1.0", - "webpack": "^5.90.3" + "webpack": "^5.94.0" }, "devDependencies": { "@types/glob": "8.0.0", diff --git a/dev-packages/bundle-analyzer-scenarios/package.json b/dev-packages/bundle-analyzer-scenarios/package.json index 6cec8aa83b2f..b1375418e16f 100644 --- a/dev-packages/bundle-analyzer-scenarios/package.json +++ b/dev-packages/bundle-analyzer-scenarios/package.json @@ -9,7 +9,7 @@ "private": true, "dependencies": { "html-webpack-plugin": "^5.6.0", - "webpack": "^5.92.1", + "webpack": "^5.94.0", "webpack-bundle-analyzer": "^4.10.2" }, "scripts": { diff --git a/packages/ember/package.json b/packages/ember/package.json index 2ff37964532e..1bec2d30f9bf 100644 --- a/packages/ember/package.json +++ b/packages/ember/package.json @@ -80,7 +80,7 @@ "qunit": "~2.19.2", "qunit-dom": "~2.0.0", "sinon": "15.2.0", - "webpack": "~5.90.3" + "webpack": "~5.94.0" }, "engines": { "node": ">=14.18" diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 6965ddcf5167..354870f6e834 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -91,7 +91,7 @@ }, "peerDependencies": { "next": "^13.2.0 || ^14.0 || ^15.0.0-rc.0", - "webpack": ">= 5.0.0" + "webpack": "5.94.0" }, "peerDependenciesMeta": { "webpack": { diff --git a/yarn.lock b/yarn.lock index 1acd7e11fbd9..b0a8c712e374 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9681,17 +9681,7 @@ dependencies: "@types/unist" "*" -"@types/history-4@npm:@types/history@4.7.8": - version "4.7.8" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" - integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== - -"@types/history-5@npm:@types/history@4.7.8": - version "4.7.8" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" - integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== - -"@types/history@*": +"@types/history-4@npm:@types/history@4.7.8", "@types/history-5@npm:@types/history@4.7.8", "@types/history@*": version "4.7.8" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== @@ -10012,15 +10002,7 @@ "@types/history" "^3" "@types/react" "*" -"@types/react-router-4@npm:@types/react-router@5.1.14": - version "5.1.14" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" - integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== - dependencies: - "@types/history" "*" - "@types/react" "*" - -"@types/react-router-5@npm:@types/react-router@5.1.14": +"@types/react-router-4@npm:@types/react-router@5.1.14", "@types/react-router-5@npm:@types/react-router@5.1.14": version "5.1.14" resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== @@ -10931,14 +10913,6 @@ "@webassemblyjs/helper-numbers" "1.11.1" "@webassemblyjs/helper-wasm-bytecode" "1.11.1" -"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" - integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" @@ -10972,11 +10946,6 @@ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== -"@webassemblyjs/helper-buffer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" - integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== - "@webassemblyjs/helper-buffer@1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" @@ -11020,16 +10989,6 @@ "@webassemblyjs/helper-wasm-bytecode" "1.11.1" "@webassemblyjs/wasm-gen" "1.11.1" -"@webassemblyjs/helper-wasm-section@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" - integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/helper-wasm-section@1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" @@ -11092,20 +11051,6 @@ "@webassemblyjs/wasm-parser" "1.11.1" "@webassemblyjs/wast-printer" "1.11.1" -"@webassemblyjs/wasm-edit@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" - integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-opt" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - "@webassemblyjs/wast-printer" "1.11.6" - "@webassemblyjs/wasm-edit@^1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" @@ -11131,17 +11076,6 @@ "@webassemblyjs/leb128" "1.11.1" "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wasm-gen@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" - integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - "@webassemblyjs/wasm-gen@1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" @@ -11163,16 +11097,6 @@ "@webassemblyjs/wasm-gen" "1.11.1" "@webassemblyjs/wasm-parser" "1.11.1" -"@webassemblyjs/wasm-opt@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" - integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - "@webassemblyjs/wasm-opt@1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" @@ -11195,18 +11119,6 @@ "@webassemblyjs/leb128" "1.11.1" "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" - integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - "@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" @@ -11227,14 +11139,6 @@ "@webassemblyjs/ast" "1.11.1" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" - integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@xtuc/long" "4.2.2" - "@webassemblyjs/wast-printer@1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" @@ -16908,18 +16812,10 @@ enhanced-resolve@^5.14.1: graceful-fs "^4.2.4" tapable "^2.2.0" -enhanced-resolve@^5.15.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enhanced-resolve@^5.17.0: - version "5.17.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz#d037603789dd9555b89aaec7eb78845c49089bc5" - integrity sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA== +enhanced-resolve@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -28522,7 +28418,7 @@ react-is@^18.0.0: dependencies: "@remix-run/router" "1.0.2" -"react-router-6@npm:react-router@6.3.0": +"react-router-6@npm:react-router@6.3.0", react-router@6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== @@ -28537,13 +28433,6 @@ react-router-dom@^6.2.2: history "^5.2.0" react-router "6.3.0" -react-router@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" - integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== - dependencies: - history "^5.2.0" - react@^18.0.0: version "18.0.0" resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96" @@ -31022,16 +30911,7 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -31143,14 +31023,7 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -33810,42 +33683,11 @@ webpack@5.76.1: watchpack "^2.4.0" webpack-sources "^3.2.3" -webpack@^5.90.3, webpack@~5.90.3: - version "5.90.3" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.90.3.tgz#37b8f74d3ded061ba789bb22b31e82eed75bd9ac" - integrity sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA== +webpack@^5.90.3, webpack@^5.94.0, webpack@~5.94.0: + version "5.94.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" + integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.5" - "@webassemblyjs/ast" "^1.11.5" - "@webassemblyjs/wasm-edit" "^1.11.5" - "@webassemblyjs/wasm-parser" "^1.11.5" - acorn "^8.7.1" - acorn-import-assertions "^1.9.0" - browserslist "^4.21.10" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.15.0" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.2.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.10" - watchpack "^2.4.0" - webpack-sources "^3.2.3" - -webpack@^5.92.1: - version "5.92.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.92.1.tgz#eca5c1725b9e189cffbd86e8b6c3c7400efc5788" - integrity sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA== - dependencies: - "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.5" "@webassemblyjs/ast" "^1.12.1" "@webassemblyjs/wasm-edit" "^1.12.1" @@ -33854,7 +33696,7 @@ webpack@^5.92.1: acorn-import-attributes "^1.9.5" browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.0" + enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" @@ -34150,16 +33992,7 @@ wrangler@^3.67.1: optionalDependencies: fsevents "~2.3.2" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@7.0.0, wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From 70f938b75ae868839bda632a1b4bf2cb9d6fab12 Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Wed, 4 Sep 2024 12:04:27 +0200 Subject: [PATCH 11/25] fix(node-fetch): Use stringified origin url (#13581) Uses the stringified value of `origin` to call `.endsWith()`. closes https://github.com/getsentry/sentry-javascript/issues/13574 --- packages/node/src/integrations/node-fetch.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node/src/integrations/node-fetch.ts b/packages/node/src/integrations/node-fetch.ts index 093b314a6138..fa7a9974135a 100644 --- a/packages/node/src/integrations/node-fetch.ts +++ b/packages/node/src/integrations/node-fetch.ts @@ -192,11 +192,11 @@ function getBreadcrumbData(request: FetchRequest): Partial function getAbsoluteUrl(origin: string, path: string = '/'): string { const url = `${origin}`; - if (origin.endsWith('/') && path.startsWith('/')) { + if (url.endsWith('/') && path.startsWith('/')) { return `${url}${path.slice(1)}`; } - if (!origin.endsWith('/') && !path.startsWith('/')) { + if (!url.endsWith('/') && !path.startsWith('/')) { return `${url}/${path.slice(1)}`; } From 6dc8aab09431561c21e9016d6dcecbc9651b6ebd Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 4 Sep 2024 12:23:03 +0200 Subject: [PATCH 12/25] fix(cloudflare): Guard `context.waitUntil` call in request handler (#13549) Guard the call for `context.waitUntil` in the CF request handler wrapper. Our public API requires `context` to be present, however, in certain cases like Astro during build (prerendering), `context` becomes `undefined`. --- packages/cloudflare/src/request.ts | 10 ++++++++-- packages/cloudflare/test/request.test.ts | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/cloudflare/src/request.ts b/packages/cloudflare/src/request.ts index 560c17afb9e7..7a474c3b27cb 100644 --- a/packages/cloudflare/src/request.ts +++ b/packages/cloudflare/src/request.ts @@ -31,7 +31,13 @@ export function wrapRequestHandler( handler: (...args: unknown[]) => Response | Promise, ): Promise { return withIsolationScope(async isolationScope => { - const { options, request, context } = wrapperOptions; + const { options, request } = wrapperOptions; + + // In certain situations, the passed context can become undefined. + // For example, for Astro while prerendering pages at build time. + // see: https://github.com/getsentry/sentry-javascript/issues/13217 + const context = wrapperOptions.context as ExecutionContext | undefined; + const client = init(options); isolationScope.setClient(client); @@ -89,7 +95,7 @@ export function wrapRequestHandler( captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); throw e; } finally { - context.waitUntil(flush(2000)); + context?.waitUntil(flush(2000)); } }, ); diff --git a/packages/cloudflare/test/request.test.ts b/packages/cloudflare/test/request.test.ts index 93764a292ab4..5218e8afe20b 100644 --- a/packages/cloudflare/test/request.test.ts +++ b/packages/cloudflare/test/request.test.ts @@ -45,6 +45,15 @@ describe('withSentry', () => { expect(context.waitUntil).toHaveBeenLastCalledWith(expect.any(Promise)); }); + test("doesn't error if context is undefined", () => { + expect(() => + wrapRequestHandler( + { options: MOCK_OPTIONS, request: new Request('https://example.com'), context: undefined as any }, + () => new Response('test'), + ), + ).not.toThrow(); + }); + test('creates a cloudflare client and sets it on the handler', async () => { const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind'); await wrapRequestHandler( From 50589cd3a30535807723ee086cccc12058282209 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 4 Sep 2024 12:42:52 +0200 Subject: [PATCH 13/25] fix(node): Replace dashes in `generic-pool` span origins with underscores (#13579) Ref https://github.com/getsentry/sentry-javascript/pull/13465#issuecomment-2327535609 --- .../suites/tracing/genericPool/test.ts | 8 ++++---- packages/node/src/integrations/tracing/genericPool.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts index a61782ae0fe5..114d3a909188 100644 --- a/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts @@ -11,18 +11,18 @@ describe('genericPool auto instrumentation', () => { spans: expect.arrayContaining([ expect.objectContaining({ description: expect.stringMatching(/^generic-pool\.ac?quire/), - origin: 'auto.db.otel.generic-pool', + origin: 'auto.db.otel.generic_pool', data: { - 'sentry.origin': 'auto.db.otel.generic-pool', + 'sentry.origin': 'auto.db.otel.generic_pool', }, status: 'ok', }), expect.objectContaining({ description: expect.stringMatching(/^generic-pool\.ac?quire/), - origin: 'auto.db.otel.generic-pool', + origin: 'auto.db.otel.generic_pool', data: { - 'sentry.origin': 'auto.db.otel.generic-pool', + 'sentry.origin': 'auto.db.otel.generic_pool', }, status: 'ok', }), diff --git a/packages/node/src/integrations/tracing/genericPool.ts b/packages/node/src/integrations/tracing/genericPool.ts index 55b8b6095f64..8bc84554071c 100644 --- a/packages/node/src/integrations/tracing/genericPool.ts +++ b/packages/node/src/integrations/tracing/genericPool.ts @@ -25,7 +25,7 @@ const _genericPoolIntegration = (() => { spanDescription === 'generic-pool.aquire' || spanDescription === 'generic-pool.acquire'; if (isGenericPoolSpan) { - span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.generic-pool'); + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.generic_pool'); } }); }, From 63863cdb76f69d620a4ab6f4504e5946834660d3 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 4 Sep 2024 12:43:14 +0200 Subject: [PATCH 14/25] feat(nextjs): Emit warning when using turbopack (#13566) Ref: https://github.com/getsentry/sentry-javascript/issues/8105 Emit a warning about certain incompatibilities when we detect a turbopack build (dev or prod build). --- packages/nextjs/src/config/withSentryConfig.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/nextjs/src/config/withSentryConfig.ts b/packages/nextjs/src/config/withSentryConfig.ts index 78df524c88c0..e87cbf11ce44 100644 --- a/packages/nextjs/src/config/withSentryConfig.ts +++ b/packages/nextjs/src/config/withSentryConfig.ts @@ -103,6 +103,17 @@ function getFinalConfigObject( ); } + if (process.env.TURBOPACK && !process.env.SENTRY_SUPPRESS_TURBOPACK_WARNING) { + // eslint-disable-next-line no-console + console.warn( + `[@sentry/nextjs] WARNING: You are using the Sentry SDK with \`next ${ + process.env.NODE_ENV === 'development' ? 'dev' : 'build' + } --turbo\`. The Sentry SDK doesn't yet fully support Turbopack. The SDK will not be loaded in the browser, and serverside instrumentation will be inaccurate or incomplete. ${ + process.env.NODE_ENV === 'development' ? 'Production builds without `--turbo` will still fully work. ' : '' + }If you are just trying out Sentry or attempting to configure the SDK, we recommend temporarily removing the \`--turbo\` flag while you are developing locally. Follow this issue for progress on Sentry + Turbopack: https://github.com/getsentry/sentry-javascript/issues/8105. (You can suppress this warning by setting SENTRY_SUPPRESS_TURBOPACK_WARNING=1 as environment variable)`, + ); + } + return { ...incomingUserNextConfigObject, webpack: constructWebpackConfigFunction(incomingUserNextConfigObject, userSentryOptions), From c4f68d8fe75ad782be68eaa342c136d103e2f054 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 4 Sep 2024 14:06:10 +0200 Subject: [PATCH 15/25] feat(nextjs): Future-proof Next.js config options overriding (#13586) The logic in this PR is slightly intense but all it does is check for the Next.js version and if we are on a version that included [this change](https://github.com/vercel/next.js/pull/68853) which stabilized `instrumentation.ts` we no longer inject the `experimental.instrumentationHook` option in `next.config.js`. This is necessary because otherwise Next.js prints scary warnings and users may be confused why. --- .../nextjs/src/config/withSentryConfig.ts | 83 ++++++++++++++++--- 1 file changed, 70 insertions(+), 13 deletions(-) diff --git a/packages/nextjs/src/config/withSentryConfig.ts b/packages/nextjs/src/config/withSentryConfig.ts index e87cbf11ce44..4f5205fecfcb 100644 --- a/packages/nextjs/src/config/withSentryConfig.ts +++ b/packages/nextjs/src/config/withSentryConfig.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity */ import { isThenable, parseSemver } from '@sentry/utils'; import * as fs from 'fs'; @@ -47,6 +48,7 @@ function getFinalConfigObject( incomingUserNextConfigObject: NextConfigObject, userSentryOptions: SentryBuildOptions, ): NextConfigObject { + // TODO(v9): Remove this check for the Sentry property if ('sentry' in incomingUserNextConfigObject) { // eslint-disable-next-line no-console console.warn( @@ -71,21 +73,10 @@ function getFinalConfigObject( } } - // We need to enable `instrumentation.ts` for users because we tell them to put their `Sentry.init()` calls inside of it. - if (incomingUserNextConfigObject.experimental?.instrumentationHook === false) { - // eslint-disable-next-line no-console - console.warn( - '[@sentry/nextjs] You turned off the `instrumentationHook` option. Note that Sentry will not be initialized if you did not set it up inside `instrumentation.ts`.', - ); - } - incomingUserNextConfigObject.experimental = { - instrumentationHook: true, - ...incomingUserNextConfigObject.experimental, - }; + const nextJsVersion = getNextjsVersion(); // Add the `clientTraceMetadata` experimental option based on Next.js version. The option got introduced in Next.js version 15.0.0 (actually 14.3.0-canary.64). // Adding the option on lower versions will cause Next.js to print nasty warnings we wouldn't confront our users with. - const nextJsVersion = getNextjsVersion(); if (nextJsVersion) { const { major, minor } = parseSemver(nextJsVersion); if (major !== undefined && minor !== undefined && (major >= 15 || (major === 14 && minor >= 3))) { @@ -99,10 +90,76 @@ function getFinalConfigObject( } else { // eslint-disable-next-line no-console console.log( - "[@sentry/nextjs] The Sentry SDK was not able to determine your Next.js version. If you are using Next.js 15 or greater, please add `experimental.clientTraceMetadata: ['sentry-trace', 'baggage']` to your Next.js config to enable pageload tracing for App Router.", + "[@sentry/nextjs] The Sentry SDK was not able to determine your Next.js version. If you are using Next.js version 15 or greater, please add `experimental.clientTraceMetadata: ['sentry-trace', 'baggage']` to your Next.js config to enable pageload tracing for App Router.", ); } + // From Next.js version (15.0.0-canary.124) onwards, Next.js does no longer require the `experimental.instrumentationHook` option and will + // print a warning when it is set, so we need to conditionally provide it for lower versions. + if (nextJsVersion) { + const { major, minor, patch, prerelease } = parseSemver(nextJsVersion); + const isFullySupportedRelease = + major !== undefined && + minor !== undefined && + patch !== undefined && + major >= 15 && + ((minor === 0 && patch === 0 && prerelease === undefined) || minor > 0 || patch > 0); + const isSupportedV15Rc = + major !== undefined && + minor !== undefined && + patch !== undefined && + prerelease !== undefined && + major === 15 && + minor === 0 && + patch === 0 && + prerelease.startsWith('rc.') && + parseInt(prerelease.split('.')[1] || '', 10) > 0; + const isSupportedCanary = + minor !== undefined && + patch !== undefined && + prerelease !== undefined && + major === 15 && + minor === 0 && + patch === 0 && + prerelease.startsWith('canary.') && + parseInt(prerelease.split('.')[1] || '', 10) >= 124; + + if (!isFullySupportedRelease && !isSupportedV15Rc && !isSupportedCanary) { + if (incomingUserNextConfigObject.experimental?.instrumentationHook === false) { + // eslint-disable-next-line no-console + console.warn( + '[@sentry/nextjs] You turned off the `experimental.instrumentationHook` option. Note that Sentry will not be initialized if you did not set it up inside `instrumentation.(js|ts)`.', + ); + } + incomingUserNextConfigObject.experimental = { + instrumentationHook: true, + ...incomingUserNextConfigObject.experimental, + }; + } + } else { + // If we cannot detect a Next.js version for whatever reason, the sensible default is to set the `experimental.instrumentationHook`, even though it may create a warning. + if ( + incomingUserNextConfigObject.experimental && + 'instrumentationHook' in incomingUserNextConfigObject.experimental + ) { + if (incomingUserNextConfigObject.experimental.instrumentationHook === false) { + // eslint-disable-next-line no-console + console.warn( + '[@sentry/nextjs] You set `experimental.instrumentationHook` to `false`. If you are using Next.js version 15 or greater, you can remove that option. If you are using Next.js version 14 or lower, you need to set `experimental.instrumentationHook` in your `next.config.(js|mjs)` to `true` for the SDK to be properly initialized in combination with `instrumentation.(js|ts)`.', + ); + } + } else { + // eslint-disable-next-line no-console + console.log( + "[@sentry/nextjs] The Sentry SDK was not able to determine your Next.js version. If you are using Next.js version 15 or greater, Next.js will probably show you a warning about the `experimental.instrumentationHook` being set. To silence Next.js' warning, explicitly set the `experimental.instrumentationHook` option in your `next.config.(js|mjs|ts)` to `undefined`. If you are on Next.js version 14 or lower, you can silence this particular warning by explicitly setting the `experimental.instrumentationHook` option in your `next.config.(js|mjs)` to `true`.", + ); + incomingUserNextConfigObject.experimental = { + instrumentationHook: true, + ...incomingUserNextConfigObject.experimental, + }; + } + } + if (process.env.TURBOPACK && !process.env.SENTRY_SUPPRESS_TURBOPACK_WARNING) { // eslint-disable-next-line no-console console.warn( From 80ec41a1f9b7501b2c6a3ff3ee338c45cf9c4bf1 Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:15:30 +0200 Subject: [PATCH 16/25] feat(nuxt): Upload sourcemaps generated by Nitro (#13382) Adding another source maps generation step with rollup to include Nitro-generated source maps as well. closes https://github.com/getsentry/sentry-javascript/issues/13383 --- packages/nuxt/package.json | 1 + packages/nuxt/src/vite/sourceMaps.ts | 126 +++++++++++++++++++-------- yarn.lock | 8 ++ 3 files changed, 97 insertions(+), 38 deletions(-) diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index 2aaa9f06dd78..688cac5489af 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -47,6 +47,7 @@ "@sentry/core": "8.28.0", "@sentry/node": "8.28.0", "@sentry/opentelemetry": "8.28.0", + "@sentry/rollup-plugin": "2.22.3", "@sentry/types": "8.28.0", "@sentry/utils": "8.28.0", "@sentry/vite-plugin": "2.22.3", diff --git a/packages/nuxt/src/vite/sourceMaps.ts b/packages/nuxt/src/vite/sourceMaps.ts index 3518c45409e0..18eed2cbcfd8 100644 --- a/packages/nuxt/src/vite/sourceMaps.ts +++ b/packages/nuxt/src/vite/sourceMaps.ts @@ -1,52 +1,102 @@ import type { Nuxt } from '@nuxt/schema'; -import { sentryVitePlugin } from '@sentry/vite-plugin'; +import { type SentryRollupPluginOptions, sentryRollupPlugin } from '@sentry/rollup-plugin'; +import { type SentryVitePluginOptions, sentryVitePlugin } from '@sentry/vite-plugin'; +import type { NitroConfig } from 'nitropack'; import type { SentryNuxtModuleOptions } from '../common/types'; /** - * Setup source maps for Sentry inside the Nuxt module during build time. + * Setup source maps for Sentry inside the Nuxt module during build time (in Vite for Nuxt and Rollup for Nitro). */ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nuxt): void { - nuxt.hook('vite:extendConfig', async (viteInlineConfig, _env) => { - const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {}; - - if ((sourceMapsUploadOptions.enabled ?? true) && viteInlineConfig.mode !== 'development') { - const sentryPlugin = sentryVitePlugin({ - org: sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG, - project: sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT, - authToken: sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN, - telemetry: sourceMapsUploadOptions.telemetry ?? true, - sourcemaps: { - assets: sourceMapsUploadOptions.sourcemaps?.assets ?? undefined, - ignore: sourceMapsUploadOptions.sourcemaps?.ignore ?? undefined, - filesToDeleteAfterUpload: sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload ?? undefined, - }, - _metaOptions: { - telemetry: { - metaFramework: 'nuxt', - }, - }, - debug: moduleOptions.debug ?? false, - }); + const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {}; + const sourceMapsEnabled = sourceMapsUploadOptions.enabled ?? true; + nuxt.hook('vite:extendConfig', async (viteInlineConfig, _env) => { + if (sourceMapsEnabled && viteInlineConfig.mode !== 'development') { + // Add Sentry plugin viteInlineConfig.plugins = viteInlineConfig.plugins || []; - viteInlineConfig.plugins.push(sentryPlugin); - - const sourceMapsPreviouslyEnabled = viteInlineConfig.build?.sourcemap; - - if (moduleOptions.debug && !sourceMapsPreviouslyEnabled) { - // eslint-disable-next-line no-console - console.log('[Sentry]: Enabled source maps generation in the Vite build options.'); - if (!moduleOptions.sourceMapsUploadOptions?.sourcemaps?.filesToDeleteAfterUpload) { - // eslint-disable-next-line no-console - console.warn( - `[Sentry] We recommend setting the \`sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload\` option to clean up source maps after uploading. -[Sentry] Otherwise, source maps might be deployed to production, depending on your configuration`, - ); - } - } + viteInlineConfig.plugins.push(sentryVitePlugin(getPluginOptions(moduleOptions))); + // Enable source maps viteInlineConfig.build = viteInlineConfig.build || {}; viteInlineConfig.build.sourcemap = true; + + logDebugInfo(moduleOptions, viteInlineConfig.build?.sourcemap); + } + }); + + nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => { + if (sourceMapsEnabled && !nitroConfig.dev) { + if (!nitroConfig.rollupConfig) { + nitroConfig.rollupConfig = {}; + } + + if (nitroConfig.rollupConfig.plugins === null || nitroConfig.rollupConfig.plugins === undefined) { + nitroConfig.rollupConfig.plugins = []; + } else if (!Array.isArray(nitroConfig.rollupConfig.plugins)) { + // `rollupConfig.plugins` can be a single plugin, so we want to put it into an array so that we can push our own plugin + nitroConfig.rollupConfig.plugins = [nitroConfig.rollupConfig.plugins]; + } + + // Add Sentry plugin + nitroConfig.rollupConfig.plugins.push(sentryRollupPlugin(getPluginOptions(moduleOptions, true))); + + // Enable source maps + nitroConfig.rollupConfig.output = nitroConfig?.rollupConfig?.output || {}; + nitroConfig.rollupConfig.output.sourcemap = true; + nitroConfig.rollupConfig.output.sourcemapExcludeSources = false; // Adding "sourcesContent" to the source map (Nitro sets this eto `true`) + + logDebugInfo(moduleOptions, nitroConfig.rollupConfig.output?.sourcemap); } }); } + +/** + * Normalizes the beginning of a path from e.g. ../../../ to ./ + */ +function normalizePath(path: string): string { + return path.replace(/^(\.\.\/)+/, './'); +} + +function getPluginOptions( + moduleOptions: SentryNuxtModuleOptions, + isNitro = false, +): SentryVitePluginOptions | SentryRollupPluginOptions { + const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {}; + + return { + org: sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG, + project: sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT, + authToken: sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN, + telemetry: sourceMapsUploadOptions.telemetry ?? true, + sourcemaps: { + assets: + sourceMapsUploadOptions.sourcemaps?.assets ?? isNitro ? ['./.output/server/**/*'] : ['./.output/public/**/*'], + ignore: sourceMapsUploadOptions.sourcemaps?.ignore ?? undefined, + filesToDeleteAfterUpload: sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload ?? undefined, + rewriteSources: (source: string) => normalizePath(source), + }, + _metaOptions: { + telemetry: { + metaFramework: 'nuxt', + }, + }, + debug: moduleOptions.debug ?? false, + }; +} + +function logDebugInfo(moduleOptions: SentryNuxtModuleOptions, sourceMapsPreviouslyEnabled: boolean): void { + if (moduleOptions.debug && !sourceMapsPreviouslyEnabled) { + // eslint-disable-next-line no-console + console.log('[Sentry]: Enabled source maps generation in the Vite build options.'); + + const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {}; + + if (!sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload) { + // eslint-disable-next-line no-console + console.warn( + '[Sentry] We recommend setting the `sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload` option to clean up source maps after uploading. Otherwise, source maps might be deployed to production, depending on your configuration', + ); + } + } +} diff --git a/yarn.lock b/yarn.lock index b0a8c712e374..a79245f2672c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8309,6 +8309,14 @@ "@sentry/cli-win32-i686" "2.33.1" "@sentry/cli-win32-x64" "2.33.1" +"@sentry/rollup-plugin@2.22.3": + version "2.22.3" + resolved "https://registry.yarnpkg.com/@sentry/rollup-plugin/-/rollup-plugin-2.22.3.tgz#18ab4b7903ee723bee4cf789b38bb3febb05faae" + integrity sha512-I1UsnYzZm5W7/Pyah2yxuMRxmzgf5iDKoptFfMaerpRO5oBhFO3tMnKSLAlYMvuXKRoYkInNv6ckkUcSOF6jig== + dependencies: + "@sentry/bundler-plugin-core" "2.22.3" + unplugin "1.0.1" + "@sentry/vite-plugin@2.22.3", "@sentry/vite-plugin@^2.22.3": version "2.22.3" resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.22.3.tgz#b52802412b6f3d8e3e56742afc9624d9babae5b6" From a69da1bab2a7a4def225d70b8ac375785887aee5 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Thu, 5 Sep 2024 09:33:07 +0200 Subject: [PATCH 17/25] feat(node): Option to only wrap instrumented modules (#13139) Likely closes many issues but I don't want to auto-close anything specific here. We should probably confirm the issues are closed individually. `import-in-the-middle` by default wraps every ES module with a wrapping module that later allows it exports to be modified. This has issues though because the wrapping output of `import-in-the-middle` is not compatible with all modules. To help work around this I [added a feature](https://github.com/nodejs/import-in-the-middle/pull/146) to `import-in-the-middle` that allows us to only wrap modules that we specifically need to instrument. ```ts import * as Sentry from '@sentry/node'; Sentry.init({ dsn: '__DSN__', registerEsmLoaderHooks: { onlyHookedModules: true }, }); ``` So far I've only changed the express integration test to use this new mode. --- .../src/instrument.mjs | 1 + .../suites/esm/import-in-the-middle/app.mjs | 21 +++++++++++++++++ .../esm/import-in-the-middle/sub-module.mjs | 2 ++ .../suites/esm/import-in-the-middle/test.ts | 12 ++++++++++ packages/node/src/sdk/initOtel.ts | 23 ++++++++++++++++++- packages/node/src/types.ts | 13 ++++++++++- 6 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/esm/import-in-the-middle/app.mjs create mode 100644 dev-packages/node-integration-tests/suites/esm/import-in-the-middle/sub-module.mjs create mode 100644 dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts diff --git a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs index 544c773e5e7c..caaf73162ded 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs @@ -5,4 +5,5 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + registerEsmLoaderHooks: { onlyIncludeInstrumentedModules: true }, }); diff --git a/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/app.mjs b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/app.mjs new file mode 100644 index 000000000000..6b20155aea38 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/app.mjs @@ -0,0 +1,21 @@ +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import * as Sentry from '@sentry/node'; +import * as iitm from 'import-in-the-middle'; + +new iitm.Hook((_, name) => { + if (name !== 'http') { + throw new Error(`'http' should be the only hooked modules but we just hooked '${name}'`); + } +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + autoSessionTracking: false, + transport: loggingTransport, + registerEsmLoaderHooks: { onlyIncludeInstrumentedModules: true }, +}); + +await import('./sub-module.mjs'); +await import('http'); +await import('os'); diff --git a/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/sub-module.mjs b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/sub-module.mjs new file mode 100644 index 000000000000..9940c57857eb --- /dev/null +++ b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/sub-module.mjs @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-console +console.assert(true); diff --git a/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts new file mode 100644 index 000000000000..8b9e6e06202f --- /dev/null +++ b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts @@ -0,0 +1,12 @@ +import { conditionalTest } from '../../../utils'; +import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; + +afterAll(() => { + cleanupChildProcesses(); +}); + +conditionalTest({ min: 18 })('import-in-the-middle', () => { + test('onlyIncludeInstrumentedModules', done => { + createRunner(__dirname, 'app.mjs').ensureNoErrorOutput().start(done); + }); +}); diff --git a/packages/node/src/sdk/initOtel.ts b/packages/node/src/sdk/initOtel.ts index 03d8cea76fac..37b94ebc439f 100644 --- a/packages/node/src/sdk/initOtel.ts +++ b/packages/node/src/sdk/initOtel.ts @@ -10,6 +10,7 @@ import { import { SDK_VERSION } from '@sentry/core'; import { SentryPropagator, SentrySampler, SentrySpanProcessor } from '@sentry/opentelemetry'; import { GLOBAL_OBJ, consoleSandbox, logger } from '@sentry/utils'; +import { createAddHookMessageChannel } from 'import-in-the-middle'; import { getOpenTelemetryInstrumentationToPreload } from '../integrations/tracing'; import { SentryContextManager } from '../otel/contextManager'; @@ -31,6 +32,26 @@ export function initOpenTelemetry(client: NodeClient): void { client.traceProvider = provider; } +type ImportInTheMiddleInitData = Pick & { + addHookMessagePort?: unknown; +}; + +interface RegisterOptions { + data?: ImportInTheMiddleInitData; + transferList?: unknown[]; +} + +function getRegisterOptions(esmHookConfig?: EsmLoaderHookOptions): RegisterOptions { + if (esmHookConfig?.onlyIncludeInstrumentedModules) { + const { addHookMessagePort } = createAddHookMessageChannel(); + // If the user supplied include, we need to use that as a starting point or use an empty array to ensure no modules + // are wrapped if they are not hooked + return { data: { addHookMessagePort, include: esmHookConfig.include || [] }, transferList: [addHookMessagePort] }; + } + + return { data: esmHookConfig }; +} + /** Initialize the ESM loader. */ export function maybeInitializeEsmLoader(esmHookConfig?: EsmLoaderHookOptions): void { const [nodeMajor = 0, nodeMinor = 0] = process.versions.node.split('.').map(Number); @@ -44,7 +65,7 @@ export function maybeInitializeEsmLoader(esmHookConfig?: EsmLoaderHookOptions): if (!GLOBAL_OBJ._sentryEsmLoaderHookRegistered && importMetaUrl) { try { // @ts-expect-error register is available in these versions - moduleModule.register('import-in-the-middle/hook.mjs', importMetaUrl, { data: esmHookConfig }); + moduleModule.register('import-in-the-middle/hook.mjs', importMetaUrl, getRegisterOptions(esmHookConfig)); GLOBAL_OBJ._sentryEsmLoaderHookRegistered = true; } catch (error) { logger.warn('Failed to register ESM hook', error); diff --git a/packages/node/src/types.ts b/packages/node/src/types.ts index 9604b31ddb22..aa9873e2da91 100644 --- a/packages/node/src/types.ts +++ b/packages/node/src/types.ts @@ -6,7 +6,18 @@ import type { NodeTransportOptions } from './transports'; export interface EsmLoaderHookOptions { include?: Array; - exclude?: Array; + exclude?: Array /** + * When set to `true`, `import-in-the-middle` will only wrap ESM modules that are specifically instrumented by + * OpenTelemetry plugins. This is useful to avoid issues where `import-in-the-middle` is not compatible with some of + * your dependencies. + * + * **Note**: This feature will only work if you `Sentry.init()` the SDK before the instrumented modules are loaded. + * This can be achieved via the Node `--import` CLI flag or by loading your app via async `import()` after calling + * `Sentry.init()`. + * + * Defaults to `false`. + */; + onlyIncludeInstrumentedModules?: boolean; } export interface BaseNodeOptions { From e2213fce15b4edd21f081b665cbafc085b805423 Mon Sep 17 00:00:00 2001 From: Andrei <168741329+andreiborza@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:37:38 +0200 Subject: [PATCH 18/25] feat(solidstart): Add `sentrySolidStartVite` plugin to simplify source maps upload (#13493) This plugin simplifies source maps upload by using `@sentry/vite-plugin` and enabling source map generation by default. Usage: ```js import { defineConfig } from '@solidjs/start/config' import { sentrySolidStartVite } from '@sentry/solidstart' export default defineConfig({ vite: { plugins: [ sentrySolidStartVite({ org: process.env.SENTRY_ORG, project: process.env.SENTRY_PROJECT, authToken: process.env.SENTRY_AUTH_TOKEN, debug: true, }), ], } }) ``` Closes: #12553 --- .github/workflows/build.yml | 2 +- .../solidstart/app.config.ts | 7 +- .../test-applications/solidstart/package.json | 9 +- .../solidstart/src/routes/client-error.tsx | 82 ++--------- .../solidstart/src/routes/error-boundary.tsx | 64 +++++++++ .../solidstart/src/routes/index.tsx | 3 + .../solidstart/tests/errorboundary.test.ts | 10 +- .../solidstart/tests/errors.client.test.ts | 5 +- packages/solidstart/.eslintrc.js | 1 + packages/solidstart/README.md | 46 ++----- packages/solidstart/src/index.server.ts | 1 + packages/solidstart/src/index.types.ts | 1 + packages/solidstart/src/vite/index.ts | 1 + .../src/vite/sentrySolidStartVite.ts | 18 +++ packages/solidstart/src/vite/sourceMaps.ts | 58 ++++++++ packages/solidstart/src/vite/types.ts | 128 ++++++++++++++++++ .../withServerActionInstrumentation.test.ts | 2 - .../test/vite/sentrySolidStartVite.test.ts | 50 +++++++ .../solidstart/test/vite/sourceMaps.test.ts | 96 +++++++++++++ 19 files changed, 464 insertions(+), 120 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/solidstart/src/routes/error-boundary.tsx create mode 100644 packages/solidstart/src/vite/index.ts create mode 100644 packages/solidstart/src/vite/sentrySolidStartVite.ts create mode 100644 packages/solidstart/src/vite/sourceMaps.ts create mode 100644 packages/solidstart/src/vite/types.ts create mode 100644 packages/solidstart/test/vite/sentrySolidStartVite.test.ts create mode 100644 packages/solidstart/test/vite/sourceMaps.test.ts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77ddae4705b6..70535bd06e89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1003,7 +1003,7 @@ jobs: working-directory: dev-packages/e2e-tests/test-applications/${{ matrix.test-application }} timeout-minutes: 5 run: pnpm test:assert - + - name: Upload Playwright Traces uses: actions/upload-artifact@v4 if: failure() diff --git a/dev-packages/e2e-tests/test-applications/solidstart/app.config.ts b/dev-packages/e2e-tests/test-applications/solidstart/app.config.ts index b3c737efe5ba..0b9a5553fb0a 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/app.config.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart/app.config.ts @@ -1,3 +1,8 @@ +import { sentrySolidStartVite } from '@sentry/solidstart'; import { defineConfig } from '@solidjs/start/config'; -export default defineConfig({}); +export default defineConfig({ + vite: { + plugins: [sentrySolidStartVite()], + }, +}); diff --git a/dev-packages/e2e-tests/test-applications/solidstart/package.json b/dev-packages/e2e-tests/test-applications/solidstart/package.json index dfcf8a47402a..e831a14c1f47 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/package.json +++ b/dev-packages/e2e-tests/test-applications/solidstart/package.json @@ -3,14 +3,19 @@ "version": "0.0.0", "scripts": { "clean": "pnpx rimraf node_modules pnpm-lock.yaml .vinxi .output", + "clean:build": "pnpx rimraf .vinxi .output", "dev": "NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev", "build": "vinxi build", "//": [ "We are using `vinxi dev` to start the server because `vinxi start` is experimental and ", "doesn't correctly resolve modules for @sentry/solidstart/solidrouter.", - "This is currently not an issue outside of our repo. See: https://github.com/nksaraf/vinxi/issues/177" + "This is currently not an issue outside of our repo. See: https://github.com/nksaraf/vinxi/issues/177", + "We run the build command to ensure building succeeds. However, keeping", + "build output around slows down the vite dev server when using `@sentry/vite-plugin` so we clear it out", + "before actually running the tests.", + "Cleaning the build output should be removed once we can use `vinxi start`." ], - "preview": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev", + "preview": "pnpm clean:build && HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev", "start": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi start", "test:prod": "TEST_ENV=production playwright test", "test:build": "pnpm install && npx playwright install && pnpm build", diff --git a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/client-error.tsx b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/client-error.tsx index e997e4fbb1e3..5e405e8c4e40 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/client-error.tsx +++ b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/client-error.tsx @@ -1,75 +1,15 @@ -import * as Sentry from '@sentry/solidstart'; -import type { ParentProps } from 'solid-js'; -import { ErrorBoundary, createSignal, onMount } from 'solid-js'; - -const SentryErrorBoundary = Sentry.withSentryErrorBoundary(ErrorBoundary); - -const [count, setCount] = createSignal(1); -const [caughtError, setCaughtError] = createSignal(false); - export default function ClientErrorPage() { return ( - - {caughtError() && ( - - )} -
-
- -
-
- -
-
-
- ); -} - -function Throw(props: { error: string }) { - onMount(() => { - throw new Error(props.error); - }); - return null; -} - -function SampleErrorBoundary(props: ParentProps) { - return ( - ( -
-

Error Boundary Fallback

-
- {error.message} -
- -
- )} - > - {props.children} -
+
+ +
); } diff --git a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/error-boundary.tsx b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/error-boundary.tsx new file mode 100644 index 000000000000..b22607667e7e --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/error-boundary.tsx @@ -0,0 +1,64 @@ +import * as Sentry from '@sentry/solidstart'; +import type { ParentProps } from 'solid-js'; +import { ErrorBoundary, createSignal, onMount } from 'solid-js'; + +const SentryErrorBoundary = Sentry.withSentryErrorBoundary(ErrorBoundary); + +const [count, setCount] = createSignal(1); +const [caughtError, setCaughtError] = createSignal(false); + +export default function ErrorBoundaryTestPage() { + return ( + + {caughtError() && ( + + )} +
+
+ +
+
+
+ ); +} + +function Throw(props: { error: string }) { + onMount(() => { + throw new Error(props.error); + }); + return null; +} + +function SampleErrorBoundary(props: ParentProps) { + return ( + ( +
+

Error Boundary Fallback

+
+ {error.message} +
+ +
+ )} + > + {props.children} +
+ ); +} diff --git a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx index eed722cba4e3..9a0b22cc38c6 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx +++ b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx @@ -14,6 +14,9 @@ export default function Home() {
  • Server error
  • +
  • + Error Boundary +
  • User 5 diff --git a/dev-packages/e2e-tests/test-applications/solidstart/tests/errorboundary.test.ts b/dev-packages/e2e-tests/test-applications/solidstart/tests/errorboundary.test.ts index a4edf3c46236..b709760aab94 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/tests/errorboundary.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart/tests/errorboundary.test.ts @@ -10,7 +10,7 @@ test('captures an exception', async ({ page }) => { ); }); - await page.goto('/client-error'); + await page.goto('/error-boundary'); await page.locator('#caughtErrorBtn').click(); const errorEvent = await errorEventPromise; @@ -27,7 +27,7 @@ test('captures an exception', async ({ page }) => { }, ], }, - transaction: '/client-error', + transaction: '/error-boundary', }); }); @@ -40,7 +40,7 @@ test('captures a second exception after resetting the boundary', async ({ page } ); }); - await page.goto('/client-error'); + await page.goto('/error-boundary'); await page.locator('#caughtErrorBtn').click(); const firstErrorEvent = await firstErrorEventPromise; @@ -57,7 +57,7 @@ test('captures a second exception after resetting the boundary', async ({ page } }, ], }, - transaction: '/client-error', + transaction: '/error-boundary', }); const secondErrorEventPromise = waitForError('solidstart', errorEvent => { @@ -85,6 +85,6 @@ test('captures a second exception after resetting the boundary', async ({ page } }, ], }, - transaction: '/client-error', + transaction: '/error-boundary', }); }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.client.test.ts index 0f5ef61b365a..e2b00786f54c 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.client.test.ts @@ -4,7 +4,7 @@ import { waitForError } from '@sentry-internal/test-utils'; test.describe('client-side errors', () => { test('captures error thrown on click', async ({ page }) => { const errorPromise = waitForError('solidstart', async errorEvent => { - return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Solid Start E2E test app'; + return errorEvent?.exception?.values?.[0]?.value === 'Uncaught error thrown from Solid Start E2E test app'; }); await page.goto(`/client-error`); @@ -16,9 +16,8 @@ test.describe('client-side errors', () => { values: [ { type: 'Error', - value: 'Error thrown from Solid Start E2E test app', + value: 'Uncaught error thrown from Solid Start E2E test app', mechanism: { - type: 'instrument', handled: false, }, }, diff --git a/packages/solidstart/.eslintrc.js b/packages/solidstart/.eslintrc.js index c1f55c94aadf..d567b12530d0 100644 --- a/packages/solidstart/.eslintrc.js +++ b/packages/solidstart/.eslintrc.js @@ -14,6 +14,7 @@ module.exports = { files: ['src/vite/**', 'src/server/**'], rules: { '@sentry-internal/sdk/no-optional-chaining': 'off', + '@sentry-internal/sdk/no-nullish-coalescing': 'off', }, }, ], diff --git a/packages/solidstart/README.md b/packages/solidstart/README.md index 0b25a3a37e3e..1bb191994c79 100644 --- a/packages/solidstart/README.md +++ b/packages/solidstart/README.md @@ -157,58 +157,34 @@ render( ); ``` -# Sourcemaps and Releases +## Uploading Source Maps -To generate and upload source maps of your Solid Start app use our Vite bundler plugin. - -1. Install the Sentry Vite plugin - -```bash -# Using npm -npm install @sentry/vite-plugin --save-dev - -# Using yarn -yarn add @sentry/vite-plugin --dev -``` - -2. Configure the vite plugin - -To upload source maps you have to configure an auth token. Auth tokens can be passed to the plugin explicitly with the -`authToken` option, with a `SENTRY_AUTH_TOKEN` environment variable, or with an `.env.sentry-build-plugin` file in the -working directory when building your project. We recommend you add the auth token to your CI/CD environment as an -environment variable. +To upload source maps, add the `sentrySolidStartVite` plugin from `@sentry/solidstart` to your `app.config.ts` and +configure an auth token. Auth tokens can be passed to the plugin explicitly with the `authToken` option, with a +`SENTRY_AUTH_TOKEN` environment variable, or with an `.env.sentry-build-plugin` file in the working directory when +building your project. We recommend you add the auth token to your CI/CD environment as an environment variable. Learn more about configuring the plugin in our [Sentry Vite Plugin documentation](https://www.npmjs.com/package/@sentry/vite-plugin). -```bash -// .env.sentry-build-plugin -SENTRY_AUTH_TOKEN= -SENTRY_ORG= -SENTRY_PROJECT= -``` - -3. Finally, add the plugin to your `app.config.ts` file. - -```javascript +```typescript +// app.config.ts import { defineConfig } from '@solidjs/start/config'; -import { sentryVitePlugin } from '@sentry/vite-plugin'; +import { sentrySolidStartVite } from '@sentry/solidstart'; export default defineConfig({ - // rest of your config // ... vite: { - build: { - sourcemap: true, - }, plugins: [ - sentryVitePlugin({ + sentrySolidStartVite({ org: process.env.SENTRY_ORG, project: process.env.SENTRY_PROJECT, authToken: process.env.SENTRY_AUTH_TOKEN, + debug: true, }), ], }, + // ... }); ``` diff --git a/packages/solidstart/src/index.server.ts b/packages/solidstart/src/index.server.ts index 0ce5251aa327..d675a1c72820 100644 --- a/packages/solidstart/src/index.server.ts +++ b/packages/solidstart/src/index.server.ts @@ -1 +1,2 @@ export * from './server'; +export * from './vite'; diff --git a/packages/solidstart/src/index.types.ts b/packages/solidstart/src/index.types.ts index 89eaa14662e3..51adf848775a 100644 --- a/packages/solidstart/src/index.types.ts +++ b/packages/solidstart/src/index.types.ts @@ -3,6 +3,7 @@ // exports in this file - which we do below. export * from './client'; export * from './server'; +export * from './vite'; import type { Integration, Options, StackParser } from '@sentry/types'; diff --git a/packages/solidstart/src/vite/index.ts b/packages/solidstart/src/vite/index.ts new file mode 100644 index 000000000000..464bbd604fbe --- /dev/null +++ b/packages/solidstart/src/vite/index.ts @@ -0,0 +1 @@ +export * from './sentrySolidStartVite'; diff --git a/packages/solidstart/src/vite/sentrySolidStartVite.ts b/packages/solidstart/src/vite/sentrySolidStartVite.ts new file mode 100644 index 000000000000..59435f919071 --- /dev/null +++ b/packages/solidstart/src/vite/sentrySolidStartVite.ts @@ -0,0 +1,18 @@ +import type { Plugin } from 'vite'; +import { makeSourceMapsVitePlugin } from './sourceMaps'; +import type { SentrySolidStartPluginOptions } from './types'; + +/** + * Various Sentry vite plugins to be used for SolidStart. + */ +export const sentrySolidStartVite = (options: SentrySolidStartPluginOptions = {}): Plugin[] => { + const sentryPlugins: Plugin[] = []; + + if (process.env.NODE_ENV !== 'development') { + if (options.sourceMapsUploadOptions?.enabled ?? true) { + sentryPlugins.push(...makeSourceMapsVitePlugin(options)); + } + } + + return sentryPlugins; +}; diff --git a/packages/solidstart/src/vite/sourceMaps.ts b/packages/solidstart/src/vite/sourceMaps.ts new file mode 100644 index 000000000000..548038515e79 --- /dev/null +++ b/packages/solidstart/src/vite/sourceMaps.ts @@ -0,0 +1,58 @@ +import { sentryVitePlugin } from '@sentry/vite-plugin'; +import type { Plugin } from 'vite'; +import type { SentrySolidStartPluginOptions } from './types'; + +/** + * A Sentry plugin for SolidStart to enable source maps and use + * @sentry/vite-plugin to automatically upload source maps to Sentry. + * @param {SourceMapsOptions} options + */ +export function makeSourceMapsVitePlugin(options: SentrySolidStartPluginOptions): Plugin[] { + const { authToken, debug, org, project, sourceMapsUploadOptions } = options; + return [ + { + name: 'sentry-solidstart-source-maps', + apply: 'build', + enforce: 'post', + config(config) { + const sourceMapsPreviouslyNotEnabled = !config.build?.sourcemap; + if (debug && sourceMapsPreviouslyNotEnabled) { + // eslint-disable-next-line no-console + console.log('[Sentry SolidStart Plugin] Enabling source map generation'); + if (!sourceMapsUploadOptions?.filesToDeleteAfterUpload) { + // eslint-disable-next-line no-console + console.warn( + `[Sentry SolidStart PLugin] We recommend setting the \`sourceMapsUploadOptions.filesToDeleteAfterUpload\` option to clean up source maps after uploading. +[Sentry SolidStart Plugin] Otherwise, source maps might be deployed to production, depending on your configuration`, + ); + } + } + return { + ...config, + build: { + ...config.build, + sourcemap: true, + }, + }; + }, + }, + ...sentryVitePlugin({ + authToken: authToken ?? process.env.SENTRY_AUTH_TOKEN, + bundleSizeOptimizations: options.bundleSizeOptimizations, + debug: debug ?? false, + org: org ?? process.env.SENTRY_ORG, + project: project ?? process.env.SENTRY_PROJECT, + sourcemaps: { + filesToDeleteAfterUpload: sourceMapsUploadOptions?.filesToDeleteAfterUpload ?? undefined, + ...sourceMapsUploadOptions?.unstable_sentryVitePluginOptions?.sourcemaps, + }, + telemetry: sourceMapsUploadOptions?.telemetry ?? true, + _metaOptions: { + telemetry: { + metaFramework: 'solidstart', + }, + }, + ...sourceMapsUploadOptions?.unstable_sentryVitePluginOptions, + }), + ]; +} diff --git a/packages/solidstart/src/vite/types.ts b/packages/solidstart/src/vite/types.ts new file mode 100644 index 000000000000..4a64e4856b5d --- /dev/null +++ b/packages/solidstart/src/vite/types.ts @@ -0,0 +1,128 @@ +import type { SentryVitePluginOptions } from '@sentry/vite-plugin'; + +type SourceMapsOptions = { + /** + * If this flag is `true`, and an auth token is detected, the Sentry SDK will + * automatically generate and upload source maps to Sentry during a production build. + * + * @default true + */ + enabled?: boolean; + + /** + * If this flag is `true`, the Sentry plugin will collect some telemetry data and send it to Sentry. + * It will not collect any sensitive or user-specific data. + * + * @default true + */ + telemetry?: boolean; + + /** + * A glob or an array of globs that specifies the build artifacts that should be deleted after the artifact + * upload to Sentry has been completed. + * + * @default [] - By default no files are deleted. + * + * The globbing patterns follow the implementation of the glob package. (https://www.npmjs.com/package/glob) + */ + filesToDeleteAfterUpload?: string | Array; + + /** + * Options to further customize the Sentry Vite Plugin (@sentry/vite-plugin) behavior directly. + * Options specified in this object take precedence over the options specified in + * the `sourcemaps` and `release` objects. + * + * @see https://www.npmjs.com/package/@sentry/vite-plugin/v/2.22.2#options which lists all available options. + * + * Warning: Options within this object are subject to change at any time. + * We DO NOT guarantee semantic versioning for these options, meaning breaking + * changes can occur at any time within a major SDK version. + * + * Furthermore, some options are untested with SvelteKit specifically. Use with caution. + */ + unstable_sentryVitePluginOptions?: Partial; +}; + +type BundleSizeOptimizationOptions = { + /** + * If set to `true`, the plugin will attempt to tree-shake (remove) any debugging code within the Sentry SDK. + * Note that the success of this depends on tree shaking being enabled in your build tooling. + * + * Setting this option to `true` will disable features like the SDK's `debug` option. + */ + excludeDebugStatements?: boolean; + + /** + * If set to true, the plugin will try to tree-shake tracing statements out. + * Note that the success of this depends on tree shaking generally being enabled in your build. + * Attention: DO NOT enable this when you're using any performance monitoring-related SDK features (e.g. Sentry.startSpan()). + */ + excludeTracing?: boolean; + + /** + * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay Shadow DOM recording functionality. + * Note that the success of this depends on tree shaking being enabled in your build tooling. + * + * This option is safe to be used when you do not want to capture any Shadow DOM activity via Sentry Session Replay. + */ + excludeReplayShadowDom?: boolean; + + /** + * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay `iframe` recording functionality. + * Note that the success of this depends on tree shaking being enabled in your build tooling. + * + * You can safely do this when you do not want to capture any `iframe` activity via Sentry Session Replay. + */ + excludeReplayIframe?: boolean; + + /** + * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay's Compression Web Worker. + * Note that the success of this depends on tree shaking being enabled in your build tooling. + * + * **Notice:** You should only do use this option if you manually host a compression worker and configure it in your Sentry Session Replay integration config via the `workerUrl` option. + */ + excludeReplayWorker?: boolean; +}; + +/** + * Build options for the Sentry module. These options are used during build-time by the Sentry SDK. + */ +export type SentrySolidStartPluginOptions = { + /** + * The auth token to use when uploading source maps to Sentry. + * + * Instead of specifying this option, you can also set the `SENTRY_AUTH_TOKEN` environment variable. + * + * To create an auth token, follow this guide: + * @see https://docs.sentry.io/product/accounts/auth-tokens/#organization-auth-tokens + */ + authToken?: string; + + /** + * The organization slug of your Sentry organization. + * Instead of specifying this option, you can also set the `SENTRY_ORG` environment variable. + */ + org?: string; + + /** + * The project slug of your Sentry project. + * Instead of specifying this option, you can also set the `SENTRY_PROJECT` environment variable. + */ + project?: string; + + /** + * Options for the Sentry Vite plugin to customize the source maps upload process. + */ + sourceMapsUploadOptions?: SourceMapsOptions; + + /** + * Options for the Sentry Vite plugin to customize bundle size optimizations. + */ + bundleSizeOptimizations?: BundleSizeOptimizationOptions; + + /** + * Enable debug functionality of the SDK during build-time. + * Enabling this will give you, for example logs about source maps. + */ + debug?: boolean; +}; diff --git a/packages/solidstart/test/server/withServerActionInstrumentation.test.ts b/packages/solidstart/test/server/withServerActionInstrumentation.test.ts index 9a5b1e0c2b51..7e1686e2ccb1 100644 --- a/packages/solidstart/test/server/withServerActionInstrumentation.test.ts +++ b/packages/solidstart/test/server/withServerActionInstrumentation.test.ts @@ -10,7 +10,6 @@ import { spanToJSON, } from '@sentry/node'; import { NodeClient } from '@sentry/node'; -import { solidRouterBrowserTracingIntegration } from '@sentry/solidstart/solidrouter'; import { redirect } from '@solidjs/router'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -98,7 +97,6 @@ describe('withServerActionInstrumentation', () => { setCurrentClient(client); client.on('spanStart', span => spanStartMock(spanToJSON(span))); - client.addIntegration(solidRouterBrowserTracingIntegration()); await serverActionGetPrefecture(); expect(spanStartMock).toHaveBeenCalledWith( diff --git a/packages/solidstart/test/vite/sentrySolidStartVite.test.ts b/packages/solidstart/test/vite/sentrySolidStartVite.test.ts new file mode 100644 index 000000000000..d3f905313859 --- /dev/null +++ b/packages/solidstart/test/vite/sentrySolidStartVite.test.ts @@ -0,0 +1,50 @@ +import type { Plugin } from 'vite'; +import { describe, expect, it, vi } from 'vitest'; +import { sentrySolidStartVite } from '../../src/vite/sentrySolidStartVite'; + +vi.spyOn(console, 'log').mockImplementation(() => { + /* noop */ +}); +vi.spyOn(console, 'warn').mockImplementation(() => { + /* noop */ +}); + +function getSentrySolidStartVitePlugins(options?: Parameters[0]): Plugin[] { + return sentrySolidStartVite({ + project: 'project', + org: 'org', + authToken: 'token', + ...options, + }); +} + +describe('sentrySolidStartVite()', () => { + it('returns an array of vite plugins', () => { + const plugins = getSentrySolidStartVitePlugins(); + const names = plugins.map(plugin => plugin.name); + expect(names).toEqual([ + 'sentry-solidstart-source-maps', + 'sentry-telemetry-plugin', + 'sentry-vite-release-injection-plugin', + 'sentry-debug-id-upload-plugin', + 'sentry-vite-debug-id-injection-plugin', + 'sentry-vite-debug-id-upload-plugin', + 'sentry-file-deletion-plugin', + ]); + }); + + it("returns an empty array if source maps upload isn't enabled", () => { + const plugins = getSentrySolidStartVitePlugins({ sourceMapsUploadOptions: { enabled: false } }); + expect(plugins).toHaveLength(0); + }); + + it('returns an empty array if `NODE_ENV` is development', async () => { + const previousEnv = process.env.NODE_ENV; + process.env.NODE_ENV = 'development'; + + const plugins = getSentrySolidStartVitePlugins({ sourceMapsUploadOptions: { enabled: true } }); + expect(plugins).toHaveLength(0); + + process.env.NODE_ENV = previousEnv; + }); +}); diff --git a/packages/solidstart/test/vite/sourceMaps.test.ts b/packages/solidstart/test/vite/sourceMaps.test.ts new file mode 100644 index 000000000000..e7d6c1bd598d --- /dev/null +++ b/packages/solidstart/test/vite/sourceMaps.test.ts @@ -0,0 +1,96 @@ +import type { SentryVitePluginOptions } from '@sentry/vite-plugin'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { makeSourceMapsVitePlugin } from '../../src/vite/sourceMaps'; + +const mockedSentryVitePlugin = { + name: 'sentry-vite-debug-id-upload-plugin', + writeBundle: vi.fn(), +}; + +const sentryVitePluginSpy = vi.fn((_options: SentryVitePluginOptions) => [mockedSentryVitePlugin]); + +vi.mock('@sentry/vite-plugin', async () => { + const original = (await vi.importActual('@sentry/vite-plugin')) as any; + + return { + ...original, + sentryVitePlugin: (options: SentryVitePluginOptions) => sentryVitePluginSpy(options), + }; +}); + +beforeEach(() => { + vi.clearAllMocks(); +}); + +describe('makeSourceMapsVitePlugin()', () => { + it('returns a plugin to set `sourcemaps` to `true`', () => { + const [sourceMapsConfigPlugin, sentryVitePlugin] = makeSourceMapsVitePlugin({}); + + expect(sourceMapsConfigPlugin?.name).toEqual('sentry-solidstart-source-maps'); + expect(sourceMapsConfigPlugin?.apply).toEqual('build'); + expect(sourceMapsConfigPlugin?.enforce).toEqual('post'); + expect(sourceMapsConfigPlugin?.config).toEqual(expect.any(Function)); + + expect(sentryVitePlugin).toEqual(mockedSentryVitePlugin); + }); + + it('passes user-specified vite plugin options to vite plugin plugin', () => { + makeSourceMapsVitePlugin({ + org: 'my-org', + authToken: 'my-token', + sourceMapsUploadOptions: { + filesToDeleteAfterUpload: ['baz/*.js'], + }, + bundleSizeOptimizations: { + excludeTracing: true, + }, + }); + + expect(sentryVitePluginSpy).toHaveBeenCalledWith( + expect.objectContaining({ + org: 'my-org', + authToken: 'my-token', + sourcemaps: { + filesToDeleteAfterUpload: ['baz/*.js'], + }, + bundleSizeOptimizations: { + excludeTracing: true, + }, + }), + ); + }); + + it('should override options with unstable_sentryVitePluginOptions', () => { + makeSourceMapsVitePlugin({ + org: 'my-org', + authToken: 'my-token', + bundleSizeOptimizations: { + excludeTracing: true, + }, + sourceMapsUploadOptions: { + unstable_sentryVitePluginOptions: { + org: 'unstable-org', + sourcemaps: { + assets: ['unstable/*.js'], + }, + bundleSizeOptimizations: { + excludeTracing: false, + }, + }, + }, + }); + + expect(sentryVitePluginSpy).toHaveBeenCalledWith( + expect.objectContaining({ + org: 'unstable-org', + authToken: 'my-token', + bundleSizeOptimizations: { + excludeTracing: false, + }, + sourcemaps: { + assets: ['unstable/*.js'], + }, + }), + ); + }); +}); From a7a8b805f5a1b1fd1c68812b223c82cb6f1e34f7 Mon Sep 17 00:00:00 2001 From: Andrei <168741329+andreiborza@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:02:57 +0200 Subject: [PATCH 19/25] chore(javascript): Update READMEs of Solid and SolidStart SDKs to indicate beta status (#13591) --- packages/solid/README.md | 10 +++++----- packages/solidstart/README.md | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/solid/README.md b/packages/solid/README.md index 06012bb34be8..e5ddd2186c02 100644 --- a/packages/solid/README.md +++ b/packages/solid/README.md @@ -4,16 +4,16 @@

    -# Official Sentry SDK for Solid (EXPERIMENTAL) +# Official Sentry SDK for Solid [![npm version](https://img.shields.io/npm/v/@sentry/solid.svg)](https://www.npmjs.com/package/@sentry/solid) [![npm dm](https://img.shields.io/npm/dm/@sentry/solid.svg)](https://www.npmjs.com/package/@sentry/solid) [![npm dt](https://img.shields.io/npm/dt/@sentry/solid.svg)](https://www.npmjs.com/package/@sentry/solid) -This SDK is considered ⚠️ **experimental and in an alpha state**. It may experience breaking changes. Please reach out -on [GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns. This -SDK currently only supports [Solid](https://www.solidjs.com/) and is not yet officially compatible with -[Solid Start](https://start.solidjs.com/). +This SDK is in **Beta**. The API is stable but updates may include minor changes in behavior. Please reach out on +[GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns. This +SDK is for [Solid](https://www.solidjs.com/). If you're using [SolidStart](https://start.solidjs.com/) see our +[SolidStart SDK here](https://github.com/getsentry/sentry-javascript/tree/develop/packages/solidstart). # Solid Router diff --git a/packages/solidstart/README.md b/packages/solidstart/README.md index 1bb191994c79..ceda55838e8d 100644 --- a/packages/solidstart/README.md +++ b/packages/solidstart/README.md @@ -4,15 +4,15 @@

    -# Official Sentry SDK for Solid Start (EXPERIMENTAL) +# Official Sentry SDK for SolidStart [![npm version](https://img.shields.io/npm/v/@sentry/solidstart.svg)](https://www.npmjs.com/package/@sentry/solidstart) [![npm dm](https://img.shields.io/npm/dm/@sentry/solidstart.svg)](https://www.npmjs.com/package/@sentry/solidstart) [![npm dt](https://img.shields.io/npm/dt/@sentry/solidstart.svg)](https://www.npmjs.com/package/@sentry/solidstart) -This SDK is considered ⚠️ **experimental and in an alpha state**. It may experience breaking changes. Please reach out -on [GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns. This -SDK is for [Solid Start](https://start.solidjs.com/). If you're using [Solid](https://www.solidjs.com/) see our +This SDK is in **Beta**. The API is stable but updates may include minor changes in behavior. Please reach out on +[GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns. This +SDK is for [SolidStart](https://start.solidjs.com/). If you're using [Solid](https://www.solidjs.com/) see our [Solid SDK here](https://github.com/getsentry/sentry-javascript/tree/develop/packages/solid). ## Links @@ -22,7 +22,7 @@ SDK is for [Solid Start](https://start.solidjs.com/). If you're using [Solid](ht ## General This package is a wrapper around `@sentry/node` for the server and `@sentry/solid` for the client side, with added -functionality related to Solid Start. +functionality related to SolidStart. ## Manual Setup @@ -30,7 +30,7 @@ If the setup through the wizard doesn't work for you, you can also set up the SD ### 1. Prerequesits & Installation -Install the Sentry Solid Start SDK: +Install the Sentry SolidStart SDK: ```bash # Using npm From 75aa007f531e2481241f99973d8c44fc982ef338 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 5 Sep 2024 14:57:42 +0200 Subject: [PATCH 20/25] ci: Fix size-limit action on develop branches (#13585) Noticed this was failing on develop e.g. here: https://github.com/getsentry/sentry-javascript/actions/runs/10699493008/job/29661468888 --- dev-packages/size-limit-gh-action/index.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-packages/size-limit-gh-action/index.mjs b/dev-packages/size-limit-gh-action/index.mjs index 680d12237bf5..848802256853 100644 --- a/dev-packages/size-limit-gh-action/index.mjs +++ b/dev-packages/size-limit-gh-action/index.mjs @@ -191,6 +191,7 @@ async function run() { } async function runSizeLimitOnComparisonBranch() { + const __dirname = path.dirname(fileURLToPath(import.meta.url)); const resultsFilePath = getResultsFilePath(); const limit = new SizeLimitFormatter(); From a8e5f593b3341f90cf9aafaaa1f6eb1e0da7545e Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 5 Sep 2024 15:11:42 +0200 Subject: [PATCH 21/25] feat(node): Update OpenTelemetry packages to instrumentation v0.53.0 (#13587) This bumps all our internal OTEL instrumentation to their latest version. Mainly, this fixes two things: * Mongoose now supports v7 & v8 https://github.com/open-telemetry/opentelemetry-js-contrib/pull/2353 * A variety of bug fixes, including a problem with http.get in ESM mode https://github.com/open-telemetry/opentelemetry-js/issues/4857 - See: https://github.com/open-telemetry/opentelemetry-js/releases/tag/experimental%2Fv0.53.0 Related: * https://github.com/open-telemetry/opentelemetry-js/issues/4975 Issue about relaxing deps in "core" instrumentation packages * PR to bump deps in `@prisma/instrumentation`: https://github.com/prisma/prisma/pull/25160 * PR to bump deps in `opentelemetry-instrument-remix`: https://github.com/justindsmith/opentelemetry-instrumentations-js/pull/52 * PR to bump deps in `opentelemetry-instrumentation-fetch-node`: https://github.com/gas-buddy/opentelemetry-instrumentation-fetch-node/pull/17 (which will also be superseded by https://github.com/getsentry/sentry-javascript/pull/13485 eventually) * Closes https://github.com/getsentry/sentry-javascript/issues/11499 --- packages/aws-serverless/package.json | 4 +- packages/nextjs/package.json | 2 +- packages/node/package.json | 38 +-- packages/remix/package.json | 2 +- yarn.lock | 384 +++++++++++++++++---------- 5 files changed, 264 insertions(+), 166 deletions(-) diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json index fa20bebe24ff..e6acf8e0e2f6 100644 --- a/packages/aws-serverless/package.json +++ b/packages/aws-serverless/package.json @@ -64,8 +64,8 @@ "access": "public" }, "dependencies": { - "@opentelemetry/instrumentation-aws-lambda": "0.43.0", - "@opentelemetry/instrumentation-aws-sdk": "0.43.1", + "@opentelemetry/instrumentation-aws-lambda": "0.44.0", + "@opentelemetry/instrumentation-aws-sdk": "0.44.0", "@sentry/core": "8.28.0", "@sentry/node": "8.28.0", "@sentry/types": "8.28.0", diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 354870f6e834..1dacc4435cd4 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -68,7 +68,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/instrumentation-http": "0.52.1", + "@opentelemetry/instrumentation-http": "0.53.0", "@opentelemetry/semantic-conventions": "^1.25.1", "@rollup/plugin-commonjs": "26.0.1", "@sentry/core": "8.28.0", diff --git a/packages/node/package.json b/packages/node/package.json index 6a64f646f64c..9a7091ef57fc 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -68,28 +68,28 @@ "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.25.1", "@opentelemetry/core": "^1.25.1", - "@opentelemetry/instrumentation": "^0.52.1", - "@opentelemetry/instrumentation-connect": "0.38.0", - "@opentelemetry/instrumentation-express": "0.41.1", - "@opentelemetry/instrumentation-fastify": "0.38.0", - "@opentelemetry/instrumentation-fs": "0.14.0", - "@opentelemetry/instrumentation-generic-pool": "0.38.0", - "@opentelemetry/instrumentation-graphql": "0.42.0", - "@opentelemetry/instrumentation-hapi": "0.40.0", - "@opentelemetry/instrumentation-http": "0.52.1", - "@opentelemetry/instrumentation-ioredis": "0.42.0", - "@opentelemetry/instrumentation-koa": "0.42.0", - "@opentelemetry/instrumentation-mongodb": "0.46.0", - "@opentelemetry/instrumentation-mongoose": "0.40.0", - "@opentelemetry/instrumentation-mysql": "0.40.0", - "@opentelemetry/instrumentation-mysql2": "0.40.0", - "@opentelemetry/instrumentation-nestjs-core": "0.39.0", - "@opentelemetry/instrumentation-pg": "0.43.0", - "@opentelemetry/instrumentation-redis-4": "0.41.0", + "@opentelemetry/instrumentation": "^0.53.0", + "@opentelemetry/instrumentation-connect": "0.39.0", + "@opentelemetry/instrumentation-express": "0.42.0", + "@opentelemetry/instrumentation-fastify": "0.39.0", + "@opentelemetry/instrumentation-fs": "0.15.0", + "@opentelemetry/instrumentation-generic-pool": "0.39.0", + "@opentelemetry/instrumentation-graphql": "0.43.0", + "@opentelemetry/instrumentation-hapi": "0.41.0", + "@opentelemetry/instrumentation-http": "0.53.0", + "@opentelemetry/instrumentation-ioredis": "0.43.0", + "@opentelemetry/instrumentation-koa": "0.43.0", + "@opentelemetry/instrumentation-mongodb": "0.47.0", + "@opentelemetry/instrumentation-mongoose": "0.42.0", + "@opentelemetry/instrumentation-mysql": "0.41.0", + "@opentelemetry/instrumentation-mysql2": "0.41.0", + "@opentelemetry/instrumentation-nestjs-core": "0.40.0", + "@opentelemetry/instrumentation-pg": "0.44.0", + "@opentelemetry/instrumentation-redis-4": "0.42.0", "@opentelemetry/resources": "^1.25.1", "@opentelemetry/sdk-trace-base": "^1.25.1", "@opentelemetry/semantic-conventions": "^1.25.1", - "@prisma/instrumentation": "5.18.0", + "@prisma/instrumentation": "5.19.1", "@sentry/core": "8.28.0", "@sentry/opentelemetry": "8.28.0", "@sentry/types": "8.28.0", diff --git a/packages/remix/package.json b/packages/remix/package.json index 286926c79f1d..9b86fd631ff8 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -52,7 +52,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/instrumentation-http": "0.52.1", + "@opentelemetry/instrumentation-http": "0.53.0", "@remix-run/router": "1.x", "@sentry/cli": "^2.33.0", "@sentry/core": "8.28.0", diff --git a/yarn.lock b/yarn.lock index a79245f2672c..246bb480abd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7004,6 +7004,13 @@ dependencies: "@opentelemetry/api" "^1.0.0" +"@opentelemetry/api-logs@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.53.0.tgz#c478cbd8120ec2547b64edfa03a552cfe42170be" + integrity sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw== + dependencies: + "@opentelemetry/api" "^1.0.0" + "@opentelemetry/api@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-0.12.0.tgz#0359c3926e8f16fdcd8c78f196bd1e9fc4e66777" @@ -7047,6 +7054,13 @@ dependencies: "@opentelemetry/semantic-conventions" "1.25.1" +"@opentelemetry/core@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.26.0.tgz#7d84265aaa850ed0ca5813f97d831155be42b328" + integrity sha512-1iKxXXE8415Cdv0yjG3G6hQnB5eVEsJce3QaawX8SjDn0mAS0ZM8fAbZZJD4ajvhC15cePvosSCut404KrIIvQ== + dependencies: + "@opentelemetry/semantic-conventions" "1.27.0" + "@opentelemetry/core@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-0.12.0.tgz#a888badc9a408fa1f13976a574e69d14be32488e" @@ -7056,185 +7070,185 @@ "@opentelemetry/context-base" "^0.12.0" semver "^7.1.3" -"@opentelemetry/instrumentation-aws-lambda@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.43.0.tgz#6a96d582627873bb34d197655b7b69792f0f8da3" - integrity sha512-pSxcWlsE/pCWQRIw92sV2C+LmKXelYkjkA7C5s39iPUi4pZ2lA1nIiw+1R/y2pDEhUHcaKkNyljQr3cx9ZpVlQ== +"@opentelemetry/instrumentation-aws-lambda@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.44.0.tgz#9b82bd6cc86f572be837578b29ef6bf242eb1a39" + integrity sha512-6vmr7FJIuopZzsQjEQTp4xWtF6kBp7DhD7pPIN8FN0dKUKyuVraABIpgWjMfelaUPy4rTYUGkYqPluhG0wx8Dw== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation" "^0.53.0" "@opentelemetry/propagator-aws-xray" "^1.3.1" "@opentelemetry/resources" "^1.8.0" - "@opentelemetry/semantic-conventions" "^1.22.0" - "@types/aws-lambda" "8.10.122" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@types/aws-lambda" "8.10.143" -"@opentelemetry/instrumentation-aws-sdk@0.43.1": - version "0.43.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.43.1.tgz#b7cb8601061d57a9290cad8c499bda135ba3ba2c" - integrity sha512-qLT2cCniJ5W+6PFzKbksnoIQuq9pS83nmgaExfUwXVvlwi0ILc50dea0tWBHZMkdIDa/zZdcuFrJ7+fUcSnRow== +"@opentelemetry/instrumentation-aws-sdk@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.44.0.tgz#f1a2d8c186d37fae42954921bbdcc3555aac331c" + integrity sha512-HIWFg4TDQsayceiikOnruMmyQ0SZYW6WiR+wknWwWVLHC3lHTCpAnqzp5V42ckArOdlwHZu2Jvq2GMSM4Myx3w== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/propagation-utils" "^0.30.10" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/propagation-utils" "^0.30.11" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-connect@0.38.0": - version "0.38.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.38.0.tgz#1f4aa27894eac2538fb3c8fce7b1be92cae0217e" - integrity sha512-2/nRnx3pjYEmdPIaBwtgtSviTKHWnDZN3R+TkRUnhIVrvBKVcq+I5B2rtd6mr6Fe9cHlZ9Ojcuh7pkNh/xdWWg== +"@opentelemetry/instrumentation-connect@0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.39.0.tgz#32bdbaac464cba061c95df6c850ee81efdd86f8b" + integrity sha512-pGBiKevLq7NNglMgqzmeKczF4XQMTOUOTkK8afRHMZMnrK3fcETyTH7lVaSozwiOM3Ws+SuEmXZT7DYrrhxGlg== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" "@types/connect" "3.4.36" -"@opentelemetry/instrumentation-express@0.41.1": - version "0.41.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-express/-/instrumentation-express-0.41.1.tgz#658561df6ffbae86f5ad33e8d7ef2abb7b4967fc" - integrity sha512-uRx0V3LPGzjn2bxAnV8eUsDT82vT7NTwI0ezEuPMBOTOsnPpGhWdhcdNdhH80sM4TrWrOfXm9HGEdfWE3TRIww== +"@opentelemetry/instrumentation-express@0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-express/-/instrumentation-express-0.42.0.tgz#279f195aa66baee2b98623a16666c6229c8e7564" + integrity sha512-YNcy7ZfGnLsVEqGXQPT+S0G1AE46N21ORY7i7yUQyfhGAL4RBjnZUqefMI0NwqIl6nGbr1IpF0rZGoN8Q7x12Q== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-fastify@0.38.0": - version "0.38.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.38.0.tgz#0cb02ee1156197075e8a90e4fd18a6b6c94221ba" - integrity sha512-HBVLpTSYpkQZ87/Df3N0gAw7VzYZV3n28THIBrJWfuqw3Or7UqdhnjeuMIPQ04BKk3aZc0cWn2naSQObbh5vXw== +"@opentelemetry/instrumentation-fastify@0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.39.0.tgz#96a040e4944daf77c53a8fe5a128bc3b2568e4aa" + integrity sha512-SS9uSlKcsWZabhBp2szErkeuuBDgxOUlllwkS92dVaWRnMmwysPhcEgHKB8rUe3BHg/GnZC1eo1hbTZv4YhfoA== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-fs@0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.14.0.tgz#19f1cb38a8c2d05f3b96af67f1c8d43f0af2829b" - integrity sha512-pVc8P5AgliC1DphyyBUgsxXlm2XaPH4BpYvt7rAZDMIqUpRk8gs19SioABtKqqxvFzg5jPtgJfJsdxq0Y+maLw== +"@opentelemetry/instrumentation-fs@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.15.0.tgz#41658507860f39fee5209bca961cea8d24ca2a83" + integrity sha512-JWVKdNLpu1skqZQA//jKOcKdJC66TWKqa2FUFq70rKohvaSq47pmXlnabNO+B/BvLfmidfiaN35XakT5RyMl2Q== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation" "^0.53.0" -"@opentelemetry/instrumentation-generic-pool@0.38.0": - version "0.38.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.38.0.tgz#9ea4d82da23541cda613d553bd405b2cbc0da184" - integrity sha512-0/ULi6pIco1fEnDPmmAul8ZoudFL7St0hjgBbWZlZPBCSyslDll1J7DFeEbjiRSSyUd+0tu73ae0DOKVKNd7VA== +"@opentelemetry/instrumentation-generic-pool@0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.39.0.tgz#2b9af16ad82d5cbe67125c0125753cecd162a728" + integrity sha512-y4v8Y+tSfRB3NNBvHjbjrn7rX/7sdARG7FuK6zR8PGb28CTa0kHpEGCJqvL9L8xkTNvTXo+lM36ajFGUaK1aNw== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation" "^0.53.0" -"@opentelemetry/instrumentation-graphql@0.42.0": - version "0.42.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.42.0.tgz#588a18c39e3b3f655bc09243566172ab0b638d35" - integrity sha512-N8SOwoKL9KQSX7z3gOaw5UaTeVQcfDO1c21csVHnmnmGUoqsXbArK2B8VuwPWcv6/BC/i3io+xTo7QGRZ/z28Q== +"@opentelemetry/instrumentation-graphql@0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.43.0.tgz#71bb94ea775c70dbd388c739b397ec1418f3f170" + integrity sha512-aI3YMmC2McGd8KW5du1a2gBA0iOMOGLqg4s9YjzwbjFwjlmMNFSK1P3AIg374GWg823RPUGfVTIgZ/juk9CVOA== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation" "^0.53.0" -"@opentelemetry/instrumentation-hapi@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.40.0.tgz#ae11190f0f57cdb4dc8d792cb8bca61e5343684c" - integrity sha512-8U/w7Ifumtd2bSN1OLaSwAAFhb9FyqWUki3lMMB0ds+1+HdSxYBe9aspEJEgvxAqOkrQnVniAPTEGf1pGM7SOw== +"@opentelemetry/instrumentation-hapi@0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.41.0.tgz#de8711907256d8fae1b5faf71fc825cef4a7ddbb" + integrity sha512-jKDrxPNXDByPlYcMdZjNPYCvw0SQJjN+B1A+QH+sx+sAHsKSAf9hwFiJSrI6C4XdOls43V/f/fkp9ITkHhKFbQ== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-http@0.52.1": - version "0.52.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.52.1.tgz#12061501601838d1c912f9c29bdd40a13a7e44cf" - integrity sha512-dG/aevWhaP+7OLv4BQQSEKMJv8GyeOp3Wxl31NHqE8xo9/fYMfEljiZphUHIfyg4gnZ9swMyWjfOQs5GUQe54Q== +"@opentelemetry/instrumentation-http@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.53.0.tgz#0d806adf1b3aba036bc46e16162e3c0dbb8a6b60" + integrity sha512-H74ErMeDuZfj7KgYCTOFGWF5W9AfaPnqLQQxeFq85+D29wwV2yqHbz2IKLYpkOh7EI6QwDEl7rZCIxjJLyc/CQ== dependencies: - "@opentelemetry/core" "1.25.1" - "@opentelemetry/instrumentation" "0.52.1" - "@opentelemetry/semantic-conventions" "1.25.1" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/instrumentation" "0.53.0" + "@opentelemetry/semantic-conventions" "1.27.0" semver "^7.5.2" -"@opentelemetry/instrumentation-ioredis@0.42.0": - version "0.42.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.42.0.tgz#0f488ffc68af3caa474e2f67861759075170729c" - integrity sha512-P11H168EKvBB9TUSasNDOGJCSkpT44XgoM6d3gRIWAa9ghLpYhl0uRkS8//MqPzcJVHr3h3RmfXIpiYLjyIZTw== +"@opentelemetry/instrumentation-ioredis@0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.43.0.tgz#dbadabaeefc4cb47c406f878444f1bcac774fa89" + integrity sha512-i3Dke/LdhZbiUAEImmRG3i7Dimm/BD7t8pDDzwepSvIQ6s2X6FPia7561gw+64w+nx0+G9X14D7rEfaMEmmjig== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation" "^0.53.0" "@opentelemetry/redis-common" "^0.36.2" - "@opentelemetry/semantic-conventions" "^1.23.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-koa@0.42.0": - version "0.42.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.42.0.tgz#1c180f3605448c2e57a4ba073b69ffba7b2970b3" - integrity sha512-H1BEmnMhho8o8HuNRq5zEI4+SIHDIglNB7BPKohZyWG4fWNuR7yM4GTlR01Syq21vODAS7z5omblScJD/eZdKw== +"@opentelemetry/instrumentation-koa@0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.43.0.tgz#963fd192a1b5f6cbae5dabf4ec82e3105cbb23b1" + integrity sha512-lDAhSnmoTIN6ELKmLJBplXzT/Jqs5jGZehuG22EdSMaTwgjMpxMDI1YtlKEhiWPWkrz5LUsd0aOO0ZRc9vn3AQ== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-mongodb@0.46.0": - version "0.46.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.46.0.tgz#e3720e8ca3ca9f228fbf02f0812f7518c030b05e" - integrity sha512-VF/MicZ5UOBiXrqBslzwxhN7TVqzu1/LN/QDpkskqM0Zm0aZ4CVRbUygL8d7lrjLn15x5kGIe8VsSphMfPJzlA== +"@opentelemetry/instrumentation-mongodb@0.47.0": + version "0.47.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.47.0.tgz#f8107d878281433905e717f223fb4c0f10356a7b" + integrity sha512-yqyXRx2SulEURjgOQyJzhCECSh5i1uM49NUaq9TqLd6fA7g26OahyJfsr9NE38HFqGRHpi4loyrnfYGdrsoVjQ== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation" "^0.53.0" "@opentelemetry/sdk-metrics" "^1.9.1" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-mongoose@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.40.0.tgz#9c888312e524c381bfdf56a094c799150332dd51" - integrity sha512-niRi5ZUnkgzRhIGMOozTyoZIvJKNJyhijQI4nF4iFSb+FUx2v5fngfR+8XLmdQAO7xmsD8E5vEGdDVYVtKbZew== +"@opentelemetry/instrumentation-mongoose@0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.42.0.tgz#375afd21adfcd897a8f521c1ffd2d91e6a428705" + integrity sha512-AnWv+RaR86uG3qNEMwt3plKX1ueRM7AspfszJYVkvkehiicC3bHQA6vWdb6Zvy5HAE14RyFbu9+2hUUjR2NSyg== dependencies: "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-mysql2@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.40.0.tgz#fa2992c36d54427dccea68e5c69fff01103dabe6" - integrity sha512-0xfS1xcqUmY7WE1uWjlmI67Xg3QsSUlNT+AcXHeA4BDUPwZtWqF4ezIwLgpVZfHOnkAEheqGfNSWd1PIu3Wnfg== +"@opentelemetry/instrumentation-mysql2@0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.41.0.tgz#6377b6e2d2487fd88e1d79aa03658db6c8d51651" + integrity sha512-REQB0x+IzVTpoNgVmy5b+UnH1/mDByrneimP6sbDHkp1j8QOl1HyWOrBH/6YWR0nrbU3l825Em5PlybjT3232g== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" "@opentelemetry/sql-common" "^0.40.1" -"@opentelemetry/instrumentation-mysql@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.40.0.tgz#bde5894c8eb447a4b8e940b030b2b73898da03fa" - integrity sha512-d7ja8yizsOCNMYIJt5PH/fKZXjb/mS48zLROO4BzZTtDfhNCl2UM/9VIomP2qkGIFVouSJrGr/T00EzY7bPtKA== +"@opentelemetry/instrumentation-mysql@0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.41.0.tgz#2d50691ead5219774bd36d66c35d5b4681485dd7" + integrity sha512-jnvrV6BsQWyHS2qb2fkfbfSb1R/lmYwqEZITwufuRl37apTopswu9izc0b1CYRp/34tUG/4k/V39PND6eyiNvw== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" - "@types/mysql" "2.15.22" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@types/mysql" "2.15.26" -"@opentelemetry/instrumentation-nestjs-core@0.39.0": - version "0.39.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.39.0.tgz#733fef4306c796951d7ea1951b45f9df0aed234d" - integrity sha512-mewVhEXdikyvIZoMIUry8eb8l3HUjuQjSjVbmLVTt4NQi35tkpnHQrG9bTRBrl3403LoWZ2njMPJyg4l6HfKvA== +"@opentelemetry/instrumentation-nestjs-core@0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.40.0.tgz#2c0e6405b56caaec32747d55c57ff9a034668ea8" + integrity sha512-WF1hCUed07vKmf5BzEkL0wSPinqJgH7kGzOjjMAiTGacofNXjb/y4KQ8loj2sNsh5C/NN7s1zxQuCgbWbVTGKg== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.23.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-pg@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.43.0.tgz#3cd94ad5144e1fd326a921280fa8bb7b49005eb5" - integrity sha512-og23KLyoxdnAeFs1UWqzSonuCkePUzCX30keSYigIzJe/6WSYA8rnEI5lobcxPEzg+GcU06J7jzokuEHbjVJNw== +"@opentelemetry/instrumentation-pg@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.44.0.tgz#1e97a0aeb2dca068ee23ce75884a0a0063a7ce3f" + integrity sha512-oTWVyzKqXud1BYEGX1loo2o4k4vaU1elr3vPO8NZolrBtFvQ34nx4HgUaexUDuEog00qQt+MLR5gws/p+JXMLQ== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" "@opentelemetry/sql-common" "^0.40.1" "@types/pg" "8.6.1" - "@types/pg-pool" "2.0.4" + "@types/pg-pool" "2.0.6" -"@opentelemetry/instrumentation-redis-4@0.41.0": - version "0.41.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.41.0.tgz#6c1b1a37c18478887f346a3bc7ef309ee9f726c0" - integrity sha512-H7IfGTqW2reLXqput4yzAe8YpDC0fmVNal95GHMLOrS89W+qWUKIqxolSh63hJyfmwPSFwXASzj7wpSk8Az+Dg== +"@opentelemetry/instrumentation-redis-4@0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.42.0.tgz#fc01104cfe884c7546385eaae03c57a47edd19d1" + integrity sha512-NaD+t2JNcOzX/Qa7kMy68JbmoVIV37fT/fJYzLKu2Wwd+0NCxt+K2OOsOakA8GVg8lSpFdbx4V/suzZZ2Pvdjg== dependencies: - "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/instrumentation" "^0.53.0" "@opentelemetry/redis-common" "^0.36.2" - "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation@0.52.1", "@opentelemetry/instrumentation@^0.49 || ^0.50 || ^0.51 || ^0.52.0", "@opentelemetry/instrumentation@^0.52.0", "@opentelemetry/instrumentation@^0.52.1": - version "0.52.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.52.1.tgz#2e7e46a38bd7afbf03cf688c862b0b43418b7f48" - integrity sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw== +"@opentelemetry/instrumentation@0.53.0", "@opentelemetry/instrumentation@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.53.0.tgz#e6369e4015eb5112468a4d45d38dcada7dad892d" + integrity sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A== dependencies: - "@opentelemetry/api-logs" "0.52.1" - "@types/shimmer" "^1.0.2" + "@opentelemetry/api-logs" "0.53.0" + "@types/shimmer" "^1.2.0" import-in-the-middle "^1.8.1" require-in-the-middle "^7.1.1" semver "^7.5.2" @@ -7262,6 +7276,18 @@ semver "^7.5.2" shimmer "^1.2.1" +"@opentelemetry/instrumentation@^0.49 || ^0.50 || ^0.51 || ^0.52.0", "@opentelemetry/instrumentation@^0.52.1": + version "0.52.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.52.1.tgz#2e7e46a38bd7afbf03cf688c862b0b43418b7f48" + integrity sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw== + dependencies: + "@opentelemetry/api-logs" "0.52.1" + "@types/shimmer" "^1.0.2" + import-in-the-middle "^1.8.1" + require-in-the-middle "^7.1.1" + semver "^7.5.2" + shimmer "^1.2.1" + "@opentelemetry/otlp-transformer@^0.50.0": version "0.50.0" resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.50.0.tgz#211fe512fcce9d76042680f955336dbde3be03ef" @@ -7274,10 +7300,10 @@ "@opentelemetry/sdk-metrics" "1.23.0" "@opentelemetry/sdk-trace-base" "1.23.0" -"@opentelemetry/propagation-utils@^0.30.10": - version "0.30.10" - resolved "https://registry.yarnpkg.com/@opentelemetry/propagation-utils/-/propagation-utils-0.30.10.tgz#d3074f7365efc62845928098bb15804aca47aaf0" - integrity sha512-hhTW8pFp9PSyosYzzuUL9rdm7HF97w3OCyElufFHyUnYnKkCBbu8ne2LyF/KSdI/xZ81ubxWZs78hX4S7pLq5g== +"@opentelemetry/propagation-utils@^0.30.11": + version "0.30.11" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagation-utils/-/propagation-utils-0.30.11.tgz#0a1c51cb4a2724fa41c41be07024bbb6f0aade46" + integrity sha512-rY4L/2LWNk5p/22zdunpqVmgz6uN419DsRTw5KFMa6u21tWhXS8devlMy4h8m8nnS20wM7r6yYweCNNKjgLYJw== "@opentelemetry/propagator-aws-xray@^1.3.1": version "1.25.1" @@ -7377,11 +7403,16 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.0.tgz#390eb4d42a29c66bdc30066af9035645e9bb7270" integrity sha512-M+kkXKRAIAiAP6qYyesfrC5TOmDpDVtsxuGfPcqd9B/iBrac+E14jYwrgm0yZBUIbIP2OnqC3j+UgkXLm1vxUQ== -"@opentelemetry/semantic-conventions@1.25.1", "@opentelemetry/semantic-conventions@^1.17.0", "@opentelemetry/semantic-conventions@^1.22.0", "@opentelemetry/semantic-conventions@^1.23.0", "@opentelemetry/semantic-conventions@^1.25.1": +"@opentelemetry/semantic-conventions@1.25.1", "@opentelemetry/semantic-conventions@^1.17.0", "@opentelemetry/semantic-conventions@^1.23.0", "@opentelemetry/semantic-conventions@^1.25.1": version "1.25.1" resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz#0deecb386197c5e9c2c28f2f89f51fb8ae9f145e" integrity sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ== +"@opentelemetry/semantic-conventions@1.27.0", "@opentelemetry/semantic-conventions@^1.27.0": + version "1.27.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz#1a857dcc95a5ab30122e04417148211e6f945e6c" + integrity sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg== + "@opentelemetry/semantic-conventions@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-0.12.0.tgz#7e392aecdbdbd5d737d3995998b120dc17589ab0" @@ -7532,10 +7563,10 @@ resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.9.1.tgz#d92bd2f7f006e0316cb4fda9d73f235965cf2c64" integrity sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ== -"@prisma/instrumentation@5.18.0": - version "5.18.0" - resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-5.18.0.tgz#8b49e25bf3f8f756eb0c4c199b4cf8b6631db891" - integrity sha512-r074avGkpPXItk+josQPhufZEmGhUCb16PQx4ITPS40vWTpTPET4VsgCBZB2alIN6SS7pRFod2vz2M2HHEEylQ== +"@prisma/instrumentation@5.19.1": + version "5.19.1" + resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-5.19.1.tgz#146319cf85f22b7a43296f0f40cfeac55516e66e" + integrity sha512-VLnzMQq7CWroL5AeaW0Py2huiNKeoMfCH3SUxstdzPrlWQi6UQ9UrfcbUkNHlVFqOMacqy8X/8YtE0kuKDpD9w== dependencies: "@opentelemetry/api" "^1.8" "@opentelemetry/instrumentation" "^0.49 || ^0.50 || ^0.51 || ^0.52.0" @@ -9205,7 +9236,12 @@ resolved "https://registry.yarnpkg.com/@types/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz#5433a141730f8e1d7a8e7486458ceb8144ee5edc" integrity sha512-JOvNJUU/zjfJWcA1aHDnCKHwQjZ7VQ3UNfbcMKXrkQKKyMkJHrQ9vpSVMhgsztrtsbIRJKazMDvg2QggFVwJqw== -"@types/aws-lambda@8.10.122", "@types/aws-lambda@^8.10.62": +"@types/aws-lambda@8.10.143": + version "8.10.143" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.143.tgz#383693fbaadc6994a71d64a7c09e8c244fad8dff" + integrity sha512-u5vzlcR14ge/4pMTTMDQr3MF0wEe38B2F9o84uC4F43vN5DGTy63npRrB6jQhyt+C0lGv4ZfiRcRkqJoZuPnmg== + +"@types/aws-lambda@^8.10.62": version "8.10.122" resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.122.tgz#206c8d71b09325d26a458dba27db842afdc54df1" integrity sha512-vBkIh9AY22kVOCEKo5CJlyCgmSWvasC+SWUxL/x/vOwRobMpI/HG1xp/Ae3AqmSiZeLUbOhW0FCD3ZjqqUxmXw== @@ -9689,7 +9725,17 @@ dependencies: "@types/unist" "*" -"@types/history-4@npm:@types/history@4.7.8", "@types/history-5@npm:@types/history@4.7.8", "@types/history@*": +"@types/history-4@npm:@types/history@4.7.8": + version "4.7.8" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" + integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== + +"@types/history-5@npm:@types/history@4.7.8": + version "4.7.8" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" + integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== + +"@types/history@*": version "4.7.8" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== @@ -9844,7 +9890,14 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.32.tgz#f6cd08939ae3ad886fcc92ef7f0109dacddf61ab" integrity sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g== -"@types/mysql@2.15.22", "@types/mysql@^2.15.21": +"@types/mysql@2.15.26": + version "2.15.26" + resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.26.tgz#f0de1484b9e2354d587e7d2bd17a873cc8300836" + integrity sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ== + dependencies: + "@types/node" "*" + +"@types/mysql@^2.15.21": version "2.15.22" resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.22.tgz#8705edb9872bf4aa9dbc004cd494e00334e5cdb4" integrity sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ== @@ -9940,10 +9993,10 @@ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb" integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g== -"@types/pg-pool@2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.4.tgz#b5c60f678094ff3acf3442628a7f708928fcf263" - integrity sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ== +"@types/pg-pool@2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.6.tgz#1376d9dc5aec4bb2ec67ce28d7e9858227403c77" + integrity sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ== dependencies: "@types/pg" "*" @@ -10010,7 +10063,15 @@ "@types/history" "^3" "@types/react" "*" -"@types/react-router-4@npm:@types/react-router@5.1.14", "@types/react-router-5@npm:@types/react-router@5.1.14": +"@types/react-router-4@npm:@types/react-router@5.1.14": + version "5.1.14" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" + integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== + dependencies: + "@types/history" "*" + "@types/react" "*" + +"@types/react-router-5@npm:@types/react-router@5.1.14": version "5.1.14" resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== @@ -10121,6 +10182,11 @@ resolved "https://registry.yarnpkg.com/@types/shimmer/-/shimmer-1.0.2.tgz#93eb2c243c351f3f17d5c580c7467ae5d686b65f" integrity sha512-dKkr1bTxbEsFlh2ARpKzcaAmsYixqt9UyCdoEZk8rHyE4iQYcDCyvSjDSf7JUWJHlJiTtbIoQjxKh6ViywqDAg== +"@types/shimmer@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/shimmer/-/shimmer-1.2.0.tgz#9b706af96fa06416828842397a70dfbbf1c14ded" + integrity sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg== + "@types/sinon@^10.0.13": version "10.0.16" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.16.tgz#4bf10313bd9aa8eef1e50ec9f4decd3dd455b4d3" @@ -28426,7 +28492,7 @@ react-is@^18.0.0: dependencies: "@remix-run/router" "1.0.2" -"react-router-6@npm:react-router@6.3.0", react-router@6.3.0: +"react-router-6@npm:react-router@6.3.0": version "6.3.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== @@ -28441,6 +28507,13 @@ react-router-dom@^6.2.2: history "^5.2.0" react-router "6.3.0" +react-router@6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" + integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== + dependencies: + history "^5.2.0" + react@^18.0.0: version "18.0.0" resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96" @@ -30919,7 +30992,16 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= -"string-width-cjs@npm:string-width@^4.2.0", string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -31031,7 +31113,14 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -34000,7 +34089,16 @@ wrangler@^3.67.1: optionalDependencies: fsevents "~2.3.2" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@7.0.0, wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From bdec0334e9a353f8fdd2812ef0a28d5c0eb6f6bd Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 6 Sep 2024 12:09:19 +0200 Subject: [PATCH 22/25] fix(gatsby): Fix assets path for sourcemaps upload (#13592) https://github.com/getsentry/sentry-javascript/issues/13582#issuecomment-2331078028 correctly identified that this path is messed up. --- packages/gatsby/gatsby-node.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby/gatsby-node.js b/packages/gatsby/gatsby-node.js index d60914a03061..de88ee73adc0 100644 --- a/packages/gatsby/gatsby-node.js +++ b/packages/gatsby/gatsby-node.js @@ -12,7 +12,7 @@ exports.onCreateWebpackConfig = ({ getConfig, actions }, options) => { sentryWebpackPlugin({ sourcemaps: { // Only include files from the build output directory - assets: ['public'], + assets: ['./public/**'], // Ignore files that aren't users' source code related ignore: [ 'polyfill-*', // related to polyfills From 8a8f08f789be5effff39a3643f0eb9319b842c37 Mon Sep 17 00:00:00 2001 From: Andrei <168741329+andreiborza@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:06:36 +0200 Subject: [PATCH 23/25] fix(nextjs): Use posix paths for sourcemap uploads (#13603) Currently, we use `path.join` to provide sourcemap directories. On Windows, the resulting strings would use `\` which is an escape character for glob patterns and thus no sourcemaps would be found. This fix ensures we use posix paths which glob then handles correctly on Windows too. Closes: https://github.com/getsentry/sentry-javascript/issues/13270 Partly fixes: https://github.com/getsentry/sentry-javascript/issues/13288 --- .../nextjs/src/config/webpackPluginOptions.ts | 36 +++++++++++-------- .../webpack/webpackPluginOptions.test.ts | 22 +++++++++++- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/packages/nextjs/src/config/webpackPluginOptions.ts b/packages/nextjs/src/config/webpackPluginOptions.ts index 1bca9bff49b6..7b183047896a 100644 --- a/packages/nextjs/src/config/webpackPluginOptions.ts +++ b/packages/nextjs/src/config/webpackPluginOptions.ts @@ -11,37 +11,43 @@ export function getWebpackPluginOptions( buildContext: BuildContext, sentryBuildOptions: SentryBuildOptions, ): SentryWebpackPluginOptions { - const { buildId, isServer, config: userNextConfig, dir: projectDir, nextRuntime } = buildContext; + const { buildId, isServer, config: userNextConfig, dir, nextRuntime } = buildContext; const prefixInsert = !isServer ? 'Client' : nextRuntime === 'edge' ? 'Edge' : 'Node.js'; - const distDirAbsPath = path.join(projectDir, (userNextConfig as NextConfigObject).distDir || '.next'); // `.next` is the default directory + // We need to convert paths to posix because Glob patterns use `\` to escape + // glob characters. This clashes with Windows path separators. + // See: https://www.npmjs.com/package/glob + const projectDir = dir.replace(/\\/g, '/'); + // `.next` is the default directory + const distDir = (userNextConfig as NextConfigObject).distDir?.replace(/\\/g, '/') ?? '.next'; + const distDirAbsPath = path.posix.join(projectDir, distDir); let sourcemapUploadAssets: string[] = []; const sourcemapUploadIgnore: string[] = []; if (isServer) { sourcemapUploadAssets.push( - path.join(distDirAbsPath, 'server', '**'), // This is normally where Next.js outputs things - path.join(distDirAbsPath, 'serverless', '**'), // This was the output location for serverless Next.js + path.posix.join(distDirAbsPath, 'server', '**'), // This is normally where Next.js outputs things + path.posix.join(distDirAbsPath, 'serverless', '**'), // This was the output location for serverless Next.js ); } else { if (sentryBuildOptions.widenClientFileUpload) { - sourcemapUploadAssets.push(path.join(distDirAbsPath, 'static', 'chunks', '**')); + sourcemapUploadAssets.push(path.posix.join(distDirAbsPath, 'static', 'chunks', '**')); } else { sourcemapUploadAssets.push( - path.join(distDirAbsPath, 'static', 'chunks', 'pages', '**'), - path.join(distDirAbsPath, 'static', 'chunks', 'app', '**'), + path.posix.join(distDirAbsPath, 'static', 'chunks', 'pages', '**'), + path.posix.join(distDirAbsPath, 'static', 'chunks', 'app', '**'), ); } // TODO: We should think about uploading these when `widenClientFileUpload` is `true`. They may be useful in some situations. sourcemapUploadIgnore.push( - path.join(distDirAbsPath, 'static', 'chunks', 'framework-*'), - path.join(distDirAbsPath, 'static', 'chunks', 'framework.*'), - path.join(distDirAbsPath, 'static', 'chunks', 'main-*'), - path.join(distDirAbsPath, 'static', 'chunks', 'polyfills-*'), - path.join(distDirAbsPath, 'static', 'chunks', 'webpack-*'), + path.posix.join(distDirAbsPath, 'static', 'chunks', 'framework-*'), + path.posix.join(distDirAbsPath, 'static', 'chunks', 'framework.*'), + path.posix.join(distDirAbsPath, 'static', 'chunks', 'main-*'), + path.posix.join(distDirAbsPath, 'static', 'chunks', 'polyfills-*'), + path.posix.join(distDirAbsPath, 'static', 'chunks', 'webpack-*'), ); } @@ -79,9 +85,9 @@ export function getWebpackPluginOptions( // We only care to delete client bundle source maps because they would be the ones being served. // Removing the server source maps crashes Vercel builds for (thus far) unknown reasons: // https://github.com/getsentry/sentry-javascript/issues/13099 - path.join(distDirAbsPath, 'static', '**', '*.js.map'), - path.join(distDirAbsPath, 'static', '**', '*.mjs.map'), - path.join(distDirAbsPath, 'static', '**', '*.cjs.map'), + path.posix.join(distDirAbsPath, 'static', '**', '*.js.map'), + path.posix.join(distDirAbsPath, 'static', '**', '*.mjs.map'), + path.posix.join(distDirAbsPath, 'static', '**', '*.cjs.map'), ] : undefined, ...sentryBuildOptions.unstable_sentryWebpackPluginOptions?.sourcemaps, diff --git a/packages/nextjs/test/config/webpack/webpackPluginOptions.test.ts b/packages/nextjs/test/config/webpack/webpackPluginOptions.test.ts index 557859b2a7e1..177077d2b5c4 100644 --- a/packages/nextjs/test/config/webpack/webpackPluginOptions.test.ts +++ b/packages/nextjs/test/config/webpack/webpackPluginOptions.test.ts @@ -2,6 +2,7 @@ import type { BuildContext, NextConfigObject } from '../../../src/config/types'; import { getWebpackPluginOptions } from '../../../src/config/webpackPluginOptions'; function generateBuildContext(overrides: { + dir?: string; isServer: boolean; nextjsConfig?: NextConfigObject; }): BuildContext { @@ -9,7 +10,7 @@ function generateBuildContext(overrides: { dev: false, // The plugin is not included in dev mode isServer: overrides.isServer, buildId: 'test-build-id', - dir: '/my/project/dir', + dir: overrides.dir ?? '/my/project/dir', config: overrides.nextjsConfig ?? {}, totalPages: 2, defaultLoaders: true, @@ -171,4 +172,23 @@ describe('getWebpackPluginOptions()', () => { assets: [], }); }); + + it('passes posix paths to the plugin', () => { + const buildContext = generateBuildContext({ + dir: 'C:\\my\\windows\\project\\dir', + nextjsConfig: { distDir: '.dist\\v1' }, + isServer: false, + }); + const generatedPluginOptions = getWebpackPluginOptions(buildContext, { widenClientFileUpload: true }); + expect(generatedPluginOptions.sourcemaps).toMatchObject({ + assets: ['C:/my/windows/project/dir/.dist/v1/static/chunks/**'], + ignore: [ + 'C:/my/windows/project/dir/.dist/v1/static/chunks/framework-*', + 'C:/my/windows/project/dir/.dist/v1/static/chunks/framework.*', + 'C:/my/windows/project/dir/.dist/v1/static/chunks/main-*', + 'C:/my/windows/project/dir/.dist/v1/static/chunks/polyfills-*', + 'C:/my/windows/project/dir/.dist/v1/static/chunks/webpack-*', + ], + }); + }); }); From e5d157563e0493822c4aa8751dfb1f55217dfc5d Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:11:53 -0400 Subject: [PATCH 24/25] fix(replays): Improve replay web vital types (#13602) Removes optional types so that type mismatches would be caught by typescript Follow up to https://github.com/getsentry/sentry-javascript/pull/13573 --- .../replay-internal/src/types/performance.ts | 2 +- .../src/util/createPerformanceEntries.ts | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/replay-internal/src/types/performance.ts b/packages/replay-internal/src/types/performance.ts index b3dcab0e7dd7..f598581c93ab 100644 --- a/packages/replay-internal/src/types/performance.ts +++ b/packages/replay-internal/src/types/performance.ts @@ -114,7 +114,7 @@ export interface WebVitalData { /** * The layout shifts of a CLS metric */ - attributions?: { value: number; nodeIds?: number[] }[]; + attributions?: { value: number; nodeIds: number[] | undefined }[]; } /** diff --git a/packages/replay-internal/src/util/createPerformanceEntries.ts b/packages/replay-internal/src/util/createPerformanceEntries.ts index 0c22ba73163a..c28e69caee00 100644 --- a/packages/replay-internal/src/util/createPerformanceEntries.ts +++ b/packages/replay-internal/src/util/createPerformanceEntries.ts @@ -58,11 +58,6 @@ interface LayoutShiftAttribution { currentRect: DOMRectReadOnly; } -interface Attribution { - value: number; - nodeIds?: number[]; -} - /** * Handler creater for web vitals */ @@ -206,7 +201,7 @@ function isLayoutShift(entry: PerformanceEntry): entry is LayoutShift { * Add a CLS event to the replay based on a CLS metric. */ export function getCumulativeLayoutShift(metric: Metric): ReplayPerformanceEntry { - const layoutShifts: Attribution[] = []; + const layoutShifts: WebVitalData['attributions'] = []; const nodes: Node[] = []; for (const entry of metric.entries) { if (isLayoutShift(entry)) { @@ -220,9 +215,10 @@ export function getCumulativeLayoutShift(metric: Metric): ReplayPerformanceEntry } } } - layoutShifts.push({ value: entry.value, nodeIds }); + layoutShifts.push({ value: entry.value, nodeIds: nodeIds.length ? nodeIds : undefined }); } } + return getWebVital(metric, 'cumulative-layout-shift', nodes, layoutShifts); } @@ -251,14 +247,14 @@ function getWebVital( metric: Metric, name: string, nodes: Node[] | undefined, - attributions?: Attribution[], + attributions?: WebVitalData['attributions'], ): ReplayPerformanceEntry { const value = metric.value; const rating = metric.rating; const end = getAbsoluteTime(value); - const data: ReplayPerformanceEntry = { + return { type: 'web-vital', name, start: end, @@ -271,6 +267,4 @@ function getWebVital( attributions, }, }; - - return data; } From d28a0e52aa46931f93ac7c48edaf89c5c7e015bc Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Thu, 5 Sep 2024 21:16:28 +0900 Subject: [PATCH 25/25] meta(changelog): Update changelog for 8.29.0 --- CHANGELOG.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 234c9e5704a3..7b0f4361b92b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,55 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +## 8.29.0 + +### Important Changes + +- **Beta releases of official Solid and SolidStart Sentry SDKs** + +This release marks the beta releases of the `@sentry/solid` and `@sentry/solidstart` Sentry SDKs. For details on how to +use them, check out the +[Sentry Solid SDK README](https://github.com/getsentry/sentry-javascript/tree/develop/packages/solid) and the +[Sentry SolidStart SDK README](https://github.com/getsentry/sentry-javascript/tree/develop/packages/solidstart) +respectively. Please reach out on [GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have +any feedback or concerns. + +- **feat(node): Option to only wrap instrumented modules (#13139)** + +Adds the SDK option to only wrap ES modules with `import-in-the-middle` that specifically need to be instrumented. + +```javascript +import * as Sentry from '@sentry/node'; + +Sentry.init({ + dsn: '__PUBLIC_DSN__', + registerEsmLoaderHooks: { onlyHookedModules: true }, +}); +``` + +- **feat(node): Update OpenTelemetry packages to instrumentation v0.53.0 (#13587)** + +All internal OpenTelemetry instrumentation was updated to their latest version. This adds support for Mongoose v7 and v8 +and fixes various bugs related to ESM mode. + +### Other Changes + +- feat(nextjs): Emit warning when using turbopack (#13566) +- feat(nextjs): Future-proof Next.js config options overriding (#13586) +- feat(node): Add `generic-pool` integration (#13465) +- feat(nuxt): Upload sourcemaps generated by Nitro (#13382) +- feat(solidstart): Add `browserTracingIntegration` by default (#13561) +- feat(solidstart): Add `sentrySolidStartVite` plugin to simplify source maps upload (#13493) +- feat(vue): Only start UI spans if parent is available (#13568) +- fix(cloudflare): Guard `context.waitUntil` call in request handler (#13549) +- fix(gatsby): Fix assets path for sourcemaps upload (#13592) +- fix(nextjs): Use posix paths for sourcemap uploads (#13603) +- fix(node-fetch): Use stringified origin url (#13581) +- fix(node): Replace dashes in `generic-pool` span origins with underscores (#13579) +- fix(replay): Fix types in WebVitalData (#13573) +- fix(replay): Improve replay web vital types (#13602) +- fix(utils): Keep logger on carrier (#13570) + Work in this release was contributed by @Zen-cronic. Thank you for your contribution! ## 8.28.0