From 8f9f42caa3ed6bcb55fbd6cd990f55c4ce8f2b21 Mon Sep 17 00:00:00 2001 From: Sam Greening <2552620+SG60@users.noreply.github.com> Date: Fri, 21 Feb 2025 10:39:37 +0000 Subject: [PATCH 1/2] feat(sveltekit): Add Support for Cloudflare (#14672) This patch adds a different set of package exports for workers. To use this, you have to use the new `initCloudflareSentryHandle` SvelteKit handler function, before your call to `sentryHandle()`. --------- Co-authored-by: Lukas Stracke --- .../sveltekit-cloudflare-pages/.gitignore | 24 ++ .../sveltekit-cloudflare-pages/.npmrc | 2 + .../sveltekit-cloudflare-pages/README.md | 38 ++++ .../sveltekit-cloudflare-pages/package.json | 31 +++ .../playwright.config.ts | 10 + .../sveltekit-cloudflare-pages/src/app.d.ts | 13 ++ .../sveltekit-cloudflare-pages/src/app.html | 12 + .../src/hooks.client.ts | 8 + .../src/hooks.server.ts | 13 ++ .../src/routes/+page.server.ts | 7 + .../src/routes/+page.svelte | 10 + .../static/favicon.png | Bin 0 -> 1571 bytes .../svelte.config.js | 21 ++ .../tests/demo.test.ts | 6 + .../sveltekit-cloudflare-pages/tsconfig.json | 19 ++ .../sveltekit-cloudflare-pages/vite.config.ts | 7 + .../sveltekit-cloudflare-pages/wrangler.toml | 2 + packages/sveltekit/package.json | 5 + packages/sveltekit/rollup.npm.config.mjs | 9 +- packages/sveltekit/src/common/utils.ts | 2 + packages/sveltekit/src/index.types.ts | 6 + packages/sveltekit/src/index.worker.ts | 2 + .../sveltekit/src/server-common/handle.ts | 208 +++++++++++++++++ .../{server => server-common}/handleError.ts | 5 +- .../src/{server => server-common}/load.ts | 8 +- .../rewriteFramesIntegration.ts | 2 +- .../{server => server-common}/serverRoute.ts | 8 +- .../src/{server => server-common}/utils.ts | 3 +- packages/sveltekit/src/server/handle.ts | 212 ++---------------- packages/sveltekit/src/server/index.ts | 9 +- packages/sveltekit/src/server/sdk.ts | 4 +- packages/sveltekit/src/vite/autoInstrument.ts | 3 +- packages/sveltekit/src/vite/sourceMaps.ts | 2 +- packages/sveltekit/src/worker/cloudflare.ts | 43 ++++ packages/sveltekit/src/worker/index.ts | 90 ++++++++ packages/sveltekit/test/server/handle.test.ts | 27 ++- .../sveltekit/test/server/handleError.test.ts | 6 +- packages/sveltekit/test/server/load.test.ts | 6 +- .../server/rewriteFramesIntegration.test.ts | 2 +- .../sveltekit/test/server/serverRoute.test.ts | 6 +- packages/sveltekit/test/server/utils.test.ts | 2 +- 41 files changed, 660 insertions(+), 233 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.gitignore create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.npmrc create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/README.md create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/playwright.config.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.d.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.html create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.client.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/static/favicon.png create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/svelte.config.js create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/tests/demo.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/tsconfig.json create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/vite.config.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/wrangler.toml create mode 100644 packages/sveltekit/src/index.worker.ts create mode 100644 packages/sveltekit/src/server-common/handle.ts rename packages/sveltekit/src/{server => server-common}/handleError.ts (95%) rename packages/sveltekit/src/{server => server-common}/load.ts (96%) rename packages/sveltekit/src/{server => server-common}/rewriteFramesIntegration.ts (97%) rename packages/sveltekit/src/{server => server-common}/serverRoute.ts (92%) rename packages/sveltekit/src/{server => server-common}/utils.ts (95%) create mode 100644 packages/sveltekit/src/worker/cloudflare.ts create mode 100644 packages/sveltekit/src/worker/index.ts diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.gitignore b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.gitignore new file mode 100644 index 000000000000..bff793d5eae7 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.gitignore @@ -0,0 +1,24 @@ +test-results +node_modules + +# Output +.output +.vercel +.netlify +.wrangler +/.svelte-kit +/build + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.* +!.env.example +!.env.test + +# Vite +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.npmrc b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.npmrc new file mode 100644 index 000000000000..070f80f05092 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/.npmrc @@ -0,0 +1,2 @@ +@sentry:registry=http://127.0.0.1:4873 +@sentry-internal:registry=http://127.0.0.1:4873 diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/README.md b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/README.md new file mode 100644 index 000000000000..b5b295070b44 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/README.md @@ -0,0 +1,38 @@ +# sv + +Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npx sv create + +# create a new project in my-app +npx sv create my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment. diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json new file mode 100644 index 000000000000..51fe00136f06 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json @@ -0,0 +1,31 @@ +{ + "name": "sveltekit-cloudflare-pages", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "wrangler pages dev ./.svelte-kit/cloudflare --port 4173", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "test:e2e": "playwright test", + "test": "pnpm run test:e2e", + "test:build": "pnpm install && pnpm build", + "test:assert": "pnpm run test:e2e" + }, + "dependencies": { + "@sentry/sveltekit": "latest || *" + }, + "devDependencies": { + "@playwright/test": "^1.45.3", + "@sveltejs/adapter-cloudflare": "^5.0.3", + "@sveltejs/kit": "^2.17.2", + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "svelte": "^5.20.2", + "svelte-check": "^4.1.4", + "typescript": "^5.0.0", + "vite": "^6.1.1", + "wrangler": "3.105.0" + } +} diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/playwright.config.ts b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/playwright.config.ts new file mode 100644 index 000000000000..18bda456025e --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/playwright.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + webServer: { + command: 'pnpm run build && pnpm run preview', + port: 4173, + }, + + testDir: 'tests', +}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.d.ts b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.d.ts new file mode 100644 index 000000000000..520c4217a10c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.html b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.html new file mode 100644 index 000000000000..77a5ff52c923 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.client.ts b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.client.ts new file mode 100644 index 000000000000..4dc12acebc45 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.client.ts @@ -0,0 +1,8 @@ +import { env } from '$env/dynamic/public'; +import * as Sentry from '@sentry/sveltekit'; + +Sentry.init({ + dsn: env.PUBLIC_E2E_TEST_DSN, +}); + +export const handleError = Sentry.handleErrorWithSentry(); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.server.ts new file mode 100644 index 000000000000..d5067459d565 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/hooks.server.ts @@ -0,0 +1,13 @@ +import { E2E_TEST_DSN } from '$env/static/private'; +import { handleErrorWithSentry, initCloudflareSentryHandle, sentryHandle } from '@sentry/sveltekit'; +import { sequence } from '@sveltejs/kit/hooks'; + +export const handleError = handleErrorWithSentry(); + +export const handle = sequence( + initCloudflareSentryHandle({ + dsn: E2E_TEST_DSN, + tracesSampleRate: 1.0, + }), + sentryHandle(), +); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.server.ts new file mode 100644 index 000000000000..3cbde33753a2 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.server.ts @@ -0,0 +1,7 @@ +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async function load() { + return { + message: 'From server load function.', + }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.svelte new file mode 100644 index 000000000000..e17881ceaca9 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/src/routes/+page.svelte @@ -0,0 +1,10 @@ + + +

Welcome to SvelteKit

+

Visit svelte.dev/docs/kit to read the documentation

+ +prerender test + +

{data.message}

diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/static/favicon.png b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH { + await page.goto('/'); + await expect(page.locator('h1')).toBeVisible(); +}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/tsconfig.json b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/tsconfig.json new file mode 100644 index 000000000000..0b2d8865f4ef --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/vite.config.ts b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/vite.config.ts new file mode 100644 index 000000000000..706faf25f2b5 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/vite.config.ts @@ -0,0 +1,7 @@ +import { sentrySvelteKit } from '@sentry/sveltekit'; +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [sentrySvelteKit({ autoUploadSourceMaps: false }), sveltekit()], +}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/wrangler.toml b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/wrangler.toml new file mode 100644 index 000000000000..d31d2fc7f225 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/wrangler.toml @@ -0,0 +1,2 @@ +compatibility_date = "2024-12-17" +compatibility_flags = ["nodejs_compat"] diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index 664f057ee808..dbcc01675dc3 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -18,6 +18,10 @@ "./package.json": "./package.json", ".": { "types": "./build/types/index.types.d.ts", + "worker": { + "import": "./build/esm/index.worker.js", + "require": "./build/cjs/index.worker.js" + }, "browser": { "import": "./build/esm/index.client.js", "require": "./build/cjs/index.client.js" @@ -38,6 +42,7 @@ } }, "dependencies": { + "@sentry/cloudflare": "9.1.0", "@sentry/core": "9.1.0", "@sentry/node": "9.1.0", "@sentry/opentelemetry": "9.1.0", diff --git a/packages/sveltekit/rollup.npm.config.mjs b/packages/sveltekit/rollup.npm.config.mjs index b0a19e091ad8..ca0792cb4868 100644 --- a/packages/sveltekit/rollup.npm.config.mjs +++ b/packages/sveltekit/rollup.npm.config.mjs @@ -2,7 +2,14 @@ import { makeBaseNPMConfig, makeNPMConfigVariants } from '@sentry-internal/rollu export default makeNPMConfigVariants( makeBaseNPMConfig({ - entrypoints: ['src/index.server.ts', 'src/index.client.ts', 'src/client/index.ts', 'src/server/index.ts'], + entrypoints: [ + 'src/index.server.ts', + 'src/index.client.ts', + 'src/index.worker.ts', + 'src/client/index.ts', + 'src/server/index.ts', + 'src/worker/index.ts', + ], packageSpecificConfig: { external: ['$app/stores'], output: { diff --git a/packages/sveltekit/src/common/utils.ts b/packages/sveltekit/src/common/utils.ts index 84b384861dff..1362ee82293c 100644 --- a/packages/sveltekit/src/common/utils.ts +++ b/packages/sveltekit/src/common/utils.ts @@ -1,5 +1,7 @@ import type { HttpError, Redirect } from '@sveltejs/kit'; +export const WRAPPED_MODULE_SUFFIX = '?sentry-auto-wrap'; + export type SentryWrappedFlag = { /** * If this flag is set, we know that the load event was already wrapped once diff --git a/packages/sveltekit/src/index.types.ts b/packages/sveltekit/src/index.types.ts index 3ad8b728bb5f..bf2edbfb0a0f 100644 --- a/packages/sveltekit/src/index.types.ts +++ b/packages/sveltekit/src/index.types.ts @@ -4,6 +4,12 @@ export * from './client'; export * from './vite'; export * from './server'; +export * from './worker'; + +// Use the ./server version of some functions that are also exported from ./worker +export { sentryHandle } from './server'; +// Use the ./worker version of some functions that are also exported from ./server +export { initCloudflareSentryHandle } from './worker'; import type { Client, Integration, Options, StackParser } from '@sentry/core'; import type { HandleClientError, HandleServerError } from '@sveltejs/kit'; diff --git a/packages/sveltekit/src/index.worker.ts b/packages/sveltekit/src/index.worker.ts new file mode 100644 index 000000000000..016e36c8a289 --- /dev/null +++ b/packages/sveltekit/src/index.worker.ts @@ -0,0 +1,2 @@ +export * from './worker'; +// export * from './vite'; diff --git a/packages/sveltekit/src/server-common/handle.ts b/packages/sveltekit/src/server-common/handle.ts new file mode 100644 index 000000000000..48167066c6d7 --- /dev/null +++ b/packages/sveltekit/src/server-common/handle.ts @@ -0,0 +1,208 @@ +import type { Span } from '@sentry/core'; +import { + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + continueTrace, + getCurrentScope, + getDefaultIsolationScope, + getIsolationScope, + getTraceMetaTags, + logger, + setHttpStatus, + startSpan, + winterCGRequestToRequestData, + withIsolationScope, +} from '@sentry/core'; +import type { Handle, ResolveOptions } from '@sveltejs/kit'; + +import { DEBUG_BUILD } from '../common/debug-build'; +import { flushIfServerless, getTracePropagationData, sendErrorToSentry } from './utils'; + +export type SentryHandleOptions = { + /** + * Controls whether the SDK should capture errors and traces in requests that don't belong to a + * route defined in your SvelteKit application. + * + * By default, this option is set to `false` to reduce noise (e.g. bots sending random requests to your server). + * + * Set this option to `true` if you want to monitor requests events without a route. This might be useful in certain + * scenarios, for instance if you registered other handlers that handle these requests. + * If you set this option, you might want adjust the the transaction name in the `beforeSendTransaction` + * callback of your server-side `Sentry.init` options. You can also use `beforeSendTransaction` to filter out + * transactions that you still don't want to be sent to Sentry. + * + * @default false + */ + handleUnknownRoutes?: boolean; + + /** + * Controls if `sentryHandle` should inject a script tag into the page that enables instrumentation + * of `fetch` calls in `load` functions. + * + * @default true + */ + injectFetchProxyScript?: boolean; +}; + +export const FETCH_PROXY_SCRIPT = ` + const f = window.fetch; + if(f){ + window._sentryFetchProxy = function(...a){return f(...a)} + window.fetch = function(...a){return window._sentryFetchProxy(...a)} + } +`; +/** + * Adds Sentry tracing tags to the returned html page. + * Adds Sentry fetch proxy script to the returned html page if enabled in options. + * + * Exported only for testing + */ +export function addSentryCodeToPage(options: { injectFetchProxyScript: boolean }): NonNullable< + ResolveOptions['transformPageChunk'] +> { + return ({ html }) => { + const metaTags = getTraceMetaTags(); + const headWithMetaTags = metaTags ? `\n${metaTags}` : ''; + + const headWithFetchScript = options.injectFetchProxyScript ? `\n` : ''; + + const modifiedHead = `${headWithMetaTags}${headWithFetchScript}`; + + return html.replace('', modifiedHead); + }; +} + +/** + * We only need to inject the fetch proxy script for SvelteKit versions < 2.16.0. + * Exported only for testing. + */ +export function isFetchProxyRequired(version: string): boolean { + try { + const [major, minor] = version.trim().replace(/-.*/, '').split('.').map(Number); + if (major != null && minor != null && (major > 2 || (major === 2 && minor >= 16))) { + return false; + } + } catch { + // ignore + } + return true; +} + +async function instrumentHandle( + { event, resolve }: Parameters[0], + options: SentryHandleOptions, +): Promise { + if (!event.route?.id && !options.handleUnknownRoutes) { + return resolve(event); + } + + // caching the result of the version check in `options.injectFetchProxyScript` + // to avoid doing the dynamic import on every request + if (options.injectFetchProxyScript == null) { + try { + // @ts-expect-error - the dynamic import is fine here + const { VERSION } = await import('@sveltejs/kit'); + options.injectFetchProxyScript = isFetchProxyRequired(VERSION); + } catch { + options.injectFetchProxyScript = true; + } + } + + const routeName = `${event.request.method} ${event.route?.id || event.url.pathname}`; + + if (getIsolationScope() !== getDefaultIsolationScope()) { + getIsolationScope().setTransactionName(routeName); + } else { + DEBUG_BUILD && logger.warn('Isolation scope is default isolation scope - skipping setting transactionName'); + } + + try { + const resolveResult = await startSpan( + { + op: 'http.server', + attributes: { + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit', + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url', + 'http.method': event.request.method, + }, + name: routeName, + }, + async (span?: Span) => { + getCurrentScope().setSDKProcessingMetadata({ + // We specifically avoid cloning the request here to avoid double read errors. + // We only read request headers so we're not consuming the body anyway. + // Note to future readers: This sounds counter-intuitive but please read + // https://github.com/getsentry/sentry-javascript/issues/14583 + normalizedRequest: winterCGRequestToRequestData(event.request), + }); + const res = await resolve(event, { + transformPageChunk: addSentryCodeToPage({ injectFetchProxyScript: options.injectFetchProxyScript ?? true }), + }); + if (span) { + setHttpStatus(span, res.status); + } + return res; + }, + ); + return resolveResult; + } catch (e: unknown) { + sendErrorToSentry(e, 'handle'); + throw e; + } finally { + await flushIfServerless(); + } +} + +/** + * A SvelteKit handle function that wraps the request for Sentry error and + * performance monitoring. + * + * Usage: + * ``` + * // src/hooks.server.ts + * import { sentryHandle } from '@sentry/sveltekit'; + * + * export const handle = sentryHandle(); + * + * // Optionally use the `sequence` function to add additional handlers. + * // export const handle = sequence(sentryHandle(), yourCustomHandler); + * ``` + */ +export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle { + const { handleUnknownRoutes, ...rest } = handlerOptions ?? {}; + const options = { + handleUnknownRoutes: handleUnknownRoutes ?? false, + ...rest, + }; + + const sentryRequestHandler: Handle = input => { + // Escape hatch to suppress request isolation and trace continuation (see initCloudflareSentryHandle) + const skipIsolation = + '_sentrySkipRequestIsolation' in input.event.locals && input.event.locals._sentrySkipRequestIsolation; + + // In case of a same-origin `fetch` call within a server`load` function, + // SvelteKit will actually just re-enter the `handle` function and set `isSubRequest` + // to `true` so that no additional network call is made. + // We want the `http.server` span of that nested call to be a child span of the + // currently active span instead of a new root span to correctly reflect this + // behavior. + if (skipIsolation || input.event.isSubRequest) { + return instrumentHandle(input, options); + } + + return withIsolationScope(isolationScope => { + // We only call continueTrace in the initial top level request to avoid + // creating a new root span for the sub request. + isolationScope.setSDKProcessingMetadata({ + // We specifically avoid cloning the request here to avoid double read errors. + // We only read request headers so we're not consuming the body anyway. + // Note to future readers: This sounds counter-intuitive but please read + // https://github.com/getsentry/sentry-javascript/issues/14583 + normalizedRequest: winterCGRequestToRequestData(input.event.request), + }); + return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options)); + }); + }; + + return sentryRequestHandler; +} diff --git a/packages/sveltekit/src/server/handleError.ts b/packages/sveltekit/src/server-common/handleError.ts similarity index 95% rename from packages/sveltekit/src/server/handleError.ts rename to packages/sveltekit/src/server-common/handleError.ts index 30ca4e28de1a..0f9782282e48 100644 --- a/packages/sveltekit/src/server/handleError.ts +++ b/packages/sveltekit/src/server-common/handleError.ts @@ -1,8 +1,7 @@ -import { consoleSandbox } from '@sentry/core'; -import { captureException } from '@sentry/node'; +import { captureException, consoleSandbox } from '@sentry/core'; import type { HandleServerError } from '@sveltejs/kit'; -import { flushIfServerless } from './utils'; +import { flushIfServerless } from '../server-common/utils'; // The SvelteKit default error handler just logs the error's stack trace to the console // see: https://github.com/sveltejs/kit/blob/369e7d6851f543a40c947e033bfc4a9506fdc0a8/packages/kit/src/runtime/server/index.js#L43 diff --git a/packages/sveltekit/src/server/load.ts b/packages/sveltekit/src/server-common/load.ts similarity index 96% rename from packages/sveltekit/src/server/load.ts rename to packages/sveltekit/src/server-common/load.ts index 30fab345e05b..49160a65b4a5 100644 --- a/packages/sveltekit/src/server/load.ts +++ b/packages/sveltekit/src/server-common/load.ts @@ -1,5 +1,9 @@ -import { addNonEnumerableProperty } from '@sentry/core'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, startSpan } from '@sentry/node'; +import { + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + addNonEnumerableProperty, + startSpan, +} from '@sentry/core'; import type { LoadEvent, ServerLoadEvent } from '@sveltejs/kit'; import type { SentryWrappedFlag } from '../common/utils'; diff --git a/packages/sveltekit/src/server/rewriteFramesIntegration.ts b/packages/sveltekit/src/server-common/rewriteFramesIntegration.ts similarity index 97% rename from packages/sveltekit/src/server/rewriteFramesIntegration.ts rename to packages/sveltekit/src/server-common/rewriteFramesIntegration.ts index 44afbca2d6df..d5928f8974b0 100644 --- a/packages/sveltekit/src/server/rewriteFramesIntegration.ts +++ b/packages/sveltekit/src/server-common/rewriteFramesIntegration.ts @@ -7,7 +7,7 @@ import { join, rewriteFramesIntegration as originalRewriteFramesIntegration, } from '@sentry/core'; -import { WRAPPED_MODULE_SUFFIX } from '../vite/autoInstrument'; +import { WRAPPED_MODULE_SUFFIX } from '../common/utils'; import type { GlobalWithSentryValues } from '../vite/injectGlobalValues'; type StackFrameIteratee = (frame: StackFrame) => StackFrame; diff --git a/packages/sveltekit/src/server/serverRoute.ts b/packages/sveltekit/src/server-common/serverRoute.ts similarity index 92% rename from packages/sveltekit/src/server/serverRoute.ts rename to packages/sveltekit/src/server-common/serverRoute.ts index 9d2cba3dbcdc..1b2169c58b8c 100644 --- a/packages/sveltekit/src/server/serverRoute.ts +++ b/packages/sveltekit/src/server-common/serverRoute.ts @@ -1,5 +1,9 @@ -import { addNonEnumerableProperty } from '@sentry/core'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, startSpan } from '@sentry/node'; +import { + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + addNonEnumerableProperty, + startSpan, +} from '@sentry/core'; import type { RequestEvent } from '@sveltejs/kit'; import { flushIfServerless, sendErrorToSentry } from './utils'; diff --git a/packages/sveltekit/src/server/utils.ts b/packages/sveltekit/src/server-common/utils.ts similarity index 95% rename from packages/sveltekit/src/server/utils.ts rename to packages/sveltekit/src/server-common/utils.ts index 8eae93d531ab..d6f09093b74d 100644 --- a/packages/sveltekit/src/server/utils.ts +++ b/packages/sveltekit/src/server-common/utils.ts @@ -1,5 +1,4 @@ -import { logger, objectify } from '@sentry/core'; -import { captureException, flush } from '@sentry/node'; +import { captureException, flush, logger, objectify } from '@sentry/core'; import type { RequestEvent } from '@sveltejs/kit'; import { DEBUG_BUILD } from '../common/debug-build'; diff --git a/packages/sveltekit/src/server/handle.ts b/packages/sveltekit/src/server/handle.ts index 84f29a2c70c5..da429bc1040f 100644 --- a/packages/sveltekit/src/server/handle.ts +++ b/packages/sveltekit/src/server/handle.ts @@ -1,208 +1,24 @@ -import type { Span } from '@sentry/core'; -import { - SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, - SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, - continueTrace, - getCurrentScope, - getDefaultIsolationScope, - getIsolationScope, - getTraceMetaTags, - logger, - setHttpStatus, - startSpan, - winterCGRequestToRequestData, - withIsolationScope, -} from '@sentry/core'; -import type { Handle, ResolveOptions } from '@sveltejs/kit'; - -import { DEBUG_BUILD } from '../common/debug-build'; -import { flushIfServerless, getTracePropagationData, sendErrorToSentry } from './utils'; - -export type SentryHandleOptions = { - /** - * Controls whether the SDK should capture errors and traces in requests that don't belong to a - * route defined in your SvelteKit application. - * - * By default, this option is set to `false` to reduce noise (e.g. bots sending random requests to your server). - * - * Set this option to `true` if you want to monitor requests events without a route. This might be useful in certain - * scenarios, for instance if you registered other handlers that handle these requests. - * If you set this option, you might want adjust the the transaction name in the `beforeSendTransaction` - * callback of your server-side `Sentry.init` options. You can also use `beforeSendTransaction` to filter out - * transactions that you still don't want to be sent to Sentry. - * - * @default false - */ - handleUnknownRoutes?: boolean; - - /** - * Controls if `sentryHandle` should inject a script tag into the page that enables instrumentation - * of `fetch` calls in `load` functions. - * - * @default true - */ - injectFetchProxyScript?: boolean; -}; +import type { CloudflareOptions } from '@sentry/cloudflare'; +import type { Handle } from '@sveltejs/kit'; +import { init } from './sdk'; /** - * Exported only for testing - */ -export const FETCH_PROXY_SCRIPT = ` - const f = window.fetch; - if(f){ - window._sentryFetchProxy = function(...a){return f(...a)} - window.fetch = function(...a){return window._sentryFetchProxy(...a)} - } -`; - -/** - * Adds Sentry tracing tags to the returned html page. - * Adds Sentry fetch proxy script to the returned html page if enabled in options. - * - * Exported only for testing - */ -export function addSentryCodeToPage(options: { injectFetchProxyScript: boolean }): NonNullable< - ResolveOptions['transformPageChunk'] -> { - return ({ html }) => { - const metaTags = getTraceMetaTags(); - const headWithMetaTags = metaTags ? `\n${metaTags}` : ''; - - const headWithFetchScript = options.injectFetchProxyScript ? `\n` : ''; - - const modifiedHead = `${headWithMetaTags}${headWithFetchScript}`; - - return html.replace('', modifiedHead); - }; -} - -/** - * A SvelteKit handle function that wraps the request for Sentry error and - * performance monitoring. - * - * Usage: - * ``` - * // src/hooks.server.ts - * import { sentryHandle } from '@sentry/sveltekit'; + * Actual implementation in ../worker/handle.ts * - * export const handle = sentryHandle(); + * This handler initializes the Sentry Node(!) SDK with the passed options. This is necessary to get + * the SDK configured for cloudflare working in dev mode. * - * // Optionally use the `sequence` function to add additional handlers. - * // export const handle = sequence(sentryHandle(), yourCustomHandler); - * ``` + * @return version of initCLoudflareSentryHandle that is called via node/server entry point */ -export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle { - const { handleUnknownRoutes, ...rest } = handlerOptions ?? {}; - const options = { - handleUnknownRoutes: handleUnknownRoutes ?? false, - ...rest, - }; +export function initCloudflareSentryHandle(options: CloudflareOptions): Handle { + let sentryInitialized = false; - const sentryRequestHandler: Handle = input => { - // In case of a same-origin `fetch` call within a server`load` function, - // SvelteKit will actually just re-enter the `handle` function and set `isSubRequest` - // to `true` so that no additional network call is made. - // We want the `http.server` span of that nested call to be a child span of the - // currently active span instead of a new root span to correctly reflect this - // behavior. - if (input.event.isSubRequest) { - return instrumentHandle(input, options); + return ({ event, resolve }) => { + if (!sentryInitialized) { + sentryInitialized = true; + init(options); } - return withIsolationScope(isolationScope => { - // We only call continueTrace in the initial top level request to avoid - // creating a new root span for the sub request. - isolationScope.setSDKProcessingMetadata({ - // We specifically avoid cloning the request here to avoid double read errors. - // We only read request headers so we're not consuming the body anyway. - // Note to future readers: This sounds counter-intuitive but please read - // https://github.com/getsentry/sentry-javascript/issues/14583 - normalizedRequest: winterCGRequestToRequestData(input.event.request), - }); - return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options)); - }); - }; - - return sentryRequestHandler; -} - -async function instrumentHandle( - { event, resolve }: Parameters[0], - options: SentryHandleOptions, -): Promise { - if (!event.route?.id && !options.handleUnknownRoutes) { return resolve(event); - } - - // caching the result of the version check in `options.injectFetchProxyScript` - // to avoid doing the dynamic import on every request - if (options.injectFetchProxyScript == null) { - try { - // @ts-expect-error - the dynamic import is fine here - const { VERSION } = await import('@sveltejs/kit'); - options.injectFetchProxyScript = isFetchProxyRequired(VERSION); - } catch { - options.injectFetchProxyScript = true; - } - } - - const routeName = `${event.request.method} ${event.route?.id || event.url.pathname}`; - - if (getIsolationScope() !== getDefaultIsolationScope()) { - getIsolationScope().setTransactionName(routeName); - } else { - DEBUG_BUILD && logger.warn('Isolation scope is default isolation scope - skipping setting transactionName'); - } - - try { - const resolveResult = await startSpan( - { - op: 'http.server', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit', - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url', - 'http.method': event.request.method, - }, - name: routeName, - }, - async (span?: Span) => { - getCurrentScope().setSDKProcessingMetadata({ - // We specifically avoid cloning the request here to avoid double read errors. - // We only read request headers so we're not consuming the body anyway. - // Note to future readers: This sounds counter-intuitive but please read - // https://github.com/getsentry/sentry-javascript/issues/14583 - normalizedRequest: winterCGRequestToRequestData(event.request), - }); - const res = await resolve(event, { - transformPageChunk: addSentryCodeToPage({ injectFetchProxyScript: options.injectFetchProxyScript ?? true }), - }); - if (span) { - setHttpStatus(span, res.status); - } - return res; - }, - ); - return resolveResult; - } catch (e: unknown) { - sendErrorToSentry(e, 'handle'); - throw e; - } finally { - await flushIfServerless(); - } -} - -/** - * We only need to inject the fetch proxy script for SvelteKit versions < 2.16.0. - * Exported only for testing. - */ -export function isFetchProxyRequired(version: string): boolean { - try { - const [major, minor] = version.trim().replace(/-.*/, '').split('.').map(Number); - if (major != null && minor != null && (major > 2 || (major === 2 && minor >= 16))) { - return false; - } - } catch { - // ignore - } - return true; + }; } diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts index 232e0562eb22..ccd09570b674 100644 --- a/packages/sveltekit/src/server/index.ts +++ b/packages/sveltekit/src/server/index.ts @@ -123,10 +123,11 @@ export * from '@sentry/node'; // ------------------------- // SvelteKit SDK exports: export { init } from './sdk'; -export { handleErrorWithSentry } from './handleError'; -export { wrapLoadWithSentry, wrapServerLoadWithSentry } from './load'; -export { sentryHandle } from './handle'; -export { wrapServerRouteWithSentry } from './serverRoute'; +export { handleErrorWithSentry } from '../server-common/handleError'; +export { wrapLoadWithSentry, wrapServerLoadWithSentry } from '../server-common/load'; +export { sentryHandle } from '../server-common/handle'; +export { initCloudflareSentryHandle } from './handle'; +export { wrapServerRouteWithSentry } from '../server-common/serverRoute'; /** * Tracks the Svelte component's initialization and mounting operation as well as diff --git a/packages/sveltekit/src/server/sdk.ts b/packages/sveltekit/src/server/sdk.ts index 7f3acbf57fbd..66362e96a729 100644 --- a/packages/sveltekit/src/server/sdk.ts +++ b/packages/sveltekit/src/server/sdk.ts @@ -3,10 +3,10 @@ import type { NodeClient, NodeOptions } from '@sentry/node'; import { getDefaultIntegrations as getDefaultNodeIntegrations } from '@sentry/node'; import { init as initNodeSdk } from '@sentry/node'; -import { rewriteFramesIntegration } from './rewriteFramesIntegration'; +import { rewriteFramesIntegration } from '../server-common/rewriteFramesIntegration'; /** - * + * Initialize the Server-side Sentry SDK * @param options */ export function init(options: NodeOptions): NodeClient | undefined { diff --git a/packages/sveltekit/src/vite/autoInstrument.ts b/packages/sveltekit/src/vite/autoInstrument.ts index 1e11f2f61500..8303af502f90 100644 --- a/packages/sveltekit/src/vite/autoInstrument.ts +++ b/packages/sveltekit/src/vite/autoInstrument.ts @@ -3,8 +3,7 @@ import * as path from 'path'; import type { ExportNamedDeclaration } from '@babel/types'; import { parseModule } from 'magicast'; import type { Plugin } from 'vite'; - -export const WRAPPED_MODULE_SUFFIX = '?sentry-auto-wrap'; +import { WRAPPED_MODULE_SUFFIX } from '../common/utils'; export type AutoInstrumentSelection = { /** diff --git a/packages/sveltekit/src/vite/sourceMaps.ts b/packages/sveltekit/src/vite/sourceMaps.ts index 78ee6389c5da..69fa4f1b2121 100644 --- a/packages/sveltekit/src/vite/sourceMaps.ts +++ b/packages/sveltekit/src/vite/sourceMaps.ts @@ -9,7 +9,7 @@ import { sentryVitePlugin } from '@sentry/vite-plugin'; import type { Plugin, UserConfig } from 'vite'; import MagicString from 'magic-string'; -import { WRAPPED_MODULE_SUFFIX } from './autoInstrument'; +import { WRAPPED_MODULE_SUFFIX } from '../common/utils'; import type { GlobalSentryValues } from './injectGlobalValues'; import { VIRTUAL_GLOBAL_VALUES_FILE, getGlobalValueInjectionCode } from './injectGlobalValues'; import { getAdapterOutputDir, getHooksFileName, loadSvelteConfig } from './svelteConfig'; diff --git a/packages/sveltekit/src/worker/cloudflare.ts b/packages/sveltekit/src/worker/cloudflare.ts new file mode 100644 index 000000000000..0d26c566ea10 --- /dev/null +++ b/packages/sveltekit/src/worker/cloudflare.ts @@ -0,0 +1,43 @@ +import { type CloudflareOptions, wrapRequestHandler } from '@sentry/cloudflare'; +import { getDefaultIntegrations as getDefaultCloudflareIntegrations } from '@sentry/cloudflare'; +import type { Handle } from '@sveltejs/kit'; + +import { addNonEnumerableProperty } from '@sentry/core'; +import { rewriteFramesIntegration } from '../server-common/rewriteFramesIntegration'; + +/** + * Initializes Sentry SvelteKit Cloudflare SDK + * This should be before the sentryHandle() call. + * + * In the Node export, this is a stub that does nothing. + */ +export function initCloudflareSentryHandle(options: CloudflareOptions): Handle { + const opts: CloudflareOptions = { + defaultIntegrations: [...getDefaultCloudflareIntegrations(options), rewriteFramesIntegration()], + ...options, + }; + + const handleInitSentry: Handle = ({ event, resolve }) => { + // if event.platform exists (should be there in a cloudflare worker), then do the cloudflare sentry init + if (event.platform) { + // This is an optional local that the `sentryHandle` handler checks for to avoid double isolation + // In Cloudflare the `wrapRequestHandler` function already takes care of + // - request isolation + // - trace continuation + // -setting the request onto the scope + addNonEnumerableProperty(event.locals, '_sentrySkipRequestIsolation', true); + return wrapRequestHandler( + { + options: opts, + request: event.request, + // @ts-expect-error This will exist in Cloudflare + context: event.platform.context, + }, + () => resolve(event), + ); + } + return resolve(event); + }; + + return handleInitSentry; +} diff --git a/packages/sveltekit/src/worker/index.ts b/packages/sveltekit/src/worker/index.ts new file mode 100644 index 000000000000..a74989b7d28e --- /dev/null +++ b/packages/sveltekit/src/worker/index.ts @@ -0,0 +1,90 @@ +// For use in cloudflare workers and other edge environments +// +// These are essentially the same as the node server exports, but using imports from @sentry/core +// instead of @sentry/node. +// +// This is expected to be used together with something like the @sentry/cloudflare package, to initialize Sentry +// in the worker. +// +// ------------------------- +// SvelteKit SDK exports: +export { handleErrorWithSentry } from '../server-common/handleError'; +export { wrapLoadWithSentry, wrapServerLoadWithSentry } from '../server-common/load'; +export { sentryHandle } from '../server-common/handle'; +export { initCloudflareSentryHandle } from './cloudflare'; +export { wrapServerRouteWithSentry } from '../server-common/serverRoute'; + +// Re-export some functions from Cloudflare SDK +export { + addBreadcrumb, + addEventProcessor, + addIntegration, + captureCheckIn, + captureConsoleIntegration, + captureEvent, + captureException, + captureFeedback, + captureMessage, + close, + continueTrace, + createTransport, + dedupeIntegration, + extraErrorDataIntegration, + flush, + functionToStringIntegration, + getActiveSpan, + getClient, + getCurrentScope, + getDefaultIntegrations, + getGlobalScope, + getIsolationScope, + getRootSpan, + getSpanDescendants, + getSpanStatusFromHttpCode, + getTraceData, + getTraceMetaTags, + inboundFiltersIntegration, + isInitialized, + lastEventId, + linkedErrorsIntegration, + requestDataIntegration, + rewriteFramesIntegration, + Scope, + SDK_VERSION, + SEMANTIC_ATTRIBUTE_SENTRY_OP, + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + setContext, + setCurrentClient, + setExtra, + setExtras, + setHttpStatus, + setMeasurement, + setTag, + setTags, + setUser, + spanToBaggageHeader, + spanToJSON, + spanToTraceHeader, + startInactiveSpan, + startNewTrace, + suppressTracing, + startSpan, + startSpanManual, + trpcMiddleware, + withActiveSpan, + withIsolationScope, + withMonitor, + withScope, + zodErrorsIntegration, +} from '@sentry/cloudflare'; + +/** + * Tracks the Svelte component's initialization and mounting operation as well as + * updates and records them as spans. These spans are only recorded on the client-side. + * Sever-side, during SSR, this function will not record any spans. + */ +export function trackComponent(_options?: unknown): void { + // no-op on the server side +} diff --git a/packages/sveltekit/test/server/handle.test.ts b/packages/sveltekit/test/server/handle.test.ts index b2adb50d91b8..9c6e2b71d330 100644 --- a/packages/sveltekit/test/server/handle.test.ts +++ b/packages/sveltekit/test/server/handle.test.ts @@ -8,16 +8,17 @@ import { spanToJSON, } from '@sentry/core'; import type { EventEnvelopeHeaders, Span } from '@sentry/core'; +import * as SentryCore from '@sentry/core'; import { NodeClient, setCurrentClient } from '@sentry/node'; -import * as SentryNode from '@sentry/node'; import type { Handle } from '@sveltejs/kit'; import { redirect } from '@sveltejs/kit'; import { vi } from 'vitest'; -import { FETCH_PROXY_SCRIPT, addSentryCodeToPage, isFetchProxyRequired, sentryHandle } from '../../src/server/handle'; +import { FETCH_PROXY_SCRIPT, addSentryCodeToPage, isFetchProxyRequired } from '../../src/server-common/handle'; +import { sentryHandle } from '../../src/server-common/handle'; import { getDefaultNodeClientOptions } from '../utils'; -const mockCaptureException = vi.spyOn(SentryNode, 'captureException').mockImplementation(() => 'xx'); +const mockCaptureException = vi.spyOn(SentryCore, 'captureException').mockImplementation(() => 'xx'); function mockEvent(override: Record = {}): Parameters[0]['event'] { const event: Parameters[0]['event'] = { @@ -98,6 +99,7 @@ beforeEach(() => { client.init(); mockCaptureException.mockClear(); + vi.clearAllMocks(); }); describe('sentryHandle', () => { @@ -366,6 +368,23 @@ describe('sentryHandle', () => { expect(_span!).toBeDefined(); }); + + it("doesn't create an isolation scope when the `_sentrySkipRequestIsolation` local is set", async () => { + const withIsolationScopeSpy = vi.spyOn(SentryCore, 'withIsolationScope'); + const continueTraceSpy = vi.spyOn(SentryCore, 'continueTrace'); + + try { + await sentryHandle({ handleUnknownRoutes: true })({ + event: { ...mockEvent({ route: undefined }), locals: { _sentrySkipRequestIsolation: true } }, + resolve: resolve(type, isError), + }); + } catch { + // + } + + expect(withIsolationScopeSpy).not.toHaveBeenCalled(); + expect(continueTraceSpy).not.toHaveBeenCalled(); + }); }); }); @@ -394,7 +413,7 @@ describe('addSentryCodeToPage', () => { it('adds meta tags and the fetch proxy script if there is an active transaction', () => { const transformPageChunk = addSentryCodeToPage({ injectFetchProxyScript: true }); - SentryNode.startSpan({ name: 'test' }, () => { + SentryCore.startSpan({ name: 'test' }, () => { const transformed = transformPageChunk({ html, done: true }) as string; expect(transformed).toContain(' 'xx'); +const mockCaptureException = vi.spyOn(SentryCore, 'captureException').mockImplementation(() => 'xx'); const captureExceptionEventHint = { mechanism: { handled: false, type: 'sveltekit' }, diff --git a/packages/sveltekit/test/server/load.test.ts b/packages/sveltekit/test/server/load.test.ts index 1001d8464ad4..8530208347a4 100644 --- a/packages/sveltekit/test/server/load.test.ts +++ b/packages/sveltekit/test/server/load.test.ts @@ -6,15 +6,15 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, } from '@sentry/core'; import type { Event } from '@sentry/core'; +import * as SentryCore from '@sentry/core'; import { NodeClient, getCurrentScope, getIsolationScope, setCurrentClient } from '@sentry/node'; -import * as SentryNode from '@sentry/node'; import type { Load, ServerLoad } from '@sveltejs/kit'; import { error, redirect } from '@sveltejs/kit'; -import { wrapLoadWithSentry, wrapServerLoadWithSentry } from '../../src/server/load'; +import { wrapLoadWithSentry, wrapServerLoadWithSentry } from '../../src/server-common/load'; import { getDefaultNodeClientOptions } from '../utils'; -const mockCaptureException = vi.spyOn(SentryNode, 'captureException').mockImplementation(() => 'xx'); +const mockCaptureException = vi.spyOn(SentryCore, 'captureException').mockImplementation(() => 'xx'); const mockStartSpan = vi.fn(); diff --git a/packages/sveltekit/test/server/rewriteFramesIntegration.test.ts b/packages/sveltekit/test/server/rewriteFramesIntegration.test.ts index 3dfd5d3e460e..1d5ca8d4d695 100644 --- a/packages/sveltekit/test/server/rewriteFramesIntegration.test.ts +++ b/packages/sveltekit/test/server/rewriteFramesIntegration.test.ts @@ -2,7 +2,7 @@ import { rewriteFramesIntegration } from '@sentry/browser'; import { basename } from '@sentry/core'; import type { Event, StackFrame } from '@sentry/core'; -import { rewriteFramesIteratee } from '../../src/server/rewriteFramesIntegration'; +import { rewriteFramesIteratee } from '../../src/server-common/rewriteFramesIntegration'; import type { GlobalWithSentryValues } from '../../src/vite/injectGlobalValues'; describe('rewriteFramesIteratee', () => { diff --git a/packages/sveltekit/test/server/serverRoute.test.ts b/packages/sveltekit/test/server/serverRoute.test.ts index de99db5a548e..046c3673a8c7 100644 --- a/packages/sveltekit/test/server/serverRoute.test.ts +++ b/packages/sveltekit/test/server/serverRoute.test.ts @@ -1,4 +1,4 @@ -import * as SentryNode from '@sentry/node'; +import * as SentryCore from '@sentry/core'; import type { NumericRange } from '@sveltejs/kit'; import { type RequestEvent, error, redirect } from '@sveltejs/kit'; import { beforeEach, describe, expect, it, vi } from 'vitest'; @@ -26,7 +26,7 @@ describe('wrapServerRouteWithSentry', () => { }); describe('wraps a server route span around the original server route handler', () => { - const startSpanSpy = vi.spyOn(SentryNode, 'startSpan'); + const startSpanSpy = vi.spyOn(SentryCore, 'startSpan'); it('assigns the route id as name if available', () => { const wrappedRouteHandler = wrapServerRouteWithSentry(originalRouteHandler); @@ -71,7 +71,7 @@ describe('wrapServerRouteWithSentry', () => { }); }); - const captureExceptionSpy = vi.spyOn(SentryNode, 'captureException'); + const captureExceptionSpy = vi.spyOn(SentryCore, 'captureException'); describe('captures server route errors', () => { it('captures and rethrows normal server route error', async () => { const error = new Error('Server Route Error'); diff --git a/packages/sveltekit/test/server/utils.test.ts b/packages/sveltekit/test/server/utils.test.ts index 5e8b9b2b99a3..53e588d683ec 100644 --- a/packages/sveltekit/test/server/utils.test.ts +++ b/packages/sveltekit/test/server/utils.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { getTracePropagationData } from '../../src/server/utils'; +import { getTracePropagationData } from '../../src/server-common/utils'; const MOCK_REQUEST_EVENT: any = { request: { From 08569e68235c5b16ff0ab48f135b546a262a3c20 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Fri, 21 Feb 2025 11:00:17 -0500 Subject: [PATCH 2/2] Revert "test(node): Add `pg-native` integration tests" (#15464) Reverts getsentry/sentry-javascript#15206 This PR requires `libpq` for `yarn install` to be complete, so going to revert this. Let's put this requirement into the docker image instead. --- .github/workflows/build.yml | 4 - .../node-integration-tests/package.json | 4 +- .../tracing/postgres/scenario-native.js | 47 ------ .../suites/tracing/postgres/test.ts | 50 ------ yarn.lock | 145 +++++------------- 5 files changed, 42 insertions(+), 208 deletions(-) delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.js diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f7341976d043..aae090f76188 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -713,10 +713,6 @@ jobs: with: dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Build `libpq` - run: yarn libpq:build - working-directory: dev-packages/node-integration-tests - - name: Overwrite typescript version if: matrix.typescript == '3.8' run: node ./scripts/use-ts-3_8.js diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index 08ede11390e7..bbb7e300ecee 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -16,7 +16,6 @@ "build:types": "tsc -p tsconfig.types.json", "clean": "rimraf -g **/node_modules && run-p clean:script", "clean:script": "node scripts/clean.js", - "libpq:build": "npm rebuild libpq", "express-v5-install": "cd suites/express-v5 && yarn --no-lockfile", "lint": "eslint . --format stylish", "fix": "eslint . --format stylish --fix", @@ -63,8 +62,7 @@ "nock": "^13.5.5", "node-cron": "^3.0.3", "node-schedule": "^2.1.1", - "pg": "^8.13.1", - "pg-native": "3.2.0", + "pg": "^8.7.3", "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/tracing/postgres/scenario-native.js b/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.js deleted file mode 100644 index ec4768217c42..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.js +++ /dev/null @@ -1,47 +0,0 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -// Stop the process from exiting before the transaction is sent -setInterval(() => {}, 1000); - -const { native } = require('pg'); -const { Client } = native; - -const client = new Client({ port: 5444, user: 'test', password: 'test', database: 'tests' }); - -async function run() { - await Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - async () => { - try { - await client.connect(); - - await client - .query( - 'CREATE TABLE "NativeUser" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"));', - ) - .catch(() => { - // if this is not a fresh database, the table might already exist - }); - - await client.query('INSERT INTO "NativeUser" ("email", "name") VALUES ($1, $2)', ['tim', 'tim@domain.com']); - await client.query('SELECT * FROM "NativeUser"'); - } finally { - await client.end(); - } - }, - ); -} - -// eslint-disable-next-line @typescript-eslint/no-floating-promises -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts index 9f8ba1449784..f2549c70eb90 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts @@ -53,54 +53,4 @@ describe('postgres auto instrumentation', () => { .expect({ transaction: EXPECTED_TRANSACTION }) .start(done); }); - - test('should auto-instrument `pg-native` package', done => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'sentry.origin': 'manual', - 'sentry.op': 'db', - }), - description: 'pg.connect', - op: 'db', - status: 'ok', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'INSERT INTO "NativeUser" ("email", "name") VALUES ($1, $2)', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'INSERT INTO "NativeUser" ("email", "name") VALUES ($1, $2)', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'SELECT * FROM "NativeUser"', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'SELECT * FROM "NativeUser"', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', - }), - ]), - }; - - createRunner(__dirname, 'scenario-native.js') - .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port 5432'] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start(done); - }); }); diff --git a/yarn.lock b/yarn.lock index 3243b6980af1..0c7b60c816e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10688,7 +10688,7 @@ binary@^0.3.0: resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.3.0.tgz#1d269cbf7e6243ea886aa41453c3651ccbe13c22" integrity sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg== -bindings@1.5.0, bindings@^1.4.0: +bindings@^1.4.0: version "1.5.0" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== @@ -11400,6 +11400,11 @@ buffer-more-ints@~1.0.0: resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz#ef4f8e2dddbad429ed3828a9c55d44f05c611422" integrity sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg== +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -15598,6 +15603,11 @@ expect@^27.5.1: jest-matcher-utils "^27.5.1" jest-message-util "^27.5.1" +exponential-backoff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" + integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== + express@4.21.1, express@^4.10.7, express@^4.16.4, express@^4.17.1, express@^4.17.3, express@^4.18.1, express@^4.21.1: version "4.21.1" resolved "https://registry.yarnpkg.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281" @@ -19951,14 +19961,6 @@ libnpmpublish@7.3.0: sigstore "^1.4.0" ssri "^10.0.1" -libpq@1.8.13: - version "1.8.13" - resolved "https://registry.yarnpkg.com/libpq/-/libpq-1.8.13.tgz#d48af53c88defa7a20f958ef51bbbc0f58747355" - integrity sha512-t1wpnGVgwRIFSKoe4RFUllAFj953kNMcdXhGvFJwI0r6lJQqgSwTeiIciaCinjOmHk0HnFeWQSMC6Uw2591G4A== - dependencies: - bindings "1.5.0" - nan "2.19.0" - license-webpack-plugin@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz#1e18442ed20b754b82f1adeff42249b81d11aec6" @@ -20468,12 +20470,7 @@ lru-cache@6.0.0, lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^10.2.0: - version "10.2.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" - integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== - -lru-cache@^10.4.3: +lru-cache@^10.2.0, lru-cache@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== @@ -21614,12 +21611,7 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.3.tgz#05ea638da44e475037ed94d1c7efcc76a25e1974" - integrity sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg== - -minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -21969,11 +21961,6 @@ named-placeholders@^1.1.3: dependencies: lru-cache "^7.14.1" -nan@2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" - integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== - nanoid@^3.3.3, nanoid@^3.3.4, nanoid@^3.3.6, nanoid@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" @@ -22317,22 +22304,18 @@ node-forge@^1, node-forge@^1.3.1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-gyp-build@^4.2.2: +node-gyp-build@^4.2.2, node-gyp-build@^4.3.0: version "4.6.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== -node-gyp-build@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" - integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== - node-gyp@^9.0.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.3.0.tgz#f8eefe77f0ad8edb3b3b898409b53e697642b319" - integrity sha512-A6rJWfXFz7TQNjpldJ915WFb1LnhO4lIve3ANPbWreuEoLoKlFT3sxIepPBkLhM27crW8YmN+pjlgbasH6cH/Q== + version "9.4.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.4.1.tgz#8a1023e0d6766ecb52764cc3a734b36ff275e185" + integrity sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ== dependencies: env-paths "^2.2.0" + exponential-backoff "^3.1.1" glob "^7.1.4" graceful-fs "^4.2.6" make-fetch-happen "^10.0.3" @@ -23443,6 +23426,11 @@ package-name-regex@~2.0.6: resolved "https://registry.yarnpkg.com/package-name-regex/-/package-name-regex-2.0.6.tgz#b54bcb04d950e38082b7bb38fa558e01c1679334" integrity sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA== +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + pacote@13.6.2: version "13.6.2" resolved "https://registry.yarnpkg.com/pacote/-/pacote-13.6.2.tgz#0d444ba3618ab3e5cd330b451c22967bbd0ca48a" @@ -23792,65 +23780,31 @@ periscopic@^3.1.0: estree-walker "^3.0.0" is-reference "^3.0.0" -pg-cloudflare@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" - integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== - -pg-connection-string@2.6.1: +pg-connection-string@2.6.1, pg-connection-string@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.1.tgz#78c23c21a35dd116f48e12e23c0965e8d9e2cbfb" integrity sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg== -pg-connection-string@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37" - integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA== - pg-int8@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== -pg-native@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/pg-native/-/pg-native-3.2.0.tgz#1183a549c00741040f1f47f9167a6bf378206826" - integrity sha512-9q9I6RmT285DiRc0xkYb8e+bwOIIbnfVLddnzzXW35K1sZc74dR+symo2oeuzSW/sDQ8n24gWAvlGWK/GDJ3+Q== - dependencies: - libpq "1.8.13" - pg-types "^1.12.1" - pg-numeric@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== -pg-pool@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.7.0.tgz#d4d3c7ad640f8c6a2245adc369bafde4ebb8cbec" - integrity sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g== +pg-pool@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" + integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== -pg-protocol@*: +pg-protocol@*, pg-protocol@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== -pg-protocol@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.7.0.tgz#ec037c87c20515372692edac8b63cf4405448a93" - integrity sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ== - -pg-types@^1.12.1: - version "1.13.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.13.0.tgz#75f490b8a8abf75f1386ef5ec4455ecf6b345c63" - integrity sha512-lfKli0Gkl/+za/+b6lzENajczwZHc7D5kiUCZfgm914jipD2kIOIvEkAhZ8GrW3/TUoP9w8FHjwpPObBye5KQQ== - dependencies: - pg-int8 "1.0.1" - postgres-array "~1.0.0" - postgres-bytea "~1.0.0" - postgres-date "~1.0.0" - postgres-interval "^1.1.0" - pg-types@^2.1.0, pg-types@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" @@ -23875,18 +23829,18 @@ pg-types@^4.0.1: postgres-interval "^3.0.0" postgres-range "^1.1.1" -pg@^8.13.1: - version "8.13.1" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.13.1.tgz#6498d8b0a87ff76c2df7a32160309d3168c0c080" - integrity sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ== - dependencies: - pg-connection-string "^2.7.0" - pg-pool "^3.7.0" - pg-protocol "^1.7.0" +pg@^8.7.3: + version "8.7.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.3.tgz#8a5bdd664ca4fda4db7997ec634c6e5455b27c44" + integrity sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.5.1" + pg-protocol "^1.5.0" pg-types "^2.1.0" pgpass "1.x" - optionalDependencies: - pg-cloudflare "^1.1.1" pgpass@1.x: version "1.0.5" @@ -24647,11 +24601,6 @@ postcss@^8.1.10, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.3.7, postcss@^8.4. picocolors "^1.1.1" source-map-js "^1.2.1" -postgres-array@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-1.0.3.tgz#c561fc3b266b21451fc6555384f4986d78ec80f5" - integrity sha512-5wClXrAP0+78mcsNX3/ithQ5exKvCyK5lr5NEEEeGwwM6NJdQgzIJBVxLvRW+huFpX92F2QnZ5CcokH0VhK2qQ== - postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -24674,7 +24623,7 @@ postgres-bytea@~3.0.0: dependencies: obuf "~1.1.2" -postgres-date@~1.0.0, postgres-date@~1.0.4: +postgres-date@~1.0.4: version "1.0.7" resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== @@ -28031,19 +27980,7 @@ tar@6.1.11: mkdirp "^1.0.3" yallist "^4.0.0" -tar@^6.1.11, tar@^6.1.2: - version "6.1.12" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.12.tgz#3b742fb05669b55671fb769ab67a7791ea1a62e6" - integrity sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tar@^6.2.0: +tar@^6.1.11, tar@^6.1.2, tar@^6.2.0: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==