Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const core = require('@sentry/core'); // exporting a separate copy of `WINDOW` rather than exporting the one from `@sentry/browser` // prevents the browser package from being bundled in the CDN bundle, and avoids a // circular dependency between the browser and feedback packages const WINDOW = core.GLOBAL_OBJ ; const DOCUMENT = WINDOW.document; const NAVIGATOR = WINDOW.navigator; const TRIGGER_LABEL = 'Report a Bug'; const CANCEL_BUTTON_LABEL = 'Cancel'; const SUBMIT_BUTTON_LABEL = 'Send Bug Report'; const CONFIRM_BUTTON_LABEL = 'Confirm'; const FORM_TITLE = 'Report a Bug'; const EMAIL_PLACEHOLDER = 'your.email@example.org'; const EMAIL_LABEL = 'Email'; const MESSAGE_PLACEHOLDER = "What's the bug? What did you expect?"; const MESSAGE_LABEL = 'Description'; const NAME_PLACEHOLDER = 'Your Name'; const NAME_LABEL = 'Name'; const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!'; const IS_REQUIRED_LABEL = '(required)'; const ADD_SCREENSHOT_LABEL = 'Add a screenshot'; const REMOVE_SCREENSHOT_LABEL = 'Remove screenshot'; const HIGHLIGHT_TOOL_TEXT = 'Highlight'; const HIDE_TOOL_TEXT = 'Hide'; const REMOVE_HIGHLIGHT_TEXT = 'Remove'; const FEEDBACK_WIDGET_SOURCE = 'widget'; const FEEDBACK_API_SOURCE = 'api'; const SUCCESS_MESSAGE_TIMEOUT = 5000; /** * Public API to send a Feedback item to Sentry */ const sendFeedback = ( params, hint = { includeReplay: true }, ) => { if (!params.message) { throw new Error('Unable to submit feedback with empty message'); } // We want to wait for the feedback to be sent (or not) const client = core.getClient(); if (!client) { throw new Error('No client setup, cannot send feedback.'); } if (params.tags && Object.keys(params.tags).length) { core.getCurrentScope().setTags(params.tags); } const eventId = core.captureFeedback( { source: FEEDBACK_API_SOURCE, url: core.getLocationHref(), ...params, }, hint, ); // We want to wait for the feedback to be sent (or not) return new Promise((resolve, reject) => { // After 30s, we want to clear anyhow const timeout = setTimeout(() => reject('Unable to determine if Feedback was correctly sent.'), 30000); const cleanup = client.on('afterSendEvent', (event, response) => { if (event.event_id !== eventId) { return; } clearTimeout(timeout); cleanup(); // Require valid status codes, otherwise can assume feedback was not sent successfully if (response?.statusCode && response.statusCode >= 200 && response.statusCode < 300) { return resolve(eventId); } if (response?.statusCode === 403) { return reject( 'Unable to send feedback. This could be because this domain is not in your list of allowed domains.', ); } return reject( 'Unable to send feedback. This could be because of network issues, or because you are using an ad-blocker.', ); }); }); }; /* * For reference, the fully built event looks something like this: * { * "type": "feedback", * "event_id": "d2132d31b39445f1938d7e21b6bf0ec4", * "timestamp": 1597977777.6189718, * "dist": "1.12", * "platform": "javascript", * "environment": "production", * "release": 42, * "tags": {"transaction": "/organizations/:orgId/performance/:eventSlug/"}, * "sdk": {"name": "name", "version": "version"}, * "user": { * "id": "123", * "username": "user", * "email": "user@site.com", * "ip_address": "192.168.11.12", * }, * "request": { * "url": None, * "headers": { * "user-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15" * }, * }, * "contexts": { * "feedback": { * "message": "test message", * "contact_email": "test@example.com", * "type": "feedback", * }, * "trace": { * "trace_id": "4C79F60C11214EB38604F4AE0781BFB2", * "span_id": "FA90FDEAD5F74052", * "type": "trace", * }, * "replay": { * "replay_id": "e2d42047b1c5431c8cba85ee2a8ab25d", * }, * }, * } */ /** * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code. * * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking. */ const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__); /** * Mobile browsers do not support `mediaDevices.getDisplayMedia` even though they have the api implemented * Instead they return things like `NotAllowedError` when called. * * It's simpler for us to browser sniff first, and avoid loading the integration if we can. * * https://stackoverflow.com/a/58879212 * https://stackoverflow.com/a/3540295 * * `mediaDevices.getDisplayMedia` is also only supported in secure contexts, and return a `mediaDevices is not supported` error, so we should also avoid loading the integration if we can. * * https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia */ function isScreenshotSupported() { if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(NAVIGATOR.userAgent)) { return false; } /** * User agent on iPads show as Macintosh, so we need extra checks * * https://forums.developer.apple.com/forums/thread/119186 * https://stackoverflow.com/questions/60482650/how-to-detect-ipad-useragent-on-safari-browser */ if (/Macintosh/i.test(NAVIGATOR.userAgent) && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 1) { return false; } if (!isSecureContext) { return false; } return true; } /** * Quick and dirty deep merge for the Feedback integration options */ function mergeOptions( defaultOptions, optionOverrides, ) { return { ...defaultOptions, ...optionOverrides, tags: { ...defaultOptions.tags, ...optionOverrides.tags, }, onFormOpen: () => { optionOverrides.onFormOpen?.(); defaultOptions.onFormOpen?.(); }, onFormClose: () => { optionOverrides.onFormClose?.(); defaultOptions.onFormClose?.(); }, onSubmitSuccess: (data, eventId) => { optionOverrides.onSubmitSuccess?.(data, eventId); defaultOptions.onSubmitSuccess?.(data, eventId); }, onSubmitError: (error) => { optionOverrides.onSubmitError?.(error); defaultOptions.onSubmitError?.(error); }, onFormSubmitted: () => { optionOverrides.onFormSubmitted?.(); defaultOptions.onFormSubmitted?.(); }, themeDark: { ...defaultOptions.themeDark, ...optionOverrides.themeDark, }, themeLight: { ...defaultOptions.themeLight, ...optionOverrides.themeLight, }, }; } /** * Creates