\n );\n}\n\nCustomSnackbar.propTypes = {\n variant: PropTypes.oneOf(['success', 'warning', 'error', 'info']).isRequired,\n message: PropTypes.string,\n autoHideDuration: PropTypes.number,\n subtitleMessage: PropTypes.string,\n};\n","import React from 'react';\nimport { v2Colors } from '@web-for-marketing/react-ui';\n\nexport function NavErrorIcon(props: React.SVGProps): JSX.Element {\n return (\n \n );\n}\n","import React, { useState, useCallback } from 'react';\nimport { CustomSnackbar } from '../components/CustomSnackbar';\nimport { LoadingDialog } from '../components/LoadingDialog';\nimport PropTypes from 'prop-types';\n\nexport const NotificationContext = React.createContext();\n\nexport function NotificationProvider({ children, ...overrides }) {\n const [openSnackbar, setOpenSnackbar] = useState({\n state: false,\n variant: 'success',\n message: '',\n autoHideDuration: 6000,\n subtitleMessage: '',\n ...overrides,\n });\n const [loadingCount, setLoadingCount] = useState(0);\n\n const show = useCallback(\n (message, variant = 'info', autoHideDuration = 6000, subtitleMessage = '', ...overrides) => {\n setOpenSnackbar({ state: true, variant, message, autoHideDuration, subtitleMessage, ...overrides });\n },\n []\n );\n\n function showLoading() {\n setLoadingCount((count) => count + 1);\n }\n\n function hideLoading() {\n setLoadingCount((count) => (count > 0 ? count - 1 : 0));\n }\n\n function clearLoading() {\n setLoadingCount(0);\n }\n\n function isLoading() {\n return loadingCount > 0;\n }\n\n return (\n \n {children}\n \n \n \n );\n}\n\nNotificationProvider.propTypes = {\n children: PropTypes.node.isRequired,\n overrides: PropTypes.object,\n};\n","import { AccessibleFormHelper } from '@models/accessibleFormHelper';\n\nexport const bannerTitle = {\n name: 'Title',\n helperText: 'Edit the large main title text.',\n};\nexport const bannerDescription = {\n name: 'Description',\n helperText: 'Edit the smaller body text.',\n};\nexport const bannerList = {\n name: 'List',\n helperText: 'Create and remove list items to make a list.',\n};\nexport const bannerBackgroundImage = {\n name: 'Banner image',\n helperText: 'Open the gallery to change the image shown behind the gradient and all of the content.',\n};\nexport const bannerMobileBackgroundImage = {\n name: 'Mobile Background image',\n helperText: 'Open the gallery to change the mobile image shown behind the gradient and all of the content.',\n};\nexport const bannerBackgroundPosition = {\n name: 'Image position slider',\n helperText:\n 'Change the position of the image shown behind all of the content. You may not see horizontal changes if an image is landscape.',\n};\nexport const bannerButtonText = {\n name: 'Button text',\n helperText:\n 'Edit the text that goes on the button. Make sure the wording is concise and informs a user of the button\\'s purpose.',\n};\nexport const bannerButtonLink = {\n name: 'Button link',\n helperText: 'Edit the link location where the button will lead.',\n};\nexport const bannerButtonType = {\n name: 'Button type',\n helperText: 'Change the button\\'s style. Either solid blue or outlined in white.',\n};\nexport const bannerButtonTarget = {\n name: 'Open button link in new tab',\n helperText:\n 'Change whether or not the button will open links in a new tab. External links will always open in a new tab',\n};\nexport const bannerShowButton = {\n name: 'Show Button',\n helperText: 'Show or hide the button.',\n};\nexport const bannerButtonsAdd = {\n name: 'New Button',\n helperText: 'Create a new button on the banner.',\n};\nexport const bannerAdd = {\n name: 'New Banner',\n helperText: 'Insert a new banner in the scrolling banners.',\n};\nexport const bannerInfiniteScroll = {\n name: 'Infinite Scroll',\n helperText: 'Toggle infinite repeating scroll of banner',\n};\nexport const bannerAutoplay = {\n name: 'Autoplay banner',\n helperText: 'Toggle automatic scrolling of the banner.',\n};\nexport const bannerAutoplayDelay = {\n name: 'Autoplay Delay (milliseconds)',\n helperText: 'Toggle the rate at which the banner transitions in milliseconds.',\n};\nexport const testimonialAuthorRole = {\n name: 'Testimonial Role Title',\n helperText: 'Edit the testimonial role title.',\n};\nexport const bannerIsAnimated = {\n name: 'Animated',\n helperText: 'Toggle on or off the scrolling animation.',\n};\nexport const bannerGradientEnabled = {\n name: 'Remove Banner Gradient',\n helperText:\n 'Change whether or not the banner will have a blue gradient background with white text, or a white background with blue title and grey description text.',\n};\nexport const bannerItalicEnabled = {\n name: 'Enable Italic Font Style',\n helperText: 'Change whether or not the description will have an italic font style.',\n};\nexport const bannerButtonsText = (index?: number): AccessibleFormHelper => {\n return {\n name: `Button ${index ? index + 1 : ''} text`,\n helperText: `Edit the text that goes on the ${\n index ? (index === 0 ? 'first ' : 'second ') : ''\n }button. Make sure the wording is concise and informs a user of the button's purpose.`,\n };\n};\nexport const bannerButtonsLink = (index?: number): AccessibleFormHelper => {\n return {\n name: `Button ${index ? index + 1 : ''} link`,\n helperText: `Edit the link location where the ${\n index ? (index === 0 ? 'first ' : 'second ') : ''\n }button will lead.`,\n };\n};\nexport const bannerButtonsType = (index?: number): AccessibleFormHelper => {\n return {\n name: `Button ${index ? index + 1 : ''} type`,\n helperText: `Change the ${index ? (index === 0 ? 'first ' : 'second ') : ''}button's style.`,\n };\n};\nexport const bannerButtonsTarget = (index?: number): AccessibleFormHelper => {\n return {\n name: `Button ${index ? index + 1 : ''} link in new tab`,\n helperText: `Change whether or not the ${\n index && index < 2 ? (index === 0 ? 'first ' : 'second ') : ''\n }button will open links in a new tab.`,\n };\n};\nexport const bannerShowButtons = (index: number): AccessibleFormHelper => {\n return {\n name: `Show button ${index ? index + 1 : ''}`,\n helperText: `Show or hide the ${index ? (index === 0 ? 'first ' : 'second ') : ''}button.`,\n };\n};\nexport const bannerParallax = {\n name: 'Parallax ',\n helperText: 'Change whether or not the image will scroll with the page or have a parallax effect.',\n};\nexport const columnCheckBoxText = {\n name: 'Checkbox text ',\n helperText: 'Edit the text that appears next to the checkbox that enables the button.',\n};\nexport const enableConfirmationCheckBox = {\n name: 'Enable confirmation checkbox',\n helperText: 'Toggle to show or hide the confirmation checkbox features.',\n};\nexport const bannerCustomCssEnabled = {\n name: 'Custom CSS Gradient',\n helperText:\n 'Enter the css code for a \"linear gradient\" to be applied to the banner. Ex. linear-gradient(-90deg, rgba(1, 23, 41, 0) 0%, rgb(1, 23, 41) 100%).',\n};\nexport const columnTitle = {\n name: 'Title',\n helperText: 'Edit the main large blue title text above the main content.',\n};\nexport const columnSubtitle = {\n name: 'Subtitle',\n helperText: 'Edit the small grey text above the title.',\n};\nexport const columnName = {\n name: 'Name',\n helperText: 'Edit the name text, either include first name or full name.',\n};\nexport const columnBody = {\n name: 'Body',\n helperText: 'Edit the grey body text.',\n};\nexport const columnHtml = {\n name: 'Html content',\n helperText: 'Use caution when entering HTML. This section will render any HTML code.',\n};\nexport const columnMedia = {\n name: 'Media embed link',\n helperText: 'Enter an embed link to any form of media, if it is youtube be sure to use the embed link.',\n};\nexport const columnLink = {\n name: 'Link',\n helperText: 'Edit the link location where the blue bold link text will lead.',\n};\nexport const columnLinkText = {\n name: 'Link text',\n helperText:\n 'Edit the clickable bolded blue link text shown underneath the body text. Make sure the wording is concise and informs a user of the button\\'s purpose.',\n};\nexport const columnLinkTarget = {\n name: 'Open Link in new tab',\n helperText: 'Change whether or not the above link will open in a new tab.',\n};\nexport const columnSideType = {\n name: 'Content type',\n helperText: 'Change the type of content that is shown, changes the layout and what content is used.',\n};\nexport const columnSideSwap = {\n name: 'Swap',\n helperText: 'Swap the content from one of the sides to the other.',\n};\nexport const columnSideSpace = {\n name: 'Section spacing',\n helperText: 'The space above and below this section.',\n};\nexport const columnMobileSwap = {\n name: 'Swap mobile stacking order',\n helperText: 'Reverses the order the modules stack on mobile.',\n};\n\nexport const image = {\n name: 'Image',\n helperText: 'Opens the gallery to change the main image.',\n};\nexport const mobileImage = {\n name: 'Mobile image',\n helperText: 'Opens the gallery to change the mobile image.',\n};\nexport const alignment = {\n name: 'Content alignment',\n helperText: 'Change the direction in which the content aligns and flows.',\n};\nexport const featuresAlignment = {\n name: 'Features alignment',\n helperText: 'Change the direction in which the features are aligned',\n};\nexport const titleAlign = {\n name: 'Title alignment',\n helperText: 'Change the alignment of the title.',\n};\nexport const textAlign = {\n name: 'Text alignment',\n helperText: 'Change the alignment of the text.',\n};\nexport const sectionAnimations = {\n name: 'Animations',\n helperText: 'Enables customizable animations on the section information, which are triggered automatically.',\n};\nexport const sectionBorder = {\n name: 'Section Border',\n helperText: 'Creates a thin border above or below the section.',\n};\nexport const columnShowForm = {\n name: 'Show Form',\n helperText: 'Show or hide the submission form, and button.',\n};\nexport const columnFormInfo = {\n name: 'Form Description',\n helperText: 'Change the small description and notices beneath the form and button.',\n};\nexport const columnFormText = {\n name: 'Form Text',\n helperText: 'Change the text that will go both inside and above the input form.',\n};\nexport const columnFormSetting = {\n name: 'Form Setting',\n helperText:\n 'Change the settings used by selected forms. Form key include: html-form-id, marketing-cloud-form-id, form-title, submit-button-text.',\n};\nexport const columnRating = {\n name: 'Rating',\n helperText: 'Add a rating in star form (out of 5).',\n};\nexport const columnButton = {\n name: 'Enable button',\n helperText: 'Toggle to show or hide the button.',\n};\nexport const columnPortrait = {\n name: 'Portrait picture',\n helperText: 'Add a new picture in portrait form.',\n};\nexport const formSelection = {\n name: 'Form Selection',\n helperText: 'Select which form should be displayed',\n};\nexport const formLeadSource = {\n name: 'Lead Source',\n helperText:\n 'Change a hidden field that sends information to salesforce, indicating the type/page/campaign this form is used. ',\n};\nexport const formInquirytype = {\n name: 'Inquiry Type',\n helperText: 'Changes a hidden value that gets passed in a hidden text field, which will send to salesforce.',\n};\n\nexport const formVideoSource = {\n name: 'Video Source',\n helperText: 'Choose to add a video or html embedding in the two column section',\n};\nexport const formButtonText = {\n name: 'Button Text',\n helperText: 'Changes the text of the button in the two column section',\n};\nexport const formButtonLink = {\n name: 'Button Link',\n helperText: 'Edit the link location where the button will lead.',\n};\nexport const formButtonTarget = {\n name: 'Button Target',\n helperText:\n 'Change whether or not the button will open links in a new tab. External links will always open in a new tab',\n};\nexport const formReturnUrl = {\n name: 'Return URL',\n helperText: 'The page will be redirected to this url after a successful form submission.',\n};\nexport const formLanguageCategory = {\n name: 'Language Category',\n helperText: 'This is the pre-defined field from salesforce based on current language selection. ',\n};\nexport const formHeaderTitle = {\n name: 'Form Header Title',\n helperText: 'This is the blue title text that is shown on top of the form.',\n};\nexport const sectionStatus = (status: boolean): AccessibleFormHelper => {\n return {\n name: status ? 'Section online' : 'Section offline',\n helperText: 'Will make the section visible to the public, or hidden/offline.',\n };\n};\nexport const columnMultiSubtitle = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} title`,\n helperText: `Edit the small title on ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiTitle = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} title`,\n helperText: `Edit the small title on ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiBody = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} body text`,\n helperText: `Edit the smaller body text on ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiImage = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} image`,\n helperText: `Open the gallery to change the main image on ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiTitleLink = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} title link`,\n helperText: `Edit the smaller title link on ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiMedia = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} media`,\n helperText: `Open the gallery to change the main media file on ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiLink = (index: number, objectType: string, color?: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n if (color) {\n return {\n name: `${capitalObjectType} ${index + 1} link`,\n helperText: `Edit the link location where the ${color} link text will link to, on ${objectType} number ${\n index + 1\n }.`,\n };\n } else {\n return {\n name: `${capitalObjectType} ${index + 1} link`,\n helperText: `Edit the link location where the blue bold link text will lead on ${objectType} number ${\n index + 1\n }.`,\n };\n }\n};\nexport const columnMultiLinkText = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} link text`,\n helperText: `Edit the clickable bolded blue link text on ${objectType} number ${\n index + 1\n }. Make sure the wording is concise and informs a user of the button's purpose.`,\n };\n};\nexport const columnMultiLinkTarget = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} link in new tab`,\n helperText: `Change whether or not the link will open in a new tab for the text on ${objectType} number ${\n index + 1\n }.`,\n };\n};\nexport const columnMultiLinkTitleHover = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} hover title`,\n helperText: `Edit the hover title on ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiName = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} name`,\n helperText: `Edit the name that appears for ${objectType} number ${index + 1}.`,\n };\n};\nexport const columnMultiJobTitle = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} job title`,\n helperText: `Edit the grey text describing ${objectType} number ${index + 1}'s job title.`,\n };\n};\nexport const columnMultiDescription = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} biography`,\n helperText: `Edit the body text describing ${objectType} number ${index + 1} as an individual.`,\n };\n};\nexport const columnMultiTwitter = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} Twitter link`,\n helperText: `Edit the link to ${objectType} number ${index + 1}'s Twitter page.`,\n };\n};\nexport const columnMultiLinkedIn = (index: number, objectType: string): AccessibleFormHelper => {\n const capitalObjectType = objectType.charAt(0).toUpperCase() + objectType.slice(1);\n\n return {\n name: `${capitalObjectType} ${index + 1} LinkedIn link`,\n helperText: `Edit the link to ${objectType} number ${index + 1}'s LinkedIn page.`,\n };\n};\nexport const columnMultiButtonLink = (index: number): AccessibleFormHelper => {\n return {\n name: `Button ${index + 1} type`,\n helperText: `Change the button / link type of link ${index + 1}.`,\n };\n};\nexport const columnAddHoverCardBox = {\n name: 'Add a hover card box',\n helperText: 'Add a new hover card box to the collection of hover cards.',\n};\nexport const customizableGalleryStackType = {\n name: 'Stack type',\n helperText: 'Change the type of customizable multi-layout used.',\n};\nexport const threeColumnStackType = {\n name: 'Stack type',\n helperText: 'Change the type of three column card layout used.',\n};\nexport const columnAddThreeColumnCard = {\n name: 'Add a card',\n helperText: 'Add a new card to the collection of cards.',\n};\nexport const columnAddProfile = {\n name: 'Add a profile',\n helperText: 'Add a new profile to the collection of profiles.',\n};\nexport const columnAddFeature = {\n name: 'Add a feature',\n helperText: 'Add a new feature group to the collection of features.',\n};\nexport const columnAddLink = {\n name: 'Add a link',\n helperText: 'Add a new link to the collection of links.',\n};\nexport const columnAddRow = {\n name: 'Add a row',\n helperText: 'Add a new row to the collection of rows.',\n};\nexport const titleWidth = {\n name: 'Title Full Width',\n helperText: 'Make title stretch full width of the screen.',\n};\nexport const imageBoxType = {\n name: 'Four column type',\n helperText: 'Change the type of four column content that is displayed.',\n};\nexport const imageZoom = {\n name: 'Image Zoom',\n helperText: 'Enables ability to click on the image and view full size image in popup modal.',\n};\nexport const galleryNewImage = {\n name: 'New image',\n helperText: 'Add a new image to the collection of images in the gallery.',\n};\nexport const gallerySize = {\n name: 'Images\\' size',\n helperText: 'Change the size of the images/cards.',\n};\nexport const galleryAlign = {\n name: 'Images\\' alignment',\n helperText: 'Change the alignment of the images or cards.',\n};\nexport const galleryLinkEnabled = {\n name: 'Image has link',\n helperText: 'Change whether or not images will link to other pages.',\n};\nexport const customSectionType = {\n name: 'Custom section type',\n helperText: 'Select the component that will be used within this section.',\n};\nexport const videoSearch = {\n name: 'Video search',\n helperText: 'Type a video title to search for it and add it below.',\n};\nexport const featuresType = {\n name: 'Feature type',\n helperText: 'Change the type of of feature layout used.',\n};\nexport const openBottom = {\n name: 'Bottom spacing',\n helperText: 'Change the space on the bottom and whether or not there is a border on the last event.',\n};\nexport const pagePreview = {\n name: 'Public preview',\n helperText: 'Creates a locked un-indexed public preview page.',\n};\nexport const pagePreviewPassword = {\n name: 'Preview password* ',\n helperText: 'Enter the password that will be used for the preview page.',\n};\nexport const eventDates = {\n name: 'Event Dates',\n helperText: 'Type the dates that the event will take place. Follow a \"Month Day-Day, Year\" format.',\n};\nexport const ariaLabel = {\n name: 'Aria label',\n helperText:\n 'An optional informative description of where the link goes. Should be used if the link text itself is not descriptive enough (ex. Read more -> Read more about ...). Avoid saying \"click to\", or \"a link to\".',\n};\nexport const eventLocation = {\n name: 'Event Location',\n helperText: 'Type the location that the event will take place. Follow a \"Venue, City, Country\" format.',\n};\nexport const greyBackgroundEnabled = {\n name: 'Enable Grey Background',\n helperText: 'Change whether or not images/cards will have a white or grey background.',\n};\nexport const referenceId = {\n name: 'Reference Anchor ID',\n helperText: 'This id is used as an anchor for anchor links to jump to',\n};\nexport const buttonsAdd = {\n name: 'Add a new button',\n helperText: 'Add an additional button to the section.',\n};\nexport const buttonsClassName = {\n name: 'Button Class Name',\n helperText: 'Edit the class name of the button.',\n};\nexport const imageUrl = {\n name: 'Image url',\n helperText: '',\n};\nexport const imageAlt = {\n name: 'Image alt',\n helperText:\n 'Edit the alternative text for the image, describing the image in detail. Image alt should be more than 15 characters long.',\n};\nexport const mediaUrl = {\n name: 'Media Url',\n helperText: 'Enter an embed URL to a video or html.',\n};\nexport const mediaHeight = {\n name: 'Fixed height',\n helperText: 'Enter a fixed height for the media in pixels. Useful for page embeddings to avoid scrollbars.',\n};\nexport const mediaTitle = {\n name: 'Media title',\n helperText: 'Enter a short but descriptive title of what it is you are embedding.',\n};\nexport const iframeUrl = {\n name: 'Url',\n helperText:\n 'The url specified will be embedded into the page. Site security limits the url location of urls. Contact admin to authorize urls.',\n};\nexport const iframeWidth = (isMobile: boolean): AccessibleFormHelper => {\n return {\n name: `${isMobile ? ' Mobile w' : 'W'}idth`,\n helperText: `Set a fixed ${isMobile ? 'mobile ' : ''}width for the iframe. Default is 80%.`,\n };\n};\nexport const iframeHeight = (isMobile: boolean): AccessibleFormHelper => {\n return {\n name: `${isMobile ? ' Mobile h' : 'H'}eight`,\n helperText: `Set a fixed ${isMobile ? 'mobile ' : ''}height for the iframe. Default is 200px.`,\n };\n};\nexport const dateText = {\n name: 'Date',\n helperText: 'Select a date from the date picker popup',\n};\nexport const timeText = {\n name: 'Time',\n helperText: 'Select a time from the time picker popup',\n};\nexport const countdownDateTimeText = {\n name: 'Countdown Date and Time',\n helperText: 'Select a date and a time from the time picker popup',\n};\nexport const iframeBorder = {\n name: 'Iframe Border',\n helperText: 'Toggle the border that frames the iframe container.',\n};\nexport const iframeScale = (isMobile: boolean): AccessibleFormHelper => ({\n name: `Scale ${isMobile ? 'mobile' : ''} iframe`,\n helperText: `Adjust the ${isMobile ? 'mobile width' : 'width'} and ${\n isMobile ? 'mobile height' : 'height'\n } by keeping the ratio the same.`,\n});\nexport const accordionAddList = {\n name: 'Add accordion',\n helperText: 'Create a new collapsing accordion with a header and description',\n};\nexport const accordionType = (type: string): AccessibleFormHelper => ({\n name: `Accordion ${type} type`,\n helperText: `This \"${type} type\" should explain what the ${type} is. Example: Question, Answer, Description, Patent, Explanation, etc...`,\n});\nexport const accordionCategoryFilter = {\n name: 'Disable category filtering',\n helperText: 'Toggle this to disable the categories above the accordions.',\n};\nexport const accordionCategory = {\n name: 'Category',\n helperText:\n 'Write a category to enable grouping and filtering. Any same categories will be grouped and can be viewed if categories are enabled.',\n};\nexport const accordionStructuredDataEnable = {\n name: 'Enable structured data',\n helperText: 'Tick to enable structured data for crawlers.',\n};\nexport const accordionTitle = {\n name: 'Title',\n helperText:\n 'Edit the title for the accordion list. This will replace the category title if category filtering is enabled.',\n};\nexport const accordionAllFilter = {\n name: 'All filter',\n helperText:\n 'Edit the all category filter for the accordion list. This will replace the category all overview filter label if category filtering is enabled.',\n};\nexport const accordionLoadMore = {\n name: 'Load more',\n helperText:\n 'Edit the load more button text for the mobile accordion list. This will replace the button label if category filtering is enabled.',\n};\nexport const accordionHeading = {\n name: 'Heading',\n helperText: 'Edit the main heading text for this collapsable accordion element.',\n};\nexport const accordionDescription = {\n name: 'Description',\n helperText: 'Edit the inner description body text for this collapsable accordion element.',\n};\nexport const duplicatePage = {\n name: 'Duplicate page',\n helperText: 'View the options for creating a copy of the current page.',\n};\nexport const duplicate = (type: string): AccessibleFormHelper => {\n return {\n name: 'Duplicate',\n helperText: `Press the Duplicate button to create a copy of this ${type}.`,\n };\n};\nexport const adminTitle = {\n name: 'Page title',\n helperText: 'Enter a unique and descriptive title for the page. It should be between 20-70 characters.',\n};\nexport const adminDescription = {\n name: 'Description',\n helperText: 'Enter an informative description of the contents of the page. It should be less than 160 characters.',\n};\nexport const adminSlug = {\n name: 'Url slug',\n helperText: 'Enter a unique and valid URL slug; it should be short and concise and not use spaces.',\n};\nexport const adminLanguage = {\n name: 'Language',\n helperText: 'Select a language for the page locale to be set in (and grouped with similar pages).',\n};\nexport const adminRedirect = {\n name: 'Redirect Url',\n helperText: 'Enter a unique URL to redirect to when the current page is reached.',\n};\nexport const adminCanonical = {\n name: 'Canonical Url',\n helperText: 'Enter a unique URL which is the most representative URL for a set of similar pages.',\n};\nexport const adminNavbar = {\n name: 'Navbar',\n helperText: 'Select a custom navbar to be displayed on the page.',\n};\nexport const adminNavbarDropdownTitle = {\n name: 'Dropdown Title',\n helperText: 'Edit the title that will be displayed on the navbar and open the dropdown.',\n};\nexport const adminNavbarButtonStyle = {\n name: 'Button style',\n helperText: 'Select the button\\'s style and design.',\n};\nexport const adminNavbarCustomSettingName = {\n name: 'Setting name',\n helperText: 'Affect one of the above available settings to change something about the section.',\n};\nexport const adminNavbarCustomSettingValue = {\n name: 'Value',\n helperText: 'Edit the value for the setting specified to the left.',\n};\nexport const adminNavbarEnableSearch = {\n name: 'Enable Search',\n helperText: 'Enabling this shows the search icon and search bar.',\n};\nexport const adminNavbarEnableLanguageRegion = {\n name: 'Enable language/region link',\n helperText: 'Enabling this will show the link to change languages/regions.',\n};\nexport const adminNavbarEnableMicroNavigation = {\n name: 'Enable Micro navigation visibility',\n helperText: 'Enabling this will show top blue navigation',\n};\nexport const adminNavbarShowLoginButton = {\n name: 'Enable Login Button',\n helperText: 'Enabling this will show login button on micro navigation',\n};\nexport const adminNavbarAddLinkText = {\n name: 'Link Text',\n helperText: 'Edit the text for the link.',\n};\nexport const adminNavbarUrlLink = {\n name: 'Url link or Section id',\n helperText: 'Edit the link\\'s url or reference an existing \"Section Id\" (start ids with a #)',\n};\nexport const adminFooter = {\n name: 'Footer',\n helperText: 'Select a custom footer to be displayed on the page.',\n};\nexport const adminFooterLinkTitle = {\n name: 'Footer link title',\n helperText: 'Edit the title for the footer.',\n};\nexport const adminFooterLink = {\n name: 'Footer link',\n helperText: 'Add a url/link for the footer.',\n};\nexport const adminFooterLinkGroupTitle = {\n name: 'Group title',\n helperText: 'Edit the title that will be displayed above a group of footer links.',\n};\nexport const adminFooterLinkGroupColumn = {\n name: 'Column',\n helperText: 'Select which vertical column the link group will be placed in.',\n};\nexport const adminFooterLinkGroups = {\n name: 'Group links',\n helperText: 'Manage the footer links set within the group.',\n};\nexport const adminFooterSocialMediaLinkTitle = {\n name: 'Footer social media link tooltip title',\n helperText:\n 'Edit the title attribute for the footer social media link. This is used to provide extra information about the link for accessibility. Ex: \"Go to Geotab\\'s instagram page\"',\n};\nexport const adminFooterSocialMediaLinkUrl = {\n name: 'Footer social media link url/path',\n helperText: 'Edit the social media url/path for the footer social media link.',\n};\nexport const adminFooterCopyrightText = {\n name: 'Copyright text',\n helperText: 'Edit the small copyright text that appears at the bottom of the footer.',\n};\nexport const adminOnlineStatus = {\n name: 'Online',\n helperText: 'Toggle whether or not the page is online to the public.',\n};\nexport const adminIndex = {\n name: 'Indexed',\n helperText: 'Toggle whether or not the page will appear on searches and is indexed on the web.',\n};\nexport const isClientSideRedirect = {\n name: 'Client-Side Redirect',\n helperText: 'Toggle whether or not client-side redirect is used. When toggled on, Google Analytics can be used.',\n};\nexport const showInSiteSearch = {\n name: 'Show In Site Search',\n helperText: 'Toggle whether or not the redirected page will appear on global site searches',\n};\nexport const adminEnglishTitle = {\n name: 'English page title',\n helperText: 'Enter a unique and descriptive English title that helps describe the page.',\n};\nexport const adminDocumentName = {\n name: 'Document name',\n helperText: 'The name of the document. This will be used as the title and heading for this document\\'s page.',\n};\nexport const adminGoogleDocUrl = {\n name: 'Google doc url',\n helperText:\n 'A url for a public and shareable google document. Ex: https://docs.google.com/document/d/2PACX-1vQi86CV86PoxTTIsPcmtGdkFx/',\n};\nexport const adminGoogleDriveUrl = {\n name: 'Google drive url',\n helperText:\n 'A url for a public and shareable google drive file. Ex: https://drive.google.com/file/d/15rTnEtOCqYc0b9y/view?usp=sharing',\n};\nexport const adminYoutubeUrl = {\n name: 'Youtube url',\n helperText: 'A url for a public and shareable youtube video. Ex: https://www.youtube.com/watch?v=xru2PhwT7t0',\n};\nexport const adminVidyardUrl = {\n name: 'Vidyard url',\n helperText: 'A url for a public and shareable vidyard video. ',\n};\nexport const adminVideoTitle = {\n name: 'Video title',\n helperText: 'A unique and descriptive title for the video and page. It should be between 20-70 characters.',\n};\nexport const adminVideoDescription = {\n name: 'Video description',\n helperText: 'An informative description of the contents of the video.',\n};\nexport const enablePopoutCustomSection = {\n name: 'Enable popout custom section',\n helperText: 'Toggle whether or not the button will open a popout with a custom section when it is interacted with.',\n};\nexport const returnURL = {\n name: 'Return URL',\n helperText: 'Enter a \"return URL\" to redirect to after the form is submitted.',\n};\nexport const entityRedirectUrl = (type: string): AccessibleFormHelper => {\n return {\n name: 'Redirect Url',\n helperText: `Enter a unique URL to redirect to when the current ${type} is reached.`,\n };\n};\nexport const adminNavbarLanguage = (type: string): AccessibleFormHelper => {\n return {\n name: 'Language',\n helperText: `Select the region and language the ${type} will be used in.`,\n };\n};\nexport const adminNavbarMenuItems = (type: string): AccessibleFormHelper => {\n return {\n name: 'Menu Items',\n helperText: `Customize the ${type} with the available items.`,\n };\n};\nexport const adminDropDownMenuItems = {\n name: 'Dropdown Menu Items',\n helperText: 'Customize the dropdown with the available items.',\n};\nexport const articleLanguage = (type: string): AccessibleFormHelper => {\n return {\n name: 'Language',\n helperText: `Select a language for the ${type}. The language will determine which microsite the ${type} belongs to.`,\n };\n};\nexport const articleTitle = (type: string): AccessibleFormHelper => {\n return {\n name: `${type} Title`,\n helperText: `Enter a unique and descriptive title that helps describe the ${type}.`,\n };\n};\nexport const articlePageTitle = (type: string): AccessibleFormHelper => {\n return {\n name: 'Page Title',\n helperText: `Enter the page title associated with the ${type}.`,\n };\n};\nexport const articleEnglishPageTitle = (type: string): AccessibleFormHelper => {\n return {\n name: 'English Page Title',\n helperText: `Enter a unique and descriptive english title that helps describe the ${type}.`,\n };\n};\nexport const articleSummary = (type: string): AccessibleFormHelper => {\n return {\n name: 'Summary',\n helperText: `Enter an informative description about the contents of the ${type}.`,\n };\n};\nexport const slugEntityBreadcrumbDisplayName = (type = 'page'): AccessibleFormHelper => {\n return {\n name: 'Breadcrumb display name',\n helperText: `Enter a name to be displayed in the breadcrumb trail of the ${type}.`,\n };\n};\nexport const articleVideoSelection = (type: string): AccessibleFormHelper => {\n return {\n name: 'Video Selection',\n helperText: `Add up to 2 videos to your ${type} and arrange their order of display using the right side arrows.`,\n };\n};\nexport const articleMetaDescription = (type: string): AccessibleFormHelper => {\n return {\n name: 'Meta Description',\n helperText: `Enter an informative description that summarizes the contents of the ${type} for the benefit of users and search engines.`,\n };\n};\nexport const articleSlug = (type: string): AccessibleFormHelper => {\n return {\n name: 'Url Slug',\n helperText: `Enter a unique and valid URL slug for the ${type}; it should be short and concise and must have no spaces or symbols.`,\n };\n};\nexport const articleCanonical = (type: string): AccessibleFormHelper => {\n return {\n name: 'Canonical Url',\n helperText: `Enter a unique URL which is the most representative URL for a set of similar ${type}(s).`,\n };\n};\nexport const articleCardImage = (type: string): AccessibleFormHelper => {\n return {\n name: 'Card Image',\n helperText: `Select an image for the ${type}'s card on the website.`,\n };\n};\nexport const articleMobileCardImage = (type: string): AccessibleFormHelper => {\n return {\n name: 'Mobile Card Image',\n helperText: `Select an image for the ${type}'s card on the mobile website.`,\n };\n};\nexport const articleCardImageAlt = (type: string): AccessibleFormHelper => {\n return {\n name: 'Card Image Alt',\n helperText: `Enter an alternative text for the card image, describing the ${type}'s image in detail.`,\n };\n};\nexport const articleMobileCardImageAlt = (type: string): AccessibleFormHelper => {\n return {\n name: 'Mobile Card Image Alt',\n helperText: `Enter an alternative text for the mobile card image, describing the ${type}'s image in detail.`,\n };\n};\nexport const articleHeaderImage = (type: string): AccessibleFormHelper => {\n return {\n name: 'Header Image',\n helperText: `Select a banner image for the ${type} on the desktop version of the website.`,\n };\n};\nexport const articleMobileHeaderImage = (type: string): AccessibleFormHelper => {\n return {\n name: 'Mobile Header Image',\n helperText: `Select a banner image for the ${type} on the mobile version of the website.`,\n };\n};\nexport const articleMobileHeaderImageAlt = (type: string): AccessibleFormHelper => {\n return {\n name: 'Mobile Header Image Alt',\n helperText: `Enter an alternative text for the mobile header image, describing the ${type}'s image in detail.`,\n };\n};\nexport const articleHeaderImageAlt = (type: string): AccessibleFormHelper => {\n return {\n name: 'Header Image Alt',\n helperText: `Enter an alternative text for the header image, describing the ${type}'s image in detail.`,\n };\n};\nexport const articleHideMobileHeaderImageStatus = (type: string): AccessibleFormHelper => {\n return {\n name: 'Hide Mobile Header Image',\n helperText: `Toggle to hide the ${type}'s header image in mobile view.`,\n };\n};\nexport const articlePublishedStatus = (type: string): AccessibleFormHelper => {\n return {\n name: 'Published',\n helperText: `Toggle to publish the ${type} and make it publicly available.`,\n };\n};\nexport const articleFeaturedStatus = (type: string): AccessibleFormHelper => {\n return {\n name: 'Featured',\n helperText: `Toogle to ensure the ${type} appears in the feature section of its homepage.`,\n };\n};\nexport const articleEditorsPickStatus = (type: string): AccessibleFormHelper => {\n return {\n name: 'Editor\\'s Pick',\n helperText: `Toogle to ensure the ${type} appears in the editor's pick section of its homepage.`,\n };\n};\nexport const articleShowCardStatus = (type: string): AccessibleFormHelper => {\n return {\n name: 'Show Card',\n helperText: `Toggle to display the ${type} card on it public homepage.`,\n };\n};\nexport const articleIndexStatus = (type: string): AccessibleFormHelper => {\n return {\n name: 'No Index',\n helperText: `Toggle whether or not the ${type} will appear on searches and is indexed on the web.`,\n };\n};\nexport const articleNoFollowStatus = (type: string): AccessibleFormHelper => {\n return {\n name: 'No Follow',\n helperText: `Toggle to allow ${type} get credits when search engines rank this ${type} against other Geotab.com pages and articles.`,\n };\n};\nexport const articleIsClientSideRedirect = (type: string): AccessibleFormHelper => {\n return {\n name: 'Client-Side Redirect',\n helperText: `'Toggle whether or not client-side redirect is used. When toggled on, Google Analytics can be used on the ${type}.`,\n };\n};\nexport const articleOpenInNewTab = (type: string): AccessibleFormHelper => {\n return {\n name: 'New Tab',\n helperText: `Toggle to ensure the ${type} open in a new tab in the browser.`,\n };\n};\nexport const articleDownloadableCopy = (type: string): AccessibleFormHelper => {\n return {\n name: 'Downloadable Copy',\n helperText: `Attach digital copy of ${type}; so users can download it publicly.`,\n };\n};\nexport const articleTag = (type: string): AccessibleFormHelper => {\n return {\n name: 'Tags',\n helperText: `Select a subject matter description of the ${type}.`,\n };\n};\nexport const videoTag = (type: string): AccessibleFormHelper => {\n return {\n name: 'Tags',\n helperText: `Select a subject matter description of the ${type}.`,\n };\n};\nexport const blogCategory = {\n name: 'Category',\n helperText: 'Select an appropriate category for the blog.',\n};\nexport const articleHiddenTag = {\n name: 'Hide tag on articles',\n helperText:\n 'A hidden tag cannot be seen by users on articles. The name will still appear when visiting the tag’s page.',\n};\nexport const blogAuthor = {\n name: 'Author',\n helperText: 'Select the author of this blog post.',\n};\nexport const successStoryClientName = {\n name: 'Client Name',\n helperText: 'Enter the name of the client.',\n};\nexport const successStoryIndustry = {\n name: 'Industry',\n helperText: 'Enter the industry where the client operates.',\n};\nexport const successStoryLocation = {\n name: 'Location',\n helperText: 'Enter the location of this business/establishment.',\n};\nexport const successStoryVehicleTypes = {\n name: 'Vehicle Types',\n helperText: 'Enter the type of vehicles used by the client ex. Sedans, EVs, pickups, dump trucks.',\n};\nexport const successStoryFleetSize = {\n name: 'Fleet-Size',\n helperText: 'Enter an approximate size of the clients fleet.',\n};\nexport const successStoryFleetSizeFilter = {\n name: 'Fleet Size Filter',\n helperText: 'Select fleet filter to help categorize the clients business.',\n};\nexport const successStoryFleetRegionFilter = {\n name: 'Fleet Region Filter',\n helperText: 'Select fleet region filter to help categorize the clients business.',\n};\nexport const successStoryFleetIndustryFilter = {\n name: 'Fleet Industry Filter',\n helperText: 'Select fleet industry filter to help categorize the clients business.',\n};\nexport const successStoryClientImage = {\n name: 'Client Image',\n helperText: 'Selects an image for the case study.',\n};\nexport const successStoryClientImageAlt = {\n name: 'Client Image Alt',\n helperText: 'Enter an alternative text for the image, describing the client image in detail.',\n};\nexport const successStoryFleetFocus = {\n name: 'Fleet Focus Items',\n helperText: 'Select a subject matter describing the clients fleet purpose.',\n};\nexport const relativeLocation = {\n name: 'Relative location',\n helperText:\n 'Enter a location that is relative to the author, it does not have to be where they currently live, it can be where they have the most experience.',\n};\nexport const blogEntityName = (type: string): AccessibleFormHelper => {\n return {\n name: `${type} Name`,\n helperText: `${\n type === 'Author' ? `Enter the full or preferred name of the ${type}.` : `Enter the name of the ${type}.`\n }`,\n };\n};\nexport const blogEntityTitle = (type: string): AccessibleFormHelper => {\n return {\n name: 'SEO Title',\n helperText: `Enter a unique and descriptive title that helps describe the ${type}.`,\n };\n};\nexport const blogEntityDescription = (type: string): AccessibleFormHelper => {\n return {\n name: 'SEO Description',\n helperText: `Enter an informative description of the contents of the ${type}.`,\n };\n};\nexport const authorShortBiography = {\n name: 'Short Biography',\n helperText: 'Enter a short biography about the author. It should be one sentence in length.',\n};\nexport const authorBiography = {\n name: 'Biography',\n helperText: 'Enter a full length biography about the author. It should be around 40-60 words and in third person.',\n};\nexport const authorPublicationsURL = {\n name: 'Link URL',\n helperText: 'Enter an external link to the author\\'s publications.',\n};\nexport const authorPublications = {\n name: 'External links',\n helperText:\n 'Add and enter a list of external links of other publications this author has made. Or relevant links pertaining to the author.',\n};\nexport const authorSocial = (social: string): AccessibleFormHelper => {\n return {\n name: `${social}`,\n helperText: `Enter a link to the author's ${social} profile.`,\n };\n};\nexport const authorImage = {\n name: 'Author Image',\n helperText: 'Select an image for the author.',\n};\nexport const authorImageAlt = {\n name: 'Author Image Alt',\n helperText: 'Enter an alternative text for the image, describing the author\\'s image in detail.',\n};\nexport const navbarDropDownColumn = {\n name: 'Columns',\n helperText: 'Select the layout of the popout between a one or two columed layout.',\n};\nexport const navbarDropDownColumnContentStyle = {\n name: 'Content Style',\n helperText:\n 'Select the layout and content style of the current column. This affects the options that are available. ',\n};\nexport const navbarDropDownColumnTitle = {\n name: 'Title',\n helperText: 'Edit the title in the dropdown section.',\n};\nexport const navbarDropDownColumnSubTitle = (side: string): AccessibleFormHelper => {\n return {\n name: 'Subtitle',\n helperText: `Edit the subtitle for the ${side} side's column in the dropdown.`,\n };\n};\nexport const navbarDropDownColumnBody = {\n name: 'Body',\n helperText: 'Edit the descriptive body text in the dropdown (under the title).',\n};\nexport const navbarDropDownColumnMainImage = {\n name: 'Main Image',\n helperText: 'Edit the image being displayed in the dropdown.',\n};\nexport const navbarDropDownColumnMainMobileImage = {\n name: 'Main Mobile Image',\n helperText: 'Edit the image being displayed in the mobile dropdown.',\n};\nexport const navbarDropDownColumnMainImageAlt = {\n name: 'Main Image Alt',\n helperText: 'Describe the image being displayed in the dropdown.',\n};\nexport const navbarDropDownColumnVerticalDivider = {\n name: 'Show vertical divider',\n helperText: 'Toggling shows or hides the vertical dividing line between the two columns.',\n};\nexport const navbarDropDownColumnDropdownLink = (side: string): AccessibleFormHelper => {\n return {\n name: 'Dropdown links',\n helperText: `Manage the links set within the ${side} side's column.`,\n };\n};\nexport const heading = {\n name: 'Heading',\n helperText: 'Edit the main heading text.',\n};\nexport const testimonialQuote = {\n name: 'Testimonial Quote',\n helperText: 'Edit the testimonial quote.',\n};\nexport const testimonialAuthor = {\n name: 'Testimonial Author',\n helperText: 'Edit the testimonial author.',\n};\nexport const testimonialAuthorImage = {\n name: 'Testimonial Author Image',\n helperText: 'Open the gallery to change the image for the author shown in the testimonial.',\n};\nexport const testimonialAuthorTitle = {\n name: 'Testimonial Author Title',\n helperText: 'Edit the testimonial author title.',\n};\nexport const goToSection = {\n name: 'Navigation Reference ID',\n helperText:\n 'When this field has a value it will enable an arrow button which will navigate to the section with the given reference id.',\n};\nexport const requestConsentText = {\n name: 'Request Consent Text',\n helperText: 'Toggle this switch to enable the request consent text box.',\n};\nexport const dropDownButtonsTarget = (index: number): AccessibleFormHelper => {\n return {\n name: `Open link ${index ? index + 1 : ''} in new tab`,\n helperText: `Change whether or not the ${\n index && index < 2 ? (index === 0 ? 'first ' : 'second ') : ''\n }button will open links in a new tab.`,\n };\n};\nexport const testimonialShowBackground = {\n name: 'Show testimonial background',\n helperText: 'Changes the background of the body text when enabled.',\n};\nexport const testimonialDirection = {\n name: 'Testimonial direction',\n helperText: 'Change the testimonial direction.',\n};\nexport const testimonialStyle = {\n name: 'Testimonial style',\n helperText: 'Change the testimonial style.',\n};\nexport const testimonialRole = {\n name: 'Role/title',\n helperText: 'Edit the role/title.',\n};\nexport const formTitle = {\n name: 'Form title',\n helperText: 'Edit the form title.',\n};\nexport const formSubTitle = {\n name: 'Form subtitle',\n helperText: 'Edit the form subtitle.',\n};\nexport const formId = {\n name: 'Form Id',\n helperText: 'Edit SFMC form id.',\n};\nexport const formHTMLFormId = {\n name: 'HTML Form ID',\n helperText: 'Edit the id identifier for the form.',\n};\nexport const formSubmitButtonText = {\n name: 'Submit button text',\n helperText: 'Edit the submit button text.',\n};\nexport const formSubmitButtonVariant = {\n name: 'Button variant',\n helperText: 'Select a button variant.',\n};\nexport const formSubmitButtonFullWidth = {\n name: 'Enable full width button',\n helperText: 'Toggle to make the button full width.',\n};\nexport const formBackgroundImage = {\n name: 'Background Image',\n helperText: 'Select a 16:9 aspect ratio image for the form background.',\n};\nexport const formBackgroundImageEnabled = {\n name: 'Enable Background Image',\n helperText: 'Toggle to enable background images for the form.',\n};\nexport const formFieldLabel = {\n name: 'Field label',\n helperText: 'Edit the label.',\n};\nexport const formFieldId = {\n name: 'Field id',\n helperText: 'Edit the field id.',\n};\nexport const formFieldType = {\n name: 'Field type',\n helperText: 'Select a component type.',\n};\nexport const formFieldPlaceholder = {\n name: 'Field placeholder',\n helperText: 'Edit the component placeholder.',\n};\nexport const formFieldDefaultValue = {\n name: 'Default value',\n helperText: 'Edit the default value. Save for changes to appear on form.',\n};\nexport const formFieldBreakPoint = {\n name: 'Field breakpoint',\n helperText: 'Select a responsive size for the component',\n};\nexport const formFieldSelectToProceed = (option: string): AccessibleFormHelper => {\n return {\n name: `${option} to proceed`,\n helperText: `Toggle to ensure the user selects ${option} before the form can be submitted.`,\n };\n};\nexport const formFieldRequired = {\n name: 'Required',\n helperText: 'Toggle to make the component required.',\n};\nexport const formFieldHidden = {\n name: 'Hidden',\n helperText: 'Toggle to hide the component from the user using CSS (display: none).',\n};\nexport const formFieldNoOfRows = {\n name: 'Number of rows',\n helperText: 'Selects number of rows the field can occupy (Max: 15 rows).',\n};\nexport const formSelectMessage = (option: string): AccessibleFormHelper => {\n return {\n name: `${option} message`,\n helperText: `Edit ${option} message.`,\n };\n};\nexport const formDefaultMessage = (option: string): AccessibleFormHelper => {\n return {\n name: `${option} default value`,\n helperText: `Select ${option} default value (Save for changes to appear on the form).`,\n };\n};\nexport const authorExpertise = {\n name: 'Relevant expertise',\n helperText: 'Enter a list of expertise that this author has that is relevant to their written articles.',\n};\nexport const authorEducation = {\n name: 'Education',\n helperText: 'Enter a list of the author\\'s formal eductaion.',\n};\nexport const authorAccomplishments = {\n name: 'Accomplishments',\n helperText:\n 'Enter a list of accomplishments that the author has. This can include being featured on public news, awards, or certifications.',\n};\nexport const accordionBlock = (type: string, key: string): AccessibleFormHelper => {\n return {\n name: `${key}` || 'Menu Items',\n helperText: key\n ? `Add / enter a list of external links of ${key} this ${type} has made. Or relevant links pertaining to the ${type}.`\n : 'Customize the menu with the available items.',\n };\n};\nexport const currentRole = {\n name: 'Current role',\n helperText: 'Enter the author\\'s current work role at Geotab.',\n};\nexport const dropDownSameKeyValuePair = {\n name: 'Same option name-value pair',\n helperText: 'Toggle to ensure the dropdown has the same value for its name and option value.',\n};\nexport const CustomDropdownOptions = {\n name: 'Convert to custom dropdown',\n helperText:\n 'Toggle to convert the predefined dropdown to a custom dropdown. This allows you to add new options to the dropdown.',\n};\nexport const headerType = {\n name: 'Typography type',\n helperText: 'Select a typography style.',\n};\nexport const headerWeight = {\n name: 'Heading weight',\n helperText: 'Select the heading weight.',\n};\nexport const headerAlignment = {\n name: 'Heading alignment',\n helperText: 'Select the heading alignment.',\n};\nexport const headerSpacing = {\n name: 'Heading spacing',\n helperText: 'The space above and below the heading.',\n};\nexport const addFeatureTab = {\n name: 'Add a feature tab',\n helperText: 'Add up to 6 tabs to the feature accordion.',\n};\nexport const featureTabStyle = {\n name: 'Feature tab style',\n helperText: 'Changes the appearance of the feature accordion tabs.',\n};\nexport const addEvent = {\n name: 'Add an event',\n helperText: 'Add a new event group to the collection of events.',\n};\nexport const autoPlay = {\n name: 'Autoplay',\n helperText: 'Starts video automatically',\n};\nexport const mediaSize = {\n name: 'Select desktop media size',\n helperText: 'Select desktop media size of the video',\n};\nexport const mediaSource = {\n name: 'Select media source',\n helperText: 'Select a video from gallery or provide a link of video',\n};\nexport const embeddedMedia = {\n name: 'Embedded media',\n helperText: 'Opens the gallery to change the embedded media.',\n};\nexport const GTMDataLayer = {\n name: 'Send values to confirmation page',\n helperText:\n 'Should be used with the DataLayer Configuration Section on a confirmation page. (thank-you/ by default)',\n};\nexport const glossaryKeyInsights = {\n name: 'Key Insights',\n helperText: 'Enter an informative key insights about the contents.',\n};\nexport const BlogFAQQuestion = {\n name: 'Question',\n helperText: 'Enter a frequently asked question that will help users understand this topic better.',\n};\nexport const BlogFAQAnswer = {\n name: 'Answer',\n helperText: 'Provide a detailed answer to the question above.',\n};\nexport const subNavAddLink = {\n name: 'Navigation items',\n helperText: 'Add a new sub navigation link to the collection of links.',\n};\nexport const subNavLink = (index: number): AccessibleFormHelper => {\n return {\n name: `link ${index + 1} url or section id`,\n helperText: `Edit the link location where the blue bold link text will lead on sub navigation link number ${\n index + 1\n }.`,\n };\n};\nexport const subNavLinkText = (index: number): AccessibleFormHelper => {\n return {\n name: `link ${index + 1} text`,\n helperText: `Edit the clickable bolded blue link text on sub navigation link number ${\n index + 1\n }. Make sure the wording is concise and informs a user of the button's purpose.`,\n };\n};\nexport const subNavLinkTarget = (index: number): AccessibleFormHelper => {\n return {\n name: `link ${index + 1} in new tab`,\n helperText: `Change whether or not the link will open in a new tab for the text on sub navigation link number ${\n index + 1\n }.`,\n };\n};\nexport const featureAccordionMediaType = {\n name: 'Media type',\n helperText: 'Change the type of media that is shown.',\n};\n","import { regexErrorMessages, regexPatterns } from './regexHelper';\nimport {\n currentRole,\n relativeLocation,\n authorPublicationsURL,\n accordionBlock,\n authorAccomplishments,\n authorEducation,\n authorExpertise,\n authorImageAlt,\n authorImage,\n authorSocial,\n authorBiography,\n authorShortBiography,\n blogEntityName,\n articleIndexStatus,\n articlePublishedStatus,\n articleCanonical,\n articleSlug,\n articleLanguage,\n entityRedirectUrl,\n columnLinkText,\n slugEntityBreadcrumbDisplayName,\n} from '@helpers/AccessibleFormHelperConstants';\nimport { BlogFormHelper } from '@models/blogForm';\nimport { Author } from '@models/author';\nimport { regexMatchesOrIsEmpty, hasLength } from '@helpers/validators';\nimport { EntityName } from '@models/entity';\nimport { breadcrumbDisplayNameValidator } from './validationRules';\nimport { UserRole } from '@models/authentication';\n\nconst friendlyName = 'Author';\n\nexport const authorFormHelper: BlogFormHelper = {\n name: 'Author',\n entityName: EntityName.Author,\n apiControllerName: 'author',\n gallerySelection: 'authorImage',\n hasMediaField: false,\n fields: [\n {\n id: 'author-language',\n key: 'language',\n name: 'Language',\n required: true,\n type: 'select',\n list: 'languages',\n listItemValueKey: 'id',\n readOnlyModes: ['edit'],\n hiddenLabel: true,\n formHelper: articleLanguage(friendlyName),\n },\n {\n id: 'author-name',\n key: 'name',\n name: 'Author Name',\n required: true,\n maxLength: 100,\n type: 'text',\n placeholderText: 'Enter the author\\'s full name...',\n formHelper: blogEntityName(friendlyName),\n },\n {\n id: 'author-slug',\n key: 'slug',\n name: 'Url Slug',\n validators: [regexMatchesOrIsEmpty(regexPatterns.slug, regexErrorMessages.slug)],\n required: true,\n maxLength: 100,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n lowercaseOnChange: true,\n },\n formHelper: articleSlug(friendlyName),\n },\n {\n id: 'author-breadcrumbDisplayName',\n key: 'breadcrumbDisplayName',\n name: 'Breadcrumb Display Name',\n validators: [breadcrumbDisplayNameValidator],\n required: false,\n type: 'text',\n formHelper: slugEntityBreadcrumbDisplayName(friendlyName),\n },\n {\n id: 'author-canonical',\n key: 'canonical',\n name: 'Canonical Url',\n required: false,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n },\n formHelper: articleCanonical(friendlyName),\n },\n {\n id: 'author-image',\n key: 'image',\n name: 'Author Image',\n required: false,\n type: 'galleryImage',\n gallerySelection: 'authorImage',\n ratio: ['1:1'],\n maxWidth: 640,\n formHelper: authorImage,\n fieldsToRevalidate: ['author-imageAlt'],\n fieldKeyToUpdate: 'imageAlt',\n },\n {\n id: 'author-imageAlt',\n key: 'imageAlt',\n name: 'Author Image Alt',\n requiredCondition: (entity) => !!entity.image,\n maxLength: 300,\n type: 'text',\n formHelper: authorImageAlt,\n },\n {\n id: 'author-redirectUrl',\n key: 'redirectUrl',\n name: 'Redirect Url',\n required: false,\n maxLength: 5000,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n },\n formHelper: entityRedirectUrl(friendlyName),\n },\n {\n id: 'author-shortBio',\n key: 'shortBiography',\n name: 'Short Biography',\n validators: [hasLength({ max: 140 }, 'Try to keep the short biography under 140 characters', true)],\n required: true,\n type: 'text',\n placeholderText: 'Enter a one sentence version of the biography...',\n formHelper: authorShortBiography,\n },\n {\n id: 'author-noIndex',\n key: 'noIndex',\n name: 'No Index',\n required: false,\n type: 'checkbox',\n formHelper: articleIndexStatus(friendlyName),\n },\n {\n id: 'author-publishedDate',\n key: 'publishedDateUtc',\n name: 'Published',\n type: 'publishBox',\n formHelper: articlePublishedStatus(friendlyName),\n modifiableByRoles: [UserRole.GeotabComCmsAdmin, UserRole.GeotabComArticleAdmin],\n },\n {\n id: 'author-fullBioHeading',\n type: 'subHeading',\n text: 'Full Biography',\n },\n {\n id: 'author-fullBio',\n key: 'fullBiography',\n name: 'Biography',\n validators: [\n (value) =>\n typeof value === 'string' && value.split(' ').length - 1 >= 60\n ? { message: 'Try to keep the biography under 60 words', isWarning: true }\n : null,\n ],\n required: false,\n type: 'text',\n placeholderText: 'Enter a biography describing the author...',\n formHelper: authorBiography,\n },\n {\n id: 'author-advancedInforHeading',\n type: 'subHeading',\n text: 'Advanced information',\n },\n {\n id: 'author-location',\n key: 'location',\n name: 'Relative location',\n type: 'text',\n required: false,\n helperText: 'Ontario, Canada',\n formHelper: relativeLocation,\n },\n {\n id: 'author-role',\n key: 'role',\n name: 'Current role',\n type: 'text',\n required: false,\n formHelper: currentRole,\n },\n {\n id: 'author-expertise',\n key: 'expertise',\n name: 'Relevant experience',\n required: false,\n type: 'listBox',\n formHelper: authorExpertise,\n },\n {\n id: 'author-education',\n key: 'education',\n name: 'Education',\n required: false,\n type: 'listBox',\n formHelper: authorEducation,\n },\n {\n id: 'author-accomplishments',\n key: 'accomplishments',\n name: 'Accomplishments',\n type: 'listBox',\n required: false,\n formHelper: authorAccomplishments,\n },\n {\n id: 'author-externalLinksHeading',\n type: 'subHeading',\n text: 'External links',\n },\n {\n id: 'author-publications',\n key: 'publications',\n name: 'publication',\n type: 'accordionBlock',\n chipTitle: 'Other publications',\n count: 10,\n usedFor: 'link',\n keyPropertyName1: 'publicationName',\n keyPropertyName2: 'publicationLink',\n formHelper: [accordionBlock(friendlyName, 'publications'), columnLinkText, authorPublicationsURL],\n },\n {\n id: 'author-linkedIn',\n key: 'linkedInLink',\n name: 'Linkedin',\n validators: [regexMatchesOrIsEmpty(regexPatterns.requireHttpHttps, regexErrorMessages.linkedInLink)],\n type: 'text',\n required: false,\n formHelper: authorSocial('Linkedin'),\n },\n {\n id: 'author-twitter',\n key: 'twitterLink',\n name: 'Twitter',\n validators: [regexMatchesOrIsEmpty(regexPatterns.requireHttpHttps, regexErrorMessages.twitterLink)],\n type: 'text',\n formHelper: authorSocial('Twitter'),\n },\n ],\n};\n\nexport const authorModel: Partial = {\n language: 1,\n name: '',\n slug: '',\n image: '',\n imageAlt: '',\n linkedInLink: '',\n twitterLink: '',\n canonical: '',\n noIndex: false,\n status: 0,\n fullBiography: '',\n education: [],\n accomplishments: [],\n expertise: [],\n location: '',\n role: '',\n publications: [],\n redirectUrl: '',\n};\n","import { UserRole } from '@models/authentication';\n\nexport const permissions = {\n basic: 'Basic admin permission',\n pages: 'Pages permission',\n articles: 'Articles permission',\n publish: 'Publish permission',\n navigation: 'Navigation permission',\n media: 'Media gallery permission',\n files: 'File gallery permission',\n videoGallery: 'Video gallery permission',\n serverInfo: 'Server info permission',\n siteSetting: 'Site setting permission',\n documents: 'Documents permission',\n hrefLang: 'Hreflang permission',\n dashboard: 'Dashboard permission',\n tools: 'Tools permission',\n uploads: 'Uploads permission',\n help: 'Help permission',\n};\n\nexport const accessLevels = {\n none: 0,\n view: 1, //_R__\n edit: 2, //CRU_\n full: 3, //CRUD\n};\n\nexport const rolePermissions = {\n [UserRole.GeotabComCmsAdmin]: {\n [permissions.basic]: accessLevels.view,\n [permissions.pages]: accessLevels.full,\n [permissions.videoGallery]: accessLevels.full,\n [permissions.media]: accessLevels.full,\n [permissions.files]: accessLevels.full,\n [permissions.navigation]: accessLevels.full,\n [permissions.serverInfo]: accessLevels.full,\n [permissions.siteSetting]: accessLevels.full,\n [permissions.articles]: accessLevels.full,\n [permissions.publish]: accessLevels.full,\n [permissions.documents]: accessLevels.full,\n [permissions.hrefLang]: accessLevels.full,\n [permissions.dashboard]: accessLevels.view,\n [permissions.tools]: accessLevels.full,\n [permissions.uploads]: accessLevels.full,\n [permissions.help]: accessLevels.full,\n },\n\n [UserRole.GeotabComArticleAdmin]: {\n [permissions.basic]: accessLevels.view,\n [permissions.pages]: accessLevels.none,\n [permissions.videoGallery]: accessLevels.none,\n [permissions.media]: accessLevels.edit,\n [permissions.files]: accessLevels.edit,\n [permissions.navigation]: accessLevels.none,\n [permissions.serverInfo]: accessLevels.none,\n [permissions.siteSetting]: accessLevels.none,\n [permissions.articles]: accessLevels.full,\n [permissions.publish]: accessLevels.full,\n [permissions.documents]: accessLevels.none,\n [permissions.hrefLang]: accessLevels.edit,\n [permissions.dashboard]: accessLevels.view,\n [permissions.tools]: accessLevels.full,\n [permissions.uploads]: accessLevels.full,\n [permissions.help]: accessLevels.full,\n },\n\n [UserRole.GeotabComArticleEditor]: {\n [permissions.basic]: accessLevels.view,\n [permissions.pages]: accessLevels.none,\n [permissions.videoGallery]: accessLevels.none,\n [permissions.media]: accessLevels.edit,\n [permissions.files]: accessLevels.edit,\n [permissions.navigation]: accessLevels.none,\n [permissions.serverInfo]: accessLevels.none,\n [permissions.siteSetting]: accessLevels.none,\n [permissions.articles]: accessLevels.full,\n [permissions.publish]: accessLevels.none,\n [permissions.documents]: accessLevels.none,\n [permissions.hrefLang]: accessLevels.edit,\n [permissions.dashboard]: accessLevels.view,\n [permissions.tools]: accessLevels.full,\n [permissions.uploads]: accessLevels.full,\n [permissions.help]: accessLevels.full,\n },\n};\n","import { languageRouteTypes } from '@helpers/languageRoutes';\nimport { categoryFormHelper } from '@helpers/categoryForm';\nimport { authorFormHelper } from '@helpers/authorForm';\nimport { tagFormHelper } from '@helpers/tagForm';\nimport { BlogEntity } from '@models/blog';\nimport { BlogSettingsEntity } from '@models/blogForm';\n\nexport const blogEntityType: Record = {\n category: {\n pluralName: 'Categories',\n singularName: 'Category',\n baseApi: 'category',\n publicBaseUrl: 'blog/category',\n formData: categoryFormHelper,\n routeType: languageRouteTypes.CATEGORY,\n },\n author: {\n pluralName: 'Authors',\n singularName: 'Author',\n baseApi: 'author',\n publicBaseUrl: 'blog/author',\n formData: authorFormHelper,\n routeType: languageRouteTypes.AUTHOR,\n },\n tag: {\n pluralName: 'Tags',\n singularName: 'Tag',\n baseApi: 'tag',\n publicBaseUrl: 'tag',\n formData: tagFormHelper,\n routeType: languageRouteTypes.TAG,\n },\n};\n","import { regexErrorMessages, regexPatterns } from './regexHelper';\nimport {\n blogEntityDescription,\n blogEntityName,\n blogEntityTitle,\n articleIndexStatus,\n articlePublishedStatus,\n articleCanonical,\n articleSlug,\n articleLanguage,\n entityRedirectUrl,\n slugEntityBreadcrumbDisplayName,\n} from '@helpers/AccessibleFormHelperConstants';\nimport { BlogFormHelper } from '@models/blogForm';\nimport { Category } from '@models/category';\nimport { EntityName } from '@models/entity';\nimport { regexMatchesOrIsEmpty } from '@helpers/validators';\nimport { breadcrumbDisplayNameValidator } from './validationRules';\nimport { UserRole } from '@models/authentication';\n\nconst friendlyName = 'Category';\n\nexport const categoryFormHelper: BlogFormHelper = {\n name: 'Category',\n entityName: EntityName.Category,\n apiControllerName: 'category',\n hasMediaField: false,\n fields: [\n {\n id: 'category-language',\n key: 'language',\n name: 'Language',\n required: true,\n type: 'select',\n list: 'languages',\n listItemValueKey: 'id',\n readOnlyModes: ['edit'],\n formHelper: articleLanguage(friendlyName),\n },\n {\n id: 'category-name',\n key: 'name',\n name: 'Category Name',\n required: true,\n maxLength: 100,\n type: 'text',\n formHelper: blogEntityName(friendlyName),\n },\n {\n id: 'category-title',\n key: 'title',\n name: 'SEO Title',\n required: true,\n type: 'text',\n formHelper: blogEntityTitle(friendlyName),\n },\n {\n id: 'category-description',\n key: 'description',\n name: 'SEO Description',\n required: true,\n type: 'text',\n formHelper: blogEntityDescription(friendlyName),\n },\n {\n id: 'category-slug',\n key: 'slug',\n name: 'Url Slug',\n validators: [regexMatchesOrIsEmpty(regexPatterns.slug, regexErrorMessages.slug)],\n required: true,\n maxLength: 100,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n lowercaseOnChange: true,\n },\n formHelper: articleSlug(friendlyName),\n },\n {\n id: 'category-breadcrumbDisplayName',\n key: 'breadcrumbDisplayName',\n name: 'Breadcrumb Display Name',\n validators: [breadcrumbDisplayNameValidator],\n required: false,\n type: 'text',\n formHelper: slugEntityBreadcrumbDisplayName(friendlyName),\n },\n {\n id: 'category-canonical',\n key: 'canonical',\n name: 'Canonical Url',\n required: false,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n },\n formHelper: articleCanonical(friendlyName),\n },\n {\n id: 'category-redirectUrl',\n key: 'redirectUrl',\n name: 'Redirect Url',\n required: false,\n maxLength: 5000,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n },\n formHelper: entityRedirectUrl(friendlyName),\n },\n {\n id: 'category-noIndex',\n key: 'noIndex',\n name: 'No Index',\n required: false,\n type: 'checkbox',\n formHelper: articleIndexStatus(friendlyName),\n },\n {\n id: 'category-isHidden',\n key: 'isHidden',\n name: 'Hidden',\n required: false,\n type: 'checkbox',\n formHelper: {\n name: 'Hidden',\n helperText:\n 'Toggle whether or not the category will be shown in the blog pages when displaying all categories.',\n },\n },\n {\n id: 'category-publishedDate',\n key: 'publishedDateUtc',\n name: 'Published',\n type: 'publishBox',\n formHelper: articlePublishedStatus(friendlyName),\n modifiableByRoles: [UserRole.GeotabComCmsAdmin, UserRole.GeotabComArticleAdmin],\n },\n ],\n};\n\nexport const categoryModel: Partial = {\n language: 1,\n name: '',\n slug: '',\n canonical: '',\n noIndex: false,\n status: 0,\n};\n","import * as Sentry from '@sentry/browser';\n\nexport function getErrorMessage(error) {\n if (error.error) {\n return getErrorMessage(error.error);\n }\n return error.message || 'Unknown error';\n}\n\nexport function isSlugSegmentLengthValid(slug, maxLength) {\n const slugSegments = slug.split('/');\n return slugSegments.every((segment) => segment.length <= maxLength);\n}\n\nexport function logError(error, taskDescription) {\n if (taskDescription) {\n console.error(`Error performing task: ${taskDescription}. See below for details.`);\n }\n console.error(error);\n Sentry.captureException(error);\n}\n","export const supportedVideoExtensions = ['mp4'];\nexport const supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'];\nexport const mediaUrlPrefixToken = '{{mediaUrlPrefix}}';\nexport const generalFileUrlPrefixToken = '{{generalFileUrlPrefix}}';\n\nexport function getFullMediaPath(mediaUrlPrefix, filePath, fileName) {\n return `${mediaUrlPrefix}${filePath}${fileName}`;\n}\n\nexport function getParentFolderFromPath(currentPath) {\n if (currentPath === '/') {\n return '/';\n }\n\n let pathParts = currentPath.split('/');\n pathParts = pathParts.slice(0, pathParts.length - 2);\n return `${pathParts.join('/')}/`;\n}\n\nexport function resolveImagePath(mediaUrlPrefix, storedImagePath) {\n const regex = new RegExp(`${mediaUrlPrefixToken}`, 'gi');\n return (storedImagePath && storedImagePath.replace(regex, mediaUrlPrefix)) || '';\n}\n\nexport function resolveGeneralFilePath(generalFileUrlPrefix, storedFilePath) {\n const regex = new RegExp(`${generalFileUrlPrefixToken}`, 'gi');\n return (storedFilePath && storedFilePath.replace(regex, generalFileUrlPrefix)) || '';\n}\n\nexport function stripMediaUrlPrefixReplacementToken(mediaPath) {\n const regex = new RegExp(`${mediaUrlPrefixToken}`, 'gi');\n return (mediaPath && mediaPath.replace(regex, '')) || '';\n}\n\nexport function containsMediaUrlPrefixReplacementToken(mediaPath) {\n return (mediaPath && mediaPath.includes(mediaUrlPrefixToken)) || '';\n}\n\nexport function ensureFilePathIsTrimmed(filePath, maxLength = 35) {\n const lastPeriod = filePath.lastIndexOf('.');\n const trimmedFilePath = lastPeriod !== -1 ? filePath.slice(0, lastPeriod) : filePath;\n return filePath.length > maxLength\n ? `${trimmedFilePath.slice(0, maxLength)}... ${filePath.slice(lastPeriod, filePath.length)}`\n : filePath;\n}\n\nexport const mediaTypes = {\n video: 'video',\n image: 'image',\n};\n\nexport function getMediaTypeByPath(filename) {\n const fileExtension = getFileExtension(filename);\n if (supportedVideoExtensions.includes(fileExtension)) {\n return mediaTypes.video;\n } else {\n return mediaTypes.image;\n }\n}\n\nexport function getFileExtension(filename) {\n return filename.split('.').pop();\n}\n","/* eslint-disable camelcase */\nconst key = 'geotabSource';\nconst secondsInADay = 86400;\nconst socialMediaSources = ['facebook', 'instagram', 'linkedin', 'tiktok', 'twitter', 'youtube'];\nconst organicSources = ['google', 'bing', 'yahoo', 'duckduckgo', 'baidu', 'ask'];\n\ninterface GeotabSource {\n initialDate: Date;\n initialUrl: string;\n initialReferrerUrl: string;\n initialSource: string;\n locale: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n visitorType: string;\n conversionUrl: string;\n conversionDate?: Date;\n conversionSource: string;\n conversionReferrerUrl: string;\n expiryDate: Date;\n}\n\nexport function initializeGeotabSourceCookie(daysToExpire = 30): void {\n if (!geotabSourceCookieExists()) {\n const secondsToExpire = daysToExpire * secondsInADay;\n const currentDate = new Date();\n const expiryDate = new Date(currentDate.getTime() + secondsToExpire * 1000);\n\n const geotabSource: GeotabSource = {\n initialDate: currentDate,\n initialUrl: window.location.href,\n initialReferrerUrl: document.referrer,\n initialSource: getReferrerSource(),\n locale: navigator.language,\n ...getUtmQueryStringValues(),\n visitorType: 'prospect',\n conversionUrl: '',\n conversionSource: '',\n conversionReferrerUrl: '',\n expiryDate: expiryDate,\n };\n\n document.cookie = `${key}=${JSON.stringify(\n geotabSource\n )}; max-age=${secondsToExpire}; path=/; Secure; SameSite=Strict`;\n }\n}\n\nexport function geotabSourceCookieExists(): boolean {\n return document.cookie.includes('geotabSource');\n}\n\nexport function updateGeotabSourceCookie(): GeotabSource | undefined {\n const geotabSourceCookie = document.cookie.split(';').find((c) => c.includes(key));\n const geotabSource = geotabSourceCookie ? getCookieValue(geotabSourceCookie) : undefined;\n\n if (geotabSource) {\n const currentDate = new Date();\n const secondsToExpire = Math.floor((geotabSource.expiryDate.getTime() - currentDate.getTime()) / 1000);\n\n geotabSource.conversionUrl = window.location.href;\n geotabSource.conversionDate = currentDate;\n geotabSource.conversionSource = getReferrerSource();\n geotabSource.conversionReferrerUrl = document.referrer;\n\n document.cookie = `${key}=${JSON.stringify(\n geotabSource\n )}; max-age=${secondsToExpire}; path=/; Secure; SameSite=Strict`;\n\n return geotabSource;\n }\n}\n\nfunction getReferrerSource(): string {\n const referrerUrl = document.referrer.toLowerCase();\n\n if (includesAny(referrerUrl, socialMediaSources)) {\n return 'social';\n } else if (includesAny(referrerUrl, organicSources)) {\n return 'organic';\n } else {\n return 'direct';\n }\n}\n\nfunction includesAny(str: string, substrings: string[]): boolean {\n return substrings.some((substring) => str.includes(substring));\n}\n\nfunction getCookieValue(cookie: string): GeotabSource {\n const value = JSON.parse(cookie.split(/=(.*)/s)[1], jsonDateParser);\n return value;\n}\n\nfunction jsonDateParser(key: string, value: string): Date | string {\n return key === 'expiryDate' || key === 'initialDate' || key === 'conversionDate' ? new Date(value) : value;\n}\n\nfunction getUtmQueryStringValues(): Record {\n const query = new URLSearchParams(window.location.search);\n const utm = {\n utm_source: query.get('utm_source') ?? '',\n utm_medium: query.get('utm_medium') ?? '',\n utm_campaign: query.get('utm_campaign') ?? '',\n };\n\n return utm;\n}\n","export const keyIsEnter = (event) => {\n return event.key === 'Enter' || event.code === 'Enter' || event.key === 'Return' || event.code === 'Return';\n};\nexport const keyIsTab = (event) => {\n return event.key === 'Tab' || event.code === 'Tab';\n};\nexport const keyIsSpace = (event) => {\n return event.key === ' ' || event.code === 'Space';\n};\nexport const keyIsBackspace = (event) => {\n return event.key === 'Backspace' || event.code === 'Backspace' || event.code === 'Delete';\n};\nexport const keyIsEscape = (event) => {\n return event.key === 'Escape' || event.code === 'Escape';\n};\nexport const keyIsDown = (event) => {\n return event.key === 'ArrowDown' || event.code === 'ArrowDown';\n};\nexport const keyIsUp = (event) => {\n return event.key === 'ArrowUp' || event.code === 'ArrowUp';\n};\n","import { LanguageRoute } from '@models/languageRoute';\n\nexport const languageRoutes: Record = {\n en: {\n blogHomeUrl: 'blog/',\n authorUrl: 'blog/author/',\n categoryUrl: 'blog/category/',\n blogPostUrl: 'blog/',\n tagUrl: 'tag/',\n pressRoomHomeUrl: 'press-releases/',\n pressReleaseUrl: 'press-release/',\n successStoriesHomeUrl: 'success-stories/',\n caseStudyUrl: 'case-study/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n glossaryUrl: 'glossary/',\n becomeInstallerUrl: 'become-installer/',\n videoUrl: 'video/',\n documentationUrl: 'documentation/',\n thankYouUrl: 'thank-you/',\n thankYouBlogUrl: 'thank-you-blog/',\n sitemap: 'sitemap/',\n publicSearchUrl: 'search/',\n },\n enUk: {\n blogHomeUrl: 'blog/',\n authorUrl: 'blog/author/',\n categoryUrl: 'blog/category/',\n blogPostUrl: 'blog/',\n tagUrl: 'tag/',\n pressRoomHomeUrl: 'press-room/',\n pressReleaseUrl: 'press-release/',\n successStoriesHomeUrl: 'success-stories/',\n caseStudyUrl: 'case-study/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n glossaryUrl: 'glossary/',\n myGeotabLoginUrl: 'mygeotab-login/',\n becomeInstallerUrl: 'become-installer/',\n videoUrl: 'video/',\n documentationUrl: 'documentation/',\n thankYouUrl: 'thank-you/',\n thankYouBlogUrl: 'thank-you-blog/',\n sitemap: 'sitemap/',\n publicSearchUrl: 'search/',\n },\n frCa: {\n thankYouUrl: 'merci/',\n thankYouBlogUrl: 'merci-blog/',\n becomeInstallerUrl: 'devenez-installateur/',\n myGeotabLoginUrl: 'mygeotab-login/',\n sitemap: 'sitemap/',\n publicSearchUrl: 'chercher/',\n },\n es: {\n blogHomeUrl: 'blog/',\n authorUrl: 'blog/autor/',\n categoryUrl: 'blog/categoria/',\n blogPostUrl: 'blog/',\n tagUrl: 'tag/',\n pressRoomHomeUrl: 'sala-de-prensa/',\n pressReleaseUrl: 'nota-de-prensa/',\n successStoriesHomeUrl: 'casos-de-exito/',\n caseStudyUrl: 'casos-de-exito/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n myGeotabLoginUrl: 'mygeotab-login/',\n becomeInstallerUrl: 'hágase-instalador/',\n documentationUrl: 'documentation/',\n thankYouUrl: 'gracias/',\n thankYouBlogUrl: 'gracias-blog/',\n sitemap: 'sitemap/',\n publicSearchUrl: 'buscar/',\n },\n de: {\n pressRoomHomeUrl: 'pressebereich/',\n myGeotabLoginUrl: 'mygeotab-login/',\n whitePaperUrl: 'white-paper/',\n whitePapersHomeUrl: 'white-papers/',\n successStoriesHomeUrl: 'erfolgsgeschichten/',\n caseStudyUrl: 'case-study/',\n pressReleaseUrl: 'presse/',\n categoryUrl: 'blog/kategorie/',\n authorUrl: 'blog/autor/',\n blogPostUrl: 'blog/',\n blogHomeUrl: 'blog/',\n becomeInstallerUrl: 'monteur-werden/',\n thankYouUrl: 'danke/',\n thankYouBlogUrl: 'danke-blog/',\n tagUrl: 'etikett/',\n documentationUrl: 'dokumentation/',\n sitemap: 'sitemap/',\n publicSearchUrl: 'suche/',\n },\n it: {\n thankYouUrl: 'grazie/',\n thankYouBlogUrl: 'grazie-blog/',\n becomeInstallerUrl: 'diventa-installatore/',\n myGeotabLoginUrl: 'mygeotab-accedi/',\n authorUrl: 'blog/autore/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n successStoriesHomeUrl: 'storie-di-successo/',\n caseStudyUrl: 'caso-di-studio/',\n pressRoomHomeUrl: 'area-stampa/',\n pressReleaseUrl: 'comunicati-stampa/',\n blogHomeUrl: 'blog/',\n categoryUrl: 'blog/categoria/',\n blogPostUrl: 'blog/',\n tagUrl: 'tag/',\n sitemap: 'sitemap/',\n publicSearchUrl: 'cerca/',\n },\n frFr: {\n thankYouUrl: 'merci/',\n thankYouBlogUrl: 'merci-blog/',\n whitePaperUrl: 'livre-blanc/',\n whitePapersHomeUrl: 'livres-blancs/',\n pressRoomHomeUrl: 'salle-de-presse/',\n pressReleaseUrl: 'espace-presse/',\n successStoriesHomeUrl: 'temoignages-reussites/',\n caseStudyUrl: 'case-study/',\n becomeInstallerUrl: 'devenir-installateur/',\n myGeotabLoginUrl: 'mygeotab-login/',\n authorUrl: 'blog/auteur/',\n categoryUrl: 'blog/categorie/',\n blogHomeUrl: 'blog/',\n blogPostUrl: 'blog/',\n tagUrl: 'marque/',\n sitemap: 'sitemap/',\n documentationUrl: 'documentation/',\n publicSearchUrl: 'chercher/',\n glossaryUrl: 'glossaire/',\n },\n ptBr: {\n thankYouUrl: 'obrigado/',\n thankYouBlogUrl: 'obrigado-blog/',\n publicSearchUrl: 'buscar/',\n pressRoomHomeUrl: 'sala-de-imprensa/',\n pressReleaseUrl: 'sala-de-imprensa/',\n becomeInstallerUrl: 'torne-se-um-instalador/',\n myGeotabLoginUrl: 'mygeotab-login/',\n whitePaperUrl: 'documento-tecnico/',\n whitePapersHomeUrl: 'white-papers/',\n successStoriesHomeUrl: 'historias-de-sucesso/',\n authorUrl: 'blog/autor/',\n caseStudyUrl: 'estudo-de-caso/',\n categoryUrl: 'blog/categoria/',\n blogHomeUrl: 'blog/',\n blogPostUrl: 'blog/',\n tagUrl: 'tag/',\n },\n enAu: {\n pressRoomHomeUrl: 'press-room/',\n pressReleaseUrl: 'press-release/',\n thankYouUrl: 'thank-you/',\n thankYouBlogUrl: 'thank-you-blog/',\n videoUrl: 'video/',\n successStoriesHomeUrl: 'success-stories/',\n caseStudyUrl: 'case-study/',\n whitePaperUrl: 'white-paper/',\n whitePapersHomeUrl: 'white-papers/',\n glossaryUrl: 'glossary/',\n authorUrl: 'blog/author/',\n categoryUrl: 'blog/category/',\n blogHomeUrl: 'blog/',\n blogPostUrl: 'blog/',\n tagUrl: 'tag/',\n sitemap: 'sitemap/',\n documentationUrl: 'documentation/',\n publicSearchUrl: 'search/',\n },\n esMx: {\n thankYouUrl: 'gracias/',\n thankYouBlogUrl: 'gracias-blog/',\n authorUrl: 'blog/autor/',\n categoryUrl: 'blog/categoria/',\n blogPostUrl: 'blog/',\n blogHomeUrl: 'blog/',\n pressRoomHomeUrl: 'sala-de-prensa-y-noticias/',\n pressReleaseUrl: 'comunicado-de-prensa/',\n tagUrl: 'tag/',\n videoUrl: 'video/',\n myGeotabLoginUrl: 'mygeotab-login/',\n successStoriesHomeUrl: 'casos-de-exito/',\n caseStudyUrl: 'casos-de-exito/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n sitemap: 'sitemap/',\n publicSearchUrl: 'buscar/',\n },\n pl: {\n thankYouUrl: 'Dziękuję-Ci/',\n publicSearchUrl: 'szukaj/',\n },\n nl: {\n blogHomeUrl: 'blog/',\n authorUrl: 'blog/author/',\n categoryUrl: 'blog/category/',\n blogPostUrl: 'blog/',\n thankYouUrl: 'bedankt/',\n thankYouBlogUrl: 'thank-you-blog/',\n publicSearchUrl: 'zoek/',\n myGeotabLoginUrl: 'mygeotab-login/',\n pressRoomHomeUrl: 'perskamer/',\n pressReleaseUrl: 'persbericht/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n successStoriesHomeUrl: 'succes-verhalen/',\n caseStudyUrl: 'case-study/',\n becomeInstallerUrl: 'word-installateur/',\n tagUrl: 'tag/',\n sitemap: 'sitemap/',\n videoUrl: 'video/',\n },\n se: {\n thankYouUrl: 'thank-you/',\n thankYouBlogUrl: 'thank-you-blog/',\n publicSearchUrl: 'search/',\n },\n ae: {\n thankYouUrl: 'thank-you/',\n thankYouBlogUrl: 'thank-you-blog/',\n publicSearchUrl: 'search/',\n },\n ie: {\n thankYouUrl: 'thank-you/',\n thankYouBlogUrl: 'thank-you-blog/',\n blogHomeUrl: 'blog/',\n authorUrl: 'blog/author/',\n categoryUrl: 'blog/category/',\n blogPostUrl: 'blog/',\n publicSearchUrl: 'search/',\n pressRoomHomeUrl: 'press-room/',\n pressReleaseUrl: 'press-release/',\n successStoriesHomeUrl: 'success-stories/',\n caseStudyUrl: 'case-study/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n glossaryUrl: 'glossary/',\n tagUrl: 'tag/',\n },\n apac: {\n thankYouUrl: 'thank-you/',\n thankYouBlogUrl: 'thank-you-blog/',\n publicSearchUrl: 'search/',\n blogHomeUrl: 'blog/',\n authorUrl: 'blog/author/',\n categoryUrl: 'blog/category/',\n blogPostUrl: 'blog/',\n whitePapersHomeUrl: 'white-papers/',\n whitePaperUrl: 'white-paper/',\n pressRoomHomeUrl: 'press-room/',\n pressReleaseUrl: 'press-release/',\n successStoriesHomeUrl: 'success-stories/',\n caseStudyUrl: 'case-study/',\n tagUrl: 'tag/',\n sitemap: 'sitemap/',\n },\n enCb: {\n thankYouUrl: 'thank-you/',\n publicSearchUrl: 'search/',\n },\n idn: {\n thankYouUrl: 'thank-you/',\n publicSearchUrl: 'search/',\n blogHomeUrl: 'blog/',\n authorUrl: 'blog/author/',\n categoryUrl: 'blog/category/',\n blogPostUrl: 'blog/',\n tagUrl: 'tag/',\n pressRoomHomeUrl: 'press-releases/',\n pressReleaseUrl: 'press-release/',\n },\n jp: {},\n};\n\ninterface LanguageRouteTypes {\n [key: string]: keyof LanguageRoute;\n}\n\nexport const languageRouteTypes = {\n BLOG_HOME: 'blogHomeUrl',\n BLOG_POST: 'blogPostUrl',\n AUTHOR: 'authorUrl',\n CATEGORY: 'categoryUrl',\n TAG: 'tagUrl',\n WHITE_PAPERS_HOME: 'whitePapersHomeUrl',\n WHITE_PAPER: 'whitePaperUrl',\n SUCCESS_STORIES_HOME: 'successStoriesHomeUrl',\n CASE_STUDY: 'caseStudyUrl',\n PRESS_ROOM_HOME: 'pressRoomHomeUrl',\n PRESS_RELEASE: 'pressReleaseUrl',\n GLOSSARY: 'glossaryUrl',\n MY_GEOTAB_LOGIN: 'myGeotabLoginUrl',\n VIDEO: 'videoUrl',\n DOCUMENT: 'documentationUrl',\n} satisfies LanguageRouteTypes;\n\nexport const articleTypesArray = Object.values(languageRouteTypes).filter((routeValue) => {\n switch (routeValue) {\n case 'blogPostUrl':\n case 'pressReleaseUrl':\n case 'whitePaperUrl':\n case 'caseStudyUrl':\n case 'glossaryUrl':\n return true;\n default:\n return false;\n }\n});\n","import { en } from '../translations/en';\n\nexport const genericFallbackMessage = '[Missing Translation]';\nconst missingFileFallbackMessage = '[Missing Translation File]';\nconst defaultFallbackLanguage = en;\n\nexport const getTranslation = (selectedLanguageTranslation, ...languagePropertyKeys) => {\n let translatedString;\n\n if (!selectedLanguageTranslation) {\n return missingFileFallbackMessage;\n }\n\n translatedString = getValueFromTranslationObject(selectedLanguageTranslation, languagePropertyKeys);\n\n if (translatedString !== '' && !translatedString) {\n translatedString = getValueFromTranslationObject(defaultFallbackLanguage, languagePropertyKeys);\n }\n\n return translatedString === '' || translatedString ? translatedString : genericFallbackMessage;\n};\n\nconst getValueFromTranslationObject = (translationObject, languagePropertyKeysArray) => {\n let translatedString;\n\n if (languagePropertyKeysArray && languagePropertyKeysArray.length) {\n let currentTranslationObject = translationObject;\n\n for (let i = 0; i < languagePropertyKeysArray.length; i++) {\n if (Object.prototype.hasOwnProperty.call(currentTranslationObject, languagePropertyKeysArray[i])) {\n if (i == languagePropertyKeysArray.length - 1) {\n translatedString = currentTranslationObject[languagePropertyKeysArray[i]];\n } else {\n currentTranslationObject = currentTranslationObject[languagePropertyKeysArray[i]];\n }\n } else {\n break;\n }\n }\n }\n\n return translatedString;\n};\n","export const af = 'af';\nexport const am = 'am';\nexport const arDz = 'ar-dz';\nexport const arIq = 'ar-iq';\nexport const arKw = 'ar-kw';\nexport const arLy = 'ar-ly';\nexport const arMa = 'ar-ma';\nexport const arSa = 'ar-sa';\nexport const artn = 'ar-tn';\nexport const ar = 'ar';\nexport const az = 'az';\nexport const be = 'be';\nexport const bg = 'bg';\nexport const bi = 'bi';\nexport const bm = 'bm';\nexport const bnBd = 'bn-bd';\nexport const bn = 'bn';\nexport const bo = 'bo';\nexport const br = 'br';\nexport const bs = 'bs';\nexport const ca = 'ca';\nexport const cs = 'cs';\nexport const cv = 'cv';\nexport const cy = 'cy';\nexport const da = 'da';\nexport const deAt = 'de-at';\nexport const deCh = 'de-ch';\nexport const de = 'de';\nexport const dv = 'dv';\nexport const el = 'el';\nexport const enAu = 'en-au';\nexport const enCa = 'en-ca';\nexport const enGb = 'en-gb';\nexport const enIe = 'en-ie';\nexport const enIl = 'en-il';\nexport const enIn = 'en-in';\nexport const enNz = 'en-nz';\nexport const enSg = 'en-sg';\nexport const enTt = 'en-tt';\nexport const en = 'en';\nexport const eo = 'eo';\nexport const esDo = 'es-do';\nexport const es = 'es';\nexport const et = 'et';\nexport const eu = 'eu';\nexport const fa = 'fa';\nexport const fi = 'fi';\nexport const fo = 'fo';\nexport const frCa = 'fr-ca';\nexport const frCh = 'fr-ch';\nexport const fr = 'fr';\nexport const fy = 'fy';\nexport const ga = 'ga';\nexport const gd = 'gd';\nexport const gl = 'gl';\nexport const gomLatn = 'gom-latn';\nexport const gu = 'gu';\nexport const he = 'he';\nexport const hi = 'hi';\nexport const hr = 'hr';\nexport const ht = 'ht';\nexport const hu = 'hu';\nexport const hyAm = 'hy-am';\nexport const id = 'id';\nexport const is = 'is';\nexport const itCh = 'it-ch';\nexport const it = 'it';\nexport const ja = 'ja';\nexport const jv = 'jv';\nexport const ka = 'ka';\nexport const kk = 'kk';\nexport const km = 'km';\nexport const kn = 'kn';\nexport const ko = 'ko';\nexport const ku = 'ku';\nexport const ky = 'ky';\nexport const lb = 'lb';\nexport const lo = 'lo';\nexport const lt = 'lt';\nexport const lv = 'lv';\nexport const me = 'me';\nexport const mi = 'mi';\nexport const mk = 'mk';\nexport const ml = 'ml';\nexport const mn = 'mn';\nexport const mr = 'mr';\nexport const msMy = 'ms-my';\nexport const ms = 'ms';\nexport const mt = 'mt';\nexport const my = 'my';\nexport const nb = 'nb';\nexport const ne = 'ne';\nexport const nlBe = 'nl-be';\nexport const nl = 'nl';\nexport const nn = 'nn';\nexport const ocLnc = 'oc-lnc';\nexport const paIn = 'pa-in';\nexport const pl = 'pl';\nexport const ptBr = 'pt-br';\nexport const pt = 'pt';\nexport const rn = 'rn';\nexport const ro = 'ro';\nexport const ru = 'ru';\nexport const rw = 'rw';\nexport const sd = 'sd';\nexport const se = 'se';\nexport const si = 'si';\nexport const sk = 'sk';\nexport const sl = 'sl';\nexport const sq = 'sq';\nexport const srCyrl = 'sr-cyrl';\nexport const sr = 'sr';\nexport const ss = 'ss';\nexport const svFi = 'sv-fi';\nexport const sv = 'sv';\nexport const sw = 'sw';\nexport const ta = 'ta';\nexport const te = 'te';\nexport const tet = 'tet';\nexport const tg = 'tg';\nexport const th = 'th';\nexport const tk = 'tk';\nexport const tlPh = 'tl-ph';\nexport const tlh = 'tlh';\nexport const tr = 'tr';\nexport const tzl = 'tzl';\nexport const tzmLatn = 'tzm-latn';\nexport const tzm = 'tzm';\nexport const ugCn = 'ug-cn';\nexport const uk = 'uk';\nexport const ur = 'ur';\nexport const uzLatn = 'uz-latn';\nexport const uz = 'uz';\nexport const vi = 'vi';\nexport const xPseudo = 'x-pseudo';\nexport const yo = 'yo';\nexport const zhCn = 'zh-cn';\nexport const zhHk = 'zh-hk';\nexport const zhTw = 'zh-tw';\nexport const zh = 'zh';\nexport const esMx = 'es-mx';\nexport const esPr = 'es-pr';\nexport const esUs = 'es-us';\n","import AustraliaFlag from '@images/CountryFlags/Australia.png';\nimport BrazilFlag from '@images/CountryFlags/Brazil.png';\nimport CanadaFlag from '@images/CountryFlags/Canada.png';\nimport FranceFlag from '@images/CountryFlags/France.png';\nimport GermanyFlag from '@images/CountryFlags/Germany.png';\nimport GlobeFlag from '@images/CountryFlags/Globe.png';\nimport IrelandFlag from '@images/CountryFlags/Ireland.png';\nimport ItalyFlag from '@images/CountryFlags/Italy.png';\nimport MexicoFlag from '@images/CountryFlags/Mexico.png';\nimport NetherlandsFlag from '@images/CountryFlags/Netherlands.png';\nimport PolandFlag from '@images/CountryFlags/Poland.png';\nimport SingaporeFlag from '@images/CountryFlags/Singapore.png';\nimport SpainFlag from '@images/CountryFlags/Spain.png';\nimport SwedenFlag from '@images/CountryFlags/Sweden.png';\nimport UAEFlag from '@images/CountryFlags/UAE.png';\nimport UKFlag from '@images/CountryFlags/UK.png';\nimport CaribbeanFlag from '@images/CountryFlags/Caribbean.png';\nimport IndonesianFlag from '@images/CountryFlags/Indonesian.png';\nimport JapanFlag from '@images/CountryFlags/Japan.png';\n\nexport const CountryFlags = {\n australia: AustraliaFlag,\n brazil: BrazilFlag,\n canada: CanadaFlag,\n france: FranceFlag,\n germany: GermanyFlag,\n ireland: IrelandFlag,\n italy: ItalyFlag,\n mexico: MexicoFlag,\n netherlands: NetherlandsFlag,\n poland: PolandFlag,\n singapore: SingaporeFlag,\n spain: SpainFlag,\n sweden: SwedenFlag,\n uae: UAEFlag,\n uk: UKFlag,\n worldwide: GlobeFlag,\n caribbean: CaribbeanFlag,\n indonesian: IndonesianFlag,\n japan: JapanFlag,\n};\n","import { languageRoutes } from './languageRoutes';\nimport { LanguageCode } from '@models/languageCode';\nimport { LanguageRoute, LanguageRouteKey } from '@models/languageRoute';\nimport { es, frCa, de, it, fr, ptBr, id } from '@models/dayJsLanguageCodes';\nimport { MobileDemoBannerType } from '@models/mobileDemoBanner';\nimport { CountryFlags } from '@helpers/staticImages/countryFlags';\n\nexport const languageRegions = Object.freeze({\n Global: 'Global',\n America: 'America',\n Europe: 'Europe',\n Asia: 'Asia',\n Australia: 'Australia',\n MiddleEast: 'MiddleEast',\n});\n\nexport interface Language {\n id: number;\n code: LanguageCode;\n alias: string;\n showInDropDown: boolean;\n urlPrefix: string;\n tempUrlPrefix?: string;\n dayjsLanguageCode?: string;\n name: string;\n region: string;\n routes: LanguageRoute;\n formDefaults: {\n noIndex?: boolean;\n };\n showGeotabSubscribe: boolean;\n isEnglish: boolean;\n isEuLanguage: boolean;\n enableSalesForceExtraField: {\n requestDemo: boolean;\n contactUsForm: boolean;\n platformPartnersForm: boolean;\n };\n flagPath: string;\n locale: string;\n disableLanguageSelection?: boolean;\n mobileDemoBannerType: MobileDemoBannerType;\n enableChatbox: boolean;\n}\n\nexport const languages: Language[] = [\n {\n id: 1,\n code: LanguageCode.en,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/',\n name: 'WorldWide (English)',\n region: languageRegions.Global,\n routes: languageRoutes.en,\n formDefaults: {\n noIndex: false,\n },\n showGeotabSubscribe: true,\n isEnglish: true,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.worldwide,\n locale: 'en_US',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: true,\n },\n {\n id: 2,\n code: LanguageCode.enGb,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/uk/',\n name: 'UK (English)',\n region: languageRegions.Europe,\n formDefaults: {\n noIndex: false,\n },\n routes: languageRoutes.enUk,\n showGeotabSubscribe: true,\n isEnglish: true,\n isEuLanguage: true,\n enableSalesForceExtraField: {\n requestDemo: true,\n contactUsForm: true,\n platformPartnersForm: true,\n },\n flagPath: CountryFlags.uk,\n locale: 'en_GB',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: true,\n },\n {\n id: 3,\n code: LanguageCode.frCa,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/fr-ca/',\n tempUrlPrefix: '/fr-ca/',\n name: 'Canada (Français)',\n region: languageRegions.America,\n routes: languageRoutes.frCa,\n dayjsLanguageCode: frCa,\n showGeotabSubscribe: false,\n isEnglish: false,\n isEuLanguage: false,\n formDefaults: {\n noIndex: true,\n },\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.canada,\n locale: 'fr_CA',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 4,\n code: LanguageCode.es,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/es/',\n name: 'Spain (Español)',\n region: languageRegions.Europe,\n routes: languageRoutes.es,\n dayjsLanguageCode: es,\n showGeotabSubscribe: true,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: false,\n isEuLanguage: true,\n enableSalesForceExtraField: {\n requestDemo: true,\n contactUsForm: true,\n platformPartnersForm: true,\n },\n flagPath: CountryFlags.spain,\n locale: 'es_ES',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 5,\n code: LanguageCode.de,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/de/',\n name: 'Germany (Deutsch)',\n region: languageRegions.Europe,\n routes: languageRoutes.de,\n dayjsLanguageCode: de,\n showGeotabSubscribe: true,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: false,\n isEuLanguage: true,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: true,\n platformPartnersForm: true,\n },\n flagPath: CountryFlags.germany,\n locale: 'de_DE',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 6,\n code: LanguageCode.it,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/it/',\n name: 'Italy (Italiano)',\n routes: languageRoutes.it,\n region: languageRegions.Europe,\n formDefaults: {\n noIndex: false,\n },\n dayjsLanguageCode: it,\n showGeotabSubscribe: true,\n isEnglish: false,\n isEuLanguage: true,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.italy,\n locale: 'it_IT',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 7,\n code: LanguageCode.frFr,\n alias: fr,\n showInDropDown: true,\n urlPrefix: '/fr/',\n name: 'France (Français)',\n routes: languageRoutes.frFr,\n region: languageRegions.Europe,\n dayjsLanguageCode: fr,\n showGeotabSubscribe: true,\n formDefaults: {\n noIndex: false,\n },\n isEuLanguage: true,\n isEnglish: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: true,\n platformPartnersForm: true,\n },\n flagPath: CountryFlags.france,\n locale: 'fr_FR',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 8,\n code: LanguageCode.ptBr,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/pt-br/',\n name: 'Brasil (Português)',\n region: languageRegions.America,\n routes: languageRoutes.ptBr,\n dayjsLanguageCode: ptBr,\n showGeotabSubscribe: true,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: false,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.brazil,\n locale: 'pt_BR',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 9,\n code: LanguageCode.enAu,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/au/',\n name: 'Australia (English)',\n region: languageRegions.Australia,\n routes: languageRoutes.enAu,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: true,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: true,\n platformPartnersForm: true,\n },\n flagPath: CountryFlags.australia,\n locale: 'en_AU',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: true,\n },\n {\n id: 11,\n code: LanguageCode.esMx,\n alias: 'es-latam',\n dayjsLanguageCode: es,\n showInDropDown: true,\n urlPrefix: '/es-latam/',\n name: 'Latin America (Español)',\n region: languageRegions.America,\n routes: languageRoutes.esMx,\n showGeotabSubscribe: true,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: false,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.mexico,\n locale: 'es_MX',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 12,\n code: LanguageCode.pl,\n alias: '',\n showInDropDown: false,\n urlPrefix: '/pl/',\n name: 'Poland (Polski)',\n region: languageRegions.Europe,\n routes: languageRoutes.pl,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: true,\n },\n isEnglish: false,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.poland,\n locale: 'pl_PL',\n mobileDemoBannerType: 'link',\n enableChatbox: false,\n },\n {\n id: 13,\n code: LanguageCode.nl,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/nl/',\n name: 'Nederlands (Nederlands)',\n routes: languageRoutes.nl,\n region: languageRegions.Europe,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: false,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.netherlands,\n locale: 'nl_NL',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: false,\n },\n {\n id: 14,\n code: LanguageCode.se,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/se/',\n name: 'Sweden (Svenska)',\n region: languageRegions.Europe,\n routes: languageRoutes.se,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: false,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.sweden,\n locale: 'sv_SE',\n mobileDemoBannerType: 'link',\n enableChatbox: false,\n },\n {\n id: 15,\n code: LanguageCode.ae,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/ae/',\n name: 'Middle East (English)',\n region: languageRegions.MiddleEast,\n routes: languageRoutes.ae,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: false,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.uae,\n locale: 'ar_AE',\n mobileDemoBannerType: 'link',\n enableChatbox: true,\n },\n {\n id: 16,\n code: LanguageCode.ie,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/ie/',\n name: 'Ireland (English)',\n region: languageRegions.Europe,\n routes: languageRoutes.ie,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: true,\n isEuLanguage: true,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.ireland,\n locale: 'en_IE',\n mobileDemoBannerType: 'link',\n enableChatbox: true,\n },\n {\n id: 17,\n code: LanguageCode.apac,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/apac/',\n name: 'APAC (English)',\n region: languageRegions.Asia,\n disableLanguageSelection: false,\n routes: languageRoutes.apac,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: false,\n },\n isEnglish: true,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.singapore,\n locale: 'en_SG',\n mobileDemoBannerType: 'popoutButton',\n enableChatbox: true,\n },\n {\n id: 18,\n code: LanguageCode.enCb,\n alias: '',\n showInDropDown: false,\n urlPrefix: '/en-cb/',\n name: 'Caribbean (English)',\n region: languageRegions.America,\n routes: languageRoutes.enCb,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: true,\n },\n isEnglish: true,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.caribbean,\n locale: 'en-TT',\n mobileDemoBannerType: 'link',\n enableChatbox: true,\n },\n {\n id: 19,\n code: LanguageCode.idn,\n alias: '',\n showInDropDown: true,\n urlPrefix: '/idn/',\n dayjsLanguageCode: id,\n name: 'Indonesia (Bahasa)',\n region: languageRegions.Asia, // update this value to show on region selector\n routes: languageRoutes.idn,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: true,\n },\n isEnglish: true,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.indonesian,\n locale: 'id_ID',\n mobileDemoBannerType: 'link',\n enableChatbox: false,\n },\n {\n id: 20,\n code: LanguageCode.jp,\n alias: '',\n showInDropDown: false,\n urlPrefix: '/jp/',\n dayjsLanguageCode: id,\n name: 'Japan (Japanese)',\n region: languageRegions.Asia,\n routes: languageRoutes.jp,\n showGeotabSubscribe: false,\n formDefaults: {\n noIndex: true,\n },\n isEnglish: true,\n isEuLanguage: false,\n enableSalesForceExtraField: {\n requestDemo: false,\n contactUsForm: false,\n platformPartnersForm: false,\n },\n flagPath: CountryFlags.japan,\n locale: 'ja_JP',\n mobileDemoBannerType: 'link',\n enableChatbox: false,\n },\n];\n\nexport function getLanguageById(languageId: number | undefined): Language | undefined {\n return languageId ? languages.find((language) => language.id === languageId) : undefined;\n}\n\nexport function getLanguageByCode(languageCode: string): Language | undefined {\n return languages.find((language) => language.code === languageCode);\n}\n\nexport function getLanguageNameById(languageId: number | undefined): string | undefined {\n const language = getLanguageById(languageId);\n return language && language.name;\n}\n\nexport function getAliasByCode(languageCode: string): string | undefined {\n const language = getLanguageByCode(languageCode);\n return language ? language.alias || languageCode : languageCode;\n}\n\nexport function getLanguageNameByCode(languageCode: string): string | undefined {\n const language = getLanguageByCode(languageCode);\n return language && language.name;\n}\n\nexport function getDayJsCodeByLanguageCode(languageCode: string): string {\n const language = getLanguageByCode(languageCode);\n return (language && language.dayjsLanguageCode) || LanguageCode.en;\n}\n\nexport function getLanguageUrlPrefixByCode(languageCode: string): string {\n const language = getLanguageByCode(languageCode);\n return (language && (language.tempUrlPrefix || language.urlPrefix)) || '/';\n}\n\nexport function getLanguageUrlPrefixById(languageId?: number): string {\n const language = getLanguageById(languageId);\n return (language && language.urlPrefix) || '/';\n}\n\nexport function getAdminLanguageUrlPrefixById(languageId?: number): string {\n const language = getLanguageById(languageId);\n return (language && (language.tempUrlPrefix || language.urlPrefix)) || '/';\n}\n\nexport function getLanguageRouteByCodeAndRouteKey(\n languageCode: string,\n routeKey: LanguageRouteKey\n): string | undefined {\n const language = getLanguageByCode(languageCode);\n return language ? language.routes[routeKey] : '/';\n}\n\nexport function getLanguageRouteByIdAndRouteKey(routeKey: LanguageRouteKey, languageId?: number): string | undefined {\n const language = getLanguageById(languageId);\n return language ? language.routes[routeKey] : '/';\n}\n\nexport function getLanguageRouteAndPrefixByCodeAndRouteKey(languageCode: string, routeKey: LanguageRouteKey): string {\n const language = getLanguageByCode(languageCode);\n return language\n ? routeKey\n ? `${language.tempUrlPrefix || language.urlPrefix}${language.routes[routeKey]}`\n : language.tempUrlPrefix || language.urlPrefix\n : '/';\n}\n\nexport function getLanguageRouteAndPrefixByIdAndRouteKey(languageId?: number, routeKey?: LanguageRouteKey): string {\n const language = getLanguageById(languageId);\n return language\n ? routeKey\n ? `${language.tempUrlPrefix || language.urlPrefix}${language.routes[routeKey]}`\n : language.tempUrlPrefix || language.urlPrefix\n : '/';\n}\n\nexport function getFormDefaults(languageId: number): { noIndex?: boolean } {\n const language = getLanguageById(languageId);\n return language ? language.formDefaults : {};\n}\n\nexport function getPageRelativeUrl(languageId: number, slug: string): string {\n const languagePrefix = getAdminLanguageUrlPrefixById(languageId);\n const slugToAppend = slug === '/' ? '' : slug;\n return `${languagePrefix}${slugToAppend}`;\n}\n\nexport function getArticleRelativeUrl(routeKey: LanguageRouteKey, languageId: number, slug: string): string {\n const languagePrefix = getAdminLanguageUrlPrefixById(languageId);\n const languageTypePrefix = getLanguageRouteByIdAndRouteKey(routeKey, languageId);\n const slugToAppend = slug === '/' ? '' : slug;\n return `${languagePrefix}${languageTypePrefix}${slugToAppend}`;\n}\n\nexport function isEuLanguage(languageCode: string): boolean {\n const language = getLanguageByCode(languageCode);\n return (language && language.isEuLanguage) || false;\n}\n\nexport function getAllEnglishLanguageCodes(): string[] {\n return languages.filter((language) => language.isEnglish === true).map((obj) => obj.code) || [];\n}\n\n//regions - Array of regions to filter languages\nexport function getLanguagesByRegions(regions: string[]): Language[] {\n return languages\n .sort((first, second) => first.name.localeCompare(second.name))\n .filter(({ region, disableLanguageSelection }) => regions.includes(region) && !disableLanguageSelection);\n}\n\nexport function getFlagPathByCode(languageCode: string): string | undefined {\n return getLanguageByCode(languageCode)?.flagPath;\n}\n\nexport function getLocaleByCode(languageCode: string): string | undefined {\n return getLanguageByCode(languageCode)?.locale;\n}\n","export function hasValue(value: unknown): boolean {\n if (typeof value === 'string') {\n return value.trim().length > 0;\n }\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n return value.length > 0;\n } else {\n return !!value && Object.keys(value).length > 0;\n }\n }\n\n if (value === undefined || value === false) {\n return false;\n }\n\n return true;\n}\n\ninterface HasLengthOptions {\n max?: number;\n min?: number;\n}\n\nexport type HasLengthPayload = HasLengthOptions | number;\n\nexport function isLengthValid(length: HasLengthPayload, value: unknown): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const trimmedValue = value.trim();\n\n if (typeof length === 'number') {\n return trimmedValue.length === length;\n }\n\n const { max, min } = length;\n let valid = true;\n\n if (typeof max === 'number' && trimmedValue.length > max) {\n valid = false;\n }\n\n if (typeof min === 'number' && trimmedValue.length < min) {\n valid = false;\n }\n\n return valid;\n}\n","export const regexPatterns: Record = {\n slug: /^[\\p{Ll}\\p{Lo}\\d/-]*\\/$/u,\n fleetSize: /^[\\d+]+$/,\n requireHttpHttps: /^(http|https):\\/\\//,\n};\n\nexport const regexErrorMessages: Record = {\n slug: 'The URL Slug may only contain lowercase letters, numbers, slashes or dashes, and must end with a trailing forward slash.',\n fleetSize: 'The fleet size should contain numbers and + sign only',\n linkedInLink: 'LinkedIn link needs to start with http:// or https://',\n twitterLink: 'Twitter link needs to start with http:// or https://',\n facebookLink: 'Facebook link needs to start with http:// or https://',\n instagramLink: 'Instagram link needs to start with http:// or https://',\n};\n","export function isAdminRoute(slug: string): boolean {\n return slug.startsWith('/admin/');\n}\n","import CorpProfile from '@images/PressRoom/icon-corporate-profile.svg';\nimport LeadershipBio from '@images/PressRoom/icon-leadership-bios.svg';\nimport MediaGuidelines from '@images/PressRoom/icon-media-guidelines.svg';\nimport LegalPolicy from '@images/PressRoom/icon-legal-policy.svg';\nimport MediaContact from '@images/PressRoom/icon-media-contact.svg';\nimport PkBackground from '@images/PressRoom/presskit-background@2x.jpg';\n\nexport const PressRoomImages = {\n corpProfile: CorpProfile,\n leadershipBio: LeadershipBio,\n mediaGuidelines: MediaGuidelines,\n legalPolicy: LegalPolicy,\n mediaContact: MediaContact,\n pkBackground: PkBackground,\n};\n","import GeneralInquiriesHeroImage from '@images/StaticPages/ContactUs/general-inquiries-hero-image@2x.jpg';\nimport CustomerSupportIcon from '@images/StaticPages/ContactUs/icon-customer-support.svg';\nimport GeneralInquiriesIcon from '@images/StaticPages/ContactUs/icon-general-inquiries.svg';\nimport SalesInquiriesIcon from '@images/StaticPages/ContactUs/icon-sales-inquiry.svg';\nimport ResellerSuport from '@images/StaticPages/ContactUs/reseller-support.jpg';\nimport SalesInquiryHeroImage from '@images/StaticPages/ContactUs/sales-inquiry-hero-image2x.jpg';\nimport FaqHeroImage from '@images/StaticPages/Faq/faqs-hero-image@2x.jpg';\nimport PhoneSoftwareEnergy from '@images/StaticPages/SubscribePage/geotab-phone-software-energy.jpg';\nimport SubscribePageBannerImage from '@images/StaticPages/SubscribePage/fleet-newsletter-landing-page-image@2x.png';\nimport SubscribeCta from '@images/StaticPages/SubscribePage/geotab-subscribe-cta.jpg';\nimport IconSubscribeSuccess from '@images/StaticPages/SubscribePage/icon-form-submission-success.svg';\nimport SubscribeFeatureImage from '@images/StaticPages/SubscribePage/subscribe-feature-image@2x.jpg';\nimport IconFirmware from '@images/StaticPages/SupportDocuments/icon-firmware.svg';\nimport IconHardware from '@images/StaticPages/SupportDocuments/icon-hardware.svg';\nimport IconHarnessAdapter from '@images/StaticPages/SupportDocuments/icon-harness-and-adapter.svg';\nimport IconIoxAddOn from '@images/StaticPages/SupportDocuments/icon-iox-and-add-on.svg';\nimport BlogGraphic from '@images/StaticPages/Videos/blog-graphic.svg';\nimport ForumsGraphic from '@images/StaticPages/Videos/forums-graphic.svg';\nimport WhitePapersGraphic from '@images/StaticPages/Videos/white-papers-graphic.svg';\n\nexport const contactUs = {\n generalInquiriesHeroImage: GeneralInquiriesHeroImage,\n customerSupportIcon: CustomerSupportIcon,\n generalInquiriesIcon: GeneralInquiriesIcon,\n salesInquiriesIcon: SalesInquiriesIcon,\n resellerSupport: ResellerSuport,\n salesInquiryHeroImage: SalesInquiryHeroImage,\n};\n\nexport const faq = {\n faqHeroImage: FaqHeroImage,\n};\n\nexport const subscribePage = {\n phoneSoftwareEnergy: PhoneSoftwareEnergy,\n subscribePageBannerImage: SubscribePageBannerImage,\n subscribeCta: SubscribeCta,\n iconSubscribeSuccess: IconSubscribeSuccess,\n subscribeFeatureImage: SubscribeFeatureImage,\n};\n\nexport const supportDocuments = {\n iconFirmware: IconFirmware,\n iconHardware: IconHardware,\n iconHarnessAdapter: IconHarnessAdapter,\n iconIoxAddOn: IconIoxAddOn,\n};\n\nexport const videos = {\n blogGraphic: BlogGraphic,\n forumsGraphic: ForumsGraphic,\n whitePapersGraphic: WhitePapersGraphic,\n};\n","import { resolveImagePath, resolveGeneralFilePath, mediaUrlPrefixToken, generalFileUrlPrefixToken } from './gallery';\n\n// eslint-disable-next-line no-useless-escape\nconst isInternalLinkRegex = new RegExp(\n // eslint-disable-next-line no-useless-escape\n /^((https?:\\/\\/(www|webtest3|webtest2)\\.geotab\\.com)|\\/).*/\n);\n\n// Example: /static/test.jpg\n// eslint-disable-next-line no-useless-escape\nconst hasDotAfterSlashRegex = new RegExp(/(\\/)([^\\/]*)(\\.)([^\\/]*)([^\\/]$)/);\n\n// eslint-disable-next-line no-useless-escape\nexport const matchesWebsitePattern = (value: string): boolean =>\n value.search(\n // eslint-disable-next-line no-useless-escape\n /[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)/\n ) >= 0;\n\n// eslint-disable-next-line no-useless-escape\nexport const isYoutubeURL = new RegExp(\n /https?:\\/\\/(?:[0-9A-Z-]+\\.)?(?:youtu\\.be\\/|youtube(?:-nocookie)?\\.com\\S*?[^\\w\\s-])([\\w-]{11})(?=[^\\w-]|$)(?![?=&+%\\w.-]*(?:['\"][^<>]*>|<\\/a>))[?=&+%\\w.-]*/gi\n);\n\nexport function escapeSpecialChar(text: string): string {\n return text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function ensureInternalURLTrailingSlash(inputString: string): string {\n if (\n !isAnchorLink(inputString) &&\n !isResource(inputString) &&\n !isQueryStringLink(inputString) &&\n isInternalLink(inputString) &&\n !lastCharacterIsSlash(inputString)\n ) {\n return `${inputString}/`;\n } else {\n return inputString;\n }\n}\n\nexport function formatString(string: string, concatString: string): string {\n return `${string}${concatString ? `-${concatString}` : ''}`\n .toLowerCase()\n .trim()\n .replace(/ /g, '-')\n .replace(/:/g, '')\n .replace(/,/g, '')\n .replace(/&/g, 'and');\n}\n\nexport function lastCharacterIsSlash(inputString: string): boolean {\n return inputString && inputString.length > 0 && inputString[inputString.length - 1] === '/' ? true : false;\n}\n\nexport function isInternalLink(inputString: string): boolean {\n return isInternalLinkRegex.test(inputString);\n}\n\nexport function isInternalOrBaseLink(inputString: string, baseUrl: string): boolean {\n return isInternalLinkRegex.test(inputString) || inputString.includes(baseUrl);\n}\n\nfunction isResource(inputString: string): boolean {\n return hasDotAfterSlashRegex.test(inputString);\n}\n\nfunction isAnchorLink(inputString: string): boolean {\n return inputString && inputString.length > 0 && inputString.includes('#') ? true : false;\n}\n\nfunction isQueryStringLink(inputString: string): boolean {\n return inputString && inputString.length > 0 && inputString.includes('?') ? true : false;\n}\n\nexport function ensureGeotabTitle(inputString: string): string {\n if (inputString && inputString.length > 0 && !inputString.includes('| Geotab')) {\n return `${inputString} | Geotab`;\n } else {\n return inputString;\n }\n}\n\nexport function classCreator(\n classes: { [key: string]: string },\n type: string,\n literal = ''\n): (literal: string) => string {\n const defaultName = 'default';\n classes[defaultName + literal];\n return function createClass(literal: string) {\n return `${classes[defaultName + literal] || ''} ${classes[type + literal] || ''}`;\n };\n}\n\nexport function ensureHttps(url: string): string {\n if (!url) {\n return url;\n }\n\n if (\n url &&\n (url.toLowerCase().startsWith('http://') ||\n url.toLowerCase().startsWith('https://') ||\n url.toLowerCase().startsWith('mailto:') ||\n url.startsWith('#'))\n ) {\n return url;\n } else {\n return `https://${url}`;\n }\n}\n\nexport function ensureEmbededYoutubeURL(videoURL: string): string {\n if (videoURL.includes('youtu.be') || videoURL.includes('youtube.com')) {\n const youtubeId = ensureHttps(videoURL).replace(isYoutubeURL, '$1');\n return `https://www.youtube.com/embed/${youtubeId}?enablejsapi=1`;\n } else {\n return videoURL;\n }\n}\n\nexport function pluralizeEntityType(entityTypeName: string): string {\n if (!entityTypeName) {\n return entityTypeName;\n }\n\n return entityTypeName.toLowerCase().endsWith('y')\n ? `${entityTypeName.substring(0, entityTypeName.length - 1)}ies`\n : `${entityTypeName}s`;\n}\n\nfunction getPhoneExtensionIfExists(phoneNumber: string): string {\n return phoneNumber.slice(0, Math.max(phoneNumber.length - 10, 0));\n}\n\nfunction getPhoneNumberWithoutExtension(phoneNumber: string): string {\n return phoneNumber.slice(Math.max(phoneNumber.length - 10, 0), phoneNumber.length).padEnd(10, ' ');\n}\n\nexport function decoratedPhoneNumber(phoneNumber: string): string {\n if (phoneNumber) {\n phoneNumber = phoneNumber.toString();\n const extension = getPhoneExtensionIfExists(phoneNumber);\n const phoneNumberWithoutExtension = getPhoneNumberWithoutExtension(phoneNumber);\n const separatedPhoneNumber = phoneNumberWithoutExtension.match(/(.{3})(.{3})(.{4})/);\n return `${extension.length > 0 ? `+${extension} ` : ''}(${separatedPhoneNumber && separatedPhoneNumber[1]}) ${\n separatedPhoneNumber && separatedPhoneNumber[2]\n }-${separatedPhoneNumber && separatedPhoneNumber[3]}`;\n } else {\n return '';\n }\n}\n\nexport function undecoratePhoneNumber(phoneNumber: string): string {\n const phoneNumberFormat = /(\\+\\d*)?\\(\\d{3}\\) (\\d{3})-(\\d{4})/;\n return phoneNumberFormat.test(phoneNumber) ? phoneNumber.replace(/\\D/g, '') : '';\n}\n\nexport function replaceValueInString(lookupString: string, replacementString: string, inputString?: string): string {\n if (inputString && inputString.includes(lookupString)) {\n const replaceRegex = new RegExp(lookupString, 'gi');\n return inputString.replace(replaceRegex, replacementString);\n }\n return inputString || '';\n}\n\nexport function getPrefixStringWithBaseUrlFunction(\n baseUrl: string,\n mediaUrlPrefix: string,\n generalFileUrlPrefix: string\n): (string?: string) => string {\n if (baseUrl && baseUrl.endsWith('/')) {\n baseUrl = baseUrl.substring(0, baseUrl.length - 1);\n }\n\n return (string?: string) => {\n if (typeof string === 'string') {\n if (string.startsWith('http://') || string.startsWith('https://')) {\n return string;\n }\n if (mediaUrlPrefix && string.includes(mediaUrlPrefixToken)) {\n return encodeURI(resolveImagePath(mediaUrlPrefix, string));\n }\n if (generalFileUrlPrefix && string.includes(generalFileUrlPrefixToken)) {\n return encodeURI(resolveGeneralFilePath(generalFileUrlPrefix, string));\n }\n if (baseUrl && !string.startsWith(baseUrl)) {\n const stringToPrefix = !string.startsWith('/') ? `/${string}` : string;\n return encodeURI(`${baseUrl}${stringToPrefix}`);\n }\n }\n\n return encodeURI(string as string);\n };\n}\n\nexport function capitalizeFirstLetter(string: string): string {\n return string && string.length > 0 ? string[0].toUpperCase() + string.slice(1) : string;\n}\n\nexport function trimEndingLetterS(string: string): string {\n return string && (string[string.length - 1] === 's' || string[string.length - 1] === 'S')\n ? string.slice(0, string.length - 1)\n : string;\n}\n\nexport function getRandomString(): string {\n return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);\n}\n\nexport function tryDecodeURI(inputString: string): string {\n try {\n return decodeURI(inputString);\n } catch (error) {\n return inputString;\n }\n}\n\nexport function formatUrlString(string: string): string {\n return string.toLowerCase().replace(/\\s/g, '%20');\n}\n\nexport function removeUrlParameters(urlString: string): string {\n return isQueryStringLink(urlString) ? urlString.split('?')[0] : urlString;\n}\n\nexport function removeStartingSlash(urlString: string): string {\n return urlString.startsWith('/') ? urlString.substring(1) : urlString;\n}\n\nexport const removeElementsFromHtmlByTag = (content: string, ...tags: string[]): string => {\n if (content) {\n const parser = new DOMParser();\n const doc = parser.parseFromString(content, 'text/html');\n if (Array.isArray(tags)) {\n tags.forEach((tag) => {\n const elements = doc.body.getElementsByTagName(tag);\n Array.from(elements).forEach((element) => element.remove());\n });\n }\n return doc.body.innerHTML.toString();\n } else {\n return content;\n }\n};\n\nexport function lastCharacterIsComma(inputString: string): boolean {\n return inputString && inputString.length > 0 && inputString[inputString.length - 1] === ',' ? true : false;\n}\n\nexport function removeSubstringByDelimiter(inputString: string, removeIndex: number, delimiter: string): string {\n const stringPartsArr = inputString.split(delimiter);\n stringPartsArr.splice(removeIndex, 1);\n\n return stringPartsArr.join(delimiter);\n}\n\nexport function removeHTMLTags(htmlString: string): string {\n const parser = new DOMParser();\n const doc = parser.parseFromString(htmlString, 'text/html');\n return doc.body.textContent || '';\n}\n","import { regexErrorMessages, regexPatterns } from './regexHelper';\nimport {\n blogEntityDescription,\n blogEntityTitle,\n blogEntityName,\n articleHiddenTag,\n articleIndexStatus,\n articlePublishedStatus,\n articleCanonical,\n articleSlug,\n articleLanguage,\n entityRedirectUrl,\n slugEntityBreadcrumbDisplayName,\n} from '@helpers/AccessibleFormHelperConstants';\nimport { BlogFormHelper } from '@models/blogForm';\nimport { Tag } from '@models/tag';\nimport { EntityName } from '@models/entity';\nimport { regexMatchesOrIsEmpty } from '@helpers/validators';\nimport { breadcrumbDisplayNameValidator } from './validationRules';\nimport { UserRole } from '@models/authentication';\n\nconst friendlyName = 'Tag';\nexport const tagFormHelper: BlogFormHelper = {\n name: 'Tag',\n entityName: EntityName.Tag,\n apiControllerName: 'tag',\n hasMediaField: false,\n fields: [\n {\n id: 'tag-language',\n key: 'language',\n name: 'Language',\n required: true,\n type: 'select',\n list: 'languages',\n listItemValueKey: 'id',\n readOnlyModes: ['edit'],\n formHelper: articleLanguage(friendlyName),\n },\n {\n id: 'tag-name',\n key: 'name',\n name: 'Tag Name',\n required: true,\n maxLength: 100,\n type: 'text',\n formHelper: blogEntityName(friendlyName),\n },\n {\n id: 'tag-title',\n key: 'title',\n name: 'SEO Title',\n required: true,\n type: 'text',\n formHelper: blogEntityTitle(friendlyName),\n },\n {\n id: 'tag-description',\n key: 'description',\n name: 'SEO Description',\n required: true,\n type: 'text',\n formHelper: blogEntityDescription(friendlyName),\n },\n {\n id: 'tag-slug',\n key: 'slug',\n name: 'Url Slug',\n validators: [regexMatchesOrIsEmpty(regexPatterns.slug, regexErrorMessages.slug)],\n required: true,\n maxLength: 100,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n lowercaseOnChange: true,\n },\n formHelper: articleSlug(friendlyName),\n },\n {\n id: 'tag-breadcrumbDisplayName',\n key: 'breadcrumbDisplayName',\n name: 'Breadcrumb Display Name',\n validators: [breadcrumbDisplayNameValidator],\n required: false,\n type: 'text',\n formHelper: slugEntityBreadcrumbDisplayName(friendlyName),\n },\n {\n id: 'tag-canonical',\n key: 'canonical',\n name: 'Canonical Url',\n required: false,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n },\n formHelper: articleCanonical(friendlyName),\n },\n {\n id: 'tag-redirectUrl',\n key: 'redirectUrl',\n name: 'Redirect Url',\n required: false,\n maxLength: 5000,\n type: 'text',\n sanitizationConfiguration: {\n autoTrim: true,\n },\n formHelper: entityRedirectUrl(friendlyName),\n },\n {\n id: 'tag-hidden',\n key: 'hidden',\n name: 'Hide tag on articles',\n required: false,\n type: 'checkbox',\n formHelper: articleHiddenTag,\n },\n {\n id: 'tag-noIndex',\n key: 'noIndex',\n name: 'No Index',\n required: false,\n type: 'checkbox',\n formHelper: articleIndexStatus(friendlyName),\n },\n {\n id: 'tag-publishedDate',\n key: 'publishedDateUtc',\n name: 'Published',\n type: 'publishBox',\n formHelper: articlePublishedStatus(friendlyName),\n modifiableByRoles: [UserRole.GeotabComCmsAdmin, UserRole.GeotabComArticleAdmin],\n },\n ],\n};\n\nexport const tagModel: Partial = {\n language: 1,\n name: '',\n slug: '',\n canonical: '',\n noIndex: false,\n status: 0,\n publishedDateUtc: '',\n};\n","import { Validator } from '@web-for-marketing/react-ui';\nimport { getValidatorMessage, hasLength, isNotEmpty, regexMatches } from '@helpers/validators';\nimport { regexErrorMessages, regexPatterns } from './regexHelper';\nimport { isSlugSegmentLengthValid } from './errors';\nimport { hasValue, isLengthValid } from '@helpers/operand';\nimport { SectionWidget } from '@models/widget';\n\nexport const altValidators: Validator[] = [\n (value, values) =>\n (values && !values.image) || (values && values.decoration) || hasValue(value) ? null : 'Alt field is empty',\n (value, values) =>\n (values && !values.image) || (values && values.decoration) || isLengthValid({ min: 15 }, value)\n ? null\n : getValidatorMessage('Alt text should be more than 15 characters long', true),\n];\n\nexport const widgetValidator: Validator = (value) => {\n function isWidget(value: unknown): value is SectionWidget {\n return typeof value === 'object' && value !== null;\n }\n\n if (isWidget(value)) {\n if (value.type === 'stats-highlights') {\n const errors: string[] = [];\n value.content.stats.forEach((content, index) => {\n if (content.url && !hasValue(content.ariaLabel)) {\n errors.push(`Aria label is required for stat ${index + 1}`);\n }\n });\n\n return errors.length ? errors.join('.') : null;\n }\n }\n\n return null;\n};\n\nexport const titleValidators: Validator[] = [\n isNotEmpty('A title is required'),\n hasLength(\n { max: 100 },\n 'Title should not be more than 100 characters. It is recommended to be between 20-70 characters',\n true\n ),\n];\n\nexport const titleHeaderSectionValidator: Validator = (value, values) =>\n !hasValue(value) && values?.headerSection ? 'A title is required for the header section' : null;\n\nexport const descriptionValidators: Validator[] = [\n isNotEmpty('A description is required'),\n hasLength({ max: 160 }, 'Description should not be more than 160 characters', true),\n];\n\nexport const slugValidators: Validator[] = [\n isNotEmpty('A slug is required'),\n regexMatches(regexPatterns.slug, regexErrorMessages.slug),\n (value) =>\n typeof value === 'string' && isSlugSegmentLengthValid(value, 80)\n ? null\n : { message: 'Each slug segment should not be over 80 characters', isWarning: true },\n];\n\nexport const authorNotPublishedValidator: Validator = (value, values) => {\n if (values && Array.isArray(values.authorList) && values.authorList.length > 0) {\n const author = values.authorList.find((item) => item.id === value);\n if (author && author.status === 0) {\n return {\n message:\n 'The associated author is currently unpublished. This blog post will not be accessible to the public until the author is published.',\n isWarning: true,\n };\n }\n }\n return null;\n};\n\nexport const breadcrumbDisplayNameValidator: Validator = hasLength(\n { max: 30 },\n 'Breadcrumb display name should not be more than 30 characters',\n true\n);\n\nexport const youtubeUrlValidators: Validator[] = [\n isNotEmpty('A Youtube URL is required'),\n (value) =>\n typeof value === 'string' && (value.includes('youtube.com/') || value.includes('youtu.be/'))\n ? null\n : 'That is not a valid Youtube URL. Please try another one.',\n];\n\nexport const driveShareUrlValidators: Validator[] = [\n isNotEmpty('A Google Drive public share link is required'),\n (value) =>\n typeof value === 'string' && value.includes('drive.google.com/')\n ? null\n : 'That is not a valid Google Drive share link. Please try another one.',\n];\n\nexport const blogFaqValidator: Validator = (value) => {\n if (Array.isArray(value) && value.length) {\n const isNotValid = value.some((content) => content.answer === '' || content.question === '');\n return isNotValid ? 'Please fill the required fields in the FAQ accordion' : null;\n }\n return null;\n};\n","import { Validator, ValidatorMessage } from '@web-for-marketing/react-ui';\nimport { hasValue, isLengthValid, HasLengthPayload } from '@helpers/operand';\nimport dayjs from 'dayjs';\nimport { FormComponent } from '@models/customForm';\n\nexport function getValidatorMessage(message: string, isWarning?: boolean): ValidatorMessage {\n return isWarning ? { message: message, isWarning: true } : message;\n}\n\nexport function isNotEmpty(message: string, isWarning?: boolean): Validator {\n return (value) => (hasValue(value) ? null : getValidatorMessage(message, isWarning));\n}\n\nexport function hasLength(length: HasLengthPayload, message: string, isWarning?: boolean): Validator {\n return (value) => (isLengthValid(length, value) ? null : getValidatorMessage(message, isWarning));\n}\n\nexport function hasDuplicateFieldID(message: string, isWarning?: boolean): Validator {\n return (value) => {\n const currentID = (value as FormComponent).fieldId;\n const hasDuplicate =\n (value as FormComponent).conditionalFields?.some((obj) =>\n obj.components.some((subcomponent) => subcomponent.fieldId === currentID)\n ) || false;\n\n return hasDuplicate ? getValidatorMessage(message, isWarning) : null;\n };\n}\n\nexport function notEmptyAndHasLength(length: HasLengthPayload, message: string, isWarning?: boolean): Validator {\n return (value) => (!value || isLengthValid(length, value) ? null : getValidatorMessage(message, isWarning));\n}\n\nexport function isNotEqual(field: string, message: string, isWarning?: boolean): Validator {\n const validatorMessage = getValidatorMessage(message, isWarning);\n\n return (value, values) => {\n if (values) {\n const fieldValue = values[field];\n\n if (typeof value === 'string' && typeof fieldValue === 'string') {\n return value.trim().toLowerCase() === fieldValue.trim().toLowerCase() ? validatorMessage : null;\n }\n\n return value === fieldValue ? validatorMessage : null;\n }\n\n return null;\n };\n}\n\nexport function regexMatches(pattern: RegExp, message: string, isWarning?: boolean): Validator {\n const validatorMessage = getValidatorMessage(message, isWarning);\n\n return (value) => (typeof value === 'string' && value.match(pattern) ? null : validatorMessage);\n}\n\nexport function regexMatchesOrIsEmpty(pattern: RegExp, message: string, isWarning?: boolean): Validator {\n const validatorMessage = getValidatorMessage(message, isWarning);\n\n return (value) =>\n typeof value === 'string' && (value.match(pattern) || value.length === 0) ? null : validatorMessage;\n}\n\nexport const hasValidDateString = (message: string, isWarning?: boolean): Validator => {\n const validatorMessage = getValidatorMessage(message, isWarning);\n\n function isValidDateString(value: string): boolean {\n return dayjs(value).isValid();\n }\n\n return (value) =>\n typeof value !== 'string' || (typeof value === 'string' && !isValidDateString(value)) ? validatorMessage : null;\n};\n\nexport const hasValidJsonString = (message: string, isWarning?: boolean): Validator => {\n const validatorMessage = getValidatorMessage(message, isWarning);\n\n function isValidJsonString(value: string): boolean {\n const regex = /^\\{.*\\}$/;\n if (!regex.test(value)) {\n return false;\n }\n try {\n JSON.parse(value);\n } catch (e) {\n return false;\n }\n return true;\n }\n\n return (value) =>\n typeof value !== 'string' || (typeof value === 'string' && !isValidJsonString(value)) ? validatorMessage : null;\n};\n\nexport const hasValidXMLString = (message: string, isWarning?: boolean): Validator => {\n const validatorMessage = getValidatorMessage(message, isWarning);\n\n function isValidXmlString(value: string): boolean {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(value, 'text/xml');\n const errorNode = xmlDoc.querySelector('parsererror');\n\n if (errorNode) {\n return false;\n }\n\n return true;\n }\n\n return (value) =>\n typeof value !== 'string' || (typeof value === 'string' && !isValidXmlString(value)) ? validatorMessage : null;\n};\n","import { hasPermission } from '@services/authorizationService';\nimport { useAtom } from 'jotai';\nimport { isAuthenticatedAtom, userRolesAtom } from '@atoms/authentication';\n\nexport function useAdminRoute(permission: string, minimumAccessLevel: number): boolean {\n const [isAuthenticated] = useAtom(isAuthenticatedAtom);\n const [userRoles] = useAtom(userRolesAtom);\n\n const hasRouteAccess = isAuthenticated && hasPermission(userRoles, permission, minimumAccessLevel);\n\n return hasRouteAccess;\n}\n","import * as React from 'react';\nimport { Action, UNSAFE_invariant, isRouteErrorResponse, createStaticHandler as createStaticHandler$1, UNSAFE_convertRoutesToDataRoutes, IDLE_NAVIGATION, IDLE_FETCHER, IDLE_BLOCKER } from '@remix-run/router';\nimport { UNSAFE_useRoutesImpl, UNSAFE_mapRouteProperties } from 'react-router';\nimport { parsePath, Router, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_FetchersContext, UNSAFE_ViewTransitionContext, createPath } from 'react-router-dom';\n\n/**\n * A `` that may not navigate to any other location. This is useful\n * on the server where there is no stateful UI.\n */\nfunction StaticRouter({\n basename,\n children,\n location: locationProp = \"/\",\n future\n}) {\n if (typeof locationProp === \"string\") {\n locationProp = parsePath(locationProp);\n }\n let action = Action.Pop;\n let location = {\n pathname: locationProp.pathname || \"/\",\n search: locationProp.search || \"\",\n hash: locationProp.hash || \"\",\n state: locationProp.state || null,\n key: locationProp.key || \"default\"\n };\n let staticNavigator = getStatelessNavigator();\n return /*#__PURE__*/React.createElement(Router, {\n basename: basename,\n children: children,\n location: location,\n navigationType: action,\n navigator: staticNavigator,\n future: future,\n static: true\n });\n}\n/**\n * A Data Router that may not navigate to any other location. This is useful\n * on the server where there is no stateful UI.\n */\nfunction StaticRouterProvider({\n context,\n router,\n hydrate = true,\n nonce\n}) {\n !(router && context) ? process.env.NODE_ENV !== \"production\" ? UNSAFE_invariant(false, \"You must provide `router` and `context` to \") : UNSAFE_invariant(false) : void 0;\n let dataRouterContext = {\n router,\n navigator: getStatelessNavigator(),\n static: true,\n staticContext: context,\n basename: context.basename || \"/\"\n };\n let fetchersContext = new Map();\n let hydrateScript = \"\";\n if (hydrate !== false) {\n let data = {\n loaderData: context.loaderData,\n actionData: context.actionData,\n errors: serializeErrors(context.errors)\n };\n // Use JSON.parse here instead of embedding a raw JS object here to speed\n // up parsing on the client. Dual-stringify is needed to ensure all quotes\n // are properly escaped in the resulting string. See:\n // https://v8.dev/blog/cost-of-javascript-2019#json\n let json = htmlEscape(JSON.stringify(JSON.stringify(data)));\n hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`;\n }\n let {\n state\n } = dataRouterContext.router;\n return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UNSAFE_DataRouterContext.Provider, {\n value: dataRouterContext\n }, /*#__PURE__*/React.createElement(UNSAFE_DataRouterStateContext.Provider, {\n value: state\n }, /*#__PURE__*/React.createElement(UNSAFE_FetchersContext.Provider, {\n value: fetchersContext\n }, /*#__PURE__*/React.createElement(UNSAFE_ViewTransitionContext.Provider, {\n value: {\n isTransitioning: false\n }\n }, /*#__PURE__*/React.createElement(Router, {\n basename: dataRouterContext.basename,\n location: state.location,\n navigationType: state.historyAction,\n navigator: dataRouterContext.navigator,\n static: dataRouterContext.static,\n future: {\n v7_relativeSplatPath: router.future.v7_relativeSplatPath\n }\n }, /*#__PURE__*/React.createElement(DataRoutes, {\n routes: router.routes,\n future: router.future,\n state: state\n })))))), hydrateScript ? /*#__PURE__*/React.createElement(\"script\", {\n suppressHydrationWarning: true,\n nonce: nonce,\n dangerouslySetInnerHTML: {\n __html: hydrateScript\n }\n }) : null);\n}\nfunction DataRoutes({\n routes,\n future,\n state\n}) {\n return UNSAFE_useRoutesImpl(routes, undefined, state, future);\n}\nfunction serializeErrors(errors) {\n if (!errors) return null;\n let entries = Object.entries(errors);\n let serialized = {};\n for (let [key, val] of entries) {\n // Hey you! If you change this, please change the corresponding logic in\n // deserializeErrors in react-router-dom/index.tsx :)\n if (isRouteErrorResponse(val)) {\n serialized[key] = {\n ...val,\n __type: \"RouteErrorResponse\"\n };\n } else if (val instanceof Error) {\n // Do not serialize stack traces from SSR for security reasons\n serialized[key] = {\n message: val.message,\n __type: \"Error\",\n // If this is a subclass (i.e., ReferenceError), send up the type so we\n // can re-create the same type during hydration.\n ...(val.name !== \"Error\" ? {\n __subType: val.name\n } : {})\n };\n } else {\n serialized[key] = val;\n }\n }\n return serialized;\n}\nfunction getStatelessNavigator() {\n return {\n createHref,\n encodeLocation,\n push(to) {\n throw new Error(`You cannot use navigator.push() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\\`navigate(${JSON.stringify(to)})\\` somewhere in your app.`);\n },\n replace(to) {\n throw new Error(`You cannot use navigator.replace() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\\`navigate(${JSON.stringify(to)}, { replace: true })\\` somewhere ` + `in your app.`);\n },\n go(delta) {\n throw new Error(`You cannot use navigator.go() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\\`navigate(${delta})\\` somewhere in your app.`);\n },\n back() {\n throw new Error(`You cannot use navigator.back() on the server because it is a stateless ` + `environment.`);\n },\n forward() {\n throw new Error(`You cannot use navigator.forward() on the server because it is a stateless ` + `environment.`);\n }\n };\n}\nfunction createStaticHandler(routes, opts) {\n return createStaticHandler$1(routes, {\n ...opts,\n mapRouteProperties: UNSAFE_mapRouteProperties\n });\n}\nfunction createStaticRouter(routes, context, opts = {}) {\n let manifest = {};\n let dataRoutes = UNSAFE_convertRoutesToDataRoutes(routes, UNSAFE_mapRouteProperties, undefined, manifest);\n\n // Because our context matches may be from a framework-agnostic set of\n // routes passed to createStaticHandler(), we update them here with our\n // newly created/enhanced data routes\n let matches = context.matches.map(match => {\n let route = manifest[match.route.id] || match.route;\n return {\n ...match,\n route\n };\n });\n let msg = method => `You cannot use router.${method}() on the server because it is a stateless environment`;\n return {\n get basename() {\n return context.basename;\n },\n get future() {\n return {\n v7_fetcherPersist: false,\n v7_normalizeFormMethod: false,\n v7_partialHydration: opts.future?.v7_partialHydration === true,\n v7_prependBasename: false,\n v7_relativeSplatPath: opts.future?.v7_relativeSplatPath === true,\n unstable_skipActionErrorRevalidation: false\n };\n },\n get state() {\n return {\n historyAction: Action.Pop,\n location: context.location,\n matches,\n loaderData: context.loaderData,\n actionData: context.actionData,\n errors: context.errors,\n initialized: true,\n navigation: IDLE_NAVIGATION,\n restoreScrollPosition: null,\n preventScrollReset: false,\n revalidation: \"idle\",\n fetchers: new Map(),\n blockers: new Map()\n };\n },\n get routes() {\n return dataRoutes;\n },\n get window() {\n return undefined;\n },\n initialize() {\n throw msg(\"initialize\");\n },\n subscribe() {\n throw msg(\"subscribe\");\n },\n enableScrollRestoration() {\n throw msg(\"enableScrollRestoration\");\n },\n navigate() {\n throw msg(\"navigate\");\n },\n fetch() {\n throw msg(\"fetch\");\n },\n revalidate() {\n throw msg(\"revalidate\");\n },\n createHref,\n encodeLocation,\n getFetcher() {\n return IDLE_FETCHER;\n },\n deleteFetcher() {\n throw msg(\"deleteFetcher\");\n },\n dispose() {\n throw msg(\"dispose\");\n },\n getBlocker() {\n return IDLE_BLOCKER;\n },\n deleteBlocker() {\n throw msg(\"deleteBlocker\");\n },\n _internalFetchControllers: new Map(),\n _internalActiveDeferreds: new Map(),\n _internalSetRoutes() {\n throw msg(\"_internalSetRoutes\");\n }\n };\n}\nfunction createHref(to) {\n return typeof to === \"string\" ? to : createPath(to);\n}\nfunction encodeLocation(to) {\n let href = typeof to === \"string\" ? to : createPath(to);\n // Treating this as a full URL will strip any trailing spaces so we need to\n // pre-encode them since they might be part of a matching splat param from\n // an ancestor route\n href = href.replace(/ $/, \"%20\");\n let encoded = ABSOLUTE_URL_REGEX.test(href) ? new URL(href) : new URL(href, \"http://localhost\");\n return {\n pathname: encoded.pathname,\n search: encoded.search,\n hash: encoded.hash\n };\n}\nconst ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i;\n\n// This utility is based on https://github.com/zertosh/htmlescape\n// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE\nconst ESCAPE_LOOKUP = {\n \"&\": \"\\\\u0026\",\n \">\": \"\\\\u003e\",\n \"<\": \"\\\\u003c\",\n \"\\u2028\": \"\\\\u2028\",\n \"\\u2029\": \"\\\\u2029\"\n};\nconst ESCAPE_REGEX = /[&><\\u2028\\u2029]/g;\nfunction htmlEscape(str) {\n return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]);\n}\n\nexport { StaticRouter, StaticRouterProvider, createStaticHandler, createStaticRouter };\n","import * as React from 'react';\nconst ThemeContext = /*#__PURE__*/React.createContext(null);\nif (process.env.NODE_ENV !== 'production') {\n ThemeContext.displayName = 'ThemeContext';\n}\nexport default ThemeContext;","import * as React from 'react';\nimport ThemeContext from \"./ThemeContext.js\";\nexport default function useTheme() {\n const theme = React.useContext(ThemeContext);\n if (process.env.NODE_ENV !== 'production') {\n // TODO: uncomment once we enable eslint-plugin-react-compiler eslint-disable-next-line react-compiler/react-compiler\n // eslint-disable-next-line react-hooks/rules-of-hooks -- It's not required to run React.useDebugValue in production\n React.useDebugValue(theme);\n }\n return theme;\n}","const hasSymbol = typeof Symbol === 'function' && Symbol.for;\nexport default hasSymbol ? Symbol.for('mui.nested') : '__THEME_NESTED__';","import * as React from 'react';\nimport PropTypes from 'prop-types';\nimport { exactProp } from '@mui/utils';\nimport ThemeContext from \"../useTheme/ThemeContext.js\";\nimport useTheme from \"../useTheme/index.js\";\nimport nested from \"./nested.js\";\n\n// To support composition of theme.\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nfunction mergeOuterLocalTheme(outerTheme, localTheme) {\n if (typeof localTheme === 'function') {\n const mergedTheme = localTheme(outerTheme);\n if (process.env.NODE_ENV !== 'production') {\n if (!mergedTheme) {\n console.error(['MUI: You should return an object from your theme function, i.e.', ' ({})} />'].join('\\n'));\n }\n }\n return mergedTheme;\n }\n return {\n ...outerTheme,\n ...localTheme\n };\n}\n\n/**\n * This component takes a `theme` prop.\n * It makes the `theme` available down the React tree thanks to React context.\n * This component should preferably be used at **the root of your component tree**.\n */\nfunction ThemeProvider(props) {\n const {\n children,\n theme: localTheme\n } = props;\n const outerTheme = useTheme();\n if (process.env.NODE_ENV !== 'production') {\n if (outerTheme === null && typeof localTheme === 'function') {\n console.error(['MUI: You are providing a theme function prop to the ThemeProvider component:', ' outerTheme} />', '', 'However, no outer theme is present.', 'Make sure a theme is already injected higher in the React tree ' + 'or provide a theme object.'].join('\\n'));\n }\n }\n const theme = React.useMemo(() => {\n const output = outerTheme === null ? {\n ...localTheme\n } : mergeOuterLocalTheme(outerTheme, localTheme);\n if (output != null) {\n output[nested] = outerTheme !== null;\n }\n return output;\n }, [localTheme, outerTheme]);\n return /*#__PURE__*/_jsx(ThemeContext.Provider, {\n value: theme,\n children: children\n });\n}\nprocess.env.NODE_ENV !== \"production\" ? ThemeProvider.propTypes = {\n /**\n * Your component tree.\n */\n children: PropTypes.node,\n /**\n * A theme object. You can provide a function to extend the outer theme.\n */\n theme: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired\n} : void 0;\nif (process.env.NODE_ENV !== 'production') {\n process.env.NODE_ENV !== \"production\" ? ThemeProvider.propTypes = exactProp(ThemeProvider.propTypes) : void 0;\n}\nexport default ThemeProvider;","'use client';\n\nimport * as React from 'react';\nimport PropTypes from 'prop-types';\nimport { ThemeProvider as MuiThemeProvider, useTheme as usePrivateTheme } from '@mui/private-theming';\nimport exactProp from '@mui/utils/exactProp';\nimport { ThemeContext as StyledEngineThemeContext } from '@mui/styled-engine';\nimport useThemeWithoutDefault from \"../useThemeWithoutDefault/index.js\";\nimport RtlProvider from \"../RtlProvider/index.js\";\nimport DefaultPropsProvider from \"../DefaultPropsProvider/index.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nconst EMPTY_THEME = {};\nfunction useThemeScoping(themeId, upperTheme, localTheme, isPrivate = false) {\n return React.useMemo(() => {\n const resolvedTheme = themeId ? upperTheme[themeId] || upperTheme : upperTheme;\n if (typeof localTheme === 'function') {\n const mergedTheme = localTheme(resolvedTheme);\n const result = themeId ? {\n ...upperTheme,\n [themeId]: mergedTheme\n } : mergedTheme;\n // must return a function for the private theme to NOT merge with the upper theme.\n // see the test case \"use provided theme from a callback\" in ThemeProvider.test.js\n if (isPrivate) {\n return () => result;\n }\n return result;\n }\n return themeId ? {\n ...upperTheme,\n [themeId]: localTheme\n } : {\n ...upperTheme,\n ...localTheme\n };\n }, [themeId, upperTheme, localTheme, isPrivate]);\n}\n\n/**\n * This component makes the `theme` available down the React tree.\n * It should preferably be used at **the root of your component tree**.\n *\n * // existing use case\n * // theme scoping\n */\nfunction ThemeProvider(props) {\n const {\n children,\n theme: localTheme,\n themeId\n } = props;\n const upperTheme = useThemeWithoutDefault(EMPTY_THEME);\n const upperPrivateTheme = usePrivateTheme() || EMPTY_THEME;\n if (process.env.NODE_ENV !== 'production') {\n if (upperTheme === null && typeof localTheme === 'function' || themeId && upperTheme && !upperTheme[themeId] && typeof localTheme === 'function') {\n console.error(['MUI: You are providing a theme function prop to the ThemeProvider component:', ' outerTheme} />', '', 'However, no outer theme is present.', 'Make sure a theme is already injected higher in the React tree ' + 'or provide a theme object.'].join('\\n'));\n }\n }\n const engineTheme = useThemeScoping(themeId, upperTheme, localTheme);\n const privateTheme = useThemeScoping(themeId, upperPrivateTheme, localTheme, true);\n const rtlValue = engineTheme.direction === 'rtl';\n return /*#__PURE__*/_jsx(MuiThemeProvider, {\n theme: privateTheme,\n children: /*#__PURE__*/_jsx(StyledEngineThemeContext.Provider, {\n value: engineTheme,\n children: /*#__PURE__*/_jsx(RtlProvider, {\n value: rtlValue,\n children: /*#__PURE__*/_jsx(DefaultPropsProvider, {\n value: engineTheme?.components,\n children: children\n })\n })\n })\n });\n}\nprocess.env.NODE_ENV !== \"production\" ? ThemeProvider.propTypes /* remove-proptypes */ = {\n // ┌────────────────────────────── Warning ──────────────────────────────┐\n // │ These PropTypes are generated from the TypeScript type definitions. │\n // │ To update them, edit the d.ts file and run `pnpm proptypes`. │\n // └─────────────────────────────────────────────────────────────────────┘\n /**\n * Your component tree.\n */\n children: PropTypes.node,\n /**\n * A theme object. You can provide a function to extend the outer theme.\n */\n theme: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,\n /**\n * The design system's unique id for getting the corresponded theme when there are multiple design systems.\n */\n themeId: PropTypes.string\n} : void 0;\nif (process.env.NODE_ENV !== 'production') {\n process.env.NODE_ENV !== \"production\" ? ThemeProvider.propTypes = exactProp(ThemeProvider.propTypes) : void 0;\n}\nexport default ThemeProvider;","'use client';\n\nimport * as React from 'react';\nimport { ThemeProvider as SystemThemeProvider } from '@mui/system';\nimport THEME_ID from \"./identifier.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default function ThemeProviderNoVars({\n theme: themeInput,\n ...props\n}) {\n const scopedTheme = THEME_ID in themeInput ? themeInput[THEME_ID] : undefined;\n return /*#__PURE__*/_jsx(SystemThemeProvider, {\n ...props,\n themeId: scopedTheme ? THEME_ID : undefined,\n theme: scopedTheme || themeInput\n });\n}","/**\n * Split this component for RSC import\n */\nimport * as React from 'react';\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport const DEFAULT_MODE_STORAGE_KEY = 'mode';\nexport const DEFAULT_COLOR_SCHEME_STORAGE_KEY = 'color-scheme';\nexport const DEFAULT_ATTRIBUTE = 'data-color-scheme';\nexport default function InitColorSchemeScript(options) {\n const {\n defaultLightColorScheme = 'light',\n defaultDarkColorScheme = 'dark',\n modeStorageKey = DEFAULT_MODE_STORAGE_KEY,\n colorSchemeStorageKey = DEFAULT_COLOR_SCHEME_STORAGE_KEY,\n attribute: initialAttribute = DEFAULT_ATTRIBUTE,\n colorSchemeNode = 'document.documentElement',\n nonce\n } = options || {};\n let setter = '';\n let attribute = initialAttribute;\n if (initialAttribute === 'class') {\n attribute = '.%s';\n }\n if (initialAttribute === 'data') {\n attribute = '[data-%s]';\n }\n if (attribute.startsWith('.')) {\n const selector = attribute.substring(1);\n setter += `${colorSchemeNode}.classList.remove('${selector}'.replace('%s', light), '${selector}'.replace('%s', dark));\n ${colorSchemeNode}.classList.add('${selector}'.replace('%s', colorScheme));`;\n }\n const matches = attribute.match(/\\[([^\\]]+)\\]/); // case [data-color-scheme=%s] or [data-color-scheme]\n if (matches) {\n const [attr, value] = matches[1].split('=');\n if (!value) {\n setter += `${colorSchemeNode}.removeAttribute('${attr}'.replace('%s', light));\n ${colorSchemeNode}.removeAttribute('${attr}'.replace('%s', dark));`;\n }\n setter += `\n ${colorSchemeNode}.setAttribute('${attr}'.replace('%s', colorScheme), ${value ? `${value}.replace('%s', colorScheme)` : '\"\"'});`;\n } else {\n setter += `${colorSchemeNode}.setAttribute('${attribute}', colorScheme);`;\n }\n return /*#__PURE__*/_jsx(\"script\", {\n suppressHydrationWarning: true,\n nonce: typeof window === 'undefined' ? nonce : ''\n // eslint-disable-next-line react/no-danger\n ,\n dangerouslySetInnerHTML: {\n __html: `(function() {\ntry {\n let colorScheme = '';\n const mode = localStorage.getItem('${modeStorageKey}') || 'system';\n const dark = localStorage.getItem('${colorSchemeStorageKey}-dark') || '${defaultDarkColorScheme}';\n const light = localStorage.getItem('${colorSchemeStorageKey}-light') || '${defaultLightColorScheme}';\n if (mode === 'system') {\n // handle system mode\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n if (mql.matches) {\n colorScheme = dark\n } else {\n colorScheme = light\n }\n }\n if (mode === 'light') {\n colorScheme = light;\n }\n if (mode === 'dark') {\n colorScheme = dark;\n }\n if (colorScheme) {\n ${setter}\n }\n} catch(e){}})();`\n }\n }, \"mui-color-scheme-init\");\n}","'use client';\n\nimport * as React from 'react';\nimport { DEFAULT_MODE_STORAGE_KEY, DEFAULT_COLOR_SCHEME_STORAGE_KEY } from \"../InitColorSchemeScript/InitColorSchemeScript.js\";\nexport function getSystemMode(mode) {\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function' && mode === 'system') {\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n if (mql.matches) {\n return 'dark';\n }\n return 'light';\n }\n return undefined;\n}\nfunction processState(state, callback) {\n if (state.mode === 'light' || state.mode === 'system' && state.systemMode === 'light') {\n return callback('light');\n }\n if (state.mode === 'dark' || state.mode === 'system' && state.systemMode === 'dark') {\n return callback('dark');\n }\n return undefined;\n}\nexport function getColorScheme(state) {\n return processState(state, mode => {\n if (mode === 'light') {\n return state.lightColorScheme;\n }\n if (mode === 'dark') {\n return state.darkColorScheme;\n }\n return undefined;\n });\n}\nfunction initializeValue(key, defaultValue) {\n if (typeof window === 'undefined') {\n return undefined;\n }\n let value;\n try {\n value = localStorage.getItem(key) || undefined;\n if (!value) {\n // the first time that user enters the site.\n localStorage.setItem(key, defaultValue);\n }\n } catch (e) {\n // Unsupported\n }\n return value || defaultValue;\n}\nexport default function useCurrentColorScheme(options) {\n const {\n defaultMode = 'light',\n defaultLightColorScheme,\n defaultDarkColorScheme,\n supportedColorSchemes = [],\n modeStorageKey = DEFAULT_MODE_STORAGE_KEY,\n colorSchemeStorageKey = DEFAULT_COLOR_SCHEME_STORAGE_KEY,\n storageWindow = typeof window === 'undefined' ? undefined : window\n } = options;\n const joinedColorSchemes = supportedColorSchemes.join(',');\n const isMultiSchemes = supportedColorSchemes.length > 1;\n const [state, setState] = React.useState(() => {\n const initialMode = initializeValue(modeStorageKey, defaultMode);\n const lightColorScheme = initializeValue(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);\n const darkColorScheme = initializeValue(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);\n return {\n mode: initialMode,\n systemMode: getSystemMode(initialMode),\n lightColorScheme,\n darkColorScheme\n };\n });\n // This could be improved with `React.useSyncExternalStore` in the future.\n const [, setHasMounted] = React.useState(false);\n const hasMounted = React.useRef(false);\n React.useEffect(() => {\n if (isMultiSchemes) {\n setHasMounted(true); // to rerender the component after hydration\n }\n hasMounted.current = true;\n }, [isMultiSchemes]);\n const colorScheme = getColorScheme(state);\n const setMode = React.useCallback(mode => {\n setState(currentState => {\n if (mode === currentState.mode) {\n // do nothing if mode does not change\n return currentState;\n }\n const newMode = mode ?? defaultMode;\n try {\n localStorage.setItem(modeStorageKey, newMode);\n } catch (e) {\n // Unsupported\n }\n return {\n ...currentState,\n mode: newMode,\n systemMode: getSystemMode(newMode)\n };\n });\n }, [modeStorageKey, defaultMode]);\n const setColorScheme = React.useCallback(value => {\n if (!value) {\n setState(currentState => {\n try {\n localStorage.setItem(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);\n localStorage.setItem(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);\n } catch (e) {\n // Unsupported\n }\n return {\n ...currentState,\n lightColorScheme: defaultLightColorScheme,\n darkColorScheme: defaultDarkColorScheme\n };\n });\n } else if (typeof value === 'string') {\n if (value && !joinedColorSchemes.includes(value)) {\n console.error(`\\`${value}\\` does not exist in \\`theme.colorSchemes\\`.`);\n } else {\n setState(currentState => {\n const newState = {\n ...currentState\n };\n processState(currentState, mode => {\n try {\n localStorage.setItem(`${colorSchemeStorageKey}-${mode}`, value);\n } catch (e) {\n // Unsupported\n }\n if (mode === 'light') {\n newState.lightColorScheme = value;\n }\n if (mode === 'dark') {\n newState.darkColorScheme = value;\n }\n });\n return newState;\n });\n }\n } else {\n setState(currentState => {\n const newState = {\n ...currentState\n };\n const newLightColorScheme = value.light === null ? defaultLightColorScheme : value.light;\n const newDarkColorScheme = value.dark === null ? defaultDarkColorScheme : value.dark;\n if (newLightColorScheme) {\n if (!joinedColorSchemes.includes(newLightColorScheme)) {\n console.error(`\\`${newLightColorScheme}\\` does not exist in \\`theme.colorSchemes\\`.`);\n } else {\n newState.lightColorScheme = newLightColorScheme;\n try {\n localStorage.setItem(`${colorSchemeStorageKey}-light`, newLightColorScheme);\n } catch (error) {\n // Unsupported\n }\n }\n }\n if (newDarkColorScheme) {\n if (!joinedColorSchemes.includes(newDarkColorScheme)) {\n console.error(`\\`${newDarkColorScheme}\\` does not exist in \\`theme.colorSchemes\\`.`);\n } else {\n newState.darkColorScheme = newDarkColorScheme;\n try {\n localStorage.setItem(`${colorSchemeStorageKey}-dark`, newDarkColorScheme);\n } catch (error) {\n // Unsupported\n }\n }\n }\n return newState;\n });\n }\n }, [joinedColorSchemes, colorSchemeStorageKey, defaultLightColorScheme, defaultDarkColorScheme]);\n const handleMediaQuery = React.useCallback(event => {\n if (state.mode === 'system') {\n setState(currentState => {\n const systemMode = event?.matches ? 'dark' : 'light';\n\n // Early exit, nothing changed.\n if (currentState.systemMode === systemMode) {\n return currentState;\n }\n return {\n ...currentState,\n systemMode\n };\n });\n }\n }, [state.mode]);\n\n // Ref hack to avoid adding handleMediaQuery as a dep\n const mediaListener = React.useRef(handleMediaQuery);\n mediaListener.current = handleMediaQuery;\n React.useEffect(() => {\n if (typeof window.matchMedia !== 'function' || !isMultiSchemes) {\n return undefined;\n }\n const handler = (...args) => mediaListener.current(...args);\n\n // Always listen to System preference\n const media = window.matchMedia('(prefers-color-scheme: dark)');\n\n // Intentionally use deprecated listener methods to support iOS & old browsers\n media.addListener(handler);\n handler(media);\n return () => {\n media.removeListener(handler);\n };\n }, [isMultiSchemes]);\n\n // Handle when localStorage has changed\n React.useEffect(() => {\n if (storageWindow && isMultiSchemes) {\n const handleStorage = event => {\n const value = event.newValue;\n if (typeof event.key === 'string' && event.key.startsWith(colorSchemeStorageKey) && (!value || joinedColorSchemes.match(value))) {\n // If the key is deleted, value will be null then reset color scheme to the default one.\n if (event.key.endsWith('light')) {\n setColorScheme({\n light: value\n });\n }\n if (event.key.endsWith('dark')) {\n setColorScheme({\n dark: value\n });\n }\n }\n if (event.key === modeStorageKey && (!value || ['light', 'dark', 'system'].includes(value))) {\n setMode(value || defaultMode);\n }\n };\n // For syncing color-scheme changes between iframes\n storageWindow.addEventListener('storage', handleStorage);\n return () => {\n storageWindow.removeEventListener('storage', handleStorage);\n };\n }\n return undefined;\n }, [setColorScheme, setMode, modeStorageKey, colorSchemeStorageKey, joinedColorSchemes, defaultMode, storageWindow, isMultiSchemes]);\n return {\n ...state,\n mode: hasMounted.current || !isMultiSchemes ? state.mode : undefined,\n systemMode: hasMounted.current || !isMultiSchemes ? state.systemMode : undefined,\n colorScheme: hasMounted.current || !isMultiSchemes ? colorScheme : undefined,\n setMode,\n setColorScheme\n };\n}","import * as React from 'react';\nimport SystemInitColorSchemeScript from '@mui/system/InitColorSchemeScript';\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport const defaultConfig = {\n attribute: 'data-mui-color-scheme',\n colorSchemeStorageKey: 'mui-color-scheme',\n defaultLightColorScheme: 'light',\n defaultDarkColorScheme: 'dark',\n modeStorageKey: 'mui-mode'\n};\nexport default (function InitColorSchemeScript(props) {\n return /*#__PURE__*/_jsx(SystemInitColorSchemeScript, {\n ...defaultConfig,\n ...props\n });\n});","'use client';\n\nimport * as React from 'react';\nimport styleFunctionSx from '@mui/system/styleFunctionSx';\nimport { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system';\nimport createTheme from \"./createTheme.js\";\nimport createTypography from \"./createTypography.js\";\nimport THEME_ID from \"./identifier.js\";\nimport { defaultConfig } from \"../InitColorSchemeScript/InitColorSchemeScript.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nconst {\n CssVarsProvider: InternalCssVarsProvider,\n useColorScheme,\n getInitColorSchemeScript: deprecatedGetInitColorSchemeScript\n} = createCssVarsProvider({\n themeId: THEME_ID,\n // @ts-ignore ignore module augmentation tests\n theme: () => createTheme({\n cssVariables: true\n }),\n colorSchemeStorageKey: defaultConfig.colorSchemeStorageKey,\n modeStorageKey: defaultConfig.modeStorageKey,\n defaultColorScheme: {\n light: defaultConfig.defaultLightColorScheme,\n dark: defaultConfig.defaultDarkColorScheme\n },\n resolveTheme: theme => {\n const newTheme = {\n ...theme,\n typography: createTypography(theme.palette, theme.typography)\n };\n newTheme.unstable_sx = function sx(props) {\n return styleFunctionSx({\n sx: props,\n theme: this\n });\n };\n return newTheme;\n }\n});\nlet warnedOnce = false;\n\n// TODO: remove in v7\n// eslint-disable-next-line @typescript-eslint/naming-convention\nfunction Experimental_CssVarsProvider(props) {\n if (process.env.NODE_ENV !== 'production') {\n if (!warnedOnce) {\n console.warn(['MUI: The Experimental_CssVarsProvider component has been ported into ThemeProvider.', '', \"You should use `import { ThemeProvider } from '@mui/material/styles'` instead.\", 'For more details, check out https://mui.com/material-ui/customization/css-theme-variables/usage/'].join('\\n'));\n warnedOnce = true;\n }\n }\n return /*#__PURE__*/_jsx(InternalCssVarsProvider, {\n ...props\n });\n}\nlet warnedInitScriptOnce = false;\n\n// TODO: remove in v7\nconst getInitColorSchemeScript = params => {\n if (!warnedInitScriptOnce) {\n console.warn(['MUI: The getInitColorSchemeScript function has been deprecated.', '', \"You should use `import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'`\", 'and replace the function call with `` instead.'].join('\\n'));\n warnedInitScriptOnce = true;\n }\n return deprecatedGetInitColorSchemeScript(params);\n};\n\n/**\n * TODO: remove this export in v7\n * @deprecated\n * The `CssVarsProvider` component has been deprecated and ported into `ThemeProvider`.\n *\n * You should use `ThemeProvider` and `createTheme` instead:\n *\n * ```diff\n * - import { CssVarsProvider, extendTheme } from '@mui/material/styles';\n * + import { ThemeProvider, createTheme } from '@mui/material/styles';\n *\n * - const theme = extendTheme();\n * + const theme = createTheme({\n * + cssVariables: true,\n * + colorSchemes: { light: true, dark: true },\n * + });\n *\n * - \n * + \n * ```\n *\n * To see the full documentation, check out https://mui.com/material-ui/customization/css-theme-variables/usage/.\n */\nexport const CssVarsProvider = InternalCssVarsProvider;\nexport { useColorScheme, getInitColorSchemeScript, Experimental_CssVarsProvider };","import * as React from 'react';\nimport PropTypes from 'prop-types';\nimport { GlobalStyles } from '@mui/styled-engine';\nimport { useTheme as muiUseTheme } from '@mui/private-theming';\nimport ThemeProvider from \"../ThemeProvider/index.js\";\nimport InitColorSchemeScript, { DEFAULT_COLOR_SCHEME_STORAGE_KEY, DEFAULT_MODE_STORAGE_KEY } from \"../InitColorSchemeScript/InitColorSchemeScript.js\";\nimport useCurrentColorScheme from \"./useCurrentColorScheme.js\";\nimport { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nexport const DISABLE_CSS_TRANSITION = '*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}';\nexport default function createCssVarsProvider(options) {\n const {\n themeId,\n /**\n * This `theme` object needs to follow a certain structure to\n * be used correctly by the finel `CssVarsProvider`. It should have a\n * `colorSchemes` key with the light and dark (and any other) palette.\n * It should also ideally have a vars object created using `prepareCssVars`.\n */\n theme: defaultTheme = {},\n modeStorageKey: defaultModeStorageKey = DEFAULT_MODE_STORAGE_KEY,\n colorSchemeStorageKey: defaultColorSchemeStorageKey = DEFAULT_COLOR_SCHEME_STORAGE_KEY,\n disableTransitionOnChange: designSystemTransitionOnChange = false,\n defaultColorScheme,\n resolveTheme\n } = options;\n const defaultContext = {\n allColorSchemes: [],\n colorScheme: undefined,\n darkColorScheme: undefined,\n lightColorScheme: undefined,\n mode: undefined,\n setColorScheme: () => {},\n setMode: () => {},\n systemMode: undefined\n };\n const ColorSchemeContext = /*#__PURE__*/React.createContext(undefined);\n if (process.env.NODE_ENV !== 'production') {\n ColorSchemeContext.displayName = 'ColorSchemeContext';\n }\n const useColorScheme = () => React.useContext(ColorSchemeContext) || defaultContext;\n function CssVarsProvider(props) {\n const {\n children,\n theme: themeProp,\n modeStorageKey = defaultModeStorageKey,\n colorSchemeStorageKey = defaultColorSchemeStorageKey,\n disableTransitionOnChange = designSystemTransitionOnChange,\n storageWindow = typeof window === 'undefined' ? undefined : window,\n documentNode = typeof document === 'undefined' ? undefined : document,\n colorSchemeNode = typeof document === 'undefined' ? undefined : document.documentElement,\n disableNestedContext = false,\n disableStyleSheetGeneration = false\n } = props;\n const hasMounted = React.useRef(false);\n const upperTheme = muiUseTheme();\n const ctx = React.useContext(ColorSchemeContext);\n const nested = !!ctx && !disableNestedContext;\n const initialTheme = React.useMemo(() => {\n if (themeProp) {\n return themeProp;\n }\n return typeof defaultTheme === 'function' ? defaultTheme() : defaultTheme;\n }, [themeProp]);\n const scopedTheme = initialTheme[themeId];\n const {\n colorSchemes = {},\n components = {},\n cssVarPrefix,\n ...restThemeProp\n } = scopedTheme || initialTheme;\n const joinedColorSchemes = Object.keys(colorSchemes).filter(k => !!colorSchemes[k]).join(',');\n const allColorSchemes = React.useMemo(() => joinedColorSchemes.split(','), [joinedColorSchemes]);\n const defaultLightColorScheme = typeof defaultColorScheme === 'string' ? defaultColorScheme : defaultColorScheme.light;\n const defaultDarkColorScheme = typeof defaultColorScheme === 'string' ? defaultColorScheme : defaultColorScheme.dark;\n const defaultMode = colorSchemes[defaultLightColorScheme] && colorSchemes[defaultDarkColorScheme] ? 'system' : colorSchemes[restThemeProp.defaultColorScheme]?.palette?.mode || restThemeProp.palette?.mode;\n\n // 1. Get the data about the `mode`, `colorScheme`, and setter functions.\n const {\n mode: stateMode,\n setMode,\n systemMode,\n lightColorScheme,\n darkColorScheme,\n colorScheme: stateColorScheme,\n setColorScheme\n } = useCurrentColorScheme({\n supportedColorSchemes: allColorSchemes,\n defaultLightColorScheme,\n defaultDarkColorScheme,\n modeStorageKey,\n colorSchemeStorageKey,\n defaultMode,\n storageWindow\n });\n let mode = stateMode;\n let colorScheme = stateColorScheme;\n if (nested) {\n mode = ctx.mode;\n colorScheme = ctx.colorScheme;\n }\n\n // `colorScheme` is undefined on the server and hydration phase\n const calculatedColorScheme = colorScheme || restThemeProp.defaultColorScheme;\n\n // 2. get the `vars` object that refers to the CSS custom properties\n const themeVars = restThemeProp.generateThemeVars?.() || restThemeProp.vars;\n\n // 3. Start composing the theme object\n const theme = {\n ...restThemeProp,\n components,\n colorSchemes,\n cssVarPrefix,\n vars: themeVars\n };\n if (typeof theme.generateSpacing === 'function') {\n theme.spacing = theme.generateSpacing();\n }\n\n // 4. Resolve the color scheme and merge it to the theme\n if (calculatedColorScheme) {\n const scheme = colorSchemes[calculatedColorScheme];\n if (scheme && typeof scheme === 'object') {\n // 4.1 Merge the selected color scheme to the theme\n Object.keys(scheme).forEach(schemeKey => {\n if (scheme[schemeKey] && typeof scheme[schemeKey] === 'object') {\n // shallow merge the 1st level structure of the theme.\n theme[schemeKey] = {\n ...theme[schemeKey],\n ...scheme[schemeKey]\n };\n } else {\n theme[schemeKey] = scheme[schemeKey];\n }\n });\n }\n }\n\n // 5. Declaring effects\n // 5.1 Updates the selector value to use the current color scheme which tells CSS to use the proper stylesheet.\n const colorSchemeSelector = restThemeProp.colorSchemeSelector;\n React.useEffect(() => {\n if (colorScheme && colorSchemeNode && colorSchemeSelector && colorSchemeSelector !== 'media') {\n const selector = colorSchemeSelector;\n let rule = colorSchemeSelector;\n if (selector === 'class') {\n rule = `.%s`;\n }\n if (selector === 'data') {\n rule = `[data-%s]`;\n }\n if (selector?.startsWith('data-') && !selector.includes('%s')) {\n // 'data-mui-color-scheme' -> '[data-mui-color-scheme=\"%s\"]'\n rule = `[${selector}=\"%s\"]`;\n }\n if (rule.startsWith('.')) {\n colorSchemeNode.classList.remove(...allColorSchemes.map(scheme => rule.substring(1).replace('%s', scheme)));\n colorSchemeNode.classList.add(rule.substring(1).replace('%s', colorScheme));\n } else {\n const matches = rule.replace('%s', colorScheme).match(/\\[([^\\]]+)\\]/);\n if (matches) {\n const [attr, value] = matches[1].split('=');\n if (!value) {\n // for attributes like `data-theme-dark`, `data-theme-light`\n // remove all the existing data attributes before setting the new one\n allColorSchemes.forEach(scheme => {\n colorSchemeNode.removeAttribute(attr.replace(colorScheme, scheme));\n });\n }\n colorSchemeNode.setAttribute(attr, value ? value.replace(/\"|'/g, '') : '');\n } else {\n colorSchemeNode.setAttribute(rule, colorScheme);\n }\n }\n }\n }, [colorScheme, colorSchemeSelector, colorSchemeNode, allColorSchemes]);\n\n // 5.2 Remove the CSS transition when color scheme changes to create instant experience.\n // credit: https://github.com/pacocoursey/next-themes/blob/b5c2bad50de2d61ad7b52a9c5cdc801a78507d7a/index.tsx#L313\n React.useEffect(() => {\n let timer;\n if (disableTransitionOnChange && hasMounted.current && documentNode) {\n const css = documentNode.createElement('style');\n css.appendChild(documentNode.createTextNode(DISABLE_CSS_TRANSITION));\n documentNode.head.appendChild(css);\n\n // Force browser repaint\n (() => window.getComputedStyle(documentNode.body))();\n timer = setTimeout(() => {\n documentNode.head.removeChild(css);\n }, 1);\n }\n return () => {\n clearTimeout(timer);\n };\n }, [colorScheme, disableTransitionOnChange, documentNode]);\n React.useEffect(() => {\n hasMounted.current = true;\n return () => {\n hasMounted.current = false;\n };\n }, []);\n const contextValue = React.useMemo(() => ({\n allColorSchemes,\n colorScheme,\n darkColorScheme,\n lightColorScheme,\n mode,\n setColorScheme,\n setMode,\n systemMode\n }), [allColorSchemes, colorScheme, darkColorScheme, lightColorScheme, mode, setColorScheme, setMode, systemMode]);\n let shouldGenerateStyleSheet = true;\n if (disableStyleSheetGeneration || restThemeProp.cssVariables === false || nested && upperTheme?.cssVarPrefix === cssVarPrefix) {\n shouldGenerateStyleSheet = false;\n }\n const element = /*#__PURE__*/_jsxs(React.Fragment, {\n children: [shouldGenerateStyleSheet && /*#__PURE__*/_jsx(React.Fragment, {\n children: (theme.generateStyleSheets?.() || []).map((styles, index) => /*#__PURE__*/_jsx(GlobalStyles, {\n styles: styles\n }, index))\n }), /*#__PURE__*/_jsx(ThemeProvider, {\n themeId: scopedTheme ? themeId : undefined,\n theme: resolveTheme ? resolveTheme(theme) : theme,\n children: children\n })]\n });\n if (nested) {\n return element;\n }\n return /*#__PURE__*/_jsx(ColorSchemeContext.Provider, {\n value: contextValue,\n children: element\n });\n }\n process.env.NODE_ENV !== \"production\" ? CssVarsProvider.propTypes = {\n /**\n * The component tree.\n */\n children: PropTypes.node,\n /**\n * The node used to attach the color-scheme attribute\n */\n colorSchemeNode: PropTypes.any,\n /**\n * localStorage key used to store `colorScheme`\n */\n colorSchemeStorageKey: PropTypes.string,\n /**\n * If `true`, the provider creates its own context and generate stylesheet as if it is a root `CssVarsProvider`.\n */\n disableNestedContext: PropTypes.bool,\n /**\n * If `true`, the style sheet won't be generated.\n *\n * This is useful for controlling nested CssVarsProvider behavior.\n */\n disableStyleSheetGeneration: PropTypes.bool,\n /**\n * Disable CSS transitions when switching between modes or color schemes.\n */\n disableTransitionOnChange: PropTypes.bool,\n /**\n * The document to attach the attribute to.\n */\n documentNode: PropTypes.any,\n /**\n * The key in the local storage used to store current color scheme.\n */\n modeStorageKey: PropTypes.string,\n /**\n * The window that attaches the 'storage' event listener.\n * @default window\n */\n storageWindow: PropTypes.any,\n /**\n * The calculated theme object that will be passed through context.\n */\n theme: PropTypes.object\n } : void 0;\n const defaultLightColorScheme = typeof defaultColorScheme === 'string' ? defaultColorScheme : defaultColorScheme.light;\n const defaultDarkColorScheme = typeof defaultColorScheme === 'string' ? defaultColorScheme : defaultColorScheme.dark;\n const getInitColorSchemeScript = params => InitColorSchemeScript({\n colorSchemeStorageKey: defaultColorSchemeStorageKey,\n defaultLightColorScheme,\n defaultDarkColorScheme,\n modeStorageKey: defaultModeStorageKey,\n ...params\n });\n return {\n CssVarsProvider,\n useColorScheme,\n getInitColorSchemeScript\n };\n}","'use client';\n\nimport * as React from 'react';\nimport ThemeProviderNoVars from \"./ThemeProviderNoVars.js\";\nimport { CssVarsProvider } from \"./ThemeProviderWithVars.js\";\nimport THEME_ID from \"./identifier.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default function ThemeProvider({\n theme,\n ...props\n}) {\n if (typeof theme === 'function') {\n return /*#__PURE__*/_jsx(ThemeProviderNoVars, {\n theme: theme,\n ...props\n });\n }\n const muiTheme = THEME_ID in theme ? theme[THEME_ID] : theme;\n if (!('colorSchemes' in muiTheme)) {\n return /*#__PURE__*/_jsx(ThemeProviderNoVars, {\n theme: theme,\n ...props\n });\n }\n return /*#__PURE__*/_jsx(CssVarsProvider, {\n theme: theme,\n ...props\n });\n}","import { getRgbaColor, breakpoints, v2Colors } from '@web-for-marketing/react-ui';\nimport { typographyStyles, formControlFontSizeStyles } from '@web-for-marketing/react-ui';\nimport { createTheme } from '@mui/material/styles';\n\nexport const appTheme = createTheme({\n breakpoints: {\n values: {\n xs: parseInt(breakpoints.xs),\n sm: parseInt(breakpoints.sm),\n md: parseInt(breakpoints.md),\n lg: parseInt(breakpoints.lg),\n xl: parseInt(breakpoints.xl),\n },\n },\n palette: {\n primary: {\n main: v2Colors.core.geotab,\n },\n secondary: {\n main: v2Colors.core.innovation,\n },\n text: {\n primary: v2Colors.core.slate,\n secondary: v2Colors.core.silver,\n },\n background: {\n default: v2Colors.core.snow,\n },\n },\n typography: {\n body1: {\n ...typographyStyles.body1,\n color: v2Colors.core.slate,\n },\n body2: {\n ...typographyStyles.body2,\n color: v2Colors.core.slate,\n },\n subtitle1: {\n ...typographyStyles.header4,\n color: v2Colors.core.slate,\n },\n subtitle2: {\n ...typographyStyles.header3,\n color: v2Colors.core.slate,\n fontWeight: 400,\n },\n caption: {\n fontSize: '1.4rem',\n color: v2Colors.core.slate,\n fontWeight: 400,\n },\n },\n components: {\n MuiLink: {\n defaultProps: {\n underline: 'hover',\n },\n },\n MuiListItemText: {\n styleOverrides: {\n primary: {\n color: v2Colors.core.slate,\n },\n },\n },\n MuiCollapse: {\n styleOverrides: {\n entered: {\n zIndex: 9999,\n transform: 'scaleY(1) translateY(0)',\n opacity: 1,\n visibility: 'visible',\n [`@media (max-width: ${breakpoints.sm})`]: {\n transform: 'scaleY(1) translateY(0)',\n },\n borderTop: `0.1rem solid ${getRgbaColor(v2Colors.core.slate, 0.1)}`,\n },\n },\n },\n MuiInputAdornment: {\n styleOverrides: {\n root: {\n height: 'unset',\n },\n },\n },\n MuiAvatar: {\n styleOverrides: {\n root: {\n height: '4rem',\n width: '4rem',\n },\n },\n },\n MuiSvgIcon: {\n styleOverrides: {\n root: {\n fontSize: '2.4rem',\n },\n colorAction: {\n fill: v2Colors.core.slate,\n },\n },\n },\n MuiAccordionDetails: {\n styleOverrides: {\n root: {\n display: 'flex',\n },\n },\n },\n MuiInputLabel: {\n styleOverrides: {\n outlined: {\n ...formControlFontSizeStyles,\n },\n root: {\n ...formControlFontSizeStyles,\n },\n },\n },\n MuiFab: {\n styleOverrides: {\n root: {\n height: '5rem',\n width: '5rem',\n color: v2Colors.core.innovation,\n backgroundColor: v2Colors.core.snow,\n transition: 'color ease .5s',\n textTransform: 'none',\n '&:hover': {\n color: `${v2Colors.core.geotab} !important`,\n backgroundColor: v2Colors.core.snow,\n transition: 'color ease .5s',\n },\n },\n },\n },\n MuiGrid: {\n styleOverrides: {\n container: {\n alignItems: 'stretch',\n },\n item: {\n width: 'auto',\n },\n },\n },\n MuiButton: {\n styleOverrides: {\n root: {\n fontSize: '1.8rem',\n textTransform: 'none',\n minWidth: 'unset',\n letterSpacing: '.05rem',\n textDecoration: 'none',\n minHeight: '5rem',\n boxShadow: 'none !important',\n lineHeight: 1.4,\n fontWeight: 500,\n borderRadius: '0.6rem',\n transition: 'background-color 500ms ease, border-color 500ms ease, color 500ms ease',\n [`@media (min-width: ${breakpoints.xl})`]: {\n fontSize: '2rem',\n },\n [`@media (max-width: ${breakpoints.lg})`]: {\n fontSize: '1.8rem',\n },\n [`@media (max-width: ${breakpoints.sm})`]: {\n fontSize: '1.6rem',\n width: '100%',\n padding: '1.7rem 0 1.9rem',\n textAlign: 'center',\n },\n '& .MuiTouchRipple-root': {\n '@media (prefers-reduced-motion: reduce)': {\n display: 'none !important',\n },\n },\n '&.Mui-disabled': {\n color: v2Colors.core.slate,\n border: `1px solid ${v2Colors.core.smoke}`,\n backgroundColor: v2Colors.core.smoke,\n },\n },\n contained: {\n padding: '1.6rem 2.6rem !important',\n backgroundColor: v2Colors.core.innovation,\n color: v2Colors.core.snow,\n border: '0.1rem solid',\n borderColor: v2Colors.core.innovation,\n '&:hover': {\n borderColor: v2Colors.core.innovation,\n color: v2Colors.core.innovation,\n backgroundColor: v2Colors.core.snow,\n },\n '@media (prefers-reduced-motion: reduce)': {\n '&:focus': {\n borderColor: v2Colors.core.innovation,\n color: v2Colors.core.innovation,\n backgroundColor: v2Colors.core.snow,\n },\n },\n [`@media (max-width: ${breakpoints.md})`]: {\n textAlign: 'center',\n },\n },\n containedPrimary: {\n padding: '1.6rem 2.6rem !important',\n backgroundColor: v2Colors.core.innovation,\n color: v2Colors.core.snow,\n border: '0.1rem solid',\n borderColor: v2Colors.core.innovation,\n '&:hover': {\n borderColor: v2Colors.core.innovation,\n color: v2Colors.core.innovation,\n backgroundColor: v2Colors.core.snow,\n },\n '@media (prefers-reduced-motion: reduce)': {\n '&:focus': {\n borderColor: v2Colors.core.innovation,\n color: v2Colors.core.innovation,\n backgroundColor: v2Colors.core.snow,\n },\n },\n [`@media (max-width: ${breakpoints.md})`]: {\n textAlign: 'center',\n },\n },\n containedSecondary: {\n padding: '1.6rem 2.6rem !important',\n backgroundColor: v2Colors.core.snow,\n color: v2Colors.core.innovation,\n border: '0.1rem solid',\n borderColor: v2Colors.core.snow,\n '&:hover': {\n borderColor: v2Colors.core.snow,\n color: v2Colors.core.snow,\n backgroundColor: v2Colors.core.innovation,\n },\n '@media (prefers-reduced-motion: reduce)': {\n '&:focus': {\n borderColor: v2Colors.core.snow,\n color: v2Colors.core.snow,\n backgroundColor: v2Colors.core.innovation,\n },\n },\n [`@media (max-width: ${breakpoints.md})`]: {\n textAlign: 'center',\n },\n },\n outlined: {\n padding: '1.6rem 2.6rem !important',\n backgroundColor: v2Colors.core.snow,\n color: v2Colors.core.innovation,\n border: '0.1rem solid',\n borderColor: v2Colors.core.innovation,\n '&:hover': {\n color: v2Colors.core.snow,\n borderColor: v2Colors.core.innovation,\n backgroundColor: v2Colors.core.innovation,\n },\n '@media (prefers-reduced-motion: reduce)': {\n '&:focus': {\n color: v2Colors.core.snow,\n borderColor: v2Colors.core.innovation,\n backgroundColor: v2Colors.core.innovation,\n },\n },\n [`@media (max-width: ${breakpoints.md})`]: {\n textAlign: 'center',\n },\n },\n outlinedSecondary: {\n padding: '1.6rem 2.6rem !important',\n backgroundColor: getRgbaColor(v2Colors.core.innovation, 0.3),\n color: v2Colors.core.snow,\n border: '0.1rem solid',\n borderColor: v2Colors.core.snow,\n '&:hover': {\n backgroundColor: v2Colors.core.innovation,\n borderColor: v2Colors.core.snow,\n },\n '@media (prefers-reduced-motion: reduce)': {\n '&:focus': {\n backgroundColor: v2Colors.core.innovation,\n borderColor: v2Colors.core.snow,\n },\n },\n [`@media (max-width: ${breakpoints.md})`]: {\n textAlign: 'center',\n },\n },\n text: {\n color: v2Colors.core.innovation,\n display: 'inline-block',\n padding: '0.6rem 0.8rem !important',\n transform: 'translateX(-0.6rem)',\n background: 'none !important',\n whiteSpace: 'initial',\n '& > *': {\n whiteSpace: 'initial',\n },\n '&:hover': {\n color: v2Colors.core.innovationDark,\n textDecoration: 'underline',\n },\n [`@media (max-width: ${breakpoints.sm})`]: {\n width: 'unset',\n },\n '@media (prefers-reduced-motion: reduce)': {\n '&:focus': {\n color: v2Colors.core.innovationDark,\n outline: `1px solid ${v2Colors.core.innovationDark}`,\n },\n '&:active': {\n color: v2Colors.core.innovationDark,\n outline: 'none',\n },\n },\n },\n textSecondary: {\n color: v2Colors.core.snow,\n display: 'inline-block',\n padding: '0.6rem 0.8rem !important',\n transform: 'translateX(-0.6rem)',\n backgroundColor: 'unset !important',\n border: `0.1rem solid ${getRgbaColor(v2Colors.core.snow, 0)}`,\n '&:hover': {\n color: v2Colors.core.snow,\n borderColor: v2Colors.core.snow,\n backgroundColor: `${getRgbaColor(v2Colors.core.innovation, 0.3)} !important`,\n },\n [`@media (max-width: ${breakpoints.sm})`]: {\n width: 'unset',\n },\n '@media (prefers-reduced-motion: reduce)': {\n '&:focus': {\n color: v2Colors.core.snow,\n borderColor: v2Colors.core.snow,\n backgroundColor: `${getRgbaColor(v2Colors.core.innovation, 0.3)} !important`,\n },\n },\n },\n },\n },\n MuiTooltip: {\n styleOverrides: {\n tooltip: {\n fontSize: '1.4rem',\n fontWeight: 400,\n lineHeight: '1.5 !important',\n },\n },\n },\n MuiList: {\n styleOverrides: {\n padding: {\n paddingTop: 0,\n paddingBottom: 0,\n },\n },\n },\n MuiDialog: {\n styleOverrides: {\n paper: {\n [`@media (max-width: ${breakpoints.sm})`]: {\n margin: '0',\n },\n },\n },\n },\n MuiPopover: {\n styleOverrides: {\n paper: {\n marginTop: '-1rem',\n },\n },\n },\n MuiListItem: {\n styleOverrides: {\n root: {\n fontFamily: 'Roboto, Helvetica, Arial, sans-serif',\n },\n },\n },\n MuiPaper: {\n styleOverrides: {\n root: {\n zIndex: '400 !important' as unknown as number,\n },\n elevation24: {\n boxShadow: `0px 0px 15px ${getRgbaColor(v2Colors.core.deepSpace, 0.5)}`,\n borderRadius: '10px',\n },\n },\n },\n MuiMobileStepper: {\n styleOverrides: {\n dotActive: {\n backgroundColor: v2Colors.core.innovation,\n },\n dot: {\n backgroundColor: v2Colors.core.cloud,\n },\n },\n },\n MuiTablePagination: {\n styleOverrides: {\n input: {\n fontSize: '1.2rem',\n },\n },\n },\n MuiStep: {\n styleOverrides: {\n root: {\n flex: 'unset !important',\n minWidth: '20rem',\n paddingLeft: '2% !important',\n paddingRight: '2% !important',\n },\n },\n },\n MuiStepIcon: {\n styleOverrides: {\n root: {\n fill: v2Colors.core.snow,\n border: `2px ${v2Colors.core.smoke} solid`,\n borderRadius: '100%',\n height: '3.8rem',\n width: '3.8rem',\n '&.Mui-active': {\n borderColor: v2Colors.core.innovation,\n '& text': {\n fill: v2Colors.core.geotab,\n },\n },\n text: {\n fill: v2Colors.core.smoke,\n fontWeight: 500,\n fontSize: '0.5em',\n },\n },\n },\n },\n MuiStepConnector: {\n styleOverrides: {\n root: {\n display: 'none',\n },\n },\n },\n MuiStepLabel: {\n styleOverrides: {\n label: {\n fontSize: '1.7rem',\n letterSpacing: 0,\n fontWeight: 500,\n color: v2Colors.core.smoke,\n marginTop: '2rem',\n },\n root: {\n '&.Mui-active': {\n color: `${v2Colors.core.geotab} !important`,\n },\n },\n },\n },\n MuiStepper: {\n styleOverrides: {\n root: {\n justifyContent: 'center',\n width: '100%',\n position: 'relative',\n '&::after': {\n content: '\"\"',\n width: '96%',\n position: 'absolute',\n backgroundColor: v2Colors.core.smoke,\n height: '2px',\n top: '25%',\n left: '2%',\n zIndex: '-1',\n },\n },\n },\n },\n MuiInput: {\n styleOverrides: {\n underline: {\n borderColor: `${v2Colors.core.geotab} !important`,\n },\n },\n },\n MuiIconButton: {\n styleOverrides: {\n root: {\n '&:hover': {\n backgroundColor: getRgbaColor(v2Colors.core.deepSpace, 0.03),\n },\n '&:focus': {\n backgroundColor: getRgbaColor(v2Colors.core.deepSpace, 0.1),\n },\n },\n },\n },\n MuiSnackbar: {\n styleOverrides: {\n anchorOriginTopCenter: {\n top: '0 !important',\n },\n },\n },\n MuiFormControl: {\n styleOverrides: {\n root: {\n ...formControlFontSizeStyles,\n },\n },\n },\n MuiInputBase: {\n styleOverrides: {\n root: {\n fontSize: 'inherit',\n },\n },\n },\n MuiFormHelperText: {\n styleOverrides: {\n root: {\n fontSize: '1.4rem',\n [`@media (min-width: ${breakpoints.xl})`]: {\n fontSize: '1.6rem',\n },\n [`@media (max-width: ${breakpoints.sm})`]: {\n fontSize: '1.2rem',\n },\n },\n },\n },\n MuiTab: {\n styleOverrides: {\n root: {\n fontSize: '1.5rem !important',\n padding: '1.5rem',\n },\n },\n },\n },\n});\n","import { useEffect, useRef } from 'react';\nimport { useAtom } from 'jotai';\nimport { isMobileAtom } from '@atoms/appSettings';\nimport { breakpoints } from '@web-for-marketing/react-ui';\n\nexport function CheckMobile(): null {\n const resizeTimer = useRef>();\n const [isMobile, setMobile] = useAtom(isMobileAtom);\n const checkWindowSize = (windowObject: Window): void => {\n if (windowObject.innerWidth) {\n if (windowObject.innerWidth <= parseInt(breakpoints.md)) {\n if (!isMobile) {\n setMobile(true);\n }\n } else {\n if (isMobile) {\n setMobile(false);\n }\n }\n }\n };\n\n useEffect(() => {\n checkWindowSize(window);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const handleResize = (): void => {\n if (resizeTimer.current) clearTimeout(resizeTimer.current);\n\n resizeTimer.current = setTimeout(() => {\n checkWindowSize(window);\n }, 300);\n };\n\n window.addEventListener('resize', handleResize);\n\n return () => {\n window.removeEventListener('resize', handleResize);\n if (resizeTimer.current) clearTimeout(resizeTimer.current);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isMobile]);\n\n return null;\n}\n","import createCache, { EmotionCache } from '@emotion/cache';\nimport { CacheProvider } from '@emotion/react';\nimport React from 'react';\n\nfunction getEmotionCache(): EmotionCache {\n const cache = createCache({\n key: 'css',\n insertionPoint:\n typeof document !== 'undefined'\n ? (document.getElementById('emotion-insertion-point') as HTMLElement)\n : undefined,\n });\n cache.compat = true;\n\n return cache;\n}\n\nexport const emotionCache = getEmotionCache();\n\ninterface EmotionCacheProviderProps {\n children: React.ReactNode;\n}\n\nexport function EmotionCacheProvider({ children }: EmotionCacheProviderProps): JSX.Element {\n return {children};\n}\n","import { createStore } from 'jotai';\n\nexport const appStore = createStore();\n","import React from 'react';\nimport Helmet from 'react-helmet';\nimport robotoRegular from '@fonts/roboto-v20-latin-regular.woff2';\nimport roboto500 from '@fonts/roboto-v20-latin-500.woff2';\nimport roboto700 from '@fonts/roboto-v20-latin-700.woff2';\n\nexport function FontPreloadPageHelmet(): JSX.Element {\n return (\n \n \n \n \n \n );\n}\n","import React from 'react';\nimport { useStaticValues } from '@stateManagement/StaticValuesContext';\nimport { v2Colors, breakpoints } from '@web-for-marketing/react-ui';\n\nconst skipToContent = {\n color: v2Colors.core.geotab,\n backgroundColor: v2Colors.core.snow,\n padding: '1.4rem 2rem',\n position: 'absolute',\n fontSize: '2rem',\n top: 0,\n left: -999,\n opacity: 0,\n height: 1,\n width: 1,\n zIndex: -999,\n '&:focus': {\n opacity: 1,\n left: 0,\n height: 'auto',\n width: 'auto',\n zIndex: 999,\n },\n '@media (max-width: 1439.9px)': {\n fontSize: '1.8rem',\n },\n [`@media (max-width: ${breakpoints.md})`]: {\n fontSize: '1.6rem',\n },\n} as const;\n\nexport function SkipToContentLink(): JSX.Element {\n const { fullUrl } = useStaticValues();\n\n return (\n \n Skip to main content\n \n );\n}\n","import type {\n Client,\n Event,\n EventHint,\n Integration,\n IntegrationClass,\n IntegrationFn,\n IntegrationFnResult,\n Options,\n} from '@sentry/types';\nimport { arrayify, logger } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { addGlobalEventProcessor } from './eventProcessors';\nimport { getClient } from './exports';\nimport { getCurrentHub } from './hub';\n\ndeclare module '@sentry/types' {\n interface Integration {\n isDefaultInstance?: boolean;\n }\n}\n\nexport const installedIntegrations: string[] = [];\n\n/** Map of integrations assigned to a client */\nexport type IntegrationIndex = {\n [key: string]: Integration;\n};\n\n/**\n * Remove duplicates from the given array, preferring the last instance of any duplicate. Not guaranteed to\n * preseve the order of integrations in the array.\n *\n * @private\n */\nfunction filterDuplicates(integrations: Integration[]): Integration[] {\n const integrationsByName: { [key: string]: Integration } = {};\n\n integrations.forEach(currentInstance => {\n const { name } = currentInstance;\n\n const existingInstance = integrationsByName[name];\n\n // We want integrations later in the array to overwrite earlier ones of the same type, except that we never want a\n // default instance to overwrite an existing user instance\n if (existingInstance && !existingInstance.isDefaultInstance && currentInstance.isDefaultInstance) {\n return;\n }\n\n integrationsByName[name] = currentInstance;\n });\n\n return Object.keys(integrationsByName).map(k => integrationsByName[k]);\n}\n\n/** Gets integrations to install */\nexport function getIntegrationsToSetup(options: Pick): Integration[] {\n const defaultIntegrations = options.defaultIntegrations || [];\n const userIntegrations = options.integrations;\n\n // We flag default instances, so that later we can tell them apart from any user-created instances of the same class\n defaultIntegrations.forEach(integration => {\n integration.isDefaultInstance = true;\n });\n\n let integrations: Integration[];\n\n if (Array.isArray(userIntegrations)) {\n integrations = [...defaultIntegrations, ...userIntegrations];\n } else if (typeof userIntegrations === 'function') {\n integrations = arrayify(userIntegrations(defaultIntegrations));\n } else {\n integrations = defaultIntegrations;\n }\n\n const finalIntegrations = filterDuplicates(integrations);\n\n // The `Debug` integration prints copies of the `event` and `hint` which will be passed to `beforeSend` or\n // `beforeSendTransaction`. It therefore has to run after all other integrations, so that the changes of all event\n // processors will be reflected in the printed values. For lack of a more elegant way to guarantee that, we therefore\n // locate it and, assuming it exists, pop it out of its current spot and shove it onto the end of the array.\n const debugIndex = findIndex(finalIntegrations, integration => integration.name === 'Debug');\n if (debugIndex !== -1) {\n const [debugInstance] = finalIntegrations.splice(debugIndex, 1);\n finalIntegrations.push(debugInstance);\n }\n\n return finalIntegrations;\n}\n\n/**\n * Given a list of integration instances this installs them all. When `withDefaults` is set to `true` then all default\n * integrations are added unless they were already provided before.\n * @param integrations array of integration instances\n * @param withDefault should enable default integrations\n */\nexport function setupIntegrations(client: Client, integrations: Integration[]): IntegrationIndex {\n const integrationIndex: IntegrationIndex = {};\n\n integrations.forEach(integration => {\n // guard against empty provided integrations\n if (integration) {\n setupIntegration(client, integration, integrationIndex);\n }\n });\n\n return integrationIndex;\n}\n\n/**\n * Execute the `afterAllSetup` hooks of the given integrations.\n */\nexport function afterSetupIntegrations(client: Client, integrations: Integration[]): void {\n for (const integration of integrations) {\n // guard against empty provided integrations\n if (integration && integration.afterAllSetup) {\n integration.afterAllSetup(client);\n }\n }\n}\n\n/** Setup a single integration. */\nexport function setupIntegration(client: Client, integration: Integration, integrationIndex: IntegrationIndex): void {\n if (integrationIndex[integration.name]) {\n DEBUG_BUILD && logger.log(`Integration skipped because it was already installed: ${integration.name}`);\n return;\n }\n integrationIndex[integration.name] = integration;\n\n // `setupOnce` is only called the first time\n if (installedIntegrations.indexOf(integration.name) === -1) {\n // eslint-disable-next-line deprecation/deprecation\n integration.setupOnce(addGlobalEventProcessor, getCurrentHub);\n installedIntegrations.push(integration.name);\n }\n\n // `setup` is run for each client\n if (integration.setup && typeof integration.setup === 'function') {\n integration.setup(client);\n }\n\n if (client.on && typeof integration.preprocessEvent === 'function') {\n const callback = integration.preprocessEvent.bind(integration) as typeof integration.preprocessEvent;\n client.on('preprocessEvent', (event, hint) => callback(event, hint, client));\n }\n\n if (client.addEventProcessor && typeof integration.processEvent === 'function') {\n const callback = integration.processEvent.bind(integration) as typeof integration.processEvent;\n\n const processor = Object.assign((event: Event, hint: EventHint) => callback(event, hint, client), {\n id: integration.name,\n });\n\n client.addEventProcessor(processor);\n }\n\n DEBUG_BUILD && logger.log(`Integration installed: ${integration.name}`);\n}\n\n/** Add an integration to the current hub's client. */\nexport function addIntegration(integration: Integration): void {\n const client = getClient();\n\n if (!client || !client.addIntegration) {\n DEBUG_BUILD && logger.warn(`Cannot add integration \"${integration.name}\" because no SDK Client is available.`);\n return;\n }\n\n client.addIntegration(integration);\n}\n\n// Polyfill for Array.findIndex(), which is not supported in ES5\nfunction findIndex(arr: T[], callback: (item: T) => boolean): number {\n for (let i = 0; i < arr.length; i++) {\n if (callback(arr[i]) === true) {\n return i;\n }\n }\n\n return -1;\n}\n\n/**\n * Convert a new integration function to the legacy class syntax.\n * In v8, we can remove this and instead export the integration functions directly.\n *\n * @deprecated This will be removed in v8!\n */\nexport function convertIntegrationFnToClass(\n name: string,\n fn: Fn,\n): IntegrationClass {\n return Object.assign(\n function ConvertedIntegration(...args: Parameters): Integration {\n return fn(...args);\n },\n { id: name },\n ) as unknown as IntegrationClass;\n}\n\n/**\n * Define an integration function that can be used to create an integration instance.\n * Note that this by design hides the implementation details of the integration, as they are considered internal.\n */\nexport function defineIntegration(fn: Fn): (...args: Parameters) => IntegrationFnResult {\n return fn;\n}\n","import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types';\nimport { getEventDescription, logger, stringMatchesSomePattern } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { convertIntegrationFnToClass, defineIntegration } from '../integration';\n\n// \"Script error.\" is hard coded into browsers for errors that it can't read.\n// this is the result of a script being pulled in from an external domain and CORS.\nconst DEFAULT_IGNORE_ERRORS = [\n /^Script error\\.?$/,\n /^Javascript error: Script error\\.? on line 0$/,\n /^ResizeObserver loop completed with undelivered notifications.$/,\n /^Cannot redefine property: googletag$/,\n];\n\nconst DEFAULT_IGNORE_TRANSACTIONS = [\n /^.*\\/healthcheck$/,\n /^.*\\/healthy$/,\n /^.*\\/live$/,\n /^.*\\/ready$/,\n /^.*\\/heartbeat$/,\n /^.*\\/health$/,\n /^.*\\/healthz$/,\n];\n\n/** Options for the InboundFilters integration */\nexport interface InboundFiltersOptions {\n allowUrls: Array;\n denyUrls: Array;\n ignoreErrors: Array;\n ignoreTransactions: Array;\n ignoreInternal: boolean;\n disableErrorDefaults: boolean;\n disableTransactionDefaults: boolean;\n}\n\nconst INTEGRATION_NAME = 'InboundFilters';\nconst _inboundFiltersIntegration = ((options: Partial = {}) => {\n return {\n name: INTEGRATION_NAME,\n // TODO v8: Remove this\n setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function\n processEvent(event, _hint, client) {\n const clientOptions = client.getOptions();\n const mergedOptions = _mergeOptions(options, clientOptions);\n return _shouldDropEvent(event, mergedOptions) ? null : event;\n },\n };\n}) satisfies IntegrationFn;\n\nexport const inboundFiltersIntegration = defineIntegration(_inboundFiltersIntegration);\n\n/**\n * Inbound filters configurable by the user.\n * @deprecated Use `inboundFiltersIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const InboundFilters = convertIntegrationFnToClass(\n INTEGRATION_NAME,\n inboundFiltersIntegration,\n) as IntegrationClass void }> & {\n new (\n options?: Partial<{\n allowUrls: Array;\n denyUrls: Array;\n ignoreErrors: Array;\n ignoreTransactions: Array;\n ignoreInternal: boolean;\n disableErrorDefaults: boolean;\n disableTransactionDefaults: boolean;\n }>,\n ): Integration;\n};\n\nfunction _mergeOptions(\n internalOptions: Partial = {},\n clientOptions: Partial = {},\n): Partial {\n return {\n allowUrls: [...(internalOptions.allowUrls || []), ...(clientOptions.allowUrls || [])],\n denyUrls: [...(internalOptions.denyUrls || []), ...(clientOptions.denyUrls || [])],\n ignoreErrors: [\n ...(internalOptions.ignoreErrors || []),\n ...(clientOptions.ignoreErrors || []),\n ...(internalOptions.disableErrorDefaults ? [] : DEFAULT_IGNORE_ERRORS),\n ],\n ignoreTransactions: [\n ...(internalOptions.ignoreTransactions || []),\n ...(clientOptions.ignoreTransactions || []),\n ...(internalOptions.disableTransactionDefaults ? [] : DEFAULT_IGNORE_TRANSACTIONS),\n ],\n ignoreInternal: internalOptions.ignoreInternal !== undefined ? internalOptions.ignoreInternal : true,\n };\n}\n\nfunction _shouldDropEvent(event: Event, options: Partial): boolean {\n if (options.ignoreInternal && _isSentryError(event)) {\n DEBUG_BUILD &&\n logger.warn(`Event dropped due to being internal Sentry Error.\\nEvent: ${getEventDescription(event)}`);\n return true;\n }\n if (_isIgnoredError(event, options.ignoreErrors)) {\n DEBUG_BUILD &&\n logger.warn(\n `Event dropped due to being matched by \\`ignoreErrors\\` option.\\nEvent: ${getEventDescription(event)}`,\n );\n return true;\n }\n if (_isIgnoredTransaction(event, options.ignoreTransactions)) {\n DEBUG_BUILD &&\n logger.warn(\n `Event dropped due to being matched by \\`ignoreTransactions\\` option.\\nEvent: ${getEventDescription(event)}`,\n );\n return true;\n }\n if (_isDeniedUrl(event, options.denyUrls)) {\n DEBUG_BUILD &&\n logger.warn(\n `Event dropped due to being matched by \\`denyUrls\\` option.\\nEvent: ${getEventDescription(\n event,\n )}.\\nUrl: ${_getEventFilterUrl(event)}`,\n );\n return true;\n }\n if (!_isAllowedUrl(event, options.allowUrls)) {\n DEBUG_BUILD &&\n logger.warn(\n `Event dropped due to not being matched by \\`allowUrls\\` option.\\nEvent: ${getEventDescription(\n event,\n )}.\\nUrl: ${_getEventFilterUrl(event)}`,\n );\n return true;\n }\n return false;\n}\n\nfunction _isIgnoredError(event: Event, ignoreErrors?: Array): boolean {\n // If event.type, this is not an error\n if (event.type || !ignoreErrors || !ignoreErrors.length) {\n return false;\n }\n\n return _getPossibleEventMessages(event).some(message => stringMatchesSomePattern(message, ignoreErrors));\n}\n\nfunction _isIgnoredTransaction(event: Event, ignoreTransactions?: Array): boolean {\n if (event.type !== 'transaction' || !ignoreTransactions || !ignoreTransactions.length) {\n return false;\n }\n\n const name = event.transaction;\n return name ? stringMatchesSomePattern(name, ignoreTransactions) : false;\n}\n\nfunction _isDeniedUrl(event: Event, denyUrls?: Array): boolean {\n // TODO: Use Glob instead?\n if (!denyUrls || !denyUrls.length) {\n return false;\n }\n const url = _getEventFilterUrl(event);\n return !url ? false : stringMatchesSomePattern(url, denyUrls);\n}\n\nfunction _isAllowedUrl(event: Event, allowUrls?: Array): boolean {\n // TODO: Use Glob instead?\n if (!allowUrls || !allowUrls.length) {\n return true;\n }\n const url = _getEventFilterUrl(event);\n return !url ? true : stringMatchesSomePattern(url, allowUrls);\n}\n\nfunction _getPossibleEventMessages(event: Event): string[] {\n const possibleMessages: string[] = [];\n\n if (event.message) {\n possibleMessages.push(event.message);\n }\n\n let lastException;\n try {\n // @ts-expect-error Try catching to save bundle size\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n lastException = event.exception.values[event.exception.values.length - 1];\n } catch (e) {\n // try catching to save bundle size checking existence of variables\n }\n\n if (lastException) {\n if (lastException.value) {\n possibleMessages.push(lastException.value);\n if (lastException.type) {\n possibleMessages.push(`${lastException.type}: ${lastException.value}`);\n }\n }\n }\n\n if (DEBUG_BUILD && possibleMessages.length === 0) {\n logger.error(`Could not extract message for event ${getEventDescription(event)}`);\n }\n\n return possibleMessages;\n}\n\nfunction _isSentryError(event: Event): boolean {\n try {\n // @ts-expect-error can't be a sentry error if undefined\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return event.exception.values[0].type === 'SentryError';\n } catch (e) {\n // ignore\n }\n return false;\n}\n\nfunction _getLastValidUrl(frames: StackFrame[] = []): string | null {\n for (let i = frames.length - 1; i >= 0; i--) {\n const frame = frames[i];\n\n if (frame && frame.filename !== '' && frame.filename !== '[native code]') {\n return frame.filename || null;\n }\n }\n\n return null;\n}\n\nfunction _getEventFilterUrl(event: Event): string | null {\n try {\n let frames;\n try {\n // @ts-expect-error we only care about frames if the whole thing here is defined\n frames = event.exception.values[0].stacktrace.frames;\n } catch (e) {\n // ignore\n }\n return frames ? _getLastValidUrl(frames) : null;\n } catch (oO) {\n DEBUG_BUILD && logger.error(`Cannot extract url for event ${getEventDescription(event)}`);\n return null;\n }\n}\n","import type { Client, Integration, IntegrationClass, IntegrationFn, WrappedFunction } from '@sentry/types';\nimport { getOriginalFunction } from '@sentry/utils';\nimport { getClient } from '../exports';\nimport { convertIntegrationFnToClass, defineIntegration } from '../integration';\n\nlet originalFunctionToString: () => void;\n\nconst INTEGRATION_NAME = 'FunctionToString';\n\nconst SETUP_CLIENTS = new WeakMap();\n\nconst _functionToStringIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n originalFunctionToString = Function.prototype.toString;\n\n // intrinsics (like Function.prototype) might be immutable in some environments\n // e.g. Node with --frozen-intrinsics, XS (an embedded JavaScript engine) or SES (a JavaScript proposal)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Function.prototype.toString = function (this: WrappedFunction, ...args: any[]): string {\n const originalFunction = getOriginalFunction(this);\n const context =\n SETUP_CLIENTS.has(getClient() as Client) && originalFunction !== undefined ? originalFunction : this;\n return originalFunctionToString.apply(context, args);\n };\n } catch {\n // ignore errors here, just don't patch this\n }\n },\n setup(client) {\n SETUP_CLIENTS.set(client, true);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Patch toString calls to return proper name for wrapped functions.\n *\n * ```js\n * Sentry.init({\n * integrations: [\n * functionToStringIntegration(),\n * ],\n * });\n * ```\n */\nexport const functionToStringIntegration = defineIntegration(_functionToStringIntegration);\n\n/**\n * Patch toString calls to return proper name for wrapped functions.\n *\n * @deprecated Use `functionToStringIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const FunctionToString = convertIntegrationFnToClass(\n INTEGRATION_NAME,\n functionToStringIntegration,\n) as IntegrationClass void }>;\n\n// eslint-disable-next-line deprecation/deprecation\nexport type FunctionToString = typeof FunctionToString;\n","import type { Client, ClientOptions } from '@sentry/types';\nimport { consoleSandbox, logger } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { getCurrentScope } from './exports';\nimport { getCurrentHub } from './hub';\n\n/** A class object that can instantiate Client objects. */\nexport type ClientClass = new (options: O) => F;\n\n/**\n * Internal function to create a new SDK client instance. The client is\n * installed and then bound to the current scope.\n *\n * @param clientClass The client class to instantiate.\n * @param options Options to pass to the client.\n */\nexport function initAndBind(\n clientClass: ClientClass,\n options: O,\n): void {\n if (options.debug === true) {\n if (DEBUG_BUILD) {\n logger.enable();\n } else {\n // use `console.warn` rather than `logger.warn` since by non-debug bundles have all `logger.x` statements stripped\n consoleSandbox(() => {\n // eslint-disable-next-line no-console\n console.warn('[Sentry] Cannot initialize SDK with `debug` option using a non-debug bundle.');\n });\n }\n }\n const scope = getCurrentScope();\n scope.update(options.initialScope);\n\n const client = new clientClass(options);\n setCurrentClient(client);\n initializeClient(client);\n}\n\n/**\n * Make the given client the current client.\n */\nexport function setCurrentClient(client: Client): void {\n // eslint-disable-next-line deprecation/deprecation\n const hub = getCurrentHub();\n // eslint-disable-next-line deprecation/deprecation\n const top = hub.getStackTop();\n top.client = client;\n top.scope.setClient(client);\n}\n\n/**\n * Initialize the client for the current scope.\n * Make sure to call this after `setCurrentClient()`.\n */\nfunction initializeClient(client: Client): void {\n if (client.init) {\n client.init();\n // TODO v8: Remove this fallback\n // eslint-disable-next-line deprecation/deprecation\n } else if (client.setupIntegrations) {\n // eslint-disable-next-line deprecation/deprecation\n client.setupIntegrations();\n }\n}\n","import { DEBUG_BUILD } from './debug-build';\nimport { logger } from './logger';\nimport { getGlobalObject } from './worldwide';\n\n// eslint-disable-next-line deprecation/deprecation\nconst WINDOW = getGlobalObject();\n\ndeclare const EdgeRuntime: string | undefined;\n\nexport { supportsHistory } from './vendor/supportsHistory';\n\n/**\n * Tells whether current environment supports ErrorEvent objects\n * {@link supportsErrorEvent}.\n *\n * @returns Answer to the given question.\n */\nexport function supportsErrorEvent(): boolean {\n try {\n new ErrorEvent('');\n return true;\n } catch (e) {\n return false;\n }\n}\n\n/**\n * Tells whether current environment supports DOMError objects\n * {@link supportsDOMError}.\n *\n * @returns Answer to the given question.\n */\nexport function supportsDOMError(): boolean {\n try {\n // Chrome: VM89:1 Uncaught TypeError: Failed to construct 'DOMError':\n // 1 argument required, but only 0 present.\n // @ts-expect-error It really needs 1 argument, not 0.\n new DOMError('');\n return true;\n } catch (e) {\n return false;\n }\n}\n\n/**\n * Tells whether current environment supports DOMException objects\n * {@link supportsDOMException}.\n *\n * @returns Answer to the given question.\n */\nexport function supportsDOMException(): boolean {\n try {\n new DOMException('');\n return true;\n } catch (e) {\n return false;\n }\n}\n\n/**\n * Tells whether current environment supports Fetch API\n * {@link supportsFetch}.\n *\n * @returns Answer to the given question.\n */\nexport function supportsFetch(): boolean {\n if (!('fetch' in WINDOW)) {\n return false;\n }\n\n try {\n new Headers();\n new Request('http://www.example.com');\n new Response();\n return true;\n } catch (e) {\n return false;\n }\n}\n/**\n * isNativeFetch checks if the given function is a native implementation of fetch()\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function isNativeFetch(func: Function): boolean {\n return func && /^function fetch\\(\\)\\s+\\{\\s+\\[native code\\]\\s+\\}$/.test(func.toString());\n}\n\n/**\n * Tells whether current environment supports Fetch API natively\n * {@link supportsNativeFetch}.\n *\n * @returns true if `window.fetch` is natively implemented, false otherwise\n */\nexport function supportsNativeFetch(): boolean {\n if (typeof EdgeRuntime === 'string') {\n return true;\n }\n\n if (!supportsFetch()) {\n return false;\n }\n\n // Fast path to avoid DOM I/O\n // eslint-disable-next-line @typescript-eslint/unbound-method\n if (isNativeFetch(WINDOW.fetch)) {\n return true;\n }\n\n // window.fetch is implemented, but is polyfilled or already wrapped (e.g: by a chrome extension)\n // so create a \"pure\" iframe to see if that has native fetch\n let result = false;\n const doc = WINDOW.document;\n // eslint-disable-next-line deprecation/deprecation\n if (doc && typeof (doc.createElement as unknown) === 'function') {\n try {\n const sandbox = doc.createElement('iframe');\n sandbox.hidden = true;\n doc.head.appendChild(sandbox);\n if (sandbox.contentWindow && sandbox.contentWindow.fetch) {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n result = isNativeFetch(sandbox.contentWindow.fetch);\n }\n doc.head.removeChild(sandbox);\n } catch (err) {\n DEBUG_BUILD &&\n logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err);\n }\n }\n\n return result;\n}\n\n/**\n * Tells whether current environment supports ReportingObserver API\n * {@link supportsReportingObserver}.\n *\n * @returns Answer to the given question.\n */\nexport function supportsReportingObserver(): boolean {\n return 'ReportingObserver' in WINDOW;\n}\n\n/**\n * Tells whether current environment supports Referrer Policy API\n * {@link supportsReferrerPolicy}.\n *\n * @returns Answer to the given question.\n */\nexport function supportsReferrerPolicy(): boolean {\n // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default'\n // (see https://caniuse.com/#feat=referrer-policy),\n // it doesn't. And it throws an exception instead of ignoring this parameter...\n // REF: https://github.com/getsentry/raven-js/issues/1233\n\n if (!supportsFetch()) {\n return false;\n }\n\n try {\n new Request('_', {\n referrerPolicy: 'origin' as ReferrerPolicy,\n });\n return true;\n } catch (e) {\n return false;\n }\n}\n","// Based on https://github.com/angular/angular.js/pull/13945/files\n// The MIT License\n\n// Copyright (c) 2010-2016 Google, Inc. http://angularjs.org\n\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport { getGlobalObject } from '../worldwide';\n\n// eslint-disable-next-line deprecation/deprecation\nconst WINDOW = getGlobalObject();\n\n/**\n * Tells whether current environment supports History API\n * {@link supportsHistory}.\n *\n * @returns Answer to the given question.\n */\nexport function supportsHistory(): boolean {\n // NOTE: in Chrome App environment, touching history.pushState, *even inside\n // a try/catch block*, will cause Chrome to output an error to console.error\n // borrowed from: https://github.com/angular/angular.js/pull/13945/files\n /* eslint-disable @typescript-eslint/no-unsafe-member-access */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const chromeVar = (WINDOW as any).chrome;\n const isChromePackagedApp = chromeVar && chromeVar.app && chromeVar.app.runtime;\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n const hasHistoryApi = 'history' in WINDOW && !!WINDOW.history.pushState && !!WINDOW.history.replaceState;\n\n return !isChromePackagedApp && hasHistoryApi;\n}\n","import { DEBUG_BUILD } from '../debug-build';\nimport { logger } from '../logger';\nimport { getFunctionName } from '../stacktrace';\n\nexport type InstrumentHandlerType = 'console' | 'dom' | 'fetch' | 'history' | 'xhr' | 'error' | 'unhandledrejection';\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type InstrumentHandlerCallback = (data: any) => void;\n\n// We keep the handlers globally\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\n/** Add a handler function. */\nexport function addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n (handlers[type] as InstrumentHandlerCallback[]).push(handler);\n}\n\n/**\n * Reset all instrumentation handlers.\n * This can be used by tests to ensure we have a clean slate of instrumentation handlers.\n */\nexport function resetInstrumentationHandlers(): void {\n Object.keys(handlers).forEach(key => {\n handlers[key as InstrumentHandlerType] = undefined;\n });\n}\n\n/** Maybe run an instrumentation function, unless it was already called. */\nexport function maybeInstrument(type: InstrumentHandlerType, instrumentFn: () => void): void {\n if (!instrumented[type]) {\n instrumentFn();\n instrumented[type] = true;\n }\n}\n\n/** Trigger handlers for a given instrumentation type. */\nexport function triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = type && handlers[type];\n if (!typeHandlers) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n logger.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n","// TODO(v8): Move everything in this file into the browser package. Nothing here is generic and we run risk of leaking browser types into non-browser packages.\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/ban-types */\nimport type { HandlerDataHistory } from '@sentry/types';\n\nimport { fill } from '../object';\nimport { supportsHistory } from '../supports';\nimport { GLOBAL_OBJ } from '../worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './_handlers';\n\nconst WINDOW = GLOBAL_OBJ as unknown as Window;\n\nlet lastHref: string | undefined;\n\n/**\n * Add an instrumentation handler for when a fetch request happens.\n * The handler function is called once when the request starts and once when it ends,\n * which can be identified by checking if it has an `endTimestamp`.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addHistoryInstrumentationHandler(handler: (data: HandlerDataHistory) => void): void {\n const type = 'history';\n addHandler(type, handler);\n maybeInstrument(type, instrumentHistory);\n}\n\nfunction instrumentHistory(): void {\n if (!supportsHistory()) {\n return;\n }\n\n const oldOnPopState = WINDOW.onpopstate;\n WINDOW.onpopstate = function (this: WindowEventHandlers, ...args: any[]): any {\n const to = WINDOW.location.href;\n // keep track of the current URL state, as we always receive only the updated state\n const from = lastHref;\n lastHref = to;\n const handlerData: HandlerDataHistory = { from, to };\n triggerHandlers('history', handlerData);\n if (oldOnPopState) {\n // Apparently this can throw in Firefox when incorrectly implemented plugin is installed.\n // https://github.com/getsentry/sentry-javascript/issues/3344\n // https://github.com/bugsnag/bugsnag-js/issues/469\n try {\n return oldOnPopState.apply(this, args);\n } catch (_oO) {\n // no-empty\n }\n }\n };\n\n function historyReplacementFunction(originalHistoryFunction: () => void): () => void {\n return function (this: History, ...args: any[]): void {\n const url = args.length > 2 ? args[2] : undefined;\n if (url) {\n // coerce to string (this is what pushState does)\n const from = lastHref;\n const to = String(url);\n // keep track of the current URL state, as we always receive only the updated state\n lastHref = to;\n const handlerData: HandlerDataHistory = { from, to };\n triggerHandlers('history', handlerData);\n }\n return originalHistoryFunction.apply(this, args);\n };\n }\n\n fill(WINDOW.history, 'pushState', historyReplacementFunction);\n fill(WINDOW.history, 'replaceState', historyReplacementFunction);\n}\n","import type { DsnComponents, DsnLike, DsnProtocol } from '@sentry/types';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { consoleSandbox, logger } from './logger';\n\n/** Regular expression used to parse a Dsn. */\nconst DSN_REGEX = /^(?:(\\w+):)\\/\\/(?:(\\w+)(?::(\\w+)?)?@)([\\w.-]+)(?::(\\d+))?\\/(.+)/;\n\nfunction isValidProtocol(protocol?: string): protocol is DsnProtocol {\n return protocol === 'http' || protocol === 'https';\n}\n\n/**\n * Renders the string representation of this Dsn.\n *\n * By default, this will render the public representation without the password\n * component. To get the deprecated private representation, set `withPassword`\n * to true.\n *\n * @param withPassword When set to true, the password will be included.\n */\nexport function dsnToString(dsn: DsnComponents, withPassword: boolean = false): string {\n const { host, path, pass, port, projectId, protocol, publicKey } = dsn;\n return (\n `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ''}` +\n `@${host}${port ? `:${port}` : ''}/${path ? `${path}/` : path}${projectId}`\n );\n}\n\n/**\n * Parses a Dsn from a given string.\n *\n * @param str A Dsn as string\n * @returns Dsn as DsnComponents or undefined if @param str is not a valid DSN string\n */\nexport function dsnFromString(str: string): DsnComponents | undefined {\n const match = DSN_REGEX.exec(str);\n\n if (!match) {\n // This should be logged to the console\n consoleSandbox(() => {\n // eslint-disable-next-line no-console\n console.error(`Invalid Sentry Dsn: ${str}`);\n });\n return undefined;\n }\n\n const [protocol, publicKey, pass = '', host, port = '', lastPath] = match.slice(1);\n let path = '';\n let projectId = lastPath;\n\n const split = projectId.split('/');\n if (split.length > 1) {\n path = split.slice(0, -1).join('/');\n projectId = split.pop() as string;\n }\n\n if (projectId) {\n const projectMatch = projectId.match(/^\\d+/);\n if (projectMatch) {\n projectId = projectMatch[0];\n }\n }\n\n return dsnFromComponents({ host, pass, path, projectId, port, protocol: protocol as DsnProtocol, publicKey });\n}\n\nfunction dsnFromComponents(components: DsnComponents): DsnComponents {\n return {\n protocol: components.protocol,\n publicKey: components.publicKey || '',\n pass: components.pass || '',\n host: components.host,\n port: components.port || '',\n path: components.path || '',\n projectId: components.projectId,\n };\n}\n\nfunction validateDsn(dsn: DsnComponents): boolean {\n if (!DEBUG_BUILD) {\n return true;\n }\n\n const { port, projectId, protocol } = dsn;\n\n const requiredComponents: ReadonlyArray = ['protocol', 'publicKey', 'host', 'projectId'];\n const hasMissingRequiredComponent = requiredComponents.find(component => {\n if (!dsn[component]) {\n logger.error(`Invalid Sentry Dsn: ${component} missing`);\n return true;\n }\n return false;\n });\n\n if (hasMissingRequiredComponent) {\n return false;\n }\n\n if (!projectId.match(/^\\d+$/)) {\n logger.error(`Invalid Sentry Dsn: Invalid projectId ${projectId}`);\n return false;\n }\n\n if (!isValidProtocol(protocol)) {\n logger.error(`Invalid Sentry Dsn: Invalid protocol ${protocol}`);\n return false;\n }\n\n if (port && isNaN(parseInt(port, 10))) {\n logger.error(`Invalid Sentry Dsn: Invalid port ${port}`);\n return false;\n }\n\n return true;\n}\n\n/**\n * Creates a valid Sentry Dsn object, identifying a Sentry instance and project.\n * @returns a valid DsnComponents object or `undefined` if @param from is an invalid DSN source\n */\nexport function makeDsn(from: DsnLike): DsnComponents | undefined {\n const components = typeof from === 'string' ? dsnFromString(from) : dsnFromComponents(from);\n if (!components || !validateDsn(components)) {\n return undefined;\n }\n return components;\n}\n","import type {\n Attachment,\n AttachmentItem,\n BaseEnvelopeHeaders,\n BaseEnvelopeItemHeaders,\n DataCategory,\n DsnComponents,\n Envelope,\n EnvelopeItemType,\n Event,\n EventEnvelopeHeaders,\n SdkInfo,\n SdkMetadata,\n TextEncoderInternal,\n} from '@sentry/types';\n\nimport { dsnToString } from './dsn';\nimport { normalize } from './normalize';\nimport { dropUndefinedKeys } from './object';\n\n/**\n * Creates an envelope.\n * Make sure to always explicitly provide the generic to this function\n * so that the envelope types resolve correctly.\n */\nexport function createEnvelope(headers: E[0], items: E[1] = []): E {\n return [headers, items] as E;\n}\n\n/**\n * Add an item to an envelope.\n * Make sure to always explicitly provide the generic to this function\n * so that the envelope types resolve correctly.\n */\nexport function addItemToEnvelope(envelope: E, newItem: E[1][number]): E {\n const [headers, items] = envelope;\n return [headers, [...items, newItem]] as unknown as E;\n}\n\n/**\n * Convenience function to loop through the items and item types of an envelope.\n * (This function was mostly created because working with envelope types is painful at the moment)\n *\n * If the callback returns true, the rest of the items will be skipped.\n */\nexport function forEachEnvelopeItem(\n envelope: Envelope,\n callback: (envelopeItem: E[1][number], envelopeItemType: E[1][number][0]['type']) => boolean | void,\n): boolean {\n const envelopeItems = envelope[1];\n\n for (const envelopeItem of envelopeItems) {\n const envelopeItemType = envelopeItem[0].type;\n const result = callback(envelopeItem, envelopeItemType);\n\n if (result) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Returns true if the envelope contains any of the given envelope item types\n */\nexport function envelopeContainsItemType(envelope: Envelope, types: EnvelopeItemType[]): boolean {\n return forEachEnvelopeItem(envelope, (_, type) => types.includes(type));\n}\n\n/**\n * Encode a string to UTF8.\n */\nfunction encodeUTF8(input: string, textEncoder?: TextEncoderInternal): Uint8Array {\n const utf8 = textEncoder || new TextEncoder();\n return utf8.encode(input);\n}\n\n/**\n * Serializes an envelope.\n */\nexport function serializeEnvelope(envelope: Envelope, textEncoder?: TextEncoderInternal): string | Uint8Array {\n const [envHeaders, items] = envelope;\n\n // Initially we construct our envelope as a string and only convert to binary chunks if we encounter binary data\n let parts: string | Uint8Array[] = JSON.stringify(envHeaders);\n\n function append(next: string | Uint8Array): void {\n if (typeof parts === 'string') {\n parts = typeof next === 'string' ? parts + next : [encodeUTF8(parts, textEncoder), next];\n } else {\n parts.push(typeof next === 'string' ? encodeUTF8(next, textEncoder) : next);\n }\n }\n\n for (const item of items) {\n const [itemHeaders, payload] = item;\n\n append(`\\n${JSON.stringify(itemHeaders)}\\n`);\n\n if (typeof payload === 'string' || payload instanceof Uint8Array) {\n append(payload);\n } else {\n let stringifiedPayload: string;\n try {\n stringifiedPayload = JSON.stringify(payload);\n } catch (e) {\n // In case, despite all our efforts to keep `payload` circular-dependency-free, `JSON.strinify()` still\n // fails, we try again after normalizing it again with infinite normalization depth. This of course has a\n // performance impact but in this case a performance hit is better than throwing.\n stringifiedPayload = JSON.stringify(normalize(payload));\n }\n append(stringifiedPayload);\n }\n }\n\n return typeof parts === 'string' ? parts : concatBuffers(parts);\n}\n\nfunction concatBuffers(buffers: Uint8Array[]): Uint8Array {\n const totalLength = buffers.reduce((acc, buf) => acc + buf.length, 0);\n\n const merged = new Uint8Array(totalLength);\n let offset = 0;\n for (const buffer of buffers) {\n merged.set(buffer, offset);\n offset += buffer.length;\n }\n\n return merged;\n}\n\nexport interface TextDecoderInternal {\n decode(input?: Uint8Array): string;\n}\n\n/**\n * Parses an envelope\n */\nexport function parseEnvelope(\n env: string | Uint8Array,\n textEncoder: TextEncoderInternal,\n textDecoder: TextDecoderInternal,\n): Envelope {\n let buffer = typeof env === 'string' ? textEncoder.encode(env) : env;\n\n function readBinary(length: number): Uint8Array {\n const bin = buffer.subarray(0, length);\n // Replace the buffer with the remaining data excluding trailing newline\n buffer = buffer.subarray(length + 1);\n return bin;\n }\n\n function readJson(): T {\n let i = buffer.indexOf(0xa);\n // If we couldn't find a newline, we must have found the end of the buffer\n if (i < 0) {\n i = buffer.length;\n }\n\n return JSON.parse(textDecoder.decode(readBinary(i))) as T;\n }\n\n const envelopeHeader = readJson();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const items: [any, any][] = [];\n\n while (buffer.length) {\n const itemHeader = readJson();\n const binaryLength = typeof itemHeader.length === 'number' ? itemHeader.length : undefined;\n\n items.push([itemHeader, binaryLength ? readBinary(binaryLength) : readJson()]);\n }\n\n return [envelopeHeader, items];\n}\n\n/**\n * Creates attachment envelope items\n */\nexport function createAttachmentEnvelopeItem(\n attachment: Attachment,\n textEncoder?: TextEncoderInternal,\n): AttachmentItem {\n const buffer = typeof attachment.data === 'string' ? encodeUTF8(attachment.data, textEncoder) : attachment.data;\n\n return [\n dropUndefinedKeys({\n type: 'attachment',\n length: buffer.length,\n filename: attachment.filename,\n content_type: attachment.contentType,\n attachment_type: attachment.attachmentType,\n }),\n buffer,\n ];\n}\n\nconst ITEM_TYPE_TO_DATA_CATEGORY_MAP: Record = {\n session: 'session',\n sessions: 'session',\n attachment: 'attachment',\n transaction: 'transaction',\n event: 'error',\n client_report: 'internal',\n user_report: 'default',\n profile: 'profile',\n replay_event: 'replay',\n replay_recording: 'replay',\n check_in: 'monitor',\n feedback: 'feedback',\n span: 'span',\n statsd: 'metric_bucket',\n};\n\n/**\n * Maps the type of an envelope item to a data category.\n */\nexport function envelopeItemTypeToDataCategory(type: EnvelopeItemType): DataCategory {\n return ITEM_TYPE_TO_DATA_CATEGORY_MAP[type];\n}\n\n/** Extracts the minimal SDK info from the metadata or an events */\nexport function getSdkMetadataForEnvelopeHeader(metadataOrEvent?: SdkMetadata | Event): SdkInfo | undefined {\n if (!metadataOrEvent || !metadataOrEvent.sdk) {\n return;\n }\n const { name, version } = metadataOrEvent.sdk;\n return { name, version };\n}\n\n/**\n * Creates event envelope headers, based on event, sdk info and tunnel\n * Note: This function was extracted from the core package to make it available in Replay\n */\nexport function createEventEnvelopeHeaders(\n event: Event,\n sdkInfo: SdkInfo | undefined,\n tunnel: string | undefined,\n dsn?: DsnComponents,\n): EventEnvelopeHeaders {\n const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;\n return {\n event_id: event.event_id as string,\n sent_at: new Date().toISOString(),\n ...(sdkInfo && { sdk: sdkInfo }),\n ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }),\n ...(dynamicSamplingContext && {\n trace: dropUndefinedKeys({ ...dynamicSamplingContext }),\n }),\n };\n}\n","import type { ConsoleLevel } from '@sentry/types';\n\n/** An error emitted by Sentry SDKs and related utilities. */\nexport class SentryError extends Error {\n /** Display name of this error instance. */\n public name: string;\n\n public logLevel: ConsoleLevel;\n\n public constructor(public message: string, logLevel: ConsoleLevel = 'warn') {\n super(message);\n\n this.name = new.target.prototype.constructor.name;\n // This sets the prototype to be `Error`, not `SentryError`. It's unclear why we do this, but commenting this line\n // out causes various (seemingly totally unrelated) playwright tests consistently time out. FYI, this makes\n // instances of `SentryError` fail `obj instanceof SentryError` checks.\n Object.setPrototypeOf(this, new.target.prototype);\n this.logLevel = logLevel;\n }\n}\n","import type { ClientOptions, DsnComponents, DsnLike, SdkInfo } from '@sentry/types';\nimport { dsnToString, makeDsn, urlEncode } from '@sentry/utils';\n\nconst SENTRY_API_VERSION = '7';\n\n/** Returns the prefix to construct Sentry ingestion API endpoints. */\nfunction getBaseApiEndpoint(dsn: DsnComponents): string {\n const protocol = dsn.protocol ? `${dsn.protocol}:` : '';\n const port = dsn.port ? `:${dsn.port}` : '';\n return `${protocol}//${dsn.host}${port}${dsn.path ? `/${dsn.path}` : ''}/api/`;\n}\n\n/** Returns the ingest API endpoint for target. */\nfunction _getIngestEndpoint(dsn: DsnComponents): string {\n return `${getBaseApiEndpoint(dsn)}${dsn.projectId}/envelope/`;\n}\n\n/** Returns a URL-encoded string with auth config suitable for a query string. */\nfunction _encodedAuth(dsn: DsnComponents, sdkInfo: SdkInfo | undefined): string {\n return urlEncode({\n // We send only the minimum set of required information. See\n // https://github.com/getsentry/sentry-javascript/issues/2572.\n sentry_key: dsn.publicKey,\n sentry_version: SENTRY_API_VERSION,\n ...(sdkInfo && { sentry_client: `${sdkInfo.name}/${sdkInfo.version}` }),\n });\n}\n\n/**\n * Returns the envelope endpoint URL with auth in the query string.\n *\n * Sending auth as part of the query string and not as custom HTTP headers avoids CORS preflight requests.\n */\nexport function getEnvelopeEndpointWithUrlEncodedAuth(\n dsn: DsnComponents,\n // TODO (v8): Remove `tunnelOrOptions` in favor of `options`, and use the substitute code below\n // options: ClientOptions = {} as ClientOptions,\n tunnelOrOptions: string | ClientOptions = {} as ClientOptions,\n): string {\n // TODO (v8): Use this code instead\n // const { tunnel, _metadata = {} } = options;\n // return tunnel ? tunnel : `${_getIngestEndpoint(dsn)}?${_encodedAuth(dsn, _metadata.sdk)}`;\n\n const tunnel = typeof tunnelOrOptions === 'string' ? tunnelOrOptions : tunnelOrOptions.tunnel;\n const sdkInfo =\n typeof tunnelOrOptions === 'string' || !tunnelOrOptions._metadata ? undefined : tunnelOrOptions._metadata.sdk;\n\n return tunnel ? tunnel : `${_getIngestEndpoint(dsn)}?${_encodedAuth(dsn, sdkInfo)}`;\n}\n\n/** Returns the url to the report dialog endpoint. */\nexport function getReportDialogEndpoint(\n dsnLike: DsnLike,\n dialogOptions: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any;\n user?: { name?: string; email?: string };\n },\n): string {\n const dsn = makeDsn(dsnLike);\n if (!dsn) {\n return '';\n }\n\n const endpoint = `${getBaseApiEndpoint(dsn)}embed/error-page/`;\n\n let encodedOptions = `dsn=${dsnToString(dsn)}`;\n for (const key in dialogOptions) {\n if (key === 'dsn') {\n continue;\n }\n\n if (key === 'onClose') {\n continue;\n }\n\n if (key === 'user') {\n const user = dialogOptions.user;\n if (!user) {\n continue;\n }\n if (user.name) {\n encodedOptions += `&name=${encodeURIComponent(user.name)}`;\n }\n if (user.email) {\n encodedOptions += `&email=${encodeURIComponent(user.email)}`;\n }\n } else {\n encodedOptions += `&${encodeURIComponent(key)}=${encodeURIComponent(dialogOptions[key] as string)}`;\n }\n }\n\n return `${endpoint}?${encodedOptions}`;\n}\n","import type { DsnComponents, MetricBucketItem, SdkMetadata, StatsdEnvelope, StatsdItem } from '@sentry/types';\nimport { createEnvelope, dsnToString } from '@sentry/utils';\nimport { serializeMetricBuckets } from './utils';\n\n/**\n * Create envelope from a metric aggregate.\n */\nexport function createMetricEnvelope(\n metricBucketItems: Array,\n dsn?: DsnComponents,\n metadata?: SdkMetadata,\n tunnel?: string,\n): StatsdEnvelope {\n const headers: StatsdEnvelope[0] = {\n sent_at: new Date().toISOString(),\n };\n\n if (metadata && metadata.sdk) {\n headers.sdk = {\n name: metadata.sdk.name,\n version: metadata.sdk.version,\n };\n }\n\n if (!!tunnel && dsn) {\n headers.dsn = dsnToString(dsn);\n }\n\n const item = createMetricEnvelopeItem(metricBucketItems);\n return createEnvelope(headers, [item]);\n}\n\nfunction createMetricEnvelopeItem(metricBucketItems: MetricBucketItem[]): StatsdItem {\n const payload = serializeMetricBuckets(metricBucketItems);\n const metricHeaders: StatsdItem[0] = {\n type: 'statsd',\n length: payload.length,\n };\n return [metricHeaders, payload];\n}\n","import type { MeasurementUnit, MetricBucketItem, Primitive } from '@sentry/types';\nimport { dropUndefinedKeys } from '@sentry/utils';\nimport type { MetricType } from './types';\n\n/**\n * Generate bucket key from metric properties.\n */\nexport function getBucketKey(\n metricType: MetricType,\n name: string,\n unit: MeasurementUnit,\n tags: Record,\n): string {\n const stringifiedTags = Object.entries(dropUndefinedKeys(tags)).sort((a, b) => a[0].localeCompare(b[0]));\n return `${metricType}${name}${unit}${stringifiedTags}`;\n}\n\n/* eslint-disable no-bitwise */\n/**\n * Simple hash function for strings.\n */\nexport function simpleHash(s: string): number {\n let rv = 0;\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i);\n rv = (rv << 5) - rv + c;\n rv &= rv;\n }\n return rv >>> 0;\n}\n/* eslint-enable no-bitwise */\n\n/**\n * Serialize metrics buckets into a string based on statsd format.\n *\n * Example of format:\n * metric.name@second:1:1.2|d|#a:value,b:anothervalue|T12345677\n * Segments:\n * name: metric.name\n * unit: second\n * value: [1, 1.2]\n * type of metric: d (distribution)\n * tags: { a: value, b: anothervalue }\n * timestamp: 12345677\n */\nexport function serializeMetricBuckets(metricBucketItems: MetricBucketItem[]): string {\n let out = '';\n for (const item of metricBucketItems) {\n const tagEntries = Object.entries(item.tags);\n const maybeTags = tagEntries.length > 0 ? `|#${tagEntries.map(([key, value]) => `${key}:${value}`).join(',')}` : '';\n out += `${item.name}@${item.unit}:${item.metric}|${item.metricType}${maybeTags}|T${item.timestamp}\\n`;\n }\n return out;\n}\n\n/** Sanitizes units */\nexport function sanitizeUnit(unit: string): string {\n return unit.replace(/[^\\w]+/gi, '_');\n}\n\n/** Sanitizes metric keys */\nexport function sanitizeMetricKey(key: string): string {\n return key.replace(/[^\\w\\-.]+/gi, '_');\n}\n\nfunction sanitizeTagKey(key: string): string {\n return key.replace(/[^\\w\\-./]+/gi, '');\n}\n\nconst tagValueReplacements: [string, string][] = [\n ['\\n', '\\\\n'],\n ['\\r', '\\\\r'],\n ['\\t', '\\\\t'],\n ['\\\\', '\\\\\\\\'],\n ['|', '\\\\u{7c}'],\n [',', '\\\\u{2c}'],\n];\n\nfunction getCharOrReplacement(input: string): string {\n for (const [search, replacement] of tagValueReplacements) {\n if (input === search) {\n return replacement;\n }\n }\n\n return input;\n}\n\nfunction sanitizeTagValue(value: string): string {\n return [...value].reduce((acc, char) => acc + getCharOrReplacement(char), '');\n}\n\n/**\n * Sanitizes tags.\n */\nexport function sanitizeTags(unsanitizedTags: Record): Record {\n const tags: Record = {};\n for (const key in unsanitizedTags) {\n if (Object.prototype.hasOwnProperty.call(unsanitizedTags, key)) {\n const sanitizedKey = sanitizeTagKey(key);\n tags[sanitizedKey] = sanitizeTagValue(String(unsanitizedTags[key]));\n }\n }\n return tags;\n}\n","/* eslint-disable max-lines */\nimport type {\n Breadcrumb,\n BreadcrumbHint,\n Client,\n ClientOptions,\n DataCategory,\n DsnComponents,\n DynamicSamplingContext,\n Envelope,\n ErrorEvent,\n Event,\n EventDropReason,\n EventHint,\n EventProcessor,\n FeedbackEvent,\n Integration,\n IntegrationClass,\n MetricBucketItem,\n MetricsAggregator,\n Outcome,\n ParameterizedString,\n SdkMetadata,\n Session,\n SessionAggregates,\n Severity,\n SeverityLevel,\n StartSpanOptions,\n Transaction,\n TransactionEvent,\n Transport,\n TransportMakeRequestResponse,\n} from '@sentry/types';\nimport {\n SentryError,\n SyncPromise,\n addItemToEnvelope,\n checkOrSetAlreadyCaught,\n createAttachmentEnvelopeItem,\n isParameterizedString,\n isPlainObject,\n isPrimitive,\n isThenable,\n logger,\n makeDsn,\n rejectedSyncPromise,\n resolvedSyncPromise,\n} from '@sentry/utils';\n\nimport { getEnvelopeEndpointWithUrlEncodedAuth } from './api';\nimport { DEBUG_BUILD } from './debug-build';\nimport { createEventEnvelope, createSessionEnvelope } from './envelope';\nimport { getClient } from './exports';\nimport { getIsolationScope } from './hub';\nimport type { IntegrationIndex } from './integration';\nimport { afterSetupIntegrations } from './integration';\nimport { setupIntegration, setupIntegrations } from './integration';\nimport { createMetricEnvelope } from './metrics/envelope';\nimport type { Scope } from './scope';\nimport { updateSession } from './session';\nimport { getDynamicSamplingContextFromClient } from './tracing/dynamicSamplingContext';\nimport { prepareEvent } from './utils/prepareEvent';\n\nconst ALREADY_SEEN_ERROR = \"Not capturing exception because it's already been captured.\";\n\n/**\n * Base implementation for all JavaScript SDK clients.\n *\n * Call the constructor with the corresponding options\n * specific to the client subclass. To access these options later, use\n * {@link Client.getOptions}.\n *\n * If a Dsn is specified in the options, it will be parsed and stored. Use\n * {@link Client.getDsn} to retrieve the Dsn at any moment. In case the Dsn is\n * invalid, the constructor will throw a {@link SentryException}. Note that\n * without a valid Dsn, the SDK will not send any events to Sentry.\n *\n * Before sending an event, it is passed through\n * {@link BaseClient._prepareEvent} to add SDK information and scope data\n * (breadcrumbs and context). To add more custom information, override this\n * method and extend the resulting prepared event.\n *\n * To issue automatically created events (e.g. via instrumentation), use\n * {@link Client.captureEvent}. It will prepare the event and pass it through\n * the callback lifecycle. To issue auto-breadcrumbs, use\n * {@link Client.addBreadcrumb}.\n *\n * @example\n * class NodeClient extends BaseClient {\n * public constructor(options: NodeOptions) {\n * super(options);\n * }\n *\n * // ...\n * }\n */\nexport abstract class BaseClient implements Client {\n /**\n * A reference to a metrics aggregator\n *\n * @experimental Note this is alpha API. It may experience breaking changes in the future.\n */\n public metricsAggregator?: MetricsAggregator;\n\n /** Options passed to the SDK. */\n protected readonly _options: O;\n\n /** The client Dsn, if specified in options. Without this Dsn, the SDK will be disabled. */\n protected readonly _dsn?: DsnComponents;\n\n protected readonly _transport?: Transport;\n\n /** Array of set up integrations. */\n protected _integrations: IntegrationIndex;\n\n /** Indicates whether this client's integrations have been set up. */\n protected _integrationsInitialized: boolean;\n\n /** Number of calls being processed */\n protected _numProcessing: number;\n\n protected _eventProcessors: EventProcessor[];\n\n /** Holds flushable */\n private _outcomes: { [key: string]: number };\n\n // eslint-disable-next-line @typescript-eslint/ban-types\n private _hooks: Record;\n\n /**\n * Initializes this client instance.\n *\n * @param options Options for the client.\n */\n protected constructor(options: O) {\n this._options = options;\n this._integrations = {};\n this._integrationsInitialized = false;\n this._numProcessing = 0;\n this._outcomes = {};\n this._hooks = {};\n this._eventProcessors = [];\n\n if (options.dsn) {\n this._dsn = makeDsn(options.dsn);\n } else {\n DEBUG_BUILD && logger.warn('No DSN provided, client will not send events.');\n }\n\n if (this._dsn) {\n const url = getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, options);\n this._transport = options.transport({\n tunnel: this._options.tunnel,\n recordDroppedEvent: this.recordDroppedEvent.bind(this),\n ...options.transportOptions,\n url,\n });\n }\n }\n\n /**\n * @inheritDoc\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types\n public captureException(exception: any, hint?: EventHint, scope?: Scope): string | undefined {\n // ensure we haven't captured this very object before\n if (checkOrSetAlreadyCaught(exception)) {\n DEBUG_BUILD && logger.log(ALREADY_SEEN_ERROR);\n return;\n }\n\n let eventId: string | undefined = hint && hint.event_id;\n\n this._process(\n this.eventFromException(exception, hint)\n .then(event => this._captureEvent(event, hint, scope))\n .then(result => {\n eventId = result;\n }),\n );\n\n return eventId;\n }\n\n /**\n * @inheritDoc\n */\n public captureMessage(\n message: ParameterizedString,\n // eslint-disable-next-line deprecation/deprecation\n level?: Severity | SeverityLevel,\n hint?: EventHint,\n scope?: Scope,\n ): string | undefined {\n let eventId: string | undefined = hint && hint.event_id;\n\n const eventMessage = isParameterizedString(message) ? message : String(message);\n\n const promisedEvent = isPrimitive(message)\n ? this.eventFromMessage(eventMessage, level, hint)\n : this.eventFromException(message, hint);\n\n this._process(\n promisedEvent\n .then(event => this._captureEvent(event, hint, scope))\n .then(result => {\n eventId = result;\n }),\n );\n\n return eventId;\n }\n\n /**\n * @inheritDoc\n */\n public captureEvent(event: Event, hint?: EventHint, scope?: Scope): string | undefined {\n // ensure we haven't captured this very object before\n if (hint && hint.originalException && checkOrSetAlreadyCaught(hint.originalException)) {\n DEBUG_BUILD && logger.log(ALREADY_SEEN_ERROR);\n return;\n }\n\n let eventId: string | undefined = hint && hint.event_id;\n\n const sdkProcessingMetadata = event.sdkProcessingMetadata || {};\n const capturedSpanScope: Scope | undefined = sdkProcessingMetadata.capturedSpanScope;\n\n this._process(\n this._captureEvent(event, hint, capturedSpanScope || scope).then(result => {\n eventId = result;\n }),\n );\n\n return eventId;\n }\n\n /**\n * @inheritDoc\n */\n public captureSession(session: Session): void {\n if (!(typeof session.release === 'string')) {\n DEBUG_BUILD && logger.warn('Discarded session because of missing or non-string release');\n } else {\n this.sendSession(session);\n // After sending, we set init false to indicate it's not the first occurrence\n updateSession(session, { init: false });\n }\n }\n\n /**\n * @inheritDoc\n */\n public getDsn(): DsnComponents | undefined {\n return this._dsn;\n }\n\n /**\n * @inheritDoc\n */\n public getOptions(): O {\n return this._options;\n }\n\n /**\n * @see SdkMetadata in @sentry/types\n *\n * @return The metadata of the SDK\n */\n public getSdkMetadata(): SdkMetadata | undefined {\n return this._options._metadata;\n }\n\n /**\n * @inheritDoc\n */\n public getTransport(): Transport | undefined {\n return this._transport;\n }\n\n /**\n * @inheritDoc\n */\n public flush(timeout?: number): PromiseLike {\n const transport = this._transport;\n if (transport) {\n if (this.metricsAggregator) {\n this.metricsAggregator.flush();\n }\n return this._isClientDoneProcessing(timeout).then(clientFinished => {\n return transport.flush(timeout).then(transportFlushed => clientFinished && transportFlushed);\n });\n } else {\n return resolvedSyncPromise(true);\n }\n }\n\n /**\n * @inheritDoc\n */\n public close(timeout?: number): PromiseLike {\n return this.flush(timeout).then(result => {\n this.getOptions().enabled = false;\n if (this.metricsAggregator) {\n this.metricsAggregator.close();\n }\n return result;\n });\n }\n\n /** Get all installed event processors. */\n public getEventProcessors(): EventProcessor[] {\n return this._eventProcessors;\n }\n\n /** @inheritDoc */\n public addEventProcessor(eventProcessor: EventProcessor): void {\n this._eventProcessors.push(eventProcessor);\n }\n\n /**\n * This is an internal function to setup all integrations that should run on the client.\n * @deprecated Use `client.init()` instead.\n */\n public setupIntegrations(forceInitialize?: boolean): void {\n if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {\n this._setupIntegrations();\n }\n }\n\n /** @inheritdoc */\n public init(): void {\n if (this._isEnabled()) {\n this._setupIntegrations();\n }\n }\n\n /**\n * Gets an installed integration by its `id`.\n *\n * @returns The installed integration or `undefined` if no integration with that `id` was installed.\n * @deprecated Use `getIntegrationByName()` instead.\n */\n public getIntegrationById(integrationId: string): Integration | undefined {\n return this.getIntegrationByName(integrationId);\n }\n\n /**\n * Gets an installed integration by its name.\n *\n * @returns The installed integration or `undefined` if no integration with that `name` was installed.\n */\n public getIntegrationByName(integrationName: string): T | undefined {\n return this._integrations[integrationName] as T | undefined;\n }\n\n /**\n * Returns the client's instance of the given integration class, it any.\n * @deprecated Use `getIntegrationByName()` instead.\n */\n public getIntegration(integration: IntegrationClass): T | null {\n try {\n return (this._integrations[integration.id] as T) || null;\n } catch (_oO) {\n DEBUG_BUILD && logger.warn(`Cannot retrieve integration ${integration.id} from the current Client`);\n return null;\n }\n }\n\n /**\n * @inheritDoc\n */\n public addIntegration(integration: Integration): void {\n const isAlreadyInstalled = this._integrations[integration.name];\n\n // This hook takes care of only installing if not already installed\n setupIntegration(this, integration, this._integrations);\n // Here we need to check manually to make sure to not run this multiple times\n if (!isAlreadyInstalled) {\n afterSetupIntegrations(this, [integration]);\n }\n }\n\n /**\n * @inheritDoc\n */\n public sendEvent(event: Event, hint: EventHint = {}): void {\n this.emit('beforeSendEvent', event, hint);\n\n let env = createEventEnvelope(event, this._dsn, this._options._metadata, this._options.tunnel);\n\n for (const attachment of hint.attachments || []) {\n env = addItemToEnvelope(\n env,\n createAttachmentEnvelopeItem(\n attachment,\n this._options.transportOptions && this._options.transportOptions.textEncoder,\n ),\n );\n }\n\n const promise = this._sendEnvelope(env);\n if (promise) {\n promise.then(sendResponse => this.emit('afterSendEvent', event, sendResponse), null);\n }\n }\n\n /**\n * @inheritDoc\n */\n public sendSession(session: Session | SessionAggregates): void {\n const env = createSessionEnvelope(session, this._dsn, this._options._metadata, this._options.tunnel);\n\n // _sendEnvelope should not throw\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._sendEnvelope(env);\n }\n\n /**\n * @inheritDoc\n */\n public recordDroppedEvent(reason: EventDropReason, category: DataCategory, eventOrCount?: Event | number): void {\n if (this._options.sendClientReports) {\n // TODO v9: We do not need the `event` passed as third argument anymore, and can possibly remove this overload\n // If event is passed as third argument, we assume this is a count of 1\n const count = typeof eventOrCount === 'number' ? eventOrCount : 1;\n\n // We want to track each category (error, transaction, session, replay_event) separately\n // but still keep the distinction between different type of outcomes.\n // We could use nested maps, but it's much easier to read and type this way.\n // A correct type for map-based implementation if we want to go that route\n // would be `Partial>>>`\n // With typescript 4.1 we could even use template literal types\n const key = `${reason}:${category}`;\n DEBUG_BUILD && logger.log(`Recording outcome: \"${key}\"${count > 1 ? ` (${count} times)` : ''}`);\n this._outcomes[key] = (this._outcomes[key] || 0) + count;\n }\n }\n\n /**\n * @inheritDoc\n */\n public captureAggregateMetrics(metricBucketItems: Array): void {\n DEBUG_BUILD && logger.log(`Flushing aggregated metrics, number of metrics: ${metricBucketItems.length}`);\n const metricsEnvelope = createMetricEnvelope(\n metricBucketItems,\n this._dsn,\n this._options._metadata,\n this._options.tunnel,\n );\n\n // _sendEnvelope should not throw\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._sendEnvelope(metricsEnvelope);\n }\n\n // Keep on() & emit() signatures in sync with types' client.ts interface\n /* eslint-disable @typescript-eslint/unified-signatures */\n\n /** @inheritdoc */\n public on(hook: 'startTransaction', callback: (transaction: Transaction) => void): void;\n\n /** @inheritdoc */\n public on(hook: 'finishTransaction', callback: (transaction: Transaction) => void): void;\n\n /** @inheritdoc */\n public on(hook: 'beforeEnvelope', callback: (envelope: Envelope) => void): void;\n\n /** @inheritdoc */\n public on(hook: 'beforeSendEvent', callback: (event: Event, hint?: EventHint) => void): void;\n\n /** @inheritdoc */\n public on(hook: 'preprocessEvent', callback: (event: Event, hint?: EventHint) => void): void;\n\n /** @inheritdoc */\n public on(\n hook: 'afterSendEvent',\n callback: (event: Event, sendResponse: TransportMakeRequestResponse | void) => void,\n ): void;\n\n /** @inheritdoc */\n public on(hook: 'beforeAddBreadcrumb', callback: (breadcrumb: Breadcrumb, hint?: BreadcrumbHint) => void): void;\n\n /** @inheritdoc */\n public on(hook: 'createDsc', callback: (dsc: DynamicSamplingContext) => void): void;\n\n /** @inheritdoc */\n public on(hook: 'otelSpanEnd', callback: (otelSpan: unknown, mutableOptions: { drop: boolean }) => void): void;\n\n /** @inheritdoc */\n public on(\n hook: 'beforeSendFeedback',\n callback: (feedback: FeedbackEvent, options?: { includeReplay: boolean }) => void,\n ): void;\n\n /** @inheritdoc */\n public on(hook: 'startPageLoadSpan', callback: (options: StartSpanOptions) => void): void;\n\n /** @inheritdoc */\n public on(hook: 'startNavigationSpan', callback: (options: StartSpanOptions) => void): void;\n\n /** @inheritdoc */\n public on(hook: string, callback: unknown): void {\n if (!this._hooks[hook]) {\n this._hooks[hook] = [];\n }\n\n // @ts-expect-error We assue the types are correct\n this._hooks[hook].push(callback);\n }\n\n /** @inheritdoc */\n public emit(hook: 'startTransaction', transaction: Transaction): void;\n\n /** @inheritdoc */\n public emit(hook: 'finishTransaction', transaction: Transaction): void;\n\n /** @inheritdoc */\n public emit(hook: 'beforeEnvelope', envelope: Envelope): void;\n\n /** @inheritdoc */\n public emit(hook: 'beforeSendEvent', event: Event, hint?: EventHint): void;\n\n /** @inheritdoc */\n public emit(hook: 'preprocessEvent', event: Event, hint?: EventHint): void;\n\n /** @inheritdoc */\n public emit(hook: 'afterSendEvent', event: Event, sendResponse: TransportMakeRequestResponse | void): void;\n\n /** @inheritdoc */\n public emit(hook: 'beforeAddBreadcrumb', breadcrumb: Breadcrumb, hint?: BreadcrumbHint): void;\n\n /** @inheritdoc */\n public emit(hook: 'createDsc', dsc: DynamicSamplingContext): void;\n\n /** @inheritdoc */\n public emit(hook: 'otelSpanEnd', otelSpan: unknown, mutableOptions: { drop: boolean }): void;\n\n /** @inheritdoc */\n public emit(hook: 'beforeSendFeedback', feedback: FeedbackEvent, options?: { includeReplay: boolean }): void;\n\n /** @inheritdoc */\n public emit(hook: 'startPageLoadSpan', options: StartSpanOptions): void;\n\n /** @inheritdoc */\n public emit(hook: 'startNavigationSpan', options: StartSpanOptions): void;\n\n /** @inheritdoc */\n public emit(hook: string, ...rest: unknown[]): void {\n if (this._hooks[hook]) {\n this._hooks[hook].forEach(callback => callback(...rest));\n }\n }\n\n /* eslint-enable @typescript-eslint/unified-signatures */\n\n /** Setup integrations for this client. */\n protected _setupIntegrations(): void {\n const { integrations } = this._options;\n this._integrations = setupIntegrations(this, integrations);\n afterSetupIntegrations(this, integrations);\n\n // TODO v8: We don't need this flag anymore\n this._integrationsInitialized = true;\n }\n\n /** Updates existing session based on the provided event */\n protected _updateSessionFromEvent(session: Session, event: Event): void {\n let crashed = false;\n let errored = false;\n const exceptions = event.exception && event.exception.values;\n\n if (exceptions) {\n errored = true;\n\n for (const ex of exceptions) {\n const mechanism = ex.mechanism;\n if (mechanism && mechanism.handled === false) {\n crashed = true;\n break;\n }\n }\n }\n\n // A session is updated and that session update is sent in only one of the two following scenarios:\n // 1. Session with non terminal status and 0 errors + an error occurred -> Will set error count to 1 and send update\n // 2. Session with non terminal status and 1 error + a crash occurred -> Will set status crashed and send update\n const sessionNonTerminal = session.status === 'ok';\n const shouldUpdateAndSend = (sessionNonTerminal && session.errors === 0) || (sessionNonTerminal && crashed);\n\n if (shouldUpdateAndSend) {\n updateSession(session, {\n ...(crashed && { status: 'crashed' }),\n errors: session.errors || Number(errored || crashed),\n });\n this.captureSession(session);\n }\n }\n\n /**\n * Determine if the client is finished processing. Returns a promise because it will wait `timeout` ms before saying\n * \"no\" (resolving to `false`) in order to give the client a chance to potentially finish first.\n *\n * @param timeout The time, in ms, after which to resolve to `false` if the client is still busy. Passing `0` (or not\n * passing anything) will make the promise wait as long as it takes for processing to finish before resolving to\n * `true`.\n * @returns A promise which will resolve to `true` if processing is already done or finishes before the timeout, and\n * `false` otherwise\n */\n protected _isClientDoneProcessing(timeout?: number): PromiseLike {\n return new SyncPromise(resolve => {\n let ticked: number = 0;\n const tick: number = 1;\n\n const interval = setInterval(() => {\n if (this._numProcessing == 0) {\n clearInterval(interval);\n resolve(true);\n } else {\n ticked += tick;\n if (timeout && ticked >= timeout) {\n clearInterval(interval);\n resolve(false);\n }\n }\n }, tick);\n });\n }\n\n /** Determines whether this SDK is enabled and a transport is present. */\n protected _isEnabled(): boolean {\n return this.getOptions().enabled !== false && this._transport !== undefined;\n }\n\n /**\n * Adds common information to events.\n *\n * The information includes release and environment from `options`,\n * breadcrumbs and context (extra, tags and user) from the scope.\n *\n * Information that is already present in the event is never overwritten. For\n * nested objects, such as the context, keys are merged.\n *\n * @param event The original event.\n * @param hint May contain additional information about the original exception.\n * @param scope A scope containing event metadata.\n * @returns A new event with more information.\n */\n protected _prepareEvent(\n event: Event,\n hint: EventHint,\n scope?: Scope,\n isolationScope = getIsolationScope(),\n ): PromiseLike {\n const options = this.getOptions();\n const integrations = Object.keys(this._integrations);\n if (!hint.integrations && integrations.length > 0) {\n hint.integrations = integrations;\n }\n\n this.emit('preprocessEvent', event, hint);\n\n return prepareEvent(options, event, hint, scope, this, isolationScope).then(evt => {\n if (evt === null) {\n return evt;\n }\n\n const propagationContext = {\n ...isolationScope.getPropagationContext(),\n ...(scope ? scope.getPropagationContext() : undefined),\n };\n\n const trace = evt.contexts && evt.contexts.trace;\n if (!trace && propagationContext) {\n const { traceId: trace_id, spanId, parentSpanId, dsc } = propagationContext;\n evt.contexts = {\n trace: {\n trace_id,\n span_id: spanId,\n parent_span_id: parentSpanId,\n },\n ...evt.contexts,\n };\n\n const dynamicSamplingContext = dsc ? dsc : getDynamicSamplingContextFromClient(trace_id, this, scope);\n\n evt.sdkProcessingMetadata = {\n dynamicSamplingContext,\n ...evt.sdkProcessingMetadata,\n };\n }\n return evt;\n });\n }\n\n /**\n * Processes the event and logs an error in case of rejection\n * @param event\n * @param hint\n * @param scope\n */\n protected _captureEvent(event: Event, hint: EventHint = {}, scope?: Scope): PromiseLike {\n return this._processEvent(event, hint, scope).then(\n finalEvent => {\n return finalEvent.event_id;\n },\n reason => {\n if (DEBUG_BUILD) {\n // If something's gone wrong, log the error as a warning. If it's just us having used a `SentryError` for\n // control flow, log just the message (no stack) as a log-level log.\n const sentryError = reason as SentryError;\n if (sentryError.logLevel === 'log') {\n logger.log(sentryError.message);\n } else {\n logger.warn(sentryError);\n }\n }\n return undefined;\n },\n );\n }\n\n /**\n * Processes an event (either error or message) and sends it to Sentry.\n *\n * This also adds breadcrumbs and context information to the event. However,\n * platform specific meta data (such as the User's IP address) must be added\n * by the SDK implementor.\n *\n *\n * @param event The event to send to Sentry.\n * @param hint May contain additional information about the original exception.\n * @param scope A scope containing event metadata.\n * @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send.\n */\n protected _processEvent(event: Event, hint: EventHint, scope?: Scope): PromiseLike {\n const options = this.getOptions();\n const { sampleRate } = options;\n\n const isTransaction = isTransactionEvent(event);\n const isError = isErrorEvent(event);\n const eventType = event.type || 'error';\n const beforeSendLabel = `before send for type \\`${eventType}\\``;\n\n // 1.0 === 100% events are sent\n // 0.0 === 0% events are sent\n // Sampling for transaction happens somewhere else\n if (isError && typeof sampleRate === 'number' && Math.random() > sampleRate) {\n this.recordDroppedEvent('sample_rate', 'error', event);\n return rejectedSyncPromise(\n new SentryError(\n `Discarding event because it's not included in the random sample (sampling rate = ${sampleRate})`,\n 'log',\n ),\n );\n }\n\n const dataCategory: DataCategory = eventType === 'replay_event' ? 'replay' : eventType;\n\n const sdkProcessingMetadata = event.sdkProcessingMetadata || {};\n const capturedSpanIsolationScope: Scope | undefined = sdkProcessingMetadata.capturedSpanIsolationScope;\n\n return this._prepareEvent(event, hint, scope, capturedSpanIsolationScope)\n .then(prepared => {\n if (prepared === null) {\n this.recordDroppedEvent('event_processor', dataCategory, event);\n throw new SentryError('An event processor returned `null`, will not send event.', 'log');\n }\n\n const isInternalException = hint.data && (hint.data as { __sentry__: boolean }).__sentry__ === true;\n if (isInternalException) {\n return prepared;\n }\n\n const result = processBeforeSend(options, prepared, hint);\n return _validateBeforeSendResult(result, beforeSendLabel);\n })\n .then(processedEvent => {\n if (processedEvent === null) {\n this.recordDroppedEvent('before_send', dataCategory, event);\n if (isTransaction) {\n const spans = event.spans || [];\n // the transaction itself counts as one span, plus all the child spans that are added\n const spanCount = 1 + spans.length;\n this.recordDroppedEvent('before_send', 'span', spanCount);\n }\n throw new SentryError(`${beforeSendLabel} returned \\`null\\`, will not send event.`, 'log');\n }\n\n const session = scope && scope.getSession();\n if (!isTransaction && session) {\n this._updateSessionFromEvent(session, processedEvent);\n }\n\n if (isTransaction) {\n const spanCountBefore =\n (processedEvent.sdkProcessingMetadata && processedEvent.sdkProcessingMetadata.spanCountBeforeProcessing) ||\n 0;\n const spanCountAfter = processedEvent.spans ? processedEvent.spans.length : 0;\n\n const droppedSpanCount = spanCountBefore - spanCountAfter;\n if (droppedSpanCount > 0) {\n this.recordDroppedEvent('before_send', 'span', droppedSpanCount);\n }\n }\n\n // None of the Sentry built event processor will update transaction name,\n // so if the transaction name has been changed by an event processor, we know\n // it has to come from custom event processor added by a user\n const transactionInfo = processedEvent.transaction_info;\n if (isTransaction && transactionInfo && processedEvent.transaction !== event.transaction) {\n const source = 'custom';\n processedEvent.transaction_info = {\n ...transactionInfo,\n source,\n };\n }\n\n this.sendEvent(processedEvent, hint);\n return processedEvent;\n })\n .then(null, reason => {\n if (reason instanceof SentryError) {\n throw reason;\n }\n\n this.captureException(reason, {\n data: {\n __sentry__: true,\n },\n originalException: reason,\n });\n throw new SentryError(\n `Event processing pipeline threw an error, original event will not be sent. Details have been sent as a new event.\\nReason: ${reason}`,\n );\n });\n }\n\n /**\n * Occupies the client with processing and event\n */\n protected _process(promise: PromiseLike): void {\n this._numProcessing++;\n void promise.then(\n value => {\n this._numProcessing--;\n return value;\n },\n reason => {\n this._numProcessing--;\n return reason;\n },\n );\n }\n\n /**\n * @inheritdoc\n */\n protected _sendEnvelope(envelope: Envelope): PromiseLike | void {\n this.emit('beforeEnvelope', envelope);\n\n if (this._isEnabled() && this._transport) {\n return this._transport.send(envelope).then(null, reason => {\n DEBUG_BUILD && logger.error('Error while sending event:', reason);\n });\n } else {\n DEBUG_BUILD && logger.error('Transport disabled');\n }\n }\n\n /**\n * Clears outcomes on this client and returns them.\n */\n protected _clearOutcomes(): Outcome[] {\n const outcomes = this._outcomes;\n this._outcomes = {};\n return Object.keys(outcomes).map(key => {\n const [reason, category] = key.split(':') as [EventDropReason, DataCategory];\n return {\n reason,\n category,\n quantity: outcomes[key],\n };\n });\n }\n\n /**\n * @inheritDoc\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types\n public abstract eventFromException(_exception: any, _hint?: EventHint): PromiseLike;\n\n /**\n * @inheritDoc\n */\n public abstract eventFromMessage(\n _message: ParameterizedString,\n // eslint-disable-next-line deprecation/deprecation\n _level?: Severity | SeverityLevel,\n _hint?: EventHint,\n ): PromiseLike;\n}\n\n/**\n * Verifies that return value of configured `beforeSend` or `beforeSendTransaction` is of expected type, and returns the value if so.\n */\nfunction _validateBeforeSendResult(\n beforeSendResult: PromiseLike | Event | null,\n beforeSendLabel: string,\n): PromiseLike | Event | null {\n const invalidValueError = `${beforeSendLabel} must return \\`null\\` or a valid event.`;\n if (isThenable(beforeSendResult)) {\n return beforeSendResult.then(\n event => {\n if (!isPlainObject(event) && event !== null) {\n throw new SentryError(invalidValueError);\n }\n return event;\n },\n e => {\n throw new SentryError(`${beforeSendLabel} rejected with ${e}`);\n },\n );\n } else if (!isPlainObject(beforeSendResult) && beforeSendResult !== null) {\n throw new SentryError(invalidValueError);\n }\n return beforeSendResult;\n}\n\n/**\n * Process the matching `beforeSendXXX` callback.\n */\nfunction processBeforeSend(\n options: ClientOptions,\n event: Event,\n hint: EventHint,\n): PromiseLike | Event | null {\n const { beforeSend, beforeSendTransaction } = options;\n\n if (isErrorEvent(event) && beforeSend) {\n return beforeSend(event, hint);\n }\n\n if (isTransactionEvent(event) && beforeSendTransaction) {\n if (event.spans) {\n // We store the # of spans before processing in SDK metadata,\n // so we can compare it afterwards to determine how many spans were dropped\n const spanCountBefore = event.spans.length;\n event.sdkProcessingMetadata = {\n ...event.sdkProcessingMetadata,\n spanCountBeforeProcessing: spanCountBefore,\n };\n }\n return beforeSendTransaction(event, hint);\n }\n\n return event;\n}\n\nfunction isErrorEvent(event: Event): event is ErrorEvent {\n return event.type === undefined;\n}\n\nfunction isTransactionEvent(event: Event): event is TransactionEvent {\n return event.type === 'transaction';\n}\n\n/**\n * Add an event processor to the current client.\n * This event processor will run for all events processed by this client.\n */\nexport function addEventProcessor(callback: EventProcessor): void {\n const client = getClient();\n\n if (!client || !client.addEventProcessor) {\n return;\n }\n\n client.addEventProcessor(callback);\n}\n","import type { Options } from '@sentry/types';\nimport { SDK_VERSION } from '../version';\n\n/**\n * A builder for the SDK metadata in the options for the SDK initialization.\n *\n * Note: This function is identical to `buildMetadata` in Remix and NextJS and SvelteKit.\n * We don't extract it for bundle size reasons.\n * @see https://github.com/getsentry/sentry-javascript/pull/7404\n * @see https://github.com/getsentry/sentry-javascript/pull/4196\n *\n * If you make changes to this function consider updating the others as well.\n *\n * @param options SDK options object that gets mutated\n * @param names list of package names\n */\nexport function applySdkMetadata(options: Options, name: string, names = [name], source = 'npm'): void {\n const metadata = options._metadata || {};\n\n if (!metadata.sdk) {\n metadata.sdk = {\n name: `sentry.javascript.${name}`,\n packages: names.map(name => ({\n name: `${source}:@sentry/${name}`,\n version: SDK_VERSION,\n })),\n version: SDK_VERSION,\n };\n }\n\n options._metadata = metadata;\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 { getClient } from '@sentry/core';\nimport type {\n Event,\n EventHint,\n Exception,\n ParameterizedString,\n Severity,\n SeverityLevel,\n StackFrame,\n StackParser,\n} from '@sentry/types';\nimport {\n addExceptionMechanism,\n addExceptionTypeValue,\n extractExceptionKeysForMessage,\n isDOMError,\n isDOMException,\n isError,\n isErrorEvent,\n isEvent,\n isParameterizedString,\n isPlainObject,\n normalizeToSize,\n resolvedSyncPromise,\n} from '@sentry/utils';\n\ntype Prototype = { constructor: (...args: unknown[]) => unknown };\n\n/**\n * This function creates an exception from a JavaScript Error\n */\nexport function exceptionFromError(stackParser: StackParser, ex: Error): Exception {\n // Get the frames first since Opera can lose the stack if we touch anything else first\n const frames = parseStackFrames(stackParser, ex);\n\n const exception: Exception = {\n type: ex && ex.name,\n value: extractMessage(ex),\n };\n\n if (frames.length) {\n exception.stacktrace = { frames };\n }\n\n if (exception.type === undefined && exception.value === '') {\n exception.value = 'Unrecoverable error caught';\n }\n\n return exception;\n}\n\n/**\n * @hidden\n */\nexport function eventFromPlainObject(\n stackParser: StackParser,\n exception: Record,\n syntheticException?: Error,\n isUnhandledRejection?: boolean,\n): Event {\n const client = getClient();\n const normalizeDepth = client && client.getOptions().normalizeDepth;\n\n const event: Event = {\n exception: {\n values: [\n {\n type: isEvent(exception) ? exception.constructor.name : isUnhandledRejection ? 'UnhandledRejection' : 'Error',\n value: getNonErrorObjectExceptionValue(exception, { isUnhandledRejection }),\n },\n ],\n },\n extra: {\n __serialized__: normalizeToSize(exception, normalizeDepth),\n },\n };\n\n if (syntheticException) {\n const frames = parseStackFrames(stackParser, syntheticException);\n if (frames.length) {\n // event.exception.values[0] has been set above\n (event.exception as { values: Exception[] }).values[0].stacktrace = { frames };\n }\n }\n\n return event;\n}\n\n/**\n * @hidden\n */\nexport function eventFromError(stackParser: StackParser, ex: Error): Event {\n return {\n exception: {\n values: [exceptionFromError(stackParser, ex)],\n },\n };\n}\n\n/** Parses stack frames from an error */\nexport function parseStackFrames(\n stackParser: StackParser,\n ex: Error & { framesToPop?: number; stacktrace?: string },\n): StackFrame[] {\n // Access and store the stacktrace property before doing ANYTHING\n // else to it because Opera is not very good at providing it\n // reliably in other circumstances.\n const stacktrace = ex.stacktrace || ex.stack || '';\n\n const popSize = getPopSize(ex);\n\n try {\n return stackParser(stacktrace, popSize);\n } catch (e) {\n // no-empty\n }\n\n return [];\n}\n\n// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108\nconst reactMinifiedRegexp = /Minified React error #\\d+;/i;\n\nfunction getPopSize(ex: Error & { framesToPop?: number }): number {\n if (ex) {\n if (typeof ex.framesToPop === 'number') {\n return ex.framesToPop;\n }\n\n if (reactMinifiedRegexp.test(ex.message)) {\n return 1;\n }\n }\n\n return 0;\n}\n\n/**\n * There are cases where stacktrace.message is an Event object\n * https://github.com/getsentry/sentry-javascript/issues/1949\n * In this specific case we try to extract stacktrace.message.error.message\n */\nfunction extractMessage(ex: Error & { message: { error?: Error } }): string {\n const message = ex && ex.message;\n if (!message) {\n return 'No error message';\n }\n if (message.error && typeof message.error.message === 'string') {\n return message.error.message;\n }\n return message;\n}\n\n/**\n * Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`.\n * @hidden\n */\nexport function eventFromException(\n stackParser: StackParser,\n exception: unknown,\n hint?: EventHint,\n attachStacktrace?: boolean,\n): PromiseLike {\n const syntheticException = (hint && hint.syntheticException) || undefined;\n const event = eventFromUnknownInput(stackParser, exception, syntheticException, attachStacktrace);\n addExceptionMechanism(event); // defaults to { type: 'generic', handled: true }\n event.level = 'error';\n if (hint && hint.event_id) {\n event.event_id = hint.event_id;\n }\n return resolvedSyncPromise(event);\n}\n\n/**\n * Builds and Event from a Message\n * @hidden\n */\nexport function eventFromMessage(\n stackParser: StackParser,\n message: ParameterizedString,\n // eslint-disable-next-line deprecation/deprecation\n level: Severity | SeverityLevel = 'info',\n hint?: EventHint,\n attachStacktrace?: boolean,\n): PromiseLike {\n const syntheticException = (hint && hint.syntheticException) || undefined;\n const event = eventFromString(stackParser, message, syntheticException, attachStacktrace);\n event.level = level;\n if (hint && hint.event_id) {\n event.event_id = hint.event_id;\n }\n return resolvedSyncPromise(event);\n}\n\n/**\n * @hidden\n */\nexport function eventFromUnknownInput(\n stackParser: StackParser,\n exception: unknown,\n syntheticException?: Error,\n attachStacktrace?: boolean,\n isUnhandledRejection?: boolean,\n): Event {\n let event: Event;\n\n if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) {\n // If it is an ErrorEvent with `error` property, extract it to get actual Error\n const errorEvent = exception as ErrorEvent;\n return eventFromError(stackParser, errorEvent.error as Error);\n }\n\n // If it is a `DOMError` (which is a legacy API, but still supported in some browsers) then we just extract the name\n // and message, as it doesn't provide anything else. According to the spec, all `DOMExceptions` should also be\n // `Error`s, but that's not the case in IE11, so in that case we treat it the same as we do a `DOMError`.\n //\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMError\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMException\n // https://webidl.spec.whatwg.org/#es-DOMException-specialness\n if (isDOMError(exception) || isDOMException(exception as DOMException)) {\n const domException = exception as DOMException;\n\n if ('stack' in (exception as Error)) {\n event = eventFromError(stackParser, exception as Error);\n } else {\n const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');\n const message = domException.message ? `${name}: ${domException.message}` : name;\n event = eventFromString(stackParser, message, syntheticException, attachStacktrace);\n addExceptionTypeValue(event, message);\n }\n if ('code' in domException) {\n // eslint-disable-next-line deprecation/deprecation\n event.tags = { ...event.tags, 'DOMException.code': `${domException.code}` };\n }\n\n return event;\n }\n if (isError(exception)) {\n // we have a real Error object, do nothing\n return eventFromError(stackParser, exception);\n }\n if (isPlainObject(exception) || isEvent(exception)) {\n // If it's a plain object or an instance of `Event` (the built-in JS kind, not this SDK's `Event` type), serialize\n // it manually. This will allow us to group events based on top-level keys which is much better than creating a new\n // group on any key/value change.\n const objectException = exception as Record;\n event = eventFromPlainObject(stackParser, objectException, syntheticException, isUnhandledRejection);\n addExceptionMechanism(event, {\n synthetic: true,\n });\n return event;\n }\n\n // If none of previous checks were valid, then it means that it's not:\n // - an instance of DOMError\n // - an instance of DOMException\n // - an instance of Event\n // - an instance of Error\n // - a valid ErrorEvent (one with an error property)\n // - a plain Object\n //\n // So bail out and capture it as a simple message:\n event = eventFromString(stackParser, exception as string, syntheticException, attachStacktrace);\n addExceptionTypeValue(event, `${exception}`, undefined);\n addExceptionMechanism(event, {\n synthetic: true,\n });\n\n return event;\n}\n\n/**\n * @hidden\n */\nexport function eventFromString(\n stackParser: StackParser,\n message: ParameterizedString,\n syntheticException?: Error,\n attachStacktrace?: boolean,\n): Event {\n const event: Event = {};\n\n if (attachStacktrace && syntheticException) {\n const frames = parseStackFrames(stackParser, syntheticException);\n if (frames.length) {\n event.exception = {\n values: [{ value: message, stacktrace: { frames } }],\n };\n }\n }\n\n if (isParameterizedString(message)) {\n const { __sentry_template_string__, __sentry_template_values__ } = message;\n\n event.logentry = {\n message: __sentry_template_string__,\n params: __sentry_template_values__,\n };\n return event;\n }\n\n event.message = message;\n return event;\n}\n\nfunction getNonErrorObjectExceptionValue(\n exception: Record,\n { isUnhandledRejection }: { isUnhandledRejection?: boolean },\n): string {\n const keys = extractExceptionKeysForMessage(exception);\n const captureType = isUnhandledRejection ? 'promise rejection' : 'exception';\n\n // Some ErrorEvent instances do not have an `error` property, which is why they are not handled before\n // We still want to try to get a decent message for these cases\n if (isErrorEvent(exception)) {\n return `Event \\`ErrorEvent\\` captured as ${captureType} with message \\`${exception.message}\\``;\n }\n\n if (isEvent(exception)) {\n const className = getObjectClassName(exception);\n return `Event \\`${className}\\` (type=${exception.type}) captured as ${captureType}`;\n }\n\n return `Object captured as ${captureType} with keys: ${keys}`;\n}\n\nfunction getObjectClassName(obj: unknown): string | undefined | void {\n try {\n const prototype: Prototype | null = Object.getPrototypeOf(obj);\n return prototype ? prototype.constructor.name : undefined;\n } catch (e) {\n // ignore errors here\n }\n}\n","import type { browserTracingIntegration } from '@sentry-internal/tracing';\nimport { BrowserTracing } from '@sentry-internal/tracing';\nimport { captureException, withScope } from '@sentry/core';\nimport type { DsnLike, Integration, Mechanism, WrappedFunction } from '@sentry/types';\nimport {\n GLOBAL_OBJ,\n addExceptionMechanism,\n addExceptionTypeValue,\n addNonEnumerableProperty,\n getOriginalFunction,\n markFunctionWrapped,\n} from '@sentry/utils';\n\nexport const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\nlet ignoreOnError: number = 0;\n\n/**\n * @hidden\n */\nexport function shouldIgnoreOnError(): boolean {\n return ignoreOnError > 0;\n}\n\n/**\n * @hidden\n */\nexport function ignoreNextOnError(): void {\n // onerror should trigger before setTimeout\n ignoreOnError++;\n setTimeout(() => {\n ignoreOnError--;\n });\n}\n\n/**\n * Instruments the given function and sends an event to Sentry every time the\n * function throws an exception.\n *\n * @param fn A function to wrap. It is generally safe to pass an unbound function, because the returned wrapper always\n * has a correct `this` context.\n * @returns The wrapped function.\n * @hidden\n */\nexport function wrap(\n fn: WrappedFunction,\n options: {\n mechanism?: Mechanism;\n } = {},\n before?: WrappedFunction,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any {\n // for future readers what this does is wrap a function and then create\n // a bi-directional wrapping between them.\n //\n // example: wrapped = wrap(original);\n // original.__sentry_wrapped__ -> wrapped\n // wrapped.__sentry_original__ -> original\n\n if (typeof fn !== 'function') {\n return fn;\n }\n\n try {\n // if we're dealing with a function that was previously wrapped, return\n // the original wrapper.\n const wrapper = fn.__sentry_wrapped__;\n if (wrapper) {\n if (typeof wrapper === 'function') {\n return wrapper;\n } else {\n // If we find that the `__sentry_wrapped__` function is not a function at the time of accessing it, it means\n // that something messed with it. In that case we want to return the originally passed function.\n return fn;\n }\n }\n\n // We don't wanna wrap it twice\n if (getOriginalFunction(fn)) {\n return fn;\n }\n } catch (e) {\n // Just accessing custom props in some Selenium environments\n // can cause a \"Permission denied\" exception (see raven-js#495).\n // Bail on wrapping and return the function as-is (defers to window.onerror).\n return fn;\n }\n\n /* eslint-disable prefer-rest-params */\n // It is important that `sentryWrapped` is not an arrow function to preserve the context of `this`\n const sentryWrapped: WrappedFunction = function (this: unknown): void {\n const args = Array.prototype.slice.call(arguments);\n\n try {\n if (before && typeof before === 'function') {\n before.apply(this, arguments);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n const wrappedArguments = args.map((arg: any) => wrap(arg, options));\n\n // Attempt to invoke user-land function\n // NOTE: If you are a Sentry user, and you are seeing this stack frame, it\n // means the sentry.javascript SDK caught an error invoking your application code. This\n // is expected behavior and NOT indicative of a bug with sentry.javascript.\n return fn.apply(this, wrappedArguments);\n } catch (ex) {\n ignoreNextOnError();\n\n withScope(scope => {\n scope.addEventProcessor(event => {\n if (options.mechanism) {\n addExceptionTypeValue(event, undefined, undefined);\n addExceptionMechanism(event, options.mechanism);\n }\n\n event.extra = {\n ...event.extra,\n arguments: args,\n };\n\n return event;\n });\n\n captureException(ex);\n });\n\n throw ex;\n }\n };\n /* eslint-enable prefer-rest-params */\n\n // Accessing some objects may throw\n // ref: https://github.com/getsentry/sentry-javascript/issues/1168\n try {\n for (const property in fn) {\n if (Object.prototype.hasOwnProperty.call(fn, property)) {\n sentryWrapped[property] = fn[property];\n }\n }\n } catch (_oO) {} // eslint-disable-line no-empty\n\n // Signal that this function has been wrapped/filled already\n // for both debugging and to prevent it to being wrapped/filled twice\n markFunctionWrapped(sentryWrapped, fn);\n\n addNonEnumerableProperty(fn, '__sentry_wrapped__', sentryWrapped);\n\n // Restore original function name (not all browsers allow that)\n try {\n const descriptor = Object.getOwnPropertyDescriptor(sentryWrapped, 'name') as PropertyDescriptor;\n if (descriptor.configurable) {\n Object.defineProperty(sentryWrapped, 'name', {\n get(): string {\n return fn.name;\n },\n });\n }\n // eslint-disable-next-line no-empty\n } catch (_oO) {}\n\n return sentryWrapped;\n}\n\n/**\n * All properties the report dialog supports\n *\n * @deprecated This type will be removed in the next major version of the Sentry SDK. `showReportDialog` will still be around, however the `eventId` option will now be required.\n */\nexport interface ReportDialogOptions {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any;\n eventId?: string;\n dsn?: DsnLike;\n user?: {\n email?: string;\n name?: string;\n };\n lang?: string;\n title?: string;\n subtitle?: string;\n subtitle2?: string;\n labelName?: string;\n labelEmail?: string;\n labelComments?: string;\n labelClose?: string;\n labelSubmit?: string;\n errorGeneric?: string;\n errorFormEntry?: string;\n successMessage?: string;\n /** Callback after reportDialog showed up */\n onLoad?(this: void): void;\n /** Callback after reportDialog closed */\n onClose?(this: void): void;\n}\n\n/**\n * This is a slim shim of `browserTracingIntegration` for the CDN bundles.\n * Since the actual functional integration uses a different code from `BrowserTracing`,\n * we want to avoid shipping both of them in the CDN bundles, as that would blow up the size.\n * Instead, we provide a functional integration with the same API, but the old implementation.\n * This means that it's not possible to register custom routing instrumentation, but that's OK for now.\n * We also don't expose the utilities for this anyhow in the CDN bundles.\n * For users that need custom routing in CDN bundles, they have to continue using `new BrowserTracing()` until v8.\n */\nexport function bundleBrowserTracingIntegration(\n options: Parameters[0] = {},\n): Integration {\n // Migrate some options from the old integration to the new one\n // eslint-disable-next-line deprecation/deprecation\n const opts: ConstructorParameters[0] = options;\n\n if (typeof options.markBackgroundSpan === 'boolean') {\n opts.markBackgroundTransactions = options.markBackgroundSpan;\n }\n\n if (typeof options.instrumentPageLoad === 'boolean') {\n opts.startTransactionOnPageLoad = options.instrumentPageLoad;\n }\n\n if (typeof options.instrumentNavigation === 'boolean') {\n opts.startTransactionOnLocationChange = options.instrumentNavigation;\n }\n\n // eslint-disable-next-line deprecation/deprecation\n return new BrowserTracing(opts);\n}\n","import type { Scope } from '@sentry/core';\nimport { applySdkMetadata } from '@sentry/core';\nimport { BaseClient } from '@sentry/core';\nimport type {\n BrowserClientProfilingOptions,\n BrowserClientReplayOptions,\n ClientOptions,\n Event,\n EventHint,\n Options,\n ParameterizedString,\n Severity,\n SeverityLevel,\n UserFeedback,\n} from '@sentry/types';\nimport { createClientReportEnvelope, dsnToString, getSDKSource, logger } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { eventFromException, eventFromMessage } from './eventbuilder';\nimport { WINDOW } from './helpers';\nimport type { BrowserTransportOptions } from './transports/types';\nimport { createUserFeedbackEnvelope } from './userfeedback';\n\n/**\n * Configuration options for the Sentry Browser SDK.\n * @see @sentry/types Options for more information.\n */\nexport type BrowserOptions = Options &\n BrowserClientReplayOptions &\n BrowserClientProfilingOptions;\n\n/**\n * Configuration options for the Sentry Browser SDK Client class\n * @see BrowserClient for more information.\n */\nexport type BrowserClientOptions = ClientOptions &\n BrowserClientReplayOptions &\n BrowserClientProfilingOptions;\n\n/**\n * The Sentry Browser SDK Client.\n *\n * @see BrowserOptions for documentation on configuration options.\n * @see SentryClient for usage documentation.\n */\nexport class BrowserClient extends BaseClient {\n /**\n * Creates a new Browser SDK instance.\n *\n * @param options Configuration options for this SDK.\n */\n public constructor(options: BrowserClientOptions) {\n const sdkSource = WINDOW.SENTRY_SDK_SOURCE || getSDKSource();\n applySdkMetadata(options, 'browser', ['browser'], sdkSource);\n\n super(options);\n\n if (options.sendClientReports && WINDOW.document) {\n WINDOW.document.addEventListener('visibilitychange', () => {\n if (WINDOW.document.visibilityState === 'hidden') {\n this._flushOutcomes();\n }\n });\n }\n }\n\n /**\n * @inheritDoc\n */\n public eventFromException(exception: unknown, hint?: EventHint): PromiseLike {\n return eventFromException(this._options.stackParser, exception, hint, this._options.attachStacktrace);\n }\n\n /**\n * @inheritDoc\n */\n public eventFromMessage(\n message: ParameterizedString,\n // eslint-disable-next-line deprecation/deprecation\n level: Severity | SeverityLevel = 'info',\n hint?: EventHint,\n ): PromiseLike {\n return eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace);\n }\n\n /**\n * Sends user feedback to Sentry.\n */\n public captureUserFeedback(feedback: UserFeedback): void {\n if (!this._isEnabled()) {\n DEBUG_BUILD && logger.warn('SDK not enabled, will not capture user feedback.');\n return;\n }\n\n const envelope = createUserFeedbackEnvelope(feedback, {\n metadata: this.getSdkMetadata(),\n dsn: this.getDsn(),\n tunnel: this.getOptions().tunnel,\n });\n\n // _sendEnvelope should not throw\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._sendEnvelope(envelope);\n }\n\n /**\n * @inheritDoc\n */\n protected _prepareEvent(event: Event, hint: EventHint, scope?: Scope): PromiseLike {\n event.platform = event.platform || 'javascript';\n return super._prepareEvent(event, hint, scope);\n }\n\n /**\n * Sends client reports as an envelope.\n */\n private _flushOutcomes(): void {\n const outcomes = this._clearOutcomes();\n\n if (outcomes.length === 0) {\n DEBUG_BUILD && logger.log('No outcomes to send');\n return;\n }\n\n // This is really the only place where we want to check for a DSN and only send outcomes then\n if (!this._dsn) {\n DEBUG_BUILD && logger.log('No dsn provided, will not send outcomes');\n return;\n }\n\n DEBUG_BUILD && logger.log('Sending outcomes:', outcomes);\n\n const envelope = createClientReportEnvelope(outcomes, this._options.tunnel && dsnToString(this._dsn));\n\n // _sendEnvelope should not throw\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._sendEnvelope(envelope);\n }\n}\n","/*\n * This module exists for optimizations in the build process through rollup and terser. We define some global\n * constants, which can be overridden during build. By guarding certain pieces of code with functions that return these\n * constants, we can control whether or not they appear in the final bundle. (Any code guarded by a false condition will\n * never run, and will hence be dropped during treeshaking.) The two primary uses for this are stripping out calls to\n * `logger` and preventing node-related code from appearing in browser bundles.\n *\n * Attention:\n * This file should not be used to define constants/flags that are intended to be used for tree-shaking conducted by\n * users. These flags should live in their respective packages, as we identified user tooling (specifically webpack)\n * having issues tree-shaking these constants across package boundaries.\n * An example for this is the __SENTRY_DEBUG__ constant. It is declared in each package individually because we want\n * users to be able to shake away expressions that it guards.\n */\n\ndeclare const __SENTRY_BROWSER_BUNDLE__: boolean | undefined;\n\nexport type SdkSource = 'npm' | 'cdn' | 'loader';\n\n/**\n * Figures out if we're building a browser bundle.\n *\n * @returns true if this is a browser bundle build.\n */\nexport function isBrowserBundle(): boolean {\n return typeof __SENTRY_BROWSER_BUNDLE__ !== 'undefined' && !!__SENTRY_BROWSER_BUNDLE__;\n}\n\n/**\n * Get source of SDK.\n */\nexport function getSDKSource(): SdkSource {\n // @ts-expect-error __SENTRY_SDK_SOURCE__ is injected by rollup during build process\n return __SENTRY_SDK_SOURCE__;\n}\n","import type { DsnComponents, EventEnvelope, SdkMetadata, UserFeedback, UserFeedbackItem } from '@sentry/types';\nimport { createEnvelope, dsnToString } from '@sentry/utils';\n\n/**\n * Creates an envelope from a user feedback.\n */\nexport function createUserFeedbackEnvelope(\n feedback: UserFeedback,\n {\n metadata,\n tunnel,\n dsn,\n }: {\n metadata: SdkMetadata | undefined;\n tunnel: string | undefined;\n dsn: DsnComponents | undefined;\n },\n): EventEnvelope {\n const headers: EventEnvelope[0] = {\n event_id: feedback.event_id,\n sent_at: new Date().toISOString(),\n ...(metadata &&\n metadata.sdk && {\n sdk: {\n name: metadata.sdk.name,\n version: metadata.sdk.version,\n },\n }),\n ...(!!tunnel && !!dsn && { dsn: dsnToString(dsn) }),\n };\n const item = createUserFeedbackEnvelopeItem(feedback);\n\n return createEnvelope(headers, [item]);\n}\n\nfunction createUserFeedbackEnvelopeItem(feedback: UserFeedback): UserFeedbackItem {\n const feedbackHeaders: UserFeedbackItem[0] = {\n type: 'user_report',\n };\n return [feedbackHeaders, feedback];\n}\n","import type { ClientReport, ClientReportEnvelope, ClientReportItem } from '@sentry/types';\n\nimport { createEnvelope } from './envelope';\nimport { dateTimestampInSeconds } from './time';\n\n/**\n * Creates client report envelope\n * @param discarded_events An array of discard events\n * @param dsn A DSN that can be set on the header. Optional.\n */\nexport function createClientReportEnvelope(\n discarded_events: ClientReport['discarded_events'],\n dsn?: string,\n timestamp?: number,\n): ClientReportEnvelope {\n const clientReportItem: ClientReportItem = [\n { type: 'client_report' },\n {\n timestamp: timestamp || dateTimestampInSeconds(),\n discarded_events,\n },\n ];\n return createEnvelope(dsn ? { dsn } : {}, [clientReportItem]);\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/ban-types */\nimport type { ConsoleLevel, HandlerDataConsole } from '@sentry/types';\n\nimport { CONSOLE_LEVELS, originalConsoleMethods } from '../logger';\nimport { fill } from '../object';\nimport { GLOBAL_OBJ } from '../worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './_handlers';\n\n/**\n * Add an instrumentation handler for when a console.xxx method is called.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addConsoleInstrumentationHandler(handler: (data: HandlerDataConsole) => void): void {\n const type = 'console';\n addHandler(type, handler);\n maybeInstrument(type, instrumentConsole);\n}\n\nfunction instrumentConsole(): void {\n if (!('console' in GLOBAL_OBJ)) {\n return;\n }\n\n CONSOLE_LEVELS.forEach(function (level: ConsoleLevel): void {\n if (!(level in GLOBAL_OBJ.console)) {\n return;\n }\n\n fill(GLOBAL_OBJ.console, level, function (originalConsoleMethod: () => any): Function {\n originalConsoleMethods[level] = originalConsoleMethod;\n\n return function (...args: any[]): void {\n const handlerData: HandlerDataConsole = { args, level };\n triggerHandlers('console', handlerData);\n\n const log = originalConsoleMethods[level];\n log && log.apply(GLOBAL_OBJ.console, args);\n };\n });\n });\n}\n","// TODO(v8): Move everything in this file into the browser package. Nothing here is generic and we run risk of leaking browser types into non-browser packages.\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/ban-types */\nimport type { HandlerDataDom } from '@sentry/types';\n\nimport { uuid4 } from '../misc';\nimport { addNonEnumerableProperty, fill } from '../object';\nimport { GLOBAL_OBJ } from '../worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './_handlers';\n\ntype SentryWrappedTarget = HTMLElement & { _sentryId?: string };\n\ntype AddEventListener = (\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n) => void;\ntype RemoveEventListener = (\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n) => void;\n\ntype InstrumentedElement = Element & {\n __sentry_instrumentation_handlers__?: {\n [key in 'click' | 'keypress']?: {\n handler?: Function;\n /** The number of custom listeners attached to this element */\n refCount: number;\n };\n };\n};\n\nconst WINDOW = GLOBAL_OBJ as unknown as Window;\nconst DEBOUNCE_DURATION = 1000;\n\nlet debounceTimerID: number | undefined;\nlet lastCapturedEventType: string | undefined;\nlet lastCapturedEventTargetId: string | undefined;\n\n/**\n * Add an instrumentation handler for when a click or a keypress happens.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addClickKeypressInstrumentationHandler(handler: (data: HandlerDataDom) => void): void {\n const type = 'dom';\n addHandler(type, handler);\n maybeInstrument(type, instrumentDOM);\n}\n\n/** Exported for tests only. */\nexport function instrumentDOM(): void {\n if (!WINDOW.document) {\n return;\n }\n\n // Make it so that any click or keypress that is unhandled / bubbled up all the way to the document triggers our dom\n // handlers. (Normally we have only one, which captures a breadcrumb for each click or keypress.) Do this before\n // we instrument `addEventListener` so that we don't end up attaching this handler twice.\n const triggerDOMHandler = triggerHandlers.bind(null, 'dom');\n const globalDOMEventHandler = makeDOMEventHandler(triggerDOMHandler, true);\n WINDOW.document.addEventListener('click', globalDOMEventHandler, false);\n WINDOW.document.addEventListener('keypress', globalDOMEventHandler, false);\n\n // After hooking into click and keypress events bubbled up to `document`, we also hook into user-handled\n // clicks & keypresses, by adding an event listener of our own to any element to which they add a listener. That\n // way, whenever one of their handlers is triggered, ours will be, too. (This is needed because their handler\n // could potentially prevent the event from bubbling up to our global listeners. This way, our handler are still\n // guaranteed to fire at least once.)\n ['EventTarget', 'Node'].forEach((target: string) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const proto = (WINDOW as any)[target] && (WINDOW as any)[target].prototype;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins\n if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {\n return;\n }\n\n fill(proto, 'addEventListener', function (originalAddEventListener: AddEventListener): AddEventListener {\n return function (\n this: Element,\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): AddEventListener {\n if (type === 'click' || type == 'keypress') {\n try {\n const el = this as InstrumentedElement;\n const handlers = (el.__sentry_instrumentation_handlers__ = el.__sentry_instrumentation_handlers__ || {});\n const handlerForType = (handlers[type] = handlers[type] || { refCount: 0 });\n\n if (!handlerForType.handler) {\n const handler = makeDOMEventHandler(triggerDOMHandler);\n handlerForType.handler = handler;\n originalAddEventListener.call(this, type, handler, options);\n }\n\n handlerForType.refCount++;\n } catch (e) {\n // Accessing dom properties is always fragile.\n // Also allows us to skip `addEventListenrs` calls with no proper `this` context.\n }\n }\n\n return originalAddEventListener.call(this, type, listener, options);\n };\n });\n\n fill(\n proto,\n 'removeEventListener',\n function (originalRemoveEventListener: RemoveEventListener): RemoveEventListener {\n return function (\n this: Element,\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): () => void {\n if (type === 'click' || type == 'keypress') {\n try {\n const el = this as InstrumentedElement;\n const handlers = el.__sentry_instrumentation_handlers__ || {};\n const handlerForType = handlers[type];\n\n if (handlerForType) {\n handlerForType.refCount--;\n // If there are no longer any custom handlers of the current type on this element, we can remove ours, too.\n if (handlerForType.refCount <= 0) {\n originalRemoveEventListener.call(this, type, handlerForType.handler, options);\n handlerForType.handler = undefined;\n delete handlers[type]; // eslint-disable-line @typescript-eslint/no-dynamic-delete\n }\n\n // If there are no longer any custom handlers of any type on this element, cleanup everything.\n if (Object.keys(handlers).length === 0) {\n delete el.__sentry_instrumentation_handlers__;\n }\n }\n } catch (e) {\n // Accessing dom properties is always fragile.\n // Also allows us to skip `addEventListenrs` calls with no proper `this` context.\n }\n }\n\n return originalRemoveEventListener.call(this, type, listener, options);\n };\n },\n );\n });\n}\n\n/**\n * Check whether the event is similar to the last captured one. For example, two click events on the same button.\n */\nfunction isSimilarToLastCapturedEvent(event: Event): boolean {\n // If both events have different type, then user definitely performed two separate actions. e.g. click + keypress.\n if (event.type !== lastCapturedEventType) {\n return false;\n }\n\n try {\n // If both events have the same type, it's still possible that actions were performed on different targets.\n // e.g. 2 clicks on different buttons.\n if (!event.target || (event.target as SentryWrappedTarget)._sentryId !== lastCapturedEventTargetId) {\n return false;\n }\n } catch (e) {\n // just accessing `target` property can throw an exception in some rare circumstances\n // see: https://github.com/getsentry/sentry-javascript/issues/838\n }\n\n // If both events have the same type _and_ same `target` (an element which triggered an event, _not necessarily_\n // to which an event listener was attached), we treat them as the same action, as we want to capture\n // only one breadcrumb. e.g. multiple clicks on the same button, or typing inside a user input box.\n return true;\n}\n\n/**\n * Decide whether an event should be captured.\n * @param event event to be captured\n */\nfunction shouldSkipDOMEvent(eventType: string, target: SentryWrappedTarget | null): boolean {\n // We are only interested in filtering `keypress` events for now.\n if (eventType !== 'keypress') {\n return false;\n }\n\n if (!target || !target.tagName) {\n return true;\n }\n\n // Only consider keypress events on actual input elements. This will disregard keypresses targeting body\n // e.g.tabbing through elements, hotkeys, etc.\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Wraps addEventListener to capture UI breadcrumbs\n */\nfunction makeDOMEventHandler(\n handler: (data: HandlerDataDom) => void,\n globalListener: boolean = false,\n): (event: Event) => void {\n return (event: Event & { _sentryCaptured?: true }): void => {\n // It's possible this handler might trigger multiple times for the same\n // event (e.g. event propagation through node ancestors).\n // Ignore if we've already captured that event.\n if (!event || event['_sentryCaptured']) {\n return;\n }\n\n const target = getEventTarget(event);\n\n // We always want to skip _some_ events.\n if (shouldSkipDOMEvent(event.type, target)) {\n return;\n }\n\n // Mark event as \"seen\"\n addNonEnumerableProperty(event, '_sentryCaptured', true);\n\n if (target && !target._sentryId) {\n // Add UUID to event target so we can identify if\n addNonEnumerableProperty(target, '_sentryId', uuid4());\n }\n\n const name = event.type === 'keypress' ? 'input' : event.type;\n\n // If there is no last captured event, it means that we can safely capture the new event and store it for future comparisons.\n // If there is a last captured event, see if the new event is different enough to treat it as a unique one.\n // If that's the case, emit the previous event and store locally the newly-captured DOM event.\n if (!isSimilarToLastCapturedEvent(event)) {\n const handlerData: HandlerDataDom = { event, name, global: globalListener };\n handler(handlerData);\n lastCapturedEventType = event.type;\n lastCapturedEventTargetId = target ? target._sentryId : undefined;\n }\n\n // Start a new debounce timer that will prevent us from capturing multiple events that should be grouped together.\n clearTimeout(debounceTimerID);\n debounceTimerID = WINDOW.setTimeout(() => {\n lastCapturedEventTargetId = undefined;\n lastCapturedEventType = undefined;\n }, DEBOUNCE_DURATION);\n };\n}\n\nfunction getEventTarget(event: Event): SentryWrappedTarget | null {\n try {\n return event.target as SentryWrappedTarget | null;\n } catch (e) {\n // just accessing `target` property can throw an exception in some rare circumstances\n // see: https://github.com/getsentry/sentry-javascript/issues/838\n return null;\n }\n}\n","// TODO(v8): Move everything in this file into the browser package. Nothing here is generic and we run risk of leaking browser types into non-browser packages.\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/ban-types */\nimport type { HandlerDataXhr, SentryWrappedXMLHttpRequest, WrappedFunction } from '@sentry/types';\n\nimport { isString } from '../is';\nimport { fill } from '../object';\nimport { GLOBAL_OBJ } from '../worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './_handlers';\n\nconst WINDOW = GLOBAL_OBJ as unknown as Window;\n\nexport const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v3__';\n\n/**\n * Add an instrumentation handler for when an XHR request happens.\n * The handler function is called once when the request starts and once when it ends,\n * which can be identified by checking if it has an `endTimestamp`.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addXhrInstrumentationHandler(handler: (data: HandlerDataXhr) => void): void {\n const type = 'xhr';\n addHandler(type, handler);\n maybeInstrument(type, instrumentXHR);\n}\n\n/** Exported only for tests. */\nexport function instrumentXHR(): void {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (!(WINDOW as any).XMLHttpRequest) {\n return;\n }\n\n const xhrproto = XMLHttpRequest.prototype;\n\n fill(xhrproto, 'open', function (originalOpen: () => void): () => void {\n return function (this: XMLHttpRequest & SentryWrappedXMLHttpRequest, ...args: any[]): void {\n const startTimestamp = Date.now();\n\n // open() should always be called with two or more arguments\n // But to be on the safe side, we actually validate this and bail out if we don't have a method & url\n const method = isString(args[0]) ? args[0].toUpperCase() : undefined;\n const url = parseUrl(args[1]);\n\n if (!method || !url) {\n return originalOpen.apply(this, args);\n }\n\n this[SENTRY_XHR_DATA_KEY] = {\n method,\n url,\n request_headers: {},\n };\n\n // if Sentry key appears in URL, don't capture it as a request\n if (method === 'POST' && url.match(/sentry_key/)) {\n this.__sentry_own_request__ = true;\n }\n\n const onreadystatechangeHandler: () => void = () => {\n // For whatever reason, this is not the same instance here as from the outer method\n const xhrInfo = this[SENTRY_XHR_DATA_KEY];\n\n if (!xhrInfo) {\n return;\n }\n\n if (this.readyState === 4) {\n try {\n // touching statusCode in some platforms throws\n // an exception\n xhrInfo.status_code = this.status;\n } catch (e) {\n /* do nothing */\n }\n\n const handlerData: HandlerDataXhr = {\n args: [method, url],\n endTimestamp: Date.now(),\n startTimestamp,\n xhr: this,\n };\n triggerHandlers('xhr', handlerData);\n }\n };\n\n if ('onreadystatechange' in this && typeof this.onreadystatechange === 'function') {\n fill(this, 'onreadystatechange', function (original: WrappedFunction): Function {\n return function (this: SentryWrappedXMLHttpRequest, ...readyStateArgs: any[]): void {\n onreadystatechangeHandler();\n return original.apply(this, readyStateArgs);\n };\n });\n } else {\n this.addEventListener('readystatechange', onreadystatechangeHandler);\n }\n\n // Intercepting `setRequestHeader` to access the request headers of XHR instance.\n // This will only work for user/library defined headers, not for the default/browser-assigned headers.\n // Request cookies are also unavailable for XHR, as `Cookie` header can't be defined by `setRequestHeader`.\n fill(this, 'setRequestHeader', function (original: WrappedFunction): Function {\n return function (this: SentryWrappedXMLHttpRequest, ...setRequestHeaderArgs: unknown[]): void {\n const [header, value] = setRequestHeaderArgs;\n\n const xhrInfo = this[SENTRY_XHR_DATA_KEY];\n\n if (xhrInfo && isString(header) && isString(value)) {\n xhrInfo.request_headers[header.toLowerCase()] = value;\n }\n\n return original.apply(this, setRequestHeaderArgs);\n };\n });\n\n return originalOpen.apply(this, args);\n };\n });\n\n fill(xhrproto, 'send', function (originalSend: () => void): () => void {\n return function (this: XMLHttpRequest & SentryWrappedXMLHttpRequest, ...args: any[]): void {\n const sentryXhrData = this[SENTRY_XHR_DATA_KEY];\n\n if (!sentryXhrData) {\n return originalSend.apply(this, args);\n }\n\n if (args[0] !== undefined) {\n sentryXhrData.body = args[0];\n }\n\n const handlerData: HandlerDataXhr = {\n args: [sentryXhrData.method, sentryXhrData.url],\n startTimestamp: Date.now(),\n xhr: this,\n };\n triggerHandlers('xhr', handlerData);\n\n return originalSend.apply(this, args);\n };\n });\n}\n\nfunction parseUrl(url: string | unknown): string | undefined {\n if (isString(url)) {\n return url;\n }\n\n try {\n // url can be a string or URL\n // but since URL is not available in IE11, we do not check for it,\n // but simply assume it is an URL and return `toString()` from it (which returns the full URL)\n // If that fails, we just return undefined\n return (url as URL).toString();\n } catch {} // eslint-disable-line no-empty\n\n return undefined;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/ban-types */\nimport type { HandlerDataFetch } from '@sentry/types';\n\nimport { fill } from '../object';\nimport { supportsNativeFetch } from '../supports';\nimport { GLOBAL_OBJ } from '../worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './_handlers';\n\ntype FetchResource = string | { toString(): string } | { url: string };\n\n/**\n * Add an instrumentation handler for when a fetch request happens.\n * The handler function is called once when the request starts and once when it ends,\n * which can be identified by checking if it has an `endTimestamp`.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addFetchInstrumentationHandler(handler: (data: HandlerDataFetch) => void): void {\n const type = 'fetch';\n addHandler(type, handler);\n maybeInstrument(type, instrumentFetch);\n}\n\nfunction instrumentFetch(): void {\n if (!supportsNativeFetch()) {\n return;\n }\n\n fill(GLOBAL_OBJ, 'fetch', function (originalFetch: () => void): () => void {\n return function (...args: any[]): void {\n const { method, url } = parseFetchArgs(args);\n\n const handlerData: HandlerDataFetch = {\n args,\n fetchData: {\n method,\n url,\n },\n startTimestamp: Date.now(),\n };\n\n triggerHandlers('fetch', {\n ...handlerData,\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return originalFetch.apply(GLOBAL_OBJ, args).then(\n (response: Response) => {\n const finishedHandlerData: HandlerDataFetch = {\n ...handlerData,\n endTimestamp: Date.now(),\n response,\n };\n\n triggerHandlers('fetch', finishedHandlerData);\n return response;\n },\n (error: Error) => {\n const erroredHandlerData: HandlerDataFetch = {\n ...handlerData,\n endTimestamp: Date.now(),\n error,\n };\n\n triggerHandlers('fetch', erroredHandlerData);\n // NOTE: If you are a Sentry user, and you are seeing this stack frame,\n // it means the sentry.javascript SDK caught an error invoking your application code.\n // This is expected behavior and NOT indicative of a bug with sentry.javascript.\n throw error;\n },\n );\n };\n });\n}\n\nfunction hasProp(obj: unknown, prop: T): obj is Record {\n return !!obj && typeof obj === 'object' && !!(obj as Record)[prop];\n}\n\nfunction getUrlFromResource(resource: FetchResource): string {\n if (typeof resource === 'string') {\n return resource;\n }\n\n if (!resource) {\n return '';\n }\n\n if (hasProp(resource, 'url')) {\n return resource.url;\n }\n\n if (resource.toString) {\n return resource.toString();\n }\n\n return '';\n}\n\n/**\n * Parses the fetch arguments to find the used Http method and the url of the request.\n * Exported for tests only.\n */\nexport function parseFetchArgs(fetchArgs: unknown[]): { method: string; url: string } {\n if (fetchArgs.length === 0) {\n return { method: 'GET', url: '' };\n }\n\n if (fetchArgs.length === 2) {\n const [url, options] = fetchArgs as [FetchResource, object];\n\n return {\n url: getUrlFromResource(url),\n method: hasProp(options, 'method') ? String(options.method).toUpperCase() : 'GET',\n };\n }\n\n const arg = fetchArgs[0];\n return {\n url: getUrlFromResource(arg as FetchResource),\n method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET',\n };\n}\n","/* eslint-disable deprecation/deprecation */\nimport type { Severity, SeverityLevel } from '@sentry/types';\n\n// Note: Ideally the `SeverityLevel` type would be derived from `validSeverityLevels`, but that would mean either\n//\n// a) moving `validSeverityLevels` to `@sentry/types`,\n// b) moving the`SeverityLevel` type here, or\n// c) importing `validSeverityLevels` from here into `@sentry/types`.\n//\n// Option A would make `@sentry/types` a runtime dependency of `@sentry/utils` (not good), and options B and C would\n// create a circular dependency between `@sentry/types` and `@sentry/utils` (also not good). So a TODO accompanying the\n// type, reminding anyone who changes it to change this list also, will have to do.\n\nexport const validSeverityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug'];\n\n/**\n * Converts a string-based level into a member of the deprecated {@link Severity} enum.\n *\n * @deprecated `severityFromString` is deprecated. Please use `severityLevelFromString` instead.\n *\n * @param level String representation of Severity\n * @returns Severity\n */\nexport function severityFromString(level: Severity | SeverityLevel | string): Severity {\n return severityLevelFromString(level) as Severity;\n}\n\n/**\n * Converts a string-based level into a `SeverityLevel`, normalizing it along the way.\n *\n * @param level String representation of desired `SeverityLevel`.\n * @returns The `SeverityLevel` corresponding to the given string, or 'log' if the string isn't a valid level.\n */\nexport function severityLevelFromString(level: SeverityLevel | string): SeverityLevel {\n return (level === 'warn' ? 'warning' : validSeverityLevels.includes(level) ? level : 'log') as SeverityLevel;\n}\n","type PartialURL = {\n host?: string;\n path?: string;\n protocol?: string;\n relative?: string;\n search?: string;\n hash?: string;\n};\n\n/**\n * Parses string form of URL into an object\n * // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B\n * // intentionally using regex and not href parsing trick because React Native and other\n * // environments where DOM might not be available\n * @returns parsed URL object\n */\nexport function parseUrl(url: string): PartialURL {\n if (!url) {\n return {};\n }\n\n const match = url.match(/^(([^:/?#]+):)?(\\/\\/([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/);\n\n if (!match) {\n return {};\n }\n\n // coerce to undefined values to empty string so we don't get 'undefined'\n const query = match[6] || '';\n const fragment = match[8] || '';\n return {\n host: match[4],\n path: match[5],\n protocol: match[2],\n search: query,\n hash: fragment,\n relative: match[5] + query + fragment, // everything minus origin\n };\n}\n\n/**\n * Strip the query string and fragment off of a given URL or path (if present)\n *\n * @param urlPath Full URL or path, including possible query string and/or fragment\n * @returns URL or path without query string or fragment\n */\nexport function stripUrlQueryAndFragment(urlPath: string): string {\n // eslint-disable-next-line no-useless-escape\n return urlPath.split(/[\\?#]/, 1)[0];\n}\n\n/**\n * Returns number of URL segments of a passed string URL.\n */\nexport function getNumberOfUrlSegments(url: string): number {\n // split at '/' or at '\\/' to split regex urls correctly\n return url.split(/\\\\?\\//).filter(s => s.length > 0 && s !== ',').length;\n}\n\n/**\n * Takes a URL object and returns a sanitized string which is safe to use as span description\n * see: https://develop.sentry.dev/sdk/data-handling/#structuring-data\n */\nexport function getSanitizedUrlString(url: PartialURL): string {\n const { protocol, host, path } = url;\n\n const filteredHost =\n (host &&\n host\n // Always filter out authority\n .replace(/^.*@/, '[filtered]:[filtered]@')\n // Don't show standard :80 (http) and :443 (https) ports to reduce the noise\n // TODO: Use new URL global if it exists\n .replace(/(:80)$/, '')\n .replace(/(:443)$/, '')) ||\n '';\n\n return `${protocol ? `${protocol}://` : ''}${filteredHost}${path}`;\n}\n","/* eslint-disable max-lines */\nimport { addBreadcrumb, convertIntegrationFnToClass, defineIntegration, getClient } from '@sentry/core';\nimport type {\n Client,\n Event as SentryEvent,\n HandlerDataConsole,\n HandlerDataDom,\n HandlerDataFetch,\n HandlerDataHistory,\n HandlerDataXhr,\n Integration,\n IntegrationClass,\n IntegrationFn,\n} from '@sentry/types';\nimport type {\n Breadcrumb,\n FetchBreadcrumbData,\n FetchBreadcrumbHint,\n XhrBreadcrumbData,\n XhrBreadcrumbHint,\n} from '@sentry/types/build/types/breadcrumb';\nimport {\n SENTRY_XHR_DATA_KEY,\n addClickKeypressInstrumentationHandler,\n addConsoleInstrumentationHandler,\n addFetchInstrumentationHandler,\n addHistoryInstrumentationHandler,\n addXhrInstrumentationHandler,\n getComponentName,\n getEventDescription,\n htmlTreeAsString,\n logger,\n parseUrl,\n safeJoin,\n severityLevelFromString,\n} from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\n\ninterface BreadcrumbsOptions {\n console: boolean;\n dom:\n | boolean\n | {\n serializeAttribute?: string | string[];\n maxStringLength?: number;\n };\n fetch: boolean;\n history: boolean;\n sentry: boolean;\n xhr: boolean;\n}\n\n/** maxStringLength gets capped to prevent 100 breadcrumbs exceeding 1MB event payload size */\nconst MAX_ALLOWED_STRING_LENGTH = 1024;\n\nconst INTEGRATION_NAME = 'Breadcrumbs';\n\nconst _breadcrumbsIntegration = ((options: Partial = {}) => {\n const _options = {\n console: true,\n dom: true,\n fetch: true,\n history: true,\n sentry: true,\n xhr: true,\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n // TODO v8: Remove this\n setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function\n setup(client) {\n if (_options.console) {\n addConsoleInstrumentationHandler(_getConsoleBreadcrumbHandler(client));\n }\n if (_options.dom) {\n addClickKeypressInstrumentationHandler(_getDomBreadcrumbHandler(client, _options.dom));\n }\n if (_options.xhr) {\n addXhrInstrumentationHandler(_getXhrBreadcrumbHandler(client));\n }\n if (_options.fetch) {\n addFetchInstrumentationHandler(_getFetchBreadcrumbHandler(client));\n }\n if (_options.history) {\n addHistoryInstrumentationHandler(_getHistoryBreadcrumbHandler(client));\n }\n if (_options.sentry && client.on) {\n client.on('beforeSendEvent', _getSentryBreadcrumbHandler(client));\n }\n },\n };\n}) satisfies IntegrationFn;\n\nexport const breadcrumbsIntegration = defineIntegration(_breadcrumbsIntegration);\n\n/**\n * Default Breadcrumbs instrumentations\n *\n * @deprecated Use `breadcrumbsIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const Breadcrumbs = convertIntegrationFnToClass(INTEGRATION_NAME, breadcrumbsIntegration) as IntegrationClass<\n Integration & { setup: (client: Client) => void }\n> & {\n new (\n options?: Partial<{\n console: boolean;\n dom:\n | boolean\n | {\n serializeAttribute?: string | string[];\n maxStringLength?: number;\n };\n fetch: boolean;\n history: boolean;\n sentry: boolean;\n xhr: boolean;\n }>,\n ): Integration;\n};\n\n/**\n * Adds a breadcrumb for Sentry events or transactions if this option is enabled.\n */\nfunction _getSentryBreadcrumbHandler(client: Client): (event: SentryEvent) => void {\n return function addSentryBreadcrumb(event: SentryEvent): void {\n if (getClient() !== client) {\n return;\n }\n\n addBreadcrumb(\n {\n category: `sentry.${event.type === 'transaction' ? 'transaction' : 'event'}`,\n event_id: event.event_id,\n level: event.level,\n message: getEventDescription(event),\n },\n {\n event,\n },\n );\n };\n}\n\n/**\n * A HOC that creaes a function that creates breadcrumbs from DOM API calls.\n * This is a HOC so that we get access to dom options in the closure.\n */\nfunction _getDomBreadcrumbHandler(\n client: Client,\n dom: BreadcrumbsOptions['dom'],\n): (handlerData: HandlerDataDom) => void {\n return function _innerDomBreadcrumb(handlerData: HandlerDataDom): void {\n if (getClient() !== client) {\n return;\n }\n\n let target;\n let componentName;\n let keyAttrs = typeof dom === 'object' ? dom.serializeAttribute : undefined;\n\n let maxStringLength =\n typeof dom === 'object' && typeof dom.maxStringLength === 'number' ? dom.maxStringLength : undefined;\n if (maxStringLength && maxStringLength > MAX_ALLOWED_STRING_LENGTH) {\n DEBUG_BUILD &&\n logger.warn(\n `\\`dom.maxStringLength\\` cannot exceed ${MAX_ALLOWED_STRING_LENGTH}, but a value of ${maxStringLength} was configured. Sentry will use ${MAX_ALLOWED_STRING_LENGTH} instead.`,\n );\n maxStringLength = MAX_ALLOWED_STRING_LENGTH;\n }\n\n if (typeof keyAttrs === 'string') {\n keyAttrs = [keyAttrs];\n }\n\n // Accessing event.target can throw (see getsentry/raven-js#838, #768)\n try {\n const event = handlerData.event as Event | Node;\n const element = _isEvent(event) ? event.target : event;\n\n target = htmlTreeAsString(element, { keyAttrs, maxStringLength });\n componentName = getComponentName(element);\n } catch (e) {\n target = '';\n }\n\n if (target.length === 0) {\n return;\n }\n\n const breadcrumb: Breadcrumb = {\n category: `ui.${handlerData.name}`,\n message: target,\n };\n\n if (componentName) {\n breadcrumb.data = { 'ui.component_name': componentName };\n }\n\n addBreadcrumb(breadcrumb, {\n event: handlerData.event,\n name: handlerData.name,\n global: handlerData.global,\n });\n };\n}\n\n/**\n * Creates breadcrumbs from console API calls\n */\nfunction _getConsoleBreadcrumbHandler(client: Client): (handlerData: HandlerDataConsole) => void {\n return function _consoleBreadcrumb(handlerData: HandlerDataConsole): void {\n if (getClient() !== client) {\n return;\n }\n\n const breadcrumb = {\n category: 'console',\n data: {\n arguments: handlerData.args,\n logger: 'console',\n },\n level: severityLevelFromString(handlerData.level),\n message: safeJoin(handlerData.args, ' '),\n };\n\n if (handlerData.level === 'assert') {\n if (handlerData.args[0] === false) {\n breadcrumb.message = `Assertion failed: ${safeJoin(handlerData.args.slice(1), ' ') || 'console.assert'}`;\n breadcrumb.data.arguments = handlerData.args.slice(1);\n } else {\n // Don't capture a breadcrumb for passed assertions\n return;\n }\n }\n\n addBreadcrumb(breadcrumb, {\n input: handlerData.args,\n level: handlerData.level,\n });\n };\n}\n\n/**\n * Creates breadcrumbs from XHR API calls\n */\nfunction _getXhrBreadcrumbHandler(client: Client): (handlerData: HandlerDataXhr) => void {\n return function _xhrBreadcrumb(handlerData: HandlerDataXhr): void {\n if (getClient() !== client) {\n return;\n }\n\n const { startTimestamp, endTimestamp } = handlerData;\n\n const sentryXhrData = handlerData.xhr[SENTRY_XHR_DATA_KEY];\n\n // We only capture complete, non-sentry requests\n if (!startTimestamp || !endTimestamp || !sentryXhrData) {\n return;\n }\n\n const { method, url, status_code, body } = sentryXhrData;\n\n const data: XhrBreadcrumbData = {\n method,\n url,\n status_code,\n };\n\n const hint: XhrBreadcrumbHint = {\n xhr: handlerData.xhr,\n input: body,\n startTimestamp,\n endTimestamp,\n };\n\n addBreadcrumb(\n {\n category: 'xhr',\n data,\n type: 'http',\n },\n hint,\n );\n };\n}\n\n/**\n * Creates breadcrumbs from fetch API calls\n */\nfunction _getFetchBreadcrumbHandler(client: Client): (handlerData: HandlerDataFetch) => void {\n return function _fetchBreadcrumb(handlerData: HandlerDataFetch): void {\n if (getClient() !== client) {\n return;\n }\n\n const { startTimestamp, endTimestamp } = handlerData;\n\n // We only capture complete fetch requests\n if (!endTimestamp) {\n return;\n }\n\n if (handlerData.fetchData.url.match(/sentry_key/) && handlerData.fetchData.method === 'POST') {\n // We will not create breadcrumbs for fetch requests that contain `sentry_key` (internal sentry requests)\n return;\n }\n\n if (handlerData.error) {\n const data: FetchBreadcrumbData = handlerData.fetchData;\n const hint: FetchBreadcrumbHint = {\n data: handlerData.error,\n input: handlerData.args,\n startTimestamp,\n endTimestamp,\n };\n\n addBreadcrumb(\n {\n category: 'fetch',\n data,\n level: 'error',\n type: 'http',\n },\n hint,\n );\n } else {\n const response = handlerData.response as Response | undefined;\n const data: FetchBreadcrumbData = {\n ...handlerData.fetchData,\n status_code: response && response.status,\n };\n const hint: FetchBreadcrumbHint = {\n input: handlerData.args,\n response,\n startTimestamp,\n endTimestamp,\n };\n addBreadcrumb(\n {\n category: 'fetch',\n data,\n type: 'http',\n },\n hint,\n );\n }\n };\n}\n\n/**\n * Creates breadcrumbs from history API calls\n */\nfunction _getHistoryBreadcrumbHandler(client: Client): (handlerData: HandlerDataHistory) => void {\n return function _historyBreadcrumb(handlerData: HandlerDataHistory): void {\n if (getClient() !== client) {\n return;\n }\n\n let from: string | undefined = handlerData.from;\n let to: string | undefined = handlerData.to;\n const parsedLoc = parseUrl(WINDOW.location.href);\n let parsedFrom = from ? parseUrl(from) : undefined;\n const parsedTo = parseUrl(to);\n\n // Initial pushState doesn't provide `from` information\n if (!parsedFrom || !parsedFrom.path) {\n parsedFrom = parsedLoc;\n }\n\n // Use only the path component of the URL if the URL matches the current\n // document (almost all the time when using pushState)\n if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host) {\n to = parsedTo.relative;\n }\n if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host) {\n from = parsedFrom.relative;\n }\n\n addBreadcrumb({\n category: 'navigation',\n data: {\n from,\n to,\n },\n });\n };\n}\n\nfunction _isEvent(event: unknown): event is Event {\n return !!event && !!(event as Record).target;\n}\n","import { convertIntegrationFnToClass, defineIntegration } from '@sentry/core';\nimport type { Event, Exception, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types';\nimport { logger } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../debug-build';\n\nconst INTEGRATION_NAME = 'Dedupe';\n\nconst _dedupeIntegration = (() => {\n let previousEvent: Event | undefined;\n\n return {\n name: INTEGRATION_NAME,\n // TODO v8: Remove this\n setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function\n processEvent(currentEvent) {\n // We want to ignore any non-error type events, e.g. transactions or replays\n // These should never be deduped, and also not be compared against as _previousEvent.\n if (currentEvent.type) {\n return currentEvent;\n }\n\n // Juuust in case something goes wrong\n try {\n if (_shouldDropEvent(currentEvent, previousEvent)) {\n DEBUG_BUILD && logger.warn('Event dropped due to being a duplicate of previously captured event.');\n return null;\n }\n } catch (_oO) {} // eslint-disable-line no-empty\n\n return (previousEvent = currentEvent);\n },\n };\n}) satisfies IntegrationFn;\n\nexport const dedupeIntegration = defineIntegration(_dedupeIntegration);\n\n/**\n * Deduplication filter.\n * @deprecated Use `dedupeIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const Dedupe = convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration) as IntegrationClass<\n Integration & { processEvent: (event: Event) => Event }\n>;\n\nfunction _shouldDropEvent(currentEvent: Event, previousEvent?: Event): boolean {\n if (!previousEvent) {\n return false;\n }\n\n if (_isSameMessageEvent(currentEvent, previousEvent)) {\n return true;\n }\n\n if (_isSameExceptionEvent(currentEvent, previousEvent)) {\n return true;\n }\n\n return false;\n}\n\nfunction _isSameMessageEvent(currentEvent: Event, previousEvent: Event): boolean {\n const currentMessage = currentEvent.message;\n const previousMessage = previousEvent.message;\n\n // If neither event has a message property, they were both exceptions, so bail out\n if (!currentMessage && !previousMessage) {\n return false;\n }\n\n // If only one event has a stacktrace, but not the other one, they are not the same\n if ((currentMessage && !previousMessage) || (!currentMessage && previousMessage)) {\n return false;\n }\n\n if (currentMessage !== previousMessage) {\n return false;\n }\n\n if (!_isSameFingerprint(currentEvent, previousEvent)) {\n return false;\n }\n\n if (!_isSameStacktrace(currentEvent, previousEvent)) {\n return false;\n }\n\n return true;\n}\n\nfunction _isSameExceptionEvent(currentEvent: Event, previousEvent: Event): boolean {\n const previousException = _getExceptionFromEvent(previousEvent);\n const currentException = _getExceptionFromEvent(currentEvent);\n\n if (!previousException || !currentException) {\n return false;\n }\n\n if (previousException.type !== currentException.type || previousException.value !== currentException.value) {\n return false;\n }\n\n if (!_isSameFingerprint(currentEvent, previousEvent)) {\n return false;\n }\n\n if (!_isSameStacktrace(currentEvent, previousEvent)) {\n return false;\n }\n\n return true;\n}\n\nfunction _isSameStacktrace(currentEvent: Event, previousEvent: Event): boolean {\n let currentFrames = _getFramesFromEvent(currentEvent);\n let previousFrames = _getFramesFromEvent(previousEvent);\n\n // If neither event has a stacktrace, they are assumed to be the same\n if (!currentFrames && !previousFrames) {\n return true;\n }\n\n // If only one event has a stacktrace, but not the other one, they are not the same\n if ((currentFrames && !previousFrames) || (!currentFrames && previousFrames)) {\n return false;\n }\n\n currentFrames = currentFrames as StackFrame[];\n previousFrames = previousFrames as StackFrame[];\n\n // If number of frames differ, they are not the same\n if (previousFrames.length !== currentFrames.length) {\n return false;\n }\n\n // Otherwise, compare the two\n for (let i = 0; i < previousFrames.length; i++) {\n const frameA = previousFrames[i];\n const frameB = currentFrames[i];\n\n if (\n frameA.filename !== frameB.filename ||\n frameA.lineno !== frameB.lineno ||\n frameA.colno !== frameB.colno ||\n frameA.function !== frameB.function\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction _isSameFingerprint(currentEvent: Event, previousEvent: Event): boolean {\n let currentFingerprint = currentEvent.fingerprint;\n let previousFingerprint = previousEvent.fingerprint;\n\n // If neither event has a fingerprint, they are assumed to be the same\n if (!currentFingerprint && !previousFingerprint) {\n return true;\n }\n\n // If only one event has a fingerprint, but not the other one, they are not the same\n if ((currentFingerprint && !previousFingerprint) || (!currentFingerprint && previousFingerprint)) {\n return false;\n }\n\n currentFingerprint = currentFingerprint as string[];\n previousFingerprint = previousFingerprint as string[];\n\n // Otherwise, compare the two\n try {\n return !!(currentFingerprint.join('') === previousFingerprint.join(''));\n } catch (_oO) {\n return false;\n }\n}\n\nfunction _getExceptionFromEvent(event: Event): Exception | undefined {\n return event.exception && event.exception.values && event.exception.values[0];\n}\n\nfunction _getFramesFromEvent(event: Event): StackFrame[] | undefined {\n const exception = event.exception;\n\n if (exception) {\n try {\n // @ts-expect-error Object could be undefined\n return exception.values[0].stacktrace.frames;\n } catch (_oO) {\n return undefined;\n }\n }\n return undefined;\n}\n","import type { HandlerDataError } from '@sentry/types';\n\nimport { GLOBAL_OBJ } from '../worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './_handlers';\n\nlet _oldOnErrorHandler: (typeof GLOBAL_OBJ)['onerror'] | null = null;\n\n/**\n * Add an instrumentation handler for when an error is captured by the global error handler.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addGlobalErrorInstrumentationHandler(handler: (data: HandlerDataError) => void): void {\n const type = 'error';\n addHandler(type, handler);\n maybeInstrument(type, instrumentError);\n}\n\nfunction instrumentError(): void {\n _oldOnErrorHandler = GLOBAL_OBJ.onerror;\n\n GLOBAL_OBJ.onerror = function (\n msg: string | object,\n url?: string,\n line?: number,\n column?: number,\n error?: Error,\n ): boolean {\n const handlerData: HandlerDataError = {\n column,\n error,\n line,\n msg,\n url,\n };\n triggerHandlers('error', handlerData);\n\n if (_oldOnErrorHandler && !_oldOnErrorHandler.__SENTRY_LOADER__) {\n // eslint-disable-next-line prefer-rest-params\n return _oldOnErrorHandler.apply(this, arguments);\n }\n\n return false;\n };\n\n GLOBAL_OBJ.onerror.__SENTRY_INSTRUMENTED__ = true;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { HandlerDataUnhandledRejection } from '@sentry/types';\n\nimport { GLOBAL_OBJ } from '../worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './_handlers';\n\nlet _oldOnUnhandledRejectionHandler: (typeof GLOBAL_OBJ)['onunhandledrejection'] | null = null;\n\n/**\n * Add an instrumentation handler for when an unhandled promise rejection is captured.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addGlobalUnhandledRejectionInstrumentationHandler(\n handler: (data: HandlerDataUnhandledRejection) => void,\n): void {\n const type = 'unhandledrejection';\n addHandler(type, handler);\n maybeInstrument(type, instrumentUnhandledRejection);\n}\n\nfunction instrumentUnhandledRejection(): void {\n _oldOnUnhandledRejectionHandler = GLOBAL_OBJ.onunhandledrejection;\n\n GLOBAL_OBJ.onunhandledrejection = function (e: any): boolean {\n const handlerData: HandlerDataUnhandledRejection = e;\n triggerHandlers('unhandledrejection', handlerData);\n\n if (_oldOnUnhandledRejectionHandler && !_oldOnUnhandledRejectionHandler.__SENTRY_LOADER__) {\n // eslint-disable-next-line prefer-rest-params\n return _oldOnUnhandledRejectionHandler.apply(this, arguments);\n }\n\n return true;\n };\n\n GLOBAL_OBJ.onunhandledrejection.__SENTRY_INSTRUMENTED__ = true;\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport { captureEvent, convertIntegrationFnToClass, defineIntegration, getClient } from '@sentry/core';\nimport type {\n Client,\n Event,\n Integration,\n IntegrationClass,\n IntegrationFn,\n Primitive,\n StackParser,\n} from '@sentry/types';\nimport {\n addGlobalErrorInstrumentationHandler,\n addGlobalUnhandledRejectionInstrumentationHandler,\n getLocationHref,\n isErrorEvent,\n isPrimitive,\n isString,\n logger,\n} from '@sentry/utils';\n\nimport type { BrowserClient } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { eventFromUnknownInput } from '../eventbuilder';\nimport { shouldIgnoreOnError } from '../helpers';\n\ntype GlobalHandlersIntegrationsOptionKeys = 'onerror' | 'onunhandledrejection';\n\ntype GlobalHandlersIntegrations = Record;\n\nconst INTEGRATION_NAME = 'GlobalHandlers';\n\nconst _globalHandlersIntegration = ((options: Partial = {}) => {\n const _options = {\n onerror: true,\n onunhandledrejection: true,\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n Error.stackTraceLimit = 50;\n },\n setup(client) {\n if (_options.onerror) {\n _installGlobalOnErrorHandler(client);\n globalHandlerLog('onerror');\n }\n if (_options.onunhandledrejection) {\n _installGlobalOnUnhandledRejectionHandler(client);\n globalHandlerLog('onunhandledrejection');\n }\n },\n };\n}) satisfies IntegrationFn;\n\nexport const globalHandlersIntegration = defineIntegration(_globalHandlersIntegration);\n\n/**\n * Global handlers.\n * @deprecated Use `globalHandlersIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const GlobalHandlers = convertIntegrationFnToClass(\n INTEGRATION_NAME,\n globalHandlersIntegration,\n) as IntegrationClass void }> & {\n new (options?: Partial): Integration;\n};\n\nfunction _installGlobalOnErrorHandler(client: Client): void {\n addGlobalErrorInstrumentationHandler(data => {\n const { stackParser, attachStacktrace } = getOptions();\n\n if (getClient() !== client || shouldIgnoreOnError()) {\n return;\n }\n\n const { msg, url, line, column, error } = data;\n\n const event =\n error === undefined && isString(msg)\n ? _eventFromIncompleteOnError(msg, url, line, column)\n : _enhanceEventWithInitialFrame(\n eventFromUnknownInput(stackParser, error || msg, undefined, attachStacktrace, false),\n url,\n line,\n column,\n );\n\n event.level = 'error';\n\n captureEvent(event, {\n originalException: error,\n mechanism: {\n handled: false,\n type: 'onerror',\n },\n });\n });\n}\n\nfunction _installGlobalOnUnhandledRejectionHandler(client: Client): void {\n addGlobalUnhandledRejectionInstrumentationHandler(e => {\n const { stackParser, attachStacktrace } = getOptions();\n\n if (getClient() !== client || shouldIgnoreOnError()) {\n return;\n }\n\n const error = _getUnhandledRejectionError(e as unknown);\n\n const event = isPrimitive(error)\n ? _eventFromRejectionWithPrimitive(error)\n : eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true);\n\n event.level = 'error';\n\n captureEvent(event, {\n originalException: error,\n mechanism: {\n handled: false,\n type: 'onunhandledrejection',\n },\n });\n });\n}\n\nfunction _getUnhandledRejectionError(error: unknown): unknown {\n if (isPrimitive(error)) {\n return error;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const e = error as any;\n\n // dig the object of the rejection out of known event types\n try {\n // PromiseRejectionEvents store the object of the rejection under 'reason'\n // see https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent\n if ('reason' in e) {\n return e.reason;\n }\n\n // something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents\n // to CustomEvents, moving the `promise` and `reason` attributes of the PRE into\n // the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec\n // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and\n // https://github.com/getsentry/sentry-javascript/issues/2380\n else if ('detail' in e && 'reason' in e.detail) {\n return e.detail.reason;\n }\n } catch {} // eslint-disable-line no-empty\n\n return error;\n}\n\n/**\n * Create an event from a promise rejection where the `reason` is a primitive.\n *\n * @param reason: The `reason` property of the promise rejection\n * @returns An Event object with an appropriate `exception` value\n */\nfunction _eventFromRejectionWithPrimitive(reason: Primitive): Event {\n return {\n exception: {\n values: [\n {\n type: 'UnhandledRejection',\n // String() is needed because the Primitive type includes symbols (which can't be automatically stringified)\n value: `Non-Error promise rejection captured with value: ${String(reason)}`,\n },\n ],\n },\n };\n}\n\n/**\n * This function creates a stack from an old, error-less onerror handler.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction _eventFromIncompleteOnError(msg: any, url: any, line: any, column: any): Event {\n const ERROR_TYPES_RE =\n /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;\n\n // If 'message' is ErrorEvent, get real message from inside\n let message = isErrorEvent(msg) ? msg.message : msg;\n let name = 'Error';\n\n const groups = message.match(ERROR_TYPES_RE);\n if (groups) {\n name = groups[1];\n message = groups[2];\n }\n\n const event = {\n exception: {\n values: [\n {\n type: name,\n value: message,\n },\n ],\n },\n };\n\n return _enhanceEventWithInitialFrame(event, url, line, column);\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction _enhanceEventWithInitialFrame(event: Event, url: any, line: any, column: any): Event {\n // event.exception\n const e = (event.exception = event.exception || {});\n // event.exception.values\n const ev = (e.values = e.values || []);\n // event.exception.values[0]\n const ev0 = (ev[0] = ev[0] || {});\n // event.exception.values[0].stacktrace\n const ev0s = (ev0.stacktrace = ev0.stacktrace || {});\n // event.exception.values[0].stacktrace.frames\n const ev0sf = (ev0s.frames = ev0s.frames || []);\n\n const colno = isNaN(parseInt(column, 10)) ? undefined : column;\n const lineno = isNaN(parseInt(line, 10)) ? undefined : line;\n const filename = isString(url) && url.length > 0 ? url : getLocationHref();\n\n // event.exception.values[0].stacktrace.frames\n if (ev0sf.length === 0) {\n ev0sf.push({\n colno,\n filename,\n function: '?',\n in_app: true,\n lineno,\n });\n }\n\n return event;\n}\n\nfunction globalHandlerLog(type: string): void {\n DEBUG_BUILD && logger.log(`Global Handler attached: ${type}`);\n}\n\nfunction getOptions(): { stackParser: StackParser; attachStacktrace?: boolean } {\n const client = getClient();\n const options = (client && client.getOptions()) || {\n stackParser: () => [],\n attachStacktrace: false,\n };\n return options;\n}\n","import { convertIntegrationFnToClass, defineIntegration } from '@sentry/core';\nimport type { Event, Integration, IntegrationClass, IntegrationFn } from '@sentry/types';\n\nimport { WINDOW } from '../helpers';\n\nconst INTEGRATION_NAME = 'HttpContext';\n\nconst _httpContextIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n // TODO v8: Remove this\n setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function\n preprocessEvent(event) {\n // if none of the information we want exists, don't bother\n if (!WINDOW.navigator && !WINDOW.location && !WINDOW.document) {\n return;\n }\n\n // grab as much info as exists and add it to the event\n const url = (event.request && event.request.url) || (WINDOW.location && WINDOW.location.href);\n const { referrer } = WINDOW.document || {};\n const { userAgent } = WINDOW.navigator || {};\n\n const headers = {\n ...(event.request && event.request.headers),\n ...(referrer && { Referer: referrer }),\n ...(userAgent && { 'User-Agent': userAgent }),\n };\n const request = { ...event.request, ...(url && { url }), headers };\n\n event.request = request;\n },\n };\n}) satisfies IntegrationFn;\n\nexport const httpContextIntegration = defineIntegration(_httpContextIntegration);\n\n/**\n * HttpContext integration collects information about HTTP request headers.\n * @deprecated Use `httpContextIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const HttpContext = convertIntegrationFnToClass(INTEGRATION_NAME, httpContextIntegration) as IntegrationClass<\n Integration & { preprocessEvent: (event: Event) => void }\n>;\n","import type { Event, EventHint, Exception, ExtendedError, StackParser } from '@sentry/types';\n\nimport { isInstanceOf } from './is';\nimport { truncate } from './string';\n\n/**\n * Creates exceptions inside `event.exception.values` for errors that are nested on properties based on the `key` parameter.\n */\nexport function applyAggregateErrorsToEvent(\n exceptionFromErrorImplementation: (stackParser: StackParser, ex: Error) => Exception,\n parser: StackParser,\n maxValueLimit: number = 250,\n key: string,\n limit: number,\n event: Event,\n hint?: EventHint,\n): void {\n if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) {\n return;\n }\n\n // Generally speaking the last item in `event.exception.values` is the exception originating from the original Error\n const originalException: Exception | undefined =\n event.exception.values.length > 0 ? event.exception.values[event.exception.values.length - 1] : undefined;\n\n // We only create exception grouping if there is an exception in the event.\n if (originalException) {\n event.exception.values = truncateAggregateExceptions(\n aggregateExceptionsFromError(\n exceptionFromErrorImplementation,\n parser,\n limit,\n hint.originalException as ExtendedError,\n key,\n event.exception.values,\n originalException,\n 0,\n ),\n maxValueLimit,\n );\n }\n}\n\nfunction aggregateExceptionsFromError(\n exceptionFromErrorImplementation: (stackParser: StackParser, ex: Error) => Exception,\n parser: StackParser,\n limit: number,\n error: ExtendedError,\n key: string,\n prevExceptions: Exception[],\n exception: Exception,\n exceptionId: number,\n): Exception[] {\n if (prevExceptions.length >= limit + 1) {\n return prevExceptions;\n }\n\n let newExceptions = [...prevExceptions];\n\n // Recursively call this function in order to walk down a chain of errors\n if (isInstanceOf(error[key], Error)) {\n applyExceptionGroupFieldsForParentException(exception, exceptionId);\n const newException = exceptionFromErrorImplementation(parser, error[key]);\n const newExceptionId = newExceptions.length;\n applyExceptionGroupFieldsForChildException(newException, key, newExceptionId, exceptionId);\n newExceptions = aggregateExceptionsFromError(\n exceptionFromErrorImplementation,\n parser,\n limit,\n error[key],\n key,\n [newException, ...newExceptions],\n newException,\n newExceptionId,\n );\n }\n\n // This will create exception grouping for AggregateErrors\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError\n if (Array.isArray(error.errors)) {\n error.errors.forEach((childError, i) => {\n if (isInstanceOf(childError, Error)) {\n applyExceptionGroupFieldsForParentException(exception, exceptionId);\n const newException = exceptionFromErrorImplementation(parser, childError);\n const newExceptionId = newExceptions.length;\n applyExceptionGroupFieldsForChildException(newException, `errors[${i}]`, newExceptionId, exceptionId);\n newExceptions = aggregateExceptionsFromError(\n exceptionFromErrorImplementation,\n parser,\n limit,\n childError,\n key,\n [newException, ...newExceptions],\n newException,\n newExceptionId,\n );\n }\n });\n }\n\n return newExceptions;\n}\n\nfunction applyExceptionGroupFieldsForParentException(exception: Exception, exceptionId: number): void {\n // Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default.\n exception.mechanism = exception.mechanism || { type: 'generic', handled: true };\n\n exception.mechanism = {\n ...exception.mechanism,\n ...(exception.type === 'AggregateError' && { is_exception_group: true }),\n exception_id: exceptionId,\n };\n}\n\nfunction applyExceptionGroupFieldsForChildException(\n exception: Exception,\n source: string,\n exceptionId: number,\n parentId: number | undefined,\n): void {\n // Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default.\n exception.mechanism = exception.mechanism || { type: 'generic', handled: true };\n\n exception.mechanism = {\n ...exception.mechanism,\n type: 'chained',\n source,\n exception_id: exceptionId,\n parent_id: parentId,\n };\n}\n\n/**\n * Truncate the message (exception.value) of all exceptions in the event.\n * Because this event processor is ran after `applyClientOptions`,\n * we need to truncate the message of the added exceptions here.\n */\nfunction truncateAggregateExceptions(exceptions: Exception[], maxValueLength: number): Exception[] {\n return exceptions.map(exception => {\n if (exception.value) {\n exception.value = truncate(exception.value, maxValueLength);\n }\n return exception;\n });\n}\n","import { convertIntegrationFnToClass, defineIntegration } from '@sentry/core';\nimport type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn } from '@sentry/types';\nimport { applyAggregateErrorsToEvent } from '@sentry/utils';\nimport { exceptionFromError } from '../eventbuilder';\n\ninterface LinkedErrorsOptions {\n key?: string;\n limit?: number;\n}\n\nconst DEFAULT_KEY = 'cause';\nconst DEFAULT_LIMIT = 5;\n\nconst INTEGRATION_NAME = 'LinkedErrors';\n\nconst _linkedErrorsIntegration = ((options: LinkedErrorsOptions = {}) => {\n const limit = options.limit || DEFAULT_LIMIT;\n const key = options.key || DEFAULT_KEY;\n\n return {\n name: INTEGRATION_NAME,\n // TODO v8: Remove this\n setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function\n preprocessEvent(event, hint, client) {\n const options = client.getOptions();\n\n applyAggregateErrorsToEvent(\n // This differs from the LinkedErrors integration in core by using a different exceptionFromError function\n exceptionFromError,\n options.stackParser,\n options.maxValueLength,\n key,\n limit,\n event,\n hint,\n );\n },\n };\n}) satisfies IntegrationFn;\n\nexport const linkedErrorsIntegration = defineIntegration(_linkedErrorsIntegration);\n\n/**\n * Aggregrate linked errors in an event.\n * @deprecated Use `linkedErrorsIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const LinkedErrors = convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration) as IntegrationClass<\n Integration & { preprocessEvent: (event: Event, hint: EventHint, client: Client) => void }\n> & { new (options?: { key?: string; limit?: number }): Integration };\n","import { convertIntegrationFnToClass, defineIntegration } from '@sentry/core';\nimport type { Integration, IntegrationClass, IntegrationFn, WrappedFunction } from '@sentry/types';\nimport { fill, getFunctionName, getOriginalFunction } from '@sentry/utils';\n\nimport { WINDOW, wrap } from '../helpers';\n\nconst DEFAULT_EVENT_TARGET = [\n 'EventTarget',\n 'Window',\n 'Node',\n 'ApplicationCache',\n 'AudioTrackList',\n 'BroadcastChannel',\n 'ChannelMergerNode',\n 'CryptoOperation',\n 'EventSource',\n 'FileReader',\n 'HTMLUnknownElement',\n 'IDBDatabase',\n 'IDBRequest',\n 'IDBTransaction',\n 'KeyOperation',\n 'MediaController',\n 'MessagePort',\n 'ModalWindow',\n 'Notification',\n 'SVGElementInstance',\n 'Screen',\n 'SharedWorker',\n 'TextTrack',\n 'TextTrackCue',\n 'TextTrackList',\n 'WebSocket',\n 'WebSocketWorker',\n 'Worker',\n 'XMLHttpRequest',\n 'XMLHttpRequestEventTarget',\n 'XMLHttpRequestUpload',\n];\n\nconst INTEGRATION_NAME = 'TryCatch';\n\ntype XMLHttpRequestProp = 'onload' | 'onerror' | 'onprogress' | 'onreadystatechange';\n\ninterface TryCatchOptions {\n setTimeout: boolean;\n setInterval: boolean;\n requestAnimationFrame: boolean;\n XMLHttpRequest: boolean;\n eventTarget: boolean | string[];\n}\n\nconst _browserApiErrorsIntegration = ((options: Partial = {}) => {\n const _options = {\n XMLHttpRequest: true,\n eventTarget: true,\n requestAnimationFrame: true,\n setInterval: true,\n setTimeout: true,\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n // TODO: This currently only works for the first client this is setup\n // We may want to adjust this to check for client etc.\n setupOnce() {\n if (_options.setTimeout) {\n fill(WINDOW, 'setTimeout', _wrapTimeFunction);\n }\n\n if (_options.setInterval) {\n fill(WINDOW, 'setInterval', _wrapTimeFunction);\n }\n\n if (_options.requestAnimationFrame) {\n fill(WINDOW, 'requestAnimationFrame', _wrapRAF);\n }\n\n if (_options.XMLHttpRequest && 'XMLHttpRequest' in WINDOW) {\n fill(XMLHttpRequest.prototype, 'send', _wrapXHR);\n }\n\n const eventTargetOption = _options.eventTarget;\n if (eventTargetOption) {\n const eventTarget = Array.isArray(eventTargetOption) ? eventTargetOption : DEFAULT_EVENT_TARGET;\n eventTarget.forEach(_wrapEventTarget);\n }\n },\n };\n}) satisfies IntegrationFn;\n\nexport const browserApiErrorsIntegration = defineIntegration(_browserApiErrorsIntegration);\n\n/**\n * Wrap timer functions and event targets to catch errors and provide better meta data.\n * @deprecated Use `browserApiErrorsIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const TryCatch = convertIntegrationFnToClass(\n INTEGRATION_NAME,\n browserApiErrorsIntegration,\n) as IntegrationClass & {\n new (options?: {\n setTimeout: boolean;\n setInterval: boolean;\n requestAnimationFrame: boolean;\n XMLHttpRequest: boolean;\n eventTarget: boolean | string[];\n }): Integration;\n};\n\nfunction _wrapTimeFunction(original: () => void): () => number {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return function (this: any, ...args: any[]): number {\n const originalCallback = args[0];\n args[0] = wrap(originalCallback, {\n mechanism: {\n data: { function: getFunctionName(original) },\n handled: false,\n type: 'instrument',\n },\n });\n return original.apply(this, args);\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction _wrapRAF(original: any): (callback: () => void) => any {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return function (this: any, callback: () => void): () => void {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return original.apply(this, [\n wrap(callback, {\n mechanism: {\n data: {\n function: 'requestAnimationFrame',\n handler: getFunctionName(original),\n },\n handled: false,\n type: 'instrument',\n },\n }),\n ]);\n };\n}\n\nfunction _wrapXHR(originalSend: () => void): () => void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return function (this: XMLHttpRequest, ...args: any[]): void {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const xhr = this;\n const xmlHttpRequestProps: XMLHttpRequestProp[] = ['onload', 'onerror', 'onprogress', 'onreadystatechange'];\n\n xmlHttpRequestProps.forEach(prop => {\n if (prop in xhr && typeof xhr[prop] === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n fill(xhr, prop, function (original: WrappedFunction): () => any {\n const wrapOptions = {\n mechanism: {\n data: {\n function: prop,\n handler: getFunctionName(original),\n },\n handled: false,\n type: 'instrument',\n },\n };\n\n // If Instrument integration has been called before TryCatch, get the name of original function\n const originalFunction = getOriginalFunction(original);\n if (originalFunction) {\n wrapOptions.mechanism.data.handler = getFunctionName(originalFunction);\n }\n\n // Otherwise wrap directly\n return wrap(original, wrapOptions);\n });\n }\n });\n\n return originalSend.apply(this, args);\n };\n}\n\nfunction _wrapEventTarget(target: string): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalObject = WINDOW as { [key: string]: any };\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const proto = globalObject[target] && globalObject[target].prototype;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins\n if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {\n return;\n }\n\n fill(proto, 'addEventListener', function (original: VoidFunction,): (\n eventName: string,\n fn: EventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void {\n return function (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this: any,\n eventName: string,\n fn: EventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): (eventName: string, fn: EventListenerObject, capture?: boolean, secure?: boolean) => void {\n try {\n if (typeof fn.handleEvent === 'function') {\n // ESlint disable explanation:\n // First, it is generally safe to call `wrap` with an unbound function. Furthermore, using `.bind()` would\n // introduce a bug here, because bind returns a new function that doesn't have our\n // flags(like __sentry_original__) attached. `wrap` checks for those flags to avoid unnecessary wrapping.\n // Without those flags, every call to addEventListener wraps the function again, causing a memory leak.\n // eslint-disable-next-line @typescript-eslint/unbound-method\n fn.handleEvent = wrap(fn.handleEvent, {\n mechanism: {\n data: {\n function: 'handleEvent',\n handler: getFunctionName(fn),\n target,\n },\n handled: false,\n type: 'instrument',\n },\n });\n }\n } catch (err) {\n // can sometimes get 'Permission denied to access property \"handle Event'\n }\n\n return original.apply(this, [\n eventName,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wrap(fn as any as WrappedFunction, {\n mechanism: {\n data: {\n function: 'addEventListener',\n handler: getFunctionName(fn),\n target,\n },\n handled: false,\n type: 'instrument',\n },\n }),\n options,\n ]);\n };\n });\n\n fill(\n proto,\n 'removeEventListener',\n function (\n originalRemoveEventListener: () => void,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): (this: any, eventName: string, fn: EventListenerObject, options?: boolean | EventListenerOptions) => () => void {\n return function (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this: any,\n eventName: string,\n fn: EventListenerObject,\n options?: boolean | EventListenerOptions,\n ): () => void {\n /**\n * There are 2 possible scenarios here:\n *\n * 1. Someone passes a callback, which was attached prior to Sentry initialization, or by using unmodified\n * method, eg. `document.addEventListener.call(el, name, handler). In this case, we treat this function\n * as a pass-through, and call original `removeEventListener` with it.\n *\n * 2. Someone passes a callback, which was attached after Sentry was initialized, which means that it was using\n * our wrapped version of `addEventListener`, which internally calls `wrap` helper.\n * This helper \"wraps\" whole callback inside a try/catch statement, and attached appropriate metadata to it,\n * in order for us to make a distinction between wrapped/non-wrapped functions possible.\n * If a function was wrapped, it has additional property of `__sentry_wrapped__`, holding the handler.\n *\n * When someone adds a handler prior to initialization, and then do it again, but after,\n * then we have to detach both of them. Otherwise, if we'd detach only wrapped one, it'd be impossible\n * to get rid of the initial handler and it'd stick there forever.\n */\n const wrappedEventHandler = fn as unknown as WrappedFunction;\n try {\n const originalEventHandler = wrappedEventHandler && wrappedEventHandler.__sentry_wrapped__;\n if (originalEventHandler) {\n originalRemoveEventListener.call(this, eventName, originalEventHandler, options);\n }\n } catch (e) {\n // ignore, accessing __sentry_wrapped__ will throw in some Selenium environments\n }\n return originalRemoveEventListener.call(this, eventName, wrappedEventHandler, options);\n };\n },\n );\n}\n","// This was originally forked from https://github.com/csnover/TraceKit, and was largely\n// re - written as part of raven - js.\n//\n// This code was later copied to the JavaScript mono - repo and further modified and\n// refactored over the years.\n\n// Copyright (c) 2013 Onur Can Cakmak onur.cakmak@gmail.com and all TraceKit contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this\n// software and associated documentation files(the 'Software'), to deal in the Software\n// without restriction, including without limitation the rights to use, copy, modify,\n// merge, publish, distribute, sublicense, and / or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to the following\n// conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies\n// or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n// PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nimport type { StackFrame, StackLineParser, StackLineParserFn } from '@sentry/types';\nimport { createStackParser } from '@sentry/utils';\n\n// global reference to slice\nconst UNKNOWN_FUNCTION = '?';\n\nconst OPERA10_PRIORITY = 10;\nconst OPERA11_PRIORITY = 20;\nconst CHROME_PRIORITY = 30;\nconst WINJS_PRIORITY = 40;\nconst GECKO_PRIORITY = 50;\n\nfunction createFrame(filename: string, func: string, lineno?: number, colno?: number): StackFrame {\n const frame: StackFrame = {\n filename,\n function: func,\n in_app: true, // All browser frames are considered in_app\n };\n\n if (lineno !== undefined) {\n frame.lineno = lineno;\n }\n\n if (colno !== undefined) {\n frame.colno = colno;\n }\n\n return frame;\n}\n\n// Chromium based browsers: Chrome, Brave, new Opera, new Edge\nconst chromeRegex =\n /^\\s*at (?:(.+?\\)(?: \\[.+\\])?|.*?) ?\\((?:address at )?)?(?:async )?((?:|[-a-z]+:|.*bundle|\\/)?.*?)(?::(\\d+))?(?::(\\d+))?\\)?\\s*$/i;\nconst chromeEvalRegex = /\\((\\S*)(?::(\\d+))(?::(\\d+))\\)/;\n\n// We cannot call this variable `chrome` because it can conflict with global `chrome` variable in certain environments\n// See: https://github.com/getsentry/sentry-javascript/issues/6880\nconst chromeStackParserFn: StackLineParserFn = line => {\n const parts = chromeRegex.exec(line);\n\n if (parts) {\n const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line\n\n if (isEval) {\n const subMatch = chromeEvalRegex.exec(parts[2]);\n\n if (subMatch) {\n // throw out eval line/column and use top-most line/column number\n parts[2] = subMatch[1]; // url\n parts[3] = subMatch[2]; // line\n parts[4] = subMatch[3]; // column\n }\n }\n\n // Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now\n // would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable)\n const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]);\n\n return createFrame(filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined);\n }\n\n return;\n};\n\nexport const chromeStackLineParser: StackLineParser = [CHROME_PRIORITY, chromeStackParserFn];\n\n// gecko regex: `(?:bundle|\\d+\\.js)`: `bundle` is for react native, `\\d+\\.js` also but specifically for ram bundles because it\n// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js\n// We need this specific case for now because we want no other regex to match.\nconst geckoREgex =\n /^\\s*(.*?)(?:\\((.*?)\\))?(?:^|@)?((?:[-a-z]+)?:\\/.*?|\\[native code\\]|[^@]*(?:bundle|\\d+\\.js)|\\/[\\w\\-. /=]+)(?::(\\d+))?(?::(\\d+))?\\s*$/i;\nconst geckoEvalRegex = /(\\S+) line (\\d+)(?: > eval line \\d+)* > eval/i;\n\nconst gecko: StackLineParserFn = line => {\n const parts = geckoREgex.exec(line);\n\n if (parts) {\n const isEval = parts[3] && parts[3].indexOf(' > eval') > -1;\n if (isEval) {\n const subMatch = geckoEvalRegex.exec(parts[3]);\n\n if (subMatch) {\n // throw out eval line/column and use top-most line number\n parts[1] = parts[1] || 'eval';\n parts[3] = subMatch[1];\n parts[4] = subMatch[2];\n parts[5] = ''; // no column when eval\n }\n }\n\n let filename = parts[3];\n let func = parts[1] || UNKNOWN_FUNCTION;\n [func, filename] = extractSafariExtensionDetails(func, filename);\n\n return createFrame(filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined);\n }\n\n return;\n};\n\nexport const geckoStackLineParser: StackLineParser = [GECKO_PRIORITY, gecko];\n\nconst winjsRegex = /^\\s*at (?:((?:\\[object object\\])?.+) )?\\(?((?:[-a-z]+):.*?):(\\d+)(?::(\\d+))?\\)?\\s*$/i;\n\nconst winjs: StackLineParserFn = line => {\n const parts = winjsRegex.exec(line);\n\n return parts\n ? createFrame(parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined)\n : undefined;\n};\n\nexport const winjsStackLineParser: StackLineParser = [WINJS_PRIORITY, winjs];\n\nconst opera10Regex = / line (\\d+).*script (?:in )?(\\S+)(?:: in function (\\S+))?$/i;\n\nconst opera10: StackLineParserFn = line => {\n const parts = opera10Regex.exec(line);\n return parts ? createFrame(parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined;\n};\n\nexport const opera10StackLineParser: StackLineParser = [OPERA10_PRIORITY, opera10];\n\nconst opera11Regex =\n / line (\\d+), column (\\d+)\\s*(?:in (?:]+)>|([^)]+))\\(.*\\))? in (.*):\\s*$/i;\n\nconst opera11: StackLineParserFn = line => {\n const parts = opera11Regex.exec(line);\n return parts ? createFrame(parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined;\n};\n\nexport const opera11StackLineParser: StackLineParser = [OPERA11_PRIORITY, opera11];\n\nexport const defaultStackLineParsers = [chromeStackLineParser, geckoStackLineParser, winjsStackLineParser];\n\nexport const defaultStackParser = createStackParser(...defaultStackLineParsers);\n\n/**\n * Safari web extensions, starting version unknown, can produce \"frames-only\" stacktraces.\n * What it means, is that instead of format like:\n *\n * Error: wat\n * at function@url:row:col\n * at function@url:row:col\n * at function@url:row:col\n *\n * it produces something like:\n *\n * function@url:row:col\n * function@url:row:col\n * function@url:row:col\n *\n * Because of that, it won't be captured by `chrome` RegExp and will fall into `Gecko` branch.\n * This function is extracted so that we can use it in both places without duplicating the logic.\n * Unfortunately \"just\" changing RegExp is too complicated now and making it pass all tests\n * and fix this case seems like an impossible, or at least way too time-consuming task.\n */\nconst extractSafariExtensionDetails = (func: string, filename: string): [string, string] => {\n const isSafariExtension = func.indexOf('safari-extension') !== -1;\n const isSafariWebExtension = func.indexOf('safari-web-extension') !== -1;\n\n return isSafariExtension || isSafariWebExtension\n ? [\n func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION,\n isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`,\n ]\n : [func, filename];\n};\n","import { SentryError } from './error';\nimport { SyncPromise, rejectedSyncPromise, resolvedSyncPromise } from './syncpromise';\n\nexport interface PromiseBuffer {\n // exposes the internal array so tests can assert on the state of it.\n // XXX: this really should not be public api.\n $: Array>;\n add(taskProducer: () => PromiseLike): PromiseLike;\n drain(timeout?: number): PromiseLike;\n}\n\n/**\n * Creates an new PromiseBuffer object with the specified limit\n * @param limit max number of promises that can be stored in the buffer\n */\nexport function makePromiseBuffer(limit?: number): PromiseBuffer {\n const buffer: Array> = [];\n\n function isReady(): boolean {\n return limit === undefined || buffer.length < limit;\n }\n\n /**\n * Remove a promise from the queue.\n *\n * @param task Can be any PromiseLike\n * @returns Removed promise.\n */\n function remove(task: PromiseLike): PromiseLike {\n return buffer.splice(buffer.indexOf(task), 1)[0];\n }\n\n /**\n * Add a promise (representing an in-flight action) to the queue, and set it to remove itself on fulfillment.\n *\n * @param taskProducer A function producing any PromiseLike; In previous versions this used to be `task:\n * PromiseLike`, but under that model, Promises were instantly created on the call-site and their executor\n * functions therefore ran immediately. Thus, even if the buffer was full, the action still happened. By\n * requiring the promise to be wrapped in a function, we can defer promise creation until after the buffer\n * limit check.\n * @returns The original promise.\n */\n function add(taskProducer: () => PromiseLike): PromiseLike {\n if (!isReady()) {\n return rejectedSyncPromise(new SentryError('Not adding Promise because buffer limit was reached.'));\n }\n\n // start the task and add its promise to the queue\n const task = taskProducer();\n if (buffer.indexOf(task) === -1) {\n buffer.push(task);\n }\n void task\n .then(() => remove(task))\n // Use `then(null, rejectionHandler)` rather than `catch(rejectionHandler)` so that we can use `PromiseLike`\n // rather than `Promise`. `PromiseLike` doesn't have a `.catch` method, making its polyfill smaller. (ES5 didn't\n // have promises, so TS has to polyfill when down-compiling.)\n .then(null, () =>\n remove(task).then(null, () => {\n // We have to add another catch here because `remove()` starts a new promise chain.\n }),\n );\n return task;\n }\n\n /**\n * Wait for all promises in the queue to resolve or for timeout to expire, whichever comes first.\n *\n * @param timeout The time, in ms, after which to resolve to `false` if the queue is still non-empty. Passing `0` (or\n * not passing anything) will make the promise wait as long as it takes for the queue to drain before resolving to\n * `true`.\n * @returns A promise which will resolve to `true` if the queue is already empty or drains before the timeout, and\n * `false` otherwise\n */\n function drain(timeout?: number): PromiseLike {\n return new SyncPromise((resolve, reject) => {\n let counter = buffer.length;\n\n if (!counter) {\n return resolve(true);\n }\n\n // wait for `timeout` ms and then resolve to `false` (if not cancelled first)\n const capturedSetTimeout = setTimeout(() => {\n if (timeout && timeout > 0) {\n resolve(false);\n }\n }, timeout);\n\n // if all promises resolve in time, cancel the timer and resolve to `true`\n buffer.forEach(item => {\n void resolvedSyncPromise(item).then(() => {\n if (!--counter) {\n clearTimeout(capturedSetTimeout);\n resolve(true);\n }\n }, reject);\n });\n });\n }\n\n return {\n $: buffer,\n add,\n drain,\n };\n}\n","import type { DataCategory, TransportMakeRequestResponse } from '@sentry/types';\n\n// Intentionally keeping the key broad, as we don't know for sure what rate limit headers get returned from backend\nexport type RateLimits = Record;\n\nexport const DEFAULT_RETRY_AFTER = 60 * 1000; // 60 seconds\n\n/**\n * Extracts Retry-After value from the request header or returns default value\n * @param header string representation of 'Retry-After' header\n * @param now current unix timestamp\n *\n */\nexport function parseRetryAfterHeader(header: string, now: number = Date.now()): number {\n const headerDelay = parseInt(`${header}`, 10);\n if (!isNaN(headerDelay)) {\n return headerDelay * 1000;\n }\n\n const headerDate = Date.parse(`${header}`);\n if (!isNaN(headerDate)) {\n return headerDate - now;\n }\n\n return DEFAULT_RETRY_AFTER;\n}\n\n/**\n * Gets the time that the given category is disabled until for rate limiting.\n * In case no category-specific limit is set but a general rate limit across all categories is active,\n * that time is returned.\n *\n * @return the time in ms that the category is disabled until or 0 if there's no active rate limit.\n */\nexport function disabledUntil(limits: RateLimits, dataCategory: DataCategory): number {\n return limits[dataCategory] || limits.all || 0;\n}\n\n/**\n * Checks if a category is rate limited\n */\nexport function isRateLimited(limits: RateLimits, dataCategory: DataCategory, now: number = Date.now()): boolean {\n return disabledUntil(limits, dataCategory) > now;\n}\n\n/**\n * Update ratelimits from incoming headers.\n *\n * @return the updated RateLimits object.\n */\nexport function updateRateLimits(\n limits: RateLimits,\n { statusCode, headers }: TransportMakeRequestResponse,\n now: number = Date.now(),\n): RateLimits {\n const updatedRateLimits: RateLimits = {\n ...limits,\n };\n\n // \"The name is case-insensitive.\"\n // https://developer.mozilla.org/en-US/docs/Web/API/Headers/get\n const rateLimitHeader = headers && headers['x-sentry-rate-limits'];\n const retryAfterHeader = headers && headers['retry-after'];\n\n if (rateLimitHeader) {\n /**\n * rate limit headers are of the form\n * ,,..\n * where each is of the form\n * : : : : \n * where\n * is a delay in seconds\n * is the event type(s) (error, transaction, etc) being rate limited and is of the form\n * ;;...\n * is what's being limited (org, project, or key) - ignored by SDK\n * is an arbitrary string like \"org_quota\" - ignored by SDK\n * Semicolon-separated list of metric namespace identifiers. Defines which namespace(s) will be affected.\n * Only present if rate limit applies to the metric_bucket data category.\n */\n for (const limit of rateLimitHeader.trim().split(',')) {\n const [retryAfter, categories, , , namespaces] = limit.split(':', 5);\n const headerDelay = parseInt(retryAfter, 10);\n const delay = (!isNaN(headerDelay) ? headerDelay : 60) * 1000; // 60sec default\n if (!categories) {\n updatedRateLimits.all = now + delay;\n } else {\n for (const category of categories.split(';')) {\n if (category === 'metric_bucket') {\n // namespaces will be present when category === 'metric_bucket'\n if (!namespaces || namespaces.split(';').includes('custom')) {\n updatedRateLimits[category] = now + delay;\n }\n } else {\n updatedRateLimits[category] = now + delay;\n }\n }\n }\n }\n } else if (retryAfterHeader) {\n updatedRateLimits.all = now + parseRetryAfterHeader(retryAfterHeader, now);\n } else if (statusCode === 429) {\n updatedRateLimits.all = now + 60 * 1000;\n }\n\n return updatedRateLimits;\n}\n","import type {\n Envelope,\n EnvelopeItem,\n EnvelopeItemType,\n Event,\n EventDropReason,\n EventItem,\n InternalBaseTransportOptions,\n Transport,\n TransportMakeRequestResponse,\n TransportRequestExecutor,\n} from '@sentry/types';\nimport type { PromiseBuffer, RateLimits } from '@sentry/utils';\nimport {\n SentryError,\n createEnvelope,\n envelopeItemTypeToDataCategory,\n forEachEnvelopeItem,\n isRateLimited,\n logger,\n makePromiseBuffer,\n resolvedSyncPromise,\n serializeEnvelope,\n updateRateLimits,\n} from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../debug-build';\n\nexport const DEFAULT_TRANSPORT_BUFFER_SIZE = 30;\n\n/**\n * Creates an instance of a Sentry `Transport`\n *\n * @param options\n * @param makeRequest\n */\nexport function createTransport(\n options: InternalBaseTransportOptions,\n makeRequest: TransportRequestExecutor,\n buffer: PromiseBuffer = makePromiseBuffer(\n options.bufferSize || DEFAULT_TRANSPORT_BUFFER_SIZE,\n ),\n): Transport {\n let rateLimits: RateLimits = {};\n const flush = (timeout?: number): PromiseLike => buffer.drain(timeout);\n\n function send(envelope: Envelope): PromiseLike {\n const filteredEnvelopeItems: EnvelopeItem[] = [];\n\n // Drop rate limited items from envelope\n forEachEnvelopeItem(envelope, (item, type) => {\n const dataCategory = envelopeItemTypeToDataCategory(type);\n if (isRateLimited(rateLimits, dataCategory)) {\n const event: Event | undefined = getEventForEnvelopeItem(item, type);\n options.recordDroppedEvent('ratelimit_backoff', dataCategory, event);\n } else {\n filteredEnvelopeItems.push(item);\n }\n });\n\n // Skip sending if envelope is empty after filtering out rate limited events\n if (filteredEnvelopeItems.length === 0) {\n return resolvedSyncPromise();\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const filteredEnvelope: Envelope = createEnvelope(envelope[0], filteredEnvelopeItems as any);\n\n // Creates client report for each item in an envelope\n const recordEnvelopeLoss = (reason: EventDropReason): void => {\n forEachEnvelopeItem(filteredEnvelope, (item, type) => {\n const event: Event | undefined = getEventForEnvelopeItem(item, type);\n options.recordDroppedEvent(reason, envelopeItemTypeToDataCategory(type), event);\n });\n };\n\n const requestTask = (): PromiseLike =>\n makeRequest({ body: serializeEnvelope(filteredEnvelope, options.textEncoder) }).then(\n response => {\n // We don't want to throw on NOK responses, but we want to at least log them\n if (response.statusCode !== undefined && (response.statusCode < 200 || response.statusCode >= 300)) {\n DEBUG_BUILD && logger.warn(`Sentry responded with status code ${response.statusCode} to sent event.`);\n }\n\n rateLimits = updateRateLimits(rateLimits, response);\n return response;\n },\n error => {\n recordEnvelopeLoss('network_error');\n throw error;\n },\n );\n\n return buffer.add(requestTask).then(\n result => result,\n error => {\n if (error instanceof SentryError) {\n DEBUG_BUILD && logger.error('Skipped sending event because buffer is full.');\n recordEnvelopeLoss('queue_overflow');\n return resolvedSyncPromise();\n } else {\n throw error;\n }\n },\n );\n }\n\n // We use this to identifify if the transport is the base transport\n // TODO (v8): Remove this again as we'll no longer need it\n send.__sentry__baseTransport__ = true;\n\n return {\n send,\n flush,\n };\n}\n\nfunction getEventForEnvelopeItem(item: Envelope[1][number], type: EnvelopeItemType): Event | undefined {\n if (type !== 'event' && type !== 'transaction') {\n return undefined;\n }\n\n return Array.isArray(item) ? (item as EventItem)[1] : undefined;\n}\n","import { isNativeFetch, logger } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\n\nlet cachedFetchImpl: FetchImpl | undefined = undefined;\n\nexport type FetchImpl = typeof fetch;\n\n/**\n * A special usecase for incorrectly wrapped Fetch APIs in conjunction with ad-blockers.\n * Whenever someone wraps the Fetch API and returns the wrong promise chain,\n * this chain becomes orphaned and there is no possible way to capture it's rejections\n * other than allowing it bubble up to this very handler. eg.\n *\n * const f = window.fetch;\n * window.fetch = function () {\n * const p = f.apply(this, arguments);\n *\n * p.then(function() {\n * console.log('hi.');\n * });\n *\n * return p;\n * }\n *\n * `p.then(function () { ... })` is producing a completely separate promise chain,\n * however, what's returned is `p` - the result of original `fetch` call.\n *\n * This mean, that whenever we use the Fetch API to send our own requests, _and_\n * some ad-blocker blocks it, this orphaned chain will _always_ reject,\n * effectively causing another event to be captured.\n * This makes a whole process become an infinite loop, which we need to somehow\n * deal with, and break it in one way or another.\n *\n * To deal with this issue, we are making sure that we _always_ use the real\n * browser Fetch API, instead of relying on what `window.fetch` exposes.\n * The only downside to this would be missing our own requests as breadcrumbs,\n * but because we are already not doing this, it should be just fine.\n *\n * Possible failed fetch error messages per-browser:\n *\n * Chrome: Failed to fetch\n * Edge: Failed to Fetch\n * Firefox: NetworkError when attempting to fetch resource\n * Safari: resource blocked by content blocker\n */\nexport function getNativeFetchImplementation(): FetchImpl {\n if (cachedFetchImpl) {\n return cachedFetchImpl;\n }\n\n /* eslint-disable @typescript-eslint/unbound-method */\n\n // Fast path to avoid DOM I/O\n if (isNativeFetch(WINDOW.fetch)) {\n return (cachedFetchImpl = WINDOW.fetch.bind(WINDOW));\n }\n\n const document = WINDOW.document;\n let fetchImpl = WINDOW.fetch;\n // eslint-disable-next-line deprecation/deprecation\n if (document && typeof document.createElement === 'function') {\n try {\n const sandbox = document.createElement('iframe');\n sandbox.hidden = true;\n document.head.appendChild(sandbox);\n const contentWindow = sandbox.contentWindow;\n if (contentWindow && contentWindow.fetch) {\n fetchImpl = contentWindow.fetch;\n }\n document.head.removeChild(sandbox);\n } catch (e) {\n DEBUG_BUILD && logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', e);\n }\n }\n\n return (cachedFetchImpl = fetchImpl.bind(WINDOW));\n /* eslint-enable @typescript-eslint/unbound-method */\n}\n\n/** Clears cached fetch impl */\nexport function clearCachedFetchImplementation(): void {\n cachedFetchImpl = undefined;\n}\n","import { createTransport } from '@sentry/core';\nimport type { Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/types';\nimport { rejectedSyncPromise } from '@sentry/utils';\n\nimport type { BrowserTransportOptions } from './types';\nimport type { FetchImpl } from './utils';\nimport { clearCachedFetchImplementation, getNativeFetchImplementation } from './utils';\n\n/**\n * Creates a Transport that uses the Fetch API to send events to Sentry.\n */\nexport function makeFetchTransport(\n options: BrowserTransportOptions,\n nativeFetch: FetchImpl = getNativeFetchImplementation(),\n): Transport {\n let pendingBodySize = 0;\n let pendingCount = 0;\n\n function makeRequest(request: TransportRequest): PromiseLike {\n const requestSize = request.body.length;\n pendingBodySize += requestSize;\n pendingCount++;\n\n const requestOptions: RequestInit = {\n body: request.body,\n method: 'POST',\n referrerPolicy: 'origin',\n headers: options.headers,\n // Outgoing requests are usually cancelled when navigating to a different page, causing a \"TypeError: Failed to\n // fetch\" error and sending a \"network_error\" client-outcome - in Chrome, the request status shows \"(cancelled)\".\n // The `keepalive` flag keeps outgoing requests alive, even when switching pages. We want this since we're\n // frequently sending events right before the user is switching pages (eg. whenfinishing navigation transactions).\n // Gotchas:\n // - `keepalive` isn't supported by Firefox\n // - As per spec (https://fetch.spec.whatwg.org/#http-network-or-cache-fetch):\n // If the sum of contentLength and inflightKeepaliveBytes is greater than 64 kibibytes, then return a network error.\n // We will therefore only activate the flag when we're below that limit.\n // There is also a limit of requests that can be open at the same time, so we also limit this to 15\n // See https://github.com/getsentry/sentry-javascript/pull/7553 for details\n keepalive: pendingBodySize <= 60_000 && pendingCount < 15,\n ...options.fetchOptions,\n };\n\n try {\n return nativeFetch(options.url, requestOptions).then(response => {\n pendingBodySize -= requestSize;\n pendingCount--;\n return {\n statusCode: response.status,\n headers: {\n 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),\n 'retry-after': response.headers.get('Retry-After'),\n },\n };\n });\n } catch (e) {\n clearCachedFetchImplementation();\n pendingBodySize -= requestSize;\n pendingCount--;\n return rejectedSyncPromise(e);\n }\n }\n\n return createTransport(options, makeRequest);\n}\n","import { createTransport } from '@sentry/core';\nimport type { Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/types';\nimport { SyncPromise } from '@sentry/utils';\n\nimport type { BrowserTransportOptions } from './types';\n\n/**\n * The DONE ready state for XmlHttpRequest\n *\n * Defining it here as a constant b/c XMLHttpRequest.DONE is not always defined\n * (e.g. during testing, it is `undefined`)\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState}\n */\nconst XHR_READYSTATE_DONE = 4;\n\n/**\n * Creates a Transport that uses the XMLHttpRequest API to send events to Sentry.\n */\nexport function makeXHRTransport(options: BrowserTransportOptions): Transport {\n function makeRequest(request: TransportRequest): PromiseLike {\n return new SyncPromise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.onerror = reject;\n\n xhr.onreadystatechange = (): void => {\n if (xhr.readyState === XHR_READYSTATE_DONE) {\n resolve({\n statusCode: xhr.status,\n headers: {\n 'x-sentry-rate-limits': xhr.getResponseHeader('X-Sentry-Rate-Limits'),\n 'retry-after': xhr.getResponseHeader('Retry-After'),\n },\n });\n }\n };\n\n xhr.open('POST', options.url);\n\n for (const header in options.headers) {\n if (Object.prototype.hasOwnProperty.call(options.headers, header)) {\n xhr.setRequestHeader(header, options.headers[header]);\n }\n }\n\n xhr.send(request.body);\n });\n }\n\n return createTransport(options, makeRequest);\n}\n","import type { Hub } from '@sentry/core';\nimport { functionToStringIntegration, inboundFiltersIntegration } from '@sentry/core';\nimport {\n captureSession,\n getClient,\n getCurrentHub,\n getIntegrationsToSetup,\n getReportDialogEndpoint,\n initAndBind,\n startSession,\n} from '@sentry/core';\nimport type { Integration, Options, UserFeedback } from '@sentry/types';\nimport {\n addHistoryInstrumentationHandler,\n logger,\n stackParserFromStackParserOptions,\n supportsFetch,\n} from '@sentry/utils';\n\nimport type { BrowserClientOptions, BrowserOptions } from './client';\nimport { BrowserClient } from './client';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { ReportDialogOptions } from './helpers';\nimport { WINDOW, wrap as internalWrap } from './helpers';\nimport { breadcrumbsIntegration } from './integrations/breadcrumbs';\nimport { dedupeIntegration } from './integrations/dedupe';\nimport { globalHandlersIntegration } from './integrations/globalhandlers';\nimport { httpContextIntegration } from './integrations/httpcontext';\nimport { linkedErrorsIntegration } from './integrations/linkederrors';\nimport { browserApiErrorsIntegration } from './integrations/trycatch';\nimport { defaultStackParser } from './stack-parsers';\nimport { makeFetchTransport, makeXHRTransport } from './transports';\n\n/** @deprecated Use `getDefaultIntegrations(options)` instead. */\nexport const defaultIntegrations = [\n inboundFiltersIntegration(),\n functionToStringIntegration(),\n browserApiErrorsIntegration(),\n breadcrumbsIntegration(),\n globalHandlersIntegration(),\n linkedErrorsIntegration(),\n dedupeIntegration(),\n httpContextIntegration(),\n];\n\n/** Get the default integrations for the browser SDK. */\nexport function getDefaultIntegrations(_options: Options): Integration[] {\n // We return a copy of the defaultIntegrations here to avoid mutating this\n return [\n // eslint-disable-next-line deprecation/deprecation\n ...defaultIntegrations,\n ];\n}\n\n/**\n * A magic string that build tooling can leverage in order to inject a release value into the SDK.\n */\ndeclare const __SENTRY_RELEASE__: string | undefined;\n\n/**\n * The Sentry Browser SDK Client.\n *\n * To use this SDK, call the {@link init} function as early as possible when\n * loading the web page. To set context information or send manual events, use\n * the provided methods.\n *\n * @example\n *\n * ```\n *\n * import { init } from '@sentry/browser';\n *\n * init({\n * dsn: '__DSN__',\n * // ...\n * });\n * ```\n *\n * @example\n * ```\n *\n * import { configureScope } from '@sentry/browser';\n * configureScope((scope: Scope) => {\n * scope.setExtra({ battery: 0.7 });\n * scope.setTag({ user_mode: 'admin' });\n * scope.setUser({ id: '4711' });\n * });\n * ```\n *\n * @example\n * ```\n *\n * import { addBreadcrumb } from '@sentry/browser';\n * addBreadcrumb({\n * message: 'My Breadcrumb',\n * // ...\n * });\n * ```\n *\n * @example\n *\n * ```\n *\n * import * as Sentry from '@sentry/browser';\n * Sentry.captureMessage('Hello, world!');\n * Sentry.captureException(new Error('Good bye'));\n * Sentry.captureEvent({\n * message: 'Manual',\n * stacktrace: [\n * // ...\n * ],\n * });\n * ```\n *\n * @see {@link BrowserOptions} for documentation on configuration options.\n */\nexport function init(options: BrowserOptions = {}): void {\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n if (options.release === undefined) {\n // This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value\n if (typeof __SENTRY_RELEASE__ === 'string') {\n options.release = __SENTRY_RELEASE__;\n }\n\n // This supports the variable that sentry-webpack-plugin injects\n if (WINDOW.SENTRY_RELEASE && WINDOW.SENTRY_RELEASE.id) {\n options.release = WINDOW.SENTRY_RELEASE.id;\n }\n }\n if (options.autoSessionTracking === undefined) {\n options.autoSessionTracking = true;\n }\n if (options.sendClientReports === undefined) {\n options.sendClientReports = true;\n }\n\n const clientOptions: BrowserClientOptions = {\n ...options,\n stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),\n integrations: getIntegrationsToSetup(options),\n transport: options.transport || (supportsFetch() ? makeFetchTransport : makeXHRTransport),\n };\n\n initAndBind(BrowserClient, clientOptions);\n\n if (options.autoSessionTracking) {\n startSessionTracking();\n }\n}\n\ntype NewReportDialogOptions = ReportDialogOptions & { eventId: string }; // eslint-disable-line\n\ninterface ShowReportDialogFunction {\n /**\n * Present the user with a report dialog.\n *\n * @param options Everything is optional, we try to fetch all info need from the global scope.\n */\n (options: NewReportDialogOptions): void;\n\n /**\n * Present the user with a report dialog.\n *\n * @param options Everything is optional, we try to fetch all info need from the global scope.\n *\n * @deprecated Please always pass an `options` argument with `eventId`. The `hub` argument will not be used in the next version of the SDK.\n */\n // eslint-disable-next-line deprecation/deprecation\n (options?: ReportDialogOptions, hub?: Hub): void;\n}\n\nexport const showReportDialog: ShowReportDialogFunction = (\n // eslint-disable-next-line deprecation/deprecation\n options: ReportDialogOptions = {},\n // eslint-disable-next-line deprecation/deprecation\n hub: Hub = getCurrentHub(),\n) => {\n // doesn't work without a document (React Native)\n if (!WINDOW.document) {\n DEBUG_BUILD && logger.error('Global document not defined in showReportDialog call');\n return;\n }\n\n // eslint-disable-next-line deprecation/deprecation\n const { client, scope } = hub.getStackTop();\n const dsn = options.dsn || (client && client.getDsn());\n if (!dsn) {\n DEBUG_BUILD && logger.error('DSN not configured for showReportDialog call');\n return;\n }\n\n if (scope) {\n options.user = {\n ...scope.getUser(),\n ...options.user,\n };\n }\n\n if (!options.eventId) {\n // eslint-disable-next-line deprecation/deprecation\n options.eventId = hub.lastEventId();\n }\n\n const script = WINDOW.document.createElement('script');\n script.async = true;\n script.crossOrigin = 'anonymous';\n script.src = getReportDialogEndpoint(dsn, options);\n\n if (options.onLoad) {\n script.onload = options.onLoad;\n }\n\n const { onClose } = options;\n if (onClose) {\n const reportDialogClosedMessageHandler = (event: MessageEvent): void => {\n if (event.data === '__sentry_reportdialog_closed__') {\n try {\n onClose();\n } finally {\n WINDOW.removeEventListener('message', reportDialogClosedMessageHandler);\n }\n }\n };\n WINDOW.addEventListener('message', reportDialogClosedMessageHandler);\n }\n\n const injectionPoint = WINDOW.document.head || WINDOW.document.body;\n if (injectionPoint) {\n injectionPoint.appendChild(script);\n } else {\n DEBUG_BUILD && logger.error('Not injecting report dialog. No injection point found in HTML');\n }\n};\n\n/**\n * This function is here to be API compatible with the loader.\n * @hidden\n */\nexport function forceLoad(): void {\n // Noop\n}\n\n/**\n * This function is here to be API compatible with the loader.\n * @hidden\n */\nexport function onLoad(callback: () => void): void {\n callback();\n}\n\n/**\n * Wrap code within a try/catch block so the SDK is able to capture errors.\n *\n * @deprecated This function will be removed in v8.\n * It is not part of Sentry's official API and it's easily replaceable by using a try/catch block\n * and calling Sentry.captureException.\n *\n * @param fn A function to wrap.\n *\n * @returns The result of wrapped function call.\n */\n// TODO(v8): Remove this function\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function wrap(fn: (...args: any) => any): any {\n return internalWrap(fn)();\n}\n\n/**\n * Enable automatic Session Tracking for the initial page load.\n */\nfunction startSessionTracking(): void {\n if (typeof WINDOW.document === 'undefined') {\n DEBUG_BUILD && logger.warn('Session tracking in non-browser environment with @sentry/browser is not supported.');\n return;\n }\n\n // The session duration for browser sessions does not track a meaningful\n // concept that can be used as a metric.\n // Automatically captured sessions are akin to page views, and thus we\n // discard their duration.\n startSession({ ignoreDuration: true });\n captureSession();\n\n // We want to create a session for every navigation as well\n addHistoryInstrumentationHandler(({ from, to }) => {\n // Don't create an additional session for the initial route or if the location did not change\n if (from !== undefined && from !== to) {\n startSession({ ignoreDuration: true });\n captureSession();\n }\n });\n}\n\n/**\n * Captures user feedback and sends it to Sentry.\n */\nexport function captureUserFeedback(feedback: UserFeedback): void {\n const client = getClient();\n if (client) {\n client.captureUserFeedback(feedback);\n }\n}\n","import type { MeasurementUnit, Span } from '@sentry/types';\nimport type { MetricSummary } from '@sentry/types';\nimport type { Primitive } from '@sentry/types';\nimport { dropUndefinedKeys } from '@sentry/utils';\nimport { getActiveSpan } from '../tracing';\nimport type { MetricType } from './types';\n\n/**\n * key: bucketKey\n * value: [exportKey, MetricSummary]\n */\ntype MetricSummaryStorage = Map;\n\nlet SPAN_METRIC_SUMMARY: WeakMap | undefined;\n\nfunction getMetricStorageForSpan(span: Span): MetricSummaryStorage | undefined {\n return SPAN_METRIC_SUMMARY ? SPAN_METRIC_SUMMARY.get(span) : undefined;\n}\n\n/**\n * Fetches the metric summary if it exists for the passed span\n */\nexport function getMetricSummaryJsonForSpan(span: Span): Record> | undefined {\n const storage = getMetricStorageForSpan(span);\n\n if (!storage) {\n return undefined;\n }\n const output: Record> = {};\n\n for (const [, [exportKey, summary]] of storage) {\n if (!output[exportKey]) {\n output[exportKey] = [];\n }\n\n output[exportKey].push(dropUndefinedKeys(summary));\n }\n\n return output;\n}\n\n/**\n * Updates the metric summary on the currently active span\n */\nexport function updateMetricSummaryOnActiveSpan(\n metricType: MetricType,\n sanitizedName: string,\n value: number,\n unit: MeasurementUnit,\n tags: Record,\n bucketKey: string,\n): void {\n const span = getActiveSpan();\n if (span) {\n const storage = getMetricStorageForSpan(span) || new Map();\n\n const exportKey = `${metricType}:${sanitizedName}@${unit}`;\n const bucketItem = storage.get(bucketKey);\n\n if (bucketItem) {\n const [, summary] = bucketItem;\n storage.set(bucketKey, [\n exportKey,\n {\n min: Math.min(summary.min, value),\n max: Math.max(summary.max, value),\n count: (summary.count += 1),\n sum: (summary.sum += value),\n tags: summary.tags,\n },\n ]);\n } else {\n storage.set(bucketKey, [\n exportKey,\n {\n min: value,\n max: value,\n count: 1,\n sum: value,\n tags,\n },\n ]);\n }\n\n if (!SPAN_METRIC_SUMMARY) {\n SPAN_METRIC_SUMMARY = new WeakMap();\n }\n\n SPAN_METRIC_SUMMARY.set(span, storage);\n }\n}\n","/**\n * Use this attribute to represent the source of a span.\n * Should be one of: custom, url, route, view, component, task, unknown\n *\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = 'sentry.source';\n\n/**\n * Use this attribute to represent the sample rate used for a span.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = 'sentry.sample_rate';\n\n/**\n * Use this attribute to represent the operation of a span.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_OP = 'sentry.op';\n\n/**\n * Use this attribute to represent the origin of a span.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = 'sentry.origin';\n\n/**\n * The id of the profile that this span occured in.\n */\nexport const SEMANTIC_ATTRIBUTE_PROFILE_ID = 'profile_id';\n","import type { Span } from '@sentry/types';\n\n/** The status of an Span.\n *\n * @deprecated Use string literals - if you require type casting, cast to SpanStatusType type\n */\nexport enum SpanStatus {\n /** The operation completed successfully. */\n Ok = 'ok',\n /** Deadline expired before operation could complete. */\n DeadlineExceeded = 'deadline_exceeded',\n /** 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) */\n Unauthenticated = 'unauthenticated',\n /** 403 Forbidden */\n PermissionDenied = 'permission_denied',\n /** 404 Not Found. Some requested entity (file or directory) was not found. */\n NotFound = 'not_found',\n /** 429 Too Many Requests */\n ResourceExhausted = 'resource_exhausted',\n /** Client specified an invalid argument. 4xx. */\n InvalidArgument = 'invalid_argument',\n /** 501 Not Implemented */\n Unimplemented = 'unimplemented',\n /** 503 Service Unavailable */\n Unavailable = 'unavailable',\n /** Other/generic 5xx. */\n InternalError = 'internal_error',\n /** Unknown. Any non-standard HTTP status code. */\n UnknownError = 'unknown_error',\n /** The operation was cancelled (typically by the user). */\n Cancelled = 'cancelled',\n /** Already exists (409) */\n AlreadyExists = 'already_exists',\n /** Operation was rejected because the system is not in a state required for the operation's */\n FailedPrecondition = 'failed_precondition',\n /** The operation was aborted, typically due to a concurrency issue. */\n Aborted = 'aborted',\n /** Operation was attempted past the valid range. */\n OutOfRange = 'out_of_range',\n /** Unrecoverable data loss or corruption */\n DataLoss = 'data_loss',\n}\n\nexport type SpanStatusType =\n /** The operation completed successfully. */\n | 'ok'\n /** Deadline expired before operation could complete. */\n | 'deadline_exceeded'\n /** 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) */\n | 'unauthenticated'\n /** 403 Forbidden */\n | 'permission_denied'\n /** 404 Not Found. Some requested entity (file or directory) was not found. */\n | 'not_found'\n /** 429 Too Many Requests */\n | 'resource_exhausted'\n /** Client specified an invalid argument. 4xx. */\n | 'invalid_argument'\n /** 501 Not Implemented */\n | 'unimplemented'\n /** 503 Service Unavailable */\n | 'unavailable'\n /** Other/generic 5xx. */\n | 'internal_error'\n /** Unknown. Any non-standard HTTP status code. */\n | 'unknown_error'\n /** The operation was cancelled (typically by the user). */\n | 'cancelled'\n /** Already exists (409) */\n | 'already_exists'\n /** Operation was rejected because the system is not in a state required for the operation's */\n | 'failed_precondition'\n /** The operation was aborted, typically due to a concurrency issue. */\n | 'aborted'\n /** Operation was attempted past the valid range. */\n | 'out_of_range'\n /** Unrecoverable data loss or corruption */\n | 'data_loss';\n\n/**\n * Converts a HTTP status code into a {@link SpanStatusType}.\n *\n * @param httpStatus The HTTP response status code.\n * @returns The span status or unknown_error.\n */\nexport function getSpanStatusFromHttpCode(httpStatus: number): SpanStatusType {\n if (httpStatus < 400 && httpStatus >= 100) {\n return 'ok';\n }\n\n if (httpStatus >= 400 && httpStatus < 500) {\n switch (httpStatus) {\n case 401:\n return 'unauthenticated';\n case 403:\n return 'permission_denied';\n case 404:\n return 'not_found';\n case 409:\n return 'already_exists';\n case 413:\n return 'failed_precondition';\n case 429:\n return 'resource_exhausted';\n default:\n return 'invalid_argument';\n }\n }\n\n if (httpStatus >= 500 && httpStatus < 600) {\n switch (httpStatus) {\n case 501:\n return 'unimplemented';\n case 503:\n return 'unavailable';\n case 504:\n return 'deadline_exceeded';\n default:\n return 'internal_error';\n }\n }\n\n return 'unknown_error';\n}\n\n/**\n * Converts a HTTP status code into a {@link SpanStatusType}.\n *\n * @deprecated Use {@link spanStatusFromHttpCode} instead.\n * This export will be removed in v8 as the signature contains a typo.\n *\n * @param httpStatus The HTTP response status code.\n * @returns The span status or unknown_error.\n */\nexport const spanStatusfromHttpCode = getSpanStatusFromHttpCode;\n\n/**\n * Sets the Http status attributes on the current span based on the http code.\n * Additionally, the span's status is updated, depending on the http code.\n */\nexport function setHttpStatus(span: Span, httpStatus: number): void {\n // TODO (v8): Remove these calls\n // Relay does not require us to send the status code as a tag\n // For now, just because users might expect it to land as a tag we keep sending it.\n // Same with data.\n // In v8, we replace both, simply with\n // span.setAttribute('http.response.status_code', httpStatus);\n\n // eslint-disable-next-line deprecation/deprecation\n span.setTag('http.status_code', String(httpStatus));\n // eslint-disable-next-line deprecation/deprecation\n span.setData('http.response.status_code', httpStatus);\n\n const spanStatus = getSpanStatusFromHttpCode(httpStatus);\n if (spanStatus !== 'unknown_error') {\n span.setStatus(spanStatus);\n }\n}\n","/* eslint-disable max-lines */\nimport type {\n Instrumenter,\n Measurements,\n Primitive,\n Span as SpanInterface,\n SpanAttributeValue,\n SpanAttributes,\n SpanContext,\n SpanContextData,\n SpanJSON,\n SpanOrigin,\n SpanTimeInput,\n TraceContext,\n Transaction,\n} from '@sentry/types';\nimport { dropUndefinedKeys, logger, timestampInSeconds, uuid4 } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { getMetricSummaryJsonForSpan } from '../metrics/metric-summary';\nimport {\n SEMANTIC_ATTRIBUTE_PROFILE_ID,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n} from '../semanticAttributes';\nimport { getRootSpan } from '../utils/getRootSpan';\nimport {\n TRACE_FLAG_NONE,\n TRACE_FLAG_SAMPLED,\n spanTimeInputToSeconds,\n spanToJSON,\n spanToTraceContext,\n spanToTraceHeader,\n} from '../utils/spanUtils';\nimport type { SpanStatusType } from './spanstatus';\nimport { setHttpStatus } from './spanstatus';\n\n/**\n * Keeps track of finished spans for a given transaction\n * @internal\n * @hideconstructor\n * @hidden\n */\nexport class SpanRecorder {\n public spans: Span[];\n\n private readonly _maxlen: number;\n\n public constructor(maxlen: number = 1000) {\n this._maxlen = maxlen;\n this.spans = [];\n }\n\n /**\n * This is just so that we don't run out of memory while recording a lot\n * of spans. At some point we just stop and flush out the start of the\n * trace tree (i.e.the first n spans with the smallest\n * start_timestamp).\n */\n public add(span: Span): void {\n if (this.spans.length > this._maxlen) {\n // eslint-disable-next-line deprecation/deprecation\n span.spanRecorder = undefined;\n } else {\n this.spans.push(span);\n }\n }\n}\n\n/**\n * Span contains all data about a span\n */\nexport class Span implements SpanInterface {\n /**\n * Tags for the span.\n * @deprecated Use `spanToJSON(span).atttributes` instead.\n */\n public tags: { [key: string]: Primitive };\n\n /**\n * Data for the span.\n * @deprecated Use `spanToJSON(span).atttributes` instead.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public data: { [key: string]: any };\n\n /**\n * List of spans that were finalized\n *\n * @deprecated This property will no longer be public. Span recording will be handled internally.\n */\n public spanRecorder?: SpanRecorder;\n\n /**\n * @inheritDoc\n * @deprecated Use top level `Sentry.getRootSpan()` instead\n */\n public transaction?: Transaction;\n\n /**\n * The instrumenter that created this span.\n *\n * TODO (v8): This can probably be replaced by an `instanceOf` check of the span class.\n * the instrumenter can only be sentry or otel so we can check the span instance\n * to verify which one it is and remove this field entirely.\n *\n * @deprecated This field will be removed.\n */\n public instrumenter: Instrumenter;\n\n protected _traceId: string;\n protected _spanId: string;\n protected _parentSpanId?: string | undefined;\n protected _sampled: boolean | undefined;\n protected _name?: string | undefined;\n protected _attributes: SpanAttributes;\n /** Epoch timestamp in seconds when the span started. */\n protected _startTime: number;\n /** Epoch timestamp in seconds when the span ended. */\n protected _endTime?: number | undefined;\n /** Internal keeper of the status */\n protected _status?: SpanStatusType | string | undefined;\n protected _exclusiveTime?: number;\n\n protected _measurements: Measurements;\n\n private _logMessage?: string;\n\n /**\n * You should never call the constructor manually, always use `Sentry.startTransaction()`\n * or call `startChild()` on an existing span.\n * @internal\n * @hideconstructor\n * @hidden\n */\n public constructor(spanContext: SpanContext = {}) {\n this._traceId = spanContext.traceId || uuid4();\n this._spanId = spanContext.spanId || uuid4().substring(16);\n this._startTime = spanContext.startTimestamp || timestampInSeconds();\n // eslint-disable-next-line deprecation/deprecation\n this.tags = spanContext.tags ? { ...spanContext.tags } : {};\n // eslint-disable-next-line deprecation/deprecation\n this.data = spanContext.data ? { ...spanContext.data } : {};\n // eslint-disable-next-line deprecation/deprecation\n this.instrumenter = spanContext.instrumenter || 'sentry';\n\n this._attributes = {};\n this.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanContext.origin || 'manual',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: spanContext.op,\n ...spanContext.attributes,\n });\n\n // eslint-disable-next-line deprecation/deprecation\n this._name = spanContext.name || spanContext.description;\n\n if (spanContext.parentSpanId) {\n this._parentSpanId = spanContext.parentSpanId;\n }\n // We want to include booleans as well here\n if ('sampled' in spanContext) {\n this._sampled = spanContext.sampled;\n }\n if (spanContext.status) {\n this._status = spanContext.status;\n }\n if (spanContext.endTimestamp) {\n this._endTime = spanContext.endTimestamp;\n }\n if (spanContext.exclusiveTime !== undefined) {\n this._exclusiveTime = spanContext.exclusiveTime;\n }\n this._measurements = spanContext.measurements ? { ...spanContext.measurements } : {};\n }\n\n // This rule conflicts with another eslint rule :(\n /* eslint-disable @typescript-eslint/member-ordering */\n\n /**\n * An alias for `description` of the Span.\n * @deprecated Use `spanToJSON(span).description` instead.\n */\n public get name(): string {\n return this._name || '';\n }\n\n /**\n * Update the name of the span.\n * @deprecated Use `spanToJSON(span).description` instead.\n */\n public set name(name: string) {\n this.updateName(name);\n }\n\n /**\n * Get the description of the Span.\n * @deprecated Use `spanToJSON(span).description` instead.\n */\n public get description(): string | undefined {\n return this._name;\n }\n\n /**\n * Get the description of the Span.\n * @deprecated Use `spanToJSON(span).description` instead.\n */\n public set description(description: string | undefined) {\n this._name = description;\n }\n\n /**\n * The ID of the trace.\n * @deprecated Use `spanContext().traceId` instead.\n */\n public get traceId(): string {\n return this._traceId;\n }\n\n /**\n * The ID of the trace.\n * @deprecated You cannot update the traceId of a span after span creation.\n */\n public set traceId(traceId: string) {\n this._traceId = traceId;\n }\n\n /**\n * The ID of the span.\n * @deprecated Use `spanContext().spanId` instead.\n */\n public get spanId(): string {\n return this._spanId;\n }\n\n /**\n * The ID of the span.\n * @deprecated You cannot update the spanId of a span after span creation.\n */\n public set spanId(spanId: string) {\n this._spanId = spanId;\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Use `startSpan` functions instead.\n */\n public set parentSpanId(string) {\n this._parentSpanId = string;\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Use `spanToJSON(span).parent_span_id` instead.\n */\n public get parentSpanId(): string | undefined {\n return this._parentSpanId;\n }\n\n /**\n * Was this span chosen to be sent as part of the sample?\n * @deprecated Use `isRecording()` instead.\n */\n public get sampled(): boolean | undefined {\n return this._sampled;\n }\n\n /**\n * Was this span chosen to be sent as part of the sample?\n * @deprecated You cannot update the sampling decision of a span after span creation.\n */\n public set sampled(sampled: boolean | undefined) {\n this._sampled = sampled;\n }\n\n /**\n * Attributes for the span.\n * @deprecated Use `spanToJSON(span).atttributes` instead.\n */\n public get attributes(): SpanAttributes {\n return this._attributes;\n }\n\n /**\n * Attributes for the span.\n * @deprecated Use `setAttributes()` instead.\n */\n public set attributes(attributes: SpanAttributes) {\n this._attributes = attributes;\n }\n\n /**\n * Timestamp in seconds (epoch time) indicating when the span started.\n * @deprecated Use `spanToJSON()` instead.\n */\n public get startTimestamp(): number {\n return this._startTime;\n }\n\n /**\n * Timestamp in seconds (epoch time) indicating when the span started.\n * @deprecated In v8, you will not be able to update the span start time after creation.\n */\n public set startTimestamp(startTime: number) {\n this._startTime = startTime;\n }\n\n /**\n * Timestamp in seconds when the span ended.\n * @deprecated Use `spanToJSON()` instead.\n */\n public get endTimestamp(): number | undefined {\n return this._endTime;\n }\n\n /**\n * Timestamp in seconds when the span ended.\n * @deprecated Set the end time via `span.end()` instead.\n */\n public set endTimestamp(endTime: number | undefined) {\n this._endTime = endTime;\n }\n\n /**\n * The status of the span.\n *\n * @deprecated Use `spanToJSON().status` instead to get the status.\n */\n public get status(): SpanStatusType | string | undefined {\n return this._status;\n }\n\n /**\n * The status of the span.\n *\n * @deprecated Use `.setStatus()` instead to set or update the status.\n */\n public set status(status: SpanStatusType | string | undefined) {\n this._status = status;\n }\n\n /**\n * Operation of the span\n *\n * @deprecated Use `spanToJSON().op` to read the op instead.\n */\n public get op(): string | undefined {\n return this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] as string | undefined;\n }\n\n /**\n * Operation of the span\n *\n * @deprecated Use `startSpan()` functions to set or `span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'op')\n * to update the span instead.\n */\n public set op(op: string | undefined) {\n this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, op);\n }\n\n /**\n * The origin of the span, giving context about what created the span.\n *\n * @deprecated Use `spanToJSON().origin` to read the origin instead.\n */\n public get origin(): SpanOrigin | undefined {\n return this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined;\n }\n\n /**\n * The origin of the span, giving context about what created the span.\n *\n * @deprecated Use `startSpan()` functions to set the origin instead.\n */\n public set origin(origin: SpanOrigin | undefined) {\n this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, origin);\n }\n\n /* eslint-enable @typescript-eslint/member-ordering */\n\n /** @inheritdoc */\n public spanContext(): SpanContextData {\n const { _spanId: spanId, _traceId: traceId, _sampled: sampled } = this;\n return {\n spanId,\n traceId,\n traceFlags: sampled ? TRACE_FLAG_SAMPLED : TRACE_FLAG_NONE,\n };\n }\n\n /**\n * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`.\n * Also the `sampled` decision will be inherited.\n *\n * @deprecated Use `startSpan()`, `startSpanManual()` or `startInactiveSpan()` instead.\n */\n public startChild(\n spanContext?: Pick>,\n ): SpanInterface {\n const childSpan = new Span({\n ...spanContext,\n parentSpanId: this._spanId,\n sampled: this._sampled,\n traceId: this._traceId,\n });\n\n // eslint-disable-next-line deprecation/deprecation\n childSpan.spanRecorder = this.spanRecorder;\n // eslint-disable-next-line deprecation/deprecation\n if (childSpan.spanRecorder) {\n // eslint-disable-next-line deprecation/deprecation\n childSpan.spanRecorder.add(childSpan);\n }\n\n const rootSpan = getRootSpan(this);\n // TODO: still set span.transaction here until we have a more permanent solution\n // Probably similarly to the weakmap we hold in node-experimental\n // eslint-disable-next-line deprecation/deprecation\n childSpan.transaction = rootSpan as Transaction;\n\n if (DEBUG_BUILD && rootSpan) {\n const opStr = (spanContext && spanContext.op) || '< unknown op >';\n const nameStr = spanToJSON(childSpan).description || '< unknown name >';\n const idStr = rootSpan.spanContext().spanId;\n\n const logMessage = `[Tracing] Starting '${opStr}' span on transaction '${nameStr}' (${idStr}).`;\n logger.log(logMessage);\n this._logMessage = logMessage;\n }\n\n return childSpan;\n }\n\n /**\n * Sets the tag attribute on the current span.\n *\n * Can also be used to unset a tag, by passing `undefined`.\n *\n * @param key Tag key\n * @param value Tag value\n * @deprecated Use `setAttribute()` instead.\n */\n public setTag(key: string, value: Primitive): this {\n // eslint-disable-next-line deprecation/deprecation\n this.tags = { ...this.tags, [key]: value };\n return this;\n }\n\n /**\n * Sets the data attribute on the current span\n * @param key Data key\n * @param value Data value\n * @deprecated Use `setAttribute()` instead.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public setData(key: string, value: any): this {\n // eslint-disable-next-line deprecation/deprecation\n this.data = { ...this.data, [key]: value };\n return this;\n }\n\n /** @inheritdoc */\n public setAttribute(key: string, value: SpanAttributeValue | undefined): void {\n if (value === undefined) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete this._attributes[key];\n } else {\n this._attributes[key] = value;\n }\n }\n\n /** @inheritdoc */\n public setAttributes(attributes: SpanAttributes): void {\n Object.keys(attributes).forEach(key => this.setAttribute(key, attributes[key]));\n }\n\n /**\n * @inheritDoc\n */\n public setStatus(value: SpanStatusType): this {\n this._status = value;\n return this;\n }\n\n /**\n * @inheritDoc\n * @deprecated Use top-level `setHttpStatus()` instead.\n */\n public setHttpStatus(httpStatus: number): this {\n setHttpStatus(this, httpStatus);\n return this;\n }\n\n /**\n * @inheritdoc\n *\n * @deprecated Use `.updateName()` instead.\n */\n public setName(name: string): void {\n this.updateName(name);\n }\n\n /**\n * @inheritDoc\n */\n public updateName(name: string): this {\n this._name = name;\n return this;\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Use `spanToJSON(span).status === 'ok'` instead.\n */\n public isSuccess(): boolean {\n return this._status === 'ok';\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Use `.end()` instead.\n */\n public finish(endTimestamp?: number): void {\n return this.end(endTimestamp);\n }\n\n /** @inheritdoc */\n public end(endTimestamp?: SpanTimeInput): void {\n // If already ended, skip\n if (this._endTime) {\n return;\n }\n const rootSpan = getRootSpan(this);\n if (\n DEBUG_BUILD &&\n // Don't call this for transactions\n rootSpan &&\n rootSpan.spanContext().spanId !== this._spanId\n ) {\n const logMessage = this._logMessage;\n if (logMessage) {\n logger.log((logMessage as string).replace('Starting', 'Finishing'));\n }\n }\n\n this._endTime = spanTimeInputToSeconds(endTimestamp);\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Use `spanToTraceHeader()` instead.\n */\n public toTraceparent(): string {\n return spanToTraceHeader(this);\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Use `spanToJSON()` or access the fields directly instead.\n */\n public toContext(): SpanContext {\n return dropUndefinedKeys({\n data: this._getData(),\n description: this._name,\n endTimestamp: this._endTime,\n // eslint-disable-next-line deprecation/deprecation\n op: this.op,\n parentSpanId: this._parentSpanId,\n sampled: this._sampled,\n spanId: this._spanId,\n startTimestamp: this._startTime,\n status: this._status,\n // eslint-disable-next-line deprecation/deprecation\n tags: this.tags,\n traceId: this._traceId,\n });\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Update the fields directly instead.\n */\n public updateWithContext(spanContext: SpanContext): this {\n // eslint-disable-next-line deprecation/deprecation\n this.data = spanContext.data || {};\n // eslint-disable-next-line deprecation/deprecation\n this._name = spanContext.name || spanContext.description;\n this._endTime = spanContext.endTimestamp;\n // eslint-disable-next-line deprecation/deprecation\n this.op = spanContext.op;\n this._parentSpanId = spanContext.parentSpanId;\n this._sampled = spanContext.sampled;\n this._spanId = spanContext.spanId || this._spanId;\n this._startTime = spanContext.startTimestamp || this._startTime;\n this._status = spanContext.status;\n // eslint-disable-next-line deprecation/deprecation\n this.tags = spanContext.tags || {};\n this._traceId = spanContext.traceId || this._traceId;\n\n return this;\n }\n\n /**\n * @inheritDoc\n *\n * @deprecated Use `spanToTraceContext()` util function instead.\n */\n public getTraceContext(): TraceContext {\n return spanToTraceContext(this);\n }\n\n /**\n * Get JSON representation of this span.\n *\n * @hidden\n * @internal This method is purely for internal purposes and should not be used outside\n * of SDK code. If you need to get a JSON representation of a span,\n * use `spanToJSON(span)` instead.\n */\n public getSpanJSON(): SpanJSON {\n return dropUndefinedKeys({\n data: this._getData(),\n description: this._name,\n op: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] as string | undefined,\n parent_span_id: this._parentSpanId,\n span_id: this._spanId,\n start_timestamp: this._startTime,\n status: this._status,\n // eslint-disable-next-line deprecation/deprecation\n tags: Object.keys(this.tags).length > 0 ? this.tags : undefined,\n timestamp: this._endTime,\n trace_id: this._traceId,\n origin: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined,\n _metrics_summary: getMetricSummaryJsonForSpan(this),\n profile_id: this._attributes[SEMANTIC_ATTRIBUTE_PROFILE_ID] as string | undefined,\n exclusive_time: this._exclusiveTime,\n measurements: Object.keys(this._measurements).length > 0 ? this._measurements : undefined,\n });\n }\n\n /** @inheritdoc */\n public isRecording(): boolean {\n return !this._endTime && !!this._sampled;\n }\n\n /**\n * Convert the object to JSON.\n * @deprecated Use `spanToJSON(span)` instead.\n */\n public toJSON(): SpanJSON {\n return this.getSpanJSON();\n }\n\n /**\n * Get the merged data for this span.\n * For now, this combines `data` and `attributes` together,\n * until eventually we can ingest `attributes` directly.\n */\n private _getData():\n | {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any;\n }\n | undefined {\n // eslint-disable-next-line deprecation/deprecation\n const { data, _attributes: attributes } = this;\n\n const hasData = Object.keys(data).length > 0;\n const hasAttributes = Object.keys(attributes).length > 0;\n\n if (!hasData && !hasAttributes) {\n return undefined;\n }\n\n if (hasData && hasAttributes) {\n return {\n ...data,\n ...attributes,\n };\n }\n\n return hasData ? data : attributes;\n }\n}\n","import type { Options } from '@sentry/types';\n\nimport { getClient } from '../exports';\n\n// Treeshakable guard to remove all code related to tracing\ndeclare const __SENTRY_TRACING__: boolean | undefined;\n\n/**\n * Determines if tracing is currently enabled.\n *\n * Tracing is enabled when at least one of `tracesSampleRate` and `tracesSampler` is defined in the SDK config.\n */\nexport function hasTracingEnabled(\n maybeOptions?: Pick | undefined,\n): boolean {\n if (typeof __SENTRY_TRACING__ === 'boolean' && !__SENTRY_TRACING__) {\n return false;\n }\n\n const client = getClient();\n const options = maybeOptions || (client && client.getOptions());\n return !!options && (options.enableTracing || 'tracesSampleRate' in options || 'tracesSampler' in options);\n}\n","import type { Scope, Span, SpanTimeInput, StartSpanOptions, TransactionContext } from '@sentry/types';\n\nimport { addNonEnumerableProperty, dropUndefinedKeys, logger, tracingContextFromHeaders } from '@sentry/utils';\nimport { getDynamicSamplingContextFromSpan } from '.';\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { getCurrentScope, withScope } from '../exports';\nimport type { Hub } from '../hub';\nimport { runWithAsyncContext } from '../hub';\nimport { getIsolationScope } from '../hub';\nimport { getCurrentHub } from '../hub';\nimport type { Scope as ScopeClass } from '../scope';\nimport { handleCallbackErrors } from '../utils/handleCallbackErrors';\nimport { hasTracingEnabled } from '../utils/hasTracingEnabled';\nimport { spanIsSampled, spanTimeInputToSeconds, spanToJSON } from '../utils/spanUtils';\n\n/**\n * Wraps a function with a transaction/span and finishes the span after the function is done.\n *\n * Note that if you have not enabled tracing extensions via `addTracingExtensions`\n * or you didn't set `tracesSampleRate`, this function will not generate spans\n * and the `span` returned from the callback will be undefined.\n *\n * This function is meant to be used internally and may break at any time. Use at your own risk.\n *\n * @internal\n * @private\n *\n * @deprecated Use `startSpan` instead.\n */\nexport function trace(\n context: TransactionContext,\n callback: (span?: Span) => T,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n onError: (error: unknown, span?: Span) => void = () => {},\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n afterFinish: () => void = () => {},\n): T {\n // eslint-disable-next-line deprecation/deprecation\n const hub = getCurrentHub();\n const scope = getCurrentScope();\n // eslint-disable-next-line deprecation/deprecation\n const parentSpan = scope.getSpan();\n\n const spanContext = normalizeContext(context);\n const activeSpan = createChildSpanOrTransaction(hub, {\n parentSpan,\n spanContext,\n forceTransaction: false,\n scope,\n });\n\n // eslint-disable-next-line deprecation/deprecation\n scope.setSpan(activeSpan);\n\n return handleCallbackErrors(\n () => callback(activeSpan),\n error => {\n activeSpan && activeSpan.setStatus('internal_error');\n onError(error, activeSpan);\n },\n () => {\n activeSpan && activeSpan.end();\n // eslint-disable-next-line deprecation/deprecation\n scope.setSpan(parentSpan);\n afterFinish();\n },\n );\n}\n\n/**\n * Wraps a function with a transaction/span and finishes the span after the function is done.\n * The created span is the active span and will be used as parent by other spans created inside the function\n * and can be accessed via `Sentry.getSpan()`, as long as the function is executed while the scope is active.\n *\n * If you want to create a span that is not set as active, use {@link startInactiveSpan}.\n *\n * Note that if you have not enabled tracing extensions via `addTracingExtensions`\n * or you didn't set `tracesSampleRate`, this function will not generate spans\n * and the `span` returned from the callback will be undefined.\n */\nexport function startSpan(context: StartSpanOptions, callback: (span: Span | undefined) => T): T {\n const spanContext = normalizeContext(context);\n\n return runWithAsyncContext(() => {\n return withScope(context.scope, scope => {\n // eslint-disable-next-line deprecation/deprecation\n const hub = getCurrentHub();\n // eslint-disable-next-line deprecation/deprecation\n const parentSpan = scope.getSpan();\n\n const shouldSkipSpan = context.onlyIfParent && !parentSpan;\n const activeSpan = shouldSkipSpan\n ? undefined\n : createChildSpanOrTransaction(hub, {\n parentSpan,\n spanContext,\n forceTransaction: context.forceTransaction,\n scope,\n });\n\n return handleCallbackErrors(\n () => callback(activeSpan),\n () => {\n // Only update the span status if it hasn't been changed yet\n if (activeSpan) {\n const { status } = spanToJSON(activeSpan);\n if (!status || status === 'ok') {\n activeSpan.setStatus('internal_error');\n }\n }\n },\n () => activeSpan && activeSpan.end(),\n );\n });\n });\n}\n\n/**\n * @deprecated Use {@link startSpan} instead.\n */\nexport const startActiveSpan = startSpan;\n\n/**\n * Similar to `Sentry.startSpan`. Wraps a function with a transaction/span, but does not finish the span\n * after the function is done automatically. You'll have to call `span.end()` manually.\n *\n * The created span is the active span and will be used as parent by other spans created inside the function\n * and can be accessed via `Sentry.getActiveSpan()`, as long as the function is executed while the scope is active.\n *\n * Note that if you have not enabled tracing extensions via `addTracingExtensions`\n * or you didn't set `tracesSampleRate`, this function will not generate spans\n * and the `span` returned from the callback will be undefined.\n */\nexport function startSpanManual