getErrorDebugIds.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import * as Sentry from '@sentry/react';
  2. const fileDebugIdCache = new Map<string, string>();
  3. /**
  4. * This function simulates having a browser API that takes an error and returns
  5. * a map of filenames and debug IDs for the error's stack trace.
  6. *
  7. * A real browser API would probably not be async - we need it to be async
  8. * because internally, this functions works by refetching source files to read
  9. * the debug ID comment at the bottom from the file's contents.
  10. *
  11. * RFC related to this: https://github.com/getsentry/rfcs/blob/main/text/0081-sourcemap-debugid.md
  12. */
  13. export async function getErrorDebugIds(e: Error): Promise<{[filename: string]: string}> {
  14. if (!e.stack) {
  15. return {};
  16. }
  17. const stackFrames = Sentry.defaultStackParser(e.stack);
  18. const debugIdMap: Record<string, string> = {};
  19. const fetchTaskGenerators = stackFrames.map(stackFrame => async () => {
  20. if (!stackFrame.filename) {
  21. return;
  22. }
  23. const cacheEntry = fileDebugIdCache.get(stackFrame.filename);
  24. if (cacheEntry) {
  25. debugIdMap[stackFrame.filename] = cacheEntry;
  26. return;
  27. }
  28. try {
  29. const text = await fetch(stackFrame.filename).then(res => res.text());
  30. const debugIdMatch = text.match(/^\/\/# debugId=(\S+)/im);
  31. if (!debugIdMatch) {
  32. return;
  33. }
  34. fileDebugIdCache.set(stackFrame.filename, debugIdMatch[1]);
  35. debugIdMap[stackFrame.filename] = debugIdMatch[1];
  36. } catch {
  37. // noop
  38. return;
  39. }
  40. });
  41. const worker = async () => {
  42. let fetchTaskGenerator = fetchTaskGenerators.pop();
  43. while (fetchTaskGenerator) {
  44. await fetchTaskGenerator();
  45. fetchTaskGenerator = fetchTaskGenerators.pop();
  46. }
  47. };
  48. // Only fetch 5 files at once
  49. await Promise.all([worker(), worker(), worker(), worker(), worker()]);
  50. return debugIdMap;
  51. }