Skip to content

Commit 04a8ee4

Browse files
isaacsclaude
andcommitted
fix(deno): Re-export portable helpers that Cloudflare exposes
Cloudflare runs on workerd with no Node APIs, but it still exports more than Deno. The missing exports already work in Deno, because they come from `@sentry/core` and `@sentry/server-utils`, which Deno depends on. The manual AI client helpers matter most. Deno does not inject diagnostics channels by default, so `instrumentOpenAiClient` and the other `instrument*` helpers are the documented way to get AI spans there. Deno now re-exports `addIntegration`, `withActiveSpan`, `getSpanDescendants`, `setConversationId`, `createConsolaReporter`, `growthbookIntegration`, `moduleMetadataIntegration`, `trpcMiddleware`, `prismaIntegration`, the OpenAI, Anthropic, Google GenAI, Mistral, TypeSafe, LangChain and LangGraph helpers, and the `FlueOptions` type. Deno also gets `initWithoutDefaultIntegrations` and `getDefaultIntegrationsWithoutPerformance`, to match Node and Bun. The default integration set does not change. Some Cloudflare exports stay out. `instrumentWorkersAiClient` wraps a binding that exists only on Cloudflare. `spotlightIntegration` and `httpServerIntegration` live in the Cloudflare package, not in a shared entry point, so they need more than a re-export. `parameterize` was in the issue, but Cloudflare no longer exports it. Fixes #23896 Fixes JS-3522 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 554668c commit 04a8ee4

4 files changed

Lines changed: 127 additions & 7 deletions

File tree

‎packages/deno/src/index.ts‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export type { DenoOptions } from './types';
2626
export {
2727
addEventProcessor,
2828
addBreadcrumb,
29+
addIntegration,
2930
captureException,
3031
captureEvent,
3132
captureMessage,
@@ -52,6 +53,7 @@ export {
5253
setAttribute,
5354
setAttributes,
5455
setUser,
56+
setConversationId,
5557
getSpanStatusFromHttpCode,
5658
setHttpStatus,
5759
withScope,
@@ -69,6 +71,8 @@ export {
6971
startNewTrace,
7072
bindScopeToEmitter,
7173
suppressTracing,
74+
withActiveSpan,
75+
getSpanDescendants,
7276
eventFiltersIntegration,
7377
linkedErrorsIntegration,
7478
functionToStringIntegration,
@@ -78,6 +82,7 @@ export {
7882
dedupeIntegration,
7983
extraErrorDataIntegration,
8084
rewriteFramesIntegration,
85+
moduleMetadataIntegration,
8186
supabaseIntegration,
8287
instrumentSupabaseClient,
8388
zodErrorsIntegration,
@@ -94,7 +99,9 @@ export {
9499
spanToTraceHeader,
95100
spanToBaggageHeader,
96101
updateSpanName,
102+
createConsolaReporter,
97103
featureFlagsIntegration,
104+
growthbookIntegration,
98105
metrics,
99106
withStaticSpan,
100107
// oxlint-disable-next-line typescript/no-deprecated
@@ -103,12 +110,30 @@ export {
103110
consoleLoggingIntegration,
104111
spanStreamingIntegration,
105112
} from '@sentry/core';
106-
export { wrapMcpServerWithSentry } from '@sentry/core/server';
107-
export { instrumentPostgresJsSql } from '@sentry/server-utils';
113+
export { trpcMiddleware, wrapMcpServerWithSentry } from '@sentry/core/server';
114+
export {
115+
instrumentPostgresJsSql,
116+
prismaIntegration,
117+
instrumentOpenAiClient,
118+
instrumentAnthropicAiClient,
119+
instrumentGoogleGenAIClient,
120+
instrumentMistralAiClient,
121+
instrumentTypeSafeClient,
122+
createLangChainCallbackHandler,
123+
instrumentLangChainEmbeddings,
124+
instrumentStateGraph,
125+
instrumentCreateReactAgent,
126+
} from '@sentry/server-utils';
127+
export type { FlueOptions } from '@sentry/server-utils';
108128

109129
export { DenoClient } from './client';
110130

111-
export { getDefaultIntegrations, init } from './sdk';
131+
export {
132+
getDefaultIntegrations,
133+
getDefaultIntegrationsWithoutPerformance,
134+
init,
135+
initWithoutDefaultIntegrations,
136+
} from './sdk';
112137
export { denoServeIntegration } from './integrations/deno-serve';
113138
export type { DenoServeIntegrationOptions } from './integrations/deno-serve';
114139
export { fetchIntegration } from './integrations/fetch';

‎packages/deno/src/sdk.ts‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import { setupOpenTelemetryTracer } from './opentelemetry/tracer';
2929
import { makeFetchTransport } from './transports';
3030
import type { DenoOptions } from './types';
3131

32-
/** Get the default integrations for the Deno SDK. */
33-
export function getDefaultIntegrations(options: Options): Integration[] {
32+
/** Get the default integrations for the Deno SDK, excluding performance integrations. */
33+
export function getDefaultIntegrationsWithoutPerformance(): Integration[] {
3434
// We return a copy of the defaultIntegrations here to avoid mutating this
3535
return [
3636
// Common
@@ -52,10 +52,14 @@ export function getDefaultIntegrations(options: Options): Integration[] {
5252
globalHandlersIntegration(),
5353
// server-utils integrations
5454
...getErrorIntegrations(),
55-
...(hasSpansEnabled(options) ? getTracingIntegrations() : []),
5655
];
5756
}
5857

58+
/** Get the default integrations for the Deno SDK. */
59+
export function getDefaultIntegrations(options: Options): Integration[] {
60+
return [...getDefaultIntegrationsWithoutPerformance(), ...(hasSpansEnabled(options) ? getTracingIntegrations() : [])];
61+
}
62+
5963
const defaultStackParser: StackParser = createStackParser(nodeStackLineParser());
6064

6165
/**
@@ -103,10 +107,21 @@ const defaultStackParser: StackParser = createStackParser(nodeStackLineParser())
103107
* @see {@link DenoOptions} for documentation on configuration options.
104108
*/
105109
export function init(options: DenoOptions = {}): Client {
110+
return _init(options, getDefaultIntegrations);
111+
}
112+
113+
/**
114+
* Initialize Sentry for Deno, without any integrations added by default.
115+
*/
116+
export function initWithoutDefaultIntegrations(options: DenoOptions = {}): Client {
117+
return _init(options, () => []);
118+
}
119+
120+
function _init(options: DenoOptions, getDefaultIntegrationsImpl: (options: Options) => Integration[]): Client {
106121
// Computed into a local rather than written back onto `options`: the default set
107122
// depends on the tracing options, so caching it on the caller's object would pin the
108123
// result of the first `init` for any reused options object.
109-
const defaultIntegrations = options.defaultIntegrations ?? getDefaultIntegrations(options);
124+
const defaultIntegrations = options.defaultIntegrations ?? getDefaultIntegrationsImpl(options);
110125

111126
const clientOptions: ServerRuntimeClientOptions = {
112127
...options,

‎packages/deno/test/exports.test.ts‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { assertEquals } from 'https://deno.land/std@0.212.0/assert/assert_equals.ts';
2+
import * as Sentry from '../build/esm/index.js';
3+
import type { FlueOptions } from '../build/esm/index.js';
4+
5+
// Exports that Cloudflare ships and that need no Node APIs.
6+
const EXPECTED_FUNCTION_EXPORTS = [
7+
// @sentry/core
8+
'addIntegration',
9+
'withActiveSpan',
10+
'getSpanDescendants',
11+
'setConversationId',
12+
'createConsolaReporter',
13+
'growthbookIntegration',
14+
'moduleMetadataIntegration',
15+
// @sentry/core/server
16+
'trpcMiddleware',
17+
// @sentry/server-utils
18+
'prismaIntegration',
19+
'instrumentOpenAiClient',
20+
'instrumentAnthropicAiClient',
21+
'instrumentGoogleGenAIClient',
22+
'instrumentMistralAiClient',
23+
'instrumentTypeSafeClient',
24+
'createLangChainCallbackHandler',
25+
'instrumentLangChainEmbeddings',
26+
'instrumentStateGraph',
27+
'instrumentCreateReactAgent',
28+
// ./sdk
29+
'initWithoutDefaultIntegrations',
30+
'getDefaultIntegrationsWithoutPerformance',
31+
];
32+
33+
for (const name of EXPECTED_FUNCTION_EXPORTS) {
34+
Deno.test(`exports ${name}`, () => {
35+
assertEquals(typeof (Sentry as Record<string, unknown>)[name], 'function');
36+
});
37+
}
38+
39+
Deno.test('exports the FlueOptions type', () => {
40+
const options: FlueOptions = {};
41+
assertEquals(typeof options, 'object');
42+
});

‎packages/deno/test/sdk.test.ts‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { assertArrayIncludes } from 'https://deno.land/std@0.212.0/assert/assert
33
import {
44
getCurrentScope,
55
getDefaultIntegrations,
6+
getDefaultIntegrationsWithoutPerformance,
67
init as initSdk,
8+
initWithoutDefaultIntegrations,
79
spanStreamingIntegration,
810
} from '../build/esm/index.js';
911
import type { DenoOptions } from '../build/esm/index.js';
@@ -82,3 +84,39 @@ Deno.test("init doesn't write the computed default integrations back onto the op
8284
const names = second.getOptions().integrations.map(i => i.name);
8385
assertArrayIncludes(names, ['Graphql']);
8486
});
87+
88+
Deno.test('initWithoutDefaultIntegrations sets up only the integrations the user passes', () => {
89+
getCurrentScope().setClient(undefined);
90+
const client = initWithoutDefaultIntegrations({
91+
tracesSampleRate: 1,
92+
traceLifecycle: 'static',
93+
integrations: [spanStreamingIntegration()],
94+
});
95+
const names = client.getOptions().integrations.map(i => i.name);
96+
assertEquals(names, ['SpanStreaming']);
97+
});
98+
99+
Deno.test('initWithoutDefaultIntegrations keeps defaultIntegrations the user passes', () => {
100+
getCurrentScope().setClient(undefined);
101+
const client = initWithoutDefaultIntegrations({
102+
traceLifecycle: 'static',
103+
defaultIntegrations: getDefaultIntegrationsWithoutPerformance(),
104+
});
105+
const names = client.getOptions().integrations.map(i => i.name);
106+
assertArrayIncludes(names, ['Breadcrumbs', 'DenoServe', 'Express']);
107+
});
108+
109+
Deno.test('getDefaultIntegrationsWithoutPerformance leaves out the tracing set', () => {
110+
const names = getDefaultIntegrationsWithoutPerformance().map(i => i.name);
111+
assertArrayIncludes(names, ['Breadcrumbs', 'DenoServe', 'Express', 'Fastify']);
112+
assert(!names.includes('Graphql'));
113+
assert(!names.includes('Postgres'));
114+
assert(!names.includes('OpenAI'));
115+
});
116+
117+
Deno.test('getDefaultIntegrations is getDefaultIntegrationsWithoutPerformance plus the tracing set', () => {
118+
const base = getDefaultIntegrationsWithoutPerformance().map(i => i.name);
119+
const full = getDefaultIntegrations({ tracesSampleRate: 1 }).map(i => i.name);
120+
assertEquals(full.slice(0, base.length), base);
121+
assertArrayIncludes(full.slice(base.length), ['Graphql', 'Postgres', 'OpenAI']);
122+
});

0 commit comments

Comments
 (0)