index.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import type {Config} from 'sentry/types/system';
  2. import {extractSlug} from 'sentry/utils/extractSlug';
  3. const BOOTSTRAP_URL = '/api/client-config/';
  4. const bootApplication = (data: Config) => {
  5. window.csrfCookieName = data.csrfCookieName;
  6. window.superUserCookieName = data.superUserCookieName;
  7. window.superUserCookieDomain = data.superUserCookieDomain ?? undefined;
  8. return data;
  9. };
  10. /**
  11. * Load the client configuration data using the BOOTSTRAP_URL. Used when
  12. * running in standalone SPA mode.
  13. */
  14. async function bootWithHydration() {
  15. const response = await fetch(BOOTSTRAP_URL);
  16. const data: Config = await response.json();
  17. // Shim up the initialData payload to quack like it came from
  18. // a customer-domains initial request. Because our initial call to BOOTSTRAP_URL
  19. // will not be on a customer domain, the response will not include this context.
  20. if (data.customerDomain === null && window.__SENTRY_DEV_UI) {
  21. const domain = extractSlug(window.location.host);
  22. if (domain) {
  23. data.customerDomain = {
  24. organizationUrl: `https://${domain.slug}.sentry.io`,
  25. sentryUrl: 'https://sentry.io',
  26. subdomain: domain.slug,
  27. };
  28. }
  29. }
  30. window.__initialData = data;
  31. bootApplication(data);
  32. preloadOrganizationData(data);
  33. return data;
  34. }
  35. function promiseRequest(url: string): Promise<any> {
  36. return new Promise(function (resolve, reject) {
  37. const xhr = new XMLHttpRequest();
  38. xhr.open('GET', url);
  39. xhr.setRequestHeader('sentry-trace', window.__initialData.initialTrace.sentry_trace);
  40. xhr.setRequestHeader('baggage', window.__initialData.initialTrace.baggage);
  41. xhr.withCredentials = true;
  42. xhr.onload = function () {
  43. try {
  44. this.status >= 200 && this.status < 300
  45. ? resolve([JSON.parse(xhr.response), this.statusText, xhr])
  46. : reject([this.status, this.statusText]);
  47. } catch (e) {
  48. reject();
  49. }
  50. };
  51. xhr.onerror = function () {
  52. reject([this.status, this.statusText]);
  53. };
  54. xhr.send();
  55. });
  56. }
  57. function preloadOrganizationData(config: Config) {
  58. if (!config.user) {
  59. // Don't send requests if there is no logged in user.
  60. return;
  61. }
  62. let slug = config.lastOrganization;
  63. if (!slug && config.customerDomain) {
  64. slug = config.customerDomain.subdomain;
  65. }
  66. let host = '';
  67. if (config.links?.regionUrl && config.links?.regionUrl !== config.links?.sentryUrl) {
  68. host = config.links.regionUrl;
  69. }
  70. // When running in 'dev-ui' mode we need to use /region/$region instead of
  71. // subdomains so that webpack/vercel can proxy requests.
  72. if (host && window.__SENTRY_DEV_UI) {
  73. const domainpattern = /https?\:\/\/([^.]*)\.sentry.io/;
  74. const domainmatch = host.match(domainpattern);
  75. if (domainmatch) {
  76. host = `/region/${domainmatch[1]}`;
  77. }
  78. }
  79. function makeUrl(suffix: string) {
  80. return host + '/api/0/organizations/' + slug + suffix;
  81. }
  82. const preloadPromises: Record<string, any> = {orgSlug: slug};
  83. window.__sentry_preload = preloadPromises;
  84. try {
  85. if (!slug) {
  86. return;
  87. }
  88. preloadPromises.organization = promiseRequest(
  89. makeUrl('/?detailed=0&include_feature_flags=1')
  90. );
  91. preloadPromises.projects = promiseRequest(
  92. makeUrl('/projects/?all_projects=1&collapse=latestDeploys&collapse=unusedFeatures')
  93. );
  94. preloadPromises.teams = promiseRequest(makeUrl('/teams/'));
  95. } catch (e) {
  96. // eslint-disable-next-line
  97. console.error(e);
  98. }
  99. }
  100. /**
  101. * Load client configuration bootstrap data. This will detect if the app is
  102. * running in SPA mode or being booted from the django-rendered layout.html
  103. * template.
  104. */
  105. export async function bootstrap() {
  106. const bootstrapData = window.__initialData;
  107. // If __initialData is not already set on the window, we are likely running in
  108. // pure SPA mode, meaning django is not serving our frontend application and we
  109. // need to make an API request to hydrate the bootstrap data to boot the app.
  110. if (bootstrapData === undefined) {
  111. return await bootWithHydration();
  112. }
  113. return bootApplication(bootstrapData);
  114. }