diff --git a/.github/ISSUE_TEMPLATE/flaky.yml b/.github/ISSUE_TEMPLATE/flaky.yml index 1b9290cc3bbc..22b035ec1145 100644 --- a/.github/ISSUE_TEMPLATE/flaky.yml +++ b/.github/ISSUE_TEMPLATE/flaky.yml @@ -18,7 +18,7 @@ body: id: job-name attributes: label: Name of Job - placeholder: 'CI: Build & Test / Nextjs (Node 18) Tests' + placeholder: 'CI: Build & Test / Nextjs (Node 20) Tests' description: name of job as reported in the status report validations: required: true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 17bf2143e1e7..70d6b1c997c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -800,7 +800,6 @@ jobs: # Only check typescript for latest version (to streamline CI) - node: 24 typescript: '5.0' - # No need to test orchestrion for v18 - node: 20.19 use_orchestrion: 'true' - node: 22 diff --git a/dev-packages/browser-integration-tests/package.json b/dev-packages/browser-integration-tests/package.json index 3b0952904a10..0a7a6c1b7d1f 100644 --- a/dev-packages/browser-integration-tests/package.json +++ b/dev-packages/browser-integration-tests/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "scripts": { diff --git a/dev-packages/bun-integration-tests/package.json b/dev-packages/bun-integration-tests/package.json index 5601caddb316..5a3f018a7faf 100644 --- a/dev-packages/bun-integration-tests/package.json +++ b/dev-packages/bun-integration-tests/package.json @@ -3,7 +3,7 @@ "version": "10.67.0", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "scripts": { diff --git a/dev-packages/clear-cache-gh-action/package.json b/dev-packages/clear-cache-gh-action/package.json index a117f7532f0a..4f71c378d3b5 100644 --- a/dev-packages/clear-cache-gh-action/package.json +++ b/dev-packages/clear-cache-gh-action/package.json @@ -4,7 +4,7 @@ "version": "10.67.0", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "main": "index.mjs", diff --git a/dev-packages/cloudflare-integration-tests/package.json b/dev-packages/cloudflare-integration-tests/package.json index 938e6c5beee7..961e60b7307a 100644 --- a/dev-packages/cloudflare-integration-tests/package.json +++ b/dev-packages/cloudflare-integration-tests/package.json @@ -3,7 +3,7 @@ "version": "10.67.0", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "scripts": { diff --git a/dev-packages/deno-integration-tests/package.json b/dev-packages/deno-integration-tests/package.json index 78de7fb40aa3..f9093d7e34dc 100644 --- a/dev-packages/deno-integration-tests/package.json +++ b/dev-packages/deno-integration-tests/package.json @@ -3,7 +3,7 @@ "version": "10.67.0", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "scripts": { diff --git a/dev-packages/e2e-tests/test-applications/ember-classic/package.json b/dev-packages/e2e-tests/test-applications/ember-classic/package.json index 9f96912ce555..1fcfbea1dc2e 100644 --- a/dev-packages/e2e-tests/test-applications/ember-classic/package.json +++ b/dev-packages/e2e-tests/test-applications/ember-classic/package.json @@ -72,7 +72,7 @@ "webpack": "~5.104.1" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "resolutions": { "@babel/traverse": "~7.25.9", diff --git a/dev-packages/e2e-tests/test-applications/ember-embroider/package.json b/dev-packages/e2e-tests/test-applications/ember-embroider/package.json index f1dff2628aac..d733eb08df19 100644 --- a/dev-packages/e2e-tests/test-applications/ember-embroider/package.json +++ b/dev-packages/e2e-tests/test-applications/ember-embroider/package.json @@ -61,7 +61,7 @@ "typescript": "^5.4.5" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "ember": { "edition": "octane" diff --git a/dev-packages/external-contributor-gh-action/package.json b/dev-packages/external-contributor-gh-action/package.json index 5ae0ff242e67..7d66114b93f6 100644 --- a/dev-packages/external-contributor-gh-action/package.json +++ b/dev-packages/external-contributor-gh-action/package.json @@ -4,7 +4,7 @@ "version": "10.67.0", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "main": "index.mjs", diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index edd41b92ed07..595611a1e888 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -3,7 +3,7 @@ "version": "10.67.0", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "main": "build/cjs/index.js", diff --git a/dev-packages/size-limit-gh-action/package.json b/dev-packages/size-limit-gh-action/package.json index 1f4c02bb2da3..5ce36a062fe9 100644 --- a/dev-packages/size-limit-gh-action/package.json +++ b/dev-packages/size-limit-gh-action/package.json @@ -4,7 +4,7 @@ "version": "10.67.0", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "private": true, "main": "index.mjs", diff --git a/dev-packages/test-utils/package.json b/dev-packages/test-utils/package.json index 4ec1db540b0f..4e288b3f7864 100644 --- a/dev-packages/test-utils/package.json +++ b/dev-packages/test-utils/package.json @@ -27,7 +27,7 @@ }, "sideEffects": false, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "scripts": { "lint:fix": "OXLINT_TSGOLINT_DANGEROUSLY_SUPPRESS_PROGRAM_DIAGNOSTICS=true oxlint . --fix --type-aware", diff --git a/docs/supporting-a-new-node-version.md b/docs/supporting-a-new-node-version.md index 957ec9b078db..bd4068d03eb5 100644 --- a/docs/supporting-a-new-node-version.md +++ b/docs/supporting-a-new-node-version.md @@ -86,7 +86,7 @@ Repo: [sentry-javascript](https://github.com/getsentry/sentry-javascript) Reference: [#20710](https://github.com/getsentry/sentry-javascript/pull/20710) -1. Add the version to the CI test matrix in `.github/workflows/build.yml` to every `node: [18, 20, 22, 24]` entry. +1. Add the version to the CI test matrix in `.github/workflows/build.yml` to every `node: [20.19, 22, 24, 26]` entry. 2. Bump the native module dependencies to the versions released in Steps 1 and 2: - [ ] `@sentry-internal/node-cpu-profiler` in `packages/profiling-node` diff --git a/packages/angular/package.json b/packages/angular/package.json index 5a98e02303e3..c65597e0241b 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "type": "module", "module": "build/fesm2015/sentry-angular.mjs", diff --git a/packages/astro/package.json b/packages/astro/package.json index c8977282394f..824d265f1fbe 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -14,7 +14,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18.19.1" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "type": "module", "files": [ diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json index 31281278cf06..c516d711d6f5 100644 --- a/packages/aws-serverless/package.json +++ b/packages/aws-serverless/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build/npm", diff --git a/packages/browser-utils/package.json b/packages/browser-utils/package.json index ca6b84d78495..ea5a26223bc1 100644 --- a/packages/browser-utils/package.json +++ b/packages/browser-utils/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/browser/package.json b/packages/browser/package.json index 7638670e1ce6..cb7f6aec3afa 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build/npm" diff --git a/packages/bun/package.json b/packages/bun/package.json index cc98b8913ac7..da4d858fa105 100644 --- a/packages/bun/package.json +++ b/packages/bun/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/bundler-plugins/package.json b/packages/bundler-plugins/package.json index 22a3a36298f9..bd0b3c7bc725 100644 --- a/packages/bundler-plugins/package.json +++ b/packages/bundler-plugins/package.json @@ -143,7 +143,7 @@ "extends": "../../package.json" }, "engines": { - "node": ">= 18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "sideEffects": [ "./sentry-release-injection-file.js", diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index d4dc35e6fbdd..b8dba6e25e52 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/core/package.json b/packages/core/package.json index 8ec000a64080..af00b77c1de4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build", diff --git a/packages/effect/package.json b/packages/effect/package.json index e19b2cef7ba2..ced278816997 100644 --- a/packages/effect/package.json +++ b/packages/effect/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/elysia/package.json b/packages/elysia/package.json index 8919adf3cf2b..ccb8f869dfdd 100644 --- a/packages/elysia/package.json +++ b/packages/elysia/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/ember/package.json b/packages/ember/package.json index 3254d31a92fc..441b6aa2ef53 100644 --- a/packages/ember/package.json +++ b/packages/ember/package.json @@ -82,7 +82,7 @@ "webpack": "~5.104.1" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "ember": { "edition": "octane" diff --git a/packages/eslint-config-sdk/package.json b/packages/eslint-config-sdk/package.json index 41ce9bff9d36..91ae0b1fdfb0 100644 --- a/packages/eslint-config-sdk/package.json +++ b/packages/eslint-config-sdk/package.json @@ -12,7 +12,7 @@ "sentry" ], "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/src" diff --git a/packages/eslint-plugin-sdk/package.json b/packages/eslint-plugin-sdk/package.json index c22affcc4f20..a295fc81fdd2 100644 --- a/packages/eslint-plugin-sdk/package.json +++ b/packages/eslint-plugin-sdk/package.json @@ -12,7 +12,7 @@ "sentry" ], "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/src" diff --git a/packages/feedback/package.json b/packages/feedback/package.json index fc85967dbf5d..47d203e41721 100644 --- a/packages/feedback/package.json +++ b/packages/feedback/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build/npm" diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index b3f06e9385ff..2e502b404072 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -11,7 +11,7 @@ "gatsby-plugin" ], "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build", diff --git a/packages/google-cloud-serverless/package.json b/packages/google-cloud-serverless/package.json index 7b05bf42a8b9..31e6a3d823b2 100644 --- a/packages/google-cloud-serverless/package.json +++ b/packages/google-cloud-serverless/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/hono/package.json b/packages/hono/package.json index f306fb07095f..e40f9ea13d4d 100644 --- a/packages/hono/package.json +++ b/packages/hono/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/integration-shims/package.json b/packages/integration-shims/package.json index 55b60925aff3..35d0d6f9c89f 100644 --- a/packages/integration-shims/package.json +++ b/packages/integration-shims/package.json @@ -50,7 +50,7 @@ "@sentry/core": "10.67.0" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "volta": { "extends": "../../package.json" diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json index 40f6330e1908..1e781fc79eb2 100644 --- a/packages/nestjs/package.json +++ b/packages/nestjs/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build", diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index a4a814869a22..09cf846ece3f 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "main": "build/cjs/index.server.js", "module": "build/esm/index.server.js", diff --git a/packages/nitro/package.json b/packages/nitro/package.json index a90e973000e4..ec0e35fcb399 100644 --- a/packages/nitro/package.json +++ b/packages/nitro/package.json @@ -14,7 +14,7 @@ "error-tracking" ], "engines": { - "node": ">=18.19.1" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/node-native/package.json b/packages/node-native/package.json index 80c3c09ce433..fbee84046e43 100644 --- a/packages/node-native/package.json +++ b/packages/node-native/package.json @@ -31,7 +31,7 @@ } }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "publishConfig": { "access": "public" diff --git a/packages/node/package.json b/packages/node/package.json index 1b6747382cc7..89ad77dbc181 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/node/src/integrations/anr/index.ts b/packages/node/src/integrations/anr/index.ts index 23255dd3357e..1c5b00fe9d4e 100644 --- a/packages/node/src/integrations/anr/index.ts +++ b/packages/node/src/integrations/anr/index.ts @@ -11,7 +11,6 @@ import { getIsolationScope, GLOBAL_OBJ, } from '@sentry/core'; -import { NODE_VERSION } from '../../nodeVersion'; import type { NodeClient } from '../../sdk/client'; import { isDebuggerEnabled } from '../../utils/debug'; import type { AnrIntegrationOptions, WorkerStartData } from './common'; @@ -65,10 +64,6 @@ type AnrInternal = { startWorker: () => void; stopWorker: () => void }; // eslint-disable-next-line typescript/no-deprecated const _anrIntegration = ((options: Partial = {}) => { - if (NODE_VERSION.major < 16 || (NODE_VERSION.major === 16 && NODE_VERSION.minor < 17)) { - throw new Error('ANR detection requires Node 16.17.0 or later'); - } - let worker: Promise<() => void> | undefined; let client: NodeClient | undefined; diff --git a/packages/node/src/integrations/local-variables/index.ts b/packages/node/src/integrations/local-variables/index.ts index 13a580383fcf..f441dd726286 100644 --- a/packages/node/src/integrations/local-variables/index.ts +++ b/packages/node/src/integrations/local-variables/index.ts @@ -1,9 +1,7 @@ import type { Integration } from '@sentry/core'; -import { NODE_VERSION } from '../../nodeVersion'; import type { LocalVariablesIntegrationOptions } from './common'; import { localVariablesAsyncIntegration } from './local-variables-async'; -import { localVariablesSyncIntegration } from './local-variables-sync'; export const localVariablesIntegration = (options: LocalVariablesIntegrationOptions = {}): Integration => { - return NODE_VERSION.major < 19 ? localVariablesSyncIntegration(options) : localVariablesAsyncIntegration(options); + return localVariablesAsyncIntegration(options); }; diff --git a/packages/node/src/integrations/local-variables/local-variables-sync.ts b/packages/node/src/integrations/local-variables/local-variables-sync.ts deleted file mode 100644 index 043132fcb275..000000000000 --- a/packages/node/src/integrations/local-variables/local-variables-sync.ts +++ /dev/null @@ -1,433 +0,0 @@ -import type { Debugger, InspectorNotification, Runtime, Session } from 'node:inspector'; -import type { CollectBehavior, Event, Exception, IntegrationFn, StackFrame, StackParser } from '@sentry/core'; -import { debug, defineIntegration, getClient, LRUMap } from '@sentry/core'; -import { NODE_MAJOR } from '../../nodeVersion'; -import type { NodeClient } from '../../sdk/client'; -import { isDebuggerEnabled } from '../../utils/debug'; -import type { - FrameVariables, - LocalVariablesIntegrationOptions, - PausedExceptionEvent, - RateLimitIncrement, - Variables, -} from './common'; -import { createRateLimiter, filterFrameVariables, functionNamesMatch } from './common'; - -/** Creates a unique hash from stack frames */ -export function hashFrames(frames: StackFrame[] | undefined): string | undefined { - if (frames === undefined) { - return; - } - - // Only hash the 10 most recent frames (ie. the last 10) - return frames.slice(-10).reduce((acc, frame) => `${acc},${frame.function},${frame.lineno},${frame.colno}`, ''); -} - -/** - * We use the stack parser to create a unique hash from the exception stack trace - * This is used to lookup vars when the exception passes through the event processor - */ -export function hashFromStack(stackParser: StackParser, stack: string | undefined): string | undefined { - if (stack === undefined) { - return undefined; - } - - return hashFrames(stackParser(stack, 1)); -} - -type OnPauseEvent = InspectorNotification; -export interface DebugSession { - /** Configures and connects to the debug session */ - configureAndConnect(onPause: (message: OnPauseEvent, complete: () => void) => void, captureAll: boolean): void; - /** Updates which kind of exceptions to capture */ - setPauseOnExceptions(captureAll: boolean): void; - /** Gets local variables for an objectId */ - getLocalVariables(objectId: string, callback: (vars: Variables) => void): void; -} - -type Next = (result: T) => void; -type Add = (fn: Next) => void; -type CallbackWrapper = { add: Add; next: Next }; - -/** Creates a container for callbacks to be called sequentially */ -export function createCallbackList(complete: Next): CallbackWrapper { - // A collection of callbacks to be executed last to first - let callbacks: Next[] = []; - - let completedCalled = false; - function checkedComplete(result: T): void { - callbacks = []; - if (completedCalled) { - return; - } - completedCalled = true; - complete(result); - } - - // complete should be called last - callbacks.push(checkedComplete); - - function add(fn: Next): void { - callbacks.push(fn); - } - - function next(result: T): void { - const popped = callbacks.pop() || checkedComplete; - - try { - popped(result); - } catch { - // If there is an error, we still want to call the complete callback - checkedComplete(result); - } - } - - return { add, next }; -} - -/** - * Promise API is available as `Experimental` and in Node 19 only. - * - * Callback-based API is `Stable` since v14 and `Experimental` since v8. - * Because of that, we are creating our own `AsyncSession` class. - * - * https://nodejs.org/docs/latest-v19.x/api/inspector.html#promises-api - * https://nodejs.org/docs/latest-v14.x/api/inspector.html - */ -class AsyncSession implements DebugSession { - /** Throws if inspector API is not available */ - private constructor(private readonly _session: Session) { - // - } - - public static async create(orDefault?: DebugSession | undefined): Promise { - if (orDefault) { - return orDefault; - } - - const inspector = await import('node:inspector'); - return new AsyncSession(new inspector.Session()); - } - - /** @inheritdoc */ - public configureAndConnect(onPause: (event: OnPauseEvent, complete: () => void) => void, captureAll: boolean): void { - this._session.connect(); - - this._session.on('Debugger.paused', event => { - onPause(event, () => { - // After the pause work is complete, resume execution or the exception context memory is leaked - this._session.post('Debugger.resume'); - }); - }); - - this._session.post('Debugger.enable'); - this._session.post('Debugger.setPauseOnExceptions', { state: captureAll ? 'all' : 'uncaught' }); - } - - public setPauseOnExceptions(captureAll: boolean): void { - this._session.post('Debugger.setPauseOnExceptions', { state: captureAll ? 'all' : 'uncaught' }); - } - - /** @inheritdoc */ - public getLocalVariables(objectId: string, complete: (vars: Variables) => void): void { - this._getProperties(objectId, props => { - const { add, next } = createCallbackList(complete); - - for (const prop of props) { - if (prop.value?.objectId && prop.value.className === 'Array') { - const id = prop.value.objectId; - add(vars => this._unrollArray(id, prop.name, vars, next)); - } else if (prop.value?.objectId && prop.value.className === 'Object') { - const id = prop.value.objectId; - add(vars => this._unrollObject(id, prop.name, vars, next)); - } else if (prop.value) { - add(vars => this._unrollOther(prop, vars, next)); - } - } - - next({}); - }); - } - - /** - * Gets all the PropertyDescriptors of an object - */ - private _getProperties(objectId: string, next: (result: Runtime.PropertyDescriptor[]) => void): void { - this._session.post( - 'Runtime.getProperties', - { - objectId, - ownProperties: true, - }, - (err, params) => { - if (err) { - next([]); - } else { - next(params.result); - } - }, - ); - } - - /** - * Unrolls an array property - */ - private _unrollArray(objectId: string, name: string, vars: Variables, next: (vars: Variables) => void): void { - this._getProperties(objectId, props => { - vars[name] = props - .filter(v => v.name !== 'length' && !isNaN(parseInt(v.name, 10))) - .sort((a, b) => parseInt(a.name, 10) - parseInt(b.name, 10)) - .map(v => v.value?.value); - - next(vars); - }); - } - - /** - * Unrolls an object property - */ - private _unrollObject(objectId: string, name: string, vars: Variables, next: (obj: Variables) => void): void { - this._getProperties(objectId, props => { - vars[name] = props - .map<[string, unknown]>(v => [v.name, v.value?.value]) - .reduce((obj, [key, val]) => { - obj[key] = val; - return obj; - }, {} as Variables); - - next(vars); - }); - } - - /** - * Unrolls other properties - */ - private _unrollOther(prop: Runtime.PropertyDescriptor, vars: Variables, next: (vars: Variables) => void): void { - if (prop.value) { - if ('value' in prop.value) { - if (prop.value.value === undefined || prop.value.value === null) { - vars[prop.name] = `<${prop.value.value}>`; - } else { - vars[prop.name] = prop.value.value; - } - } else if ('description' in prop.value && prop.value.type !== 'function') { - vars[prop.name] = `<${prop.value.description}>`; - } else if (prop.value.type === 'undefined') { - vars[prop.name] = ''; - } - } - - next(vars); - } -} - -const INTEGRATION_NAME = 'LocalVariables' as const; - -/** - * Adds local variables to exception frames - */ -const _localVariablesSyncIntegration = (( - options: LocalVariablesIntegrationOptions = {}, - sessionOverride?: DebugSession, -) => { - const cachedFrames: LRUMap = new LRUMap(20); - let rateLimiter: RateLimitIncrement | undefined; - let shouldProcessEvent = false; - - function addLocalVariablesToException(exception: Exception, behavior: CollectBehavior): void { - const hash = hashFrames(exception.stacktrace?.frames); - - if (hash === undefined) { - return; - } - - // Check if we have local variables for an exception that matches the hash - // remove is identical to get but also removes the entry from the cache - const cachedFrame = cachedFrames.remove(hash); - - // When disabled, nothing is collected so we don't attach empty `vars` to frames - if (cachedFrame === undefined || behavior === false) { - return; - } - - // Filter out frames where the function name is `new Promise` since these are in the error.stack frames - // but do not appear in the debugger call frames - const frames = (exception.stacktrace?.frames || []).filter(frame => frame.function !== 'new Promise'); - - for (let i = 0; i < frames.length; i++) { - // Sentry frames are in reverse order - const frameIndex = frames.length - i - 1; - - const cachedFrameVariable = cachedFrame[i]; - const frameVariable = frames[frameIndex]; - - // Drop out if we run out of frames to match up - if (!frameVariable || !cachedFrameVariable) { - break; - } - - if ( - // We need to have vars to add - cachedFrameVariable.vars === undefined || - // Only skip out-of-app frames if includeOutOfAppFrames is not true - (frameVariable.in_app === false && options.includeOutOfAppFrames !== true) || - // The function names need to match - !functionNamesMatch(frameVariable.function, cachedFrameVariable.function) - ) { - continue; - } - - frameVariable.vars = filterFrameVariables(cachedFrameVariable.vars, behavior); - } - } - - function addLocalVariablesToEvent(event: Event): Event { - for (const exception of event.exception?.values || []) { - addLocalVariablesToException(exception, getClient()?.getDataCollectionOptions().stackFrameVariables ?? true); - } - - return event; - } - - let setupPromise: Promise | undefined; - - async function setup(): Promise { - const client = getClient(); - const clientOptions = client?.getOptions(); - - if (!clientOptions?.includeLocalVariables) { - return; - } - - // Only setup this integration if the Node version is >= v18 - // https://github.com/getsentry/sentry-javascript/issues/7697 - const unsupportedNodeVersion = NODE_MAJOR < 18; - - if (unsupportedNodeVersion) { - debug.log('The `LocalVariables` integration is only supported on Node >= v18.'); - return; - } - - if (await isDebuggerEnabled()) { - debug.warn('Local variables capture has been disabled because the debugger was already enabled'); - return; - } - - try { - const session = await AsyncSession.create(sessionOverride); - - const handlePaused = ( - stackParser: StackParser, - { params: { reason, data, callFrames } }: InspectorNotification, - complete: () => void, - ): void => { - if (reason !== 'exception' && reason !== 'promiseRejection') { - complete(); - return; - } - - rateLimiter?.(); - - // data.description contains the original error.stack - const exceptionHash = hashFromStack(stackParser, data.description); - - if (exceptionHash == undefined) { - complete(); - return; - } - - const { add, next } = createCallbackList(frames => { - cachedFrames.set(exceptionHash, frames); - complete(); - }); - - // Because we're queuing up and making all these calls synchronously, we can potentially overflow the stack - // For this reason we only attempt to get local variables for the first 5 frames - for (let i = 0; i < Math.min(callFrames.length, 5); i++) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { scopeChain, functionName, this: obj } = callFrames[i]!; - - const localScope = scopeChain.find(scope => scope.type === 'local'); - - // obj.className is undefined in ESM modules - const fn = obj.className === 'global' || !obj.className ? functionName : `${obj.className}.${functionName}`; - - if (localScope?.object.objectId === undefined) { - add(frames => { - frames[i] = { function: fn }; - next(frames); - }); - } else { - const id = localScope.object.objectId; - add(frames => - session.getLocalVariables(id, vars => { - frames[i] = { function: fn, vars }; - next(frames); - }), - ); - } - } - - next([]); - }; - - const captureAll = options.captureAllExceptions !== false; - - session.configureAndConnect( - (ev, complete) => - handlePaused(clientOptions.stackParser, ev as InspectorNotification, complete), - captureAll, - ); - - if (captureAll) { - const max = options.maxExceptionsPerSecond || 50; - - rateLimiter = createRateLimiter( - max, - () => { - debug.log('Local variables rate-limit lifted.'); - session.setPauseOnExceptions(true); - }, - seconds => { - debug.log( - `Local variables rate-limit exceeded. Disabling capturing of caught exceptions for ${seconds} seconds.`, - ); - session.setPauseOnExceptions(false); - }, - ); - } - - shouldProcessEvent = true; - } catch (error) { - debug.log('The `LocalVariables` integration failed to start.', error); - } - } - - return { - name: INTEGRATION_NAME, - setupOnce() { - setupPromise = setup(); - }, - async processEvent(event: Event): Promise { - await setupPromise; - - if (shouldProcessEvent) { - return addLocalVariablesToEvent(event); - } - - return event; - }, - // These are entirely for testing - _getCachedFramesCount(): number { - return cachedFrames.size; - }, - _getFirstCachedFrame(): FrameVariables[] | undefined { - return cachedFrames.values()[0]; - }, - }; -}) satisfies IntegrationFn; - -/** - * Adds local variables to exception frames. - */ -export const localVariablesSyncIntegration = defineIntegration(_localVariablesSyncIntegration); diff --git a/packages/node/src/integrations/node-fetch/SentryNodeFetchInstrumentation.ts b/packages/node/src/integrations/node-fetch/SentryNodeFetchInstrumentation.ts index 6a8439a60b57..ffdd56bb2f8c 100644 --- a/packages/node/src/integrations/node-fetch/SentryNodeFetchInstrumentation.ts +++ b/packages/node/src/integrations/node-fetch/SentryNodeFetchInstrumentation.ts @@ -2,7 +2,6 @@ import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; import { InstrumentationBase } from '@opentelemetry/instrumentation'; import { LRUMap, SDK_VERSION, isTracingSuppressed } from '@sentry/core'; import * as diagch from 'diagnostics_channel'; -import { NODE_MAJOR, NODE_MINOR } from '../../nodeVersion'; import { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest, @@ -160,23 +159,11 @@ export class SentryNodeFetchInstrumentation extends InstrumentationBase void, ): void { - // `diagnostics_channel` had a ref counting bug until v18.19.0. - // https://github.com/nodejs/node/pull/47520 - const useNewSubscribe = NODE_MAJOR > 18 || (NODE_MAJOR === 18 && NODE_MINOR >= 19); - - let unsubscribe: () => void; - if (useNewSubscribe) { - diagch.subscribe?.(diagnosticChannel, onMessage); - unsubscribe = () => diagch.unsubscribe?.(diagnosticChannel, onMessage); - } else { - const channel = diagch.channel(diagnosticChannel); - channel.subscribe(onMessage); - unsubscribe = () => channel.unsubscribe(onMessage); - } + diagch.subscribe?.(diagnosticChannel, onMessage); this._channelSubs.push({ name: diagnosticChannel, - unsubscribe, + unsubscribe: () => diagch.unsubscribe?.(diagnosticChannel, onMessage), }); } diff --git a/packages/node/src/integrations/node-fetch/undici-instrumentation.ts b/packages/node/src/integrations/node-fetch/undici-instrumentation.ts index 89a754b36274..c20a0ef4ae13 100644 --- a/packages/node/src/integrations/node-fetch/undici-instrumentation.ts +++ b/packages/node/src/integrations/node-fetch/undici-instrumentation.ts @@ -116,19 +116,7 @@ function subscribeToChannel( diagnosticChannel: string, onMessage: (message: unknown, name: string | symbol) => void, ): void { - // `diagnostics_channel` had a ref counting bug until v18.19.0. - // https://github.com/nodejs/node/pull/47520 - const [major = 0, minor = 0] = process.version - .replace('v', '') - .split('.') - .map(n => Number(n)); - const useNewSubscribe = major > 18 || (major === 18 && minor >= 19); - - if (useNewSubscribe) { - _channelSubs.push(diagch.subscribe?.(diagnosticChannel, onMessage)); - } else { - _channelSubs.push(diagch.channel(diagnosticChannel).subscribe(onMessage)); - } + _channelSubs.push(diagch.subscribe?.(diagnosticChannel, onMessage)); } function parseRequestHeaders(request: UndiciRequest): Map { diff --git a/packages/node/src/integrations/pino.ts b/packages/node/src/integrations/pino.ts index b6b1c777ef30..89105bdaa0b6 100644 --- a/packages/node/src/integrations/pino.ts +++ b/packages/node/src/integrations/pino.ts @@ -232,7 +232,7 @@ interface PinoIntegrationFunction { * * If you disable automatic instrumentation with `autoInstrument: false`, you can mark specific loggers to be tracked with `pinoIntegration.trackLogger(logger)`. * - * Requires Pino >=v8.0.0 and Node >=20.6.0 or >=18.19.0 + * Requires Pino >=v8.0.0 */ export const pinoIntegration = Object.assign(_pinoIntegration, { trackLogger(logger: unknown): void { diff --git a/packages/node/src/integrations/spotlight.ts b/packages/node/src/integrations/spotlight.ts index 5e85bdb092e1..217ef197b135 100644 --- a/packages/node/src/integrations/spotlight.ts +++ b/packages/node/src/integrations/spotlight.ts @@ -36,8 +36,6 @@ const _spotlightIntegration = ((options: Partial = { * Use this integration to send errors and transactions to Spotlight. * * Learn more about spotlight at https://spotlightjs.com - * - * Important: This integration only works with Node 18 or newer. */ export const spotlightIntegration = defineIntegration(_spotlightIntegration); diff --git a/packages/node/src/integrations/tracing/redis/index.ts b/packages/node/src/integrations/tracing/redis/index.ts index 9d01332cf679..77bde6ca57ea 100644 --- a/packages/node/src/integrations/tracing/redis/index.ts +++ b/packages/node/src/integrations/tracing/redis/index.ts @@ -1,6 +1,5 @@ import type { IntegrationFn } from '@sentry/core'; import { defineIntegration, extendIntegration } from '@sentry/core'; -import * as dc from 'node:diagnostics_channel'; import { redisIntegration as redisChannelIntegration } from '@sentry/server-utils'; import { generateInstrumentOnce } from '../../../otel/instrument'; import { isDiagnosticsChannelInjectionEnabled } from '../../../sdk/diagnosticsChannelInjection'; @@ -35,9 +34,8 @@ export const instrumentRedis = Object.assign( (): void => { // When diagnostics-channel injection is opted in, orchestrion fully owns the older // ioredis (`<5.11.0`) and redis/node-redis (`<5.12.0`) ranges — commands, connect, and - // batches — so skip both OTel monkey-patches to avoid double instrumentation. On Node - // without `tracingChannel` (<18.19) orchestrion can't run, so keep the OTel patches there. - if (!isDiagnosticsChannelInjectionEnabled() || !dc.tracingChannel) { + // batches — so skip both OTel monkey-patches to avoid double instrumentation. + if (!isDiagnosticsChannelInjectionEnabled()) { instrumentIORedis(); instrumentRedisModule(); } diff --git a/packages/node/src/utils/detection.ts b/packages/node/src/utils/detection.ts index 43799c611782..98fcf3975609 100644 --- a/packages/node/src/utils/detection.ts +++ b/packages/node/src/utils/detection.ts @@ -1,6 +1,3 @@ -import { consoleSandbox } from '@sentry/core'; -import { NODE_MAJOR, NODE_MINOR } from '../nodeVersion'; - function isCjs(): boolean { /*! rollup-include-cjs-only */ return true; @@ -11,30 +8,9 @@ function isCjs(): boolean { /*! rollup-include-esm-only-end */ } -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; + return !isCjs(); } diff --git a/packages/node/test/integrations/localvariables.test.ts b/packages/node/test/integrations/localvariables.test.ts index 82e43ef34135..0b42e2f702e9 100644 --- a/packages/node/test/integrations/localvariables.test.ts +++ b/packages/node/test/integrations/localvariables.test.ts @@ -1,11 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createRateLimiter, filterFrameVariables } from '../../src/integrations/local-variables/common'; -import { createCallbackList } from '../../src/integrations/local-variables/local-variables-sync'; -import { NODE_MAJOR } from '../../src/nodeVersion'; -const describeIf = (condition: boolean) => (condition ? describe : describe.skip); - -describeIf(NODE_MAJOR >= 18)('LocalVariables', () => { +describe('LocalVariables', () => { beforeEach(() => { vi.useFakeTimers(); }); @@ -42,77 +38,6 @@ describeIf(NODE_MAJOR >= 18)('LocalVariables', () => { }); }); - describe('createCallbackList', () => { - it('Should call callbacks in reverse order', () => - new Promise(done => { - const log: number[] = []; - - const { add, next } = createCallbackList(n => { - expect(log).toEqual([5, 4, 3, 2, 1]); - expect(n).toBe(15); - done(); - }); - - add(n => { - log.push(1); - next(n + 1); - }); - - add(n => { - log.push(2); - next(n + 1); - }); - - add(n => { - log.push(3); - next(n + 1); - }); - - add(n => { - log.push(4); - next(n + 1); - }); - - add(n => { - log.push(5); - next(n + 11); - }); - - next(0); - })); - - it('only calls complete once even if multiple next', () => - new Promise(done => { - const { add, next } = createCallbackList(n => { - expect(n).toBe(1); - done(); - }); - - add(n => { - next(n + 1); - // We dont actually do this in our code... - next(n + 1); - }); - - next(0); - })); - - it('calls completed if added closure throws', () => - new Promise(done => { - const { add, next } = createCallbackList(n => { - expect(n).toBe(10); - done(); - }); - - add(n => { - throw new Error('test'); - next(n + 1); - }); - - next(10); - })); - }); - describe('rateLimiter', () => { it('calls disable if exceeded', () => new Promise(done => { diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index b8f31311f7b7..e758e5799bb0 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18.19.1" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json index fe8bab714e74..5d7810c30611 100644 --- a/packages/opentelemetry/package.json +++ b/packages/opentelemetry/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/profiling-node/package.json b/packages/profiling-node/package.json index fdeb64d30945..7ece3c425827 100644 --- a/packages/profiling-node/package.json +++ b/packages/profiling-node/package.json @@ -26,7 +26,7 @@ "sentry-prune-profiler-binaries": "scripts/prune-profiler-binaries.js" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "publishConfig": { "access": "public" diff --git a/packages/react-router/package.json b/packages/react-router/package.json index d2abc3eab12a..0108b4f650da 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=20" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/react/package.json b/packages/react/package.json index c0a9fd9c4113..5f9295db8479 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/remix/package.json b/packages/remix/package.json index 3aae87ea0539..92cabfe9a8dc 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -10,7 +10,7 @@ "sentry-upload-sourcemaps": "scripts/sentry-upload-sourcemaps.js" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build", diff --git a/packages/replay-canvas/package.json b/packages/replay-canvas/package.json index 61915f6b2645..6b57dbe06edd 100644 --- a/packages/replay-canvas/package.json +++ b/packages/replay-canvas/package.json @@ -64,7 +64,7 @@ "@sentry/core": "10.67.0" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "volta": { "extends": "../../package.json" diff --git a/packages/replay-internal/package.json b/packages/replay-internal/package.json index 6459bc993bd5..b46272836031 100644 --- a/packages/replay-internal/package.json +++ b/packages/replay-internal/package.json @@ -83,7 +83,7 @@ "@sentry/core": "10.67.0" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "volta": { "extends": "../../package.json" diff --git a/packages/replay-worker/package.json b/packages/replay-worker/package.json index 67b10318c6a7..fbfcb04a11c9 100644 --- a/packages/replay-worker/package.json +++ b/packages/replay-worker/package.json @@ -57,7 +57,7 @@ "fflate": "0.8.2" }, "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "volta": { "extends": "../../package.json" diff --git a/packages/server-utils/package.json b/packages/server-utils/package.json index 4b7c302aa376..3d0f564dc2a5 100644 --- a/packages/server-utils/package.json +++ b/packages/server-utils/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/solid/package.json b/packages/solid/package.json index 484401f88e93..64add39d2488 100644 --- a/packages/solid/package.json +++ b/packages/solid/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build", diff --git a/packages/solidstart/package.json b/packages/solidstart/package.json index ac54823eb596..d2a4196fc90c 100644 --- a/packages/solidstart/package.json +++ b/packages/solidstart/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18.19.1" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build", diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 77a8368f0138..4151002b92ac 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index b61b9df48341..dfb79075f0fb 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/tanstackstart-react/package.json b/packages/tanstackstart-react/package.json index a47644115ac4..e48b14426041 100644 --- a/packages/tanstackstart-react/package.json +++ b/packages/tanstackstart-react/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "main": "build/cjs/index.server.js", "module": "build/esm/index.server.js", diff --git a/packages/types/package.json b/packages/types/package.json index a6f5d8bc8f34..6c5e85858c31 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/vercel-edge/package.json b/packages/vercel-edge/package.json index a6e04692401c..eafcdfdd4704 100644 --- a/packages/vercel-edge/package.json +++ b/packages/vercel-edge/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build" diff --git a/packages/vue/package.json b/packages/vue/package.json index 58dacc73417a..fa22b3bcd6b0 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build", diff --git a/packages/wasm/package.json b/packages/wasm/package.json index a2a33011f48b..367890d8b073 100644 --- a/packages/wasm/package.json +++ b/packages/wasm/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0" }, "files": [ "/build/npm" diff --git a/scripts/ci-unit-tests.ts b/scripts/ci-unit-tests.ts index 8d4032f62b5a..7bb6f6a4d8d2 100644 --- a/scripts/ci-unit-tests.ts +++ b/scripts/ci-unit-tests.ts @@ -4,7 +4,6 @@ import * as path from 'path'; const UNIT_TEST_ENV = process.env.UNIT_TEST_ENV as 'node' | 'browser' | undefined; const RUN_AFFECTED = process.argv.includes('--affected'); -const NODE_VERSION = process.env.NODE_VERSION as '18' | '20' | '22' | '24'; // These packages are tested separately in CI, so no need to run them here const DEFAULT_SKIP_PACKAGES = ['@sentry/bun', '@sentry/deno']; @@ -27,9 +26,6 @@ const BROWSER_TEST_PACKAGES = [ '@sentry/wasm', ]; -// Packages that cannot run in Node 18 -const SKIP_NODE_18_PACKAGES = ['@sentry/react-router']; - function getAllPackages(): string[] { const { workspaces }: { workspaces: string[] } = JSON.parse( fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'), @@ -60,10 +56,6 @@ function runTests(): void { }); } else if (UNIT_TEST_ENV === 'node') { BROWSER_TEST_PACKAGES.forEach(pkg => ignores.add(pkg)); - - if (NODE_VERSION === '18') { - SKIP_NODE_18_PACKAGES.forEach(pkg => ignores.add(pkg)); - } } if (RUN_AFFECTED) {