diff --git a/.claude/settings.local.json b/.claude/settings.json similarity index 100% rename from .claude/settings.local.json rename to .claude/settings.json diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 38da90a027b8..64709dd1f999 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -133,6 +133,16 @@ body: description: Logs? Screenshots? Yes, please. validations: required: true + - type: textarea + id: additional + attributes: + label: Additional Context + description: + Add any other context here. Please keep the pre-filled text, which helps us manage issue prioritization. + value: |- + Tip: React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. + validations: + required: false - type: markdown attributes: value: |- diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml index 67039ae57441..2859c10d2dc0 100644 --- a/.github/ISSUE_TEMPLATE/feature.yml +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -23,6 +23,16 @@ body: Add a blender to Sentry. validations: required: true + - type: textarea + id: additional + attributes: + label: Additional Context + description: + Add any other context here. Please keep the pre-filled text, which helps us manage feature prioritization. + value: |- + Tip: React with 👍 to help prioritize this improvement. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. + validations: + required: false - type: markdown attributes: value: |- diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index b1c5f619de19..fbf476c369a4 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -81,9 +81,6 @@ jobs: - test-application: 'nextjs-app-dir' build-command: 'test:build-latest' label: 'nextjs-app-dir (latest)' - - test-application: 'nextjs-13' - build-command: 'test:build-canary' - label: 'nextjs-13 (canary)' - test-application: 'nextjs-13' build-command: 'test:build-latest' label: 'nextjs-13 (latest)' diff --git a/.size-limit.js b/.size-limit.js index 36bf0607e840..32d5d19e1495 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -135,7 +135,7 @@ module.exports = [ path: 'packages/vue/build/esm/index.js', import: createImport('init', 'browserTracingIntegration'), gzip: true, - limit: '42 KB', + limit: '43 KB', }, // Svelte SDK (ESM) { @@ -233,7 +233,7 @@ module.exports = [ import: createImport('init'), ignore: [...builtinModules, ...nodePrefixedBuiltinModules], gzip: true, - limit: '154 KB', + limit: '156 KB', }, { name: '@sentry/node - without tracing', @@ -263,7 +263,7 @@ module.exports = [ import: createImport('init'), ignore: [...builtinModules, ...nodePrefixedBuiltinModules], gzip: true, - limit: '107 KB', + limit: '111 KB', }, ]; diff --git a/CHANGELOG.md b/CHANGELOG.md index a76e7d2696d2..6ec252166664 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,134 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +# 10.12.0 + +### Important Changes + +- **ref: Add and Adjust error event `mechanism` values** + + This release includes a variety of changes aimed at setting the `mechanism` field on errors captured automatically by the Sentry SDKs. [The intention](https://github.com/getsentry/sentry-javascript/issues/17212) is to clearly mark which instrumentation captured an error. In addition, some instrumentations previously did not yet annotate the error as handled or unhandled which this series of PRs corrects as well. + +
+ Relevant PRs + +
+ + Released in `10.12.0`: + - ref(angular): Adjust ErrorHandler event mechanism ([#17608](https://github.com/getsentry/sentry-javascript/pull/17608)) + - ref(astro): Adjust `mechanism` on error events captured by astro middleware ([#17613](https://github.com/getsentry/sentry-javascript/pull/17613)) + - ref(aws-severless): Slightly adjust aws-serverless mechanism type ([#17614](https://github.com/getsentry/sentry-javascript/pull/17614)) + - ref(bun): Adjust `mechanism` of errors captured in Bun.serve ([#17616](https://github.com/getsentry/sentry-javascript/pull/17616)) + - ref(cloudflare): Adjust event `mechanisms` and durable object origin ([#17618](https://github.com/getsentry/sentry-javascript/pull/17618)) + - ref(core): Adjust `mechanism` in `captureConsoleIntegration` ([#17633](https://github.com/getsentry/sentry-javascript/pull/17633)) + - ref(core): Adjust MCP server error event `mechanism` ([#17622](https://github.com/getsentry/sentry-javascript/pull/17622)) + - ref(core): Simplify `linkedErrors` mechanism logic ([#17600](https://github.com/getsentry/sentry-javascript/pull/17600)) + - ref(deno): Adjust `mechanism` of errors caught by `globalHandlersIntegration` ([#17635](https://github.com/getsentry/sentry-javascript/pull/17635)) + - ref(nextjs): Set more specific event `mechanism`s ([#17543](https://github.com/getsentry/sentry-javascript/pull/17543)) + - ref(node): Adjust mechanism of express, hapi and fastify error handlers ([#17623](https://github.com/getsentry/sentry-javascript/pull/17623)) + - ref(node-core): Add `mechanism` to cron instrumentations ([#17544](https://github.com/getsentry/sentry-javascript/pull/17544)) + - ref(node-core): Add more specific `mechanism.type` to worker thread errors from `childProcessIntegration` ([#17578](https://github.com/getsentry/sentry-javascript/pull/17578)) + - ref(node-core): Adjust `mechanism` of `onUnhandledRejection` and `onUnhandledException` integrations ([#17636](https://github.com/getsentry/sentry-javascript/pull/17636)) + - ref(node): Add mechanism to errors captured via connect and koa integrations ([#17579](https://github.com/getsentry/sentry-javascript/pull/17579)) + - ref(nuxt): Add and adjust `mechanism.type` in error events ([#17599](https://github.com/getsentry/sentry-javascript/pull/17599)) + - ref(react): Add mechanism to `reactErrorHandler` and adjust mechanism in `ErrorBoundary` ([#17602](https://github.com/getsentry/sentry-javascript/pull/17602)) + - ref(remix): Adjust event mechanism of `captureRemixServerException` ([#17629](https://github.com/getsentry/sentry-javascript/pull/17629)) + - ref(replay-internal): Add mechanism to error caught by `replayIntegration` in debug mode ([#17606](https://github.com/getsentry/sentry-javascript/pull/17606)) + - ref(solid): Add `mechanism` to error captured by `withSentryErrorBoundary` ([#17607](https://github.com/getsentry/sentry-javascript/pull/17607)) + - ref(solidstart): Adjust event mechanism in withServerActionInstrumentation ([#17637](https://github.com/getsentry/sentry-javascript/pull/17637)) + - ref(sveltekit): Adjust `mechanism` of error events ([#17646](https://github.com/getsentry/sentry-javascript/pull/17646)) + - ref(vue): Adjust mechanism in Vue error handler ([#17647](https://github.com/getsentry/sentry-javascript/pull/17647)) + +
+ + Released in `10.11.0`: + - ref(browser): Add more specific `mechanism.type` to errors captured by `httpClientIntegration` ([#17254](https://github.com/getsentry/sentry-javascript/pull/17254)) + - ref(browser): Set more descriptive `mechanism.type` in `browserApiErrorsIntergation` ([#17251](https://github.com/getsentry/sentry-javascript/pull/17251)) + - ref(core): Add `mechanism.type` to `trpcMiddleware` errors ([#17287](https://github.com/getsentry/sentry-javascript/pull/17287)) + - ref(core): Add more specific event `mechanism`s and span origins to `openAiIntegration` ([#17288](https://github.com/getsentry/sentry-javascript/pull/17288)) + - ref(nestjs): Add `mechanism` to captured errors ([#17312](https://github.com/getsentry/sentry-javascript/pull/17312)) + +
+ +- **feat(node) Ensure `prismaIntegration` works with Prisma 5 ([#17595](https://github.com/getsentry/sentry-javascript/pull/17595))** + +We used to require to pass in the v5 version of `@prisma/instrumentation` into `prismaIntegration({ prismaInstrumentation: new PrismaInstrumentation() })`, if you wanted to get full instrumentation for Prisma v5. However, it turns out this does not work on v10 of the SDK anymore, because `@prisma/instrumentation@5` requires OTEL v1. + +With this release, we dropped the requirement to configure anything to get v5 support of Prisma. You do not need to configure anything in the integration anymore, and can remove the dependency on `@prisma/instrumentation@5` if you had it in your application. You only need to configure the `tracing` preview feature [according to our docs](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma/). + +- **feat(deps): Update OpenTelemetry dependencies ([#17558](https://github.com/getsentry/sentry-javascript/pull/17558))** + - @opentelemetry/core bumped to ^2.1.0 + - @opentelemetry/context-async-hooks bumped to ^2.1.0 + - @opentelemetry/resources bumped to ^2.1.0 + - @opentelemetry/sdk-trace-base bumped to ^2.1.0 + - @opentelemetry/semantic-conventions bumped to ^1.37.0 + - @opentelemetry/instrumentation bumped to ^0.204.0 + - @opentelemetry/instrumentation-http bumped to ^0.204.0 + - @opentelemetry/instrumentation-amqplib bumped to ^0.51.0 + - @opentelemetry/instrumentation-aws-sdk bumped to ^0.59.0 + - @opentelemetry/instrumentation-connect bumped to ^0.48.0 + - @opentelemetry/instrumentation-dataloader bumped to ^0.22.0 + - @opentelemetry/instrumentation-express bumped to ^0.53.0 + - @opentelemetry/instrumentation-fs bumped from to ^0.24.0 + - @opentelemetry/instrumentation-generic-pool bumped to ^0.48.0 + - @opentelemetry/instrumentation-graphql bumped to ^0.52.0 + - @opentelemetry/instrumentation-hapi bumped to ^0.51.0 + - @opentelemetry/instrumentation-ioredis bumped to ^0.52.0 + - @opentelemetry/instrumentation-kafkajs bumped to ^0.14.0 + - @opentelemetry/instrumentation-knex bumped to ^0.49.0 + - @opentelemetry/instrumentation-koa bumped to ^0.52.0 + - @opentelemetry/instrumentation-lru-memoizer bumped to ^0.49.0 + - @opentelemetry/instrumentation-mongodb bumped from to ^0.57.0 + - @opentelemetry/instrumentation-mongoose bumped from to ^0.51.0 + - @opentelemetry/instrumentation-mysql bumped to ^0.50.0 + - @opentelemetry/instrumentation-mysql2 bumped to ^0.51.0 + - @opentelemetry/instrumentation-nestjs-core bumped to ^0.50.0 + - @opentelemetry/instrumentation-pg bumped to ^0.57.0 + - @opentelemetry/instrumentation-redis bumped to ^0.53.0 + - @opentelemetry/instrumentation-undici bumped to ^0.15.0 + - @prisma/instrumentation bumped to 6.15.0 + +### Other Changes + +- feat(browser): Add timing and status atttributes to resource spans ([#17562](https://github.com/getsentry/sentry-javascript/pull/17562)) +- feat(cloudflare,vercel-edge): Add support for Anthropic AI instrumentation ([#17571](https://github.com/getsentry/sentry-javascript/pull/17571)) +- feat(core): Add Consola integration ([#17435](https://github.com/getsentry/sentry-javascript/pull/17435)) +- feat(deps): Update OpenTelemetry dependencies ([#17569](https://github.com/getsentry/sentry-javascript/pull/17569)) +- feat(core): Export `TracesSamplerSamplingContext` type ([#17523](https://github.com/getsentry/sentry-javascript/pull/17523)) +- feat(deno): Add OpenTelemetry support and vercelAI integration ([#17445](https://github.com/getsentry/sentry-javascript/pull/17445)) +- feat(node-core): Remove experimental note from winston api ([#17626](https://github.com/getsentry/sentry-javascript/pull/17626)) +- feat(node): Ensure `prismaIntegration` works with Prisma v5 ([#17595](https://github.com/getsentry/sentry-javascript/pull/17595)) +- feat(node): Tidy existing ESM loader hook ([#17566](https://github.com/getsentry/sentry-javascript/pull/17566)) +- feat(sveltekit): Align build time options with shared type ([#17413](https://github.com/getsentry/sentry-javascript/pull/17413)) +- fix(core): Fix error handling when sending envelopes ([#17662](https://github.com/getsentry/sentry-javascript/pull/17662)) +- fix(browser): Always start navigation as root span ([#17648](https://github.com/getsentry/sentry-javascript/pull/17648)) +- fix(browser): Ensure propagated `parentSpanId` stays consistent during trace in TwP mode ([#17526](https://github.com/getsentry/sentry-javascript/pull/17526)) +- fix(cloudflare): Initialize once per workflow run and preserve scope for `step.do` ([#17582](https://github.com/getsentry/sentry-javascript/pull/17582)) +- fix(nextjs): Add edge polyfills for nextjs-13 in dev mode ([#17488](https://github.com/getsentry/sentry-javascript/pull/17488)) +- fix(nitro): Support nested `_platform` properties in Nitro 2.11.7+ ([#17596](https://github.com/getsentry/sentry-javascript/pull/17596)) +- fix(node): Preserve synchronous return behavior for streamText and other methods for AI ([#17580](https://github.com/getsentry/sentry-javascript/pull/17580)) +- ref(node): Inline types imported from `shimmer` ([#17597](https://github.com/getsentry/sentry-javascript/pull/17597)) - ref(nuxt): Add and adjust `mechanism.type` in error events ([#17599](https://github.com/getsentry/sentry-javascript/pull/17599)) +- ref(browser): Improve `fetchTransport` error handling ([#17661](https://github.com/getsentry/sentry-javascript/pull/17661)) + +
+ Internal Changes + +- chore: Add changelog note about mechanism changes ([#17632](https://github.com/getsentry/sentry-javascript/pull/17632)) +- chore(aws): Update README.md ([#17601](https://github.com/getsentry/sentry-javascript/pull/17601)) +- chore(deps): bump hono from 4.7.10 to 4.9.7 in /dev-packages/e2e-tests/test-applications/cloudflare-hono ([#17630](https://github.com/getsentry/sentry-javascript/pull/17630)) +- chore(deps): bump next from 14.2.25 to 14.2.32 in /dev-packages/e2e-tests/test-applications/nextjs-app-dir ([#17627](https://github.com/getsentry/sentry-javascript/pull/17627)) +- chore(deps): bump next from 14.2.25 to 14.2.32 in /dev-packages/e2e-tests/test-applications/nextjs-pages-dir ([#17620](https://github.com/getsentry/sentry-javascript/pull/17620)) +- chore(deps): bump next from 14.2.29 to 14.2.32 in /dev-packages/e2e-tests/test-applications/nextjs-orpc ([#17494](https://github.com/getsentry/sentry-javascript/pull/17494)) +- chore(deps): bump next from 14.2.30 to 14.2.32 in /dev-packages/e2e-tests/test-applications/nextjs-14 ([#17628](https://github.com/getsentry/sentry-javascript/pull/17628)) +- chore(repo): Rename `.claude/settings.local.json` to `.claude/settings.json` ([#17591](https://github.com/getsentry/sentry-javascript/pull/17591)) +- docs(issue-template): Add note about prioritization ([#17590](https://github.com/getsentry/sentry-javascript/pull/17590)) +- ref(core): Streamline event processor handling ([#17634](https://github.com/getsentry/sentry-javascript/pull/17634)) +- test(angular): Bump TS version to 5.9.0 in Angular 20 e2e test ([#17605](https://github.com/getsentry/sentry-javascript/pull/17605)) +- test(nextjs): Remove Next 13 and pin Next 14 canary and latest tests ([#17577](https://github.com/getsentry/sentry-javascript/pull/17577)) +- test(react-router): Unflake `flushIfServerless` test ([#17610](https://github.com/getsentry/sentry-javascript/pull/17610)) + +
+ ## 10.11.0 ### Important Changes diff --git a/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts b/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts index fc8c1b378e7f..ff15c17832c6 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts @@ -37,7 +37,7 @@ sentryTest( expect(logEvent?.exception?.values![0]).toMatchObject({ mechanism: { handled: true, - type: 'console', + type: 'auto.core.capture_console', synthetic: true, }, value: 'console log', @@ -59,7 +59,7 @@ sentryTest( expect(warnEvent?.exception?.values![0]).toMatchObject({ mechanism: { handled: true, - type: 'console', + type: 'auto.core.capture_console', synthetic: true, }, value: 'console warn', @@ -81,7 +81,7 @@ sentryTest( expect(infoEvent?.exception?.values![0]).toMatchObject({ mechanism: { handled: true, - type: 'console', + type: 'auto.core.capture_console', synthetic: true, }, value: 'console info', @@ -103,7 +103,7 @@ sentryTest( expect(errorEvent?.exception?.values![0]).toMatchObject({ mechanism: { handled: true, - type: 'console', + type: 'auto.core.capture_console', synthetic: true, }, value: 'console error', @@ -125,7 +125,7 @@ sentryTest( expect(traceEvent?.exception?.values![0]).toMatchObject({ mechanism: { handled: true, - type: 'console', + type: 'auto.core.capture_console', synthetic: true, }, value: 'console trace', @@ -153,7 +153,7 @@ sentryTest( expect(errorWithErrorEvent?.exception?.values?.[0].value).toBe('console error with error object'); expect(errorWithErrorEvent?.exception?.values?.[0].mechanism).toEqual({ handled: true, - type: 'console', + type: 'auto.core.capture_console', }); expect(traceWithErrorEvent).toEqual( expect.objectContaining({ diff --git a/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts b/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts index 06d989cc4433..8e7e6aaa58e3 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts @@ -96,7 +96,7 @@ sentryTest('it captures console messages correctly', async ({ getLocalTestUrl, p expect(errorWithErrorEvent?.exception?.values?.[0].value).toBe('console error with error object'); expect(errorWithErrorEvent?.exception?.values?.[0].mechanism).toEqual({ handled: true, - type: 'console', + type: 'auto.core.capture_console', }); expect(traceWithErrorEvent).toEqual( expect.objectContaining({ diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/http-timings/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/http-timings/test.ts index f47552f5e9b6..633be5f570b5 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/http-timings/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/http-timings/test.ts @@ -3,7 +3,7 @@ import type { Event } from '@sentry/core'; import { sentryTest } from '../../../../utils/fixtures'; import { getMultipleSentryEnvelopeRequests, shouldSkipTracingTest } from '../../../../utils/helpers'; -sentryTest('should create fetch spans with http timing @firefox', async ({ browserName, getLocalTestUrl, page }) => { +sentryTest('creates fetch spans with http timing', async ({ browserName, getLocalTestUrl, page }) => { const supportedBrowsers = ['chromium', 'firefox']; if (shouldSkipTracingTest() || !supportedBrowsers.includes(browserName)) { @@ -40,6 +40,8 @@ sentryTest('should create fetch spans with http timing @firefox', async ({ brows trace_id: tracingEvent.contexts?.trace?.trace_id, data: expect.objectContaining({ 'http.request.redirect_start': expect.any(Number), + 'http.request.redirect_end': expect.any(Number), + 'http.request.worker_start': expect.any(Number), 'http.request.fetch_start': expect.any(Number), 'http.request.domain_lookup_start': expect.any(Number), 'http.request.domain_lookup_end': expect.any(Number), @@ -49,6 +51,7 @@ sentryTest('should create fetch spans with http timing @firefox', async ({ brows 'http.request.request_start': expect.any(Number), 'http.request.response_start': expect.any(Number), 'http.request.response_end': expect.any(Number), + 'http.request.time_to_first_byte': expect.any(Number), 'network.protocol.version': expect.any(String), }), }), diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/init.js new file mode 100644 index 000000000000..63ce47b4c91c --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/init.js @@ -0,0 +1,13 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + tracesSampleRate: 1, + integrations: [ + Sentry.browserTracingIntegration({ + _experiments: { enableInteractions: true }, + }), + ], +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/subject.js new file mode 100644 index 000000000000..f45d2c974586 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/subject.js @@ -0,0 +1,7 @@ +// Clicking the navigate button will push a new history state, triggering navigation +document.querySelector('[data-test-id=navigate-button]').addEventListener('click', () => { + const loc = window.location; + const url = loc.href.includes('#nav') ? loc.pathname : `${loc.pathname}#nav`; + + history.pushState({}, '', url); +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/template.html b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/template.html new file mode 100644 index 000000000000..789445ddfdd4 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/test.ts new file mode 100644 index 000000000000..4931aaa4b172 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/test.ts @@ -0,0 +1,39 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../../utils/fixtures'; +import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers'; + +sentryTest( + 'click-triggered navigation should produce a root navigation transaction', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + await waitForTransactionRequest(page); // "pageload" root span + + const interactionRequestPromise = waitForTransactionRequest( + page, + evt => evt.contexts?.trace?.op === 'ui.action.click', + ); + const navigationRequestPromise = waitForTransactionRequest(page, evt => evt.contexts?.trace?.op === 'navigation'); + + await page.locator('[data-test-id=navigate-button]').click(); + + const interactionEvent = envelopeRequestParser(await interactionRequestPromise); + const navigationEvent = envelopeRequestParser(await navigationRequestPromise); + + // Navigation is root span, not a child span on the interaction + expect(interactionEvent.contexts?.trace?.op).toBe('ui.action.click'); + expect(navigationEvent.contexts?.trace?.op).toBe('navigation'); + + expect(interactionEvent.contexts?.trace?.trace_id).not.toEqual(navigationEvent.contexts?.trace?.trace_id); + + // does not contain a child navigation span + const interactionSpans = interactionEvent.spans || []; + const hasNavigationChild = interactionSpans.some(span => span.op === 'navigation' || span.op === 'http.server'); + expect(hasNavigationChild).toBeFalsy(); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/linked-traces/consistent-sampling/meta-precedence/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/linked-traces/consistent-sampling/meta-precedence/test.ts index 1b55f5235088..ece2b1f85790 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/linked-traces/consistent-sampling/meta-precedence/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/linked-traces/consistent-sampling/meta-precedence/test.ts @@ -30,10 +30,13 @@ sentryTest.describe('When `consistentTraceSampling` is `true` and page contains const clientReportPromise = waitForClientReportRequest(page); await sentryTest.step('Initial pageload', async () => { + // negative sampling decision -> no pageload txn await page.goto(url); }); await sentryTest.step('Make fetch request', async () => { + // The fetch requests starts a new trace on purpose. So we only want the + // sampling decision and rand to be the same as from the meta tag but not the trace id or DSC const tracingHeadersPromise = waitForTracingHeadersOnUrl(page, 'http://sentry-test-external.io'); await page.locator('#btn2').click(); diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts b/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts index 38c7e61ff541..f748c339ce14 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts @@ -4,7 +4,7 @@ import { type Event, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORI import { sentryTest } from '../../../../utils/fixtures'; import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; -sentryTest('should add resource spans to pageload transaction', async ({ getLocalTestUrl, page, browserName }) => { +sentryTest('adds resource spans to pageload transaction', async ({ getLocalTestUrl, page, browserName }) => { if (shouldSkipTracingTest()) { sentryTest.skip(); } @@ -74,6 +74,19 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca 'http.decoded_response_content_length': expect.any(Number), 'http.response_content_length': expect.any(Number), 'http.response_transfer_size': expect.any(Number), + 'http.request.connect_start': expect.any(Number), + 'http.request.connection_end': expect.any(Number), + 'http.request.domain_lookup_end': expect.any(Number), + 'http.request.domain_lookup_start': expect.any(Number), + 'http.request.fetch_start': expect.any(Number), + 'http.request.redirect_end': expect.any(Number), + 'http.request.redirect_start': expect.any(Number), + 'http.request.request_start': expect.any(Number), + 'http.request.secure_connection_start': expect.any(Number), + 'http.request.worker_start': expect.any(Number), + 'http.request.response_end': expect.any(Number), + 'http.request.response_start': expect.any(Number), + 'http.request.time_to_first_byte': expect.any(Number), 'network.protocol.name': '', 'network.protocol.version': 'unknown', [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.img', @@ -82,6 +95,7 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca 'url.same_origin': false, 'url.scheme': 'https', ...(!isWebkitRun && { + 'http.response.status_code': expect.any(Number), 'resource.render_blocking_status': 'non-blocking', 'http.response_delivery_type': '', }), @@ -96,11 +110,30 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca trace_id: traceId, }); + // range check: TTFB must be >0 (at least in this case) and it's reasonable to + // assume <10 seconds. This also tests that we're reporting TTFB in seconds. + const imgSpanTtfb = imgSpan?.data['http.request.time_to_first_byte']; + expect(imgSpanTtfb).toBeGreaterThan(0); + expect(imgSpanTtfb).toBeLessThan(10); + expect(linkSpan).toEqual({ data: { 'http.decoded_response_content_length': expect.any(Number), 'http.response_content_length': expect.any(Number), 'http.response_transfer_size': expect.any(Number), + 'http.request.connect_start': expect.any(Number), + 'http.request.connection_end': expect.any(Number), + 'http.request.domain_lookup_end': expect.any(Number), + 'http.request.domain_lookup_start': expect.any(Number), + 'http.request.fetch_start': expect.any(Number), + 'http.request.redirect_end': expect.any(Number), + 'http.request.redirect_start': expect.any(Number), + 'http.request.request_start': expect.any(Number), + 'http.request.secure_connection_start': expect.any(Number), + 'http.request.worker_start': expect.any(Number), + 'http.request.response_end': expect.any(Number), + 'http.request.response_start': expect.any(Number), + 'http.request.time_to_first_byte': expect.any(Number), 'network.protocol.name': '', 'network.protocol.version': 'unknown', [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.link', @@ -109,6 +142,7 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca 'url.same_origin': false, 'url.scheme': 'https', ...(!isWebkitRun && { + 'http.response.status_code': expect.any(Number), 'resource.render_blocking_status': 'non-blocking', 'http.response_delivery_type': '', }), @@ -128,6 +162,19 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca 'http.decoded_response_content_length': expect.any(Number), 'http.response_content_length': expect.any(Number), 'http.response_transfer_size': expect.any(Number), + 'http.request.connection_end': expect.any(Number), + 'http.request.connect_start': expect.any(Number), + 'http.request.domain_lookup_end': expect.any(Number), + 'http.request.domain_lookup_start': expect.any(Number), + 'http.request.fetch_start': expect.any(Number), + 'http.request.redirect_end': expect.any(Number), + 'http.request.redirect_start': expect.any(Number), + 'http.request.request_start': expect.any(Number), + 'http.request.secure_connection_start': expect.any(Number), + 'http.request.worker_start': expect.any(Number), + 'http.request.response_end': expect.any(Number), + 'http.request.response_start': expect.any(Number), + 'http.request.time_to_first_byte': expect.any(Number), 'network.protocol.name': '', 'network.protocol.version': 'unknown', 'sentry.op': 'resource.script', @@ -136,6 +183,7 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca 'url.same_origin': false, 'url.scheme': 'https', ...(!isWebkitRun && { + 'http.response.status_code': expect.any(Number), 'resource.render_blocking_status': 'non-blocking', 'http.response_delivery_type': '', }), diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/subject.js b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/subject.js index e9a1ca98b5b0..60acaa1ebdf8 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/subject.js +++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/subject.js @@ -1 +1,2 @@ -fetch('http://sentry-test-site.example/0').then(); +fetch('http://sentry-test-site.example/0'); +fetch('http://sentry-test-site.example/1'); diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/test.ts b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/test.ts index 22cc7ba98eb8..718cca0c8701 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-tracing-without-performance-propagateTraceparent/test.ts @@ -12,21 +12,36 @@ sentryTest( const url = await getLocalTestUrl({ testDir: __dirname }); - const [, request] = await Promise.all([page.goto(url), page.waitForRequest('http://sentry-test-site.example/0')]); + const [, request0, request1] = await Promise.all([ + page.goto(url), + page.waitForRequest('http://sentry-test-site.example/0'), + page.waitForRequest('http://sentry-test-site.example/1'), + ]); - const requestHeaders = request.headers(); + const requestHeaders0 = request0.headers(); - const traceparentData = extractTraceparentData(requestHeaders['sentry-trace']); + const traceparentData = extractTraceparentData(requestHeaders0['sentry-trace']); expect(traceparentData).toMatchObject({ traceId: expect.stringMatching(/^([a-f0-9]{32})$/), parentSpanId: expect.stringMatching(/^([a-f0-9]{16})$/), parentSampled: undefined, }); - expect(requestHeaders).toMatchObject({ + expect(requestHeaders0).toMatchObject({ 'sentry-trace': `${traceparentData?.traceId}-${traceparentData?.parentSpanId}`, baggage: expect.stringContaining(`sentry-trace_id=${traceparentData?.traceId}`), traceparent: `00-${traceparentData?.traceId}-${traceparentData?.parentSpanId}-00`, }); + + const requestHeaders1 = request1.headers(); + expect(requestHeaders1).toMatchObject({ + 'sentry-trace': `${traceparentData?.traceId}-${traceparentData?.parentSpanId}`, + baggage: expect.stringContaining(`sentry-trace_id=${traceparentData?.traceId}`), + traceparent: `00-${traceparentData?.traceId}-${traceparentData?.parentSpanId}-00`, + }); + + expect(requestHeaders1['sentry-trace']).toBe(requestHeaders0['sentry-trace']); + expect(requestHeaders1['baggage']).toBe(requestHeaders0['baggage']); + expect(requestHeaders1['traceparent']).toBe(requestHeaders0['traceparent']); }, ); diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/init.js b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/init.js new file mode 100644 index 000000000000..b5b7d0354f77 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + // in browser TwP means not setting tracesSampleRate but adding browserTracingIntegration, + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [Sentry.browserTracingIntegration()], + tracePropagationTargets: ['http://sentry-test-site.example'], + propagateTraceparent: true, +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/template.html b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/template.html new file mode 100644 index 000000000000..755df10f3a1a --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/template.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/test.ts b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/test.ts new file mode 100644 index 000000000000..d2106b892b7b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/tracing-without-performance-propagateTraceparent/test.ts @@ -0,0 +1,130 @@ +import { expect } from '@playwright/test'; +import { extractTraceparentData } from '@sentry/core'; +import { sentryTest } from '../../../../utils/fixtures'; +import { shouldSkipTracingTest } from '../../../../utils/helpers'; + +const META_TAG_TRACE_ID = '12345678901234567890123456789012'; +const META_TAG_PARENT_SPAN_ID = '1234567890123456'; +const META_TAG_BAGGAGE = + 'sentry-trace_id=12345678901234567890123456789012,sentry-public_key=public,sentry-release=1.0.0,sentry-environment=prod,sentry-sample_rand=0.42'; + +sentryTest( + 'outgoing fetch requests have new traceId after navigation (with propagateTraceparent)', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('http://sentry-test-site.example/**', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({}), + }); + }); + + await page.goto(url); + + const requestPromise = page.waitForRequest('http://sentry-test-site.example/*'); + await page.locator('#fetchBtn').click(); + const request = await requestPromise; + const headers = request.headers(); + + const sentryTraceParentData = extractTraceparentData(headers['sentry-trace']); + // sampling decision is deferred because TwP means we didn't sample any span + expect(sentryTraceParentData).toEqual({ + traceId: META_TAG_TRACE_ID, + parentSpanId: expect.stringMatching(/^[0-9a-f]{16}$/), + parentSampled: undefined, + }); + expect(headers['baggage']).toBe(META_TAG_BAGGAGE); + // but traceparent propagates a negative sampling decision because it has no concept of deferred sampling + expect(headers['traceparent']).toBe( + `00-${sentryTraceParentData?.traceId}-${sentryTraceParentData?.parentSpanId}-00`, + ); + + const requestPromise2 = page.waitForRequest('http://sentry-test-site.example/*'); + await page.locator('#fetchBtn').click(); + const request2 = await requestPromise2; + const headers2 = request2.headers(); + + const sentryTraceParentData2 = extractTraceparentData(headers2['sentry-trace']); + expect(sentryTraceParentData2).toEqual(sentryTraceParentData); + + await page.goto(`${url}#navigation`); + + const requestPromise3 = page.waitForRequest('http://sentry-test-site.example/*'); + await page.locator('#fetchBtn').click(); + const request3 = await requestPromise3; + const headers3 = request3.headers(); + + const sentryTraceParentData3 = extractTraceparentData(headers3['sentry-trace']); + // sampling decision is deferred because TwP means we didn't sample any span + expect(sentryTraceParentData3).toEqual({ + traceId: expect.not.stringContaining(sentryTraceParentData!.traceId!), + parentSpanId: expect.not.stringContaining(sentryTraceParentData!.parentSpanId!), + parentSampled: undefined, + }); + + expect(headers3['baggage']).toMatch( + /sentry-environment=production,sentry-public_key=public,sentry-trace_id=[0-9a-f]{32}/, + ); + expect(headers3['baggage']).not.toContain(`sentry-trace_id=${META_TAG_TRACE_ID}`); + // but traceparent propagates a negative sampling decision because it has no concept of deferred sampling + expect(headers3['traceparent']).toBe( + `00-${sentryTraceParentData3!.traceId}-${sentryTraceParentData3!.parentSpanId}-00`, + ); + + const requestPromise4 = page.waitForRequest('http://sentry-test-site.example/*'); + await page.locator('#fetchBtn').click(); + const request4 = await requestPromise4; + const headers4 = request4.headers(); + + const sentryTraceParentData4 = extractTraceparentData(headers4['sentry-trace']); + expect(sentryTraceParentData4).toEqual(sentryTraceParentData3); + }, +); + +sentryTest('outgoing XHR requests have new traceId after navigation', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('http://sentry-test-site.example/**', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({}), + }); + }); + + await page.goto(url); + + const requestPromise = page.waitForRequest('http://sentry-test-site.example/*'); + await page.locator('#xhrBtn').click(); + const request = await requestPromise; + const headers = request.headers(); + + // sampling decision is deferred because TwP means we didn't sample any span + expect(headers['sentry-trace']).toMatch(new RegExp(`^${META_TAG_TRACE_ID}-[0-9a-f]{16}$`)); + expect(headers['baggage']).toBe(META_TAG_BAGGAGE); + + await page.goto(`${url}#navigation`); + + const requestPromise2 = page.waitForRequest('http://sentry-test-site.example/*'); + await page.locator('#xhrBtn').click(); + const request2 = await requestPromise2; + const headers2 = request2.headers(); + + // sampling decision is deferred because TwP means we didn't sample any span + expect(headers2['sentry-trace']).toMatch(/^[0-9a-f]{32}-[0-9a-f]{16}$/); + expect(headers2['baggage']).not.toBe(`${META_TAG_TRACE_ID}-${META_TAG_PARENT_SPAN_ID}`); + expect(headers2['baggage']).toMatch( + /sentry-environment=production,sentry-public_key=public,sentry-trace_id=[0-9a-f]{32}/, + ); + expect(headers2['baggage']).not.toContain(`sentry-trace_id=${META_TAG_TRACE_ID}`); +}); diff --git a/dev-packages/cloudflare-integration-tests/suites/basic/test.ts b/dev-packages/cloudflare-integration-tests/suites/basic/test.ts index 1bd7b4bac094..b785e6e37fd1 100644 --- a/dev-packages/cloudflare-integration-tests/suites/basic/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/basic/test.ts @@ -15,7 +15,7 @@ it('Basic error in fetch handler', async () => { stacktrace: { frames: expect.any(Array), }, - mechanism: { type: 'cloudflare', handled: false }, + mechanism: { type: 'auto.http.cloudflare', handled: false }, }, ], }, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts new file mode 100644 index 000000000000..08df5e24b05b --- /dev/null +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts @@ -0,0 +1,32 @@ +import * as Sentry from '@sentry/cloudflare'; +import type { AnthropicAiClient } from '@sentry/core'; +import { MockAnthropic } from './mocks'; + +interface Env { + SENTRY_DSN: string; +} + +const mockClient = new MockAnthropic({ + apiKey: 'mock-api-key', +}); + +const client: AnthropicAiClient = Sentry.instrumentAnthropicAiClient(mockClient); + +export default Sentry.withSentry( + (env: Env) => ({ + dsn: env.SENTRY_DSN, + tracesSampleRate: 1.0, + }), + { + async fetch(_request, _env, _ctx) { + const response = await client.messages?.create({ + model: 'claude-3-haiku-20240307', + messages: [{ role: 'user', content: 'What is the capital of France?' }], + temperature: 0.7, + max_tokens: 100, + }); + + return new Response(JSON.stringify(response)); + }, + }, +); diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/mocks.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/mocks.ts new file mode 100644 index 000000000000..cff87ca84cbc --- /dev/null +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/mocks.ts @@ -0,0 +1,68 @@ +import type { AnthropicAiClient, AnthropicAiResponse } from '@sentry/core'; + +export class MockAnthropic implements AnthropicAiClient { + public messages: { + create: (...args: unknown[]) => Promise; + countTokens: (...args: unknown[]) => Promise; + }; + public models: { + list: (...args: unknown[]) => Promise; + get: (...args: unknown[]) => Promise; + }; + public completions: { + create: (...args: unknown[]) => Promise; + }; + public apiKey: string; + + public constructor(config: { apiKey: string }) { + this.apiKey = config.apiKey; + + // Main focus: messages.create functionality + this.messages = { + create: async (...args: unknown[]) => { + const params = args[0] as { model: string; stream?: boolean }; + // Simulate processing time + await new Promise(resolve => setTimeout(resolve, 10)); + + if (params.model === 'error-model') { + const error = new Error('Model not found'); + (error as unknown as { status: number }).status = 404; + (error as unknown as { headers: Record }).headers = { 'x-request-id': 'mock-request-123' }; + throw error; + } + + return { + id: 'msg_mock123', + type: 'message', + role: 'assistant', + model: params.model, + content: [ + { + type: 'text', + text: 'Hello from Anthropic mock!', + }, + ], + stop_reason: 'end_turn', + stop_sequence: null, + usage: { + input_tokens: 10, + output_tokens: 15, + cache_creation_input_tokens: 0, + cache_read_input_tokens: 0, + }, + }; + }, + countTokens: async (..._args: unknown[]) => ({ id: 'mock', type: 'model', model: 'mock', input_tokens: 0 }), + }; + + // Minimal implementations for required interface compliance + this.models = { + list: async (..._args: unknown[]) => ({ id: 'mock', type: 'model', model: 'mock' }), + get: async (..._args: unknown[]) => ({ id: 'mock', type: 'model', model: 'mock' }), + }; + + this.completions = { + create: async (..._args: unknown[]) => ({ id: 'mock', type: 'completion', model: 'mock' }), + }; + } +} diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts new file mode 100644 index 000000000000..13966caaf460 --- /dev/null +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts @@ -0,0 +1,41 @@ +import { expect, it } from 'vitest'; +import { createRunner } from '../../../runner'; + +// These tests are not exhaustive because the instrumentation is +// already tested in the node integration tests and we merely +// want to test that the instrumentation does not break in our +// cloudflare SDK. + +it('traces a basic message creation request', async () => { + const runner = createRunner(__dirname) + .ignore('event') + .expect(envelope => { + const transactionEvent = envelope[1]?.[0]?.[1] as any; + + expect(transactionEvent.transaction).toBe('GET /'); + expect(transactionEvent.spans).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'gen_ai.operation.name': 'messages', + 'sentry.op': 'gen_ai.messages', + 'sentry.origin': 'auto.ai.anthropic', + 'gen_ai.system': 'anthropic', + 'gen_ai.request.model': 'claude-3-haiku-20240307', + 'gen_ai.request.temperature': 0.7, + 'gen_ai.response.model': 'claude-3-haiku-20240307', + 'gen_ai.response.id': 'msg_mock123', + 'gen_ai.usage.input_tokens': 10, + 'gen_ai.usage.output_tokens': 15, + }), + description: 'messages claude-3-haiku-20240307', + op: 'gen_ai.messages', + origin: 'auto.ai.anthropic', + }), + ]), + ); + }) + .start(); + await runner.makeRequest('get', '/'); + await runner.completed(); +}); diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/wrangler.jsonc b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/wrangler.jsonc new file mode 100644 index 000000000000..d6be01281f0c --- /dev/null +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/wrangler.jsonc @@ -0,0 +1,6 @@ +{ + "name": "worker-name", + "compatibility_date": "2025-06-17", + "main": "index.ts", + "compatibility_flags": ["nodejs_compat"], +} diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts index cfb6841004a9..a9daae21480f 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts @@ -12,9 +12,9 @@ it('traces a durable object method', async () => { op: 'rpc', data: expect.objectContaining({ 'sentry.op': 'rpc', - 'sentry.origin': 'auto.faas.cloudflare_durableobjects', + 'sentry.origin': 'auto.faas.cloudflare.durable_object', }), - origin: 'auto.faas.cloudflare_durableobjects', + origin: 'auto.faas.cloudflare.durable_object', }), }), transaction: 'sayHello', diff --git a/dev-packages/e2e-tests/test-applications/angular-17/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/angular-17/tests/errors.test.ts index e6bd5ad180a9..391086555708 100644 --- a/dev-packages/e2e-tests/test-applications/angular-17/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/angular-17/tests/errors.test.ts @@ -19,7 +19,7 @@ test('sends an error', async ({ page }) => { type: 'Error', value: 'Error thrown from Angular 17 E2E test app', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, @@ -54,7 +54,7 @@ test('assigns the correct transaction value after a navigation', async ({ page } type: 'Error', value: 'Error thrown from user page', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, diff --git a/dev-packages/e2e-tests/test-applications/angular-18/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/angular-18/tests/errors.test.ts index 36d23bd077a5..98d4ce9d1169 100644 --- a/dev-packages/e2e-tests/test-applications/angular-18/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/angular-18/tests/errors.test.ts @@ -19,7 +19,7 @@ test('sends an error', async ({ page }) => { type: 'Error', value: 'Error thrown from Angular 18 E2E test app', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, @@ -54,7 +54,7 @@ test('assigns the correct transaction value after a navigation', async ({ page } type: 'Error', value: 'Error thrown from user page', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, diff --git a/dev-packages/e2e-tests/test-applications/angular-19/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/angular-19/tests/errors.test.ts index c6e8bc43abed..7fa706c00504 100644 --- a/dev-packages/e2e-tests/test-applications/angular-19/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/angular-19/tests/errors.test.ts @@ -19,7 +19,7 @@ test('sends an error', async ({ page }) => { type: 'Error', value: 'Error thrown from Angular 18 E2E test app', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, @@ -54,7 +54,7 @@ test('assigns the correct transaction value after a navigation', async ({ page } type: 'Error', value: 'Error thrown from user page', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, diff --git a/dev-packages/e2e-tests/test-applications/angular-20/package.json b/dev-packages/e2e-tests/test-applications/angular-20/package.json index 73f22787cd85..5488a1fef56c 100644 --- a/dev-packages/e2e-tests/test-applications/angular-20/package.json +++ b/dev-packages/e2e-tests/test-applications/angular-20/package.json @@ -44,9 +44,17 @@ "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", - "typescript": "~5.8.3" + "typescript": "~5.9.0" }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "optionalVariants": [ + { + "build-command": "pnpm test:build-canary", + "label": "angular (canary)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/angular-20/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/angular-20/tests/errors.test.ts index 98ae26e195cc..a6e12b6a79c4 100644 --- a/dev-packages/e2e-tests/test-applications/angular-20/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/angular-20/tests/errors.test.ts @@ -19,7 +19,7 @@ test('sends an error', async ({ page }) => { type: 'Error', value: 'Error thrown from Angular 20 E2E test app', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, @@ -54,7 +54,7 @@ test('assigns the correct transaction value after a navigation', async ({ page } type: 'Error', value: 'Error thrown from user page', mechanism: { - type: 'angular', + type: 'auto.function.angular.error_handler', handled: false, }, }, diff --git a/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.server.test.ts index 3faacdb30090..f3b0e9a189de 100644 --- a/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.server.test.ts @@ -47,11 +47,8 @@ test.describe('server-side errors', () => { values: [ { mechanism: { - data: { - function: 'astroMiddleware', - }, handled: false, - type: 'astro', + type: 'auto.middleware.astro', }, stacktrace: expect.any(Object), type: 'TypeError', @@ -136,11 +133,8 @@ test.describe('server-side errors', () => { values: [ { mechanism: { - data: { - function: 'astroMiddleware', - }, handled: false, - type: 'astro', + type: 'auto.middleware.astro', }, stacktrace: expect.any(Object), type: 'Error', diff --git a/dev-packages/e2e-tests/test-applications/astro-5/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/astro-5/tests/errors.server.test.ts index d6a9514da1d1..77d515ad2a24 100644 --- a/dev-packages/e2e-tests/test-applications/astro-5/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/astro-5/tests/errors.server.test.ts @@ -47,11 +47,8 @@ test.describe('server-side errors', () => { values: [ { mechanism: { - data: { - function: 'astroMiddleware', - }, handled: false, - type: 'astro', + type: 'auto.middleware.astro', }, stacktrace: expect.any(Object), type: 'TypeError', @@ -136,11 +133,8 @@ test.describe('server-side errors', () => { values: [ { mechanism: { - data: { - function: 'astroMiddleware', - }, handled: false, - type: 'astro', + type: 'auto.middleware.astro', }, stacktrace: expect.any(Object), type: 'Error', diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts index 0439aba5f53c..6ec76124140d 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts @@ -160,7 +160,7 @@ test.describe('Lambda layer', () => { type: 'Error', value: 'test', mechanism: { - type: 'auto.function.aws-serverless.otel', + type: 'auto.function.aws_serverless.otel', handled: false, }, }), @@ -188,7 +188,7 @@ test.describe('Lambda layer', () => { type: 'Error', value: 'test esm', mechanism: { - type: 'auto.function.aws-serverless.otel', + type: 'auto.function.aws_serverless.otel', handled: false, }, }), diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json b/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json index 4329f837613a..a8fe024e9405 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json +++ b/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@sentry/cloudflare": "latest || *", - "hono": "4.7.10" + "hono": "4.9.7" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.8.31", diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts b/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts index c69c955fafd8..73abbd951b90 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts @@ -15,6 +15,7 @@ const config = getPlaywrightConfig( { // This comes with the risk of tests leaking into each other but the tests run quite slow so we should parallelize workers: '100%', + retries: 0, }, ); diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts index 31cc02b8c5e8..ad63c1a0d307 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts @@ -10,7 +10,7 @@ test('Index page', async ({ baseURL }) => { test("worker's withSentry", async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.http.cloudflare'; }); const response = await fetch(`${baseURL}/throwException`); expect(response.status).toBe(500); @@ -20,25 +20,27 @@ test("worker's withSentry", async ({ baseURL }) => { test('RPC method which throws an exception to be logged to sentry', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const response = await fetch(`${baseURL}/rpc/throwException`); expect(response.status).toBe(500); const event = await eventWaiter; expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry.'); }); + test("Request processed by DurableObject's fetch is recorded", async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const response = await fetch(`${baseURL}/pass-to-object/throwException`); expect(response.status).toBe(500); const event = await eventWaiter; expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry.'); }); + test('Websocket.webSocketMessage', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return !!event.exception?.values?.[0]; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); @@ -49,11 +51,12 @@ test('Websocket.webSocketMessage', async ({ baseURL }) => { const event = await eventWaiter; socket.close(); expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry: webSocketMessage'); + expect(event.exception?.values?.[0]?.mechanism?.type).toBe('auto.faas.cloudflare.durable_object'); }); test('Websocket.webSocketClose', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return !!event.exception?.values?.[0]; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); @@ -64,4 +67,5 @@ test('Websocket.webSocketClose', async ({ baseURL }) => { }); const event = await eventWaiter; expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry: webSocketClose'); + expect(event.exception?.values?.[0]?.mechanism?.type).toBe('auto.faas.cloudflare.durable_object'); }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/middleware.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/middleware.ts new file mode 100644 index 000000000000..b2117419c10f --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/middleware.ts @@ -0,0 +1,6 @@ +import { NextResponse } from 'next/server'; + +export function middleware() { + // Basic middleware to ensure that the build works with edge runtime + return NextResponse.next(); +} diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/package.json b/dev-packages/e2e-tests/test-applications/nextjs-13/package.json index 32430917ddc0..adb8005d1a9d 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/package.json @@ -8,8 +8,7 @@ "test:prod": "TEST_ENV=production playwright test", "test:dev": "TEST_ENV=development playwright test", "test:build": "pnpm install && pnpm build", - "test:build-canary": "pnpm install && pnpm add next@canary && pnpm add react@beta && pnpm add react-dom@beta && pnpm build", - "test:build-latest": "pnpm install && pnpm add next@latest && pnpm build", + "test:build-latest": "pnpm install && pnpm add next@next-13 && pnpm build", "test:assert": "pnpm test:prod && pnpm test:dev" }, "dependencies": { @@ -31,10 +30,6 @@ }, "sentryTest": { "optionalVariants": [ - { - "build-command": "pnpm test:build-canary", - "label": "nextjs-13 (canary)" - }, { "build-command": "pnpm test:build-latest", "label": "nextjs-13 (latest)" diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/client/click-error.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/client/click-error.test.ts index a9fbcdb69a45..481e7264c62d 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/client/click-error.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/client/click-error.test.ts @@ -13,8 +13,18 @@ test('should send error for faulty click handlers', async ({ page }) => { expect(errorEvent).toBeDefined(); - const frames = errorEvent?.exception?.values?.[0]?.stacktrace?.frames; + const exception = errorEvent?.exception?.values?.[0]; + + expect(exception?.mechanism).toEqual({ + type: 'auto.browser.browserapierrors.addEventListener', + handled: false, + data: { + handler: expect.any(String), // the handler name varies in CI and locally + target: 'EventTarget', + }, + }); + const frames = exception?.stacktrace?.frames; await test.step('error should have a non-url-encoded top frame in route with parameter', () => { if (process.env.TEST_ENV === 'development') { // In dev mode we want to check local source mapping diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/cjs-api-endpoints.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/cjs-api-endpoints.test.ts index 42b2e3727bd6..28cc91e9b879 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/cjs-api-endpoints.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/cjs-api-endpoints.test.ts @@ -11,7 +11,8 @@ test('should create a transaction for a CJS pages router API endpoint', async ({ const transactionPromise = waitForTransaction('nextjs-13', async transactionEvent => { return ( transactionEvent.transaction === 'GET /api/cjs-api-endpoint' && - transactionEvent.contexts?.trace?.op === 'http.server' + transactionEvent.contexts?.trace?.op === 'http.server' && + transactionEvent.transaction_info?.source === 'route' ); }); @@ -73,7 +74,8 @@ test('should not mess up require statements in CJS API endpoints', async ({ requ const transactionPromise = waitForTransaction('nextjs-13', async transactionEvent => { return ( transactionEvent.transaction === 'GET /api/cjs-api-endpoint-with-require' && - transactionEvent.contexts?.trace?.op === 'http.server' + transactionEvent.contexts?.trace?.op === 'http.server' && + transactionEvent.transaction_info?.source === 'route' ); }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/getServerSideProps.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/getServerSideProps.test.ts index 60f9842ca20e..3338d8e28595 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/getServerSideProps.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/getServerSideProps.test.ts @@ -23,7 +23,7 @@ test('Should report an error event for errors thrown in getServerSideProps', asy exception: { values: [ { - mechanism: { handled: false, type: 'generic' }, + mechanism: { handled: false, type: 'auto.function.nextjs.wrapped' }, type: 'Error', value: 'getServerSideProps Error', stacktrace: { @@ -110,7 +110,7 @@ test('Should report an error event for errors thrown in getServerSideProps in pa exception: { values: [ { - mechanism: { handled: false, type: 'generic' }, + mechanism: { handled: false, type: 'auto.function.nextjs.wrapped' }, type: 'Error', value: 'custom page extension error', stacktrace: { diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/pages-router-api-endpoints.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/pages-router-api-endpoints.test.ts index 36592b56fb94..9f5ff5db8434 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/pages-router-api-endpoints.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/pages-router-api-endpoints.test.ts @@ -30,7 +30,7 @@ test('Should report an error event for errors thrown in pages router api routes' function: 'withSentry', }, handled: false, - type: 'instrument', + type: 'auto.http.nextjs.api_handler', }, stacktrace: { frames: expect.arrayContaining([]) }, type: 'Error', diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/server-component-error.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/server-component-error.test.ts index 937d7c8da6c0..c485c02716a3 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/server-component-error.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/server-component-error.test.ts @@ -20,7 +20,7 @@ test('Should capture an error thrown in a server component', async ({ page }) => exception: { values: [ { - mechanism: { handled: false, type: 'generic' }, + mechanism: { handled: false, type: 'auto.function.nextjs.server_component' }, type: 'Error', value: 'RSC error', }, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/wrapApiHandlerWithSentry.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/wrapApiHandlerWithSentry.test.ts index 3bcc1bbbea92..798ea3409089 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/wrapApiHandlerWithSentry.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/tests/server/wrapApiHandlerWithSentry.test.ts @@ -22,7 +22,11 @@ const cases = [ cases.forEach(({ name, url, transactionName }) => { test(`Should capture transactions for routes with various shapes (${name})`, async ({ request }) => { const transactionEventPromise = waitForTransaction('nextjs-13', transactionEvent => { - return transactionEvent.transaction === transactionName && transactionEvent.contexts?.trace?.op === 'http.server'; + return ( + transactionEvent.transaction === transactionName && + transactionEvent.contexts?.trace?.op === 'http.server' && + transactionEvent.transaction_info?.source === 'route' + ); }); request.get(url).catch(() => { diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/package.json b/dev-packages/e2e-tests/test-applications/nextjs-14/package.json index 822d321b2028..fc6b31591bfa 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/package.json @@ -8,8 +8,8 @@ "test:prod": "TEST_ENV=production playwright test", "test:dev": "TEST_ENV=development playwright test", "test:build": "pnpm install && pnpm build", - "test:build-canary": "pnpm install && pnpm add next@canary && pnpm add react@beta && pnpm add react-dom@beta && pnpm build", - "test:build-latest": "pnpm install && pnpm add next@latest && pnpm build", + "test:build-canary": "pnpm install && pnpm add next@~14.3.0-canary.0 && pnpm add react@beta && pnpm add react-dom@beta && pnpm build", + "test:build-latest": "pnpm install && pnpm add next@next-14 && pnpm build", "test:assert": "pnpm test:prod && pnpm test:dev" }, "dependencies": { @@ -17,7 +17,7 @@ "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", - "next": "14.2.30", + "next": "14.2.32", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "~5.0.0" diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/tests/nested-rsc-error.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-15/tests/nested-rsc-error.test.ts index 863e5de111a2..68d03a00d601 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15/tests/nested-rsc-error.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/tests/nested-rsc-error.test.ts @@ -41,4 +41,9 @@ test('Should capture errors from nested server components when `Sentry.captureRe router_path: '/nested-rsc-error/[param]', request_path: '/nested-rsc-error/123', }); + + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + handled: false, + type: 'auto.function.nextjs.on_request_error', + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/tests/streaming-rsc-error.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-15/tests/streaming-rsc-error.test.ts index 0a20e97be74a..6133d0fa29b1 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15/tests/streaming-rsc-error.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/tests/streaming-rsc-error.test.ts @@ -41,4 +41,9 @@ test('Should capture errors for crashing streaming promises in server components router_path: '/streaming-rsc-error/[param]', request_path: '/streaming-rsc-error/123', }); + + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + handled: false, + type: 'auto.function.nextjs.on_request_error', + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json index e37e4a0c8ca3..2ac1965e180a 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json @@ -20,7 +20,7 @@ "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", - "next": "14.2.25", + "next": "14.2.32", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "~5.0.0" diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/client-errors.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/client-errors.test.ts index 091c8fc1e46c..580368f4b9a1 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/client-errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/client-errors.test.ts @@ -35,4 +35,15 @@ test('Sends a client-side exception to Sentry', async ({ page }) => { trace_id: expect.stringMatching(/[a-f0-9]{32}/), span_id: expect.stringMatching(/[a-f0-9]{16}/), }); + + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + handled: false, + type: nextjsMajor >= 15 ? 'auto.browser.global_handlers.onerror' : 'auto.browser.browserapierrors.addEventListener', + ...(nextjsMajor < 15 && { + data: { + handler: expect.any(String), // the handler name varies in CI and locally + target: 'EventTarget', + }, + }), + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts index 934cfa2e472d..a19fe3402951 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts @@ -19,6 +19,11 @@ test('Should record exceptions for faulty edge server components', async ({ page expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined(); expect(errorEvent.transaction).toBe(`Page Server Component (/edge-server-components/error)`); + + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + handled: false, + type: 'auto.function.nextjs.server_component', + }); }); test('Should record transaction for edge server components', async ({ page }) => { diff --git a/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json b/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json index f8c9e58f06d1..0a15260db4e8 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json @@ -19,7 +19,7 @@ "@sentry/nextjs": "latest || *", "@orpc/server": "latest", "@orpc/client": "latest", - "next": "14.2.29", + "next": "14.2.32", "react": "18.3.1", "react-dom": "18.3.1", "server-only": "^0.0.1" diff --git a/dev-packages/e2e-tests/test-applications/nextjs-orpc/tests/orpc-error.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-orpc/tests/orpc-error.test.ts index 8a9f371972c0..a503533b6f00 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-orpc/tests/orpc-error.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-orpc/tests/orpc-error.test.ts @@ -19,4 +19,10 @@ test('should capture orpc error', async ({ page }) => { }), ], }); + + // orpc errors are captured manually by the orpc middleware (user-land) + expect(orpcError.exception?.values?.[0]?.mechanism).toEqual({ + handled: true, + type: 'generic', + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json index 233ceb802536..0ef1d9bbcac7 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json @@ -20,7 +20,7 @@ "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", - "next": "14.2.25", + "next": "14.2.32", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "~5.0.0" diff --git a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/pages-ssr-errors.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/pages-ssr-errors.test.ts index c3925f52ba48..e5539244570f 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/pages-ssr-errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/pages-ssr-errors.test.ts @@ -43,4 +43,9 @@ test('Will capture error for SSR rendering error with a connected trace (Functio // TODO(lforst): Reuse SSR request span isolation scope to fix the following two assertions // expect(ssrTransaction.tags?.['my-isolated-tag']).toBe(true); // expect(ssrTransaction.tags?.['my-global-scope-isolated-tag']).not.toBeDefined(); + + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + handled: false, + type: 'auto.function.nextjs.page_function', + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json b/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json index af4d92497ad9..f6e3613b379d 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json @@ -20,7 +20,7 @@ "@trpc/client": "~11.3.0", "@trpc/react-query": "~11.3.0", "@trpc/server": "~11.3.0", - "next": "14.2.29", + "next": "14.2.32", "react": "18.3.1", "react-dom": "18.3.1", "server-only": "^0.0.1", diff --git a/dev-packages/e2e-tests/test-applications/nextjs-t3/tests/trpc-error.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-t3/tests/trpc-error.test.ts index d3e175e0558b..2a7af1b14d52 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-t3/tests/trpc-error.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-t3/tests/trpc-error.test.ts @@ -16,6 +16,14 @@ test('should capture error with trpc context', async ({ page }) => { expect(trpcError.contexts?.trpc?.procedure_type).toEqual('mutation'); expect(trpcError.contexts?.trpc?.procedure_path).toBe('post.throwError'); expect(trpcError.contexts?.trpc?.input).toEqual({ name: 'I love dogs' }); + + expect(trpcError.exception?.values?.[0]?.mechanism).toEqual({ + handled: false, + type: 'auto.rpc.trpc.middleware', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); }); test('should create transaction with trpc input for error', async ({ page }) => { diff --git a/dev-packages/e2e-tests/test-applications/nextjs-turbo/tests/app-router/rsc-error.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-turbo/tests/app-router/rsc-error.test.ts index 604faae7ea59..d9c94de2d2be 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-turbo/tests/app-router/rsc-error.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-turbo/tests/app-router/rsc-error.test.ts @@ -11,4 +11,8 @@ test('Should capture errors from server components', async ({ page }) => { const errorEvent = await errorEventPromise; expect(errorEvent).toBeDefined(); + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + handled: false, + type: 'auto.function.nextjs.on_request_error', + }); }); diff --git a/dev-packages/e2e-tests/test-applications/node-connect/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-connect/tests/errors.test.ts index 2aa569915eb4..c8d7b3123482 100644 --- a/dev-packages/e2e-tests/test-applications/node-connect/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-connect/tests/errors.test.ts @@ -11,7 +11,13 @@ test('Sends correct error event', async ({ baseURL }) => { const errorEvent = await errorEventPromise; expect(errorEvent.exception?.values).toHaveLength(1); - expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an exception'); + const exception = errorEvent.exception?.values?.[0]; + expect(exception?.value).toBe('This is an exception'); + + expect(exception?.mechanism).toEqual({ + type: 'auto.middleware.connect', + handled: false, + }); expect(errorEvent.request).toEqual({ method: 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json index 3b6c974f44b2..e29a40c2887e 100644 --- a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json +++ b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json @@ -12,13 +12,13 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/instrumentation-http": "^0.203.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-trace-node": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-http": "^0.204.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@sentry/node-core": "latest || *", "@sentry/opentelemetry": "latest || *", "@types/express": "4.17.17", diff --git a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json index 9da336fdf8d1..34b050f350c1 100644 --- a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json +++ b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json @@ -12,15 +12,15 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/instrumentation-http": "^0.203.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-trace-node": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0", - "@opentelemetry/sdk-node": "^0.203.0", - "@opentelemetry/exporter-trace-otlp-http": "^0.203.0", + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-http": "^0.204.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", + "@opentelemetry/sdk-node": "^0.204.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.204.0", "@sentry/node-core": "latest || *", "@sentry/opentelemetry": "latest || *", "@types/express": "4.17.17", diff --git a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json index cab490640de9..2252750e423e 100644 --- a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json +++ b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json @@ -14,13 +14,13 @@ "@sentry/node-core": "latest || *", "@sentry/opentelemetry": "latest || *", "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/instrumentation-http": "^0.203.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-trace-node": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-http": "^0.204.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@types/express": "^4.17.21", "@types/node": "^18.19.1", "express": "^4.21.2", diff --git a/dev-packages/e2e-tests/test-applications/node-express/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-express/tests/errors.test.ts index 00f9f413906f..3a3c821a927d 100644 --- a/dev-packages/e2e-tests/test-applications/node-express/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express/tests/errors.test.ts @@ -11,7 +11,12 @@ test('Sends correct error event', async ({ baseURL }) => { const errorEvent = await errorEventPromise; expect(errorEvent.exception?.values).toHaveLength(1); - expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an exception with id 123'); + const exception = errorEvent.exception?.values?.[0]; + expect(exception?.value).toBe('This is an exception with id 123'); + expect(exception?.mechanism).toEqual({ + type: 'auto.middleware.express', + handled: false, + }); expect(errorEvent.request).toMatchObject({ method: 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/errors.test.ts index cf1428b7a34a..a25f990748ea 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/errors.test.ts @@ -11,7 +11,12 @@ test('Sends correct error event', async ({ baseURL }) => { const errorEvent = await errorEventPromise; expect(errorEvent.exception?.values).toHaveLength(1); - expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an exception with id 123'); + const exception = errorEvent.exception?.values?.[0]; + expect(exception?.value).toBe('This is an exception with id 123'); + expect(exception?.mechanism).toEqual({ + type: 'auto.function.fastify', + handled: false, + }); expect(errorEvent.request).toEqual({ method: 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-hapi/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-hapi/tests/errors.test.ts index 4f2fba52aa95..39edc8bcde0e 100644 --- a/dev-packages/e2e-tests/test-applications/node-hapi/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-hapi/tests/errors.test.ts @@ -22,7 +22,12 @@ test('Sends thrown error to Sentry', async ({ baseURL }) => { }); expect(errorEvent.exception?.values).toHaveLength(1); - expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an error'); + const exception = errorEvent.exception?.values?.[0]; + expect(exception?.value).toBe('This is an error'); + expect(exception?.mechanism).toEqual({ + type: 'auto.function.hapi', + handled: false, + }); expect(errorEvent.request).toEqual({ method: 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-koa/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-koa/tests/errors.test.ts index cadf29fbda90..dd0dfa4a084d 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-koa/tests/errors.test.ts @@ -11,7 +11,13 @@ test('Sends correct error event', async ({ baseURL }) => { const errorEvent = await errorEventPromise; expect(errorEvent.exception?.values).toHaveLength(1); - expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an exception with id 123'); + const exception = errorEvent.exception?.values?.[0]; + + expect(exception?.value).toBe('This is an exception with id 123'); + expect(exception?.mechanism).toEqual({ + type: 'auto.middleware.koa', + handled: false, + }); expect(errorEvent.request).toEqual({ method: 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-koa/yarn.lock b/dev-packages/e2e-tests/test-applications/node-koa/yarn.lock deleted file mode 100644 index 201176ad5cdf..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-koa/yarn.lock +++ /dev/null @@ -1,312 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@koa/router@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@koa/router/-/router-12.0.1.tgz#1a66f92a630c02832cf5bbf0db06c9e53e423468" - integrity sha512-ribfPYfHb+Uw3b27Eiw6NPqjhIhTpVFzEWLwyc/1Xp+DCdwRRyIlAUODX+9bPARF6aQtUu1+/PHzdNvRzcs/+Q== - dependencies: - debug "^4.3.4" - http-errors "^2.0.0" - koa-compose "^4.1.0" - methods "^1.1.2" - path-to-regexp "^6.2.1" - -accepts@^1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -cache-content-type@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" - integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA== - dependencies: - mime-types "^2.1.18" - ylru "^1.2.0" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - -content-disposition@~0.5.2: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -cookies@~0.9.0: - version "0.9.1" - resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.9.1.tgz#3ffed6f60bb4fb5f146feeedba50acc418af67e3" - integrity sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw== - dependencies: - depd "~2.0.0" - keygrip "~1.1.0" - -debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -deep-equal@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - integrity sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw== - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - -depd@2.0.0, depd@^2.0.0, depd@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - -destroy@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -encodeurl@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -escape-html@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -fresh@~0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -http-assert@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" - integrity sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w== - dependencies: - deep-equal "~1.0.1" - http-errors "~1.8.0" - -http-errors@^1.6.3, http-errors@~1.8.0: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - -http-errors@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -inherits@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - -keygrip@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" - integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ== - dependencies: - tsscmp "1.0.6" - -koa-compose@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" - integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== - -koa-convert@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-2.0.0.tgz#86a0c44d81d40551bae22fee6709904573eea4f5" - integrity sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA== - dependencies: - co "^4.6.0" - koa-compose "^4.1.0" - -koa@^2.15.2: - version "2.15.2" - resolved "https://registry.yarnpkg.com/koa/-/koa-2.15.2.tgz#1e4afe1482d01bd24ed6e30f630a960411f5ebf2" - integrity sha512-MXTeZH3M6AJ8ukW2QZ8wqO3Dcdfh2WRRmjCBkEP+NhKNCiqlO5RDqHmSnsyNrbRJrdjyvIGSJho4vQiWgQJSVA== - dependencies: - accepts "^1.3.5" - cache-content-type "^1.0.0" - content-disposition "~0.5.2" - content-type "^1.0.4" - cookies "~0.9.0" - debug "^4.3.2" - delegates "^1.0.0" - depd "^2.0.0" - destroy "^1.0.4" - encodeurl "^1.0.2" - escape-html "^1.0.3" - fresh "~0.5.2" - http-assert "^1.3.0" - http-errors "^1.6.3" - is-generator-function "^1.0.7" - koa-compose "^4.1.0" - koa-convert "^2.0.0" - on-finished "^2.3.0" - only "~0.0.2" - parseurl "^1.3.2" - statuses "^1.5.0" - type-is "^1.6.16" - vary "^1.1.2" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -methods@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.18, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -on-finished@^2.3.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -only@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" - integrity sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ== - -parseurl@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -path-to-regexp@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" - integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== - -safe-buffer@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -"statuses@>= 1.5.0 < 2", statuses@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -tsscmp@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" - integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== - -type-is@^1.6.16: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -vary@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -ylru@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.4.0.tgz#0cf0aa57e9c24f8a2cbde0cc1ca2c9592ac4e0f6" - integrity sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA== diff --git a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json index 92770106970e..9ba6f629e78c 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/sdk-trace-node": "^2.0.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", "@sentry/node": "latest || *", "@sentry/opentelemetry": "latest || *", "@types/express": "4.17.17", diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json index d26dc2db5843..7296f72218cd 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json @@ -11,8 +11,8 @@ "test:assert": "pnpm test" }, "dependencies": { - "@opentelemetry/sdk-node": "0.203.0", - "@opentelemetry/exporter-trace-otlp-http": "0.203.0", + "@opentelemetry/sdk-node": "0.204.0", + "@opentelemetry/exporter-trace-otlp-http": "0.204.0", "@sentry/node": "latest || *", "@types/express": "4.17.17", "@types/node": "^18.19.1", diff --git a/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json b/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json index 11b5509fb637..f13daab2ef6c 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json @@ -11,11 +11,11 @@ "test:assert": "pnpm test" }, "dependencies": { - "@opentelemetry/sdk-trace-node": "2.0.0", - "@opentelemetry/exporter-trace-otlp-http": "0.203.0", + "@opentelemetry/sdk-trace-node": "2.1.0", + "@opentelemetry/exporter-trace-otlp-http": "0.204.0", "@opentelemetry/instrumentation-undici": "0.13.2", - "@opentelemetry/instrumentation-http": "0.203.0", - "@opentelemetry/instrumentation": "0.203.0", + "@opentelemetry/instrumentation-http": "0.204.0", + "@opentelemetry/instrumentation": "0.204.0", "@sentry/node": "latest || *", "@types/express": "4.17.17", "@types/node": "^18.19.1", diff --git a/dev-packages/e2e-tests/test-applications/node-otel/package.json b/dev-packages/e2e-tests/test-applications/node-otel/package.json index 1a554ece3bf7..31cf99c32c91 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel/package.json @@ -11,8 +11,8 @@ "test:assert": "pnpm test" }, "dependencies": { - "@opentelemetry/sdk-node": "0.203.0", - "@opentelemetry/exporter-trace-otlp-http": "0.203.0", + "@opentelemetry/sdk-node": "0.204.0", + "@opentelemetry/exporter-trace-otlp-http": "0.204.0", "@sentry/node": "latest || *", "@types/express": "4.17.17", "@types/node": "^18.19.1", diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts index f4ca86413598..123b6f9a332a 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts @@ -21,6 +21,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -49,6 +50,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Param Route Button', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -82,6 +84,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -96,6 +99,7 @@ test.describe('client-side errors', async () => { value: 'Another Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts index b18da9ba0a3b..53d89e5b937f 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts @@ -14,10 +14,23 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/server-error'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); test('captures api fetch error (fetched on click) with parametrized route', async ({ page }) => { @@ -32,9 +45,22 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/param-error/1234'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Param Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Param Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Param Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts index 0de0c3dd498a..e9ef67ef75b6 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts @@ -21,6 +21,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3-min E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -49,6 +50,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Param Route Button', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -82,6 +84,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3-min E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -96,6 +99,7 @@ test.describe('client-side errors', async () => { value: 'Another Error thrown from Nuxt-3-min E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts index 40904b51b993..8b182fec69c7 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts @@ -14,10 +14,23 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/server-error'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Server error'); + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); test('captures api fetch error (fetched on click) with parametrized route', async ({ page }) => { @@ -32,9 +45,22 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/param-error/1234'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Param Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Param Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Param Server error'); + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.client.test.ts index 445a62e54b2a..ff99eb1b192f 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.client.test.ts @@ -21,6 +21,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -49,6 +50,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Param Route Button', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -82,6 +84,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -96,6 +99,7 @@ test.describe('client-side errors', async () => { value: 'Another Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts index 551a33ee1fc1..d7aafde49d55 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts @@ -19,10 +19,23 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/server-error'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); expect(error.tags?.['my-isolated-tag']).toBe(true); expect(error.tags?.['my-global-scope-isolated-tag']).not.toBeDefined(); @@ -63,9 +76,22 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/param-error/1234'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Param Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Param Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Param Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts index d94f649f78d1..11e4a5a367d4 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts @@ -21,6 +21,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -62,6 +63,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown in Error Boundary', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -90,6 +92,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Param Route Button', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -123,6 +126,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -137,6 +141,7 @@ test.describe('client-side errors', async () => { value: 'Another Error thrown from Nuxt-3 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts index b62654b60c47..338ee6e3f78a 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts @@ -14,10 +14,23 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/server-error'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'chained', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); test('captures api fetch error (fetched on click) with parametrized route', async ({ page }) => { @@ -32,9 +45,22 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/param-error/1234'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 3 Param Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 3 Param Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'chained', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 3 Param Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts index 6694ae851df1..2aed77dbfed6 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts @@ -21,6 +21,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-4 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -62,6 +63,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown in Error Boundary', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -90,6 +92,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Param Route Button', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -123,6 +126,7 @@ test.describe('client-side errors', async () => { value: 'Error thrown from Nuxt-4 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], @@ -137,6 +141,7 @@ test.describe('client-side errors', async () => { value: 'Another Error thrown from Nuxt-4 E2E test app', mechanism: { handled: false, + type: 'auto.function.nuxt.vue-error', }, }, ], diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts index 1d593cb09caf..62933f29dd48 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts @@ -14,10 +14,23 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/server-error'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 4 Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 4 Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 4 Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); test('captures api fetch error (fetched on click) with parametrized route', async ({ page }) => { @@ -32,9 +45,22 @@ test.describe('server-side errors', async () => { expect(error.transaction).toEqual('GET /api/param-error/1234'); - const exception = error.exception.values[0]; - expect(exception.type).toEqual('Error'); - expect(exception.value).toEqual('Nuxt 4 Param Server error'); - expect(exception.mechanism.handled).toBe(false); + const exception0 = error.exception.values[0]; + const exception1 = error.exception.values[1]; + + expect(exception0.type).toEqual('Error'); + expect(exception0.value).toEqual('Nuxt 4 Param Server error'); + expect(exception0.mechanism).toEqual({ + handled: false, + type: 'auto.function.nuxt.nitro', + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(exception1.type).toEqual('Error'); + expect(exception1.value).toEqual('Nuxt 4 Param Server error'); + // TODO: This isn't correct but requires adjustment in the core SDK + expect(exception1.mechanism).toEqual({ handled: true, type: 'generic', exception_id: 0 }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/react-19/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/react-19/tests/errors.test.ts index 46e19b11a2ac..496c47e417d2 100644 --- a/dev-packages/e2e-tests/test-applications/react-19/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/react-19/tests/errors.test.ts @@ -19,6 +19,20 @@ test('Catches errors caught by error boundary', async ({ page }) => { expect(errorEvent.exception?.values).toHaveLength(2); expect(errorEvent.exception?.values?.[0]?.value).toBe('caught error'); + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + type: 'auto.function.react.error_handler', + handled: true, // true because a callback was provided + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(errorEvent.exception?.values?.[1]?.value).toBe('caught error'); + expect(errorEvent.exception?.values?.[1]?.mechanism).toEqual({ + type: 'generic', + handled: true, // true because a callback was provided + exception_id: 0, + }); }); test('Catches errors uncaught by error boundary', async ({ page }) => { @@ -39,4 +53,18 @@ test('Catches errors uncaught by error boundary', async ({ page }) => { expect(errorEvent.exception?.values).toHaveLength(2); expect(errorEvent.exception?.values?.[0]?.value).toBe('uncaught error'); + expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ + type: 'auto.function.react.error_handler', + handled: true, // true because a callback was provided + exception_id: 1, + parent_id: 0, + source: 'cause', + }); + + expect(errorEvent.exception?.values?.[1]?.value).toBe('uncaught error'); + expect(errorEvent.exception?.values?.[1]?.mechanism).toEqual({ + type: 'generic', + handled: true, // true because a callback was provided + exception_id: 0, + }); }); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-spa-node-20-18/yarn.lock b/dev-packages/e2e-tests/test-applications/react-router-7-framework-spa-node-20-18/yarn.lock deleted file mode 100644 index 43736103138f..000000000000 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-spa-node-20-18/yarn.lock +++ /dev/null @@ -1,2311 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" - integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== - dependencies: - "@babel/helper-validator-identifier" "^7.27.1" - js-tokens "^4.0.0" - picocolors "^1.1.1" - -"@babel/compat-data@^7.27.2": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz#4183f9e642fd84e74e3eea7ffa93a412e3b102c9" - integrity sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ== - -"@babel/core@^7.21.8", "@babel/core@^7.23.7": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz#89de51e86bd12246003e3524704c49541b16c3e6" - integrity sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.27.1" - "@babel/helper-compilation-targets" "^7.27.1" - "@babel/helper-module-transforms" "^7.27.1" - "@babel/helpers" "^7.27.1" - "@babel/parser" "^7.27.1" - "@babel/template" "^7.27.1" - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.21.5", "@babel/generator@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz#862d4fad858f7208edd487c28b58144036b76230" - integrity sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w== - dependencies: - "@babel/parser" "^7.27.1" - "@babel/types" "^7.27.1" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/helper-annotate-as-pure@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz#4345d81a9a46a6486e24d069469f13e60445c05d" - integrity sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow== - dependencies: - "@babel/types" "^7.27.1" - -"@babel/helper-compilation-targets@^7.27.1": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" - integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== - dependencies: - "@babel/compat-data" "^7.27.2" - "@babel/helper-validator-option" "^7.27.1" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz#5bee4262a6ea5ddc852d0806199eb17ca3de9281" - integrity sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A== - dependencies: - "@babel/helper-annotate-as-pure" "^7.27.1" - "@babel/helper-member-expression-to-functions" "^7.27.1" - "@babel/helper-optimise-call-expression" "^7.27.1" - "@babel/helper-replace-supers" "^7.27.1" - "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" - "@babel/traverse" "^7.27.1" - semver "^6.3.1" - -"@babel/helper-member-expression-to-functions@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44" - integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA== - dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/helper-module-imports@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" - integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== - dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/helper-module-transforms@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz#e1663b8b71d2de948da5c4fb2a20ca4f3ec27a6f" - integrity sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g== - dependencies: - "@babel/helper-module-imports" "^7.27.1" - "@babel/helper-validator-identifier" "^7.27.1" - "@babel/traverse" "^7.27.1" - -"@babel/helper-optimise-call-expression@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" - integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== - dependencies: - "@babel/types" "^7.27.1" - -"@babel/helper-plugin-utils@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" - integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== - -"@babel/helper-replace-supers@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0" - integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.27.1" - "@babel/helper-optimise-call-expression" "^7.27.1" - "@babel/traverse" "^7.27.1" - -"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" - integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== - dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/helper-string-parser@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" - integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== - -"@babel/helper-validator-identifier@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" - integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== - -"@babel/helper-validator-option@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" - integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== - -"@babel/helpers@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz#ffc27013038607cdba3288e692c3611c06a18aa4" - integrity sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ== - dependencies: - "@babel/template" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/parser@^7.21.8", "@babel/parser@^7.23.6", "@babel/parser@^7.27.1", "@babel/parser@^7.27.2": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz#577518bedb17a2ce4212afd052e01f7df0941127" - integrity sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw== - dependencies: - "@babel/types" "^7.27.1" - -"@babel/plugin-syntax-decorators@^7.22.10": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz#ee7dd9590aeebc05f9d4c8c0560007b05979a63d" - integrity sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-syntax-jsx@^7.21.4", "@babel/plugin-syntax-jsx@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" - integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-syntax-typescript@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" - integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-transform-modules-commonjs@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz#8e44ed37c2787ecc23bdc367f49977476614e832" - integrity sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw== - dependencies: - "@babel/helper-module-transforms" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-transform-typescript@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz#d3bb65598bece03f773111e88cc4e8e5070f1140" - integrity sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.27.1" - "@babel/helper-create-class-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" - "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" - "@babel/plugin-syntax-typescript" "^7.27.1" - -"@babel/preset-typescript@^7.21.5": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz#190742a6428d282306648a55b0529b561484f912" - integrity sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - "@babel/helper-validator-option" "^7.27.1" - "@babel/plugin-syntax-jsx" "^7.27.1" - "@babel/plugin-transform-modules-commonjs" "^7.27.1" - "@babel/plugin-transform-typescript" "^7.27.1" - -"@babel/template@^7.27.1": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" - integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== - dependencies: - "@babel/code-frame" "^7.27.1" - "@babel/parser" "^7.27.2" - "@babel/types" "^7.27.1" - -"@babel/traverse@^7.23.2", "@babel/traverse@^7.23.7", "@babel/traverse@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz#4db772902b133bbddd1c4f7a7ee47761c1b9f291" - integrity sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg== - dependencies: - "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.27.1" - "@babel/parser" "^7.27.1" - "@babel/template" "^7.27.1" - "@babel/types" "^7.27.1" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.22.5", "@babel/types@^7.23.6", "@babel/types@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz#9defc53c16fc899e46941fc6901a9eea1c9d8560" - integrity sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q== - dependencies: - "@babel/helper-string-parser" "^7.27.1" - "@babel/helper-validator-identifier" "^7.27.1" - -"@emnapi/core@^1.4.3": - version "1.4.3" - resolved "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz#9ac52d2d5aea958f67e52c40a065f51de59b77d6" - integrity sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g== - dependencies: - "@emnapi/wasi-threads" "1.0.2" - tslib "^2.4.0" - -"@emnapi/runtime@^1.4.3": - version "1.4.3" - resolved "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz#c0564665c80dc81c448adac23f9dfbed6c838f7d" - integrity sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ== - dependencies: - tslib "^2.4.0" - -"@emnapi/wasi-threads@1.0.2", "@emnapi/wasi-threads@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz#977f44f844eac7d6c138a415a123818c655f874c" - integrity sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA== - dependencies: - tslib "^2.4.0" - -"@esbuild/aix-ppc64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz#830d6476cbbca0c005136af07303646b419f1162" - integrity sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q== - -"@esbuild/android-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz#d11d4fc299224e729e2190cacadbcc00e7a9fd67" - integrity sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A== - -"@esbuild/android-arm@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz#5660bd25080553dd2a28438f2a401a29959bd9b1" - integrity sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ== - -"@esbuild/android-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz#18ddde705bf984e8cd9efec54e199ac18bc7bee1" - integrity sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ== - -"@esbuild/darwin-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz#b0b7fb55db8fc6f5de5a0207ae986eb9c4766e67" - integrity sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g== - -"@esbuild/darwin-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz#e6813fdeba0bba356cb350a4b80543fbe66bf26f" - integrity sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A== - -"@esbuild/freebsd-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz#dc11a73d3ccdc308567b908b43c6698e850759be" - integrity sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ== - -"@esbuild/freebsd-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz#91da08db8bd1bff5f31924c57a81dab26e93a143" - integrity sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ== - -"@esbuild/linux-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz#efc15e45c945a082708f9a9f73bfa8d4db49728a" - integrity sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ== - -"@esbuild/linux-arm@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz#9b93c3e54ac49a2ede6f906e705d5d906f6db9e8" - integrity sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ== - -"@esbuild/linux-ia32@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz#be8ef2c3e1d99fca2d25c416b297d00360623596" - integrity sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ== - -"@esbuild/linux-loong64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz#b0840a2707c3fc02eec288d3f9defa3827cd7a87" - integrity sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA== - -"@esbuild/linux-mips64el@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz#2a198e5a458c9f0e75881a4e63d26ba0cf9df39f" - integrity sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg== - -"@esbuild/linux-ppc64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz#64f4ae0b923d7dd72fb860b9b22edb42007cf8f5" - integrity sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag== - -"@esbuild/linux-riscv64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz#fb2844b11fdddd39e29d291c7cf80f99b0d5158d" - integrity sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA== - -"@esbuild/linux-s390x@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz#1466876e0aa3560c7673e63fdebc8278707bc750" - integrity sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g== - -"@esbuild/linux-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz#c10fde899455db7cba5f11b3bccfa0e41bf4d0cd" - integrity sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA== - -"@esbuild/netbsd-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz#02e483fbcbe3f18f0b02612a941b77be76c111a4" - integrity sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ== - -"@esbuild/netbsd-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz#ec401fb0b1ed0ac01d978564c5fc8634ed1dc2ed" - integrity sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw== - -"@esbuild/openbsd-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz#f272c2f41cfea1d91b93d487a51b5c5ca7a8c8c4" - integrity sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A== - -"@esbuild/openbsd-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz#2e25950bc10fa9db1e5c868e3d50c44f7c150fd7" - integrity sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw== - -"@esbuild/sunos-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz#cd596fa65a67b3b7adc5ecd52d9f5733832e1abd" - integrity sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q== - -"@esbuild/win32-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz#b4dbcb57b21eeaf8331e424c3999b89d8951dc88" - integrity sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ== - -"@esbuild/win32-ia32@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz#410842e5d66d4ece1757634e297a87635eb82f7a" - integrity sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg== - -"@esbuild/win32-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz#0b17ec8a70b2385827d52314c1253160a0b9bacc" - integrity sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ== - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - -"@isaacs/fs-minipass@^4.0.0": - version "4.0.1" - resolved "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" - integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== - dependencies: - minipass "^7.0.4" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.8" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" - integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@mjackson/node-fetch-server@^0.2.0": - version "0.2.0" - resolved "https://registry.npmjs.org/@mjackson/node-fetch-server/-/node-fetch-server-0.2.0.tgz#577c0c25d8aae9f69a97738b7b0d03d1471cdc49" - integrity sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng== - -"@napi-rs/wasm-runtime@^0.2.9": - version "0.2.10" - resolved "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz#f3b7109419c6670000b2401e0c778b98afc25f84" - integrity sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ== - dependencies: - "@emnapi/core" "^1.4.3" - "@emnapi/runtime" "^1.4.3" - "@tybys/wasm-util" "^0.9.0" - -"@npmcli/git@^4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz#ab0ad3fd82bc4d8c1351b6c62f0fa56e8fe6afa6" - integrity sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ== - dependencies: - "@npmcli/promise-spawn" "^6.0.0" - lru-cache "^7.4.4" - npm-pick-manifest "^8.0.0" - proc-log "^3.0.0" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^3.0.0" - -"@npmcli/package-json@^4.0.1": - version "4.0.1" - resolved "https://registry.npmjs.org/@npmcli/package-json/-/package-json-4.0.1.tgz#1a07bf0e086b640500791f6bf245ff43cc27fa37" - integrity sha512-lRCEGdHZomFsURroh522YvA/2cVb9oPIJrjHanCJZkiasz1BzcnLr3tBJhlV7S86MBJBuAQ33is2D60YitZL2Q== - dependencies: - "@npmcli/git" "^4.1.0" - glob "^10.2.2" - hosted-git-info "^6.1.1" - json-parse-even-better-errors "^3.0.0" - normalize-package-data "^5.0.0" - proc-log "^3.0.0" - semver "^7.5.3" - -"@npmcli/promise-spawn@^6.0.0": - version "6.0.2" - resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz#c8bc4fa2bd0f01cb979d8798ba038f314cfa70f2" - integrity sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg== - dependencies: - which "^3.0.0" - -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - -"@react-router/dev@^7.5.3": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/dev/-/dev-7.6.0.tgz#9974e608be0398ee22282405992d0a62a3cc26ba" - integrity sha512-XSxEslex0ddJPxNNgdU1Eqmc9lsY/lhcLNCcRLAtlrOPyOz3Y8kIPpAf5T/U2AG3HGXFVBa9f8aQ7wXU3wTJSw== - dependencies: - "@babel/core" "^7.21.8" - "@babel/generator" "^7.21.5" - "@babel/parser" "^7.21.8" - "@babel/plugin-syntax-decorators" "^7.22.10" - "@babel/plugin-syntax-jsx" "^7.21.4" - "@babel/preset-typescript" "^7.21.5" - "@babel/traverse" "^7.23.2" - "@babel/types" "^7.22.5" - "@npmcli/package-json" "^4.0.1" - "@react-router/node" "7.6.0" - arg "^5.0.1" - babel-dead-code-elimination "^1.0.6" - chokidar "^4.0.0" - dedent "^1.5.3" - es-module-lexer "^1.3.1" - exit-hook "2.2.1" - fs-extra "^10.0.0" - jsesc "3.0.2" - lodash "^4.17.21" - pathe "^1.1.2" - picocolors "^1.1.1" - prettier "^2.7.1" - react-refresh "^0.14.0" - semver "^7.3.7" - set-cookie-parser "^2.6.0" - valibot "^0.41.0" - vite-node "3.0.0-beta.2" - -"@react-router/express@7.6.0": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/express/-/express-7.6.0.tgz#1c9686e9154aab7b9411d4d1bcf4cc14145ebc94" - integrity sha512-nxSTCcTsVx94bXOI9JjG7Cg338myi8EdQWTOjA97v2ApX35wZm/ZDYos5MbrvZiMi0aB4KgAD62o4byNqF9Z1A== - dependencies: - "@react-router/node" "7.6.0" - -"@react-router/node@7.6.0", "@react-router/node@^7.5.3": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/node/-/node-7.6.0.tgz#18c31c502f8004f2b8a1ca6ceebd0ac1e9307e12" - integrity sha512-agjDPUzisLdGJ7Q2lx/Z3OfdS2t1k6qv/nTvA45iahGsQJCMDvMqVoIi7iIULKQJwrn4HWjM9jqEp75+WsMOXg== - dependencies: - "@mjackson/node-fetch-server" "^0.2.0" - source-map-support "^0.5.21" - stream-slice "^0.1.2" - undici "^6.19.2" - -"@react-router/serve@^7.5.3": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/serve/-/serve-7.6.0.tgz#ab0ff21cf80b3dbbb746fad1110d9d2903b24439" - integrity sha512-2O8ALEYgJfimvEdNRqMpnZb2N+DQ5UK/SKo9Xo3mTkt3no0rNTcNxzmhzD2tm92Q/HI7kHmMY1nBegNB2i1abA== - dependencies: - "@react-router/express" "7.6.0" - "@react-router/node" "7.6.0" - compression "^1.7.4" - express "^4.19.2" - get-port "5.1.1" - morgan "^1.10.0" - source-map-support "^0.5.21" - -"@rollup/rollup-android-arm-eabi@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz#9145b38faf3fbfe3ec557130110e772f797335aa" - integrity sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A== - -"@rollup/rollup-android-arm64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz#d73d641c59e9d7827e5ce0af9dfbc168b95cce0f" - integrity sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ== - -"@rollup/rollup-darwin-arm64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz#45d9d71d941117c98e7a5e77f60f0bc682d27e82" - integrity sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw== - -"@rollup/rollup-darwin-x64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz#8d72fb5f81714cb43e90f263fb1674520cce3f2a" - integrity sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ== - -"@rollup/rollup-freebsd-arm64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz#a52b58852c9cec9255e382a2f335b08bc8c6111d" - integrity sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg== - -"@rollup/rollup-freebsd-x64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz#104511dc64612789ddda41d164ab07cdac84a6c1" - integrity sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg== - -"@rollup/rollup-linux-arm-gnueabihf@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz#643e3ad19c93903201fde89abd76baaee725e6c2" - integrity sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA== - -"@rollup/rollup-linux-arm-musleabihf@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz#fdc6a595aec7b20c5bfdac81412028c56d734e63" - integrity sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg== - -"@rollup/rollup-linux-arm64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz#c28620bcd385496bdbbc24920b21f9fcca9ecbfa" - integrity sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw== - -"@rollup/rollup-linux-arm64-musl@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz#a6b71b1e8fa33bac9f65b6f879e8ed878035d120" - integrity sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ== - -"@rollup/rollup-linux-loongarch64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz#b06374601ce865a1110324b2f06db574d3a1b0e1" - integrity sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w== - -"@rollup/rollup-linux-powerpc64le-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz#8a2a1f6058c920889c2aff3753a20fead7a8cc26" - integrity sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg== - -"@rollup/rollup-linux-riscv64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz#8ef6f680d011b95a2f6546c6c31a37a33138035f" - integrity sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A== - -"@rollup/rollup-linux-riscv64-musl@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz#9f4884c5955a7cd39b396f6e27aa59b3269988eb" - integrity sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A== - -"@rollup/rollup-linux-s390x-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz#5619303cc51994e3df404a497f42c79dc5efd6eb" - integrity sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw== - -"@rollup/rollup-linux-x64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz#c3e42b66c04e25ad0f2a00beec42ede96ccc8983" - integrity sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ== - -"@rollup/rollup-linux-x64-musl@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz#8d3452de42aa72fc5fc3e5ad1eb0b68030742a25" - integrity sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg== - -"@rollup/rollup-win32-arm64-msvc@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz#3b7bbd9f43f1c380061f306abce6f3f64de20306" - integrity sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg== - -"@rollup/rollup-win32-ia32-msvc@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz#e27ef5c40bbec49fac3d4e4b1618fbe4597b40e5" - integrity sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ== - -"@rollup/rollup-win32-x64-msvc@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz#b0b595ad4720259bbb81600750d26a655cac06be" - integrity sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA== - -"@tailwindcss/node@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.7.tgz#6d2df06c6b84a6fd8255a535b4f537c5235a37ee" - integrity sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g== - dependencies: - "@ampproject/remapping" "^2.3.0" - enhanced-resolve "^5.18.1" - jiti "^2.4.2" - lightningcss "1.30.1" - magic-string "^0.30.17" - source-map-js "^1.2.1" - tailwindcss "4.1.7" - -"@tailwindcss/oxide-android-arm64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.7.tgz#3b115097b64aff6487715304ebe0bb43d7a2d42a" - integrity sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg== - -"@tailwindcss/oxide-darwin-arm64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.7.tgz#6c9d8cd3cd631a2ac0dff58a766c958cff5b0046" - integrity sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg== - -"@tailwindcss/oxide-darwin-x64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.7.tgz#a022b5ef006570ac8bb92128ec7fc9cc2314bdd1" - integrity sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw== - -"@tailwindcss/oxide-freebsd-x64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.7.tgz#efc133e6065c3c6299a981caa9c5f426e1d60e5e" - integrity sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw== - -"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.7.tgz#7a4dc1d9636c1b1e62936bd679a8867030dc0ad6" - integrity sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g== - -"@tailwindcss/oxide-linux-arm64-gnu@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.7.tgz#9a0da009c37d135fe983d1093bfb6d370fe926dc" - integrity sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA== - -"@tailwindcss/oxide-linux-arm64-musl@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.7.tgz#ef2398b48c426148c1b9949fdbdd86d364dca10d" - integrity sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A== - -"@tailwindcss/oxide-linux-x64-gnu@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.7.tgz#4d36aec4c4df87f8c332526bb6874b2c36230901" - integrity sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg== - -"@tailwindcss/oxide-linux-x64-musl@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.7.tgz#6e3045edc70d5156089aba0cd4a9760caa53965c" - integrity sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA== - -"@tailwindcss/oxide-wasm32-wasi@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.7.tgz#79b41b0c8da6e2f1dc5b722fe43528aa324222d5" - integrity sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A== - dependencies: - "@emnapi/core" "^1.4.3" - "@emnapi/runtime" "^1.4.3" - "@emnapi/wasi-threads" "^1.0.2" - "@napi-rs/wasm-runtime" "^0.2.9" - "@tybys/wasm-util" "^0.9.0" - tslib "^2.8.0" - -"@tailwindcss/oxide-win32-arm64-msvc@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.7.tgz#6c695b870eb8a3f9a958d0afccc67b1b6ee7e78d" - integrity sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw== - -"@tailwindcss/oxide-win32-x64-msvc@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.7.tgz#012b2929f6f33ba720a48793e3dbabc34bb0212c" - integrity sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ== - -"@tailwindcss/oxide@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.7.tgz#d8370c4d524a3017a85d4f63c41ca2318770debd" - integrity sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ== - dependencies: - detect-libc "^2.0.4" - tar "^7.4.3" - optionalDependencies: - "@tailwindcss/oxide-android-arm64" "4.1.7" - "@tailwindcss/oxide-darwin-arm64" "4.1.7" - "@tailwindcss/oxide-darwin-x64" "4.1.7" - "@tailwindcss/oxide-freebsd-x64" "4.1.7" - "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.7" - "@tailwindcss/oxide-linux-arm64-gnu" "4.1.7" - "@tailwindcss/oxide-linux-arm64-musl" "4.1.7" - "@tailwindcss/oxide-linux-x64-gnu" "4.1.7" - "@tailwindcss/oxide-linux-x64-musl" "4.1.7" - "@tailwindcss/oxide-wasm32-wasi" "4.1.7" - "@tailwindcss/oxide-win32-arm64-msvc" "4.1.7" - "@tailwindcss/oxide-win32-x64-msvc" "4.1.7" - -"@tailwindcss/vite@^4.1.4": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.7.tgz#73fb55d2341982fb920f916e1ef6781099cf2df6" - integrity sha512-tYa2fO3zDe41I7WqijyVbRd8oWT0aEID1Eokz5hMT6wShLIHj3yvwj9XbfuloHP9glZ6H+aG2AN/+ZrxJ1Y5RQ== - dependencies: - "@tailwindcss/node" "4.1.7" - "@tailwindcss/oxide" "4.1.7" - tailwindcss "4.1.7" - -"@tybys/wasm-util@^0.9.0": - version "0.9.0" - resolved "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" - integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== - dependencies: - tslib "^2.4.0" - -"@types/estree@1.0.7": - version "1.0.7" - resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" - integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== - -"@types/node@^20": - version "20.17.50" - resolved "https://registry.npmjs.org/@types/node/-/node-20.17.50.tgz#d2640af991fc839ba746f799516fc6a4e47ebe50" - integrity sha512-Mxiq0ULv/zo1OzOhwPqOA13I81CV/W3nvd3ChtQZRT5Cwz3cr0FKo/wMSsbTqL3EXpaBAEQhva2B8ByRkOIh9A== - dependencies: - undici-types "~6.19.2" - -"@types/react-dom@^19.1.2": - version "19.1.5" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.5.tgz#cdfe2c663742887372f54804b16e8dbc26bd794a" - integrity sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg== - -"@types/react@^19.1.2": - version "19.1.5" - resolved "https://registry.npmjs.org/@types/react/-/react-19.1.5.tgz#9feb3bdeb506d0c79d8533b6ebdcacdbcb4756db" - integrity sha512-piErsCVVbpMMT2r7wbawdZsq4xMvIAhQuac2gedQHysu1TZYEigE6pnFfgZT+/jQnrRuF5r+SHzuehFjfRjr4g== - dependencies: - csstype "^3.0.2" - -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" - integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== - -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -arg@^5.0.1: - version "5.0.2" - resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - -babel-dead-code-elimination@^1.0.6: - version "1.0.10" - resolved "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.10.tgz#e230562b57bf72ff3de4639ac763ba54f15d37b0" - integrity sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA== - dependencies: - "@babel/core" "^7.23.7" - "@babel/parser" "^7.23.6" - "@babel/traverse" "^7.23.7" - "@babel/types" "^7.23.6" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -basic-auth@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" - integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== - dependencies: - safe-buffer "5.1.2" - -body-parser@1.20.3: - version "1.20.3" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" - integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== - dependencies: - bytes "3.1.2" - content-type "~1.0.5" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.13.0" - raw-body "2.5.2" - type-is "~1.6.18" - unpipe "1.0.0" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -browserslist@^4.24.0: - version "4.24.5" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz#aa0f5b8560fe81fde84c6dcb38f759bafba0e11b" - integrity sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw== - dependencies: - caniuse-lite "^1.0.30001716" - electron-to-chromium "^1.5.149" - node-releases "^2.0.19" - update-browserslist-db "^1.1.3" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -cac@^6.7.14: - version "6.7.14" - resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" - integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== - -call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" - integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - -call-bound@^1.0.2: - version "1.0.4" - resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" - integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== - dependencies: - call-bind-apply-helpers "^1.0.2" - get-intrinsic "^1.3.0" - -caniuse-lite@^1.0.30001716: - version "1.0.30001718" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz#dae13a9c80d517c30c6197515a96131c194d8f82" - integrity sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw== - -chokidar@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" - integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== - dependencies: - readdirp "^4.0.1" - -chownr@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" - integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -compressible@~2.0.18: - version "2.0.18" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.8.0" - resolved "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz#09420efc96e11a0f44f3a558de59e321364180f7" - integrity sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA== - dependencies: - bytes "3.1.2" - compressible "~2.0.18" - debug "2.6.9" - negotiator "~0.6.4" - on-headers "~1.0.2" - safe-buffer "5.2.1" - vary "~1.1.2" - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4, content-type@~1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.7.1: - version "0.7.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" - integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== - -cookie@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" - integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== - -cross-spawn@^7.0.6: - version "7.0.6" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" - integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -debug@2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.4.0: - version "4.4.1" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" - integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== - dependencies: - ms "^2.1.3" - -dedent@^1.5.3: - version "1.6.0" - resolved "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz#79d52d6389b1ffa67d2bcef59ba51847a9d503b2" - integrity sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA== - -depd@2.0.0, depd@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-libc@^2.0.3, detect-libc@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" - integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== - -dunder-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" - integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-errors "^1.3.0" - gopd "^1.2.0" - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.5.149: - version "1.5.155" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.155.tgz#809dd0ae9ae1db87c358e0c0c17c09a2ffc432d1" - integrity sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -encodeurl@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" - integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== - -enhanced-resolve@^5.18.1: - version "5.18.1" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" - integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -err-code@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== - -es-define-property@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" - integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== - -es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-module-lexer@^1.3.1, es-module-lexer@^1.5.4: - version "1.7.0" - resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" - integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== - -es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== - dependencies: - es-errors "^1.3.0" - -esbuild@^0.25.0: - version "0.25.4" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz#bb9a16334d4ef2c33c7301a924b8b863351a0854" - integrity sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q== - optionalDependencies: - "@esbuild/aix-ppc64" "0.25.4" - "@esbuild/android-arm" "0.25.4" - "@esbuild/android-arm64" "0.25.4" - "@esbuild/android-x64" "0.25.4" - "@esbuild/darwin-arm64" "0.25.4" - "@esbuild/darwin-x64" "0.25.4" - "@esbuild/freebsd-arm64" "0.25.4" - "@esbuild/freebsd-x64" "0.25.4" - "@esbuild/linux-arm" "0.25.4" - "@esbuild/linux-arm64" "0.25.4" - "@esbuild/linux-ia32" "0.25.4" - "@esbuild/linux-loong64" "0.25.4" - "@esbuild/linux-mips64el" "0.25.4" - "@esbuild/linux-ppc64" "0.25.4" - "@esbuild/linux-riscv64" "0.25.4" - "@esbuild/linux-s390x" "0.25.4" - "@esbuild/linux-x64" "0.25.4" - "@esbuild/netbsd-arm64" "0.25.4" - "@esbuild/netbsd-x64" "0.25.4" - "@esbuild/openbsd-arm64" "0.25.4" - "@esbuild/openbsd-x64" "0.25.4" - "@esbuild/sunos-x64" "0.25.4" - "@esbuild/win32-arm64" "0.25.4" - "@esbuild/win32-ia32" "0.25.4" - "@esbuild/win32-x64" "0.25.4" - -escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -exit-hook@2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz#007b2d92c6428eda2b76e7016a34351586934593" - integrity sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw== - -express@^4.19.2: - version "4.21.2" - resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" - integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.3" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.7.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~2.0.0" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.3.1" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.3" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.12" - proxy-addr "~2.0.7" - qs "6.13.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.19.0" - serve-static "1.16.2" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -fdir@^6.4.4: - version "6.4.4" - resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz#1cfcf86f875a883e19a8fab53622cfe992e8d2f9" - integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg== - -finalhandler@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" - integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== - dependencies: - debug "2.6.9" - encodeurl "~2.0.0" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - -foreground-child@^3.1.0: - version "3.3.1" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" - integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== - dependencies: - cross-spawn "^7.0.6" - signal-exit "^4.0.1" - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -fs-extra@^10.0.0: - version "10.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" - integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== - dependencies: - call-bind-apply-helpers "^1.0.2" - es-define-property "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.1.1" - function-bind "^1.1.2" - get-proto "^1.0.1" - gopd "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - math-intrinsics "^1.1.0" - -get-port@5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - -get-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" - integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== - dependencies: - dunder-proto "^1.0.1" - es-object-atoms "^1.0.0" - -glob@^10.2.2: - version "10.4.5" - resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globrex@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" - integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== - -gopd@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" - integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== - -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -has-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" - integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== - -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -hosted-git-info@^6.0.0, hosted-git-info@^6.1.1: - version "6.1.3" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.3.tgz#2ee1a14a097a1236bddf8672c35b613c46c55946" - integrity sha512-HVJyzUrLIL1c0QmviVh5E8VGyUS7xCFPS6yydaVd1UegW+ibV/CohqTH9MkOLDp5o+rb82DMo77PTuc9F/8GKw== - dependencies: - lru-cache "^7.5.1" - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -inherits@2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-core-module@^2.8.1: - version "2.16.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== - dependencies: - hasown "^2.0.2" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -isbot@^5.1.27: - version "5.1.28" - resolved "https://registry.npmjs.org/isbot/-/isbot-5.1.28.tgz#a9a32e70c890cf19b76090971b1fccf6021a519b" - integrity sha512-qrOp4g3xj8YNse4biorv6O5ZShwsJM0trsoda4y7j/Su7ZtTTfVXFzbKkpgcSoDrHS8FcTuUwcU04YimZlZOxw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - -jiti@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" - integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - -jsesc@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" - integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== - -json-parse-even-better-errors@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz#b43d35e89c0f3be6b5fbbe9dc6c82467b30c28da" - integrity sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ== - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -lightningcss-darwin-arm64@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae" - integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== - -lightningcss-darwin-x64@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" - integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== - -lightningcss-freebsd-x64@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" - integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== - -lightningcss-linux-arm-gnueabihf@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" - integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== - -lightningcss-linux-arm64-gnu@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" - integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== - -lightningcss-linux-arm64-musl@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" - integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== - -lightningcss-linux-x64-gnu@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" - integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== - -lightningcss-linux-x64-musl@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" - integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== - -lightningcss-win32-arm64-msvc@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" - integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== - -lightningcss-win32-x64-msvc@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" - integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== - -lightningcss@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz#78e979c2d595bfcb90d2a8c0eb632fe6c5bfed5d" - integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== - dependencies: - detect-libc "^2.0.3" - optionalDependencies: - lightningcss-darwin-arm64 "1.30.1" - lightningcss-darwin-x64 "1.30.1" - lightningcss-freebsd-x64 "1.30.1" - lightningcss-linux-arm-gnueabihf "1.30.1" - lightningcss-linux-arm64-gnu "1.30.1" - lightningcss-linux-arm64-musl "1.30.1" - lightningcss-linux-x64-gnu "1.30.1" - lightningcss-linux-x64-musl "1.30.1" - lightningcss-win32-arm64-msvc "1.30.1" - lightningcss-win32-x64-msvc "1.30.1" - -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^7.4.4, lru-cache@^7.5.1: - version "7.18.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -magic-string@^0.30.17: - version "0.30.17" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" - integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.5.0" - -math-intrinsics@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" - integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -merge-descriptors@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -"mime-db@>= 1.43.0 < 2": - version "1.54.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" - integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== - -mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - -minizlib@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz#f33d638eb279f664439aa38dc5f91607468cb574" - integrity sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== - dependencies: - minipass "^7.1.2" - -mkdirp@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" - integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== - -morgan@^1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" - integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== - dependencies: - basic-auth "~2.0.1" - debug "2.6.9" - depd "~2.0.0" - on-finished "~2.3.0" - on-headers "~1.0.2" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.3, ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@^3.3.8: - version "3.3.11" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" - integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -negotiator@~0.6.4: - version "0.6.4" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" - integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== - -node-releases@^2.0.19: - version "2.0.19" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" - integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== - -normalize-package-data@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz#abcb8d7e724c40d88462b84982f7cbf6859b4588" - integrity sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q== - dependencies: - hosted-git-info "^6.0.0" - is-core-module "^2.8.1" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - -npm-install-checks@^6.0.0: - version "6.3.0" - resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" - integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== - dependencies: - semver "^7.1.1" - -npm-normalize-package-bin@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" - integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== - -npm-package-arg@^10.0.0: - version "10.1.0" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz#827d1260a683806685d17193073cc152d3c7e9b1" - integrity sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA== - dependencies: - hosted-git-info "^6.0.0" - proc-log "^3.0.0" - semver "^7.3.5" - validate-npm-package-name "^5.0.0" - -npm-pick-manifest@^8.0.0: - version "8.0.2" - resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz#2159778d9c7360420c925c1a2287b5a884c713aa" - integrity sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg== - dependencies: - npm-install-checks "^6.0.0" - npm-normalize-package-bin "^3.0.0" - npm-package-arg "^10.0.0" - semver "^7.3.5" - -object-inspect@^1.13.3: - version "1.13.4" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" - integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -package-json-from-dist@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" - integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - -path-to-regexp@0.1.12: - version "0.1.12" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" - integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== - -pathe@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" - integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== - -picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - -picomatch@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" - integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== - -postcss@^8.5.3: - version "8.5.3" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" - integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== - dependencies: - nanoid "^3.3.8" - picocolors "^1.1.1" - source-map-js "^1.2.1" - -prettier@^2.7.1: - version "2.8.8" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - -proc-log@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" - integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== - -promise-retry@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" - integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== - dependencies: - err-code "^2.0.2" - retry "^0.12.0" - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -qs@6.13.0: - version "6.13.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== - dependencies: - side-channel "^1.0.6" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-dom@^19.1.0: - version "19.1.0" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" - integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== - dependencies: - scheduler "^0.26.0" - -react-refresh@^0.14.0: - version "0.14.2" - resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" - integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== - -react-router@^7.5.3: - version "7.6.0" - resolved "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz#e2d0872d7bea8df79465a8bba9a20c87c32ce995" - integrity sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ== - dependencies: - cookie "^1.0.1" - set-cookie-parser "^2.6.0" - -react@^19.1.0: - version "19.1.0" - resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" - integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== - -readdirp@^4.0.1: - version "4.1.2" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" - integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== - -rollup@^4.34.9: - version "4.41.0" - resolved "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz#17476835d2967759e3ffebe5823ed15fc4b7d13e" - integrity sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg== - dependencies: - "@types/estree" "1.0.7" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.41.0" - "@rollup/rollup-android-arm64" "4.41.0" - "@rollup/rollup-darwin-arm64" "4.41.0" - "@rollup/rollup-darwin-x64" "4.41.0" - "@rollup/rollup-freebsd-arm64" "4.41.0" - "@rollup/rollup-freebsd-x64" "4.41.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.41.0" - "@rollup/rollup-linux-arm-musleabihf" "4.41.0" - "@rollup/rollup-linux-arm64-gnu" "4.41.0" - "@rollup/rollup-linux-arm64-musl" "4.41.0" - "@rollup/rollup-linux-loongarch64-gnu" "4.41.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.41.0" - "@rollup/rollup-linux-riscv64-gnu" "4.41.0" - "@rollup/rollup-linux-riscv64-musl" "4.41.0" - "@rollup/rollup-linux-s390x-gnu" "4.41.0" - "@rollup/rollup-linux-x64-gnu" "4.41.0" - "@rollup/rollup-linux-x64-musl" "4.41.0" - "@rollup/rollup-win32-arm64-msvc" "4.41.0" - "@rollup/rollup-win32-ia32-msvc" "4.41.0" - "@rollup/rollup-win32-x64-msvc" "4.41.0" - fsevents "~2.3.2" - -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -scheduler@^0.26.0: - version "0.26.0" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" - integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3: - version "7.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -send@0.19.0: - version "0.19.0" - resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serve-static@1.16.2: - version "1.16.2" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== - dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" - -set-cookie-parser@^2.6.0: - version "2.7.1" - resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" - integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -side-channel-list@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" - integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - -side-channel-map@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" - integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - -side-channel-weakmap@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" - integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - side-channel-map "^1.0.1" - -side-channel@^1.0.6: - version "1.1.0" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" - integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - side-channel-list "^1.0.0" - side-channel-map "^1.0.1" - side-channel-weakmap "^1.0.2" - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -source-map-js@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" - integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== - -source-map-support@^0.5.21: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.5.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" - integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.21" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz#6d6e980c9df2b6fc905343a3b2d702a6239536c3" - integrity sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg== - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -stream-slice@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b" - integrity sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA== - -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: - version "4.2.3" - resolved "https://registry.npmjs.org/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@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -tailwindcss@4.1.7, tailwindcss@^4.1.4: - version "4.1.7" - resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz#949f76d50667946ddd7291e0c7a4b5a7dfc9e765" - integrity sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg== - -tapable@^2.2.0: - version "2.2.2" - resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz#ab4984340d30cb9989a490032f086dbb8b56d872" - integrity sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== - -tar@^7.4.3: - version "7.4.3" - resolved "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" - integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== - dependencies: - "@isaacs/fs-minipass" "^4.0.0" - chownr "^3.0.0" - minipass "^7.1.2" - minizlib "^3.0.1" - mkdirp "^3.0.1" - yallist "^5.0.0" - -tinyglobby@^0.2.13: - version "0.2.13" - resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz#a0e46515ce6cbcd65331537e57484af5a7b2ff7e" - integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw== - dependencies: - fdir "^6.4.4" - picomatch "^4.0.2" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -tsconfck@^3.0.3: - version "3.1.6" - resolved "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz#da1f0b10d82237ac23422374b3fce1edb23c3ead" - integrity sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w== - -tslib@^2.4.0, tslib@^2.8.0: - version "2.8.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typescript@^5.8.3: - version "5.8.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" - integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== - -undici-types@~6.19.2: - version "6.19.8" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== - -undici@^6.19.2: - version "6.21.3" - resolved "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz#185752ad92c3d0efe7a7d1f6854a50f83b552d7a" - integrity sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw== - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -update-browserslist-db@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" - integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.1" - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -valibot@^0.41.0: - version "0.41.0" - resolved "https://registry.npmjs.org/valibot/-/valibot-0.41.0.tgz#5c2efd49c078e455f7862379365f6036f3cd9f96" - integrity sha512-igDBb8CTYr8YTQlOKgaN9nSS0Be7z+WRuaeYqGf3Cjz3aKmSnqEmYnkfVjzIuumGqfHpa3fLIvMEAfhrpqN8ng== - -validate-npm-package-license@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validate-npm-package-name@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" - integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -vite-node@3.0.0-beta.2: - version "3.0.0-beta.2" - resolved "https://registry.npmjs.org/vite-node/-/vite-node-3.0.0-beta.2.tgz#4208a6be384f9e7bba97570114d662ce9c957dc1" - integrity sha512-ofTf6cfRdL30Wbl9n/BX81EyIR5s4PReLmSurrxQ+koLaWUNOEo8E0lCM53OJkb8vpa2URM2nSrxZsIFyvY1rg== - dependencies: - cac "^6.7.14" - debug "^4.4.0" - es-module-lexer "^1.5.4" - pathe "^1.1.2" - vite "^5.0.0 || ^6.0.0" - -vite-tsconfig-paths@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz#d9a71106a7ff2c1c840c6f1708042f76a9212ed4" - integrity sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w== - dependencies: - debug "^4.1.1" - globrex "^0.1.2" - tsconfck "^3.0.3" - -"vite@^5.0.0 || ^6.0.0", vite@^6.3.3: - version "6.3.5" - resolved "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz#fec73879013c9c0128c8d284504c6d19410d12a3" - integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ== - dependencies: - esbuild "^0.25.0" - fdir "^6.4.4" - picomatch "^4.0.2" - postcss "^8.5.3" - rollup "^4.34.9" - tinyglobby "^0.2.13" - optionalDependencies: - fsevents "~2.3.3" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -which@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/which/-/which-3.0.1.tgz#89f1cd0c23f629a8105ffe69b8172791c87b4be1" - integrity sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg== - dependencies: - isexe "^2.0.0" - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/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@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" - integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-spa/yarn.lock b/dev-packages/e2e-tests/test-applications/react-router-7-framework-spa/yarn.lock deleted file mode 100644 index 43736103138f..000000000000 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-spa/yarn.lock +++ /dev/null @@ -1,2311 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" - integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== - dependencies: - "@babel/helper-validator-identifier" "^7.27.1" - js-tokens "^4.0.0" - picocolors "^1.1.1" - -"@babel/compat-data@^7.27.2": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz#4183f9e642fd84e74e3eea7ffa93a412e3b102c9" - integrity sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ== - -"@babel/core@^7.21.8", "@babel/core@^7.23.7": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz#89de51e86bd12246003e3524704c49541b16c3e6" - integrity sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.27.1" - "@babel/helper-compilation-targets" "^7.27.1" - "@babel/helper-module-transforms" "^7.27.1" - "@babel/helpers" "^7.27.1" - "@babel/parser" "^7.27.1" - "@babel/template" "^7.27.1" - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.21.5", "@babel/generator@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz#862d4fad858f7208edd487c28b58144036b76230" - integrity sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w== - dependencies: - "@babel/parser" "^7.27.1" - "@babel/types" "^7.27.1" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/helper-annotate-as-pure@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz#4345d81a9a46a6486e24d069469f13e60445c05d" - integrity sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow== - dependencies: - "@babel/types" "^7.27.1" - -"@babel/helper-compilation-targets@^7.27.1": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" - integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== - dependencies: - "@babel/compat-data" "^7.27.2" - "@babel/helper-validator-option" "^7.27.1" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz#5bee4262a6ea5ddc852d0806199eb17ca3de9281" - integrity sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A== - dependencies: - "@babel/helper-annotate-as-pure" "^7.27.1" - "@babel/helper-member-expression-to-functions" "^7.27.1" - "@babel/helper-optimise-call-expression" "^7.27.1" - "@babel/helper-replace-supers" "^7.27.1" - "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" - "@babel/traverse" "^7.27.1" - semver "^6.3.1" - -"@babel/helper-member-expression-to-functions@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44" - integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA== - dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/helper-module-imports@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" - integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== - dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/helper-module-transforms@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz#e1663b8b71d2de948da5c4fb2a20ca4f3ec27a6f" - integrity sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g== - dependencies: - "@babel/helper-module-imports" "^7.27.1" - "@babel/helper-validator-identifier" "^7.27.1" - "@babel/traverse" "^7.27.1" - -"@babel/helper-optimise-call-expression@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" - integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== - dependencies: - "@babel/types" "^7.27.1" - -"@babel/helper-plugin-utils@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" - integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== - -"@babel/helper-replace-supers@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0" - integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.27.1" - "@babel/helper-optimise-call-expression" "^7.27.1" - "@babel/traverse" "^7.27.1" - -"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" - integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== - dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/helper-string-parser@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" - integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== - -"@babel/helper-validator-identifier@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" - integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== - -"@babel/helper-validator-option@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" - integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== - -"@babel/helpers@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz#ffc27013038607cdba3288e692c3611c06a18aa4" - integrity sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ== - dependencies: - "@babel/template" "^7.27.1" - "@babel/types" "^7.27.1" - -"@babel/parser@^7.21.8", "@babel/parser@^7.23.6", "@babel/parser@^7.27.1", "@babel/parser@^7.27.2": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz#577518bedb17a2ce4212afd052e01f7df0941127" - integrity sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw== - dependencies: - "@babel/types" "^7.27.1" - -"@babel/plugin-syntax-decorators@^7.22.10": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz#ee7dd9590aeebc05f9d4c8c0560007b05979a63d" - integrity sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-syntax-jsx@^7.21.4", "@babel/plugin-syntax-jsx@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" - integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-syntax-typescript@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" - integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-transform-modules-commonjs@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz#8e44ed37c2787ecc23bdc367f49977476614e832" - integrity sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw== - dependencies: - "@babel/helper-module-transforms" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" - -"@babel/plugin-transform-typescript@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz#d3bb65598bece03f773111e88cc4e8e5070f1140" - integrity sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.27.1" - "@babel/helper-create-class-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" - "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" - "@babel/plugin-syntax-typescript" "^7.27.1" - -"@babel/preset-typescript@^7.21.5": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz#190742a6428d282306648a55b0529b561484f912" - integrity sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ== - dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - "@babel/helper-validator-option" "^7.27.1" - "@babel/plugin-syntax-jsx" "^7.27.1" - "@babel/plugin-transform-modules-commonjs" "^7.27.1" - "@babel/plugin-transform-typescript" "^7.27.1" - -"@babel/template@^7.27.1": - version "7.27.2" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" - integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== - dependencies: - "@babel/code-frame" "^7.27.1" - "@babel/parser" "^7.27.2" - "@babel/types" "^7.27.1" - -"@babel/traverse@^7.23.2", "@babel/traverse@^7.23.7", "@babel/traverse@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz#4db772902b133bbddd1c4f7a7ee47761c1b9f291" - integrity sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg== - dependencies: - "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.27.1" - "@babel/parser" "^7.27.1" - "@babel/template" "^7.27.1" - "@babel/types" "^7.27.1" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.22.5", "@babel/types@^7.23.6", "@babel/types@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz#9defc53c16fc899e46941fc6901a9eea1c9d8560" - integrity sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q== - dependencies: - "@babel/helper-string-parser" "^7.27.1" - "@babel/helper-validator-identifier" "^7.27.1" - -"@emnapi/core@^1.4.3": - version "1.4.3" - resolved "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz#9ac52d2d5aea958f67e52c40a065f51de59b77d6" - integrity sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g== - dependencies: - "@emnapi/wasi-threads" "1.0.2" - tslib "^2.4.0" - -"@emnapi/runtime@^1.4.3": - version "1.4.3" - resolved "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz#c0564665c80dc81c448adac23f9dfbed6c838f7d" - integrity sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ== - dependencies: - tslib "^2.4.0" - -"@emnapi/wasi-threads@1.0.2", "@emnapi/wasi-threads@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz#977f44f844eac7d6c138a415a123818c655f874c" - integrity sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA== - dependencies: - tslib "^2.4.0" - -"@esbuild/aix-ppc64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz#830d6476cbbca0c005136af07303646b419f1162" - integrity sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q== - -"@esbuild/android-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz#d11d4fc299224e729e2190cacadbcc00e7a9fd67" - integrity sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A== - -"@esbuild/android-arm@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz#5660bd25080553dd2a28438f2a401a29959bd9b1" - integrity sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ== - -"@esbuild/android-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz#18ddde705bf984e8cd9efec54e199ac18bc7bee1" - integrity sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ== - -"@esbuild/darwin-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz#b0b7fb55db8fc6f5de5a0207ae986eb9c4766e67" - integrity sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g== - -"@esbuild/darwin-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz#e6813fdeba0bba356cb350a4b80543fbe66bf26f" - integrity sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A== - -"@esbuild/freebsd-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz#dc11a73d3ccdc308567b908b43c6698e850759be" - integrity sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ== - -"@esbuild/freebsd-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz#91da08db8bd1bff5f31924c57a81dab26e93a143" - integrity sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ== - -"@esbuild/linux-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz#efc15e45c945a082708f9a9f73bfa8d4db49728a" - integrity sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ== - -"@esbuild/linux-arm@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz#9b93c3e54ac49a2ede6f906e705d5d906f6db9e8" - integrity sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ== - -"@esbuild/linux-ia32@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz#be8ef2c3e1d99fca2d25c416b297d00360623596" - integrity sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ== - -"@esbuild/linux-loong64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz#b0840a2707c3fc02eec288d3f9defa3827cd7a87" - integrity sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA== - -"@esbuild/linux-mips64el@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz#2a198e5a458c9f0e75881a4e63d26ba0cf9df39f" - integrity sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg== - -"@esbuild/linux-ppc64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz#64f4ae0b923d7dd72fb860b9b22edb42007cf8f5" - integrity sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag== - -"@esbuild/linux-riscv64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz#fb2844b11fdddd39e29d291c7cf80f99b0d5158d" - integrity sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA== - -"@esbuild/linux-s390x@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz#1466876e0aa3560c7673e63fdebc8278707bc750" - integrity sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g== - -"@esbuild/linux-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz#c10fde899455db7cba5f11b3bccfa0e41bf4d0cd" - integrity sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA== - -"@esbuild/netbsd-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz#02e483fbcbe3f18f0b02612a941b77be76c111a4" - integrity sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ== - -"@esbuild/netbsd-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz#ec401fb0b1ed0ac01d978564c5fc8634ed1dc2ed" - integrity sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw== - -"@esbuild/openbsd-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz#f272c2f41cfea1d91b93d487a51b5c5ca7a8c8c4" - integrity sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A== - -"@esbuild/openbsd-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz#2e25950bc10fa9db1e5c868e3d50c44f7c150fd7" - integrity sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw== - -"@esbuild/sunos-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz#cd596fa65a67b3b7adc5ecd52d9f5733832e1abd" - integrity sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q== - -"@esbuild/win32-arm64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz#b4dbcb57b21eeaf8331e424c3999b89d8951dc88" - integrity sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ== - -"@esbuild/win32-ia32@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz#410842e5d66d4ece1757634e297a87635eb82f7a" - integrity sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg== - -"@esbuild/win32-x64@0.25.4": - version "0.25.4" - resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz#0b17ec8a70b2385827d52314c1253160a0b9bacc" - integrity sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ== - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - -"@isaacs/fs-minipass@^4.0.0": - version "4.0.1" - resolved "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" - integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== - dependencies: - minipass "^7.0.4" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.8" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" - integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@mjackson/node-fetch-server@^0.2.0": - version "0.2.0" - resolved "https://registry.npmjs.org/@mjackson/node-fetch-server/-/node-fetch-server-0.2.0.tgz#577c0c25d8aae9f69a97738b7b0d03d1471cdc49" - integrity sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng== - -"@napi-rs/wasm-runtime@^0.2.9": - version "0.2.10" - resolved "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz#f3b7109419c6670000b2401e0c778b98afc25f84" - integrity sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ== - dependencies: - "@emnapi/core" "^1.4.3" - "@emnapi/runtime" "^1.4.3" - "@tybys/wasm-util" "^0.9.0" - -"@npmcli/git@^4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz#ab0ad3fd82bc4d8c1351b6c62f0fa56e8fe6afa6" - integrity sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ== - dependencies: - "@npmcli/promise-spawn" "^6.0.0" - lru-cache "^7.4.4" - npm-pick-manifest "^8.0.0" - proc-log "^3.0.0" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^3.0.0" - -"@npmcli/package-json@^4.0.1": - version "4.0.1" - resolved "https://registry.npmjs.org/@npmcli/package-json/-/package-json-4.0.1.tgz#1a07bf0e086b640500791f6bf245ff43cc27fa37" - integrity sha512-lRCEGdHZomFsURroh522YvA/2cVb9oPIJrjHanCJZkiasz1BzcnLr3tBJhlV7S86MBJBuAQ33is2D60YitZL2Q== - dependencies: - "@npmcli/git" "^4.1.0" - glob "^10.2.2" - hosted-git-info "^6.1.1" - json-parse-even-better-errors "^3.0.0" - normalize-package-data "^5.0.0" - proc-log "^3.0.0" - semver "^7.5.3" - -"@npmcli/promise-spawn@^6.0.0": - version "6.0.2" - resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz#c8bc4fa2bd0f01cb979d8798ba038f314cfa70f2" - integrity sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg== - dependencies: - which "^3.0.0" - -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - -"@react-router/dev@^7.5.3": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/dev/-/dev-7.6.0.tgz#9974e608be0398ee22282405992d0a62a3cc26ba" - integrity sha512-XSxEslex0ddJPxNNgdU1Eqmc9lsY/lhcLNCcRLAtlrOPyOz3Y8kIPpAf5T/U2AG3HGXFVBa9f8aQ7wXU3wTJSw== - dependencies: - "@babel/core" "^7.21.8" - "@babel/generator" "^7.21.5" - "@babel/parser" "^7.21.8" - "@babel/plugin-syntax-decorators" "^7.22.10" - "@babel/plugin-syntax-jsx" "^7.21.4" - "@babel/preset-typescript" "^7.21.5" - "@babel/traverse" "^7.23.2" - "@babel/types" "^7.22.5" - "@npmcli/package-json" "^4.0.1" - "@react-router/node" "7.6.0" - arg "^5.0.1" - babel-dead-code-elimination "^1.0.6" - chokidar "^4.0.0" - dedent "^1.5.3" - es-module-lexer "^1.3.1" - exit-hook "2.2.1" - fs-extra "^10.0.0" - jsesc "3.0.2" - lodash "^4.17.21" - pathe "^1.1.2" - picocolors "^1.1.1" - prettier "^2.7.1" - react-refresh "^0.14.0" - semver "^7.3.7" - set-cookie-parser "^2.6.0" - valibot "^0.41.0" - vite-node "3.0.0-beta.2" - -"@react-router/express@7.6.0": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/express/-/express-7.6.0.tgz#1c9686e9154aab7b9411d4d1bcf4cc14145ebc94" - integrity sha512-nxSTCcTsVx94bXOI9JjG7Cg338myi8EdQWTOjA97v2ApX35wZm/ZDYos5MbrvZiMi0aB4KgAD62o4byNqF9Z1A== - dependencies: - "@react-router/node" "7.6.0" - -"@react-router/node@7.6.0", "@react-router/node@^7.5.3": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/node/-/node-7.6.0.tgz#18c31c502f8004f2b8a1ca6ceebd0ac1e9307e12" - integrity sha512-agjDPUzisLdGJ7Q2lx/Z3OfdS2t1k6qv/nTvA45iahGsQJCMDvMqVoIi7iIULKQJwrn4HWjM9jqEp75+WsMOXg== - dependencies: - "@mjackson/node-fetch-server" "^0.2.0" - source-map-support "^0.5.21" - stream-slice "^0.1.2" - undici "^6.19.2" - -"@react-router/serve@^7.5.3": - version "7.6.0" - resolved "https://registry.npmjs.org/@react-router/serve/-/serve-7.6.0.tgz#ab0ff21cf80b3dbbb746fad1110d9d2903b24439" - integrity sha512-2O8ALEYgJfimvEdNRqMpnZb2N+DQ5UK/SKo9Xo3mTkt3no0rNTcNxzmhzD2tm92Q/HI7kHmMY1nBegNB2i1abA== - dependencies: - "@react-router/express" "7.6.0" - "@react-router/node" "7.6.0" - compression "^1.7.4" - express "^4.19.2" - get-port "5.1.1" - morgan "^1.10.0" - source-map-support "^0.5.21" - -"@rollup/rollup-android-arm-eabi@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz#9145b38faf3fbfe3ec557130110e772f797335aa" - integrity sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A== - -"@rollup/rollup-android-arm64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz#d73d641c59e9d7827e5ce0af9dfbc168b95cce0f" - integrity sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ== - -"@rollup/rollup-darwin-arm64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz#45d9d71d941117c98e7a5e77f60f0bc682d27e82" - integrity sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw== - -"@rollup/rollup-darwin-x64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz#8d72fb5f81714cb43e90f263fb1674520cce3f2a" - integrity sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ== - -"@rollup/rollup-freebsd-arm64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz#a52b58852c9cec9255e382a2f335b08bc8c6111d" - integrity sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg== - -"@rollup/rollup-freebsd-x64@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz#104511dc64612789ddda41d164ab07cdac84a6c1" - integrity sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg== - -"@rollup/rollup-linux-arm-gnueabihf@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz#643e3ad19c93903201fde89abd76baaee725e6c2" - integrity sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA== - -"@rollup/rollup-linux-arm-musleabihf@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz#fdc6a595aec7b20c5bfdac81412028c56d734e63" - integrity sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg== - -"@rollup/rollup-linux-arm64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz#c28620bcd385496bdbbc24920b21f9fcca9ecbfa" - integrity sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw== - -"@rollup/rollup-linux-arm64-musl@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz#a6b71b1e8fa33bac9f65b6f879e8ed878035d120" - integrity sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ== - -"@rollup/rollup-linux-loongarch64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz#b06374601ce865a1110324b2f06db574d3a1b0e1" - integrity sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w== - -"@rollup/rollup-linux-powerpc64le-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz#8a2a1f6058c920889c2aff3753a20fead7a8cc26" - integrity sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg== - -"@rollup/rollup-linux-riscv64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz#8ef6f680d011b95a2f6546c6c31a37a33138035f" - integrity sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A== - -"@rollup/rollup-linux-riscv64-musl@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz#9f4884c5955a7cd39b396f6e27aa59b3269988eb" - integrity sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A== - -"@rollup/rollup-linux-s390x-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz#5619303cc51994e3df404a497f42c79dc5efd6eb" - integrity sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw== - -"@rollup/rollup-linux-x64-gnu@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz#c3e42b66c04e25ad0f2a00beec42ede96ccc8983" - integrity sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ== - -"@rollup/rollup-linux-x64-musl@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz#8d3452de42aa72fc5fc3e5ad1eb0b68030742a25" - integrity sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg== - -"@rollup/rollup-win32-arm64-msvc@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz#3b7bbd9f43f1c380061f306abce6f3f64de20306" - integrity sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg== - -"@rollup/rollup-win32-ia32-msvc@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz#e27ef5c40bbec49fac3d4e4b1618fbe4597b40e5" - integrity sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ== - -"@rollup/rollup-win32-x64-msvc@4.41.0": - version "4.41.0" - resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz#b0b595ad4720259bbb81600750d26a655cac06be" - integrity sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA== - -"@tailwindcss/node@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.7.tgz#6d2df06c6b84a6fd8255a535b4f537c5235a37ee" - integrity sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g== - dependencies: - "@ampproject/remapping" "^2.3.0" - enhanced-resolve "^5.18.1" - jiti "^2.4.2" - lightningcss "1.30.1" - magic-string "^0.30.17" - source-map-js "^1.2.1" - tailwindcss "4.1.7" - -"@tailwindcss/oxide-android-arm64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.7.tgz#3b115097b64aff6487715304ebe0bb43d7a2d42a" - integrity sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg== - -"@tailwindcss/oxide-darwin-arm64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.7.tgz#6c9d8cd3cd631a2ac0dff58a766c958cff5b0046" - integrity sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg== - -"@tailwindcss/oxide-darwin-x64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.7.tgz#a022b5ef006570ac8bb92128ec7fc9cc2314bdd1" - integrity sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw== - -"@tailwindcss/oxide-freebsd-x64@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.7.tgz#efc133e6065c3c6299a981caa9c5f426e1d60e5e" - integrity sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw== - -"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.7.tgz#7a4dc1d9636c1b1e62936bd679a8867030dc0ad6" - integrity sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g== - -"@tailwindcss/oxide-linux-arm64-gnu@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.7.tgz#9a0da009c37d135fe983d1093bfb6d370fe926dc" - integrity sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA== - -"@tailwindcss/oxide-linux-arm64-musl@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.7.tgz#ef2398b48c426148c1b9949fdbdd86d364dca10d" - integrity sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A== - -"@tailwindcss/oxide-linux-x64-gnu@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.7.tgz#4d36aec4c4df87f8c332526bb6874b2c36230901" - integrity sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg== - -"@tailwindcss/oxide-linux-x64-musl@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.7.tgz#6e3045edc70d5156089aba0cd4a9760caa53965c" - integrity sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA== - -"@tailwindcss/oxide-wasm32-wasi@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.7.tgz#79b41b0c8da6e2f1dc5b722fe43528aa324222d5" - integrity sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A== - dependencies: - "@emnapi/core" "^1.4.3" - "@emnapi/runtime" "^1.4.3" - "@emnapi/wasi-threads" "^1.0.2" - "@napi-rs/wasm-runtime" "^0.2.9" - "@tybys/wasm-util" "^0.9.0" - tslib "^2.8.0" - -"@tailwindcss/oxide-win32-arm64-msvc@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.7.tgz#6c695b870eb8a3f9a958d0afccc67b1b6ee7e78d" - integrity sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw== - -"@tailwindcss/oxide-win32-x64-msvc@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.7.tgz#012b2929f6f33ba720a48793e3dbabc34bb0212c" - integrity sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ== - -"@tailwindcss/oxide@4.1.7": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.7.tgz#d8370c4d524a3017a85d4f63c41ca2318770debd" - integrity sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ== - dependencies: - detect-libc "^2.0.4" - tar "^7.4.3" - optionalDependencies: - "@tailwindcss/oxide-android-arm64" "4.1.7" - "@tailwindcss/oxide-darwin-arm64" "4.1.7" - "@tailwindcss/oxide-darwin-x64" "4.1.7" - "@tailwindcss/oxide-freebsd-x64" "4.1.7" - "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.7" - "@tailwindcss/oxide-linux-arm64-gnu" "4.1.7" - "@tailwindcss/oxide-linux-arm64-musl" "4.1.7" - "@tailwindcss/oxide-linux-x64-gnu" "4.1.7" - "@tailwindcss/oxide-linux-x64-musl" "4.1.7" - "@tailwindcss/oxide-wasm32-wasi" "4.1.7" - "@tailwindcss/oxide-win32-arm64-msvc" "4.1.7" - "@tailwindcss/oxide-win32-x64-msvc" "4.1.7" - -"@tailwindcss/vite@^4.1.4": - version "4.1.7" - resolved "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.7.tgz#73fb55d2341982fb920f916e1ef6781099cf2df6" - integrity sha512-tYa2fO3zDe41I7WqijyVbRd8oWT0aEID1Eokz5hMT6wShLIHj3yvwj9XbfuloHP9glZ6H+aG2AN/+ZrxJ1Y5RQ== - dependencies: - "@tailwindcss/node" "4.1.7" - "@tailwindcss/oxide" "4.1.7" - tailwindcss "4.1.7" - -"@tybys/wasm-util@^0.9.0": - version "0.9.0" - resolved "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" - integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== - dependencies: - tslib "^2.4.0" - -"@types/estree@1.0.7": - version "1.0.7" - resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" - integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== - -"@types/node@^20": - version "20.17.50" - resolved "https://registry.npmjs.org/@types/node/-/node-20.17.50.tgz#d2640af991fc839ba746f799516fc6a4e47ebe50" - integrity sha512-Mxiq0ULv/zo1OzOhwPqOA13I81CV/W3nvd3ChtQZRT5Cwz3cr0FKo/wMSsbTqL3EXpaBAEQhva2B8ByRkOIh9A== - dependencies: - undici-types "~6.19.2" - -"@types/react-dom@^19.1.2": - version "19.1.5" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.5.tgz#cdfe2c663742887372f54804b16e8dbc26bd794a" - integrity sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg== - -"@types/react@^19.1.2": - version "19.1.5" - resolved "https://registry.npmjs.org/@types/react/-/react-19.1.5.tgz#9feb3bdeb506d0c79d8533b6ebdcacdbcb4756db" - integrity sha512-piErsCVVbpMMT2r7wbawdZsq4xMvIAhQuac2gedQHysu1TZYEigE6pnFfgZT+/jQnrRuF5r+SHzuehFjfRjr4g== - dependencies: - csstype "^3.0.2" - -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" - integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== - -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -arg@^5.0.1: - version "5.0.2" - resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - -babel-dead-code-elimination@^1.0.6: - version "1.0.10" - resolved "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.10.tgz#e230562b57bf72ff3de4639ac763ba54f15d37b0" - integrity sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA== - dependencies: - "@babel/core" "^7.23.7" - "@babel/parser" "^7.23.6" - "@babel/traverse" "^7.23.7" - "@babel/types" "^7.23.6" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -basic-auth@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" - integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== - dependencies: - safe-buffer "5.1.2" - -body-parser@1.20.3: - version "1.20.3" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" - integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== - dependencies: - bytes "3.1.2" - content-type "~1.0.5" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.13.0" - raw-body "2.5.2" - type-is "~1.6.18" - unpipe "1.0.0" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -browserslist@^4.24.0: - version "4.24.5" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz#aa0f5b8560fe81fde84c6dcb38f759bafba0e11b" - integrity sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw== - dependencies: - caniuse-lite "^1.0.30001716" - electron-to-chromium "^1.5.149" - node-releases "^2.0.19" - update-browserslist-db "^1.1.3" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -cac@^6.7.14: - version "6.7.14" - resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" - integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== - -call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" - integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - -call-bound@^1.0.2: - version "1.0.4" - resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" - integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== - dependencies: - call-bind-apply-helpers "^1.0.2" - get-intrinsic "^1.3.0" - -caniuse-lite@^1.0.30001716: - version "1.0.30001718" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz#dae13a9c80d517c30c6197515a96131c194d8f82" - integrity sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw== - -chokidar@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" - integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== - dependencies: - readdirp "^4.0.1" - -chownr@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" - integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -compressible@~2.0.18: - version "2.0.18" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.8.0" - resolved "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz#09420efc96e11a0f44f3a558de59e321364180f7" - integrity sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA== - dependencies: - bytes "3.1.2" - compressible "~2.0.18" - debug "2.6.9" - negotiator "~0.6.4" - on-headers "~1.0.2" - safe-buffer "5.2.1" - vary "~1.1.2" - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4, content-type@~1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.7.1: - version "0.7.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" - integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== - -cookie@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" - integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== - -cross-spawn@^7.0.6: - version "7.0.6" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" - integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -debug@2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.4.0: - version "4.4.1" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" - integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== - dependencies: - ms "^2.1.3" - -dedent@^1.5.3: - version "1.6.0" - resolved "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz#79d52d6389b1ffa67d2bcef59ba51847a9d503b2" - integrity sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA== - -depd@2.0.0, depd@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-libc@^2.0.3, detect-libc@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" - integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== - -dunder-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" - integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-errors "^1.3.0" - gopd "^1.2.0" - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.5.149: - version "1.5.155" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.155.tgz#809dd0ae9ae1db87c358e0c0c17c09a2ffc432d1" - integrity sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -encodeurl@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" - integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== - -enhanced-resolve@^5.18.1: - version "5.18.1" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" - integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -err-code@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== - -es-define-property@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" - integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== - -es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-module-lexer@^1.3.1, es-module-lexer@^1.5.4: - version "1.7.0" - resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" - integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== - -es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== - dependencies: - es-errors "^1.3.0" - -esbuild@^0.25.0: - version "0.25.4" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz#bb9a16334d4ef2c33c7301a924b8b863351a0854" - integrity sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q== - optionalDependencies: - "@esbuild/aix-ppc64" "0.25.4" - "@esbuild/android-arm" "0.25.4" - "@esbuild/android-arm64" "0.25.4" - "@esbuild/android-x64" "0.25.4" - "@esbuild/darwin-arm64" "0.25.4" - "@esbuild/darwin-x64" "0.25.4" - "@esbuild/freebsd-arm64" "0.25.4" - "@esbuild/freebsd-x64" "0.25.4" - "@esbuild/linux-arm" "0.25.4" - "@esbuild/linux-arm64" "0.25.4" - "@esbuild/linux-ia32" "0.25.4" - "@esbuild/linux-loong64" "0.25.4" - "@esbuild/linux-mips64el" "0.25.4" - "@esbuild/linux-ppc64" "0.25.4" - "@esbuild/linux-riscv64" "0.25.4" - "@esbuild/linux-s390x" "0.25.4" - "@esbuild/linux-x64" "0.25.4" - "@esbuild/netbsd-arm64" "0.25.4" - "@esbuild/netbsd-x64" "0.25.4" - "@esbuild/openbsd-arm64" "0.25.4" - "@esbuild/openbsd-x64" "0.25.4" - "@esbuild/sunos-x64" "0.25.4" - "@esbuild/win32-arm64" "0.25.4" - "@esbuild/win32-ia32" "0.25.4" - "@esbuild/win32-x64" "0.25.4" - -escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -exit-hook@2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz#007b2d92c6428eda2b76e7016a34351586934593" - integrity sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw== - -express@^4.19.2: - version "4.21.2" - resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" - integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.3" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.7.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~2.0.0" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.3.1" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.3" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.12" - proxy-addr "~2.0.7" - qs "6.13.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.19.0" - serve-static "1.16.2" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -fdir@^6.4.4: - version "6.4.4" - resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz#1cfcf86f875a883e19a8fab53622cfe992e8d2f9" - integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg== - -finalhandler@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" - integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== - dependencies: - debug "2.6.9" - encodeurl "~2.0.0" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - -foreground-child@^3.1.0: - version "3.3.1" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" - integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== - dependencies: - cross-spawn "^7.0.6" - signal-exit "^4.0.1" - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -fs-extra@^10.0.0: - version "10.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" - integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== - dependencies: - call-bind-apply-helpers "^1.0.2" - es-define-property "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.1.1" - function-bind "^1.1.2" - get-proto "^1.0.1" - gopd "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - math-intrinsics "^1.1.0" - -get-port@5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - -get-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" - integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== - dependencies: - dunder-proto "^1.0.1" - es-object-atoms "^1.0.0" - -glob@^10.2.2: - version "10.4.5" - resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globrex@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" - integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== - -gopd@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" - integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== - -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -has-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" - integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== - -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -hosted-git-info@^6.0.0, hosted-git-info@^6.1.1: - version "6.1.3" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.3.tgz#2ee1a14a097a1236bddf8672c35b613c46c55946" - integrity sha512-HVJyzUrLIL1c0QmviVh5E8VGyUS7xCFPS6yydaVd1UegW+ibV/CohqTH9MkOLDp5o+rb82DMo77PTuc9F/8GKw== - dependencies: - lru-cache "^7.5.1" - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -inherits@2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-core-module@^2.8.1: - version "2.16.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== - dependencies: - hasown "^2.0.2" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -isbot@^5.1.27: - version "5.1.28" - resolved "https://registry.npmjs.org/isbot/-/isbot-5.1.28.tgz#a9a32e70c890cf19b76090971b1fccf6021a519b" - integrity sha512-qrOp4g3xj8YNse4biorv6O5ZShwsJM0trsoda4y7j/Su7ZtTTfVXFzbKkpgcSoDrHS8FcTuUwcU04YimZlZOxw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - -jiti@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" - integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - -jsesc@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" - integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== - -json-parse-even-better-errors@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz#b43d35e89c0f3be6b5fbbe9dc6c82467b30c28da" - integrity sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ== - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -lightningcss-darwin-arm64@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae" - integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== - -lightningcss-darwin-x64@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" - integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== - -lightningcss-freebsd-x64@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" - integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== - -lightningcss-linux-arm-gnueabihf@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" - integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== - -lightningcss-linux-arm64-gnu@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" - integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== - -lightningcss-linux-arm64-musl@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" - integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== - -lightningcss-linux-x64-gnu@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" - integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== - -lightningcss-linux-x64-musl@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" - integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== - -lightningcss-win32-arm64-msvc@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" - integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== - -lightningcss-win32-x64-msvc@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" - integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== - -lightningcss@1.30.1: - version "1.30.1" - resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz#78e979c2d595bfcb90d2a8c0eb632fe6c5bfed5d" - integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== - dependencies: - detect-libc "^2.0.3" - optionalDependencies: - lightningcss-darwin-arm64 "1.30.1" - lightningcss-darwin-x64 "1.30.1" - lightningcss-freebsd-x64 "1.30.1" - lightningcss-linux-arm-gnueabihf "1.30.1" - lightningcss-linux-arm64-gnu "1.30.1" - lightningcss-linux-arm64-musl "1.30.1" - lightningcss-linux-x64-gnu "1.30.1" - lightningcss-linux-x64-musl "1.30.1" - lightningcss-win32-arm64-msvc "1.30.1" - lightningcss-win32-x64-msvc "1.30.1" - -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^7.4.4, lru-cache@^7.5.1: - version "7.18.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -magic-string@^0.30.17: - version "0.30.17" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" - integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.5.0" - -math-intrinsics@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" - integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -merge-descriptors@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -"mime-db@>= 1.43.0 < 2": - version "1.54.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" - integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== - -mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - -minizlib@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz#f33d638eb279f664439aa38dc5f91607468cb574" - integrity sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== - dependencies: - minipass "^7.1.2" - -mkdirp@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" - integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== - -morgan@^1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" - integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== - dependencies: - basic-auth "~2.0.1" - debug "2.6.9" - depd "~2.0.0" - on-finished "~2.3.0" - on-headers "~1.0.2" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.3, ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@^3.3.8: - version "3.3.11" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" - integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -negotiator@~0.6.4: - version "0.6.4" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" - integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== - -node-releases@^2.0.19: - version "2.0.19" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" - integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== - -normalize-package-data@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz#abcb8d7e724c40d88462b84982f7cbf6859b4588" - integrity sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q== - dependencies: - hosted-git-info "^6.0.0" - is-core-module "^2.8.1" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - -npm-install-checks@^6.0.0: - version "6.3.0" - resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" - integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== - dependencies: - semver "^7.1.1" - -npm-normalize-package-bin@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" - integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== - -npm-package-arg@^10.0.0: - version "10.1.0" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz#827d1260a683806685d17193073cc152d3c7e9b1" - integrity sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA== - dependencies: - hosted-git-info "^6.0.0" - proc-log "^3.0.0" - semver "^7.3.5" - validate-npm-package-name "^5.0.0" - -npm-pick-manifest@^8.0.0: - version "8.0.2" - resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz#2159778d9c7360420c925c1a2287b5a884c713aa" - integrity sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg== - dependencies: - npm-install-checks "^6.0.0" - npm-normalize-package-bin "^3.0.0" - npm-package-arg "^10.0.0" - semver "^7.3.5" - -object-inspect@^1.13.3: - version "1.13.4" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" - integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -package-json-from-dist@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" - integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - -path-to-regexp@0.1.12: - version "0.1.12" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" - integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== - -pathe@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" - integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== - -picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - -picomatch@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" - integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== - -postcss@^8.5.3: - version "8.5.3" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" - integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== - dependencies: - nanoid "^3.3.8" - picocolors "^1.1.1" - source-map-js "^1.2.1" - -prettier@^2.7.1: - version "2.8.8" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - -proc-log@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" - integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== - -promise-retry@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" - integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== - dependencies: - err-code "^2.0.2" - retry "^0.12.0" - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -qs@6.13.0: - version "6.13.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== - dependencies: - side-channel "^1.0.6" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-dom@^19.1.0: - version "19.1.0" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" - integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== - dependencies: - scheduler "^0.26.0" - -react-refresh@^0.14.0: - version "0.14.2" - resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" - integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== - -react-router@^7.5.3: - version "7.6.0" - resolved "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz#e2d0872d7bea8df79465a8bba9a20c87c32ce995" - integrity sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ== - dependencies: - cookie "^1.0.1" - set-cookie-parser "^2.6.0" - -react@^19.1.0: - version "19.1.0" - resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" - integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== - -readdirp@^4.0.1: - version "4.1.2" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" - integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== - -rollup@^4.34.9: - version "4.41.0" - resolved "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz#17476835d2967759e3ffebe5823ed15fc4b7d13e" - integrity sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg== - dependencies: - "@types/estree" "1.0.7" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.41.0" - "@rollup/rollup-android-arm64" "4.41.0" - "@rollup/rollup-darwin-arm64" "4.41.0" - "@rollup/rollup-darwin-x64" "4.41.0" - "@rollup/rollup-freebsd-arm64" "4.41.0" - "@rollup/rollup-freebsd-x64" "4.41.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.41.0" - "@rollup/rollup-linux-arm-musleabihf" "4.41.0" - "@rollup/rollup-linux-arm64-gnu" "4.41.0" - "@rollup/rollup-linux-arm64-musl" "4.41.0" - "@rollup/rollup-linux-loongarch64-gnu" "4.41.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.41.0" - "@rollup/rollup-linux-riscv64-gnu" "4.41.0" - "@rollup/rollup-linux-riscv64-musl" "4.41.0" - "@rollup/rollup-linux-s390x-gnu" "4.41.0" - "@rollup/rollup-linux-x64-gnu" "4.41.0" - "@rollup/rollup-linux-x64-musl" "4.41.0" - "@rollup/rollup-win32-arm64-msvc" "4.41.0" - "@rollup/rollup-win32-ia32-msvc" "4.41.0" - "@rollup/rollup-win32-x64-msvc" "4.41.0" - fsevents "~2.3.2" - -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -scheduler@^0.26.0: - version "0.26.0" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" - integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3: - version "7.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -send@0.19.0: - version "0.19.0" - resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serve-static@1.16.2: - version "1.16.2" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== - dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" - -set-cookie-parser@^2.6.0: - version "2.7.1" - resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" - integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -side-channel-list@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" - integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - -side-channel-map@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" - integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - -side-channel-weakmap@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" - integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - side-channel-map "^1.0.1" - -side-channel@^1.0.6: - version "1.1.0" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" - integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - side-channel-list "^1.0.0" - side-channel-map "^1.0.1" - side-channel-weakmap "^1.0.2" - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -source-map-js@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" - integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== - -source-map-support@^0.5.21: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.5.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" - integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.21" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz#6d6e980c9df2b6fc905343a3b2d702a6239536c3" - integrity sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg== - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -stream-slice@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b" - integrity sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA== - -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: - version "4.2.3" - resolved "https://registry.npmjs.org/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@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -tailwindcss@4.1.7, tailwindcss@^4.1.4: - version "4.1.7" - resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz#949f76d50667946ddd7291e0c7a4b5a7dfc9e765" - integrity sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg== - -tapable@^2.2.0: - version "2.2.2" - resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz#ab4984340d30cb9989a490032f086dbb8b56d872" - integrity sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== - -tar@^7.4.3: - version "7.4.3" - resolved "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" - integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== - dependencies: - "@isaacs/fs-minipass" "^4.0.0" - chownr "^3.0.0" - minipass "^7.1.2" - minizlib "^3.0.1" - mkdirp "^3.0.1" - yallist "^5.0.0" - -tinyglobby@^0.2.13: - version "0.2.13" - resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz#a0e46515ce6cbcd65331537e57484af5a7b2ff7e" - integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw== - dependencies: - fdir "^6.4.4" - picomatch "^4.0.2" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -tsconfck@^3.0.3: - version "3.1.6" - resolved "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz#da1f0b10d82237ac23422374b3fce1edb23c3ead" - integrity sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w== - -tslib@^2.4.0, tslib@^2.8.0: - version "2.8.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typescript@^5.8.3: - version "5.8.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" - integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== - -undici-types@~6.19.2: - version "6.19.8" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== - -undici@^6.19.2: - version "6.21.3" - resolved "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz#185752ad92c3d0efe7a7d1f6854a50f83b552d7a" - integrity sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw== - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -update-browserslist-db@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" - integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.1" - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -valibot@^0.41.0: - version "0.41.0" - resolved "https://registry.npmjs.org/valibot/-/valibot-0.41.0.tgz#5c2efd49c078e455f7862379365f6036f3cd9f96" - integrity sha512-igDBb8CTYr8YTQlOKgaN9nSS0Be7z+WRuaeYqGf3Cjz3aKmSnqEmYnkfVjzIuumGqfHpa3fLIvMEAfhrpqN8ng== - -validate-npm-package-license@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validate-npm-package-name@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" - integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -vite-node@3.0.0-beta.2: - version "3.0.0-beta.2" - resolved "https://registry.npmjs.org/vite-node/-/vite-node-3.0.0-beta.2.tgz#4208a6be384f9e7bba97570114d662ce9c957dc1" - integrity sha512-ofTf6cfRdL30Wbl9n/BX81EyIR5s4PReLmSurrxQ+koLaWUNOEo8E0lCM53OJkb8vpa2URM2nSrxZsIFyvY1rg== - dependencies: - cac "^6.7.14" - debug "^4.4.0" - es-module-lexer "^1.5.4" - pathe "^1.1.2" - vite "^5.0.0 || ^6.0.0" - -vite-tsconfig-paths@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz#d9a71106a7ff2c1c840c6f1708042f76a9212ed4" - integrity sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w== - dependencies: - debug "^4.1.1" - globrex "^0.1.2" - tsconfck "^3.0.3" - -"vite@^5.0.0 || ^6.0.0", vite@^6.3.3: - version "6.3.5" - resolved "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz#fec73879013c9c0128c8d284504c6d19410d12a3" - integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ== - dependencies: - esbuild "^0.25.0" - fdir "^6.4.4" - picomatch "^4.0.2" - postcss "^8.5.3" - rollup "^4.34.9" - tinyglobby "^0.2.13" - optionalDependencies: - fsevents "~2.3.3" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -which@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/which/-/which-3.0.1.tgz#89f1cd0c23f629a8105ffe69b8172791c87b4be1" - integrity sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg== - dependencies: - isexe "^2.0.0" - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/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@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" - integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== diff --git a/dev-packages/e2e-tests/test-applications/solid-solidrouter/tests/errorboundary.test.ts b/dev-packages/e2e-tests/test-applications/solid-solidrouter/tests/errorboundary.test.ts index 287642424850..14396feb2334 100644 --- a/dev-packages/e2e-tests/test-applications/solid-solidrouter/tests/errorboundary.test.ts +++ b/dev-packages/e2e-tests/test-applications/solid-solidrouter/tests/errorboundary.test.ts @@ -15,7 +15,7 @@ test('captures an exception', async ({ page }) => { type: 'ReferenceError', value: 'NonExistentComponent is not defined', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -39,7 +39,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'ReferenceError', value: 'NonExistentComponent is not defined', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -64,7 +64,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'ReferenceError', value: 'NonExistentComponent is not defined', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solid/tests/errorboundary.test.ts b/dev-packages/e2e-tests/test-applications/solid/tests/errorboundary.test.ts index d192ed9cfcfd..896426e1765c 100644 --- a/dev-packages/e2e-tests/test-applications/solid/tests/errorboundary.test.ts +++ b/dev-packages/e2e-tests/test-applications/solid/tests/errorboundary.test.ts @@ -22,7 +22,7 @@ test('captures an exception', async ({ page }) => { type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -53,7 +53,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -82,7 +82,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 2 thrown from Sentry ErrorBoundary in Solid E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errorboundary.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errorboundary.test.ts index 599b5c121455..63b46a5870ec 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errorboundary.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errorboundary.test.ts @@ -23,7 +23,7 @@ test('captures an exception', async ({ page }) => { type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -53,7 +53,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -81,7 +81,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 2 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errors.server.test.ts index 7ef5cd0e07de..72761a94fdbc 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/errors.server.test.ts @@ -18,7 +18,7 @@ test.describe('server-side errors', () => { type: 'Error', value: 'Error thrown from Solid Start E2E test app server route', mechanism: { - type: 'solidstart', + type: 'auto.function.solidstart', handled: false, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errorboundary.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errorboundary.test.ts index 692e19f54393..4cf6eccd4b71 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errorboundary.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errorboundary.test.ts @@ -21,7 +21,7 @@ test('captures an exception', async ({ page }) => { type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -51,7 +51,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -79,7 +79,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 2 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errors.server.test.ts index be5c635fdd9e..0ccbbd61e2ae 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/errors.server.test.ts @@ -18,7 +18,7 @@ test.describe('server-side errors', () => { type: 'Error', value: 'Error thrown from Solid Start E2E test app server route', mechanism: { - type: 'solidstart', + type: 'auto.function.solidstart', handled: false, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errorboundary.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errorboundary.test.ts index 49f50f882b50..a362fc76de84 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errorboundary.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errorboundary.test.ts @@ -21,7 +21,7 @@ test('captures an exception', async ({ page }) => { type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -51,7 +51,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -79,7 +79,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 2 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errors.server.test.ts index 682dd34e10f9..5d866efffe0e 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/errors.server.test.ts @@ -18,7 +18,7 @@ test.describe('server-side errors', () => { type: 'Error', value: 'Error thrown from Solid Start E2E test app server route', mechanism: { - type: 'solidstart', + type: 'auto.function.solidstart', handled: false, }, }, 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 b709760aab94..9b169d6abda4 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 @@ -21,7 +21,7 @@ test('captures an exception', async ({ page }) => { type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -51,7 +51,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 1 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, @@ -79,7 +79,7 @@ test('captures a second exception after resetting the boundary', async ({ page } type: 'Error', value: 'Error 2 thrown from Sentry ErrorBoundary in Solid Start E2E test app', mechanism: { - type: 'generic', + type: 'auto.function.solid.error_boundary', handled: true, }, }, diff --git a/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.server.test.ts index ccd0a802fbb2..7bf86b364da9 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart/tests/errors.server.test.ts @@ -18,7 +18,7 @@ test.describe('server-side errors', () => { type: 'Error', value: 'Error thrown from Solid Start E2E test app server route', mechanism: { - type: 'solidstart', + type: 'auto.function.solidstart', handled: false, }, }, diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json index 03e5441733da..2b6184b8cb28 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json @@ -22,7 +22,7 @@ "@playwright/test": "~1.53.2", "@sentry-internal/test-utils": "link:../../../test-utils", "@sveltejs/adapter-node": "^5.3.1", - "@sveltejs/kit": "^2.31.0", + "@sveltejs/kit": "2.31.0", "@sveltejs/vite-plugin-svelte": "^6.1.3", "svelte": "^5.38.3", "svelte-check": "^4.3.1", diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json index 689934c1011f..3c5dcfd8f279 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json @@ -22,7 +22,7 @@ "@playwright/test": "~1.53.2", "@sentry-internal/test-utils": "link:../../../test-utils", "@sveltejs/adapter-auto": "^3.0.0", - "@sveltejs/kit": "^2.21.3", + "@sveltejs/kit": "2.41.0", "@sveltejs/vite-plugin-svelte": "^3.0.0", "svelte": "^5.0.0-next.115", "svelte-check": "^3.6.0", diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/tests/performance.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/tests/performance.test.ts index 95855d8f8e81..6a29276f4dc8 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/tests/performance.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/tests/performance.test.ts @@ -316,7 +316,7 @@ test.describe('performance events', () => { 'sentry.origin': 'auto.navigation.sveltekit', 'sentry.op': 'navigation', 'sentry.source': 'route', - 'sentry.sveltekit.navigation.type': 'goto', + 'sentry.sveltekit.navigation.type': 'link', 'sentry.sveltekit.navigation.from': '/', 'sentry.sveltekit.navigation.to': '/redirect2', 'sentry.sample_rate': 1, @@ -337,7 +337,7 @@ test.describe('performance events', () => { 'sentry.origin': 'auto.ui.sveltekit', 'sentry.sveltekit.navigation.from': '/', 'sentry.sveltekit.navigation.to': '/redirect2', - 'sentry.sveltekit.navigation.type': 'goto', + 'sentry.sveltekit.navigation.type': 'link', }, }); @@ -353,7 +353,7 @@ test.describe('performance events', () => { 'sentry.origin': 'auto.navigation.sveltekit', 'sentry.op': 'navigation', 'sentry.source': 'route', - 'sentry.sveltekit.navigation.type': 'goto', + 'sentry.sveltekit.navigation.type': 'link', 'sentry.sveltekit.navigation.from': '/', 'sentry.sveltekit.navigation.to': '/users/[id]', 'sentry.sample_rate': 1, @@ -374,7 +374,7 @@ test.describe('performance events', () => { 'sentry.origin': 'auto.ui.sveltekit', 'sentry.sveltekit.navigation.from': '/', 'sentry.sveltekit.navigation.to': '/users/[id]', - 'sentry.sveltekit.navigation.type': 'goto', + 'sentry.sveltekit.navigation.type': 'link', }, }); }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json index 03b4b1dad959..1f73b47bc10b 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json @@ -22,7 +22,7 @@ "@sentry-internal/test-utils": "link:../../../test-utils", "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-node": "^2.0.0", - "@sveltejs/kit": "^2.21.3", + "@sveltejs/kit": "2.21.3", "@sveltejs/vite-plugin-svelte": "^3.0.0", "svelte": "^4.2.8", "svelte-check": "^3.6.0", diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/tests/errors.server.test.ts index fd2e58e9c2a3..0d78c9c7d649 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/tests/errors.server.test.ts @@ -73,9 +73,7 @@ test.describe('server-side errors', () => { value: "'HttpError' captured as exception with keys: body, status", mechanism: { handled: false, - data: { - function: 'serverRoute', - }, + type: 'auto.function.sveltekit.server_route', }, stacktrace: { frames: expect.any(Array) }, }, diff --git a/dev-packages/e2e-tests/test-applications/vue-3/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/vue-3/tests/errors.test.ts index b86e56eb4b83..118476aeb485 100644 --- a/dev-packages/e2e-tests/test-applications/vue-3/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/vue-3/tests/errors.test.ts @@ -19,7 +19,7 @@ test('sends an error', async ({ page }) => { type: 'Error', value: 'This is a Vue test error', mechanism: { - type: 'vue', + type: 'auto.function.vue.error_handler', handled: false, }, }, @@ -47,7 +47,7 @@ test('sends an error with a parameterized transaction name', async ({ page }) => type: 'Error', value: 'This is a Vue test error', mechanism: { - type: 'vue', + type: 'auto.function.vue.error_handler', handled: false, }, }, diff --git a/dev-packages/node-core-integration-tests/package.json b/dev-packages/node-core-integration-tests/package.json index 7ea4dc2b31ed..62a2e9cc91ab 100644 --- a/dev-packages/node-core-integration-tests/package.json +++ b/dev-packages/node-core-integration-tests/package.json @@ -27,13 +27,13 @@ "@nestjs/core": "10.4.6", "@nestjs/platform-express": "10.4.6", "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/instrumentation-http": "0.203.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-http": "0.204.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@sentry/core": "10.11.0", "@sentry/node-core": "10.11.0", "body-parser": "^1.20.3", diff --git a/dev-packages/node-core-integration-tests/suites/child-process/test.ts b/dev-packages/node-core-integration-tests/suites/child-process/test.ts index 798cd48d86d0..1d04772c351e 100644 --- a/dev-packages/node-core-integration-tests/suites/child-process/test.ts +++ b/dev-packages/node-core-integration-tests/suites/child-process/test.ts @@ -10,7 +10,7 @@ const WORKER_EVENT: Event = { type: 'Error', value: 'Test error', mechanism: { - type: 'instrument', + type: 'auto.child_process.worker_thread', handled: false, data: { threadId: expect.any(String), diff --git a/dev-packages/node-core-integration-tests/suites/cron/cron/test.ts b/dev-packages/node-core-integration-tests/suites/cron/cron/test.ts index 8b9fdfd5c593..c7d0ca5239fc 100644 --- a/dev-packages/node-core-integration-tests/suites/cron/cron/test.ts +++ b/dev-packages/node-core-integration-tests/suites/cron/cron/test.ts @@ -69,7 +69,15 @@ test('cron instrumentation', async () => { }) .expect({ event: { - exception: { values: [{ type: 'Error', value: 'Error in cron job' }] }, + exception: { + values: [ + { + type: 'Error', + value: 'Error in cron job', + mechanism: { type: 'auto.function.cron.instrumentCron', handled: false }, + }, + ], + }, }, }) .start() diff --git a/dev-packages/node-core-integration-tests/suites/cron/node-cron/test.ts b/dev-packages/node-core-integration-tests/suites/cron/node-cron/test.ts index 1c5fa515e208..fb3e7bacbf45 100644 --- a/dev-packages/node-core-integration-tests/suites/cron/node-cron/test.ts +++ b/dev-packages/node-core-integration-tests/suites/cron/node-cron/test.ts @@ -69,7 +69,15 @@ test('node-cron instrumentation', async () => { }) .expect({ event: { - exception: { values: [{ type: 'Error', value: 'Error in cron job' }] }, + exception: { + values: [ + { + type: 'Error', + value: 'Error in cron job', + mechanism: { type: 'auto.function.node-cron.instrumentNodeCron', handled: false }, + }, + ], + }, }, }) .start() diff --git a/dev-packages/node-core-integration-tests/suites/cron/node-schedule/test.ts b/dev-packages/node-core-integration-tests/suites/cron/node-schedule/test.ts index a2019253203f..285e41cee304 100644 --- a/dev-packages/node-core-integration-tests/suites/cron/node-schedule/test.ts +++ b/dev-packages/node-core-integration-tests/suites/cron/node-schedule/test.ts @@ -69,7 +69,15 @@ test('node-schedule instrumentation', async () => { }) .expect({ event: { - exception: { values: [{ type: 'Error', value: 'Error in cron job' }] }, + exception: { + values: [ + { + type: 'Error', + value: 'Error in cron job', + mechanism: { type: 'auto.node.onunhandledrejection', handled: false }, + }, + ], + }, }, }) .start() diff --git a/dev-packages/node-core-integration-tests/suites/public-api/OnUncaughtException/basic.js b/dev-packages/node-core-integration-tests/suites/public-api/OnUncaughtException/basic.js new file mode 100644 index 000000000000..656a5b19220b --- /dev/null +++ b/dev-packages/node-core-integration-tests/suites/public-api/OnUncaughtException/basic.js @@ -0,0 +1,9 @@ +const Sentry = require('@sentry/node'); +const { loggingTransport } = require('@sentry-internal/node-integration-tests'); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + transport: loggingTransport, +}); + +throw new Error('foo'); diff --git a/dev-packages/node-core-integration-tests/suites/public-api/OnUncaughtException/test.ts b/dev-packages/node-core-integration-tests/suites/public-api/OnUncaughtException/test.ts index d27b08f152be..5a35991bfd4b 100644 --- a/dev-packages/node-core-integration-tests/suites/public-api/OnUncaughtException/test.ts +++ b/dev-packages/node-core-integration-tests/suites/public-api/OnUncaughtException/test.ts @@ -1,6 +1,7 @@ import * as childProcess from 'child_process'; import * as path from 'path'; import { describe, expect, test } from 'vitest'; +import { createRunner } from '../../../utils/runner'; describe('OnUncaughtException integration', () => { test('should close process on uncaught error with no additional listeners registered', () => @@ -74,4 +75,30 @@ describe('OnUncaughtException integration', () => { }); })); }); + + test('sets correct event mechanism', async () => { + await createRunner(__dirname, 'basic.js') + .expect({ + event: { + level: 'fatal', + exception: { + values: [ + { + type: 'Error', + value: 'foo', + mechanism: { + type: 'auto.node.onuncaughtexception', + handled: false, + }, + stacktrace: { + frames: expect.any(Array), + }, + }, + ], + }, + }, + }) + .start() + .completed(); + }); }); diff --git a/dev-packages/node-core-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts b/dev-packages/node-core-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts index 2f4a22c835a4..8ee873a4f017 100644 --- a/dev-packages/node-core-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts +++ b/dev-packages/node-core-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts @@ -83,7 +83,7 @@ test rejection`); type: 'Error', value: 'test rejection', mechanism: { - type: 'onunhandledrejection', + type: 'auto.node.onunhandledrejection', handled: false, }, stacktrace: { @@ -109,7 +109,7 @@ test rejection`); type: 'Error', value: 'test rejection', mechanism: { - type: 'onunhandledrejection', + type: 'auto.node.onunhandledrejection', handled: false, }, stacktrace: { diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index 5f5c80094fc5..799338890030 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -39,6 +39,7 @@ "apollo-server": "^3.11.1", "body-parser": "^1.20.3", "connect": "^3.7.0", + "consola": "^3.2.3", "cors": "^2.8.5", "cron": "^3.1.6", "dataloader": "2.2.2", @@ -61,6 +62,8 @@ "openai": "5.18.1", "pg": "8.16.0", "postgres": "^3.4.7", + "@prisma/client": "6.15.0", + "prisma": "6.15.0", "proxy": "^2.1.1", "redis-4": "npm:redis@^4.6.14", "reflect-metadata": "0.2.1", diff --git a/dev-packages/node-integration-tests/suites/child-process/test.ts b/dev-packages/node-integration-tests/suites/child-process/test.ts index 798cd48d86d0..1d04772c351e 100644 --- a/dev-packages/node-integration-tests/suites/child-process/test.ts +++ b/dev-packages/node-integration-tests/suites/child-process/test.ts @@ -10,7 +10,7 @@ const WORKER_EVENT: Event = { type: 'Error', value: 'Test error', mechanism: { - type: 'instrument', + type: 'auto.child_process.worker_thread', handled: false, data: { threadId: expect.any(String), diff --git a/dev-packages/node-integration-tests/suites/consola/subject-args.ts b/dev-packages/node-integration-tests/suites/consola/subject-args.ts new file mode 100644 index 000000000000..11b39d1588cb --- /dev/null +++ b/dev-packages/node-integration-tests/suites/consola/subject-args.ts @@ -0,0 +1,37 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import { consola } from 'consola'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0.0', + environment: 'test', + enableLogs: true, + transport: loggingTransport, +}); + +async function run(): Promise { + // Set consola level to capture all logs including debug and trace + consola.level = 5; + + // Create a Sentry reporter for consola + const sentryReporter = Sentry.createConsolaReporter(); + + // Add the reporter to consola + consola.addReporter(sentryReporter); + + // Test with arguments formatting + consola.info('Message with args:', 'hello', 123, { key: 'value' }, [1, 2, 3]); + consola.log({ + type: 'debug', + message: 'Debug message', + userId: 12345, + sessionId: 'abc-123-def', + customData: { nested: 'value', count: 42 }, + }); + + await Sentry.flush(); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +void run(); diff --git a/dev-packages/node-integration-tests/suites/consola/subject-custom-levels.ts b/dev-packages/node-integration-tests/suites/consola/subject-custom-levels.ts new file mode 100644 index 000000000000..3f3690f7d110 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/consola/subject-custom-levels.ts @@ -0,0 +1,30 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import { consola } from 'consola'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0.0', + environment: 'test', + enableLogs: true, + transport: loggingTransport, +}); + +async function run(): Promise { + // Test custom levels filtering + const customReporter = Sentry.createConsolaReporter({ + levels: ['error', 'warn'], // Only capture errors and warnings + }); + + // Add the custom reporter to consola + consola.addReporter(customReporter); + + consola.info('This should not be captured'); + consola.warn('This should be captured'); + consola.error('This should also be captured'); + + await Sentry.flush(); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +void run(); diff --git a/dev-packages/node-integration-tests/suites/consola/subject-levels.ts b/dev-packages/node-integration-tests/suites/consola/subject-levels.ts new file mode 100644 index 000000000000..02052febfb65 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/consola/subject-levels.ts @@ -0,0 +1,32 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import { consola } from 'consola'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0.0', + environment: 'test', + enableLogs: true, + transport: loggingTransport, +}); + +async function run(): Promise { + // Set consola level to capture all logs including debug and trace + consola.level = 5; + + // Create a Sentry reporter for consola + const sentryReporter = Sentry.createConsolaReporter(); + + // Add the reporter to consola + consola.addReporter(sentryReporter); + + // Test level-based logging - test some basic level mappings by using different log methods + consola.fatal('Fatal level message'); + consola.warn('Warning level message'); + consola.info('Info level message'); + + await Sentry.flush(); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +void run(); diff --git a/dev-packages/node-integration-tests/suites/consola/subject-tags.ts b/dev-packages/node-integration-tests/suites/consola/subject-tags.ts new file mode 100644 index 000000000000..ca458a68a068 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/consola/subject-tags.ts @@ -0,0 +1,32 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import { consola } from 'consola'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0.0', + environment: 'test', + enableLogs: true, + transport: loggingTransport, +}); + +async function run(): Promise { + // Set consola level to capture all logs including debug and trace + consola.level = 5; + + // Create a Sentry reporter for consola + const sentryReporter = Sentry.createConsolaReporter(); + + // Add the reporter to consola + consola.addReporter(sentryReporter); + + // Test with scoped logger (tags) + const taggedLogger = consola.withTag('api'); + taggedLogger.info('Tagged info message'); + taggedLogger.error('Tagged error message'); + + await Sentry.flush(); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +void run(); diff --git a/dev-packages/node-integration-tests/suites/consola/subject-types.ts b/dev-packages/node-integration-tests/suites/consola/subject-types.ts new file mode 100644 index 000000000000..fc63c38cf614 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/consola/subject-types.ts @@ -0,0 +1,42 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import { consola } from 'consola'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0.0', + environment: 'test', + enableLogs: true, + transport: loggingTransport, +}); + +async function run(): Promise { + // Set consola level to capture all logs including debug, trace, and verbose + consola.level = Number.POSITIVE_INFINITY; + + // Create a Sentry reporter for consola + const sentryReporter = Sentry.createConsolaReporter(); + + // Add the reporter to consola + consola.addReporter(sentryReporter); + + // Test basic logging with different types + consola.info('Test info message'); + consola.error('Test error message'); + consola.warn('Test warn message'); + + // Test different consola log types + consola.success('Test success message'); + consola.fail('Test fail message'); + consola.ready('Test ready message'); + consola.start('Test start message'); + consola.box('Test box message'); + consola.verbose('Test verbose message'); + consola.debug('Test debug message'); + consola.trace('Test trace message'); + + await Sentry.flush(); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +void run(); diff --git a/dev-packages/node-integration-tests/suites/consola/subject.ts b/dev-packages/node-integration-tests/suites/consola/subject.ts new file mode 100644 index 000000000000..834aac57d993 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/consola/subject.ts @@ -0,0 +1,32 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import { consola } from 'consola'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0.0', + environment: 'test', + enableLogs: true, + transport: loggingTransport, +}); + +async function run(): Promise { + // Set consola level to capture all logs including debug and trace + consola.level = 5; + + // Create a Sentry reporter for consola + const sentryReporter = Sentry.createConsolaReporter(); + + // Add the reporter to consola + consola.addReporter(sentryReporter); + + // Test basic logging with different types + consola.info('Test info message'); + consola.error('Test error message'); + consola.warn('Test warn message'); + + await Sentry.flush(); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +void run(); diff --git a/dev-packages/node-integration-tests/suites/consola/test.ts b/dev-packages/node-integration-tests/suites/consola/test.ts new file mode 100644 index 000000000000..cf396e319c51 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/consola/test.ts @@ -0,0 +1,494 @@ +import { afterAll, describe, expect, test } from 'vitest'; +import { cleanupChildProcesses, createRunner } from '../../utils/runner'; + +describe('consola integration', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + test('should capture consola logs with default levels', async () => { + const runner = createRunner(__dirname, 'subject.ts') + .expect({ + log: { + items: [ + { + timestamp: expect.any(Number), + level: 'info', + body: 'Test info message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'info', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'error', + body: 'Test error message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'error', type: 'string' }, + 'consola.level': { value: 0, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'warn', + body: 'Test warn message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'warn', type: 'string' }, + 'consola.level': { value: 1, type: 'integer' }, + }, + }, + ], + }, + }) + .start(); + + await runner.completed(); + }); + + test('should capture different consola log types', async () => { + const runner = createRunner(__dirname, 'subject-types.ts') + .expect({ + log: { + items: [ + // Basic logs from default test + { + timestamp: expect.any(Number), + level: 'info', + body: 'Test info message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'info', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'error', + body: 'Test error message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'error', type: 'string' }, + 'consola.level': { value: 0, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'warn', + body: 'Test warn message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'warn', type: 'string' }, + 'consola.level': { value: 1, type: 'integer' }, + }, + }, + // Consola-specific log types + { + timestamp: expect.any(Number), + level: 'info', + body: 'Test success message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'success', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'error', + body: 'Test fail message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'fail', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'info', + body: 'Test ready message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'ready', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'info', + body: 'Test start message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'start', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'info', + body: 'Test box message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'box', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'debug', + body: 'Test verbose message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'verbose', type: 'string' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'debug', + body: 'Test debug message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'debug', type: 'string' }, + 'consola.level': { value: 4, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'trace', + body: 'Test trace message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'trace', type: 'string' }, + 'consola.level': { value: 5, type: 'integer' }, + }, + }, + ], + }, + }) + .start(); + + await runner.completed(); + }); + + test('should capture consola logs with arguments formatting', async () => { + const runner = createRunner(__dirname, 'subject-args.ts') + .expect({ + log: { + items: [ + { + timestamp: expect.any(Number), + level: 'info', + body: 'Message with args: hello 123 {"key":"value"} [1,2,3]', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'info', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'debug', + body: 'Debug message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'debug', type: 'string' }, + 'consola.level': { value: 2, type: 'integer' }, + customData: { + value: '{"nested":"value","count":42}', + type: 'string', + }, + sessionId: { + value: 'abc-123-def', + type: 'string', + }, + userId: { + value: 12345, + type: 'integer', + }, + }, + }, + ], + }, + }) + .start(); + + await runner.completed(); + }); + + test('should capture consola logs with tags', async () => { + const runner = createRunner(__dirname, 'subject-tags.ts') + .expect({ + log: { + items: [ + { + timestamp: expect.any(Number), + level: 'info', + body: 'Tagged info message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.tag': { value: 'api', type: 'string' }, + 'consola.type': { value: 'info', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'error', + body: 'Tagged error message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.tag': { value: 'api', type: 'string' }, + 'consola.type': { value: 'error', type: 'string' }, + 'consola.level': { value: 0, type: 'integer' }, + }, + }, + ], + }, + }) + .start(); + + await runner.completed(); + }); + + test('should respect custom level filtering', async () => { + const runner = createRunner(__dirname, 'subject-custom-levels.ts') + .expect({ + log: { + items: [ + // Should capture the warn message + { + timestamp: expect.any(Number), + level: 'warn', + body: 'This should be captured', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'warn', type: 'string' }, + 'consola.level': { value: 1, type: 'integer' }, + }, + }, + // Should capture the error message + { + timestamp: expect.any(Number), + level: 'error', + body: 'This should also be captured', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'error', type: 'string' }, + 'consola.level': { value: 0, type: 'integer' }, + }, + }, + ], + }, + }) + .start(); + + await runner.completed(); + }); + + test('should capture different consola level methods', async () => { + const runner = createRunner(__dirname, 'subject-levels.ts') + .expect({ + log: { + items: [ + { + timestamp: expect.any(Number), + level: 'fatal', + body: 'Fatal level message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'fatal', type: 'string' }, + 'consola.level': { value: 0, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'warn', + body: 'Warning level message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'warn', type: 'string' }, + 'consola.level': { value: 1, type: 'integer' }, + }, + }, + { + timestamp: expect.any(Number), + level: 'info', + body: 'Info level message', + severity_number: expect.any(Number), + trace_id: expect.any(String), + attributes: { + 'sentry.origin': { value: 'auto.logging.consola', type: 'string' }, + 'sentry.release': { value: '1.0.0', type: 'string' }, + 'sentry.environment': { value: 'test', type: 'string' }, + 'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' }, + 'sentry.sdk.version': { value: expect.any(String), type: 'string' }, + 'server.address': { value: expect.any(String), type: 'string' }, + 'consola.type': { value: 'info', type: 'string' }, + 'consola.level': { value: 3, type: 'integer' }, + }, + }, + ], + }, + }) + .start(); + + await runner.completed(); + }); +}); diff --git a/dev-packages/node-integration-tests/suites/express/handle-error-scope-data-loss/test.ts b/dev-packages/node-integration-tests/suites/express/handle-error-scope-data-loss/test.ts index 61291f86320d..cb5d20760c00 100644 --- a/dev-packages/node-integration-tests/suites/express/handle-error-scope-data-loss/test.ts +++ b/dev-packages/node-integration-tests/suites/express/handle-error-scope-data-loss/test.ts @@ -22,7 +22,7 @@ test('withScope scope is NOT applied to thrown error caught by global handler', values: [ { mechanism: { - type: 'middleware', + type: 'auto.middleware.express', handled: false, }, type: 'Error', @@ -61,7 +61,7 @@ test('http requestisolation scope is applied to thrown error caught by global ha values: [ { mechanism: { - type: 'middleware', + type: 'auto.middleware.express', handled: false, }, type: 'Error', @@ -109,7 +109,7 @@ test('withIsolationScope scope is NOT applied to thrown error caught by global h values: [ { mechanism: { - type: 'middleware', + type: 'auto.middleware.express', handled: false, }, type: 'Error', diff --git a/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-0/test.ts b/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-0/test.ts index 1f434ebc0971..b8cc2cf53d34 100644 --- a/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-0/test.ts +++ b/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-0/test.ts @@ -13,7 +13,7 @@ test('should capture and send Express controller error with txn name if tracesSa values: [ { mechanism: { - type: 'middleware', + type: 'auto.middleware.express', handled: false, }, type: 'Error', diff --git a/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-unset/test.ts b/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-unset/test.ts index 4f0dcaae1411..a5f9a1332866 100644 --- a/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-unset/test.ts +++ b/dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-unset/test.ts @@ -14,7 +14,7 @@ test('should capture and send Express controller error if tracesSampleRate is no values: [ { mechanism: { - type: 'middleware', + type: 'auto.middleware.express', handled: false, }, type: 'Error', diff --git a/dev-packages/node-integration-tests/suites/express/handle-error/test.ts b/dev-packages/node-integration-tests/suites/express/handle-error/test.ts index 0db624160959..4e702360242f 100644 --- a/dev-packages/node-integration-tests/suites/express/handle-error/test.ts +++ b/dev-packages/node-integration-tests/suites/express/handle-error/test.ts @@ -18,7 +18,7 @@ test('should capture and send Express controller error with txn name if tracesSa values: [ { mechanism: { - type: 'middleware', + type: 'auto.middleware.express', handled: false, }, type: 'Error', diff --git a/dev-packages/node-integration-tests/suites/public-api/OnUncaughtException/basic.js b/dev-packages/node-integration-tests/suites/public-api/OnUncaughtException/basic.js new file mode 100644 index 000000000000..656a5b19220b --- /dev/null +++ b/dev-packages/node-integration-tests/suites/public-api/OnUncaughtException/basic.js @@ -0,0 +1,9 @@ +const Sentry = require('@sentry/node'); +const { loggingTransport } = require('@sentry-internal/node-integration-tests'); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + transport: loggingTransport, +}); + +throw new Error('foo'); diff --git a/dev-packages/node-integration-tests/suites/public-api/OnUncaughtException/test.ts b/dev-packages/node-integration-tests/suites/public-api/OnUncaughtException/test.ts index d27b08f152be..5a35991bfd4b 100644 --- a/dev-packages/node-integration-tests/suites/public-api/OnUncaughtException/test.ts +++ b/dev-packages/node-integration-tests/suites/public-api/OnUncaughtException/test.ts @@ -1,6 +1,7 @@ import * as childProcess from 'child_process'; import * as path from 'path'; import { describe, expect, test } from 'vitest'; +import { createRunner } from '../../../utils/runner'; describe('OnUncaughtException integration', () => { test('should close process on uncaught error with no additional listeners registered', () => @@ -74,4 +75,30 @@ describe('OnUncaughtException integration', () => { }); })); }); + + test('sets correct event mechanism', async () => { + await createRunner(__dirname, 'basic.js') + .expect({ + event: { + level: 'fatal', + exception: { + values: [ + { + type: 'Error', + value: 'foo', + mechanism: { + type: 'auto.node.onuncaughtexception', + handled: false, + }, + stacktrace: { + frames: expect.any(Array), + }, + }, + ], + }, + }, + }) + .start() + .completed(); + }); }); diff --git a/dev-packages/node-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts b/dev-packages/node-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts index 468e66a058ca..d3c8b4d599ff 100644 --- a/dev-packages/node-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts +++ b/dev-packages/node-integration-tests/suites/public-api/onUnhandledRejectionIntegration/test.ts @@ -84,7 +84,7 @@ test rejection`); type: 'Error', value: 'test rejection', mechanism: { - type: 'onunhandledrejection', + type: 'auto.node.onunhandledrejection', handled: false, }, stacktrace: { @@ -110,7 +110,7 @@ test rejection`); type: 'Error', value: 'test rejection', mechanism: { - type: 'onunhandledrejection', + type: 'auto.node.onunhandledrejection', handled: false, }, stacktrace: { diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/docker-compose.yml b/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/docker-compose.yml new file mode 100644 index 000000000000..788311e4e117 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.9' + +services: + db_mysql2: + image: mysql:8 + restart: always + container_name: integration-tests-knex-mysql2 + ports: + - '3307:3306' + environment: + MYSQL_ROOT_PASSWORD: docker + MYSQL_DATABASE: tests diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/instrument-withMysql2.mjs b/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/instrument.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/tracing/knex/instrument-withMysql2.mjs rename to dev-packages/node-integration-tests/suites/tracing/knex/mysql2/instrument.mjs diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.mjs b/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/scenario.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.mjs rename to dev-packages/node-integration-tests/suites/tracing/knex/mysql2/scenario.mjs diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/test.ts b/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/test.ts new file mode 100644 index 000000000000..e8116293de09 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/knex/mysql2/test.ts @@ -0,0 +1,73 @@ +import { describe, expect } from 'vitest'; +import { createEsmAndCjsTests } from '../../../../utils/runner'; + +describe('knex auto instrumentation', () => { + // Update this if another knex version is installed + const KNEX_VERSION = '2.5.1'; + + describe('with `mysql2` client', () => { + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { + test('should auto-instrument `knex` package', { timeout: 60_000 }, async () => { + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, + 'db.system': 'mysql2', + 'db.name': 'tests', + 'db.user': 'root', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 3307, + }), + status: 'ok', + description: + 'create table `User` (`id` int unsigned not null auto_increment primary key, `createdAt` timestamp(3) not null default CURRENT_TIMESTAMP(3), `email` text not null, `name` text not null)', + origin: 'auto.db.otel.knex', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, + 'db.system': 'mysql2', + 'db.name': 'tests', + 'db.user': 'root', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 3307, + }), + status: 'ok', + description: 'insert into `User` (`email`, `name`) values (?, ?)', + origin: 'auto.db.otel.knex', + }), + + expect.objectContaining({ + data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, + 'db.operation': 'select', + 'db.sql.table': 'User', + 'db.system': 'mysql2', + 'db.name': 'tests', + 'db.statement': 'select * from `User`', + 'db.user': 'root', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + }), + status: 'ok', + description: 'select * from `User`', + origin: 'auto.db.otel.knex', + }), + ]), + }; + + await createRunner() + .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port: 3306'] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); + }); +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml b/dev-packages/node-integration-tests/suites/tracing/knex/pg/docker-compose.yml similarity index 55% rename from dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml rename to dev-packages/node-integration-tests/suites/tracing/knex/pg/docker-compose.yml index 50eb7bc94237..e3edcd1d8d7b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml +++ b/dev-packages/node-integration-tests/suites/tracing/knex/pg/docker-compose.yml @@ -11,13 +11,3 @@ services: POSTGRES_USER: test POSTGRES_PASSWORD: test POSTGRES_DB: tests - - db_mysql2: - image: mysql:8 - restart: always - container_name: integration-tests-knex-mysql2 - ports: - - '3307:3306' - environment: - MYSQL_ROOT_PASSWORD: docker - MYSQL_DATABASE: tests diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/instrument-withPg.mjs b/dev-packages/node-integration-tests/suites/tracing/knex/pg/instrument.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/tracing/knex/instrument-withPg.mjs rename to dev-packages/node-integration-tests/suites/tracing/knex/pg/instrument.mjs diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPg.mjs b/dev-packages/node-integration-tests/suites/tracing/knex/pg/scenario.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPg.mjs rename to dev-packages/node-integration-tests/suites/tracing/knex/pg/scenario.mjs diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/pg/test.ts b/dev-packages/node-integration-tests/suites/tracing/knex/pg/test.ts new file mode 100644 index 000000000000..7c38381eb125 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/knex/pg/test.ts @@ -0,0 +1,71 @@ +import { describe, expect } from 'vitest'; +import { createEsmAndCjsTests } from '../../../../utils/runner'; + +describe('knex auto instrumentation', () => { + // Update this if another knex version is installed + const KNEX_VERSION = '2.5.1'; + + describe('with `pg` client', () => { + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { + test('should auto-instrument `knex` package', { timeout: 60_000 }, async () => { + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, + 'db.system': 'postgresql', + 'db.name': 'tests', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 5445, + }), + status: 'ok', + description: + 'create table "User" ("id" serial primary key, "createdAt" timestamptz(3) not null default CURRENT_TIMESTAMP(3), "email" text not null, "name" text not null)', + origin: 'auto.db.otel.knex', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, + 'db.system': 'postgresql', + 'db.name': 'tests', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 5445, + }), + status: 'ok', + // In the knex-otel spans, the placeholders (e.g., `$1`) are replaced by a `?`. + description: 'insert into "User" ("email", "name") values (?, ?)', + origin: 'auto.db.otel.knex', + }), + + expect.objectContaining({ + data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, + 'db.operation': 'select', + 'db.sql.table': 'User', + 'db.system': 'postgresql', + 'db.name': 'tests', + 'db.statement': 'select * from "User"', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + }), + status: 'ok', + description: 'select * from "User"', + origin: 'auto.db.otel.knex', + }), + ]), + }; + + await createRunner() + .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port 5432'] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); + }); +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts deleted file mode 100644 index f60ea76a1c54..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { describe, expect } from 'vitest'; -import { createEsmAndCjsTests } from '../../../utils/runner'; - -describe('knex auto instrumentation', () => { - // Update this if another knex version is installed - const KNEX_VERSION = '2.5.1'; - - describe('with `pg` client', () => { - createEsmAndCjsTests(__dirname, 'scenario-withPg.mjs', 'instrument-withPg.mjs', (createRunner, test) => { - test('should auto-instrument `knex` package', { timeout: 60_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'knex.version': KNEX_VERSION, - 'db.system': 'postgresql', - 'db.name': 'tests', - 'sentry.origin': 'auto.db.otel.knex', - 'sentry.op': 'db', - 'net.peer.name': 'localhost', - 'net.peer.port': 5445, - }), - status: 'ok', - description: - 'create table "User" ("id" serial primary key, "createdAt" timestamptz(3) not null default CURRENT_TIMESTAMP(3), "email" text not null, "name" text not null)', - origin: 'auto.db.otel.knex', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'knex.version': KNEX_VERSION, - 'db.system': 'postgresql', - 'db.name': 'tests', - 'sentry.origin': 'auto.db.otel.knex', - 'sentry.op': 'db', - 'net.peer.name': 'localhost', - 'net.peer.port': 5445, - }), - status: 'ok', - // In the knex-otel spans, the placeholders (e.g., `$1`) are replaced by a `?`. - description: 'insert into "User" ("email", "name") values (?, ?)', - origin: 'auto.db.otel.knex', - }), - - expect.objectContaining({ - data: expect.objectContaining({ - 'knex.version': KNEX_VERSION, - 'db.operation': 'select', - 'db.sql.table': 'User', - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'select * from "User"', - 'sentry.origin': 'auto.db.otel.knex', - 'sentry.op': 'db', - }), - status: 'ok', - description: 'select * from "User"', - origin: 'auto.db.otel.knex', - }), - ]), - }; - - await createRunner() - .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port 5432'] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }); - }); - }); - - describe('with `mysql2` client', () => { - createEsmAndCjsTests(__dirname, 'scenario-withMysql2.mjs', 'instrument-withMysql2.mjs', (createRunner, test) => { - test('should auto-instrument `knex` package', { timeout: 60_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'knex.version': KNEX_VERSION, - 'db.system': 'mysql2', - 'db.name': 'tests', - 'db.user': 'root', - 'sentry.origin': 'auto.db.otel.knex', - 'sentry.op': 'db', - 'net.peer.name': 'localhost', - 'net.peer.port': 3307, - }), - status: 'ok', - description: - 'create table `User` (`id` int unsigned not null auto_increment primary key, `createdAt` timestamp(3) not null default CURRENT_TIMESTAMP(3), `email` text not null, `name` text not null)', - origin: 'auto.db.otel.knex', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'knex.version': KNEX_VERSION, - 'db.system': 'mysql2', - 'db.name': 'tests', - 'db.user': 'root', - 'sentry.origin': 'auto.db.otel.knex', - 'sentry.op': 'db', - 'net.peer.name': 'localhost', - 'net.peer.port': 3307, - }), - status: 'ok', - description: 'insert into `User` (`email`, `name`) values (?, ?)', - origin: 'auto.db.otel.knex', - }), - - expect.objectContaining({ - data: expect.objectContaining({ - 'knex.version': KNEX_VERSION, - 'db.operation': 'select', - 'db.sql.table': 'User', - 'db.system': 'mysql2', - 'db.name': 'tests', - 'db.statement': 'select * from `User`', - 'db.user': 'root', - 'sentry.origin': 'auto.db.otel.knex', - 'sentry.op': 'db', - }), - status: 'ok', - description: 'select * from `User`', - origin: 'auto.db.otel.knex', - }), - ]), - }; - - await createRunner() - .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port: 3306'] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }); - }); - }); -}); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/package.json b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/package.json deleted file mode 100644 index d3dcaf9d1328..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "sentry-prisma-test", - "version": "1.0.0", - "description": "", - "main": "index.js", - "engines": { - "node": ">=18" - }, - "scripts": { - "generate": "prisma generate", - "migrate": "prisma migrate dev -n sentry-test", - "setup": "run-s --silent generate migrate" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@prisma/client": "5.22.0", - "prisma": "5.22.0" - } -} diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/scenario.js b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/scenario.mjs similarity index 64% rename from dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/scenario.mjs index 767a6f27bdaa..631ca4a1cfb4 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/scenario.mjs @@ -1,16 +1,6 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, - integrations: [Sentry.prismaIntegration()], -}); - -const { randomBytes } = require('crypto'); -const { PrismaClient } = require('@prisma/client'); +import { PrismaClient } from '@prisma/client'; +import * as Sentry from '@sentry/node'; +import { randomBytes } from 'crypto'; // Stop the process from exiting before the transaction is sent setInterval(() => {}, 1000); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/test.ts b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/test.ts index b7788d58e372..74bdf4be4bd2 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/test.ts @@ -1,80 +1,136 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; afterAll(() => { cleanupChildProcesses(); }); describe('Prisma ORM v5 Tests', () => { - test('CJS - should instrument PostgreSQL queries from Prisma ORM', { timeout: 75_000 }, async () => { - await createRunner(__dirname, 'scenario.js') - .withDockerCompose({ - workingDirectory: [__dirname], - readyMatches: ['port 5432'], - setupCommand: 'yarn && yarn setup', - }) - .expect({ - transaction: transaction => { - expect(transaction.transaction).toBe('Test Transaction'); - const spans = transaction.spans || []; - expect(spans.length).toBeGreaterThanOrEqual(5); + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument.mjs', + (createRunner, test, _mode, cwd) => { + test('should instrument PostgreSQL queries from Prisma ORM', { timeout: 75_000 }, async () => { + await createRunner() + .withDockerCompose({ + workingDirectory: [cwd], + readyMatches: ['port 5432'], + setupCommand: 'yarn prisma generate && yarn prisma migrate dev -n sentry-test', + }) + .expect({ + transaction: transaction => { + expect(transaction.transaction).toBe('Test Transaction'); + const spans = transaction.spans || []; + expect(spans.length).toBeGreaterThanOrEqual(5); - expect(spans).toContainEqual( - expect.objectContaining({ - data: { - method: 'create', - model: 'User', - name: 'User.create', - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:operation', - status: 'ok', - }), - ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + method: 'create', + model: 'User', + name: 'User.create', + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:operation', + status: 'ok', + }), + ); - expect(spans).toContainEqual( - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:serialize', - status: 'ok', - }), - ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:serialize', + status: 'ok', + }), + ); - expect(spans).toContainEqual( - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:connect', - status: 'ok', - }), - ); - expect(spans).toContainEqual( - expect.objectContaining({ - data: { - method: 'findMany', - model: 'User', - name: 'User.findMany', - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:operation', - status: 'ok', - }), - ); - expect(spans).toContainEqual( - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:serialize', - status: 'ok', - }), - ); - }, - }) - .start() - .completed(); - }); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:connect', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + method: 'findMany', + model: 'User', + name: 'User.findMany', + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:operation', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:serialize', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'db.statement': expect.stringContaining('INSERT INTO'), + 'db.system': 'postgresql', + 'otel.kind': 'CLIENT', + 'sentry.op': 'db', + 'sentry.origin': 'auto.db.otel.prisma', + }, + op: 'db', + description: expect.stringContaining('INSERT INTO'), + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'db.statement': expect.stringContaining('SELECT'), + 'db.system': 'postgresql', + 'otel.kind': 'CLIENT', + 'sentry.op': 'db', + 'sentry.origin': 'auto.db.otel.prisma', + }, + op: 'db', + description: expect.stringContaining('SELECT'), + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'db.statement': expect.stringContaining('DELETE'), + 'db.system': 'postgresql', + 'otel.kind': 'CLIENT', + 'sentry.op': 'db', + 'sentry.origin': 'auto.db.otel.prisma', + }, + op: 'db', + description: expect.stringContaining('DELETE'), + status: 'ok', + }), + ); + }, + }) + .start() + .completed(); + }); + }, + { + additionalDependencies: { + '@prisma/client': '5.22.0', + prisma: '5.22.0', + }, + copyPaths: ['prisma', 'docker-compose.yml'], + }, + ); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/yarn.lock b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/yarn.lock deleted file mode 100644 index 860aa032d6cc..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v5/yarn.lock +++ /dev/null @@ -1,58 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@prisma/client@5.22.0": - version "5.22.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.22.0.tgz#da1ca9c133fbefe89e0da781c75e1c59da5f8802" - integrity sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA== - -"@prisma/debug@5.22.0": - version "5.22.0" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.22.0.tgz#58af56ed7f6f313df9fb1042b6224d3174bbf412" - integrity sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ== - -"@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2": - version "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz#d534dd7235c1ba5a23bacd5b92cc0ca3894c28f4" - integrity sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ== - -"@prisma/engines@5.22.0": - version "5.22.0" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.22.0.tgz#28f3f52a2812c990a8b66eb93a0987816a5b6d84" - integrity sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA== - dependencies: - "@prisma/debug" "5.22.0" - "@prisma/engines-version" "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2" - "@prisma/fetch-engine" "5.22.0" - "@prisma/get-platform" "5.22.0" - -"@prisma/fetch-engine@5.22.0": - version "5.22.0" - resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz#4fb691b483a450c5548aac2f837b267dd50ef52e" - integrity sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA== - dependencies: - "@prisma/debug" "5.22.0" - "@prisma/engines-version" "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2" - "@prisma/get-platform" "5.22.0" - -"@prisma/get-platform@5.22.0": - version "5.22.0" - resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.22.0.tgz#fc675bc9d12614ca2dade0506c9c4a77e7dddacd" - integrity sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q== - dependencies: - "@prisma/debug" "5.22.0" - -fsevents@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -prisma@5.22.0: - version "5.22.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.22.0.tgz#1f6717ff487cdef5f5799cc1010459920e2e6197" - integrity sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A== - dependencies: - "@prisma/engines" "5.22.0" - optionalDependencies: - fsevents "2.3.3" diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/package.json b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/package.json deleted file mode 100644 index dc062f1b9e3b..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "sentry-prisma-test", - "version": "1.0.0", - "description": "", - "main": "index.js", - "engines": { - "node": ">=18" - }, - "scripts": { - "generate": "prisma generate", - "migrate": "prisma migrate dev -n sentry-test", - "setup": "run-s --silent generate migrate" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@prisma/client": "6.2.1", - "prisma": "6.2.1" - } -} diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/scenario.js b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/scenario.mjs similarity index 64% rename from dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/scenario.mjs index b6e3805fa595..89469a30a0c0 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/scenario.mjs @@ -1,16 +1,6 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, - integrations: [Sentry.prismaIntegration()], -}); - -const { randomBytes } = require('crypto'); -const { PrismaClient } = require('@prisma/client'); +import { PrismaClient } from '@prisma/client'; +import * as Sentry from '@sentry/node'; +import { randomBytes } from 'crypto'; // Stop the process from exiting before the transaction is sent setInterval(() => {}, 1000); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/test.ts b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/test.ts index 5e00a00966b7..07405a496fd0 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/test.ts @@ -1,96 +1,106 @@ import type { SpanJSON } from '@sentry/core'; -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; afterAll(() => { cleanupChildProcesses(); }); describe('Prisma ORM v6 Tests', () => { - test('CJS - should instrument PostgreSQL queries from Prisma ORM', { timeout: 75_000 }, async () => { - await createRunner(__dirname, 'scenario.js') - .withDockerCompose({ - workingDirectory: [__dirname], - readyMatches: ['port 5432'], - setupCommand: 'yarn && yarn setup', - }) - .expect({ - transaction: transaction => { - expect(transaction.transaction).toBe('Test Transaction'); + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument.mjs', + (createRunner, test, _mode, cwd) => { + test('should instrument PostgreSQL queries from Prisma ORM', { timeout: 75_000 }, async () => { + await createRunner() + .withDockerCompose({ + workingDirectory: [cwd], + readyMatches: ['port 5432'], + setupCommand: `yarn prisma generate --schema ${cwd}/prisma/schema.prisma && yarn prisma migrate dev -n sentry-test --schema ${cwd}/prisma/schema.prisma`, + }) + .expect({ + transaction: transaction => { + expect(transaction.transaction).toBe('Test Transaction'); - const spans = transaction.spans || []; - expect(spans.length).toBeGreaterThanOrEqual(5); + const spans = transaction.spans || []; + expect(spans.length).toBeGreaterThanOrEqual(5); - function expectPrismaSpanToIncludeSpanWith(span: Partial) { - expect(spans).toContainEqual( - expect.objectContaining({ - ...span, - data: { - ...span.data, - 'sentry.origin': 'auto.db.otel.prisma', - }, - status: 'ok', - }), - ); - } + function expectPrismaSpanToIncludeSpanWith(span: Partial) { + expect(spans).toContainEqual( + expect.objectContaining({ + ...span, + data: { + ...span.data, + 'sentry.origin': 'auto.db.otel.prisma', + }, + status: 'ok', + }), + ); + } - expectPrismaSpanToIncludeSpanWith({ - description: 'prisma:client:detect_platform', - }); + expectPrismaSpanToIncludeSpanWith({ + description: 'prisma:client:detect_platform', + }); - expectPrismaSpanToIncludeSpanWith({ - description: 'prisma:client:load_engine', - }); + expectPrismaSpanToIncludeSpanWith({ + description: 'prisma:client:load_engine', + }); - expectPrismaSpanToIncludeSpanWith({ - description: 'prisma:client:operation', - data: { - method: 'create', - model: 'User', - name: 'User.create', - }, - }); + expectPrismaSpanToIncludeSpanWith({ + description: 'prisma:client:operation', + data: { + method: 'create', + model: 'User', + name: 'User.create', + }, + }); - expectPrismaSpanToIncludeSpanWith({ - description: 'prisma:client:serialize', - }); + expectPrismaSpanToIncludeSpanWith({ + description: 'prisma:client:serialize', + }); - expectPrismaSpanToIncludeSpanWith({ - description: 'prisma:client:connect', - }); + expectPrismaSpanToIncludeSpanWith({ + description: 'prisma:client:connect', + }); - expectPrismaSpanToIncludeSpanWith({ - description: 'prisma:engine:connect', - }); + expectPrismaSpanToIncludeSpanWith({ + description: 'prisma:engine:connect', + }); - expectPrismaSpanToIncludeSpanWith({ - description: 'prisma:engine:query', - }); + expectPrismaSpanToIncludeSpanWith({ + description: 'prisma:engine:query', + }); - expectPrismaSpanToIncludeSpanWith({ - data: { - 'sentry.op': 'db', - 'db.query.text': - 'SELECT "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" FROM "public"."User" WHERE 1=1 OFFSET $1', - 'db.system': 'postgresql', - 'otel.kind': 'CLIENT', - }, - description: - 'SELECT "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" FROM "public"."User" WHERE 1=1 OFFSET $1', - }); + expectPrismaSpanToIncludeSpanWith({ + data: { + 'sentry.op': 'db', + 'db.query.text': + 'SELECT "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" FROM "public"."User" WHERE 1=1 OFFSET $1', + 'db.system': 'postgresql', + 'otel.kind': 'CLIENT', + }, + description: + 'SELECT "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" FROM "public"."User" WHERE 1=1 OFFSET $1', + }); - expectPrismaSpanToIncludeSpanWith({ - data: { - 'sentry.op': 'db', - 'db.query.text': 'DELETE FROM "public"."User" WHERE "public"."User"."email"::text LIKE $1', - 'db.system': 'postgresql', - 'otel.kind': 'CLIENT', + expectPrismaSpanToIncludeSpanWith({ + data: { + 'sentry.op': 'db', + 'db.query.text': 'DELETE FROM "public"."User" WHERE "public"."User"."email"::text LIKE $1', + 'db.system': 'postgresql', + 'otel.kind': 'CLIENT', + }, + description: 'DELETE FROM "public"."User" WHERE "public"."User"."email"::text LIKE $1', + }); }, - description: 'DELETE FROM "public"."User" WHERE "public"."User"."email"::text LIKE $1', - }); - }, - }) - .start() - .completed(); - }); + }) + .start() + .completed(); + }); + }, + { + copyPaths: ['prisma', 'docker-compose.yml'], + }, + ); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/yarn.lock b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/yarn.lock deleted file mode 100644 index fbdff7a9505d..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v6/yarn.lock +++ /dev/null @@ -1,58 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@prisma/client@6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-6.2.1.tgz#3d7d0c8669bba490247e1ffff67b93a516bd789f" - integrity sha512-msKY2iRLISN8t5X0Tj7hU0UWet1u0KuxSPHWuf3IRkB4J95mCvGpyQBfQ6ufcmvKNOMQSq90O2iUmJEN2e5fiA== - -"@prisma/debug@6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-6.2.1.tgz#887719967c4942d125262e48f6c47c45d17c1f61" - integrity sha512-0KItvt39CmQxWkEw6oW+RQMD6RZ43SJWgEUnzxN8VC9ixMysa7MzZCZf22LCK5DSooiLNf8vM3LHZm/I/Ni7bQ== - -"@prisma/engines-version@6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69": - version "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69.tgz#b84ce3fab44bfa13a22669da02752330b61745b2" - integrity sha512-7tw1qs/9GWSX6qbZs4He09TOTg1ff3gYsB3ubaVNN0Pp1zLm9NC5C5MZShtkz7TyQjx7blhpknB7HwEhlG+PrQ== - -"@prisma/engines@6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-6.2.1.tgz#14ef56bb780f02871a728667161d997a14aedb69" - integrity sha512-lTBNLJBCxVT9iP5I7Mn6GlwqAxTpS5qMERrhebkUhtXpGVkBNd/jHnNJBZQW4kGDCKaQg/r2vlJYkzOHnAb7ZQ== - dependencies: - "@prisma/debug" "6.2.1" - "@prisma/engines-version" "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69" - "@prisma/fetch-engine" "6.2.1" - "@prisma/get-platform" "6.2.1" - -"@prisma/fetch-engine@6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-6.2.1.tgz#cd7eb7428a407105e0f3761dba536aefd41fc7f7" - integrity sha512-OO7O9d6Mrx2F9i+Gu1LW+DGXXyUFkP7OE5aj9iBfA/2jjDXEJjqa9X0ZmM9NZNo8Uo7ql6zKm6yjDcbAcRrw1A== - dependencies: - "@prisma/debug" "6.2.1" - "@prisma/engines-version" "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69" - "@prisma/get-platform" "6.2.1" - -"@prisma/get-platform@6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-6.2.1.tgz#34313cd0ee3587798ad33a7b57b6342dc8e66426" - integrity sha512-zp53yvroPl5m5/gXYLz7tGCNG33bhG+JYCm74ohxOq1pPnrL47VQYFfF3RbTZ7TzGWCrR3EtoiYMywUBw7UK6Q== - dependencies: - "@prisma/debug" "6.2.1" - -fsevents@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -prisma@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-6.2.1.tgz#457b210326d66d0e6f583cc6f9cd2819b984408f" - integrity sha512-hhyM0H13pQleQ+br4CkzGizS5I0oInoeTw3JfLw1BRZduBSQxPILlJLwi+46wZzj9Je7ndyQEMGw/n5cN2fknA== - dependencies: - "@prisma/engines" "6.2.1" - optionalDependencies: - fsevents "2.3.3" diff --git a/dev-packages/node-integration-tests/utils/runner.ts b/dev-packages/node-integration-tests/utils/runner.ts index 46c031c2c786..dfe27dc5a4a5 100644 --- a/dev-packages/node-integration-tests/utils/runner.ts +++ b/dev-packages/node-integration-tests/utils/runner.ts @@ -13,10 +13,11 @@ import type { } from '@sentry/core'; import { normalize } from '@sentry/core'; import { createBasicSentryServer } from '@sentry-internal/test-utils'; -import { execSync, spawn, spawnSync } from 'child_process'; -import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'; +import { exec, execSync, spawn, spawnSync } from 'child_process'; +import { existsSync } from 'fs'; +import { cp, mkdir, readFile, rm, writeFile } from 'fs/promises'; import { basename, join } from 'path'; -import { inspect } from 'util'; +import { inspect, promisify } from 'util'; import { afterAll, beforeAll, describe, test } from 'vitest'; import { assertEnvelopeHeader, @@ -29,6 +30,8 @@ import { assertSentryTransaction, } from './assertions'; +const execPromise = promisify(exec); + const CLEANUP_STEPS = new Set(); export function cleanupChildProcesses(): void { @@ -104,7 +107,11 @@ async function runDockerCompose(options: DockerOptions): Promise { child.stdout.removeAllListeners(); clearTimeout(timeout); if (options.setupCommand) { - execSync(options.setupCommand, { cwd, stdio: 'inherit' }); + try { + execSync(options.setupCommand, { cwd, stdio: 'inherit' }); + } catch (e) { + log('Error running docker setup command', e); + } } resolve(close); } @@ -174,11 +181,20 @@ export function createEsmAndCjsTests( createTestRunner: () => ReturnType, testFn: typeof test | typeof test.fails, mode: 'esm' | 'cjs', + cwd: string, ) => void, - // `additionalDependencies` to install in a tmp dir for the esm and cjs tests - // This could be used to override packages that live in the parent package.json for the specific run of the test - // e.g. `{ ai: '^5.0.0' }` to test Vercel AI v5 - options?: { failsOnCjs?: boolean; failsOnEsm?: boolean; additionalDependencies?: Record }, + options?: { + failsOnCjs?: boolean; + failsOnEsm?: boolean; + /** + * `additionalDependencies` to install in a tmp dir for the esm and cjs tests + * This could be used to override packages that live in the parent package.json for the specific run of the test + * e.g. `{ ai: '^5.0.0' }` to test Vercel AI v5 + */ + additionalDependencies?: Record; + /** Copy these files/dirs into the tmp dir. */ + copyPaths?: string[]; + }, ): void { const mjsScenarioPath = join(cwd, scenarioPath); const mjsInstrumentPath = join(cwd, instrumentPath); @@ -202,16 +218,23 @@ export function createEsmAndCjsTests( const cjsScenarioPath = join(tmpDirPath, esmScenarioBasename.replace('.mjs', '.cjs')); const cjsInstrumentPath = join(tmpDirPath, esmInstrumentBasename.replace('.mjs', '.cjs')); - function createTmpDir(): void { - mkdirSync(tmpDirPath); + async function createTmpDir(): Promise { + await mkdir(tmpDirPath); // Copy ESM files as-is into tmp dir - writeFileSync(esmScenarioPathForRun, readFileSync(mjsScenarioPath, 'utf8')); - writeFileSync(esmInstrumentPathForRun, readFileSync(mjsInstrumentPath, 'utf8')); + await writeFile(esmScenarioPathForRun, await readFile(mjsScenarioPath, 'utf8')); + await writeFile(esmInstrumentPathForRun, await readFile(mjsInstrumentPath, 'utf8')); // Pre-create CJS converted files inside tmp dir - convertEsmFileToCjs(esmScenarioPathForRun, cjsScenarioPath); - convertEsmFileToCjs(esmInstrumentPathForRun, cjsInstrumentPath); + await convertEsmFileToCjs(esmScenarioPathForRun, cjsScenarioPath); + await convertEsmFileToCjs(esmInstrumentPathForRun, cjsInstrumentPath); + + // Copy any additional files/dirs into tmp dir + if (options?.copyPaths) { + for (const path of options.copyPaths) { + await cp(join(cwd, path), join(tmpDirPath, path), { recursive: true }); + } + } // Create a minimal package.json with requested dependencies (if any) and install them const additionalDependencies = options?.additionalDependencies ?? {}; @@ -223,7 +246,7 @@ export function createEsmAndCjsTests( dependencies: additionalDependencies, } as const; - writeFileSync(join(tmpDirPath, 'package.json'), JSON.stringify(packageJson, null, 2)); + await writeFile(join(tmpDirPath, 'package.json'), JSON.stringify(packageJson, null, 2)); try { const deps = Object.entries(additionalDependencies).map(([name, range]) => { @@ -234,33 +257,24 @@ export function createEsmAndCjsTests( }); if (deps.length > 0) { - // Prefer npm for temp installs to avoid Yarn engine strictness; see https://github.com/vercel/ai/issues/7777 - // We rely on the generated package.json dependencies and run a plain install. - const result = spawnSync('npm', ['install', '--silent', '--no-audit', '--no-fund'], { - cwd: tmpDirPath, - encoding: 'utf8', - }); - - if (process.env.DEBUG) { - // eslint-disable-next-line no-console - console.log('[additionalDependencies via npm]', deps.join(' ')); - // eslint-disable-next-line no-console - console.log('[npm stdout]', result.stdout); - // eslint-disable-next-line no-console - console.log('[npm stderr]', result.stderr); - } + try { + // Prefer npm for temp installs to avoid Yarn engine strictness; see https://github.com/vercel/ai/issues/7777 + // We rely on the generated package.json dependencies and run a plain install. + const { stdout, stderr } = await execPromise('npm install --silent --no-audit --no-fund', { + cwd: tmpDirPath, + encoding: 'utf8', + }); - if (result.error) { - throw new Error( - `Failed to install additionalDependencies in tmp dir ${tmpDirPath}: ${result.error.message}`, - ); - } - if (typeof result.status === 'number' && result.status !== 0) { - throw new Error( - `Failed to install additionalDependencies in tmp dir ${tmpDirPath} (exit ${result.status}):\n${ - result.stderr || result.stdout || '(no output)' - }`, - ); + if (process.env.DEBUG) { + // eslint-disable-next-line no-console + console.log('[additionalDependencies via npm]', deps.join(' ')); + // eslint-disable-next-line no-console + console.log('[npm stdout]', stdout); + // eslint-disable-next-line no-console + console.log('[npm stderr]', stderr); + } + } catch (error) { + throw new Error(`Failed to install additionalDependencies in tmp dir ${tmpDirPath}: ${error}`); } } } catch (e) { @@ -278,37 +292,46 @@ export function createEsmAndCjsTests( () => createRunner(esmScenarioPathForRun).withFlags('--import', esmInstrumentPathForRun), esmTestFn, 'esm', + tmpDirPath, ); }); const cjsTestFn = options?.failsOnCjs ? test.fails : test; describe('cjs', () => { - callback(() => createRunner(cjsScenarioPath).withFlags('--require', cjsInstrumentPath), cjsTestFn, 'cjs'); + callback( + () => createRunner(cjsScenarioPath).withFlags('--require', cjsInstrumentPath), + cjsTestFn, + 'cjs', + tmpDirPath, + ); }); // Create tmp directory - beforeAll(() => { - createTmpDir(); - }); + beforeAll(async () => { + await createTmpDir(); + }, 60_000); // Clean up the tmp directory after both esm and cjs suites have run - afterAll(() => { + afterAll(async () => { + // First do cleanup! + cleanupChildProcesses(); + try { - rmSync(tmpDirPath, { recursive: true, force: true }); + await rm(tmpDirPath, { recursive: true, force: true }); } catch { if (process.env.DEBUG) { // eslint-disable-next-line no-console console.error(`Failed to remove tmp dir: ${tmpDirPath}`); } } - }); + }, 30_000); }); } -function convertEsmFileToCjs(inputPath: string, outputPath: string): void { - const cjsFileContent = readFileSync(inputPath, 'utf8'); +async function convertEsmFileToCjs(inputPath: string, outputPath: string): Promise { + const cjsFileContent = await readFile(inputPath, 'utf8'); const cjsFileContentConverted = convertEsmToCjs(cjsFileContent); - writeFileSync(outputPath, cjsFileContentConverted); + return writeFile(outputPath, cjsFileContentConverted); } /** Creates a test runner */ diff --git a/packages/angular/src/errorhandler.ts b/packages/angular/src/errorhandler.ts index 31f945b08731..ceb05c0b9e9f 100644 --- a/packages/angular/src/errorhandler.ts +++ b/packages/angular/src/errorhandler.ts @@ -111,7 +111,7 @@ class SentryErrorHandler implements AngularErrorHandler, OnDestroy { // Capture handled exception and send it to Sentry. const eventId = runOutsideAngular(() => Sentry.captureException(extractedError, { - mechanism: { type: 'angular', handled: false }, + mechanism: { type: 'auto.function.angular.error_handler', handled: false }, }), ); diff --git a/packages/angular/test/errorhandler.test.ts b/packages/angular/test/errorhandler.test.ts index af532c12d9ae..09b6d69d3337 100644 --- a/packages/angular/test/errorhandler.test.ts +++ b/packages/angular/test/errorhandler.test.ts @@ -1,7 +1,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import * as SentryBrowser from '@sentry/browser'; import type { Client, Event } from '@sentry/core'; -import { vi } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createErrorHandler, SentryErrorHandler } from '../src/errorhandler'; const captureExceptionSpy = vi.spyOn(SentryBrowser, 'captureException'); @@ -9,7 +9,7 @@ const captureExceptionSpy = vi.spyOn(SentryBrowser, 'captureException'); vi.spyOn(console, 'error').mockImplementation(() => {}); const captureExceptionEventHint = { - mechanism: { handled: false, type: 'angular' }, + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, }; class CustomError extends Error { @@ -71,7 +71,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(str); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(str, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(str, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an empty Error', () => { @@ -79,7 +81,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(err, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(err, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts a non-empty Error', () => { @@ -88,7 +92,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(err, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(err, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an error-like object without stack', () => { @@ -169,7 +175,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(err, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(err, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an instance of class not extending Error but that has an error-like shape', () => { @@ -178,7 +186,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(err, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(err, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an instance of a class that does not extend Error and does not have an error-like shape', () => { @@ -251,7 +261,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(ngErr, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(ngErr, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an `HttpErrorResponse` with `Error`', () => { @@ -261,7 +273,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(httpErr, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(httpErr, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an `HttpErrorResponse` with `ErrorEvent`', () => { @@ -431,7 +445,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(err, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(err, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an `HttpErrorResponse` with an instance of class not extending Error but that has an error-like shape', () => { @@ -441,7 +457,9 @@ describe('SentryErrorHandler', () => { createErrorHandler().handleError(err); expect(captureExceptionSpy).toHaveBeenCalledTimes(1); - expect(captureExceptionSpy).toHaveBeenCalledWith(innerErr, { mechanism: { handled: false, type: 'angular' } }); + expect(captureExceptionSpy).toHaveBeenCalledWith(innerErr, { + mechanism: { handled: false, type: 'auto.function.angular.error_handler' }, + }); }); it('extracts an `HttpErrorResponse` with an instance of a class that does not extend Error and does not have an error-like shape', () => { diff --git a/packages/astro/src/index.server.ts b/packages/astro/src/index.server.ts index c91d98725d9b..5abf8d51633d 100644 --- a/packages/astro/src/index.server.ts +++ b/packages/astro/src/index.server.ts @@ -142,6 +142,7 @@ export { profiler, logger, consoleLoggingIntegration, + createConsolaReporter, wrapMcpServerWithSentry, NODE_VERSION, featureFlagsIntegration, diff --git a/packages/astro/src/server/middleware.ts b/packages/astro/src/server/middleware.ts index 61f7913cf1b1..a12c25ff6045 100644 --- a/packages/astro/src/server/middleware.ts +++ b/packages/astro/src/server/middleware.ts @@ -50,11 +50,8 @@ function sendErrorToSentry(e: unknown): unknown { captureException(objectifiedErr, { mechanism: { - type: 'astro', + type: 'auto.middleware.astro', handled: false, - data: { - function: 'astroMiddleware', - }, }, }); diff --git a/packages/astro/test/server/middleware.test.ts b/packages/astro/test/server/middleware.test.ts index 03933582c846..10e314268264 100644 --- a/packages/astro/test/server/middleware.test.ts +++ b/packages/astro/test/server/middleware.test.ts @@ -168,7 +168,7 @@ describe('sentryMiddleware', () => { await expect(async () => middleware(ctx, next)).rejects.toThrowError(); expect(captureExceptionSpy).toHaveBeenCalledWith(error, { - mechanism: { handled: false, type: 'astro', data: { function: 'astroMiddleware' } }, + mechanism: { handled: false, type: 'auto.middleware.astro' }, }); }); @@ -205,7 +205,7 @@ describe('sentryMiddleware', () => { await expect(() => resultFromNext!.text()).rejects.toThrowError(); expect(captureExceptionSpy).toHaveBeenCalledWith(error, { - mechanism: { handled: false, type: 'astro', data: { function: 'astroMiddleware' } }, + mechanism: { handled: false, type: 'auto.middleware.astro' }, }); }); diff --git a/packages/aws-serverless/README.md b/packages/aws-serverless/README.md index 9109b8e059b0..353b702fbcb9 100644 --- a/packages/aws-serverless/README.md +++ b/packages/aws-serverless/README.md @@ -4,21 +4,17 @@

-# Official Sentry SDK for Serverless environments +# Official Sentry SDK for AWS Lambda ## Links -- [Official SDK Docs](https://docs.sentry.io/) +- [Official SDK Docs](https://docs.sentry.io/platforms/javascript/guides/aws-lambda) ## General -This package is a wrapper around `@sentry/node`, with added functionality related to various Serverless solutions. All +This package is a wrapper around `@sentry/node`, with added functionality related to AWS Lambda. All methods available in `@sentry/node` can be imported from `@sentry/aws-serverless`. -Currently supported environment: - -### AWS Lambda - To use this SDK, call `Sentry.init(options)` at the very beginning of your JavaScript file. ```javascript @@ -30,14 +26,14 @@ Sentry.init({ }); // async (recommended) -exports.handler = Sentry.wrapHandler(async (event, context) => { +export const handler = async (event, context) => { throw new Error('oh, hello there!'); -}); +}; // sync -exports.handler = Sentry.wrapHandler((event, context, callback) => { +export const handler = (event, context, callback) => { throw new Error('oh, hello there!'); -}); +}; ``` If you also want to trace performance of all the incoming requests and also outgoing AWS service requests, just set the @@ -46,21 +42,21 @@ If you also want to trace performance of all the incoming requests and also outg ```javascript import * as Sentry from '@sentry/aws-serverless'; -Sentry.AWSLambda.init({ +Sentry.init({ dsn: '__DSN__', tracesSampleRate: 1.0, }); ``` -#### Integrate Sentry using internal extension +#### Integrate Sentry using the Sentry Lambda layer -Another and much simpler way to integrate Sentry to your AWS Lambda function is to add an official layer. +Another much simpler way to integrate Sentry to your AWS Lambda function is to add the official layer. 1. Choose Layers -> Add Layer. -2. Specify an ARN: `arn:aws:lambda:us-west-1:TODO:layer:TODO:VERSION`. +2. Specify an ARN: `arn:aws:lambda:us-west-1:943013980633:layer:SentryNodeServerlessSDKv10:19`. Get the latest ARN from the [docs](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/install/layer). 3. Go to Environment variables and add: - - `NODE_OPTIONS`: `-r @sentry/aws-serverless/build/npm/cjs/awslambda-auto`. + - `NODE_OPTIONS`: `--import @sentry/aws-serverless/awslambda-auto`. - `SENTRY_DSN`: `your dsn`. - `SENTRY_TRACES_SAMPLE_RATE`: a number between 0 and 1 representing the chance a transaction is sent to Sentry. For more information, see - [docs](https://docs.sentry.io/platforms/node/guides/aws-lambda/configuration/options/#tracesSampleRate). + [docs](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/configuration/options/#tracesSampleRate). diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json index d04809c989a7..ea32abd115b5 100644 --- a/packages/aws-serverless/package.json +++ b/packages/aws-serverless/package.json @@ -66,9 +66,9 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/instrumentation-aws-sdk": "0.57.0", - "@opentelemetry/semantic-conventions": "^1.36.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-aws-sdk": "0.59.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@sentry/core": "10.11.0", "@sentry/node": "10.11.0", "@types/aws-lambda": "^8.10.62" diff --git a/packages/aws-serverless/src/index.ts b/packages/aws-serverless/src/index.ts index a041e0a7231f..541f8a97a410 100644 --- a/packages/aws-serverless/src/index.ts +++ b/packages/aws-serverless/src/index.ts @@ -128,6 +128,7 @@ export { vercelAIIntegration, logger, consoleLoggingIntegration, + createConsolaReporter, wrapMcpServerWithSentry, NODE_VERSION, featureFlagsIntegration, diff --git a/packages/aws-serverless/src/integration/awslambda.ts b/packages/aws-serverless/src/integration/awslambda.ts index c459fc8e25e8..2eaa1fd17354 100644 --- a/packages/aws-serverless/src/integration/awslambda.ts +++ b/packages/aws-serverless/src/integration/awslambda.ts @@ -29,7 +29,7 @@ export const instrumentAwsLambda = generateInstrumentOnce( }, responseHook(_span, { err }) { if (err) { - captureException(err, scope => markEventUnhandled(scope, 'auto.function.aws-serverless.otel')); + captureException(err, scope => markEventUnhandled(scope, 'auto.function.aws_serverless.otel')); } }, }; diff --git a/packages/aws-serverless/src/sdk.ts b/packages/aws-serverless/src/sdk.ts index fd647d3a3376..b7ac8927813c 100644 --- a/packages/aws-serverless/src/sdk.ts +++ b/packages/aws-serverless/src/sdk.ts @@ -235,13 +235,13 @@ export function wrapHandler( if (options.captureAllSettledReasons && Array.isArray(rv) && isPromiseAllSettledResult(rv)) { const reasons = getRejectedReasons(rv); reasons.forEach(exception => { - captureException(exception, scope => markEventUnhandled(scope, 'auto.function.aws-serverless.promise')); + captureException(exception, scope => markEventUnhandled(scope, 'auto.function.aws_serverless.promise')); }); } } catch (e) { // Errors should already captured in the instrumentation's `responseHook`, // we capture them here just to be safe. Double captures are deduplicated by the SDK. - captureException(e, scope => markEventUnhandled(scope, 'auto.function.aws-serverless.handler')); + captureException(e, scope => markEventUnhandled(scope, 'auto.function.aws_serverless.handler')); throw e; } finally { clearTimeout(timeoutWarningTimer); @@ -281,14 +281,14 @@ function wrapStreamingHandler( enhanceScopeWithEnvironmentData(scope, context, startTime); responseStream.on('error', error => { - captureException(error, scope => markEventUnhandled(scope, 'auto.function.aws-serverless.stream')); + captureException(error, scope => markEventUnhandled(scope, 'auto.function.aws_serverless.stream')); }); return await handler(event, responseStream, context); } catch (e) { // Errors should already captured in the instrumentation's `responseHook`, // we capture them here just to be safe. Double captures are deduplicated by the SDK. - captureException(e, scope => markEventUnhandled(scope, 'auto.function.aws-serverless.handler')); + captureException(e, scope => markEventUnhandled(scope, 'auto.function.aws_serverless.handler')); throw e; } finally { if (timeoutWarningTimer) { diff --git a/packages/aws-serverless/test/sdk.test.ts b/packages/aws-serverless/test/sdk.test.ts index 3bf2c42b8fd2..d2047274d744 100644 --- a/packages/aws-serverless/test/sdk.test.ts +++ b/packages/aws-serverless/test/sdk.test.ts @@ -533,7 +533,7 @@ describe('AWSLambda', () => { // @ts-expect-error just mocking around... expect(evtProcessor!(event).exception.values[0]?.mechanism).toEqual({ handled: false, - type: 'auto.function.aws-serverless.handler', + type: 'auto.function.aws_serverless.handler', }); } }); @@ -576,7 +576,7 @@ describe('AWSLambda', () => { // @ts-expect-error just mocking around... expect(evtProcessor(event).exception.values[0]?.mechanism).toEqual({ handled: false, - type: 'auto.function.aws-serverless.handler', + type: 'auto.function.aws_serverless.handler', }); } }); diff --git a/packages/browser-utils/src/index.ts b/packages/browser-utils/src/index.ts index bf6605f3f399..accf3cb3a278 100644 --- a/packages/browser-utils/src/index.ts +++ b/packages/browser-utils/src/index.ts @@ -30,4 +30,6 @@ export { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from './instrument/ export { getBodyString, getFetchRequestArgBody, serializeFormData } from './networkUtils'; +export { resourceTimingToSpanAttributes } from './metrics/resourceTiming'; + export type { FetchHint, NetworkMetaWarning, XhrHint } from './types'; diff --git a/packages/browser-utils/src/metrics/browserMetrics.ts b/packages/browser-utils/src/metrics/browserMetrics.ts index 870558ada39d..8b1592408e8a 100644 --- a/packages/browser-utils/src/metrics/browserMetrics.ts +++ b/packages/browser-utils/src/metrics/browserMetrics.ts @@ -22,13 +22,8 @@ import { addTtfbInstrumentationHandler, } from './instrument'; import { trackLcpAsStandaloneSpan } from './lcp'; -import { - extractNetworkProtocol, - getBrowserPerformanceAPI, - isMeasurementValue, - msToSec, - startAndEndSpan, -} from './utils'; +import { resourceTimingToSpanAttributes } from './resourceTiming'; +import { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils'; import { getActivationStart } from './web-vitals/lib/getActivationStart'; import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry'; import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher'; @@ -637,7 +632,7 @@ export function _addResourceSpans( startTime: number, duration: number, timeOrigin: number, - ignoreResourceSpans?: Array, + ignoredResourceSpanOps?: Array, ): void { // we already instrument based on fetch and xhr, so we don't need to // duplicate spans here. @@ -646,31 +641,15 @@ export function _addResourceSpans( } const op = entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other'; - if (ignoreResourceSpans?.includes(op)) { + if (ignoredResourceSpanOps?.includes(op)) { return; } - const parsedUrl = parseUrl(resourceUrl); - const attributes: SpanAttributes = { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics', }; - setResourceEntrySizeData(attributes, entry, 'transferSize', 'http.response_transfer_size'); - setResourceEntrySizeData(attributes, entry, 'encodedBodySize', 'http.response_content_length'); - setResourceEntrySizeData(attributes, entry, 'decodedBodySize', 'http.decoded_response_content_length'); - - // `deliveryType` is experimental and does not exist everywhere - const deliveryType = (entry as { deliveryType?: 'cache' | 'navigational-prefetch' | '' }).deliveryType; - if (deliveryType != null) { - attributes['http.response_delivery_type'] = deliveryType; - } - // Types do not reflect this property yet - const renderBlockingStatus = (entry as { renderBlockingStatus?: 'render-blocking' | 'non-render-blocking' }) - .renderBlockingStatus; - if (renderBlockingStatus) { - attributes['resource.render_blocking_status'] = renderBlockingStatus; - } + const parsedUrl = parseUrl(resourceUrl); if (parsedUrl.protocol) { attributes['url.scheme'] = parsedUrl.protocol.split(':').pop(); // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it. @@ -682,13 +661,22 @@ export function _addResourceSpans( attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin); - // Checking for only `undefined` and `null` is intentional because it's - // valid for `nextHopProtocol` to be an empty string. - if (entry.nextHopProtocol != null) { - const { name, version } = extractNetworkProtocol(entry.nextHopProtocol); - attributes['network.protocol.name'] = name; - attributes['network.protocol.version'] = version; - } + _setResourceRequestAttributes(entry, attributes, [ + // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus + ['responseStatus', 'http.response.status_code'], + + ['transferSize', 'http.response_transfer_size'], + ['encodedBodySize', 'http.response_content_length'], + ['decodedBodySize', 'http.decoded_response_content_length'], + + // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/renderBlockingStatus + ['renderBlockingStatus', 'resource.render_blocking_status'], + + // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/deliveryType + ['deliveryType', 'http.response_delivery_type'], + ]); + + const attributesWithResourceTiming: SpanAttributes = { ...attributes, ...resourceTimingToSpanAttributes(entry) }; const startTimestamp = timeOrigin + startTime; const endTimestamp = startTimestamp + duration; @@ -696,7 +684,7 @@ export function _addResourceSpans( startAndEndSpan(span, startTimestamp, endTimestamp, { name: resourceUrl.replace(WINDOW.location.origin, ''), op, - attributes, + attributes: attributesWithResourceTiming, }); } @@ -776,16 +764,37 @@ function _setWebVitalAttributes(span: Span, options: AddPerformanceEntriesOption } } -function setResourceEntrySizeData( +type ExperimentalResourceTimingProperty = + | 'renderBlockingStatus' + | 'deliveryType' + // For some reason, TS during build, errors on `responseStatus` not being a property of + // PerformanceResourceTiming while it actually is. Hence, we're adding it here. + // Perhaps because response status is not yet available in Webkit/Safari. + // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus + | 'responseStatus'; + +/** + * Use this to set any attributes we can take directly form the PerformanceResourceTiming entry. + * + * This is just a mapping function for entry->attribute to keep bundle-size minimal. + * Experimental properties are also accepted (see {@link ExperimentalResourceTimingProperty}). + * Assumes that all entry properties might be undefined for browser-specific differences. + * Only accepts string and number values for now and also sets 0-values. + */ +export function _setResourceRequestAttributes( + entry: Partial & Partial>, attributes: SpanAttributes, - entry: PerformanceResourceTiming, - key: keyof Pick, - dataKey: 'http.response_transfer_size' | 'http.response_content_length' | 'http.decoded_response_content_length', + properties: [keyof PerformanceResourceTiming | ExperimentalResourceTimingProperty, string][], ): void { - const entryVal = entry[key]; - if (entryVal != null && entryVal < MAX_INT_AS_BYTES) { - attributes[dataKey] = entryVal; - } + properties.forEach(([entryKey, attributeKey]) => { + const entryVal = entry[entryKey]; + if ( + entryVal != null && + ((typeof entryVal === 'number' && entryVal < MAX_INT_AS_BYTES) || typeof entryVal === 'string') + ) { + attributes[attributeKey] = entryVal; + } + }); } /** diff --git a/packages/browser-utils/src/metrics/resourceTiming.ts b/packages/browser-utils/src/metrics/resourceTiming.ts new file mode 100644 index 000000000000..fe613355c55d --- /dev/null +++ b/packages/browser-utils/src/metrics/resourceTiming.ts @@ -0,0 +1,60 @@ +import type { SpanAttributes } from '@sentry/core'; +import { browserPerformanceTimeOrigin } from '@sentry/core'; +import { extractNetworkProtocol, getBrowserPerformanceAPI } from './utils'; + +function getAbsoluteTime(time = 0): number { + return ((browserPerformanceTimeOrigin() || performance.timeOrigin) + time) / 1000; +} + +/** + * Converts a PerformanceResourceTiming entry to span data for the resource span. Most importantly, + * it converts the timing values from timestamps relative to the `performance.timeOrigin` to absolute timestamps + * in seconds. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming#timestamps + * + * @param resourceTiming + * @returns An array where the first element is the attribute name and the second element is the attribute value. + */ +export function resourceTimingToSpanAttributes(resourceTiming: PerformanceResourceTiming): SpanAttributes { + const timingSpanData: SpanAttributes = {}; + // Checking for only `undefined` and `null` is intentional because it's + // valid for `nextHopProtocol` to be an empty string. + if (resourceTiming.nextHopProtocol != undefined) { + const { name, version } = extractNetworkProtocol(resourceTiming.nextHopProtocol); + timingSpanData['network.protocol.version'] = version; + timingSpanData['network.protocol.name'] = name; + } + + if (!(browserPerformanceTimeOrigin() || getBrowserPerformanceAPI()?.timeOrigin)) { + return timingSpanData; + } + + return { + ...timingSpanData, + + 'http.request.redirect_start': getAbsoluteTime(resourceTiming.redirectStart), + 'http.request.redirect_end': getAbsoluteTime(resourceTiming.redirectEnd), + + 'http.request.worker_start': getAbsoluteTime(resourceTiming.workerStart), + + 'http.request.fetch_start': getAbsoluteTime(resourceTiming.fetchStart), + + 'http.request.domain_lookup_start': getAbsoluteTime(resourceTiming.domainLookupStart), + 'http.request.domain_lookup_end': getAbsoluteTime(resourceTiming.domainLookupEnd), + + 'http.request.connect_start': getAbsoluteTime(resourceTiming.connectStart), + 'http.request.secure_connection_start': getAbsoluteTime(resourceTiming.secureConnectionStart), + 'http.request.connection_end': getAbsoluteTime(resourceTiming.connectEnd), + + 'http.request.request_start': getAbsoluteTime(resourceTiming.requestStart), + + 'http.request.response_start': getAbsoluteTime(resourceTiming.responseStart), + 'http.request.response_end': getAbsoluteTime(resourceTiming.responseEnd), + + // For TTFB we actually want the relative time from timeOrigin to responseStart + // This way, TTFB always measures the "first page load" experience. + // see: https://web.dev/articles/ttfb#measure-resource-requests + 'http.request.time_to_first_byte': (resourceTiming.responseStart ?? 0) / 1000, + }; +} diff --git a/packages/browser-utils/test/browser/browserMetrics.test.ts b/packages/browser-utils/test/browser/browserMetrics.test.ts index 50dcfd65a528..c717bb81ca0b 100644 --- a/packages/browser-utils/test/browser/browserMetrics.test.ts +++ b/packages/browser-utils/test/browser/browserMetrics.test.ts @@ -1,4 +1,4 @@ -import type { Span } from '@sentry/core'; +import type { Span, SpanAttributes } from '@sentry/core'; import { getClient, getCurrentScope, @@ -10,7 +10,12 @@ import { spanToJSON, } from '@sentry/core'; import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'; -import { _addMeasureSpans, _addNavigationSpans, _addResourceSpans } from '../../src/metrics/browserMetrics'; +import { + _addMeasureSpans, + _addNavigationSpans, + _addResourceSpans, + _setResourceRequestAttributes, +} from '../../src/metrics/browserMetrics'; import { WINDOW } from '../../src/types'; import { getDefaultClientOptions, TestClient } from '../utils/TestClient'; @@ -289,6 +294,19 @@ describe('_addResourceSpans', () => { ['url.same_origin']: true, ['network.protocol.name']: 'http', ['network.protocol.version']: '1.1', + 'http.request.connect_start': expect.any(Number), + 'http.request.connection_end': expect.any(Number), + 'http.request.domain_lookup_end': expect.any(Number), + 'http.request.domain_lookup_start': expect.any(Number), + 'http.request.fetch_start': expect.any(Number), + 'http.request.redirect_end': expect.any(Number), + 'http.request.redirect_start': expect.any(Number), + 'http.request.request_start': expect.any(Number), + 'http.request.response_end': expect.any(Number), + 'http.request.response_start': expect.any(Number), + 'http.request.secure_connection_start': expect.any(Number), + 'http.request.time_to_first_byte': 0, + 'http.request.worker_start': expect.any(Number), }, }), ); @@ -404,7 +422,7 @@ describe('_addResourceSpans', () => { expect(spans).toHaveLength(1); expect(spanToJSON(spans[0]!)).toEqual( expect.objectContaining({ - data: { + data: expect.objectContaining({ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.css', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics', ['http.decoded_response_content_length']: entry.decodedBodySize, @@ -416,7 +434,7 @@ describe('_addResourceSpans', () => { ['url.same_origin']: true, ['network.protocol.name']: 'http', ['network.protocol.version']: '2', - }, + }), }), ); }); @@ -441,7 +459,7 @@ describe('_addResourceSpans', () => { expect(spans).toHaveLength(1); expect(spanToJSON(spans[0]!)).toEqual( expect.objectContaining({ - data: { + data: expect.objectContaining({ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.css', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics', 'server.address': 'example.com', @@ -449,7 +467,7 @@ describe('_addResourceSpans', () => { 'url.scheme': 'https', ['network.protocol.name']: 'http', ['network.protocol.version']: '3', - }, + }), description: '/assets/to/css', timestamp: 468, op: 'resource.css', @@ -489,6 +507,19 @@ describe('_addResourceSpans', () => { 'url.scheme': 'https', ['network.protocol.name']: 'http', ['network.protocol.version']: '3', + 'http.request.connect_start': expect.any(Number), + 'http.request.connection_end': expect.any(Number), + 'http.request.domain_lookup_end': expect.any(Number), + 'http.request.domain_lookup_start': expect.any(Number), + 'http.request.fetch_start': expect.any(Number), + 'http.request.redirect_end': expect.any(Number), + 'http.request.redirect_start': expect.any(Number), + 'http.request.request_start': expect.any(Number), + 'http.request.response_end': expect.any(Number), + 'http.request.response_start': expect.any(Number), + 'http.request.secure_connection_start': expect.any(Number), + 'http.request.time_to_first_byte': 0, + 'http.request.worker_start': expect.any(Number), }, description: '/assets/to/css', timestamp: 468, @@ -709,6 +740,75 @@ describe('_addNavigationSpans', () => { }); }); +describe('_setResourceRequestAttributes', () => { + it('sets resource request attributes', () => { + const attributes: SpanAttributes = {}; + + const entry = mockPerformanceResourceTiming({ + transferSize: 0, + deliveryType: 'cache', + renderBlockingStatus: 'non-blocking', + responseStatus: 200, + redirectStart: 100, + responseStart: 200, + }); + + _setResourceRequestAttributes(entry, attributes, [ + ['transferSize', 'http.response_transfer_size'], + ['deliveryType', 'http.response_delivery_type'], + ['renderBlockingStatus', 'resource.render_blocking_status'], + ['responseStatus', 'http.response.status_code'], + ['redirectStart', 'http.request.redirect_start'], + ['responseStart', 'http.response.start'], + ]); + + expect(attributes).toEqual({ + 'http.response_transfer_size': 0, + 'http.request.redirect_start': 100, + 'http.response.start': 200, + 'http.response.status_code': 200, + 'http.response_delivery_type': 'cache', + 'resource.render_blocking_status': 'non-blocking', + }); + }); + + it("doesn't set other attributes", () => { + const attributes: SpanAttributes = {}; + + const entry = mockPerformanceResourceTiming({ + transferSize: 0, + deliveryType: 'cache', + renderBlockingStatus: 'non-blocking', + }); + + _setResourceRequestAttributes(entry, attributes, [['transferSize', 'http.response_transfer_size']]); + + expect(attributes).toEqual({ + 'http.response_transfer_size': 0, + }); + }); + + it("doesn't set non-primitive or undefined values", () => { + const attributes: SpanAttributes = {}; + + const entry = mockPerformanceResourceTiming({ + transferSize: undefined, + // @ts-expect-error null is invalid but let's test it anyway + deliveryType: null, + // @ts-expect-error object is invalid but let's test it anyway + renderBlockingStatus: { blocking: 'non-blocking' }, + }); + + _setResourceRequestAttributes(entry, attributes, [ + ['transferSize', 'http.response_transfer_size'], + ['deliveryType', 'http.response_delivery_type'], + ['renderBlockingStatus', 'resource.render_blocking_status'], + ]); + + expect(attributes).toEqual({}); + }); +}); + const setGlobalLocation = (location: Location) => { // @ts-expect-error need to delete this in order to set to new value delete WINDOW.location; diff --git a/packages/browser-utils/test/instrument/metrics/elementTiming.test.ts b/packages/browser-utils/test/metrics/elementTiming.test.ts similarity index 98% rename from packages/browser-utils/test/instrument/metrics/elementTiming.test.ts rename to packages/browser-utils/test/metrics/elementTiming.test.ts index 04456ceadc44..14431415873b 100644 --- a/packages/browser-utils/test/instrument/metrics/elementTiming.test.ts +++ b/packages/browser-utils/test/metrics/elementTiming.test.ts @@ -1,8 +1,8 @@ import * as sentryCore from '@sentry/core'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { _onElementTiming, startTrackingElementTiming } from '../../../src/metrics/elementTiming'; -import * as browserMetricsInstrumentation from '../../../src/metrics/instrument'; -import * as browserMetricsUtils from '../../../src/metrics/utils'; +import { _onElementTiming, startTrackingElementTiming } from '../../src/metrics/elementTiming'; +import * as browserMetricsInstrumentation from '../../src/metrics/instrument'; +import * as browserMetricsUtils from '../../src/metrics/utils'; describe('_onElementTiming', () => { const spanEndSpy = vi.fn(); diff --git a/packages/browser-utils/test/instrument/metrics/inpt.test.ts b/packages/browser-utils/test/metrics/inpt.test.ts similarity index 95% rename from packages/browser-utils/test/instrument/metrics/inpt.test.ts rename to packages/browser-utils/test/metrics/inpt.test.ts index 437ae650d0fe..bfa44b17a5b4 100644 --- a/packages/browser-utils/test/instrument/metrics/inpt.test.ts +++ b/packages/browser-utils/test/metrics/inpt.test.ts @@ -1,8 +1,8 @@ import { afterEach } from 'node:test'; import { describe, expect, it, vi } from 'vitest'; -import { _onInp, _trackINP } from '../../../src/metrics/inp'; -import * as instrument from '../../../src/metrics/instrument'; -import * as utils from '../../../src/metrics/utils'; +import { _onInp, _trackINP } from '../../src/metrics/inp'; +import * as instrument from '../../src/metrics/instrument'; +import * as utils from '../../src/metrics/utils'; describe('_trackINP', () => { const addInpInstrumentationHandler = vi.spyOn(instrument, 'addInpInstrumentationHandler'); diff --git a/packages/browser/test/tracing/resource-timing.test.ts b/packages/browser-utils/test/metrics/resourceTiming.test.ts similarity index 60% rename from packages/browser/test/tracing/resource-timing.test.ts rename to packages/browser-utils/test/metrics/resourceTiming.test.ts index c3ad8b9c0c85..881a7075441e 100644 --- a/packages/browser/test/tracing/resource-timing.test.ts +++ b/packages/browser-utils/test/metrics/resourceTiming.test.ts @@ -1,8 +1,8 @@ import * as utils from '@sentry/core'; -import * as browserUtils from '@sentry-internal/browser-utils'; import type { MockInstance } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { resourceTimingToSpanAttributes } from '../../src/tracing/resource-timing'; +import { resourceTimingToSpanAttributes } from '../../src/metrics/resourceTiming'; +import * as browserMetricsUtils from '../../src/metrics/utils'; describe('resourceTimingToSpanAttributes', () => { let browserPerformanceTimeOriginSpy: MockInstance; @@ -11,7 +11,7 @@ describe('resourceTimingToSpanAttributes', () => { beforeEach(() => { vi.clearAllMocks(); browserPerformanceTimeOriginSpy = vi.spyOn(utils, 'browserPerformanceTimeOrigin'); - extractNetworkProtocolSpy = vi.spyOn(browserUtils, 'extractNetworkProtocol'); + extractNetworkProtocolSpy = vi.spyOn(browserMetricsUtils, 'extractNetworkProtocol'); }); afterEach(() => { @@ -48,7 +48,7 @@ describe('resourceTimingToSpanAttributes', () => { }; describe('with network protocol information', () => { - it('should extract network protocol when nextHopProtocol is available', () => { + it('extracts network protocol when nextHopProtocol is available', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: 'h2', }); @@ -70,16 +70,16 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); expect(extractNetworkProtocolSpy).toHaveBeenCalledWith('h2'); - expect(result).toEqual([ - ['network.protocol.version', '2.0'], - ['network.protocol.name', 'http'], - ]); + expect(result).toEqual({ + 'network.protocol.version': '2.0', + 'network.protocol.name': 'http', + }); // Restore global performance global.performance = originalPerformance; }); - it('should handle different network protocols', () => { + it('handles different network protocols', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: 'http/1.1', }); @@ -101,16 +101,16 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); expect(extractNetworkProtocolSpy).toHaveBeenCalledWith('http/1.1'); - expect(result).toEqual([ - ['network.protocol.version', '1.1'], - ['network.protocol.name', 'http'], - ]); + expect(result).toEqual({ + 'network.protocol.version': '1.1', + 'network.protocol.name': 'http', + }); // Restore global performance global.performance = originalPerformance; }); - it('should extract network protocol even when nextHopProtocol is empty', () => { + it('extracts network protocol even when nextHopProtocol is empty', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: '', }); @@ -132,16 +132,16 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); expect(extractNetworkProtocolSpy).toHaveBeenCalledWith(''); - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + }); // Restore global performance global.performance = originalPerformance; }); - it('should not extract network protocol when nextHopProtocol is undefined', () => { + it("doesn't extract network protocol when nextHopProtocol is undefined", () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: undefined as any, }); @@ -158,7 +158,7 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); expect(extractNetworkProtocolSpy).not.toHaveBeenCalled(); - expect(result).toEqual([]); + expect(result).toEqual({}); // Restore global performance global.performance = originalPerformance; @@ -166,7 +166,7 @@ describe('resourceTimingToSpanAttributes', () => { }); describe('without browserPerformanceTimeOrigin', () => { - it('should return only network protocol data when browserPerformanceTimeOrigin is not available', () => { + it('returns only network protocol data when browserPerformanceTimeOrigin is not available', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: 'h2', }); @@ -187,16 +187,16 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', '2.0'], - ['network.protocol.name', 'http'], - ]); + expect(result).toEqual({ + 'network.protocol.version': '2.0', + 'network.protocol.name': 'http', + }); // Restore global performance global.performance = originalPerformance; }); - it('should return network protocol attributes even when empty string and no browserPerformanceTimeOrigin', () => { + it('returns network protocol attributes even when empty string and no browserPerformanceTimeOrigin', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: '', }); @@ -217,10 +217,10 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + }); // Restore global performance global.performance = originalPerformance; @@ -232,10 +232,12 @@ describe('resourceTimingToSpanAttributes', () => { browserPerformanceTimeOriginSpy.mockReturnValue(1000000); // 1 second in milliseconds }); - it('should include all timing attributes when browserPerformanceTimeOrigin is available', () => { + it('includes all timing attributes when browserPerformanceTimeOrigin is available', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: 'h2', redirectStart: 10, + redirectEnd: 20, + workerStart: 22, fetchStart: 25, domainLookupStart: 30, domainLookupEnd: 35, @@ -254,23 +256,26 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', '2.0'], - ['network.protocol.name', 'http'], - ['http.request.redirect_start', 1000.01], // (1000000 + 10) / 1000 - ['http.request.fetch_start', 1000.025], // (1000000 + 25) / 1000 - ['http.request.domain_lookup_start', 1000.03], // (1000000 + 30) / 1000 - ['http.request.domain_lookup_end', 1000.035], // (1000000 + 35) / 1000 - ['http.request.connect_start', 1000.04], // (1000000 + 40) / 1000 - ['http.request.secure_connection_start', 1000.045], // (1000000 + 45) / 1000 - ['http.request.connection_end', 1000.05], // (1000000 + 50) / 1000 - ['http.request.request_start', 1000.055], // (1000000 + 55) / 1000 - ['http.request.response_start', 1000.15], // (1000000 + 150) / 1000 - ['http.request.response_end', 1000.2], // (1000000 + 200) / 1000 - ]); + expect(result).toEqual({ + 'network.protocol.version': '2.0', + 'network.protocol.name': 'http', + 'http.request.redirect_start': 1000.01, // (1000000 + 10) / 1000 + 'http.request.redirect_end': 1000.02, // (1000000 + 20) / 1000 + 'http.request.worker_start': 1000.022, // (1000000 + 22) / 1000 + 'http.request.fetch_start': 1000.025, // (1000000 + 25) / 1000 + 'http.request.domain_lookup_start': 1000.03, // (1000000 + 30) / 1000 + 'http.request.domain_lookup_end': 1000.035, // (1000000 + 35) / 1000 + 'http.request.connect_start': 1000.04, // (1000000 + 40) / 1000 + 'http.request.secure_connection_start': 1000.045, // (1000000 + 45) / 1000 + 'http.request.connection_end': 1000.05, // (1000000 + 50) / 1000 + 'http.request.request_start': 1000.055, // (1000000 + 55) / 1000 + 'http.request.response_start': 1000.15, // (1000000 + 150) / 1000 + 'http.request.response_end': 1000.2, // (1000000 + 200) / 1000 + 'http.request.time_to_first_byte': 0.15, // 150 / 1000 + }); }); - it('should handle zero timing values', () => { + it('handles zero timing values', () => { extractNetworkProtocolSpy.mockReturnValue({ name: '', version: 'unknown', @@ -292,23 +297,26 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ['http.request.redirect_start', 1000], // (1000000 + 0) / 1000 - ['http.request.fetch_start', 1000], - ['http.request.domain_lookup_start', 1000], - ['http.request.domain_lookup_end', 1000], - ['http.request.connect_start', 1000], - ['http.request.secure_connection_start', 1000], - ['http.request.connection_end', 1000], - ['http.request.request_start', 1000], - ['http.request.response_start', 1000], - ['http.request.response_end', 1000], - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + 'http.request.redirect_start': 1000, // (1000000 + 0) / 1000 + 'http.request.redirect_end': 1000.02, + 'http.request.worker_start': 1000, + 'http.request.fetch_start': 1000, + 'http.request.domain_lookup_start': 1000, + 'http.request.domain_lookup_end': 1000, + 'http.request.connect_start': 1000, + 'http.request.secure_connection_start': 1000, + 'http.request.connection_end': 1000, + 'http.request.request_start': 1000, + 'http.request.response_start': 1000, + 'http.request.response_end': 1000, + 'http.request.time_to_first_byte': 0, + }); }); - it('should combine network protocol and timing attributes', () => { + it('combines network protocol and timing attributes', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: 'http/1.1', redirectStart: 5, @@ -330,25 +338,28 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', '1.1'], - ['network.protocol.name', 'http'], - ['http.request.redirect_start', 1000.005], - ['http.request.fetch_start', 1000.01], - ['http.request.domain_lookup_start', 1000.015], - ['http.request.domain_lookup_end', 1000.02], - ['http.request.connect_start', 1000.025], - ['http.request.secure_connection_start', 1000.03], - ['http.request.connection_end', 1000.035], - ['http.request.request_start', 1000.04], - ['http.request.response_start', 1000.08], - ['http.request.response_end', 1000.1], - ]); + expect(result).toEqual({ + 'network.protocol.version': '1.1', + 'network.protocol.name': 'http', + 'http.request.redirect_start': 1000.005, + 'http.request.redirect_end': 1000.02, + 'http.request.worker_start': 1000, + 'http.request.fetch_start': 1000.01, + 'http.request.domain_lookup_start': 1000.015, + 'http.request.domain_lookup_end': 1000.02, + 'http.request.connect_start': 1000.025, + 'http.request.secure_connection_start': 1000.03, + 'http.request.connection_end': 1000.035, + 'http.request.request_start': 1000.04, + 'http.request.response_start': 1000.08, + 'http.request.response_end': 1000.1, + 'http.request.time_to_first_byte': 0.08, + }); }); }); describe('fallback to performance.timeOrigin', () => { - it('should use performance.timeOrigin when browserPerformanceTimeOrigin returns null', () => { + it('uses performance.timeOrigin when browserPerformanceTimeOrigin returns null', () => { // Mock browserPerformanceTimeOrigin to return null for the main check browserPerformanceTimeOriginSpy.mockReturnValue(null); @@ -374,13 +385,13 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); // When browserPerformanceTimeOrigin returns null, function returns early with only network protocol attributes - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + }); }); - it('should use performance.timeOrigin fallback in getAbsoluteTime when available', () => { + it('uses performance.timeOrigin fallback in getAbsoluteTime when available', () => { // Mock browserPerformanceTimeOrigin to return 500000 for the main check browserPerformanceTimeOriginSpy.mockReturnValue(500000); @@ -392,6 +403,8 @@ describe('resourceTimingToSpanAttributes', () => { const mockResourceTiming = createMockResourceTiming({ nextHopProtocol: '', redirectStart: 20, + redirectEnd: 30, + workerStart: 35, fetchStart: 40, domainLookupStart: 60, domainLookupEnd: 80, @@ -405,23 +418,26 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ['http.request.redirect_start', 500.02], // (500000 + 20) / 1000 - ['http.request.fetch_start', 500.04], // (500000 + 40) / 1000 - ['http.request.domain_lookup_start', 500.06], // (500000 + 60) / 1000 - ['http.request.domain_lookup_end', 500.08], // (500000 + 80) / 1000 - ['http.request.connect_start', 500.1], // (500000 + 100) / 1000 - ['http.request.secure_connection_start', 500.12], // (500000 + 120) / 1000 - ['http.request.connection_end', 500.14], // (500000 + 140) / 1000 - ['http.request.request_start', 500.16], // (500000 + 160) / 1000 - ['http.request.response_start', 500.3], // (500000 + 300) / 1000 - ['http.request.response_end', 500.4], // (500000 + 400) / 1000 - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + 'http.request.redirect_start': 500.02, // (500000 + 20) / 1000 + 'http.request.redirect_end': 500.03, // (500000 + 30) / 1000 + 'http.request.worker_start': 500.035, // (500000 + 35) / 1000 + 'http.request.fetch_start': 500.04, // (500000 + 40) / 1000 + 'http.request.domain_lookup_start': 500.06, // (500000 + 60) / 1000 + 'http.request.domain_lookup_end': 500.08, // (500000 + 80) / 1000 + 'http.request.connect_start': 500.1, // (500000 + 100) / 1000 + 'http.request.secure_connection_start': 500.12, // (500000 + 120) / 1000 + 'http.request.connection_end': 500.14, // (500000 + 140) / 1000 + 'http.request.request_start': 500.16, // (500000 + 160) / 1000 + 'http.request.response_start': 500.3, // (500000 + 300) / 1000 + 'http.request.response_end': 500.4, // (500000 + 400) / 1000 + 'http.request.time_to_first_byte': 0.3, // 300 / 1000 + }); }); - it('should handle case when neither browserPerformanceTimeOrigin nor performance.timeOrigin is available', () => { + it('handles case when neither browserPerformanceTimeOrigin nor performance.timeOrigin is available', () => { browserPerformanceTimeOriginSpy.mockReturnValue(null); extractNetworkProtocolSpy.mockReturnValue({ @@ -443,10 +459,10 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); // When neither timing source is available, should return network protocol attributes for empty string - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + }); // Restore global performance global.performance = originalPerformance; @@ -454,7 +470,7 @@ describe('resourceTimingToSpanAttributes', () => { }); describe('edge cases', () => { - it('should handle undefined timing values', () => { + it('handles undefined timing values', () => { browserPerformanceTimeOriginSpy.mockReturnValue(1000000); extractNetworkProtocolSpy.mockReturnValue({ @@ -466,6 +482,7 @@ describe('resourceTimingToSpanAttributes', () => { nextHopProtocol: '', redirectStart: undefined as any, fetchStart: undefined as any, + workerStart: undefined as any, domainLookupStart: undefined as any, domainLookupEnd: undefined as any, connectStart: undefined as any, @@ -478,23 +495,26 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ['http.request.redirect_start', 1000], // (1000000 + 0) / 1000 - ['http.request.fetch_start', 1000], - ['http.request.domain_lookup_start', 1000], - ['http.request.domain_lookup_end', 1000], - ['http.request.connect_start', 1000], - ['http.request.secure_connection_start', 1000], - ['http.request.connection_end', 1000], - ['http.request.request_start', 1000], - ['http.request.response_start', 1000], - ['http.request.response_end', 1000], - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + 'http.request.redirect_start': 1000, // (1000000 + 0) / 1000 + 'http.request.redirect_end': 1000.02, + 'http.request.worker_start': 1000, + 'http.request.fetch_start': 1000, + 'http.request.domain_lookup_start': 1000, + 'http.request.domain_lookup_end': 1000, + 'http.request.connect_start': 1000, + 'http.request.secure_connection_start': 1000, + 'http.request.connection_end': 1000, + 'http.request.request_start': 1000, + 'http.request.response_start': 1000, + 'http.request.response_end': 1000, + 'http.request.time_to_first_byte': 0, + }); }); - it('should handle very large timing values', () => { + it('handles very large timing values', () => { browserPerformanceTimeOriginSpy.mockReturnValue(1000000); extractNetworkProtocolSpy.mockReturnValue({ @@ -518,20 +538,23 @@ describe('resourceTimingToSpanAttributes', () => { const result = resourceTimingToSpanAttributes(mockResourceTiming); - expect(result).toEqual([ - ['network.protocol.version', 'unknown'], - ['network.protocol.name', ''], - ['http.request.redirect_start', 1999.999], // (1000000 + 999999) / 1000 - ['http.request.fetch_start', 1999.999], - ['http.request.domain_lookup_start', 1999.999], - ['http.request.domain_lookup_end', 1999.999], - ['http.request.connect_start', 1999.999], - ['http.request.secure_connection_start', 1999.999], - ['http.request.connection_end', 1999.999], - ['http.request.request_start', 1999.999], - ['http.request.response_start', 1999.999], - ['http.request.response_end', 1999.999], - ]); + expect(result).toEqual({ + 'network.protocol.version': 'unknown', + 'network.protocol.name': '', + 'http.request.redirect_start': 1999.999, // (1000000 + 999999) / 1000 + 'http.request.redirect_end': 1000.02, + 'http.request.worker_start': 1000, + 'http.request.fetch_start': 1999.999, + 'http.request.domain_lookup_start': 1999.999, + 'http.request.domain_lookup_end': 1999.999, + 'http.request.connect_start': 1999.999, + 'http.request.secure_connection_start': 1999.999, + 'http.request.connection_end': 1999.999, + 'http.request.request_start': 1999.999, + 'http.request.response_start': 1999.999, + 'http.request.response_end': 1999.999, + 'http.request.time_to_first_byte': 999.999, + }); }); }); }); diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 0bc523506454..35de77f611d0 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -16,6 +16,7 @@ export { extraErrorDataIntegration, rewriteFramesIntegration, consoleLoggingIntegration, + createConsolaReporter, } from '@sentry/core'; export { replayIntegration, getReplay } from '@sentry-internal/replay'; diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index cd63678de16f..305b1e0322a0 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -5,6 +5,7 @@ import { browserPerformanceTimeOrigin, dateTimestampInSeconds, debug, + generateSpanId, generateTraceId, getClient, getCurrentScope, @@ -12,6 +13,7 @@ import { getIsolationScope, getLocationHref, GLOBAL_OBJ, + hasSpansEnabled, parseStringToURLObject, propagationContextFromHeaders, registerSpanErrorInstrumentation, @@ -512,10 +514,19 @@ export const browserTracingIntegration = ((_options: Partial { entries.forEach(entry => { if (isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) { - const spanAttributes = resourceTimingToSpanAttributes(entry); - spanAttributes.forEach(attributeArray => span.setAttribute(...attributeArray)); + span.setAttributes(resourceTimingToSpanAttributes(entry)); // In the next tick, clean this handler up // We have to wait here because otherwise this cleans itself up before it is fully done setTimeout(cleanup); diff --git a/packages/browser/src/tracing/resource-timing.ts b/packages/browser/src/tracing/resource-timing.ts deleted file mode 100644 index c741a7e91016..000000000000 --- a/packages/browser/src/tracing/resource-timing.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { Span } from '@sentry/core'; -import { browserPerformanceTimeOrigin } from '@sentry/core'; -import { extractNetworkProtocol } from '@sentry-internal/browser-utils'; - -function getAbsoluteTime(time: number = 0): number { - return ((browserPerformanceTimeOrigin() || performance.timeOrigin) + time) / 1000; -} - -/** - * Converts a PerformanceResourceTiming entry to span data for the resource span. - * - * @param resourceTiming - * @returns An array where the first element is the attribute name and the second element is the attribute value. - */ -export function resourceTimingToSpanAttributes( - resourceTiming: PerformanceResourceTiming, -): Array> { - const timingSpanData: Array> = []; - // Checking for only `undefined` and `null` is intentional because it's - // valid for `nextHopProtocol` to be an empty string. - if (resourceTiming.nextHopProtocol != undefined) { - const { name, version } = extractNetworkProtocol(resourceTiming.nextHopProtocol); - timingSpanData.push(['network.protocol.version', version], ['network.protocol.name', name]); - } - if (!browserPerformanceTimeOrigin()) { - return timingSpanData; - } - return [ - ...timingSpanData, - ['http.request.redirect_start', getAbsoluteTime(resourceTiming.redirectStart)], - ['http.request.fetch_start', getAbsoluteTime(resourceTiming.fetchStart)], - ['http.request.domain_lookup_start', getAbsoluteTime(resourceTiming.domainLookupStart)], - ['http.request.domain_lookup_end', getAbsoluteTime(resourceTiming.domainLookupEnd)], - ['http.request.connect_start', getAbsoluteTime(resourceTiming.connectStart)], - ['http.request.secure_connection_start', getAbsoluteTime(resourceTiming.secureConnectionStart)], - ['http.request.connection_end', getAbsoluteTime(resourceTiming.connectEnd)], - ['http.request.request_start', getAbsoluteTime(resourceTiming.requestStart)], - ['http.request.response_start', getAbsoluteTime(resourceTiming.responseStart)], - ['http.request.response_end', getAbsoluteTime(resourceTiming.responseEnd)], - ]; -} diff --git a/packages/browser/src/transports/fetch.ts b/packages/browser/src/transports/fetch.ts index d21ae82486ec..f690f015f281 100644 --- a/packages/browser/src/transports/fetch.ts +++ b/packages/browser/src/transports/fetch.ts @@ -1,5 +1,5 @@ import type { Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/core'; -import { createTransport, rejectedSyncPromise } from '@sentry/core'; +import { createTransport } from '@sentry/core'; import { clearCachedImplementation, getNativeImplementation } from '@sentry-internal/browser-utils'; import type { WINDOW } from '../helpers'; import type { BrowserTransportOptions } from './types'; @@ -9,12 +9,12 @@ import type { BrowserTransportOptions } from './types'; */ export function makeFetchTransport( options: BrowserTransportOptions, - nativeFetch: typeof WINDOW.fetch | undefined = getNativeImplementation('fetch'), + nativeFetch: typeof WINDOW.fetch = getNativeImplementation('fetch'), ): Transport { let pendingBodySize = 0; let pendingCount = 0; - function makeRequest(request: TransportRequest): PromiseLike { + async function makeRequest(request: TransportRequest): Promise { const requestSize = request.body.length; pendingBodySize += requestSize; pendingCount++; @@ -39,29 +39,23 @@ export function makeFetchTransport( ...options.fetchOptions, }; - if (!nativeFetch) { - clearCachedImplementation('fetch'); - return rejectedSyncPromise('No fetch implementation available'); - } - try { - // Note: We do not need to suppress tracing here, becasue we are using the native fetch, instead of our wrapped one. - return nativeFetch(options.url, requestOptions).then(response => { - pendingBodySize -= requestSize; - pendingCount--; - return { - statusCode: response.status, - headers: { - 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'), - 'retry-after': response.headers.get('Retry-After'), - }, - }; - }); + // Note: We do not need to suppress tracing here, because we are using the native fetch, instead of our wrapped one. + const response = await nativeFetch(options.url, requestOptions); + + return { + statusCode: response.status, + headers: { + 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'), + 'retry-after': response.headers.get('Retry-After'), + }, + }; } catch (e) { clearCachedImplementation('fetch'); + throw e; + } finally { pendingBodySize -= requestSize; pendingCount--; - return rejectedSyncPromise(e); } } diff --git a/packages/browser/test/tracing/browserTracingIntegration.test.ts b/packages/browser/test/tracing/browserTracingIntegration.test.ts index 6a5d8c3b4894..7e573cae1866 100644 --- a/packages/browser/test/tracing/browserTracingIntegration.test.ts +++ b/packages/browser/test/tracing/browserTracingIntegration.test.ts @@ -723,6 +723,7 @@ describe('browserTracingIntegration', () => { expect(oldCurrentScopePropCtx).toEqual({ traceId: expect.stringMatching(/[a-f0-9]{32}/), + propagationSpanId: expect.stringMatching(/[a-f0-9]{16}/), sampleRand: expect.any(Number), }); expect(oldIsolationScopePropCtx).toEqual({ @@ -731,15 +732,18 @@ describe('browserTracingIntegration', () => { }); expect(newCurrentScopePropCtx).toEqual({ traceId: expect.stringMatching(/[a-f0-9]{32}/), + propagationSpanId: expect.stringMatching(/[a-f0-9]{16}/), sampleRand: expect.any(Number), }); expect(newIsolationScopePropCtx).toEqual({ traceId: expect.stringMatching(/[a-f0-9]{32}/), + propagationSpanId: expect.stringMatching(/[a-f0-9]{16}/), sampleRand: expect.any(Number), }); expect(newIsolationScopePropCtx.traceId).not.toEqual(oldIsolationScopePropCtx.traceId); expect(newCurrentScopePropCtx.traceId).not.toEqual(oldCurrentScopePropCtx.traceId); + expect(newIsolationScopePropCtx.propagationSpanId).not.toEqual(oldIsolationScopePropCtx.propagationSpanId); }); it("saves the span's positive sampling decision and its DSC on the propagationContext when the span finishes", () => { @@ -758,7 +762,7 @@ describe('browserTracingIntegration', () => { }); const propCtxBeforeEnd = getCurrentScope().getPropagationContext(); - expect(propCtxBeforeEnd).toStrictEqual({ + expect(propCtxBeforeEnd).toEqual({ sampleRand: expect.any(Number), traceId: expect.stringMatching(/[a-f0-9]{32}/), }); @@ -766,7 +770,7 @@ describe('browserTracingIntegration', () => { navigationSpan!.end(); const propCtxAfterEnd = getCurrentScope().getPropagationContext(); - expect(propCtxAfterEnd).toStrictEqual({ + expect(propCtxAfterEnd).toEqual({ traceId: propCtxBeforeEnd.traceId, sampled: true, sampleRand: expect.any(Number), @@ -800,7 +804,7 @@ describe('browserTracingIntegration', () => { }); const propCtxBeforeEnd = getCurrentScope().getPropagationContext(); - expect(propCtxBeforeEnd).toStrictEqual({ + expect(propCtxBeforeEnd).toEqual({ traceId: expect.stringMatching(/[a-f0-9]{32}/), sampleRand: expect.any(Number), }); @@ -808,7 +812,7 @@ describe('browserTracingIntegration', () => { navigationSpan!.end(); const propCtxAfterEnd = getCurrentScope().getPropagationContext(); - expect(propCtxAfterEnd).toStrictEqual({ + expect(propCtxAfterEnd).toEqual({ traceId: propCtxBeforeEnd.traceId, sampled: false, sampleRand: expect.any(Number), diff --git a/packages/browser/test/transports/fetch.test.ts b/packages/browser/test/transports/fetch.test.ts index cf8f8810531f..d330fe886d5f 100644 --- a/packages/browser/test/transports/fetch.test.ts +++ b/packages/browser/test/transports/fetch.test.ts @@ -1,7 +1,7 @@ import type { EventEnvelope, EventItem } from '@sentry/core'; import { createEnvelope, serializeEnvelope } from '@sentry/core'; import type { Mock } from 'vitest'; -import { describe, expect, it, vi } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { makeFetchTransport } from '../../src/transports/fetch'; import type { BrowserTransportOptions } from '../../src/transports/types'; @@ -29,7 +29,11 @@ class Headers { } } -describe('NewFetchTransport', () => { +describe('fetchTransport', () => { + afterEach(() => { + vi.resetAllMocks(); + }); + it('calls fetch with the given URL', async () => { const mockFetch = vi.fn(() => Promise.resolve({ @@ -102,15 +106,28 @@ describe('NewFetchTransport', () => { }); }); - it('handles when `getNativetypeof window.fetchementation` is undefined', async () => { + it('handles when native fetch implementation returns undefined', async () => { const mockFetch = vi.fn(() => undefined) as unknown as typeof window.fetch; const transport = makeFetchTransport(DEFAULT_FETCH_TRANSPORT_OPTIONS, mockFetch); expect(mockFetch).toHaveBeenCalledTimes(0); - await expect(() => transport.send(ERROR_ENVELOPE)).not.toThrow(); + await expect(() => transport.send(ERROR_ENVELOPE)).rejects.toThrow( + "Cannot read properties of undefined (reading 'status')", + ); expect(mockFetch).toHaveBeenCalledTimes(1); }); + it('handles when native fetch implementation is undefined', async () => { + vi.mock('@sentry-internal/browser-utils', async importOriginal => ({ + ...(await importOriginal()), + getNativeImplementation: () => undefined, + })); + + const transport = makeFetchTransport(DEFAULT_FETCH_TRANSPORT_OPTIONS); + + await expect(() => transport.send(ERROR_ENVELOPE)).rejects.toThrow('nativeFetch is not a function'); + }); + it('correctly sets keepalive flag', async () => { const mockFetch = vi.fn(() => Promise.resolve({ diff --git a/packages/bun/src/index.ts b/packages/bun/src/index.ts index e0ce86b1bd23..bc5bf37c0de4 100644 --- a/packages/bun/src/index.ts +++ b/packages/bun/src/index.ts @@ -146,6 +146,7 @@ export { vercelAIIntegration, logger, consoleLoggingIntegration, + createConsolaReporter, createSentryWinstonTransport, wrapMcpServerWithSentry, featureFlagsIntegration, diff --git a/packages/bun/src/integrations/bunserver.ts b/packages/bun/src/integrations/bunserver.ts index 9c235b8bc97c..4a079f488474 100644 --- a/packages/bun/src/integrations/bunserver.ts +++ b/packages/bun/src/integrations/bunserver.ts @@ -246,11 +246,8 @@ function wrapRequestHandler( } catch (e) { captureException(e, { mechanism: { - type: 'bun', + type: 'auto.http.bun.serve', handled: false, - data: { - function: 'serve', - }, }, }); throw e; diff --git a/packages/cloudflare/src/durableobject.ts b/packages/cloudflare/src/durableobject.ts index bda7a9aa3538..0f139a80ccd0 100644 --- a/packages/cloudflare/src/durableobject.ts +++ b/packages/cloudflare/src/durableobject.ts @@ -79,7 +79,7 @@ function wrapMethodWithSentry( (e: unknown) => { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); @@ -94,7 +94,7 @@ function wrapMethodWithSentry( } catch (e) { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); @@ -106,7 +106,7 @@ function wrapMethodWithSentry( const attributes = wrapperOptions.spanOp ? { [SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare_durableobjects', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object', } : {}; @@ -123,7 +123,7 @@ function wrapMethodWithSentry( (e: unknown) => { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); @@ -138,7 +138,7 @@ function wrapMethodWithSentry( } catch (e) { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); @@ -243,7 +243,7 @@ export function instrumentDurableObjectWithSentry< (_, error) => captureException(error, { mechanism: { - type: 'cloudflare_durableobject_websocket', + type: 'auto.faas.cloudflare.durable_object_websocket', handled: false, }, }), diff --git a/packages/cloudflare/src/handler.ts b/packages/cloudflare/src/handler.ts index 354233154a0b..a6e5983902c6 100644 --- a/packages/cloudflare/src/handler.ts +++ b/packages/cloudflare/src/handler.ts @@ -59,7 +59,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.scheduled' } }); throw e; } finally { waitUntil(flush(2000)); @@ -138,7 +138,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.email' } }); throw e; } finally { waitUntil(flush(2000)); @@ -188,7 +188,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.queue' } }); throw e; } finally { waitUntil(flush(2000)); @@ -220,7 +220,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.tail' } }); throw e; } finally { waitUntil(flush(2000)); diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts index 23e902c4dc2e..db0e0aab98a7 100644 --- a/packages/cloudflare/src/index.ts +++ b/packages/cloudflare/src/index.ts @@ -70,6 +70,7 @@ export { // eslint-disable-next-line deprecation/deprecation inboundFiltersIntegration, instrumentOpenAiClient, + instrumentAnthropicAiClient, eventFiltersIntegration, linkedErrorsIntegration, requestDataIntegration, @@ -93,6 +94,7 @@ export { updateSpanName, wrapMcpServerWithSentry, consoleLoggingIntegration, + createConsolaReporter, featureFlagsIntegration, } from '@sentry/core'; diff --git a/packages/cloudflare/src/request.ts b/packages/cloudflare/src/request.ts index 45fe548696ab..5c97562d9fde 100644 --- a/packages/cloudflare/src/request.ts +++ b/packages/cloudflare/src/request.ts @@ -84,7 +84,7 @@ export function wrapRequestHandler( return await handler(); } catch (e) { if (captureErrors) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } }); } throw e; } finally { @@ -110,7 +110,7 @@ export function wrapRequestHandler( return res; } catch (e) { if (captureErrors) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } }); } throw e; } finally { diff --git a/packages/cloudflare/src/workflows.ts b/packages/cloudflare/src/workflows.ts index 7ca31d00bbd5..336df2abe301 100644 --- a/packages/cloudflare/src/workflows.ts +++ b/packages/cloudflare/src/workflows.ts @@ -2,6 +2,7 @@ import type { PropagationContext } from '@sentry/core'; import { captureException, flush, + getCurrentScope, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, startSpan, @@ -56,29 +57,6 @@ async function propagationContextFromInstanceId(instanceId: string): Promise( - instanceId: string, - options: CloudflareOptions, - callback: () => V, -): Promise { - setAsyncLocalStorageAsyncContextStrategy(); - - return withIsolationScope(async isolationScope => { - const client = init({ ...options, enableDedupe: false }); - isolationScope.setClient(client); - - addCloudResourceContext(isolationScope); - - return withScope(async scope => { - const propagationContext = await propagationContextFromInstanceId(instanceId); - scope.setPropagationContext(propagationContext); - - // eslint-disable-next-line no-return-await - return await callback(); - }); - }); -} - class WrappedWorkflowStep implements WorkflowStep { public constructor( private _instanceId: string, @@ -98,38 +76,40 @@ class WrappedWorkflowStep implements WorkflowStep { configOrCallback: WorkflowStepConfig | (() => Promise), maybeCallback?: () => Promise, ): Promise { + // Capture the current scope, so parent span (e.g., a startSpan surrounding step.do) is preserved + const scopeForStep = getCurrentScope(); + const userCallback = (maybeCallback || configOrCallback) as () => Promise; const config = typeof configOrCallback === 'function' ? undefined : configOrCallback; const instrumentedCallback: () => Promise = async () => { - return workflowStepWithSentry(this._instanceId, this._options, async () => { - return startSpan( - { - op: 'function.step.do', - name, - attributes: { - 'cloudflare.workflow.timeout': config?.timeout, - 'cloudflare.workflow.retries.backoff': config?.retries?.backoff, - 'cloudflare.workflow.retries.delay': config?.retries?.delay, - 'cloudflare.workflow.retries.limit': config?.retries?.limit, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.workflow', - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'task', - }, - }, - async span => { - try { - const result = await userCallback(); - span.setStatus({ code: 1 }); - return result; - } catch (error) { - captureException(error, { mechanism: { handled: true, type: 'cloudflare' } }); - throw error; - } finally { - this._ctx.waitUntil(flush(2000)); - } + return startSpan( + { + op: 'function.step.do', + name, + scope: scopeForStep, + attributes: { + 'cloudflare.workflow.timeout': config?.timeout, + 'cloudflare.workflow.retries.backoff': config?.retries?.backoff, + 'cloudflare.workflow.retries.delay': config?.retries?.delay, + 'cloudflare.workflow.retries.limit': config?.retries?.limit, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.workflow', + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'task', }, - ); - }); + }, + async span => { + try { + const result = await userCallback(); + span.setStatus({ code: 1 }); + return result; + } catch (error) { + captureException(error, { mechanism: { handled: true, type: 'auto.faas.cloudflare.workflow' } }); + throw error; + } finally { + this._ctx.waitUntil(flush(2000)); + } + }, + ); }; return config ? this._step.do(name, config, instrumentedCallback) : this._step.do(name, instrumentedCallback); @@ -183,7 +163,29 @@ export function instrumentWorkflowWithSentry< get(obj, prop, receiver) { if (prop === 'run') { return async function (event: WorkflowEvent

, step: WorkflowStep): Promise { - return obj.run.call(obj, event, new WrappedWorkflowStep(event.instanceId, ctx, options, step)); + setAsyncLocalStorageAsyncContextStrategy(); + + return withIsolationScope(async isolationScope => { + const client = init({ ...options, enableDedupe: false }); + isolationScope.setClient(client); + + addCloudResourceContext(isolationScope); + + return withScope(async scope => { + const propagationContext = await propagationContextFromInstanceId(event.instanceId); + scope.setPropagationContext(propagationContext); + + try { + return await obj.run.call( + obj, + event, + new WrappedWorkflowStep(event.instanceId, ctx, options, step), + ); + } finally { + ctx.waitUntil(flush(2000)); + } + }); + }); }; } return Reflect.get(obj, prop, receiver); diff --git a/packages/cloudflare/test/handler.test.ts b/packages/cloudflare/test/handler.test.ts index ddd4b0010ec0..97e93199ea31 100644 --- a/packages/cloudflare/test/handler.test.ts +++ b/packages/cloudflare/test/handler.test.ts @@ -305,7 +305,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.scheduled' }, }); }); @@ -545,7 +545,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.email' }, }); }); @@ -784,7 +784,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.queue' }, }); }); @@ -1027,7 +1027,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.tail' }, }); }); @@ -1102,7 +1102,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.error_handler' }, }); expect(errorHandlerResponse?.status).toBe(500); }); diff --git a/packages/cloudflare/test/request.test.ts b/packages/cloudflare/test/request.test.ts index ad323e3c5b5a..d6d0de5824a1 100644 --- a/packages/cloudflare/test/request.test.ts +++ b/packages/cloudflare/test/request.test.ts @@ -192,7 +192,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.http.cloudflare' }, }); }); diff --git a/packages/cloudflare/test/workflow.test.ts b/packages/cloudflare/test/workflow.test.ts index c403023fb525..2ca2ccd28e46 100644 --- a/packages/cloudflare/test/workflow.test.ts +++ b/packages/cloudflare/test/workflow.test.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/unbound-method */ +import { startSpan } from '@sentry/core'; import type { WorkflowEvent, WorkflowStep, WorkflowStepConfig } from 'cloudflare:workers'; import { beforeEach, describe, expect, test, vi } from 'vitest'; import { deterministicTraceIdFromInstanceId, instrumentWorkflowWithSentry } from '../src/workflows'; @@ -96,7 +97,8 @@ describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { expect(mockStep.do).toHaveBeenCalledTimes(1); expect(mockStep.do).toHaveBeenCalledWith('first step', expect.any(Function)); - expect(mockContext.waitUntil).toHaveBeenCalledTimes(1); + // We flush after the step.do and at the end of the run + expect(mockContext.waitUntil).toHaveBeenCalledTimes(2); expect(mockContext.waitUntil).toHaveBeenCalledWith(expect.any(Promise)); expect(mockTransport.send).toHaveBeenCalledTimes(1); expect(mockTransport.send).toHaveBeenCalledWith([ @@ -161,7 +163,8 @@ describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { expect(mockStep.do).toHaveBeenCalledTimes(1); expect(mockStep.do).toHaveBeenCalledWith('first step', expect.any(Function)); - expect(mockContext.waitUntil).toHaveBeenCalledTimes(1); + // We flush after the step.do and at the end of the run + expect(mockContext.waitUntil).toHaveBeenCalledTimes(2); expect(mockContext.waitUntil).toHaveBeenCalledWith(expect.any(Promise)); expect(mockTransport.send).toHaveBeenCalledTimes(1); expect(mockTransport.send).toHaveBeenCalledWith([ @@ -232,8 +235,10 @@ describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { expect(mockStep.do).toHaveBeenCalledTimes(1); expect(mockStep.do).toHaveBeenCalledWith('sometimes error step', expect.any(Function)); - expect(mockContext.waitUntil).toHaveBeenCalledTimes(2); + // One flush for the error transaction, one for the retry success, one at end of run + expect(mockContext.waitUntil).toHaveBeenCalledTimes(3); expect(mockContext.waitUntil).toHaveBeenCalledWith(expect.any(Promise)); + // error event + failed transaction + successful retry transaction expect(mockTransport.send).toHaveBeenCalledTimes(3); // First we should get the error event @@ -267,7 +272,7 @@ describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { expect.objectContaining({ type: 'Error', value: 'Test error', - mechanism: { type: 'cloudflare', handled: true }, + mechanism: { type: 'auto.faas.cloudflare.workflow', handled: true }, }), ], }, @@ -376,11 +381,11 @@ describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { expect(mockStep.do).toHaveBeenCalledTimes(1); expect(mockStep.do).toHaveBeenCalledWith('sometimes error step', expect.any(Function)); - expect(mockContext.waitUntil).toHaveBeenCalledTimes(2); + // One flush for the error event and one at end of run + expect(mockContext.waitUntil).toHaveBeenCalledTimes(3); expect(mockContext.waitUntil).toHaveBeenCalledWith(expect.any(Promise)); - // We should get the error event and then nothing else. No transactions - // should be sent + // We should get the error event and then nothing else. No transactions should be sent expect(mockTransport.send).toHaveBeenCalledTimes(1); expect(mockTransport.send).toHaveBeenCalledWith([ @@ -421,4 +426,41 @@ describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { ], ]); }); + + test('Step.do span becomes child of surrounding custom span', async () => { + class ParentChildWorkflow { + constructor(_ctx: ExecutionContext, _env: unknown) {} + + async run(_event: Readonly>, step: WorkflowStep): Promise { + await startSpan({ name: 'custom span' }, async () => { + await step.do('first step', async () => { + return { files: ['a'] }; + }); + }); + } + } + + const TestWorkflowInstrumented = instrumentWorkflowWithSentry(getSentryOptions, ParentChildWorkflow as any); + const workflow = new TestWorkflowInstrumented(mockContext, {}) as ParentChildWorkflow; + const event = { payload: {}, timestamp: new Date(), instanceId: INSTANCE_ID }; + await workflow.run(event, mockStep); + + // Flush after step.do and at end of run + expect(mockContext.waitUntil).toHaveBeenCalledTimes(2); + expect(mockTransport.send).toHaveBeenCalledTimes(1); + + const sendArg = mockTransport.send.mock.calls[0]![0] as any; + const items = sendArg[1] as any[]; + const rootSpanItem = items.find(i => i[0].type === 'transaction'); + expect(rootSpanItem).toBeDefined(); + const rootSpan = rootSpanItem[1]; + + expect(rootSpan.transaction).toBe('custom span'); + const rootSpanId = rootSpan.contexts.trace.span_id; + + // Child span for the step.do with the custom span as parent + const stepSpan = rootSpan.spans.find((s: any) => s.description === 'first step' && s.op === 'function.step.do'); + expect(stepSpan).toBeDefined(); + expect(stepSpan.parent_span_id).toBe(rootSpanId); + }); }); diff --git a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts index 5c40d53174c1..e43160cc03ab 100644 --- a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts +++ b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts @@ -257,6 +257,13 @@ interface ReleaseOptions { */ name?: string; + /** + * Whether the plugin should inject release information into the build for the SDK to pick it up when sending events (recommended). + * + * @default true + */ + inject?: boolean; + /** * Whether to create a new release. * diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index 88fab9107874..75a0d5ed49d2 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -415,10 +415,9 @@ export abstract class Client { env = addItemToEnvelope(env, createAttachmentEnvelopeItem(attachment)); } - const promise = this.sendEnvelope(env); - if (promise) { - promise.then(sendResponse => this.emit('afterSendEvent', event, sendResponse), null); - } + // sendEnvelope should not throw + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.sendEnvelope(env).then(sendResponse => this.emit('afterSendEvent', event, sendResponse)); } /** @@ -879,12 +878,11 @@ export abstract class Client { if (this._isEnabled() && this._transport) { return this._transport.send(envelope).then(null, reason => { DEBUG_BUILD && debug.error('Error while sending envelope:', reason); - return reason; + return {}; }); } DEBUG_BUILD && debug.error('Transport disabled'); - return resolvedSyncPromise({}); } diff --git a/packages/core/src/eventProcessors.ts b/packages/core/src/eventProcessors.ts index 3bebe71b9316..ca41e5ee2a03 100644 --- a/packages/core/src/eventProcessors.ts +++ b/packages/core/src/eventProcessors.ts @@ -3,7 +3,7 @@ import type { Event, EventHint } from './types-hoist/event'; import type { EventProcessor } from './types-hoist/eventprocessor'; import { debug } from './utils/debug-logger'; import { isThenable } from './utils/is'; -import { SyncPromise } from './utils/syncpromise'; +import { rejectedSyncPromise, resolvedSyncPromise } from './utils/syncpromise'; /** * Process an array of event processors, returning the processed event (or `null` if the event was dropped). @@ -14,24 +14,33 @@ export function notifyEventProcessors( hint: EventHint, index: number = 0, ): PromiseLike { - return new SyncPromise((resolve, reject) => { - const processor = processors[index]; - if (event === null || typeof processor !== 'function') { - resolve(event); - } else { - const result = processor({ ...event }, hint) as Event | null; + try { + const result = _notifyEventProcessors(event, hint, processors, index); + return isThenable(result) ? result : resolvedSyncPromise(result); + } catch (error) { + return rejectedSyncPromise(error); + } +} + +function _notifyEventProcessors( + event: Event | null, + hint: EventHint, + processors: EventProcessor[], + index: number, +): Event | null | PromiseLike { + const processor = processors[index]; + + if (!event || !processor) { + return event; + } + + const result = processor({ ...event }, hint); + + DEBUG_BUILD && result === null && debug.log(`Event processor "${processor.id || '?'}" dropped event`); - DEBUG_BUILD && processor.id && result === null && debug.log(`Event processor "${processor.id}" dropped event`); + if (isThenable(result)) { + return result.then(final => _notifyEventProcessors(final, hint, processors, index + 1)); + } - if (isThenable(result)) { - void result - .then(final => notifyEventProcessors(processors, final, hint, index + 1).then(resolve)) - .then(null, reject); - } else { - void notifyEventProcessors(processors, result, hint, index + 1) - .then(resolve) - .then(null, reject); - } - } - }); + return _notifyEventProcessors(result, hint, processors, index + 1); } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ef61364ab3f0..b971aa8b43a3 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -124,6 +124,7 @@ export { captureFeedback } from './feedback'; export type { ReportDialogOptions } from './report-dialog'; export { _INTERNAL_captureLog, _INTERNAL_flushLogsBuffer, _INTERNAL_captureSerializedLog } from './logs/exports'; export { consoleLoggingIntegration } from './logs/console-integration'; +export { createConsolaReporter } from './integrations/consola'; export { addVercelAiProcessors } from './utils/vercel-ai'; export { _INTERNAL_getSpanForToolCallId, _INTERNAL_cleanupToolCallSpan } from './utils/vercel-ai/utils'; export { instrumentOpenAiClient } from './utils/openai'; @@ -131,7 +132,12 @@ export { OPENAI_INTEGRATION_NAME } from './utils/openai/constants'; export { instrumentAnthropicAiClient } from './utils/anthropic-ai'; export { ANTHROPIC_AI_INTEGRATION_NAME } from './utils/anthropic-ai/constants'; export type { OpenAiClient, OpenAiOptions, InstrumentedMethod } from './utils/openai/types'; -export type { AnthropicAiClient, AnthropicAiOptions, AnthropicAiInstrumentedMethod } from './utils/anthropic-ai/types'; +export type { + AnthropicAiClient, + AnthropicAiOptions, + AnthropicAiInstrumentedMethod, + AnthropicAiResponse, +} from './utils/anthropic-ai/types'; export type { FeatureFlag } from './utils/featureFlags'; export { @@ -404,7 +410,11 @@ export type { Stacktrace, StackParser, StackLineParser, StackLineParserFn } from export type { PropagationContext, TracePropagationTargets, SerializedTraceData } from './types-hoist/tracing'; export type { StartSpanOptions } from './types-hoist/startSpanOptions'; export type { TraceparentData, TransactionSource } from './types-hoist/transaction'; -export type { CustomSamplingContext, SamplingContext } from './types-hoist/samplingcontext'; +export type { + TracesSamplerSamplingContext, + CustomSamplingContext, + SamplingContext, +} from './types-hoist/samplingcontext'; export type { DurationUnit, InformationUnit, diff --git a/packages/core/src/integrations/captureconsole.ts b/packages/core/src/integrations/captureconsole.ts index e491efedd83f..d5d34bd554aa 100644 --- a/packages/core/src/integrations/captureconsole.ts +++ b/packages/core/src/integrations/captureconsole.ts @@ -65,7 +65,7 @@ function consoleHandler(args: unknown[], level: string, handled: boolean): void addExceptionMechanism(event, { handled, - type: 'console', + type: 'auto.core.capture_console', }); return event; diff --git a/packages/core/src/integrations/consola.ts b/packages/core/src/integrations/consola.ts new file mode 100644 index 000000000000..cdae9efa17dc --- /dev/null +++ b/packages/core/src/integrations/consola.ts @@ -0,0 +1,312 @@ +import type { Client } from '../client'; +import { getClient } from '../currentScopes'; +import { _INTERNAL_captureLog } from '../logs/exports'; +import { formatConsoleArgs } from '../logs/utils'; +import type { LogSeverityLevel } from '../types-hoist/log'; + +/** + * Options for the Sentry Consola reporter. + */ +interface ConsolaReporterOptions { + /** + * Use this option to filter which levels should be captured. By default, all levels are captured. + * + * @example + * ```ts + * const sentryReporter = Sentry.createConsolaReporter({ + * // Only capture error and warn logs + * levels: ['error', 'warn'], + * }); + * consola.addReporter(sentryReporter); + * ``` + */ + levels?: Array; + + /** + * Optionally provide a specific Sentry client instance to use for capturing logs. + * If not provided, the current client will be retrieved using `getClient()`. + * + * This is useful when you want to use specific client options for log normalization + * or when working with multiple client instances. + * + * @example + * ```ts + * const sentryReporter = Sentry.createConsolaReporter({ + * client: myCustomClient, + * }); + * ``` + */ + client?: Client; +} + +export interface ConsolaReporter { + log: (logObj: ConsolaLogObject) => void; +} + +/** + * Represents a log object that Consola reporters receive. + * + * This interface matches the structure of log objects passed to Consola reporters. + * See: https://github.com/unjs/consola#custom-reporters + * + * @example + * ```ts + * const reporter = { + * log(logObj: ConsolaLogObject) { + * console.log(`[${logObj.type}] ${logObj.message || logObj.args?.join(' ')}`); + * } + * }; + * consola.addReporter(reporter); + * ``` + */ +export interface ConsolaLogObject { + /** + * Allows additional custom properties to be set on the log object. + * These properties will be captured as log attributes with a 'consola.' prefix. + * + * @example + * ```ts + * const reporter = Sentry.createConsolaReporter(); + * reporter.log({ + * type: 'info', + * message: 'User action', + * userId: 123, + * sessionId: 'abc-123' + * }); + * // Will create attributes: consola.userId and consola.sessionId + * ``` + */ + [key: string]: unknown; + + /** + * The numeric log level (0-5) or null. + * + * Consola log levels: + * - 0: Fatal and Error + * - 1: Warnings + * - 2: Normal logs + * - 3: Informational logs, success, fail, ready, start, box, ... + * - 4: Debug logs + * - 5: Trace logs + * - null: Some special types like 'verbose' + * + * See: https://github.com/unjs/consola/blob/main/README.md#log-level + */ + level?: number | null; + + /** + * The log type/method name (e.g., 'error', 'warn', 'info', 'debug', 'trace', 'success', 'fail', etc.). + * + * Consola built-in types include: + * - Standard: silent, fatal, error, warn, log, info, success, fail, ready, start, box, debug, trace, verbose + * - Custom types can also be defined + * + * See: https://github.com/unjs/consola/blob/main/README.md#log-types + */ + type?: string; + + /** + * An optional tag/scope for the log entry. + * + * Tags are created using `consola.withTag('scope')` and help categorize logs. + * + * @example + * ```ts + * const scopedLogger = consola.withTag('auth'); + * scopedLogger.info('User logged in'); // tag will be 'auth' + * ``` + * + * See: https://github.com/unjs/consola/blob/main/README.md#withtagtag + */ + tag?: string; + + /** + * The raw arguments passed to the log method. + * + * When `message` is not provided, these args are typically formatted into the final message. + * + * @example + * ```ts + * consola.info('Hello', 'world', { user: 'john' }); + * // args = ['Hello', 'world', { user: 'john' }] + * ``` + */ + args?: unknown[]; + + /** + * The timestamp when the log was created. + * + * This is automatically set by Consola when the log is created. + */ + date?: Date; + + /** + * The formatted log message. + * + * When provided, this is the final formatted message. When not provided, + * the message should be constructed from the `args` array. + */ + message?: string; +} + +const DEFAULT_CAPTURED_LEVELS: Array = ['trace', 'debug', 'info', 'warn', 'error', 'fatal']; + +/** + * Creates a new Sentry reporter for Consola that forwards logs to Sentry. Requires the `enableLogs` option to be enabled. + * + * **Note: This integration supports Consola v3.x only.** The reporter interface and log object structure + * may differ in other versions of Consola. + * + * @param options - Configuration options for the reporter. + * @returns A Consola reporter that can be added to consola instances. + * + * @example + * ```ts + * import * as Sentry from '@sentry/node'; + * import { consola } from 'consola'; + * + * Sentry.init({ + * enableLogs: true, + * }); + * + * const sentryReporter = Sentry.createConsolaReporter({ + * // Optional: filter levels to capture + * levels: ['error', 'warn', 'info'], + * }); + * + * consola.addReporter(sentryReporter); + * + * // Now consola logs will be captured by Sentry + * consola.info('This will be sent to Sentry'); + * consola.error('This error will also be sent to Sentry'); + * ``` + */ +export function createConsolaReporter(options: ConsolaReporterOptions = {}): ConsolaReporter { + const levels = new Set(options.levels ?? DEFAULT_CAPTURED_LEVELS); + const providedClient = options.client; + + return { + log(logObj: ConsolaLogObject) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { type, level, message: consolaMessage, args, tag, date: _date, ...attributes } = logObj; + + // Get client - use provided client or current client + const client = providedClient || getClient(); + if (!client) { + return; + } + + // Determine the log severity level + const logSeverityLevel = getLogSeverityLevel(type, level); + + // Early exit if this level should not be captured + if (!levels.has(logSeverityLevel)) { + return; + } + + const { normalizeDepth = 3, normalizeMaxBreadth = 1_000 } = client.getOptions(); + + // Format the log message using the same approach as consola's basic reporter + const messageParts = []; + if (consolaMessage) { + messageParts.push(consolaMessage); + } + if (args && args.length > 0) { + messageParts.push(formatConsoleArgs(args, normalizeDepth, normalizeMaxBreadth)); + } + const message = messageParts.join(' '); + + // Build attributes + attributes['sentry.origin'] = 'auto.logging.consola'; + + if (tag) { + attributes['consola.tag'] = tag; + } + + if (type) { + attributes['consola.type'] = type; + } + + // Only add level if it's a valid number (not null/undefined) + if (level != null && typeof level === 'number') { + attributes['consola.level'] = level; + } + + _INTERNAL_captureLog({ + level: logSeverityLevel, + message, + attributes, + }); + }, + }; +} + +// Mapping from consola log types to Sentry log severity levels +const CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP: Record = { + // Consola built-in types + silent: 'trace', + fatal: 'fatal', + error: 'error', + warn: 'warn', + log: 'info', + info: 'info', + success: 'info', + fail: 'error', + ready: 'info', + start: 'info', + box: 'info', + debug: 'debug', + trace: 'trace', + verbose: 'debug', + // Custom types that might exist + critical: 'fatal', + notice: 'info', +}; + +// Mapping from consola log levels (numbers) to Sentry log severity levels +const CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP: Record = { + 0: 'fatal', // Fatal and Error + 1: 'warn', // Warnings + 2: 'info', // Normal logs + 3: 'info', // Informational logs, success, fail, ready, start, ... + 4: 'debug', // Debug logs + 5: 'trace', // Trace logs +}; + +/** + * Determines the log severity level from Consola type and level. + * + * @param type - The Consola log type (e.g., 'error', 'warn', 'info') + * @param level - The Consola numeric log level (0-5) or null for some types like 'verbose' + * @returns The corresponding Sentry log severity level + */ +function getLogSeverityLevel(type?: string, level?: number | null): LogSeverityLevel { + // Handle special case for verbose logs (level can be null with infinite level in Consola) + if (type === 'verbose') { + return 'debug'; + } + + // Handle silent logs - these should be at trace level + if (type === 'silent') { + return 'trace'; + } + + // First try to map by type (more specific) + if (type) { + const mappedLevel = CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP[type]; + if (mappedLevel) { + return mappedLevel; + } + } + + // Fallback to level mapping (handle null level) + if (typeof level === 'number') { + const mappedLevel = CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP[level]; + if (mappedLevel) { + return mappedLevel; + } + } + + // Default fallback + return 'info'; +} diff --git a/packages/core/src/integrations/mcp-server/errorCapture.ts b/packages/core/src/integrations/mcp-server/errorCapture.ts index 544d61cf71ad..2ba401c93d08 100644 --- a/packages/core/src/integrations/mcp-server/errorCapture.ts +++ b/packages/core/src/integrations/mcp-server/errorCapture.ts @@ -36,7 +36,7 @@ export function captureError(error: Error, errorType?: McpErrorType, extraData?: captureException(error, { mechanism: { - type: 'mcp_server', + type: 'auto.ai.mcp_server', handled: false, data: { error_type: errorType || 'handler_execution', diff --git a/packages/core/src/logs/console-integration.ts b/packages/core/src/logs/console-integration.ts index a69d406a659c..6c967499800f 100644 --- a/packages/core/src/logs/console-integration.ts +++ b/packages/core/src/logs/console-integration.ts @@ -6,21 +6,13 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes'; import type { ConsoleLevel } from '../types-hoist/instrument'; import type { IntegrationFn } from '../types-hoist/integration'; import { CONSOLE_LEVELS, debug } from '../utils/debug-logger'; -import { isPrimitive } from '../utils/is'; -import { normalize } from '../utils/normalize'; -import { GLOBAL_OBJ } from '../utils/worldwide'; import { _INTERNAL_captureLog } from './exports'; +import { formatConsoleArgs } from './utils'; interface CaptureConsoleOptions { levels: ConsoleLevel[]; } -type GlobalObjectWithUtil = typeof GLOBAL_OBJ & { - util: { - format: (...args: unknown[]) => string; - }; -}; - const INTEGRATION_NAME = 'ConsoleLogs'; const DEFAULT_ATTRIBUTES = { @@ -89,17 +81,3 @@ const _consoleLoggingIntegration = ((options: Partial = { * ``` */ export const consoleLoggingIntegration = defineIntegration(_consoleLoggingIntegration); - -function formatConsoleArgs(values: unknown[], normalizeDepth: number, normalizeMaxBreadth: number): string { - return 'util' in GLOBAL_OBJ && typeof (GLOBAL_OBJ as GlobalObjectWithUtil).util.format === 'function' - ? (GLOBAL_OBJ as GlobalObjectWithUtil).util.format(...values) - : safeJoinConsoleArgs(values, normalizeDepth, normalizeMaxBreadth); -} - -function safeJoinConsoleArgs(values: unknown[], normalizeDepth: number, normalizeMaxBreadth: number): string { - return values - .map(value => - isPrimitive(value) ? String(value) : JSON.stringify(normalize(value, normalizeDepth, normalizeMaxBreadth)), - ) - .join(' '); -} diff --git a/packages/core/src/logs/utils.ts b/packages/core/src/logs/utils.ts new file mode 100644 index 000000000000..c30bfd75530b --- /dev/null +++ b/packages/core/src/logs/utils.ts @@ -0,0 +1,39 @@ +import { isPrimitive } from '../utils/is'; +import { normalize } from '../utils/normalize'; +import { GLOBAL_OBJ } from '../utils/worldwide'; + +type GlobalObjectWithUtil = typeof GLOBAL_OBJ & { + util: { + format: (...args: unknown[]) => string; + }; +}; + +/** + * Formats the given values into a string. + * + * @param values - The values to format. + * @param normalizeDepth - The depth to normalize the values. + * @param normalizeMaxBreadth - The max breadth to normalize the values. + * @returns The formatted string. + */ +export function formatConsoleArgs(values: unknown[], normalizeDepth: number, normalizeMaxBreadth: number): string { + return 'util' in GLOBAL_OBJ && typeof (GLOBAL_OBJ as GlobalObjectWithUtil).util.format === 'function' + ? (GLOBAL_OBJ as GlobalObjectWithUtil).util.format(...values) + : safeJoinConsoleArgs(values, normalizeDepth, normalizeMaxBreadth); +} + +/** + * Joins the given values into a string. + * + * @param values - The values to join. + * @param normalizeDepth - The depth to normalize the values. + * @param normalizeMaxBreadth - The max breadth to normalize the values. + * @returns The joined string. + */ +export function safeJoinConsoleArgs(values: unknown[], normalizeDepth: number, normalizeMaxBreadth: number): string { + return values + .map(value => + isPrimitive(value) ? String(value) : JSON.stringify(normalize(value, normalizeDepth, normalizeMaxBreadth)), + ) + .join(' '); +} diff --git a/packages/core/src/utils/aggregate-errors.ts b/packages/core/src/utils/aggregate-errors.ts index f472e5b9968b..16d100d60c09 100644 --- a/packages/core/src/utils/aggregate-errors.ts +++ b/packages/core/src/utils/aggregate-errors.ts @@ -99,10 +99,9 @@ function aggregateExceptionsFromError( } function applyExceptionGroupFieldsForParentException(exception: Exception, exceptionId: number): void { - // Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default. - exception.mechanism = exception.mechanism || { type: 'generic', handled: true }; - exception.mechanism = { + handled: true, + type: 'auto.core.linked_errors', ...exception.mechanism, ...(exception.type === 'AggregateError' && { is_exception_group: true }), exception_id: exceptionId, @@ -115,10 +114,8 @@ function applyExceptionGroupFieldsForChildException( exceptionId: number, parentId: number | undefined, ): void { - // Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default. - exception.mechanism = exception.mechanism || { type: 'generic', handled: true }; - exception.mechanism = { + handled: true, ...exception.mechanism, type: 'chained', source, diff --git a/packages/core/src/utils/anthropic-ai/index.ts b/packages/core/src/utils/anthropic-ai/index.ts index 563724d98c5c..a771dff4c75d 100644 --- a/packages/core/src/utils/anthropic-ai/index.ts +++ b/packages/core/src/utils/anthropic-ai/index.ts @@ -27,7 +27,6 @@ import { buildMethodPath, getFinalOperationName, getSpanOperation, setTokenUsage import { ANTHROPIC_AI_INTEGRATION_NAME } from './constants'; import { instrumentStream } from './streaming'; import type { - AnthropicAiClient, AnthropicAiInstrumentedMethod, AnthropicAiIntegration, AnthropicAiOptions, @@ -304,7 +303,7 @@ function instrumentMethod( /** * Create a deep proxy for Anthropic AI client instrumentation */ -function createDeepProxy(target: T, currentPath = '', options?: AnthropicAiOptions): T { +function createDeepProxy(target: T, currentPath = '', options?: AnthropicAiOptions): T { return new Proxy(target, { get(obj: object, prop: string): unknown { const value = (obj as Record)[prop]; @@ -332,11 +331,11 @@ function createDeepProxy(target: T, currentPath = ' * Instrument an Anthropic AI client with Sentry tracing * Can be used across Node.js, Cloudflare Workers, and Vercel Edge * - * @template T - The type of the client that extends AnthropicAiClient + * @template T - The type of the client that extends object * @param client - The Anthropic AI client to instrument * @param options - Optional configuration for recording inputs and outputs * @returns The instrumented client with the same type as the input */ -export function instrumentAnthropicAiClient(client: T, options?: AnthropicAiOptions): T { +export function instrumentAnthropicAiClient(client: T, options?: AnthropicAiOptions): T { return createDeepProxy(client, '', options); } diff --git a/packages/core/src/utils/spanUtils.ts b/packages/core/src/utils/spanUtils.ts index b6761c9930e7..89ecc6872efb 100644 --- a/packages/core/src/utils/spanUtils.ts +++ b/packages/core/src/utils/spanUtils.ts @@ -17,7 +17,7 @@ import type { SpanStatus } from '../types-hoist/spanStatus'; import { addNonEnumerableProperty } from '../utils/object'; import { generateSpanId } from '../utils/propagationContext'; import { timestampInSeconds } from '../utils/time'; -import { generateSentryTraceHeader } from '../utils/tracing'; +import { generateSentryTraceHeader, generateTraceparentHeader } from '../utils/tracing'; import { consoleSandbox } from './debug-logger'; import { _getSpanForScope } from './spanOnScope'; @@ -77,6 +77,15 @@ export function spanToTraceHeader(span: Span): string { return generateSentryTraceHeader(traceId, spanId, sampled); } +/** + * Convert a Span to a W3C traceparent header. + */ +export function spanToTraceparentHeader(span: Span): string { + const { traceId, spanId } = span.spanContext(); + const sampled = spanIsSampled(span); + return generateTraceparentHeader(traceId, spanId, sampled); +} + /** * Converts the span links array to a flattened version to be sent within an envelope. * diff --git a/packages/core/src/utils/traceData.ts b/packages/core/src/utils/traceData.ts index aa335dbd37bd..325e45a038e0 100644 --- a/packages/core/src/utils/traceData.ts +++ b/packages/core/src/utils/traceData.ts @@ -9,8 +9,8 @@ import type { Span } from '../types-hoist/span'; import type { SerializedTraceData } from '../types-hoist/tracing'; import { dynamicSamplingContextToSentryBaggageHeader } from './baggage'; import { debug } from './debug-logger'; -import { getActiveSpan, spanToTraceHeader } from './spanUtils'; -import { extractTraceparentData, generateSentryTraceHeader, TRACEPARENT_REGEXP } from './tracing'; +import { getActiveSpan, spanToTraceHeader, spanToTraceparentHeader } from './spanUtils'; +import { generateSentryTraceHeader, generateTraceparentHeader, TRACEPARENT_REGEXP } from './tracing'; /** * Extracts trace propagation data from the current span or from the client's scope (via transaction or propagation @@ -58,7 +58,7 @@ export function getTraceData( }; if (options.propagateTraceparent) { - const traceparent = _sentryTraceToTraceParentHeader(sentryTrace); + const traceparent = span ? spanToTraceparentHeader(span) : scopeToTraceparentHeader(scope); if (traceparent) { traceData.traceparent = traceparent; } @@ -75,22 +75,7 @@ function scopeToTraceHeader(scope: Scope): string { return generateSentryTraceHeader(traceId, propagationSpanId, sampled); } -/** - * Builds a W3C traceparent header from the given sentry-trace header. - * - * Why parse that header and not create traceparent from primitives? - * We want these two headers to always have the same ids. The easiest way to do this is to take - * one of them as the source of truth (sentry-trace) and derive the other from it. - * - * Most importantly, this guarantees parentSpanId consistency between sentry-trace and traceparent - * in tracing without performance (TwP) mode, where we always generate a random parentSpanId. - * - * Exported for testing - */ -export function _sentryTraceToTraceParentHeader(sentryTrace: string): string | undefined { - const { traceId, parentSpanId, parentSampled } = extractTraceparentData(sentryTrace) || {}; - if (!traceId || !parentSpanId) { - return undefined; - } - return `00-${traceId}-${parentSpanId}-${parentSampled ? '01' : '00'}`; +function scopeToTraceparentHeader(scope: Scope): string { + const { traceId, sampled, propagationSpanId } = scope.getPropagationContext(); + return generateTraceparentHeader(traceId, propagationSpanId, sampled); } diff --git a/packages/core/src/utils/tracing.ts b/packages/core/src/utils/tracing.ts index 0310cc8640e6..aa5a15153674 100644 --- a/packages/core/src/utils/tracing.ts +++ b/packages/core/src/utils/tracing.ts @@ -102,6 +102,17 @@ export function generateSentryTraceHeader( return `${traceId}-${spanId}${sampledString}`; } +/** + * Creates a W3C traceparent header from the given trace and span ids. + */ +export function generateTraceparentHeader( + traceId: string | undefined = generateTraceId(), + spanId: string | undefined = generateSpanId(), + sampled?: boolean, +): string { + return `00-${traceId}-${spanId}-${sampled ? '01' : '00'}`; +} + /** * Given any combination of an incoming trace, generate a sample rand based on its defined semantics. * diff --git a/packages/core/test/lib/client.test.ts b/packages/core/test/lib/client.test.ts index 6a7d0af22857..b7767a7e6c58 100644 --- a/packages/core/test/lib/client.test.ts +++ b/packages/core/test/lib/client.test.ts @@ -1833,15 +1833,13 @@ describe('Client', () => { }); }); - test('event processor sends an event and logs when it crashes', () => { - expect.assertions(3); - + test('event processor sends an event and logs when it crashes synchronously', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); const client = new TestClient(options); const captureExceptionSpy = vi.spyOn(client, 'captureException'); const loggerWarnSpy = vi.spyOn(debugLoggerModule.debug, 'warn'); const scope = new Scope(); - const exception = new Error('sorry'); + const exception = new Error('sorry 1'); scope.addEventProcessor(() => { throw exception; }); @@ -1850,7 +1848,7 @@ describe('Client', () => { expect(TestClient.instance!.event!.exception!.values![0]).toStrictEqual({ type: 'Error', - value: 'sorry', + value: 'sorry 1', mechanism: { type: 'internal', handled: false }, }); expect(captureExceptionSpy).toBeCalledWith(exception, { @@ -1865,6 +1863,117 @@ describe('Client', () => { ); }); + test('event processor sends an event and logs when it crashes asynchronously', async () => { + vi.useFakeTimers(); + + const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); + const client = new TestClient(options); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const loggerWarnSpy = vi.spyOn(debugLoggerModule.debug, 'warn'); + const scope = new Scope(); + const exception = new Error('sorry 2'); + scope.addEventProcessor(() => { + return new Promise((_resolve, reject) => { + reject(exception); + }); + }); + + client.captureEvent({ message: 'hello' }, {}, scope); + + await vi.runOnlyPendingTimersAsync(); + + expect(TestClient.instance!.event!.exception!.values![0]).toStrictEqual({ + type: 'Error', + value: 'sorry 2', + mechanism: { type: 'internal', handled: false }, + }); + expect(captureExceptionSpy).toBeCalledWith(exception, { + data: { + __sentry__: true, + }, + originalException: exception, + mechanism: { type: 'internal', handled: false }, + }); + expect(loggerWarnSpy).toBeCalledWith( + `Event processing pipeline threw an error, original event will not be sent. Details have been sent as a new event.\nReason: ${exception}`, + ); + }); + + test('event processor sends an event and logs when it crashes synchronously in processor chain', () => { + const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); + const client = new TestClient(options); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const scope = new Scope(); + const exception = new Error('sorry 3'); + + const processor1 = vi.fn(event => { + return event; + }); + const processor2 = vi.fn(() => { + throw exception; + }); + const processor3 = vi.fn(event => { + return event; + }); + + scope.addEventProcessor(processor1); + scope.addEventProcessor(processor2); + scope.addEventProcessor(processor3); + + client.captureEvent({ message: 'hello' }, {}, scope); + + expect(processor1).toHaveBeenCalledTimes(1); + expect(processor2).toHaveBeenCalledTimes(1); + expect(processor3).toHaveBeenCalledTimes(0); + + expect(captureExceptionSpy).toBeCalledWith(exception, { + data: { + __sentry__: true, + }, + originalException: exception, + mechanism: { type: 'internal', handled: false }, + }); + }); + + test('event processor sends an event and logs when it crashes asynchronously in processor chain', async () => { + vi.useFakeTimers(); + + const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); + const client = new TestClient(options); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const scope = new Scope(); + const exception = new Error('sorry 4'); + + const processor1 = vi.fn(async event => { + return event; + }); + const processor2 = vi.fn(async () => { + throw exception; + }); + const processor3 = vi.fn(event => { + return event; + }); + + scope.addEventProcessor(processor1); + scope.addEventProcessor(processor2); + scope.addEventProcessor(processor3); + + client.captureEvent({ message: 'hello' }, {}, scope); + await vi.runOnlyPendingTimersAsync(); + + expect(processor1).toHaveBeenCalledTimes(1); + expect(processor2).toHaveBeenCalledTimes(1); + expect(processor3).toHaveBeenCalledTimes(0); + + expect(captureExceptionSpy).toBeCalledWith(exception, { + data: { + __sentry__: true, + }, + originalException: exception, + mechanism: { type: 'internal', handled: false }, + }); + }); + test('records events dropped due to `sampleRate` option', () => { expect.assertions(1); @@ -2159,7 +2268,7 @@ describe('Client', () => { expect(mockSend).toBeCalledTimes(1); expect(callback).toBeCalledTimes(1); - expect(callback).toBeCalledWith(errorEvent, 'send error'); + expect(callback).toBeCalledWith(errorEvent, {}); }); it('passes the response to the hook', async () => { diff --git a/packages/core/test/lib/integrations/captureconsole.test.ts b/packages/core/test/lib/integrations/captureconsole.test.ts index 2fe971710a07..8da7c6570d74 100644 --- a/packages/core/test/lib/integrations/captureconsole.test.ts +++ b/packages/core/test/lib/integrations/captureconsole.test.ts @@ -328,7 +328,7 @@ describe('CaptureConsole setup', () => { expect(someEvent.exception?.values?.[0]?.mechanism).toEqual({ handled: true, - type: 'console', + type: 'auto.core.capture_console', }); }); @@ -352,7 +352,7 @@ describe('CaptureConsole setup', () => { expect(someEvent.exception?.values?.[0]?.mechanism).toEqual({ handled: true, - type: 'console', + type: 'auto.core.capture_console', }); }); @@ -376,7 +376,7 @@ describe('CaptureConsole setup', () => { expect(someEvent.exception?.values?.[0]?.mechanism).toEqual({ handled: false, - type: 'console', + type: 'auto.core.capture_console', }); }); }); diff --git a/packages/core/test/lib/integrations/consola.test.ts b/packages/core/test/lib/integrations/consola.test.ts new file mode 100644 index 000000000000..66830fb75e06 --- /dev/null +++ b/packages/core/test/lib/integrations/consola.test.ts @@ -0,0 +1,303 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { getClient } from '../../../src/currentScopes'; +import { createConsolaReporter } from '../../../src/integrations/consola'; +import { _INTERNAL_captureLog } from '../../../src/logs/exports'; +import { formatConsoleArgs } from '../../../src/logs/utils'; +import { getDefaultTestClientOptions, TestClient } from '../../mocks/client'; + +// Mock dependencies +vi.mock('../../../src/logs/exports', () => ({ + _INTERNAL_captureLog: vi.fn(), +})); + +vi.mock('../../../src/logs/utils', async actual => ({ + formatConsoleArgs: vi.fn(((await actual()) as any).formatConsoleArgs), +})); + +vi.mock('../../../src/currentScopes', () => ({ + getClient: vi.fn(), +})); + +describe('createConsolaReporter', () => { + let mockClient: TestClient; + + beforeEach(() => { + vi.clearAllMocks(); + + // Create a test client with enableLogs: true + mockClient = new TestClient({ + ...getDefaultTestClientOptions({ dsn: 'https://username@domain/123' }), + enableLogs: true, + normalizeDepth: 3, + normalizeMaxBreadth: 1000, + }); + + vi.mocked(getClient).mockReturnValue(mockClient); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('reporter creation', () => { + it('should create a reporter with log function', () => { + const reporter = createConsolaReporter(); + + expect(reporter).toEqual({ + log: expect.any(Function), + }); + }); + }); + + describe('log capturing', () => { + let sentryReporter: any; + + beforeEach(() => { + sentryReporter = createConsolaReporter(); + }); + + it('should capture error logs', () => { + const logObj = { + type: 'error', + level: 0, + message: 'This is an error', + tag: 'test', + date: new Date('2023-01-01T00:00:00.000Z'), + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'error', + message: 'This is an error', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.tag': 'test', + 'consola.type': 'error', + 'consola.level': 0, + }, + }); + }); + + it('should capture warn logs', () => { + const logObj = { + type: 'warn', + message: 'This is a warning', + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'warn', + message: 'This is a warning', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': 'warn', + }, + }); + }); + + it('should capture info logs', () => { + const logObj = { + type: 'info', + message: 'This is info', + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'info', + message: 'This is info', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': 'info', + }, + }); + }); + + it('should capture debug logs', () => { + const logObj = { + type: 'debug', + message: 'Debug message', + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'debug', + message: 'Debug message', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': 'debug', + }, + }); + }); + + it('should capture trace logs', () => { + const logObj = { + type: 'trace', + message: 'Trace message', + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'trace', + message: 'Trace message', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': 'trace', + }, + }); + }); + + it('should capture fatal logs', () => { + const logObj = { + type: 'fatal', + message: 'Fatal error', + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'fatal', + message: 'Fatal error', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': 'fatal', + }, + }); + }); + + it('should format message from args when message is not provided', () => { + const logObj = { + type: 'info', + args: ['Hello', 'world', 123, { key: 'value' }], + }; + + sentryReporter.log(logObj); + + expect(formatConsoleArgs).toHaveBeenCalledWith(['Hello', 'world', 123, { key: 'value' }], 3, 1000); + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'info', + message: 'Hello world 123 {"key":"value"}', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': 'info', + }, + }); + }); + + it('should handle args with unparseable objects', () => { + const circular: any = {}; + circular.self = circular; + + const logObj = { + type: 'info', + args: ['Message', circular], + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'info', + message: 'Message {"self":"[Circular ~]"}', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': 'info', + }, + }); + }); + + it('should map consola levels to sentry levels when type is not provided', () => { + const logObj = { + level: 0, // Fatal level + message: 'Fatal message', + }; + + sentryReporter.log(logObj); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: 'fatal', + message: 'Fatal message', + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.level': 0, + }, + }); + }); + + it('should map various consola types correctly', () => { + const testCases = [ + { type: 'success', expectedLevel: 'info' }, + { type: 'fail', expectedLevel: 'error' }, + { type: 'ready', expectedLevel: 'info' }, + { type: 'start', expectedLevel: 'info' }, + { type: 'verbose', expectedLevel: 'debug' }, + { type: 'log', expectedLevel: 'info' }, + { type: 'silent', expectedLevel: 'trace' }, + ]; + + testCases.forEach(({ type, expectedLevel }) => { + vi.clearAllMocks(); + + sentryReporter.log({ + type, + message: `Test ${type} message`, + }); + + expect(_INTERNAL_captureLog).toHaveBeenCalledWith({ + level: expectedLevel, + message: `Test ${type} message`, + attributes: { + 'sentry.origin': 'auto.logging.consola', + 'consola.type': type, + }, + }); + }); + }); + }); + + describe('level filtering', () => { + it('should only capture specified levels', () => { + const filteredReporter = createConsolaReporter({ + levels: ['error', 'warn'], + }); + + // Should capture error + filteredReporter.log({ + type: 'error', + message: 'Error message', + }); + expect(_INTERNAL_captureLog).toHaveBeenCalledTimes(1); + + // Should capture warn + filteredReporter.log({ + type: 'warn', + message: 'Warn message', + }); + expect(_INTERNAL_captureLog).toHaveBeenCalledTimes(2); + + // Should not capture info + filteredReporter.log({ + type: 'info', + message: 'Info message', + }); + expect(_INTERNAL_captureLog).toHaveBeenCalledTimes(2); + }); + + it('should use default levels when none specified', () => { + const defaultReporter = createConsolaReporter(); + + // Should capture all default levels + ['trace', 'debug', 'info', 'warn', 'error', 'fatal'].forEach(type => { + defaultReporter.log({ + type, + message: `${type} message`, + }); + }); + + expect(_INTERNAL_captureLog).toHaveBeenCalledTimes(6); + }); + }); +}); diff --git a/packages/core/test/lib/integrations/eventFilters.test.ts b/packages/core/test/lib/integrations/eventFilters.test.ts index d78b59ede112..a107efe17719 100644 --- a/packages/core/test/lib/integrations/eventFilters.test.ts +++ b/packages/core/test/lib/integrations/eventFilters.test.ts @@ -256,7 +256,7 @@ const USELESS_EXCEPTION_EVENT: Event = { values: [ {}, { - mechanism: { type: 'onunhandledrejection', handled: false }, + mechanism: { type: 'auto.node.onunhandledrejection', handled: false }, }, ], }, diff --git a/packages/core/test/lib/integrations/mcp-server/mcpServerErrorCapture.test.ts b/packages/core/test/lib/integrations/mcp-server/mcpServerErrorCapture.test.ts index bd5af090b0d9..210b303b29bf 100644 --- a/packages/core/test/lib/integrations/mcp-server/mcpServerErrorCapture.test.ts +++ b/packages/core/test/lib/integrations/mcp-server/mcpServerErrorCapture.test.ts @@ -24,7 +24,7 @@ describe('MCP Server Error Capture', () => { expect(captureExceptionSpy).toHaveBeenCalledWith(error, { mechanism: { - type: 'mcp_server', + type: 'auto.ai.mcp_server', handled: false, data: { error_type: 'tool_execution', @@ -40,7 +40,7 @@ describe('MCP Server Error Capture', () => { expect(captureExceptionSpy).toHaveBeenCalledWith(error, { mechanism: { - type: 'mcp_server', + type: 'auto.ai.mcp_server', handled: false, data: { error_type: 'transport', @@ -56,7 +56,7 @@ describe('MCP Server Error Capture', () => { expect(captureExceptionSpy).toHaveBeenCalledWith(error, { mechanism: { - type: 'mcp_server', + type: 'auto.ai.mcp_server', handled: false, data: { error_type: 'protocol', @@ -72,7 +72,7 @@ describe('MCP Server Error Capture', () => { expect(captureExceptionSpy).toHaveBeenCalledWith(error, { mechanism: { - type: 'mcp_server', + type: 'auto.ai.mcp_server', handled: false, data: { error_type: 'validation', @@ -88,7 +88,7 @@ describe('MCP Server Error Capture', () => { expect(captureExceptionSpy).toHaveBeenCalledWith(error, { mechanism: { - type: 'mcp_server', + type: 'auto.ai.mcp_server', handled: false, data: { error_type: 'timeout', @@ -104,7 +104,7 @@ describe('MCP Server Error Capture', () => { expect(captureExceptionSpy).toHaveBeenCalledWith(error, { mechanism: { - type: 'mcp_server', + type: 'auto.ai.mcp_server', handled: false, data: { error_type: 'tool_execution', diff --git a/packages/core/test/lib/utils/aggregate-errors.test.ts b/packages/core/test/lib/utils/aggregate-errors.test.ts index 01ede6d9186a..fa11fd22f7c8 100644 --- a/packages/core/test/lib/utils/aggregate-errors.test.ts +++ b/packages/core/test/lib/utils/aggregate-errors.test.ts @@ -160,6 +160,26 @@ describe('applyAggregateErrorsToEvent()', () => { expect(event.exception?.values?.[event.exception.values.length - 1]?.mechanism?.type).toBe('instrument'); }); + test('should assign a defualt mechanism type for the root exception', () => { + const fakeAggregateError = new FakeAggregateError( + [new Error('Nested Error 1'), new Error('Nested Error 2')], + 'Root Error', + ); + + const exceptionFromError = (_stackParser: StackParser, ex: Error): Exception => { + return { value: ex.message, type: ex.name }; + }; + + const event: Event = { exception: { values: [exceptionFromError(stackParser, fakeAggregateError)] } }; + const eventHint: EventHint = { originalException: fakeAggregateError }; + + applyAggregateErrorsToEvent(exceptionFromError, stackParser, 'cause', 100, event, eventHint); + + expect(event.exception?.values?.[event.exception.values.length - 1]?.mechanism?.type).toBe( + 'auto.core.linked_errors', + ); + }); + test('should recursively walk mixed errors (Aggregate errors and based on `key`)', () => { const chainedError: ExtendedError = new Error('Nested Error 3'); chainedError.cause = new Error('Nested Error 4'); diff --git a/packages/core/test/lib/utils/traceData.test.ts b/packages/core/test/lib/utils/traceData.test.ts index 37764cfc94a3..379103a8a48c 100644 --- a/packages/core/test/lib/utils/traceData.test.ts +++ b/packages/core/test/lib/utils/traceData.test.ts @@ -15,7 +15,6 @@ import { import { getAsyncContextStrategy } from '../../../src/asyncContext'; import { freezeDscOnSpan } from '../../../src/tracing/dynamicSamplingContext'; import type { Span } from '../../../src/types-hoist/span'; -import { _sentryTraceToTraceParentHeader } from '../../../src/utils/traceData'; import type { TestClientOptions } from '../../mocks/client'; import { getDefaultTestClientOptions, TestClient } from '../../mocks/client'; @@ -349,34 +348,3 @@ describe('getTraceData', () => { expect(traceData.traceparent).toMatch(/00-12345678901234567890123456789099-[0-9a-f]{16}-00/); }); }); - -describe('_sentryTraceToTraceParentHeader', () => { - it('returns positively sampled traceparent header for sentry-trace with positive sampling decision', () => { - const traceparent = _sentryTraceToTraceParentHeader('12345678901234567890123456789012-1234567890123456-1'); - expect(traceparent).toBe('00-12345678901234567890123456789012-1234567890123456-01'); - }); - - it('returns negatively sampled traceparent header for sentry-trace with negative sampling decision', () => { - const traceparent = _sentryTraceToTraceParentHeader('12345678901234567890123456789012-1234567890123456-0'); - expect(traceparent).toBe('00-12345678901234567890123456789012-1234567890123456-00'); - }); - - it('returns negatively sampled traceparent header for sentry-trace with no/deferred sampling decision', () => { - const traceparent = _sentryTraceToTraceParentHeader('12345678901234567890123456789012-1234567890123456'); - expect(traceparent).toBe('00-12345678901234567890123456789012-1234567890123456-00'); - }); - - it.each([ - '12345678901234567890123456789012--0', - '-12345678901234567890123456789012-0', - '--1', - '0', - '1', - '', - '00-12345678901234567890123456789012-1234567890123456-01', - '00-12345678901234567890123456789012-1234567890123456-00', - ])('returns undefined if the sentry-trace header is invalid (%s)', sentryTrace => { - const traceparent = _sentryTraceToTraceParentHeader(sentryTrace); - expect(traceparent).toBeUndefined(); - }); -}); diff --git a/packages/core/test/lib/utils/tracing.test.ts b/packages/core/test/lib/utils/tracing.test.ts index ea41190f3bb3..c950679a21be 100644 --- a/packages/core/test/lib/utils/tracing.test.ts +++ b/packages/core/test/lib/utils/tracing.test.ts @@ -1,5 +1,10 @@ import { describe, expect, it, test } from 'vitest'; -import { extractTraceparentData, propagationContextFromHeaders, shouldContinueTrace } from '../../../src/utils/tracing'; +import { + extractTraceparentData, + generateTraceparentHeader, + propagationContextFromHeaders, + shouldContinueTrace, +} from '../../../src/utils/tracing'; import { getDefaultTestClientOptions, TestClient } from '../../mocks/client'; const EXAMPLE_SENTRY_TRACE = '12312012123120121231201212312012-1121201211212012-1'; @@ -177,3 +182,20 @@ describe('shouldContinueTrace', () => { expect(result).toBe(false); }); }); + +describe('generateTraceparentHeader', () => { + test('returns a traceparent header with the given ids and positive sampling decision', () => { + const traceparent = generateTraceparentHeader('12345678901234567890123456789012', '1234567890123456', true); + expect(traceparent).toBe('00-12345678901234567890123456789012-1234567890123456-01'); + }); + + test('returns a traceparent header with the given ids and negative sampling decision', () => { + const traceparent = generateTraceparentHeader('12345678901234567890123456789012', '1234567890123456', false); + expect(traceparent).toBe('00-12345678901234567890123456789012-1234567890123456-00'); + }); + + test('no sampling decision passed, creates a negatively sampled traceparent header', () => { + const traceparent = generateTraceparentHeader('12345678901234567890123456789012', '1234567890123456'); + expect(traceparent).toBe('00-12345678901234567890123456789012-1234567890123456-00'); + }); +}); diff --git a/packages/deno/package.json b/packages/deno/package.json index 8b34ebcc838e..ec80eef93401 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -24,6 +24,7 @@ "/build" ], "dependencies": { + "@opentelemetry/api": "^1.9.0", "@sentry/core": "10.11.0" }, "scripts": { @@ -42,7 +43,7 @@ "lint:es-compatibility": "es-check es2022 ./build/esm/*.js --module", "install:deno": "node ./scripts/install-deno.mjs", "test": "run-s install:deno deno-types test:unit", - "test:unit": "deno test --allow-read --allow-run --no-check", + "test:unit": "deno test --allow-read --allow-run --allow-env --no-check", "test:unit:update": "deno test --allow-read --allow-write --allow-run -- --update", "yalc:publish": "yalc publish --push --sig" }, diff --git a/packages/deno/src/index.ts b/packages/deno/src/index.ts index 12bcedc35270..5f987b4459aa 100644 --- a/packages/deno/src/index.ts +++ b/packages/deno/src/index.ts @@ -101,3 +101,4 @@ export { normalizePathsIntegration } from './integrations/normalizepaths'; export { contextLinesIntegration } from './integrations/contextlines'; export { denoCronIntegration } from './integrations/deno-cron'; export { breadcrumbsIntegration } from './integrations/breadcrumbs'; +export { vercelAIIntegration } from './integrations/tracing/vercelai'; diff --git a/packages/deno/src/integrations/globalhandlers.ts b/packages/deno/src/integrations/globalhandlers.ts index 0e3639a7472d..ae66a28068c4 100644 --- a/packages/deno/src/integrations/globalhandlers.ts +++ b/packages/deno/src/integrations/globalhandlers.ts @@ -61,7 +61,7 @@ function installGlobalErrorHandler(client: Client): void { originalException: error, mechanism: { handled: false, - type: 'error', + type: 'auto.deno.global_handlers.error', }, }); @@ -110,7 +110,7 @@ function installGlobalUnhandledRejectionHandler(client: Client): void { originalException: error, mechanism: { handled: false, - type: 'unhandledrejection', + type: 'auto.deno.global_handlers.unhandledrejection', }, }); diff --git a/packages/deno/src/integrations/tracing/vercelai.ts b/packages/deno/src/integrations/tracing/vercelai.ts new file mode 100644 index 000000000000..c400babf0d64 --- /dev/null +++ b/packages/deno/src/integrations/tracing/vercelai.ts @@ -0,0 +1,45 @@ +/** + * This is a copy of the Vercel AI integration from the cloudflare SDK. + */ + +import type { IntegrationFn } from '@sentry/core'; +import { addVercelAiProcessors, defineIntegration } from '@sentry/core'; + +const INTEGRATION_NAME = 'VercelAI'; + +const _vercelAIIntegration = (() => { + return { + name: INTEGRATION_NAME, + setup(client) { + addVercelAiProcessors(client); + }, + }; +}) satisfies IntegrationFn; + +/** + * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library. + * This integration is not enabled by default, you need to manually add it. + * + * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry). + * + * You need to enable collecting spans for a specific call by setting + * `experimental_telemetry.isEnabled` to `true` in the first argument of the function call. + * + * ```javascript + * const result = await generateText({ + * model: openai('gpt-4-turbo'), + * experimental_telemetry: { isEnabled: true }, + * }); + * ``` + * + * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each + * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs` + * to `true`. + * + * ```javascript + * const result = await generateText({ + * model: openai('gpt-4-turbo'), + * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true }, + * }); + */ +export const vercelAIIntegration = defineIntegration(_vercelAIIntegration); diff --git a/packages/deno/src/opentelemetry/tracer.ts b/packages/deno/src/opentelemetry/tracer.ts new file mode 100644 index 000000000000..801badefa19f --- /dev/null +++ b/packages/deno/src/opentelemetry/tracer.ts @@ -0,0 +1,110 @@ +import type { Context, Span, SpanOptions, Tracer, TracerProvider } from '@opentelemetry/api'; +import { SpanKind, trace } from '@opentelemetry/api'; +import { + SEMANTIC_ATTRIBUTE_SENTRY_OP, + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + startInactiveSpan, + startSpanManual, +} from '@sentry/core'; + +/** + * Set up a mock OTEL tracer to allow inter-op with OpenTelemetry emitted spans. + * This is not perfect but handles easy/common use cases. + */ +export function setupOpenTelemetryTracer(): void { + trace.setGlobalTracerProvider(new SentryDenoTraceProvider()); +} + +class SentryDenoTraceProvider implements TracerProvider { + private readonly _tracers: Map = new Map(); + + public getTracer(name: string, version?: string, options?: { schemaUrl?: string }): Tracer { + const key = `${name}@${version || ''}:${options?.schemaUrl || ''}`; + if (!this._tracers.has(key)) { + this._tracers.set(key, new SentryDenoTracer()); + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this._tracers.get(key)!; + } +} + +class SentryDenoTracer implements Tracer { + public startSpan(name: string, options?: SpanOptions): Span { + // Map OpenTelemetry SpanKind to Sentry operation + const op = this._mapSpanKindToOp(options?.kind); + + return startInactiveSpan({ + name, + ...options, + attributes: { + ...options?.attributes, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'manual', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op, + 'sentry.deno_tracer': true, + }, + }); + } + + /** + * NOTE: This does not handle `context` being passed in. It will always put spans on the current scope. + */ + public startActiveSpan unknown>(name: string, fn: F): ReturnType; + public startActiveSpan unknown>(name: string, options: SpanOptions, fn: F): ReturnType; + public startActiveSpan unknown>( + name: string, + options: SpanOptions, + context: Context, + fn: F, + ): ReturnType; + public startActiveSpan unknown>( + name: string, + options: unknown, + context?: unknown, + fn?: F, + ): ReturnType { + const opts = (typeof options === 'object' && options !== null ? options : {}) as SpanOptions; + + // Map OpenTelemetry SpanKind to Sentry operation + const op = this._mapSpanKindToOp(opts.kind); + + const spanOpts = { + name, + ...opts, + attributes: { + ...opts.attributes, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'manual', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op, + 'sentry.deno_tracer': true, + }, + }; + + const callback = ( + typeof options === 'function' + ? options + : typeof context === 'function' + ? context + : typeof fn === 'function' + ? fn + : () => {} + ) as F; + + // In OTEL the semantic matches `startSpanManual` because spans are not auto-ended + return startSpanManual(spanOpts, callback) as ReturnType; + } + + private _mapSpanKindToOp(kind?: SpanKind): string { + switch (kind) { + case SpanKind.CLIENT: + return 'http.client'; + case SpanKind.SERVER: + return 'http.server'; + case SpanKind.PRODUCER: + return 'message.produce'; + case SpanKind.CONSUMER: + return 'message.consume'; + default: + return 'otel.span'; + } + } +} diff --git a/packages/deno/src/sdk.ts b/packages/deno/src/sdk.ts index 955417842f94..e670a86f50d6 100644 --- a/packages/deno/src/sdk.ts +++ b/packages/deno/src/sdk.ts @@ -16,6 +16,7 @@ import { denoContextIntegration } from './integrations/context'; import { contextLinesIntegration } from './integrations/contextlines'; import { globalHandlersIntegration } from './integrations/globalhandlers'; import { normalizePathsIntegration } from './integrations/normalizepaths'; +import { setupOpenTelemetryTracer } from './opentelemetry/tracer'; import { makeFetchTransport } from './transports'; import type { DenoOptions } from './types'; @@ -97,5 +98,13 @@ export function init(options: DenoOptions = {}): Client { transport: options.transport || makeFetchTransport, }; - return initAndBind(DenoClient, clientOptions); + const client = initAndBind(DenoClient, clientOptions); + + // Set up OpenTelemetry compatibility to capture spans from libraries using @opentelemetry/api + // Note: This is separate from Deno's native OTEL support and doesn't capture auto-instrumented spans + if (!options.skipOpenTelemetrySetup) { + setupOpenTelemetryTracer(); + } + + return client; } diff --git a/packages/deno/src/types.ts b/packages/deno/src/types.ts index 422e561bb644..1659e7a635e1 100644 --- a/packages/deno/src/types.ts +++ b/packages/deno/src/types.ts @@ -23,6 +23,19 @@ export interface BaseDenoOptions { /** Sets an optional server name (device name) */ serverName?: string; + /** + * The Deno SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility + * via a custom trace provider. + * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry. + * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope. + * This should be good enough for many, but not all integrations. + * + * If you want to opt-out of setting up the OpenTelemetry compatibility tracer, set this to `true`. + * + * @default false + */ + skipOpenTelemetrySetup?: boolean; + /** Callback that is executed when a fatal global error occurs. */ onFatalError?(this: void, error: Error): void; } diff --git a/packages/deno/test/opentelemetry.test.ts b/packages/deno/test/opentelemetry.test.ts new file mode 100644 index 000000000000..2c37ddc48843 --- /dev/null +++ b/packages/deno/test/opentelemetry.test.ts @@ -0,0 +1,225 @@ +import { assertEquals, assertNotEquals } from 'https://deno.land/std@0.212.0/assert/mod.ts'; +import { context, propagation, trace } from 'npm:@opentelemetry/api@1'; +import type { DenoClient } from '../build/esm/index.js'; +import { getCurrentScope, getGlobalScope, getIsolationScope, init, startSpan } from '../build/esm/index.js'; + +function resetGlobals(): void { + getCurrentScope().clear(); + getCurrentScope().setClient(undefined); + getIsolationScope().clear(); + getGlobalScope().clear(); +} + +function cleanupOtel(): void { + // Disable all globally registered APIs + trace.disable(); + context.disable(); + propagation.disable(); +} + +function resetSdk(): void { + resetGlobals(); + cleanupOtel(); +} + +Deno.test('should not capture spans emitted via @opentelemetry/api when skipOpenTelemetrySetup is true', async () => { + resetSdk(); + const transactionEvents: any[] = []; + + const client = init({ + dsn: 'https://username@domain/123', + tracesSampleRate: 1, + skipOpenTelemetrySetup: true, + beforeSendTransaction: event => { + transactionEvents.push(event); + return null; + }, + }) as DenoClient; + + const tracer = trace.getTracer('test'); + const span = tracer.startSpan('test'); + span.end(); + + await client.flush(); + + tracer.startActiveSpan('test 2', { attributes: { 'test.attribute': 'test' } }, span2 => { + const span = tracer.startSpan('test 3', { attributes: { 'test.attribute': 'test2' } }); + span.end(); + span2.end(); + }); + + await client.flush(); + + assertEquals(transactionEvents.length, 0); +}); + +Deno.test('should capture spans emitted via @opentelemetry/api', async () => { + resetSdk(); + const transactionEvents: any[] = []; + + const client = init({ + dsn: 'https://username@domain/123', + tracesSampleRate: 1, + beforeSendTransaction: event => { + transactionEvents.push(event); + return null; + }, + }) as DenoClient; + + const tracer = trace.getTracer('test'); + const span = tracer.startSpan('test'); + span.end(); + + await client.flush(); + + tracer.startActiveSpan('test 2', { attributes: { 'test.attribute': 'test' } }, span2 => { + const span = tracer.startSpan('test 3', { attributes: { 'test.attribute': 'test2' } }); + span.end(); + span2.end(); + }); + + await client.flush(); + + assertEquals(transactionEvents.length, 2); + const [transactionEvent, transactionEvent2] = transactionEvents; + + assertEquals(transactionEvent?.spans?.length, 0); + assertEquals(transactionEvent?.transaction, 'test'); + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.deno_tracer'], true); + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.origin'], 'manual'); + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.sample_rate'], 1); + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.source'], 'custom'); + + assertEquals(transactionEvent2?.spans?.length, 1); + assertEquals(transactionEvent2?.transaction, 'test 2'); + assertEquals(transactionEvent2?.contexts?.trace?.data?.['sentry.deno_tracer'], true); + assertEquals(transactionEvent2?.contexts?.trace?.data?.['sentry.origin'], 'manual'); + assertEquals(transactionEvent2?.contexts?.trace?.data?.['sentry.sample_rate'], 1); + assertEquals(transactionEvent2?.contexts?.trace?.data?.['sentry.source'], 'custom'); + assertEquals(transactionEvent2?.contexts?.trace?.data?.['test.attribute'], 'test'); + + const childSpan = transactionEvent2?.spans?.[0]; + assertEquals(childSpan?.description, 'test 3'); + assertEquals(childSpan?.data?.['sentry.deno_tracer'], true); + assertEquals(childSpan?.data?.['sentry.origin'], 'manual'); + assertEquals(childSpan?.data?.['test.attribute'], 'test2'); +}); + +Deno.test('opentelemetry spans should interop with Sentry spans', async () => { + resetSdk(); + const transactionEvents: any[] = []; + + const client = init({ + dsn: 'https://username@domain/123', + tracesSampleRate: 1, + beforeSendTransaction: event => { + transactionEvents.push(event); + return null; + }, + }) as DenoClient; + + const tracer = trace.getTracer('test'); + + startSpan({ name: 'sentry span' }, () => { + const span = tracer.startSpan('otel span'); + span.end(); + }); + + await client.flush(); + + assertEquals(transactionEvents.length, 1); + const [transactionEvent] = transactionEvents; + + assertEquals(transactionEvent?.spans?.length, 1); + assertEquals(transactionEvent?.transaction, 'sentry span'); + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.origin'], 'manual'); + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.sample_rate'], 1); + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.source'], 'custom'); + // Note: Sentry-created spans don't have the deno_tracer marker + assertEquals(transactionEvent?.contexts?.trace?.data?.['sentry.deno_tracer'], undefined); + + const otelSpan = transactionEvent?.spans?.[0]; + assertEquals(otelSpan?.description, 'otel span'); + assertEquals(otelSpan?.data?.['sentry.deno_tracer'], true); + assertEquals(otelSpan?.data?.['sentry.origin'], 'manual'); +}); + +Deno.test('should be compatible with native Deno OpenTelemetry', async () => { + resetSdk(); + + const providerBefore = trace.getTracerProvider(); + + const client = init({ + dsn: 'https://username@domain/123', + tracesSampleRate: 1, + beforeSendTransaction: () => null, + }) as DenoClient; + + const providerAfter = trace.getTracerProvider(); + assertEquals(providerBefore, providerAfter); + + const tracer = trace.getTracer('compat-test'); + const span = tracer.startSpan('test-span'); + span.setAttributes({ 'test.compatibility': true }); + span.end(); + + tracer.startActiveSpan('active-span', activeSpan => { + activeSpan.end(); + }); + + const otelSpan = tracer.startSpan('post-init-span'); + otelSpan.end(); + + startSpan({ name: 'sentry-span' }, () => { + const nestedOtelSpan = tracer.startSpan('nested-otel-span'); + nestedOtelSpan.end(); + }); + + await client.flush(); +}); + +Deno.test('should verify native Deno OpenTelemetry works when enabled', async () => { + resetSdk(); + + // Set environment variable to enable native OTel + const originalValue = Deno.env.get('OTEL_DENO'); + Deno.env.set('OTEL_DENO', 'true'); + + try { + const client = init({ + dsn: 'https://username@domain/123', + tracesSampleRate: 1, + beforeSendTransaction: () => null, + }) as DenoClient; + + const provider = trace.getTracerProvider(); + const tracer = trace.getTracer('native-verification'); + const span = tracer.startSpan('verification-span'); + + if (provider.constructor.name === 'Function') { + // Native OTel is active + assertNotEquals(span.constructor.name, 'NonRecordingSpan'); + + let contextWorks = false; + tracer.startActiveSpan('parent-span', parentSpan => { + if (trace.getActiveSpan() === parentSpan) { + contextWorks = true; + } + parentSpan.end(); + }); + assertEquals(contextWorks, true); + } + + span.setAttributes({ 'test.native_otel': true }); + span.end(); + + await client.flush(); + } finally { + // Restore original environment + if (originalValue === undefined) { + Deno.env.delete('OTEL_DENO'); + } else { + Deno.env.set('OTEL_DENO', originalValue); + } + } +}); diff --git a/packages/google-cloud-serverless/src/index.ts b/packages/google-cloud-serverless/src/index.ts index 83292ab11e46..e8042e4260a8 100644 --- a/packages/google-cloud-serverless/src/index.ts +++ b/packages/google-cloud-serverless/src/index.ts @@ -128,6 +128,7 @@ export { vercelAIIntegration, logger, consoleLoggingIntegration, + createConsolaReporter, wrapMcpServerWithSentry, NODE_VERSION, featureFlagsIntegration, diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json index 132ca2b802b4..f231b220149d 100644 --- a/packages/nestjs/package.json +++ b/packages/nestjs/package.json @@ -45,10 +45,10 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/instrumentation-nestjs-core": "0.49.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-nestjs-core": "0.50.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@sentry/core": "10.11.0", "@sentry/node": "10.11.0" }, diff --git a/packages/nextjs/.eslintrc.js b/packages/nextjs/.eslintrc.js index d255f74ce829..1f0ae547d4e0 100644 --- a/packages/nextjs/.eslintrc.js +++ b/packages/nextjs/.eslintrc.js @@ -21,5 +21,11 @@ module.exports = { 'import/no-extraneous-dependencies': 'off', }, }, + { + files: ['src/config/polyfills/perf_hooks.js'], + globals: { + globalThis: 'readonly', + }, + }, ], }; diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 0fe39c265264..d4817c742010 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -77,7 +77,7 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@rollup/plugin-commonjs": "28.0.1", "@sentry-internal/browser-utils": "10.11.0", "@sentry/bundler-plugin-core": "^4.3.0", diff --git a/packages/nextjs/rollup.npm.config.mjs b/packages/nextjs/rollup.npm.config.mjs index 3582cf4574ef..89271a21e9d3 100644 --- a/packages/nextjs/rollup.npm.config.mjs +++ b/packages/nextjs/rollup.npm.config.mjs @@ -88,5 +88,20 @@ export default [ }, }), ), + ...makeNPMConfigVariants( + makeBaseNPMConfig({ + entrypoints: ['src/config/polyfills/perf_hooks.js'], + + packageSpecificConfig: { + output: { + // Preserve the original file structure (i.e., so that everything is still relative to `src`) + entryFileNames: 'config/polyfills/[name].js', + + // make it so Rollup calms down about the fact that we're combining default and named exports + exports: 'named', + }, + }, + }), + ), ...makeOtelLoaders('./build', 'sentry-node'), ]; diff --git a/packages/nextjs/src/common/captureRequestError.ts b/packages/nextjs/src/common/captureRequestError.ts index fec9d46d0e65..6fd2e83d3188 100644 --- a/packages/nextjs/src/common/captureRequestError.ts +++ b/packages/nextjs/src/common/captureRequestError.ts @@ -38,6 +38,7 @@ export function captureRequestError(error: unknown, request: RequestInfo, errorC captureException(error, { mechanism: { handled: false, + type: 'auto.function.nextjs.on_request_error', }, }); diff --git a/packages/nextjs/src/common/pages-router-instrumentation/_error.ts b/packages/nextjs/src/common/pages-router-instrumentation/_error.ts index b33c648839fa..354fbe0438e2 100644 --- a/packages/nextjs/src/common/pages-router-instrumentation/_error.ts +++ b/packages/nextjs/src/common/pages-router-instrumentation/_error.ts @@ -45,7 +45,7 @@ export async function captureUnderscoreErrorException(contextOrProps: ContextOrP // is what passing a string to `captureException` will wind up doing) captureException(err || `_error.js called with falsy error (${err})`, { mechanism: { - type: 'instrument', + type: 'auto.function.nextjs.underscore_error', handled: false, data: { function: '_error.getInitialProps', diff --git a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts index a0e4112404cd..4cf8fde751fb 100644 --- a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts +++ b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts @@ -112,7 +112,7 @@ export function wrapApiHandlerWithSentry(apiHandler: NextApiHandler, parameteriz captureException(objectifiedErr, { mechanism: { - type: 'instrument', + type: 'auto.http.nextjs.api_handler', handled: false, data: { wrapped_handler: wrappingTarget.name, diff --git a/packages/nextjs/src/common/pages-router-instrumentation/wrapPageComponentWithSentry.ts b/packages/nextjs/src/common/pages-router-instrumentation/wrapPageComponentWithSentry.ts index b08bdad5e9ab..693341024726 100644 --- a/packages/nextjs/src/common/pages-router-instrumentation/wrapPageComponentWithSentry.ts +++ b/packages/nextjs/src/common/pages-router-instrumentation/wrapPageComponentWithSentry.ts @@ -48,6 +48,7 @@ export function wrapPageComponentWithSentry(pageComponent: FunctionComponent | C captureException(e, { mechanism: { handled: false, + type: 'auto.function.nextjs.page_class', }, }); throw e; @@ -77,6 +78,7 @@ export function wrapPageComponentWithSentry(pageComponent: FunctionComponent | C captureException(e, { mechanism: { handled: false, + type: 'auto.function.nextjs.page_function', }, }); throw e; diff --git a/packages/nextjs/src/common/utils/wrapperUtils.ts b/packages/nextjs/src/common/utils/wrapperUtils.ts index 23b960c857cf..5bde1f76f0d4 100644 --- a/packages/nextjs/src/common/utils/wrapperUtils.ts +++ b/packages/nextjs/src/common/utils/wrapperUtils.ts @@ -25,7 +25,11 @@ export function withErrorInstrumentation any>( return await origFunction.apply(this, origFunctionArguments); } catch (e) { // TODO: Extract error logic from `withSentry` in here or create a new wrapper with said logic or something like that. - captureException(e, { mechanism: { handled: false } }); + captureException(e, { + // TODO: check if origFunction.name actually returns the correct name or minified garbage + // in this case, we can add another argument to this wrapper with the respective function name + mechanism: { handled: false, type: 'auto.function.nextjs.wrapped', data: { function: origFunction.name } }, + }); throw e; } }; @@ -99,7 +103,7 @@ export async function callDataFetcherTraced Promis try { return await origFunction(...origFunctionArgs); } catch (e) { - captureException(e, { mechanism: { handled: false } }); + captureException(e, { mechanism: { handled: false, type: 'auto.function.nextjs.data_fetcher' } }); throw e; } } diff --git a/packages/nextjs/src/common/withServerActionInstrumentation.ts b/packages/nextjs/src/common/withServerActionInstrumentation.ts index e3cc2831d5e4..f5a1170cc44b 100644 --- a/packages/nextjs/src/common/withServerActionInstrumentation.ts +++ b/packages/nextjs/src/common/withServerActionInstrumentation.ts @@ -7,6 +7,7 @@ import { getClient, getIsolationScope, handleCallbackErrors, + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SPAN_STATUS_ERROR, startSpan, @@ -116,6 +117,7 @@ async function withServerActionInstrumentationImplementation { @@ -130,6 +132,7 @@ async function withServerActionInstrumentationImplementation a captureException(err, { mechanism: { handled: false, + type: 'auto.function.nextjs.generation_function', + data: { + function: generationFunctionIdentifier, + }, }, }); } diff --git a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts index bd84fb4195b7..ab05fbd5e944 100644 --- a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts +++ b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts @@ -98,7 +98,7 @@ export function wrapMiddlewareWithSentry( op: 'http.server.middleware', attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: spanSource, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.wrapMiddlewareWithSentry', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.wrap_middleware', ...headerAttributes, }, }, @@ -108,7 +108,7 @@ export function wrapMiddlewareWithSentry( error => { captureException(error, { mechanism: { - type: 'instrument', + type: 'auto.function.nextjs.wrap_middleware', handled: false, }, }); diff --git a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts index e10d51321a0e..54858a9bdae2 100644 --- a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts +++ b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts @@ -96,6 +96,7 @@ export function wrapRouteHandlerWithSentry any>( captureException(error, { mechanism: { handled: false, + type: 'auto.function.nextjs.route_handler', }, }); } diff --git a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts index f0f8e9df8717..d25225a149f9 100644 --- a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts +++ b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts @@ -114,7 +114,7 @@ export function wrapServerComponentWithSentry any> name: `${componentType} Server Component (${componentRoute})`, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.server_component', 'sentry.nextjs.ssr.function.type': componentType, 'sentry.nextjs.ssr.function.route': componentRoute, }, @@ -136,6 +136,7 @@ export function wrapServerComponentWithSentry any> captureException(error, { mechanism: { handled: false, + type: 'auto.function.nextjs.server_component', }, }); } diff --git a/packages/nextjs/src/config/polyfills/perf_hooks.js b/packages/nextjs/src/config/polyfills/perf_hooks.js new file mode 100644 index 000000000000..1a0ce4a2af76 --- /dev/null +++ b/packages/nextjs/src/config/polyfills/perf_hooks.js @@ -0,0 +1,26 @@ +// Polyfill for Node.js perf_hooks module in edge runtime +// This mirrors the polyfill from packages/vercel-edge/rollup.npm.config.mjs +const __sentry__timeOrigin = Date.now(); + +// Ensure performance global is available +if (typeof globalThis !== 'undefined' && globalThis.performance === undefined) { + globalThis.performance = { + timeOrigin: __sentry__timeOrigin, + now: function () { + return Date.now() - __sentry__timeOrigin; + }, + }; +} + +// Export the performance object for perf_hooks compatibility +export const performance = globalThis.performance || { + timeOrigin: __sentry__timeOrigin, + now: function () { + return Date.now() - __sentry__timeOrigin; + }, +}; + +// Default export for CommonJS compatibility +export default { + performance, +}; diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index 1ca5eaa6bab0..55f080fb433e 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -581,6 +581,7 @@ export type BuildContext = { webpack: { version: string; DefinePlugin: new (values: Record) => WebpackPluginInstance; + ProvidePlugin: new (values: Record) => WebpackPluginInstance; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any defaultLoaders: any; // needed for type tests (test:types) diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index b336e1e2ee9b..8741efe81194 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -60,6 +60,8 @@ export function constructWebpackConfigFunction( const pageExtensions = userNextConfig.pageExtensions || ['tsx', 'ts', 'jsx', 'js']; const dotPrefixedPageExtensions = pageExtensions.map(ext => `.${ext}`); const pageExtensionRegex = pageExtensions.map(escapeStringForRegex).join('|'); + const nextVersion = nextJsVersion || getNextjsVersion(); + const { major } = parseSemver(nextVersion || ''); // We add `.ts` and `.js` back in because `pageExtensions` might not be relevant to the instrumentation file // e.g. user's setting `.mdx`. In that case we still want to default look up @@ -70,8 +72,6 @@ export function constructWebpackConfigFunction( warnAboutDeprecatedConfigFiles(projectDir, instrumentationFile, runtime); } if (runtime === 'server') { - const nextJsVersion = getNextjsVersion(); - const { major } = parseSemver(nextJsVersion || ''); // was added in v15 (https://github.com/vercel/next.js/pull/67539) if (major && major >= 15) { warnAboutMissingOnRequestErrorHandler(instrumentationFile); @@ -103,6 +103,11 @@ export function constructWebpackConfigFunction( addOtelWarningIgnoreRule(newConfig); + // Add edge runtime polyfills when building for edge in dev mode + if (major && major === 13 && runtime === 'edge' && isDev) { + addEdgeRuntimePolyfills(newConfig, buildContext); + } + let pagesDirPath: string | undefined; const maybePagesDirPath = path.join(projectDir, 'pages'); const maybeSrcPagesDirPath = path.join(projectDir, 'src', 'pages'); @@ -865,6 +870,24 @@ function addOtelWarningIgnoreRule(newConfig: WebpackConfigObjectWithModuleRules) } } +function addEdgeRuntimePolyfills(newConfig: WebpackConfigObjectWithModuleRules, buildContext: BuildContext): void { + // Use ProvidePlugin to inject performance global only when accessed + newConfig.plugins = newConfig.plugins || []; + newConfig.plugins.push( + new buildContext.webpack.ProvidePlugin({ + performance: [path.resolve(__dirname, 'polyfills', 'perf_hooks.js'), 'performance'], + }), + ); + + // Add module resolution aliases for problematic Node.js modules in edge runtime + newConfig.resolve = newConfig.resolve || {}; + newConfig.resolve.alias = { + ...newConfig.resolve.alias, + // Redirect perf_hooks imports to a polyfilled version + perf_hooks: path.resolve(__dirname, 'polyfills', 'perf_hooks.js'), + }; +} + function _getModules(projectDir: string): Record { try { const packageJson = path.join(projectDir, 'package.json'); diff --git a/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts b/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts index 6002981cfcf4..735caf8d7788 100644 --- a/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts +++ b/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts @@ -79,7 +79,7 @@ export function wrapApiHandlerWithSentry( op: op, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.wrapApiHandlerWithSentry', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.wrap_api_handler', ...headerAttributes, }, }, @@ -89,7 +89,7 @@ export function wrapApiHandlerWithSentry( error => { captureException(error, { mechanism: { - type: 'instrument', + type: 'auto.function.nextjs.wrap_api_handler', handled: false, }, }); diff --git a/packages/nextjs/test/config/fixtures.ts b/packages/nextjs/test/config/fixtures.ts index a3c4feb0123b..5f5d4a2d3504 100644 --- a/packages/nextjs/test/config/fixtures.ts +++ b/packages/nextjs/test/config/fixtures.ts @@ -99,7 +99,13 @@ export function getBuildContext( distDir: '.next', ...materializedNextConfig, } as NextConfigObject, - webpack: { version: webpackVersion, DefinePlugin: class {} as any }, + webpack: { + version: webpackVersion, + DefinePlugin: class {} as any, + ProvidePlugin: class { + constructor(public definitions: Record) {} + } as any, + }, defaultLoaders: true, totalPages: 2, isServer: buildTarget === 'server' || buildTarget === 'edge', diff --git a/packages/nextjs/test/config/webpack/constructWebpackConfig.test.ts b/packages/nextjs/test/config/webpack/constructWebpackConfig.test.ts index 3a8e86b94e29..7371d35c859a 100644 --- a/packages/nextjs/test/config/webpack/constructWebpackConfig.test.ts +++ b/packages/nextjs/test/config/webpack/constructWebpackConfig.test.ts @@ -2,11 +2,13 @@ import '../mocks'; import * as core from '@sentry/core'; import { describe, expect, it, vi } from 'vitest'; +import * as util from '../../../src/config/util'; import * as getWebpackPluginOptionsModule from '../../../src/config/webpackPluginOptions'; import { CLIENT_SDK_CONFIG_FILE, clientBuildContext, clientWebpackConfig, + edgeBuildContext, exportedNextConfig, serverBuildContext, serverWebpackConfig, @@ -185,4 +187,123 @@ describe('constructWebpackConfigFunction()', () => { }); }); }); + + describe('edge runtime polyfills', () => { + it('adds polyfills only for edge runtime in dev mode on Next.js 13', async () => { + // Mock Next.js version 13 - polyfills should be added + vi.spyOn(util, 'getNextjsVersion').mockReturnValue('13.0.0'); + + // Test edge runtime in dev mode with Next.js 13 - should add polyfills + const edgeDevBuildContext = { ...edgeBuildContext, dev: true }; + const edgeDevConfig = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: edgeDevBuildContext, + }); + + const edgeProvidePlugin = edgeDevConfig.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin'); + expect(edgeProvidePlugin).toBeDefined(); + expect(edgeDevConfig.resolve?.alias?.perf_hooks).toMatch(/perf_hooks\.js$/); + + vi.restoreAllMocks(); + }); + + it('does NOT add polyfills for edge runtime in prod mode even on Next.js 13', async () => { + // Mock Next.js version 13 - but prod mode should still not add polyfills + vi.spyOn(util, 'getNextjsVersion').mockReturnValue('13.0.0'); + + // Test edge runtime in prod mode - should NOT add polyfills + const edgeProdBuildContext = { ...edgeBuildContext, dev: false }; + const edgeProdConfig = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: edgeProdBuildContext, + }); + + const edgeProdProvidePlugin = edgeProdConfig.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin'); + expect(edgeProdProvidePlugin).toBeUndefined(); + + vi.restoreAllMocks(); + }); + + it('does NOT add polyfills for server runtime even on Next.js 13', async () => { + // Mock Next.js version 13 + vi.spyOn(util, 'getNextjsVersion').mockReturnValue('13.0.0'); + + // Test server runtime in dev mode - should NOT add polyfills + const serverDevBuildContext = { ...serverBuildContext, dev: true }; + const serverDevConfig = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: serverDevBuildContext, + }); + + const serverProvidePlugin = serverDevConfig.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin'); + expect(serverProvidePlugin).toBeUndefined(); + + vi.restoreAllMocks(); + }); + + it('does NOT add polyfills for client runtime even on Next.js 13', async () => { + // Mock Next.js version 13 + vi.spyOn(util, 'getNextjsVersion').mockReturnValue('13.0.0'); + + // Test client runtime in dev mode - should NOT add polyfills + const clientDevBuildContext = { ...clientBuildContext, dev: true }; + const clientDevConfig = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: clientWebpackConfig, + incomingWebpackBuildContext: clientDevBuildContext, + }); + + const clientProvidePlugin = clientDevConfig.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin'); + expect(clientProvidePlugin).toBeUndefined(); + + vi.restoreAllMocks(); + }); + + it('does NOT add polyfills for edge runtime in dev mode on Next.js versions other than 13', async () => { + const edgeDevBuildContext = { ...edgeBuildContext, dev: true }; + + // Test with Next.js 12 - should NOT add polyfills + vi.spyOn(util, 'getNextjsVersion').mockReturnValue('12.3.0'); + const edgeConfigV12 = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: edgeDevBuildContext, + }); + expect(edgeConfigV12.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin')).toBeUndefined(); + vi.restoreAllMocks(); + + // Test with Next.js 14 - should NOT add polyfills + vi.spyOn(util, 'getNextjsVersion').mockReturnValue('14.0.0'); + const edgeConfigV14 = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: edgeDevBuildContext, + }); + expect(edgeConfigV14.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin')).toBeUndefined(); + vi.restoreAllMocks(); + + // Test with Next.js 15 - should NOT add polyfills + vi.spyOn(util, 'getNextjsVersion').mockReturnValue('15.0.0'); + const edgeConfigV15 = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: edgeDevBuildContext, + }); + expect(edgeConfigV15.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin')).toBeUndefined(); + vi.restoreAllMocks(); + + // Test with undefined Next.js version - should NOT add polyfills + vi.spyOn(util, 'getNextjsVersion').mockReturnValue(undefined); + const edgeConfigUndefined = await materializeFinalWebpackConfig({ + exportedNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: edgeDevBuildContext, + }); + expect(edgeConfigUndefined.plugins?.find(plugin => plugin.constructor.name === 'ProvidePlugin')).toBeUndefined(); + vi.restoreAllMocks(); + }); + }); }); diff --git a/packages/node-core/package.json b/packages/node-core/package.json index 695eea2c6626..8ca46387868a 100644 --- a/packages/node-core/package.json +++ b/packages/node-core/package.json @@ -58,12 +58,12 @@ }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", - "@opentelemetry/core": "^1.30.1 || ^2.0.0", + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/instrumentation": ">=0.57.1 <1", - "@opentelemetry/resources": "^1.30.1 || ^2.0.0", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0" + "@opentelemetry/resources": "^1.30.1 || ^2.1.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0" }, "dependencies": { "@sentry/core": "10.11.0", @@ -72,12 +72,12 @@ }, "devDependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@types/node": "^18.19.1" }, "scripts": { diff --git a/packages/node-core/src/cron/cron.ts b/packages/node-core/src/cron/cron.ts index ce6225ced2fa..2c764c877c46 100644 --- a/packages/node-core/src/cron/cron.ts +++ b/packages/node-core/src/cron/cron.ts @@ -99,7 +99,12 @@ export function instrumentCron(lib: T & CronJobConstructor, monitorSlug: stri try { await onTick(context, onComplete); } catch (e) { - captureException(e); + captureException(e, { + mechanism: { + handled: false, + type: 'auto.function.cron.instrumentCron', + }, + }); throw e; } }, @@ -136,7 +141,12 @@ export function instrumentCron(lib: T & CronJobConstructor, monitorSlug: stri try { await onTick(context, onComplete); } catch (e) { - captureException(e); + captureException(e, { + mechanism: { + handled: false, + type: 'auto.function.cron.instrumentCron', + }, + }); throw e; } }, diff --git a/packages/node-core/src/cron/node-cron.ts b/packages/node-core/src/cron/node-cron.ts index 5b9e48900287..a2374b06d4b5 100644 --- a/packages/node-core/src/cron/node-cron.ts +++ b/packages/node-core/src/cron/node-cron.ts @@ -53,7 +53,12 @@ export function instrumentNodeCron(lib: Partial & T): T { try { return await callback(); } catch (e) { - captureException(e); + captureException(e, { + mechanism: { + handled: false, + type: 'auto.function.node-cron.instrumentNodeCron', + }, + }); throw e; } }, diff --git a/packages/node-core/src/index.ts b/packages/node-core/src/index.ts index cf581bd63b66..87f96f09ab8e 100644 --- a/packages/node-core/src/index.ts +++ b/packages/node-core/src/index.ts @@ -35,7 +35,8 @@ export { getSentryRelease, defaultStackParser } from './sdk/api'; export { createGetModuleFromFilename } from './utils/module'; export { addOriginToSpan } from './utils/addOriginToSpan'; export { getRequestUrl } from './utils/getRequestUrl'; -export { isCjs } from './utils/commonjs'; +export { initializeEsmLoader } from './sdk/esmLoader'; +export { isCjs } from './utils/detection'; export { ensureIsWrapped } from './utils/ensureIsWrapped'; export { createMissingInstrumentationContext } from './utils/createMissingInstrumentationContext'; export { envToBool } from './utils/envToBool'; @@ -126,6 +127,7 @@ export { zodErrorsIntegration, profiler, consoleLoggingIntegration, + createConsolaReporter, consoleIntegration, wrapMcpServerWithSentry, featureFlagsIntegration, diff --git a/packages/node-core/src/integrations/childProcess.ts b/packages/node-core/src/integrations/childProcess.ts index 6fc6046c7e2f..0e3fcfe4633a 100644 --- a/packages/node-core/src/integrations/childProcess.ts +++ b/packages/node-core/src/integrations/childProcess.ts @@ -99,7 +99,7 @@ function captureWorkerThreadEvents(worker: Worker, options: Options): void { .on('error', error => { if (options.captureWorkerErrors !== false) { captureException(error, { - mechanism: { type: 'instrument', handled: false, data: { threadId: String(threadId) } }, + mechanism: { type: 'auto.child_process.worker_thread', handled: false, data: { threadId: String(threadId) } }, }); } else { addBreadcrumb({ diff --git a/packages/node-core/src/integrations/modules.ts b/packages/node-core/src/integrations/modules.ts index 6724a473b5bb..7079f4a2fab8 100644 --- a/packages/node-core/src/integrations/modules.ts +++ b/packages/node-core/src/integrations/modules.ts @@ -1,7 +1,7 @@ import { existsSync, readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import type { IntegrationFn } from '@sentry/core'; -import { isCjs } from '../utils/commonjs'; +import { isCjs } from '../utils/detection'; type ModuleInfo = Record; diff --git a/packages/node-core/src/integrations/onuncaughtexception.ts b/packages/node-core/src/integrations/onuncaughtexception.ts index 045e2e9f7736..41c4bf96917d 100644 --- a/packages/node-core/src/integrations/onuncaughtexception.ts +++ b/packages/node-core/src/integrations/onuncaughtexception.ts @@ -108,7 +108,7 @@ export function makeErrorHandler(client: NodeClient, options: OnUncaughtExceptio }, mechanism: { handled: false, - type: 'onuncaughtexception', + type: 'auto.node.onuncaughtexception', }, }); } diff --git a/packages/node-core/src/integrations/onunhandledrejection.ts b/packages/node-core/src/integrations/onunhandledrejection.ts index a11d5c3cf7b0..dbddb2a4c396 100644 --- a/packages/node-core/src/integrations/onunhandledrejection.ts +++ b/packages/node-core/src/integrations/onunhandledrejection.ts @@ -69,7 +69,7 @@ export function makeUnhandledPromiseHandler( }, mechanism: { handled: false, - type: 'onunhandledrejection', + type: 'auto.node.onunhandledrejection', }, }); }); diff --git a/packages/node-core/src/integrations/winston.ts b/packages/node-core/src/integrations/winston.ts index a58a3ea31ad0..63e208920914 100644 --- a/packages/node-core/src/integrations/winston.ts +++ b/packages/node-core/src/integrations/winston.ts @@ -35,9 +35,6 @@ interface WinstonTransportOptions { * @param TransportClass - The Winston transport class to extend. * @returns The extended transport class. * - * @experimental This method will experience breaking changes. This is not yet part of - * the stable Sentry SDK API and can be changed or removed without warning. - * * @example * ```ts * const winston = require('winston'); diff --git a/packages/node-core/src/sdk/esmLoader.ts b/packages/node-core/src/sdk/esmLoader.ts index 2f0d8b405333..14f24f0df311 100644 --- a/packages/node-core/src/sdk/esmLoader.ts +++ b/packages/node-core/src/sdk/esmLoader.ts @@ -1,31 +1,31 @@ -import { consoleSandbox, debug, GLOBAL_OBJ } from '@sentry/core'; +import { debug, GLOBAL_OBJ } from '@sentry/core'; import { createAddHookMessageChannel } from 'import-in-the-middle'; -import moduleModule from 'module'; +import * as moduleModule from 'module'; +import { supportsEsmLoaderHooks } from '../utils/detection'; -/** Initialize the ESM loader. */ -export function maybeInitializeEsmLoader(): void { - const [nodeMajor = 0, nodeMinor = 0] = process.versions.node.split('.').map(Number); +/** + * Initialize the ESM loader - This method is private and not part of the public + * API. + * + * @ignore + */ +export function initializeEsmLoader(): void { + if (!supportsEsmLoaderHooks()) { + return; + } + + if (!GLOBAL_OBJ._sentryEsmLoaderHookRegistered) { + GLOBAL_OBJ._sentryEsmLoaderHookRegistered = true; - // Register hook was added in v20.6.0 and v18.19.0 - if (nodeMajor >= 21 || (nodeMajor === 20 && nodeMinor >= 6) || (nodeMajor === 18 && nodeMinor >= 19)) { - if (!GLOBAL_OBJ._sentryEsmLoaderHookRegistered) { - try { - const { addHookMessagePort } = createAddHookMessageChannel(); - // @ts-expect-error register is available in these versions - moduleModule.register('import-in-the-middle/hook.mjs', import.meta.url, { - data: { addHookMessagePort, include: [] }, - transferList: [addHookMessagePort], - }); - } catch (error) { - debug.warn('Failed to register ESM hook', error); - } + try { + const { addHookMessagePort } = createAddHookMessageChannel(); + // @ts-expect-error register is available in these versions + moduleModule.register('import-in-the-middle/hook.mjs', import.meta.url, { + data: { addHookMessagePort, include: [] }, + transferList: [addHookMessagePort], + }); + } catch (error) { + debug.warn("Failed to register 'import-in-the-middle' hook", error); } - } else { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn( - `[Sentry] You are using Node.js v${process.versions.node} in ESM mode ("import syntax"). The Sentry Node.js SDK is not compatible with ESM in Node.js versions before 18.19.0 or before 20.6.0. Please either build your application with CommonJS ("require() syntax"), or upgrade your Node.js version.`, - ); - }); } } diff --git a/packages/node-core/src/sdk/index.ts b/packages/node-core/src/sdk/index.ts index e5b12166d962..c4a16d76a1d0 100644 --- a/packages/node-core/src/sdk/index.ts +++ b/packages/node-core/src/sdk/index.ts @@ -35,11 +35,11 @@ import { INTEGRATION_NAME as SPOTLIGHT_INTEGRATION_NAME, spotlightIntegration } import { systemErrorIntegration } from '../integrations/systemError'; import { makeNodeTransport } from '../transports'; import type { NodeClientOptions, NodeOptions } from '../types'; -import { isCjs } from '../utils/commonjs'; +import { isCjs } from '../utils/detection'; import { envToBool } from '../utils/envToBool'; import { defaultStackParser, getSentryRelease } from './api'; import { NodeClient } from './client'; -import { maybeInitializeEsmLoader } from './esmLoader'; +import { initializeEsmLoader } from './esmLoader'; /** * Get default integrations for the Node-Core SDK. @@ -106,8 +106,8 @@ function _init( } } - if (!isCjs() && options.registerEsmLoaderHooks !== false) { - maybeInitializeEsmLoader(); + if (options.registerEsmLoaderHooks !== false) { + initializeEsmLoader(); } setOpenTelemetryContextAsyncContextStrategy(); @@ -131,7 +131,7 @@ function _init( client.init(); - debug.log(`Running in ${isCjs() ? 'CommonJS' : 'ESM'} mode.`); + debug.log(`SDK initialized from ${isCjs() ? 'CommonJS' : 'ESM'}`); client.startClientReportTracking(); diff --git a/packages/node-core/src/utils/commonjs.ts b/packages/node-core/src/utils/commonjs.ts deleted file mode 100644 index 23a9b97f9fc1..000000000000 --- a/packages/node-core/src/utils/commonjs.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** Detect CommonJS. */ -export function isCjs(): boolean { - try { - return typeof module !== 'undefined' && typeof module.exports !== 'undefined'; - } catch { - return false; - } -} diff --git a/packages/node-core/src/utils/createMissingInstrumentationContext.ts b/packages/node-core/src/utils/createMissingInstrumentationContext.ts index 1930bcf782eb..3af8dc9e176a 100644 --- a/packages/node-core/src/utils/createMissingInstrumentationContext.ts +++ b/packages/node-core/src/utils/createMissingInstrumentationContext.ts @@ -1,5 +1,5 @@ import type { MissingInstrumentationContext } from '@sentry/core'; -import { isCjs } from './commonjs'; +import { isCjs } from './detection'; export const createMissingInstrumentationContext = (pkg: string): MissingInstrumentationContext => ({ package: pkg, diff --git a/packages/node-core/src/utils/detection.ts b/packages/node-core/src/utils/detection.ts new file mode 100644 index 000000000000..f7ae9a792c27 --- /dev/null +++ b/packages/node-core/src/utils/detection.ts @@ -0,0 +1,39 @@ +import { consoleSandbox } from '@sentry/core'; +import { NODE_MAJOR, NODE_MINOR } from '../nodeVersion'; + +/** Detect CommonJS. */ +export function isCjs(): boolean { + try { + return typeof module !== 'undefined' && typeof module.exports !== 'undefined'; + } catch { + return false; + } +} + +let hasWarnedAboutNodeVersion: boolean | undefined; + +/** + * Check if the current Node.js version supports module.register + */ +export function supportsEsmLoaderHooks(): boolean { + if (isCjs()) { + return false; + } + + if (NODE_MAJOR >= 21 || (NODE_MAJOR === 20 && NODE_MINOR >= 6) || (NODE_MAJOR === 18 && NODE_MINOR >= 19)) { + return true; + } + + if (!hasWarnedAboutNodeVersion) { + hasWarnedAboutNodeVersion = true; + + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.warn( + `[Sentry] You are using Node.js v${process.versions.node} in ESM mode ("import syntax"). The Sentry Node.js SDK is not compatible with ESM in Node.js versions before 18.19.0 or before 20.6.0. Please either build your application with CommonJS ("require() syntax"), or upgrade your Node.js version.`, + ); + }); + } + + return false; +} diff --git a/packages/node-core/src/utils/ensureIsWrapped.ts b/packages/node-core/src/utils/ensureIsWrapped.ts index 70253d9debb7..a73c087ebaf2 100644 --- a/packages/node-core/src/utils/ensureIsWrapped.ts +++ b/packages/node-core/src/utils/ensureIsWrapped.ts @@ -1,8 +1,8 @@ import { isWrapped } from '@opentelemetry/instrumentation'; import { consoleSandbox, getClient, getGlobalScope, hasSpansEnabled, isEnabled } from '@sentry/core'; import type { NodeClient } from '../sdk/client'; -import { isCjs } from './commonjs'; import { createMissingInstrumentationContext } from './createMissingInstrumentationContext'; +import { isCjs } from './detection'; /** * Checks and warns if a framework isn't wrapped by opentelemetry. diff --git a/packages/node/package.json b/packages/node/package.json index 77856d85df3a..ba44a688d33b 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -66,35 +66,35 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/instrumentation-amqplib": "0.50.0", - "@opentelemetry/instrumentation-connect": "0.47.0", - "@opentelemetry/instrumentation-dataloader": "0.21.1", - "@opentelemetry/instrumentation-express": "0.52.0", - "@opentelemetry/instrumentation-fs": "0.23.0", - "@opentelemetry/instrumentation-generic-pool": "0.47.0", - "@opentelemetry/instrumentation-graphql": "0.51.0", - "@opentelemetry/instrumentation-hapi": "0.50.0", - "@opentelemetry/instrumentation-http": "0.203.0", + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-amqplib": "0.51.0", + "@opentelemetry/instrumentation-connect": "0.48.0", + "@opentelemetry/instrumentation-dataloader": "0.22.0", + "@opentelemetry/instrumentation-express": "0.53.0", + "@opentelemetry/instrumentation-fs": "0.24.0", + "@opentelemetry/instrumentation-generic-pool": "0.48.0", + "@opentelemetry/instrumentation-graphql": "0.52.0", + "@opentelemetry/instrumentation-hapi": "0.51.0", + "@opentelemetry/instrumentation-http": "0.204.0", "@opentelemetry/instrumentation-ioredis": "0.52.0", - "@opentelemetry/instrumentation-kafkajs": "0.13.0", - "@opentelemetry/instrumentation-knex": "0.48.0", - "@opentelemetry/instrumentation-koa": "0.51.0", - "@opentelemetry/instrumentation-lru-memoizer": "0.48.0", - "@opentelemetry/instrumentation-mongodb": "0.56.0", - "@opentelemetry/instrumentation-mongoose": "0.50.0", - "@opentelemetry/instrumentation-mysql": "0.49.0", - "@opentelemetry/instrumentation-mysql2": "0.50.0", - "@opentelemetry/instrumentation-pg": "0.55.0", - "@opentelemetry/instrumentation-redis": "0.51.0", - "@opentelemetry/instrumentation-tedious": "0.22.0", - "@opentelemetry/instrumentation-undici": "0.14.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0", - "@prisma/instrumentation": "6.14.0", + "@opentelemetry/instrumentation-kafkajs": "0.14.0", + "@opentelemetry/instrumentation-knex": "0.49.0", + "@opentelemetry/instrumentation-koa": "0.52.0", + "@opentelemetry/instrumentation-lru-memoizer": "0.49.0", + "@opentelemetry/instrumentation-mongodb": "0.57.0", + "@opentelemetry/instrumentation-mongoose": "0.51.0", + "@opentelemetry/instrumentation-mysql": "0.50.0", + "@opentelemetry/instrumentation-mysql2": "0.51.0", + "@opentelemetry/instrumentation-pg": "0.57.0", + "@opentelemetry/instrumentation-redis": "0.53.0", + "@opentelemetry/instrumentation-tedious": "0.23.0", + "@opentelemetry/instrumentation-undici": "0.15.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", + "@prisma/instrumentation": "6.15.0", "@sentry/core": "10.11.0", "@sentry/node-core": "10.11.0", "@sentry/opentelemetry": "10.11.0", diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index f510ca733d19..84603db7e575 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -127,6 +127,7 @@ export { zodErrorsIntegration, profiler, consoleLoggingIntegration, + createConsolaReporter, consoleIntegration, wrapMcpServerWithSentry, featureFlagsIntegration, diff --git a/packages/node/src/integrations/tracing/connect.ts b/packages/node/src/integrations/tracing/connect.ts index c2ab3716bd33..3fd7d10b28fb 100644 --- a/packages/node/src/integrations/tracing/connect.ts +++ b/packages/node/src/integrations/tracing/connect.ts @@ -48,7 +48,12 @@ export const connectIntegration = defineIntegration(_connectIntegration); // eslint-disable-next-line @typescript-eslint/no-explicit-any function connectErrorMiddleware(err: any, req: any, res: any, next: any): void { - captureException(err); + captureException(err, { + mechanism: { + handled: false, + type: 'auto.middleware.connect', + }, + }); next(err); } diff --git a/packages/node/src/integrations/tracing/express.ts b/packages/node/src/integrations/tracing/express.ts index fed0a65cfd0b..e645cc24d31e 100644 --- a/packages/node/src/integrations/tracing/express.ts +++ b/packages/node/src/integrations/tracing/express.ts @@ -130,7 +130,7 @@ export function expressErrorHandler(options?: ExpressHandlerOptions): ExpressErr const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError; if (shouldHandleError(error)) { - const eventId = captureException(error, { mechanism: { type: 'middleware', handled: false } }); + const eventId = captureException(error, { mechanism: { type: 'auto.middleware.express', handled: false } }); (res as { sentry?: string }).sentry = eventId; } diff --git a/packages/node/src/integrations/tracing/fastify/index.ts b/packages/node/src/integrations/tracing/fastify/index.ts index 65d783eb8be7..084c50a6957e 100644 --- a/packages/node/src/integrations/tracing/fastify/index.ts +++ b/packages/node/src/integrations/tracing/fastify/index.ts @@ -132,7 +132,7 @@ function handleFastifyError( } if (shouldHandleError(error, request, reply)) { - captureException(error, { mechanism: { handled: false, type: 'fastify' } }); + captureException(error, { mechanism: { handled: false, type: 'auto.function.fastify' } }); } } diff --git a/packages/node/src/integrations/tracing/firebase/otel/patches/firestore.ts b/packages/node/src/integrations/tracing/firebase/otel/patches/firestore.ts index b450be959b69..cc28aded8e8c 100644 --- a/packages/node/src/integrations/tracing/firebase/otel/patches/firestore.ts +++ b/packages/node/src/integrations/tracing/firebase/otel/patches/firestore.ts @@ -16,7 +16,6 @@ import { ATTR_SERVER_PORT, } from '@opentelemetry/semantic-conventions'; import type { SpanAttributes } from '@sentry/core'; -import type { unwrap as shimmerUnwrap, wrap as shimmerWrap } from 'shimmer'; import type { FirebaseInstrumentation } from '../firebaseInstrumentation'; import type { AddDocType, @@ -37,6 +36,11 @@ import type { WithFieldValue, } from '../types'; +// Inline minimal types used from `shimmer` to avoid importing shimmer's types directly. +// We only need the shape for `wrap` and `unwrap` used in this file. +type ShimmerWrap = (target: any, name: string, wrapper: (...args: any[]) => any) => void; +type ShimmerUnwrap = (target: any, name: string) => void; + /** * * @param tracer - Opentelemetry Tracer @@ -47,8 +51,8 @@ import type { export function patchFirestore( tracer: Tracer, firestoreSupportedVersions: string[], - wrap: typeof shimmerWrap, - unwrap: typeof shimmerUnwrap, + wrap: ShimmerWrap, + unwrap: ShimmerUnwrap, config: FirebaseInstrumentationConfig, ): InstrumentationNodeModuleDefinition { // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -102,8 +106,8 @@ export function patchFirestore( function wrapMethods( // eslint-disable-next-line @typescript-eslint/no-explicit-any moduleExports: any, - wrap: typeof shimmerWrap, - unwrap: typeof shimmerUnwrap, + wrap: ShimmerWrap, + unwrap: ShimmerUnwrap, tracer: Tracer, firestoreSpanCreationHook: FirestoreSpanCreationHook, // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -121,7 +125,7 @@ function wrapMethods( function unwrapMethods( // eslint-disable-next-line @typescript-eslint/no-explicit-any moduleExports: any, - unwrap: typeof shimmerUnwrap, + unwrap: ShimmerUnwrap, // eslint-disable-next-line @typescript-eslint/no-explicit-any ): any { for (const method of ['addDoc', 'getDocs', 'setDoc', 'deleteDoc']) { diff --git a/packages/node/src/integrations/tracing/hapi/index.ts b/packages/node/src/integrations/tracing/hapi/index.ts index eaa8d9c56ad9..a8a64c0b0714 100644 --- a/packages/node/src/integrations/tracing/hapi/index.ts +++ b/packages/node/src/integrations/tracing/hapi/index.ts @@ -54,11 +54,8 @@ function isErrorEvent(event: unknown): event is RequestEvent { function sendErrorToSentry(errorData: object): void { captureException(errorData, { mechanism: { - type: 'hapi', + type: 'auto.function.hapi', handled: false, - data: { - function: 'hapiErrorPlugin', - }, }, }); } diff --git a/packages/node/src/integrations/tracing/koa.ts b/packages/node/src/integrations/tracing/koa.ts index 487f471a9a12..7125479e91e0 100644 --- a/packages/node/src/integrations/tracing/koa.ts +++ b/packages/node/src/integrations/tracing/koa.ts @@ -134,7 +134,12 @@ export const setupKoaErrorHandler = (app: { use: (arg0: (ctx: any, next: any) => try { await next(); } catch (error) { - captureException(error); + captureException(error, { + mechanism: { + handled: false, + type: 'auto.middleware.koa', + }, + }); throw error; } }); diff --git a/packages/node/src/integrations/tracing/prisma.ts b/packages/node/src/integrations/tracing/prisma.ts index bc845362b6bb..503e8c1908a4 100644 --- a/packages/node/src/integrations/tracing/prisma.ts +++ b/packages/node/src/integrations/tracing/prisma.ts @@ -1,4 +1,7 @@ +import type { Link, Tracer } from '@opentelemetry/api'; +import { context, SpanKind, trace, TraceFlags } from '@opentelemetry/api'; import type { Instrumentation } from '@opentelemetry/instrumentation'; +import type { IdGenerator } from '@opentelemetry/sdk-trace-base'; import { PrismaInstrumentation } from '@prisma/instrumentation'; import { consoleSandbox, defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanToJSON } from '@sentry/core'; import { generateInstrumentOnce } from '@sentry/node-core'; @@ -9,6 +12,27 @@ const INTEGRATION_NAME = 'Prisma'; type CompatibilityLayerTraceHelper = PrismaV5TracingHelper & PrismaV6TracingHelper; +// Vendored in from @prisma/instrumentation v5: +type V5EngineSpanEvent = { + span: boolean; + spans: V5EngineSpan[]; +}; + +type V5EngineSpanKind = 'client' | 'internal'; + +type V5EngineSpan = { + span: boolean; + name: string; + trace_id: string; + span_id: string; + parent_span_id: string; + start_time: [number, number]; + end_time: [number, number]; + attributes?: Record; + links?: { trace_id: string; span_id: string }[]; + kind: V5EngineSpanKind; +}; + function isPrismaV6TracingHelper(helper: unknown): helper is PrismaV6TracingHelper { return !!helper && typeof helper === 'object' && 'dispatchEngineSpans' in helper; } @@ -25,6 +49,17 @@ function getPrismaTracingHelper(): unknown | undefined { return prismaTracingHelper; } +type TracerWithIdGenerator = Tracer & { + _idGenerator?: IdGenerator; +}; + +interface PrismaOptions { + /** + * @deprecated This is no longer used, v5 works out of the box. + */ + prismaInstrumentation?: Instrumentation; +} + class SentryPrismaInteropInstrumentation extends PrismaInstrumentation { public constructor() { super(); @@ -35,38 +70,104 @@ class SentryPrismaInteropInstrumentation extends PrismaInstrumentation { // The PrismaIntegration (super class) defines a global variable `global["PRISMA_INSTRUMENTATION"]` when `enable()` is called. This global variable holds a "TracingHelper" which Prisma uses internally to create tracing data. It's their way of not depending on OTEL with their main package. The sucky thing is, prisma broke the interface of the tracing helper with the v6 major update. This means that if you use Prisma 5 with the v6 instrumentation (or vice versa) Prisma just blows up, because tries to call methods on the helper that no longer exist. // Because we actually want to use the v6 instrumentation and not blow up in Prisma 5 user's faces, what we're doing here is backfilling the v5 method (`createEngineSpan`) with a noop so that no longer crashes when it attempts to call that function. - // We still won't fully emit all the spans, but this could potentially be implemented in the future. const prismaTracingHelper = getPrismaTracingHelper(); - let emittedWarning = false; - if (isPrismaV6TracingHelper(prismaTracingHelper)) { - (prismaTracingHelper as CompatibilityLayerTraceHelper).createEngineSpan = () => { - consoleSandbox(() => { - if (!emittedWarning) { - emittedWarning = true; + // Inspired & adjusted from https://github.com/prisma/prisma/tree/5.22.0/packages/instrumentation + (prismaTracingHelper as CompatibilityLayerTraceHelper).createEngineSpan = ( + engineSpanEvent: V5EngineSpanEvent, + ) => { + const tracer = trace.getTracer('prismaV5Compatibility') as TracerWithIdGenerator; + + // Prisma v5 relies on being able to create spans with a specific span & trace ID + // this is no longer possible in OTEL v2, there is no public API to do this anymore + // So in order to kind of hack this possibility, we rely on the internal `_idGenerator` property + // This is used to generate the random IDs, and we overwrite this temporarily to generate static IDs + // This is flawed and may not work, e.g. if the code is bundled and the private property is renamed + // in such cases, these spans will not be captured and some Prisma spans will be missing + const initialIdGenerator = tracer._idGenerator; + + if (!initialIdGenerator) { + consoleSandbox(() => { // eslint-disable-next-line no-console console.warn( - '[Sentry] The Sentry SDK supports tracing with Prisma version 5 only with limited capabilities. For full tracing capabilities pass `prismaInstrumentation` for version 5 to the Sentry `prismaIntegration`. Read more: https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma/', + '[Sentry] Could not find _idGenerator on tracer, skipping Prisma v5 compatibility - some Prisma spans may be missing!', ); - } - }); + }); + + return; + } + + try { + engineSpanEvent.spans.forEach(engineSpan => { + const kind = engineSpanKindToOTELSpanKind(engineSpan.kind); + + const parentSpanId = engineSpan.parent_span_id; + const spanId = engineSpan.span_id; + const traceId = engineSpan.trace_id; + + const links: Link[] | undefined = engineSpan.links?.map(link => { + return { + context: { + traceId: link.trace_id, + spanId: link.span_id, + traceFlags: TraceFlags.SAMPLED, + }, + }; + }); + + const ctx = trace.setSpanContext(context.active(), { + traceId, + spanId: parentSpanId, + traceFlags: TraceFlags.SAMPLED, + }); + + context.with(ctx, () => { + const temporaryIdGenerator: IdGenerator = { + generateTraceId: () => { + return traceId; + }, + generateSpanId: () => { + return spanId; + }, + }; + + tracer._idGenerator = temporaryIdGenerator; + + const span = tracer.startSpan(engineSpan.name, { + kind, + links, + startTime: engineSpan.start_time, + attributes: engineSpan.attributes, + }); + + span.end(engineSpan.end_time); + + tracer._idGenerator = initialIdGenerator; + }); + }); + } finally { + // Ensure we always restore this at the end, even if something errors + tracer._idGenerator = initialIdGenerator; + } }; } } } -export const instrumentPrisma = generateInstrumentOnce<{ prismaInstrumentation?: Instrumentation }>( - INTEGRATION_NAME, - options => { - // Use a passed instrumentation instance to support older Prisma versions - if (options?.prismaInstrumentation) { - return options.prismaInstrumentation; - } +function engineSpanKindToOTELSpanKind(engineSpanKind: V5EngineSpanKind): SpanKind { + switch (engineSpanKind) { + case 'client': + return SpanKind.CLIENT; + case 'internal': + default: // Other span kinds aren't currently supported + return SpanKind.INTERNAL; + } +} - return new SentryPrismaInteropInstrumentation(); - }, -); +export const instrumentPrisma = generateInstrumentOnce(INTEGRATION_NAME, _options => { + return new SentryPrismaInteropInstrumentation(); +}); /** * Adds Sentry tracing instrumentation for the [prisma](https://www.npmjs.com/package/prisma) library. @@ -100,49 +201,36 @@ export const instrumentPrisma = generateInstrumentOnce<{ prismaInstrumentation?: * } * ``` */ -export const prismaIntegration = defineIntegration( - ({ - prismaInstrumentation, - }: { - /** - * Overrides the instrumentation used by the Sentry SDK with the passed in instrumentation instance. - * - * NOTE: By default, the Sentry SDK uses the Prisma v6 instrumentation. Use this option if you need performance instrumentation different Prisma versions. - * - * For more information refer to the documentation of `prismaIntegration()` or see https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma/ - */ - prismaInstrumentation?: Instrumentation; - } = {}) => { - return { - name: INTEGRATION_NAME, - setupOnce() { - instrumentPrisma({ prismaInstrumentation }); - }, - setup(client) { - // If no tracing helper exists, we skip any work here - // this means that prisma is not being used - if (!getPrismaTracingHelper()) { - return; +export const prismaIntegration = defineIntegration((_options?: PrismaOptions) => { + return { + name: INTEGRATION_NAME, + setupOnce() { + instrumentPrisma(); + }, + setup(client) { + // If no tracing helper exists, we skip any work here + // this means that prisma is not being used + if (!getPrismaTracingHelper()) { + return; + } + + client.on('spanStart', span => { + const spanJSON = spanToJSON(span); + if (spanJSON.description?.startsWith('prisma:')) { + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma'); + } + + // Make sure we use the query text as the span name, for ex. SELECT * FROM "User" WHERE "id" = $1 + if (spanJSON.description === 'prisma:engine:db_query' && spanJSON.data['db.query.text']) { + span.updateName(spanJSON.data['db.query.text'] as string); } - client.on('spanStart', span => { - const spanJSON = spanToJSON(span); - if (spanJSON.description?.startsWith('prisma:')) { - span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma'); - } - - // Make sure we use the query text as the span name, for ex. SELECT * FROM "User" WHERE "id" = $1 - if (spanJSON.description === 'prisma:engine:db_query' && spanJSON.data['db.query.text']) { - span.updateName(spanJSON.data['db.query.text'] as string); - } - - // In Prisma v5.22+, the `db.system` attribute is automatically set - // On older versions, this is missing, so we add it here - if (spanJSON.description === 'prisma:engine:db_query' && !spanJSON.data['db.system']) { - span.setAttribute('db.system', 'prisma'); - } - }); - }, - }; - }, -); + // In Prisma v5.22+, the `db.system` attribute is automatically set + // On older versions, this is missing, so we add it here + if (spanJSON.description === 'prisma:engine:db_query' && !spanJSON.data['db.system']) { + span.setAttribute('db.system', 'prisma'); + } + }); + }, + }; +}); diff --git a/packages/node/src/integrations/tracing/vercelai/instrumentation.ts b/packages/node/src/integrations/tracing/vercelai/instrumentation.ts index 0b66f7e80919..bf32d417c42e 100644 --- a/packages/node/src/integrations/tracing/vercelai/instrumentation.ts +++ b/packages/node/src/integrations/tracing/vercelai/instrumentation.ts @@ -9,6 +9,7 @@ import { getActiveSpan, getCurrentScope, handleCallbackErrors, + isThenable, SDK_VERSION, withScope, } from '@sentry/core'; @@ -71,7 +72,7 @@ function isToolError(obj: unknown): obj is ToolError { * Check for tool errors in the result and capture them * Tool errors are not rejected in Vercel V5, it is added as metadata to the result content */ -function checkResultForToolErrors(result: unknown | Promise): void { +function checkResultForToolErrors(result: unknown): void { if (typeof result !== 'object' || result === null || !('content' in result)) { return; } @@ -236,13 +237,18 @@ export class SentryVercelAiInstrumentation extends InstrumentationBase { }; return handleCallbackErrors( - async () => { + () => { // @ts-expect-error we know that the method exists - const result = await originalMethod.apply(this, args); + const result = originalMethod.apply(this, args); - // Tool errors are not rejected in Vercel V5, it is added as metadata to the result content - checkResultForToolErrors(result); + if (isThenable(result)) { + // check for tool errors when the promise resolves, keep the original promise identity + result.then(checkResultForToolErrors, () => {}); + return result; + } + // check for tool errors when the result is synchronous + checkResultForToolErrors(result); return result; }, error => { diff --git a/packages/node/src/sdk/initOtel.ts b/packages/node/src/sdk/initOtel.ts index ef27be0514c3..67de29821537 100644 --- a/packages/node/src/sdk/initOtel.ts +++ b/packages/node/src/sdk/initOtel.ts @@ -7,11 +7,14 @@ import { ATTR_SERVICE_VERSION, SEMRESATTRS_SERVICE_NAMESPACE, } from '@opentelemetry/semantic-conventions'; -import { consoleSandbox, debug as coreDebug, GLOBAL_OBJ, SDK_VERSION } from '@sentry/core'; -import { type NodeClient, isCjs, SentryContextManager, setupOpenTelemetryLogger } from '@sentry/node-core'; +import { debug as coreDebug, SDK_VERSION } from '@sentry/core'; +import { + type NodeClient, + initializeEsmLoader, + SentryContextManager, + setupOpenTelemetryLogger, +} from '@sentry/node-core'; import { SentryPropagator, SentrySampler, SentrySpanProcessor } from '@sentry/opentelemetry'; -import { createAddHookMessageChannel } from 'import-in-the-middle'; -import moduleModule from 'module'; import { DEBUG_BUILD } from '../debug-build'; import { getOpenTelemetryInstrumentationToPreload } from '../integrations/tracing'; @@ -35,34 +38,6 @@ export function initOpenTelemetry(client: NodeClient, options: AdditionalOpenTel client.traceProvider = provider; } -/** Initialize the ESM loader. */ -export function maybeInitializeEsmLoader(): void { - const [nodeMajor = 0, nodeMinor = 0] = process.versions.node.split('.').map(Number); - - // Register hook was added in v20.6.0 and v18.19.0 - if (nodeMajor >= 21 || (nodeMajor === 20 && nodeMinor >= 6) || (nodeMajor === 18 && nodeMinor >= 19)) { - if (!GLOBAL_OBJ._sentryEsmLoaderHookRegistered) { - try { - const { addHookMessagePort } = createAddHookMessageChannel(); - // @ts-expect-error register is available in these versions - moduleModule.register('import-in-the-middle/hook.mjs', import.meta.url, { - data: { addHookMessagePort, include: [] }, - transferList: [addHookMessagePort], - }); - } catch (error) { - coreDebug.warn('Failed to register ESM hook', error); - } - } - } else { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn( - `[Sentry] You are using Node.js v${process.versions.node} in ESM mode ("import syntax"). The Sentry Node.js SDK is not compatible with ESM in Node.js versions before 18.19.0 or before 20.6.0. Please either build your application with CommonJS ("require() syntax"), or upgrade your Node.js version.`, - ); - }); - } -} - interface NodePreloadOptions { debug?: boolean; integrations?: string[]; @@ -80,9 +55,7 @@ export function preloadOpenTelemetry(options: NodePreloadOptions = {}): void { coreDebug.enable(); } - if (!isCjs()) { - maybeInitializeEsmLoader(); - } + initializeEsmLoader(); // These are all integrations that we need to pre-load to ensure they are set up before any other code runs getPreloadMethods(options.integrations).forEach(fn => { diff --git a/packages/nuxt/src/runtime/hooks/captureErrorHook.ts b/packages/nuxt/src/runtime/hooks/captureErrorHook.ts index 7a27b7e6e4c6..9c2bc1011277 100644 --- a/packages/nuxt/src/runtime/hooks/captureErrorHook.ts +++ b/packages/nuxt/src/runtime/hooks/captureErrorHook.ts @@ -40,7 +40,7 @@ export async function sentryCaptureErrorHook(error: Error, errorContext: Capture captureException(error, { captureContext: { contexts: { nuxt: structuredContext } }, - mechanism: { handled: false }, + mechanism: { handled: false, type: 'auto.function.nuxt.nitro' }, }); await flushIfServerless(); diff --git a/packages/nuxt/src/runtime/plugins/index.ts b/packages/nuxt/src/runtime/plugins/index.ts index dbe41b848a0c..b7a5c217edf2 100644 --- a/packages/nuxt/src/runtime/plugins/index.ts +++ b/packages/nuxt/src/runtime/plugins/index.ts @@ -1,2 +1 @@ -// fixme: Can this be exported like this? export { sentryCloudflareNitroPlugin } from './sentry-cloudflare.server'; diff --git a/packages/nuxt/src/runtime/plugins/sentry-cloudflare.server.ts b/packages/nuxt/src/runtime/plugins/sentry-cloudflare.server.ts index 4ddbe8749586..5438ac829d8a 100644 --- a/packages/nuxt/src/runtime/plugins/sentry-cloudflare.server.ts +++ b/packages/nuxt/src/runtime/plugins/sentry-cloudflare.server.ts @@ -1,4 +1,4 @@ -import type { ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types'; +import type { IncomingRequestCfProperties } from '@cloudflare/workers-types'; import type { CloudflareOptions } from '@sentry/cloudflare'; import { setAsyncLocalStorageAsyncContextStrategy, wrapRequestHandler } from '@sentry/cloudflare'; import { debug, getDefaultIsolationScope, getIsolationScope, getTraceData } from '@sentry/core'; @@ -8,50 +8,7 @@ import type { NuxtRenderHTMLContext } from 'nuxt/app'; import { sentryCaptureErrorHook } from '../hooks/captureErrorHook'; import { updateRouteBeforeResponse } from '../hooks/updateRouteBeforeResponse'; import { addSentryTracingMetaTags } from '../utils'; - -interface CfEventType { - protocol: string; - host: string; - method: string; - headers: Record; - context: { - cf: { - httpProtocol?: string; - country?: string; - // ...other CF properties - }; - cloudflare: { - context: ExecutionContext; - request?: Record; - env?: Record; - }; - }; -} - -function isEventType(event: unknown): event is CfEventType { - if (event === null || typeof event !== 'object') return false; - - return ( - // basic properties - 'protocol' in event && - 'host' in event && - typeof event.protocol === 'string' && - typeof event.host === 'string' && - // context property - 'context' in event && - typeof event.context === 'object' && - event.context !== null && - // context.cf properties - 'cf' in event.context && - typeof event.context.cf === 'object' && - event.context.cf !== null && - // context.cloudflare properties - 'cloudflare' in event.context && - typeof event.context.cloudflare === 'object' && - event.context.cloudflare !== null && - 'context' in event.context.cloudflare - ); -} +import { getCfProperties, getCloudflareProperties, hasCfProperty, isEventType } from '../utils/event-type-check'; /** * Sentry Cloudflare Nitro plugin for when using the "cloudflare-pages" preset in Nuxt. @@ -107,13 +64,13 @@ export const sentryCloudflareNitroPlugin = const request = new Request(url, { method: event.method, headers: event.headers, - cf: event.context.cf, + cf: getCfProperties(event), }) as Request>; const requestHandlerOptions = { options: cloudflareOptions, request, - context: event.context.cloudflare.context, + context: getCloudflareProperties(event).context, }; return wrapRequestHandler(requestHandlerOptions, () => { @@ -124,7 +81,7 @@ export const sentryCloudflareNitroPlugin = const traceData = getTraceData(); if (traceData && Object.keys(traceData).length > 0) { // Storing trace data in the WeakMap using event.context.cf as key for later use in HTML meta-tags - traceDataMap.set(event.context.cf, traceData); + traceDataMap.set(getCfProperties(event), traceData); debug.log('Stored trace data for later use in HTML meta-tags: ', traceData); } @@ -144,7 +101,19 @@ export const sentryCloudflareNitroPlugin = // @ts-expect-error - 'render:html' is a valid hook name in the Nuxt context nitroApp.hooks.hook('render:html', (html: NuxtRenderHTMLContext, { event }: { event: H3Event }) => { - const storedTraceData = event?.context?.cf ? traceDataMap.get(event.context.cf) : undefined; + let storedTraceData: ReturnType | undefined = undefined; + + if ( + event?.context && + '_platform' in event.context && + event.context._platform && + hasCfProperty(event.context._platform) + ) { + storedTraceData = traceDataMap.get(event.context._platform.cf); + } else if (event?.context && hasCfProperty(event.context)) { + // legacy support (before Nitro v2.11.7 (PR: https://github.com/nitrojs/nitro/pull/3224)) + storedTraceData = traceDataMap.get(event.context.cf); + } if (storedTraceData && Object.keys(storedTraceData).length > 0) { debug.log('Using stored trace data for HTML meta-tags: ', storedTraceData); diff --git a/packages/nuxt/src/runtime/utils.ts b/packages/nuxt/src/runtime/utils.ts index 29abbe23ec62..ce8069c58cdb 100644 --- a/packages/nuxt/src/runtime/utils.ts +++ b/packages/nuxt/src/runtime/utils.ts @@ -81,7 +81,7 @@ export function reportNuxtError(options: { setTimeout(() => { captureException(error, { captureContext: { contexts: { nuxt: metadata } }, - mechanism: { handled: false }, + mechanism: { handled: false, type: `auto.function.nuxt.${instance ? 'vue' : 'app'}-error` }, }); }); } diff --git a/packages/nuxt/src/runtime/utils/event-type-check.ts b/packages/nuxt/src/runtime/utils/event-type-check.ts new file mode 100644 index 000000000000..1da0d8b2677a --- /dev/null +++ b/packages/nuxt/src/runtime/utils/event-type-check.ts @@ -0,0 +1,105 @@ +import type { CfProperties, ExecutionContext } from '@cloudflare/workers-types'; + +interface EventBase { + protocol: string; + host: string; + method: string; + headers: Record; +} + +interface MinimalCloudflareProps { + context: ExecutionContext; + request?: Record; + env?: Record; +} + +interface CloudflareContext { + cf: CfProperties; + cloudflare: MinimalCloudflareProps; +} + +// Direct shape: cf and cloudflare are directly on context +interface CfEventDirect extends EventBase { + context: CloudflareContext; +} + +// Nested shape: cf and cloudflare are under _platform +// Since Nitro v2.11.7 (PR: https://github.com/nitrojs/nitro/pull/3224) +interface CfEventPlatform extends EventBase { + context: { + _platform: CloudflareContext; + }; +} + +export type CfEventType = CfEventDirect | CfEventPlatform; + +function hasCloudflareProperty(context: unknown): boolean { + return ( + context !== null && + typeof context === 'object' && + // context.cloudflare properties + 'cloudflare' in context && + typeof context.cloudflare === 'object' && + context.cloudflare !== null && + 'context' in context.cloudflare + ); +} + +/** + * Type guard to check if an event context object has cf properties + */ +export function hasCfProperty(context: unknown): context is { cf: CfProperties } { + return ( + context !== null && + typeof context === 'object' && + // context.cf properties + 'cf' in context && + typeof context.cf === 'object' && + context.cf !== null + ); +} + +function hasCfAndCloudflare(context: unknown): context is CloudflareContext { + return hasCfProperty(context) && hasCloudflareProperty(context); +} + +/** + * Type guard to check if an event is a Cloudflare event (nested in _platform or direct) + */ +export function isEventType(event: unknown): event is CfEventType { + if (event === null || typeof event !== 'object') return false; + + return ( + // basic properties + 'protocol' in event && + 'host' in event && + typeof event.protocol === 'string' && + typeof event.host === 'string' && + // context property + 'context' in event && + typeof event.context === 'object' && + event.context !== null && + // context.cf properties + (hasCfAndCloudflare(event.context) || ('_platform' in event.context && hasCfAndCloudflare(event.context._platform))) + ); +} + +/** + * Extracts cf properties from a Cloudflare event + */ +export function getCfProperties(event: CfEventType): CfProperties { + if ('cf' in event.context) { + return event.context.cf; + } + return event.context._platform.cf; +} + +/** + * Extracts cloudflare properties from a Cloudflare event + */ +export function getCloudflareProperties(event: CfEventType): MinimalCloudflareProps { + if ('cloudflare' in event.context) { + return event.context.cloudflare; + } + return event.context._platform.cloudflare; +} diff --git a/packages/nuxt/test/runtime/utils.test.ts b/packages/nuxt/test/runtime/utils.test.ts index 9c3dd568d67a..70226ee12c86 100644 --- a/packages/nuxt/test/runtime/utils.test.ts +++ b/packages/nuxt/test/runtime/utils.test.ts @@ -119,7 +119,7 @@ describe('reportNuxtError', () => { expect(captureException).toHaveBeenCalledWith(mockError, { captureContext: { contexts: { nuxt: { info: undefined } } }, - mechanism: { handled: false }, + mechanism: { handled: false, type: 'auto.function.nuxt.app-error' }, }); }); @@ -129,7 +129,7 @@ describe('reportNuxtError', () => { expect(captureException).toHaveBeenCalledWith(mockError, { captureContext: { contexts: { nuxt: { info: undefined, propsData: { foo: 'bar' } } } }, - mechanism: { handled: false }, + mechanism: { handled: false, type: 'auto.function.nuxt.vue-error' }, }); }); @@ -141,7 +141,7 @@ describe('reportNuxtError', () => { expect(captureException).toHaveBeenCalledWith(mockError, { captureContext: { contexts: { nuxt: { info: undefined } } }, - mechanism: { handled: false }, + mechanism: { handled: false, type: 'auto.function.nuxt.vue-error' }, }); }); @@ -151,7 +151,7 @@ describe('reportNuxtError', () => { expect(captureException).toHaveBeenCalledWith(mockError, { captureContext: { contexts: { nuxt: { info: 'Some info' } } }, - mechanism: { handled: false }, + mechanism: { handled: false, type: 'auto.function.nuxt.app-error' }, }); }); }); diff --git a/packages/nuxt/test/runtime/utils/event-type-check.test.ts b/packages/nuxt/test/runtime/utils/event-type-check.test.ts new file mode 100644 index 000000000000..a63de96b193d --- /dev/null +++ b/packages/nuxt/test/runtime/utils/event-type-check.test.ts @@ -0,0 +1,216 @@ +import type { CfProperties } from '@cloudflare/workers-types'; +import { describe, expect, it, vi } from 'vitest'; +import { + type CfEventType, + getCfProperties, + getCloudflareProperties, + isEventType, +} from '../../../src/runtime/utils/event-type-check'; + +describe('event-type-check', () => { + const mockCfProperties: CfProperties = { + colo: 'IMLND', + country: 'IL', + region: 'CoreRegion', + timezone: 'ImagineLand/Core', + city: 'Core', + } as CfProperties; + + const mockCloudflareProperties = { + context: { + waitUntil: vi.fn(), + passThroughOnException: vi.fn(), + props: { key: 'value' }, + }, + request: { url: 'https://example.com' }, + env: { API_KEY: 'test' }, + }; + + const createUnnestedCfEvent = (): CfEventType => ({ + protocol: 'https', + host: 'example.com', + method: 'GET', + headers: { 'user-agent': 'test' }, + context: { + cf: mockCfProperties, + cloudflare: mockCloudflareProperties, + }, + }); + + const createPlatformCfEvent = (): CfEventType => ({ + protocol: 'https', + host: 'example.com', + method: 'POST', + headers: { 'content-type': 'application/json' }, + context: { + _platform: { + cf: mockCfProperties, + cloudflare: mockCloudflareProperties, + }, + }, + }); + + describe('isEventType', () => { + describe('should return true for valid Cloudflare events', () => { + it.each([ + ['direct cf event', createUnnestedCfEvent()], + ['platform cf event', createPlatformCfEvent()], + ])('%s', (_, event) => { + expect(isEventType(event)).toBe(true); + }); + }); + + describe('should return false for invalid inputs', () => { + it.each([ + ['null', null], + ['undefined', undefined], + ['string', 'invalid'], + ['number', 123], + ['boolean', true], + ['array', []], + ['empty object', {}], + ])('%s', (_, input) => { + expect(isEventType(input)).toBe(false); + }); + }); + + describe('should return false for objects missing required properties', () => { + const baseEvent = createUnnestedCfEvent(); + + it.each([ + ['missing protocol', { ...baseEvent, protocol: undefined }], + ['missing host', { ...baseEvent, host: undefined }], + ['missing context', { ...baseEvent, context: undefined }], + ['null context', { ...baseEvent, context: null }], + ['context without cf', { ...baseEvent, context: { cloudflare: mockCloudflareProperties } }], + ['context without cloudflare', { ...baseEvent, context: { cf: mockCfProperties } }], + ['context with null cf', { ...baseEvent, context: { cf: null, cloudflare: mockCloudflareProperties } }], + ['context with null cloudflare', { ...baseEvent, context: { cf: mockCfProperties, cloudflare: null } }], + [ + 'cloudflare without context property', + { + ...baseEvent, + context: { + cf: mockCfProperties, + cloudflare: { request: {}, env: {} }, + }, + }, + ], + ])('%s', (_, invalidEvent) => { + expect(isEventType(invalidEvent)).toBe(false); + }); + }); + + describe('should return false for platform events missing required properties', () => { + const basePlatformEvent = createPlatformCfEvent(); + + it.each([ + [ + 'platform without cf', + { + ...basePlatformEvent, + context: { + _platform: { + cloudflare: mockCloudflareProperties, + }, + }, + }, + ], + [ + 'platform without cloudflare', + { + ...basePlatformEvent, + context: { + _platform: { + cf: mockCfProperties, + }, + }, + }, + ], + [ + 'platform with null cf', + { + ...basePlatformEvent, + context: { + _platform: { + cf: null, + cloudflare: mockCloudflareProperties, + }, + }, + }, + ], + ])('%s', (_, invalidEvent) => { + expect(isEventType(invalidEvent)).toBe(false); + }); + }); + }); + + describe('getCfProperties', () => { + it.each([ + ['direct cf event', createUnnestedCfEvent()], + ['platform cf event', createPlatformCfEvent()], + ])('should extract cf properties from %s', (_, event) => { + const result = getCfProperties(event); + expect(result).toEqual(mockCfProperties); + expect(result.colo).toBe('IMLND'); + expect(result.country).toBe('IL'); + }); + + it('should return the same cf properties for both event types', () => { + const directEvent = createUnnestedCfEvent(); + const platformEvent = createPlatformCfEvent(); + + const directCf = getCfProperties(directEvent); + const platformCf = getCfProperties(platformEvent); + + expect(directCf).toEqual(platformCf); + }); + }); + + describe('getCloudflareProperties', () => { + it.each([ + ['direct cf event', createUnnestedCfEvent()], + ['platform cf event', createPlatformCfEvent()], + ])('should extract cloudflare properties from %s', (_, event) => { + const result = getCloudflareProperties(event); + expect(result).toEqual(mockCloudflareProperties); + expect(result.context).toBeDefined(); + expect(result.request).toEqual({ url: 'https://example.com' }); + expect(result.env).toEqual({ API_KEY: 'test' }); + }); + + it('should return the same cloudflare properties for both event types', () => { + const directEvent = createUnnestedCfEvent(); + const platformEvent = createPlatformCfEvent(); + + const directCloudflare = getCloudflareProperties(directEvent); + const platformCloudflare = getCloudflareProperties(platformEvent); + + expect(directCloudflare).toEqual(platformCloudflare); + }); + }); + + describe('integration tests', () => { + it('should work together for a complete workflow', () => { + const event = createUnnestedCfEvent(); + + expect(isEventType(event)).toBe(true); + + const cf = getCfProperties(event); + const cloudflare = getCloudflareProperties(event); + + expect(cf.country).toBe('IL'); + expect(cloudflare.request?.url).toBe('https://example.com'); + }); + + it('should handle both event structures consistently', () => { + const events = [createUnnestedCfEvent(), createPlatformCfEvent()]; + + events.forEach(event => { + expect(isEventType(event)).toBe(true); + expect(getCfProperties(event)).toEqual(mockCfProperties); + expect(getCloudflareProperties(event)).toEqual(mockCloudflareProperties); + }); + }); + }); +}); diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json index c21b7cfd782a..13f2c2d990e7 100644 --- a/packages/opentelemetry/package.json +++ b/packages/opentelemetry/package.json @@ -43,17 +43,17 @@ }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", - "@opentelemetry/core": "^1.30.1 || ^2.0.0", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0" + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0" }, "devDependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0" + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 659c39996819..4709b74853ef 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -46,9 +46,9 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@sentry/browser": "10.11.0", "@sentry/cli": "^2.52.0", "@sentry/core": "10.11.0", diff --git a/packages/react-router/test/server/createSentryHandleError.test.ts b/packages/react-router/test/server/createSentryHandleError.test.ts index 0cad5d2a04ba..dddcf2eba86c 100644 --- a/packages/react-router/test/server/createSentryHandleError.test.ts +++ b/packages/react-router/test/server/createSentryHandleError.test.ts @@ -156,7 +156,8 @@ describe('createSentryHandleError', () => { }); describe('flushIfServerless behavior', () => { - it('should wait for flushIfServerless to complete', async () => { + it('waits for flushIfServerless to complete', async () => { + vi.useFakeTimers(); const handleError = createSentryHandleError({}); let resolveFlush: () => void; @@ -172,7 +173,8 @@ describe('createSentryHandleError', () => { const handleErrorPromise = handleError(mockError, mockArgs); - setTimeout(() => resolveFlush(), 10); + vi.advanceTimersByTime(10); + resolveFlush!(); await handleErrorPromise; const endTime = Date.now(); diff --git a/packages/react/src/error.ts b/packages/react/src/error.ts index ca5ccd8b2698..c10cebe4ecf4 100644 --- a/packages/react/src/error.ts +++ b/packages/react/src/error.ts @@ -95,8 +95,11 @@ export function reactErrorHandler( ): (error: any, errorInfo: ErrorInfo) => void { // eslint-disable-next-line @typescript-eslint/no-explicit-any return (error: any, errorInfo: ErrorInfo) => { - const eventId = captureReactException(error, errorInfo); - if (callback) { + const hasCallback = !!callback; + const eventId = captureReactException(error, errorInfo, { + mechanism: { handled: hasCallback, type: 'auto.function.react.error_handler' }, + }); + if (hasCallback) { callback(error, errorInfo, eventId); } }; diff --git a/packages/react/src/errorboundary.tsx b/packages/react/src/errorboundary.tsx index f37afe961042..6377ae9c8399 100644 --- a/packages/react/src/errorboundary.tsx +++ b/packages/react/src/errorboundary.tsx @@ -123,7 +123,9 @@ class ErrorBoundary extends React.Component { test.each([ @@ -13,3 +14,45 @@ describe('isAtLeastReact17', () => { expect(isAtLeastReact17(input)).toBe(output); }); }); + +describe('reactErrorHandler', () => { + const captureException = vi.spyOn(SentryBrowser, 'captureException'); + + beforeEach(() => { + captureException.mockClear(); + }); + + it('captures errors as unhandled when no callback is provided', () => { + const error = new Error('test error'); + const errorInfo = { componentStack: 'component stack' }; + + const handler = reactErrorHandler(); + + handler(error, errorInfo); + + expect(captureException).toHaveBeenCalledTimes(1); + expect(captureException).toHaveBeenCalledWith(error, { + mechanism: { handled: false, type: 'auto.function.react.error_handler' }, + }); + }); + + it('captures errors as handled when a callback is provided', () => { + captureException.mockReturnValueOnce('custom-event-id'); + + const error = new Error('test error'); + const errorInfo = { componentStack: 'component stack' }; + + const callback = vi.fn(); + const handler = reactErrorHandler(callback); + + handler(error, errorInfo); + + expect(captureException).toHaveBeenCalledTimes(1); + expect(captureException).toHaveBeenCalledWith(error, { + mechanism: { handled: true, type: 'auto.function.react.error_handler' }, + }); + + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledWith(error, errorInfo, 'custom-event-id'); + }); +}); diff --git a/packages/react/test/errorboundary.test.tsx b/packages/react/test/errorboundary.test.tsx index 5e731cc86b49..3d2198e81dc9 100644 --- a/packages/react/test/errorboundary.test.tsx +++ b/packages/react/test/errorboundary.test.tsx @@ -385,7 +385,7 @@ describe('ErrorBoundary', () => { expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenLastCalledWith(expect.any(Error), { - mechanism: { handled: true }, + mechanism: { handled: true, type: 'auto.function.react.error_boundary' }, }); expect(scopeSetContextSpy).toHaveBeenCalledTimes(1); @@ -444,7 +444,7 @@ describe('ErrorBoundary', () => { expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenLastCalledWith('bam', { - mechanism: { handled: true }, + mechanism: { handled: true, type: 'auto.function.react.error_boundary' }, }); expect(scopeSetContextSpy).toHaveBeenCalledTimes(1); @@ -483,7 +483,7 @@ describe('ErrorBoundary', () => { expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenLastCalledWith(expect.any(Error), { - mechanism: { handled: true }, + mechanism: { handled: true, type: 'auto.function.react.error_boundary' }, }); expect(scopeSetContextSpy).toHaveBeenCalledTimes(1); @@ -527,7 +527,7 @@ describe('ErrorBoundary', () => { expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenLastCalledWith(expect.any(Error), { - mechanism: { handled: true }, + mechanism: { handled: true, type: 'auto.function.react.error_boundary' }, }); expect(scopeSetContextSpy).toHaveBeenCalledTimes(1); @@ -695,7 +695,7 @@ describe('ErrorBoundary', () => { expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenLastCalledWith(expect.any(Object), { - mechanism: { handled: expected }, + mechanism: { handled: expected, type: 'auto.function.react.error_boundary' }, }); expect(scopeSetContextSpy).toHaveBeenCalledTimes(1); diff --git a/packages/remix/package.json b/packages/remix/package.json index 903019b09cdc..0bf7416ef2fe 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -65,8 +65,8 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/instrumentation": "^0.203.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@remix-run/router": "1.x", "@sentry/cli": "^2.52.0", "@sentry/core": "10.11.0", diff --git a/packages/remix/src/server/errors.ts b/packages/remix/src/server/errors.ts index def6092717c8..e622e743b74c 100644 --- a/packages/remix/src/server/errors.ts +++ b/packages/remix/src/server/errors.ts @@ -65,7 +65,7 @@ export async function captureRemixServerException(err: unknown, name: string, re scope.addEventProcessor(event => { addExceptionMechanism(event, { - type: 'instrument', + type: 'auto.function.remix.server', handled: false, data: { function: name, diff --git a/packages/remix/src/server/index.ts b/packages/remix/src/server/index.ts index 9a785f1d144c..ef25e4b703e6 100644 --- a/packages/remix/src/server/index.ts +++ b/packages/remix/src/server/index.ts @@ -118,6 +118,7 @@ export { zodErrorsIntegration, logger, consoleLoggingIntegration, + createConsolaReporter, createSentryWinstonTransport, } from '@sentry/node'; diff --git a/packages/remix/test/integration/test/server/instrumentation/action.test.ts b/packages/remix/test/integration/test/server/instrumentation/action.test.ts index bca38429ee29..d511368ba707 100644 --- a/packages/remix/test/integration/test/server/instrumentation/action.test.ts +++ b/packages/remix/test/integration/test/server/instrumentation/action.test.ts @@ -90,7 +90,7 @@ describe('Remix API Actions', () => { function: 'remix.server.handleError', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -185,7 +185,7 @@ describe('Remix API Actions', () => { function: 'remix.server.handleError', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -232,7 +232,7 @@ describe('Remix API Actions', () => { function: 'action', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -279,7 +279,7 @@ describe('Remix API Actions', () => { function: 'action', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -326,7 +326,7 @@ describe('Remix API Actions', () => { function: 'action', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -373,7 +373,7 @@ describe('Remix API Actions', () => { function: 'action', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -420,7 +420,7 @@ describe('Remix API Actions', () => { function: 'remix.server.handleError', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -467,7 +467,7 @@ describe('Remix API Actions', () => { function: 'remix.server.handleError', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], diff --git a/packages/remix/test/integration/test/server/instrumentation/loader.test.ts b/packages/remix/test/integration/test/server/instrumentation/loader.test.ts index c90c23d135c8..75bcadf29b0c 100644 --- a/packages/remix/test/integration/test/server/instrumentation/loader.test.ts +++ b/packages/remix/test/integration/test/server/instrumentation/loader.test.ts @@ -35,7 +35,7 @@ describe('Remix API Loaders', () => { function: 'remix.server.handleError', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -77,7 +77,7 @@ describe('Remix API Loaders', () => { function: 'loader', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], @@ -155,7 +155,7 @@ describe('Remix API Loaders', () => { function: 'remix.server.handleError', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], diff --git a/packages/remix/test/integration/test/server/instrumentation/ssr.test.ts b/packages/remix/test/integration/test/server/instrumentation/ssr.test.ts index 1b2a97a99b55..4f5965fac31f 100644 --- a/packages/remix/test/integration/test/server/instrumentation/ssr.test.ts +++ b/packages/remix/test/integration/test/server/instrumentation/ssr.test.ts @@ -36,7 +36,7 @@ describe('Server Side Rendering', () => { function: 'remix.server.handleError', }, handled: false, - type: 'instrument', + type: 'auto.function.remix.server', }, }, ], diff --git a/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts b/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts index 827fc6f5b99b..4df1b62532ac 100644 --- a/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts +++ b/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts @@ -14,11 +14,10 @@ export function handleAfterSendEvent(replay: ReplayContainer): AfterSendEventCal return; } - const statusCode = sendResponse?.statusCode; + const statusCode = sendResponse.statusCode; // We only want to do stuff on successful error sending, otherwise you get error replays without errors attached - // If not using the base transport, we allow `undefined` response (as a custom transport may not implement this correctly yet) - // If we do use the base transport, we skip if we encountered an non-OK status code + // We skip if we encountered an non-OK status code if (!statusCode || statusCode < 200 || statusCode >= 300) { return; } diff --git a/packages/replay-internal/src/util/logger.ts b/packages/replay-internal/src/util/logger.ts index 89ded3c69468..dfdd44b18472 100644 --- a/packages/replay-internal/src/util/logger.ts +++ b/packages/replay-internal/src/util/logger.ts @@ -74,7 +74,12 @@ function makeReplayDebugLogger(): ReplayDebugLogger { coreDebug.error(PREFIX, error); if (_capture) { - captureException(error); + captureException(error, { + mechanism: { + handled: true, + type: 'auto.function.replay.debug', + }, + }); } else if (_trace) { // No need for a breadcrumb if `_capture` is enabled since it should be // captured as an exception diff --git a/packages/replay-internal/test/integration/sendReplayEvent.test.ts b/packages/replay-internal/test/integration/sendReplayEvent.test.ts index 3b6c9b5764e1..1e870a8f577b 100644 --- a/packages/replay-internal/test/integration/sendReplayEvent.test.ts +++ b/packages/replay-internal/test/integration/sendReplayEvent.test.ts @@ -399,7 +399,12 @@ describe('Integration | sendReplayEvent', () => { expect(spyHandleException).toHaveBeenCalledTimes(5); const expectedError = new Error('Unable to send Replay - max retries exceeded'); (expectedError as any).cause = new Error('Something bad happened'); - expect(spyHandleException).toHaveBeenLastCalledWith(expectedError); + expect(spyHandleException).toHaveBeenLastCalledWith(expectedError, { + mechanism: { + handled: true, + type: 'auto.function.replay.debug', + }, + }); const spyHandleExceptionCall = spyHandleException.mock.calls; expect(spyHandleExceptionCall[spyHandleExceptionCall.length - 1][0]?.cause.message).toEqual( diff --git a/packages/replay-internal/test/unit/util/logger.test.ts b/packages/replay-internal/test/unit/util/logger.test.ts index a52512dabed8..a3fc85099525 100644 --- a/packages/replay-internal/test/unit/util/logger.test.ts +++ b/packages/replay-internal/test/unit/util/logger.test.ts @@ -52,7 +52,12 @@ describe('logger', () => { const err = new Error('An error'); debug.exception(err, 'a message'); if (captureExceptions) { - expect(mockCaptureException).toHaveBeenCalledWith(err); + expect(mockCaptureException).toHaveBeenCalledWith(err, { + mechanism: { + handled: true, + type: 'auto.function.replay.debug', + }, + }); } expect(mockLogError).toHaveBeenCalledWith('[Replay] ', 'a message'); expect(mockLogError).toHaveBeenLastCalledWith('[Replay] ', err); @@ -75,7 +80,12 @@ describe('logger', () => { const err = new Error('An error'); debug.exception(err); if (captureExceptions) { - expect(mockCaptureException).toHaveBeenCalledWith(err); + expect(mockCaptureException).toHaveBeenCalledWith(err, { + mechanism: { + handled: true, + type: 'auto.function.replay.debug', + }, + }); expect(mockAddBreadcrumb).not.toHaveBeenCalled(); } expect(mockLogError).toHaveBeenCalledTimes(1); diff --git a/packages/solid/src/errorboundary.ts b/packages/solid/src/errorboundary.ts index df75f9da80f9..aaf99c3f23b2 100644 --- a/packages/solid/src/errorboundary.ts +++ b/packages/solid/src/errorboundary.ts @@ -17,7 +17,12 @@ export function withSentryErrorBoundary(ErrorBoundary: Component void): JSX.Element => { - captureException(error); + captureException(error, { + mechanism: { + handled: true, // handled because user has to provide a fallback + type: 'auto.function.solid.error_boundary', + }, + }); const f = local.fallback; return typeof f === 'function' ? f(error, reset) : f; diff --git a/packages/solid/test/errorboundary.test.tsx b/packages/solid/test/errorboundary.test.tsx index 0ba1a2602bfe..53539e9b0d8e 100644 --- a/packages/solid/test/errorboundary.test.tsx +++ b/packages/solid/test/errorboundary.test.tsx @@ -49,7 +49,12 @@ describe('withSentryErrorBoundary', () => { )); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenLastCalledWith(new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenLastCalledWith(new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); }); it('renders the fallback component', async () => { @@ -89,13 +94,23 @@ describe('withSentryErrorBoundary', () => { )); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenNthCalledWith(1, new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenNthCalledWith(1, new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); const button = await findByRole('button'); await user.click(button); expect(mockCaptureException).toHaveBeenCalledTimes(2); - expect(mockCaptureException).toHaveBeenNthCalledWith(2, new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenNthCalledWith(2, new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); }); it('renders children when there is no error', async () => { diff --git a/packages/solidstart/src/server/index.ts b/packages/solidstart/src/server/index.ts index 17e7eaa9ef50..d1ad987da56f 100644 --- a/packages/solidstart/src/server/index.ts +++ b/packages/solidstart/src/server/index.ts @@ -123,6 +123,7 @@ export { zodErrorsIntegration, logger, consoleLoggingIntegration, + createConsolaReporter, createSentryWinstonTransport, } from '@sentry/node'; diff --git a/packages/solidstart/src/server/withServerActionInstrumentation.ts b/packages/solidstart/src/server/withServerActionInstrumentation.ts index c5c726614279..753188f805c3 100644 --- a/packages/solidstart/src/server/withServerActionInstrumentation.ts +++ b/packages/solidstart/src/server/withServerActionInstrumentation.ts @@ -48,7 +48,7 @@ export async function withServerActionInstrumentation { )); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenLastCalledWith(new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenLastCalledWith(new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); }); it('renders the fallback component', async () => { @@ -89,13 +94,23 @@ describe('withSentryErrorBoundary', () => { )); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenNthCalledWith(1, new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenNthCalledWith(1, new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); const button = await findByRole('button'); await user.click(button); expect(mockCaptureException).toHaveBeenCalledTimes(2); - expect(mockCaptureException).toHaveBeenNthCalledWith(2, new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenNthCalledWith(2, new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); }); it('renders children when there is no error', async () => { diff --git a/packages/solidstart/test/server/errorboundary.test.tsx b/packages/solidstart/test/server/errorboundary.test.tsx index afa2d44e98d7..3ed39bbfea13 100644 --- a/packages/solidstart/test/server/errorboundary.test.tsx +++ b/packages/solidstart/test/server/errorboundary.test.tsx @@ -49,7 +49,12 @@ describe('withSentryErrorBoundary', () => { )); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenLastCalledWith(new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenLastCalledWith(new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); }); it('renders the fallback component', async () => { @@ -89,13 +94,23 @@ describe('withSentryErrorBoundary', () => { )); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenNthCalledWith(1, new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenNthCalledWith(1, new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); const button = await findByRole('button'); await user.click(button); expect(mockCaptureException).toHaveBeenCalledTimes(2); - expect(mockCaptureException).toHaveBeenNthCalledWith(2, new ReferenceError('NonExistentComponent is not defined')); + expect(mockCaptureException).toHaveBeenNthCalledWith(2, new ReferenceError('NonExistentComponent is not defined'), { + mechanism: { + handled: true, + type: 'auto.function.solid.error_boundary', + }, + }); }); it('renders children when there is no error', async () => { diff --git a/packages/solidstart/test/server/withServerActionInstrumentation.test.ts b/packages/solidstart/test/server/withServerActionInstrumentation.test.ts index d2bc90259942..cdfb8050e20d 100644 --- a/packages/solidstart/test/server/withServerActionInstrumentation.test.ts +++ b/packages/solidstart/test/server/withServerActionInstrumentation.test.ts @@ -74,7 +74,9 @@ describe('withServerActionInstrumentation', () => { await expect(res).rejects.toThrow(); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenCalledWith(error, { mechanism: { handled: false, type: 'solidstart' } }); + expect(mockCaptureException).toHaveBeenCalledWith(error, { + mechanism: { handled: false, type: 'auto.function.solidstart' }, + }); }); it("doesn't call captureException for thrown redirects", async () => { diff --git a/packages/sveltekit/src/client/handleError.ts b/packages/sveltekit/src/client/handleError.ts index 14a0a5b4b9cd..d6c50b3519a9 100644 --- a/packages/sveltekit/src/client/handleError.ts +++ b/packages/sveltekit/src/client/handleError.ts @@ -38,7 +38,7 @@ export function handleErrorWithSentry(handleError?: HandleClientError): HandleCl captureException(input.error, { mechanism: { - type: 'sveltekit', + type: 'auto.function.sveltekit.handle_error', handled: !!handleError, }, }); diff --git a/packages/sveltekit/src/client/load.ts b/packages/sveltekit/src/client/load.ts index bf8cf7cb058e..216d2c373547 100644 --- a/packages/sveltekit/src/client/load.ts +++ b/packages/sveltekit/src/client/load.ts @@ -29,11 +29,8 @@ function sendErrorToSentry(e: unknown): unknown { captureException(objectifiedErr, { mechanism: { - type: 'sveltekit', + type: 'auto.function.sveltekit.load', handled: false, - data: { - function: 'load', - }, }, }); diff --git a/packages/sveltekit/src/server-common/handleError.ts b/packages/sveltekit/src/server-common/handleError.ts index 0ca6597ea864..4a7bce331622 100644 --- a/packages/sveltekit/src/server-common/handleError.ts +++ b/packages/sveltekit/src/server-common/handleError.ts @@ -36,7 +36,7 @@ export function handleErrorWithSentry(handleError?: HandleServerError): HandleSe captureException(input.error, { mechanism: { - type: 'sveltekit', + type: 'auto.function.sveltekit.handle_error', handled: !!handleError, }, }); diff --git a/packages/sveltekit/src/server-common/serverRoute.ts b/packages/sveltekit/src/server-common/serverRoute.ts index d09233cb3633..3b98ce270f2d 100644 --- a/packages/sveltekit/src/server-common/serverRoute.ts +++ b/packages/sveltekit/src/server-common/serverRoute.ts @@ -62,7 +62,7 @@ export function wrapServerRouteWithSentry( () => wrappingTarget.apply(thisArg, args), ); } catch (e) { - sendErrorToSentry(e, 'serverRoute'); + sendErrorToSentry(e, 'server_route'); throw e; } finally { await flushIfServerless(); diff --git a/packages/sveltekit/src/server-common/utils.ts b/packages/sveltekit/src/server-common/utils.ts index b861bf758697..6fc67dc60612 100644 --- a/packages/sveltekit/src/server-common/utils.ts +++ b/packages/sveltekit/src/server-common/utils.ts @@ -23,7 +23,7 @@ export function getTracePropagationData(event: RequestEvent): { sentryTrace: str * * @returns an objectified version of @param e */ -export function sendErrorToSentry(e: unknown, handlerFn: 'handle' | 'load' | 'serverRoute'): object { +export function sendErrorToSentry(e: unknown, handlerFn: 'handle' | 'load' | 'server_route'): object { // In case we have a primitive, wrap it in the equivalent wrapper class (string -> String, etc.) so that we can // store a seen flag on it. const objectifiedErr = objectify(e); @@ -42,11 +42,8 @@ export function sendErrorToSentry(e: unknown, handlerFn: 'handle' | 'load' | 'se captureException(objectifiedErr, { mechanism: { - type: 'sveltekit', + type: `auto.function.sveltekit.${handlerFn}`, handled: false, - data: { - function: handlerFn, - }, }, }); diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts index d287331df14d..0613d6397f96 100644 --- a/packages/sveltekit/src/server/index.ts +++ b/packages/sveltekit/src/server/index.ts @@ -125,6 +125,7 @@ export { zodErrorsIntegration, logger, consoleLoggingIntegration, + createConsolaReporter, createSentryWinstonTransport, vercelAIIntegration, } from '@sentry/node'; diff --git a/packages/sveltekit/src/vite/sentryVitePlugins.ts b/packages/sveltekit/src/vite/sentryVitePlugins.ts index 61b388a94cf2..56493e071a55 100644 --- a/packages/sveltekit/src/vite/sentryVitePlugins.ts +++ b/packages/sveltekit/src/vite/sentryVitePlugins.ts @@ -91,31 +91,80 @@ export function generateVitePluginOptions( }; } + // todo(v11): remove deprecated options (Also from options type) + // Source Maps if (svelteKitPluginOptions.autoUploadSourceMaps && process.env.NODE_ENV !== 'development') { - const { unstable_sentryVitePluginOptions, ...sourceMapsUploadOptions } = - svelteKitPluginOptions.sourceMapsUploadOptions || {}; + const { + // eslint-disable-next-line deprecation/deprecation + unstable_sentryVitePluginOptions: deprecated_unstableSourceMapUploadOptions, + ...deprecatedSourceMapUploadOptions + // eslint-disable-next-line deprecation/deprecation + } = svelteKitPluginOptions.sourceMapsUploadOptions || {}; + + const { + // eslint-disable-next-line @typescript-eslint/no-unused-vars,deprecation/deprecation + sourceMapsUploadOptions: _filtered1, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + unstable_sentryVitePluginOptions: _filtered2, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + autoUploadSourceMaps: _filtered3, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + autoInstrument: _filtered4, + sentryUrl, + ...newSvelteKitPluginOptions + } = svelteKitPluginOptions; + + const { unstable_sentryVitePluginOptions } = svelteKitPluginOptions; sentryVitePluginsOptions = { ...(sentryVitePluginsOptions ? sentryVitePluginsOptions : {}), - ...sourceMapsUploadOptions, + ...deprecatedSourceMapUploadOptions, + ...newSvelteKitPluginOptions, + + url: sentryUrl, + + ...deprecated_unstableSourceMapUploadOptions, ...unstable_sentryVitePluginOptions, + adapter: svelteKitPluginOptions.adapter, // override the plugin's debug flag with the one from the top-level options debug: svelteKitPluginOptions.debug, }; - if (sentryVitePluginsOptions.sourcemaps) { + // Handle sourcemaps options - merge deprecated and new, with new taking precedence + if ( + // eslint-disable-next-line deprecation/deprecation + deprecatedSourceMapUploadOptions.sourcemaps || + svelteKitPluginOptions.sourcemaps || + deprecated_unstableSourceMapUploadOptions?.sourcemaps || + unstable_sentryVitePluginOptions?.sourcemaps + ) { sentryVitePluginsOptions.sourcemaps = { - ...sourceMapsUploadOptions?.sourcemaps, + // eslint-disable-next-line deprecation/deprecation + ...deprecatedSourceMapUploadOptions.sourcemaps, + ...svelteKitPluginOptions.sourcemaps, + // Also handle nested deprecated options from unstable plugin options + ...deprecated_unstableSourceMapUploadOptions?.sourcemaps, ...unstable_sentryVitePluginOptions?.sourcemaps, }; } - if (sentryVitePluginsOptions.release) { + // Handle release options - merge deprecated and new, with new taking precedence + if ( + // eslint-disable-next-line deprecation/deprecation + deprecatedSourceMapUploadOptions.release || + svelteKitPluginOptions.release || + deprecated_unstableSourceMapUploadOptions?.release || + unstable_sentryVitePluginOptions?.release + ) { sentryVitePluginsOptions.release = { - ...sourceMapsUploadOptions?.release, + // eslint-disable-next-line deprecation/deprecation + ...deprecatedSourceMapUploadOptions.release, + ...svelteKitPluginOptions.release, + // Also handle nested deprecated options from unstable plugin options + ...deprecated_unstableSourceMapUploadOptions?.release, ...unstable_sentryVitePluginOptions?.release, }; } diff --git a/packages/sveltekit/src/vite/types.ts b/packages/sveltekit/src/vite/types.ts index 4267ce378bb1..5f623cc876ad 100644 --- a/packages/sveltekit/src/vite/types.ts +++ b/packages/sveltekit/src/vite/types.ts @@ -1,3 +1,4 @@ +import type { BuildTimeOptionsBase, UnstableVitePluginOptions } from '@sentry/core'; import type { SentryVitePluginOptions } from '@sentry/vite-plugin'; import type { AutoInstrumentSelection } from './autoInstrument'; import type { SupportedSvelteKitAdapters } from './detectAdapter'; @@ -19,18 +20,24 @@ type SourceMapsUploadOptions = { * * To create an auth token, follow this guide: * @see https://docs.sentry.io/product/accounts/auth-tokens/#organization-auth-tokens + * + * @deprecated Use option `authToken` instead of `sourceMapsUploadOptions.authToken` */ authToken?: string; /** * The organization slug of your Sentry organization. * Instead of specifying this option, you can also set the `SENTRY_ORG` environment variable. + * + * @deprecated Use option `org` instead of `sourceMapsUploadOptions.org` */ org?: string; /** * The project slug of your Sentry project. * Instead of specifying this option, you can also set the `SENTRY_PROJECT` environment variable. + * + * @deprecated Use option `project` instead of `sourceMapsUploadOptions.project` */ project?: string; @@ -39,11 +46,13 @@ type SourceMapsUploadOptions = { * It will not collect any sensitive or user-specific data. * * @default true + * @deprecated Use option `telemetry` instead of `sourceMapsUploadOptions.telemetry` */ telemetry?: boolean; /** * Options related to sourcemaps + * @deprecated Use `sourcemaps` instead of `sourceMapsUploadOptions.sourcemaps` */ sourcemaps?: { /** @@ -55,6 +64,7 @@ type SourceMapsUploadOptions = { * * The globbing patterns must follow the implementation of the `glob` package. * @see https://www.npmjs.com/package/glob#glob-primer + * @deprecated Use `sourcemaps.assets` instead of `sourceMapsUploadOptions.sourcemaps.assets` */ assets?: string | Array; @@ -65,6 +75,8 @@ type SourceMapsUploadOptions = { * or the default value for `assets` are uploaded. * * The globbing patterns follow the implementation of the glob package. (https://www.npmjs.com/package/glob) + * + * @deprecated Use `sourcemaps.ignore` instead of `sourceMapsUploadOptions.sourcemaps.ignore` */ ignore?: string | Array; @@ -75,6 +87,8 @@ type SourceMapsUploadOptions = { * @default [] - By default no files are deleted. * * The globbing patterns follow the implementation of the glob package. (https://www.npmjs.com/package/glob) + * + * @deprecated Use `sourcemaps.filesToDeleteAfterUpload` instead of `sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload` */ filesToDeleteAfterUpload?: string | Array; }; @@ -83,6 +97,8 @@ type SourceMapsUploadOptions = { * Options related to managing the Sentry releases for a build. * * Note: Managing releases is optional and not required for uploading source maps. + * + * @deprecated Use `release` instead of `sourceMapsUploadOptions.release` */ release?: { /** @@ -94,6 +110,8 @@ type SourceMapsUploadOptions = { * access to git CLI and for the root directory to be a valid repository). * * If you didn't provide a value and the plugin can't automatically detect one, no release will be created. + * + * @deprecated Use `release.name` instead of `sourceMapsUploadOptions.release.name` */ name?: string; @@ -102,12 +120,16 @@ type SourceMapsUploadOptions = { * sending events. * * Defaults to `true`. + * + * @deprecated Use `release.inject` instead of `sourceMapsUploadOptions.release.inject` */ inject?: boolean; }; /** * The URL of the Sentry instance to upload the source maps to. + * + * @deprecated Use `sentryUrl` instead of `sourceMapsUploadOptions.url` */ url?: string; @@ -123,105 +145,54 @@ type SourceMapsUploadOptions = { * 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()). + * @deprecated Use `unstable_sentryVitePluginOptions` instead of `sourceMapsUploadOptions.unstable_sentryVitePluginOptions` */ - 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; + unstable_sentryVitePluginOptions?: Partial; }; /** Options for the Sentry SvelteKit plugin */ -export type SentrySvelteKitPluginOptions = { - /** - * If this flag is `true`, the Sentry plugins will log some useful debug information. - * @default false. - */ - debug?: boolean; - - /** - * The Sentry plugin will automatically instrument certain parts of your SvelteKit application at build time. - * Set this option to `false` to disable this behavior or what is intrumented by passing an object. - * - * Auto instrumentation includes: - * - Universal `load` functions in `+page.(js|ts)` files - * - Server-only `load` functions in `+page.server.(js|ts)` files - * - * @default true (meaning, the plugin will instrument all of the above) - */ - autoInstrument?: boolean | AutoInstrumentSelection; - - /** - * Specify which SvelteKit adapter you're using. - * By default, the SDK will attempt auto-detect the used adapter at build time and apply the - * correct config for source maps upload or auto-instrumentation. - * - * Currently, the SDK supports the following adapters: - * - node (@sveltejs/adapter-node) - * - auto (@sveltejs/adapter-auto) only Vercel - * - vercel (@sveltejs/adapter-auto) only Serverless functions, no edge runtime - * - * Set this option, if the SDK detects the wrong adapter or you want to use an adapter - * that is not in this list. If you specify 'other', you'll most likely need to configure - * source maps upload yourself. - * - * @default {} the SDK attempts to auto-detect the used adapter at build time - */ - adapter?: SupportedSvelteKitAdapters; +export type SentrySvelteKitPluginOptions = BuildTimeOptionsBase & + UnstableVitePluginOptions> & { + /** + * The Sentry plugin will automatically instrument certain parts of your SvelteKit application at build time. + * Set this option to `false` to disable this behavior or what is intrumented by passing an object. + * + * Auto instrumentation includes: + * - Universal `load` functions in `+page.(js|ts)` files + * - Server-only `load` functions in `+page.server.(js|ts)` files + * + * @default true (meaning, the plugin will instrument all of the above) + */ + autoInstrument?: boolean | AutoInstrumentSelection; - /** - * Options for the Sentry Vite plugin to customize bundle size optimizations. - * - * These options are always read from the `sentryAstro` integration. - * Do not define them in the `sentry.client.config.(js|ts)` or `sentry.server.config.(js|ts)` files. - */ - bundleSizeOptimizations?: BundleSizeOptimizationOptions; + /** + * Specify which SvelteKit adapter you're using. + * By default, the SDK will attempt auto-detect the used adapter at build time and apply the + * correct config for source maps upload or auto-instrumentation. + * + * Currently, the SDK supports the following adapters: + * - node (@sveltejs/adapter-node) + * - auto (@sveltejs/adapter-auto) only Vercel + * - vercel (@sveltejs/adapter-auto) only Serverless functions, no edge runtime + * + * Set this option, if the SDK detects the wrong adapter or you want to use an adapter + * that is not in this list. If you specify 'other', you'll most likely need to configure + * source maps upload yourself. + * + * @default {} the SDK attempts to auto-detect the used adapter at build time + */ + adapter?: SupportedSvelteKitAdapters; - /** - * If this flag is `true`, the Sentry plugins will automatically upload source maps to Sentry. - * @default true`. - */ - autoUploadSourceMaps?: boolean; + /** + * If this flag is `true`, the Sentry plugins will automatically upload source maps to Sentry. + * @default true`. + */ + autoUploadSourceMaps?: boolean; - /** - * Options related to source maps upload to Sentry - */ - sourceMapsUploadOptions?: SourceMapsUploadOptions; -}; + /** * Options related to source maps upload to Sentry + * + * @deprecated This option was deprecated as it adds unnecessary nesting. Put the options one level higher to the root-level of the Sentry Svelte plugin options. + */ + sourceMapsUploadOptions?: SourceMapsUploadOptions; + }; diff --git a/packages/sveltekit/test/client/handleError.test.ts b/packages/sveltekit/test/client/handleError.test.ts index 810acd865aa2..3511ff62f83b 100644 --- a/packages/sveltekit/test/client/handleError.test.ts +++ b/packages/sveltekit/test/client/handleError.test.ts @@ -21,10 +21,6 @@ const navigationEvent: NavigationEvent = { url: new URL('http://example.org/users/123'), }; -const captureExceptionEventHint = { - mechanism: { handled: false, type: 'sveltekit' }, -}; - const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(_ => {}); describe('handleError (client)', () => { @@ -42,7 +38,9 @@ describe('handleError (client)', () => { expect(returnVal).not.toBeDefined(); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenCalledWith(mockError, captureExceptionEventHint); + expect(mockCaptureException).toHaveBeenCalledWith(mockError, { + mechanism: { handled: false, type: 'auto.function.sveltekit.handle_error' }, + }); // The default handler logs the error to the console expect(consoleErrorSpy).toHaveBeenCalledTimes(1); }); @@ -56,7 +54,7 @@ describe('handleError (client)', () => { expect(returnVal.message).toEqual('Whoops!'); expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenCalledWith(mockError, { - mechanism: { handled: true, type: 'sveltekit' }, + mechanism: { handled: true, type: 'auto.function.sveltekit.handle_error' }, }); // Check that the default handler wasn't invoked diff --git a/packages/sveltekit/test/client/load.test.ts b/packages/sveltekit/test/client/load.test.ts index 465167265d49..b7d0b58ffe93 100644 --- a/packages/sveltekit/test/client/load.test.ts +++ b/packages/sveltekit/test/client/load.test.ts @@ -154,7 +154,7 @@ describe('wrapLoadWithSentry', () => { expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error), { - mechanism: { handled: false, type: 'sveltekit', data: { function: 'load' } }, + mechanism: { handled: false, type: 'auto.function.sveltekit.load' }, }); }); diff --git a/packages/sveltekit/test/server-common/handle.test.ts b/packages/sveltekit/test/server-common/handle.test.ts index db1e1fe4811f..fdb4a1103d90 100644 --- a/packages/sveltekit/test/server-common/handle.test.ts +++ b/packages/sveltekit/test/server-common/handle.test.ts @@ -317,7 +317,7 @@ describe('sentryHandle', () => { } catch (e) { expect(mockCaptureException).toBeCalledTimes(1); expect(mockCaptureException).toBeCalledWith(expect.any(Error), { - mechanism: { handled: false, type: 'sveltekit', data: { function: 'handle' } }, + mechanism: { handled: false, type: 'auto.function.sveltekit.handle' }, }); } }); diff --git a/packages/sveltekit/test/server-common/handleError.test.ts b/packages/sveltekit/test/server-common/handleError.test.ts index 6b4b3af992d1..30fa7e78c137 100644 --- a/packages/sveltekit/test/server-common/handleError.test.ts +++ b/packages/sveltekit/test/server-common/handleError.test.ts @@ -5,10 +5,6 @@ import { handleErrorWithSentry } from '../../src/server-common/handleError'; const mockCaptureException = vi.spyOn(SentryCore, 'captureException').mockImplementation(() => 'xx'); -const captureExceptionEventHint = { - mechanism: { handled: false, type: 'sveltekit' }, -}; - function handleError(_input: { error: unknown; event: RequestEvent }): ReturnType { return { message: 'Whoops!', @@ -73,7 +69,9 @@ describe('handleError (server)', () => { expect(returnVal).not.toBeDefined(); expect(mockCaptureException).toHaveBeenCalledTimes(1); - expect(mockCaptureException).toHaveBeenCalledWith(mockError, captureExceptionEventHint); + expect(mockCaptureException).toHaveBeenCalledWith(mockError, { + mechanism: { handled: false, type: 'auto.function.sveltekit.handle_error' }, + }); // The default handler logs the error to the console expect(consoleErrorSpy).toHaveBeenCalledTimes(1); }); @@ -91,7 +89,7 @@ describe('handleError (server)', () => { expect(returnVal.message).toEqual('Whoops!'); expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenCalledWith(mockError, { - mechanism: { handled: true, type: 'sveltekit' }, + mechanism: { handled: true, type: 'auto.function.sveltekit.handle_error' }, }); // Check that the default handler wasn't invoked expect(consoleErrorSpy).toHaveBeenCalledTimes(0); diff --git a/packages/sveltekit/test/server-common/load.test.ts b/packages/sveltekit/test/server-common/load.test.ts index c3200d9a7927..4ec2cf6967c2 100644 --- a/packages/sveltekit/test/server-common/load.test.ts +++ b/packages/sveltekit/test/server-common/load.test.ts @@ -150,7 +150,7 @@ describe.each([ expect(mockCaptureException).toHaveBeenCalledTimes(1); expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error), { - mechanism: { handled: false, type: 'sveltekit', data: { function: 'load' } }, + mechanism: { handled: false, type: 'auto.function.sveltekit.load' }, }); }); }); diff --git a/packages/sveltekit/test/server-common/serverRoute.test.ts b/packages/sveltekit/test/server-common/serverRoute.test.ts index 046c3673a8c7..2ec3ef2cf2d2 100644 --- a/packages/sveltekit/test/server-common/serverRoute.test.ts +++ b/packages/sveltekit/test/server-common/serverRoute.test.ts @@ -85,7 +85,7 @@ describe('wrapServerRouteWithSentry', () => { }).rejects.toThrowError('Server Route Error'); expect(captureExceptionSpy).toHaveBeenCalledWith(error, { - mechanism: { type: 'sveltekit', handled: false, data: { function: 'serverRoute' } }, + mechanism: { type: 'auto.function.sveltekit.server_route', handled: false }, }); }); @@ -101,7 +101,10 @@ describe('wrapServerRouteWithSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledWith( { body: { message: `error(${status}) error` }, status }, { - mechanism: { type: 'sveltekit', handled: false, data: { function: 'serverRoute' } }, + mechanism: { + type: 'auto.function.sveltekit.server_route', + handled: false, + }, }, ); }); diff --git a/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts b/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts index fa8df96f03a6..eef008fca73d 100644 --- a/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts +++ b/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts @@ -30,6 +30,7 @@ function getSentrySvelteKitPlugins(options?: Parameters[ authToken: 'token', org: 'org', project: 'project', + // eslint-disable-next-line deprecation/deprecation ...options?.sourceMapsUploadOptions, }, ...options, @@ -389,4 +390,263 @@ describe('generateVitePluginOptions', () => { process.env.NODE_ENV = originalEnv; }); + + it.each([ + { + testName: 'org setting precedence', + options: { + autoUploadSourceMaps: true, + org: 'root-org', + sourceMapsUploadOptions: { + org: 'deprecated-org', + unstable_sentryVitePluginOptions: { + org: 'unstable-org', + }, + }, + unstable_sentryVitePluginOptions: { + org: 'new-unstable-org', + }, + }, + expectedOrg: 'new-unstable-org', + }, + { + testName: 'project setting precedence', + options: { + autoUploadSourceMaps: true, + project: 'root-project', + sourceMapsUploadOptions: { + project: 'deprecated-project', + unstable_sentryVitePluginOptions: { + project: 'unstable-project', + }, + }, + unstable_sentryVitePluginOptions: { + project: 'new-unstable-project', + }, + }, + expectedProject: 'new-unstable-project', + }, + { + testName: 'authToken setting precedence', + options: { + autoUploadSourceMaps: true, + authToken: 'root-token', + sourceMapsUploadOptions: { + authToken: 'deprecated-token', + unstable_sentryVitePluginOptions: { + authToken: 'unstable-token', + }, + }, + unstable_sentryVitePluginOptions: { + authToken: 'new-unstable-token', + }, + }, + expectedAuthToken: 'new-unstable-token', + }, + { + testName: 'telemetry setting precedence', + options: { + autoUploadSourceMaps: true, + telemetry: true, + sourceMapsUploadOptions: { + telemetry: false, + unstable_sentryVitePluginOptions: { + telemetry: true, + }, + }, + unstable_sentryVitePluginOptions: { + telemetry: false, + }, + }, + expectedTelemetry: false, + }, + { + testName: 'url setting precedence', + options: { + autoUploadSourceMaps: true, + sentryUrl: 'https://root.sentry.io', + sourceMapsUploadOptions: { + url: 'https://deprecated.sentry.io', + unstable_sentryVitePluginOptions: { + url: 'https://unstable.sentry.io', + }, + }, + unstable_sentryVitePluginOptions: { + url: 'https://new-unstable.sentry.io', + }, + }, + expectedUrl: 'https://new-unstable.sentry.io', + }, + ])( + 'should use correct $testName', + ({ options, expectedOrg, expectedProject, expectedAuthToken, expectedTelemetry, expectedUrl }) => { + const result = generateVitePluginOptions(options as SentrySvelteKitPluginOptions); + + if (expectedOrg !== undefined) { + expect(result?.org).toBe(expectedOrg); + } + if (expectedProject !== undefined) { + expect(result?.project).toBe(expectedProject); + } + if (expectedAuthToken !== undefined) { + expect(result?.authToken).toBe(expectedAuthToken); + } + if (expectedTelemetry !== undefined) { + expect(result?.telemetry).toBe(expectedTelemetry); + } + if (expectedUrl !== undefined) { + expect(result?.url).toBe(expectedUrl); + } + }, + ); + + it('should handle sourcemap settings with correct order of overrides', () => { + const options: SentrySvelteKitPluginOptions = { + autoUploadSourceMaps: true, + sourcemaps: { + assets: ['root/*.js'], + ignore: ['root/ignore/*.js'], + filesToDeleteAfterUpload: ['root/delete/*.js'], + }, + sourceMapsUploadOptions: { + sourcemaps: { + assets: ['deprecated/*.js'], + ignore: ['deprecated/ignore/*.js'], + filesToDeleteAfterUpload: ['deprecated/delete/*.js'], + }, + unstable_sentryVitePluginOptions: { + sourcemaps: { + assets: ['unstable/*.js'], + ignore: ['unstable/ignore/*.js'], + }, + }, + }, + unstable_sentryVitePluginOptions: { + sourcemaps: { + assets: ['new-unstable/*.js'], + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], + }, + }, + }; + + const result = generateVitePluginOptions(options); + + expect(result?.sourcemaps).toEqual({ + assets: ['new-unstable/*.js'], // new unstable takes precedence + ignore: ['unstable/ignore/*.js'], // from deprecated unstable (not overridden by new unstable) + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], // new unstable takes precedence + }); + }); + + it('should handle release settings with correct order of overrides', () => { + const newReleaseOptions = { + name: 'root-release', + inject: true, + }; + const newUnstableReleaseOptions = { + name: 'new-unstable-release', + deploy: { + env: 'production', + }, + }; + + const options: SentrySvelteKitPluginOptions = { + autoUploadSourceMaps: true, + release: newReleaseOptions, + sourceMapsUploadOptions: { + release: { + name: 'deprecated-release', + inject: false, + }, + unstable_sentryVitePluginOptions: { + release: { name: 'deprecated-unstable-release', setCommits: { auto: true } }, + }, + }, + unstable_sentryVitePluginOptions: { release: newUnstableReleaseOptions }, + }; + + const result = generateVitePluginOptions(options); + + expect(result?.release).toEqual({ + name: newUnstableReleaseOptions.name, + inject: newReleaseOptions.inject, + setCommits: { + auto: true, // from deprecated unstable (not overridden) + }, + deploy: { + env: 'production', // from new unstable + }, + }); + }); + + it('should handle complex override scenario with all settings', () => { + const options: SentrySvelteKitPluginOptions = { + autoUploadSourceMaps: true, + org: 'root-org', + project: 'root-project', + authToken: 'root-token', + telemetry: true, + sentryUrl: 'https://root.sentry.io', + debug: false, + sourcemaps: { + assets: ['root/*.js'], + }, + release: { + name: 'root-1.0.0', + }, + sourceMapsUploadOptions: { + org: 'deprecated-org', + project: 'deprecated-project', + authToken: 'deprecated-token', + telemetry: false, + url: 'https://deprecated.sentry.io', + sourcemaps: { + assets: ['deprecated/*.js'], + ignore: ['deprecated/ignore/*.js'], + }, + release: { + name: 'deprecated-1.0.0', + inject: false, + }, + unstable_sentryVitePluginOptions: { + org: 'old-unstable-org', + sourcemaps: { + assets: ['old-unstable/*.js'], + }, + }, + }, + unstable_sentryVitePluginOptions: { + org: 'new-unstable-org', + authToken: 'new-unstable-token', + sourcemaps: { + assets: ['new-unstable/*.js'], + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], + }, + release: { + name: 'new-unstable-1.0.0', + }, + }, + }; + + const result = generateVitePluginOptions(options); + + expect(result).toEqual({ + org: 'new-unstable-org', + project: 'root-project', + authToken: 'new-unstable-token', + telemetry: true, + url: 'https://root.sentry.io', + sourcemaps: { + assets: ['new-unstable/*.js'], + ignore: ['deprecated/ignore/*.js'], + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], + }, + release: { + name: 'new-unstable-1.0.0', + inject: false, + }, + adapter: undefined, + debug: false, + }); + }); }); diff --git a/packages/tanstackstart-react/package.json b/packages/tanstackstart-react/package.json index 4eb3507ad0be..42d94c1188c8 100644 --- a/packages/tanstackstart-react/package.json +++ b/packages/tanstackstart-react/package.json @@ -51,7 +51,7 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@sentry-internal/browser-utils": "10.11.0", "@sentry/core": "10.11.0", "@sentry/node": "10.11.0", diff --git a/packages/vercel-edge/package.json b/packages/vercel-edge/package.json index 7cb476c38f40..3afcf65244aa 100644 --- a/packages/vercel-edge/package.json +++ b/packages/vercel-edge/package.json @@ -40,14 +40,14 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/resources": "^2.1.0", "@sentry/core": "10.11.0" }, "devDependencies": { "@edge-runtime/types": "3.0.1", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", "@sentry/opentelemetry": "10.11.0" }, "scripts": { diff --git a/packages/vercel-edge/src/index.ts b/packages/vercel-edge/src/index.ts index e2fd90eda5b7..3e432c06c1fd 100644 --- a/packages/vercel-edge/src/index.ts +++ b/packages/vercel-edge/src/index.ts @@ -70,6 +70,7 @@ export { // eslint-disable-next-line deprecation/deprecation inboundFiltersIntegration, instrumentOpenAiClient, + instrumentAnthropicAiClient, eventFiltersIntegration, linkedErrorsIntegration, requestDataIntegration, @@ -92,6 +93,7 @@ export { spanToBaggageHeader, wrapMcpServerWithSentry, consoleLoggingIntegration, + createConsolaReporter, featureFlagsIntegration, } from '@sentry/core'; diff --git a/packages/vue/src/errorhandler.ts b/packages/vue/src/errorhandler.ts index f8ca3b9a2c9f..c18a51492c4a 100644 --- a/packages/vue/src/errorhandler.ts +++ b/packages/vue/src/errorhandler.ts @@ -30,7 +30,7 @@ export const attachErrorHandler = (app: Vue, options: VueOptions): void => { setTimeout(() => { captureException(error, { captureContext: { contexts: { vue: metadata } }, - mechanism: { handled: !!originalErrorHandler, type: 'vue' }, + mechanism: { handled: !!originalErrorHandler, type: 'auto.function.vue.error_handler' }, }); }); diff --git a/packages/vue/test/errorHandler.test.ts b/packages/vue/test/errorHandler.test.ts index 9e8e7572ba54..54fd80133017 100644 --- a/packages/vue/test/errorHandler.test.ts +++ b/packages/vue/test/errorHandler.test.ts @@ -26,7 +26,9 @@ describe('attachErrorHandler', () => { // assert t.expect.errorToHaveBeenCaptured().withoutProps(); - t.expect.errorToHaveBeenCaptured().withMechanismMetadata({ handled: false, type: 'vue' }); + t.expect + .errorToHaveBeenCaptured() + .withMechanismMetadata({ handled: false, type: 'auto.function.vue.error_handler' }); }); }); @@ -47,7 +49,9 @@ describe('attachErrorHandler', () => { // assert t.expect.errorToHaveBeenCaptured().withoutProps(); - t.expect.errorToHaveBeenCaptured().withMechanismMetadata({ handled: false, type: 'vue' }); + t.expect + .errorToHaveBeenCaptured() + .withMechanismMetadata({ handled: false, type: 'auto.function.vue.error_handler' }); }); }); @@ -146,7 +150,9 @@ describe('attachErrorHandler', () => { vi.runAllTimers(); // assert - t.expect.errorToHaveBeenCaptured().withMechanismMetadata({ handled: false, type: 'vue' }); + t.expect + .errorToHaveBeenCaptured() + .withMechanismMetadata({ handled: false, type: 'auto.function.vue.error_handler' }); }); it('should mark error as handled and properly delegate to error handler', () => { @@ -167,7 +173,9 @@ describe('attachErrorHandler', () => { // assert t.expect.errorHandlerSpy.toHaveBeenCalledWith(expect.any(Error), vm, 'stub-lifecycle-hook'); - t.expect.errorToHaveBeenCaptured().withMechanismMetadata({ handled: true, type: 'vue' }); + t.expect + .errorToHaveBeenCaptured() + .withMechanismMetadata({ handled: true, type: 'auto.function.vue.error_handler' }); }); }); }); @@ -305,7 +313,7 @@ const testHarness = ({ withoutProps: () => { expect(contexts).not.toHaveProperty('vue.propsData'); }, - withMechanismMetadata: (mechanism: { handled: boolean; type: 'vue' }) => { + withMechanismMetadata: (mechanism: { handled: boolean; type: 'auto.function.vue.error_handler' }) => { expect(mechanismMetadata).toEqual(mechanism); }, }; diff --git a/yarn.lock b/yarn.lock index db7641e5a892..f1bedd816167 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5858,13 +5858,6 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@opentelemetry/api-logs@0.203.0": - version "0.203.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.203.0.tgz#3309a76c51a848ea820cd7f00ee62daf36b06380" - integrity sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ== - dependencies: - "@opentelemetry/api" "^1.3.0" - "@opentelemetry/api-logs@0.204.0": version "0.204.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.204.0.tgz#c0285aa5c79625a1c424854393902d21732fd76b" @@ -5884,108 +5877,100 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== -"@opentelemetry/context-async-hooks@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-2.0.0.tgz#c98a727238ca199cda943780acf6124af8d8cd80" - integrity sha512-IEkJGzK1A9v3/EHjXh3s2IiFc6L4jfK+lNgKVgUjeUJQRRhnVFMIO3TAvKwonm9O1HebCuoOt98v8bZW7oVQHA== - -"@opentelemetry/core@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.0.0.tgz#37e9f0e9ddec4479b267aca6f32d88757c941b3a" - integrity sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ== - dependencies: - "@opentelemetry/semantic-conventions" "^1.29.0" +"@opentelemetry/context-async-hooks@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-2.1.0.tgz#de1de21d9536abfe73769f822b52a59a8c97b083" + integrity sha512-zOyetmZppnwTyPrt4S7jMfXiSX9yyfF0hxlA8B5oo2TtKl+/RGCy7fi4DrBfIf3lCPrkKsRBWZZD7RFojK7FDg== -"@opentelemetry/core@2.0.1", "@opentelemetry/core@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.0.1.tgz#44e1149d5666a4743cde943ef89841db3ce0f8bc" - integrity sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw== +"@opentelemetry/core@2.1.0", "@opentelemetry/core@^2.0.0", "@opentelemetry/core@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.1.0.tgz#5539f04eb9e5245e000b0c3f77bdfaa07557e3a7" + integrity sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ== dependencies: "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/instrumentation-amqplib@0.50.0": - version "0.50.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.50.0.tgz#91899a7e2821db956daeaa803d3bd8f5af8b8050" - integrity sha512-kwNs/itehHG/qaQBcVrLNcvXVPW0I4FCOVtw3LHMLdYIqD7GJ6Yv2nX+a4YHjzbzIeRYj8iyMp0Bl7tlkidq5w== +"@opentelemetry/instrumentation-amqplib@0.51.0": + version "0.51.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.51.0.tgz#1779326433f1ab8a743bbf8e1957e1b1252cf036" + integrity sha512-XGmjYwjVRktD4agFnWBWQXo9SiYHKBxR6Ag3MLXwtLE4R99N3a08kGKM5SC1qOFKIELcQDGFEFT9ydXMH00Luw== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-aws-sdk@0.57.0": - version "0.57.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.57.0.tgz#22d0a2ac113718c85c39d3561ee338dfad2234f6" - integrity sha512-RfbyjaeZzX3mPhuaRHlSAQyfX3skfeWOl30jrqSXtE9k0DPdnIqpHhdYS0C/DEDuZbwTmruVJ4cUwMBw5Z6FAg== +"@opentelemetry/instrumentation-aws-sdk@0.59.0": + version "0.59.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.59.0.tgz#bd612836a6158f1773369a5646984b95f805273d" + integrity sha512-GN/9YGBMb//s0vnchM2jMCkCaIKDB/Piau72fcuqcDXNBffMgu+AA9vCHZD2umriciXLtXJ2GXTh2/yaaHwLIw== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" - "@opentelemetry/propagation-utils" "^0.31.3" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.34.0" -"@opentelemetry/instrumentation-connect@0.47.0": - version "0.47.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.47.0.tgz#47271b8454fa88d97aa78e175c3d0cb7e10bd9e2" - integrity sha512-pjenvjR6+PMRb6/4X85L4OtkQCootgb/Jzh/l/Utu3SJHBid1F+gk9sTGU2FWuhhEfV6P7MZ7BmCdHXQjgJ42g== +"@opentelemetry/instrumentation-connect@0.48.0": + version "0.48.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.48.0.tgz#4481c84315b33b54a67c6e787be0eb72a84b23b3" + integrity sha512-OMjc3SFL4pC16PeK+tDhwP7MRvDPalYCGSvGqUhX5rASkI2H0RuxZHOWElYeXkV0WP+70Gw6JHWac/2Zqwmhdw== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" "@types/connect" "3.4.38" -"@opentelemetry/instrumentation-dataloader@0.21.1": - version "0.21.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.21.1.tgz#46fbbe59d9d6796980707768cf733225d43adea5" - integrity sha512-hNAm/bwGawLM8VDjKR0ZUDJ/D/qKR3s6lA5NV+btNaPVm2acqhPcT47l2uCVi+70lng2mywfQncor9v8/ykuyw== +"@opentelemetry/instrumentation-dataloader@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.22.0.tgz#a34f8ac6ec18e8f1585dcd89f9f611570868d1a2" + integrity sha512-bXnTcwtngQsI1CvodFkTemrrRSQjAjZxqHVc+CJZTDnidT0T6wt3jkKhnsjU/Kkkc0lacr6VdRpCu2CUWa0OKw== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" -"@opentelemetry/instrumentation-express@0.52.0": - version "0.52.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-express/-/instrumentation-express-0.52.0.tgz#d87d2130fe779dd757db28edb78262af83510d5b" - integrity sha512-W7pizN0Wh1/cbNhhTf7C62NpyYw7VfCFTYg0DYieSTrtPBT1vmoSZei19wfKLnrMsz3sHayCg0HxCVL2c+cz5w== +"@opentelemetry/instrumentation-express@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-express/-/instrumentation-express-0.53.0.tgz#902634e3de640bd4fa5370924397e716608ecb90" + integrity sha512-r/PBafQmFYRjuxLYEHJ3ze1iBnP2GDA1nXOSS6E02KnYNZAVjj6WcDA1MSthtdAUUK0XnotHvvWM8/qz7DMO5A== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-fs@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.23.0.tgz#e3cd3a53fa975c69de33e207b35561f3f90106f0" - integrity sha512-Puan+QopWHA/KNYvDfOZN6M/JtF6buXEyD934vrb8WhsX1/FuM7OtoMlQyIqAadnE8FqqDL4KDPiEfCQH6pQcQ== +"@opentelemetry/instrumentation-fs@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.24.0.tgz#edf0f7418f6a1cdcbe135857ab75629e7d94b910" + integrity sha512-HjIxJ6CBRD770KNVaTdMXIv29Sjz4C1kPCCK5x1Ujpc6SNnLGPqUVyJYZ3LUhhnHAqdbrl83ogVWjCgeT4Q0yw== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" -"@opentelemetry/instrumentation-generic-pool@0.47.0": - version "0.47.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.47.0.tgz#f5fa9d42236eb7d57fa544954f316faee937b0b4" - integrity sha512-UfHqf3zYK+CwDwEtTjaD12uUqGGTswZ7ofLBEdQ4sEJp9GHSSJMQ2hT3pgBxyKADzUdoxQAv/7NqvL42ZI+Qbw== +"@opentelemetry/instrumentation-generic-pool@0.48.0": + version "0.48.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.48.0.tgz#76fc08d76515db04f3833d730c5cb18cb0b237d4" + integrity sha512-TLv/On8pufynNR+pUbpkyvuESVASZZKMlqCm4bBImTpXKTpqXaJJ3o/MUDeMlM91rpen+PEv2SeyOKcHCSlgag== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" -"@opentelemetry/instrumentation-graphql@0.51.0": - version "0.51.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.51.0.tgz#1b29aa6330d196d523460e593167dca7dbcd42bb" - integrity sha512-LchkOu9X5DrXAnPI1+Z06h/EH/zC7D6sA86hhPrk3evLlsJTz0grPrkL/yUJM9Ty0CL/y2HSvmWQCjbJEz/ADg== +"@opentelemetry/instrumentation-graphql@0.52.0": + version "0.52.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.52.0.tgz#a2d23a669bdd0a1b031f785fe447d5a34ac56343" + integrity sha512-3fEJ8jOOMwopvldY16KuzHbRhPk8wSsOTSF0v2psmOCGewh6ad+ZbkTx/xyUK9rUdUMWAxRVU0tFpj4Wx1vkPA== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" -"@opentelemetry/instrumentation-hapi@0.50.0": - version "0.50.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.50.0.tgz#c755e9c21bfeb82046221bfd51303f816ae649e8" - integrity sha512-5xGusXOFQXKacrZmDbpHQzqYD1gIkrMWuwvlrEPkYOsjUqGUjl1HbxCsn5Y9bUXOCgP1Lj6A4PcKt1UiJ2MujA== +"@opentelemetry/instrumentation-hapi@0.51.0": + version "0.51.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.51.0.tgz#879926dfbb2e1609cc8658392167b1456c75d9e0" + integrity sha512-qyf27DaFNL1Qhbo/da+04MSCw982B02FhuOS5/UF+PMhM61CcOiu7fPuXj8TvbqyReQuJFljXE6UirlvoT/62g== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-http@0.203.0": - version "0.203.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.203.0.tgz#21f198547b5c72fc64e83ed25cdc991aef7b8fee" - integrity sha512-y3uQAcCOAwnO6vEuNVocmpVzG3PER6/YZqbPbbffDdJ9te5NkHEkfSMNzlC3+v7KlE+WinPGc3N7MR30G1HY2g== +"@opentelemetry/instrumentation-http@0.204.0": + version "0.204.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.204.0.tgz#faaf009b75e6a68729923b0a2a5270dc7d336f1d" + integrity sha512-1afJYyGRA4OmHTv0FfNTrTAzoEjPQUYgd+8ih/lX0LlZBnGio/O80vxA0lN3knsJPS7FiDrsDrWq25K7oAzbkw== dependencies: - "@opentelemetry/core" "2.0.1" - "@opentelemetry/instrumentation" "0.203.0" + "@opentelemetry/core" "2.1.0" + "@opentelemetry/instrumentation" "0.204.0" "@opentelemetry/semantic-conventions" "^1.29.0" forwarded-parse "2.1.2" @@ -5998,129 +5983,120 @@ "@opentelemetry/redis-common" "^0.38.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-kafkajs@0.13.0": - version "0.13.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.13.0.tgz#f959fecd0a9d53bed2fd662e41a5c155295ffbc8" - integrity sha512-FPQyJsREOaGH64hcxlzTsIEQC4DYANgTwHjiB7z9lldmvua1LRMVn3/FfBlzXoqF179B0VGYviz6rn75E9wsDw== +"@opentelemetry/instrumentation-kafkajs@0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.14.0.tgz#ffc30728b5845907d2c5b9f3883676c754ef4927" + integrity sha512-kbB5yXS47dTIdO/lfbbXlzhvHFturbux4EpP0+6H78Lk0Bn4QXiZQW7rmZY1xBCY16mNcCb8Yt0mhz85hTnSVA== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.30.0" -"@opentelemetry/instrumentation-knex@0.48.0": - version "0.48.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.48.0.tgz#ed24a81dfe6099cfe56136a3fed90565e1259f58" - integrity sha512-V5wuaBPv/lwGxuHjC6Na2JFRjtPgstw19jTFl1B1b6zvaX8zVDYUDaR5hL7glnQtUSCMktPttQsgK4dhXpddcA== +"@opentelemetry/instrumentation-knex@0.49.0": + version "0.49.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.49.0.tgz#8c04c80c00ead5fbdf600cd2460dcd21b4069157" + integrity sha512-NKsRRT27fbIYL4Ix+BjjP8h4YveyKc+2gD6DMZbr5R5rUeDqfC8+DTfIt3c3ex3BIc5Vvek4rqHnN7q34ZetLQ== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.33.1" -"@opentelemetry/instrumentation-koa@0.51.0": - version "0.51.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.51.0.tgz#1ff57866b7882033639477d3d2d9bada19a2129f" - integrity sha512-XNLWeMTMG1/EkQBbgPYzCeBD0cwOrfnn8ao4hWgLv0fNCFQu1kCsJYygz2cvKuCs340RlnG4i321hX7R8gj3Rg== +"@opentelemetry/instrumentation-koa@0.52.0": + version "0.52.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.52.0.tgz#7266785ea85334366c3e50dc2b45468df438eb3f" + integrity sha512-JJSBYLDx/mNSy8Ibi/uQixu2rH0bZODJa8/cz04hEhRaiZQoeJ5UrOhO/mS87IdgVsHrnBOsZ6vDu09znupyuA== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-lru-memoizer@0.48.0": - version "0.48.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.48.0.tgz#b9fbbd45b7a742a6795bf7166f65684251f184b1" - integrity sha512-KUW29wfMlTPX1wFz+NNrmE7IzN7NWZDrmFWHM/VJcmFEuQGnnBuTIdsP55CnBDxKgQ/qqYFp4udQFNtjeFosPw== +"@opentelemetry/instrumentation-lru-memoizer@0.49.0": + version "0.49.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.49.0.tgz#6353b877628339e3f07189f4fb15919a73fe1503" + integrity sha512-ctXu+O/1HSadAxtjoEg2w307Z5iPyLOMM8IRNwjaKrIpNAthYGSOanChbk1kqY6zU5CrpkPHGdAT6jk8dXiMqw== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" -"@opentelemetry/instrumentation-mongodb@0.56.0": - version "0.56.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.56.0.tgz#81281d2d151c3bfb26864c50b938a82ba2831b2d" - integrity sha512-YG5IXUUmxX3Md2buVMvxm9NWlKADrnavI36hbJsihqqvBGsWnIfguf0rUP5Srr0pfPqhQjUP+agLMsvu0GmUpA== +"@opentelemetry/instrumentation-mongodb@0.57.0": + version "0.57.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.57.0.tgz#e697261b2eac05280134e1851b72c89d5b4b3da8" + integrity sha512-KD6Rg0KSHWDkik+qjIOWoksi1xqSpix8TSPfquIK1DTmd9OTFb5PHmMkzJe16TAPVEuElUW8gvgP59cacFcrMQ== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-mongoose@0.50.0": - version "0.50.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.50.0.tgz#1fae5d2769ca7e67d15291fb91b61403839ad91d" - integrity sha512-Am8pk1Ct951r4qCiqkBcGmPIgGhoDiFcRtqPSLbJrUZqEPUsigjtMjoWDRLG1Ki1NHgOF7D0H7d+suWz1AAizw== +"@opentelemetry/instrumentation-mongoose@0.51.0": + version "0.51.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.51.0.tgz#688e9f3448e3d0979c4aaab5b566e14f30a1aa72" + integrity sha512-gwWaAlhhV2By7XcbyU3DOLMvzsgeaymwP/jktDC+/uPkCmgB61zurwqOQdeiRq9KAf22Y2dtE5ZLXxytJRbEVA== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-mysql2@0.50.0": - version "0.50.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.50.0.tgz#259344ba8771fd59c70a1a91360215b4b047a323" - integrity sha512-PoOMpmq73rOIE3nlTNLf3B1SyNYGsp7QXHYKmeTZZnJ2Ou7/fdURuOhWOI0e6QZ5gSem18IR1sJi6GOULBQJ9g== +"@opentelemetry/instrumentation-mysql2@0.51.0": + version "0.51.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.51.0.tgz#7eec3a0b9e4b27759df5df1c82eaedcf34b27528" + integrity sha512-zT2Wg22Xn43RyfU3NOUmnFtb5zlDI0fKcijCj9AcK9zuLZ4ModgtLXOyBJSSfO+hsOCZSC1v/Fxwj+nZJFdzLQ== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" "@opentelemetry/sql-common" "^0.41.0" -"@opentelemetry/instrumentation-mysql@0.49.0": - version "0.49.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.49.0.tgz#24fa7473134867236ed4068ee645e51922bcb654" - integrity sha512-QU9IUNqNsrlfE3dJkZnFHqLjlndiU39ll/YAAEvWE40sGOCi9AtOF6rmEGzJ1IswoZ3oyePV7q2MP8SrhJfVAA== +"@opentelemetry/instrumentation-mysql@0.50.0": + version "0.50.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.50.0.tgz#25de9de05191cecf8b01df379544eba50fa6f548" + integrity sha512-duKAvMRI3vq6u9JwzIipY9zHfikN20bX05sL7GjDeLKr2qV0LQ4ADtKST7KStdGcQ+MTN5wghWbbVdLgNcB3rA== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" "@types/mysql" "2.15.27" -"@opentelemetry/instrumentation-nestjs-core@0.49.0": - version "0.49.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.49.0.tgz#a79428e72c14250c44913a3a57f39c7297aab013" - integrity sha512-1R/JFwdmZIk3T/cPOCkVvFQeKYzbbUvDxVH3ShXamUwBlGkdEu5QJitlRMyVNZaHkKZKWgYrBarGQsqcboYgaw== +"@opentelemetry/instrumentation-nestjs-core@0.50.0": + version "0.50.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.50.0.tgz#f803bbeb6c972ac8f0685885cca7f6e5a4e09056" + integrity sha512-10u2Gjw260W8vdUem6pM7ENrb8i+UAyrgouhjN7HRdQYh9rcit51tRhgrI52fxTsRjrrBNIItHkX0YM8WnEU2w== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.30.0" -"@opentelemetry/instrumentation-pg@0.55.0": - version "0.55.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.55.0.tgz#f411d1e48c50b1c1f0f185d9fe94cfbb8812d8f6" - integrity sha512-yfJ5bYE7CnkW/uNsnrwouG/FR7nmg09zdk2MSs7k0ZOMkDDAE3WBGpVFFApGgNu2U+gtzLgEzOQG4I/X+60hXw== +"@opentelemetry/instrumentation-pg@0.57.0": + version "0.57.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.57.0.tgz#346cb613ccd1100221cef9692271468a3fe92eb0" + integrity sha512-dWLGE+r5lBgm2A8SaaSYDE3OKJ/kwwy5WLyGyzor8PLhUL9VnJRiY6qhp4njwhnljiLtzeffRtG2Mf/YyWLeTw== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" - "@opentelemetry/semantic-conventions" "^1.27.0" + "@opentelemetry/instrumentation" "^0.204.0" + "@opentelemetry/semantic-conventions" "^1.34.0" "@opentelemetry/sql-common" "^0.41.0" - "@types/pg" "8.15.4" + "@types/pg" "8.15.5" "@types/pg-pool" "2.0.6" -"@opentelemetry/instrumentation-redis@0.51.0": - version "0.51.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.51.0.tgz#70504ba6c3856fcb25e436b4915e85efaa7d38a6" - integrity sha512-uL/GtBA0u72YPPehwOvthAe+Wf8k3T+XQPBssJmTYl6fzuZjNq8zTfxVFhl9nRFjFVEe+CtiYNT0Q3AyqW1Z0A== +"@opentelemetry/instrumentation-redis@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.53.0.tgz#826cfeacebaf7ce571bb932ad410f23caf170b9c" + integrity sha512-WUHV8fr+8yo5RmzyU7D5BIE1zwiaNQcTyZPwtxlfr7px6NYYx7IIpSihJK7WA60npWynfxxK1T67RAVF0Gdfjg== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/redis-common" "^0.38.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation-tedious@0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.22.0.tgz#f71374c52cb9c57a6b879bea3256a1465c02efbb" - integrity sha512-XrrNSUCyEjH1ax9t+Uo6lv0S2FCCykcF7hSxBMxKf7Xn0bPRxD3KyFUZy25aQXzbbbUHhtdxj3r2h88SfEM3aA== +"@opentelemetry/instrumentation-tedious@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.23.0.tgz#a781de2cb33ff71ef65bbefba11c9fe2d79c4b32" + integrity sha512-3TMTk/9VtlRonVTaU4tCzbg4YqW+Iq/l5VnN2e5whP6JgEg/PKfrGbqQ+CxQWNLfLaQYIUgEZqAn5gk/inh1uQ== dependencies: - "@opentelemetry/instrumentation" "^0.203.0" + "@opentelemetry/instrumentation" "^0.204.0" "@opentelemetry/semantic-conventions" "^1.27.0" "@types/tedious" "^4.0.14" -"@opentelemetry/instrumentation-undici@0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.14.0.tgz#7a9cd276f7664773b5daf5ae53365b3593e6e7a9" - integrity sha512-2HN+7ztxAReXuxzrtA3WboAKlfP5OsPA57KQn2AdYZbJ3zeRPcLXyW4uO/jpLE6PLm0QRtmeGCmfYpqRlwgSwg== +"@opentelemetry/instrumentation-undici@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.15.0.tgz#c8193a162d4abe61c2fd247912e0cb8c0c3bc10c" + integrity sha512-sNFGA/iCDlVkNjzTzPRcudmI11vT/WAfAguRdZY9IspCw02N4WSC72zTuQhSMheh2a1gdeM9my1imnKRvEEvEg== dependencies: "@opentelemetry/core" "^2.0.0" - "@opentelemetry/instrumentation" "^0.203.0" - -"@opentelemetry/instrumentation@0.203.0", "@opentelemetry/instrumentation@^0.203.0": - version "0.203.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.203.0.tgz#5c74a41cd6868f7ba47b346ff5a58ea7b18cf381" - integrity sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ== - dependencies: - "@opentelemetry/api-logs" "0.203.0" - import-in-the-middle "^1.8.1" - require-in-the-middle "^7.1.1" + "@opentelemetry/instrumentation" "^0.204.0" -"@opentelemetry/instrumentation@^0.204.0": +"@opentelemetry/instrumentation@0.204.0", "@opentelemetry/instrumentation@^0.204.0": version "0.204.0" resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.204.0.tgz#587c104c02c9ccb38932ce508d9c81514ec7a7c4" integrity sha512-vV5+WSxktzoMP8JoYWKeopChy6G3HKk4UQ2hESCRDUUTZqQ3+nM3u8noVG0LmNfRWwcFBnbZ71GKC7vaYYdJ1g== @@ -6141,45 +6117,32 @@ semver "^7.5.2" shimmer "^1.2.1" -"@opentelemetry/propagation-utils@^0.31.3": - version "0.31.3" - resolved "https://registry.yarnpkg.com/@opentelemetry/propagation-utils/-/propagation-utils-0.31.3.tgz#42aab61a1a3cec64ce221cbcec5f3f6fc84e9701" - integrity sha512-ZI6LKjyo+QYYZY5SO8vfoCQ9A69r1/g+pyjvtu5RSK38npINN1evEmwqbqhbg2CdcIK3a4PN6pDAJz/yC5/gAA== - "@opentelemetry/redis-common@^0.38.0": version "0.38.0" resolved "https://registry.yarnpkg.com/@opentelemetry/redis-common/-/redis-common-0.38.0.tgz#87d2a792dcbcf466a41bb7dfb8a7cd094d643d0b" integrity sha512-4Wc0AWURII2cfXVVoZ6vDqK+s5n4K5IssdrlVrvGsx6OEOKdghKtJZqXAHWFiZv4nTDLH2/2fldjIHY8clMOjQ== -"@opentelemetry/resources@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.0.0.tgz#15c04794c32b7d0b3c7589225ece6ae9bba25989" - integrity sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg== - dependencies: - "@opentelemetry/core" "2.0.0" - "@opentelemetry/semantic-conventions" "^1.29.0" - -"@opentelemetry/resources@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.0.1.tgz#0365d134291c0ed18d96444a1e21d0e6a481c840" - integrity sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw== +"@opentelemetry/resources@2.1.0", "@opentelemetry/resources@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.1.0.tgz#11772e732af4f27953cf55567a6630d8b4d8282d" + integrity sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw== dependencies: - "@opentelemetry/core" "2.0.1" + "@opentelemetry/core" "2.1.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/sdk-trace-base@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz#ebc06ea7537dea62f3882f8236c1234f4faf6b23" - integrity sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw== +"@opentelemetry/sdk-trace-base@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz#9d31474824e9ed215f94bf71260d5321f64d402a" + integrity sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ== dependencies: - "@opentelemetry/core" "2.0.0" - "@opentelemetry/resources" "2.0.0" + "@opentelemetry/core" "2.1.0" + "@opentelemetry/resources" "2.1.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/semantic-conventions@^1.27.0", "@opentelemetry/semantic-conventions@^1.29.0", "@opentelemetry/semantic-conventions@^1.30.0", "@opentelemetry/semantic-conventions@^1.33.1", "@opentelemetry/semantic-conventions@^1.34.0", "@opentelemetry/semantic-conventions@^1.36.0": - version "1.36.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.36.0.tgz#149449bd4df4d0464220915ad4164121e0d75d4d" - integrity sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ== +"@opentelemetry/semantic-conventions@^1.27.0", "@opentelemetry/semantic-conventions@^1.29.0", "@opentelemetry/semantic-conventions@^1.30.0", "@opentelemetry/semantic-conventions@^1.33.1", "@opentelemetry/semantic-conventions@^1.34.0", "@opentelemetry/semantic-conventions@^1.37.0": + version "1.37.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.37.0.tgz#aa2b4fa0b910b66a050c5ddfcac1d262e91a321a" + integrity sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA== "@opentelemetry/sql-common@^0.41.0": version "0.41.0" @@ -6341,10 +6304,61 @@ resolved "https://registry.yarnpkg.com/@poppinss/exception/-/exception-1.2.2.tgz#8d30d42e126c54fe84e997433e4dcac610090743" integrity sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg== -"@prisma/instrumentation@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-6.14.0.tgz#8f6e43b73ee2b88b98cec901457f4da7da13aea3" - integrity sha512-Po/Hry5bAeunRDq0yAQueKookW3glpP+qjjvvyOfm6dI2KG5/Y6Bgg3ahyWd7B0u2E+Wf9xRk2rtdda7ySgK1A== +"@prisma/client@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-6.15.0.tgz#c4166aa8492878c842e63c515853d7a4125e6168" + integrity sha512-wR2LXUbOH4cL/WToatI/Y2c7uzni76oNFND7+23ypLllBmIS8e3ZHhO+nud9iXSXKFt1SoM3fTZvHawg63emZw== + +"@prisma/config@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@prisma/config/-/config-6.15.0.tgz#b9a4fd87620baae3ce71015ee4ad632995838d89" + integrity sha512-KMEoec9b2u6zX0EbSEx/dRpx1oNLjqJEBZYyK0S3TTIbZ7GEGoVyGyFRk4C72+A38cuPLbfQGQvgOD+gBErKlA== + dependencies: + c12 "3.1.0" + deepmerge-ts "7.1.5" + effect "3.16.12" + empathic "2.0.0" + +"@prisma/debug@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-6.15.0.tgz#8595f8ae91eadd20d926398449b8602c74e36bbf" + integrity sha512-y7cSeLuQmyt+A3hstAs6tsuAiVXSnw9T55ra77z0nbNkA8Lcq9rNcQg6PI00by/+WnE/aMRJ/W7sZWn2cgIy1g== + +"@prisma/engines-version@6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb": + version "6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb.tgz#718b17890287447360107bef3675487d8cb0ae15" + integrity sha512-a/46aK5j6L3ePwilZYEgYDPrhBQ/n4gYjLxT5YncUTJJNRnTCVjPF86QdzUOLRdYjCLfhtZp9aum90W0J+trrg== + +"@prisma/engines@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-6.15.0.tgz#77a220e40f4ed3345ef27407f8f0323e80debea8" + integrity sha512-opITiR5ddFJ1N2iqa7mkRlohCZqVSsHhRcc29QXeldMljOf4FSellLT0J5goVb64EzRTKcIDeIsJBgmilNcKxA== + dependencies: + "@prisma/debug" "6.15.0" + "@prisma/engines-version" "6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb" + "@prisma/fetch-engine" "6.15.0" + "@prisma/get-platform" "6.15.0" + +"@prisma/fetch-engine@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-6.15.0.tgz#ec7e57030789ed42a87bf5b66be4db6e612412e9" + integrity sha512-xcT5f6b+OWBq6vTUnRCc7qL+Im570CtwvgSj+0MTSGA1o9UDSKZ/WANvwtiRXdbYWECpyC3CukoG3A04VTAPHw== + dependencies: + "@prisma/debug" "6.15.0" + "@prisma/engines-version" "6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb" + "@prisma/get-platform" "6.15.0" + +"@prisma/get-platform@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-6.15.0.tgz#86a114534a534090b931801b83356b0bbe676f29" + integrity sha512-Jbb+Xbxyp05NSR1x2epabetHiXvpO8tdN2YNoWoA/ZsbYyxxu/CO/ROBauIFuMXs3Ti+W7N7SJtWsHGaWte9Rg== + dependencies: + "@prisma/debug" "6.15.0" + +"@prisma/instrumentation@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-6.15.0.tgz#40b066dc6b1ea621aa5ae0fd6d54319550b7d8c9" + integrity sha512-6TXaH6OmDkMOQvOxwLZ8XS51hU2v4A3vmE2pSijCIiGRJYyNeMcL6nMHQMyYdZRD8wl7LF3Wzc+AMPMV/9Oo7A== dependencies: "@opentelemetry/instrumentation" "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" @@ -7688,6 +7702,11 @@ resolved "https://registry.yarnpkg.com/@speed-highlight/core/-/core-1.2.7.tgz#eeaa7c1e7198559abbb98e4acbc93d108d35f2d3" integrity sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g== +"@standard-schema/spec@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.0.0.tgz#f193b73dc316c4170f2e82a881da0f550d551b9c" + integrity sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA== + "@supabase/auth-js@2.69.1": version "2.69.1" resolved "https://registry.yarnpkg.com/@supabase/auth-js/-/auth-js-2.69.1.tgz#fcf310d24dfab823ffbf22191e6ceaef933360d8" @@ -8649,10 +8668,10 @@ dependencies: "@types/pg" "*" -"@types/pg@*", "@types/pg@8.15.4", "@types/pg@^8.6.5": - version "8.15.4" - resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.15.4.tgz#419f791c6fac8e0bed66dd8f514b60f8ba8db46d" - integrity sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg== +"@types/pg@*", "@types/pg@8.15.5", "@types/pg@^8.6.5": + version "8.15.5" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.15.5.tgz#ef43e0f33b62dac95cae2f042888ec7980b30c09" + integrity sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ== dependencies: "@types/node" "*" pg-protocol "*" @@ -12168,6 +12187,24 @@ bytes@3.1.2, bytes@^3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +c12@3.1.0, c12@^3.0.4: + version "3.1.0" + resolved "https://registry.yarnpkg.com/c12/-/c12-3.1.0.tgz#9e237970e1d3b74ebae51d25945cb59664c12c89" + integrity sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw== + dependencies: + chokidar "^4.0.3" + confbox "^0.2.2" + defu "^6.1.4" + dotenv "^16.6.1" + exsolve "^1.0.7" + giget "^2.0.0" + jiti "^2.4.2" + ohash "^2.0.11" + pathe "^2.0.3" + perfect-debounce "^1.0.0" + pkg-types "^2.2.0" + rc9 "^2.1.2" + c12@^1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/c12/-/c12-1.11.2.tgz#f8a1e30c10f4b273894a1bcb6944f76c15b56717" @@ -12186,24 +12223,6 @@ c12@^1.11.2: pkg-types "^1.2.0" rc9 "^2.1.2" -c12@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/c12/-/c12-3.0.4.tgz#2d65d9ba8f6958bd88f65013f54e15140332099b" - integrity sha512-t5FaZTYbbCtvxuZq9xxIruYydrAGsJ+8UdP0pZzMiK2xl/gNiSOy0OxhLzHUEEb0m1QXYqfzfvyIFEmz/g9lqg== - dependencies: - chokidar "^4.0.3" - confbox "^0.2.2" - defu "^6.1.4" - dotenv "^16.5.0" - exsolve "^1.0.5" - giget "^2.0.0" - jiti "^2.4.2" - ohash "^2.0.11" - pathe "^2.0.3" - perfect-debounce "^1.0.0" - pkg-types "^2.1.0" - rc9 "^2.1.2" - cac@^6.7.14: version "6.7.14" resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" @@ -13937,6 +13956,11 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge-ts@7.1.5: + version "7.1.5" + resolved "https://registry.yarnpkg.com/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz#ff818564007f5c150808d2b7b732cac83aa415ab" + integrity sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw== + deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" @@ -14507,10 +14531,10 @@ dotenv@16.0.3: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== -dotenv@^16.3.1, dotenv@^16.4.5, dotenv@^16.5.0: - version "16.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.0.tgz#b96bd4e7c2043ba5f51cbe1b8f9347850c864850" - integrity sha512-Omf1L8paOy2VJhILjyhrhqwLIdstqm1BvcDPKg4NGAlkwEu9ODyrFbvk8UymUOMCT+HXo31jg1lArIrVAAhuGA== +dotenv@^16.3.1, dotenv@^16.4.5, dotenv@^16.6.1: + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== dotenv@~10.0.0: version "10.0.0" @@ -14590,6 +14614,14 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +effect@3.16.12: + version "3.16.12" + resolved "https://registry.yarnpkg.com/effect/-/effect-3.16.12.tgz#3762f745846cfa4905512e397e17f683438addbe" + integrity sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg== + dependencies: + "@standard-schema/spec" "^1.0.0" + fast-check "^3.23.1" + ejs@^3.1.7: version "3.1.8" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b" @@ -15164,6 +15196,11 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== +empathic@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/empathic/-/empathic-2.0.0.tgz#71d3c2b94fad49532ef98a6c34be0386659f6131" + integrity sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA== + enabled@2.0.x: version "2.0.0" resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" @@ -16568,7 +16605,7 @@ express@5.1.0: type-is "^2.0.1" vary "^1.1.2" -exsolve@^1.0.4, exsolve@^1.0.5, exsolve@^1.0.7: +exsolve@^1.0.4, exsolve@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.7.tgz#3b74e4c7ca5c5f9a19c3626ca857309fa99f9e9e" integrity sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw== @@ -16649,6 +16686,13 @@ fake-indexeddb@^4.0.1: dependencies: realistic-structured-clone "^3.0.0" +fast-check@^3.23.1: + version "3.23.2" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.23.2.tgz#0129f1eb7e4f500f58e8290edc83c670e4a574a2" + integrity sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A== + dependencies: + pure-rand "^6.1.0" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -24783,10 +24827,10 @@ pkg-types@^1.0.3, pkg-types@^1.1.3, pkg-types@^1.2.0, pkg-types@^1.3.0: mlly "^1.7.4" pathe "^2.0.1" -pkg-types@^2.0.0, pkg-types@^2.0.1, pkg-types@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.1.1.tgz#b8b209b2e269af62f55ba51f0648b540039dc6ca" - integrity sha512-eY0QFb6eSwc9+0d/5D2lFFUq+A3n3QNGSy/X2Nvp+6MfzGw2u6EbA7S80actgjY1lkvvI0pqB+a4hioMh443Ew== +pkg-types@^2.0.0, pkg-types@^2.0.1, pkg-types@^2.1.0, pkg-types@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.3.0.tgz#037f2c19bd5402966ff6810e32706558cb5b5726" + integrity sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig== dependencies: confbox "^0.2.2" exsolve "^1.0.7" @@ -25630,6 +25674,14 @@ printf@^0.6.1: resolved "https://registry.yarnpkg.com/printf/-/printf-0.6.1.tgz#b9afa3d3b55b7f2e8b1715272479fc756ed88650" integrity sha512-is0ctgGdPJ5951KulgfzvHGwJtZ5ck8l042vRkV6jrkpBzTmb/lueTqguWHy2JfVA+RY6gFVlaZgUS0j7S/dsw== +prisma@6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-6.15.0.tgz#198f95a4468aba8f3c95b58bf3400f65daeb8942" + integrity sha512-E6RCgOt+kUVtjtZgLQDBJ6md2tDItLJNExwI0XJeBc1FKL+Vwb+ovxXxuok9r8oBgsOXBA33fGDuE/0qDdCWqQ== + dependencies: + "@prisma/config" "6.15.0" + "@prisma/engines" "6.15.0" + prismjs@^1.29.0: version "1.29.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" @@ -25828,6 +25880,11 @@ pupa@^2.1.1: dependencies: escape-goat "^2.0.0" +pure-rand@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + qs@6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" @@ -28751,7 +28808,6 @@ stylus@0.59.0, stylus@^0.59.0: sucrase@^3.27.0, sucrase@^3.35.0, sucrase@getsentry/sucrase#es2020-polyfills: version "3.36.0" - uid fd682f6129e507c00bb4e6319cc5d6b767e36061 resolved "https://codeload.github.com/getsentry/sucrase/tar.gz/fd682f6129e507c00bb4e6319cc5d6b767e36061" dependencies: "@jridgewell/gen-mapping" "^0.3.2"