Object.defineProperty(exports, '__esModule', { value: true }); const utils = require('@sentry/utils'); 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 = utils.GLOBAL_OBJ ; const LIGHT_BACKGROUND = '#ffffff'; const INHERIT = 'inherit'; const SUBMIT_COLOR = 'rgba(108, 95, 199, 1)'; const LIGHT_THEME = { fontFamily: "system-ui, 'Helvetica Neue', Arial, sans-serif", fontSize: '14px', background: LIGHT_BACKGROUND, backgroundHover: '#f6f6f7', foreground: '#2b2233', border: '1.5px solid rgba(41, 35, 47, 0.13)', borderRadius: '12px', boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', success: '#268d75', error: '#df3338', submitBackground: 'rgba(88, 74, 192, 1)', submitBackgroundHover: SUBMIT_COLOR, submitBorder: SUBMIT_COLOR, submitOutlineFocus: '#29232f', submitForeground: LIGHT_BACKGROUND, submitForegroundHover: LIGHT_BACKGROUND, cancelBackground: 'transparent', cancelBackgroundHover: 'var(--background-hover)', cancelBorder: 'var(--border)', cancelOutlineFocus: 'var(--input-outline-focus)', cancelForeground: 'var(--foreground)', cancelForegroundHover: 'var(--foreground)', inputBackground: INHERIT, inputForeground: INHERIT, inputBorder: 'var(--border)', inputOutlineFocus: SUBMIT_COLOR, formBorderRadius: '20px', formContentBorderRadius: '6px', }; const DEFAULT_THEME = { light: LIGHT_THEME, dark: { ...LIGHT_THEME, background: '#29232f', backgroundHover: '#352f3b', foreground: '#ebe6ef', border: '1.5px solid rgba(235, 230, 239, 0.15)', success: '#2da98c', error: '#f55459', }, }; const ACTOR_LABEL = 'Report a Bug'; const CANCEL_BUTTON_LABEL = 'Cancel'; const SUBMIT_BUTTON_LABEL = 'Send Bug Report'; 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 FEEDBACK_WIDGET_SOURCE = 'widget'; const FEEDBACK_API_SOURCE = 'api'; /** * Prepare a feedback event & enrich it with the SDK metadata. */ async function prepareFeedbackEvent({ client, scope, event, }) { const eventHint = {}; if (client.emit) { client.emit('preprocessEvent', event, eventHint); } const preparedEvent = (await core.prepareEvent( client.getOptions(), event, eventHint, scope, client, core.getIsolationScope(), )) ; if (preparedEvent === null) { // Taken from baseclient's `_processEvent` method, where this is handled for errors/transactions client.recordDroppedEvent('event_processor', 'feedback', event); return null; } // This normally happens in browser client "_prepareEvent" // but since we do not use this private method from the client, but rather the plain import // we need to do this manually. preparedEvent.platform = preparedEvent.platform || 'javascript'; return preparedEvent; } /** * Send feedback using transport */ async function sendFeedbackRequest( { feedback: { message, email, name, source, url } }, { includeReplay = true } = {}, ) { const client = core.getClient(); const transport = client && client.getTransport(); const dsn = client && client.getDsn(); if (!client || !transport || !dsn) { return; } const baseEvent = { contexts: { feedback: { contact_email: email, name, message, url, source, }, }, type: 'feedback', }; return core.withScope(async scope => { // No use for breadcrumbs in feedback scope.clearBreadcrumbs(); if ([FEEDBACK_API_SOURCE, FEEDBACK_WIDGET_SOURCE].includes(String(source))) { scope.setLevel('info'); } const feedbackEvent = await prepareFeedbackEvent({ scope, client, event: baseEvent, }); if (!feedbackEvent) { return; } if (client.emit) { client.emit('beforeSendFeedback', feedbackEvent, { includeReplay: Boolean(includeReplay) }); } const envelope = core.createEventEnvelope(feedbackEvent, dsn, client.getOptions()._metadata, client.getOptions().tunnel); let response; try { response = await transport.send(envelope); } catch (err) { const error = new Error('Unable to send Feedback'); try { // In case browsers don't allow this property to be writable // @ts-expect-error This needs lib es2022 and newer error.cause = err; } catch (e) { // nothing to do } throw error; } // TODO (v8): we can remove this guard once transport.send's type signature doesn't include void anymore if (!response) { return; } // Require valid status codes, otherwise can assume feedback was not sent successfully if (typeof response.statusCode === 'number' && (response.statusCode < 200 || response.statusCode >= 300)) { throw new Error('Unable to send Feedback'); } return response; }); } /* * 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", * }, * }, * } */ /** * Public API to send a Feedback item to Sentry */ function sendFeedback( { name, email, message, source = FEEDBACK_API_SOURCE, url = utils.getLocationHref() }, options = {}, ) { if (!message) { throw new Error('Unable to submit feedback with empty message'); } return sendFeedbackRequest( { feedback: { name, email, message, url, source, }, }, options, ); } /** * 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__); /** * Quick and dirty deep merge for the Feedback integration options */ function mergeOptions( defaultOptions, optionOverrides, ) { return { ...defaultOptions, ...optionOverrides, themeDark: { ...defaultOptions.themeDark, ...optionOverrides.themeDark, }, themeLight: { ...defaultOptions.themeLight, ...optionOverrides.themeLight, }, }; } /** * Creates