diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b3b35020083..98fcc5ebcce1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## Unreleased -- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +- feat(browser): Enable Spotlight via `SENTRY_SPOTLIGHT` env var ([#18050](https://github.com/getsentry/sentry-javascript/pull/18050)) + - Truthy values (`true`, `t`, `y`, `yes`, `on`, `1`) enable Spotlight with the default URL + - Any other non-falsy string value is used as a custom Spotlight Sidecar URL + - Falsy values (`false`, `f`, `n`, `no`, `off`, `0`) disable Spotlight Work in this release was contributed by @hanseo0507. Thank you for your contribution! diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 1b4289d66992..263c6d4e4f40 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/sdk.ts b/packages/browser/src/sdk.ts index 7b5d67c636ae..615fbb94b8fb 100644 --- a/packages/browser/src/sdk.ts +++ b/packages/browser/src/sdk.ts @@ -1,6 +1,7 @@ import type { Client, Integration, Options } from '@sentry/core'; import { dedupeIntegration, + envToBool, functionToStringIntegration, getIntegrationsToSetup, inboundFiltersIntegration, @@ -15,6 +16,7 @@ import { browserSessionIntegration } from './integrations/browsersession'; import { globalHandlersIntegration } from './integrations/globalhandlers'; import { httpContextIntegration } from './integrations/httpcontext'; import { linkedErrorsIntegration } from './integrations/linkederrors'; +import { INTEGRATION_NAME as SPOTLIGHT_INTEGRATION_NAME, spotlightBrowserIntegration } from './integrations/spotlight'; import { defaultStackParser } from './stack-parsers'; import { makeFetchTransport } from './transports/fetch'; import { checkAndWarnIfIsEmbeddedBrowserExtension } from './utils/detectBrowserExtension'; @@ -90,6 +92,17 @@ export function init(options: BrowserOptions = {}): Client | undefined { const shouldDisableBecauseIsBrowserExtenstion = !options.skipBrowserExtensionCheck && checkAndWarnIfIsEmbeddedBrowserExtension(); + // Read spotlight config from env var with graceful fallback + // This will be replaced at build time by bundlers like webpack/vite + let spotlightFromEnv: boolean | string | undefined; + if (typeof process !== 'undefined' && process.env && process.env.SENTRY_SPOTLIGHT !== undefined) { + const envValue = process.env.SENTRY_SPOTLIGHT; + const parsedEnvValue = envToBool(envValue, { strict: true }); + spotlightFromEnv = parsedEnvValue ?? envValue; + } + + const spotlight = options.spotlight ?? spotlightFromEnv; + const clientOptions: BrowserClientOptions = { ...options, enabled: shouldDisableBecauseIsBrowserExtenstion ? false : options.enabled, @@ -100,7 +113,18 @@ export function init(options: BrowserOptions = {}): Client | undefined { options.defaultIntegrations == null ? getDefaultIntegrations(options) : options.defaultIntegrations, }), transport: options.transport || makeFetchTransport, + spotlight, }; + + // Auto-add spotlight integration if enabled and not already present + if (spotlight && !clientOptions.integrations.some(({ name }) => name === SPOTLIGHT_INTEGRATION_NAME)) { + clientOptions.integrations.push( + spotlightBrowserIntegration({ + sidecarUrl: typeof spotlight === 'string' ? spotlight : undefined, + }), + ); + } + return initAndBind(BrowserClient, clientOptions); } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index f3b29009b9ce..5718d8deee17 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -313,6 +313,8 @@ export { flushIfServerless } from './utils/flushIfServerless'; export { SDK_VERSION } from './utils/version'; export { getDebugImagesForResources, getFilenameToDebugIdMap } from './utils/debug-ids'; export { escapeStringForRegex } from './vendor/escapeStringForRegex'; +export { envToBool, TRUTHY_ENV_VALUES, FALSY_ENV_VALUES } from './utils/envToBool'; +export type { BoolCastOptions, StrictBoolCast, LooseBoolCast } from './utils/envToBool'; export type { Attachment } from './types-hoist/attachment'; export type { diff --git a/packages/node-core/src/utils/envToBool.ts b/packages/core/src/utils/envToBool.ts similarity index 100% rename from packages/node-core/src/utils/envToBool.ts rename to packages/core/src/utils/envToBool.ts diff --git a/packages/node-core/test/utils/envToBool.test.ts b/packages/core/test/utils/envToBool.test.ts similarity index 100% rename from packages/node-core/test/utils/envToBool.test.ts rename to packages/core/test/utils/envToBool.test.ts diff --git a/packages/node-core/src/index.ts b/packages/node-core/src/index.ts index 7557d73c74a2..200855f928ab 100644 --- a/packages/node-core/src/index.ts +++ b/packages/node-core/src/index.ts @@ -43,7 +43,6 @@ export { initializeEsmLoader } from './sdk/esmLoader'; export { isCjs } from './utils/detection'; export { ensureIsWrapped } from './utils/ensureIsWrapped'; export { createMissingInstrumentationContext } from './utils/createMissingInstrumentationContext'; -export { envToBool } from './utils/envToBool'; export { makeNodeTransport, type NodeTransportOptions } from './transports'; export type { HTTPModuleRequestIncomingMessage } from './transports/http-module'; export { NodeClient } from './sdk/client'; @@ -112,6 +111,7 @@ export { startSession, captureSession, endSession, + envToBool, addIntegration, startSpan, startSpanManual, diff --git a/packages/node-core/src/sdk/index.ts b/packages/node-core/src/sdk/index.ts index d53f5d4faefb..24ded762a3e1 100644 --- a/packages/node-core/src/sdk/index.ts +++ b/packages/node-core/src/sdk/index.ts @@ -4,6 +4,7 @@ import { consoleIntegration, consoleSandbox, debug, + envToBool, functionToStringIntegration, getCurrentScope, getIntegrationsToSetup, @@ -37,7 +38,6 @@ import { systemErrorIntegration } from '../integrations/systemError'; import { makeNodeTransport } from '../transports'; import type { NodeClientOptions, NodeOptions } from '../types'; import { isCjs } from '../utils/detection'; -import { envToBool } from '../utils/envToBool'; import { defaultStackParser, getSentryRelease } from './api'; import { NodeClient } from './client'; import { initializeEsmLoader } from './esmLoader';