Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as Sentry from '@sentry/nextjs';

export const dynamic = 'force-dynamic';

export default async function FeatureFlagServerComponent() {
Sentry.buildLaunchDarklyFlagUsedHandler();
Sentry.launchDarklyIntegration();
Sentry.openFeatureIntegration();
new Sentry.OpenFeatureIntegrationHook();
// @ts-ignore - we just want to test that the statsigIntegration is imported
Sentry.statsigIntegration();
// @ts-ignore - we just want to test that the unleashIntegration is imported
Sentry.unleashIntegration();

return <div>FeatureFlagServerComponent</div>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,9 @@ test('Should capture an error and transaction for a app router page', async ({ p
}),
);
});

test('Should not throw error on server component when importing shimmed feature flag function', async ({ page }) => {
await page.goto('/server-component/featureFlag');
// tests that none of the feature flag functions throw an error when imported in a node environment
await expect(page.locator('body')).toContainText('FeatureFlagServerComponent');
});
6 changes: 6 additions & 0 deletions packages/astro/src/index.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ export {
NODE_VERSION,
featureFlagsIntegration,
type FeatureFlagsIntegration,
launchDarklyIntegration,
buildLaunchDarklyFlagUsedHandler,
openFeatureIntegration,
OpenFeatureIntegrationHook,
statsigIntegration,
unleashIntegration,
} from '@sentry/node';

export { init } from './server/sdk';
Expand Down
7 changes: 7 additions & 0 deletions packages/astro/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@ export declare const Span: clientSdk.Span;

export declare const logger: typeof clientSdk.logger | typeof serverSdk.logger;

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;

export default sentryAstro;
6 changes: 6 additions & 0 deletions packages/aws-serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ export {
NODE_VERSION,
featureFlagsIntegration,
type FeatureFlagsIntegration,
launchDarklyIntegration,
buildLaunchDarklyFlagUsedHandler,
openFeatureIntegration,
OpenFeatureIntegrationHook,
statsigIntegration,
unleashIntegration,
} from '@sentry/node';

export {
Expand Down
6 changes: 6 additions & 0 deletions packages/bun/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ export {
createSentryWinstonTransport,
wrapMcpServerWithSentry,
featureFlagsIntegration,
launchDarklyIntegration,
buildLaunchDarklyFlagUsedHandler,
openFeatureIntegration,
OpenFeatureIntegrationHook,
statsigIntegration,
unleashIntegration,
} from '@sentry/node';

export {
Expand Down
6 changes: 6 additions & 0 deletions packages/google-cloud-serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ export {
NODE_VERSION,
featureFlagsIntegration,
type FeatureFlagsIntegration,
launchDarklyIntegration,
buildLaunchDarklyFlagUsedHandler,
openFeatureIntegration,
OpenFeatureIntegrationHook,
statsigIntegration,
unleashIntegration,
} from '@sentry/node';

export {
Expand Down
1 change: 1 addition & 0 deletions packages/integration-shims/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { feedbackIntegrationShim } from './Feedback';
export { replayIntegrationShim } from './Replay';
export { browserTracingIntegrationShim } from './BrowserTracing';
export { launchDarklyIntegrationShim, buildLaunchDarklyFlagUsedHandlerShim } from './launchDarkly';
38 changes: 38 additions & 0 deletions packages/integration-shims/src/launchDarkly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { consoleSandbox, defineIntegration, isBrowser } from '@sentry/core';
import { FAKE_FUNCTION } from './common';

/**
* This is a shim for the LaunchDarkly integration.
* We need this in order to not throw runtime errors when accidentally importing this on the server through a meta framework like Next.js.
*/
export const launchDarklyIntegrationShim = defineIntegration((_options?: unknown) => {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The launchDarklyIntegration() can only be used in the browser.');
});
}

return {
name: 'LaunchDarkly',
};
});

/**
* This is a shim for the LaunchDarkly flag used handler.
*/
export function buildLaunchDarklyFlagUsedHandlerShim(): unknown {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The buildLaunchDarklyFlagUsedHandler() can only be used in the browser.');
});
}

return {
name: 'sentry-flag-auditor',
type: 'flag-used',
synchronous: true,
method: FAKE_FUNCTION,
};
}
7 changes: 7 additions & 0 deletions packages/nextjs/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,10 @@ export declare function wrapApiHandlerWithSentryVercelCrons<F extends (...args:
export declare function wrapPageComponentWithSentry<C>(WrappingTarget: C): C;

export { captureRequestError } from './common/captureRequestError';

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;
8 changes: 8 additions & 0 deletions packages/node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ export { amqplibIntegration } from './integrations/tracing/amqplib';
export { vercelAIIntegration } from './integrations/tracing/vercelai';
export { childProcessIntegration } from './integrations/childProcess';
export { createSentryWinstonTransport } from './integrations/winston';
export {
launchDarklyIntegration,
buildLaunchDarklyFlagUsedHandler,
openFeatureIntegration,
OpenFeatureIntegrationHook,
statsigIntegration,
unleashIntegration,
} from './integrations/featureFlagShims';

export { SentryContextManager } from './otel/contextManager';
export { generateInstrumentOnce } from './otel/instrument';
Expand Down
13 changes: 13 additions & 0 deletions packages/node/src/integrations/featureFlagShims/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export {
launchDarklyIntegrationShim as launchDarklyIntegration,
buildLaunchDarklyFlagUsedHandlerShim as buildLaunchDarklyFlagUsedHandler,
} from './launchDarkly';

export {
openFeatureIntegrationShim as openFeatureIntegration,
OpenFeatureIntegrationHookShim as OpenFeatureIntegrationHook,
} from './openFeature';

export { statsigIntegrationShim as statsigIntegration } from './statsig';

export { unleashIntegrationShim as unleashIntegration } from './unleash';
37 changes: 37 additions & 0 deletions packages/node/src/integrations/featureFlagShims/launchDarkly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { consoleSandbox, defineIntegration, isBrowser } from '@sentry/core';

/**
* This is a shim for the LaunchDarkly integration.
* We need this in order to not throw runtime errors when accidentally importing this on the server through a meta framework like Next.js.
*/
export const launchDarklyIntegrationShim = defineIntegration((_options?: unknown) => {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The launchDarklyIntegration() can only be used in the browser.');
});
}

return {
name: 'LaunchDarkly',
};
});

/**
* This is a shim for the LaunchDarkly flag used handler.
*/
export function buildLaunchDarklyFlagUsedHandlerShim(): unknown {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The buildLaunchDarklyFlagUsedHandler() can only be used in the browser.');
});
}

return {
name: 'sentry-flag-auditor',
type: 'flag-used',
synchronous: true,
method: () => null,
};
}
49 changes: 49 additions & 0 deletions packages/node/src/integrations/featureFlagShims/openFeature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { consoleSandbox, defineIntegration, isBrowser } from '@sentry/core';

/**
* This is a shim for the OpenFeature integration.
* We need this in order to not throw runtime errors when accidentally importing this on the server through a meta framework like Next.js.
*/
export const openFeatureIntegrationShim = defineIntegration((_options?: unknown) => {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The openFeatureIntegration() can only be used in the browser.');
});
}

return {
name: 'OpenFeature',
};
});

/**
* This is a shim for the OpenFeature integration hook.
*/
export class OpenFeatureIntegrationHookShim {
/**
*
*/
public constructor() {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The OpenFeatureIntegrationHook can only be used in the browser.');
});
}
}

/**
*
*/
public after(): void {
// No-op
}

/**
*
*/
public error(): void {
// No-op
}
}
18 changes: 18 additions & 0 deletions packages/node/src/integrations/featureFlagShims/statsig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { consoleSandbox, defineIntegration, isBrowser } from '@sentry/core';

/**
* This is a shim for the Statsig integration.
* We need this in order to not throw runtime errors when accidentally importing this on the server through a meta framework like Next.js.
*/
export const statsigIntegrationShim = defineIntegration((_options?: unknown) => {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The statsigIntegration() can only be used in the browser.');
});
}

return {
name: 'Statsig',
};
});
18 changes: 18 additions & 0 deletions packages/node/src/integrations/featureFlagShims/unleash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { consoleSandbox, defineIntegration, isBrowser } from '@sentry/core';

/**
* This is a shim for the Unleash integration.
* We need this in order to not throw runtime errors when accidentally importing this on the server through a meta framework like Next.js.
*/
export const unleashIntegrationShim = defineIntegration((_options?: unknown) => {
if (!isBrowser()) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('The unleashIntegration() can only be used in the browser.');
});
}

return {
name: 'Unleash',
};
});
7 changes: 7 additions & 0 deletions packages/nuxt/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ export declare const getDefaultIntegrations: (options: Options) => Integration[]
export declare const defaultStackParser: StackParser;

export declare const logger: typeof clientSdk.logger | typeof serverSdk.logger;

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;
7 changes: 7 additions & 0 deletions packages/react-router/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ export declare const defaultStackParser: StackParser;
export declare const getDefaultIntegrations: (options: Options) => Integration[];

export declare const logger: typeof clientSdk.logger | typeof serverSdk.logger;

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;
7 changes: 7 additions & 0 deletions packages/remix/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ declare const runtime: 'client' | 'server';
export const close = runtime === 'client' ? clientSdk.close : serverSdk.close;
export const flush = runtime === 'client' ? clientSdk.flush : serverSdk.flush;
export const lastEventId = runtime === 'client' ? clientSdk.lastEventId : serverSdk.lastEventId;

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;
7 changes: 7 additions & 0 deletions packages/solidstart/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,10 @@ export declare function flush(timeout?: number | undefined): PromiseLike<boolean
export declare function lastEventId(): string | undefined;

export declare const logger: typeof clientSdk.logger | typeof serverSdk.logger;

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;
7 changes: 7 additions & 0 deletions packages/sveltekit/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,10 @@ export declare function lastEventId(): string | undefined;
export declare function trackComponent(options: clientSdk.TrackingOptions): ReturnType<typeof clientSdk.trackComponent>;

export declare const logger: typeof clientSdk.logger | typeof serverSdk.logger;

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;
7 changes: 7 additions & 0 deletions packages/tanstackstart-react/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,10 @@ export declare const showReportDialog: typeof clientSdk.showReportDialog;
export declare const withErrorBoundary: typeof clientSdk.withErrorBoundary;

export declare const logger: typeof clientSdk.logger | typeof serverSdk.logger;

export declare const launchDarklyIntegration: typeof clientSdk.launchDarklyIntegration;
export declare const buildLaunchDarklyFlagUsedHandler: typeof clientSdk.buildLaunchDarklyFlagUsedHandler;
export declare const openFeatureIntegration: typeof clientSdk.openFeatureIntegration;
export declare const OpenFeatureIntegrationHook: typeof clientSdk.OpenFeatureIntegrationHook;
export declare const statsigIntegration: typeof clientSdk.statsigIntegration;
export declare const unleashIntegration: typeof clientSdk.unleashIntegration;
Loading