Skip to content

Commit 22b9a47

Browse files
authored
fix(core): Always instantiate global Error class in injected code snippets (#594)
Ensures that we always use the `Error` class explicitly from the global object instead of the "ambient" `Error` class. The reason is that users (or as reported frameworks) are free to name their own classes "Error" in which case the file injection would instantiate the user-created and not the global class.
1 parent 6993888 commit 22b9a47

File tree

7 files changed

+84
-4
lines changed

7 files changed

+84
-4
lines changed

packages/bundler-plugin-core/sentry-esbuild-debugid-injection-file.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ try {
88
? self
99
: {};
1010

11-
var stack = new Error().stack;
11+
var stack = new globalObject.Error().stack;
1212

1313
if (stack) {
1414
globalObject._sentryDebugIds = globalObject._sentryDebugIds || {};

packages/bundler-plugin-core/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ export function createComponentNameAnnotateHooks() {
673673
}
674674

675675
export function getDebugIdSnippet(debugId: string): string {
676-
return `;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="${debugId}",e._sentryDebugIdIdentifier="sentry-dbid-${debugId}")}catch(e){}}();`;
676+
return `;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="${debugId}",e._sentryDebugIdIdentifier="sentry-dbid-${debugId}")}catch(e){}}();`;
677677
}
678678

679679
export { stringToUUID, replaceBooleanFlagsInCode } from "./utils";

packages/bundler-plugin-core/src/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,10 @@ export function generateModuleMetadataInjectorCode(metadata: any) {
351351
_sentryModuleMetadataGlobal._sentryModuleMetadata =
352352
_sentryModuleMetadataGlobal._sentryModuleMetadata || {};
353353
354-
_sentryModuleMetadataGlobal._sentryModuleMetadata[new Error().stack] =
354+
_sentryModuleMetadataGlobal._sentryModuleMetadata[new _sentryModuleMetadataGlobal.Error().stack] =
355355
Object.assign(
356356
{},
357-
_sentryModuleMetadataGlobal._sentryModuleMetadata[new Error().stack],
357+
_sentryModuleMetadataGlobal._sentryModuleMetadata[new _sentryModuleMetadataGlobal.Error().stack],
358358
${JSON.stringify(metadata)}
359359
);
360360
}`;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getDebugIdSnippet } from "../src";
2+
3+
describe("getDebugIdSnippet", () => {
4+
it("returns the debugId injection snippet for a passed debugId", () => {
5+
const snippet = getDebugIdSnippet("1234");
6+
expect(snippet).toMatchInlineSnapshot(
7+
`";!function(){try{var e=\\"undefined\\"!=typeof window?window:\\"undefined\\"!=typeof global?global:\\"undefined\\"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]=\\"1234\\",e._sentryDebugIdIdentifier=\\"sentry-dbid-1234\\")}catch(e){}}();"`
8+
);
9+
});
10+
});

packages/bundler-plugin-core/test/utils.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
generateModuleMetadataInjectorCode,
23
getDependencies,
34
getPackageJson,
45
parseMajorVersion,
@@ -214,3 +215,64 @@ if (false && true) {
214215
});
215216
});
216217
});
218+
219+
describe("generateModuleMetadataInjectorCode", () => {
220+
it("generates code with empty metadata object", () => {
221+
const generatedCode = generateModuleMetadataInjectorCode({});
222+
expect(generatedCode).toMatchInlineSnapshot(`
223+
"{
224+
var _sentryModuleMetadataGlobal =
225+
typeof window !== \\"undefined\\"
226+
? window
227+
: typeof global !== \\"undefined\\"
228+
? global
229+
: typeof self !== \\"undefined\\"
230+
? self
231+
: {};
232+
233+
_sentryModuleMetadataGlobal._sentryModuleMetadata =
234+
_sentryModuleMetadataGlobal._sentryModuleMetadata || {};
235+
236+
_sentryModuleMetadataGlobal._sentryModuleMetadata[new _sentryModuleMetadataGlobal.Error().stack] =
237+
Object.assign(
238+
{},
239+
_sentryModuleMetadataGlobal._sentryModuleMetadata[new _sentryModuleMetadataGlobal.Error().stack],
240+
{}
241+
);
242+
}"
243+
`);
244+
});
245+
246+
it("generates code with metadata object", () => {
247+
const generatedCode = generateModuleMetadataInjectorCode({
248+
"file1.js": {
249+
foo: "bar",
250+
},
251+
"file2.js": {
252+
bar: "baz",
253+
},
254+
});
255+
expect(generatedCode).toMatchInlineSnapshot(`
256+
"{
257+
var _sentryModuleMetadataGlobal =
258+
typeof window !== \\"undefined\\"
259+
? window
260+
: typeof global !== \\"undefined\\"
261+
? global
262+
: typeof self !== \\"undefined\\"
263+
? self
264+
: {};
265+
266+
_sentryModuleMetadataGlobal._sentryModuleMetadata =
267+
_sentryModuleMetadataGlobal._sentryModuleMetadata || {};
268+
269+
_sentryModuleMetadataGlobal._sentryModuleMetadata[new _sentryModuleMetadataGlobal.Error().stack] =
270+
Object.assign(
271+
{},
272+
_sentryModuleMetadataGlobal._sentryModuleMetadata[new _sentryModuleMetadataGlobal.Error().stack],
273+
{\\"file1.js\\":{\\"foo\\":\\"bar\\"},\\"file2.js\\":{\\"bar\\":\\"baz\\"}}
274+
);
275+
}"
276+
`);
277+
});
278+
});

packages/integration-tests/fixtures/debug-id-injection/debug-id-injection.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ function checkBundle(bundlePath1: string, bundlePath2: string): string[] {
1313
expect.stringMatching(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/)
1414
);
1515

16+
expect(Object.keys(debugIdMap1)[0]).toContain("Error");
17+
1618
const process2Output = childProcess.execSync(`node ${bundlePath2}`, { encoding: "utf-8" });
1719
const debugIdMap2 = JSON.parse(process2Output) as Record<string, string>;
1820
const debugIds2 = Object.values(debugIdMap2);
@@ -21,6 +23,8 @@ function checkBundle(bundlePath1: string, bundlePath2: string): string[] {
2123
expect.stringMatching(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/)
2224
);
2325

26+
expect(Object.keys(debugIdMap2)[0]).toContain("Error");
27+
2428
expect(debugIds1).not.toEqual(debugIds2);
2529

2630
return [...debugIds1, ...debugIds2];

packages/integration-tests/fixtures/metadata-injection/metadata-injection.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ function checkBundle(bundlePath: string): void {
1313
expect(Object.values(map)).toHaveLength(1);
1414
// The value should be the expected metadata
1515
expect(Object.values(map)).toEqual([{ team: "frontend" }]);
16+
17+
// The key is the stack trace of the error thrown in the file
18+
expect(Object.keys(map)[0]).toContain("Error");
19+
expect(Object.keys(map)[0]).toContain("bundle.js");
1620
}
1721

1822
describe("metadata injection", () => {

0 commit comments

Comments
 (0)