Skip to content

Commit d826f1d

Browse files
chargomeandreiborza
authored andcommitted
Revert "fix(nextjs): Avoid Edge build warning from OpenTelemetry `process.arg…"
This reverts commit fae3a77.
1 parent ccccb05 commit d826f1d

File tree

7 files changed

+75
-240
lines changed

7 files changed

+75
-240
lines changed

packages/nextjs/src/common/utils/dropMiddlewareTunnelRequests.ts

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import { SEMATTRS_HTTP_TARGET } from '@opentelemetry/semantic-conventions';
2-
import {
3-
getClient,
4-
GLOBAL_OBJ,
5-
isSentryRequestUrl,
6-
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
7-
type Span,
8-
type SpanAttributes,
9-
} from '@sentry/core';
2+
import { GLOBAL_OBJ, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, type Span, type SpanAttributes } from '@sentry/core';
3+
import { isSentryRequestSpan } from '@sentry/opentelemetry';
104
import { ATTR_NEXT_SPAN_TYPE } from '../nextSpanAttributes';
115
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../span-attributes-with-logic-attached';
126

@@ -42,36 +36,6 @@ export function dropMiddlewareTunnelRequests(span: Span, attrs: SpanAttributes |
4236
}
4337
}
4438

45-
/**
46-
* Local copy of `@sentry/opentelemetry`'s `isSentryRequestSpan`, to avoid pulling the whole package into Edge bundles.
47-
*/
48-
function isSentryRequestSpan(span: Span): boolean {
49-
const attributes = spanToAttributes(span);
50-
if (!attributes) {
51-
return false;
52-
}
53-
54-
const httpUrl = attributes['http.url'] || attributes['url.full'];
55-
if (!httpUrl) {
56-
return false;
57-
}
58-
59-
return isSentryRequestUrl(httpUrl.toString(), getClient());
60-
}
61-
62-
function spanToAttributes(span: Span): Record<string, unknown> | undefined {
63-
// OTEL spans expose attributes in different shapes depending on implementation.
64-
// We only need best-effort read access.
65-
type MaybeSpanAttributes = {
66-
attributes?: Record<string, unknown>;
67-
_attributes?: Record<string, unknown>;
68-
};
69-
70-
const maybeSpan = span as unknown as MaybeSpanAttributes;
71-
const attrs = maybeSpan.attributes || maybeSpan._attributes;
72-
return attrs;
73-
}
74-
7539
/**
7640
* Checks if a span's HTTP target matches the tunnel route.
7741
*/

packages/nextjs/src/edge/index.ts

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// import/export got a false positive, and affects most of our index barrel files
22
// can be removed once following issue is fixed: https://github.com/import-js/eslint-plugin-import/issues/703
33
/* eslint-disable import/export */
4-
import { context, createContextKey } from '@opentelemetry/api';
4+
import { context } from '@opentelemetry/api';
55
import {
66
applySdkMetadata,
77
type EventProcessor,
@@ -12,14 +12,14 @@ import {
1212
getRootSpan,
1313
GLOBAL_OBJ,
1414
registerSpanErrorInstrumentation,
15-
type Scope,
1615
SEMANTIC_ATTRIBUTE_SENTRY_OP,
1716
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
1817
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
1918
setCapturedScopesOnSpan,
2019
spanToJSON,
2120
stripUrlQueryAndFragment,
2221
} from '@sentry/core';
22+
import { getScopesFromContext } from '@sentry/opentelemetry';
2323
import type { VercelEdgeOptions } from '@sentry/vercel-edge';
2424
import { getDefaultIntegrations, init as vercelEdgeInit } from '@sentry/vercel-edge';
2525
import { DEBUG_BUILD } from '../common/debug-build';
@@ -42,32 +42,6 @@ export { wrapApiHandlerWithSentry } from './wrapApiHandlerWithSentry';
4242

4343
export type EdgeOptions = VercelEdgeOptions;
4444

45-
type CurrentScopes = {
46-
scope: Scope;
47-
isolationScope: Scope;
48-
};
49-
50-
// This key must match `@sentry/opentelemetry`'s `SENTRY_SCOPES_CONTEXT_KEY`.
51-
// We duplicate it here so the Edge bundle does not need to import the full `@sentry/opentelemetry` package.
52-
const SENTRY_SCOPES_CONTEXT_KEY = createContextKey('sentry_scopes');
53-
54-
type ContextWithGetValue = {
55-
getValue(key: unknown): unknown;
56-
};
57-
58-
function getScopesFromContext(otelContext: unknown): CurrentScopes | undefined {
59-
if (!otelContext || typeof otelContext !== 'object') {
60-
return undefined;
61-
}
62-
63-
const maybeContext = otelContext as Partial<ContextWithGetValue>;
64-
if (typeof maybeContext.getValue !== 'function') {
65-
return undefined;
66-
}
67-
68-
return maybeContext.getValue(SENTRY_SCOPES_CONTEXT_KEY) as CurrentScopes | undefined;
69-
}
70-
7145
const globalWithInjectedValues = GLOBAL_OBJ as typeof GLOBAL_OBJ & {
7246
_sentryRewriteFramesDistDir?: string;
7347
_sentryRelease?: string;

packages/opentelemetry/src/constants.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ export const SENTRY_TRACE_STATE_URL = 'sentry.url';
99
export const SENTRY_TRACE_STATE_SAMPLE_RAND = 'sentry.sample_rand';
1010
export const SENTRY_TRACE_STATE_SAMPLE_RATE = 'sentry.sample_rate';
1111

12-
// NOTE: `@sentry/nextjs` has a local copy of this context key for Edge bundles:
13-
// - `packages/nextjs/src/edge/index.ts` (`SENTRY_SCOPES_CONTEXT_KEY`)
14-
//
15-
// If you change the key name passed to `createContextKey(...)`, update that file too.
1612
export const SENTRY_SCOPES_CONTEXT_KEY = createContextKey('sentry_scopes');
1713

1814
export const SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY = createContextKey('sentry_fork_isolation_scope');

packages/opentelemetry/src/utils/contextData.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ const SCOPE_CONTEXT_FIELD = '_scopeContext';
1111
* This requires a Context Manager that was wrapped with getWrappedContextManager.
1212
*/
1313
export function getScopesFromContext(context: Context): CurrentScopes | undefined {
14-
// NOTE: `@sentry/nextjs` has a local copy of this helper for Edge bundles:
15-
// - `packages/nextjs/src/edge/index.ts` (`getScopesFromContext`)
16-
//
17-
// If you change how scopes are stored/read (key or retrieval), update that file too.
1814
return context.getValue(SENTRY_SCOPES_CONTEXT_KEY) as CurrentScopes | undefined;
1915
}
2016

packages/opentelemetry/src/utils/isSentryRequest.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ import { spanHasAttributes } from './spanTypes';
99
* @returns boolean
1010
*/
1111
export function isSentryRequestSpan(span: AbstractSpan): boolean {
12-
// NOTE: `@sentry/nextjs` has a local copy of this helper for Edge bundles:
13-
// - `packages/nextjs/src/common/utils/dropMiddlewareTunnelRequests.ts` (`isSentryRequestSpan`)
14-
//
15-
// If you change supported OTEL attribute keys or request detection logic, update that file too.
1612
if (!spanHasAttributes(span)) {
1713
return false;
1814
}
Lines changed: 71 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,79 @@
11
import replace from '@rollup/plugin-replace';
22
import { makeBaseNPMConfig, makeNPMConfigVariants, plugins } from '@sentry-internal/rollup-utils';
33

4-
const downlevelLogicalAssignmentsPlugin = {
5-
name: 'downlevel-logical-assignments',
6-
renderChunk(code) {
7-
// ES2021 logical assignment operators (`||=`, `&&=`, `??=`) are not allowed by our ES2020 compatibility check.
8-
// OTEL currently ships some of these, so we downlevel them in the final output.
9-
//
10-
// Note: This is intentionally conservative (only matches property access-like LHS) to avoid duplicating side effects.
11-
// IMPORTANT: Use regex literals (not `String.raw` + `RegExp(...)`) to avoid accidental double-escaping.
12-
let out = code;
13-
14-
// ??=
15-
out = out.replace(/([A-Za-z_$][\w$]*(?:\[[^\]]+\]|\.[A-Za-z_$][\w$]*)+)\s*\?\?=\s*([^;]+);/g, (_m, left, right) => {
16-
return `${left} = ${left} ?? ${right};`;
17-
});
18-
19-
// ||=
20-
out = out.replace(/([A-Za-z_$][\w$]*(?:\[[^\]]+\]|\.[A-Za-z_$][\w$]*)+)\s*\|\|=\s*([^;]+);/g, (_m, left, right) => {
21-
return `${left} = ${left} || ${right};`;
22-
});
23-
24-
// &&=
25-
out = out.replace(/([A-Za-z_$][\w$]*(?:\[[^\]]+\]|\.[A-Za-z_$][\w$]*)+)\s*&&=\s*([^;]+);/g, (_m, left, right) => {
26-
return `${left} = ${left} && ${right};`;
27-
});
28-
29-
return { code: out, map: null };
30-
},
31-
};
32-
33-
const baseConfig = makeBaseNPMConfig({
34-
entrypoints: ['src/index.ts'],
35-
bundledBuiltins: ['perf_hooks', 'util'],
36-
packageSpecificConfig: {
37-
context: 'globalThis',
38-
output: {
39-
preserveModules: false,
40-
},
41-
plugins: [
42-
plugins.makeCommonJSPlugin({ transformMixedEsModules: true }), // Needed because various modules in the OTEL toolchain use CJS (require-in-the-middle, shimmer, etc..)
43-
plugins.makeJsonPlugin(), // Needed because `require-in-the-middle` imports json via require
44-
replace({
45-
preventAssignment: true,
46-
values: {
47-
'process.argv0': JSON.stringify(''), // needed because otel relies on process.argv0 for the default service name, but that api is not available in the edge runtime.
48-
},
49-
}),
50-
{
51-
// This plugin is needed because otel imports `performance` from `perf_hooks` and also uses it via the `performance` global.
52-
// It also imports `inspect` and `promisify` from node's `util` which are not available in the edge runtime so we need to define a polyfill.
53-
// Both of these APIs are not available in the edge runtime so we need to define a polyfill.
54-
// Vercel does something similar in the `@vercel/otel` package: https://github.com/vercel/otel/blob/087601ae585cb116bb2b46c211d014520de76c71/packages/otel/build.ts#L62
55-
name: 'edge-runtime-polyfills',
56-
banner: `
57-
{
58-
if (globalThis.performance === undefined) {
59-
globalThis.performance = {
60-
timeOrigin: 0,
61-
now: () => Date.now()
62-
};
63-
}
64-
}
65-
`,
66-
resolveId: source => {
67-
if (source === 'perf_hooks') {
68-
return '\0perf_hooks_sentry_shim';
69-
} else if (source === 'util') {
70-
return '\0util_sentry_shim';
71-
} else {
72-
return null;
73-
}
74-
},
75-
load: id => {
76-
if (id === '\0perf_hooks_sentry_shim') {
77-
return `
78-
export const performance = {
79-
timeOrigin: 0,
80-
now: () => Date.now()
4+
export default makeNPMConfigVariants(
5+
makeBaseNPMConfig({
6+
entrypoints: ['src/index.ts'],
7+
bundledBuiltins: ['perf_hooks', 'util'],
8+
packageSpecificConfig: {
9+
context: 'globalThis',
10+
output: {
11+
preserveModules: false,
12+
},
13+
plugins: [
14+
plugins.makeCommonJSPlugin({ transformMixedEsModules: true }), // Needed because various modules in the OTEL toolchain use CJS (require-in-the-middle, shimmer, etc..)
15+
plugins.makeJsonPlugin(), // Needed because `require-in-the-middle` imports json via require
16+
replace({
17+
preventAssignment: true,
18+
values: {
19+
'process.argv0': JSON.stringify(''), // needed because otel relies on process.argv0 for the default service name, but that api is not available in the edge runtime.
20+
},
21+
}),
22+
{
23+
// This plugin is needed because otel imports `performance` from `perf_hooks` and also uses it via the `performance` global.
24+
// It also imports `inspect` and `promisify` from node's `util` which are not available in the edge runtime so we need to define a polyfill.
25+
// Both of these APIs are not available in the edge runtime so we need to define a polyfill.
26+
// Vercel does something similar in the `@vercel/otel` package: https://github.com/vercel/otel/blob/087601ae585cb116bb2b46c211d014520de76c71/packages/otel/build.ts#L62
27+
name: 'edge-runtime-polyfills',
28+
banner: `
29+
{
30+
if (globalThis.performance === undefined) {
31+
globalThis.performance = {
32+
timeOrigin: 0,
33+
now: () => Date.now()
34+
};
8135
}
82-
`;
83-
} else if (id === '\0util_sentry_shim') {
84-
return `
85-
export const inspect = (object) =>
86-
JSON.stringify(object, null, 2);
36+
}
37+
`,
38+
resolveId: source => {
39+
if (source === 'perf_hooks') {
40+
return '\0perf_hooks_sentry_shim';
41+
} else if (source === 'util') {
42+
return '\0util_sentry_shim';
43+
} else {
44+
return null;
45+
}
46+
},
47+
load: id => {
48+
if (id === '\0perf_hooks_sentry_shim') {
49+
return `
50+
export const performance = {
51+
timeOrigin: 0,
52+
now: () => Date.now()
53+
}
54+
`;
55+
} else if (id === '\0util_sentry_shim') {
56+
return `
57+
export const inspect = (object) =>
58+
JSON.stringify(object, null, 2);
8759
88-
export const promisify = (fn) => {
89-
return (...args) => {
90-
return new Promise((resolve, reject) => {
91-
fn(...args, (err, result) => {
92-
if (err) reject(err);
93-
else resolve(result);
60+
export const promisify = (fn) => {
61+
return (...args) => {
62+
return new Promise((resolve, reject) => {
63+
fn(...args, (err, result) => {
64+
if (err) reject(err);
65+
else resolve(result);
66+
});
9467
});
95-
});
68+
};
9669
};
97-
};
98-
`;
99-
} else {
100-
return null;
101-
}
70+
`;
71+
} else {
72+
return null;
73+
}
74+
},
10275
},
103-
},
104-
downlevelLogicalAssignmentsPlugin,
105-
],
106-
},
107-
});
108-
109-
// `makeBaseNPMConfig` marks dependencies/peers as external by default.
110-
// For Edge, we must ensure the OTEL SDK bits which reference `process.argv0` are bundled so our replace() plugin applies.
111-
const baseExternal = baseConfig.external;
112-
baseConfig.external = (source, importer, isResolved) => {
113-
// Never treat these as external - they need to be inlined so `process.argv0` can be replaced.
114-
if (
115-
source === '@opentelemetry/resources' ||
116-
source.startsWith('@opentelemetry/resources/') ||
117-
source === '@opentelemetry/sdk-trace-base' ||
118-
source.startsWith('@opentelemetry/sdk-trace-base/')
119-
) {
120-
return false;
121-
}
122-
123-
if (typeof baseExternal === 'function') {
124-
return baseExternal(source, importer, isResolved);
125-
}
126-
127-
if (Array.isArray(baseExternal)) {
128-
return baseExternal.includes(source);
129-
}
130-
131-
if (baseExternal instanceof RegExp) {
132-
return baseExternal.test(source);
133-
}
134-
135-
return false;
136-
};
137-
138-
export default makeNPMConfigVariants(baseConfig);
76+
],
77+
},
78+
}),
79+
);

packages/vercel-edge/test/build-artifacts.test.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)