From 9788d8a8b733644cffe411d1c5e79d23aa446833 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 27 Jul 2026 16:50:00 +0200 Subject: [PATCH] feat(core)!: Enable span streaming by default Default clients to the streamed trace lifecycle and automatically install the required streaming integration in browser and server runtimes. Explicit static lifecycle configuration remains supported. Changes: - `traceLifecycle` now defaults to `'stream'` - `spanStreamingIntegration` is now added everywhere unless `traceLifecycle === 'static'` - This adds a bundle size increase to the browser SDK (~2KB gzip), unavoidable as long as transactions are still supported as an opt-out. - removed the `beforeSetup` hook on `spanStreamingIntegration` in the browser SDK, since it no longer needs to set the `traceLifecycle` option itself - added support for the `SENTRY_TRACE_LIFECYCLE` env var to Node, Cloudflare, and Vercel Edge to support opt-out for init-less SDK setups (AWS Lambda via `-i @sentry/aws-serverless/auto`, Astro Cloudflare pages) BREAKING CHANGE: Spans use the streamed trace lifecycle unless configured otherwise. Fixes #22344 Co-Authored-By: Cursor Co-Authored-By: Claude Sonnet 5 --- .../noOnLoad/pageloadTransaction/test.ts | 22 ++++------- .../astro-5-cf-workers/wrangler.jsonc | 1 + .../aws-serverless-layer/src/stack.ts | 1 + .../aws-serverless/src/stack.ts | 1 + .../browser/src/integrations/spanstreaming.ts | 10 ----- packages/browser/src/sdk.ts | 17 +++++++-- .../test/integrations/spanstreaming.test.ts | 15 -------- packages/browser/test/sdk.test.ts | 37 +++++++++++++++++++ .../src/core/sentry/telemetry.ts | 1 + packages/cloudflare/src/options.ts | 5 +++ packages/cloudflare/test/sdk.test.ts | 7 ++-- packages/core/src/client.ts | 2 +- packages/core/src/server-runtime-client.ts | 2 + packages/core/src/types/options.ts | 2 +- packages/core/test/lib/client.test.ts | 16 +++++++- packages/deno/test/sdk.test.ts | 8 ++-- packages/node/src/sdk/index.ts | 16 ++++++++ packages/node/test/sdk/init.test.ts | 18 ++++----- packages/vercel-edge/src/sdk.ts | 6 +++ packages/vercel-edge/test/sdk.test.ts | 10 ++--- 20 files changed, 127 insertions(+), 70 deletions(-) diff --git a/dev-packages/browser-integration-tests/loader-suites/loader/noOnLoad/pageloadTransaction/test.ts b/dev-packages/browser-integration-tests/loader-suites/loader/noOnLoad/pageloadTransaction/test.ts index 257934434358..5c520e975524 100644 --- a/dev-packages/browser-integration-tests/loader-suites/loader/noOnLoad/pageloadTransaction/test.ts +++ b/dev-packages/browser-integration-tests/loader-suites/loader/noOnLoad/pageloadTransaction/test.ts @@ -1,27 +1,21 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../../utils/fixtures'; -import { - envelopeRequestParser, - shouldSkipTracingTest, - waitForTransactionRequestOnUrl, -} from '../../../../utils/helpers'; +import { shouldSkipTracingTest } from '../../../../utils/helpers'; +import { getSpanOp, waitForStreamedSpan } from '../../../../utils/spanUtils'; -sentryTest('should create a pageload transaction', async ({ getLocalTestUrl, page }) => { +sentryTest('should create a pageload span', async ({ getLocalTestUrl, page }) => { if (shouldSkipTracingTest()) { sentryTest.skip(); } + const spanPromise = waitForStreamedSpan(page, s => getSpanOp(s) === 'pageload'); const url = await getLocalTestUrl({ testDir: __dirname }); - const req = await waitForTransactionRequestOnUrl(page, url); + await page.goto(url); + const pageloadSpan = await spanPromise; - const eventData = envelopeRequestParser(req); const timeOrigin = await page.evaluate('window._testBaseTimestamp'); - const { start_timestamp: startTimestamp } = eventData; + expect(pageloadSpan.start_timestamp).toBeCloseTo(timeOrigin, 1); - expect(startTimestamp).toBeCloseTo(timeOrigin, 1); - - expect(eventData.contexts?.trace?.op).toBe('pageload'); - expect(eventData.spans?.length).toBeGreaterThan(0); - expect(eventData.transaction_info?.source).toEqual('url'); + expect(pageloadSpan.attributes?.['sentry.segment.name.source'].value).toEqual('url'); }); diff --git a/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/wrangler.jsonc b/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/wrangler.jsonc index 9dbebf825355..135d0dbcd544 100644 --- a/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/wrangler.jsonc +++ b/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/wrangler.jsonc @@ -9,6 +9,7 @@ "SENTRY_ENVIRONMENT": "qa", "SENTRY_TRACES_SAMPLE_RATE": "1.0", "SENTRY_TUNNEL": "http://localhost:3031/", + "SENTRY_TRACE_LIFECYCLE": "static", }, "assets": { "binding": "ASSETS", diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts b/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts index 4b4a54ef24f1..7171e66872c0 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts @@ -77,6 +77,7 @@ export class LocalLambdaStack extends Stack { Variables: { SENTRY_TRACES_SAMPLE_RATE: 1.0, SENTRY_DEBUG: true, + SENTRY_TRACE_LIFECYCLE: 'static', NODE_OPTIONS: `--import=@sentry/aws-serverless/awslambda-auto`, // We only set SENTRY_DSN if not running TunnelNoDsn, because there // we want to test that the extension tunnel forwards requests when SENTRY_DSN is missing. diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts index cb3f4db7d0ec..9375ac6f0835 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts @@ -112,6 +112,7 @@ export class LocalLambdaStack extends Stack { SENTRY_DSN: dsn, SENTRY_TRACES_SAMPLE_RATE: 1.0, SENTRY_DEBUG: true, + SENTRY_TRACE_LIFECYCLE: 'static', NODE_OPTIONS: `--import=@sentry/aws-serverless/awslambda-auto`, }, }, diff --git a/packages/browser/src/integrations/spanstreaming.ts b/packages/browser/src/integrations/spanstreaming.ts index 6c1a647cb1fb..e8ed1a0de537 100644 --- a/packages/browser/src/integrations/spanstreaming.ts +++ b/packages/browser/src/integrations/spanstreaming.ts @@ -14,16 +14,6 @@ export const spanStreamingIntegration = defineIntegration(() => { return { name: 'SpanStreaming' as const, - beforeSetup(client) { - // If users only set spanStreamingIntegration, without traceLifecycle, we set it to "stream" for them. - // This avoids the classic double-opt-in problem we'd otherwise have in the browser SDK. - const clientOptions = client.getOptions(); - if (!clientOptions.traceLifecycle) { - DEBUG_BUILD && debug.log('[SpanStreaming] setting `traceLifecycle` to "stream"'); - clientOptions.traceLifecycle = 'stream'; - } - }, - setup(client) { const initialMessage = 'SpanStreaming integration requires'; const fallbackMsg = 'Falling back to static trace lifecycle.'; diff --git a/packages/browser/src/sdk.ts b/packages/browser/src/sdk.ts index f9ee4938ace1..d3bf3c960d6e 100644 --- a/packages/browser/src/sdk.ts +++ b/packages/browser/src/sdk.ts @@ -19,6 +19,7 @@ import { globalHandlersIntegration } from './integrations/globalhandlers'; import { httpContextIntegration } from './integrations/httpcontext'; import { linkedErrorsIntegration } from './integrations/linkederrors'; import { spotlightBrowserIntegration } from './integrations/spotlight'; +import { spanStreamingIntegration } from './integrations/spanstreaming'; import { defaultStackParser } from './stack-parsers'; import { makeFetchTransport } from './transports/fetch'; import { normalizeStringifyValue } from './normalizeStringifyValue'; @@ -110,14 +111,22 @@ export function init(options: BrowserOptions = {}): Client | undefined { } /*! rollup-include-development-only-end */ + const integrations = getIntegrationsToSetup({ + integrations: options.integrations, + defaultIntegrations, + }); + + options.traceLifecycle ??= 'stream'; + + if (options.traceLifecycle === 'stream' && !integrations.some(integration => integration.name === 'SpanStreaming')) { + integrations.push(spanStreamingIntegration()); + } + const clientOptions: BrowserClientOptions = { ...options, enabled: shouldDisableBecauseIsBrowserExtenstion ? false : options.enabled, stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser), - integrations: getIntegrationsToSetup({ - integrations: options.integrations, - defaultIntegrations, - }), + integrations, transport: options.transport || makeFetchTransport, }; diff --git a/packages/browser/test/integrations/spanstreaming.test.ts b/packages/browser/test/integrations/spanstreaming.test.ts index dd5268dab4ec..db4209a823e8 100644 --- a/packages/browser/test/integrations/spanstreaming.test.ts +++ b/packages/browser/test/integrations/spanstreaming.test.ts @@ -37,24 +37,9 @@ describe('spanStreamingIntegration', () => { const integration = spanStreamingIntegration(); expect(integration.name).toBe('SpanStreaming'); // eslint-disable-next-line @typescript-eslint/unbound-method - expect(integration.beforeSetup).toBeDefined(); - // eslint-disable-next-line @typescript-eslint/unbound-method expect(integration.setup).toBeDefined(); }); - it('sets traceLifecycle to "stream" if not set', () => { - const client = new BrowserClient({ - ...getDefaultBrowserClientOptions(), - dsn: 'https://username@domain/123', - integrations: [spanStreamingIntegration()], - }); - - SentryCore.setCurrentClient(client); - client.init(); - - expect(client.getOptions().traceLifecycle).toBe('stream'); - }); - it.each(['static', 'somethingElse'])( 'logs a warning if traceLifecycle is not set to "stream" but to %s', traceLifecycle => { diff --git a/packages/browser/test/sdk.test.ts b/packages/browser/test/sdk.test.ts index 3d84da69e565..744025bc1b1d 100644 --- a/packages/browser/test/sdk.test.ts +++ b/packages/browser/test/sdk.test.ts @@ -61,6 +61,32 @@ describe('init', () => { expect(optionsPassed?.integrations.length).toBeGreaterThan(0); }); + it('installs spanStreamingIntegration by default', () => { + // @ts-expect-error this is fine for testing + const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind').mockImplementationOnce(() => {}); + const options = getDefaultBrowserOptions({ dsn: PUBLIC_DSN, defaultIntegrations: undefined }); + + init(options); + + const optionsPassed = initAndBindSpy.mock.calls[0]?.[1]; + expect(optionsPassed?.integrations.some(integration => integration.name === 'SpanStreaming')).toBe(true); + }); + + it('does not install spanStreamingIntegration when traceLifecycle is static', () => { + // @ts-expect-error this is fine for testing + const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind').mockImplementationOnce(() => {}); + const options = getDefaultBrowserOptions({ + dsn: PUBLIC_DSN, + defaultIntegrations: undefined, + traceLifecycle: 'static', + }); + + init(options); + + const optionsPassed = initAndBindSpy.mock.calls[0]?.[1]; + expect(optionsPassed?.integrations.some(integration => integration.name === 'SpanStreaming')).toBe(false); + }); + test("doesn't install default integrations if told not to", () => { const DEFAULT_INTEGRATIONS: Integration[] = [ new MockIntegration('MockIntegration 0.3'), @@ -73,6 +99,17 @@ describe('init', () => { expect(DEFAULT_INTEGRATIONS[1]!.setupOnce as Mock).toHaveBeenCalledTimes(0); }); + it('installs spanStreamingIntegration with defaultIntegrations disabled', () => { + // @ts-expect-error this is fine for testing + const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind').mockImplementationOnce(() => {}); + const options = getDefaultBrowserOptions({ dsn: PUBLIC_DSN, defaultIntegrations: false }); + + init(options); + + const optionsPassed = initAndBindSpy.mock.calls[0]?.[1]; + expect(optionsPassed?.integrations.some(integration => integration.name === 'SpanStreaming')).toBe(true); + }); + it('installs merged default integrations, with overrides provided through options', () => { const DEFAULT_INTEGRATIONS = [ new MockIntegration('MockIntegration 1.1'), diff --git a/packages/bundler-plugins/src/core/sentry/telemetry.ts b/packages/bundler-plugins/src/core/sentry/telemetry.ts index afeedda2f87c..5615ac3e8f6f 100644 --- a/packages/bundler-plugins/src/core/sentry/telemetry.ts +++ b/packages/bundler-plugins/src/core/sentry/telemetry.ts @@ -27,6 +27,7 @@ export function createSentryInstance( dsn: 'https://4c2bae7d9fbc413e8f7385f55c515d51@o1.ingest.sentry.io/6690737', tracesSampleRate: 1, + traceLifecycle: 'static', sampleRate: 1, release: LIB_VERSION, diff --git a/packages/cloudflare/src/options.ts b/packages/cloudflare/src/options.ts index 947d6d921892..a90a236e4bf1 100644 --- a/packages/cloudflare/src/options.ts +++ b/packages/cloudflare/src/options.ts @@ -70,6 +70,7 @@ export function getFinalOptions(userOptions: CloudflareOptions = {}, env: unknow tracesSampleRate: isFinite(tracesSampleRate) ? tracesSampleRate : undefined, debug: userOptions.debug ?? envToBool(getEnvVar(env, 'SENTRY_DEBUG')), tunnel: userOptions.tunnel ?? getEnvVar(env, 'SENTRY_TUNNEL'), + traceLifecycle: userOptions.traceLifecycle ?? getTraceLifecycleFromEnv(getEnvVar(env, 'SENTRY_TRACE_LIFECYCLE')), /*! rollup-include-development-only */ spotlight, /*! rollup-include-development-only-end */ @@ -102,3 +103,7 @@ function getSpotlightFromEnv( ? (envUrl ?? true) // true: use env URL if present, otherwise true : (envBool ?? envUrl); // undefined: use env var (bool or URL) } + +function getTraceLifecycleFromEnv(envVar: string | undefined): 'static' | 'stream' | undefined { + return envVar === 'stream' || envVar === 'static' ? envVar : undefined; +} diff --git a/packages/cloudflare/test/sdk.test.ts b/packages/cloudflare/test/sdk.test.ts index 09efdd96f3d6..643c9f4462fb 100644 --- a/packages/cloudflare/test/sdk.test.ts +++ b/packages/cloudflare/test/sdk.test.ts @@ -22,10 +22,9 @@ describe('init', () => { expect(client).toBeInstanceOf(CloudflareClient); }); - test('installs SpanStreaming integration when traceLifecycle is "stream"', () => { + test('installs SpanStreaming integration by default', () => { init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', - traceLifecycle: 'stream', }); const client = getClient(); @@ -36,8 +35,8 @@ describe('init', () => { ); }); - test("does not install SpanStreaming integration when traceLifecycle is not 'stream'", () => { - init({ dsn: 'https://public@dsn.ingest.sentry.io/1337' }); + test("does not install SpanStreaming integration when traceLifecycle is 'static'", () => { + init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', traceLifecycle: 'static' }); const client = getClient(); expect(client?.getOptions()).toEqual( diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index 8171a53c02c4..6a11959e9983 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -234,7 +234,7 @@ export abstract class Client { * @param options Options for the client. */ protected constructor(options: O) { - this._options = { attachStacktrace: true, ...options }; + this._options = { attachStacktrace: true, traceLifecycle: 'stream', ...options }; this._integrations = {}; this._numProcessing = 0; this._outcomes = {}; diff --git a/packages/core/src/server-runtime-client.ts b/packages/core/src/server-runtime-client.ts index 9b1c2374e50a..ec10c516ef9b 100644 --- a/packages/core/src/server-runtime-client.ts +++ b/packages/core/src/server-runtime-client.ts @@ -40,6 +40,8 @@ export class ServerRuntimeClient< public constructor(options: O) { addUserAgentToTransportHeaders(options); + options.traceLifecycle ??= 'stream'; + // When span streaming is enabled (`traceLifecycle: 'stream'`), the `spanStreamingIntegration` // is required to flush spans. We add it here so the individual server SDKs don't have to. // A user-provided `spanStreamingIntegration` always takes precedence over the one we add. diff --git a/packages/core/src/types/options.ts b/packages/core/src/types/options.ts index b96c3159dad6..4aa93e6ac12e 100644 --- a/packages/core/src/types/options.ts +++ b/packages/core/src/types/options.ts @@ -543,7 +543,7 @@ export interface ClientOptions { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, test: true }); const client = new TestClient(options); - expect(client.getOptions()).toEqual({ attachStacktrace: true, ...options }); + expect(client.getOptions()).toEqual({ attachStacktrace: true, traceLifecycle: 'stream', ...options }); + }); + + test('defaults traceLifecycle to stream', () => { + const options = getDefaultTestClientOptions(); + delete options.traceLifecycle; + const client = new TestClient(options); + + expect(client.getOptions().traceLifecycle).toBe('stream'); + }); + + test('preserves an explicit static traceLifecycle', () => { + const client = new TestClient(getDefaultTestClientOptions({ traceLifecycle: 'static' })); + + expect(client.getOptions().traceLifecycle).toBe('static'); }); }); diff --git a/packages/deno/test/sdk.test.ts b/packages/deno/test/sdk.test.ts index eac8f4d7997e..5d0d8973a075 100644 --- a/packages/deno/test/sdk.test.ts +++ b/packages/deno/test/sdk.test.ts @@ -8,8 +8,8 @@ Deno.test('init() should return client', () => { assertNotEquals(init({}), undefined); }); -Deno.test('adds spanStreamingIntegration when traceLifecycle is "stream"', () => { - const client = init({ traceLifecycle: 'stream' }); +Deno.test('adds spanStreamingIntegration by default', () => { + const client = init({}); const integrations = client.getOptions().integrations; assertArrayIncludes( integrations.map(i => i.name), @@ -17,8 +17,8 @@ Deno.test('adds spanStreamingIntegration when traceLifecycle is "stream"', () => ); }); -Deno.test('doesn\'t add spanStreamingIntegration when traceLifecycle is not "stream"', () => { - const client = init({}); +Deno.test('doesn\'t add spanStreamingIntegration when traceLifecycle is "static"', () => { + const client = init({ traceLifecycle: 'static' }); const integrations = client.getOptions().integrations; assert(!integrations.some(i => i.name === 'SpanStreaming')); }); diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index c519b4408269..fe5df56cd5c1 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -300,6 +300,7 @@ function getClientOptions( const spotlight = getSpotlightConfig(options.spotlight); const tracesSampleRate = getTracesSampleRate(options.tracesSampleRate); + const traceLifecycle = getTraceLifecycle(options.traceLifecycle); const mergedOptions = { ...options, @@ -311,6 +312,7 @@ function getClientOptions( release, tracesSampleRate, spotlight, + traceLifecycle, debug: envToBool(options.debug ?? process.env.SENTRY_DEBUG), }; @@ -355,6 +357,20 @@ function getTracesSampleRate(tracesSampleRate: NodeOptions['tracesSampleRate']): return isFinite(parsed) ? parsed : undefined; } +function getTraceLifecycle(traceLifecycle: NodeOptions['traceLifecycle']): 'stream' | 'static' { + if (traceLifecycle !== undefined) { + return traceLifecycle; + } + + const lifecycleFromEnv = process.env.SENTRY_TRACE_LIFECYCLE; + + if (lifecycleFromEnv === 'stream' || lifecycleFromEnv === 'static') { + return lifecycleFromEnv; + } + + return 'stream'; +} + /** * Update scope and propagation context based on environmental variables. * diff --git a/packages/node/test/sdk/init.test.ts b/packages/node/test/sdk/init.test.ts index c4b0550098fa..c6c845ac4eba 100644 --- a/packages/node/test/sdk/init.test.ts +++ b/packages/node/test/sdk/init.test.ts @@ -59,16 +59,12 @@ describe('init()', () => { }); describe('integrations', () => { - it("doesn't install default integrations if told not to", () => { + it('only installs the required spanStreaming integration if default integrations are disabled', () => { init({ dsn: PUBLIC_DSN, defaultIntegrations: false }); const client = getClient(); - expect(client?.getOptions()).toEqual( - expect.objectContaining({ - integrations: [], - }), - ); + expect(client?.getOptions().integrations.map(integration => integration.name)).toEqual(['SpanStreaming']); expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); }); @@ -169,8 +165,8 @@ describe('init()', () => { ); }); - it('installs spanStreaming integration when traceLifecycle is "stream"', () => { - init({ dsn: PUBLIC_DSN, traceLifecycle: 'stream' }); + it('installs spanStreaming integration by default', () => { + init({ dsn: PUBLIC_DSN }); const client = getClient(); expect(client?.getOptions()).toEqual( @@ -180,8 +176,8 @@ describe('init()', () => { ); }); - it("doesn't install spanStreaming integration when traceLifecycle is not 'stream'", () => { - init({ dsn: PUBLIC_DSN }); + it("doesn't install spanStreaming integration when traceLifecycle is 'static'", () => { + init({ dsn: PUBLIC_DSN, traceLifecycle: 'static' }); const client = getClient(); expect(client?.getOptions()).toEqual( @@ -192,7 +188,7 @@ describe('init()', () => { }); it('installs spanStreaming integration even with custom defaultIntegrations', () => { - init({ dsn: PUBLIC_DSN, traceLifecycle: 'stream', defaultIntegrations: [] }); + init({ dsn: PUBLIC_DSN, defaultIntegrations: [] }); const client = getClient(); expect(client?.getOptions()).toEqual( diff --git a/packages/vercel-edge/src/sdk.ts b/packages/vercel-edge/src/sdk.ts index 43bdecdf3931..a845a9d77886 100644 --- a/packages/vercel-edge/src/sdk.ts +++ b/packages/vercel-edge/src/sdk.ts @@ -89,6 +89,8 @@ export function init(options: VercelEdgeOptions = {}): Client { options.environment = options.environment || process.env.SENTRY_ENVIRONMENT || getVercelEnv(false) || process.env.NODE_ENV; + options.traceLifecycle = options.traceLifecycle ?? getTraceLifecycleFromEnv(process.env.SENTRY_TRACE_LIFECYCLE); + const client = new VercelEdgeClient({ ...options, stackParser: stackParserFromStackParserOptions(options.stackParser || nodeStackParser), @@ -258,3 +260,7 @@ export function getSentryRelease(fallback?: string): string | undefined { fallback ); } + +function getTraceLifecycleFromEnv(envVar: string | undefined): 'static' | 'stream' | undefined { + return envVar === 'stream' || envVar === 'static' ? envVar : undefined; +} diff --git a/packages/vercel-edge/test/sdk.test.ts b/packages/vercel-edge/test/sdk.test.ts index d5a67edff718..0da12197a5f4 100644 --- a/packages/vercel-edge/test/sdk.test.ts +++ b/packages/vercel-edge/test/sdk.test.ts @@ -3,22 +3,22 @@ import { init, spanStreamingIntegration } from '../src'; import type { Integration } from '@sentry/core'; describe('init', () => { - it('adds spanStreamingIntegration when traceLifecycle is "stream"', () => { - const client = init({ traceLifecycle: 'stream' }); + it('adds spanStreamingIntegration by default', () => { + const client = init({}); const integrations = client?.getOptions().integrations; expect(integrations?.map(i => i.name)).toContain('SpanStreaming'); }); - it('doesn\'t add spanStreamingIntegration when traceLifecycle is not "stream"', () => { - const client = init({}); + it('doesn\'t add spanStreamingIntegration when traceLifecycle is "static"', () => { + const client = init({ traceLifecycle: 'static' }); const integrations = client?.getOptions().integrations; expect(integrations?.map(i => i.name)).not.toContain('SpanStreaming'); }); it('adds spanStreaming integration even with custom defaultIntegrations', () => { - const client = init({ traceLifecycle: 'stream', defaultIntegrations: [] }); + const client = init({ defaultIntegrations: [] }); const integrations = client?.getOptions().integrations; expect(integrations?.map(i => i.name)).toContain('SpanStreaming');