{"version":3,"file":"index.js","sources":["../../../src/constants/index.ts","../../../src/core/sendFeedback.ts","../../../src/util/debug-build.ts","../../../src/util/isScreenshotSupported.ts","../../../src/util/mergeOptions.ts","../../../src/core/components/Actor.css.ts","../../../src/util/setAttributesNS.ts","../../../src/core/components/FeedbackIcon.ts","../../../src/core/components/Actor.ts","../../../src/core/createMainStyles.ts","../../../src/core/integration.ts","../../../src/core/getFeedback.ts","../../../../../node_modules/preact/dist/preact.mjs","../../../../../node_modules/preact/hooks/dist/hooks.mjs","../../../src/modal/components/SentryLogo.ts","../../../src/modal/components/DialogHeader.tsx","../../../src/util/validate.ts","../../../src/modal/components/Form.tsx","../../../src/modal/components/SuccessIcon.ts","../../../src/modal/components/Dialog.tsx","../../../src/modal/components/Dialog.css.ts","../../../src/modal/integration.tsx","../../../src/screenshot/components/IconClose.tsx","../../../src/screenshot/components/ScreenshotInput.css.ts","../../../src/screenshot/components/Toolbar.tsx","../../../src/screenshot/components/useTakeScreenshot.tsx","../../../src/screenshot/components/ScreenshotEditor.tsx","../../../src/screenshot/integration.ts"],"sourcesContent":["import { GLOBAL_OBJ } from '@sentry/core';\n\n// exporting a separate copy of `WINDOW` rather than exporting the one from `@sentry/browser`\n// prevents the browser package from being bundled in the CDN bundle, and avoids a\n// circular dependency between the browser and feedback packages\nexport const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\nexport const DOCUMENT = WINDOW.document;\nexport const NAVIGATOR = WINDOW.navigator;\n\nexport const TRIGGER_LABEL = 'Report a Bug';\nexport const CANCEL_BUTTON_LABEL = 'Cancel';\nexport const SUBMIT_BUTTON_LABEL = 'Send Bug Report';\nexport const CONFIRM_BUTTON_LABEL = 'Confirm';\nexport const FORM_TITLE = 'Report a Bug';\nexport const EMAIL_PLACEHOLDER = 'your.email@example.org';\nexport const EMAIL_LABEL = 'Email';\nexport const MESSAGE_PLACEHOLDER = \"What's the bug? What did you expect?\";\nexport const MESSAGE_LABEL = 'Description';\nexport const NAME_PLACEHOLDER = 'Your Name';\nexport const NAME_LABEL = 'Name';\nexport const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!';\nexport const IS_REQUIRED_LABEL = '(required)';\nexport const ADD_SCREENSHOT_LABEL = 'Add a screenshot';\nexport const REMOVE_SCREENSHOT_LABEL = 'Remove screenshot';\nexport const HIGHLIGHT_TOOL_TEXT = 'Highlight';\nexport const HIDE_TOOL_TEXT = 'Hide';\nexport const REMOVE_HIGHLIGHT_TEXT = 'Remove';\n\nexport const FEEDBACK_WIDGET_SOURCE = 'widget';\nexport const FEEDBACK_API_SOURCE = 'api';\n\nexport const SUCCESS_MESSAGE_TIMEOUT = 5000;\n","import type { Event, EventHint, SendFeedback, SendFeedbackParams, TransportMakeRequestResponse } from '@sentry/core';\nimport { captureFeedback, getClient, getCurrentScope, getLocationHref } from '@sentry/core';\nimport { FEEDBACK_API_SOURCE } from '../constants';\n\n/**\n * Public API to send a Feedback item to Sentry\n */\nexport const sendFeedback: SendFeedback = (\n params: SendFeedbackParams,\n hint: EventHint & { includeReplay?: boolean } = { includeReplay: true },\n): Promise => {\n if (!params.message) {\n throw new Error('Unable to submit feedback with empty message');\n }\n\n // We want to wait for the feedback to be sent (or not)\n const client = getClient();\n\n if (!client) {\n throw new Error('No client setup, cannot send feedback.');\n }\n\n if (params.tags && Object.keys(params.tags).length) {\n getCurrentScope().setTags(params.tags);\n }\n const eventId = captureFeedback(\n {\n source: FEEDBACK_API_SOURCE,\n url: getLocationHref(),\n ...params,\n },\n hint,\n );\n\n // We want to wait for the feedback to be sent (or not)\n return new Promise((resolve, reject) => {\n // After 30s, we want to clear anyhow\n const timeout = setTimeout(() => reject('Unable to determine if Feedback was correctly sent.'), 30_000);\n\n const cleanup = client.on('afterSendEvent', (event: Event, response: TransportMakeRequestResponse) => {\n if (event.event_id !== eventId) {\n return;\n }\n\n clearTimeout(timeout);\n cleanup();\n\n // Require valid status codes, otherwise can assume feedback was not sent successfully\n if (response?.statusCode && response.statusCode >= 200 && response.statusCode < 300) {\n return resolve(eventId);\n }\n\n if (response?.statusCode === 403) {\n return reject(\n 'Unable to send feedback. This could be because this domain is not in your list of allowed domains.',\n );\n }\n\n return reject(\n 'Unable to send feedback. This could be because of network issues, or because you are using an ad-blocker.',\n );\n });\n });\n};\n\n/*\n * For reference, the fully built event looks something like this:\n * {\n * \"type\": \"feedback\",\n * \"event_id\": \"d2132d31b39445f1938d7e21b6bf0ec4\",\n * \"timestamp\": 1597977777.6189718,\n * \"dist\": \"1.12\",\n * \"platform\": \"javascript\",\n * \"environment\": \"production\",\n * \"release\": 42,\n * \"tags\": {\"transaction\": \"/organizations/:orgId/performance/:eventSlug/\"},\n * \"sdk\": {\"name\": \"name\", \"version\": \"version\"},\n * \"user\": {\n * \"id\": \"123\",\n * \"username\": \"user\",\n * \"email\": \"user@site.com\",\n * \"ip_address\": \"192.168.11.12\",\n * },\n * \"request\": {\n * \"url\": None,\n * \"headers\": {\n * \"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\"\n * },\n * },\n * \"contexts\": {\n * \"feedback\": {\n * \"message\": \"test message\",\n * \"contact_email\": \"test@example.com\",\n * \"type\": \"feedback\",\n * },\n * \"trace\": {\n * \"trace_id\": \"4C79F60C11214EB38604F4AE0781BFB2\",\n * \"span_id\": \"FA90FDEAD5F74052\",\n * \"type\": \"trace\",\n * },\n * \"replay\": {\n * \"replay_id\": \"e2d42047b1c5431c8cba85ee2a8ab25d\",\n * },\n * },\n * }\n */\n","declare const __DEBUG_BUILD__: boolean;\n\n/**\n * 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.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n","import { NAVIGATOR } from '../constants';\n\n/**\n * Mobile browsers do not support `mediaDevices.getDisplayMedia` even though they have the api implemented\n * Instead they return things like `NotAllowedError` when called.\n *\n * It's simpler for us to browser sniff first, and avoid loading the integration if we can.\n *\n * https://stackoverflow.com/a/58879212\n * https://stackoverflow.com/a/3540295\n *\n * `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.\n *\n * https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia\n */\nexport function isScreenshotSupported(): boolean {\n if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(NAVIGATOR.userAgent)) {\n return false;\n }\n /**\n * User agent on iPads show as Macintosh, so we need extra checks\n *\n * https://forums.developer.apple.com/forums/thread/119186\n * https://stackoverflow.com/questions/60482650/how-to-detect-ipad-useragent-on-safari-browser\n */\n if (/Macintosh/i.test(NAVIGATOR.userAgent) && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 1) {\n return false;\n }\n if (!isSecureContext) {\n return false;\n }\n return true;\n}\n","import type { FeedbackFormData, FeedbackInternalOptions } from '@sentry/core';\nimport type { OptionalFeedbackConfiguration } from '../core/types';\n\n/**\n * Quick and dirty deep merge for the Feedback integration options\n */\nexport function mergeOptions(\n defaultOptions: FeedbackInternalOptions,\n optionOverrides: OptionalFeedbackConfiguration,\n): FeedbackInternalOptions {\n return {\n ...defaultOptions,\n ...optionOverrides,\n tags: {\n ...defaultOptions.tags,\n ...optionOverrides.tags,\n },\n onFormOpen: () => {\n optionOverrides.onFormOpen?.();\n defaultOptions.onFormOpen?.();\n },\n onFormClose: () => {\n optionOverrides.onFormClose?.();\n defaultOptions.onFormClose?.();\n },\n onSubmitSuccess: (data: FeedbackFormData, eventId: string) => {\n optionOverrides.onSubmitSuccess?.(data, eventId);\n defaultOptions.onSubmitSuccess?.(data, eventId);\n },\n onSubmitError: (error: Error) => {\n optionOverrides.onSubmitError?.(error);\n defaultOptions.onSubmitError?.(error);\n },\n onFormSubmitted: () => {\n optionOverrides.onFormSubmitted?.();\n defaultOptions.onFormSubmitted?.();\n },\n themeDark: {\n ...defaultOptions.themeDark,\n ...optionOverrides.themeDark,\n },\n themeLight: {\n ...defaultOptions.themeLight,\n ...optionOverrides.themeLight,\n },\n };\n}\n","import { DOCUMENT } from '../../constants';\n\n/**\n * Creates