Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions packages/plugins/error-tracking/src/sourcemaps/debugId.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,48 @@ describe('extractDebugId', () => {
await expect(extractDebugId(filePath)).resolves.toBe(debugId);
});

test('Should extract the debug ID when the value is wrapped in single quotes (some minifiers emit single-quoted strings)', async () => {
const filePath = path.join(tempDir, 'single-quoted-value.min.js');
outputFileSync(
filePath,
`!function(){}({service:"app",version:"1.0.0",ddDebugId:'${debugId}'},"DD_SOURCE_CODE_CONTEXT");`,
);

await expect(extractDebugId(filePath)).resolves.toBe(debugId);
});

test('Should extract the debug ID when the key is quoted and the value is single-quoted', async () => {
const filePath = path.join(tempDir, 'mixed-quotes.min.js');
outputFileSync(
filePath,
`!function(){}({"service":"app","version":"1.0.0","ddDebugId":'${debugId}'},"DD_SOURCE_CODE_CONTEXT");`,
);

await expect(extractDebugId(filePath)).resolves.toBe(debugId);
});

test('Should extract the debug ID when the value is wrapped in backticks (some minifiers use template-literal-style strings)', async () => {
const filePath = path.join(tempDir, 'backticked-value.min.js');
outputFileSync(
filePath,
'!function(){}' +
`({service:"app",version:"1.0.0",ddDebugId:\`${debugId}\`},` +
'"DD_SOURCE_CODE_CONTEXT");',
);

await expect(extractDebugId(filePath)).resolves.toBe(debugId);
});

test('Should return undefined when the opening and closing quotes do not match', async () => {
const filePath = path.join(tempDir, 'mismatched-quotes.min.js');
outputFileSync(
filePath,
`!function(){}({service:"app",version:"1.0.0",ddDebugId:'${debugId}"},"DD_SOURCE_CODE_CONTEXT");`,
);

await expect(extractDebugId(filePath)).resolves.toBeUndefined();
});

test('Should stop reading after finding the debug ID in the first chunk', async () => {
const filePath = path.join(tempDir, 'first-chunk.min.js');
const literal = `ddDebugId:"${debugId}"`;
Expand Down
12 changes: 7 additions & 5 deletions packages/plugins/error-tracking/src/sourcemaps/debugId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import fsp from 'fs/promises';
// (see packages/plugins/rum/src/getSourceCodeContextSnippet.ts). The key is quoted in source
// (`JSON.stringify(context)`) but minifiers like terser strip quotes from object keys that are
// valid identifiers, so the built output can have either `"ddDebugId":"..."` or `ddDebugId:"..."`.
// Reading it back out of the file we're about to upload means we never have to trust a filename
// as a coordination key between the RUM plugin and this one, so it stays correct across any
// bundler renaming step.
const DEBUG_ID_RX = /"?ddDebugId"?:"([0-9a-fA-F-]{36})"/;
// The value can also end up wrapped in single quotes or backticks depending on the minifier, so all
// three of `"`, `'` and `` ` `` are accepted around it. The opening quote is captured and
// backreferenced so the closing quote must match it. Reading it back out of the file we're about to
// upload means we never have to trust a filename as a coordination key between the RUM plugin and
// this one, so it stays correct across any bundler renaming step.
const DEBUG_ID_RX = /"?ddDebugId"?:(["'`])([0-9a-fA-F-]{36})\1/;

// Read progressively so the common case only needs the first KiB, while still supporting
// bundlers or transforms that place the injected snippet later in the artifact.
Expand All @@ -22,7 +24,7 @@ export const DEBUG_ID_SEARCH_CHUNK_BYTES = 1024;
const DEBUG_ID_SEARCH_OVERLAP_CHARACTERS = 64;

const matchDebugId = (fileContent: string): string | undefined => {
return DEBUG_ID_RX.exec(fileContent)?.[1];
return DEBUG_ID_RX.exec(fileContent)?.[2];
};

// Search in fixed-size reads and stop as soon as the debug ID is found. Only a small overlap is
Expand Down
Loading