diff --git a/.size-limit.js b/.size-limit.js
index b4819fc83126..2d07afde52ab 100644
--- a/.size-limit.js
+++ b/.size-limit.js
@@ -5,14 +5,14 @@ module.exports = [
// Browser SDK (ESM)
{
name: '@sentry/browser',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init'),
gzip: true,
limit: '25 KB',
},
{
name: '@sentry/browser - with treeshaking flags',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init'),
gzip: true,
limit: '24.1 KB',
@@ -35,28 +35,28 @@ module.exports = [
},
{
name: '@sentry/browser (incl. Tracing)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'browserTracingIntegration'),
gzip: true,
limit: '41.3 KB',
},
{
name: '@sentry/browser (incl. Tracing, Profiling)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'browserTracingIntegration', 'browserProfilingIntegration'),
gzip: true,
limit: '48 KB',
},
{
name: '@sentry/browser (incl. Tracing, Replay)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'browserTracingIntegration', 'replayIntegration'),
gzip: true,
limit: '80 KB',
},
{
name: '@sentry/browser (incl. Tracing, Replay) - with treeshaking flags',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'browserTracingIntegration', 'replayIntegration'),
gzip: true,
limit: '75 KB',
@@ -79,35 +79,35 @@ module.exports = [
},
{
name: '@sentry/browser (incl. Tracing, Replay with Canvas)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'replayCanvasIntegration'),
gzip: true,
limit: '85 KB',
},
{
name: '@sentry/browser (incl. Tracing, Replay, Feedback)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'feedbackIntegration'),
gzip: true,
limit: '97 KB',
},
{
name: '@sentry/browser (incl. Feedback)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'feedbackIntegration'),
gzip: true,
limit: '42 KB',
},
{
name: '@sentry/browser (incl. sendFeedback)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'sendFeedback'),
gzip: true,
limit: '30 KB',
},
{
name: '@sentry/browser (incl. FeedbackAsync)',
- path: 'packages/browser/build/npm/esm/index.js',
+ path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'feedbackAsyncIntegration'),
gzip: true,
limit: '35 KB',
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f98b440d47d..d5cf4d9b810f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,23 @@
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
+## 10.25.0
+
+- feat(browser): Include Spotlight in development bundles ([#18078](https://github.com/getsentry/sentry-javascript/pull/18078))
+- feat(cloudflare): Add metrics exports ([#18147](https://github.com/getsentry/sentry-javascript/pull/18147))
+- feat(core): Truncate request string inputs in OpenAI integration ([#18136](https://github.com/getsentry/sentry-javascript/pull/18136))
+- feat(metrics): Add missing metric node exports ([#18149](https://github.com/getsentry/sentry-javascript/pull/18149))
+- feat(node): Add `maxCacheKeyLength` to Redis integration (remove truncation) ([#18045](https://github.com/getsentry/sentry-javascript/pull/18045))
+- feat(vercel-edge): Add metrics export ([#18148](https://github.com/getsentry/sentry-javascript/pull/18148))
+- fix(core): Only consider exception mechanism when updating session status from event with exceptions ([#18137](https://github.com/getsentry/sentry-javascript/pull/18137))
+- ref(browser): Remove truncation when not needed ([#18051](https://github.com/getsentry/sentry-javascript/pull/18051))
+
+
+ Internal Changes
+
+- chore(build): Fix incorrect versions after merge ([#18154](https://github.com/getsentry/sentry-javascript/pull/18154))
+
+
## 10.24.0
### Important Changes
diff --git a/dev-packages/browser-integration-tests/utils/generatePlugin.ts b/dev-packages/browser-integration-tests/utils/generatePlugin.ts
index 0a90b5e2be23..6e3ef99aa7ea 100644
--- a/dev-packages/browser-integration-tests/utils/generatePlugin.ts
+++ b/dev-packages/browser-integration-tests/utils/generatePlugin.ts
@@ -46,8 +46,8 @@ const IMPORTED_INTEGRATION_CDN_BUNDLE_PATHS: Record = {
const BUNDLE_PATHS: Record> = {
browser: {
- cjs: 'build/npm/cjs/index.js',
- esm: 'build/npm/esm/index.js',
+ cjs: 'build/npm/cjs/prod/index.js',
+ esm: 'build/npm/esm/prod/index.js',
bundle: 'build/bundles/bundle.js',
bundle_min: 'build/bundles/bundle.min.js',
bundle_replay: 'build/bundles/bundle.replay.js',
@@ -67,8 +67,8 @@ const BUNDLE_PATHS: Record> = {
loader_tracing_replay: 'build/bundles/bundle.tracing.replay.debug.min.js',
},
integrations: {
- cjs: 'build/npm/cjs/index.js',
- esm: 'build/npm/esm/index.js',
+ cjs: 'build/npm/cjs/prod/index.js',
+ esm: 'build/npm/esm/prod/index.js',
bundle: 'build/bundles/[INTEGRATION_NAME].js',
bundle_min: 'build/bundles/[INTEGRATION_NAME].min.js',
},
@@ -77,8 +77,8 @@ const BUNDLE_PATHS: Record> = {
bundle_min: 'build/bundles/[INTEGRATION_NAME].min.js',
},
wasm: {
- cjs: 'build/npm/cjs/index.js',
- esm: 'build/npm/esm/index.js',
+ cjs: 'build/npm/cjs/prod/index.js',
+ esm: 'build/npm/esm/prod/index.js',
bundle: 'build/bundles/wasm.js',
bundle_min: 'build/bundles/wasm.min.js',
},
diff --git a/dev-packages/bundler-tests/.eslintrc.js b/dev-packages/bundler-tests/.eslintrc.js
new file mode 100644
index 000000000000..a65cf78e0b57
--- /dev/null
+++ b/dev-packages/bundler-tests/.eslintrc.js
@@ -0,0 +1,6 @@
+module.exports = {
+ extends: ['../../.eslintrc.js'],
+ parserOptions: {
+ sourceType: 'module',
+ },
+};
diff --git a/dev-packages/bundler-tests/fixtures/basic/index.html b/dev-packages/bundler-tests/fixtures/basic/index.html
new file mode 100644
index 000000000000..40e5dbc0642e
--- /dev/null
+++ b/dev-packages/bundler-tests/fixtures/basic/index.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/dev-packages/bundler-tests/fixtures/basic/index.js b/dev-packages/bundler-tests/fixtures/basic/index.js
new file mode 100644
index 000000000000..f3d47c97f7a2
--- /dev/null
+++ b/dev-packages/bundler-tests/fixtures/basic/index.js
@@ -0,0 +1,5 @@
+import { init } from '@sentry/browser';
+
+init({
+ dsn: 'https://00000000000000000000000000000000@o000000.ingest.sentry.io/0000000',
+});
diff --git a/dev-packages/bundler-tests/package.json b/dev-packages/bundler-tests/package.json
new file mode 100644
index 000000000000..1e61939cac5f
--- /dev/null
+++ b/dev-packages/bundler-tests/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "@sentry-internal/bundler-tests",
+ "version": "10.24.0",
+ "description": "Bundler tests for Sentry Browser SDK",
+ "repository": "git://github.com/getsentry/sentry-javascript.git",
+ "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/bundler-tests",
+ "author": "Sentry",
+ "license": "MIT",
+ "private": true,
+ "main": "./index.mjs",
+ "scripts": {
+ "test": "vitest run"
+ },
+ "dependencies": {
+ "@sentry/browser": "10.24.0",
+ "webpack": "^5.0.0",
+ "rollup": "^4.0.0",
+ "vite": "^5.0.0",
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "vitest": "^3.2.4"
+ },
+ "volta": {
+ "extends": "../../package.json"
+ },
+ "type": "module"
+}
diff --git a/dev-packages/bundler-tests/tests/bundling.test.ts b/dev-packages/bundler-tests/tests/bundling.test.ts
new file mode 100644
index 000000000000..2cc8113ca83b
--- /dev/null
+++ b/dev-packages/bundler-tests/tests/bundling.test.ts
@@ -0,0 +1,144 @@
+import { describe, expect, beforeAll, test } from 'vitest';
+import * as path from 'node:path';
+import * as fs from 'node:fs';
+import { fileURLToPath } from 'node:url';
+
+import webpack from 'webpack';
+import { rollup } from 'rollup';
+import { build as viteBuild } from 'vite';
+import nodeResolve from '@rollup/plugin-node-resolve';
+
+// Helper functions
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+function distDir(name: string): string {
+ const dir = path.join(__dirname, '..', 'dist', name);
+ if (!fs.existsSync(dir)) {
+ fs.mkdirSync(dir, { recursive: true });
+ }
+ return dir;
+}
+
+function rimraf(dir: string): void {
+ if (fs.existsSync(dir)) {
+ fs.rmSync(dir, { recursive: true, force: true });
+ }
+}
+
+function readAllJs(outDir: string): string {
+ let contents = '';
+ const stack = [outDir];
+ while (stack.length) {
+ const current = stack.pop()!;
+ for (const entry of fs.readdirSync(current)) {
+ const full = path.join(current, entry);
+ const stat = fs.statSync(full);
+ if (stat.isDirectory()) {
+ stack.push(full);
+ } else if (entry.endsWith('.js') || entry.endsWith('.mjs')) {
+ contents += fs.readFileSync(full, 'utf8');
+ }
+ }
+ }
+ return contents;
+}
+
+function fixtureEntry(name: string): string {
+ return path.resolve(__dirname, '..', 'fixtures', name, 'index.js');
+}
+
+function rootDir(): string {
+ return path.join(__dirname, '../../..');
+}
+
+const SPOTLIGHT_URL = 'localhost:8969';
+
+type BundleMode = 'development' | 'production';
+
+function bundleWithWebpack(mode: BundleMode): Promise {
+ return new Promise((resolve, reject) => {
+ const outDir = distDir(`webpack-${mode}`);
+ rimraf(outDir);
+ const compiler = webpack({
+ mode,
+ entry: fixtureEntry('basic'),
+ output: { path: outDir, filename: 'bundle.js' },
+ });
+ compiler?.run((err: Error | null | undefined, stats: webpack.Stats | undefined) => {
+ try {
+ if (err) throw err;
+ if (stats?.hasErrors()) {
+ throw new Error(stats.toString('errors-only'));
+ }
+ resolve(readAllJs(outDir));
+ } catch (e) {
+ reject(e);
+ } finally {
+ compiler.close(() => {});
+ }
+ });
+ });
+}
+
+async function bundleWithRollup(mode: BundleMode): Promise {
+ const outDir = distDir(`rollup-${mode}`);
+ rimraf(outDir);
+
+ const bundle = await rollup({
+ input: fixtureEntry('basic'),
+ plugins: [
+ nodeResolve({
+ // There should really be a default where these get specified automatically
+ exportConditions: [mode === 'production' ? 'production' : 'development'],
+ }),
+ ],
+ });
+ await bundle.write({ dir: outDir, format: 'esm' });
+ await bundle.close();
+ return readAllJs(outDir);
+}
+
+async function bundleWithVite(mode: BundleMode): Promise {
+ const outDir = distDir(`vite-${mode}`);
+ rimraf(outDir);
+
+ // In Vitest, NODE_ENV is always 'test', so we need to override it here
+ const prev = process.env.NODE_ENV;
+ process.env.NODE_ENV = mode;
+
+ await viteBuild({
+ mode,
+ root: path.dirname(fixtureEntry('basic')),
+ build: { outDir, minify: mode === 'production' },
+ });
+
+ process.env.NODE_ENV = prev;
+
+ return readAllJs(outDir);
+}
+
+describe('spotlight', () => {
+ beforeAll(() => {
+ const distRoot = path.join(rootDir(), 'dist');
+ rimraf(distRoot);
+ });
+
+ const cases: [string, (mode: BundleMode) => Promise][] = [
+ ['webpack', bundleWithWebpack],
+ ['rollup', bundleWithRollup],
+ ['vite', bundleWithVite],
+ ];
+
+ for (const [name, bundler] of cases) {
+ test(`${name} development bundle contains spotlight`, async () => {
+ const code = await bundler('development');
+ expect(code).toContain(SPOTLIGHT_URL);
+ });
+
+ test(`${name} production bundle does not contain spotlight`, async () => {
+ const code = await bundler('production');
+ expect(code).not.toContain(SPOTLIGHT_URL);
+ });
+ }
+});
diff --git a/dev-packages/bundler-tests/vitest.config.mjs b/dev-packages/bundler-tests/vitest.config.mjs
new file mode 100644
index 000000000000..8baf9e1fbf68
--- /dev/null
+++ b/dev-packages/bundler-tests/vitest.config.mjs
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ include: ['tests/**/*.test.*s'],
+ timeout: 10000,
+ hookTimeout: 10000,
+ },
+});
diff --git a/dev-packages/e2e-tests/test-applications/node-exports-test-app/scripts/consistentExports.ts b/dev-packages/e2e-tests/test-applications/node-exports-test-app/scripts/consistentExports.ts
index ee4b7ac35421..17c6f714c499 100644
--- a/dev-packages/e2e-tests/test-applications/node-exports-test-app/scripts/consistentExports.ts
+++ b/dev-packages/e2e-tests/test-applications/node-exports-test-app/scripts/consistentExports.ts
@@ -41,8 +41,6 @@ const DEPENDENTS: Dependent[] = [
ignoreExports: [
// Not needed for Astro
'setupFastifyErrorHandler',
- // Todo(metrics): Add metrics exports for beta
- 'metrics',
],
},
{
@@ -56,8 +54,6 @@ const DEPENDENTS: Dependent[] = [
'childProcessIntegration',
'systemErrorIntegration',
'pinoIntegration',
- // Todo(metrics): Add metrics exports for beta
- 'metrics',
],
},
{
@@ -79,8 +75,6 @@ const DEPENDENTS: Dependent[] = [
ignoreExports: [
// Not needed for Serverless
'setupFastifyErrorHandler',
- // Todo(metrics): Add metrics exports for beta
- 'metrics',
],
},
{
@@ -90,8 +84,6 @@ const DEPENDENTS: Dependent[] = [
ignoreExports: [
// Not needed for Serverless
'setupFastifyErrorHandler',
- // Todo(metrics): Add metrics exports for beta
- 'metrics',
],
},
{
diff --git a/dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation.mjs b/dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation-completions.mjs
similarity index 97%
rename from dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation.mjs
rename to dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation-completions.mjs
index 5623d3763657..96684ed9ec4f 100644
--- a/dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation.mjs
+++ b/dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation-completions.mjs
@@ -12,7 +12,7 @@ class MockOpenAI {
await new Promise(resolve => setTimeout(resolve, 10));
return {
- id: 'chatcmpl-truncation-test',
+ id: 'chatcmpl-completions-truncation-test',
object: 'chat.completion',
created: 1677652288,
model: params.model,
diff --git a/dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation-responses.mjs b/dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation-responses.mjs
new file mode 100644
index 000000000000..aebd3341eb33
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/openai/scenario-message-truncation-responses.mjs
@@ -0,0 +1,93 @@
+import { instrumentOpenAiClient } from '@sentry/core';
+import * as Sentry from '@sentry/node';
+
+class MockOpenAI {
+ constructor(config) {
+ this.apiKey = config.apiKey;
+
+ this.responses = {
+ create: async params => {
+ // Simulate processing time
+ await new Promise(resolve => setTimeout(resolve, 10));
+
+ return {
+ id: 'chatcmpl-responses-truncation-test',
+ object: 'response',
+ created_at: 1677652288,
+ status: 'completed',
+ error: null,
+ incomplete_details: null,
+ instructions: null,
+ max_output_tokens: null,
+ model: params.model,
+ output: [
+ {
+ type: 'message',
+ id: 'message-123',
+ status: 'completed',
+ role: 'assistant',
+ content: [
+ {
+ type: 'output_text',
+ text: 'Response to truncated messages',
+ annotations: [],
+ },
+ ],
+ },
+ ],
+ parallel_tool_calls: true,
+ previous_response_id: null,
+ reasoning: {
+ effort: null,
+ summary: null,
+ },
+ store: true,
+ temperature: params.temperature,
+ text: {
+ format: {
+ type: 'text',
+ },
+ },
+ tool_choice: 'auto',
+ tools: [],
+ top_p: 1.0,
+ truncation: 'disabled',
+ usage: {
+ input_tokens: 10,
+ input_tokens_details: {
+ cached_tokens: 0,
+ },
+ output_tokens: 15,
+ output_tokens_details: {
+ reasoning_tokens: 0,
+ },
+ total_tokens: 25,
+ },
+ user: null,
+ metadata: {},
+ };
+ },
+ };
+ }
+}
+
+async function run() {
+ await Sentry.startSpan({ op: 'function', name: 'main' }, async () => {
+ const mockClient = new MockOpenAI({
+ apiKey: 'mock-api-key',
+ });
+
+ const client = instrumentOpenAiClient(mockClient);
+
+ // Create 1 large message that gets truncated to fit within the 20KB limit
+ const largeContent = 'A'.repeat(25000) + 'B'.repeat(25000); // ~50KB gets truncated to include only As
+
+ await client.responses.create({
+ model: 'gpt-3.5-turbo',
+ input: largeContent,
+ temperature: 0.7,
+ });
+ });
+}
+
+run();
diff --git a/dev-packages/node-integration-tests/suites/tracing/openai/test.ts b/dev-packages/node-integration-tests/suites/tracing/openai/test.ts
index 218e3c7ee61f..5cbb27df73bf 100644
--- a/dev-packages/node-integration-tests/suites/tracing/openai/test.ts
+++ b/dev-packages/node-integration-tests/suites/tracing/openai/test.ts
@@ -400,7 +400,7 @@ describe('OpenAI integration', () => {
createEsmAndCjsTests(
__dirname,
- 'scenario-message-truncation.mjs',
+ 'scenario-message-truncation-completions.mjs',
'instrument-with-pii.mjs',
(createRunner, test) => {
test('truncates messages when they exceed byte limit - keeps only last message and crops it', async () => {
@@ -433,4 +433,40 @@ describe('OpenAI integration', () => {
});
},
);
+
+ createEsmAndCjsTests(
+ __dirname,
+ 'scenario-message-truncation-responses.mjs',
+ 'instrument-with-pii.mjs',
+ (createRunner, test) => {
+ test('truncates string inputs when they exceed byte limit', async () => {
+ await createRunner()
+ .ignore('event')
+ .expect({
+ transaction: {
+ transaction: 'main',
+ spans: expect.arrayContaining([
+ expect.objectContaining({
+ data: expect.objectContaining({
+ 'gen_ai.operation.name': 'responses',
+ 'sentry.op': 'gen_ai.responses',
+ 'sentry.origin': 'auto.ai.openai',
+ 'gen_ai.system': 'openai',
+ 'gen_ai.request.model': 'gpt-3.5-turbo',
+ // Messages should be present and should include truncated string input (contains only As)
+ 'gen_ai.request.messages': expect.stringMatching(/^A+$/),
+ }),
+ description: 'responses gpt-3.5-turbo',
+ op: 'gen_ai.responses',
+ origin: 'auto.ai.openai',
+ status: 'ok',
+ }),
+ ]),
+ },
+ })
+ .start()
+ .completed();
+ });
+ },
+ );
});
diff --git a/dev-packages/rollup-utils/bundleHelpers.mjs b/dev-packages/rollup-utils/bundleHelpers.mjs
index b353eebaa214..8dd2ebd21999 100644
--- a/dev-packages/rollup-utils/bundleHelpers.mjs
+++ b/dev-packages/rollup-utils/bundleHelpers.mjs
@@ -11,7 +11,6 @@ import {
makeCleanupPlugin,
makeCommonJSPlugin,
makeIsDebugBuildPlugin,
- makeJsonPlugin,
makeLicensePlugin,
makeNodeResolvePlugin,
makeRrwebBuildPlugin,
@@ -20,6 +19,7 @@ import {
makeTerserPlugin,
} from './plugins/index.mjs';
import { mergePlugins } from './utils.mjs';
+import { makeProductionReplacePlugin } from './plugins/npmPlugins.mjs';
const BUNDLE_VARIANTS = ['.js', '.min.js', '.debug.min.js'];
@@ -35,14 +35,13 @@ export function makeBaseBundleConfig(options) {
excludeIframe: false,
excludeShadowDom: false,
});
+ const productionReplacePlugin = makeProductionReplacePlugin();
// The `commonjs` plugin is the `esModuleInterop` of the bundling world. When used with `transformMixedEsModules`, it
// will include all dependencies, imported or required, in the final bundle. (Without it, CJS modules aren't included
// at all, and without `transformMixedEsModules`, they're only included if they're imported, not if they're required.)
const commonJSPlugin = makeCommonJSPlugin({ transformMixedEsModules: true });
- const jsonPlugin = makeJsonPlugin();
-
// used by `@sentry/browser`
const standAloneBundleConfig = {
output: {
@@ -119,7 +118,7 @@ export function makeBaseBundleConfig(options) {
strict: false,
esModule: false,
},
- plugins: [sucrasePlugin, nodeResolvePlugin, cleanupPlugin],
+ plugins: [productionReplacePlugin, sucrasePlugin, nodeResolvePlugin, cleanupPlugin],
treeshake: 'smallest',
};
diff --git a/dev-packages/rollup-utils/npmHelpers.mjs b/dev-packages/rollup-utils/npmHelpers.mjs
index cff113d622d6..d5f7428b992d 100644
--- a/dev-packages/rollup-utils/npmHelpers.mjs
+++ b/dev-packages/rollup-utils/npmHelpers.mjs
@@ -16,6 +16,7 @@ import {
makeCleanupPlugin,
makeDebugBuildStatementReplacePlugin,
makeNodeResolvePlugin,
+ makeProductionReplacePlugin,
makeRrwebBuildPlugin,
makeSucrasePlugin,
} from './plugins/index.mjs';
@@ -114,22 +115,47 @@ export function makeBaseNPMConfig(options = {}) {
}
export function makeNPMConfigVariants(baseConfig, options = {}) {
- const { emitEsm = true, emitCjs = true } = options;
+ const { emitEsm = true, emitCjs = true, splitDevProd = false } = options;
const variantSpecificConfigs = [];
if (emitCjs) {
- variantSpecificConfigs.push({ output: { format: 'cjs', dir: path.join(baseConfig.output.dir, 'cjs') } });
+ if (splitDevProd) {
+ variantSpecificConfigs.push({ output: { format: 'cjs', dir: path.join(baseConfig.output.dir, 'cjs/dev') } });
+ variantSpecificConfigs.push({
+ output: { format: 'cjs', dir: path.join(baseConfig.output.dir, 'cjs/prod') },
+ plugins: [makeProductionReplacePlugin()],
+ });
+ } else {
+ variantSpecificConfigs.push({ output: { format: 'cjs', dir: path.join(baseConfig.output.dir, 'cjs') } });
+ }
}
if (emitEsm) {
- variantSpecificConfigs.push({
- output: {
- format: 'esm',
- dir: path.join(baseConfig.output.dir, 'esm'),
- plugins: [makePackageNodeEsm()],
- },
- });
+ if (splitDevProd) {
+ variantSpecificConfigs.push({
+ output: {
+ format: 'esm',
+ dir: path.join(baseConfig.output.dir, 'esm/dev'),
+ plugins: [makePackageNodeEsm()],
+ },
+ });
+ variantSpecificConfigs.push({
+ output: {
+ format: 'esm',
+ dir: path.join(baseConfig.output.dir, 'esm/prod'),
+ plugins: [makeProductionReplacePlugin(), makePackageNodeEsm()],
+ },
+ });
+ } else {
+ variantSpecificConfigs.push({
+ output: {
+ format: 'esm',
+ dir: path.join(baseConfig.output.dir, 'esm'),
+ plugins: [makePackageNodeEsm()],
+ },
+ });
+ }
}
return variantSpecificConfigs.map(variant => deepMerge(baseConfig, variant));
diff --git a/dev-packages/rollup-utils/plugins/npmPlugins.mjs b/dev-packages/rollup-utils/plugins/npmPlugins.mjs
index 8c7e0ff10a80..7f08873f1c80 100644
--- a/dev-packages/rollup-utils/plugins/npmPlugins.mjs
+++ b/dev-packages/rollup-utils/plugins/npmPlugins.mjs
@@ -125,6 +125,24 @@ export function makeDebugBuildStatementReplacePlugin() {
});
}
+export function makeProductionReplacePlugin() {
+ const pattern = /\/\* rollup-include-development-only \*\/[\s\S]*?\/\* rollup-include-development-only-end \*\/\s*/g;
+
+ function stripDevBlocks(code) {
+ if (!code) return null;
+ if (!code.includes('rollup-include-development-only')) return null;
+ const replaced = code.replace(pattern, '');
+ return { code: replaced, map: null };
+ }
+
+ return {
+ name: 'remove-dev-mode-blocks',
+ renderChunk(code) {
+ return stripDevBlocks(code);
+ },
+ };
+}
+
/**
* Creates a plugin to replace build flags of rrweb with either a constant (if passed true/false) or with a safe statement that:
* a) evaluates to `true`
diff --git a/dev-packages/rollup-utils/utils.mjs b/dev-packages/rollup-utils/utils.mjs
index 94b8c4483c23..b687ff9993c4 100644
--- a/dev-packages/rollup-utils/utils.mjs
+++ b/dev-packages/rollup-utils/utils.mjs
@@ -21,7 +21,16 @@ export function mergePlugins(pluginsA, pluginsB) {
// here.
// Additionally, the excludeReplay plugin must run before TS/Sucrase so that we can eliminate the replay code
// before anything is type-checked (TS-only) and transpiled.
- const order = ['excludeReplay', 'typescript', 'sucrase', '...', 'terser', 'license', 'output-base64-worker-script'];
+ const order = [
+ 'remove-dev-mode-blocks',
+ 'excludeReplay',
+ 'typescript',
+ 'sucrase',
+ '...',
+ 'terser',
+ 'license',
+ 'output-base64-worker-script',
+ ];
const sortKeyA = order.includes(a.name) ? a.name : '...';
const sortKeyB = order.includes(b.name) ? b.name : '...';
diff --git a/package.json b/package.json
index 1fd6eb062564..298e17031240 100644
--- a/package.json
+++ b/package.json
@@ -100,7 +100,8 @@
"dev-packages/clear-cache-gh-action",
"dev-packages/external-contributor-gh-action",
"dev-packages/rollup-utils",
- "dev-packages/node-overhead-gh-action"
+ "dev-packages/node-overhead-gh-action",
+ "dev-packages/bundler-tests"
],
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
diff --git a/packages/astro/src/index.server.ts b/packages/astro/src/index.server.ts
index 69ca79e04a17..1774f597af43 100644
--- a/packages/astro/src/index.server.ts
+++ b/packages/astro/src/index.server.ts
@@ -162,6 +162,7 @@ export {
statsigIntegration,
unleashIntegration,
growthbookIntegration,
+ metrics,
} from '@sentry/node';
export { init } from './server/sdk';
diff --git a/packages/aws-serverless/src/index.ts b/packages/aws-serverless/src/index.ts
index da0393d9b0e9..586babab40ee 100644
--- a/packages/aws-serverless/src/index.ts
+++ b/packages/aws-serverless/src/index.ts
@@ -148,6 +148,7 @@ export {
statsigIntegration,
unleashIntegration,
growthbookIntegration,
+ metrics,
} from '@sentry/node';
export {
diff --git a/packages/browser-utils/src/metrics/lcp.ts b/packages/browser-utils/src/metrics/lcp.ts
index 5f84f1782041..a6410ac08580 100644
--- a/packages/browser-utils/src/metrics/lcp.ts
+++ b/packages/browser-utils/src/metrics/lcp.ts
@@ -77,8 +77,7 @@ export function _sendStandaloneLcpSpan(
entry.element && (attributes['lcp.element'] = htmlTreeAsString(entry.element));
entry.id && (attributes['lcp.id'] = entry.id);
- // Trim URL to the first 200 characters.
- entry.url && (attributes['lcp.url'] = entry.url.trim().slice(0, 200));
+ entry.url && (attributes['lcp.url'] = entry.url);
// loadTime is the time of LCP that's related to receiving the LCP element response..
entry.loadTime != null && (attributes['lcp.loadTime'] = entry.loadTime);
diff --git a/packages/browser/package.json b/packages/browser/package.json
index 5c07b30eaab8..9ac303dbbd95 100644
--- a/packages/browser/package.json
+++ b/packages/browser/package.json
@@ -12,19 +12,24 @@
"files": [
"/build/npm"
],
- "main": "build/npm/cjs/index.js",
- "module": "build/npm/esm/index.js",
+ "main": "build/npm/cjs/prod/index.js",
+ "module": "build/npm/esm/prod/index.js",
"types": "build/npm/types/index.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
- "import": {
- "types": "./build/npm/types/index.d.ts",
- "default": "./build/npm/esm/index.js"
+ "types": "./build/npm/types/index.d.ts",
+ "development": {
+ "import": "./build/npm/esm/dev/index.js",
+ "require": "./build/npm/cjs/dev/index.js"
},
- "require": {
- "types": "./build/npm/types/index.d.ts",
- "default": "./build/npm/cjs/index.js"
+ "production": {
+ "import": "./build/npm/esm/prod/index.js",
+ "require": "./build/npm/cjs/prod/index.js"
+ },
+ "default": {
+ "import": "./build/npm/esm/prod/index.js",
+ "require": "./build/npm/cjs/prod/index.js"
}
}
},
@@ -67,7 +72,7 @@
"clean": "rimraf build coverage .rpt2_cache sentry-browser-*.tgz",
"fix": "eslint . --format stylish --fix",
"lint": "eslint . --format stylish",
- "lint:es-compatibility": "es-check es2020 ./build/{bundles,npm/cjs}/*.js && es-check es2020 ./build/npm/esm/*.js --module",
+ "lint:es-compatibility": "es-check es2020 ./build/{bundles,npm/cjs/prod}/*.js && es-check es2020 ./build/npm/esm/prod/*.js --module",
"size:check": "cat build/bundles/bundle.min.js | gzip -9 | wc -c | awk '{$1=$1/1024; print \"ES2017: \",$1,\"kB\";}'",
"test": "vitest run",
"test:watch": "vitest --watch",
diff --git a/packages/browser/rollup.npm.config.mjs b/packages/browser/rollup.npm.config.mjs
index 00251eea81fd..40e3cbff5906 100644
--- a/packages/browser/rollup.npm.config.mjs
+++ b/packages/browser/rollup.npm.config.mjs
@@ -16,4 +16,5 @@ export default makeNPMConfigVariants(
},
},
}),
+ { splitDevProd: true },
);
diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts
index dddaa440b198..ea55174f340c 100644
--- a/packages/browser/src/client.ts
+++ b/packages/browser/src/client.ts
@@ -63,6 +63,18 @@ type BrowserSpecificOptions = BrowserClientReplayOptions &
* @default false
*/
propagateTraceparent?: boolean;
+
+ /**
+ * If you use Spotlight by Sentry during development, use
+ * this option to forward captured Sentry events to Spotlight.
+ *
+ * Either set it to true, or provide a specific Spotlight Sidecar URL.
+ *
+ * More details: https://spotlightjs.com/
+ *
+ * IMPORTANT: Only set this option to `true` while developing, not in production!
+ */
+ spotlight?: boolean | string;
};
/**
* Configuration options for the Sentry Browser SDK.
diff --git a/packages/browser/src/integrations/globalhandlers.ts b/packages/browser/src/integrations/globalhandlers.ts
index aa7b2fa9e412..6bada802b98e 100644
--- a/packages/browser/src/integrations/globalhandlers.ts
+++ b/packages/browser/src/integrations/globalhandlers.ts
@@ -217,5 +217,5 @@ function getFilenameFromUrl(url: string | undefined): string | undefined {
return ``;
}
- return url.slice(0, 1024);
+ return url; // it's fine to not truncate it as it's not put in a regex (https://codeql.github.com/codeql-query-help/javascript/js-polynomial-redos)
}
diff --git a/packages/browser/src/sdk.ts b/packages/browser/src/sdk.ts
index 7b5d67c636ae..800c1b701352 100644
--- a/packages/browser/src/sdk.ts
+++ b/packages/browser/src/sdk.ts
@@ -15,6 +15,7 @@ import { browserSessionIntegration } from './integrations/browsersession';
import { globalHandlersIntegration } from './integrations/globalhandlers';
import { httpContextIntegration } from './integrations/httpcontext';
import { linkedErrorsIntegration } from './integrations/linkederrors';
+import { spotlightBrowserIntegration } from './integrations/spotlight';
import { defaultStackParser } from './stack-parsers';
import { makeFetchTransport } from './transports/fetch';
import { checkAndWarnIfIsEmbeddedBrowserExtension } from './utils/detectBrowserExtension';
@@ -90,14 +91,26 @@ export function init(options: BrowserOptions = {}): Client | undefined {
const shouldDisableBecauseIsBrowserExtenstion =
!options.skipBrowserExtensionCheck && checkAndWarnIfIsEmbeddedBrowserExtension();
+ let defaultIntegrations =
+ options.defaultIntegrations == null ? getDefaultIntegrations(options) : options.defaultIntegrations;
+
+ /* rollup-include-development-only */
+ if (options.spotlight) {
+ if (!defaultIntegrations) {
+ defaultIntegrations = [];
+ }
+ const args = typeof options.spotlight === 'string' ? { sidecarUrl: options.spotlight } : undefined;
+ defaultIntegrations.push(spotlightBrowserIntegration(args));
+ }
+ /* rollup-include-development-only-end */
+
const clientOptions: BrowserClientOptions = {
...options,
enabled: shouldDisableBecauseIsBrowserExtenstion ? false : options.enabled,
stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
integrations: getIntegrationsToSetup({
integrations: options.integrations,
- defaultIntegrations:
- options.defaultIntegrations == null ? getDefaultIntegrations(options) : options.defaultIntegrations,
+ defaultIntegrations,
}),
transport: options.transport || makeFetchTransport,
};
diff --git a/packages/bun/src/index.ts b/packages/bun/src/index.ts
index 33af15790191..813e087dc2d2 100644
--- a/packages/bun/src/index.ts
+++ b/packages/bun/src/index.ts
@@ -16,6 +16,7 @@ export type {
Thread,
User,
FeatureFlagsIntegration,
+ Metric,
} from '@sentry/core';
export {
@@ -164,6 +165,7 @@ export {
OpenFeatureIntegrationHook,
statsigIntegration,
unleashIntegration,
+ metrics,
} from '@sentry/node';
export {
diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts
index a6aa7ffc8d9a..36de54816030 100644
--- a/packages/cloudflare/src/index.ts
+++ b/packages/cloudflare/src/index.ts
@@ -16,6 +16,7 @@ export type {
Stacktrace,
Thread,
User,
+ Metric,
} from '@sentry/core';
export type { CloudflareOptions } from './client';
@@ -100,6 +101,7 @@ export {
featureFlagsIntegration,
growthbookIntegration,
logger,
+ metrics,
} from '@sentry/core';
export { withSentry } from './handler';
diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts
index c3ff126732f8..53e0328965a4 100644
--- a/packages/core/src/client.ts
+++ b/packages/core/src/client.ts
@@ -1037,16 +1037,18 @@ export abstract class Client {
/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
+ // initially, set `crashed` based on the event level and update from exceptions if there are any later on
let crashed = event.level === 'fatal';
let errored = false;
const exceptions = event.exception?.values;
if (exceptions) {
errored = true;
+ // reset crashed to false if there are exceptions, to ensure `mechanism.handled` is respected.
+ crashed = false;
for (const ex of exceptions) {
- const mechanism = ex.mechanism;
- if (mechanism?.handled === false) {
+ if (ex.mechanism?.handled === false) {
crashed = true;
break;
}
diff --git a/packages/core/src/utils/ai/messageTruncation.ts b/packages/core/src/utils/ai/messageTruncation.ts
index 64d186f927b8..945761f6220c 100644
--- a/packages/core/src/utils/ai/messageTruncation.ts
+++ b/packages/core/src/utils/ai/messageTruncation.ts
@@ -294,3 +294,13 @@ export function truncateMessagesByBytes(messages: unknown[], maxBytes: number):
export function truncateGenAiMessages(messages: unknown[]): unknown[] {
return truncateMessagesByBytes(messages, DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT);
}
+
+/**
+ * Truncate GenAI string input using the default byte limit.
+ *
+ * @param input - The string to truncate
+ * @returns Truncated string
+ */
+export function truncateGenAiStringInput(input: string): string {
+ return truncateTextByBytes(input, DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT);
+}
diff --git a/packages/core/src/utils/ai/utils.ts b/packages/core/src/utils/ai/utils.ts
index 00e147a16e5f..4a7a14eea554 100644
--- a/packages/core/src/utils/ai/utils.ts
+++ b/packages/core/src/utils/ai/utils.ts
@@ -7,7 +7,7 @@ import {
GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,
GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,
} from './gen-ai-attributes';
-import { truncateGenAiMessages } from './messageTruncation';
+import { truncateGenAiMessages, truncateGenAiStringInput } from './messageTruncation';
/**
* Maps AI method paths to Sentry operation name
*/
@@ -95,7 +95,7 @@ export function setTokenUsageAttributes(
export function getTruncatedJsonString(value: T | T[]): string {
if (typeof value === 'string') {
// Some values are already JSON strings, so we don't need to duplicate the JSON parsing
- return value;
+ return truncateGenAiStringInput(value);
}
if (Array.isArray(value)) {
// truncateGenAiMessages returns an array of strings, so we need to stringify it
diff --git a/packages/core/test/lib/client.test.ts b/packages/core/test/lib/client.test.ts
index db25793ccf7b..acb4197cf4cf 100644
--- a/packages/core/test/lib/client.test.ts
+++ b/packages/core/test/lib/client.test.ts
@@ -1,4 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest';
+import type { SeverityLevel } from '../../src';
import {
addBreadcrumb,
dsnToString,
@@ -2308,6 +2309,108 @@ describe('Client', () => {
});
});
+ describe('_updateSessionFromEvent()', () => {
+ describe('event has no exceptions', () => {
+ it('sets status to crashed if level is fatal', () => {
+ const client = new TestClient(getDefaultTestClientOptions());
+ const session = makeSession();
+ getCurrentScope().setSession(session);
+
+ client.captureEvent({ message: 'test', level: 'fatal' });
+
+ const updatedSession = client.session;
+
+ expect(updatedSession).toMatchObject({
+ duration: expect.any(Number),
+ errors: 1,
+ init: false,
+ sid: expect.any(String),
+ started: expect.any(Number),
+ status: 'crashed',
+ timestamp: expect.any(Number),
+ });
+ });
+
+ it.each(['error', 'warning', 'log', 'info', 'debug'] as const)(
+ 'sets status to ok if level is %s',
+ (level: SeverityLevel) => {
+ const client = new TestClient(getDefaultTestClientOptions());
+ const session = makeSession();
+ getCurrentScope().setSession(session);
+
+ client.captureEvent({ message: 'test', level });
+
+ const updatedSession = client.session;
+
+ expect(updatedSession?.status).toEqual('ok');
+ },
+ );
+ });
+
+ describe('event has exceptions', () => {
+ it.each(['fatal', 'error', 'warning', 'log', 'info', 'debug'] as const)(
+ 'sets status ok for handled exceptions and ignores event level %s',
+ (level: SeverityLevel) => {
+ const client = new TestClient(getDefaultTestClientOptions());
+ const session = makeSession();
+ getCurrentScope().setSession(session);
+
+ client.captureException(new Error('test'), { captureContext: { level } });
+
+ const updatedSession = client.session;
+
+ expect(updatedSession?.status).toEqual('ok');
+ },
+ );
+
+ it.each(['fatal', 'error', 'warning', 'log', 'info', 'debug'] as const)(
+ 'sets status crashed for unhandled exceptions and ignores event level %s',
+ (level: SeverityLevel) => {
+ const client = new TestClient(getDefaultTestClientOptions());
+ const session = makeSession();
+ getCurrentScope().setSession(session);
+
+ client.captureException(new Error('test'), { captureContext: { level }, mechanism: { handled: false } });
+
+ const updatedSession = client.session;
+
+ expect(updatedSession?.status).toEqual('crashed');
+ },
+ );
+
+ it('sets status crashed if at least one exception is unhandled', () => {
+ const client = new TestClient(getDefaultTestClientOptions());
+ const session = makeSession();
+ getCurrentScope().setSession(session);
+
+ const event: Event = {
+ exception: {
+ values: [
+ {
+ mechanism: { type: 'generic', handled: true },
+ },
+ {
+ mechanism: { type: 'generic', handled: false },
+ },
+ {
+ mechanism: { type: 'generic', handled: true },
+ },
+ ],
+ },
+ };
+
+ client.captureEvent(event);
+
+ const updatedSession = client.session;
+
+ expect(updatedSession).toMatchObject({
+ status: 'crashed',
+ errors: 1, // an event with multiple exceptions still counts as one error in the session
+ });
+ });
+ });
+ });
+
describe('recordDroppedEvent()/_clearOutcomes()', () => {
test('records and returns outcomes', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
diff --git a/packages/google-cloud-serverless/src/index.ts b/packages/google-cloud-serverless/src/index.ts
index 02e55c45a7ba..3aa7da1cbab9 100644
--- a/packages/google-cloud-serverless/src/index.ts
+++ b/packages/google-cloud-serverless/src/index.ts
@@ -148,6 +148,7 @@ export {
OpenFeatureIntegrationHook,
statsigIntegration,
unleashIntegration,
+ metrics,
} from '@sentry/node';
export {
diff --git a/packages/node/src/integrations/tracing/redis.ts b/packages/node/src/integrations/tracing/redis.ts
index 8376c99c1998..f8be12352ae0 100644
--- a/packages/node/src/integrations/tracing/redis.ts
+++ b/packages/node/src/integrations/tracing/redis.ts
@@ -24,14 +24,34 @@ import {
} from '../../utils/redisCache';
interface RedisOptions {
+ /**
+ * Define cache prefixes for cache keys that should be captured as a cache span.
+ *
+ * Setting this to, for example, `['user:']` will capture cache keys that start with `user:`.
+ */
cachePrefixes?: string[];
+ /**
+ * Maximum length of the cache key added to the span description. If the key exceeds this length, it will be truncated.
+ *
+ * Passing `0` will use the full cache key without truncation.
+ *
+ * By default, the full cache key is used.
+ */
+ maxCacheKeyLength?: number;
}
const INTEGRATION_NAME = 'Redis';
-let _redisOptions: RedisOptions = {};
+/* Only exported for testing purposes */
+export let _redisOptions: RedisOptions = {};
-const cacheResponseHook: RedisResponseCustomAttributeFunction = (span: Span, redisCommand, cmdArgs, response) => {
+/* Only exported for testing purposes */
+export const cacheResponseHook: RedisResponseCustomAttributeFunction = (
+ span: Span,
+ redisCommand,
+ cmdArgs,
+ response,
+) => {
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.redis');
const safeKey = getCacheKeySafely(redisCommand, cmdArgs);
@@ -70,9 +90,12 @@ const cacheResponseHook: RedisResponseCustomAttributeFunction = (span: Span, red
[SEMANTIC_ATTRIBUTE_CACHE_KEY]: safeKey,
});
+ // todo: change to string[] once EAP supports it
const spanDescription = safeKey.join(', ');
- span.updateName(truncate(spanDescription, 1024));
+ span.updateName(
+ _redisOptions.maxCacheKeyLength ? truncate(spanDescription, _redisOptions.maxCacheKeyLength) : spanDescription,
+ );
};
const instrumentIORedis = generateInstrumentOnce(`${INTEGRATION_NAME}.IORedis`, () => {
diff --git a/packages/node/test/integrations/tracing/redis.test.ts b/packages/node/test/integrations/tracing/redis.test.ts
index 38a5b80eb759..ae5b879c0b8e 100644
--- a/packages/node/test/integrations/tracing/redis.test.ts
+++ b/packages/node/test/integrations/tracing/redis.test.ts
@@ -1,4 +1,5 @@
-import { describe, expect, it } from 'vitest';
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+import { _redisOptions, cacheResponseHook } from '../../../src/integrations/tracing/redis';
import {
calculateCacheItemSize,
GET_COMMANDS,
@@ -8,6 +9,82 @@ import {
} from '../../../src/utils/redisCache';
describe('Redis', () => {
+ describe('cacheResponseHook', () => {
+ let mockSpan: any;
+ let originalRedisOptions: any;
+
+ beforeEach(() => {
+ mockSpan = {
+ setAttribute: vi.fn(),
+ setAttributes: vi.fn(),
+ updateName: vi.fn(),
+ spanContext: () => ({ spanId: 'test-span-id', traceId: 'test-trace-id' }),
+ };
+
+ originalRedisOptions = { ..._redisOptions };
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ // Reset redis options by clearing all properties first, then restoring original ones
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+ Object.keys(_redisOptions).forEach(key => delete (_redisOptions as any)[key]);
+ Object.assign(_redisOptions, originalRedisOptions);
+ });
+
+ describe('early returns', () => {
+ it.each([
+ { desc: 'no args', cmd: 'get', args: [], response: 'test' },
+ { desc: 'unsupported command', cmd: 'exists', args: ['key'], response: 'test' },
+ { desc: 'no cache prefixes', cmd: 'get', args: ['key'], response: 'test', options: {} },
+ { desc: 'non-matching prefix', cmd: 'get', args: ['key'], response: 'test', options: { cachePrefixes: ['c'] } },
+ ])('should always set sentry.origin but return early when $desc', ({ cmd, args, response, options = {} }) => {
+ Object.assign(_redisOptions, options);
+
+ cacheResponseHook(mockSpan, cmd, args, response);
+
+ expect(mockSpan.setAttribute).toHaveBeenCalledWith('sentry.origin', 'auto.db.otel.redis');
+ expect(mockSpan.setAttributes).not.toHaveBeenCalled();
+ expect(mockSpan.updateName).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('span name truncation', () => {
+ beforeEach(() => {
+ Object.assign(_redisOptions, { cachePrefixes: ['cache:'] });
+ });
+
+ it('should not truncate span name when maxCacheKeyLength is not set', () => {
+ cacheResponseHook(
+ mockSpan,
+ 'mget',
+ ['cache:very-long-key-name', 'cache:very-long-key-name-2', 'cache:very-long-key-name-3'],
+ 'value',
+ );
+
+ expect(mockSpan.updateName).toHaveBeenCalledWith(
+ 'cache:very-long-key-name, cache:very-long-key-name-2, cache:very-long-key-name-3',
+ );
+ });
+
+ it('should truncate span name when maxCacheKeyLength is set', () => {
+ Object.assign(_redisOptions, { maxCacheKeyLength: 10 });
+
+ cacheResponseHook(mockSpan, 'get', ['cache:very-long-key-name'], 'value');
+
+ expect(mockSpan.updateName).toHaveBeenCalledWith('cache:very...');
+ });
+
+ it('should truncate multiple keys joined with commas', () => {
+ Object.assign(_redisOptions, { maxCacheKeyLength: 20 });
+
+ cacheResponseHook(mockSpan, 'mget', ['cache:key1', 'cache:key2', 'cache:key3'], ['val1', 'val2', 'val3']);
+
+ expect(mockSpan.updateName).toHaveBeenCalledWith('cache:key1, cache:ke...');
+ });
+ });
+ });
+
describe('getCacheKeySafely (single arg)', () => {
it('should return an empty string if there are no command arguments', () => {
const result = getCacheKeySafely('get', []);
@@ -26,7 +103,7 @@ describe('Redis', () => {
expect(result).toStrictEqual(['key1']);
});
- it('should return only the key for multiple arguments', () => {
+ it('should return only the first key for commands that only accept a singe key (get)', () => {
const cmdArgs = ['key1', 'the-value'];
const result = getCacheKeySafely('get', cmdArgs);
expect(result).toStrictEqual(['key1']);
diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts
index 0613d6397f96..88177f11354a 100644
--- a/packages/sveltekit/src/server/index.ts
+++ b/packages/sveltekit/src/server/index.ts
@@ -128,6 +128,7 @@ export {
createConsolaReporter,
createSentryWinstonTransport,
vercelAIIntegration,
+ metrics,
} from '@sentry/node';
// We can still leave this for the carrier init and type exports
diff --git a/packages/vercel-edge/src/index.ts b/packages/vercel-edge/src/index.ts
index 7a73234f535e..4f5017bb8f6c 100644
--- a/packages/vercel-edge/src/index.ts
+++ b/packages/vercel-edge/src/index.ts
@@ -16,6 +16,7 @@ export type {
Stacktrace,
Thread,
User,
+ Metric,
} from '@sentry/core';
export type { VercelEdgeOptions } from './types';
@@ -98,6 +99,7 @@ export {
createLangChainCallbackHandler,
featureFlagsIntegration,
logger,
+ metrics,
} from '@sentry/core';
export { VercelEdgeClient } from './client';
diff --git a/scripts/ci-unit-tests.ts b/scripts/ci-unit-tests.ts
index 2802bde62fa6..2b6468c3e4ce 100644
--- a/scripts/ci-unit-tests.ts
+++ b/scripts/ci-unit-tests.ts
@@ -23,6 +23,7 @@ const BROWSER_TEST_PACKAGES = [
'@sentry-internal/replay-canvas',
'@sentry-internal/replay-worker',
'@sentry-internal/feedback',
+ '@sentry-internal/bundler-tests',
'@sentry/wasm',
];
diff --git a/yarn.lock b/yarn.lock
index a49764ebb218..99e434f5efff 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6824,105 +6824,115 @@
estree-walker "^2.0.2"
picomatch "^4.0.2"
-"@rollup/rollup-android-arm-eabi@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz#f768e3b2b0e6b55c595d7a053652c06413713983"
- integrity sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==
-
-"@rollup/rollup-android-arm64@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz#40379fd5501cfdfd7d8f86dfa1d3ce8d3a609493"
- integrity sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==
-
-"@rollup/rollup-darwin-arm64@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz#972c227bc89fe8a38a3f0c493e1966900e4e1ff7"
- integrity sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==
-
-"@rollup/rollup-darwin-x64@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz#96c919dcb87a5aa7dec5f7f77d90de881e578fdd"
- integrity sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==
-
-"@rollup/rollup-freebsd-arm64@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz#d199d8eaef830179c0c95b7a6e5455e893d1102c"
- integrity sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==
-
-"@rollup/rollup-freebsd-x64@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz#cab01f9e06ca756c1fabe87d64825ae016af4713"
- integrity sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==
-
-"@rollup/rollup-linux-arm-gnueabihf@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz#f6f1c42036dba0e58dc2315305429beff0d02c78"
- integrity sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==
-
-"@rollup/rollup-linux-arm-musleabihf@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz#1157e98e740facf858993fb51431dce3a4a96239"
- integrity sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==
-
-"@rollup/rollup-linux-arm64-gnu@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz#b39db73f8a4c22e7db31a4f3fd45170105f33265"
- integrity sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==
-
-"@rollup/rollup-linux-arm64-musl@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz#4043398049fe4449c1485312d1ae9ad8af4056dd"
- integrity sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==
-
-"@rollup/rollup-linux-loongarch64-gnu@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz#855a80e7e86490da15a85dcce247dbc25265bc08"
- integrity sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==
-
-"@rollup/rollup-linux-powerpc64le-gnu@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz#8cf843cb7ab1d42e1dda680937cf0a2db6d59047"
- integrity sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==
-
-"@rollup/rollup-linux-riscv64-gnu@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz#287c085472976c8711f16700326f736a527f2f38"
- integrity sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==
-
-"@rollup/rollup-linux-riscv64-musl@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz#095ad5e53a54ba475979f1b3226b92440c95c892"
- integrity sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==
-
-"@rollup/rollup-linux-s390x-gnu@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz#a3dec8281d8f2aef1703e48ebc65d29fe847933c"
- integrity sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==
-
-"@rollup/rollup-linux-x64-gnu@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz#4b211e6fd57edd6a134740f4f8e8ea61972ff2c5"
- integrity sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==
-
-"@rollup/rollup-linux-x64-musl@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz#3ecbf8e21b4157e57bb15dc6837b6db851f9a336"
- integrity sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==
-
-"@rollup/rollup-win32-arm64-msvc@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz#d4aae38465b2ad200557b53c8c817266a3ddbfd0"
- integrity sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==
-
-"@rollup/rollup-win32-ia32-msvc@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz#0258e8ca052abd48b23fd6113360fa0cd1ec3e23"
- integrity sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==
-
-"@rollup/rollup-win32-x64-msvc@4.44.1":
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz#1c982f6a5044ffc2a35cd754a0951bdcb44d5ba0"
- integrity sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==
+"@rollup/rollup-android-arm-eabi@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz#0f44a2f8668ed87b040b6fe659358ac9239da4db"
+ integrity sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==
+
+"@rollup/rollup-android-arm64@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz#25b9a01deef6518a948431564c987bcb205274f5"
+ integrity sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==
+
+"@rollup/rollup-darwin-arm64@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz#8a102869c88f3780c7d5e6776afd3f19084ecd7f"
+ integrity sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==
+
+"@rollup/rollup-darwin-x64@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz#8e526417cd6f54daf1d0c04cf361160216581956"
+ integrity sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==
+
+"@rollup/rollup-freebsd-arm64@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz#0e7027054493f3409b1f219a3eac5efd128ef899"
+ integrity sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==
+
+"@rollup/rollup-freebsd-x64@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz#72b204a920139e9ec3d331bd9cfd9a0c248ccb10"
+ integrity sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz#ab1b522ebe5b7e06c99504cc38f6cd8b808ba41c"
+ integrity sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==
+
+"@rollup/rollup-linux-arm-musleabihf@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz#f8cc30b638f1ee7e3d18eac24af47ea29d9beb00"
+ integrity sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==
+
+"@rollup/rollup-linux-arm64-gnu@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz#7af37a9e85f25db59dc8214172907b7e146c12cc"
+ integrity sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==
+
+"@rollup/rollup-linux-arm64-musl@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz#a623eb0d3617c03b7a73716eb85c6e37b776f7e0"
+ integrity sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==
+
+"@rollup/rollup-linux-loong64-gnu@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz#76ea038b549c5c6c5f0d062942627c4066642ee2"
+ integrity sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==
+
+"@rollup/rollup-linux-ppc64-gnu@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz#d9a4c3f0a3492bc78f6fdfe8131ac61c7359ccd5"
+ integrity sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==
+
+"@rollup/rollup-linux-riscv64-gnu@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz#87ab033eebd1a9a1dd7b60509f6333ec1f82d994"
+ integrity sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==
+
+"@rollup/rollup-linux-riscv64-musl@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz#bda3eb67e1c993c1ba12bc9c2f694e7703958d9f"
+ integrity sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==
+
+"@rollup/rollup-linux-s390x-gnu@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz#f7bc10fbe096ab44694233dc42a2291ed5453d4b"
+ integrity sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==
+
+"@rollup/rollup-linux-x64-gnu@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz#a151cb1234cc9b2cf5e8cfc02aa91436b8f9e278"
+ integrity sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==
+
+"@rollup/rollup-linux-x64-musl@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz#7859e196501cc3b3062d45d2776cfb4d2f3a9350"
+ integrity sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==
+
+"@rollup/rollup-openharmony-arm64@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz#85d0df7233734df31e547c1e647d2a5300b3bf30"
+ integrity sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==
+
+"@rollup/rollup-win32-arm64-msvc@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz#e62357d00458db17277b88adbf690bb855cac937"
+ integrity sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==
+
+"@rollup/rollup-win32-ia32-msvc@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz#fc7cd40f44834a703c1f1c3fe8bcc27ce476cd50"
+ integrity sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==
+
+"@rollup/rollup-win32-x64-gnu@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz#1a22acfc93c64a64a48c42672e857ee51774d0d3"
+ integrity sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==
+
+"@rollup/rollup-win32-x64-msvc@4.52.5":
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz#1657f56326bbe0ac80eedc9f9c18fc1ddd24e107"
+ integrity sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==
"@schematics/angular@14.2.13":
version "14.2.13"
@@ -27073,33 +27083,35 @@ rollup@^3.27.1, rollup@^3.28.1:
optionalDependencies:
fsevents "~2.3.2"
-rollup@^4.20.0, rollup@^4.34.9, rollup@^4.35.0, rollup@^4.44.0:
- version "4.44.1"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.44.1.tgz#641723932894e7acbe6052aea34b8e72ef8b7c8f"
- integrity sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==
+rollup@^4.0.0, rollup@^4.20.0, rollup@^4.34.9, rollup@^4.35.0, rollup@^4.44.0:
+ version "4.52.5"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.52.5.tgz#96982cdcaedcdd51b12359981f240f94304ec235"
+ integrity sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==
dependencies:
"@types/estree" "1.0.8"
optionalDependencies:
- "@rollup/rollup-android-arm-eabi" "4.44.1"
- "@rollup/rollup-android-arm64" "4.44.1"
- "@rollup/rollup-darwin-arm64" "4.44.1"
- "@rollup/rollup-darwin-x64" "4.44.1"
- "@rollup/rollup-freebsd-arm64" "4.44.1"
- "@rollup/rollup-freebsd-x64" "4.44.1"
- "@rollup/rollup-linux-arm-gnueabihf" "4.44.1"
- "@rollup/rollup-linux-arm-musleabihf" "4.44.1"
- "@rollup/rollup-linux-arm64-gnu" "4.44.1"
- "@rollup/rollup-linux-arm64-musl" "4.44.1"
- "@rollup/rollup-linux-loongarch64-gnu" "4.44.1"
- "@rollup/rollup-linux-powerpc64le-gnu" "4.44.1"
- "@rollup/rollup-linux-riscv64-gnu" "4.44.1"
- "@rollup/rollup-linux-riscv64-musl" "4.44.1"
- "@rollup/rollup-linux-s390x-gnu" "4.44.1"
- "@rollup/rollup-linux-x64-gnu" "4.44.1"
- "@rollup/rollup-linux-x64-musl" "4.44.1"
- "@rollup/rollup-win32-arm64-msvc" "4.44.1"
- "@rollup/rollup-win32-ia32-msvc" "4.44.1"
- "@rollup/rollup-win32-x64-msvc" "4.44.1"
+ "@rollup/rollup-android-arm-eabi" "4.52.5"
+ "@rollup/rollup-android-arm64" "4.52.5"
+ "@rollup/rollup-darwin-arm64" "4.52.5"
+ "@rollup/rollup-darwin-x64" "4.52.5"
+ "@rollup/rollup-freebsd-arm64" "4.52.5"
+ "@rollup/rollup-freebsd-x64" "4.52.5"
+ "@rollup/rollup-linux-arm-gnueabihf" "4.52.5"
+ "@rollup/rollup-linux-arm-musleabihf" "4.52.5"
+ "@rollup/rollup-linux-arm64-gnu" "4.52.5"
+ "@rollup/rollup-linux-arm64-musl" "4.52.5"
+ "@rollup/rollup-linux-loong64-gnu" "4.52.5"
+ "@rollup/rollup-linux-ppc64-gnu" "4.52.5"
+ "@rollup/rollup-linux-riscv64-gnu" "4.52.5"
+ "@rollup/rollup-linux-riscv64-musl" "4.52.5"
+ "@rollup/rollup-linux-s390x-gnu" "4.52.5"
+ "@rollup/rollup-linux-x64-gnu" "4.52.5"
+ "@rollup/rollup-linux-x64-musl" "4.52.5"
+ "@rollup/rollup-openharmony-arm64" "4.52.5"
+ "@rollup/rollup-win32-arm64-msvc" "4.52.5"
+ "@rollup/rollup-win32-ia32-msvc" "4.52.5"
+ "@rollup/rollup-win32-x64-gnu" "4.52.5"
+ "@rollup/rollup-win32-x64-msvc" "4.52.5"
fsevents "~2.3.2"
router@^2.2.0: