fetch.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { fill } from '../object.js';
  2. import { supportsNativeFetch } from '../supports.js';
  3. import { GLOBAL_OBJ } from '../worldwide.js';
  4. import { addHandler, maybeInstrument, triggerHandlers } from './_handlers.js';
  5. /**
  6. * Add an instrumentation handler for when a fetch request happens.
  7. * The handler function is called once when the request starts and once when it ends,
  8. * which can be identified by checking if it has an `endTimestamp`.
  9. *
  10. * Use at your own risk, this might break without changelog notice, only used internally.
  11. * @hidden
  12. */
  13. function addFetchInstrumentationHandler(handler) {
  14. const type = 'fetch';
  15. addHandler(type, handler);
  16. maybeInstrument(type, instrumentFetch);
  17. }
  18. function instrumentFetch() {
  19. if (!supportsNativeFetch()) {
  20. return;
  21. }
  22. fill(GLOBAL_OBJ, 'fetch', function (originalFetch) {
  23. return function (...args) {
  24. const { method, url } = parseFetchArgs(args);
  25. const handlerData = {
  26. args,
  27. fetchData: {
  28. method,
  29. url,
  30. },
  31. startTimestamp: Date.now(),
  32. };
  33. triggerHandlers('fetch', {
  34. ...handlerData,
  35. });
  36. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
  37. return originalFetch.apply(GLOBAL_OBJ, args).then(
  38. (response) => {
  39. const finishedHandlerData = {
  40. ...handlerData,
  41. endTimestamp: Date.now(),
  42. response,
  43. };
  44. triggerHandlers('fetch', finishedHandlerData);
  45. return response;
  46. },
  47. (error) => {
  48. const erroredHandlerData = {
  49. ...handlerData,
  50. endTimestamp: Date.now(),
  51. error,
  52. };
  53. triggerHandlers('fetch', erroredHandlerData);
  54. // NOTE: If you are a Sentry user, and you are seeing this stack frame,
  55. // it means the sentry.javascript SDK caught an error invoking your application code.
  56. // This is expected behavior and NOT indicative of a bug with sentry.javascript.
  57. throw error;
  58. },
  59. );
  60. };
  61. });
  62. }
  63. function hasProp(obj, prop) {
  64. return !!obj && typeof obj === 'object' && !!(obj )[prop];
  65. }
  66. function getUrlFromResource(resource) {
  67. if (typeof resource === 'string') {
  68. return resource;
  69. }
  70. if (!resource) {
  71. return '';
  72. }
  73. if (hasProp(resource, 'url')) {
  74. return resource.url;
  75. }
  76. if (resource.toString) {
  77. return resource.toString();
  78. }
  79. return '';
  80. }
  81. /**
  82. * Parses the fetch arguments to find the used Http method and the url of the request.
  83. * Exported for tests only.
  84. */
  85. function parseFetchArgs(fetchArgs) {
  86. if (fetchArgs.length === 0) {
  87. return { method: 'GET', url: '' };
  88. }
  89. if (fetchArgs.length === 2) {
  90. const [url, options] = fetchArgs ;
  91. return {
  92. url: getUrlFromResource(url),
  93. method: hasProp(options, 'method') ? String(options.method).toUpperCase() : 'GET',
  94. };
  95. }
  96. const arg = fetchArgs[0];
  97. return {
  98. url: getUrlFromResource(arg ),
  99. method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET',
  100. };
  101. }
  102. export { addFetchInstrumentationHandler, parseFetchArgs };
  103. //# sourceMappingURL=fetch.js.map